aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/ptrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/ptrace.c')
-rw-r--r--arch/x86_64/kernel/ptrace.c28
1 files changed, 18 insertions, 10 deletions
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index e26e86bb56fe..bbf64b59a21e 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -257,13 +257,13 @@ static int putreg(struct task_struct *child,
257 value &= 0xffff; 257 value &= 0xffff;
258 return 0; 258 return 0;
259 case offsetof(struct user_regs_struct,fs_base): 259 case offsetof(struct user_regs_struct,fs_base):
260 if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) 260 if (value >= TASK_SIZE_OF(child))
261 return -EIO; 261 return -EIO;
262 child->thread.fs = value; 262 child->thread.fs = value;
263 return 0; 263 return 0;
264 case offsetof(struct user_regs_struct,gs_base): 264 case offsetof(struct user_regs_struct,gs_base):
265 if (!((value >> 48) == 0 || (value >> 48) == 0xffff)) 265 if (value >= TASK_SIZE_OF(child))
266 return -EIO; 266 return -EIO;
267 child->thread.gs = value; 267 child->thread.gs = value;
268 return 0; 268 return 0;
269 case offsetof(struct user_regs_struct, eflags): 269 case offsetof(struct user_regs_struct, eflags):
@@ -277,6 +277,11 @@ static int putreg(struct task_struct *child,
277 return -EIO; 277 return -EIO;
278 value &= 0xffff; 278 value &= 0xffff;
279 break; 279 break;
280 case offsetof(struct user_regs_struct, rip):
281 /* Check if the new RIP address is canonical */
282 if (value >= TASK_SIZE_OF(child))
283 return -EIO;
284 break;
280 } 285 }
281 put_stack_long(child, regno - sizeof(struct pt_regs), value); 286 put_stack_long(child, regno - sizeof(struct pt_regs), value);
282 return 0; 287 return 0;
@@ -375,7 +380,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
375 break; 380 break;
376 381
377 switch (addr) { 382 switch (addr) {
378 case 0 ... sizeof(struct user_regs_struct): 383 case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
379 tmp = getreg(child, addr); 384 tmp = getreg(child, addr);
380 break; 385 break;
381 case offsetof(struct user, u_debugreg[0]): 386 case offsetof(struct user, u_debugreg[0]):
@@ -414,33 +419,35 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
414 break; 419 break;
415 420
416 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ 421 case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
422 {
423 int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7;
417 ret = -EIO; 424 ret = -EIO;
418 if ((addr & 7) || 425 if ((addr & 7) ||
419 addr > sizeof(struct user) - 7) 426 addr > sizeof(struct user) - 7)
420 break; 427 break;
421 428
422 switch (addr) { 429 switch (addr) {
423 case 0 ... sizeof(struct user_regs_struct): 430 case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
424 ret = putreg(child, addr, data); 431 ret = putreg(child, addr, data);
425 break; 432 break;
426 /* Disallows to set a breakpoint into the vsyscall */ 433 /* Disallows to set a breakpoint into the vsyscall */
427 case offsetof(struct user, u_debugreg[0]): 434 case offsetof(struct user, u_debugreg[0]):
428 if (data >= TASK_SIZE-7) break; 435 if (data >= TASK_SIZE_OF(child) - dsize) break;
429 child->thread.debugreg0 = data; 436 child->thread.debugreg0 = data;
430 ret = 0; 437 ret = 0;
431 break; 438 break;
432 case offsetof(struct user, u_debugreg[1]): 439 case offsetof(struct user, u_debugreg[1]):
433 if (data >= TASK_SIZE-7) break; 440 if (data >= TASK_SIZE_OF(child) - dsize) break;
434 child->thread.debugreg1 = data; 441 child->thread.debugreg1 = data;
435 ret = 0; 442 ret = 0;
436 break; 443 break;
437 case offsetof(struct user, u_debugreg[2]): 444 case offsetof(struct user, u_debugreg[2]):
438 if (data >= TASK_SIZE-7) break; 445 if (data >= TASK_SIZE_OF(child) - dsize) break;
439 child->thread.debugreg2 = data; 446 child->thread.debugreg2 = data;
440 ret = 0; 447 ret = 0;
441 break; 448 break;
442 case offsetof(struct user, u_debugreg[3]): 449 case offsetof(struct user, u_debugreg[3]):
443 if (data >= TASK_SIZE-7) break; 450 if (data >= TASK_SIZE_OF(child) - dsize) break;
444 child->thread.debugreg3 = data; 451 child->thread.debugreg3 = data;
445 ret = 0; 452 ret = 0;
446 break; 453 break;
@@ -464,6 +471,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
464 break; 471 break;
465 } 472 }
466 break; 473 break;
474 }
467 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ 475 case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
468 case PTRACE_CONT: /* restart after signal. */ 476 case PTRACE_CONT: /* restart after signal. */
469 477