Kernel RCE in iOS/macOS with ICMP
lgtm.com
lgtm.com
Ok, yeah, not exactly the same, but humor me. It's a Halloween undead miracle!
As an aside:
> Even on a Mac, XNU is highly non-trivial to build.
I find it to be an extremely sad state of affairs when it requires scouring the internet for a blog post from a Darwin engineer to build an outdated XNU :(
That's something practically every linux kernel dev does, but surely every time a XNU dev wants to add a single debug print statement, they'll go through the whole CI system before being able to run it.
IIRC Chrome has this workflow for this reason.
I occasionally build chromium on my machine, and sure it takes two hours the first time, but incremental builds after that are only on the order of minutes.
C++ code can be incrementally compiled... Sure, it's not as good as in many other languages due to headers being so heavy, but it's still a massive reduction in total build time.
Linking does take some time, but it’s only really noticeable if you do very incremental changes (e.g. change a single value, build, boot, repeat).
Overall, building a whole kernel from scratch even for multiple configurations is not unbearable during normal development.
Large projects at companies tend to be hard to build, simply because it takes a lot of effort to make the build system for something so complex easy. If community contributions aren't particularly valued (which they aren't for XNU), then it's hard to internally justify spending the effort. Linux hackers are spoiled…
XNU isn't even one of the worst offenders. Try compiling Google's Skia, for example…
On my case I ended up giving up and went back to Qt.
There’s probably three build systems and none of them work on certain days of the week and the guy who wrote it all left six months ago.
It's not receiving an ICMP packet that causes the crash, it's when sending an ICMP error response packet. ICMP error packets can be generated in response to any type of IP packet, for example "host unreachable" when using UDP. These packets copy the original header of the packet which generated the error, which is where the out-of-bounds copy is.
I understand why the author doesn't want to give full details, but in this case it leads to a lot of misunderstandings on how it works.
I expect to see a PoC soon with arbitrary code execution in kernel space on all unpatched MacOS/iOS devices soon. Which would be bad...
At least ARM is getting pointer tagging.
Unless the same mistake would have been done inside an unsafe code block/module.
If anything, C's history of memory corruption errors and how they come to be, proves that even the best aren't able to follow best practices that apparently all good C coders do.
Linux kernel is full of such CVEs in spite of the approval processes in place to accept new code into the kernel, and I assume Apple does have similar practices in place.
I see your point, and I agree partly, some languages can avoid the particular secuence of events in this bug or make it more difficult.
In this case, imagine:
- Sloppiness getting code into the icmp module (this is speculation, to be fair).
- Buffer overrun leading to RCE.
- Solution:
1 You rewrite in rust because you think the root cause is that C is unsafe.
2 You don't write sloppy code, higher your standars, more audit/testing/verification.
To me, if you don't fix #2, you are going to have big problems anyway even if you have safer tools.The thing is,
Σ logic errors < Σ logic errors + Σ memory corruption errors
So while errors don't go away, the exploit area is considerably dimished.
Naturally it gets hand waved as errors are errors.
Which is why I really do look forward for harder lawsuits when security exploits happen.
When money starts speaking, more companies will take security more seriously.
But, all I was saying in the beginning (and I later digressed) is that just blaming 'C memory model' is not fair.
(Dramatization) "Hey, boss, yes... an RCE, what a pitty. Yeah, missing check. But don't blame me. Is C it is at fault". That is just not realistic/ridiculous. Is like saying is the parents of Denis Ritchie that are at fault here.
Even Multics had less exploits than earlier UNIX versions, as stated on a DoD report about inexistence of memory corruption issues thanks to PL/I.
If you bother to read the early C history document written by Richie, they were aware of such shortcomings and thus lint was born in 1979.
A tool that to this day many devs still ignore.
As for alternative languages I haven't named a single one on this thread. There are plenty to chose from since 1961.
As for alternatives, I was just giving examples, you didn't say anything yes.
I wish more public WiFi was well ran, as many of these same network attacks wouldn't have an opportunity to work in the first place.
These things happen.
To bad, I liked the older OS Xes.
Your 2011 iMac can be update to 10.13, so I would update, a iMac 2011 with enough ram and a ssd works very well even on 10.13.
In this commit a bunch of code was copy-pasted from BSD into ip_icmp.c in icmp_error() to quote IP packet data in icmp error responses. Unfortunately they forgot to copy a line from the BSD source which would prevent the overflow:
icmplen = min(icmplen, M_TRAILINGSPACE(m) - sizeof(struct ip) - ICMP_MINLEN);
m is allocated with a fixed-length buffer (mbuf), which means without that line above we can overrun it: m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
Copy-paste programming in core networking code...There is nothing special about core networking code.
Not sure what you are trying to say.
> there are countless other undiscovered bugs like this
How do you know that they exist if they're undiscovered?
At this point, there are probably very few in linux after the level of fuzzing its received.
Linux is heavily developed, which means significant code churn. It's a victim of its own success.
And there's much less fuzzing happening than you think. It's an on-again, off-again activity; not something that any particular organization (AFAIK) is rigorously and repeatedly performing on Linux for any serious length of time (i.e. years). Fuzzing isn't an automatic thing; it requires human intervention to help craft the tests so they reach and tickle the right corner cases. And if the code is constantly changing, you need to constantly review your tests.
Also, syscall fuzzing must be done differently from network fuzzing, for example. And fuzzing kernels in general is more difficult than, e.g., a self-contained library.
If you look at the Linux kernel CVEs, they've been steadily increasing over time: https://www.cvedetails.com/product/47/ We can quibble over the causes and significance, but I don't think those data points support your argument.
Yes, remote exploits in Linux are rare, just as they're rare in most operating systems, including macOS and Windows. But not rare enough. And there's little indication that they're becoming more rare. Unfortunately, I'll bet that the shift to eBPF to implement basic filtering and routing will cause a spike over the next few years.
At this point the Linux kernel is a lost cause. Everybody serious about security understands that the future is moving your most sensitive assets to secure enclaves not running general purpose OSs like Linux. Unfortunately those enclaves are recapitulating the same mistakes--too many features, too flexible, too much emphasis on adding more complexity to try to fix things. But one thing is certain, Linux is definitely not getting any simpler, and people are moving assets to slower moving train wrecks.
The number of CVEs don't support any argument really. More CVEs are assigned, yes. That doesn't mean more security issues. In the olden days of 8 years ago, a buffer overflow would be patched with no fanfare and no CVE assigned. Nowadays, often only theoretically exploitable issues will still be given a CVE.
The article says that the problem was found by codifying the mistake that led to a previous CVE as a query in a logic language called QL, and then running that query over XNU, so if there were any more they would have been found at the same time.
(edit: corrected typography)