xref: /openbmc/linux/security/apparmor/lib.c (revision bf690f59)
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 /**
29cdff2642SJohn Johansen  * aa_split_fqname - split a fqname into a profile and namespace name
30cdff2642SJohn Johansen  * @fqname: a full qualified name in namespace profile format (NOT NULL)
31cdff2642SJohn Johansen  * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
32cdff2642SJohn Johansen  *
33cdff2642SJohn Johansen  * Returns: profile name or NULL if one is not specified
34cdff2642SJohn Johansen  *
35cdff2642SJohn Johansen  * Split a namespace name from a profile name (see policy.c for naming
36cdff2642SJohn Johansen  * description).  If a portion of the name is missing it returns NULL for
37cdff2642SJohn Johansen  * that portion.
38cdff2642SJohn Johansen  *
39cdff2642SJohn Johansen  * NOTE: may modify the @fqname string.  The pointers returned point
40cdff2642SJohn Johansen  *       into the @fqname string.
41cdff2642SJohn Johansen  */
42cdff2642SJohn Johansen char *aa_split_fqname(char *fqname, char **ns_name)
43cdff2642SJohn Johansen {
44cdff2642SJohn Johansen 	char *name = strim(fqname);
45cdff2642SJohn Johansen 
46cdff2642SJohn Johansen 	*ns_name = NULL;
47cdff2642SJohn Johansen 	if (name[0] == ':') {
48cdff2642SJohn Johansen 		char *split = strchr(&name[1], ':');
4904ccd53fSJohn Johansen 		*ns_name = skip_spaces(&name[1]);
50cdff2642SJohn Johansen 		if (split) {
51cdff2642SJohn Johansen 			/* overwrite ':' with \0 */
522654bfbcSJohn Johansen 			*split++ = 0;
532654bfbcSJohn Johansen 			if (strncmp(split, "//", 2) == 0)
542654bfbcSJohn Johansen 				split += 2;
552654bfbcSJohn Johansen 			name = skip_spaces(split);
56cdff2642SJohn Johansen 		} else
57cdff2642SJohn Johansen 			/* a ns name without a following profile is allowed */
58cdff2642SJohn Johansen 			name = NULL;
59cdff2642SJohn Johansen 	}
60cdff2642SJohn Johansen 	if (name && *name == 0)
61cdff2642SJohn Johansen 		name = NULL;
62cdff2642SJohn Johansen 
63cdff2642SJohn Johansen 	return name;
64cdff2642SJohn Johansen }
65cdff2642SJohn Johansen 
66cdff2642SJohn Johansen /**
673b0aaf58SJohn Johansen  * skipn_spaces - Removes leading whitespace from @str.
683b0aaf58SJohn Johansen  * @str: The string to be stripped.
693b0aaf58SJohn Johansen  *
703b0aaf58SJohn Johansen  * Returns a pointer to the first non-whitespace character in @str.
713b0aaf58SJohn Johansen  * if all whitespace will return NULL
723b0aaf58SJohn Johansen  */
733b0aaf58SJohn Johansen 
74b91deb9dSJohn Johansen const char *skipn_spaces(const char *str, size_t n)
753b0aaf58SJohn Johansen {
763b0aaf58SJohn Johansen 	for (; n && isspace(*str); --n)
773b0aaf58SJohn Johansen 		++str;
783b0aaf58SJohn Johansen 	if (n)
793b0aaf58SJohn Johansen 		return (char *)str;
803b0aaf58SJohn Johansen 	return NULL;
813b0aaf58SJohn Johansen }
823b0aaf58SJohn Johansen 
833b0aaf58SJohn Johansen const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
843b0aaf58SJohn Johansen 			     size_t *ns_len)
853b0aaf58SJohn Johansen {
863b0aaf58SJohn Johansen 	const char *end = fqname + n;
873b0aaf58SJohn Johansen 	const char *name = skipn_spaces(fqname, n);
883b0aaf58SJohn Johansen 
893b0aaf58SJohn Johansen 	*ns_name = NULL;
903b0aaf58SJohn Johansen 	*ns_len = 0;
91250f2da4SZubin Mithra 
92250f2da4SZubin Mithra 	if (!name)
93250f2da4SZubin Mithra 		return NULL;
94250f2da4SZubin Mithra 
953b0aaf58SJohn Johansen 	if (name[0] == ':') {
963b0aaf58SJohn Johansen 		char *split = strnchr(&name[1], end - &name[1], ':');
973b0aaf58SJohn Johansen 		*ns_name = skipn_spaces(&name[1], end - &name[1]);
983b0aaf58SJohn Johansen 		if (!*ns_name)
993b0aaf58SJohn Johansen 			return NULL;
1003b0aaf58SJohn Johansen 		if (split) {
1013b0aaf58SJohn Johansen 			*ns_len = split - *ns_name;
1023b0aaf58SJohn Johansen 			if (*ns_len == 0)
1033b0aaf58SJohn Johansen 				*ns_name = NULL;
1043b0aaf58SJohn Johansen 			split++;
1053b0aaf58SJohn Johansen 			if (end - split > 1 && strncmp(split, "//", 2) == 0)
1063b0aaf58SJohn Johansen 				split += 2;
1073b0aaf58SJohn Johansen 			name = skipn_spaces(split, end - split);
1083b0aaf58SJohn Johansen 		} else {
1093b0aaf58SJohn Johansen 			/* a ns name without a following profile is allowed */
1103b0aaf58SJohn Johansen 			name = NULL;
1113b0aaf58SJohn Johansen 			*ns_len = end - *ns_name;
1123b0aaf58SJohn Johansen 		}
1133b0aaf58SJohn Johansen 	}
1143b0aaf58SJohn Johansen 	if (name && *name == 0)
1153b0aaf58SJohn Johansen 		name = NULL;
1163b0aaf58SJohn Johansen 
1173b0aaf58SJohn Johansen 	return name;
1183b0aaf58SJohn Johansen }
1193b0aaf58SJohn Johansen 
1203b0aaf58SJohn Johansen /**
121cdff2642SJohn Johansen  * aa_info_message - log a none profile related status message
122cdff2642SJohn Johansen  * @str: message to log
123cdff2642SJohn Johansen  */
124cdff2642SJohn Johansen void aa_info_message(const char *str)
125cdff2642SJohn Johansen {
126cdff2642SJohn Johansen 	if (audit_enabled) {
127ef88a7acSJohn Johansen 		DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
128ef88a7acSJohn Johansen 
129ef88a7acSJohn Johansen 		aad(&sa)->info = str;
130cdff2642SJohn Johansen 		aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
131cdff2642SJohn Johansen 	}
132cdff2642SJohn Johansen 	printk(KERN_INFO "AppArmor: %s\n", str);
133cdff2642SJohn Johansen }
134cdff2642SJohn Johansen 
135a1bd627bSJohn Johansen __counted char *aa_str_alloc(int size, gfp_t gfp)
136a1bd627bSJohn Johansen {
137a1bd627bSJohn Johansen 	struct counted_str *str;
138a1bd627bSJohn Johansen 
139c0ea4b91SGustavo A. R. Silva 	str = kmalloc(struct_size(str, name, size), gfp);
140a1bd627bSJohn Johansen 	if (!str)
141a1bd627bSJohn Johansen 		return NULL;
142a1bd627bSJohn Johansen 
143a1bd627bSJohn Johansen 	kref_init(&str->count);
144a1bd627bSJohn Johansen 	return str->name;
145a1bd627bSJohn Johansen }
146a1bd627bSJohn Johansen 
147a1bd627bSJohn Johansen void aa_str_kref(struct kref *kref)
148a1bd627bSJohn Johansen {
149a1bd627bSJohn Johansen 	kfree(container_of(kref, struct counted_str, count));
150a1bd627bSJohn Johansen }
151a1bd627bSJohn Johansen 
152a1bd627bSJohn Johansen 
153e53cfe6cSJohn Johansen const char aa_file_perm_chrs[] = "xwracd         km l     ";
154e53cfe6cSJohn Johansen const char *aa_file_perm_names[] = {
155e53cfe6cSJohn Johansen 	"exec",
156e53cfe6cSJohn Johansen 	"write",
157e53cfe6cSJohn Johansen 	"read",
158e53cfe6cSJohn Johansen 	"append",
159e53cfe6cSJohn Johansen 
160e53cfe6cSJohn Johansen 	"create",
161e53cfe6cSJohn Johansen 	"delete",
162e53cfe6cSJohn Johansen 	"open",
163e53cfe6cSJohn Johansen 	"rename",
164e53cfe6cSJohn Johansen 
165e53cfe6cSJohn Johansen 	"setattr",
166e53cfe6cSJohn Johansen 	"getattr",
167e53cfe6cSJohn Johansen 	"setcred",
168e53cfe6cSJohn Johansen 	"getcred",
169e53cfe6cSJohn Johansen 
170e53cfe6cSJohn Johansen 	"chmod",
171e53cfe6cSJohn Johansen 	"chown",
172e53cfe6cSJohn Johansen 	"chgrp",
173e53cfe6cSJohn Johansen 	"lock",
174e53cfe6cSJohn Johansen 
175e53cfe6cSJohn Johansen 	"mmap",
176e53cfe6cSJohn Johansen 	"mprot",
177e53cfe6cSJohn Johansen 	"link",
178e53cfe6cSJohn Johansen 	"snapshot",
179e53cfe6cSJohn Johansen 
180e53cfe6cSJohn Johansen 	"unknown",
181e53cfe6cSJohn Johansen 	"unknown",
182e53cfe6cSJohn Johansen 	"unknown",
183e53cfe6cSJohn Johansen 	"unknown",
184e53cfe6cSJohn Johansen 
185e53cfe6cSJohn Johansen 	"unknown",
186e53cfe6cSJohn Johansen 	"unknown",
187e53cfe6cSJohn Johansen 	"unknown",
188e53cfe6cSJohn Johansen 	"unknown",
189e53cfe6cSJohn Johansen 
190e53cfe6cSJohn Johansen 	"stack",
191e53cfe6cSJohn Johansen 	"change_onexec",
192e53cfe6cSJohn Johansen 	"change_profile",
193e53cfe6cSJohn Johansen 	"change_hat",
194e53cfe6cSJohn Johansen };
195e53cfe6cSJohn Johansen 
196e53cfe6cSJohn Johansen /**
197e53cfe6cSJohn Johansen  * aa_perm_mask_to_str - convert a perm mask to its short string
198e53cfe6cSJohn Johansen  * @str: character buffer to store string in (at least 10 characters)
1997f3ebcf2STyler Hicks  * @str_size: size of the @str buffer
2007f3ebcf2STyler Hicks  * @chrs: NUL-terminated character buffer of permission characters
201e53cfe6cSJohn Johansen  * @mask: permission mask to convert
202e53cfe6cSJohn Johansen  */
2037f3ebcf2STyler Hicks void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
204e53cfe6cSJohn Johansen {
205e53cfe6cSJohn Johansen 	unsigned int i, perm = 1;
2067f3ebcf2STyler Hicks 	size_t num_chrs = strlen(chrs);
207e53cfe6cSJohn Johansen 
2087f3ebcf2STyler Hicks 	for (i = 0; i < num_chrs; perm <<= 1, i++) {
2097f3ebcf2STyler Hicks 		if (mask & perm) {
2107f3ebcf2STyler Hicks 			/* Ensure that one byte is left for NUL-termination */
2117f3ebcf2STyler Hicks 			if (WARN_ON_ONCE(str_size <= 1))
2127f3ebcf2STyler Hicks 				break;
2137f3ebcf2STyler Hicks 
214e53cfe6cSJohn Johansen 			*str++ = chrs[i];
2157f3ebcf2STyler Hicks 			str_size--;
2167f3ebcf2STyler Hicks 		}
217e53cfe6cSJohn Johansen 	}
218e53cfe6cSJohn Johansen 	*str = '\0';
219e53cfe6cSJohn Johansen }
220e53cfe6cSJohn Johansen 
22156974a6fSJohn Johansen void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
22256974a6fSJohn Johansen 			 u32 mask)
223aa9aeea8SJohn Johansen {
224aa9aeea8SJohn Johansen 	const char *fmt = "%s";
225aa9aeea8SJohn Johansen 	unsigned int i, perm = 1;
226aa9aeea8SJohn Johansen 	bool prev = false;
227aa9aeea8SJohn Johansen 
228aa9aeea8SJohn Johansen 	for (i = 0; i < 32; perm <<= 1, i++) {
229aa9aeea8SJohn Johansen 		if (mask & perm) {
230aa9aeea8SJohn Johansen 			audit_log_format(ab, fmt, names[i]);
231aa9aeea8SJohn Johansen 			if (!prev) {
232aa9aeea8SJohn Johansen 				prev = true;
233aa9aeea8SJohn Johansen 				fmt = " %s";
234aa9aeea8SJohn Johansen 			}
235aa9aeea8SJohn Johansen 		}
236aa9aeea8SJohn Johansen 	}
237aa9aeea8SJohn Johansen }
238aa9aeea8SJohn Johansen 
239aa9aeea8SJohn Johansen void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
24056974a6fSJohn Johansen 			u32 chrsmask, const char * const *names, u32 namesmask)
241aa9aeea8SJohn Johansen {
242aa9aeea8SJohn Johansen 	char str[33];
243aa9aeea8SJohn Johansen 
244aa9aeea8SJohn Johansen 	audit_log_format(ab, "\"");
245aa9aeea8SJohn Johansen 	if ((mask & chrsmask) && chrs) {
2467f3ebcf2STyler Hicks 		aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
247aa9aeea8SJohn Johansen 		mask &= ~chrsmask;
248aa9aeea8SJohn Johansen 		audit_log_format(ab, "%s", str);
249aa9aeea8SJohn Johansen 		if (mask & namesmask)
250aa9aeea8SJohn Johansen 			audit_log_format(ab, " ");
251aa9aeea8SJohn Johansen 	}
252aa9aeea8SJohn Johansen 	if ((mask & namesmask) && names)
253aa9aeea8SJohn Johansen 		aa_audit_perm_names(ab, names, mask & namesmask);
254aa9aeea8SJohn Johansen 	audit_log_format(ab, "\"");
255aa9aeea8SJohn Johansen }
256aa9aeea8SJohn Johansen 
257aa9aeea8SJohn Johansen /**
258637f688dSJohn Johansen  * aa_audit_perms_cb - generic callback fn for auditing perms
259637f688dSJohn Johansen  * @ab: audit buffer (NOT NULL)
260637f688dSJohn Johansen  * @va: audit struct to audit values of (NOT NULL)
261637f688dSJohn Johansen  */
262637f688dSJohn Johansen static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
263637f688dSJohn Johansen {
264637f688dSJohn Johansen 	struct common_audit_data *sa = va;
265637f688dSJohn Johansen 
266637f688dSJohn Johansen 	if (aad(sa)->request) {
267637f688dSJohn Johansen 		audit_log_format(ab, " requested_mask=");
268637f688dSJohn Johansen 		aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
269637f688dSJohn Johansen 				   PERMS_CHRS_MASK, aa_file_perm_names,
270637f688dSJohn Johansen 				   PERMS_NAMES_MASK);
271637f688dSJohn Johansen 	}
272637f688dSJohn Johansen 	if (aad(sa)->denied) {
273637f688dSJohn Johansen 		audit_log_format(ab, "denied_mask=");
274637f688dSJohn Johansen 		aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
275637f688dSJohn Johansen 				   PERMS_CHRS_MASK, aa_file_perm_names,
276637f688dSJohn Johansen 				   PERMS_NAMES_MASK);
277637f688dSJohn Johansen 	}
278637f688dSJohn Johansen 	audit_log_format(ab, " peer=");
279637f688dSJohn Johansen 	aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
280637f688dSJohn Johansen 				      FLAGS_NONE, GFP_ATOMIC);
281637f688dSJohn Johansen }
282637f688dSJohn Johansen 
283637f688dSJohn Johansen /**
284aa9aeea8SJohn Johansen  * aa_apply_modes_to_perms - apply namespace and profile flags to perms
285aa9aeea8SJohn Johansen  * @profile: that perms where computed from
286aa9aeea8SJohn Johansen  * @perms: perms to apply mode modifiers to
287aa9aeea8SJohn Johansen  *
288aa9aeea8SJohn Johansen  * TODO: split into profile and ns based flags for when accumulating perms
289aa9aeea8SJohn Johansen  */
290aa9aeea8SJohn Johansen void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
291aa9aeea8SJohn Johansen {
292aa9aeea8SJohn Johansen 	switch (AUDIT_MODE(profile)) {
293aa9aeea8SJohn Johansen 	case AUDIT_ALL:
294aa9aeea8SJohn Johansen 		perms->audit = ALL_PERMS_MASK;
295df561f66SGustavo A. R. Silva 		fallthrough;
296aa9aeea8SJohn Johansen 	case AUDIT_NOQUIET:
297aa9aeea8SJohn Johansen 		perms->quiet = 0;
298aa9aeea8SJohn Johansen 		break;
299aa9aeea8SJohn Johansen 	case AUDIT_QUIET:
300aa9aeea8SJohn Johansen 		perms->audit = 0;
301df561f66SGustavo A. R. Silva 		fallthrough;
302aa9aeea8SJohn Johansen 	case AUDIT_QUIET_DENIED:
303aa9aeea8SJohn Johansen 		perms->quiet = ALL_PERMS_MASK;
304aa9aeea8SJohn Johansen 		break;
305aa9aeea8SJohn Johansen 	}
306aa9aeea8SJohn Johansen 
307aa9aeea8SJohn Johansen 	if (KILL_MODE(profile))
308aa9aeea8SJohn Johansen 		perms->kill = ALL_PERMS_MASK;
309aa9aeea8SJohn Johansen 	else if (COMPLAIN_MODE(profile))
310aa9aeea8SJohn Johansen 		perms->complain = ALL_PERMS_MASK;
311aa9aeea8SJohn Johansen /*
312aa9aeea8SJohn Johansen  *  TODO:
313aa9aeea8SJohn Johansen  *	else if (PROMPT_MODE(profile))
314aa9aeea8SJohn Johansen  *		perms->prompt = ALL_PERMS_MASK;
315aa9aeea8SJohn Johansen  */
316aa9aeea8SJohn Johansen }
317aa9aeea8SJohn Johansen 
318cdff2642SJohn Johansen /**
319637f688dSJohn Johansen  * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
320637f688dSJohn Johansen  * @accum - perms struct to accumulate into
321637f688dSJohn Johansen  * @addend - perms struct to add to @accum
322637f688dSJohn Johansen  */
323637f688dSJohn Johansen void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
324637f688dSJohn Johansen {
325637f688dSJohn Johansen 	accum->deny |= addend->deny;
326637f688dSJohn Johansen 	accum->allow &= addend->allow & ~addend->deny;
327637f688dSJohn Johansen 	accum->audit |= addend->audit & addend->allow;
328637f688dSJohn Johansen 	accum->quiet &= addend->quiet & ~addend->allow;
329637f688dSJohn Johansen 	accum->kill |= addend->kill & ~addend->allow;
330637f688dSJohn Johansen 	accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
331637f688dSJohn Johansen 	accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
332637f688dSJohn Johansen 	accum->hide &= addend->hide & ~addend->allow;
333637f688dSJohn Johansen 	accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
334*bf690f59SJohn Johansen 	accum->subtree |= addend->subtree & ~addend->deny;
335637f688dSJohn Johansen }
336637f688dSJohn Johansen 
337637f688dSJohn Johansen /**
338637f688dSJohn Johansen  * aa_perms_accum - accumulate perms, masking off overlapping perms
339637f688dSJohn Johansen  * @accum - perms struct to accumulate into
340637f688dSJohn Johansen  * @addend - perms struct to add to @accum
341637f688dSJohn Johansen  */
342637f688dSJohn Johansen void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
343637f688dSJohn Johansen {
344637f688dSJohn Johansen 	accum->deny |= addend->deny;
345637f688dSJohn Johansen 	accum->allow &= addend->allow & ~accum->deny;
346637f688dSJohn Johansen 	accum->audit |= addend->audit & accum->allow;
347637f688dSJohn Johansen 	accum->quiet &= addend->quiet & ~accum->allow;
348637f688dSJohn Johansen 	accum->kill |= addend->kill & ~accum->allow;
349637f688dSJohn Johansen 	accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
350637f688dSJohn Johansen 	accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
351637f688dSJohn Johansen 	accum->hide &= addend->hide & ~accum->allow;
352637f688dSJohn Johansen 	accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
353*bf690f59SJohn Johansen 	accum->subtree &= addend->subtree & ~accum->deny;
354637f688dSJohn Johansen }
355637f688dSJohn Johansen 
356637f688dSJohn Johansen void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
357637f688dSJohn Johansen 			    int type, u32 request, struct aa_perms *perms)
358637f688dSJohn Johansen {
359637f688dSJohn Johansen 	/* TODO: doesn't yet handle extended types */
360637f688dSJohn Johansen 	unsigned int state;
361637f688dSJohn Johansen 
362637f688dSJohn Johansen 	state = aa_dfa_next(profile->policy.dfa,
363637f688dSJohn Johansen 			    profile->policy.start[AA_CLASS_LABEL],
364637f688dSJohn Johansen 			    type);
365637f688dSJohn Johansen 	aa_label_match(profile, label, state, false, request, perms);
366637f688dSJohn Johansen }
367637f688dSJohn Johansen 
368637f688dSJohn Johansen 
369637f688dSJohn Johansen /* currently unused */
370637f688dSJohn Johansen int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
371637f688dSJohn Johansen 			  u32 request, int type, u32 *deny,
372637f688dSJohn Johansen 			  struct common_audit_data *sa)
373637f688dSJohn Johansen {
374637f688dSJohn Johansen 	struct aa_perms perms;
375637f688dSJohn Johansen 
376637f688dSJohn Johansen 	aad(sa)->label = &profile->label;
377637f688dSJohn Johansen 	aad(sa)->peer = &target->label;
378637f688dSJohn Johansen 	aad(sa)->request = request;
379637f688dSJohn Johansen 
380637f688dSJohn Johansen 	aa_profile_match_label(profile, &target->label, type, request, &perms);
381637f688dSJohn Johansen 	aa_apply_modes_to_perms(profile, &perms);
382637f688dSJohn Johansen 	*deny |= request & perms.deny;
383637f688dSJohn Johansen 	return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
384637f688dSJohn Johansen }
385637f688dSJohn Johansen 
386637f688dSJohn Johansen /**
387637f688dSJohn Johansen  * aa_check_perms - do audit mode selection based on perms set
388637f688dSJohn Johansen  * @profile: profile being checked
389637f688dSJohn Johansen  * @perms: perms computed for the request
390637f688dSJohn Johansen  * @request: requested perms
391637f688dSJohn Johansen  * @deny: Returns: explicit deny set
392637f688dSJohn Johansen  * @sa: initialized audit structure (MAY BE NULL if not auditing)
39369ad4a44SZygmunt Krynicki  * @cb: callback fn for type specific fields (MAY BE NULL)
394637f688dSJohn Johansen  *
395637f688dSJohn Johansen  * Returns: 0 if permission else error code
396637f688dSJohn Johansen  *
397637f688dSJohn Johansen  * Note: profile audit modes need to be set before calling by setting the
398637f688dSJohn Johansen  *       perm masks appropriately.
399637f688dSJohn Johansen  *
400637f688dSJohn Johansen  *       If not auditing then complain mode is not enabled and the
401637f688dSJohn Johansen  *       error code will indicate whether there was an explicit deny
402637f688dSJohn Johansen  *	 with a positive value.
403637f688dSJohn Johansen  */
404637f688dSJohn Johansen int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
405637f688dSJohn Johansen 		   u32 request, struct common_audit_data *sa,
406637f688dSJohn Johansen 		   void (*cb)(struct audit_buffer *, void *))
407637f688dSJohn Johansen {
408637f688dSJohn Johansen 	int type, error;
409637f688dSJohn Johansen 	u32 denied = request & (~perms->allow | perms->deny);
410637f688dSJohn Johansen 
411637f688dSJohn Johansen 	if (likely(!denied)) {
412637f688dSJohn Johansen 		/* mask off perms that are not being force audited */
413637f688dSJohn Johansen 		request &= perms->audit;
414637f688dSJohn Johansen 		if (!request || !sa)
415637f688dSJohn Johansen 			return 0;
416637f688dSJohn Johansen 
417637f688dSJohn Johansen 		type = AUDIT_APPARMOR_AUDIT;
418637f688dSJohn Johansen 		error = 0;
419637f688dSJohn Johansen 	} else {
420637f688dSJohn Johansen 		error = -EACCES;
421637f688dSJohn Johansen 
422637f688dSJohn Johansen 		if (denied & perms->kill)
423637f688dSJohn Johansen 			type = AUDIT_APPARMOR_KILL;
424637f688dSJohn Johansen 		else if (denied == (denied & perms->complain))
425637f688dSJohn Johansen 			type = AUDIT_APPARMOR_ALLOWED;
426637f688dSJohn Johansen 		else
427637f688dSJohn Johansen 			type = AUDIT_APPARMOR_DENIED;
428637f688dSJohn Johansen 
429637f688dSJohn Johansen 		if (denied == (denied & perms->hide))
430637f688dSJohn Johansen 			error = -ENOENT;
431637f688dSJohn Johansen 
432637f688dSJohn Johansen 		denied &= ~perms->quiet;
433637f688dSJohn Johansen 		if (!sa || !denied)
434637f688dSJohn Johansen 			return error;
435637f688dSJohn Johansen 	}
436637f688dSJohn Johansen 
437637f688dSJohn Johansen 	if (sa) {
438637f688dSJohn Johansen 		aad(sa)->label = &profile->label;
439637f688dSJohn Johansen 		aad(sa)->request = request;
440637f688dSJohn Johansen 		aad(sa)->denied = denied;
441637f688dSJohn Johansen 		aad(sa)->error = error;
442637f688dSJohn Johansen 		aa_audit_msg(type, sa, cb);
443637f688dSJohn Johansen 	}
444637f688dSJohn Johansen 
445637f688dSJohn Johansen 	if (type == AUDIT_APPARMOR_ALLOWED)
446637f688dSJohn Johansen 		error = 0;
447637f688dSJohn Johansen 
448637f688dSJohn Johansen 	return error;
449637f688dSJohn Johansen }
450637f688dSJohn Johansen 
451637f688dSJohn Johansen 
452637f688dSJohn Johansen /**
453fe6bb31fSJohn Johansen  * aa_policy_init - initialize a policy structure
454fe6bb31fSJohn Johansen  * @policy: policy to initialize  (NOT NULL)
455fe6bb31fSJohn Johansen  * @prefix: prefix name if any is required.  (MAYBE NULL)
456fe6bb31fSJohn Johansen  * @name: name of the policy, init will make a copy of it  (NOT NULL)
457a1bd627bSJohn Johansen  * @gfp: allocation mode
458fe6bb31fSJohn Johansen  *
459fe6bb31fSJohn Johansen  * Note: this fn creates a copy of strings passed in
460fe6bb31fSJohn Johansen  *
461fe6bb31fSJohn Johansen  * Returns: true if policy init successful
462fe6bb31fSJohn Johansen  */
463fe6bb31fSJohn Johansen bool aa_policy_init(struct aa_policy *policy, const char *prefix,
464d102d895SJohn Johansen 		    const char *name, gfp_t gfp)
465fe6bb31fSJohn Johansen {
466a1bd627bSJohn Johansen 	char *hname;
467a1bd627bSJohn Johansen 
468fe6bb31fSJohn Johansen 	/* freed by policy_free */
469fe6bb31fSJohn Johansen 	if (prefix) {
470a1bd627bSJohn Johansen 		hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
471a1bd627bSJohn Johansen 		if (hname)
472a1bd627bSJohn Johansen 			sprintf(hname, "%s//%s", prefix, name);
473a1bd627bSJohn Johansen 	} else {
474a1bd627bSJohn Johansen 		hname = aa_str_alloc(strlen(name) + 1, gfp);
475a1bd627bSJohn Johansen 		if (hname)
476a1bd627bSJohn Johansen 			strcpy(hname, name);
477a1bd627bSJohn Johansen 	}
478a1bd627bSJohn Johansen 	if (!hname)
479b9c42ac7Skbuild test robot 		return false;
480a1bd627bSJohn Johansen 	policy->hname = hname;
481fe6bb31fSJohn Johansen 	/* base.name is a substring of fqname */
482d102d895SJohn Johansen 	policy->name = basename(policy->hname);
483fe6bb31fSJohn Johansen 	INIT_LIST_HEAD(&policy->list);
484fe6bb31fSJohn Johansen 	INIT_LIST_HEAD(&policy->profiles);
485fe6bb31fSJohn Johansen 
486b9c42ac7Skbuild test robot 	return true;
487fe6bb31fSJohn Johansen }
488fe6bb31fSJohn Johansen 
489fe6bb31fSJohn Johansen /**
490fe6bb31fSJohn Johansen  * aa_policy_destroy - free the elements referenced by @policy
491fe6bb31fSJohn Johansen  * @policy: policy that is to have its elements freed  (NOT NULL)
492fe6bb31fSJohn Johansen  */
493fe6bb31fSJohn Johansen void aa_policy_destroy(struct aa_policy *policy)
494fe6bb31fSJohn Johansen {
4955fd1b95fSJohn Johansen 	AA_BUG(on_list_rcu(&policy->profiles));
4965fd1b95fSJohn Johansen 	AA_BUG(on_list_rcu(&policy->list));
497fe6bb31fSJohn Johansen 
498fe6bb31fSJohn Johansen 	/* don't free name as its a subset of hname */
499a1bd627bSJohn Johansen 	aa_put_str(policy->hname);
500fe6bb31fSJohn Johansen }
501