DragonFlyBSD Kernel Audit
DF-0745 / run.3.log
← back to finding ↓ download raw
=== DF-0745 deterministic harness: l2cap_request_free / l2cap_rtx double-free + TAILQ-corruption race ===
transcribed from sys/netbt/l2cap_misc.c:163-197 and sys/kern/kern_timeout.c:857-930

########## SCENARIO 1: pure double-free (no slab reuse) ##########
[setup] req=0x8005008c0 on g_link=0x403680 (ACTIVE+armed, in hl_reqs)
[TAILQ_REMOVE] Thread B stale-remove: req=0x8005008c0 cached-link=0x403680; req->lr_link=0x403680 (clobbered by freelist); tqe_prev=0x403680 tqe_next=0x0
    -> stale tqe_prev dereferenced by TAILQ_REMOVE writes into whatever list the reuser put this slot on (cross-list corruption)
[TAILQ_REMOVE] Thread B stale-remove: req=0x8005008c0 cached-link=0x403680; req->lr_link=0x0 (clobbered by freelist); tqe_prev=0x403680 tqe_next=0x0
    -> stale tqe_prev dereferenced by TAILQ_REMOVE writes into whatever list the reuser put this slot on (cross-list corruption)
[zfree] DOUBLE-FREE DETECTED: req=0x8005008c0 already marked ZENTRY_FREE -> would zerror(ZONE_ERROR_ALREADYFREE) -> panic("zone: freeing free entry") on GENERIC

zone_free() calls on req slot: 2 (expected 2)
double-free events:            1
stale TAILQ_REMOVE events:     2
>>> DOUBLE-FREE CONFIRMED (vm/vm_zone.c:235 ZONE_ERROR_ALREADYFREE -> panic on GENERIC) <<<

########## SCENARIO 2: slab reuse between the two frees ##########
[setup] req=0x800500880 on g_link=0x403680 (ACTIVE+armed, in hl_reqs)
[TAILQ_REMOVE] Thread B stale-remove: req=0x800500880 cached-link=0x403680; req->lr_link=0x403680 (clobbered by freelist); tqe_prev=0x403680 tqe_next=0x0
    -> stale tqe_prev dereferenced by TAILQ_REMOVE writes into whatever list the reuser put this slot on (cross-list corruption)
[reclaim] slab reuse: zone_alloc returned 0x800500880 (== old req slot); now a live request on g_link2.hl_reqs (pre-callout-arm window)
[TAILQ_REMOVE] Thread B stale-remove: req=0x800500880 cached-link=0x403680; req->lr_link=0x403660 (clobbered by freelist); tqe_prev=0x403660 tqe_next=0x0
    -> stale tqe_prev dereferenced by TAILQ_REMOVE writes into whatever list the reuser put this slot on (cross-list corruption)

zone_free() calls on req slot: 2 (expected 2)
double-free events:            0
stale TAILQ_REMOVE events:     2
g_link2.hl_reqs.tqh_first = 0x0 (reused req=0x800500880); LIVE REQ UNLINKED by Thread B's stale remove
>>> TAILQ CORRUPTION CONFIRMED (stale tqe_prev dereferenced; live req on g_link2 unlinked by Thread B's stale remove) <<<
>>> FREE-OF-LIVE-OBJECT CONFIRMED (slab reuse turned the double-free into freeing the reuser's in-use request -> use-after-free) <<<

=== SUMMARY ===
Scenario 1 (double-free):         CONFIRMED
Scenario 2 (TAILQ/UAF corruption): CONFIRMED

>>> DF-0745 REPRODUCED: double-free AND TAILQ/use-after-free corruption both confirmed <<<