xref: /linux/security/apparmor/lib.c (revision e9f0878c4b2004ac19581274c1ae4c61ae3ca70e)
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  * @str_size: size of the @str buffer
202  * @chrs: NUL-terminated character buffer of permission characters
203  * @mask: permission mask to convert
204  */
205 void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
206 {
207 	unsigned int i, perm = 1;
208 	size_t num_chrs = strlen(chrs);
209 
210 	for (i = 0; i < num_chrs; perm <<= 1, i++) {
211 		if (mask & perm) {
212 			/* Ensure that one byte is left for NUL-termination */
213 			if (WARN_ON_ONCE(str_size <= 1))
214 				break;
215 
216 			*str++ = chrs[i];
217 			str_size--;
218 		}
219 	}
220 	*str = '\0';
221 }
222 
223 void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
224 			 u32 mask)
225 {
226 	const char *fmt = "%s";
227 	unsigned int i, perm = 1;
228 	bool prev = false;
229 
230 	for (i = 0; i < 32; perm <<= 1, i++) {
231 		if (mask & perm) {
232 			audit_log_format(ab, fmt, names[i]);
233 			if (!prev) {
234 				prev = true;
235 				fmt = " %s";
236 			}
237 		}
238 	}
239 }
240 
241 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
242 			u32 chrsmask, const char * const *names, u32 namesmask)
243 {
244 	char str[33];
245 
246 	audit_log_format(ab, "\"");
247 	if ((mask & chrsmask) && chrs) {
248 		aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
249 		mask &= ~chrsmask;
250 		audit_log_format(ab, "%s", str);
251 		if (mask & namesmask)
252 			audit_log_format(ab, " ");
253 	}
254 	if ((mask & namesmask) && names)
255 		aa_audit_perm_names(ab, names, mask & namesmask);
256 	audit_log_format(ab, "\"");
257 }
258 
259 /**
260  * aa_audit_perms_cb - generic callback fn for auditing perms
261  * @ab: audit buffer (NOT NULL)
262  * @va: audit struct to audit values of (NOT NULL)
263  */
264 static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
265 {
266 	struct common_audit_data *sa = va;
267 
268 	if (aad(sa)->request) {
269 		audit_log_format(ab, " requested_mask=");
270 		aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
271 				   PERMS_CHRS_MASK, aa_file_perm_names,
272 				   PERMS_NAMES_MASK);
273 	}
274 	if (aad(sa)->denied) {
275 		audit_log_format(ab, "denied_mask=");
276 		aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
277 				   PERMS_CHRS_MASK, aa_file_perm_names,
278 				   PERMS_NAMES_MASK);
279 	}
280 	audit_log_format(ab, " peer=");
281 	aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
282 				      FLAGS_NONE, GFP_ATOMIC);
283 }
284 
285 /**
286  * aa_apply_modes_to_perms - apply namespace and profile flags to perms
287  * @profile: that perms where computed from
288  * @perms: perms to apply mode modifiers to
289  *
290  * TODO: split into profile and ns based flags for when accumulating perms
291  */
292 void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
293 {
294 	switch (AUDIT_MODE(profile)) {
295 	case AUDIT_ALL:
296 		perms->audit = ALL_PERMS_MASK;
297 		/* fall through */
298 	case AUDIT_NOQUIET:
299 		perms->quiet = 0;
300 		break;
301 	case AUDIT_QUIET:
302 		perms->audit = 0;
303 		/* fall through */
304 	case AUDIT_QUIET_DENIED:
305 		perms->quiet = ALL_PERMS_MASK;
306 		break;
307 	}
308 
309 	if (KILL_MODE(profile))
310 		perms->kill = ALL_PERMS_MASK;
311 	else if (COMPLAIN_MODE(profile))
312 		perms->complain = ALL_PERMS_MASK;
313 /*
314  *  TODO:
315  *	else if (PROMPT_MODE(profile))
316  *		perms->prompt = ALL_PERMS_MASK;
317  */
318 }
319 
320 static u32 map_other(u32 x)
321 {
322 	return ((x & 0x3) << 8) |	/* SETATTR/GETATTR */
323 		((x & 0x1c) << 18) |	/* ACCEPT/BIND/LISTEN */
324 		((x & 0x60) << 19);	/* SETOPT/GETOPT */
325 }
326 
327 void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
328 		      struct aa_perms *perms)
329 {
330 	*perms = (struct aa_perms) {
331 		.allow = dfa_user_allow(dfa, state),
332 		.audit = dfa_user_audit(dfa, state),
333 		.quiet = dfa_user_quiet(dfa, state),
334 	};
335 
336 	/* for v5 perm mapping in the policydb, the other set is used
337 	 * to extend the general perm set
338 	 */
339 	perms->allow |= map_other(dfa_other_allow(dfa, state));
340 	perms->audit |= map_other(dfa_other_audit(dfa, state));
341 	perms->quiet |= map_other(dfa_other_quiet(dfa, state));
342 //	perms->xindex = dfa_user_xindex(dfa, state);
343 }
344 
345 /**
346  * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
347  * @accum - perms struct to accumulate into
348  * @addend - perms struct to add to @accum
349  */
350 void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
351 {
352 	accum->deny |= addend->deny;
353 	accum->allow &= addend->allow & ~addend->deny;
354 	accum->audit |= addend->audit & addend->allow;
355 	accum->quiet &= addend->quiet & ~addend->allow;
356 	accum->kill |= addend->kill & ~addend->allow;
357 	accum->stop |= addend->stop & ~addend->allow;
358 	accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
359 	accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
360 	accum->hide &= addend->hide & ~addend->allow;
361 	accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
362 }
363 
364 /**
365  * aa_perms_accum - accumulate perms, masking off overlapping perms
366  * @accum - perms struct to accumulate into
367  * @addend - perms struct to add to @accum
368  */
369 void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
370 {
371 	accum->deny |= addend->deny;
372 	accum->allow &= addend->allow & ~accum->deny;
373 	accum->audit |= addend->audit & accum->allow;
374 	accum->quiet &= addend->quiet & ~accum->allow;
375 	accum->kill |= addend->kill & ~accum->allow;
376 	accum->stop |= addend->stop & ~accum->allow;
377 	accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
378 	accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
379 	accum->hide &= addend->hide & ~accum->allow;
380 	accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
381 }
382 
383 void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
384 			    int type, u32 request, struct aa_perms *perms)
385 {
386 	/* TODO: doesn't yet handle extended types */
387 	unsigned int state;
388 
389 	state = aa_dfa_next(profile->policy.dfa,
390 			    profile->policy.start[AA_CLASS_LABEL],
391 			    type);
392 	aa_label_match(profile, label, state, false, request, perms);
393 }
394 
395 
396 /* currently unused */
397 int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
398 			  u32 request, int type, u32 *deny,
399 			  struct common_audit_data *sa)
400 {
401 	struct aa_perms perms;
402 
403 	aad(sa)->label = &profile->label;
404 	aad(sa)->peer = &target->label;
405 	aad(sa)->request = request;
406 
407 	aa_profile_match_label(profile, &target->label, type, request, &perms);
408 	aa_apply_modes_to_perms(profile, &perms);
409 	*deny |= request & perms.deny;
410 	return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
411 }
412 
413 /**
414  * aa_check_perms - do audit mode selection based on perms set
415  * @profile: profile being checked
416  * @perms: perms computed for the request
417  * @request: requested perms
418  * @deny: Returns: explicit deny set
419  * @sa: initialized audit structure (MAY BE NULL if not auditing)
420  * @cb: callback fn for type specific fields (MAY BE NULL)
421  *
422  * Returns: 0 if permission else error code
423  *
424  * Note: profile audit modes need to be set before calling by setting the
425  *       perm masks appropriately.
426  *
427  *       If not auditing then complain mode is not enabled and the
428  *       error code will indicate whether there was an explicit deny
429  *	 with a positive value.
430  */
431 int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
432 		   u32 request, struct common_audit_data *sa,
433 		   void (*cb)(struct audit_buffer *, void *))
434 {
435 	int type, error;
436 	u32 denied = request & (~perms->allow | perms->deny);
437 
438 	if (likely(!denied)) {
439 		/* mask off perms that are not being force audited */
440 		request &= perms->audit;
441 		if (!request || !sa)
442 			return 0;
443 
444 		type = AUDIT_APPARMOR_AUDIT;
445 		error = 0;
446 	} else {
447 		error = -EACCES;
448 
449 		if (denied & perms->kill)
450 			type = AUDIT_APPARMOR_KILL;
451 		else if (denied == (denied & perms->complain))
452 			type = AUDIT_APPARMOR_ALLOWED;
453 		else
454 			type = AUDIT_APPARMOR_DENIED;
455 
456 		if (denied == (denied & perms->hide))
457 			error = -ENOENT;
458 
459 		denied &= ~perms->quiet;
460 		if (!sa || !denied)
461 			return error;
462 	}
463 
464 	if (sa) {
465 		aad(sa)->label = &profile->label;
466 		aad(sa)->request = request;
467 		aad(sa)->denied = denied;
468 		aad(sa)->error = error;
469 		aa_audit_msg(type, sa, cb);
470 	}
471 
472 	if (type == AUDIT_APPARMOR_ALLOWED)
473 		error = 0;
474 
475 	return error;
476 }
477 
478 
479 /**
480  * aa_policy_init - initialize a policy structure
481  * @policy: policy to initialize  (NOT NULL)
482  * @prefix: prefix name if any is required.  (MAYBE NULL)
483  * @name: name of the policy, init will make a copy of it  (NOT NULL)
484  * @gfp: allocation mode
485  *
486  * Note: this fn creates a copy of strings passed in
487  *
488  * Returns: true if policy init successful
489  */
490 bool aa_policy_init(struct aa_policy *policy, const char *prefix,
491 		    const char *name, gfp_t gfp)
492 {
493 	char *hname;
494 
495 	/* freed by policy_free */
496 	if (prefix) {
497 		hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
498 		if (hname)
499 			sprintf(hname, "%s//%s", prefix, name);
500 	} else {
501 		hname = aa_str_alloc(strlen(name) + 1, gfp);
502 		if (hname)
503 			strcpy(hname, name);
504 	}
505 	if (!hname)
506 		return false;
507 	policy->hname = hname;
508 	/* base.name is a substring of fqname */
509 	policy->name = basename(policy->hname);
510 	INIT_LIST_HEAD(&policy->list);
511 	INIT_LIST_HEAD(&policy->profiles);
512 
513 	return true;
514 }
515 
516 /**
517  * aa_policy_destroy - free the elements referenced by @policy
518  * @policy: policy that is to have its elements freed  (NOT NULL)
519  */
520 void aa_policy_destroy(struct aa_policy *policy)
521 {
522 	AA_BUG(on_list_rcu(&policy->profiles));
523 	AA_BUG(on_list_rcu(&policy->list));
524 
525 	/* don't free name as its a subset of hname */
526 	aa_put_str(policy->hname);
527 }
528