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