Skip to content

apple-ibridge: fix heap out-of-bounds write in appleib_add_device() (sub_hdevs[] indexed by raw collection index)#11

Open
xeeban wants to merge 1 commit into
t2linux:mbp15from
xeeban:fix/appleib-add-device-oob
Open

apple-ibridge: fix heap out-of-bounds write in appleib_add_device() (sub_hdevs[] indexed by raw collection index)#11
xeeban wants to merge 1 commit into
t2linux:mbp15from
xeeban:fix/appleib-add-device-oob

Conversation

@xeeban

@xeeban xeeban commented Jun 12, 2026

Copy link
Copy Markdown

Scope / safety: memory-safety fix in the T1 iBridge path — apple_ibridge binds only USB_DEVICE_ID_APPLE_IBRIDGE (0x8600), so appleib_add_device() never runs on a T2 machine (the T2 Touch Bar 0x8302/0x8102 is handled by separate drivers). It is also behavior-preserving for any well-formed layout, so it is inert / zero-risk for T2 users.

What

appleib_add_device() indexes the fixed-size sub_hdevs[] array — which has only ARRAY_SIZE(appleib_sub_hid_ids) (= 2) slots — by the raw HID collection index i. On the T1's combined display/ALS interface the report descriptor has 7 collections (the ALS, five nested sensor collections, and the Touch Bar display at index 6), so the display's hid_device * is written to sub_hdevs[6] — 24 bytes past the end of the devm-allocated appleib_hid_dev_info. This is a heap out-of-bounds write on every probe / every boot; the corrupted adjacent object then GPFs on any later teardown of the iBridge (driver unload, USB unbind/re-enumerate, or suspend/resume).

This PR indexes sub_hdevs[] by the matched sub-device-id slot instead (dev_id - appleib_sub_hid_ids, {0,1}, in-bounds by construction).

Root cause

for (i = 0; i < hdev->maxcollection; i++) {        /* iterates ALL collections (7 on T1) */
    usage  = hdev->collection[i].usage;
    dev_id = appleib_find_dev_id_for_usage(usage);
    if (!dev_id)
        hid_warn(hdev, "Unknown collection ... usage %x\n", usage);  /* the 5 nested ones */
    else
        hdev_info->sub_hdevs[i] = appleib_add_sub_dev(hdev_info, dev_id);  /* i can be 6 -> OOB */
}

hdev->maxcollection counts every collection, while sub_hdevs[] is only ever sized/iterated as 2 slots everywhere else (appleib_remove_device(), appleib_forward_int_op(), raw-event), so i is the wrong index here.

Proof

A later teardown GPFs with non-canonical "pointers" that are byte-for-byte the first 16 bytes of the live report descriptor (a hid_device's first member is dev_rdesc):

WARNING: ... lib/list_debug.c ... __list_del_entry_valid_or_report+0x...
Oops: general protection fault, probably for non-canonical address 0x25011503160a2005 [#1] SMP
RIP: 0010:remove_nodes.isra.0+0x...
Call Trace:
  hid_destroy_device+0x68/0x80

The change

  • appleib_add_device() — index by the matched slot; warn only for unmatched application collections (the nested sensor collections are expected, not errors); guard against a duplicate collection mapping to an already-filled slot; never store an ERR_PTR in the array; clean up the full array on the error path. Correct indexing also means the display sub-device is now destroyed by appleib_remove_device() (it was orphaned at the OOB index → leak + UAF on parent unbind) and the sub_open[] flag lands on the right slot.
  • raw-event forwarder — read sub_hdevs[i] once and NULL/IS_ERR-guard it before hid_input_report().

No functional change on the normal path — the same sub-devices register and bind, the bar lights as before, minus the five bogus Unknown collection warnings per boot. (The old code's extra sub-devices at indices ≥ 2 were never touched by any forwarder/remove/open loop — they were pure orphans/leaks.)

Testing

  • Hardware: MacBookPro13,2 (T1), Arch Linux, kernels 6.x and 7.0.10.
  • Before: every boot logs 5 Unknown collection warnings; any iBridge teardown (echo 0/1 > .../authorized, modprobe -r apple_touchbar) GPFs in remove_nodes()/hid_destroy_device() or D-state-deadlocks modprobe; recovery is a hard reboot.
  • After: warnings gone; the same authorized 0→1 power-cycle and a full modprobe -r/reload run clean (no GPF, no D-state, process stays R), repeatedly; Touch Bar + ALS bind and function across reboots.
  • Patched module builds clean against 7.0.10 headers (both modules, no new warnings).

Note

This is a generic memory-safety bug — not suspend-specific; that's just one reliable trigger. Full write-up (crash forensics + adversarial review of the fix): https://github.com/xeeban/macbook-t1-linux/blob/main/touch-bar/IBRIDGE-TEARDOWN-UAF-ANALYSIS.md

Credit to @roadrunner2 (Ronald Tschalär) for the original driver.

appleib_add_device() indexes the fixed-size sub_hdevs[] array -- which has
only ARRAY_SIZE(appleib_sub_hid_ids) (== 2) slots -- by the raw HID collection
index. On the T1's combined display/ALS interface the report descriptor has 7
collections (the ALS, five nested sensor collections, and the Touch Bar
display at index 6), so the display's hid_device* is written to sub_hdevs[6]:
24 bytes past the end of the devm-allocated appleib_hid_dev_info. This corrupts
the adjacent slab object on every probe, and the latent corruption then GPFs on
any later iBridge teardown (driver unload, USB unbind/re-enumerate, or
suspend/resume) in remove_nodes()/hid_destroy_device(); the non-canonical
"pointers" in the crash are byte-for-byte the device's report descriptor.

Index sub_hdevs[] by the matched id's slot in appleib_sub_hid_ids[]
(dev_id - appleib_sub_hid_ids, {0,1}, in-bounds by construction) instead. Warn
only for unmatched application collections (the nested sensor collections are
expected, not errors), guard against a duplicate collection filling a slot,
never store an ERR_PTR in the array, and clean up the full array on the error
path. Correct indexing also means the display sub-device is actually destroyed
by appleib_remove_device() (it was orphaned at the OOB index, leaking + UAF on
parent unbind) and the sub_open[] flag lands on the right slot. Also
NULL/ERR-guard the sub-device in the raw-event forwarder.

Tested on MacBookPro13,2 (T1), kernels 6.x and 7.0.10: the per-boot "Unknown
collection" warnings are gone and iBridge teardown / USB re-enumeration no
longer GPFs or D-state-deadlocks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
xeeban pushed a commit to xeeban/macbook-t1-linux that referenced this pull request Jun 12, 2026
The heap-OOB fix is filed at t2linux/apple-ib-drv#11
(build-tested, T1-iBridge-scoped, inert on T2; issues are disabled on that
repo so it went as a PR). Link it from README #7, touch-bar Upstream, and the
issue/PR drafts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants