Why do CNodes have guard bits?

Each CNode can be configured with a guard value of a particular size which must be matched int the path before any actual index bits within that CNode.

The manual suggests this is to ‘permit sparsity’, but as the structure is a prefix-tree anyway it is otherwise pretty sparse.

I haven’t seen any code that benefits from the existence of guard bits, but I’ve seen plenty that seems to pad out the addresses of CNode trees to a full word as a convention. This simply has the effect of preventing referencing anything of further depth than the tree is designed for directly.

What was the original motivation for using guards and does any such motivation still exist?

The addition of guards in the prefix-tree structure makes it substantially more complex to describe and think about, and I think many cases would benefit from a simpler API.

Thinking about this more, I think the guard bits allows you to have CNodes with a number of slots smaller than the word size, which is quite important. This is because all invocations look up from the TCB CNode and decode seL4_WordBits -guard bits.

So, I think guard bits need to stay. Guard values on the other hand I’m not so sure about.

I think Anna’s analysis is correct. The original motivation was to have a model that is close to the lookup used for general guarded page tables, which allows you to store very sparse tables fairly efficiently (There is a paper by Liedtke on this: [https://dl.acm.org/citation.cfm?id=504411] and a technical report that is available as PDF [http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.26.834&rep=rep1&type=pdf]). When it later became apparent that nobody is really using the mechanism and performance could be gained by removing the guard values, we did that. As Anna says, removing the guard completely would force you to always spend the full word width somehow, either by deeper lookup (more CNodes) or larger CNodes.

Does this mean that guard values have already been removed?

This behavior also seems to imply that, as with a VSpace, an executing thread has no access to the capabilities that make up its root capability tree (it has no inherent way of accessing them). Is my understanding correct here? Is this something that is explicitly desired?

@curtis correct. A cspace does not need to contain a reference to the root of that cspace. Threads using that cspace can still invoke caps, but they cannot change the layout of their cspace. System policy determines capability distribution.

In addition: yes, the ability to not have an inherent way of accessing one’s own CSpace is intended and important for constraining untrusted components.

1 Like