diff options
Diffstat (limited to 'kernel/events/uprobes.c')
-rw-r--r-- | kernel/events/uprobes.c | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 5ce99cfd2e6e..dea7acfbb071 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/ptrace.h> /* user_enable_single_step */ | 33 | #include <linux/ptrace.h> /* user_enable_single_step */ |
34 | #include <linux/kdebug.h> /* notifier mechanism */ | 34 | #include <linux/kdebug.h> /* notifier mechanism */ |
35 | #include "../../mm/internal.h" /* munlock_vma_page */ | 35 | #include "../../mm/internal.h" /* munlock_vma_page */ |
36 | #include <linux/percpu-rwsem.h> | ||
36 | 37 | ||
37 | #include <linux/uprobes.h> | 38 | #include <linux/uprobes.h> |
38 | 39 | ||
@@ -71,6 +72,8 @@ static struct mutex uprobes_mutex[UPROBES_HASH_SZ]; | |||
71 | static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; | 72 | static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; |
72 | #define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) | 73 | #define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) |
73 | 74 | ||
75 | static struct percpu_rw_semaphore dup_mmap_sem; | ||
76 | |||
74 | /* | 77 | /* |
75 | * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe | 78 | * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe |
76 | * events active at this time. Probably a fine grained per inode count is | 79 | * events active at this time. Probably a fine grained per inode count is |
@@ -766,10 +769,13 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) | |||
766 | struct map_info *info; | 769 | struct map_info *info; |
767 | int err = 0; | 770 | int err = 0; |
768 | 771 | ||
772 | percpu_down_write(&dup_mmap_sem); | ||
769 | info = build_map_info(uprobe->inode->i_mapping, | 773 | info = build_map_info(uprobe->inode->i_mapping, |
770 | uprobe->offset, is_register); | 774 | uprobe->offset, is_register); |
771 | if (IS_ERR(info)) | 775 | if (IS_ERR(info)) { |
772 | return PTR_ERR(info); | 776 | err = PTR_ERR(info); |
777 | goto out; | ||
778 | } | ||
773 | 779 | ||
774 | while (info) { | 780 | while (info) { |
775 | struct mm_struct *mm = info->mm; | 781 | struct mm_struct *mm = info->mm; |
@@ -799,7 +805,8 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register) | |||
799 | mmput(mm); | 805 | mmput(mm); |
800 | info = free_map_info(info); | 806 | info = free_map_info(info); |
801 | } | 807 | } |
802 | 808 | out: | |
809 | percpu_up_write(&dup_mmap_sem); | ||
803 | return err; | 810 | return err; |
804 | } | 811 | } |
805 | 812 | ||
@@ -1131,6 +1138,16 @@ void uprobe_clear_state(struct mm_struct *mm) | |||
1131 | kfree(area); | 1138 | kfree(area); |
1132 | } | 1139 | } |
1133 | 1140 | ||
1141 | void uprobe_start_dup_mmap(void) | ||
1142 | { | ||
1143 | percpu_down_read(&dup_mmap_sem); | ||
1144 | } | ||
1145 | |||
1146 | void uprobe_end_dup_mmap(void) | ||
1147 | { | ||
1148 | percpu_up_read(&dup_mmap_sem); | ||
1149 | } | ||
1150 | |||
1134 | void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) | 1151 | void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) |
1135 | { | 1152 | { |
1136 | newmm->uprobes_state.xol_area = NULL; | 1153 | newmm->uprobes_state.xol_area = NULL; |
@@ -1597,6 +1614,9 @@ static int __init init_uprobes(void) | |||
1597 | mutex_init(&uprobes_mmap_mutex[i]); | 1614 | mutex_init(&uprobes_mmap_mutex[i]); |
1598 | } | 1615 | } |
1599 | 1616 | ||
1617 | if (percpu_init_rwsem(&dup_mmap_sem)) | ||
1618 | return -ENOMEM; | ||
1619 | |||
1600 | return register_die_notifier(&uprobe_exception_nb); | 1620 | return register_die_notifier(&uprobe_exception_nb); |
1601 | } | 1621 | } |
1602 | module_init(init_uprobes); | 1622 | module_init(init_uprobes); |