linux-hardening.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Fixes for usercopy
@ 2022-06-12 21:32 Matthew Wilcox (Oracle)
  2022-06-12 21:32 ` [PATCH 1/3] usercopy: Handle vm_map_ram() areas Matthew Wilcox (Oracle)
                   ` (4 more replies)
  0 siblings, 5 replies; 17+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-12 21:32 UTC (permalink / raw)
  To: Kees Cook
  Cc: Matthew Wilcox (Oracle),
	linux-mm, Uladzislau Rezki, Zorro Lang, linux-xfs,
	linux-hardening

Kees, I'm hoping you'll take these through your tree.  I think they're
all reasonable fixes to go into 5.19.  The first one is essential;
it fixes two different bugs that people have hit.

Matthew Wilcox (Oracle) (3):
  usercopy: Handle vm_map_ram() areas
  usercopy: Cast pointer to an integer once
  usercopy: Make usercopy resilient against ridiculously large copies

 include/linux/vmalloc.h |  1 +
 mm/usercopy.c           | 24 +++++++++++++-----------
 mm/vmalloc.c            |  2 +-
 3 files changed, 15 insertions(+), 12 deletions(-)

-- 
2.35.1


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

* [PATCH 1/3] usercopy: Handle vm_map_ram() areas
  2022-06-12 21:32 [PATCH 0/3] Fixes for usercopy Matthew Wilcox (Oracle)
@ 2022-06-12 21:32 ` Matthew Wilcox (Oracle)
  2022-06-13 10:00   ` Uladzislau Rezki
  2022-06-13 16:23   ` Kees Cook
  2022-06-12 21:32 ` [PATCH 2/3] usercopy: Cast pointer to an integer once Matthew Wilcox (Oracle)
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 17+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-12 21:32 UTC (permalink / raw)
  To: Kees Cook
  Cc: Matthew Wilcox (Oracle),
	linux-mm, Uladzislau Rezki, Zorro Lang, linux-xfs,
	linux-hardening

vmalloc does not allocate a vm_struct for vm_map_ram() areas.  That causes
us to deny usercopies from those areas.  This affects XFS which uses
vm_map_ram() for its directories.

Fix this by calling find_vmap_area() instead of find_vm_area().

Fixes: 0aef499f3172 ("mm/usercopy: Detect vmalloc overruns")
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 include/linux/vmalloc.h | 1 +
 mm/usercopy.c           | 8 +++++---
 mm/vmalloc.c            | 2 +-
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index b159c2789961..096d48aa3437 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -215,6 +215,7 @@ extern struct vm_struct *__get_vm_area_caller(unsigned long size,
 void free_vm_area(struct vm_struct *area);
 extern struct vm_struct *remove_vm_area(const void *addr);
 extern struct vm_struct *find_vm_area(const void *addr);
+struct vmap_area *find_vmap_area(unsigned long addr);
 
 static inline bool is_vm_area_hugepages(const void *addr)
 {
diff --git a/mm/usercopy.c b/mm/usercopy.c
index baeacc735b83..fdd1bed3b90a 100644
--- a/mm/usercopy.c
+++ b/mm/usercopy.c
@@ -173,7 +173,7 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
 	}
 
 	if (is_vmalloc_addr(ptr)) {
-		struct vm_struct *area = find_vm_area(ptr);
+		struct vmap_area *area = find_vmap_area((unsigned long)ptr);
 		unsigned long offset;
 
 		if (!area) {
@@ -181,8 +181,10 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
 			return;
 		}
 
-		offset = ptr - area->addr;
-		if (offset + n > get_vm_area_size(area))
+		/* XXX: We should also abort for free vmap_areas */
+
+		offset = (unsigned long)ptr - area->va_start;
+		if ((unsigned long)ptr + n > area->va_end)
 			usercopy_abort("vmalloc", NULL, to_user, offset, n);
 		return;
 	}
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 07db42455dd4..effd1ff6a4b4 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1798,7 +1798,7 @@ static void free_unmap_vmap_area(struct vmap_area *va)
 	free_vmap_area_noflush(va);
 }
 
-static struct vmap_area *find_vmap_area(unsigned long addr)
+struct vmap_area *find_vmap_area(unsigned long addr)
 {
 	struct vmap_area *va;
 
-- 
2.35.1


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

* [PATCH 2/3] usercopy: Cast pointer to an integer once
  2022-06-12 21:32 [PATCH 0/3] Fixes for usercopy Matthew Wilcox (Oracle)
  2022-06-12 21:32 ` [PATCH 1/3] usercopy: Handle vm_map_ram() areas Matthew Wilcox (Oracle)
@ 2022-06-12 21:32 ` Matthew Wilcox (Oracle)
  2022-06-13  9:51   ` Uladzislau Rezki
  2022-06-12 21:32 ` [PATCH 3/3] usercopy: Make usercopy resilient against ridiculously large copies Matthew Wilcox (Oracle)
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 17+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-12 21:32 UTC (permalink / raw)
  To: Kees Cook
  Cc: Matthew Wilcox (Oracle),
	linux-mm, Uladzislau Rezki, Zorro Lang, linux-xfs,
	linux-hardening

Get rid of a lot of annoying casts by setting 'addr' once at the top
of the function.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 mm/usercopy.c | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/mm/usercopy.c b/mm/usercopy.c
index fdd1bed3b90a..31deee7dd2f5 100644
--- a/mm/usercopy.c
+++ b/mm/usercopy.c
@@ -161,19 +161,20 @@ static inline void check_bogus_address(const unsigned long ptr, unsigned long n,
 static inline void check_heap_object(const void *ptr, unsigned long n,
 				     bool to_user)
 {
+	uintptr_t addr = (uintptr_t)ptr;
 	struct folio *folio;
 
 	if (is_kmap_addr(ptr)) {
-		unsigned long page_end = (unsigned long)ptr | (PAGE_SIZE - 1);
+		unsigned long page_end = addr | (PAGE_SIZE - 1);
 
-		if ((unsigned long)ptr + n - 1 > page_end)
+		if (addr + n - 1 > page_end)
 			usercopy_abort("kmap", NULL, to_user,
 					offset_in_page(ptr), n);
 		return;
 	}
 
 	if (is_vmalloc_addr(ptr)) {
-		struct vmap_area *area = find_vmap_area((unsigned long)ptr);
+		struct vmap_area *area = find_vmap_area(addr);
 		unsigned long offset;
 
 		if (!area) {
@@ -183,8 +184,8 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
 
 		/* XXX: We should also abort for free vmap_areas */
 
-		offset = (unsigned long)ptr - area->va_start;
-		if ((unsigned long)ptr + n > area->va_end)
+		offset = addr - area->va_start;
+		if (addr + n > area->va_end)
 			usercopy_abort("vmalloc", NULL, to_user, offset, n);
 		return;
 	}
-- 
2.35.1


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

* [PATCH 3/3] usercopy: Make usercopy resilient against ridiculously large copies
  2022-06-12 21:32 [PATCH 0/3] Fixes for usercopy Matthew Wilcox (Oracle)
  2022-06-12 21:32 ` [PATCH 1/3] usercopy: Handle vm_map_ram() areas Matthew Wilcox (Oracle)
  2022-06-12 21:32 ` [PATCH 2/3] usercopy: Cast pointer to an integer once Matthew Wilcox (Oracle)
@ 2022-06-12 21:32 ` Matthew Wilcox (Oracle)
  2022-06-13  9:57   ` Uladzislau Rezki
  2022-06-13  8:04 ` [PATCH 0/3] Fixes for usercopy Zorro Lang
  2022-06-13 16:25 ` Kees Cook
  4 siblings, 1 reply; 17+ messages in thread
From: Matthew Wilcox (Oracle) @ 2022-06-12 21:32 UTC (permalink / raw)
  To: Kees Cook
  Cc: Matthew Wilcox (Oracle),
	linux-mm, Uladzislau Rezki, Zorro Lang, linux-xfs,
	linux-hardening

If 'n' is so large that it's negative, we might wrap around and mistakenly
think that the copy is OK when it's not.  Such a copy would probably
crash, but just doing the arithmetic in a more simple way lets us detect
and refuse this case.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
 mm/usercopy.c | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/mm/usercopy.c b/mm/usercopy.c
index 31deee7dd2f5..ff16083cf1c8 100644
--- a/mm/usercopy.c
+++ b/mm/usercopy.c
@@ -162,20 +162,18 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
 				     bool to_user)
 {
 	uintptr_t addr = (uintptr_t)ptr;
+	unsigned long offset;
 	struct folio *folio;
 
 	if (is_kmap_addr(ptr)) {
-		unsigned long page_end = addr | (PAGE_SIZE - 1);
-
-		if (addr + n - 1 > page_end)
-			usercopy_abort("kmap", NULL, to_user,
-					offset_in_page(ptr), n);
+		offset = offset_in_page(ptr);
+		if (n > PAGE_SIZE - offset)
+			usercopy_abort("kmap", NULL, to_user, offset, n);
 		return;
 	}
 
 	if (is_vmalloc_addr(ptr)) {
 		struct vmap_area *area = find_vmap_area(addr);
-		unsigned long offset;
 
 		if (!area) {
 			usercopy_abort("vmalloc", "no area", to_user, 0, n);
@@ -184,9 +182,10 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
 
 		/* XXX: We should also abort for free vmap_areas */
 
-		offset = addr - area->va_start;
-		if (addr + n > area->va_end)
+		if (n > area->va_end - addr) {
+			offset = addr - area->va_start;
 			usercopy_abort("vmalloc", NULL, to_user, offset, n);
+		}
 		return;
 	}
 
@@ -199,8 +198,8 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
 		/* Check slab allocator for flags and size. */
 		__check_heap_object(ptr, n, folio_slab(folio), to_user);
 	} else if (folio_test_large(folio)) {
-		unsigned long offset = ptr - folio_address(folio);
-		if (offset + n > folio_size(folio))
+		offset = ptr - folio_address(folio);
+		if (n > folio_size(folio) - offset)
 			usercopy_abort("page alloc", NULL, to_user, offset, n);
 	}
 }
-- 
2.35.1


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

* Re: [PATCH 0/3] Fixes for usercopy
  2022-06-12 21:32 [PATCH 0/3] Fixes for usercopy Matthew Wilcox (Oracle)
                   ` (2 preceding siblings ...)
  2022-06-12 21:32 ` [PATCH 3/3] usercopy: Make usercopy resilient against ridiculously large copies Matthew Wilcox (Oracle)
@ 2022-06-13  8:04 ` Zorro Lang
  2022-06-13 16:25 ` Kees Cook
  4 siblings, 0 replies; 17+ messages in thread
From: Zorro Lang @ 2022-06-13  8:04 UTC (permalink / raw)
  To: Matthew Wilcox (Oracle)
  Cc: Kees Cook, linux-mm, Uladzislau Rezki, linux-xfs, linux-hardening

On Sun, Jun 12, 2022 at 10:32:24PM +0100, Matthew Wilcox (Oracle) wrote:
> Kees, I'm hoping you'll take these through your tree.  I think they're
> all reasonable fixes to go into 5.19.  The first one is essential;
> it fixes two different bugs that people have hit.
> 
> Matthew Wilcox (Oracle) (3):
>   usercopy: Handle vm_map_ram() areas
>   usercopy: Cast pointer to an integer once
>   usercopy: Make usercopy resilient against ridiculously large copies

Hi Matthew,

[Quick response] ...
After merging this patchset onto linux v5.19-rc2, I can't reproduce bug [1]
anymore. I'd like to keep the test running, if it find other issues I'll
feedback.

Thanks,
Zorro

[1]
https://bugzilla.kernel.org/show_bug.cgi?id=216073

> 
>  include/linux/vmalloc.h |  1 +
>  mm/usercopy.c           | 24 +++++++++++++-----------
>  mm/vmalloc.c            |  2 +-
>  3 files changed, 15 insertions(+), 12 deletions(-)
> 
> -- 
> 2.35.1
> 


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

* Re: [PATCH 2/3] usercopy: Cast pointer to an integer once
  2022-06-12 21:32 ` [PATCH 2/3] usercopy: Cast pointer to an integer once Matthew Wilcox (Oracle)
@ 2022-06-13  9:51   ` Uladzislau Rezki
  2022-06-13 16:20     ` Kees Cook
  0 siblings, 1 reply; 17+ messages in thread
From: Uladzislau Rezki @ 2022-06-13  9:51 UTC (permalink / raw)
  To: Matthew Wilcox (Oracle)
  Cc: Kees Cook, linux-mm, Uladzislau Rezki, Zorro Lang, linux-xfs,
	linux-hardening

On Sun, Jun 12, 2022 at 10:32:26PM +0100, Matthew Wilcox (Oracle) wrote:
> Get rid of a lot of annoying casts by setting 'addr' once at the top
> of the function.
> 
> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> ---
>  mm/usercopy.c | 11 ++++++-----
>  1 file changed, 6 insertions(+), 5 deletions(-)
> 
> diff --git a/mm/usercopy.c b/mm/usercopy.c
> index fdd1bed3b90a..31deee7dd2f5 100644
> --- a/mm/usercopy.c
> +++ b/mm/usercopy.c
> @@ -161,19 +161,20 @@ static inline void check_bogus_address(const unsigned long ptr, unsigned long n,
>  static inline void check_heap_object(const void *ptr, unsigned long n,
>  				     bool to_user)
>  {
> +	uintptr_t addr = (uintptr_t)ptr;
>  	struct folio *folio;
>  
>  	if (is_kmap_addr(ptr)) {
> -		unsigned long page_end = (unsigned long)ptr | (PAGE_SIZE - 1);
> +		unsigned long page_end = addr | (PAGE_SIZE - 1);
>  
> -		if ((unsigned long)ptr + n - 1 > page_end)
> +		if (addr + n - 1 > page_end)
>  			usercopy_abort("kmap", NULL, to_user,
>  					offset_in_page(ptr), n);
>  		return;
>  	}
>  
>  	if (is_vmalloc_addr(ptr)) {
> -		struct vmap_area *area = find_vmap_area((unsigned long)ptr);
> +		struct vmap_area *area = find_vmap_area(addr);
>  		unsigned long offset;
>  
>  		if (!area) {
> @@ -183,8 +184,8 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
>  
>  		/* XXX: We should also abort for free vmap_areas */
>  
> -		offset = (unsigned long)ptr - area->va_start;
> -		if ((unsigned long)ptr + n > area->va_end)
> +		offset = addr - area->va_start;
> +		if (addr + n > area->va_end)
>  			usercopy_abort("vmalloc", NULL, to_user, offset, n);
>  		return;
>  	}
> -- 
> 2.35.1
> 
Looks good to me: Reviewed-by: Uladzislau Rezki (Sony) <urezki@gmail.com>

--
Uladzislau Rezki

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

* Re: [PATCH 3/3] usercopy: Make usercopy resilient against ridiculously large copies
  2022-06-12 21:32 ` [PATCH 3/3] usercopy: Make usercopy resilient against ridiculously large copies Matthew Wilcox (Oracle)
@ 2022-06-13  9:57   ` Uladzislau Rezki
  0 siblings, 0 replies; 17+ messages in thread
From: Uladzislau Rezki @ 2022-06-13  9:57 UTC (permalink / raw)
  To: Matthew Wilcox (Oracle)
  Cc: Kees Cook, linux-mm, Uladzislau Rezki, Zorro Lang, linux-xfs,
	linux-hardening

> If 'n' is so large that it's negative, we might wrap around and mistakenly
> think that the copy is OK when it's not.  Such a copy would probably
> crash, but just doing the arithmetic in a more simple way lets us detect
> and refuse this case.
> 
> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> ---
>  mm/usercopy.c | 19 +++++++++----------
>  1 file changed, 9 insertions(+), 10 deletions(-)
> 
> diff --git a/mm/usercopy.c b/mm/usercopy.c
> index 31deee7dd2f5..ff16083cf1c8 100644
> --- a/mm/usercopy.c
> +++ b/mm/usercopy.c
> @@ -162,20 +162,18 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
>  				     bool to_user)
>  {
>  	uintptr_t addr = (uintptr_t)ptr;
> +	unsigned long offset;
>  	struct folio *folio;
>  
>  	if (is_kmap_addr(ptr)) {
> -		unsigned long page_end = addr | (PAGE_SIZE - 1);
> -
> -		if (addr + n - 1 > page_end)
> -			usercopy_abort("kmap", NULL, to_user,
> -					offset_in_page(ptr), n);
> +		offset = offset_in_page(ptr);
> +		if (n > PAGE_SIZE - offset)
> +			usercopy_abort("kmap", NULL, to_user, offset, n);
>  		return;
>  	}
>  
>  	if (is_vmalloc_addr(ptr)) {
>  		struct vmap_area *area = find_vmap_area(addr);
> -		unsigned long offset;
>  
>  		if (!area) {
>  			usercopy_abort("vmalloc", "no area", to_user, 0, n);
> @@ -184,9 +182,10 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
>  
>  		/* XXX: We should also abort for free vmap_areas */
>  
> -		offset = addr - area->va_start;
> -		if (addr + n > area->va_end)
> +		if (n > area->va_end - addr) {
> +			offset = addr - area->va_start;
>  			usercopy_abort("vmalloc", NULL, to_user, offset, n);
> +		}
>  		return;
>  	}
>  
> @@ -199,8 +198,8 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
>  		/* Check slab allocator for flags and size. */
>  		__check_heap_object(ptr, n, folio_slab(folio), to_user);
>  	} else if (folio_test_large(folio)) {
> -		unsigned long offset = ptr - folio_address(folio);
> -		if (offset + n > folio_size(folio))
> +		offset = ptr - folio_address(folio);
> +		if (n > folio_size(folio) - offset)
>  			usercopy_abort("page alloc", NULL, to_user, offset, n);
>  	}
>  }
> -- 
> 2.35.1
> 
Looks good to me: Reviewed-by: Uladzislau Rezki (Sony) <urezki@gmail.com>

--
Uladzislau Rezki

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

* Re: [PATCH 1/3] usercopy: Handle vm_map_ram() areas
  2022-06-12 21:32 ` [PATCH 1/3] usercopy: Handle vm_map_ram() areas Matthew Wilcox (Oracle)
@ 2022-06-13 10:00   ` Uladzislau Rezki
  2022-06-13 11:52     ` Baoquan He
  2022-06-13 16:23   ` Kees Cook
  1 sibling, 1 reply; 17+ messages in thread
From: Uladzislau Rezki @ 2022-06-13 10:00 UTC (permalink / raw)
  To: Matthew Wilcox (Oracle)
  Cc: Kees Cook, linux-mm, Uladzislau Rezki, Zorro Lang, linux-xfs,
	linux-hardening

> vmalloc does not allocate a vm_struct for vm_map_ram() areas.  That causes
> us to deny usercopies from those areas.  This affects XFS which uses
> vm_map_ram() for its directories.
> 
> Fix this by calling find_vmap_area() instead of find_vm_area().
> 
> Fixes: 0aef499f3172 ("mm/usercopy: Detect vmalloc overruns")
> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> ---
>  include/linux/vmalloc.h | 1 +
>  mm/usercopy.c           | 8 +++++---
>  mm/vmalloc.c            | 2 +-
>  3 files changed, 7 insertions(+), 4 deletions(-)
> 
> diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
> index b159c2789961..096d48aa3437 100644
> --- a/include/linux/vmalloc.h
> +++ b/include/linux/vmalloc.h
> @@ -215,6 +215,7 @@ extern struct vm_struct *__get_vm_area_caller(unsigned long size,
>  void free_vm_area(struct vm_struct *area);
>  extern struct vm_struct *remove_vm_area(const void *addr);
>  extern struct vm_struct *find_vm_area(const void *addr);
> +struct vmap_area *find_vmap_area(unsigned long addr);
Make it "extern" since it becomes globally visible?

--
Uladzislau Rezki

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

* Re: [PATCH 1/3] usercopy: Handle vm_map_ram() areas
  2022-06-13 10:00   ` Uladzislau Rezki
@ 2022-06-13 11:52     ` Baoquan He
  2022-06-13 12:56       ` Uladzislau Rezki
  0 siblings, 1 reply; 17+ messages in thread
From: Baoquan He @ 2022-06-13 11:52 UTC (permalink / raw)
  To: Uladzislau Rezki
  Cc: Matthew Wilcox (Oracle),
	Kees Cook, linux-mm, Zorro Lang, linux-xfs, linux-hardening

On 06/13/22 at 12:00pm, Uladzislau Rezki wrote:
> > vmalloc does not allocate a vm_struct for vm_map_ram() areas.  That causes
> > us to deny usercopies from those areas.  This affects XFS which uses
> > vm_map_ram() for its directories.
> > 
> > Fix this by calling find_vmap_area() instead of find_vm_area().
> > 
> > Fixes: 0aef499f3172 ("mm/usercopy: Detect vmalloc overruns")
> > Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> > ---
> >  include/linux/vmalloc.h | 1 +
> >  mm/usercopy.c           | 8 +++++---
> >  mm/vmalloc.c            | 2 +-
> >  3 files changed, 7 insertions(+), 4 deletions(-)
> > 
> > diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
> > index b159c2789961..096d48aa3437 100644
> > --- a/include/linux/vmalloc.h
> > +++ b/include/linux/vmalloc.h
> > @@ -215,6 +215,7 @@ extern struct vm_struct *__get_vm_area_caller(unsigned long size,
> >  void free_vm_area(struct vm_struct *area);
> >  extern struct vm_struct *remove_vm_area(const void *addr);
> >  extern struct vm_struct *find_vm_area(const void *addr);
> > +struct vmap_area *find_vmap_area(unsigned long addr);
> Make it "extern" since it becomes globally visible?

extern is not suggested any more to add for function declaration in
header file, and removing it doesn't impact thing.

> 
> --
> Uladzislau Rezki
> 


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

* Re: [PATCH 1/3] usercopy: Handle vm_map_ram() areas
  2022-06-13 11:52     ` Baoquan He
@ 2022-06-13 12:56       ` Uladzislau Rezki
  0 siblings, 0 replies; 17+ messages in thread
From: Uladzislau Rezki @ 2022-06-13 12:56 UTC (permalink / raw)
  To: Baoquan He, Matthew Wilcox (Oracle)
  Cc: Uladzislau Rezki, Matthew Wilcox (Oracle),
	Kees Cook, linux-mm, Zorro Lang, linux-xfs, linux-hardening

> On 06/13/22 at 12:00pm, Uladzislau Rezki wrote:
> > > vmalloc does not allocate a vm_struct for vm_map_ram() areas.  That causes
> > > us to deny usercopies from those areas.  This affects XFS which uses
> > > vm_map_ram() for its directories.
> > > 
> > > Fix this by calling find_vmap_area() instead of find_vm_area().
> > > 
> > > Fixes: 0aef499f3172 ("mm/usercopy: Detect vmalloc overruns")
> > > Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> > > ---
> > >  include/linux/vmalloc.h | 1 +
> > >  mm/usercopy.c           | 8 +++++---
> > >  mm/vmalloc.c            | 2 +-
> > >  3 files changed, 7 insertions(+), 4 deletions(-)
> > > 
> > > diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
> > > index b159c2789961..096d48aa3437 100644
> > > --- a/include/linux/vmalloc.h
> > > +++ b/include/linux/vmalloc.h
> > > @@ -215,6 +215,7 @@ extern struct vm_struct *__get_vm_area_caller(unsigned long size,
> > >  void free_vm_area(struct vm_struct *area);
> > >  extern struct vm_struct *remove_vm_area(const void *addr);
> > >  extern struct vm_struct *find_vm_area(const void *addr);
> > > +struct vmap_area *find_vmap_area(unsigned long addr);
> > Make it "extern" since it becomes globally visible?
> 
> extern is not suggested any more to add for function declaration in
> header file, and removing it doesn't impact thing.
> 
OK, thanks for the hint: Reviewed-by: Uladzislau Rezki (Sony) <urezki@gmail.com>

--
Uladzislau Rezki

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

* Re: [PATCH 2/3] usercopy: Cast pointer to an integer once
  2022-06-13  9:51   ` Uladzislau Rezki
@ 2022-06-13 16:20     ` Kees Cook
  2022-06-13 16:27       ` Uladzislau Rezki
  0 siblings, 1 reply; 17+ messages in thread
From: Kees Cook @ 2022-06-13 16:20 UTC (permalink / raw)
  To: Uladzislau Rezki
  Cc: Matthew Wilcox (Oracle),
	linux-mm, Zorro Lang, linux-xfs, linux-hardening

On Mon, Jun 13, 2022 at 11:51:24AM +0200, Uladzislau Rezki wrote:
> On Sun, Jun 12, 2022 at 10:32:26PM +0100, Matthew Wilcox (Oracle) wrote:
> > Get rid of a lot of annoying casts by setting 'addr' once at the top
> > of the function.
> > 
> > Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> > ---
> >  mm/usercopy.c | 11 ++++++-----
> >  1 file changed, 6 insertions(+), 5 deletions(-)
> > 
> > diff --git a/mm/usercopy.c b/mm/usercopy.c
> > index fdd1bed3b90a..31deee7dd2f5 100644
> > --- a/mm/usercopy.c
> > +++ b/mm/usercopy.c
> > @@ -161,19 +161,20 @@ static inline void check_bogus_address(const unsigned long ptr, unsigned long n,
> >  static inline void check_heap_object(const void *ptr, unsigned long n,
> >  				     bool to_user)
> >  {
> > +	uintptr_t addr = (uintptr_t)ptr;
> >  	struct folio *folio;
> >  
> >  	if (is_kmap_addr(ptr)) {
> > -		unsigned long page_end = (unsigned long)ptr | (PAGE_SIZE - 1);
> > +		unsigned long page_end = addr | (PAGE_SIZE - 1);
> >  
> > -		if ((unsigned long)ptr + n - 1 > page_end)
> > +		if (addr + n - 1 > page_end)
> >  			usercopy_abort("kmap", NULL, to_user,
> >  					offset_in_page(ptr), n);
> >  		return;
> >  	}
> >  
> >  	if (is_vmalloc_addr(ptr)) {
> > -		struct vmap_area *area = find_vmap_area((unsigned long)ptr);
> > +		struct vmap_area *area = find_vmap_area(addr);
> >  		unsigned long offset;
> >  
> >  		if (!area) {
> > @@ -183,8 +184,8 @@ static inline void check_heap_object(const void *ptr, unsigned long n,
> >  
> >  		/* XXX: We should also abort for free vmap_areas */
> >  
> > -		offset = (unsigned long)ptr - area->va_start;
> > -		if ((unsigned long)ptr + n > area->va_end)
> > +		offset = addr - area->va_start;
> > +		if (addr + n > area->va_end)
> >  			usercopy_abort("vmalloc", NULL, to_user, offset, n);
> >  		return;
> >  	}
> > -- 
> > 2.35.1
> > 
> Looks good to me: Reviewed-by: Uladzislau Rezki (Sony) <urezki@gmail.com>

For the future, please put your tags ("Reviewed-by") on a separate line
or the workflow tools (b4, patchwork, etc) won't see it. :)

-- 
Kees Cook

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

* Re: [PATCH 1/3] usercopy: Handle vm_map_ram() areas
  2022-06-12 21:32 ` [PATCH 1/3] usercopy: Handle vm_map_ram() areas Matthew Wilcox (Oracle)
  2022-06-13 10:00   ` Uladzislau Rezki
@ 2022-06-13 16:23   ` Kees Cook
  2022-06-13 16:44     ` Matthew Wilcox
  1 sibling, 1 reply; 17+ messages in thread
From: Kees Cook @ 2022-06-13 16:23 UTC (permalink / raw)
  To: Matthew Wilcox (Oracle)
  Cc: linux-mm, Uladzislau Rezki, Zorro Lang, linux-xfs, linux-hardening

On Sun, Jun 12, 2022 at 10:32:25PM +0100, Matthew Wilcox (Oracle) wrote:
> vmalloc does not allocate a vm_struct for vm_map_ram() areas.  That causes
> us to deny usercopies from those areas.  This affects XFS which uses
> vm_map_ram() for its directories.
> 
> Fix this by calling find_vmap_area() instead of find_vm_area().

Thanks for the fixes!

> [...]
> +		/* XXX: We should also abort for free vmap_areas */

What's needed to detect this?

-- 
Kees Cook

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

* Re: [PATCH 0/3] Fixes for usercopy
  2022-06-12 21:32 [PATCH 0/3] Fixes for usercopy Matthew Wilcox (Oracle)
                   ` (3 preceding siblings ...)
  2022-06-13  8:04 ` [PATCH 0/3] Fixes for usercopy Zorro Lang
@ 2022-06-13 16:25 ` Kees Cook
  4 siblings, 0 replies; 17+ messages in thread
From: Kees Cook @ 2022-06-13 16:25 UTC (permalink / raw)
  To: willy; +Cc: Kees Cook, linux-mm, urezki, linux-xfs, linux-hardening, zlang

On Sun, 12 Jun 2022 22:32:24 +0100, Matthew Wilcox (Oracle) wrote:
> Kees, I'm hoping you'll take these through your tree.  I think they're
> all reasonable fixes to go into 5.19.  The first one is essential;
> it fixes two different bugs that people have hit.
> 
> Matthew Wilcox (Oracle) (3):
>   usercopy: Handle vm_map_ram() areas
>   usercopy: Cast pointer to an integer once
>   usercopy: Make usercopy resilient against ridiculously large copies
> 
> [...]

Applied to for-next/hardening, thanks!

[1/3] usercopy: Handle vm_map_ram() areas
      https://git.kernel.org/kees/c/751ad8bdde7f
[2/3] usercopy: Cast pointer to an integer once
      https://git.kernel.org/kees/c/de2ae8f5331a
[3/3] usercopy: Make usercopy resilient against ridiculously large copies
      https://git.kernel.org/kees/c/630b2014e60e

-- 
Kees Cook


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

* Re: [PATCH 2/3] usercopy: Cast pointer to an integer once
  2022-06-13 16:20     ` Kees Cook
@ 2022-06-13 16:27       ` Uladzislau Rezki
  0 siblings, 0 replies; 17+ messages in thread
From: Uladzislau Rezki @ 2022-06-13 16:27 UTC (permalink / raw)
  To: Kees Cook
  Cc: Matthew Wilcox (Oracle),
	Linux Memory Management List, Zorro Lang, linux-xfs,
	linux-hardening

>
> For the future, please put your tags ("Reviewed-by") on a separate line
> or the workflow tools (b4, patchwork, etc) won't see it. :)
>
OK. Thanks :)

-- 
Uladzislau Rezki

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

* Re: [PATCH 1/3] usercopy: Handle vm_map_ram() areas
  2022-06-13 16:23   ` Kees Cook
@ 2022-06-13 16:44     ` Matthew Wilcox
  2022-06-13 17:02       ` Uladzislau Rezki
  0 siblings, 1 reply; 17+ messages in thread
From: Matthew Wilcox @ 2022-06-13 16:44 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-mm, Uladzislau Rezki, Zorro Lang, linux-xfs, linux-hardening

On Mon, Jun 13, 2022 at 09:23:15AM -0700, Kees Cook wrote:
> On Sun, Jun 12, 2022 at 10:32:25PM +0100, Matthew Wilcox (Oracle) wrote:
> > vmalloc does not allocate a vm_struct for vm_map_ram() areas.  That causes
> > us to deny usercopies from those areas.  This affects XFS which uses
> > vm_map_ram() for its directories.
> > 
> > Fix this by calling find_vmap_area() instead of find_vm_area().
> 
> Thanks for the fixes!
> 
> > [...]
> > +		/* XXX: We should also abort for free vmap_areas */
> 
> What's needed to detect this?

I'm not entirely sure.  I only just learned of the existence of this
struct ;-)

        /*
         * The following two variables can be packed, because
         * a vmap_area object can be either:
         *    1) in "free" tree (root is free_vmap_area_root)
         *    2) or "busy" tree (root is vmap_area_root)
         */
        union {
                unsigned long subtree_max_size; /* in "free" tree */
                struct vm_struct *vm;           /* in "busy" tree */
        };

Hmm.  Actually, we only search vmap_area_root, so I suppose it can't
be a free area.  So this XXX can be removed, as we'll get NULL back
if we've got a pointer to a free area.  Ulad, do I have this right?

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

* Re: [PATCH 1/3] usercopy: Handle vm_map_ram() areas
  2022-06-13 16:44     ` Matthew Wilcox
@ 2022-06-13 17:02       ` Uladzislau Rezki
  2022-06-13 17:04         ` Kees Cook
  0 siblings, 1 reply; 17+ messages in thread
From: Uladzislau Rezki @ 2022-06-13 17:02 UTC (permalink / raw)
  To: Matthew Wilcox
  Cc: Kees Cook, linux-mm, Uladzislau Rezki, Zorro Lang, linux-xfs,
	linux-hardening

On Mon, Jun 13, 2022 at 05:44:35PM +0100, Matthew Wilcox wrote:
> On Mon, Jun 13, 2022 at 09:23:15AM -0700, Kees Cook wrote:
> > On Sun, Jun 12, 2022 at 10:32:25PM +0100, Matthew Wilcox (Oracle) wrote:
> > > vmalloc does not allocate a vm_struct for vm_map_ram() areas.  That causes
> > > us to deny usercopies from those areas.  This affects XFS which uses
> > > vm_map_ram() for its directories.
> > > 
> > > Fix this by calling find_vmap_area() instead of find_vm_area().
> > 
> > Thanks for the fixes!
> > 
> > > [...]
> > > +		/* XXX: We should also abort for free vmap_areas */
> > 
> > What's needed to detect this?
> 
> I'm not entirely sure.  I only just learned of the existence of this
> struct ;-)
> 
>         /*
>          * The following two variables can be packed, because
>          * a vmap_area object can be either:
>          *    1) in "free" tree (root is free_vmap_area_root)
>          *    2) or "busy" tree (root is vmap_area_root)
>          */
>         union {
>                 unsigned long subtree_max_size; /* in "free" tree */
>                 struct vm_struct *vm;           /* in "busy" tree */
>         };
> 
> Hmm.  Actually, we only search vmap_area_root, so I suppose it can't
> be a free area.  So this XXX can be removed, as we'll get NULL back
> if we've got a pointer to a free area.  Ulad, do I have this right?
>
Yep, we find here only allocated areas which bind to the "vmap_area_root"
tree, so it can not be a freed area. So we will not get a pointer to the
free area :)

--
Uladzislau Rezki

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

* Re: [PATCH 1/3] usercopy: Handle vm_map_ram() areas
  2022-06-13 17:02       ` Uladzislau Rezki
@ 2022-06-13 17:04         ` Kees Cook
  0 siblings, 0 replies; 17+ messages in thread
From: Kees Cook @ 2022-06-13 17:04 UTC (permalink / raw)
  To: Uladzislau Rezki
  Cc: Matthew Wilcox, linux-mm, Zorro Lang, linux-xfs, linux-hardening

On Mon, Jun 13, 2022 at 07:02:10PM +0200, Uladzislau Rezki wrote:
> On Mon, Jun 13, 2022 at 05:44:35PM +0100, Matthew Wilcox wrote:
> > On Mon, Jun 13, 2022 at 09:23:15AM -0700, Kees Cook wrote:
> > > On Sun, Jun 12, 2022 at 10:32:25PM +0100, Matthew Wilcox (Oracle) wrote:
> > > > vmalloc does not allocate a vm_struct for vm_map_ram() areas.  That causes
> > > > us to deny usercopies from those areas.  This affects XFS which uses
> > > > vm_map_ram() for its directories.
> > > > 
> > > > Fix this by calling find_vmap_area() instead of find_vm_area().
> > > 
> > > Thanks for the fixes!
> > > 
> > > > [...]
> > > > +		/* XXX: We should also abort for free vmap_areas */
> > > 
> > > What's needed to detect this?
> > 
> > I'm not entirely sure.  I only just learned of the existence of this
> > struct ;-)
> > 
> >         /*
> >          * The following two variables can be packed, because
> >          * a vmap_area object can be either:
> >          *    1) in "free" tree (root is free_vmap_area_root)
> >          *    2) or "busy" tree (root is vmap_area_root)
> >          */
> >         union {
> >                 unsigned long subtree_max_size; /* in "free" tree */
> >                 struct vm_struct *vm;           /* in "busy" tree */
> >         };
> > 
> > Hmm.  Actually, we only search vmap_area_root, so I suppose it can't
> > be a free area.  So this XXX can be removed, as we'll get NULL back
> > if we've got a pointer to a free area.  Ulad, do I have this right?
> >
> Yep, we find here only allocated areas which bind to the "vmap_area_root"
> tree, so it can not be a freed area. So we will not get a pointer to the
> free area :)

Thanks!

I've tweaked the patch to drop the XXX comment.

-- 
Kees Cook

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

end of thread, other threads:[~2022-06-13 19:10 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-12 21:32 [PATCH 0/3] Fixes for usercopy Matthew Wilcox (Oracle)
2022-06-12 21:32 ` [PATCH 1/3] usercopy: Handle vm_map_ram() areas Matthew Wilcox (Oracle)
2022-06-13 10:00   ` Uladzislau Rezki
2022-06-13 11:52     ` Baoquan He
2022-06-13 12:56       ` Uladzislau Rezki
2022-06-13 16:23   ` Kees Cook
2022-06-13 16:44     ` Matthew Wilcox
2022-06-13 17:02       ` Uladzislau Rezki
2022-06-13 17:04         ` Kees Cook
2022-06-12 21:32 ` [PATCH 2/3] usercopy: Cast pointer to an integer once Matthew Wilcox (Oracle)
2022-06-13  9:51   ` Uladzislau Rezki
2022-06-13 16:20     ` Kees Cook
2022-06-13 16:27       ` Uladzislau Rezki
2022-06-12 21:32 ` [PATCH 3/3] usercopy: Make usercopy resilient against ridiculously large copies Matthew Wilcox (Oracle)
2022-06-13  9:57   ` Uladzislau Rezki
2022-06-13  8:04 ` [PATCH 0/3] Fixes for usercopy Zorro Lang
2022-06-13 16:25 ` Kees Cook

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).