signal: Add an optional check for altstack size
commit 1bdda24c4a
upstream.
New x86 FPU features will be very large, requiring ~10k of stack in
signal handlers. These new features require a new approach called
"dynamic features".
The kernel currently tries to ensure that altstacks are reasonably
sized. Right now, on x86, sys_sigaltstack() requires a size of >=2k.
However, that 2k is a constant. Simply raising that 2k requirement
to >10k for the new features would break existing apps which have a
compiled-in size of 2k.
Instead of universally enforcing a larger stack, prohibit a process from
using dynamic features without properly-sized altstacks. This must be
enforced in two places:
* A dynamic feature can not be enabled without an large-enough altstack
for each process thread.
* Once a dynamic feature is enabled, any request to install a too-small
altstack will be rejected
The dynamic feature enabling code must examine each thread in a
process to ensure that the altstacks are large enough. Add a new lock
(sigaltstack_lock()) to ensure that threads can not race and change
their altstack after being examined.
Add the infrastructure in form of a config option and provide empty
stubs for architectures which do not need dynamic altstack size checks.
This implementation will be fleshed out for x86 in a future patch called
x86/arch_prctl: Add controls for dynamic XSTATE components
[dhansen: commit message. ]
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Link: https://lkml.kernel.org/r/20211021225527.10184-2-chang.seok.bae@intel.com
Signed-off-by: Chen Zhuo <sagazchen@tencent.com>
Signed-off-by: Xinghui Li <korantli@tencent.com>
This commit is contained in:
parent
b890d54d72
commit
815976f881
|
@ -983,6 +983,9 @@ config RELR
|
|||
config ARCH_HAS_MEM_ENCRYPT
|
||||
bool
|
||||
|
||||
config DYNAMIC_SIGFRAME
|
||||
bool
|
||||
|
||||
source "kernel/gcov/Kconfig"
|
||||
|
||||
source "scripts/gcc-plugins/Kconfig"
|
||||
|
|
|
@ -454,6 +454,12 @@ int __save_altstack(stack_t __user *, unsigned long);
|
|||
sas_ss_reset(t); \
|
||||
} while (0);
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_SIGFRAME
|
||||
bool sigaltstack_size_valid(size_t ss_size);
|
||||
#else
|
||||
static inline bool sigaltstack_size_valid(size_t size) { return true; }
|
||||
#endif /* !CONFIG_DYNAMIC_SIGFRAME */
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
struct seq_file;
|
||||
extern void render_sigset_t(struct seq_file *, const char *, sigset_t *);
|
||||
|
|
|
@ -4001,11 +4001,29 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_SIGFRAME
|
||||
static inline void sigaltstack_lock(void)
|
||||
__acquires(¤t->sighand->siglock)
|
||||
{
|
||||
spin_lock_irq(¤t->sighand->siglock);
|
||||
}
|
||||
|
||||
static inline void sigaltstack_unlock(void)
|
||||
__releases(¤t->sighand->siglock)
|
||||
{
|
||||
spin_unlock_irq(¤t->sighand->siglock);
|
||||
}
|
||||
#else
|
||||
static inline void sigaltstack_lock(void) { }
|
||||
static inline void sigaltstack_unlock(void) { }
|
||||
#endif
|
||||
|
||||
static int
|
||||
do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp,
|
||||
size_t min_ss_size)
|
||||
{
|
||||
struct task_struct *t = current;
|
||||
int ret = 0;
|
||||
|
||||
if (oss) {
|
||||
memset(oss, 0, sizeof(stack_t));
|
||||
|
@ -4029,19 +4047,24 @@ do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp,
|
|||
ss_mode != 0))
|
||||
return -EINVAL;
|
||||
|
||||
sigaltstack_lock();
|
||||
if (ss_mode == SS_DISABLE) {
|
||||
ss_size = 0;
|
||||
ss_sp = NULL;
|
||||
} else {
|
||||
if (unlikely(ss_size < min_ss_size))
|
||||
return -ENOMEM;
|
||||
ret = -ENOMEM;
|
||||
if (!sigaltstack_size_valid(ss_size))
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
|
||||
t->sas_ss_sp = (unsigned long) ss_sp;
|
||||
t->sas_ss_size = ss_size;
|
||||
t->sas_ss_flags = ss_flags;
|
||||
if (!ret) {
|
||||
t->sas_ss_sp = (unsigned long) ss_sp;
|
||||
t->sas_ss_size = ss_size;
|
||||
t->sas_ss_flags = ss_flags;
|
||||
}
|
||||
sigaltstack_unlock();
|
||||
}
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss)
|
||||
|
|
Loading…
Reference in New Issue