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