Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ipv6: mcast: better catch silly mtu values

syzkaller reported crashes in IPv6 stack [1]

Xin Long found that lo MTU was set to silly values.

IPv6 stack reacts to changes to small MTU, by disabling itself under
RTNL.

But there is a window where threads not using RTNL can see a wrong
device mtu. This can lead to surprises, in mld code where it is assumed
the mtu is suitable.

Fix this by reading device mtu once and checking IPv6 minimal MTU.

[1]
skbuff: skb_over_panic: text:0000000010b86b8d len:196 put:20
head:000000003b477e60 data:000000000e85441e tail:0xd4 end:0xc0 dev:lo
------------[ cut here ]------------
kernel BUG at net/core/skbuff.c:104!
invalid opcode: 0000 [#1] SMP KASAN
Dumping ftrace buffer:
(ftrace buffer empty)
Modules linked in:
CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.15.0-rc2-mm1+ #39
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS
Google 01/01/2011
RIP: 0010:skb_panic+0x15c/0x1f0 net/core/skbuff.c:100
RSP: 0018:ffff8801db307508 EFLAGS: 00010286
RAX: 0000000000000082 RBX: ffff8801c517e840 RCX: 0000000000000000
RDX: 0000000000000082 RSI: 1ffff1003b660e61 RDI: ffffed003b660e95
RBP: ffff8801db307570 R08: 1ffff1003b660e23 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000000 R12: ffffffff85bd4020
R13: ffffffff84754ed2 R14: 0000000000000014 R15: ffff8801c4e26540
FS: 0000000000000000(0000) GS:ffff8801db300000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000463610 CR3: 00000001c6698000 CR4: 00000000001406e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
<IRQ>
skb_over_panic net/core/skbuff.c:109 [inline]
skb_put+0x181/0x1c0 net/core/skbuff.c:1694
add_grhead.isra.24+0x42/0x3b0 net/ipv6/mcast.c:1695
add_grec+0xa55/0x1060 net/ipv6/mcast.c:1817
mld_send_cr net/ipv6/mcast.c:1903 [inline]
mld_ifc_timer_expire+0x4d2/0x770 net/ipv6/mcast.c:2448
call_timer_fn+0x23b/0x840 kernel/time/timer.c:1320
expire_timers kernel/time/timer.c:1357 [inline]
__run_timers+0x7e1/0xb60 kernel/time/timer.c:1660
run_timer_softirq+0x4c/0xb0 kernel/time/timer.c:1686
__do_softirq+0x29d/0xbb2 kernel/softirq.c:285
invoke_softirq kernel/softirq.c:365 [inline]
irq_exit+0x1d3/0x210 kernel/softirq.c:405
exiting_irq arch/x86/include/asm/apic.h:540 [inline]
smp_apic_timer_interrupt+0x16b/0x700 arch/x86/kernel/apic/apic.c:1052
apic_timer_interrupt+0xa9/0xb0 arch/x86/entry/entry_64.S:920

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: syzbot <syzkaller@googlegroups.com>
Tested-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
b9b312a7 6b782f43

+15 -10
+15 -10
net/ipv6/mcast.c
··· 1682 1682 } 1683 1683 1684 1684 static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc, 1685 - int type, struct mld2_grec **ppgr) 1685 + int type, struct mld2_grec **ppgr, unsigned int mtu) 1686 1686 { 1687 - struct net_device *dev = pmc->idev->dev; 1688 1687 struct mld2_report *pmr; 1689 1688 struct mld2_grec *pgr; 1690 1689 1691 - if (!skb) 1692 - skb = mld_newpack(pmc->idev, dev->mtu); 1693 - if (!skb) 1694 - return NULL; 1690 + if (!skb) { 1691 + skb = mld_newpack(pmc->idev, mtu); 1692 + if (!skb) 1693 + return NULL; 1694 + } 1695 1695 pgr = skb_put(skb, sizeof(struct mld2_grec)); 1696 1696 pgr->grec_type = type; 1697 1697 pgr->grec_auxwords = 0; ··· 1714 1714 struct mld2_grec *pgr = NULL; 1715 1715 struct ip6_sf_list *psf, *psf_next, *psf_prev, **psf_list; 1716 1716 int scount, stotal, first, isquery, truncate; 1717 + unsigned int mtu; 1717 1718 1718 1719 if (pmc->mca_flags & MAF_NOREPORT) 1720 + return skb; 1721 + 1722 + mtu = READ_ONCE(dev->mtu); 1723 + if (mtu < IPV6_MIN_MTU) 1719 1724 return skb; 1720 1725 1721 1726 isquery = type == MLD2_MODE_IS_INCLUDE || ··· 1743 1738 AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { 1744 1739 if (skb) 1745 1740 mld_sendpack(skb); 1746 - skb = mld_newpack(idev, dev->mtu); 1741 + skb = mld_newpack(idev, mtu); 1747 1742 } 1748 1743 } 1749 1744 first = 1; ··· 1779 1774 pgr->grec_nsrcs = htons(scount); 1780 1775 if (skb) 1781 1776 mld_sendpack(skb); 1782 - skb = mld_newpack(idev, dev->mtu); 1777 + skb = mld_newpack(idev, mtu); 1783 1778 first = 1; 1784 1779 scount = 0; 1785 1780 } 1786 1781 if (first) { 1787 - skb = add_grhead(skb, pmc, type, &pgr); 1782 + skb = add_grhead(skb, pmc, type, &pgr, mtu); 1788 1783 first = 0; 1789 1784 } 1790 1785 if (!skb) ··· 1819 1814 mld_sendpack(skb); 1820 1815 skb = NULL; /* add_grhead will get a new one */ 1821 1816 } 1822 - skb = add_grhead(skb, pmc, type, &pgr); 1817 + skb = add_grhead(skb, pmc, type, &pgr, mtu); 1823 1818 } 1824 1819 } 1825 1820 if (pgr)