Slashdot Mirror


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.

29 of 98 comments (clear)

  1. Re: microsofties here is your chance to party by AvitarX · · Score: 5, Insightful

    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
  2. Re:microsofties here is your chance to party by Anonymous Coward · · Score: 2, Funny

    CAN YOU HEAR ME NOW?? HELLO?

  3. Honestly, when will people learn? by Anonymous Coward · · Score: 5, Insightful

    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.

    1. Re:Honestly, when will people learn? by Narcocide · · Score: 4, Insightful

      This is seriously shit your CS 100 or 200-level teacher SHOULD have taught you, if you got a CS degree. I think it may depend largely upon where/when you got your degree though. They're only all the same on paper.

    2. Re:Honestly, when will people learn? by grahamsaa · · Score: 3, Interesting

      No. While it depends on your end users (end users of some products / libraries / etc are very technical, while other products draw from a much larger, less technical user base), a non-trivial number of bug reports are due to user error, or to something that you don't actually have any control over. Skipping stage 1 probably makes sense in all cases, but the rest of the stages are all valid. Sometimes you never get past stage 2 because the answer is "oh, right, because my machine isn't infected with something" or "because I didn't mis-configure the application".

      --
      Facts have a liberal bias.
    3. Re:Honestly, when will people learn? by katterjohn · · Score: 3, Interesting

      While I don't feel buffer overflows are something to ignore, from what I see the developer never actually said "unexploitable."

      From the "skeptical glibc developer" link:

      > if not maybe the one byte overflow is still exploitable.

      Hmm. How likely is that? It overflows in to malloc metadata, and the
      glibc malloc hardening should catch that these days.

    4. Re:Honestly, when will people learn? by JazzXP · · Score: 3, Insightful

      Yes, but according to your clients, it's still your fault.

    5. Re:Honestly, when will people learn? by Anubis+IV · · Score: 3, Insightful

      Sure, which is why you have proper logging that allows you to point them in the right direction. At least a few times a year, I have to advise users to get in touch with their IT department to fix their corrupted Arial font file or some other such nonsense since it's causing problems for our app (and probably a number of others as well). Where the fault lies is a tangential discussion, however. What matters here is that Step 2 is actually valuable at times, since it can assist you in answering #4 by narrowing down the possible causes.

    6. Re:Honestly, when will people learn? by Anonymous Coward · · Score: 2, Insightful

      The things they don't teach you in a CS degree.
      Actually they *do* teach you that in a CS degree, and also how to fix it. FTFY. Also, they don't put the word 'an' before a word beginning with a consonant.

  4. Re: microsofties here is your chance to party by Anonymous Coward · · Score: 5, Informative

    Embedded stuff would typically use uClibc. Android uses Bionic libc.

    Most ARM might be 32 bit but most ARM doesn't use Glibc.

  5. Re: microsofties here is your chance to party by Ralph+Wiggam · · Score: 2, Insightful

    The first part is arrogance. The second part is pragmatic humility.

  6. Summary is completely exagerated by Anonymous Coward · · Score: 5, Informative

    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?"

    1. Re:Summary is completely exagerated by NotInHere · · Score: 4, Informative

      I chose the word scepticism, and still I think it is. I agree that the word "unexploitable" was a bit exaggerated, but that was added by unknown lamer.

      Florian Weimer said:

      My assessment is "not exploitable" because it's a NUL byte written into malloc metadata. But Tavis disagrees. He is usually right. And that's why I'm not really sure.

      Its however true that he corrects himself the same day a bit later:

      >> if not maybe the one byte overflow is still exploitable.
      >
      > Hmm. How likely is that? It overflows in to malloc metadata, and the
      > glibc malloc hardening should catch that these days.

      Not necessarily on 32-bit architectures, so I agree with Tavis now, and
      we need a CVE.

  7. "Unexploitable" sudo bug pre-1.6.3p6 by Anonymous Coward · · Score: 5, Interesting

    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.

    1. Re:"Unexploitable" sudo bug pre-1.6.3p6 by NotInHere · · Score: 3, Informative

      I've read a bit through the threads and think that the reason it took so long was because they decided to remove a feature to fix the problem:

      I believe the current plan is to completely remove the transliteration
      module support, as it hasn't worked for 10+ years.

      The git commit message states the same. There were really some problems in that function: https://sourceware.org/ml/libc...

  8. Amazing to use such a crude programming language by aberglas · · Score: 2

    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...

  9. Re: microsofties here is your chance to party by phantomfive · · Score: 3, Insightful

    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."
  10. C Needs Bounds Checking by Sanians · · Score: 5, Informative

    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.

    ...but let's assume it was. Assume bounds checking would reduce program execution speeds by 10%. How often do you worry about network services you run being exploitable, vs. worrying that they won't execute quickly enough? Personally, I never worry about code not executing enough. I might wish it were faster, but worry? Hell no. On the other hand, I don't even keep an SSH server running, despite how convenient it might be to access my computer when I am away from home, because I fear it might be exploitable. I'd prefer more secure software, and if I'm then not happy with the speed at which that software executes, I'll just get a faster computer. After all, our software is clearly slower today than it was 20 years ago. I can put DOS on my PC and run the software from that era at incredible speeds, but I don't because I like the features I get from a modern OS, even if those features mean that my software isn't as fast as it could be. Bounds checking to prevent a frequent and often exploitable programming mistake is just another feature, and it's about time we have it.

    ..and like everything else the compiler does, bounds checking could always be a compile-time option. Those obsessed with speed could turn it off, but I'm pretty certain that if the option existed, anyone who even thought about turning it off would quickly decide that doing so would be stupid. Maybe for some non-networked applications that have already been well-tested with the option enabled and where execution speed is a serious factor, it might make sense to turn it off, but when it comes to network services and web browsers and the like, no sane person would ever disable the bounds checking when compiling those applications because everyone believes security is more important than speed.

    1. Re:C Needs Bounds Checking by Dutch+Gun · · Score: 5, Informative

      Personally, I never worry about code not executing [quickly] enough.

      You know, people say stuff like that all the time, but all it proves is you're not a programmer that developers speed-critical applications. Guess what? There are lots of people who are. Game programmers (me). Simulations programmers. OS / Kernel developers. There are some situations where fast is never fast enough. You're thinking like a desktop developer who writes business applications that are probably not that demanding of the CPU. Get a faster processor? I wish! Not possible for console developers, or when you're running software in data centers with thousands of machines. Those are real problems, and they require highly optimized code, not more hardware. Most programmers have no idea how much the constant push for efficiency colors everything we do.

      Just today the other day I was looking at a test case where a complicated pathfinding test scenario bogs pegs my 8 core CPU when a lot of units are on-screen at once. That's not some theoretical problem, and telling users they need some uber-machine to play the game is a non-starter. I either need to ensure my game design avoids those scenarios or I'll need to further optimize the pathfinding systems to allow for more units in the game.

      That being said, I agree with your complain about C's fundamental insecurity, but it's not so simple as adding in a compilers switch. For the most common and checkable types of bounds problems, or library functions that can cause problems, Microsoft's C/C++ compiler already does what you've suggested to a degree (not as certain about GCC). The big problem with bounds checking in C is that arrays are simple pointers to memory. The compiler doesn't always know how big that free space is, because there's no type or size associated with it. It's possible in some cases to do bounds-checking, but not in many others. It's a fundamental difficulty with the language, and it's impossible for the compiler to check all those bounds without help from the language or the programmer.

      --
      Irony: Agile development has too much intertia to be abandoned now.
    2. Re:C Needs Bounds Checking by Sanians · · Score: 3, Interesting

      Your idea only works if bound sizes are defined at compile time which is hardly going to be even a majority of cases.

      Use your imagination...

      I was imagining a special type of pointer, but one compatible with ordinary pointers. Kind of how C99 added the "complex" data type for complex numbers, but you can assign to them from ordinary non-complex numbers. A future version of C could add a type of pointer that includes a limit, and a future version of malloc() could return this new type of pointer, and for compatibility, the compiler can just downgrade it to an ordinary pointer any time it is assigned to an ordinary pointer, so that old code continues to work with the new malloc() return value, and new code can continue to call old code that only accepts ordinary pointers. Of course, we won't call them "new" and "ordinary," we'll call them "safe" and "dangerous" when, after several years, we grow tired of hearing of yet another buffer overflow exploit discovered in some old code that hasn't yet been updated to use the new type of pointer.

      ...or I'm sure there's many other possibilities. This isn't an impossible thing to do.

    3. Re:C Needs Bounds Checking by TheRaven64 · · Score: 2

      It is possible, but for good performance it needs hardware support. We've implemented hardware-enforced bounds checking for C code using our processor. If you only care about accidental bugs and not about a malicious attacker, and don't use threads (or are happy to bound every pointer store with a transactional region), and don't mind that the semantics of C are subtly broken in the kinds of permitted pointer operations, then Intel's Memory Protection Extensions will do the same thing.

      --
      I am TheRaven on Soylent News
    4. Re:C Needs Bounds Checking by Dutch+Gun · · Score: 2

      I'm not sure how well you know C, but... you can't turn a pointer into something more than a raw memory pointer. This would flat-out destroy all sorts of code that relies on that behavior, both in C and C++, and not necessarily badly-written code. The behavior of memory pointers is a part of the language contract, and you can't change it without breaking the language. For systems programmers with large, legacy codebases, they'd never risk turning on such an intrusive feature because of the simply fact that it would break compatibility, nor would they wish to pay a global penalty to apply protection for some very specific vulnerabilities.

      In my own code (which is C++, not C, but the point still applies), I'm actually performing my own low-level memory management in order to improve efficiency - it's pretty much standard practice in the videogame industry, at least for large projects. Anything the compiler tried to do in terms of mucking around with allocations, pointers, or arrays could very well break code, and wouldn't help in any case. For instance, it's pretty common to allocate a big block of memory and to pass off small chunks of it to structures instead of performing an OS-level heap allocation for each one. In this scenario, a pointer has no explicit type at all, and any inferred type can be malleable to such a degree that it could never really be analyzed either at compile time or runtime.

      When discussing a "no-brainer" feature like this, I tend to assume that other people (compiler writers) have already thought of this idea and rejected it for very pragmatic reasons. I'd imagine no one wishes more than C programmers that they could flip a magic switch and have a lot more protection, but I just don't see how it could realistically happen.

      --
      Irony: Agile development has too much intertia to be abandoned now.
  11. Re:microsofties here is your chance to party by Sun · · Score: 4, Insightful

    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

  12. Raspberry Pi, obscure NAS boxes by dutchwhizzman · · Score: 4, Interesting

    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?
  13. Some C compilers already have bounds checking by Sits · · Score: 2

    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.

  14. Re: microsofties here is your chance to party by phantomfive · · Score: 2

    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."
  15. Address space randomization does not help. by Animats · · Score: 5, Interesting

    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.)

  16. Re:microsofties here is your chance to party by TheRaven64 · · Score: 2

    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
  17. not the same thing by luis_a_espinal · · Score: 2

    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.