|
|
Log in / Subscribe / Register

A pair of GCC plugins

By Jake Edge
January 25, 2017

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:

Well, as pointed out, there are plenty of false positives where the [plugin] reports the need to initialize the variable when it doesn't. It doesn't report that it's missing a constructor. :) This is a pragmatic description of what is happening, and since the plugin does sometimes needlessly insert initializations where none are needed, that really seems like a false positive to me. :)

Beyond wording issues, though, as Mark Rutland pointed out, the __user annotation is not a true indication that there is a problem:

To me, it seems that the __user annotation can only be an indicator of an issue by chance. We have structures with __user pointers in structs that will never be copied to userspace, and conversely we have structs that don't contain a __user field, but will be copied to userspace.

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
KernelBuild system/GCC plugins
KernelSecurity/Kernel hardening
SecurityHardening
SecurityLinux kernel


to post comments

A pair of GCC plugins

Posted Jan 26, 2017 1:41 UTC (Thu) by spender (guest, #23067) [Link] (15 responses)

PXN would be the ARM equivalent, not PAN. Also the description of the KERNEXEC plugin is wrong and mimics the wrong description provided by Kees for the upstream kernel (modified from what was correctly written in PaX, though actually, Kees' description is even more incorrect). The reason for the GPF (as opposed to some simple non-present page fault) also isn't explained. The or/bts explanation is wrong. Lack of assembly modifications results in more than just missing coverage too. Kees' revisions of the STRUCTLEAK documentation are wrong as well, presumably you echoed that they were "reasonable" because the PaX Team didn't yet respond to that particular part of the mail (he has real work to do, after all, on something I should very much hope LWN writes about when it is released). The use of 'several' while technically correct suggests more plugins than 3, two of which are trivial.

This is all old news though, personally I think the more important news is that after over more than a year, the KSPP took a break from plagiarizing and finally contributed code back to grsecurity for the first time: an incomplete typo fix to an error message no one has ever seen in real life. It's great that they care about the long-term survivability of our work, despite the fact that they can totally exist independently and don't need the PaX Team to spoon-feed them details about how the code they're copy+pasting works.

-Brad

A pair of GCC plugins

Posted Jan 26, 2017 6:38 UTC (Thu) by zyzzyva (guest, #107472) [Link] (14 responses)

Kees' description of the KERNEXEC plugin is actually pretty good, as far as I can tell. The reason for the fault is that setting the high bit on any userspace address will produce a non-canonical address, i.e. an address whose bits 48-63 are not the same as bit 47, which in Linux is 0 for all userspace addresses. I actually think it's the description for the PaX config option that's incorrect, since it claims that the pointers will "fall into kernel memory" which isn't the case. A non-canonical address is simply considered invalid by the CPU; it's neither a userspace address nor a kernel address.

The patch could maybe use a mention of the "OR" and "BTS" instrumentation methods and how only "BTS" is being proposed to be turned on upstream --- which I think is where some of your commentary comes from, though it isn't clear when you simply say things are "wrong", without saying how. As far as I can tell, the important difference between the two methods isn't fully reflected in their names; the difference is actually that the "OR" instrumentation reserves register r12 in all kernel code to hold the value 1<<63 which can then be OR'ed with code pointers, while the "BTS" instrumentation does not reserve a register and therefore needs to load 1<<63 as an immediate and OR it with the pointer (as it does for calls; or rather, it uses a higher-level expression which gcc tends to compile as that) or use 'btsq' to set bit 63 of the pointer (as it does for returns).

At first impression I think that it's kind of insane to reserve r12 everywhere just to hold a constant just for a (quite small, I expect) performance improvement. I can see that in grsecurity/PaX it required a lot of hacks to change assembly code using r12 to use some other register instead, it also makes the kernel incompatible with binary-only modules. It maybe makes more sense in the context of the grsecurity patch, but I don't think it would be a very maintainable solution for upstream. Of course, at the risk of me getting flamed for saying this, if you and/or PaX Team have good arguments otherwise, I'd encourage you to clearly advocate for them on the mailing lists, which is where patches actually get proposed and reviewed. Vague complaints on LWN are, from a technical perspective, simply not as effective at helping make Linux more secure.

A pair of GCC plugins

Posted Jan 27, 2017 1:14 UTC (Fri) by spender (guest, #23067) [Link] (13 responses)

Well if it's pretty good as far as you can tell, there's no need for me to correct you then is there? ;) I'll then ignore your bogus performance claims (gee, who would know better about that one, an armchair expert or someone who wrote the code and ran the actual benchmarks?), UB, misunderstanding of the documentation (your addition of 'will' changes the intended meaning), not understanding how the 'OR' method works (it doesn't require reserving r12 'everywhere'), missing that the 'OR' method can be made trivially compatible with binary modules if the whole point of the method wasn't performance, etc, since clearly you know better than the person who wrote the plugin in the first place.

For your final comment (and re: vague complaints): https://lwn.net/Articles/706310/

Finally, congrats on your first LWN comment after subscribing in March -- how much is the Linux Foundation paying you? Clearly they should be paying more for someone who's written as many GCC plugins as you to maintain the ones KSPP currently is responsible for, and which KSPP members are completely inept at maintaining themselves ;)

-Brad

A pair of GCC plugins

Posted Jan 27, 2017 21:02 UTC (Fri) by mtanski (guest, #56423) [Link] (12 responses)

Wow, the toxicity of comments on this thread has escalated quickly.

A pair of GCC plugins

Posted Jan 27, 2017 22:32 UTC (Fri) by spender (guest, #23067) [Link] (11 responses)

Thank you for your technical and informative contribution. Feel free to read this: https://lwn.net/Articles/711694/ and add me to your killfile of choice in the future, to spare me your pointless tone arguments.

-Brad

A pair of GCC plugins

Posted Jan 27, 2017 23:02 UTC (Fri) by jake (editor, #205) [Link] (9 responses)

Hey Brad,

Maybe you could spare all of us your endless vitriol? Not all readers have the ability to do comment filtering. Consider this particular 'tone argument' to be a request from one of the editors of the site to stop the attacks on people and ideas you disagree with. Disagreeing is fine, do so politely and respectfully please.

thanks!

jake

A pair of GCC plugins

Posted Jan 27, 2017 23:24 UTC (Fri) by spender (guest, #23067) [Link] (8 responses)

Hi Jake,

That's fine, this will be my last comment on this site then, as you've made clear to me you'd prefer LWN to be a site for armchair experts to spread misinformation. I can't help but feel though that you're making this personal attack because it was your article in question that was filled with factual errors. Of course that makes me wonder: if the only method LWN employs in publishing "news" is to repeat misinformation and not bother to reach out to primary sources to ensure the accuracy of that information, and if the editor must surely know he's out of his depth in evaluating the correctness of that information, what purpose does its articles serve? Clearly it's not to increase readers' knowledge, as it's providing them with false information. So I really do wonder what purpose they're supposed to serve other than advertisement. I hope one day you're able to achieve your goal of having no one on this site attack ideas they disagree with and that everyone can peacefully come together to agree on the same set of misinformation produced by whatever company happens to be funding your trips the most.

Goodbye and good luck.

-Brad

A pair of GCC plugins

Posted Jan 28, 2017 0:01 UTC (Sat) by corbet (editor, #1) [Link] (7 responses)

Oh please.

Nobody is asking you not to disagree. Jake was quite clear on that. You're just being asked to be a bit more adult about it. If that makes you take your marbles and go home then so be it, but that was not actually the intent.

A pair of GCC plugins

Posted Jan 31, 2017 23:16 UTC (Tue) by paulj (subscriber, #341) [Link] (6 responses)

What a sad situation.

That Brad mentions "free work" and money a few times, suggests the lack of funding is at least partially an issue here. That LF is paying people to take his (their? /me unsure of how many people PaXTeam are) work and port it to L-K strongly suggests there is value in that work.

Someone should really find a way to make the source of these clearly valuable security patches happy (happier anyway), despite the clear chip on his/their shoulder (which LF paying others to port their work can only magnify - greatly).

:(

A pair of GCC plugins

Posted Feb 1, 2017 16:05 UTC (Wed) by raven667 (subscriber, #5198) [Link] (5 responses)

> Someone should really find a way to make the source of these clearly valuable security patches happy

I don't think that's possible, the conflict is pretty fundamental, if rational discourse and compromise could have fixed it it would have done so by now.

A pair of GCC plugins

Posted Feb 2, 2017 11:52 UTC (Thu) by paulj (subscriber, #341) [Link] (4 responses)

I'm not suggesting the existing bad feelings can be fixed. I'm suggesting the generation of _further_ bad feelings (and deepening problems) can be avoided.

Seriously, people are paying _other_ people to work on Brad (et al?)'s work, but not him (them?). Fairly obvious this can only increase bad will.

A pair of GCC plugins

Posted Feb 2, 2017 14:33 UTC (Thu) by pabs (subscriber, #43278) [Link] (3 responses)

In addition, the money is coming from the Linux Foundation, an organisation Brad has stated he would not take money from.

A pair of GCC plugins

Posted Feb 3, 2017 12:35 UTC (Fri) by tao (subscriber, #17563) [Link] (2 responses)

So, to summarise the situation:

A does a great job doing something.
A' does a similar job OK:ish, mostly based on the job of A.
B needs that job done and offers money to have it done.
A refuses to work for B.
B still needs that work done, and contracts A' to do it instead.
A complains that no one offers to pay him to do the job, and that A' is doing a shitty job.

A pair of GCC plugins

Posted Feb 3, 2017 13:25 UTC (Fri) by paulj (subscriber, #341) [Link] (1 responses)

Well, it's not clear to me that "A refuses to work for B" happened after "B contracts A' to do it". It may be that A took their "A refuses to work for B" position _because_ B went and contracted someone else (A') to work on their work.

Be interesting if someone knows for sure.

It is still a sad and unproductive state of affairs. The work of A (don't want to write "A's work" given the notation you've chosen ;) ) clearly has a lot of value.

A pair of GCC plugins

Posted Feb 3, 2017 13:25 UTC (Fri) by paulj (subscriber, #341) [Link]

Sorry, in the first sentence "happened after" should obviously be "happened before".

A pair of GCC plugins

Posted Feb 3, 2017 0:44 UTC (Fri) by zlynx (guest, #2285) [Link]

Yes, I've been ignoring you for years now.

A pair of GCC plugins

Posted Jan 26, 2017 21:09 UTC (Thu) by quotemstr (subscriber, #45331) [Link] (1 responses)

How much trouble would it be to initialize *all* structs and variables to zero when not otherwise initialized? All of these things should be cache-hot anyway.

A pair of GCC plugins

Posted Feb 2, 2017 17:38 UTC (Thu) by Wol (subscriber, #4433) [Link]

What happens if you make a mistake, and zero a struct that's already been initialised?

And doing extra unnecessary work ALWAYS has a cost. The kernel guys are hot on unnecessary work. (Not always in a sane way, I don't think, but the mindset of "machines are powerful, who cares about cost" is imho a very bad - and far too prevalent - one.)

Cheers,
Wol


Copyright © 2017, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds