xref: /openbmc/linux/security/apparmor/lib.c (revision c57bc80f4508acd8c52bd89b01d324889065320d)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2cdff2642SJohn Johansen /*
3cdff2642SJohn Johansen  * AppArmor security module
4cdff2642SJohn Johansen  *
5cdff2642SJohn Johansen  * This file contains basic common functions used in AppArmor
6cdff2642SJohn Johansen  *
7cdff2642SJohn Johansen  * Copyright (C) 1998-2008 Novell/SUSE
8cdff2642SJohn Johansen  * Copyright 2009-2010 Canonical Ltd.
9cdff2642SJohn Johansen  */
10cdff2642SJohn Johansen 
113b0aaf58SJohn Johansen #include <linux/ctype.h>
12b7f080cfSAlexey Dobriyan #include <linux/mm.h>
13cdff2642SJohn Johansen #include <linux/slab.h>
14cdff2642SJohn Johansen #include <linux/string.h>
15cdff2642SJohn Johansen #include <linux/vmalloc.h>
16cdff2642SJohn Johansen 
17cdff2642SJohn Johansen #include "include/audit.h"
1832c3df63SJames Morris #include "include/apparmor.h"
1912557dcbSJohn Johansen #include "include/lib.h"
20fc7e0b26SJohn Johansen #include "include/perms.h"
21fe6bb31fSJohn Johansen #include "include/policy.h"
22cdff2642SJohn Johansen 
232d679f3cSJohn Johansen struct aa_perms nullperms;
24aa9aeea8SJohn Johansen struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
25aa9aeea8SJohn Johansen 			     .quiet = ALL_PERMS_MASK,
26aa9aeea8SJohn Johansen 			     .hide = ALL_PERMS_MASK };
27aa9aeea8SJohn Johansen 
28cdff2642SJohn Johansen /**
2990917d5bSJohn Johansen  * aa_free_str_table - free entries str table
3073221ebeSGaosheng Cui  * @t: the string table to free  (MAYBE NULL)
3190917d5bSJohn Johansen  */
3290917d5bSJohn Johansen void aa_free_str_table(struct aa_str_table *t)
3390917d5bSJohn Johansen {
3490917d5bSJohn Johansen 	int i;
3590917d5bSJohn Johansen 
3690917d5bSJohn Johansen 	if (t) {
3790917d5bSJohn Johansen 		if (!t->table)
3890917d5bSJohn Johansen 			return;
3990917d5bSJohn Johansen 
4090917d5bSJohn Johansen 		for (i = 0; i < t->size; i++)
4190917d5bSJohn Johansen 			kfree_sensitive(t->table[i]);
4290917d5bSJohn Johansen 		kfree_sensitive(t->table);
4390917d5bSJohn Johansen 		t->table = NULL;
4490917d5bSJohn Johansen 	}
4590917d5bSJohn Johansen }
4690917d5bSJohn Johansen 
4790917d5bSJohn Johansen /**
48cdff2642SJohn Johansen  * aa_split_fqname - split a fqname into a profile and namespace name
49cdff2642SJohn Johansen  * @fqname: a full qualified name in namespace profile format (NOT NULL)
50cdff2642SJohn Johansen  * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
51cdff2642SJohn Johansen  *
52cdff2642SJohn Johansen  * Returns: profile name or NULL if one is not specified
53cdff2642SJohn Johansen  *
54cdff2642SJohn Johansen  * Split a namespace name from a profile name (see policy.c for naming
55cdff2642SJohn Johansen  * description).  If a portion of the name is missing it returns NULL for
56cdff2642SJohn Johansen  * that portion.
57cdff2642SJohn Johansen  *
58cdff2642SJohn Johansen  * NOTE: may modify the @fqname string.  The pointers returned point
59cdff2642SJohn Johansen  *       into the @fqname string.
60cdff2642SJohn Johansen  */
61cdff2642SJohn Johansen char *aa_split_fqname(char *fqname, char **ns_name)
62cdff2642SJohn Johansen {
63cdff2642SJohn Johansen 	char *name = strim(fqname);
64cdff2642SJohn Johansen 
65cdff2642SJohn Johansen 	*ns_name = NULL;
66cdff2642SJohn Johansen 	if (name[0] == ':') {
67cdff2642SJohn Johansen 		char *split = strchr(&name[1], ':');
6804ccd53fSJohn Johansen 		*ns_name = skip_spaces(&name[1]);
69cdff2642SJohn Johansen 		if (split) {
70cdff2642SJohn Johansen 			/* overwrite ':' with \0 */
712654bfbcSJohn Johansen 			*split++ = 0;
722654bfbcSJohn Johansen 			if (strncmp(split, "//", 2) == 0)
732654bfbcSJohn Johansen 				split += 2;
742654bfbcSJohn Johansen 			name = skip_spaces(split);
75cdff2642SJohn Johansen 		} else
76cdff2642SJohn Johansen 			/* a ns name without a following profile is allowed */
77cdff2642SJohn Johansen 			name = NULL;
78cdff2642SJohn Johansen 	}
79cdff2642SJohn Johansen 	if (name && *name == 0)
80cdff2642SJohn Johansen 		name = NULL;
81cdff2642SJohn Johansen 
82cdff2642SJohn Johansen 	return name;
83cdff2642SJohn Johansen }
84cdff2642SJohn Johansen 
85cdff2642SJohn Johansen /**
863b0aaf58SJohn Johansen  * skipn_spaces - Removes leading whitespace from @str.
873b0aaf58SJohn Johansen  * @str: The string to be stripped.
8873221ebeSGaosheng Cui  * @n: length of str to parse, will stop at \0 if encountered before n
893b0aaf58SJohn Johansen  *
903b0aaf58SJohn Johansen  * Returns a pointer to the first non-whitespace character in @str.
913b0aaf58SJohn Johansen  * if all whitespace will return NULL
923b0aaf58SJohn Johansen  */
933b0aaf58SJohn Johansen 
94b91deb9dSJohn Johansen const char *skipn_spaces(const char *str, size_t n)
953b0aaf58SJohn Johansen {
963b0aaf58SJohn Johansen 	for (; n && isspace(*str); --n)
973b0aaf58SJohn Johansen 		++str;
983b0aaf58SJohn Johansen 	if (n)
993b0aaf58SJohn Johansen 		return (char *)str;
1003b0aaf58SJohn Johansen 	return NULL;
1013b0aaf58SJohn Johansen }
1023b0aaf58SJohn Johansen 
1033b0aaf58SJohn Johansen const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
1043b0aaf58SJohn Johansen 			     size_t *ns_len)
1053b0aaf58SJohn Johansen {
1063b0aaf58SJohn Johansen 	const char *end = fqname + n;
1073b0aaf58SJohn Johansen 	const char *name = skipn_spaces(fqname, n);
1083b0aaf58SJohn Johansen 
1093b0aaf58SJohn Johansen 	*ns_name = NULL;
1103b0aaf58SJohn Johansen 	*ns_len = 0;
111250f2da4SZubin Mithra 
112250f2da4SZubin Mithra 	if (!name)
113250f2da4SZubin Mithra 		return NULL;
114250f2da4SZubin Mithra 
1153b0aaf58SJohn Johansen 	if (name[0] == ':') {
1163b0aaf58SJohn Johansen 		char *split = strnchr(&name[1], end - &name[1], ':');
1173b0aaf58SJohn Johansen 		*ns_name = skipn_spaces(&name[1], end - &name[1]);
1183b0aaf58SJohn Johansen 		if (!*ns_name)
1193b0aaf58SJohn Johansen 			return NULL;
1203b0aaf58SJohn Johansen 		if (split) {
1213b0aaf58SJohn Johansen 			*ns_len = split - *ns_name;
1223b0aaf58SJohn Johansen 			if (*ns_len == 0)
1233b0aaf58SJohn Johansen 				*ns_name = NULL;
1243b0aaf58SJohn Johansen 			split++;
1253b0aaf58SJohn Johansen 			if (end - split > 1 && strncmp(split, "//", 2) == 0)
1263b0aaf58SJohn Johansen 				split += 2;
1273b0aaf58SJohn Johansen 			name = skipn_spaces(split, end - split);
1283b0aaf58SJohn Johansen 		} else {
1293b0aaf58SJohn Johansen 			/* a ns name without a following profile is allowed */
1303b0aaf58SJohn Johansen 			name = NULL;
1313b0aaf58SJohn Johansen 			*ns_len = end - *ns_name;
1323b0aaf58SJohn Johansen 		}
1333b0aaf58SJohn Johansen 	}
1343b0aaf58SJohn Johansen 	if (name && *name == 0)
1353b0aaf58SJohn Johansen 		name = NULL;
1363b0aaf58SJohn Johansen 
1373b0aaf58SJohn Johansen 	return name;
1383b0aaf58SJohn Johansen }
1393b0aaf58SJohn Johansen 
1403b0aaf58SJohn Johansen /**
141cdff2642SJohn Johansen  * aa_info_message - log a none profile related status message
142cdff2642SJohn Johansen  * @str: message to log
143cdff2642SJohn Johansen  */
144cdff2642SJohn Johansen void aa_info_message(const char *str)
145cdff2642SJohn Johansen {
146cdff2642SJohn Johansen 	if (audit_enabled) {
147*c57bc80fSJohn Johansen 		DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
148ef88a7acSJohn Johansen 
149*c57bc80fSJohn Johansen 		ad.info = str;
150*c57bc80fSJohn Johansen 		aa_audit_msg(AUDIT_APPARMOR_STATUS, &ad, NULL);
151cdff2642SJohn Johansen 	}
152cdff2642SJohn Johansen 	printk(KERN_INFO "AppArmor: %s\n", str);
153cdff2642SJohn Johansen }
154cdff2642SJohn Johansen 
155a1bd627bSJohn Johansen __counted char *aa_str_alloc(int size, gfp_t gfp)
156a1bd627bSJohn Johansen {
157a1bd627bSJohn Johansen 	struct counted_str *str;
158a1bd627bSJohn Johansen 
159c0ea4b91SGustavo A. R. Silva 	str = kmalloc(struct_size(str, name, size), gfp);
160a1bd627bSJohn Johansen 	if (!str)
161a1bd627bSJohn Johansen 		return NULL;
162a1bd627bSJohn Johansen 
163a1bd627bSJohn Johansen 	kref_init(&str->count);
164a1bd627bSJohn Johansen 	return str->name;
165a1bd627bSJohn Johansen }
166a1bd627bSJohn Johansen 
167a1bd627bSJohn Johansen void aa_str_kref(struct kref *kref)
168a1bd627bSJohn Johansen {
169a1bd627bSJohn Johansen 	kfree(container_of(kref, struct counted_str, count));
170a1bd627bSJohn Johansen }
171a1bd627bSJohn Johansen 
172a1bd627bSJohn Johansen 
173e53cfe6cSJohn Johansen const char aa_file_perm_chrs[] = "xwracd         km l     ";
174e53cfe6cSJohn Johansen const char *aa_file_perm_names[] = {
175e53cfe6cSJohn Johansen 	"exec",
176e53cfe6cSJohn Johansen 	"write",
177e53cfe6cSJohn Johansen 	"read",
178e53cfe6cSJohn Johansen 	"append",
179e53cfe6cSJohn Johansen 
180e53cfe6cSJohn Johansen 	"create",
181e53cfe6cSJohn Johansen 	"delete",
182e53cfe6cSJohn Johansen 	"open",
183e53cfe6cSJohn Johansen 	"rename",
184e53cfe6cSJohn Johansen 
185e53cfe6cSJohn Johansen 	"setattr",
186e53cfe6cSJohn Johansen 	"getattr",
187e53cfe6cSJohn Johansen 	"setcred",
188e53cfe6cSJohn Johansen 	"getcred",
189e53cfe6cSJohn Johansen 
190e53cfe6cSJohn Johansen 	"chmod",
191e53cfe6cSJohn Johansen 	"chown",
192e53cfe6cSJohn Johansen 	"chgrp",
193e53cfe6cSJohn Johansen 	"lock",
194e53cfe6cSJohn Johansen 
195e53cfe6cSJohn Johansen 	"mmap",
196e53cfe6cSJohn Johansen 	"mprot",
197e53cfe6cSJohn Johansen 	"link",
198e53cfe6cSJohn Johansen 	"snapshot",
199e53cfe6cSJohn Johansen 
200e53cfe6cSJohn Johansen 	"unknown",
201e53cfe6cSJohn Johansen 	"unknown",
202e53cfe6cSJohn Johansen 	"unknown",
203e53cfe6cSJohn Johansen 	"unknown",
204e53cfe6cSJohn Johansen 
205e53cfe6cSJohn Johansen 	"unknown",
206e53cfe6cSJohn Johansen 	"unknown",
207e53cfe6cSJohn Johansen 	"unknown",
208e53cfe6cSJohn Johansen 	"unknown",
209e53cfe6cSJohn Johansen 
210e53cfe6cSJohn Johansen 	"stack",
211e53cfe6cSJohn Johansen 	"change_onexec",
212e53cfe6cSJohn Johansen 	"change_profile",
213e53cfe6cSJohn Johansen 	"change_hat",
214e53cfe6cSJohn Johansen };
215e53cfe6cSJohn Johansen 
216e53cfe6cSJohn Johansen /**
217e53cfe6cSJohn Johansen  * aa_perm_mask_to_str - convert a perm mask to its short string
218e53cfe6cSJohn Johansen  * @str: character buffer to store string in (at least 10 characters)
2197f3ebcf2STyler Hicks  * @str_size: size of the @str buffer
2207f3ebcf2STyler Hicks  * @chrs: NUL-terminated character buffer of permission characters
221e53cfe6cSJohn Johansen  * @mask: permission mask to convert
222e53cfe6cSJohn Johansen  */
2237f3ebcf2STyler Hicks void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
224e53cfe6cSJohn Johansen {
225e53cfe6cSJohn Johansen 	unsigned int i, perm = 1;
2267f3ebcf2STyler Hicks 	size_t num_chrs = strlen(chrs);
227e53cfe6cSJohn Johansen 
2287f3ebcf2STyler Hicks 	for (i = 0; i < num_chrs; perm <<= 1, i++) {
2297f3ebcf2STyler Hicks 		if (mask & perm) {
2307f3ebcf2STyler Hicks 			/* Ensure that one byte is left for NUL-termination */
2317f3ebcf2STyler Hicks 			if (WARN_ON_ONCE(str_size <= 1))
2327f3ebcf2STyler Hicks 				break;
2337f3ebcf2STyler Hicks 
234e53cfe6cSJohn Johansen 			*str++ = chrs[i];
2357f3ebcf2STyler Hicks 			str_size--;
2367f3ebcf2STyler Hicks 		}
237e53cfe6cSJohn Johansen 	}
238e53cfe6cSJohn Johansen 	*str = '\0';
239e53cfe6cSJohn Johansen }
240e53cfe6cSJohn Johansen 
24156974a6fSJohn Johansen void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
24256974a6fSJohn Johansen 			 u32 mask)
243aa9aeea8SJohn Johansen {
244aa9aeea8SJohn Johansen 	const char *fmt = "%s";
245aa9aeea8SJohn Johansen 	unsigned int i, perm = 1;
246aa9aeea8SJohn Johansen 	bool prev = false;
247aa9aeea8SJohn Johansen 
248aa9aeea8SJohn Johansen 	for (i = 0; i < 32; perm <<= 1, i++) {
249aa9aeea8SJohn Johansen 		if (mask & perm) {
250aa9aeea8SJohn Johansen 			audit_log_format(ab, fmt, names[i]);
251aa9aeea8SJohn Johansen 			if (!prev) {
252aa9aeea8SJohn Johansen 				prev = true;
253aa9aeea8SJohn Johansen 				fmt = " %s";
254aa9aeea8SJohn Johansen 			}
255aa9aeea8SJohn Johansen 		}
256aa9aeea8SJohn Johansen 	}
257aa9aeea8SJohn Johansen }
258aa9aeea8SJohn Johansen 
259aa9aeea8SJohn Johansen void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
26056974a6fSJohn Johansen 			u32 chrsmask, const char * const *names, u32 namesmask)
261aa9aeea8SJohn Johansen {
262aa9aeea8SJohn Johansen 	char str[33];
263aa9aeea8SJohn Johansen 
264aa9aeea8SJohn Johansen 	audit_log_format(ab, "\"");
265aa9aeea8SJohn Johansen 	if ((mask & chrsmask) && chrs) {
2667f3ebcf2STyler Hicks 		aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
267aa9aeea8SJohn Johansen 		mask &= ~chrsmask;
268aa9aeea8SJohn Johansen 		audit_log_format(ab, "%s", str);
269aa9aeea8SJohn Johansen 		if (mask & namesmask)
270aa9aeea8SJohn Johansen 			audit_log_format(ab, " ");
271aa9aeea8SJohn Johansen 	}
272aa9aeea8SJohn Johansen 	if ((mask & namesmask) && names)
273aa9aeea8SJohn Johansen 		aa_audit_perm_names(ab, names, mask & namesmask);
274aa9aeea8SJohn Johansen 	audit_log_format(ab, "\"");
275aa9aeea8SJohn Johansen }
276aa9aeea8SJohn Johansen 
277aa9aeea8SJohn Johansen /**
278637f688dSJohn Johansen  * aa_audit_perms_cb - generic callback fn for auditing perms
279637f688dSJohn Johansen  * @ab: audit buffer (NOT NULL)
280637f688dSJohn Johansen  * @va: audit struct to audit values of (NOT NULL)
281637f688dSJohn Johansen  */
282637f688dSJohn Johansen static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
283637f688dSJohn Johansen {
284637f688dSJohn Johansen 	struct common_audit_data *sa = va;
285*c57bc80fSJohn Johansen 	struct apparmor_audit_data *ad = aad(sa);
286637f688dSJohn Johansen 
287*c57bc80fSJohn Johansen 	if (ad->request) {
288637f688dSJohn Johansen 		audit_log_format(ab, " requested_mask=");
289*c57bc80fSJohn Johansen 		aa_audit_perm_mask(ab, ad->request, aa_file_perm_chrs,
290637f688dSJohn Johansen 				   PERMS_CHRS_MASK, aa_file_perm_names,
291637f688dSJohn Johansen 				   PERMS_NAMES_MASK);
292637f688dSJohn Johansen 	}
293*c57bc80fSJohn Johansen 	if (ad->denied) {
294637f688dSJohn Johansen 		audit_log_format(ab, "denied_mask=");
295*c57bc80fSJohn Johansen 		aa_audit_perm_mask(ab, ad->denied, aa_file_perm_chrs,
296637f688dSJohn Johansen 				   PERMS_CHRS_MASK, aa_file_perm_names,
297637f688dSJohn Johansen 				   PERMS_NAMES_MASK);
298637f688dSJohn Johansen 	}
299637f688dSJohn Johansen 	audit_log_format(ab, " peer=");
300*c57bc80fSJohn Johansen 	aa_label_xaudit(ab, labels_ns(ad->label), ad->peer,
301637f688dSJohn Johansen 				      FLAGS_NONE, GFP_ATOMIC);
302637f688dSJohn Johansen }
303637f688dSJohn Johansen 
304637f688dSJohn Johansen /**
305aa9aeea8SJohn Johansen  * aa_apply_modes_to_perms - apply namespace and profile flags to perms
306aa9aeea8SJohn Johansen  * @profile: that perms where computed from
307aa9aeea8SJohn Johansen  * @perms: perms to apply mode modifiers to
308aa9aeea8SJohn Johansen  *
309aa9aeea8SJohn Johansen  * TODO: split into profile and ns based flags for when accumulating perms
310aa9aeea8SJohn Johansen  */
311aa9aeea8SJohn Johansen void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
312aa9aeea8SJohn Johansen {
313aa9aeea8SJohn Johansen 	switch (AUDIT_MODE(profile)) {
314aa9aeea8SJohn Johansen 	case AUDIT_ALL:
315aa9aeea8SJohn Johansen 		perms->audit = ALL_PERMS_MASK;
316df561f66SGustavo A. R. Silva 		fallthrough;
317aa9aeea8SJohn Johansen 	case AUDIT_NOQUIET:
318aa9aeea8SJohn Johansen 		perms->quiet = 0;
319aa9aeea8SJohn Johansen 		break;
320aa9aeea8SJohn Johansen 	case AUDIT_QUIET:
321aa9aeea8SJohn Johansen 		perms->audit = 0;
322df561f66SGustavo A. R. Silva 		fallthrough;
323aa9aeea8SJohn Johansen 	case AUDIT_QUIET_DENIED:
324aa9aeea8SJohn Johansen 		perms->quiet = ALL_PERMS_MASK;
325aa9aeea8SJohn Johansen 		break;
326aa9aeea8SJohn Johansen 	}
327aa9aeea8SJohn Johansen 
328aa9aeea8SJohn Johansen 	if (KILL_MODE(profile))
329aa9aeea8SJohn Johansen 		perms->kill = ALL_PERMS_MASK;
330aa9aeea8SJohn Johansen 	else if (COMPLAIN_MODE(profile))
331aa9aeea8SJohn Johansen 		perms->complain = ALL_PERMS_MASK;
33222fac8a0SJohn Johansen 	else if (USER_MODE(profile))
33322fac8a0SJohn Johansen 		perms->prompt = ALL_PERMS_MASK;
334aa9aeea8SJohn Johansen }
335aa9aeea8SJohn Johansen 
336217af7e2SJohn Johansen void aa_profile_match_label(struct aa_profile *profile,
337217af7e2SJohn Johansen 			    struct aa_ruleset *rules,
338217af7e2SJohn Johansen 			    struct aa_label *label,
339637f688dSJohn Johansen 			    int type, u32 request, struct aa_perms *perms)
340637f688dSJohn Johansen {
341637f688dSJohn Johansen 	/* TODO: doesn't yet handle extended types */
34233fc95d8SJohn Johansen 	aa_state_t state;
343637f688dSJohn Johansen 
344217af7e2SJohn Johansen 	state = aa_dfa_next(rules->policy.dfa,
345217af7e2SJohn Johansen 			    rules->policy.start[AA_CLASS_LABEL],
346637f688dSJohn Johansen 			    type);
347217af7e2SJohn Johansen 	aa_label_match(profile, rules, label, state, false, request, perms);
348637f688dSJohn Johansen }
349637f688dSJohn Johansen 
350637f688dSJohn Johansen 
351637f688dSJohn Johansen /* currently unused */
352637f688dSJohn Johansen int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
353637f688dSJohn Johansen 			  u32 request, int type, u32 *deny,
354*c57bc80fSJohn Johansen 			  struct apparmor_audit_data *ad)
355637f688dSJohn Johansen {
3561ad22fccSJohn Johansen 	struct aa_ruleset *rules = list_first_entry(&profile->rules,
3571ad22fccSJohn Johansen 						    typeof(*rules), list);
358637f688dSJohn Johansen 	struct aa_perms perms;
359637f688dSJohn Johansen 
360*c57bc80fSJohn Johansen 	ad->label = &profile->label;
361*c57bc80fSJohn Johansen 	ad->peer = &target->label;
362*c57bc80fSJohn Johansen 	ad->request = request;
363637f688dSJohn Johansen 
3641ad22fccSJohn Johansen 	aa_profile_match_label(profile, rules, &target->label, type, request,
3651ad22fccSJohn Johansen 			       &perms);
366637f688dSJohn Johansen 	aa_apply_modes_to_perms(profile, &perms);
367637f688dSJohn Johansen 	*deny |= request & perms.deny;
368*c57bc80fSJohn Johansen 	return aa_check_perms(profile, &perms, request, ad, aa_audit_perms_cb);
369637f688dSJohn Johansen }
370637f688dSJohn Johansen 
371637f688dSJohn Johansen /**
372637f688dSJohn Johansen  * aa_check_perms - do audit mode selection based on perms set
373637f688dSJohn Johansen  * @profile: profile being checked
374637f688dSJohn Johansen  * @perms: perms computed for the request
375637f688dSJohn Johansen  * @request: requested perms
376*c57bc80fSJohn Johansen  * @ad: initialized audit structure (MAY BE NULL if not auditing)
37769ad4a44SZygmunt Krynicki  * @cb: callback fn for type specific fields (MAY BE NULL)
378637f688dSJohn Johansen  *
379637f688dSJohn Johansen  * Returns: 0 if permission else error code
380637f688dSJohn Johansen  *
381637f688dSJohn Johansen  * Note: profile audit modes need to be set before calling by setting the
382637f688dSJohn Johansen  *       perm masks appropriately.
383637f688dSJohn Johansen  *
384637f688dSJohn Johansen  *       If not auditing then complain mode is not enabled and the
385637f688dSJohn Johansen  *       error code will indicate whether there was an explicit deny
386637f688dSJohn Johansen  *	 with a positive value.
387637f688dSJohn Johansen  */
388637f688dSJohn Johansen int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
389*c57bc80fSJohn Johansen 		   u32 request, struct apparmor_audit_data *ad,
390637f688dSJohn Johansen 		   void (*cb)(struct audit_buffer *, void *))
391637f688dSJohn Johansen {
392637f688dSJohn Johansen 	int type, error;
393637f688dSJohn Johansen 	u32 denied = request & (~perms->allow | perms->deny);
394637f688dSJohn Johansen 
395637f688dSJohn Johansen 	if (likely(!denied)) {
396637f688dSJohn Johansen 		/* mask off perms that are not being force audited */
397637f688dSJohn Johansen 		request &= perms->audit;
398*c57bc80fSJohn Johansen 		if (!request || !ad)
399637f688dSJohn Johansen 			return 0;
400637f688dSJohn Johansen 
401637f688dSJohn Johansen 		type = AUDIT_APPARMOR_AUDIT;
402637f688dSJohn Johansen 		error = 0;
403637f688dSJohn Johansen 	} else {
404637f688dSJohn Johansen 		error = -EACCES;
405637f688dSJohn Johansen 
406637f688dSJohn Johansen 		if (denied & perms->kill)
407637f688dSJohn Johansen 			type = AUDIT_APPARMOR_KILL;
408637f688dSJohn Johansen 		else if (denied == (denied & perms->complain))
409637f688dSJohn Johansen 			type = AUDIT_APPARMOR_ALLOWED;
410637f688dSJohn Johansen 		else
411637f688dSJohn Johansen 			type = AUDIT_APPARMOR_DENIED;
412637f688dSJohn Johansen 
413637f688dSJohn Johansen 		if (denied == (denied & perms->hide))
414637f688dSJohn Johansen 			error = -ENOENT;
415637f688dSJohn Johansen 
416637f688dSJohn Johansen 		denied &= ~perms->quiet;
417*c57bc80fSJohn Johansen 		if (!ad || !denied)
418637f688dSJohn Johansen 			return error;
419637f688dSJohn Johansen 	}
420637f688dSJohn Johansen 
421*c57bc80fSJohn Johansen 	if (ad) {
422*c57bc80fSJohn Johansen 		ad->label = &profile->label;
423*c57bc80fSJohn Johansen 		ad->request = request;
424*c57bc80fSJohn Johansen 		ad->denied = denied;
425*c57bc80fSJohn Johansen 		ad->error = error;
426*c57bc80fSJohn Johansen 		aa_audit_msg(type, ad, cb);
427637f688dSJohn Johansen 	}
428637f688dSJohn Johansen 
429637f688dSJohn Johansen 	if (type == AUDIT_APPARMOR_ALLOWED)
430637f688dSJohn Johansen 		error = 0;
431637f688dSJohn Johansen 
432637f688dSJohn Johansen 	return error;
433637f688dSJohn Johansen }
434637f688dSJohn Johansen 
435637f688dSJohn Johansen 
436637f688dSJohn Johansen /**
437fe6bb31fSJohn Johansen  * aa_policy_init - initialize a policy structure
438fe6bb31fSJohn Johansen  * @policy: policy to initialize  (NOT NULL)
439fe6bb31fSJohn Johansen  * @prefix: prefix name if any is required.  (MAYBE NULL)
440fe6bb31fSJohn Johansen  * @name: name of the policy, init will make a copy of it  (NOT NULL)
441a1bd627bSJohn Johansen  * @gfp: allocation mode
442fe6bb31fSJohn Johansen  *
443fe6bb31fSJohn Johansen  * Note: this fn creates a copy of strings passed in
444fe6bb31fSJohn Johansen  *
445fe6bb31fSJohn Johansen  * Returns: true if policy init successful
446fe6bb31fSJohn Johansen  */
447fe6bb31fSJohn Johansen bool aa_policy_init(struct aa_policy *policy, const char *prefix,
448d102d895SJohn Johansen 		    const char *name, gfp_t gfp)
449fe6bb31fSJohn Johansen {
450a1bd627bSJohn Johansen 	char *hname;
451a1bd627bSJohn Johansen 
452fe6bb31fSJohn Johansen 	/* freed by policy_free */
453fe6bb31fSJohn Johansen 	if (prefix) {
454a1bd627bSJohn Johansen 		hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
455a1bd627bSJohn Johansen 		if (hname)
456a1bd627bSJohn Johansen 			sprintf(hname, "%s//%s", prefix, name);
457a1bd627bSJohn Johansen 	} else {
458a1bd627bSJohn Johansen 		hname = aa_str_alloc(strlen(name) + 1, gfp);
459a1bd627bSJohn Johansen 		if (hname)
460a1bd627bSJohn Johansen 			strcpy(hname, name);
461a1bd627bSJohn Johansen 	}
462a1bd627bSJohn Johansen 	if (!hname)
463b9c42ac7Skbuild test robot 		return false;
464a1bd627bSJohn Johansen 	policy->hname = hname;
465fe6bb31fSJohn Johansen 	/* base.name is a substring of fqname */
466d102d895SJohn Johansen 	policy->name = basename(policy->hname);
467fe6bb31fSJohn Johansen 	INIT_LIST_HEAD(&policy->list);
468fe6bb31fSJohn Johansen 	INIT_LIST_HEAD(&policy->profiles);
469fe6bb31fSJohn Johansen 
470b9c42ac7Skbuild test robot 	return true;
471fe6bb31fSJohn Johansen }
472fe6bb31fSJohn Johansen 
473fe6bb31fSJohn Johansen /**
474fe6bb31fSJohn Johansen  * aa_policy_destroy - free the elements referenced by @policy
475fe6bb31fSJohn Johansen  * @policy: policy that is to have its elements freed  (NOT NULL)
476fe6bb31fSJohn Johansen  */
477fe6bb31fSJohn Johansen void aa_policy_destroy(struct aa_policy *policy)
478fe6bb31fSJohn Johansen {
4795fd1b95fSJohn Johansen 	AA_BUG(on_list_rcu(&policy->profiles));
4805fd1b95fSJohn Johansen 	AA_BUG(on_list_rcu(&policy->list));
481fe6bb31fSJohn Johansen 
482fe6bb31fSJohn Johansen 	/* don't free name as its a subset of hname */
483a1bd627bSJohn Johansen 	aa_put_str(policy->hname);
484fe6bb31fSJohn Johansen }
485