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

c18n: Support for wrapping function pointers in trampolines #2301

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion lib/csu/aarch64/caprel.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ elf_reloc(const Elf_Rela *rela, void * __capability data_cap,
Elf_Addr addr;
Elf_Addr *where;

if (ELF_R_TYPE(rela->r_info) != R_MORELLO_RELATIVE)
if (ELF_R_TYPE(rela->r_info) != R_MORELLO_RELATIVE &&
ELF_R_TYPE(rela->r_info) != R_MORELLO_FUNC_RELATIVE)
__builtin_trap();

addr = relocbase + rela->r_offset;
Expand Down
2 changes: 2 additions & 0 deletions lib/libkldelf/ef_aarch64.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ ef_aarch64_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,

switch (rtype) {
case R_AARCH64_RELATIVE:
case R_AARCH64_FUNC_RELATIVE:
addr = relbase + addend;
le64enc(where, addr);
break;
Expand All @@ -73,6 +74,7 @@ ef_aarch64_reloc(struct elf_file *ef, const void *reldata, Elf_Type reltype,
le64enc(where, addr);
break;
case R_MORELLO_RELATIVE:
case R_MORELLO_FUNC_RELATIVE:
fragment = (Elf64_Addr *)where;
le64enc(where, fragment[0] + relbase + addend);
break;
Expand Down
79 changes: 66 additions & 13 deletions libexec/rtld-elf/aarch64/reloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,23 @@ _rtld_relocate_nonplt_self(Elf_Dyn *dynp, Elf_Auxinfo *aux)
relalim = (const Elf_Rela *)((const char *)rela + relasz);
pcc = __builtin_cheri_program_counter_get();

/* Self-relocations should all be local, i.e. R_MORELLO_RELATIVE. */
/* Self-relocations should all be local, i.e. relative. */
for (; rela < relalim; rela++) {
if (ELF_R_TYPE(rela->r_info) != R_MORELLO_RELATIVE)
switch (ELF_R_TYPE(rela->r_info)) {
case R_AARCH64_RELATIVE:
case R_AARCH64_FUNC_RELATIVE:
*where = (Elf_Addr)(relocbase + rela->r_addend);
break;
case R_MORELLO_RELATIVE:
case R_MORELLO_FUNC_RELATIVE:
where = (Elf_Addr *)(relocbase + rela->r_offset);
*(uintcap_t *)where = init_cap_from_fragment(where,
relocbase, pcc, (Elf_Addr)(uintptr_t)relocbase,
rela->r_addend);
break;
default:
__builtin_trap();

where = (Elf_Addr *)(relocbase + rela->r_offset);
*(uintcap_t *)where = init_cap_from_fragment(where, relocbase,
pcc, (Elf_Addr)(uintptr_t)relocbase, rela->r_addend);
}
}
}
#endif /* __CHERI_PURE_CAPABILITY__ */
Expand Down Expand Up @@ -732,13 +741,16 @@ reloc_gnu_ifunc_plt(Plt_Entry *plt, int flags, RtldLockState *lockstate)
lock_release(rtld_bind_lock, lockstate);
target = (uintptr_t)rtld_resolve_ifunc(defobj, def);
#ifdef CHERI_LIB_C18N
target = (uintptr_t)tramp_intern(plt, plt->compart_id,
&(struct tramp_data) {
.target = (void *)target,
.defobj = defobj,
.def = def,
.sig = sigtab_get(obj, ELF_R_SYM(rela->r_info))
});
if (!C18N_FPTR_ENABLED)
target = (uintptr_t)tramp_intern(plt,
plt->compart_id,
&(struct tramp_data) {
.target = (void *)target,
.defobj = defobj,
.def = def,
.sig = sigtab_get(obj,
ELF_R_SYM(rela->r_info))
});
#endif
wlock_acquire(rtld_bind_lock, lockstate);
reloc_jmpslot(where, target, defobj, obj,
Expand Down Expand Up @@ -910,10 +922,39 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
(Elf_Addr)(uintptr_t)obj->relocbase,
rela->r_addend);
break;
case R_MORELLO_FUNC_RELATIVE:
*(uintcap_t *)(void *)where =
init_cap_from_fragment(where, data_cap,
pcc_cap(obj, where[0]),
(Elf_Addr)(uintptr_t)obj->relocbase,
rela->r_addend);
#ifdef CHERI_LIB_C18N
if (C18N_FPTR_ENABLED)
*(void **)where = tramp_intern(NULL,
RTLD_COMPART_ID,
&(struct tramp_data) {
.target = *(void **)where,
.defobj = obj
});
#endif
break;
#endif /* __has_feature(capabilities) */
case R_AARCH64_ABS64:
case R_AARCH64_GLOB_DAT:
*where = symval + rela->r_addend;
#ifdef CHERI_LIB_C18N
if (C18N_FPTR_ENABLED &&
ELF_ST_TYPE(def->st_info) == STT_FUNC)
*where = (Elf_Addr)tramp_intern(NULL,
RTLD_COMPART_ID,
&(struct tramp_data) {
.target = (void *)(uintptr_t)*where,
.defobj = defobj,
.def = def,
.sig = sigtab_get(obj,
ELF_R_SYM(rela->r_info))
});
#endif
break;
case R_AARCH64_COPY:
/*
Expand Down Expand Up @@ -983,6 +1024,18 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
case R_AARCH64_RELATIVE:
*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
break;
case R_AARCH64_FUNC_RELATIVE:
*where = (Elf_Addr)(obj->relocbase + rela->r_addend);
#ifdef CHERI_LIB_C18N
if (C18N_FPTR_ENABLED)
*where = (Elf_Addr)tramp_intern(NULL,
RTLD_COMPART_ID,
&(struct tramp_data) {
.target = (void *)(uintptr_t)*where,
.defobj = obj
});
#endif
break;
case R_AARCH64_NONE:
break;
#ifdef __CHERI_PURE_CAPABILITY__
Expand Down
34 changes: 20 additions & 14 deletions libexec/rtld-elf/aarch64/rtld_machdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,22 +86,28 @@ uintptr_t reloc_jmpslot(uintptr_t *where, uintptr_t target,
/* TODO: Per-function captable/PLT/FNDESC support */
#ifdef CHERI_LIB_C18N
#define call_init_array_pointer(_obj, _target) \
(((InitArrFunc)tramp_intern(NULL, RTLD_COMPART_ID, \
&(struct tramp_data) { \
.target = (void *)(_target).value, \
.defobj = _obj, \
.sig = (struct func_sig) { .valid = true, \
.reg_args = 3, .mem_args = false, .ret_args = NONE }\
}))(main_argc, main_argv, environ))
(C18N_FPTR_ENABLED ? (InitArrFunc)(_target).value : \
(InitArrFunc)tramp_intern(NULL, RTLD_COMPART_ID, \
&(struct tramp_data) { \
.target = (void *)(_target).value, \
.defobj = _obj, \
.sig = (struct func_sig) { \
.valid = true, \
.reg_args = 3, .mem_args = false, \
.ret_args = NONE } \
}))(main_argc, main_argv, environ)

#define call_fini_array_pointer(_obj, _target) \
(((InitFunc)tramp_intern(NULL, RTLD_COMPART_ID, \
&(struct tramp_data) { \
.target = (void *)(_target).value, \
.defobj = _obj, \
.sig = (struct func_sig) { .valid = true, \
.reg_args = 0, .mem_args = false, .ret_args = NONE }\
}))())
(C18N_FPTR_ENABLED ? (InitFunc)(_target).value : \
(InitFunc)tramp_intern(NULL, RTLD_COMPART_ID, \
&(struct tramp_data) { \
.target = (void *)(_target).value, \
.defobj = _obj, \
.sig = (struct func_sig) { \
.valid = true, \
.reg_args = 0, .mem_args = false, \
.ret_args = NONE } \
}))()
#else
#define call_init_array_pointer(obj, target) \
(((InitArrFunc)(target).value)(main_argc, main_argv, environ))
Expand Down
10 changes: 10 additions & 0 deletions libexec/rtld-elf/cheri/cheri_reloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,16 @@ process_r_cheri_capability(Obj_Entry *obj, Elf_Word r_symndx,
symname(obj, r_symndx), obj->path);
return -1;
}
#ifdef CHERI_LIB_C18N
if (C18N_FPTR_ENABLED)
symval = tramp_intern(NULL, RTLD_COMPART_ID,
&(struct tramp_data) {
.target = __DECONST(void *, symval),
.defobj = defobj,
.def = def,
.sig = sigtab_get(obj, r_symndx)
});
#endif
} else {
/* Remove execute permissions and set bounds */
symval = cheri_incoffset(make_data_cap(def, defobj), addend);
Expand Down
65 changes: 22 additions & 43 deletions libexec/rtld-elf/rtld.c
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ static struct ld_env_var_desc ld_env_vars[] = {
LD_ENV_DESC(COMPARTMENT_UNWIND, false),
LD_ENV_DESC(COMPARTMENT_STATS, false),
LD_ENV_DESC(COMPARTMENT_SWITCH_COUNT, false),
LD_ENV_DESC(COMPARTMENT_FPTR, false),
#endif
};

Expand Down Expand Up @@ -824,6 +825,7 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
ld_compartment_unwind = ld_get_env_var(LD_COMPARTMENT_UNWIND);
ld_compartment_stats = ld_get_env_var(LD_COMPARTMENT_STATS);
ld_compartment_switch_count = ld_get_env_var(LD_COMPARTMENT_SWITCH_COUNT);
ld_compartment_fptr = ld_get_env_var(LD_COMPARTMENT_FPTR) != NULL;
/*
* DISABLE takes precedence over ENABLE.
*/
Expand Down Expand Up @@ -1149,20 +1151,8 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
dbg("transferring control to program entry point = " PTR_FMT, obj_main->entry);

/* Return the exit procedure and the program entry point. */
if (rtld_exit_ptr == NULL) {
if (rtld_exit_ptr == NULL)
rtld_exit_ptr = make_rtld_function_pointer(rtld_exit);
#ifdef CHERI_LIB_C18N
rtld_exit_ptr = tramp_intern(NULL, RTLD_COMPART_ID,
&(struct tramp_data) {
.target = rtld_exit_ptr,
.defobj = &obj_rtld,
.sig = (struct func_sig) {
.valid = true,
.reg_args = 0, .mem_args = false, .ret_args = NONE
}
});
#endif
}
*exit_proc = rtld_exit_ptr;
*objp = obj_main;

Expand Down Expand Up @@ -3665,31 +3655,9 @@ objlist_call_init(Objlist *list, RtldLockState *lockstate)
lock_release(rtld_bind_lock, lockstate);
if (reg != NULL) {
func_ptr_type exit_ptr = make_rtld_function_pointer(rtld_exit);
#ifdef CHERI_LIB_C18N
exit_ptr = tramp_intern(NULL, RTLD_COMPART_ID,
&(struct tramp_data) {
.target = exit_ptr,
.defobj = &obj_rtld,
.sig = (struct func_sig) {
.valid = true,
.reg_args = 0, .mem_args = false, .ret_args = NONE
}
});
#endif
dbg("Calling __libc_atexit(rtld_exit (" PTR_FMT "))", (void*)exit_ptr);
reg(exit_ptr);
rtld_exit_ptr = make_rtld_function_pointer(rtld_nop_exit);
#ifdef CHERI_LIB_C18N
rtld_exit_ptr = tramp_intern(NULL, RTLD_COMPART_ID,
&(struct tramp_data) {
.target = rtld_exit_ptr,
.defobj = &obj_rtld,
.sig = (struct func_sig) {
.valid = true,
.reg_args = 0, .mem_args = false, .ret_args = NONE
}
});
#endif
}

/*
Expand Down Expand Up @@ -4615,6 +4583,14 @@ do_dlsym(void *handle, const char *name, void *retaddr, const Ver_Entry *ve,
if (ELF_ST_TYPE(def->st_info) == STT_FUNC) {
sym = __DECONST(void*, make_function_pointer(def, defobj));
dbg("dlsym(%s) is function: " PTR_FMT, name, sym);
#ifdef CHERI_LIB_C18N
if (C18N_FPTR_ENABLED)
sym = tramp_intern(NULL, RTLD_COMPART_ID, &(struct tramp_data) {
.target = sym,
.defobj = defobj,
.def = def
});
#endif
} else if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
sym = rtld_resolve_ifunc(defobj, def);
dbg("dlsym(%s) is ifunc. Resolved to: " PTR_FMT, name, sym);
Expand Down Expand Up @@ -4854,14 +4830,17 @@ dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param)
error = 0;

#ifdef CHERI_LIB_C18N
callback = tramp_intern(NULL, RTLD_COMPART_ID, &(struct tramp_data) {
.target = callback,
.defobj = obj_from_addr(callback),
.sig = (struct func_sig) {
.valid = true,
.reg_args = 3, .mem_args = false, .ret_args = ONE
}
});
if (!C18N_FPTR_ENABLED)
callback = tramp_intern(NULL, RTLD_COMPART_ID,
&(struct tramp_data) {
.target = callback,
.defobj = obj_from_addr(callback),
.sig = (struct func_sig) {
.valid = true,
.reg_args = 3, .mem_args = false,
.ret_args = ONE
}
});
#endif

wlock_acquire(rtld_phdr_lock, &phdr_lockstate);
Expand Down
22 changes: 22 additions & 0 deletions libexec/rtld-elf/rtld.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@
extern bool ld_compartment_enable;

#define C18N_ENABLED ld_compartment_enable

#ifdef __aarch64__
extern bool ld_compartment_fptr;

#define C18N_FPTR_ENABLED ld_compartment_fptr
#else
#define C18N_FPTR_ENABLED 0
#endif
#endif

#include "rtld_lock.h"
Expand Down Expand Up @@ -506,6 +514,7 @@ enum {
LD_COMPARTMENT_UNWIND,
LD_COMPARTMENT_STATS,
LD_COMPARTMENT_SWITCH_COUNT,
LD_COMPARTMENT_FPTR,
#endif
};

Expand Down Expand Up @@ -578,8 +587,21 @@ __END_DECLS
#endif

#ifndef make_rtld_function_pointer
#ifdef CHERI_LIB_C18N
#define make_rtld_function_pointer(target_func) \
tramp_intern(NULL, RTLD_COMPART_ID, &(struct tramp_data) { \
.target = &target_func, \
.defobj = &obj_rtld, \
.sig = (struct func_sig) { \
.valid = true, \
.reg_args = 0, .mem_args = false, \
.ret_args = NONE \
} \
})
#else
#define make_rtld_function_pointer(target_func) (&target_func)
#endif
#endif
#ifndef make_rtld_local_function_pointer
#define make_rtld_local_function_pointer(target_func) (&target_func)
#endif
Expand Down
Loading