* [PATCH] cred: clarify usage of get_cred_rcu()
@ 2026-02-20 9:19 Alice Ryhl
2026-02-27 2:18 ` Paul Moore
0 siblings, 1 reply; 4+ messages in thread
From: Alice Ryhl @ 2026-02-20 9:19 UTC (permalink / raw)
To: Paul Moore, Serge Hallyn; +Cc: linux-security-module, linux-kernel, Alice Ryhl
After being confused by looking at get_cred() and get_cred_rcu(), I
figured out what's going on. Thus, add some comments to clarify how
get_cred_rcu() works for the benefit of others looking in the future.
Note that in principle we could add an assertion that non_rcu is zero in
the failure path of atomic_long_inc_not_zero().
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
include/linux/cred.h | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/include/linux/cred.h b/include/linux/cred.h
index ed1609d78cd7..95dcf5e967c7 100644
--- a/include/linux/cred.h
+++ b/include/linux/cred.h
@@ -213,32 +213,50 @@ * get_cred_many - Get references on a set of credentials
static inline const struct cred *get_cred_many(const struct cred *cred, int nr)
{
struct cred *nonconst_cred = (struct cred *) cred;
if (!cred)
return cred;
nonconst_cred->non_rcu = 0;
atomic_long_add(nr, &nonconst_cred->usage);
return cred;
}
/*
* get_cred - Get a reference on a set of credentials
* @cred: The credentials to reference
*
* Get a reference on the specified set of credentials. The caller must
* release the reference. If %NULL is passed, it is returned with no action.
*
* This is used to deal with a committed set of credentials.
*/
static inline const struct cred *get_cred(const struct cred *cred)
{
return get_cred_many(cred, 1);
}
+/*
+ * get_cred_rcu - Get a reference on a set of credentials under rcu
+ * @cred: The credentials to reference
+ *
+ * Get a reference on the specified set of credentials, or %NULL if the last
+ * refcount has already been put.
+ *
+ * This is used to obtain a reference under an rcu read lock.
+ */
static inline const struct cred *get_cred_rcu(const struct cred *cred)
{
struct cred *nonconst_cred = (struct cred *) cred;
if (!cred)
return NULL;
if (!atomic_long_inc_not_zero(&nonconst_cred->usage))
return NULL;
+ /*
+ * If non_rcu is not already zero, then this call to get_cred_rcu() is
+ * probably wrong because if 'usage' goes to zero prior to this call,
+ * then get_cred_rcu() assumes it is freed with rcu.
+ *
+ * However, an exception to this is using get_cred_rcu() in cases where
+ * get_cred() would have been okay. To support that case, we do not
+ * check non_rcu and set it to zero regardless.
+ */
nonconst_cred->non_rcu = 0;
return cred;
}
--
2.53.0.345.g96ddfc5eaa-goog
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH] cred: clarify usage of get_cred_rcu()
2026-02-20 9:19 [PATCH] cred: clarify usage of get_cred_rcu() Alice Ryhl
@ 2026-02-27 2:18 ` Paul Moore
2026-02-27 10:04 ` Alice Ryhl
0 siblings, 1 reply; 4+ messages in thread
From: Paul Moore @ 2026-02-27 2:18 UTC (permalink / raw)
To: Alice Ryhl; +Cc: Serge Hallyn, linux-security-module, linux-kernel
On Fri, Feb 20, 2026 at 4:19 AM Alice Ryhl <aliceryhl@google.com> wrote:
>
> After being confused by looking at get_cred() and get_cred_rcu(), I
> figured out what's going on. Thus, add some comments to clarify how
> get_cred_rcu() works for the benefit of others looking in the future.
>
> Note that in principle we could add an assertion that non_rcu is zero in
> the failure path of atomic_long_inc_not_zero().
That would be interesting to add a WARN_ON() there and see what
happens. Hopefully nothing, but one never knows ;) Have you tried
this?
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> include/linux/cred.h | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
...
> +/*
> + * get_cred_rcu - Get a reference on a set of credentials under rcu
I agree this is a bit pedantic, but it looks like the bulk of the file
capitalizes RCU and technically that is correct as it is an acronym.
> + * @cred: The credentials to reference
> + *
> + * Get a reference on the specified set of credentials, or %NULL if the last
> + * refcount has already been put.
> + *
> + * This is used to obtain a reference under an rcu read lock.
I would suggest a different description:
"Get a reference to the specified set of credentials and return a
pointer to the cred struct, or %NULL if it is not possible to obtain a
new reference. After successfully taking a new reference to the
specified credentials, the cred struct will be marked for free'ing via
RCU."
> + */
> static inline const struct cred *get_cred_rcu(const struct cred *cred)
> {
> struct cred *nonconst_cred = (struct cred *) cred;
> if (!cred)
> return NULL;
> if (!atomic_long_inc_not_zero(&nonconst_cred->usage))
> return NULL;
> + /*
> + * If non_rcu is not already zero, then this call to get_cred_rcu() is
> + * probably wrong because if 'usage' goes to zero prior to this call,
> + * then get_cred_rcu() assumes it is freed with rcu.
> + *
> + * However, an exception to this is using get_cred_rcu() in cases where
> + * get_cred() would have been okay. To support that case, we do not
> + * check non_rcu and set it to zero regardless.
> + */
This is surely a matter of perspective, but the above seems a bit
wordy, and doesn't address what I believe is the important part:
setting non_rcu to zero means this credential will be freed
asynchronously via RCU. Both get_cred_rcu() and get_cred() set
non_rcu to 0/false ... although get_cred() doesn't do the non-zero
check before bumping the refcount.
I suppose we could consider adding the zero check in the get_cred()
case, but even if we ignore the KCSAN barrier, it looks like the arch
support for the inc_not_zero() case isn't nearly as good, likely
resulting in more code to execute.
> nonconst_cred->non_rcu = 0;
> return cred;
> }
> --
> 2.53.0.345.g96ddfc5eaa-goog
--
paul-moore.com
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] cred: clarify usage of get_cred_rcu()
2026-02-27 2:18 ` Paul Moore
@ 2026-02-27 10:04 ` Alice Ryhl
2026-02-27 20:49 ` Paul Moore
0 siblings, 1 reply; 4+ messages in thread
From: Alice Ryhl @ 2026-02-27 10:04 UTC (permalink / raw)
To: Paul Moore; +Cc: Serge Hallyn, linux-security-module, linux-kernel
On Thu, Feb 26, 2026 at 09:18:29PM -0500, Paul Moore wrote:
> On Fri, Feb 20, 2026 at 4:19 AM Alice Ryhl <aliceryhl@google.com> wrote:
> >
> > After being confused by looking at get_cred() and get_cred_rcu(), I
> > figured out what's going on. Thus, add some comments to clarify how
> > get_cred_rcu() works for the benefit of others looking in the future.
> >
> > Note that in principle we could add an assertion that non_rcu is zero in
> > the failure path of atomic_long_inc_not_zero().
>
> That would be interesting to add a WARN_ON() there and see what
> happens. Hopefully nothing, but one never knows ;) Have you tried
> this?
I tried just now. I put it on an Android phone, and it did not seem to
be triggered after a few minute of usage.
I can send a patch adding it if you would like?
> > Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> > ---
> > include/linux/cred.h | 18 ++++++++++++++++++
> > 1 file changed, 18 insertions(+)
>
> ...
>
> > +/*
> > + * get_cred_rcu - Get a reference on a set of credentials under rcu
>
> I agree this is a bit pedantic, but it looks like the bulk of the file
> capitalizes RCU and technically that is correct as it is an acronym.
Will do.
> > + * @cred: The credentials to reference
> > + *
> > + * Get a reference on the specified set of credentials, or %NULL if the last
> > + * refcount has already been put.
> > + *
> > + * This is used to obtain a reference under an rcu read lock.
>
> I would suggest a different description:
>
> "Get a reference to the specified set of credentials and return a
> pointer to the cred struct, or %NULL if it is not possible to obtain a
> new reference. After successfully taking a new reference to the
> specified credentials, the cred struct will be marked for free'ing via
> RCU."
I actually think it's confusing to include
After successfully taking a new reference to the specified
credentials, the cred struct will be marked for free'ing via
RCU.
in the documentation, because it makes it sounds like this method has
the _rcu() suffix because it marks the struct for free'ing via RCU. But
that is not the case. After all, get_cred() also marks it for free'ing
via RCU.
It has the _rcu() suffix because - if the cred struct is *already*
marked for free'ing via RCU, then you are allowed to do this:
rcu_read_lock();
cred = get_cred_rcu(&foo->my_cred);
rcu_read_unlock();
even if another thread might put foo->my_cred in parallel with the above
piece of code.
> > + */
> > static inline const struct cred *get_cred_rcu(const struct cred *cred)
> > {
> > struct cred *nonconst_cred = (struct cred *) cred;
> > if (!cred)
> > return NULL;
> > if (!atomic_long_inc_not_zero(&nonconst_cred->usage))
> > return NULL;
> > + /*
> > + * If non_rcu is not already zero, then this call to get_cred_rcu() is
> > + * probably wrong because if 'usage' goes to zero prior to this call,
> > + * then get_cred_rcu() assumes it is freed with rcu.
> > + *
> > + * However, an exception to this is using get_cred_rcu() in cases where
> > + * get_cred() would have been okay. To support that case, we do not
> > + * check non_rcu and set it to zero regardless.
> > + */
>
> This is surely a matter of perspective, but the above seems a bit
> wordy, and doesn't address what I believe is the important part:
> setting non_rcu to zero means this credential will be freed
> asynchronously via RCU. Both get_cred_rcu() and get_cred() set
> non_rcu to 0/false ... although get_cred() doesn't do the non-zero
> check before bumping the refcount.
I think that would be a good comment to add to get_cred(), but in the
case of get_cred_rcu(), it really should already be set to zero, because
otherwise
rcu_read_lock();
cred = get_cred_rcu(&foo->my_cred);
rcu_read_unlock();
is illegal.
> I suppose we could consider adding the zero check in the get_cred()
> case, but even if we ignore the KCSAN barrier, it looks like the arch
> support for the inc_not_zero() case isn't nearly as good, likely
> resulting in more code to execute.
I don't think that's necessary. If you use get_cred() in a scenario
where it might be zero, you have a bug.
Alice
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH] cred: clarify usage of get_cred_rcu()
2026-02-27 10:04 ` Alice Ryhl
@ 2026-02-27 20:49 ` Paul Moore
0 siblings, 0 replies; 4+ messages in thread
From: Paul Moore @ 2026-02-27 20:49 UTC (permalink / raw)
To: Alice Ryhl; +Cc: Serge Hallyn, linux-security-module, linux-kernel
On Fri, Feb 27, 2026 at 5:04 AM Alice Ryhl <aliceryhl@google.com> wrote:
> On Thu, Feb 26, 2026 at 09:18:29PM -0500, Paul Moore wrote:
> > On Fri, Feb 20, 2026 at 4:19 AM Alice Ryhl <aliceryhl@google.com> wrote:
> > >
> > > After being confused by looking at get_cred() and get_cred_rcu(), I
> > > figured out what's going on. Thus, add some comments to clarify how
> > > get_cred_rcu() works for the benefit of others looking in the future.
> > >
> > > Note that in principle we could add an assertion that non_rcu is zero in
> > > the failure path of atomic_long_inc_not_zero().
> >
> > That would be interesting to add a WARN_ON() there and see what
> > happens. Hopefully nothing, but one never knows ;) Have you tried
> > this?
>
> I tried just now. I put it on an Android phone, and it did not seem to
> be triggered after a few minute of usage.
>
> I can send a patch adding it if you would like?
It would need much more testing than running it on Android for a few
minutes before I would consider merging it :) I suspect it's probably
not worth the effort, I just thought it would be mildly interesting to
see if anything tripped the assertion.
> > > Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> > > ---
> > > include/linux/cred.h | 18 ++++++++++++++++++
> > > 1 file changed, 18 insertions(+)
> >
> > ...
> >
> > > +/*
> > > + * get_cred_rcu - Get a reference on a set of credentials under rcu
> >
> > I agree this is a bit pedantic, but it looks like the bulk of the file
> > capitalizes RCU and technically that is correct as it is an acronym.
>
> Will do.
>
> > > + * @cred: The credentials to reference
> > > + *
> > > + * Get a reference on the specified set of credentials, or %NULL if the last
> > > + * refcount has already been put.
> > > + *
> > > + * This is used to obtain a reference under an rcu read lock.
> >
> > I would suggest a different description:
> >
> > "Get a reference to the specified set of credentials and return a
> > pointer to the cred struct, or %NULL if it is not possible to obtain a
> > new reference. After successfully taking a new reference to the
> > specified credentials, the cred struct will be marked for free'ing via
> > RCU."
>
> I actually think it's confusing to include
>
> After successfully taking a new reference to the specified
> credentials, the cred struct will be marked for free'ing via
> RCU.
>
> in the documentation, because it makes it sounds like this method has
> the _rcu() suffix because it marks the struct for free'ing via RCU. But
> that is not the case. After all, get_cred() also marks it for free'ing
> via RCU.
>
> It has the _rcu() suffix because - if the cred struct is *already*
> marked for free'ing via RCU, then you are allowed to do this:
>
> rcu_read_lock();
> cred = get_cred_rcu(&foo->my_cred);
> rcu_read_unlock();
>
> even if another thread might put foo->my_cred in parallel with the above
> piece of code.
To be really nit picky, the code doesn't actually enforce these usage
guidelines, so both are "allowed" in that sense. The key difference
is that the rcu variant checks if the refcount is zero (the cred has
had its last ref dropped, but has not yet been free'd via rcu),
whereas the non-rcu variant always assumes the refcount is greater
than zero.
If you want to add a description/comment to the functions, I'd focus on that.
> > I suppose we could consider adding the zero check in the get_cred()
> > case, but even if we ignore the KCSAN barrier, it looks like the arch
> > support for the inc_not_zero() case isn't nearly as good, likely
> > resulting in more code to execute.
>
> I don't think that's necessary ...
I didn't say it was, in fact I was trying to dissuade anyone from
trying that because it will likely negatively impact performance for
minimal, if any, benefit.
--
paul-moore.com
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-02-27 20:49 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-20 9:19 [PATCH] cred: clarify usage of get_cred_rcu() Alice Ryhl
2026-02-27 2:18 ` Paul Moore
2026-02-27 10:04 ` Alice Ryhl
2026-02-27 20:49 ` Paul Moore
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox