.. | .. |
---|
120 | 120 | u32 sig; |
---|
121 | 121 | int ret; |
---|
122 | 122 | |
---|
123 | | - if (copy_from_user(&ptr, &t->rseq->rseq_cs.ptr64, sizeof(ptr))) |
---|
| 123 | +#ifdef CONFIG_64BIT |
---|
| 124 | + if (get_user(ptr, &t->rseq->rseq_cs)) |
---|
124 | 125 | return -EFAULT; |
---|
| 126 | +#else |
---|
| 127 | + if (copy_from_user(&ptr, &t->rseq->rseq_cs, sizeof(ptr))) |
---|
| 128 | + return -EFAULT; |
---|
| 129 | +#endif |
---|
125 | 130 | if (!ptr) { |
---|
126 | 131 | memset(rseq_cs, 0, sizeof(*rseq_cs)); |
---|
127 | 132 | return 0; |
---|
.. | .. |
---|
204 | 209 | * |
---|
205 | 210 | * Set rseq_cs to NULL. |
---|
206 | 211 | */ |
---|
207 | | - if (clear_user(&t->rseq->rseq_cs.ptr64, sizeof(t->rseq->rseq_cs.ptr64))) |
---|
| 212 | +#ifdef CONFIG_64BIT |
---|
| 213 | + return put_user(0UL, &t->rseq->rseq_cs); |
---|
| 214 | +#else |
---|
| 215 | + if (clear_user(&t->rseq->rseq_cs, sizeof(t->rseq->rseq_cs))) |
---|
208 | 216 | return -EFAULT; |
---|
209 | 217 | return 0; |
---|
| 218 | +#endif |
---|
210 | 219 | } |
---|
211 | 220 | |
---|
212 | 221 | /* |
---|
.. | .. |
---|
254 | 263 | * - signal delivery, |
---|
255 | 264 | * and return to user-space. |
---|
256 | 265 | * |
---|
257 | | - * This is how we can ensure that the entire rseq critical section, |
---|
258 | | - * consisting of both the C part and the assembly instruction sequence, |
---|
| 266 | + * This is how we can ensure that the entire rseq critical section |
---|
259 | 267 | * will issue the commit instruction only if executed atomically with |
---|
260 | 268 | * respect to other threads scheduled on the same CPU, and with respect |
---|
261 | 269 | * to signal handlers. |
---|
.. | .. |
---|
267 | 275 | |
---|
268 | 276 | if (unlikely(t->flags & PF_EXITING)) |
---|
269 | 277 | return; |
---|
270 | | - if (unlikely(!access_ok(VERIFY_WRITE, t->rseq, sizeof(*t->rseq)))) |
---|
| 278 | + if (unlikely(!access_ok(t->rseq, sizeof(*t->rseq)))) |
---|
271 | 279 | goto error; |
---|
272 | | - ret = rseq_ip_fixup(regs); |
---|
273 | | - if (unlikely(ret < 0)) |
---|
274 | | - goto error; |
---|
| 280 | + /* |
---|
| 281 | + * regs is NULL if and only if the caller is in a syscall path. Skip |
---|
| 282 | + * fixup and leave rseq_cs as is so that rseq_sycall() will detect and |
---|
| 283 | + * kill a misbehaving userspace on debug kernels. |
---|
| 284 | + */ |
---|
| 285 | + if (regs) { |
---|
| 286 | + ret = rseq_ip_fixup(regs); |
---|
| 287 | + if (unlikely(ret < 0)) |
---|
| 288 | + goto error; |
---|
| 289 | + } |
---|
275 | 290 | if (unlikely(rseq_update_cpu_id(t))) |
---|
276 | 291 | goto error; |
---|
277 | 292 | return; |
---|
278 | 293 | |
---|
279 | 294 | error: |
---|
280 | 295 | sig = ksig ? ksig->sig : 0; |
---|
281 | | - force_sigsegv(sig, t); |
---|
| 296 | + force_sigsegv(sig); |
---|
282 | 297 | } |
---|
283 | 298 | |
---|
284 | 299 | #ifdef CONFIG_DEBUG_RSEQ |
---|
.. | .. |
---|
295 | 310 | |
---|
296 | 311 | if (!t->rseq) |
---|
297 | 312 | return; |
---|
298 | | - if (!access_ok(VERIFY_READ, t->rseq, sizeof(*t->rseq)) || |
---|
| 313 | + if (!access_ok(t->rseq, sizeof(*t->rseq)) || |
---|
299 | 314 | rseq_get_rseq_cs(t, &rseq_cs) || in_rseq_cs(ip, &rseq_cs)) |
---|
300 | | - force_sig(SIGSEGV, t); |
---|
| 315 | + force_sig(SIGSEGV); |
---|
301 | 316 | } |
---|
302 | 317 | |
---|
303 | 318 | #endif |
---|
.. | .. |
---|
311 | 326 | int ret; |
---|
312 | 327 | |
---|
313 | 328 | if (flags & RSEQ_FLAG_UNREGISTER) { |
---|
| 329 | + if (flags & ~RSEQ_FLAG_UNREGISTER) |
---|
| 330 | + return -EINVAL; |
---|
314 | 331 | /* Unregister rseq for current thread. */ |
---|
315 | 332 | if (current->rseq != rseq || !current->rseq) |
---|
316 | 333 | return -EINVAL; |
---|
317 | | - if (current->rseq_len != rseq_len) |
---|
| 334 | + if (rseq_len != sizeof(*rseq)) |
---|
318 | 335 | return -EINVAL; |
---|
319 | 336 | if (current->rseq_sig != sig) |
---|
320 | 337 | return -EPERM; |
---|
.. | .. |
---|
322 | 339 | if (ret) |
---|
323 | 340 | return ret; |
---|
324 | 341 | current->rseq = NULL; |
---|
325 | | - current->rseq_len = 0; |
---|
326 | 342 | current->rseq_sig = 0; |
---|
327 | 343 | return 0; |
---|
328 | 344 | } |
---|
.. | .. |
---|
336 | 352 | * the provided address differs from the prior |
---|
337 | 353 | * one. |
---|
338 | 354 | */ |
---|
339 | | - if (current->rseq != rseq || current->rseq_len != rseq_len) |
---|
| 355 | + if (current->rseq != rseq || rseq_len != sizeof(*rseq)) |
---|
340 | 356 | return -EINVAL; |
---|
341 | 357 | if (current->rseq_sig != sig) |
---|
342 | 358 | return -EPERM; |
---|
.. | .. |
---|
351 | 367 | if (!IS_ALIGNED((unsigned long)rseq, __alignof__(*rseq)) || |
---|
352 | 368 | rseq_len != sizeof(*rseq)) |
---|
353 | 369 | return -EINVAL; |
---|
354 | | - if (!access_ok(VERIFY_WRITE, rseq, rseq_len)) |
---|
| 370 | + if (!access_ok(rseq, rseq_len)) |
---|
355 | 371 | return -EFAULT; |
---|
356 | 372 | current->rseq = rseq; |
---|
357 | | - current->rseq_len = rseq_len; |
---|
358 | 373 | current->rseq_sig = sig; |
---|
359 | 374 | /* |
---|
360 | 375 | * If rseq was previously inactive, and has just been |
---|