The branch main has been updated by emaste:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=2ef2c26f3f132af33f6f12cd7b27d4dbbd7fa435

commit 2ef2c26f3f132af33f6f12cd7b27d4dbbd7fa435
Author:     Ed Maste <ema...@freebsd.org>
AuthorDate: 2023-04-12 14:04:27 +0000
Commit:     Ed Maste <ema...@freebsd.org>
CommitDate: 2023-04-12 19:33:55 +0000

    link_elf: 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
---
 sys/kern/link_elf.c | 19 ++++++++-----------
 1 file changed, 8 insertions(+), 11 deletions(-)

diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 5f0649d7540c..8e1495acee2b 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -1470,23 +1470,20 @@ relocate_file(elf_file_t ef)
 }
 
 /*
- * Hash function for symbol table lookup.  Don't even think about changing
- * this.  It is specified by the System V ABI.
+ * SysV hash function for symbol table lookup.  It is specified by the
+ * System V ABI.
  */
-static unsigned long
+static Elf32_Word
 elf_hash(const char *name)
 {
-       const unsigned char *p = (const unsigned char *) name;
-       unsigned long h = 0;
-       unsigned long g;
+       const unsigned char *p = (const unsigned char *)name;
+       Elf32_Word h = 0;
 
        while (*p != '\0') {
                h = (h << 4) + *p++;
-               if ((g = h & 0xf0000000) != 0)
-                       h ^= g >> 24;
-               h &= ~g;
+               h ^= (h >> 24) & 0xf0;
        }
-       return (h);
+       return (h & 0x0fffffff);
 }
 
 static int
@@ -1497,7 +1494,7 @@ link_elf_lookup_symbol1(linker_file_t lf, const char 
*name, c_linker_sym_t *sym,
        unsigned long symnum;
        const Elf_Sym* symp;
        const char *strp;
-       unsigned long hash;
+       Elf32_Word hash;
 
        /* If we don't have a hash, bail. */
        if (ef->buckets == NULL || ef->nbuckets == 0) {

Reply via email to