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