Skip to content

apple_sep: unbinding warns twice and leaks the firmware IOMMU mapping #591

Description

@brentkearney

Unbinding apple_sep triggers two IOMMU WARNs and leaves the SEP firmware mapped in the device's DART. remove() unmaps the firmware region with its physical address instead of the IOVA that dma_map_resource() returned, so the unmap tears down page table entries that were never present and the real mapping survives.

drivers/soc/apple/sep.rs keeps only the shifted IOVA that MSG_BOOT_IMG4 needs and discards the IOVA itself:

let res = bindings::dma_map_resource(
    self.dev.as_raw(),
    self.region_params.addr,
    ...
);
self.fw_mapped.store(true, Relaxed);
res >> IOVA_SHIFT            // res is never stored

remove() then passes the physical address of the reserved region:

bindings::dma_unmap_resource(
    self.dev.as_raw(),
    self.region_params.addr, // should be the IOVA from dma_map_resource()
    self.region_params.size,
    ...
);

Impact

  • Two WARNs per unbind, which taint the kernel.
  • The firmware region stays mapped in the SEP's DART until reboot.
  • Reachable on shipping configurations: the sep node is enabled by default on t8103-j293, t8103-j313, t8103-j456, and t8103-j457.
  • Anyone debugging the SEP hits this immediately, because unbind and rebind is the natural way to re-run probe().

Steps to reproduce

  1. Boot a machine whose sep node is enabled and confirm the driver is bound:

    ls -l /sys/bus/platform/devices/396400000.sep/driver
    
  2. Unbind the driver:

    echo 396400000.sep | sudo tee /sys/bus/platform/drivers/apple_sep/unbind
    
  3. Read dmesg.

Expected: the firmware mapping is torn down and dmesg stays quiet.

Actual: two WARNs, and the mapping is still present.

WARNING: drivers/iommu/io-pgtable-dart.c:308 at dart_unmap_pages+0x11c/0x140, CPU#1
 pc : dart_unmap_pages+0x11c/0x140
 lr : dart_unmap_pages+0x44/0x140
  dart_unmap_pages+0x11c/0x140 (P)
  apple_dart_unmap_pages+0x24/0x30
  __iommu_dma_unmap+0x94/0x140
  iommu_dma_unmap_phys+0xf8/0x118
  _RNvMs0_...3sep9SepDriverEE20post_unbind_callback+0x34/0x70

WARNING: drivers/iommu/dma-iommu.c:844 at __iommu_dma_unmap+0x128/0x140, CPU#1
 pc : __iommu_dma_unmap+0x128/0x140
 lr : __iommu_dma_unmap+0x94/0x140
  __iommu_dma_unmap+0x128/0x140 (P)
  iommu_dma_unmap_phys+0xf8/0x118
  _RNvMs0_...3sep9SepDriverEE20post_unbind_callback+0x34/0x70

The reserved region on this machine is at 0x10006340000, outside the device's DART address space, which is why the unmap finds nothing:

OF: reserved mem: 0x0000010006340000..0x00000100068b7fff (5600 KiB) map non-reusable sep-firmware

A rebind afterwards sends MSG_BOOT_TZ0 and never receives an ack, because SEPOS is already running. That is expected, but it makes unbind one-way.

Environment

Machine Apple MacBook Pro (16-inch, 2021), apple,j316s / apple,t6000
Kernel 7.1.6-1-1-ARCH (linux-asahi 7.1.6.asahi1-1), aarch64
Distribution Arch Linux ARM (Omarchy)
Config CONFIG_APPLE_SEP=y

t600x does not enable the sep node, so reproducing here required adding aliases { sep = &sep; } and status = "okay" to t6000-j316s.dtb. The bug is in the unmap path and does not depend on that change.

Fix

Store the IOVA that dma_map_resource() returns and unmap that. Fix in #592.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions