Skip to content

Commit 84ee6e8

Browse files
arunarKAGA-KOKO
authored andcommitted
x86/pkeys: Add helper functions to update PKRU on the sigframe
In the case where a user thread sets up an alternate signal stack protected by the default PKEY (i.e. PKEY 0), while the thread's stack is protected by a non-zero PKEY, both these PKEYS have to be enabled in the PKRU register for the signal to be delivered to the application correctly. However, the PKRU value restored after handling the signal must not enable this extra PKEY (i.e. PKEY 0) - i.e., the PKRU value in the sigframe has to be overwritten with the user-defined value. Add helper functions that will update PKRU value in the sigframe after XSAVE. Note that sig_prepare_pkru() makes no assumption about which PKEY could be used to protect the altstack (i.e. it may not be part of init_pkru), and so enables all PKEYS. No functional change. Signed-off-by: Aruna Ramakrishna <aruna.ramakrishna@oracle.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/all/20240802061318.2140081-3-aruna.ramakrishna@oracle.com
1 parent 24cf2bc commit 84ee6e8

4 files changed

Lines changed: 43 additions & 0 deletions

File tree

arch/x86/kernel/fpu/signal.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ static inline bool check_xstate_in_sigframe(struct fxregs_state __user *fxbuf,
6363
return true;
6464
}
6565

66+
/*
67+
* Update the value of PKRU register that was already pushed onto the signal frame.
68+
*/
69+
static inline int update_pkru_in_sigframe(struct xregs_state __user *buf, u32 pkru)
70+
{
71+
if (unlikely(!cpu_feature_enabled(X86_FEATURE_OSPKE)))
72+
return 0;
73+
return __put_user(pkru, (unsigned int __user *)get_xsave_addr_user(buf, XFEATURE_PKRU));
74+
}
75+
6676
/*
6777
* Signal frame handlers.
6878
*/

arch/x86/kernel/fpu/xstate.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -993,6 +993,19 @@ void *get_xsave_addr(struct xregs_state *xsave, int xfeature_nr)
993993
}
994994
EXPORT_SYMBOL_GPL(get_xsave_addr);
995995

996+
/*
997+
* Given an xstate feature nr, calculate where in the xsave buffer the state is.
998+
* The xsave buffer should be in standard format, not compacted (e.g. user mode
999+
* signal frames).
1000+
*/
1001+
void __user *get_xsave_addr_user(struct xregs_state __user *xsave, int xfeature_nr)
1002+
{
1003+
if (WARN_ON_ONCE(!xfeature_enabled(xfeature_nr)))
1004+
return NULL;
1005+
1006+
return (void __user *)xsave + xstate_offsets[xfeature_nr];
1007+
}
1008+
9961009
#ifdef CONFIG_ARCH_HAS_PKEYS
9971010

9981011
/*

arch/x86/kernel/fpu/xstate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ extern int copy_sigframe_from_user_to_xstate(struct task_struct *tsk, const void
5454
extern void fpu__init_cpu_xstate(void);
5555
extern void fpu__init_system_xstate(unsigned int legacy_size);
5656

57+
extern void __user *get_xsave_addr_user(struct xregs_state __user *xsave, int xfeature_nr);
58+
5759
static inline u64 xfeatures_mask_supervisor(void)
5860
{
5961
return fpu_kernel_cfg.max_features & XFEATURE_MASK_SUPERVISOR_SUPPORTED;

arch/x86/kernel/signal.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,24 @@ static inline int is_x32_frame(struct ksignal *ksig)
6060
ksig->ka.sa.sa_flags & SA_X32_ABI;
6161
}
6262

63+
/*
64+
* Enable all pkeys temporarily, so as to ensure that both the current
65+
* execution stack as well as the alternate signal stack are writeable.
66+
* The application can use any of the available pkeys to protect the
67+
* alternate signal stack, and we don't know which one it is, so enable
68+
* all. The PKRU register will be reset to init_pkru later in the flow,
69+
* in fpu__clear_user_states(), and it is the application's responsibility
70+
* to enable the appropriate pkey as the first step in the signal handler
71+
* so that the handler does not segfault.
72+
*/
73+
static inline u32 sig_prepare_pkru(void)
74+
{
75+
u32 orig_pkru = read_pkru();
76+
77+
write_pkru(0);
78+
return orig_pkru;
79+
}
80+
6381
/*
6482
* Set up a signal frame.
6583
*/

0 commit comments

Comments
 (0)