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