]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 4 Jun 2019 14:46:52 +0000 (16:46 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 4 Jun 2019 14:46:52 +0000 (16:46 +0200)
added patches:
binder-replace-p-with-pk-for-stable.patch
binder-replace-p-with-pk.patch
bnx2x-disable-gso-where-gso_size-is-too-big-for-hardware.patch
brcmfmac-add-length-checks-in-scheduled-scan-result-handler.patch
brcmfmac-add-length-checks-on-firmware-events.patch
brcmfmac-add-subtype-check-for-event-handling-in-data-path.patch
brcmfmac-fix-incorrect-event-channel-deduction.patch
brcmfmac-revise-handling-events-in-receive-path.patch
brcmfmac-screening-firmware-event-packet.patch
coredump-fix-race-condition-between-mmget_not_zero-get_task_mm-and-core-dumping.patch
net-create-skb_gso_validate_mac_len.patch
userfaultfd-don-t-pin-the-user-memory-in-userfaultfd_file_create.patch

13 files changed:
queue-4.4/binder-replace-p-with-pk-for-stable.patch [new file with mode: 0644]
queue-4.4/binder-replace-p-with-pk.patch [new file with mode: 0644]
queue-4.4/bnx2x-disable-gso-where-gso_size-is-too-big-for-hardware.patch [new file with mode: 0644]
queue-4.4/brcmfmac-add-length-checks-in-scheduled-scan-result-handler.patch [new file with mode: 0644]
queue-4.4/brcmfmac-add-length-checks-on-firmware-events.patch [new file with mode: 0644]
queue-4.4/brcmfmac-add-subtype-check-for-event-handling-in-data-path.patch [new file with mode: 0644]
queue-4.4/brcmfmac-fix-incorrect-event-channel-deduction.patch [new file with mode: 0644]
queue-4.4/brcmfmac-revise-handling-events-in-receive-path.patch [new file with mode: 0644]
queue-4.4/brcmfmac-screening-firmware-event-packet.patch [new file with mode: 0644]
queue-4.4/coredump-fix-race-condition-between-mmget_not_zero-get_task_mm-and-core-dumping.patch [new file with mode: 0644]
queue-4.4/net-create-skb_gso_validate_mac_len.patch [new file with mode: 0644]
queue-4.4/series
queue-4.4/userfaultfd-don-t-pin-the-user-memory-in-userfaultfd_file_create.patch [new file with mode: 0644]

diff --git a/queue-4.4/binder-replace-p-with-pk-for-stable.patch b/queue-4.4/binder-replace-p-with-pk-for-stable.patch
new file mode 100644 (file)
index 0000000..ca3e8f7
--- /dev/null
@@ -0,0 +1,146 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 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
+@@ -477,7 +477,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) {
+@@ -555,7 +555,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)
+@@ -595,7 +595,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;
+               }
+@@ -604,7 +604,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;
+               }
+@@ -708,7 +708,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 =
+@@ -738,7 +738,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;
+@@ -778,7 +778,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);
+       }
+@@ -791,14 +791,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 ?
+@@ -819,7 +819,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);
+@@ -2912,7 +2912,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;
+               }
+       }
+@@ -3170,7 +3170,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]);
+@@ -3271,7 +3271,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");
+@@ -3374,7 +3374,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);
+ }
diff --git a/queue-4.4/binder-replace-p-with-pk.patch b/queue-4.4/binder-replace-p-with-pk.patch
new file mode 100644 (file)
index 0000000..bf0a163
--- /dev/null
@@ -0,0 +1,59 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 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.4: 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
+@@ -1249,7 +1249,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);
+@@ -2105,7 +2105,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) {
+@@ -3249,7 +3249,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,
+@@ -3263,7 +3263,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);
+ }
diff --git a/queue-4.4/bnx2x-disable-gso-where-gso_size-is-too-big-for-hardware.patch b/queue-4.4/bnx2x-disable-gso-where-gso_size-is-too-big-for-hardware.patch
new file mode 100644 (file)
index 0000000..61aea25
--- /dev/null
@@ -0,0 +1,58 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 PM CEST
+From: Daniel Axtens <dja@axtens.net>
+Date: Wed, 31 Jan 2018 14:15:34 +1100
+Subject: bnx2x: disable GSO where gso_size is too big for hardware
+
+From: Daniel Axtens <dja@axtens.net>
+
+commit 8914a595110a6eca69a5e275b323f5d09e18f4f9 upstream.
+
+If a bnx2x card is passed a GSO packet with a gso_size larger than
+~9700 bytes, it will cause a firmware error that will bring the card
+down:
+
+bnx2x: [bnx2x_attn_int_deasserted3:4323(enP24p1s0f0)]MC assert!
+bnx2x: [bnx2x_mc_assert:720(enP24p1s0f0)]XSTORM_ASSERT_LIST_INDEX 0x2
+bnx2x: [bnx2x_mc_assert:736(enP24p1s0f0)]XSTORM_ASSERT_INDEX 0x0 = 0x00000000 0x25e43e47 0x00463e01 0x00010052
+bnx2x: [bnx2x_mc_assert:750(enP24p1s0f0)]Chip Revision: everest3, FW Version: 7_13_1
+... (dump of values continues) ...
+
+Detect when the mac length of a GSO packet is greater than the maximum
+packet size (9700 bytes) and disable GSO.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c |   18 ++++++++++++++++++
+ 1 file changed, 18 insertions(+)
+
+--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
++++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+@@ -12824,6 +12824,24 @@ static netdev_features_t bnx2x_features_
+                                             struct net_device *dev,
+                                             netdev_features_t features)
+ {
++      /*
++       * A skb with gso_size + header length > 9700 will cause a
++       * firmware panic. Drop GSO support.
++       *
++       * Eventually the upper layer should not pass these packets down.
++       *
++       * For speed, if the gso_size is <= 9000, assume there will
++       * not be 700 bytes of headers and pass it through. Only do a
++       * full (slow) validation if the gso_size is > 9000.
++       *
++       * (Due to the way SKB_BY_FRAGS works this will also do a full
++       * validation in that case.)
++       */
++      if (unlikely(skb_is_gso(skb) &&
++                   (skb_shinfo(skb)->gso_size > 9000) &&
++                   !skb_gso_validate_mac_len(skb, 9700)))
++              features &= ~NETIF_F_GSO_MASK;
++
+       features = vlan_features_check(skb, features);
+       return vxlan_features_check(skb, features);
+ }
diff --git a/queue-4.4/brcmfmac-add-length-checks-in-scheduled-scan-result-handler.patch b/queue-4.4/brcmfmac-add-length-checks-in-scheduled-scan-result-handler.patch
new file mode 100644 (file)
index 0000000..c061bfc
--- /dev/null
@@ -0,0 +1,72 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 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.4:
+ - Move the assignment to "data" along with the assignment to "netinfo_start"
+   that depends on it
+ - Adjust filename, context, indentation]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c |   14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -3328,6 +3328,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");
+@@ -3354,6 +3355,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);
+@@ -3363,9 +3372,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) {
+@@ -3375,6 +3381,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);
diff --git a/queue-4.4/brcmfmac-add-length-checks-on-firmware-events.patch b/queue-4.4/brcmfmac-add-length-checks-on-firmware-events.patch
new file mode 100644 (file)
index 0000000..ebc84e1
--- /dev/null
@@ -0,0 +1,286 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 PM CEST
+From: Hante Meuleman <meuleman@broadcom.com>
+Date: Wed, 17 Feb 2016 11:26:54 +0100
+Subject: brcmfmac: Add length checks on firmware events
+
+From: Hante Meuleman <meuleman@broadcom.com>
+
+commit 0aedbcaf6f182690790d98d90d5fe1e64c846c34 upstream.
+
+Add additional length checks on firmware events to create more
+robust code.
+
+Reviewed-by: Arend Van Spriel <arend@broadcom.com>
+Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
+Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
+Reviewed-by: Lei Zhang <leizh@broadcom.com>
+Signed-off-by: Hante Meuleman <meuleman@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+[bwh: Backported to 4.4:
+ - Drop changes to brcmf_wowl_nd_results()
+ - Adjust filenames]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c |    5 +
+ drivers/net/wireless/brcm80211/brcmfmac/fweh.c     |   57 +++--------------
+ drivers/net/wireless/brcm80211/brcmfmac/fweh.h     |   68 ++++++++++++++++-----
+ drivers/net/wireless/brcm80211/brcmfmac/p2p.c      |   10 +++
+ 4 files changed, 82 insertions(+), 58 deletions(-)
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+@@ -3331,6 +3331,11 @@ brcmf_notify_sched_scan_results(struct b
+       brcmf_dbg(SCAN, "Enter\n");
++      if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
++              brcmf_dbg(SCAN, "Event data to small. Ignore\n");
++              return 0;
++      }
++
+       if (e->event_code == BRCMF_E_PFN_NET_LOST) {
+               brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
+               return 0;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
+@@ -26,50 +26,6 @@
+ #include "fwil.h"
+ /**
+- * struct brcm_ethhdr - broadcom specific ether header.
+- *
+- * @subtype: subtype for this packet.
+- * @length: TODO: length of appended data.
+- * @version: version indication.
+- * @oui: OUI of this packet.
+- * @usr_subtype: subtype for this OUI.
+- */
+-struct brcm_ethhdr {
+-      __be16 subtype;
+-      __be16 length;
+-      u8 version;
+-      u8 oui[3];
+-      __be16 usr_subtype;
+-} __packed;
+-
+-struct brcmf_event_msg_be {
+-      __be16 version;
+-      __be16 flags;
+-      __be32 event_type;
+-      __be32 status;
+-      __be32 reason;
+-      __be32 auth_type;
+-      __be32 datalen;
+-      u8 addr[ETH_ALEN];
+-      char ifname[IFNAMSIZ];
+-      u8 ifidx;
+-      u8 bsscfgidx;
+-} __packed;
+-
+-/**
+- * struct brcmf_event - contents of broadcom event packet.
+- *
+- * @eth: standard ether header.
+- * @hdr: broadcom specific ether header.
+- * @msg: common part of the actual event message.
+- */
+-struct brcmf_event {
+-      struct ethhdr eth;
+-      struct brcm_ethhdr hdr;
+-      struct brcmf_event_msg_be msg;
+-} __packed;
+-
+-/**
+  * struct brcmf_fweh_queue_item - event item on event queue.
+  *
+  * @q: list element for queuing.
+@@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item {
+       u8 ifidx;
+       u8 ifaddr[ETH_ALEN];
+       struct brcmf_event_msg_be emsg;
++      u32 datalen;
+       u8 data[0];
+ };
+@@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(stru
+               brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
+                                  min_t(u32, emsg.datalen, 64),
+                                  "event payload, len=%d\n", emsg.datalen);
++              if (emsg.datalen > event->datalen) {
++                      brcmf_err("event invalid length header=%d, msg=%d\n",
++                                event->datalen, emsg.datalen);
++                      goto event_free;
++              }
+               /* special handling of interface event */
+               if (event->code == BRCMF_E_IF) {
+@@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct br
+  * dispatch the event to a registered handler (using worker).
+  */
+ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
+-                            struct brcmf_event *event_packet)
++                            struct brcmf_event *event_packet,
++                            u32 packet_len)
+ {
+       enum brcmf_fweh_event_code code;
+       struct brcmf_fweh_info *fweh = &drvr->fweh;
+@@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brc
+       if (code != BRCMF_E_IF && !fweh->evt_handler[code])
+               return;
++      if (datalen > BRCMF_DCMD_MAXLEN)
++              return;
++
+       if (in_interrupt())
+               alloc_flag = GFP_ATOMIC;
+@@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brc
+       /* use memcpy to get aligned event message */
+       memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
+       memcpy(event->data, data, datalen);
++      event->datalen = datalen;
+       memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
+       brcmf_fweh_queue_event(fweh, event);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
+@@ -27,7 +27,6 @@
+ struct brcmf_pub;
+ struct brcmf_if;
+ struct brcmf_cfg80211_info;
+-struct brcmf_event;
+ /* list of firmware events */
+ #define BRCMF_FWEH_EVENT_ENUM_DEFLIST \
+@@ -180,13 +179,55 @@ enum brcmf_fweh_event_code {
+ /**
+  * definitions for event packet validation.
+  */
+-#define BRCMF_EVENT_OUI_OFFSET                19
+-#define BRCM_OUI                      "\x00\x10\x18"
+-#define DOT11_OUI_LEN                 3
+-#define BCMILCP_BCM_SUBTYPE_EVENT     1
++#define BRCM_OUI                              "\x00\x10\x18"
++#define BCMILCP_BCM_SUBTYPE_EVENT             1
+ /**
++ * struct brcm_ethhdr - broadcom specific ether header.
++ *
++ * @subtype: subtype for this packet.
++ * @length: TODO: length of appended data.
++ * @version: version indication.
++ * @oui: OUI of this packet.
++ * @usr_subtype: subtype for this OUI.
++ */
++struct brcm_ethhdr {
++      __be16 subtype;
++      __be16 length;
++      u8 version;
++      u8 oui[3];
++      __be16 usr_subtype;
++} __packed;
++
++struct brcmf_event_msg_be {
++      __be16 version;
++      __be16 flags;
++      __be32 event_type;
++      __be32 status;
++      __be32 reason;
++      __be32 auth_type;
++      __be32 datalen;
++      u8 addr[ETH_ALEN];
++      char ifname[IFNAMSIZ];
++      u8 ifidx;
++      u8 bsscfgidx;
++} __packed;
++
++/**
++ * struct brcmf_event - contents of broadcom event packet.
++ *
++ * @eth: standard ether header.
++ * @hdr: broadcom specific ether header.
++ * @msg: common part of the actual event message.
++ */
++struct brcmf_event {
++      struct ethhdr eth;
++      struct brcm_ethhdr hdr;
++      struct brcmf_event_msg_be msg;
++} __packed;
++
++/**
+  * struct brcmf_event_msg - firmware event message.
+  *
+  * @version: version information.
+@@ -256,34 +297,35 @@ void brcmf_fweh_unregister(struct brcmf_
+                          enum brcmf_fweh_event_code code);
+ int brcmf_fweh_activate_events(struct brcmf_if *ifp);
+ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
+-                            struct brcmf_event *event_packet);
++                            struct brcmf_event *event_packet,
++                            u32 packet_len);
+ 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 brcmf_event *event_packet;
+-      u8 *data;
+       u16 usr_stype;
+       /* only process events when protocol matches */
+       if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
+               return;
++      if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
++              return;
++
+       /* check for BRCM oui match */
+       event_packet = (struct brcmf_event *)skb_mac_header(skb);
+-      data = (u8 *)event_packet;
+-      data += BRCMF_EVENT_OUI_OFFSET;
+-      if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
++      if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
++                 sizeof(event_packet->hdr.oui)))
+               return;
+       /* final match on usr_subtype */
+-      data += DOT11_OUI_LEN;
+-      usr_stype = get_unaligned_be16(data);
++      usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype);
+       if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
+               return;
+-      brcmf_fweh_process_event(drvr, event_packet);
++      brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN);
+ }
+ #endif /* FWEH_H_ */
+--- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c
+@@ -1365,6 +1365,11 @@ int brcmf_p2p_notify_action_frame_rx(str
+       u16 mgmt_type;
+       u8 action;
++      if (e->datalen < sizeof(*rxframe)) {
++              brcmf_dbg(SCAN, "Event data to small. Ignore\n");
++              return 0;
++      }
++
+       ch.chspec = be16_to_cpu(rxframe->chanspec);
+       cfg->d11inf.decchspec(&ch);
+       /* Check if wpa_supplicant has registered for this frame */
+@@ -1862,6 +1867,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probere
+       brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
+                 e->reason);
++      if (e->datalen < sizeof(*rxframe)) {
++              brcmf_dbg(SCAN, "Event data to small. Ignore\n");
++              return 0;
++      }
++
+       ch.chspec = be16_to_cpu(rxframe->chanspec);
+       cfg->d11inf.decchspec(&ch);
diff --git a/queue-4.4/brcmfmac-add-subtype-check-for-event-handling-in-data-path.patch b/queue-4.4/brcmfmac-add-subtype-check-for-event-handling-in-data-path.patch
new file mode 100644 (file)
index 0000000..d51292b
--- /dev/null
@@ -0,0 +1,103 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 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>
+[bwh: Backported to 4.4: adjust filenames]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/brcm80211/brcmfmac/core.c   |    5 +++--
+ drivers/net/wireless/brcm80211/brcmfmac/fweh.h   |   16 ++++++++++++----
+ drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c |    2 +-
+ 3 files changed, 16 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -548,7 +548,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);
+       }
+@@ -575,7 +576,7 @@ void brcmf_rx_event(struct device *dev,
+       skb->protocol = eth_type_trans(skb, ifp->ndev);
+-      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/brcm80211/brcmfmac/fweh.h
++++ b/drivers/net/wireless/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/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -1112,7 +1112,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);
diff --git a/queue-4.4/brcmfmac-fix-incorrect-event-channel-deduction.patch b/queue-4.4/brcmfmac-fix-incorrect-event-channel-deduction.patch
new file mode 100644 (file)
index 0000000..ca63e6c
--- /dev/null
@@ -0,0 +1,40 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 PM CEST
+From: Gavin Li <git@thegavinli.com>
+Date: Tue, 17 Jan 2017 15:24:05 -0800
+Subject: brcmfmac: fix incorrect event channel deduction
+
+From: Gavin Li <git@thegavinli.com>
+
+commit 8e290cecdd0178f3d4cf7d463c51dc7e462843b4 upstream.
+
+brcmf_sdio_fromevntchan() was being called on the the data frame
+rather than the software header, causing some frames to be
+mischaracterized as on the event channel rather than the data channel.
+
+This fixes a major performance regression (due to dropped packets). With
+this patch the download speed jumped from 1Mbit/s back up to 40MBit/s due
+to the sheer amount of packets being incorrectly processed.
+
+Fixes: c56caa9db8ab ("brcmfmac: screening firmware event packet")
+Signed-off-by: Gavin Li <git@thegavinli.com>
+Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
+[kvalo@codeaurora.org: improve commit logs based on email discussion]
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+[bwh: Backported to 4.4: adjust filename]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/brcm80211/brcmfmac/sdio.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+@@ -1765,7 +1765,7 @@ static u8 brcmf_sdio_rxglom(struct brcmf
+                                          pfirst->len, pfirst->next,
+                                          pfirst->prev);
+                       skb_unlink(pfirst, &bus->glom);
+-                      if (brcmf_sdio_fromevntchan(pfirst->data))
++                      if (brcmf_sdio_fromevntchan(&dptr[SDPCM_HWHDR_LEN]))
+                               brcmf_rx_event(bus->sdiodev->dev, pfirst);
+                       else
+                               brcmf_rx_frame(bus->sdiodev->dev, pfirst,
diff --git a/queue-4.4/brcmfmac-revise-handling-events-in-receive-path.patch b/queue-4.4/brcmfmac-revise-handling-events-in-receive-path.patch
new file mode 100644 (file)
index 0000000..b39658f
--- /dev/null
@@ -0,0 +1,149 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 PM CEST
+From: Arend van Spriel <arend@broadcom.com>
+Date: Mon, 11 Apr 2016 11:35:27 +0200
+Subject: brcmfmac: revise handling events in receive path
+
+From: Arend van Spriel <arend@broadcom.com>
+
+commit 9c349892ccc90c6de2baaa69cc78449f58082273 upstream.
+
+Move event handling out of brcmf_netif_rx() avoiding the need
+to pass a flag. This flag is only ever true for USB hosts as
+other interface use separate brcmf_rx_event() function.
+
+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@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+[bwh: Backported to 4.4 as dependency of commit a4176ec356c7
+ "brcmfmac: add subtype check for event handling in data path"
+ - Adjust filenames, context]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/brcm80211/brcmfmac/bus.h    |    2 -
+ drivers/net/wireless/brcm80211/brcmfmac/core.c   |   32 +++++++++++------------
+ drivers/net/wireless/brcm80211/brcmfmac/core.h   |    3 --
+ drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c |    2 -
+ 4 files changed, 19 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
+@@ -214,7 +214,7 @@ bool brcmf_c_prec_enq(struct device *dev
+                     int prec);
+ /* Receive frame for delivery to OS.  Callee disposes of rxp. */
+-void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_evnt);
++void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_event);
+ /* Receive async event packet from firmware. Callee disposes of rxp. */
+ void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -301,18 +301,11 @@ void brcmf_txflowblock(struct device *de
+       brcmf_fws_bus_blocked(drvr, state);
+ }
+-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
+-                  bool handle_event)
++void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
+ {
+-      skb->protocol = eth_type_trans(skb, ifp->ndev);
+-
+       if (skb->pkt_type == PACKET_MULTICAST)
+               ifp->stats.multicast++;
+-      /* Process special event packets */
+-      if (handle_event)
+-              brcmf_fweh_process_skb(ifp->drvr, skb);
+-
+       if (!(ifp->ndev->flags & IFF_UP)) {
+               brcmu_pkt_buf_free_skb(skb);
+               return;
+@@ -372,7 +365,7 @@ static void brcmf_rxreorder_process_info
+       /* validate flags and flow id */
+       if (flags == 0xFF) {
+               brcmf_err("invalid flags...so ignore this packet\n");
+-              brcmf_netif_rx(ifp, pkt, false);
++              brcmf_netif_rx(ifp, pkt);
+               return;
+       }
+@@ -384,7 +377,7 @@ static void brcmf_rxreorder_process_info
+               if (rfi == NULL) {
+                       brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
+                                 flow_id);
+-                      brcmf_netif_rx(ifp, pkt, false);
++                      brcmf_netif_rx(ifp, pkt);
+                       return;
+               }
+@@ -409,7 +402,7 @@ static void brcmf_rxreorder_process_info
+               rfi = kzalloc(buf_size, GFP_ATOMIC);
+               if (rfi == NULL) {
+                       brcmf_err("failed to alloc buffer\n");
+-                      brcmf_netif_rx(ifp, pkt, false);
++                      brcmf_netif_rx(ifp, pkt);
+                       return;
+               }
+@@ -523,11 +516,11 @@ static void brcmf_rxreorder_process_info
+ netif_rx:
+       skb_queue_walk_safe(&reorder_list, pkt, pnext) {
+               __skb_unlink(pkt, &reorder_list);
+-              brcmf_netif_rx(ifp, pkt, false);
++              brcmf_netif_rx(ifp, pkt);
+       }
+ }
+-void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt)
++void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event)
+ {
+       struct brcmf_if *ifp;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+@@ -547,11 +540,18 @@ void brcmf_rx_frame(struct device *dev,
+               return;
+       }
++      skb->protocol = eth_type_trans(skb, ifp->ndev);
++
+       rd = (struct brcmf_skb_reorder_data *)skb->cb;
+-      if (rd->reorder)
++      if (rd->reorder) {
+               brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
+-      else
+-              brcmf_netif_rx(ifp, skb, handle_evnt);
++      } else {
++              /* Process special event packets */
++              if (handle_event)
++                      brcmf_fweh_process_skb(ifp->drvr, skb);
++
++              brcmf_netif_rx(ifp, skb);
++      }
+ }
+ void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
+@@ -215,8 +215,7 @@ int brcmf_get_next_free_bsscfgidx(struct
+ void brcmf_txflowblock_if(struct brcmf_if *ifp,
+                         enum brcmf_netif_stop_reason reason, bool state);
+ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
+-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
+-                  bool handle_event);
++void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
+ void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
+ #endif /* BRCMFMAC_CORE_H */
+--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -1155,7 +1155,7 @@ brcmf_msgbuf_process_rx_complete(struct
+               brcmu_pkt_buf_free_skb(skb);
+               return;
+       }
+-      brcmf_netif_rx(ifp, skb, false);
++      brcmf_netif_rx(ifp, skb);
+ }
diff --git a/queue-4.4/brcmfmac-screening-firmware-event-packet.patch b/queue-4.4/brcmfmac-screening-firmware-event-packet.patch
new file mode 100644 (file)
index 0000000..6c5006d
--- /dev/null
@@ -0,0 +1,312 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 PM CEST
+From: Franky Lin <franky.lin@broadcom.com>
+Date: Mon, 11 Apr 2016 11:35:25 +0200
+Subject: brcmfmac: screening firmware event packet
+
+From: Franky Lin <franky.lin@broadcom.com>
+
+commit c56caa9db8abbbfb9e31325e0897705aa897db37 upstream.
+
+Firmware uses asynchronized events as a communication method to the
+host. The event packets are marked as ETH_P_LINK_CTL protocol type. For
+SDIO and PCIe bus, this kind of packets are delivered through virtual
+event channel not data channel. This patch adds a screening logic to
+make sure the event handler only processes the events coming from the
+correct channel.
+
+Reviewed-by: Pieter-Paul Giesberts <pieter-paul.giesberts@broadcom.com>
+Signed-off-by: Franky Lin <franky.lin@broadcom.com>
+Signed-off-by: Arend van Spriel <arend@broadcom.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+[bwh: Backported to 4.4 adjust filenames]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/net/wireless/brcm80211/brcmfmac/bus.h    |    4 +-
+ drivers/net/wireless/brcm80211/brcmfmac/core.c   |   46 ++++++++++++++++++-----
+ drivers/net/wireless/brcm80211/brcmfmac/core.h   |    3 +
+ drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c |   42 ++++++++++++---------
+ drivers/net/wireless/brcm80211/brcmfmac/sdio.c   |   32 ++++++++++++----
+ drivers/net/wireless/brcm80211/brcmfmac/usb.c    |    2 -
+ 6 files changed, 90 insertions(+), 39 deletions(-)
+
+--- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
+@@ -214,7 +214,9 @@ bool brcmf_c_prec_enq(struct device *dev
+                     int prec);
+ /* Receive frame for delivery to OS.  Callee disposes of rxp. */
+-void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
++void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_evnt);
++/* Receive async event packet from firmware. Callee disposes of rxp. */
++void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
+ /* Indication from bus module regarding presence/insertion of dongle. */
+ int brcmf_attach(struct device *dev);
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
+@@ -301,16 +301,17 @@ void brcmf_txflowblock(struct device *de
+       brcmf_fws_bus_blocked(drvr, state);
+ }
+-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
++void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
++                  bool handle_event)
+ {
+-      skb->dev = ifp->ndev;
+-      skb->protocol = eth_type_trans(skb, skb->dev);
++      skb->protocol = eth_type_trans(skb, ifp->ndev);
+       if (skb->pkt_type == PACKET_MULTICAST)
+               ifp->stats.multicast++;
+       /* Process special event packets */
+-      brcmf_fweh_process_skb(ifp->drvr, skb);
++      if (handle_event)
++              brcmf_fweh_process_skb(ifp->drvr, skb);
+       if (!(ifp->ndev->flags & IFF_UP)) {
+               brcmu_pkt_buf_free_skb(skb);
+@@ -371,7 +372,7 @@ static void brcmf_rxreorder_process_info
+       /* validate flags and flow id */
+       if (flags == 0xFF) {
+               brcmf_err("invalid flags...so ignore this packet\n");
+-              brcmf_netif_rx(ifp, pkt);
++              brcmf_netif_rx(ifp, pkt, false);
+               return;
+       }
+@@ -383,7 +384,7 @@ static void brcmf_rxreorder_process_info
+               if (rfi == NULL) {
+                       brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
+                                 flow_id);
+-                      brcmf_netif_rx(ifp, pkt);
++                      brcmf_netif_rx(ifp, pkt, false);
+                       return;
+               }
+@@ -408,7 +409,7 @@ static void brcmf_rxreorder_process_info
+               rfi = kzalloc(buf_size, GFP_ATOMIC);
+               if (rfi == NULL) {
+                       brcmf_err("failed to alloc buffer\n");
+-                      brcmf_netif_rx(ifp, pkt);
++                      brcmf_netif_rx(ifp, pkt, false);
+                       return;
+               }
+@@ -522,11 +523,11 @@ static void brcmf_rxreorder_process_info
+ netif_rx:
+       skb_queue_walk_safe(&reorder_list, pkt, pnext) {
+               __skb_unlink(pkt, &reorder_list);
+-              brcmf_netif_rx(ifp, pkt);
++              brcmf_netif_rx(ifp, pkt, false);
+       }
+ }
+-void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
++void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_evnt)
+ {
+       struct brcmf_if *ifp;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+@@ -550,7 +551,32 @@ void brcmf_rx_frame(struct device *dev,
+       if (rd->reorder)
+               brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
+       else
+-              brcmf_netif_rx(ifp, skb);
++              brcmf_netif_rx(ifp, skb, handle_evnt);
++}
++
++void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
++{
++      struct brcmf_if *ifp;
++      struct brcmf_bus *bus_if = dev_get_drvdata(dev);
++      struct brcmf_pub *drvr = bus_if->drvr;
++      int ret;
++
++      brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
++
++      /* process and remove protocol-specific header */
++      ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
++
++      if (ret || !ifp || !ifp->ndev) {
++              if (ret != -ENODATA && ifp)
++                      ifp->stats.rx_errors++;
++              brcmu_pkt_buf_free_skb(skb);
++              return;
++      }
++
++      skb->protocol = eth_type_trans(skb, ifp->ndev);
++
++      brcmf_fweh_process_skb(ifp->drvr, skb);
++      brcmu_pkt_buf_free_skb(skb);
+ }
+ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
+--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
++++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
+@@ -215,7 +215,8 @@ int brcmf_get_next_free_bsscfgidx(struct
+ void brcmf_txflowblock_if(struct brcmf_if *ifp,
+                         enum brcmf_netif_stop_reason reason, bool state);
+ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
+-void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
++void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb,
++                  bool handle_event);
+ void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
+ #endif /* BRCMFMAC_CORE_H */
+--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+@@ -20,6 +20,7 @@
+ #include <linux/types.h>
+ #include <linux/netdevice.h>
++#include <linux/etherdevice.h>
+ #include <brcmu_utils.h>
+ #include <brcmu_wifi.h>
+@@ -1076,28 +1077,13 @@ static void brcmf_msgbuf_rxbuf_event_pos
+ }
+-static void
+-brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
+-                  u8 ifidx)
+-{
+-      struct brcmf_if *ifp;
+-
+-      ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
+-      if (!ifp || !ifp->ndev) {
+-              brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
+-              brcmu_pkt_buf_free_skb(skb);
+-              return;
+-      }
+-      brcmf_netif_rx(ifp, skb);
+-}
+-
+-
+ static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
+ {
+       struct msgbuf_rx_event *event;
+       u32 idx;
+       u16 buflen;
+       struct sk_buff *skb;
++      struct brcmf_if *ifp;
+       event = (struct msgbuf_rx_event *)buf;
+       idx = le32_to_cpu(event->msg.request_id);
+@@ -1117,7 +1103,19 @@ static void brcmf_msgbuf_process_event(s
+       skb_trim(skb, buflen);
+-      brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx);
++      ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);
++      if (!ifp || !ifp->ndev) {
++              brcmf_err("Received pkt for invalid ifidx %d\n",
++                        event->msg.ifidx);
++              goto exit;
++      }
++
++      skb->protocol = eth_type_trans(skb, ifp->ndev);
++
++      brcmf_fweh_process_skb(ifp->drvr, skb);
++
++exit:
++      brcmu_pkt_buf_free_skb(skb);
+ }
+@@ -1129,6 +1127,7 @@ brcmf_msgbuf_process_rx_complete(struct
+       u16 data_offset;
+       u16 buflen;
+       u32 idx;
++      struct brcmf_if *ifp;
+       brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);
+@@ -1149,7 +1148,14 @@ brcmf_msgbuf_process_rx_complete(struct
+       skb_trim(skb, buflen);
+-      brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx);
++      ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
++      if (!ifp || !ifp->ndev) {
++              brcmf_err("Received pkt for invalid ifidx %d\n",
++                        rx_complete->msg.ifidx);
++              brcmu_pkt_buf_free_skb(skb);
++              return;
++      }
++      brcmf_netif_rx(ifp, skb, false);
+ }
+--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+@@ -1394,6 +1394,17 @@ static inline u8 brcmf_sdio_getdatoffset
+       return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
+ }
++static inline bool brcmf_sdio_fromevntchan(u8 *swheader)
++{
++      u32 hdrvalue;
++      u8 ret;
++
++      hdrvalue = *(u32 *)swheader;
++      ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT);
++
++      return (ret == SDPCM_EVENT_CHANNEL);
++}
++
+ static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
+                             struct brcmf_sdio_hdrinfo *rd,
+                             enum brcmf_sdio_frmtype type)
+@@ -1754,7 +1765,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf
+                                          pfirst->len, pfirst->next,
+                                          pfirst->prev);
+                       skb_unlink(pfirst, &bus->glom);
+-                      brcmf_rx_frame(bus->sdiodev->dev, pfirst);
++                      if (brcmf_sdio_fromevntchan(pfirst->data))
++                              brcmf_rx_event(bus->sdiodev->dev, pfirst);
++                      else
++                              brcmf_rx_frame(bus->sdiodev->dev, pfirst,
++                                             false);
+                       bus->sdcnt.rxglompkts++;
+               }
+@@ -2081,18 +2096,19 @@ static uint brcmf_sdio_readframes(struct
+               __skb_trim(pkt, rd->len);
+               skb_pull(pkt, rd->dat_offset);
++              if (pkt->len == 0)
++                      brcmu_pkt_buf_free_skb(pkt);
++              else if (rd->channel == SDPCM_EVENT_CHANNEL)
++                      brcmf_rx_event(bus->sdiodev->dev, pkt);
++              else
++                      brcmf_rx_frame(bus->sdiodev->dev, pkt,
++                                     false);
++
+               /* prepare the descriptor for the next read */
+               rd->len = rd->len_nxtfrm << 4;
+               rd->len_nxtfrm = 0;
+               /* treat all packet as event if we don't know */
+               rd->channel = SDPCM_EVENT_CHANNEL;
+-
+-              if (pkt->len == 0) {
+-                      brcmu_pkt_buf_free_skb(pkt);
+-                      continue;
+-              }
+-
+-              brcmf_rx_frame(bus->sdiodev->dev, pkt);
+       }
+       rxcount = maxframes - rxleft;
+--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
++++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+@@ -502,7 +502,7 @@ static void brcmf_usb_rx_complete(struct
+       if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
+               skb_put(skb, urb->actual_length);
+-              brcmf_rx_frame(devinfo->dev, skb);
++              brcmf_rx_frame(devinfo->dev, skb, true);
+               brcmf_usb_rx_refill(devinfo, req);
+       } else {
+               brcmu_pkt_buf_free_skb(skb);
diff --git a/queue-4.4/coredump-fix-race-condition-between-mmget_not_zero-get_task_mm-and-core-dumping.patch b/queue-4.4/coredump-fix-race-condition-between-mmget_not_zero-get_task_mm-and-core-dumping.patch
new file mode 100644 (file)
index 0000000..f638b9e
--- /dev/null
@@ -0,0 +1,208 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 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.4:
+ - 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
+@@ -947,6 +947,24 @@ static ssize_t clear_refs_write(struct f
+                                       continue;
+                               up_read(&mm->mmap_sem);
+                               down_write(&mm->mmap_sem);
++                              /*
++                               * 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
+@@ -446,6 +446,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();
+@@ -468,6 +470,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:
+@@ -769,6 +772,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;
+@@ -914,6 +919,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
+@@ -2625,6 +2625,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 *);
+ /* Grab a reference to a task's mm, if it is not already going away */
+--- a/mm/mmap.c
++++ b/mm/mmap.c
+@@ -42,6 +42,7 @@
+ #include <linux/memory.h>
+ #include <linux/printk.h>
+ #include <linux/userfaultfd_k.h>
++#include <linux/sched.h>
+ #include <asm/uaccess.h>
+ #include <asm/cacheflush.h>
+@@ -2398,7 +2399,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);
+@@ -2424,6 +2426,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;
diff --git a/queue-4.4/net-create-skb_gso_validate_mac_len.patch b/queue-4.4/net-create-skb_gso_validate_mac_len.patch
new file mode 100644 (file)
index 0000000..57919c0
--- /dev/null
@@ -0,0 +1,86 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 PM CEST
+From: Daniel Axtens <dja@axtens.net>
+Date: Wed, 31 Jan 2018 14:15:33 +1100
+Subject: net: create skb_gso_validate_mac_len()
+
+From: Daniel Axtens <dja@axtens.net>
+
+commit 2b16f048729bf35e6c28a40cbfad07239f9dcd90 upstream.
+
+If you take a GSO skb, and split it into packets, will the MAC
+length (L2 + L3 + L4 headers + payload) of those packets be small
+enough to fit within a given length?
+
+Move skb_gso_mac_seglen() to skbuff.h with other related functions
+like skb_gso_network_seglen() so we can use it, and then create
+skb_gso_validate_mac_len to do the full calculation.
+
+Signed-off-by: Daniel Axtens <dja@axtens.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[bwh: Backported to 4.4: There is no GSO_BY_FRAGS case to handle, so
+ skb_gso_validate_mac_len() becomes a trivial comparison. Put it inline in
+ <linux/skbuff.h>.]
+Signed-off-by: Ben Hutchings <ben.hutchings@codethink.co.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/skbuff.h |   30 ++++++++++++++++++++++++++++++
+ net/sched/sch_tbf.c    |   10 ----------
+ 2 files changed, 30 insertions(+), 10 deletions(-)
+
+--- a/include/linux/skbuff.h
++++ b/include/linux/skbuff.h
+@@ -3664,5 +3664,35 @@ static inline unsigned int skb_gso_netwo
+       return hdr_len + skb_gso_transport_seglen(skb);
+ }
++/**
++ * skb_gso_mac_seglen - Return length of individual segments of a gso packet
++ *
++ * @skb: GSO skb
++ *
++ * skb_gso_mac_seglen is used to determine the real size of the
++ * individual segments, including MAC/L2, Layer3 (IP, IPv6) and L4
++ * headers (TCP/UDP).
++ */
++static inline unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
++{
++      unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
++      return hdr_len + skb_gso_transport_seglen(skb);
++}
++
++/**
++ * skb_gso_validate_mac_len - Will a split GSO skb fit in a given length?
++ *
++ * @skb: GSO skb
++ * @len: length to validate against
++ *
++ * skb_gso_validate_mac_len validates if a given skb will fit a wanted
++ * length once split, including L2, L3 and L4 headers and the payload.
++ */
++static inline bool
++skb_gso_validate_mac_len(const struct sk_buff *skb, unsigned int len)
++{
++      return skb_gso_mac_seglen(skb) <= len;
++}
++
+ #endif        /* __KERNEL__ */
+ #endif        /* _LINUX_SKBUFF_H */
+--- a/net/sched/sch_tbf.c
++++ b/net/sched/sch_tbf.c
+@@ -142,16 +142,6 @@ static u64 psched_ns_t2l(const struct ps
+       return len;
+ }
+-/*
+- * Return length of individual segments of a gso packet,
+- * including all headers (MAC, IP, TCP/UDP)
+- */
+-static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
+-{
+-      unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
+-      return hdr_len + skb_gso_transport_seglen(skb);
+-}
+-
+ /* GSO packet is too big, segment it so that tbf can transmit
+  * each segment in time
+  */
index 4ed1ce99d2e1853f35264fe3fd665c0a31d6376d..c6923a7f41cf9d443c53e89fca0272bd698dd055 100644 (file)
@@ -212,3 +212,15 @@ memcg-make-it-work-on-sparse-non-0-node-systems.patch
 kernel-signal.c-trace_signal_deliver-when-signal_group_exit.patch
 cifs-cifs_read_allocate_pages-don-t-iterate-through-whole-page-array-on-enomem.patch
 drm-rockchip-shutdown-drm-subsystem-on-shutdown.patch
+binder-replace-p-with-pk-for-stable.patch
+binder-replace-p-with-pk.patch
+net-create-skb_gso_validate_mac_len.patch
+bnx2x-disable-gso-where-gso_size-is-too-big-for-hardware.patch
+brcmfmac-add-length-checks-on-firmware-events.patch
+brcmfmac-screening-firmware-event-packet.patch
+brcmfmac-revise-handling-events-in-receive-path.patch
+brcmfmac-fix-incorrect-event-channel-deduction.patch
+brcmfmac-add-length-checks-in-scheduled-scan-result-handler.patch
+brcmfmac-add-subtype-check-for-event-handling-in-data-path.patch
+userfaultfd-don-t-pin-the-user-memory-in-userfaultfd_file_create.patch
+coredump-fix-race-condition-between-mmget_not_zero-get_task_mm-and-core-dumping.patch
diff --git a/queue-4.4/userfaultfd-don-t-pin-the-user-memory-in-userfaultfd_file_create.patch b/queue-4.4/userfaultfd-don-t-pin-the-user-memory-in-userfaultfd_file_create.patch
new file mode 100644 (file)
index 0000000..23a5d3a
--- /dev/null
@@ -0,0 +1,177 @@
+From foo@baz Tue 04 Jun 2019 04:46:27 PM CEST
+From: Oleg Nesterov <oleg@redhat.com>
+Date: Fri, 20 May 2016 16:58:36 -0700
+Subject: userfaultfd: don't pin the user memory in userfaultfd_file_create()
+
+From: Oleg Nesterov <oleg@redhat.com>
+
+commit d2005e3f41d4f9299e2df6a967c8beb5086967a9 upstream.
+
+userfaultfd_file_create() increments mm->mm_users; this means that the
+memory won't be unmapped/freed if mm owner exits/execs, and UFFDIO_COPY
+after that can populate the orphaned mm more.
+
+Change userfaultfd_file_create() and userfaultfd_ctx_put() to use
+mm->mm_count to pin mm_struct.  This means that
+atomic_inc_not_zero(mm->mm_users) is needed when we are going to
+actually play with this memory.  Except handle_userfault() path doesn't
+need this, the caller must already have a reference.
+
+The patch adds the new trivial helper, mmget_not_zero(), it can have
+more users.
+
+Link: http://lkml.kernel.org/r/20160516172254.GA8595@redhat.com
+Signed-off-by: Oleg Nesterov <oleg@redhat.com>
+Cc: Andrea Arcangeli <aarcange@redhat.com>
+Cc: Michal Hocko <mhocko@kernel.org>
+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>
+---
+ fs/userfaultfd.c      |   41 ++++++++++++++++++++++++++++-------------
+ include/linux/sched.h |    7 ++++++-
+ 2 files changed, 34 insertions(+), 14 deletions(-)
+
+--- a/fs/userfaultfd.c
++++ b/fs/userfaultfd.c
+@@ -137,7 +137,7 @@ static void userfaultfd_ctx_put(struct u
+               VM_BUG_ON(waitqueue_active(&ctx->fault_wqh));
+               VM_BUG_ON(spin_is_locked(&ctx->fd_wqh.lock));
+               VM_BUG_ON(waitqueue_active(&ctx->fd_wqh));
+-              mmput(ctx->mm);
++              mmdrop(ctx->mm);
+               kmem_cache_free(userfaultfd_ctx_cachep, ctx);
+       }
+ }
+@@ -434,6 +434,9 @@ static int userfaultfd_release(struct in
+       ACCESS_ONCE(ctx->released) = true;
++      if (!mmget_not_zero(mm))
++              goto wakeup;
++
+       /*
+        * Flush page faults out of all CPUs. NOTE: all page faults
+        * must be retried without returning VM_FAULT_SIGBUS if
+@@ -466,7 +469,8 @@ static int userfaultfd_release(struct in
+               vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX;
+       }
+       up_write(&mm->mmap_sem);
+-
++      mmput(mm);
++wakeup:
+       /*
+        * After no new page faults can wait on this fault_*wqh, flush
+        * the last page faults that may have been already waiting on
+@@ -760,10 +764,12 @@ static int userfaultfd_register(struct u
+       start = uffdio_register.range.start;
+       end = start + uffdio_register.range.len;
++      ret = -ENOMEM;
++      if (!mmget_not_zero(mm))
++              goto out;
++
+       down_write(&mm->mmap_sem);
+       vma = find_vma_prev(mm, start, &prev);
+-
+-      ret = -ENOMEM;
+       if (!vma)
+               goto out_unlock;
+@@ -864,6 +870,7 @@ static int userfaultfd_register(struct u
+       } while (vma && vma->vm_start < end);
+ out_unlock:
+       up_write(&mm->mmap_sem);
++      mmput(mm);
+       if (!ret) {
+               /*
+                * Now that we scanned all vmas we can already tell
+@@ -902,10 +909,12 @@ static int userfaultfd_unregister(struct
+       start = uffdio_unregister.start;
+       end = start + uffdio_unregister.len;
++      ret = -ENOMEM;
++      if (!mmget_not_zero(mm))
++              goto out;
++
+       down_write(&mm->mmap_sem);
+       vma = find_vma_prev(mm, start, &prev);
+-
+-      ret = -ENOMEM;
+       if (!vma)
+               goto out_unlock;
+@@ -998,6 +1007,7 @@ static int userfaultfd_unregister(struct
+       } while (vma && vma->vm_start < end);
+ out_unlock:
+       up_write(&mm->mmap_sem);
++      mmput(mm);
+ out:
+       return ret;
+ }
+@@ -1067,9 +1077,11 @@ static int userfaultfd_copy(struct userf
+               goto out;
+       if (uffdio_copy.mode & ~UFFDIO_COPY_MODE_DONTWAKE)
+               goto out;
+-
+-      ret = mcopy_atomic(ctx->mm, uffdio_copy.dst, uffdio_copy.src,
+-                         uffdio_copy.len);
++      if (mmget_not_zero(ctx->mm)) {
++              ret = mcopy_atomic(ctx->mm, uffdio_copy.dst, uffdio_copy.src,
++                                 uffdio_copy.len);
++              mmput(ctx->mm);
++      }
+       if (unlikely(put_user(ret, &user_uffdio_copy->copy)))
+               return -EFAULT;
+       if (ret < 0)
+@@ -1110,8 +1122,11 @@ static int userfaultfd_zeropage(struct u
+       if (uffdio_zeropage.mode & ~UFFDIO_ZEROPAGE_MODE_DONTWAKE)
+               goto out;
+-      ret = mfill_zeropage(ctx->mm, uffdio_zeropage.range.start,
+-                           uffdio_zeropage.range.len);
++      if (mmget_not_zero(ctx->mm)) {
++              ret = mfill_zeropage(ctx->mm, uffdio_zeropage.range.start,
++                                   uffdio_zeropage.range.len);
++              mmput(ctx->mm);
++      }
+       if (unlikely(put_user(ret, &user_uffdio_zeropage->zeropage)))
+               return -EFAULT;
+       if (ret < 0)
+@@ -1289,12 +1304,12 @@ static struct file *userfaultfd_file_cre
+       ctx->released = false;
+       ctx->mm = current->mm;
+       /* prevent the mm struct to be freed */
+-      atomic_inc(&ctx->mm->mm_users);
++      atomic_inc(&ctx->mm->mm_count);
+       file = anon_inode_getfile("[userfaultfd]", &userfaultfd_fops, ctx,
+                                 O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS));
+       if (IS_ERR(file)) {
+-              mmput(ctx->mm);
++              mmdrop(ctx->mm);
+               kmem_cache_free(userfaultfd_ctx_cachep, ctx);
+       }
+ out:
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -2614,12 +2614,17 @@ extern struct mm_struct * mm_alloc(void)
+ /* mmdrop drops the mm and the page tables */
+ extern void __mmdrop(struct mm_struct *);
+-static inline void mmdrop(struct mm_struct * mm)
++static inline void mmdrop(struct mm_struct *mm)
+ {
+       if (unlikely(atomic_dec_and_test(&mm->mm_count)))
+               __mmdrop(mm);
+ }
++static inline bool mmget_not_zero(struct mm_struct *mm)
++{
++      return atomic_inc_not_zero(&mm->mm_users);
++}
++
+ /* mmput gets rid of the mappings and all user-space */
+ extern void mmput(struct mm_struct *);
+ /* Grab a reference to a task's mm, if it is not already going away */