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