]>
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 | 16 | * AppArmor sets confinement on every task, via the the aa_task_ctx and |
637f688d | 17 | * the aa_task_ctx.label, both of which are required and are not allowed |
55a26ebf | 18 | * to be NULL. The aa_task_ctx is not reference counted and is unique |
637f688d | 19 | * to each cred (which is reference count). The label 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 | ||
c75afcd1 JJ |
32 | |
33 | /** | |
55a26ebf JJ |
34 | * aa_free_task_context - free a task_ctx |
35 | * @ctx: task_ctx to free (MAYBE NULL) | |
c75afcd1 | 36 | */ |
55a26ebf | 37 | void aa_free_task_context(struct aa_task_ctx *ctx) |
c75afcd1 | 38 | { |
55a26ebf | 39 | if (ctx) { |
637f688d JJ |
40 | aa_put_label(ctx->label); |
41 | aa_put_label(ctx->previous); | |
42 | aa_put_label(ctx->onexec); | |
c75afcd1 JJ |
43 | } |
44 | } | |
45 | ||
46 | /** | |
47 | * aa_dup_task_context - duplicate a task context, incrementing reference counts | |
48 | * @new: a blank task context (NOT NULL) | |
49 | * @old: the task context to copy (NOT NULL) | |
50 | */ | |
55a26ebf | 51 | void aa_dup_task_context(struct aa_task_ctx *new, const struct aa_task_ctx *old) |
c75afcd1 JJ |
52 | { |
53 | *new = *old; | |
637f688d JJ |
54 | aa_get_label(new->label); |
55 | aa_get_label(new->previous); | |
56 | aa_get_label(new->onexec); | |
c75afcd1 JJ |
57 | } |
58 | ||
3cfcc19e | 59 | /** |
637f688d | 60 | * aa_get_task_label - Get another task's label |
3cfcc19e JJ |
61 | * @task: task to query (NOT NULL) |
62 | * | |
637f688d | 63 | * Returns: counted reference to @task's label |
3cfcc19e | 64 | */ |
637f688d | 65 | struct aa_label *aa_get_task_label(struct task_struct *task) |
3cfcc19e | 66 | { |
637f688d | 67 | struct aa_label *p; |
3cfcc19e JJ |
68 | |
69 | rcu_read_lock(); | |
637f688d | 70 | p = aa_get_newest_label(__aa_task_raw_label(task)); |
3cfcc19e JJ |
71 | rcu_read_unlock(); |
72 | ||
73 | return p; | |
74 | } | |
75 | ||
c75afcd1 | 76 | /** |
637f688d JJ |
77 | * aa_replace_current_label - replace the current tasks label |
78 | * @label: new label (NOT NULL) | |
c75afcd1 JJ |
79 | * |
80 | * Returns: 0 or error on failure | |
81 | */ | |
637f688d | 82 | int aa_replace_current_label(struct aa_label *label) |
c75afcd1 | 83 | { |
55a26ebf | 84 | struct aa_task_ctx *ctx = current_ctx(); |
c75afcd1 | 85 | struct cred *new; |
637f688d | 86 | AA_BUG(!label); |
c75afcd1 | 87 | |
637f688d | 88 | if (ctx->label == label) |
c75afcd1 JJ |
89 | return 0; |
90 | ||
a20aa95f JJ |
91 | if (current_cred() != current_real_cred()) |
92 | return -EBUSY; | |
93 | ||
c75afcd1 JJ |
94 | new = prepare_creds(); |
95 | if (!new) | |
96 | return -ENOMEM; | |
97 | ||
55a26ebf | 98 | ctx = cred_ctx(new); |
637f688d JJ |
99 | if (unconfined(label) || (labels_ns(ctx->label) != labels_ns(label))) |
100 | /* if switching to unconfined or a different label namespace | |
c75afcd1 JJ |
101 | * clear out context state |
102 | */ | |
55a26ebf | 103 | aa_clear_task_ctx_trans(ctx); |
7a2871b5 | 104 | |
55a26ebf JJ |
105 | /* |
106 | * be careful switching ctx->profile, when racing replacement it | |
107 | * is possible that ctx->profile->proxy->profile is the reference | |
77b071b3 | 108 | * keeping @profile valid, so make sure to get its reference before |
55a26ebf JJ |
109 | * dropping the reference on ctx->profile |
110 | */ | |
637f688d JJ |
111 | aa_get_label(label); |
112 | aa_put_label(ctx->label); | |
113 | ctx->label = label; | |
c75afcd1 JJ |
114 | |
115 | commit_creds(new); | |
116 | return 0; | |
117 | } | |
118 | ||
119 | /** | |
120 | * aa_set_current_onexec - set the tasks change_profile to happen onexec | |
637f688d JJ |
121 | * @label: system label to set at exec (MAYBE NULL to clear value) |
122 | * @stack: whether stacking should be done | |
c75afcd1 JJ |
123 | * Returns: 0 or error on failure |
124 | */ | |
637f688d | 125 | int aa_set_current_onexec(struct aa_label *label, bool stack) |
c75afcd1 | 126 | { |
55a26ebf | 127 | struct aa_task_ctx *ctx; |
c75afcd1 JJ |
128 | struct cred *new = prepare_creds(); |
129 | if (!new) | |
130 | return -ENOMEM; | |
131 | ||
55a26ebf | 132 | ctx = cred_ctx(new); |
637f688d JJ |
133 | aa_get_label(label); |
134 | aa_clear_task_ctx_trans(ctx); | |
135 | ctx->onexec = label; | |
136 | ctx->token = stack; | |
c75afcd1 JJ |
137 | |
138 | commit_creds(new); | |
139 | return 0; | |
140 | } | |
141 | ||
142 | /** | |
143 | * aa_set_current_hat - set the current tasks hat | |
637f688d | 144 | * @label: label to set as the current hat (NOT NULL) |
c75afcd1 JJ |
145 | * @token: token value that must be specified to change from the hat |
146 | * | |
147 | * Do switch of tasks hat. If the task is currently in a hat | |
148 | * validate the token to match. | |
149 | * | |
150 | * Returns: 0 or error on failure | |
151 | */ | |
637f688d | 152 | int aa_set_current_hat(struct aa_label *label, u64 token) |
c75afcd1 | 153 | { |
55a26ebf | 154 | struct aa_task_ctx *ctx; |
c75afcd1 JJ |
155 | struct cred *new = prepare_creds(); |
156 | if (!new) | |
157 | return -ENOMEM; | |
637f688d | 158 | AA_BUG(!label); |
c75afcd1 | 159 | |
55a26ebf JJ |
160 | ctx = cred_ctx(new); |
161 | if (!ctx->previous) { | |
c75afcd1 | 162 | /* transfer refcount */ |
637f688d | 163 | ctx->previous = ctx->label; |
55a26ebf JJ |
164 | ctx->token = token; |
165 | } else if (ctx->token == token) { | |
637f688d | 166 | aa_put_label(ctx->label); |
c75afcd1 | 167 | } else { |
55a26ebf | 168 | /* previous_profile && ctx->token != token */ |
c75afcd1 JJ |
169 | abort_creds(new); |
170 | return -EACCES; | |
171 | } | |
637f688d | 172 | ctx->label = aa_get_newest_label(label); |
c75afcd1 | 173 | /* clear exec on switching context */ |
637f688d | 174 | aa_put_label(ctx->onexec); |
55a26ebf | 175 | ctx->onexec = NULL; |
c75afcd1 JJ |
176 | |
177 | commit_creds(new); | |
178 | return 0; | |
179 | } | |
180 | ||
181 | /** | |
637f688d | 182 | * aa_restore_previous_label - exit from hat context restoring previous label |
c75afcd1 JJ |
183 | * @token: the token that must be matched to exit hat context |
184 | * | |
637f688d | 185 | * Attempt to return out of a hat to the previous label. The token |
c75afcd1 JJ |
186 | * must match the stored token value. |
187 | * | |
188 | * Returns: 0 or error of failure | |
189 | */ | |
637f688d | 190 | int aa_restore_previous_label(u64 token) |
c75afcd1 | 191 | { |
55a26ebf | 192 | struct aa_task_ctx *ctx; |
c75afcd1 JJ |
193 | struct cred *new = prepare_creds(); |
194 | if (!new) | |
195 | return -ENOMEM; | |
196 | ||
55a26ebf JJ |
197 | ctx = cred_ctx(new); |
198 | if (ctx->token != token) { | |
c75afcd1 JJ |
199 | abort_creds(new); |
200 | return -EACCES; | |
201 | } | |
637f688d | 202 | /* ignore restores when there is no saved label */ |
55a26ebf | 203 | if (!ctx->previous) { |
c75afcd1 JJ |
204 | abort_creds(new); |
205 | return 0; | |
206 | } | |
207 | ||
637f688d JJ |
208 | aa_put_label(ctx->label); |
209 | ctx->label = aa_get_newest_label(ctx->previous); | |
210 | AA_BUG(!ctx->label); | |
7a2871b5 | 211 | /* clear exec && prev information when restoring to previous context */ |
55a26ebf | 212 | aa_clear_task_ctx_trans(ctx); |
c75afcd1 JJ |
213 | |
214 | commit_creds(new); | |
215 | return 0; | |
216 | } |