[PATCH 3/3] x86/sigreturn: Reject system segements

From: Brian Gerst
Date: Wed Dec 13 2023 - 11:35:00 EST


Do not allow system segments (TSS and LDT) from being loaded into segment
registers via sigreturn. Loading these segments into a segment register
normally results in a general protection fault. In the case of sigreturn,
setting CS or SS to a system segment will cause IRET to fault. This
then results in the instruction decoder attempting to use the invalid
segment. This can be avoided by rejecting system segments in the
sigreturn() syscall.

Signed-off-by: Brian Gerst <brgerst@xxxxxxxxx>
Reported-By: Michal Luczaj <mhal@xxxxxxx>
Link: https://lore.kernel.org/lkml/20231206004654.2986026-1-mhal@xxxxxxx/
---
arch/x86/kernel/signal_32.c | 4 ++++
arch/x86/kernel/signal_64.c | 4 ++++
2 files changed, 8 insertions(+)

diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index c12624bc82a3..0e1926b676b0 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -98,7 +98,11 @@ static bool ia32_restore_sigcontext(struct pt_regs *regs,

/* Get CS/SS and force CPL3 */
regs->cs = sc.cs | 0x03;
+ if (!valid_user_selector(regs->cs))
+ return false;
regs->ss = sc.ss | 0x03;
+ if (!valid_user_selector(regs->ss))
+ return false;

regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS);
/* disable syscall checks */
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index 23d8aaf8d9fd..666b147bf43a 100644
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -79,7 +79,11 @@ static bool restore_sigcontext(struct pt_regs *regs,

/* Get CS/SS and force CPL3 */
regs->cs = sc.cs | 0x03;
+ if (!valid_user_selector(regs->cs))
+ return false;
regs->ss = sc.ss | 0x03;
+ if (!valid_user_selector(regs->ss))
+ return false;

regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS);
/* disable syscall checks */
--
2.43.0