โฌข DragonFlyBSD Kernel Audit
DF-4385 / trigger.c
โ† back to finding โ†“ download raw
/*
 * DF-4385 trigger replica: oce_img_flashing_required() CRC read.
 *
 *   oce_sysctl.c:458  crc_offset = hdrs_size + img_offset + img_size - 4;
 *   oce_sysctl.c:460  p += crc_offset;           // p = fw->data
 *   oce_sysctl.c:468  bcmp(flashed_crc, p, 4);   // NO fw->datasize check
 *
 * Called from oce_be3_flashdata() case IMG_REDBOOT (:334) with
 * img_offset=262144, img_size=1048576, BEFORE the image-size gate at :389.
 * A tiny "firmware" whose cookie scan succeeds makes the kernel read at
 * fw->data + ~1.31 MB regardless of fw->datasize.
 *
 * Build: cc -O2 -o trigger trigger.c
 * Run:   ./trigger     -> prints offset, then dies on the guard page.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>

/* file header(128) + num_imgs(1)*image_hdr(48) โ€” bin_offset in the driver */
static uint32_t sizeof_hdrs(void) { return 128 + 1 * 48; }

int main(void)
{
	/* smallest viable hostile image: valid file header + one image
	 * header with imageid==1 + a sec-info block with the right cookie โ€”
	 * a couple of KB is plenty for the parse to succeed */
	size_t datasize = 4096;
	uint8_t *fw = mmap(NULL, 16384, PROT_NONE,
			   MAP_PRIVATE | MAP_ANON, -1, 0);
	if (fw == MAP_FAILED) { perror("mmap"); return 1; }
	/* readable region of exactly datasize, then an UNMAPPED-mood guard */
	if (mprotect(fw, datasize, PROT_READ) != 0) { perror("mprotect"); return 1; }

	uint32_t hdrs_size = sizeof_hdrs();
	uint32_t img_offset = 262144;                 /* IMG_REDBOOT start */
	uint32_t img_size = 1048576;                  /* IMG_REDBOOT size  */
	uint32_t crc_offset = hdrs_size + img_offset + img_size - 4;

	printf("fw->datasize = %zu\n", datasize);
	printf("bcmp read at fw->data + %u  (%.2f MB past a %zu-byte image)\n",
	       crc_offset, crc_offset / 1048576.0, datasize);
	fflush(stdout);

	const char *p = (const char *)fw + crc_offset;   /* :460 */
	uint8_t flashed_crc[4] = {0};
	int differs = bcmp(flashed_crc, p, 4) != 0;      /* :468 โ€” OOB READ */
	printf("unreachable: bcmp returned %d\n", differs);
	return 0;
}