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