Skip to content

Commit 58c1f99

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc
Pull sparc fixes from David Miller: "sparc64 mmu context allocation and trap return bug fixes" * git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc: sparc64: Fix return from trap window fill crashes. sparc: Harden signal return frame checks. sparc64: Take ctx_alloc_lock properly in hugetlb_setup().
2 parents 367d3fd + 7cafc0b commit 58c1f99

File tree

11 files changed

+215
-100
lines changed

11 files changed

+215
-100
lines changed

arch/sparc/include/asm/head_64.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515

1616
#define PTREGS_OFF (STACK_BIAS + STACKFRAME_SZ)
1717

18+
#define RTRAP_PSTATE (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE)
19+
#define RTRAP_PSTATE_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV)
20+
#define RTRAP_PSTATE_AG_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
21+
1822
#define __CHEETAH_ID 0x003e0014
1923
#define __JALAPENO_ID 0x003e0016
2024
#define __SERRANO_ID 0x003e0022

arch/sparc/include/asm/ttable.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -589,8 +589,8 @@ user_rtt_fill_64bit: \
589589
restored; \
590590
nop; nop; nop; nop; nop; nop; \
591591
nop; nop; nop; nop; nop; \
592-
ba,a,pt %xcc, user_rtt_fill_fixup; \
593-
ba,a,pt %xcc, user_rtt_fill_fixup; \
592+
ba,a,pt %xcc, user_rtt_fill_fixup_dax; \
593+
ba,a,pt %xcc, user_rtt_fill_fixup_mna; \
594594
ba,a,pt %xcc, user_rtt_fill_fixup;
595595

596596

@@ -652,8 +652,8 @@ user_rtt_fill_32bit: \
652652
restored; \
653653
nop; nop; nop; nop; nop; \
654654
nop; nop; nop; \
655-
ba,a,pt %xcc, user_rtt_fill_fixup; \
656-
ba,a,pt %xcc, user_rtt_fill_fixup; \
655+
ba,a,pt %xcc, user_rtt_fill_fixup_dax; \
656+
ba,a,pt %xcc, user_rtt_fill_fixup_mna; \
657657
ba,a,pt %xcc, user_rtt_fill_fixup;
658658

659659

arch/sparc/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ CFLAGS_REMOVE_perf_event.o := -pg
2121
CFLAGS_REMOVE_pcr.o := -pg
2222
endif
2323

24+
obj-$(CONFIG_SPARC64) += urtt_fill.o
2425
obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o
2526
obj-$(CONFIG_SPARC32) += etrap_32.o
2627
obj-$(CONFIG_SPARC32) += rtrap_32.o

arch/sparc/kernel/rtrap_64.S

Lines changed: 9 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,6 @@
1414
#include <asm/visasm.h>
1515
#include <asm/processor.h>
1616

17-
#define RTRAP_PSTATE (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_IE)
18-
#define RTRAP_PSTATE_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV)
19-
#define RTRAP_PSTATE_AG_IRQOFF (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
20-
2117
#ifdef CONFIG_CONTEXT_TRACKING
2218
# define SCHEDULE_USER schedule_user
2319
#else
@@ -242,52 +238,17 @@ rt_continue: ldx [%sp + PTREGS_OFF + PT_V9_G1], %g1
242238
wrpr %g1, %cwp
243239
ba,a,pt %xcc, user_rtt_fill_64bit
244240

245-
user_rtt_fill_fixup:
246-
rdpr %cwp, %g1
247-
add %g1, 1, %g1
248-
wrpr %g1, 0x0, %cwp
249-
250-
rdpr %wstate, %g2
251-
sll %g2, 3, %g2
252-
wrpr %g2, 0x0, %wstate
253-
254-
/* We know %canrestore and %otherwin are both zero. */
255-
256-
sethi %hi(sparc64_kern_pri_context), %g2
257-
ldx [%g2 + %lo(sparc64_kern_pri_context)], %g2
258-
mov PRIMARY_CONTEXT, %g1
259-
260-
661: stxa %g2, [%g1] ASI_DMMU
261-
.section .sun4v_1insn_patch, "ax"
262-
.word 661b
263-
stxa %g2, [%g1] ASI_MMU
264-
.previous
265-
266-
sethi %hi(KERNBASE), %g1
267-
flush %g1
241+
user_rtt_fill_fixup_dax:
242+
ba,pt %xcc, user_rtt_fill_fixup_common
243+
mov 1, %g3
268244

269-
or %g4, FAULT_CODE_WINFIXUP, %g4
270-
stb %g4, [%g6 + TI_FAULT_CODE]
271-
stx %g5, [%g6 + TI_FAULT_ADDR]
245+
user_rtt_fill_fixup_mna:
246+
ba,pt %xcc, user_rtt_fill_fixup_common
247+
mov 2, %g3
272248

273-
mov %g6, %l1
274-
wrpr %g0, 0x0, %tl
275-
276-
661: nop
277-
.section .sun4v_1insn_patch, "ax"
278-
.word 661b
279-
SET_GL(0)
280-
.previous
281-
282-
wrpr %g0, RTRAP_PSTATE, %pstate
283-
284-
mov %l1, %g6
285-
ldx [%g6 + TI_TASK], %g4
286-
LOAD_PER_CPU_BASE(%g5, %g6, %g1, %g2, %g3)
287-
call do_sparc64_fault
288-
add %sp, PTREGS_OFF, %o0
289-
ba,pt %xcc, rtrap
290-
nop
249+
user_rtt_fill_fixup:
250+
ba,pt %xcc, user_rtt_fill_fixup_common
251+
clr %g3
291252

292253
user_rtt_pre_restore:
293254
add %g1, 1, %g1

arch/sparc/kernel/signal32.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,24 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
138138
return 0;
139139
}
140140

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+
*/
145+
static 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+
141153
void do_sigreturn32(struct pt_regs *regs)
142154
{
143155
struct signal_frame32 __user *sf;
144156
compat_uptr_t fpu_save;
145157
compat_uptr_t rwin_save;
146-
unsigned int psr;
158+
unsigned int psr, ufp;
147159
unsigned int pc, npc;
148160
sigset_t set;
149161
compat_sigset_t seta;
@@ -158,11 +170,16 @@ void do_sigreturn32(struct pt_regs *regs)
158170
sf = (struct signal_frame32 __user *) regs->u_regs[UREG_FP];
159171

160172
/* 1. Make sure we are not getting garbage from the user */
161-
if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
162-
(((unsigned long) sf) & 3))
173+
if (invalid_frame_pointer(sf, sizeof(*sf)))
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)
163180
goto segv;
164181

165-
if (get_user(pc, &sf->info.si_regs.pc) ||
182+
if (__get_user(pc, &sf->info.si_regs.pc) ||
166183
__get_user(npc, &sf->info.si_regs.npc))
167184
goto segv;
168185

@@ -227,7 +244,7 @@ void do_sigreturn32(struct pt_regs *regs)
227244
asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
228245
{
229246
struct rt_signal_frame32 __user *sf;
230-
unsigned int psr, pc, npc;
247+
unsigned int psr, pc, npc, ufp;
231248
compat_uptr_t fpu_save;
232249
compat_uptr_t rwin_save;
233250
sigset_t set;
@@ -242,11 +259,16 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
242259
sf = (struct rt_signal_frame32 __user *) regs->u_regs[UREG_FP];
243260

244261
/* 1. Make sure we are not getting garbage from the user */
245-
if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
246-
(((unsigned long) sf) & 3))
262+
if (invalid_frame_pointer(sf, sizeof(*sf)))
247263
goto segv;
248264

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) ||
250272
__get_user(npc, &sf->regs.npc))
251273
goto segv;
252274

@@ -307,14 +329,6 @@ asmlinkage void do_rt_sigreturn32(struct pt_regs *regs)
307329
force_sig(SIGSEGV, current);
308330
}
309331

310-
/* Checks if the fp is valid */
311-
static 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-
318332
static void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
319333
{
320334
unsigned long sp;

arch/sparc/kernel/signal_32.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,22 @@ struct rt_signal_frame {
6060
#define SF_ALIGNEDSZ (((sizeof(struct signal_frame) + 7) & (~7)))
6161
#define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7)))
6262

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+
*/
67+
static 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+
6375
asmlinkage void do_sigreturn(struct pt_regs *regs)
6476
{
77+
unsigned long up_psr, pc, npc, ufp;
6578
struct signal_frame __user *sf;
66-
unsigned long up_psr, pc, npc;
6779
sigset_t set;
6880
__siginfo_fpu_t __user *fpu_save;
6981
__siginfo_rwin_t __user *rwin_save;
@@ -77,10 +89,13 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
7789
sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];
7890

7991
/* 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]))
8196
goto segv_and_exit;
8297

83-
if (((unsigned long) sf) & 3)
98+
if (ufp & 0x7)
8499
goto segv_and_exit;
85100

86101
err = __get_user(pc, &sf->info.si_regs.pc);
@@ -127,16 +142,21 @@ asmlinkage void do_sigreturn(struct pt_regs *regs)
127142
asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
128143
{
129144
struct rt_signal_frame __user *sf;
130-
unsigned int psr, pc, npc;
145+
unsigned int psr, pc, npc, ufp;
131146
__siginfo_fpu_t __user *fpu_save;
132147
__siginfo_rwin_t __user *rwin_save;
133148
sigset_t set;
134149
int err;
135150

136151
synchronize_user_stack();
137152
sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP];
138-
if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) ||
139-
(((unsigned long) sf) & 0x03))
153+
if (!invalid_frame_pointer(sf, sizeof(*sf)))
154+
goto segv;
155+
156+
if (get_user(ufp, &sf->regs.u_regs[UREG_FP]))
157+
goto segv;
158+
159+
if (ufp & 0x7)
140160
goto segv;
141161

142162
err = __get_user(pc, &sf->regs.pc);
@@ -178,15 +198,6 @@ asmlinkage void do_rt_sigreturn(struct pt_regs *regs)
178198
force_sig(SIGSEGV, current);
179199
}
180200

181-
/* Checks if the fp is valid */
182-
static 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-
190201
static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
191202
{
192203
unsigned long sp = regs->u_regs[UREG_FP];

arch/sparc/kernel/signal_64.c

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,17 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
234234
goto out;
235235
}
236236

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+
*/
241+
static bool invalid_frame_pointer(void __user *fp)
242+
{
243+
if (((unsigned long) fp) & 15)
244+
return true;
245+
return false;
246+
}
247+
237248
struct rt_signal_frame {
238249
struct sparc_stackf ss;
239250
siginfo_t info;
@@ -246,8 +257,8 @@ struct rt_signal_frame {
246257

247258
void do_rt_sigreturn(struct pt_regs *regs)
248259
{
260+
unsigned long tpc, tnpc, tstate, ufp;
249261
struct rt_signal_frame __user *sf;
250-
unsigned long tpc, tnpc, tstate;
251262
__siginfo_fpu_t __user *fpu_save;
252263
__siginfo_rwin_t __user *rwin_save;
253264
sigset_t set;
@@ -261,10 +272,16 @@ void do_rt_sigreturn(struct pt_regs *regs)
261272
(regs->u_regs [UREG_FP] + STACK_BIAS);
262273

263274
/* 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]))
265279
goto segv;
266280

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);
268285
err |= __get_user(tnpc, &sf->regs.tnpc);
269286
if (test_thread_flag(TIF_32BIT)) {
270287
tpc &= 0xffffffff;
@@ -308,14 +325,6 @@ void do_rt_sigreturn(struct pt_regs *regs)
308325
force_sig(SIGSEGV, current);
309326
}
310327

311-
/* Checks if the fp is valid */
312-
static int invalid_frame_pointer(void __user *fp)
313-
{
314-
if (((unsigned long) fp) & 15)
315-
return 1;
316-
return 0;
317-
}
318-
319328
static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize)
320329
{
321330
unsigned long sp = regs->u_regs[UREG_FP] + STACK_BIAS;

arch/sparc/kernel/sigutil_32.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ int save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
4848
int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
4949
{
5050
int err;
51+
52+
if (((unsigned long) fpu) & 3)
53+
return -EFAULT;
54+
5155
#ifdef CONFIG_SMP
5256
if (test_tsk_thread_flag(current, TIF_USEDFPU))
5357
regs->psr &= ~PSR_EF;
@@ -97,7 +101,10 @@ int restore_rwin_state(__siginfo_rwin_t __user *rp)
97101
struct thread_info *t = current_thread_info();
98102
int i, wsaved, err;
99103

100-
__get_user(wsaved, &rp->wsaved);
104+
if (((unsigned long) rp) & 3)
105+
return -EFAULT;
106+
107+
get_user(wsaved, &rp->wsaved);
101108
if (wsaved > NSWINS)
102109
return -EFAULT;
103110

arch/sparc/kernel/sigutil_64.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ int restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu)
3737
unsigned long fprs;
3838
int err;
3939

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);
4144
fprs_write(0);
4245
regs->tstate &= ~TSTATE_PEF;
4346
if (fprs & FPRS_DL)
@@ -72,7 +75,10 @@ int restore_rwin_state(__siginfo_rwin_t __user *rp)
7275
struct thread_info *t = current_thread_info();
7376
int i, wsaved, err;
7477

75-
__get_user(wsaved, &rp->wsaved);
78+
if (((unsigned long) rp) & 7)
79+
return -EFAULT;
80+
81+
get_user(wsaved, &rp->wsaved);
7682
if (wsaved > NSWINS)
7783
return -EFAULT;
7884

0 commit comments

Comments
 (0)