diff options
author | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2022-04-07 08:43:00 +0100 |
---|---|---|
committer | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2022-11-22 14:31:25 +0000 |
commit | 0b5f254b4daa0307a898b17eeb994a84e5e1a89f (patch) | |
tree | 04f7adf6897a39169efcb6b1eb7d510a090210a0 /elf/rtld.c | |
parent | 0946809134764e4dc5c69f3fe464d9b3580ee83b (diff) | |
download | glibc-0b5f254b4daa0307a898b17eeb994a84e5e1a89f.tar.gz glibc-0b5f254b4daa0307a898b17eeb994a84e5e1a89f.tar.xz glibc-0b5f254b4daa0307a898b17eeb994a84e5e1a89f.zip |
cheri: elf: Setup per module RX and RW capabilities
_dl_map_segments must use capabilities, this required changes beyond the obvious elfptr_t changes: - Ensure map_end is derived from map_start, - Use strict mmap bounds with MAP_FIXED: c->mapend is aligned up to pagesize which may be out of bounds of l_map_start (covering the load segments, but bounds are not aligned up), so use c->dataend instead. Propagate l_map_start and l_rw_start capabilities of ld.so and exe that come from auxv, and ensure they are not recomputed incorrectly by ld.so. The l_rw_range should exclude the relro region, but in libc.so and ld.so this does not work: symbols are accessed before relro is applied and then the permission should be writable.
Diffstat (limited to 'elf/rtld.c')
-rw-r--r-- | elf/rtld.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/elf/rtld.c b/elf/rtld.c index 205df43bb2..26af99305e 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -474,10 +474,19 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) sizeof GL(dl_rtld_map).l_info); GL(dl_rtld_map).l_mach = info->l.l_mach; GL(dl_rtld_map).l_relocated = 1; +# ifdef __CHERI_PURE_CAPABILITY__ + GL(dl_rtld_map).l_map_start = info->l.l_map_start; + GL(dl_rtld_map).l_rw_start = info->l.l_rw_start; + GL(dl_rtld_map).l_rw_count = info->l.l_rw_count; + for (int i = 0; i < info->l.l_rw_count; i++) + GL(dl_rtld_map).l_rw_range[i] = info->l.l_rw_range[i]; +# endif #endif _dl_setup_hash (&GL(dl_rtld_map)); GL(dl_rtld_map).l_real = &GL(dl_rtld_map); +#ifndef __CHERI_PURE_CAPABILITY__ GL(dl_rtld_map).l_map_start = (ElfW(Addr)) &__ehdr_start; +#endif GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end; GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext; /* Copy the TLS related data if necessary. */ @@ -542,11 +551,16 @@ _dl_start (void *arg) # endif #endif +#ifdef __CHERI_PURE_CAPABILITY__ + elf_machine_rtld_base_setup (&bootstrap_map, arg); + bootstrap_map.l_ld = elf_machine_runtime_dynamic (); +#else /* Figure out the run-time load address of the dynamic linker itself. */ bootstrap_map.l_addr = elf_machine_load_address (); /* Read our own dynamic section and fill in the info array. */ bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic (); +#endif bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION; elf_get_dynamic_info (&bootstrap_map, true, false); @@ -1125,8 +1139,13 @@ rtld_setup_main_map (struct link_map *main_map) main_map->l_map_end = 0; main_map->l_text_end = 0; +#ifndef __CHERI_PURE_CAPABILITY__ /* Perhaps the executable has no PT_LOAD header entries at all. */ main_map->l_map_start = ~0; +#else + /* May be computed already when exe is loaded by ld.so. */ + main_map->l_rw_count = 0; +#endif /* And it was opened directly. */ ++main_map->l_direct_opencount; main_map->l_contiguous = 1; @@ -1205,8 +1224,10 @@ rtld_setup_main_map (struct link_map *main_map) /* Remember where the main program starts in memory. */ mapstart = (main_map->l_addr + (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1))); +#ifndef __CHERI_PURE_CAPABILITY__ if (main_map->l_map_start > mapstart) main_map->l_map_start = mapstart; +#endif if (main_map->l_contiguous && expected_load_address != 0 && expected_load_address != mapstart) @@ -1223,6 +1244,15 @@ rtld_setup_main_map (struct link_map *main_map) segment. */ expected_load_address = ((allocend + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1)); +#ifdef __CHERI_PURE_CAPABILITY__ + if (ph->p_flags & PF_W) + { + assert (main_map->l_rw_count < DL_MAX_RW_COUNT); + main_map->l_rw_range[main_map->l_rw_count].start = mapstart; + main_map->l_rw_range[main_map->l_rw_count].end = allocend; + main_map->l_rw_count++; + } +#endif } break; @@ -1635,6 +1665,14 @@ dl_main (const ElfW(Phdr) *phdr, case AT_EXECFN: av->a_un.a_val = (uintptr_t) _dl_argv[0]; break; +# ifdef __CHERI_PURE_CAPABILITY__ + case AT_CHERI_EXEC_RX_CAP: + av->a_un.a_val = main_map->l_map_start; + break; + case AT_CHERI_EXEC_RW_CAP: + av->a_un.a_val = main_map->l_rw_start; + break; +# endif } #endif @@ -1678,6 +1716,19 @@ dl_main (const ElfW(Phdr) *phdr, /* We delay initializing the path structure until we got the dynamic information for the program. */ + +#ifdef __CHERI_PURE_CAPABILITY__ + for (ElfW(auxv_t) *av = auxv; av->a_type != AT_NULL; av++) + switch (av->a_type) + { + case AT_CHERI_EXEC_RX_CAP: + main_map->l_map_start = av->a_un.a_val; + break; + case AT_CHERI_EXEC_RW_CAP: + main_map->l_rw_start = av->a_un.a_val; + break; + } +#endif } bool has_interp = rtld_setup_main_map (main_map); |