Hardware Coyotos variant?

34 views
Skip to first unread message

Jonathan S. Shapiro

unread,
Dec 1, 2025, 11:22:56 AMDec 1
to cap-talk
So.... this is a totally hair-brained thought, but I'm wondering if it's interesting.

One of the really painful limitations of the KeyKOS family is that you can't store capabilities to main memory. This means that capabilities cannot be passed on the application stack as parameters in any natural or practical way. This makes building libraries that manipulate capabilities really hard. EROS and later have capability pages mainly so that they can support a "split stack". Easier to work with than what KeyKOS was doing, but far from easy. Best I could do without changing the hardware.

I have finally started to look at the CHERI work from Cambridge. It starts with a 128 bit capability format and a side unit that adds a tag bit to every 8 byte region of memory.

CHERI chose to focus on fine-grain memory-oriented capabilities. I think this is because they were trying to continue to support large bodies of existing C code. I'm of the opinion that the result is fantastic, more expensive (in terms of porting cost) than anybody anticipated, and could be done in other ways by making different programming language choices. 

Some thoughts:
  • It is possible to use their tagged memory approach to allow KeyKOS-style capability structures to be stored in main memory in a KeyKOS-style system.
  • Parts of the kernel could be implemented in hardware - most critically the invocation path.
I'm not suggesting that we eliminate the kernel (though that's both possible and interesting), though there are paths we could accelerate given enough FPGA space. I'm suggesting that a strongly typed low-level programming language coupled with strong OS-capability isolation seems like an interesting path to explore.

Before you scoff about the programming language part (and you might be right):
  • I think that Rust's success is making people more open to the possibility that maybe we don't need to remain stuck in C.
  • The language might even be Rust - perhaps with SES-like extensions if needed.
  • Alternatively, the language might be a type-safe variant of C, again with SES-like extensions if needed.
I realize this is a crazy, hair-brained thought. But is it hair-brained enough to be interesting?


Jonathan

Matt Rice

unread,
Dec 1, 2025, 6:39:01 PMDec 1
to cap-...@googlegroups.com
I recall that Laurence Tratt has written a blog post about
difficulties of using rusts pointer
types with cheri because of the additional data and rusts assumption
that a pointer basically
just contains an address. (If I recall correctly from memory)

https://tratt.net/laurie/blog/2022/making_rust_a_better_fit_for_cheri_and_other_platforms.html

Jonathan S. Shapiro

unread,
Dec 1, 2025, 8:04:01 PMDec 1
to cap-...@googlegroups.com
On Mon, Dec 1, 2025 at 3:39 PM Matt Rice <rat...@gmail.com> wrote:

I recall that Laurence Tratt has written a blog post about
difficulties of using rusts pointer
types with cheri because of the additional data and rusts assumption
that a pointer basically
just contains an address. (If I recall correctly from memory)

https://tratt.net/laurie/blog/2022/making_rust_a_better_fit_for_cheri_and_other_platforms.html


I can see how that would be an issue, and thanks very much for that link.

But let's start with a different question: What added value does CHERI provide if we start from the assumption that the application code is required to be type safe and/or verified memory safe? I'm considering a variant in which capabilities reference OS objects, and do not replace conventional pointers.

Which may be completely stupid. It's just a brain fart at this point.


Jonathan

Matt Rice

unread,
Dec 1, 2025, 8:20:43 PMDec 1
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 1:04 AM Jonathan S. Shapiro
<jonathan....@gmail.com> wrote:
>
> On Mon, Dec 1, 2025 at 3:39 PM Matt Rice <rat...@gmail.com> wrote:
>>
>>
>> I recall that Laurence Tratt has written a blog post about
>> difficulties of using rusts pointer
>> types with cheri because of the additional data and rusts assumption
>> that a pointer basically
>> just contains an address. (If I recall correctly from memory)
>>
>> https://tratt.net/laurie/blog/2022/making_rust_a_better_fit_for_cheri_and_other_platforms.html
>>
>
> I can see how that would be an issue, and thanks very much for that link.
>
> But let's start with a different question: What added value does CHERI provide if we start from the assumption that the application code is required to be type safe and/or verified memory safe?

That is a great question, one I'm not familiar enough with CHERI to
actually have an answer for though.
I could imagine a world where the only value of running rust code on
CHERI (under the assumption of soundness) is just one wants to run
rust code on it... But I don't know if that is actually true, but if
there is additional value it has gone over my head.

>I'm considering a variant in which capabilities reference OS objects, and do not replace conventional pointers.

So kind of like a system call which is stored.

Matt Rice

unread,
Dec 1, 2025, 8:28:59 PMDec 1
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 1:20 AM Matt Rice <rat...@gmail.com> wrote:
>
> On Tue, Dec 2, 2025 at 1:04 AM Jonathan S. Shapiro
> <jonathan....@gmail.com> wrote:
> >
> > On Mon, Dec 1, 2025 at 3:39 PM Matt Rice <rat...@gmail.com> wrote:
> >>
> >>
> >> I recall that Laurence Tratt has written a blog post about
> >> difficulties of using rusts pointer
> >> types with cheri because of the additional data and rusts assumption
> >> that a pointer basically
> >> just contains an address. (If I recall correctly from memory)
> >>
> >> https://tratt.net/laurie/blog/2022/making_rust_a_better_fit_for_cheri_and_other_platforms.html
> >>
> >
> > I can see how that would be an issue, and thanks very much for that link.
> >
> > But let's start with a different question: What added value does CHERI provide if we start from the assumption that the application code is required to be type safe and/or verified memory safe?
>
> That is a great question, one I'm not familiar enough with CHERI to
> actually have an answer for though.
> I could imagine a world where the only value of running rust code on
> CHERI (under the assumption of soundness) is just one wants to run
> rust code on it... But I don't know if that is actually true, but if
> there is additional value it has gone over my head.
>

Actually, I am reminded of the language Mezzo, which is based upon
separation logic.
In it (in fact right in the description) "marrying a static discipline
of permissions and a dynamic mechanism of adoption and abandon."
https://protz.github.io/mezzo/

I would imagine the added value would be similar to this
static/dynamic divide, presumably you could have a dynamic
distribution of permissions with a static enforcement or some such.

I could maybe convince myself that adds value?

Matt Rice

unread,
Dec 1, 2025, 8:46:22 PMDec 1
to cap-...@googlegroups.com
Sorry, I really should make clear here that I was speaking not of
CHERI specifically here (Where I don't know.),
But of a more theoretical "what additional value could there be?".

William ML Leslie

unread,
Dec 1, 2025, 9:29:16 PMDec 1
to cap-...@googlegroups.com
On Tue, 2 Dec 2025 at 11:46, Matt Rice <rat...@gmail.com> wrote:
On Tue, Dec 2, 2025 at 1:28 AM Matt Rice <rat...@gmail.com> wrote:
>
> On Tue, Dec 2, 2025 at 1:20 AM Matt Rice <rat...@gmail.com> wrote:
> Actually, I am reminded of the language Mezzo, which is based upon
> separation logic.
> In it (in fact right in the description) "marrying a static discipline
> of permissions and a dynamic mechanism of adoption and abandon."
> https://protz.github.io/mezzo/
>
> I would imagine the added value would be similar to this
> static/dynamic divide, presumably you could have a dynamic
> distribution of permissions with a static enforcement or some such.
>
> I could maybe convince myself that adds value?

Sorry, I really should make clear here that I was speaking not of
CHERI specifically here (Where I don't know.),
But of a more theoretical "what additional value could there be?".

One source of additional value is, it does let you prevent random bit flips that could allow you to violate memory safety.

A better one is that if you're using Rust to wrap some existing C library - I had some jobs at one point where we we building Rust applications on PJSIP, if you need a concrete example - it's quite easy to ensure that all of your unsafe Rust is in fact safe, and then to have later refactorings violate some of those unwritten assumptions you'd made in the verification process.  Having an additional dynamic check for dealing with a sprawling FFI would be invaluable.
 
> > >I'm considering a variant in which capabilities reference OS objects, and do not replace conventional pointers.
> >
> > So kind of like a system call which is stored.

Think more like a pointer to a particular process, device driver, fault handler, x86 I/O port etc.

--
William ML Leslie

Kevin Reid

unread,
Dec 1, 2025, 9:38:22 PMDec 1
to cap-...@googlegroups.com
On Mon, Dec 1, 2025 at 5:20 PM Matt Rice <rat...@gmail.com> wrote:
I could imagine a world where the only value of running rust code on CHERI (under the assumption of soundness) is just one wants to run rust code on it... But I don't know if that is actually true, but if there is additional value it has gone over my head.

Speaking more of Rust than CHERI: almost no Rust program is made entirely of Rust safe code. You could say that “in this program, the only unsafe is in the standard library”, but that can sometimes (depending very much on the kind of problem being solved) come at a severe expressiveness or performance cost. Therefore, there is plenty of unsafe code which can benefit from the additional run-time checking CHERI provides — and we can assume that code to be well-motivated and well-written, yet not be absolutely certain that it is sound.

And in the other direction, since all CHERI provides is isolation, and not protection against e.g. data races and other forms of bug causing corruption of the state of reachable memory, there is still value in Rust’s strict ownership-and-mutability paradigm to help write code that is correct, not just unable to break the rest of the system.

Jonathan S. Shapiro

unread,
Dec 1, 2025, 11:13:50 PMDec 1
to cap-...@googlegroups.com
On Mon, Dec 1, 2025 at 5:46 PM Matt Rice <rat...@gmail.com> wrote:

Sorry, I really should make clear here that I was speaking not of
CHERI specifically here (Where I don't know.),
But of a more theoretical "what additional value could there be?".

Yeah. And to confess *my* ignorance I’m just catching up with CHERI simultaneous with some other things, so this is a little bit “the lame leading the blind”.

CHERI capabilities for memory have a base and bound and some permissions. Google “Cheri capability permissions”. I haven’t wrapped my head around the capability permissions yet - need to actually read their papers.

Strict PL type safety seems to handle all of the cases where the bound is statically known, and can be extended to [dynamic] vectors. There are advantages to hardware enforcement, but perhaps fewer than there were when segments were invented. Which is essentially what CHERI fat pointers are re-inventing. But there is more to CHERI than that. 

But I don’t mean to detract here. The difficult thing about understanding something like CHERI is that the descriptions tend to be bottom up, and you’re left to derive the transitive implications. I’m still working on that.


Jonathan

Matt Rice

unread,
Dec 2, 2025, 12:47:30 AMDec 2
to cap-...@googlegroups.com
On Mon, Dec 1, 2025 at 4:22 PM Jonathan S. Shapiro
<jonathan....@gmail.com> wrote:
>
> Before you scoff about the programming language part (and you might be right):
>
> I think that Rust's success is making people more open to the possibility that maybe we don't need to remain stuck in C.
> The language might even be Rust - perhaps with SES-like extensions if needed.
> Alternatively, the language might be a type-safe variant of C, again with SES-like extensions if needed.

One thing I think that throwing out C would make nicer is just the
main entry point,
and stringifying arguments through char pointers.

This at least always felt pretty unnatural when using c compilers
targeting a capability system.
You could really integrate a language and its module system together
with the executable format
by tossing out the notion of a singular main entry point.

These sorts of benefits that come from tossing out historical baggage
though may come at the expense of
running legacy code on the hardware and running the software on
current hardware. I think maybe you _could_ implement something of
the sort which could run on current day glibc as a position
independent executable with a custom PT_INTERP that somehow selects
between entry points.

That was the first thing that came to mind for benefits involving
tossing aside historical details anyways.

Jonathan S. Shapiro

unread,
Dec 2, 2025, 3:23:34 PMDec 2
to cap-...@googlegroups.com
On Mon, Dec 1, 2025 at 9:47 PM Matt Rice <rat...@gmail.com> wrote:
One thing I think that throwing out C would make nicer is just the
main entry point,
and stringifying arguments through char pointers.

I haven't done anything with Rust, so I'm curious how they handle this.

But more importantly, I think the entire notion of UNIX-style command line arguments may not turn out to be a great fit for Coyotos.

Context: because everything is capability-oriented, Coyotos is heavily biased toward "design to API" rather than "design to command line". For those applications that respond to a command line interface, the likely mechanism is that they start in main, do their initialization, and at some point return a capability (via the construction process) that publishes an interface suitable for command interaction. The native shell doesn't do fork+exec; it sends a set of strings to that published capability API.

I'm making this up, of course, because we haven't done it yet. But what I'm saying is that we want to think about this in capability terms.

One nice thing about this, just incidentally, is that the entire concept of init() procedures (which is a bodge) becomes completely unnecessary.

OK. So there's a design issue here. We're going to have a command line interface somewhere - it's too essential for dev use to avoid. What should the CapIDL spec be for applications launched from the command line?
 
You could really integrate a language and its module system together
with the executable format
by tossing out the notion of a singular main entry point.

I like the idea, but it's not immediately clear where one would publish these interfaces to, from which they could be invoked. I think the idea of "the new app returns a single initial capability" is still a good one. That capability can include protocol to fetch other capabilities; enabling a bootstrap-like process.

This kind of thing is why CapIDL has had interface inheritance from the beginning. In retrospect, I think that should have been mixins, but at the time it was an expedient way to get going quickly, and there are some minor challenges with mixins in a capability context. Nothing insurmountable; it was just that interface inheritance fit the kernel API requirements and I was in a hurry.
 
I think maybe you _could_ implement something of
the sort which could run on current day glibc as a position
independent executable with a custom PT_INTERP that somehow selects
between entry points.

You could. But we should be very cautious about adding complexity to the runtime. That stuff has a way of getting carved into stone by compatibility constraints.


Jonathan

John Carlson

unread,
Dec 2, 2025, 4:04:26 PMDec 2
to cap-...@googlegroups.com
If one is talking read capabilities, how about adding standard control (stdctl) to stdin, stdout, stderr?

John 

--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/cap-talk/CAAP%3D3QPFaNjdKCRmYMX5EBSYm4RVNL%2Bma27hFqhXQzvxfLuC7A%40mail.gmail.com.

Jonathan S. Shapiro

unread,
Dec 2, 2025, 4:15:00 PMDec 2
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 1:04 PM John Carlson <yott...@gmail.com> wrote:
If one is talking read capabilities, how about adding standard control (stdctl) to stdin, stdout, stderr?

Coyotos doesn't build on the stdin/stdout/stderr pattern; it's API-centric. Offhand I'm not sure what you have in mind by stdctl. Can you expand?

There is a place for I/O streams, and UNIX has gotten a lot of leverage out of using a very simple model. Much to be said for that. In an API-centric system design you wouldn't start with streams as your baseline. One of the reasons you want APIs is so that communication is typed and therefore validatable. Streams are effectively typeless; which strips away all of the advantages of comm validation between components.


Jonathan

John Carlson

unread,
Dec 2, 2025, 4:24:06 PMDec 2
to cap-...@googlegroups.com
Yes, my idea is a bit like streams, because there’s two inputs and two outputs, but instead of streams of bytes, think streams of capabilities.

Then think about complex capability local networks that could be created with two inputs and two outputs.

It’s just an idea I had some years ago.

I had a different idea in that one could stream capabilities (unforgeable URLs) to document capabilities in a CapWeb context.

John

--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

John Carlson

unread,
Dec 2, 2025, 4:35:06 PMDec 2
to cap-...@googlegroups.com
So capin, capout, caperr and capctl.

John 

John Carlson

unread,
Dec 2, 2025, 4:53:57 PMDec 2
to cap-...@googlegroups.com
So essentially, a stream of capabilities could just be a single capability, one just loses the streaming effect.

A single capability could be used to send or receive other capabilities to revive the streaming effect.

John

John Carlson

unread,
Dec 2, 2025, 5:15:14 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
A stream of capabilities on capctl would replace filenames on a typical UNIX-style command line, for example.

I’m not clear if Coyotos even has filenames, probably not!

John

Jonathan S. Shapiro

unread,
Dec 2, 2025, 5:16:23 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 1:24 PM John Carlson <yott...@gmail.com> wrote:
Yes, my idea is a bit like streams, because there’s two inputs and two outputs, but instead of streams of bytes, think streams of capabilities.

This deserves more consideration than I've given it, but I do have a broad thought that may provoke useful discussion.

I don't know what is true in other systems, but the patterns I have seen in the KeyKOS family tend to transfer capabilities around during setup rather than at runtime. Once two capabilities have been transferred to an object that obeys unknown code, you have to assume that the output from that object commingles their inputs. If you need isolation, you need to instantiate a new web of objects.

I may not be thinking about this right, or maybe I just haven't encountered the right use cases, but it strikes me that a stream of capabilities is almost axiomatically incompatible with isolation, even if the capabilities being transmitted are transitive-read-only. The only counter-example I can think of quickly is when you are building an application made up of components for debugging, or structural, or robustness reasons, but you aren't planning to treat these components as living in distinct protection domains. That is: they aren't intended to be isolated. There are use cases for that pattern, but it's an inherently risky pattern from a security perspective.


Jonathan

Jonathan S. Shapiro

unread,
Dec 2, 2025, 5:17:35 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 2:15 PM John Carlson <yott...@gmail.com> wrote:
I’m not clear if Coyotos even has filenames, probably not!

From the kernel perspective, it does not. But from a human perspective it is useful to organize things using names that humans can understand. The Directory object does this.


Jonathan 

John Carlson

unread,
Dec 2, 2025, 5:46:42 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
UNIX did this by only providing stdin, but then they created parameters/arguments which effectively created stdctl, and the ambient file system.

So yeah, I acknowledge that a single capability on “process” launch is a good idea.

So perhaps the initial capability is to a temporary Directory of capabilities.

Other functionality can be layered on top of this.

John 
On Tue, Dec 2, 2025 at 4:16 PM Jonathan S. Shapiro <jonathan....@gmail.com> wrote:c
--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

John Carlson

unread,
Dec 2, 2025, 5:54:26 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
And a Directory of capabilities is a c-list.

Jihn

John Carlson

unread,
Dec 2, 2025, 6:03:15 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
So we are discussing a c-list fixed set of capabilities, probably created before networking, and a stream of capabilities, more suited for a network environment, like POLA access to portions of a live video stream, or a dynamic list of channels you have access to on a chat server.

Good thoughts!

John

Kris Kowal

unread,
Dec 2, 2025, 6:09:53 PM (14 days ago) Dec 2
to cap-talk
Apropos of exactly and only this, I like to call a directory of capabilities a petstore.

John Carlson

unread,
Dec 2, 2025, 6:24:27 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
That sounds great.  I did have some conflict between object (no methods or functions) and array.   I come from the JSON mindset, where they are similar.

What do we call a stream of petnames?

John 

Jonathan S. Shapiro

unread,
Dec 2, 2025, 6:26:43 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 2:46 PM John Carlson <yott...@gmail.com> wrote:
So perhaps the initial capability is to a temporary Directory of capabilities.

There are much simpler solutions.

What problem are you trying to solve by returning multiple capability values?

John Carlson

unread,
Dec 2, 2025, 6:34:36 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
I had in mind different levels of membership for an influencer’s channel, probably a bit like multi-level security.  Broader memberships would allow larger and larger number of capabilities.   But memberships might also be distinct from each other.

But my idea sounds a bit like ambient authority, without any intention of being so.  Each member would receive an initial batch of capabilities, which could be extended with new content being available.

John 

--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

John Carlson

unread,
Dec 2, 2025, 6:48:56 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
So perhaps influencer software could have a list of petnames (membership levels)
which they could use to assign  media content to, and for a given petname, a member would receive new content that’s stored in the petname capability’s list or stream of capabilities.

I know this sounds a lot like RBAC.  Better ideas are welcome.

John 

Alan Karp

unread,
Dec 2, 2025, 7:05:40 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 2:54 PM John Carlson <yott...@gmail.com> wrote:
And a Directory of capabilities is a c-list.

I'm out of my depth here, but I'll comment anyway.

A c-list is conventionally the set of capabilities that you have.  I read "Directory of Capabilities" to be a place where you can find things you don't have capabilities for but can ask to get them.  That component was a key piece of HP's E-speak product.

--------------
Alan Karp


Alan Karp

unread,
Dec 2, 2025, 7:07:42 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 3:24 PM John Carlson <yott...@gmail.com> wrote:

What do we call a stream of petnames?

Why would you ever stream petnames?  They're only meaningful to you.

--------------
Alan Karp

John Carlson

unread,
Dec 2, 2025, 7:10:53 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
With another hat, I am considering which contacts I want to invite to meetings, such that I could create a revocable capability (bearer token) I could send them to access a meeting.

So in this case, the meeting object that the host has would have a petstore of people with capabilities they invited to a meeting.

So again, a growing set of capabilities.   Maybe not a stream though.

Let me think more of streaming capabilities for a potentially indefinite list of media content.  My initial thought on this was to provide different scenes or worlds streamed to a web browser or metaverse browser, “spatial services.”

John

Alan Karp

unread,
Dec 2, 2025, 7:14:57 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 3:34 PM John Carlson <yott...@gmail.com> wrote:
I had in mind different levels of membership for an influencer’s channel, probably a bit like multi-level security.  Broader memberships would allow larger and larger number of capabilities.   But memberships might also be distinct from each other.

But my idea sounds a bit like ambient authority, without any intention of being so.  Each member would receive an initial batch of capabilities, which could be extended with new content being available.

UCAN has the concept of a wildcard capability.  The idea is to grant permission to a set of objects that are not necessarily in a collection, e.g., all PDFs on a given machine, even those that don't exist yet.  That UCAN can't be used in an invocation because it doesn't designate a specific resource, but it can be used to delegate a UCAN for a specific resource.

--------------
Alan Karp

Alan Karp

unread,
Dec 2, 2025, 7:18:47 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 4:10 PM John Carlson <yott...@gmail.com> wrote:
With another hat, I am considering which contacts I want to invite to meetings, such that I could create a revocable capability (bearer token) I could send them to access a meeting.

That sounds similar to what we did for HP's Halo Conference rooms.  Instead of giving everyone the same meeting number, each invitee got a separate one.  That allowed us to both revoke access and track responsibility when someone had a delegate attend. 

--------------
Alan Karp

John Carlson

unread,
Dec 2, 2025, 7:39:40 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
Again, I don’t see much difference between a set and a directory, except a directory has readable keys.

So the keys in a set are hidden, but they are still there in the implementation, even with HashSet.  So both a set and a directory have keys (petnames, indices) and values (capabilities).  It’s the interface that’s different.

I will now switch to typical mathematical definitions to agree with everyone.

The domain of a set is capabilities.  The range of a set is set membership.  The domain of a directory is petnames.  The range of a directory is capabilities.

John 

John Carlson

unread,
Dec 2, 2025, 7:41:29 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
Excellent point, I’ll step back and say that I am streaming capabilities.

Apologies!   I get confused between resource name and petname.

--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

John Carlson

unread,
Dec 2, 2025, 8:02:03 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
I realize that TreeSet may not have indexes or keys, but they do have pointers/address/references which are ordered in hardware implementation.

Matt Rice

unread,
Dec 2, 2025, 8:24:08 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
On Tue, Dec 2, 2025 at 8:23 PM Jonathan S. Shapiro
<jonathan....@gmail.com> wrote:
>
> On Mon, Dec 1, 2025 at 9:47 PM Matt Rice <rat...@gmail.com> wrote:
>>
>> One thing I think that throwing out C would make nicer is just the
>> main entry point,
>> and stringifying arguments through char pointers.
>
>
> I haven't done anything with Rust, so I'm curious how they handle this.
>

Well, it kind of depends.
for a no_std or freestanding embedded kernel and what not
It essentially uses no_mangle extern "C" functions to define _start.

https://os.phil-opp.com/freestanding-rust-binary/

the gist of which is below (Note this isn't initializing stack etc,
it's just a minimal example):

```
#![no_std] // don't link the Rust standard library
#![no_main] // disable all Rust-level entry points

use core::panic::PanicInfo;

#[unsafe(no_mangle)] // don't mangle the name of this function
pub extern "C" fn _start() -> ! {
// this function is the entry point, since the linker looks for a function
// named `_start` by default
loop {}
}

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
```

When using the `std` it's pretty much the same as the C, it's just
plugged in the std panic handler and start function along with crt0.
Everything to do with command line args uses the normal C. There are
some serialization wrapper libraries that make command line arguments
more safe (clap, structopt) but these are just fancy ways of
converting structures and enums to stringified command line arguments.


> But more importantly, I think the entire notion of UNIX-style command line arguments may not turn out to be a great fit for Coyotos.
>
> Context: because everything is capability-oriented, Coyotos is heavily biased toward "design to API" rather than "design to command line". For those applications that respond to a command line interface, the likely mechanism is that they start in main, do their initialization, and at some point return a capability (via the construction process) that publishes an interface suitable for command interaction. The native shell doesn't do fork+exec; it sends a set of strings to that published capability API.
>

When I tried writing a shell for coyotos/capros I believe the way I
went (the details are fuzzy) was by sending the `allegedType` message
to the target, and having the shell parse the IDL for that type (I
don't remember if allegedType returned the IDL directly or if it just
returned a code that I then had to have the IDL for).
It then after parsing the IDl could hand out completions to the user,
and use their input to build a message sent to the target.


> I'm making this up, of course, because we haven't done it yet. But what I'm saying is that we want to think about this in capability terms.
>
> One nice thing about this, just incidentally, is that the entire concept of init() procedures (which is a bodge) becomes completely unnecessary.
>
> OK. So there's a design issue here. We're going to have a command line interface somewhere - it's too essential for dev use to avoid. What should the CapIDL spec be for applications launched from the command line?
>
>>
>> You could really integrate a language and its module system together
>> with the executable format
>> by tossing out the notion of a singular main entry point.
>
>
> I like the idea, but it's not immediately clear where one would publish these interfaces to, from which they could be invoked. I think the idea of "the new app returns a single initial capability" is still a good one. That capability can include protocol to fetch other capabilities; enabling a bootstrap-like process.

Fair enough, the idea was more "This is the kind of thing that *could*
be done by unshackling from c", than
"this is a thing that should be done". Indeed my feeling was it'd be
something like binary introspection/symbol searching.
like _start_foo, _start_bar, and perhaps a _start_default. A loader
is then optionally given a "foo", "bar", and falls back to "default"
if none is provided.

> This kind of thing is why CapIDL has had interface inheritance from the beginning. In retrospect, I think that should have been mixins, but at the time it was an expedient way to get going quickly, and there are some minor challenges with mixins in a capability context. Nothing insurmountable; it was just that interface inheritance fit the kernel API requirements and I was in a hurry.
>

I suppose that works, I probably prefer multiple entry points for a
bad reason that I hate naming things, and I'd have to name an extra
interface :D. But I *think* that really what I was hoping for here
more than that was to signal a tighter integration between whatever
languages header file, and the CapIDL such that the two are actually
the same.

From what I remember of the code generation from the IDL main gets in
the way of that.

>> I think maybe you _could_ implement something of
>> the sort which could run on current day glibc as a position
>> independent executable with a custom PT_INTERP that somehow selects
>> between entry points.
>
>
> You could. But we should be very cautious about adding complexity to the runtime. That stuff has a way of getting carved into stone by compatibility constraints.
>


absolutely

Alan Karp

unread,
Dec 2, 2025, 8:28:42 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
I think you missed my point.  Your c-list is the set of permissions you have.  We identified a need for a place to learn about resources you don't already have permission to use.  That's what I mean by a directory.

--------------
Alan Karp


William ML Leslie

unread,
Dec 2, 2025, 9:19:18 PM (14 days ago) Dec 2
to cap-...@googlegroups.com
On Wed, 3 Dec 2025 at 11:24, Matt Rice <rat...@gmail.com> wrote:
On Tue, Dec 2, 2025 at 8:23 PM Jonathan S. Shapiro
<jonathan....@gmail.com> wrote:
>
> On Mon, Dec 1, 2025 at 9:47 PM Matt Rice <rat...@gmail.com> wrote:
> But more importantly, I think the entire notion of UNIX-style command line arguments may not turn out to be a great fit for Coyotos.
>
> Context: because everything is capability-oriented, Coyotos is heavily biased toward "design to API" rather than "design to command line". For those applications that respond to a command line interface, the likely mechanism is that they start in main, do their initialization, and at some point return a capability (via the construction process) that publishes an interface suitable for command interaction. The native shell doesn't do fork+exec; it sends a set of strings to that published capability API.
>

When I tried writing a shell for coyotos/capros I believe the way I
went (the details are fuzzy) was by sending the `allegedType` message
to the target, and having the shell parse the IDL for that type (I
don't remember if allegedType returned the IDL directly or if it just
returned a code that I then had to have the IDL for).
 It then after parsing the IDl could hand out completions to the user,
and use their input to build a message sent to the target.

The other approach is to attach a tag that indicates the expected type to the petname and pass these around everywhere in your shell.  I like the idea of using this sort of tagging to discriminate not just type, but also provenance, for example, a-la Yee's Security Tartan.  There are still cases where you need to ask the object about itself (e.g. distinguishing files vs directories in a legacy filesystem).
 
--
William ML Leslie

Ben Laurie

unread,
Dec 3, 2025, 10:18:29 AM (13 days ago) Dec 3
to cap-...@googlegroups.com


On Mon, 1 Dec 2025 at 16:22, Jonathan S. Shapiro <jonathan....@gmail.com> wrote:
So.... this is a totally hair-brained thought, but I'm wondering if it's interesting.

One of the really painful limitations of the KeyKOS family is that you can't store capabilities to main memory. This means that capabilities cannot be passed on the application stack as parameters in any natural or practical way. This makes building libraries that manipulate capabilities really hard. EROS and later have capability pages mainly so that they can support a "split stack". Easier to work with than what KeyKOS was doing, but far from easy. Best I could do without changing the hardware.

I have finally started to look at the CHERI work from Cambridge. It starts with a 128 bit capability format and a side unit that adds a tag bit to every 8 byte region of memory.

CHERI chose to focus on fine-grain memory-oriented capabilities. I think this is because they were trying to continue to support large bodies of existing C code. I'm of the opinion that the result is fantastic, more expensive (in terms of porting cost) than anybody anticipated, and could be done in other ways by making different programming language choices. 

Speaking as one of the first members of the project: the original motivation was actually to reduce the enormous cost of compartmentalisation. Which CHERI turns out to do very well. C/C++ memory safety was an unintended but very welcome side effect of the underlying mechanism.

In terms of cost of porting: I am not sure where you got that impression., CHERI porting is mostly *very* cheap - .03% of lines of code change and most of those are changing int/void * to the correct type (intptr_t) and the need to do that is clearly signalled by compile-time errors.

A few types of things are significantly harder:

1. Operating systems.

2. VMs (by which I mean Java/Javescript VMs) - mostly because of JITs.

3. Things that use compressed memory pointers.

V8 just happens to be both 2 and 3, so is incredibly painful.

But I ported OpenCV (10M lines of code) in 3 days. And then found security bugs by running the self tests.

There is more ported C/C++ than all the open source Rust in existence. And obviously that has been done by far fewer people.


Some thoughts:
  • It is possible to use their tagged memory approach to allow KeyKOS-style capability structures to be stored in main memory in a KeyKOS-style system.

Indeed it is.
 
  • Parts of the kernel could be implemented in hardware - most critically the invocation path.

Look at CHERIoT to understand why CHERI as it stands is already a fantastic boon for OSes.
 
I'm not suggesting that we eliminate the kernel (though that's both possible and interesting), though there are paths we could accelerate given enough FPGA space. I'm suggesting that a strongly typed low-level programming language coupled with strong OS-capability isolation seems like an interesting path to explore.

Before you scoff about the programming language part (and you might be right):
  • I think that Rust's success is making people more open to the possibility that maybe we don't need to remain stuck in C.
  • The language might even be Rust - perhaps with SES-like extensions if needed.
  • Alternatively, the language might be a type-safe variant of C, again with SES-like extensions if needed.
I realize this is a crazy, hair-brained thought. But is it hair-brained enough to be interesting?

If you want to go down the language path, I think it is also a good idea to build an understanding of the memory lifecycle into it - see CheriOS for some inspiration.

Rust,. IMO, is too constrained to impedance match CHERI well. 



Jonathan

--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

John Carlson

unread,
Dec 3, 2025, 10:55:25 AM (13 days ago) Dec 3
to cap-...@googlegroups.com
First off, I get that capabilities are things like small integers that are passed to operations.  I realize that there’s some where in the kernel or process where these numbers are mapped on a per process basis to a binding between a list of operations and a resource.  The implementation of capabilities is a c-list to resource+operations (object or permissions) mapping (IOW, a directory).  Also, it’s my understanding that webkeys are capabilities.

I also know next to nothing about how capabilities are implemented in hardware or kernel.

Alan’s comment is fair, my definition of directory stems from a list of names mapped to numbers, much like DNS does.   Today, it’s called a contacts app or petstore.  We can add contacts to our contacts app.  Having a contact doesn’t imply we can contact them via voice, we might only have email permission.

In general, both sets and directories are mathematical functions, potentially functions that produce more than one value, and even functions that can change over time.   Functions are also a relationship or mapping between a domain of concepts and a range of concepts, not just numbers.  I can have a function which maps functions to functions, for example.  But a capability being just operations without a resource might be weird.

When you get into implementing sets and directories on a computer, you might see the similarity clearer.  Every piece of memory or long term storage has location address and a value on a Von Neumann computer.  An address is limited to an address space.  When we get to non-Von Neumann computers, perhaps this will change.  For example, memory might be distributed inside ALUs, but I’m not even sure that sets and directories make sense in that context?  I’ll have to think some more, like can a liquid be stored in a set or directory.  

Certainly, milk and orange juice filled containers are resources+operations (drink from, pour from, fill etc.) stored in a refrigerator.  The containers are conventionally typed, so you don’t mix contents.  They don’t need names, but you know where the directory (your refrigerator) is to find your resources, or other directories, like your counter or table if you took the liquids out of the refrigerator.

A c-list might be the permissions presently in your hands, like a set of keys.  So the distinction between whether something is a c-list and a directory, might be whether it’s registers, main memory, long-term storage, or across a network.  One does have a limited number of registers, if one puts c-lists there.

If my object is a stream of capabilities, then certainly there can be a capability that allows me to access the object and use operations on it to store and retrieve capabilities.  It seems like there’s a restriction that capabilities should be in a pre allocated array before a process starts, and I don’t really have an issue with that.  I just don’t want every process I create to have the same size c-list.

I think your argument is that c-lists don’t exist in storage, but I’d like to hear about the actual implementation of that.  Maybe a c-list is how user and kernel space communicate?

Back to the liquid metaphor, I can have an unending list of milk carton or orange juice containers in a factory, but are these capabilities?   Surely, a machine has permissions to fill the container?  But you don’t want to give the orange juice filler permissions to fill milk bottles; you don’t want to delegate to another type of filler.

I’m very interested in temporal sets and temporal graphs, if someone wants to discuss these further.  Whether such things should be discussed on cap-talk, IDK!

I do have some experience upping the number of network file descriptors to unlimited to simulate 250000 wireless lights sending UDP messages to a server, so I kind of know what I’m talking about at an application point of view.  I do realize they all go to same port in the server.  I only had 2 clients to simulate load from.  I realize this is different than receiving capabilities.   I just think that the number of capabilities in a system may be potentially unbounded, and the system can still chug away as capabilities are opened and closed.

So yes, with thousands of threads on a client machine, one can have a dynamic number of capabilities, but probably fixed at 65536 for UDP.  I needed 4 machines.

John

Matt Rice

unread,
Dec 3, 2025, 8:32:23 PM (13 days ago) Dec 3
to cap-...@googlegroups.com
On Wed, Dec 3, 2025 at 12:05 AM Alan Karp <alan...@gmail.com> wrote:
>
> On Tue, Dec 2, 2025 at 2:54 PM John Carlson <yott...@gmail.com> wrote:
>>
>> And a Directory of capabilities is a c-list.
>
>
> I'm out of my depth here, but I'll comment anyway.
>
> A c-list is conventionally the set of capabilities that you have. I read "Directory of Capabilities" to be a place where you can find things you don't have capabilities for but can ask to get them. That component was a key piece of HP's E-speak product.
>

From what I recall on coyotos, eros, and capros the directory object was
a fixed size array with a name and capability buffer. Where the
longer the name strings were the less capabilities it could hold. e.g.
it's like a sequence of [([char; ...], cap), ...]

These were closely held and generally not passed around, in favor of
passing around capabilities to others.
They were used for organizing one's own capabilities and giving them
human meaningful names.
Sharing them is bad (contra kindergarten).

William ML Leslie

unread,
Dec 3, 2025, 8:41:09 PM (13 days ago) Dec 3
to cap-...@googlegroups.com

You'll notice there's no explicit bound on size, but you could set bounds on the spacebank if you like.

It's not really necessary to pass directories to programs for the most part, you would normally design the external API of a program to accept the capabilities it needs.  But there's nothing preventing you from passing a directory to e.g. your shell.

--
William ML Leslie

Matt Rice

unread,
Dec 3, 2025, 10:51:34 PM (13 days ago) Dec 3
to cap-...@googlegroups.com
Totally true, The key thing you want to *avoid* is using a "shared
directory" in a way that mimics a filesystem and subsequently
reintroduces all of the confused deputy problems associated with using
a filesystem. It does not need to be an os provided global file system
for those problems to appear. But I kind of digress from the thread
this subject has been covered on the list before.

Jonathan S. Shapiro

unread,
Dec 4, 2025, 12:49:38 AM (13 days ago) Dec 4
to cap-...@googlegroups.com
On Wed, Dec 3, 2025 at 7:18 AM 'Ben Laurie' via cap-talk <cap-...@googlegroups.com> wrote:
Speaking as one of the first members of the project: the original motivation was actually to reduce the enormous cost of compartmentalisation. Which CHERI turns out to do very well. C/C++ memory safety was an unintended but very welcome side effect of the underlying mechanism.

x86/amd64 is a big impediment to compartmentalization. On other architectures Jochen and I and others got the cycle counts fairly far down, but there are greater parallelization opportunities in hardware.
 
In terms of cost of porting: I am not sure where you got that impression., CHERI porting is mostly *very* cheap - .03% of lines of code change and most of those are changing int/void * to the correct type (intptr_t) and the need to do that is clearly signalled by compile-time errors.

Probably pulled it from some combination of my a*s and a vague recollection of a random statement someone made that I happened across.

A few types of things are significantly harder:

I would have expected everything on that list. They share in common a bunch of low-level memory abuses. I'm a little surprised that garbage collectors aren't on that list as well.

  • It is possible to use their tagged memory approach to allow KeyKOS-style capability structures to be stored in main memory in a KeyKOS-style system.
Indeed it is.

Very helpful to have that confirmed.
 
  • Parts of the kernel could be implemented in hardware - most critically the invocation path.
Look at CHERIoT to understand why CHERI as it stands is already a fantastic boon for OSes.

I've been actively trying to figure out which FPGA board to buy. Definitely not the existing Sonata or the Arty A7. Unfortunate, to my mind, that the Sonata XL (apparently) wasn't commercialized, but a board with an A7200T part (or comparable) would be enough to let me play around with stray thoughts. Any recommendations?
 
If you want to go down the language path, I think it is also a good idea to build an understanding of the memory lifecycle into it - see CheriOS for some inspiration.

Concur.
 
Rust,. IMO, is too constrained to impedance match CHERI well.

To my mind, that's completely believable. And one of the things we learned from Cyclone is that simple region inference isn't good enough either. But I think we're in a much different position today socially than we were 15 years ago in terms of perceived requirements:
  • Whole program compilation is now acceptable (c.f. go), which changes what we can analyze in a major way.
  • The burst of alternative systems languages says there's a window of acceptance for innovation that didn't exist in 2010 (or earlier).
  • People are now willing to tolerate a surprising amount of pain (c.f. borrow checker) for robust results - especially for the sake of concurrency.
All I'm saying is that I think there may be a window of opportunity at the moment, and the final winner isn't at all clear.


Jonathan

Jonathan S. Shapiro

unread,
Dec 4, 2025, 2:05:14 AM (13 days ago) Dec 4
to cap-...@googlegroups.com
On Wed, Dec 3, 2025 at 7:55 AM John Carlson <yott...@gmail.com> wrote:
First off, I get that capabilities are things like small integers that are passed to operations.

Since that's not correct, I'd like to pause you right there for a moment.

Let me preface this by saying that cryptographic capabilities are very different from descriptor-style capabilities. In cryptographic capabilities they are indeed integers, though I'd be hard pressed to describe them as small. Passing them around is fine until you get to some operation that actually uses them. At that point you actually have to check signatures or encryption, which is pretty time consuming.

In descriptor-style systems the small numbers are indices into a system-protected array (or other storage structure) that holds the actual capabilities. What you are passing around is a capability reference, not a capability. In EROS that structure was a constant-length c-list: the capability register set. In UNIX the per-process descriptor table is a bounded-length dynamic c-list.

The implementation of capabilities is a c-list to resource+operations (object or permissions) mapping.

Yes. But a c-list is not what we mean here when we're talking about directories. A c-list is typically a mapping from non-negative integer indices to capabilities. The capabilities in turn designate a resource and a further map from non-negative integers to operations. The first non-negative integer is for looking up the capability in the c-list. The second non-negative integer is for identifying the operation that you are attempting to perform by invoking the capability.

If you are comfortable with PL theory, another way to think about a capability is that it is a signature of closures over a common resource.

In the KeyKOS family, each process has a c-list of sorts: the capability register set. That proves in some cases to be limiting, so EROS introduced capability pages, which are also a c-list. The capability reference argument presented to the kernel at invocation time is either a register number or an address that either (a) resolves to a capability page entry, or (b) is malformed and generates a fault.
 
I also know next to nothing about how capabilities are implemented in hardware or kernel.

Here's one way:

 
BTW that's not a stable URL - the coyotos repo will be moving to GitHub shortly.
 
Alan’s comment is fair, my definition of directory stems from a list of names mapped to numbers, much like DNS does.

In typical capability systems, a directory is a mapping from names to capabilities rather than numbers. The reason this distinction matters is that capabilities are (by definition) protected from certain kinds of tampering in ways that mere numbers are not.

If my object is a stream of capabilities...

Do you perhaps mean "If I implement an object having an interface that delivers a stream of capabilities"?
 
It seems like there’s a restriction that capabilities should be in a pre allocated array before a process starts, and I don’t really have an issue with that.  I just don’t want every process I create to have the same size c-list.

So first, there is no such restriction. For the vast majority of objects, a fixed-size c-list is actually sufficient. In EROS and Coyotos, applications that need more than 32 capability registers are very rare. But if more are needed, it's possible to fabricate a dynamically growing capability memory region, add it to the application's address space by mapping it, and off you go.

For performance reasons, it's very helpful if the baseline per-process c-list has a fixed size. Dynamically sized things carry a larger cost at the CPU execution level. That doesn't stop you from building a dynamic c-list in the form of a memory region. It merely provides a useful baseline starting point that works well for the overwhelming majority of components.

I think your argument is that c-lists don’t exist in storage, but I’d like to hear about the actual implementation of that.

I'm not sure who "you" is here, so if I'm responding out of turn please forgive my confusion.

In EROS and Coyotos, the capability registers are most definitely written to durable storage on a regular basis, as are all other system objects. This isn't really because they are capability-based. It is rather because they are orthogonally persistent systems.

On the IBM AS/400 this process is much more complex and managed manually - and incidentally with lower performance. Sometimes you find a technical choice that works really well if you go "all in" but not nearly as well if you try to go halfway. Orthogonal persistence seems to be an example of this:


 
I do have some experience upping the number of network file descriptors to unlimited to simulate 250000 wireless lights sending UDP messages to a server...

I can see why you would want 250,000 nameable things in that scenario. I'm not at all clear that 250,000 descriptors would be the most natural way to achieve that - especially if they transit a network.


Jonathan

Jonathan S. Shapiro

unread,
Dec 4, 2025, 2:10:02 AM (13 days ago) Dec 4
to cap-...@googlegroups.com
On Wed, Dec 3, 2025 at 5:32 PM Matt Rice <rat...@gmail.com> wrote:
From what I recall on coyotos, eros, and capros the directory object was
a fixed size array with a name and capability buffer.

Not fixed size, but otherwise close enough. KeyKOS directories were actually mappings from indices to capabilities. But there is also a filesystem-style directory object that is a mapping from strings to capabilities.

Unfortunately neither of these is present in the BitBucket coyotos tree.


Jonathan

John Carlson

unread,
Dec 4, 2025, 3:28:54 AM (13 days ago) Dec 4
to cap-...@googlegroups.com
I do have some experience upping the number of network file descriptors to unlimited to simulate 250000 wireless lights sending UDP messages to a server...

I can see why you would want 250,000 nameable things in that scenario. I'm not at all clear that 250,000 descriptors would be the most natural way to achieve that - especially if they transit a network.


And I've forgotten if UDP sockets actually consumes a file descriptor, I recall I was running out of them.  I could have used the UDP port over again, but that wasn't how JMeter worked, as I recall.  I'm not saying that JMeter couldn't have done it right, it's just what I was given.  If we want to simulate a bunch of lights sending data via UDP though, unique ports in a simulation (with same IP address) can simulate different IP addresses with the same UDP port (well, kind of).

John 

John Carlson

unread,
Dec 4, 2025, 3:32:59 AM (13 days ago) Dec 4
to cap-...@googlegroups.com
I recall we were also generating unique identifiers between 2 client machines.  I'm not clear on what the mechanism was, but I can't imagine that taking a lot of descriptors. 

Alan Karp

unread,
Dec 4, 2025, 11:14:52 AM (12 days ago) Dec 4
to cap-...@googlegroups.com
On Wed, Dec 3, 2025 at 9:49 PM Jonathan S. Shapiro <jonathan....@gmail.com> wrote:
  • People are now willing to tolerate a surprising amount of pain (c.f. borrow checker) for robust results - especially for the sake of concurrency.
Pain is what I felt when I started programming in Rust, but as I gained experience I realized that the borrow checker was my friend, stopping me from doing some really stupid #@%&.  Instead of fighting the borrow checker, I started having conversations with it.  In the few cases where it was overly conservative, throwing in a .clone() or two got me going again.

--------------
Alan Karp

Ben Laurie

unread,
Dec 4, 2025, 11:26:24 AM (12 days ago) Dec 4
to cap-...@googlegroups.com
On Thu, 4 Dec 2025 at 05:49, Jonathan S. Shapiro <jonathan....@gmail.com> wrote:
On Wed, Dec 3, 2025 at 7:18 AM 'Ben Laurie' via cap-talk <cap-...@googlegroups.com> wrote:
Speaking as one of the first members of the project: the original motivation was actually to reduce the enormous cost of compartmentalisation. Which CHERI turns out to do very well. C/C++ memory safety was an unintended but very welcome side effect of the underlying mechanism.

x86/amd64 is a big impediment to compartmentalization. On other architectures Jochen and I and others got the cycle counts fairly far down, but there are greater parallelization opportunities in hardware.

In CHERI switches between compartments are literally just a register bank switch. It's hard to get any faster than that.
 
In terms of cost of porting: I am not sure where you got that impression., CHERI porting is mostly *very* cheap - .03% of lines of code change and most of those are changing int/void * to the correct type (intptr_t) and the need to do that is clearly signalled by compile-time errors.

Probably pulled it from some combination of my a*s and a vague recollection of a random statement someone made that I happened across.

A few types of things are significantly harder:

I would have expected everything on that list. They share in common a bunch of low-level memory abuses. I'm a little surprised that garbage collectors aren't on that list as well.

CHERI makes all garbage collection precise which tends to be helpful, but I'm sure I should have included memory allocators in general. :-)
 

  • It is possible to use their tagged memory approach to allow KeyKOS-style capability structures to be stored in main memory in a KeyKOS-style system.
Indeed it is.

Very helpful to have that confirmed.

Sealed capabilities are the basic mechanism you need.
 
 
  • Parts of the kernel could be implemented in hardware - most critically the invocation path.
Look at CHERIoT to understand why CHERI as it stands is already a fantastic boon for OSes.

I've been actively trying to figure out which FPGA board to buy. Definitely not the existing Sonata or the Arty A7. Unfortunate, to my mind, that the Sonata XL (apparently) wasn't commercialized, but a board with an A7200T part (or comparable) would be enough to let me play around with stray thoughts. Any recommendations?
 
If you want to go down the language path, I think it is also a good idea to build an understanding of the memory lifecycle into it - see CheriOS for some inspiration.

Concur.
 
Rust,. IMO, is too constrained to impedance match CHERI well.

To my mind, that's completely believable. And one of the things we learned from Cyclone is that simple region inference isn't good enough either. But I think we're in a much different position today socially than we were 15 years ago in terms of perceived requirements:
  • Whole program compilation is now acceptable (c.f. go), which changes what we can analyze in a major way.
  • The burst of alternative systems languages says there's a window of acceptance for innovation that didn't exist in 2010 (or earlier).
  • People are now willing to tolerate a surprising amount of pain (c.f. borrow checker) for robust results - especially for the sake of concurrency.
All I'm saying is that I think there may be a window of opportunity at the moment, and the final winner isn't at all clear.

Well, a CHERI-Rust port is in hand. Rust Strict Provenance was actually designed, pretty much, for CHERI.
 


Jonathan

--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

Matt Rice

unread,
Dec 4, 2025, 11:22:28 PM (12 days ago) Dec 4
to cap-...@googlegroups.com
On Thu, Dec 4, 2025 at 7:05 AM Jonathan S. Shapiro
<jonathan....@gmail.com> wrote:
>
> In EROS and Coyotos, the capability registers are most definitely written to durable storage on a regular basis, as are all other system objects. This isn't really because they are capability-based. It is rather because they are orthogonally persistent systems.
>
> On the IBM AS/400 this process is much more complex and managed manually - and incidentally with lower performance. Sometimes you find a technical choice that works really well if you go "all in" but not nearly as well if you try to go halfway. Orthogonal persistence seems to be an example of this:
>
> http://usenix.org/publications/library/proceedings/usenix02/full_papers/shapiro/shapiro.pdf
>

I somewhat hesitate to ask, but in the hardware variant is there a
plan for how transparent
the persistence layer is going to be? I would somewhat assume it
would keep the MMU/paging system
like design at the hardware level (i.e. not transparent). In your
original email you wrote "I'm not suggesting that we eliminate the
kernel (though that's both possible and interesting)" I kind of assume
that for driver separation alone
the persistence mechanism would not be transparent to the kernel.

Part of the reason I ask is I've always wanted to explore ways to keep
orthogonal persistence while making it less transparent at least for
some applications. Either through allowing processes to read the
status of dirty bits.
Or some kind of atomic commit phase, and capability which sends a
message when a checkpoint is reached.
This latter thing is made more difficult due to the lack of signals
but I digress.

The main point is that if you intend to make the persistence entirely
hardware and totally transparent, there are
probably some applications where that is desirable. But tinkering with
the persistence layer isn't one of those.

Jonathan S. Shapiro

unread,
Dec 5, 2025, 3:28:36 PM (11 days ago) Dec 5
to cap-...@googlegroups.com
On Thu, Dec 4, 2025 at 8:22 PM Matt Rice <rat...@gmail.com> wrote:
I somewhat hesitate to ask, but in the hardware variant is there a
plan for how transparent
the persistence layer is going to be?

The consistent evidence over the last 40 years is that the practical choices are either full orthogonal persistence or full manual persistence. To my knowledge, nobody has come up with a good way to implement durable process authority protection if a manual approach is used.
 
I would somewhat assume it
would keep the MMU/paging system
like design at the hardware level (i.e. not transparent).

I haven't yet caught up on CHERI enough to answer that, but persisting the mapping structures isn't usually the hard part. In Coyotos there is a design challenge in mapping between GPTs and the native translation mechanism, but I don't know enough yet to know if that's even necessary with CHERI.

The other piece of what I meant is that not everything has to be implemented in hardware. If we can expedite the invocation path and the translation path that's great, but it's not necessary. CHERI has some context switching support that would be nice to use .
 
Part of the reason I ask is I've always wanted to explore ways to keep
orthogonal persistence while making it less transparent at least for
some applications. Either through allowing processes to read the
status of dirty bits.
Or some kind of atomic commit phase, and capability which sends a
message when a checkpoint is reached.
This latter thing is made more difficult due to the lack of signals
but I digress.

There is already an exception to support database commit.

Dirty bits are not part of the architected semantics. They are an efficiency convenience for internal use by the kernel. There's also a concern that exposing knowledge of checkpoint timing introduces a covert channel.

What's the use case for the information exposure you are suggesting? What are you actually trying to accomplish?
 
The main point is that if you intend to make the persistence entirely
hardware and totally transparent, there are
probably some applications where that is desirable. But tinkering with
the persistence layer isn't one of those.

Letting applications tinker with the persistence layer is a very firm anti-goal. From a "must trust this" perspective, it's in the same bucket as the system storage allocator (the space bank).


Jonathan

Matt Rice

unread,
Dec 5, 2025, 7:25:02 PM (11 days ago) Dec 5
to cap-...@googlegroups.com
On Fri, Dec 5, 2025 at 8:28 PM Jonathan S. Shapiro
<jonathan....@gmail.com> wrote:
>
> On Thu, Dec 4, 2025 at 8:22 PM Matt Rice <rat...@gmail.com> wrote:
>>
>> I somewhat hesitate to ask, but in the hardware variant is there a
>> plan for how transparent
>> the persistence layer is going to be?
>
>
> The consistent evidence over the last 40 years is that the practical choices are either full orthogonal persistence or full manual persistence. To my knowledge, nobody has come up with a good way to implement durable process authority protection if a manual approach is used.
>
>>
>> I would somewhat assume it
>> would keep the MMU/paging system
>> like design at the hardware level (i.e. not transparent).
>
>
> I haven't yet caught up on CHERI enough to answer that, but persisting the mapping structures isn't usually the hard part. In Coyotos there is a design challenge in mapping between GPTs and the native translation mechanism, but I don't know enough yet to know if that's even necessary with CHERI.
>
> The other piece of what I meant is that not everything has to be implemented in hardware. If we can expedite the invocation path and the translation path that's great, but it's not necessary. CHERI has some context switching support that would be nice to use .
>
>>
>> Part of the reason I ask is I've always wanted to explore ways to keep
>> orthogonal persistence while making it less transparent at least for
>> some applications. Either through allowing processes to read the
>> status of dirty bits.
>> Or some kind of atomic commit phase, and capability which sends a
>> message when a checkpoint is reached.
>> This latter thing is made more difficult due to the lack of signals
>> but I digress.
>
>
> There is already an exception to support database commit.
>
> Dirty bits are not part of the architected semantics. They are an efficiency convenience for internal use by the kernel. There's also a concern that exposing knowledge of checkpoint timing introduces a covert channel.

Yeah that concern is why I thought that it should be a capability and
probably not widely granted.

>
> What's the use case for the information exposure you are suggesting? What are you actually trying to accomplish?
>

I had two things in mind, the first is very simply displaying the saved status.
The second (probably more controversial) is actually organizing the
process's state so that it can produce a
diff between the last checkpointed state and the current state. That
may well fall under the same banner of being a manually managed
persistence just without any obvious manual management API.

E.g. when one is replicating process state between systems via network
and wants to give priority to the uncheckpointed portion of data.

The general idea was that if you kept within your process state an
array, and you could keep a tally of the last persisted index which
was fully/completely written at which point the data associated with
that index was finished.
The notion of atomic commit that I was considering was "is guaranteed
to be either entirely written checkpoint or entirely absent from a
checkpoint"

Jonathan S. Shapiro

unread,
Dec 5, 2025, 7:57:12 PM (11 days ago) Dec 5
to cap-...@googlegroups.com
On Fri, Dec 5, 2025 at 4:25 PM Matt Rice <rat...@gmail.com> wrote:
> What's the use case for the information exposure you are suggesting? What are you actually trying to accomplish?
>

I had two things in mind, the first is very simply displaying the saved status.

Right. There's a more general issue of how and what events we might want to log as operating health and/or performance metrics, which would presumably be exposed through a capability interface.
 
The second (probably more controversial) is actually organizing the
process's state so that it can produce a
diff between the last checkpointed state and the current state.

This is something that we explicitly do not want a process to be able to do. It would have the effect of preventing the checkpointing mechanism from freeing the checkpoint log after migration, which would bring the entire system to a halt in single digit minutes. With SSDs involved, that would probably take under 30 seconds. 

There are other ways to approach logging of updates using mechanisms available to memory keepers in the normal way. Keeping that checkpoint-oblivious is probably best.
 
E.g. when one is replicating process state between systems via network
and wants to give priority to the uncheckpointed portion of data.

Hmm. Replicating processes across systems via network inherently exits the consistency boundary. Offhand, it doesn't seem clear that knowing about checkpoint boundaries is helpful.

I don't know if you remember, but a distributed system version of EROS was my originally intended dissertation topic. There's a seriously incomprehensible tech note on how to do it that I wrote at that time and could possibly convert to English so somebody else might try it.
 
The general idea was that if you kept within your process state an
array, and you could keep a tally of the last persisted index which
was fully/completely written at which point the data associated with
that index was finished.

I haven't given this enough thought to have anything like a strong opinion, but I'm wondering if what you really want here isn't a loggable copy-on-write address space. The checkpoint boundaries don't really have much to do with cross-network cloning. 
 
The notion of atomic commit that I was considering was "is guaranteed
to be either entirely written checkpoint or entirely absent from a
checkpoint"

There are two points where an atomic commit occurs in the checkpoint process. One is when a checkpoint is completely written down, and the other happens when a checkpoint migration has completed and the associated chunk of the checkpoint log can be released for re-use. Later versions of the checkpoint log are effectively ring buffers. None of these commits are per-application; they are per-system.



Jonathan

Matt Rice

unread,
Dec 5, 2025, 8:14:53 PM (11 days ago) Dec 5
to cap-...@googlegroups.com
On Sat, Dec 6, 2025 at 12:57 AM Jonathan S. Shapiro
<jonathan....@gmail.com> wrote:
>

> I don't know if you remember, but a distributed system version of EROS was my originally intended dissertation topic. There's a seriously incomprehensible tech note on how to do it that I wrote at that time and could possibly convert to English so somebody else might try it.
>

Nope, I actually wasn't around until maybe a week before coyotos went on hiatus.
So I was very late to the party.

>
> There are two points where an atomic commit occurs in the checkpoint process. One is when a checkpoint is completely written down, and the other happens when a checkpoint migration has completed and the associated chunk of the checkpoint log can be released for re-use. Later versions of the checkpoint log are effectively ring buffers. None of these commits are per-application; they are per-system.

Perhaps I am remembering capros then that had I believe per-domain checkpoint.
I remember something had switched from per-system to per-domain, but
it could also be something
that was tried but never panned out. *shrug*

Jonathan S. Shapiro

unread,
Dec 5, 2025, 8:25:22 PM (11 days ago) Dec 5
to cap-...@googlegroups.com
On Fri, Dec 5, 2025 at 5:14 PM Matt Rice <rat...@gmail.com> wrote:
Perhaps I am remembering capros then that had I believe per-domain checkpoint.

I'm afraid not. None of the KeyKOS family have ever done that. It would be unusable.

If you want to look at what changed going into Coyotos: Design Evolution of the EROS Single-Level Store. It's a USENIX paper, so thankfully not paywalled.


Jonathan

Matt Rice

unread,
Dec 6, 2025, 7:12:57 AM (10 days ago) Dec 6
to cap-...@googlegroups.com
On Sat, Dec 6, 2025 at 12:57 AM Jonathan S. Shapiro
<jonathan....@gmail.com> wrote:
>
> On Fri, Dec 5, 2025 at 4:25 PM Matt Rice <rat...@gmail.com> wrote:
>>
>> > What's the use case for the information exposure you are suggesting? What are you actually trying to accomplish?
>> >
>>
>> I had two things in mind, the first is very simply displaying the saved status.
>
>
> Right. There's a more general issue of how and what events we might want to log as operating health and/or performance metrics, which would presumably be exposed through a capability interface.
>
>>
>> The second (probably more controversial) is actually organizing the
>> process's state so that it can produce a
>> diff between the last checkpointed state and the current state.
>
>
> This is something that we explicitly do not want a process to be able to do. It would have the effect of preventing the checkpointing mechanism from freeing the checkpoint log after migration, which would bring the entire system to a halt in single digit minutes. With SSDs involved, that would probably take under 30 seconds.
>
> There are other ways to approach logging of updates using mechanisms available to memory keepers in the normal way. Keeping that checkpoint-oblivious is probably best.
>

Sorry I don't want to belabour the point...
There is at least one correction I should make, and perhaps a more
high-level explanation of the application,
and let me just drop the distributed aspects of the problem
altogether. I hope that will put things into
better perspective.

First, when I said "diff between the last checkpointed state and the
current state.", I really should have said
"the unwritten portion of an append-only log" or something similar, in
theory it isn't append-only,
the ideal implementation that I wanted was basically a LIFO queue in a
ring buffer.
It wasn't clear to me that the database log "escape hatch" described
in the single level store paper was suitable as that kind of a ring
buffer.

Let me use an analogy which is not perfect, but also not too far from the truth.
Basically we wanted a flight-recorder box (that also transmits its
current sensor data via a network).

The checkpoint interval if I recall was minutes, which is ample time
to crash and burn due to
catastrophic failure between checkpoints. Leaving the most
crash-relevant data in the short window
before machine failure the most likely to be outside of the current checkpoint.

So it seemed like I was after something very similar to the checkpoint
mechanism, with a faster checkpoint interval,
for small amounts of sensor data, possibly even just raw data and not
a reference graph of capabilities.

The distributed aspects of this were much simpler than a typical
distributed system where we can't actually
distribute all the time series data collected by each node. But still
need to transmit via a network a fairly narrow window of the same data
for which we wanted a shorter checkpoint interval.

In the real flight recorder problem there is also probably a trust
relationship that needs to be dealt with
between a regulatory agency and the instrument/sensor provider and
manuf**turers.
It isn't clear to me that there *is* a standard flight data recorder
that includes arbitrary sensor data and control input data.
Not just voice/radio transmission...

In our case the intent was to deploy them in front of fire lines of
forest fires to relay conditions on the ground to those behind them,
putting the machine in harm's way. This made it more of a distributed
problem.

I feel like the flight recorder problem is an important problem that
coyotos should be
well suited to. The persistence mechanism it has is tantalizingly
close to what is needed for post mortem analysis
but even if we throw away the distributed problem that I presented it
as initially it doesn't really seem suitable for the kind of
post-mortem analysis that goes with rapid catastrophic failure.

It is entirely possbile that the checkpoint-oblivious approach *is*
the right approach, and that the similarities to the
persistence mechanism are a mirage, but it seemed to me like it was
worth experimenting with checkpoint aware approaches.

I apologize for not actually being able to come up with a shorter
explanation, I hope that makes sense.

>>
>> E.g. when one is replicating process state between systems via network
>> and wants to give priority to the uncheckpointed portion of data.
>
>
> Hmm. Replicating processes across systems via network inherently exits the consistency boundary. Offhand, it doesn't seem clear that knowing about checkpoint boundaries is helpful.
>
> I don't know if you remember, but a distributed system version of EROS was my originally intended dissertation topic. There's a seriously incomprehensible tech note on how to do it that I wrote at that time and could possibly convert to English so somebody else might try it.
>
>>
>> The general idea was that if you kept within your process state an
>> array, and you could keep a tally of the last persisted index which
>> was fully/completely written at which point the data associated with
>> that index was finished.
>
>
> I haven't given this enough thought to have anything like a strong opinion, but I'm wondering if what you really want here isn't a loggable copy-on-write address space. The checkpoint boundaries don't really have much to do with cross-network cloning.
>
>>
>> The notion of atomic commit that I was considering was "is guaranteed
>> to be either entirely written checkpoint or entirely absent from a
>> checkpoint"
>
>
> There are two points where an atomic commit occurs in the checkpoint process. One is when a checkpoint is completely written down, and the other happens when a checkpoint migration has completed and the associated chunk of the checkpoint log can be released for re-use. Later versions of the checkpoint log are effectively ring buffers. None of these commits are per-application; they are per-system.
>
>
>
> Jonathan
>
> --
> You received this message because you are subscribed to the Google Groups "cap-talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/cap-talk/CAAP%3D3QN2PCyxxrR0bN3k%3DYBEUCweEjCGg8HF2vy%3DBA%3D91YCBMw%40mail.gmail.com.

Jonathan S. Shapiro

unread,
Dec 6, 2025, 3:21:00 PM (10 days ago) Dec 6
to cap-...@googlegroups.com
On Sat, Dec 6, 2025 at 4:12 AM Matt Rice <rat...@gmail.com> wrote:
Sorry I don't want to belabour the point...

There's plenty of confusion to be had when talking about checkpoint. Better to get it out in the open.
 
First, when I said "diff between the last checkpointed state and the
current state.", I really should have said
"the unwritten portion of an append-only log" or something similar, in
theory it isn't append-only, 
the ideal implementation that I wanted was basically a LIFO queue in a
ring buffer.
It wasn't clear to me that the database log "escape hatch" described
in the single level store paper was suitable as that kind of a ring
buffer.

Let me take this in reverse.

The "escape hatch" was designed for database logs, but it probably could be put to other uses. I don't know if anybody has given that much thought. What it essentially does is take a [designated] data page, write it to the checkpoint log, and ensure that it gets incorporated into the committed checkpoint. Because the page has been dirtied, it is already guaranteed that there is space reserved for it in the checkpoint area; the tricky part is getting it added to the list of saved pages in the committed checkpoint. Because the page is dirty, it also appears in the in memory directory of objects that will become the next checkpoint. So either the system makes it to the next checkpoint and saves it, or the system reverts to the previous checkpoint and recovers it from the log.

Assume that we've just committed checkpoint A, and we are now executing and mutating against what will become the next checkpoint B. Somewhere in all this there is a database running. It is either appending updates to the log (for redo on recovery) or appending old values to the log (for undo on recovery). In a persistent system it is probably sticking these in an in-memory ring buffer. After writing the records, it explicitly writes the pages that have changed using the escape hatch, forcing them to durable storage in the checkpoint log.

Once those pages have been captured, the system may crash before checkpoint B is written down. But by this point the pages have already been written down and appended to checkpoint A. When the system restarts, these pages survive and continue to be part of the database log and therefore the database state.

These database log pages are likely to get written multiple times between checkpoints if the database is active. The trickiest parts of the escape hatch are making sure that the pages are written down atomically (so that we either have the old page or the new page) and that the checkpoint directory written in the log is also updated atomically.



The part of your description that made me nervous is the idea of diffing across generations. In order for checkpointing to be able to continue on a regular basis, we need to clear the space in the checkpoint ring buffer incrementally by writing those objects back to their home locations. Once that is done, that portion of the ring buffer is used to improve object read efficiency until that region is "claimed" for a new checkpoint. The problem with diff is that you would still need access to those objects until the diff is complete, and that basically means that a new checkpoint can't be taken if it would step on the checkpoint region that you are diffing against.

It would make me even more concerned if the client application doing the diff isn't part of the system TCB, because that application can effectively bring the entire system to a halt by failing to complete on time or merely by having an execution bug.
 
Let me use an analogy which is not perfect, but also not too far from the truth.
Basically we wanted a flight-recorder box (that also transmits its
current sensor data via a network).

Right. That doesn't sound like a checkpoint problem. It sounds like a database problem.
 
The checkpoint interval if I recall was minutes, which is ample time
to crash and burn due to catastrophic failure between checkpoints.

So first, that's a thing that can be tuned. 5 minutes was an ad hoc choice to arrive at a tolerable level of I/O overhead on slowly spinning media and low speed processors. Today, with the prevalence of SSDs, bigger memories, and much faster processors, that number would need re-assessment.

But even if it were every 10s or 15s, that's still way to slow for anything similar to a database transaction log.
 
It isn't clear to me that there *is* a standard flight data recorder
that includes arbitrary sensor data and control input data.

I haven't looked at the relevant standards or directives, but commercial jets record a lot of telemetry in addition to voice data. It's necessary for a whole bunch of reasons.
 
In our case the intent was to deploy them in front of fire lines of
forest fires to relay conditions on the ground to those behind them,
putting the machine in harm's way. This made it more of a distributed
problem.

Yup. And a very cool and very helpful application.


Jonathan

Jonathan S. Shapiro

unread,
Dec 15, 2025, 5:12:12 PM (24 hours ago) Dec 15
to cap-...@googlegroups.com
I think pain was not the word I wanted. Rust requires learning some new memory management concepts, or at least mapping them to stuff you already knew to see what they actually do. If you are coming at this cold, it feels like a big lift, it can be intimidating, and you end up spending a bunch of time fighting with it.

In my case, it's more that I was kind of "stuck" about this, and I suspect I'm not alone. I actually understand the underlying type theory and control flow issues; I was just resisting the work to apply them for various reasons. I'm quite certain I'll get stuck at various points, and some of them will turn out to be irritating. But I'll be surprised if I find myself in a situation where I don't understand why I'm stuck. One of the things Rust actually did very well is to limit the scope of the borrow checking rules in such a way that a small change here doesn't lead to a catastrophic explosion there. That helps quite a lot.

My concerns about kernel-level use were unfounded. The resolution revolves around UnsafeCell. Which is unfortunate, because it changes the sequencing and memory barrier model in significant ways that impede the optimizer. But I'm now at the point where I think the Crate model may end up being more hassle for me than Rust's memory handling provisions. :-)


Jonathan

Alan Karp

unread,
Dec 15, 2025, 6:10:55 PM (23 hours ago) Dec 15
to cap-...@googlegroups.com
Someone pointed out that what the Rust borrow checker does for you is what you have to do in your head with C/C++.  The biggest difference is that you get compiler errors instead of vulnerabilities and segfaults.  That's frustrating for people used to easy to compile, debug at runtime.    One strategy to  reduce your frustration as you're learning is to just throw in clone() whenever that will get around a borrow check error.  After a while, you won't have to do that, but it will reduce your frustration while you're learning.  You'll be able to get rid of most of them when you're more comfortable with the language

One last point.  Most compilers' error messages are as useful as if they'd been encrypted, so you learn to ignore them.  Not so with Rust.  Very often the compiler will say, "Did you mean this?" and give you the fix.  That feature substantially shortened my learning curve.

--------------
Alan Karp


--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

Jonathan S. Shapiro

unread,
Dec 15, 2025, 6:30:20 PM (23 hours ago) Dec 15
to cap-...@googlegroups.com
Alan:

Thanks for the helpful thought. Unfortunately, modify-in-place is pretty essential in many parts of a kernel. Clone() isn't a solution for those. But one of the things I was really happy to see is that Rust handles the control flow graph around non-returning procedures correctly. Without that, I think I'd be toast.

Oddly enough, I'm not that worried about the borrow checker now that I understand what it actually does. I suppose we will see whether that's false optimism. :-)

Error messages are hard, and tend to require modifications to an already complicated parser. In consequence, compiler writers try not to think about them until late in the game, by which time they are a pain to retrofit. Nice to hear that the Rust folks have worked hard on them.


Jonathan


Matt Rice

unread,
Dec 15, 2025, 6:52:21 PM (22 hours ago) Dec 15
to cap-talk


On Mon, Dec 15, 2025, 3:30 PM Jonathan S. Shapiro <jonathan....@gmail.com> wrote:
Alan:

Thanks for the helpful thought. Unfortunately, modify-in-place is pretty essential in many parts of a kernel. Clone() isn't a solution for those. But one of the things I was really happy to see is that Rust handles the control flow graph around non-returning procedures correctly. Without that, I think I'd be toast.

One thing to look at which interestingly doesn't appear to require unsafe is the tock-os TakeCell implementation. It isn't exactly modify-in-place. In the sense that it takes ownership of a mutable reference by moving that. Mutating through the reference and moving the reference back.
At least limiting the move to a reference.
I don't know if that is a pattern coyotos can benefit from anywhere

From my phone...

Jonathan S. Shapiro

unread,
Dec 15, 2025, 7:30:53 PM (22 hours ago) Dec 15
to cap-...@googlegroups.com
Matt:

This is clearly going to involve some learning curve on my part. Thanks for pointing the TakeCell option out. Maybe lets get to the point where there's enough rust code in place to have a live example to look at and talk about the options.

The current kernel has a mildly unusual set of namespace and publication interactions. Figuring out how to translate that into Cargo-speak has taken a bit of time. It sometimes feels like beating build systems into submission is the hardest part of compiling large projects. :-)

I'm sure some of the answers from ChatGPT won't be right, but it has been surprisingly helpful in learning how to think about some things in the Cargo ethos. I think I'm ready to start laying out the shape of a rust kernel tree. Undoubtedly incorrectly, but you have to start somewhere. :-)


Jonathan

Matt Rice

unread,
Dec 15, 2025, 8:46:14 PM (20 hours ago) Dec 15
to cap-talk
Indeed, well I am happy to help, I do see where you're coming from, with all the image generation and IDL code gen in the original coyotos build system. It definitely is seems like the build aspects could be intricate.

One of the projects I have worked on a lot is the grntools yacc implementation which also requires a lot of code gen at build time. 

In that case we have things like CTParserBuilder and CTLexerBuilder where CT stands for Compile TIme.  I.e. those run at build phase and generate code which subsequently gets compiled.

I don't see a direct replacement for a lot of things in the coyotos build process, like cargo gives you pretty basic bin and lib targets. Nothing directly equivalent to an image.

Similarly I'm not certain how to beat integrate the IDL compiler, proc macros which read the IDL files I would guess.

Anyhow build process is not likely going to end up sharing a whole lot of familiarity to the make based one. Just because cargo isn't flexible like make (for better or worse).

On my phone




Jonathan

--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

William ML Leslie

unread,
Dec 15, 2025, 9:49:55 PM (19 hours ago) Dec 15
to cap-...@googlegroups.com
On Tue, 16 Dec 2025 at 11:46, Matt Rice <rat...@gmail.com> wrote:
I don't see a direct replacement for a lot of things in the coyotos build process, like cargo gives you pretty basic bin and lib targets. Nothing directly equivalent to an image.

Similarly I'm not certain how to beat integrate the IDL compiler, proc macros which read the IDL files I would guess.

I don't know that we need to worry about this too much.  Microkit, the current build system for seL4, is in Rust; and their build is more involved than ours.

Having rewritten the image generator in Monte and now almost rewritten it in javascript, it's work, but not that much work.  Assuming you actually want to move those to Rust.  I would prefer the image descriptions to be in an ocap language, but I don't know what Shap wants to do.

When I did the Guix builds, I put the build tools and libraries in their own package, and had the userspace build depend on them.  It meant cutting up some make files, but I liked the result.

--
William ML Leslie

William ML Leslie

unread,
Dec 15, 2025, 10:13:23 PM (19 hours ago) Dec 15
to cap-...@googlegroups.com
On Tue, 16 Dec 2025 at 11:46, Matt Rice <rat...@gmail.com> wrote:
Similarly I'm not certain how to beat integrate the IDL compiler, proc macros which read the IDL files I would guess.

Well I have seen tonic build, which is used to generate grpc clients and servers, and bindgen, which is used to integrate with C libraries.  I was using both of these at my last job, they rely on the build.rs mechanism.  We could do something similar.
 
--
William ML Leslie

Matt Rice

unread,
Dec 15, 2025, 10:32:26 PM (19 hours ago) Dec 15
to cap-talk
Yeah I meant to say that invoking either rustc directly or cargo as part of a make based build script is also doable.  I haven't looked at Microkit or rust-sel4 but sel4 is cmake based so they either invoke cmake from cargo, or cargo or rustc directly from cmake.  Both are possible.

One of the reasons I advocate a purely cargo based approach is the ability to avoid pre installation of tools and interpreters.  It would be nice if the total sum of cross build instructions could be, install rust compilers, checkout, and cargo build. Without futzing with setting up build environments, etc.  that is personally what I think would be ideal, but it might not be the easiest thing in the world...

To me though for a book like project, the lower friction the amount of pre build setup the better. To just avoid losing people in the initial bootstrap before they even get their feet wet.

But yeah, you are right there are ways to go about it that are probably less invasive and more in keeping with how coyotos has been built historically.

On my phone


--
William ML Leslie

--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

Alan Karp

unread,
Dec 15, 2025, 10:58:22 PM (18 hours ago) Dec 15
to cap-...@googlegroups.com
Have you looked at projects developing an OS in Rust, such as https://www.redox-os.org/?  Maybe they have some tools you can use.

--------------
Alan Karp


--
You received this message because you are subscribed to the Google Groups "cap-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cap-talk+u...@googlegroups.com.

William ML Leslie

unread,
Dec 15, 2025, 10:59:33 PM (18 hours ago) Dec 15
to cap-...@googlegroups.com
On Tue, 16 Dec 2025 at 13:32, Matt Rice <rat...@gmail.com> wrote:
Yeah I meant to say that invoking either rustc directly or cargo as part of a make based build script is also doable.  I haven't looked at Microkit or rust-sel4 but sel4 is cmake based so they either invoke cmake from cargo, or cargo or rustc directly from cmake.  Both are possible.

Microkit is not prescriptive as to build system.  The tutorial uses gnu make, since the example components are written in C.

One of the reasons I advocate a purely cargo based approach is the ability to avoid pre installation of tools and interpreters.  It would be nice if the total sum of cross build instructions could be, install rust compilers, checkout, and cargo build. Without futzing with setting up build environments, etc.  that is personally what I think would be ideal, but it might not be the easiest thing in the world...

To me though for a book like project, the lower friction the amount of pre build setup the better. To just avoid losing people in the initial bootstrap before they even get their feet wet.

Given how much cargo loves static linking, I wouldn't be surprised if you could do a cargo package of our existing tools, or even of wasm-compiled interpreters.

--
William ML Leslie

William ML Leslie

unread,
Dec 15, 2025, 11:02:16 PM (18 hours ago) Dec 15
to cap-...@googlegroups.com
On Tue, 16 Dec 2025 at 13:58, Alan Karp <alan...@gmail.com> wrote:
Have you looked at projects developing an OS in Rust, such as https://www.redox-os.org/?  Maybe they have some tools you can use.

Related: did you know they are planning to make Redox OS a capability system?  It's still early stages, but they seem serious.

--
William ML Leslie

Daira-Emma Hopwood

unread,
5:07 AM (12 hours ago) 5:07 AM
to cap-...@googlegroups.com


On Tue, 2 Dec 2025, 01:04 Jonathan S. Shapiro, <jonathan....@gmail.com> wrote:

But let's start with a different question: What added value does CHERI provide if we start from the assumption that the application code is required to be type safe and/or verified memory safe?

"Required" here means that someone is relying on it for security or reliability. Clearly for each program, we want it to be compiled by a correct and security-preserving compiler. But that doesn't mean that we want the overall security of the system to be dependent on every version of every compiler used to compile executables. That was the Achilles heel of early attempts at language-based security like the Burroughs machines. (Note that recompiling everything when you fix a compiler security bug both isn't particularly feasible, and does not solve the problem if the system-level security properties have already been corrupted.)

CHERI would be one way of addressing that problem, allowing the security of the OS to avoid relying on particular compilers.

I'm considering a variant in which capabilities reference OS objects, and do not replace conventional pointers.

The above discussion is independent of this choice, I think.

-- 
Daira-Emma Hopwood
Reply all
Reply to author
Forward
0 new messages