Open andresag01 opened 1 year ago
Nothing is written, yet, no. In part I think this would be part of a larger effort to evaluate more recent changes to the privileged spec. There are some important lessons to be learned here from Morello which requires bounds to cover the entire cache line which is not ideal. Probably you just want the bounds to overlap with at least part of the region you are flushing (at least for flush and prefetch) as the actual write was already validated and flush is just changing the "timing" of a commit, and similarly for prefetch the actual read will be validated in the future.
Invalidate is the interesting one. RISC-V made the, in my opinion, dangerous and misguided choice to not require write permission in the corresponding PTE (contrast with Arm, which does). For invalidate the only sensible option is to require bounds of the whole line and write permission, since otherwise it is a hole through which you can revert writes.
Invalidate is incredibly dangerous since it could be used to restore capabilities that were expected to be deleted. IMO the only sane thing is to not allow invalidates or require an almighty capability.
As far as I know, the RISC-V CMO spec allows disabling invalidations in lower privileged levels by writing bits in a CSR. It is possible to either cause a trap when an invalidation is performed or simply perform a cbo.flush
in place of an invalidation depending on the CSR configuration. I do not know if it a compliant implementation can completely get rid of the cbo.inval
instruction.
it's valid to do that - I asked for clarification earlier this year - so I think what we should do is strongly recommend that when CHERI is implemented that CBO.INVAL always operates as CBO.FLUSH. Apart from anything else, it's always valid to use CBO.FLUSH as you never know whether a line is in the cache or not.
To answer @bsdjhb 's comment from above - we need to write some rules for this (which accidentally turned into a new issue when I try to reply to his comment)
CBO.ZERO must clearly cover the whole cache line, as every byte is written. CBO.INVAL -> remap to CBO.FLUSH CBO.FLUSH -> bounds cover at least part of the cache line? Must it include the VA? PREFETCH.* -> do we need bounds checking? Are we introducing a side-channel if we don't include any? As you say the actual read is accurately validated, so we're only issuing a hint to update the cache state.
After discussions, the current proposal is as follows:
The data itself may be invalidated from the cache, but the cache line's capability tags must be zeroed and written back
This is very odd. I get that it’s a dangerous instruction, but this is not an invalidate operation, an invalidate is to drop everything and read what’s in DRAM again, which would include whatever tags DRAM has.
These instructions do not provide data/instruction access and make no architecturally visible changes, so it is safe to not require capabilities to execute them.
I don’t see a good reason not to, and code that wants to talk about memory it doesn’t have access to is dodgy anyway. Prefetching should silently become a nop given an invalid capability, and flush/clean likely should fault. Otherwise it sounds like you’re potentially giving people useful gadgets for speculation attacks. This could be of significant concern in a compartmentalised environment. I would be uncomfortable not having these checks.
The data itself may be invalidated from the cache, but the cache line's capability tags must be zeroed and written back
This is very odd. I get that it’s a dangerous instruction, but this is not an invalidate operation, an invalidate is to drop everything and read what’s in DRAM again, which would include whatever tags DRAM has.
I guess that if you really want an invalidate then you shoudl get just that. The concern is that rogue invalidations could reveal stale capabilities which have been overwritten.
Maybe you need controls on it per privilege level (or ring), and / or an invalidate permission bit?
As discussed:
RISC-V has a cache management extension with instructions for operations like flush, clean, prefetch, etc. It would be good to write the specification for these instructions in the CHERI-RISC-V context. The bounds, access, etc checks for these instructions are different when compared to load/store instructions.
Are there currently any CHERI proposals in connection with the RISC-V cache management extension?