A pair of GCC plugins
Over the last year or more, multiple hardening features have made their way from the grsecurity/PaX kernels into the mainline under the auspices of the Kernel Self Protection Project. One that was added for the 4.8 kernel is the GCC plugin infrastructure that allows processing kernel code during the build to inject various kinds of protections. Several plugins have been merged, most notably the latent_entropy plugin for 4.9. Two other plugins have recently been proposed: kernexec for preventing the kernel from executing user-space code and structleak to clear structure fields that might be copied to user space.
kernexec
If the kernel is tricked into executing user-space memory, that can be used by attackers to subvert the system. An attacker can run the code of their choice with the kernel's privileges. So the ability to prevent that is an important hardening feature that is implemented in hardware as Supervisor Mode Execution Protection (SMEP) on some Intel CPUs and as Privileged Access Never (PAN) on some ARM systems.
For those x86_64 systems that lack SMEP, though, kernexec can provide much the same protection. In mid-January, Kees Cook posted an initial version of the kernexec plugin. The plugin changes the kernel so that, at run time, addresses used to make C function calls always have the high bit set. All kernel functions reside in the kernel address space, which has the high bit set. Since the Linux kernel will never map user-space memory at addresses with the high bit set, attempts to run user-space code by overwriting addresses to point into user space will fail. Instead of executing code at the address arranged for by the attacker, the plugin arranges to trigger a general protection fault instead. Similarly, return addresses are forced at run time to have the high bit set before the return instruction is executed.
The performance impact of kernel hardening efforts is always a concern, so the plugin attempts to optimize the calls and return instructions. If a register is available, the call site simply does a logical-or of the address and 0x8000000000000000 that it loads into the register. For the return, it uses a bit-set instruction (btsq) to set the high bit of the return address on the stack.
Cook notes that there is "significant coverage missing
" with
this version of the plugin. It is missing the assembly language
pieces, which means that assembly code can still make calls into
or return to user-space addresses. That infrastructure still needs to be
ported over from PaX, he said.
structleak
Kernel structures (or fields contained within them) are often copied to user space. If those structures are not initialized, though, they can contain "interesting" values that have lingered in the kernel's memory. If an attacker can arrange for those values to line up with the structure and get them copied to user space, the result is a kernel information leak. CVE-2013-2141 was a leak of that sort; it led "PaX Team" (who develops the PaX patch set) to create the structleak plugin.
Cook also posted a port of that plugin to the kernel mailing list on January 13. It looks for the __user attribute (which is an annotation that is used to indicate user-space pointers) on fields in structures declared as variables local to a function. If those variables are not initialized (thus would still contain "garbage" from the stack), the plugin zeroes them out. In that way, if those values get copied to user space at some point, there will be no exposure of kernel memory contents.
PaX Team commented on the patch posting, mostly suggesting tweaks to some of the text accompanying the plugin. In particular, Cook had changed the description of the plugin in the Kconfig description from what is in PaX. However, Cook had reasonable justifications for most of those changes.
In addition,
the wording of a Kconfig option that turns on verbose mode for structleak
(GCC_PLUGIN_STRUCTLEAK_VERBOSE) did not meet with PaX Team's approval.
It notes that false positives can be reported since "not all
existing initializers are detected by the plugin
", but PaX Team
objected to that characterization: "a variable either has a
constructor or it does not ;)
". But Cook looks at things a bit
differently:
Beyond wording issues, though, as Mark Rutland pointed out, the __user annotation is not a true indication that there is a problem:
He suggested that analyzing calls to copy_to_user() and friends
might allow better detection. PaX Team agreed, but said that the original idea was to
find a simple pattern to match to eliminate CVE-2013-2141 and other, similar
bugs. Now that the bug is fixed, it is unclear if the plugin is actually
blocking any problems, but
there is little reason not to keep it, PaX Team said: "i keep this plugin around because
it costs nothing to maintain
it and the alternative (better) solution doesn't exist yet.
"
These are both fairly straightforward hardening features that may prevent kernel bugs from being (ab)used by attackers. Structleak may not truly be needed at this point, but new code could introduce a similar problem and the plugin is not particularly intrusive. Kernexec, on the other hand, has the potential to stop attacks that rely on the kernel executing user-space code in their tracks. While both plugins have existed out of tree for some time, getting them upstream so that distributors can start building their kernels that way, thus get them in the hands of more Linux users, can only be a good thing. Hopefully we will see some of the others make their way into the mainline before too long as well.
| Index entries for this article | |
|---|---|
| Kernel | Build system/GCC plugins |
| Kernel | Security/Kernel hardening |
| Security | Hardening |
| Security | Linux kernel |
