arch/i386|x86_64/kernel/ptrace.c linux-2.6.7
Quoted 31 lines · John
Hi Andi,
In linux-2.6.7, I would like to suggest a few small changes to the error checking the
PTRACE_GETREGSandPTRACE_SETREGSprocessing insys_ptrace().While working on our own linux debugger, we noticed that if an invalid user-space address is passed in, then the
ptrace()call would return success even though the registers were not properly read (PTRACE_GETREGS)
or written (PTRACE_SETREGS).Since the
access_ok()check only ensures that the user-space address is within the range of valid user space addresses, the subsequent__put_user()or__get_user()calls can still fail if the user-space address is not current a valid address within the caller's address space.The suggested fix below for i386 and
x86_64is to logically OR the returned
value into 'ret' from the__put_user()or__get_user()calls, in the same way that thearch/x86_64/ia32/ptrace32.ccode does.Additionally, for
x86_64only, theaccess_ok()size parameter should really
besizeof(struct user_regs_struct)instead ofFRAME_SIZE, since onx86_64
theuser_regs_structbeing read/written is actually a bit larger than theFRAME_SIZEdefine.
Quoted 2 lines
Thank you.
Sorry, I guess my diffs got new-line-botched-up.
I'll try again:
diff -ru linux-2.6.7/arch/i386/kernel/ptrace.clinux/arch/i386/kernel/ptrace.c
--- linux-2.6.7/arch/i386/kernel/ptrace.c 2004-06-16
01:19:03.000000000 -0400
+++ linux/arch/i386/kernel/ptrace.c 2004-07-12 13:09:33.000000000 -0400
@@ -428,11 +428,11 @@
ret = -EIO;
break;
}
+ ret = 0;
for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long)
) {
- __put_user(getreg(child, i), datap);
+ ret |= __put_user(getreg(child, i), datap);
datap++;
}
- ret = 0;
break;
}@@ -442,12 +442,12 @@
ret = -EIO;
break;
}
+ ret = 0;
for ( i = 0; i < FRAME_SIZE*sizeof(long); i += sizeof(long)
) {
- __get_user(tmp, datap);
+ ret |=__get_user(tmp, datap);
putreg(child, i, tmp);
datap++;
}
- ret = 0;
break;
}diff -ru linux-2.6.7/arch/x86_64/kernel/ptrace.clinux/arch/x86_64/kernel/ptrace.c
--- linux-2.6.7/arch/x86_64/kernel/ptrace.c 2004-06-16
01:19:09.000000000 -0400
+++ linux/arch/x86_64/kernel/ptrace.c 2004-07-12 16:03:35.584411668 -0400
@@ -429,30 +429,30 @@
break;
case PTRACE_GETREGS: { /* Get all gp regs from the child. */
- if (!access_ok(VERIFY_WRITE, (unsigned __user *)data,FRAME_SIZE)) {
+ if (!access_ok(VERIFY_WRITE, (unsigned __user *)data,
sizeof(struct user_regs_struct))) {
ret = -EIO;
break;
}
+ ret = 0;
for (ui = 0; ui < sizeof(struct user_regs_struct); ui +=sizeof(long)) {
- __put_user(getreg(child, ui),(unsigned long __user
*) data);
+ ret |= __put_user(getreg(child, ui),(unsigned long
__user *) data);
data += sizeof(long);
}
- ret = 0;
break;
}
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
unsigned long tmp;
- if (!access_ok(VERIFY_READ, (unsigned __user *)data,
FRAME_SIZE)) {
+ if (!access_ok(VERIFY_READ, (unsigned __user *)data,
sizeof(struct user_regs_struct))) {
ret = -EIO;
break;
}
+ ret = 0;
for (ui = 0; ui < sizeof(struct user_regs_struct); ui +=
sizeof(long)) {
- __get_user(tmp, (unsigned long __user *) data);
+ ret |= __get_user(tmp, (unsigned long __user *)
data);
putreg(child, ui, tmp);
data += sizeof(long);
}
- ret = 0;
break;
}Quoted 12 lines · John
Quoted 12 lines
returned
value into 'ret' from the__put_user()or__get_user()calls, in the same way that thearch/x86_64/ia32/ptrace32.ccode does.Additionally, for
x86_64only, theaccess_ok()size parameter should really
besizeof(struct user_regs_struct)instead ofFRAME_SIZE, since onx86_64
theuser_regs_structbeing read/written is actually a bit larger than theFRAME_SIZEdefine.
Quoted 5 lines
Quoted 2 lines
Thank you.
Sorry, I guess my diffs got new-line-botched-up.
I'll try again:
The newlines were still broken, but I applied the x86-64 part by hand. Thanks. For i386 I guess Andrew will queue it up.
-Andi