RFC: ELF branding. looking to a ".note.ABI-tag" section

From: Chagin Dmitry <dchagin_at_freebsd.org>
Date: Tue, 6 Jan 2009 15:46:16 +0300
Hi, please, look a patch bellow. kern/118473 related.
any comments, help :)

Implement new way of branding ELF binaries by looking to a ".note.ABI-tag"
section. For what handler .brand_abi_note in Elf_Brandinfo is added.
The search order of a brand is changed, now first of all the ".note.ABI-tag"
is looked through.
Implement .brand_abi_note handler for FreeBSD and Linux binaries. Move
code which fetch osreldate for FreeBSD binaries to corresponding handler.

Add new branding flag BI_CAN_EXEC_INTERP, which is used if the ABI allows
interpreter start (as executable). Implement corresponding handler.



diff --git a/sys/amd64/amd64/elf_machdep.c b/sys/amd64/amd64/elf_machdep.c
index 4f6d178..0aea61d 100644
--- a/sys/amd64/amd64/elf_machdep.c
+++ b/sys/amd64/amd64/elf_machdep.c
_at__at_ -84,7 +84,8 _at__at_ static Elf64_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY,
_at__at_ -99,7 +100,8 _at__at_ static Elf64_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
index de60744..339bc38 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
_at__at_ -42,6 +42,7 _at__at_ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/systm.h>
+#include <sys/elf.h>
 #include <sys/exec.h>
 #include <sys/fcntl.h>
 #include <sys/imgact.h>
_at__at_ -93,6 +94,8 _at__at_ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
 		suword32(pos++, val);	\
 	} while (0)
 
+#define	aligned(a, t)	(rounddown((unsigned long)(a), sizeof(t)) == (unsigned long)(a))
+
 #if BYTE_ORDER == LITTLE_ENDIAN
 #define SHELLMAGIC      0x2123 /* #! */
 #else
_at__at_ -999,6 +1002,54 _at__at_ linux32_fixlimit(struct rlimit *rl, int which)
 	}
 }
 
+static const char GNULINUX_ABI_VENDOR[] = "GNU";
+static const int GNULINUX_ABI_LEN = 16;
+
+static int
+linux32_abi_note(struct image_params *imgp, int32_t *osrel)
+{
+	const Elf_Note *note, *note_end;
+	const Elf32_Phdr *phdr, *pnote;
+	const Elf32_Ehdr *hdr;
+	const char *note_name;
+	int i;
+
+	pnote = NULL;
+	hdr = (const Elf32_Ehdr *)imgp->image_header;
+	phdr = (const Elf32_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 (0);
+
+	note = (const Elf_Note *)(imgp->image_header + pnote->p_offset);
+	if (!aligned(note, uint32_t))
+		return (0);
+	note_end = (const Elf_Note *)(hdr + pnote->p_offset +
+	    pnote->p_filesz);
+	while (note < note_end) {
+		if (note->n_namesz == sizeof(GNULINUX_ABI_VENDOR) &&
+		    note->n_descsz == GNULINUX_ABI_LEN &&
+		    note->n_type == 1 /* ABI_NOTETYPE */) {
+			note_name = (const char *)(note + 1);
+			if (strncmp(GNULINUX_ABI_VENDOR, note_name,
+			    sizeof(GNULINUX_ABI_VENDOR)) == 0)
+				return(1);
+		}
+		note = (const Elf_Note *)((const char *)(note + 1) +
+		    roundup2(note->n_namesz, sizeof(Elf32_Addr)) +
+		    roundup2(note->n_descsz, sizeof(Elf32_Addr)));
+	}
+
+	return (0);
+}
+
 struct sysentvec elf_linux_sysvec = {
 	.sv_size	= LINUX_SYS_MAXSYSCALL,
 	.sv_table	= linux_sysent,
_at__at_ -1038,7 +1089,8 _at__at_ static Elf32_Brandinfo linux_brand = {
 	.interp_path	= "/lib/ld-linux.so.1",
 	.sysvec		= &elf_linux_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= linux32_abi_note,
+	.flags		= BI_CAN_EXEC_DYN | BI_CAN_EXEC_INTERP
 };
 
 static Elf32_Brandinfo linux_glibc2brand = {
_at__at_ -1049,7 +1101,8 _at__at_ static Elf32_Brandinfo linux_glibc2brand = {
 	.interp_path	= "/lib/ld-linux.so.2",
 	.sysvec		= &elf_linux_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= linux32_abi_note,
+	.flags		= BI_CAN_EXEC_DYN | BI_CAN_EXEC_INTERP
 };
 
 Elf32_Brandinfo *linux_brandlist[] = {
diff --git a/sys/arm/arm/elf_machdep.c b/sys/arm/arm/elf_machdep.c
index 693eab1..e65f947 100644
--- a/sys/arm/arm/elf_machdep.c
+++ b/sys/arm/arm/elf_machdep.c
_at__at_ -84,7 +84,8 _at__at_ static Elf32_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
_at__at_ -99,7 +100,8 _at__at_ static Elf32_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index 0b32b9a..92b990a 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
_at__at_ -148,6 +148,7 _at__at_ static Elf32_Brandinfo ia32_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &ia32_freebsd_sysvec,
 	.interp_newpath	= "/libexec/ld-elf32.so.1",
+	.brand_abi_note	= __elfN(freebsd_abi_note),
 	.flags		= BI_CAN_EXEC_DYN
 };
 
_at__at_ -163,7 +164,8 _at__at_ static Elf32_Brandinfo ia32_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &ia32_freebsd_sysvec,
 	.interp_newpath	= "/libexec/ld-elf32.so.1",
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oia32, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/compat/svr4/svr4_sysvec.c b/sys/compat/svr4/svr4_sysvec.c
index 0030e3a..a406576 100644
--- a/sys/compat/svr4/svr4_sysvec.c
+++ b/sys/compat/svr4/svr4_sysvec.c
_at__at_ -204,6 +204,7 _at__at_ Elf32_Brandinfo svr4_brand = {
 	.interp_path	= "/lib/libc.so.1",
 	.sysvec		= &svr4_sysvec,
 	.interp_newpath	= NULL,
+	.brand_abi_note	= NULL,
 	.flags		= 0
 };
 
diff --git a/sys/i386/i386/elf_machdep.c b/sys/i386/i386/elf_machdep.c
index 19eddd0..593f9bd 100644
--- a/sys/i386/i386/elf_machdep.c
+++ b/sys/i386/i386/elf_machdep.c
_at__at_ -84,7 +84,8 _at__at_ static Elf32_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
_at__at_ -99,7 +100,8 _at__at_ static Elf32_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/i386/linux/linux_sysvec.c b/sys/i386/linux/linux_sysvec.c
index 66cb336..c3f1e84 100644
--- a/sys/i386/linux/linux_sysvec.c
+++ b/sys/i386/linux/linux_sysvec.c
_at__at_ -91,6 +91,7 _at__at_ MALLOC_DEFINE(M_LINUX, "linux", "Linux mode structures");
 
 #define	fldcw(addr)		__asm("fldcw %0" : : "m" (*(addr)))
 #define	__LINUX_NPXCW__		0x37f
+#define aligned(a, t)	(rounddown((unsigned long)(a), sizeof(t)) == (unsigned long)(a))
 
 extern char linux_sigcode[];
 extern int linux_szsigcode;
_at__at_ -964,6 +965,53 _at__at_ linux_get_machine(const char **dst)
 	return (0);
 }
 
+static const char GNULINUX_ABI_VENDOR[] = "GNU";
+static const int GNULINUX_ABI_LEN = 16;
+
+static int
+linux_abi_note(struct image_params *imgp, int32_t *osrel)
+{
+	const Elf_Note *note, *note_end;
+	const Elf32_Phdr *phdr, *pnote;
+	const Elf32_Ehdr *hdr;
+	const char *note_name;
+	int i;
+
+	pnote = NULL;
+	hdr = (const Elf32_Ehdr *)imgp->image_header;
+	phdr = (const Elf32_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 (0);
+
+	note = (const Elf_Note *)(imgp->image_header + pnote->p_offset);
+	if (!aligned(note, uint32_t))
+		return (0);
+	note_end = (const Elf_Note *)(hdr + pnote->p_offset +
+	    pnote->p_filesz);
+	while (note < note_end) {
+		if (note->n_namesz == sizeof(GNULINUX_ABI_VENDOR) &&
+		    note->n_descsz == GNULINUX_ABI_LEN &&
+		    note->n_type == 1 /* ABI_NOTETYPE */) {
+			note_name = (const char *)(note + 1);
+			if (strncmp(GNULINUX_ABI_VENDOR, note_name,
+			    sizeof(GNULINUX_ABI_VENDOR)) == 0)
+				return(1);
+		}
+		note = (const Elf_Note *)((const char *)(note + 1) +
+		    roundup2(note->n_namesz, sizeof(Elf32_Addr)) +
+		    roundup2(note->n_descsz, sizeof(Elf32_Addr)));
+	}
+
+	return (0);
+}
+
 
 struct sysentvec linux_sysvec = {
 	.sv_size	= LINUX_SYS_MAXSYSCALL,
_at__at_ -1035,7 +1083,8 _at__at_ static Elf32_Brandinfo linux_brand = {
 	.interp_path	= "/lib/ld-linux.so.1",
 	.sysvec		= &elf_linux_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= linux_abi_note,
+	.flags		= BI_CAN_EXEC_DYN | BI_CAN_EXEC_INTERP
 };
 
 static Elf32_Brandinfo linux_glibc2brand = {
_at__at_ -1046,7 +1095,8 _at__at_ static Elf32_Brandinfo linux_glibc2brand = {
 	.interp_path	= "/lib/ld-linux.so.2",
 	.sysvec		= &elf_linux_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= linux_abi_note,
+	.flags		= BI_CAN_EXEC_DYN | BI_CAN_EXEC_INTERP
 };
 
 Elf32_Brandinfo *linux_brandlist[] = {
diff --git a/sys/ia64/ia64/elf_machdep.c b/sys/ia64/ia64/elf_machdep.c
index a3a6e57..a0289de 100644
--- a/sys/ia64/ia64/elf_machdep.c
+++ b/sys/ia64/ia64/elf_machdep.c
_at__at_ -92,7 +92,8 _at__at_ static Elf64_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY,
     (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_info);
_at__at_ -105,7 +106,8 _at__at_ static Elf64_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
     (sysinit_cfunc_t)elf64_insert_brand_entry, &freebsd_brand_oinfo);
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index 431ee38..c970291 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
_at__at_ -78,8 +78,8 _at__at_ __FBSDID("$FreeBSD$");
 #define OLD_EI_BRAND	8
 
 static int __elfN(check_header)(const Elf_Ehdr *hdr);
-static Elf_Brandinfo *__elfN(get_brandinfo)(const Elf_Ehdr *hdr,
-    const char *interp);
+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, size_t pagesize);
 static int __elfN(load_section)(struct vmspace *vmspace, vm_object_t object,
_at__at_ -158,19 +158,31 _at__at_ __elfN(brand_inuse)(Elf_Brandinfo *entry)
 }
 
 static Elf_Brandinfo *
-__elfN(get_brandinfo)(const Elf_Ehdr *hdr, const char *interp)
+__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;
+	int ret, fname_len, interp_len;
 	int i;
 
 	/*
-	 * We support three types of branding -- (1) the ELF EI_OSABI field
+	 * 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 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.
+	 * branding w/in 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 && hdr->e_machine == bi->machine && bi->brand_abi_note) {
+			ret = (*bi->brand_abi_note)(imgp, 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];
_at__at_ -191,6 +203,23 _at__at_ __elfN(get_brandinfo)(const Elf_Ehdr *hdr, const char *interp)
 		}
 	}
 
+	/* Some ABI (Linux) allow to run the interpreter. */
+	for (i = 0; i < MAX_BRANDS; i++) {
+		bi = elf_brand_list[i];
+		if (bi == NULL || hdr->e_machine != bi->machine ||
+		    (bi->flags & BI_CAN_EXEC_INTERP) == 0)
+			continue;
+
+		fname_len = strlen(imgp->args->fname);
+		interp_len = strlen(bi->interp_path);
+		if (fname_len < interp_len)
+			continue;
+		ret = strncmp(imgp->args->fname + (fname_len - interp_len),
+		    bi->interp_path, interp_len);
+		if (ret == 0)
+			return (bi);
+	}
+
 	/* Lacking a recognized interpreter, try the default brand */
 	for (i = 0; i < MAX_BRANDS; i++) {
 		bi = elf_brand_list[i];
_at__at_ -590,13 +619,11 _at__at_ fail:
 	return (error);
 }
 
-static const char FREEBSD_ABI_VENDOR[] = "FreeBSD";
-
 static int
 __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 {
 	const Elf_Ehdr *hdr = (const Elf_Ehdr *)imgp->image_header;
-	const Elf_Phdr *phdr, *pnote = NULL;
+	const Elf_Phdr *phdr;
 	Elf_Auxargs *elf_auxargs;
 	struct vmspace *vmspace;
 	vm_prot_t prot;
_at__at_ -604,12 +631,11 _at__at_ __CONCAT(exec_, __elfN(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 = 0, i;
 	const char *interp = NULL, *newinterp = NULL;
 	Elf_Brandinfo *brand_info;
-	const Elf_Note *note, *note_end;
 	char *path;
-	const char *note_name;
 	struct sysentvec *sv;
 
 	/*
_at__at_ -646,7 +672,7 _at__at_ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 		}
 	}
 
-	brand_info = __elfN(get_brandinfo)(hdr, interp);
+	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]);
_at__at_ -750,9 +776,6 _at__at_ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 		case PT_PHDR: 	/* Program header table info */
 			proghdr = phdr[i].p_vaddr;
 			break;
-		case PT_NOTE:
-			pnote = &phdr[i];
-			break;
 		default:
 			break;
 		}
_at__at_ -839,41 +862,7 _at__at_ __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp)
 
 	imgp->auxargs = elf_auxargs;
 	imgp->interpreted = 0;
-
-	/*
-	 * Try to fetch the osreldate for FreeBSD binary from the ELF
-	 * OSABI-note. Only the first page of the image is searched,
-	 * the same as for headers.
-	 */
-	if (pnote != NULL && pnote->p_offset < PAGE_SIZE &&
-	    pnote->p_offset + pnote->p_filesz < PAGE_SIZE ) {
-		note = (const Elf_Note *)(imgp->image_header + pnote->p_offset);
-		if (!aligned(note, Elf32_Addr)) {
-			free(imgp->auxargs, M_TEMP);
-			imgp->auxargs = NULL;
-			return (ENOEXEC);
-		}
-		note_end = (const Elf_Note *)(imgp->image_header + pnote->p_offset +
-		    pnote->p_filesz);
-		while (note < note_end) {
-			if (note->n_namesz == sizeof(FREEBSD_ABI_VENDOR) &&
-			    note->n_descsz == sizeof(int32_t) &&
-			    note->n_type == 1 /* ABI_NOTETYPE */) {
-				note_name = (const char *)(note + 1);
-				if (strncmp(FREEBSD_ABI_VENDOR, note_name,
-				    sizeof(FREEBSD_ABI_VENDOR)) == 0) {
-					imgp->proc->p_osrel = *(const int32_t *)
-					    (note_name +
-					    round_page_ps(sizeof(FREEBSD_ABI_VENDOR),
-						sizeof(Elf32_Addr)));
-					break;
-				}
-			}
-			note = (const Elf_Note *)((const char *)(note + 1) +
-			    round_page_ps(note->n_namesz, sizeof(Elf32_Addr)) +
-			    round_page_ps(note->n_descsz, sizeof(Elf32_Addr)));
-		}
-	}
+	imgp->proc->p_osrel = osrel;
 
 	return (error);
 }
_at__at_ -1334,6 +1323,63 _at__at_ __elfN(putnote)(void *dst, size_t *off, const char *name, int type,
 	*off += roundup2(note.n_descsz, sizeof(Elf_Size));
 }
 
+static const char FREEBSD_ABI_VENDOR[] = "FreeBSD";
+
+int
+__elfN(freebsd_abi_note)(struct image_params *imgp, int32_t *osrel)
+{
+	const Elf_Note *note, *note_end;
+	const Elf32_Phdr *phdr, *pnote;
+	const Elf32_Ehdr *hdr;
+	const char *note_name;
+	int i;
+
+	pnote = NULL;
+	hdr = (const Elf32_Ehdr *)imgp->image_header;
+	phdr = (const Elf32_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 (0);
+
+	note = (const Elf_Note *)(imgp->image_header + pnote->p_offset);
+	if (!aligned(note, uint32_t))
+		return (0);
+	note_end = (const Elf_Note *)(hdr + pnote->p_offset +
+	    pnote->p_filesz);
+	while (note < note_end) {
+		if (note->n_namesz == sizeof(FREEBSD_ABI_VENDOR) &&
+		    note->n_descsz == sizeof(int32_t) &&
+		    note->n_type == 1 /* ABI_NOTETYPE */) {
+			note_name = (const char *)(note + 1);
+			if (strncmp(FREEBSD_ABI_VENDOR, note_name,
+			    sizeof(FREEBSD_ABI_VENDOR)) != 0)
+				continue;
+			/*
+			 * Fetch the osreldate for FreeBSD binary
+			 * from the ELF OSABI-note.
+			 */
+			if (osrel != NULL)
+				*osrel = *(const int32_t *)
+				    (note_name +
+				    round_page_ps(sizeof(FREEBSD_ABI_VENDOR),
+				    sizeof(Elf32_Addr)));
+			return(1);
+		}
+		note = (const Elf_Note *)((const char *)(note + 1) +
+		    round_page_ps(note->n_namesz, sizeof(Elf32_Addr)) +
+		    round_page_ps(note->n_descsz, sizeof(Elf32_Addr)));
+	}
+
+	return (0);
+}
+
 /*
  * Tell kern_execve.c about it, with a little help from the linker.
  */
diff --git a/sys/mips/mips/elf_machdep.c b/sys/mips/mips/elf_machdep.c
index 163d0ee..807ae67 100644
--- a/sys/mips/mips/elf_machdep.c
+++ b/sys/mips/mips/elf_machdep.c
_at__at_ -86,6 +86,8 _at__at_ static Elf32_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
+	.brand_abi_note	= NULL,
+	.brand_abi_note	= NULL,
 	.flags		= 0
 };
 
diff --git a/sys/powerpc/powerpc/elf_machdep.c b/sys/powerpc/powerpc/elf_machdep.c
index 69ac55b..f0dc474 100644
--- a/sys/powerpc/powerpc/elf_machdep.c
+++ b/sys/powerpc/powerpc/elf_machdep.c
_at__at_ -87,7 +87,8 _at__at_ static Elf32_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(elf32, SI_SUB_EXEC, SI_ORDER_ANY,
_at__at_ -102,7 +103,8 _at__at_ static Elf32_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf32_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oelf32, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/sparc64/sparc64/elf_machdep.c b/sys/sparc64/sparc64/elf_machdep.c
index a956c5c..03b9056 100644
--- a/sys/sparc64/sparc64/elf_machdep.c
+++ b/sys/sparc64/sparc64/elf_machdep.c
_at__at_ -99,7 +99,8 _at__at_ static Elf64_Brandinfo freebsd_brand_info = {
 	.interp_path	= "/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(elf64, SI_SUB_EXEC, SI_ORDER_ANY,
_at__at_ -114,7 +115,8 _at__at_ static Elf64_Brandinfo freebsd_brand_oinfo = {
 	.interp_path	= "/usr/libexec/ld-elf.so.1",
 	.sysvec		= &elf64_freebsd_sysvec,
 	.interp_newpath	= NULL,
-	.flags		= BI_CAN_EXEC_DYN,
+	.brand_abi_note	= __elfN(freebsd_abi_note),
+	.flags		= BI_CAN_EXEC_DYN
 };
 
 SYSINIT(oelf64, SI_SUB_EXEC, SI_ORDER_ANY,
diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h
index deb5b10..d290185 100644
--- a/sys/sys/imgact_elf.h
+++ b/sys/sys/imgact_elf.h
_at__at_ -62,8 +62,10 _at__at_ typedef struct {
 	const char *interp_path;
 	struct sysentvec *sysvec;
 	const char *interp_newpath;
+	int (*brand_abi_note)(struct image_params *, int32_t *);
 	int flags;
-#define	BI_CAN_EXEC_DYN	0x0001
+#define	BI_CAN_EXEC_DYN		0x0001
+#define	BI_CAN_EXEC_INTERP	0x0002
 } __ElfN(Brandinfo);
 
 __ElfType(Auxargs);
_at__at_ -76,6 +78,7 _at__at_ int	__elfN(insert_brand_entry)(Elf_Brandinfo *entry);
 int	__elfN(remove_brand_entry)(Elf_Brandinfo *entry);
 int	__elfN(freebsd_fixup)(register_t **, struct image_params *);
 int	__elfN(coredump)(struct thread *, struct vnode *, off_t);
+int	__elfN(freebsd_abi_note)(struct image_params *, int32_t *);
 
 /* Machine specific function to dump per-thread information. */
 void	__elfN(dump_thread)(struct thread *, void *, size_t *);


-- 
Have fun!
chd
Received on Tue Jan 06 2009 - 12:14:20 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:40 UTC