Skip to content

Commit 85709a8

Browse files
committed
lib-manager: validate ELF sizes and offsets
The library manager loads ELF files from the host file-system. Those files have to be only root-writable, so they are relatively trust- worthy - if you're root, it's anyway "game over." Still it's good to verify for corrupt or maniputalte invalid ELF images. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
1 parent 34a8d7c commit 85709a8

1 file changed

Lines changed: 38 additions & 9 deletions

File tree

src/library_manager/lib_manager.c

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#if CONFIG_LLEXT
3838
#include <zephyr/llext/llext.h>
3939
#endif
40+
#include <zephyr/sys/math_extras.h>
4041

4142
#if CONFIG_LIBRARY_AUTH_SUPPORT
4243
#include <auth/intel_auth_api.h>
@@ -129,7 +130,7 @@ static int lib_manager_auth_proc(const void *buffer_data, size_t buffer_size,
129130

130131
#define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE
131132

132-
static int lib_manager_load_data_from_storage(void __sparse_cache *vma, void *s_addr, uint32_t size,
133+
static int lib_manager_load_data_from_storage(void __sparse_cache *vma, void *s_addr, size_t size,
133134
uint32_t flags)
134135
{
135136
/* Region must be first mapped as writable in order to initialize its contents. */
@@ -147,16 +148,26 @@ static int lib_manager_load_data_from_storage(void __sparse_cache *vma, void *s_
147148
return sys_mm_drv_update_region_flags((__sparse_force void *)vma, size, flags);
148149
}
149150

150-
static int lib_manager_load_module(const uint32_t module_id, const struct sof_man_module *const mod)
151+
static int lib_manager_load_module(const struct sof_man_fw_desc *const desc,
152+
const uint32_t module_id, const struct sof_man_module *const mod)
151153
{
152154
struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id);
153155
const uintptr_t load_offset = POINTER_TO_UINT(ctx->base_addr);
156+
size_t lib_size;
157+
size_t file_offset;
154158
void *src;
155159
void __sparse_cache *va_base;
156160
size_t size;
157161
uint32_t flags;
158162
int ret, idx;
159163

164+
/*
165+
* ELF file segment offsets and sizes come from library files, so they
166+
* have to be validated.
167+
*/
168+
if (size_mul_overflow(desc->header.preload_page_count, PAGE_SZ, &lib_size))
169+
return -EOVERFLOW;
170+
160171
for (idx = 0; idx < ARRAY_SIZE(mod->segment); ++idx) {
161172
if (!mod->segment[idx].flags.r.load)
162173
continue;
@@ -168,9 +179,23 @@ static int lib_manager_load_module(const uint32_t module_id, const struct sof_ma
168179
else if (!mod->segment[idx].flags.r.readonly)
169180
flags = SYS_MM_MEM_PERM_RW;
170181

171-
src = UINT_TO_POINTER(mod->segment[idx].file_offset + load_offset);
182+
file_offset = mod->segment[idx].file_offset;
183+
if (size_mul_overflow(mod->segment[idx].flags.r.length, PAGE_SZ, &size)) {
184+
ret = -EOVERFLOW;
185+
goto err;
186+
}
187+
188+
/* Reject segments that would read outside the loaded library image. */
189+
if (file_offset > lib_size || size > lib_size - file_offset) {
190+
tr_err(&lib_manager_tr,
191+
"segment %d out of bounds: file_offset %#zx, size %#zx, total %#zx",
192+
idx, file_offset, size, lib_size);
193+
ret = -ENOSPC;
194+
goto err;
195+
}
196+
197+
src = UINT_TO_POINTER(file_offset + load_offset);
172198
va_base = (void __sparse_cache *)UINT_TO_POINTER(mod->segment[idx].v_base_addr);
173-
size = mod->segment[idx].flags.r.length * PAGE_SZ;
174199
ret = lib_manager_load_data_from_storage(va_base, src, size, flags);
175200
if (ret < 0)
176201
goto err;
@@ -230,7 +255,8 @@ static int lib_manager_load_libcode_modules(const uint32_t module_id)
230255

231256
for (idx = 0; idx < desc->header.num_module_entries; ++idx, ++module_entry) {
232257
if (module_entry->type.lib_code) {
233-
ret = lib_manager_load_module(lib_id << LIB_MANAGER_LIB_ID_SHIFT | idx,
258+
ret = lib_manager_load_module(desc,
259+
lib_id << LIB_MANAGER_LIB_ID_SHIFT | idx,
234260
module_entry);
235261
if (ret < 0)
236262
goto err;
@@ -338,7 +364,8 @@ static int lib_manager_free_module_instance(uint32_t instance_id, const struct s
338364
*
339365
* Function is responsible to allocate module in available free memory and assigning proper address.
340366
*/
341-
static uintptr_t lib_manager_allocate_module(const struct sof_man_module *mod,
367+
static uintptr_t lib_manager_allocate_module(const struct sof_man_fw_desc *const desc,
368+
const struct sof_man_module *mod,
342369
const struct comp_ipc_config *ipc_config,
343370
const void *ipc_specific_config)
344371
{
@@ -351,7 +378,7 @@ static uintptr_t lib_manager_allocate_module(const struct sof_man_module *mod,
351378
if (module_is_llext(mod))
352379
return llext_manager_allocate_module(ipc_config, ipc_specific_config);
353380

354-
ret = lib_manager_load_module(module_id, mod);
381+
ret = lib_manager_load_module(desc, module_id, mod);
355382
if (ret < 0)
356383
return 0;
357384

@@ -424,7 +451,8 @@ static int lib_manager_free_module(const uint32_t component_id)
424451

425452
#define PAGE_SZ 4096 /* equals to MAN_PAGE_SIZE used by rimage */
426453

427-
static uintptr_t lib_manager_allocate_module(const struct comp_ipc_config *ipc_config,
454+
static uintptr_t lib_manager_allocate_module(const struct sof_man_fw_desc *const desc,
455+
const struct comp_ipc_config *ipc_config,
428456
const void *ipc_specific_config, const void **buildinfo)
429457
{
430458
tr_err(&lib_manager_tr, "Dynamic module allocation is not supported");
@@ -644,7 +672,8 @@ static struct comp_dev *lib_manager_module_create(const struct comp_driver *drv,
644672
mod = (const struct sof_man_module *)
645673
((const uint8_t *)desc + SOF_MAN_MODULE_OFFSET(entry_index));
646674

647-
const uintptr_t module_entry_point = lib_manager_allocate_module(mod, config, args->data);
675+
const uintptr_t module_entry_point = lib_manager_allocate_module(desc, mod, config,
676+
args->data);
648677

649678
if (!module_entry_point) {
650679
tr_err(&lib_manager_tr, "lib_manager_allocate_module() failed!");

0 commit comments

Comments
 (0)