DF-1012 / poc.c
/* * DF-1012 — UVC heap underflow when VS_COLORFORMAT or VS_FRAME precedes * any VS_FORMAT descriptor. * * Bug location: sys/bus/u4b/uvc/uvc_drv.c:1836-1846, 1924 * * At uvc_drv.c:1836 the parser sets * fmt = data->fmt - 1; * which intentionally starts fmt one slot BEFORE the data->fmt[] * allocation. The intent is that the FIRST VS_FORMAT_* descriptor * will execute `fmt++;` (line 1851/1878) to advance fmt onto the * first valid slot. However the VS_COLORFORMAT case (line 1842) and * the VS_FRAME_* cases (line 1897, 1927) write to `fmt->colorspace` * / increment `fmt->nfrm` UNCONDITIONALLY: * * case UDESCSUB_VS_COLORFORMAT: * cld = (struct uvc_vs_color_desc *)desc; * fmt->colorspace = uvc_drv_get_colorspace(cld->bColorPris); * break; * * sizeof(struct uvc_data_format) == 96 (verified from uvc_drv.h:629), * colorspace is at struct offset 30, nfrm is at struct offset 8. So * if a COLORFORMAT or FRAME descriptor appears in the descriptor list * BEFORE any VS_FORMAT_* descriptor, the parser writes: * fmt->colorspace at data->fmt - 96 + 30 = data->fmt - 66 * fmt->nfrm at data->fmt - 96 + 8 = data->fmt - 88 * i.e. a heap underflow 66..88 bytes before the data->fmt allocation. * * The UVC spec requires VS_FORMAT descriptors to precede the * VS_FRAME descriptors for that format, but a malicious USB webcam * can present a descriptor list in any order. The parser already * trusts the device for ordering elsewhere (init_data_fmt just * counts descriptors without ordering checks). * * Reachability on the audit guest: * - The QEMU/KVM guest has no USB UVC device attached; uvc.ko is * shipped as a loadable module but never matches a real device. * - There is no software path that reaches uvc_drv_parse_data() * without a USB UVC webcam present. * - The bug is therefore LATENT on this guest but live on any * physical host that plugs in a (potentially malicious) UVC * webcam — the parser runs at device-attach time with no user * interaction beyond plug-in. * * This harness documents the trigger and the fix. */ #include <stdio.h> int main(void) { printf("=== DF-1012 trigger documentation ===\n"); printf("\nVulnerable path (device-attach time):\n"); printf(" uvc_attach -> uvc_drv_parse_data (uvc_drv.c:1776)\n"); printf(" fmt = data->fmt - 1; // uvc_drv.c:1836\n"); printf(" while (desc = usbd_find_descriptor(...)) {\n"); printf(" case UDESCSUB_VS_COLORFORMAT:\n"); printf(" fmt->colorspace = ...; // writes data->fmt - 66\n"); printf(" case UDESCSUB_VS_FRAME_*:\n"); printf(" fmt->nfrm++; // writes data->fmt - 88\n"); printf(" }\n"); printf("Trigger precondition: a malicious USB UVC webcam whose\n"); printf(" descriptor list emits a VS_COLORFORMAT or VS_FRAME_*\n"); printf(" descriptor BEFORE any VS_FORMAT_* descriptor.\n"); printf("Effect: heap underflow write 66..88 bytes before the\n"); printf(" data->fmt allocation; corrupts slab metadata / adjacent\n"); printf(" objects -> write-what-where primitive on a remote-capable\n"); printf(" attacker-controlled device.\n"); printf("\nStatus on this audit guest (no USB UVC device attached):\n"); printf(" NOT REACHABLE. Bug confirmed by code trace at\n"); printf(" sys/bus/u4b/uvc/uvc_drv.c:1836-1846 and 1924. Fix: track a\n"); printf(" fmt_seen flag and skip the COLORFORMAT / FRAME writes until\n"); printf(" the first VS_FORMAT descriptor has executed fmt++. See\n"); printf(" fix.diff and VERDICT.md.\n"); return 0; } |