Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <CAORiPTPcHA0n-iT7Hk9tpCHknqcPCGnR8GnptxD9XjwGC2FD3w@mail.gmail.com>
Date: Fri, 22 Aug 2025 11:12:47 +0200
From: Tomáš Hulata <hulata@...art.tech>
To: musl@...ts.openwall.com
Subject: [PATCH] vdso: add support for GNU hash tables

On some kernels (e.g. AWS Ubuntu's Graviton official AMIs) the arm64 vDSO
exports symbols with DT_GNU_HASH but omits DT_HASH.  musl's
__vdsosym resolver only understands SysV hash, so vDSO symbols
fail to resolve and clock_gettime falls back to syscalls.

This patch adds a minimal GNU hash lookup implementation to
__vdsosym, fixing vDSO usage on affected systems.

---
 src/internal/vdso.c | 75 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 66 insertions(+), 9 deletions(-)

diff --git a/src/internal/vdso.c b/src/internal/vdso.c
index d46d3228..8fa19526 100644
--- a/src/internal/vdso.c
+++ b/src/internal/vdso.c
@@ -40,6 +40,53 @@ static int checkver(Verdef *def, int vsym, const char
*vername, char *strings)
 #define OK_TYPES (1<<STT_NOTYPE | 1<<STT_OBJECT | 1<<STT_FUNC |
1<<STT_COMMON)
 #define OK_BINDS (1<<STB_GLOBAL | 1<<STB_WEAK | 1<<STB_GNU_UNIQUE)

+static uint32_t gnu_hash(const char *s0)
+{
+    const unsigned char *s = (const void *)s0;
+    uint_fast32_t h = 5381;
+    for (; *s; s++) h += h*32 + *s;
+    return h;
+}
+
+static Sym *gnu_lookup(uint32_t h1, uint32_t *hashtab,
+                       Sym *syms, char *strings, uint16_t *versym,
+                       Verdef *verdef, const char *vername, const char *s)
+{
+    uint32_t nbuckets  = hashtab[0];
+    uint32_t symoffset = hashtab[1];
+    uint32_t *buckets  = hashtab + 4 + hashtab[2]*(sizeof(size_t)/4);
+    uint32_t i = buckets[h1 % nbuckets];
+    if (!i) return 0;
+
+    uint32_t *hashval = buckets + nbuckets + (i - symoffset);
+    for (h1 |= 1; ; i++) {
+        uint32_t h2 = *hashval++;
+        if ((h1 == (h2|1))
+            && (1<<(syms[i].st_info&0xf) & OK_TYPES)
+            && (1<<(syms[i].st_info>>4) & OK_BINDS)
+            && syms[i].st_shndx
+            && !strcmp(s, strings + syms[i].st_name)
+            && (!versym || !vername || checkver(verdef, versym[i],
vername, strings)))
+            return syms+i;
+        if (h2 & 1) break;
+    }
+    return 0;
+}
+
+static Sym *gnu_lookup_filtered(uint32_t h1, uint32_t *hashtab,
+                                Sym *syms, char *strings, uint16_t *versym,
+                                Verdef *verdef, const char *vername, const
char *s)
+{
+    const size_t *bloomwords = (const void *)(hashtab+4);
+    size_t bloom_sz = hashtab[2];
+    size_t f = bloomwords[(h1 / (8*sizeof(size_t))) & (bloom_sz - 1)];
+    size_t fmask = 1ul << (h1 % (8*sizeof(size_t)));
+    if (!(f & fmask)) return 0;
+    f >>= (h1 >> hashtab[3]) % (8 * sizeof f);
+    if (!(f & 1)) return 0;
+    return gnu_lookup(h1, hashtab, syms, strings, versym, verdef, vername,
s);
+}
+
 void *__vdsosym(const char *vername, const char *name)
 {
  size_t i;
@@ -60,6 +107,7 @@ void *__vdsosym(const char *vername, const char *name)
  char *strings = 0;
  Sym *syms = 0;
  Elf_Symndx *hashtab = 0;
+ uint32_t *ghashtab = 0; /* GNU hash */
  uint16_t *versym = 0;
  Verdef *verdef = 0;

@@ -69,22 +117,31 @@ void *__vdsosym(const char *vername, const char *name)
  case DT_STRTAB: strings = p; break;
  case DT_SYMTAB: syms = p; break;
  case DT_HASH: hashtab = p; break;
+ case DT_GNU_HASH: ghashtab = p; break;
  case DT_VERSYM: versym = p; break;
  case DT_VERDEF: verdef = p; break;
  }
  }

- if (!strings || !syms || !hashtab) return 0;
+ if (!strings || !syms) return 0;
  if (!verdef) versym = 0;

- for (i=0; i<hashtab[1]; i++) {
- if (!(1<<(syms[i].st_info&0xf) & OK_TYPES)) continue;
- if (!(1<<(syms[i].st_info>>4) & OK_BINDS)) continue;
- if (!syms[i].st_shndx) continue;
- if (strcmp(name, strings+syms[i].st_name)) continue;
- if (versym && !checkver(verdef, versym[i], vername, strings))
- continue;
- return (void *)(base + syms[i].st_value);
+ if (ghashtab) {
+ uint32_t h = gnu_hash(name);
+ Sym *s = gnu_lookup_filtered(h, ghashtab, syms, strings, versym, verdef,
vername, name);
+ if (s) return (void *)(base + s->st_value);
+ }
+
+ if (hashtab) {
+ for (i=0; i<hashtab[1]; i++) {
+ if (!(1<<(syms[i].st_info&0xf) & OK_TYPES)) continue;
+ if (!(1<<(syms[i].st_info>>4) & OK_BINDS)) continue;
+ if (!syms[i].st_shndx) continue;
+ if (strcmp(name, strings+syms[i].st_name)) continue;
+ if (versym && !checkver(verdef, versym[i], vername, strings))
+ continue;
+ return (void *)(base + syms[i].st_value);
+ }
  }

  return 0;
-- 

Best Regardas
Tomáš Hulata
*[ SysArt,  **Pixel Federation ]*

Content of type "text/html" skipped

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.