Re: [RFC v2 2/4] cred: Add a light version of override/revert_creds()
From: Amir Goldstein
Date: Fri Jan 26 2024 - 09:34:44 EST
On Fri, Jan 26, 2024 at 1:57 AM Vinicius Costa Gomes
<vinicius.gomes@xxxxxxxxx> wrote:
>
> Add a light version of override/revert_creds(), this should only be
> used when the credentials in question will outlive the critical
> section and the critical section doesn't change the ->usage of the
> credentials.
>
> To make their usage less error prone, introduce cleanup guards asto be
> used like this:
>
> guard(cred)(credentials_to_override_and_restore);
>
> or this:
>
> scoped_guard(cred, credentials_to_override_and_restore) {
> /* with credentials overridden */
> }
>
> Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@xxxxxxxxx>
You may add:
Reviewed-by: Amir Goldstein <amir73il@xxxxxxxxx>
I would also add:
Suggested-by: Christian Brauner <brauner@xxxxxxxxxx>
Thanks,
Amir.
> ---
> include/linux/cred.h | 21 +++++++++++++++++++++
> kernel/cred.c | 6 +++---
> 2 files changed, 24 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/cred.h b/include/linux/cred.h
> index 2976f534a7a3..e9f2237e4bf8 100644
> --- a/include/linux/cred.h
> +++ b/include/linux/cred.h
> @@ -172,6 +172,27 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred)
> cred->cap_inheritable));
> }
>
> +/*
> + * Override creds without bumping reference count. Caller must ensure
> + * reference remains valid or has taken reference. Almost always not the
> + * interface you want. Use override_creds()/revert_creds() instead.
> + */
> +static inline const struct cred *override_creds_light(const struct cred *override_cred)
> +{
> + const struct cred *old = current->cred;
> +
> + rcu_assign_pointer(current->cred, override_cred);
> + return old;
> +}
> +
> +static inline void revert_creds_light(const struct cred *revert_cred)
> +{
> + rcu_assign_pointer(current->cred, revert_cred);
> +}
> +
> +DEFINE_GUARD(cred, const struct cred *, _T = override_creds_light(_T),
> + revert_creds_light(_T));
> +
> /**
> * get_new_cred_many - Get references on a new set of credentials
> * @cred: The new credentials to reference
> diff --git a/kernel/cred.c b/kernel/cred.c
> index c033a201c808..f95f71e3ac1d 100644
> --- a/kernel/cred.c
> +++ b/kernel/cred.c
> @@ -485,7 +485,7 @@ EXPORT_SYMBOL(abort_creds);
> */
> const struct cred *override_creds(const struct cred *new)
> {
> - const struct cred *old = current->cred;
> + const struct cred *old;
>
> kdebug("override_creds(%p{%ld})", new,
> atomic_long_read(&new->usage));
> @@ -499,7 +499,7 @@ const struct cred *override_creds(const struct cred *new)
> * visible to other threads under RCU.
> */
> get_new_cred((struct cred *)new);
> - rcu_assign_pointer(current->cred, new);
> + old = override_creds_light(new);
>
> kdebug("override_creds() = %p{%ld}", old,
> atomic_long_read(&old->usage));
> @@ -521,7 +521,7 @@ void revert_creds(const struct cred *old)
> kdebug("revert_creds(%p{%ld})", old,
> atomic_long_read(&old->usage));
>
> - rcu_assign_pointer(current->cred, old);
> + revert_creds_light(old);
> put_cred(override);
> }
> EXPORT_SYMBOL(revert_creds);
> --
> 2.43.0
>