Linux Test Project
 help / color / mirror / Atom feed
* [LTP] [PATCH] lapi/tls: remove the TLS support from i386
@ 2026-01-21  9:01 Li Wang via ltp
  2026-01-21  9:48 ` Wei Gao via ltp
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Li Wang via ltp @ 2026-01-21  9:01 UTC (permalink / raw)
  To: ltp

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


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [LTP] [PATCH] lapi/tls: remove the TLS support from i386
  2026-01-21  9:01 [LTP] [PATCH] lapi/tls: remove the TLS support from i386 Li Wang via ltp
@ 2026-01-21  9:48 ` Wei Gao via ltp
  2026-01-21 13:32 ` Cyril Hrubis
  2026-01-22 10:41 ` Jan Stancek via ltp
  2 siblings, 0 replies; 7+ messages in thread
From: Wei Gao via ltp @ 2026-01-21  9:48 UTC (permalink / raw)
  To: Li Wang; +Cc: ltp

On Wed, Jan 21, 2026 at 05:01:59PM +0800, Li Wang wrote:
> 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
>  }

Thanks for your patch.
Reviewed-by: Wei Gao <wegao@suse.com>
>  
> -- 
> 2.52.0
> 

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [LTP] [PATCH] lapi/tls: remove the TLS support from i386
  2026-01-21  9:01 [LTP] [PATCH] lapi/tls: remove the TLS support from i386 Li Wang via ltp
  2026-01-21  9:48 ` Wei Gao via ltp
@ 2026-01-21 13:32 ` Cyril Hrubis
  2026-01-22  0:39   ` Li Wang via ltp
  2026-01-22 10:41 ` Jan Stancek via ltp
  2 siblings, 1 reply; 7+ messages in thread
From: Cyril Hrubis @ 2026-01-21 13:32 UTC (permalink / raw)
  To: Li Wang; +Cc: ltp

Hi!
Shouldn't we also set .supported_archs to x86_64 in clone10?

Otherwise:

Acked-by: Cyril Hrubis <chrubis@suse.cz>

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [LTP] [PATCH] lapi/tls: remove the TLS support from i386
  2026-01-21 13:32 ` Cyril Hrubis
@ 2026-01-22  0:39   ` Li Wang via ltp
  2026-01-22 10:20     ` Cyril Hrubis
  0 siblings, 1 reply; 7+ messages in thread
From: Li Wang via ltp @ 2026-01-22  0:39 UTC (permalink / raw)
  To: Cyril Hrubis; +Cc: ltp

> Shouldn't we also set .supported_archs to x86_64 in clone10?

Nope, the others archs also work (aarch64, s390x, etc).

> Otherwise:
>
> Acked-by: Cyril Hrubis <chrubis@suse.cz>

Merged, thanks!

-- 
Regards,
Li Wang


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [LTP] [PATCH] lapi/tls: remove the TLS support from i386
  2026-01-22  0:39   ` Li Wang via ltp
@ 2026-01-22 10:20     ` Cyril Hrubis
  2026-01-22 10:27       ` Li Wang via ltp
  0 siblings, 1 reply; 7+ messages in thread
From: Cyril Hrubis @ 2026-01-22 10:20 UTC (permalink / raw)
  To: Li Wang; +Cc: ltp

Hi!
> > Shouldn't we also set .supported_archs to x86_64 in clone10?
> 
> Nope, the others archs also work (aarch64, s390x, etc).

The the supported_archs should be set to:

{"x86_64", "s390x", "aarch64", NULL}

right?

The code would TCONF on any other architecture.

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [LTP] [PATCH] lapi/tls: remove the TLS support from i386
  2026-01-22 10:20     ` Cyril Hrubis
@ 2026-01-22 10:27       ` Li Wang via ltp
  0 siblings, 0 replies; 7+ messages in thread
From: Li Wang via ltp @ 2026-01-22 10:27 UTC (permalink / raw)
  To: Cyril Hrubis; +Cc: ltp

Cyril Hrubis <chrubis@suse.cz> wrote:

> > > Shouldn't we also set .supported_archs to x86_64 in clone10?
> >
> > Nope, the others archs also work (aarch64, s390x, etc).
>
> The the supported_archs should be set to:
>
> {"x86_64", "s390x", "aarch64", NULL}
>
> right?

Ah right, I have sent a new patch.

-- 
Regards,
Li Wang


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [LTP] [PATCH] lapi/tls: remove the TLS support from i386
  2026-01-21  9:01 [LTP] [PATCH] lapi/tls: remove the TLS support from i386 Li Wang via ltp
  2026-01-21  9:48 ` Wei Gao via ltp
  2026-01-21 13:32 ` Cyril Hrubis
@ 2026-01-22 10:41 ` Jan Stancek via ltp
  2 siblings, 0 replies; 7+ messages in thread
From: Jan Stancek via ltp @ 2026-01-22 10:41 UTC (permalink / raw)
  To: Li Wang; +Cc: ltp

On Wed, Jan 21, 2026 at 10:02 AM Li Wang via ltp <ltp@lists.linux.it> wrote:
>
> 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>

Acked-by: Jan Stancek <jstancek@redhat.com>


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-01-22 10:42 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-21  9:01 [LTP] [PATCH] lapi/tls: remove the TLS support from i386 Li Wang via ltp
2026-01-21  9:48 ` Wei Gao via ltp
2026-01-21 13:32 ` Cyril Hrubis
2026-01-22  0:39   ` Li Wang via ltp
2026-01-22 10:20     ` Cyril Hrubis
2026-01-22 10:27       ` Li Wang via ltp
2026-01-22 10:41 ` Jan Stancek via ltp

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox