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