| From b8e33541f524eb6e6b27983ebd8b38917f0240b8 Mon Sep 17 00:00:00 2001 |
| From: Taras Chornyi <taras.chornyi@plvision.eu> |
| Date: Thu, 9 Apr 2020 20:25:24 +0300 |
| Subject: [PATCH] net: ipv4: devinet: Fix crash when add/del multicast IP with |
| autojoin |
| |
| commit 690cc86321eb9bcee371710252742fb16fe96824 upstream. |
| |
| 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> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c |
| index af0c3ea78c45..e931efcadf5f 100644 |
| --- a/net/ipv4/devinet.c |
| +++ b/net/ipv4/devinet.c |
| @@ -593,12 +593,15 @@ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, |
| return NULL; |
| } |
| |
| -static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa) |
| +static int ip_mc_autojoin_config(struct net *net, bool join, |
| + const struct in_ifaddr *ifa) |
| { |
| +#if defined(CONFIG_IP_MULTICAST) |
| struct ip_mreqn mreq = { |
| .imr_multiaddr.s_addr = ifa->ifa_address, |
| .imr_ifindex = ifa->ifa_dev->dev->ifindex, |
| }; |
| + struct sock *sk = net->ipv4.mc_autojoin_sk; |
| int ret; |
| |
| ASSERT_RTNL(); |
| @@ -611,6 +614,9 @@ static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa) |
| release_sock(sk); |
| |
| return ret; |
| +#else |
| + return -EOPNOTSUPP; |
| +#endif |
| } |
| |
| static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, |
| @@ -652,7 +658,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, |
| continue; |
| |
| if (ipv4_is_multicast(ifa->ifa_address)) |
| - ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa); |
| + ip_mc_autojoin_config(net, false, ifa); |
| __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid); |
| return 0; |
| } |
| @@ -914,8 +920,7 @@ static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, |
| */ |
| set_ifa_lifetime(ifa, valid_lft, prefered_lft); |
| if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) { |
| - int ret = ip_mc_config(net->ipv4.mc_autojoin_sk, |
| - true, ifa); |
| + int ret = ip_mc_autojoin_config(net, true, ifa); |
| |
| if (ret < 0) { |
| inet_free_ifa(ifa); |
| -- |
| 2.7.4 |
| |