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

cleaner kernel-user exchange area manipulation #102

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion uapi/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ test(
'--test-threads=1',
],
is_parallel: false,
should_fail: true,
suite: 'uapi',
)

Expand Down
10 changes: 0 additions & 10 deletions uapi/src/arch/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@

use crate::systypes::*;

#[cfg(test)]
use sysgate::gate;

pub fn debug_syscall_handler(syscall_number: u8, args: &[u32]) -> u32 {
#[cfg(not(test))]
match Syscall::try_from(syscall_number) {
Ok(sysc) => {
#[cfg(feature = "std")]
Expand All @@ -22,12 +18,6 @@ pub fn debug_syscall_handler(syscall_number: u8, args: &[u32]) -> u32 {
Status::Invalid as u32
}
}

#[cfg(test)]
match gate::syscall_dispatch(syscall_number, args) {
Ok(_) => Status::Ok as u32,
Err(x) => x as u32,
}
}

macro_rules! syscall {
Expand Down
159 changes: 159 additions & 0 deletions uapi/src/exchange.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// SPDX-FileCopyrightText: 2023 Ledger SAS
// SPDX-License-Identifier: Apache-2.0

use core::ptr::{addr_of_mut,addr_of};
use crate::systypes::shm::ShmInfo;
use crate::systypes::Status;

const EXCHANGE_AREA_LEN: usize = 128; // TODO: replace by CONFIG-defined value


/// The effective kernelspace/userspace exchange zone, set in a dedicated section
///
#[unsafe(link_section = ".svcexchange")]
static mut EXCHANGE_AREA: [u8; EXCHANGE_AREA_LEN] = [0u8; EXCHANGE_AREA_LEN];

/// public trait of kernel-user exchangeable objects
///
/// This trait is public at the crate-internal level in order to support
/// ffi_c copy_to_user/copy_from_user implementation.
/// Although, this very module is kept private, so that the crate external
/// API do not deliver such a trait specification.
/// This allows to ensure that only sentry-uapi local types are exchangeable
/// with the Sentry kernel.
pub trait SentryExchangeable {
fn to_kernel(&self) -> Result<Status,Status>;
fn from_kernel(&mut self) -> Result<Status, Status>;
}


/// SentryExchangeable trait implementation for ShmInfo.
/// Shminfo is a typical structure which is returned by the kernel to the
/// userspace in order to delivers various SHM-related information to a given
/// task that is using the corresponding SHM.
///
/// In test mode only, this structure can be written back to the Exchange Area.
/// In production mode, the application can't write such a content to the exchange
/// as the kernel as strictly no use of it.
///
impl SentryExchangeable for crate::systypes::shm::ShmInfo {
#[allow(static_mut_refs)]
fn from_kernel(&mut self) -> Result<Status, Status> {
unsafe {
core::ptr::copy_nonoverlapping(
EXCHANGE_AREA.as_ptr(),
addr_of_mut!(*self) as *mut u8,
core::mem::size_of::<ShmInfo>().min(EXCHANGE_AREA_LEN),
);
}
Ok(Status::Ok)
}

#[cfg(test)]
#[allow(static_mut_refs)]
fn to_kernel(&self) -> Result<Status,Status> {
unsafe {
core::ptr::copy_nonoverlapping(
addr_of!(*self) as *const u8,
EXCHANGE_AREA.as_mut_ptr(),
core::mem::size_of::<ShmInfo>().min(EXCHANGE_AREA_LEN),
);
}
Ok(Status::Ok)
}

#[cfg(not(test))]
#[allow(static_mut_refs)]
fn to_kernel(&self) -> Result<Status,Status> {
Err(Status::Invalid)
}
}

impl SentryExchangeable for *mut u8 {
#[allow(static_mut_refs)]
fn from_kernel(&mut self) -> Result<Status, Status> {
unsafe {
core::ptr::copy_nonoverlapping(
EXCHANGE_AREA.as_ptr(),
addr_of_mut!(*self) as *mut u8,
core::mem::size_of::<ShmInfo>().min(EXCHANGE_AREA_LEN),
);
}
Ok(Status::Ok)
}

#[allow(static_mut_refs)]
fn to_kernel(&self) -> Result<Status,Status> {
unsafe {
core::ptr::copy_nonoverlapping(
addr_of!(*self) as *const u8,
EXCHANGE_AREA.as_mut_ptr(),
core::mem::size_of::<ShmInfo>().min(EXCHANGE_AREA_LEN),
);
}
Ok(Status::Ok)
}
}

impl SentryExchangeable for *const u8 {
#[allow(static_mut_refs)]
fn from_kernel(&mut self) -> Result<Status, Status> {
Err(Status::Invalid)
}

#[allow(static_mut_refs)]
fn to_kernel(&self) -> Result<Status,Status> {
unsafe {
core::ptr::copy_nonoverlapping(
addr_of!(*self) as *const u8,
EXCHANGE_AREA.as_mut_ptr(),
core::mem::size_of::<ShmInfo>().min(EXCHANGE_AREA_LEN),
);
}
Ok(Status::Ok)
}
}


pub const fn length() -> usize {
EXCHANGE_AREA_LEN
}

pub fn copy_to_kernel<T>(from : &T) -> Result<Status,Status>
where T:SentryExchangeable
{
from.to_kernel()
}

pub fn copy_from_kernel<T>(to: &mut T) -> Result<Status,Status>
where T:SentryExchangeable
{
to.from_kernel()
}


#[cfg(test)]
mod tests {
use super::*;

#[test]
fn back_to_back_shminfo() {
let src = ShmInfo {
handle: 2,
label: 42,
base: 0x123456,
len: 64,
perms: 0x1,
};
let mut dst = ShmInfo {
handle: 0,
label: 0,
base: 0,
len: 0,
perms: 0,
};
let _ = src.to_kernel();
let _ = dst.from_kernel();
assert_eq!(src, dst);
}
}
62 changes: 42 additions & 20 deletions uapi/src/ffi_c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
// SPDX-License-Identifier: Apache-2.0

use crate::systypes::*;
use crate::exchange;

#[no_mangle]
pub extern "C" fn __sys_get_process_handle(process: ProcessLabel) -> Status {
pub extern "C" fn __sys_get_process_handle(process: TaskLabel) -> Status {
crate::syscall::get_process_handle(process)
}

Expand Down Expand Up @@ -34,37 +35,41 @@ pub extern "C" fn __sys_sleep(duration_ms: SleepDuration, mode: SleepMode) -> St
}

#[no_mangle]
pub extern "C" fn __sys_start(process: ProcessLabel) -> Status {
pub extern "C" fn __sys_start(process: TaskLabel) -> Status {
crate::syscall::start(process)
}

#[no_mangle]
pub extern "C" fn __sys_map_dev(dev: devh_t) -> Status {
crate::syscall::map_dev(dev as devh_t)
pub extern "C" fn __sys_map_dev(dev: DeviceHandle) -> Status {
crate::syscall::map_dev(dev as DeviceHandle)
}

#[no_mangle]
pub extern "C" fn __sys_map_shm(shm: shmh_t) -> Status {
crate::syscall::map_shm(shm as shmh_t)
pub extern "C" fn __sys_map_shm(shm: ShmHandle) -> Status {
crate::syscall::map_shm(shm as ShmHandle)
}

#[no_mangle]
pub extern "C" fn __sys_unmap_dev(dev: devh_t) -> Status {
crate::syscall::unmap_dev(dev as devh_t)
pub extern "C" fn __sys_unmap_dev(dev: DeviceHandle) -> Status {
crate::syscall::unmap_dev(dev as DeviceHandle)
}

#[no_mangle]
pub extern "C" fn __sys_unmap_shm(shm: shmh_t) -> Status {
crate::syscall::unmap_shm(shm as shmh_t)
pub extern "C" fn __sys_unmap_shm(shm: ShmHandle) -> Status {
crate::syscall::unmap_shm(shm as ShmHandle)
}

#[no_mangle]
pub extern "C" fn __sys_shm_set_credential(shm: shmh_t, id: taskh_t, shm_perm: u32) -> Status {
pub extern "C" fn __sys_shm_set_credential(
shm: ShmHandle,
id: TaskHandle,
shm_perm: u32,
) -> Status {
crate::syscall::shm_set_credential(shm, id, shm_perm)
}

#[no_mangle]
pub extern "C" fn __sys_send_ipc(target: taskh_t, length: u8) -> Status {
pub extern "C" fn __sys_send_ipc(target: TaskHandle, length: u8) -> Status {
crate::syscall::send_ipc(target, length)
}

Expand Down Expand Up @@ -154,41 +159,58 @@ pub extern "C" fn __sys_pm_set_clock(clk_reg: u32, clkmsk: u32, val: u32) -> Sta
}

#[no_mangle]
pub extern "C" fn __sys_dma_start_stream(dmah: dmah_t) -> Status {
pub extern "C" fn __sys_dma_start_stream(dmah: StreamHandle) -> Status {
crate::syscall::dma_start_stream(dmah)
}

#[no_mangle]
pub extern "C" fn __sys_dma_suspend_stream(dmah: dmah_t) -> Status {
pub extern "C" fn __sys_dma_suspend_stream(dmah: StreamHandle) -> Status {
crate::syscall::dma_suspend_stream(dmah)
}

#[no_mangle]
pub extern "C" fn __sys_dma_get_stream_status(dmah: dmah_t) -> Status {
pub extern "C" fn __sys_dma_get_stream_status(dmah: StreamHandle) -> Status {
crate::syscall::dma_get_stream_status(dmah)
}

#[no_mangle]
pub extern "C" fn __sys_shm_get_infos(shm: shmh_t) -> Status {
pub extern "C" fn __sys_shm_get_infos(shm: ShmHandle) -> Status {
crate::syscall::shm_get_infos(shm)
}

#[no_mangle]
pub extern "C" fn __sys_dma_assign_stream(dmah: dmah_t) -> Status {
pub extern "C" fn __sys_dma_assign_stream(dmah: StreamHandle) -> Status {
crate::syscall::dma_assign_stream(dmah)
}

#[no_mangle]
pub extern "C" fn __sys_dma_unassign_stream(dmah: dmah_t) -> Status {
pub extern "C" fn __sys_dma_unassign_stream(dmah: StreamHandle) -> Status {
crate::syscall::dma_unassign_stream(dmah)
}

#[no_mangle]
pub extern "C" fn __sys_dma_get_stream_info(dmah: dmah_t) -> Status {
pub extern "C" fn __sys_dma_get_stream_info(dmah: StreamHandle) -> Status {
crate::syscall::dma_get_stream_info(dmah)
}

#[no_mangle]
pub extern "C" fn __sys_dma_resume_stream(dmah: dmah_t) -> Status {
pub extern "C" fn __sys_dma_resume_stream(dmah: StreamHandle) -> Status {
crate::syscall::dma_resume_stream(dmah)
}

#[no_mangle]
pub extern "C" fn copy_from_user(from: *const u8, _length: usize) -> Status {
match exchange::copy_to_kernel(&from) {
Ok(_) => Status::Ok,
Err(err) => err,
}
}

#[no_mangle]
pub extern "C" fn copy_to_user(mut to: *mut u8, _length: usize) -> Status
{
match exchange::copy_from_kernel(&mut to) {
Ok(_) => Status::Ok,
Err(err) => err
}
}
29 changes: 20 additions & 9 deletions uapi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@
//!
//! -**Sentry syscalls** — Syscall are defined in a two layers way. The bare syscalls
//! are implemented in the [`mod@syscall`] module, while the upper, easy interface
//! is implemented in the [`mod@uapi`] module. Unless specific needs, there is no
//! usual case where the [`mod@syscall`] module interface needs to be acceded directly.
//! is out of the scope of this very crate, and written in the shield crate instead.

#![cfg_attr(not(feature = "std"), no_std)]

Expand All @@ -34,19 +33,19 @@ mod arch;
/// This allows a full Rust usage without extern C and thus unsafe calls when
/// writing Rust application with cargo
/// interface is used. Sentry kernel interactions should be, instead, made with
/// the [`mod@uapi`] upper interface.
/// a upper interface such as shield.
///
pub mod ffi_c;

/// Sentry SVC_EXCHANGE area manipulation primitives
/// Sentry kernel exchange area manipulation primitives
///
/// # Usage
///
/// This module should not be used directly unless the [`mod@syscall`] module
/// interface is used. Sentry kernel interactions should be, instead, made with
/// the [`mod@uapi`] upper interface.
/// an upper interface.
///
/// As the SVC_EXCHANGE area is a special userspace/kernelspace fixed size area
/// As the exchange area is a special userspace/kernelspace fixed size area
/// made in order to exchange data between userspace and kernelspace without
/// manipulating any pointer, this space has a particular meaning and usage, holding
/// any type of content as a 'retention area' before and after system calls.
Expand All @@ -63,7 +62,7 @@ pub mod ffi_c;
/// if unsafe is used, there is no UB risk when manipulating the exchange area
/// based on the Operating System architecture.
///
pub mod svc_exchange;
mod exchange;

/// Sentry kernel low level syscall implementation
///
Expand All @@ -73,8 +72,8 @@ pub mod svc_exchange;
/// architecture supervisor access opcode, in interaction with the corresponding
/// arch backend.
///
/// There is no abstraction at this module's level and should not be used directly.
/// The [`mod@uapi`] module should be used instead.
/// There is no abstraction at this module's level and should not be used directly,
/// but instead with an upper interface such as shield
///
/// > **NOTE**: This module may not be kept public forever
///
Expand Down Expand Up @@ -102,5 +101,17 @@ pub mod syscall;
///
pub mod systypes;

/// Copy a given generic type from the kernel exchange zone to the given mutable reference
pub use self::exchange::copy_from_kernel as copy_from_kernel;

/// Copy a given generic type to the kernel exchange zone from the given eference
pub use self::exchange::copy_to_kernel as copy_to_kernel;

/// Sentry exchangeable opaque trait, only defined for systypes defined types
///
/// This trait is declared in order to allow the attribute checking but is not
/// exported as no upper layer type needs to implement it
pub use self::exchange::SentryExchangeable as SentryExchangeable;

#[cfg(not(feature = "std"))]
mod panic;
Loading
Loading