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