More empty HASH and/or GNU_HASH when Rust-musl

https://github.com/upx/upx/issues/568
	modified:   p_lx_elf.cpp
This commit is contained in:
John Reiser
2022-03-12 14:21:51 -08:00
committed by Markus F.X.J. Oberhumer
parent 540164849b
commit 34df0d6ef1
+15 -13
View File
@@ -5732,13 +5732,13 @@ Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const
unsigned const nbucket = get_te32(&hashtab[0]); unsigned const nbucket = get_te32(&hashtab[0]);
unsigned const *const buckets = &hashtab[2]; unsigned const *const buckets = &hashtab[2];
unsigned const *const chains = &buckets[nbucket]; unsigned const *const chains = &buckets[nbucket];
if (!nbucket if ((unsigned)(file_size - ((char const *)buckets - (char const *)(void const *)file_image))
|| (unsigned)(file_size - ((char const *)buckets - (char const *)(void const *)file_image))
<= sizeof(unsigned)*nbucket ) { <= sizeof(unsigned)*nbucket ) {
char msg[80]; snprintf(msg, sizeof(msg), char msg[80]; snprintf(msg, sizeof(msg),
"bad nbucket %#x\n", nbucket); "bad nbucket %#x\n", nbucket);
throwCantPack(msg); throwCantPack(msg);
} }
if (nbucket) {
unsigned const m = elf_hash(name) % nbucket; unsigned const m = elf_hash(name) % nbucket;
unsigned si; unsigned si;
for (si= get_te32(&buckets[m]); 0!=si; si= get_te32(&chains[si])) { for (si= get_te32(&buckets[m]); 0!=si; si= get_te32(&chains[si])) {
@@ -5748,6 +5748,7 @@ Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const
} }
} }
} }
}
if (gashtab && dynsym && dynstr) { if (gashtab && dynsym && dynstr) {
unsigned const n_bucket = get_te32(&gashtab[0]); unsigned const n_bucket = get_te32(&gashtab[0]);
unsigned const symbias = get_te32(&gashtab[1]); unsigned const symbias = get_te32(&gashtab[1]);
@@ -5756,8 +5757,7 @@ Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const
unsigned const *const bitmask = &gashtab[4]; unsigned const *const bitmask = &gashtab[4];
unsigned const *const buckets = &bitmask[n_bitmask]; unsigned const *const buckets = &bitmask[n_bitmask];
unsigned const *const hasharr = &buckets[n_bucket]; unsigned const *const hasharr = &buckets[n_bucket];
if (!n_bucket if ((void const *)&file_image[file_size] <= (void const *)hasharr) {
|| (void const *)&file_image[file_size] <= (void const *)hasharr) {
char msg[80]; snprintf(msg, sizeof(msg), char msg[80]; snprintf(msg, sizeof(msg),
"bad n_bucket %#x\n", n_bucket); "bad n_bucket %#x\n", n_bucket);
throwCantPack(msg); throwCantPack(msg);
@@ -5769,7 +5769,7 @@ Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const
"bad n_bitmask %#x\n", n_bitmask); "bad n_bitmask %#x\n", n_bitmask);
throwCantPack(msg); throwCantPack(msg);
} }
if (n_bucket) {
unsigned const h = gnu_hash(name); unsigned const h = gnu_hash(name);
unsigned const hbit1 = 037& h; unsigned const hbit1 = 037& h;
unsigned const hbit2 = 037& (h>>gnu_shift); unsigned const hbit2 = 037& (h>>gnu_shift);
@@ -5786,7 +5786,6 @@ Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const
if (0!=bucket) { if (0!=bucket) {
Elf32_Sym const *dsp = &dynsym[bucket]; Elf32_Sym const *dsp = &dynsym[bucket];
unsigned const *hp = &hasharr[bucket - symbias]; unsigned const *hp = &hasharr[bucket - symbias];
do if (0==((h ^ get_te32(hp))>>1)) { do if (0==((h ^ get_te32(hp))>>1)) {
unsigned st_name = get_te32(&dsp->st_name); unsigned st_name = get_te32(&dsp->st_name);
char const *const p = get_str_name(st_name, (unsigned)-1); char const *const p = get_str_name(st_name, (unsigned)-1);
@@ -5799,10 +5798,12 @@ Elf32_Sym const *PackLinuxElf32::elf_lookup(char const *name) const
} }
} }
} }
}
// 2021-12-25 FIXME: Some Rust programs use // 2021-12-25 FIXME: Some Rust programs use
// (1==n_bucket && 0==buckets[0] && 1==n_bitmask && 0==bitmask[0]) // (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. // to minimize space in DT_GNU_HASH. This causes the fancy lookup to fail.
// Is a fallback to linear seach assumed? // Is a fallback to linear seach assumed?
// 2022-03-12 Some Rust programs have 0==n_bucket.
return nullptr; return nullptr;
} }
@@ -5813,13 +5814,13 @@ Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const
unsigned const nbucket = get_te32(&hashtab[0]); unsigned const nbucket = get_te32(&hashtab[0]);
unsigned const *const buckets = &hashtab[2]; unsigned const *const buckets = &hashtab[2];
unsigned const *const chains = &buckets[nbucket]; unsigned const *const chains = &buckets[nbucket];
if (!nbucket if ((unsigned)(file_size - ((char const *)buckets - (char const *)(void const *)file_image))
|| (unsigned)(file_size - ((char const *)buckets - (char const *)(void const *)file_image))
<= sizeof(unsigned)*nbucket ) { <= sizeof(unsigned)*nbucket ) {
char msg[80]; snprintf(msg, sizeof(msg), char msg[80]; snprintf(msg, sizeof(msg),
"bad nbucket %#x\n", nbucket); "bad nbucket %#x\n", nbucket);
throwCantPack(msg); throwCantPack(msg);
} }
if (nbucket) { // -rust-musl can have "empty" hashtab
unsigned const m = elf_hash(name) % nbucket; unsigned const m = elf_hash(name) % nbucket;
unsigned si; unsigned si;
for (si= get_te32(&buckets[m]); 0!=si; si= get_te32(&chains[si])) { for (si= get_te32(&buckets[m]); 0!=si; si= get_te32(&chains[si])) {
@@ -5829,6 +5830,7 @@ Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const
} }
} }
} }
}
if (gashtab && dynsym && dynstr) { if (gashtab && dynsym && dynstr) {
unsigned const n_bucket = get_te32(&gashtab[0]); unsigned const n_bucket = get_te32(&gashtab[0]);
unsigned const symbias = get_te32(&gashtab[1]); unsigned const symbias = get_te32(&gashtab[1]);
@@ -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]; 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 buckets = (unsigned const *)&bitmask[n_bitmask];
unsigned const *const hasharr = &buckets[n_bucket]; 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), char msg[80]; snprintf(msg, sizeof(msg),
"bad n_bucket %#x\n", n_bucket); "bad n_bucket %#x\n", n_bucket);
throwCantPack(msg); throwCantPack(msg);
@@ -5850,12 +5852,11 @@ Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const
"bad n_bitmask %#x\n", n_bitmask); "bad n_bitmask %#x\n", n_bitmask);
throwCantPack(msg); throwCantPack(msg);
} }
if (n_bucket) { // -rust-musl can have "empty" gashtab
unsigned const h = gnu_hash(name); unsigned const h = gnu_hash(name);
unsigned const hbit1 = 077& h; unsigned const hbit1 = 077& h;
unsigned const hbit2 = 077& (h>>gnu_shift); unsigned const hbit2 = 077& (h>>gnu_shift);
upx_uint64_t const w = get_te64(&bitmask[(n_bitmask -1) & (h>>6)]); upx_uint64_t const w = get_te64(&bitmask[(n_bitmask -1) & (h>>6)]);
if (1& (w>>hbit1) & (w>>hbit2)) { if (1& (w>>hbit1) & (w>>hbit2)) {
unsigned bucket = get_te32(&buckets[h % n_bucket]); unsigned bucket = get_te32(&buckets[h % n_bucket]);
if (n_bucket <= bucket) { if (n_bucket <= bucket) {
@@ -5867,7 +5868,6 @@ Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const
if (0!=bucket) { if (0!=bucket) {
Elf64_Sym const *dsp = &dynsym[bucket]; Elf64_Sym const *dsp = &dynsym[bucket];
unsigned const *hp = &hasharr[bucket - symbias]; unsigned const *hp = &hasharr[bucket - symbias];
do if (0==((h ^ get_te32(hp))>>1)) { do if (0==((h ^ get_te32(hp))>>1)) {
unsigned st_name = get_te32(&dsp->st_name); unsigned st_name = get_te32(&dsp->st_name);
char const *const p = get_str_name(st_name, (unsigned)-1); char const *const p = get_str_name(st_name, (unsigned)-1);
@@ -5880,10 +5880,12 @@ Elf64_Sym const *PackLinuxElf64::elf_lookup(char const *name) const
} }
} }
} }
}
// 2021-12-25 FIXME: Some Rust programs use // 2021-12-25 FIXME: Some Rust programs use
// (1==n_bucket && 0==buckets[0] && 1==n_bitmask && 0==bitmask[0]) // (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. // to minimize space in DT_GNU_HASH. This causes the fancy lookup to fail.
// Is a fallback to linear seach assumed? // Is a fallback to linear seach assumed?
// 2022-03-12 Some Rust programs have 0==n_bucket.
return nullptr; return nullptr;
} }