Commit 7f4d0069 authored by Andrew Boie's avatar Andrew Boie Committed by Andrew Boie
Browse files

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: default avatarAndrew Boie <andrew.p.boie@intel.com>
parent 89f87ec5
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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 */
+15 −2
Original line number Diff line number Diff line
@@ -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 */
+1 −0
Original line number Diff line number Diff line
@@ -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);
+3 −3
Original line number Diff line number Diff line
@@ -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
Loading