From: John Marino Date: Tue, 10 May 2011 19:17:07 +0000 (+0200) Subject: kernel ELF: Reimplement Elf Branding, .note.ABI-tag X-Git-Tag: v2.12.0~645 X-Git-Url: https://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/315b8b8b77c1101b25fef36483a8d0474a1befb2 kernel ELF: Reimplement Elf Branding, .note.ABI-tag Static executables built with the GNU gold linker are not recognized as valid ELF binaries, although the same binaries built by ld linker did work. It was suspected that gold was keying off the .note.ABI-tag. Primitive support for this tag had been added years ago from NetBSD, and later Corecode disabled it except for ELF program headers. I removed all the .note.ABI-tag support that had been added after DragonFly forked from FreeBSD and ported over FreeBSD's branding logic and .note.ABI-tag support. In particular, the branding logic a lot cleaner now, and will easily support 32-bit binaries on x86_64 should this feature arise in DragonFly in the future. With these changes, gold can now build static executables that are recognized and execute. The Linuxolator had to be modified to work with the new branding scheme as well (i386 only). --- diff --git a/sys/cpu/i386/misc/elf_machdep.c b/sys/cpu/i386/misc/elf_machdep.c index 5394f1d5b1..d24fe8fb1b 100644 --- a/sys/cpu/i386/misc/elf_machdep.c +++ b/sys/cpu/i386/misc/elf_machdep.c @@ -23,13 +23,55 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/i386/i386/elf_machdep.c,v 1.8 1999/12/21 11:14:02 eivind Exp $ - * $DragonFly: src/sys/cpu/i386/misc/elf_machdep.c,v 1.4 2006/12/23 00:27:02 swildner Exp $ */ #include +#include #include #include +#include +#include +#include +#include +#include #include +#include + +static struct sysentvec elf32_dragonfly_sysvec = { + .sv_size = SYS_MAXSYSCALL, + .sv_table = sysent, + .sv_mask = -1, + .sv_sigsize = 0, + .sv_sigtbl = NULL, + .sv_errsize = 0, + .sv_errtbl = NULL, + .sv_transtrap = NULL, + .sv_fixup = __elfN(dragonfly_fixup), + .sv_sendsig = sendsig, + .sv_sigcode = sigcode, + .sv_szsigcode = &szsigcode, + .sv_prepsyscall = NULL, + .sv_name = "DragonFly ELF32", + .sv_coredump = __elfN(coredump), + .sv_imgact_try = NULL, + .sv_minsigstksz = MINSIGSTKSZ, +}; + +static Elf32_Brandinfo dragonfly_brand_info = { + .brand = ELFOSABI_NONE, + .machine = EM_386, + .compat_3_brand = "DragonFly", + .emul_path = NULL, + .interp_path = "/usr/libexec/ld-elf.so.2", + .sysvec = &elf32_dragonfly_sysvec, + .interp_newpath = NULL, + .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, + .brand_note = &elf32_dragonfly_brandnote, +}; + +SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, + (sysinit_cfunc_t) elf32_insert_brand_entry, + &dragonfly_brand_info); /* Process one elf relocation with addend. */ static int diff --git a/sys/cpu/x86_64/misc/elf_machdep.c b/sys/cpu/x86_64/misc/elf_machdep.c index 474b2b48a2..5774bc801c 100644 --- a/sys/cpu/x86_64/misc/elf_machdep.c +++ b/sys/cpu/x86_64/misc/elf_machdep.c @@ -26,9 +26,52 @@ */ #include +#include #include #include +#include +#include +#include +#include +#include #include +#include + +static struct sysentvec elf64_dragonfly_sysvec = { + .sv_size = SYS_MAXSYSCALL, + .sv_table = sysent, + .sv_mask = -1, + .sv_sigsize = 0, + .sv_sigtbl = NULL, + .sv_errsize = 0, + .sv_errtbl = NULL, + .sv_transtrap = NULL, + .sv_fixup = __elfN(dragonfly_fixup), + .sv_sendsig = sendsig, + .sv_sigcode = sigcode, + .sv_szsigcode = &szsigcode, + .sv_prepsyscall = NULL, + .sv_name = "DragonFly ELF64", + .sv_coredump = __elfN(coredump), + .sv_imgact_try = NULL, + .sv_minsigstksz = MINSIGSTKSZ, +}; + +static Elf64_Brandinfo dragonfly_brand_info = { + .brand = ELFOSABI_NONE, + .machine = EM_X86_64, + .compat_3_brand = "DragonFly", + .emul_path = NULL, + .interp_path = "/usr/libexec/ld-elf.so.2", + .sysvec = &elf64_dragonfly_sysvec, + .interp_newpath = NULL, + .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, + .brand_note = &elf64_dragonfly_brandnote, +}; + +SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_FIRST, + (sysinit_cfunc_t) elf64_insert_brand_entry, + &dragonfly_brand_info); /* Process one elf relocation with addend. */ static int diff --git a/sys/emulation/linux/i386/linux_sysvec.c b/sys/emulation/linux/i386/linux_sysvec.c index a6845293ea..ced609e41d 100644 --- a/sys/emulation/linux/i386/linux_sysvec.c +++ b/sys/emulation/linux/i386/linux_sysvec.c @@ -222,9 +222,6 @@ elf_linux_fixup(register_t **stack_base, struct image_params *imgp) pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); - if (args->trace) { - AUXARGS_ENTRY(pos, AT_DEBUG, 1); - } if (args->execfd != -1) { AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); } @@ -791,120 +788,108 @@ exec_linux_imgact_try(struct image_params *imgp) return(error); } -struct sysentvec linux_sysvec = { - LINUX_SYS_MAXSYSCALL, - linux_sysent, - 0xffffffff, - LINUX_SIGTBLSZ, - bsd_to_linux_signal, - ELAST + 1, - bsd_to_linux_errno, - translate_traps, - linux_fixup, - linux_sendsig, - linux_sigcode, - &linux_szsigcode, - linux_prepsyscall, - "Linux a.out", - NULL, - exec_linux_imgact_try, - LINUX_MINSIGSTKSZ +struct sysentvec linux32_sysvec = { + .sv_size = LINUX_SYS_MAXSYSCALL, + .sv_table = linux_sysent, + .sv_mask = 0xffffffff, + .sv_sigsize = LINUX_SIGTBLSZ, + .sv_sigtbl = bsd_to_linux_signal, + .sv_errsize = ELAST + 1, + .sv_errtbl = bsd_to_linux_errno, + .sv_transtrap = translate_traps, + .sv_fixup = linux_fixup, + .sv_sendsig = linux_sendsig, + .sv_sigcode = linux_sigcode, + .sv_szsigcode = &linux_szsigcode, + .sv_prepsyscall = linux_prepsyscall, + .sv_name = "Linux a.out", + .sv_coredump = NULL, + .sv_imgact_try = exec_linux_imgact_try, + .sv_minsigstksz = LINUX_MINSIGSTKSZ }; -struct sysentvec elf_linux_sysvec = { - LINUX_SYS_MAXSYSCALL, - linux_sysent, - 0xffffffff, - LINUX_SIGTBLSZ, - bsd_to_linux_signal, - ELAST + 1, - bsd_to_linux_errno, - translate_traps, - elf_linux_fixup, - linux_sendsig, - linux_sigcode, - &linux_szsigcode, - linux_prepsyscall, -#if defined(__x86_64__) - "Linux ELF64", -#else - "Linux ELF32", -#endif - elf_coredump, - exec_linux_imgact_try, - LINUX_MINSIGSTKSZ +struct sysentvec elf32_linux_sysvec = { + .sv_size = LINUX_SYS_MAXSYSCALL, + .sv_table = linux_sysent, + .sv_mask = 0xffffffff, + .sv_sigsize = LINUX_SIGTBLSZ, + .sv_sigtbl = bsd_to_linux_signal, + .sv_errsize = ELAST + 1, + .sv_errtbl = bsd_to_linux_errno, + .sv_transtrap = translate_traps, + .sv_fixup = elf_linux_fixup, + .sv_sendsig = linux_sendsig, + .sv_sigcode = linux_sigcode, + .sv_szsigcode = &linux_szsigcode, + .sv_prepsyscall = linux_prepsyscall, + .sv_name = "Linux ELF32", + .sv_coredump = elf32_coredump, + .sv_imgact_try = exec_linux_imgact_try, + .sv_minsigstksz = LINUX_MINSIGSTKSZ }; -static int linux_match_abi_note(const Elf_Note *abi_note); -static int linux_match_suse_note(const Elf_Note *abi_note); - -static Elf32_Brandinfo linux_brand = { - ELFOSABI_LINUX, - "Linux", - linux_match_abi_note, - "/compat/linux", - "/lib/ld-linux.so.1", - &elf_linux_sysvec - }; - -static Elf32_Brandinfo linux_glibc2brand = { - ELFOSABI_LINUX, - "Linux", - linux_match_abi_note, - "/compat/linux", - "/lib/ld-linux.so.2", - &elf_linux_sysvec - }; - -static Elf32_Brandinfo linux_suse_brand = { - ELFOSABI_LINUX, - "Linux", - linux_match_suse_note, - "/compat/linux", - "/lib/ld-linux.so.2", - &elf_linux_sysvec - }; +static Elf_Brandinfo *linux_brand_list[MAX_BRANDS]; -Elf32_Brandinfo *linux_brandlist[] = { - &linux_brand, - &linux_glibc2brand, - &linux_suse_brand, - NULL - }; +static const char GNU_ABI_VENDOR[] = "GNU"; +static const char SUSE_ABI_VENDOR[] = "SuSE"; -static int -linux_match_abi_note(const Elf_Note *abi_note) -{ - const char *abi_name = (const char *) - ((const uint8_t *)abi_note + sizeof(*abi_note)); - const uint32_t *descr = (const uint32_t *) - ((const uint8_t *)abi_name + abi_note->n_namesz); - - if (abi_note->n_namesz != sizeof("GNU")) - return(FALSE); - if (memcmp(abi_name, "GNU", sizeof("GNU"))) - return(FALSE); - if (abi_note->n_descsz < sizeof(uint32_t)) - return(FALSE); - - if (*descr != 0) - return(FALSE); - return(TRUE); -} +static Elf_Brandnote linux32_generic_brandnote = { + .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), + .hdr.n_descsz = sizeof(int32_t), + .hdr.n_type = 1, + .vendor = GNU_ABI_VENDOR, + .flags = 0, +}; -static int -linux_match_suse_note(const Elf_Note *abi_note) -{ - const char *abi_name = (const char *) - ((const uint8_t *)abi_note + sizeof(*abi_note)); +static Elf_Brandnote linux32_suse_brandnote = { + .hdr.n_namesz = sizeof(SUSE_ABI_VENDOR), + .hdr.n_descsz = sizeof(int32_t), + .hdr.n_type = 1, + .vendor = SUSE_ABI_VENDOR, + .flags = 0, +}; - if (abi_note->n_namesz != sizeof("SuSE")) - return(FALSE); - if (memcmp(abi_name, "SuSE", sizeof("SuSE"))) - return(FALSE); +static Elf32_Brandinfo linux32_brand = { + .brand = ELFOSABI_LINUX, + .machine = EM_386, + .compat_3_brand = "Linux", + .emul_path = "/compat/linux", + .interp_path = "/lib/ld-linux.so.1", + .sysvec = &elf32_linux_sysvec, + .interp_newpath = NULL, + .flags = BI_CAN_EXEC_DYN, + .brand_note = &linux32_generic_brandnote, +}; - return(TRUE); -} +static Elf32_Brandinfo linux32_glibc2_brand = { + .brand = ELFOSABI_LINUX, + .machine = EM_386, + .compat_3_brand = "Linux", + .emul_path = "/compat/linux", + .interp_path = "/lib/ld-linux.so.2", + .sysvec = &elf32_linux_sysvec, + .interp_newpath = NULL, + .flags = BI_CAN_EXEC_DYN, + .brand_note = &linux32_generic_brandnote, +}; + +static Elf32_Brandinfo linux32_suse_brand = { + .brand = ELFOSABI_LINUX, + .machine = EM_386, + .compat_3_brand = "Linux", + .emul_path = "/compat/linux", + .interp_path = "/lib/ld-linux.so.2", + .sysvec = &elf32_linux_sysvec, + .interp_newpath = NULL, + .flags = BI_CAN_EXEC_DYN, + .brand_note = &linux32_suse_brandnote, +}; + +Elf32_Brandinfo *linux_brandlist[] = { + &linux32_brand, + &linux32_glibc2_brand, + &linux32_suse_brand, +}; static int linux_elf_modevent(module_t mod, int type, void *data) @@ -918,7 +903,7 @@ linux_elf_modevent(module_t mod, int type, void *data) case MOD_LOAD: for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; ++brandinfo) - if (elf_insert_brand_entry(*brandinfo) < 0) + if (elf32_insert_brand_entry(*brandinfo) < 0) error = EINVAL; if (error == 0) { if (bootverbose) @@ -936,12 +921,12 @@ linux_elf_modevent(module_t mod, int type, void *data) case MOD_UNLOAD: for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; ++brandinfo) - if (elf_brand_inuse(*brandinfo)) + if (elf32_brand_inuse(*brandinfo)) error = EBUSY; if (error == 0) { for (brandinfo = &linux_brandlist[0]; *brandinfo != NULL; ++brandinfo) - if (elf_remove_brand_entry(*brandinfo) < 0) + if (elf32_remove_brand_entry(*brandinfo) < 0) error = EINVAL; } if (error == 0) { diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 099d1db56e..528409f6dd 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -1,4 +1,5 @@ /*- + * Copyright (c) 2000 David O'Brien * Copyright (c) 1995-1996 Søren Schmidt * Copyright (c) 1996 Peter Wemm * All rights reserved. @@ -27,7 +28,6 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/kern/imgact_elf.c,v 1.73.2.13 2002/12/28 19:49:41 dillon Exp $ - * $DragonFly: src/sys/kern/imgact_elf.c,v 1.55 2008/08/17 17:21:36 nth Exp $ */ #include @@ -68,137 +68,87 @@ #include #include #include -#define OLD_EI_BRAND 8 -__ElfType(Brandinfo); -__ElfType(Auxargs); +#define OLD_EI_BRAND 8 +#define truncps(va,ps) ((va) & ~(ps - 1)) +#define aligned(a,t) (truncps((u_long)(a), sizeof(t)) == (u_long)(a)) -static int elf_check_header (const Elf_Ehdr *hdr); -static int elf_freebsd_fixup (register_t **stack_base, - struct image_params *imgp); -static int elf_load_file (struct proc *p, const char *file, u_long *addr, +static int __elfN(check_header)(const Elf_Ehdr *hdr); +static Elf_Brandinfo *__elfN(get_brandinfo)(struct image_params *imgp, + const char *interp, int32_t *osrel); +static int __elfN(load_file)(struct proc *p, const char *file, u_long *addr, u_long *entry); -static int elf_load_section (struct proc *p, +static int __elfN(load_section)(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot); -static int exec_elf_imgact (struct image_params *imgp); +static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp); +static boolean_t __elfN(check_note)(struct image_params *imgp, + Elf_Brandnote *checknote, int32_t *osrel); -static int elf_trace = 0; -SYSCTL_INT(_debug, OID_AUTO, elf_trace, CTLFLAG_RW, &elf_trace, 0, ""); static int elf_legacy_coredump = 0; -SYSCTL_INT(_debug, OID_AUTO, elf_legacy_coredump, CTLFLAG_RW, - &elf_legacy_coredump, 0, - "Do not dump inaccessible mappings, legacy coredump mode"); - -static int dragonfly_match_abi_note(const Elf_Note *); -static int freebsd_match_abi_note(const Elf_Note *); - -static struct sysentvec elf_freebsd_sysvec = { - SYS_MAXSYSCALL, - sysent, - -1, - 0, - 0, - 0, - 0, - 0, - elf_freebsd_fixup, - sendsig, - sigcode, - &szsigcode, - 0, +static int __elfN(fallback_brand) = -1; #if defined(__x86_64__) - "FreeBSD ELF64", -#else - "FreeBSD ELF32", +SYSCTL_NODE(_kern, OID_AUTO, elf64, CTLFLAG_RW, 0, ""); +SYSCTL_INT(_debug, OID_AUTO, elf64_legacy_coredump, CTLFLAG_RW, + &elf_legacy_coredump, 0, "legacy coredump mode"); +SYSCTL_INT(_kern_elf64, OID_AUTO, fallback_brand, CTLFLAG_RW, + &elf64_fallback_brand, 0, "ELF64 brand of last resort"); +TUNABLE_INT("kern.elf64.fallback_brand", &elf64_fallback_brand); +#else /* i386 assumed */ +SYSCTL_NODE(_kern, OID_AUTO, elf32, CTLFLAG_RW, 0, ""); +SYSCTL_INT(_debug, OID_AUTO, elf32_legacy_coredump, CTLFLAG_RW, + &elf_legacy_coredump, 0, "legacy coredump mode"); +SYSCTL_INT(_kern_elf32, OID_AUTO, fallback_brand, CTLFLAG_RW, + &elf32_fallback_brand, 0, "ELF32 brand of last resort"); +TUNABLE_INT("kern.elf32.fallback_brand", &elf32_fallback_brand); #endif - elf_coredump, - NULL, - MINSIGSTKSZ -}; -static Elf_Brandinfo freebsd_brand_info = { - ELFOSABI_FREEBSD, - "FreeBSD", - freebsd_match_abi_note, - "", - "/usr/libexec/ld-elf.so.1", - &elf_freebsd_sysvec - }; - -static Elf_Brandinfo dragonfly_brand_info = { - ELFOSABI_NONE, - "DragonFly", - dragonfly_match_abi_note, - "", - "/usr/libexec/ld-elf.so.2", - &elf_freebsd_sysvec - }; - -static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = { - &dragonfly_brand_info, - &freebsd_brand_info, - NULL, NULL, NULL, - NULL, NULL, NULL - }; +static Elf_Brandinfo *elf_brand_list[MAX_BRANDS]; -static int -freebsd_match_abi_note(const Elf_Note *abi_note) -{ - const char *abi_name = (const char *) - ((const uint8_t *)abi_note + sizeof(*abi_note)); - - if (abi_note->n_namesz != sizeof("FreeBSD")) - return(FALSE); - if (memcmp(abi_name, "FreeBSD", sizeof("FreeBSD"))) - return(FALSE); - return(TRUE); -} +static const char DRAGONFLY_ABI_VENDOR[] = "DragonFly"; -static int -dragonfly_match_abi_note(const Elf_Note *abi_note) -{ - const char *abi_name = (const char *) - ((const uint8_t *)abi_note + sizeof(*abi_note)); - - if (abi_note->n_namesz != sizeof("DragonFly")) - return(FALSE); - if (memcmp(abi_name, "DragonFly", sizeof("DragonFly"))) - return(FALSE); - return(TRUE); -} +Elf_Brandnote __elfN(dragonfly_brandnote) = { + .hdr.n_namesz = sizeof(DRAGONFLY_ABI_VENDOR), + .hdr.n_descsz = sizeof(int32_t), + .hdr.n_type = 1, + .vendor = DRAGONFLY_ABI_VENDOR, + .flags = BN_CAN_FETCH_OSREL, +}; int -elf_insert_brand_entry(Elf_Brandinfo *entry) +__elfN(insert_brand_entry)(Elf_Brandinfo *entry) { int i; - for (i=1; ip_sysent == info->entry->sysvec) { info->rval = TRUE; - return(-1); + return (-1); } - return(0); + return (0); } static int -elf_check_header(const Elf_Ehdr *hdr) +__elfN(check_header)(const Elf_Ehdr *hdr) { + Elf_Brandinfo *bi; + int i; + if (!IS_ELF(*hdr) || hdr->e_ident[EI_CLASS] != ELF_TARG_CLASS || hdr->e_ident[EI_DATA] != ELF_TARG_DATA || @@ -248,100 +201,25 @@ elf_check_header(const Elf_Ehdr *hdr) hdr->e_phentsize != sizeof(Elf_Phdr) || hdr->e_ehsize != sizeof(Elf_Ehdr) || hdr->e_version != ELF_TARG_VER) - return ENOEXEC; - - if (!ELF_MACHINE_OK(hdr->e_machine)) - return ENOEXEC; - - return 0; -} - -static Elf_Brandinfo * -elf_check_abi_note(struct image_params *imgp, const Elf_Phdr *ph) -{ - Elf_Brandinfo *match = NULL; - const Elf_Note *tmp_note; - struct lwbuf *lwb; - struct lwbuf lwb_cache; - const char *page; - char *data = NULL; - Elf_Off off; - size_t firstoff; - size_t len; - size_t firstlen; - - len = ph->p_filesz; - off = ph->p_offset; - - firstoff = off & PAGE_MASK; - firstlen = PAGE_SIZE - firstoff; - - if (len < sizeof(Elf_Note) || len > PAGE_SIZE) - return NULL; /* ENOEXEC? */ - - lwb = &lwb_cache; - if (exec_map_page(imgp, off >> PAGE_SHIFT, &lwb, &page)) - return NULL; + return (ENOEXEC); /* - * Crosses page boundary? Is that allowed? + * Make sure we have at least one brand for this machine. */ - if (firstlen < len) { - data = kmalloc(len, M_TEMP, M_WAITOK); - - bcopy(page + firstoff, data, firstlen); - exec_unmap_page(lwb); - lwb = &lwb_cache; - if (exec_map_page(imgp, (off >> PAGE_SHIFT) + 1, &lwb, &page)) { - kfree(data, M_TEMP); - return NULL; - } - bcopy(page, data + firstlen, len - firstlen); - tmp_note = (void *)data; - } else { - tmp_note = (const void *)(page + firstoff); - } - - while (len >= sizeof(Elf_Note)) { - int i; - size_t nlen = roundup(tmp_note->n_namesz, sizeof(Elf_Word)) + - roundup(tmp_note->n_descsz, sizeof(Elf_Word)) + - sizeof(Elf_Note); - - if (nlen > len) + for (i = 0; i < MAX_BRANDS; i++) { + bi = elf_brand_list[i]; + if (bi != NULL && bi->machine == hdr->e_machine) break; - - if (tmp_note->n_type != 1) - goto next; - - for (i = 0; i < MAX_BRANDS; i++) { - Elf_Brandinfo *bi = elf_brand_list[i]; - - if (bi != NULL && bi->match_abi_note != NULL && - bi->match_abi_note(tmp_note)) { - match = bi; - break; - } - } - - if (match != NULL) - break; - -next: - len -= nlen; - tmp_note += nlen; } + if (i == MAX_BRANDS) + return (ENOEXEC); - if (data != NULL) - kfree(data, M_TEMP); - exec_unmap_page(lwb); - - return (match); + return (0); } static int -elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, +__elfN(load_section)(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot) { @@ -405,12 +283,12 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_map_entry_release(count); if (rv != KERN_SUCCESS) { vm_object_deallocate(object); - return EINVAL; + return (EINVAL); } /* we can stop now if we've covered it all */ if (memsz == filsz) { - return 0; + return (0); } } @@ -438,7 +316,7 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_map_unlock(&vmspace->vm_map); vm_map_entry_release(count); if (rv != KERN_SUCCESS) { - return EINVAL; + return (EINVAL); } } @@ -467,7 +345,7 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, vm_map_protect(&vmspace->vm_map, map_addr, map_addr + map_len, prot, FALSE); - return error; + return (error); } /* @@ -483,7 +361,7 @@ elf_load_section(struct proc *p, struct vmspace *vmspace, struct vnode *vp, * the entry point for the loaded file. */ static int -elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) +__elfN(load_file)(struct proc *p, const char *file, u_long *addr, u_long *entry) { struct { struct nlookupdata nd; @@ -547,7 +425,7 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) goto fail; hdr = (const Elf_Ehdr *)imgp->image_header; - if ((error = elf_check_header(hdr)) != 0) + if ((error = __elfN(check_header)(hdr)) != 0) goto fail; if (hdr->e_type == ET_DYN) rbase = *addr; @@ -558,8 +436,8 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) goto fail; } - /* Only support headers that fit within first page for now - * (multiplication of two Elf_Half fields will not overflow) */ + /* Only support headers that fit within first page for now */ + /* (multiplication of two Elf_Half fields will not overflow) */ if ((hdr->e_phoff > PAGE_SIZE) || (hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE - hdr->e_phoff) { error = ENOEXEC; @@ -578,7 +456,7 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) if (phdr[i].p_flags & PF_R) prot |= VM_PROT_READ; - error = elf_load_section( + error = __elfN(load_section)( p, vmspace, imgp->vp, phdr[i].p_offset, (caddr_t)phdr[i].p_vaddr + @@ -597,7 +475,7 @@ elf_load_file(struct proc *p, const char *file, u_long *addr, u_long *entry) } } *addr = base_addr; - *entry=(unsigned long)hdr->e_entry + rbase; + *entry = (unsigned long)hdr->e_entry + rbase; fail: if (imgp->firstpage) @@ -608,24 +486,79 @@ fail: } kfree(tempdata, M_TEMP); - return error; + return (error); } -/* - * non static, as it can be overridden by start_init() - */ -int fallback_elf_brand = -1; -SYSCTL_INT(_kern, OID_AUTO, fallback_elf_brand, CTLFLAG_RW, - &fallback_elf_brand, -1, - "ELF brand of last resort"); +static Elf_Brandinfo * +__elfN(get_brandinfo)(struct image_params *imgp, const char *interp, + int32_t *osrel) +{ + const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header; + Elf_Brandinfo *bi; + boolean_t ret; + int i; + + /* We support four types of branding -- (1) the ELF EI_OSABI field + * that SCO added to the ELF spec, (2) FreeBSD 3.x's traditional string + * branding within the ELF header, (3) path of the `interp_path' field, + * and (4) the ".note.ABI-tag" ELF section. + */ + + /* Look for an ".note.ABI-tag" ELF section */ + for (i = 0; i < MAX_BRANDS; i++) { + bi = elf_brand_list[i]; + + if (bi == NULL) + continue; + if (hdr->e_machine == bi->machine && (bi->flags & + (BI_BRAND_NOTE|BI_BRAND_NOTE_MANDATORY)) != 0) { + ret = __elfN(check_note)(imgp, bi->brand_note, osrel); + if (ret) + return (bi); + } + } + + /* If the executable has a brand, search for it in the brand list. */ + for (i = 0; i < MAX_BRANDS; i++) { + bi = elf_brand_list[i]; + + if (bi == NULL || bi->flags & BI_BRAND_NOTE_MANDATORY) + continue; + if (hdr->e_machine == bi->machine && + (hdr->e_ident[EI_OSABI] == bi->brand || + strncmp((const char *)&hdr->e_ident[OLD_EI_BRAND], + bi->compat_3_brand, strlen(bi->compat_3_brand)) == 0)) + return (bi); + } + + /* Lacking a known brand, search for a recognized interpreter. */ + if (interp != NULL) { + for (i = 0; i < MAX_BRANDS; i++) { + bi = elf_brand_list[i]; + + if (bi == NULL || bi->flags & BI_BRAND_NOTE_MANDATORY) + continue; + if (hdr->e_machine == bi->machine && + strcmp(interp, bi->interp_path) == 0) + return (bi); + } + } -static int can_exec_dyn = 1; -SYSCTL_INT(_kern, OID_AUTO, elf_exec_dyn, CTLFLAG_RW, - &can_exec_dyn, 1, - "ELF: can exec shared libraries"); + /* Lacking a recognized interpreter, try the default brand */ + for (i = 0; i < MAX_BRANDS; i++) { + bi = elf_brand_list[i]; + + if (bi == NULL || bi->flags & BI_BRAND_NOTE_MANDATORY) + continue; + if (hdr->e_machine == bi->machine && + __elfN(fallback_brand) == bi->brand) + return (bi); + } + return (NULL); +} static int -exec_elf_imgact(struct image_params *imgp) +__CONCAT(exec_,__elfN(imgact))(struct image_params *imgp) { const Elf_Ehdr *hdr = (const Elf_Ehdr *) imgp->image_header; const Elf_Phdr *phdr; @@ -636,21 +569,23 @@ exec_elf_imgact(struct image_params *imgp) u_long text_addr = 0, data_addr = 0; u_long seg_size, seg_addr; u_long addr, entry = 0, proghdr = 0; + int32_t osrel = 0; int error, i; - const char *interp = NULL; - const Elf_Note *abi_note = NULL; - Elf_Brandinfo *brand_info = NULL; + const char *interp = NULL, *newinterp = NULL; + Elf_Brandinfo *brand_info; char *path; error = 0; /* * Do we have a valid ELF header ? - * We allow execution of ET_EXEC and, if kern.elf_exec_dyn is 1, ET_DYN. + * + * Only allow ET_EXEC & ET_DYN here, reject ET_DYN later if a particular + * brand doesn't support it. Both DragonFly platforms do by default. */ - if (elf_check_header(hdr) != 0 || - (hdr->e_type != ET_EXEC && (!can_exec_dyn || hdr->e_type != ET_DYN))) - return -1; + if (__elfN(check_header)(hdr) != 0 || + (hdr->e_type != ET_EXEC && hdr->e_type != ET_DYN)) + return (-1); /* * From here on down, we return an errno, not -1, as we've @@ -660,13 +595,33 @@ exec_elf_imgact(struct image_params *imgp) if ((hdr->e_phoff > PAGE_SIZE) || (hdr->e_phoff + hdr->e_phentsize * hdr->e_phnum) > PAGE_SIZE) { /* Only support headers in first page for now */ - return ENOEXEC; + return (ENOEXEC); } phdr = (const Elf_Phdr*)(imgp->image_header + hdr->e_phoff); + for (i = 0; i < hdr->e_phnum; i++) { + if (phdr[i].p_type == PT_INTERP) { + /* Path to interpreter */ + if (phdr[i].p_filesz > MAXPATHLEN || + phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) + return (ENOEXEC); + interp = imgp->image_header + phdr[i].p_offset; + break; + } + } - /* - * From this point on, we may have resources that need to be freed. - */ + brand_info = __elfN(get_brandinfo)(imgp, interp, &osrel); + if (brand_info == NULL) { + uprintf("ELF binary type \"%u\" not known.\n", + hdr->e_ident[EI_OSABI]); + return (ENOEXEC); + } + if (hdr->e_type == ET_DYN && + (brand_info->flags & BI_CAN_EXEC_DYN) == 0) { + return (ENOEXEC); + } + + if (interp != NULL && brand_info->interp_newpath != NULL) + newinterp = brand_info->interp_newpath; exec_new_vmspace(imgp, NULL); @@ -681,7 +636,7 @@ exec_elf_imgact(struct image_params *imgp) vmspace = imgp->proc->p_vmspace; for (i = 0; i < hdr->e_phnum; i++) { - switch(phdr[i].p_type) { + switch (phdr[i].p_type) { case PT_LOAD: /* Loadable segment */ prot = 0; @@ -692,13 +647,14 @@ exec_elf_imgact(struct image_params *imgp) if (phdr[i].p_flags & PF_R) prot |= VM_PROT_READ; - if ((error = elf_load_section(imgp->proc, - vmspace, imgp->vp, - phdr[i].p_offset, - (caddr_t)phdr[i].p_vaddr, - phdr[i].p_memsz, - phdr[i].p_filesz, prot)) != 0) - goto fail; + if ((error = __elfN(load_section)( + imgp->proc, + vmspace, imgp->vp, + phdr[i].p_offset, + (caddr_t)phdr[i].p_vaddr, + phdr[i].p_memsz, + phdr[i].p_filesz, prot)) != 0) + return (error); /* * If this segment contains the program headers, @@ -753,20 +709,8 @@ exec_elf_imgact(struct image_params *imgp) total_size > imgp->proc->p_rlimit[RLIMIT_VMEM].rlim_cur) { error = ENOMEM; - goto fail; - } - break; - case PT_INTERP: /* Path to interpreter */ - if (phdr[i].p_filesz > MAXPATHLEN || - phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE) { - error = ENOEXEC; - goto fail; + return (error); } - interp = imgp->image_header + phdr[i].p_offset; - break; - case PT_NOTE: /* Check for .note.ABI-tag */ - if (brand_info == NULL) - brand_info = elf_check_abi_note(imgp, &phdr[i]); break; case PT_PHDR: /* Program header table info */ proghdr = phdr[i].p_vaddr; @@ -785,104 +729,38 @@ exec_elf_imgact(struct image_params *imgp) imgp->entry_addr = entry; - /* We support three types of branding -- (1) the ELF EI_OSABI field - * that SCO added to the ELF spec, (2) FreeBSD 3.x's traditional string - * branding w/in the ELF header, and (3) path of the `interp_path' - * field. We should also look for an ".note.ABI-tag" ELF section now - * in all Linux ELF binaries, FreeBSD 4.1+, and some NetBSD ones. - */ + imgp->proc->p_sysent = brand_info->sysvec; + EVENTHANDLER_INVOKE(process_exec, imgp); - /* If the executable has a brand, search for it in the brand list. */ - if (brand_info == NULL && hdr->e_ident[EI_OSABI] != ELFOSABI_NONE) { - for (i = 0; i < MAX_BRANDS; i++) { - Elf_Brandinfo *bi = elf_brand_list[i]; - - if (bi != NULL && - (hdr->e_ident[EI_OSABI] == bi->brand - || 0 == - strncmp((const char *)&hdr->e_ident[OLD_EI_BRAND], - bi->compat_3_brand, strlen(bi->compat_3_brand)))) { - brand_info = bi; - break; - } + if (interp != NULL) { + int have_interp = FALSE; + if (brand_info->emul_path != NULL && + brand_info->emul_path[0] != '\0') { + path = kmalloc(MAXPATHLEN, M_TEMP, M_WAITOK); + ksnprintf(path, MAXPATHLEN, "%s%s", + brand_info->emul_path, interp); + error = __elfN(load_file)(imgp->proc, path, &addr, + &imgp->entry_addr); + kfree(path, M_TEMP); + if (error == 0) + have_interp = TRUE; } - } - - /* Search for a recognized ABI. */ - if (brand_info == NULL && abi_note != NULL) { - } - - /* - * ELFOSABI_NONE == ELFOSABI_SYSV, so a SYSV binary misses all - * checks so far, since it is neither branded nor does it have - * an ABI note. If the EI_OSABI field is ELFOSABI_NONE, assume - * it is svr4 and look for an entry in the elf_brand_list with - * match_abi_note == NULL. - */ - if (brand_info == NULL && hdr->e_ident[EI_OSABI] == ELFOSABI_NONE) { - for (i = 0; i < MAX_BRANDS; i++) { - Elf_Brandinfo *bi = elf_brand_list[i]; - - if (bi != NULL && bi->match_abi_note == NULL && - ELFOSABI_SYSV == bi->brand) { - brand_info = bi; - break; - } + if (!have_interp && newinterp != NULL) { + error = __elfN(load_file)(imgp->proc, newinterp, + &addr, &imgp->entry_addr); + if (error == 0) + have_interp = TRUE; } - } - - /* Lacking a recognized ABI, search for a recognized interpreter. */ - if (brand_info == NULL && interp != NULL) { - for (i = 0; i < MAX_BRANDS; i++) { - Elf_Brandinfo *bi = elf_brand_list[i]; - - if (bi != NULL && - strcmp(interp, bi->interp_path) == 0) { - brand_info = bi; - break; - } + if (!have_interp) { + error = __elfN(load_file)(imgp->proc, interp, &addr, + &imgp->entry_addr); } - } - - /* Lacking a recognized interpreter, try the default brand */ - if (brand_info == NULL) { - for (i = 0; i < MAX_BRANDS; i++) { - Elf_Brandinfo *bi = elf_brand_list[i]; - - if (bi != NULL && fallback_elf_brand == bi->brand) { - brand_info = bi; - break; - } + if (error != 0) { + uprintf("ELF interpreter %s not found\n", interp); + return (error); } - } - - if (brand_info == NULL) { - uprintf("ELF binary type \"%u\" not known.\n", - hdr->e_ident[EI_OSABI]); - error = ENOEXEC; - goto fail; - } - - imgp->proc->p_sysent = brand_info->sysvec; - EVENTHANDLER_INVOKE(process_exec, imgp); - - if (interp != NULL) { - path = kmalloc(MAXPATHLEN, M_TEMP, M_WAITOK); - ksnprintf(path, MAXPATHLEN, "%s%s", - brand_info->emul_path, interp); - if ((error = elf_load_file(imgp->proc, path, &addr, - &imgp->entry_addr)) != 0) { - if ((error = elf_load_file(imgp->proc, interp, &addr, - &imgp->entry_addr)) != 0) { - uprintf("ELF interpreter %s not found\n", path); - kfree(path, M_TEMP); - goto fail; - } - } - kfree(path, M_TEMP); - } else { + } else addr = 0; - } /* * Construct auxargs table (used by the fixup routine) @@ -896,29 +774,26 @@ exec_elf_imgact(struct image_params *imgp) elf_auxargs->base = addr; elf_auxargs->flags = 0; elf_auxargs->entry = entry; - elf_auxargs->trace = elf_trace; imgp->auxargs = elf_auxargs; imgp->interpreted = 0; + imgp->proc->p_osrel = osrel; -fail: - return error; + return (error); } -static int -elf_freebsd_fixup(register_t **stack_base, struct image_params *imgp) +int +__elfN(dragonfly_fixup)(register_t **stack_base, struct image_params *imgp) { Elf_Auxargs *args = (Elf_Auxargs *)imgp->auxargs; - register_t *pos; + Elf_Addr *base; + Elf_Addr *pos; - pos = *stack_base + (imgp->args->argc + imgp->args->envc + 2); + base = (Elf_Addr *)*stack_base; + pos = base + (imgp->args->argc + imgp->args->envc + 2); - if (args->trace) { - AUXARGS_ENTRY(pos, AT_DEBUG, 1); - } - if (args->execfd != -1) { + if (args->execfd != -1) AUXARGS_ENTRY(pos, AT_EXECFD, args->execfd); - } AUXARGS_ENTRY(pos, AT_PHDR, args->phdr); AUXARGS_ENTRY(pos, AT_PHENT, args->phent); AUXARGS_ENTRY(pos, AT_PHNUM, args->phnum); @@ -933,10 +808,11 @@ elf_freebsd_fixup(register_t **stack_base, struct image_params *imgp) kfree(imgp->auxargs, M_TEMP); imgp->auxargs = NULL; - (*stack_base)--; - suword(*stack_base, (long) imgp->args->argc); - return 0; -} + base--; + suword(base, (long)imgp->args->argc); + *stack_base = (register_t *)base; + return (0); +} /* * Code for generating ELF core dumps. @@ -980,22 +856,20 @@ static int cb_put_fp(vm_map_entry_t, void *); static int each_segment (struct proc *, segment_callback, void *, int); -static int elf_corehdr (struct lwp *, int, struct file *, struct ucred *, +static int __elfN(corehdr)(struct lwp *, int, struct file *, struct ucred *, int, elf_buf_t); enum putmode { WRITE, DRYRUN }; -static int elf_puthdr (struct lwp *, elf_buf_t, int sig, enum putmode, +static int __elfN(puthdr)(struct lwp *, elf_buf_t, int sig, enum putmode, int, struct file *); static int elf_putallnotes(struct lwp *, elf_buf_t, int, enum putmode); -static int elf_putnote (elf_buf_t, const char *, int, const void *, size_t); +static int __elfN(putnote)(elf_buf_t, const char *, int, const void *, size_t); static int elf_putsigs(struct lwp *, elf_buf_t); static int elf_puttextvp(struct proc *, elf_buf_t); static int elf_putfiles(struct proc *, elf_buf_t, struct file *); -extern int osreldate; - int -elf_coredump(struct lwp *lp, int sig, struct vnode *vp, off_t limit) +__elfN(coredump)(struct lwp *lp, int sig, struct vnode *vp, off_t limit) { struct file *fp; int error; @@ -1048,7 +922,7 @@ generic_elf_coredump(struct lwp *lp, int sig, struct file *fp, off_t limit) * size is calculated. */ bzero(&target, sizeof(target)); - elf_puthdr(lp, &target, sig, DRYRUN, seginfo.count, fp); + __elfN(puthdr)(lp, &target, sig, DRYRUN, seginfo.count, fp); if (target.off + seginfo.vsize >= limit) return (EFAULT); @@ -1061,7 +935,7 @@ generic_elf_coredump(struct lwp *lp, int sig, struct file *fp, off_t limit) target.off = 0; target.buf = kmalloc(target.off_max, M_TEMP, M_WAITOK|M_ZERO); - error = elf_corehdr(lp, sig, fp, cred, seginfo.count, &target); + error = __elfN(corehdr)(lp, sig, fp, cred, seginfo.count, &target); /* Write the contents of all of the writable segments. */ if (error == 0) { @@ -1080,7 +954,7 @@ generic_elf_coredump(struct lwp *lp, int sig, struct file *fp, off_t limit) } kfree(target.buf, M_TEMP); - return error; + return (error); } /* @@ -1094,7 +968,7 @@ cb_put_phdr(vm_map_entry_t entry, void *closure) Elf_Phdr *phdr = phc->phdr; if (phc->phdr == phc->phdr_max) - return EINVAL; + return (EINVAL); phc->offset = round_page(phc->offset); @@ -1114,7 +988,7 @@ cb_put_phdr(vm_map_entry_t entry, void *closure) phc->offset += phdr->p_filesz; ++phc->phdr; - return 0; + return (0); } /* @@ -1128,7 +1002,7 @@ cb_size_segment(vm_map_entry_t entry, void *closure) ++ssc->count; ssc->vsize += entry->end - entry->start; - return 0; + return (0); } /* @@ -1144,10 +1018,10 @@ cb_fpcount_segment(vm_map_entry_t entry, void *closure) if (entry->object.vm_object->type == OBJT_VNODE) { vp = (struct vnode *)entry->object.vm_object->handle; if ((vp->v_flag & VCKPT) && curproc->p_textvp == vp) - return 0; + return (0); ++*count; } - return 0; + return (0); } static int @@ -1180,9 +1054,9 @@ cb_put_fp(vm_map_entry_t entry, void *closure) if (entry->object.vm_object->type == OBJT_VNODE) { vp = (struct vnode *)entry->object.vm_object->handle; if ((vp->v_flag & VCKPT) && curproc->p_textvp == vp) - return 0; + return (0); if (vnh == fpc->vnh_max) - return EINVAL; + return (EINVAL); if (vp->v_mount) vnh->vnh_fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid; @@ -1215,7 +1089,7 @@ cb_put_fp(vm_map_entry_t entry, void *closure) ++fpc->vnh; ++fpc->count; } - return 0; + return (0); } /* @@ -1277,7 +1151,7 @@ each_segment(struct proc *p, segment_callback func, void *closure, int writable) error = (*func)(entry, closure); } - return error; + return (error); } static @@ -1301,7 +1175,7 @@ target_reserve(elf_buf_t target, size_t bytes, int *error) * the page boundary. */ static int -elf_corehdr(struct lwp *lp, int sig, struct file *fp, struct ucred *cred, +__elfN(corehdr)(struct lwp *lp, int sig, struct file *fp, struct ucred *cred, int numsegs, elf_buf_t target) { int error; @@ -1312,18 +1186,18 @@ elf_corehdr(struct lwp *lp, int sig, struct file *fp, struct ucred *cred, * a checkpoint file pointer within the core file itself, because * it may not be restored from the same file handle. */ - error = elf_puthdr(lp, target, sig, WRITE, numsegs, fp); + error = __elfN(puthdr)(lp, target, sig, WRITE, numsegs, fp); /* Write it to the core file. */ if (error == 0) { error = fp_write(fp, target->buf, target->off, &nbytes, UIO_SYSSPACE); } - return error; + return (error); } static int -elf_puthdr(struct lwp *lp, elf_buf_t target, int sig, enum putmode mode, +__elfN(puthdr)(struct lwp *lp, elf_buf_t target, int sig, enum putmode mode, int numsegs, struct file *fp) { struct proc *p = lp->lwp_proc; @@ -1458,16 +1332,17 @@ elf_putallnotes(struct lwp *corelp, elf_buf_t target, int sig, if (mode != DRYRUN) { psinfo->pr_version = PRPSINFO_VERSION; psinfo->pr_psinfosz = sizeof(prpsinfo_t); - strncpy(psinfo->pr_fname, p->p_comm, - sizeof(psinfo->pr_fname) - 1); + strlcpy(psinfo->pr_fname, p->p_comm, + sizeof(psinfo->pr_fname)); /* * XXX - We don't fill in the command line arguments * properly yet. */ - strncpy(psinfo->pr_psargs, p->p_comm, PRARGSZ); + strlcpy(psinfo->pr_psargs, p->p_comm, + sizeof(psinfo->pr_psargs)); } error = - elf_putnote(target, "CORE", NT_PRPSINFO, psinfo, sizeof *psinfo); + __elfN(putnote)(target, "CORE", NT_PRPSINFO, psinfo, sizeof *psinfo); if (error) goto exit; @@ -1492,11 +1367,11 @@ elf_putallnotes(struct lwp *corelp, elf_buf_t target, int sig, fill_fpregs(corelp, fpregs); } error = - elf_putnote(target, "CORE", NT_PRSTATUS, status, sizeof *status); + __elfN(putnote)(target, "CORE", NT_PRSTATUS, status, sizeof *status); if (error) goto exit; error = - elf_putnote(target, "CORE", NT_FPREGSET, fpregs, sizeof *fpregs); + __elfN(putnote)(target, "CORE", NT_FPREGSET, fpregs, sizeof *fpregs); if (error) goto exit; @@ -1514,11 +1389,11 @@ elf_putallnotes(struct lwp *corelp, elf_buf_t target, int sig, fill_regs(lp, &status->pr_reg); fill_fpregs(lp, fpregs); } - error = elf_putnote(target, "CORE", NT_PRSTATUS, + error = __elfN(putnote)(target, "CORE", NT_PRSTATUS, status, sizeof *status); if (error) goto exit; - error = elf_putnote(target, "CORE", NT_FPREGSET, + error = __elfN(putnote)(target, "CORE", NT_FPREGSET, fpregs, sizeof *fpregs); if (error) goto exit; @@ -1536,7 +1411,7 @@ exit: * NOTE: 4-byte alignment. */ static int -elf_putnote(elf_buf_t target, const char *name, int type, +__elfN(putnote)(elf_buf_t target, const char *name, int type, const void *desc, size_t descsz) { int error = 0; @@ -1557,7 +1432,7 @@ elf_putnote(elf_buf_t target, const char *name, int type, if (dst != NULL) bcopy(desc, dst, note.n_descsz); target->off = roundup2(target->off, sizeof(Elf_Word)); - return(error); + return (error); } @@ -1578,7 +1453,7 @@ elf_putsigs(struct lwp *lp, elf_buf_t target) sizeof(sigset_t)); csi->csi_sigparent = p->p_sigparent; } - return(error); + return (error); } static int @@ -1651,7 +1526,7 @@ elf_putfiles(struct proc *p, elf_buf_t target, struct file *ckfp) } fdrop(fp); } - return(error); + return (error); } static int @@ -1683,12 +1558,81 @@ elf_puttextvp(struct proc *p, elf_buf_t target) error = each_segment(p, cb_fpcount_segment, &fpc.count, 0); } target->off += fpc.count * sizeof(struct vn_hdr); - return(error); + return (error); } +/* + * Try to find the appropriate ABI-note section for checknote, + * fetch the osreldate for binary from the ELF OSABI-note. Only the + * first page of the image is searched, the same as for headers. + */ +static boolean_t +__elfN(check_note)(struct image_params *imgp, Elf_Brandnote *checknote, + int32_t *osrel) +{ + const Elf_Note *note, *note0, *note_end; + const Elf_Phdr *phdr, *pnote; + const Elf_Ehdr *hdr; + const char *note_name; + int i; + + pnote = NULL; + hdr = (const Elf_Ehdr *)imgp->image_header; + phdr = (const Elf_Phdr *)(imgp->image_header + hdr->e_phoff); + + for (i = 0; i < hdr->e_phnum; i++) { + if (phdr[i].p_type == PT_NOTE) { + pnote = &phdr[i]; + break; + } + } + + if (pnote == NULL || pnote->p_offset >= PAGE_SIZE || + pnote->p_offset + pnote->p_filesz >= PAGE_SIZE) + return (FALSE); + + note = note0 = (const Elf_Note *)(imgp->image_header + pnote->p_offset); + note_end = (const Elf_Note *)(imgp->image_header + + pnote->p_offset + pnote->p_filesz); + for (i = 0; i < 100 && note >= note0 && note < note_end; i++) { + if (!aligned(note, Elf32_Addr)) + return (FALSE); + if (note->n_namesz != checknote->hdr.n_namesz || + note->n_descsz != checknote->hdr.n_descsz || + note->n_type != checknote->hdr.n_type) + goto nextnote; + note_name = (const char *)(note + 1); + if (strncmp(checknote->vendor, note_name, + checknote->hdr.n_namesz) != 0) + goto nextnote; + + /* + * Fetch the osreldate for binary + * from the ELF OSABI-note if necessary. + */ + if ((checknote->flags & BN_CAN_FETCH_OSREL) != 0 && + osrel != NULL) + *osrel = *(const int32_t *) (note_name + + roundup2(checknote->hdr.n_namesz, + sizeof(Elf32_Addr))); + return (TRUE); + +nextnote: + note = (const Elf_Note *)((const char *)(note + 1) + + roundup2(note->n_namesz, sizeof(Elf32_Addr)) + + roundup2(note->n_descsz, sizeof(Elf32_Addr))); + } + + return (FALSE); +} /* * Tell kern_execve.c about it, with a little help from the linker. */ -static struct execsw elf_execsw = {exec_elf_imgact, "ELF"}; -EXEC_SET_ORDERED(elf, elf_execsw, SI_ORDER_FIRST); +#if defined(__x86_64__) +static struct execsw elf_execsw = {exec_elf64_imgact, "ELF64"}; +EXEC_SET_ORDERED(elf64, elf_execsw, SI_ORDER_FIRST); +#else /* i386 assumed */ +static struct execsw elf_execsw = {exec_elf32_imgact, "ELF32"}; +EXEC_SET_ORDERED(elf32, elf_execsw, SI_ORDER_FIRST); +#endif diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index bf488b9bbf..c5e2489cdb 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -40,7 +40,6 @@ * * @(#)init_main.c 8.9 (Berkeley) 1/21/94 * $FreeBSD: src/sys/kern/init_main.c,v 1.134.2.8 2003/06/06 20:21:32 tegge Exp $ - * $DragonFly: src/sys/kern/init_main.c,v 1.87 2008/06/07 11:37:23 mneumann Exp $ */ #include "opt_init_path.h" @@ -100,7 +99,6 @@ int cmask = CMASK; u_int cpu_mi_feature; cpumask_t usched_global_cpumask; extern struct user *proc0paddr; -extern int fallback_elf_brand; int boothowto = 0; /* initialized so that it can be patched */ SYSCTL_INT(_debug, OID_AUTO, boothowto, CTLFLAG_RD, &boothowto, 0, @@ -357,6 +355,11 @@ proc0_init(void *dummy __unused) p = &proc0; lp = &lwp0; + /* + * Initialize osrel + */ + p->p_osrel = osreldate; + /* * Initialize process and pgrp structures. */ @@ -579,9 +582,7 @@ start_init(void *dummy, struct trapframe *frame) strncpy(init_path, var, sizeof init_path); init_path[sizeof init_path - 1] = 0; } - if ((var = kgetenv("kern.fallback_elf_brand")) != NULL) - fallback_elf_brand = strtol(var, NULL, 0); - + for (path = init_path; *path != '\0'; path = next) { while (*path == ':') path++; diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index f27d4e1ed0..3effc92eb0 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -255,6 +255,8 @@ interpret: if (error) goto exec_fail_dealloc; + imgp->proc->p_osrel = 0; + if (debug_execve_args && imgp->interpreted) { kprintf(" target is interpreted -- recursive pass\n"); kprintf(" interpreter: %s\n", imgp->interpreter_name); diff --git a/sys/kern/kern_mib.c b/sys/kern/kern_mib.c index f65425b092..fa5387bb31 100644 --- a/sys/kern/kern_mib.c +++ b/sys/kern/kern_mib.c @@ -38,7 +38,6 @@ * * @(#)kern_sysctl.c 8.4 (Berkeley) 4/14/94 * $FreeBSD: src/sys/kern/kern_mib.c,v 1.29.2.4 2001/07/30 23:28:00 peter Exp $ - * $DragonFly: src/sys/kern/kern_mib.c,v 1.16 2008/01/04 12:16:19 matthias Exp $ */ #include @@ -95,7 +94,6 @@ SYSCTL_STRING(_kern, KERN_VERSION, version, CTLFLAG_RD, SYSCTL_STRING(_kern, KERN_OSTYPE, ostype, CTLFLAG_RD, ostype, 0, "Operating system type"); -extern int osreldate; SYSCTL_INT(_kern, KERN_OSRELDATE, osreldate, CTLFLAG_RD, &osreldate, 0, "Operating system release date"); diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h index 7ff0edeaec..aaa50a6c59 100644 --- a/sys/sys/imgact_elf.h +++ b/sys/sys/imgact_elf.h @@ -26,93 +26,74 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD: src/sys/sys/imgact_elf.h,v 1.17.2.1 2000/07/06 22:26:40 obrien Exp $ - * $DragonFly: src/sys/sys/imgact_elf.h,v 1.9 2008/07/23 17:22:33 dillon Exp $ */ #ifndef _SYS_IMGACT_ELF_H_ -#define _SYS_IMGACT_ELF_H_ +#define _SYS_IMGACT_ELF_H_ #include #include #ifdef _KERNEL -#define AUXARGS_ENTRY(pos, id, val) {suword(pos++, id); suword(pos++, val);} +#define AUXARGS_ENTRY(pos, id, val) {suword(pos++, id); suword(pos++, val);} -#if ELF_TARG_CLASS == ELFCLASS32 +struct lwp; +struct file; +struct vnode; /* * Structure used to pass infomation from the loader to the * stack fixup routine. */ typedef struct { - Elf32_Sword execfd; - Elf32_Size phdr; - Elf32_Size phent; - Elf32_Size phnum; - Elf32_Size pagesz; - Elf32_Size base; - Elf32_Size flags; - Elf32_Size entry; - Elf32_Size trace; -} Elf32_Auxargs; + Elf_Sword execfd; + Elf_Size phdr; + Elf_Size phent; + Elf_Size phnum; + Elf_Size pagesz; + Elf_Size base; + Elf_Size flags; + Elf_Size entry; +} __ElfN(Auxargs); typedef struct { - int brand; - const char *compat_3_brand; /* pre Binutils 2.10 method (FBSD 3) */ - int (*match_abi_note)(const Elf_Note *); - const char *emul_path; - const char *interp_path; - struct sysentvec *sysvec; -} Elf32_Brandinfo; - -#define MAX_BRANDS 8 - -int elf_brand_inuse (Elf32_Brandinfo *entry); -int elf_insert_brand_entry (Elf32_Brandinfo *entry); -int elf_remove_brand_entry (Elf32_Brandinfo *entry); - -#else /* !(ELF_TARG_CLASS == ELFCLASS32) */ - -/* - * Structure used to pass infomation from the loader to the - * stack fixup routine. - */ -typedef struct { - Elf64_Ssize execfd; - Elf64_Size phdr; - Elf64_Size phent; - Elf64_Size phnum; - Elf64_Size pagesz; - Elf64_Size base; - Elf64_Size flags; - Elf64_Size entry; - Elf64_Size trace; -} Elf64_Auxargs; + Elf_Note hdr; + const char * vendor; + int flags; +} Elf_Brandnote; typedef struct { int brand; + int machine; const char *compat_3_brand; /* pre Binutils 2.10 method (FBSD 3) */ - int (*match_abi_note)(const Elf_Note *); const char *emul_path; const char *interp_path; - struct sysentvec *sysvec; -} Elf64_Brandinfo; - -#define MAX_BRANDS 8 - -int elf_brand_inuse (Elf64_Brandinfo *entry); -int elf_insert_brand_entry (Elf64_Brandinfo *entry); -int elf_remove_brand_entry (Elf64_Brandinfo *entry); - -#endif /* ELF_TARG_CLASS == ELFCLASS32 */ - -struct lwp; -struct file; -struct vnode; + struct sysentvec *sysvec; + const char *interp_newpath; + int flags; + Elf_Brandnote *brand_note; +} __ElfN(Brandinfo); + +__ElfType(Auxargs); +__ElfType(Brandinfo); + +#define MAX_BRANDS 8 +#define BI_CAN_EXEC_DYN 0x0001 +#define BI_BRAND_NOTE 0x0002 /* May have note.ABI-tag section. */ +#define BI_BRAND_NOTE_MANDATORY 0x0004 /* Must have note.ABI-tag section. */ +#define BN_CAN_FETCH_OSREL 0x0001 + +int __elfN(brand_inuse) (Elf_Brandinfo *entry); +int __elfN(insert_brand_entry) (Elf_Brandinfo *entry); +int __elfN(remove_brand_entry) (Elf_Brandinfo *entry); +int __elfN(dragonfly_fixup) (register_t **, struct image_params *); +int __elfN(coredump) (struct lwp *, int, struct vnode *, off_t); + +int generic_elf_coredump (struct lwp *lp, int sig, struct file *fp, + off_t limit); +extern Elf_Brandnote __elfN(dragonfly_brandnote); -int elf_coredump (struct lwp *, int, struct vnode *, off_t); -int generic_elf_coredump(struct lwp *lp, int sig, struct file *fp, off_t limit); #endif /* _KERNEL */ #endif /* !_SYS_IMGACT_ELF_H_ */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index be6ad417da..b82beca6cf 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -37,7 +37,6 @@ * * @(#)proc.h 8.15 (Berkeley) 5/19/95 * $FreeBSD: src/sys/sys/proc.h,v 1.99.2.9 2003/06/06 20:21:32 tegge Exp $ - * $DragonFly: src/sys/sys/proc.h,v 1.121 2008/07/23 17:22:33 dillon Exp $ */ #ifndef _SYS_PROC_H_ @@ -292,6 +291,7 @@ struct proc { char p_pad3; /* Process lock (prevent destruct) count. */ char p_nice; /* Process "nice" value. */ char p_pad4; + int p_osrel; /* release date for binary ELF note */ struct pgrp *p_pgrp; /* Pointer to process group. */ diff --git a/sys/sys/systm.h b/sys/sys/systm.h index fd60dd3010..b6f3735d37 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -62,6 +62,7 @@ extern int tsleep_now_works; /* tsleep won't just return any more */ extern const char *panicstr; /* panic message */ extern int dumping; /* system is dumping */ extern int safepri; /* safe ipl when cold or panicing */ +extern int osreldate; /* System release date */ extern char version[]; /* system version */ extern char copyright[]; /* system copyright */