1 |
From b45833f10556483f80abf1a239fff7712d0555dd Mon Sep 17 00:00:00 2001 |
2 |
From: Will Deacon <will.deacon@arm.com> |
3 |
Date: Wed, 5 Sep 2018 15:34:42 +0100 |
4 |
Subject: [PATCH 041/145] signal: Introduce COMPAT_SIGMINSTKSZ for use in |
5 |
compat_sys_sigaltstack |
6 |
|
7 |
[ Upstream commit 22839869f21ab3850fbbac9b425ccc4c0023926f ] |
8 |
|
9 |
The sigaltstack(2) system call fails with -ENOMEM if the new alternative |
10 |
signal stack is found to be smaller than SIGMINSTKSZ. On architectures |
11 |
such as arm64, where the native value for SIGMINSTKSZ is larger than |
12 |
the compat value, this can result in an unexpected error being reported |
13 |
to a compat task. See, for example: |
14 |
|
15 |
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=904385 |
16 |
|
17 |
This patch fixes the problem by extending do_sigaltstack to take the |
18 |
minimum signal stack size as an additional parameter, allowing the |
19 |
native and compat system call entry code to pass in their respective |
20 |
values. COMPAT_SIGMINSTKSZ is just defined as SIGMINSTKSZ if it has not |
21 |
been defined by the architecture. |
22 |
|
23 |
Cc: Arnd Bergmann <arnd@arndb.de> |
24 |
Cc: Dominik Brodowski <linux@dominikbrodowski.net> |
25 |
Cc: "Eric W. Biederman" <ebiederm@xmission.com> |
26 |
Cc: Andrew Morton <akpm@linux-foundation.org> |
27 |
Cc: Al Viro <viro@zeniv.linux.org.uk> |
28 |
Cc: Oleg Nesterov <oleg@redhat.com> |
29 |
Reported-by: Steve McIntyre <steve.mcintyre@arm.com> |
30 |
Tested-by: Steve McIntyre <93sam@debian.org> |
31 |
Signed-off-by: Will Deacon <will.deacon@arm.com> |
32 |
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> |
33 |
Signed-off-by: Sasha Levin <sashal@kernel.org> |
34 |
--- |
35 |
include/linux/compat.h | 3 +++ |
36 |
kernel/signal.c | 14 +++++++++----- |
37 |
2 files changed, 12 insertions(+), 5 deletions(-) |
38 |
|
39 |
diff --git a/include/linux/compat.h b/include/linux/compat.h |
40 |
index 1a3c4f37e908..de0c13bdcd2c 100644 |
41 |
--- a/include/linux/compat.h |
42 |
+++ b/include/linux/compat.h |
43 |
@@ -103,6 +103,9 @@ typedef struct compat_sigaltstack { |
44 |
compat_size_t ss_size; |
45 |
} compat_stack_t; |
46 |
#endif |
47 |
+#ifndef COMPAT_MINSIGSTKSZ |
48 |
+#define COMPAT_MINSIGSTKSZ MINSIGSTKSZ |
49 |
+#endif |
50 |
|
51 |
#define compat_jiffies_to_clock_t(x) \ |
52 |
(((unsigned long)(x) * COMPAT_USER_HZ) / HZ) |
53 |
diff --git a/kernel/signal.c b/kernel/signal.c |
54 |
index 5843c541fda9..e4aad0e90882 100644 |
55 |
--- a/kernel/signal.c |
56 |
+++ b/kernel/signal.c |
57 |
@@ -3460,7 +3460,8 @@ int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) |
58 |
} |
59 |
|
60 |
static int |
61 |
-do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp) |
62 |
+do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp, |
63 |
+ size_t min_ss_size) |
64 |
{ |
65 |
struct task_struct *t = current; |
66 |
|
67 |
@@ -3490,7 +3491,7 @@ do_sigaltstack (const stack_t *ss, stack_t *oss, unsigned long sp) |
68 |
ss_size = 0; |
69 |
ss_sp = NULL; |
70 |
} else { |
71 |
- if (unlikely(ss_size < MINSIGSTKSZ)) |
72 |
+ if (unlikely(ss_size < min_ss_size)) |
73 |
return -ENOMEM; |
74 |
} |
75 |
|
76 |
@@ -3508,7 +3509,8 @@ SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss) |
77 |
if (uss && copy_from_user(&new, uss, sizeof(stack_t))) |
78 |
return -EFAULT; |
79 |
err = do_sigaltstack(uss ? &new : NULL, uoss ? &old : NULL, |
80 |
- current_user_stack_pointer()); |
81 |
+ current_user_stack_pointer(), |
82 |
+ MINSIGSTKSZ); |
83 |
if (!err && uoss && copy_to_user(uoss, &old, sizeof(stack_t))) |
84 |
err = -EFAULT; |
85 |
return err; |
86 |
@@ -3519,7 +3521,8 @@ int restore_altstack(const stack_t __user *uss) |
87 |
stack_t new; |
88 |
if (copy_from_user(&new, uss, sizeof(stack_t))) |
89 |
return -EFAULT; |
90 |
- (void)do_sigaltstack(&new, NULL, current_user_stack_pointer()); |
91 |
+ (void)do_sigaltstack(&new, NULL, current_user_stack_pointer(), |
92 |
+ MINSIGSTKSZ); |
93 |
/* squash all but EFAULT for now */ |
94 |
return 0; |
95 |
} |
96 |
@@ -3553,7 +3556,8 @@ static int do_compat_sigaltstack(const compat_stack_t __user *uss_ptr, |
97 |
uss.ss_size = uss32.ss_size; |
98 |
} |
99 |
ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, |
100 |
- compat_user_stack_pointer()); |
101 |
+ compat_user_stack_pointer(), |
102 |
+ COMPAT_MINSIGSTKSZ); |
103 |
if (ret >= 0 && uoss_ptr) { |
104 |
compat_stack_t old; |
105 |
memset(&old, 0, sizeof(old)); |
106 |
-- |
107 |
2.19.1 |
108 |
|