kernel: introduce object validation mechanism
All system calls made from userspace which involve pointers to kernel objects (including device drivers) will need to have those pointers validated; userspace should never be able to crash the kernel by passing it garbage. The actual validation with _k_object_validate() will be in the system call receiver code, which doesn't exist yet. - CONFIG_USERSPACE introduced. We are somewhat far away from having an end-to-end implementation, but at least need a Kconfig symbol to guard the incoming code with. Formal documentation doesn't exist yet either, but will appear later down the road once the implementation is mostly finalized. - In the memory region for RAM, the data section has been moved last, past bss and noinit. This ensures that inserting generated tables with addresses of kernel objects does not change the addresses of those objects (which would make the table invalid) - The DWARF debug information in the generated ELF binary is parsed to fetch the locations of all kernel objects and pass this to gperf to create a perfect hash table of their memory addresses. - The generated gperf code doesn't know that we are exclusively working with memory addresses and uses memory inefficently. A post-processing script process_gperf.py adjusts the generated code before it is compiled to work with pointer values directly and not strings containing them. - _k_object_init() calls inserted into the init functions for the set of kernel object types we are going to support so far Issue: ZEP-2187 Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
3ef0b56c15
commit
945af95f42
26 changed files with 1188 additions and 89 deletions
|
@ -123,6 +123,103 @@ struct k_timer;
|
|||
struct k_poll_event;
|
||||
struct k_poll_signal;
|
||||
|
||||
enum k_objects {
|
||||
K_OBJ_ALERT,
|
||||
K_OBJ_DELAYED_WORK,
|
||||
K_OBJ_MEM_SLAB,
|
||||
K_OBJ_MSGQ,
|
||||
K_OBJ_MUTEX,
|
||||
K_OBJ_PIPE,
|
||||
K_OBJ_SEM,
|
||||
K_OBJ_STACK,
|
||||
K_OBJ_THREAD,
|
||||
K_OBJ_TIMER,
|
||||
K_OBJ_WORK,
|
||||
K_OBJ_WORK_Q,
|
||||
|
||||
K_OBJ_LAST
|
||||
};
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
/* Table generated by gperf, these objects are retrieved via
|
||||
* _k_object_find() */
|
||||
struct _k_object {
|
||||
char *name;
|
||||
char perms[CONFIG_MAX_THREAD_BYTES];
|
||||
char type;
|
||||
char flags;
|
||||
} __packed;
|
||||
|
||||
#define K_OBJ_FLAG_INITIALIZED BIT(0)
|
||||
/**
|
||||
* Ensure a system object is a valid object of the expected type
|
||||
*
|
||||
* Searches for the object and ensures that it is indeed an object
|
||||
* of the expected type, that the caller has the right permissions on it,
|
||||
* and that the object has been initialized.
|
||||
*
|
||||
* This function is intended to be called on the kernel-side system
|
||||
* call handlers to validate kernel object pointers passed in from
|
||||
* userspace.
|
||||
*
|
||||
* @param obj Address of the kernel object
|
||||
* @param otype Expected type of the kernel object
|
||||
* @param init If true, this is for an init function and we will not error
|
||||
* out if the object is not initialized
|
||||
* @return 0 If the object is valid
|
||||
* -EBADF if not a valid object of the specified type
|
||||
* -EPERM If the caller does not have permissions
|
||||
* -EINVAL Object is not intitialized
|
||||
*/
|
||||
int _k_object_validate(void *obj, enum k_objects otype, int init);
|
||||
|
||||
|
||||
/**
|
||||
* Lookup a kernel object and init its metadata if it exists
|
||||
*
|
||||
* Calling this on an object will make it usable from userspace.
|
||||
* Intended to be called as the last statement in kernel object init
|
||||
* functions.
|
||||
*
|
||||
* @param object Address of the kernel object
|
||||
*/
|
||||
void _k_object_init(void *obj);
|
||||
|
||||
|
||||
/**
|
||||
* grant a thread access to a kernel object
|
||||
*
|
||||
* The thread will be granted access to the object if the caller is from
|
||||
* supervisor mode, or the caller is from user mode AND has permissions
|
||||
* on the object already.
|
||||
*
|
||||
* @param object Address of kernel object
|
||||
* @param thread Thread to grant access to the object
|
||||
*/
|
||||
void k_object_grant_access(void *object, struct k_thread *thread);
|
||||
|
||||
#else
|
||||
static inline int _k_object_validate(void *obj, enum k_objects otype, int init)
|
||||
{
|
||||
ARG_UNUSED(obj);
|
||||
ARG_UNUSED(otype);
|
||||
ARG_UNUSED(init);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void _k_object_init(void *obj)
|
||||
{
|
||||
ARG_UNUSED(obj);
|
||||
}
|
||||
|
||||
static inline void k_object_grant_access(void *object, struct k_thread *thread)
|
||||
{
|
||||
ARG_UNUSED(object);
|
||||
ARG_UNUSED(thread);
|
||||
}
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
|
||||
/* timeouts */
|
||||
|
||||
struct _timeout;
|
||||
|
@ -196,7 +293,6 @@ struct _thread_base {
|
|||
/* this thread's entry in a timeout queue */
|
||||
struct _timeout timeout;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
typedef struct _thread_base _thread_base_t;
|
||||
|
@ -2022,6 +2118,7 @@ static inline void k_work_init(struct k_work *work, k_work_handler_t handler)
|
|||
{
|
||||
atomic_clear_bit(work->flags, K_WORK_STATE_PENDING);
|
||||
work->handler = handler;
|
||||
_k_object_init(work);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue