Skip to content

Commit

Permalink
cred: switch to using atomic_long_t
Browse files Browse the repository at this point in the history
commit f8fa5d7 upstream.

There are multiple ways to grab references to credentials, and the only
protection we have against overflowing it is the memory required to do
so.

With memory sizes only moving in one direction, let's bump the reference
count to 64-bit and move it outside the realm of feasibly overflowing.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
axboe authored and gregkh committed Dec 20, 2023
1 parent 3b5daf2 commit f6a7ce5
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 36 deletions.
8 changes: 4 additions & 4 deletions include/linux/cred.h
Expand Up @@ -108,7 +108,7 @@ static inline int groups_search(const struct group_info *group_info, kgid_t grp)
* same context as task->real_cred.
*/
struct cred {
atomic_t usage;
atomic_long_t usage;
#ifdef CONFIG_DEBUG_CREDENTIALS
atomic_t subscribers; /* number of processes subscribed */
void *put_addr;
Expand Down Expand Up @@ -227,7 +227,7 @@ static inline bool cap_ambient_invariant_ok(const struct cred *cred)
*/
static inline struct cred *get_new_cred(struct cred *cred)
{
atomic_inc(&cred->usage);
atomic_long_inc(&cred->usage);
return cred;
}

Expand Down Expand Up @@ -259,7 +259,7 @@ 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_inc_not_zero(&nonconst_cred->usage))
if (!atomic_long_inc_not_zero(&nonconst_cred->usage))
return NULL;
validate_creds(cred);
nonconst_cred->non_rcu = 0;
Expand All @@ -283,7 +283,7 @@ static inline void put_cred(const struct cred *_cred)

if (cred) {
validate_creds(cred);
if (atomic_dec_and_test(&(cred)->usage))
if (atomic_long_dec_and_test(&(cred)->usage))
__put_cred(cred);
}
}
Expand Down
64 changes: 32 additions & 32 deletions kernel/cred.c
Expand Up @@ -102,17 +102,17 @@ static void put_cred_rcu(struct rcu_head *rcu)

#ifdef CONFIG_DEBUG_CREDENTIALS
if (cred->magic != CRED_MAGIC_DEAD ||
atomic_read(&cred->usage) != 0 ||
atomic_long_read(&cred->usage) != 0 ||
read_cred_subscribers(cred) != 0)
panic("CRED: put_cred_rcu() sees %p with"
" mag %x, put %p, usage %d, subscr %d\n",
" mag %x, put %p, usage %ld, subscr %d\n",
cred, cred->magic, cred->put_addr,
atomic_read(&cred->usage),
atomic_long_read(&cred->usage),
read_cred_subscribers(cred));
#else
if (atomic_read(&cred->usage) != 0)
panic("CRED: put_cred_rcu() sees %p with usage %d\n",
cred, atomic_read(&cred->usage));
if (atomic_long_read(&cred->usage) != 0)
panic("CRED: put_cred_rcu() sees %p with usage %ld\n",
cred, atomic_long_read(&cred->usage));
#endif

security_cred_free(cred);
Expand All @@ -137,11 +137,11 @@ static void put_cred_rcu(struct rcu_head *rcu)
*/
void __put_cred(struct cred *cred)
{
kdebug("__put_cred(%p{%d,%d})", cred,
atomic_read(&cred->usage),
kdebug("__put_cred(%p{%ld,%d})", cred,
atomic_long_read(&cred->usage),
read_cred_subscribers(cred));

BUG_ON(atomic_read(&cred->usage) != 0);
BUG_ON(atomic_long_read(&cred->usage) != 0);
#ifdef CONFIG_DEBUG_CREDENTIALS
BUG_ON(read_cred_subscribers(cred) != 0);
cred->magic = CRED_MAGIC_DEAD;
Expand All @@ -164,8 +164,8 @@ void exit_creds(struct task_struct *tsk)
{
struct cred *cred;

kdebug("exit_creds(%u,%p,%p,{%d,%d})", tsk->pid, tsk->real_cred, tsk->cred,
atomic_read(&tsk->cred->usage),
kdebug("exit_creds(%u,%p,%p,{%ld,%d})", tsk->pid, tsk->real_cred, tsk->cred,
atomic_long_read(&tsk->cred->usage),
read_cred_subscribers(tsk->cred));

cred = (struct cred *) tsk->real_cred;
Expand Down Expand Up @@ -224,7 +224,7 @@ struct cred *cred_alloc_blank(void)
if (!new)
return NULL;

atomic_set(&new->usage, 1);
atomic_long_set(&new->usage, 1);
#ifdef CONFIG_DEBUG_CREDENTIALS
new->magic = CRED_MAGIC;
#endif
Expand Down Expand Up @@ -270,7 +270,7 @@ struct cred *prepare_creds(void)
memcpy(new, old, sizeof(struct cred));

new->non_rcu = 0;
atomic_set(&new->usage, 1);
atomic_long_set(&new->usage, 1);
set_cred_subscribers(new, 0);
get_group_info(new->group_info);
get_uid(new->user);
Expand Down Expand Up @@ -358,8 +358,8 @@ int copy_creds(struct task_struct *p, unsigned long clone_flags)
p->real_cred = get_cred(p->cred);
get_cred(p->cred);
alter_cred_subscribers(p->cred, 2);
kdebug("share_creds(%p{%d,%d})",
p->cred, atomic_read(&p->cred->usage),
kdebug("share_creds(%p{%ld,%d})",
p->cred, atomic_long_read(&p->cred->usage),
read_cred_subscribers(p->cred));
inc_rlimit_ucounts(task_ucounts(p), UCOUNT_RLIMIT_NPROC, 1);
return 0;
Expand Down Expand Up @@ -452,8 +452,8 @@ int commit_creds(struct cred *new)
struct task_struct *task = current;
const struct cred *old = task->real_cred;

kdebug("commit_creds(%p{%d,%d})", new,
atomic_read(&new->usage),
kdebug("commit_creds(%p{%ld,%d})", new,
atomic_long_read(&new->usage),
read_cred_subscribers(new));

BUG_ON(task->cred != old);
Expand All @@ -462,7 +462,7 @@ int commit_creds(struct cred *new)
validate_creds(old);
validate_creds(new);
#endif
BUG_ON(atomic_read(&new->usage) < 1);
BUG_ON(atomic_long_read(&new->usage) < 1);

get_cred(new); /* we will require a ref for the subj creds too */

Expand Down Expand Up @@ -535,14 +535,14 @@ EXPORT_SYMBOL(commit_creds);
*/
void abort_creds(struct cred *new)
{
kdebug("abort_creds(%p{%d,%d})", new,
atomic_read(&new->usage),
kdebug("abort_creds(%p{%ld,%d})", new,
atomic_long_read(&new->usage),
read_cred_subscribers(new));

#ifdef CONFIG_DEBUG_CREDENTIALS
BUG_ON(read_cred_subscribers(new) != 0);
#endif
BUG_ON(atomic_read(&new->usage) < 1);
BUG_ON(atomic_long_read(&new->usage) < 1);
put_cred(new);
}
EXPORT_SYMBOL(abort_creds);
Expand All @@ -558,8 +558,8 @@ const struct cred *override_creds(const struct cred *new)
{
const struct cred *old = current->cred;

kdebug("override_creds(%p{%d,%d})", new,
atomic_read(&new->usage),
kdebug("override_creds(%p{%ld,%d})", new,
atomic_long_read(&new->usage),
read_cred_subscribers(new));

validate_creds(old);
Expand All @@ -581,8 +581,8 @@ const struct cred *override_creds(const struct cred *new)
rcu_assign_pointer(current->cred, new);
alter_cred_subscribers(old, -1);

kdebug("override_creds() = %p{%d,%d}", old,
atomic_read(&old->usage),
kdebug("override_creds() = %p{%ld,%d}", old,
atomic_long_read(&old->usage),
read_cred_subscribers(old));
return old;
}
Expand All @@ -599,8 +599,8 @@ void revert_creds(const struct cred *old)
{
const struct cred *override = current->cred;

kdebug("revert_creds(%p{%d,%d})", old,
atomic_read(&old->usage),
kdebug("revert_creds(%p{%ld,%d})", old,
atomic_long_read(&old->usage),
read_cred_subscribers(old));

validate_creds(old);
Expand Down Expand Up @@ -731,7 +731,7 @@ struct cred *prepare_kernel_cred(struct task_struct *daemon)

*new = *old;
new->non_rcu = 0;
atomic_set(&new->usage, 1);
atomic_long_set(&new->usage, 1);
set_cred_subscribers(new, 0);
get_uid(new->user);
get_user_ns(new->user_ns);
Expand Down Expand Up @@ -845,8 +845,8 @@ static void dump_invalid_creds(const struct cred *cred, const char *label,
cred == tsk->cred ? "[eff]" : "");
pr_err("->magic=%x, put_addr=%p\n",
cred->magic, cred->put_addr);
pr_err("->usage=%d, subscr=%d\n",
atomic_read(&cred->usage),
pr_err("->usage=%ld, subscr=%d\n",
atomic_long_read(&cred->usage),
read_cred_subscribers(cred));
pr_err("->*uid = { %d,%d,%d,%d }\n",
from_kuid_munged(&init_user_ns, cred->uid),
Expand Down Expand Up @@ -918,9 +918,9 @@ EXPORT_SYMBOL(__validate_process_creds);
*/
void validate_creds_for_do_exit(struct task_struct *tsk)
{
kdebug("validate_creds_for_do_exit(%p,%p{%d,%d})",
kdebug("validate_creds_for_do_exit(%p,%p{%ld,%d})",
tsk->real_cred, tsk->cred,
atomic_read(&tsk->cred->usage),
atomic_long_read(&tsk->cred->usage),
read_cred_subscribers(tsk->cred));

__validate_process_creds(tsk, __FILE__, __LINE__);
Expand Down

0 comments on commit f6a7ce5

Please sign in to comment.