xref: /openbmc/linux/security/apparmor/lib.c (revision 337c86dc)
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  */
aa_free_str_table(struct aa_str_table * t)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 		t->size = 0;
45 	}
46 }
47 
48 /**
49  * aa_split_fqname - split a fqname into a profile and namespace name
50  * @fqname: a full qualified name in namespace profile format (NOT NULL)
51  * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
52  *
53  * Returns: profile name or NULL if one is not specified
54  *
55  * Split a namespace name from a profile name (see policy.c for naming
56  * description).  If a portion of the name is missing it returns NULL for
57  * that portion.
58  *
59  * NOTE: may modify the @fqname string.  The pointers returned point
60  *       into the @fqname string.
61  */
aa_split_fqname(char * fqname,char ** ns_name)62 char *aa_split_fqname(char *fqname, char **ns_name)
63 {
64 	char *name = strim(fqname);
65 
66 	*ns_name = NULL;
67 	if (name[0] == ':') {
68 		char *split = strchr(&name[1], ':');
69 		*ns_name = skip_spaces(&name[1]);
70 		if (split) {
71 			/* overwrite ':' with \0 */
72 			*split++ = 0;
73 			if (strncmp(split, "//", 2) == 0)
74 				split += 2;
75 			name = skip_spaces(split);
76 		} else
77 			/* a ns name without a following profile is allowed */
78 			name = NULL;
79 	}
80 	if (name && *name == 0)
81 		name = NULL;
82 
83 	return name;
84 }
85 
86 /**
87  * skipn_spaces - Removes leading whitespace from @str.
88  * @str: The string to be stripped.
89  * @n: length of str to parse, will stop at \0 if encountered before n
90  *
91  * Returns a pointer to the first non-whitespace character in @str.
92  * if all whitespace will return NULL
93  */
94 
skipn_spaces(const char * str,size_t n)95 const char *skipn_spaces(const char *str, size_t n)
96 {
97 	for (; n && isspace(*str); --n)
98 		++str;
99 	if (n)
100 		return (char *)str;
101 	return NULL;
102 }
103 
aa_splitn_fqname(const char * fqname,size_t n,const char ** ns_name,size_t * ns_len)104 const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
105 			     size_t *ns_len)
106 {
107 	const char *end = fqname + n;
108 	const char *name = skipn_spaces(fqname, n);
109 
110 	*ns_name = NULL;
111 	*ns_len = 0;
112 
113 	if (!name)
114 		return NULL;
115 
116 	if (name[0] == ':') {
117 		char *split = strnchr(&name[1], end - &name[1], ':');
118 		*ns_name = skipn_spaces(&name[1], end - &name[1]);
119 		if (!*ns_name)
120 			return NULL;
121 		if (split) {
122 			*ns_len = split - *ns_name;
123 			if (*ns_len == 0)
124 				*ns_name = NULL;
125 			split++;
126 			if (end - split > 1 && strncmp(split, "//", 2) == 0)
127 				split += 2;
128 			name = skipn_spaces(split, end - split);
129 		} else {
130 			/* a ns name without a following profile is allowed */
131 			name = NULL;
132 			*ns_len = end - *ns_name;
133 		}
134 	}
135 	if (name && *name == 0)
136 		name = NULL;
137 
138 	return name;
139 }
140 
141 /**
142  * aa_info_message - log a none profile related status message
143  * @str: message to log
144  */
aa_info_message(const char * str)145 void aa_info_message(const char *str)
146 {
147 	if (audit_enabled) {
148 		DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
149 
150 		ad.info = str;
151 		aa_audit_msg(AUDIT_APPARMOR_STATUS, &ad, NULL);
152 	}
153 	printk(KERN_INFO "AppArmor: %s\n", str);
154 }
155 
aa_str_alloc(int size,gfp_t gfp)156 __counted char *aa_str_alloc(int size, gfp_t gfp)
157 {
158 	struct counted_str *str;
159 
160 	str = kmalloc(struct_size(str, name, size), gfp);
161 	if (!str)
162 		return NULL;
163 
164 	kref_init(&str->count);
165 	return str->name;
166 }
167 
aa_str_kref(struct kref * kref)168 void aa_str_kref(struct kref *kref)
169 {
170 	kfree(container_of(kref, struct counted_str, count));
171 }
172 
173 
174 const char aa_file_perm_chrs[] = "xwracd         km l     ";
175 const char *aa_file_perm_names[] = {
176 	"exec",
177 	"write",
178 	"read",
179 	"append",
180 
181 	"create",
182 	"delete",
183 	"open",
184 	"rename",
185 
186 	"setattr",
187 	"getattr",
188 	"setcred",
189 	"getcred",
190 
191 	"chmod",
192 	"chown",
193 	"chgrp",
194 	"lock",
195 
196 	"mmap",
197 	"mprot",
198 	"link",
199 	"snapshot",
200 
201 	"unknown",
202 	"unknown",
203 	"unknown",
204 	"unknown",
205 
206 	"unknown",
207 	"unknown",
208 	"unknown",
209 	"unknown",
210 
211 	"stack",
212 	"change_onexec",
213 	"change_profile",
214 	"change_hat",
215 };
216 
217 /**
218  * aa_perm_mask_to_str - convert a perm mask to its short string
219  * @str: character buffer to store string in (at least 10 characters)
220  * @str_size: size of the @str buffer
221  * @chrs: NUL-terminated character buffer of permission characters
222  * @mask: permission mask to convert
223  */
aa_perm_mask_to_str(char * str,size_t str_size,const char * chrs,u32 mask)224 void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
225 {
226 	unsigned int i, perm = 1;
227 	size_t num_chrs = strlen(chrs);
228 
229 	for (i = 0; i < num_chrs; perm <<= 1, i++) {
230 		if (mask & perm) {
231 			/* Ensure that one byte is left for NUL-termination */
232 			if (WARN_ON_ONCE(str_size <= 1))
233 				break;
234 
235 			*str++ = chrs[i];
236 			str_size--;
237 		}
238 	}
239 	*str = '\0';
240 }
241 
aa_audit_perm_names(struct audit_buffer * ab,const char * const * names,u32 mask)242 void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
243 			 u32 mask)
244 {
245 	const char *fmt = "%s";
246 	unsigned int i, perm = 1;
247 	bool prev = false;
248 
249 	for (i = 0; i < 32; perm <<= 1, i++) {
250 		if (mask & perm) {
251 			audit_log_format(ab, fmt, names[i]);
252 			if (!prev) {
253 				prev = true;
254 				fmt = " %s";
255 			}
256 		}
257 	}
258 }
259 
aa_audit_perm_mask(struct audit_buffer * ab,u32 mask,const char * chrs,u32 chrsmask,const char * const * names,u32 namesmask)260 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
261 			u32 chrsmask, const char * const *names, u32 namesmask)
262 {
263 	char str[33];
264 
265 	audit_log_format(ab, "\"");
266 	if ((mask & chrsmask) && chrs) {
267 		aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
268 		mask &= ~chrsmask;
269 		audit_log_format(ab, "%s", str);
270 		if (mask & namesmask)
271 			audit_log_format(ab, " ");
272 	}
273 	if ((mask & namesmask) && names)
274 		aa_audit_perm_names(ab, names, mask & namesmask);
275 	audit_log_format(ab, "\"");
276 }
277 
278 /**
279  * aa_audit_perms_cb - generic callback fn for auditing perms
280  * @ab: audit buffer (NOT NULL)
281  * @va: audit struct to audit values of (NOT NULL)
282  */
aa_audit_perms_cb(struct audit_buffer * ab,void * va)283 static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
284 {
285 	struct common_audit_data *sa = va;
286 	struct apparmor_audit_data *ad = aad(sa);
287 
288 	if (ad->request) {
289 		audit_log_format(ab, " requested_mask=");
290 		aa_audit_perm_mask(ab, ad->request, aa_file_perm_chrs,
291 				   PERMS_CHRS_MASK, aa_file_perm_names,
292 				   PERMS_NAMES_MASK);
293 	}
294 	if (ad->denied) {
295 		audit_log_format(ab, "denied_mask=");
296 		aa_audit_perm_mask(ab, ad->denied, aa_file_perm_chrs,
297 				   PERMS_CHRS_MASK, aa_file_perm_names,
298 				   PERMS_NAMES_MASK);
299 	}
300 	audit_log_format(ab, " peer=");
301 	aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
302 				      FLAGS_NONE, GFP_ATOMIC);
303 }
304 
305 /**
306  * aa_apply_modes_to_perms - apply namespace and profile flags to perms
307  * @profile: that perms where computed from
308  * @perms: perms to apply mode modifiers to
309  *
310  * TODO: split into profile and ns based flags for when accumulating perms
311  */
aa_apply_modes_to_perms(struct aa_profile * profile,struct aa_perms * perms)312 void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
313 {
314 	switch (AUDIT_MODE(profile)) {
315 	case AUDIT_ALL:
316 		perms->audit = ALL_PERMS_MASK;
317 		fallthrough;
318 	case AUDIT_NOQUIET:
319 		perms->quiet = 0;
320 		break;
321 	case AUDIT_QUIET:
322 		perms->audit = 0;
323 		fallthrough;
324 	case AUDIT_QUIET_DENIED:
325 		perms->quiet = ALL_PERMS_MASK;
326 		break;
327 	}
328 
329 	if (KILL_MODE(profile))
330 		perms->kill = ALL_PERMS_MASK;
331 	else if (COMPLAIN_MODE(profile))
332 		perms->complain = ALL_PERMS_MASK;
333 	else if (USER_MODE(profile))
334 		perms->prompt = ALL_PERMS_MASK;
335 }
336 
aa_profile_match_label(struct aa_profile * profile,struct aa_ruleset * rules,struct aa_label * label,int type,u32 request,struct aa_perms * perms)337 void aa_profile_match_label(struct aa_profile *profile,
338 			    struct aa_ruleset *rules,
339 			    struct aa_label *label,
340 			    int type, u32 request, struct aa_perms *perms)
341 {
342 	/* TODO: doesn't yet handle extended types */
343 	aa_state_t state;
344 
345 	state = aa_dfa_next(rules->policy.dfa,
346 			    rules->policy.start[AA_CLASS_LABEL],
347 			    type);
348 	aa_label_match(profile, rules, label, state, false, request, perms);
349 }
350 
351 
352 /* currently unused */
aa_profile_label_perm(struct aa_profile * profile,struct aa_profile * target,u32 request,int type,u32 * deny,struct apparmor_audit_data * ad)353 int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
354 			  u32 request, int type, u32 *deny,
355 			  struct apparmor_audit_data *ad)
356 {
357 	struct aa_ruleset *rules = list_first_entry(&profile->rules,
358 						    typeof(*rules), list);
359 	struct aa_perms perms;
360 
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  */
aa_check_perms(struct aa_profile * profile,struct aa_perms * perms,u32 request,struct apparmor_audit_data * ad,void (* cb)(struct audit_buffer *,void *))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->subj_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  */
aa_policy_init(struct aa_policy * policy,const char * prefix,const char * name,gfp_t gfp)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  */
aa_policy_destroy(struct aa_policy * policy)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