| From 3f6a1a4a0413901b83aa03dcf8843308fc6aebcc Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 18 Oct 2019 09:16:57 -0700 |
| Subject: net: netem: fix error path for corrupted GSO frames |
| |
| From: Jakub Kicinski <jakub.kicinski@netronome.com> |
| |
| [ Upstream commit a7fa12d15855904aff1716e1fc723c03ba38c5cc ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| net/sched/sch_netem.c | 9 ++++++--- |
| 1 file changed, 6 insertions(+), 3 deletions(-) |
| |
| diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c |
| index 308d92491757e..11c4c93f5ded7 100644 |
| --- a/net/sched/sch_netem.c |
| +++ b/net/sched/sch_netem.c |
| @@ -510,6 +510,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, |
| if (skb->ip_summed == CHECKSUM_PARTIAL && |
| skb_checksum_help(skb)) { |
| qdisc_drop(skb, sch, to_free); |
| + skb = NULL; |
| goto finish_segs; |
| } |
| |
| @@ -586,9 +587,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; |
| @@ -605,7 +607,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; |
| } |
| -- |
| 2.20.1 |
| |