[RFC PATCH 2/7] x86/sci: add core implementation for system call isolation

Ingo Molnar mingo at kernel.org
Sat Apr 27 10:46:15 UTC 2019


* Ingo Molnar <mingo at kernel.org> wrote:

> * Andy Lutomirski <luto at kernel.org> wrote:
> 
> > > And no, I'm not arguing for Java or C#, but I am arguing for a saner
> > > version of C.
> > 
> > IMO three are three credible choices:
> > 
> > 1. C with fairly strong CFI protection. Grsecurity has this (supposedly 
> > — there’s a distinct lack of source code available), and clang is 
> > gradually working on it.
> > 
> > 2. A safe language for parts of the kernel, e.g. drivers and maybe 
> > eventually filesystems.  Rust is probably the only credible candidate. 
> > Actually creating a decent Rust wrapper around the core kernel 
> > facilities would be quite a bit of work.  Things like sysfs would be 
> > interesting in Rust, since AFAIK few or even no drivers actually get 
> > the locking fully correct.  This means that naive users of the API 
> > cannot port directly to safe Rust, because all the races won't compile
> > :)
> > 
> > 3. A sandbox for parts of the kernel, e.g. drivers.  The obvious 
> > candidates are eBPF and WASM.
> > 
> > #2 will give very good performance.  #3 gives potentially stronger
> > protection against a sandboxed component corrupting the kernel overall, 
> > but it gives much weaker protection against a sandboxed component 
> > corrupting itself.
> > 
> > In an ideal world, we could do #2 *and* #3.  Drivers could, for 
> > example, be written in a language like Rust, compiled to WASM, and run 
> > in the kernel.
> 
> So why not go for #1, which would still outperform #2/#3, right? Do we 
> know what it would take, roughly, and how the runtime overhead looks 
> like?

BTW., CFI protection is in essence a compiler (or hardware) technique to 
detect stack frame or function pointer corruption after the fact.

So I'm wondering whether there's a 4th choice as well, which avoids 
control flow corruption *before* it happens:

 - A C language runtime that is a subset of current C syntax and 
   semantics used in the kernel, and which doesn't allow access outside 
   of existing objects and thus creates a strictly enforced separation 
   between memory used for data, and memory used for code and control 
   flow.

 - This would involve, at minimum:

    - tracking every type and object and its inherent length and valid 
      access patterns, and never losing track of its type.

    - being a lot more organized about initialization, i.e. no 
      uninitialized variables/fields.

    - being a lot more strict about type conversions and pointers in 
      general.

    - ... and a metric ton of other details.

 - If such a runtime could co-exist without big complications with 
   regular C kernel code then we could convert particular pieces of C 
   code into this safe-C runtime step by step, and would also allow the 
   compilation of a piece of code as regular C, or into the safe runtime.

 - If a particular function can be formally proven to be safe, it can be 
   compiled as C - otherwise it would be compiled as safe-C.

 - ... or something like this.

The advantage would be: data corruption could never be triggered by code 
itself, if the compiler and runtime is correct. Return addresses and 
stacks wouldn't have to be 'hardened' or 'checked', because they'd never 
be corrupted in the first place. WX memory wouldn't be an issue as kernel 
code could never jump into generated shell code or ROP gadgets.

The disadvantage: the overhead of managing this, and any loss of 
flexibility on the kernel programming side.

Does this make sense, and if yes, does such a project exist already?
(And no, I don't mean Java or C#.)

Or would we in essence end up with a Java runtime, with C syntax?

Thanks,

	Ingo



More information about the Linux-security-module-archive mailing list