简体   繁体   English

使用 ARM Cortex-M MPU 的 NULL 指针保护

[英]NULL pointer protection with ARM Cortex-M MPU

The MPU in ARM Cortex-M (M0+/M3/M4/M7/etc.) is often advertised as allowing to set up protection against dereferencing the NULL pointer. ARM Cortex-M(M0+/M3/M4/M7/等)中的 MPU通常被宣传为允许设置防止取消引用 NULL 指针的保护。 But how to do this in practice?但如何在实践中做到这一点? (Some online discussions, like in the Zephyr Project , indicate that the issue is not quite trivial.) (一些在线讨论,如 Zephyr 项目中的讨论,表明该问题并非微不足道。)

I'm looking for the simplest possible MPU code running in "Privileged mode" on bare-metal ARM Cortex-M.我正在寻找在裸机 ARM Cortex-M 上以“特权模式”运行的最简单的 MPU 代码。 Please note that "protection against dereferencing the NULL pointer" means to me protection both against reads and writes.请注意,“防止取消引用 NULL 指针”对我来说意味着防止读取和写入。 Also, it is not just about the address 0x0, but small offsets from it as well.此外,它不仅与地址 0x0 有关,还与它的小偏移量有关。 For example, accessing a struct member via a NULL pointer should also cause MPU exception:例如,通过 NULL 指针访问结构成员也应该导致 MPU 异常:

struct foo {
    . . .
    uint8_t x;
};
. . .
uint8_t x = (*(struct foo volatile *)NULL)->x; // should fail!

After some experimentation, I've come up with the MPU setting that seems to work for most ARM Cortex-M MCUs.经过一些实验后,我提出了似乎适用于大多数 ARM Cortex-M MCU 的 MPU 设置。 Here is the code (using the CMSIS):这是代码(使用 CMSIS):

/* Configure the MPU to prevent NULL-pointer dereferencing ... */
MPU->RBAR = 0x0U                          /* base address (NULL) */
            | MPU_RBAR_VALID_Msk          /* valid region */
            | (MPU_RBAR_REGION_Msk & 7U); /* region #7 */
MPU->RASR = (7U << MPU_RASR_SIZE_Pos)     /* 2^(7+1) region, see NOTE0 */
            | (0x0U << MPU_RASR_AP_Pos)   /* no-access region */
            | MPU_RASR_ENABLE_Msk;        /* region enable */

MPU->CTRL = MPU_CTRL_PRIVDEFENA_Msk       /* enable background region */
            | MPU_CTRL_ENABLE_Msk;        /* enable the MPU */
__ISB();
__DSB();

This code sets up a no-access MPU region #7 around the address 0x0 (any other MPU region will do as well).此代码在地址 0x0 周围设置了一个不可访问的 MPU 区域#7(任何其他 MPU 区域也可以)。 This works even for the MCUs, where the Vector Table also resides at address 0x0.这甚至适用于 MCU,其中向量表也位于地址 0x0。 Apparently, the MPU does not check access to the region by instructions other than LDR/STR, such as reading the vector address during Cortex-M exception entry.显然,除了 LDR/STR,MPU 不会检查对该区域的访问,例如在 Cortex-M 异常进入期间读取向量地址。

However, in case the Vector Table resides at 0, the size of the no-access region must not contain any data that the CPU would legitimately read with the LDR instruction.但是,如果向量表位于 0,则不可访问区域的大小不得包含 CPU 可以使用 LDR 指令合法读取的任何数据。 This means that the size of the no-access region should be about the size of the Vector Table.这意味着不可访问区域的大小应该大约是向量表的大小。 In the code above, the size is set to 2^(7+1)==256 bytes, which should be fine even for relatively small vector tables.在上面的代码中,大小设置为 2^(7+1)==256 字节,即使对于相对较小的向量表也应该没问题。

The code above works also for MCUs that automatically relocate the Vector Table, such as STM32.上面的代码也适用于自动重定位向量表的 MCU,例如 STM32。 For these MCUs, the size of the no-access region can be increased all the way to the relocated Vector Table, like 0x0800'0000 in the case of STM32.对于这些 MCU,不可访问区域的大小可以一直增加到重定位的向量表,例如 STM32 中的 0x0800'0000。 (You could set the size to 2^(26+1)==0x0800'0000). (您可以将大小设置为 2^(26+1)==0x0800'0000)。

Protection against NULL-pointer dereferencing is an important tool for improving the system's robustness and even for preventing malicious attacks.防止空指针取消引用是提高系统健壮性甚至防止恶意攻击的重要工具。 I hope that this answer will help fellow embedded developers.我希望这个答案能帮助嵌入式开发人员。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM