ARM Cortex-A Permission Fault Behavior During Code Execution from Writable Memory Regions

When executing code from a memory region mapped as read/write (AP[2] == 0) on an ARM Cortex-A processor, a permission fault occurs, specifically an instruction abort with exception class 0b100001 and instruction fault status code 0b001111. This fault indicates a permission fault at level 3, which is triggered when the processor attempts to execute code from a memory region that is writable. The fault disappears when the memory region is remapped as read-only (AP[2] == 1). This behavior is consistent with the ARM architecture’s security and memory protection mechanisms, which are designed to prevent execution from writable memory regions under certain conditions.

The ARM Architecture Reference Manual (ARM DDI 0487I.a) provides detailed explanations of this behavior. Specifically, the manual outlines how access permissions (AP) and execute-never (XN) attributes interact to enforce memory protection policies. The fault occurs because the memory region is marked as writable, and the processor’s configuration enforces a policy that treats writable memory as non-executable. This is controlled by the SCTLR_ELx.WXN (Write Execute Never) bit, which, when set to 1, forces writable memory regions to be treated as execute-never, regardless of the descriptor fields in the page tables.

The fault is not a bug but rather a deliberate feature of the ARM architecture to enhance system security. By preventing execution from writable memory regions, the architecture mitigates certain types of security vulnerabilities, such as code injection attacks. This behavior is particularly relevant in systems where multiple exception levels (ELs) are used, as the permissions and protections can vary depending on the current execution level.


Memory Protection Mechanisms and SCTLR_ELx.WXN Configuration

The root cause of the permission fault lies in the interaction between the memory region’s access permissions and the processor’s configuration, specifically the SCTLR_ELx.WXN bit. The SCTLR_ELx (System Control Register for Exception Level x) register contains several control fields that influence memory management and protection. The WXN bit, when enabled, enforces a policy where writable memory regions are treated as execute-never, regardless of the page table descriptor settings.

For a stage 1 translation in a translation regime that supports two exception levels, the SCTLR_ELx.WXN bit has the following effects:

  • If WXN is set to 0, the access permissions defined in the page table descriptors are honored without additional restrictions.
  • If WXN is set to 1, the following rules apply:
    • If the memory region is writable from EL0 (user mode), it is treated as Unprivileged Execute-Never (UXN), regardless of the UXN field in the page table descriptor.
    • If the memory region is writable from a higher exception level (EL1, EL2, or EL3), it is treated as Privileged Execute-Never (PXN), regardless of the PXN field in the page table descriptor.

This behavior ensures that writable memory regions cannot be used to execute code, thereby reducing the attack surface for exploits that rely on modifying executable memory. The fault observed in the scenario is a direct result of this security mechanism.

Additionally, the ARM architecture provides further granularity through the use of the PXN (Privileged Execute-Never) and UXN (Unprivileged Execute-Never) bits in the page table descriptors. These bits allow system designers to explicitly mark memory regions as non-executable for privileged or unprivileged code, respectively. However, when the WXN bit is enabled, these descriptor fields are overridden for writable memory regions.


Resolving Permission Faults by Configuring Memory Regions and SCTLR_ELx

To resolve the permission fault and allow execution from a memory region that is also writable, the following steps can be taken:

  1. Review and Modify Page Table Descriptors: Ensure that the memory region is mapped with the appropriate access permissions and execute-never attributes. If execution from the region is required, the region should not be marked as writable (AP[2] == 1). Alternatively, if the region must remain writable, the PXN and UXN bits should be cleared to allow execution. However, this approach should be used with caution, as it may introduce security risks.

  2. Configure the SCTLR_ELx.WXN Bit: If the system design requires execution from writable memory regions, the WXN bit in the SCTLR_ELx register should be cleared (set to 0). This disables the enforcement of execute-never policies for writable memory regions. The following assembly code demonstrates how to modify the SCTLR_EL1 register:

    MRS X0, SCTLR_EL1        // Read the current value of SCTLR_EL1
    BIC X0, X0, #(1 << 19)   // Clear the WXN bit (bit 19)
    MSR SCTLR_EL1, X0        // Write the modified value back to SCTLR_EL1
    

    Note that modifying the WXN bit may have broader implications for system security, and the change should be carefully evaluated in the context of the overall system design.

  3. Use Separate Memory Regions for Code and Data: A more secure and maintainable approach is to use separate memory regions for code and data. Code regions should be mapped as read-only and executable, while data regions should be mapped as writable and non-executable. This separation ensures that the processor’s memory protection mechanisms are used effectively without compromising security.

  4. Leverage ARM Architecture Documentation: Refer to the ARM Architecture Reference Manual (ARM DDI 0487I.a) for detailed information on memory management and protection mechanisms. Key sections include:

    • Page D8-5136: Access Permission (AP) bits and their encoding.
    • Page D8-5142: Preventing execution from writable locations and the role of the WXN bit.
    • Page D17-5657: Exception class 0b100001 (Instruction Abort without a change in Exception level).
    • Page D17-5680: Instruction fault status code 0b001111 (Permission fault, level 3).

By carefully configuring the memory regions and the SCTLR_ELx register, the permission fault can be resolved while maintaining the desired functionality and security of the system. However, any changes to the memory protection settings should be thoroughly tested and validated to ensure they do not introduce vulnerabilities or unintended behavior.


In summary, the permission fault observed when executing code from a writable memory region is a result of the ARM architecture’s security mechanisms, specifically the interaction between the access permissions and the SCTLR_ELx.WXN bit. By understanding and configuring these mechanisms appropriately, the fault can be resolved while maintaining the integrity and security of the system.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *