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 *