crypto: user - make NETLINK_CRYPTO work inside netns
authorOndrej Mosnacek <omosnace@redhat.com>
Tue, 9 Jul 2019 11:11:24 +0000 (13:11 +0200)
committerHerbert Xu <herbert@gondor.apana.org.au>
Fri, 26 Jul 2019 12:08:02 +0000 (22:08 +1000)
Currently, NETLINK_CRYPTO works only in the init network namespace. It
doesn't make much sense to cut it out of the other network namespaces,
so do the minor plumbing work necessary to make it work in any network
namespace. Code inspired by net/core/sock_diag.c.

Tested using kcapi-dgst from libkcapi [1]:
Before:
    # unshare -n kcapi-dgst -c sha256 </dev/null | wc -c
    libkcapi - Error: Netlink error: sendmsg failed
    libkcapi - Error: Netlink error: sendmsg failed
    libkcapi - Error: NETLINK_CRYPTO: cannot obtain cipher information for hmac(sha512) (is required crypto_user.c patch missing? see documentation)
    0

After:
    # unshare -n kcapi-dgst -c sha256 </dev/null | wc -c
    32

[1] https://github.com/smuellerDD/libkcapi

Signed-off-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/crypto_user_base.c
crypto/crypto_user_stat.c
include/crypto/internal/cryptouser.h
include/net/net_namespace.h

index c65e39005ce2a3268270eedeb9fd8289aa49efef..910e0b46012e37e8097f6578e2a305ddfc75a9b7 100644 (file)
 #include <linux/crypto.h>
 #include <linux/cryptouser.h>
 #include <linux/sched.h>
-#include <net/netlink.h>
 #include <linux/security.h>
+#include <net/netlink.h>
 #include <net/net_namespace.h>
+#include <net/sock.h>
 #include <crypto/internal/skcipher.h>
 #include <crypto/internal/rng.h>
 #include <crypto/akcipher.h>
@@ -25,9 +26,6 @@
 
 static DEFINE_MUTEX(crypto_cfg_mutex);
 
-/* The crypto netlink socket */
-struct sock *crypto_nlsk;
-
 struct crypto_dump_info {
        struct sk_buff *in_skb;
        struct sk_buff *out_skb;
@@ -186,6 +184,7 @@ out:
 static int crypto_report(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
                         struct nlattr **attrs)
 {
+       struct net *net = sock_net(in_skb->sk);
        struct crypto_user_alg *p = nlmsg_data(in_nlh);
        struct crypto_alg *alg;
        struct sk_buff *skb;
@@ -217,7 +216,7 @@ drop_alg:
        if (err)
                return err;
 
-       return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
+       return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
 }
 
 static int crypto_dump_report(struct sk_buff *skb, struct netlink_callback *cb)
@@ -420,6 +419,7 @@ static const struct crypto_link {
 static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
                               struct netlink_ext_ack *extack)
 {
+       struct net *net = sock_net(skb->sk);
        struct nlattr *attrs[CRYPTOCFGA_MAX+1];
        const struct crypto_link *link;
        int type, err;
@@ -450,7 +450,7 @@ static int crypto_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
                                .done = link->done,
                                .min_dump_alloc = min(dump_alloc, 65535UL),
                        };
-                       err = netlink_dump_start(crypto_nlsk, skb, nlh, &c);
+                       err = netlink_dump_start(net->crypto_nlsk, skb, nlh, &c);
                }
 
                return err;
@@ -474,22 +474,35 @@ static void crypto_netlink_rcv(struct sk_buff *skb)
        mutex_unlock(&crypto_cfg_mutex);
 }
 
-static int __init crypto_user_init(void)
+static int __net_init crypto_netlink_init(struct net *net)
 {
        struct netlink_kernel_cfg cfg = {
                .input  = crypto_netlink_rcv,
        };
 
-       crypto_nlsk = netlink_kernel_create(&init_net, NETLINK_CRYPTO, &cfg);
-       if (!crypto_nlsk)
-               return -ENOMEM;
+       net->crypto_nlsk = netlink_kernel_create(net, NETLINK_CRYPTO, &cfg);
+       return net->crypto_nlsk == NULL ? -ENOMEM : 0;
+}
 
-       return 0;
+static void __net_exit crypto_netlink_exit(struct net *net)
+{
+       netlink_kernel_release(net->crypto_nlsk);
+       net->crypto_nlsk = NULL;
+}
+
+static struct pernet_operations crypto_netlink_net_ops = {
+       .init = crypto_netlink_init,
+       .exit = crypto_netlink_exit,
+};
+
+static int __init crypto_user_init(void)
+{
+       return register_pernet_subsys(&crypto_netlink_net_ops);
 }
 
 static void __exit crypto_user_exit(void)
 {
-       netlink_kernel_release(crypto_nlsk);
+       unregister_pernet_subsys(&crypto_netlink_net_ops);
 }
 
 module_init(crypto_user_init);
index a03f326a63d32a15536fe9a570843082288f7c0b..8bad88413de163e831edc3beb374fed74a3d4dd8 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/cryptouser.h>
 #include <linux/sched.h>
 #include <net/netlink.h>
+#include <net/sock.h>
 #include <crypto/internal/skcipher.h>
 #include <crypto/internal/rng.h>
 #include <crypto/akcipher.h>
@@ -298,6 +299,7 @@ out:
 int crypto_reportstat(struct sk_buff *in_skb, struct nlmsghdr *in_nlh,
                      struct nlattr **attrs)
 {
+       struct net *net = sock_net(in_skb->sk);
        struct crypto_user_alg *p = nlmsg_data(in_nlh);
        struct crypto_alg *alg;
        struct sk_buff *skb;
@@ -329,7 +331,7 @@ drop_alg:
        if (err)
                return err;
 
-       return nlmsg_unicast(crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
+       return nlmsg_unicast(net->crypto_nlsk, skb, NETLINK_CB(in_skb).portid);
 }
 
 MODULE_LICENSE("GPL");
index 8c602b187c58ae17086b367c08139abb5b90010f..40623f4457df66f7971ce1aa68fdc0ee224bc570 100644 (file)
@@ -1,8 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #include <net/netlink.h>
 
-extern struct sock *crypto_nlsk;
-
 struct crypto_alg *crypto_alg_match(struct crypto_user_alg *p, int exact);
 
 #ifdef CONFIG_CRYPTO_STATS
index 4a9da951a794efbf9183c0a2e3d3ca94ec88f9d5..85bc1de5decec1199ef3d30795f3bdfcba029578 100644 (file)
@@ -170,6 +170,9 @@ struct net {
 #endif
 #ifdef CONFIG_XDP_SOCKETS
        struct netns_xdp        xdp;
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_USER)
+       struct sock             *crypto_nlsk;
 #endif
        struct sock             *diag_nlsk;
        atomic_t                fnhe_genid;