I wonder what would happen if we can find a way to build software protection in supervisor mode, ditching user mode and associated context switches.
I wonder what would happen if we can find a way to build software protection in supervisor mode, ditching user mode and associated context switches.
For example, if you are building a grid computer, you don't need mechanisms that were designed to protect university students from one another. Consider if everything is driven from a single codebase. Your type system can provide protections that have traditionally been done by the kernel.
I am currently playing with this. Have a boot loader up, and a handoff to c++. Today I am looking at page-management.
There are some interesting trade-offs that come from unconventional approaches like this. For example, I have read that if you make SIMD registers available to the kernel, it hurts the performance of context-switching. (https://os.phil-opp.com/minimal-rust-kernel/)
A mitigation I am considering: do all interrupt handling on one core, and then have all other cores for work-processing. Use channels to communicate between the burnt interrupt core and the worker cores. Downside of this: worker cores would need to poll for new messages. In low-activity periods, I could slow the poll interval. I would be interested to hear from anyone who has gone deep on this, or knows of papers.
For what you're doing I recall reading about IncludeOS[1] which seems to have similar goals
Ideally, OS's would explicitly support information protection domains (after all, this is already a feature in some niche, specialized OS's) and only sensitive info/data would be protected by a switch to a different protection domain. Most user tasks which deal entirely with non-critical data could simply run in a shared address space.
That's nonsense! Separate address spaces have nothing to do with hardware vulnerabilities. The MMU uses address spaces to isolate processes from each other, which is required for proper multi-tasking.
If you don't use process isolation, every task can overwrite the heap and stack of every other running task (including the OS kernel and drivers!). Information disclosure (in this context) is only relevant in virtual environments, where multiple tenants have to be strictly isolated from each other and affects (hardware) VM supervisors.
It's a different topic entirely.
This is not a concern if all code is rigorously checked for memory safety which is quite feasible in principle, and possibly already the case for some uses of WASM/WASI. (Native binary code would need to be annotated with low-level proofs, to be checked by the OS.)
It's impossible to automatically check memory safety at compile time as that implies solving the Halting Problem.
Runtime checks would need to rely on the compiler enforcing these checks in the RTL. This, however, can easily circumvented using return-oriented programming (remember: you don't want the MMU to protect stack spaces).
No amount of software-based sandboxing or compile-time checks can effectively prevent non-isolated processes from accessing and corrupting each other's state. That's exactly why MMU were introduced in the first place.
Experiments using Software-Isolated Processes like Microsoft's Singularity [1] rely on complete toolchains from OS kernel to "safe" languages and runtimes and are not suitable for every requirement (e.g. hard real-time becomes near impossible).
The SIP concept also just shifts the burden of proving correctness from app and system developers to compiler and toolchain developers and we all know that those guys never make mistakes ;)
[1] https://www.microsoft.com/en-us/research/wp-content/uploads/...
For the general case, yeah. And while I agree that I would not remove process isolation, I think they have a point about "almost guaranteed to be safe" languages could be potentially used without isolation (not with zero risk, of course).
We have a lot of modern languages that are memory safe at least in theory. However quite a few rely on the OS using these safety features in the background. For example the Java Runtime uses segfaults to catch null pointers instead of actively checking for them, at least as far as I remember.