/* * Copyright (c) 2024 Arduino SA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include LOG_MODULE_DECLARE(llext, CONFIG_LLEXT_LOG_LEVEL); #include "llext_priv.h" ssize_t z_impl_llext_get_fn_table(struct llext *ext, bool is_init, void *buf, size_t buf_size) { size_t table_size; if (!ext) { return -EINVAL; } if (is_init) { table_size = ext->mem_size[LLEXT_MEM_PREINIT] + ext->mem_size[LLEXT_MEM_INIT]; } else { table_size = ext->mem_size[LLEXT_MEM_FINI]; } if (buf) { char *byte_ptr = buf; if (buf_size < table_size) { return -ENOMEM; } if (is_init) { /* setup functions from preinit_array and init_array */ memcpy(byte_ptr, ext->mem[LLEXT_MEM_PREINIT], ext->mem_size[LLEXT_MEM_PREINIT]); memcpy(byte_ptr + ext->mem_size[LLEXT_MEM_PREINIT], ext->mem[LLEXT_MEM_INIT], ext->mem_size[LLEXT_MEM_INIT]); } else { /* cleanup functions from fini_array */ memcpy(byte_ptr, ext->mem[LLEXT_MEM_FINI], ext->mem_size[LLEXT_MEM_FINI]); } /* Sanity check: pointers in this table must map inside the * text region of the extension. If this fails, something went * wrong during the relocation process. * Using "char *" for these simplifies pointer arithmetic. */ const char *text_start = ext->mem[LLEXT_MEM_TEXT]; const char *text_end = text_start + ext->mem_size[LLEXT_MEM_TEXT]; const char **fn_ptrs = buf; for (int i = 0; i < table_size / sizeof(void *); i++) { if (fn_ptrs[i] < text_start || fn_ptrs[i] >= text_end) { LOG_ERR("%s function %i (%p) outside text region", is_init ? "bringup" : "teardown", i, fn_ptrs[i]); return -EFAULT; } } } return table_size; } #ifdef CONFIG_USERSPACE static int ext_is_valid(struct llext *ext, void *arg) { return ext == arg; } static inline ssize_t z_vrfy_llext_get_fn_table(struct llext *ext, bool is_init, void *buf, size_t size) { /* Test that ext matches a loaded extension */ K_OOPS(llext_iterate(ext_is_valid, ext) == 0); if (buf) { /* Test that buf is a valid user-accessible pointer */ K_OOPS(K_SYSCALL_MEMORY_WRITE(buf, size)); } return z_impl_llext_get_fn_table(ext, is_init, buf, size); } #include #endif /* CONFIG_USERSPACE */