1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * AppArmor security module
4 *
5 * This file contains AppArmor task related definitions and mediation
6 *
7 * Copyright 2017 Canonical Ltd.
8 *
9 * TODO
10 * If a task uses change_hat it currently does not return to the old
11 * cred or task context but instead creates a new one. Ideally the task
12 * should return to the previous cred if it has not been modified.
13 */
14
15 #include <linux/gfp.h>
16 #include <linux/ptrace.h>
17 #include <linux/task_work.h>
18
19 #include "include/path.h"
20 #include "include/audit.h"
21 #include "include/cred.h"
22 #include "include/policy.h"
23 #include "include/task.h"
24
25 /**
26 * aa_get_task_label - Get another task's label
27 * @task: task to query (NOT NULL)
28 *
29 * Returns: counted reference to @task's label
30 */
aa_get_task_label(struct task_struct * task)31 struct aa_label *aa_get_task_label(struct task_struct *task)
32 {
33 struct aa_label *p;
34
35 rcu_read_lock();
36 p = aa_get_newest_cred_label(__task_cred(task));
37 rcu_read_unlock();
38
39 return p;
40 }
41
42 /**
43 * aa_replace_current_label - replace the current tasks label
44 * @label: new label (NOT NULL)
45 *
46 * Returns: 0 or error on failure
47 */
aa_replace_current_label(struct aa_label * label)48 int aa_replace_current_label(struct aa_label *label)
49 {
50 struct aa_label *old = aa_current_raw_label();
51 struct aa_task_ctx *ctx = task_ctx(current);
52 struct cred *new;
53
54 AA_BUG(!label);
55
56 if (old == label)
57 return 0;
58
59 if (current_cred() != current_real_cred())
60 return -EBUSY;
61
62 new = prepare_creds();
63 if (!new)
64 return -ENOMEM;
65
66 if (ctx->nnp && label_is_stale(ctx->nnp)) {
67 struct aa_label *tmp = ctx->nnp;
68
69 ctx->nnp = aa_get_newest_label(tmp);
70 aa_put_label(tmp);
71 }
72 if (unconfined(label) || (labels_ns(old) != labels_ns(label)))
73 /*
74 * if switching to unconfined or a different label namespace
75 * clear out context state
76 */
77 aa_clear_task_ctx_trans(task_ctx(current));
78
79 /*
80 * be careful switching cred label, when racing replacement it
81 * is possible that the cred labels's->proxy->label is the reference
82 * keeping @label valid, so make sure to get its reference before
83 * dropping the reference on the cred's label
84 */
85 aa_get_label(label);
86 aa_put_label(cred_label(new));
87 set_cred_label(new, label);
88
89 commit_creds(new);
90 return 0;
91 }
92
aa_replace_stale_label_tw_func(struct callback_head * tw)93 static void aa_replace_stale_label_tw_func(struct callback_head *tw)
94 {
95 struct aa_task_ctx *ctx = task_ctx(current);
96 struct aa_label *label;
97
98 ctx->label_replacement_pending = false;
99 label = aa_current_raw_label();
100 if (!label_is_stale(label))
101 return;
102 label = aa_get_newest_label(label);
103 aa_replace_current_label(label);
104 aa_put_label(label);
105 }
106
107 /* replace the current task's stale label on syscall return */
aa_schedule_stale_label_replacement(void)108 void aa_schedule_stale_label_replacement(void)
109 {
110 struct aa_task_ctx *ctx = task_ctx(current);
111
112 if (ctx->label_replacement_pending)
113 return;
114 init_task_work(&ctx->label_replacement_tw, aa_replace_stale_label_tw_func);
115 if (task_work_add(current, &ctx->label_replacement_tw, TWA_RESUME) == 0)
116 ctx->label_replacement_pending = true;
117 }
118
119
120 /**
121 * aa_set_current_onexec - set the tasks change_profile to happen onexec
122 * @label: system label to set at exec (MAYBE NULL to clear value)
123 * @stack: whether stacking should be done
124 */
aa_set_current_onexec(struct aa_label * label,bool stack)125 void aa_set_current_onexec(struct aa_label *label, bool stack)
126 {
127 struct aa_task_ctx *ctx = task_ctx(current);
128
129 aa_get_label(label);
130 aa_put_label(ctx->onexec);
131 ctx->onexec = label;
132 ctx->token = stack;
133 }
134
135 /**
136 * aa_set_current_hat - set the current tasks hat
137 * @label: label to set as the current hat (NOT NULL)
138 * @token: token value that must be specified to change from the hat
139 *
140 * Do switch of tasks hat. If the task is currently in a hat
141 * validate the token to match.
142 *
143 * Returns: 0 or error on failure
144 */
aa_set_current_hat(struct aa_label * label,u64 token)145 int aa_set_current_hat(struct aa_label *label, u64 token)
146 {
147 struct aa_task_ctx *ctx = task_ctx(current);
148 struct cred *new;
149
150 new = prepare_creds();
151 if (!new)
152 return -ENOMEM;
153 AA_BUG(!label);
154
155 if (!ctx->previous) {
156 /* transfer refcount */
157 ctx->previous = cred_label(new);
158 ctx->token = token;
159 } else if (ctx->token == token) {
160 aa_put_label(cred_label(new));
161 } else {
162 /* previous_profile && ctx->token != token */
163 abort_creds(new);
164 return -EACCES;
165 }
166
167 set_cred_label(new, aa_get_newest_label(label));
168 /* clear exec on switching context */
169 aa_put_label(ctx->onexec);
170 ctx->onexec = NULL;
171
172 commit_creds(new);
173 return 0;
174 }
175
176 /**
177 * aa_restore_previous_label - exit from hat context restoring previous label
178 * @token: the token that must be matched to exit hat context
179 *
180 * Attempt to return out of a hat to the previous label. The token
181 * must match the stored token value.
182 *
183 * Returns: 0 or error of failure
184 */
aa_restore_previous_label(u64 token)185 int aa_restore_previous_label(u64 token)
186 {
187 struct aa_task_ctx *ctx = task_ctx(current);
188 struct cred *new;
189
190 if (ctx->token != token)
191 return -EACCES;
192 /* ignore restores when there is no saved label */
193 if (!ctx->previous)
194 return 0;
195
196 new = prepare_creds();
197 if (!new)
198 return -ENOMEM;
199
200 aa_put_label(cred_label(new));
201 set_cred_label(new, aa_get_newest_label(ctx->previous));
202 AA_BUG(!cred_label(new));
203 /* clear exec && prev information when restoring to previous context */
204 aa_clear_task_ctx_trans(ctx);
205
206 commit_creds(new);
207
208 return 0;
209 }
210
211 /**
212 * audit_ptrace_mask - convert mask to permission string
213 * @mask: permission mask to convert
214 *
215 * Returns: pointer to static string
216 */
audit_ptrace_mask(u32 mask)217 static const char *audit_ptrace_mask(u32 mask)
218 {
219 switch (mask) {
220 case MAY_READ:
221 return "read";
222 case MAY_WRITE:
223 return "trace";
224 case AA_MAY_BE_READ:
225 return "readby";
226 case AA_MAY_BE_TRACED:
227 return "tracedby";
228 }
229 return "";
230 }
231
232 /* call back to audit ptrace fields */
audit_ptrace_cb(struct audit_buffer * ab,void * va)233 static void audit_ptrace_cb(struct audit_buffer *ab, void *va)
234 {
235 struct common_audit_data *sa = va;
236 struct apparmor_audit_data *ad = aad(sa);
237
238 if (ad->request & AA_PTRACE_PERM_MASK) {
239 audit_log_format(ab, " requested_mask=\"%s\"",
240 audit_ptrace_mask(ad->request));
241
242 if (ad->denied & AA_PTRACE_PERM_MASK) {
243 audit_log_format(ab, " denied_mask=\"%s\"",
244 audit_ptrace_mask(ad->denied));
245 }
246 }
247 audit_log_format(ab, " peer=");
248 aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
249 FLAGS_NONE, GFP_ATOMIC);
250 }
251
252 /* assumes check for RULE_MEDIATES is already done */
253 /* TODO: conditionals */
profile_ptrace_perm(const struct cred * cred,struct aa_profile * profile,struct aa_label * peer,u32 request,struct apparmor_audit_data * ad)254 static int profile_ptrace_perm(const struct cred *cred,
255 struct aa_profile *profile,
256 struct aa_label *peer, u32 request,
257 struct apparmor_audit_data *ad)
258 {
259 struct aa_ruleset *rules = profile->label.rules[0];
260 struct aa_perms perms = { };
261
262 ad->subj_cred = cred;
263 ad->peer = peer;
264 aa_profile_match_label(profile, rules, peer, AA_CLASS_PTRACE, request,
265 &perms);
266 aa_apply_modes_to_perms(profile, &perms);
267 return aa_check_perms(profile, &perms, request, ad, audit_ptrace_cb);
268 }
269
profile_tracee_perm(const struct cred * cred,struct aa_profile * tracee,struct aa_label * tracer,u32 request,struct apparmor_audit_data * ad)270 static int profile_tracee_perm(const struct cred *cred,
271 struct aa_profile *tracee,
272 struct aa_label *tracer, u32 request,
273 struct apparmor_audit_data *ad)
274 {
275 if (profile_unconfined(tracee) || unconfined(tracer) ||
276 !label_mediates(&tracee->label, AA_CLASS_PTRACE))
277 return 0;
278
279 return profile_ptrace_perm(cred, tracee, tracer, request, ad);
280 }
281
profile_tracer_perm(const struct cred * cred,struct aa_profile * tracer,struct aa_label * tracee,u32 request,struct apparmor_audit_data * ad)282 static int profile_tracer_perm(const struct cred *cred,
283 struct aa_profile *tracer,
284 struct aa_label *tracee, u32 request,
285 struct apparmor_audit_data *ad)
286 {
287 if (profile_unconfined(tracer))
288 return 0;
289
290 if (label_mediates(&tracer->label, AA_CLASS_PTRACE))
291 return profile_ptrace_perm(cred, tracer, tracee, request, ad);
292
293 /* profile uses the old style capability check for ptrace */
294 if (&tracer->label == tracee)
295 return 0;
296
297 ad->subj_label = &tracer->label;
298 ad->peer = tracee;
299 ad->request = 0;
300 ad->error = aa_capable(cred, &tracer->label, CAP_SYS_PTRACE,
301 CAP_OPT_NONE);
302
303 return aa_audit(AUDIT_APPARMOR_AUTO, tracer, ad, audit_ptrace_cb);
304 }
305
306 /**
307 * aa_may_ptrace - test if tracer task can trace the tracee
308 * @tracer_cred: cred of task doing the tracing (NOT NULL)
309 * @tracer: label of the task doing the tracing (NOT NULL)
310 * @tracee_cred: cred of task to be traced
311 * @tracee: task label to be traced
312 * @request: permission request
313 *
314 * Returns: %0 else error code if permission denied or error
315 */
aa_may_ptrace(const struct cred * tracer_cred,struct aa_label * tracer,const struct cred * tracee_cred,struct aa_label * tracee,u32 request)316 int aa_may_ptrace(const struct cred *tracer_cred, struct aa_label *tracer,
317 const struct cred *tracee_cred, struct aa_label *tracee,
318 u32 request)
319 {
320 struct aa_profile *profile;
321 u32 xrequest = request << PTRACE_PERM_SHIFT;
322 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, AA_CLASS_PTRACE, OP_PTRACE);
323
324 return xcheck_labels(tracer, tracee, profile,
325 profile_tracer_perm(tracer_cred, profile, tracee,
326 request, &sa),
327 profile_tracee_perm(tracee_cred, profile, tracer,
328 xrequest, &sa));
329 }
330
get_current_exe_path(char * buffer,int buffer_size)331 static const char *get_current_exe_path(char *buffer, int buffer_size)
332 {
333 struct file *exe_file;
334 struct path p;
335 const char *path_str;
336
337 exe_file = get_task_exe_file(current);
338 if (!exe_file)
339 return ERR_PTR(-ENOENT);
340 p = exe_file->f_path;
341 path_get(&p);
342
343 if (aa_path_name(&p, FLAG_VIEW_SUBNS, buffer, &path_str, NULL, NULL))
344 path_str = ERR_PTR(-ENOMEM);
345
346 fput(exe_file);
347 path_put(&p);
348
349 return path_str;
350 }
351
352 /* call back to audit ptrace fields */
audit_ns_cb(struct audit_buffer * ab,void * va)353 static void audit_ns_cb(struct audit_buffer *ab, void *va)
354 {
355 struct apparmor_audit_data *ad = aad_of_va(va);
356 char *buffer;
357 const char *path;
358
359 if (ad->request & AA_USERNS_CREATE)
360 audit_log_format(ab, " requested=\"userns_create\"");
361
362 if (ad->denied & AA_USERNS_CREATE)
363 audit_log_format(ab, " denied=\"userns_create\"");
364
365 buffer = aa_get_buffer(false);
366 if (!buffer)
367 return; // OOM
368 path = get_current_exe_path(buffer, aa_g_path_max);
369 if (!IS_ERR(path))
370 audit_log_format(ab, " execpath=\"%s\"", path);
371 aa_put_buffer(buffer);
372 }
373
aa_profile_ns_perm(struct aa_profile * profile,struct apparmor_audit_data * ad,u32 request)374 int aa_profile_ns_perm(struct aa_profile *profile,
375 struct apparmor_audit_data *ad,
376 u32 request)
377 {
378 struct aa_perms perms = { };
379 int error = 0;
380
381 ad->subj_label = &profile->label;
382 ad->request = request;
383
384 if (!profile_unconfined(profile)) {
385 struct aa_ruleset *rules = profile->label.rules[0];
386 aa_state_t state;
387
388 state = RULE_MEDIATES(rules, ad->class);
389 if (!state)
390 /* TODO: add flag to complain about unmediated */
391 return 0;
392 perms = *aa_lookup_perms(rules->policy, state);
393 aa_apply_modes_to_perms(profile, &perms);
394 error = aa_check_perms(profile, &perms, request, ad,
395 audit_ns_cb);
396 }
397
398 return error;
399 }
400