|
PebbleOS
|
Calls from unprivileged threads into privileged code. More...
Macros | |
| #define | PBL_SYSCALL_COPY_MAX 128 |
| Largest argument PBL_SYSCALL() copies onto the syscall stack. | |
| #define | PBL_SYSCALL(ret, name, ...) PRV_SC_DEFINE(, return, ret, name, __VA_ARGS__) |
| Define a syscall whose arguments are checked from their declared kinds. | |
| #define | PBL_SYSCALL_NORETURN(name, ...) PRV_SC_DEFINE([[noreturn]], , void, name, __VA_ARGS__) |
| As PBL_SYSCALL(), for a syscall that never returns. | |
Functions | |
| void | pbl_syscall_fail (void) |
| Kill the thread whose syscall is in progress. | |
| void | pbl_syscall_verify_user (const void *buf, size_t num_bytes) |
| Kill the caller unless a range is its memory. | |
| bool | pbl_user_access_ok (const void *buf, size_t num_bytes) |
| Check that the caller of the syscall in progress may access a range. | |
| int | pbl_user_copy_from (void *dst, const void *src, size_t num_bytes) |
| Copy from the caller's memory. | |
| int | pbl_user_copy_to (void *dst, const void *src, size_t num_bytes) |
| Copy to the caller's memory. | |
| int | pbl_user_strnlen (const char *str, size_t max) |
| Measure a string in the caller's memory. | |
| static bool | pbl_is_user_context (void) |
| Check whether the CPU runs unprivileged code. | |
| void | pbl_user_mode_enter (void) |
| Drop the calling thread to unprivileged mode for good. | |
| void | pbl_user_call (void(*fn)(void *), void *ctx) |
| Call a function unprivileged from privileged thread mode. | |
| void | pbl_kernel_syscall_exit (void) |
| Called on the way out of every syscall made from unprivileged code. | |
| void | pbl_kernel_syscall_fault (uintptr_t lr) |
| Kill the thread whose syscall failed. | |
Calls from unprivileged threads into privileged code.
A syscall is defined with PBL_SYSCALL(). Its stub raises privilege, checks the arguments against the kinds they are declared with, runs the body and drops privilege again on return. Only stubs linked between __syscall_text_start__ and __syscall_text_end__ may raise privilege. A thread created with a syscall stack runs the bodies there instead of on its own stack.
Pointers from the caller are only accepted within the thread's user memory (see pbl_thread_attr::user_start), above the stack pointer it made the syscall from.
| #define PBL_SYSCALL | ( | ret, | |
| name, | |||
| ... | |||
| ) | PRV_SC_DEFINE(, return, ret, name, __VA_ARGS__) |
Define a syscall whose arguments are checked from their declared kinds.
Each argument is a tuple (KIND, type, name[, extra]):
An unprivileged caller passing an argument that fails its check is killed. Privileged callers skip all checks. The body follows the macro, like a function body, and also gets bool from_user, true for a checked call from unprivileged code.
| ret | Return type. |
| name | Syscall name. |
| #define PBL_SYSCALL_COPY_MAX 128 |
Largest argument PBL_SYSCALL() copies onto the syscall stack.
| #define PBL_SYSCALL_NORETURN | ( | name, | |
| ... | |||
| ) | PRV_SC_DEFINE([[noreturn]], , void, name, __VA_ARGS__) |
As PBL_SYSCALL(), for a syscall that never returns.
|
inlinestatic |
Check whether the CPU runs unprivileged code.
CONFIG_USERSPACE. | void pbl_kernel_syscall_exit | ( | void | ) |
Called on the way out of every syscall made from unprivileged code.
Implemented by the application. Runs privileged, on the syscall's stack, just before privilege is dropped; it may block, e.g. to hold a thread that is being killed.
| void pbl_kernel_syscall_fault | ( | uintptr_t | lr | ) |
Kill the thread whose syscall failed.
Implemented by the application; called by pbl_syscall_fail().
| lr | Return address of the failed check, for the crash report. |
| void pbl_syscall_fail | ( | void | ) |
Kill the thread whose syscall is in progress.
For a syscall handed bad arguments. Calls pbl_kernel_syscall_fault().
| void pbl_syscall_verify_user | ( | const void * | buf, |
| size_t | num_bytes | ||
| ) |
Kill the caller unless a range is its memory.
| buf | Start of the range. |
| num_bytes | Length of the range. |
| bool pbl_user_access_ok | ( | const void * | buf, |
| size_t | num_bytes | ||
| ) |
Check that the caller of the syscall in progress may access a range.
| buf | Start of the range. |
| num_bytes | Length of the range. |
buf, buf + num_bytes) is the caller's memory. | void pbl_user_call | ( | void(*)(void *) | fn, |
| void * | ctx | ||
| ) |
Call a function unprivileged from privileged thread mode.
For untrusted callbacks: memory or peripheral access the thread is not allowed inside fn faults the MPU instead of silently succeeding. The caller is privileged again when this returns.
| fn | Function to call. |
| ctx | Argument passed to fn. |
| int pbl_user_copy_from | ( | void * | dst, |
| const void * | src, | ||
| size_t | num_bytes | ||
| ) |
Copy from the caller's memory.
| dst | Kernel destination. |
| src | Source in the caller's memory. |
| num_bytes | Bytes to copy. |
src is not the caller's memory. | int pbl_user_copy_to | ( | void * | dst, |
| const void * | src, | ||
| size_t | num_bytes | ||
| ) |
Copy to the caller's memory.
| dst | Destination in the caller's memory. |
| src | Kernel source. |
| num_bytes | Bytes to copy. |
dst is not the caller's memory. | void pbl_user_mode_enter | ( | void | ) |
Drop the calling thread to unprivileged mode for good.
From then on it reaches privileged code only through syscalls.
| int pbl_user_strnlen | ( | const char * | str, |
| size_t | max | ||
| ) |
Measure a string in the caller's memory.
| str | String. |
| max | Longest length accepted. |
str, or -EFAULT if it is longer than max or does not end within the caller's memory.