rxrpc: Absorb the rxkad security module
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>
This commit is contained in:
parent
6dd050f88d
commit
648af7fca1
|
@ -30,7 +30,7 @@ config AF_RXRPC_DEBUG
|
||||||
|
|
||||||
|
|
||||||
config RXKAD
|
config RXKAD
|
||||||
tristate "RxRPC Kerberos security"
|
bool "RxRPC Kerberos security"
|
||||||
depends on AF_RXRPC
|
depends on AF_RXRPC
|
||||||
select CRYPTO
|
select CRYPTO
|
||||||
select CRYPTO_MANAGER
|
select CRYPTO_MANAGER
|
||||||
|
|
|
@ -22,8 +22,7 @@ af-rxrpc-y := \
|
||||||
misc.o
|
misc.o
|
||||||
|
|
||||||
af-rxrpc-$(CONFIG_PROC_FS) += ar-proc.o
|
af-rxrpc-$(CONFIG_PROC_FS) += ar-proc.o
|
||||||
|
af-rxrpc-$(CONFIG_RXKAD) += rxkad.o
|
||||||
af-rxrpc-$(CONFIG_SYSCTL) += sysctl.o
|
af-rxrpc-$(CONFIG_SYSCTL) += sysctl.o
|
||||||
|
|
||||||
obj-$(CONFIG_AF_RXRPC) += af-rxrpc.o
|
obj-$(CONFIG_AF_RXRPC) += af-rxrpc.o
|
||||||
|
|
||||||
obj-$(CONFIG_RXKAD) += rxkad.o
|
|
||||||
|
|
|
@ -806,6 +806,12 @@ static int __init af_rxrpc_init(void)
|
||||||
goto error_work_queue;
|
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);
|
ret = proto_register(&rxrpc_proto, 1);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
printk(KERN_CRIT "RxRPC: Cannot register protocol\n");
|
printk(KERN_CRIT "RxRPC: Cannot register protocol\n");
|
||||||
|
@ -853,6 +859,8 @@ error_sock:
|
||||||
proto_unregister(&rxrpc_proto);
|
proto_unregister(&rxrpc_proto);
|
||||||
error_proto:
|
error_proto:
|
||||||
destroy_workqueue(rxrpc_workqueue);
|
destroy_workqueue(rxrpc_workqueue);
|
||||||
|
error_security:
|
||||||
|
rxrpc_exit_security();
|
||||||
error_work_queue:
|
error_work_queue:
|
||||||
kmem_cache_destroy(rxrpc_call_jar);
|
kmem_cache_destroy(rxrpc_call_jar);
|
||||||
error_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_conns", init_net.proc_net);
|
||||||
remove_proc_entry("rxrpc_calls", init_net.proc_net);
|
remove_proc_entry("rxrpc_calls", init_net.proc_net);
|
||||||
destroy_workqueue(rxrpc_workqueue);
|
destroy_workqueue(rxrpc_workqueue);
|
||||||
|
rxrpc_exit_security();
|
||||||
kmem_cache_destroy(rxrpc_call_jar);
|
kmem_cache_destroy(rxrpc_call_jar);
|
||||||
_leave("");
|
_leave("");
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,11 +124,15 @@ enum rxrpc_command {
|
||||||
* RxRPC security module interface
|
* RxRPC security module interface
|
||||||
*/
|
*/
|
||||||
struct rxrpc_security {
|
struct rxrpc_security {
|
||||||
struct module *owner; /* providing module */
|
|
||||||
struct list_head link; /* link in master list */
|
|
||||||
const char *name; /* name of this service */
|
const char *name; /* name of this service */
|
||||||
u8 security_index; /* security type provided */
|
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 */
|
/* initialise a connection's security */
|
||||||
int (*init_connection_security)(struct rxrpc_connection *);
|
int (*init_connection_security)(struct rxrpc_connection *);
|
||||||
|
|
||||||
|
@ -268,7 +272,7 @@ struct rxrpc_connection {
|
||||||
struct rb_root calls; /* calls on this connection */
|
struct rb_root calls; /* calls on this connection */
|
||||||
struct sk_buff_head rx_queue; /* received conn-level packets */
|
struct sk_buff_head rx_queue; /* received conn-level packets */
|
||||||
struct rxrpc_call *channels[RXRPC_MAXCALLS]; /* channels (active calls) */
|
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 *key; /* security for this connection (client) */
|
||||||
struct key *server_key; /* security for this service */
|
struct key *server_key; /* security for this service */
|
||||||
struct crypto_skcipher *cipher; /* encryption handle */
|
struct crypto_skcipher *cipher; /* encryption handle */
|
||||||
|
@ -604,8 +608,8 @@ int rxrpc_recvmsg(struct socket *, struct msghdr *, size_t, int);
|
||||||
/*
|
/*
|
||||||
* ar-security.c
|
* ar-security.c
|
||||||
*/
|
*/
|
||||||
int rxrpc_register_security(struct rxrpc_security *);
|
int __init rxrpc_init_security(void);
|
||||||
void rxrpc_unregister_security(struct rxrpc_security *);
|
void rxrpc_exit_security(void);
|
||||||
int rxrpc_init_client_conn_security(struct rxrpc_connection *);
|
int rxrpc_init_client_conn_security(struct rxrpc_connection *);
|
||||||
int rxrpc_init_server_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,
|
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);
|
extern const char *rxrpc_acks(u8 reason);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rxkad.c
|
||||||
|
*/
|
||||||
|
#ifdef CONFIG_RXKAD
|
||||||
|
extern const struct rxrpc_security rxkad;
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sysctl.c
|
* sysctl.c
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -22,109 +22,59 @@
|
||||||
static LIST_HEAD(rxrpc_security_methods);
|
static LIST_HEAD(rxrpc_security_methods);
|
||||||
static DECLARE_RWSEM(rxrpc_security_sem);
|
static DECLARE_RWSEM(rxrpc_security_sem);
|
||||||
|
|
||||||
/*
|
static const struct rxrpc_security *rxrpc_security_types[] = {
|
||||||
* get an RxRPC security module
|
#ifdef CONFIG_RXKAD
|
||||||
*/
|
[RXRPC_SECURITY_RXKAD] = &rxkad,
|
||||||
static struct rxrpc_security *rxrpc_security_get(struct rxrpc_security *sec)
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
int __init rxrpc_init_security(void)
|
||||||
{
|
{
|
||||||
return try_module_get(sec->owner) ? sec : NULL;
|
int i, ret;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
for (i--; i >= 0; i--)
|
||||||
|
if (rxrpc_security_types[i])
|
||||||
|
rxrpc_security_types[i]->exit();
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void rxrpc_exit_security(void)
|
||||||
* release an RxRPC security module
|
|
||||||
*/
|
|
||||||
static void rxrpc_security_put(struct rxrpc_security *sec)
|
|
||||||
{
|
{
|
||||||
module_put(sec->owner);
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(rxrpc_security_types); i++)
|
||||||
|
if (rxrpc_security_types[i])
|
||||||
|
rxrpc_security_types[i]->exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* look up an rxrpc security module
|
* look up an rxrpc security module
|
||||||
*/
|
*/
|
||||||
static struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
|
static const struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
|
||||||
{
|
{
|
||||||
struct rxrpc_security *sec = NULL;
|
if (security_index >= ARRAY_SIZE(rxrpc_security_types))
|
||||||
|
return NULL;
|
||||||
_enter("");
|
return rxrpc_security_types[security_index];
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sec = NULL;
|
|
||||||
out:
|
|
||||||
up_read(&rxrpc_security_sem);
|
|
||||||
_leave(" = %p [%s]", sec, sec ? sec->name : "");
|
|
||||||
return sec;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
|
|
||||||
out:
|
|
||||||
up_write(&rxrpc_security_sem);
|
|
||||||
_leave(" = %d", ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(rxrpc_register_security);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* rxrpc_unregister_security - unregister an RxRPC security handler
|
|
||||||
* @sec: security module
|
|
||||||
*
|
|
||||||
* unregister an RxRPC security handler
|
|
||||||
*/
|
|
||||||
void rxrpc_unregister_security(struct rxrpc_security *sec)
|
|
||||||
{
|
|
||||||
|
|
||||||
_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);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(rxrpc_unregister_security);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialise the security on a client connection
|
* initialise the security on a client connection
|
||||||
*/
|
*/
|
||||||
int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
|
int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
|
||||||
{
|
{
|
||||||
|
const struct rxrpc_security *sec;
|
||||||
struct rxrpc_key_token *token;
|
struct rxrpc_key_token *token;
|
||||||
struct rxrpc_security *sec;
|
|
||||||
struct key *key = conn->key;
|
struct key *key = conn->key;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -148,7 +98,6 @@ int rxrpc_init_client_conn_security(struct rxrpc_connection *conn)
|
||||||
|
|
||||||
ret = conn->security->init_connection_security(conn);
|
ret = conn->security->init_connection_security(conn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
rxrpc_security_put(conn->security);
|
|
||||||
conn->security = NULL;
|
conn->security = NULL;
|
||||||
return ret;
|
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)
|
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_local *local = conn->trans->local;
|
||||||
struct rxrpc_sock *rx;
|
struct rxrpc_sock *rx;
|
||||||
struct key *key;
|
struct key *key;
|
||||||
|
@ -188,14 +137,12 @@ int rxrpc_init_server_conn_security(struct rxrpc_connection *conn)
|
||||||
|
|
||||||
/* the service appears to have died */
|
/* the service appears to have died */
|
||||||
read_unlock_bh(&local->services_lock);
|
read_unlock_bh(&local->services_lock);
|
||||||
rxrpc_security_put(sec);
|
|
||||||
_leave(" = -ENOENT");
|
_leave(" = -ENOENT");
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
found_service:
|
found_service:
|
||||||
if (!rx->securities) {
|
if (!rx->securities) {
|
||||||
read_unlock_bh(&local->services_lock);
|
read_unlock_bh(&local->services_lock);
|
||||||
rxrpc_security_put(sec);
|
|
||||||
_leave(" = -ENOKEY");
|
_leave(" = -ENOKEY");
|
||||||
return -ENOKEY;
|
return -ENOKEY;
|
||||||
}
|
}
|
||||||
|
@ -205,7 +152,6 @@ found_service:
|
||||||
&key_type_rxrpc_s, kdesc);
|
&key_type_rxrpc_s, kdesc);
|
||||||
if (IS_ERR(kref)) {
|
if (IS_ERR(kref)) {
|
||||||
read_unlock_bh(&local->services_lock);
|
read_unlock_bh(&local->services_lock);
|
||||||
rxrpc_security_put(sec);
|
|
||||||
_leave(" = %ld [search]", PTR_ERR(kref));
|
_leave(" = %ld [search]", PTR_ERR(kref));
|
||||||
return 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);
|
_enter("{%d}", conn->debug_id);
|
||||||
|
|
||||||
if (conn->security) {
|
if (conn->security)
|
||||||
conn->security->clear(conn);
|
conn->security->clear(conn);
|
||||||
rxrpc_security_put(conn->security);
|
|
||||||
conn->security = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
key_put(conn->key);
|
key_put(conn->key);
|
||||||
key_put(conn->server_key);
|
key_put(conn->server_key);
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
#include <net/af_rxrpc.h>
|
#include <net/af_rxrpc.h>
|
||||||
#include <keys/rxrpc-type.h>
|
#include <keys/rxrpc-type.h>
|
||||||
#define rxrpc_debug rxkad_debug
|
|
||||||
#include "ar-internal.h"
|
#include "ar-internal.h"
|
||||||
|
|
||||||
#define RXKAD_VERSION 2
|
#define RXKAD_VERSION 2
|
||||||
|
@ -31,10 +30,6 @@
|
||||||
#define REALM_SZ 40 /* size of principal's auth domain */
|
#define REALM_SZ 40 /* size of principal's auth domain */
|
||||||
#define SNAME_SZ 40 /* size of service name */
|
#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 {
|
struct rxkad_level1_hdr {
|
||||||
__be32 data_size; /* true data size (excluding padding) */
|
__be32 data_size; /* true data size (excluding padding) */
|
||||||
};
|
};
|
||||||
|
@ -44,10 +39,6 @@ struct rxkad_level2_hdr {
|
||||||
__be32 checksum; /* decrypted data checksum */
|
__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
|
* 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
|
* 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);
|
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
|
* RxRPC Kerberos-based security
|
||||||
*/
|
*/
|
||||||
static struct rxrpc_security rxkad = {
|
const struct rxrpc_security rxkad = {
|
||||||
.owner = THIS_MODULE,
|
|
||||||
.name = "rxkad",
|
.name = "rxkad",
|
||||||
.security_index = RXRPC_SECURITY_RXKAD,
|
.security_index = RXRPC_SECURITY_RXKAD,
|
||||||
|
.init = rxkad_init,
|
||||||
|
.exit = rxkad_exit,
|
||||||
.init_connection_security = rxkad_init_connection_security,
|
.init_connection_security = rxkad_init_connection_security,
|
||||||
.prime_packet_security = rxkad_prime_packet_security,
|
.prime_packet_security = rxkad_prime_packet_security,
|
||||||
.secure_packet = rxkad_secure_packet,
|
.secure_packet = rxkad_secure_packet,
|
||||||
|
@ -1179,28 +1193,3 @@ static struct rxrpc_security rxkad = {
|
||||||
.verify_response = rxkad_verify_response,
|
.verify_response = rxkad_verify_response,
|
||||||
.clear = rxkad_clear,
|
.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);
|
|
||||||
|
|
Loading…
Reference in New Issue