Skip to content

Commit 74f114c

Browse files
Andrew Boienashif
authored andcommitted
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 <andrew.p.boie@intel.com>
1 parent a4605eb commit 74f114c

File tree

2 files changed

+35
-0
lines changed

2 files changed

+35
-0
lines changed

doc/kernel/usermode/syscalls.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,14 @@ Several macros exist to validate arguments:
299299
instance, to validate the GPIO driver, one could use the
300300
:c:macro:`Z_SYSCALL_DRIVER_GPIO()` macro.
301301

302+
* :c:macro:`Z_SYSCALL_SPECIFIC_DRIVER()` is a runtime check to verify that
303+
a provided pointer is a valid instance of a specific device driver, that
304+
the calling thread has permissions on it, and that the driver has been
305+
initialized. It does this by checking the init function pointer that
306+
is stored within the driver instance and ensuring that it matches the
307+
provided value, which should be the address of the specific driver's
308+
init function.
309+
302310
If any check fails, the macros will return a nonzero value. The macro
303311
:c:macro:`Z_OOPS()` can be used to induce a kernel oops which will kill the
304312
calling thread. This is done instead of returning some error condition to

kernel/include/syscall_handler.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,33 @@ static inline int _obj_validation_check(struct _k_object *ko,
434434
# op, __device__); \
435435
})
436436

437+
/**
438+
* @brief Runtime check that device object is of a specific driver type
439+
*
440+
* Checks that the driver object passed in is initialized, the caller has
441+
* correct permissions, and that it belongs to the specified driver
442+
* subsystems. Additionally, all devices store a function pointer to the
443+
* driver's init function. If this doesn't match the value provided, the
444+
* check will fail.
445+
*
446+
* This provides an easy way to determine if a device object not only
447+
* belongs to a particular subsystem, but is of a specific device driver
448+
* implementation. Useful for defining out-of-subsystem system calls
449+
* which are implemented for only one driver.
450+
*
451+
* @param _device Untrusted device pointer
452+
* @param _dtype Expected kernel object type for the provided device pointer
453+
* @param _init_fn Expected init function memory address
454+
* @return 0 on success, nonzero on failure
455+
*/
456+
#define Z_SYSCALL_SPECIFIC_DRIVER(_device, _dtype, _init_fn) \
457+
({ \
458+
struct device *_dev = (struct device *)_device; \
459+
Z_SYSCALL_OBJ(_dev, _dtype) || \
460+
Z_SYSCALL_VERIFY_MSG(_dev->config->init == _init_fn, \
461+
"init function mismatch"); \
462+
})
463+
437464
/**
438465
* @brief Runtime check kernel object pointer for non-init functions
439466
*

0 commit comments

Comments
 (0)