From 34df0d6ef1b91d9a6125de4e29c855bd3c92b749 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Sat, 12 Mar 2022 14:21:51 -0800 Subject: [PATCH] More empty HASH and/or GNU_HASH when Rust-musl https://github.com/upx/upx/issues/568 modified: p_lx_elf.cpp --- src/p_lx_elf.cpp | 148 ++++++++++++++++++++++++----------------------- 1 file changed, 75 insertions(+), 73 deletions(-) diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 5d4c5018..6050153d 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -5732,19 +5732,20 @@ Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const unsigned const nbucket = get_te32(&hashtab[0]); unsigned const *const buckets = &hashtab[2]; unsigned const *const chains = &buckets[nbucket]; - if (!nbucket - || (unsigned)(file_size - ((char const *)buckets - (char const *)(void const *)file_image)) + if ((unsigned)(file_size - ((char const *)buckets - (char const *)(void const *)file_image)) <= sizeof(unsigned)*nbucket ) { char msg[80]; snprintf(msg, sizeof(msg), "bad nbucket %#x\n", nbucket); throwCantPack(msg); } - unsigned const m = elf_hash(name) % nbucket; - unsigned si; - for (si= get_te32(&buckets[m]); 0!=si; si= get_te32(&chains[si])) { - char const *const p= get_dynsym_name(si, (unsigned)-1); - if (0==strcmp(name, p)) { - return &dynsym[si]; + if (nbucket) { + unsigned const m = elf_hash(name) % nbucket; + unsigned si; + for (si= get_te32(&buckets[m]); 0!=si; si= get_te32(&chains[si])) { + char const *const p= get_dynsym_name(si, (unsigned)-1); + if (0==strcmp(name, p)) { + return &dynsym[si]; + } } } } @@ -5756,8 +5757,7 @@ Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const unsigned const *const bitmask = &gashtab[4]; unsigned const *const buckets = &bitmask[n_bitmask]; unsigned const *const hasharr = &buckets[n_bucket]; - if (!n_bucket - || (void const *)&file_image[file_size] <= (void const *)hasharr) { + if ((void const *)&file_image[file_size] <= (void const *)hasharr) { char msg[80]; snprintf(msg, sizeof(msg), "bad n_bucket %#x\n", n_bucket); throwCantPack(msg); @@ -5769,33 +5769,33 @@ Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const "bad n_bitmask %#x\n", n_bitmask); throwCantPack(msg); } + if (n_bucket) { + unsigned const h = gnu_hash(name); + unsigned const hbit1 = 037& h; + unsigned const hbit2 = 037& (h>>gnu_shift); + unsigned const w = get_te32(&bitmask[(n_bitmask -1) & (h>>5)]); - unsigned const h = gnu_hash(name); - unsigned const hbit1 = 037& h; - unsigned const hbit2 = 037& (h>>gnu_shift); - unsigned const w = get_te32(&bitmask[(n_bitmask -1) & (h>>5)]); - - if (1& (w>>hbit1) & (w>>hbit2)) { - unsigned bucket = get_te32(&buckets[h % n_bucket]); - if (n_bucket <= bucket) { - char msg[90]; snprintf(msg, sizeof(msg), - "bad DT_GNU_HASH n_bucket{%#x} <= buckets[%d]{%#x}\n", - n_bucket, h % n_bucket, bucket); - throwCantPack(msg); - } - if (0!=bucket) { - Elf32_Sym const *dsp = &dynsym[bucket]; - unsigned const *hp = &hasharr[bucket - symbias]; - - do if (0==((h ^ get_te32(hp))>>1)) { - unsigned st_name = get_te32(&dsp->st_name); - char const *const p = get_str_name(st_name, (unsigned)-1); - if (0==strcmp(name, p)) { - return dsp; - } - } while (++dsp, - (char const *)hp < (char const *)&file_image[file_size] - && 0==(1u& get_te32(hp++))); + if (1& (w>>hbit1) & (w>>hbit2)) { + unsigned bucket = get_te32(&buckets[h % n_bucket]); + if (n_bucket <= bucket) { + char msg[90]; snprintf(msg, sizeof(msg), + "bad DT_GNU_HASH n_bucket{%#x} <= buckets[%d]{%#x}\n", + n_bucket, h % n_bucket, bucket); + throwCantPack(msg); + } + if (0!=bucket) { + Elf32_Sym const *dsp = &dynsym[bucket]; + unsigned const *hp = &hasharr[bucket - symbias]; + do if (0==((h ^ get_te32(hp))>>1)) { + unsigned st_name = get_te32(&dsp->st_name); + char const *const p = get_str_name(st_name, (unsigned)-1); + if (0==strcmp(name, p)) { + return dsp; + } + } while (++dsp, + (char const *)hp < (char const *)&file_image[file_size] + && 0==(1u& get_te32(hp++))); + } } } } @@ -5803,6 +5803,7 @@ Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const // (1==n_bucket && 0==buckets[0] && 1==n_bitmask && 0==bitmask[0]) // to minimize space in DT_GNU_HASH. This causes the fancy lookup to fail. // Is a fallback to linear seach assumed? + // 2022-03-12 Some Rust programs have 0==n_bucket. return nullptr; } @@ -5813,19 +5814,20 @@ Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const unsigned const nbucket = get_te32(&hashtab[0]); unsigned const *const buckets = &hashtab[2]; unsigned const *const chains = &buckets[nbucket]; - if (!nbucket - || (unsigned)(file_size - ((char const *)buckets - (char const *)(void const *)file_image)) + if ((unsigned)(file_size - ((char const *)buckets - (char const *)(void const *)file_image)) <= sizeof(unsigned)*nbucket ) { char msg[80]; snprintf(msg, sizeof(msg), "bad nbucket %#x\n", nbucket); throwCantPack(msg); } - unsigned const m = elf_hash(name) % nbucket; - unsigned si; - for (si= get_te32(&buckets[m]); 0!=si; si= get_te32(&chains[si])) { - char const *const p= get_dynsym_name(si, (unsigned)-1); - if (0==strcmp(name, p)) { - return &dynsym[si]; + if (nbucket) { // -rust-musl can have "empty" hashtab + unsigned const m = elf_hash(name) % nbucket; + unsigned si; + for (si= get_te32(&buckets[m]); 0!=si; si= get_te32(&chains[si])) { + char const *const p= get_dynsym_name(si, (unsigned)-1); + if (0==strcmp(name, p)) { + return &dynsym[si]; + } } } } @@ -5837,8 +5839,8 @@ Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const upx_uint64_t const *const bitmask = (upx_uint64_t const *)(void const *)&gashtab[4]; unsigned const *const buckets = (unsigned const *)&bitmask[n_bitmask]; unsigned const *const hasharr = &buckets[n_bucket]; - if (!n_bucket - || (void const *)&file_image[file_size] <= (void const *)hasharr) { + + if ((void const *)&file_image[file_size] <= (void const *)hasharr) { char msg[80]; snprintf(msg, sizeof(msg), "bad n_bucket %#x\n", n_bucket); throwCantPack(msg); @@ -5850,33 +5852,32 @@ Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const "bad n_bitmask %#x\n", n_bitmask); throwCantPack(msg); } - - unsigned const h = gnu_hash(name); - unsigned const hbit1 = 077& h; - unsigned const hbit2 = 077& (h>>gnu_shift); - upx_uint64_t const w = get_te64(&bitmask[(n_bitmask -1) & (h>>6)]); - - if (1& (w>>hbit1) & (w>>hbit2)) { - unsigned bucket = get_te32(&buckets[h % n_bucket]); - if (n_bucket <= bucket) { - char msg[90]; snprintf(msg, sizeof(msg), - "bad DT_GNU_HASH n_bucket{%#x} <= buckets[%d]{%#x}\n", - n_bucket, h % n_bucket, bucket); - throwCantPack(msg); - } - if (0!=bucket) { - Elf64_Sym const *dsp = &dynsym[bucket]; - unsigned const *hp = &hasharr[bucket - symbias]; - - do if (0==((h ^ get_te32(hp))>>1)) { - unsigned st_name = get_te32(&dsp->st_name); - char const *const p = get_str_name(st_name, (unsigned)-1); - if (0==strcmp(name, p)) { - return dsp; - } - } while (++dsp, - (char const *)hp < (char const *)&file_image[file_size] - && 0==(1u& get_te32(hp++))); + if (n_bucket) { // -rust-musl can have "empty" gashtab + unsigned const h = gnu_hash(name); + unsigned const hbit1 = 077& h; + unsigned const hbit2 = 077& (h>>gnu_shift); + upx_uint64_t const w = get_te64(&bitmask[(n_bitmask -1) & (h>>6)]); + if (1& (w>>hbit1) & (w>>hbit2)) { + unsigned bucket = get_te32(&buckets[h % n_bucket]); + if (n_bucket <= bucket) { + char msg[90]; snprintf(msg, sizeof(msg), + "bad DT_GNU_HASH n_bucket{%#x} <= buckets[%d]{%#x}\n", + n_bucket, h % n_bucket, bucket); + throwCantPack(msg); + } + if (0!=bucket) { + Elf64_Sym const *dsp = &dynsym[bucket]; + unsigned const *hp = &hasharr[bucket - symbias]; + do if (0==((h ^ get_te32(hp))>>1)) { + unsigned st_name = get_te32(&dsp->st_name); + char const *const p = get_str_name(st_name, (unsigned)-1); + if (0==strcmp(name, p)) { + return dsp; + } + } while (++dsp, + (char const *)hp < (char const *)&file_image[file_size] + && 0==(1u& get_te32(hp++))); + } } } } @@ -5884,6 +5885,7 @@ Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const // (1==n_bucket && 0==buckets[0] && 1==n_bitmask && 0==bitmask[0]) // to minimize space in DT_GNU_HASH. This causes the fancy lookup to fail. // Is a fallback to linear seach assumed? + // 2022-03-12 Some Rust programs have 0==n_bucket. return nullptr; }