Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vaddr_t rules #22

Open
ltratt opened this issue Oct 5, 2021 · 13 comments
Open

vaddr_t rules #22

ltratt opened this issue Oct 5, 2021 · 13 comments

Comments

@ltratt
Copy link

ltratt commented Oct 5, 2021

We (mostly @jacobbramley and I) are unsure about the precise semantics of vaddr_t. The C/C++ programming guide says:

vaddr_t This is a new integer type introduced by CHERI C and should be used to hold virtual
addresses. vaddr_t should not be directly cast to a pointer type for dereference; instead,
it must be combined with an existing valid capability to the address space to generate a
dereferenceable pointer. Typically, this is done using the cheri_address_set(c, x)
function.

From this we infer that the expectation is that it maps to a uintX_t type? Does it map to the same type in both hybrid and purecap compilation? [One possibility is that vaddr_t could map to void * in hybrid mode but that wouldn't work in purecap mode where presumably uintX_t is the only practical C type to map to.]

We're also not sure what to do with "vaddr_t should not be directly cast to a pointer type for dereference". Does that mean that (say) char *x = cheri_address_get(cap) causes UB? Are there implications for pointer provenance (and are those the same in hybrid/purecap)? We're also not sure if there are things that we should think are different about CHERI C/C++ vs. "standard" C/C++.

I'm sure there are other questions I should ask. I know enough about C's semantics to know that I don't know everything :)

@arichardson
Copy link
Member

arichardson commented Oct 5, 2021

ptraddr_t (the new name for vaddr_t) is a non-provenance-carrying integer type in both purecap and hybrid. In hybrid you can obviously still cast it to an integer pointer and dereference it (relative to DDC), but in purecap it's always a plain integer than can't be dereferenced.
The compiler now provides __PTRADDR_TYPE__ to define ptraddr_t (it usually expands to long unsigned int)

@jrtc27
Copy link
Member

jrtc27 commented Oct 5, 2021

On RV32 it should be just unsigned int, and on 64-bit Windows it would be unsigned long long as their long is 32-bit.

As with all types in C though there’s no upper bound on its size, it’s just large enough to be able to hold the integer addresses of all valid pointers.

@ltratt
Copy link
Author

ltratt commented Oct 5, 2021

ptraddr_t (the new name for vaddr_t) is a non-provenance-carrying integer type in both purecap and hybrid. In hybrid you can obviously still cast it to an integer pointer and dereference it (relative to DDC)

In hybrid mode, if it's non-provenance carrying, can I safely cast it to a pointer type and dereference it? [I ask this slightly naively: I've not poked and prodded all the dark corners of pointer provenance.]

@jrtc27
Copy link
Member

jrtc27 commented Oct 5, 2021

It's non-provenance-carrying in the CHERI sense. In hybrid C it maintains all the same semantics as any other integral type being cast to a pointer, namely that it works provided the integer is big enough (which, by the definition of ptraddr_t, it will be), so in hybrid C you can consider it to just be another name for uintptr_t (though they could differ in representation).

@ltratt
Copy link
Author

ltratt commented Oct 5, 2021

It's non-provenance-carrying in the CHERI sense

Just to check: if I'm in hybrid mode, and I cast a capability to (say) void *, I've lost CHERI provenance (since I no longer have a capability) and I'm back in normal C provenance rules?

@jrtc27
Copy link
Member

jrtc27 commented Oct 5, 2021

It's non-provenance-carrying in the CHERI sense

Just to check: if I'm in hybrid mode, and I cast a capability to (say) void *, I've lost CHERI provenance (since I no longer have a capability) and I'm back in normal C provenance rules?

Yes (with the only subtle difference being that, if you've mucked with DDC, that pointer had better be in DDC's bounds if you want to use it).

@ltratt
Copy link
Author

ltratt commented Oct 5, 2021

with the only subtle difference being that, if you've mucked with DDC, that pointer had better be in DDC's bounds if you want to use it

Indeed :)

OK, I think that @jacobbramley and I feel better informed now. I can't promise we won't have future questions, but I am grateful for the answers to our current head-scratchers!

@mirabilos
Copy link

mirabilos commented Aug 11, 2023

are there corresponding limits for ptraddr_t (and why’s the guide not updated for the new name)?

ok I guess one could use ((ptraddr_t)~(ptraddr_t)0) as limit as with all other unsigned types

… but CheriOS uses vaddr_t!

@mirabilos
Copy link

and are there cpp constants to check whether to use vaddr_t or ptraddr_t (with CHERI) or uintptr_t with a fallback to size_t (on nōn-CHERI UNIX)?

@jrtc27
Copy link
Member

jrtc27 commented Aug 11, 2023

b6062ce, just the published report predates that. CheriOS is old abandonware, most of which was written years before ptraddr_t was adopted.

__PTRADDR_MAX__ exists like __SIZE_MAX__ for GNU C, but it's true we're missing a PTRADDR_MAX in CheriBSD like the standard non-GNU-specific SIZE_MAX.

@jrtc27
Copy link
Member

jrtc27 commented Aug 11, 2023

and are there cpp constants to check whether to use vaddr_t or ptraddr_t (with CHERI) or uintptr_t with a fallback to size_t (on nōn-CHERI UNIX)?

__PTRADDR_TYPE__ exists like __SIZE_TYPE__ and __(U)INTPTR_TYPE__, though it's GNU-specific if that matters to you (which likely doesn't, unless Windows+CHERI becomes a thing?).

@mirabilos
Copy link

mirabilos commented Aug 11, 2023

Thanks! Is there also something for Cheri* (generally, not limited to BSD, and yes including a hypothetical Windows) so that I could use…

#ifdef __CHERI__    /* ← this? */
#define myPointerBaseAddressType ptraddr_t
#elif defined(UINTPTR_MAX)
#define myPointerBaseAddressType uintptr_t
#else
#define myPointerBaseAddressType size_t /* fallback */
#endif

… and in which header(s) would ptraddr_t be? (And, I can completely disregard vaddr_t now?)

@jrtc27
Copy link
Member

jrtc27 commented Aug 11, 2023

Eh, __CHERI__ does exist, and currently means "hybrid or pure-capability". Some of us want to repurpose it to mean "pure-capability" given we call that CHERI C/C++ these days. Having said that, for you it doesn't matter, since in the hybrid case ptraddr_t and uintptr_t will both exist and be the same type. There's also __has_feature(capabilities) for "hybrid or pure-capability" and __CHERI_PURE_CAPABILITY__ for pure-capability specifically. Take your pick.

ptraddr_t lives in stdint.h like (u)intptr_t. You can ignore vaddr_t; using it will even give you a warning in CheriBSD as of late, so that we can finally purge it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants