summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/amd64/amd64/elf_machdep.c17
-rw-r--r--sys/amd64/amd64/trap.c4
-rw-r--r--sys/amd64/linux32/linux32_sysvec.c35
-rw-r--r--sys/compat/ia32/ia32_sysvec.c15
-rw-r--r--sys/i386/i386/elf_machdep.c16
-rw-r--r--sys/i386/i386/trap.c4
-rw-r--r--sys/i386/linux/linux_sysvec.c35
-rw-r--r--sys/kern/imgact_elf.c60
-rw-r--r--sys/sys/imgact_elf.h6
9 files changed, 173 insertions, 19 deletions
diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c
index c5e19cf..ea48b25 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>
@@ -108,6 +109,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 323e8d1..65f761e 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -409,7 +409,9 @@ trap(struct trapframe *frame)
* This check also covers the images
* without the ABI-tag ELF note.
*/
- if (p->p_osrel >= 700004) {
+ if (SV_CURPROC_ABI() ==
+ SV_ABI_FREEBSD &&
+ 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 77186a1..54a04ee 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -127,6 +127,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;
@@ -1066,14 +1067,38 @@ struct sysentvec elf_linux_sysvec = {
.sv_flags = SV_ABI_LINUX | SV_ILP32 | SV_IA32
};
-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 af8168e..5c2c571 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -172,6 +172,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 b68a73e..a4ff9e2 100644
--- a/sys/i386/i386/elf_machdep.c
+++ b/sys/i386/i386/elf_machdep.c
@@ -108,6 +108,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 354d791..f7064f0 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -423,7 +423,9 @@ trap(struct trapframe *frame)
* This check also covers the images
* without the ABI-tag ELF note.
*/
- if (p->p_osrel >= 700004) {
+ if (SV_CURPROC_ABI() ==
+ SV_ABI_FREEBSD &&
+ 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 186e14c..d07f655 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
@@ -108,6 +108,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;
@@ -1027,14 +1028,38 @@ struct sysentvec elf_linux_sysvec = {
.sv_flags = SV_ABI_LINUX | SV_IA32 | SV_ILP32
};
-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 e2c0a12..6803523 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);
@@ -116,9 +119,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)
{
@@ -1371,11 +1421,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 60979d9..3eecf85 100644
--- a/sys/sys/imgact_elf.h
+++ b/sys/sys/imgact_elf.h
@@ -58,7 +58,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 {
@@ -91,6 +94,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_ */
OpenPOWER on IntegriCloud