regmap: Correct offset handling in regmap_volatile_range
[linux/fpc-iii.git] / security / apparmor / lib.c
blob4d5e98e49d5e06a9066f618adabe2767da45ff3c
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 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;
116 if (name && *name == 0)
117 name = NULL;
119 return name;
123 * aa_info_message - log a none profile related status message
124 * @str: message to log
126 void aa_info_message(const char *str)
128 if (audit_enabled) {
129 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
131 aad(&sa)->info = str;
132 aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
134 printk(KERN_INFO "AppArmor: %s\n", str);
137 __counted char *aa_str_alloc(int size, gfp_t gfp)
139 struct counted_str *str;
141 str = kmalloc(sizeof(struct counted_str) + size, gfp);
142 if (!str)
143 return NULL;
145 kref_init(&str->count);
146 return str->name;
149 void aa_str_kref(struct kref *kref)
151 kfree(container_of(kref, struct counted_str, count));
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",
162 "create",
163 "delete",
164 "open",
165 "rename",
167 "setattr",
168 "getattr",
169 "setcred",
170 "getcred",
172 "chmod",
173 "chown",
174 "chgrp",
175 "lock",
177 "mmap",
178 "mprot",
179 "link",
180 "snapshot",
182 "unknown",
183 "unknown",
184 "unknown",
185 "unknown",
187 "unknown",
188 "unknown",
189 "unknown",
190 "unknown",
192 "stack",
193 "change_onexec",
194 "change_profile",
195 "change_hat",
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 * @mask: permission mask to convert
203 void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask)
205 unsigned int i, perm = 1;
207 for (i = 0; i < 32; perm <<= 1, i++) {
208 if (mask & perm)
209 *str++ = chrs[i];
211 *str = '\0';
214 void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask)
216 const char *fmt = "%s";
217 unsigned int i, perm = 1;
218 bool prev = false;
220 for (i = 0; i < 32; perm <<= 1, i++) {
221 if (mask & perm) {
222 audit_log_format(ab, fmt, names[i]);
223 if (!prev) {
224 prev = true;
225 fmt = " %s";
231 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
232 u32 chrsmask, const char **names, u32 namesmask)
234 char str[33];
236 audit_log_format(ab, "\"");
237 if ((mask & chrsmask) && chrs) {
238 aa_perm_mask_to_str(str, chrs, mask & chrsmask);
239 mask &= ~chrsmask;
240 audit_log_format(ab, "%s", str);
241 if (mask & namesmask)
242 audit_log_format(ab, " ");
244 if ((mask & namesmask) && names)
245 aa_audit_perm_names(ab, names, mask & namesmask);
246 audit_log_format(ab, "\"");
250 * aa_audit_perms_cb - generic callback fn for auditing perms
251 * @ab: audit buffer (NOT NULL)
252 * @va: audit struct to audit values of (NOT NULL)
254 static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
256 struct common_audit_data *sa = va;
258 if (aad(sa)->request) {
259 audit_log_format(ab, " requested_mask=");
260 aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
261 PERMS_CHRS_MASK, aa_file_perm_names,
262 PERMS_NAMES_MASK);
264 if (aad(sa)->denied) {
265 audit_log_format(ab, "denied_mask=");
266 aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
267 PERMS_CHRS_MASK, aa_file_perm_names,
268 PERMS_NAMES_MASK);
270 audit_log_format(ab, " peer=");
271 aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
272 FLAGS_NONE, GFP_ATOMIC);
276 * aa_apply_modes_to_perms - apply namespace and profile flags to perms
277 * @profile: that perms where computed from
278 * @perms: perms to apply mode modifiers to
280 * TODO: split into profile and ns based flags for when accumulating perms
282 void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
284 switch (AUDIT_MODE(profile)) {
285 case AUDIT_ALL:
286 perms->audit = ALL_PERMS_MASK;
287 /* fall through */
288 case AUDIT_NOQUIET:
289 perms->quiet = 0;
290 break;
291 case AUDIT_QUIET:
292 perms->audit = 0;
293 /* fall through */
294 case AUDIT_QUIET_DENIED:
295 perms->quiet = ALL_PERMS_MASK;
296 break;
299 if (KILL_MODE(profile))
300 perms->kill = ALL_PERMS_MASK;
301 else if (COMPLAIN_MODE(profile))
302 perms->complain = ALL_PERMS_MASK;
304 * TODO:
305 * else if (PROMPT_MODE(profile))
306 * perms->prompt = ALL_PERMS_MASK;
310 static u32 map_other(u32 x)
312 return ((x & 0x3) << 8) | /* SETATTR/GETATTR */
313 ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */
314 ((x & 0x60) << 19); /* SETOPT/GETOPT */
317 void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
318 struct aa_perms *perms)
320 *perms = (struct aa_perms) {
321 .allow = dfa_user_allow(dfa, state),
322 .audit = dfa_user_audit(dfa, state),
323 .quiet = dfa_user_quiet(dfa, state),
326 /* for v5 perm mapping in the policydb, the other set is used
327 * to extend the general perm set
329 perms->allow |= map_other(dfa_other_allow(dfa, state));
330 perms->audit |= map_other(dfa_other_audit(dfa, state));
331 perms->quiet |= map_other(dfa_other_quiet(dfa, state));
332 // perms->xindex = dfa_user_xindex(dfa, state);
336 * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
337 * @accum - perms struct to accumulate into
338 * @addend - perms struct to add to @accum
340 void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
342 accum->deny |= addend->deny;
343 accum->allow &= addend->allow & ~addend->deny;
344 accum->audit |= addend->audit & addend->allow;
345 accum->quiet &= addend->quiet & ~addend->allow;
346 accum->kill |= addend->kill & ~addend->allow;
347 accum->stop |= addend->stop & ~addend->allow;
348 accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
349 accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
350 accum->hide &= addend->hide & ~addend->allow;
351 accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
355 * aa_perms_accum - accumulate perms, masking off overlapping perms
356 * @accum - perms struct to accumulate into
357 * @addend - perms struct to add to @accum
359 void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
361 accum->deny |= addend->deny;
362 accum->allow &= addend->allow & ~accum->deny;
363 accum->audit |= addend->audit & accum->allow;
364 accum->quiet &= addend->quiet & ~accum->allow;
365 accum->kill |= addend->kill & ~accum->allow;
366 accum->stop |= addend->stop & ~accum->allow;
367 accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
368 accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
369 accum->hide &= addend->hide & ~accum->allow;
370 accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
373 void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
374 int type, u32 request, struct aa_perms *perms)
376 /* TODO: doesn't yet handle extended types */
377 unsigned int state;
379 state = aa_dfa_next(profile->policy.dfa,
380 profile->policy.start[AA_CLASS_LABEL],
381 type);
382 aa_label_match(profile, label, state, false, request, perms);
386 /* currently unused */
387 int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
388 u32 request, int type, u32 *deny,
389 struct common_audit_data *sa)
391 struct aa_perms perms;
393 aad(sa)->label = &profile->label;
394 aad(sa)->peer = &target->label;
395 aad(sa)->request = request;
397 aa_profile_match_label(profile, &target->label, type, request, &perms);
398 aa_apply_modes_to_perms(profile, &perms);
399 *deny |= request & perms.deny;
400 return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
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 * @deny: Returns: explicit deny set
409 * @sa: initialized audit structure (MAY BE NULL if not auditing)
410 * @cb: callback fn for tpye specific fields (MAY BE NULL)
412 * Returns: 0 if permission else error code
414 * Note: profile audit modes need to be set before calling by setting the
415 * perm masks appropriately.
417 * If not auditing then complain mode is not enabled and the
418 * error code will indicate whether there was an explicit deny
419 * with a positive value.
421 int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
422 u32 request, struct common_audit_data *sa,
423 void (*cb)(struct audit_buffer *, void *))
425 int type, error;
426 u32 denied = request & (~perms->allow | perms->deny);
428 if (likely(!denied)) {
429 /* mask off perms that are not being force audited */
430 request &= perms->audit;
431 if (!request || !sa)
432 return 0;
434 type = AUDIT_APPARMOR_AUDIT;
435 error = 0;
436 } else {
437 error = -EACCES;
439 if (denied & perms->kill)
440 type = AUDIT_APPARMOR_KILL;
441 else if (denied == (denied & perms->complain))
442 type = AUDIT_APPARMOR_ALLOWED;
443 else
444 type = AUDIT_APPARMOR_DENIED;
446 if (denied == (denied & perms->hide))
447 error = -ENOENT;
449 denied &= ~perms->quiet;
450 if (!sa || !denied)
451 return error;
454 if (sa) {
455 aad(sa)->label = &profile->label;
456 aad(sa)->request = request;
457 aad(sa)->denied = denied;
458 aad(sa)->error = error;
459 aa_audit_msg(type, sa, cb);
462 if (type == AUDIT_APPARMOR_ALLOWED)
463 error = 0;
465 return error;
470 * aa_policy_init - initialize a policy structure
471 * @policy: policy to initialize (NOT NULL)
472 * @prefix: prefix name if any is required. (MAYBE NULL)
473 * @name: name of the policy, init will make a copy of it (NOT NULL)
474 * @gfp: allocation mode
476 * Note: this fn creates a copy of strings passed in
478 * Returns: true if policy init successful
480 bool aa_policy_init(struct aa_policy *policy, const char *prefix,
481 const char *name, gfp_t gfp)
483 char *hname;
485 /* freed by policy_free */
486 if (prefix) {
487 hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
488 if (hname)
489 sprintf(hname, "%s//%s", prefix, name);
490 } else {
491 hname = aa_str_alloc(strlen(name) + 1, gfp);
492 if (hname)
493 strcpy(hname, name);
495 if (!hname)
496 return false;
497 policy->hname = hname;
498 /* base.name is a substring of fqname */
499 policy->name = basename(policy->hname);
500 INIT_LIST_HEAD(&policy->list);
501 INIT_LIST_HEAD(&policy->profiles);
503 return true;
507 * aa_policy_destroy - free the elements referenced by @policy
508 * @policy: policy that is to have its elements freed (NOT NULL)
510 void aa_policy_destroy(struct aa_policy *policy)
512 AA_BUG(on_list_rcu(&policy->profiles));
513 AA_BUG(on_list_rcu(&policy->list));
515 /* don't free name as its a subset of hname */
516 aa_put_str(policy->hname);