--- /dev/null
+From 823d81b0fa2cd83a640734e74caee338b5d3c093 Mon Sep 17 00:00:00 2001
+From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
+Date: Mon, 24 Feb 2020 18:46:22 +0200
+Subject: net: bridge: fix stale eth hdr pointer in br_dev_xmit
+
+From: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
+
+commit 823d81b0fa2cd83a640734e74caee338b5d3c093 upstream.
+
+In br_dev_xmit() we perform vlan filtering in br_allowed_ingress() but
+if the packet has the vlan header inside (e.g. bridge with disabled
+tx-vlan-offload) then the vlan filtering code will use skb_vlan_untag()
+to extract the vid before filtering which in turn calls pskb_may_pull()
+and we may end up with a stale eth pointer. Moreover the cached eth header
+pointer will generally be wrong after that operation. Remove the eth header
+caching and just use eth_hdr() directly, the compiler does the right thing
+and calculates it only once so we don't lose anything.
+
+Fixes: 057658cb33fb ("bridge: suppress arp pkts on BR_NEIGH_SUPPRESS ports")
+Signed-off-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Cc: Eduardo Vela <Nava> <evn@google.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/bridge/br_device.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/net/bridge/br_device.c
++++ b/net/bridge/br_device.c
+@@ -33,7 +33,6 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
+ struct pcpu_sw_netstats *brstats = this_cpu_ptr(br->stats);
+ const struct nf_br_ops *nf_ops;
+ const unsigned char *dest;
+- struct ethhdr *eth;
+ u16 vid = 0;
+
+ rcu_read_lock();
+@@ -53,15 +52,14 @@ netdev_tx_t br_dev_xmit(struct sk_buff *
+ BR_INPUT_SKB_CB(skb)->frag_max_size = 0;
+
+ skb_reset_mac_header(skb);
+- eth = eth_hdr(skb);
+ skb_pull(skb, ETH_HLEN);
+
+ if (!br_allowed_ingress(br, br_vlan_group_rcu(br), skb, &vid))
+ goto out;
+
+ if (IS_ENABLED(CONFIG_INET) &&
+- (eth->h_proto == htons(ETH_P_ARP) ||
+- eth->h_proto == htons(ETH_P_RARP)) &&
++ (eth_hdr(skb)->h_proto == htons(ETH_P_ARP) ||
++ eth_hdr(skb)->h_proto == htons(ETH_P_RARP)) &&
+ br_opt_get(br, BROPT_NEIGH_SUPPRESS_ENABLED)) {
+ br_do_proxy_suppress_arp(skb, br, vid, NULL);
+ } else if (IS_ENABLED(CONFIG_IPV6) &&