Summary: | Dynamic TLS address is not congruent with p_vaddr when (p_vaddr % p_align != 0) | ||
---|---|---|---|
Product: | glibc | Reporter: | Ryan Prichard <rprichard> |
Component: | libc | Assignee: | Not yet assigned to anyone <unassigned> |
Status: | NEW --- | ||
Severity: | normal | CC: | bugdal, drepper.fsp, i, nsz, nsz, rprichard |
Priority: | P2 | Flags: | fweimer:
security-
|
Version: | 2.31 | ||
Target Milestone: | --- | ||
Host: | Target: | ||
Build: | Last reconfirmed: | 2019-05-24 00:00:00 | |
Attachments: |
test case DSO
test1_main.c trim-pt-tls.c test1_dso.c |
Description
Ryan Prichard
2019-05-23 03:55:55 UTC
Created attachment 11793 [details]
test case DSO
Created attachment 11794 [details]
test1_main.c
Created attachment 11795 [details]
trim-pt-tls.c
Created attachment 11796 [details]
test1_dso.c
i think the intention in glibc is to satisfy the % formula, based on the big comment in _dl_determine_tlsoffset (and on the presence of map->l_tls_firstbyte_offset which is the % p_align remainder). it seems to work on aarch64, at least the test gives &tlsvar % 4 == 1. x86 tls offsets are handled with a different code path because that's "tls variant 2" (TLS_TCB_AT_TP) instead of "tls variant 1" (TLS_DTV_AT_TP) so it's possible that there is a bug in that (but right now i dont have an x86 machine available to test that). I see the same thing with aarch64 glibc: tp = 0x77f7144710 &tlsvar = 0x77f71447b1 Based on the value of &tlsvar vs __builtin_thread_pointer(), it appears that a small-enough TLS segment is automatically allocated in reserved static TLS space. If I increase the size of tlsvar from 4 to 0x1000, then the test case fails: tp = 0x771d65b710 &tlsvar = 0x64be7458e0 On x86-64, if I mark tlsvar with __attribute__((tls_model("initial-exec"))), forcing it into the reserved static TLS area, then the test case passes: tp = 0x7f6033d7c700 &tlsvar = 0x7f6033d7c685 sorry somehow i missed that we are talking about dynamic tls and i was looking at the static tls code. indeed the dynamic tls code does not access the l_tls_firstbyte_offset, only alignment and size are passed to allocate_dtv_entry. i guess there were historical linkers that produced p_vaddr % p_align != 0 for static tls, but not for dynamic tls or the dynamic tls case were not visible because affected targets supported unaligned access, so it was only fixed in the static tls case. (with local exec tls the runtime tp offset must match the value computed by the static linker, there is no such requirement in the dynamic case, so if the user code does not care about alignment then wrong alignment works.) i assume nowadays linkers ensure the beginning of the tls block is aligned, so it's not an issue in practice, but still an ELF TLS correctness issue. |