/*
 * DF-4386 trigger replica: hw.oceN.firmware_version served by strlen().
 *
 *   oce_mbox.c:289        bcopy(fw_ver_str, sc->fw_version, 32);  // 32
 *                         device bytes, NUL not guaranteed
 *   oce_sysctl.c:84-89    SYSCTL_ADD_STRING(.. &sc->fw_version,
 *                         sizeof(sc->fw_version) ..)
 *   kern_sysctl.c:1171    SYSCTL_OUT(req, arg1, strlen(arg1)+1);
 *                                                            ^^^^
 *                         unbounded strlen on a buffer whose 32 bytes
 *                         may all be non-NUL -> walks past fw_version
 *                         into the rest of struct oce_softc (macaddr,
 *                         OCE_DMA_MEM bsmbz with kernel pointers) and
 *                         hands the bytes to any unprivileged reader.
 *
 * Guard-page model: 32 readable bytes (the hostile device string),
 * then more readable bytes modeling the adjacent softc fields; the
 * strlen walk is demonstrated by counting how far it goes.
 *
 * Build: cc -O2 -o trigger trigger.c
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>

int main(void)
{
	size_t page = 4096;
	uint8_t *region = mmap(NULL, page, PROT_READ | PROT_WRITE,
			       MAP_PRIVATE | MAP_ANON, -1, 0);
	if (region == MAP_FAILED) { perror("mmap"); return 1; }

	/* softc model: [0..31] = fw_version filled with 32 non-NUL bytes
	 * by the device; [32..] = following softc fields, non-zero */
	memset(region, 'A', 32);
	memset(region + 32, 0xB1, 256);	/* macaddr, bsmbx, ... */
	/* one NUL eventually, modeling a pointer's zero byte */
	region[32 + 55] = 0;

	volatile size_t len = strlen((char *)region);	/* :1171 */

	printf("fw_version capacity : 32 bytes (all non-NUL from device)\n");
	printf("strlen() walked     : %zu bytes  (+%zu past the buffer)\n",
	       len, len - 32);
	if (len > 32) {
		printf("RESULT: strlen OOB confirmed; kernel copies len+1 "
		       "bytes (incl. adjacent softc fields) to userspace\n");
		return 0;
	}
	printf("RESULT: bounded (unexpected)\n");
	return 1;
}
