diff options
| author | Bjoern A. Zeeb <bz@FreeBSD.org> | 2009-08-27 17:36:59 +0000 |
|---|---|---|
| committer | Bjoern A. Zeeb <bz@FreeBSD.org> | 2009-08-27 17:36:59 +0000 |
| commit | f613e8217080c49a8fbf89b40bbc4a0737a7b67c (patch) | |
| tree | 3dcca9f4b33a8ec7790d3ef7e2823de99a2a9213 | |
| parent | 9d16faa36bea51e414201da64ff4c9fd6ff51c2b (diff) | |
Notes
| -rw-r--r-- | sys/amd64/amd64/elf_machdep.c | 17 | ||||
| -rw-r--r-- | sys/amd64/amd64/trap.c | 16 | ||||
| -rw-r--r-- | sys/amd64/linux32/linux32_sysvec.c | 35 | ||||
| -rw-r--r-- | sys/compat/ia32/ia32_sysvec.c | 15 | ||||
| -rw-r--r-- | sys/i386/i386/elf_machdep.c | 16 | ||||
| -rw-r--r-- | sys/i386/i386/trap.c | 7 | ||||
| -rw-r--r-- | sys/i386/linux/linux_sysvec.c | 35 | ||||
| -rw-r--r-- | sys/kern/imgact_elf.c | 60 | ||||
| -rw-r--r-- | sys/sys/imgact_elf.h | 6 |
9 files changed, 188 insertions, 19 deletions
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c index 2f33303e041b..a2d967079ce1 100644 --- a/sys/amd64/amd64/elf_machdep.c +++ b/sys/amd64/amd64/elf_machdep.c @@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <sys/sysent.h> #include <sys/imgact_elf.h> #include <sys/syscall.h> +#include <sys/sysent.h> #include <sys/signalvar.h> #include <sys/vnode.h> @@ -107,6 +108,22 @@ SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY, (sysinit_cfunc_t) elf64_insert_brand_entry, &freebsd_brand_oinfo); +static Elf64_Brandinfo kfreebsd_brand_info = { + .brand = ELFOSABI_FREEBSD, + .machine = EM_X86_64, + .compat_3_brand = "FreeBSD", + .emul_path = NULL, + .interp_path = "/lib/ld-kfreebsd-x86-64.so.1", + .sysvec = &elf64_freebsd_sysvec, + .interp_newpath = NULL, + .brand_note = &elf64_kfreebsd_brandnote, + .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE +}; + +SYSINIT(kelf64, SI_SUB_EXEC, SI_ORDER_ANY, + (sysinit_cfunc_t) elf64_insert_brand_entry, + &kfreebsd_brand_info); + void elf64_dump_thread(struct thread *td __unused, void *dst __unused, diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 8107864e51c7..16f8157e1d4b 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); */ #include "opt_clock.h" +#include "opt_compat.h" #include "opt_cpu.h" #include "opt_hwpmc_hooks.h" #include "opt_isa.h" @@ -115,6 +116,13 @@ dtrace_doubletrap_func_t dtrace_doubletrap_func; systrace_probe_func_t systrace_probe_func; #endif +/* Defined in amd64/amd64/elf_machdep.c. */ +extern struct sysentvec elf64_freebsd_sysvec; +#ifdef COMPAT_IA32 +/* Defined in compat/ia32/ia32_sysvec.c. */ +extern struct sysentvec ia32_freebsd_sysvec; +#endif + extern void trap(struct trapframe *frame); extern void syscall(struct trapframe *frame); void dblfault_handler(struct trapframe *frame); @@ -359,7 +367,13 @@ trap(struct trapframe *frame) * This check also covers the images * without the ABI-tag ELF note. */ - if (p->p_osrel >= 700004) { + if ((curproc->p_sysent == + &elf64_freebsd_sysvec +#ifdef COMPAT_IA32 + || curproc->p_sysent == + &ia32_freebsd_sysvec +#endif + ) && p->p_osrel >= 700004) { i = SIGSEGV; ucode = SEGV_ACCERR; } else { diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c index 86d4bbd2bd23..5338da4a848c 100644 --- a/sys/amd64/linux32/linux32_sysvec.c +++ b/sys/amd64/linux32/linux32_sysvec.c @@ -126,6 +126,7 @@ static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); static void exec_linux_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings); static void linux32_fixlimit(struct rlimit *rl, int which); +static boolean_t linux32_trans_osrel(const Elf_Note *note, int32_t *osrel); static eventhandler_tag linux_exit_tag; static eventhandler_tag linux_schedtail_tag; @@ -1055,14 +1056,38 @@ struct sysentvec elf_linux_sysvec = { .sv_maxssiz = &linux32_maxssiz, }; -static char GNULINUX_ABI_VENDOR[] = "GNU"; +static char GNU_ABI_VENDOR[] = "GNU"; +static int GNULINUX_ABI_DESC = 0; + +static boolean_t +linux32_trans_osrel(const Elf_Note *note, int32_t *osrel) +{ + const Elf32_Word *desc; + uintptr_t p; + + p = (uintptr_t)(note + 1); + p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); + + desc = (const Elf32_Word *)p; + if (desc[0] != GNULINUX_ABI_DESC) + return (FALSE); + + /* + * For linux we encode osrel as follows (see linux_mib.c): + * VVVMMMIII (version, major, minor), see linux_mib.c. + */ + *osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3]; + + return (TRUE); +} static Elf_Brandnote linux32_brandnote = { - .hdr.n_namesz = sizeof(GNULINUX_ABI_VENDOR), - .hdr.n_descsz = 16, + .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), + .hdr.n_descsz = 16, /* XXX at least 16 */ .hdr.n_type = 1, - .vendor = GNULINUX_ABI_VENDOR, - .flags = 0 + .vendor = GNU_ABI_VENDOR, + .flags = BN_TRANSLATE_OSREL, + .trans_osrel = linux32_trans_osrel }; static Elf32_Brandinfo linux_brand = { diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c index 644dba6918ee..a44431a79e4a 100644 --- a/sys/compat/ia32/ia32_sysvec.c +++ b/sys/compat/ia32/ia32_sysvec.c @@ -171,6 +171,21 @@ SYSINIT(oia32, SI_SUB_EXEC, SI_ORDER_ANY, (sysinit_cfunc_t) elf32_insert_brand_entry, &ia32_brand_oinfo); +static Elf32_Brandinfo kia32_brand_info = { + .brand = ELFOSABI_FREEBSD, + .machine = EM_386, + .compat_3_brand = "FreeBSD", + .emul_path = NULL, + .interp_path = "/lib/ld.so.1", + .sysvec = &ia32_freebsd_sysvec, + .brand_note = &elf32_kfreebsd_brandnote, + .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE +}; + +SYSINIT(kia32, SI_SUB_EXEC, SI_ORDER_ANY, + (sysinit_cfunc_t) elf32_insert_brand_entry, + &kia32_brand_info); + void elf32_dump_thread(struct thread *td __unused, void *dst __unused, diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c index 6df39f7353d9..42779595ff89 100644 --- a/sys/i386/i386/elf_machdep.c +++ b/sys/i386/i386/elf_machdep.c @@ -107,6 +107,22 @@ SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY, (sysinit_cfunc_t) elf32_insert_brand_entry, &freebsd_brand_oinfo); +static Elf32_Brandinfo kfreebsd_brand_info = { + .brand = ELFOSABI_FREEBSD, + .machine = EM_386, + .compat_3_brand = "FreeBSD", + .emul_path = NULL, + .interp_path = "/lib/ld.so.1", + .sysvec = &elf32_freebsd_sysvec, + .interp_newpath = NULL, + .brand_note = &elf32_kfreebsd_brandnote, + .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE +}; + +SYSINIT(kelf32, SI_SUB_EXEC, SI_ORDER_ANY, + (sysinit_cfunc_t) elf32_insert_brand_entry, + &kfreebsd_brand_info); + void elf32_dump_thread(struct thread *td __unused, void *dst __unused, diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 3d7633c74e78..fddad06a4e13 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -123,6 +123,9 @@ dtrace_doubletrap_func_t dtrace_doubletrap_func; systrace_probe_func_t systrace_probe_func; #endif +/* Defined in i386/i386/elf_machdep.c. */ +extern struct sysentvec elf32_freebsd_sysvec; + extern void trap(struct trapframe *frame); extern void syscall(struct trapframe *frame); @@ -423,7 +426,9 @@ trap(struct trapframe *frame) * This check also covers the images * without the ABI-tag ELF note. */ - if (p->p_osrel >= 700004) { + if (curproc->p_sysent == + &elf32_freebsd_sysvec && + p->p_osrel >= 700004) { i = SIGSEGV; ucode = SEGV_ACCERR; } else { diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c index 8f43df3a4c66..522b8339ac68 100644 --- a/sys/i386/linux/linux_sysvec.c +++ b/sys/i386/linux/linux_sysvec.c @@ -107,6 +107,7 @@ static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask); static void exec_linux_setregs(struct thread *td, u_long entry, u_long stack, u_long ps_strings); static register_t *linux_copyout_strings(struct image_params *imgp); +static boolean_t linux_trans_osrel(const Elf_Note *note, int32_t *osrel); static int linux_szplatform; const char *linux_platform; @@ -1025,14 +1026,38 @@ struct sysentvec elf_linux_sysvec = { .sv_maxssiz = NULL }; -static char GNULINUX_ABI_VENDOR[] = "GNU"; +static char GNU_ABI_VENDOR[] = "GNU"; +static int GNULINUX_ABI_DESC = 0; + +static boolean_t +linux_trans_osrel(const Elf_Note *note, int32_t *osrel) +{ + const Elf32_Word *desc; + uintptr_t p; + + p = (uintptr_t)(note + 1); + p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); + + desc = (const Elf32_Word *)p; + if (desc[0] != GNULINUX_ABI_DESC) + return (FALSE); + + /* + * For linux we encode osrel as follows (see linux_mib.c): + * VVVMMMIII (version, major, minor), see linux_mib.c. + */ + *osrel = desc[1] * 1000000 + desc[2] * 1000 + desc[3]; + + return (TRUE); +} static Elf_Brandnote linux_brandnote = { - .hdr.n_namesz = sizeof(GNULINUX_ABI_VENDOR), - .hdr.n_descsz = 16, + .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), + .hdr.n_descsz = 16, /* XXX at least 16 */ .hdr.n_type = 1, - .vendor = GNULINUX_ABI_VENDOR, - .flags = 0 + .vendor = GNU_ABI_VENDOR, + .flags = BN_TRANSLATE_OSREL, + .trans_osrel = linux_trans_osrel }; static Elf32_Brandinfo linux_brand = { diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 5e6dc0e6f0f8..817a8ee40f46 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -86,6 +86,9 @@ static int __elfN(load_section)(struct vmspace *vmspace, vm_object_t object, vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz, vm_prot_t prot, size_t pagesize); static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp); +static boolean_t __elfN(freebsd_trans_osrel)(const Elf_Note *note, + int32_t *osrel); +static boolean_t kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel); static boolean_t __elfN(check_note)(struct image_params *imgp, Elf_Brandnote *checknote, int32_t *osrel); @@ -119,9 +122,56 @@ Elf_Brandnote __elfN(freebsd_brandnote) = { .hdr.n_descsz = sizeof(int32_t), .hdr.n_type = 1, .vendor = FREEBSD_ABI_VENDOR, - .flags = BN_CAN_FETCH_OSREL + .flags = BN_TRANSLATE_OSREL, + .trans_osrel = __elfN(freebsd_trans_osrel) }; +static boolean_t +__elfN(freebsd_trans_osrel)(const Elf_Note *note, int32_t *osrel) +{ + uintptr_t p; + + p = (uintptr_t)(note + 1); + p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); + *osrel = *(const int32_t *)(p); + + return (TRUE); +} + +static const char GNU_ABI_VENDOR[] = "GNU"; +static int GNU_KFREEBSD_ABI_DESC = 3; + +Elf_Brandnote __elfN(kfreebsd_brandnote) = { + .hdr.n_namesz = sizeof(GNU_ABI_VENDOR), + .hdr.n_descsz = 16, /* XXX at least 16 */ + .hdr.n_type = 1, + .vendor = GNU_ABI_VENDOR, + .flags = BN_TRANSLATE_OSREL, + .trans_osrel = kfreebsd_trans_osrel +}; + +static boolean_t +kfreebsd_trans_osrel(const Elf_Note *note, int32_t *osrel) +{ + const Elf32_Word *desc; + uintptr_t p; + + p = (uintptr_t)(note + 1); + p += roundup2(note->n_namesz, sizeof(Elf32_Addr)); + + desc = (const Elf32_Word *)p; + if (desc[0] != GNU_KFREEBSD_ABI_DESC) + return (FALSE); + + /* + * Debian GNU/kFreeBSD embed the earliest compatible kernel version + * (__FreeBSD_version: <major><two digit minor>Rxx) in the LSB way. + */ + *osrel = desc[1] * 100000 + desc[2] * 1000 + desc[3]; + + return (TRUE); +} + int __elfN(insert_brand_entry)(Elf_Brandinfo *entry) { @@ -1382,11 +1432,9 @@ __elfN(check_note)(struct image_params *imgp, Elf_Brandnote *checknote, * 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))); + if ((checknote->flags & BN_TRANSLATE_OSREL) != 0 && + checknote->trans_osrel != NULL) + return (checknote->trans_osrel(note, osrel)); return (TRUE); nextnote: diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h index c0410cb16416..7a9283946f21 100644 --- a/sys/sys/imgact_elf.h +++ b/sys/sys/imgact_elf.h @@ -59,7 +59,10 @@ typedef struct { Elf_Note hdr; const char * vendor; int flags; -#define BN_CAN_FETCH_OSREL 0x0001 + boolean_t (*trans_osrel)(const Elf_Note *, int32_t *); +#define BN_CAN_FETCH_OSREL 0x0001 /* Deprecated. */ +#define BN_TRANSLATE_OSREL 0x0002 /* Use trans_osrel fetch osrel after */ + /* checking ABI contraint if needed. */ } Elf_Brandnote; typedef struct { @@ -92,6 +95,7 @@ void __elfN(dump_thread)(struct thread *, void *, size_t *); extern int __elfN(fallback_brand); extern Elf_Brandnote __elfN(freebsd_brandnote); +extern Elf_Brandnote __elfN(kfreebsd_brandnote); #endif /* _KERNEL */ #endif /* !_SYS_IMGACT_ELF_H_ */ |
