[PATCH 3.16 15/25] net: netem: fix error path for corrupted GSO frames

From: Ben Hutchings
Date: Tue Nov 12 2019 - 18:50:56 EST


3.16.77-rc1 review patch. If anyone has any objections, please let me know.

------------------

From: Jakub Kicinski <jakub.kicinski@xxxxxxxxxxxxx>

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@xxxxxxxxx>
Reported-by: Dan Carpenter <dan.carpenter@xxxxxxxxxx>
Reported-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
Signed-off-by: Jakub Kicinski <jakub.kicinski@xxxxxxxxxxxxx>
Reviewed-by: Simon Horman <simon.horman@xxxxxxxxxxxxx>
Signed-off-by: David S. Miller <davem@xxxxxxxxxxxxx>
[bwh: Backported to 3.16: adjust context]
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
---
net/sched/sch_netem.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)

--- a/net/sched/sch_netem.c
+++ b/net/sched/sch_netem.c
@@ -506,6 +506,7 @@ static int netem_enqueue(struct sk_buff
(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
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;
}