History

mm: Hold a file reference in madvise_remove

Otherwise the code races with munmap (causing a use-after-free of the vma) or with close (causing a use-after-free of the struct file). The bug was introduced by commit 90ed52ebe481 ("[PATCH] holepunch: fix mmap_sem i_mutex deadlock")

Andy Lutomirski committed 14 years ago

Commit 9ab42331 parent 1b7fa4c1 file · +14 −4Browse files

Unified · Split

mm/madvise.c+14−4
@@ -15,6 +15,7 @@ · 14 unmodified lines
15#include <linux/sched.h>15#include <linux/sched.h>
16#include <linux/ksm.h>16#include <linux/ksm.h>
17#include <linux/fs.h>17#include <linux/fs.h>
18#include <linux/file.h>
18 19
19/*20/*
20 * Any behaviour which results in changes to the vma->vm_flags needs to21 * Any behaviour which results in changes to the vma->vm_flags needs to
@@ -204,14 +205,16 @@ static long madvise_remove(struct vm_area_struct *vma, · 183 unmodified lines
204{205{
205 loff_t offset;206 loff_t offset;
206 int error;207 int error;
208 struct file *f;
207 209
208 *prev = NULL; /* tell sys_madvise we drop mmap_sem */210 *prev = NULL; /* tell sys_madvise we drop mmap_sem */
209 211
210 if (vma->vm_flags & (VM_LOCKED|VM_NONLINEAR|VM_HUGETLB))212 if (vma->vm_flags & (VM_LOCKED|VM_NONLINEAR|VM_HUGETLB))
211 return -EINVAL;213 return -EINVAL;
212 214
213 if (!vma->vm_file || !vma->vm_file->f_mapping215 f = vma->vm_file;
214 || !vma->vm_file->f_mapping->host) {216
217 if (!f || !f->f_mapping || !f->f_mapping->host) {
215 return -EINVAL;218 return -EINVAL;
216 }219 }
217 220
@@ -221,11 +224,18 @@ static long madvise_remove(struct vm_area_struct *vma, · 3 unmodified lines
221 offset = (loff_t)(start - vma->vm_start)224 offset = (loff_t)(start - vma->vm_start)
222 + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);225 + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
223 226
224 /* filesystem's fallocate may need to take i_mutex */227 /*
228 * Filesystem's fallocate may need to take i_mutex. We need to
229 * explicitly grab a reference because the vma (and hence the
230 * vma's reference to the file) can go away as soon as we drop
231 * mmap_sem.
232 */
233 get_file(f);
225 up_read(&current->mm->mmap_sem);234 up_read(&current->mm->mmap_sem);
226 error = do_fallocate(vma->vm_file,235 error = do_fallocate(f,
227 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,236 FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
228 offset, end - start);237 offset, end - start);
238 fput(f);
229 down_read(&current->mm->mmap_sem);239 down_read(&current->mm->mmap_sem);
230 return error;240 return error;
231}241}