.. _syscalls:

System Calls
############
User threads run with a reduced set of privileges than supervisor threads:
certain CPU instructions may not be used, and they have access to only a
limited part of the memory map. System calls (may) allow user threads to
perform operations not directly available to them.

When defining system calls, it is very important to ensure that access to the
API's private data is done exclusively through system call interfaces.
Private kernel data should never be made available to user mode threads
directly. For example, the ``k_queue`` APIs were intentionally not made
available as they store bookkeeping information about the queue directly
in the queue buffers which are visible from user mode.

APIs that allow the user to register callback functions that run in
supervisor mode should never be exposed as system calls. Reserve these
for supervisor-mode access only.

This section describes how to declare new system calls and discusses a few
implementation details relevant to them.

Components
**********

All system calls have the following components:

* A **C prototype** prefixed with :c:macro:`__syscall` for the API. It
  will be declared in some header under ``include/`` or in another
  ``SYSCALL_INCLUDE_DIRS`` directory. This prototype is never implemented
  manually, instead it gets created by the :ref:`gen_syscalls.py` script.
  What gets generated is an inline function which either calls the
  implementation function directly (if called from supervisor mode) or goes
  through privilege elevation and validation steps (if called from user
  mode).

* An **implementation function**, which is the real implementation of the
  system call. The implementation function may assume that all parameters
  passed in have been validated if it was invoked from user mode.

* A **verification function**, which wraps the implementation function
  and does validation of all the arguments passed in.

* An **unmarshalling function**, which is an automatically generated
  handler that must be included by user source code.

C Prototype
***********

The C prototype represents how the API is invoked from either user or
supervisor mode. For example, to initialize a semaphore:

.. code-block:: c

    __syscall void k_sem_init(struct k_sem *sem, unsigned int initial_count,
                              unsigned int limit);

The :c:macro:`__syscall` attribute is very special. To the C compiler, it
simply expands to 'static inline'. However to the post-build
:ref:`parse_syscalls.py` script, it indicates that this API is a system call.
The :ref:`parse_syscalls.py` script does some parsing of the function prototype,
to determine the data types of its return value and arguments, and has some
limitations:

* Array arguments must be passed in as pointers, not arrays. For example,
  ``int foo[]`` or ``int foo[12]`` is not allowed, but should instead be
  expressed as ``int *foo``.

* Function pointers horribly confuse the limited parser. The workaround is
  to typedef them first, and then express in the argument list in terms
  of that typedef.

* :c:macro:`__syscall` must be the first thing in the prototype.

The preprocessor is intentionally not used when determining the set of system
calls to generate. However, any generated system calls that don't actually have
a verification function defined (because the related feature is not enabled in
the kernel configuration) will instead point to a special verification for
unimplemented system calls. Data type definitions for APIs should not have
conditional visibility to the compiler.

Any header file that declares system calls must include a special generated
header at the very bottom of the header file. This header follows the
naming convention ``syscalls/<name of header file>``. For example, at the
bottom of ``include/sensor.h``:

.. code-block:: c

    #include <syscalls/sensor.h>

C prototype functions must be declared in one of the directories
listed in the CMake variable ``SYSCALL_INCLUDE_DIRS``. This list
always contains ``${ZEPHYR_BASE}/include``, but will also contain
``APPLICATION_SOURCE_DIR`` when ``CONFIG_APPLICATION_DEFINED_SYSCALL``
is set, or ``${ZEPHYR_BASE}/subsys/testsuite/ztest/include`` when
``CONFIG_ZTEST`` is set. Additional paths can be added to the list
through the CMake command line or in CMake code that is run before
``${ZEPHYR_BASE}/cmake/app/boilerplate.cmake`` is run.

Invocation Context
==================

Source code that uses system call APIs can be made more efficient if it is
known that all the code inside a particular C file runs exclusively in
user mode, or exclusively in supervisor mode. The system will look for
the definition of macros :c:macro:`__ZEPHYR_SUPERVISOR__` or
:c:macro:`__ZEPHYR_USER__`, typically these will be added to the compiler
flags in the build system for the related files.

* If :option:`CONFIG_USERSPACE` is not enabled, all APIs just directly call
  the implementation function.

* Otherwise, the default case is to make a runtime check to see if the
  processor is currently running in user mode, and either make the system call
  or directly call the implementation function as appropriate.

* If :c:macro:`__ZEPHYR_SUPERVISOR__` is defined, then it is assumed that
  all the code runs in supervisor mode and all APIs just directly call the
  implementation function. If the code was actually running in user mode,
  there will be a CPU exception as soon as it tries to do something it isn't
  allowed to do.

* If :c:macro:`__ZEPHYR_USER__` is defined, then it is assumed that all the
  code runs in user mode and system calls are unconditionally made.

Implementation Details
======================

Declaring an API with :c:macro:`__syscall` causes some code to be generated in
C and header files by the :ref:`gen_syscalls.py` script, all of which can be found in
the project out directory under ``include/generated/``:

* The system call is added to the enumerated type of system call IDs,
  which is expressed in ``include/generated/syscall_list.h``. It is the name
  of the API in uppercase, prefixed with ``K_SYSCALL_``.

* An entry for the system call is created in the dispatch table
  ``_k_sycall_table``, expressed in ``include/generated/syscall_dispatch.c``

* A weak verification function is declared, which is just an alias of the
  'unimplemented system call' verifier. This is necessary since the real
  verification function may or may not be built depending on the kernel
  configuration. For example, if a user thread makes a sensor subsystem
  API call, but the sensor subsystem is not enabled, the weak verifier
  will be invoked instead.

* An unmarshalling function is defined in ``include/generated/<name>_mrsh.c``

The body of the API is created in the generated system header. Using the
example of :c:func:`k_sem_init()`, this API is declared in
``include/kernel.h``. At the bottom of ``include/kernel.h`` is::

    #include <syscalls/kernel.h>

Inside this header is the body of :c:func:`k_sem_init()`::

    static inline void k_sem_init(struct k_sem * sem, unsigned int initial_count, unsigned int limit)
    {
    #ifdef CONFIG_USERSPACE
            if (z_syscall_trap()) {
                    arch_syscall_invoke3(*(uintptr_t *)&sem, *(uintptr_t *)&initial_count, *(uintptr_t *)&limit, K_SYSCALL_K_SEM_INIT);
                    return;
            }
            compiler_barrier();
    #endif
            z_impl_k_sem_init(sem, initial_count, limit);
    }

This generates an inline function that takes three arguments with void
return value. Depending on context it will either directly call the
implementation function or go through a system call elevation. A
prototype for the implementation function is also automatically generated.

The final layer is the invocation of the system call itself. All architectures
implementing system calls must implement the seven inline functions
:c:func:`_arch_syscall_invoke0` through :c:func:`_arch_syscall_invoke6`.  These
functions marshal arguments into designated CPU registers and perform the
necessary privilege elevation. In this layer, all arguments are treated as an
unsigned 32-bit type. There is always a 32-bit unsigned return value, which
may or may not be used.

.. figure:: syscall_flow.png
   :alt: System Call execution flow
   :width: 80%
   :align: center

   System Call execution flow

Some system calls may have more than six arguments. The number of
arguments passed via registers is limited to six for all
architectures. Additional arguments will need to be passed in an array
in the source memory space, which needs to be treated as untrusted
memory in the verification function. This code (packing, unpacking and
validation) is generated automatically as needed in the stub above and
in the unmarshalling function.

Some system calls may return a value that will not fit in a 32-bit
register, such as APIs that return a 64-bit value. In this scenario,
the return value is populated in a **untrusted** memory buffer that is
passed in as a final argument.  Likewise, this code is generated
automatically.

Implementation Function
***********************

The implementation function is what actually does the work for the API.
Zephyr normally does little to no error checking of arguments, or does this
kind of checking with assertions. When writing the implementation function,
validation of any parameters is optional and should be done with assertions.

All implementation functions must follow the naming convention, which is the
name of the API prefixed with ``_impl_``. Implementation functions may be
declared in the same header as the API as a static inline function or
declared in some C file. There is no prototype needed for implementation
functions, these are automatically generated.

Verification Function
*********************

The verification function runs on the kernel side when a user thread makes
a system call. When the user thread makes a software interrupt to elevate to
supervisor mode, the common system call entry point uses the system call ID
provided by the user to look up the appropriate unmarshalling function for that
system call and jump into it. This in turn calls the verification function.

Verification and unmarshalling functions only run when system call APIs are
invoked from user mode. If an API is invoked from supervisor mode, the
implementation is simply called and there is no software trap.

The purpose of the verification function is to validate all the arguments
passed in.  This includes:

* Any kernel object pointers provided. For example, the semaphore APIs must
  ensure that the semaphore object passed in is a valid semaphore and that
  the calling thread has permission on it.

* Any memory buffers passed in from user mode. Checks must be made that the
  calling thread has read or write permissions on the provided buffer.

* Any other arguments that have a limited range of valid values.

Verification functions involve a great deal of boilerplate code which has been
made simpler by some macros in ``kernel/include/syscall_handlers.h``.
Verification functions should be declared using these macros.

Argument Validation
===================

Several macros exist to validate arguments:

* :c:macro:`Z_SYSCALL_OBJ()` Checks a memory address to assert that it is
  a valid kernel object of the expected type, that the calling thread
  has permissions on it, and that the object is initialized.

* :c:macro:`Z_SYSCALL_OBJ_INIT()` is the same as
  :c:macro:`Z_SYSCALL_OBJ()`, except that the provided object may be
  uninitialized. This is useful for verifiers of object init functions.

* :c:macro:`Z_SYSCALL_OBJ_NEVER_INIT()` is the same as
  :c:macro:`Z_SYSCALL_OBJ()`, except that the provided object must be
  uninitialized. This is not used very often, currently only for
  :c:func:`k_thread_create()`.

* :c:macro:`Z_SYSCALL_MEMORY_READ()` validates a memory buffer of a particular
  size. The calling thread must have read permissions on the entire buffer.

* :c:macro:`Z_SYSCALL_MEMORY_WRITE()` is the same as
  :c:macro:`Z_SYSCALL_MEMORY_READ()` but the calling thread must additionally
  have write permissions.

* :c:macro:`Z_SYSCALL_MEMORY_ARRAY_READ()` validates an array whose total size
  is expressed as separate arguments for the number of elements and the
  element size. This macro correctly accounts for multiplication overflow
  when computing the total size. The calling thread must have read permissions
  on the total size.

* :c:macro:`Z_SYSCALL_MEMORY_ARRAY_WRITE()` is the same as
  :c:macro:`Z_SYSCALL_MEMORY_ARRAY_READ()` but the calling thread must
  additionally have write permissions.

* :c:macro:`Z_SYSCALL_VERIFY_MSG()` does a runtime check of some boolean
  expression which must evaluate to true otherwise the check will fail.
  A variant :c:macro:`Z_SYSCALL_VERIFY` exists which does not take
  a message parameter, instead printing the expression tested if it
  fails. The latter should only be used for the most obvious of tests.

* :c:macro:`Z_SYSCALL_DRIVER_OP()` checks at runtime if a driver
  instance is capable of performing a particular operation.  While this
  macro can be used by itself, it's mostly a building block for macros
  that are automatically generated for every driver subsystem.  For
  instance, to validate the GPIO driver, one could use the
  :c:macro:`Z_SYSCALL_DRIVER_GPIO()` macro.

* :c:macro:`Z_SYSCALL_SPECIFIC_DRIVER()` is a runtime check to verify that
  a provided pointer is a valid instance of a specific device driver, that
  the calling thread has permissions on it, and that the driver has been
  initialized. It does this by checking the API structure pointer that
  is stored within the driver instance and ensuring that it matches the
  provided value, which should be the address of the specific driver's
  API structure.

If any check fails, the macros will return a nonzero value. The macro
:c:macro:`Z_OOPS()` can be used to induce a kernel oops which will kill the
calling thread. This is done instead of returning some error condition to
keep the APIs the same when calling from supervisor mode.

Verifier Definition
===================

All system calls are dispatched to a verifier function with a prefixed
``z_vrfy_`` name based on the system call.  They have exactly the same
return type and argument types as the wrapped system call.  Their job
is to execute the system call (generally by calling the implementation
function) after having validated all arguments.

The verifier is itself invoked by an automatically generated
unmarshaller function which takes care of unpacking the register
arguments from the architecture layer and casting them to the correct
type.  This is defined in a header file that must be included from
user code, generally somewhere after the definition of the verifier in
a translation unit (so that it can be inlined).

For example:

.. code-block:: c

    static int z_vrfy_k_sem_take(struct k_sem *sem, int32_t timeout)
    {
        Z_OOPS(Z_SYSCALL_OBJ(sem, K_OBJ_SEM));
        return z_impl_k_sem_take(sem, timeout);
    }
    #include <syscalls/k_sem_take_mrsh.c>


Verification Memory Access Policies
===================================

Parameters passed to system calls by reference require special handling,
because the value of these parameters can be changed at any time by any
user thread that has access to the memory that parameter points to. If the
kernel makes any logical decisions based on the contents of this memory, this
can open up the kernel to attacks even if checking is done. This is a class
of exploits known as TOCTOU (Time Of Check to Time Of Use).

The proper procedure to mitigate these attacks is to make a copies in the
verification function, and only perform parameter checks on the copies, which
user threads will never have access to. The implementation functions get passed
the copy and not the original data sent by the user. The
:c:func:`z_user_to_copy()` and :c:func:`z_user_from_copy()` APIs exist for
this purpose.

There is one exception in place, with respect to large data buffers which are
only used to provide a memory area that is either only written to, or whose
contents are never used for any validation or control flow. Further
discussion of this later in this section.

As a first example, consider a parameter which is used as an output parameter
for some integral value:


.. code-block:: c

    int z_vrfy_some_syscall(int *out_param)
    {
        int local_out_param;
        int ret;

        ret = z_impl_some_syscall(&local_out_param);
        Z_OOPS(z_user_to_copy(out_param, &local_out_param, sizeof(*out_param)));
        return ret;
    }

Here we have allocated ``local_out_param`` on the stack, passed its address to
the implementation function, and then used :c:func:`z_user_to_copy()` to fill
in the memory passed in by the caller.

It might be tempting to do something more concise:

.. code-block:: c

    int z_vrfy_some_syscall(int *out_param)
    {
        Z_OOPS(Z_SYSCALL_MEMORY_WRITE(out_param, sizeof(*out_param)));
        return z_impl_some_syscall(out_param);
    }

However, this is unsafe if the implementation ever does any reads to this
memory as part of its logic. For example, it could be used to store some
counter value, and this could be meddled with by user threads that have access
to its memory. It is by far safest for small integral values to do the copying
as shown in the first example.

Some parameters may be input/output. For instance, it's not uncommon to see APIs
which pass in a pointer to some ``size_t`` which is a maximum allowable size,
which is then updated by the implementation to reflect the actual number of
bytes processed. This too should use a stack copy:

.. code-block:: c

    int z_vrfy_in_out_syscall(size_t *size_ptr)
    {
        size_t size;
        int ret;

        Z_OOPS(z_user_from_copy(&size, size_ptr, sizeof(size));
        ret = z_impl_in_out_syscall(&size);
        *size_ptr = size;
        return ret;
    }

Many system calls pass in structs, or even linked data structures. All should
be copied. Typically this is done by allocating copies on the stack:

.. code-block:: c

    struct bar {
        ...
    };

    struct foo {
        ...
        struct bar *bar_left;
        struct bar *bar_right;
    };

    int z_vrfy_must_alloc(struct foo *foo)
    {
        int ret;
        struct foo foo_copy;
        struct bar bar_right_copy;
        struct bar bar_left_copy;

        Z_OOPS(z_user_from_copy(&foo_copy, foo, sizeof(*foo)));
        Z_OOPS(z_user_from_copy(&bar_right_copy, foo_copy.bar_right,
                                sizeof(struct bar)));
        foo_copy.bar_right = &bar_right_copy;
        Z_OOPS(z_user_from_copy(&bar_left_copy, foo_copy.bar_left,
                                sizeof(struct bar)));
        foo_copy.bar_left = &bar_left_copy;

        return z_impl_must_alloc(&foo_copy);
    }

In some cases the amount of data isn't known at compile time or may be too
large to allocate on the stack. In this scenario, it may be necessary to draw
memory from the caller's resource pool via :c:func:`z_thread_malloc()`. This
should always be a method of last resort. Functional safety programming
guidelines heavily discourge the use of heaps, the fact that a resource pool is
used must be clearly documented, and any issue with allocations must be
propaged to the caller with a ``-ENOMEM`` return value, never a ``Z_OOPS()``.

.. code-block:: c

    struct bar {
        ...
    };

    struct foo {
        size_t count;
        struct bar *bar_list; /* array of struct bar of size count */
    };

    int z_vrfy_must_alloc(struct foo *foo)
    {
        int ret;
        struct foo foo_copy;
        struct bar *bar_list_copy;
        size_t bar_list_bytes;

        /* Safely copy foo into foo_copy */
        Z_OOPS(z_user_from_copy(&foo_copy, foo, sizeof(*foo)));

        /* Bounds check the count member, in the copy we made */
        if (foo_copy.count > 32) {
            return -EINVAL;
        }

        /* Allocate RAM for the bar_list, replace the pointer in
         * foo_copy */
        bar_list_bytes = foo_copy.count * sizeof(struct_bar);
        bar_list_copy = z_thread_malloc(bar_list_bytes);
        if (bar_list_copy == NULL) {
            return -ENOMEM;
        }
        Z_OOPS(z_user_from_copy(bar_list_copy, foo_copy.bar_list,
                                bar_list_bytes));
        foo_copy.bar_list = bar_list_copy;

        ret = z_impl_must_alloc(&foo_copy);

        /* All done with the memory, free it and return */
        k_free(foo_copy.bar_list_copy);
        return ret;
    }

Finally, we must consider large data buffers. These represent areas of user
memory which either have data copied out of, or copied into. It is permitted
to pass these pointers to the implementation function directly. The caller's
access to the buffer still must be validated with ``Z_SYSCALL_MEMORY`` APIs.
The following constraints need to be met:

 * If the buffer is used by the implementation function to write data, such
   as data captured from some MMIO region, the implementation function must
   only write this data, and never read it.

 * If the buffer is used by the implementation function to read data, such
   as a block of memory to write to some hardware destination, this data
   must be read without any processing. No conditional logic can be implemented
   due to the data buffer's contents. If such logic is required a copy must be
   made.

 * The buffer must only be used synchronously with the call. The implementation
   must not ever save the buffer address and use it asynchronously, such as
   when an interrupt fires.

.. code-block:: c

    int z_vrfy_get_data_from_kernel(void *buf, size_t size)
    {
        Z_OOPS(Z_SYSCALL_MEMORY_WRITE(buf, size));
        return z_impl_get_data_from_kernel(buf, size);
    }

Verification Return Value Policies
==================================

When verifying system calls, it's important to note which kinds of verification
failures should propagate a return value to the caller, and which should
simply invoke :c:macro:`Z_OOPS()` which kills the calling thread. The current
coventions are as follows:

#. For system calls that are defined but not compiled, invocations of these
   missing system calls are routed to :c:func:`handler_no_syscall()` which
   invokes :c:macro:`Z_OOPS()`.

#. Any invalid access to memory found by the set of ``Z_SYSCALL_MEMORY`` APIs,
   :c:func:`z_user_from_copy()`, :c:func:`z_user_to_copy()`
   should trigger a :c:macro:`Z_OOPS`. This happens when the caller doesn't have
   appropriate permissions on the memory buffer or some size calculation
   overflowed.

#. Most system calls take kernel object pointers as an argument, checked either
   with one of the ``Z_SYSCALL_OBJ`` functions,  ``Z_SYSCALL_DRIVER_nnnnn``, or
   manually using :c:func:`z_object_validate()`. These can fail for a variety
   of reasons: missing driver API, bad kernel object pointer, wrong kernel
   object type, or improper initialization state. These issues should always
   invoke :c:macro:`Z_OOPS()`.

#. Any error resulting from a failed memory heap allocation, often from
   invoking :c:func:`z_thread_malloc()`, should propagate ``-ENOMEM`` to the
   caller.

#. General parameter checks should be done in the implementation function,
   in most cases using ``CHECKIF()``.

   * The behavior of ``CHECKIF()`` depends on the kernel configuration, but if
     user mode is enabled, :option:`CONFIG_RUNTIME_ERROR_CHECKS` is enforced,
     which guarantees that these checks will be made and a return value
     propagated.

#. It is totally forbidden for any kind of kernel mode callback function to
   be registered from user mode. APIs which simply install callbacks shall not
   be exposed as system calls. Some driver subsystem APIs may take optional
   function callback pointers. User mode verification functions for these APIs
   must enforce that these are NULL and should invoke :c:macro:`Z_OOPS()` if
   not.

#. Some parameter checks are enforced only from user mode. These should be
   checked in the verification function and propagate a return value to the
   caller if possible.

There are some known exceptions to these policies currently in Zephyr:

* :c:func:`k_thread_join()` and :c:func:`k_thread_abort()` are no-ops if
  the thread object isn't initialized. This is because for threads, the
  initialization bit pulls double-duty to indicate whether a thread is
  running, cleared upon exit. See #23030.

* :c:func:`k_thread_create()` invokes :c:macro:`Z_OOPS()` for parameter
  checks, due to a great deal of existing code ignoring the return value.
  This will also be addressed by #23030.

* :c:func:`k_thread_abort()` invokes :c:macro:`Z_OOPS()` if an essential
  thread is aborted, as the function has no return value.

* Various system calls related to logging invoke :c:macro:`Z_OOPS()`
  when bad parameters are passed in as they do not propagate errors.

Configuration Options
*********************

Related configuration options:

* :option:`CONFIG_USERSPACE`

APIs
****

Helper macros for creating system call verification functions are provided in
:zephyr_file:`kernel/include/syscall_handler.h`:

* :c:macro:`Z_SYSCALL_OBJ()`
* :c:macro:`Z_SYSCALL_OBJ_INIT()`
* :c:macro:`Z_SYSCALL_OBJ_NEVER_INIT()`
* :c:macro:`Z_OOPS()`
* :c:macro:`Z_SYSCALL_MEMORY_READ()`
* :c:macro:`Z_SYSCALL_MEMORY_WRITE()`
* :c:macro:`Z_SYSCALL_MEMORY_ARRAY_READ()`
* :c:macro:`Z_SYSCALL_MEMORY_ARRAY_WRITE()`
* :c:macro:`Z_SYSCALL_VERIFY_MSG()`
* :c:macro:`Z_SYSCALL_VERIFY`

Functions for invoking system calls are defined in
:zephyr_file:`include/syscall.h`:

* :c:func:`_arch_syscall_invoke0`
* :c:func:`_arch_syscall_invoke1`
* :c:func:`_arch_syscall_invoke2`
* :c:func:`_arch_syscall_invoke3`
* :c:func:`_arch_syscall_invoke4`
* :c:func:`_arch_syscall_invoke5`
* :c:func:`_arch_syscall_invoke6`
