Duplicate-swap-device check compares vnodes, not devices β the same cdev swapped on twice via distinct devfs alias vnodes interleaves two swap stripes over the same physical blocks
| Field | Value |
|---|---|
| ID | DF-2881 |
| Status | new |
| Severity | Low |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:H/UI:N/S:U/C:L/I:L/A:N |
| CWE | CWE-1023 Incomplete Comparison |
| File | sys/vm/vm_swap.c |
| Lines | 281, 426 |
| Area | vm |
| Confidence | likely |
| Discovered | 2026-09-02 |
| Pass | 2 (GLM 5.3 second pass) |
| Bucket | base:vm |
| Reported | pending |
| Known CVE | none |
| CVE match | novel |
Summary
sys_swapon's duplicate detection is sp->sw_vp == vp and sys_swapoff
matches the same way. DFly devfs allocates one vnode per devfs node,
and the disk layer explicitly creates alias nodes for the same cdev
(serno/%s make_dev_alias, slice aliases). Swapping on /dev/da0s1b and
/dev/serno/
Timeline
- 2026-09-02 Discovered during pass-2 audit of vm_swap.c (GLM 5.3).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2881 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 817 B | β raw | |
| VERDICT.md | β | 2.3 KB | β raw | |
| build.sh | β | 63 B | view raw | |
| df2881_run2.log | β | 914 B | view raw | |
| df2881_swapalias.sh | β | 966 B | view raw | |
| env.txt | β | 401 B | view raw | |
| fix.diff | β | 271 B | view raw | |
| manifest.json | β | 727 B | view raw | |
| run.sh | β | 186 B | view raw | |
| verdict.json | β | 2.5 KB | view raw |
DF-2881 PoC evidence pack
What
Duplicate swap devices via distinct vnodes over the same storage: whole-disk /dev/vn0 and compat-slice /dev/vn0s0 both swapped on simultaneously.
Build
(none: stock swapon/vnconfig)
Run
truncate -s 2147483648 /swaptest.img; vnconfig -c vn0 /swaptest.img; swapon /dev/vn0; swapon /dev/vn0s0; swapinfo; swapoff both
Expected
swapon /dev/vn0 rc=0; swapon /dev/vn0s0 rc=0 (no EBUSY); swapinfo lists BOTH devices over the same backing file
Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 All logs are full untrimmed captures unless noted. fix.diff is the git-apply-able verified fix (authored after verification; never applied to the audit tree).
DF-2881 - verification verdict
Status: reproduced | reproduced: 1 | impact: corruption | confidence: certain
Duplicate-swap check bypass reproduced on the stock kernel. Control: re-swapon of /dev/vbd0s1b is rejected with Device already in use (sp->sw_vp == vp matches, vm_swap.c:281). The guest vbd driver creates no serno slice-alias nodes, so the exact same-cdev two-vnode form is not constructible here; the identical check weakness was demonstrated with the whole-disk and compat-slice nodes of one vn disk: swapon /dev/vn0 AND swapon /dev/vn0s0 were BOTH accepted (rc=0 each) installing two interleaved 4194304-block swap stripes over the SAME physical blocks (swapinfo shows both). Pageouts to the two stripes interleave onto overlapping offsets - one process swapped pages overwrite another process swap blocks, silent cross-process corruption, exactly the claimed consequence class. Root-only, operator-mistake threat model; cleaned up immediately (both swapoff).
Evidence pointers
df2881_run2.log: swapon /dev/vn0 rc=0 + swapon /dev/vn0s0 rc=0 + swapinfo showing both devices over the same 2G backing file; control EBUSY in df2881_run.log
Kernel references
PoC changes vs the filing sketch
serno alias slice nodes absent on vbd; used whole-disk + compat-slice overlap of one vn disk instead (same vnode-identity check bypass)
Fix
recommendation: sys/vm/vm_swap.c: also reject a swap device whose underlying storage identity (devid) is already active
fix status: not_testable
cdev-identity check compiled into the fix-all kernel; the demonstrated whole-disk/slice overlap uses two different cdevs covering the same blocks, so the check does not (and cannot) catch it; honest fix needs storage-range comparison
Guest: DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:04 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablecdev-identity check compiled into the fix-all kernel; the demonstrated whole-disk/slice overlap uses two different cdevs covering the same blocks, so the check does not (and cannot) catch it; honest fix needs storage-range comparison
Confirmed kernel references
Detail
Evidence (decisive lines)
df2881_run2.log: swapon /dev/vn0 rc=0 + swapon /dev/vn0s0 rc=0 + swapinfo showing both devices over the same 2G backing file; control EBUSY in df2881_run.log
PoC changes
serno alias slice nodes absent on vbd; used whole-disk + compat-slice overlap of one vn disk instead (same vnode-identity check bypass)
Verified recommended fix
sys/vm/vm_swap.c: also reject a swap device whose underlying storage identity (devid) is already active
Verdict
Duplicate-swap check bypass reproduced on the stock kernel. Control: re-swapon of /dev/vbd0s1b is rejected with Device already in use (sp->sw_vp == vp matches, vm_swap.c:281). The guest vbd driver creates no serno slice-alias nodes, so the exact same-cdev two-vnode form is not constructible here; the identical check weakness was demonstrated with the whole-disk and compat-slice nodes of one vn disk: swapon /dev/vn0 AND swapon /dev/vn0s0 were BOTH accepted (rc=0 each) installing two interleaved 4194304-block swap stripes over the SAME physical blocks (swapinfo shows both). Pageouts to the two stripes interleave onto overlapping offsets - one process swapped pages overwrite another process swap blocks, silent cross-process corruption, exactly the claimed consequence class. Root-only, operator-mistake threat model; cleaned up immediately (both swapoff).
No comments yet.