blob: 76491e7f4177fa94c9d742e91d049a5ebcfe04e1 [file] [log] [blame]
Andrew Scullb4b6d4a2019-01-02 15:54:55 +00001/*
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
27struct aa_perms nullperms;
28struct 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 */
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], ':');
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
78const 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
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
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 */
128void 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
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
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)
203 * @str_size: size of the @str buffer
204 * @chrs: NUL-terminated character buffer of permission characters
205 * @mask: permission mask to convert
206 */
207void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
208{
209 unsigned int i, perm = 1;
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;
217
218 *str++ = chrs[i];
219 str_size--;
220 }
221 }
222 *str = '\0';
223}
224
225void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
226 u32 mask)
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,
244 u32 chrsmask, const char * const *names, u32 namesmask)
245{
246 char str[33];
247
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, " ");
255 }
256 if ((mask & namesmask) && names)
257 aa_audit_perm_names(ab, names, mask & namesmask);
258 audit_log_format(ab, "\"");
259}
260
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
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{
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 };
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
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)
422 * @cb: callback fn for type specific fields (MAY BE NULL)
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;
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
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
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)
486 * @gfp: allocation mode
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,
493 const char *name, gfp_t gfp)
494{
495 char *hname;
496
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);
506 }
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);
514
515 return true;
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{
524 AA_BUG(on_list_rcu(&policy->profiles));
525 AA_BUG(on_list_rcu(&policy->list));
526
527 /* don't free name as its a subset of hname */
528 aa_put_str(policy->hname);
529}