diff options
| author | Oleg Nesterov <oleg@redhat.com> | 2012-07-29 14:22:29 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2012-07-30 05:27:20 -0400 |
| commit | 665605a2a207dbe1fa429b474f932d6ea138ba92 (patch) | |
| tree | a9f99fcb3972a73066af4591dd3e818b8b14ab27 /kernel/events | |
| parent | 9f92448ceeea5326db7d114005a7e7ac03904edf (diff) | |
uprobes: Uprobe_mmap/munmap needs list_for_each_entry_safe()
The bug was introduced by me in 449d0d7c ("uprobes: Simplify the
usage of uprobe->pending_list").
Yes, we do not care about uprobe->pending_list after return and
nobody can remove the current list entry, but put_uprobe(uprobe)
can actually free it and thus we need list_for_each_safe().
Reported-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Srikar Dronamraju <srikar.vnet.ibm.com>
Cc: Anton Arapov <anton@redhat.com>
Link: http://lkml.kernel.org/r/20120729182229.GA20329@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel/events')
| -rw-r--r-- | kernel/events/uprobes.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 5db150b306d2..bed2161620d7 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
| @@ -1010,7 +1010,7 @@ static void build_probe_list(struct inode *inode, struct list_head *head) | |||
| 1010 | int uprobe_mmap(struct vm_area_struct *vma) | 1010 | int uprobe_mmap(struct vm_area_struct *vma) |
| 1011 | { | 1011 | { |
| 1012 | struct list_head tmp_list; | 1012 | struct list_head tmp_list; |
| 1013 | struct uprobe *uprobe; | 1013 | struct uprobe *uprobe, *u; |
| 1014 | struct inode *inode; | 1014 | struct inode *inode; |
| 1015 | int ret, count; | 1015 | int ret, count; |
| 1016 | 1016 | ||
| @@ -1028,7 +1028,7 @@ int uprobe_mmap(struct vm_area_struct *vma) | |||
| 1028 | ret = 0; | 1028 | ret = 0; |
| 1029 | count = 0; | 1029 | count = 0; |
| 1030 | 1030 | ||
| 1031 | list_for_each_entry(uprobe, &tmp_list, pending_list) { | 1031 | list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { |
| 1032 | if (!ret) { | 1032 | if (!ret) { |
| 1033 | loff_t vaddr = vma_address(vma, uprobe->offset); | 1033 | loff_t vaddr = vma_address(vma, uprobe->offset); |
| 1034 | 1034 | ||
| @@ -1076,7 +1076,7 @@ int uprobe_mmap(struct vm_area_struct *vma) | |||
| 1076 | void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) | 1076 | void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) |
| 1077 | { | 1077 | { |
| 1078 | struct list_head tmp_list; | 1078 | struct list_head tmp_list; |
| 1079 | struct uprobe *uprobe; | 1079 | struct uprobe *uprobe, *u; |
| 1080 | struct inode *inode; | 1080 | struct inode *inode; |
| 1081 | 1081 | ||
| 1082 | if (!atomic_read(&uprobe_events) || !valid_vma(vma, false)) | 1082 | if (!atomic_read(&uprobe_events) || !valid_vma(vma, false)) |
| @@ -1093,7 +1093,7 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon | |||
| 1093 | mutex_lock(uprobes_mmap_hash(inode)); | 1093 | mutex_lock(uprobes_mmap_hash(inode)); |
| 1094 | build_probe_list(inode, &tmp_list); | 1094 | build_probe_list(inode, &tmp_list); |
| 1095 | 1095 | ||
| 1096 | list_for_each_entry(uprobe, &tmp_list, pending_list) { | 1096 | list_for_each_entry_safe(uprobe, u, &tmp_list, pending_list) { |
| 1097 | loff_t vaddr = vma_address(vma, uprobe->offset); | 1097 | loff_t vaddr = vma_address(vma, uprobe->offset); |
| 1098 | 1098 | ||
| 1099 | if (vaddr >= start && vaddr < end) { | 1099 | if (vaddr >= start && vaddr < end) { |
