--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Date: Wed, 29 May 2019 18:02:44 +0100
+Subject: binder: Replace "%p" with "%pK" for stable
+
+From: Ben Hutchings <ben.hutchings@codethink.co.uk>
+
+This was done as part of upstream commits fdfb4a99b6ab "8inder:
+separate binder allocator structure from binder proc", 19c987241ca1
+"binder: separate out binder_alloc functions", and 7a4408c6bd3e
+"binder: make sure accesses to proc/thread are safe". However, those
+commits made lots of other changes that are not suitable for stable.
+
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/android/binder.c | 28 ++++++++++++++--------------
+ 1 file changed, 14 insertions(+), 14 deletions(-)
+
+--- a/drivers/android/binder.c
++++ b/drivers/android/binder.c
+@@ -488,7 +488,7 @@ static void binder_insert_free_buffer(st
+ new_buffer_size = binder_buffer_size(proc, new_buffer);
+
+ binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
+- "%d: add free buffer, size %zd, at %p\n",
++ "%d: add free buffer, size %zd, at %pK\n",
+ proc->pid, new_buffer_size, new_buffer);
+
+ while (*p) {
+@@ -566,7 +566,7 @@ static int binder_update_page_range(stru
+ struct mm_struct *mm;
+
+ binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
+- "%d: %s pages %p-%p\n", proc->pid,
++ "%d: %s pages %pK-%pK\n", proc->pid,
+ allocate ? "allocate" : "free", start, end);
+
+ if (end <= start)
+@@ -606,7 +606,7 @@ static int binder_update_page_range(stru
+ BUG_ON(*page);
+ *page = alloc_page(GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
+ if (*page == NULL) {
+- pr_err("%d: binder_alloc_buf failed for page at %p\n",
++ pr_err("%d: binder_alloc_buf failed for page at %pK\n",
+ proc->pid, page_addr);
+ goto err_alloc_page_failed;
+ }
+@@ -615,7 +615,7 @@ static int binder_update_page_range(stru
+ flush_cache_vmap((unsigned long)page_addr,
+ (unsigned long)page_addr + PAGE_SIZE);
+ if (ret != 1) {
+- pr_err("%d: binder_alloc_buf failed to map page at %p in kernel\n",
++ pr_err("%d: binder_alloc_buf failed to map page at %pK in kernel\n",
+ proc->pid, page_addr);
+ goto err_map_kernel_failed;
+ }
+@@ -719,7 +719,7 @@ static struct binder_buffer *binder_allo
+ }
+
+ binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
+- "%d: binder_alloc_buf size %zd got buffer %p size %zd\n",
++ "%d: binder_alloc_buf size %zd got buffer %pK size %zd\n",
+ proc->pid, size, buffer, buffer_size);
+
+ has_page_addr =
+@@ -749,7 +749,7 @@ static struct binder_buffer *binder_allo
+ binder_insert_free_buffer(proc, new_buffer);
+ }
+ binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
+- "%d: binder_alloc_buf size %zd got %p\n",
++ "%d: binder_alloc_buf size %zd got %pK\n",
+ proc->pid, size, buffer);
+ buffer->data_size = data_size;
+ buffer->offsets_size = offsets_size;
+@@ -789,7 +789,7 @@ static void binder_delete_free_buffer(st
+ if (buffer_end_page(prev) == buffer_end_page(buffer))
+ free_page_end = 0;
+ binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
+- "%d: merge free, buffer %p share page with %p\n",
++ "%d: merge free, buffer %pK share page with %pK\n",
+ proc->pid, buffer, prev);
+ }
+
+@@ -802,14 +802,14 @@ static void binder_delete_free_buffer(st
+ buffer_start_page(buffer))
+ free_page_start = 0;
+ binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
+- "%d: merge free, buffer %p share page with %p\n",
++ "%d: merge free, buffer %pK share page with %pK\n",
+ proc->pid, buffer, prev);
+ }
+ }
+ list_del(&buffer->entry);
+ if (free_page_start || free_page_end) {
+ binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
+- "%d: merge free, buffer %p do not share page%s%s with %p or %p\n",
++ "%d: merge free, buffer %pK do not share page%s%s with %pK or %pK\n",
+ proc->pid, buffer, free_page_start ? "" : " end",
+ free_page_end ? "" : " start", prev, next);
+ binder_update_page_range(proc, 0, free_page_start ?
+@@ -830,7 +830,7 @@ static void binder_free_buf(struct binde
+ ALIGN(buffer->offsets_size, sizeof(void *));
+
+ binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
+- "%d: binder_free_buf %p size %zd buffer_size %zd\n",
++ "%d: binder_free_buf %pK size %zd buffer_size %zd\n",
+ proc->pid, buffer, size, buffer_size);
+
+ BUG_ON(buffer->free);
+@@ -2930,7 +2930,7 @@ static int binder_mmap(struct file *filp
+ #ifdef CONFIG_CPU_CACHE_VIPT
+ if (cache_is_vipt_aliasing()) {
+ while (CACHE_COLOUR((vma->vm_start ^ (uint32_t)proc->buffer))) {
+- pr_info("binder_mmap: %d %lx-%lx maps %p bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
++ pr_info("binder_mmap: %d %lx-%lx maps %pK bad alignment\n", proc->pid, vma->vm_start, vma->vm_end, proc->buffer);
+ vma->vm_start += PAGE_SIZE;
+ }
+ }
+@@ -3191,7 +3191,7 @@ static void binder_deferred_release(stru
+
+ page_addr = proc->buffer + i * PAGE_SIZE;
+ binder_debug(BINDER_DEBUG_BUFFER_ALLOC,
+- "%s: %d: page %d at %p not freed\n",
++ "%s: %d: page %d at %pK not freed\n",
+ __func__, proc->pid, i, page_addr);
+ unmap_kernel_range((unsigned long)page_addr, PAGE_SIZE);
+ __free_page(proc->pages[i]);
+@@ -3294,7 +3294,7 @@ static void print_binder_transaction(str
+ static void print_binder_buffer(struct seq_file *m, const char *prefix,
+ struct binder_buffer *buffer)
+ {
+- seq_printf(m, "%s %d: %p size %zd:%zd %s\n",
++ seq_printf(m, "%s %d: %pK size %zd:%zd %s\n",
+ prefix, buffer->debug_id, buffer->data,
+ buffer->data_size, buffer->offsets_size,
+ buffer->transaction ? "active" : "delivered");
+@@ -3397,7 +3397,7 @@ static void print_binder_node(struct seq
+
+ static void print_binder_ref(struct seq_file *m, struct binder_ref *ref)
+ {
+- seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %p\n",
++ seq_printf(m, " ref %d: desc %d %snode %d s %d w %d d %pK\n",
+ ref->debug_id, ref->desc, ref->node->proc ? "" : "dead ",
+ ref->node->debug_id, ref->strong, ref->weak, ref->death);
+ }
--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Todd Kjos <tkjos@android.com>
+Date: Wed, 7 Feb 2018 13:57:37 -0800
+Subject: binder: replace "%p" with "%pK"
+
+From: Todd Kjos <tkjos@android.com>
+
+commit 8ca86f1639ec5890d400fff9211aca22d0a392eb upstream.
+
+The format specifier "%p" can leak kernel addresses. Use
+"%pK" instead. There were 4 remaining cases in binder.c.
+
+Signed-off-by: Todd Kjos <tkjos@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+[bwh: Backported to 4.9: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/android/binder.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+--- a/drivers/android/binder.c
++++ b/drivers/android/binder.c
+@@ -1260,7 +1260,7 @@ static void binder_transaction_buffer_re
+ int debug_id = buffer->debug_id;
+
+ binder_debug(BINDER_DEBUG_TRANSACTION,
+- "%d buffer release %d, size %zd-%zd, failed at %p\n",
++ "%d buffer release %d, size %zd-%zd, failed at %pK\n",
+ proc->pid, buffer->debug_id,
+ buffer->data_size, buffer->offsets_size, failed_at);
+
+@@ -2123,7 +2123,7 @@ static int binder_thread_write(struct bi
+ }
+ }
+ binder_debug(BINDER_DEBUG_DEAD_BINDER,
+- "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n",
++ "%d:%d BC_DEAD_BINDER_DONE %016llx found %pK\n",
+ proc->pid, thread->pid, (u64)cookie,
+ death);
+ if (death == NULL) {
+@@ -3272,7 +3272,7 @@ static void print_binder_transaction(str
+ struct binder_transaction *t)
+ {
+ seq_printf(m,
+- "%s %d: %p from %d:%d to %d:%d code %x flags %x pri %ld r%d",
++ "%s %d: %pK from %d:%d to %d:%d code %x flags %x pri %ld r%d",
+ prefix, t->debug_id, t,
+ t->from ? t->from->proc->pid : 0,
+ t->from ? t->from->pid : 0,
+@@ -3286,7 +3286,7 @@ static void print_binder_transaction(str
+ if (t->buffer->target_node)
+ seq_printf(m, " node %d",
+ t->buffer->target_node->debug_id);
+- seq_printf(m, " size %zd:%zd data %p\n",
++ seq_printf(m, " size %zd:%zd data %pK\n",
+ t->buffer->data_size, t->buffer->offsets_size,
+ t->buffer->data);
+ }
--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 6 Apr 2017 13:14:40 +0100
+Subject: brcmfmac: add length checks in scheduled scan result handler
+
+From: Arend Van Spriel <arend.vanspriel@broadcom.com>
+
+commit 4835f37e3bafc138f8bfa3cbed2920dd56fed283 upstream.
+
+Assure the event data buffer is long enough to hold the array
+of netinfo items and that SSID length does not exceed the maximum
+of 32 characters as per 802.11 spec.
+
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+[bwh: Backported to 4.9:
+ - Move the assignment to "data" along with the assignment to "netinfo_start"
+ that depends on it
+ - Adjust context, indentation]
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 14 +++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -3220,6 +3220,7 @@ brcmf_notify_sched_scan_results(struct b
+ struct brcmf_pno_scanresults_le *pfn_result;
+ u32 result_count;
+ u32 status;
++ u32 datalen;
+
+ brcmf_dbg(SCAN, "Enter\n");
+
+@@ -3245,6 +3246,14 @@ brcmf_notify_sched_scan_results(struct b
+ if (result_count > 0) {
+ int i;
+
++ data += sizeof(struct brcmf_pno_scanresults_le);
++ netinfo_start = (struct brcmf_pno_net_info_le *)data;
++ datalen = e->datalen - ((void *)netinfo_start - (void *)pfn_result);
++ if (datalen < result_count * sizeof(*netinfo)) {
++ brcmf_err("insufficient event data\n");
++ goto out_err;
++ }
++
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ ssid = kcalloc(result_count, sizeof(*ssid), GFP_KERNEL);
+ channel = kcalloc(result_count, sizeof(*channel), GFP_KERNEL);
+@@ -3254,9 +3263,6 @@ brcmf_notify_sched_scan_results(struct b
+ }
+
+ request->wiphy = wiphy;
+- data += sizeof(struct brcmf_pno_scanresults_le);
+- netinfo_start = (struct brcmf_pno_net_info_le *)data;
+-
+ for (i = 0; i < result_count; i++) {
+ netinfo = &netinfo_start[i];
+ if (!netinfo) {
+@@ -3266,6 +3272,8 @@ brcmf_notify_sched_scan_results(struct b
+ goto out_err;
+ }
+
++ if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
++ netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
+ brcmf_dbg(SCAN, "SSID:%s Channel:%d\n",
+ netinfo->SSID, netinfo->channel);
+ memcpy(ssid[i].ssid, netinfo->SSID, netinfo->SSID_len);
--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Arend van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 14 Feb 2019 13:43:48 +0100
+Subject: brcmfmac: add subtype check for event handling in data path
+
+From: Arend van Spriel <arend.vanspriel@broadcom.com>
+
+commit a4176ec356c73a46c07c181c6d04039fafa34a9f upstream.
+
+For USB there is no separate channel being used to pass events
+from firmware to the host driver and as such are passed over the
+data path. In order to detect mock event messages an additional
+check is needed on event subtype. This check is added conditionally
+using unlikely() keyword.
+
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c | 5 ++--
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h | 16 ++++++++++----
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 2 -
+ 3 files changed, 16 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+@@ -339,7 +339,8 @@ void brcmf_rx_frame(struct device *dev,
+ } else {
+ /* Process special event packets */
+ if (handle_event)
+- brcmf_fweh_process_skb(ifp->drvr, skb);
++ brcmf_fweh_process_skb(ifp->drvr, skb,
++ BCMILCP_SUBTYPE_VENDOR_LONG);
+
+ brcmf_netif_rx(ifp, skb);
+ }
+@@ -356,7 +357,7 @@ void brcmf_rx_event(struct device *dev,
+ if (brcmf_rx_hdrpull(drvr, skb, &ifp))
+ return;
+
+- brcmf_fweh_process_skb(ifp->drvr, skb);
++ brcmf_fweh_process_skb(ifp->drvr, skb, 0);
+ brcmu_pkt_buf_free_skb(skb);
+ }
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.h
+@@ -181,7 +181,7 @@ enum brcmf_fweh_event_code {
+ */
+ #define BRCM_OUI "\x00\x10\x18"
+ #define BCMILCP_BCM_SUBTYPE_EVENT 1
+-
++#define BCMILCP_SUBTYPE_VENDOR_LONG 32769
+
+ /**
+ * struct brcm_ethhdr - broadcom specific ether header.
+@@ -302,10 +302,10 @@ void brcmf_fweh_process_event(struct brc
+ void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
+
+ static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
+- struct sk_buff *skb)
++ struct sk_buff *skb, u16 stype)
+ {
+ struct brcmf_event *event_packet;
+- u16 usr_stype;
++ u16 subtype, usr_stype;
+
+ /* only process events when protocol matches */
+ if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
+@@ -314,8 +314,16 @@ static inline void brcmf_fweh_process_sk
+ if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
+ return;
+
+- /* check for BRCM oui match */
+ event_packet = (struct brcmf_event *)skb_mac_header(skb);
++
++ /* check subtype if needed */
++ if (unlikely(stype)) {
++ subtype = get_unaligned_be16(&event_packet->hdr.subtype);
++ if (subtype != stype)
++ return;
++ }
++
++ /* check for BRCM oui match */
+ if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
+ sizeof(event_packet->hdr.oui)))
+ return;
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+@@ -1114,7 +1114,7 @@ static void brcmf_msgbuf_process_event(s
+
+ skb->protocol = eth_type_trans(skb, ifp->ndev);
+
+- brcmf_fweh_process_skb(ifp->drvr, skb);
++ brcmf_fweh_process_skb(ifp->drvr, skb, 0);
+
+ exit:
+ brcmu_pkt_buf_free_skb(skb);
--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Arend van Spriel <arend.vanspriel@broadcom.com>
+Date: Thu, 14 Feb 2019 13:43:47 +0100
+Subject: brcmfmac: assure SSID length from firmware is limited
+
+From: Arend van Spriel <arend.vanspriel@broadcom.com>
+
+commit 1b5e2423164b3670e8bc9174e4762d297990deff upstream.
+
+The SSID length as received from firmware should not exceed
+IEEE80211_MAX_SSID_LEN as that would result in heap overflow.
+
+Reviewed-by: Hante Meuleman <hante.meuleman@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Reviewed-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+[bwh: Backported to 4.9: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
+@@ -3579,6 +3579,8 @@ brcmf_wowl_nd_results(struct brcmf_if *i
+
+ data += sizeof(struct brcmf_pno_scanresults_le);
+ netinfo = (struct brcmf_pno_net_info_le *)data;
++ if (netinfo->SSID_len > IEEE80211_MAX_SSID_LEN)
++ netinfo->SSID_len = IEEE80211_MAX_SSID_LEN;
+ memcpy(cfg->wowl.nd->ssid.ssid, netinfo->SSID, netinfo->SSID_len);
+ cfg->wowl.nd->ssid.ssid_len = netinfo->SSID_len;
+ cfg->wowl.nd->n_channels = 1;
--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Andrea Arcangeli <aarcange@redhat.com>
+Date: Thu, 18 Apr 2019 17:50:52 -0700
+Subject: coredump: fix race condition between mmget_not_zero()/get_task_mm() and core dumping
+
+From: Andrea Arcangeli <aarcange@redhat.com>
+
+commit 04f5866e41fb70690e28397487d8bd8eea7d712a upstream.
+
+The core dumping code has always run without holding the mmap_sem for
+writing, despite that is the only way to ensure that the entire vma
+layout will not change from under it. Only using some signal
+serialization on the processes belonging to the mm is not nearly enough.
+This was pointed out earlier. For example in Hugh's post from Jul 2017:
+
+ https://lkml.kernel.org/r/alpine.LSU.2.11.1707191716030.2055@eggly.anvils
+
+ "Not strictly relevant here, but a related note: I was very surprised
+ to discover, only quite recently, how handle_mm_fault() may be called
+ without down_read(mmap_sem) - when core dumping. That seems a
+ misguided optimization to me, which would also be nice to correct"
+
+In particular because the growsdown and growsup can move the
+vm_start/vm_end the various loops the core dump does around the vma will
+not be consistent if page faults can happen concurrently.
+
+Pretty much all users calling mmget_not_zero()/get_task_mm() and then
+taking the mmap_sem had the potential to introduce unexpected side
+effects in the core dumping code.
+
+Adding mmap_sem for writing around the ->core_dump invocation is a
+viable long term fix, but it requires removing all copy user and page
+faults and to replace them with get_dump_page() for all binary formats
+which is not suitable as a short term fix.
+
+For the time being this solution manually covers the places that can
+confuse the core dump either by altering the vma layout or the vma flags
+while it runs. Once ->core_dump runs under mmap_sem for writing the
+function mmget_still_valid() can be dropped.
+
+Allowing mmap_sem protected sections to run in parallel with the
+coredump provides some minor parallelism advantage to the swapoff code
+(which seems to be safe enough by never mangling any vma field and can
+keep doing swapins in parallel to the core dumping) and to some other
+corner case.
+
+In order to facilitate the backporting I added "Fixes: 86039bd3b4e6"
+however the side effect of this same race condition in /proc/pid/mem
+should be reproducible since before 2.6.12-rc2 so I couldn't add any
+other "Fixes:" because there's no hash beyond the git genesis commit.
+
+Because find_extend_vma() is the only location outside of the process
+context that could modify the "mm" structures under mmap_sem for
+reading, by adding the mmget_still_valid() check to it, all other cases
+that take the mmap_sem for reading don't need the new check after
+mmget_not_zero()/get_task_mm(). The expand_stack() in page fault
+context also doesn't need the new check, because all tasks under core
+dumping are frozen.
+
+Link: http://lkml.kernel.org/r/20190325224949.11068-1-aarcange@redhat.com
+Fixes: 86039bd3b4e6 ("userfaultfd: add new syscall to provide memory externalization")
+Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
+Reported-by: Jann Horn <jannh@google.com>
+Suggested-by: Oleg Nesterov <oleg@redhat.com>
+Acked-by: Peter Xu <peterx@redhat.com>
+Reviewed-by: Mike Rapoport <rppt@linux.ibm.com>
+Reviewed-by: Oleg Nesterov <oleg@redhat.com>
+Reviewed-by: Jann Horn <jannh@google.com>
+Acked-by: Jason Gunthorpe <jgg@mellanox.com>
+Acked-by: Michal Hocko <mhocko@suse.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+[bwh: Backported to 4.9:
+ - Drop changes in Infiniband and userfaultfd_event_wait_completion()
+ - Adjust filename, context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/proc/task_mmu.c | 18 ++++++++++++++++++
+ fs/userfaultfd.c | 7 +++++++
+ include/linux/sched.h | 21 +++++++++++++++++++++
+ mm/mmap.c | 7 ++++++-
+ 4 files changed, 52 insertions(+), 1 deletion(-)
+
+--- a/fs/proc/task_mmu.c
++++ b/fs/proc/task_mmu.c
+@@ -1057,6 +1057,24 @@ static ssize_t clear_refs_write(struct f
+ count = -EINTR;
+ goto out_mm;
+ }
++ /*
++ * Avoid to modify vma->vm_flags
++ * without locked ops while the
++ * coredump reads the vm_flags.
++ */
++ if (!mmget_still_valid(mm)) {
++ /*
++ * Silently return "count"
++ * like if get_task_mm()
++ * failed. FIXME: should this
++ * function have returned
++ * -ESRCH if get_task_mm()
++ * failed like if
++ * get_proc_task() fails?
++ */
++ up_write(&mm->mmap_sem);
++ goto out_mm;
++ }
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ vma->vm_flags &= ~VM_SOFTDIRTY;
+ vma_set_page_prot(vma);
+--- a/fs/userfaultfd.c
++++ b/fs/userfaultfd.c
+@@ -479,6 +479,8 @@ static int userfaultfd_release(struct in
+ * taking the mmap_sem for writing.
+ */
+ down_write(&mm->mmap_sem);
++ if (!mmget_still_valid(mm))
++ goto skip_mm;
+ prev = NULL;
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ cond_resched();
+@@ -501,6 +503,7 @@ static int userfaultfd_release(struct in
+ vma->vm_flags = new_flags;
+ vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
+ }
++skip_mm:
+ up_write(&mm->mmap_sem);
+ mmput(mm);
+ wakeup:
+@@ -802,6 +805,8 @@ static int userfaultfd_register(struct u
+ goto out;
+
+ down_write(&mm->mmap_sem);
++ if (!mmget_still_valid(mm))
++ goto out_unlock;
+ vma = find_vma_prev(mm, start, &prev);
+ if (!vma)
+ goto out_unlock;
+@@ -947,6 +952,8 @@ static int userfaultfd_unregister(struct
+ goto out;
+
+ down_write(&mm->mmap_sem);
++ if (!mmget_still_valid(mm))
++ goto out_unlock;
+ vma = find_vma_prev(mm, start, &prev);
+ if (!vma)
+ goto out_unlock;
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -2938,6 +2938,27 @@ static inline bool mmget_not_zero(struct
+ return atomic_inc_not_zero(&mm->mm_users);
+ }
+
++/*
++ * This has to be called after a get_task_mm()/mmget_not_zero()
++ * followed by taking the mmap_sem for writing before modifying the
++ * vmas or anything the coredump pretends not to change from under it.
++ *
++ * NOTE: find_extend_vma() called from GUP context is the only place
++ * that can modify the "mm" (notably the vm_start/end) under mmap_sem
++ * for reading and outside the context of the process, so it is also
++ * the only case that holds the mmap_sem for reading that must call
++ * this function. Generally if the mmap_sem is hold for reading
++ * there's no need of this check after get_task_mm()/mmget_not_zero().
++ *
++ * This function can be obsoleted and the check can be removed, after
++ * the coredump code will hold the mmap_sem for writing before
++ * invoking the ->core_dump methods.
++ */
++static inline bool mmget_still_valid(struct mm_struct *mm)
++{
++ return likely(!mm->core_state);
++}
++
+ /* mmput gets rid of the mappings and all user-space */
+ extern void mmput(struct mm_struct *);
+ #ifdef CONFIG_MMU
+--- a/mm/mmap.c
++++ b/mm/mmap.c
+@@ -44,6 +44,7 @@
+ #include <linux/userfaultfd_k.h>
+ #include <linux/moduleparam.h>
+ #include <linux/pkeys.h>
++#include <linux/sched.h>
+
+ #include <asm/uaccess.h>
+ #include <asm/cacheflush.h>
+@@ -2448,7 +2449,8 @@ find_extend_vma(struct mm_struct *mm, un
+ vma = find_vma_prev(mm, addr, &prev);
+ if (vma && (vma->vm_start <= addr))
+ return vma;
+- if (!prev || expand_stack(prev, addr))
++ /* don't alter vm_end if the coredump is running */
++ if (!prev || !mmget_still_valid(mm) || expand_stack(prev, addr))
+ return NULL;
+ if (prev->vm_flags & VM_LOCKED)
+ populate_vma_page_range(prev, addr, prev->vm_end, NULL);
+@@ -2474,6 +2476,9 @@ find_extend_vma(struct mm_struct *mm, un
+ return vma;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ return NULL;
++ /* don't alter vm_start if the coredump is running */
++ if (!mmget_still_valid(mm))
++ return NULL;
+ start = vma->vm_start;
+ if (expand_stack(vma, addr))
+ return NULL;
--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Matthew Wilcox <willy@infradead.org>
+Date: Fri, 5 Apr 2019 14:02:10 -0700
+Subject: fs: prevent page refcount overflow in pipe_buf_get
+
+From: Matthew Wilcox <willy@infradead.org>
+
+commit 15fab63e1e57be9fdb5eec1bbc5916e9825e9acb upstream.
+
+Change pipe_buf_get() to return a bool indicating whether it succeeded
+in raising the refcount of the page (if the thing in the pipe is a page).
+This removes another mechanism for overflowing the page refcount. All
+callers converted to handle a failure.
+
+Reported-by: Jann Horn <jannh@google.com>
+Signed-off-by: Matthew Wilcox <willy@infradead.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+[bwh: Backported to 4.9: adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/fuse/dev.c | 12 ++++++------
+ fs/pipe.c | 4 ++--
+ fs/splice.c | 12 ++++++++++--
+ include/linux/pipe_fs_i.h | 10 ++++++----
+ kernel/trace/trace.c | 6 +++++-
+ 5 files changed, 29 insertions(+), 15 deletions(-)
+
+--- a/fs/fuse/dev.c
++++ b/fs/fuse/dev.c
+@@ -1975,10 +1975,8 @@ static ssize_t fuse_dev_splice_write(str
+ rem += pipe->bufs[(pipe->curbuf + idx) & (pipe->buffers - 1)].len;
+
+ ret = -EINVAL;
+- if (rem < len) {
+- pipe_unlock(pipe);
+- goto out;
+- }
++ if (rem < len)
++ goto out_free;
+
+ rem = len;
+ while (rem) {
+@@ -1996,7 +1994,9 @@ static ssize_t fuse_dev_splice_write(str
+ pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
+ pipe->nrbufs--;
+ } else {
+- pipe_buf_get(pipe, ibuf);
++ if (!pipe_buf_get(pipe, ibuf))
++ goto out_free;
++
+ *obuf = *ibuf;
+ obuf->flags &= ~PIPE_BUF_FLAG_GIFT;
+ obuf->len = rem;
+@@ -2019,11 +2019,11 @@ static ssize_t fuse_dev_splice_write(str
+ ret = fuse_dev_do_write(fud, &cs, len);
+
+ pipe_lock(pipe);
++out_free:
+ for (idx = 0; idx < nbuf; idx++)
+ pipe_buf_release(pipe, &bufs[idx]);
+ pipe_unlock(pipe);
+
+-out:
+ kfree(bufs);
+ return ret;
+ }
+--- a/fs/pipe.c
++++ b/fs/pipe.c
+@@ -193,9 +193,9 @@ EXPORT_SYMBOL(generic_pipe_buf_steal);
+ * in the tee() system call, when we duplicate the buffers in one
+ * pipe into another.
+ */
+-void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
++bool generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf)
+ {
+- get_page(buf->page);
++ return try_get_page(buf->page);
+ }
+ EXPORT_SYMBOL(generic_pipe_buf_get);
+
+--- a/fs/splice.c
++++ b/fs/splice.c
+@@ -1585,7 +1585,11 @@ retry:
+ * Get a reference to this pipe buffer,
+ * so we can copy the contents over.
+ */
+- pipe_buf_get(ipipe, ibuf);
++ if (!pipe_buf_get(ipipe, ibuf)) {
++ if (ret == 0)
++ ret = -EFAULT;
++ break;
++ }
+ *obuf = *ibuf;
+
+ /*
+@@ -1659,7 +1663,11 @@ static int link_pipe(struct pipe_inode_i
+ * Get a reference to this pipe buffer,
+ * so we can copy the contents over.
+ */
+- pipe_buf_get(ipipe, ibuf);
++ if (!pipe_buf_get(ipipe, ibuf)) {
++ if (ret == 0)
++ ret = -EFAULT;
++ break;
++ }
+
+ obuf = opipe->bufs + nbuf;
+ *obuf = *ibuf;
+--- a/include/linux/pipe_fs_i.h
++++ b/include/linux/pipe_fs_i.h
+@@ -107,18 +107,20 @@ struct pipe_buf_operations {
+ /*
+ * Get a reference to the pipe buffer.
+ */
+- void (*get)(struct pipe_inode_info *, struct pipe_buffer *);
++ bool (*get)(struct pipe_inode_info *, struct pipe_buffer *);
+ };
+
+ /**
+ * pipe_buf_get - get a reference to a pipe_buffer
+ * @pipe: the pipe that the buffer belongs to
+ * @buf: the buffer to get a reference to
++ *
++ * Return: %true if the reference was successfully obtained.
+ */
+-static inline void pipe_buf_get(struct pipe_inode_info *pipe,
++static inline __must_check bool pipe_buf_get(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf)
+ {
+- buf->ops->get(pipe, buf);
++ return buf->ops->get(pipe, buf);
+ }
+
+ /**
+@@ -178,7 +180,7 @@ struct pipe_inode_info *alloc_pipe_info(
+ void free_pipe_info(struct pipe_inode_info *);
+
+ /* Generic pipe buffer ops functions */
+-void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *);
++bool generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *);
+ int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *);
+ int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *);
+ void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *);
+--- a/kernel/trace/trace.c
++++ b/kernel/trace/trace.c
+@@ -6145,12 +6145,16 @@ static void buffer_pipe_buf_release(stru
+ buf->private = 0;
+ }
+
+-static void buffer_pipe_buf_get(struct pipe_inode_info *pipe,
++static bool buffer_pipe_buf_get(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf)
+ {
+ struct buffer_ref *ref = (struct buffer_ref *)buf->private;
+
++ if (ref->ref > INT_MAX/2)
++ return false;
++
+ ref->ref++;
++ return true;
+ }
+
+ /* Pipe buffer operations for a buffer. */
--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Punit Agrawal <punit.agrawal@arm.com>
+Date: Thu, 6 Jul 2017 15:39:39 -0700
+Subject: mm, gup: ensure real head page is ref-counted when using hugepages
+
+From: Punit Agrawal <punit.agrawal@arm.com>
+
+commit d63206ee32b6e64b0e12d46e5d6004afd9913713 upstream.
+
+When speculatively taking references to a hugepage using
+page_cache_add_speculative() in gup_huge_pmd(), it is assumed that the
+page returned by pmd_page() is the head page. Although normally true,
+this assumption doesn't hold when the hugepage comprises of successive
+page table entries such as when using contiguous bit on arm64 at PTE or
+PMD levels.
+
+This can be addressed by ensuring that the page passed to
+page_cache_add_speculative() is the real head or by de-referencing the
+head page within the function.
+
+We take the first approach to keep the usage pattern aligned with
+page_cache_get_speculative() where users already pass the appropriate
+page, i.e., the de-referenced head.
+
+Apply the same logic to fix gup_huge_[pud|pgd]() as well.
+
+[punit.agrawal@arm.com: fix arm64 ltp failure]
+ Link: http://lkml.kernel.org/r/20170619170145.25577-5-punit.agrawal@arm.com
+Link: http://lkml.kernel.org/r/20170522133604.11392-3-punit.agrawal@arm.com
+Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
+Acked-by: Steve Capper <steve.capper@arm.com>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com>
+Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Will Deacon <will.deacon@arm.com>
+Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Hillf Danton <hillf.zj@alibaba-inc.com>
+Cc: Mike Kravetz <mike.kravetz@oracle.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/gup.c | 12 ++++++------
+ 1 file changed, 6 insertions(+), 6 deletions(-)
+
+--- a/mm/gup.c
++++ b/mm/gup.c
+@@ -1313,8 +1313,7 @@ static int gup_huge_pmd(pmd_t orig, pmd_
+ return 0;
+
+ refs = 0;
+- head = pmd_page(orig);
+- page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
++ page = pmd_page(orig) + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+ do {
+ pages[*nr] = page;
+ (*nr)++;
+@@ -1322,6 +1321,7 @@ static int gup_huge_pmd(pmd_t orig, pmd_
+ refs++;
+ } while (addr += PAGE_SIZE, addr != end);
+
++ head = compound_head(pmd_page(orig));
+ if (!page_cache_add_speculative(head, refs)) {
+ *nr -= refs;
+ return 0;
+@@ -1347,8 +1347,7 @@ static int gup_huge_pud(pud_t orig, pud_
+ return 0;
+
+ refs = 0;
+- head = pud_page(orig);
+- page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
++ page = pud_page(orig) + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
+ do {
+ pages[*nr] = page;
+ (*nr)++;
+@@ -1356,6 +1355,7 @@ static int gup_huge_pud(pud_t orig, pud_
+ refs++;
+ } while (addr += PAGE_SIZE, addr != end);
+
++ head = compound_head(pud_page(orig));
+ if (!page_cache_add_speculative(head, refs)) {
+ *nr -= refs;
+ return 0;
+@@ -1382,8 +1382,7 @@ static int gup_huge_pgd(pgd_t orig, pgd_
+ return 0;
+
+ refs = 0;
+- head = pgd_page(orig);
+- page = head + ((addr & ~PGDIR_MASK) >> PAGE_SHIFT);
++ page = pgd_page(orig) + ((addr & ~PGDIR_MASK) >> PAGE_SHIFT);
+ do {
+ pages[*nr] = page;
+ (*nr)++;
+@@ -1391,6 +1390,7 @@ static int gup_huge_pgd(pgd_t orig, pgd_
+ refs++;
+ } while (addr += PAGE_SIZE, addr != end);
+
++ head = compound_head(pgd_page(orig));
+ if (!page_cache_add_speculative(head, refs)) {
+ *nr -= refs;
+ return 0;
--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Will Deacon <will.deacon@arm.com>
+Date: Thu, 6 Jul 2017 15:39:36 -0700
+Subject: mm, gup: remove broken VM_BUG_ON_PAGE compound check for hugepages
+
+From: Will Deacon <will.deacon@arm.com>
+
+commit a3e328556d41bb61c55f9dfcc62d6a826ea97b85 upstream.
+
+When operating on hugepages with DEBUG_VM enabled, the GUP code checks
+the compound head for each tail page prior to calling
+page_cache_add_speculative. This is broken, because on the fast-GUP
+path (where we don't hold any page table locks) we can be racing with a
+concurrent invocation of split_huge_page_to_list.
+
+split_huge_page_to_list deals with this race by using page_ref_freeze to
+freeze the page and force concurrent GUPs to fail whilst the component
+pages are modified. This modification includes clearing the
+compound_head field for the tail pages, so checking this prior to a
+successful call to page_cache_add_speculative can lead to false
+positives: In fact, page_cache_add_speculative *already* has this check
+once the page refcount has been successfully updated, so we can simply
+remove the broken calls to VM_BUG_ON_PAGE.
+
+Link: http://lkml.kernel.org/r/20170522133604.11392-2-punit.agrawal@arm.com
+Signed-off-by: Will Deacon <will.deacon@arm.com>
+Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
+Acked-by: Steve Capper <steve.capper@arm.com>
+Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
+Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
+Cc: Catalin Marinas <catalin.marinas@arm.com>
+Cc: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com>
+Cc: Mark Rutland <mark.rutland@arm.com>
+Cc: Hillf Danton <hillf.zj@alibaba-inc.com>
+Cc: Michal Hocko <mhocko@suse.com>
+Cc: Mike Kravetz <mike.kravetz@oracle.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/gup.c | 3 ---
+ 1 file changed, 3 deletions(-)
+
+--- a/mm/gup.c
++++ b/mm/gup.c
+@@ -1316,7 +1316,6 @@ static int gup_huge_pmd(pmd_t orig, pmd_
+ head = pmd_page(orig);
+ page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
+ do {
+- VM_BUG_ON_PAGE(compound_head(page) != head, page);
+ pages[*nr] = page;
+ (*nr)++;
+ page++;
+@@ -1351,7 +1350,6 @@ static int gup_huge_pud(pud_t orig, pud_
+ head = pud_page(orig);
+ page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
+ do {
+- VM_BUG_ON_PAGE(compound_head(page) != head, page);
+ pages[*nr] = page;
+ (*nr)++;
+ page++;
+@@ -1387,7 +1385,6 @@ static int gup_huge_pgd(pgd_t orig, pgd_
+ head = pgd_page(orig);
+ page = head + ((addr & ~PGDIR_MASK) >> PAGE_SHIFT);
+ do {
+- VM_BUG_ON_PAGE(compound_head(page) != head, page);
+ pages[*nr] = page;
+ (*nr)++;
+ page++;
--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Thu, 11 Apr 2019 10:06:20 -0700
+Subject: mm: make page ref count overflow check tighter and more explicit
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit f958d7b528b1b40c44cfda5eabe2d82760d868c3 upstream.
+
+We have a VM_BUG_ON() to check that the page reference count doesn't
+underflow (or get close to overflow) by checking the sign of the count.
+
+That's all fine, but we actually want to allow people to use a "get page
+ref unless it's already very high" helper function, and we want that one
+to use the sign of the page ref (without triggering this VM_BUG_ON).
+
+Change the VM_BUG_ON to only check for small underflows (or _very_ close
+to overflowing), and ignore overflows which have strayed into negative
+territory.
+
+Acked-by: Matthew Wilcox <willy@infradead.org>
+Cc: Jann Horn <jannh@google.com>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/mm.h | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/include/linux/mm.h
++++ b/include/linux/mm.h
+@@ -763,6 +763,10 @@ static inline bool is_zone_device_page(c
+ }
+ #endif
+
++/* 127: arbitrary random number, small enough to assemble well */
++#define page_ref_zero_or_close_to_overflow(page) \
++ ((unsigned int) page_ref_count(page) + 127u <= 127u)
++
+ static inline void get_page(struct page *page)
+ {
+ page = compound_head(page);
+@@ -770,7 +774,7 @@ static inline void get_page(struct page
+ * Getting a normal page or the head of a compound page
+ * requires to already have an elevated page->_refcount.
+ */
+- VM_BUG_ON_PAGE(page_ref_count(page) <= 0, page);
++ VM_BUG_ON_PAGE(page_ref_zero_or_close_to_overflow(page), page);
+ page_ref_inc(page);
+
+ if (unlikely(is_zone_device_page(page)))
--- /dev/null
+From foo@baz Tue 04 Jun 2019 04:44:10 PM CEST
+From: Linus Torvalds <torvalds@linux-foundation.org>
+Date: Thu, 11 Apr 2019 10:49:19 -0700
+Subject: mm: prevent get_user_pages() from overflowing page refcount
+
+From: Linus Torvalds <torvalds@linux-foundation.org>
+
+commit 8fde12ca79aff9b5ba951fce1a2641901b8d8e64 upstream.
+
+If the page refcount wraps around past zero, it will be freed while
+there are still four billion references to it. One of the possible
+avenues for an attacker to try to make this happen is by doing direct IO
+on a page multiple times. This patch makes get_user_pages() refuse to
+take a new page reference if there are already more than two billion
+references to the page.
+
+Reported-by: Jann Horn <jannh@google.com>
+Acked-by: Matthew Wilcox <willy@infradead.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+[bwh: Backported to 4.9:
+ - Add the "err" variable in follow_hugetlb_page()
+ - Adjust context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ mm/gup.c | 45 ++++++++++++++++++++++++++++++++++-----------
+ mm/hugetlb.c | 16 +++++++++++++++-
+ 2 files changed, 49 insertions(+), 12 deletions(-)
+
+--- a/mm/gup.c
++++ b/mm/gup.c
+@@ -153,7 +153,10 @@ retry:
+ }
+
+ if (flags & FOLL_GET) {
+- get_page(page);
++ if (unlikely(!try_get_page(page))) {
++ page = ERR_PTR(-ENOMEM);
++ goto out;
++ }
+
+ /* drop the pgmap reference now that we hold the page */
+ if (pgmap) {
+@@ -292,7 +295,10 @@ struct page *follow_page_mask(struct vm_
+ 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);
+@@ -348,7 +354,10 @@ static int get_gate_page(struct mm_struc
+ goto unmap;
+ *page = pte_page(*pte);
+ }
+- get_page(*page);
++ if (unlikely(!try_get_page(*page))) {
++ ret = -ENOMEM;
++ goto unmap;
++ }
+ out:
+ ret = 0;
+ unmap:
+@@ -1231,6 +1240,20 @@ struct page *get_dump_page(unsigned long
+ */
+ #ifdef CONFIG_HAVE_GENERIC_RCU_GUP
+
++/*
++ * Return the compund head page with ref appropriately incremented,
++ * or NULL if that failed.
++ */
++static inline struct page *try_get_compound_head(struct page *page, int refs)
++{
++ struct page *head = compound_head(page);
++ if (WARN_ON_ONCE(page_ref_count(head) < 0))
++ return NULL;
++ if (unlikely(!page_cache_add_speculative(head, refs)))
++ return NULL;
++ return head;
++}
++
+ #ifdef __HAVE_ARCH_PTE_SPECIAL
+ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end,
+ int write, struct page **pages, int *nr)
+@@ -1263,9 +1286,9 @@ static int gup_pte_range(pmd_t pmd, unsi
+
+ VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
+ page = pte_page(pte);
+- head = compound_head(page);
+
+- if (!page_cache_get_speculative(head))
++ head = try_get_compound_head(page, 1);
++ if (!head)
+ goto pte_unmap;
+
+ if (unlikely(pte_val(pte) != pte_val(*ptep))) {
+@@ -1321,8 +1344,8 @@ static int gup_huge_pmd(pmd_t orig, pmd_
+ refs++;
+ } while (addr += PAGE_SIZE, addr != end);
+
+- head = compound_head(pmd_page(orig));
+- if (!page_cache_add_speculative(head, refs)) {
++ head = try_get_compound_head(pmd_page(orig), refs);
++ if (!head) {
+ *nr -= refs;
+ return 0;
+ }
+@@ -1355,8 +1378,8 @@ static int gup_huge_pud(pud_t orig, pud_
+ refs++;
+ } while (addr += PAGE_SIZE, addr != end);
+
+- head = compound_head(pud_page(orig));
+- if (!page_cache_add_speculative(head, refs)) {
++ head = try_get_compound_head(pud_page(orig), refs);
++ if (!head) {
+ *nr -= refs;
+ return 0;
+ }
+@@ -1390,8 +1413,8 @@ static int gup_huge_pgd(pgd_t orig, pgd_
+ refs++;
+ } while (addr += PAGE_SIZE, addr != end);
+
+- head = compound_head(pgd_page(orig));
+- if (!page_cache_add_speculative(head, refs)) {
++ head = try_get_compound_head(pgd_page(orig), refs);
++ if (!head) {
+ *nr -= refs;
+ return 0;
+ }
+--- a/mm/hugetlb.c
++++ b/mm/hugetlb.c
+@@ -3984,6 +3984,7 @@ long follow_hugetlb_page(struct mm_struc
+ unsigned long vaddr = *position;
+ unsigned long remainder = *nr_pages;
+ struct hstate *h = hstate_vma(vma);
++ int err = -EFAULT;
+
+ while (vaddr < vma->vm_end && remainder) {
+ pte_t *pte;
+@@ -4055,6 +4056,19 @@ long follow_hugetlb_page(struct mm_struc
+
+ pfn_offset = (vaddr & ~huge_page_mask(h)) >> PAGE_SHIFT;
+ page = pte_page(huge_ptep_get(pte));
++
++ /*
++ * Instead of doing 'try_get_page()' below in the same_page
++ * loop, just check the count once here.
++ */
++ if (unlikely(page_count(page) <= 0)) {
++ if (pages) {
++ spin_unlock(ptl);
++ remainder = 0;
++ err = -ENOMEM;
++ break;
++ }
++ }
+ same_page:
+ if (pages) {
+ pages[i] = mem_map_offset(page, pfn_offset);
+@@ -4081,7 +4095,7 @@ same_page:
+ *nr_pages = remainder;
+ *position = vaddr;
+
+- return i ? i : -EFAULT;
++ return i ? i : err;
+ }
+
+ #ifndef __HAVE_ARCH_FLUSH_HUGETLB_TLB_RANGE
gcc-plugins-fix-build-failures-under-darwin-host.patch
drm-vmwgfx-don-t-send-drm-sysfs-hotplug-events-on-initial-master-set.patch
drm-rockchip-shutdown-drm-subsystem-on-shutdown.patch
+brcmfmac-add-length-checks-in-scheduled-scan-result-handler.patch
+brcmfmac-assure-ssid-length-from-firmware-is-limited.patch
+brcmfmac-add-subtype-check-for-event-handling-in-data-path.patch
+binder-replace-p-with-pk-for-stable.patch
+binder-replace-p-with-pk.patch
+fs-prevent-page-refcount-overflow-in-pipe_buf_get.patch
+mm-gup-remove-broken-vm_bug_on_page-compound-check-for-hugepages.patch
+mm-gup-ensure-real-head-page-is-ref-counted-when-using-hugepages.patch
+mm-prevent-get_user_pages-from-overflowing-page-refcount.patch
+mm-make-page-ref-count-overflow-check-tighter-and-more-explicit.patch
+coredump-fix-race-condition-between-mmget_not_zero-get_task_mm-and-core-dumping.patch