CDRIOCSETBLOCKSIZE with arg=0 causes kernel divide-by-zero panic via rounddown()
Summary
acd_ioctl CDRIOCSETBLOCKSIZE at atapi-cd.c:723-726: cdp->block_size=*(int*)data, no validation. acd_set_ioparm :951: rounddown(iomax,block_size) = (iomax/block_size)*block_size. block_size=0 -> div-by-zero #DE panic. No caps_priv_check (unlike CDIOCRESET). /dev/acdN 0640 root:operator. Operator group. Fix: reject bs<=0.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1434 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| fix.diff | suggested-fix | Add `if (*(int*)ap->a_data <= 0) { error = EINVAL; break; }` guard in CDRIOCSETBLOCKSIZE. | 349 B | view raw |
| VERDICT.md | verdict | Full source-trace analysis | 2.0 KB | β raw |
| build.sh | build-script | Kernel build validation | 533 B | view raw |
| run.sh | run-script | PoC runner (not runnable on guest) | 538 B | view raw |
| fix_build.log | build-log | Full kernel build output (make nativekernel rc=0) | 5.6 MB | β download |
| env.txt | environment | Guest environment | 277 B | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1434 β Verification Verdict
Verdict: CONFIRMED-BY-SOURCE-TRACE (operator-only, maxx not in operator)
Status: inconclusive (HW-gated / not reachable as unprivileged maxx) Impact: none (cannot reproduce on QEMU guest β no GPU/HW, or root/operator-only) Confidence: certain (source-trace confirmed bug is real)
Mechanism
acd_ioctl CDRIOCSETBLOCKSIZE (:723-726): cdp->block_size=(int)data, no validation. acd_set_ioparm (:951): rounddown(iomax,block_size) = (iomax/block_size)*block_size. block_size=0 β div-by-zero #DE panic. No caps_priv_check (unlike CDIOCRESET at :360 which has one). /dev/acdN is 0640 root:operator.
Source: sys/dev/disk/nata/atapi-cd.c:723-726, 951
Why it cannot be reproduced on this guest
Operator-group only. /dev/acd0 is 0640 root:operator. maxx (uid 1001) is NOT in operator group. Cannot open the device.
Phase 6: Escalation Assessment
This is a Operator-only (NATA ATAPI CD) finding. The primitive is not reachable from the unprivileged maxx user on this guest (no hardware / module not loaded / root-only device). No escalation chain is possible because the trigger path is not exercisable.
For GPU findings: the module (radeon.ko/amdgpu.ko/i915.ko) is a loadable module not present in the GENERIC kernel and requires actual GPU hardware absent from the QEMU guest. For root/operator findings: the device node is mode 0600 or 0640 root:operator, and maxx (uid 1001) has no operator group membership.
Fix
Reject block_size <= 0 in CDRIOCSETBLOCKSIZE handler with EINVAL.
Fix description: Add if (*(int*)ap->a_data <= 0) { error = EINVAL; break; } guard in CDRIOCSETBLOCKSIZE.
The full git-apply-able diff is in fix.diff. It applies cleanly to the audit source tree
and compiles as part of the kernel build (validated via make nativekernel rc=0).
Classification
- status: inconclusive
- reproduced: 0
- impact: none
- fix_status: not_testable (HW-gated: PoC cannot run on guest; diff applies + compiles verified)
Confirmed kernel references
- s
- y
- s
- /
- d
- e
- v
- /
- d
- i
- s
- k
- /
- n
- a
- t
- a
- /
- a
- t
- a
- p
- i
- -
- c
- d
- .
- c
- :
- 7
- 2
- 3
- -
- 7
- 2
- 6
- s
- y
- s
- /
- d
- e
- v
- /
- d
- i
- s
- k
- /
- n
- a
- t
- a
- /
- a
- t
- a
- p
- i
- -
- c
- d
- .
- c
- :
- 9
- 5
- 1
Detail
Exploit chain
none (div-by-zero DoS β no write primitive. Device is operator-group-only; maxx not in operator. Cannot even open /dev/acd0. The threat model is an operator-group member.)
Evidence (decisive lines)
Source trace: atapi-cd.c:724 'cdp->block_size = *(int *)ap->a_data' β no validation. :951 'rounddown(cdp->iomax, cdp->block_size)' β div-by-zero if block_size=0. Guest: ls -la /dev/acd0 β 'crw-r----- root operator'. id maxx β 'groups=1001(maxx)' β NOT in operator.
PoC changes
Authored fix.diff: reject block_size <= 0 in CDRIOCSETBLOCKSIZE handler with EINVAL.
Verified recommended fix
Add 'if ((int)ap->a_data <= 0) { error = EINVAL; break; }' guard in CDRIOCSETBLOCKSIZE. matches finding proposal. Full diff in findings/poc/DF-1434/fix.diff.
Verdict
CONFIRMED BY SOURCE TRACE. acd_ioctl CDRIOCSETBLOCKSIZE (:723-726): cdp->block_size=(int)data, no validation. acd_set_ioparm (:951): rounddown(iomax,block_size). block_size=0 β div-by-zero #DE panic. No caps_priv_check (unlike CDIOCRESET :360). Bug is real. /dev/acd0 EXISTS on guest (natapicd in GENERIC) but is 0640 root:operator β maxx (uid 1001) is NOT in operator group. Cannot open device.
No comments yet.