DragonFlyBSD Kernel Audit
DF-2619 / getdents_dump.c
← back to finding ↓ download raw
/* DF-2619: getdents dumper with hexdump of every d_name (leak capture).
 * DragonFly dirent: d_ino(8) d_namlen(u16@8) d_type(u8@10) .. d_name@16;
 * advance by _DIRENT_DIRSIZ = (16 + namlen + 1 + 7) & ~7.
 */
#include <sys/types.h>
#include <sys/dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

ssize_t getdents(int, char *, size_t);

#define DOFF __offsetof(struct dirent, d_name)

int
main(int argc, char **argv)
{
	char buf[65536];
	int fd;
	int n;
	int i;
	int off;
	int rec;

	if (argc != 2) {
		fprintf(stderr, "usage: getdents_dump <dir>\n");
		return 2;
	}
	fd = open(argv[1], O_RDONLY);
	if (fd < 0) { perror("open"); return 1; }
	for (;;) {
		n = getdents(fd, buf, sizeof(buf));
		if (n <= 0) {
			printf("getdents rc=%d\n", n);
			break;
		}
		for (off = 0; off < n; off += rec) {
			struct dirent *de = (struct dirent *)(buf + off);
			printf("ino=%llu namlen=%u type=%u name=",
			       (unsigned long long)de->d_ino,
			       de->d_namlen, de->d_type);
			for (i = 0; i < de->d_namlen; ++i) {
				unsigned char c = (unsigned char)de->d_name[i];
				if (c >= 0x20 && c < 0x7f && c != '\\')
					putchar(c);
				else if (c == '\\')
					printf("\\\\");
				else
					printf("\\x%02x", c);
			}
			putchar('\n');
			if (de->d_namlen > 64) {
				printf("  hexdump[0..%u]: ", de->d_namlen);
				for (i = 0; i < de->d_namlen; ++i)
					printf("%02x", (unsigned char)de->d_name[i]);
				putchar('\n');
			}
			rec = (DOFF + de->d_namlen + 1 + 7) & ~7;
			if (rec < 24)
				rec = 24;
		}
	}
	close(fd);
	return 0;
}