notes-computer-programming-programmingLanguageDesign-cheri thoughts

see Self:proj-plbook-plChSecurityLangs for my notes on CHERI.


my questions on the above:

1) Let's say there is a capability sitting in main memory (so, its tag is on). If a non-capability register loads this (via repeated CLD instructions; page 131) and then stores it (via repeated CSD instructions), then does the stored value retain the tag?

i don't think so.

Some evidence that it would retain the tag is:

But some evidence that it wouldn't retain the tag is:

2) I see how Permit_Store_Capability gives you the option of giving code a capability without permitting it to share that capability (to 'write it down'). But what is the purpose of the Permit_Load_Capability capability? That is, in what circumstances would you want for some code to posses Permit_Load but not Permit_Load_Capability?

they list as one of their 'deeper design decisions' "Permissions on capabilities include the ability to not just control loading and storing of data, but also loading and storing of capabilities" (section 4.6 page 68), but what is the purpose of this?

if the answer to (1) were that the tag was preserved, then i would say that the purpose of Permit_Load was to allow code to copy capabilities in memory without being able to actually use them itself.

maybe the answer is here: " The decision to strip tags on load, but throw an exception on store, reflects pragmatic software utilization goals: language runtimes and system libraries often need to implement capability-oblivious memory copying , as the programmer may not wish to specify whether a region of memory must (or must not) contain capabilities). By stripping tags rather than throw- ing an exception on load, a capability-oblivious memory copy is safe to use against arbitrary virtual addresses and source capabilities – without risk of throwing an exception. Software that wishes to copy only data from a source capability, excluding tag bits due to a non-propagation goal, can simply remove the load-capability permission from the source capability before be- ginning a memory copy " (section 3.2.7 page 44)

so the idea is that you can use the capability registers to copy data, while stripping the tag bits, if Permit_Load is unset? That's not very satisfying if you could have already done that using non-capability registers.

actually, i think the idea is that you can have one copy routine which is passed in a capability to use while copying and, depending on whether or not Permit_Load and Permit_Store are set, will either end up stripping the tag bits, or preserving them (but if Permit_Load were set but Permit_Store were not, an exception would be thrown).

i don't find that so useful because the copy routine could have just branched on Permit_Store to either use the capability register or the non-capability GPRs for the copying.

now, what if ordinary data copies DID preserve capabilities? At first glance, this would seem to provide a way for the lack of Permit_Load_Capability to indicate that capabilities CAN be copied but CANNOT be used directly. That is, without Permit_Load_Capability or Permit_Store_Capability , there would still be some way to copy capabilities in main memory, preserving their tag bits; but these capabilities would not be able to be loaded into capability registers, noting that "Where general-purpose registers describe the computation state of a software thread, capability registers describe its instantaneous rights within an address space".

An critical flaw with this is that it prevents there from being any way to give a process read access to a chunk of main memory containing capabilities while preventing it from copying/sharing those capabilities with others. If the others have Permit_Load_Capability on ANY chunk of memory they can receive the capability using ordinary data copy from the sharing process, and then copy it into the chunk of memory in which they have Permit_Load_Capability, and then load it into a capability register from there.

In fact, i guess if a 'middleman' process wanted to transmit capabilities without using them itself, it could just pass on a pointer to them to a third process. If the third process then had Permit_Load_Capability on that area of memory, it could then use the contained capabilities. Note that the middleman can only pass by reference, not via copying; and note that the end recipient must already have a Permit_Load_Capability that spans the memory region that the capability is in. So the middleman can't do anything as useful as compacting garbage collection; it can only refer in conversation with the end recipient to memory locations that the end recipient can already see.

i suppose one way to have middleman copiers or compacting garbage collectors who cannot themselves use the capabilities in the contained memory would be to have a way to say "within the one memory region defined by this capability, you can copy capabilities, but you can't copy them outside of it". The "you can't copy them outside of it" is covered by Permit_Store_Local.

3) is there any use for a capability having Permit_Store_Local without also having Permit_Store?


so i think there should be a 'CMemCpy?' instruction which can copy capabilities only within the region of memory defined by the capability (provided that either Global is set on the capability being copied, or Permit_Store_Local is set on the enabling capability; otoh maybe we dont want to use Permit_Store_Local for this, as we want to preserve Permit_Store without Permit_Store_Local to mean that you can only store global capabilities into here, but what if you had Permit_Store only, would that mean you can copy? this is getting hairy. Maybe introduce a new capability just for CMemCpy?).

This allows: