Syzbot found a kernel bug in the ipv6 stack: LINK: https://syzkaller.appspot.com/bug?id=205d6f11d72329ab8d62a610c44c5e7e2541558... The reproducer triggers it by sending a crafted message via sendmmsg() call, which triggers skb_over_panic, and crashes the kernel:
skbuff: skb_over_panic: text:ffffffff84647fb4 len:65575 put:65575 head:ffff888109ff0000 data:ffff888109ff0088 tail:0x100af end:0xfec0 dev:<NULL>
Add a check that prevents an invalid packet with MTU equall to the fregment header size to eat up all the space for payload.
The reproducer can be found here: LINK: https://syzkaller.appspot.com/text?tag=ReproC&x=1648c83fb00000
Cc: Willem de Bruijn willemdebruijn.kernel@gmail.com Cc: David S. Miller davem@davemloft.net Cc: Hideaki YOSHIFUJI yoshfuji@linux-ipv6.org Cc: David Ahern dsahern@kernel.org Cc: Jakub Kicinski kuba@kernel.org Cc: Alexei Starovoitov ast@kernel.org Cc: Daniel Borkmann daniel@iogearbox.net Cc: Andrii Nakryiko andrii@kernel.org Cc: Martin KaFai Lau kafai@fb.com Cc: Song Liu songliubraving@fb.com Cc: Yonghong Song yhs@fb.com Cc: John Fastabend john.fastabend@gmail.com Cc: KP Singh kpsingh@kernel.org Cc: netdev@vger.kernel.org Cc: bpf@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org
Reported-by: syzbot+e223cf47ec8ae183f2a0@syzkaller.appspotmail.com Signed-off-by: Tadeusz Struk tadeusz.struk@linaro.org --- v2: Instead of updating the alloclen add a check that prevents an invalid packet with MTU equall to the fregment header size to eat up all the space for payload. Fix suggested by Willem de Bruijn willemdebruijn.kernel@gmail.com --- net/ipv6/ip6_output.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 4788f6b37053..6d45112322a0 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1649,6 +1649,16 @@ static int __ip6_append_data(struct sock *sk, skb->protocol = htons(ETH_P_IPV6); skb->ip_summed = csummode; skb->csum = 0; + + /* + * Check if there is still room for payload + */ + if (fragheaderlen >= mtu) { + err = -EMSGSIZE; + kfree_skb(skb); + goto error; + } + /* reserve for fragmentation and ipsec header */ skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + dst_exthdrlen);