Linux 3.4+: arbitrary write with CONFIG_X86_X32 (CVE-2014-0038)
seclists.org
seclists.org
http://en.wikipedia.org/wiki/X32_ABI
an application binary interface project for Linux that allows programs to take advantage of the benefits of x86-64 (larger number of CPU registers, better floating-point performance, ... ) while using 32-bit pointers and thus avoiding the overhead of 64-bit pointers
Code running in 32-bit protected mode can't access 64-bit instructions or registers, of course, but that's a different issue. x32 is basically just long mode code that limits itself to instructions that use 32-bit addresses.
BITS 32
start:
call far 0x33:code64
code32:
nop ; resume
code64:
BITS 64
xor rax, rax
BITS 32
retf ; return to 0x23:code32That's what I was referring to - in 16-bit realmode you can use 32-bit registers and addressing modes with prefix bytes just like you can use 16-bit operands or addresses in 32-bit mode, and in protected mode both 16 and 32-bit segments can coexist in the same system. But it looks like 64-bit is completely isolated from that, although they could've used some other prefices, enabling access to 64-bit operands (including the extra registers) and addresses from any mode, and also allow coexistence of 64-bit segments with existing 32- and 16-bit segments. Then x32 wouldn't really need to exist; it would just be a 32-bit segment with instructions that use 64-bit operands.
Debian has some work in progress on a port to x32 here: https://wiki.debian.org/X32Port
But it looks like they had the foresight to disable it for regular kernels because of security concerns: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=708070#10
- if (get_compat_timespec(&ktspec, timeout))
+ if (compat_get_timespec(&ktspec, timeout))
return -EFAULT;
Sighhttps://bugs.launchpad.net/ubuntu/+source/linux/+bug/1274754
-Brad
<grsecurity> If you're running Linux 3.4 or newer and enabled CONFIG_X86_X32 , you need to disable it or update
immediately; upstream vuln CVE-2014-0038
and <grsecurity> In case there's confusion, this vuln is not about 32bit userland on 64bit (CONFIG_X86_32), but the new X32
ABI. Ubuntu enables it recently
Does the second line affect the first? EDIT: I ask because it looks like I need to fix my kernel, but I'd rather be lazy if possible.Most distros don't use it, most don't even offer an x32 install image, but if they enable the kernel option for the x32 abi even without intending to use it, they're vulnerable.
If you're using the x32 abi, either you're using it on purpose, or your distro happens to offer an x32 install image and you downloaded it by accident instead of the normal 32-bit image you probably wanted. In all other cases it should be safe enough to disable the kernel option.
The first one, with the second X, enables the new X32 ABI. The second one, without the second X, is the "32bit userland on 64bit".
So far though, I haven't seen anything about merging in the patch provided by PaX.
edit: It doesn't appear there is. Not shocking, but I was hoping for a bit of luck.
That said, this is a local exploit, so unless you have untrusted users or otherwise run untrusted native code, your risk is pretty low. Someone would have to exploit something else first to get access to run custom code on the box.
At this level, you're dealing with an API at the calling end (you should be fairly intimately familiar with the semantics without much reference to the docs if you're working on the implementation) and the functions being calling are almost readable as English.
Code should strive to be written such that it doesn't need comments unless it's being clever - and it should avoid being clever if possible.
Also, I'm not sure where you saw a "wall of code". I don't see any walls of code, not in the commit diff, nor in the smaller diff in the email. A wall of code, for me, would have to be long (say, 70+ lines - but it depends on the language) and dense (e.g. boolean expressions complex enough to need parentheses to clarify precedence).
"you should be fairly intimately familiar with the semantics" - do you see a problem bootstrapping that on an obscure code base?
No, I don't. It just requires that you can read C and understand it. Any large codebase (in whatever language) is going to require you to understand certain semantics and idioms, and it doesn't make any sense to document those idioms every single place you use them. Big codebases require context and a comment in some random function isn't going to give you enough context unless it was a tome.
Also, did you see the 2 patches linked in the bug report? They significantly changed the code. C is just like that. It's an environment ripe for comment bitrot. And the only thing worse than no comments is incorrect comments.
In the end, the code is what matters. If you can read it, you can understand it.
The only thing worse about something is the preconceived idea that there is indeed only a _single_ thing worse - all the rest being better or equal.
No, worse than missing comments is also _bad code_ which was the case here. And bad attitudes like "my code is prone to bit rot so I won't comment it" or "my code is self-explanatory so I won't comment it" or worse "my code is so special and super optimized and smart that I will not comment it so only super special guys will be able to modify it". And also "I'm a kernel maintainer so I don't have to comment anything"
Have you actually ever programmed anything for Linux kernel? What have you programmed that would be relevant and give the weight to your (for me dubious) claims?
That's not to say that nobody else has made this mistake or that it won't be made again by otherwise capable programmers. One can talk about this as bad code while still having sympathies for the error. Hate the sin, not the sinner.
The deeper issue is about code as it is communicated to the next developer. For various reasons (most - me included) developers do not talk to the next developer but to the compiler. And some other guy comes later who doesn't know about copy_to/from_user shit because he is not exposed to the internals.
He might be competent programmer but he lacks exposure. He might also be able to see in a second the dereference but when he is reviewing the code, he keeps a stack of several levels of irrelevant contexts that blurred his view.
He could have avoided all that if only the code was being written with him in mind.
Edit: Re-reading your comment I also wanted to point out that the problem of handling user mode pointers in a kernel is a difficult one, and requires discipline. You can't keep a straight face and say as you do that you can handle it in a way that newbies can come right in and write bug free code without learning these conventions. The only sane way is to create a workable set of conventions, apply them consistently, and do what you can to educate new contributors as they come along. It's not unique to Linux - I used to work at MS and can tell you the NT kernel has the same issues.
This particular piece of code is simple and easy to understand and follow. The function is small - you can take a few hours and understand the stack.
The point is, you have to play the compiler game in order to understand. The original coder is not helping you in any way. It doesn't give you any context. Where's the place of this (any) function? Why was it written in the first place? What problem is it trying to solve?
There are some things that the code alone can't tell. Because the code talks to the compiler and the compiler doesn't care about context - people do. And people understand either by taking the hard way (playing the compiler game - having to jump back & forth) or talking to a human. And the code comments are the best that you can get short of talking directly to the developer.
I'm all about leaving code maintainable for the next guy, however I think we disagree about what that means. To me, it's largely about writing your code in consistent patterns that make certain classes of bug "pop out" at you (because doing things that way would stand out and look like a break from the convention).
However as a practical concern, if you're writing kernel code you shouldn't assume your future maintainers don't know about the distinction between user and kernel address spaces. And you shouldn't have to be very detailed about every small little compatibility shim you write - if compat_sys_recvfrom does very little else but call sys_recvfrom without much comment or fanfare that is OK by me (keep in mind there's going to be one of these wrappers for almost every syscall).
I for one would draw the line before (4). The original developer drew it after. If I would explain API conventions I would draw it before (3) but crypto _API_ for example has the line after (4). And there are appropriate places for (1) and (2) also.
The point is, you address to some audience. But even if the code is clean, a newcomer will have a hard time getting up to speed if he has no idea about the context. The way I see it, for some parts of the kernel, either the code is too precious to be touched or the maintainers do not have any interest in explaining it to an outsider. It's like they are loosing knowledge by sharing.
Think new comers. How can you make them contribute? Or maybe the barrier to entry is high enough on purpose?
Now, I don't have to show you anything. What are you talking about?
Do you dismiss me because I extrapolate developer attitudes from their obtuse/obscure code (dubious/discuss) or because I can't keep a stack of callbacks in my mind to get myself out of the maze (true by the way)?
But what about that function? It has 5 arguments! Do you claim that they need no explanation whatsoever? And don't cheat. Tell me without looking what is "type" suppose to contain?
Relevant quote: "The ideal number of arguments for a function is zero (niladic). Next comes one (monadic), followed closely by two (dyadic). Three arguments (triadic) should be avoided where possible. More than three (polyadic) requires very special justification—and then shouldn’t be used anyway."
Haven't read that book, but color me neon skeptical.
1. Those that return the same result every time.
2. Those that mutate some internal state (or, roughly equivalently, those that inspect internal state being mutated elsewhere).
#1 isn't all that useful in general, although there are obviously cases where it's exactly what you want. For #2, while state is useful at times and a necessary evil in many other cases, it's hardly ideal.
Even a single parameter seems decidedly un-ideal. To do useful work in general, you're typically going to want to take two parameters: something to be modified, and the modification to make. This can be done with state (modify in place) or functionally (return a new object with the modifications applied). Once again, having a single argument seems to imply either something not very useful (basically a getter or some similar derive-a-value function) or something relying on mutable state. You need two arguments to achieve the sort of combinatorial power that makes functions interesting and properly useful.
So if you're converting that rule back to C, you'd need to add one to each element of the rule. The one parameter rule is saying that when special cases are common, a special function to handle it is a good thing. So writing `i++` rather than `i = i + 1` or `next(node)` rather than `skip(node,1)`.
The second mmsg parameter points to an array of compat_mmsg objects. In C, the array length must be passed as a separate parameter, so the second and third parameters are really one logical array parameter.
Well I don't know, let's see some code for postgresql, a quite large C codebase. I took this file at random:
https://github.com/postgres/postgres/blob/master/src/pl/plpg...
So assuming "what you know" means the same as "what is the best" is probably not a good idea.
It strikes me as kind of uninteresting glue code written for compatibility with a non-native ABI. The kind that gets repetitive if you're not terse.
Sparse code is not necessarily self-explaining.
Why is this obvious? I can extrapolate on sys, but what cues are in 'compat' that I don't see?