1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright 1996-1998 John D. Polstra. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/kernel.h> 33 #include <sys/systm.h> 34 #include <sys/exec.h> 35 #include <sys/imgact.h> 36 #include <sys/linker.h> 37 #include <sys/proc.h> 38 #include <sys/reg.h> 39 #include <sys/sysent.h> 40 #include <sys/imgact_elf.h> 41 #include <sys/syscall.h> 42 #include <sys/signalvar.h> 43 #include <sys/vnode.h> 44 45 #include <vm/vm.h> 46 #include <vm/pmap.h> 47 #include <vm/vm_param.h> 48 49 #include <machine/elf.h> 50 #include <machine/fpu.h> 51 #include <machine/md_var.h> 52 53 #include "vdso_offsets.h" 54 55 extern const char _binary_elf_vdso_so_1_start[]; 56 extern const char _binary_elf_vdso_so_1_end[]; 57 extern char _binary_elf_vdso_so_1_size; 58 59 struct sysentvec elf64_freebsd_sysvec_la48 = { 60 .sv_size = SYS_MAXSYSCALL, 61 .sv_table = sysent, 62 .sv_transtrap = NULL, 63 .sv_fixup = __elfN(freebsd_fixup), 64 .sv_sendsig = sendsig, 65 .sv_sigcode = _binary_elf_vdso_so_1_start, 66 .sv_szsigcode = (int *)&_binary_elf_vdso_so_1_size, 67 .sv_sigcodeoff = VDSO_SIGCODE_OFFSET, 68 .sv_name = "FreeBSD ELF64", 69 .sv_coredump = __elfN(coredump), 70 .sv_elf_core_osabi = ELFOSABI_FREEBSD, 71 .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR, 72 .sv_elf_core_prepare_notes = __elfN(prepare_notes), 73 .sv_imgact_try = NULL, 74 .sv_minsigstksz = MINSIGSTKSZ, 75 .sv_minuser = VM_MIN_ADDRESS, 76 .sv_maxuser = VM_MAXUSER_ADDRESS_LA48, 77 .sv_usrstack = USRSTACK_LA48, 78 .sv_psstrings = PS_STRINGS_LA48, 79 .sv_psstringssz = sizeof(struct ps_strings), 80 .sv_stackprot = VM_PROT_ALL, 81 .sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs), 82 .sv_copyout_strings = exec_copyout_strings, 83 .sv_setregs = exec_setregs, 84 .sv_fixlimit = NULL, 85 .sv_maxssiz = NULL, 86 .sv_flags = SV_ABI_FREEBSD | SV_ASLR | SV_LP64 | SV_SHP | 87 SV_TIMEKEEP | SV_RNG_SEED_VER | SV_DSO_SIG, 88 .sv_set_syscall_retval = cpu_set_syscall_retval, 89 .sv_fetch_syscall_args = cpu_fetch_syscall_args, 90 .sv_syscallnames = syscallnames, 91 .sv_shared_page_base = SHAREDPAGE_LA48, 92 .sv_shared_page_len = PAGE_SIZE, 93 .sv_schedtail = NULL, 94 .sv_thread_detach = NULL, 95 .sv_trap = NULL, 96 .sv_onexec_old = exec_onexec_old, 97 .sv_onexit = exit_onexit, 98 .sv_set_fork_retval = x86_set_fork_retval, 99 .sv_regset_begin = SET_BEGIN(__elfN(regset)), 100 .sv_regset_end = SET_LIMIT(__elfN(regset)), 101 }; 102 103 struct sysentvec elf64_freebsd_sysvec_la57 = { 104 .sv_size = SYS_MAXSYSCALL, 105 .sv_table = sysent, 106 .sv_transtrap = NULL, 107 .sv_fixup = __elfN(freebsd_fixup), 108 .sv_sendsig = sendsig, 109 .sv_sigcode = _binary_elf_vdso_so_1_start, 110 .sv_szsigcode = (int *)&_binary_elf_vdso_so_1_size, 111 .sv_sigcodeoff = VDSO_SIGCODE_OFFSET, 112 .sv_name = "FreeBSD ELF64", 113 .sv_coredump = __elfN(coredump), 114 .sv_elf_core_osabi = ELFOSABI_FREEBSD, 115 .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR, 116 .sv_elf_core_prepare_notes = __elfN(prepare_notes), 117 .sv_imgact_try = NULL, 118 .sv_minsigstksz = MINSIGSTKSZ, 119 .sv_minuser = VM_MIN_ADDRESS, 120 .sv_maxuser = VM_MAXUSER_ADDRESS_LA57, 121 .sv_usrstack = USRSTACK_LA57, 122 .sv_psstrings = PS_STRINGS_LA57, 123 .sv_psstringssz = sizeof(struct ps_strings), 124 .sv_stackprot = VM_PROT_ALL, 125 .sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs), 126 .sv_copyout_strings = exec_copyout_strings, 127 .sv_setregs = exec_setregs, 128 .sv_fixlimit = NULL, 129 .sv_maxssiz = NULL, 130 .sv_flags = SV_ABI_FREEBSD | SV_ASLR | SV_LP64 | SV_SHP | 131 SV_TIMEKEEP | SV_RNG_SEED_VER | SV_DSO_SIG, 132 .sv_set_syscall_retval = cpu_set_syscall_retval, 133 .sv_fetch_syscall_args = cpu_fetch_syscall_args, 134 .sv_syscallnames = syscallnames, 135 .sv_shared_page_base = SHAREDPAGE_LA57, 136 .sv_shared_page_len = PAGE_SIZE, 137 .sv_schedtail = NULL, 138 .sv_thread_detach = NULL, 139 .sv_trap = NULL, 140 .sv_onexec_old = exec_onexec_old, 141 .sv_onexit = exit_onexit, 142 .sv_set_fork_retval= x86_set_fork_retval, 143 .sv_regset_begin = SET_BEGIN(__elfN(regset)), 144 .sv_regset_end = SET_LIMIT(__elfN(regset)), 145 }; 146 147 static void 148 amd64_init_sysvecs(void *arg) 149 { 150 amd64_lower_shared_page(&elf64_freebsd_sysvec_la48); 151 if (la57) { 152 exec_sysvec_init(&elf64_freebsd_sysvec_la57); 153 exec_sysvec_init_secondary(&elf64_freebsd_sysvec_la57, 154 &elf64_freebsd_sysvec_la48); 155 } else { 156 exec_sysvec_init(&elf64_freebsd_sysvec_la48); 157 } 158 } 159 SYSINIT(elf64_sysvec, SI_SUB_EXEC, SI_ORDER_ANY, amd64_init_sysvecs, NULL); 160 161 void 162 amd64_lower_shared_page(struct sysentvec *sv) 163 { 164 if (hw_lower_amd64_sharedpage != 0) { 165 sv->sv_maxuser -= PAGE_SIZE; 166 sv->sv_shared_page_base -= PAGE_SIZE; 167 sv->sv_usrstack -= PAGE_SIZE; 168 sv->sv_psstrings -= PAGE_SIZE; 169 } 170 } 171 172 static boolean_t 173 freebsd_brand_info_la57_img_compat(struct image_params *imgp, 174 int32_t *osrel __unused, uint32_t *fctl0) 175 { 176 if ((imgp->proc->p_md.md_flags & P_MD_LA57) != 0) 177 return (TRUE); 178 if (fctl0 == NULL || (*fctl0 & NT_FREEBSD_FCTL_LA48) != 0) 179 return (FALSE); 180 if ((imgp->proc->p_md.md_flags & P_MD_LA48) != 0) 181 return (FALSE); 182 return (TRUE); 183 } 184 185 static Elf64_Brandinfo freebsd_brand_info_la48 = { 186 .brand = ELFOSABI_FREEBSD, 187 .machine = EM_X86_64, 188 .compat_3_brand = "FreeBSD", 189 .emul_path = NULL, 190 .interp_path = "/libexec/ld-elf.so.1", 191 .sysvec = &elf64_freebsd_sysvec_la48, 192 .interp_newpath = NULL, 193 .brand_note = &elf64_freebsd_brandnote, 194 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, 195 }; 196 197 static Elf64_Brandinfo freebsd_brand_info_la57 = { 198 .brand = ELFOSABI_FREEBSD, 199 .machine = EM_X86_64, 200 .compat_3_brand = "FreeBSD", 201 .emul_path = NULL, 202 .interp_path = "/libexec/ld-elf.so.1", 203 .sysvec = &elf64_freebsd_sysvec_la57, 204 .interp_newpath = NULL, 205 .brand_note = &elf64_freebsd_brandnote, 206 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, 207 .header_supported = freebsd_brand_info_la57_img_compat, 208 }; 209 210 static void 211 sysinit_register_elf64_brand_entries(void *arg __unused) 212 { 213 /* 214 * _57 must go first so it can either claim the image or hand 215 * it to _48. 216 */ 217 if (la57) 218 elf64_insert_brand_entry(&freebsd_brand_info_la57); 219 elf64_insert_brand_entry(&freebsd_brand_info_la48); 220 } 221 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST, 222 sysinit_register_elf64_brand_entries, NULL); 223 224 static Elf64_Brandinfo freebsd_brand_oinfo = { 225 .brand = ELFOSABI_FREEBSD, 226 .machine = EM_X86_64, 227 .compat_3_brand = "FreeBSD", 228 .emul_path = NULL, 229 .interp_path = "/usr/libexec/ld-elf.so.1", 230 .sysvec = &elf64_freebsd_sysvec_la48, 231 .interp_newpath = NULL, 232 .brand_note = &elf64_freebsd_brandnote, 233 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 234 }; 235 236 SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY, 237 (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_oinfo); 238 239 static Elf64_Brandinfo kfreebsd_brand_info = { 240 .brand = ELFOSABI_FREEBSD, 241 .machine = EM_X86_64, 242 .compat_3_brand = "FreeBSD", 243 .emul_path = NULL, 244 .interp_path = "/lib/ld-kfreebsd-x86-64.so.1", 245 .sysvec = &elf64_freebsd_sysvec_la48, 246 .interp_newpath = NULL, 247 .brand_note = &elf64_kfreebsd_brandnote, 248 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE_MANDATORY 249 }; 250 251 SYSINIT(kelf64, SI_SUB_EXEC, SI_ORDER_ANY, 252 (sysinit_cfunc_t)elf64_insert_brand_entry, &kfreebsd_brand_info); 253 254 void 255 elf64_dump_thread(struct thread *td, void *dst, size_t *off) 256 { 257 void *buf; 258 size_t len; 259 260 len = 0; 261 if (use_xsave) { 262 if (dst != NULL) { 263 fpugetregs(td); 264 len += elf64_populate_note(NT_X86_XSTATE, 265 get_pcb_user_save_td(td), dst, 266 cpu_max_ext_state_size, &buf); 267 *(uint64_t *)((char *)buf + X86_XSTATE_XCR0_OFFSET) = 268 xsave_mask; 269 } else 270 len += elf64_populate_note(NT_X86_XSTATE, NULL, NULL, 271 cpu_max_ext_state_size, NULL); 272 } 273 *off = len; 274 } 275 276 bool 277 elf_is_ifunc_reloc(Elf_Size r_info) 278 { 279 280 return (ELF_R_TYPE(r_info) == R_X86_64_IRELATIVE); 281 } 282 283 /* Process one elf relocation with addend. */ 284 static int 285 elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, 286 int type, bool late_ifunc, elf_lookup_fn lookup) 287 { 288 Elf64_Addr *where, val; 289 Elf32_Addr *where32, val32; 290 Elf_Addr addr; 291 Elf_Addr addend; 292 Elf_Size rtype, symidx; 293 const Elf_Rel *rel; 294 const Elf_Rela *rela; 295 int error; 296 297 switch (type) { 298 case ELF_RELOC_REL: 299 rel = (const Elf_Rel *)data; 300 where = (Elf_Addr *) (relocbase + rel->r_offset); 301 rtype = ELF_R_TYPE(rel->r_info); 302 symidx = ELF_R_SYM(rel->r_info); 303 /* Addend is 32 bit on 32 bit relocs */ 304 switch (rtype) { 305 case R_X86_64_PC32: 306 case R_X86_64_32S: 307 case R_X86_64_PLT32: 308 addend = *(Elf32_Addr *)where; 309 break; 310 default: 311 addend = *where; 312 break; 313 } 314 break; 315 case ELF_RELOC_RELA: 316 rela = (const Elf_Rela *)data; 317 where = (Elf_Addr *) (relocbase + rela->r_offset); 318 addend = rela->r_addend; 319 rtype = ELF_R_TYPE(rela->r_info); 320 symidx = ELF_R_SYM(rela->r_info); 321 break; 322 default: 323 panic("unknown reloc type %d\n", type); 324 } 325 326 if (late_ifunc) { 327 KASSERT(type == ELF_RELOC_RELA, 328 ("Only RELA ifunc relocations are supported")); 329 if (rtype != R_X86_64_IRELATIVE) 330 return (0); 331 } 332 333 switch (rtype) { 334 case R_X86_64_NONE: /* none */ 335 break; 336 337 case R_X86_64_64: /* S + A */ 338 error = lookup(lf, symidx, 1, &addr); 339 val = addr + addend; 340 if (error != 0) 341 return (-1); 342 if (*where != val) 343 *where = val; 344 break; 345 346 case R_X86_64_PC32: /* S + A - P */ 347 case R_X86_64_PLT32: /* L + A - P, L is PLT location for 348 the symbol, which we treat as S */ 349 error = lookup(lf, symidx, 1, &addr); 350 where32 = (Elf32_Addr *)where; 351 val32 = (Elf32_Addr)(addr + addend - (Elf_Addr)where); 352 if (error != 0) 353 return (-1); 354 if (*where32 != val32) 355 *where32 = val32; 356 break; 357 358 case R_X86_64_32S: /* S + A sign extend */ 359 error = lookup(lf, symidx, 1, &addr); 360 val32 = (Elf32_Addr)(addr + addend); 361 where32 = (Elf32_Addr *)where; 362 if (error != 0) 363 return (-1); 364 if (*where32 != val32) 365 *where32 = val32; 366 break; 367 368 case R_X86_64_COPY: /* none */ 369 /* 370 * There shouldn't be copy relocations in kernel 371 * objects. 372 */ 373 printf("kldload: unexpected R_COPY relocation, " 374 "symbol index %ld\n", symidx); 375 return (-1); 376 377 case R_X86_64_GLOB_DAT: /* S */ 378 case R_X86_64_JMP_SLOT: /* XXX need addend + offset */ 379 error = lookup(lf, symidx, 1, &addr); 380 if (error != 0) 381 return (-1); 382 if (*where != addr) 383 *where = addr; 384 break; 385 386 case R_X86_64_RELATIVE: /* B + A */ 387 addr = elf_relocaddr(lf, relocbase + addend); 388 val = addr; 389 if (*where != val) 390 *where = val; 391 break; 392 393 case R_X86_64_IRELATIVE: 394 addr = relocbase + addend; 395 val = ((Elf64_Addr (*)(void))addr)(); 396 if (*where != val) 397 *where = val; 398 break; 399 400 default: 401 printf("kldload: unexpected relocation type %ld, " 402 "symbol index %ld\n", rtype, symidx); 403 return (-1); 404 } 405 return (0); 406 } 407 408 int 409 elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, 410 elf_lookup_fn lookup) 411 { 412 413 return (elf_reloc_internal(lf, relocbase, data, type, false, lookup)); 414 } 415 416 int 417 elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, 418 int type, elf_lookup_fn lookup) 419 { 420 421 return (elf_reloc_internal(lf, relocbase, data, type, false, lookup)); 422 } 423 424 int 425 elf_reloc_late(linker_file_t lf, Elf_Addr relocbase, const void *data, 426 int type, elf_lookup_fn lookup) 427 { 428 429 return (elf_reloc_internal(lf, relocbase, data, type, true, lookup)); 430 } 431 432 int 433 elf_cpu_load_file(linker_file_t lf __unused) 434 { 435 436 return (0); 437 } 438 439 int 440 elf_cpu_unload_file(linker_file_t lf __unused) 441 { 442 443 return (0); 444 } 445 446 int 447 elf_cpu_parse_dynamic(caddr_t loadbase __unused, Elf_Dyn *dynamic __unused) 448 { 449 450 return (0); 451 } 452