Module Name: src Committed By: martin Date: Tue Aug 1 17:03:54 UTC 2023
Modified Files: src/distrib/sets/lists/debug [netbsd-10]: mi src/distrib/sets/lists/tests [netbsd-10]: mi src/libexec/ld.elf_so [netbsd-10]: Makefile reloc.c rtld.c rtld.h symbol.c src/tests/libexec/ld.elf_so [netbsd-10]: Makefile Added Files: src/libexec/ld.elf_so [netbsd-10]: hash.c hash.h src/tests/libexec/ld.elf_so [netbsd-10]: t_hash.c Log Message: Pull up following revision(s) (requested by riastradh in ticket #300): libexec/ld.elf_so/rtld.h: revision 1.145 libexec/ld.elf_so/symbol.c: revision 1.74 libexec/ld.elf_so/rtld.h: revision 1.147 libexec/ld.elf_so/symbol.c: revision 1.75 libexec/ld.elf_so/symbol.c: revision 1.76 tests/libexec/ld.elf_so/t_hash.c: revision 1.1 libexec/ld.elf_so/Makefile: revision 1.145 libexec/ld.elf_so/Makefile: revision 1.146 libexec/ld.elf_so/Makefile: revision 1.147 libexec/ld.elf_so/reloc.c: revision 1.118 distrib/sets/lists/tests/mi: revision 1.1280 libexec/ld.elf_so/rtld.c: revision 1.215 tests/libexec/ld.elf_so/Makefile: revision 1.21 libexec/ld.elf_so/hash.c: revision 1.1 libexec/ld.elf_so/hash.h: revision 1.1 distrib/sets/lists/debug/mi: revision 1.409 The SysV ABI specifies that the symbol hash function should return only 32 bits of hash. Unfortunately due to an implementation bug and the fact that the return type is unsigned long which is 64 bits in LP64, this can fail in some cases: "\xff\x0f\x0f\x0f\x0f\x0f\x12". See: "https://maskray.me/blog/2023-04-12-elf-hash-function >From Ed Maste @ FreeBSD: https://cgit.freebsd.org/src/commit/?id=29e3a06510823edbb91667d21f530d3ec778116d Need to write Unit Tests for this. Oops wrong mask. ld.elf_so: Split SRCS onto multiple lines. Makes updates easier. No functional change intended. ld.elf_so: Sort SRCS. No functional change intended. ld.elf_so: Split hash functions into a separate file. This way we can test them in isolation. No functional change intended. ld.elf_so: Add some known-answer tests for hash functions. Make sure the testing mechanism detects the traditional overflow bug. To generate a diff of this commit: cvs rdiff -u -r1.394.2.1 -r1.394.2.2 src/distrib/sets/lists/debug/mi cvs rdiff -u -r1.1238.2.1 -r1.1238.2.2 src/distrib/sets/lists/tests/mi cvs rdiff -u -r1.144 -r1.144.2.1 src/libexec/ld.elf_so/Makefile cvs rdiff -u -r0 -r1.1.2.2 src/libexec/ld.elf_so/hash.c \ src/libexec/ld.elf_so/hash.h cvs rdiff -u -r1.117 -r1.117.2.1 src/libexec/ld.elf_so/reloc.c cvs rdiff -u -r1.212.2.2 -r1.212.2.3 src/libexec/ld.elf_so/rtld.c cvs rdiff -u -r1.144.2.1 -r1.144.2.2 src/libexec/ld.elf_so/rtld.h cvs rdiff -u -r1.73 -r1.73.8.1 src/libexec/ld.elf_so/symbol.c cvs rdiff -u -r1.12.4.1 -r1.12.4.2 src/tests/libexec/ld.elf_so/Makefile cvs rdiff -u -r0 -r1.1.2.2 src/tests/libexec/ld.elf_so/t_hash.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/debug/mi diff -u src/distrib/sets/lists/debug/mi:1.394.2.1 src/distrib/sets/lists/debug/mi:1.394.2.2 --- src/distrib/sets/lists/debug/mi:1.394.2.1 Tue Aug 1 16:34:57 2023 +++ src/distrib/sets/lists/debug/mi Tue Aug 1 17:03:54 2023 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.394.2.1 2023/08/01 16:34:57 martin Exp $ +# $NetBSD: mi,v 1.394.2.2 2023/08/01 17:03:54 martin Exp $ ./etc/mtree/set.debug comp-sys-root ./usr/lib comp-sys-usr compatdir ./usr/lib/i18n/libBIG5_g.a comp-c-debuglib debuglib,compatfile @@ -2401,8 +2401,9 @@ ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlerror-false.debug tests-libexec-debug debug,atf,pic,compattestfile ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlinfo.debug tests-libexec-debug debug,atf,pic,compattestfile ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_dlvsym.debug tests-libexec-debug debug,atf,pic,compattestfile -./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_rtld_r_debug.debug tests-libexec-debug debug,atf,pic,compattestfile +./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_hash.debug tests-libexec-debug debug,atf,pic,compattestfile ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_ifunc.debug tests-libexec-debug debug,atf,pic,compattestfile +./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_rtld_r_debug.debug tests-libexec-debug debug,atf,pic,compattestfile ./usr/libdata/debug/usr/tests/libexec/ld.elf_so/t_tls_extern.debug tests-libexec-debug debug,atf,pic,compattestfile ./usr/libdata/debug/usr/tests/net/bpf/t_bpf.debug tests-net-debug debug,atf,rump ./usr/libdata/debug/usr/tests/net/bpf/t_div-by-zero.debug tests-net-debug debug,atf,rump Index: src/distrib/sets/lists/tests/mi diff -u src/distrib/sets/lists/tests/mi:1.1238.2.1 src/distrib/sets/lists/tests/mi:1.1238.2.2 --- src/distrib/sets/lists/tests/mi:1.1238.2.1 Tue Aug 1 16:34:56 2023 +++ src/distrib/sets/lists/tests/mi Tue Aug 1 17:03:53 2023 @@ -1,4 +1,4 @@ -# $NetBSD: mi,v 1.1238.2.1 2023/08/01 16:34:56 martin Exp $ +# $NetBSD: mi,v 1.1238.2.2 2023/08/01 17:03:53 martin Exp $ # # Note: don't delete entries from here - mark them as "obsolete" instead. # @@ -4093,6 +4093,7 @@ ./usr/tests/libexec/ld.elf_so/t_dlerror-false tests-libexec-tests compattestfile,atf,pic ./usr/tests/libexec/ld.elf_so/t_dlinfo tests-libexec-tests compattestfile,atf,pic ./usr/tests/libexec/ld.elf_so/t_dlvsym tests-libexec-tests compattestfile,atf,pic +./usr/tests/libexec/ld.elf_so/t_hash tests-libexec-tests compattestfile,atf,pic ./usr/tests/libexec/ld.elf_so/t_ifunc tests-libexec-tests compattestfile,atf,pic ./usr/tests/libexec/ld.elf_so/t_rtld_r_debug tests-libexec-tests compattestfile,atf,pic ./usr/tests/libexec/ld.elf_so/t_thread_local_dtor tests-libexec-tests compattestfile,atf,pic Index: src/libexec/ld.elf_so/Makefile diff -u src/libexec/ld.elf_so/Makefile:1.144 src/libexec/ld.elf_so/Makefile:1.144.2.1 --- src/libexec/ld.elf_so/Makefile:1.144 Sat Dec 4 08:45:56 2021 +++ src/libexec/ld.elf_so/Makefile Tue Aug 1 17:03:53 2023 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.144 2021/12/04 08:45:56 skrll Exp $ +# $NetBSD: Makefile,v 1.144.2.1 2023/08/01 17:03:53 martin Exp $ # # NOTE: when changing ld.so, ensure that ldd still compiles. # @@ -72,9 +72,23 @@ PROG= ld.elf_so CLIBOBJ!= cd ${NETBSDSRCDIR}/lib/libc && ${PRINTOBJDIR} -SRCS+= rtld.c reloc.c symbol.c xmalloc.c xprintf.c debug.c \ - map_object.c load.c search.c headers.c paths.c expand.c \ - tls.c symver.c diagassert.c compat.c +SRCS+= compat.c +SRCS+= debug.c +SRCS+= diagassert.c +SRCS+= expand.c +SRCS+= hash.c +SRCS+= headers.c +SRCS+= load.c +SRCS+= map_object.c +SRCS+= paths.c +SRCS+= reloc.c +SRCS+= rtld.c +SRCS+= search.c +SRCS+= symbol.c +SRCS+= symver.c +SRCS+= tls.c +SRCS+= xmalloc.c +SRCS+= xprintf.c .if ${USE_FORT} == "yes" .PATH.c: ${NETBSDSRCDIR}/lib/libc/misc Index: src/libexec/ld.elf_so/reloc.c diff -u src/libexec/ld.elf_so/reloc.c:1.117 src/libexec/ld.elf_so/reloc.c:1.117.2.1 --- src/libexec/ld.elf_so/reloc.c:1.117 Sat Dec 4 08:53:34 2021 +++ src/libexec/ld.elf_so/reloc.c Tue Aug 1 17:03:53 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: reloc.c,v 1.117 2021/12/04 08:53:34 skrll Exp $ */ +/* $NetBSD: reloc.c,v 1.117.2.1 2023/08/01 17:03:53 martin Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -39,7 +39,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: reloc.c,v 1.117 2021/12/04 08:53:34 skrll Exp $"); +__RCSID("$NetBSD: reloc.c,v 1.117.2.1 2023/08/01 17:03:53 martin Exp $"); #endif /* not lint */ #include <err.h> @@ -56,6 +56,7 @@ __RCSID("$NetBSD: reloc.c,v 1.117 2021/1 #include <dirent.h> #include "debug.h" +#include "hash.h" #include "rtld.h" #ifndef RTLD_INHIBIT_COPY_RELOCS Index: src/libexec/ld.elf_so/rtld.c diff -u src/libexec/ld.elf_so/rtld.c:1.212.2.2 src/libexec/ld.elf_so/rtld.c:1.212.2.3 --- src/libexec/ld.elf_so/rtld.c:1.212.2.2 Tue Aug 1 16:34:56 2023 +++ src/libexec/ld.elf_so/rtld.c Tue Aug 1 17:03:53 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: rtld.c,v 1.212.2.2 2023/08/01 16:34:56 martin Exp $ */ +/* $NetBSD: rtld.c,v 1.212.2.3 2023/08/01 17:03:53 martin Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -40,7 +40,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: rtld.c,v 1.212.2.2 2023/08/01 16:34:56 martin Exp $"); +__RCSID("$NetBSD: rtld.c,v 1.212.2.3 2023/08/01 17:03:53 martin Exp $"); #endif /* not lint */ #include <sys/param.h> @@ -60,7 +60,9 @@ __RCSID("$NetBSD: rtld.c,v 1.212.2.2 202 #include <ctype.h> #include <dlfcn.h> + #include "debug.h" +#include "hash.h" #include "rtld.h" #if !defined(lint) Index: src/libexec/ld.elf_so/rtld.h diff -u src/libexec/ld.elf_so/rtld.h:1.144.2.1 src/libexec/ld.elf_so/rtld.h:1.144.2.2 --- src/libexec/ld.elf_so/rtld.h:1.144.2.1 Tue Aug 1 16:34:56 2023 +++ src/libexec/ld.elf_so/rtld.h Tue Aug 1 17:03:53 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: rtld.h,v 1.144.2.1 2023/08/01 16:34:56 martin Exp $ */ +/* $NetBSD: rtld.h,v 1.144.2.2 2023/08/01 17:03:53 martin Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -442,8 +442,6 @@ void _rtld_call_ifunc(Obj_Entry *, sigse Obj_Entry *_rtld_load_library(const char *, const Obj_Entry *, int); /* symbol.c */ -unsigned long _rtld_sysv_hash(const char *); -unsigned long _rtld_gnu_hash(const char *); const Elf_Sym *_rtld_symlook_obj(const char *, Elf_Hash *, const Obj_Entry *, u_int, const Ver_Entry *); const Elf_Sym *_rtld_find_symdef(unsigned long, const Obj_Entry *, Index: src/libexec/ld.elf_so/symbol.c diff -u src/libexec/ld.elf_so/symbol.c:1.73 src/libexec/ld.elf_so/symbol.c:1.73.8.1 --- src/libexec/ld.elf_so/symbol.c:1.73 Sat Feb 29 18:45:20 2020 +++ src/libexec/ld.elf_so/symbol.c Tue Aug 1 17:03:53 2023 @@ -1,4 +1,4 @@ -/* $NetBSD: symbol.c,v 1.73 2020/02/29 18:45:20 kamil Exp $ */ +/* $NetBSD: symbol.c,v 1.73.8.1 2023/08/01 17:03:53 martin Exp $ */ /* * Copyright 1996 John D. Polstra. @@ -40,7 +40,7 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: symbol.c,v 1.73 2020/02/29 18:45:20 kamil Exp $"); +__RCSID("$NetBSD: symbol.c,v 1.73.8.1 2023/08/01 17:03:53 martin Exp $"); #endif /* not lint */ #include <err.h> @@ -57,6 +57,7 @@ __RCSID("$NetBSD: symbol.c,v 1.73 2020/0 #include <dirent.h> #include "debug.h" +#include "hash.h" #include "rtld.h" /* @@ -80,45 +81,6 @@ _rtld_donelist_check(DoneList *dlp, cons return false; } -/* - * Hash function for symbol table lookup. Don't even think about changing - * this. It is specified by the System V ABI. - */ -unsigned long -_rtld_sysv_hash(const char *name) -{ - const unsigned char *p = (const unsigned char *) name; - unsigned long h = 0; - unsigned long g; - unsigned long c; - - for (; __predict_true((c = *p) != '\0'); p++) { - h <<= 4; - h += c; - if ((g = h & 0xf0000000) != 0) { - h ^= g; - h ^= g >> 24; - } - } - return (h); -} - -/* - * Hash function for symbol table lookup. Don't even think about changing - * this. It is specified by the GNU toolchain ABI. - */ -unsigned long -_rtld_gnu_hash(const char *name) -{ - const unsigned char *p = (const unsigned char *) name; - uint_fast32_t h = 5381; - unsigned char c; - - for (c = *p; c != '\0'; c = *++p) - h = h * 33 + c; - return (unsigned long)h; -} - const Elf_Sym * _rtld_symlook_list(const char *name, Elf_Hash *hash, const Objlist *objlist, const Obj_Entry **defobj_out, u_int flags, const Ver_Entry *ventry, Index: src/tests/libexec/ld.elf_so/Makefile diff -u src/tests/libexec/ld.elf_so/Makefile:1.12.4.1 src/tests/libexec/ld.elf_so/Makefile:1.12.4.2 --- src/tests/libexec/ld.elf_so/Makefile:1.12.4.1 Tue Aug 1 16:34:58 2023 +++ src/tests/libexec/ld.elf_so/Makefile Tue Aug 1 17:03:53 2023 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.12.4.1 2023/08/01 16:34:58 martin Exp $ +# $NetBSD: Makefile,v 1.12.4.2 2023/08/01 17:03:53 martin Exp $ # NOMAN= # defined @@ -30,6 +30,12 @@ TESTSDIR= ${TESTSBASE}/libexec/ld.elf_so TESTS_C+= t_dlerror-cleared t_dlerror-false t_dlinfo t_dlvsym t_ifunc TESTS_C+= t_rtld_r_debug TESTS_C+= t_tls_extern +TESTS_C+= t_hash + +.PATH: ${NETBSDSRCDIR}/libexec/ld.elf_so +SRCS.t_hash+= t_hash.c +SRCS.t_hash+= hash.c +CPPFLAGS.t_hash.c+= -I${NETBSDSRCDIR}/libexec/ld.elf_so COPTS.t_rtld_r_debug.c += ${${ACTIVE_CC} == "gcc" :? -Wno-maybe-uninitialized :} Added files: Index: src/libexec/ld.elf_so/hash.c diff -u /dev/null src/libexec/ld.elf_so/hash.c:1.1.2.2 --- /dev/null Tue Aug 1 17:03:54 2023 +++ src/libexec/ld.elf_so/hash.c Tue Aug 1 17:03:53 2023 @@ -0,0 +1,81 @@ +/* $NetBSD: hash.c,v 1.1.2.2 2023/08/01 17:03:53 martin Exp $ */ + +/* + * Copyright 1996 John D. Polstra. + * Copyright 1996 Matt Thomas <m...@3am-software.com> + * Copyright 2002 Charles M. Hannum <r...@ihack.net> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Polstra. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Dynamic linker for ELF. + * + * John Polstra <j...@polstra.com>. + */ + +#include <sys/cdefs.h> +#ifndef lint +__RCSID("$NetBSD: hash.c,v 1.1.2.2 2023/08/01 17:03:53 martin Exp $"); +#endif /* not lint */ + +#include <stdint.h> + +#include "hash.h" + +/* + * SysV hash function for symbol table lookup. It is a slightly optimized + * version of the hash specified by the System V ABI. + */ +Elf32_Word +_rtld_sysv_hash(const char *name) +{ + const unsigned char *p = (const unsigned char *) name; + Elf32_Word h = 0; + + while (__predict_true(*p != '\0')) { + h = (h << 4) + *p++; + h ^= (h >> 24) & 0xf0; + } + return (h & 0x0fffffff); +} + +/* + * Hash function for symbol table lookup. Don't even think about changing + * this. It is specified by the GNU toolchain ABI. + */ +Elf32_Word +_rtld_gnu_hash(const char *name) +{ + const unsigned char *p = (const unsigned char *) name; + uint_fast32_t h = 5381; + unsigned char c; + + for (c = *p; c != '\0'; c = *++p) + h = h * 33 + c; + return (h & 0xffffffff); +} Index: src/libexec/ld.elf_so/hash.h diff -u /dev/null src/libexec/ld.elf_so/hash.h:1.1.2.2 --- /dev/null Tue Aug 1 17:03:54 2023 +++ src/libexec/ld.elf_so/hash.h Tue Aug 1 17:03:53 2023 @@ -0,0 +1,42 @@ +/* $NetBSD: hash.h,v 1.1.2.2 2023/08/01 17:03:53 martin Exp $ */ + +/* + * Copyright 1996 John D. Polstra. + * Copyright 1996 Matt Thomas <m...@3am-software.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Polstra. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RTLD_HASH_H +#define RTLD_HASH_H + +#include <sys/exec_elf.h> + +Elf32_Word _rtld_sysv_hash(const char *); +Elf32_Word _rtld_gnu_hash(const char *); + +#endif /* RTLD_HASH_H */ Index: src/tests/libexec/ld.elf_so/t_hash.c diff -u /dev/null src/tests/libexec/ld.elf_so/t_hash.c:1.1.2.2 --- /dev/null Tue Aug 1 17:03:54 2023 +++ src/tests/libexec/ld.elf_so/t_hash.c Tue Aug 1 17:03:53 2023 @@ -0,0 +1,218 @@ +/* $NetBSD: t_hash.c,v 1.1.2.2 2023/08/01 17:03:53 martin Exp $ */ + +/*- + * Copyright (c) 2023 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <atf-c.h> +#include <stdint.h> + +#include "hash.h" + +/* known-answer tests */ +struct kat { + const char *in; + unsigned long long out; +}; + +/* + * From the SysV spec, with uint64_t instead of unsigned long to + * illustrate the problem on all systems, not just LP64 ones. + * + * https://www.sco.com/developers/devspecs/gabi41.pdf#page=95 + */ +static uint64_t +sysv_broken_hash(const char *name) +{ + uint64_t h = 0, g; + + while (*name) { + h = (h << 4) + *name++; + if ((g = h & 0xf0000000) != 0) + h ^= g >> 24; + h &= ~g; + } + + return h; +} + +ATF_TC(sysv); +ATF_TC_HEAD(sysv, tc) +{ + atf_tc_set_md_var(tc, "descr", "SysV hash (32-bit)"); +} +ATF_TC_BODY(sysv, tc) +{ + static const struct kat kat[] = { + { "", 0x00000000 }, + { "a", 0x00000061 }, + { "aa", 0x00000671 }, + { "aaa", 0x00006771 }, + { "aaaa", 0x00067771 }, + { "aaaaa", 0x00677771 }, + { "aaaaaa", 0x06777771 }, + { "aaaaaaa", 0x07777711 }, + { "aaaaaaaa", 0x07777101 }, + { "aaaaaaaaa", 0x07771001 }, + { "ab", 0x00000672 }, + { "abc", 0x00006783 }, + { "abcd", 0x00067894 }, + { "abcde", 0x006789a5 }, + { "abcdef", 0x06789ab6 }, + { "abcdefg", 0x0789aba7 }, + { "abcdefgh", 0x089abaa8 }, + { "abcdefghi", 0x09abaa69 }, + /* https://maskray.me/blog/2023-04-12-elf-hash-function */ + { "Z", 0x0000005a }, + { "ZZ", 0x000005fa }, + { "ZZZ", 0x00005ffa }, + { "ZZZZ", 0x0005fffa }, + { "ZZZZZ", 0x005ffffa }, + { "ZZZZZW", 0x05fffff7 }, + { "ZZZZZW9", 0x0ffffff9 }, + { "ZZZZZW9p", 0x00000000 }, + { "pneumonoultramicroscopicsilicovolcanoconiosis", + 0x051706b3 }, + }; + unsigned i; + + for (i = 0; i < __arraycount(kat); i++) { + unsigned long long h = _rtld_sysv_hash(kat[i].in); + + ATF_CHECK_EQ_MSG(h, kat[i].out, + "[%u] _rtld_hash_sysv(\"%s\") = 0x%08llx != 0x%08llx", + i, kat[i].in, h, kat[i].out); + } +} + +ATF_TC(sysv_broken); +ATF_TC_HEAD(sysv_broken, tc) +{ + atf_tc_set_md_var(tc, "descr", + "SysV hash (broken with 64-bit unsigned long)"); +} +ATF_TC_BODY(sysv_broken, tc) +{ + static const struct kat kat[] = { + { "", 0x00000000 }, + { "a", 0x00000061 }, + { "aa", 0x00000671 }, + { "aaa", 0x00006771 }, + { "aaaa", 0x00067771 }, + { "aaaaa", 0x00677771 }, + { "aaaaaa", 0x06777771 }, + { "aaaaaaa", 0x07777711 }, + { "aaaaaaaa", 0x07777101 }, + { "aaaaaaaaa", 0x07771001 }, + { "ab", 0x00000672 }, + { "abc", 0x00006783 }, + { "abcd", 0x00067894 }, + { "abcde", 0x006789a5 }, + { "abcdef", 0x06789ab6 }, + { "abcdefg", 0x0789aba7 }, + { "abcdefgh", 0x089abaa8 }, + { "abcdefghi", 0x09abaa69 }, + /* https://maskray.me/blog/2023-04-12-elf-hash-function */ + { "Z", 0x0000005a }, + { "ZZ", 0x000005fa }, + { "ZZZ", 0x00005ffa }, + { "ZZZZ", 0x0005fffa }, + { "ZZZZZ", 0x005ffffa }, + { "ZZZZZW", 0x05fffff7 }, + { "ZZZZZW9", 0x0ffffff9 }, + { "ZZZZZW9p", 0x100000000 }, + { "pneumonoultramicroscopicsilicovolcanoconiosis", + 0x051706b3 }, + }; + unsigned i; + + for (i = 0; i < __arraycount(kat); i++) { + unsigned long long h = sysv_broken_hash(kat[i].in); + + ATF_CHECK_EQ_MSG(h, kat[i].out, + "[%u] sysv_broken_hash(\"%s\") = 0x%08llx != 0x%08llx", + i, kat[i].in, h, kat[i].out); + } +} + +ATF_TC(gnu); +ATF_TC_HEAD(gnu, tc) +{ + atf_tc_set_md_var(tc, "descr", "GNU hash (djb2)"); +} +ATF_TC_BODY(gnu, tc) +{ + static const struct kat kat[] = { + { """", 0x00001505 }, + { "a", 0x0002b606 }, + { "aa", 0x00597727 }, + { "aaa", 0x0b885c68 }, + { "aaaa", 0x7c93e9c9 }, + { "aaaaa", 0x0f11234a }, + { "aaaaaa", 0xf1358ceb }, + { "aaaaaaa", 0x17e72aac }, + { "aaaaaaaa", 0x14cc808d }, + { "aaaaaaaaa", 0xae5c928e }, + { "ab", 0x00597728 }, + { "abc", 0x0b885c8b }, + { "abcd", 0x7c93ee4f }, + { "abcde", 0x0f11b894 }, + { "abcdef", 0xf148cb7a }, + { "abcdefg", 0x1a623b21 }, + { "abcdefgh", 0x66a99fa9 }, + { "abcdefghi", 0x3bdd9532 }, + { "Z", 0x0002b5ff }, + { "ZZ", 0x00597639 }, + { "ZZZ", 0x0b883db3 }, + { "ZZZZ", 0x7c8ff46d }, + { "ZZZZZ", 0x0e8e8267 }, + { "ZZZZZW", 0xe05ecf9e }, + { "ZZZZZW9", 0xec38c397 }, + { "ZZZZZW9p", 0x735136e7 }, + { "pneumonoultramicroscopicsilicovolcanoconiosis", + 0xee6245b5 }, + }; + unsigned i; + + for (i = 0; i < __arraycount(kat); i++) { + unsigned long long h = _rtld_gnu_hash(kat[i].in); + + ATF_CHECK_EQ_MSG(h, kat[i].out, + "[%u] _rtld_gnu_hash(\"%s\") = 0x%08llx != 0x%08llx", + i, kat[i].in, h, kat[i].out); + } +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, gnu); + ATF_TP_ADD_TC(tp, sysv); + ATF_TP_ADD_TC(tp, sysv_broken); + + return atf_no_error(); +}