[PATCH v2 2/3] nptl: Add libc allocated shadow stack for new threads

Yury Khrustalev yury.khrustalev@arm.com
Tue Sep 9 13:58:55 GMT 2025


* Adhemerval et al.

On Mon, Sep 08, 2025 at 08:18:07AM -0300, Adhemerval Zanella Netto wrote:
> 
> On 05/09/25 14:55, Mark Brown wrote:
> > On Fri, Sep 05, 2025 at 02:22:46PM -0300, Adhemerval Zanella Netto wrote:
> > 
> >> So what is the advantage of extending clone3 to accept a map_shadow_stack
> >> stack if the idea is to not allow user re-use the allocated shadow guard
> >> region and forcing it to always deallocate it after thread finishes?
> > 
> > It is possible to switch between shadow stacks at runtime with no kernel
> > intervention, if a userspace is doing that then there is no guarantee
> > that the shadow stack in use at the time the thread exits is the same
> > one that the thread was started with.  Potentially a thread will be
> > started with a stack that was previously in use in another context.  You
> > either end up with userspace having to deallocate stacks when they're
> > finished with or having the kernel always allocate a stack and userspace
> > pivot off that if it wants something else.
> 
> But this is not the usual programming mode for pthread code, and in places
> glibc does it (makecontext) it leaks the allocate shadow stack anyway.  I
> can't not say much what other runtime might do wrt shadow stack management,
> or if users will mess with stack pointer along with pthread; but in either
> cases it seems that the shadow stack management is out of scope of the C
> runtime.
> 
> So maybe if clone3 just allows to setup the expected shadow stack size instead
> of requiring C runtime to manage the shadow stack itself would be a 
> more straightforward interface to use along pthread.

So, if I understand correctly, to re-use shadow stack mapping after some
thread that was using it exits, we would need to re-initialise it.
Initially, the correctly initialised mapping comes from the call to
map_shadow_stack(). After stack started using this mapping, it's no
longer usable (by design). So, kernel needs to restore the data in this
mapping before we can give it to another thread. Currently, this is not
done however this can be implemented later and clone3() interface does
not depend on it.

On the glibc side we can check if the shadow stack is "restored" after a
thread exists, and if it is, we would put it in the cache to be picked
up later. Then on the pthread_create() side we'd check if there are any
shadow stacks in the cache and use one if it's there.

Naturally, some kernels might support "shadow stack restoring" and some
won't, and glibc would be able to re-use shadow stacks only if the
kernel supports it. However, the interface around clone3(), which
includes original allocation if a shadow stack on the glibc side, would
not need to be changed and we can make some progress.

Would this solution be acceptable?

Thanks,
Yury



More information about the Libc-alpha mailing list