diff options
author | Oleg Nesterov <oleg@redhat.com> | 2012-09-14 12:31:23 -0400 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2012-09-29 15:21:52 -0400 |
commit | 0578a97098dab967ece4b025fe5eb4984c4c86c0 (patch) | |
tree | cf48aeca0e414d1eb2cafdfd28e8e31282a58af1 /kernel/events | |
parent | 746a9e6ba24af2ccf03279c99d435a1b88ca5d17 (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')
-rw-r--r-- | kernel/events/uprobes.c | 31 |
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 | */ |
1390 | static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs) | 1390 | static 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 | ||
1511 | cleanup_ret: | 1512 | restart: |
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 | */ | 1518 | out: |
1518 | instruction_pointer_set(regs, bp_vaddr); | ||
1519 | |||
1520 | put_uprobe(uprobe); | 1519 | put_uprobe(uprobe); |
1521 | } | 1520 | } |
1522 | 1521 | ||