Bug Mechanism and Technical Root Cause
1. Manifestation Site and Mechanism
The crash occurs at lib/rbtree.c:354 in ____rb_erase_color() (inlined into rb_erase()):
sibling = parent->rb_left;
if (rb_is_red(sibling)) { ... }
rb_is_red(sibling) dereferences sibling->__rb_parent_color. Because sibling is NULL, the instruction attempts to access offset 0 (0x0000000000000000), which traps under KASAN shadow address check at 0xdfff800000000000 (or causes an immediate fatal paging request / page fault on systems without KASAN).
Under red-black tree invariants, ____rb_erase_color() is reached only after deleting a black node, which requires the sibling subtree to have a black-height of at least 1; therefore, sibling can never be NULL in an uncorrupted red-black tree. Furthermore, within fs/kernfs/dir.c, all directory operations manipulating kn_parent->dir.children (kernfs_link_sibling, kernfs_unlink_sibling, and lookup routines) are strictly serialized under exclusive lock root->kernfs_rwsem. The presence of a NULL sibling demonstrates that the in-memory rbtree structure of kernfs_node was corrupted.
2. Triggering Sequence and Deferred Manifestation
The crash is triggered during network namespace teardown:
- When a network namespace exits,
cleanup_net() invokes ops_exit_list(), which executes rdma_dev_exit_net() (drivers/infiniband/core/device.c).
rdma_dev_exit_net() calls remove_one_compat_dev(), which calls ib_free_port_attrs() (drivers/infiniband/core/sysfs.c).
ib_free_port_attrs() calls destroy_gid_attrs(), which calls sysfs_remove_groups(), iterating over the attribute group and invoking sysfs_remove_group() -> remove_files() -> kernfs_remove_by_name().
kernfs_remove_by_name() invokes kernfs_unlink_sibling() to detach the attribute node from its parent kernfs directory rbtree (&kn_parent->dir.children) using rb_erase().
- Due to prior memory corruption of the
kernfs_node pointers/children, rb_erase() attempts to rebalance using ____rb_erase_color(), encountering parent->rb_left == NULL and dereferencing NULL.
3. Underlying Root Cause
The root cause is external physical memory corruption enabled via drivers/pci/pci-sysfs.c:
- Userspace mounts
sysfs and opens the PCI device BAR0 MMIO resource /sys/bus/pci/devices/0000:00:02.0/resource0 with O_RDWR.
- Userspace
mmaps the device MMIO BAR into its address space and writes directly into it (in the reproducer, via read() from /proc/thread-self/cmdline into the mmap'd MMIO range).
- Directly writing arbitrary data into a PCI device's MMIO control and DMA registers reprograms the hardware (e.g., ring buffers, base addresses, descriptor queues), causing the device to initiate DMA transfers into arbitrary physical memory addresses.
- The rogue DMA overwrites kernel heap memory containing
kernfs_node rbtree structures. The corrupted rbtree is only encountered later when the network namespace worker asynchronously tears down sysfs nodes in cleanup_net.