aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/events
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-05-29 15:28:57 -0400
committerIngo Molnar <mingo@kernel.org>2012-06-06 11:15:17 -0400
commit3a9ea0520f38def4a3915b91f82455b749f07d88 (patch)
tree810a4d5bb6f075497ad3b2cd94c120ae235e026f /kernel/events
parenta3d7bb47937b3a40b9f0c75655e97b3bb6407cbe (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.c47
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/* 1492static 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 */
1496static 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 */
1524static 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);