points by pizlonator 1 year ago

Fil-C is now best case 2x slower than normal C, worst case about 6x, and I haven’t even finished implementing the obvious optimizations.

I bet that the Intel chip I’m on is more than 6x faster than any of the CHERI hardware.

Fil-C has a more deterministic and safer handling of use-after-free and it’s flexible enough to run CPython (pretty sure CPython was too much for CHERI’s capabilities).

If you consider that:

- Fil-C will get faster even without architecture help

- Fil-C runs on normal HW

- it probably only takes a small extension to the HW to eliminate any remaining Fil-C overhead (a much smaller extension than CHERI).

- Fil-C is just a thing I pulled out of my ass in the last 10 months or so and is a totally solo spare-time project (I.e. if a real compiler team did this full time they’d probably make it even better than where I’m at)

Then it sure does seem like CHERI is going to be doomed long term.

IshKebab 1 year ago

A big application of CHERI is embedded where you can't just spend 6x more area/power on software.

Also CHERI isn't just about memory safety. It also supports software isolation & capabilities.

See CherIoT for an example of both of these.

  • pizlonator 1 year ago

    Fil-C is capability based and its capabilities offer stronger guarantees than CHERI’s.

    My point is that if a single dude working solo for 10 months gets to 6x overhead in the bad case then the overhead of the software capability approach (either exactly Fil-C or something vaguely like it) is likely to be much much less than 6x in the limit. Fil-C was 200x slower just six months ago and I’m not even done optimizing. That should give you an idea of where it’s heading.

nullc 1 year ago

CHERI is more powerful than memory-safe-C because it's a capability system. It's also still useful in a world where memory safe languages are common because the there is still a large amount of unsafe code that world and CHERI lets that unsafe code still maintain the guarantees the safe code relies on.

The cheri extension is rather small and simple, though isn't not extremely cheap due to the longer pointers and the tag bit.

Cheri does have an answer to temporal safety too, though it has added costs. Freed memory is not immediately reused, eventually the tagged memory is swept for references then the pointer freed memory can be reused. This is both safe and faster than you might guess because all tagged objects are capabilities and all capabilities are tagged.

The simplicity of cheri itself makes it easier to be confident that its protection is correct-- relative to the entirety of a compiler/libc/etc.

The cheri solution to use after free still kinda stinks though, so I think a combination of safer languages and cheri will be interesting in the future.

Edit: I see now that Fil-c is also a capabilities system. Thanks for bringing it to my attention.

  • pizlonator 1 year ago

    > The simplicity of cheri itself makes it easier to be confident that its protection is correct-- relative to the entirety of a compiler/libc/etc.

    To get confidence in Fil-C’s safety, you don’t have to prove anything about the libc because the libc is compiled with Fil-C.

    You have to prove stuff about the compiler and Fil-C’s runtime. The runtime is about 100KLoC.

gchadwick 1 year ago

Improved hardware based abstractions to provide stronger security and better ways to isolate software components just seems like a good idea. Yes you can certainly do plenty in software (in particular using language like Rust) but presumably we still want hardware enforced security properties? So why not improve those as well as software?

To put it another way why not remove existing hardware security abstractions we do have? Ditch virtualization (or hugely strip it back), get rid of different privilege levels, loose page-table enforced permissions. After all you can just build safe software why bother with these things?

I for one don't think this is a sensible line of argument, defence in depth is a good idea, build your software to be as secure as possible then build your hardware such that if there is some flaw in your software's defences you can keep things contained though hardware abstractions.

Even with improved languages there's a giant body of existing code you need to work with, with compartmentalization in CHERI you can keep this stuff safely contained. Plus how do you guarantee everything running on the system has been built in your safe language and compiled with your blessed known good compiler? Feasible in some places (like embedded systems) far less feasible in others.

  • pizlonator 1 year ago

    Fil-C is not ABI compatible with regular C, so there’s no way to accidentally forget to compile some part of your stack with Fil-C.

    If changing all the HW we use was as easy as waving a wand, then your argument would be sound. Unfortunately, it’s super hard to get folks to use different HW. And because of how silicon economics work out, a new upstart architecture with limited users is sure to experience slower perf scaling than the mainstream HW. That strongly disincentivizes anyone from being an early adopter of exotic new HW. I think that’s why CHERI isn’t mainstream yet despite a decade of investment.

    Hence why even ignoring Fil-C, it’s probably more realistic to rewrite stuff in Rust than it is to switch to CHERI. Fil-C adds a third option where you pay some perf but you don’t have to rewrite your code or switch what HW you use. CHERI also costs perf - practically speaking, available CHERI HW is more than 6x slower than the HW Fil-C can run on. That’s fundamental, due to silicon economics.

    Finally, I think you’re overselling the CHERI defense in depth. My understanding is that CHERIoT doesn’t use virtual memory and that there are subtle reasons why virtual memory and CHERI put together gets weird, especially if you want to support capability revocation. On the other hand, Fil-C works on top of virtual memory so you get both virtual memory protection and capability protection, hence more defense in depth.

    • nullc 1 year ago

      Rust still needs CHERI to fully deliver on our expectations because it is astonishingly easy for unsafe code to violate sometimes subtle invariant that must be upheld for safe code to be safe. And both due to performance and because some correct and important code structures can't be represented well in safe rust, there will always exist some unsafe code.

      One of the advantages of CHERI is that you can get a safe system with no virtual memory, no overheads of TLB lookups and hardware, etc. but you don't have to do that. The CHERI arm and riscv64 designs have the normal memory management hardware.

      • pizlonator 1 year ago

        That’s pretty damning if Rust needs CHERI to be fully safe. Fil-C has no such problem since there is no unsafe statement in Fil-C.

        No virtual memory is not an advantage of CHERI, it’s a disadvantage. It means CHERI replaces a very well understood security barrier (virtual memory) with one that is less well understood (no matter how many proofs you write about it). I would be more willing to buy CHERI’s claims if they had kept virtual memory. Fil-C plays nice with virtual memory so there’s no need to disable it.

        • remexre 1 year ago

          CHERI is insufficient for unsafe Rust to be fully safe, and I suspect Fil-C plus C's restrict is insufficient as well (if restrict isn't treated as a no-op, of course).

          For unsafe Rust code to be sound, it has to uphold the invariant that no location pointed to by an &mut is modified through a pointer not derived from that &mut. However, there's no such restriction on *mut pointers ("raw pointers"), and it is in many cases perfectly sound (but unsafe, of course) to cast from *mut to &mut, or to directly mutate through a *mut. Without maintaining global information about what references are live, it sounds really, really hard to guarantee this.

          • pizlonator 1 year ago

            Restrict is treated as a no-op in Fil-C. Fil-C offers no escape hatch from memory safety, period.

        • nullc 1 year ago

          CHERI plays fine with virtual memory, it's omitted in some of these minimized cores because it's not necessary for security and the target cores didn't have virtual memory to begin with.

          It's still useful for making swapping work efficiently, but that's not relevant on a tiny embedded device.

          • pizlonator 1 year ago

            What happens if you do a shared memory mapping and place capabilities into it?

            Fil-C just says that shared memory mappings are integer-only, so trying to place a capability there instantly traps. That’s both sound and adequate even for sophisticated uses of shared memory.

            My understanding is that this is a conundrum for CHERI, but maybe my understanding is wrong.

pitaj 1 year ago

It's an interesting approach. A hybrid software with limited hardware change is interesting.

> Fil-C will get faster even without architecture help

Only to a point. You'll plateau eventually since you have checks on every dereference.

  • pizlonator 1 year ago

    No, I won’t have checks on every dereference. The monotonicity of Fil-C’s capabilities makes it possible to do a lot of redundant check elimination.

    That’s what I’m working on now. Should have some early results soon.

    • pitaj 1 year ago

      Obviously, removing repeated/redundant bounds checks is a basic optimization. That's not what I meant. My point still stands.

      • pizlonator 1 year ago

        I think that check on every access is a lot different than check on some accesses.

        That plateau might not be any different than the CHERI plateau, since at the microarch level, CHERI will have more checks since it cannot benefit from a compiler’s static reasoning about redundant check elimination.

pitaj 1 year ago

Recompiling everything is a non-starter in many cases.

  • pizlonator 1 year ago

    If recompiling is a nonstarter then a new HW arch like CHERI is even more of a nonstarter.

    • nwf 1 year ago

      That's only mostly true; Big CHERI (that is, the 64-bit CHERI systems, not CHERIoT) specifically has support for running legacy binaries within capability confinement. It's true that we think recompiling is generally the better approach, but we can sandbox pre-CHERI libraries, for example, at library-scale granularity.