|
|
Subscribe / Log in / New account

Capability Revocation and Indirection

Capability Revocation and Indirection

Posted Sep 24, 2025 22:49 UTC (Wed) by wahern (subscriber, #37304)
Parent article: CHERI with a Linux on top

While CHERI avoids indirection when using a capability/pointer, a consequence is that capability revocation (e.g. free(3)) requires sweeping the process address space to invalidate capabilities. In the simplest implementation it's stop-the-world during a linear word-by-word sweep of the address space. There have been several optimizations explored, including schemes to avoid reading memory unnecessarily by skipping words without the out-of-band capability tag bit, concurrent sweeping by leveraging page tables or memory coloring, etc. I think the latest upstreamed to CheriBSD is Cornucopia Reloaded[1]--during the pendency of a concurrent background sweep, a CoW-like scheme temporarily traps all reads to sweep specific pages on demand, permitting forward progress before the concurrent sweep completes.

CHERI is great for spatial safety, but the cost of avoiding indirection means temporal safety requires more work. Perhaps the next evolution will be exploring how linear or affine typing in application languages such as Rust could be leveraged to minimize the sweeping work, e.g. by automatically clearing capabilities as they're copied through the application from malloc through free. Or evolving allocation APIs and page table permission schemes so memory that doesn't need to store a capability/pointer can be skipped from sweeping entirely.

[1] https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/202...


to post comments

Capability Revocation and Indirection

Posted Sep 26, 2025 0:29 UTC (Fri) by cpatulea (subscriber, #87498) [Link] (1 responses)

> capability revocation (e.g. free(3)) requires sweeping the process address space to invalidate capabilities

Any chance you might have a deeper reference for this?

Capability Revocation and Indirection

Posted Sep 26, 2025 12:24 UTC (Fri) by wahern (subscriber, #37304) [Link]

The Cornucopia Reloaded paper I linked earlier has a decent summary and references. The most recent paper on the topic, also with a good summary and references, is A CHERI C Memory Model for Verified Temporal Safety, https://dl.acm.org/doi/pdf/10.1145/3703595.3705878. One of the earliest papers discussing revocation is the CHERIvoke paper, https://www.cl.cam.ac.uk/~tmj32/papers/docs/xia19-micro.pdf. Most CHERI-related papers are listed at https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/ch...

Also worthwhile to read the core papers on CHERI, especially papers about and subsequent to the ARM Morello implementation. Once you understand the basic architecture, in particular the hidden 129th bit that tags a word (i.e. C pointer) in memory as a valid capability and which is copied along with the visible 128-bit value (e.g. in `char *b = *a;`), it's easy to see understand the problem space regarding revocation. Most of the early work in CHERI was finding and verifying the minimum software and hardware requirements for guaranteed spatial safety that was also maximally performant in hardware and practical to incorporate into existing platforms (language standards, ABIs, kernels, etc). Temporal safety, especially performant revocation, didn't receive as much attention until later, after the shape of capability pointers (i.e. 129-bit compressed pointers) had already largely been settled. But it's still an active area of research and may yet result in some design changes or at least suggest additional hardware facilities for future implementations.

Capability Revocation and Indirection

Posted Sep 27, 2025 23:15 UTC (Sat) by NYKevin (subscriber, #129325) [Link]

I can imagine an alternative scheme, which looks roughly as follows:

1. Every "regular" capability is really a double indirection (a pointer-to-a-pointer) in disguise. I will use the term "outer pointer" to refer to the first layer of indirection (exposed to user code) and "inner pointer" to refer to the second layer (the pointee of the outer pointer).
2. When an allocation is created, we create an inner pointer for it. When an allocation is deallocated, we mark its inner pointer as invalid.
3. Inner pointers live in a special region of address space. When it fills up with dead pointers, you unmap the whole region, and map a fresh one somewhere else. The region is not allowed to contain any object other than an inner pointer (no "real" allocations).
4. A region that has ever been mapped for inner pointers during the lifetime of a process can never again be remapped to contain inner pointers (but it can be remapped for any other purpose, so this is not a pervasive restriction and should not break anything else). malloc or its equivalent would be responsible for the necessary bookkeeping, which might involve mapping regions at some fixed or regular pattern of offsets to reduce the amount of data that you need to track.
5. When an outer pointer is dereferenced by user code, you first check the validity of the outer pointer, then check that it points to a region currently mapped for inner pointers, and finally check the validity of the inner pointer.
6. In principle, you could run out of address space doing this, but that ought to take a rather long time if we're using 64-bit addresses. If we really insist on reusing inner pointer regions, one option could be to give each mapping and each outer pointer a generation number, but CHERI pointers are already wider than standard pointers, and I'm not sure this is worth it. Besides, then you're just running out of generation numbers instead.

I know that double indirection is significantly more expensive than single indirection... but sweeping address space not only seems like it should be similarly expensive, it gets slower the more memory we allocate (whereas double indirection is a fixed cost per dereference). How much memory do you have to allocate before you hit the break-even point?

The other obvious question is how much of this you can hardware-accelerate, and to what extent.

Capability Revocation and Indirection

Posted Oct 2, 2025 13:03 UTC (Thu) by Vorpal (guest, #136011) [Link] (2 responses)

> While CHERI avoids indirection when using a capability/pointer, a consequence is that capability revocation (e.g. free(3)) requires sweeping the process address space to invalidate capabilities.

Oof, that seems like a complete deal breaker to me. My main interests are in low latency hard realtime code, and that would completely kill any RT guarantees.

I don't see it scaling well to large workloads either. Imagine a database server with hundreds of GB of memory mapped into the process, no way that you want to sweep through all the pointers in that either. And even if you do it in the background concurrently, you will eat a lot of memory bandwidth, and you risk falling behind.

Which means we are left with a small niche: small systems with no RT guarantees.

> during the pendency of a concurrent background sweep, a CoW-like scheme temporarily traps all reads to sweep specific pages on demand, permitting forward progress before the concurrent sweep completes.

Isn't there a race condition in that: if you copy the capability around you may be able to copy it from a yet-to-be-swept page to an already swept page while the sweep is somewhere in between those pages? Or maybe I'm misunderstanding you.

Capability Revocation and Indirection

Posted Oct 2, 2025 17:19 UTC (Thu) by Wol (subscriber, #4433) [Link] (1 responses)

> I don't see it scaling well to large workloads either. Imagine a database server with hundreds of GB of memory mapped into the process, no way that you want to sweep through all the pointers in that either. And even if you do it in the background concurrently, you will eat a lot of memory bandwidth, and you risk falling behind.

Then you're using the wrong database server :-)

Cheers,
Wol

Capability Revocation and Indirection

Posted Oct 2, 2025 17:25 UTC (Thu) by jake (editor, #205) [Link]

> Then you're using the wrong database server :-)

Please do not continue down this path, Wol. You have been asked before. Your favorite hobby horse is off-topic on this article (and many, many others).

thanks,

jake


Copyright © 2025, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds