Divide-by-zero (SIGFPE) in hpt_copy_array_info rebuild/verify percentage for arrays with bArnMember==1 or per-member capacity < 2MB
Summary
The % ksprintf divides by ((VDeviceCapacity/(bArnMember-1))>>11) unguarded; the driver itself creates bArnMember==1 arrays (1-member RAID-1/JBOD starting states). REPRODUCED on guest harness: Fatal trap 18; guarded-divisor fix survives. Root plants, any user detonates via sysctl read.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4765 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.5 KB | β raw | |
| VERDICT.md | β | 1.5 KB | β raw | |
| h1_harness.c | β | 18.7 KB | view raw | |
| build.sh | β | 97 B | view raw | |
| run.sh | β | 140 B | view raw | |
| build.log | β | 1.2 KB | view raw | |
| run.log | β | 774 B | view raw | |
| run.fixed.log | β | 692 B | view raw | |
| panic.txt | β | 1.0 KB | view raw | |
| env.txt | β | 258 B | view raw | |
| fix.diff | β | 2.4 KB | view raw |
DF-4765 β divide-by-zero panic in hpt_copy_array_info rebuild/verify percentage (bArnMember==1 / tiny per-member capacity)
File: sys/dev/raid/hptmv/hptproc.c (pass 2)
Build & run (same KLD harness as DF-4764)
./build.sh # builds /root/h1/h1harness.ko on the guest kldload /root/h1/h1harness.ko sysctl h1harness.trigger=2 # baseline: panics (Fatal trap 18) # after reset + rebuild: sysctl h1harness.trigger=5 -> fix: survives
Expected baseline (run.log)
=== H2 (DF-4765) bArnMember==1 -> div/0 === H2: real RAID-1 array, bArnMember=1 rf_verifying=1 Fatal trap 18: integer divide fault while in kernel mode Stopped at hpt_copy_array_info.constprop.3+0x187: divq %rdi,%eax
Why it is reachable
gui_lib.c:614acceptsAT_RAID1withnDisk <= 2β a 1-member mirror (bArnMember = pParam->nDisk= 1 at :618) is the create-and-duplicate starting state.hptproc.c:182-183lets theverify start Nsysctl command run on any RAID-1/RAID-5 array regardless of member count.- The percentage
ksprintfathptproc.c:457/462divides by(VDeviceCapacity/(bArnMember-1))>>11with no guard. - The outer divisor is also 0 whenever per-member capacity < 2 MB.
Detonator: any local user reading sysctl hptmv.status (world-readable).
Precondition: hptmv hardware with such an array (absent from audit guest;
verified via verbatim-code harness β see VERDICT.md in DF-4764).
Fix: fix.diff F2 hunk (guarded divisor) β validated in-harness
(trigger 5 survives, prints Verifying 0%).
DF-4765 VERDICT
Status: REPRODUCED (source+harness). See ../DF-4764/VERDICT.md for the
shared harness methodology; this trigger uses a REAL RaidArray (no type
confusion) with bArnMember==1, rf_verifying==1:
- run.log:
Fatal trap 18: integer divide fault while in kernel mode,Stopped at hpt_copy_array_info.constprop.3+0x187: divq %rdi,%rax. - run.fixed.log (trigger 5, fix.diff F2): prints
1 RAID 1 ... Verifying 0%and survives.
Reachability chain (static): HPT_IOCTL_CREATE_ARRAY AT_RAID1 nDisk=1 β
gui_lib.c:614 (nDisk <= 2) + :618 (bArnMember = pParam->nDisk) β
1-member mirror; verify start accepted at hptproc.c:182-183 (type check
only) β rf_verifying set by the rebuild DPC β any unprivileged
sysctl hptmv.status read β hptproc.c:462 x / 0 β SIGFPE panic.
The 1-member flag state is set by the closed-source raid library (x86_64-elf.raid.o.uu) β flagged as the one unverifiable link; confidence 'likely'. The alternative trigger (per-member capacity < 2 MB β zero denominator with bArnMember==2) needs no flag logic beyond capacity.
Kernel refs: hptproc.c:457, hptproc.c:462, gui_lib.c:614, gui_lib.c:618, hptproc.c:182.
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
fixedHarness-level A/B: unpatched verbatim copy panics (run.log); guarded version prints 'Verifying 0%' and survives (run.fixed.log trigger 5). Kernel-rebuild validation impossible on this guest (no hptmv hardware).
run.log vs run.fixed.log; fix.diff F2 hunk applies cleanly to pristine sys/dev/raid/hptmv/hptproc.c.
Confirmed kernel references
Detail
Exploit chain
root/admin creates a 1-member RAID-1 (or JBOD) via HPT_IOCTL_CREATE_ARRAY (accepted) and starts rebuild/verify (sysctl command or HPT_SET_ARRAY_STATE MIRROR_REBUILD_START) -> array sits with bArnMember==1 and rf_rebuilding/rf_verifying set -> any unprivileged user reads sysctl hptmv.status -> hpt_copy_array_info ksprintf divides by zero -> SIGFPE -> kernel panic (local DoS).
Evidence (decisive lines)
run.log (H2 banner then Fatal trap 18, Stopped at hpt_copy_array_info.constprop.3+0x187: divq %rdi,%rax); run.fixed.log trigger 5 (guarded divisor renders 'Verifying 0%', survives); fix.diff F2 hunk.
PoC changes
Trigger 2 of the DF-4764 KLD harness (verbatim function, real driver structs).
Verified recommended fix
Guard the percentage divisor: only divide when bArnMember>1 and the shifted per-member capacity is nonzero (fix.diff F2).
Verdict
REPRODUCED at source+harness (guest, same KLD as DF-4764): trigger 2 drives the VERBATIM hpt_copy_array_info (hptproc.c:402-478) with a REAL RAID-1 array object (no type confusion) having bArnMember==1 and rf_verifying==1, i.e. the exact state the driver itself allows: gui_lib.c:614 accepts AT_RAID1 with nDisk<=2 (1-member mirrors are the create-and-duplicate starting state) and the sysctl 'verify start N' command at hptproc.c:182-183 gates only on VDeviceType being RAID-1/RAID-5. The ksprintf at hptproc.c:462 divides by (VDeviceCapacity/(bArnMember-1))>>11 with bArnMember-1==0 -> 'Fatal trap 18: integer divide fault' at hpt_copy_array_info+0x187 divq (run.log). The same expression zeroes for per-member capacities < 2MB ((cap/(n-1))>>11 == 0). Detonator in production: any local user reading 'sysctl hptmv.status' while such an array is rebuilding/verifying. Preconditions (hptmv hardware + 1-member RAID-1 or tiny-capacity array being rebuilt/verified) cannot exist on the audit guest; everything downstream was executed verbatim in-kernel via the harness. Fix (guarded divisor, fix.diff) validated in-harness: trigger 5 prints 'Verifying 0%' and survives (run.fixed.log).
No comments yet.