From 4e3e9a618e9015c1ac79d8d094e17315b45ccd00 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 20 Nov 2023 15:45:13 +0100 Subject: [PATCH] llext: protect the global llext list Use an existing mutex to also protect the global llext list. Signed-off-by: Guennadi Liakhovetski --- subsys/llext/llext.c | 49 ++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/subsys/llext/llext.c b/subsys/llext/llext.c index be2507ca63d..1bc56f4d23b 100644 --- a/subsys/llext/llext.c +++ b/subsys/llext/llext.c @@ -23,6 +23,8 @@ static const char ELF_MAGIC[] = {0x7f, 'E', 'L', 'F'}; static sys_slist_t _llext_list = SYS_SLIST_STATIC_INIT(&_llext_list); +static struct k_mutex llext_lock = Z_MUTEX_INITIALIZER(llext_lock); + ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name) { elf_shdr_t *shdr; @@ -50,19 +52,28 @@ ssize_t llext_find_section(struct llext_loader *ldr, const char *search_name) return -ENOENT; } +/* + * Note, that while we protect the global llext list while searching, we release + * the lock before returning the found extension to the caller. Therefore it's + * a responsibility of the caller to protect against races with a freeing + * context when calling this function. + */ struct llext *llext_by_name(const char *name) { - sys_snode_t *node = sys_slist_peek_head(&_llext_list); - struct llext *ext = CONTAINER_OF(node, struct llext, _llext_list); + k_mutex_lock(&llext_lock, K_FOREVER); + + for (sys_snode_t *node = sys_slist_peek_head(&_llext_list); + node != NULL; + node = sys_slist_peek_next(node)) { + struct llext *ext = CONTAINER_OF(node, struct llext, _llext_list); - while (node != NULL) { if (strncmp(ext->name, name, sizeof(ext->name)) == 0) { + k_mutex_unlock(&llext_lock); return ext; } - node = sys_slist_peek_next(node); - ext = CONTAINER_OF(node, struct llext, _llext_list); } + k_mutex_unlock(&llext_lock); return NULL; } @@ -72,6 +83,8 @@ int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg) unsigned int i; int ret = 0; + k_mutex_lock(&llext_lock, K_FOREVER); + for (node = sys_slist_peek_head(&_llext_list), i = 0; node; node = sys_slist_peek_next(node), i++) { @@ -83,6 +96,7 @@ int llext_iterate(int (*fn)(struct llext *ext, void *arg), void *arg) } } + k_mutex_unlock(&llext_lock); return ret; } @@ -873,8 +887,6 @@ out: return ret; } -static struct k_mutex llext_lock = Z_MUTEX_INITIALIZER(llext_lock); - int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, struct llext_load_param *ldr_parm) { @@ -886,28 +898,26 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, if (*ext) { /* The use count is at least 1 */ ret = (*ext)->use_count++; - k_mutex_unlock(&llext_lock); - return ret; + goto out; } - k_mutex_unlock(&llext_lock); - ret = llext_seek(ldr, 0); if (ret != 0) { LOG_ERR("Failed to seek for ELF header"); - return ret; + goto out; } ret = llext_read(ldr, &ehdr, sizeof(ehdr)); if (ret != 0) { LOG_ERR("Failed to read ELF header"); - return ret; + goto out; } /* check whether this is an valid elf file */ if (memcmp(ehdr.e_ident, ELF_MAGIC, sizeof(ELF_MAGIC)) != 0) { LOG_HEXDUMP_ERR(ehdr.e_ident, 16, "Invalid ELF, magic does not match"); - return -EINVAL; + ret = -EINVAL; + goto out; } switch (ehdr.e_type) { @@ -917,7 +927,8 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, *ext = k_heap_alloc(&llext_heap, sizeof(struct llext), K_NO_WAIT); if (*ext == NULL) { LOG_ERR("Not enough memory for extension metadata"); - return -ENOMEM; + ret = -ENOMEM; + goto out; } memset(*ext, 0, sizeof(struct llext)); @@ -926,7 +937,7 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, if (ret < 0) { k_heap_free(&llext_heap, *ext); *ext = NULL; - return ret; + goto out; } strncpy((*ext)->name, name, sizeof((*ext)->name)); @@ -939,10 +950,12 @@ int llext_load(struct llext_loader *ldr, const char *name, struct llext **ext, break; default: LOG_ERR("Unsupported elf file type %x", ehdr.e_type); - return -EINVAL; + ret = -EINVAL; } - return 0; +out: + k_mutex_unlock(&llext_lock); + return ret; } int llext_unload(struct llext **ext)