aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJakub Kicinski <jakub.kicinski@netronome.com>2019-10-18 12:16:57 -0400
committerDavid S. Miller <davem@davemloft.net>2019-10-19 15:12:35 -0400
commita7fa12d15855904aff1716e1fc723c03ba38c5cc (patch)
tree6e498c1ecc9037df177701ac780e2d5d65b9e82d /net
parentbd310aca442fcc72731b7acb65d32d05c956d56b (diff)
net: netem: fix error path for corrupted GSO frames
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>
Diffstat (limited to 'net')
-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 0e44039e729c..942eb17f413c 100644
--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -509,6 +509,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
509 if (skb->ip_summed == CHECKSUM_PARTIAL && 509 if (skb->ip_summed == CHECKSUM_PARTIAL &&
510 skb_checksum_help(skb)) { 510 skb_checksum_help(skb)) {
511 qdisc_drop(skb, sch, to_free); 511 qdisc_drop(skb, sch, to_free);
512 skb = NULL;
512 goto finish_segs; 513 goto finish_segs;
513 } 514 }
514 515
@@ -593,9 +594,10 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,
593finish_segs: 594finish_segs:
594 if (segs) { 595 if (segs) {
595 unsigned int len, last_len; 596 unsigned int len, last_len;
596 int nb = 0; 597 int nb;
597 598
598 len = skb->len; 599 len = skb ? skb->len : 0;
600 nb = skb ? 1 : 0;
599 601
600 while (segs) { 602 while (segs) {
601 skb2 = segs->next; 603 skb2 = segs->next;
@@ -612,7 +614,8 @@ finish_segs:
612 } 614 }
613 segs = skb2; 615 segs = skb2;
614 } 616 }
615 qdisc_tree_reduce_backlog(sch, -nb, prev_len - len); 617 /* Parent qdiscs accounted for 1 skb of size @prev_len */
618 qdisc_tree_reduce_backlog(sch, -(nb - 1), -(len - prev_len));
616 } 619 }
617 return NET_XMIT_SUCCESS; 620 return NET_XMIT_SUCCESS;
618} 621}