⬢ DragonFlyBSD Kernel Audit
DF-3428 / trigger_reserved_livelock.c
← back to finding ↓ download raw
/* DF-3428 — generic_netmap_rxsync: 32-bit wrap of ring->reserved
 *          validation lets the release-loop target escape [0, lim],
 *          producing an unbounded kernel loop holding the kring lock.
 *
 * Bug (sys/net/netmap/netmap_generic.c:641, 691-711):
 *
 *   u_int k, resvd = ring->reserved;          // :641  user-writable (mmap)
 *   ...
 *   j = kring->nr_hwcur;
 *   k = ring->cur;                            // :692  validated <= lim at :643
 *   if (resvd > 0) {
 *       if (resvd + ring->avail >= lim + 1) { // :694  32-bit WRAP defeats check
 *           ring->reserved = resvd = 0;       //        e.g. resvd=0xFFFFFFFF, avail=1 -> sum=0
 *       }
 *       k = (k >= resvd) ? k - resvd : k + lim + 1 - resvd;   // :698 underflow
 *   }
 *   if (j != k) {
 *       for (n = 0; j != k; n++) {            // :702  j cycles [0..lim],
 *           ...ring->slot[j]...               //        k in [lim+2, 2*lim+2]
 *           if (j++ == lim) j = 0;            //        -> j NEVER equals k
 *       }
 *
 *   With lim = 1023 (default netmap_generic_ringsize = 1024 slots,
 *   netmap.c:216) and resvd = 0xFFFFFFFF: the wrap check passes
 *   (0xFFFFFFFF + 1 == 0 < 1024), so k = cur + 1024 + 1 - 0xFFFFFFFF
 *   == cur + 2 (mod 2^32) + lim -> always > lim -> infinite loop.
 *   The slot writes stay in-bounds (pure livelock), but the loop runs
 *   under the kring q_lock taken by the NIOCRXSYNC/poll path
 *   (netmap.c:1474/1768 via nm_kr_get/netmap_ioctl), so the thread is
 *   unkillable and the ring is wedged: local kernel DoS.
 *
 *   Note: the sibling host-ring code netmap.c:909-920 has the same wrap
 *   but only does arithmetic (no loop) there; the infinite loop is
 *   specific to the generic adapter rxsync.
 *
 * Trigger (would-be, needs loadable netmap):
 *   fd = open("/dev/netmap"); NIOCREGIF(generic adapter); mmap;
 *   ring->cur = 0; ring->reserved = 0xFFFFFFFF; ring->avail = 1;
 *   ioctl(fd, NIOCRXSYNC);   // never returns
 *
 * Platform fact: netmap KLD unbuildable on this tree (netmap_build.log).
 */
int main(void) { return 1; }