aboutsummaryrefslogtreecommitdiff
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 e26e86bb56f..bbf64b59a21 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,
value &= 0xffff;
return 0;
case offsetof(struct user_regs_struct,fs_base):
- if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
- return -EIO;
+ if (value >= TASK_SIZE_OF(child))
+ return -EIO;
child->thread.fs = value;
return 0;
case offsetof(struct user_regs_struct,gs_base):
- if (!((value >> 48) == 0 || (value >> 48) == 0xffff))
- return -EIO;
+ if (value >= TASK_SIZE_OF(child))
+ return -EIO;
child->thread.gs = value;
return 0;
case offsetof(struct user_regs_struct, eflags):
@@ -277,6 +277,11 @@ static int putreg(struct task_struct *child,
return -EIO;
value &= 0xffff;
break;
+ case offsetof(struct user_regs_struct, rip):
+ /* Check if the new RIP address is canonical */
+ if (value >= TASK_SIZE_OF(child))
+ return -EIO;
+ break;
}
put_stack_long(child, regno - sizeof(struct pt_regs), value);
return 0;
@@ -375,7 +380,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
break;
switch (addr) {
- case 0 ... sizeof(struct user_regs_struct):
+ case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
tmp = getreg(child, addr);
break;
case offsetof(struct user, u_debugreg[0]):
@@ -414,33 +419,35 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
break;
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
+ {
+ int dsize = test_tsk_thread_flag(child, TIF_IA32) ? 3 : 7;
ret = -EIO;
if ((addr & 7) ||
addr > sizeof(struct user) - 7)
break;
switch (addr) {
- case 0 ... sizeof(struct user_regs_struct):
+ case 0 ... sizeof(struct user_regs_struct) - sizeof(long):
ret = putreg(child, addr, data);
break;
/* Disallows to set a breakpoint into the vsyscall */
case offsetof(struct user, u_debugreg[0]):
- if (data >= TASK_SIZE-7) break;
+ if (data >= TASK_SIZE_OF(child) - dsize) break;
child->thread.debugreg0 = data;
ret = 0;
break;
case offsetof(struct user, u_debugreg[1]):
- if (data >= TASK_SIZE-7) break;
+ if (data >= TASK_SIZE_OF(child) - dsize) break;
child->thread.debugreg1 = data;
ret = 0;
break;
case offsetof(struct user, u_debugreg[2]):
- if (data >= TASK_SIZE-7) break;
+ if (data >= TASK_SIZE_OF(child) - dsize) break;
child->thread.debugreg2 = data;
ret = 0;
break;
case offsetof(struct user, u_debugreg[3]):
- if (data >= TASK_SIZE-7) break;
+ if (data >= TASK_SIZE_OF(child) - dsize) break;
child->thread.debugreg3 = data;
ret = 0;
break;
@@ -464,6 +471,7 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
break;
}
break;
+ }
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: /* restart after signal. */