Hi,
I'm looking to run Genode on an ARM Cortex A8. I'm primarily interested in the security properties of the resulting system. I'm explicitly not interested in running multiple OS personalities or doing virtualization. What I do want is as pure an object capability system as possible and as small an attack surface as possible. This seems to suggest Fiasco.OC or OKL4, but perhaps the bare hardware kernel is better. I think NOVA doesn't come into question, because it only runs on x86.
I couldn't find much information about the bare hardware kernel. I'd appreciate any pointers.
Thanks!
:) Neal
Hi Neal,
The Genode base provided by base-hw follows the approach to minimalize the code running in privileged CPU mode. Its kernel (base-hw/src/core/kernel*) is a single-threaded state machine that tries to hand over handling of caught hardware- exceptions as fast as possible to userland. Additionally we try to keep the kernel interface (base-hw/include/kernel/syscalls.h) small and expressive.
Nethertheless I'm afraid that base-hw kernel isn't yet what your looking for. It doesn't handle real capabilities by now. Instead it links kernel objects to global names that are provided to the userland. Genodes capabilities are only carriers of these global names but they're not backed by an in-kernel right- management. If a thread guesses a global name right, it is allowed to acces the according kernel object.
However, adding capability based right management is one of the next profound issues in base-hw, so it might be a solution for your requirements in the near future.
I'm not that skilled at the other base repositories of Genode but I'm sure the other Genode fellows can help you with this. If you have further questions don't hesitate to ask.
Best regards, Martin
On 24.10.2013 11:28, Neal H. Walfield wrote:
Hi,
I'm looking to run Genode on an ARM Cortex A8. I'm primarily interested in the security properties of the resulting system. I'm explicitly not interested in running multiple OS personalities or doing virtualization. What I do want is as pure an object capability system as possible and as small an attack surface as possible. This seems to suggest Fiasco.OC or OKL4, but perhaps the bare hardware kernel is better. I think NOVA doesn't come into question, because it only runs on x86.
I couldn't find much information about the bare hardware kernel. I'd appreciate any pointers.
Thanks!
:) Neal
October Webinars: Code for Performance Free Intel webinars can help you accelerate application performance. Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from the latest Intel processors and coprocessors. See abstracts and register > http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clk... _______________________________________________ Genode-main mailing list Genode-main@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/genode-main
Hi Martin,
At Thu, 24 Oct 2013 12:26:41 +0200, Martin Stein wrote:
Nethertheless I'm afraid that base-hw kernel isn't yet what your looking for. It doesn't handle real capabilities by now. Instead it links kernel objects to global names that are provided to the userland. Genodes capabilities are only carriers of these global names but they're not backed by an in-kernel right- management. If a thread guesses a global name right, it is allowed to acces the according kernel object.
This is definately not what I'm looking for. Thanks for the help.
:) Neal
If no other solves this problem beforehand (it's all open source), I think we'll not implement it before the end of this year. But there is a good chance for it to happen during the first half of 2014.
Martin
On 24.10.2013 13:01, buzz heavyyear wrote:
Hi Martin
However, adding capability based right management is one of the next profound issues in base-hw, so it might be a solution for your requirements in the near future.
Do you have a rough idea when this will be implemented?
Thanks Best regards Nick
October Webinars: Code for Performance Free Intel webinars can help you accelerate application performance. Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from the latest Intel processors and coprocessors. See abstracts and register > http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clk...
Genode-main mailing list Genode-main@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/genode-main
OK, thanks :)
Date: Thu, 24 Oct 2013 14:04:39 +0200 From: martin.stein@...1... To: genode-main@lists.sourceforge.net Subject: Re: Choosing a Kernel
If no other solves this problem beforehand
(it's all open source), I think we'll not implement
it before the end of this year. But there is a
good chance for it to happen during the first
half of 2014.
Martin
On 24.10.2013 13:01, buzz heavyyear wrote:
Hi Martin
> However, adding capability based right
> management is one of the next profound
> issues in base-hw, so it might be a solution
> for your requirements in the near future.
Do you have a rough idea when this will be implemented?
Thanks Best regards Nick
------------------------------------------------------------------------------ October Webinars: Code for Performance Free Intel webinars can help you accelerate application performance. Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from the latest Intel processors and coprocessors. See abstracts and register > http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clk...
_______________________________________________ Genode-main mailing list Genode-main@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/genode-main
------------------------------------------------------------------------------ October Webinars: Code for Performance Free Intel webinars can help you accelerate application performance. Explore tips for MPI, OpenMP, advanced profiling, and more. Get the most from the latest Intel processors and coprocessors. See abstracts and register > http://pubads.g.doubleclick.net/gampad/clk?id=60135991&iu=/4140/ostg.clk... _______________________________________________ Genode-main mailing list Genode-main@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/genode-main
Hi Neal,
from what you write, I'd suggest to go for Fiasco.OC as it runs on ARM Cortex and provides real object capabilities. In my opinion, this kernel is not a perfect choice esp. looking at minimality but will get you the best available. Note, for several reasons Genode on OKL4 does only support version 2.1, which disqualifies it in both regards - ARM and object capabilities.
Regards
Hi, Christian,
At Thu, 24 Oct 2013 17:53:41 +0200, Christian Helmuth wrote:
from what you write, I'd suggest to go for Fiasco.OC as it runs on ARM Cortex and provides real object capabilities. In my opinion, this kernel is not a perfect choice esp. looking at minimality but will get you the best available. Note, for several reasons Genode on OKL4 does only support version 2.1, which disqualifies it in both regards - ARM and object capabilities.
Thanks for the prompt reply. I'll take a closer look at Fiasco.OC.
In terms of Genode support, where does Fiasco.OC rank? Is the current focus on a custom kernel (which I guess is the bare hardware solution)?
If you have a moment, could you mention some more of the disadvantages of Fiasco.OC that you were thinking of?
Thanks!
:) Neal
Hello Neal,
On Thu, Oct 24, 2013 at 10:23:24PM +0200, Neal H. Walfield wrote:
In terms of Genode support, where does Fiasco.OC rank? Is the current focus on a custom kernel (which I guess is the bare hardware solution)?
First, the base-hw kernel is our first choice when exploring new grounds, e.g., porting to new ARM platforms or testing specific ARM features like TrustZone. For us, base-hw is the least complex Genode platform and we have a thorough understanding of its internals.
Beyond that, Genode has extensive support for both NOVA and Fiasco.OC which includes real object capabilities. We use all supported kernels regularly in practice as each has its own benefits when it comes to debugging or platform support. But, NOVA and Fiasco.OC receive special attention currently.
If you have a moment, could you mention some more of the disadvantages of Fiasco.OC that you were thinking of?
My personal opinion about Fiasco.OC is somewhat ambivalent. The kernel has certain assets: extensive hardware-platform support for x86 32/64bit and various ARM platforms, object-capability support, and regular updates. On the other hand, our team is repeatedly hit by the following peculiarities.
- Fiasco.OC does not bring a precise specification of its interface and semantics. This forces us to derive assumptions about expected behavior or usage from the implementation of the kernel and L4Re, which are not always appropriate.
- The kernel is tightly coupled with the L4Re user land. This may be an advantage for other users, but it also leads to design decisions affecting the kernel interface that originate from the L4Re design and are worth a discussion for general application. For example, Norman proposed to reconsider the benefits behind sigma0 especially with regard to cache problems on ARM on the l4-hackers mailing list. But, the discussion was rather short and had no satisfying consent.
- Also, I always desired a more open development process and a predictable release cycle with some notes about important changes (and maybe some rationale behind them). Actually, we are sometimes surprised by modifications in SVN revision r(X) in comparison to r(X-1).
- The last (but not least) property of the kernel that kind of scares me is its raw complexity. It may be unfair to just count all sources, but that is the complexity a developer faces when looking for a bug. The overall 'sloccount' in the Fiasco src/ directory results in about 120 KLOC. A typical build for arm_v7 (Arndale) comprises 52 KLOC. The file list is retrieved from the dependency information of the object files. In comparison, a simple 'sloccount .' in the NOVA sources results in 9,606 LOC. I intentionally call these counts "raw complexity" as an educated Fiasco.OC may reduce the LOC running on target even further by configuration or a more accurate counting strategy.
Please do not take these bullets as a rant about the work of the L4Re developers. I really appreciate their work and I'm also proud of what we could achieve with Genode on top of Fiasco.OC.
Regards
Hi, Christian,
Thank you very much for these details!
At Sat, 26 Oct 2013 14:44:56 +0200, Christian Helmuth wrote:
On Thu, Oct 24, 2013 at 10:23:24PM +0200, Neal H. Walfield wrote:
In terms of Genode support, where does Fiasco.OC rank? Is the current focus on a custom kernel (which I guess is the bare hardware solution)?
First, the base-hw kernel is our first choice when exploring new grounds, e.g., porting to new ARM platforms or testing specific ARM features like TrustZone. For us, base-hw is the least complex Genode platform and we have a thorough understanding of its internals.
This sounds a bit different from the story that Martin told (cf. his message from October 24 with Message-ID: <5268F5E1.6000407@...1...>).
Is the intention that the base-hw remain experimental? Or, is the long-term plan to make it a proper microkernel? From what you say here, it sounds like I shouldn't consider base-hw as a potential microkernel. Martin, however, seems to suggest it will become a viable target in the near future.
Thanks,
:) Neal
Hi Neal,
thanks for tuning-in on the Genode mailing list! :-)
Is the intention that the base-hw remain experimental? Or, is the long-term plan to make it a proper microkernel? From what you say here, it sounds like I shouldn't consider base-hw as a potential microkernel. Martin, however, seems to suggest it will become a viable target in the near future.
Sure, base-hw is definitely planned to become a proper platform. But the word "kernel" does not really express well the role of base-hw. Let me explain:
Base-hw was born out of the observation that classical L4-based systems carry quite significant redundancies between the microkernel and roottask as both kernel and roottask have to keep track of how resources are assigned to processes. I.e., the kernel contains a mapping data base and page tables, but roottask also keeps records of how memory pages are used by user-level processes. The same story can be told of other kernel objects such as threads and protection domains.
The crux is that both kernel and roottask are mandatory parts of the trusted computing base. On typical L4-based systems, the code for those parts amounts to 20,000+ LOC (10+ KLOC kernel plus 10 KLOC roottask). This observation led us to the idea to merge both kernel and Genode's roottask (core) into one program. In this design, the "kernel" is not a self-sustaining piece of software but a mere library that provides back-end functionality for roottask. I.e., it performs no allocations and becomes active only when called by the roottask code (via one of the roottask-local system calls) or by IPC operations. All the dynamic (and complicated) stuff like memory management is handled by roottask code using Genode's user-level abstractions. The outcome of this experiment is that the combined program (base-hw core) comprises about 13,000 LOC, indicating that the approach is able to drastically reduce the mandatory parts of the trusted computing base.
As of now, we don't recommend the use of base-hw in serious settings because it is still in flux. That said, Genode hides the peculiarities of the particular kernels. Because hopping between kernels (such as base-hw and Fiasco.OC) is almost seamless, there is no need to pick a kernel upfront when starting the development of a Genode-based system. Just pick the most convenient kernel to start with. At the API level, Genode is capability-based. So developers using the API effectively develop components for a capability-based system. Once kernel-protected capabilities become available in base-hw, this change will be transparent to users of the API.
Regardless of the state of base-hw, if you desire a Genode base platform with kernel-protected capabilities today, you can use Fiasco.OC (ARM, x86) or NOVA (x86) right away.
Regards Norman
Hi, Norman,
Thank you for the information!
At Wed, 30 Oct 2013 18:10:07 +0100, Norman Feske wrote:
Base-hw was born out of the observation that classical L4-based systems carry quite significant redundancies between the microkernel and roottask as both kernel and roottask have to keep track of how resources are assigned to processes. I.e., the kernel contains a mapping data base and page tables, but roottask also keeps records of how memory pages are used by user-level processes. The same story can be told of other kernel objects such as threads and protection domains.
This is similar to my experience with Viengoos. I initially started designing Viengoos as an L4 root task. The double accounting was annoying, but the real killer for me was the tacit policy imposed by L4's API: L4's abstractions were getting in the way! In particular, because I wanted mappings to survive after a task's destruction, I had to route all mapping operations via the root task. This complicated the design of interfaces and effectively doubled the number of required IPCs for some tasks. It turned out that rewriting Viengoos to run on bare hardware was easier than working around the API mismatch and resulted in more elegant low-level interfaces.
In this design, the "kernel" is not a self-sustaining piece of software but a mere library that provides back-end functionality for roottask. I.e., it performs no allocations and becomes active only when called by the roottask code (via one of the roottask-local system calls) or by IPC operations. All the dynamic (and complicated) stuff like memory management is handled by roottask code using Genode's user-level abstractions.
Is the library running in kernel space and the "kernel" running in user space? Do they directly share data structures?
As of now, we don't recommend the use of base-hw in serious settings because it is still in flux. That said, Genode hides the peculiarities of the particular kernels. Because hopping between kernels (such as base-hw and Fiasco.OC) is almost seamless, there is no need to pick a kernel upfront when starting the development of a Genode-based system. Just pick the most convenient kernel to start with. At the API level, Genode is capability-based. So developers using the API effectively develop components for a capability-based system. Once kernel-protected capabilities become available in base-hw, this change will be transparent to users of the API.
Great!
Thanks,
:) Neal
Hi Neal,
On 05.11.2013 14:48, Neal H. Walfield wrote:
In this design, the "kernel" is not a self-sustaining piece of software but a mere library that provides back-end functionality for roottask. I.e., it performs no allocations and becomes active only when called by the roottask code (via one of the roottask-local system calls) or by IPC operations. All the dynamic (and complicated) stuff like memory management is handled by roottask code using Genode's user-level abstractions.
Is the library running in kernel space and the "kernel" running in user space? Do they directly share data structures?
The single "kernel"-thread executes solely in privileged CPU mode. Initially it disables the MMU and runs in physical address space. Before leaving privileged CPU mode the first time, it enables the MMU, using the address space of the root-task (core). Thus both, threads of the non-privileged root-task and the single "kernel" thread use the same virtual address space. For the purpose of simplification "kernel" thread and root-task threads also share data structures (e.g. raw page-tables or the interrupt-lookup table). This must be done carefully because "kernel" thread can always interrupt root-task threads and access shared objects without synchronization.
Martin
At Tue, 05 Nov 2013 15:15:49 +0100, Martin Stein wrote:
The single "kernel"-thread executes solely in privileged CPU mode. Initially it disables the MMU and runs in physical address space. Before leaving privileged CPU mode the first time, it enables the MMU, using the address space of the root-task (core). Thus both, threads of the non-privileged root-task and the single "kernel" thread use the same virtual address space. For the purpose of simplification "kernel" thread and root-task threads also share data structures (e.g. raw page-tables or the interrupt-lookup table). This must be done carefully because "kernel" thread can always interrupt root-task threads and access shared objects without synchronization.
If I understand correctly, you are basically implementing a fail fast mechanism for the root task.
Thus, the root task can, say, walk the page tables, but to modify the page tables or to switch protection domains, it traps to the kernel? Similarly, I'm guessing the kernel doesn't walk any of the root task's data structure (or, it does so very conservatively).
Thanks!
:) Neal
On 05.11.2013 15:59, Neal H. Walfield wrote:
At Tue, 05 Nov 2013 15:15:49 +0100, Martin Stein wrote:
The single "kernel"-thread executes solely in privileged CPU mode. Initially it disables the MMU and runs in physical address space. Before leaving privileged CPU mode the first time, it enables the MMU, using the address space of the root-task (core). Thus both, threads of the non-privileged root-task and the single "kernel" thread use the same virtual address space. For the purpose of simplification "kernel" thread and root-task threads also share data structures (e.g. raw page-tables or the interrupt-lookup table). This must be done carefully because "kernel" thread can always interrupt root-task threads and access shared objects without synchronization.
If I understand correctly, you are basically implementing a fail fast mechanism for the root task.
Thus, the root task can, say, walk the page tables, but to modify the page tables or to switch protection domains, it traps to the kernel? Similarly, I'm guessing the kernel doesn't walk any of the root task's data structure (or, it does so very conservatively).
By now the "kernel" thread creates the root-task page-table at start-up in a way, that it contains 1:1 mappings for all physical regions that are ever needed by root-task or kernel. Thus root-task threads and the kernel thread never throw page-faults and access resources in virtual space via their physical addresses. This way we keep things simple while benefit from several performance features the ARM MMU provides. As a result of this, root-task never touches its own page table. If root-task threads want to create further page tables they use a syscall. During this syscall, kernel initializes the page table with generic stuff. After that, application-specific control of the new page table is in the hands of the root-task threads.
Martin
Hi, Martin,
At Tue, 05 Nov 2013 16:27:30 +0100, Martin Stein wrote:
On 05.11.2013 15:59, Neal H. Walfield wrote:
At Tue, 05 Nov 2013 15:15:49 +0100, Martin Stein wrote:
The single "kernel"-thread executes solely in privileged CPU mode. Initially it disables the MMU and runs in physical address space. Before leaving privileged CPU mode the first time, it enables the MMU, using the address space of the root-task (core). Thus both, threads of the non-privileged root-task and the single "kernel" thread use the same virtual address space. For the purpose of simplification "kernel" thread and root-task threads also share data structures (e.g. raw page-tables or the interrupt-lookup table). This must be done carefully because "kernel" thread can always interrupt root-task threads and access shared objects without synchronization.
If I understand correctly, you are basically implementing a fail fast mechanism for the root task.
Thus, the root task can, say, walk the page tables, but to modify the page tables or to switch protection domains, it traps to the kernel? Similarly, I'm guessing the kernel doesn't walk any of the root task's data structure (or, it does so very conservatively).
By now the "kernel" thread creates the root-task page-table at start-up in a way, that it contains 1:1 mappings for all physical regions that are ever needed by root-task or kernel. Thus root-task threads and the kernel thread never throw page-faults and access resources in virtual space via their physical addresses. This way we keep things simple while benefit from several performance features the ARM MMU provides. As a result of this, root-task never touches its own page table. If root-task threads want to create further page tables they use a syscall. During this syscall, kernel initializes the page table with generic stuff. After that, application-specific control of the new page table is in the hands of the root-task threads.
Thanks for the details!
:) Neal
I forgot:
On 05.11.2013 15:59, Neal H. Walfield wrote:
At Tue, 05 Nov 2013 15:15:49 +0100, Martin Stein wrote:
The single "kernel"-thread executes solely in privileged CPU mode. Initially it disables the MMU and runs in physical address space. Before leaving privileged CPU mode the first time, it enables the MMU, using the address space of the root-task (core). Thus both, threads of the non-privileged root-task and the single "kernel" thread use the same virtual address space. For the purpose of simplification "kernel" thread and root-task threads also share data structures (e.g. raw page-tables or the interrupt-lookup table). This must be done carefully because "kernel" thread can always interrupt root-task threads and access shared objects without synchronization.
If I understand correctly, you are basically implementing a fail fast mechanism for the root task.
Thus, the root task can, say, walk the page tables, but to modify the page tables or to switch protection domains, it traps to the kernel? Similarly, I'm guessing the kernel doesn't walk any of the root task's data structure (or, it does so very conservatively).
Switching of address spaces is done when switching between privileged and non-privileged mode. When a thread is interrupted by privileged mode, root-task address-space gets applied before the kernel thread is called. As soon as kernel is done and switches back to non-privileged mode, the address space of the currently scheduled non-privileged context is applied. Only in case of a switch between root-task thread and kernel-thread, address space keeps the same.