public inbox for ltp@lists.linux.it
 help / color / mirror / Atom feed
* [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
@ 2026-02-07 14:59 Changwei Zou via ltp
  2026-02-09  7:51 ` Petr Vorel
  2026-02-26  7:56 ` Li Wang via ltp
  0 siblings, 2 replies; 12+ messages in thread
From: Changwei Zou via ltp @ 2026-02-07 14:59 UTC (permalink / raw)
  To: ltp; +Cc: changwei.zou

Allocate extra space before the TLS area to hold a struct pthread, ensuring
THREAD_SELF->cancelhandling is initialized to 0. This prevents undefined
behavior in __pthread_disable_asynccancel(), which is called at thread
cancellation points such as write().

Without this, touch_tls_in_child() could get stuck in tst_res().

(gdb) bt
  0  futex_wait () at ../sysdeps/nptl/futex-internal.h:141
  1  futex_wait_simple () at ../sysdeps/nptl/futex-internal.h:172
  2  __libc_disable_asynccancel () at ../nptl/cancellation.c:100
  3  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:26
  4  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:24
  5  print_result ()  at tst_test.c:387
  6  tst_vres_ () at tst_test.c:401
  7  tst_res_ () at tst_test.c:512
  8  touch_tls_in_child (arg=<optimized out>) at clone10.c:48
  9  thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78

Signed-off-by: Changwei Zou <changwei.zou@canonical.com>
---
 include/lapi/tls.h | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/include/lapi/tls.h b/include/lapi/tls.h
index 468fe3086..7f2fa18a1 100644
--- a/include/lapi/tls.h
+++ b/include/lapi/tls.h
@@ -22,6 +22,15 @@
 #define TLS_SIZE 4096
 #define TLS_ALIGN 16
 
+/*
+ * Space allocated large enough to hold a struct pthread.
+ *
+ * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
+ * avoiding undefined behavior (e.g., in clone10.c) in __pthread_disable_asynccancel(),
+ * which is called at thread cancellation points such as write().
+ */
+#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
+
 #if defined(__x86_64__)
 typedef struct {
 	void *tcb;
@@ -36,10 +45,11 @@ extern void *tls_ptr;
 
 static inline void *allocate_tls_area(void)
 {
-	void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
+	char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
 	if (!tls_area)
 		tst_brk(TBROK | TERRNO, "aligned_alloc failed");
-	memset(tls_area, 0, TLS_SIZE);
+	memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
+	tls_area += TLS_PRE_TCB_SIZE;
 
 #if defined(__x86_64__)
 	tcb_t *tcb = (tcb_t *)tls_area;
@@ -59,7 +69,7 @@ static inline void free_tls(void)
 {
 	usleep(10000);
 	if (tls_ptr) {
-		free(tls_ptr);
+		free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
 		tls_ptr = NULL;
 	}
 }
-- 
2.43.0


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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-07 14:59 [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c Changwei Zou via ltp
@ 2026-02-09  7:51 ` Petr Vorel
  2026-02-09  9:42   ` Changwei Zou via ltp
  2026-02-09 11:20   ` Changwei Zou via ltp
  2026-02-26  7:56 ` Li Wang via ltp
  1 sibling, 2 replies; 12+ messages in thread
From: Petr Vorel @ 2026-02-09  7:51 UTC (permalink / raw)
  To: Changwei Zou; +Cc: ltp

Hi Changwei,

> Allocate extra space before the TLS area to hold a struct pthread, ensuring
> THREAD_SELF->cancelhandling is initialized to 0. This prevents undefined
> behavior in __pthread_disable_asynccancel(), which is called at thread
> cancellation points such as write().

> Without this, touch_tls_in_child() could get stuck in tst_res().

LGTM, but I'd prefer others had a look on it.
Acked-by: Petr Vorel <pvorel@suse.cz>

BTW clone10.c segfaults w/a the patch when run with more iterations:

./clone10 -i200
clone10.c:48: TINFO: Child (PID: 4271, TID: 4285): TLS value set to: 101
clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
clone10.c:48: TINFO: Child (PID: 4271, TID: 4286): TLS value set to: 101
clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
tst_test.c:1953: TBROK: Test killed by SIGSEGV!

Summary:
passed   15
failed   0
broken   1
skipped  0
warnings 0

Kind regards,
Petr

> (gdb) bt
>   0  futex_wait () at ../sysdeps/nptl/futex-internal.h:141
>   1  futex_wait_simple () at ../sysdeps/nptl/futex-internal.h:172
>   2  __libc_disable_asynccancel () at ../nptl/cancellation.c:100
>   3  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:26
>   4  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:24
>   5  print_result ()  at tst_test.c:387
>   6  tst_vres_ () at tst_test.c:401
>   7  tst_res_ () at tst_test.c:512
>   8  touch_tls_in_child (arg=<optimized out>) at clone10.c:48
>   9  thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78

> Signed-off-by: Changwei Zou <changwei.zou@canonical.com>
> ---
>  include/lapi/tls.h | 16 +++++++++++++---
>  1 file changed, 13 insertions(+), 3 deletions(-)

> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
> index 468fe3086..7f2fa18a1 100644
> --- a/include/lapi/tls.h
> +++ b/include/lapi/tls.h
> @@ -22,6 +22,15 @@
>  #define TLS_SIZE 4096
>  #define TLS_ALIGN 16

> +/*
> + * Space allocated large enough to hold a struct pthread.
> + *
> + * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
> + * avoiding undefined behavior (e.g., in clone10.c) in __pthread_disable_asynccancel(),
> + * which is called at thread cancellation points such as write().
> + */
> +#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
> +
>  #if defined(__x86_64__)
>  typedef struct {
>  	void *tcb;
> @@ -36,10 +45,11 @@ extern void *tls_ptr;

>  static inline void *allocate_tls_area(void)
>  {
> -	void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
> +	char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
>  	if (!tls_area)
>  		tst_brk(TBROK | TERRNO, "aligned_alloc failed");
> -	memset(tls_area, 0, TLS_SIZE);
> +	memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
> +	tls_area += TLS_PRE_TCB_SIZE;

>  #if defined(__x86_64__)
>  	tcb_t *tcb = (tcb_t *)tls_area;
> @@ -59,7 +69,7 @@ static inline void free_tls(void)
>  {
>  	usleep(10000);
>  	if (tls_ptr) {
> -		free(tls_ptr);
> +		free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
>  		tls_ptr = NULL;
>  	}
>  }

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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-09  7:51 ` Petr Vorel
@ 2026-02-09  9:42   ` Changwei Zou via ltp
  2026-02-09 11:20   ` Changwei Zou via ltp
  1 sibling, 0 replies; 12+ messages in thread
From: Changwei Zou via ltp @ 2026-02-09  9:42 UTC (permalink / raw)
  To: Petr Vorel; +Cc: ltp

Hi Petr,
Additional details can be found on the following page:
https://bugs.launchpad.net/ubuntu-kernel-tests/+bug/2139127/comments/1
Thank you very much.
Kind regards,
Changwei


On 2/9/26 18:51, Petr Vorel wrote:
> Hi Changwei,
>
>> Allocate extra space before the TLS area to hold a struct pthread, ensuring
>> THREAD_SELF->cancelhandling is initialized to 0. This prevents undefined
>> behavior in __pthread_disable_asynccancel(), which is called at thread
>> cancellation points such as write().
>> Without this, touch_tls_in_child() could get stuck in tst_res().
> LGTM, but I'd prefer others had a look on it.
> Acked-by: Petr Vorel<pvorel@suse.cz>
>
> BTW clone10.c segfaults w/a the patch when run with more iterations:
>
> ./clone10 -i200
> clone10.c:48: TINFO: Child (PID: 4271, TID: 4285): TLS value set to: 101
> clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
> clone10.c:48: TINFO: Child (PID: 4271, TID: 4286): TLS value set to: 101
> clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
> tst_test.c:1953: TBROK: Test killed by SIGSEGV!
>
> Summary:
> passed   15
> failed   0
> broken   1
> skipped  0
> warnings 0
>
> Kind regards,
> Petr
>
>> (gdb) bt
>>    0  futex_wait () at ../sysdeps/nptl/futex-internal.h:141
>>    1  futex_wait_simple () at ../sysdeps/nptl/futex-internal.h:172
>>    2  __libc_disable_asynccancel () at ../nptl/cancellation.c:100
>>    3  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:26
>>    4  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:24
>>    5  print_result ()  at tst_test.c:387
>>    6  tst_vres_ () at tst_test.c:401
>>    7  tst_res_ () at tst_test.c:512
>>    8  touch_tls_in_child (arg=<optimized out>) atclone10.c:48
>>    9  thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
>> Signed-off-by: Changwei Zou<changwei.zou@canonical.com>
>> ---
>>   include/lapi/tls.h | 16 +++++++++++++---
>>   1 file changed, 13 insertions(+), 3 deletions(-)
>> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
>> index 468fe3086..7f2fa18a1 100644
>> --- a/include/lapi/tls.h
>> +++ b/include/lapi/tls.h
>> @@ -22,6 +22,15 @@
>>   #define TLS_SIZE 4096
>>   #define TLS_ALIGN 16
>> +/*
>> + * Space allocated large enough to hold a struct pthread.
>> + *
>> + * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
>> + * avoiding undefined behavior (e.g., in clone10.c) in __pthread_disable_asynccancel(),
>> + * which is called at thread cancellation points such as write().
>> + */
>> +#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
>> +
>>   #if defined(__x86_64__)
>>   typedef struct {
>>   	void *tcb;
>> @@ -36,10 +45,11 @@ extern void *tls_ptr;
>>   static inline void *allocate_tls_area(void)
>>   {
>> -	void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
>> +	char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
>>   	if (!tls_area)
>>   		tst_brk(TBROK | TERRNO, "aligned_alloc failed");
>> -	memset(tls_area, 0, TLS_SIZE);
>> +	memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
>> +	tls_area += TLS_PRE_TCB_SIZE;
>>   #if defined(__x86_64__)
>>   	tcb_t *tcb = (tcb_t *)tls_area;
>> @@ -59,7 +69,7 @@ static inline void free_tls(void)
>>   {
>>   	usleep(10000);
>>   	if (tls_ptr) {
>> -		free(tls_ptr);
>> +		free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
>>   		tls_ptr = NULL;
>>   	}
>>   }

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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-09  7:51 ` Petr Vorel
  2026-02-09  9:42   ` Changwei Zou via ltp
@ 2026-02-09 11:20   ` Changwei Zou via ltp
  2026-02-09 11:47     ` Petr Vorel
  1 sibling, 1 reply; 12+ messages in thread
From: Changwei Zou via ltp @ 2026-02-09 11:20 UTC (permalink / raw)
  To: Petr Vorel; +Cc: ltp

Hi Petr,
With the original upstream LTP,
I ran clone10 -i 1000 on three machines (including AArch64 and AMD64), 
and it failed on all of them.
This suggests there may be another bug that we still need to identify.
Thank you very much for your invaluable information.
Kind regards,
Changwei
*1. On an AArch64 cloud instance*
```sh
azure@clone10-aarch64-kcp:~/orig/ltp$ 
./testcases/kernel/syscalls/clone/clone10-i1000
clone10.c:68: TPASS:Parent(PID: 106163,TID:106163): TLS value correct: 100
clone10.c:48: TINFO:Child(PID: 106163,TID:106200): TLS value set to: 101
tst_test.c:1953: TBROK:TestkilledbySIGBUS!
Summary:
passed 36
failed 0
broken 1
skipped 0
warnings 0
```
*2. On an AMD64 machine*
```sh
ubuntu@ZBook:~/orig/ltp$ ./testcases/kernel/syscalls/clone/clone10-i1000
clone10.c:48: TINFO:Child(PID: 125560,TID:125870): TLS value set to: 101
clone10.c:68: TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
double freeorcorruption(out)
clone10.c:48: TINFO:Child(PID: 125560,TID:125871): TLS value set to: 101
clone10.c:68: TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
tst_test.c:1953: TBROK:TestkilledbySIGIOT/SIGABRT!
Summary:
passed 311
failed 0
broken 1
skipped 0
warnings 0
```
*3. On an AArch64 machine*
```sh
ubuntu@asus-pe100a:~/orig/ltp$ 
./testcases/kernel/syscalls/clone/clone10-i1000
clone10.c:68: TPASS:Parent(PID: 158953,TID:158953): TLS value correct: 100
clone10.c:48: TINFO:Child(PID: 158953,TID:159029): TLS value set to: 101
tst_test.c:1953: TBROK:TestkilledbySIGSEGV!
Summary:
passed 75
failed 0
broken 1
skipped 0
warnings 0
```


On 2/9/26 18:51, Petr Vorel wrote:
> Hi Changwei,
>
>> Allocate extra space before the TLS area to hold a struct pthread, ensuring
>> THREAD_SELF->cancelhandling is initialized to 0. This prevents undefined
>> behavior in __pthread_disable_asynccancel(), which is called at thread
>> cancellation points such as write().
>> Without this, touch_tls_in_child() could get stuck in tst_res().
> LGTM, but I'd prefer others had a look on it.
> Acked-by: Petr Vorel<pvorel@suse.cz>
>
> BTW clone10.c segfaults w/a the patch when run with more iterations:
>
> ./clone10 -i200
> clone10.c:48: TINFO: Child (PID: 4271, TID: 4285): TLS value set to: 101
> clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
> clone10.c:48: TINFO: Child (PID: 4271, TID: 4286): TLS value set to: 101
> clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
> tst_test.c:1953: TBROK: Test killed by SIGSEGV!
>
> Summary:
> passed   15
> failed   0
> broken   1
> skipped  0
> warnings 0
>
> Kind regards,
> Petr
>
>> (gdb) bt
>>    0  futex_wait () at ../sysdeps/nptl/futex-internal.h:141
>>    1  futex_wait_simple () at ../sysdeps/nptl/futex-internal.h:172
>>    2  __libc_disable_asynccancel () at ../nptl/cancellation.c:100
>>    3  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:26
>>    4  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:24
>>    5  print_result ()  at tst_test.c:387
>>    6  tst_vres_ () at tst_test.c:401
>>    7  tst_res_ () at tst_test.c:512
>>    8  touch_tls_in_child (arg=<optimized out>) atclone10.c:48
>>    9  thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
>> Signed-off-by: Changwei Zou<changwei.zou@canonical.com>
>> ---
>>   include/lapi/tls.h | 16 +++++++++++++---
>>   1 file changed, 13 insertions(+), 3 deletions(-)
>> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
>> index 468fe3086..7f2fa18a1 100644
>> --- a/include/lapi/tls.h
>> +++ b/include/lapi/tls.h
>> @@ -22,6 +22,15 @@
>>   #define TLS_SIZE 4096
>>   #define TLS_ALIGN 16
>> +/*
>> + * Space allocated large enough to hold a struct pthread.
>> + *
>> + * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
>> + * avoiding undefined behavior (e.g., in clone10.c) in __pthread_disable_asynccancel(),
>> + * which is called at thread cancellation points such as write().
>> + */
>> +#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
>> +
>>   #if defined(__x86_64__)
>>   typedef struct {
>>   	void *tcb;
>> @@ -36,10 +45,11 @@ extern void *tls_ptr;
>>   static inline void *allocate_tls_area(void)
>>   {
>> -	void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
>> +	char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
>>   	if (!tls_area)
>>   		tst_brk(TBROK | TERRNO, "aligned_alloc failed");
>> -	memset(tls_area, 0, TLS_SIZE);
>> +	memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
>> +	tls_area += TLS_PRE_TCB_SIZE;
>>   #if defined(__x86_64__)
>>   	tcb_t *tcb = (tcb_t *)tls_area;
>> @@ -59,7 +69,7 @@ static inline void free_tls(void)
>>   {
>>   	usleep(10000);
>>   	if (tls_ptr) {
>> -		free(tls_ptr);
>> +		free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
>>   		tls_ptr = NULL;
>>   	}
>>   }

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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-09 11:20   ` Changwei Zou via ltp
@ 2026-02-09 11:47     ` Petr Vorel
  2026-02-10  7:03       ` Changwei Zou via ltp
  0 siblings, 1 reply; 12+ messages in thread
From: Petr Vorel @ 2026-02-09 11:47 UTC (permalink / raw)
  To: Changwei Zou; +Cc: ltp

Hi Changwei,

> Hi Petr,
> With the original upstream LTP,
> I ran clone10 -i 1000 on three machines (including AArch64 and AMD64), and
> it failed on all of them.

> This suggests there may be another bug that we still need to identify.

Yes, it's a separate bug, not relevant to your fix. I trigger it on x86_64.

Kind regards,
Petr

> Thank you very much for your invaluable information.
> Kind regards,
> Changwei
> *1. On an AArch64 cloud instance*
> ```sh
> azure@clone10-aarch64-kcp:~/orig/ltp$
> ./testcases/kernel/syscalls/clone/clone10-i1000
> clone10.c:68: TPASS:Parent(PID: 106163,TID:106163): TLS value correct: 100
> clone10.c:48: TINFO:Child(PID: 106163,TID:106200): TLS value set to: 101
> tst_test.c:1953: TBROK:TestkilledbySIGBUS!
> Summary:
> passed 36
> failed 0
> broken 1
> skipped 0
> warnings 0
> ```
> *2. On an AMD64 machine*
> ```sh
> ubuntu@ZBook:~/orig/ltp$ ./testcases/kernel/syscalls/clone/clone10-i1000
> clone10.c:48: TINFO:Child(PID: 125560,TID:125870): TLS value set to: 101
> clone10.c:68: TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
> double freeorcorruption(out)
> clone10.c:48: TINFO:Child(PID: 125560,TID:125871): TLS value set to: 101
> clone10.c:68: TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
> tst_test.c:1953: TBROK:TestkilledbySIGIOT/SIGABRT!
> Summary:
> passed 311
> failed 0
> broken 1
> skipped 0
> warnings 0
> ```
> *3. On an AArch64 machine*
> ```sh
> ubuntu@asus-pe100a:~/orig/ltp$
> ./testcases/kernel/syscalls/clone/clone10-i1000
> clone10.c:68: TPASS:Parent(PID: 158953,TID:158953): TLS value correct: 100
> clone10.c:48: TINFO:Child(PID: 158953,TID:159029): TLS value set to: 101
> tst_test.c:1953: TBROK:TestkilledbySIGSEGV!
> Summary:
> passed 75
> failed 0
> broken 1
> skipped 0
> warnings 0
> ```


> On 2/9/26 18:51, Petr Vorel wrote:
> > Hi Changwei,

> > > Allocate extra space before the TLS area to hold a struct pthread, ensuring
> > > THREAD_SELF->cancelhandling is initialized to 0. This prevents undefined
> > > behavior in __pthread_disable_asynccancel(), which is called at thread
> > > cancellation points such as write().
> > > Without this, touch_tls_in_child() could get stuck in tst_res().
> > LGTM, but I'd prefer others had a look on it.
> > Acked-by: Petr Vorel<pvorel@suse.cz>

> > BTW clone10.c segfaults w/a the patch when run with more iterations:

> > ./clone10 -i200
> > clone10.c:48: TINFO: Child (PID: 4271, TID: 4285): TLS value set to: 101
> > clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
> > clone10.c:48: TINFO: Child (PID: 4271, TID: 4286): TLS value set to: 101
> > clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
> > tst_test.c:1953: TBROK: Test killed by SIGSEGV!

> > Summary:
> > passed   15
> > failed   0
> > broken   1
> > skipped  0
> > warnings 0

> > Kind regards,
> > Petr

> > > (gdb) bt
> > >    0  futex_wait () at ../sysdeps/nptl/futex-internal.h:141
> > >    1  futex_wait_simple () at ../sysdeps/nptl/futex-internal.h:172
> > >    2  __libc_disable_asynccancel () at ../nptl/cancellation.c:100
> > >    3  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:26
> > >    4  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:24
> > >    5  print_result ()  at tst_test.c:387
> > >    6  tst_vres_ () at tst_test.c:401
> > >    7  tst_res_ () at tst_test.c:512
> > >    8  touch_tls_in_child (arg=<optimized out>) atclone10.c:48
> > >    9  thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
> > > Signed-off-by: Changwei Zou<changwei.zou@canonical.com>
> > > ---
> > >   include/lapi/tls.h | 16 +++++++++++++---
> > >   1 file changed, 13 insertions(+), 3 deletions(-)
> > > diff --git a/include/lapi/tls.h b/include/lapi/tls.h
> > > index 468fe3086..7f2fa18a1 100644
> > > --- a/include/lapi/tls.h
> > > +++ b/include/lapi/tls.h
> > > @@ -22,6 +22,15 @@
> > >   #define TLS_SIZE 4096
> > >   #define TLS_ALIGN 16
> > > +/*
> > > + * Space allocated large enough to hold a struct pthread.
> > > + *
> > > + * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
> > > + * avoiding undefined behavior (e.g., in clone10.c) in __pthread_disable_asynccancel(),
> > > + * which is called at thread cancellation points such as write().
> > > + */
> > > +#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
> > > +
> > >   #if defined(__x86_64__)
> > >   typedef struct {
> > >   	void *tcb;
> > > @@ -36,10 +45,11 @@ extern void *tls_ptr;
> > >   static inline void *allocate_tls_area(void)
> > >   {
> > > -	void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
> > > +	char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
> > >   	if (!tls_area)
> > >   		tst_brk(TBROK | TERRNO, "aligned_alloc failed");
> > > -	memset(tls_area, 0, TLS_SIZE);
> > > +	memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
> > > +	tls_area += TLS_PRE_TCB_SIZE;
> > >   #if defined(__x86_64__)
> > >   	tcb_t *tcb = (tcb_t *)tls_area;
> > > @@ -59,7 +69,7 @@ static inline void free_tls(void)
> > >   {
> > >   	usleep(10000);
> > >   	if (tls_ptr) {
> > > -		free(tls_ptr);
> > > +		free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
> > >   		tls_ptr = NULL;
> > >   	}
> > >   }

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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-09 11:47     ` Petr Vorel
@ 2026-02-10  7:03       ` Changwei Zou via ltp
  2026-02-10 12:40         ` Changwei Zou via ltp
  2026-02-12  8:09         ` Petr Vorel
  0 siblings, 2 replies; 12+ messages in thread
From: Changwei Zou via ltp @ 2026-02-10  7:03 UTC (permalink / raw)
  To: Petr Vorel; +Cc: ltp

Hi Petr,
LTP uses glibc.
Even a simple library function like write(),
which wraps the sys_write system call,
is involved in the memory model of pthreads.
Therefore, touch_tls_in_child() must behave almost exactly like a pthread.
Otherwise, memory corruption can occur when executing functions inside 
glibc.
In the current version of clone10.c, according to the assembly code,
the statement tls_var = 0x65; already constitutes a buffer overflow on 
x86_64.
Unfortunately, the struct pthread is opaque and may vary between 
different versions of glibc.
I assume the purpose of clone10.c is to test whether the CLONE_SETTLS 
flag works.
Making touch_tls_in_child() behave exactly like a pthread, however, is 
extremely difficult.
static __thread int tls_var;
static int touch_tls_in_child(void *arg)
{
// 0xfffffffffffffffc is -4
// movl $0x65,%fs:0xfffffffffffffffc
tls_var = 0x65;
}
```sh
(gdb) disassemble touch_tls_in_child
Dump ofassemblercodeforfunctiontouch_tls_in_child:
0x000055555555be40 <+0>:endbr64
0x000055555555be44 <+4>:push%rbx
0x000055555555be45 <+5>:mov0x33c0c(%rip),%rdx# 0x55555558fa58 <tls_ptr>
0x000055555555be4c <+12>:xor%eax,%eax
0x000055555555be4e <+14>:mov$0x1002,%esi
0x000055555555be53 <+19>:mov$0x9e,%edi
0x000055555555be58 <+24>:call0x55555555b500<syscall@plt>
0x000055555555be5d <+29>:cmp$0xffffffffffffffff,%rax
0x000055555555be61 <+33>:je0x55555555bf1d<touch_tls_in_child+221>
0x000055555555be67 <+39>:movl$0x65,%fs:0xfffffffffffffffc//bufferoverflow?
```
On 2/9/26 22:47, Petr Vorel wrote:
> Hi Changwei,
>
>> Hi Petr,
>> With the original upstream LTP,
>> I ran clone10 -i 1000 on three machines (including AArch64 and AMD64), and
>> it failed on all of them.
>> This suggests there may be another bug that we still need to identify.
> Yes, it's a separate bug, not relevant to your fix. I trigger it on x86_64.
>
> Kind regards,
> Petr
>
>> Thank you very much for your invaluable information.
>> Kind regards,
>> Changwei
>> *1. On an AArch64 cloud instance*
>> ```sh
>> azure@clone10-aarch64-kcp:~/orig/ltp$
>> ./testcases/kernel/syscalls/clone/clone10-i1000
>> clone10.c:68:TPASS:Parent(PID: 106163,TID:106163): TLS value correct: 100
>> clone10.c:48:TINFO:Child(PID: 106163,TID:106200): TLS value set to: 101
>> tst_test.c:1953:TBROK:TestkilledbySIGBUS!
>> Summary:
>> passed 36
>> failed 0
>> broken 1
>> skipped 0
>> warnings 0
>> ```
>> *2. On an AMD64 machine*
>> ```sh
>> ubuntu@ZBook:~/orig/ltp$ ./testcases/kernel/syscalls/clone/clone10-i1000
>> clone10.c:48:TINFO:Child(PID: 125560,TID:125870): TLS value set to: 101
>> clone10.c:68:TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
>> double freeorcorruption(out)
>> clone10.c:48:TINFO:Child(PID: 125560,TID:125871): TLS value set to: 101
>> clone10.c:68:TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
>> tst_test.c:1953:TBROK:TestkilledbySIGIOT/SIGABRT!
>> Summary:
>> passed 311
>> failed 0
>> broken 1
>> skipped 0
>> warnings 0
>> ```
>> *3. On an AArch64 machine*
>> ```sh
>> ubuntu@asus-pe100a:~/orig/ltp$
>> ./testcases/kernel/syscalls/clone/clone10-i1000
>> clone10.c:68:TPASS:Parent(PID: 158953,TID:158953): TLS value correct: 100
>> clone10.c:48:TINFO:Child(PID: 158953,TID:159029): TLS value set to: 101
>> tst_test.c:1953:TBROK:TestkilledbySIGSEGV!
>> Summary:
>> passed 75
>> failed 0
>> broken 1
>> skipped 0
>> warnings 0
>> ```
>
>> On 2/9/26 18:51, Petr Vorel wrote:
>>> Hi Changwei,
>>>> Allocate extra space before the TLS area to hold a struct pthread, ensuring
>>>> THREAD_SELF->cancelhandling is initialized to 0. This prevents undefined
>>>> behavior in __pthread_disable_asynccancel(), which is called at thread
>>>> cancellation points such as write().
>>>> Without this, touch_tls_in_child() could get stuck in tst_res().
>>> LGTM, but I'd prefer others had a look on it.
>>> Acked-by: Petr Vorel<pvorel@suse.cz>
>>> BTW clone10.c segfaults w/a the patch when run with more iterations:
>>> ./clone10 -i200
>>> clone10.c:48: TINFO: Child (PID: 4271, TID: 4285): TLS value set to: 101
>>> clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
>>> clone10.c:48: TINFO: Child (PID: 4271, TID: 4286): TLS value set to: 101
>>> clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
>>> tst_test.c:1953: TBROK: Test killed by SIGSEGV!
>>> Summary:
>>> passed   15
>>> failed   0
>>> broken   1
>>> skipped  0
>>> warnings 0
>>> Kind regards,
>>> Petr
>>>> (gdb) bt
>>>>     0  futex_wait () at ../sysdeps/nptl/futex-internal.h:141
>>>>     1  futex_wait_simple () at ../sysdeps/nptl/futex-internal.h:172
>>>>     2  __libc_disable_asynccancel () at ../nptl/cancellation.c:100
>>>>     3  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:26
>>>>     4  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:24
>>>>     5  print_result ()  at tst_test.c:387
>>>>     6  tst_vres_ () at tst_test.c:401
>>>>     7  tst_res_ () at tst_test.c:512
>>>>     8  touch_tls_in_child (arg=<optimized out>)atclone10.c:48
>>>>     9  thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
>>>> Signed-off-by: Changwei Zou<changwei.zou@canonical.com>
>>>> ---
>>>>    include/lapi/tls.h | 16 +++++++++++++---
>>>>    1 file changed, 13 insertions(+), 3 deletions(-)
>>>> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
>>>> index 468fe3086..7f2fa18a1 100644
>>>> --- a/include/lapi/tls.h
>>>> +++ b/include/lapi/tls.h
>>>> @@ -22,6 +22,15 @@
>>>>    #define TLS_SIZE 4096
>>>>    #define TLS_ALIGN 16
>>>> +/*
>>>> + * Space allocated large enough to hold a struct pthread.
>>>> + *
>>>> + * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
>>>> + * avoiding undefined behavior (e.g., in clone10.c) in __pthread_disable_asynccancel(),
>>>> + * which is called at thread cancellation points such as write().
>>>> + */
>>>> +#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
>>>> +
>>>>    #if defined(__x86_64__)
>>>>    typedef struct {
>>>>    	void *tcb;
>>>> @@ -36,10 +45,11 @@ extern void *tls_ptr;
>>>>    static inline void *allocate_tls_area(void)
>>>>    {
>>>> -	void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
>>>> +	char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
>>>>    	if (!tls_area)
>>>>    		tst_brk(TBROK | TERRNO, "aligned_alloc failed");
>>>> -	memset(tls_area, 0, TLS_SIZE);
>>>> +	memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
>>>> +	tls_area += TLS_PRE_TCB_SIZE;
>>>>    #if defined(__x86_64__)
>>>>    	tcb_t *tcb = (tcb_t *)tls_area;
>>>> @@ -59,7 +69,7 @@ static inline void free_tls(void)
>>>>    {
>>>>    	usleep(10000);
>>>>    	if (tls_ptr) {
>>>> -		free(tls_ptr);
>>>> +		free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
>>>>    		tls_ptr = NULL;
>>>>    	}
>>>>    }

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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-10  7:03       ` Changwei Zou via ltp
@ 2026-02-10 12:40         ` Changwei Zou via ltp
  2026-02-12  1:32           ` Changwei Zou via ltp
  2026-02-12  8:09         ` Petr Vorel
  1 sibling, 1 reply; 12+ messages in thread
From: Changwei Zou via ltp @ 2026-02-10 12:40 UTC (permalink / raw)
  To: Petr Vorel; +Cc: ltp

Hi Petr,
I have rewritten the touch_tls_in_child() function and pushed it to my 
GitHub account.
https://github.com/sheisc/ltp
The motivation was to avoid interacting with pthread’s memory model.
I have tested it on both x86_64 and arm64.
The command clone10 -i 100000 passed successfully on both platforms.
Could you please take a look at it?
Thank you very much.
Kine regards,
Changwei
1 On x86_64
```sh
x86_64_ltp$ ./testcases/kernel/syscalls/clone/clone10-i100000
clone10.c:66: TPASS:Parent(PID: 655699,TID:655699): TLS value correct: 100
clone10.c:66: TPASS:Parent(PID: 655699,TID:655699): TLS value correct: 100
Summary:
passed 100000
failed 0
broken 0
skipped 0
warnings 0
```
2 On arm64
```sh
arm64_ltp$ ./testcases/kernel/syscalls/clone/clone10-i100000
clone10.c:66: TPASS:Parent(PID: 222184,TID:222184): TLS value correct: 100
clone10.c:66: TPASS:Parent(PID: 222184,TID:222184): TLS value correct: 100
Summary:
passed 100000
failed 0
broken 0
skipped 0
warnings 0
```


On 2/10/26 18:03, Changwei Zou wrote:
> Hi Petr,
> LTP uses glibc.
> Even a simple library function like write(),
> which wraps the sys_write system call,
> is involved in the memory model of pthreads.
> Therefore, touch_tls_in_child() must behave almost exactly like a 
> pthread.
> Otherwise, memory corruption can occur when executing functions inside 
> glibc.
> In the current version of clone10.c, according to the assembly code,
> the statement tls_var = 0x65; already constitutes a buffer overflow on 
> x86_64.
> Unfortunately, the struct pthread is opaque and may vary between 
> different versions of glibc.
> I assume the purpose of clone10.c is to test whether the CLONE_SETTLS 
> flag works.
> Making touch_tls_in_child() behave exactly like a pthread, however, is 
> extremely difficult.
> static __thread int tls_var;
> static int touch_tls_in_child(void *arg)
> {
> // 0xfffffffffffffffc is -4
> // movl $0x65,%fs:0xfffffffffffffffc
> tls_var = 0x65;
> }
> ```sh
> (gdb) disassemble touch_tls_in_child
> Dump ofassemblercodeforfunctiontouch_tls_in_child:
> 0x000055555555be40 <+0>:endbr64
> 0x000055555555be44 <+4>:push%rbx
> 0x000055555555be45 <+5>:mov0x33c0c(%rip),%rdx# 0x55555558fa58 <tls_ptr>
> 0x000055555555be4c <+12>:xor%eax,%eax
> 0x000055555555be4e <+14>:mov$0x1002,%esi
> 0x000055555555be53 <+19>:mov$0x9e,%edi
> 0x000055555555be58 <+24>:call0x55555555b500<syscall@plt>
> 0x000055555555be5d <+29>:cmp$0xffffffffffffffff,%rax
> 0x000055555555be61 <+33>:je0x55555555bf1d<touch_tls_in_child+221>
> 0x000055555555be67 <+39>:movl$0x65,%fs:0xfffffffffffffffc//bufferoverflow?
> ```
> On 2/9/26 22:47, Petr Vorel wrote:
>> Hi Changwei,
>>
>>> Hi Petr,
>>> With the original upstream LTP,
>>> I ran clone10 -i 1000 on three machines (including AArch64 and AMD64), and
>>> it failed on all of them.
>>> This suggests there may be another bug that we still need to identify.
>> Yes, it's a separate bug, not relevant to your fix. I trigger it on x86_64.
>>
>> Kind regards,
>> Petr
>>
>>> Thank you very much for your invaluable information.
>>> Kind regards,
>>> Changwei
>>> *1. On an AArch64 cloud instance*
>>> ```sh
>>> azure@clone10-aarch64-kcp:~/orig/ltp$
>>> ./testcases/kernel/syscalls/clone/clone10-i1000
>>> clone10.c:68:TPASS:Parent(PID: 106163,TID:106163): TLS value correct: 100
>>> clone10.c:48:TINFO:Child(PID: 106163,TID:106200): TLS value set to: 101
>>> tst_test.c:1953:TBROK:TestkilledbySIGBUS!
>>> Summary:
>>> passed 36
>>> failed 0
>>> broken 1
>>> skipped 0
>>> warnings 0
>>> ```
>>> *2. On an AMD64 machine*
>>> ```sh
>>> ubuntu@ZBook:~/orig/ltp$ ./testcases/kernel/syscalls/clone/clone10-i1000
>>> clone10.c:48:TINFO:Child(PID: 125560,TID:125870): TLS value set to: 101
>>> clone10.c:68:TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
>>> double freeorcorruption(out)
>>> clone10.c:48:TINFO:Child(PID: 125560,TID:125871): TLS value set to: 101
>>> clone10.c:68:TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
>>> tst_test.c:1953:TBROK:TestkilledbySIGIOT/SIGABRT!
>>> Summary:
>>> passed 311
>>> failed 0
>>> broken 1
>>> skipped 0
>>> warnings 0
>>> ```
>>> *3. On an AArch64 machine*
>>> ```sh
>>> ubuntu@asus-pe100a:~/orig/ltp$
>>> ./testcases/kernel/syscalls/clone/clone10-i1000
>>> clone10.c:68:TPASS:Parent(PID: 158953,TID:158953): TLS value correct: 100
>>> clone10.c:48:TINFO:Child(PID: 158953,TID:159029): TLS value set to: 101
>>> tst_test.c:1953:TBROK:TestkilledbySIGSEGV!
>>> Summary:
>>> passed 75
>>> failed 0
>>> broken 1
>>> skipped 0
>>> warnings 0
>>> ```
>>> On 2/9/26 18:51, Petr Vorel wrote:
>>>> Hi Changwei,
>>>>> Allocate extra space before the TLS area to hold a struct pthread, ensuring
>>>>> THREAD_SELF->cancelhandling is initialized to 0. This prevents undefined
>>>>> behavior in __pthread_disable_asynccancel(), which is called at thread
>>>>> cancellation points such as write().
>>>>> Without this, touch_tls_in_child() could get stuck in tst_res().
>>>> LGTM, but I'd prefer others had a look on it.
>>>> Acked-by: Petr Vorel<pvorel@suse.cz>
>>>> BTW clone10.c segfaults w/a the patch when run with more iterations:
>>>> ./clone10 -i200
>>>> clone10.c:48: TINFO: Child (PID: 4271, TID: 4285): TLS value set to: 101
>>>> clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
>>>> clone10.c:48: TINFO: Child (PID: 4271, TID: 4286): TLS value set to: 101
>>>> clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
>>>> tst_test.c:1953: TBROK: Test killed by SIGSEGV!
>>>> Summary:
>>>> passed   15
>>>> failed   0
>>>> broken   1
>>>> skipped  0
>>>> warnings 0
>>>> Kind regards,
>>>> Petr
>>>>> (gdb) bt
>>>>>     0  futex_wait () at ../sysdeps/nptl/futex-internal.h:141
>>>>>     1  futex_wait_simple () at ../sysdeps/nptl/futex-internal.h:172
>>>>>     2  __libc_disable_asynccancel () at ../nptl/cancellation.c:100
>>>>>     3  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:26
>>>>>     4  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:24
>>>>>     5  print_result ()  at tst_test.c:387
>>>>>     6  tst_vres_ () at tst_test.c:401
>>>>>     7  tst_res_ () at tst_test.c:512
>>>>>     8  touch_tls_in_child (arg=<optimized out>)atclone10.c:48
>>>>>     9  thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
>>>>> Signed-off-by: Changwei Zou<changwei.zou@canonical.com>
>>>>> ---
>>>>>    include/lapi/tls.h | 16 +++++++++++++---
>>>>>    1 file changed, 13 insertions(+), 3 deletions(-)
>>>>> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
>>>>> index 468fe3086..7f2fa18a1 100644
>>>>> --- a/include/lapi/tls.h
>>>>> +++ b/include/lapi/tls.h
>>>>> @@ -22,6 +22,15 @@
>>>>>    #define TLS_SIZE 4096
>>>>>    #define TLS_ALIGN 16
>>>>> +/*
>>>>> + * Space allocated large enough to hold a struct pthread.
>>>>> + *
>>>>> + * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
>>>>> + * avoiding undefined behavior (e.g., in clone10.c) in __pthread_disable_asynccancel(),
>>>>> + * which is called at thread cancellation points such as write().
>>>>> + */
>>>>> +#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
>>>>> +
>>>>>    #if defined(__x86_64__)
>>>>>    typedef struct {
>>>>>    	void *tcb;
>>>>> @@ -36,10 +45,11 @@ extern void *tls_ptr;
>>>>>    static inline void *allocate_tls_area(void)
>>>>>    {
>>>>> -	void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
>>>>> +	char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
>>>>>    	if (!tls_area)
>>>>>    		tst_brk(TBROK | TERRNO, "aligned_alloc failed");
>>>>> -	memset(tls_area, 0, TLS_SIZE);
>>>>> +	memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
>>>>> +	tls_area += TLS_PRE_TCB_SIZE;
>>>>>    #if defined(__x86_64__)
>>>>>    	tcb_t *tcb = (tcb_t *)tls_area;
>>>>> @@ -59,7 +69,7 @@ static inline void free_tls(void)
>>>>>    {
>>>>>    	usleep(10000);
>>>>>    	if (tls_ptr) {
>>>>> -		free(tls_ptr);
>>>>> +		free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
>>>>>    		tls_ptr = NULL;
>>>>>    	}
>>>>>    }

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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-10 12:40         ` Changwei Zou via ltp
@ 2026-02-12  1:32           ` Changwei Zou via ltp
  2026-02-26  6:39             ` Li Wang via ltp
  0 siblings, 1 reply; 12+ messages in thread
From: Changwei Zou via ltp @ 2026-02-12  1:32 UTC (permalink / raw)
  To: Petr Vorel; +Cc: ltp

Hi Team,
With the following two patches (also available at 
https://github.com/sheisc/ltp.git),
I ran clone10 -i 1000000 on three machines (s390x, aarch64, and x86_64)
using different glibc versions (2.35, 2.31, and 2.39, respectively).
The test passed on all of these machines.
If you have any feedback or suggestions, please feel free to let me know.
Thank you very much.
Kind regards,
Changwei
// patch for clone10.c
```sh
$ gitdiffHEAD~1HEAD
diff 
--gita/testcases/kernel/syscalls/clone/clone10.cb/testcases/kernel/syscalls/clone/clone10.c
index 9ffb49c37..96de811ad100644
--- a/testcases/kernel/syscalls/clone/clone10.c
+++ b/testcases/kernel/syscalls/clone/clone10.c
@@ -20,6+20,7@@
#include "tst_test.h"
#include "clone_platform.h"
#include "lapi/syscalls.h"
+#include "tst_atomic.h"
#include "lapi/tls.h"
#define TLS_EXP 100
@@ -34,21+35,15@@structuser_desc*tls_desc;
static __threadinttls_var;
static char*child_stack;
-static volatileintchild_done;
+static tst_atomic_tchild_done;
static intflags=CLONE_THREAD| CLONE_VM | CLONE_FS | CLONE_FILES | 
CLONE_SIGHAND | CLONE_SETTLS;
static inttouch_tls_in_child(void *argLTP_ATTRIBUTE_UNUSED)
{
-#if defined(__x86_64__)
- if(syscall(SYS_arch_prctl, ARCH_SET_FS,tls_ptr) == -1)
- exit(EXIT_FAILURE);
-#endif
tls_var =TLS_EXP+1;
- tst_res(TINFO, "Child (PID: %d, TID: %d): TLS value set to: 
%d",getpid(),(pid_t)syscall(SYS_gettid),tls_var);
+ tst_atomic_store(1, &child_done);
- TST_CHECKPOINT_WAKE(0);
- free_tls();
tst_syscall(__NR_exit, 0);
return0;
}
@@ -56,13+51,16@@staticinttouch_tls_in_child(void *argLTP_ATTRIBUTE_UNUSED)
static voidverify_tls(void)
{
tls_var =TLS_EXP;
+ tst_atomic_store(0, &child_done);
TEST(ltp_clone7(flags, 
touch_tls_in_child,NULL,CHILD_STACK_SIZE,child_stack,NULL,tls_ptr,NULL));
if(TST_RET ==-1)
tst_brk(TBROK | TTERRNO, "clone() failed");
- TST_CHECKPOINT_WAIT(0);
+ while(tst_atomic_load(&child_done) == 0) {
+ usleep(10);
+ }
if(tls_var ==TLS_EXP) {
tst_res(TPASS,
@@ -84,6+82,7@@staticvoidsetup(void)
static voidcleanup(void)
{
free(child_stack);
+ free_tls();
}
static structtst_testtest={
```
// current patch for tls.h
```sh
$ gitdiffHEAD~2HEAD~1
diff --gita/include/lapi/tls.hb/include/lapi/tls.h
index 468fe3086..7f2fa18a1100644
--- a/include/lapi/tls.h
+++ b/include/lapi/tls.h
@@ -22,6+22,15@@
#define TLS_SIZE 4096
#define TLS_ALIGN 16
+/*
+ *Spaceallocatedlargeenoughtoholdastructpthread.
+ *
+ *Zero-initializedtoensureTHREAD_SELF->cancelhandlingstartsat0,
+ *avoidingundefinedbehavior(e.g., inclone10.c) in 
__pthread_disable_asynccancel(),
+ *whichiscalledatthreadcancellationpointssuchaswrite().
+ */
+#define TLS_PRE_TCB_SIZE(TLS_ALIGN *256)
+
#if defined(__x86_64__)
typedef struct{
void *tcb;
@@ -36,10+45,11@@externvoid*tls_ptr;
static inlinevoid*allocate_tls_area(void)
{
- void*tls_area=aligned_alloc(TLS_ALIGN, TLS_SIZE);
+ char*tls_area=aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE+TLS_SIZE);
if(!tls_area)
tst_brk(TBROK | TERRNO, "aligned_alloc failed");
- memset(tls_area, 0,TLS_SIZE);
+ memset(tls_area, 0,TLS_PRE_TCB_SIZE+TLS_SIZE);
+ tls_area+=TLS_PRE_TCB_SIZE;
#if defined(__x86_64__)
tcb_t *tcb=(tcb_t *)tls_area;
@@ -59,7+69,7@@staticinlinevoidfree_tls(void)
{
usleep(10000);
if(tls_ptr) {
- free(tls_ptr);
+ free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
tls_ptr = NULL;
}
}
```


On 2/10/26 23:40, Changwei Zou wrote:
> Hi Petr,
> I have rewritten the touch_tls_in_child() function and pushed it to my 
> GitHub account.
> https://github.com/sheisc/ltp
> The motivation was to avoid interacting with pthread’s memory model.
> I have tested it on both x86_64 and arm64.
> The command clone10 -i 100000 passed successfully on both platforms.
> Could you please take a look at it?
> Thank you very much.
> Kine regards,
> Changwei
> 1 On x86_64
> ```sh
> x86_64_ltp$ ./testcases/kernel/syscalls/clone/clone10-i100000
> clone10.c:66: TPASS:Parent(PID: 655699,TID:655699): TLS value correct: 100
> clone10.c:66: TPASS:Parent(PID: 655699,TID:655699): TLS value correct: 100
> Summary:
> passed 100000
> failed 0
> broken 0
> skipped 0
> warnings 0
> ```
> 2 On arm64
> ```sh
> arm64_ltp$ ./testcases/kernel/syscalls/clone/clone10-i100000
> clone10.c:66: TPASS:Parent(PID: 222184,TID:222184): TLS value correct: 100
> clone10.c:66: TPASS:Parent(PID: 222184,TID:222184): TLS value correct: 100
> Summary:
> passed 100000
> failed 0
> broken 0
> skipped 0
> warnings 0
> ```
>
>
> On 2/10/26 18:03, Changwei Zou wrote:
>> Hi Petr,
>> LTP uses glibc.
>> Even a simple library function like write(),
>> which wraps the sys_write system call,
>> is involved in the memory model of pthreads.
>> Therefore, touch_tls_in_child() must behave almost exactly like a 
>> pthread.
>> Otherwise, memory corruption can occur when executing functions 
>> inside glibc.
>> In the current version of clone10.c, according to the assembly code,
>> the statement tls_var = 0x65; already constitutes a buffer overflow 
>> on x86_64.
>> Unfortunately, the struct pthread is opaque and may vary between 
>> different versions of glibc.
>> I assume the purpose of clone10.c is to test whether the CLONE_SETTLS 
>> flag works.
>> Making touch_tls_in_child() behave exactly like a pthread, however, 
>> is extremely difficult.
>> static __thread int tls_var;
>> static int touch_tls_in_child(void *arg)
>> {
>> // 0xfffffffffffffffc is -4
>> // movl $0x65,%fs:0xfffffffffffffffc
>> tls_var = 0x65;
>> }
>> ```sh
>> (gdb) disassemble touch_tls_in_child
>> Dump ofassemblercodeforfunctiontouch_tls_in_child:
>> 0x000055555555be40 <+0>:endbr64
>> 0x000055555555be44 <+4>:push%rbx
>> 0x000055555555be45 <+5>:mov0x33c0c(%rip),%rdx# 0x55555558fa58 <tls_ptr>
>> 0x000055555555be4c <+12>:xor%eax,%eax
>> 0x000055555555be4e <+14>:mov$0x1002,%esi
>> 0x000055555555be53 <+19>:mov$0x9e,%edi
>> 0x000055555555be58 <+24>:call0x55555555b500<syscall@plt>
>> 0x000055555555be5d <+29>:cmp$0xffffffffffffffff,%rax
>> 0x000055555555be61 <+33>:je0x55555555bf1d<touch_tls_in_child+221>
>> 0x000055555555be67 
>> <+39>:movl$0x65,%fs:0xfffffffffffffffc//bufferoverflow?
>> ```
>> On 2/9/26 22:47, Petr Vorel wrote:
>>> Hi Changwei,
>>>
>>>> Hi Petr,
>>>> With the original upstream LTP,
>>>> I ran clone10 -i 1000 on three machines (including AArch64 and AMD64), and
>>>> it failed on all of them.
>>>> This suggests there may be another bug that we still need to identify.
>>> Yes, it's a separate bug, not relevant to your fix. I trigger it on x86_64.
>>>
>>> Kind regards,
>>> Petr
>>>
>>>> Thank you very much for your invaluable information.
>>>> Kind regards,
>>>> Changwei
>>>> *1. On an AArch64 cloud instance*
>>>> ```sh
>>>> azure@clone10-aarch64-kcp:~/orig/ltp$
>>>> ./testcases/kernel/syscalls/clone/clone10-i1000
>>>> clone10.c:68:TPASS:Parent(PID: 106163,TID:106163): TLS value correct: 100
>>>> clone10.c:48:TINFO:Child(PID: 106163,TID:106200): TLS value set to: 101
>>>> tst_test.c:1953:TBROK:TestkilledbySIGBUS!
>>>> Summary:
>>>> passed 36
>>>> failed 0
>>>> broken 1
>>>> skipped 0
>>>> warnings 0
>>>> ```
>>>> *2. On an AMD64 machine*
>>>> ```sh
>>>> ubuntu@ZBook:~/orig/ltp$ ./testcases/kernel/syscalls/clone/clone10-i1000
>>>> clone10.c:48:TINFO:Child(PID: 125560,TID:125870): TLS value set to: 101
>>>> clone10.c:68:TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
>>>> double freeorcorruption(out)
>>>> clone10.c:48:TINFO:Child(PID: 125560,TID:125871): TLS value set to: 101
>>>> clone10.c:68:TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
>>>> tst_test.c:1953:TBROK:TestkilledbySIGIOT/SIGABRT!
>>>> Summary:
>>>> passed 311
>>>> failed 0
>>>> broken 1
>>>> skipped 0
>>>> warnings 0
>>>> ```
>>>> *3. On an AArch64 machine*
>>>> ```sh
>>>> ubuntu@asus-pe100a:~/orig/ltp$
>>>> ./testcases/kernel/syscalls/clone/clone10-i1000
>>>> clone10.c:68:TPASS:Parent(PID: 158953,TID:158953): TLS value correct: 100
>>>> clone10.c:48:TINFO:Child(PID: 158953,TID:159029): TLS value set to: 101
>>>> tst_test.c:1953:TBROK:TestkilledbySIGSEGV!
>>>> Summary:
>>>> passed 75
>>>> failed 0
>>>> broken 1
>>>> skipped 0
>>>> warnings 0
>>>> ```
>>>> On 2/9/26 18:51, Petr Vorel wrote:
>>>>> Hi Changwei,
>>>>>> Allocate extra space before the TLS area to hold a struct pthread, ensuring
>>>>>> THREAD_SELF->cancelhandling is initialized to 0. This prevents undefined
>>>>>> behavior in __pthread_disable_asynccancel(), which is called at thread
>>>>>> cancellation points such as write().
>>>>>> Without this, touch_tls_in_child() could get stuck in tst_res().
>>>>> LGTM, but I'd prefer others had a look on it.
>>>>> Acked-by: Petr Vorel<pvorel@suse.cz>
>>>>> BTW clone10.c segfaults w/a the patch when run with more iterations:
>>>>> ./clone10 -i200
>>>>> clone10.c:48: TINFO: Child (PID: 4271, TID: 4285): TLS value set to: 101
>>>>> clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
>>>>> clone10.c:48: TINFO: Child (PID: 4271, TID: 4286): TLS value set to: 101
>>>>> clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
>>>>> tst_test.c:1953: TBROK: Test killed by SIGSEGV!
>>>>> Summary:
>>>>> passed   15
>>>>> failed   0
>>>>> broken   1
>>>>> skipped  0
>>>>> warnings 0
>>>>> Kind regards,
>>>>> Petr
>>>>>> (gdb) bt
>>>>>>     0  futex_wait () at ../sysdeps/nptl/futex-internal.h:141
>>>>>>     1  futex_wait_simple () at ../sysdeps/nptl/futex-internal.h:172
>>>>>>     2  __libc_disable_asynccancel () at ../nptl/cancellation.c:100
>>>>>>     3  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:26
>>>>>>     4  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:24
>>>>>>     5  print_result ()  at tst_test.c:387
>>>>>>     6  tst_vres_ () at tst_test.c:401
>>>>>>     7  tst_res_ () at tst_test.c:512
>>>>>>     8  touch_tls_in_child (arg=<optimized out>)atclone10.c:48
>>>>>>     9  thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
>>>>>> Signed-off-by: Changwei Zou<changwei.zou@canonical.com>
>>>>>> ---
>>>>>>    include/lapi/tls.h | 16 +++++++++++++---
>>>>>>    1 file changed, 13 insertions(+), 3 deletions(-)
>>>>>> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
>>>>>> index 468fe3086..7f2fa18a1 100644
>>>>>> --- a/include/lapi/tls.h
>>>>>> +++ b/include/lapi/tls.h
>>>>>> @@ -22,6 +22,15 @@
>>>>>>    #define TLS_SIZE 4096
>>>>>>    #define TLS_ALIGN 16
>>>>>> +/*
>>>>>> + * Space allocated large enough to hold a struct pthread.
>>>>>> + *
>>>>>> + * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
>>>>>> + * avoiding undefined behavior (e.g., in clone10.c) in __pthread_disable_asynccancel(),
>>>>>> + * which is called at thread cancellation points such as write().
>>>>>> + */
>>>>>> +#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
>>>>>> +
>>>>>>    #if defined(__x86_64__)
>>>>>>    typedef struct {
>>>>>>    	void *tcb;
>>>>>> @@ -36,10 +45,11 @@ extern void *tls_ptr;
>>>>>>    static inline void *allocate_tls_area(void)
>>>>>>    {
>>>>>> -	void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
>>>>>> +	char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
>>>>>>    	if (!tls_area)
>>>>>>    		tst_brk(TBROK | TERRNO, "aligned_alloc failed");
>>>>>> -	memset(tls_area, 0, TLS_SIZE);
>>>>>> +	memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
>>>>>> +	tls_area += TLS_PRE_TCB_SIZE;
>>>>>>    #if defined(__x86_64__)
>>>>>>    	tcb_t *tcb = (tcb_t *)tls_area;
>>>>>> @@ -59,7 +69,7 @@ static inline void free_tls(void)
>>>>>>    {
>>>>>>    	usleep(10000);
>>>>>>    	if (tls_ptr) {
>>>>>> -		free(tls_ptr);
>>>>>> +		free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
>>>>>>    		tls_ptr = NULL;
>>>>>>    	}
>>>>>>    }

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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-10  7:03       ` Changwei Zou via ltp
  2026-02-10 12:40         ` Changwei Zou via ltp
@ 2026-02-12  8:09         ` Petr Vorel
  2026-02-12  9:52           ` Changwei Zou via ltp
  1 sibling, 1 reply; 12+ messages in thread
From: Petr Vorel @ 2026-02-12  8:09 UTC (permalink / raw)
  To: Changwei Zou; +Cc: ltp

Hi Changwei,

> Hi Petr,
> LTP uses glibc.

Side note: *you* (and we in SUSE) use LTP with glibc. FYI other people use LTP
with musl (although few tests don't compile, see rm in ci/alpine.sh), uclibc-ng,
Google uses LTP with bionic. It's probably not relevant here (it's more about
kernel arch implementations than about libc), but just safer to mention LTP is
not glibc specific.

Kind regards,
Petr

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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-12  8:09         ` Petr Vorel
@ 2026-02-12  9:52           ` Changwei Zou via ltp
  0 siblings, 0 replies; 12+ messages in thread
From: Changwei Zou via ltp @ 2026-02-12  9:52 UTC (permalink / raw)
  To: Petr Vorel; +Cc: ltp

Hi Petr,
I couldn’t agree more: LTP is not glibc-specific.
“On the system I am evaluating, LTP uses glibc” would be a more precise 
way for me to put it.
I’ve learned a great deal from reading LTP’s source code and truly 
enjoyed the experience.
Thank you very much for the information.
Kind regards,
Changwei


On 2/12/26 19:09, Petr Vorel wrote:
> It's probably not relevant here (it's more about
> kernel arch implementations than about libc), but just safer to mention LTP is
> not glibc specific.

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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-12  1:32           ` Changwei Zou via ltp
@ 2026-02-26  6:39             ` Li Wang via ltp
  0 siblings, 0 replies; 12+ messages in thread
From: Li Wang via ltp @ 2026-02-26  6:39 UTC (permalink / raw)
  To: Changwei Zou; +Cc: ltp

Hi Changwei,

These two patches make sense, can you send another one separately to the
mailing list?

On Thu, Feb 12, 2026 at 9:33 AM Changwei Zou <changwei.zou@canonical.com>
wrote:

> Hi Team,
> With the following two patches (also available at
> https://github.com/sheisc/ltp.git),
> I ran clone10 -i 1000000 on three machines (s390x, aarch64, and x86_64)
> using different glibc versions (2.35, 2.31, and 2.39, respectively).
> The test passed on all of these machines.
> If you have any feedback or suggestions, please feel free to let me know.
> Thank you very much.
> Kind regards,
> Changwei
> // patch for clone10.c
> ```sh
> $ git diff HEAD~1 HEAD
> diff --git a/testcases/kernel/syscalls/clone/clone10.c
> b/testcases/kernel/syscalls/clone/clone10.c
> index 9ffb49c37..96de811ad 100644
> --- a/testcases/kernel/syscalls/clone/clone10.c
> +++ b/testcases/kernel/syscalls/clone/clone10.c
> @@ -20,6 +20,7 @@
> #include "tst_test.h"
> #include "clone_platform.h"
> #include "lapi/syscalls.h"
> +#include "tst_atomic.h"
> #include "lapi/tls.h"
> #define TLS_EXP 100
> @@ -34,21 +35,15 @@ struct user_desc *tls_desc;
> static __thread int tls_var;
> static char *child_stack;
> -static volatile int child_done;
> +static tst_atomic_t child_done;
> static int flags = CLONE_THREAD | CLONE_VM | CLONE_FS | CLONE_FILES |
> CLONE_SIGHAND | CLONE_SETTLS;
> static int touch_tls_in_child(void *arg LTP_ATTRIBUTE_UNUSED)
> {
> -#if defined(__x86_64__)
> - if (syscall(SYS_arch_prctl, ARCH_SET_FS, tls_ptr) == -1)
> - exit(EXIT_FAILURE);
> -#endif
> tls_var = TLS_EXP + 1;
> - tst_res(TINFO, "Child (PID: %d, TID: %d): TLS value set to: %d", getpid
> (), (pid_t)syscall(SYS_gettid), tls_var);
> + tst_atomic_store(1, &child_done);
> - TST_CHECKPOINT_WAKE(0);
> - free_tls();
> tst_syscall(__NR_exit, 0);
> return 0;
> }
> @@ -56,13 +51,16 @@ static int touch_tls_in_child(void *arg
> LTP_ATTRIBUTE_UNUSED)
> static void verify_tls(void)
> {
> tls_var = TLS_EXP;
> + tst_atomic_store(0, &child_done);
> TEST(ltp_clone7(flags, touch_tls_in_child, NULL, CHILD_STACK_SIZE,
> child_stack, NULL, tls_ptr, NULL));
> if (TST_RET == -1)
> tst_brk(TBROK | TTERRNO, "clone() failed");
> - TST_CHECKPOINT_WAIT(0);
> + while (tst_atomic_load(&child_done) == 0) {
> + usleep(10);
> + }
> if (tls_var == TLS_EXP) {
> tst_res(TPASS,
> @@ -84,6 +82,7 @@ static void setup(void)
> static void cleanup(void)
> {
> free(child_stack);
> + free_tls();
> }
> static struct tst_test test = {
> ```
> // current patch for tls.h
> ```sh
> $ git diff HEAD~2 HEAD~1
> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
> index 468fe3086..7f2fa18a1 100644
> --- a/include/lapi/tls.h
> +++ b/include/lapi/tls.h
> @@ -22,6 +22,15 @@
> #define TLS_SIZE 4096
> #define TLS_ALIGN 16
> +/*
> + * Space allocated large enough to hold a struct pthread.
> + *
> + * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
> + * avoiding undefined behavior (e.g., in clone10.c) in
> __pthread_disable_asynccancel(),
> + * which is called at thread cancellation points such as write().
> + */
> +#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
> +
> #if defined(__x86_64__)
> typedef struct {
> void *tcb;
> @@ -36,10 +45,11 @@ extern void *tls_ptr;
> static inline void *allocate_tls_area(void)
> {
> - void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
> + char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
> if (!tls_area)
> tst_brk(TBROK | TERRNO, "aligned_alloc failed");
> - memset(tls_area, 0, TLS_SIZE);
> + memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
> + tls_area += TLS_PRE_TCB_SIZE;
> #if defined(__x86_64__)
> tcb_t *tcb = (tcb_t *)tls_area;
> @@ -59,7 +69,7 @@ static inline void free_tls(void)
> {
> usleep(10000);
> if (tls_ptr) {
> - free(tls_ptr);
> + free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
> tls_ptr = NULL;
> }
> }
> ```
>
>
> On 2/10/26 23:40, Changwei Zou wrote:
>
> Hi Petr,
> I have rewritten the touch_tls_in_child() function and pushed it to my
> GitHub account.
> https://github.com/sheisc/ltp
> The motivation was to avoid interacting with pthread’s memory model.
> I have tested it on both x86_64 and arm64.
> The command clone10 -i 100000 passed successfully on both platforms.
> Could you please take a look at it?
> Thank you very much.
> Kine regards,
> Changwei
> 1 On x86_64
> ```sh
> x86_64_ltp$ ./testcases/kernel/syscalls/clone/clone10 -i 100000
> clone10.c:66: TPASS: Parent (PID: 655699, TID: 655699): TLS value
> correct: 100
> clone10.c:66: TPASS: Parent (PID: 655699, TID: 655699): TLS value
> correct: 100
> Summary:
> passed 100000
> failed 0
> broken 0
> skipped 0
> warnings 0
> ```
> 2 On arm64
> ```sh
> arm64_ltp$ ./testcases/kernel/syscalls/clone/clone10 -i 100000
> clone10.c:66: TPASS: Parent (PID: 222184, TID: 222184): TLS value
> correct: 100
> clone10.c:66: TPASS: Parent (PID: 222184, TID: 222184): TLS value
> correct: 100
> Summary:
> passed 100000
> failed 0
> broken 0
> skipped 0
> warnings 0
> ```
>
>
> On 2/10/26 18:03, Changwei Zou wrote:
>
> Hi Petr,
> LTP uses glibc.
> Even a simple library function like write(),
> which wraps the sys_write system call,
> is involved in the memory model of pthreads.
> Therefore, touch_tls_in_child() must behave almost exactly like a pthread.
> Otherwise, memory corruption can occur when executing functions inside
> glibc.
> In the current version of clone10.c, according to the assembly code,
> the statement tls_var = 0x65; already constitutes a buffer overflow on
> x86_64.
> Unfortunately, the struct pthread is opaque and may vary between different
> versions of glibc.
> I assume the purpose of clone10.c is to test whether the CLONE_SETTLS flag
> works.
> Making touch_tls_in_child() behave exactly like a pthread, however, is
> extremely difficult.
> static __thread int tls_var;
> static int touch_tls_in_child(void *arg)
> {
> // 0xfffffffffffffffc is -4
> // movl $0x65,%fs:0xfffffffffffffffc
> tls_var = 0x65;
> }
> ```sh
> (gdb) disassemble touch_tls_in_child
> Dump of assembler code for function touch_tls_in_child:
> 0x000055555555be40 <+0>: endbr64
> 0x000055555555be44 <+4>: push %rbx
> 0x000055555555be45 <+5>: mov 0x33c0c(%rip),%rdx # 0x55555558fa58 <tls_ptr>
> 0x000055555555be4c <+12>: xor %eax,%eax
> 0x000055555555be4e <+14>: mov $0x1002,%esi
> 0x000055555555be53 <+19>: mov $0x9e,%edi
> 0x000055555555be58 <+24>: call 0x55555555b500 <syscall@plt>
> 0x000055555555be5d <+29>: cmp $0xffffffffffffffff,%rax
> 0x000055555555be61 <+33>: je 0x55555555bf1d <touch_tls_in_child+221>
> 0x000055555555be67 <+39>: movl $0x65,%fs:0xfffffffffffffffc //buffer
> overflow ?
> ```
> On 2/9/26 22:47, Petr Vorel wrote:
>
> Hi Changwei,
>
>
> Hi Petr,
> With the original upstream LTP,
> I ran clone10 -i 1000 on three machines (including AArch64 and AMD64), and
> it failed on all of them.
>
> This suggests there may be another bug that we still need to identify.
>
> Yes, it's a separate bug, not relevant to your fix. I trigger it on x86_64.
>
> Kind regards,
> Petr
>
>
> Thank you very much for your invaluable information.
> Kind regards,
> Changwei
> *1. On an AArch64 cloud instance*
> ```sh
> azure@clone10-aarch64-kcp:~/orig/ltp$
> ./testcases/kernel/syscalls/clone/clone10-i1000clone10.c:68: TPASS:Parent(PID: 106163,TID:106163): TLS value correct: 100clone10.c:48: TINFO:Child(PID: 106163,TID:106200): TLS value set to: 101
> tst_test.c:1953: TBROK:TestkilledbySIGBUS!
> Summary:
> passed 36
> failed 0
> broken 1
> skipped 0
> warnings 0
> ```
> *2. On an AMD64 machine*
> ```sh
> ubuntu@ZBook:~/orig/ltp$ ./testcases/kernel/syscalls/clone/clone10-i1000clone10.c:48: TINFO:Child(PID: 125560,TID:125870): TLS value set to: 101clone10.c:68: TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
> double freeorcorruption(out)clone10.c:48: TINFO:Child(PID: 125560,TID:125871): TLS value set to: 101clone10.c:68: TPASS:Parent(PID: 125560,TID:125560): TLS value correct: 100
> tst_test.c:1953: TBROK:TestkilledbySIGIOT/SIGABRT!
> Summary:
> passed 311
> failed 0
> broken 1
> skipped 0
> warnings 0
> ```
> *3. On an AArch64 machine*
> ```sh
> ubuntu@asus-pe100a:~/orig/ltp$
> ./testcases/kernel/syscalls/clone/clone10-i1000clone10.c:68: TPASS:Parent(PID: 158953,TID:158953): TLS value correct: 100clone10.c:48: TINFO:Child(PID: 158953,TID:159029): TLS value set to: 101
> tst_test.c:1953: TBROK:TestkilledbySIGSEGV!
> Summary:
> passed 75
> failed 0
> broken 1
> skipped 0
> warnings 0
> ```
>
> On 2/9/26 18:51, Petr Vorel wrote:
>
> Hi Changwei,
>
> Allocate extra space before the TLS area to hold a struct pthread, ensuring
> THREAD_SELF->cancelhandling is initialized to 0. This prevents undefined
> behavior in __pthread_disable_asynccancel(), which is called at thread
> cancellation points such as write().
> Without this, touch_tls_in_child() could get stuck in tst_res().
>
> LGTM, but I'd prefer others had a look on it.
> Acked-by: Petr Vorel<pvorel@suse.cz> <pvorel@suse.cz>
>
> BTW clone10.c segfaults w/a the patch when run with more iterations:
>
> ./clone10 -i200clone10.c:48: TINFO: Child (PID: 4271, TID: 4285): TLS value set to: 101clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100clone10.c:48: TINFO: Child (PID: 4271, TID: 4286): TLS value set to: 101clone10.c:68: TPASS: Parent (PID: 4271, TID: 4271): TLS value correct: 100
> tst_test.c:1953: TBROK: Test killed by SIGSEGV!
>
> Summary:
> passed   15
> failed   0
> broken   1
> skipped  0
> warnings 0
>
> Kind regards,
> Petr
>
> (gdb) bt
>    0  futex_wait () at ../sysdeps/nptl/futex-internal.h:141
>    1  futex_wait_simple () at ../sysdeps/nptl/futex-internal.h:172
>    2  __libc_disable_asynccancel () at ../nptl/cancellation.c:100
>    3  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:26
>    4  __GI___libc_write () at ../sysdeps/unix/sysv/linux/write.c:24
>    5  print_result ()  at tst_test.c:387
>    6  tst_vres_ () at tst_test.c:401
>    7  tst_res_ () at tst_test.c:512
>    8  touch_tls_in_child (arg=<optimized out>) atclone10.c:48
>    9  thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone.S:78
> Signed-off-by: Changwei Zou<changwei.zou@canonical.com> <changwei.zou@canonical.com>
> ---
>   include/lapi/tls.h | 16 +++++++++++++---
>   1 file changed, 13 insertions(+), 3 deletions(-)
> diff --git a/include/lapi/tls.h b/include/lapi/tls.h
> index 468fe3086..7f2fa18a1 100644
> --- a/include/lapi/tls.h
> +++ b/include/lapi/tls.h
> @@ -22,6 +22,15 @@
>   #define TLS_SIZE 4096
>   #define TLS_ALIGN 16
> +/*
> + * Space allocated large enough to hold a struct pthread.
> + *
> + * Zero-initialized to ensure THREAD_SELF->cancelhandling starts at 0,
> + * avoiding undefined behavior (e.g., in clone10.c) in __pthread_disable_asynccancel(),
> + * which is called at thread cancellation points such as write().
> + */
> +#define TLS_PRE_TCB_SIZE (TLS_ALIGN * 256)
> +
>   #if defined(__x86_64__)
>   typedef struct {
>   	void *tcb;
> @@ -36,10 +45,11 @@ extern void *tls_ptr;
>   static inline void *allocate_tls_area(void)
>   {
> -	void *tls_area = aligned_alloc(TLS_ALIGN, TLS_SIZE);
> +	char *tls_area = aligned_alloc(TLS_ALIGN, TLS_PRE_TCB_SIZE + TLS_SIZE);
>   	if (!tls_area)
>   		tst_brk(TBROK | TERRNO, "aligned_alloc failed");
> -	memset(tls_area, 0, TLS_SIZE);
> +	memset(tls_area, 0, TLS_PRE_TCB_SIZE + TLS_SIZE);
> +	tls_area += TLS_PRE_TCB_SIZE;
>   #if defined(__x86_64__)
>   	tcb_t *tcb = (tcb_t *)tls_area;
> @@ -59,7 +69,7 @@ static inline void free_tls(void)
>   {
>   	usleep(10000);
>   	if (tls_ptr) {
> -		free(tls_ptr);
> +		free(((char *)tls_ptr) - TLS_PRE_TCB_SIZE);
>   		tls_ptr = NULL;
>   	}
>   }
>
>

-- 
Regards,
Li Wang

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

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

* Re: [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c
  2026-02-07 14:59 [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c Changwei Zou via ltp
  2026-02-09  7:51 ` Petr Vorel
@ 2026-02-26  7:56 ` Li Wang via ltp
  1 sibling, 0 replies; 12+ messages in thread
From: Li Wang via ltp @ 2026-02-26  7:56 UTC (permalink / raw)
  To: Changwei Zou; +Cc: ltp

This patch merged, thanks!

-- 
Regards,
Li Wang

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

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

end of thread, other threads:[~2026-02-26  7:57 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-07 14:59 [LTP] [PATCH] lapi/tls: reserve pre-TCB space to avoid undefined behavior in clone10.c Changwei Zou via ltp
2026-02-09  7:51 ` Petr Vorel
2026-02-09  9:42   ` Changwei Zou via ltp
2026-02-09 11:20   ` Changwei Zou via ltp
2026-02-09 11:47     ` Petr Vorel
2026-02-10  7:03       ` Changwei Zou via ltp
2026-02-10 12:40         ` Changwei Zou via ltp
2026-02-12  1:32           ` Changwei Zou via ltp
2026-02-26  6:39             ` Li Wang via ltp
2026-02-12  8:09         ` Petr Vorel
2026-02-12  9:52           ` Changwei Zou via ltp
2026-02-26  7:56 ` Li Wang via ltp

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