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:
Andrew Boie 2017-08-22 13:15:23 -07:00 committed by Andrew Boie
commit 945af95f42
26 changed files with 1188 additions and 89 deletions

View file

@ -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);
}
/**