|  | .. _kernelobjects: | 
|  |  | 
|  | Kernel Objects | 
|  | ############## | 
|  |  | 
|  | A kernel object can be one of three classes of data: | 
|  |  | 
|  | * A core kernel object, such as a semaphore, thread, pipe, etc. | 
|  | * A thread stack, which is an array of :c:struct:`z_thread_stack_element` | 
|  | and declared with :c:macro:`K_THREAD_STACK_DEFINE()` | 
|  | * A device driver instance (const struct device) that belongs to one of a defined | 
|  | set of subsystems | 
|  |  | 
|  | The set of known kernel objects and driver subsystems is defined in | 
|  | include/kernel.h as :c:enum:`k_objects`. | 
|  |  | 
|  | Kernel objects are completely opaque to user threads. User threads work | 
|  | with addresses to kernel objects when making API calls, but may never | 
|  | dereference these addresses, doing so will cause a memory protection fault. | 
|  | All kernel objects must be placed in memory that is not accessible by | 
|  | user threads. | 
|  |  | 
|  | Since user threads may not directly manipulate kernel objects, all use of | 
|  | them must go through system calls. In order to perform a system call on | 
|  | a kernel object, checks are performed by system call handler functions | 
|  | that the kernel object address is valid and that the calling thread | 
|  | has sufficient permissions to work with it. | 
|  |  | 
|  | Permission on an object also has the semantics of a reference to an object. | 
|  | This is significant for certain object APIs which do temporary allocations, | 
|  | or objects which themselves have been allocated from a runtime memory pool. | 
|  |  | 
|  | If an object loses all references, two events may happen: | 
|  |  | 
|  | * If the object has an associated cleanup function, the cleanup function | 
|  | may be called to release any runtime-allocated buffers the object was using. | 
|  |  | 
|  | * If the object itself was dynamically allocated, the memory for the object | 
|  | will be freed. | 
|  |  | 
|  | Object Placement | 
|  | **************** | 
|  |  | 
|  | Kernel objects that are only used by supervisor threads have no restrictions | 
|  | and can be located anywhere in the binary, or even declared on stacks. However, | 
|  | to prevent accidental or intentional corruption by user threads, they must | 
|  | not be located in any memory that user threads have direct access to. | 
|  |  | 
|  | In order for a static kernel object to be usable by a user thread via system | 
|  | call APIs, several conditions must be met on how the kernel object is declared: | 
|  |  | 
|  | * The object must be declared as a top-level global at build time, such that it | 
|  | appears in the ELF symbol table. It is permitted to declare kernel objects | 
|  | with static scope. The post-build script :ref:`gen_kobject_list.py` scans the | 
|  | generated ELF file to find kernel objects and places their memory addresses | 
|  | in a special table of kernel object metadata.  Kernel objects may be members | 
|  | of arrays or embedded within other data structures. | 
|  |  | 
|  | * Kernel objects must be located in memory reserved for the kernel. They | 
|  | must not be located in any memory partitions that are user-accessible. | 
|  |  | 
|  | * Any memory reserved for a kernel object must be used exclusively for that | 
|  | object. Kernel objects may not be members of a union data type. | 
|  |  | 
|  | Kernel objects that are found but do not meet the above conditions will not be | 
|  | included in the generated table that is used to validate kernel object pointers | 
|  | passed in from user mode. | 
|  |  | 
|  | The debug output of the :ref:`gen_kobject_list.py` script may be useful when | 
|  | debugging why some object was unexpectedly not being tracked. This | 
|  | information will be printed if the script is run with the ``--verbose`` flag, | 
|  | or if the build system is invoked with verbose output. | 
|  |  | 
|  | Dynamic Objects | 
|  | *************** | 
|  |  | 
|  | Kernel objects may also be allocated at runtime if | 
|  | :kconfig:option:`CONFIG_DYNAMIC_OBJECTS` is enabled. In this case, the | 
|  | :c:func:`k_object_alloc` API may be used to instantiate an object from | 
|  | the calling thread's resource pool. Such allocations may be freed in two | 
|  | ways: | 
|  |  | 
|  | * Supervisor threads may call :c:func:`k_object_free` to force a dynamic | 
|  | object to be released. | 
|  |  | 
|  | * If an object's references drop to zero (which happens when no threads have | 
|  | permissions on it) the object will be automatically freed. User threads | 
|  | may drop their own permission on an object with | 
|  | :c:func:`k_object_release`, and their permissions are automatically | 
|  | cleared when a thread terminates. Supervisor threads may additionally | 
|  | revoke references for another thread using | 
|  | :c:func:`k_object_access_revoke`. | 
|  |  | 
|  | Because permissions are also used for reference counting, it is important for | 
|  | supervisor threads to acquire permissions on objects they are using even though | 
|  | the access control aspects of the permission system are not enforced. | 
|  |  | 
|  | Implementation Details | 
|  | ====================== | 
|  |  | 
|  | The :ref:`gen_kobject_list.py` script is a post-build step which finds all the | 
|  | valid kernel object instances in the binary. It accomplishes this by parsing | 
|  | the DWARF debug information present in the generated ELF file for the kernel. | 
|  |  | 
|  | Any instances of structs or arrays corresponding to kernel objects that meet | 
|  | the object placement criteria will have their memory addresses placed in a | 
|  | special perfect hash table of kernel objects generated by the 'gperf' tool. | 
|  | When a system call is made and the kernel is presented with a memory address | 
|  | of what may or may not be a valid kernel object, the address can be validated | 
|  | with a constant-time lookup in this table. | 
|  |  | 
|  | Drivers are a special case. All drivers are instances of :c:struct:`device`, but | 
|  | it is important to know what subsystem a driver belongs to so that | 
|  | incorrect operations, such as calling a UART API on a sensor driver object, can | 
|  | be prevented. When a device struct is found, its API pointer is examined to | 
|  | determine what subsystem the driver belongs to. | 
|  |  | 
|  | The table itself maps kernel object memory addresses to instances of | 
|  | :c:struct:`z_object`, which has all the metadata for that object. This | 
|  | includes: | 
|  |  | 
|  | * A bitfield indicating permissions on that object. All threads have a | 
|  | numerical ID assigned to them at build time, used to index the permission | 
|  | bitfield for an object to see if that thread has permission on it. The size | 
|  | of this bitfield is controlled by the :kconfig:option:`CONFIG_MAX_THREAD_BYTES` | 
|  | option and the build system will generate an error if this value is too low. | 
|  | * A type field indicating what kind of object this is, which is some | 
|  | instance of :c:enum:`k_objects`. | 
|  | * A set of flags for that object. This is currently used to track | 
|  | initialization state and whether an object is public or not. | 
|  | * An extra data field. The semantics of this field vary by object type, see | 
|  | the definition of :c:union:`z_object_data`. | 
|  |  | 
|  | Dynamic objects allocated at runtime are tracked in a runtime red/black tree | 
|  | which is used in parallel to the gperf table when validating object pointers. | 
|  |  | 
|  | Supervisor Thread Access Permission | 
|  | *********************************** | 
|  |  | 
|  | Supervisor threads can access any kernel object. However, permissions for | 
|  | supervisor threads are still tracked for two reasons: | 
|  |  | 
|  | * If a supervisor thread calls :c:func:`k_thread_user_mode_enter`, the | 
|  | thread will then run in user mode with any permissions it had been granted | 
|  | (in many cases, by itself) when it was a supervisor thread. | 
|  |  | 
|  | * If a supervisor thread creates a user thread with the | 
|  | :c:macro:`K_INHERIT_PERMS` option, the child thread will be granted the | 
|  | same permissions as the parent thread, except the parent thread object. | 
|  |  | 
|  | User Thread Access Permission | 
|  | ***************************** | 
|  |  | 
|  | By default, when a user thread is created, it will only have access permissions | 
|  | on its own thread object. Other kernel objects by default are not usable. | 
|  | Access to them needs to be explicitly or implicitly granted. There are several | 
|  | ways to do this. | 
|  |  | 
|  | * If a thread is created with the :c:macro:`K_INHERIT_PERMS`, that thread | 
|  | will inherit all the permissions of the parent thread, except the parent | 
|  | thread object. | 
|  |  | 
|  | * A thread that has permission on an object, or is running in supervisor mode, | 
|  | may grant permission on that object to another thread via the | 
|  | :c:func:`k_object_access_grant` API. The convenience pseudo-function | 
|  | :c:func:`k_thread_access_grant` may also be used, which accepts an arbitrary | 
|  | number of pointers to kernel objects and calls | 
|  | :c:func:`k_object_access_grant` on each of them. The thread being granted | 
|  | permission, or the object whose access is being granted, do not need to be | 
|  | in an initialized state. If the caller is from user mode, the caller must | 
|  | have permissions on both the kernel object and the target thread object. | 
|  |  | 
|  | * Supervisor threads may declare a particular kernel object to be a public | 
|  | object, usable by all current and future threads with the | 
|  | :c:func:`k_object_access_all_grant` API. You must assume that any | 
|  | untrusted or exploited code will then be able to access the object. Use | 
|  | this API with caution! | 
|  |  | 
|  | * If a thread was declared statically with :c:macro:`K_THREAD_DEFINE()`, | 
|  | then the :c:macro:`K_THREAD_ACCESS_GRANT()` may be used to grant that thread | 
|  | access to a set of kernel objects at boot time. | 
|  |  | 
|  | Once a thread has been granted access to an object, such access may be | 
|  | removed with the :c:func:`k_object_access_revoke` API. This API is not | 
|  | available to user threads, however user threads may use | 
|  | :c:func:`k_object_release` to relinquish their own permissions on an | 
|  | object. | 
|  |  | 
|  | API calls from supervisor mode to set permissions on kernel objects that are | 
|  | not being tracked by the kernel will be no-ops. Doing the same from user mode | 
|  | will result in a fatal error for the calling thread. | 
|  |  | 
|  | Objects allocated with :c:func:`k_object_alloc` implicitly grant | 
|  | permission on the allocated object to the calling thread. | 
|  |  | 
|  | Initialization State | 
|  | ******************** | 
|  |  | 
|  | Most operations on kernel objects will fail if the object is considered to be | 
|  | in an uninitialized state. The appropriate init function for the object must | 
|  | be performed first. | 
|  |  | 
|  | Some objects will be implicitly initialized at boot: | 
|  |  | 
|  | * Kernel objects that were declared with static initialization macros | 
|  | (such as :c:macro:`K_SEM_DEFINE` for semaphores) will be in an initialized | 
|  | state at build time. | 
|  |  | 
|  | * Device driver objects are considered initialized after their init function | 
|  | is run by the kernel early in the boot process. | 
|  |  | 
|  | If a kernel object is initialized with a private static initializer, the object | 
|  | must have :c:func:`k_object_init` called on it at some point by a supervisor | 
|  | thread, otherwise the kernel will consider the object uninitialized if accessed | 
|  | by a user thread. This is very uncommon, typically only for kernel objects that | 
|  | are embedded within some larger struct and initialized statically. | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | struct foo { | 
|  | struct k_sem sem; | 
|  | ... | 
|  | }; | 
|  |  | 
|  | struct foo my_foo = { | 
|  | .sem = Z_SEM_INITIALIZER(my_foo.sem, 0, 1), | 
|  | ... | 
|  | }; | 
|  |  | 
|  | ... | 
|  | k_object_init(&my_foo.sem); | 
|  | ... | 
|  |  | 
|  |  | 
|  | Creating New Kernel Object Types | 
|  | ******************************** | 
|  |  | 
|  | When implementing new kernel features or driver subsystems, it may be necessary | 
|  | to define some new kernel object types. There are different steps needed | 
|  | for creating core kernel objects and new driver subsystems. | 
|  |  | 
|  | Creating New Core Kernel Objects | 
|  | ================================ | 
|  |  | 
|  | * In ``scripts/build/gen_kobject_list.py``, add the name of the struct to the | 
|  | :py:data:`kobjects` list. | 
|  |  | 
|  | Instances of the new struct should now be tracked. | 
|  |  | 
|  | Creating New Driver Subsystem Kernel Objects | 
|  | ============================================ | 
|  |  | 
|  | All driver instances are :c:struct:`device`. They are differentiated by | 
|  | what API struct they are set to. | 
|  |  | 
|  | * In ``scripts/build/gen_kobject_list.py``, add the name of the API struct for the | 
|  | new subsystem to the :py:data:`subsystems` list. | 
|  |  | 
|  | Driver instances of the new subsystem should now be tracked. | 
|  |  | 
|  | Configuration Options | 
|  | ********************* | 
|  |  | 
|  | Related configuration options: | 
|  |  | 
|  | * :kconfig:option:`CONFIG_USERSPACE` | 
|  | * :kconfig:option:`CONFIG_MAX_THREAD_BYTES` | 
|  |  | 
|  | API Reference | 
|  | ************* | 
|  |  | 
|  | .. doxygengroup:: usermode_apis |