Skip to content

Commit

Permalink
kernel/capability_ptr: make new_with_metadata an unsafe method
Browse files Browse the repository at this point in the history
  • Loading branch information
lschuermann committed Nov 13, 2024
1 parent 670a5d0 commit 3810ca8
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 49 deletions.
28 changes: 16 additions & 12 deletions kernel/src/process_standard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -862,12 +862,14 @@ impl<C: Chip, D: 'static + ProcessStandardDebug> Process for ProcessStandard<'_,
self.chip.mpu().configure_mpu(config);

let base = self.mem_start() as usize;
let break_result = CapabilityPtr::new_with_metadata(
old_break as *const (),
base,
(new_break as usize) - base,
CapabilityPtrPermissions::ReadWrite,
);
let break_result = unsafe {
CapabilityPtr::new_with_metadata(
old_break as *const (),
base,
(new_break as usize) - base,
CapabilityPtrPermissions::ReadWrite,
)
};

Ok(break_result)
}
Expand Down Expand Up @@ -2147,12 +2149,14 @@ impl<C: 'static + Chip, D: 'static + ProcessStandardDebug> ProcessStandard<'_, C
// We need to construct a capability with sufficient authority to cover all of a user's
// code, with permissions to execute it. The entirety of flash is sufficient.

let init_fn = CapabilityPtr::new_with_metadata(
init_addr as *const (),
flash_start as usize,
(self.flash_end() as usize) - (flash_start as usize),
CapabilityPtrPermissions::Execute,
);
let init_fn = unsafe {
CapabilityPtr::new_with_metadata(
init_addr as *const (),
flash_start as usize,
(self.flash_end() as usize) - (flash_start as usize),
CapabilityPtrPermissions::Execute,
)
};

self.enqueue_task(Task::FunctionCall(FunctionCall {
source: FunctionCallSource::Kernel,
Expand Down
84 changes: 48 additions & 36 deletions kernel/src/utilities/arch_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,65 +348,77 @@ pub fn encode_syscall_return_usize(
}
SyscallReturn::AllowReadWriteSuccess(ptr, len) => {
*a0 = (SyscallReturnVariant::SuccessPtrUsize as usize).into();
*a1 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::ReadWrite,
);
*a1 = unsafe {
CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::ReadWrite,
)
};
*a2 = len.into();
}
SyscallReturn::UserspaceReadableAllowSuccess(ptr, len) => {
*a0 = (SyscallReturnVariant::SuccessPtrUsize as usize).into();
*a1 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
);
*a1 = unsafe {
CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
)
};
*a2 = len.into();
}
SyscallReturn::AllowReadWriteFailure(err, ptr, len) => {
*a0 = (SyscallReturnVariant::FailurePtrUsize as usize).into();
*a1 = (usize::from(err)).into();
*a2 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::ReadWrite,
);
*a2 = unsafe {
CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::ReadWrite,
)
};
*a3 = len.into();
}
SyscallReturn::UserspaceReadableAllowFailure(err, ptr, len) => {
*a0 = (SyscallReturnVariant::FailurePtrUsize as usize).into();
*a1 = (usize::from(err)).into();
*a2 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
);
*a2 = unsafe {
CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
)
};
*a3 = len.into();
}
SyscallReturn::AllowReadOnlySuccess(ptr, len) => {
*a0 = (SyscallReturnVariant::SuccessPtrUsize as usize).into();
*a1 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
);
*a1 = unsafe {
CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
)
};
*a2 = len.into();
}
SyscallReturn::AllowReadOnlyFailure(err, ptr, len) => {
*a0 = (SyscallReturnVariant::FailurePtrUsize as usize).into();
*a1 = (usize::from(err)).into();
*a2 = CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
);
*a2 = unsafe {
CapabilityPtr::new_with_metadata(
ptr as *const (),
ptr as usize,
len,
CapabilityPtrPermissions::Read,
)
};
*a3 = len.into();
}
SyscallReturn::SubscribeSuccess(ptr, data) => {
Expand Down
15 changes: 14 additions & 1 deletion kernel/src/utilities/capability_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,23 @@ impl CapabilityPtr {

/// Construct a [`CapabilityPtr`] from a raw pointer, with authority ranging over
/// [`base`, `base + length`) and permissions `perms`.
///
/// Provenance note: may derive from a pointer other than the input to provide something with
/// valid provenance to justify the other arguments.
///
/// ## Safety
///
/// Constructing a [`CapabilityPtr`] with metadata may convey authority to
/// dereference this pointer, such as on userspace. When these pointers
/// serve as the only memory isolation primitive in the system, this method
/// can thus break Tock's isolation model. As semi-trusted kernel code can
/// name this type and method, it is thus marked as `unsafe`.
///
/// TODO: Once Tock supports hardware that uses the [`CapabilityPtr`]'s
/// metdata to convey authority, this comment should incorporate the exact
/// safety conditions of this function.
#[inline]
pub fn new_with_metadata(
pub unsafe fn new_with_metadata(
ptr: *const (),
_base: usize,
_length: usize,
Expand Down

0 comments on commit 3810ca8

Please sign in to comment.