fix dl_iterate_phdr dlpi_tls_data reporting to match spec
authorRich Felker <dalias@aerifal.cx>
Fri, 26 Mar 2021 17:35:41 +0000 (13:35 -0400)
committerRich Felker <dalias@aerifal.cx>
Fri, 26 Mar 2021 17:35:41 +0000 (13:35 -0400)
dl_iterate_phdr was wrongly reporting the address of the DSO's PT_TLS
image rather than the calling thread's instance of the TLS. the man
page, which is essentially normative for a nonstandard function of
this sort, clearly specifies the latter. it does not clarify where
exactly within/relative-to the image the pointer should point, but the
reasonable thing to do is match the ABI's DTP offset, and this seems
to be what other implementations do.

ldso/dynlink.c
src/ldso/dl_iterate_phdr.c

index aaadcce..b66ad53 100644 (file)
@@ -2331,7 +2331,7 @@ int dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size_t size, void
                info.dlpi_adds      = gencnt;
                info.dlpi_subs      = 0;
                info.dlpi_tls_modid = current->tls_id;
-               info.dlpi_tls_data  = current->tls.image;
+               info.dlpi_tls_data = __tls_get_addr((tls_mod_off_t[]){current->tls_id,0});
 
                ret = (callback)(&info, sizeof (info), data);
 
index 86c87ef..9546dd3 100644 (file)
@@ -1,5 +1,6 @@
 #include <elf.h>
 #include <link.h>
+#include "pthread_impl.h"
 #include "libc.h"
 
 #define AUX_CNT 38
@@ -35,7 +36,7 @@ static int static_dl_iterate_phdr(int(*callback)(struct dl_phdr_info *info, size
        info.dlpi_subs  = 0;
        if (tls_phdr) {
                info.dlpi_tls_modid = 1;
-               info.dlpi_tls_data = (void *)(base + tls_phdr->p_vaddr);
+               info.dlpi_tls_data = __tls_get_addr((tls_mod_off_t[]){1,0});
        } else {
                info.dlpi_tls_modid = 0;
                info.dlpi_tls_data = 0;