mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Eric Biggers <ebiggers@kernel.org>
To: Jarkko Sakkinen <jarkko@kernel.org>
Cc: David Howells <dhowells@redhat.com>,
	keyrings@vger.kernel.org,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Thomas Graf <tgraf@suug.ch>,
	Herbert Xu <herbert@gondor.apana.org.au>,
	Paul Moore <paul@paul-moore.com>,
	James Morris <jmorris@namei.org>,
	"Serge E. Hallyn" <serge@hallyn.com>,
	open list <linux-kernel@vger.kernel.org>,
	"open list:RHASHTABLE" <linux-crypto@vger.kernel.org>,
	"open list:SECURITY SUBSYSTEM"
	<linux-security-module@vger.kernel.org>
Subject: Re: [PATCH v3 5/6] KEYS: Replace assoc_array with rhashtable
Date: Mon, 26 Oct 2026 18:29:52 -0700	[thread overview]
Message-ID: <20261027012952.GC2395@quark> (raw)
In-Reply-To: <20261025001105.1824178-6-jarkko@kernel.org>

On Sun, Oct 25, 2026 at 03:10:13AM +0300, Jarkko Sakkinen wrote:
> The keyring subsystem depends on assoc_array for searching keys by their
> description, type and domain. It is the sole user of this data structure,
> which has during the age of LLMs transformed into a maintenance nightmare.

Maybe reword to be more specific, like: "It is the sole user of this
data structure, which has 1700 lines of code with no test suite and has
had many bugs reported over the years, with LLMs now finding more."

>  struct key_tag {
>  	struct rcu_head		rcu;
> @@ -118,18 +118,7 @@ struct key_tag {
>  struct keyring_index_key {
>  	/* [!] If this structure is altered, the union in struct key must change too! */
>  	unsigned long		hash;			/* Hash value */

As I suggested before, I think the hash field (here and in struct key)
should be changed to u32, since that is all that is used now.  Also, the
SipHash value can just be truncated from 64 bits to 32 instead of
"folded".  Also, the pointers can be used directly in the computation
once again, now that they're no longer needed for the assoc_array key.
(And that means the domain_id and type_id can be removed.)

Are those simplifications planned for follow-up commits, maybe?

> +static int keyring_obj_cmpfn(struct rhashtable_compare_arg *arg,
> +			     const void *obj)
> +{
> +	const struct keyring_link *link = obj;
> +	const struct key *key = rcu_dereference_check(link->key, true);

This probably should use keyring_link_key(), which should be moved up to
earlier in the file.  Or rcu_dereference(), since it looks like this is
always called under the RCU lock.

> +static void keyring_index_free(struct key *keyring)
> +{
> +	struct keyring_index *index = keyring_index_locked(keyring);
> +
> +	if (!index)
> +		return;
> +
> +	rcu_assign_pointer(keyring->index, NULL);
> +	queue_rcu_work(system_dfl_wq, &index->rcu_work);

It's queue_rcu_work() rather than call_rcu() because
rhashtable_destroy() can sleep, right?  Commenting that might help.

> +static struct keyring_index *keyring_get_index(struct key *keyring)
> +{
> +	struct keyring_index *links __free(kfree) =
> +		keyring_index_locked(keyring);
> +	int ret;
> +
> +	if (links)
> +		return_ptr(links);
> +
> +	links = kzalloc_obj(struct keyring_index);
> +	if (!links)
> +		return ERR_PTR(-ENOMEM);
> +	ret = rhashtable_init(&links->ht, &keyring_link_params);
> +	if (ret < 0)
> +		return ERR_PTR(ret);
> +
> +	INIT_LIST_HEAD(&links->list);
> +	INIT_RCU_WORK(&links->rcu_work, keyring_index_free_work);
> +	rcu_assign_pointer(keyring->index, links);
> +	return_ptr(links);
> +}

Assigning the live index to a __free variable is kind of weird (even
though return_ptr handles it).  I think it would be simpler without
scoped cleanup here:

static struct keyring_index *keyring_get_index(struct key *keyring)
{
	struct keyring_index *links = keyring_index_locked(keyring);
	int ret;

	if (links)
		return links;

	links = kzalloc_obj(struct keyring_index);
	if (!links)
		return ERR_PTR(-ENOMEM);
	ret = rhashtable_init(&links->ht, &keyring_link_params);
	if (ret < 0) {
		kfree(links);
		return ERR_PTR(ret);
	}

	INIT_LIST_HEAD(&links->list);
	INIT_RCU_WORK(&links->rcu_work, keyring_index_free_work);
	rcu_assign_pointer(keyring->index, links);
	return links;
}

> +void __key_link(struct key *keyring, struct key *key, struct keyring_link *edit[2])
>  {
> +	struct keyring_index *index = keyring_index_locked(keyring);
> +	int ret = 0;
> +
>  	__key_get(key);
> -	assoc_array_insert_set_object(*_edit, keyring_key_to_ptr(key));
> -	assoc_array_apply_edit(*_edit);
> -	*_edit = NULL;
> +	rcu_assign_pointer(edit[0]->key, key);
> +
> +	if (edit[1]) {
> +		ret = rhashtable_replace_fast(&index->ht, &edit[1]->node,
> +					      &edit[0]->node, keyring_link_params);
> +		if (ret)
> +			goto out;

rhashtable_replace_fast() shouldn't fail here, but if it does, we should
put the reference to the key that was taken earlier in the function:

		if (WARN_ON(ret)) {
			key_put(key);
			return;
		}

(That would replace the 'out' label and its WARN_ON.)

>  void __key_link_end(struct key *keyring,
>  		    const struct keyring_index_key *index_key,
> -		    struct assoc_array_edit *edit)
> +		    struct keyring_link *edit[2])
>  	__releases(&keyring->sem)
>  	__releases(&keyring_serialise_link_lock)
>  {
> +	struct keyring_link *link = edit[0];
> +
>  	BUG_ON(index_key->type == NULL);
>  	kenter("%d,%s,", keyring->serial, index_key->type->name);
>  
> -	if (edit) {
> -		if (!edit->dead_leaf) {
> +	if (link) {
> +		if (!edit[1]) {
>  			key_payload_reserve(keyring,
>  				keyring->datalen - KEYQUOTA_LINK_BYTES);
> +			WARN_ON(rhashtable_remove_fast(&keyring_index_locked(keyring)->ht,
> +						       &link->node,
> +						       keyring_link_params));
> +			call_rcu(&link->rcu, keyring_link_free_rcu);
> +		} else {
> +			kfree(link);
>  		}
> -		assoc_array_cancel_edit(edit);
> +
> +		edit[0] = NULL;
> +		edit[1] = NULL;
>  	}

How about replacing 'struct keyring_link *edit[2]' with a named struct?
It's kind of hard to remember what [0] and [1] are.

- Eric

  reply	other threads:[~2026-10-27  1:29 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-25  0:10 [PATCH v3 0/6] " Jarkko Sakkinen
2026-10-25  0:10 ` [PATCH v3 1/6] KEYS: Expand key->{datalen,quotalen} to unsigned int Jarkko Sakkinen
2026-10-25  0:10 ` [PATCH v3 2/6] KEYS: Reject descriptions larger than KEY_MAX_DESC_SIZE Jarkko Sakkinen
2026-10-25  0:10 ` [PATCH v3 3/6] KEYS: Verify the key identity in __key_unlink_begin Jarkko Sakkinen
2026-10-25  0:10 ` [PATCH v3 4/6] KEYS: Introduce keyring_is_empty() Jarkko Sakkinen
2026-10-26 23:55   ` Eric Biggers
2026-10-27  0:01     ` Jarkko Sakkinen
2026-10-25  0:10 ` [PATCH v3 5/6] KEYS: Replace assoc_array with rhashtable Jarkko Sakkinen
2026-10-27  1:29   ` Eric Biggers [this message]
2026-10-27  2:56     ` Jarkko Sakkinen
2026-10-27  3:00     ` Jarkko Sakkinen
2026-10-25  0:10 ` [PATCH v3 6/6] lib: Remove assoc_array Jarkko Sakkinen
2026-10-26 23:57   ` Eric Biggers

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=20261027012952.GC2395@quark \
    --to=ebiggers@kernel.org \
    --cc=akpm@linux-foundation.org \
    --cc=dhowells@redhat.com \
    --cc=herbert@gondor.apana.org.au \
    --cc=jarkko@kernel.org \
    --cc=jmorris@namei.org \
    --cc=keyrings@vger.kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=paul@paul-moore.com \
    --cc=serge@hallyn.com \
    --cc=tgraf@suug.ch \
    --cc=torvalds@linux-foundation.org \
    /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

all inboxes | Powered by JetHome®