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