[LTP] clone10.c failed on 32bit compilation
Li Wang
liwang@redhat.com
Wed Jan 21 08:25:42 CET 2026
Wei Gao <wegao@suse.com> wrote:
> > Well, this indicates that the Child does not switch to itself TLS
> > correctly, still use the parent, and so the '__thread tls_var' value
> > gets modified.
> >
> > With two days of research, I roughly drew the picture of the possible
> > reason as below:
> >
> > Using a naked clone() to verify that CLONE_SETTLS is unreliable
> > when running 32-bit on x86_64, since i386 TLS requires two steps:
> > writing the descriptor and switching the selector, but CLONE_SETTLS
> > only overrides the former:
> >
> > This is the simplified call chain:
> >
> > 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, 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.
> >
> > In summary, if this analysis is make sense, we need to configure the TCONF
> > test branch skip on i386.
>
> Your analysis is correct when we use 13 as tls_desc->entry_number. If we
> not change kernel logic (force switch child's %gs to poing gdt 13 entry then
> we can not test this feature).
When we allocate a new TLS entry (e.g., 13) and don’t actually
switch %gs to it, that's not breaking anything, user space continues
to run with the original %gs, so it survives.
> So correct solution is not create new GDT TLS entry but reuse exist
No, we shouldn't do this for clone10.
The purpose of clone10 is to test that the cloned child process will
create a new TLS are and verify that it is different from the parent's.
> entry, by default parent will use GDT_ENTRY_TLS_MIN which number is 12.
> So we clone with tls_desc->entry_number to 12 and ONLY change
> tls_desc->base_addr, when switch to child %gs still same but GDT
> number 12 entry already updated by new base_addr. But now i encounter strange
> SIGSEGV error when switch to child, no idea why.
If you reuse the currently active entry (often 12) and change only
the descriptor base, you are effectively changing GS.base while keeping
%gs the same. That means all existing TLS references now land at a
different base, almost certainly not a valid TCB, so you crash quickly.
> BTW: if we use pure 32bit we should resuse entry_number to 6, so basicly
> in code we should first use __NR_get_thread_area get currently using
> entry_number.
>
> I agree we can skip test on i386 firstly since we are currently still not support
> in this test case.
--
Regards,
Li Wang
More information about the ltp
mailing list