8000 Clarify the Usage and Mechanism of Guard Values and Bits in the Docs · Issue #1457 · seL4/seL4 · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Clarify the Usage and Mechanism of Guard Values and Bits in the Docs #1457

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
moritz-meier opened this issue May 13, 2025 · 1 comment
Open
Labels
docs Manual and other documentation

Comments

@moritz-meier
Copy link

We are currently experimenting with CSpaces, VSpace, TCBs, etc ... but have some problem with regards to addressing CNodes and Capabilities in a CSpace hierarchy. Especially Guard Values and Sizes are confusing and poorly documented.

It would be nice if the documentation could explain why they exist, how they should be used as well as how they work. Also why does the kernel assume GUARD_SIZE = WORD_SIZE - RADIX_SIZE for the roottask? In my understanding this would prevent the root task from addressing capabilities in nested CNodes?

This Thread hints that Guard Values were removed, but the current API and documentation still include them?

@Indanz
Copy link
Contributor
Indanz commented May 13, 2025

Welcome to one of the most tricky parts of using seL4, CSpace management!

Instead of repeating myself more, I'll link to a thread on the devel mailinglist which discusses some details and complexities.

Like the thread you linked to says, sizes are to support sparse multilevel CSpaces, so the kernel knows how many bits to resolve to find a slot to the next level CNode. If you didn't configure the size, the kernel would need to use the CNode size.

However, to me it is unclear why that would prevent supporting sparse multi-level CSpace, it would just mean that the indices for the top-level CNode are the top bits of the CPtr, so you can't have nice, low numbers anymore. E.g. seL4_CapInitThreadTCB is currently 1, but without explicit sizes it would be 1 << (WORD_SIZE - RADIX_SIZE).

The nice property of this would be that you don't need to know how many levels your CSpace will have beforehand, you just resolve bits from high to low until you reach a destination slot. The less nice property is that all your addressing changes when you resize a CNode. The definition of seL4_CapInitThreadTCB would depend on the KernelRootCNodeSizeBits kernel config option.

So to answer your question, people didn't want e.g. 0x10000000000000 as seL4_CapInitThreadTCB, they wanted a simple 1 instead. Guards and sizes give you control over how to address your CSpace.

Guard values aren't removed, so the thread is wrong there. Once you have sizes, you can as well have guard bits instead of hard-coding them to zero. They can be used to make CNode addressing more robust. Top level guards are a way to create namespaces, both to distinguish other integers from Cptrs and well as make them distinct from normal pointers. Intermediate guard bits can be used to partition the CSpace further.

For instance, the initial thread's CSpace has all very low numbers. If you give it a higher bits guard, it reduces the chance that random numbers are valid CPtrs. It makes it harder for bugs to mess up things (and hence harder to exploit the code too).

Imagine you have a 2-level CSpace where T in 0xTTTT0000 bits define the top level CNode's guard + slot index and L in 0x0000LLLL define the second level CNode bits. Say your cnode2 has starting address 0x12340000 and its last slot is at 0x123400ff, as it is 8 bits big. If you overflow the space size and try to address 0x12340100, you could accidentally address another cap by accident, if there is another CNode starting at 0x12340100. To guard against this, instead of padding the address with zeroes, you can give each sub-CNode it's own unique guard, e.g. 0xa0 for our cnode2, and 0xb1 for its sibling. Now if you overflow to 0x1234a100, you don't accidentally address the sibling's CNode any more.

In my understanding this would prevent the root task from addressing capabilities in nested CNodes?

Yes, and that's exactly the point: All the capabilities in the initial CNode need to be addressable, which means that they are reached after resolving WORD_SIZE bits. All syscalls take caps which are reached after fully resolving the CPtr, this is what the manual means when it says "Must be at a depth equivalent to the wordsize". See my link above how to change from a 1-level initial CSpace to a multilevel one, that's what that thread is about.

Only Cnode operating syscalls (CNode ops and retyping) can address such indirect slots, and they do it via the convoluted root + index + depth way.

Anyway, when starting, ignore guards and use zero for them. Once you have that working and understand how CSpace addressing practically works, you can add non-zero guards where you want.

Guards and sizes could be better documented. One thing that is currently unclear is that they are part of the CNode cap, not part of the CNode itself, so it's stored for each CNode reference and that's why it's part of a TCB's configuration, as it not only needs to know the CNode, but also how to address it.

@lsf37 lsf37 added the docs Manual and other documentation label Jun 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs Manual and other documentation
Projects
None yet
Development

No branches or pull requests

3 participants
0