Root Cause Analysis
1. Overview and Manifestation
The reported crash is a General Protection Fault (#GP) on a non-canonical address (0xdffffc00000003d1), reported by KASAN as a suspected user memory access in the range [0x0000000000001e88 - 0x0000000000001e8f].
The fault occurs in __iterate_interfaces() (net/mac80211/util.c:757):
static void __iterate_interfaces(struct ieee80211_local *local,
u32 iter_flags,
void (*iterator)(void *data, u8 *mac,
struct ieee80211_vif *vif),
void *data)
{
struct ieee80211_sub_if_data *sdata;
bool active_only = iter_flags & IEEE80211_IFACE_ITER_ACTIVE;
list_for_each_entry_rcu(sdata, &local->interfaces, list,
lockdep_is_held(&local->iflist_mtx) ||
lockdep_is_held(&local->hw.wiphy->mtx)) {
switch (sdata->vif.type) {
In the disassembly of __iterate_interfaces():
1c: 4c 8d a3 90 1e 00 00 lea 0x1e90(%rbx),%r12
23: 4c 89 e0 mov %r12,%rax
26: 48 c1 e8 03 shr $0x3,%rax
2a: 0f b6 04 28 movzbl (%rax,%rbp,1),%eax <-- trapping instruction
...
3a: 8b bb 90 1e 00 00 mov 0x1e90(%rbx),%edi
Here, %rbx holds sdata, which was read from &local->interfaces (local->interfaces.next). Offset 0x1e90 corresponds to sdata->vif.type (offsetof(struct ieee80211_sub_if_data, vif.type) == 0x1e90).
The registers show:
RBX: ffffffffffffffff
R12 = RBX + 0x1e90 = 0x0000000000001e8f
RAX = R12 >> 3 = 0x00000000000003d1
RBP = 0xdffffc0000000000 (KASAN shadow memory base)
- Trapping address:
RAX + RBP = 0xdffffc00000003d1
The value read for sdata (local->interfaces.next) was 0xffffffffffffffff (-1).
2. Root Cause Mechanism
Inspection of the stack trace reveals two concurrent activities:
-
Task Context (Process syz.3.228, UID 0):
The process was executing a write() system call on a PCI config space file in /proc/bus/pci:
proc_reg_write() -> proc_bus_pci_write() -> pci_user_write_config_dword()
In pci_user_write_config_dword() (drivers/pci/access.c:278), the kernel acquires raw_spin_lock_irq(&pci_lock), performs the configuration write to the target PCI device via dev->bus->ops->write(), and then releases the lock via raw_spin_unlock_irq(&pci_lock).
In _raw_spin_unlock_irq(), the sti instruction re-enables CPU interrupts.
-
Hardware / Chipset Configuration Corruption:
Writing arbitrary configuration data into the PCI configuration space of root/host bridge devices (specifically on QEMU Q35 / ICH9 chipset, device 00:00.0) allows privileged userspace to reprogram memory controller routing registers, such as PAM (Programmable Attribute Map), SMRAM/TSEG, or BARs.
Reprogramming these registers unmaps or aliases the underlying physical RAM pages. On x86 / PCI platforms, reads directed to unmapped or aborted memory spaces return all-ones (~0UL or 0xffffffffffffffff).
-
Interrupt Context (<IRQ>):
Immediately upon execution of the sti instruction in _raw_spin_unlock_irq(), an APIC timer interrupt fired. The timer softirq executed mac80211_hwsim_beacon(), which iterates active interfaces and transmits a simulated beacon frame:
mac80211_hwsim_beacon()
-> ieee80211_iterate_active_interfaces_atomic()
-> mac80211_hwsim_beacon_tx()
-> mac80211_hwsim_tx_frame()
-> mac80211_hwsim_tx_frame_no_nl()
-> mac80211_hwsim_addr_match()
-> ieee80211_iterate_active_interfaces_atomic()
-> __iterate_interfaces()
Inside __iterate_interfaces(), the list head &local->interfaces (R14 = 0xffff888059542a98, physical address 0x59542a98) fell within the physical address range whose mapping was corrupted by the PCI configuration write. Reading local->interfaces.next yielded 0xffffffffffffffff instead of a valid pointer.
The function dereferenced sdata->vif.type at 0xffffffffffffffff + 0x1e90 = 0x1e8f, leading to the crash.
3. Summary
The bug is caused by allowing unrestricted writes to PCI host bridge configuration space via /proc/bus/pci (drivers/pci/proc.c and drivers/pci/access.c), which can corrupt chipset physical memory routing in virtualization environments. When memory reads subsequently return bus-abort all-ones (0xffffffffffffffff), kernel pointer dereferences in subsequent memory accesses crash the system.