OSDN Git Service

mptcp: avoid lock_fast usage in accept path
authorFlorian Westphal <fw@strlen.de>
Fri, 12 Feb 2021 23:59:59 +0000 (15:59 -0800)
committerDavid S. Miller <davem@davemloft.net>
Sat, 13 Feb 2021 00:31:46 +0000 (16:31 -0800)
Once event support is added this may need to allocate memory while msk
lock is held with softirqs disabled.

Not using lock_fast also allows to do the allocation with GFP_KERNEL.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Mat Martineau <mathew.j.martineau@linux.intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/genetlink.h
net/mptcp/protocol.c
net/netlink/genetlink.c

index e55ec15..7cb3fa8 100644 (file)
@@ -14,6 +14,7 @@
  */
 struct genl_multicast_group {
        char                    name[GENL_NAMSIZ];
+       u8                      flags;
 };
 
 struct genl_ops;
index 56240b8..fe6da1b 100644 (file)
@@ -3260,9 +3260,8 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock,
                struct mptcp_sock *msk = mptcp_sk(newsock->sk);
                struct mptcp_subflow_context *subflow;
                struct sock *newsk = newsock->sk;
-               bool slowpath;
 
-               slowpath = lock_sock_fast(newsk);
+               lock_sock(newsk);
 
                /* PM/worker can now acquire the first subflow socket
                 * lock without racing with listener queue cleanup,
@@ -3288,7 +3287,7 @@ static int mptcp_stream_accept(struct socket *sock, struct socket *newsock,
                        if (!ssk->sk_socket)
                                mptcp_sock_graft(ssk, newsock);
                }
-               unlock_sock_fast(newsk, slowpath);
+               release_sock(newsk);
        }
 
        if (inet_csk_listen_poll(ssock->sk))
index c992424..2d6fdf4 100644 (file)
@@ -1360,11 +1360,43 @@ static struct genl_family genl_ctrl __ro_after_init = {
        .netnsok = true,
 };
 
+static int genl_bind(struct net *net, int group)
+{
+       const struct genl_family *family;
+       unsigned int id;
+       int ret = 0;
+
+       genl_lock_all();
+
+       idr_for_each_entry(&genl_fam_idr, family, id) {
+               const struct genl_multicast_group *grp;
+               int i;
+
+               if (family->n_mcgrps == 0)
+                       continue;
+
+               i = group - family->mcgrp_offset;
+               if (i < 0 || i >= family->n_mcgrps)
+                       continue;
+
+               grp = &family->mcgrps[i];
+               if ((grp->flags & GENL_UNS_ADMIN_PERM) &&
+                   !ns_capable(net->user_ns, CAP_NET_ADMIN))
+                       ret = -EPERM;
+
+               break;
+       }
+
+       genl_unlock_all();
+       return ret;
+}
+
 static int __net_init genl_pernet_init(struct net *net)
 {
        struct netlink_kernel_cfg cfg = {
                .input          = genl_rcv,
                .flags          = NL_CFG_F_NONROOT_RECV,
+               .bind           = genl_bind,
        };
 
        /* we'll bump the group number right afterwards */