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