xref: /openbmc/linux/kernel/cred.c (revision 9b1bf12d)
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