From: David Howells <dhowells@redhat.com>
To: netdev@vger.kernel.org
Cc: David Howells <dhowells@redhat.com>,
Marc Dionne <marc.dionne@auristor.com>,
Jakub Kicinski <kuba@kernel.org>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
Christian Brauner <brauner@kernel.org>,
Chuck Lever <chuck.lever@oracle.com>,
linux-afs@lists.infradead.org, linux-kernel@vger.kernel.org,
Herbert Xu <herbert@gondor.apana.org.au>,
linux-crypto@vger.kernel.org
Subject: [PATCH net-next v2 08/13] rxrpc: rxgk: Implement connection rekeying
Date: Mon, 7 Apr 2025 17:11:21 +0100 [thread overview]
Message-ID: <20250407161130.1349147-9-dhowells@redhat.com> (raw)
In-Reply-To: <20250407161130.1349147-1-dhowells@redhat.com>
Implement rekeying of connections with the RxGK security class. This
involves regenerating the keys with a different key number as part of the
input data after a certain amount of time or a certain amount of bytes
encrypted. Rekeying may be triggered by either end.
The LSW of the key number is inserted into the security-specific field in
the RX header, and we try and expand it to 32-bits to make it last longer.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: Herbert Xu <herbert@gondor.apana.org.au>
cc: "David S. Miller" <davem@davemloft.net>
cc: Chuck Lever <chuck.lever@oracle.com>
cc: Eric Dumazet <edumazet@google.com>
cc: Jakub Kicinski <kuba@kernel.org>
cc: Paolo Abeni <pabeni@redhat.com>
cc: Simon Horman <horms@kernel.org>
cc: linux-afs@lists.infradead.org
cc: linux-crypto@vger.kernel.org
cc: netdev@vger.kernel.org
---
include/trace/events/rxrpc.h | 24 ++++++
net/rxrpc/ar-internal.h | 5 +-
net/rxrpc/conn_object.c | 1 +
net/rxrpc/rxgk.c | 158 +++++++++++++++++++++++++++++++++--
4 files changed, 181 insertions(+), 7 deletions(-)
diff --git a/include/trace/events/rxrpc.h b/include/trace/events/rxrpc.h
index aab81e8196ae..920439df1f6f 100644
--- a/include/trace/events/rxrpc.h
+++ b/include/trace/events/rxrpc.h
@@ -2725,6 +2725,30 @@ TRACE_EVENT(rxrpc_rack_timer,
ktime_to_us(__entry->delay))
);
+TRACE_EVENT(rxrpc_rxgk_rekey,
+ TP_PROTO(struct rxrpc_connection *conn,
+ unsigned int current_key, unsigned int requested_key),
+
+ TP_ARGS(conn, current_key, requested_key),
+
+ TP_STRUCT__entry(
+ __field(unsigned int, conn)
+ __field(unsigned int, current_key)
+ __field(unsigned int, requested_key)
+ ),
+
+ TP_fast_assign(
+ __entry->conn = conn->debug_id;
+ __entry->current_key = current_key;
+ __entry->requested_key = requested_key;
+ ),
+
+ TP_printk("C=%08x cur=%x req=%x",
+ __entry->conn,
+ __entry->current_key,
+ __entry->requested_key)
+ );
+
#undef EM
#undef E_
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index c8d66a02c8fe..d23ea4710cb2 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -565,13 +565,16 @@ struct rxrpc_connection {
u32 nonce; /* response re-use preventer */
} rxkad;
struct {
- struct rxgk_context *keys[1];
+ struct rxgk_context *keys[4]; /* (Re-)keying buffer */
u64 start_time; /* The start time for TK derivation */
u8 nonce[20]; /* Response re-use preventer */
u32 enctype; /* Kerberos 5 encoding type */
+ u32 key_number; /* Current key number */
} rxgk;
};
+ rwlock_t security_use_lock; /* Security use/modification lock */
struct sk_buff *tx_response; /* Response packet to be transmitted */
+
unsigned long flags;
unsigned long events;
unsigned long idle_timestamp; /* Time at which last became idle */
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index f1e36cba9f4c..6733a7692443 100644
--- a/net/rxrpc/conn_object.c
+++ b/net/rxrpc/conn_object.c
@@ -73,6 +73,7 @@ struct rxrpc_connection *rxrpc_alloc_connection(struct rxrpc_net *rxnet,
skb_queue_head_init(&conn->rx_queue);
conn->rxnet = rxnet;
conn->security = &rxrpc_no_security;
+ rwlock_init(&conn->security_use_lock);
spin_lock_init(&conn->state_lock);
conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
conn->idle_timestamp = jiffies;
diff --git a/net/rxrpc/rxgk.c b/net/rxrpc/rxgk.c
index 02752eeb2395..8b1ccdf8bc58 100644
--- a/net/rxrpc/rxgk.c
+++ b/net/rxrpc/rxgk.c
@@ -76,11 +76,155 @@ static void rxgk_describe_server_key(const struct key *key, struct seq_file *m)
seq_printf(m, ": %s", krb5->name);
}
+/*
+ * Handle rekeying the connection when we see our limits overrun or when the
+ * far side decided to rekey.
+ *
+ * Returns a ref on the context if successful or -ESTALE if the key is out of
+ * date.
+ */
+static struct rxgk_context *rxgk_rekey(struct rxrpc_connection *conn,
+ const u16 *specific_key_number)
+{
+ struct rxgk_context *gk, *dead = NULL;
+ unsigned int key_number, current_key, mask = ARRAY_SIZE(conn->rxgk.keys) - 1;
+ bool crank = false;
+
+ _enter("%d", specific_key_number ? *specific_key_number : -1);
+
+ mutex_lock(&conn->security_lock);
+
+ current_key = conn->rxgk.key_number;
+ if (!specific_key_number) {
+ key_number = current_key;
+ } else {
+ if (*specific_key_number == (u16)current_key)
+ key_number = current_key;
+ else if (*specific_key_number == (u16)(current_key - 1))
+ key_number = current_key - 1;
+ else if (*specific_key_number == (u16)(current_key + 1))
+ goto crank_window;
+ else
+ goto bad_key;
+ }
+
+ gk = conn->rxgk.keys[key_number & mask];
+ if (!gk)
+ goto generate_key;
+ if (!specific_key_number &&
+ test_bit(RXGK_TK_NEEDS_REKEY, &gk->flags))
+ goto crank_window;
+
+grab:
+ refcount_inc(&gk->usage);
+ mutex_unlock(&conn->security_lock);
+ rxgk_put(dead);
+ return gk;
+
+crank_window:
+ trace_rxrpc_rxgk_rekey(conn, current_key,
+ specific_key_number ? *specific_key_number : -1);
+ if (current_key == UINT_MAX)
+ goto bad_key;
+ if (current_key + 1 == UINT_MAX)
+ set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags);
+
+ key_number = current_key + 1;
+ if (WARN_ON(conn->rxgk.keys[key_number & mask]))
+ goto bad_key;
+ crank = true;
+
+generate_key:
+ gk = conn->rxgk.keys[current_key & mask];
+ gk = rxgk_generate_transport_key(conn, gk->key, key_number, GFP_NOFS);
+ if (IS_ERR(gk)) {
+ mutex_unlock(&conn->security_lock);
+ return gk;
+ }
+
+ write_lock(&conn->security_use_lock);
+ if (crank) {
+ current_key++;
+ conn->rxgk.key_number = current_key;
+ dead = conn->rxgk.keys[(current_key - 2) & mask];
+ conn->rxgk.keys[(current_key - 2) & mask] = NULL;
+ }
+ conn->rxgk.keys[current_key & mask] = gk;
+ write_unlock(&conn->security_use_lock);
+ goto grab;
+
+bad_key:
+ mutex_unlock(&conn->security_lock);
+ return ERR_PTR(-ESTALE);
+}
+
+/*
+ * Get the specified keying context.
+ *
+ * Returns a ref on the context if successful or -ESTALE if the key is out of
+ * date.
+ */
static struct rxgk_context *rxgk_get_key(struct rxrpc_connection *conn,
- u16 *specific_key_number)
+ const u16 *specific_key_number)
{
- refcount_inc(&conn->rxgk.keys[0]->usage);
- return conn->rxgk.keys[0];
+ struct rxgk_context *gk;
+ unsigned int key_number, current_key, mask = ARRAY_SIZE(conn->rxgk.keys) - 1;
+
+ _enter("{%u},%d",
+ conn->rxgk.key_number, specific_key_number ? *specific_key_number : -1);
+
+ read_lock(&conn->security_use_lock);
+
+ current_key = conn->rxgk.key_number;
+ if (!specific_key_number) {
+ key_number = current_key;
+ } else {
+ /* Only the bottom 16 bits of the key number are exposed in the
+ * header, so we try and keep the upper 16 bits in step. The
+ * whole 32 bits are used to generate the TK.
+ */
+ if (*specific_key_number == (u16)current_key)
+ key_number = current_key;
+ else if (*specific_key_number == (u16)(current_key - 1))
+ key_number = current_key - 1;
+ else if (*specific_key_number == (u16)(current_key + 1))
+ goto rekey;
+ else
+ goto bad_key;
+ }
+
+ gk = conn->rxgk.keys[key_number & mask];
+ if (!gk)
+ goto slow_path;
+ if (!specific_key_number &&
+ key_number < UINT_MAX) {
+ if (time_after(jiffies, gk->expiry) ||
+ gk->bytes_remaining < 0) {
+ set_bit(RXGK_TK_NEEDS_REKEY, &gk->flags);
+ goto slow_path;
+ }
+
+ if (test_bit(RXGK_TK_NEEDS_REKEY, &gk->flags))
+ goto slow_path;
+ }
+
+ refcount_inc(&gk->usage);
+ read_unlock(&conn->security_use_lock);
+ return gk;
+
+rekey:
+ _debug("rekey");
+ if (current_key == UINT_MAX)
+ goto bad_key;
+ gk = conn->rxgk.keys[current_key & mask];
+ if (gk)
+ set_bit(RXGK_TK_NEEDS_REKEY, &gk->flags);
+slow_path:
+ read_unlock(&conn->security_use_lock);
+ return rxgk_rekey(conn, specific_key_number);
+bad_key:
+ read_unlock(&conn->security_use_lock);
+ return ERR_PTR(-ESTALE);
}
/*
@@ -92,7 +236,8 @@ static int rxgk_init_connection_security(struct rxrpc_connection *conn,
struct rxgk_context *gk;
int ret;
- _enter("{%d},{%x}", conn->debug_id, key_serial(conn->key));
+ _enter("{%d,%u},{%x}",
+ conn->debug_id, conn->rxgk.key_number, key_serial(conn->key));
conn->security_ix = token->security_index;
conn->security_level = token->rxgk->level;
@@ -102,11 +247,12 @@ static int rxgk_init_connection_security(struct rxrpc_connection *conn,
do_div(conn->rxgk.start_time, 100);
}
- gk = rxgk_generate_transport_key(conn, token->rxgk, 0, GFP_NOFS);
+ gk = rxgk_generate_transport_key(conn, token->rxgk, conn->rxgk.key_number,
+ GFP_NOFS);
if (IS_ERR(gk))
return PTR_ERR(gk);
conn->rxgk.enctype = gk->krb5->etype;
- conn->rxgk.keys[0] = gk;
+ conn->rxgk.keys[gk->key_number & 3] = gk;
switch (conn->security_level) {
case RXRPC_SECURITY_PLAIN:
next prev parent reply other threads:[~2025-04-07 16:12 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-04-07 16:11 [PATCH net-next v2 00/13] rxrpc, afs: Add AFS GSSAPI security class to AF_RXRPC and kafs David Howells
2025-04-07 16:11 ` [PATCH net-next v2 01/13] rxrpc: kdoc: Update function descriptions and add link from rxrpc.rst David Howells
2025-04-07 16:11 ` [PATCH net-next v2 02/13] rxrpc: Pull out certain app callback funcs into an ops table David Howells
2025-04-07 16:11 ` [PATCH net-next v2 03/13] rxrpc: Allow CHALLENGEs to the passed to the app for a RESPONSE David Howells
2025-04-10 2:06 ` Jakub Kicinski
2025-04-10 6:48 ` David Howells
2025-04-07 16:11 ` [PATCH net-next v2 04/13] rxrpc: Add the security index for yfs-rxgk David Howells
2025-04-07 16:11 ` [PATCH net-next v2 05/13] rxrpc: Add YFS RxGK (GSSAPI) security class David Howells
2025-04-07 16:11 ` [PATCH net-next v2 06/13] rxrpc: rxgk: Provide infrastructure and key derivation David Howells
2025-04-10 2:03 ` Jakub Kicinski
2025-04-10 6:54 ` David Howells
2025-04-10 23:31 ` Jakub Kicinski
2025-04-11 7:46 ` David Howells
2025-04-07 16:11 ` [PATCH net-next v2 07/13] rxrpc: rxgk: Implement the yfs-rxgk security class (GSSAPI) David Howells
2025-04-07 16:11 ` David Howells [this message]
2025-04-07 16:11 ` [PATCH net-next v2 09/13] rxrpc: Allow the app to store private data on peer structs David Howells
2025-04-07 16:11 ` [PATCH net-next v2 10/13] rxrpc: Display security params in the afs_cb_call tracepoint David Howells
2025-04-07 16:11 ` [PATCH net-next v2 11/13] afs: Use rxgk RESPONSE to pass token for callback channel David Howells
2025-04-07 16:11 ` [PATCH net-next v2 12/13] rxrpc: Add more CHALLENGE/RESPONSE packet tracing David Howells
2025-04-07 16:11 ` [PATCH net-next v2 13/13] rxrpc: rxperf: Add test RxGK server keys David Howells
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=20250407161130.1349147-9-dhowells@redhat.com \
--to=dhowells@redhat.com \
--cc=brauner@kernel.org \
--cc=chuck.lever@oracle.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=herbert@gondor.apana.org.au \
--cc=horms@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-afs@lists.infradead.org \
--cc=linux-crypto@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=marc.dionne@auristor.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.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;
as well as URLs for NNTP newsgroup(s).