⬢ DragonFlyBSD Kernel Audit
DF-5756 / craft5756.c
← back to finding ↓ download raw
/* DF-5756 — craft a FAT image whose LFN entries contain unpaired surrogate
 * code units, then the reader (kread5756) shows what the kernel does with
 * them on readdir.
 *
 * Patch targets (UTF-16LE bytes, found by scanning the raw image):
 *   "abcdefghij.k" unit[4] 'e' -> U+DC00 (lone LOW surrogate)
 *   "wxyzabcd.k"   unit[0] 'w' -> U+D83D (lone HIGH surrogate)
 *
 * weChksum covers only the 8.3 alias, so no checksum fixup is needed.
 */
#include <sys/types.h>
#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

/* wePart1 (units 0-4, UTF-16LE) + entry meta (attr 0x0f follows at +10) */
static const unsigned char patA[] = {
	'a',0,'b',0,'c',0,'d',0,'e',0
};
static const unsigned char patB[] = {
	'w',0,'x',0,'y',0,'z',0,'a',0
};

static size_t
find(unsigned char *buf, size_t sz, const unsigned char *pat, size_t pl)
{
	size_t i;

	for (i = 0; i + pl <= sz; i++)
		if (memcmp(buf + i, pat, pl) == 0)
			return i;
	return (size_t)-1;
}

static void
patch(unsigned char *buf, size_t sz, const unsigned char *pat, size_t pl,
    size_t unitidx, unsigned char lo, unsigned char hi, const char *label)
{
	size_t off = find(buf, sz, pat, pl);

	if (off == (size_t)-1) {
		printf("[craft] %s: base name NOT found in image\n", label);
		exit(1);
	}
	if (off + 10 < sz && buf[off + 10] != 0x0f) {
		printf("[craft] %s: found at 0x%zx but attr byte is 0x%02x "
		    "(not an LFN entry)\n", label, off, buf[off + 10]);
		exit(1);
	}
	/* LFN entry: byte0=seq, name starts at entry+1 == match offset */
	printf("[craft] %s: name at 0x%zx, patching unit[%zu] -> %02x %02x\n",
	    label, off, unitidx, lo, hi);
	buf[off + unitidx * 2] = lo;
	buf[off + unitidx * 2 + 1] = hi;
}

int
main(int argc, char **argv)
{
	unsigned char *buf;
	ssize_t n;
	size_t sz;
	int fd;

	if (argc != 2)
		errx(1, "usage: %s <image>", argv[0]);
	fd = open(argv[1], O_RDWR);
	if (fd < 0)
		err(1, "open %s", argv[1]);
	sz = lseek(fd, 0, SEEK_END);
	lseek(fd, 0, SEEK_SET);
	buf = malloc(sz);
	if (!buf)
		err(1, "malloc");
	n = read(fd, buf, sz);
	if (n < 0 || (size_t)n != sz)
		err(1, "read");

	/* unit[4] of A ('e') -> U+DC00 (LE: 00 DC) */
	patch(buf, sz, patA, sizeof(patA), 4, 0x00, 0xDC, "low-surrogate");
	/* unit[0] of B ('w') -> U+D83D (LE: 3D D8) */
	patch(buf, sz, patB, sizeof(patB), 0, 0x3D, 0xD8, "high-surrogate");

	if (lseek(fd, 0, SEEK_SET) != 0)
		err(1, "lseek");
	if (write(fd, buf, sz) != (ssize_t)sz)
		err(1, "write");
	close(fd);
	free(buf);
	printf("[craft] image patched\n");
	return 0;
}