198870ab0SDavid Howells /* Task credentials management - see Documentation/credentials.txt 2f1752eecSDavid Howells * 3f1752eecSDavid Howells * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. 4f1752eecSDavid Howells * Written by David Howells (dhowells@redhat.com) 5f1752eecSDavid Howells * 6f1752eecSDavid Howells * This program is free software; you can redistribute it and/or 7f1752eecSDavid Howells * modify it under the terms of the GNU General Public Licence 8f1752eecSDavid Howells * as published by the Free Software Foundation; either version 9f1752eecSDavid Howells * 2 of the Licence, or (at your option) any later version. 10f1752eecSDavid Howells */ 11f1752eecSDavid Howells #include <linux/module.h> 12f1752eecSDavid Howells #include <linux/cred.h> 135a0e3ad6STejun Heo #include <linux/slab.h> 14f1752eecSDavid Howells #include <linux/sched.h> 15f1752eecSDavid Howells #include <linux/key.h> 16f1752eecSDavid Howells #include <linux/keyctl.h> 17f1752eecSDavid Howells #include <linux/init_task.h> 18f1752eecSDavid Howells #include <linux/security.h> 19d84f4f99SDavid Howells #include <linux/cn_proc.h> 20d84f4f99SDavid Howells 21e0e81739SDavid Howells #if 0 22e0e81739SDavid Howells #define kdebug(FMT, ...) \ 23e0e81739SDavid Howells printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__) 24e0e81739SDavid Howells #else 25e0e81739SDavid Howells #define kdebug(FMT, ...) \ 26e0e81739SDavid Howells no_printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__) 27e0e81739SDavid Howells #endif 28e0e81739SDavid Howells 29d84f4f99SDavid Howells static struct kmem_cache *cred_jar; 30f1752eecSDavid Howells 31f1752eecSDavid Howells /* 32bb952bb9SDavid Howells * The common credentials for the initial task's thread group 33bb952bb9SDavid Howells */ 34bb952bb9SDavid Howells #ifdef CONFIG_KEYS 35bb952bb9SDavid Howells static struct thread_group_cred init_tgcred = { 36bb952bb9SDavid Howells .usage = ATOMIC_INIT(2), 37bb952bb9SDavid Howells .tgid = 0, 38bb952bb9SDavid Howells .lock = SPIN_LOCK_UNLOCKED, 39bb952bb9SDavid Howells }; 40bb952bb9SDavid Howells #endif 41bb952bb9SDavid Howells 42bb952bb9SDavid Howells /* 43f1752eecSDavid Howells * The initial credentials for the initial task 44f1752eecSDavid Howells */ 45f1752eecSDavid Howells struct cred init_cred = { 463b11a1deSDavid Howells .usage = ATOMIC_INIT(4), 47e0e81739SDavid Howells #ifdef CONFIG_DEBUG_CREDENTIALS 48e0e81739SDavid Howells .subscribers = ATOMIC_INIT(2), 49e0e81739SDavid Howells .magic = CRED_MAGIC, 50e0e81739SDavid Howells #endif 51f1752eecSDavid Howells .securebits = SECUREBITS_DEFAULT, 52f1752eecSDavid Howells .cap_inheritable = CAP_INIT_INH_SET, 53f1752eecSDavid Howells .cap_permitted = CAP_FULL_SET, 54f1752eecSDavid Howells .cap_effective = CAP_INIT_EFF_SET, 55f1752eecSDavid Howells .cap_bset = CAP_INIT_BSET, 56f1752eecSDavid Howells .user = INIT_USER, 57f1752eecSDavid Howells .group_info = &init_groups, 58bb952bb9SDavid Howells #ifdef CONFIG_KEYS 59bb952bb9SDavid Howells .tgcred = &init_tgcred, 60bb952bb9SDavid Howells #endif 61f1752eecSDavid Howells }; 62f1752eecSDavid Howells 63e0e81739SDavid Howells static inline void set_cred_subscribers(struct cred *cred, int n) 64e0e81739SDavid Howells { 65e0e81739SDavid Howells #ifdef CONFIG_DEBUG_CREDENTIALS 66e0e81739SDavid Howells atomic_set(&cred->subscribers, n); 67e0e81739SDavid Howells #endif 68e0e81739SDavid Howells } 69e0e81739SDavid Howells 70e0e81739SDavid Howells static inline int read_cred_subscribers(const struct cred *cred) 71e0e81739SDavid Howells { 72e0e81739SDavid Howells #ifdef CONFIG_DEBUG_CREDENTIALS 73e0e81739SDavid Howells return atomic_read(&cred->subscribers); 74e0e81739SDavid Howells #else 75e0e81739SDavid Howells return 0; 76e0e81739SDavid Howells #endif 77e0e81739SDavid Howells } 78e0e81739SDavid Howells 79e0e81739SDavid Howells static inline void alter_cred_subscribers(const struct cred *_cred, int n) 80e0e81739SDavid Howells { 81e0e81739SDavid Howells #ifdef CONFIG_DEBUG_CREDENTIALS 82e0e81739SDavid Howells struct cred *cred = (struct cred *) _cred; 83e0e81739SDavid Howells 84e0e81739SDavid Howells atomic_add(n, &cred->subscribers); 85e0e81739SDavid Howells #endif 86e0e81739SDavid Howells } 87e0e81739SDavid Howells 88f1752eecSDavid Howells /* 89bb952bb9SDavid Howells * Dispose of the shared task group credentials 90bb952bb9SDavid Howells */ 91bb952bb9SDavid Howells #ifdef CONFIG_KEYS 92bb952bb9SDavid Howells static void release_tgcred_rcu(struct rcu_head *rcu) 93bb952bb9SDavid Howells { 94bb952bb9SDavid Howells struct thread_group_cred *tgcred = 95bb952bb9SDavid Howells container_of(rcu, struct thread_group_cred, rcu); 96bb952bb9SDavid Howells 97bb952bb9SDavid Howells BUG_ON(atomic_read(&tgcred->usage) != 0); 98bb952bb9SDavid Howells 99bb952bb9SDavid Howells key_put(tgcred->session_keyring); 100bb952bb9SDavid Howells key_put(tgcred->process_keyring); 101bb952bb9SDavid Howells kfree(tgcred); 102bb952bb9SDavid Howells } 103bb952bb9SDavid Howells #endif 104bb952bb9SDavid Howells 105bb952bb9SDavid Howells /* 106bb952bb9SDavid Howells * Release a set of thread group credentials. 107bb952bb9SDavid Howells */ 108a6f76f23SDavid Howells static void release_tgcred(struct cred *cred) 109bb952bb9SDavid Howells { 110bb952bb9SDavid Howells #ifdef CONFIG_KEYS 111bb952bb9SDavid Howells struct thread_group_cred *tgcred = cred->tgcred; 112bb952bb9SDavid Howells 113bb952bb9SDavid Howells if (atomic_dec_and_test(&tgcred->usage)) 114bb952bb9SDavid Howells call_rcu(&tgcred->rcu, release_tgcred_rcu); 115bb952bb9SDavid Howells #endif 116bb952bb9SDavid Howells } 117bb952bb9SDavid Howells 118bb952bb9SDavid Howells /* 119f1752eecSDavid Howells * The RCU callback to actually dispose of a set of credentials 120f1752eecSDavid Howells */ 121f1752eecSDavid Howells static void put_cred_rcu(struct rcu_head *rcu) 122f1752eecSDavid Howells { 123f1752eecSDavid Howells struct cred *cred = container_of(rcu, struct cred, rcu); 124f1752eecSDavid Howells 125e0e81739SDavid Howells kdebug("put_cred_rcu(%p)", cred); 126e0e81739SDavid Howells 127e0e81739SDavid Howells #ifdef CONFIG_DEBUG_CREDENTIALS 128e0e81739SDavid Howells if (cred->magic != CRED_MAGIC_DEAD || 129e0e81739SDavid Howells atomic_read(&cred->usage) != 0 || 130e0e81739SDavid Howells read_cred_subscribers(cred) != 0) 131e0e81739SDavid Howells panic("CRED: put_cred_rcu() sees %p with" 132e0e81739SDavid Howells " mag %x, put %p, usage %d, subscr %d\n", 133e0e81739SDavid Howells cred, cred->magic, cred->put_addr, 134e0e81739SDavid Howells atomic_read(&cred->usage), 135e0e81739SDavid Howells read_cred_subscribers(cred)); 136e0e81739SDavid Howells #else 137d84f4f99SDavid Howells if (atomic_read(&cred->usage) != 0) 138d84f4f99SDavid Howells panic("CRED: put_cred_rcu() sees %p with usage %d\n", 139d84f4f99SDavid Howells cred, atomic_read(&cred->usage)); 140e0e81739SDavid Howells #endif 141f1752eecSDavid Howells 142d84f4f99SDavid Howells security_cred_free(cred); 143f1752eecSDavid Howells key_put(cred->thread_keyring); 144f1752eecSDavid Howells key_put(cred->request_key_auth); 145bb952bb9SDavid Howells release_tgcred(cred); 1464a5d6ba1SDavid Howells if (cred->group_info) 147f1752eecSDavid Howells put_group_info(cred->group_info); 148f1752eecSDavid Howells free_uid(cred->user); 149d84f4f99SDavid Howells kmem_cache_free(cred_jar, cred); 150f1752eecSDavid Howells } 151f1752eecSDavid Howells 152f1752eecSDavid Howells /** 153f1752eecSDavid Howells * __put_cred - Destroy a set of credentials 154d84f4f99SDavid Howells * @cred: The record to release 155f1752eecSDavid Howells * 156f1752eecSDavid Howells * Destroy a set of credentials on which no references remain. 157f1752eecSDavid Howells */ 158f1752eecSDavid Howells void __put_cred(struct cred *cred) 159f1752eecSDavid Howells { 160e0e81739SDavid Howells kdebug("__put_cred(%p{%d,%d})", cred, 161e0e81739SDavid Howells atomic_read(&cred->usage), 162e0e81739SDavid Howells read_cred_subscribers(cred)); 163e0e81739SDavid Howells 164d84f4f99SDavid Howells BUG_ON(atomic_read(&cred->usage) != 0); 165e0e81739SDavid Howells #ifdef CONFIG_DEBUG_CREDENTIALS 166e0e81739SDavid Howells BUG_ON(read_cred_subscribers(cred) != 0); 167e0e81739SDavid Howells cred->magic = CRED_MAGIC_DEAD; 168e0e81739SDavid Howells cred->put_addr = __builtin_return_address(0); 169e0e81739SDavid Howells #endif 170e0e81739SDavid Howells BUG_ON(cred == current->cred); 171e0e81739SDavid Howells BUG_ON(cred == current->real_cred); 172d84f4f99SDavid Howells 173f1752eecSDavid Howells call_rcu(&cred->rcu, put_cred_rcu); 174f1752eecSDavid Howells } 175f1752eecSDavid Howells EXPORT_SYMBOL(__put_cred); 176f1752eecSDavid Howells 177e0e81739SDavid Howells /* 178e0e81739SDavid Howells * Clean up a task's credentials when it exits 179e0e81739SDavid Howells */ 180e0e81739SDavid Howells void exit_creds(struct task_struct *tsk) 181e0e81739SDavid Howells { 182e0e81739SDavid Howells struct cred *cred; 183e0e81739SDavid Howells 184e0e81739SDavid Howells kdebug("exit_creds(%u,%p,%p,{%d,%d})", tsk->pid, tsk->real_cred, tsk->cred, 185e0e81739SDavid Howells atomic_read(&tsk->cred->usage), 186e0e81739SDavid Howells read_cred_subscribers(tsk->cred)); 187e0e81739SDavid Howells 188e0e81739SDavid Howells cred = (struct cred *) tsk->real_cred; 189e0e81739SDavid Howells tsk->real_cred = NULL; 190e0e81739SDavid Howells validate_creds(cred); 191e0e81739SDavid Howells alter_cred_subscribers(cred, -1); 192e0e81739SDavid Howells put_cred(cred); 193e0e81739SDavid Howells 194e0e81739SDavid Howells cred = (struct cred *) tsk->cred; 195e0e81739SDavid Howells tsk->cred = NULL; 196e0e81739SDavid Howells validate_creds(cred); 197e0e81739SDavid Howells alter_cred_subscribers(cred, -1); 198e0e81739SDavid Howells put_cred(cred); 199ee18d64cSDavid Howells 200ee18d64cSDavid Howells cred = (struct cred *) tsk->replacement_session_keyring; 201ee18d64cSDavid Howells if (cred) { 202ee18d64cSDavid Howells tsk->replacement_session_keyring = NULL; 203ee18d64cSDavid Howells validate_creds(cred); 204ee18d64cSDavid Howells put_cred(cred); 205ee18d64cSDavid Howells } 206ee18d64cSDavid Howells } 207ee18d64cSDavid Howells 208de09a977SDavid Howells /** 209de09a977SDavid Howells * get_task_cred - Get another task's objective credentials 210de09a977SDavid Howells * @task: The task to query 211de09a977SDavid Howells * 212de09a977SDavid Howells * Get the objective credentials of a task, pinning them so that they can't go 213de09a977SDavid Howells * away. Accessing a task's credentials directly is not permitted. 214de09a977SDavid Howells * 215de09a977SDavid Howells * The caller must also make sure task doesn't get deleted, either by holding a 216de09a977SDavid Howells * ref on task or by holding tasklist_lock to prevent it from being unlinked. 217de09a977SDavid Howells */ 218de09a977SDavid Howells const struct cred *get_task_cred(struct task_struct *task) 219de09a977SDavid Howells { 220de09a977SDavid Howells const struct cred *cred; 221de09a977SDavid Howells 222de09a977SDavid Howells rcu_read_lock(); 223de09a977SDavid Howells 224de09a977SDavid Howells do { 225de09a977SDavid Howells cred = __task_cred((task)); 226de09a977SDavid Howells BUG_ON(!cred); 227de09a977SDavid Howells } while (!atomic_inc_not_zero(&((struct cred *)cred)->usage)); 228de09a977SDavid Howells 229de09a977SDavid Howells rcu_read_unlock(); 230de09a977SDavid Howells return cred; 231de09a977SDavid Howells } 232de09a977SDavid Howells 233ee18d64cSDavid Howells /* 234ee18d64cSDavid Howells * Allocate blank credentials, such that the credentials can be filled in at a 235ee18d64cSDavid Howells * later date without risk of ENOMEM. 236ee18d64cSDavid Howells */ 237ee18d64cSDavid Howells struct cred *cred_alloc_blank(void) 238ee18d64cSDavid Howells { 239ee18d64cSDavid Howells struct cred *new; 240ee18d64cSDavid Howells 241ee18d64cSDavid Howells new = kmem_cache_zalloc(cred_jar, GFP_KERNEL); 242ee18d64cSDavid Howells if (!new) 243ee18d64cSDavid Howells return NULL; 244ee18d64cSDavid Howells 245ee18d64cSDavid Howells #ifdef CONFIG_KEYS 246ee18d64cSDavid Howells new->tgcred = kzalloc(sizeof(*new->tgcred), GFP_KERNEL); 247ee18d64cSDavid Howells if (!new->tgcred) { 248b8a1d37cSJulia Lawall kmem_cache_free(cred_jar, new); 249ee18d64cSDavid Howells return NULL; 250ee18d64cSDavid Howells } 251ee18d64cSDavid Howells atomic_set(&new->tgcred->usage, 1); 252ee18d64cSDavid Howells #endif 253ee18d64cSDavid Howells 254ee18d64cSDavid Howells atomic_set(&new->usage, 1); 255ee18d64cSDavid Howells 256ee18d64cSDavid Howells if (security_cred_alloc_blank(new, GFP_KERNEL) < 0) 257ee18d64cSDavid Howells goto error; 258ee18d64cSDavid Howells 259ee18d64cSDavid Howells #ifdef CONFIG_DEBUG_CREDENTIALS 260ee18d64cSDavid Howells new->magic = CRED_MAGIC; 261ee18d64cSDavid Howells #endif 262ee18d64cSDavid Howells return new; 263ee18d64cSDavid Howells 264ee18d64cSDavid Howells error: 265ee18d64cSDavid Howells abort_creds(new); 266ee18d64cSDavid Howells return NULL; 267e0e81739SDavid Howells } 268e0e81739SDavid Howells 269d84f4f99SDavid Howells /** 270d84f4f99SDavid Howells * prepare_creds - Prepare a new set of credentials for modification 271d84f4f99SDavid Howells * 272d84f4f99SDavid Howells * Prepare a new set of task credentials for modification. A task's creds 273d84f4f99SDavid Howells * shouldn't generally be modified directly, therefore this function is used to 274d84f4f99SDavid Howells * prepare a new copy, which the caller then modifies and then commits by 275d84f4f99SDavid Howells * calling commit_creds(). 276d84f4f99SDavid Howells * 2773b11a1deSDavid Howells * Preparation involves making a copy of the objective creds for modification. 2783b11a1deSDavid Howells * 279d84f4f99SDavid Howells * Returns a pointer to the new creds-to-be if successful, NULL otherwise. 280d84f4f99SDavid Howells * 281d84f4f99SDavid Howells * Call commit_creds() or abort_creds() to clean up. 282f1752eecSDavid Howells */ 283d84f4f99SDavid Howells struct cred *prepare_creds(void) 284f1752eecSDavid Howells { 285d84f4f99SDavid Howells struct task_struct *task = current; 286d84f4f99SDavid Howells const struct cred *old; 287d84f4f99SDavid Howells struct cred *new; 288f1752eecSDavid Howells 289e0e81739SDavid Howells validate_process_creds(); 290d84f4f99SDavid Howells 291d84f4f99SDavid Howells new = kmem_cache_alloc(cred_jar, GFP_KERNEL); 292d84f4f99SDavid Howells if (!new) 293d84f4f99SDavid Howells return NULL; 294d84f4f99SDavid Howells 295e0e81739SDavid Howells kdebug("prepare_creds() alloc %p", new); 296e0e81739SDavid Howells 297d84f4f99SDavid Howells old = task->cred; 298d84f4f99SDavid Howells memcpy(new, old, sizeof(struct cred)); 299d84f4f99SDavid Howells 300d84f4f99SDavid Howells atomic_set(&new->usage, 1); 301e0e81739SDavid Howells set_cred_subscribers(new, 0); 302d84f4f99SDavid Howells get_group_info(new->group_info); 303d84f4f99SDavid Howells get_uid(new->user); 304f1752eecSDavid Howells 305bb952bb9SDavid Howells #ifdef CONFIG_KEYS 306d84f4f99SDavid Howells key_get(new->thread_keyring); 307d84f4f99SDavid Howells key_get(new->request_key_auth); 308d84f4f99SDavid Howells atomic_inc(&new->tgcred->usage); 309bb952bb9SDavid Howells #endif 310bb952bb9SDavid Howells 311f1752eecSDavid Howells #ifdef CONFIG_SECURITY 312d84f4f99SDavid Howells new->security = NULL; 313f1752eecSDavid Howells #endif 314f1752eecSDavid Howells 315d84f4f99SDavid Howells if (security_prepare_creds(new, old, GFP_KERNEL) < 0) 316d84f4f99SDavid Howells goto error; 317e0e81739SDavid Howells validate_creds(new); 318d84f4f99SDavid Howells return new; 319d84f4f99SDavid Howells 320d84f4f99SDavid Howells error: 321d84f4f99SDavid Howells abort_creds(new); 322d84f4f99SDavid Howells return NULL; 323d84f4f99SDavid Howells } 324d84f4f99SDavid Howells EXPORT_SYMBOL(prepare_creds); 325d84f4f99SDavid Howells 326d84f4f99SDavid Howells /* 327a6f76f23SDavid Howells * Prepare credentials for current to perform an execve() 3289b1bf12dSKOSAKI Motohiro * - The caller must hold ->cred_guard_mutex 329a6f76f23SDavid Howells */ 330a6f76f23SDavid Howells struct cred *prepare_exec_creds(void) 331a6f76f23SDavid Howells { 332a6f76f23SDavid Howells struct thread_group_cred *tgcred = NULL; 333a6f76f23SDavid Howells struct cred *new; 334a6f76f23SDavid Howells 335a6f76f23SDavid Howells #ifdef CONFIG_KEYS 336a6f76f23SDavid Howells tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); 337a6f76f23SDavid Howells if (!tgcred) 338a6f76f23SDavid Howells return NULL; 339a6f76f23SDavid Howells #endif 340a6f76f23SDavid Howells 341a6f76f23SDavid Howells new = prepare_creds(); 342a6f76f23SDavid Howells if (!new) { 343a6f76f23SDavid Howells kfree(tgcred); 344a6f76f23SDavid Howells return new; 345a6f76f23SDavid Howells } 346a6f76f23SDavid Howells 347a6f76f23SDavid Howells #ifdef CONFIG_KEYS 348a6f76f23SDavid Howells /* newly exec'd tasks don't get a thread keyring */ 349a6f76f23SDavid Howells key_put(new->thread_keyring); 350a6f76f23SDavid Howells new->thread_keyring = NULL; 351a6f76f23SDavid Howells 352a6f76f23SDavid Howells /* create a new per-thread-group creds for all this set of threads to 353a6f76f23SDavid Howells * share */ 354a6f76f23SDavid Howells memcpy(tgcred, new->tgcred, sizeof(struct thread_group_cred)); 355a6f76f23SDavid Howells 356a6f76f23SDavid Howells atomic_set(&tgcred->usage, 1); 357a6f76f23SDavid Howells spin_lock_init(&tgcred->lock); 358a6f76f23SDavid Howells 359a6f76f23SDavid Howells /* inherit the session keyring; new process keyring */ 360a6f76f23SDavid Howells key_get(tgcred->session_keyring); 361a6f76f23SDavid Howells tgcred->process_keyring = NULL; 362a6f76f23SDavid Howells 363a6f76f23SDavid Howells release_tgcred(new); 364a6f76f23SDavid Howells new->tgcred = tgcred; 365a6f76f23SDavid Howells #endif 366a6f76f23SDavid Howells 367a6f76f23SDavid Howells return new; 368a6f76f23SDavid Howells } 369a6f76f23SDavid Howells 370a6f76f23SDavid Howells /* 371d84f4f99SDavid Howells * Copy credentials for the new process created by fork() 372d84f4f99SDavid Howells * 373d84f4f99SDavid Howells * We share if we can, but under some circumstances we have to generate a new 374d84f4f99SDavid Howells * set. 3753b11a1deSDavid Howells * 3763b11a1deSDavid Howells * The new process gets the current process's subjective credentials as its 3773b11a1deSDavid Howells * objective and subjective credentials 378d84f4f99SDavid Howells */ 379d84f4f99SDavid Howells int copy_creds(struct task_struct *p, unsigned long clone_flags) 380d84f4f99SDavid Howells { 381d84f4f99SDavid Howells #ifdef CONFIG_KEYS 382d84f4f99SDavid Howells struct thread_group_cred *tgcred; 383d84f4f99SDavid Howells #endif 384d84f4f99SDavid Howells struct cred *new; 38518b6e041SSerge Hallyn int ret; 386f1752eecSDavid Howells 387d84f4f99SDavid Howells if ( 388d84f4f99SDavid Howells #ifdef CONFIG_KEYS 389d84f4f99SDavid Howells !p->cred->thread_keyring && 390d84f4f99SDavid Howells #endif 391d84f4f99SDavid Howells clone_flags & CLONE_THREAD 392d84f4f99SDavid Howells ) { 3933b11a1deSDavid Howells p->real_cred = get_cred(p->cred); 394d84f4f99SDavid Howells get_cred(p->cred); 395e0e81739SDavid Howells alter_cred_subscribers(p->cred, 2); 396e0e81739SDavid Howells kdebug("share_creds(%p{%d,%d})", 397e0e81739SDavid Howells p->cred, atomic_read(&p->cred->usage), 398e0e81739SDavid Howells read_cred_subscribers(p->cred)); 399d84f4f99SDavid Howells atomic_inc(&p->cred->user->processes); 400f1752eecSDavid Howells return 0; 401f1752eecSDavid Howells } 402d84f4f99SDavid Howells 403d84f4f99SDavid Howells new = prepare_creds(); 404d84f4f99SDavid Howells if (!new) 405d84f4f99SDavid Howells return -ENOMEM; 406d84f4f99SDavid Howells 40718b6e041SSerge Hallyn if (clone_flags & CLONE_NEWUSER) { 40818b6e041SSerge Hallyn ret = create_user_ns(new); 40918b6e041SSerge Hallyn if (ret < 0) 41018b6e041SSerge Hallyn goto error_put; 41118b6e041SSerge Hallyn } 41218b6e041SSerge Hallyn 413d84f4f99SDavid Howells #ifdef CONFIG_KEYS 414d84f4f99SDavid Howells /* new threads get their own thread keyrings if their parent already 415d84f4f99SDavid Howells * had one */ 416d84f4f99SDavid Howells if (new->thread_keyring) { 417d84f4f99SDavid Howells key_put(new->thread_keyring); 418d84f4f99SDavid Howells new->thread_keyring = NULL; 419d84f4f99SDavid Howells if (clone_flags & CLONE_THREAD) 420d84f4f99SDavid Howells install_thread_keyring_to_cred(new); 421d84f4f99SDavid Howells } 422d84f4f99SDavid Howells 423d84f4f99SDavid Howells /* we share the process and session keyrings between all the threads in 424d84f4f99SDavid Howells * a process - this is slightly icky as we violate COW credentials a 425d84f4f99SDavid Howells * bit */ 426d84f4f99SDavid Howells if (!(clone_flags & CLONE_THREAD)) { 427d84f4f99SDavid Howells tgcred = kmalloc(sizeof(*tgcred), GFP_KERNEL); 428d84f4f99SDavid Howells if (!tgcred) { 42918b6e041SSerge Hallyn ret = -ENOMEM; 43018b6e041SSerge Hallyn goto error_put; 431d84f4f99SDavid Howells } 432d84f4f99SDavid Howells atomic_set(&tgcred->usage, 1); 433d84f4f99SDavid Howells spin_lock_init(&tgcred->lock); 434d84f4f99SDavid Howells tgcred->process_keyring = NULL; 435d84f4f99SDavid Howells tgcred->session_keyring = key_get(new->tgcred->session_keyring); 436d84f4f99SDavid Howells 437d84f4f99SDavid Howells release_tgcred(new); 438d84f4f99SDavid Howells new->tgcred = tgcred; 439d84f4f99SDavid Howells } 440d84f4f99SDavid Howells #endif 441d84f4f99SDavid Howells 442d84f4f99SDavid Howells atomic_inc(&new->user->processes); 4433b11a1deSDavid Howells p->cred = p->real_cred = get_cred(new); 444e0e81739SDavid Howells alter_cred_subscribers(new, 2); 445e0e81739SDavid Howells validate_creds(new); 446d84f4f99SDavid Howells return 0; 44718b6e041SSerge Hallyn 44818b6e041SSerge Hallyn error_put: 44918b6e041SSerge Hallyn put_cred(new); 45018b6e041SSerge Hallyn return ret; 451d84f4f99SDavid Howells } 452d84f4f99SDavid Howells 453d84f4f99SDavid Howells /** 454d84f4f99SDavid Howells * commit_creds - Install new credentials upon the current task 455d84f4f99SDavid Howells * @new: The credentials to be assigned 456d84f4f99SDavid Howells * 457d84f4f99SDavid Howells * Install a new set of credentials to the current task, using RCU to replace 4583b11a1deSDavid Howells * the old set. Both the objective and the subjective credentials pointers are 4593b11a1deSDavid Howells * updated. This function may not be called if the subjective credentials are 4603b11a1deSDavid Howells * in an overridden state. 461d84f4f99SDavid Howells * 462d84f4f99SDavid Howells * This function eats the caller's reference to the new credentials. 463d84f4f99SDavid Howells * 464d84f4f99SDavid Howells * Always returns 0 thus allowing this function to be tail-called at the end 465d84f4f99SDavid Howells * of, say, sys_setgid(). 466d84f4f99SDavid Howells */ 467d84f4f99SDavid Howells int commit_creds(struct cred *new) 468d84f4f99SDavid Howells { 469d84f4f99SDavid Howells struct task_struct *task = current; 470e0e81739SDavid Howells const struct cred *old = task->real_cred; 471d84f4f99SDavid Howells 472e0e81739SDavid Howells kdebug("commit_creds(%p{%d,%d})", new, 473e0e81739SDavid Howells atomic_read(&new->usage), 474e0e81739SDavid Howells read_cred_subscribers(new)); 475e0e81739SDavid Howells 476e0e81739SDavid Howells BUG_ON(task->cred != old); 477e0e81739SDavid Howells #ifdef CONFIG_DEBUG_CREDENTIALS 478e0e81739SDavid Howells BUG_ON(read_cred_subscribers(old) < 2); 479e0e81739SDavid Howells validate_creds(old); 480e0e81739SDavid Howells validate_creds(new); 481e0e81739SDavid Howells #endif 482d84f4f99SDavid Howells BUG_ON(atomic_read(&new->usage) < 1); 483d84f4f99SDavid Howells 4843b11a1deSDavid Howells get_cred(new); /* we will require a ref for the subj creds too */ 4853b11a1deSDavid Howells 486d84f4f99SDavid Howells /* dumpability changes */ 487d84f4f99SDavid Howells if (old->euid != new->euid || 488d84f4f99SDavid Howells old->egid != new->egid || 489d84f4f99SDavid Howells old->fsuid != new->fsuid || 490d84f4f99SDavid Howells old->fsgid != new->fsgid || 491d84f4f99SDavid Howells !cap_issubset(new->cap_permitted, old->cap_permitted)) { 492b9456371SDavid Howells if (task->mm) 493d84f4f99SDavid Howells set_dumpable(task->mm, suid_dumpable); 494d84f4f99SDavid Howells task->pdeath_signal = 0; 495d84f4f99SDavid Howells smp_wmb(); 496d84f4f99SDavid Howells } 497d84f4f99SDavid Howells 498d84f4f99SDavid Howells /* alter the thread keyring */ 499d84f4f99SDavid Howells if (new->fsuid != old->fsuid) 500d84f4f99SDavid Howells key_fsuid_changed(task); 501d84f4f99SDavid Howells if (new->fsgid != old->fsgid) 502d84f4f99SDavid Howells key_fsgid_changed(task); 503d84f4f99SDavid Howells 504d84f4f99SDavid Howells /* do it 505d84f4f99SDavid Howells * - What if a process setreuid()'s and this brings the 506d84f4f99SDavid Howells * new uid over his NPROC rlimit? We can check this now 507d84f4f99SDavid Howells * cheaply with the new uid cache, so if it matters 508d84f4f99SDavid Howells * we should be checking for it. -DaveM 509d84f4f99SDavid Howells */ 510e0e81739SDavid Howells alter_cred_subscribers(new, 2); 511d84f4f99SDavid Howells if (new->user != old->user) 512d84f4f99SDavid Howells atomic_inc(&new->user->processes); 5133b11a1deSDavid Howells rcu_assign_pointer(task->real_cred, new); 514d84f4f99SDavid Howells rcu_assign_pointer(task->cred, new); 515d84f4f99SDavid Howells if (new->user != old->user) 516d84f4f99SDavid Howells atomic_dec(&old->user->processes); 517e0e81739SDavid Howells alter_cred_subscribers(old, -2); 518d84f4f99SDavid Howells 519d84f4f99SDavid Howells /* send notifications */ 520d84f4f99SDavid Howells if (new->uid != old->uid || 521d84f4f99SDavid Howells new->euid != old->euid || 522d84f4f99SDavid Howells new->suid != old->suid || 523d84f4f99SDavid Howells new->fsuid != old->fsuid) 524d84f4f99SDavid Howells proc_id_connector(task, PROC_EVENT_UID); 525d84f4f99SDavid Howells 526d84f4f99SDavid Howells if (new->gid != old->gid || 527d84f4f99SDavid Howells new->egid != old->egid || 528d84f4f99SDavid Howells new->sgid != old->sgid || 529d84f4f99SDavid Howells new->fsgid != old->fsgid) 530d84f4f99SDavid Howells proc_id_connector(task, PROC_EVENT_GID); 531d84f4f99SDavid Howells 5323b11a1deSDavid Howells /* release the old obj and subj refs both */ 5333b11a1deSDavid Howells put_cred(old); 534d84f4f99SDavid Howells put_cred(old); 535d84f4f99SDavid Howells return 0; 536d84f4f99SDavid Howells } 537d84f4f99SDavid Howells EXPORT_SYMBOL(commit_creds); 538d84f4f99SDavid Howells 539d84f4f99SDavid Howells /** 540d84f4f99SDavid Howells * abort_creds - Discard a set of credentials and unlock the current task 541d84f4f99SDavid Howells * @new: The credentials that were going to be applied 542d84f4f99SDavid Howells * 543d84f4f99SDavid Howells * Discard a set of credentials that were under construction and unlock the 544d84f4f99SDavid Howells * current task. 545d84f4f99SDavid Howells */ 546d84f4f99SDavid Howells void abort_creds(struct cred *new) 547d84f4f99SDavid Howells { 548e0e81739SDavid Howells kdebug("abort_creds(%p{%d,%d})", new, 549e0e81739SDavid Howells atomic_read(&new->usage), 550e0e81739SDavid Howells read_cred_subscribers(new)); 551e0e81739SDavid Howells 552e0e81739SDavid Howells #ifdef CONFIG_DEBUG_CREDENTIALS 553e0e81739SDavid Howells BUG_ON(read_cred_subscribers(new) != 0); 554e0e81739SDavid Howells #endif 555d84f4f99SDavid Howells BUG_ON(atomic_read(&new->usage) < 1); 556d84f4f99SDavid Howells put_cred(new); 557d84f4f99SDavid Howells } 558d84f4f99SDavid Howells EXPORT_SYMBOL(abort_creds); 559d84f4f99SDavid Howells 560d84f4f99SDavid Howells /** 5613b11a1deSDavid Howells * override_creds - Override the current process's subjective credentials 562d84f4f99SDavid Howells * @new: The credentials to be assigned 563d84f4f99SDavid Howells * 5643b11a1deSDavid Howells * Install a set of temporary override subjective credentials on the current 5653b11a1deSDavid Howells * process, returning the old set for later reversion. 566d84f4f99SDavid Howells */ 567d84f4f99SDavid Howells const struct cred *override_creds(const struct cred *new) 568d84f4f99SDavid Howells { 569d84f4f99SDavid Howells const struct cred *old = current->cred; 570d84f4f99SDavid Howells 571e0e81739SDavid Howells kdebug("override_creds(%p{%d,%d})", new, 572e0e81739SDavid Howells atomic_read(&new->usage), 573e0e81739SDavid Howells read_cred_subscribers(new)); 574e0e81739SDavid Howells 575e0e81739SDavid Howells validate_creds(old); 576e0e81739SDavid Howells validate_creds(new); 577e0e81739SDavid Howells get_cred(new); 578e0e81739SDavid Howells alter_cred_subscribers(new, 1); 579e0e81739SDavid Howells rcu_assign_pointer(current->cred, new); 580e0e81739SDavid Howells alter_cred_subscribers(old, -1); 581e0e81739SDavid Howells 582e0e81739SDavid Howells kdebug("override_creds() = %p{%d,%d}", old, 583e0e81739SDavid Howells atomic_read(&old->usage), 584e0e81739SDavid Howells read_cred_subscribers(old)); 585d84f4f99SDavid Howells return old; 586d84f4f99SDavid Howells } 587d84f4f99SDavid Howells EXPORT_SYMBOL(override_creds); 588d84f4f99SDavid Howells 589d84f4f99SDavid Howells /** 5903b11a1deSDavid Howells * revert_creds - Revert a temporary subjective credentials override 591d84f4f99SDavid Howells * @old: The credentials to be restored 592d84f4f99SDavid Howells * 5933b11a1deSDavid Howells * Revert a temporary set of override subjective credentials to an old set, 5943b11a1deSDavid Howells * discarding the override set. 595d84f4f99SDavid Howells */ 596d84f4f99SDavid Howells void revert_creds(const struct cred *old) 597d84f4f99SDavid Howells { 598d84f4f99SDavid Howells const struct cred *override = current->cred; 599d84f4f99SDavid Howells 600e0e81739SDavid Howells kdebug("revert_creds(%p{%d,%d})", old, 601e0e81739SDavid Howells atomic_read(&old->usage), 602e0e81739SDavid Howells read_cred_subscribers(old)); 603e0e81739SDavid Howells 604e0e81739SDavid Howells validate_creds(old); 605e0e81739SDavid Howells validate_creds(override); 606e0e81739SDavid Howells alter_cred_subscribers(old, 1); 607d84f4f99SDavid Howells rcu_assign_pointer(current->cred, old); 608e0e81739SDavid Howells alter_cred_subscribers(override, -1); 609d84f4f99SDavid Howells put_cred(override); 610d84f4f99SDavid Howells } 611d84f4f99SDavid Howells EXPORT_SYMBOL(revert_creds); 612d84f4f99SDavid Howells 613d84f4f99SDavid Howells /* 614d84f4f99SDavid Howells * initialise the credentials stuff 615d84f4f99SDavid Howells */ 616d84f4f99SDavid Howells void __init cred_init(void) 617d84f4f99SDavid Howells { 618d84f4f99SDavid Howells /* allocate a slab in which we can store credentials */ 619d84f4f99SDavid Howells cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), 620d84f4f99SDavid Howells 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); 621d84f4f99SDavid Howells } 6223a3b7ce9SDavid Howells 6233a3b7ce9SDavid Howells /** 6243a3b7ce9SDavid Howells * prepare_kernel_cred - Prepare a set of credentials for a kernel service 6253a3b7ce9SDavid Howells * @daemon: A userspace daemon to be used as a reference 6263a3b7ce9SDavid Howells * 6273a3b7ce9SDavid Howells * Prepare a set of credentials for a kernel service. This can then be used to 6283a3b7ce9SDavid Howells * override a task's own credentials so that work can be done on behalf of that 6293a3b7ce9SDavid Howells * task that requires a different subjective context. 6303a3b7ce9SDavid Howells * 6313a3b7ce9SDavid Howells * @daemon is used to provide a base for the security record, but can be NULL. 6323a3b7ce9SDavid Howells * If @daemon is supplied, then the security data will be derived from that; 6333a3b7ce9SDavid Howells * otherwise they'll be set to 0 and no groups, full capabilities and no keys. 6343a3b7ce9SDavid Howells * 6353a3b7ce9SDavid Howells * The caller may change these controls afterwards if desired. 6363a3b7ce9SDavid Howells * 6373a3b7ce9SDavid Howells * Returns the new credentials or NULL if out of memory. 6383a3b7ce9SDavid Howells * 6393a3b7ce9SDavid Howells * Does not take, and does not return holding current->cred_replace_mutex. 6403a3b7ce9SDavid Howells */ 6413a3b7ce9SDavid Howells struct cred *prepare_kernel_cred(struct task_struct *daemon) 6423a3b7ce9SDavid Howells { 6433a3b7ce9SDavid Howells const struct cred *old; 6443a3b7ce9SDavid Howells struct cred *new; 6453a3b7ce9SDavid Howells 6463a3b7ce9SDavid Howells new = kmem_cache_alloc(cred_jar, GFP_KERNEL); 6473a3b7ce9SDavid Howells if (!new) 6483a3b7ce9SDavid Howells return NULL; 6493a3b7ce9SDavid Howells 650e0e81739SDavid Howells kdebug("prepare_kernel_cred() alloc %p", new); 651e0e81739SDavid Howells 6523a3b7ce9SDavid Howells if (daemon) 6533a3b7ce9SDavid Howells old = get_task_cred(daemon); 6543a3b7ce9SDavid Howells else 6553a3b7ce9SDavid Howells old = get_cred(&init_cred); 6563a3b7ce9SDavid Howells 657e0e81739SDavid Howells validate_creds(old); 658e0e81739SDavid Howells 65943529c97SDavid Howells *new = *old; 6603a3b7ce9SDavid Howells get_uid(new->user); 6613a3b7ce9SDavid Howells get_group_info(new->group_info); 6623a3b7ce9SDavid Howells 6633a3b7ce9SDavid Howells #ifdef CONFIG_KEYS 6643a3b7ce9SDavid Howells atomic_inc(&init_tgcred.usage); 6653a3b7ce9SDavid Howells new->tgcred = &init_tgcred; 6663a3b7ce9SDavid Howells new->request_key_auth = NULL; 6673a3b7ce9SDavid Howells new->thread_keyring = NULL; 6683a3b7ce9SDavid Howells new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; 6693a3b7ce9SDavid Howells #endif 6703a3b7ce9SDavid Howells 6713a3b7ce9SDavid Howells #ifdef CONFIG_SECURITY 6723a3b7ce9SDavid Howells new->security = NULL; 6733a3b7ce9SDavid Howells #endif 6743a3b7ce9SDavid Howells if (security_prepare_creds(new, old, GFP_KERNEL) < 0) 6753a3b7ce9SDavid Howells goto error; 6763a3b7ce9SDavid Howells 6773a3b7ce9SDavid Howells atomic_set(&new->usage, 1); 678e0e81739SDavid Howells set_cred_subscribers(new, 0); 6793a3b7ce9SDavid Howells put_cred(old); 680e0e81739SDavid Howells validate_creds(new); 6813a3b7ce9SDavid Howells return new; 6823a3b7ce9SDavid Howells 6833a3b7ce9SDavid Howells error: 6843a3b7ce9SDavid Howells put_cred(new); 6850de33681SDavid Howells put_cred(old); 6863a3b7ce9SDavid Howells return NULL; 6873a3b7ce9SDavid Howells } 6883a3b7ce9SDavid Howells EXPORT_SYMBOL(prepare_kernel_cred); 6893a3b7ce9SDavid Howells 6903a3b7ce9SDavid Howells /** 6913a3b7ce9SDavid Howells * set_security_override - Set the security ID in a set of credentials 6923a3b7ce9SDavid Howells * @new: The credentials to alter 6933a3b7ce9SDavid Howells * @secid: The LSM security ID to set 6943a3b7ce9SDavid Howells * 6953a3b7ce9SDavid Howells * Set the LSM security ID in a set of credentials so that the subjective 6963a3b7ce9SDavid Howells * security is overridden when an alternative set of credentials is used. 6973a3b7ce9SDavid Howells */ 6983a3b7ce9SDavid Howells int set_security_override(struct cred *new, u32 secid) 6993a3b7ce9SDavid Howells { 7003a3b7ce9SDavid Howells return security_kernel_act_as(new, secid); 7013a3b7ce9SDavid Howells } 7023a3b7ce9SDavid Howells EXPORT_SYMBOL(set_security_override); 7033a3b7ce9SDavid Howells 7043a3b7ce9SDavid Howells /** 7053a3b7ce9SDavid Howells * set_security_override_from_ctx - Set the security ID in a set of credentials 7063a3b7ce9SDavid Howells * @new: The credentials to alter 7073a3b7ce9SDavid Howells * @secctx: The LSM security context to generate the security ID from. 7083a3b7ce9SDavid Howells * 7093a3b7ce9SDavid Howells * Set the LSM security ID in a set of credentials so that the subjective 7103a3b7ce9SDavid Howells * security is overridden when an alternative set of credentials is used. The 7113a3b7ce9SDavid Howells * security ID is specified in string form as a security context to be 7123a3b7ce9SDavid Howells * interpreted by the LSM. 7133a3b7ce9SDavid Howells */ 7143a3b7ce9SDavid Howells int set_security_override_from_ctx(struct cred *new, const char *secctx) 7153a3b7ce9SDavid Howells { 7163a3b7ce9SDavid Howells u32 secid; 7173a3b7ce9SDavid Howells int ret; 7183a3b7ce9SDavid Howells 7193a3b7ce9SDavid Howells ret = security_secctx_to_secid(secctx, strlen(secctx), &secid); 7203a3b7ce9SDavid Howells if (ret < 0) 7213a3b7ce9SDavid Howells return ret; 7223a3b7ce9SDavid Howells 7233a3b7ce9SDavid Howells return set_security_override(new, secid); 7243a3b7ce9SDavid Howells } 7253a3b7ce9SDavid Howells EXPORT_SYMBOL(set_security_override_from_ctx); 7263a3b7ce9SDavid Howells 7273a3b7ce9SDavid Howells /** 7283a3b7ce9SDavid Howells * set_create_files_as - Set the LSM file create context in a set of credentials 7293a3b7ce9SDavid Howells * @new: The credentials to alter 7303a3b7ce9SDavid Howells * @inode: The inode to take the context from 7313a3b7ce9SDavid Howells * 7323a3b7ce9SDavid Howells * Change the LSM file creation context in a set of credentials to be the same 7333a3b7ce9SDavid Howells * as the object context of the specified inode, so that the new inodes have 7343a3b7ce9SDavid Howells * the same MAC context as that inode. 7353a3b7ce9SDavid Howells */ 7363a3b7ce9SDavid Howells int set_create_files_as(struct cred *new, struct inode *inode) 7373a3b7ce9SDavid Howells { 7383a3b7ce9SDavid Howells new->fsuid = inode->i_uid; 7393a3b7ce9SDavid Howells new->fsgid = inode->i_gid; 7403a3b7ce9SDavid Howells return security_kernel_create_files_as(new, inode); 7413a3b7ce9SDavid Howells } 7423a3b7ce9SDavid Howells EXPORT_SYMBOL(set_create_files_as); 743e0e81739SDavid Howells 744e0e81739SDavid Howells #ifdef CONFIG_DEBUG_CREDENTIALS 745e0e81739SDavid Howells 74674908a00SAndrew Morton bool creds_are_invalid(const struct cred *cred) 74774908a00SAndrew Morton { 74874908a00SAndrew Morton if (cred->magic != CRED_MAGIC) 74974908a00SAndrew Morton return true; 75074908a00SAndrew Morton #ifdef CONFIG_SECURITY_SELINUX 75174908a00SAndrew Morton if (selinux_is_enabled()) { 75274908a00SAndrew Morton if ((unsigned long) cred->security < PAGE_SIZE) 75374908a00SAndrew Morton return true; 75474908a00SAndrew Morton if ((*(u32 *)cred->security & 0xffffff00) == 75574908a00SAndrew Morton (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)) 75674908a00SAndrew Morton return true; 75774908a00SAndrew Morton } 75874908a00SAndrew Morton #endif 75974908a00SAndrew Morton return false; 76074908a00SAndrew Morton } 761764db03fSRandy Dunlap EXPORT_SYMBOL(creds_are_invalid); 76274908a00SAndrew Morton 763e0e81739SDavid Howells /* 764e0e81739SDavid Howells * dump invalid credentials 765e0e81739SDavid Howells */ 766e0e81739SDavid Howells static void dump_invalid_creds(const struct cred *cred, const char *label, 767e0e81739SDavid Howells const struct task_struct *tsk) 768e0e81739SDavid Howells { 769e0e81739SDavid Howells printk(KERN_ERR "CRED: %s credentials: %p %s%s%s\n", 770e0e81739SDavid Howells label, cred, 771e0e81739SDavid Howells cred == &init_cred ? "[init]" : "", 772e0e81739SDavid Howells cred == tsk->real_cred ? "[real]" : "", 773e0e81739SDavid Howells cred == tsk->cred ? "[eff]" : ""); 774e0e81739SDavid Howells printk(KERN_ERR "CRED: ->magic=%x, put_addr=%p\n", 775e0e81739SDavid Howells cred->magic, cred->put_addr); 776e0e81739SDavid Howells printk(KERN_ERR "CRED: ->usage=%d, subscr=%d\n", 777e0e81739SDavid Howells atomic_read(&cred->usage), 778e0e81739SDavid Howells read_cred_subscribers(cred)); 779e0e81739SDavid Howells printk(KERN_ERR "CRED: ->*uid = { %d,%d,%d,%d }\n", 780e0e81739SDavid Howells cred->uid, cred->euid, cred->suid, cred->fsuid); 781e0e81739SDavid Howells printk(KERN_ERR "CRED: ->*gid = { %d,%d,%d,%d }\n", 782e0e81739SDavid Howells cred->gid, cred->egid, cred->sgid, cred->fsgid); 783e0e81739SDavid Howells #ifdef CONFIG_SECURITY 784e0e81739SDavid Howells printk(KERN_ERR "CRED: ->security is %p\n", cred->security); 785e0e81739SDavid Howells if ((unsigned long) cred->security >= PAGE_SIZE && 786e0e81739SDavid Howells (((unsigned long) cred->security & 0xffffff00) != 787e0e81739SDavid Howells (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))) 788e0e81739SDavid Howells printk(KERN_ERR "CRED: ->security {%x, %x}\n", 789e0e81739SDavid Howells ((u32*)cred->security)[0], 790e0e81739SDavid Howells ((u32*)cred->security)[1]); 791e0e81739SDavid Howells #endif 792e0e81739SDavid Howells } 793e0e81739SDavid Howells 794e0e81739SDavid Howells /* 795e0e81739SDavid Howells * report use of invalid credentials 796e0e81739SDavid Howells */ 797e0e81739SDavid Howells void __invalid_creds(const struct cred *cred, const char *file, unsigned line) 798e0e81739SDavid Howells { 799e0e81739SDavid Howells printk(KERN_ERR "CRED: Invalid credentials\n"); 800e0e81739SDavid Howells printk(KERN_ERR "CRED: At %s:%u\n", file, line); 801e0e81739SDavid Howells dump_invalid_creds(cred, "Specified", current); 802e0e81739SDavid Howells BUG(); 803e0e81739SDavid Howells } 804e0e81739SDavid Howells EXPORT_SYMBOL(__invalid_creds); 805e0e81739SDavid Howells 806e0e81739SDavid Howells /* 807e0e81739SDavid Howells * check the credentials on a process 808e0e81739SDavid Howells */ 809e0e81739SDavid Howells void __validate_process_creds(struct task_struct *tsk, 810e0e81739SDavid Howells const char *file, unsigned line) 811e0e81739SDavid Howells { 812e0e81739SDavid Howells if (tsk->cred == tsk->real_cred) { 813e0e81739SDavid Howells if (unlikely(read_cred_subscribers(tsk->cred) < 2 || 814e0e81739SDavid Howells creds_are_invalid(tsk->cred))) 815e0e81739SDavid Howells goto invalid_creds; 816e0e81739SDavid Howells } else { 817e0e81739SDavid Howells if (unlikely(read_cred_subscribers(tsk->real_cred) < 1 || 818e0e81739SDavid Howells read_cred_subscribers(tsk->cred) < 1 || 819e0e81739SDavid Howells creds_are_invalid(tsk->real_cred) || 820e0e81739SDavid Howells creds_are_invalid(tsk->cred))) 821e0e81739SDavid Howells goto invalid_creds; 822e0e81739SDavid Howells } 823e0e81739SDavid Howells return; 824e0e81739SDavid Howells 825e0e81739SDavid Howells invalid_creds: 826e0e81739SDavid Howells printk(KERN_ERR "CRED: Invalid process credentials\n"); 827e0e81739SDavid Howells printk(KERN_ERR "CRED: At %s:%u\n", file, line); 828e0e81739SDavid Howells 829e0e81739SDavid Howells dump_invalid_creds(tsk->real_cred, "Real", tsk); 830e0e81739SDavid Howells if (tsk->cred != tsk->real_cred) 831e0e81739SDavid Howells dump_invalid_creds(tsk->cred, "Effective", tsk); 832e0e81739SDavid Howells else 833e0e81739SDavid Howells printk(KERN_ERR "CRED: Effective creds == Real creds\n"); 834e0e81739SDavid Howells BUG(); 835e0e81739SDavid Howells } 836e0e81739SDavid Howells EXPORT_SYMBOL(__validate_process_creds); 837e0e81739SDavid Howells 838e0e81739SDavid Howells /* 839e0e81739SDavid Howells * check creds for do_exit() 840e0e81739SDavid Howells */ 841e0e81739SDavid Howells void validate_creds_for_do_exit(struct task_struct *tsk) 842e0e81739SDavid Howells { 843e0e81739SDavid Howells kdebug("validate_creds_for_do_exit(%p,%p{%d,%d})", 844e0e81739SDavid Howells tsk->real_cred, tsk->cred, 845e0e81739SDavid Howells atomic_read(&tsk->cred->usage), 846e0e81739SDavid Howells read_cred_subscribers(tsk->cred)); 847e0e81739SDavid Howells 848e0e81739SDavid Howells __validate_process_creds(tsk, __FILE__, __LINE__); 849e0e81739SDavid Howells } 850e0e81739SDavid Howells 851e0e81739SDavid Howells #endif /* CONFIG_DEBUG_CREDENTIALS */ 852