RFC: Memory Protection Features
Posted: Thu Oct 09, 2014 4:05 pm
This is a request for comments and to see how much interest there is out there on these topics. I have written some modules that improve the penetration-resistance of my ChibiOS-enabled project, and I want to see how much interest there is in generalizing them for other users. My host processor is an STM32F4-series part.
I've added runtime support for the GCC stack canary (-fstack-protector). Very early in CRT startup (as a global constructor) the hardware random number generator is used to draw a random number for the stack canary. In the event that the RNG doesn't work in some way, the values \0, \r \f and (signed char)-1 are used, since they typically terminate the various C string handling functions.
I set up the Cortex-M MPU to enable W^X (write xor execute) support as well as make NULL inaccessible. In the absense of a specific flag telling GCC otherwise, GCC will assume that any accesses to NULL cause a fault, and may elliminate "dead" code based on that assumption. Of course, on STM32 (and possibly other Cortex-M processors) there is ordinary accessible data at NULL. A number of bugs in the Linux kernel were exploited due to this mismatch between hardware and the language model.
Finally, W^X works by making most of the general-purpose RAM non-executable on STM32. The CCM is already no-execute. A separate slice of RAM is marked executable and readable after loading it from a section called "ramtext", so that I can mix code in RAM with code in flash. Otherewise, the remainder is readable, writable, and non-executable.
Alas, most of my code at this point is highly processor-specific. W^X relies on programming the Cortex-M MPU, and stack protection relies entirely on the STM32F4 FWLIB and that part's hardware RNG. But these features aren't isolated to STM32, and other users may want it.
I've added runtime support for the GCC stack canary (-fstack-protector). Very early in CRT startup (as a global constructor) the hardware random number generator is used to draw a random number for the stack canary. In the event that the RNG doesn't work in some way, the values \0, \r \f and (signed char)-1 are used, since they typically terminate the various C string handling functions.
I set up the Cortex-M MPU to enable W^X (write xor execute) support as well as make NULL inaccessible. In the absense of a specific flag telling GCC otherwise, GCC will assume that any accesses to NULL cause a fault, and may elliminate "dead" code based on that assumption. Of course, on STM32 (and possibly other Cortex-M processors) there is ordinary accessible data at NULL. A number of bugs in the Linux kernel were exploited due to this mismatch between hardware and the language model.
Finally, W^X works by making most of the general-purpose RAM non-executable on STM32. The CCM is already no-execute. A separate slice of RAM is marked executable and readable after loading it from a section called "ramtext", so that I can mix code in RAM with code in flash. Otherewise, the remainder is readable, writable, and non-executable.
Alas, most of my code at this point is highly processor-specific. W^X relies on programming the Cortex-M MPU, and stack protection relies entirely on the STM32F4 FWLIB and that part's hardware RNG. But these features aren't isolated to STM32, and other users may want it.