From: Jarkko Sakkinen <jarkko@kernel.org>
To: David Howells <dhowells@redhat.com>
Cc: Jarkko Sakkinen <jarkko@kernel.org>,
keyrings@vger.kernel.org, linux-afs@lists.infradead.org,
linux-cifs@vger.kernel.org, linux-integrity@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-nfs@vger.kernel.org,
linux-s390@vger.kernel.org,
linux-security-module@vger.kernel.org, netdev@vger.kernel.org,
samba-technical@lists.samba.org,
Alexander Gordeev <agordeev@linux.ibm.com>,
Anna Schumaker <anna@kernel.org>,
Bharath SM <bharathsm@microsoft.com>,
Christian Borntraeger <borntraeger@linux.ibm.com>,
"David S. Miller" <davem@davemloft.net>,
Eric Biggers <ebiggers@kernel.org>,
Eric Dumazet <edumazet@kernel.org>,
Heiko Carstens <hca@linux.ibm.com>,
Jakub Kicinski <kuba@kernel.org>,
James Bottomley <James.Bottomley@HansenPartnership.com>,
James Morris <jmorris@namei.org>,
Marc Dionne <marc.dionne@auristor.com>,
Mimi Zohar <zohar@linux.ibm.com>,
Namjae Jeon <linkinjeon@kernel.org>,
Paolo Abeni <pabeni@redhat.com>, Paul Moore <paul@paul-moore.com>,
Paulo Alcantara <pc@manguebit.org>,
Ronnie Sahlberg <ronniesahlberg@gmail.com>,
"Serge E. Hallyn" <serge@hallyn.com>,
Shyam Prasad N <sprasad@microsoft.com>,
Simon Horman <horms@kernel.org>,
Sumit Garg <sumit.garg@kernel.org>,
Sven Schnelle <svens@linux.ibm.com>, Tom Talpey <tom@talpey.com>,
Trond Myklebust <trondmy@kernel.org>,
Vasily Gorbik <gor@linux.ibm.com>
Subject: [RFC PATCH v3 08/11] rxrpc: Move key types to their own module
Date: Thu, 5 Nov 2026 02:53:07 +0200 [thread overview]
Message-ID: <20261105005311.804098-9-jarkko@kernel.org> (raw)
In-Reply-To: <20261105005311.804098-1-jarkko@kernel.org>
Once keys pin the kernel module implementing their key type, hosting rxrpc
and rxrpc_s keys inside the same module prevents unloading the transport
module while keys remain in keyrings or cached connections.
Split the key types and their preparse logic into a separate rxrpc_keys.ko
module that rxrpc.ko depends on, and flush key GC on rxrpc exit.
By doing this, rxrpc.ko can be removed while the persistent keys pin only
rxrpc_keys.ko.
Co-developed-by: David Howells <dhowells@redhat.com>
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
net/Makefile | 2 +-
net/rxrpc/Kconfig | 20 ++++
net/rxrpc/Makefile | 7 +-
net/rxrpc/af_rxrpc.c | 19 +--
net/rxrpc/ar-internal.h | 25 +---
net/rxrpc/key.c | 122 ++++++-------------
net/rxrpc/rxgk.c | 66 ----------
net/rxrpc/rxkad.c | 47 --------
net/rxrpc/security.c | 184 ++++++++++++++++++++++++++++
net/rxrpc/server_key.c | 260 ++++++++++++++++++++++++----------------
10 files changed, 410 insertions(+), 342 deletions(-)
diff --git a/net/Makefile b/net/Makefile
index 69c16a7851b4..97b2bd2ace7b 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -30,7 +30,7 @@ obj-$(CONFIG_LAPB) += lapb/
obj-$(CONFIG_CAN) += can/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_SUNRPC) += sunrpc/
-obj-$(CONFIG_AF_RXRPC) += rxrpc/
+obj-$(CONFIG_RXRPC_KEYS) += rxrpc/
obj-$(CONFIG_AF_KCM) += kcm/
obj-$(CONFIG_STREAM_PARSER) += strparser/
obj-$(CONFIG_ATM) += atm/
diff --git a/net/rxrpc/Kconfig b/net/rxrpc/Kconfig
index 2cebb666dc07..30135ae62bd6 100644
--- a/net/rxrpc/Kconfig
+++ b/net/rxrpc/Kconfig
@@ -3,6 +3,18 @@
# RxRPC session sockets
#
+config RXRPC_KEYS
+ tristate "RxRPC key types"
+ select CRYPTO
+ select CRYPTO_LIB_DES if RXKAD
+ select KEYS
+ help
+ Say Y or M here to include support for rxrpc and rxrpc_s key types
+ independently of RxRPC session sockets.
+
+ To compile this as a module, choose M here: the module will be called
+ rxrpc_keys.
+
config AF_RXRPC
tristate "RxRPC session sockets"
depends on INET
@@ -10,6 +22,7 @@ config AF_RXRPC
select CRYPTO_LIB_DES if RXKAD
select KEYS
select NET_UDP_TUNNEL
+ select RXRPC_KEYS
help
Say Y or M here to include support for RxRPC session sockets (just
the transport part, not the presentation part: (un)marshalling is
@@ -54,6 +67,9 @@ config AF_RXRPC_DEBUG
See Documentation/networking/rxrpc.rst.
+endif
+
+if RXRPC_KEYS
config RXKAD
bool "RxRPC Kerberos security"
@@ -86,6 +102,10 @@ config RXGK
See Documentation/networking/rxrpc.rst.
+endif
+
+if AF_RXRPC
+
config RXPERF
tristate "RxRPC test service"
help
diff --git a/net/rxrpc/Makefile b/net/rxrpc/Makefile
index f994f9f30a29..196e0ce085ba 100644
--- a/net/rxrpc/Makefile
+++ b/net/rxrpc/Makefile
@@ -3,6 +3,7 @@
# Makefile for Linux kernel RxRPC
#
+obj-$(CONFIG_RXRPC_KEYS) += rxrpc_keys.o
obj-$(CONFIG_AF_RXRPC) += rxrpc.o
rxrpc-y := \
@@ -19,7 +20,6 @@ rxrpc-y := \
input_rack.o \
insecure.o \
io_thread.o \
- key.o \
local_event.o \
local_object.o \
misc.o \
@@ -32,7 +32,6 @@ rxrpc-y := \
rtt.o \
security.o \
sendmsg.o \
- server_key.o \
skbuff.o \
txbuf.o \
utils.o
@@ -45,5 +44,9 @@ rxrpc-$(CONFIG_RXGK) += \
rxgk_app.o \
rxgk_kdf.o
+rxrpc_keys-y := \
+ key.o \
+ server_key.o
+
obj-$(CONFIG_RXPERF) += rxperf.o
obj-$(CONFIG_KUNIT) += tests/
diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c
index 9ab0f22c881e..6ccb99a992b9 100644
--- a/net/rxrpc/af_rxrpc.c
+++ b/net/rxrpc/af_rxrpc.c
@@ -1077,18 +1077,6 @@ static int __init af_rxrpc_init(void)
goto error_sock;
}
- ret = register_key_type(&key_type_rxrpc);
- if (ret < 0) {
- pr_crit("Cannot register client key type\n");
- goto error_key_type;
- }
-
- ret = register_key_type(&key_type_rxrpc_s);
- if (ret < 0) {
- pr_crit("Cannot register server key type\n");
- goto error_key_type_s;
- }
-
ret = rxrpc_sysctl_init();
if (ret < 0) {
pr_crit("Cannot register sysctls\n");
@@ -1098,10 +1086,6 @@ static int __init af_rxrpc_init(void)
return 0;
error_sysctls:
- unregister_key_type(&key_type_rxrpc_s);
-error_key_type_s:
- unregister_key_type(&key_type_rxrpc);
-error_key_type:
sock_unregister(PF_RXRPC);
error_sock:
proto_unregister(&rxrpc_proto);
@@ -1124,8 +1108,6 @@ static void __exit af_rxrpc_exit(void)
{
_enter("");
rxrpc_sysctl_exit();
- unregister_key_type(&key_type_rxrpc_s);
- unregister_key_type(&key_type_rxrpc);
sock_unregister(PF_RXRPC);
proto_unregister(&rxrpc_proto);
unregister_pernet_device(&rxrpc_net_ops);
@@ -1139,6 +1121,7 @@ static void __exit af_rxrpc_exit(void)
destroy_workqueue(rxrpc_workqueue);
rxrpc_exit_security();
kmem_cache_destroy(rxrpc_call_jar);
+ key_gc_flush();
_leave("");
}
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index 865f05fe37ab..b5deab0e1ed9 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -273,18 +273,6 @@ struct rxrpc_security {
/* Clean up a security service */
void (*exit)(void);
- /* Parse the information from a server key */
- int (*preparse_server_key)(struct key_preparsed_payload *);
-
- /* Clean up the preparse buffer after parsing a server key */
- void (*free_preparse_server_key)(struct key_preparsed_payload *);
-
- /* Destroy the payload of a server key */
- void (*destroy_server_key)(struct key *);
-
- /* Describe a server key */
- void (*describe_server_key)(const struct key *, struct seq_file *);
-
/* initialise a connection's security */
int (*init_connection_security)(struct rxrpc_connection *,
struct rxrpc_key_token *);
@@ -1307,10 +1295,6 @@ extern const struct rxrpc_security rxrpc_no_security;
*/
extern struct key_type key_type_rxrpc;
-int rxrpc_request_key(struct rxrpc_sock *, sockptr_t , int);
-int rxrpc_get_server_data_key(struct rxrpc_connection *, const void *, time64_t,
- u32);
-
/*
* local_event.c
*/
@@ -1492,6 +1476,11 @@ const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *,
struct sk_buff *);
struct key *rxrpc_look_up_server_security(struct rxrpc_connection *,
struct sk_buff *, u32, u32);
+int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen);
+int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
+ const void *session_key, time64_t expiry,
+ u32 kvno);
+int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen);
/*
* sendmsg.c
@@ -1505,8 +1494,6 @@ int rxrpc_do_sendmsg(struct rxrpc_sock *, struct msghdr *, size_t);
*/
extern struct key_type key_type_rxrpc_s;
-int rxrpc_server_keyring(struct rxrpc_sock *, sockptr_t, int);
-
/*
* skbuff.c
*/
@@ -1633,7 +1620,7 @@ extern unsigned int rxrpc_debug;
#define _leave(FMT,...) kleave(FMT,##__VA_ARGS__)
#define _debug(FMT,...) kdebug(FMT,##__VA_ARGS__)
-#elif defined(CONFIG_AF_RXRPC_DEBUG)
+#elif defined(CONFIG_AF_RXRPC_DEBUG) && !defined(RXRPC_KEY_PROVIDER)
#define RXRPC_DEBUG_KENTER 0x01
#define RXRPC_DEBUG_KLEAVE 0x02
#define RXRPC_DEBUG_KDEBUG 0x04
diff --git a/net/rxrpc/key.c b/net/rxrpc/key.c
index cbd26da44951..49d0871beaf9 100644
--- a/net/rxrpc/key.c
+++ b/net/rxrpc/key.c
@@ -9,6 +9,7 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#define RXRPC_KEY_PROVIDER
#include <linux/module.h>
#include <linux/net.h>
@@ -615,89 +616,6 @@ static void rxrpc_describe(const struct key *key, struct seq_file *m)
}
}
-/*
- * grab the security key for a socket
- */
-int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
-{
- struct key *key;
- char *description;
-
- _enter("");
-
- if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->key)
- return -EINVAL;
-
- description = memdup_sockptr_nul(optval, optlen);
- if (IS_ERR(description))
- return PTR_ERR(description);
-
- key = request_key_net(&key_type_rxrpc, description, sock_net(&rx->sk), NULL);
- if (IS_ERR(key)) {
- kfree(description);
- _leave(" = %ld", PTR_ERR(key));
- return PTR_ERR(key);
- }
-
- rx->key = key;
- kfree(description);
- _leave(" = 0 [key %x]", key->serial);
- return 0;
-}
-
-/*
- * generate a server data key
- */
-int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
- const void *session_key,
- time64_t expiry,
- u32 kvno)
-{
- const struct cred *cred = current_cred();
- struct key *key;
- int ret;
-
- struct {
- u32 kver;
- struct rxrpc_key_data_v1 v1;
- } data;
-
- _enter("");
-
- key = key_alloc(&key_type_rxrpc, "x",
- GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,
- KEY_ALLOC_NOT_IN_QUOTA, NULL);
- if (IS_ERR(key)) {
- _leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
- return -ENOMEM;
- }
-
- _debug("key %d", key_serial(key));
-
- data.kver = 1;
- data.v1.security_index = RXRPC_SECURITY_RXKAD;
- data.v1.ticket_length = 0;
- data.v1.expiry = rxrpc_time64_to_u32(expiry);
- data.v1.kvno = 0;
-
- memcpy(&data.v1.session_key, session_key, sizeof(data.v1.session_key));
-
- ret = key_instantiate_and_link(key, &data, sizeof(data), NULL, NULL);
- if (ret < 0)
- goto error;
-
- conn->key = key;
- _leave(" = 0 [%d]", key_serial(key));
- return 0;
-
-error:
- key_revoke(key);
- key_put(key);
- _leave(" = -ENOMEM [ins %d]", ret);
- return -ENOMEM;
-}
-EXPORT_SYMBOL(rxrpc_get_server_data_key);
-
/**
* rxrpc_get_null_key - Generate a null RxRPC key
* @keyname: The name to give the key.
@@ -893,3 +811,41 @@ static long rxrpc_read(const struct key *key,
_leave(" = %zu", size);
return size;
}
+
+static int __init rxrpc_keys_init(void)
+{
+ int ret;
+
+ ret = register_key_type(&key_type_rxrpc);
+ if (ret < 0) {
+ pr_crit("Cannot register client key type\n");
+ goto error_key_type;
+ }
+
+ ret = register_key_type(&key_type_rxrpc_s);
+ if (ret < 0) {
+ pr_crit("Cannot register server key type\n");
+ goto error_key_type_s;
+ }
+
+ return 0;
+
+error_key_type_s:
+ unregister_key_type(&key_type_rxrpc);
+
+error_key_type:
+ return ret;
+}
+
+static void __exit rxrpc_keys_exit(void)
+{
+ unregister_key_type(&key_type_rxrpc_s);
+ unregister_key_type(&key_type_rxrpc);
+}
+
+module_init(rxrpc_keys_init);
+module_exit(rxrpc_keys_exit);
+
+MODULE_DESCRIPTION("RxRPC key types");
+MODULE_AUTHOR("David Howells <dhowells@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
index 77a67ace1d24..5fb3ce15cac4 100644
--- a/net/rxrpc/rxgk.c
+++ b/net/rxrpc/rxgk.c
@@ -14,68 +14,6 @@
#include "ar-internal.h"
#include "rxgk_common.h"
-/*
- * Parse the information from a server key
- */
-static int rxgk_preparse_server_key(struct key_preparsed_payload *prep)
-{
- const struct krb5_enctype *krb5;
- struct krb5_buffer *server_key = (void *)&prep->payload.data[2];
- unsigned int service, sec_class, kvno, enctype;
- int n = 0;
-
- _enter("%zu", prep->datalen);
-
- if (sscanf(prep->orig_description, "%u:%u:%u:%u%n",
- &service, &sec_class, &kvno, &enctype, &n) != 4)
- return -EINVAL;
-
- if (prep->orig_description[n])
- return -EINVAL;
-
- krb5 = crypto_krb5_find_enctype(enctype);
- if (!krb5)
- return -ENOPKG;
-
- prep->payload.data[0] = (struct krb5_enctype *)krb5;
-
- if (prep->datalen != krb5->key_len)
- return -EKEYREJECTED;
-
- server_key->len = prep->datalen;
- server_key->data = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
- if (!server_key->data)
- return -ENOMEM;
-
- _leave(" = 0");
- return 0;
-}
-
-static void rxgk_free_server_key(union key_payload *payload)
-{
- struct krb5_buffer *server_key = (void *)&payload->data[2];
-
- kfree_sensitive(server_key->data);
-}
-
-static void rxgk_free_preparse_server_key(struct key_preparsed_payload *prep)
-{
- rxgk_free_server_key(&prep->payload);
-}
-
-static void rxgk_destroy_server_key(struct key *key)
-{
- rxgk_free_server_key(&key->payload);
-}
-
-static void rxgk_describe_server_key(const struct key *key, struct seq_file *m)
-{
- const struct krb5_enctype *krb5 = key->payload.data[0];
-
- if (krb5)
- seq_printf(m, ": %s", krb5->name);
-}
-
/*
* Handle rekeying the connection when we see our limits overrun or when the
* far side decided to rekey.
@@ -1335,10 +1273,6 @@ const struct rxrpc_security rxgk_yfs = {
.no_key_abort = RXGK_NOTAUTH,
.init = rxgk_init,
.exit = rxgk_exit,
- .preparse_server_key = rxgk_preparse_server_key,
- .free_preparse_server_key = rxgk_free_preparse_server_key,
- .destroy_server_key = rxgk_destroy_server_key,
- .describe_server_key = rxgk_describe_server_key,
.init_connection_security = rxgk_init_connection_security,
.alloc_txbuf = rxgk_alloc_txbuf,
.secure_packet = rxgk_secure_packet,
diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c
index ca9f0e82cb9a..2936c6effae3 100644
--- a/net/rxrpc/rxkad.c
+++ b/net/rxrpc/rxkad.c
@@ -47,50 +47,6 @@ struct rxkad_level2_hdr {
static void rxkad_prime_packet_security(struct rxrpc_connection *conn,
const struct fcrypt_key *cipher);
-/*
- * Parse the information from a server key
- *
- * The data should be the 8-byte secret key.
- */
-static int rxkad_preparse_server_key(struct key_preparsed_payload *prep)
-{
- struct des_ctx *des_key;
- int err;
-
- if (prep->datalen != 8)
- return -EINVAL;
-
- memcpy(&prep->payload.data[2], prep->data, 8);
-
- des_key = kmalloc_obj(*des_key);
- if (!des_key) {
- _leave(" = -ENOMEM");
- return -ENOMEM;
- }
-
- err = des_expand_key(des_key, prep->data, 8);
- if (err) {
- kfree_sensitive(des_key);
- _leave(" = %d", err);
- return err;
- }
-
- prep->payload.data[0] = des_key;
- _leave(" = 0");
- return 0;
-}
-
-static void rxkad_free_preparse_server_key(struct key_preparsed_payload *prep)
-{
- kfree_sensitive(prep->payload.data[0]);
-}
-
-static void rxkad_destroy_server_key(struct key *key)
-{
- kfree_sensitive(key->payload.data[0]);
- key->payload.data[0] = NULL;
-}
-
/*
* initialise connection security
*/
@@ -1124,9 +1080,6 @@ const struct rxrpc_security rxkad = {
.no_key_abort = RXKADUNKNOWNKEY,
.init = rxkad_init,
.exit = rxkad_exit,
- .preparse_server_key = rxkad_preparse_server_key,
- .free_preparse_server_key = rxkad_free_preparse_server_key,
- .destroy_server_key = rxkad_destroy_server_key,
.init_connection_security = rxkad_init_connection_security,
.alloc_txbuf = rxkad_alloc_txbuf,
.secure_packet = rxkad_secure_packet,
diff --git a/net/rxrpc/security.c b/net/rxrpc/security.c
index 2bfbf2b2bb37..28883a70c9e8 100644
--- a/net/rxrpc/security.c
+++ b/net/rxrpc/security.c
@@ -10,6 +10,8 @@
#include <linux/skbuff.h>
#include <linux/udp.h>
#include <linux/crypto.h>
+#include <linux/key-type.h>
+#include <linux/slab.h>
#include <net/sock.h>
#include <net/af_rxrpc.h>
#include <keys/rxrpc-type.h>
@@ -208,3 +210,185 @@ struct key *rxrpc_look_up_server_security(struct rxrpc_connection *conn,
read_unlock(&conn->local->services_lock);
return key;
}
+
+/*
+ * grab the security key for a socket
+ */
+int rxrpc_request_key(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
+{
+ struct key *key;
+ char *description;
+
+ _enter("");
+
+ if (optlen <= 0 || optlen > PAGE_SIZE - 1 || rx->key)
+ return -EINVAL;
+
+ description = memdup_sockptr_nul(optval, optlen);
+ if (IS_ERR(description))
+ return PTR_ERR(description);
+
+ key = request_key_net(&key_type_rxrpc, description, sock_net(&rx->sk), NULL);
+ if (IS_ERR(key)) {
+ kfree(description);
+ _leave(" = %ld", PTR_ERR(key));
+ return PTR_ERR(key);
+ }
+
+ rx->key = key;
+ kfree(description);
+ _leave(" = 0 [key %x]", key->serial);
+ return 0;
+}
+
+/*
+ * generate a server data key
+ */
+int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
+ const void *session_key,
+ time64_t expiry,
+ u32 kvno)
+{
+ const struct cred *cred = current_cred();
+ struct {
+ u32 kver;
+ struct rxrpc_key_data_v1 v1;
+ } data;
+ struct key *key;
+ int ret;
+
+ _enter("");
+
+ key = key_alloc(&key_type_rxrpc, "x",
+ GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,
+ KEY_ALLOC_NOT_IN_QUOTA, NULL);
+ if (IS_ERR(key)) {
+ _leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
+ return -ENOMEM;
+ }
+
+ _debug("key %d", key_serial(key));
+
+ data.kver = 1;
+ data.v1.security_index = RXRPC_SECURITY_RXKAD;
+ data.v1.ticket_length = 0;
+ data.v1.expiry = rxrpc_time64_to_u32(expiry);
+ data.v1.kvno = 0;
+
+ memcpy(&data.v1.session_key, session_key, sizeof(data.v1.session_key));
+
+ ret = key_instantiate_and_link(key, &data, sizeof(data), NULL, NULL);
+ if (ret < 0)
+ goto error;
+
+ conn->key = key;
+ _leave(" = 0 [%d]", key_serial(key));
+ return 0;
+
+error:
+ key_revoke(key);
+ key_put(key);
+ _leave(" = -ENOMEM [ins %d]", ret);
+ return -ENOMEM;
+}
+EXPORT_SYMBOL(rxrpc_get_server_data_key);
+
+/*
+ * grab the security keyring for a server socket
+ */
+int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
+{
+ struct key *key;
+ char *description;
+
+ _enter("");
+
+ if (rx->securities)
+ return -EINVAL;
+
+ if (optlen <= 0 || optlen > PAGE_SIZE - 1)
+ return -EINVAL;
+
+ description = memdup_sockptr_nul(optval, optlen);
+ if (IS_ERR(description))
+ return PTR_ERR(description);
+
+ key = request_key(&key_type_keyring, description, NULL);
+ if (IS_ERR(key)) {
+ kfree(description);
+ _leave(" = %ld", PTR_ERR(key));
+ return PTR_ERR(key);
+ }
+
+ rx->securities = key;
+ kfree(description);
+ _leave(" = 0 [key %x]", key->serial);
+ return 0;
+}
+
+/**
+ * rxrpc_sock_set_security_keyring - Set the security keyring for a kernel service
+ * @sk: The socket to set the keyring on
+ * @keyring: The keyring to set
+ *
+ * Set the server security keyring on an rxrpc socket. This is used to provide
+ * the encryption keys for a kernel service.
+ *
+ * Return: %0 if successful and a negative error code otherwise.
+ */
+int rxrpc_sock_set_security_keyring(struct sock *sk, struct key *keyring)
+{
+ struct rxrpc_sock *rx = rxrpc_sk(sk);
+ int ret = 0;
+
+ lock_sock(sk);
+ if (rx->securities)
+ ret = -EINVAL;
+ else if (rx->sk.sk_state != RXRPC_UNBOUND)
+ ret = -EISCONN;
+ else
+ rx->securities = key_get(keyring);
+ release_sock(sk);
+ return ret;
+}
+EXPORT_SYMBOL(rxrpc_sock_set_security_keyring);
+
+/**
+ * rxrpc_sock_set_manage_response - Set the manage-response flag for a kernel service
+ * @sk: The socket to set the keyring on
+ * @set: True to set, false to clear the flag
+ *
+ * Set the flag on an rxrpc socket to say that the caller wants to manage the
+ * RESPONSE packet and the user-defined data it may contain. Setting this
+ * means that recvmsg() will return messages with RXRPC_CHALLENGED in the
+ * control message buffer containing information about the challenge.
+ *
+ * The user should respond to the challenge by passing RXRPC_RESPOND or
+ * RXRPC_RESPOND_ABORT control messages with sendmsg() to the same call.
+ * Supplementary control messages, such as RXRPC_RESP_RXGK_APPDATA, may be
+ * included to indicate the parts the user wants to supply.
+ *
+ * The server will be passed the response data with a RXRPC_RESPONDED control
+ * message when it gets the first data from each call.
+ *
+ * Note that this is only honoured by security classes that need auxiliary data
+ * (e.g. RxGK). Those that don't offer the facility (e.g. RxKAD) respond
+ * without consulting userspace.
+ *
+ * Return: The previous setting.
+ */
+int rxrpc_sock_set_manage_response(struct sock *sk, bool set)
+{
+ struct rxrpc_sock *rx = rxrpc_sk(sk);
+ int ret;
+
+ lock_sock(sk);
+ ret = !!test_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
+ if (set)
+ set_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
+ else
+ clear_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
+ release_sock(sk);
+ return ret;
+}
+EXPORT_SYMBOL(rxrpc_sock_set_manage_response);
diff --git a/net/rxrpc/server_key.c b/net/rxrpc/server_key.c
index 3efe104b1930..0be259dd0df0 100644
--- a/net/rxrpc/server_key.c
+++ b/net/rxrpc/server_key.c
@@ -9,6 +9,11 @@
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#define RXRPC_KEY_PROVIDER
+
+#include <crypto/des.h>
+#include <crypto/krb5.h>
+#include <linux/fips.h>
#include <linux/module.h>
#include <linux/net.h>
@@ -42,6 +47,7 @@ struct key_type key_type_rxrpc_s = {
.destroy = rxrpc_destroy_s,
.describe = rxrpc_describe_s,
};
+EXPORT_SYMBOL(key_type_rxrpc_s);
/*
* Vet the description for an RxRPC server key.
@@ -60,156 +66,198 @@ static int rxrpc_vet_description_s(const char *desc)
return 0;
}
+#ifdef CONFIG_RXKAD
/*
- * Preparse a server secret key.
+ * Parse the information from a server key
+ *
+ * The data should be the 8-byte secret key.
*/
-static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
+static int rxkad_preparse_server_key(struct key_preparsed_payload *prep)
{
- const struct rxrpc_security *sec;
- unsigned int service, sec_class;
- int n;
+ struct des_ctx *des_key;
+ int err;
+
+ if (fips_enabled)
+ return -ENOPKG;
+
+ if (prep->datalen != 8)
+ return -EINVAL;
+
+ memcpy(&prep->payload.data[2], prep->data, 8);
+
+ des_key = kmalloc_obj(*des_key);
+ if (!des_key) {
+ _leave(" = -ENOMEM");
+ return -ENOMEM;
+ }
+
+ err = des_expand_key(des_key, prep->data, 8);
+ if (err) {
+ kfree_sensitive(des_key);
+ _leave(" = %d", err);
+ return err;
+ }
+
+ prep->payload.data[0] = des_key;
+ _leave(" = 0");
+ return 0;
+}
+
+static void rxkad_free_preparse_server_key(struct key_preparsed_payload *prep)
+{
+ kfree_sensitive(prep->payload.data[0]);
+}
+
+static void rxkad_destroy_server_key(struct key *key)
+{
+ kfree_sensitive(key->payload.data[0]);
+ key->payload.data[0] = NULL;
+}
+#endif
+
+#ifdef CONFIG_RXGK
+/*
+ * Parse the information from a server key
+ */
+static int rxgk_preparse_server_key(struct key_preparsed_payload *prep)
+{
+ const struct krb5_enctype *krb5;
+ struct krb5_buffer *server_key = (void *)&prep->payload.data[2];
+ unsigned int service, sec_class, kvno, enctype;
+ int n = 0;
_enter("%zu", prep->datalen);
- if (!prep->orig_description)
+ if (sscanf(prep->orig_description, "%u:%u:%u:%u%n",
+ &service, &sec_class, &kvno, &enctype, &n) != 4)
return -EINVAL;
- if (sscanf(prep->orig_description, "%u:%u%n", &service, &sec_class, &n) != 2)
+ if (prep->orig_description[n])
return -EINVAL;
- sec = rxrpc_security_lookup(sec_class);
- if (!sec)
+ krb5 = crypto_krb5_find_enctype(enctype);
+ if (!krb5)
return -ENOPKG;
- prep->payload.data[1] = (struct rxrpc_security *)sec;
+ prep->payload.data[0] = (struct krb5_enctype *)krb5;
- if (!sec->preparse_server_key)
- return -EINVAL;
+ if (prep->datalen != krb5->key_len)
+ return -EKEYREJECTED;
+
+ server_key->len = prep->datalen;
+ server_key->data = kmemdup(prep->data, prep->datalen, GFP_KERNEL);
+ if (!server_key->data)
+ return -ENOMEM;
- return sec->preparse_server_key(prep);
+ _leave(" = 0");
+ return 0;
}
-static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
+static void rxgk_free_server_key(union key_payload *payload)
{
- const struct rxrpc_security *sec = prep->payload.data[1];
+ struct krb5_buffer *server_key = (void *)&payload->data[2];
- if (sec && sec->free_preparse_server_key)
- sec->free_preparse_server_key(prep);
+ kfree_sensitive(server_key->data);
}
-static void rxrpc_destroy_s(struct key *key)
+static void rxgk_free_preparse_server_key(struct key_preparsed_payload *prep)
{
- const struct rxrpc_security *sec = key->payload.data[1];
+ rxgk_free_server_key(&prep->payload);
+}
- if (sec && sec->destroy_server_key)
- sec->destroy_server_key(key);
+static void rxgk_destroy_server_key(struct key *key)
+{
+ rxgk_free_server_key(&key->payload);
}
-static void rxrpc_describe_s(const struct key *key, struct seq_file *m)
+static void rxgk_describe_server_key(const struct key *key, struct seq_file *m)
{
- const struct rxrpc_security *sec = key->payload.data[1];
+ const struct krb5_enctype *krb5 = key->payload.data[0];
- seq_puts(m, key->description);
- if (sec && sec->describe_server_key)
- sec->describe_server_key(key, m);
+ if (krb5)
+ seq_printf(m, ": %s", krb5->name);
}
+#endif
/*
- * grab the security keyring for a server socket
+ * Preparse a server secret key.
*/
-int rxrpc_server_keyring(struct rxrpc_sock *rx, sockptr_t optval, int optlen)
+static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
{
- struct key *key;
- char *description;
+ unsigned int service, sec_class;
+ int n;
- _enter("");
+ _enter("%zu", prep->datalen);
- if (rx->securities)
+ if (!prep->orig_description)
return -EINVAL;
- if (optlen <= 0 || optlen > PAGE_SIZE - 1)
+ if (sscanf(prep->orig_description, "%u:%u%n", &service, &sec_class, &n) != 2)
return -EINVAL;
- description = memdup_sockptr_nul(optval, optlen);
- if (IS_ERR(description))
- return PTR_ERR(description);
+ prep->payload.data[1] = (void *)(uintptr_t)sec_class;
- key = request_key(&key_type_keyring, description, NULL);
- if (IS_ERR(key)) {
- kfree(description);
- _leave(" = %ld", PTR_ERR(key));
- return PTR_ERR(key);
+ switch (sec_class) {
+#ifdef CONFIG_RXKAD
+ case RXRPC_SECURITY_RXKAD:
+ return rxkad_preparse_server_key(prep);
+#endif
+#ifdef CONFIG_RXGK
+ case RXRPC_SECURITY_YFS_RXGK:
+ return rxgk_preparse_server_key(prep);
+#endif
+ default:
+ return -ENOPKG;
}
+}
- rx->securities = key;
- kfree(description);
- _leave(" = 0 [key %x]", key->serial);
- return 0;
+static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
+{
+ switch ((uintptr_t)prep->payload.data[1]) {
+#ifdef CONFIG_RXKAD
+ case RXRPC_SECURITY_RXKAD:
+ rxkad_free_preparse_server_key(prep);
+ break;
+#endif
+#ifdef CONFIG_RXGK
+ case RXRPC_SECURITY_YFS_RXGK:
+ rxgk_free_preparse_server_key(prep);
+ break;
+#endif
+ default:
+ break;
+ }
}
-/**
- * rxrpc_sock_set_security_keyring - Set the security keyring for a kernel service
- * @sk: The socket to set the keyring on
- * @keyring: The keyring to set
- *
- * Set the server security keyring on an rxrpc socket. This is used to provide
- * the encryption keys for a kernel service.
- *
- * Return: %0 if successful and a negative error code otherwise.
- */
-int rxrpc_sock_set_security_keyring(struct sock *sk, struct key *keyring)
+static void rxrpc_destroy_s(struct key *key)
{
- struct rxrpc_sock *rx = rxrpc_sk(sk);
- int ret = 0;
-
- lock_sock(sk);
- if (rx->securities)
- ret = -EINVAL;
- else if (rx->sk.sk_state != RXRPC_UNBOUND)
- ret = -EISCONN;
- else
- rx->securities = key_get(keyring);
- release_sock(sk);
- return ret;
+ switch ((uintptr_t)key->payload.data[1]) {
+#ifdef CONFIG_RXKAD
+ case RXRPC_SECURITY_RXKAD:
+ rxkad_destroy_server_key(key);
+ break;
+#endif
+#ifdef CONFIG_RXGK
+ case RXRPC_SECURITY_YFS_RXGK:
+ rxgk_destroy_server_key(key);
+ break;
+#endif
+ default:
+ break;
+ }
}
-EXPORT_SYMBOL(rxrpc_sock_set_security_keyring);
-/**
- * rxrpc_sock_set_manage_response - Set the manage-response flag for a kernel service
- * @sk: The socket to set the keyring on
- * @set: True to set, false to clear the flag
- *
- * Set the flag on an rxrpc socket to say that the caller wants to manage the
- * RESPONSE packet and the user-defined data it may contain. Setting this
- * means that recvmsg() will return messages with RXRPC_CHALLENGED in the
- * control message buffer containing information about the challenge.
- *
- * The user should respond to the challenge by passing RXRPC_RESPOND or
- * RXRPC_RESPOND_ABORT control messages with sendmsg() to the same call.
- * Supplementary control messages, such as RXRPC_RESP_RXGK_APPDATA, may be
- * included to indicate the parts the user wants to supply.
- *
- * The server will be passed the response data with a RXRPC_RESPONDED control
- * message when it gets the first data from each call.
- *
- * Note that this is only honoured by security classes that need auxiliary data
- * (e.g. RxGK). Those that don't offer the facility (e.g. RxKAD) respond
- * without consulting userspace.
- *
- * Return: The previous setting.
- */
-int rxrpc_sock_set_manage_response(struct sock *sk, bool set)
+static void rxrpc_describe_s(const struct key *key, struct seq_file *m)
{
- struct rxrpc_sock *rx = rxrpc_sk(sk);
- int ret;
-
- lock_sock(sk);
- ret = !!test_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
- if (set)
- set_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
- else
- clear_bit(RXRPC_SOCK_MANAGE_RESPONSE, &rx->flags);
- release_sock(sk);
- return ret;
+ seq_puts(m, key->description);
+
+ switch ((uintptr_t)key->payload.data[1]) {
+#ifdef CONFIG_RXGK
+ case RXRPC_SECURITY_YFS_RXGK:
+ rxgk_describe_server_key(key, m);
+ break;
+#endif
+ default:
+ break;
+ }
}
-EXPORT_SYMBOL(rxrpc_sock_set_manage_response);
--
2.47.3
next prev parent reply other threads:[~2026-11-05 0:53 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 0:52 [RFC PATCH v3 00/11] KEYS: Sanitize the garbage collector Jarkko Sakkinen
2026-11-05 0:53 ` [RFC PATCH v3 01/11] KEYS: Add key_gc_flush() for draining RCU callbacks Jarkko Sakkinen
2026-11-05 0:53 ` [RFC PATCH v3 02/11] dns_resolver: Move the key type into a separate module Jarkko Sakkinen
2026-11-05 0:53 ` [RFC PATCH v3 03/11] NFSv4: Clear idmap keyring cache when the last client unloads Jarkko Sakkinen
2026-11-05 0:53 ` [RFC PATCH v3 04/11] smb: client: Clear idmap/SPNEGO caches when the last session is unloaded Jarkko Sakkinen
2026-11-05 0:53 ` [RFC PATCH v3 05/11] s390/cert_store: Start tracking subsystem keys Jarkko Sakkinen
2026-11-05 0:53 ` [RFC PATCH v3 06/11] KEYS: trusted: TEE: Disable sysfs bind attributes Jarkko Sakkinen
2026-11-05 0:53 ` [RFC PATCH v3 07/11] KEYS: trusted: TEE: Synchronize session lifetime Jarkko Sakkinen
2026-11-05 0:53 ` Jarkko Sakkinen [this message]
2026-11-05 0:53 ` [RFC PATCH v3 09/11] KEYS: Pin the backing kernel module for a key type Jarkko Sakkinen
2026-11-05 0:53 ` [RFC PATCH v3 10/11] KEYS: Remove key_type_dead Jarkko Sakkinen
2026-11-05 0:53 ` [RFC PATCH v3 11/11] KEYS: key_garbage_collector(): process in chunks Jarkko Sakkinen
2026-11-05 1:04 ` [RFC PATCH v3 00/11] KEYS: Sanitize the garbage collector Jarkko Sakkinen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261105005311.804098-9-jarkko@kernel.org \
--to=jarkko@kernel.org \
--cc=James.Bottomley@HansenPartnership.com \
--cc=agordeev@linux.ibm.com \
--cc=anna@kernel.org \
--cc=bharathsm@microsoft.com \
--cc=borntraeger@linux.ibm.com \
--cc=davem@davemloft.net \
--cc=dhowells@redhat.com \
--cc=ebiggers@kernel.org \
--cc=edumazet@kernel.org \
--cc=gor@linux.ibm.com \
--cc=hca@linux.ibm.com \
--cc=horms@kernel.org \
--cc=jmorris@namei.org \
--cc=keyrings@vger.kernel.org \
--cc=kuba@kernel.org \
--cc=linkinjeon@kernel.org \
--cc=linux-afs@lists.infradead.org \
--cc=linux-cifs@vger.kernel.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=linux-s390@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=marc.dionne@auristor.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=paul@paul-moore.com \
--cc=pc@manguebit.org \
--cc=ronniesahlberg@gmail.com \
--cc=samba-technical@lists.samba.org \
--cc=serge@hallyn.com \
--cc=sprasad@microsoft.com \
--cc=sumit.garg@kernel.org \
--cc=svens@linux.ibm.com \
--cc=tom@talpey.com \
--cc=trondmy@kernel.org \
--cc=zohar@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox