Index: sys/kern/link_elf.c =================================================================== --- sys/kern/link_elf.c +++ sys/kern/link_elf.c @@ -736,9 +736,46 @@ #endif #undef LS_PADDING +/* + * Apply the specified protection to the loadable segments of a preloaded linker + * file. + */ static int -link_elf_link_preload(linker_class_t cls, - const char* filename, linker_file_t *result) +preload_protect(elf_file_t ef, vm_prot_t prot) +{ +#ifdef __amd64__ + Elf_Ehdr *hdr; + Elf_Phdr *phdr, *phlimit; + vm_prot_t nprot; + int error; + + error = 0; + hdr = (Elf_Ehdr *)ef->address; + phdr = (Elf_Phdr *)(ef->address + hdr->e_phoff); + phlimit = phdr + hdr->e_phnum; + for (; phdr < phlimit; phdr++) { + if (phdr->p_type != PT_LOAD) + continue; + + nprot = prot | VM_PROT_READ; + if ((phdr->p_flags & PF_W) != 0) + nprot |= VM_PROT_WRITE; + if ((phdr->p_flags & PF_X) != 0) + nprot |= VM_PROT_EXECUTE; + error = pmap_change_prot((vm_offset_t)ef->address + + phdr->p_vaddr, round_page(phdr->p_memsz), nprot); + if (error != 0) + break; + } + return (error); +#else + return (0); +#endif +} + +static int +link_elf_link_preload(linker_class_t cls, const char *filename, + linker_file_t *result) { Elf_Addr *ctors_addrp; Elf_Size *ctors_sizep; @@ -798,6 +835,8 @@ if (error == 0) error = parse_vnet(ef); #endif + if (error == 0) + error = preload_protect(ef, VM_PROT_ALL); if (error != 0) { linker_file_unload(lf, LINKER_UNLOAD_FORCE); return (error); @@ -815,6 +854,8 @@ ef = (elf_file_t) lf; error = relocate_file(ef); + if (error == 0) + error = preload_protect(ef, VM_PROT_NONE); if (error != 0) return (error); (void)link_elf_preload_parse_symbols(ef); @@ -1274,6 +1315,7 @@ static void link_elf_unload_preload(linker_file_t file) { + if (file->pathname != NULL) preload_delete_name(file->pathname); } Index: sys/kern/link_elf_obj.c =================================================================== --- sys/kern/link_elf_obj.c +++ sys/kern/link_elf_obj.c @@ -193,7 +193,6 @@ linker_add_class(&link_elf_class); } - SYSINIT(link_elf_obj, SI_SUB_KLD, SI_ORDER_SECOND, link_elf_init, NULL); static void @@ -208,6 +207,15 @@ if (start == end) return; + if (ef->preloaded) { +#ifdef __amd64__ + error = pmap_change_prot(start, end - start, prot); + KASSERT(error == 0, + ("link_elf_protect_range: pmap_change_prot() returned %d", + error)); +#endif + return; + } error = vm_map_protect(kernel_map, start, end, prot, FALSE); KASSERT(error == KERN_SUCCESS, ("link_elf_protect_range: vm_map_protect() returned %d", error)); @@ -555,6 +563,14 @@ goto out; } + /* + * The file needs to be writeable and executable while applying + * relocations. Mapping protections are applied once relocation + * processing is complete. + */ + link_elf_protect_range(ef, (vm_offset_t)ef->address, + round_page((vm_offset_t)ef->address + ef->lf.size), VM_PROT_ALL); + /* Local intra-module relocations */ error = link_elf_reloc_local(lf, false); if (error != 0) @@ -607,7 +623,9 @@ return (error); #endif - /* Invoke .ctors */ + /* Apply protections now that relocation processing is complete. */ + link_elf_protect(ef); + link_elf_invoke_ctors(lf->ctors_addr, lf->ctors_size); return (0); } Index: sys/vm/vm_kern.c =================================================================== --- sys/vm/vm_kern.c +++ sys/vm/vm_kern.c @@ -834,6 +834,14 @@ end = trunc_page(start + size); start = round_page(start); +#ifdef __amd64__ + /* + * Preloaded files do not have execute permissions by default on amd64. + * Restore the default permissions to ensure that the direct map alias + * is updated. + */ + pmap_change_prot(start, end - start, VM_PROT_RW); +#endif for (va = start; va < end; va += PAGE_SIZE) { pa = pmap_kextract(va); m = PHYS_TO_VM_PAGE(pa);