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