xref: /openbmc/linux/security/apparmor/lib.c (revision 9a29f5fc)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * AppArmor security module
4  *
5  * This file contains basic common functions used in AppArmor
6  *
7  * Copyright (C) 1998-2008 Novell/SUSE
8  * Copyright 2009-2010 Canonical Ltd.
9  */
10 
11 #include <linux/ctype.h>
12 #include <linux/mm.h>
13 #include <linux/slab.h>
14 #include <linux/string.h>
15 #include <linux/vmalloc.h>
16 
17 #include "include/audit.h"
18 #include "include/apparmor.h"
19 #include "include/lib.h"
20 #include "include/perms.h"
21 #include "include/policy.h"
22 
23 struct aa_perms nullperms;
24 struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
25 			     .quiet = ALL_PERMS_MASK,
26 			     .hide = ALL_PERMS_MASK };
27 
28 /**
29  * aa_split_fqname - split a fqname into a profile and namespace name
30  * @fqname: a full qualified name in namespace profile format (NOT NULL)
31  * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
32  *
33  * Returns: profile name or NULL if one is not specified
34  *
35  * Split a namespace name from a profile name (see policy.c for naming
36  * description).  If a portion of the name is missing it returns NULL for
37  * that portion.
38  *
39  * NOTE: may modify the @fqname string.  The pointers returned point
40  *       into the @fqname string.
41  */
42 char *aa_split_fqname(char *fqname, char **ns_name)
43 {
44 	char *name = strim(fqname);
45 
46 	*ns_name = NULL;
47 	if (name[0] == ':') {
48 		char *split = strchr(&name[1], ':');
49 		*ns_name = skip_spaces(&name[1]);
50 		if (split) {
51 			/* overwrite ':' with \0 */
52 			*split++ = 0;
53 			if (strncmp(split, "//", 2) == 0)
54 				split += 2;
55 			name = skip_spaces(split);
56 		} else
57 			/* a ns name without a following profile is allowed */
58 			name = NULL;
59 	}
60 	if (name && *name == 0)
61 		name = NULL;
62 
63 	return name;
64 }
65 
66 /**
67  * skipn_spaces - Removes leading whitespace from @str.
68  * @str: The string to be stripped.
69  *
70  * Returns a pointer to the first non-whitespace character in @str.
71  * if all whitespace will return NULL
72  */
73 
74 const char *skipn_spaces(const char *str, size_t n)
75 {
76 	for (; n && isspace(*str); --n)
77 		++str;
78 	if (n)
79 		return (char *)str;
80 	return NULL;
81 }
82 
83 const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
84 			     size_t *ns_len)
85 {
86 	const char *end = fqname + n;
87 	const char *name = skipn_spaces(fqname, n);
88 
89 	*ns_name = NULL;
90 	*ns_len = 0;
91 
92 	if (!name)
93 		return NULL;
94 
95 	if (name[0] == ':') {
96 		char *split = strnchr(&name[1], end - &name[1], ':');
97 		*ns_name = skipn_spaces(&name[1], end - &name[1]);
98 		if (!*ns_name)
99 			return NULL;
100 		if (split) {
101 			*ns_len = split - *ns_name;
102 			if (*ns_len == 0)
103 				*ns_name = NULL;
104 			split++;
105 			if (end - split > 1 && strncmp(split, "//", 2) == 0)
106 				split += 2;
107 			name = skipn_spaces(split, end - split);
108 		} else {
109 			/* a ns name without a following profile is allowed */
110 			name = NULL;
111 			*ns_len = end - *ns_name;
112 		}
113 	}
114 	if (name && *name == 0)
115 		name = NULL;
116 
117 	return name;
118 }
119 
120 /**
121  * aa_info_message - log a none profile related status message
122  * @str: message to log
123  */
124 void aa_info_message(const char *str)
125 {
126 	if (audit_enabled) {
127 		DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
128 
129 		aad(&sa)->info = str;
130 		aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
131 	}
132 	printk(KERN_INFO "AppArmor: %s\n", str);
133 }
134 
135 __counted char *aa_str_alloc(int size, gfp_t gfp)
136 {
137 	struct counted_str *str;
138 
139 	str = kmalloc(struct_size(str, name, size), gfp);
140 	if (!str)
141 		return NULL;
142 
143 	kref_init(&str->count);
144 	return str->name;
145 }
146 
147 void aa_str_kref(struct kref *kref)
148 {
149 	kfree(container_of(kref, struct counted_str, count));
150 }
151 
152 
153 const char aa_file_perm_chrs[] = "xwracd         km l     ";
154 const char *aa_file_perm_names[] = {
155 	"exec",
156 	"write",
157 	"read",
158 	"append",
159 
160 	"create",
161 	"delete",
162 	"open",
163 	"rename",
164 
165 	"setattr",
166 	"getattr",
167 	"setcred",
168 	"getcred",
169 
170 	"chmod",
171 	"chown",
172 	"chgrp",
173 	"lock",
174 
175 	"mmap",
176 	"mprot",
177 	"link",
178 	"snapshot",
179 
180 	"unknown",
181 	"unknown",
182 	"unknown",
183 	"unknown",
184 
185 	"unknown",
186 	"unknown",
187 	"unknown",
188 	"unknown",
189 
190 	"stack",
191 	"change_onexec",
192 	"change_profile",
193 	"change_hat",
194 };
195 
196 /**
197  * aa_perm_mask_to_str - convert a perm mask to its short string
198  * @str: character buffer to store string in (at least 10 characters)
199  * @str_size: size of the @str buffer
200  * @chrs: NUL-terminated character buffer of permission characters
201  * @mask: permission mask to convert
202  */
203 void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
204 {
205 	unsigned int i, perm = 1;
206 	size_t num_chrs = strlen(chrs);
207 
208 	for (i = 0; i < num_chrs; perm <<= 1, i++) {
209 		if (mask & perm) {
210 			/* Ensure that one byte is left for NUL-termination */
211 			if (WARN_ON_ONCE(str_size <= 1))
212 				break;
213 
214 			*str++ = chrs[i];
215 			str_size--;
216 		}
217 	}
218 	*str = '\0';
219 }
220 
221 void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
222 			 u32 mask)
223 {
224 	const char *fmt = "%s";
225 	unsigned int i, perm = 1;
226 	bool prev = false;
227 
228 	for (i = 0; i < 32; perm <<= 1, i++) {
229 		if (mask & perm) {
230 			audit_log_format(ab, fmt, names[i]);
231 			if (!prev) {
232 				prev = true;
233 				fmt = " %s";
234 			}
235 		}
236 	}
237 }
238 
239 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
240 			u32 chrsmask, const char * const *names, u32 namesmask)
241 {
242 	char str[33];
243 
244 	audit_log_format(ab, "\"");
245 	if ((mask & chrsmask) && chrs) {
246 		aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
247 		mask &= ~chrsmask;
248 		audit_log_format(ab, "%s", str);
249 		if (mask & namesmask)
250 			audit_log_format(ab, " ");
251 	}
252 	if ((mask & namesmask) && names)
253 		aa_audit_perm_names(ab, names, mask & namesmask);
254 	audit_log_format(ab, "\"");
255 }
256 
257 /**
258  * aa_audit_perms_cb - generic callback fn for auditing perms
259  * @ab: audit buffer (NOT NULL)
260  * @va: audit struct to audit values of (NOT NULL)
261  */
262 static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
263 {
264 	struct common_audit_data *sa = va;
265 
266 	if (aad(sa)->request) {
267 		audit_log_format(ab, " requested_mask=");
268 		aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
269 				   PERMS_CHRS_MASK, aa_file_perm_names,
270 				   PERMS_NAMES_MASK);
271 	}
272 	if (aad(sa)->denied) {
273 		audit_log_format(ab, "denied_mask=");
274 		aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
275 				   PERMS_CHRS_MASK, aa_file_perm_names,
276 				   PERMS_NAMES_MASK);
277 	}
278 	audit_log_format(ab, " peer=");
279 	aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
280 				      FLAGS_NONE, GFP_ATOMIC);
281 }
282 
283 /**
284  * aa_apply_modes_to_perms - apply namespace and profile flags to perms
285  * @profile: that perms where computed from
286  * @perms: perms to apply mode modifiers to
287  *
288  * TODO: split into profile and ns based flags for when accumulating perms
289  */
290 void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
291 {
292 	switch (AUDIT_MODE(profile)) {
293 	case AUDIT_ALL:
294 		perms->audit = ALL_PERMS_MASK;
295 		fallthrough;
296 	case AUDIT_NOQUIET:
297 		perms->quiet = 0;
298 		break;
299 	case AUDIT_QUIET:
300 		perms->audit = 0;
301 		fallthrough;
302 	case AUDIT_QUIET_DENIED:
303 		perms->quiet = ALL_PERMS_MASK;
304 		break;
305 	}
306 
307 	if (KILL_MODE(profile))
308 		perms->kill = ALL_PERMS_MASK;
309 	else if (COMPLAIN_MODE(profile))
310 		perms->complain = ALL_PERMS_MASK;
311 /*
312  *  TODO:
313  *	else if (PROMPT_MODE(profile))
314  *		perms->prompt = ALL_PERMS_MASK;
315  */
316 }
317 
318 static u32 map_other(u32 x)
319 {
320 	return ((x & 0x3) << 8) |	/* SETATTR/GETATTR */
321 		((x & 0x1c) << 18) |	/* ACCEPT/BIND/LISTEN */
322 		((x & 0x60) << 19);	/* SETOPT/GETOPT */
323 }
324 
325 static u32 map_xbits(u32 x)
326 {
327 	return ((x & 0x1) << 7) |
328 		((x & 0x7e) << 9);
329 }
330 
331 void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
332 		      struct aa_perms *perms)
333 {
334 	/* This mapping is convulated due to history.
335 	 * v1-v4: only file perms
336 	 * v5: added policydb which dropped in perm user conditional to
337 	 *     gain new perm bits, but had to map around the xbits because
338 	 *     the userspace compiler was still munging them.
339 	 * v9: adds using the xbits in policydb because the compiler now
340 	 *     supports treating policydb permission bits different.
341 	 *     Unfortunately there is not way to force auditing on the
342 	 *     perms represented by the xbits
343 	 */
344 	*perms = (struct aa_perms) {
345 		.allow = dfa_user_allow(dfa, state) |
346 			 map_xbits(dfa_user_xbits(dfa, state)),
347 		.audit = dfa_user_audit(dfa, state),
348 		.quiet = dfa_user_quiet(dfa, state) |
349 			 map_xbits(dfa_other_xbits(dfa, state)),
350 	};
351 
352 	/* for v5-v9 perm mapping in the policydb, the other set is used
353 	 * to extend the general perm set
354 	 */
355 	perms->allow |= map_other(dfa_other_allow(dfa, state));
356 	perms->audit |= map_other(dfa_other_audit(dfa, state));
357 	perms->quiet |= map_other(dfa_other_quiet(dfa, state));
358 }
359 
360 /**
361  * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
362  * @accum - perms struct to accumulate into
363  * @addend - perms struct to add to @accum
364  */
365 void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
366 {
367 	accum->deny |= addend->deny;
368 	accum->allow &= addend->allow & ~addend->deny;
369 	accum->audit |= addend->audit & addend->allow;
370 	accum->quiet &= addend->quiet & ~addend->allow;
371 	accum->kill |= addend->kill & ~addend->allow;
372 	accum->stop |= addend->stop & ~addend->allow;
373 	accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
374 	accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
375 	accum->hide &= addend->hide & ~addend->allow;
376 	accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
377 }
378 
379 /**
380  * aa_perms_accum - accumulate perms, masking off overlapping perms
381  * @accum - perms struct to accumulate into
382  * @addend - perms struct to add to @accum
383  */
384 void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
385 {
386 	accum->deny |= addend->deny;
387 	accum->allow &= addend->allow & ~accum->deny;
388 	accum->audit |= addend->audit & accum->allow;
389 	accum->quiet &= addend->quiet & ~accum->allow;
390 	accum->kill |= addend->kill & ~accum->allow;
391 	accum->stop |= addend->stop & ~accum->allow;
392 	accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
393 	accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
394 	accum->hide &= addend->hide & ~accum->allow;
395 	accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
396 }
397 
398 void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
399 			    int type, u32 request, struct aa_perms *perms)
400 {
401 	/* TODO: doesn't yet handle extended types */
402 	unsigned int state;
403 
404 	state = aa_dfa_next(profile->policy.dfa,
405 			    profile->policy.start[AA_CLASS_LABEL],
406 			    type);
407 	aa_label_match(profile, label, state, false, request, perms);
408 }
409 
410 
411 /* currently unused */
412 int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
413 			  u32 request, int type, u32 *deny,
414 			  struct common_audit_data *sa)
415 {
416 	struct aa_perms perms;
417 
418 	aad(sa)->label = &profile->label;
419 	aad(sa)->peer = &target->label;
420 	aad(sa)->request = request;
421 
422 	aa_profile_match_label(profile, &target->label, type, request, &perms);
423 	aa_apply_modes_to_perms(profile, &perms);
424 	*deny |= request & perms.deny;
425 	return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
426 }
427 
428 /**
429  * aa_check_perms - do audit mode selection based on perms set
430  * @profile: profile being checked
431  * @perms: perms computed for the request
432  * @request: requested perms
433  * @deny: Returns: explicit deny set
434  * @sa: initialized audit structure (MAY BE NULL if not auditing)
435  * @cb: callback fn for type specific fields (MAY BE NULL)
436  *
437  * Returns: 0 if permission else error code
438  *
439  * Note: profile audit modes need to be set before calling by setting the
440  *       perm masks appropriately.
441  *
442  *       If not auditing then complain mode is not enabled and the
443  *       error code will indicate whether there was an explicit deny
444  *	 with a positive value.
445  */
446 int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
447 		   u32 request, struct common_audit_data *sa,
448 		   void (*cb)(struct audit_buffer *, void *))
449 {
450 	int type, error;
451 	u32 denied = request & (~perms->allow | perms->deny);
452 
453 	if (likely(!denied)) {
454 		/* mask off perms that are not being force audited */
455 		request &= perms->audit;
456 		if (!request || !sa)
457 			return 0;
458 
459 		type = AUDIT_APPARMOR_AUDIT;
460 		error = 0;
461 	} else {
462 		error = -EACCES;
463 
464 		if (denied & perms->kill)
465 			type = AUDIT_APPARMOR_KILL;
466 		else if (denied == (denied & perms->complain))
467 			type = AUDIT_APPARMOR_ALLOWED;
468 		else
469 			type = AUDIT_APPARMOR_DENIED;
470 
471 		if (denied == (denied & perms->hide))
472 			error = -ENOENT;
473 
474 		denied &= ~perms->quiet;
475 		if (!sa || !denied)
476 			return error;
477 	}
478 
479 	if (sa) {
480 		aad(sa)->label = &profile->label;
481 		aad(sa)->request = request;
482 		aad(sa)->denied = denied;
483 		aad(sa)->error = error;
484 		aa_audit_msg(type, sa, cb);
485 	}
486 
487 	if (type == AUDIT_APPARMOR_ALLOWED)
488 		error = 0;
489 
490 	return error;
491 }
492 
493 
494 /**
495  * aa_policy_init - initialize a policy structure
496  * @policy: policy to initialize  (NOT NULL)
497  * @prefix: prefix name if any is required.  (MAYBE NULL)
498  * @name: name of the policy, init will make a copy of it  (NOT NULL)
499  * @gfp: allocation mode
500  *
501  * Note: this fn creates a copy of strings passed in
502  *
503  * Returns: true if policy init successful
504  */
505 bool aa_policy_init(struct aa_policy *policy, const char *prefix,
506 		    const char *name, gfp_t gfp)
507 {
508 	char *hname;
509 
510 	/* freed by policy_free */
511 	if (prefix) {
512 		hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
513 		if (hname)
514 			sprintf(hname, "%s//%s", prefix, name);
515 	} else {
516 		hname = aa_str_alloc(strlen(name) + 1, gfp);
517 		if (hname)
518 			strcpy(hname, name);
519 	}
520 	if (!hname)
521 		return false;
522 	policy->hname = hname;
523 	/* base.name is a substring of fqname */
524 	policy->name = basename(policy->hname);
525 	INIT_LIST_HEAD(&policy->list);
526 	INIT_LIST_HEAD(&policy->profiles);
527 
528 	return true;
529 }
530 
531 /**
532  * aa_policy_destroy - free the elements referenced by @policy
533  * @policy: policy that is to have its elements freed  (NOT NULL)
534  */
535 void aa_policy_destroy(struct aa_policy *policy)
536 {
537 	AA_BUG(on_list_rcu(&policy->profiles));
538 	AA_BUG(on_list_rcu(&policy->list));
539 
540 	/* don't free name as its a subset of hname */
541 	aa_put_str(policy->hname);
542 }
543