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