diff options
Diffstat (limited to 'arch/sparc/kernel/signal_32.c')
| -rw-r--r-- | arch/sparc/kernel/signal_32.c | 41 |
1 files changed, 26 insertions, 15 deletions
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 | */ | ||
| 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 | |||
| 63 | asmlinkage void do_sigreturn(struct pt_regs *regs) | 75 | asmlinkage 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: | |||
| 127 | asmlinkage void do_rt_sigreturn(struct pt_regs *regs) | 142 | asmlinkage 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 */ | ||
| 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 | |||
| 190 | static inline void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, unsigned long framesize) | 201 | static 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]; |
