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