Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[backport v2.2] Restore socket descriptor permission management #27175

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 25 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ set(SYSCALL_LIST_H_TARGET syscall_list_h_target)
set(DRIVER_VALIDATION_H_TARGET driver_validation_h_target)
set(KOBJ_TYPES_H_TARGET kobj_types_h_target)
set(LINKER_SCRIPT_TARGET linker_script_target)

set(PARSE_SYSCALLS_TARGET parse_syscalls_target)

define_property(GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT BRIEF_DOCS " " FULL_DOCS " ")
set_property( GLOBAL PROPERTY PROPERTY_OUTPUT_FORMAT elf32-little${ARCH}) # BFD format
Expand Down Expand Up @@ -492,8 +492,9 @@ if(EXISTS ${CMAKE_BINARY_DIR}/zephyr_modules.txt)
set(ZEPHYR_CURRENT_MODULE_DIR)
endif()

set(syscall_list_h ${CMAKE_CURRENT_BINARY_DIR}/include/generated/syscall_list.h)
set(syscalls_json ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/syscalls.json)
set(syscall_list_h ${CMAKE_CURRENT_BINARY_DIR}/include/generated/syscall_list.h)
set(syscalls_json ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/syscalls.json)
set(struct_tags_json ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/struct_tags.json)

# The syscalls subdirs txt file is constructed by python containing a list of folders to use for
# dependency handling, including empty folders.
Expand Down Expand Up @@ -585,16 +586,22 @@ endforeach()
add_custom_command(
OUTPUT
${syscalls_json}
${struct_tags_json}
COMMAND
${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/parse_syscalls.py
--include ${ZEPHYR_BASE}/include # Read files from this dir
--include ${ZEPHYR_BASE}/drivers # For net sockets
--include ${ZEPHYR_BASE}/subsys/net # More net sockets
${parse_syscalls_include_args} # Read files from these dirs also
--json-file ${syscalls_json} # Write this file
--json-file ${syscalls_json} # Write this file
--tag-struct-file ${struct_tags_json} # Write subsystem list to this file
DEPENDS ${syscalls_subdirs_trigger} ${PARSE_SYSCALLS_HEADER_DEPENDS}
)

add_custom_target(${SYSCALL_LIST_H_TARGET} DEPENDS ${syscall_list_h})
add_custom_target(${PARSE_SYSCALLS_TARGET}
DEPENDS ${syscalls_json} ${struct_tags_json})

# 64-bit systems do not require special handling of 64-bit system call
# parameters or return values, indicate this to the system call boilerplate
Expand All @@ -614,18 +621,25 @@ add_custom_command(OUTPUT include/generated/syscall_dispatch.c ${syscall_list_h}
--syscall-list ${syscall_list_h}
${SYSCALL_LONG_REGISTERS_ARG}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS ${syscalls_json}
DEPENDS ${PARSE_SYSCALLS_TARGET}
)

# This is passed into all calls to the gen_kobject_list.py script.
set(gen_kobject_list_include_args --include ${struct_tags_json})

set(DRV_VALIDATION ${PROJECT_BINARY_DIR}/include/generated/driver-validation.h)
add_custom_command(
OUTPUT ${DRV_VALIDATION}
COMMAND
${PYTHON_EXECUTABLE}
${ZEPHYR_BASE}/scripts/gen_kobject_list.py
--validation-output ${DRV_VALIDATION}
${gen_kobject_list_include_args}
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
DEPENDS ${ZEPHYR_BASE}/scripts/gen_kobject_list.py
DEPENDS
${ZEPHYR_BASE}/scripts/gen_kobject_list.py
${PARSE_SYSCALLS_TARGET}
${struct_tags_json}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_target(${DRIVER_VALIDATION_H_TARGET} DEPENDS ${DRV_VALIDATION})
Expand Down Expand Up @@ -941,8 +955,11 @@ if(CONFIG_USERSPACE)
${GEN_KOBJ_LIST}
--kernel $<TARGET_FILE:${ZEPHYR_PREBUILT_EXECUTABLE}>
--gperf-output ${OBJ_LIST}
${gen_kobject_list_include_args}
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
DEPENDS ${ZEPHYR_PREBUILT_EXECUTABLE}
DEPENDS
${ZEPHYR_PREBUILT_EXECUTABLE}
${PARSE_SYSCALLS_TARGET}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_target(obj_list DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OBJ_LIST})
Expand Down Expand Up @@ -972,7 +989,7 @@ if(CONFIG_USERSPACE)
${PROCESS_GPERF}
-i ${OUTPUT_SRC_PRE}
-o ${OUTPUT_SRC}
-p "struct _k_object"
-p "struct z_object"
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
DEPENDS output_src_pre ${OUTPUT_SRC_PRE}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
Expand Down
5 changes: 4 additions & 1 deletion cmake/kobj.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ function(gen_kobj gen_dir_out)
--kobj-types-output ${KOBJ_TYPES}
--kobj-otype-output ${KOBJ_OTYPE}
--kobj-size-output ${KOBJ_SIZE}
${gen_kobject_list_include_args}
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
DEPENDS $ENV{ZEPHYR_BASE}/scripts/gen_kobject_list.py
DEPENDS
$ENV{ZEPHYR_BASE}/scripts/gen_kobject_list.py
${PARSE_SYSCALLS_TARGET}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
add_custom_target(${KOBJ_TYPES_H_TARGET} DEPENDS ${KOBJ_TYPES} ${KOBJ_OTYPE})
Expand Down
4 changes: 2 additions & 2 deletions doc/guides/documentation/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ For example::

.. code-block:: c

struct _k_object {
struct z_object {
char *name;
u8_t perms[CONFIG_MAX_THREAD_BYTES];
u8_t type;
Expand All @@ -412,7 +412,7 @@ This would be rendered as:

.. code-block:: c

struct _k_object {
struct z_object {
char *name;
u8_t perms[CONFIG_MAX_THREAD_BYTES];
u8_t type;
Expand Down
7 changes: 3 additions & 4 deletions doc/reference/usermode/kernelobjects.rst
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ 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:type:`struct _k_object`, which has all the metadata for that object. This
:c:type:`struct z_object`, which has all the metadata for that object. This
includes:

* A bitfield indicating permissions on that object. All threads have a
Expand All @@ -128,9 +128,8 @@ includes:
instance of :cpp: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. This is currently used for thread stack objects
to denote how large the stack is, and for thread objects to indicate
the thread's index in kernel object permission bitfields.
* An extra data field. The semantics of this field vary by object type, see
the definition of :c:type:`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.
Expand Down
2 changes: 1 addition & 1 deletion drivers/modem/modem_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
extern "C" {
#endif

struct modem_socket {
__net_socket struct modem_socket {
sa_family_t family;
enum net_sock_type type;
enum net_ip_protocol ip_proto;
Expand Down
54 changes: 51 additions & 3 deletions include/kernel.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ struct k_poll_signal;
struct k_mem_domain;
struct k_mem_partition;
struct k_futex;
struct z_futex_data;

/**
* @brief Kernel Object Types
Expand Down Expand Up @@ -165,14 +166,32 @@ enum k_objects {
*/

#ifdef CONFIG_USERSPACE
/* Object extra data. Only some objects use this, determined by object type */
union z_object_data {
/* Backing mutex for K_OBJ_SYS_MUTEX */
struct k_mutex *mutex;

/* Numerical thread ID for K_OBJ_THREAD */
unsigned int thread_id;

/* Stack buffer size for K_OBJ__THREAD_STACK_ELEMENT */
size_t stack_size;

/* Futex wait queue and spinlock for K_OBJ_FUTEX */
struct z_futex_data *futex_data;

/* All other objects */
int unused;
};

/* Table generated by gperf, these objects are retrieved via
* z_object_find() */
struct _k_object {
struct z_object {
void *name;
u8_t perms[CONFIG_MAX_THREAD_BYTES];
u8_t type;
u8_t flags;
uintptr_t data;
union z_object_data data;
} __packed __aligned(4);

struct _k_object_assignment {
Expand Down Expand Up @@ -337,6 +356,27 @@ void k_object_access_all_grant(void *object);
__syscall void *k_object_alloc(enum k_objects otype);

#ifdef CONFIG_DYNAMIC_OBJECTS
/**
* Allocate memory and install as a generic kernel object
*
* This is a low-level function to allocate some memory, and register that
* allocated memory in the kernel object lookup tables with type K_OBJ_ANY.
* Initialization state and thread permissions will be cleared. The
* returned z_object's data value will be uninitialized.
*
* Most users will want to use k_object_alloc() instead.
*
* Memory allocated will be drawn from the calling thread's reasource pool
* and may be freed later by passing the actual object pointer (found
* in the returned z_object's 'name' member) to k_object_free().
*
* @param size Size of the allocated object
* @return NULL on insufficient memory
* @return A pointer to the associated z_object that is installed in the
* kernel object tables
*/
struct z_object *z_dynamic_object_create(size_t size);

/**
* Free a kernel object previously allocated with k_object_alloc()
*
Expand All @@ -355,12 +395,20 @@ static inline void *z_impl_k_object_alloc(enum k_objects otype)

return NULL;
}

static inline struct z_object *z_dynamic_object_create(size_t size)
{
ARG_UNUSED(size);

return NULL;
}

/**
* @brief Free an object
*
* @param obj
*/
static inline void k_obj_free(void *obj)
static inline void k_object_free(void *obj)
{
ARG_UNUSED(obj);
}
Expand Down
2 changes: 1 addition & 1 deletion include/net/net_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ struct tls_context;
* If there is no such source address there, the packet cannot be sent
* anyway. This saves 12 bytes / context in IPv6.
*/
struct net_context {
__net_socket struct net_context {
/** User data.
*
* First member of the structure to let users either have user data
Expand Down
43 changes: 43 additions & 0 deletions include/net/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,44 @@ struct zsock_addrinfo {
char _ai_canonname[DNS_MAX_NAME_SIZE + 1];
};

/**
* @brief Obtain a file descriptor's associated net context
*
* With CONFIG_USERSPACE enabled, the kernel's object permission system
* must apply to socket file descriptors. When a socket is opened, by default
* only the caller has permission, access by other threads will fail unless
* they have been specifically granted permission.
*
* This is achieved by tagging data structure definitions that implement the
* underlying object associated with a network socket file descriptor with
* '__net_socket`. All pointers to instances of these will be known to the
* kernel as kernel objects with type K_OBJ_NET_SOCKET.
*
* This API is intended for threads that need to grant access to the object
* associated with a particular file descriptor to another thread. The
* returned pointer represents the underlying K_OBJ_NET_SOCKET and
* may be passed to APIs like k_object_access_grant().
*
* In a system like Linux which has the notion of threads running in processes
* in a shared virtual address space, this sort of management is unnecessary as
* the scope of file descriptors is implemented at the process level.
*
* However in Zephyr the file descriptor scope is global, and MPU-based systems
* are not able to implement a process-like model due to the lack of memory
* virtualization hardware. They use discrete object permissions and memory
* domains instead to define thread access scope.
*
* User threads will have no direct access to the returned object
* and will fault if they try to access its memory; the pointer can only be
* used to make permission assignment calls, which follow exactly the rules
* for other kernel objects like device drivers and IPC.
*
* @param sock file descriptor
* @return pointer to associated network socket object, or NULL if the
* file descriptor wasn't valid or the caller had no access permission
*/
__syscall void *zsock_get_context_object(int sock);

/**
* @brief Create a network socket
*
Expand All @@ -156,6 +194,11 @@ struct zsock_addrinfo {
* This function is also exposed as ``socket()``
* if :option:`CONFIG_NET_SOCKETS_POSIX_NAMES` is defined.
* @endrst
*
* If CONFIG_USERSPACE is enabled, the caller will be granted access to the
* context object associated with the returned file descriptor.
* @see zsock_get_context_object()
*
*/
__syscall int zsock_socket(int family, int type, int proto);

Expand Down
Loading