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: Nick Piggin <npiggin@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Nick Piggin and committed by
Linus Torvalds
2f98735c fe2528b9

+13 -16
+2
drivers/char/drm/drm_vm.c
··· 506 506 vma->vm_ops = &drm_vm_dma_ops; 507 507 508 508 vma->vm_flags |= VM_RESERVED; /* Don't swap */ 509 + vma->vm_flags |= VM_DONTEXPAND; 509 510 510 511 vma->vm_file = filp; /* Needed for drm_vm_open() */ 511 512 drm_vm_open_locked(vma); ··· 656 655 return -EINVAL; /* This should never happen. */ 657 656 } 658 657 vma->vm_flags |= VM_RESERVED; /* Don't swap */ 658 + vma->vm_flags |= VM_DONTEXPAND; 659 659 660 660 vma->vm_file = filp; /* Needed for drm_vm_open() */ 661 661 drm_vm_open_locked(vma);
+1 -1
drivers/char/mspec.c
··· 283 283 vdata->refcnt = ATOMIC_INIT(1); 284 284 vma->vm_private_data = vdata; 285 285 286 - vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP); 286 + vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND); 287 287 if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED) 288 288 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); 289 289 vma->vm_ops = &mspec_vm_ops;
-4
fs/ncpfs/mmap.c
··· 50 50 pos = vmf->pgoff << PAGE_SHIFT; 51 51 52 52 count = PAGE_SIZE; 53 - if ((unsigned long)vmf->virtual_address + PAGE_SIZE > area->vm_end) { 54 - WARN_ON(1); /* shouldn't happen? */ 55 - count = area->vm_end - (unsigned long)vmf->virtual_address; 56 - } 57 53 /* what we can read in one go */ 58 54 bufsize = NCP_SERVER(inode)->buffer_size; 59 55
+1
kernel/relay.c
··· 92 92 return -EINVAL; 93 93 94 94 vma->vm_ops = &relay_file_mmap_ops; 95 + vma->vm_flags |= VM_DONTEXPAND; 95 96 vma->vm_private_data = buf; 96 97 buf->chan->cb->buf_mapped(buf, filp); 97 98
+1 -1
mm/mmap.c
··· 2216 2216 vma->vm_start = addr; 2217 2217 vma->vm_end = addr + len; 2218 2218 2219 - vma->vm_flags = vm_flags | mm->def_flags; 2219 + vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND; 2220 2220 vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); 2221 2221 2222 2222 vma->vm_ops = &special_mapping_vmops;
+6 -8
sound/oss/via82cxxx_audio.c
··· 2104 2104 { 2105 2105 struct via_info *card = vma->vm_private_data; 2106 2106 struct via_channel *chan = &card->ch_out; 2107 + unsigned long max_bufs; 2107 2108 struct page *dmapage; 2108 2109 unsigned long pgoff; 2109 2110 int rd, wr; ··· 2128 2127 rd = card->ch_in.is_mapped; 2129 2128 wr = card->ch_out.is_mapped; 2130 2129 2131 - #ifndef VIA_NDEBUG 2132 - { 2133 - unsigned long max_bufs = chan->frag_number; 2134 - if (rd && wr) max_bufs *= 2; 2135 - /* via_dsp_mmap() should ensure this */ 2136 - assert (pgoff < max_bufs); 2137 - } 2138 - #endif 2130 + max_bufs = chan->frag_number; 2131 + if (rd && wr) 2132 + max_bufs *= 2; 2133 + if (pgoff >= max_bufs) 2134 + return NOPAGE_SIGBUS; 2139 2135 2140 2136 /* if full-duplex (read+write) and we have two sets of bufs, 2141 2137 * then the playback buffers come first, sez soundcard.c */
+1 -1
sound/usb/usx2y/usX2Yhwdep.c
··· 84 84 us428->us428ctls_sharedmem->CtlSnapShotLast = -2; 85 85 } 86 86 area->vm_ops = &us428ctls_vm_ops; 87 - area->vm_flags |= VM_RESERVED; 87 + area->vm_flags |= VM_RESERVED | VM_DONTEXPAND; 88 88 area->vm_private_data = hw->private_data; 89 89 return 0; 90 90 }
+1 -1
sound/usb/usx2y/usx2yhwdeppcm.c
··· 722 722 return -ENODEV; 723 723 } 724 724 area->vm_ops = &snd_usX2Y_hwdep_pcm_vm_ops; 725 - area->vm_flags |= VM_RESERVED; 725 + area->vm_flags |= VM_RESERVED | VM_DONTEXPAND; 726 726 area->vm_private_data = hw->private_data; 727 727 return 0; 728 728 }