Merge tag 'apparmor-pr-2019-02-01' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / security / apparmor / lib.c
CommitLineData
cdff2642
JJ
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
3b0aaf58 15#include <linux/ctype.h>
b7f080cf 16#include <linux/mm.h>
cdff2642
JJ
17#include <linux/slab.h>
18#include <linux/string.h>
19#include <linux/vmalloc.h>
20
21#include "include/audit.h"
32c3df63 22#include "include/apparmor.h"
12557dcb 23#include "include/lib.h"
fc7e0b26 24#include "include/perms.h"
fe6bb31f 25#include "include/policy.h"
cdff2642 26
2d679f3c 27struct aa_perms nullperms;
aa9aeea8
JJ
28struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
29 .quiet = ALL_PERMS_MASK,
30 .hide = ALL_PERMS_MASK };
31
cdff2642
JJ
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 */
46char *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], ':');
04ccd53f 53 *ns_name = skip_spaces(&name[1]);
cdff2642
JJ
54 if (split) {
55 /* overwrite ':' with \0 */
2654bfbc
JJ
56 *split++ = 0;
57 if (strncmp(split, "//", 2) == 0)
58 split += 2;
59 name = skip_spaces(split);
cdff2642
JJ
60 } else
61 /* a ns name without a following profile is allowed */
62 name = NULL;
cdff2642
JJ
63 }
64 if (name && *name == 0)
65 name = NULL;
66
67 return name;
68}
69
3b0aaf58
JJ
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
b91deb9d 78const char *skipn_spaces(const char *str, size_t n)
3b0aaf58
JJ
79{
80 for (; n && isspace(*str); --n)
81 ++str;
82 if (n)
83 return (char *)str;
84 return NULL;
85}
86
87const 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
3b0aaf58
JJ
93 *ns_name = NULL;
94 *ns_len = 0;
250f2da4
ZM
95
96 if (!name)
97 return NULL;
98
3b0aaf58
JJ
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
cdff2642
JJ
124/**
125 * aa_info_message - log a none profile related status message
126 * @str: message to log
127 */
128void aa_info_message(const char *str)
129{
130 if (audit_enabled) {
ef88a7ac
JJ
131 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
132
133 aad(&sa)->info = str;
cdff2642
JJ
134 aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
135 }
136 printk(KERN_INFO "AppArmor: %s\n", str);
137}
138
a1bd627b
JJ
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
151void aa_str_kref(struct kref *kref)
152{
153 kfree(container_of(kref, struct counted_str, count));
154}
155
156
e53cfe6c
JJ
157const char aa_file_perm_chrs[] = "xwracd km l ";
158const 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)
7f3ebcf2
TH
203 * @str_size: size of the @str buffer
204 * @chrs: NUL-terminated character buffer of permission characters
e53cfe6c
JJ
205 * @mask: permission mask to convert
206 */
7f3ebcf2 207void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
e53cfe6c
JJ
208{
209 unsigned int i, perm = 1;
7f3ebcf2
TH
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;
e53cfe6c 217
e53cfe6c 218 *str++ = chrs[i];
7f3ebcf2
TH
219 str_size--;
220 }
e53cfe6c
JJ
221 }
222 *str = '\0';
223}
224
56974a6f
JJ
225void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
226 u32 mask)
aa9aeea8
JJ
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
243void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
56974a6f 244 u32 chrsmask, const char * const *names, u32 namesmask)
aa9aeea8
JJ
245{
246 char str[33];
247
248 audit_log_format(ab, "\"");
249 if ((mask & chrsmask) && chrs) {
7f3ebcf2 250 aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
aa9aeea8
JJ
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
637f688d
JJ
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 */
266static 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
aa9aeea8
JJ
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 */
294void 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
322static 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
329void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
330 struct aa_perms *perms)
331{
7bba39ae
AB
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 };
aa9aeea8
JJ
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
637f688d
JJ
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 */
352void 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 */
371void 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
385void 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 */
399int 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)
69ad4a44 422 * @cb: callback fn for type specific fields (MAY BE NULL)
637f688d
JJ
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 */
433int 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;
637f688d
JJ
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
637f688d
JJ
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
fe6bb31f
JJ
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)
a1bd627b 486 * @gfp: allocation mode
fe6bb31f
JJ
487 *
488 * Note: this fn creates a copy of strings passed in
489 *
490 * Returns: true if policy init successful
491 */
492bool aa_policy_init(struct aa_policy *policy, const char *prefix,
d102d895 493 const char *name, gfp_t gfp)
fe6bb31f 494{
a1bd627b
JJ
495 char *hname;
496
fe6bb31f
JJ
497 /* freed by policy_free */
498 if (prefix) {
a1bd627b
JJ
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)
b9c42ac7 508 return false;
a1bd627b 509 policy->hname = hname;
fe6bb31f 510 /* base.name is a substring of fqname */
d102d895 511 policy->name = basename(policy->hname);
fe6bb31f
JJ
512 INIT_LIST_HEAD(&policy->list);
513 INIT_LIST_HEAD(&policy->profiles);
514
b9c42ac7 515 return true;
fe6bb31f
JJ
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 */
522void aa_policy_destroy(struct aa_policy *policy)
523{
5fd1b95f
JJ
524 AA_BUG(on_list_rcu(&policy->profiles));
525 AA_BUG(on_list_rcu(&policy->list));
fe6bb31f
JJ
526
527 /* don't free name as its a subset of hname */
a1bd627b 528 aa_put_str(policy->hname);
fe6bb31f 529}