diff mbox series

[Pull,v2,Xenial,SRU,CVE-2019-11487] Avoid overflowing page reference count

Message ID 20190813170230.22451-1-connor.kuehl@canonical.com
State New
Headers show
Series [Pull,v2,Xenial,SRU,CVE-2019-11487] Avoid overflowing page reference count | expand

Pull-request

git://git.launchpad.net/~connork/+git/xenial CVE-2019-11487

Commit Message

Connor Kuehl Aug. 13, 2019, 5:02 p.m. UTC
v1 -> v2:

 * Relocated 'mm: add 'try_get_page()' helper' to before its first use in the series.
 * Fixed whitespace issue in 'mm: add 'try_get_page()' helper'

https://people.canonical.com/~ubuntu-security/cve/2019/CVE-2019-11487.html

From the link above:

"The Linux kernel before 5.1-rc5 allows page->_refcount reference count
overflow, with resultant use-after-free issues, if about 140 GiB of RAM
exists. This is related to fs/fuse/dev.c, fs/pipe.c, fs/splice.c,
include/linux/mm.h, include/linux/pipe_fs_i.h, kernel/trace/trace.c,
mm/gup.c, and mm/hugetlb.c. It can occur with FUSE requests."

Bionic has already received these patches during an upstream sync:
https://bugs.launchpad.net/bugs/1838459

Xenial felt like a bit of an involved backport that touched the mm subsystem,
and because of that, I think it is possible there's a breakage risk here that
I don't see as I'm not very familiar with mm.

It builds on all arches and I boot-tested amd64.

* mm: prevent get_user_pages() from overflowing page refcount

  This is the patch I'm most concerned about. It appears to be based on a
  refactoring patch which split a function into a number of others. Rather
  than try to backport the refactoring patch(es). I've backported the code
  to what I think is equivalent to what the refactored one does.

  In my backport, I didn't see an equivalent error path for this hunk from
  the original patch, so it was omitted:

=======================================
 			ret = split_huge_page(page); 

* mm, gup: ensure real head page is ref-counted when using hugepages
  This patch wasn't named as part of the CVE fix itself, but bringing this one in
  made it easier to apply the last fix "mm: prevent get_user_pages() from overflowing page refcount"
* mm: make page ref count overflow check tighter and more explicit
  Minor offset adjustments, and used atomic_read instead of a wrapper function
  that is introduced in a later commit (that commit makes a large number of changes
  so I felt it was better to just use the mechanism that it ultimately uses).
* fs: prevent page refcount overflow in pipe_buf_get
  Offset adjustment and manually change the function signature for buffer_pipe_buf_get
* mm: add 'try_get_page()' helper function
  Offset adjustment, directly use atomic_read and atomic_inc rather than the
  page_ref wrappers that aren't introduced until a later and larger commit.
* pipe: add pipe_buf_get() helper
  Clean cherry pick. Needed for "fs: prevent page refcount overflow in pipe_buf_get"

----------------------------------------------------------------
The following changes since commit ccb7110c8c340a5008de4d1959a1a11c869feb79:

  platform/x86: asus-wmi: Only Tell EC the OS will handle display hotkeys from asus_nb_wmi (2019-08-13 01:31:09 -0400)

are available in the Git repository at:

  git://git.launchpad.net/~connork/+git/xenial CVE-2019-11487

for you to fetch changes up to b7f98e42ebcfe6bfdc45ba1b153bb4f92c945262:

  mm: prevent get_user_pages() from overflowing page refcount (2019-08-13 07:23:30 -0700)

----------------------------------------------------------------
Linus Torvalds (3):
      mm: add 'try_get_page()' helper function
      mm: make page ref count overflow check tighter and more explicit
      mm: prevent get_user_pages() from overflowing page refcount

Matthew Wilcox (1):
      fs: prevent page refcount overflow in pipe_buf_get

Miklos Szeredi (1):
      pipe: add pipe_buf_get() helper

Punit Agrawal (1):
      mm, gup: ensure real head page is ref-counted when using hugepages

 fs/fuse/dev.c             | 12 ++++++------
 fs/pipe.c                 |  4 ++--
 fs/splice.c               | 12 ++++++++++--
 include/linux/mm.h        | 15 +++++++++++++-
 include/linux/pipe_fs_i.h | 17 ++++++++++++++--
 kernel/trace/trace.c      |  6 +++++-
 mm/gup.c                  | 50 ++++++++++++++++++++++++++++++++++-------------
 mm/hugetlb.c              | 16 ++++++++++++++-
 8 files changed, 103 insertions(+), 29 deletions(-)

Comments

Tyler Hicks Aug. 14, 2019, 11:03 p.m. UTC | #1
On 2019-08-13 10:02:30, Connor Kuehl wrote:
> v1 -> v2:
> 
>  * Relocated 'mm: add 'try_get_page()' helper' to before its first use in the series.
>  * Fixed whitespace issue in 'mm: add 'try_get_page()' helper'

Thanks for the fixups!

 Acked-by: Tyler Hicks <tyhicks@canonical.com>

Tyler

> 
> https://people.canonical.com/~ubuntu-security/cve/2019/CVE-2019-11487.html
> 
> From the link above:
> 
> "The Linux kernel before 5.1-rc5 allows page->_refcount reference count
> overflow, with resultant use-after-free issues, if about 140 GiB of RAM
> exists. This is related to fs/fuse/dev.c, fs/pipe.c, fs/splice.c,
> include/linux/mm.h, include/linux/pipe_fs_i.h, kernel/trace/trace.c,
> mm/gup.c, and mm/hugetlb.c. It can occur with FUSE requests."
> 
> Bionic has already received these patches during an upstream sync:
> https://bugs.launchpad.net/bugs/1838459
> 
> Xenial felt like a bit of an involved backport that touched the mm subsystem,
> and because of that, I think it is possible there's a breakage risk here that
> I don't see as I'm not very familiar with mm.
> 
> It builds on all arches and I boot-tested amd64.
> 
> * mm: prevent get_user_pages() from overflowing page refcount
> 
>   This is the patch I'm most concerned about. It appears to be based on a
>   refactoring patch which split a function into a number of others. Rather
>   than try to backport the refactoring patch(es). I've backported the code
>   to what I think is equivalent to what the refactored one does.
> 
>   In my backport, I didn't see an equivalent error path for this hunk from
>   the original patch, so it was omitted:
> 
> =======================================
> diff --git a/mm/gup.c b/mm/gup.c
> index 75029649baca..81e0bdefa2cc 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -295,7 +299,10 @@
>  static struct page *follow_pmd_mask(struct vm_area_struct *vma,
>  			if (pmd_trans_unstable(pmd)) 
>  				ret = -EBUSY; 
>  		} else { 
> -			get_page(page); 
> +			if (unlikely(!try_get_page(page))) { 
> +				spin_unlock(ptl); 
> +				return ERR_PTR(-ENOMEM); 
> +			} 
>  			spin_unlock(ptl); 
>  			lock_page(page); 
>  			ret = split_huge_page(page); 
> 
> * mm, gup: ensure real head page is ref-counted when using hugepages
>   This patch wasn't named as part of the CVE fix itself, but bringing this one in
>   made it easier to apply the last fix "mm: prevent get_user_pages() from overflowing page refcount"
> * mm: make page ref count overflow check tighter and more explicit
>   Minor offset adjustments, and used atomic_read instead of a wrapper function
>   that is introduced in a later commit (that commit makes a large number of changes
>   so I felt it was better to just use the mechanism that it ultimately uses).
> * fs: prevent page refcount overflow in pipe_buf_get
>   Offset adjustment and manually change the function signature for buffer_pipe_buf_get
> * mm: add 'try_get_page()' helper function
>   Offset adjustment, directly use atomic_read and atomic_inc rather than the
>   page_ref wrappers that aren't introduced until a later and larger commit.
> * pipe: add pipe_buf_get() helper
>   Clean cherry pick. Needed for "fs: prevent page refcount overflow in pipe_buf_get"
> 
> ----------------------------------------------------------------
> The following changes since commit ccb7110c8c340a5008de4d1959a1a11c869feb79:
> 
>   platform/x86: asus-wmi: Only Tell EC the OS will handle display hotkeys from asus_nb_wmi (2019-08-13 01:31:09 -0400)
> 
> are available in the Git repository at:
> 
>   git://git.launchpad.net/~connork/+git/xenial CVE-2019-11487
> 
> for you to fetch changes up to b7f98e42ebcfe6bfdc45ba1b153bb4f92c945262:
> 
>   mm: prevent get_user_pages() from overflowing page refcount (2019-08-13 07:23:30 -0700)
> 
> ----------------------------------------------------------------
> Linus Torvalds (3):
>       mm: add 'try_get_page()' helper function
>       mm: make page ref count overflow check tighter and more explicit
>       mm: prevent get_user_pages() from overflowing page refcount
> 
> Matthew Wilcox (1):
>       fs: prevent page refcount overflow in pipe_buf_get
> 
> Miklos Szeredi (1):
>       pipe: add pipe_buf_get() helper
> 
> Punit Agrawal (1):
>       mm, gup: ensure real head page is ref-counted when using hugepages
> 
>  fs/fuse/dev.c             | 12 ++++++------
>  fs/pipe.c                 |  4 ++--
>  fs/splice.c               | 12 ++++++++++--
>  include/linux/mm.h        | 15 +++++++++++++-
>  include/linux/pipe_fs_i.h | 17 ++++++++++++++--
>  kernel/trace/trace.c      |  6 +++++-
>  mm/gup.c                  | 50 ++++++++++++++++++++++++++++++++++-------------
>  mm/hugetlb.c              | 16 ++++++++++++++-
>  8 files changed, 103 insertions(+), 29 deletions(-)
> 
> -- 
> kernel-team mailing list
> kernel-team@lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
Stefan Bader Aug. 26, 2019, 1:55 p.m. UTC | #2
On 13.08.19 19:02, Connor Kuehl wrote:
> git://git.launchpad.net/~connork/+git/xenial CVE-2019-11487

Acked-by: Stefan Bader <stefan.bader@canonical.com>
Kleber Sacilotto de Souza Sept. 3, 2019, 1:06 p.m. UTC | #3
On 8/13/19 7:02 PM, Connor Kuehl wrote:
> v1 -> v2:
> 
>  * Relocated 'mm: add 'try_get_page()' helper' to before its first use in the series.
>  * Fixed whitespace issue in 'mm: add 'try_get_page()' helper'
> 
> https://people.canonical.com/~ubuntu-security/cve/2019/CVE-2019-11487.html
> 
> From the link above:
> 
> "The Linux kernel before 5.1-rc5 allows page->_refcount reference count
> overflow, with resultant use-after-free issues, if about 140 GiB of RAM
> exists. This is related to fs/fuse/dev.c, fs/pipe.c, fs/splice.c,
> include/linux/mm.h, include/linux/pipe_fs_i.h, kernel/trace/trace.c,
> mm/gup.c, and mm/hugetlb.c. It can occur with FUSE requests."
> 
> Bionic has already received these patches during an upstream sync:
> https://bugs.launchpad.net/bugs/1838459
> 
> Xenial felt like a bit of an involved backport that touched the mm subsystem,
> and because of that, I think it is possible there's a breakage risk here that
> I don't see as I'm not very familiar with mm.
> 
> It builds on all arches and I boot-tested amd64.
> 
> * mm: prevent get_user_pages() from overflowing page refcount
> 
>   This is the patch I'm most concerned about. It appears to be based on a
>   refactoring patch which split a function into a number of others. Rather
>   than try to backport the refactoring patch(es). I've backported the code
>   to what I think is equivalent to what the refactored one does.
> 
>   In my backport, I didn't see an equivalent error path for this hunk from
>   the original patch, so it was omitted:
> 
> =======================================
> diff --git a/mm/gup.c b/mm/gup.c
> index 75029649baca..81e0bdefa2cc 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -295,7 +299,10 @@
>  static struct page *follow_pmd_mask(struct vm_area_struct *vma,
>  			if (pmd_trans_unstable(pmd)) 
>  				ret = -EBUSY; 
>  		} else { 
> -			get_page(page); 
> +			if (unlikely(!try_get_page(page))) { 
> +				spin_unlock(ptl); 
> +				return ERR_PTR(-ENOMEM); 
> +			} 
>  			spin_unlock(ptl); 
>  			lock_page(page); 
>  			ret = split_huge_page(page); 
> 
> * mm, gup: ensure real head page is ref-counted when using hugepages
>   This patch wasn't named as part of the CVE fix itself, but bringing this one in
>   made it easier to apply the last fix "mm: prevent get_user_pages() from overflowing page refcount"
> * mm: make page ref count overflow check tighter and more explicit
>   Minor offset adjustments, and used atomic_read instead of a wrapper function
>   that is introduced in a later commit (that commit makes a large number of changes
>   so I felt it was better to just use the mechanism that it ultimately uses).
> * fs: prevent page refcount overflow in pipe_buf_get
>   Offset adjustment and manually change the function signature for buffer_pipe_buf_get
> * mm: add 'try_get_page()' helper function
>   Offset adjustment, directly use atomic_read and atomic_inc rather than the
>   page_ref wrappers that aren't introduced until a later and larger commit.
> * pipe: add pipe_buf_get() helper
>   Clean cherry pick. Needed for "fs: prevent page refcount overflow in pipe_buf_get"
> 
> ----------------------------------------------------------------
> The following changes since commit ccb7110c8c340a5008de4d1959a1a11c869feb79:
> 
>   platform/x86: asus-wmi: Only Tell EC the OS will handle display hotkeys from asus_nb_wmi (2019-08-13 01:31:09 -0400)
> 
> are available in the Git repository at:
> 
>   git://git.launchpad.net/~connork/+git/xenial CVE-2019-11487
> 
> for you to fetch changes up to b7f98e42ebcfe6bfdc45ba1b153bb4f92c945262:
> 
>   mm: prevent get_user_pages() from overflowing page refcount (2019-08-13 07:23:30 -0700)

Applied to xenial/master-next branch.

Thanks,
Kleber

> 
> ----------------------------------------------------------------
> Linus Torvalds (3):
>       mm: add 'try_get_page()' helper function
>       mm: make page ref count overflow check tighter and more explicit
>       mm: prevent get_user_pages() from overflowing page refcount
> 
> Matthew Wilcox (1):
>       fs: prevent page refcount overflow in pipe_buf_get
> 
> Miklos Szeredi (1):
>       pipe: add pipe_buf_get() helper
> 
> Punit Agrawal (1):
>       mm, gup: ensure real head page is ref-counted when using hugepages
> 
>  fs/fuse/dev.c             | 12 ++++++------
>  fs/pipe.c                 |  4 ++--
>  fs/splice.c               | 12 ++++++++++--
>  include/linux/mm.h        | 15 +++++++++++++-
>  include/linux/pipe_fs_i.h | 17 ++++++++++++++--
>  kernel/trace/trace.c      |  6 +++++-
>  mm/gup.c                  | 50 ++++++++++++++++++++++++++++++++++-------------
>  mm/hugetlb.c              | 16 ++++++++++++++-
>  8 files changed, 103 insertions(+), 29 deletions(-)
>
diff mbox series

Patch

diff --git a/mm/gup.c b/mm/gup.c
index 75029649baca..81e0bdefa2cc 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -295,7 +299,10 @@ 
 static struct page *follow_pmd_mask(struct vm_area_struct *vma,
 			if (pmd_trans_unstable(pmd)) 
 				ret = -EBUSY; 
 		} else { 
-			get_page(page); 
+			if (unlikely(!try_get_page(page))) { 
+				spin_unlock(ptl); 
+				return ERR_PTR(-ENOMEM); 
+			} 
 			spin_unlock(ptl); 
 			lock_page(page);