Commit 2f98735c authored by Nick Piggin's avatar Nick Piggin Committed by Linus Torvalds

vm audit: add VM_DONTEXPAND to mmap for drivers that need it

Drivers that register a ->fault handler, but do not range-check the
offset argument, must set VM_DONTEXPAND in the vm_flags in order to
prevent an expanding mremap from overflowing the resource.

I've audited the tree and attempted to fix these problems (usually by
adding VM_DONTEXPAND where it is not obvious).
Signed-off-by: default avatarNick Piggin <npiggin@suse.de>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent fe2528b9
...@@ -506,6 +506,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) ...@@ -506,6 +506,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
vma->vm_ops = &drm_vm_dma_ops; vma->vm_ops = &drm_vm_dma_ops;
vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_flags |= VM_DONTEXPAND;
vma->vm_file = filp; /* Needed for drm_vm_open() */ vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open_locked(vma); drm_vm_open_locked(vma);
...@@ -655,6 +656,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) ...@@ -655,6 +656,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
return -EINVAL; /* This should never happen. */ return -EINVAL; /* This should never happen. */
} }
vma->vm_flags |= VM_RESERVED; /* Don't swap */ vma->vm_flags |= VM_RESERVED; /* Don't swap */
vma->vm_flags |= VM_DONTEXPAND;
vma->vm_file = filp; /* Needed for drm_vm_open() */ vma->vm_file = filp; /* Needed for drm_vm_open() */
drm_vm_open_locked(vma); drm_vm_open_locked(vma);
......
...@@ -283,7 +283,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, ...@@ -283,7 +283,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma,
vdata->refcnt = ATOMIC_INIT(1); vdata->refcnt = ATOMIC_INIT(1);
vma->vm_private_data = vdata; vma->vm_private_data = vdata;
vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP); vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND);
if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED) if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
vma->vm_ops = &mspec_vm_ops; vma->vm_ops = &mspec_vm_ops;
......
...@@ -50,10 +50,6 @@ static int ncp_file_mmap_fault(struct vm_area_struct *area, ...@@ -50,10 +50,6 @@ static int ncp_file_mmap_fault(struct vm_area_struct *area,
pos = vmf->pgoff << PAGE_SHIFT; pos = vmf->pgoff << PAGE_SHIFT;
count = PAGE_SIZE; count = PAGE_SIZE;
if ((unsigned long)vmf->virtual_address + PAGE_SIZE > area->vm_end) {
WARN_ON(1); /* shouldn't happen? */
count = area->vm_end - (unsigned long)vmf->virtual_address;
}
/* what we can read in one go */ /* what we can read in one go */
bufsize = NCP_SERVER(inode)->buffer_size; bufsize = NCP_SERVER(inode)->buffer_size;
......
...@@ -92,6 +92,7 @@ static int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma) ...@@ -92,6 +92,7 @@ static int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
return -EINVAL; return -EINVAL;
vma->vm_ops = &relay_file_mmap_ops; vma->vm_ops = &relay_file_mmap_ops;
vma->vm_flags |= VM_DONTEXPAND;
vma->vm_private_data = buf; vma->vm_private_data = buf;
buf->chan->cb->buf_mapped(buf, filp); buf->chan->cb->buf_mapped(buf, filp);
......
...@@ -2216,7 +2216,7 @@ int install_special_mapping(struct mm_struct *mm, ...@@ -2216,7 +2216,7 @@ int install_special_mapping(struct mm_struct *mm,
vma->vm_start = addr; vma->vm_start = addr;
vma->vm_end = addr + len; vma->vm_end = addr + len;
vma->vm_flags = vm_flags | mm->def_flags; vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND;
vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
vma->vm_ops = &special_mapping_vmops; vma->vm_ops = &special_mapping_vmops;
......
...@@ -2104,6 +2104,7 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma, ...@@ -2104,6 +2104,7 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma,
{ {
struct via_info *card = vma->vm_private_data; struct via_info *card = vma->vm_private_data;
struct via_channel *chan = &card->ch_out; struct via_channel *chan = &card->ch_out;
unsigned long max_bufs;
struct page *dmapage; struct page *dmapage;
unsigned long pgoff; unsigned long pgoff;
int rd, wr; int rd, wr;
...@@ -2127,14 +2128,11 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma, ...@@ -2127,14 +2128,11 @@ static struct page * via_mm_nopage (struct vm_area_struct * vma,
rd = card->ch_in.is_mapped; rd = card->ch_in.is_mapped;
wr = card->ch_out.is_mapped; wr = card->ch_out.is_mapped;
#ifndef VIA_NDEBUG max_bufs = chan->frag_number;
{ if (rd && wr)
unsigned long max_bufs = chan->frag_number; max_bufs *= 2;
if (rd && wr) max_bufs *= 2; if (pgoff >= max_bufs)
/* via_dsp_mmap() should ensure this */ return NOPAGE_SIGBUS;
assert (pgoff < max_bufs);
}
#endif
/* if full-duplex (read+write) and we have two sets of bufs, /* if full-duplex (read+write) and we have two sets of bufs,
* then the playback buffers come first, sez soundcard.c */ * then the playback buffers come first, sez soundcard.c */
......
...@@ -84,7 +84,7 @@ static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct v ...@@ -84,7 +84,7 @@ static int snd_us428ctls_mmap(struct snd_hwdep * hw, struct file *filp, struct v
us428->us428ctls_sharedmem->CtlSnapShotLast = -2; us428->us428ctls_sharedmem->CtlSnapShotLast = -2;
} }
area->vm_ops = &us428ctls_vm_ops; area->vm_ops = &us428ctls_vm_ops;
area->vm_flags |= VM_RESERVED; area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
area->vm_private_data = hw->private_data; area->vm_private_data = hw->private_data;
return 0; return 0;
} }
......
...@@ -722,7 +722,7 @@ static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, st ...@@ -722,7 +722,7 @@ static int snd_usX2Y_hwdep_pcm_mmap(struct snd_hwdep * hw, struct file *filp, st
return -ENODEV; return -ENODEV;
} }
area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops; area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops;
area->vm_flags |= VM_RESERVED; area->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
area->vm_private_data = hw->private_data; area->vm_private_data = hw->private_data;
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment