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.c29
1 files changed, 17 insertions, 12 deletions
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index 2d50024c9f30..addc14af0c56 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -116,17 +116,17 @@ unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *r
116 return addr; 116 return addr;
117} 117}
118 118
119static int is_at_popf(struct task_struct *child, struct pt_regs *regs) 119static int is_setting_trap_flag(struct task_struct *child, struct pt_regs *regs)
120{ 120{
121 int i, copied; 121 int i, copied;
122 unsigned char opcode[16]; 122 unsigned char opcode[15];
123 unsigned long addr = convert_rip_to_linear(child, regs); 123 unsigned long addr = convert_rip_to_linear(child, regs);
124 124
125 copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0); 125 copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0);
126 for (i = 0; i < copied; i++) { 126 for (i = 0; i < copied; i++) {
127 switch (opcode[i]) { 127 switch (opcode[i]) {
128 /* popf */ 128 /* popf and iret */
129 case 0x9d: 129 case 0x9d: case 0xcf:
130 return 1; 130 return 1;
131 131
132 /* CHECKME: 64 65 */ 132 /* CHECKME: 64 65 */
@@ -138,14 +138,17 @@ static int is_at_popf(struct task_struct *child, struct pt_regs *regs)
138 case 0x26: case 0x2e: 138 case 0x26: case 0x2e:
139 case 0x36: case 0x3e: 139 case 0x36: case 0x3e:
140 case 0x64: case 0x65: 140 case 0x64: case 0x65:
141 case 0xf0: case 0xf2: case 0xf3: 141 case 0xf2: case 0xf3:
142 continue; 142 continue;
143 143
144 /* REX prefixes */
145 case 0x40 ... 0x4f: 144 case 0x40 ... 0x4f:
145 if (regs->cs != __USER_CS)
146 /* 32-bit mode: register increment */
147 return 0;
148 /* 64-bit mode: REX prefix */
146 continue; 149 continue;
147 150
148 /* CHECKME: f0, f2, f3 */ 151 /* CHECKME: f2, f3 */
149 152
150 /* 153 /*
151 * pushf: NOTE! We should probably not let 154 * pushf: NOTE! We should probably not let
@@ -186,10 +189,8 @@ static void set_singlestep(struct task_struct *child)
186 * ..but if TF is changed by the instruction we will trace, 189 * ..but if TF is changed by the instruction we will trace,
187 * don't mark it as being "us" that set it, so that we 190 * don't mark it as being "us" that set it, so that we
188 * won't clear it by hand later. 191 * won't clear it by hand later.
189 *
190 * AK: this is not enough, LAHF and IRET can change TF in user space too.
191 */ 192 */
192 if (is_at_popf(child, regs)) 193 if (is_setting_trap_flag(child, regs))
193 return; 194 return;
194 195
195 child->ptrace |= PT_DTRACE; 196 child->ptrace |= PT_DTRACE;
@@ -420,9 +421,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
420 if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1) 421 if ((0x5554 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
421 break; 422 break;
422 if (i == 4) { 423 if (i == 4) {
423 child->thread.debugreg7 = data; 424 child->thread.debugreg7 = data;
425 if (data)
426 set_tsk_thread_flag(child, TIF_DEBUG);
427 else
428 clear_tsk_thread_flag(child, TIF_DEBUG);
424 ret = 0; 429 ret = 0;
425 } 430 }
426 break; 431 break;
427 } 432 }
428 break; 433 break;