[PATCH v2 2/3] nptl: Add libc allocated shadow stack for new threads
Mark Brown
broonie@kernel.org
Wed Sep 3 20:46:17 GMT 2025
On Wed, Sep 03, 2025 at 04:46:47PM -0300, Adhemerval Zanella Netto wrote:
> There is currently no logic to resize the thread cache; it only adjusts the
> guarded control stack as needed. Remapping would defeat the cache’s main
> benefit, since allocating a new stack is typically faster (and, in cases
> where virtual memory area constraints are significant, users can already
> limit the cache size).
Note that you need a token on the shadow stack so reuse of an already
used one is perhaps more trouble to arrange than it's worth for glibc.
The security requirements do result in some overhead.
> As a side-note, things would be a lot more straightforward if userland could
> simply allocate a region such as [stack + guard control stack], and the kernel
> offered an API (e.g., via `madvise`) to establish the control-guarded region.
That was discussed as part of the API design when the x86 shadow stack
support was being merged, from what I remember of reading the discussion
people weren't very happy with the security issues surrounding being
able to madvise() existing blocks of memory to be shadow stacks due to
the ease with which race conditions or other bugs could be introduced.
This is especially true given the need to place a token in the shadow
stack, something needs to place the token and half the goal is that
userspace can't write to the shadow stack.
If you're willing to take an extra syscall anyway then map_shadow_stack()
can take an address as an argument so you can control placement, you
just have to call it on an unmapped region (though I suspect you're
thinking of working from an already mapped block of memory so that
doesn't work).
> Alternatively, if `clone3` itself allowed definition of the guard region start,
> this could be exposed. My understanding is that the guarded region is intended
> to prevent all writes except specific GCS operations, effectively acting as a
> guard page.
The GCS/shadow stack is normally only writable by userspace through
procedure call and return instructions or explicit stack pivot
instructions.
An older version of the clone3() ABI did specify the shadow stack as a
base and size like we do for the regular stack. We could I guess do
that and also do the allocation, though that'd be inconsistent with the
way we handle the regular stack and we'd also have flags like we do in
map_shadow_stack() to allow for configuration of the optional top of
stack marker and anything else that comes up in future. You'd have to
handle the case where something, potentially something mapped with
map_shadow_stack(), is already there. It *does* save a syscall but I'm
having a hard time loving it, there's a bunch of stuff to get right
there and it's not terribly well aligned with the regular stack.
You could also just specify the size then have the kernel manage the
allocation and free like it does for regular clone(), the main goal here
is to allow userspace to control the size. However I suspect that there
will be users that do want to control the placement for whatever reason
(eg, spawning a real thread for an existing userspace thread).
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20250903/7d9dc926/attachment.sig>
More information about the Libc-alpha
mailing list