]>
Commit | Line | Data |
---|---|---|
c75afcd1 JJ |
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 | * | |
55a26ebf JJ |
16 | * AppArmor sets confinement on every task, via the the aa_task_ctx and |
17 | * the aa_task_ctx.profile, both of which are required and are not allowed | |
18 | * to be NULL. The aa_task_ctx is not reference counted and is unique | |
c75afcd1 | 19 | * to each cred (which is reference count). The profile pointed to by |
55a26ebf | 20 | * the task_ctx is reference counted. |
c75afcd1 JJ |
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 | /** | |
55a26ebf | 33 | * aa_alloc_task_context - allocate a new task_ctx |
c75afcd1 JJ |
34 | * @flags: gfp flags for allocation |
35 | * | |
36 | * Returns: allocated buffer or NULL on failure | |
37 | */ | |
55a26ebf | 38 | struct aa_task_ctx *aa_alloc_task_context(gfp_t flags) |
c75afcd1 | 39 | { |
55a26ebf | 40 | return kzalloc(sizeof(struct aa_task_ctx), flags); |
c75afcd1 JJ |
41 | } |
42 | ||
43 | /** | |
55a26ebf JJ |
44 | * aa_free_task_context - free a task_ctx |
45 | * @ctx: task_ctx to free (MAYBE NULL) | |
c75afcd1 | 46 | */ |
55a26ebf | 47 | void aa_free_task_context(struct aa_task_ctx *ctx) |
c75afcd1 | 48 | { |
55a26ebf JJ |
49 | if (ctx) { |
50 | aa_put_profile(ctx->profile); | |
51 | aa_put_profile(ctx->previous); | |
52 | aa_put_profile(ctx->onexec); | |
c75afcd1 | 53 | |
55a26ebf | 54 | kzfree(ctx); |
c75afcd1 JJ |
55 | } |
56 | } | |
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 | */ | |
55a26ebf | 63 | void aa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old) |
c75afcd1 JJ |
64 | { |
65 | *new = *old; | |
66 | aa_get_profile(new->profile); | |
67 | aa_get_profile(new->previous); | |
68 | aa_get_profile(new->onexec); | |
69 | } | |
70 | ||
3cfcc19e JJ |
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 | 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 | return p; | |
86 | } | |
87 | ||
c75afcd1 JJ |
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 | int aa_replace_current_profile(struct aa_profile *profile) | |
95 | { | |
55a26ebf | 96 | struct aa_task_ctx *ctx = current_ctx(); |
c75afcd1 | 97 | struct cred *new; |
e6bfa25d | 98 | AA_BUG(!profile); |
c75afcd1 | 99 | |
55a26ebf | 100 | if (ctx->profile == profile) |
c75afcd1 JJ |
101 | return 0; |
102 | ||
a20aa95f JJ |
103 | if (current_cred() != current_real_cred()) |
104 | return -EBUSY; | |
105 | ||
c75afcd1 JJ |
106 | new = prepare_creds(); |
107 | if (!new) | |
108 | return -ENOMEM; | |
109 | ||
55a26ebf JJ |
110 | ctx = cred_ctx(new); |
111 | if (unconfined(profile) || (ctx->profile->ns != profile->ns)) | |
c75afcd1 JJ |
112 | /* if switching to unconfined or a different profile namespace |
113 | * clear out context state | |
114 | */ | |
55a26ebf | 115 | aa_clear_task_ctx_trans(ctx); |
7a2871b5 | 116 | |
55a26ebf JJ |
117 | /* |
118 | * be careful switching ctx->profile, when racing replacement it | |
119 | * is possible that ctx->profile->proxy->profile is the reference | |
77b071b3 | 120 | * keeping @profile valid, so make sure to get its reference before |
55a26ebf JJ |
121 | * dropping the reference on ctx->profile |
122 | */ | |
c75afcd1 | 123 | aa_get_profile(profile); |
55a26ebf JJ |
124 | aa_put_profile(ctx->profile); |
125 | ctx->profile = profile; | |
c75afcd1 JJ |
126 | |
127 | commit_creds(new); | |
128 | return 0; | |
129 | } | |
130 | ||
131 | /** | |
132 | * aa_set_current_onexec - set the tasks change_profile to happen onexec | |
133 | * @profile: system profile to set at exec (MAYBE NULL to clear value) | |
134 | * | |
135 | * Returns: 0 or error on failure | |
136 | */ | |
137 | int aa_set_current_onexec(struct aa_profile *profile) | |
138 | { | |
55a26ebf | 139 | struct aa_task_ctx *ctx; |
c75afcd1 JJ |
140 | struct cred *new = prepare_creds(); |
141 | if (!new) | |
142 | return -ENOMEM; | |
143 | ||
55a26ebf | 144 | ctx = cred_ctx(new); |
c75afcd1 | 145 | aa_get_profile(profile); |
55a26ebf JJ |
146 | aa_put_profile(ctx->onexec); |
147 | ctx->onexec = profile; | |
c75afcd1 JJ |
148 | |
149 | commit_creds(new); | |
150 | return 0; | |
151 | } | |
152 | ||
153 | /** | |
154 | * aa_set_current_hat - set the current tasks hat | |
155 | * @profile: profile to set as the current hat (NOT NULL) | |
156 | * @token: token value that must be specified to change from the hat | |
157 | * | |
158 | * Do switch of tasks hat. If the task is currently in a hat | |
159 | * validate the token to match. | |
160 | * | |
161 | * Returns: 0 or error on failure | |
162 | */ | |
163 | int aa_set_current_hat(struct aa_profile *profile, u64 token) | |
164 | { | |
55a26ebf | 165 | struct aa_task_ctx *ctx; |
c75afcd1 JJ |
166 | struct cred *new = prepare_creds(); |
167 | if (!new) | |
168 | return -ENOMEM; | |
e6bfa25d | 169 | AA_BUG(!profile); |
c75afcd1 | 170 | |
55a26ebf JJ |
171 | ctx = cred_ctx(new); |
172 | if (!ctx->previous) { | |
c75afcd1 | 173 | /* transfer refcount */ |
55a26ebf JJ |
174 | ctx->previous = ctx->profile; |
175 | ctx->token = token; | |
176 | } else if (ctx->token == token) { | |
177 | aa_put_profile(ctx->profile); | |
c75afcd1 | 178 | } else { |
55a26ebf | 179 | /* previous_profile && ctx->token != token */ |
c75afcd1 JJ |
180 | abort_creds(new); |
181 | return -EACCES; | |
182 | } | |
55a26ebf | 183 | ctx->profile = aa_get_newest_profile(profile); |
c75afcd1 | 184 | /* clear exec on switching context */ |
55a26ebf JJ |
185 | aa_put_profile(ctx->onexec); |
186 | ctx->onexec = NULL; | |
c75afcd1 JJ |
187 | |
188 | commit_creds(new); | |
189 | return 0; | |
190 | } | |
191 | ||
192 | /** | |
193 | * aa_restore_previous_profile - exit from hat context restoring the profile | |
194 | * @token: the token that must be matched to exit hat context | |
195 | * | |
196 | * Attempt to return out of a hat to the previous profile. The token | |
197 | * must match the stored token value. | |
198 | * | |
199 | * Returns: 0 or error of failure | |
200 | */ | |
201 | int aa_restore_previous_profile(u64 token) | |
202 | { | |
55a26ebf | 203 | struct aa_task_ctx *ctx; |
c75afcd1 JJ |
204 | struct cred *new = prepare_creds(); |
205 | if (!new) | |
206 | return -ENOMEM; | |
207 | ||
55a26ebf JJ |
208 | ctx = cred_ctx(new); |
209 | if (ctx->token != token) { | |
c75afcd1 JJ |
210 | abort_creds(new); |
211 | return -EACCES; | |
212 | } | |
213 | /* ignore restores when there is no saved profile */ | |
55a26ebf | 214 | if (!ctx->previous) { |
c75afcd1 JJ |
215 | abort_creds(new); |
216 | return 0; | |
217 | } | |
218 | ||
55a26ebf JJ |
219 | aa_put_profile(ctx->profile); |
220 | ctx->profile = aa_get_newest_profile(ctx->previous); | |
221 | AA_BUG(!ctx->profile); | |
7a2871b5 | 222 | /* clear exec && prev information when restoring to previous context */ |
55a26ebf | 223 | aa_clear_task_ctx_trans(ctx); |
c75afcd1 JJ |
224 | |
225 | commit_creds(new); | |
226 | return 0; | |
227 | } |