Linux Audio

Check our new training course

Loading...
v6.13.7
  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
 23struct aa_perms nullperms;
 24struct 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 */
 32void 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 * skipn_spaces - Removes leading whitespace from @str.
 50 * @str: The string to be stripped.
 51 * @n: length of str to parse, will stop at \0 if encountered before n
 52 *
 53 * Returns a pointer to the first non-whitespace character in @str.
 54 * if all whitespace will return NULL
 55 */
 56
 57const char *skipn_spaces(const char *str, size_t n)
 58{
 59	for (; n && isspace(*str); --n)
 60		++str;
 61	if (n)
 62		return (char *)str;
 63	return NULL;
 64}
 65
 66const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
 67			     size_t *ns_len)
 68{
 69	const char *end = fqname + n;
 70	const char *name = skipn_spaces(fqname, n);
 71
 72	*ns_name = NULL;
 73	*ns_len = 0;
 74
 75	if (!name)
 76		return NULL;
 77
 
 78	if (name[0] == ':') {
 79		char *split = strnchr(&name[1], end - &name[1], ':');
 80		*ns_name = skipn_spaces(&name[1], end - &name[1]);
 81		if (!*ns_name)
 82			return NULL;
 83		if (split) {
 84			*ns_len = split - *ns_name;
 85			if (*ns_len == 0)
 86				*ns_name = NULL;
 87			split++;
 88			if (end - split > 1 && strncmp(split, "//", 2) == 0)
 89				split += 2;
 90			name = skipn_spaces(split, end - split);
 91		} else {
 92			/* a ns name without a following profile is allowed */
 93			name = NULL;
 94			*ns_len = end - *ns_name;
 95		}
 96	}
 97	if (name && *name == 0)
 98		name = NULL;
 99
100	return name;
101}
102
103/**
104 * aa_info_message - log a none profile related status message
105 * @str: message to log
106 */
107void aa_info_message(const char *str)
108{
109	if (audit_enabled) {
110		DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL);
111
112		ad.info = str;
113		aa_audit_msg(AUDIT_APPARMOR_STATUS, &ad, NULL);
114	}
115	printk(KERN_INFO "AppArmor: %s\n", str);
116}
117
118__counted char *aa_str_alloc(int size, gfp_t gfp)
119{
120	struct counted_str *str;
121
122	str = kmalloc(struct_size(str, name, size), gfp);
123	if (!str)
124		return NULL;
125
126	kref_init(&str->count);
127	return str->name;
128}
129
130void aa_str_kref(struct kref *kref)
131{
132	kfree(container_of(kref, struct counted_str, count));
133}
134
135
136const char aa_file_perm_chrs[] = "xwracd         km l     ";
137const char *aa_file_perm_names[] = {
138	"exec",
139	"write",
140	"read",
141	"append",
142
143	"create",
144	"delete",
145	"open",
146	"rename",
147
148	"setattr",
149	"getattr",
150	"setcred",
151	"getcred",
152
153	"chmod",
154	"chown",
155	"chgrp",
156	"lock",
157
158	"mmap",
159	"mprot",
160	"link",
161	"snapshot",
162
163	"unknown",
164	"unknown",
165	"unknown",
166	"unknown",
167
168	"unknown",
169	"unknown",
170	"unknown",
171	"unknown",
172
173	"stack",
174	"change_onexec",
175	"change_profile",
176	"change_hat",
177};
178
179/**
180 * aa_perm_mask_to_str - convert a perm mask to its short string
181 * @str: character buffer to store string in (at least 10 characters)
182 * @str_size: size of the @str buffer
183 * @chrs: NUL-terminated character buffer of permission characters
184 * @mask: permission mask to convert
185 */
186void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
187{
188	unsigned int i, perm = 1;
189	size_t num_chrs = strlen(chrs);
190
191	for (i = 0; i < num_chrs; perm <<= 1, i++) {
192		if (mask & perm) {
193			/* Ensure that one byte is left for NUL-termination */
194			if (WARN_ON_ONCE(str_size <= 1))
195				break;
196
 
 
197			*str++ = chrs[i];
198			str_size--;
199		}
200	}
201	*str = '\0';
202}
203
204void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
205			 u32 mask)
206{
207	const char *fmt = "%s";
208	unsigned int i, perm = 1;
209	bool prev = false;
210
211	for (i = 0; i < 32; perm <<= 1, i++) {
212		if (mask & perm) {
213			audit_log_format(ab, fmt, names[i]);
214			if (!prev) {
215				prev = true;
216				fmt = " %s";
217			}
218		}
219	}
220}
221
222void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
223			u32 chrsmask, const char * const *names, u32 namesmask)
224{
225	char str[33];
226
227	audit_log_format(ab, "\"");
228	if ((mask & chrsmask) && chrs) {
229		aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
230		mask &= ~chrsmask;
231		audit_log_format(ab, "%s", str);
232		if (mask & namesmask)
233			audit_log_format(ab, " ");
234	}
235	if ((mask & namesmask) && names)
236		aa_audit_perm_names(ab, names, mask & namesmask);
237	audit_log_format(ab, "\"");
238}
239
240/**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241 * aa_apply_modes_to_perms - apply namespace and profile flags to perms
242 * @profile: that perms where computed from
243 * @perms: perms to apply mode modifiers to
244 *
245 * TODO: split into profile and ns based flags for when accumulating perms
246 */
247void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
248{
249	switch (AUDIT_MODE(profile)) {
250	case AUDIT_ALL:
251		perms->audit = ALL_PERMS_MASK;
252		fallthrough;
253	case AUDIT_NOQUIET:
254		perms->quiet = 0;
255		break;
256	case AUDIT_QUIET:
257		perms->audit = 0;
258		fallthrough;
259	case AUDIT_QUIET_DENIED:
260		perms->quiet = ALL_PERMS_MASK;
261		break;
262	}
263
264	if (KILL_MODE(profile))
265		perms->kill = ALL_PERMS_MASK;
266	else if (COMPLAIN_MODE(profile))
267		perms->complain = ALL_PERMS_MASK;
268	else if (USER_MODE(profile))
269		perms->prompt = ALL_PERMS_MASK;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
270}
271
272void aa_profile_match_label(struct aa_profile *profile,
273			    struct aa_ruleset *rules,
274			    struct aa_label *label,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
275			    int type, u32 request, struct aa_perms *perms)
276{
277	/* TODO: doesn't yet handle extended types */
278	aa_state_t state;
279
280	state = aa_dfa_next(rules->policy->dfa,
281			    rules->policy->start[AA_CLASS_LABEL],
282			    type);
283	aa_label_match(profile, rules, label, state, false, request, perms);
284}
285
286
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287/**
288 * aa_check_perms - do audit mode selection based on perms set
289 * @profile: profile being checked
290 * @perms: perms computed for the request
291 * @request: requested perms
292 * @ad: initialized audit structure (MAY BE NULL if not auditing)
293 * @cb: callback fn for type specific fields (MAY BE NULL)
 
294 *
295 * Returns: 0 if permission else error code
296 *
297 * Note: profile audit modes need to be set before calling by setting the
298 *       perm masks appropriately.
299 *
300 *       If not auditing then complain mode is not enabled and the
301 *       error code will indicate whether there was an explicit deny
302 *	 with a positive value.
303 */
304int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
305		   u32 request, struct apparmor_audit_data *ad,
306		   void (*cb)(struct audit_buffer *, void *))
307{
308	int type, error;
309	u32 denied = request & (~perms->allow | perms->deny);
310
311	if (likely(!denied)) {
312		/* mask off perms that are not being force audited */
313		request &= perms->audit;
314		if (!request || !ad)
315			return 0;
316
317		type = AUDIT_APPARMOR_AUDIT;
318		error = 0;
319	} else {
320		error = -EACCES;
321
322		if (denied & perms->kill)
323			type = AUDIT_APPARMOR_KILL;
324		else if (denied == (denied & perms->complain))
325			type = AUDIT_APPARMOR_ALLOWED;
326		else
327			type = AUDIT_APPARMOR_DENIED;
328
329		if (denied == (denied & perms->hide))
330			error = -ENOENT;
331
332		denied &= ~perms->quiet;
333		if (!ad || !denied)
334			return error;
335	}
336
337	if (ad) {
338		ad->subj_label = &profile->label;
339		ad->request = request;
340		ad->denied = denied;
341		ad->error = error;
342		aa_audit_msg(type, ad, cb);
343	}
344
345	if (type == AUDIT_APPARMOR_ALLOWED)
346		error = 0;
347
348	return error;
349}
350
351
352/**
353 * aa_policy_init - initialize a policy structure
354 * @policy: policy to initialize  (NOT NULL)
355 * @prefix: prefix name if any is required.  (MAYBE NULL)
356 * @name: name of the policy, init will make a copy of it  (NOT NULL)
357 * @gfp: allocation mode
358 *
359 * Note: this fn creates a copy of strings passed in
360 *
361 * Returns: true if policy init successful
362 */
363bool aa_policy_init(struct aa_policy *policy, const char *prefix,
364		    const char *name, gfp_t gfp)
365{
366	char *hname;
367
368	/* freed by policy_free */
369	if (prefix) {
370		hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
371		if (hname)
372			sprintf(hname, "%s//%s", prefix, name);
373	} else {
374		hname = aa_str_alloc(strlen(name) + 1, gfp);
375		if (hname)
376			strcpy(hname, name);
377	}
378	if (!hname)
379		return false;
380	policy->hname = hname;
381	/* base.name is a substring of fqname */
382	policy->name = basename(policy->hname);
383	INIT_LIST_HEAD(&policy->list);
384	INIT_LIST_HEAD(&policy->profiles);
385
386	return true;
387}
388
389/**
390 * aa_policy_destroy - free the elements referenced by @policy
391 * @policy: policy that is to have its elements freed  (NOT NULL)
392 */
393void aa_policy_destroy(struct aa_policy *policy)
394{
395	AA_BUG(on_list_rcu(&policy->profiles));
396	AA_BUG(on_list_rcu(&policy->list));
397
398	/* don't free name as its a subset of hname */
399	aa_put_str(policy->hname);
400}
v4.17
 
  1/*
  2 * AppArmor security module
  3 *
  4 * This file contains basic common functions used in AppArmor
  5 *
  6 * Copyright (C) 1998-2008 Novell/SUSE
  7 * Copyright 2009-2010 Canonical Ltd.
  8 *
  9 * This program is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU General Public License as
 11 * published by the Free Software Foundation, version 2 of the
 12 * License.
 13 */
 14
 15#include <linux/ctype.h>
 16#include <linux/mm.h>
 17#include <linux/slab.h>
 18#include <linux/string.h>
 19#include <linux/vmalloc.h>
 20
 21#include "include/audit.h"
 22#include "include/apparmor.h"
 23#include "include/lib.h"
 24#include "include/perms.h"
 25#include "include/policy.h"
 26
 27struct aa_perms nullperms;
 28struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
 29			     .quiet = ALL_PERMS_MASK,
 30			     .hide = ALL_PERMS_MASK };
 31
 32/**
 33 * aa_split_fqname - split a fqname into a profile and namespace name
 34 * @fqname: a full qualified name in namespace profile format (NOT NULL)
 35 * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
 36 *
 37 * Returns: profile name or NULL if one is not specified
 38 *
 39 * Split a namespace name from a profile name (see policy.c for naming
 40 * description).  If a portion of the name is missing it returns NULL for
 41 * that portion.
 42 *
 43 * NOTE: may modify the @fqname string.  The pointers returned point
 44 *       into the @fqname string.
 45 */
 46char *aa_split_fqname(char *fqname, char **ns_name)
 47{
 48	char *name = strim(fqname);
 49
 50	*ns_name = NULL;
 51	if (name[0] == ':') {
 52		char *split = strchr(&name[1], ':');
 53		*ns_name = skip_spaces(&name[1]);
 54		if (split) {
 55			/* overwrite ':' with \0 */
 56			*split++ = 0;
 57			if (strncmp(split, "//", 2) == 0)
 58				split += 2;
 59			name = skip_spaces(split);
 60		} else
 61			/* a ns name without a following profile is allowed */
 62			name = NULL;
 63	}
 64	if (name && *name == 0)
 65		name = NULL;
 66
 67	return name;
 68}
 69
 70/**
 71 * skipn_spaces - Removes leading whitespace from @str.
 72 * @str: The string to be stripped.
 
 73 *
 74 * Returns a pointer to the first non-whitespace character in @str.
 75 * if all whitespace will return NULL
 76 */
 77
 78const char *skipn_spaces(const char *str, size_t n)
 79{
 80	for (; n && isspace(*str); --n)
 81		++str;
 82	if (n)
 83		return (char *)str;
 84	return NULL;
 85}
 86
 87const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
 88			     size_t *ns_len)
 89{
 90	const char *end = fqname + n;
 91	const char *name = skipn_spaces(fqname, n);
 92
 
 
 
 93	if (!name)
 94		return NULL;
 95	*ns_name = NULL;
 96	*ns_len = 0;
 97	if (name[0] == ':') {
 98		char *split = strnchr(&name[1], end - &name[1], ':');
 99		*ns_name = skipn_spaces(&name[1], end - &name[1]);
100		if (!*ns_name)
101			return NULL;
102		if (split) {
103			*ns_len = split - *ns_name;
104			if (*ns_len == 0)
105				*ns_name = NULL;
106			split++;
107			if (end - split > 1 && strncmp(split, "//", 2) == 0)
108				split += 2;
109			name = skipn_spaces(split, end - split);
110		} else {
111			/* a ns name without a following profile is allowed */
112			name = NULL;
113			*ns_len = end - *ns_name;
114		}
115	}
116	if (name && *name == 0)
117		name = NULL;
118
119	return name;
120}
121
122/**
123 * aa_info_message - log a none profile related status message
124 * @str: message to log
125 */
126void aa_info_message(const char *str)
127{
128	if (audit_enabled) {
129		DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
130
131		aad(&sa)->info = str;
132		aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
133	}
134	printk(KERN_INFO "AppArmor: %s\n", str);
135}
136
137__counted char *aa_str_alloc(int size, gfp_t gfp)
138{
139	struct counted_str *str;
140
141	str = kmalloc(sizeof(struct counted_str) + size, gfp);
142	if (!str)
143		return NULL;
144
145	kref_init(&str->count);
146	return str->name;
147}
148
149void aa_str_kref(struct kref *kref)
150{
151	kfree(container_of(kref, struct counted_str, count));
152}
153
154
155const char aa_file_perm_chrs[] = "xwracd         km l     ";
156const char *aa_file_perm_names[] = {
157	"exec",
158	"write",
159	"read",
160	"append",
161
162	"create",
163	"delete",
164	"open",
165	"rename",
166
167	"setattr",
168	"getattr",
169	"setcred",
170	"getcred",
171
172	"chmod",
173	"chown",
174	"chgrp",
175	"lock",
176
177	"mmap",
178	"mprot",
179	"link",
180	"snapshot",
181
182	"unknown",
183	"unknown",
184	"unknown",
185	"unknown",
186
187	"unknown",
188	"unknown",
189	"unknown",
190	"unknown",
191
192	"stack",
193	"change_onexec",
194	"change_profile",
195	"change_hat",
196};
197
198/**
199 * aa_perm_mask_to_str - convert a perm mask to its short string
200 * @str: character buffer to store string in (at least 10 characters)
 
 
201 * @mask: permission mask to convert
202 */
203void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask)
204{
205	unsigned int i, perm = 1;
 
 
 
 
 
 
 
206
207	for (i = 0; i < 32; perm <<= 1, i++) {
208		if (mask & perm)
209			*str++ = chrs[i];
 
 
210	}
211	*str = '\0';
212}
213
214void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
215			 u32 mask)
216{
217	const char *fmt = "%s";
218	unsigned int i, perm = 1;
219	bool prev = false;
220
221	for (i = 0; i < 32; perm <<= 1, i++) {
222		if (mask & perm) {
223			audit_log_format(ab, fmt, names[i]);
224			if (!prev) {
225				prev = true;
226				fmt = " %s";
227			}
228		}
229	}
230}
231
232void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
233			u32 chrsmask, const char * const *names, u32 namesmask)
234{
235	char str[33];
236
237	audit_log_format(ab, "\"");
238	if ((mask & chrsmask) && chrs) {
239		aa_perm_mask_to_str(str, chrs, mask & chrsmask);
240		mask &= ~chrsmask;
241		audit_log_format(ab, "%s", str);
242		if (mask & namesmask)
243			audit_log_format(ab, " ");
244	}
245	if ((mask & namesmask) && names)
246		aa_audit_perm_names(ab, names, mask & namesmask);
247	audit_log_format(ab, "\"");
248}
249
250/**
251 * aa_audit_perms_cb - generic callback fn for auditing perms
252 * @ab: audit buffer (NOT NULL)
253 * @va: audit struct to audit values of (NOT NULL)
254 */
255static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
256{
257	struct common_audit_data *sa = va;
258
259	if (aad(sa)->request) {
260		audit_log_format(ab, " requested_mask=");
261		aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
262				   PERMS_CHRS_MASK, aa_file_perm_names,
263				   PERMS_NAMES_MASK);
264	}
265	if (aad(sa)->denied) {
266		audit_log_format(ab, "denied_mask=");
267		aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
268				   PERMS_CHRS_MASK, aa_file_perm_names,
269				   PERMS_NAMES_MASK);
270	}
271	audit_log_format(ab, " peer=");
272	aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
273				      FLAGS_NONE, GFP_ATOMIC);
274}
275
276/**
277 * aa_apply_modes_to_perms - apply namespace and profile flags to perms
278 * @profile: that perms where computed from
279 * @perms: perms to apply mode modifiers to
280 *
281 * TODO: split into profile and ns based flags for when accumulating perms
282 */
283void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
284{
285	switch (AUDIT_MODE(profile)) {
286	case AUDIT_ALL:
287		perms->audit = ALL_PERMS_MASK;
288		/* fall through */
289	case AUDIT_NOQUIET:
290		perms->quiet = 0;
291		break;
292	case AUDIT_QUIET:
293		perms->audit = 0;
294		/* fall through */
295	case AUDIT_QUIET_DENIED:
296		perms->quiet = ALL_PERMS_MASK;
297		break;
298	}
299
300	if (KILL_MODE(profile))
301		perms->kill = ALL_PERMS_MASK;
302	else if (COMPLAIN_MODE(profile))
303		perms->complain = ALL_PERMS_MASK;
304/*
305 *  TODO:
306 *	else if (PROMPT_MODE(profile))
307 *		perms->prompt = ALL_PERMS_MASK;
308 */
309}
310
311static u32 map_other(u32 x)
312{
313	return ((x & 0x3) << 8) |	/* SETATTR/GETATTR */
314		((x & 0x1c) << 18) |	/* ACCEPT/BIND/LISTEN */
315		((x & 0x60) << 19);	/* SETOPT/GETOPT */
316}
317
318void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
319		      struct aa_perms *perms)
320{
321	*perms = (struct aa_perms) {
322		.allow = dfa_user_allow(dfa, state),
323		.audit = dfa_user_audit(dfa, state),
324		.quiet = dfa_user_quiet(dfa, state),
325	};
326
327	/* for v5 perm mapping in the policydb, the other set is used
328	 * to extend the general perm set
329	 */
330	perms->allow |= map_other(dfa_other_allow(dfa, state));
331	perms->audit |= map_other(dfa_other_audit(dfa, state));
332	perms->quiet |= map_other(dfa_other_quiet(dfa, state));
333//	perms->xindex = dfa_user_xindex(dfa, state);
334}
335
336/**
337 * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
338 * @accum - perms struct to accumulate into
339 * @addend - perms struct to add to @accum
340 */
341void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
342{
343	accum->deny |= addend->deny;
344	accum->allow &= addend->allow & ~addend->deny;
345	accum->audit |= addend->audit & addend->allow;
346	accum->quiet &= addend->quiet & ~addend->allow;
347	accum->kill |= addend->kill & ~addend->allow;
348	accum->stop |= addend->stop & ~addend->allow;
349	accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
350	accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
351	accum->hide &= addend->hide & ~addend->allow;
352	accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
353}
354
355/**
356 * aa_perms_accum - accumulate perms, masking off overlapping perms
357 * @accum - perms struct to accumulate into
358 * @addend - perms struct to add to @accum
359 */
360void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
361{
362	accum->deny |= addend->deny;
363	accum->allow &= addend->allow & ~accum->deny;
364	accum->audit |= addend->audit & accum->allow;
365	accum->quiet &= addend->quiet & ~accum->allow;
366	accum->kill |= addend->kill & ~accum->allow;
367	accum->stop |= addend->stop & ~accum->allow;
368	accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
369	accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
370	accum->hide &= addend->hide & ~accum->allow;
371	accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
372}
373
374void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
375			    int type, u32 request, struct aa_perms *perms)
376{
377	/* TODO: doesn't yet handle extended types */
378	unsigned int state;
379
380	state = aa_dfa_next(profile->policy.dfa,
381			    profile->policy.start[AA_CLASS_LABEL],
382			    type);
383	aa_label_match(profile, label, state, false, request, perms);
384}
385
386
387/* currently unused */
388int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
389			  u32 request, int type, u32 *deny,
390			  struct common_audit_data *sa)
391{
392	struct aa_perms perms;
393
394	aad(sa)->label = &profile->label;
395	aad(sa)->peer = &target->label;
396	aad(sa)->request = request;
397
398	aa_profile_match_label(profile, &target->label, type, request, &perms);
399	aa_apply_modes_to_perms(profile, &perms);
400	*deny |= request & perms.deny;
401	return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
402}
403
404/**
405 * aa_check_perms - do audit mode selection based on perms set
406 * @profile: profile being checked
407 * @perms: perms computed for the request
408 * @request: requested perms
409 * @deny: Returns: explicit deny set
410 * @sa: initialized audit structure (MAY BE NULL if not auditing)
411 * @cb: callback fn for tpye specific fields (MAY BE NULL)
412 *
413 * Returns: 0 if permission else error code
414 *
415 * Note: profile audit modes need to be set before calling by setting the
416 *       perm masks appropriately.
417 *
418 *       If not auditing then complain mode is not enabled and the
419 *       error code will indicate whether there was an explicit deny
420 *	 with a positive value.
421 */
422int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
423		   u32 request, struct common_audit_data *sa,
424		   void (*cb)(struct audit_buffer *, void *))
425{
426	int type, error;
427	u32 denied = request & (~perms->allow | perms->deny);
428
429	if (likely(!denied)) {
430		/* mask off perms that are not being force audited */
431		request &= perms->audit;
432		if (!request || !sa)
433			return 0;
434
435		type = AUDIT_APPARMOR_AUDIT;
436		error = 0;
437	} else {
438		error = -EACCES;
439
440		if (denied & perms->kill)
441			type = AUDIT_APPARMOR_KILL;
442		else if (denied == (denied & perms->complain))
443			type = AUDIT_APPARMOR_ALLOWED;
444		else
445			type = AUDIT_APPARMOR_DENIED;
446
447		if (denied == (denied & perms->hide))
448			error = -ENOENT;
449
450		denied &= ~perms->quiet;
451		if (!sa || !denied)
452			return error;
453	}
454
455	if (sa) {
456		aad(sa)->label = &profile->label;
457		aad(sa)->request = request;
458		aad(sa)->denied = denied;
459		aad(sa)->error = error;
460		aa_audit_msg(type, sa, cb);
461	}
462
463	if (type == AUDIT_APPARMOR_ALLOWED)
464		error = 0;
465
466	return error;
467}
468
469
470/**
471 * aa_policy_init - initialize a policy structure
472 * @policy: policy to initialize  (NOT NULL)
473 * @prefix: prefix name if any is required.  (MAYBE NULL)
474 * @name: name of the policy, init will make a copy of it  (NOT NULL)
475 * @gfp: allocation mode
476 *
477 * Note: this fn creates a copy of strings passed in
478 *
479 * Returns: true if policy init successful
480 */
481bool aa_policy_init(struct aa_policy *policy, const char *prefix,
482		    const char *name, gfp_t gfp)
483{
484	char *hname;
485
486	/* freed by policy_free */
487	if (prefix) {
488		hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
489		if (hname)
490			sprintf(hname, "%s//%s", prefix, name);
491	} else {
492		hname = aa_str_alloc(strlen(name) + 1, gfp);
493		if (hname)
494			strcpy(hname, name);
495	}
496	if (!hname)
497		return false;
498	policy->hname = hname;
499	/* base.name is a substring of fqname */
500	policy->name = basename(policy->hname);
501	INIT_LIST_HEAD(&policy->list);
502	INIT_LIST_HEAD(&policy->profiles);
503
504	return true;
505}
506
507/**
508 * aa_policy_destroy - free the elements referenced by @policy
509 * @policy: policy that is to have its elements freed  (NOT NULL)
510 */
511void aa_policy_destroy(struct aa_policy *policy)
512{
513	AA_BUG(on_list_rcu(&policy->profiles));
514	AA_BUG(on_list_rcu(&policy->list));
515
516	/* don't free name as its a subset of hname */
517	aa_put_str(policy->hname);
518}