From 817dc004334f9ece7675bd86199886afe746e52c Mon Sep 17 00:00:00 2001 From: Warner Losh Date: Mon, 18 Aug 2014 02:44:56 +0000 Subject: [PATCH] Expand the elf brandelf infrastructure to give access to the whole ELF header (Elf_Ehdr) to determine if a particular interpretor wants to accept it or not. Use this mechanism to filter EABI arm on OABI arm kernels, and vice versa. This method could also be used to implement OABI on EABI arm kernels, if desired, or to allow a single mips kernel to run o32, n32 and n64 binaries. Differential Revision: https://reviews.freebsd.org/D609 --- sys/arm/arm/elf_machdep.c | 36 ++++++++++++++++++++++++++++++++++-- sys/arm/include/elf.h | 6 ++++++ sys/kern/imgact_elf.c | 13 +++++++++++++ sys/sys/imgact_elf.h | 1 + 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c index d8169805d0a..0d6f1629e6a 100644 --- a/sys/arm/arm/elf_machdep.c +++ b/sys/arm/arm/elf_machdep.c @@ -46,6 +46,8 @@ __FBSDID("$FreeBSD$"); #include #include +static boolean_t elf32_arm_abi_supported(struct image_params *); + struct sysentvec elf32_freebsd_sysvec = { .sv_size = SYS_MAXSYSCALL, .sv_table = sysent, @@ -90,7 +92,8 @@ static Elf32_Brandinfo freebsd_brand_info = { .sysvec = &elf32_freebsd_sysvec, .interp_newpath = NULL, .brand_note = &elf32_freebsd_brandnote, - .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE + .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, + .header_supported= elf32_arm_abi_supported, }; SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_FIRST, @@ -106,13 +109,42 @@ static Elf32_Brandinfo freebsd_brand_oinfo = { .sysvec = &elf32_freebsd_sysvec, .interp_newpath = NULL, .brand_note = &elf32_freebsd_brandnote, - .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE + .flags = BI_CAN_EXEC_DYN | BI_BRAND_NOTE, + .header_supported= elf32_arm_abi_supported, }; SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY, (sysinit_cfunc_t) elf32_insert_brand_entry, &freebsd_brand_oinfo); +static boolean_t +elf32_arm_abi_supported(struct image_params *imgp) +{ + const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header; + +#ifdef __ARM_EABI__ + /* + * When configured for EABI, FreeBSD supports EABI vesions 4 and 5. + */ + if (EF_ARM_EABI_VERSION(hdr->e_flags) < EF_ARM_EABI_FREEBSD_MIN) { + if (bootverbose) + uprintf("Attempting to execute non EABI binary (rev %d) image %s", + EF_ARM_EABI_VERSION(hdr->e_flags), imgp->args->fname); + return (FALSE); + } +#else + /* + * When configured for OABI, that's all we do, so reject EABI binaries. + */ + if (EF_ARM_EABI_VERSION(hdr->e_flags) != EF_ARM_EABI_VERSION_UNKNOWN) { + if (bootverbose) + uprintf("Attempting to execute EABI binary (rev %d) image %s", + EF_ARM_EABI_VERSION(hdr->e_flags), imgp->args->fname); + return (FALSE); + } +#endif + return (TRUE); +} void elf32_dump_thread(struct thread *td __unused, void *dst __unused, diff --git a/sys/arm/include/elf.h b/sys/arm/include/elf.h index 9b18646d187..b0aa7c628bc 100644 --- a/sys/arm/include/elf.h +++ b/sys/arm/include/elf.h @@ -103,6 +103,12 @@ __ElfType(Auxinfo); #define ELF_TARG_MACH EM_ARM #define ELF_TARG_VER 1 +/* Defines specific for arm headers */ +#define EF_ARM_EABIMASK 0xff000000 +#define EF_ARM_EABI_VERSION(x) (((x) & EF_ARM_EABIMASK) >> 24) +#define EF_ARM_EABI_VERSION_UNKNOWN 0 +#define EF_ARM_EABI_FREEBSD_MIN 4 + /* * Magic number for the elf trampoline, chosen wisely to be an immediate * value. diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c index 6342119d154..e15d0ab0007 100644 --- a/sys/kern/imgact_elf.c +++ b/sys/kern/imgact_elf.c @@ -294,6 +294,19 @@ __elfN(get_brandinfo)(struct image_params *imgp, const char *interp, return (bi); } + /* No known brand, see if the header is recognized by any brand */ + for (i = 0; i < MAX_BRANDS; i++) { + bi = elf_brand_list[i]; + if (bi == NULL || bi->flags & BI_BRAND_NOTE_MANDATORY || + bi->header_supported == NULL) + continue; + if (hdr->e_machine == bi->machine) { + ret = bi->header_supported(imgp); + if (ret) + return (bi); + } + } + /* Lacking a known brand, search for a recognized interpreter. */ if (interp != NULL) { for (i = 0; i < MAX_BRANDS; i++) { diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h index faef5f8518d..712a55e1bac 100644 --- a/sys/sys/imgact_elf.h +++ b/sys/sys/imgact_elf.h @@ -74,6 +74,7 @@ typedef struct { const char *interp_newpath; int flags; Elf_Brandnote *brand_note; + boolean_t (*header_supported)(struct image_params *); #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. */