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