Apparently this was done intentionally. The rationale given is that we don't want to allow non-safe C to be used in fil-C programs. Fair enough.
But why should we prevent fil-C programs to be used from Rust (or C, for that matter)?
I don't understand much about compilers, but I guess allowing one would also allow the other? i.e. it's not possible to make fil-C ABI compatible with C (so that it can be more easily called), while also not letting you use call C from it?
I worry that this same problem will doom the extern "Fil-C" idea that this post advocates. Zig is not really an encouraging precedent because Zig's proposed memory-safe mode adds runtime checks to everything just like Fil-C does, whereas the post author wants to avoid those checks for Rust code that's already statically known to be memory-safe. That said, it's possible I'm missing something.
It's not a replacement for Fil-C's role as a precise ASAN/Valgrind, but it works great if you want to call a C library without letting it freely spray caller's memory.
Fil-C is more precise than valgrind or asan. Valgrind and asan will allow a buggy access (like an OOB) to succeed if the resulting address is valid at all - which is useless from a security enforcement perspective since clobbering valid addresses is what the attacker is trying to do.
Fil-C only allows an access to succeed if it’s in bounds of that pointer’s capability. That is a useful level of precision for security, since it prevents the attacker from clobbering the addresses of their choice.
Solvable by turning the usual C library allocation pattern inside-out:
Only the C side allocates, Rust gets views of that memory.
Also well established - calling WebAssembly components requires exactly the same pattern, as the only way to malloc is to call into the WASM side.
The Fil-C side could change the data behind the pointer, which will not reflect on the Rust side due to the copy. Even if you manage to copy back the changes, Fil-C could also persist those pointers in e.g. global memory: at that point you no longer know when it's safe to copy back (or forward) any change.
The only way I can see this work if you cannot pass any Rust-land pointers into Fil-C, but at that point you could also compile the C code to WASM and use the WASM FFI (which has similar restrictions)
WASM is not memory safe in the same sense, in particular, heap corruption vulnerabilities still exist, which could eg. allow bypassing auth, leaking private information etc.
C compiled to WASM is still vulnerable to something like OpenSSL Heartbleed. Fil-C (and CHERI) is not.
While this cannot compile C/C++, it can serve as a fil-C alternative for unsafe pure rust code.
But it’s strictly less safe than either Fil-C or Rust since it only protects bounds
A normal C compiler actually has to worry about a lot of extreme cases.
Imagine a function takes two pointer arguments. What if they point to the same thing? What if one points to the other and is used for a write?
The nature of the code generated varies greatly if these are possibilities…
That being said I wouldn't be surprised if there were other factors that would weigh against considering FFI calls to Fil-C safe by default (e.g., Fil-C's somewhat looser bounds on what is considered a valid pointer access).
Out of curiosity. If you really needed to, could a language speak both the C ABI and the Fil-C ABI? As I understand Fil-C itself can't do this without having Python-like FFI overhead, but maybe a different compiler implementation could?
Hm on first reading I was confused by the extern "fil-c" framing -- that seems to imply a bridge between C and Fil-C, which introduces some nasty language/runtime inter-op issues.
But I like this part
I want a Rust FFI that speaks the Fil-C ABI. ... We could use Rust for compile-time safety and then pay a performance penalty for using C.
Say what you say, but there's plenty in that article looking like it came out of an LLM. This could of course be my own paranoia, since there's a lot of slop coming out right now.