linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/6] mm: audit find_vma() callers
@ 2014-04-20  2:26 Davidlohr Bueso
  2014-04-20  2:26 ` [PATCH 1/6] blackfin/ptrace: call find_vma with the mmap_sem held Davidlohr Bueso
                   ` (6 more replies)
  0 siblings, 7 replies; 17+ messages in thread
From: Davidlohr Bueso @ 2014-04-20  2:26 UTC (permalink / raw)
  To: akpm; +Cc: zeus, aswin, davidlohr, linux-mm, linux-kernel

Ensure find_vma() callers do so with the mmap_sem held. 

I'm sure there are a few more places left to fix, but 
this is a pretty good start. Following the call chain,
some users become all tangled up, but I believe these
fixes are correct. Furthermore, the bulk of the callers
of find_vma are in a lot of functions where it is well
known that the mmap_sem is taken way before, such as
get_unmapped_area() family.

Please note that none of the patches are tested.

Thanks!

  blackfin/ptrace: call find_vma with the mmap_sem held
  m68k: call find_vma with the mmap_sem held in sys_cacheflush()
  mips: call find_vma with the mmap_sem held
  arc: call find_vma with the mmap_sem held
  drivers/misc/sgi-gru/grufault.c: call find_vma with the mmap_sem held
  drm/exynos: call find_vma with the mmap_sem held

 arch/arc/kernel/troubleshoot.c          |  7 ++++---
 arch/blackfin/kernel/ptrace.c           |  8 ++++++--
 arch/m68k/kernel/sys_m68k.c             | 18 ++++++++++++------
 arch/mips/kernel/traps.c                |  2 ++
 arch/mips/mm/c-octeon.c                 |  2 ++
 drivers/gpu/drm/exynos/exynos_drm_g2d.c |  6 ++++++
 drivers/misc/sgi-gru/grufault.c         | 13 +++++++++----
 7 files changed, 41 insertions(+), 15 deletions(-)

-- 
1.8.1.4


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 1/6] blackfin/ptrace: call find_vma with the mmap_sem held
  2014-04-20  2:26 [PATCH 0/6] mm: audit find_vma() callers Davidlohr Bueso
@ 2014-04-20  2:26 ` Davidlohr Bueso
  2014-04-22  3:07   ` Steven Miao
  2014-04-20  2:26 ` [PATCH 2/6] m68k: call find_vma with the mmap_sem held in sys_cacheflush() Davidlohr Bueso
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 17+ messages in thread
From: Davidlohr Bueso @ 2014-04-20  2:26 UTC (permalink / raw)
  To: akpm
  Cc: zeus, aswin, davidlohr, linux-mm, linux-kernel, Steven Miao,
	adi-buildroot-devel

Performing vma lookups without taking the mm->mmap_sem is asking
for trouble. While doing the search, the vma in question can be
modified or even removed before returning to the caller. Take the
lock (shared) in order to avoid races while iterating through the
vmacache and/or rbtree.

This patch is completely *untested*.

Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
Cc: Steven Miao <realmz6@gmail.com>
Cc: adi-buildroot-devel@lists.sourceforge.net
---
 arch/blackfin/kernel/ptrace.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index e1f88e0..8b8fe67 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -117,6 +117,7 @@ put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
 int
 is_user_addr_valid(struct task_struct *child, unsigned long start, unsigned long len)
 {
+	bool valid;
 	struct vm_area_struct *vma;
 	struct sram_list_struct *sraml;
 
@@ -124,9 +125,12 @@ is_user_addr_valid(struct task_struct *child, unsigned long start, unsigned long
 	if (start + len < start)
 		return -EIO;
 
+	down_read(&child->mm->mmap_sem);
 	vma = find_vma(child->mm, start);
-	if (vma && start >= vma->vm_start && start + len <= vma->vm_end)
-			return 0;
+	valid = vma && start >= vma->vm_start && start + len <= vma->vm_end;
+	up_read(&child->mm->mmap_sem);
+	if (valid)
+		return 0;
 
 	for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
 		if (start >= (unsigned long)sraml->addr
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 2/6] m68k: call find_vma with the mmap_sem held in sys_cacheflush()
  2014-04-20  2:26 [PATCH 0/6] mm: audit find_vma() callers Davidlohr Bueso
  2014-04-20  2:26 ` [PATCH 1/6] blackfin/ptrace: call find_vma with the mmap_sem held Davidlohr Bueso
@ 2014-04-20  2:26 ` Davidlohr Bueso
  2014-04-20  8:04   ` Geert Uytterhoeven
  2014-04-20  2:26 ` [PATCH 3/6] mips: call find_vma with the mmap_sem held Davidlohr Bueso
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 17+ messages in thread
From: Davidlohr Bueso @ 2014-04-20  2:26 UTC (permalink / raw)
  To: akpm
  Cc: zeus, aswin, davidlohr, linux-mm, linux-kernel,
	Geert Uytterhoeven, linux-m68k

Performing vma lookups without taking the mm->mmap_sem is asking
for trouble. While doing the search, the vma in question can be
modified or even removed before returning to the caller. Take the
lock (shared) in order to avoid races while iterating through
the vmacache and/or rbtree.

This patch is completely *untested*.

Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
Cc: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: linux-m68k@lists.linux-m68k.org
---
 arch/m68k/kernel/sys_m68k.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 3a480b3..d2263a0 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -376,7 +376,6 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
 asmlinkage int
 sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
 {
-	struct vm_area_struct *vma;
 	int ret = -EINVAL;
 
 	if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
@@ -389,16 +388,23 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
 		if (!capable(CAP_SYS_ADMIN))
 			goto out;
 	} else {
+		struct vm_area_struct *vma;
+		bool invalid;
+
+		/* Check for overflow.  */
+		if (addr + len < addr)
+			goto out;
+
 		/*
 		 * Verify that the specified address region actually belongs
 		 * to this process.
 		 */
-		vma = find_vma (current->mm, addr);
 		ret = -EINVAL;
-		/* Check for overflow.  */
-		if (addr + len < addr)
-			goto out;
-		if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
+		down_read(&current->mm->mmap_sem);
+		vma = find_vma(current->mm, addr);
+		invalid = !vma || addr < vma->vm_start || addr + len > vma->vm_end;
+		up_read(&current->mm->mmap_sem);
+		if (invalid)
 			goto out;
 	}
 
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 3/6] mips: call find_vma with the mmap_sem held
  2014-04-20  2:26 [PATCH 0/6] mm: audit find_vma() callers Davidlohr Bueso
  2014-04-20  2:26 ` [PATCH 1/6] blackfin/ptrace: call find_vma with the mmap_sem held Davidlohr Bueso
  2014-04-20  2:26 ` [PATCH 2/6] m68k: call find_vma with the mmap_sem held in sys_cacheflush() Davidlohr Bueso
@ 2014-04-20  2:26 ` Davidlohr Bueso
  2014-04-22 13:25   ` Andreas Herrmann
  2014-04-20  2:26 ` [PATCH 4/6] arc: " Davidlohr Bueso
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 17+ messages in thread
From: Davidlohr Bueso @ 2014-04-20  2:26 UTC (permalink / raw)
  To: akpm
  Cc: zeus, aswin, davidlohr, linux-mm, linux-kernel, Ralf Baechle, linux-mips

Performing vma lookups without taking the mm->mmap_sem is asking
for trouble. While doing the search, the vma in question can be
modified or even removed before returning to the caller. Take the
lock (exclusively) in order to avoid races while iterating through
the vmacache and/or rbtree.

Updates two functions:
  - process_fpemu_return()
  - cteon_flush_cache_sigtramp()

This patch is completely *untested*.

Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
---
 arch/mips/kernel/traps.c | 2 ++
 arch/mips/mm/c-octeon.c  | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 074e857..c51bd20 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -712,10 +712,12 @@ int process_fpemu_return(int sig, void __user *fault_addr)
 		si.si_addr = fault_addr;
 		si.si_signo = sig;
 		if (sig == SIGSEGV) {
+			down_read(&current->mm->mmap_sem);
 			if (find_vma(current->mm, (unsigned long)fault_addr))
 				si.si_code = SEGV_ACCERR;
 			else
 				si.si_code = SEGV_MAPERR;
+			up_read(&current->mm->mmap_sem);
 		} else {
 			si.si_code = BUS_ADRERR;
 		}
diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c
index f41a5c5..05b1d7c 100644
--- a/arch/mips/mm/c-octeon.c
+++ b/arch/mips/mm/c-octeon.c
@@ -137,8 +137,10 @@ static void octeon_flush_cache_sigtramp(unsigned long addr)
 {
 	struct vm_area_struct *vma;
 
+	down_read(&current->mm->mmap_sem);
 	vma = find_vma(current->mm, addr);
 	octeon_flush_icache_all_cores(vma);
+	up_read(&current->mm->mmap_sem);
 }
 
 
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 4/6] arc: call find_vma with the mmap_sem held
  2014-04-20  2:26 [PATCH 0/6] mm: audit find_vma() callers Davidlohr Bueso
                   ` (2 preceding siblings ...)
  2014-04-20  2:26 ` [PATCH 3/6] mips: call find_vma with the mmap_sem held Davidlohr Bueso
@ 2014-04-20  2:26 ` Davidlohr Bueso
  2014-04-22  6:02   ` Vineet Gupta
  2014-04-20  2:26 ` [PATCH 5/6] drivers,sgi-gru/grufault.c: " Davidlohr Bueso
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 17+ messages in thread
From: Davidlohr Bueso @ 2014-04-20  2:26 UTC (permalink / raw)
  To: akpm; +Cc: zeus, aswin, davidlohr, linux-mm, linux-kernel, Vineet Gupta

Performing vma lookups without taking the mm->mmap_sem is asking
for trouble. While doing the search, the vma in question can be
modified or even removed before returning to the caller. Take the
lock (shared) in order to avoid races while iterating through
the vmacache and/or rbtree.

This patch is completely *untested*.

Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
Cc: Vineet Gupta <vgupta@synopsys.com>
---
 arch/arc/kernel/troubleshoot.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c
index 73a7450..3a5a5c1 100644
--- a/arch/arc/kernel/troubleshoot.c
+++ b/arch/arc/kernel/troubleshoot.c
@@ -90,7 +90,7 @@ static void show_faulting_vma(unsigned long address, char *buf)
 	/* can't use print_vma_addr() yet as it doesn't check for
 	 * non-inclusive vma
 	 */
-
+	down_read(&current->active_mm->mmap_sem);
 	vma = find_vma(current->active_mm, address);
 
 	/* check against the find_vma( ) behaviour which returns the next VMA
@@ -110,9 +110,10 @@ static void show_faulting_vma(unsigned long address, char *buf)
 			vma->vm_start < TASK_UNMAPPED_BASE ?
 				address : address - vma->vm_start,
 			nm, vma->vm_start, vma->vm_end);
-	} else {
+	} else
 		pr_info("    @No matching VMA found\n");
-	}
+
+	up_read(&current->active_mm->mmap_sem);
 }
 
 static void show_ecr_verbose(struct pt_regs *regs)
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 5/6] drivers,sgi-gru/grufault.c: call find_vma with the mmap_sem held
  2014-04-20  2:26 [PATCH 0/6] mm: audit find_vma() callers Davidlohr Bueso
                   ` (3 preceding siblings ...)
  2014-04-20  2:26 ` [PATCH 4/6] arc: " Davidlohr Bueso
@ 2014-04-20  2:26 ` Davidlohr Bueso
  2014-04-21 13:36   ` Dimitri Sivanich
  2014-04-20  2:26 ` [PATCH 6/6] drm/exynos: " Davidlohr Bueso
  2014-04-28 18:09 ` [PATCH 7/6] media: videobuf2-dma-sg: " Davidlohr Bueso
  6 siblings, 1 reply; 17+ messages in thread
From: Davidlohr Bueso @ 2014-04-20  2:26 UTC (permalink / raw)
  To: akpm
  Cc: zeus, aswin, davidlohr, linux-mm, linux-kernel, Dimitri,
	Sivanich <sivanich

From: Jonathan Gonzalez V <zeus@gnu.org>

Performing vma lookups without taking the mm->mmap_sem is asking
for trouble. While doing the search, the vma in question can
be modified or even removed before returning to the caller.
Take the lock in order to avoid races while iterating through
the vmacache and/or rbtree.

This patch is completely *untested*.

Signed-off-by: Jonathan Gonzalez V <zeus@gnu.org>
Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
Cc: Dimitri Sivanich <sivanich@sgi.com
---
 drivers/misc/sgi-gru/grufault.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
index f74fc0c..15adc84 100644
--- a/drivers/misc/sgi-gru/grufault.c
+++ b/drivers/misc/sgi-gru/grufault.c
@@ -266,6 +266,7 @@ static int gru_vtop(struct gru_thread_state *gts, unsigned long vaddr,
 	unsigned long paddr;
 	int ret, ps;
 
+	down_write(&mm->mmap_sem);
 	vma = find_vma(mm, vaddr);
 	if (!vma)
 		goto inval;
@@ -277,22 +278,26 @@ static int gru_vtop(struct gru_thread_state *gts, unsigned long vaddr,
 	rmb();	/* Must/check ms_range_active before loading PTEs */
 	ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &ps);
 	if (ret) {
-		if (atomic)
-			goto upm;
+		if (atomic) {
+			up_write(&mm->mmap_sem);
+			return VTOP_RETRY;
+		}
 		if (non_atomic_pte_lookup(vma, vaddr, write, &paddr, &ps))
 			goto inval;
 	}
 	if (is_gru_paddr(paddr))
 		goto inval;
+
+	up_write(&mm->mmap_sem);
+
 	paddr = paddr & ~((1UL << ps) - 1);
 	*gpa = uv_soc_phys_ram_to_gpa(paddr);
 	*pageshift = ps;
 	return VTOP_SUCCESS;
 
 inval:
+	up_write(&mm->mmap_sem);
 	return VTOP_INVALID;
-upm:
-	return VTOP_RETRY;
 }
 
 
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH 6/6] drm/exynos: call find_vma with the mmap_sem held
  2014-04-20  2:26 [PATCH 0/6] mm: audit find_vma() callers Davidlohr Bueso
                   ` (4 preceding siblings ...)
  2014-04-20  2:26 ` [PATCH 5/6] drivers,sgi-gru/grufault.c: " Davidlohr Bueso
@ 2014-04-20  2:26 ` Davidlohr Bueso
  2014-04-28 18:09 ` [PATCH 7/6] media: videobuf2-dma-sg: " Davidlohr Bueso
  6 siblings, 0 replies; 17+ messages in thread
From: Davidlohr Bueso @ 2014-04-20  2:26 UTC (permalink / raw)
  To: akpm
  Cc: zeus, aswin, davidlohr, linux-mm, linux-kernel, Inki Dae,
	Joonyoung Shim, David Airlie, dri-devel, linux-samsung-soc

From: Jonathan Gonzalez V <zeus@gnu.org>

Performing vma lookups without taking the mm->mmap_sem is asking
for trouble. While doing the search, the vma in question can be
modified or even removed before returning to the caller. Take the
lock (exclusively) in order to avoid races while iterating through
the vmacache and/or rbtree.

This patch is completely *untested*.

Signed-off-by: Jonathan Gonzalez V <zeus@gnu.org>
Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
Cc: Inki Dae <inki.dae@samsung.com>
Cc: Joonyoung Shim <jy0922.shim@samsung.com>
Cc: David Airlie <airlied@linux.ie>
Cc: dri-devel@lists.freedesktop.org
Cc: linux-samsung-soc@vger.kernel.org
---
 drivers/gpu/drm/exynos/exynos_drm_g2d.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 6c1885e..8001587 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -467,14 +467,17 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
 		goto err_free;
 	}
 
+	down_read(&current->mm->mmap_sem);
 	vma = find_vma(current->mm, userptr);
 	if (!vma) {
+		up_read(&current->mm->mmap_sem);
 		DRM_ERROR("failed to get vm region.\n");
 		ret = -EFAULT;
 		goto err_free_pages;
 	}
 
 	if (vma->vm_end < userptr + size) {
+		up_read(&current->mm->mmap_sem);
 		DRM_ERROR("vma is too small.\n");
 		ret = -EFAULT;
 		goto err_free_pages;
@@ -482,6 +485,7 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
 
 	g2d_userptr->vma = exynos_gem_get_vma(vma);
 	if (!g2d_userptr->vma) {
+		up_read(&current->mm->mmap_sem);
 		DRM_ERROR("failed to copy vma.\n");
 		ret = -ENOMEM;
 		goto err_free_pages;
@@ -492,10 +496,12 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
 	ret = exynos_gem_get_pages_from_userptr(start & PAGE_MASK,
 						npages, pages, vma);
 	if (ret < 0) {
+		up_read(&current->mm->mmap_sem);
 		DRM_ERROR("failed to get user pages from userptr.\n");
 		goto err_put_vma;
 	}
 
+	up_read(&current->mm->mmap_sem);
 	g2d_userptr->pages = pages;
 
 	sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
-- 
1.8.1.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/6] m68k: call find_vma with the mmap_sem held in sys_cacheflush()
  2014-04-20  2:26 ` [PATCH 2/6] m68k: call find_vma with the mmap_sem held in sys_cacheflush() Davidlohr Bueso
@ 2014-04-20  8:04   ` Geert Uytterhoeven
  2014-04-20 22:28     ` Davidlohr Bueso
  0 siblings, 1 reply; 17+ messages in thread
From: Geert Uytterhoeven @ 2014-04-20  8:04 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: Andrew Morton, zeus, Aswin Chandramouleeswaran, Linux MM,
	linux-kernel, linux-m68k

Hi David,

On Sun, Apr 20, 2014 at 4:26 AM, Davidlohr Bueso <davidlohr@hp.com> wrote:
> Performing vma lookups without taking the mm->mmap_sem is asking
> for trouble. While doing the search, the vma in question can be
> modified or even removed before returning to the caller. Take the
> lock (shared) in order to avoid races while iterating through
> the vmacache and/or rbtree.

Thanks for your patch!

> This patch is completely *untested*.
>
> Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
> Cc: Geert Uytterhoeven <geert@linux-m68k.org>
> Cc: linux-m68k@lists.linux-m68k.org
> ---
>  arch/m68k/kernel/sys_m68k.c | 18 ++++++++++++------
>  1 file changed, 12 insertions(+), 6 deletions(-)
>
> diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
> index 3a480b3..d2263a0 100644
> --- a/arch/m68k/kernel/sys_m68k.c
> +++ b/arch/m68k/kernel/sys_m68k.c
> @@ -376,7 +376,6 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
>  asmlinkage int
>  sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
>  {
> -       struct vm_area_struct *vma;
>         int ret = -EINVAL;
>
>         if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
> @@ -389,16 +388,23 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
>                 if (!capable(CAP_SYS_ADMIN))
>                         goto out;
>         } else {
> +               struct vm_area_struct *vma;
> +               bool invalid;
> +
> +               /* Check for overflow.  */
> +               if (addr + len < addr)
> +                       goto out;
> +
>                 /*
>                  * Verify that the specified address region actually belongs
>                  * to this process.
>                  */
> -               vma = find_vma (current->mm, addr);
>                 ret = -EINVAL;
> -               /* Check for overflow.  */
> -               if (addr + len < addr)
> -                       goto out;
> -               if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
> +               down_read(&current->mm->mmap_sem);
> +               vma = find_vma(current->mm, addr);
> +               invalid = !vma || addr < vma->vm_start || addr + len > vma->vm_end;
> +               up_read(&current->mm->mmap_sem);
> +               if (invalid)
>                         goto out;
>         }

Shouldn't the up_read() be moved to the end of the function?
The vma may still be modified or destroyed between the call to find_vma(),
and the actual cache flush?

Am I missing something?

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/6] m68k: call find_vma with the mmap_sem held in sys_cacheflush()
  2014-04-20  8:04   ` Geert Uytterhoeven
@ 2014-04-20 22:28     ` Davidlohr Bueso
  2014-04-21  7:52       ` Geert Uytterhoeven
  0 siblings, 1 reply; 17+ messages in thread
From: Davidlohr Bueso @ 2014-04-20 22:28 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Andrew Morton, zeus, Aswin Chandramouleeswaran, Linux MM,
	linux-kernel, linux-m68k

On Sun, 2014-04-20 at 10:04 +0200, Geert Uytterhoeven wrote:
> Hi David,
> 
> On Sun, Apr 20, 2014 at 4:26 AM, Davidlohr Bueso <davidlohr@hp.com> wrote:
> > Performing vma lookups without taking the mm->mmap_sem is asking
> > for trouble. While doing the search, the vma in question can be
> > modified or even removed before returning to the caller. Take the
> > lock (shared) in order to avoid races while iterating through
> > the vmacache and/or rbtree.
> 
> Thanks for your patch!
> 
> > This patch is completely *untested*.
> >
> > Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
> > Cc: Geert Uytterhoeven <geert@linux-m68k.org>
> > Cc: linux-m68k@lists.linux-m68k.org
> > ---
> >  arch/m68k/kernel/sys_m68k.c | 18 ++++++++++++------
> >  1 file changed, 12 insertions(+), 6 deletions(-)
> >
> > diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
> > index 3a480b3..d2263a0 100644
> > --- a/arch/m68k/kernel/sys_m68k.c
> > +++ b/arch/m68k/kernel/sys_m68k.c
> > @@ -376,7 +376,6 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
> >  asmlinkage int
> >  sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
> >  {
> > -       struct vm_area_struct *vma;
> >         int ret = -EINVAL;
> >
> >         if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
> > @@ -389,16 +388,23 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
> >                 if (!capable(CAP_SYS_ADMIN))
> >                         goto out;
> >         } else {
> > +               struct vm_area_struct *vma;
> > +               bool invalid;
> > +
> > +               /* Check for overflow.  */
> > +               if (addr + len < addr)
> > +                       goto out;
> > +
> >                 /*
> >                  * Verify that the specified address region actually belongs
> >                  * to this process.
> >                  */
> > -               vma = find_vma (current->mm, addr);
> >                 ret = -EINVAL;
> > -               /* Check for overflow.  */
> > -               if (addr + len < addr)
> > -                       goto out;
> > -               if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
> > +               down_read(&current->mm->mmap_sem);
> > +               vma = find_vma(current->mm, addr);
> > +               invalid = !vma || addr < vma->vm_start || addr + len > vma->vm_end;
> > +               up_read(&current->mm->mmap_sem);
> > +               if (invalid)
> >                         goto out;
> >         }
> 
> Shouldn't the up_read() be moved to the end of the function?
> The vma may still be modified or destroyed between the call to find_vma(),
> and the actual cache flush?

I don't think so. afaict the vma is only searched to check upon validity
for the address being passed. Once the sem is dropped, the call doesn't
do absolutely anything else with the returned vma.

Thanks,
Davidlohr


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/6] m68k: call find_vma with the mmap_sem held in sys_cacheflush()
  2014-04-20 22:28     ` Davidlohr Bueso
@ 2014-04-21  7:52       ` Geert Uytterhoeven
  2014-08-07 22:44         ` Davidlohr Bueso
  0 siblings, 1 reply; 17+ messages in thread
From: Geert Uytterhoeven @ 2014-04-21  7:52 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: Andrew Morton, zeus, Aswin Chandramouleeswaran, Linux MM,
	linux-kernel, linux-m68k

Hi David,

On Mon, Apr 21, 2014 at 12:28 AM, Davidlohr Bueso <davidlohr@hp.com> wrote:
> On Sun, 2014-04-20 at 10:04 +0200, Geert Uytterhoeven wrote:
>> On Sun, Apr 20, 2014 at 4:26 AM, Davidlohr Bueso <davidlohr@hp.com> wrote:
>> > Performing vma lookups without taking the mm->mmap_sem is asking
>> > for trouble. While doing the search, the vma in question can be
>> > modified or even removed before returning to the caller. Take the
>> > lock (shared) in order to avoid races while iterating through
>> > the vmacache and/or rbtree.
>>
>> Thanks for your patch!
>>
>> > This patch is completely *untested*.
>> >
>> > Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
>> > Cc: Geert Uytterhoeven <geert@linux-m68k.org>
>> > Cc: linux-m68k@lists.linux-m68k.org
>> > ---
>> >  arch/m68k/kernel/sys_m68k.c | 18 ++++++++++++------
>> >  1 file changed, 12 insertions(+), 6 deletions(-)
>> >
>> > diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
>> > index 3a480b3..d2263a0 100644
>> > --- a/arch/m68k/kernel/sys_m68k.c
>> > +++ b/arch/m68k/kernel/sys_m68k.c
>> > @@ -376,7 +376,6 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
>> >  asmlinkage int
>> >  sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
>> >  {
>> > -       struct vm_area_struct *vma;
>> >         int ret = -EINVAL;
>> >
>> >         if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
>> > @@ -389,16 +388,23 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
>> >                 if (!capable(CAP_SYS_ADMIN))
>> >                         goto out;
>> >         } else {
>> > +               struct vm_area_struct *vma;
>> > +               bool invalid;
>> > +
>> > +               /* Check for overflow.  */
>> > +               if (addr + len < addr)
>> > +                       goto out;
>> > +
>> >                 /*
>> >                  * Verify that the specified address region actually belongs
>> >                  * to this process.
>> >                  */
>> > -               vma = find_vma (current->mm, addr);
>> >                 ret = -EINVAL;
>> > -               /* Check for overflow.  */
>> > -               if (addr + len < addr)
>> > -                       goto out;
>> > -               if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
>> > +               down_read(&current->mm->mmap_sem);
>> > +               vma = find_vma(current->mm, addr);
>> > +               invalid = !vma || addr < vma->vm_start || addr + len > vma->vm_end;
>> > +               up_read(&current->mm->mmap_sem);
>> > +               if (invalid)
>> >                         goto out;
>> >         }
>>
>> Shouldn't the up_read() be moved to the end of the function?
>> The vma may still be modified or destroyed between the call to find_vma(),
>> and the actual cache flush?
>
> I don't think so. afaict the vma is only searched to check upon validity
> for the address being passed. Once the sem is dropped, the call doesn't
> do absolutely anything else with the returned vma.

The function indeed doesn't do anything anymore with the vma itself, but
it does do something with the addr/len pair, which may no longer match
with the vma if it changes after the up_read(). I.e. the address may no longer
be valid when the cache is actually flushed.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 5/6] drivers,sgi-gru/grufault.c: call find_vma with the mmap_sem held
  2014-04-20  2:26 ` [PATCH 5/6] drivers,sgi-gru/grufault.c: " Davidlohr Bueso
@ 2014-04-21 13:36   ` Dimitri Sivanich
  0 siblings, 0 replies; 17+ messages in thread
From: Dimitri Sivanich @ 2014-04-21 13:36 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: akpm, zeus, aswin, linux-mm, linux-kernel, Dimitri,
	Sivanich <sivanich

On Sat, Apr 19, 2014 at 07:26:30PM -0700, Davidlohr Bueso wrote:
> From: Jonathan Gonzalez V <zeus@gnu.org>
> 
> Performing vma lookups without taking the mm->mmap_sem is asking
> for trouble. While doing the search, the vma in question can
> be modified or even removed before returning to the caller.
> Take the lock in order to avoid races while iterating through
> the vmacache and/or rbtree.
> 
> This patch is completely *untested*.

The mmap_sem is already taken in all paths calling gru_vtop().

The gru_intr() function takes it before calling gru_try_dropin(), from which
all calls to gru_vtop() originate.

The gru_find_lock_gts() function takes it when called from
gru_handle_user_call_os(), which then calls gru_user_dropin()->gru_try_dropin().

Nacked-by: Dimitri Sivanich <sivanich@sgi.com>

> 
> Signed-off-by: Jonathan Gonzalez V <zeus@gnu.org>
> Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
> Cc: Dimitri Sivanich <sivanich@sgi.com
> ---
>  drivers/misc/sgi-gru/grufault.c | 13 +++++++++----
>  1 file changed, 9 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
> index f74fc0c..15adc84 100644
> --- a/drivers/misc/sgi-gru/grufault.c
> +++ b/drivers/misc/sgi-gru/grufault.c
> @@ -266,6 +266,7 @@ static int gru_vtop(struct gru_thread_state *gts, unsigned long vaddr,
>  	unsigned long paddr;
>  	int ret, ps;
>  
> +	down_write(&mm->mmap_sem);
>  	vma = find_vma(mm, vaddr);
>  	if (!vma)
>  		goto inval;
> @@ -277,22 +278,26 @@ static int gru_vtop(struct gru_thread_state *gts, unsigned long vaddr,
>  	rmb();	/* Must/check ms_range_active before loading PTEs */
>  	ret = atomic_pte_lookup(vma, vaddr, write, &paddr, &ps);
>  	if (ret) {
> -		if (atomic)
> -			goto upm;
> +		if (atomic) {
> +			up_write(&mm->mmap_sem);
> +			return VTOP_RETRY;
> +		}
>  		if (non_atomic_pte_lookup(vma, vaddr, write, &paddr, &ps))
>  			goto inval;
>  	}
>  	if (is_gru_paddr(paddr))
>  		goto inval;
> +
> +	up_write(&mm->mmap_sem);
> +
>  	paddr = paddr & ~((1UL << ps) - 1);
>  	*gpa = uv_soc_phys_ram_to_gpa(paddr);
>  	*pageshift = ps;
>  	return VTOP_SUCCESS;
>  
>  inval:
> +	up_write(&mm->mmap_sem);
>  	return VTOP_INVALID;
> -upm:
> -	return VTOP_RETRY;
>  }
>  
>  
> -- 
> 1.8.1.4

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 1/6] blackfin/ptrace: call find_vma with the mmap_sem held
  2014-04-20  2:26 ` [PATCH 1/6] blackfin/ptrace: call find_vma with the mmap_sem held Davidlohr Bueso
@ 2014-04-22  3:07   ` Steven Miao
  0 siblings, 0 replies; 17+ messages in thread
From: Steven Miao @ 2014-04-22  3:07 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: Andrew Morton, zeus, aswin, linux-mm,
	open list:CAN NETWORK DRIVERS <linux-can@vger.kernel.org>,
	open list:NETWORKING DRIVERS <netdev@vger.kernel.org>,
	open list, bfin

Hi Davidlohr,

On Sun, Apr 20, 2014 at 10:26 AM, Davidlohr Bueso <davidlohr@hp.com> wrote:
> Performing vma lookups without taking the mm->mmap_sem is asking
> for trouble. While doing the search, the vma in question can be
> modified or even removed before returning to the caller. Take the
> lock (shared) in order to avoid races while iterating through the
> vmacache and/or rbtree.
Yes, mm->mmap_sem should lock here. Applied, thanks.
>
> This patch is completely *untested*.
>
> Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
> Cc: Steven Miao <realmz6@gmail.com>
> Cc: adi-buildroot-devel@lists.sourceforge.net
> ---
>  arch/blackfin/kernel/ptrace.c | 8 ++++++--
>  1 file changed, 6 insertions(+), 2 deletions(-)
>
> diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
> index e1f88e0..8b8fe67 100644
> --- a/arch/blackfin/kernel/ptrace.c
> +++ b/arch/blackfin/kernel/ptrace.c
> @@ -117,6 +117,7 @@ put_reg(struct task_struct *task, unsigned long regno, unsigned long data)
>  int
>  is_user_addr_valid(struct task_struct *child, unsigned long start, unsigned long len)
>  {
> +       bool valid;
>         struct vm_area_struct *vma;
>         struct sram_list_struct *sraml;
>
> @@ -124,9 +125,12 @@ is_user_addr_valid(struct task_struct *child, unsigned long start, unsigned long
>         if (start + len < start)
>                 return -EIO;
>
> +       down_read(&child->mm->mmap_sem);
>         vma = find_vma(child->mm, start);
> -       if (vma && start >= vma->vm_start && start + len <= vma->vm_end)
> -                       return 0;
> +       valid = vma && start >= vma->vm_start && start + len <= vma->vm_end;
> +       up_read(&child->mm->mmap_sem);
> +       if (valid)
> +               return 0;
>
>         for (sraml = child->mm->context.sram_list; sraml; sraml = sraml->next)
>                 if (start >= (unsigned long)sraml->addr
> --
> 1.8.1.4
>
-steven

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 4/6] arc: call find_vma with the mmap_sem held
  2014-04-20  2:26 ` [PATCH 4/6] arc: " Davidlohr Bueso
@ 2014-04-22  6:02   ` Vineet Gupta
  0 siblings, 0 replies; 17+ messages in thread
From: Vineet Gupta @ 2014-04-22  6:02 UTC (permalink / raw)
  To: Davidlohr Bueso, akpm; +Cc: zeus, aswin, linux-mm, linux-kernel

Hi,

On Sunday 20 April 2014 07:56 AM, Davidlohr Bueso wrote:
> Performing vma lookups without taking the mm->mmap_sem is asking
> for trouble. While doing the search, the vma in question can be
> modified or even removed before returning to the caller. Take the
> lock (shared) in order to avoid races while iterating through
> the vmacache and/or rbtree.
> 
> This patch is completely *untested*.
> 
> Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
> Cc: Vineet Gupta <vgupta@synopsys.com>
> ---
>  arch/arc/kernel/troubleshoot.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arc/kernel/troubleshoot.c b/arch/arc/kernel/troubleshoot.c
> index 73a7450..3a5a5c1 100644
> --- a/arch/arc/kernel/troubleshoot.c
> +++ b/arch/arc/kernel/troubleshoot.c
> @@ -90,7 +90,7 @@ static void show_faulting_vma(unsigned long address, char *buf)
>  	/* can't use print_vma_addr() yet as it doesn't check for
>  	 * non-inclusive vma
>  	 */
> -
> +	down_read(&current->active_mm->mmap_sem);

Actually avoiding the lock here was intentional - atleast in the past, in case of
a crash from mmap_region() - due to our custom mmap syscall handler (not in
mainline) it would cause a double lockup.

However given that this code is now only called for user contexts [if
user_mode(regs)] above becomes moot point anyways and it would be safe to do that.

So, yes this looks good.

A minor suggestion though - can you please use a tmp for current->active_mm as
there are 3 users now in the function.

Acked-by: Vineet Gupta <vgupta@synopsys.com>

Thx
-Vineet



>  	vma = find_vma(current->active_mm, address);
>  
>  	/* check against the find_vma( ) behaviour which returns the next VMA
> @@ -110,9 +110,10 @@ static void show_faulting_vma(unsigned long address, char *buf)
>  			vma->vm_start < TASK_UNMAPPED_BASE ?
>  				address : address - vma->vm_start,
>  			nm, vma->vm_start, vma->vm_end);
> -	} else {
> +	} else
>  		pr_info("    @No matching VMA found\n");
> -	}
> +
> +	up_read(&current->active_mm->mmap_sem);
>  }
>  
>  static void show_ecr_verbose(struct pt_regs *regs)
> 


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 3/6] mips: call find_vma with the mmap_sem held
  2014-04-20  2:26 ` [PATCH 3/6] mips: call find_vma with the mmap_sem held Davidlohr Bueso
@ 2014-04-22 13:25   ` Andreas Herrmann
  0 siblings, 0 replies; 17+ messages in thread
From: Andreas Herrmann @ 2014-04-22 13:25 UTC (permalink / raw)
  To: Davidlohr Bueso
  Cc: akpm, zeus, aswin, linux-mm, linux-kernel, Ralf Baechle, linux-mips

On Sat, Apr 19, 2014 at 07:26:28PM -0700, Davidlohr Bueso wrote:
> Performing vma lookups without taking the mm->mmap_sem is asking
> for trouble. While doing the search, the vma in question can be
> modified or even removed before returning to the caller. Take the
> lock (exclusively) in order to avoid races while iterating through
> the vmacache and/or rbtree.
> 
> Updates two functions:
>   - process_fpemu_return()
>   - cteon_flush_cache_sigtramp()
> 
> This patch is completely *untested*.
> 
> Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Cc: linux-mips@linux-mips.org

Tested-by: Andreas Herrmann <andreas.herrmann@caviumnetworks.com>


Thanks,

Andreas

> ---
>  arch/mips/kernel/traps.c | 2 ++
>  arch/mips/mm/c-octeon.c  | 2 ++
>  2 files changed, 4 insertions(+)
> 
> diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
> index 074e857..c51bd20 100644
> --- a/arch/mips/kernel/traps.c
> +++ b/arch/mips/kernel/traps.c
> @@ -712,10 +712,12 @@ int process_fpemu_return(int sig, void __user *fault_addr)
>  		si.si_addr = fault_addr;
>  		si.si_signo = sig;
>  		if (sig == SIGSEGV) {
> +			down_read(&current->mm->mmap_sem);
>  			if (find_vma(current->mm, (unsigned long)fault_addr))
>  				si.si_code = SEGV_ACCERR;
>  			else
>  				si.si_code = SEGV_MAPERR;
> +			up_read(&current->mm->mmap_sem);
>  		} else {
>  			si.si_code = BUS_ADRERR;
>  		}
> diff --git a/arch/mips/mm/c-octeon.c b/arch/mips/mm/c-octeon.c
> index f41a5c5..05b1d7c 100644
> --- a/arch/mips/mm/c-octeon.c
> +++ b/arch/mips/mm/c-octeon.c
> @@ -137,8 +137,10 @@ static void octeon_flush_cache_sigtramp(unsigned long addr)
>  {
>  	struct vm_area_struct *vma;
>  
> +	down_read(&current->mm->mmap_sem);
>  	vma = find_vma(current->mm, addr);
>  	octeon_flush_icache_all_cores(vma);
> +	up_read(&current->mm->mmap_sem);
>  }
>  
>  
> -- 
> 1.8.1.4
> 
> 

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH 7/6] media: videobuf2-dma-sg: call find_vma with the mmap_sem held
  2014-04-20  2:26 [PATCH 0/6] mm: audit find_vma() callers Davidlohr Bueso
                   ` (5 preceding siblings ...)
  2014-04-20  2:26 ` [PATCH 6/6] drm/exynos: " Davidlohr Bueso
@ 2014-04-28 18:09 ` Davidlohr Bueso
  2014-04-29  8:35   ` Marek Szyprowski
  6 siblings, 1 reply; 17+ messages in thread
From: Davidlohr Bueso @ 2014-04-28 18:09 UTC (permalink / raw)
  To: akpm
  Cc: davidlohr, aswin, linux-mm, linux-kernel, Pawel Osciak,
	Marek Szyprowski, Kyungmin Park, Mauro Carvalho Chehab,
	linux-media

Performing vma lookups without taking the mm->mmap_sem is asking
for trouble. While doing the search, the vma in question can
be modified or even removed before returning to the caller.
Take the lock in order to avoid races while iterating through
the vmacache and/or rbtree.

Also do some very minor cleanup changes.

This patch is only compile tested.

Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
Cc: Pawel Osciak <pawel@osciak.com>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Kyungmin Park <kyungmin.park@samsung.com>
Cc: Mauro Carvalho Chehab <m.chehab@samsung.com>
Cc: linux-media@vger.kernel.org
---
It would seem this is the last offending user. 
v4l2 is a maze but I believe that this is needed as I don't
see the mmap_sem being taken by any callers of vb2_dma_sg_get_userptr().

 drivers/media/v4l2-core/videobuf2-dma-sg.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index c779f21..2a21100 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -168,8 +168,9 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
 	unsigned long first, last;
 	int num_pages_from_user;
 	struct vm_area_struct *vma;
+	struct mm_struct *mm = current->mm;
 
-	buf = kzalloc(sizeof *buf, GFP_KERNEL);
+	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
 	if (!buf)
 		return NULL;
 
@@ -178,7 +179,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
 	buf->offset = vaddr & ~PAGE_MASK;
 	buf->size = size;
 
-	first = (vaddr           & PAGE_MASK) >> PAGE_SHIFT;
+	first = (vaddr & PAGE_MASK) >> PAGE_SHIFT;
 	last  = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
 	buf->num_pages = last - first + 1;
 
@@ -187,7 +188,8 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
 	if (!buf->pages)
 		goto userptr_fail_alloc_pages;
 
-	vma = find_vma(current->mm, vaddr);
+	down_write(&mm->mmap_sem);
+	vma = find_vma(mm, vaddr);
 	if (!vma) {
 		dprintk(1, "no vma for address %lu\n", vaddr);
 		goto userptr_fail_find_vma;
@@ -218,7 +220,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
 			buf->pages[num_pages_from_user] = pfn_to_page(pfn);
 		}
 	} else
-		num_pages_from_user = get_user_pages(current, current->mm,
+		num_pages_from_user = get_user_pages(current, mm,
 					     vaddr & PAGE_MASK,
 					     buf->num_pages,
 					     write,
@@ -233,6 +235,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
 			buf->num_pages, buf->offset, size, 0))
 		goto userptr_fail_alloc_table_from_pages;
 
+	up_write(&mm->mmap_sem);
 	return buf;
 
 userptr_fail_alloc_table_from_pages:
@@ -244,6 +247,7 @@ userptr_fail_get_user_pages:
 			put_page(buf->pages[num_pages_from_user]);
 	vb2_put_vma(buf->vma);
 userptr_fail_find_vma:
+	up_write(&mm->mmap_sem);
 	kfree(buf->pages);
 userptr_fail_alloc_pages:
 	kfree(buf);
-- 
1.8.1.4




^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH 7/6] media: videobuf2-dma-sg: call find_vma with the mmap_sem held
  2014-04-28 18:09 ` [PATCH 7/6] media: videobuf2-dma-sg: " Davidlohr Bueso
@ 2014-04-29  8:35   ` Marek Szyprowski
  0 siblings, 0 replies; 17+ messages in thread
From: Marek Szyprowski @ 2014-04-29  8:35 UTC (permalink / raw)
  To: Davidlohr Bueso, akpm
  Cc: aswin, linux-mm, linux-kernel, Pawel Osciak, Kyungmin Park,
	Mauro Carvalho Chehab, linux-media

Hello,

On 2014-04-28 20:09, Davidlohr Bueso wrote:
> Performing vma lookups without taking the mm->mmap_sem is asking
> for trouble. While doing the search, the vma in question can
> be modified or even removed before returning to the caller.
> Take the lock in order to avoid races while iterating through
> the vmacache and/or rbtree.
>
> Also do some very minor cleanup changes.
>
> This patch is only compile tested.

NACK.

mm->mmap_sem is taken by videobuf2-core to avoid AB-BA deadlock with v4l2 core lock. For more information, please check videobuf2-core.c. However you are right that this is a bit confusing and we need more comments about the place where mmap_sem is taken. Here is some background for this decision:

https://www.mail-archive.com/linux-media@vger.kernel.org/msg38599.html
http://www.spinics.net/lists/linux-media/msg40225.html

> Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
> Cc: Pawel Osciak <pawel@osciak.com>
> Cc: Marek Szyprowski <m.szyprowski@samsung.com>
> Cc: Kyungmin Park <kyungmin.park@samsung.com>
> Cc: Mauro Carvalho Chehab <m.chehab@samsung.com>
> Cc: linux-media@vger.kernel.org
> ---
> It would seem this is the last offending user.
> v4l2 is a maze but I believe that this is needed as I don't
> see the mmap_sem being taken by any callers of vb2_dma_sg_get_userptr().
>
>   drivers/media/v4l2-core/videobuf2-dma-sg.c | 12 ++++++++----
>   1 file changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c
> index c779f21..2a21100 100644
> --- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
> +++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
> @@ -168,8 +168,9 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
>   	unsigned long first, last;
>   	int num_pages_from_user;
>   	struct vm_area_struct *vma;
> +	struct mm_struct *mm = current->mm;
>   
> -	buf = kzalloc(sizeof *buf, GFP_KERNEL);
> +	buf = kzalloc(sizeof(*buf), GFP_KERNEL);
>   	if (!buf)
>   		return NULL;
>   
> @@ -178,7 +179,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
>   	buf->offset = vaddr & ~PAGE_MASK;
>   	buf->size = size;
>   
> -	first = (vaddr           & PAGE_MASK) >> PAGE_SHIFT;
> +	first = (vaddr & PAGE_MASK) >> PAGE_SHIFT;
>   	last  = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
>   	buf->num_pages = last - first + 1;
>   
> @@ -187,7 +188,8 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
>   	if (!buf->pages)
>   		goto userptr_fail_alloc_pages;
>   
> -	vma = find_vma(current->mm, vaddr);
> +	down_write(&mm->mmap_sem);
> +	vma = find_vma(mm, vaddr);
>   	if (!vma) {
>   		dprintk(1, "no vma for address %lu\n", vaddr);
>   		goto userptr_fail_find_vma;
> @@ -218,7 +220,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
>   			buf->pages[num_pages_from_user] = pfn_to_page(pfn);
>   		}
>   	} else
> -		num_pages_from_user = get_user_pages(current, current->mm,
> +		num_pages_from_user = get_user_pages(current, mm,
>   					     vaddr & PAGE_MASK,
>   					     buf->num_pages,
>   					     write,
> @@ -233,6 +235,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
>   			buf->num_pages, buf->offset, size, 0))
>   		goto userptr_fail_alloc_table_from_pages;
>   
> +	up_write(&mm->mmap_sem);
>   	return buf;
>   
>   userptr_fail_alloc_table_from_pages:
> @@ -244,6 +247,7 @@ userptr_fail_get_user_pages:
>   			put_page(buf->pages[num_pages_from_user]);
>   	vb2_put_vma(buf->vma);
>   userptr_fail_find_vma:
> +	up_write(&mm->mmap_sem);
>   	kfree(buf->pages);
>   userptr_fail_alloc_pages:
>   	kfree(buf);

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH 2/6] m68k: call find_vma with the mmap_sem held in sys_cacheflush()
  2014-04-21  7:52       ` Geert Uytterhoeven
@ 2014-08-07 22:44         ` Davidlohr Bueso
  0 siblings, 0 replies; 17+ messages in thread
From: Davidlohr Bueso @ 2014-08-07 22:44 UTC (permalink / raw)
  To: Geert Uytterhoeven
  Cc: Andrew Morton, Aswin Chandramouleeswaran, Linux MM, linux-kernel,
	linux-m68k

Hi Geert,

On Mon, 2014-04-21 at 09:52 +0200, Geert Uytterhoeven wrote:
> Hi David,
> 
> On Mon, Apr 21, 2014 at 12:28 AM, Davidlohr Bueso <davidlohr@hp.com> wrote:
> > On Sun, 2014-04-20 at 10:04 +0200, Geert Uytterhoeven wrote:
> >> On Sun, Apr 20, 2014 at 4:26 AM, Davidlohr Bueso <davidlohr@hp.com> wrote:
> >> > Performing vma lookups without taking the mm->mmap_sem is asking
> >> > for trouble. While doing the search, the vma in question can be
> >> > modified or even removed before returning to the caller. Take the
> >> > lock (shared) in order to avoid races while iterating through
> >> > the vmacache and/or rbtree.
> >>
> >> Thanks for your patch!
> >>
> >> > This patch is completely *untested*.
> >> >
> >> > Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
> >> > Cc: Geert Uytterhoeven <geert@linux-m68k.org>
> >> > Cc: linux-m68k@lists.linux-m68k.org
> >> > ---
> >> >  arch/m68k/kernel/sys_m68k.c | 18 ++++++++++++------
> >> >  1 file changed, 12 insertions(+), 6 deletions(-)
> >> >
> >> > diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
> >> > index 3a480b3..d2263a0 100644
> >> > --- a/arch/m68k/kernel/sys_m68k.c
> >> > +++ b/arch/m68k/kernel/sys_m68k.c
> >> > @@ -376,7 +376,6 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
> >> >  asmlinkage int
> >> >  sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
> >> >  {
> >> > -       struct vm_area_struct *vma;
> >> >         int ret = -EINVAL;
> >> >
> >> >         if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
> >> > @@ -389,16 +388,23 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
> >> >                 if (!capable(CAP_SYS_ADMIN))
> >> >                         goto out;
> >> >         } else {
> >> > +               struct vm_area_struct *vma;
> >> > +               bool invalid;
> >> > +
> >> > +               /* Check for overflow.  */
> >> > +               if (addr + len < addr)
> >> > +                       goto out;
> >> > +
> >> >                 /*
> >> >                  * Verify that the specified address region actually belongs
> >> >                  * to this process.
> >> >                  */
> >> > -               vma = find_vma (current->mm, addr);
> >> >                 ret = -EINVAL;
> >> > -               /* Check for overflow.  */
> >> > -               if (addr + len < addr)
> >> > -                       goto out;
> >> > -               if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
> >> > +               down_read(&current->mm->mmap_sem);
> >> > +               vma = find_vma(current->mm, addr);
> >> > +               invalid = !vma || addr < vma->vm_start || addr + len > vma->vm_end;
> >> > +               up_read(&current->mm->mmap_sem);
> >> > +               if (invalid)
> >> >                         goto out;
> >> >         }
> >>
> >> Shouldn't the up_read() be moved to the end of the function?
> >> The vma may still be modified or destroyed between the call to find_vma(),
> >> and the actual cache flush?
> >
> > I don't think so. afaict the vma is only searched to check upon validity
> > for the address being passed. Once the sem is dropped, the call doesn't
> > do absolutely anything else with the returned vma.
> 
> The function indeed doesn't do anything anymore with the vma itself, but
> it does do something with the addr/len pair, which may no longer match
> with the vma if it changes after the up_read(). I.e. the address may no longer
> be valid when the cache is actually flushed.

Apologies for the delay, I completely forgot about this. 

So I wasn't sure if we *really* required to serialize the entire address
space for this operation. However, looking at other archs, sh seems to
do exactly that, so I guess, at least for safety, we should hold the
lock until we exit the function. I guess taking it as a reader enables
us to guarantee it won't be removed underneath us. So here's v2.

Thanks,
Davidlohr


8<-------------------------------------------------------------------------
From: Davidlohr Bueso <davidlohr@hp.com>
Subject: [PATCH v2] m68k: call find_vma with the mmap_sem held in sys_cacheflush()

Performing vma lookups without taking the mm->mmap_sem is asking
for trouble. While doing the search, the vma in question can be
modified or even removed before returning to the caller. Take the
lock (shared) in order to avoid races while iterating through
the vmacache and/or rbtree. In addition, this guarantees that the
address space will remain intact during the CPU flushing.

Signed-off-by: Davidlohr Bueso <davidlohr@hp.com>
---
Completely untested patch.

 arch/m68k/kernel/sys_m68k.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 3a480b3..9aa01ad 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -376,7 +376,6 @@ cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
 asmlinkage int
 sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
 {
-	struct vm_area_struct *vma;
 	int ret = -EINVAL;
 
 	if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL ||
@@ -389,17 +388,21 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
 		if (!capable(CAP_SYS_ADMIN))
 			goto out;
 	} else {
+		struct vm_area_struct *vma;
+
+		/* Check for overflow.  */
+		if (addr + len < addr)
+			goto out;
+
 		/*
 		 * Verify that the specified address region actually belongs
 		 * to this process.
 		 */
-		vma = find_vma (current->mm, addr);
 		ret = -EINVAL;
-		/* Check for overflow.  */
-		if (addr + len < addr)
-			goto out;
-		if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
-			goto out;
+		down_read(&current->mm->mmap_sem);
+		vma = find_vma(current->mm, addr);
+		if (!vma || addr < vma->vm_start || addr + len > vma->vm_end)
+			goto out_unlock;
 	}
 
 	if (CPU_IS_020_OR_030) {
@@ -429,7 +432,7 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
 			__asm__ __volatile__ ("movec %0, %%cacr" : : "r" (cacr));
 		}
 		ret = 0;
-		goto out;
+		goto out_unlock;
 	} else {
 	    /*
 	     * 040 or 060: don't blindly trust 'scope', someone could
@@ -446,6 +449,8 @@ sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
 		ret = cache_flush_060 (addr, scope, cache, len);
 	    }
 	}
+out_unlock:
+	up_read(&current->mm->mmap_sem);
 out:
 	return ret;
 }
-- 
1.8.1.4




^ permalink raw reply related	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2014-08-07 22:44 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-20  2:26 [PATCH 0/6] mm: audit find_vma() callers Davidlohr Bueso
2014-04-20  2:26 ` [PATCH 1/6] blackfin/ptrace: call find_vma with the mmap_sem held Davidlohr Bueso
2014-04-22  3:07   ` Steven Miao
2014-04-20  2:26 ` [PATCH 2/6] m68k: call find_vma with the mmap_sem held in sys_cacheflush() Davidlohr Bueso
2014-04-20  8:04   ` Geert Uytterhoeven
2014-04-20 22:28     ` Davidlohr Bueso
2014-04-21  7:52       ` Geert Uytterhoeven
2014-08-07 22:44         ` Davidlohr Bueso
2014-04-20  2:26 ` [PATCH 3/6] mips: call find_vma with the mmap_sem held Davidlohr Bueso
2014-04-22 13:25   ` Andreas Herrmann
2014-04-20  2:26 ` [PATCH 4/6] arc: " Davidlohr Bueso
2014-04-22  6:02   ` Vineet Gupta
2014-04-20  2:26 ` [PATCH 5/6] drivers,sgi-gru/grufault.c: " Davidlohr Bueso
2014-04-21 13:36   ` Dimitri Sivanich
2014-04-20  2:26 ` [PATCH 6/6] drm/exynos: " Davidlohr Bueso
2014-04-28 18:09 ` [PATCH 7/6] media: videobuf2-dma-sg: " Davidlohr Bueso
2014-04-29  8:35   ` Marek Szyprowski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).