1c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen/*
2c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * AppArmor security module
3c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
4c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * This file contains AppArmor functions used to manipulate object security
5c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * contexts.
6c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
7c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * Copyright (C) 1998-2008 Novell/SUSE
8c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * Copyright 2009-2010 Canonical Ltd.
9c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
10c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * This program is free software; you can redistribute it and/or
11c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * modify it under the terms of the GNU General Public License as
12c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * published by the Free Software Foundation, version 2 of the
13c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * License.
14c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
15c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
16c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * AppArmor sets confinement on every task, via the the aa_task_cxt and
17c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * the aa_task_cxt.profile, both of which are required and are not allowed
18c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * to be NULL.  The aa_task_cxt is not reference counted and is unique
19c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * to each cred (which is reference count).  The profile pointed to by
20c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * the task_cxt is reference counted.
21c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
22c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * TODO
23c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * If a task uses change_hat it currently does not return to the old
24c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * cred or task context but instead creates a new one.  Ideally the task
25c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * should return to the previous cred if it has not been modified.
26c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
27c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen */
28c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
29c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen#include "include/context.h"
30c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen#include "include/policy.h"
31c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
32c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen/**
33c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * aa_alloc_task_context - allocate a new task_cxt
34c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * @flags: gfp flags for allocation
35c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
36c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * Returns: allocated buffer or NULL on failure
37c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen */
38c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansenstruct aa_task_cxt *aa_alloc_task_context(gfp_t flags)
39c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen{
40c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	return kzalloc(sizeof(struct aa_task_cxt), flags);
41c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen}
42c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
43c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen/**
44c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * aa_free_task_context - free a task_cxt
45c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * @cxt: task_cxt to free (MAYBE NULL)
46c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen */
47c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansenvoid aa_free_task_context(struct aa_task_cxt *cxt)
48c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen{
49c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	if (cxt) {
50c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		aa_put_profile(cxt->profile);
51c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		aa_put_profile(cxt->previous);
52c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		aa_put_profile(cxt->onexec);
53c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
54c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		kzfree(cxt);
55c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	}
56c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen}
57c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
58c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen/**
59c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * aa_dup_task_context - duplicate a task context, incrementing reference counts
60c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * @new: a blank task context      (NOT NULL)
61c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * @old: the task context to copy  (NOT NULL)
62c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen */
63c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansenvoid aa_dup_task_context(struct aa_task_cxt *new, const struct aa_task_cxt *old)
64c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen{
65c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	*new = *old;
66c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	aa_get_profile(new->profile);
67c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	aa_get_profile(new->previous);
68c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	aa_get_profile(new->onexec);
69c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen}
70c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
71c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen/**
723cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen * aa_get_task_profile - Get another task's profile
733cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen * @task: task to query  (NOT NULL)
743cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen *
753cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen * Returns: counted reference to @task's profile
763cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen */
773cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansenstruct aa_profile *aa_get_task_profile(struct task_struct *task)
783cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen{
793cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen	struct aa_profile *p;
803cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen
813cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen	rcu_read_lock();
823cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen	p = aa_get_profile(__aa_task_profile(task));
833cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen	rcu_read_unlock();
843cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen
853cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen	return p;
863cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen}
873cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen
883cfcc19e0b5390c04cb5bfa4e8fde39395410e61John Johansen/**
89c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * aa_replace_current_profile - replace the current tasks profiles
90c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * @profile: new profile  (NOT NULL)
91c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
92c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * Returns: 0 or error on failure
93c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen */
94c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansenint aa_replace_current_profile(struct aa_profile *profile)
95c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen{
96214beacaa7b669473bc963af719fa359a8312ea4John Johansen	struct aa_task_cxt *cxt = current_cxt();
97c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	struct cred *new;
98c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	BUG_ON(!profile);
99c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
100c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	if (cxt->profile == profile)
101c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		return 0;
102c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
103c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	new  = prepare_creds();
104c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	if (!new)
105c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		return -ENOMEM;
106c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
107214beacaa7b669473bc963af719fa359a8312ea4John Johansen	cxt = cred_cxt(new);
1087a2871b566f34d980556072943295efd107eb53cJohn Johansen	if (unconfined(profile) || (cxt->profile->ns != profile->ns))
109c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		/* if switching to unconfined or a different profile namespace
110c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		 * clear out context state
111c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		 */
1127a2871b566f34d980556072943295efd107eb53cJohn Johansen		aa_clear_task_cxt_trans(cxt);
1137a2871b566f34d980556072943295efd107eb53cJohn Johansen
114c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	/* be careful switching cxt->profile, when racing replacement it
11577b071b34045a0c65d0e1f85f3d47fd2b8b7a8a1John Johansen	 * is possible that cxt->profile->replacedby->profile is the reference
11677b071b34045a0c65d0e1f85f3d47fd2b8b7a8a1John Johansen	 * keeping @profile valid, so make sure to get its reference before
11777b071b34045a0c65d0e1f85f3d47fd2b8b7a8a1John Johansen	 * dropping the reference on cxt->profile */
118c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	aa_get_profile(profile);
119c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	aa_put_profile(cxt->profile);
120c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	cxt->profile = profile;
121c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
122c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	commit_creds(new);
123c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	return 0;
124c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen}
125c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
126c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen/**
127c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * aa_set_current_onexec - set the tasks change_profile to happen onexec
128c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * @profile: system profile to set at exec  (MAYBE NULL to clear value)
129c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
130c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * Returns: 0 or error on failure
131c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen */
132c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansenint aa_set_current_onexec(struct aa_profile *profile)
133c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen{
134c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	struct aa_task_cxt *cxt;
135c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	struct cred *new = prepare_creds();
136c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	if (!new)
137c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		return -ENOMEM;
138c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
139214beacaa7b669473bc963af719fa359a8312ea4John Johansen	cxt = cred_cxt(new);
140c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	aa_get_profile(profile);
141c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	aa_put_profile(cxt->onexec);
142c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	cxt->onexec = profile;
143c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
144c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	commit_creds(new);
145c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	return 0;
146c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen}
147c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
148c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen/**
149c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * aa_set_current_hat - set the current tasks hat
150c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * @profile: profile to set as the current hat  (NOT NULL)
151c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * @token: token value that must be specified to change from the hat
152c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
153c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * Do switch of tasks hat.  If the task is currently in a hat
154c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * validate the token to match.
155c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
156c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * Returns: 0 or error on failure
157c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen */
158c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansenint aa_set_current_hat(struct aa_profile *profile, u64 token)
159c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen{
160c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	struct aa_task_cxt *cxt;
161c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	struct cred *new = prepare_creds();
162c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	if (!new)
163c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		return -ENOMEM;
164c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	BUG_ON(!profile);
165c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
166214beacaa7b669473bc963af719fa359a8312ea4John Johansen	cxt = cred_cxt(new);
167c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	if (!cxt->previous) {
168c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		/* transfer refcount */
169c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		cxt->previous = cxt->profile;
170c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		cxt->token = token;
171c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	} else if (cxt->token == token) {
172c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		aa_put_profile(cxt->profile);
173c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	} else {
174c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		/* previous_profile && cxt->token != token */
175c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		abort_creds(new);
176c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		return -EACCES;
177c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	}
17877b071b34045a0c65d0e1f85f3d47fd2b8b7a8a1John Johansen	cxt->profile = aa_get_newest_profile(profile);
179c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	/* clear exec on switching context */
180c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	aa_put_profile(cxt->onexec);
181c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	cxt->onexec = NULL;
182c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
183c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	commit_creds(new);
184c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	return 0;
185c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen}
186c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
187c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen/**
188c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * aa_restore_previous_profile - exit from hat context restoring the profile
189c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * @token: the token that must be matched to exit hat context
190c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
191c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * Attempt to return out of a hat to the previous profile.  The token
192c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * must match the stored token value.
193c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen *
194c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen * Returns: 0 or error of failure
195c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen */
196c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansenint aa_restore_previous_profile(u64 token)
197c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen{
198c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	struct aa_task_cxt *cxt;
199c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	struct cred *new = prepare_creds();
200c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	if (!new)
201c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		return -ENOMEM;
202c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
203214beacaa7b669473bc963af719fa359a8312ea4John Johansen	cxt = cred_cxt(new);
204c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	if (cxt->token != token) {
205c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		abort_creds(new);
206c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		return -EACCES;
207c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	}
208c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	/* ignore restores when there is no saved profile */
209c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	if (!cxt->previous) {
210c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		abort_creds(new);
211c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen		return 0;
212c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	}
213c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
214c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	aa_put_profile(cxt->profile);
21577b071b34045a0c65d0e1f85f3d47fd2b8b7a8a1John Johansen	cxt->profile = aa_get_newest_profile(cxt->previous);
216c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	BUG_ON(!cxt->profile);
2177a2871b566f34d980556072943295efd107eb53cJohn Johansen	/* clear exec && prev information when restoring to previous context */
2187a2871b566f34d980556072943295efd107eb53cJohn Johansen	aa_clear_task_cxt_trans(cxt);
219c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen
220c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	commit_creds(new);
221c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen	return 0;
222c75afcd153f6147d3b094f45a1d87e5df7f4f053John Johansen}
223