mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-22 01:51:51 +00:00
vdso: Fixes in DT_GNU_HASH handling
* Hash buckets is an array of 32-bit words. While DT_HASH is 32-bit on most platforms except s390 (where it's 64-bit). * The bloom filter word size differs between 32-bit and 64-bit ELF files. This commit adjusts the code to handle both cases. Signed-off-by: Andrei Vagin <avagin@google.com>
This commit is contained in:
parent
4b099510b3
commit
e5fe6cc16d
@ -121,7 +121,8 @@ static int has_elf_identity(Ehdr_t *ehdr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int parse_elf_phdr(uintptr_t mem, size_t size, Phdr_t **dynamic, Phdr_t **load)
|
||||
static int parse_elf_phdr(uintptr_t mem, size_t size,
|
||||
Phdr_t **dynamic, Phdr_t **load, bool *is_32bit)
|
||||
{
|
||||
Ehdr_t *ehdr = (void *)mem;
|
||||
uintptr_t addr;
|
||||
@ -136,6 +137,8 @@ static int parse_elf_phdr(uintptr_t mem, size_t size, Phdr_t **dynamic, Phdr_t *
|
||||
if (!has_elf_identity(ehdr))
|
||||
return -EINVAL;
|
||||
|
||||
*is_32bit = ehdr->e_ident[EI_CLASS] != ELFCLASS64;
|
||||
|
||||
addr = mem + ehdr->e_phoff;
|
||||
if (__ptr_oob(addr, mem, size))
|
||||
goto err_oob;
|
||||
@ -272,6 +275,8 @@ typedef unsigned long Hash_t;
|
||||
typedef Word_t Hash_t;
|
||||
#endif
|
||||
|
||||
typedef uint32_t Hash32_t;
|
||||
|
||||
static bool elf_symbol_match(uintptr_t mem, size_t size,
|
||||
uintptr_t dynsymbol_names, Sym_t *sym,
|
||||
const char *symbol, const size_t vdso_symbol_length)
|
||||
@ -297,21 +302,22 @@ static bool elf_symbol_match(uintptr_t mem, size_t size,
|
||||
static unsigned long elf_symbol_lookup(uintptr_t mem, size_t size,
|
||||
const char *symbol, uint32_t symbol_hash, unsigned int sym_off,
|
||||
uintptr_t dynsymbol_names, Dyn_t *dyn_symtab, Phdr_t *load,
|
||||
Hash_t nbucket, Hash_t nchain, Hash_t *bucket, Hash_t *chain,
|
||||
uint64_t nbucket, uint64_t nchain, void *_bucket, Hash_t *chain,
|
||||
const size_t vdso_symbol_length, bool use_gnu_hash)
|
||||
{
|
||||
unsigned int j;
|
||||
uintptr_t addr;
|
||||
|
||||
j = bucket[symbol_hash % nbucket];
|
||||
if (j == STN_UNDEF)
|
||||
return 0;
|
||||
|
||||
addr = mem + dyn_symtab->d_un.d_ptr - load->p_vaddr;
|
||||
|
||||
if (use_gnu_hash) {
|
||||
uint32_t *h = bucket + nbucket + (j - sym_off);
|
||||
uint32_t hash_val;
|
||||
Hash32_t *h, hash_val, *bucket = _bucket;
|
||||
|
||||
j = bucket[symbol_hash % nbucket];
|
||||
if (j == STN_UNDEF)
|
||||
return 0;
|
||||
|
||||
h = bucket + nbucket + (j - sym_off);
|
||||
|
||||
symbol_hash |= 1;
|
||||
do {
|
||||
@ -325,6 +331,12 @@ static unsigned long elf_symbol_lookup(uintptr_t mem, size_t size,
|
||||
j++;
|
||||
} while (!(hash_val & 1));
|
||||
} else {
|
||||
Hash_t *bucket = _bucket;
|
||||
|
||||
j = bucket[symbol_hash % nbucket];
|
||||
if (j == STN_UNDEF)
|
||||
return 0;
|
||||
|
||||
for (; j < nchain && j != STN_UNDEF; j = chain[j]) {
|
||||
Sym_t *sym = (void *)addr + sizeof(Sym_t) * j;
|
||||
|
||||
@ -338,17 +350,17 @@ static unsigned long elf_symbol_lookup(uintptr_t mem, size_t size,
|
||||
|
||||
static int parse_elf_symbols(uintptr_t mem, size_t size, Phdr_t *load,
|
||||
struct vdso_symtable *t, uintptr_t dynsymbol_names,
|
||||
Hash_t *hash, Dyn_t *dyn_symtab, bool use_gnu_hash)
|
||||
Hash_t *hash, Dyn_t *dyn_symtab, bool use_gnu_hash,
|
||||
bool is_32bit)
|
||||
{
|
||||
ARCH_VDSO_SYMBOLS_LIST
|
||||
|
||||
const char *vdso_symbols[VDSO_SYMBOL_MAX] = { ARCH_VDSO_SYMBOLS };
|
||||
const size_t vdso_symbol_length = sizeof(t->symbols[0].name) - 1;
|
||||
|
||||
Hash_t *bucket = NULL;
|
||||
void *bucket = NULL;
|
||||
Hash_t *chain = NULL;
|
||||
Hash_t nbucket = 0;
|
||||
Hash_t nchain = 0;
|
||||
uint64_t nbucket, nchain = 0;
|
||||
|
||||
unsigned int sym_off = 0;
|
||||
unsigned int i = 0;
|
||||
@ -358,17 +370,23 @@ static int parse_elf_symbols(uintptr_t mem, size_t size, Phdr_t *load,
|
||||
if (use_gnu_hash) {
|
||||
uint32_t *gnu_hash = (uint32_t *)hash;
|
||||
uint32_t bloom_sz;
|
||||
size_t *bloom;
|
||||
|
||||
nbucket = gnu_hash[0];
|
||||
sym_off = gnu_hash[1];
|
||||
bloom_sz = gnu_hash[2];
|
||||
bloom = (size_t *)&gnu_hash[4];
|
||||
bucket = (Hash_t *)(&bloom[bloom_sz]);
|
||||
if (is_32bit) {
|
||||
uint32_t *bloom;
|
||||
bloom = (uint32_t *)&gnu_hash[4];
|
||||
bucket = (Hash_t *)(&bloom[bloom_sz]);
|
||||
} else {
|
||||
uint64_t *bloom;
|
||||
bloom = (uint64_t *)&gnu_hash[4];
|
||||
bucket = (Hash_t *)(&bloom[bloom_sz]);
|
||||
}
|
||||
elf_hash = &elf_gnu_hash;
|
||||
pr_debug("nbucket %lx sym_off %lx bloom_sz %lx bloom %lx bucket %lx\n",
|
||||
pr_debug("nbucket %lx sym_off %lx bloom_sz %lx bucket %lx\n",
|
||||
(unsigned long)nbucket, (unsigned long)sym_off,
|
||||
(unsigned long)bloom_sz, (unsigned long)bloom,
|
||||
(unsigned long)bloom_sz,
|
||||
(unsigned long)bucket);
|
||||
} else {
|
||||
nbucket = hash[0];
|
||||
@ -417,6 +435,7 @@ int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t)
|
||||
Dyn_t *dyn_hash = NULL;
|
||||
Hash_t *hash = NULL;
|
||||
bool use_gnu_hash;
|
||||
bool is_32bit;
|
||||
|
||||
uintptr_t dynsymbol_names;
|
||||
uintptr_t addr;
|
||||
@ -427,7 +446,7 @@ int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t)
|
||||
/*
|
||||
* We need PT_LOAD and PT_DYNAMIC here. Each once.
|
||||
*/
|
||||
ret = parse_elf_phdr(mem, size, &dynamic, &load);
|
||||
ret = parse_elf_phdr(mem, size, &dynamic, &load, &is_32bit);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (!load || !dynamic) {
|
||||
@ -458,7 +477,7 @@ int vdso_fill_symtable(uintptr_t mem, size_t size, struct vdso_symtable *t)
|
||||
hash = (void *)addr;
|
||||
|
||||
ret = parse_elf_symbols(mem, size, load, t, dynsymbol_names, hash, dyn_symtab,
|
||||
use_gnu_hash);
|
||||
use_gnu_hash, is_32bit);
|
||||
|
||||
if (ret <0)
|
||||
return ret;
|
||||
|
Loading…
x
Reference in New Issue
Block a user