Commit 0f7e10c4 authored by Paolo \'Blaisorblade\' Giarrusso's avatar Paolo \'Blaisorblade\' Giarrusso Committed by Linus Torvalds

[PATCH] ptrace POKEUSR: add comment about the DR7 check.

The DR7 register on i386/x86_64 has a special meaning, so there is a
special check to do.  Since the code is rather difficult, I added an
explaination about it.  Also, while studying the i386 Intel Manual, I saw
that x86_64, even on 32bit emulation, allows using values which are
disallowed on i386.  It's almost obvious that what it allows is setting a
8-byte wide data watchpoint (in fact I double checked the AMD manuals, just
in case, and this is true; I couldn't find a mention of this in my Intel
manuals).

But since the original ia32 emulation code has this comment:

	/* You are not expected to understand this ... I don't neither. */

I am dubious that the code in ptrace32.c is wrong: does x86_64 supports
8byte-wide watchpoints in 32-bit emulation?  I've checked the AMD manual
Vol.  2 (no.  24593), which says that to set the length to 8 bits "long
mode must be enabled".  This means, actually, that the current code is
safe, notwithstanding the comment (which I removed).
Signed-off-by: default avatarPaolo 'Blaisorblade' Giarrusso <blaisorblade_spam@yahoo.it>
Cc: Roland McGrath <roland@redhat.com>, Andi Kleen <ak@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 67e8e04a
...@@ -344,6 +344,36 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) ...@@ -344,6 +344,36 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
if(addr < (long) &dummy->u_debugreg[4] && if(addr < (long) &dummy->u_debugreg[4] &&
((unsigned long) data) >= TASK_SIZE-3) break; ((unsigned long) data) >= TASK_SIZE-3) break;
/* Sanity-check data. Take one half-byte at once with
* check = (val >> (16 + 4*i)) & 0xf. It contains the
* R/Wi and LENi bits; bits 0 and 1 are R/Wi, and bits
* 2 and 3 are LENi. Given a list of invalid values,
* we do mask |= 1 << invalid_value, so that
* (mask >> check) & 1 is a correct test for invalid
* values.
*
* R/Wi contains the type of the breakpoint /
* watchpoint, LENi contains the length of the watched
* data in the watchpoint case.
*
* The invalid values are:
* - LENi == 0x10 (undefined), so mask |= 0x0f00.
* - R/Wi == 0x10 (break on I/O reads or writes), so
* mask |= 0x4444.
* - R/Wi == 0x00 && LENi != 0x00, so we have mask |=
* 0x1110.
*
* Finally, mask = 0x0f00 | 0x4444 | 0x1110 == 0x5f54.
*
* See the Intel Manual "System Programming Guide",
* 15.2.4
*
* Note that LENi == 0x10 is defined on x86_64 in long
* mode (i.e. even for 32-bit userspace software, but
* 64-bit kernel), so the x86_64 mask value is 0x5454.
* See the AMD manual no. 24593 (AMD64 System
* Programming)*/
if(addr == (long) &dummy->u_debugreg[7]) { if(addr == (long) &dummy->u_debugreg[7]) {
data &= ~DR_CONTROL_RESERVED; data &= ~DR_CONTROL_RESERVED;
for(i=0; i<4; i++) for(i=0; i<4; i++)
......
...@@ -109,7 +109,8 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val) ...@@ -109,7 +109,8 @@ static int putreg32(struct task_struct *child, unsigned regno, u32 val)
case offsetof(struct user32, u_debugreg[7]): case offsetof(struct user32, u_debugreg[7]):
val &= ~DR_CONTROL_RESERVED; val &= ~DR_CONTROL_RESERVED;
/* You are not expected to understand this ... I don't neither. */ /* See arch/i386/kernel/ptrace.c for an explanation of
* this awkward check.*/
for(i=0; i<4; i++) for(i=0; i<4; i++)
if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1) if ((0x5454 >> ((val >> (16 + 4*i)) & 0xf)) & 1)
return -EIO; return -EIO;
......
...@@ -323,6 +323,8 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data ...@@ -323,6 +323,8 @@ asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, long data
ret = 0; ret = 0;
break; break;
case offsetof(struct user, u_debugreg[7]): case offsetof(struct user, u_debugreg[7]):
/* See arch/i386/kernel/ptrace.c for an explanation of
* this awkward check.*/
data &= ~DR_CONTROL_RESERVED; data &= ~DR_CONTROL_RESERVED;
for(i=0; i<4; i++) for(i=0; i<4; i++)
if ((0x5454 >> ((data >> (16 + 4*i)) & 0xf)) & 1) if ((0x5454 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment