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

net: ipv4: devinet: Fix crash when add/del multicast IP with autojoin

When CONFIG_IP_MULTICAST is not set and multicast ip is added to the device
with autojoin flag or when multicast ip is deleted kernel will crash.

steps to reproduce:

ip addr add 224.0.0.0/32 dev eth0
ip addr del 224.0.0.0/32 dev eth0

or

ip addr add 224.0.0.0/32 dev eth0 autojoin

Unable to handle kernel NULL pointer dereference at virtual address 0000000000000088
pc : _raw_write_lock_irqsave+0x1e0/0x2ac
lr : lock_sock_nested+0x1c/0x60
Call trace:
_raw_write_lock_irqsave+0x1e0/0x2ac
lock_sock_nested+0x1c/0x60
ip_mc_config.isra.28+0x50/0xe0
inet_rtm_deladdr+0x1a8/0x1f0
rtnetlink_rcv_msg+0x120/0x350
netlink_rcv_skb+0x58/0x120
rtnetlink_rcv+0x14/0x20
netlink_unicast+0x1b8/0x270
netlink_sendmsg+0x1a0/0x3b0
____sys_sendmsg+0x248/0x290
___sys_sendmsg+0x80/0xc0
__sys_sendmsg+0x68/0xc0
__arm64_sys_sendmsg+0x20/0x30
el0_svc_common.constprop.2+0x88/0x150
do_el0_svc+0x20/0x80
el0_sync_handler+0x118/0x190
el0_sync+0x140/0x180

Fixes: 93a714d6b53d ("multicast: Extend ip address command to enable multicast group join/leave on")
Signed-off-by: Taras Chornyi <taras.chornyi@plvision.eu>
Signed-off-by: Vadym Kochan <vadym.kochan@plvision.eu>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Taras Chornyi and committed by
David S. Miller
690cc863 2fabef4f

+9 -4
+9 -4
net/ipv4/devinet.c
··· 614 614 return NULL; 615 615 } 616 616 617 - static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa) 617 + static int ip_mc_autojoin_config(struct net *net, bool join, 618 + const struct in_ifaddr *ifa) 618 619 { 620 + #if defined(CONFIG_IP_MULTICAST) 619 621 struct ip_mreqn mreq = { 620 622 .imr_multiaddr.s_addr = ifa->ifa_address, 621 623 .imr_ifindex = ifa->ifa_dev->dev->ifindex, 622 624 }; 625 + struct sock *sk = net->ipv4.mc_autojoin_sk; 623 626 int ret; 624 627 625 628 ASSERT_RTNL(); ··· 635 632 release_sock(sk); 636 633 637 634 return ret; 635 + #else 636 + return -EOPNOTSUPP; 637 + #endif 638 638 } 639 639 640 640 static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, ··· 681 675 continue; 682 676 683 677 if (ipv4_is_multicast(ifa->ifa_address)) 684 - ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa); 678 + ip_mc_autojoin_config(net, false, ifa); 685 679 __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid); 686 680 return 0; 687 681 } ··· 946 940 */ 947 941 set_ifa_lifetime(ifa, valid_lft, prefered_lft); 948 942 if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) { 949 - int ret = ip_mc_config(net->ipv4.mc_autojoin_sk, 950 - true, ifa); 943 + int ret = ip_mc_autojoin_config(net, true, ifa); 951 944 952 945 if (ret < 0) { 953 946 inet_free_ifa(ifa);