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 to be used like this: guard(cred)(credentials_to_override_and_restore); or this: scoped_guard(cred, credentials_to_override_and_restore) { /* with credentials overridden */ } Suggested-by: Christian Brauner <brauner@xxxxxxxxxx> Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@xxxxxxxxx> Reviewed-by: Amir Goldstein <amir73il@xxxxxxxxx> --- 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..be1e211d82e0 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_LOCK_GUARD_1(cred, const struct cred, _T->lock = override_creds_light(_T->lock), + revert_creds_light(_T->lock)); + /** * 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.1