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