[LTP] [PATCH] lapi/tls: remove the TLS support from i386
Li Wang
liwang@redhat.com
Wed Jan 21 10:01:59 CET 2026
Using a LTP naked clone() to verify that CLONE_SETTLS is unreliable
when running 32-bit on x86_64, since TLS requires two steps: writing
the descriptor and switching the selector. But CLONE_SETTLS on i386
only overrides the former:
kernel_clone()
copy_process()
copy_thread()
set_new_tls()
do_set_thread_area()
In copy_thread(), the child's register frame is copied from the parent
*childregs = *current_pt_regs(); and on the 32-bit side it also does
savesegment(gs, p->thread.gs); saving the current %gs into thread_struct.
Together, this means that unless something explicitly overwrites it later,
the child's initial %gs selector is inherited from the parent.
https://elixir.bootlin.com/linux/v6.18/source/arch/x86/kernel/process.c#L243
Then, in do_set_thread_area(), the kernel updates the TLS descriptor
set_tls_desc(p, idx, &info, 1); However, when (p != current), the x86_32 path
does not update or refresh any segment selector. So it updates the descriptor
but does not switch the child's %gs selector to the new modified_sel.
https://elixir.bootlin.com/linux/v6.18/source/arch/x86/kernel/tls.c#L150
Therefore, on i386, relying on CLONE_SETTLS alone can leave the child
executing with the parent's %gs selector, so TLS accesses still resolve
to the old TLS base.
===============
The behavior above explains why clone10 fails even if we update the TLS
descriptor base (either hard-coding or via set_thread_area()).
Example (x86_64 kernel running a 32-bit ELF):
# uname -rm
6.19.0-rc2.liwang x86_64
# readelf -h clone10 |grep Class
Class: ELF32
# ./clone10
...
clone10.c:48: TINFO: Child (PID: 5262, TID: 5263): TLS value set to: 101
clone10.c:72: TFAIL: Parent (PID: 5262, TID: 5262): TLS value mismatch: got 101, expected 100
Reported-by: Wei Gao <wegao@suse.com>
Signed-off-by: Li Wang <liwang@redhat.com>
---
include/lapi/tls.h | 26 --------------------------
1 file changed, 26 deletions(-)
diff --git a/include/lapi/tls.h b/include/lapi/tls.h
index a067872e0..f7e2f483f 100644
--- a/include/lapi/tls.h
+++ b/include/lapi/tls.h
@@ -17,10 +17,6 @@
#include <stdio.h>
#include <unistd.h>
-#if defined(__i386__)
-#include <asm/ldt.h>
-#endif
-
#include "tst_test.h"
#define TLS_SIZE 4096
@@ -37,7 +33,6 @@ typedef struct {
#endif
extern void *tls_ptr;
-extern struct user_desc *tls_desc;
static inline void *allocate_tls_area(void)
{
@@ -59,21 +54,6 @@ static inline void init_tls(void)
{
#if defined(__x86_64__) || defined(__aarch64__) || defined(__s390x__)
tls_ptr = allocate_tls_area();
-
-#elif defined(__i386__)
- tls_ptr = allocate_tls_area();
- tls_desc = SAFE_MALLOC(sizeof(*tls_desc));
- memset(tls_desc, 0, sizeof(*tls_desc));
- tls_desc->entry_number = -1;
- tls_desc->base_addr = (unsigned long)tls_ptr;
- tls_desc->limit = TLS_SIZE;
- tls_desc->seg_32bit = 1;
- tls_desc->contents = 0;
- tls_desc->read_exec_only = 0;
- tls_desc->limit_in_pages = 0;
- tls_desc->seg_not_present = 0;
- tls_desc->useable = 1;
-
#else
tst_brk(TCONF, "Unsupported architecture for TLS");
#endif
@@ -87,12 +67,6 @@ static inline void free_tls(void)
free(tls_ptr);
tls_ptr = NULL;
}
-#elif defined(__i386__)
- if (tls_desc) {
- free((void *)(uintptr_t)tls_desc->base_addr);
- free(tls_desc);
- tls_desc = NULL;
- }
#endif
}
--
2.52.0
More information about the ltp
mailing list