userns-don-t-let-unprivileged-users-trick-privileged-users-into-setting-the-id_map.patch
userns-check-uid_map-s-opener-s-fsuid-not-the-current-fsuid.patch
userns-changing-any-namespace-id-mappings-should-require-privileges.patch
+vm-add-vm_iomap_memory-helper-function.patch
+vm-convert-snd_pcm_lib_mmap_iomem-to-vm_iomap_memory-helper.patch
+vm-convert-fb_mmap-to-vm_iomap_memory-helper.patch
+vm-convert-hpet-mmap-to-vm_iomap_memory-helper.patch
+vm-convert-mtdchar-mmap-to-vm_iomap_memory-helper.patch
--- /dev/null
+From b4cbb197c7e7a68dbad0d491242e3ca67420c13e Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Tue, 16 Apr 2013 13:45:37 -0700
+Subject: vm: add vm_iomap_memory() helper function
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit b4cbb197c7e7a68dbad0d491242e3ca67420c13e upstream.
+
+Various drivers end up replicating the code to mmap() their memory
+buffers into user space, and our core memory remapping function may be
+very flexible but it is unnecessarily complicated for the common cases
+to use.
+
+Our internal VM uses pfn's ("page frame numbers") which simplifies
+things for the VM, and allows us to pass physical addresses around in a
+denser and more efficient format than passing a "phys_addr_t" around,
+and having to shift it up and down by the page size. But it just means
+that drivers end up doing that shifting instead at the interface level.
+
+It also means that drivers end up mucking around with internal VM things
+like the vma details (vm_pgoff, vm_start/end) way more than they really
+need to.
+
+So this just exports a function to map a certain physical memory range
+into user space (using a phys_addr_t based interface that is much more
+natural for a driver) and hides all the complexity from the driver.
+Some drivers will still end up tweaking the vm_page_prot details for
+things like prefetching or cacheability etc, but that's actually
+relevant to the driver, rather than caring about what the page offset of
+the mapping is into the particular IO memory region.
+
+Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+
+---
+ include/linux/mm.h | 2 ++
+ mm/memory.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+)
+
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -1623,6 +1623,8 @@ int vm_insert_pfn(struct vm_area_struct
+ unsigned long pfn);
+ int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn);
++int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len);
++
+
+ struct page *follow_page(struct vm_area_struct *, unsigned long address,
+ unsigned int foll_flags);
+--- a/mm/memory.c
++++ b/mm/memory.c
+@@ -2358,6 +2358,53 @@ int remap_pfn_range(struct vm_area_struc
+ }
+ EXPORT_SYMBOL(remap_pfn_range);
+
++/**
++ * vm_iomap_memory - remap memory to userspace
++ * @vma: user vma to map to
++ * @start: start of area
++ * @len: size of area
++ *
++ * This is a simplified io_remap_pfn_range() for common driver use. The
++ * driver just needs to give us the physical memory range to be mapped,
++ * we'll figure out the rest from the vma information.
++ *
++ * NOTE! Some drivers might want to tweak vma->vm_page_prot first to get
++ * whatever write-combining details or similar.
++ */
++int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len)
++{
++ unsigned long vm_len, pfn, pages;
++
++ /* Check that the physical memory area passed in looks valid */
++ if (start + len < start)
++ return -EINVAL;
++ /*
++ * You *really* shouldn't map things that aren't page-aligned,
++ * but we've historically allowed it because IO memory might
++ * just have smaller alignment.
++ */
++ len += start & ~PAGE_MASK;
++ pfn = start >> PAGE_SHIFT;
++ pages = (len + ~PAGE_MASK) >> PAGE_SHIFT;
++ if (pfn + pages < pfn)
++ return -EINVAL;
++
++ /* We start the mapping 'vm_pgoff' pages into the area */
++ if (vma->vm_pgoff > pages)
++ return -EINVAL;
++ pfn += vma->vm_pgoff;
++ pages -= vma->vm_pgoff;
++
++ /* Can we fit all of the mapping? */
++ vm_len = vma->vm_end - vma->vm_start;
++ if (vm_len >> PAGE_SHIFT > pages)
++ return -EINVAL;
++
++ /* Ok, let it rip */
++ return io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot);
++}
++EXPORT_SYMBOL(vm_iomap_memory);
++
+ static int apply_to_pte_range(struct mm_struct *mm, pmd_t *pmd,
+ unsigned long addr, unsigned long end,
+ pte_fn_t fn, void *data)
--- /dev/null
+From fc9bbca8f650e5f738af8806317c0a041a48ae4a Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Fri, 19 Apr 2013 09:57:35 -0700
+Subject: vm: convert fb_mmap to vm_iomap_memory() helper
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit fc9bbca8f650e5f738af8806317c0a041a48ae4a upstream.
+
+This is my example conversion of a few existing mmap users. The
+fb_mmap() case is a good example because it is a bit more complicated
+than some: fb_mmap() mmaps one of two different memory areas depending
+on the page offset of the mmap (but happily there is never any mixing of
+the two, so the helper function still works).
+
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/video/fbmem.c | 39 ++++++++++++++-------------------------
+ 1 file changed, 14 insertions(+), 25 deletions(-)
+
+--- a/drivers/video/fbmem.c
++++ b/drivers/video/fbmem.c
+@@ -1373,15 +1373,12 @@ fb_mmap(struct file *file, struct vm_are
+ {
+ struct fb_info *info = file_fb_info(file);
+ struct fb_ops *fb;
+- unsigned long off;
++ unsigned long mmio_pgoff;
+ unsigned long start;
+ u32 len;
+
+ if (!info)
+ return -ENODEV;
+- if (vma->vm_pgoff > (~0UL >> PAGE_SHIFT))
+- return -EINVAL;
+- off = vma->vm_pgoff << PAGE_SHIFT;
+ fb = info->fbops;
+ if (!fb)
+ return -ENODEV;
+@@ -1393,32 +1390,24 @@ fb_mmap(struct file *file, struct vm_are
+ return res;
+ }
+
+- /* frame buffer memory */
++ /*
++ * Ugh. This can be either the frame buffer mapping, or
++ * if pgoff points past it, the mmio mapping.
++ */
+ start = info->fix.smem_start;
+- len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
+- if (off >= len) {
+- /* memory mapped io */
+- off -= len;
+- if (info->var.accel_flags) {
+- mutex_unlock(&info->mm_lock);
+- return -EINVAL;
+- }
++ len = info->fix.smem_len;
++ mmio_pgoff = PAGE_ALIGN((start & ~PAGE_MASK) + len) >> PAGE_SHIFT;
++ if (vma->vm_pgoff >= mmio_pgoff) {
++ vma->vm_pgoff -= mmio_pgoff;
+ start = info->fix.mmio_start;
+- len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.mmio_len);
++ len = info->fix.mmio_len;
+ }
+ mutex_unlock(&info->mm_lock);
+- start &= PAGE_MASK;
+- if ((vma->vm_end - vma->vm_start + off) > len)
+- return -EINVAL;
+- off += start;
+- vma->vm_pgoff = off >> PAGE_SHIFT;
+- /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by io_remap_pfn_range()*/
++
+ vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
+- fb_pgprotect(file, vma, off);
+- if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+- vma->vm_end - vma->vm_start, vma->vm_page_prot))
+- return -EAGAIN;
+- return 0;
++ fb_pgprotect(file, vma, start);
++
++ return vm_iomap_memory(vma, start, len);
+ }
+
+ static int
--- /dev/null
+From 2323036dfec8ce3ce6e1c86a49a31b039f3300d1 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Fri, 19 Apr 2013 09:46:39 -0700
+Subject: vm: convert HPET mmap to vm_iomap_memory() helper
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit 2323036dfec8ce3ce6e1c86a49a31b039f3300d1 upstream.
+
+This is my example conversion of a few existing mmap users. The HPET
+case is simple, widely available, and easy to test (Clemens Ladisch sent
+a trivial test-program for it).
+
+Test-program-by: Clemens Ladisch <clemens@ladisch.de>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/hpet.c | 14 +-------------
+ 1 file changed, 1 insertion(+), 13 deletions(-)
+
+--- a/drivers/char/hpet.c
++++ b/drivers/char/hpet.c
+@@ -373,26 +373,14 @@ static int hpet_mmap(struct file *file,
+ struct hpet_dev *devp;
+ unsigned long addr;
+
+- if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
+- return -EINVAL;
+-
+ devp = file->private_data;
+ addr = devp->hd_hpets->hp_hpet_phys;
+
+ if (addr & (PAGE_SIZE - 1))
+ return -ENOSYS;
+
+- vma->vm_flags |= VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+-
+- if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
+- PAGE_SIZE, vma->vm_page_prot)) {
+- printk(KERN_ERR "%s: io_remap_pfn_range failed\n",
+- __func__);
+- return -EAGAIN;
+- }
+-
+- return 0;
++ return vm_iomap_memory(vma, addr, PAGE_SIZE);
+ #else
+ return -ENOSYS;
+ #endif
--- /dev/null
+From 8558e4a26b00225efeb085725bc319f91201b239 Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Fri, 19 Apr 2013 09:53:07 -0700
+Subject: vm: convert mtdchar mmap to vm_iomap_memory() helper
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit 8558e4a26b00225efeb085725bc319f91201b239 upstream.
+
+This is my example conversion of a few existing mmap users. The mtdchar
+case is actually disabled right now (and stays disabled), but I did it
+because it showed up on my "git grep", and I was familiar with the code
+due to fixing an overflow problem in the code in commit 9c603e53d380
+("mtdchar: fix offset overflow detection").
+
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/mtd/mtdchar.c | 32 ++------------------------------
+ 1 file changed, 2 insertions(+), 30 deletions(-)
+
+--- a/drivers/mtd/mtdchar.c
++++ b/drivers/mtd/mtdchar.c
+@@ -1159,45 +1159,17 @@ static int mtdchar_mmap(struct file *fil
+ struct mtd_file_info *mfi = file->private_data;
+ struct mtd_info *mtd = mfi->mtd;
+ struct map_info *map = mtd->priv;
+- resource_size_t start, off;
+- unsigned long len, vma_len;
+
+ /* This is broken because it assumes the MTD device is map-based
+ and that mtd->priv is a valid struct map_info. It should be
+ replaced with something that uses the mtd_get_unmapped_area()
+ operation properly. */
+ if (0 /*mtd->type == MTD_RAM || mtd->type == MTD_ROM*/) {
+- off = get_vm_offset(vma);
+- start = map->phys;
+- len = PAGE_ALIGN((start & ~PAGE_MASK) + map->size);
+- start &= PAGE_MASK;
+- vma_len = get_vm_size(vma);
+-
+- /* Overflow in off+len? */
+- if (vma_len + off < off)
+- return -EINVAL;
+- /* Does it fit in the mapping? */
+- if (vma_len + off > len)
+- return -EINVAL;
+-
+- off += start;
+- /* Did that overflow? */
+- if (off < start)
+- return -EINVAL;
+- if (set_vm_offset(vma, off) < 0)
+- return -EINVAL;
+- vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
+-
+ #ifdef pgprot_noncached
+- if (file->f_flags & O_DSYNC || off >= __pa(high_memory))
++ if (file->f_flags & O_DSYNC || map->phys >= __pa(high_memory))
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ #endif
+- if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT,
+- vma->vm_end - vma->vm_start,
+- vma->vm_page_prot))
+- return -EAGAIN;
+-
+- return 0;
++ return vm_iomap_memory(vma, map->phys, map->size);
+ }
+ return -ENOSYS;
+ #else
--- /dev/null
+From 0fe09a45c4848b5b5607b968d959fdc1821c161d Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Fri, 19 Apr 2013 10:01:04 -0700
+Subject: vm: convert snd_pcm_lib_mmap_iomem() to vm_iomap_memory() helper
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit 0fe09a45c4848b5b5607b968d959fdc1821c161d upstream.
+
+This is my example conversion of a few existing mmap users. The pcm
+mmap case is one of the more straightforward ones.
+
+Acked-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/pcm_native.c | 12 ++----------
+ 1 file changed, 2 insertions(+), 10 deletions(-)
+
+--- a/sound/core/pcm_native.c
++++ b/sound/core/pcm_native.c
+@@ -3222,18 +3222,10 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mm
+ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
+ struct vm_area_struct *area)
+ {
+- long size;
+- unsigned long offset;
++ struct snd_pcm_runtime *runtime = substream->runtime;;
+
+ area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
+- area->vm_flags |= VM_IO;
+- size = area->vm_end - area->vm_start;
+- offset = area->vm_pgoff << PAGE_SHIFT;
+- if (io_remap_pfn_range(area, area->vm_start,
+- (substream->runtime->dma_addr + offset) >> PAGE_SHIFT,
+- size, area->vm_page_prot))
+- return -EAGAIN;
+- return 0;
++ return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes);
+ }
+
+ EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);