On Tue, 2026-08-04 at 15:43 -0500, Bill Roberts wrote: > > IIRC CRIU needed to unlock shadow stack during the save. Because it's tricks > > for > > saving the process involved messing with the stack. So it needs to be able > > to > > unlock but *only* via ptrace. Apps cannot be allowed to unlock themselves. > > Because, well, obviously.. > > > > As MUSL and > > others get patches, it would be much simpler to have one interface to do > > this in, and right now > > unlock is unused (even in the test suite :-p). > > I think I raised this on the other arch's APIs originally. x86 went first, > > and then later arm/riscv wanted a unified approach, but didn't solve this > > ptrace unlock part. So we didn't join. AFAICT the situation hasn't changed. > > So I'm worried it's too soon to unify. Or we might need to do multiple steps > > of unifications. > > At this point, the only remaining semantic difference is support for > unlocking a locked shadow stack during ptrace/CRIU restore. Arm64 and RISC-V > don't currently expose a generic unlock operation because they use > architecture-specific ptrace mechanisms for state restoration. If those > architectures eventually converge on a common unlock model for CRIU, I think > it would make sense to unify that interface as well. Until then, I don't think > the lack of a generic unlock should prevent unifying the parts of the ABI that > already have equivalent semantics. Especially considering how it unifies the > loader/libc side of the house.
The locking needs to be done after the linked DSOs are checked for shadow stack compatibility. > > > Also looking forward to understanding the security module problem > > statement better. > > Right now all the controls are opt in, and requires support in glibc, via > per arch tunable flags for both enabling and locking. x86 glibc was originally supposed to have two modes for shadow stack. A normal mode and a permissive mode. The normal mode would first check all the ldd DSOs for shadow stack compatibility. If they all have shadow stack, it enables shadow stack and does the lock on the main thread, which then gets inherited by all the child tasks. If dlopen() is later made with a DSO that does not shadow stack, the dlopen() call is failed. In permissive mode, it did the enablement checks like the normal mode, except it did not lock shadow stack. Then if dlopen() call was made with a non supporting DSO, it would disable shadow stack on the calling thread. This didn't really work, because the other threads in the app still had shadow stack enabled. Why didn't it just disable it shadow stack for the full app? Lots of races with apps doing shadow stack specific stuff while the support gets disabled out from under them. To fix permissive mode, there was a proposal (I don't know if it ever made it into glibc) where the shadow stack would get disabled on the first dlopen() to a non-compatible shadow stack OR the first thread was spawned. This was questionable to me. But there was a desire to minimize the compatibility hit first so it could be enabled widely. Then tighten it up over time. But in any case, lock is still needed for the normal mode right? You need to decide in the loader whether you want to have shadow stack for the app. Or we are talking about another mode, like a forced-on mode where the app will do something else if it finds the linked DSOs don't support shadow stack. Like exit with an error or something. But if that's the case, it's a decent amount of new stuff to me, so please explain. > The glibc folks are > starting to balk at the amount of flags. Additionally, it would be nice to > have MAC controls on them, and the best way for that is via LSM into > SE Linux. Normal applications can be placed in a domain where > they can never remove protections, and things like CRIU will have these > elevated > perms, if they are ever needed, since right now they go through a > different channel. This sounds like a new paradigm. If we have enough shadow stack support out there, seems interesting to me. But I would like to hear more details about how it works. I'm just speculating above. > The LSM actually removes the need for lock flags in essence, but yeah we > can't count > on that. ? > The lore is here: > https://sourceware.org/pipermail/libc-alpha/2025-December/173636.html This seems to be about other shadow stack knobs. Stack size, etc. > > For the following LSM piece, there is no hard dependency on this. I can > put the LSM hooks into arch_prctl for x86 and things would work fine, in fact > there is no getting around that or the arch_prctl interface for x86 wouldn't > get the LSM protections. I want x86 to get the LSM protections. I also want to > coalesce what we can around the around the current generic interfaces for > glibc. Work could be done there to start dropping arch tunables around this > too. I am sitting on these patches right now, because they have a soft > dependency on conflicts. > > > > Ill spin out a v2 with the comments, but the one thing left to be > > > addressed, afaik, is the testing patch > > > do you want that? I'll drop it, but I think that's a bad approach. > > Yea, I hear your point. It is good to test more, but #including c files with > > pre-processor switches seems too hacky. Is there anything we could do to > > make it > > in one c file? Like not the templated tricks to generate two test binaries? > > For > > example embed the switch between the two APIs in a macros in the single > > file. > > Like say we have SHSTK_ENABLE(). Inside it does either ARCH_PRCTL() or > > regular. > > Then have a global or something that switches between the two behaviors. > > Pull > > out the parts in main() into something that could be run twice? > > > Anything is possible, but is the juice worth the squeeze here? This > approach is used > already in tree: > - bpf/progs/arena_htab_asm.c > - bpf/progs/test_cls_redirect_subprogs.c > - bpf/progs/test_sk_assign_libbpf.c > - kvm/lib/rbtree.c > - kvm/rseq_test.c > - livepatch/test_modules/test_klp_state3.c > - powerpc/vphn/test-vphn.c > - x86/test_shadow_stack_prctl.c Uhh... that is your own changes. :) > > I am generally a fan of doing the simplest, most obvious thing first > that follows existing conventions > unless a really big reason can be made to not do it. I can refactor it > if it's a show stopper, but IMHO > not worth it here. But if you want it refactored, sure. We'll we can leave it to x86 maintainers to weigh in on the style thing. I don't like it, but won't throw a fit.

