|
|
Log in / Subscribe / Register

Two LSS talks

By Jake Edge
October 9, 2013

Linux Security Summit

The 2013 Linux Security Summit (LSS) had many different talks over its first day. It started with Ted Ts'o's keynote, then had several "refereed" talks (two of which were covered here: Embedded integrity and Kernel ASLR). The day ended with a selection of short topics, which were mostly updates on various security subsystems (SELinux, Smack, and Integrity). Unfortunately, there isn't enough time to write all of them up, but we will complete our LSS coverage with reports from two kernel-related talks.

LSM composition

Composing (or stacking) Linux Security Modules (LSMs) has been a perpetual topic in kernel security circles. We have looked at the problem and solutions many times over the years (most recently in August). Casey Schaufler has been working on a solution to the problem over the last few years. He presented the problem and his solution to the assembled security developers looking for guidance on where to go from here.

The problem in a nutshell is that there can be only one LSM active on any given boot of the kernel. But there are multiple use cases for having more than one active. Many think that certain combinations (e.g. SELinux and Smack) do not make sense, but there are reports of people who want to be able to combine arbitrary LSMs. In addition, only allowing a single LSM restricts systems with multiple containers to only using one security model, when it might be desirable to support all of them for use in different containers.

There is also the problem of special-purpose LSMs. Whenever someone brings up an idea for a new way to tighten security in the kernel core, they are almost inevitably pointed in the direction of the LSM API. But, since many distributions already ship with the single LSM slot filled, those smaller LSMs are unlikely to be used. Yama started off as a special-purpose LSM, but it was eventually manually—unconditionally—stacked so that it could coexist. That was meant as a temporary change until stacking was added to the kernel, but without a stacking solution, its temporary nature is somewhat in question.

Schaufler's proposal still follows the broad outlines we described a year ago. It has added the ability to stack any and all of the existing LSMs, which was not working at that point. It has also added a user-space interface that has separate directories for each LSM under /proc/PID/attr. It now tries to deal with labeled networking by restricting the different mechanisms (NetLabel, XFRM, and secmark) each to a single LSM per boot. The first LSM that asks for a given network labeling scheme "gets it". The details are available in Schaufler's slides [PDF] as well as the patches. But the point of his talk was mostly to get feedback and ideas on whether it was an idea worth moving forward with.

Some were not particularly happy with the user-space interface and/or the networking changes, believing that they added too much complexity. Others seemed skeptical that stacking was ever a sensible thing to do. But several folks spoke up from the audience about how they currently use multiple LSMs and have to carry out-of-tree patches to make it all work. In addition, the standard stacking arguments were restated. There is a clear demand for the feature—whether that is enough to overcome the objections remains to be seen.

In a post-presentation discussion, Paul Moore and Schaufler explored the possibility of pushing forward the stacking core, while leaving some of the "messier" pieces (like the user-space interface and labeled networking handling) as later additions. Most or all of the stated use cases would be fully served by a "simplified stacking" solution. The other pieces could continue to be worked on, or possibly dropped if there were no real users for them. That sounded like the approach that will be tried next, but, so far, patches have not yet appeared.

Core kernel anti-patterns

There are lots of known "anti-patterns" for kernel code, like busy waiting or hardcoding values, but security anti-patterns are not as well-known, Kees Cook said at the beginning of his talk. He and others have been spending some time trying to find "obvious" bugs in the kernel, some of which fall into the anti-pattern category. His talk was meant to document some of them to hopefully avoid them in the future.

It is frustrating that he can so easily find security holes in the kernel, he said. In addition, Dan Carpenter has been using smatch to find more examples of these anti-patterns once someone has found the first instance. Cook suggested that perhaps checkpatch.pl could be extended to catch some of this bad code long before it ever reached the kernel. He also suggested that kernel developers just go look for other examples of "something ugly" when they find such bugs—surprisingly often they will find many more instances.

Format strings are one source of these errors. For example:

    printk(buffer);
If the user can influence what goes into the buffer, they can put format specifiers into it, which can cause havoc. Fixing the problem is as easy as:
    printk("%s", buffer);
GCC can be used to help find these kinds of problems, using the format and format-security warning/error flags, but it is, unfortunately, "dumb" about const char *, so it will complain even for static buffers that are not exploitable.

A related problem is the addition of the "%n" format specifier, which writes the number of characters written to an address that is passed as an argument on the stack. It was not added to the kernel until 2009 and is only used for padding calculations in procfs output. But it is the format specifier of choice for those performing format string attacks. He would like to see support for that specifier removed entirely: "I don't care about prettiness if it leaves %n as an attack vector."

String manipulation is another area with lots of low-hanging fruit. He noted that strncpy() is generally a safer call than some others (e.g. strcpy()), but you have to check the length of the destination, not the source.

    strncpy(dest, src, strlen(src));
can sometimes be found and it will leave the dest string without a NULL termination. He suggested that for purposely leaving the destination unterminated, one should use memcpy() to make it clear.

Another problem that is fairly easy to find is unchecked copy_*_user() calls. The return from those is the number of bytes not copied, which typically indicates some kind of error. So calling those routines without checking the return value can lead to security holes. Various graphics drivers are currently guilty, he said.

Reading from the same user-space location twice can lead to a race condition where the value changes between the two reads. It is a hard race to win, but still a problem. This often happens when the first part of a structure being read from user space is the length of the data. The length is read in, the structure is allocated, then the whole thing (length and all) is read into the new structure. If the length changes between the reads, it can lead to problems. He has found this anti-pattern in both the kernel and U-Boot.

A problem similar to the double-read occurs in drivers for unusual devices. USB human interface devices (HID) have a complex way of describing the data being delivered. In a week's time, he found 12 CVEs in that code using malicious hardware. He verified each using a Facedancer a software-defined USB device, which allows him to write a Python script that acts like a USB device. In the future, he plans to look for problems in the mass storage and webcam USB drivers.

Cook said these kinds of bugs are an indication that the "many eyes" theory is failing in some areas. He knows this because he keeps finding the same kinds of bugs whenever he has time to look. There are tools that could help, including stronger GCC default flags and using the GCC plugins from the PaX project. Coccinelle and smatch are also useful. It is important that we get more proactive, he said, and keep these anti-patterns from ever getting into the kernel to begin with.

[I would like to thank LWN subscribers for travel assistance to New Orleans for LSS.]

Index entries for this article
KernelSecurity
SecurityLinux kernel
SecurityLinux Security Modules (LSM)
ConferenceLinux Security Summit/2013


to post comments

The 1970s called

Posted Oct 10, 2013 12:29 UTC (Thu) by HelloWorld (guest, #56129) [Link] (4 responses)

They want their programming languages back.

Seriously, does anybody else think it's pathetic that we still have to deal with format string vulnerabilities and buffer overflows? It's time that the kernel community acknowledges the fact that ordinary programmers (i. e. other than gurus like djb) can't write secure code in C. Rust will probably be a viable candidate for parts of the kernel code once it reached its 1.0 release. Not to mention that probably most of the code would be way shorter and cleaner in Rust due to superior abstraction facilities.

The 1970s called

Posted Oct 10, 2013 21:58 UTC (Thu) by dlang (guest, #313) [Link] (3 responses)

Rust is probably not even in the first hundred 'new secure languages that the kernel should be re-written in to solve all the evils of the world'

the answer now is the same as every other time.

If you think that writing a kernel in a different language is the right thing to do, go write it, and if you are correct and it is superior, you will displace Linux

Linus has said many times that he expects that eventually there will be some other kernel written that will replace Linux. It is possible that you are correct and Rust will be the language that such a kernel is written in.

but given the track record of such claims, I'm not going to worry about it.

The 1970s called

Posted Oct 11, 2013 10:51 UTC (Fri) by HelloWorld (guest, #56129) [Link] (2 responses)

> Rust is probably not even in the first hundred 'new secure languages that the kernel should be re-written in to solve all the evils of the world'
I never claimed that any language will solve all evils of the world, or that the kernel should be rewritten. But a programming language *can* solve silly things like buffer overflows (well, most of them) or format string vulnerabilities.
And let's not mention the fact that you didn't name even *one* argument why Rust wouldn't be a viable competitor. Especially when considering that I was talking about Rust 1.0 that isn't even released yet...

> If you think that writing a kernel in a different language is the right thing to do, go write it, and if you are correct and it is superior, you will displace Linux
So you're essentially saying that the success of a kernel is determined solely by the programming language it's implemented in? Because otherwise your point doesn't make any sense at all.

> Linus has said many times that he expects that eventually there will be some other kernel written that will replace Linux.
I don't think Linus is right about that. Linux is "too big to fail" by now, it's not going to be replaced. The best that one could hope for is an incremental solution to the C problem by allowing, say, some new drivers for non-critical hardware to be written in another language, and then gradually expand from there.

The 1970s called

Posted Oct 14, 2013 12:17 UTC (Mon) by rdc (guest, #87801) [Link] (1 responses)

>So you're essentially saying that the success of a kernel is determined solely by the programming language it's implemented in? Because otherwise your point doesn't make any sense at all.

No it't the exact arguement you make in the next paragraph, its too big to rewrite.

> I don't think Linus is right about that. Linux is "too big to fail" by now, it's not going to be replaced. The best that one could hope for is an incremental solution to the C problem by allowing, say, some new drivers for non-critical hardware to be written in another language, and then gradually expand from there.

The 1980s called they want there micro kernels back //tounge in check

The 1970s called

Posted Oct 14, 2013 22:59 UTC (Mon) by HelloWorld (guest, #56129) [Link]

> No it't the exact arguement you make in the next paragraph

He wrote this:
> If you think that writing a kernel in a different language is the right thing to do, go write it, and if you are correct and it is superior, you will displace Linux
The only ambiguity here is what "it" refers to. It could be either the newly written kernel or the Rust programming language. However, with the phrase "if you are correct" he clearly refers to some statement I made earlier, and I never said anything about some hypothetical new kernel, so he must be talking about the Rust language. So I'm sorry, but what he was saying just rubbish; he probably meant something else but it's hard to tell...

> The 1980s called they want there micro kernels back
The whole point of using a memory-safe language like Rust in the kernel is *not* having to bother with a Microkernel architecture.

Two LSS talks

Posted Oct 10, 2013 12:49 UTC (Thu) by etienne (guest, #25256) [Link] (7 responses)

Another anti-patterns which seems to have changed behaviour with newer GCC, at least on ARM:

void fct (const char *str)
{
char *ptr = strchr (str, ':');
if (ptr != 0) *ptr = '\0';
... do something with str which is declared const ...
}

Two LSS talks

Posted Oct 10, 2013 16:13 UTC (Thu) by mathstuf (subscriber, #69389) [Link] (6 responses)

Well, I don't see how this was guaranteed to work anyways. If `str` points to ro memory, you're hosed anyways. The C standard should fix these const -> non const issues at some point (as C++11/C++14 is finally doing). Is there a `strlchr` function floating around somewhere?

Two LSS talks

Posted Oct 10, 2013 19:39 UTC (Thu) by BenHutchings (subscriber, #37955) [Link] (5 responses)

The C standard should fix these const -> non const issues at some point (as C++11/C++14 is finally doing).

What you mean by that? Even C++98 requires std::strchr() and similar functions to be overloaded so that the return type matches the pointer argument type. I don't know how that could be achieved in C.

Two LSS talks

Posted Oct 10, 2013 20:06 UTC (Thu) by mathstuf (subscriber, #69389) [Link] (4 responses)

Well, the ideal fix's first step is "acquire time machine", but other than that, there's not much to be done other than something like a flag day (which I don't see happening any time soon), or adding overloading to C (somehow…), or CDR (C Done "Right") (which would never take off due to the incompatibilities).

If you're replying to the C++ side of things, it's most in reference to the fact that lots of container methods are now accepting const_iterator instead of iterator (such as erase() and insert()) so that you don't have to "infect" non-const-ness around to other places (or const_cast).

Two LSS talks

Posted Oct 11, 2013 9:24 UTC (Fri) by dgm (subscriber, #49227) [Link] (3 responses)

CDR exists. It's called Embedded C++: http://en.wikipedia.org/wiki/Embedded_C%2B%2B.

I always though ABC (A Better C) was a better name but, apparently, that's already taken.

Two LSS talks

Posted Oct 11, 2013 10:00 UTC (Fri) by khim (subscriber, #9252) [Link]

Embedded C++ is very strange creature because it removes one of the most important advantages of C++: namespaces. Thing like a namespace is more-or-less required to manage large programs and Embedded C++ forced the same fourty years old substitute (prefixes and/or suffixes).

Frankly I don't see a point. It's not really compatible with C++, but it's not compatible with C either. It includes not usable rounded-up set features but bunch of easily implementable features instead. In short: it's something designed to brag about, not something designed with real work in mind. Very similar to LSB: both in idea and in implementation. Only LSB has slowly started to acquire useful features recently, while EC++ just died.

Two LSS talks

Posted Oct 11, 2013 10:57 UTC (Fri) by HelloWorld (guest, #56129) [Link]

Embedded C++ is a pathetic idiocy that remove tons of useful functionality without any reason and doesn't solve any of the real problems that C and C++ have. Quoting Stroustrup: "To the best of my knowledge EC++ is dead (2004), and if it isn't it ought to be." (http://www.stroustrup.com/bs_faq.html#EC++).

Two LSS talks

Posted Oct 15, 2013 12:05 UTC (Tue) by jwakely (subscriber, #60262) [Link]

There is nothing done right about EC++, you'll have to try harder than that.

"Many eyes"

Posted Oct 10, 2013 21:42 UTC (Thu) by cesarb (subscriber, #6266) [Link] (4 responses)

He is one of these "many eyes", and he is finding bugs.

The theory seems to be working here.

"Many eyes"

Posted Oct 11, 2013 1:39 UTC (Fri) by mathstuf (subscriber, #69389) [Link] (2 responses)

I think it's more referencing the fact that there *are* lots of eyeballs on the code and there are *still* plenty of problems. That he can go in and find problems left and right isn't good even if he is fixing them; there's only so much time in a day.

"Many eyes"

Posted Oct 11, 2013 9:26 UTC (Fri) by dgm (subscriber, #49227) [Link] (1 responses)

Hey mathstuf, live up to your name and look at the "enough" part of the proposition (shall we call it theorem, conjecture?).

"Many eyes"

Posted Oct 11, 2013 10:03 UTC (Fri) by jezuch (subscriber, #52988) [Link]

> Hey mathstuf, live up to your name and look at the "enough" part of the proposition (shall we call it theorem, conjecture?).

The mathematical "enough" is a very, very abstract thing. "For a sufficiently large N" works for math, but it does not work for the real world.

"Given enough effort we can solve world hunger, ensure world peace and prosperity for all".

So, yeah, that doesn't prove anything, methinks.

"Many eyes"

Posted Oct 13, 2013 22:37 UTC (Sun) by jackb (guest, #41909) [Link]

We don't know how many of the eyes are paid not to report and fix those problems.

Actually we don't even know how many of the anti-patterns are accidental and how many are deliberate.

I wonder if the automated tools mentioned in the article could be hooked up to "git blame" and used to deduce possible patterns in the sources of vulnerabilities.


Copyright © 2013, 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