diff options
author | bsd <bsd@FreeBSD.org> | 2000-02-20 20:51:23 +0000 |
---|---|---|
committer | bsd <bsd@FreeBSD.org> | 2000-02-20 20:51:23 +0000 |
commit | 85f1c223b39c92c49e8b7c6c7ad39d3e42a27574 (patch) | |
tree | 24b3d3119a30ef55034eb6483b006f39f272b986 /sys/amd64/amd64 | |
parent | 5e5e3ebba622666325b5191546c69ed7f00a5781 (diff) | |
download | FreeBSD-src-85f1c223b39c92c49e8b7c6c7ad39d3e42a27574.zip FreeBSD-src-85f1c223b39c92c49e8b7c6c7ad39d3e42a27574.tar.gz |
Don't forget to reset the hardware debug registers when a process that
was using them exits.
Don't allow a user process to cause the kernel to take a TRCTRAP on a
user space address.
Reviewed by: jlemon, sef
Approved by: jkh
Diffstat (limited to 'sys/amd64/amd64')
-rw-r--r-- | sys/amd64/amd64/machdep.c | 70 | ||||
-rw-r--r-- | sys/amd64/amd64/support.S | 17 | ||||
-rw-r--r-- | sys/amd64/amd64/support.s | 17 | ||||
-rw-r--r-- | sys/amd64/amd64/trap.c | 20 | ||||
-rw-r--r-- | sys/amd64/amd64/vm_machdep.c | 7 |
5 files changed, 130 insertions, 1 deletions
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 397efdc..1efc7e4 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -2239,6 +2239,76 @@ set_dbregs(p, dbregs) return (0); } +/* + * Return > 0 if a hardware breakpoint has been hit, and the + * breakpoint was in user space. Return 0, otherwise. + */ +int +user_dbreg_trap(void) +{ + u_int32_t dr7, dr6; /* debug registers dr6 and dr7 */ + u_int32_t bp; /* breakpoint bits extracted from dr6 */ + int nbp; /* number of breakpoints that triggered */ + caddr_t addr[4]; /* breakpoint addresses */ + int i; + + dr7 = rdr7(); + if ((dr7 & 0x000000ff) == 0) { + /* + * all GE and LE bits in the dr7 register are zero, + * thus the trap couldn't have been caused by the + * hardware debug registers + */ + return 0; + } + + nbp = 0; + dr6 = rdr6(); + bp = dr6 & 0x0000000f; + + if (!bp) { + /* + * None of the breakpoint bits are set meaning this + * trap was not caused by any of the debug registers + */ + return 0; + } + + /* + * at least one of the breakpoints were hit, check to see + * which ones and if any of them are user space addresses + */ + + if (bp & 0x01) { + addr[nbp++] = (caddr_t)rdr0(); + } + if (bp & 0x02) { + addr[nbp++] = (caddr_t)rdr1(); + } + if (bp & 0x04) { + addr[nbp++] = (caddr_t)rdr2(); + } + if (bp & 0x08) { + addr[nbp++] = (caddr_t)rdr3(); + } + + for (i=0; i<nbp; i++) { + if (addr[i] < + (caddr_t)VM_MAXUSER_ADDRESS) { + /* + * addr[i] is in user space + */ + return nbp; + } + } + + /* + * None of the breakpoints are in user space. + */ + return 0; +} + + #ifndef DDB void Debugger(const char *msg) diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S index ae99af9..394848c 100644 --- a/sys/amd64/amd64/support.S +++ b/sys/amd64/amd64/support.S @@ -1586,6 +1586,23 @@ ENTRY(load_cr4) movl %eax,%cr4 ret +/* void load_dr6(u_int dr6) */ +ENTRY(load_dr6) + movl 4(%esp),%eax + movl %eax,%dr6 + ret + +/* void reset_dbregs() */ +ENTRY(reset_dbregs) + movl $0,%eax + movl %eax,%dr7 /* disable all breapoints first */ + movl %eax,%dr0 + movl %eax,%dr1 + movl %eax,%dr2 + movl %eax,%dr3 + movl %eax,%dr6 + ret + /*****************************************************************************/ /* setjump, longjump */ /*****************************************************************************/ diff --git a/sys/amd64/amd64/support.s b/sys/amd64/amd64/support.s index ae99af9..394848c 100644 --- a/sys/amd64/amd64/support.s +++ b/sys/amd64/amd64/support.s @@ -1586,6 +1586,23 @@ ENTRY(load_cr4) movl %eax,%cr4 ret +/* void load_dr6(u_int dr6) */ +ENTRY(load_dr6) + movl 4(%esp),%eax + movl %eax,%dr6 + ret + +/* void reset_dbregs() */ +ENTRY(reset_dbregs) + movl $0,%eax + movl %eax,%dr7 /* disable all breapoints first */ + movl %eax,%dr0 + movl %eax,%dr1 + movl %eax,%dr2 + movl %eax,%dr3 + movl %eax,%dr6 + ret + /*****************************************************************************/ /* setjump, longjump */ /*****************************************************************************/ diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 4199346..a8b73cf 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -519,8 +519,26 @@ kernel_trap: frame.tf_eflags &= ~PSL_T; return; } + /* + * Ignore debug register trace traps due to + * accesses in the user's address space, which + * can happen under several conditions such as + * if a user sets a watchpoint on a buffer and + * then passes that buffer to a system call. + * We still want to get TRCTRAPS for addresses + * in kernel space because that is useful when + * debugging the kernel. + */ + if (user_dbreg_trap()) { + /* + * Reset breakpoint bits because the + * processor doesn't + */ + load_dr6(rdr6() & 0xfffffff0); + return; + } /* - * Fall through. + * Fall through (TRCTRAP kernel mode, kernel address) */ case T_BPTFLT: /* diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c index d7fa73b1..cdcc278 100644 --- a/sys/amd64/amd64/vm_machdep.c +++ b/sys/amd64/amd64/vm_machdep.c @@ -246,6 +246,13 @@ cpu_exit(p) #ifdef USER_LDT user_ldt_free(pcb); #endif + if (pcb->pcb_flags & PCB_DBREGS) { + /* + * disable all hardware breakpoints + */ + reset_dbregs(); + pcb->pcb_flags &= ~PCB_DBREGS; + } cnt.v_swtch++; cpu_switch(p); panic("cpu_exit"); |