xref: /openbmc/linux/security/apparmor/lib.c (revision 7f3ebcf2b1395e0248e56146041e1e5625fd2f23)
1cdff2642SJohn Johansen /*
2cdff2642SJohn Johansen  * AppArmor security module
3cdff2642SJohn Johansen  *
4cdff2642SJohn Johansen  * This file contains basic common functions used in AppArmor
5cdff2642SJohn Johansen  *
6cdff2642SJohn Johansen  * Copyright (C) 1998-2008 Novell/SUSE
7cdff2642SJohn Johansen  * Copyright 2009-2010 Canonical Ltd.
8cdff2642SJohn Johansen  *
9cdff2642SJohn Johansen  * This program is free software; you can redistribute it and/or
10cdff2642SJohn Johansen  * modify it under the terms of the GNU General Public License as
11cdff2642SJohn Johansen  * published by the Free Software Foundation, version 2 of the
12cdff2642SJohn Johansen  * License.
13cdff2642SJohn Johansen  */
14cdff2642SJohn Johansen 
153b0aaf58SJohn Johansen #include <linux/ctype.h>
16b7f080cfSAlexey Dobriyan #include <linux/mm.h>
17cdff2642SJohn Johansen #include <linux/slab.h>
18cdff2642SJohn Johansen #include <linux/string.h>
19cdff2642SJohn Johansen #include <linux/vmalloc.h>
20cdff2642SJohn Johansen 
21cdff2642SJohn Johansen #include "include/audit.h"
2232c3df63SJames Morris #include "include/apparmor.h"
2312557dcbSJohn Johansen #include "include/lib.h"
24fc7e0b26SJohn Johansen #include "include/perms.h"
25fe6bb31fSJohn Johansen #include "include/policy.h"
26cdff2642SJohn Johansen 
272d679f3cSJohn Johansen struct aa_perms nullperms;
28aa9aeea8SJohn Johansen struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
29aa9aeea8SJohn Johansen 			     .quiet = ALL_PERMS_MASK,
30aa9aeea8SJohn Johansen 			     .hide = ALL_PERMS_MASK };
31aa9aeea8SJohn Johansen 
32cdff2642SJohn Johansen /**
33cdff2642SJohn Johansen  * aa_split_fqname - split a fqname into a profile and namespace name
34cdff2642SJohn Johansen  * @fqname: a full qualified name in namespace profile format (NOT NULL)
35cdff2642SJohn Johansen  * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
36cdff2642SJohn Johansen  *
37cdff2642SJohn Johansen  * Returns: profile name or NULL if one is not specified
38cdff2642SJohn Johansen  *
39cdff2642SJohn Johansen  * Split a namespace name from a profile name (see policy.c for naming
40cdff2642SJohn Johansen  * description).  If a portion of the name is missing it returns NULL for
41cdff2642SJohn Johansen  * that portion.
42cdff2642SJohn Johansen  *
43cdff2642SJohn Johansen  * NOTE: may modify the @fqname string.  The pointers returned point
44cdff2642SJohn Johansen  *       into the @fqname string.
45cdff2642SJohn Johansen  */
46cdff2642SJohn Johansen char *aa_split_fqname(char *fqname, char **ns_name)
47cdff2642SJohn Johansen {
48cdff2642SJohn Johansen 	char *name = strim(fqname);
49cdff2642SJohn Johansen 
50cdff2642SJohn Johansen 	*ns_name = NULL;
51cdff2642SJohn Johansen 	if (name[0] == ':') {
52cdff2642SJohn Johansen 		char *split = strchr(&name[1], ':');
5304ccd53fSJohn Johansen 		*ns_name = skip_spaces(&name[1]);
54cdff2642SJohn Johansen 		if (split) {
55cdff2642SJohn Johansen 			/* overwrite ':' with \0 */
562654bfbcSJohn Johansen 			*split++ = 0;
572654bfbcSJohn Johansen 			if (strncmp(split, "//", 2) == 0)
582654bfbcSJohn Johansen 				split += 2;
592654bfbcSJohn Johansen 			name = skip_spaces(split);
60cdff2642SJohn Johansen 		} else
61cdff2642SJohn Johansen 			/* a ns name without a following profile is allowed */
62cdff2642SJohn Johansen 			name = NULL;
63cdff2642SJohn Johansen 	}
64cdff2642SJohn Johansen 	if (name && *name == 0)
65cdff2642SJohn Johansen 		name = NULL;
66cdff2642SJohn Johansen 
67cdff2642SJohn Johansen 	return name;
68cdff2642SJohn Johansen }
69cdff2642SJohn Johansen 
70cdff2642SJohn Johansen /**
713b0aaf58SJohn Johansen  * skipn_spaces - Removes leading whitespace from @str.
723b0aaf58SJohn Johansen  * @str: The string to be stripped.
733b0aaf58SJohn Johansen  *
743b0aaf58SJohn Johansen  * Returns a pointer to the first non-whitespace character in @str.
753b0aaf58SJohn Johansen  * if all whitespace will return NULL
763b0aaf58SJohn Johansen  */
773b0aaf58SJohn Johansen 
78b91deb9dSJohn Johansen const char *skipn_spaces(const char *str, size_t n)
793b0aaf58SJohn Johansen {
803b0aaf58SJohn Johansen 	for (; n && isspace(*str); --n)
813b0aaf58SJohn Johansen 		++str;
823b0aaf58SJohn Johansen 	if (n)
833b0aaf58SJohn Johansen 		return (char *)str;
843b0aaf58SJohn Johansen 	return NULL;
853b0aaf58SJohn Johansen }
863b0aaf58SJohn Johansen 
873b0aaf58SJohn Johansen const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
883b0aaf58SJohn Johansen 			     size_t *ns_len)
893b0aaf58SJohn Johansen {
903b0aaf58SJohn Johansen 	const char *end = fqname + n;
913b0aaf58SJohn Johansen 	const char *name = skipn_spaces(fqname, n);
923b0aaf58SJohn Johansen 
933b0aaf58SJohn Johansen 	if (!name)
943b0aaf58SJohn Johansen 		return NULL;
953b0aaf58SJohn Johansen 	*ns_name = NULL;
963b0aaf58SJohn Johansen 	*ns_len = 0;
973b0aaf58SJohn Johansen 	if (name[0] == ':') {
983b0aaf58SJohn Johansen 		char *split = strnchr(&name[1], end - &name[1], ':');
993b0aaf58SJohn Johansen 		*ns_name = skipn_spaces(&name[1], end - &name[1]);
1003b0aaf58SJohn Johansen 		if (!*ns_name)
1013b0aaf58SJohn Johansen 			return NULL;
1023b0aaf58SJohn Johansen 		if (split) {
1033b0aaf58SJohn Johansen 			*ns_len = split - *ns_name;
1043b0aaf58SJohn Johansen 			if (*ns_len == 0)
1053b0aaf58SJohn Johansen 				*ns_name = NULL;
1063b0aaf58SJohn Johansen 			split++;
1073b0aaf58SJohn Johansen 			if (end - split > 1 && strncmp(split, "//", 2) == 0)
1083b0aaf58SJohn Johansen 				split += 2;
1093b0aaf58SJohn Johansen 			name = skipn_spaces(split, end - split);
1103b0aaf58SJohn Johansen 		} else {
1113b0aaf58SJohn Johansen 			/* a ns name without a following profile is allowed */
1123b0aaf58SJohn Johansen 			name = NULL;
1133b0aaf58SJohn Johansen 			*ns_len = end - *ns_name;
1143b0aaf58SJohn Johansen 		}
1153b0aaf58SJohn Johansen 	}
1163b0aaf58SJohn Johansen 	if (name && *name == 0)
1173b0aaf58SJohn Johansen 		name = NULL;
1183b0aaf58SJohn Johansen 
1193b0aaf58SJohn Johansen 	return name;
1203b0aaf58SJohn Johansen }
1213b0aaf58SJohn Johansen 
1223b0aaf58SJohn Johansen /**
123cdff2642SJohn Johansen  * aa_info_message - log a none profile related status message
124cdff2642SJohn Johansen  * @str: message to log
125cdff2642SJohn Johansen  */
126cdff2642SJohn Johansen void aa_info_message(const char *str)
127cdff2642SJohn Johansen {
128cdff2642SJohn Johansen 	if (audit_enabled) {
129ef88a7acSJohn Johansen 		DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
130ef88a7acSJohn Johansen 
131ef88a7acSJohn Johansen 		aad(&sa)->info = str;
132cdff2642SJohn Johansen 		aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
133cdff2642SJohn Johansen 	}
134cdff2642SJohn Johansen 	printk(KERN_INFO "AppArmor: %s\n", str);
135cdff2642SJohn Johansen }
136cdff2642SJohn Johansen 
137a1bd627bSJohn Johansen __counted char *aa_str_alloc(int size, gfp_t gfp)
138a1bd627bSJohn Johansen {
139a1bd627bSJohn Johansen 	struct counted_str *str;
140a1bd627bSJohn Johansen 
141a1bd627bSJohn Johansen 	str = kmalloc(sizeof(struct counted_str) + size, gfp);
142a1bd627bSJohn Johansen 	if (!str)
143a1bd627bSJohn Johansen 		return NULL;
144a1bd627bSJohn Johansen 
145a1bd627bSJohn Johansen 	kref_init(&str->count);
146a1bd627bSJohn Johansen 	return str->name;
147a1bd627bSJohn Johansen }
148a1bd627bSJohn Johansen 
149a1bd627bSJohn Johansen void aa_str_kref(struct kref *kref)
150a1bd627bSJohn Johansen {
151a1bd627bSJohn Johansen 	kfree(container_of(kref, struct counted_str, count));
152a1bd627bSJohn Johansen }
153a1bd627bSJohn Johansen 
154a1bd627bSJohn Johansen 
155e53cfe6cSJohn Johansen const char aa_file_perm_chrs[] = "xwracd         km l     ";
156e53cfe6cSJohn Johansen const char *aa_file_perm_names[] = {
157e53cfe6cSJohn Johansen 	"exec",
158e53cfe6cSJohn Johansen 	"write",
159e53cfe6cSJohn Johansen 	"read",
160e53cfe6cSJohn Johansen 	"append",
161e53cfe6cSJohn Johansen 
162e53cfe6cSJohn Johansen 	"create",
163e53cfe6cSJohn Johansen 	"delete",
164e53cfe6cSJohn Johansen 	"open",
165e53cfe6cSJohn Johansen 	"rename",
166e53cfe6cSJohn Johansen 
167e53cfe6cSJohn Johansen 	"setattr",
168e53cfe6cSJohn Johansen 	"getattr",
169e53cfe6cSJohn Johansen 	"setcred",
170e53cfe6cSJohn Johansen 	"getcred",
171e53cfe6cSJohn Johansen 
172e53cfe6cSJohn Johansen 	"chmod",
173e53cfe6cSJohn Johansen 	"chown",
174e53cfe6cSJohn Johansen 	"chgrp",
175e53cfe6cSJohn Johansen 	"lock",
176e53cfe6cSJohn Johansen 
177e53cfe6cSJohn Johansen 	"mmap",
178e53cfe6cSJohn Johansen 	"mprot",
179e53cfe6cSJohn Johansen 	"link",
180e53cfe6cSJohn Johansen 	"snapshot",
181e53cfe6cSJohn Johansen 
182e53cfe6cSJohn Johansen 	"unknown",
183e53cfe6cSJohn Johansen 	"unknown",
184e53cfe6cSJohn Johansen 	"unknown",
185e53cfe6cSJohn Johansen 	"unknown",
186e53cfe6cSJohn Johansen 
187e53cfe6cSJohn Johansen 	"unknown",
188e53cfe6cSJohn Johansen 	"unknown",
189e53cfe6cSJohn Johansen 	"unknown",
190e53cfe6cSJohn Johansen 	"unknown",
191e53cfe6cSJohn Johansen 
192e53cfe6cSJohn Johansen 	"stack",
193e53cfe6cSJohn Johansen 	"change_onexec",
194e53cfe6cSJohn Johansen 	"change_profile",
195e53cfe6cSJohn Johansen 	"change_hat",
196e53cfe6cSJohn Johansen };
197e53cfe6cSJohn Johansen 
198e53cfe6cSJohn Johansen /**
199e53cfe6cSJohn Johansen  * aa_perm_mask_to_str - convert a perm mask to its short string
200e53cfe6cSJohn Johansen  * @str: character buffer to store string in (at least 10 characters)
201*7f3ebcf2STyler Hicks  * @str_size: size of the @str buffer
202*7f3ebcf2STyler Hicks  * @chrs: NUL-terminated character buffer of permission characters
203e53cfe6cSJohn Johansen  * @mask: permission mask to convert
204e53cfe6cSJohn Johansen  */
205*7f3ebcf2STyler Hicks void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
206e53cfe6cSJohn Johansen {
207e53cfe6cSJohn Johansen 	unsigned int i, perm = 1;
208*7f3ebcf2STyler Hicks 	size_t num_chrs = strlen(chrs);
209e53cfe6cSJohn Johansen 
210*7f3ebcf2STyler Hicks 	for (i = 0; i < num_chrs; perm <<= 1, i++) {
211*7f3ebcf2STyler Hicks 		if (mask & perm) {
212*7f3ebcf2STyler Hicks 			/* Ensure that one byte is left for NUL-termination */
213*7f3ebcf2STyler Hicks 			if (WARN_ON_ONCE(str_size <= 1))
214*7f3ebcf2STyler Hicks 				break;
215*7f3ebcf2STyler Hicks 
216e53cfe6cSJohn Johansen 			*str++ = chrs[i];
217*7f3ebcf2STyler Hicks 			str_size--;
218*7f3ebcf2STyler Hicks 		}
219e53cfe6cSJohn Johansen 	}
220e53cfe6cSJohn Johansen 	*str = '\0';
221e53cfe6cSJohn Johansen }
222e53cfe6cSJohn Johansen 
22356974a6fSJohn Johansen void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
22456974a6fSJohn Johansen 			 u32 mask)
225aa9aeea8SJohn Johansen {
226aa9aeea8SJohn Johansen 	const char *fmt = "%s";
227aa9aeea8SJohn Johansen 	unsigned int i, perm = 1;
228aa9aeea8SJohn Johansen 	bool prev = false;
229aa9aeea8SJohn Johansen 
230aa9aeea8SJohn Johansen 	for (i = 0; i < 32; perm <<= 1, i++) {
231aa9aeea8SJohn Johansen 		if (mask & perm) {
232aa9aeea8SJohn Johansen 			audit_log_format(ab, fmt, names[i]);
233aa9aeea8SJohn Johansen 			if (!prev) {
234aa9aeea8SJohn Johansen 				prev = true;
235aa9aeea8SJohn Johansen 				fmt = " %s";
236aa9aeea8SJohn Johansen 			}
237aa9aeea8SJohn Johansen 		}
238aa9aeea8SJohn Johansen 	}
239aa9aeea8SJohn Johansen }
240aa9aeea8SJohn Johansen 
241aa9aeea8SJohn Johansen void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
24256974a6fSJohn Johansen 			u32 chrsmask, const char * const *names, u32 namesmask)
243aa9aeea8SJohn Johansen {
244aa9aeea8SJohn Johansen 	char str[33];
245aa9aeea8SJohn Johansen 
246aa9aeea8SJohn Johansen 	audit_log_format(ab, "\"");
247aa9aeea8SJohn Johansen 	if ((mask & chrsmask) && chrs) {
248*7f3ebcf2STyler Hicks 		aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
249aa9aeea8SJohn Johansen 		mask &= ~chrsmask;
250aa9aeea8SJohn Johansen 		audit_log_format(ab, "%s", str);
251aa9aeea8SJohn Johansen 		if (mask & namesmask)
252aa9aeea8SJohn Johansen 			audit_log_format(ab, " ");
253aa9aeea8SJohn Johansen 	}
254aa9aeea8SJohn Johansen 	if ((mask & namesmask) && names)
255aa9aeea8SJohn Johansen 		aa_audit_perm_names(ab, names, mask & namesmask);
256aa9aeea8SJohn Johansen 	audit_log_format(ab, "\"");
257aa9aeea8SJohn Johansen }
258aa9aeea8SJohn Johansen 
259aa9aeea8SJohn Johansen /**
260637f688dSJohn Johansen  * aa_audit_perms_cb - generic callback fn for auditing perms
261637f688dSJohn Johansen  * @ab: audit buffer (NOT NULL)
262637f688dSJohn Johansen  * @va: audit struct to audit values of (NOT NULL)
263637f688dSJohn Johansen  */
264637f688dSJohn Johansen static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
265637f688dSJohn Johansen {
266637f688dSJohn Johansen 	struct common_audit_data *sa = va;
267637f688dSJohn Johansen 
268637f688dSJohn Johansen 	if (aad(sa)->request) {
269637f688dSJohn Johansen 		audit_log_format(ab, " requested_mask=");
270637f688dSJohn Johansen 		aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
271637f688dSJohn Johansen 				   PERMS_CHRS_MASK, aa_file_perm_names,
272637f688dSJohn Johansen 				   PERMS_NAMES_MASK);
273637f688dSJohn Johansen 	}
274637f688dSJohn Johansen 	if (aad(sa)->denied) {
275637f688dSJohn Johansen 		audit_log_format(ab, "denied_mask=");
276637f688dSJohn Johansen 		aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
277637f688dSJohn Johansen 				   PERMS_CHRS_MASK, aa_file_perm_names,
278637f688dSJohn Johansen 				   PERMS_NAMES_MASK);
279637f688dSJohn Johansen 	}
280637f688dSJohn Johansen 	audit_log_format(ab, " peer=");
281637f688dSJohn Johansen 	aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
282637f688dSJohn Johansen 				      FLAGS_NONE, GFP_ATOMIC);
283637f688dSJohn Johansen }
284637f688dSJohn Johansen 
285637f688dSJohn Johansen /**
286aa9aeea8SJohn Johansen  * aa_apply_modes_to_perms - apply namespace and profile flags to perms
287aa9aeea8SJohn Johansen  * @profile: that perms where computed from
288aa9aeea8SJohn Johansen  * @perms: perms to apply mode modifiers to
289aa9aeea8SJohn Johansen  *
290aa9aeea8SJohn Johansen  * TODO: split into profile and ns based flags for when accumulating perms
291aa9aeea8SJohn Johansen  */
292aa9aeea8SJohn Johansen void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
293aa9aeea8SJohn Johansen {
294aa9aeea8SJohn Johansen 	switch (AUDIT_MODE(profile)) {
295aa9aeea8SJohn Johansen 	case AUDIT_ALL:
296aa9aeea8SJohn Johansen 		perms->audit = ALL_PERMS_MASK;
297aa9aeea8SJohn Johansen 		/* fall through */
298aa9aeea8SJohn Johansen 	case AUDIT_NOQUIET:
299aa9aeea8SJohn Johansen 		perms->quiet = 0;
300aa9aeea8SJohn Johansen 		break;
301aa9aeea8SJohn Johansen 	case AUDIT_QUIET:
302aa9aeea8SJohn Johansen 		perms->audit = 0;
303aa9aeea8SJohn Johansen 		/* fall through */
304aa9aeea8SJohn Johansen 	case AUDIT_QUIET_DENIED:
305aa9aeea8SJohn Johansen 		perms->quiet = ALL_PERMS_MASK;
306aa9aeea8SJohn Johansen 		break;
307aa9aeea8SJohn Johansen 	}
308aa9aeea8SJohn Johansen 
309aa9aeea8SJohn Johansen 	if (KILL_MODE(profile))
310aa9aeea8SJohn Johansen 		perms->kill = ALL_PERMS_MASK;
311aa9aeea8SJohn Johansen 	else if (COMPLAIN_MODE(profile))
312aa9aeea8SJohn Johansen 		perms->complain = ALL_PERMS_MASK;
313aa9aeea8SJohn Johansen /*
314aa9aeea8SJohn Johansen  *  TODO:
315aa9aeea8SJohn Johansen  *	else if (PROMPT_MODE(profile))
316aa9aeea8SJohn Johansen  *		perms->prompt = ALL_PERMS_MASK;
317aa9aeea8SJohn Johansen  */
318aa9aeea8SJohn Johansen }
319aa9aeea8SJohn Johansen 
320aa9aeea8SJohn Johansen static u32 map_other(u32 x)
321aa9aeea8SJohn Johansen {
322aa9aeea8SJohn Johansen 	return ((x & 0x3) << 8) |	/* SETATTR/GETATTR */
323aa9aeea8SJohn Johansen 		((x & 0x1c) << 18) |	/* ACCEPT/BIND/LISTEN */
324aa9aeea8SJohn Johansen 		((x & 0x60) << 19);	/* SETOPT/GETOPT */
325aa9aeea8SJohn Johansen }
326aa9aeea8SJohn Johansen 
327aa9aeea8SJohn Johansen void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
328aa9aeea8SJohn Johansen 		      struct aa_perms *perms)
329aa9aeea8SJohn Johansen {
3307bba39aeSArnd Bergmann 	*perms = (struct aa_perms) {
3317bba39aeSArnd Bergmann 		.allow = dfa_user_allow(dfa, state),
3327bba39aeSArnd Bergmann 		.audit = dfa_user_audit(dfa, state),
3337bba39aeSArnd Bergmann 		.quiet = dfa_user_quiet(dfa, state),
3347bba39aeSArnd Bergmann 	};
335aa9aeea8SJohn Johansen 
336aa9aeea8SJohn Johansen 	/* for v5 perm mapping in the policydb, the other set is used
337aa9aeea8SJohn Johansen 	 * to extend the general perm set
338aa9aeea8SJohn Johansen 	 */
339aa9aeea8SJohn Johansen 	perms->allow |= map_other(dfa_other_allow(dfa, state));
340aa9aeea8SJohn Johansen 	perms->audit |= map_other(dfa_other_audit(dfa, state));
341aa9aeea8SJohn Johansen 	perms->quiet |= map_other(dfa_other_quiet(dfa, state));
342aa9aeea8SJohn Johansen //	perms->xindex = dfa_user_xindex(dfa, state);
343aa9aeea8SJohn Johansen }
344aa9aeea8SJohn Johansen 
345cdff2642SJohn Johansen /**
346637f688dSJohn Johansen  * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
347637f688dSJohn Johansen  * @accum - perms struct to accumulate into
348637f688dSJohn Johansen  * @addend - perms struct to add to @accum
349637f688dSJohn Johansen  */
350637f688dSJohn Johansen void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
351637f688dSJohn Johansen {
352637f688dSJohn Johansen 	accum->deny |= addend->deny;
353637f688dSJohn Johansen 	accum->allow &= addend->allow & ~addend->deny;
354637f688dSJohn Johansen 	accum->audit |= addend->audit & addend->allow;
355637f688dSJohn Johansen 	accum->quiet &= addend->quiet & ~addend->allow;
356637f688dSJohn Johansen 	accum->kill |= addend->kill & ~addend->allow;
357637f688dSJohn Johansen 	accum->stop |= addend->stop & ~addend->allow;
358637f688dSJohn Johansen 	accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
359637f688dSJohn Johansen 	accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
360637f688dSJohn Johansen 	accum->hide &= addend->hide & ~addend->allow;
361637f688dSJohn Johansen 	accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
362637f688dSJohn Johansen }
363637f688dSJohn Johansen 
364637f688dSJohn Johansen /**
365637f688dSJohn Johansen  * aa_perms_accum - accumulate perms, masking off overlapping perms
366637f688dSJohn Johansen  * @accum - perms struct to accumulate into
367637f688dSJohn Johansen  * @addend - perms struct to add to @accum
368637f688dSJohn Johansen  */
369637f688dSJohn Johansen void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
370637f688dSJohn Johansen {
371637f688dSJohn Johansen 	accum->deny |= addend->deny;
372637f688dSJohn Johansen 	accum->allow &= addend->allow & ~accum->deny;
373637f688dSJohn Johansen 	accum->audit |= addend->audit & accum->allow;
374637f688dSJohn Johansen 	accum->quiet &= addend->quiet & ~accum->allow;
375637f688dSJohn Johansen 	accum->kill |= addend->kill & ~accum->allow;
376637f688dSJohn Johansen 	accum->stop |= addend->stop & ~accum->allow;
377637f688dSJohn Johansen 	accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
378637f688dSJohn Johansen 	accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
379637f688dSJohn Johansen 	accum->hide &= addend->hide & ~accum->allow;
380637f688dSJohn Johansen 	accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
381637f688dSJohn Johansen }
382637f688dSJohn Johansen 
383637f688dSJohn Johansen void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
384637f688dSJohn Johansen 			    int type, u32 request, struct aa_perms *perms)
385637f688dSJohn Johansen {
386637f688dSJohn Johansen 	/* TODO: doesn't yet handle extended types */
387637f688dSJohn Johansen 	unsigned int state;
388637f688dSJohn Johansen 
389637f688dSJohn Johansen 	state = aa_dfa_next(profile->policy.dfa,
390637f688dSJohn Johansen 			    profile->policy.start[AA_CLASS_LABEL],
391637f688dSJohn Johansen 			    type);
392637f688dSJohn Johansen 	aa_label_match(profile, label, state, false, request, perms);
393637f688dSJohn Johansen }
394637f688dSJohn Johansen 
395637f688dSJohn Johansen 
396637f688dSJohn Johansen /* currently unused */
397637f688dSJohn Johansen int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
398637f688dSJohn Johansen 			  u32 request, int type, u32 *deny,
399637f688dSJohn Johansen 			  struct common_audit_data *sa)
400637f688dSJohn Johansen {
401637f688dSJohn Johansen 	struct aa_perms perms;
402637f688dSJohn Johansen 
403637f688dSJohn Johansen 	aad(sa)->label = &profile->label;
404637f688dSJohn Johansen 	aad(sa)->peer = &target->label;
405637f688dSJohn Johansen 	aad(sa)->request = request;
406637f688dSJohn Johansen 
407637f688dSJohn Johansen 	aa_profile_match_label(profile, &target->label, type, request, &perms);
408637f688dSJohn Johansen 	aa_apply_modes_to_perms(profile, &perms);
409637f688dSJohn Johansen 	*deny |= request & perms.deny;
410637f688dSJohn Johansen 	return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
411637f688dSJohn Johansen }
412637f688dSJohn Johansen 
413637f688dSJohn Johansen /**
414637f688dSJohn Johansen  * aa_check_perms - do audit mode selection based on perms set
415637f688dSJohn Johansen  * @profile: profile being checked
416637f688dSJohn Johansen  * @perms: perms computed for the request
417637f688dSJohn Johansen  * @request: requested perms
418637f688dSJohn Johansen  * @deny: Returns: explicit deny set
419637f688dSJohn Johansen  * @sa: initialized audit structure (MAY BE NULL if not auditing)
42069ad4a44SZygmunt Krynicki  * @cb: callback fn for type specific fields (MAY BE NULL)
421637f688dSJohn Johansen  *
422637f688dSJohn Johansen  * Returns: 0 if permission else error code
423637f688dSJohn Johansen  *
424637f688dSJohn Johansen  * Note: profile audit modes need to be set before calling by setting the
425637f688dSJohn Johansen  *       perm masks appropriately.
426637f688dSJohn Johansen  *
427637f688dSJohn Johansen  *       If not auditing then complain mode is not enabled and the
428637f688dSJohn Johansen  *       error code will indicate whether there was an explicit deny
429637f688dSJohn Johansen  *	 with a positive value.
430637f688dSJohn Johansen  */
431637f688dSJohn Johansen int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
432637f688dSJohn Johansen 		   u32 request, struct common_audit_data *sa,
433637f688dSJohn Johansen 		   void (*cb)(struct audit_buffer *, void *))
434637f688dSJohn Johansen {
435637f688dSJohn Johansen 	int type, error;
436637f688dSJohn Johansen 	u32 denied = request & (~perms->allow | perms->deny);
437637f688dSJohn Johansen 
438637f688dSJohn Johansen 	if (likely(!denied)) {
439637f688dSJohn Johansen 		/* mask off perms that are not being force audited */
440637f688dSJohn Johansen 		request &= perms->audit;
441637f688dSJohn Johansen 		if (!request || !sa)
442637f688dSJohn Johansen 			return 0;
443637f688dSJohn Johansen 
444637f688dSJohn Johansen 		type = AUDIT_APPARMOR_AUDIT;
445637f688dSJohn Johansen 		error = 0;
446637f688dSJohn Johansen 	} else {
447637f688dSJohn Johansen 		error = -EACCES;
448637f688dSJohn Johansen 
449637f688dSJohn Johansen 		if (denied & perms->kill)
450637f688dSJohn Johansen 			type = AUDIT_APPARMOR_KILL;
451637f688dSJohn Johansen 		else if (denied == (denied & perms->complain))
452637f688dSJohn Johansen 			type = AUDIT_APPARMOR_ALLOWED;
453637f688dSJohn Johansen 		else
454637f688dSJohn Johansen 			type = AUDIT_APPARMOR_DENIED;
455637f688dSJohn Johansen 
456637f688dSJohn Johansen 		if (denied == (denied & perms->hide))
457637f688dSJohn Johansen 			error = -ENOENT;
458637f688dSJohn Johansen 
459637f688dSJohn Johansen 		denied &= ~perms->quiet;
460637f688dSJohn Johansen 		if (!sa || !denied)
461637f688dSJohn Johansen 			return error;
462637f688dSJohn Johansen 	}
463637f688dSJohn Johansen 
464637f688dSJohn Johansen 	if (sa) {
465637f688dSJohn Johansen 		aad(sa)->label = &profile->label;
466637f688dSJohn Johansen 		aad(sa)->request = request;
467637f688dSJohn Johansen 		aad(sa)->denied = denied;
468637f688dSJohn Johansen 		aad(sa)->error = error;
469637f688dSJohn Johansen 		aa_audit_msg(type, sa, cb);
470637f688dSJohn Johansen 	}
471637f688dSJohn Johansen 
472637f688dSJohn Johansen 	if (type == AUDIT_APPARMOR_ALLOWED)
473637f688dSJohn Johansen 		error = 0;
474637f688dSJohn Johansen 
475637f688dSJohn Johansen 	return error;
476637f688dSJohn Johansen }
477637f688dSJohn Johansen 
478637f688dSJohn Johansen 
479637f688dSJohn Johansen /**
480fe6bb31fSJohn Johansen  * aa_policy_init - initialize a policy structure
481fe6bb31fSJohn Johansen  * @policy: policy to initialize  (NOT NULL)
482fe6bb31fSJohn Johansen  * @prefix: prefix name if any is required.  (MAYBE NULL)
483fe6bb31fSJohn Johansen  * @name: name of the policy, init will make a copy of it  (NOT NULL)
484a1bd627bSJohn Johansen  * @gfp: allocation mode
485fe6bb31fSJohn Johansen  *
486fe6bb31fSJohn Johansen  * Note: this fn creates a copy of strings passed in
487fe6bb31fSJohn Johansen  *
488fe6bb31fSJohn Johansen  * Returns: true if policy init successful
489fe6bb31fSJohn Johansen  */
490fe6bb31fSJohn Johansen bool aa_policy_init(struct aa_policy *policy, const char *prefix,
491d102d895SJohn Johansen 		    const char *name, gfp_t gfp)
492fe6bb31fSJohn Johansen {
493a1bd627bSJohn Johansen 	char *hname;
494a1bd627bSJohn Johansen 
495fe6bb31fSJohn Johansen 	/* freed by policy_free */
496fe6bb31fSJohn Johansen 	if (prefix) {
497a1bd627bSJohn Johansen 		hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
498a1bd627bSJohn Johansen 		if (hname)
499a1bd627bSJohn Johansen 			sprintf(hname, "%s//%s", prefix, name);
500a1bd627bSJohn Johansen 	} else {
501a1bd627bSJohn Johansen 		hname = aa_str_alloc(strlen(name) + 1, gfp);
502a1bd627bSJohn Johansen 		if (hname)
503a1bd627bSJohn Johansen 			strcpy(hname, name);
504a1bd627bSJohn Johansen 	}
505a1bd627bSJohn Johansen 	if (!hname)
506b9c42ac7Skbuild test robot 		return false;
507a1bd627bSJohn Johansen 	policy->hname = hname;
508fe6bb31fSJohn Johansen 	/* base.name is a substring of fqname */
509d102d895SJohn Johansen 	policy->name = basename(policy->hname);
510fe6bb31fSJohn Johansen 	INIT_LIST_HEAD(&policy->list);
511fe6bb31fSJohn Johansen 	INIT_LIST_HEAD(&policy->profiles);
512fe6bb31fSJohn Johansen 
513b9c42ac7Skbuild test robot 	return true;
514fe6bb31fSJohn Johansen }
515fe6bb31fSJohn Johansen 
516fe6bb31fSJohn Johansen /**
517fe6bb31fSJohn Johansen  * aa_policy_destroy - free the elements referenced by @policy
518fe6bb31fSJohn Johansen  * @policy: policy that is to have its elements freed  (NOT NULL)
519fe6bb31fSJohn Johansen  */
520fe6bb31fSJohn Johansen void aa_policy_destroy(struct aa_policy *policy)
521fe6bb31fSJohn Johansen {
5225fd1b95fSJohn Johansen 	AA_BUG(on_list_rcu(&policy->profiles));
5235fd1b95fSJohn Johansen 	AA_BUG(on_list_rcu(&policy->list));
524fe6bb31fSJohn Johansen 
525fe6bb31fSJohn Johansen 	/* don't free name as its a subset of hname */
526a1bd627bSJohn Johansen 	aa_put_str(policy->hname);
527fe6bb31fSJohn Johansen }
528