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@intel.com>
---
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
On Fri, Jan 26, 2024 at 1:57 AM Vinicius Costa Gomes
<vinicius.gomes@intel.com> 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@intel.com>
You may add:
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
I would also add:
Suggested-by: Christian Brauner <brauner@kernel.org>
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
>
Amir Goldstein <amir73il@gmail.com> writes:
> On Fri, Jan 26, 2024 at 1:57 AM Vinicius Costa Gomes
> <vinicius.gomes@intel.com> 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@intel.com>
>
> You may add:
> Reviewed-by: Amir Goldstein <amir73il@gmail.com>
>
> I would also add:
> Suggested-by: Christian Brauner <brauner@kernel.org>
>
Forgot about that one.
Cheers,
--
Vinicius
© 2016 - 2025 Red Hat, Inc.