userspace: flesh out internal syscall interface
* Instead of a common system call entry function, we instead create a table mapping system call ids to handler skeleton functions which are invoked directly by the architecture code which receives the system call. * system call handler prototype specified. All but the most trivial system calls will implement one of these. They validate all the arguments, including verifying kernel/device object pointers, ensuring that the calling thread has appropriate access to any memory buffers passed in, and performing other parameter checks that the base system call implementation does not check, or only checks with __ASSERT(). It's only possible to install a system call implementation directly inside this table if the implementation has a return value and requires no validation of any of its arguments. A sample handler implementation for k_mutex_unlock() might look like: u32_t _syscall_k_mutex_unlock(u32_t mutex_arg, u32_t arg2, u32_t arg3, u32_t arg4, u32_t arg5, void *ssf) { struct k_mutex *mutex = (struct k_mutex *)mutex_arg; _SYSCALL_ARG1; _SYSCALL_IS_OBJ(mutex, K_OBJ_MUTEX, 0, ssf); _SYSCALL_VERIFY(mutex->lock_count > 0, ssf); _SYSCALL_VERIFY(mutex->owner == _current, ssf); k_mutex_unlock(mutex); return 0; } * the x86 port modified to work with the system call table instead of calling a common handler function. fixed an issue where registers being changed could confuse the compiler has been fixed; all registers, even ones used for parameters, must be preserved across the system call. * a new arch API for producing a kernel oops when validating system call arguments added. The debug information reported will be from the system call site and not inside the handler function. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
2541f8788e
commit
a23c245a9a
6 changed files with 239 additions and 27 deletions
111
include/syscall.h
Normal file
111
include/syscall.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (c) 2017, Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache 2.0
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _ZEPHYR_SYSCALL_H_
|
||||
#define _ZEPHYR_SYSCALL_H_
|
||||
|
||||
/* Fixed system call IDs. We use #defines instead of enumeration so that if
|
||||
* system calls are retired it does not shift the IDs of other system calls.
|
||||
*/
|
||||
#define K_SYSCALL_BAD 0
|
||||
|
||||
#define K_SYSCALL_LIMIT 1
|
||||
|
||||
#ifndef _ASMLANGUAGE
|
||||
#include <misc/printk.h>
|
||||
|
||||
/**
|
||||
* @typedef _k_syscall_handler_t
|
||||
* @brief System call handler function type
|
||||
*
|
||||
* These are kernel-side skeleton functions for system calls. They are
|
||||
* necessary to sanitize the arguments passed into the system call:
|
||||
*
|
||||
* - Any kernel object or device pointers are validated with _SYSCALL_IS_OBJ()
|
||||
* - Any memory buffers passed in are checked to ensure that the calling thread
|
||||
* actually has access to them
|
||||
* - Many kernel calls do no sanity checking of parameters other than
|
||||
* assertions. The handler must check all of these conditions using
|
||||
* _SYSCALL_ASSERT()
|
||||
* - If the system call has more then 5 arguments, then arg5 will be a pointer
|
||||
* to some struct containing arguments 5+. The struct itself needs to be
|
||||
* validated like any other buffer passed in from userspace, and its members
|
||||
* individually validated (if necessary) and then passed to the real
|
||||
* implementation like normal arguments
|
||||
*
|
||||
* Even if the system call implementation has no return value, these always
|
||||
* return something, even 0, to prevent register leakage to userspace.
|
||||
*
|
||||
* Once everything has been validated, the real implementation will be executed.
|
||||
*
|
||||
* @param arg1 system call argument 1
|
||||
* @param arg2 system call argument 2
|
||||
* @param arg3 system call argument 3
|
||||
* @param arg4 system call argument 4
|
||||
* @param arg5 system call argument 5
|
||||
* @param ssf System call stack frame pointer. Used to generate kernel oops
|
||||
* via _arch_syscall_oops_at(). Contents are arch-specific.
|
||||
* @return system call return value, or 0 if the system call implementation
|
||||
* return void
|
||||
*
|
||||
*/
|
||||
typedef u32_t (*_k_syscall_handler_t)(u32_t arg1, u32_t arg2, u32_t arg3,
|
||||
u32_t arg4, u32_t arg5, void *ssf);
|
||||
|
||||
|
||||
extern const _k_syscall_handler_t _k_syscall_table[K_SYSCALL_LIMIT];
|
||||
|
||||
|
||||
/**
|
||||
* @brief Runtime expression check for system call arguments
|
||||
*
|
||||
* Used in handler functions to perform various runtime checks on arguments,
|
||||
* and generate a kernel oops if anything is not expected
|
||||
*
|
||||
* @param expr Boolean expression to verify, a false result will trigger an
|
||||
* oops
|
||||
* @param ssf Syscall stack frame argument passed to the handler function
|
||||
*/
|
||||
#define _SYSCALL_VERIFY(expr, ssf) \
|
||||
do { \
|
||||
if (!(expr)) { \
|
||||
printk("FATAL: syscall failed check: " #expr "\n"); \
|
||||
_arch_syscall_oops(ssf); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* @brief Runtime check that a pointer is a kernel object of expected type
|
||||
*
|
||||
* Passes along arguments to _k_object_validate() and triggers a kernel oops
|
||||
* if the object wasn't valid or had incorrect permissions.
|
||||
*
|
||||
* @param ptr Untrusted kernel object pointer
|
||||
* @param type Expected kernel object type
|
||||
* @param init Whether this is an init function handler
|
||||
* @param ssf Syscall stack frame argument passed to the handler function
|
||||
*/
|
||||
#define _SYSCALL_IS_OBJ(ptr, type, init, ssf) \
|
||||
_SYSCALL_VERIFY(!_k_object_validate((void *)ptr, type, init), ssf)
|
||||
|
||||
/* Convenience macros for handler implementations */
|
||||
#define _SYSCALL_ARG0 ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); \
|
||||
ARG_UNUSED(arg4); ARH_UNUSED(arg5)
|
||||
|
||||
#define _SYSCALL_ARG1 ARG_UNUSED(arg2); ARG_UNUSED(arg3); ARG_UNUSED(arg4); \
|
||||
ARG_UNUSED(arg5)
|
||||
|
||||
#define _SYSCALL_ARG2 ARG_UNUSED(arg3); ARG_UNUSED(arg4); ARG_UNUSED(arg5)
|
||||
|
||||
#define _SYSCALL_ARG3 ARG_UNUSED(arg4); ARG_UNUSED(arg5)
|
||||
|
||||
#define _SYSCALL_ARG4 ARG_UNUSED(arg5)
|
||||
|
||||
|
||||
#endif /* _ASMLANGUAGE */
|
||||
|
||||
#endif /* _ZEPHYR_SYSCALL_H_ */
|
Loading…
Add table
Add a link
Reference in a new issue