rtld: fix SysV hash function overflow
Quoting from https://maskray.me/blog/2023-04-12-elf-hash-function: The System V Application Binary Interface (generic ABI) specifies the ELF object file format. When producing an output executable or shared object needing a dynamic symbol table (.dynsym), a linker generates a .hash section with type SHT_HASH to hold a symbol hash table. A DT_HASH tag is produced to hold the address of .hash. The function is supposed to return a value no larger than 0x0fffffff. Unfortunately, there is a bug. When unsigned long consists of more than 32 bits, the return value may be larger than UINT32_MAX. For instance, elf_hash((const unsigned char *)"\xff\x0f\x0f\x0f\x0f\x0f\x12") returns 0x100000002, which is clearly unintended, as the function should behave the same way regardless of whether long represents a 32-bit integer or a 64-bit integer. Reviewed by: kib, Fangrui Song Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D39517
This commit is contained in:
@@ -1796,23 +1796,20 @@ donelist_check(DoneList *dlp, const Obj_Entry *obj)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hash function for symbol table lookup. Don't even think about changing
|
* SysV hash function for symbol table lookup. It is a slightly optimized
|
||||||
* this. It is specified by the System V ABI.
|
* version of the hash specified by the System V ABI.
|
||||||
*/
|
*/
|
||||||
unsigned long
|
Elf32_Word
|
||||||
elf_hash(const char *name)
|
elf_hash(const char *name)
|
||||||
{
|
{
|
||||||
const unsigned char *p = (const unsigned char *)name;
|
const unsigned char *p = (const unsigned char *)name;
|
||||||
unsigned long h = 0;
|
Elf32_Word h = 0;
|
||||||
unsigned long g;
|
|
||||||
|
|
||||||
while (*p != '\0') {
|
while (*p != '\0') {
|
||||||
h = (h << 4) + *p++;
|
h = (h << 4) + *p++;
|
||||||
if ((g = h & 0xf0000000) != 0)
|
h ^= (h >> 24) & 0xf0;
|
||||||
h ^= g >> 24;
|
|
||||||
h &= ~g;
|
|
||||||
}
|
}
|
||||||
return (h);
|
return (h & 0x0fffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ void dump_Elf_Rela(Obj_Entry *, const Elf_Rela *, u_long);
|
|||||||
*/
|
*/
|
||||||
uintptr_t rtld_round_page(uintptr_t);
|
uintptr_t rtld_round_page(uintptr_t);
|
||||||
uintptr_t rtld_trunc_page(uintptr_t);
|
uintptr_t rtld_trunc_page(uintptr_t);
|
||||||
unsigned long elf_hash(const char *);
|
Elf32_Word elf_hash(const char *);
|
||||||
const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *,
|
const Elf_Sym *find_symdef(unsigned long, const Obj_Entry *,
|
||||||
const Obj_Entry **, int, SymCache *, struct Struct_RtldLockState *);
|
const Obj_Entry **, int, SymCache *, struct Struct_RtldLockState *);
|
||||||
void lockdflt_init(void);
|
void lockdflt_init(void);
|
||||||
|
|||||||
Reference in New Issue
Block a user