Re: [PATCH net v2 12/16] keys: Add refcounting to user-defined key type payload

From: Jarkko Sakkinen

Date: Sat Jul 11 2026 - 13:51:41 EST


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.

> Link: https://sashiko.dev/#/patchset/20260624163819.3017002-1-dhowells%40redhat.com
> Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
> cc: Marc Dionne <marc.dionne@xxxxxxxxxxxx>
> cc: Jeffrey Altman <jaltman@xxxxxxxxxxxx>
> cc: Eric Dumazet <edumazet@xxxxxxxxxx>
> cc: "David S. Miller" <davem@xxxxxxxxxxxxx>
> cc: Jakub Kicinski <kuba@xxxxxxxxxx>
> cc: Paolo Abeni <pabeni@xxxxxxxxxx>
> cc: Simon Horman <horms@xxxxxxxxxx>
> cc: Jarkko Sakkinen <jarkko@xxxxxxxxxx>
> cc: linux-afs@xxxxxxxxxxxxxxxxxxx
> cc: keyrings@xxxxxxxxxxxxxxx
> cc: stable@xxxxxxxxxx
> ---
> 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