GNU Linux-libre 4.14.259-gnu1
[releases.git] / security / apparmor / lib.c
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  */
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
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
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  */
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
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
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  */
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
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
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  */
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  */
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
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
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  */
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  */
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
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 */
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  */
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  */
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  */
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 }