@@ -58,7 +58,7 @@ struct mr6_table {
58
58
struct list_head list ;
59
59
possible_net_t net ;
60
60
u32 id ;
61
- struct sock * mroute6_sk ;
61
+ struct sock __rcu * mroute6_sk ;
62
62
struct timer_list ipmr_expire_timer ;
63
63
struct list_head mfc6_unres_queue ;
64
64
struct list_head mfc6_cache_array [MFC6_LINES ];
@@ -1121,6 +1121,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
1121
1121
static int ip6mr_cache_report (struct mr6_table * mrt , struct sk_buff * pkt ,
1122
1122
mifi_t mifi , int assert )
1123
1123
{
1124
+ struct sock * mroute6_sk ;
1124
1125
struct sk_buff * skb ;
1125
1126
struct mrt6msg * msg ;
1126
1127
int ret ;
@@ -1190,17 +1191,19 @@ static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
1190
1191
skb -> ip_summed = CHECKSUM_UNNECESSARY ;
1191
1192
}
1192
1193
1193
- if (!mrt -> mroute6_sk ) {
1194
+ rcu_read_lock ();
1195
+ mroute6_sk = rcu_dereference (mrt -> mroute6_sk );
1196
+ if (!mroute6_sk ) {
1197
+ rcu_read_unlock ();
1194
1198
kfree_skb (skb );
1195
1199
return - EINVAL ;
1196
1200
}
1197
1201
1198
1202
mrt6msg_netlink_event (mrt , skb );
1199
1203
1200
- /*
1201
- * Deliver to user space multicast routing algorithms
1202
- */
1203
- ret = sock_queue_rcv_skb (mrt -> mroute6_sk , skb );
1204
+ /* Deliver to user space multicast routing algorithms */
1205
+ ret = sock_queue_rcv_skb (mroute6_sk , skb );
1206
+ rcu_read_unlock ();
1204
1207
if (ret < 0 ) {
1205
1208
net_warn_ratelimited ("mroute6: pending queue full, dropping entries\n" );
1206
1209
kfree_skb (skb );
@@ -1584,11 +1587,11 @@ static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
1584
1587
1585
1588
rtnl_lock ();
1586
1589
write_lock_bh (& mrt_lock );
1587
- if (likely (mrt -> mroute6_sk == NULL )) {
1588
- mrt -> mroute6_sk = sk ;
1589
- net -> ipv6 .devconf_all -> mc_forwarding ++ ;
1590
- } else {
1590
+ if (rtnl_dereference (mrt -> mroute6_sk )) {
1591
1591
err = - EADDRINUSE ;
1592
+ } else {
1593
+ rcu_assign_pointer (mrt -> mroute6_sk , sk );
1594
+ net -> ipv6 .devconf_all -> mc_forwarding ++ ;
1592
1595
}
1593
1596
write_unlock_bh (& mrt_lock );
1594
1597
@@ -1614,9 +1617,9 @@ int ip6mr_sk_done(struct sock *sk)
1614
1617
1615
1618
rtnl_lock ();
1616
1619
ip6mr_for_each_table (mrt , net ) {
1617
- if (sk == mrt -> mroute6_sk ) {
1620
+ if (sk == rtnl_dereference ( mrt -> mroute6_sk ) ) {
1618
1621
write_lock_bh (& mrt_lock );
1619
- mrt -> mroute6_sk = NULL ;
1622
+ RCU_INIT_POINTER ( mrt -> mroute6_sk , NULL ) ;
1620
1623
net -> ipv6 .devconf_all -> mc_forwarding -- ;
1621
1624
write_unlock_bh (& mrt_lock );
1622
1625
inet6_netconf_notify_devconf (net , RTM_NEWNETCONF ,
@@ -1630,11 +1633,12 @@ int ip6mr_sk_done(struct sock *sk)
1630
1633
}
1631
1634
}
1632
1635
rtnl_unlock ();
1636
+ synchronize_rcu ();
1633
1637
1634
1638
return err ;
1635
1639
}
1636
1640
1637
- struct sock * mroute6_socket (struct net * net , struct sk_buff * skb )
1641
+ bool mroute6_is_socket (struct net * net , struct sk_buff * skb )
1638
1642
{
1639
1643
struct mr6_table * mrt ;
1640
1644
struct flowi6 fl6 = {
@@ -1646,8 +1650,9 @@ struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
1646
1650
if (ip6mr_fib_lookup (net , & fl6 , & mrt ) < 0 )
1647
1651
return NULL ;
1648
1652
1649
- return mrt -> mroute6_sk ;
1653
+ return rcu_access_pointer ( mrt -> mroute6_sk ) ;
1650
1654
}
1655
+ EXPORT_SYMBOL (mroute6_is_socket );
1651
1656
1652
1657
/*
1653
1658
* Socket options and virtual interface manipulation. The whole
@@ -1674,7 +1679,8 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1674
1679
return - ENOENT ;
1675
1680
1676
1681
if (optname != MRT6_INIT ) {
1677
- if (sk != mrt -> mroute6_sk && !ns_capable (net -> user_ns , CAP_NET_ADMIN ))
1682
+ if (sk != rcu_access_pointer (mrt -> mroute6_sk ) &&
1683
+ !ns_capable (net -> user_ns , CAP_NET_ADMIN ))
1678
1684
return - EACCES ;
1679
1685
}
1680
1686
@@ -1696,7 +1702,8 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1696
1702
if (vif .mif6c_mifi >= MAXMIFS )
1697
1703
return - ENFILE ;
1698
1704
rtnl_lock ();
1699
- ret = mif6_add (net , mrt , & vif , sk == mrt -> mroute6_sk );
1705
+ ret = mif6_add (net , mrt , & vif ,
1706
+ sk == rtnl_dereference (mrt -> mroute6_sk ));
1700
1707
rtnl_unlock ();
1701
1708
return ret ;
1702
1709
@@ -1731,7 +1738,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1731
1738
ret = ip6mr_mfc_delete (mrt , & mfc , parent );
1732
1739
else
1733
1740
ret = ip6mr_mfc_add (net , mrt , & mfc ,
1734
- sk == mrt -> mroute6_sk , parent );
1741
+ sk ==
1742
+ rtnl_dereference (mrt -> mroute6_sk ),
1743
+ parent );
1735
1744
rtnl_unlock ();
1736
1745
return ret ;
1737
1746
@@ -1783,7 +1792,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
1783
1792
/* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
1784
1793
if (v != RT_TABLE_DEFAULT && v >= 100000000 )
1785
1794
return - EINVAL ;
1786
- if (sk == mrt -> mroute6_sk )
1795
+ if (sk == rcu_access_pointer ( mrt -> mroute6_sk ) )
1787
1796
return - EBUSY ;
1788
1797
1789
1798
rtnl_lock ();
0 commit comments