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