Don't match executables with ELFOSABI_NONE against the brand list.
authorJoerg Sonnenberger <joerg@dragonflybsd.org>
Tue, 31 May 2005 17:45:20 +0000 (17:45 +0000)
committerJoerg Sonnenberger <joerg@dragonflybsd.org>
Tue, 31 May 2005 17:45:20 +0000 (17:45 +0000)
For binaries without matching brand, try to match PT_NOTE header
of type 1 (which is equal to .note.ABI-tag as section).

Implement matching for FreeBSD, the up-coming DragonFly and Linux
ABI tag.

This implementation has some known limitations:
- only one PT_NOTE header of type 1 is checked (the last)
- the PT_NOTE header has to be part of the first page
- ELF branding is prefered, no further matching is done (prevents multiple
  ABI emulations for the same ELF OS ABI)

Inspired-by: NetBSD
sys/emulation/linux/i386/linux_sysvec.c
sys/emulation/svr4/svr4_sysvec.c
sys/kern/imgact_elf.c
sys/sys/imgact_elf.h

index 33300df..c6a1f8d 100644 (file)
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/i386/linux/linux_sysvec.c,v 1.55.2.9 2002/01/12 11:03:30 bde Exp $
- * $DragonFly: src/sys/emulation/linux/i386/linux_sysvec.c,v 1.16 2004/08/15 14:15:00 joerg Exp $
+ * $DragonFly: src/sys/emulation/linux/i386/linux_sysvec.c,v 1.17 2005/05/31 17:45:20 joerg Exp $
  */
 
 /* XXX we use functions that might not exist. */
@@ -793,9 +793,12 @@ struct sysentvec elf_linux_sysvec = {
        LINUX_MINSIGSTKSZ
 };
 
+static int     linux_match_abi_note(const Elf_Note *abi_note);
+
 static Elf32_Brandinfo linux_brand = {
                                        ELFOSABI_LINUX,
                                        "Linux",
+                                       linux_match_abi_note,
                                        "/compat/linux",
                                        "/lib/ld-linux.so.1",
                                        &elf_linux_sysvec
@@ -804,6 +807,7 @@ static Elf32_Brandinfo linux_brand = {
 static Elf32_Brandinfo linux_glibc2brand = {
                                        ELFOSABI_LINUX,
                                        "Linux",
+                                       linux_match_abi_note,
                                        "/compat/linux",
                                        "/lib/ld-linux.so.2",
                                        &elf_linux_sysvec
@@ -815,6 +819,26 @@ Elf32_Brandinfo *linux_brandlist[] = {
                                        NULL
                                };
 
+static int
+linux_match_abi_note(const Elf_Note *abi_note)
+{
+       const char *abi_name = (const char *)
+           ((const uint8_t *)abi_note + sizeof(*abi_note));
+       const uint32_t *descr = (const uint32_t *)
+           ((const uint8_t *)abi_name + abi_note->n_namesz);
+
+       if (abi_note->n_namesz != sizeof("GNU"))
+               return(FALSE);
+       if (memcmp(abi_name, "GNU", sizeof("GNU")))
+               return(FALSE);
+       if (abi_note->n_descsz < sizeof(uint32_t))
+               return(FALSE);
+
+       if (*descr != 0)
+               return(FALSE);
+       return(TRUE);
+}
+
 static int
 linux_elf_modevent(module_t mod, int type, void *data)
 {
index c03819b..989936a 100644 (file)
@@ -28,7 +28,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * 
  * $FreeBSD: src/sys/svr4/svr4_sysvec.c,v 1.10.2.2 2002/07/09 14:12:43 robert Exp $
- * $DragonFly: src/sys/emulation/svr4/Attic/svr4_sysvec.c,v 1.11 2004/11/12 00:09:22 dillon Exp $
+ * $DragonFly: src/sys/emulation/svr4/Attic/svr4_sysvec.c,v 1.12 2005/05/31 17:45:20 joerg Exp $
  */
 
 /* XXX we use functions that might not exist. */
@@ -190,6 +190,7 @@ struct sysentvec svr4_sysvec = {
 Elf32_Brandinfo svr4_brand = {
   ELFOSABI_SYSV,
   "SVR4",
+  NULL,
   "/compat/svr4",
   "/lib/libc.so.1",
   &svr4_sysvec
index abff851..34985e3 100644 (file)
@@ -27,7 +27,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/imgact_elf.c,v 1.73.2.13 2002/12/28 19:49:41 dillon Exp $
- * $DragonFly: src/sys/kern/imgact_elf.c,v 1.26 2005/03/08 12:30:32 davidxu Exp $
+ * $DragonFly: src/sys/kern/imgact_elf.c,v 1.27 2005/05/31 17:45:19 joerg Exp $
  */
 
 #include <sys/param.h>
@@ -87,6 +87,9 @@ static int elf_legacy_coredump = 0;
 SYSCTL_INT(_debug, OID_AUTO, elf_legacy_coredump, CTLFLAG_RW,
     &elf_legacy_coredump, 0, "");
 
+static int dragonfly_match_abi_note(const Elf_Note *);
+static int freebsd_match_abi_note(const Elf_Note *);
+
 static struct sysentvec elf_freebsd_sysvec = {
         SYS_MAXSYSCALL,
         sysent,
@@ -110,16 +113,54 @@ static struct sysentvec elf_freebsd_sysvec = {
 static Elf_Brandinfo freebsd_brand_info = {
                                                ELFOSABI_FREEBSD,
                                                "FreeBSD",
+                                               freebsd_match_abi_note,
                                                "",
                                                "/usr/libexec/ld-elf.so.1",
                                                &elf_freebsd_sysvec
                                          };
+
+static Elf_Brandinfo dragonfly_brand_info = {
+                                               ELFOSABI_NONE,
+                                               "DragonFly",
+                                               dragonfly_match_abi_note,
+                                               "",
+                                               "/usr/libexec/ld-elf.so.2",
+                                               &elf_freebsd_sysvec
+                                         };
+
 static Elf_Brandinfo *elf_brand_list[MAX_BRANDS] = {
+                                                       &dragonfly_brand_info,
                                                        &freebsd_brand_info,
                                                        NULL, NULL, NULL,
-                                                       NULL, NULL, NULL, NULL
+                                                       NULL, NULL, NULL
                                                    };
 
+static int
+freebsd_match_abi_note(const Elf_Note *abi_note)
+{
+       const char *abi_name = (const char *)
+           ((const uint8_t *)abi_note + sizeof(*abi_note));
+
+       if (abi_note->n_namesz != sizeof("FreeBSD"))
+               return(FALSE);
+       if (memcmp(abi_name, "FreeBSD", sizeof("FreeBSD")))
+               return(FALSE);
+       return(TRUE);
+}
+
+static int
+dragonfly_match_abi_note(const Elf_Note *abi_note)
+{
+       const char *abi_name = (const char *)
+           ((const uint8_t *)abi_note + sizeof(*abi_note));
+
+       if (abi_note->n_namesz != sizeof("DragonFly"))
+               return(FALSE);
+       if (memcmp(abi_name, "DragonFly", sizeof("DragonFly")))
+               return(FALSE);
+       return(TRUE);
+}
+
 int
 elf_insert_brand_entry(Elf_Brandinfo *entry)
 {
@@ -483,6 +524,7 @@ exec_elf_imgact(struct image_params *imgp)
        u_long addr, entry = 0, proghdr = 0;
        int error, i;
        const char *interp = NULL;
+       const Elf_Note *abi_note = NULL;
        Elf_Brandinfo *brand_info;
        char *path;
 
@@ -606,6 +648,23 @@ exec_elf_imgact(struct image_params *imgp)
                        }
                        interp = imgp->image_header + phdr[i].p_offset;
                        break;
+               case PT_NOTE:   /* Check for .note.ABI-tag */
+               {
+                       const Elf_Note *tmp_note;
+                       /* XXX handle anything outside the first page */
+                       if (phdr[i].p_offset + phdr[i].p_filesz > PAGE_SIZE)
+                               continue;
+                       if (phdr[i].p_filesz < sizeof(Elf_Note))
+                               continue; /* ENOEXEC? */
+                       tmp_note = (const Elf_Note *)(imgp->image_header + phdr[i].p_offset);
+                       if (tmp_note->n_type != 1)
+                               continue;
+                       if (tmp_note->n_namesz + sizeof(Elf_Note) +
+                           tmp_note->n_descsz > phdr[i].p_filesz)
+                               continue; /* ENOEXEC? */
+                       abi_note = tmp_note;
+               }       
+                       break;
                case PT_PHDR:   /* Program header table info */
                        proghdr = phdr[i].p_vaddr;
                        break;
@@ -633,7 +692,7 @@ exec_elf_imgact(struct image_params *imgp)
         */
 
        /* If the executable has a brand, search for it in the brand list. */
-       if (brand_info == NULL) {
+       if (brand_info == NULL && hdr->e_ident[EI_OSABI] != ELFOSABI_NONE) {
                for (i = 0;  i < MAX_BRANDS;  i++) {
                        Elf_Brandinfo *bi = elf_brand_list[i];
 
@@ -648,7 +707,20 @@ exec_elf_imgact(struct image_params *imgp)
                }
        }
 
-       /* Lacking a known brand, search for a recognized interpreter. */
+       /* Search for a recognized ABI. */
+       if (brand_info == NULL && abi_note != NULL) {
+               for (i = 0; i < MAX_BRANDS; i++) {
+                       Elf_Brandinfo *bi = elf_brand_list[i];
+
+                       if (bi != NULL && bi->match_abi_note != NULL &&
+                           (*bi->match_abi_note)(abi_note)) {
+                               brand_info = bi;
+                               break;
+                       }
+               }
+       }
+
+       /* Lacking a recognized ABI, search for a recognized interpreter. */
        if (brand_info == NULL && interp != NULL) {
                for (i = 0;  i < MAX_BRANDS;  i++) {
                        Elf_Brandinfo *bi = elf_brand_list[i];
@@ -678,7 +750,7 @@ exec_elf_imgact(struct image_params *imgp)
                    hdr->e_ident[EI_OSABI]);
                error = ENOEXEC;
                goto fail;
-       }
+       } else
 
        imgp->proc->p_sysent = brand_info->sysvec;
        if (interp != NULL) {
index d66e667..f1b092f 100644 (file)
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/sys/imgact_elf.h,v 1.17.2.1 2000/07/06 22:26:40 obrien Exp $
- * $DragonFly: src/sys/sys/imgact_elf.h,v 1.5 2004/10/25 08:57:50 dillon Exp $
+ * $DragonFly: src/sys/sys/imgact_elf.h,v 1.6 2005/05/31 17:45:19 joerg Exp $
  */
 
 #ifndef _SYS_IMGACT_ELF_H_
 #define _SYS_IMGACT_ELF_H_
 
+#include <sys/elf_common.h>
 #include <machine/elf.h>
 
 #ifdef _KERNEL
@@ -59,6 +60,7 @@ typedef struct {
 typedef struct {
        int brand;
        const char *compat_3_brand;     /* pre Binutils 2.10 method (FBSD 3) */
+       int (*match_abi_note)(const Elf_Note *);
        const char *emul_path;
        const char *interp_path;
         struct sysentvec *sysvec;