aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events/uprobes.c
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-09-14 12:31:23 -0400
committerOleg Nesterov <oleg@redhat.com>2012-09-29 15:21:52 -0400
commit0578a97098dab967ece4b025fe5eb4984c4c86c0 (patch)
treecf48aeca0e414d1eb2cafdfd28e8e31282a58af1 /kernel/events/uprobes.c
parent746a9e6ba24af2ccf03279c99d435a1b88ca5d17 (diff)
uprobes: Fix UPROBE_SKIP_SSTEP checks in handle_swbp()
If handle_swbp()->add_utask() fails but UPROBE_SKIP_SSTEP is set, cleanup_ret: path do not restart the insn, this is wrong. Remove this check and add the additional label for can_skip_sstep() = T case. Note also that UPROBE_SKIP_SSTEP can be false positive, we simply can not trust it unless arch_uprobe_skip_sstep() was already called. Also, move another UPROBE_SKIP_SSTEP check before can_skip_sstep() into this helper, this looks more clean and understandable. Note: probably we should rename "skip" to "emulate" and I think that "clear UPROBE_SKIP_SSTEP" should be moved to arch_can_skip. Signed-off-by: Oleg Nesterov <oleg@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/events/uprobes.c')
-rw-r--r--kernel/events/uprobes.c31
1 files changed, 15 insertions, 16 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 41f048c91425..d2392968d4e6 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1389,10 +1389,11 @@ bool uprobe_deny_signal(void)
1389 */ 1389 */
1390static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs) 1390static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs)
1391{ 1391{
1392 if (arch_uprobe_skip_sstep(&uprobe->arch, regs)) 1392 if (uprobe->flags & UPROBE_SKIP_SSTEP) {
1393 return true; 1393 if (arch_uprobe_skip_sstep(&uprobe->arch, regs))
1394 1394 return true;
1395 uprobe->flags &= ~UPROBE_SKIP_SSTEP; 1395 uprobe->flags &= ~UPROBE_SKIP_SSTEP;
1396 }
1396 return false; 1397 return false;
1397} 1398}
1398 1399
@@ -1494,12 +1495,12 @@ static void handle_swbp(struct pt_regs *regs)
1494 utask = add_utask(); 1495 utask = add_utask();
1495 /* Cannot allocate; re-execute the instruction. */ 1496 /* Cannot allocate; re-execute the instruction. */
1496 if (!utask) 1497 if (!utask)
1497 goto cleanup_ret; 1498 goto restart;
1498 } 1499 }
1499 1500
1500 handler_chain(uprobe, regs); 1501 handler_chain(uprobe, regs);
1501 if (uprobe->flags & UPROBE_SKIP_SSTEP && can_skip_sstep(uprobe, regs)) 1502 if (can_skip_sstep(uprobe, regs))
1502 goto cleanup_ret; 1503 goto out;
1503 1504
1504 if (!pre_ssout(uprobe, regs, bp_vaddr)) { 1505 if (!pre_ssout(uprobe, regs, bp_vaddr)) {
1505 arch_uprobe_enable_step(&uprobe->arch); 1506 arch_uprobe_enable_step(&uprobe->arch);
@@ -1508,15 +1509,13 @@ static void handle_swbp(struct pt_regs *regs)
1508 return; 1509 return;
1509 } 1510 }
1510 1511
1511cleanup_ret: 1512restart:
1512 if (!(uprobe->flags & UPROBE_SKIP_SSTEP)) 1513 /*
1513 1514 * cannot singlestep; cannot skip instruction;
1514 /* 1515 * re-execute the instruction.
1515 * cannot singlestep; cannot skip instruction; 1516 */
1516 * re-execute the instruction. 1517 instruction_pointer_set(regs, bp_vaddr);
1517 */ 1518out:
1518 instruction_pointer_set(regs, bp_vaddr);
1519
1520 put_uprobe(uprobe); 1519 put_uprobe(uprobe);
1521} 1520}
1522 1521