ip6_mc_msfget() should be called under RTNL because it accesses RTNL
protected data. but the caller doesn't acquire rtnl_lock().
So, data couldn't be protected.
Therefore, it adds rtnl_lock() in do_ipv6_getsockopt(),
which is the caller of ip6_mc_msfget().

Splat looks like:
=============================
WARNING: suspicious RCU usage
5.12.0-rc4+ #480 Tainted: G        W
-----------------------------
include/net/addrconf.h:314 suspicious rcu_dereference_check() usage!

other info that might help us debug this:

rcu_scheduler_active = 2, debug_locks = 1
1 lock held by sockopt_msfilte/4955:
 #0: ffff88800aa21370 (sk_lock-AF_INET6){+.+.}-{0:0}, at: \
        ipv6_get_msfilter+0xaf/0x190

stack backtrace:
Call Trace:
 dump_stack+0xa4/0xe5
 ip6_mc_find_dev_rtnl+0x117/0x150
 ip6_mc_msfget+0x17d/0x700
 ? lock_acquire+0x191/0x720
 ? ipv6_sock_mc_join_ssm+0x10/0x10
 ? lockdep_hardirqs_on_prepare+0x3e0/0x3e0
 ? mark_held_locks+0xb7/0x120
 ? lockdep_hardirqs_on_prepare+0x27c/0x3e0
 ? __local_bh_enable_ip+0xa5/0xf0
 ? lock_sock_nested+0x82/0xf0
 ipv6_get_msfilter+0xc3/0x190
 ? compat_ipv6_get_msfilter+0x300/0x300
 ? lock_downgrade+0x690/0x690
 do_ipv6_getsockopt.isra.6.constprop.13+0x1706/0x29f0
 ? do_ipv6_mcast_group_source+0x150/0x150
 ? __wake_up_common+0x620/0x620
 ? mutex_trylock+0x23f/0x2a0
[ ... ]

Fixes: 88e2ca308094 ("mld: convert ifmcaddr6 to RCU")
Reported-by: Eric Dumazet <eduma...@google.com>
Signed-off-by: Taehee Yoo <ap420...@gmail.com>
---

commit 88e2ca308094 ("mld: convert ifmcaddr6 to RCU") is not yet merged
to "net" branch. So, target branch is "net-next"

 net/ipv6/ipv6_sockglue.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index a6804a7e34c1..55dc35e09c68 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -1137,9 +1137,12 @@ static int do_ipv6_getsockopt(struct sock *sk, int 
level, int optname,
                val = sk->sk_family;
                break;
        case MCAST_MSFILTER:
+               rtnl_lock();
                if (in_compat_syscall())
-                       return compat_ipv6_get_msfilter(sk, optval, optlen);
-               return ipv6_get_msfilter(sk, optval, optlen, len);
+                       val = compat_ipv6_get_msfilter(sk, optval, optlen);
+               val = ipv6_get_msfilter(sk, optval, optlen, len);
+               rtnl_unlock();
+               return val;
        case IPV6_2292PKTOPTIONS:
        {
                struct msghdr msg;
-- 
2.17.1

Reply via email to