* [PATCH 0/3] x86/shstk: ban ia32 sigreturn
@ 2026-10-08 20:16 Richard Patel
2026-10-08 20:16 ` [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled Richard Patel
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Richard Patel @ 2026-10-08 20:16 UTC (permalink / raw)
To: Rick Edgecombe, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86
Cc: H . Peter Anvin, Kees Cook, Shuah Khan, linux-kernel,
linux-kselftest, Richard Patel
User shadow stacks protect only the x64 and x32 rt_sigreturn syscalls.
Calling ia32 rt_sigreturn, which lacks return address validation, is
still possible via `int $0x80`. The bypass also requires the executable
is mapped into low 32-bit address space. (This scenario is basically
impossible to occur in the wild, but it's probably worth fixing
nonetheless.)
Since user shadow stacks explicitly only support 64-bit mode, the
simplest fix is to fault attempts to do 32-bit rt_sigreturn.
Richard Patel (3):
x86/shstk: ban ia32 sigreturn when shadow stack is enabled
selftests/x86: test shadow stack sigreturn protection
selftests/x86: skip shstk tests where perf_event_open() fails
arch/x86/kernel/signal_32.c | 4 +
.../testing/selftests/x86/test_shadow_stack.c | 120 +++++++++++++++++-
2 files changed, 122 insertions(+), 2 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled
2026-10-08 20:16 [PATCH 0/3] x86/shstk: ban ia32 sigreturn Richard Patel
@ 2026-10-08 20:16 ` Richard Patel
2026-10-08 20:59 ` Edgecombe, Rick P
2026-10-08 20:16 ` [PATCH 2/3] selftests/x86: test shadow stack sigreturn protection Richard Patel
` (2 subsequent siblings)
3 siblings, 1 reply; 13+ messages in thread
From: Richard Patel @ 2026-10-08 20:16 UTC (permalink / raw)
To: Rick Edgecombe, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86
Cc: H . Peter Anvin, Kees Cook, Shuah Khan, linux-kernel,
linux-kselftest, Richard Patel
When returning from a signal via x32 or x64 rt_sigreturn, the
shadow-stack-restore token is validated, but ia32 (rt_)sigreturn
do not call restore_signal_shadow_stack().
With IA32_EMULATION, 'int $0x80' allows ia32 sigreturn in 64-bit
mode, which could defeat sigreturn protection.
Refuse ia32 sigreturn by forcing a SIGSEGV instead.
Fixes: 05e36022c054 ("x86/shstk: Handle signals for shadow stack")
Signed-off-by: Richard Patel <ripatel@wii.dev>
---
arch/x86/kernel/signal_32.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index 8e87ab586437..a28e750b4e6d 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -32,6 +32,7 @@
#include <asm/sighandling.h>
#include <asm/smap.h>
#include <asm/gsseg.h>
+#include <asm/shstk.h>
/*
* The first GDT descriptor is reserved as 'NULL descriptor'. As bits 0
@@ -109,6 +110,9 @@ static bool ia32_restore_sigcontext(struct pt_regs *regs,
{
struct sigcontext_32 sc;
+ if (shstk_is_enabled())
+ return false;
+
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/3] selftests/x86: test shadow stack sigreturn protection
2026-10-08 20:16 [PATCH 0/3] x86/shstk: ban ia32 sigreturn Richard Patel
2026-10-08 20:16 ` [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled Richard Patel
@ 2026-10-08 20:16 ` Richard Patel
2026-10-08 20:16 ` [PATCH 3/3] selftests/x86: skip shstk tests where perf_event_open() fails Richard Patel
2026-10-08 21:00 ` [PATCH 0/3] x86/shstk: ban ia32 sigreturn Edgecombe, Rick P
3 siblings, 0 replies; 13+ messages in thread
From: Richard Patel @ 2026-10-08 20:16 UTC (permalink / raw)
To: Rick Edgecombe, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86
Cc: H . Peter Anvin, Kees Cook, Shuah Khan, linux-kernel,
linux-kselftest, Richard Patel
Check that a crafted signal frame return address (rip) is rejected
by rt_sigreturn when shadow stack is enabled. Test both 'syscall'
and 'int $0x80' (CONFIG_IA32_EMULATION) with and without SHSTK.
Signed-off-by: Richard Patel <ripatel@wii.dev>
---
.../testing/selftests/x86/test_shadow_stack.c | 110 ++++++++++++++++++
1 file changed, 110 insertions(+)
diff --git a/tools/testing/selftests/x86/test_shadow_stack.c b/tools/testing/selftests/x86/test_shadow_stack.c
index 3d6ca33edba4..67baebbdbd87 100644
--- a/tools/testing/selftests/x86/test_shadow_stack.c
+++ b/tools/testing/selftests/x86/test_shadow_stack.c
@@ -735,6 +735,110 @@ int test_32bit(void)
return !segv_triggered;
}
+/*
+ * Fork and sigreturn with a crafted signal frame.
+ * Returns the child's exit code, or 0x100+signal if it was killed.
+ */
+static int crafted_sigreturn(unsigned long sp, bool ia32, bool shstk)
+{
+ int status;
+ pid_t pid;
+
+ pid = fork();
+ if (!pid) {
+ signal(SIGSEGV, SIG_DFL);
+ if (ARCH_PRCTL(shstk ? ARCH_SHSTK_ENABLE : ARCH_SHSTK_DISABLE,
+ ARCH_SHSTK_SHSTK))
+ _exit(1);
+ if (ia32) /* ia32 rt_sigreturn */
+ asm volatile("movq %0, %%rsp; int $0x80; ud2"
+ : : "r" (sp), "a" (173));
+ else /* rt_sigreturn */
+ asm volatile("movq %0, %%rsp; syscall; ud2"
+ : : "r" (sp), "a" (__NR_rt_sigreturn));
+ __builtin_unreachable();
+ }
+
+ if (pid < 0 || waitpid(pid, &status, 0) != pid)
+ return -1;
+ return WIFSIGNALED(status) ? 0x100 + WTERMSIG(status) : WEXITSTATUS(status);
+}
+
+struct rt_sigframe_ia32 {
+ uint32_t pretcode, sig, pinfo, puc;
+ uint8_t info[128];
+ uint32_t uc_flags, uc_link, ss_sp, ss_flags, ss_size;
+ uint16_t gs, __gsh, fs, __fsh, es, __esh, ds, __dsh;
+ uint32_t di, si, bp, sp, bx, dx, cx, ax, trapno, err, ip;
+ uint16_t cs, __csh;
+ uint32_t flags, sp_at_signal;
+ uint16_t ss, __ssh;
+ uint32_t fpstate, oldmask, cr2;
+ uint32_t uc_sigmask[2];
+ uint8_t retcode[8];
+};
+
+_Static_assert(sizeof(struct rt_sigframe_ia32) == 268, "ia32 rt_sigframe layout");
+
+/* This tests whether shadow stack protects sigreturn */
+int test_sigreturn(void)
+{
+ static const uint8_t target_routine[] = {
+ 0xbf, 0x2a, 0x00, 0x00, 0x00, /* mov $42, %edi */
+ 0xb8, 0xe7, 0x00, 0x00, 0x00, /* mov $231, %eax (exit_group) */
+ 0x0f, 0x05, /* syscall */
+ };
+
+ struct { uint64_t pretcode; ucontext_t uc; } *f64;
+ struct rt_sigframe_ia32 *f32;
+ void *retsite;
+ int ret = 1;
+
+ /* ia32 sigreturn truncates RIP and RSP to 32 bits */
+ retsite = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_32BIT | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (retsite == MAP_FAILED)
+ return 1;
+ memcpy(retsite, target_routine, sizeof(target_routine));
+
+ f64 = retsite + 0x100;
+ f64->uc.uc_mcontext.gregs[REG_RIP] = (unsigned long)retsite;
+ f64->uc.uc_mcontext.gregs[REG_RSP] = (unsigned long)retsite + PAGE_SIZE;
+ f64->uc.uc_mcontext.gregs[REG_CSGSFS] = 0x33; /* __USER_CS */
+
+ f32 = retsite + 0x800;
+ f32->ip = (unsigned long)retsite;
+ f32->sp = (unsigned long)retsite + PAGE_SIZE;
+ f32->cs = 0x33; /* __USER_CS (64-bit) */
+ f32->ss = 0x2b; /* __USER_DS */
+
+ if (crafted_sigreturn((unsigned long)f64 + 8, false, false) != 42) {
+ printf("[FAIL]\trt_sigreturn protection (hijack failed without shadow stack)\n");
+ goto out;
+ }
+ if (crafted_sigreturn((unsigned long)f64 + 8, false, true) != 0x100 + SIGSEGV) {
+ printf("[FAIL]\trt_sigreturn protection\n");
+ goto out;
+ }
+ printf("[OK]\trt_sigreturn protection\n");
+
+ if (crafted_sigreturn((unsigned long)f32 + 4, true, false) != 42) {
+ printf("[SKIP]\tia32 rt_sigreturn protection (int $0x80 unavailable)\n");
+ ret = 0;
+ goto out;
+ }
+ if (crafted_sigreturn((unsigned long)f32 + 4, true, true) != 0x100 + SIGSEGV) {
+ printf("[FAIL]\tia32 rt_sigreturn protection\n");
+ goto out;
+ }
+ printf("[OK]\tia32 rt_sigreturn protection\n");
+ ret = 0;
+
+out:
+ munmap(retsite, PAGE_SIZE);
+ return ret;
+}
+
static int parse_uint_from_file(const char *file, const char *fmt)
{
int err, ret;
@@ -1145,6 +1249,12 @@ int main(int argc, char *argv[])
goto out;
}
+ if (test_sigreturn()) {
+ ret = 1;
+ printf("[FAIL]\tsigreturn test\n");
+ goto out;
+ }
+
if (test_uretprobe()) {
ret = 1;
printf("[FAIL]\turetprobe test\n");
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/3] selftests/x86: skip shstk tests where perf_event_open() fails
2026-10-08 20:16 [PATCH 0/3] x86/shstk: ban ia32 sigreturn Richard Patel
2026-10-08 20:16 ` [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled Richard Patel
2026-10-08 20:16 ` [PATCH 2/3] selftests/x86: test shadow stack sigreturn protection Richard Patel
@ 2026-10-08 20:16 ` Richard Patel
2026-10-08 21:00 ` [PATCH 0/3] x86/shstk: ban ia32 sigreturn Edgecombe, Rick P
3 siblings, 0 replies; 13+ messages in thread
From: Richard Patel @ 2026-10-08 20:16 UTC (permalink / raw)
To: Rick Edgecombe, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86
Cc: H . Peter Anvin, Kees Cook, Shuah Khan, linux-kernel,
linux-kselftest, Richard Patel
perf_event_open() without caps fails with EACCES on some kernels.
With this fix, the shadow stack selftest passes without privileges
on a kernel with a RHEL-like config.
Signed-off-by: Richard Patel <ripatel@wii.dev>
---
tools/testing/selftests/x86/test_shadow_stack.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/x86/test_shadow_stack.c b/tools/testing/selftests/x86/test_shadow_stack.c
index 67baebbdbd87..e2340232a7b6 100644
--- a/tools/testing/selftests/x86/test_shadow_stack.c
+++ b/tools/testing/selftests/x86/test_shadow_stack.c
@@ -952,8 +952,11 @@ static int test_uretprobe(void)
fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */, -1 /* cpu */,
-1 /* group_fd */, PERF_FLAG_FD_CLOEXEC);
- if (fd < 0)
+ if (fd < 0) {
+ printf("[SKIP]\tUretprobe test, perf_event_open() failed: %m\n");
+ err = 0;
goto out;
+ }
if (sigsetjmp(jmp_buffer, 1))
goto out;
@@ -1031,8 +1034,11 @@ static int test_uprobe_call(void)
fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */, -1 /* cpu */,
-1 /* group_fd */, PERF_FLAG_FD_CLOEXEC);
- if (fd < 0)
+ if (fd < 0) {
+ printf("[SKIP]\tUprobe on CALL test, perf_event_open() failed: %m\n");
+ err = 0;
goto out;
+ }
if (sigsetjmp(jmp_buffer, 1))
goto out;
--
2.52.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled
2026-10-08 20:16 ` [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled Richard Patel
@ 2026-10-08 20:59 ` Edgecombe, Rick P
2026-10-08 21:50 ` Richard Patel
0 siblings, 1 reply; 13+ messages in thread
From: Edgecombe, Rick P @ 2026-10-08 20:59 UTC (permalink / raw)
To: x86@kernel.org, mingo@redhat.com, ripatel@wii.dev,
tglx@kernel.org, bp@alien8.de, dave.hansen@linux.intel.com
Cc: hpa@zytor.com, kees@kernel.org, shuah@kernel.org,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org
On Thu, 2026-10-08 at 20:16 +0000, Richard Patel wrote:
> When returning from a signal via x32 or x64 rt_sigreturn, the
> shadow-stack-restore token is validated, but ia32 (rt_)sigreturn
> do not call restore_signal_shadow_stack().
>
> With IA32_EMULATION, 'int $0x80' allows ia32 sigreturn in 64-bit
> mode, which could defeat sigreturn protection.
>
> Refuse ia32 sigreturn by forcing a SIGSEGV instead.
How can it defeat protection? If doesn't process the shadow stack sigframe at
all, leaving the SSP where ever it was originally. What am I missing?
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/3] x86/shstk: ban ia32 sigreturn
2026-10-08 20:16 [PATCH 0/3] x86/shstk: ban ia32 sigreturn Richard Patel
` (2 preceding siblings ...)
2026-10-08 20:16 ` [PATCH 3/3] selftests/x86: skip shstk tests where perf_event_open() fails Richard Patel
@ 2026-10-08 21:00 ` Edgecombe, Rick P
3 siblings, 0 replies; 13+ messages in thread
From: Edgecombe, Rick P @ 2026-10-08 21:00 UTC (permalink / raw)
To: x86@kernel.org, mingo@redhat.com, ripatel@wii.dev,
tglx@kernel.org, bp@alien8.de, dave.hansen@linux.intel.com
Cc: hpa@zytor.com, kees@kernel.org, shuah@kernel.org,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org
On Thu, 2026-10-08 at 20:16 +0000, Richard Patel wrote:
> (This scenario is basically
> impossible to occur in the wild, but it's probably worth fixing
> nonetheless.)
The original purpose of limiting it at all vs just leaving it unimplemented was
to not have to think through the implications. Since there was an easy way to
dissuade almost all usage, it was closed. If it will require plugging a bunch of
loose ends then I think the cost/benefit needs to be revisited.
I'd also wonder if we couldn't do a shadow stack check in do_int80_emulation()
vs for each syscall that might grow shadow stack behavior someday.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled
2026-10-08 20:59 ` Edgecombe, Rick P
@ 2026-10-08 21:50 ` Richard Patel
2026-10-08 22:34 ` Edgecombe, Rick P
0 siblings, 1 reply; 13+ messages in thread
From: Richard Patel @ 2026-10-08 21:50 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: x86@kernel.org, mingo@redhat.com, tglx@kernel.org, bp@alien8.de,
dave.hansen@linux.intel.com, hpa@zytor.com, kees@kernel.org,
shuah@kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org
On Thu, Oct 08, 2026 at 08:59:57PM +0000, Edgecombe, Rick P wrote:
> On Thu, 2026-10-08 at 20:16 +0000, Richard Patel wrote:
> > When returning from a signal via x32 or x64 rt_sigreturn, the
> > shadow-stack-restore token is validated, but ia32 (rt_)sigreturn
> > do not call restore_signal_shadow_stack().
> >
> > With IA32_EMULATION, 'int $0x80' allows ia32 sigreturn in 64-bit
> > mode, which could defeat sigreturn protection.
> >
> > Refuse ia32 sigreturn by forcing a SIGSEGV instead.
>
> How can it defeat protection? If doesn't process the shadow stack sigframe at
> all, leaving the SSP where ever it was originally. What am I missing?
The selftest demonstrates that 'int $0x80' rt_sigreturn from 64-bit mode
jumps to an arbitrary %eip in the signal frame (zero-extended to %rip), \
whereas the 'syscall' variant raises SIGSEGV if %rip is corrupt.
I don't think it matters that SSP is still at the old place. It would
only break 'ret' after sigreturn, but the problem is that the sigreturn
itself is a wild jump.
"defeat protection" was badly worded, I just meant that the 'syscall'
path has protections that the 'int $0x80' path doesn't have, so I
thought it'd be worth fixing.
I might be missing something, maybe SHSTK never intended to defend
against a wild sigreturn? Either way, it's not a security thing.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled
2026-10-08 21:50 ` Richard Patel
@ 2026-10-08 22:34 ` Edgecombe, Rick P
2026-10-08 22:47 ` Richard Patel
0 siblings, 1 reply; 13+ messages in thread
From: Edgecombe, Rick P @ 2026-10-08 22:34 UTC (permalink / raw)
To: ripatel@wii.dev
Cc: kees@kernel.org, x86@kernel.org, dave.hansen@linux.intel.com,
hpa@zytor.com, shuah@kernel.org, mingo@redhat.com, bp@alien8.de,
tglx@kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org
On Thu, 2026-10-08 at 21:50 +0000, Richard Patel wrote:
> > How can it defeat protection? If doesn't process the shadow stack sigframe
> > at
> > all, leaving the SSP where ever it was originally. What am I missing?
>
> The selftest demonstrates that 'int $0x80' rt_sigreturn from 64-bit mode
> jumps to an arbitrary %eip in the signal frame (zero-extended to %rip), \
> whereas the 'syscall' variant raises SIGSEGV if %rip is corrupt.
>
It should just be restoring the SSP from the shadow stack signal frame. Perhaps
you saw the syscall variant fail because it was not at the restorer. Since you
are manually calling sigreturn instead of returning normally. So then it was was
not at the shadow stack signal frame and the shadow stack signal check thought
it was a forged SSP. And the 32 bit one succeed because there was nothing
checked.
But that doesn't have to do with checking EIP matches where the signal was
generated?
>
> I don't think it matters that SSP is still at the old place. It would
> only break 'ret' after sigreturn, but the problem is that the sigreturn
> itself is a wild jump.
>
> "defeat protection" was badly worded, I just meant that the 'syscall'
> path has protections that the 'int $0x80' path doesn't have, so I
> thought it'd be worth fixing.
>
> I might be missing something, maybe SHSTK never intended to defend
> against a wild sigreturn? Either way, it's not a security thing.
Hmm, I guess its kind of on the line between forward edge and backwards edge. I
see your point.
But today setting EIP to an arbitrary point is fairly easy. But even in a future
case of IBT enabled, shadow stack would still need enhancements for the normal
64 bit runtime to prevent this.
In the past we discussed hashing some amount of the sigframe and putting it on
the shadow stack to give some sigframe integrity. But this runs the risk of
breaking apps so would need to be an opt-in enhancement.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled
2026-10-08 22:34 ` Edgecombe, Rick P
@ 2026-10-08 22:47 ` Richard Patel
2026-10-08 23:11 ` Edgecombe, Rick P
0 siblings, 1 reply; 13+ messages in thread
From: Richard Patel @ 2026-10-08 22:47 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: kees@kernel.org, x86@kernel.org, dave.hansen@linux.intel.com,
hpa@zytor.com, shuah@kernel.org, mingo@redhat.com, bp@alien8.de,
tglx@kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org
On Thu, Oct 08, 2026 at 10:34:02PM +0000, Edgecombe, Rick P wrote:
> On Thu, 2026-10-08 at 21:50 +0000, Richard Patel wrote:
> > > How can it defeat protection? If doesn't process the shadow stack sigframe
> > > at
> > > all, leaving the SSP where ever it was originally. What am I missing?
> >
> > The selftest demonstrates that 'int $0x80' rt_sigreturn from 64-bit mode
> > jumps to an arbitrary %eip in the signal frame (zero-extended to %rip), \
> > whereas the 'syscall' variant raises SIGSEGV if %rip is corrupt.
> >
>
> It should just be restoring the SSP from the shadow stack signal frame. Perhaps
> you saw the syscall variant fail because it was not at the restorer. Since you
> are manually calling sigreturn instead of returning normally. So then it was was
> not at the shadow stack signal frame and the shadow stack signal check thought
> it was a forged SSP. And the 32 bit one succeed because there was nothing
> checked.
>
> But that doesn't have to do with checking EIP matches where the signal was
> generated?
I see now, sorry. Yes, I misread the code, and assumed the signal frame
has a matching shadow stack entry that includes the RIP check.
> > I don't think it matters that SSP is still at the old place. It would
> > only break 'ret' after sigreturn, but the problem is that the sigreturn
> > itself is a wild jump.
> >
> > "defeat protection" was badly worded, I just meant that the 'syscall'
> > path has protections that the 'int $0x80' path doesn't have, so I
> > thought it'd be worth fixing.
> >
> > I might be missing something, maybe SHSTK never intended to defend
> > against a wild sigreturn? Either way, it's not a security thing.
>
> Hmm, I guess its kind of on the line between forward edge and backwards edge. I
> see your point.
>
> But today setting EIP to an arbitrary point is fairly easy. But even in a future
> case of IBT enabled, shadow stack would still need enhancements for the normal
> 64 bit runtime to prevent this.
What do you think of creating a shadow stack frame on signal delivery
and popping that on sigreturn? I suppose that would need siglongjmp
modifications and probably break CRIU. :(
I wonder if there are real apps that abuse sigreturn as a forward edge.
If so, they should not be advertising their DSO as shstk-compatible.
> In the past we discussed hashing some amount of the sigframe and putting it on
> the shadow stack to give some sigframe integrity. But this runs the risk of
> breaking apps so would need to be an opt-in enhancement.
Yes that seems a bit excessive to me. At least, the 64-bit path protects
against obviously forged signal frames, so maybe there is still a case
for the patch?
-- Richard
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled
2026-10-08 22:47 ` Richard Patel
@ 2026-10-08 23:11 ` Edgecombe, Rick P
2026-10-08 23:29 ` Richard Patel
2026-10-09 11:36 ` Richard Patel
0 siblings, 2 replies; 13+ messages in thread
From: Edgecombe, Rick P @ 2026-10-08 23:11 UTC (permalink / raw)
To: ripatel@wii.dev
Cc: kees@kernel.org, x86@kernel.org, dave.hansen@linux.intel.com,
hpa@zytor.com, shuah@kernel.org, mingo@redhat.com, bp@alien8.de,
tglx@kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org
On Thu, 2026-10-08 at 22:47 +0000, Richard Patel wrote:
> > But today setting EIP to an arbitrary point is fairly easy. But even in a
> > future
> > case of IBT enabled, shadow stack would still need enhancements for the
> > normal
> > 64 bit runtime to prevent this.
>
> What do you think of creating a shadow stack frame on signal delivery
> and popping that on sigreturn? I suppose that would need siglongjmp
> modifications and probably break CRIU. :(
Yes I didn't know they did not parse the shadow stack signal frame
appropriately. That is unfortunate. But we can still evolve the shadow stack ABI
by adding new modes to the enable prctl if we want.
>
> I wonder if there are real apps that abuse sigreturn as a forward edge.
> If so, they should not be advertising their DSO as shstk-compatible.
The wishes from the glibc/distro side were to support as many apps as possible.
The other way would be to create a more locked down mode where developers need
to carefully verify their apps.
>
> > In the past we discussed hashing some amount of the sigframe and putting it
> > on
> > the shadow stack to give some sigframe integrity. But this runs the risk of
> > breaking apps so would need to be an opt-in enhancement.
>
> Yes that seems a bit excessive to me. At least, the 64-bit path protects
> against obviously forged signal frames, so maybe there is still a case
> for the patch?
For the 32 bit signal blocking patch? I'm not sure why on the security grounds.
I think it depends on how much we want to deflect ia32 mischief vs just ignore
it.
To me it is a cost/benefit thing. Having to think through which syscalls matter
was the point of blocking 32 bit runtime in the first place, so this evaluation
seems too high on the cost. If we do anything more, it should be another small
and complete thing. Like blocking all 32 bit syscalls.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled
2026-10-08 23:11 ` Edgecombe, Rick P
@ 2026-10-08 23:29 ` Richard Patel
2026-10-09 11:36 ` Richard Patel
1 sibling, 0 replies; 13+ messages in thread
From: Richard Patel @ 2026-10-08 23:29 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: kees@kernel.org, x86@kernel.org, dave.hansen@linux.intel.com,
hpa@zytor.com, shuah@kernel.org, mingo@redhat.com, bp@alien8.de,
tglx@kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org
On Thu, Oct 08, 2026 at 11:11:41PM +0000, Edgecombe, Rick P wrote:
> On Thu, 2026-10-08 at 22:47 +0000, Richard Patel wrote:
> > On Thu, Oct 08, 2026 at 10:34:02PM +0000, Edgecombe, Rick P wrote:
> > > But today setting EIP to an arbitrary point is fairly easy. But even in a
> > > future
> > > case of IBT enabled, shadow stack would still need enhancements for the
> > > normal
> > > 64 bit runtime to prevent this.
> >
> > What do you think of creating a shadow stack frame on signal delivery
> > and popping that on sigreturn? I suppose that would need siglongjmp
> > modifications and probably break CRIU. :(
>
> Yes I didn't know they did not parse the shadow stack signal frame
> appropriately. That is unfortunate. But we can still evolve the shadow stack ABI
> by adding new modes to the enable prctl if we want.
Will send libgcc and CRIU patches for this.
> > I wonder if there are real apps that abuse sigreturn as a forward edge.
> > If so, they should not be advertising their DSO as shstk-compatible.
>
> The wishes from the glibc/distro side were to support as many apps as possible.
> The other way would be to create a more locked down mode where developers need
> to carefully verify their apps.
I'll have an AI scan through all Debian repo sources to see if anyone
is doing naughty sigreturns. Even if so, if we evolve the user shstk
ABI, it might be worth breaking that (via opt-in arch_prctl), if it
helps with security.
> > > In the past we discussed hashing some amount of the sigframe and putting it
> > > on
> > > the shadow stack to give some sigframe integrity. But this runs the risk of
> > > breaking apps so would need to be an opt-in enhancement.
> >
> > Yes that seems a bit excessive to me. At least, the 64-bit path protects
> > against obviously forged signal frames, so maybe there is still a case
> > for the patch?
>
> For the 32 bit signal blocking patch? I'm not sure why on the security grounds.
> I think it depends on how much we want to deflect ia32 mischief vs just ignore
> it.
>
> To me it is a cost/benefit thing. Having to think through which syscalls matter
> was the point of blocking 32 bit runtime in the first place, so this evaluation
> seems too high on the cost. If we do anything more, it should be another small
> and complete thing. Like blocking all 32 bit syscalls.
Conceptually, I think shadow stack should authenticate all return
addresses placed on the stack. %rip in the signal frame is a return
address for any non-crazy use, but it's not authenticated. And IMHO that
should be fixed.
Unfortunately my patches fall short of plugging that gap, so I agree
they don't have a security benefit.
I'm eager to fix it and authenticate sigreturn rip, provided you think
it's worth doing.
Cheers,
-- Richard
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled
2026-10-08 23:11 ` Edgecombe, Rick P
2026-10-08 23:29 ` Richard Patel
@ 2026-10-09 11:36 ` Richard Patel
2026-10-09 22:14 ` Edgecombe, Rick P
1 sibling, 1 reply; 13+ messages in thread
From: Richard Patel @ 2026-10-09 11:36 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: kees@kernel.org, x86@kernel.org, dave.hansen@linux.intel.com,
hpa@zytor.com, shuah@kernel.org, mingo@redhat.com, bp@alien8.de,
tglx@kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org
On Thu, Oct 08, 2026 at 11:11:41PM +0000, Edgecombe, Rick P wrote:
> On Thu, 2026-10-08 at 22:47 +0000, Richard Patel wrote:
> > > But today setting EIP to an arbitrary point is fairly easy. But even in a
> > > future
> > > case of IBT enabled, shadow stack would still need enhancements for the
> > > normal
> > > 64 bit runtime to prevent this.
> >
> > What do you think of creating a shadow stack frame on signal delivery
> > and popping that on sigreturn? I suppose that would need siglongjmp
> > modifications and probably break CRIU. :(
>
> Yes I didn't know they did not parse the shadow stack signal frame
> appropriately. That is unfortunate. But we can still evolve the shadow stack ABI
> by adding new modes to the enable prctl if we want.
In the case of CRIU, they are not only parsing, but crafting their own
frames on the shadow stack. I suppose we can keep the kernel's parser
lenient so it works with older CRIU frames even after IBT enablement.
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled
2026-10-09 11:36 ` Richard Patel
@ 2026-10-09 22:14 ` Edgecombe, Rick P
0 siblings, 0 replies; 13+ messages in thread
From: Edgecombe, Rick P @ 2026-10-09 22:14 UTC (permalink / raw)
To: ripatel@wii.dev
Cc: kees@kernel.org, x86@kernel.org, dave.hansen@linux.intel.com,
hpa@zytor.com, shuah@kernel.org, mingo@redhat.com, bp@alien8.de,
tglx@kernel.org, linux-kernel@vger.kernel.org,
linux-kselftest@vger.kernel.org
On Fri, 2026-10-09 at 11:36 +0000, Richard Patel wrote:
> On Thu, Oct 08, 2026 at 11:11:41PM +0000, Edgecombe, Rick P wrote:
> > On Thu, 2026-10-08 at 22:47 +0000, Richard Patel wrote:
> > > > But today setting EIP to an arbitrary point is fairly easy. But even in a
> > > > future
> > > > case of IBT enabled, shadow stack would still need enhancements for the
> > > > normal
> > > > 64 bit runtime to prevent this.
> > >
> > > What do you think of creating a shadow stack frame on signal delivery
> > > and popping that on sigreturn? I suppose that would need siglongjmp
> > > modifications and probably break CRIU. :(
> >
> > Yes I didn't know they did not parse the shadow stack signal frame
> > appropriately. That is unfortunate. But we can still evolve the shadow stack ABI
> > by adding new modes to the enable prctl if we want.
>
> In the case of CRIU, they are not only parsing
>
Ah so the parsing is right, but they don't add the extra frames?
> , but crafting their own
> frames on the shadow stack. I suppose we can keep the kernel's parser
> lenient so it works with older CRIU frames even after IBT enablement.
Yea we would need a backwards compatible frame. The real sigframes have the same
problems to solve.
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-10-09 22:14 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-08 20:16 [PATCH 0/3] x86/shstk: ban ia32 sigreturn Richard Patel
2026-10-08 20:16 ` [PATCH 1/3] x86/shstk: ban ia32 sigreturn when shadow stack is enabled Richard Patel
2026-10-08 20:59 ` Edgecombe, Rick P
2026-10-08 21:50 ` Richard Patel
2026-10-08 22:34 ` Edgecombe, Rick P
2026-10-08 22:47 ` Richard Patel
2026-10-08 23:11 ` Edgecombe, Rick P
2026-10-08 23:29 ` Richard Patel
2026-10-09 11:36 ` Richard Patel
2026-10-09 22:14 ` Edgecombe, Rick P
2026-10-08 20:16 ` [PATCH 2/3] selftests/x86: test shadow stack sigreturn protection Richard Patel
2026-10-08 20:16 ` [PATCH 3/3] selftests/x86: skip shstk tests where perf_event_open() fails Richard Patel
2026-10-08 21:00 ` [PATCH 0/3] x86/shstk: ban ia32 sigreturn Edgecombe, Rick P
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox