mm/vmscan.c: prevent useless kswapd loops
[linux/fpc-iii.git] / security / apparmor / lib.c
blob76491e7f4177fa94c9d742e91d049a5ebcfe04e1
1 /*
2 * AppArmor security module
4 * This file contains basic common functions used in AppArmor
6 * Copyright (C) 1998-2008 Novell/SUSE
7 * Copyright 2009-2010 Canonical Ltd.
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.
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>
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"
27 struct aa_perms nullperms;
28 struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
29 .quiet = ALL_PERMS_MASK,
30 .hide = ALL_PERMS_MASK };
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)
37 * Returns: profile name or NULL if one is not specified
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.
43 * NOTE: may modify the @fqname string. The pointers returned point
44 * into the @fqname string.
46 char *aa_split_fqname(char *fqname, char **ns_name)
48 char *name = strim(fqname);
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;
64 if (name && *name == 0)
65 name = NULL;
67 return name;
70 /**
71 * skipn_spaces - Removes leading whitespace from @str.
72 * @str: The string to be stripped.
74 * Returns a pointer to the first non-whitespace character in @str.
75 * if all whitespace will return NULL
78 const char *skipn_spaces(const char *str, size_t n)
80 for (; n && isspace(*str); --n)
81 ++str;
82 if (n)
83 return (char *)str;
84 return NULL;
87 const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
88 size_t *ns_len)
90 const char *end = fqname + n;
91 const char *name = skipn_spaces(fqname, n);
93 *ns_name = NULL;
94 *ns_len = 0;
96 if (!name)
97 return NULL;
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;
118 if (name && *name == 0)
119 name = NULL;
121 return name;
125 * aa_info_message - log a none profile related status message
126 * @str: message to log
128 void aa_info_message(const char *str)
130 if (audit_enabled) {
131 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
133 aad(&sa)->info = str;
134 aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
136 printk(KERN_INFO "AppArmor: %s\n", str);
139 __counted char *aa_str_alloc(int size, gfp_t gfp)
141 struct counted_str *str;
143 str = kmalloc(sizeof(struct counted_str) + size, gfp);
144 if (!str)
145 return NULL;
147 kref_init(&str->count);
148 return str->name;
151 void aa_str_kref(struct kref *kref)
153 kfree(container_of(kref, struct counted_str, count));
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",
164 "create",
165 "delete",
166 "open",
167 "rename",
169 "setattr",
170 "getattr",
171 "setcred",
172 "getcred",
174 "chmod",
175 "chown",
176 "chgrp",
177 "lock",
179 "mmap",
180 "mprot",
181 "link",
182 "snapshot",
184 "unknown",
185 "unknown",
186 "unknown",
187 "unknown",
189 "unknown",
190 "unknown",
191 "unknown",
192 "unknown",
194 "stack",
195 "change_onexec",
196 "change_profile",
197 "change_hat",
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
207 void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
209 unsigned int i, perm = 1;
210 size_t num_chrs = strlen(chrs);
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;
218 *str++ = chrs[i];
219 str_size--;
222 *str = '\0';
225 void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
226 u32 mask)
228 const char *fmt = "%s";
229 unsigned int i, perm = 1;
230 bool prev = false;
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";
243 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
244 u32 chrsmask, const char * const *names, u32 namesmask)
246 char str[33];
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, " ");
256 if ((mask & namesmask) && names)
257 aa_audit_perm_names(ab, names, mask & namesmask);
258 audit_log_format(ab, "\"");
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)
266 static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
268 struct common_audit_data *sa = va;
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);
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);
282 audit_log_format(ab, " peer=");
283 aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
284 FLAGS_NONE, GFP_ATOMIC);
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
292 * TODO: split into profile and ns based flags for when accumulating perms
294 void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
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;
311 if (KILL_MODE(profile))
312 perms->kill = ALL_PERMS_MASK;
313 else if (COMPLAIN_MODE(profile))
314 perms->complain = ALL_PERMS_MASK;
316 * TODO:
317 * else if (PROMPT_MODE(profile))
318 * perms->prompt = ALL_PERMS_MASK;
322 static u32 map_other(u32 x)
324 return ((x & 0x3) << 8) | /* SETATTR/GETATTR */
325 ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */
326 ((x & 0x60) << 19); /* SETOPT/GETOPT */
329 void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
330 struct aa_perms *perms)
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),
338 /* for v5 perm mapping in the policydb, the other set is used
339 * to extend the general perm set
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);
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
352 void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
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;
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
371 void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
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;
385 void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
386 int type, u32 request, struct aa_perms *perms)
388 /* TODO: doesn't yet handle extended types */
389 unsigned int state;
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);
398 /* currently unused */
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)
403 struct aa_perms perms;
405 aad(sa)->label = &profile->label;
406 aad(sa)->peer = &target->label;
407 aad(sa)->request = request;
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);
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)
424 * Returns: 0 if permission else error code
426 * Note: profile audit modes need to be set before calling by setting the
427 * perm masks appropriately.
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.
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 *))
437 int type, error;
438 u32 denied = request & (~perms->allow | perms->deny);
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;
446 type = AUDIT_APPARMOR_AUDIT;
447 error = 0;
448 } else {
449 error = -EACCES;
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;
458 if (denied == (denied & perms->hide))
459 error = -ENOENT;
461 denied &= ~perms->quiet;
462 if (!sa || !denied)
463 return error;
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);
474 if (type == AUDIT_APPARMOR_ALLOWED)
475 error = 0;
477 return error;
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
488 * Note: this fn creates a copy of strings passed in
490 * Returns: true if policy init successful
492 bool aa_policy_init(struct aa_policy *policy, const char *prefix,
493 const char *name, gfp_t gfp)
495 char *hname;
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);
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);
515 return true;
519 * aa_policy_destroy - free the elements referenced by @policy
520 * @policy: policy that is to have its elements freed (NOT NULL)
522 void aa_policy_destroy(struct aa_policy *policy)
524 AA_BUG(on_list_rcu(&policy->profiles));
525 AA_BUG(on_list_rcu(&policy->list));
527 /* don't free name as its a subset of hname */
528 aa_put_str(policy->hname);