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_fixup = __elfN(freebsd_fixup), 63 .sv_sendsig = sendsig, 64 .sv_sigcode = _binary_elf_vdso_so_1_start, 65 .sv_szsigcode = (int *)&_binary_elf_vdso_so_1_size, 66 .sv_sigcodeoff = VDSO_SIGCODE_OFFSET, 67 .sv_name = "FreeBSD ELF64", 68 .sv_coredump = __elfN(coredump), 69 .sv_elf_core_osabi = ELFOSABI_FREEBSD, 70 .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR, 71 .sv_elf_core_prepare_notes = __elfN(prepare_notes), 72 .sv_imgact_try = NULL, 73 .sv_minsigstksz = MINSIGSTKSZ, 74 .sv_minuser = VM_MIN_ADDRESS, 75 .sv_maxuser = VM_MAXUSER_ADDRESS_LA48, 76 .sv_usrstack = USRSTACK_LA48, 77 .sv_psstrings = PS_STRINGS_LA48, 78 .sv_psstringssz = sizeof(struct ps_strings), 79 .sv_stackprot = VM_PROT_ALL, 80 .sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs), 81 .sv_copyout_strings = exec_copyout_strings, 82 .sv_setregs = exec_setregs, 83 .sv_fixlimit = NULL, 84 .sv_maxssiz = NULL, 85 .sv_flags = SV_ABI_FREEBSD | SV_ASLR | SV_LP64 | SV_SHP | 86 SV_TIMEKEEP | SV_RNG_SEED_VER | SV_DSO_SIG, 87 .sv_set_syscall_retval = cpu_set_syscall_retval, 88 .sv_fetch_syscall_args = cpu_fetch_syscall_args, 89 .sv_syscallnames = syscallnames, 90 .sv_shared_page_base = SHAREDPAGE_LA48, 91 .sv_shared_page_len = PAGE_SIZE, 92 .sv_schedtail = NULL, 93 .sv_thread_detach = NULL, 94 .sv_trap = NULL, 95 .sv_onexec_old = exec_onexec_old, 96 .sv_onexit = exit_onexit, 97 .sv_set_fork_retval = x86_set_fork_retval, 98 .sv_regset_begin = SET_BEGIN(__elfN(regset)), 99 .sv_regset_end = SET_LIMIT(__elfN(regset)), 100 }; 101 102 struct sysentvec elf64_freebsd_sysvec_la57 = { 103 .sv_size = SYS_MAXSYSCALL, 104 .sv_table = sysent, 105 .sv_fixup = __elfN(freebsd_fixup), 106 .sv_sendsig = sendsig, 107 .sv_sigcode = _binary_elf_vdso_so_1_start, 108 .sv_szsigcode = (int *)&_binary_elf_vdso_so_1_size, 109 .sv_sigcodeoff = VDSO_SIGCODE_OFFSET, 110 .sv_name = "FreeBSD ELF64", 111 .sv_coredump = __elfN(coredump), 112 .sv_elf_core_osabi = ELFOSABI_FREEBSD, 113 .sv_elf_core_abi_vendor = FREEBSD_ABI_VENDOR, 114 .sv_elf_core_prepare_notes = __elfN(prepare_notes), 115 .sv_imgact_try = NULL, 116 .sv_minsigstksz = MINSIGSTKSZ, 117 .sv_minuser = VM_MIN_ADDRESS, 118 .sv_maxuser = VM_MAXUSER_ADDRESS_LA57, 119 .sv_usrstack = USRSTACK_LA57, 120 .sv_psstrings = PS_STRINGS_LA57, 121 .sv_psstringssz = sizeof(struct ps_strings), 122 .sv_stackprot = VM_PROT_ALL, 123 .sv_copyout_auxargs = __elfN(freebsd_copyout_auxargs), 124 .sv_copyout_strings = exec_copyout_strings, 125 .sv_setregs = exec_setregs, 126 .sv_fixlimit = NULL, 127 .sv_maxssiz = NULL, 128 .sv_flags = SV_ABI_FREEBSD | SV_ASLR | SV_LP64 | SV_SHP | 129 SV_TIMEKEEP | SV_RNG_SEED_VER | SV_DSO_SIG, 130 .sv_set_syscall_retval = cpu_set_syscall_retval, 131 .sv_fetch_syscall_args = cpu_fetch_syscall_args, 132 .sv_syscallnames = syscallnames, 133 .sv_shared_page_base = SHAREDPAGE_LA57, 134 .sv_shared_page_len = PAGE_SIZE, 135 .sv_schedtail = NULL, 136 .sv_thread_detach = NULL, 137 .sv_trap = NULL, 138 .sv_onexec_old = exec_onexec_old, 139 .sv_onexit = exit_onexit, 140 .sv_set_fork_retval= x86_set_fork_retval, 141 .sv_regset_begin = SET_BEGIN(__elfN(regset)), 142 .sv_regset_end = SET_LIMIT(__elfN(regset)), 143 }; 144 145 static void 146 amd64_init_sysvecs(void *arg) 147 { 148 amd64_lower_shared_page(&elf64_freebsd_sysvec_la48); 149 if (la57) { 150 exec_sysvec_init(&elf64_freebsd_sysvec_la57); 151 exec_sysvec_init_secondary(&elf64_freebsd_sysvec_la57, 152 &elf64_freebsd_sysvec_la48); 153 } else { 154 exec_sysvec_init(&elf64_freebsd_sysvec_la48); 155 } 156 } 157 SYSINIT(elf64_sysvec, SI_SUB_EXEC, SI_ORDER_ANY, amd64_init_sysvecs, NULL); 158 159 void 160 amd64_lower_shared_page(struct sysentvec *sv) 161 { 162 if (hw_lower_amd64_sharedpage != 0) { 163 sv->sv_maxuser -= PAGE_SIZE; 164 sv->sv_shared_page_base -= PAGE_SIZE; 165 sv->sv_usrstack -= PAGE_SIZE; 166 sv->sv_psstrings -= PAGE_SIZE; 167 } 168 } 169 170 static boolean_t 171 freebsd_brand_info_la57_img_compat(struct image_params *imgp, 172 int32_t *osrel __unused, uint32_t *fctl0) 173 { 174 if ((imgp->proc->p_md.md_flags & P_MD_LA57) != 0) 175 return (TRUE); 176 if (fctl0 == NULL || (*fctl0 & NT_FREEBSD_FCTL_LA48) != 0) 177 return (FALSE); 178 if ((imgp->proc->p_md.md_flags & P_MD_LA48) != 0) 179 return (FALSE); 180 return (TRUE); 181 } 182 183 static Elf64_Brandinfo freebsd_brand_info_la48 = { 184 .brand = ELFOSABI_FREEBSD, 185 .machine = EM_X86_64, 186 .compat_3_brand = "FreeBSD", 187 .emul_path = NULL, 188 .interp_path = "/libexec/ld-elf.so.1", 189 .sysvec = &elf64_freebsd_sysvec_la48, 190 .interp_newpath = NULL, 191 .brand_note = &elf64_freebsd_brandnote, 192 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, 193 }; 194 195 static Elf64_Brandinfo freebsd_brand_info_la57 = { 196 .brand = ELFOSABI_FREEBSD, 197 .machine = EM_X86_64, 198 .compat_3_brand = "FreeBSD", 199 .emul_path = NULL, 200 .interp_path = "/libexec/ld-elf.so.1", 201 .sysvec = &elf64_freebsd_sysvec_la57, 202 .interp_newpath = NULL, 203 .brand_note = &elf64_freebsd_brandnote, 204 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, 205 .header_supported = freebsd_brand_info_la57_img_compat, 206 }; 207 208 static void 209 sysinit_register_elf64_brand_entries(void *arg __unused) 210 { 211 /* 212 * _57 must go first so it can either claim the image or hand 213 * it to _48. 214 */ 215 if (la57) 216 elf64_insert_brand_entry(&freebsd_brand_info_la57); 217 elf64_insert_brand_entry(&freebsd_brand_info_la48); 218 } 219 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST, 220 sysinit_register_elf64_brand_entries, NULL); 221 222 static Elf64_Brandinfo freebsd_brand_oinfo = { 223 .brand = ELFOSABI_FREEBSD, 224 .machine = EM_X86_64, 225 .compat_3_brand = "FreeBSD", 226 .emul_path = NULL, 227 .interp_path = "/usr/libexec/ld-elf.so.1", 228 .sysvec = &elf64_freebsd_sysvec_la48, 229 .interp_newpath = NULL, 230 .brand_note = &elf64_freebsd_brandnote, 231 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE 232 }; 233 234 SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY, 235 (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_oinfo); 236 237 static Elf64_Brandinfo kfreebsd_brand_info = { 238 .brand = ELFOSABI_FREEBSD, 239 .machine = EM_X86_64, 240 .compat_3_brand = "FreeBSD", 241 .emul_path = NULL, 242 .interp_path = "/lib/ld-kfreebsd-x86-64.so.1", 243 .sysvec = &elf64_freebsd_sysvec_la48, 244 .interp_newpath = NULL, 245 .brand_note = &elf64_kfreebsd_brandnote, 246 .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE_MANDATORY 247 }; 248 249 SYSINIT(kelf64, SI_SUB_EXEC, SI_ORDER_ANY, 250 (sysinit_cfunc_t)elf64_insert_brand_entry, &kfreebsd_brand_info); 251 252 void 253 elf64_dump_thread(struct thread *td, void *dst, size_t *off) 254 { 255 void *buf; 256 size_t len; 257 258 len = 0; 259 if (use_xsave) { 260 if (dst != NULL) { 261 fpugetregs(td); 262 len += elf64_populate_note(NT_X86_XSTATE, 263 get_pcb_user_save_td(td), dst, 264 cpu_max_ext_state_size, &buf); 265 *(uint64_t *)((char *)buf + X86_XSTATE_XCR0_OFFSET) = 266 xsave_mask; 267 } else 268 len += elf64_populate_note(NT_X86_XSTATE, NULL, NULL, 269 cpu_max_ext_state_size, NULL); 270 } 271 *off = len; 272 } 273 274 bool 275 elf_is_ifunc_reloc(Elf_Size r_info) 276 { 277 278 return (ELF_R_TYPE(r_info) == R_X86_64_IRELATIVE); 279 } 280 281 /* Process one elf relocation with addend. */ 282 static int 283 elf_reloc_internal(linker_file_t lf, Elf_Addr relocbase, const void *data, 284 int type, bool late_ifunc, elf_lookup_fn lookup) 285 { 286 Elf64_Addr *where, val; 287 Elf32_Addr *where32, val32; 288 Elf_Addr addr; 289 Elf_Addr addend; 290 Elf_Size rtype, symidx; 291 const Elf_Rel *rel; 292 const Elf_Rela *rela; 293 int error; 294 295 switch (type) { 296 case ELF_RELOC_REL: 297 rel = (const Elf_Rel *)data; 298 where = (Elf_Addr *) (relocbase + rel->r_offset); 299 rtype = ELF_R_TYPE(rel->r_info); 300 symidx = ELF_R_SYM(rel->r_info); 301 /* Addend is 32 bit on 32 bit relocs */ 302 switch (rtype) { 303 case R_X86_64_PC32: 304 case R_X86_64_32S: 305 case R_X86_64_PLT32: 306 addend = *(Elf32_Addr *)where; 307 break; 308 default: 309 addend = *where; 310 break; 311 } 312 break; 313 case ELF_RELOC_RELA: 314 rela = (const Elf_Rela *)data; 315 where = (Elf_Addr *) (relocbase + rela->r_offset); 316 addend = rela->r_addend; 317 rtype = ELF_R_TYPE(rela->r_info); 318 symidx = ELF_R_SYM(rela->r_info); 319 break; 320 default: 321 panic("unknown reloc type %d\n", type); 322 } 323 324 if (late_ifunc) { 325 KASSERT(type == ELF_RELOC_RELA, 326 ("Only RELA ifunc relocations are supported")); 327 if (rtype != R_X86_64_IRELATIVE) 328 return (0); 329 } 330 331 switch (rtype) { 332 case R_X86_64_NONE: /* none */ 333 break; 334 335 case R_X86_64_64: /* S + A */ 336 error = lookup(lf, symidx, 1, &addr); 337 val = addr + addend; 338 if (error != 0) 339 return (-1); 340 if (*where != val) 341 *where = val; 342 break; 343 344 case R_X86_64_PC32: /* S + A - P */ 345 case R_X86_64_PLT32: /* L + A - P, L is PLT location for 346 the symbol, which we treat as S */ 347 error = lookup(lf, symidx, 1, &addr); 348 where32 = (Elf32_Addr *)where; 349 val32 = (Elf32_Addr)(addr + addend - (Elf_Addr)where); 350 if (error != 0) 351 return (-1); 352 if (*where32 != val32) 353 *where32 = val32; 354 break; 355 356 case R_X86_64_32S: /* S + A sign extend */ 357 error = lookup(lf, symidx, 1, &addr); 358 val32 = (Elf32_Addr)(addr + addend); 359 where32 = (Elf32_Addr *)where; 360 if (error != 0) 361 return (-1); 362 if (*where32 != val32) 363 *where32 = val32; 364 break; 365 366 case R_X86_64_COPY: /* none */ 367 /* 368 * There shouldn't be copy relocations in kernel 369 * objects. 370 */ 371 printf("kldload: unexpected R_COPY relocation, " 372 "symbol index %ld\n", symidx); 373 return (-1); 374 375 case R_X86_64_GLOB_DAT: /* S */ 376 case R_X86_64_JMP_SLOT: /* XXX need addend + offset */ 377 error = lookup(lf, symidx, 1, &addr); 378 if (error != 0) 379 return (-1); 380 if (*where != addr) 381 *where = addr; 382 break; 383 384 case R_X86_64_RELATIVE: /* B + A */ 385 addr = elf_relocaddr(lf, relocbase + addend); 386 val = addr; 387 if (*where != val) 388 *where = val; 389 break; 390 391 case R_X86_64_IRELATIVE: 392 addr = relocbase + addend; 393 val = ((Elf64_Addr (*)(void))addr)(); 394 if (*where != val) 395 *where = val; 396 break; 397 398 default: 399 printf("kldload: unexpected relocation type %ld, " 400 "symbol index %ld\n", rtype, symidx); 401 return (-1); 402 } 403 return (0); 404 } 405 406 int 407 elf_reloc(linker_file_t lf, Elf_Addr relocbase, const void *data, int type, 408 elf_lookup_fn lookup) 409 { 410 411 return (elf_reloc_internal(lf, relocbase, data, type, false, lookup)); 412 } 413 414 int 415 elf_reloc_local(linker_file_t lf, Elf_Addr relocbase, const void *data, 416 int type, elf_lookup_fn lookup) 417 { 418 419 return (elf_reloc_internal(lf, relocbase, data, type, false, lookup)); 420 } 421 422 int 423 elf_reloc_late(linker_file_t lf, Elf_Addr relocbase, const void *data, 424 int type, elf_lookup_fn lookup) 425 { 426 427 return (elf_reloc_internal(lf, relocbase, data, type, true, lookup)); 428 } 429 430 int 431 elf_cpu_load_file(linker_file_t lf __unused) 432 { 433 434 return (0); 435 } 436 437 int 438 elf_cpu_unload_file(linker_file_t lf __unused) 439 { 440 441 return (0); 442 } 443 444 int 445 elf_cpu_parse_dynamic(caddr_t loadbase __unused, Elf_Dyn *dynamic __unused) 446 { 447 448 return (0); 449 } 450