xref: /linux/security/apparmor/task.c (revision 8fefe68784ae1606e11a5c65c04167c3b95051a0)
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