DF-5677 / verdict.json
{ "finding_id": "DF-5677", "status": "reproduced", "reproduced": true, "impact": "dos", "confidence": "certain", "verdict": "prop_object_release_emergency dispatches (*po->po_type->pot_emergency_free)(parent) with parent==NULL whenever the first loop iteration breaks (ocnt!=1 concurrent-retain race or DONE) \u2014 reproduced deterministically at unit level on the same-source rig: assert(parent) abort at prop_object.c:1048 (exit 134) and raw NULL-deref SIGSEGV under NDEBUG (exit 139). Kernel impact none today: the emergency path requires _prop_stack_push to fail, and kernel _PROP_MALLOC is kmalloc(M_WAITOK) which cannot return NULL (kern_kmalloc.c:706 panics instead) \u2014 dead code in-kernel, live for userland libprop under allocation failure plus the retain race. Fixed and validated on the rig: parent==NULL early-return makes both builds survive.", "exploit_chain": "userland libprop under malloc pressure: prop_object_release on a deep container hits _PROP_OBJECT_FREE_FAILED (stack-push malloc fails) -> emergency walk -> concurrent retain on the target restores refcount>1 -> first iteration breaks with parent==NULL -> NULL deref/abort. Kernel chain blocked by M_WAITOK semantics (no FAILED possible).", "evidence": "run.log: Assertion failed: (parent), function prop_object_release_emergency, file proporig/prop_object.c, line 1048 exit=134; NDEBUG control Segmentation fault exit=139; fixed rig DF5677: survived (bug not present) exit=0 both builds.", "kernel_refs": [ "sys/libprop/prop_object.c:1005-1052", "sys/libprop/prop_object.c:1094-1105", "sys/libprop/prop_object_impl.h:260", "sys/kern/kern_kmalloc.c:706", "sys/libprop/prop_stack.c:49-53" ], "poc_changes": "Harness written fresh: TU-include of prop_object.c to reach the static function; refcount-2 array as the deterministic stand-in for the raced state; NDEBUG control build to show the raw NULL deref behind the assert.", "attempts": 1, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 200, "guest_dirty": 0, "build_cmd": "sh build.sh (guest root /tmp/df5677: same-source rig + TU-include harness)", "run_cmd": "sh run.sh (assert build + NDEBUG control, then fixed-rig re-run)", "code_hash": "4de1d75f3711d2315113c6f4d4ee2cc4c52d6942c6d79d136bc3d0d9a633c1f5", "notes": "Filed Low because the kernel path is unreachable with M_WAITOK semantics; noted in the same bucket (not separately filed): emergency_free called without the type lock and the refcount restore at prop_object.c:1046/1102 running outside the lock \u2014 same malloc-failure/race edge, and the pot_lock contract hole for this family is already tracked as DF-5674.", "recommended_fix": "Return early when parent==NULL (nothing was walked, nothing to emergency-free) instead of asserting and dereferencing.", "fix_status": "fixed", "fix_baseline_reproduced": true, "fix_patched_reproduced": false, "fix_verdict": "fix.diff (parent==NULL early return) applied to the same-source rig on the guest: baseline aborts/SIGSEGVs, fixed harness survives in both assert and NDEBUG builds (exit 0). Kernel rebuild not performed \u2014 the emergency path cannot execute in-kernel (M_WAITOK push cannot fail), so there is no kernel behavior to validate.", "fix_evidence": "run.log (baseline exit=134 assert / 139 NDEBUG; fixed survived (bug not present) exit=0 both); fix.diff" } |