]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
ipmr: fix tables suspicious RCU usage
authorPaolo Abeni <pabeni@redhat.com>
Sun, 24 Nov 2024 15:40:58 +0000 (16:40 +0100)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 28 Nov 2024 09:23:23 +0000 (10:23 +0100)
Similar to the previous patch, plumb the RCU lock inside
the ipmr_get_table(), provided a lockless variant and apply
the latter in the few spots were the lock is already held.

Fixes: 709b46e8d90b ("net: Add compat ioctl support for the ipv4 multicast ioctl SIOCGETSGCNT")
Fixes: f0ad0860d01e ("ipv4: ipmr: support multiple tables")
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
net/ipv4/ipmr.c

index bac0776648e09946aadb74aa0ac1e5a0c051ff68..383ea8b91cc78c17b1d68a801c2e0d0dbebcfe17 100644 (file)
@@ -142,7 +142,7 @@ static struct mr_table *ipmr_mr_table_iter(struct net *net,
        return ret;
 }
 
-static struct mr_table *ipmr_get_table(struct net *net, u32 id)
+static struct mr_table *__ipmr_get_table(struct net *net, u32 id)
 {
        struct mr_table *mrt;
 
@@ -153,6 +153,16 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)
        return NULL;
 }
 
+static struct mr_table *ipmr_get_table(struct net *net, u32 id)
+{
+       struct mr_table *mrt;
+
+       rcu_read_lock();
+       mrt = __ipmr_get_table(net, id);
+       rcu_read_unlock();
+       return mrt;
+}
+
 static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
                           struct mr_table **mrt)
 {
@@ -194,7 +204,7 @@ static int ipmr_rule_action(struct fib_rule *rule, struct flowi *flp,
 
        arg->table = fib_rule_get_table(rule, arg);
 
-       mrt = ipmr_get_table(rule->fr_net, arg->table);
+       mrt = __ipmr_get_table(rule->fr_net, arg->table);
        if (!mrt)
                return -EAGAIN;
        res->mrt = mrt;
@@ -325,6 +335,8 @@ static struct mr_table *ipmr_get_table(struct net *net, u32 id)
        return net->ipv4.mrt;
 }
 
+#define __ipmr_get_table ipmr_get_table
+
 static int ipmr_fib_lookup(struct net *net, struct flowi4 *flp4,
                           struct mr_table **mrt)
 {
@@ -413,7 +425,7 @@ static struct mr_table *ipmr_new_table(struct net *net, u32 id)
        if (id != RT_TABLE_DEFAULT && id >= 1000000000)
                return ERR_PTR(-EINVAL);
 
-       mrt = ipmr_get_table(net, id);
+       mrt = __ipmr_get_table(net, id);
        if (mrt)
                return mrt;
 
@@ -1388,7 +1400,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, sockptr_t optval,
                goto out_unlock;
        }
 
-       mrt = ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
+       mrt = __ipmr_get_table(net, raw_sk(sk)->ipmr_table ? : RT_TABLE_DEFAULT);
        if (!mrt) {
                ret = -ENOENT;
                goto out_unlock;
@@ -2276,11 +2288,13 @@ int ipmr_get_route(struct net *net, struct sk_buff *skb,
        struct mr_table *mrt;
        int err;
 
-       mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
-       if (!mrt)
+       rcu_read_lock();
+       mrt = __ipmr_get_table(net, RT_TABLE_DEFAULT);
+       if (!mrt) {
+               rcu_read_unlock();
                return -ENOENT;
+       }
 
-       rcu_read_lock();
        cache = ipmr_cache_find(mrt, saddr, daddr);
        if (!cache && skb->dev) {
                int vif = ipmr_find_vif(mrt, skb->dev);
@@ -2564,7 +2578,7 @@ static int ipmr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh,
        grp = nla_get_in_addr_default(tb[RTA_DST], 0);
        tableid = nla_get_u32_default(tb[RTA_TABLE], 0);
 
-       mrt = ipmr_get_table(net, tableid ? tableid : RT_TABLE_DEFAULT);
+       mrt = __ipmr_get_table(net, tableid ? tableid : RT_TABLE_DEFAULT);
        if (!mrt) {
                err = -ENOENT;
                goto errout_free;
@@ -2618,7 +2632,7 @@ static int ipmr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
        if (filter.table_id) {
                struct mr_table *mrt;
 
-               mrt = ipmr_get_table(sock_net(skb->sk), filter.table_id);
+               mrt = __ipmr_get_table(sock_net(skb->sk), filter.table_id);
                if (!mrt) {
                        if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IPMR)
                                return skb->len;
@@ -2726,7 +2740,7 @@ static int rtm_to_ipmr_mfcc(struct net *net, struct nlmsghdr *nlh,
                        break;
                }
        }
-       mrt = ipmr_get_table(net, tblid);
+       mrt = __ipmr_get_table(net, tblid);
        if (!mrt) {
                ret = -ENOENT;
                goto out;
@@ -2934,13 +2948,15 @@ static void *ipmr_vif_seq_start(struct seq_file *seq, loff_t *pos)
        struct net *net = seq_file_net(seq);
        struct mr_table *mrt;
 
-       mrt = ipmr_get_table(net, RT_TABLE_DEFAULT);
-       if (!mrt)
+       rcu_read_lock();
+       mrt = __ipmr_get_table(net, RT_TABLE_DEFAULT);
+       if (!mrt) {
+               rcu_read_unlock();
                return ERR_PTR(-ENOENT);
+       }
 
        iter->mrt = mrt;
 
-       rcu_read_lock();
        return mr_vif_seq_start(seq, pos);
 }