Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 Aug 2009 17:37:00 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org
Subject:   svn commit: r196602 - in stable/7/sys: . amd64/amd64 amd64/linux32 compat/ia32 conf contrib/pf i386/i386 i386/linux kern sys
Message-ID:  <200908271737.n7RHb0KM003313@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Thu Aug 27 17:36:59 2009
New Revision: 196602
URL: http://svn.freebsd.org/changeset/base/196602

Log:
  MFC r196512:
  
    Fix handling of .note.ABI-tag section for GNU systems [1].
    Handle GNU/Linux according to LSB Core Specification 4.0,
    Chapter 11. Object Format, 11.8. ABI note tag.
  
    Also check the first word of desc, not only name, according to
    glibc abi-tags specification to distinguish between Linux and
    kFreeBSD.
  
    Add explicit handling for Debian GNU/kFreeBSD, which runs
    on our kernels as well [2].
  
    In {amd64,i386}/trap.c, when checking osrel of the current process,
    also check the ABI to not change the signal behaviour for Linux
    binary processes, now that we save an osrel version for all three
    from the lists above in struct proc [2] (slightly different to HEAD).
  
    These changes make it possible to run FreeBSD, Debian GNU/kFreeBSD
    and Linux binaries on the same machine again for at least i386 and
    amd64, and no longer break kFreeBSD which was detected as GNU(/Linux).
  
  PR:		kern/135468
  Submitted by:	dchagin [1] (initial patch)
  Suggested by:	kib [2]
  Tested by:	Petr Salinger (Petr.Salinger seznam.cz) for kFreeBSD
  Reviewed by:	kib

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/amd64/amd64/elf_machdep.c
  stable/7/sys/amd64/amd64/trap.c
  stable/7/sys/amd64/linux32/linux32_sysvec.c
  stable/7/sys/compat/ia32/ia32_sysvec.c
  stable/7/sys/conf/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/i386/i386/elf_machdep.c
  stable/7/sys/i386/i386/trap.c
  stable/7/sys/i386/linux/linux_sysvec.c
  stable/7/sys/kern/imgact_elf.c
  stable/7/sys/sys/imgact_elf.h

Modified: stable/7/sys/amd64/amd64/elf_machdep.c
==============================================================================
--- stable/7/sys/amd64/amd64/elf_machdep.c	Thu Aug 27 17:34:13 2009	(r196601)
+++ stable/7/sys/amd64/amd64/elf_machdep.c	Thu Aug 27 17:36:59 2009	(r196602)
@@ -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_AN
 	(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,

Modified: stable/7/sys/amd64/amd64/trap.c
==============================================================================
--- stable/7/sys/amd64/amd64/trap.c	Thu Aug 27 17:34:13 2009	(r196601)
+++ stable/7/sys/amd64/amd64/trap.c	Thu Aug 27 17:36:59 2009	(r196602)
@@ -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_doubletr
 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 {

Modified: stable/7/sys/amd64/linux32/linux32_sysvec.c
==============================================================================
--- stable/7/sys/amd64/linux32/linux32_sysvec.c	Thu Aug 27 17:34:13 2009	(r196601)
+++ stable/7/sys/amd64/linux32/linux32_sysvec.c	Thu Aug 27 17:36:59 2009	(r196602)
@@ -126,6 +126,7 @@ static void     linux_sendsig(sig_t catc
 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 = {

Modified: stable/7/sys/compat/ia32/ia32_sysvec.c
==============================================================================
--- stable/7/sys/compat/ia32/ia32_sysvec.c	Thu Aug 27 17:34:13 2009	(r196601)
+++ stable/7/sys/compat/ia32/ia32_sysvec.c	Thu Aug 27 17:36:59 2009	(r196602)
@@ -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,

Modified: stable/7/sys/i386/i386/elf_machdep.c
==============================================================================
--- stable/7/sys/i386/i386/elf_machdep.c	Thu Aug 27 17:34:13 2009	(r196601)
+++ stable/7/sys/i386/i386/elf_machdep.c	Thu Aug 27 17:36:59 2009	(r196602)
@@ -107,6 +107,22 @@ SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_AN
 	(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,

Modified: stable/7/sys/i386/i386/trap.c
==============================================================================
--- stable/7/sys/i386/i386/trap.c	Thu Aug 27 17:34:13 2009	(r196601)
+++ stable/7/sys/i386/i386/trap.c	Thu Aug 27 17:36:59 2009	(r196602)
@@ -123,6 +123,9 @@ dtrace_doubletrap_func_t	dtrace_doubletr
 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 {

Modified: stable/7/sys/i386/linux/linux_sysvec.c
==============================================================================
--- stable/7/sys/i386/linux/linux_sysvec.c	Thu Aug 27 17:34:13 2009	(r196601)
+++ stable/7/sys/i386/linux/linux_sysvec.c	Thu Aug 27 17:36:59 2009	(r196602)
@@ -107,6 +107,7 @@ static void     linux_sendsig(sig_t catc
 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 = {

Modified: stable/7/sys/kern/imgact_elf.c
==============================================================================
--- stable/7/sys/kern/imgact_elf.c	Thu Aug 27 17:34:13 2009	(r196601)
+++ stable/7/sys/kern/imgact_elf.c	Thu Aug 27 17:36:59 2009	(r196602)
@@ -86,6 +86,9 @@ static int __elfN(load_section)(struct v
     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 *
 		 * 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:

Modified: stable/7/sys/sys/imgact_elf.h
==============================================================================
--- stable/7/sys/sys/imgact_elf.h	Thu Aug 27 17:34:13 2009	(r196601)
+++ stable/7/sys/sys/imgact_elf.h	Thu Aug 27 17:36:59 2009	(r196602)
@@ -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 *
 
 extern	int __elfN(fallback_brand);
 extern Elf_Brandnote __elfN(freebsd_brandnote);
+extern Elf_Brandnote __elfN(kfreebsd_brandnote);
 #endif /* _KERNEL */
 
 #endif /* !_SYS_IMGACT_ELF_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200908271737.n7RHb0KM003313>