Patch "x86/pkeys: Add PKRU as a parameter in signal handling functions" has been added to the 6.6-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    x86/pkeys: Add PKRU as a parameter in signal handling functions

to the 6.6-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     x86-pkeys-add-pkru-as-a-parameter-in-signal-handling.patch
and it can be found in the queue-6.6 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 4a655cb29e3adef5e41fd9f81a58780092679657
Author: Aruna Ramakrishna <aruna.ramakrishna@xxxxxxxxxx>
Date:   Fri Aug 2 06:13:14 2024 +0000

    x86/pkeys: Add PKRU as a parameter in signal handling functions
    
    [ Upstream commit 24cf2bc982ffe02aeffb4a3885c71751a2c7023b ]
    
    Assume there's a multithreaded application that runs untrusted user
    code. Each thread has its stack/code protected by a non-zero PKEY, and the
    PKRU register is set up such that only that particular non-zero PKEY is
    enabled. Each thread also sets up an alternate signal stack to handle
    signals, which is protected by PKEY zero. The PKEYs man page documents that
    the PKRU will be reset to init_pkru when the signal handler is invoked,
    which means that PKEY zero access will be enabled.  But this reset happens
    after the kernel attempts to push fpu state to the alternate stack, which
    is not (yet) accessible by the kernel, which leads to a new SIGSEGV being
    sent to the application, terminating it.
    
    Enabling both the non-zero PKEY (for the thread) and PKEY zero in
    userspace will not work for this use case. It cannot have the alt stack
    writeable by all - the rationale here is that the code running in that
    thread (using a non-zero PKEY) is untrusted and should not have access
    to the alternate signal stack (that uses PKEY zero), to prevent the
    return address of a function from being changed. The expectation is that
    kernel should be able to set up the alternate signal stack and deliver
    the signal to the application even if PKEY zero is explicitly disabled
    by the application. The signal handler accessibility should not be
    dictated by whatever PKRU value the thread sets up.
    
    The PKRU register is managed by XSAVE, which means the sigframe contents
    must match the register contents - which is not the case here. It's
    required that the signal frame contains the user-defined PKRU value (so
    that it is restored correctly from sigcontext) but the actual register must
    be reset to init_pkru so that the alt stack is accessible and the signal
    can be delivered to the application. It seems that the proper fix here
    would be to remove PKRU from the XSAVE framework and manage it separately,
    which is quite complicated. As a workaround, do this:
    
            orig_pkru = rdpkru();
            wrpkru(orig_pkru & init_pkru_value);
            xsave_to_user_sigframe();
            put_user(pkru_sigframe_addr, orig_pkru)
    
    In preparation for writing PKRU to sigframe, pass PKRU as an additional
    parameter down the call chain from get_sigframe().
    
    No functional change.
    
    Signed-off-by: Aruna Ramakrishna <aruna.ramakrishna@xxxxxxxxxx>
    Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
    Link: https://lore.kernel.org/all/20240802061318.2140081-2-aruna.ramakrishna@xxxxxxxxxx
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/arch/x86/include/asm/fpu/signal.h b/arch/x86/include/asm/fpu/signal.h
index 611fa41711aff..eccc75bc9c4f3 100644
--- a/arch/x86/include/asm/fpu/signal.h
+++ b/arch/x86/include/asm/fpu/signal.h
@@ -29,7 +29,7 @@ fpu__alloc_mathframe(unsigned long sp, int ia32_frame,
 
 unsigned long fpu__get_fpstate_size(void);
 
-extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size);
+extern bool copy_fpstate_to_sigframe(void __user *buf, void __user *fp, int size, u32 pkru);
 extern void fpu__clear_user_states(struct fpu *fpu);
 extern bool fpu__restore_sig(void __user *buf, int ia32_frame);
 
diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c
index 247f2225aa9f3..2b3b9e140dd41 100644
--- a/arch/x86/kernel/fpu/signal.c
+++ b/arch/x86/kernel/fpu/signal.c
@@ -156,7 +156,7 @@ static inline bool save_xstate_epilog(void __user *buf, int ia32_frame,
 	return !err;
 }
 
-static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)
+static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf, u32 pkru)
 {
 	if (use_xsave())
 		return xsave_to_user_sigframe(buf);
@@ -185,7 +185,7 @@ static inline int copy_fpregs_to_sigframe(struct xregs_state __user *buf)
  * For [f]xsave state, update the SW reserved fields in the [f]xsave frame
  * indicating the absence/presence of the extended state to the user.
  */
-bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
+bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size, u32 pkru)
 {
 	struct task_struct *tsk = current;
 	struct fpstate *fpstate = tsk->thread.fpu.fpstate;
@@ -228,7 +228,7 @@ bool copy_fpstate_to_sigframe(void __user *buf, void __user *buf_fx, int size)
 		fpregs_restore_userregs();
 
 	pagefault_disable();
-	ret = copy_fpregs_to_sigframe(buf_fx);
+	ret = copy_fpregs_to_sigframe(buf_fx, pkru);
 	pagefault_enable();
 	fpregs_unlock();
 
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 65fe2094da59b..876d3b30c2c77 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -83,6 +83,7 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size,
 	unsigned long math_size = 0;
 	unsigned long sp = regs->sp;
 	unsigned long buf_fx = 0;
+	u32 pkru = read_pkru();
 
 	/* redzone */
 	if (!ia32_frame)
@@ -138,7 +139,7 @@ get_sigframe(struct ksignal *ksig, struct pt_regs *regs, size_t frame_size,
 	}
 
 	/* save i387 and extended state */
-	if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size))
+	if (!copy_fpstate_to_sigframe(*fpstate, (void __user *)buf_fx, math_size, pkru))
 		return (void __user *)-1L;
 
 	return (void __user *)sp;




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux