DF-0835 / trigger.c
/* * DF-0835 trigger — smbfs_advlock unconditional lock-type overwrite. * * Bug: sys/vfs/smbfs/smbfs_vnops.c:943 does * lkop = SMB_LOCK_EXCL; * AFTER the inner switch (lines 927-939) has correctly mapped * F_WRLCK -> SMB_LOCK_EXCL, F_RDLCK -> SMB_LOCK_SHARED, * F_UNLCK -> SMB_LOCK_RELEASE. * The unconditional overwrite makes every F_SETLK call sent to the * SMB server an EXCLUSIVE lock (SMB_LOCKING_ANDX_SHARED_LOCK never set, * unlock-count=0 / lock-count=1 even for F_UNLCK). * * This trigger issues fcntl(F_SETLK, F_RDLCK) on a file that lives on an * smbfs mount. With the bug, the SMB client sends SMB_COM_LOCKING_ANDX * WITHOUT the SMB_LOCKING_ANDX_SHARED_LOCK flag (i.e. an exclusive lock), * so a second reader is blocked — violating POSIX shared-lock semantics. * * FULL runtime proof requires: * - an SMB server exporting a share (the audit guest has none), and * - a root-mounted smbfs filesystem: mount_smbfs //user@server/share /mnt * - then: ./trigger /mnt/somefile * * Without a live SMB share the trigger still validates the syscall surface * (it will get ENOENT/EINVAL on a non-smbfs path, confirming the fcntl path * is exercised). The PRIMARY evidence for this finding is the deterministic * source trace in VERDICT.md (the overwrite at smbfs_vnops.c:943 is * unambiguous dead-code-making-the-switch-moot). * * Build: cc -o trigger trigger.c * Run: ./trigger <file-on-smbfs-mount> */ #include <sys/fcntl.h> #include <unistd.h> #include <stdio.h> #include <string.h> #include <errno.h> #include <stdlib.h> int main(int argc, char **argv) { const char *path; int fd, rc; struct flock fl; if (argc != 2) { fprintf(stderr, "usage: %s <file-on-smbfs>\n", argv[0]); return 2; } path = argv[1]; fd = open(path, O_RDWR); if (fd < 0) { fprintf(stderr, "open(%s) failed: %s\n", path, strerror(errno)); return 2; } /* Request a SHARED (read) byte-range lock. With the bug the SMB client * forwards this to the server as an EXCLUSIVE lock. */ memset(&fl, 0, sizeof(fl)); fl.l_type = F_RDLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 1; /* lock 1 byte */ rc = fcntl(fd, F_SETLK, &fl); if (rc < 0) { fprintf(stderr, "fcntl(F_SETLK, F_RDLCK) failed: %s\n", strerror(errno)); close(fd); return 1; } printf("F_RDLCK issued on %s (rc=%d)\n", path, rc); printf("On an UNPATCHED kernel the server received SMB_LOCK_EXCL\n"); printf(" => a second reader would be blocked (shared-lock semantics broken)\n"); printf("On a PATCHED kernel the server received SMB_LOCK_SHARED\n"); /* cleanup: unlock */ fl.l_type = F_UNLCK; fcntl(fd, F_SETLK, &fl); close(fd); return 0; } |