aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-05-29 00:21:31 -0400
committerDavid S. Miller <davem@davemloft.net>2016-05-29 14:24:05 -0400
commitd11c2a0de2824395656cf8ed15811580c9dd38aa (patch)
tree1a2024f157752d35d4ac42807c6ca1da7b52b58c
parent9ea46abe22550e3366ff7cee2f8391b35b12f730 (diff)
sparc: Harden signal return frame checks.
All signal frames must be at least 16-byte aligned, because that is the alignment we explicitly create when we build signal return stack frames. All stack pointers must be at least 8-byte aligned. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--arch/sparc/kernel/signal32.c46
-rw-r--r--arch/sparc/kernel/signal_32.c41
-rw-r--r--arch/sparc/kernel/signal_64.c31
-rw-r--r--arch/sparc/kernel/sigutil_32.c9
-rw-r--r--arch/sparc/kernel/sigutil_64.c10
5 files changed, 92 insertions, 45 deletions
diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c
index 3c25241fa5cb..91cc2f4ae4d9 100644
--- a/arch/sparc/kernel/signal32.c
+++ b/arch/sparc/kernel/signal32.c
@@ -138,12 +138,24 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
138 return 0; 138 return 0;
139} 139}
140 140
141/* Checks if the fp is valid. We always build signal frames which are
142 * 16-byte aligned, therefore we can always enforce that the restore
143 * frame has that property as well.
144 */
145static bool invalid_frame_pointer(void __user *fp, int fplen)
146{
147 if ((((unsigned long) fp) & 15) ||
148 ((unsigned long)fp) > 0x100000000ULL - fplen)
149 return true;
150 return false;
151}
152
141void do_sigreturn32(struct pt_regs *regs) 153void do_sigreturn32(struct pt_regs *regs)
142{ 154{
143 struct signal_frame32 __user *sf; 155 struct signal_frame32 __user *sf;
144 compat_uptr_t fpu_save; 156 compat_uptr_t fpu_save;
145 compat_uptr_t rwin_save; 157 compat_uptr_t rwin_save;
146 unsigned int psr; 158 unsigned int psr, ufp;
147 unsigned int pc, npc; 159 unsigned int pc, npc;
148 sigset_t set; 160 sigset_t set;
149 compat_sigset_t seta; 161 compat_sigset_t seta;
@@ -158,11 +170,16 @@ void do_sigreturn32(struct pt_regs *regs)
158 sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP]; 170 sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
159 171
160 /* 1. Make sure we are not getting garbage from the user */ 172 /* 1. Make sure we are not getting garbage from the user */
161 if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || 173 if (invalid_frame_pointer(sf, sizeof(*sf)))
162 (((unsigned long) sf) & 3)) 174 goto segv;
175
176 if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
177 goto segv;
178
179 if (ufp & 0x7)
163 goto segv; 180 goto segv;
164 181
165 if (get_user(pc, &sf->info.si_regs.pc) || 182 if (__get_user(pc, &sf->info.si_regs.pc) ||
166 __get_user(npc, &sf->info.si_regs.npc)) 183 __get_user(npc, &sf->info.si_regs.npc))
167 goto segv; 184 goto segv;
168 185
@@ -227,7 +244,7 @@ segv:
227asmlinkage void do_rt_sigreturn32(struct pt_regs *regs) 244asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
228{ 245{
229 struct rt_signal_frame32 __user *sf; 246 struct rt_signal_frame32 __user *sf;
230 unsigned int psr, pc, npc; 247 unsigned int psr, pc, npc, ufp;
231 compat_uptr_t fpu_save; 248 compat_uptr_t fpu_save;
232 compat_uptr_t rwin_save; 249 compat_uptr_t rwin_save;
233 sigset_t set; 250 sigset_t set;
@@ -242,11 +259,16 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
242 sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP]; 259 sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
243 260
244 /* 1. Make sure we are not getting garbage from the user */ 261 /* 1. Make sure we are not getting garbage from the user */
245 if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || 262 if (invalid_frame_pointer(sf, sizeof(*sf)))
246 (((unsigned long) sf) & 3))
247 goto segv; 263 goto segv;
248 264
249 if (get_user(pc, &sf->regs.pc) || 265 if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
266 goto segv;
267
268 if (ufp & 0x7)
269 goto segv;
270
271 if (__get_user(pc, &sf->regs.pc) ||
250 __get_user(npc, &sf->regs.npc)) 272 __get_user(npc, &sf->regs.npc))
251 goto segv; 273 goto segv;
252 274
@@ -307,14 +329,6 @@ segv:
307 force_sig(SIGSEGV, current); 329 force_sig(SIGSEGV, current);
308} 330}
309 331
310/* Checks if the fp is valid */
311static int invalid_frame_pointer(void __user *fp, int fplen)
312{
313 if ((((unsigned long) fp) & 7) || ((unsigned long)fp) > 0x100000000ULL - fplen)
314 return 1;
315 return 0;
316}
317
318static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) 332static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
319{ 333{
320 unsigned long sp; 334 unsigned long sp;
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c
index 52aa5e4ce5e7..c3c12efe0bc0 100644
--- a/arch/sparc/kernel/signal_32.c
+++ b/arch/sparc/kernel/signal_32.c
@@ -60,10 +60,22 @@ struct rt_signal_frame {
60#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7))) 60#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
61#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) 61#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
62 62
63/* Checks if the fp is valid. We always build signal frames which are
64 * 16-byte aligned, therefore we can always enforce that the restore
65 * frame has that property as well.
66 */
67static inline bool invalid_frame_pointer(void __user *fp, int fplen)
68{
69 if ((((unsigned long) fp) & 15) || !__access_ok((unsigned long)fp, fplen))
70 return true;
71
72 return false;
73}
74
63asmlinkage void do_sigreturn(struct pt_regs *regs) 75asmlinkage void do_sigreturn(struct pt_regs *regs)
64{ 76{
77 unsigned long up_psr, pc, npc, ufp;
65 struct signal_frame __user *sf; 78 struct signal_frame __user *sf;
66 unsigned long up_psr, pc, npc;
67 sigset_t set; 79 sigset_t set;
68 __siginfo_fpu_t __user *fpu_save; 80 __siginfo_fpu_t __user *fpu_save;
69 __siginfo_rwin_t __user *rwin_save; 81 __siginfo_rwin_t __user *rwin_save;
@@ -77,10 +89,13 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
77 sf = (struct signal_frame __user *) regs->u_regs[UREG_FP]; 89 sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];
78 90
79 /* 1. Make sure we are not getting garbage from the user */ 91 /* 1. Make sure we are not getting garbage from the user */
80 if (!access_ok(VERIFY_READ, sf, sizeof(*sf))) 92 if (!invalid_frame_pointer(sf, sizeof(*sf)))
93 goto segv_and_exit;
94
95 if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
81 goto segv_and_exit; 96 goto segv_and_exit;
82 97
83 if (((unsigned long) sf) & 3) 98 if (ufp & 0x7)
84 goto segv_and_exit; 99 goto segv_and_exit;
85 100
86 err = __get_user(pc, &sf->info.si_regs.pc); 101 err = __get_user(pc, &sf->info.si_regs.pc);
@@ -127,7 +142,7 @@ segv_and_exit:
127asmlinkage void do_rt_sigreturn(struct pt_regs *regs) 142asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
128{ 143{
129 struct rt_signal_frame __user *sf; 144 struct rt_signal_frame __user *sf;
130 unsigned int psr, pc, npc; 145 unsigned int psr, pc, npc, ufp;
131 __siginfo_fpu_t __user *fpu_save; 146 __siginfo_fpu_t __user *fpu_save;
132 __siginfo_rwin_t __user *rwin_save; 147 __siginfo_rwin_t __user *rwin_save;
133 sigset_t set; 148 sigset_t set;
@@ -135,8 +150,13 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
135 150
136 synchronize_user_stack(); 151 synchronize_user_stack();
137 sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP]; 152 sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
138 if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || 153 if (!invalid_frame_pointer(sf, sizeof(*sf)))
139 (((unsigned long) sf) & 0x03)) 154 goto segv;
155
156 if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
157 goto segv;
158
159 if (ufp & 0x7)
140 goto segv; 160 goto segv;
141 161
142 err = __get_user(pc, &sf->regs.pc); 162 err = __get_user(pc, &sf->regs.pc);
@@ -178,15 +198,6 @@ segv:
178 force_sig(SIGSEGV, current); 198 force_sig(SIGSEGV, current);
179} 199}
180 200
181/* Checks if the fp is valid */
182static inline int invalid_frame_pointer(void __user *fp, int fplen)
183{
184 if ((((unsigned long) fp) & 7) || !__access_ok((unsigned long)fp, fplen))
185 return 1;
186
187 return 0;
188}
189
190static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) 201static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
191{ 202{
192 unsigned long sp = regs->u_regs[UREG_FP]; 203 unsigned long sp = regs->u_regs[UREG_FP];
diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c
index 39aaec173f66..5ee930c48f4c 100644
--- a/arch/sparc/kernel/signal_64.c
+++ b/arch/sparc/kernel/signal_64.c
@@ -234,6 +234,17 @@ do_sigsegv:
234 goto out; 234 goto out;
235} 235}
236 236
237/* Checks if the fp is valid. We always build rt signal frames which
238 * are 16-byte aligned, therefore we can always enforce that the
239 * restore frame has that property as well.
240 */
241static bool invalid_frame_pointer(void __user *fp)
242{
243 if (((unsigned long) fp) & 15)
244 return true;
245 return false;
246}
247
237struct rt_signal_frame { 248struct rt_signal_frame {
238 struct sparc_stackf ss; 249 struct sparc_stackf ss;
239 siginfo_t info; 250 siginfo_t info;
@@ -246,8 +257,8 @@ struct rt_signal_frame {
246 257
247void do_rt_sigreturn(struct pt_regs *regs) 258void do_rt_sigreturn(struct pt_regs *regs)
248{ 259{
260 unsigned long tpc, tnpc, tstate, ufp;
249 struct rt_signal_frame __user *sf; 261 struct rt_signal_frame __user *sf;
250 unsigned long tpc, tnpc, tstate;
251 __siginfo_fpu_t __user *fpu_save; 262 __siginfo_fpu_t __user *fpu_save;
252 __siginfo_rwin_t __user *rwin_save; 263 __siginfo_rwin_t __user *rwin_save;
253 sigset_t set; 264 sigset_t set;
@@ -261,10 +272,16 @@ void do_rt_sigreturn(struct pt_regs *regs)
261 (regs->u_regs [UREG_FP] + STACK_BIAS); 272 (regs->u_regs [UREG_FP] + STACK_BIAS);
262 273
263 /* 1. Make sure we are not getting garbage from the user */ 274 /* 1. Make sure we are not getting garbage from the user */
264 if (((unsigned long) sf) & 3) 275 if (invalid_frame_pointer(sf))
276 goto segv;
277
278 if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
265 goto segv; 279 goto segv;
266 280
267 err = get_user(tpc, &sf->regs.tpc); 281 if ((ufp + STACK_BIAS) & 0x7)
282 goto segv;
283
284 err = __get_user(tpc, &sf->regs.tpc);
268 err |= __get_user(tnpc, &sf->regs.tnpc); 285 err |= __get_user(tnpc, &sf->regs.tnpc);
269 if (test_thread_flag(TIF_32BIT)) { 286 if (test_thread_flag(TIF_32BIT)) {
270 tpc &= 0xffffffff; 287 tpc &= 0xffffffff;
@@ -308,14 +325,6 @@ segv:
308 force_sig(SIGSEGV, current); 325 force_sig(SIGSEGV, current);
309} 326}
310 327
311/* Checks if the fp is valid */
312static int invalid_frame_pointer(void __user *fp)
313{
314 if (((unsigned long) fp) & 15)
315 return 1;
316 return 0;
317}
318
319static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) 328static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
320{ 329{
321 unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS; 330 unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;
diff --git a/arch/sparc/kernel/sigutil_32.c b/arch/sparc/kernel/sigutil_32.c
index 0f6eebe71e6c..e5fe8cef9a69 100644
--- a/arch/sparc/kernel/sigutil_32.c
+++ b/arch/sparc/kernel/sigutil_32.c
@@ -48,6 +48,10 @@ int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
48int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) 48int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
49{ 49{
50 int err; 50 int err;
51
52 if (((unsigned long) fpu) & 3)
53 return -EFAULT;
54
51#ifdef CONFIG_SMP 55#ifdef CONFIG_SMP
52 if (test_tsk_thread_flag(current, TIF_USEDFPU)) 56 if (test_tsk_thread_flag(current, TIF_USEDFPU))
53 regs->psr &= ~PSR_EF; 57 regs->psr &= ~PSR_EF;
@@ -97,7 +101,10 @@ int restore_rwin_state(__siginfo_rwin_t __user *rp)
97 struct thread_info *t = current_thread_info(); 101 struct thread_info *t = current_thread_info();
98 int i, wsaved, err; 102 int i, wsaved, err;
99 103
100 __get_user(wsaved, &rp->wsaved); 104 if (((unsigned long) rp) & 3)
105 return -EFAULT;
106
107 get_user(wsaved, &rp->wsaved);
101 if (wsaved > NSWINS) 108 if (wsaved > NSWINS)
102 return -EFAULT; 109 return -EFAULT;
103 110
diff --git a/arch/sparc/kernel/sigutil_64.c b/arch/sparc/kernel/sigutil_64.c
index 387834a9c56a..36aadcbeac69 100644
--- a/arch/sparc/kernel/sigutil_64.c
+++ b/arch/sparc/kernel/sigutil_64.c
@@ -37,7 +37,10 @@ int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
37 unsigned long fprs; 37 unsigned long fprs;
38 int err; 38 int err;
39 39
40 err = __get_user(fprs, &fpu->si_fprs); 40 if (((unsigned long) fpu) & 7)
41 return -EFAULT;
42
43 err = get_user(fprs, &fpu->si_fprs);
41 fprs_write(0); 44 fprs_write(0);
42 regs->tstate &= ~TSTATE_PEF; 45 regs->tstate &= ~TSTATE_PEF;
43 if (fprs & FPRS_DL) 46 if (fprs & FPRS_DL)
@@ -72,7 +75,10 @@ int restore_rwin_state(__siginfo_rwin_t __user *rp)
72 struct thread_info *t = current_thread_info(); 75 struct thread_info *t = current_thread_info();
73 int i, wsaved, err; 76 int i, wsaved, err;
74 77
75 __get_user(wsaved, &rp->wsaved); 78 if (((unsigned long) rp) & 7)
79 return -EFAULT;
80
81 get_user(wsaved, &rp->wsaved);
76 if (wsaved > NSWINS) 82 if (wsaved > NSWINS)
77 return -EFAULT; 83 return -EFAULT;
78 84