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