diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-28 11:41:51 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-09-28 18:06:21 +0100 |
commit | aa45ee8fc0ee87c1711b5fe8eb3556d06530c39e (patch) | |
tree | 4fd5a65dd1dda67ba8e2c4857bf1c7f5c19edaf8 /arch/arm/kernel | |
parent | 90140c30a7b8c77e8872a389d48678d78e58789f (diff) | |
download | lwn-aa45ee8fc0ee87c1711b5fe8eb3556d06530c39e.tar.gz lwn-aa45ee8fc0ee87c1711b5fe8eb3556d06530c39e.zip |
ARM: Ensure do_cache_op takes mmap_sem
do_cache_op() uses find_vma() to validate its arguments without holding
any locking. This means that the VMA could vanish beneath us. Fix
this by taking a read lock on mmap_sem.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r-- | arch/arm/kernel/traps.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 57eb0f6f6005..467b69ed1021 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c @@ -418,12 +418,14 @@ static int bad_syscall(int n, struct pt_regs *regs) static inline void do_cache_op(unsigned long start, unsigned long end, int flags) { + struct mm_struct *mm = current->active_mm; struct vm_area_struct *vma; if (end < start || flags) return; - vma = find_vma(current->active_mm, start); + down_read(&mm->mmap_sem); + vma = find_vma(mm, start); if (vma && vma->vm_start < end) { if (start < vma->vm_start) start = vma->vm_start; @@ -432,6 +434,7 @@ do_cache_op(unsigned long start, unsigned long end, int flags) flush_cache_user_range(vma, start, end); } + up_read(&mm->mmap_sem); } /* |