commit:     e20faa493f9dd326f7bc0fbf2c0abe1a4fdae0e4
Author:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
AuthorDate: Wed Jul 27 04:47:39 2016 +0000
Commit:     Mike Frysinger <vapier <AT> gentoo <DOT> org>
CommitDate: Sat Nov 12 07:10:13 2016 +0000
URL:        https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=e20faa49

paxldso: properly decode the flags bits in the cache

This fixes handling of multiple ABIs for a single arch like x86/x86_64/x32
or mips o32/n32/n64.  It also fixes decoding of arm float libs.

 paxldso.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 114 insertions(+), 34 deletions(-)

diff --git a/paxldso.c b/paxldso.c
index 5ea0bfc..2227387 100644
--- a/paxldso.c
+++ b/paxldso.c
@@ -20,30 +20,121 @@ static size_t ldcache_size = 0;
 static char *ldso_cache_buf = NULL;
 static size_t ldso_cache_buf_size = 0;
 
+#if defined(__GLIBC__) || defined(__UCLIBC__)
+
 /* Defines can be seen in glibc's sysdeps/generic/ldconfig.h */
-#define LDSO_CACHE_MAGIC "ld.so-"
-#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
-#define LDSO_CACHE_VER "1.7.0"
-#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
-#define FLAG_ANY            -1
-#define FLAG_TYPE_MASK      0x00ff
-#define FLAG_LIBC4          0x0000
-#define FLAG_ELF            0x0001
-#define FLAG_ELF_LIBC5      0x0002
-#define FLAG_ELF_LIBC6      0x0003
-#define FLAG_REQUIRED_MASK  0xff00
-#define FLAG_SPARC_LIB64    0x0100
-#define FLAG_IA64_LIB64     0x0200
-#define FLAG_X8664_LIB64    0x0300
-#define FLAG_S390_LIB64     0x0400
-#define FLAG_POWERPC_LIB64  0x0500
-#define FLAG_MIPS64_LIBN32  0x0600
-#define FLAG_MIPS64_LIBN64  0x0700
-#define FLAG_X8664_LIBX32   0x0800
-#define FLAG_ARM_LIBHF      0x0900
-#define FLAG_AARCH64_LIB64  0x0a00
+#define LDSO_CACHE_MAGIC             "ld.so-"
+#define LDSO_CACHE_MAGIC_LEN         (sizeof LDSO_CACHE_MAGIC -1)
+#define LDSO_CACHE_VER               "1.7.0"
+#define LDSO_CACHE_VER_LEN           (sizeof LDSO_CACHE_VER -1)
+#define FLAG_ANY                     -1
+#define FLAG_TYPE_MASK               0x00ff
+#define FLAG_LIBC4                   0x0000
+#define FLAG_ELF                     0x0001
+#define FLAG_ELF_LIBC5               0x0002
+#define FLAG_ELF_LIBC6               0x0003
+#define FLAG_REQUIRED_MASK           0xff00
+#define FLAG_SPARC_LIB64             0x0100
+#define FLAG_IA64_LIB64              0x0200
+#define FLAG_X8664_LIB64             0x0300
+#define FLAG_S390_LIB64              0x0400
+#define FLAG_POWERPC_LIB64           0x0500
+#define FLAG_MIPS64_LIBN32           0x0600
+#define FLAG_MIPS64_LIBN64           0x0700
+#define FLAG_X8664_LIBX32            0x0800
+#define FLAG_ARM_LIBHF               0x0900
+#define FLAG_AARCH64_LIB64           0x0a00
+#define FLAG_ARM_LIBSF               0x0b00
+#define FLAG_MIPS_LIB32_NAN2008      0x0c00
+#define FLAG_MIPS64_LIBN32_NAN2008   0x0d00
+#define FLAG_MIPS64_LIBN64_NAN2008   0x0e00
+
+typedef struct {
+       int flags;
+       unsigned int sooffset;
+       unsigned int liboffset;
+} libentry_t;
+
+static bool is_compatible(elfobj *elf, libentry_t *libent)
+{
+       int flags = libent->flags & FLAG_REQUIRED_MASK;
+
+       /* We assume that ((flags & FLAG_TYPE_MASK) == FLAG_ELF_LIBC6)
+        * since anything older is very very old and no one cares.
+        *
+        * Otherwise we really only need to check here for cases where
+        * an arch has more than one ABI per bitsize (e.g. x86, x32, and
+        * x86_64).  The default case should be fine otherwise.
+        */
+
+       if (elf->elf_class == ELFCLASS32) {
+               Elf32_Ehdr *ehdr = EHDR32(elf->ehdr);
+
+               switch (EGET(ehdr->e_machine)) {
+               case EM_AARCH64:
+                       break;
+               case EM_ARM:
+                       if ((flags == FLAG_ARM_LIBHF && (ehdr->e_flags & 
EF_ARM_ABI_FLOAT_HARD)) ||
+                           (flags == FLAG_ARM_LIBSF && (ehdr->e_flags & 
EF_ARM_ABI_FLOAT_SOFT)) ||
+                           (flags == 0 && !(ehdr->e_flags & 
(EF_ARM_ABI_FLOAT_HARD | EF_ARM_ABI_FLOAT_SOFT))))
+                               return true;
+                       break;
+               case EM_IA_64:
+                       break;
+               case EM_MIPS: {
+                       int ef_flags = (ehdr->e_flags & (EF_MIPS_ABI2 | 
EF_MIPS_NAN2008));
+                       if ((flags == 0 && ef_flags == 0) ||
+                           (flags == FLAG_MIPS64_LIBN32 && ef_flags == 
EF_MIPS_ABI2) ||
+                           (flags == FLAG_MIPS_LIB32_NAN2008 && ef_flags == 
EF_MIPS_NAN2008) ||
+                           (flags == FLAG_MIPS64_LIBN32_NAN2008 && ef_flags == 
(EF_MIPS_ABI2 | EF_MIPS_NAN2008)))
+                               return true;
+                       break;
+               }
+               case EM_X86_64:
+                       if (flags == FLAG_X8664_LIBX32)
+                               return true;
+                       break;
+               default:
+                       /* A sane enough default. */
+                       if (flags == 0)
+                               return true;
+                       break;
+               }
+       } else {
+               Elf64_Ehdr *ehdr = EHDR64(elf->ehdr);
+
+               switch (EGET(ehdr->e_machine)) {
+               case EM_AARCH64:
+                       if (flags == FLAG_AARCH64_LIB64)
+                               return true;
+                       break;
+               case EM_ARM:
+                       break;
+               case EM_IA_64:
+                       if (flags == FLAG_IA64_LIB64)
+                               return true;
+                       break;
+               case EM_MIPS: {
+                       int ef_flags = (ehdr->e_flags & EF_MIPS_NAN2008);
+                       if ((flags == FLAG_MIPS64_LIBN64 && ef_flags == 0) ||
+                           (flags == FLAG_MIPS64_LIBN64_NAN2008 && ef_flags == 
EF_MIPS_NAN2008))
+                               return true;
+                       break;
+               }
+               case EM_X86_64:
+                       if (flags == FLAG_X8664_LIB64)
+                               return true;
+                       break;
+               default:
+                       /* A sane enough default. */
+                       if (flags != 0)
+                               return true;
+                       break;
+               }
+       }
 
-#if defined(__GLIBC__) || defined(__UCLIBC__)
+       return false;
+}
 
 char *ldso_cache_lookup_lib(elfobj *elf, const char *fname)
 {
@@ -58,11 +149,6 @@ char *ldso_cache_lookup_lib(elfobj *elf, const char *fname)
        } header_t;
        header_t *header;
 
-       typedef struct {
-               int flags;
-               unsigned int sooffset;
-               unsigned int liboffset;
-       } libentry_t;
        libentry_t *libent;
 
        if (fname == NULL)
@@ -110,13 +196,7 @@ char *ldso_cache_lookup_lib(elfobj *elf, const char *fname)
                const char *lib;
                size_t lib_len;
 
-               /* This should be more fine grained, but for now we assume that
-                * diff arches will not be cached together, and we ignore the
-                * the different multilib mips cases.
-                */
-               if (elf->elf_class == ELFCLASS64 && !(libent[nlib].flags & 
FLAG_REQUIRED_MASK))
-                       continue;
-               if (elf->elf_class == ELFCLASS32 && (libent[nlib].flags & 
FLAG_REQUIRED_MASK))
+               if (!is_compatible(elf, &libent[nlib]))
                        continue;
 
                if (strcmp(fname, strs + libent[nlib].sooffset) != 0)

Reply via email to