|
|
Subscribe / Log in / New account

Looking at a few recent kernel security holes

By Jonathan Corbet
October 21, 2015
The Linux kernel is the source of far more CVE numbers than any other component in the system; even wireshark doesn't really come close. To an extent, that is one of the hazards of kernel programming: errors that would simply be bugs in user space become vulnerabilities in the kernel realm. Still, there is always room to wonder if the kernel community could be doing better than it is in this regard. One way to try to answer such a question is to look at what types of vulnerabilities are being discovered to see what patterns emerge. Thus, this brief survey, which looks at a few recent issues.

Buffer overflows and more

CVE-2015-5156 is, at its core, a buffer overflow in the virtio network driver subsystem. This driver sets the NETIF_F_FRAGLIST flag on its devices, indicating that it can handle packets that have been split into multiple fragments. When it gets an actual packet, it calls skb_to_sgvec() to turn that list of fragments into a scatter/gather I/O list. Unfortunately, the size of the scatterlist array it allocates for the fragment list is insufficient; in some circumstances, there can be more fragments than can fit into the scatter/gather list. The result is that skb_to_sgvec() writes beyond the end of the list, corrupting a random range of memory.

The problem was "fixed" by removing the NETIF_F_FRAGLIST flag. As a minimal fix for stable kernels, this change probably makes sense. But one could argue that fixing it properly would involve either (1) sizing the scatterlist array properly in virtio, or, better, (2) passing the length of the list to skb_to_sgvec() so it cannot be overrun. Without that latter fix, skb_to_sgvec() behaves much like strcpy(), and this type of overrun could easily happen again.

CVE-2015-2925 is a vulnerability that allows a process to escape from a mount namespace if it can create a bind mount within that namespace. In practice, it means that processes can get out of a container and access the entire host-system filesystem. It was reported in April and was the subject of a long series of discussions. The proposed fixes were complex (to say the least) and ran into some opposition. In the end, a simpler fix was merged for 4.3.

This bug came about because nobody thought about the effects that a rename() call outside of a bind mount might have on processes whose current working directory lies within that mount. In short, a process following ".." out of a directory is normally stopped at the root of the filesystem it is in, but, if a directory can be moved out of a bind mount, a process within that directory can move up without ever encountering that root; it will thus never be stopped. Intersections of security domains will often be fraught with this kind of problem. The issue is fixed, but it is hard to believe that there won't be others like it.

CVE-2015-5257 is a null pointer dereference in the USB WhiteHEAT driver. These bugs can be used to cause a kernel oops; in some cases they can be exploited for privilege escalation, though most distributions should be configured to defeat such exploits. The source of the problem here is clear: the driver trusted the hardware to behave as expected. If somebody shows up with a purpose-built USB device, they can trigger the bug.

This particular vulnerability has few people worried. But the vulnerability of the kernel to malicious hardware in general is worrisome indeed. Such hardware is increasingly easy to make, and it can often create conditions that developers have never thought about or tested for. We will almost certainly see more vulnerabilities of this nature.

Initialization failures of various types

CVE-2015-7613 is a failure to properly initialize memory. In particular, the user and group IDs associated with a System V shared-memory object are not set before the object is exposed to the wider world, meaning that authentication checks can be done against random data. At a minimum, this bug can be exploited to gain access to shared-memory segments that should be inaccessible. But, as the Red Hat bugzilla entry notes: "It is almost certain that this vulnerability can be used to gain arbitrary code execution in the kernel."

The good news here is that, in KASan, we have a tool that can detect use of uninitialized memory in the kernel. Indeed, it was KASan that flagged this particular problem. The not-so-good news is that, as Linus Torvalds noted in the changelog to the fix, this problem had already been found and fixed in the System V semaphore code (for 3.18). It would have been good to fix all three types of System V IPC (message queues are vulnerable too), but, as Linus notes, "we clearly forgot about msg and shm". The lessons seem clear: tools are invaluable, but, as Al Viro once said: "Bugs are like mushrooms - found one, look around for more."

Initialization-related race conditions are fairly common; another example can be seen in CVE-2015-5283. In a modular system, the module for the SCTP network protocol will not be loaded until a user requests an SCTP socket. The initialization code in the SCTP module registers its installed protocols before it is fully initialized; that opens a window within which another process can attempt to open sockets while the module is in a half-baked state. Good things rarely come from such situations.

Almost any kernel module, be it a driver, a network protocol, or something else, must generally initialize a long list of resources and make them available to the rest of the system. It is easy to create a situation where some resources become visible before the module is fully prepared to manage them. An interrupt handler may be registered before the data structures the handler needs are ready. A sysfs file could show up before the driver is ready. Or an SCTP protocol can appear before the module is ready to handle it. These problems manifest themselves as difficult-to-find race conditions; they are hard to test for. So they will probably continue to pop up.

CVE-2015-5697 is an information-leak vulnerability. The MD (RAID) system implements an ioctl() operation called GET_BITMAP_FILE, which returns the name of the external bitmap file associated with a specific device. Should that device not actually have an external bitmap file, though, the ioctl() will copy 4096 bytes of uninitialized kernel memory to user space after having set just the first byte to zero. The remaining 4095 bytes could contain pretty much anything. An attacker could scan this data for specific patterns and possibly obtain kernel addresses or private data.

The fix is straightforward enough: allocate the space for the file name with kzalloc() instead of kmalloc(). But, once again, this is an easy sort of error to make; it is hard to ensure that all data copied to user space is initialized in all paths through the code. There has been a push over the years to use functions like kzalloc() everywhere, but there is resistance to doing so, especially in hot-path code where the developer is certain that the memory will be properly initialized. In any case, the GET_BITMAP_FILE ioctl() is not one of those hot paths, so there is no reason not to be sure in this case.

These examples were all taken from vulnerabilities that were fixed in distributor updates over the last month or so. Needless to say, it is not an exhaustive list. But it does show a few of the numerous ways in which security-related bugs can be introduced into the kernel. Kernel programming requires great care, an extreme distrust of the environment in which the code is running, and, whenever possible, good testing tools. The kernel community has gotten better with all of these over the years, but there is clearly a lot of ground to be covered still.

Index entries for this article
KernelSecurity/Vulnerabilities
SecurityLinux kernel


to post comments

Looking at a few recent kernel security holes

Posted Oct 22, 2015 4:29 UTC (Thu) by jamesmorris (subscriber, #82698) [Link] (4 responses)

Reducing the number of bugs is a laudable goal, but they will still always exist to some extent. From a practical point of view, we need to look at ways of mitigating classes of bugs, to reduce or eliminate their security impact. We have some mechanisms in place already, although frankly, we are behind the state of the art, and we need to do more in this area.

Kees and I will be talking about this next week at the kernel summit.

Looking at a few recent kernel security holes

Posted Oct 22, 2015 12:09 UTC (Thu) by pabs (subscriber, #43278) [Link] (1 responses)

Does that mean you are talking to the grsec/PaX folks about merging the rest of their patchset?

Looking at a few recent kernel security holes

Posted Oct 23, 2015 0:42 UTC (Fri) by jamesmorris (subscriber, #82698) [Link]

We need to get the core kernel folk to understand the issues, before anything else.

Looking at a few recent kernel security holes

Posted Oct 23, 2015 16:13 UTC (Fri) by Aissen (subscriber, #59976) [Link]

I fully agree. I kind of liked PaX's SANITIZE that would have helped with most of the missing initialization vulns. I tried porting/reimplementing a (very) small subset of this feature and sent a few patches (https://lwn.net/Articles/644528/ ). I'm currently busy with other endeavors, but it's on my todo list to try pushing this a bit more.

Looking at a few recent kernel security holes

Posted Oct 30, 2015 1:23 UTC (Fri) by pabs (subscriber, #43278) [Link]

An article about what you talked about:

https://lwn.net/Articles/662219/

Looking at a few recent kernel security holes

Posted Oct 22, 2015 10:02 UTC (Thu) by jezuch (subscriber, #52988) [Link]

> "Bugs are like mushrooms - found one, look around for more."

Great quote, especially when talking in context of fertile ground like the C language ;) That's something I learned along the way. Nowadays when I see something wrong that should be improved, I in fact see a pattern and often fire up a semantic patching utility[1] to find more instances of it.

[1] For Java there's one in NetBeans, and this is the only thing I use NetBeans for. It's a little neglected, though.

Looking at a few recent kernel security holes

Posted Oct 22, 2015 12:49 UTC (Thu) by spender (guest, #23067) [Link]

CVE-2015-7613 was actually found with KTSAN, not KASAN (as noted by the RH bugzilla entry).

-Brad

Looking at a few recent kernel security holes

Posted Oct 22, 2015 14:48 UTC (Thu) by error27 (subscriber, #8346) [Link]

We have started getting quite a few bug reports based on KASan. For example, http://marc.info/?l=linux-netdev&m=144524986130518&... and http://www.spinics.net/lists/linux-scsi/msg89404.html It seems like it will make a measurable improvement, similar to how lockdep improved locking.

I thought I would look at how the number of CVEs this year compares with previous years. I used the Ubuntu CVE tracker (https://launchpad.net/ubuntu-cve-tracker) and grepped for "kernel" and counted the CVEs for each year.

2005 112
2006 90
2007 80
2008 85
2009 118
2010 163
2011 161
2012 96
2013 190
2014 154
2015 72

We still have 20% of the year left so it's likely that we'll hit 90 something bugs before the year is over. Maybe more if we get a lot of KASan bugs, I suppose. I was thinking there would be a trend in those numbers but there really isn't... My gut says there is a increased focus on security these days so you would expect the number of CVEs to go up.

Looking at a few recent kernel security holes

Posted Oct 23, 2015 14:09 UTC (Fri) by SLi (subscriber, #53131) [Link] (7 responses)

Having done both some Linux kernel programming in C and other systems programming in C++, I cannot help but wonder if a fairly large number of these vulnerabilities (like buffer overflows) and other bugs (like resource leaks) could be avoided by not using C. RAII in particular, but also other things, are features that C just lacks and where the lack of them causes programmers to endlessly make the same mistakes because the compiler doesn't help you at all.

I know what Linus' opinion of C++ is, but perhaps it would be possible to sneak the good C++ features into C one by one and trick Linus into thinking it's not C++?

Looking at a few recent kernel security holes

Posted Oct 24, 2015 11:33 UTC (Sat) by JdGordy (subscriber, #70103) [Link]

gcc has some RAII extensions but they are pretty simple to mess up (or forget about). <wishful thinking>just start rewriting modules in rust...</thinking>

Looking at a few recent kernel security holes

Posted Oct 27, 2015 22:04 UTC (Tue) by Seegras (guest, #20463) [Link] (5 responses)

C-blublub? Ah no, that's a can of worms. For everything that it fixes it opens up new ways for screwing everything up.

But actually, there is something like C which does have features that makes the code really more secure. https://www.rust-lang.org/ Probably not useful for kernels, but certainly for everything else low-level.

Looking at a few recent kernel security holes

Posted Oct 28, 2015 17:12 UTC (Wed) by smckay (guest, #103253) [Link] (4 responses)

Rust has a freestanding subset which some people are using for embedded. I expect mostly just "Hello, ARM Cortex-M World!" but you can do it. If you're only dealing with a single core it seems like a reasonable choice. Once you get to something like the Linux kernel...the whole thing is horribly unsafe, and kind of has to be, because doing kernel things in a safe way would be horribly slow. You'd have to wrap practically the entire Rinux kernel in an unsafe block. Why bother?

P.S. To anyone who feels like saying that safe kernels don't have to be slow: I would very much appreciate a demonstration. For serious, please point me to the project website or Github so I can read more.

Looking at a few recent kernel security holes

Posted Oct 28, 2015 18:52 UTC (Wed) by madscientist (subscriber, #16861) [Link] (3 responses)

Of course since no one has done it yet we can't know for sure. But the conceit behind Rust is that the safety checking is a compile-time feature. So you get that safety at no cost to the runtime. Of course, some data structures (refcounted things etc.) have runtime overhead but presumably similar types of refcounting, etc. would be needed in a C program. I see no reason that the Rust implementations must be slower than the C ones.

I further see no reason why, even though clearly some unsafe parts are required, this would have to be all or even a significant part of the code.

Looking at a few recent kernel security holes

Posted Oct 28, 2015 19:23 UTC (Wed) by smckay (guest, #103253) [Link] (2 responses)

Mainly because safe Rust doesn't allow shared mutable state. The kernel's job is mainly to manage the huge pile of mutable state called a computer (RAM, CPU, disk, etc) and do the hard concurrent things on behalf of userspace. Safe Rust rests on top of unsafe Rust rests on top of the OS.

Looking at a few recent kernel security holes

Posted Oct 28, 2015 23:58 UTC (Wed) by mathstuf (subscriber, #69389) [Link] (1 responses)

Some researchers did a kernel in Rust and found that an additional parameter to data is "execution context" where you can make better guarantees and allows for more distributed resource management. I'll try and find a linkā€¦

Looking at a few recent kernel security holes

Posted Oct 30, 2015 4:50 UTC (Fri) by mathstuf (subscriber, #69389) [Link]


Copyright © 2015, Eklektix, Inc.
This article may be redistributed under the terms of the Creative Commons CC BY-SA 4.0 license
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy