summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2017-03-17 08:05:28 -0700
committerBen Hutchings <ben@decadent.org.uk>2017-07-18 18:40:20 +0100
commita89905a9dfb593068c28727585e24a2810be82ea (patch)
tree3760b966a0330b87dae595a06af4cf55a1ff34e4 /net
parent0c361c9410c11a75755b1889fcc24cb2ae4ddcdb (diff)
downloadlinux-stable-a89905a9dfb593068c28727585e24a2810be82ea.tar.gz
linux-stable-a89905a9dfb593068c28727585e24a2810be82ea.tar.bz2
linux-stable-a89905a9dfb593068c28727585e24a2810be82ea.zip
sch_dsmark: fix invalid skb_cow() usage
commit aea92fb2e09e29653b023d4254ac9fbf94221538 upstream. skb_cow(skb, sizeof(ip header)) is not very helpful in this context. First we need to use pskb_may_pull() to make sure the ip header is in skb linear part, then use skb_try_make_writable() to address clones issues. Fixes: 4c30719f4f55 ("[PKT_SCHED] dsmark: handle cloned and non-linear skb's") Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> [bwh: Backported to 3.16: adjust context] Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'net')
-rw-r--r--net/sched/sch_dsmark.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index 5d8180269dc9..5571e7c076de 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -197,9 +197,13 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
pr_debug("%s(skb %p,sch %p,[qdisc %p])\n", __func__, skb, sch, p);
if (p->set_tc_index) {
+ int wlen = skb_network_offset(skb);
+
switch (skb->protocol) {
case htons(ETH_P_IP):
- if (skb_cow_head(skb, sizeof(struct iphdr)))
+ wlen += sizeof(struct iphdr);
+ if (!pskb_may_pull(skb, wlen) ||
+ skb_try_make_writable(skb, wlen))
goto drop;
skb->tc_index = ipv4_get_dsfield(ip_hdr(skb))
@@ -207,7 +211,9 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch)
break;
case htons(ETH_P_IPV6):
- if (skb_cow_head(skb, sizeof(struct ipv6hdr)))
+ wlen += sizeof(struct ipv6hdr);
+ if (!pskb_may_pull(skb, wlen) ||
+ skb_try_make_writable(skb, wlen))
goto drop;
skb->tc_index = ipv6_get_dsfield(ipv6_hdr(skb))