From: Greg Kroah-Hartman Date: Mon, 18 Feb 2019 12:48:45 +0000 (+0100) Subject: 4.9-stable patches X-Git-Tag: v3.18.135~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=e212617380ffc9d91819dde9ea34d1a96db510ee;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: ch9200-use-skb_cow_head-to-deal-with-cloned-skbs.patch kaweth-use-skb_cow_head-to-deal-with-cloned-skbs.patch netfilter-nf_tables-fix-mismatch-in-big-endian-system.patch smsc95xx-use-skb_cow_head-to-deal-with-cloned-skbs.patch usb-dwc2-remove-unnecessary-kfree.patch --- diff --git a/queue-4.9/ch9200-use-skb_cow_head-to-deal-with-cloned-skbs.patch b/queue-4.9/ch9200-use-skb_cow_head-to-deal-with-cloned-skbs.patch new file mode 100644 index 00000000000..45543c3b5cf --- /dev/null +++ b/queue-4.9/ch9200-use-skb_cow_head-to-deal-with-cloned-skbs.patch @@ -0,0 +1,45 @@ +From 6bc6895bdd6744e0136eaa4a11fbdb20a7db4e40 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Wed, 19 Apr 2017 09:59:25 -0700 +Subject: ch9200: use skb_cow_head() to deal with cloned skbs + +From: Eric Dumazet + +commit 6bc6895bdd6744e0136eaa4a11fbdb20a7db4e40 upstream. + +We need to ensure there is enough headroom to push extra header, +but we also need to check if we are allowed to change headers. + +skb_cow_head() is the proper helper to deal with this. + +Fixes: 4a476bd6d1d9 ("usbnet: New driver for QinHeng CH9200 devices") +Signed-off-by: Eric Dumazet +Cc: James Hughes +Cc: Matthew Garrett +Signed-off-by: David S. Miller +Signed-off-by: Linus Walleij +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/usb/ch9200.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +--- a/drivers/net/usb/ch9200.c ++++ b/drivers/net/usb/ch9200.c +@@ -254,14 +254,9 @@ static struct sk_buff *ch9200_tx_fixup(s + tx_overhead = 0x40; + + len = skb->len; +- if (skb_headroom(skb) < tx_overhead) { +- struct sk_buff *skb2; +- +- skb2 = skb_copy_expand(skb, tx_overhead, 0, flags); ++ if (skb_cow_head(skb, tx_overhead)) { + dev_kfree_skb_any(skb); +- skb = skb2; +- if (!skb) +- return NULL; ++ return NULL; + } + + __skb_push(skb, tx_overhead); diff --git a/queue-4.9/kaweth-use-skb_cow_head-to-deal-with-cloned-skbs.patch b/queue-4.9/kaweth-use-skb_cow_head-to-deal-with-cloned-skbs.patch new file mode 100644 index 00000000000..e7b85c86931 --- /dev/null +++ b/queue-4.9/kaweth-use-skb_cow_head-to-deal-with-cloned-skbs.patch @@ -0,0 +1,50 @@ +From 39fba7835aacda65284a86e611774cbba71dac20 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Wed, 19 Apr 2017 09:59:26 -0700 +Subject: kaweth: use skb_cow_head() to deal with cloned skbs + +From: Eric Dumazet + +commit 39fba7835aacda65284a86e611774cbba71dac20 upstream. + +We can use skb_cow_head() to properly deal with clones, +especially the ones coming from TCP stack that allow their head being +modified. This avoids a copy. + +Signed-off-by: Eric Dumazet +Cc: James Hughes +Signed-off-by: David S. Miller +Signed-off-by: Linus Walleij +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/usb/kaweth.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +--- a/drivers/net/usb/kaweth.c ++++ b/drivers/net/usb/kaweth.c +@@ -803,18 +803,12 @@ static netdev_tx_t kaweth_start_xmit(str + } + + /* We now decide whether we can put our special header into the sk_buff */ +- if (skb_cloned(skb) || skb_headroom(skb) < 2) { +- /* no such luck - we make our own */ +- struct sk_buff *copied_skb; +- copied_skb = skb_copy_expand(skb, 2, 0, GFP_ATOMIC); +- dev_kfree_skb_irq(skb); +- skb = copied_skb; +- if (!copied_skb) { +- kaweth->stats.tx_errors++; +- netif_start_queue(net); +- spin_unlock_irq(&kaweth->device_lock); +- return NETDEV_TX_OK; +- } ++ if (skb_cow_head(skb, 2)) { ++ kaweth->stats.tx_errors++; ++ netif_start_queue(net); ++ spin_unlock_irq(&kaweth->device_lock); ++ dev_kfree_skb_any(skb); ++ return NETDEV_TX_OK; + } + + private_header = (__le16 *)__skb_push(skb, 2); diff --git a/queue-4.9/netfilter-nf_tables-fix-mismatch-in-big-endian-system.patch b/queue-4.9/netfilter-nf_tables-fix-mismatch-in-big-endian-system.patch new file mode 100644 index 00000000000..412d770bf82 --- /dev/null +++ b/queue-4.9/netfilter-nf_tables-fix-mismatch-in-big-endian-system.patch @@ -0,0 +1,330 @@ +From 10596608c4d62cb8c1c2b806debcbd32fe657e71 Mon Sep 17 00:00:00 2001 +From: Liping Zhang +Date: Wed, 8 Mar 2017 22:54:18 +0800 +Subject: netfilter: nf_tables: fix mismatch in big-endian system + +From: Liping Zhang + +commit 10596608c4d62cb8c1c2b806debcbd32fe657e71 upstream. + +Currently, there are two different methods to store an u16 integer to +the u32 data register. For example: + u32 *dest = ®s->data[priv->dreg]; + 1. *dest = 0; *(u16 *) dest = val_u16; + 2. *dest = val_u16; + +For method 1, the u16 value will be stored like this, either in +big-endian or little-endian system: + 0 15 31 + +-+-+-+-+-+-+-+-+-+-+-+-+ + | Value | 0 | + +-+-+-+-+-+-+-+-+-+-+-+-+ + +For method 2, in little-endian system, the u16 value will be the same +as listed above. But in big-endian system, the u16 value will be stored +like this: + 0 15 31 + +-+-+-+-+-+-+-+-+-+-+-+-+ + | 0 | Value | + +-+-+-+-+-+-+-+-+-+-+-+-+ + +So later we use "memcmp(®s->data[priv->sreg], data, 2);" to do +compare in nft_cmp, nft_lookup expr ..., method 2 will get the wrong +result in big-endian system, as 0~15 bits will always be zero. + +For the similar reason, when loading an u16 value from the u32 data +register, we should use "*(u16 *) sreg;" instead of "(u16)*sreg;", +the 2nd method will get the wrong value in the big-endian system. + +So introduce some wrapper functions to store/load an u8 or u16 +integer to/from the u32 data register, and use them in the right +place. + +Signed-off-by: Liping Zhang +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Linus Walleij +Signed-off-by: Greg Kroah-Hartman + +--- + include/net/netfilter/nf_tables.h | 29 ++++++++++++++++++++++++ + net/ipv4/netfilter/nft_masq_ipv4.c | 8 +++--- + net/ipv4/netfilter/nft_redir_ipv4.c | 8 +++--- + net/ipv6/netfilter/nft_masq_ipv6.c | 8 +++--- + net/ipv6/netfilter/nft_redir_ipv6.c | 8 +++--- + net/netfilter/nft_ct.c | 10 ++++---- + net/netfilter/nft_meta.c | 42 ++++++++++++++++++------------------ + net/netfilter/nft_nat.c | 8 +++--- + 8 files changed, 76 insertions(+), 45 deletions(-) + +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -87,6 +87,35 @@ struct nft_regs { + }; + }; + ++/* Store/load an u16 or u8 integer to/from the u32 data register. ++ * ++ * Note, when using concatenations, register allocation happens at 32-bit ++ * level. So for store instruction, pad the rest part with zero to avoid ++ * garbage values. ++ */ ++ ++static inline void nft_reg_store16(u32 *dreg, u16 val) ++{ ++ *dreg = 0; ++ *(u16 *)dreg = val; ++} ++ ++static inline void nft_reg_store8(u32 *dreg, u8 val) ++{ ++ *dreg = 0; ++ *(u8 *)dreg = val; ++} ++ ++static inline u16 nft_reg_load16(u32 *sreg) ++{ ++ return *(u16 *)sreg; ++} ++ ++static inline u8 nft_reg_load8(u32 *sreg) ++{ ++ return *(u8 *)sreg; ++} ++ + static inline void nft_data_copy(u32 *dst, const struct nft_data *src, + unsigned int len) + { +--- a/net/ipv4/netfilter/nft_masq_ipv4.c ++++ b/net/ipv4/netfilter/nft_masq_ipv4.c +@@ -26,10 +26,10 @@ static void nft_masq_ipv4_eval(const str + memset(&range, 0, sizeof(range)); + range.flags = priv->flags; + if (priv->sreg_proto_min) { +- range.min_proto.all = +- *(__be16 *)®s->data[priv->sreg_proto_min]; +- range.max_proto.all = +- *(__be16 *)®s->data[priv->sreg_proto_max]; ++ range.min_proto.all = (__force __be16)nft_reg_load16( ++ ®s->data[priv->sreg_proto_min]); ++ range.max_proto.all = (__force __be16)nft_reg_load16( ++ ®s->data[priv->sreg_proto_max]); + } + regs->verdict.code = nf_nat_masquerade_ipv4(pkt->skb, pkt->hook, + &range, pkt->out); +--- a/net/ipv4/netfilter/nft_redir_ipv4.c ++++ b/net/ipv4/netfilter/nft_redir_ipv4.c +@@ -26,10 +26,10 @@ static void nft_redir_ipv4_eval(const st + + memset(&mr, 0, sizeof(mr)); + if (priv->sreg_proto_min) { +- mr.range[0].min.all = +- *(__be16 *)®s->data[priv->sreg_proto_min]; +- mr.range[0].max.all = +- *(__be16 *)®s->data[priv->sreg_proto_max]; ++ mr.range[0].min.all = (__force __be16)nft_reg_load16( ++ ®s->data[priv->sreg_proto_min]); ++ mr.range[0].max.all = (__force __be16)nft_reg_load16( ++ ®s->data[priv->sreg_proto_max]); + mr.range[0].flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + } + +--- a/net/ipv6/netfilter/nft_masq_ipv6.c ++++ b/net/ipv6/netfilter/nft_masq_ipv6.c +@@ -27,10 +27,10 @@ static void nft_masq_ipv6_eval(const str + memset(&range, 0, sizeof(range)); + range.flags = priv->flags; + if (priv->sreg_proto_min) { +- range.min_proto.all = +- *(__be16 *)®s->data[priv->sreg_proto_min]; +- range.max_proto.all = +- *(__be16 *)®s->data[priv->sreg_proto_max]; ++ range.min_proto.all = (__force __be16)nft_reg_load16( ++ ®s->data[priv->sreg_proto_min]); ++ range.max_proto.all = (__force __be16)nft_reg_load16( ++ ®s->data[priv->sreg_proto_max]); + } + regs->verdict.code = nf_nat_masquerade_ipv6(pkt->skb, &range, pkt->out); + } +--- a/net/ipv6/netfilter/nft_redir_ipv6.c ++++ b/net/ipv6/netfilter/nft_redir_ipv6.c +@@ -26,10 +26,10 @@ static void nft_redir_ipv6_eval(const st + + memset(&range, 0, sizeof(range)); + if (priv->sreg_proto_min) { +- range.min_proto.all = +- *(__be16 *)®s->data[priv->sreg_proto_min], +- range.max_proto.all = +- *(__be16 *)®s->data[priv->sreg_proto_max], ++ range.min_proto.all = (__force __be16)nft_reg_load16( ++ ®s->data[priv->sreg_proto_min]); ++ range.max_proto.all = (__force __be16)nft_reg_load16( ++ ®s->data[priv->sreg_proto_max]); + range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + } + +--- a/net/netfilter/nft_ct.c ++++ b/net/netfilter/nft_ct.c +@@ -77,7 +77,7 @@ static void nft_ct_get_eval(const struct + + switch (priv->key) { + case NFT_CT_DIRECTION: +- *dest = CTINFO2DIR(ctinfo); ++ nft_reg_store8(dest, CTINFO2DIR(ctinfo)); + return; + case NFT_CT_STATUS: + *dest = ct->status; +@@ -129,10 +129,10 @@ static void nft_ct_get_eval(const struct + return; + } + case NFT_CT_L3PROTOCOL: +- *dest = nf_ct_l3num(ct); ++ nft_reg_store8(dest, nf_ct_l3num(ct)); + return; + case NFT_CT_PROTOCOL: +- *dest = nf_ct_protonum(ct); ++ nft_reg_store8(dest, nf_ct_protonum(ct)); + return; + default: + break; +@@ -149,10 +149,10 @@ static void nft_ct_get_eval(const struct + nf_ct_l3num(ct) == NFPROTO_IPV4 ? 4 : 16); + return; + case NFT_CT_PROTO_SRC: +- *dest = (__force __u16)tuple->src.u.all; ++ nft_reg_store16(dest, (__force u16)tuple->src.u.all); + return; + case NFT_CT_PROTO_DST: +- *dest = (__force __u16)tuple->dst.u.all; ++ nft_reg_store16(dest, (__force u16)tuple->dst.u.all); + return; + default: + break; +--- a/net/netfilter/nft_meta.c ++++ b/net/netfilter/nft_meta.c +@@ -45,16 +45,15 @@ void nft_meta_get_eval(const struct nft_ + *dest = skb->len; + break; + case NFT_META_PROTOCOL: +- *dest = 0; +- *(__be16 *)dest = skb->protocol; ++ nft_reg_store16(dest, (__force u16)skb->protocol); + break; + case NFT_META_NFPROTO: +- *dest = pkt->pf; ++ nft_reg_store8(dest, pkt->pf); + break; + case NFT_META_L4PROTO: + if (!pkt->tprot_set) + goto err; +- *dest = pkt->tprot; ++ nft_reg_store8(dest, pkt->tprot); + break; + case NFT_META_PRIORITY: + *dest = skb->priority; +@@ -85,14 +84,12 @@ void nft_meta_get_eval(const struct nft_ + case NFT_META_IIFTYPE: + if (in == NULL) + goto err; +- *dest = 0; +- *(u16 *)dest = in->type; ++ nft_reg_store16(dest, in->type); + break; + case NFT_META_OIFTYPE: + if (out == NULL) + goto err; +- *dest = 0; +- *(u16 *)dest = out->type; ++ nft_reg_store16(dest, out->type); + break; + case NFT_META_SKUID: + sk = skb_to_full_sk(skb); +@@ -142,22 +139,22 @@ void nft_meta_get_eval(const struct nft_ + #endif + case NFT_META_PKTTYPE: + if (skb->pkt_type != PACKET_LOOPBACK) { +- *dest = skb->pkt_type; ++ nft_reg_store8(dest, skb->pkt_type); + break; + } + + switch (pkt->pf) { + case NFPROTO_IPV4: + if (ipv4_is_multicast(ip_hdr(skb)->daddr)) +- *dest = PACKET_MULTICAST; ++ nft_reg_store8(dest, PACKET_MULTICAST); + else +- *dest = PACKET_BROADCAST; ++ nft_reg_store8(dest, PACKET_BROADCAST); + break; + case NFPROTO_IPV6: + if (ipv6_hdr(skb)->daddr.s6_addr[0] == 0xFF) +- *dest = PACKET_MULTICAST; ++ nft_reg_store8(dest, PACKET_MULTICAST); + else +- *dest = PACKET_BROADCAST; ++ nft_reg_store8(dest, PACKET_BROADCAST); + break; + case NFPROTO_NETDEV: + switch (skb->protocol) { +@@ -171,14 +168,14 @@ void nft_meta_get_eval(const struct nft_ + goto err; + + if (ipv4_is_multicast(iph->daddr)) +- *dest = PACKET_MULTICAST; ++ nft_reg_store8(dest, PACKET_MULTICAST); + else +- *dest = PACKET_BROADCAST; ++ nft_reg_store8(dest, PACKET_BROADCAST); + + break; + } + case htons(ETH_P_IPV6): +- *dest = PACKET_MULTICAST; ++ nft_reg_store8(dest, PACKET_MULTICAST); + break; + default: + WARN_ON_ONCE(1); +@@ -233,7 +230,9 @@ void nft_meta_set_eval(const struct nft_ + { + const struct nft_meta *meta = nft_expr_priv(expr); + struct sk_buff *skb = pkt->skb; +- u32 value = regs->data[meta->sreg]; ++ u32 *sreg = ®s->data[meta->sreg]; ++ u32 value = *sreg; ++ u8 pkt_type; + + switch (meta->key) { + case NFT_META_MARK: +@@ -243,9 +242,12 @@ void nft_meta_set_eval(const struct nft_ + skb->priority = value; + break; + case NFT_META_PKTTYPE: +- if (skb->pkt_type != value && +- skb_pkt_type_ok(value) && skb_pkt_type_ok(skb->pkt_type)) +- skb->pkt_type = value; ++ pkt_type = nft_reg_load8(sreg); ++ ++ if (skb->pkt_type != pkt_type && ++ skb_pkt_type_ok(pkt_type) && ++ skb_pkt_type_ok(skb->pkt_type)) ++ skb->pkt_type = pkt_type; + break; + case NFT_META_NFTRACE: + skb->nf_trace = !!value; +--- a/net/netfilter/nft_nat.c ++++ b/net/netfilter/nft_nat.c +@@ -65,10 +65,10 @@ static void nft_nat_eval(const struct nf + } + + if (priv->sreg_proto_min) { +- range.min_proto.all = +- *(__be16 *)®s->data[priv->sreg_proto_min]; +- range.max_proto.all = +- *(__be16 *)®s->data[priv->sreg_proto_max]; ++ range.min_proto.all = (__force __be16)nft_reg_load16( ++ ®s->data[priv->sreg_proto_min]); ++ range.max_proto.all = (__force __be16)nft_reg_load16( ++ ®s->data[priv->sreg_proto_max]); + range.flags |= NF_NAT_RANGE_PROTO_SPECIFIED; + } + diff --git a/queue-4.9/series b/queue-4.9/series index bb30904b444..b27cabbac97 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -49,3 +49,8 @@ signal-restore-the-stop-ptrace_event_exit.patch x86-a.out-clear-the-dump-structure-initially.patch dm-thin-fix-bug-where-bio-that-overwrites-thin-block-ignores-fua.patch drm-i915-prevent-a-race-during-i915_gem_mmap-ioctl-with-wc-set.patch +smsc95xx-use-skb_cow_head-to-deal-with-cloned-skbs.patch +ch9200-use-skb_cow_head-to-deal-with-cloned-skbs.patch +kaweth-use-skb_cow_head-to-deal-with-cloned-skbs.patch +usb-dwc2-remove-unnecessary-kfree.patch +netfilter-nf_tables-fix-mismatch-in-big-endian-system.patch diff --git a/queue-4.9/smsc95xx-use-skb_cow_head-to-deal-with-cloned-skbs.patch b/queue-4.9/smsc95xx-use-skb_cow_head-to-deal-with-cloned-skbs.patch new file mode 100644 index 00000000000..5ac173917e6 --- /dev/null +++ b/queue-4.9/smsc95xx-use-skb_cow_head-to-deal-with-cloned-skbs.patch @@ -0,0 +1,47 @@ +From e9156cd26a495a18706e796f02a81fee41ec14f4 Mon Sep 17 00:00:00 2001 +From: James Hughes +Date: Wed, 19 Apr 2017 11:13:40 +0100 +Subject: smsc95xx: Use skb_cow_head to deal with cloned skbs + +From: James Hughes + +commit e9156cd26a495a18706e796f02a81fee41ec14f4 upstream. + +The driver was failing to check that the SKB wasn't cloned +before adding checksum data. +Replace existing handling to extend/copy the header buffer +with skb_cow_head. + +Signed-off-by: James Hughes +Acked-by: Eric Dumazet +Acked-by: Woojung Huh +Signed-off-by: David S. Miller +Signed-off-by: Linus Walleij +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/usb/smsc95xx.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/drivers/net/usb/smsc95xx.c ++++ b/drivers/net/usb/smsc95xx.c +@@ -2011,13 +2011,13 @@ static struct sk_buff *smsc95xx_tx_fixup + /* We do not advertise SG, so skbs should be already linearized */ + BUG_ON(skb_shinfo(skb)->nr_frags); + +- if (skb_headroom(skb) < overhead) { +- struct sk_buff *skb2 = skb_copy_expand(skb, +- overhead, 0, flags); ++ /* Make writable and expand header space by overhead if required */ ++ if (skb_cow_head(skb, overhead)) { ++ /* Must deallocate here as returning NULL to indicate error ++ * means the skb won't be deallocated in the caller. ++ */ + dev_kfree_skb_any(skb); +- skb = skb2; +- if (!skb) +- return NULL; ++ return NULL; + } + + if (csum) { diff --git a/queue-4.9/usb-dwc2-remove-unnecessary-kfree.patch b/queue-4.9/usb-dwc2-remove-unnecessary-kfree.patch new file mode 100644 index 00000000000..2018a2c2ad2 --- /dev/null +++ b/queue-4.9/usb-dwc2-remove-unnecessary-kfree.patch @@ -0,0 +1,31 @@ +From cd4b1e34655d46950c065d9284b596cd8d7b28cd Mon Sep 17 00:00:00 2001 +From: John Youn +Date: Thu, 3 Nov 2016 17:55:45 -0700 +Subject: usb: dwc2: Remove unnecessary kfree + +From: John Youn + +commit cd4b1e34655d46950c065d9284b596cd8d7b28cd upstream. + +This shouldn't be freed by the HCD as it is owned by the core and +allocated with devm_kzalloc. + +Signed-off-by: John Youn +Signed-off-by: Felipe Balbi +Signed-off-by: Linus Walleij +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/dwc2/hcd.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/usb/dwc2/hcd.c ++++ b/drivers/usb/dwc2/hcd.c +@@ -5202,7 +5202,6 @@ error3: + error2: + usb_put_hcd(hcd); + error1: +- kfree(hsotg->core_params); + + #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS + kfree(hsotg->last_frame_num_array);