DF-5688 / df5688_minimal.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /* * df5688_minimal.h โ two deterministic minimized sequences, ddmin-shrunk * from fuzz runs against the UNMODIFIED kernel source. * * Part A (8 ops, from seed 6: 276 -> 8): two bogus idr_remove()s of * never-allocated ids (139, 136) sitting on the Fenwick chains of live * allocations corrupt the cumulative 'allocated' counters. On the hard * build (live KKASSERT) the subsequent LEGIT remove(142) drives a * counter negative and trips the kernel's own * KKASSERT(idr_nodes[id].allocated >= 0) (linux_idr.c:197) โ an * in-kernel panic(). On the soft build (asserts off) the same * sequence leaves id 135 LIVE but unfindable (idr_find(135) == NULL): * the object pointer is lost and the id is never handed out again โ * a permanent leak of the kernel object at the drm consumer layer. * * Part B (4 ops, from seed 3: 363 -> 4): the pure DUPLICATE-ID path โ * no counter ever goes negative, so it reproduces identically with * live KKASSERT (hard build, and in-kernel via df5688_mod.c): * * chain(526) = {526, 525, 523, ...}: allocating 526 bumps nodes[525] * to 1. idr_remove(525) โ 525 was NEVER allocated โ passes the * `allocated != 0' guard and phantom-decrements nodes[525] and its * chain. The tree now undercounts block 525: idr_alloc(525, 532) * hands out 525, then idr_alloc(525, 0) hands out 525 AGAIN while it * is live โ the previous kernel object pointer is silently * overwritten. * * This is exactly the DRM_IOCTL_SYNCOBJ_CREATE / SYNCOBJ_DESTROY * interleaving an unprivileged DRI client can drive * (sys/dev/drm/drm_syncobj.c:333 idr_alloc(start=1); drm_syncobj.c:369 * feeds the raw ioctl handle straight into idr_remove). */ /* ---- Part A ---- */ { int id = idr_alloc(&idr, (void *)0x515000000220UL, 142, 194, 0); printf("alloc(142,194) -> %d\n", id); if (id >= 0) { mused[id] = 1; mval[id] = (void *)0x515000000220UL; } } printf("remove(139) [never allocated] -> %p\n", idr_remove(&idr, 139)); printf("remove(139) [never allocated] -> %p\n", idr_remove(&idr, 139)); { int id = idr_alloc(&idr, (void *)0x515000008600UL, 135, 192, 0); printf("alloc(135,192) -> %d\n", id); if (id >= 0) { mused[id] = 1; mval[id] = (void *)0x515000008600UL; } } printf("remove(136) [never allocated] -> %p\n", idr_remove(&idr, 136)); /* hard build: KKASSERT fires inside THIS legit remove (counter * goes to -1); soft build continues */ { void *p = idr_remove(&idr, 142); printf("remove(142) [live] -> %p\n", p); mused[142] = 0; mval[142] = NULL; } /* legit: update model */ { int id = -1, t; for (t = 0; t < 4; t++) { if (idr_pre_get(&idr, 0) == 0) break; if (idr_get_new_above(&idr, (void *)0x515000100000UL, 187, &id) == 0) break; } printf("get_new(187) -> %d\n", id); if (id >= 0) { mused[id] = 1; mval[id] = (void *)0x515000100000UL; } } { int id = idr_alloc(&idr, (void *)0x515000113000UL, 187, 245, 0); printf("alloc(187,245) -> %d\n", id); if (id >= 0) { if (mused[id]) { n_dup++; diverged = 1; printf(">>> DUPLICATE ID %d (still allocated, ptr %p " "overwritten)\n", id, mval[id]); } else { mused[id] = 1; mval[id] = (void *)0x515000113000UL; } } } /* ---- Part B ---- */ { int id = idr_alloc(&idr, (void *)0x5150000f6000UL, 526, 0, 0); printf("alloc(526,0) -> %d\n", id); if (id >= 0) { mused[id] = 1; mval[id] = (void *)0x5150000f6000UL; } } printf("remove(525) [never allocated] -> %p\n", idr_remove(&idr, 525)); { int id = idr_alloc(&idr, (void *)0x5150014700UL, 525, 532, 0); printf("alloc(525,532) -> %d\n", id); if (id >= 0) { mused[id] = 1; mval[id] = (void *)0x5150014700UL; } } { int id = idr_alloc(&idr, (void *)0x5150016a00UL, 525, 0, 0); printf("alloc(525,0) -> %d\n", id); if (id >= 0) { if (mused[id]) { n_dup++; diverged = 1; printf(">>> DUPLICATE ID %d: idr_alloc returned an id " "STILL ALLOCATED (ptr %p) โ silently overwritten " "with %p\n", id, mval[id], (void *)0x5150016a00UL); } else { mused[id] = 1; mval[id] = (void *)0x5150016a00UL; } } } |