kernel: fix errno access for user mode
The errno "variable" is required to be thread-specific. It gets defined to a macro which dereferences a pointer returned by a kernel function. In user mode, we cannot simply read/write the thread struct. We do not have thread-local storage mechanism, so for now use the lowest address of the thread stack to store this value, since this is guaranteed to be read/writable by a user thread. The downside of this approach is potential stack corruption if the stack pointer goes down this far but does not exceed the location, since a fault won't be generated in this case. Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
parent
89f87ec56e
commit
7f4d006959
6 changed files with 69 additions and 5 deletions
|
@ -538,9 +538,17 @@ struct k_thread {
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_ERRNO
|
||||
#ifdef CONFIG_USERSPACE
|
||||
/* Set to the lowest area in the thread stack since this needs to
|
||||
* be directly read/writable by user mode. Not ideal, but best we
|
||||
* can do until we have thread-local storage
|
||||
*/
|
||||
int *errno_location;
|
||||
#else
|
||||
/** per-thread errno variable */
|
||||
int errno_var;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_THREAD_STACK_INFO)
|
||||
/** Stack Info */
|
||||
|
|
36
include/misc/errno_private.h
Normal file
36
include/misc/errno_private.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Intel Corporation.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _MISC_ERRNO_PRIVATE_H_
|
||||
#define _MISC_ERRNO_PRIVATE_H_
|
||||
|
||||
#include <toolchain.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* NOTE: located here to avoid include dependency loops between errno.h
|
||||
* and kernel.h
|
||||
*/
|
||||
|
||||
/**
|
||||
* return a pointer to a memory location containing errno
|
||||
*
|
||||
* errno is thread-specific, and can't just be a global. This pointer
|
||||
* is guaranteed to be read/writable from user mode.
|
||||
*
|
||||
* @return Memory location of errno data for current thread
|
||||
*/
|
||||
__syscall int *z_errno(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <syscalls/errno_private.h>
|
||||
|
||||
#endif /* _MISC_ERRNO_PRIVATE_H */
|
|
@ -13,6 +13,7 @@
|
|||
*/
|
||||
|
||||
#include <kernel_structs.h>
|
||||
#include <syscall_handler.h>
|
||||
|
||||
/*
|
||||
* Define _k_neg_eagain for use in assembly files as errno.h is
|
||||
|
@ -22,8 +23,20 @@
|
|||
const int _k_neg_eagain = -EAGAIN;
|
||||
|
||||
#ifdef CONFIG_ERRNO
|
||||
int *__errno(void)
|
||||
#ifdef CONFIG_USERSPACE
|
||||
int *_impl_z_errno(void)
|
||||
{
|
||||
/* Initialized to the lowest address in the stack so the thread can
|
||||
* directly read/write it
|
||||
*/
|
||||
return _current->errno_location;
|
||||
}
|
||||
|
||||
Z_SYSCALL_HANDLER0_SIMPLE(z_errno);
|
||||
#else
|
||||
int *_impl_z_errno(void)
|
||||
{
|
||||
return &_current->errno_var;
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
#endif /* CONFIG_ERRNO */
|
||||
|
|
|
@ -312,6 +312,7 @@ void _setup_new_thread(struct k_thread *new_thread,
|
|||
_k_object_init(new_thread);
|
||||
_k_object_init(stack);
|
||||
new_thread->stack_obj = stack;
|
||||
new_thread->errno_location = (int *)K_THREAD_STACK_BUFFER(stack);
|
||||
|
||||
/* Any given thread has access to itself */
|
||||
k_object_access_grant(new_thread, new_thread);
|
||||
|
|
|
@ -17,13 +17,13 @@
|
|||
#ifndef __INCerrnoh
|
||||
#define __INCerrnoh
|
||||
|
||||
#include <misc/errno_private.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
extern int *__errno(void);
|
||||
#define errno (*__errno())
|
||||
#define errno (*z_errno())
|
||||
|
||||
/*
|
||||
* POSIX Error codes
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <linker/linker-defs.h>
|
||||
#include <misc/util.h>
|
||||
#include <kernel_internal.h>
|
||||
#include <misc/errno_private.h>
|
||||
|
||||
#define USED_RAM_END_ADDR POINTER_TO_UINT(&_end)
|
||||
|
||||
|
@ -178,3 +179,8 @@ void z_newlib_get_heap_bounds(void **base, size_t *size)
|
|||
*base = heap_base;
|
||||
*size = MAX_HEAP_SIZE;
|
||||
}
|
||||
|
||||
int *__errno(void)
|
||||
{
|
||||
return z_errno();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue