Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 3 Nov 2023 21:44:14 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 98fd69f0090d - main - rtld/arm: fix initial-exec (IE) thread-local storage relocation
Message-ID:  <202311032144.3A3LiEF3049266@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=98fd69f0090da73d9d0451bd769d7752468284c6

commit 98fd69f0090da73d9d0451bd769d7752468284c6
Author:     R. Christian McDonald <rcm@rcm.sh>
AuthorDate: 2023-11-03 12:56:58 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-11-03 21:43:40 +0000

    rtld/arm: fix initial-exec (IE) thread-local storage relocation
    
    net/frr[89] revealed an interesting edge-case on arm when dynamically
    linking a shared library that declares more than one static TLS variable
    with at least one  using the "initial-exec" TLS model. In the case
    of frr[89], this library was libfrr.so which essentially does the
    following:
    
            #include <stdio.h>
    
            #include "lib.h"
    
            static __thread int *a
                    __attribute__((tls_model("initial-exec")));
    
            void lib_test()
            {
                    static __thread int b = -1;
    
                    printf("&a = %p\n", &a);
                    printf(" a = %p\n", a);
    
                    printf("\n");
    
                    printf("&b = %p\n", &b);
                    printf(" b = %d\n", b);
            }
    
    Allocates a file scoped `static __thread` pointer with
    tls_model("initial-exec") and later a block scoped TLS int. Notice in
    the above minimal reproducer, `b == -1`. The relocation process does
    the wrong thing and ends up pointing both `a` and `b` at the same place
    in memory.
    
    The output of the above in the broken state is:
    
            &a = 0x4009c018
             a = 0xffffffff
    
            &b = 0x4009c018
             b = -1
    
    With the patch applied, the output becomes:
    
            &a = 0x4009c01c
             a = 0x0
    
            &b = 0x4009c018
             b = -1
    
    Reviewed by:    kib
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D42415/
---
 libexec/rtld-elf/arm/reloc.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/libexec/rtld-elf/arm/reloc.c b/libexec/rtld-elf/arm/reloc.c
index c3e95940be74..6efc9f499761 100644
--- a/libexec/rtld-elf/arm/reloc.c
+++ b/libexec/rtld-elf/arm/reloc.c
@@ -280,10 +280,13 @@ reloc_nonplt_object(Obj_Entry *obj, const Elf_Rel *rel, SymCache *cache,
 				return -1;
 
 			tmp = (Elf_Addr)def->st_value + defobj->tlsoffset;
-			if (__predict_true(RELOC_ALIGNED_P(where)))
+			if (__predict_true(RELOC_ALIGNED_P(where))) {
+				tmp += *where;
 				*where = tmp;
-			else
+			} else {
+				tmp += load_ptr(where);
 				store_ptr(where, tmp);
+			}
 			dbg("TLS_TPOFF32 %s in %s --> %p",
 			    obj->strtab + obj->symtab[symnum].st_name,
 			    obj->path, (void *)tmp);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202311032144.3A3LiEF3049266>