* Ingo Molnar <mi...@kernel.org> wrote:
> * Andy Lutomirski <l...@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