DragonFlyBSD Kernel Audit
DF-2732 / iovcnt0.c
← back to finding ↓ download raw
/*
 * DF-2732 PoC: readv/writev/extpreadv/extpwritev accept iovcnt == 0.
 * sys/kern/sys_generic.c:188-210,391-414,218-246,422-450 + kern_subr.c
 * iovec_copyin() (kern_subr.c:455 `if ((u_int)iov_cnt > UIO_MAXIOV)`).
 *
 * With iovcnt==0 the syscall proceeds with auio.uio_iov pointing at an
 * UNINITIALIZED stack iovec (aiov[] in sys_readv) and uio_resid==0.
 * POSIX: "If iovcnt is less than or equal to zero ... EINVAL".
 *
 * Build:  cc -O -o iovcnt0 iovcnt0.c
 */
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define SYS_EXTPREADV  289
#define SYS_EXTPWRITEV 290

static void show(const char *what, ssize_t r, int e)
{
	printf("%-52s ret=%zd errno=%d (%s)\n", what, r, e,
	       e ? strerror(e) : "-");
}

int main(void)
{
	char tmpfile[] = "/tmp/df2732.scratch";
	struct iovec iov[1] = { { (void *)tmpfile, 1 } };
	char buf[16];
	int sv[2], fd, pf[2];
	ssize_t r;

	fd = open(tmpfile, O_RDWR | O_CREAT | O_TRUNC, 0644);
	if (fd < 0) { perror("open"); return 1; }
	if (write(fd, "HELLO", 5) != 5) { perror("write"); }
	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) { perror("socketpair"); return 1; }
	if (pipe(pf) < 0) { perror("pipe"); return 1; }

	puts("--- regular file ---");
	errno = 0; r = readv(fd, NULL, 0);            show("readv(file, NULL, 0) [expect EINVAL]", r, errno);
	errno = 0; r = readv(fd, iov, 0);             show("readv(file, iov, 0)", r, errno);
	errno = 0; r = writev(fd, NULL, 0);           show("writev(file, NULL, 0)", r, errno);
	errno = 0; r = syscall(SYS_EXTPREADV, fd, NULL, 0, (off_t)0, 0);
	                                               show("extpreadv(file, NULL, 0, 0, 0)", r, errno);
	errno = 0; r = syscall(SYS_EXTPWRITEV, fd, NULL, 0, (off_t)0, 0);
	                                               show("extpwritev(file, NULL, 0, 0, 0)", r, errno);

	puts("--- socket ---");
	errno = 0; r = readv(sv[0], NULL, 0);         show("readv(sock, NULL, 0)", r, errno);
	errno = 0; r = writev(sv[0], NULL, 0);        show("writev(sock, NULL, 0)", r, errno);

	puts("--- pipe ---");
	errno = 0; r = readv(pf[0], NULL, 0);         show("readv(pipe, NULL, 0)", r, errno);
	errno = 0; r = writev(pf[1], NULL, 0);        show("writev(pipe, NULL, 0)", r, errno);

	puts("--- /dev/zero ---");
	{
		int z = open("/dev/zero", O_RDONLY);
		if (z >= 0) {
			errno = 0; r = readv(z, NULL, 0); show("readv(/dev/zero, NULL, 0)", r, errno);
			close(z);
		}
	}

	puts("--- negative control ---");
	errno = 0; r = readv(fd, NULL, (int)-1);      show("readv(file, NULL, -1)", r, errno);
	errno = 0; r = readv(fd, iov, 1);             show("readv(file, iov, 1) [sanity]", r, errno);
	(void)buf;
	printf("DONE df2732\n");
	return 0;
}