Would a Rust OS need paging?
Would a Rust OS need paging?
I'm getting comfortable with Rust, and the pointer safety mechanisms are really nice. But the Rust website clearly states they're purely compile-time, and indistinguishable from C pointers at run-time. Due to a lack of grasping paging and the relationship between the kernel's C library and the standard C library, I had come under the assumption that a Rust-based OS would still need paging as it's not performing any type safety at runtime. But then I saw this page making some grandiose statements, namely that paging wouldn't be necessary. Even if everything for this OS was written in Rust, any hand-crafted C or Assembly could probably wreak some havoc.
So am I right? Or would this really not need paging? I know the other benefits of paging of course, I'm just trying to clear up some ambiguity for myself.
So am I right? Or would this really not need paging? I know the other benefits of paging of course, I'm just trying to clear up some ambiguity for myself.
Last edited by konacake on Thu Dec 04, 2014 2:43 pm, edited 1 time in total.
Re: Would a Rust OS need paging?
I'd say that you are right. The author of that project doesn't appear to understand what paging is and why it is used. (S)he probably doesn't use it because (s)he doesn't know how to code it.
- thepowersgang
- Member
- Posts: 734
- Joined: Tue Dec 25, 2007 6:03 am
- Libera.chat IRC: thePowersGang
- Location: Perth, Western Australia
- Contact:
Re: Would a Rust OS need paging?
Rust is still a compiled language, and even within the source, there's unsafe blocks which allow use of raw pointers. You still need paging with a rust OS (for security and defensive programming reasons).
Even without that, paging gives you far more features than just protection (memory tracing, swapping, memory-mapped files, etc.) - For that reason, I didn't even think about going single-address-space for my rust kernel.
Even without that, paging gives you far more features than just protection (memory tracing, swapping, memory-mapped files, etc.) - For that reason, I didn't even think about going single-address-space for my rust kernel.
Kernel Development, It's the brain surgery of programming.
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Acess2 OS (c) | Tifflin OS (rust) | mrustc - Rust compiler
Currently Working on: mrustc
Re: Would a Rust OS need paging?
RustOS author here.konacake wrote:I'm getting comfortable with Rust, and the pointer safety mechanisms are really nice. But the Rust website clearly states they're purely compile-time, and indistinguishable from C pointers at run-time. Due to a lack of grasping paging and the relationship between the kernel's C library and the standard C library, I had come under the assumption that a Rust-based OS would still need paging as it's not performing any type safety at runtime. But then I saw this page making some grandiose statements, namely that paging wouldn't be necessary. Even if everything for this OS was written in Rust, any hand-crafted C or Assembly could probably wreak some havoc.
So am I right? Or would this really not need paging? I know the other benefits of paging of course, I'm just trying to clear up some ambiguity for myself.
That part of the readme is a little old, but the original idea is to use the rust language to enforce safety. So, the OS wouldn't allow execution of arbitrary code, but only code that could be guaranteed to be safe. And the way of guaranteeing native code to be safe would be, for example, to compile safe high-level code it with a trusted compiler.
-
- Member
- Posts: 307
- Joined: Wed Oct 30, 2013 1:57 pm
- Libera.chat IRC: no92
- Location: Germany
- Contact:
Re: Would a Rust OS need paging?
Every OS has to choose whether to use paging (the normal choice) or segmentation (pretty rare nowadays) of some sort. Memory management relies on it.
Re: Would a Rust OS need paging?
You really don't actually need paging or segmentation in such a system. Like the README says, "everything is running in kernel mode and safety is enforced by the language." If you only ever run Rust code (potentially with unsafe forbidden by the compiler), and it only links with the libraries provided by the OS, there's no way to break out.
One big use case would be something like MirageOS- you write your application in the verified language, link it directly with the kernel, and run the whole thing in kernel mode. This is a particularly good way to do virtualized server applications- instead of virtualizing a full OS, you just virtualize a bare-metal application that has its safety verified at compile time.
Another use case would be something like Singularity. It's a little bigger in scope, in that you can load and run new programs beyond what you built the OS image with, but those programs are still written in the safe language, compiled by a trusted compiler, and linked with trusted libraries (the compiler and libraries included with the OS). Still no way to escape.
Of course, you may still want paging to help avoid memory fragmentation, or to provide virtual memory, or whatever else, but it's not needed for security. It's only once you can run arbitrary binaries off external media or the internet or wherever that you need any kind of hardware memory protection.
One big use case would be something like MirageOS- you write your application in the verified language, link it directly with the kernel, and run the whole thing in kernel mode. This is a particularly good way to do virtualized server applications- instead of virtualizing a full OS, you just virtualize a bare-metal application that has its safety verified at compile time.
Another use case would be something like Singularity. It's a little bigger in scope, in that you can load and run new programs beyond what you built the OS image with, but those programs are still written in the safe language, compiled by a trusted compiler, and linked with trusted libraries (the compiler and libraries included with the OS). Still no way to escape.
Of course, you may still want paging to help avoid memory fragmentation, or to provide virtual memory, or whatever else, but it's not needed for security. It's only once you can run arbitrary binaries off external media or the internet or wherever that you need any kind of hardware memory protection.
Re: Would a Rust OS need paging?
That might be true if it could be formally verified that no bugs exist in the compiler and runtime. As it is, with having to install critical JVM updates seemingly every week, I for one am somewhat less enthused about sandboxed runtimes in practice than I might have been in the abstract. And Rust code doesn't even compile to intermediary bytecode but to genuine machine code, compounding the problem.Rusky wrote:You really don't actually need paging or segmentation in such a system. Like the README says, "everything is running in kernel mode and safety is enforced by the language." If you only ever run Rust code (potentially with unsafe forbidden by the compiler), and it only links with the libraries provided by the OS, there's no way to break out.
Developer of libc11
-
- Member
- Posts: 307
- Joined: Wed Oct 30, 2013 1:57 pm
- Libera.chat IRC: no92
- Location: Germany
- Contact:
Re: Would a Rust OS need paging?
@Rusky: You're partly not talking about a monolithic/microkernel any more, but about things like exokernels, which aren't really suited for day-to-day useage. The only OSes that don't use paging/segmentation are Hello World operating systems.
- AndrewAPrice
- Member
- Posts: 2303
- Joined: Mon Jun 05, 2006 11:00 pm
- Location: USA (and Australia)
Re: Would a Rust OS need paging?
Paging isn't just about protecting against bugs, but also against malicious arbitrary machine code. We mostly care about allowing users to execute arbitrary machine code so people can use their own languages and compilers.
If the goal is everything-must-be-written-in-Rust, that's fine. You could have a LUA or Javascript OS where the kernel is one big virtual machine and everything it executes must be in that language (no arbitrary machine code).
Regarding the performance of not having paging enabled - I don't know if context switching is that big of a performance penalty. You still have to save your registers, the only thing you're not doing is invalidating the TLB (equivalent to switching threads within the same running programs).
In long mode (x86_64), you're forced to use paging. With paging, you can worry less about memory fragmentation as physical pages all over memory can be mapped sequentially in virtual memory - giving every new process a clean address space, in contrast to one operating system level allocator that's used for all programs that would eventually get very fragmented - and you may not be able to fit large objects (such as a screen buffer) on a long running allocator, unless it was some kind of compacting garbage collector, at which time, the overhead of not using paging would have outweighed the advantages.
MMU-less operating systems aren't a bad idea, but you shouldn't be scared of paging. It's really just something you deal with and figure out once when you start on your kernel, and then not have to worry about it again until you want to add advance features.
Also, on x86_64, a lot of the instructions only take 32-bit operands, so compilers like things in the first or last 2GB of virtual memory - to access memory or jump to code outside of the first and last 2GB of virtual memory, it needs to copy the 64-bit address to a register first.
You also have your paging tricks - swapping memory out to a page file, giving the illusion of a lot more memory, and allowing applications handle their own page faults (when you try to access an unmapped page) so they can lazily load resources, using page faults to implement memory mapped files, etc.
If the goal is everything-must-be-written-in-Rust, that's fine. You could have a LUA or Javascript OS where the kernel is one big virtual machine and everything it executes must be in that language (no arbitrary machine code).
Regarding the performance of not having paging enabled - I don't know if context switching is that big of a performance penalty. You still have to save your registers, the only thing you're not doing is invalidating the TLB (equivalent to switching threads within the same running programs).
In long mode (x86_64), you're forced to use paging. With paging, you can worry less about memory fragmentation as physical pages all over memory can be mapped sequentially in virtual memory - giving every new process a clean address space, in contrast to one operating system level allocator that's used for all programs that would eventually get very fragmented - and you may not be able to fit large objects (such as a screen buffer) on a long running allocator, unless it was some kind of compacting garbage collector, at which time, the overhead of not using paging would have outweighed the advantages.
MMU-less operating systems aren't a bad idea, but you shouldn't be scared of paging. It's really just something you deal with and figure out once when you start on your kernel, and then not have to worry about it again until you want to add advance features.
Also, on x86_64, a lot of the instructions only take 32-bit operands, so compilers like things in the first or last 2GB of virtual memory - to access memory or jump to code outside of the first and last 2GB of virtual memory, it needs to copy the 64-bit address to a register first.
You also have your paging tricks - swapping memory out to a page file, giving the illusion of a lot more memory, and allowing applications handle their own page faults (when you try to access an unmapped page) so they can lazily load resources, using page faults to implement memory mapped files, etc.
My OS is Perception.
Re: Would a Rust OS need paging?
Hi,
This isn't about Rust, but using a managed language for protection (instead of using the protection mechanisms the CPU provides). In general:
For other cases (e.g. intentionally skewed benchmarks that don't resemble realistic work-loads running on CPUs or OSs that don't have "Process-context identifiers") it can matter a lot.
For all cases, it'd be a mistake to only consider the disadvantages of paging without also taking into account the advantages. For example, if you do accurate and fair measurements and find that paging/TLB misses adds 5% overhead but also saves 10% of overhead in other areas, then it'd be silly to say "OMG, 5% overhead! Let's get rid of paging".
Cheers,
Brendan
This isn't about Rust, but using a managed language for protection (instead of using the protection mechanisms the CPU provides). In general:
- If anyone wants self modifying code (including virtual machines/JIT compiling), you're screwed (it's prohibited by the OS design).
- There are still cases where assembly is needed for performance. Optimising compilers are "good" (nowhere near perfect).
- Bugs in either the compiler, the kernel or the device drivers can leave you with no protection at all. In terms of surface area that's a massive amount of complex code that has to be perfect (or in other words, guaranteeing protection is virtually impossible).
- Not all problems are software problems. For example, with "guaranteed perfect" software, a simple RAM error can corrupt "assumed safe" native code, and in that case there's nothing to catch the problem before it (potentially) does serious damage.
- For some cases (e.g. long mode on 80x86) it's simply not possible to disable the CPU's protection, so you gain nothing by not using it
- In most cases, you need paging for other reasons, so you gain nothing by not using it for (additional?) protection.
That depends a lot on both the CPU and the code it's executing. For some cases (e.g. "ping pong" on modern 80x86 where the OS uses the CPU's "Process-context identifiers" to avoid TLB flush on virtual address space switches; or thread switches within the same process) there's no performance penalty. For other cases the performance penalty is hidden by out-of-order execution and/or SMT. For other cases it doesn't happen often enough to matter (e.g. CPU bound tasks).MessiahAndrw wrote:Regarding the performance of not having paging enabled - I don't know if context switching is that big of a performance penalty. You still have to save your registers, the only thing you're not doing is invalidating the TLB (equivalent to switching threads within the same running programs).
For other cases (e.g. intentionally skewed benchmarks that don't resemble realistic work-loads running on CPUs or OSs that don't have "Process-context identifiers") it can matter a lot.
For all cases, it'd be a mistake to only consider the disadvantages of paging without also taking into account the advantages. For example, if you do accurate and fair measurements and find that paging/TLB misses adds 5% overhead but also saves 10% of overhead in other areas, then it'd be silly to say "OMG, 5% overhead! Let's get rid of paging".
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
-
- Member
- Posts: 307
- Joined: Wed Oct 30, 2013 1:57 pm
- Libera.chat IRC: no92
- Location: Germany
- Contact:
Re: Would a Rust OS need paging?
tl;dr: to have a relatively secure system, you have to be seriously paranoid. Rust isn't the complete solution to the problem.
Re: Would a Rust OS need paging?
@no92: I was never talking about monolithic, micro, or exokernels. Whether protection domains are implemented in software or hardware is a completely orthogonal concept. In fact, paging/segmentation aren't even the only ways to implement protection domains in hardware.
There are certainly large tradeoffs between hardware and software protection, but that doesn't mean they're not both useful.
Compile-time, software-protected bare metal applications (like MirageOS or this Rust experiment) work great for embedded systems (cheaper hardware, less chance of things going wrong at runtime while your microcontroller is trying to land a probe on an asteroid) and virtualization (you already have a different sort of hardware protection, why emulate another?).
Managed language systems (like Inferno, SingularityOS, or web browsers) work great for portability (your cross-OS and cross-CPU browser already needs to keep JavaScript from messing with other tabs/windows).
Imperfectly-verified compilers and cosmic rays are no reason to completely ignore chunks of the design space. There are also imperfectly-verified CPUs and flipped bits in page tables... and not everybody wants to make a unix clone for desktop machines.
There are certainly large tradeoffs between hardware and software protection, but that doesn't mean they're not both useful.
Compile-time, software-protected bare metal applications (like MirageOS or this Rust experiment) work great for embedded systems (cheaper hardware, less chance of things going wrong at runtime while your microcontroller is trying to land a probe on an asteroid) and virtualization (you already have a different sort of hardware protection, why emulate another?).
Managed language systems (like Inferno, SingularityOS, or web browsers) work great for portability (your cross-OS and cross-CPU browser already needs to keep JavaScript from messing with other tabs/windows).
Imperfectly-verified compilers and cosmic rays are no reason to completely ignore chunks of the design space. There are also imperfectly-verified CPUs and flipped bits in page tables... and not everybody wants to make a unix clone for desktop machines.