From 74f114caefd997eb9a97c7f9531820fb00ddbb08 Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Wed, 12 Dec 2018 13:58:30 -0800 Subject: [PATCH] userspace: easy checking for specific driver In general driver system calls are implemented at a subsystem layer. However, some drivers may have capabilities specific to the hardware not covered by the subsystem API. Such drivers may want to define their own system calls. This macro makes it simple to validate in the driver-specific system call handlers that not only does the untrusted device pointer correspond to the expected subsystem, initialization state, and caller permissions, but also that the device object is an instance of a specific driver (and not just any driver in that subsystem). Signed-off-by: Andrew Boie --- doc/kernel/usermode/syscalls.rst | 8 ++++++++ kernel/include/syscall_handler.h | 27 +++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/doc/kernel/usermode/syscalls.rst b/doc/kernel/usermode/syscalls.rst index 6a3c2c033b4..9d7ef4d49c7 100644 --- a/doc/kernel/usermode/syscalls.rst +++ b/doc/kernel/usermode/syscalls.rst @@ -299,6 +299,14 @@ Several macros exist to validate arguments: instance, to validate the GPIO driver, one could use the :c:macro:`Z_SYSCALL_DRIVER_GPIO()` macro. +* :c:macro:`Z_SYSCALL_SPECIFIC_DRIVER()` is a runtime check to verify that + a provided pointer is a valid instance of a specific device driver, that + the calling thread has permissions on it, and that the driver has been + initialized. It does this by checking the init function pointer that + is stored within the driver instance and ensuring that it matches the + provided value, which should be the address of the specific driver's + init function. + If any check fails, the macros will return a nonzero value. The macro :c:macro:`Z_OOPS()` can be used to induce a kernel oops which will kill the calling thread. This is done instead of returning some error condition to diff --git a/kernel/include/syscall_handler.h b/kernel/include/syscall_handler.h index 0d417b5857c..a26e1442745 100644 --- a/kernel/include/syscall_handler.h +++ b/kernel/include/syscall_handler.h @@ -434,6 +434,33 @@ static inline int _obj_validation_check(struct _k_object *ko, # op, __device__); \ }) +/** + * @brief Runtime check that device object is of a specific driver type + * + * Checks that the driver object passed in is initialized, the caller has + * correct permissions, and that it belongs to the specified driver + * subsystems. Additionally, all devices store a function pointer to the + * driver's init function. If this doesn't match the value provided, the + * check will fail. + * + * This provides an easy way to determine if a device object not only + * belongs to a particular subsystem, but is of a specific device driver + * implementation. Useful for defining out-of-subsystem system calls + * which are implemented for only one driver. + * + * @param _device Untrusted device pointer + * @param _dtype Expected kernel object type for the provided device pointer + * @param _init_fn Expected init function memory address + * @return 0 on success, nonzero on failure + */ +#define Z_SYSCALL_SPECIFIC_DRIVER(_device, _dtype, _init_fn) \ + ({ \ + struct device *_dev = (struct device *)_device; \ + Z_SYSCALL_OBJ(_dev, _dtype) || \ + Z_SYSCALL_VERIFY_MSG(_dev->config->init == _init_fn, \ + "init function mismatch"); \ + }) + /** * @brief Runtime check kernel object pointer for non-init functions *