Skip to content

Commit

Permalink
core, ldelf: add support for runtime loading of shared libraries
Browse files Browse the repository at this point in the history
This commit prepares the introduction of libdl, a dynamic linking
library which will allow TAs to load shared libraries at run time,
and resolve symbols on demand. It adds the following function to the
system PTA, inspired from the POSIX dlopen() and dlsym():

 - system_dlopen(): takes a UUID and flags. Performs an upcall into
ldelf which then uses the usual system PTA functions to load an map the
requested library into the address space of the calling TA.
 - system_dlsym(): takes a UUID and a symbol name. The symbol is
looked up in the library specified by UUID by calling into ldelf. If
UUID is all zeros, all the mapped binaries are searched.

Signed-off-by: Jerome Forissier <[email protected]>
Reviewed-by: Jens Wiklander <[email protected]>
Acked-by: Etienne Carriere <[email protected]>
  • Loading branch information
jforissier committed Aug 23, 2019
1 parent 791ee55 commit ebef121
Show file tree
Hide file tree
Showing 13 changed files with 417 additions and 49 deletions.
1 change: 1 addition & 0 deletions core/arch/arm/include/kernel/user_ta.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ struct user_ta_ctx {
#ifdef CFG_TA_FTRACE_SUPPORT
uaddr_t ftrace_entry_func;
#endif
uaddr_t dl_entry_func;
uaddr_t ldelf_stack_ptr;
bool is_32bit;
bool is_initializing;
Expand Down
1 change: 1 addition & 0 deletions core/arch/arm/kernel/user_ta.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ static TEE_Result init_with_ldelf(struct tee_ta_session *sess,
utc->ftrace_entry_func = arg->ftrace_entry;
sess->fbuf = arg->fbuf;
#endif
utc->dl_entry_func = arg->dl_entry;

out:
s = tee_ta_pop_current_session();
Expand Down
175 changes: 175 additions & 0 deletions core/arch/arm/pta/system.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
* Copyright (c) 2018-2019, Linaro Limited
*/

#include <assert.h>
#include <crypto/crypto.h>
#include <kernel/handle.h>
#include <kernel/huk_subkey.h>
Expand All @@ -11,10 +12,12 @@
#include <kernel/pseudo_ta.h>
#include <kernel/user_ta.h>
#include <kernel/user_ta_store.h>
#include <ldelf.h>
#include <mm/file.h>
#include <mm/fobj.h>
#include <mm/tee_mmu.h>
#include <pta_system.h>
#include <string.h>
#include <tee_api_defines_extensions.h>
#include <tee_api_defines.h>
#include <util.h>
Expand Down Expand Up @@ -600,6 +603,174 @@ static TEE_Result system_remap(struct tee_ta_session *s, uint32_t param_types,
return res;
}

/* ldelf has the same architecture/register width as the kernel */
#ifdef ARM32
static const bool is_arm32 = true;
#else
static const bool is_arm32;
#endif

static TEE_Result call_ldelf_dlopen(struct user_ta_ctx *utc, TEE_UUID *uuid,
uint32_t flags)
{
uaddr_t usr_stack = utc->ldelf_stack_ptr;
TEE_Result res = TEE_ERROR_GENERIC;
struct dl_entry_arg *arg = NULL;
uint32_t panic_code = 0;
uint32_t panicked = 0;

assert(uuid);

usr_stack -= ROUNDUP(sizeof(*arg), STACK_ALIGNMENT);
arg = (struct dl_entry_arg *)usr_stack;

res = tee_mmu_check_access_rights(utc, TEE_MEMORY_ACCESS_READ |
TEE_MEMORY_ACCESS_WRITE |
TEE_MEMORY_ACCESS_ANY_OWNER,
(uaddr_t)arg, sizeof(*arg));
if (res) {
EMSG("ldelf stack is inaccessible!");
return res;
}

memset(arg, 0, sizeof(*arg));
arg->cmd = LDELF_DL_ENTRY_DLOPEN;
arg->dlopen.uuid = *uuid;
arg->dlopen.flags = flags;

res = thread_enter_user_mode((vaddr_t)arg, 0, 0, 0,
usr_stack, utc->dl_entry_func,
is_arm32, &panicked, &panic_code);
if (panicked) {
EMSG("ldelf dl_entry function panicked");
abort_print_current_ta();
res = TEE_ERROR_TARGET_DEAD;
}
if (!res)
res = arg->ret;

return res;
}

static TEE_Result call_ldelf_dlsym(struct user_ta_ctx *utc, TEE_UUID *uuid,
const char *sym, size_t maxlen, vaddr_t *val)
{
uaddr_t usr_stack = utc->ldelf_stack_ptr;
TEE_Result res = TEE_ERROR_GENERIC;
struct dl_entry_arg *arg = NULL;
uint32_t panic_code = 0;
uint32_t panicked = 0;
size_t len = strnlen(sym, maxlen);

if (len == maxlen)
return TEE_ERROR_BAD_PARAMETERS;

usr_stack -= ROUNDUP(sizeof(*arg) + len + 1, STACK_ALIGNMENT);
arg = (struct dl_entry_arg *)usr_stack;

res = tee_mmu_check_access_rights(utc, TEE_MEMORY_ACCESS_READ |
TEE_MEMORY_ACCESS_WRITE |
TEE_MEMORY_ACCESS_ANY_OWNER,
(uaddr_t)arg,
sizeof(*arg) + len + 1);
if (res) {
EMSG("ldelf stack is inaccessible!");
return res;
}

memset(arg, 0, sizeof(*arg));
arg->cmd = LDELF_DL_ENTRY_DLSYM;
arg->dlsym.uuid = *uuid;
memcpy(arg->dlsym.symbol, sym, len);
arg->dlsym.symbol[len + 1] = '\0';

res = thread_enter_user_mode((vaddr_t)arg, 0, 0, 0,
usr_stack, utc->dl_entry_func,
is_arm32, &panicked, &panic_code);
if (panicked) {
EMSG("ldelf dl_entry function panicked");
abort_print_current_ta();
res = TEE_ERROR_TARGET_DEAD;
}
if (!res) {
res = arg->ret;
if (!res)
*val = arg->dlsym.val;
}

return res;
}

static TEE_Result system_dlopen(struct tee_ta_session *cs, uint32_t param_types,
TEE_Param params[TEE_NUM_PARAMS])
{
uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
TEE_PARAM_TYPE_VALUE_INPUT,
TEE_PARAM_TYPE_NONE,
TEE_PARAM_TYPE_NONE);
TEE_Result res = TEE_ERROR_GENERIC;
struct tee_ta_session *s = NULL;
struct user_ta_ctx *utc = NULL;
TEE_UUID *uuid = NULL;
uint32_t flags = 0;

if (exp_pt != param_types)
return TEE_ERROR_BAD_PARAMETERS;

uuid = params[0].memref.buffer;
if (!uuid || params[0].memref.size != sizeof(*uuid))
return TEE_ERROR_BAD_PARAMETERS;

flags = params[1].value.a;

utc = to_user_ta_ctx(cs->ctx);

s = tee_ta_pop_current_session();
res = call_ldelf_dlopen(utc, uuid, flags);
tee_ta_push_current_session(s);

return res;
}

static TEE_Result system_dlsym(struct tee_ta_session *cs, uint32_t param_types,
TEE_Param params[TEE_NUM_PARAMS])
{
uint32_t exp_pt = TEE_PARAM_TYPES(TEE_PARAM_TYPE_MEMREF_INPUT,
TEE_PARAM_TYPE_MEMREF_INPUT,
TEE_PARAM_TYPE_VALUE_OUTPUT,
TEE_PARAM_TYPE_NONE);
TEE_Result res = TEE_ERROR_GENERIC;
struct tee_ta_session *s = NULL;
struct user_ta_ctx *utc = NULL;
const char *sym = NULL;
TEE_UUID *uuid = NULL;
size_t maxlen = 0;
vaddr_t va = 0;

if (exp_pt != param_types)
return TEE_ERROR_BAD_PARAMETERS;

uuid = params[0].memref.buffer;
if (uuid && params[0].memref.size != sizeof(*uuid))
return TEE_ERROR_BAD_PARAMETERS;

sym = params[1].memref.buffer;
if (!sym)
return TEE_ERROR_BAD_PARAMETERS;
maxlen = params[1].memref.size;

utc = to_user_ta_ctx(cs->ctx);

s = tee_ta_pop_current_session();
res = call_ldelf_dlsym(utc, uuid, sym, maxlen, &va);
tee_ta_push_current_session(s);

if (!res)
reg_pair_from_64(va, &params[2].value.a, &params[2].value.b);

return res;
}

static TEE_Result open_session(uint32_t param_types __unused,
TEE_Param params[TEE_NUM_PARAMS] __unused,
void **sess_ctx)
Expand Down Expand Up @@ -659,6 +830,10 @@ static TEE_Result invoke_command(void *sess_ctx, uint32_t cmd_id,
return system_set_prot(s, param_types, params);
case PTA_SYSTEM_REMAP:
return system_remap(s, param_types, params);
case PTA_SYSTEM_DLOPEN:
return system_dlopen(s, param_types, params);
case PTA_SYSTEM_DLSYM:
return system_dlsym(s, param_types, params);
default:
break;
}
Expand Down
37 changes: 37 additions & 0 deletions ldelf/dl.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: BSD-2-Clause
/*
* Copyright (c) 2019, Linaro Limited
*/
#include <ldelf.h>
#include <string.h>

#include "dl.h"
#include "ta_elf.h"

TEE_Result dlopen_entry(struct dl_entry_arg *arg)
{
TEE_UUID zero = { };

if (arg->dlopen.flags != (RTLD_NOW | RTLD_GLOBAL | RTLD_NODELETE))
return TEE_ERROR_BAD_PARAMETERS;

if (!memcmp(&arg->dlopen.uuid, &zero, sizeof(zero)))
return TEE_SUCCESS;

return ta_elf_add_library(&arg->dlopen.uuid);
}

TEE_Result dlsym_entry(struct dl_entry_arg *arg)
{
struct ta_elf *elf = NULL;
TEE_UUID zero = { };

if (memcmp(&arg->dlsym.uuid, &zero, sizeof(zero))) {
elf = ta_elf_find_elf(&arg->dlsym.uuid);
if (!elf)
return TEE_ERROR_ITEM_NOT_FOUND;
}

return ta_elf_resolve_sym(arg->dlsym.symbol, &arg->dlsym.val, elf);
}

16 changes: 16 additions & 0 deletions ldelf/dl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: BSD-2-Clause */
/*
* Copyright (c) 2019, Linaro Limited
*/

#ifndef LDELF_DL_H
#define LDELF_DL_H

#include <types_ext.h>
#include <ldelf.h>

TEE_Result dlopen_entry(struct dl_entry_arg *arg);
TEE_Result dlsym_entry(struct dl_entry_arg *arg);

#endif /*LDELF_DL_H*/

2 changes: 1 addition & 1 deletion ldelf/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ bool ftrace_init(struct ftrace_buf **fbuf_ptr)
int count = 0;
size_t fbuf_size = 0;

res = ta_elf_resolve_sym("__ftrace_info", &val);
res = ta_elf_resolve_sym("__ftrace_info", &val, NULL);
if (res)
return false;

Expand Down
34 changes: 34 additions & 0 deletions ldelf/include/ldelf.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
* @dump_entry: [out] Dump TA mappings and stack trace
* @ftrace_entry: [out] Dump TA mappings and ftrace buffer
* @fbuf: [out] ftrace buffer pointer
* @dl_entry: [out] Dynamic linking interface (for libdl)
*/
struct ldelf_arg {
TEE_UUID uuid;
Expand All @@ -32,6 +33,7 @@ struct ldelf_arg {
uint64_t stack_ptr;
uint64_t dump_entry;
uint64_t ftrace_entry;
uint64_t dl_entry;
struct ftrace_buf *fbuf;
};

Expand Down Expand Up @@ -66,6 +68,38 @@ struct dump_entry_arg {
} maps[];
};

/*
* struct dl_entry_arg - argument for ldelf_arg::dl_entry()
*/
struct dl_entry_arg {
uint32_t cmd;
TEE_Result ret;
union {
struct {
TEE_UUID uuid; /* in */
uint32_t flags; /* in */
} dlopen;
struct {
TEE_UUID uuid; /* in */
vaddr_t val; /* out */
char symbol[]; /* in */
} dlsym;
};
};

/*
* Values for dl_entry_arg::cmd
*/
#define LDELF_DL_ENTRY_DLOPEN 0
#define LDELF_DL_ENTRY_DLSYM 1

/*
* Values for dl_entry_arg::dlopen::flags
*/
#define RTLD_NOW 2
#define RTLD_GLOBAL 0x100
#define RTLD_NODELETE 0x1000

/*
* ldelf is loaded into memory by TEE Core. BSS is initialized and a
* stack is allocated and supplied in SP register. A struct ldelf_arg
Expand Down
18 changes: 18 additions & 0 deletions ldelf/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <types_ext.h>
#include <util.h>

#include "dl.h"
#include "ftrace.h"
#include "sys.h"
#include "ta_elf.h"
Expand Down Expand Up @@ -102,6 +103,22 @@ static void __noreturn ftrace_dump(void *buf, size_t *blen)
}
#endif

static void __noreturn dl_entry(struct dl_entry_arg *arg)
{
switch (arg->cmd) {
case LDELF_DL_ENTRY_DLOPEN:
arg->ret = dlopen_entry(arg);
break;
case LDELF_DL_ENTRY_DLSYM:
arg->ret = dlsym_entry(arg);
break;
default:
arg->ret = TEE_ERROR_NOT_SUPPORTED;
}

sys_return_cleanup();
}

/*
* ldelf()- Loads ELF into memory
* @arg: Argument passing to/from TEE Core
Expand Down Expand Up @@ -156,6 +173,7 @@ void ldelf(struct ldelf_arg *arg)
#else
arg->dump_entry = 0;
#endif
arg->dl_entry = (vaddr_t)(void *)dl_entry;

sys_return_cleanup();
}
1 change: 1 addition & 0 deletions ldelf/sub.mk
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
global-incdirs-y += include
srcs-$(CFG_ARM32_$(sm)) += start_a32.S
srcs-$(CFG_ARM64_$(sm)) += start_a64.S
srcs-y += dl.c
srcs-y += main.c
srcs-y += sys.c
srcs-y += ta_elf.c
Expand Down
Loading

0 comments on commit ebef121

Please sign in to comment.