On Thu, Sep 25, 2025 at 11:58:01PM +0000, Edgecombe, Rick P wrote:
On Fri, 2025-09-26 at 00:22 +0100, Mark Brown wrote:
I think those were around the use of alt stacks, which we don't currently do for shadow stacks at all because we couldn't figure out those edge cases. Possibly there's others as well, though - the alt stacks issues dominated discussion a bit.
For longjmp, IIRC there were some plans to search for a token on the target stack and use it, which seems somewhat at odds with the quick efficient jump that longjmp() gets usually used for. But it also doesn't solve the problem of taking a signal while you are unwinding.
Yeah, that all seemed very unclear to me.
Like say you do calls all the way to the end of a shadow stack, and it's about to overflow. Then the thread swaps to another shadow stack. If you longjmp back to the original stack you will have to transition to the end of the first stack as you unwind. If at that point the thread gets a signal, it would overflow the shadow stack. This is a subtle difference in behavior compared to non-shadow stack. You also need to know that nothing else could consume that token on that stack in the meantime. So doing it safely is not nearly as simple as normal longjmp().
Anyway, I think you don't need alt shadow stack to hit that. Just normal userspace threading?
Ah, the backtrack through a pivot case - yes, I don't think anyone had a good story for how that was going to work sensibly without making the stack writable. Sorry, I'd written off that case as entirely so it didn't cross my mind.
As far as re-using allocated shadow stacks, there is always the option to enable WRSS (or similar) to write the shadow stack as well as longjmp at will.
That's obviously a substantial downgrade in security though.
I don't know about substantial, but I'd love to hear some offensive security persons analysis. There definitely was a school of thought though, that shadow stack should be turned on as widely as possible. If we need WRSS to make that happen in a sane way, you could argue there is sort of a security at scale benefit.
I agree it seems clearly better from a security point of view to have writable shadow stacks than none at all, I don't think there's much argument there other than the concerns about the memory consumption and performance tradeoffs.
But for automatic thread created shadow stacks, there is no need to allow userspace to unmap a shadow stack, so the automatically created stacks could simply be msealed on creation and unmapped from the kernel. For a lot of apps (most?) this would work perfectly fine.
Indeed, we should be able to just do that if we're mseal()ing system mappings I think - most likely anything that has a problem with it probably already has a problem the existing mseal() stuff. Yet another reason we should be factoring more of this code out into the generic code, like I say I'll try to look at that.
Agree. But for the mseal stuff, I think you would want to have map_shadow_stack not available.
That seems like something userspace could enforce with existing security mechanisms? I can imagine a system might want different policies for different programs.
I think the important thing from a kernel ABI point of view is to give userspace the tools to do whatever it wants and get out of the way, and that ideally this should include options that don't just make the shadow stack writable since that's a substantial step down in protection.
Yes I hear that. But also try to avoid creating maintenance issues by adding features that didn't turn out to be useful. It sounds like we agree that we need more proof that this will work out in the long run.
Yes, we need at least some buy in from userspace.
That said your option 2 is already supported with the existing clone3() on both arm64 and x86_64, policy for switching between that and kernel managed stacks could be set by restricting the writable stacks flag on the enable prctl(), and/or restricting map_shadow_stack().
You mean userspace could already re-use shadow stacks if they enable writable shadow stacks? Yes I agree.
Yes, exactly.
This RFC seems to be going down the path of addressing one edge case at a time. Alone it's fine, but I'd rather punt these types of usages to (2) by default.
For me this is in the category of "oh, of course you should be able to do that" where it feels like an obvious usability thing than an edge case.
True. I guess I was thinking more about the stack unwinding. Badly phrased, sorry.
I'm completely with you on stack unwinding over pivot stuff, I wasn't imagining we could address that. There's so many landmines there that we'd need a super solid story before doing anything specific to that case.