Uninitialized kernel-stack bytes leaked to userspace via uep FIFO during short-transfer packet reassembly
Summary
In uep_intr_callback cross-transfer reassembly path computes res=pkt_len-sc->buf_len from previous transfer header bytes then does memcpy(sc->buf+sc->buf_len buf res) without checking res<=len where len is how many valid bytes current interrupt transfer actually delivered. When device sends short transfer (len<res) copy reads uninitialized kernel-stack bytes from local buf[17] deposits into sc->buf. For REPORT packets (byte0 0x80/0x81) uep_process_pkt() passes straight to uep_put_queue() which pushes 5 bytes including uninitialized ones into RX FIFO userspace reads from /dev/uepN. short_xfer_ok=1 permits 1-byte transfers making this fully reachable. 1-byte 0x80 first transfer sets buf_len=1 second 1-byte transfer res=4 copies 3 uninit bytes into sc->buf[2..4] leaked to userspace. [VERIFIED pass2: reproduced - 1-byte then 1-byte transfer makes memcpy sc buf plus 1 read 3 bytes the device never sent with poisoned stack readable from 0644 dev uepN by unpriv users; short-transfer stash fix-validated]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2337 Β· 10 files| File | Type | Description | Size | |
|---|---|---|---|---|
| build.log | β | 528 B | view raw | |
| build.sh | β | 91 B | view raw | |
| env.txt | β | 412 B | view raw | |
| fix.diff | β | 404 B | view raw | |
| run.log | β | 317 B | view raw | |
| run.sh | β | 107 B | view raw | |
| run_fixed.log | β | 169 B | view raw | |
| uep_rig.c | β | 5.3 KB | view raw | |
| verdict.json | β | 2.0 KB | view raw | |
| fix.diff | β | 404 B | view raw |
Fix verification
not_testableConfirmed kernel references
Detail
Exploit chain
malicious USB pointer device sends 1-byte 0x80 then 1 byte; unprivileged user reads /dev/uepN and receives 3 uninitialized kernel-stack bytes per report pair
Evidence (decisive lines)
run.log (attack FIFO: 80 55 a5 a5 a5, attack_exit=0; control 80 11 22 33 44), run_fixed.log (attack: fifo bytes (0) - stash and wait), fix.diff
PoC changes
none beyond scenario plumbing; shims reproduce the exact short-transfer copy semantics
Verified recommended fix
stash the delivered bytes and wait when res exceeds the transfer length
Verdict
uep_intr_callback (uep.c:188-276) verbatim rig with stack poisoning: after a 1-byte 0x80 transfer (REPORT header) a second 1-byte transfer computes res = 5 - 1 = 4 and memcpy(sc->buf+1, buf, 4) reads three bytes the device never delivered; the poisoned stack residue (0xA5) lands verbatim in the FIFO record (80 55 A5 A5 A5) that uep_put_queue pushes to /dev/uepN. Control (full 5-byte transfer) shows all device bytes. With the short-transfer stash the attack queues nothing and waits for the rest of the packet; the control path is byte-identical. Requires a malicious or buggy eGalax touch panel (short_xfer_ok makes 1-byte transfers legal), 0644 device, so an unprivileged local user can read the leaked kernel-stack bytes.
No comments yet.