Linux Kernel Use-After-Free Remote Code Execution Vulnerability
securityfocus.com
securityfocus.com
[1] http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.g...
[2] https://source.android.com/security/bulletin/2016-10-01.html
Better URL that goes right to the appropriate section.
We've all heard it already, we all know what you'll say. So skip the smug post, and go do something productive. Like writing a really cool piece of new code, or fixing a use-after-free, or posting something more insightful, or inventing a new type of shoelace that doesn't come untied until you want it to.
Yes ..
Does this vulnerability work only on a particular architecture?
This is why seL4 does not support internal SMP. You can run an instance per core and assign it a separate memory space like to a VM though.
So, then, why do you think that "We need to rewrite everything in Rust" isn't doing something productive? I've been a C++ and C developer for a long time and have been waiting for some safer language that lets me do what I've been doing in those languages. Knowing that Rust was a realistic option was what inspired me to learn it and write new things in it. If that happens at scale, that's how we actually get things written in a memory-safe language.
The Linux kernel didn't get written because people on a forum said "we need to write a complete open source reimplementation of the UNIX kernel," but because Torvalds just went ahead and wrote it. Most things in F/OSS work that way.
Hello everybody out there using minix -
I'm doing a (free) operating system (just a hobby, won't be big and professional like gnu) for 386(486) AT clones. This has been brewing since april, and is starting to get ready.
https://groups.google.com/forum/#!msg/comp.os.minix/dlNtH7RR...
It would be much easier to submit patches to slowly upgrade the kernel to a memory safe language, but that would require a lot of political savvy to push through, also making it an unlikely path to be taken. Ultimately, you'd have to convince Linus of the merits, and we all know how much he likes complex languages.
For one, Rust is a different language from the other memory-safe languages that have existed in the past, and in fact incorporates a lot of research in programming languages that didn't exist when Ada was designed. But even if that weren't true, one thing that's changed since the past is we now are slowly understanding how difficult it is to write secure software in C, and how important it is to write secure software. When Unix was first designed we (the entire programming community) didn't know about a lot of security issues, and the lack of Internet meant that it was less important to defend against them. It is probably much more worth rewriting our tools in Ada today than it was ten or twenty or thirty years ago.
IMO, because it's harder to break the rules. Sometimes the rules just need to be broken. There was a recent article about someone attempting to interface with OpenGL in Rust a month or so ago, and it discussed how they ended up giving up, since the things they needed to do didn't mesh well with how Rust expected programs to be written. If interfacing with a driver is so hard, how will interfacing with hardware be easier?
Programming for hardware requires a lot of breaking and bending the rules. How can being memory safe help when you're creating memory spaces as most software knows of it?
Performance is King, low memory overhead is Queen. Even rust can't take those thrones away from C. Not yet, at least. Perhaps not ever (I expect that C++ would have done it, were it possible for a language with the complexity of Rust).
> If interfacing with a driver is so hard, how will interfacing with
> hardware be easier?
It really depends. The key is to identify the proper ways to make the abstraction as safe as possible. This is a fairly new skill, in a new language. Said post was good, and the author has been using Rust for a long time, but one person failing to do so doesn't mean that it's impossible.I'm still a noob at this kind of thing myself, but I recently wrote a (tiny) driver for a memory-mapped device. My first iteration had tons of unsafe code. My second iteration had three lines of unsafe code. My latest iteration has zero unsafe code, though you do need one call to an unsafe function outside of it in order to construct it. (to create a slice from the raw memory location that's mapped.)
That is, of course, pretty much the simplest possible case. But I believe the pattern will hold, over time, as people learn how to do it.
> Even rust can't take those thrones away from C.
Rust is faster than C on some microbenchmarks. We'll see what the future holds.The beginning of the end of use-after-free, buffer overflows, stack smashers, et al will be when we as a community finally accept that C is a terrible language, impossible for ordinary humans to reason about, and must be abandoned. Only when we begin to accept that truth will we all get serious about moving away from it.
For many years the response has been that "C is fine" or some variant of "humans will be better programmers in the future" both of which are demonstrably false.
No one questions the wisdom of paramtaraizing SQL. No one questions the wisdom of not writing your own crypto. Yet despite the mountains of evidence, wasting billions (yes BILLIONS) of man-hours and dollars, and even lives lost there is still resistance to the idea that C needs to die ASAP.
So as long as there are posts like yours our job of educating and persuading isn't finished and that's extremely important if we have a hope of actually making this desperately needed change.
If you still doubt let me go ahead and make a prediction: before the end of the year there will be another RCE exploit in the Linux kernel discovered and a different one will be written, code-reviewed, and committed but not discovered until later (but within 5 years). I'm happy to put $1,000 on this wager.
The problem is this line of reasoning doesn't generally hold up when applied to C codebases (because in practice statistics catches up with you eventually) and C code generators, in effect, happen to contain an admittedly small but rather obfuscated C codebase.
Moreover, you must always include such checks - manually crashing on e.g. null pointers even if you'd be entirely satisfied with a segfault - just to avoid the optimizer potentially going apeshit on your code. Which can have... poor effects on program performance.
1) All the complaints you have apply equally well to assembly language, yet assembly language is all that the CPU understands. Somebody always has to deal with the low level complexity of writing the foundational software constructs necessary to build safe environments and C is still the most natural mapping to varied assembly languages that we have.
2) Nothing else will fit for many embedded systems. Your choices are C or assembly language. What safe environment/language are you going to fit into a microcontroller with 1kB of RAM?
(And, yes, maybe Rust or one of the other proposed system language replacements will be better than C someday, but that someday isn't today.)
No, machine code is all that the CPU understands. Assembly language is source code that gets converted into machine code by an assembler.
The advocates of these alternatives aren't creating this situation. The unavoidable fact is that our traditional tools have a propensity to propagate bugs that are fabulously difficult to discover. That's one of the lessons of nearly a half century of C. New tools are emerging that solve this problem and their advocates have every reason to say so.
Another lesson C teaches us through its popularity and longevity is that performance will always be critical for systems code; there will never be a day when we can squander cycles and RAM on garbage collectors and reference counts and indirections and all the other bookkeeping and abstractions inherent to so many languages that have utterly failed to displace C for systems programming.
I don't know what the future looks like. Maybe it's Rust. Maybe Linus will get fed up and invent a better language in 4 days. Maybe someone will create an AI system that can spot this sort of bug before it ever gets checked in. All I know for sure is that the current situation is intolerable and yelling at people to shut up about it won't work.
BTW the kernel is full of reference counts.
I think the OP is pointing to languages like Swift/Objective-C where reference counts are used even if you don't really need them, not that ever reference counting anything is a lazy abstraction.
Every program written in Go is one program less written in C.
...
Make sure there's less C code around.
Once there's a firm consensus that it's time to move away from C we'll probably stop talking about it. But that consensus has to develop through discussion and argument here and elsewhere (and if you look at the conversations now compared to a year or two ago, I'd say we've made a lot of progress). If you don't believe there's value in talking about technical issues then what are you even doing here?
A tree thread is good for discovery but not so good for reaching a conclusion/consensus. Flat/linear thread should be used instead.
You're welcome to post, of course. I'd just rather you not. There's no sense preaching to the choir.
Once your language is at that point, then start building up your arguments to convince Linus and the majority of the core kernel developers that your language is the right choice for continued development.
Until these occur, it's all just pointless speculation.
The biggest cost is not them, it's every other C programmer, every other company, the whole industry. It's unrealistic to even think that any significant part of them is going to invest resources into another language just to gain memory safety.
The l-k devs and the big commercial Linux vendors/users (Google, IBM, Red Hat, Amazon etc) should gang up and start offering big bounties for these. And simultaenously start doing subsystem rewrites in a memory-safe way prioritized by bugs found by bounty program (and other ways). If they're allergic to non-C languages, a safe C subset like SAFEcode or C0 could be used[1].
[1] I'm saying it's possible to have a memory safe C subset with current compiler technology, even though you can point out something missing from C0
And if the bugs you find can be exploited in google products the bounty is _very_ high.
(Many of the results are for code like language runtimes and debugging tools that don't actually use recvmmsg() themselves)
tl;dr looks like it'd function well a local privilege exploit. not an expert, but as a remote exploit think it would need 1) a service running recvmmsg (which is kind of unlikely) 2) a way to cause recvmsg to error, and 3) a way to cause the service to close its socket in the middle of the recvmmsg call.
I was just starting to look into this since people were claiming it was pretty severe and yet I hadn't seen any POC's. Have you made any more progress?
For whatever my opinion is worth (i.e. not much), I would agree with you that remote exploitation of this particular bug would be really difficult.
Mitre link: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-7117
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux....
I guess the post on securityfocus (also not reachable) slipped out before end of embargo time?
This bug was found because a KASAN ( https://www.kernel.org/doc/Documentation/kasan.txt ) assertion triggered during fuzzing.
Looking at http://vault.centos.org/6.8/updates/Source/SPackages/kernel-... it looks like RedHat backported this function but has not applied the fix.
Do I need to worry about a fully upgraded ubuntu 14.04 with or without the Hardware Enablement Stack?
Unfortunately in this case Ubuntu's CVE tracker just shows "needs-triage" or "does not exist" for CVE-2016-7117.
[1] Well, most Linux systems don't get timely security patches, like most Android phones or most embedded/iot products, but you get the idea
- Debian is prevalently not vulnerable: https://security-tracker.debian.org/tracker/CVE-2016-7117 (except the "oldstable" release)
- for Ubuntu, the situation is more complicated, as it depends on the actual kernel package installed: https://people.canonical.com/~ubuntu-security/cve/2016/CVE-2... For the "linux" kernel package (prob the most common), the situation looks like this at the moment::
Upstream: released (4.6~rc1)
Ubuntu 12.04 LTS (Precise Pangolin): needed
Ubuntu 14.04 LTS (Trusty Tahr): released (3.13.0-86.130)
Ubuntu Touch 15.04: DNE
Ubuntu Core 15.04: pending (3.19.0-59.65)
Ubuntu 16.04 LTS (Xenial Xerus): released (4.4.0-22.39)
Ubuntu 16.10 (Yakkety Yak): not-affected (4.4.0-22.39)
- for CentOS/RHEL, my understanding is that fixed kernels have not yet been released: https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2016-7117And consider mitigations at various tech stack layers.
I think the best advice is not to listen to anyone on HN about this shit except for cperciva
Original response:
----
Reimage everything from scratch if you're a bit paranoid, because in theory someone could have rooted every server running any internet-accessible thing (even just sshd or nginx)
Realistically, update ASAP and figure out from other sources how difficult this is to exploit and how likely it is that anyone actually did get a working RCE
Rust and ATS seem to be pretty well suited. With Rust getting more and more traction, maybe not all is lost :)
Redox is a ground up OS, but I wonder if we shouldn't instead be taking more of an Oxidization approach where we rewrite more and more pieces of an existing OS in Rust piecemeal. This would add some overhead (programmatically not instructionwise) of a lot of context switches though between the C and the Rust code, which is to say it would be a little ugly for a while.
It might be cleaner to go after a microkernel to do this though, like L4 or rumprun.
That's kind of the opposite of having the mindshare, IMO :) Having the mindshare means people would be reaching for it when they need things done, not have to be dragged in, and there's a wide pool of people knowing it.
I'm pretty sure you can write OS kernel in almost any language that can be compiled into runnable code, and probably if you are really determined also in those that are compiled into bytecode. As I said, it's not the main issue.
Unless you are a titan of programming that can do an OS project all by yourself, or have more money than Google, you'll need random people to come to the project, pick up pieces and work on them. The question is, does Rust have pool of people wide enough so that probability of people wanting to work on your project is higher than your needs?
C definitely has a huge pool. So do C++, Java, JS, Python and many other languages. Rust? I'm not sure it does so far. Maybe I'm wrong.
I think for its age, the success it already enjoys is impressive.
The only way I could see a kernel being truly written in Haskell is in a DSL something like atom[1]. Atom is an EDSL represents code that not only doesn't need a garbage collector, but also has a verified constant bound on memory usage. However if that's what you're looking for, you might as well go with an EDSL in a dependently typed language like Idris to make verification easier and extensible.
Some of my colleagues did, a few years ago.
I think if the Rust communtiy wants to make it somehow to the Linux (or other UNIX or windows) Kernel space, there needs to be an effort to build Kernel Rust, if there isn't one already..
Rust is popular because Mozilla, a well-known company, is developing it for a well-known major project, a web browser.
Go is well-known due to Google, and the fact that many people with an opinion-setting power know who Rob Pike is.
Haskell, well, just spent 20 years being around, sometimes in university curricula.
ATS is only, it seems, known to people who are specifically interested in formally-correct low-level code, on the sparsely-populated intersection of math and hardware geekery.
See also: seL4, Isabelle/Coq, Idris
I think solutions that don't require any code modification like Softbound and SAFEcode (and even the LLVM sanitizers) aren't popular because the resulting executables are quite slow. Whereas SaferCPlusPlus strives for minimal performance penalty. (Perhaps with some cooperation from C/C++'s formidable optimizing compilers.) (Btw, if it's not already clear, this is a shameless plug.)
And not only is conversion to SaferCPlusPlus far less effort than rewriting everything in another memory safe language, it can be done completely incrementally. What language has better "bidirectional C interoperability" than C++?
Look, this hasn't been a good day so far, okay?
Unit testing for security vulnerabilities has been discussed to death on HN and is generally agreed that it doesn't work. Yet, every time there is any kind of vulnerability, a comment like mine shows up, except in ernest.
Believe me when I say we have a difficult time ahead of us. But if we are to be prepared for it, we must first shed our fear of it. I stand here, before you now, truthfully unafraid. Why? Because I believe something you do not? No, I stand here without fear because I remember. I remember that I am here not because of the path that lies before me but because of the path that lies behind me. I remember that for many years we have fought these security guys. I remember that for many years they have sent their armies to destroy us, and after a life-time of war I remember that which matters most... C is still here! Today, let us send a message to that army. Tonight, let us shake this thread. Tonight, let us tremble these keyboards of silicon, steel, and plastic, let us be heard from low-level assembly to bloat-ware web applications. Tonight, let us make them remember, THIS IS LINUX AND WE ARE NOT AFRAID!