signal: use scoped user access in __save_altstack()

__save_altstack() and __compat_save_altstack() write three fields with
__put_user(), relying on the caller having done access_ok() on the whole
signal frame.  Each of those writes enables and disables user access on
its own, so that check saves nothing.

x86 and powerpc already avoid these functions by using
unsafe_save_altstack() inside their own user access regions.  Use the
same helpers here, inside a scoped_user_write_access(), so that every
other architecture gets a single range check and a single user access
region too.  None of those callers is itself inside a user access
region, so nothing nests.

This is part of getting rid of __get_user() and __put_user() entirely.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Linus Torvalds 2026-10-19 19:23:16 -10:00
parent 5c8590157b
commit b040da2a00

View File

@ -4539,11 +4539,12 @@ int restore_altstack(const stack_t __user *uss)
int __save_altstack(stack_t __user *uss, unsigned long sp)
{
struct task_struct *t = current;
int err = __put_user((void __user *)t->sas_ss_sp, &uss->ss_sp) |
__put_user(t->sas_ss_flags, &uss->ss_flags) |
__put_user(t->sas_ss_size, &uss->ss_size);
return err;
scoped_user_write_access(uss, Efault)
unsafe_save_altstack(uss, sp, Efault);
return 0;
Efault:
return -EFAULT;
}
#ifdef CONFIG_COMPAT
@ -4592,13 +4593,12 @@ int compat_restore_altstack(const compat_stack_t __user *uss)
int __compat_save_altstack(compat_stack_t __user *uss, unsigned long sp)
{
int err;
struct task_struct *t = current;
err = __put_user(ptr_to_compat((void __user *)t->sas_ss_sp),
&uss->ss_sp) |
__put_user(t->sas_ss_flags, &uss->ss_flags) |
__put_user(t->sas_ss_size, &uss->ss_size);
return err;
scoped_user_write_access(uss, Efault)
unsafe_compat_save_altstack(uss, sp, Efault);
return 0;
Efault:
return -EFAULT;
}
#endif