| .. | .. |
|---|
| 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 |
|---|