The packet corruption code only flipped bits in the linear header portion of the skb, skipping corruption when skb_headlen() was zero. Linearize the whole skb if necessary before corruption. That step also makes calling skb_unshare() unnecessary. Extends d64cb81dcbd5 ("net/sched: sch_netem: fix out-of-bounds access in packet corruption") with a more general solution. Signed-off-by: Stephen Hemminger --- net/sched/sch_netem.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 53bdfa77ee2d..020dbfb6e4a7 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -508,21 +508,17 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch, qdisc_skb_cb(skb)->pkt_len = skb->len; } - skb = skb_unshare(skb, GFP_ATOMIC); - if (unlikely(!skb)) { - qdisc_qstats_drop(sch); - goto finish_segs; - } - if (skb->ip_summed == CHECKSUM_PARTIAL && - skb_checksum_help(skb)) { + if (skb_linearize(skb) || + (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))) { qdisc_drop(skb, sch, to_free); skb = NULL; goto finish_segs; } - if (skb_headlen(skb)) - skb->data[get_random_u32_below(skb_headlen(skb))] ^= - 1 << get_random_u32_below(8); + if (skb->len) { + u32 offset = get_random_u32_below(skb->len); + skb->data[offset] ^= 1 << get_random_u32_below(8); + } } if (unlikely(sch->q.qlen >= sch->limit)) { -- 2.53.0