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