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