diff options
Diffstat (limited to 'arch/arm/kernel/signal.c')
| -rw-r--r-- | arch/arm/kernel/signal.c | 96 |
1 files changed, 18 insertions, 78 deletions
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index a94d75fef598..a917e3dd3666 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c | |||
| @@ -139,93 +139,33 @@ struct iwmmxt_sigframe { | |||
| 139 | unsigned long storage[0x98/4]; | 139 | unsigned long storage[0x98/4]; |
| 140 | }; | 140 | }; |
| 141 | 141 | ||
| 142 | static int page_present(struct mm_struct *mm, void __user *uptr, int wr) | ||
| 143 | { | ||
| 144 | unsigned long addr = (unsigned long)uptr; | ||
| 145 | pgd_t *pgd = pgd_offset(mm, addr); | ||
| 146 | if (pgd_present(*pgd)) { | ||
| 147 | pmd_t *pmd = pmd_offset(pgd, addr); | ||
| 148 | if (pmd_present(*pmd)) { | ||
| 149 | pte_t *pte = pte_offset_map(pmd, addr); | ||
| 150 | return (pte_present(*pte) && (!wr || pte_write(*pte))); | ||
| 151 | } | ||
| 152 | } | ||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | static int copy_locked(void __user *uptr, void *kptr, size_t size, int write, | ||
| 157 | void (*copyfn)(void *, void __user *)) | ||
| 158 | { | ||
| 159 | unsigned char v, __user *userptr = uptr; | ||
| 160 | int err = 0; | ||
| 161 | |||
| 162 | do { | ||
| 163 | struct mm_struct *mm; | ||
| 164 | |||
| 165 | if (write) { | ||
| 166 | __put_user_error(0, userptr, err); | ||
| 167 | __put_user_error(0, userptr + size - 1, err); | ||
| 168 | } else { | ||
| 169 | __get_user_error(v, userptr, err); | ||
| 170 | __get_user_error(v, userptr + size - 1, err); | ||
| 171 | } | ||
| 172 | |||
| 173 | if (err) | ||
| 174 | break; | ||
| 175 | |||
| 176 | mm = current->mm; | ||
| 177 | spin_lock(&mm->page_table_lock); | ||
| 178 | if (page_present(mm, userptr, write) && | ||
| 179 | page_present(mm, userptr + size - 1, write)) { | ||
| 180 | copyfn(kptr, uptr); | ||
| 181 | } else | ||
| 182 | err = 1; | ||
| 183 | spin_unlock(&mm->page_table_lock); | ||
| 184 | } while (err); | ||
| 185 | |||
| 186 | return err; | ||
| 187 | } | ||
| 188 | |||
| 189 | static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) | 142 | static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame) |
| 190 | { | 143 | { |
| 191 | int err = 0; | 144 | char kbuf[sizeof(*frame) + 8]; |
| 145 | struct iwmmxt_sigframe *kframe; | ||
| 192 | 146 | ||
| 193 | /* the iWMMXt context must be 64 bit aligned */ | 147 | /* the iWMMXt context must be 64 bit aligned */ |
| 194 | WARN_ON((unsigned long)frame & 7); | 148 | kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); |
| 195 | 149 | kframe->magic0 = IWMMXT_MAGIC0; | |
| 196 | __put_user_error(IWMMXT_MAGIC0, &frame->magic0, err); | 150 | kframe->magic1 = IWMMXT_MAGIC1; |
| 197 | __put_user_error(IWMMXT_MAGIC1, &frame->magic1, err); | 151 | iwmmxt_task_copy(current_thread_info(), &kframe->storage); |
| 198 | 152 | return __copy_to_user(frame, kframe, sizeof(*frame)); | |
| 199 | /* | ||
| 200 | * iwmmxt_task_copy() doesn't check user permissions. | ||
| 201 | * Let's do a dummy write on the upper boundary to ensure | ||
| 202 | * access to user mem is OK all way up. | ||
| 203 | */ | ||
| 204 | err |= copy_locked(&frame->storage, current_thread_info(), | ||
| 205 | sizeof(frame->storage), 1, iwmmxt_task_copy); | ||
| 206 | return err; | ||
| 207 | } | 153 | } |
| 208 | 154 | ||
| 209 | static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) | 155 | static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame) |
| 210 | { | 156 | { |
| 211 | unsigned long magic0, magic1; | 157 | char kbuf[sizeof(*frame) + 8]; |
| 212 | int err = 0; | 158 | struct iwmmxt_sigframe *kframe; |
| 213 | 159 | ||
| 214 | /* the iWMMXt context is 64 bit aligned */ | 160 | /* the iWMMXt context must be 64 bit aligned */ |
| 215 | WARN_ON((unsigned long)frame & 7); | 161 | kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7); |
| 216 | 162 | if (__copy_from_user(kframe, frame, sizeof(*frame))) | |
| 217 | /* | 163 | return -1; |
| 218 | * Validate iWMMXt context signature. | 164 | if (kframe->magic0 != IWMMXT_MAGIC0 || |
| 219 | * Also, iwmmxt_task_restore() doesn't check user permissions. | 165 | kframe->magic1 != IWMMXT_MAGIC1) |
| 220 | * Let's do a dummy write on the upper boundary to ensure | 166 | return -1; |
| 221 | * access to user mem is OK all way up. | 167 | iwmmxt_task_restore(current_thread_info(), &kframe->storage); |
| 222 | */ | 168 | return 0; |
| 223 | __get_user_error(magic0, &frame->magic0, err); | ||
| 224 | __get_user_error(magic1, &frame->magic1, err); | ||
| 225 | if (!err && magic0 == IWMMXT_MAGIC0 && magic1 == IWMMXT_MAGIC1) | ||
| 226 | err = copy_locked(&frame->storage, current_thread_info(), | ||
| 227 | sizeof(frame->storage), 0, iwmmxt_task_restore); | ||
| 228 | return err; | ||
| 229 | } | 169 | } |
| 230 | 170 | ||
| 231 | #endif | 171 | #endif |
