linux-kernelarm64xnu

On AArch64, how does SCTLR_EL1.SPAN=0 work when a translation fault occurs while PSTATE.PAN=1?


For example, the XNU kernel has the copyin()/copyout() functions to copy data from user-space to kernel-space and vice versa. Since these functions need to access user-space, they disable PAN by setting PSTATE.PAN to 0. However, if SCTLR_EL1.SPAN is set to 0, the specification says that "PSTATE.PAN is set to 1 on taking an exception to EL1".

First, let's say that a translation fault occurs during the copy operation while PAN is enabled (either on a user address or a kernel address). Then, an exception would be taken to EL1. Note that we were already running in EL1, so I'm not 100% sure that this counts as taking an exception "to EL1". I'll assume that it does, but please correct me if I'm wrong. In that case, because SCTLR_EL1.SPAN is set to 0, PAN is re-enabled automatically before the fault handler is executed.

Next, let's say that the fault handler succeeds (i.e. it finds the page and inserts it in the page tables), then what happens when the exception returns? I don't see any mention in the specification that PAN should be re-disabled automatically when the exception returns. However, if PAN stays enabled, then the next user-space access will trigger another exception, which should cause a kernel panic because the kernel is accessing a user address while PAN is enabled.

What am I getting wrong? I'm more familiar with XNU, but the same question probably applies to the Linux kernel with copy_from_user()/copy_to_user().


Solution

  • According to the ArmĀ® Architecture Reference Manual for A-profile architecture, section D8.4.1 "Effect of PSTATE on access permission":

    When taking an exception from an EL in AArch64 state to an ELx, PSTATE.PAN is saved to and restored from SPSR_ELx.PAN.

    And if we take a look at SPSR_EL1.PAN in section C5.2.18 we can read:

    When FEAT_PAN is implemented:

    Privileged Access Never. Set to the value of PSTATE.PAN on taking an exception to EL1, and copied to PSTATE.PAN on executing an exception return operation in EL1.

    So this seems like an easy hardware-assisted way to solve the problem. No magic software workarounds needed.