Project Zero Exploits 'Unexploitable' Glibc Bug
NotInHere (3654617) writes with news that Google's Project Zero has been busy at work. A month ago they reported an off-by-one error in glibc that would overwrite a word on the heap with NUL and were met with skepticism at its ability to be used in an attack. Google's 'Project Zero' devised an exploit of the out-of-bounds NUL write in glibc to gain root access using the setuid binary pkexec in order to convince skeptical glibc developers. 44 days after being reported, the bug has been fixed.
They even managed to defeat address space randomization on 32-bit platforms by tweaking ulimits. 64-bit systems should remain safe if they are using address space randomization.
Actually, I find the arrogance of calling an obvious bug "unexploitable" disturbing.
Most ARM is 32 bit...
Wow, sent an e-mail as suggested when clicking on "use classic" banner, and got a fast response that addressed my msg
OpenBSD assumes all bugs are capable of being used, and they treat them as such.
CAN YOU HEAR ME NOW?? HELLO?
The word you're looking for is 'skeptical', and then they went and fixed it when they were proven wrong. This is actually the opposite of arrogant.
Never say never.
Unexploitable? Srsly? GAC.
An acquaintance recently posted "Six Stages of Debugging" on his g+ page. (1. That can't happen, 2. That doesn't happen on my machine, 3. That shouldn't happen, 4. Why does that happen? 5. Oh, I see, and 6. How did that ever work). Doesn't an software dev who has been working for more than about three years go straight to No. 4?
The things they don't teach you in a CS degree.
99 reasons not to use a 32BIT OS, even windows 32bit has issues not seen on the 64bit version thanks to a more advanced address space randomization...
Yup, time to dumb 32bit...
Has Drepper become a maintainer again?
I think that's the definition of the difference between being "paranoid" and being "observant."
But OpenBSD is being run by masturbating monkeys. Linus said so.
Embedded stuff would typically use uClibc. Android uses Bionic libc.
Most ARM might be 32 bit but most ARM doesn't use Glibc.
Meanwhile, slopping programming in any language results in unintended side effects.
The first part is arrogance. The second part is pragmatic humility.
You're right, I unfairly used summary words as quotes.
I read through the thread and at no point was the bug considered "Unexploitable". Even skepticism is too strong of a word to use. The only doubt that was raised was asking "How likely is that?"
Reminds me of this overflow bug which was fixed in sudo 1.6.3p6. It writes a single NUL byte past the end of a buffer, calls syslog(), and the restores the original overwritten byte. Seems unexploitable, right?
Wrong. Here's the detailed writeup of the exploit. It requires some jiggering with the parameters to get the exploit to work on a particular system, but you don't need a local root exploit to work every time, you just need it to work once and you own the system.
One that a slight slip anywhere in millions of lines of code could produce random memory corruptions with unpredictable consequences. Who would have believed that anybody would even dream of using a language with constructs such as ptr++. And we are surprised to find bugs...
We're talking about Google here. They use binary blobs and all sorts of non-free software and licensing. Plus they're generally creepy. So whatever they claim or even prove doesn't matter anyway. They don't exist. LALALA
The word you're looking for is 'skeptical', and then they went and fixed it when they were proven wrong. This is actually the opposite of arrogant.
They should have fixed the bug as soon as they realized it was there, and not waited until someone proved it was an especially bad bug.
"First they came for the slanderers and i said nothing."
At least OpenBSD wasn't stupid enough to include glibc in their OS.
Meanwhile, slopping programming in any language results in unintended side effects.
Yes, but the lack of bounds checking in C is kind of crazy. The compiler is now going out of its way to delete error-checking code simply because it runs into "undefined behavior," but no matter how obvious a bounds violation is, the compiler won't even mention it. Go ahead and try it. Create an array, index it with an immediate value of negative one, and compile. It won't complain at all. ...but god-forbid you accidentally write code that depends upon signed overflow to function correctly, because that's something the compiler needs to notice and do something about, namely, it needs to remove your overflow detection code because obviously you've memorized the C standards in their entirety and you're infallible, and there's no chance whatsoever that anyone ever thought that "undefined behavior" might mean "it'll just do whatever the platform the code was compiled for happens to do" rather than "it can do anything at all, no matter how little sense it makes."
Due to just how well GCC optimizes code, bounds checking wouldn't be a huge detriment to program execution speed. In some cases the compiler could verify at compile time that bounds violations will not occur. At other times, it could find more logical ways to check, like if there's a "for (int i = 0; i < some_variable; i++)" used to index an array, the compiler would know that simply checking "some_variable" against the bounds of the array before executing the loop is sufficient. I've looked at the code GCC generates, and optimizations like these are well within its abilities. The end result is that bounds checking wouldn't hinder execution speeds as much as everyone thinks. A compare and a conditional jump isn't a whole lot of code to begin with, and with the compiler determining that a lot of those tests aren't even necessary, it simply wouldn't be a big deal.
No.
Off by ones are much easier to fix than to prove safe. The amounts of bugs called "unexploitable" until an exploit was provided is staggering. No mildly security aware person will avoid fixing a buffer overflow because it is unexploitable.
Shachar
Protip: Your fancy "modern" language is written in this "crude" language.
Was the glibc boffin who said it looked unexpoitable just expressing a casual opinion, or was he actually trying to wriggle out of fixing it? If the former, then its not very interesting. If the latter, then yeah it's a problem.
My name is Joe Dangerous.
Not necessarily. The lambda calculus languages predate the procedural languages and object languages that are in wide use today. They were less efficient on older hardware so they never gained currency (there's also the theory that requiring an understanding of recursion instead of sequential programming was a barrier to adoption). But LISP can be used to create the C++ compiler, just as C++ can be used to create the LISP compiler.
Because all bugs that are found have the same priority, right?
They probably had a backlog of other bugs to fix (or features to work on), and put this one in the Severity 5 (Trivial) bucket. Once the exploit was discovered it then got moved into the Sev 1 bucket, i.e. the "Drop Everything and Fix this" bucket
Nope. My fancy modern language is written in said fancy modern language.
Anyone remember the poisoned NUL byte: http://www.ouah.org/nullbyte.html
While you have a point, you shouldn't forget the Raspberry Pi. It is probably the most popular internet facing non-mobile ARM platform today. Literally millions of these run glibc and at least hundreds of thousands are in some way or form directly connected to the internet. While I don't believe that this bug can be exploited without first gaining RCE on the raspberry pi, once an attacker gets access to the rpi, this bug should be able to get them to escalate to root privileges.
There are quite a few people that put a full debian (or other) distribution on their NAS server. I own a zyxel NSA 325 and it is possible to install a full debian release on this and some other NAS boxes. These might be a limited amount of systems overall, but it's significant enough to deserve mentioning because they too often are internet facing.
I was promised a flying car. Where is my flying car?
You can already ask some compilers to do what you are asking - it's just often not on in shipped builds.
At compilation time warnings can be generated for out of bounds accesses that can be determined statically. Clang has -fsanitize=bounds, GCC has -Warray-bounds.
As an Anonymous Coward pointed out, it can be hard to detect runtime allocations overruns at compilation time. For these something like Clang's AddressSanitizer (GCC has added it too will help but at a cost of both time (slow down factor of 2) and space which is why you're unlikely to find it enabled on your precompiled SSH server binary. It's true there are cheaper checks (such as GCC's FORTIFY_SOURCE) that are less thorough/specialized that are often enabled by distros.
It's an oldschool attitude to not touch things, from back in the day where software was so flaky that chances were someone had already 'exploited' the bug to do something non-malicious.
It drives me fucking crazy, having been born pretty much into the internet age where the corrected answer can be available in *seconds*. It's pretty obvious from the description what the bug is, so saying you aren't going to fix it is, as you say, pure laziness.
It's OK Bender, there's no such thing as 2.
At some point, you'll have to break that high level language down to opcodes the cpu can understand, that means breaking high level logic down to many simple steps, which is what procedural languages are for. You can force the programmer to write these steps one at a time in assembly, 'script' the generation of assembly in C, or have a runtime and/or VM do it at a cost of speed and footprint, but there is no magical way to skip generating that list of procedures.
It's an oldschool attitude to not touch things, from back in the day where software was so flaky that chances were someone had already 'exploited' the bug to do something non-malicious.
Ah, that actually makes sense, good analysis.
. It's pretty obvious from the description what the bug is, so saying you aren't going to fix it is, as you say, pure laziness.
This sort of thing worries me about glibc, and the attitude that 'bugs are no big deal' is a dangerous one that is infecting software developers all over.
"First they came for the slanderers and i said nothing."
Protip: Your fancy "modern" language is written in this "crude" language.
Even if a compiler for a "fancy" safe language were written with a "crude" unsafe language, it would still be just one program to verify for ptr++ kind of bugs. Additionally, a compiler is a classical input -> output kind of non-interactive program, which yields itself very well for running under verification tools like valgrind, which increases confidence that at least for any given input, it will not do nasty things.
64-bit systems should remain safe if they are using address space randomization.
Nah. It just takes more crashes before the exploit achieves penetration.
(Address space randomization is a terrible idea. It's a desperation measure and an excuse for not fixing problems. In exchange for making penetration slightly harder, you give up repeatable crash bug behavior.)
Which one is that?
Haskell, Python, PHP, Perl all end up in either compilers or interpreters written in C.
This is a C library.
Even if you wrote all your programs in python, the runtime library at some point will be implemented in C or assembler.
So you would have the same problem.
It's an oldschool attitude to not touch things, from back in the day where software was so flaky that chances were someone had already 'exploited' the bug to do something non-malicious.
That problem is still prevalent today. Since there are a lot of people who considers the source code and the API description to be sufficient documentation one can't assume that the users can make a good distinction between what is bugs and what is features.
If intentional side effects aren't documented then all side effects will be assumed to be intentional.
If intended usage isn't documented then all possible ways to use the function will be used.
And 3 of my phones.
N900, N9 and Jolla all use glibc.
Watch this Heartland Institute video
The OpenBSD philosophy says that the difference between a bug and a vulnerability is the intelligence of the attacker. There are lots of categories of bugs (null pointer dereferences, integer overflows) that were thought to be unexploitable, right up until someone exploited them. It's the same as with cryptosystems: the fact that you can't break your encryption algorithm doesn't mean that it's secure.
I am TheRaven on Soylent News
What high-level language does not depend on the C standard library and so would be suitable for implementing the C standard library?
I am TheRaven on Soylent News
I felt very old, seeing the -almost- standard assembler practices called old school. When I was young, most CPUs had lots of undocumented instructions, usually due to overuse of Karnaugh. Given the basic electronic structures are still the same, I have a strong suspicion, that position still holds true...
The first part is also pragmatic. Releasing a security fix is a lot of work, not just for the developers, but also for everybody else. So you only do that if you have reasonable suspicion that the bug is a security risk. They were good reasons to believe that it is not the case here, although in the end they did not apply in every situation.
If you treat every bug as a security issue, you end up with the Google situation where only one version, the latest, is ever supported. And for libc that is not an acceptable option.
This clearly shows that any bug is a potentially security bug. It is just that some are a lot more obviously exploitable than others. A memory leak used to fill the heap so that it meets the stack?!
Three important facts to learn from this:
1. ulimit and setuid/setgid don't mix well. This one we need to fix in the general case, adding some extra limits to the ulimits(!) so that they cannot be too small. setuid/setgid already ignores a lot of crap from the linker.
2. complicated libraries are for the desktop bling and have no place in tooling and pumbling. If it is setuid/setgid, it cannot link to complicated crap like full glib, we need a *safe subset* of these libraries, properly lobotomized to be safe to use in sensitive security scenarios like setuid/setgid.
3. *any* bug in a setuid/setgid binary is a security bug.
Sorry, old Unix guy here. My first reaction was "What the F is pkexec and why is it running setuid?"
Yet another way to execute arbitrary privileged executables is yet another potential security hole. This dumb thing is apparently part of the "Free Desktop" but it's depended on by all kinds of stuff including the fricking RedHat power management. What's wrong with plain old sudo?
The first part is also pragmatic. Releasing a security fix is a lot of work, not just for the developers, but also for everybody else. So you only do that if you have reasonable suspicion that the bug is a security risk. They were good reasons to believe that it is not the case here, although in the end they did not apply in every situation.
If you treat every bug as a security issue, you end up with the Google situation where only one version, the latest, is ever supported. And for libc that is not an acceptable option.
It is one thing to say we will not fix it right now because of the costs and the unlikely of seeing this in the wild. It is quite another to call it unexploitable. The former is pragmatism. The later is hubris.
The word you're looking for is 'skeptical', and then they went and fixed it when they were proven wrong. This is actually the opposite of arrogant.
They should have fixed the bug as soon as they realized it was there, and not waited until someone proved it was an especially bad bug.
Hmmmm, not really. You fix bugs according to cost of fixing it which includes regression testing to ensure you do not break something else with your fix (effort), the likelihood of the bug manifesting itself in the wild (priority) and the ramifications when the bug manifests itself (severity.)
More systems have been broken by people "fixing" things without doing the proper analysis than by actually looking at the backlog and deciding what shall be fixed (fixed in this release), what will be fixed (fixed in this or some other release), what should be fixed (fix not bound to a release yet), what should not be needing a fix (no consequences of fixing it right now, gives room to fix more important things), what will not be fixed (not in this release), and what shall not be fixed (too risky, not worth it).
We are in the business of engineering complex systems, from inception to realization to deployment to support and decomission. This is how you manage how to engineer complex things.
It's an oldschool attitude to not touch things
It's called engineering.
, from back in the day where software was so flaky that chances were someone had already 'exploited' the bug to do something non-malicious.
It drives me fucking crazy, having been born pretty much into the internet age where the corrected answer can be available in *seconds*.
Just because we are in the era of the Interweebz, that does not mean everything is a web app whose solutions can be put together in seconds. Specially something like a compiler, a shared library or an embedded system. You have to think of regression testing and crap like that, the backlog of issues that are begging fixing, etc, etc, etc. As a result, you do not touch things unless you truly need to, in a controlled manner.
If it is a web-based system with limited visibility, yeah, slap that fix and test it right there, just browse the page to see that it works. A web service or composite other systems depend on, hmmm, first device a functional test with SoapUI just to validate behavior before and after the change. An enterprise system with hundreds of developers and thousands of issues in back logs, slow down, time to prioritize a bit. Something system-level, and used by millions, hold on your danged horses.
I'm not saying the Glibc developers did the right thing at first - I mean, calling a bug "unexploitable" just like that, that is arrogance, not competence or prudence.
But that is a far cry from saying oh, we know what it is, we can put some code in place in seconds. Slapping some code changes =/= fix. A fix is a code change preceded by a cost analysis and followed by a regression/acceptance test, Internet or no Internet.
It's pretty obvious from the description what the bug is, so saying you aren't going to fix it is, as you say, pure laziness.
In this particular case, perhaps. In general, see my previous sentences above.
Nothing prevents writing runtime libraries on safer languages than C, even C++11 would be a lot better (unless abused, but that applies to C too). And assembler is used very little these days, because there are many relevant CPUs in the market (ARM variants, x86, x64).
they? or you; this is FOSS after all
Hmm. How likely is that? It overflows in to malloc metadata, and the
glibc malloc hardening should catch that these days.
--
Florian Weimer / Red Hat Product Security
Yeah, they should have just invented Python in 1950.
Of course, the C standard library itself is hardly a shining example of secure library design.
Indeed. And yet, in Java, it's impossible for me to accidentally shoot myself in the face with pointer arithmetic.
I use C++, and like it in its way, but you don't have much of a point.
Don't make excuses for not fixing bugs. When you find bugs, fix them.
All software is buggy by definition because the entire stack from the moving charge carriers to the behavior of the person using the computer cannot be mathematically proven to be correct.
No matter what measures you as the hardware or software creator take, there will be bugs.
Don't make people angry at you or ridicule their bug reports because that's a major incentive for them to make you look foolish.
Dear Retard,
Posting as AC then adding your monograph is a good way to get trolled.
HTH
You may be correct but there's a couple of differences - firstly the processor designs are so incredibly complex now (Intel recently issued a 'microcode patch' that actually disabled some instructions on a certain batch of CPUs) that they're all optimised by computer, so it's unlikely that there's much leftover unused functionality. That brings me to the second point, in that whatever 'undocumented' behaviour is available is unlikely to be as useful as e.g. a deprecated opcode on a ZX80. Moreover, you don't go buy a ZX80 with exactly the same processor as everyone else any more. Not only do you have multiple brands to choose from for the same architecture, you probably aren't even paying attention to the exact model you are buying.
It's OK Bender, there's no such thing as 2.
If you're talking about 'hold your head this way, right click on your keyboard then unplug your RAM == crash' then yes a change might be something you weigh up.
When you're looking at the code and you see *'this is logically incorrect'* then you fix it immediately. If you're smart you also create some unit tests _proving_ that it was incorrect before and is now correct.
Fuck everyone else who wants to reformat the headers of this part of the project and has it all checked out, fuck people who bitch about 'stability' in the sense of things not changing (after all, you don't HAVE to upgrade), you just fucking fix it.
That's what a programmer does - tells a computer how to *correctly* solve a problem.
It's OK Bender, there's no such thing as 2.