Re: [PATCH net v2 12/16] keys: Add refcounting to user-defined key type payload
From: Jarkko Sakkinen <jarkko@kernel.org>
Date: 2026-07-11 17:51:23
Also in:
keyrings, lkml
On Fri, Jul 10, 2026 at 08:22:14PM +0100, David Howells wrote:
Add refcounting to user-defined key type payload so that a kernel service
wanting to use such a key can hold onto the payload without the RCU read
lock held in order that it can do an allocation without having to be
concerned with the key getting updated.
This is the first part of the fix for the AF_RXRPC challenge response
generation code.
Fixes: 5800b1cf3fd8 ("rxrpc: Allow CHALLENGEs to the passed to the app for a RESPONSE")I get the relaxing part when it comes to RCU read lock but why does it carry fixes tag? The commit message does not do a great job on explaining this part.
quoted hunk ↗ jump to hunk
Link: https://sashiko.dev/#/patchset/20260624163819.3017002-1-dhowells%40redhat.com Signed-off-by: David Howells <dhowells@redhat.com> cc: Marc Dionne <marc.dionne@auristor.com> cc: Jeffrey Altman <redacted> cc: Eric Dumazet <edumazet@google.com> cc: "David S. Miller" <davem@davemloft.net> cc: Jakub Kicinski <kuba@kernel.org> cc: Paolo Abeni <pabeni@redhat.com> cc: Simon Horman <horms@kernel.org> cc: Jarkko Sakkinen <jarkko@kernel.org> cc: linux-afs@lists.infradead.org cc: keyrings@vger.kernel.org cc: stable@kernel.org --- include/keys/user-type.h | 2 ++ net/dns_resolver/dns_key.c | 1 + security/keys/user_defined.c | 23 ++++++++++++++++------- 3 files changed, 19 insertions(+), 7 deletions(-)diff --git a/include/keys/user-type.h b/include/keys/user-type.h index 386c31432789..7002a993a472 100644 --- a/include/keys/user-type.h +++ b/include/keys/user-type.h@@ -26,6 +26,7 @@ */ struct user_key_payload { struct rcu_head rcu; /* RCU destructor */ + refcount_t ref; unsigned short datalen; /* length of this data */ char data[] __aligned(__alignof__(u64)); /* actual data */ };@@ -37,6 +38,7 @@ struct key_preparsed_payload; extern int user_preparse(struct key_preparsed_payload *prep); extern void user_free_preparse(struct key_preparsed_payload *prep); +void put_user_key_payload(struct user_key_payload *payload); extern int user_update(struct key *key, struct key_preparsed_payload *prep); extern void user_revoke(struct key *key); extern void user_destroy(struct key *key);diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c index c3c8c3240ef9..aa3c058f4095 100644 --- a/net/dns_resolver/dns_key.c +++ b/net/dns_resolver/dns_key.c@@ -208,6 +208,7 @@ dns_resolver_preparse(struct key_preparsed_payload *prep) kleave(" = -ENOMEM"); return -ENOMEM; } + refcount_set(&upayload->ref, 1); upayload->datalen = result_len; memcpy(upayload->data, data, result_len);diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c index 6f88b507f927..90c1bd5d7dfe 100644 --- a/security/keys/user_defined.c +++ b/security/keys/user_defined.c@@ -67,6 +67,7 @@ int user_preparse(struct key_preparsed_payload *prep) upayload = kmalloc_flex(*upayload, data, datalen); if (!upayload) return -ENOMEM; + refcount_set(&upayload->ref, 1); /* attach the data */ prep->quotalen = datalen;@@ -88,12 +89,22 @@ EXPORT_SYMBOL_GPL(user_free_preparse); static void user_free_payload_rcu(struct rcu_head *head) { - struct user_key_payload *payload; + struct user_key_payload *payload = + container_of(head, struct user_key_payload, rcu); - payload = container_of(head, struct user_key_payload, rcu); kfree_sensitive(payload); } +/* + * Free a user defined key payload. + */ +void put_user_key_payload(struct user_key_payload *payload) +{ + if (payload && refcount_dec_and_test(&payload->ref)) + call_rcu(&payload->rcu, user_free_payload_rcu); +} +EXPORT_SYMBOL_GPL(put_user_key_payload); + /* * update a user defined key * - the key's semaphore is write-locked@@ -115,8 +126,7 @@ int user_update(struct key *key, struct key_preparsed_payload *prep) rcu_assign_keypointer(key, prep->payload.data[0]); prep->payload.data[0] = NULL; - if (zap) - call_rcu(&zap->rcu, user_free_payload_rcu); + put_user_key_payload(zap); return ret; } EXPORT_SYMBOL_GPL(user_update);@@ -134,7 +144,7 @@ void user_revoke(struct key *key) if (upayload) { rcu_assign_keypointer(key, NULL); - call_rcu(&upayload->rcu, user_free_payload_rcu); + put_user_key_payload(upayload); } }@@ -147,9 +157,8 @@ void user_destroy(struct key *key) { struct user_key_payload *upayload = key->payload.data[0]; - kfree_sensitive(upayload); + put_user_key_payload(upayload); } - EXPORT_SYMBOL_GPL(user_destroy); /*
BR, Jarkko