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

Add CapbilityPtr and Add SuccessAddr and SuccessPtr syscall variants #4174

Merged
merged 47 commits into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
12abe15
MetaPtr + usize/u32 changes
Aug 17, 2024
c32507d
Have MetaPtr wrap a pointer not usize
Oct 14, 2024
677183f
Link to CHERI tracking issue
Oct 14, 2024
6254b9e
Add explicit return codes for usize/ptr
Oct 14, 2024
a5ee396
Better comment for MetaPtr
Oct 14, 2024
fd51098
Fix typo
Oct 14, 2024
c97deea
Apply comment suggestions
LawrenceEsswood Oct 21, 2024
291c8f4
Rename MetaPtr -> CapabilityPtr
Oct 29, 2024
695af1b
Add comment saying into_compat is for legacy only
Oct 29, 2024
7ec6bdd
capability_ptr: update doc to reflect meaning
alevy Nov 4, 2024
d0fa5fc
Update kernel/src/syscall.rs
LawrenceEsswood Nov 8, 2024
be62a66
Update kernel/src/process.rs
LawrenceEsswood Nov 8, 2024
950deb2
Revert notes change
Nov 8, 2024
236a8ac
Remove extra cast step
Nov 8, 2024
a4e5936
Preface internal Google bug tracker
Nov 8, 2024
9ac666b
Remove as_checked_ptr until CHERI lands
Nov 8, 2024
010bf22
Change panic for assert and checked alignment too
Nov 8, 2024
604460c
Make the oddly chosen ANY permission a NONE permission
Nov 8, 2024
79b2b8d
Add provenance notes
Nov 8, 2024
6feb692
Refine CapabilityPtr description slightly
Nov 8, 2024
f800ddd
Minor changes to encode
Nov 8, 2024
2cd33d2
Move capability_ptr to utilities
Nov 8, 2024
bf24e72
Update kernel/src/process.rs
LawrenceEsswood Nov 11, 2024
d569776
Rename into_compat
Nov 11, 2024
743c8cd
Document what authority the CapabilityPtr from brk/sbrk should have
Nov 11, 2024
144269e
Do not pollute scope with Execute
Nov 11, 2024
cc0b53e
Add comment to construction of intial fn
Nov 11, 2024
45f8a44
Remove mention of CHERI
Nov 11, 2024
391dfc8
Use .cast_mut(), not as
Nov 11, 2024
8f8ce44
Document all methods on CapabilityPtr
Nov 11, 2024
a5e5a6d
More formatting/comments/name change for permissions
Nov 11, 2024
f3feec6
Style changes
Nov 11, 2024
a001b33
kernel/syscall: split out encode_syscall_return, create TRD104 subset
lschuermann Nov 8, 2024
7ea663f
kernel: fix rustdoc links
lschuermann Nov 12, 2024
9560125
Merge remote-tracking branch 'upstream/master' into meta_ptr
alevy Nov 13, 2024
670a5d0
kernel: handle_syscall: elaborate on NonNull change for CapabilityPtr
lschuermann Nov 13, 2024
3810ca8
kernel/capability_ptr: make new_with_metadata an unsafe method
lschuermann Nov 13, 2024
0709e6a
kernel/arch_helpers: remove 32bit infix from encode_syscall_return_tr…
lschuermann Nov 13, 2024
1ebf509
kernel: remove CapabilityPtr aliases for now
alevy Nov 14, 2024
d23676d
kernel: remove stale reference in upcall doc
alevy Nov 14, 2024
38a5188
kernel: remove unused syscall return variant
alevy Nov 14, 2024
08caaa5
kernel: rename capability_ptr constructor
alevy Nov 14, 2024
c6156c8
kernel: documentation nits
alevy Nov 14, 2024
a803e1e
kernel: remove SuccessUsize in favor of SuccessPtr
alevy Nov 14, 2024
096536c
kernel: fix import order nit
alevy Nov 14, 2024
3c1876b
kernel: memop: add provenance to memop returns
alevy Nov 14, 2024
37cb959
Merge remote-tracking branch 'upstream/master' into meta_ptr
lschuermann Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
kernel/syscall: split out encode_syscall_return, create TRD104 subset
Because all architecture crates depend on the kernel crate, we use it
not just for architecture-agnostic core kernel infrastructure, but
also architecture-specific code that happens to be shared between two
or more `arch` crates. Prior to this change, we conflated these
helpers with the core kernel infrastructure in `syscall.rs`.

With this change, we split out the 32-bit and TRD 104-specific
`encode_syscall_return` helper, shared between the 32-bit RISC-V and
Cortex-M architecture implementations, into its own dedicated module
under utilities.

We create a separate `SyscallReturn` subset for those return values as
specified in TRD 104, and create a function that translates between
these types. This allows architectures which use these functions to
guarantee that they are conformant to TRD 104 by first explicitly
converting into this type, and then encoding it into their stored
registers using the TRD 104 encoding helper.
  • Loading branch information
lschuermann committed Nov 12, 2024
commit a001b334cbdbce9ddb9e2b7e749c9e5ca3e30f31
10 changes: 9 additions & 1 deletion arch/cortex-m/src/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,15 @@ impl<A: CortexMVariant> kernel::syscall::UserspaceKernelBoundary for SysCall<A>
//
// Refer to
// https://doc.rust-lang.org/std/primitive.pointer.html#safety-13
return_value.encode_syscall_return_32bit_trd104(&mut *r0, &mut *r1, &mut *r2, &mut *r3);
kernel::utilities::arch_helpers::encode_syscall_return_32bit_trd104(
&kernel::utilities::arch_helpers::TRD104SyscallReturn::from_syscall_return(
return_value,
),
&mut *r0,
&mut *r1,
&mut *r2,
&mut *r3,
);

Ok(())
}
Expand Down
5 changes: 4 additions & 1 deletion arch/rv32i/src/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,10 @@ impl kernel::syscall::UserspaceKernelBoundary for SysCall {
let (a1slice, r) = r.split_at_mut(R_A2 - R_A1);
let (a2slice, a3slice) = r.split_at_mut(R_A3 - R_A2);

return_value.encode_syscall_return_32bit_trd104(
kernel::utilities::arch_helpers::encode_syscall_return_32bit_trd104(
&kernel::utilities::arch_helpers::TRD104SyscallReturn::from_syscall_return(
return_value,
),
&mut a0slice[0],
&mut a1slice[0],
&mut a2slice[0],
Expand Down
270 changes: 3 additions & 267 deletions kernel/src/syscall.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,22 +70,10 @@ use core::fmt::Write;

use crate::errorcode::ErrorCode;
use crate::process;
use crate::utilities::capability_ptr::{CapabilityPtr, CapabilityPtrPermissions};
use crate::utilities::capability_ptr::CapabilityPtr;

pub use crate::syscall_driver::{CommandReturn, SyscallDriver};

/// Helper function to split a [`u64`] into a higher and lower [`u32`].
///
/// Used in encoding 64-bit wide system call return values on 32-bit platforms.
#[inline]
fn u64_to_be_u32s(src: u64) -> (u32, u32) {
let src_bytes = src.to_be_bytes();
let src_msb = u32::from_be_bytes([src_bytes[0], src_bytes[1], src_bytes[2], src_bytes[3]]);
let src_lsb = u32::from_be_bytes([src_bytes[4], src_bytes[5], src_bytes[6], src_bytes[7]]);

(src_msb, src_lsb)
}

// ---------- SYSTEMCALL ARGUMENT DECODING ----------

/// Enumeration of the system call classes based on the identifiers specified in
Expand Down Expand Up @@ -381,58 +369,9 @@ impl Syscall {
}
}

// ---------- SYSCALL RETURN VALUE ENCODING ----------
// ---------- SYSCALL RETURN VALUES ----------

/// Enumeration of the system call return type variant identifiers described
/// in TRD104.
///
/// Each variant is associated with the respective variant identifier that would
/// be passed along with the return value to userspace.
#[repr(u32)]
#[derive(Copy, Clone, Debug)]
pub enum SyscallReturnVariant {
Failure = 0,
FailureU32 = 1,
FailureU32U32 = 2,
FailureU64 = 3,
FailurePtrUsize = 4,
FailurePtrPtr = 5,
Success = 128,
SuccessU32 = 129,
SuccessU32U32 = 130,
SuccessU64 = 131,
SuccessU32U32U32 = 132,
SuccessU32U64 = 133,
SuccessUsize = 134,
SuccessPtr = 135,
SuccessPtrUsize = 136,
SuccessPtrPtr = 137,
}

impl SyscallReturnVariant {
/// Maps newly introduced return variants (usize and ptr)
/// to old ones (u32) for backwards compatibility.
/// This should not be used for any newly designed interfaces,
/// and will eventually be deprecated once all interfaces are updated.
pub const fn into_compat_32bit_trd104(self) -> Self {
// We only need to be backwards compatible on 32-bit systems
let compat = core::mem::size_of::<usize>() == core::mem::size_of::<u32>();

if !compat {
return self;
}

match self {
// Map all usizes and ptrs to u32
Self::SuccessUsize | Self::SuccessPtr => Self::SuccessU32,
Self::SuccessPtrUsize | Self::SuccessPtrPtr => Self::SuccessU32U32,
Self::FailurePtrUsize | Self::FailurePtrPtr => Self::FailureU32U32,
x => x,
}
}
}

/// Enumeration of the possible system call return variants specified in TRD104.
/// Enumeration of the possible system call return variants.
///
/// This struct operates over primitive types such as integers of fixed length
/// and pointers. It is constructed by the scheduler and passed down to the
Expand Down Expand Up @@ -567,209 +506,6 @@ impl SyscallReturn {
SyscallReturn::SuccessUsize(_) => true,
}
}

/// Encode the system call return value into 4 registers, following the
/// encoding specified in TRD104. Architectures which do not follow TRD104
/// are free to define their own encoding.
pub fn encode_syscall_return_32bit_trd104(
&self,
a0: &mut u32,
a1: &mut u32,
a2: &mut u32,
a3: &mut u32,
) {
assert!(
core::mem::size_of::<CapabilityPtr>() == core::mem::size_of::<u32>()
&& core::mem::align_of::<u32>() >= align_of::<CapabilityPtr>(),
"encode_syscall_return used on a 64-bit platform or CHERI platform"
);

// SAFETY: if the two integers are the same size (and alignment permits) references
// to them can be safely transmuted.
// Ugly coercion could be avoided by first copying to the stack, then assigning with
// "as" in order to satisfy the compiler.
unsafe {
let a0 = &mut *(core::ptr::from_mut(a0).cast::<CapabilityPtr>());
let a1 = &mut *(core::ptr::from_mut(a1).cast::<CapabilityPtr>());
let a2 = &mut *(core::ptr::from_mut(a2).cast::<CapabilityPtr>());
let a3 = &mut *(core::ptr::from_mut(a3).cast::<CapabilityPtr>());
self.encode_syscall_return_usize_trd104_compat(a0, a1, a2, a3);
}
}

/// An extension of TRD104 that works for 32-bit and 64-bit platforms.
/// This implements TRD104 exactly on 32-bit platforms by mapping new codes intended for
/// 64-bit platforms to existing ones.
/// On 64-bit platforms, both 64-bit and usize values are passed as a single register,
/// Does not handle usize other than 4 and 8 bytes.
/// Pointers from allow'd buffers have permissions and length reattached matching
/// those that were checked at the syscall boundary.
fn encode_syscall_return_usize_trd104_compat(
&self,
a0: &mut CapabilityPtr,
a1: &mut CapabilityPtr,
a2: &mut CapabilityPtr,
a3: &mut CapabilityPtr,
) {
// On 32-bit CHERI, given that capabilities cannot be used as 64-bit integers, 64-bit
// integers will still be returned as two 32-bit values in different registers.
fn write_64(a: &mut CapabilityPtr, b: &mut CapabilityPtr, val: u64) {
let is_64_bit = core::mem::size_of::<usize>() == 8;
if !is_64_bit {
let (msb, lsb) = u64_to_be_u32s(val);
*a = (lsb as usize).into();
*b = (msb as usize).into();
} else {
*a = (val as usize).into();
}
}

match *self {
SyscallReturn::Failure(e) => {
*a0 = (SyscallReturnVariant::Failure as usize).into();
*a1 = (usize::from(e)).into();
}
SyscallReturn::FailureU32(e, data0) => {
*a0 = (SyscallReturnVariant::FailureU32 as usize).into();
*a1 = usize::from(e).into();
*a2 = (data0 as usize).into();
}
SyscallReturn::FailureU32U32(e, data0, data1) => {
*a0 = (SyscallReturnVariant::FailureU32U32 as usize).into();
*a1 = (usize::from(e)).into();
*a2 = (data0 as usize).into();
*a3 = (data1 as usize).into();
}
SyscallReturn::FailureU64(e, data0) => {
*a0 = (SyscallReturnVariant::FailureU64 as usize).into();
*a1 = (usize::from(e)).into();
write_64(a2, a3, data0)
}
SyscallReturn::Success => {
*a0 = (SyscallReturnVariant::Success as usize).into();
}
SyscallReturn::SuccessU32(data0) => {
*a0 = (SyscallReturnVariant::SuccessU32 as usize).into();
*a1 = (data0 as usize).into();
}
SyscallReturn::SuccessU32U32(data0, data1) => {
*a0 = (SyscallReturnVariant::SuccessU32U32 as usize).into();
*a1 = (data0 as usize).into();
*a2 = (data1 as usize).into();
}
SyscallReturn::SuccessU32U32U32(data0, data1, data2) => {
*a0 = (SyscallReturnVariant::SuccessU32U32U32 as usize).into();
*a1 = (data0 as usize).into();
*a2 = (data1 as usize).into();
*a3 = (data2 as usize).into();
}
SyscallReturn::SuccessU64(data0) => {
*a0 = (SyscallReturnVariant::SuccessU64 as usize).into();
write_64(a1, a2, data0);
}
SyscallReturn::SuccessU32U64(data0, data1) => {
*a0 = (SyscallReturnVariant::SuccessU32U64 as usize).into();
*a1 = (data0 as usize).into();
write_64(a2, a3, data1);
}
SyscallReturn::AllowReadWriteSuccess(ptr, len) => {
*a0 = (SyscallReturnVariant::SuccessPtrUsize.into_compat_32bit_trd104() as usize)
.into();
*a1 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::ReadWrite,
);
*a2 = len.into();
}
SyscallReturn::UserspaceReadableAllowSuccess(ptr, len) => {
*a0 = (SyscallReturnVariant::SuccessPtrUsize.into_compat_32bit_trd104() as usize)
.into();
*a1 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
);
*a2 = len.into();
}
SyscallReturn::AllowReadWriteFailure(err, ptr, len) => {
*a0 = (SyscallReturnVariant::FailurePtrUsize.into_compat_32bit_trd104() as usize)
.into();
*a1 = (usize::from(err)).into();
*a2 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::ReadWrite,
);
*a3 = len.into();
}
SyscallReturn::UserspaceReadableAllowFailure(err, ptr, len) => {
*a0 = (SyscallReturnVariant::FailurePtrUsize.into_compat_32bit_trd104() as usize)
.into();
*a1 = (usize::from(err)).into();
*a2 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
);
*a3 = len.into();
}
SyscallReturn::AllowReadOnlySuccess(ptr, len) => {
*a0 = (SyscallReturnVariant::SuccessPtrUsize.into_compat_32bit_trd104() as usize)
.into();
*a1 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
);
*a2 = len.into();
}
SyscallReturn::AllowReadOnlyFailure(err, ptr, len) => {
*a0 = (SyscallReturnVariant::FailurePtrUsize.into_compat_32bit_trd104() as usize)
.into();
*a1 = (usize::from(err)).into();
*a2 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
);
*a3 = len.into();
}
SyscallReturn::SubscribeSuccess(ptr, data) => {
*a0 = (SyscallReturnVariant::SuccessPtrPtr.into_compat_32bit_trd104() as usize)
.into();
*a1 = (ptr as usize).into();
*a2 = data.into();
}
SyscallReturn::SubscribeFailure(err, ptr, data) => {
*a0 = (SyscallReturnVariant::FailurePtrPtr.into_compat_32bit_trd104() as usize)
.into();
*a1 = (usize::from(err)).into();
*a2 = (ptr as usize).into();
*a3 = data.into();
}
SyscallReturn::SuccessPtr(ptr) => {
*a0 = (SyscallReturnVariant::SuccessPtr.into_compat_32bit_trd104() as usize).into();
*a1 = ptr;
}
SyscallReturn::YieldWaitFor(data0, data1, data2) => {
*a0 = data0.into();
*a1 = data1.into();
*a2 = data2.into();
}
SyscallReturn::SuccessUsize(data) => {
*a0 =
(SyscallReturnVariant::SuccessUsize.into_compat_32bit_trd104() as usize).into();
*a1 = data.into();
}
}
}
}

// ---------- USERSPACE KERNEL BOUNDARY ----------
Expand Down
Loading
Loading