kernel ELF: Improve OS Release Date handling
authorJohn Marino <draco@marino.st>
Thu, 19 May 2011 22:33:16 +0000 (00:33 +0200)
committerJohn Marino <draco@marino.st>
Thu, 19 May 2011 22:37:15 +0000 (00:37 +0200)
This brings in FreeBSD's method of having separate OS Release Date
(osreldate) handling for each brand.  Previously the decoding method
was hardcoded for *BSD, which meant it was broken for the Linux brand.
Now all supported brands (DragonFly, FreeBSD, Linux) are retrieving the
osreldate values correctly.

sys/emulation/linux/i386/linux_sysvec.c
sys/kern/imgact_elf.c
sys/sys/imgact_elf.h

index 8f6f3d3..f819797 100644 (file)
@@ -26,7 +26,6 @@
  * 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.31 2008/04/21 15:47:53 dillon Exp $
  */
 
 /* XXX we use functions that might not exist. */
@@ -98,6 +97,7 @@ static void   linux_prepsyscall (struct trapframe *tf, int *args,
                                       u_int *code, caddr_t *params);
 static void     linux_sendsig (sig_t catcher, int sig, sigset_t *mask,
                                   u_long code);
+static boolean_t linux_trans_osrel(const Elf_Note *note, int32_t *osrel);
 
 static eventhandler_tag linux_exec_tag;
 static eventhandler_tag linux_exit_tag;
@@ -830,21 +830,47 @@ struct sysentvec elf_linux_sysvec = {
 
 static const char GNU_ABI_VENDOR[] = "GNU";
 static const char SUSE_ABI_VENDOR[] = "SuSE";
+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:
+        * VVVMMMIII (version, major, minor)
+        */
+       *osrel = desc[1] * 1000000 +
+                desc[2] * 1000 +
+                desc[3];
+
+       return (TRUE);
+}
 
 static Elf_Brandnote linux32_generic_brandnote = {
-        .hdr.n_namesz  = sizeof(GNU_ABI_VENDOR),
-        .hdr.n_descsz  = 16,
-        .hdr.n_type    = 1,
-        .vendor                = GNU_ABI_VENDOR,
-        .flags         = 0,
+       .hdr.n_namesz   = sizeof(GNU_ABI_VENDOR),
+       .hdr.n_descsz   = 16,
+       .hdr.n_type     = 1,
+       .vendor         = GNU_ABI_VENDOR,
+       .flags          = BN_TRANSLATE_OSREL,
+       .trans_osrel    = linux_trans_osrel,
 };
 
 static Elf_Brandnote linux32_suse_brandnote = {
-        .hdr.n_namesz  = sizeof(SUSE_ABI_VENDOR),
-        .hdr.n_descsz  = 16,
-        .hdr.n_type    = 1,
-        .vendor                = SUSE_ABI_VENDOR,
-        .flags         = 0,
+       .hdr.n_namesz   = sizeof(SUSE_ABI_VENDOR),
+       .hdr.n_descsz   = 16,
+       .hdr.n_type     = 1,
+       .vendor         = SUSE_ABI_VENDOR,
+       .flags          = BN_TRANSLATE_OSREL,
+       .trans_osrel    = linux_trans_osrel,
 };
 
 static Elf32_Brandinfo linux32_brand = {
index 4915b31..b805836 100644 (file)
@@ -83,6 +83,8 @@ static int __elfN(load_section)(struct proc *p,
     vm_offset_t offset, caddr_t vmaddr, size_t memsz, size_t filsz,
     vm_prot_t prot);
 static int __CONCAT(exec_, __elfN(imgact))(struct image_params *imgp);
+static boolean_t __elfN(bsd_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);
 static boolean_t check_PT_NOTE(struct image_params *imgp,
@@ -118,7 +120,8 @@ Elf_Brandnote __elfN(dragonfly_brandnote) = {
        .hdr.n_descsz   = sizeof(int32_t),
        .hdr.n_type     = 1,
        .vendor         = DRAGONFLY_ABI_VENDOR,
-       .flags          = BN_CAN_FETCH_OSREL,
+       .flags          = BN_TRANSLATE_OSREL,
+       .trans_osrel    = __elfN(bsd_trans_osrel),
 };
 
 Elf_Brandnote __elfN(freebsd_brandnote) = {
@@ -126,7 +129,8 @@ 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(bsd_trans_osrel),
 };
 
 int
@@ -1724,11 +1728,9 @@ check_PT_NOTE(struct image_params *imgp, Elf_Brandnote *checknote,
                    && (strncmp(checknote->vendor, note_name,
                        checknote->hdr.n_namesz) == 0)) {
                        /* Fetch osreldata from ABI.note-tag */
-                       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));
                        found = TRUE;
                        break;
                }
@@ -1797,6 +1799,18 @@ extract_interpreter(struct image_params *imgp, const Elf_Phdr *pinterpreter,
        return (result_success);
 }
 
+static boolean_t
+__elfN(bsd_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);
+}
+
 /*
  * Tell kern_execve.c about it, with a little help from the linker.
  */
index ad31c49..dd4a0bc 100644 (file)
@@ -61,6 +61,7 @@ typedef struct {
        Elf_Note        hdr;
        const char *    vendor;
        int             flags;
+       boolean_t       (*trans_osrel)(const Elf_Note *, int32_t *);
 } Elf_Brandnote;
 
 typedef struct {
@@ -82,7 +83,8 @@ __ElfType(Brandinfo);
 #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. */
-#define        BN_CAN_FETCH_OSREL      0x0001
+#define        BN_CAN_FETCH_OSREL      0x0001  /* No longer used */
+#define        BN_TRANSLATE_OSREL      0x0002  /* New osreldate function pointer */
 
 int    __elfN(brand_inuse)        (Elf_Brandinfo *entry);
 int    __elfN(insert_brand_entry) (Elf_Brandinfo *entry);