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