summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Kicinski <jakub.kicinski@netronome.com>2019-10-18 09:16:57 -0700
committerBen Hutchings <ben@decadent.org.uk>2019-11-15 00:56:52 +0000
commitf45c7f9120781fcc7e91e5ac5572d78468db299c (patch)
tree8e357af0d6954119609d5dc1b05940add340c4ac
parent5013e6d917ac9f3df823d94d17e9cfe99c003517 (diff)
downloadlinux-stable-f45c7f9120781fcc7e91e5ac5572d78468db299c.tar.gz
linux-stable-f45c7f9120781fcc7e91e5ac5572d78468db299c.tar.bz2
linux-stable-f45c7f9120781fcc7e91e5ac5572d78468db299c.zip
net: netem: fix error path for corrupted GSO frames
commit a7fa12d15855904aff1716e1fc723c03ba38c5cc upstream. To corrupt a GSO frame we first perform segmentation. We then proceed using the first segment instead of the full GSO skb and requeue the rest of the segments as separate packets. If there are any issues with processing the first segment we still want to process the rest, therefore we jump to the finish_segs label. Commit 177b8007463c ("net: netem: fix backlog accounting for corrupted GSO frames") started using the pointer to the first segment in the "rest of segments processing", but as mentioned above the first segment may had already been freed at this point. Backlog corrections for parent qdiscs have to be adjusted. Fixes: 177b8007463c ("net: netem: fix backlog accounting for corrupted GSO frames") Reported-by: kbuild test robot <lkp@intel.com> Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Reported-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> Reviewed-by: Simon Horman <simon.horman@netronome.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>
-rw-r--r--net/sched/sch_netem.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c
index 996b919d82c7..ab8263d97c5b 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -506,6 +506,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
(skb->ip_summed == CHECKSUM_PARTIAL &&
skb_checksum_help(skb))) {
rc = qdisc_drop(skb, sch);
+ skb = NULL;
goto finish_segs;
}
@@ -576,9 +577,10 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
finish_segs:
if (segs) {
unsigned int len, last_len;
- int nb = 0;
+ int nb;
- len = skb->len;
+ len = skb ? skb->len : 0;
+ nb = skb ? 1 : 0;
while (segs) {
skb2 = segs->next;
@@ -595,7 +597,8 @@ finish_segs:
}
segs = skb2;
}
- qdisc_tree_reduce_backlog(sch, -nb, prev_len - len);
+ /* Parent qdiscs accounted for 1 skb of size @prev_len */
+ qdisc_tree_reduce_backlog(sch, -(nb - 1), -(len - prev_len));
}
return NET_XMIT_SUCCESS;
}