rxrpc: Absorb the rxkad security module
authorDavid Howells <dhowells@redhat.com>
Thu, 7 Apr 2016 16:23:51 +0000 (17:23 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 11 Apr 2016 19:34:41 +0000 (15:34 -0400)
Absorb the rxkad security module into the af_rxrpc module so that there's
only one module file.  This avoids a circular dependency whereby rxkad pins
af_rxrpc and cached connections pin rxkad but can't be manually evicted
(they will expire eventually and cease pinning).

With this change, af_rxrpc can just be unloaded, despite having cached
connections.

Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/rxrpc/Kconfig
net/rxrpc/Makefile
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-internal.h
net/rxrpc/ar-security.c
net/rxrpc/rxkad.c

index 23dcef12b986dcd5774147b5ed215ff2fa62cb50..784c53163b7b045ac8c98c60da8e227886a40d85 100644 (file)
@@ -30,7 +30,7 @@ config AF_RXRPC_DEBUG
 
 
 config RXKAD
-       tristate "RxRPC Kerberos security"
+       bool "RxRPC Kerberos security"
        depends on AF_RXRPC
        select CRYPTO
        select CRYPTO_MANAGER
index 5b98c1640d6d9a3a23e825cd1c324b335c831956..fa09cb55bfce7a298baf35468b8adde217cee01a 100644 (file)
@@ -22,8 +22,7 @@ af-rxrpc-y := \
        misc.o
 
 af-rxrpc-$(CONFIG_PROC_FS) += ar-proc.o
+af-rxrpc-$(CONFIG_RXKAD) += rxkad.o
 af-rxrpc-$(CONFIG_SYSCTL) += sysctl.o
 
 obj-$(CONFIG_AF_RXRPC) += af-rxrpc.o
-
-obj-$(CONFIG_RXKAD) += rxkad.o
index 9d935fa5a2a98884beca08329433cf66dbafebdc..e45e94ca030f3b1e3a6881d3178b021b4ce670ad 100644 (file)
@@ -806,6 +806,12 @@ static int __init af_rxrpc_init(void)
                goto error_work_queue;
        }
 
+       ret = rxrpc_init_security();
+       if (ret < 0) {
+               printk(KERN_CRIT "RxRPC: Cannot initialise security\n");
+               goto error_security;
+       }
+
        ret = proto_register(&rxrpc_proto, 1);
        if (ret < 0) {
                printk(KERN_CRIT "RxRPC: Cannot register protocol\n");
@@ -853,6 +859,8 @@ error_sock:
        proto_unregister(&rxrpc_proto);
 error_proto:
        destroy_workqueue(rxrpc_workqueue);
+error_security:
+       rxrpc_exit_security();
 error_work_queue:
        kmem_cache_destroy(rxrpc_call_jar);
 error_call_jar:
@@ -883,6 +891,7 @@ static void __exit af_rxrpc_exit(void)
        remove_proc_entry("rxrpc_conns", init_net.proc_net);
        remove_proc_entry("rxrpc_calls", init_net.proc_net);
        destroy_workqueue(rxrpc_workqueue);
+       rxrpc_exit_security();
        kmem_cache_destroy(rxrpc_call_jar);
        _leave("");
 }
index d38071b09f7220b09cc0aa706883e4729629883c..72fd675a891ef1b758d87901d48a80722fe596a7 100644 (file)
@@ -124,11 +124,15 @@ enum rxrpc_command {
  * RxRPC security module interface
  */
 struct rxrpc_security {
-       struct module           *owner;         /* providing module */
-       struct list_head        link;           /* link in master list */
        const char              *name;          /* name of this service */
        u8                      security_index; /* security type provided */
 
+       /* Initialise a security service */
+       int (*init)(void);
+
+       /* Clean up a security service */
+       void (*exit)(void);
+
        /* initialise a connection's security */
        int (*init_connection_security)(struct rxrpc_connection *);
 
@@ -268,7 +272,7 @@ struct rxrpc_connection {
        struct rb_root          calls;          /* calls on this connection */
        struct sk_buff_head     rx_queue;       /* received conn-level packets */
        struct rxrpc_call       *channels[RXRPC_MAXCALLS]; /* channels (active calls) */
-       struct rxrpc_security   *security;      /* applied security module */
+       const struct rxrpc_security *security;  /* applied security module */
        struct key              *key;           /* security for this connection (client) */
        struct key              *server_key;    /* security for this service */
        struct crypto_skcipher  *cipher;        /* encryption handle */
@@ -604,8 +608,8 @@ int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);
 /*
  * ar-security.c
  */
-int rxrpc_register_security(struct rxrpc_security *);
-void rxrpc_unregister_security(struct rxrpc_security *);
+int __init rxrpc_init_security(void);
+void rxrpc_exit_security(void);
 int rxrpc_init_client_conn_security(struct rxrpc_connection *);
 int rxrpc_init_server_conn_security(struct rxrpc_connection *);
 int rxrpc_secure_packet(const struct rxrpc_call *, struct sk_buff *, size_t,
@@ -645,6 +649,13 @@ extern const s8 rxrpc_ack_priority[];
 
 extern const char *rxrpc_acks(u8 reason);
 
+/*
+ * rxkad.c
+ */
+#ifdef CONFIG_RXKAD
+extern const struct rxrpc_security rxkad;
+#endif
+
 /*
  * sysctl.c
  */
index ceff6394a65f62e118f56aa599ccafb82dfa6cad..6946aec7ab1fc5f82473a1acc21812ec2818cb03 100644 (file)
 static LIST_HEAD(rxrpc_security_methods);
 static DECLARE_RWSEM(rxrpc_security_sem);
 
-/*
- * get an RxRPC security module
- */
-static struct rxrpc_security *rxrpc_security_get(struct rxrpc_security *sec)
-{
-       return try_module_get(sec->owner) ? sec : NULL;
-}
+static const struct rxrpc_security *rxrpc_security_types[] = {
+#ifdef CONFIG_RXKAD
+       [RXRPC_SECURITY_RXKAD]  = &rxkad,
+#endif
+};
 
-/*
- * release an RxRPC security module
- */
-static void rxrpc_security_put(struct rxrpc_security *sec)
+int __init rxrpc_init_security(void)
 {
-       module_put(sec->owner);
-}
+       int i, ret;
 
-/*
- * look up an rxrpc security module
- */
-static struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
-{
-       struct rxrpc_security *sec = NULL;
-
-       _enter("");
-
-       down_read(&rxrpc_security_sem);
-
-       list_for_each_entry(sec, &rxrpc_security_methods, link) {
-               if (sec->security_index == security_index) {
-                       if (unlikely(!rxrpc_security_get(sec)))
-                               break;
-                       goto out;
+       for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++) {
+               if (rxrpc_security_types[i]) {
+                       ret = rxrpc_security_types[i]->init();
+                       if (ret < 0)
+                               goto failed;
                }
        }
 
-       sec = NULL;
-out:
-       up_read(&rxrpc_security_sem);
-       _leave(" = %p [%s]", sec, sec ? sec->name : "");
-       return sec;
+       return 0;
+
+failed:
+       for (i--; i >= 0; i--)
+               if (rxrpc_security_types[i])
+                       rxrpc_security_types[i]->exit();
+       return ret;
 }
 
-/**
- * rxrpc_register_security - register an RxRPC security handler
- * @sec: security module
- *
- * register an RxRPC security handler for use by RxRPC
- */
-int rxrpc_register_security(struct rxrpc_security *sec)
+void rxrpc_exit_security(void)
 {
-       struct rxrpc_security *psec;
-       int ret;
-
-       _enter("");
-       down_write(&rxrpc_security_sem);
-
-       ret = -EEXIST;
-       list_for_each_entry(psec, &rxrpc_security_methods, link) {
-               if (psec->security_index == sec->security_index)
-                       goto out;
-       }
-
-       list_add(&sec->link, &rxrpc_security_methods);
-
-       printk(KERN_NOTICE "RxRPC: Registered security type %d '%s'\n",
-              sec->security_index, sec->name);
-       ret = 0;
+       int i;
 
-out:
-       up_write(&rxrpc_security_sem);
-       _leave(" = %d", ret);
-       return ret;
+       for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++)
+               if (rxrpc_security_types[i])
+                       rxrpc_security_types[i]->exit();
 }
 
-EXPORT_SYMBOL_GPL(rxrpc_register_security);
-
-/**
- * rxrpc_unregister_security - unregister an RxRPC security handler
- * @sec: security module
- *
- * unregister an RxRPC security handler
+/*
+ * look up an rxrpc security module
  */
-void rxrpc_unregister_security(struct rxrpc_security *sec)
+static const struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
 {
-
-       _enter("");
-       down_write(&rxrpc_security_sem);
-       list_del_init(&sec->link);
-       up_write(&rxrpc_security_sem);
-
-       printk(KERN_NOTICE "RxRPC: Unregistered security type %d '%s'\n",
-              sec->security_index, sec->name);
+       if (security_index >= ARRAY_SIZE(rxrpc_security_types))
+               return NULL;
+       return rxrpc_security_types[security_index];
 }
 
-EXPORT_SYMBOL_GPL(rxrpc_unregister_security);
-
 /*
  * initialise the security on a client connection
  */
 int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
 {
+       const struct rxrpc_security *sec;
        struct rxrpc_key_token *token;
-       struct rxrpc_security *sec;
        struct key *key = conn->key;
        int ret;
 
@@ -148,7 +98,6 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
 
        ret = conn->security->init_connection_security(conn);
        if (ret < 0) {
-               rxrpc_security_put(conn->security);
                conn->security = NULL;
                return ret;
        }
@@ -162,7 +111,7 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
  */
 int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
 {
-       struct rxrpc_security *sec;
+       const struct rxrpc_security *sec;
        struct rxrpc_local *local = conn->trans->local;
        struct rxrpc_sock *rx;
        struct key *key;
@@ -188,14 +137,12 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
 
        /* the service appears to have died */
        read_unlock_bh(&local->services_lock);
-       rxrpc_security_put(sec);
        _leave(" = -ENOENT");
        return -ENOENT;
 
 found_service:
        if (!rx->securities) {
                read_unlock_bh(&local->services_lock);
-               rxrpc_security_put(sec);
                _leave(" = -ENOKEY");
                return -ENOKEY;
        }
@@ -205,7 +152,6 @@ found_service:
                              &key_type_rxrpc_s, kdesc);
        if (IS_ERR(kref)) {
                read_unlock_bh(&local->services_lock);
-               rxrpc_security_put(sec);
                _leave(" = %ld [search]", PTR_ERR(kref));
                return PTR_ERR(kref);
        }
@@ -253,11 +199,8 @@ void rxrpc_clear_conn_security(struct rxrpc_connection *conn)
 {
        _enter("{%d}", conn->debug_id);
 
-       if (conn->security) {
+       if (conn->security)
                conn->security->clear(conn);
-               rxrpc_security_put(conn->security);
-               conn->security = NULL;
-       }
 
        key_put(conn->key);
        key_put(conn->server_key);
index f0aeb8163688e6f4167874d9a6ac0f3bd270891d..6b726a046a7d47995ecc281f67979073fe02c102 100644 (file)
@@ -20,7 +20,6 @@
 #include <net/sock.h>
 #include <net/af_rxrpc.h>
 #include <keys/rxrpc-type.h>
-#define rxrpc_debug rxkad_debug
 #include "ar-internal.h"
 
 #define RXKAD_VERSION                  2
 #define REALM_SZ                       40      /* size of principal's auth domain */
 #define SNAME_SZ                       40      /* size of service name */
 
-unsigned int rxrpc_debug;
-module_param_named(debug, rxrpc_debug, uint, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(debug, "rxkad debugging mask");
-
 struct rxkad_level1_hdr {
        __be32  data_size;      /* true data size (excluding padding) */
 };
@@ -44,10 +39,6 @@ struct rxkad_level2_hdr {
        __be32  checksum;       /* decrypted data checksum */
 };
 
-MODULE_DESCRIPTION("RxRPC network protocol type-2 security (Kerberos 4)");
-MODULE_AUTHOR("Red Hat, Inc.");
-MODULE_LICENSE("GPL");
-
 /*
  * this holds a pinned cipher so that keventd doesn't get called by the cipher
  * alloc routine, but since we have it to hand, we use it to decrypt RESPONSE
@@ -1163,13 +1154,36 @@ static void rxkad_clear(struct rxrpc_connection *conn)
                crypto_free_skcipher(conn->cipher);
 }
 
+/*
+ * Initialise the rxkad security service.
+ */
+static int rxkad_init(void)
+{
+       /* pin the cipher we need so that the crypto layer doesn't invoke
+        * keventd to go get it */
+       rxkad_ci = crypto_alloc_skcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(rxkad_ci))
+               return PTR_ERR(rxkad_ci);
+       return 0;
+}
+
+/*
+ * Clean up the rxkad security service.
+ */
+static void rxkad_exit(void)
+{
+       if (rxkad_ci)
+               crypto_free_skcipher(rxkad_ci);
+}
+
 /*
  * RxRPC Kerberos-based security
  */
-static struct rxrpc_security rxkad = {
-       .owner                          = THIS_MODULE,
+const struct rxrpc_security rxkad = {
        .name                           = "rxkad",
        .security_index                 = RXRPC_SECURITY_RXKAD,
+       .init                           = rxkad_init,
+       .exit                           = rxkad_exit,
        .init_connection_security       = rxkad_init_connection_security,
        .prime_packet_security          = rxkad_prime_packet_security,
        .secure_packet                  = rxkad_secure_packet,
@@ -1179,28 +1193,3 @@ static struct rxrpc_security rxkad = {
        .verify_response                = rxkad_verify_response,
        .clear                          = rxkad_clear,
 };
-
-static __init int rxkad_init(void)
-{
-       _enter("");
-
-       /* pin the cipher we need so that the crypto layer doesn't invoke
-        * keventd to go get it */
-       rxkad_ci = crypto_alloc_skcipher("pcbc(fcrypt)", 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(rxkad_ci))
-               return PTR_ERR(rxkad_ci);
-
-       return rxrpc_register_security(&rxkad);
-}
-
-module_init(rxkad_init);
-
-static __exit void rxkad_exit(void)
-{
-       _enter("");
-
-       rxrpc_unregister_security(&rxkad);
-       crypto_free_skcipher(rxkad_ci);
-}
-
-module_exit(rxkad_exit);