]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
signal: Introduce COMPAT_SIGMINSTKSZ for use in compat_sys_sigaltstack
authorWill Deacon <will.deacon@arm.com>
Wed, 5 Sep 2018 14:34:42 +0000 (15:34 +0100)
committerJuerg Haefliger <juergh@canonical.com>
Wed, 24 Jul 2019 01:56:35 +0000 (19:56 -0600)
BugLink: https://bugs.launchpad.net/bugs/1836802
[ Upstream commit 22839869f21ab3850fbbac9b425ccc4c0023926f ]

The sigaltstack(2) system call fails with -ENOMEM if the new alternative
signal stack is found to be smaller than SIGMINSTKSZ. On architectures
such as arm64, where the native value for SIGMINSTKSZ is larger than
the compat value, this can result in an unexpected error being reported
to a compat task. See, for example:

  https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=904385

This patch fixes the problem by extending do_sigaltstack to take the
minimum signal stack size as an additional parameter, allowing the
native and compat system call entry code to pass in their respective
values. COMPAT_SIGMINSTKSZ is just defined as SIGMINSTKSZ if it has not
been defined by the architecture.

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Dominik Brodowski <linux@dominikbrodowski.net>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Oleg Nesterov <oleg@redhat.com>
Reported-by: Steve McIntyre <steve.mcintyre@arm.com>
Tested-by: Steve McIntyre <93sam@debian.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Andrea Righi <andrea.righi@canonical.com>
Signed-off-by: Khalid Elmously <khalid.elmously@canonical.com>
include/linux/compat.h
kernel/signal.c

index 0fc36406f32c6801051bde7218e3ac6d992f1d76..29751150ef06d5ef605f63a7293bfd3af9f6122c 100644 (file)
@@ -68,6 +68,9 @@ typedef struct compat_sigaltstack {
        compat_size_t                   ss_size;
 } compat_stack_t;
 #endif
+#ifndef COMPAT_MINSIGSTKSZ
+#define COMPAT_MINSIGSTKSZ     MINSIGSTKSZ
+#endif
 
 #define compat_jiffies_to_clock_t(x)   \
                (((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
index 17f4fbc192a26fe47aa18f3f3f048755a61bf197..a594dbb45782f43418615e8db35ee406e2388a62 100644 (file)
@@ -3197,7 +3197,8 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
 }
 
 static int
-do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp)
+do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp,
+               size_t min_ss_size)
 {
        struct task_struct *t = current;
 
@@ -3227,7 +3228,7 @@ do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp)
                        ss_size = 0;
                        ss_sp = NULL;
                } else {
-                       if (unlikely(ss_size < MINSIGSTKSZ))
+                       if (unlikely(ss_size < min_ss_size))
                                return -ENOMEM;
                }
 
@@ -3245,7 +3246,8 @@ SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss)
        if (uss && copy_from_user(&new, uss, sizeof(stack_t)))
                return -EFAULT;
        err = do_sigaltstack(uss ? &new : NULL, uoss ? &old : NULL,
-                             current_user_stack_pointer());
+                             current_user_stack_pointer(),
+                             MINSIGSTKSZ);
        if (!err && uoss && copy_to_user(uoss, &old, sizeof(stack_t)))
                err = -EFAULT;
        return err;
@@ -3256,7 +3258,8 @@ int restore_altstack(const stack_t __user *uss)
        stack_t new;
        if (copy_from_user(&new, uss, sizeof(stack_t)))
                return -EFAULT;
-       (void)do_sigaltstack(&new, NULL, current_user_stack_pointer());
+       (void)do_sigaltstack(&new, NULL, current_user_stack_pointer(),
+                            MINSIGSTKSZ);
        /* squash all but EFAULT for now */
        return 0;
 }
@@ -3291,7 +3294,8 @@ COMPAT_SYSCALL_DEFINE2(sigaltstack,
                uss.ss_size = uss32.ss_size;
        }
        ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss,
-                            compat_user_stack_pointer());
+                            compat_user_stack_pointer(),
+                            COMPAT_MINSIGSTKSZ);
        if (ret >= 0 && uoss_ptr)  {
                compat_stack_t old;
                memset(&old, 0, sizeof(old));