diff options
author | Oleg Nesterov <oleg@redhat.com> | 2012-05-29 15:28:57 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-06-06 11:15:17 -0400 |
commit | 3a9ea0520f38def4a3915b91f82455b749f07d88 (patch) | |
tree | 810a4d5bb6f075497ad3b2cd94c120ae235e026f /kernel/events | |
parent | a3d7bb47937b3a40b9f0c75655e97b3bb6407cbe (diff) |
uprobes: Introduce find_active_uprobe() helper
No functional changes. Move the "find uprobe" code from
handle_swbp() to the new helper, find_active_uprobe().
Note: with or without this change, the find-active-uprobe logic
is not exactly right. We can race with another thread which
unmaps the memory with the valid uprobe before we take
mm->mmap_sem. We can't find this uprobe simply because
find_vma() fails. In this case we wrongly assume that this trap
was not caused by uprobe and send the erroneous SIGTRAP. See the
next changes.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Anton Arapov <anton@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20120529192857.GC8057@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/events')
-rw-r--r-- | kernel/events/uprobes.c | 47 |
1 files changed, 28 insertions, 19 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index a0dbc87a2ec6..eaf4d55fd424 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -1489,38 +1489,47 @@ static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs) | |||
1489 | return false; | 1489 | return false; |
1490 | } | 1490 | } |
1491 | 1491 | ||
1492 | /* | 1492 | static struct uprobe *find_active_uprobe(unsigned long bp_vaddr) |
1493 | * Run handler and ask thread to singlestep. | ||
1494 | * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. | ||
1495 | */ | ||
1496 | static void handle_swbp(struct pt_regs *regs) | ||
1497 | { | 1493 | { |
1494 | struct mm_struct *mm = current->mm; | ||
1495 | struct uprobe *uprobe = NULL; | ||
1498 | struct vm_area_struct *vma; | 1496 | struct vm_area_struct *vma; |
1499 | struct uprobe_task *utask; | ||
1500 | struct uprobe *uprobe; | ||
1501 | struct mm_struct *mm; | ||
1502 | unsigned long bp_vaddr; | ||
1503 | 1497 | ||
1504 | uprobe = NULL; | ||
1505 | bp_vaddr = uprobe_get_swbp_addr(regs); | ||
1506 | mm = current->mm; | ||
1507 | down_read(&mm->mmap_sem); | 1498 | down_read(&mm->mmap_sem); |
1508 | vma = find_vma(mm, bp_vaddr); | 1499 | vma = find_vma(mm, bp_vaddr); |
1509 | 1500 | ||
1510 | if (vma && vma->vm_start <= bp_vaddr && valid_vma(vma, false)) { | 1501 | if (vma && vma->vm_start <= bp_vaddr) { |
1511 | struct inode *inode; | 1502 | if (valid_vma(vma, false)) { |
1512 | loff_t offset; | 1503 | struct inode *inode; |
1504 | loff_t offset; | ||
1513 | 1505 | ||
1514 | inode = vma->vm_file->f_mapping->host; | 1506 | inode = vma->vm_file->f_mapping->host; |
1515 | offset = bp_vaddr - vma->vm_start; | 1507 | offset = bp_vaddr - vma->vm_start; |
1516 | offset += (vma->vm_pgoff << PAGE_SHIFT); | 1508 | offset += (vma->vm_pgoff << PAGE_SHIFT); |
1517 | uprobe = find_uprobe(inode, offset); | 1509 | uprobe = find_uprobe(inode, offset); |
1510 | } | ||
1518 | } | 1511 | } |
1519 | 1512 | ||
1520 | srcu_read_unlock_raw(&uprobes_srcu, current->uprobe_srcu_id); | 1513 | srcu_read_unlock_raw(&uprobes_srcu, current->uprobe_srcu_id); |
1521 | current->uprobe_srcu_id = -1; | 1514 | current->uprobe_srcu_id = -1; |
1522 | up_read(&mm->mmap_sem); | 1515 | up_read(&mm->mmap_sem); |
1523 | 1516 | ||
1517 | return uprobe; | ||
1518 | } | ||
1519 | |||
1520 | /* | ||
1521 | * Run handler and ask thread to singlestep. | ||
1522 | * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. | ||
1523 | */ | ||
1524 | static void handle_swbp(struct pt_regs *regs) | ||
1525 | { | ||
1526 | struct uprobe_task *utask; | ||
1527 | struct uprobe *uprobe; | ||
1528 | unsigned long bp_vaddr; | ||
1529 | |||
1530 | bp_vaddr = uprobe_get_swbp_addr(regs); | ||
1531 | uprobe = find_active_uprobe(bp_vaddr); | ||
1532 | |||
1524 | if (!uprobe) { | 1533 | if (!uprobe) { |
1525 | /* No matching uprobe; signal SIGTRAP. */ | 1534 | /* No matching uprobe; signal SIGTRAP. */ |
1526 | send_sig(SIGTRAP, current, 0); | 1535 | send_sig(SIGTRAP, current, 0); |