diff options
author | Oleg Nesterov <oleg@redhat.com> | 2012-12-28 11:58:38 -0500 |
---|---|---|
committer | Oleg Nesterov <oleg@redhat.com> | 2013-02-08 11:47:10 -0500 |
commit | 8a7f2fa0dea3b019500961b86d765e6fdd4bffb2 (patch) | |
tree | c6c467e02da75a9e92f8541cf8889dbd0e2fe5fb /kernel/events | |
parent | 806a98bdf2a862fef0fc880399d677b35ba525ff (diff) |
uprobes: Reintroduce uprobe_consumer->filter()
Finally add uprobe_consumer->filter() and change consumer_filter()
to actually call this method.
Note that ->filter() accepts mm_struct, not task_struct. Because:
1. We do not have for_each_mm_user(mm, task).
2. Even if we implement for_each_mm_user(), ->filter() can
use it itself.
3. It is not clear who will actually need this interface to
do the "nontrivial" filtering.
Another argument is "enum uprobe_filter_ctx", consumer->filter() can
use it to figure out why/where it was called. For example, perhaps
we can add UPROBE_FILTER_PRE_REGISTER used by build_map_info() to
quickly "nack" the unwanted mm's. In this case consumer should know
that it is called under ->i_mmap_mutex.
See the previous discussion at http://marc.info/?t=135214229700002
Perhaps we should pass more arguments, vma/vaddr?
Note: this patch obviously can't help to filter out the child created
by fork(), this will be addressed later.
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 | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 33912086d54e..c2737be3c4b8 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -579,19 +579,21 @@ static int prepare_uprobe(struct uprobe *uprobe, struct file *file, | |||
579 | return ret; | 579 | return ret; |
580 | } | 580 | } |
581 | 581 | ||
582 | static inline bool consumer_filter(struct uprobe_consumer *uc) | 582 | static inline bool consumer_filter(struct uprobe_consumer *uc, |
583 | enum uprobe_filter_ctx ctx, struct mm_struct *mm) | ||
583 | { | 584 | { |
584 | return true; /* TODO: !uc->filter || uc->filter(...) */ | 585 | return !uc->filter || uc->filter(uc, ctx, mm); |
585 | } | 586 | } |
586 | 587 | ||
587 | static bool filter_chain(struct uprobe *uprobe) | 588 | static bool filter_chain(struct uprobe *uprobe, |
589 | enum uprobe_filter_ctx ctx, struct mm_struct *mm) | ||
588 | { | 590 | { |
589 | struct uprobe_consumer *uc; | 591 | struct uprobe_consumer *uc; |
590 | bool ret = false; | 592 | bool ret = false; |
591 | 593 | ||
592 | down_read(&uprobe->consumer_rwsem); | 594 | down_read(&uprobe->consumer_rwsem); |
593 | for (uc = uprobe->consumers; uc; uc = uc->next) { | 595 | for (uc = uprobe->consumers; uc; uc = uc->next) { |
594 | ret = consumer_filter(uc); | 596 | ret = consumer_filter(uc, ctx, mm); |
595 | if (ret) | 597 | if (ret) |
596 | break; | 598 | break; |
597 | } | 599 | } |
@@ -772,10 +774,12 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) | |||
772 | 774 | ||
773 | if (is_register) { | 775 | if (is_register) { |
774 | /* consult only the "caller", new consumer. */ | 776 | /* consult only the "caller", new consumer. */ |
775 | if (consumer_filter(uprobe->consumers)) | 777 | if (consumer_filter(uprobe->consumers, |
778 | UPROBE_FILTER_REGISTER, mm)) | ||
776 | err = install_breakpoint(uprobe, mm, vma, info->vaddr); | 779 | err = install_breakpoint(uprobe, mm, vma, info->vaddr); |
777 | } else if (test_bit(MMF_HAS_UPROBES, &mm->flags)) { | 780 | } else if (test_bit(MMF_HAS_UPROBES, &mm->flags)) { |
778 | if (!filter_chain(uprobe)) | 781 | if (!filter_chain(uprobe, |
782 | UPROBE_FILTER_UNREGISTER, mm)) | ||
779 | err |= remove_breakpoint(uprobe, mm, info->vaddr); | 783 | err |= remove_breakpoint(uprobe, mm, info->vaddr); |
780 | } | 784 | } |
781 | 785 | ||
@@ -968,7 +972,7 @@ int uprobe_mmap(struct vm_area_struct *vma) | |||
968 | */ | 972 | */ |
969 | list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { | 973 | list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { |
970 | if (!fatal_signal_pending(current) && | 974 | if (!fatal_signal_pending(current) && |
971 | filter_chain(uprobe)) { | 975 | filter_chain(uprobe, UPROBE_FILTER_MMAP, vma->vm_mm)) { |
972 | unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset); | 976 | unsigned long vaddr = offset_to_vaddr(vma, uprobe->offset); |
973 | install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); | 977 | install_breakpoint(uprobe, vma->vm_mm, vma, vaddr); |
974 | } | 978 | } |