Skip to content

Commit

Permalink
c18n: Add LD_COMPARTMENT_FPTR flag
Browse files Browse the repository at this point in the history
Setting this flag causes all function pointers to be wrapped in
trampolines. Binaries MUST be compiled with -cheri-codeptr-relocs for
this to work properly.

This flag is only available as a transition mechanism. It will become
the default in the future and the flag will then be removed.
  • Loading branch information
dpgao committed Jan 26, 2025
1 parent 4694279 commit cbfaa9c
Show file tree
Hide file tree
Showing 8 changed files with 171 additions and 96 deletions.
37 changes: 37 additions & 0 deletions libexec/rtld-elf/aarch64/reloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -898,17 +898,44 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
return (-1);
break;
case R_MORELLO_RELATIVE:
*(uintcap_t *)(void *)where =
init_cap_from_fragment(where, data_cap,
text_rodata_cap,
(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,
text_rodata_cap,
(Elf_Addr)(uintptr_t)obj->relocbase,
rela->r_addend);
#ifdef CHERI_LIB_C18N
if (C18N_FPTR_ENABLED)
*(void **)where = tramp_intern(NULL,
&(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 ||
ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC))
*where = (Elf_Addr)tramp_intern(NULL,
&(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 @@ -976,8 +1003,18 @@ reloc_non_plt(Obj_Entry *obj, Obj_Entry *obj_rtld, int flags,
break;
#endif
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,
&(struct tramp_data) {
.target = (void *)(uintptr_t)*where,
.defobj = obj
});
#endif
break;
case R_AARCH64_NONE:
break;
Expand Down
10 changes: 6 additions & 4 deletions libexec/rtld-elf/aarch64/rtld_machdep.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,22 @@ 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, &(struct tramp_data) { \
(C18N_FPTR_ENABLED ? (InitArrFunc)(_target).value : \
(InitArrFunc)tramp_intern(NULL, &(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))
}))(main_argc, main_argv, environ)

#define call_fini_array_pointer(_obj, _target) \
(((InitFunc)tramp_intern(NULL, &(struct tramp_data) { \
(C18N_FPTR_ENABLED ? (InitFunc)(_target).value : \
(InitFunc)tramp_intern(NULL, &(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
17 changes: 10 additions & 7 deletions libexec/rtld-elf/cheri/cheri_reloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,16 @@ process_r_cheri_capability(Obj_Entry *obj, Elf_Word r_symndx,
symname(obj, r_symndx), obj->path);
return -1;
}
#if defined(CHERI_LIB_C18N) && defined(__riscv)
symval = tramp_intern(NULL, &(struct tramp_data) {
.target = __DECONST(void *, symval),
.defobj = defobj,
.def = def,
.sig = sigtab_get(obj, r_symndx)
});
#ifdef CHERI_LIB_C18N
#ifndef __riscv
if (C18N_FPTR_ENABLED)
#endif
symval = tramp_intern(NULL, &(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 */
Expand Down
96 changes: 42 additions & 54 deletions libexec/rtld-elf/rtld.c
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,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 @@ -821,6 +822,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 @@ -1142,19 +1144,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, &(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 @@ -1225,9 +1216,18 @@ _rtld_bind(Obj_Entry *obj, Elf_Size reloff)
NULL, &lockstate);
if (def == NULL)
rtld_die();
if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC)
if (ELF_ST_TYPE(def->st_info) == STT_GNU_IFUNC) {
target = (uintptr_t)rtld_resolve_ifunc(defobj, def);
else {
#ifdef CHERI_LIB_C18N
if (C18N_FPTR_ENABLED)
target = (uintptr_t)tramp_intern(obj, &(struct tramp_data) {
.target = (void *)target,
.defobj = defobj,
.def = def,
.sig = sigtab_get(obj, ELF_R_SYM(rel->r_info))
});
#endif
} else {
#ifdef __CHERI_PURE_CAPABILITY__
target = (uintptr_t)make_function_pointer(def, defobj);
#ifdef CHERI_LIB_C18N
Expand Down Expand Up @@ -3509,29 +3509,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, &(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, &(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 @@ -4451,22 +4431,28 @@ 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);
#if defined(CHERI_LIB_C18N) && defined(__riscv)
sym = tramp_intern(NULL, &(struct tramp_data) {
.target = sym,
.defobj = defobj,
.def = def
});
#ifdef CHERI_LIB_C18N
#ifndef __riscv
if (C18N_FPTR_ENABLED)
#endif
sym = tramp_intern(NULL, &(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);
#if defined(CHERI_LIB_C18N) && defined(__riscv)
sym = tramp_intern(NULL, &(struct tramp_data) {
.target = sym,
.defobj = defobj,
.def = def
});
#ifdef CHERI_LIB_C18N
#ifndef __riscv
if (C18N_FPTR_ENABLED)
#endif
sym = tramp_intern(NULL, &(struct tramp_data) {
.target = sym,
.defobj = defobj,
.def = def
});
#endif
} else if (ELF_ST_TYPE(def->st_info) == STT_TLS) {
ti.ti_module = defobj->tlsindex;
Expand Down Expand Up @@ -4704,14 +4690,16 @@ dl_iterate_phdr(__dl_iterate_hdr_callback callback, void *param)
error = 0;

#ifdef CHERI_LIB_C18N
callback = tramp_intern(NULL, &(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, &(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 @@ -479,6 +487,7 @@ enum {
LD_COMPARTMENT_UNWIND,
LD_COMPARTMENT_STATS,
LD_COMPARTMENT_SWITCH_COUNT,
LD_COMPARTMENT_FPTR,
#endif
};

Expand Down Expand Up @@ -546,8 +555,21 @@ __END_DECLS
#endif

#ifndef make_rtld_function_pointer
#ifdef CHERI_LIB_C18N
#define make_rtld_function_pointer(target_func) \
tramp_intern(NULL, &(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

0 comments on commit cbfaa9c

Please sign in to comment.