Revert "apparmor: add base infastructure for socket mediation"
[sfrench/cifs-2.6.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         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;
114                 }
115         }
116         if (name && *name == 0)
117                 name = NULL;
118
119         return name;
120 }
121
122 /**
123  * aa_info_message - log a none profile related status message
124  * @str: message to log
125  */
126 void aa_info_message(const char *str)
127 {
128         if (audit_enabled) {
129                 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
130
131                 aad(&sa)->info = str;
132                 aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
133         }
134         printk(KERN_INFO "AppArmor: %s\n", str);
135 }
136
137 __counted char *aa_str_alloc(int size, gfp_t gfp)
138 {
139         struct counted_str *str;
140
141         str = kmalloc(sizeof(struct counted_str) + size, gfp);
142         if (!str)
143                 return NULL;
144
145         kref_init(&str->count);
146         return str->name;
147 }
148
149 void aa_str_kref(struct kref *kref)
150 {
151         kfree(container_of(kref, struct counted_str, count));
152 }
153
154
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",
161
162         "create",
163         "delete",
164         "open",
165         "rename",
166
167         "setattr",
168         "getattr",
169         "setcred",
170         "getcred",
171
172         "chmod",
173         "chown",
174         "chgrp",
175         "lock",
176
177         "mmap",
178         "mprot",
179         "link",
180         "snapshot",
181
182         "unknown",
183         "unknown",
184         "unknown",
185         "unknown",
186
187         "unknown",
188         "unknown",
189         "unknown",
190         "unknown",
191
192         "stack",
193         "change_onexec",
194         "change_profile",
195         "change_hat",
196 };
197
198 /**
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
202  */
203 void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask)
204 {
205         unsigned int i, perm = 1;
206
207         for (i = 0; i < 32; perm <<= 1, i++) {
208                 if (mask & perm)
209                         *str++ = chrs[i];
210         }
211         *str = '\0';
212 }
213
214 void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask)
215 {
216         const char *fmt = "%s";
217         unsigned int i, perm = 1;
218         bool prev = false;
219
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";
226                         }
227                 }
228         }
229 }
230
231 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
232                         u32 chrsmask, const char **names, u32 namesmask)
233 {
234         char str[33];
235
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, " ");
243         }
244         if ((mask & namesmask) && names)
245                 aa_audit_perm_names(ab, names, mask & namesmask);
246         audit_log_format(ab, "\"");
247 }
248
249 /**
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)
253  */
254 static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
255 {
256         struct common_audit_data *sa = va;
257
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);
263         }
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);
269         }
270         audit_log_format(ab, " peer=");
271         aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
272                                       FLAGS_NONE, GFP_ATOMIC);
273 }
274
275 /**
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
279  *
280  * TODO: split into profile and ns based flags for when accumulating perms
281  */
282 void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
283 {
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;
297         }
298
299         if (KILL_MODE(profile))
300                 perms->kill = ALL_PERMS_MASK;
301         else if (COMPLAIN_MODE(profile))
302                 perms->complain = ALL_PERMS_MASK;
303 /*
304  *  TODO:
305  *      else if (PROMPT_MODE(profile))
306  *              perms->prompt = ALL_PERMS_MASK;
307  */
308 }
309
310 static u32 map_other(u32 x)
311 {
312         return ((x & 0x3) << 8) |       /* SETATTR/GETATTR */
313                 ((x & 0x1c) << 18) |    /* ACCEPT/BIND/LISTEN */
314                 ((x & 0x60) << 19);     /* SETOPT/GETOPT */
315 }
316
317 void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
318                       struct aa_perms *perms)
319 {
320         perms->deny = 0;
321         perms->kill = perms->stop = 0;
322         perms->complain = perms->cond = 0;
323         perms->hide = 0;
324         perms->prompt = 0;
325         perms->allow = dfa_user_allow(dfa, state);
326         perms->audit = dfa_user_audit(dfa, state);
327         perms->quiet = dfa_user_quiet(dfa, state);
328
329         /* for v5 perm mapping in the policydb, the other set is used
330          * to extend the general perm set
331          */
332         perms->allow |= map_other(dfa_other_allow(dfa, state));
333         perms->audit |= map_other(dfa_other_audit(dfa, state));
334         perms->quiet |= map_other(dfa_other_quiet(dfa, state));
335 //      perms->xindex = dfa_user_xindex(dfa, state);
336 }
337
338 /**
339  * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
340  * @accum - perms struct to accumulate into
341  * @addend - perms struct to add to @accum
342  */
343 void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
344 {
345         accum->deny |= addend->deny;
346         accum->allow &= addend->allow & ~addend->deny;
347         accum->audit |= addend->audit & addend->allow;
348         accum->quiet &= addend->quiet & ~addend->allow;
349         accum->kill |= addend->kill & ~addend->allow;
350         accum->stop |= addend->stop & ~addend->allow;
351         accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
352         accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
353         accum->hide &= addend->hide & ~addend->allow;
354         accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
355 }
356
357 /**
358  * aa_perms_accum - accumulate perms, masking off overlapping perms
359  * @accum - perms struct to accumulate into
360  * @addend - perms struct to add to @accum
361  */
362 void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
363 {
364         accum->deny |= addend->deny;
365         accum->allow &= addend->allow & ~accum->deny;
366         accum->audit |= addend->audit & accum->allow;
367         accum->quiet &= addend->quiet & ~accum->allow;
368         accum->kill |= addend->kill & ~accum->allow;
369         accum->stop |= addend->stop & ~accum->allow;
370         accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
371         accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
372         accum->hide &= addend->hide & ~accum->allow;
373         accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
374 }
375
376 void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
377                             int type, u32 request, struct aa_perms *perms)
378 {
379         /* TODO: doesn't yet handle extended types */
380         unsigned int state;
381
382         state = aa_dfa_next(profile->policy.dfa,
383                             profile->policy.start[AA_CLASS_LABEL],
384                             type);
385         aa_label_match(profile, label, state, false, request, perms);
386 }
387
388
389 /* currently unused */
390 int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
391                           u32 request, int type, u32 *deny,
392                           struct common_audit_data *sa)
393 {
394         struct aa_perms perms;
395
396         aad(sa)->label = &profile->label;
397         aad(sa)->peer = &target->label;
398         aad(sa)->request = request;
399
400         aa_profile_match_label(profile, &target->label, type, request, &perms);
401         aa_apply_modes_to_perms(profile, &perms);
402         *deny |= request & perms.deny;
403         return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
404 }
405
406 /**
407  * aa_check_perms - do audit mode selection based on perms set
408  * @profile: profile being checked
409  * @perms: perms computed for the request
410  * @request: requested perms
411  * @deny: Returns: explicit deny set
412  * @sa: initialized audit structure (MAY BE NULL if not auditing)
413  * @cb: callback fn for tpye specific fields (MAY BE NULL)
414  *
415  * Returns: 0 if permission else error code
416  *
417  * Note: profile audit modes need to be set before calling by setting the
418  *       perm masks appropriately.
419  *
420  *       If not auditing then complain mode is not enabled and the
421  *       error code will indicate whether there was an explicit deny
422  *       with a positive value.
423  */
424 int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
425                    u32 request, struct common_audit_data *sa,
426                    void (*cb)(struct audit_buffer *, void *))
427 {
428         int type, error;
429         bool stop = false;
430         u32 denied = request & (~perms->allow | perms->deny);
431
432         if (likely(!denied)) {
433                 /* mask off perms that are not being force audited */
434                 request &= perms->audit;
435                 if (!request || !sa)
436                         return 0;
437
438                 type = AUDIT_APPARMOR_AUDIT;
439                 error = 0;
440         } else {
441                 error = -EACCES;
442
443                 if (denied & perms->kill)
444                         type = AUDIT_APPARMOR_KILL;
445                 else if (denied == (denied & perms->complain))
446                         type = AUDIT_APPARMOR_ALLOWED;
447                 else
448                         type = AUDIT_APPARMOR_DENIED;
449
450                 if (denied & perms->stop)
451                         stop = true;
452                 if (denied == (denied & perms->hide))
453                         error = -ENOENT;
454
455                 denied &= ~perms->quiet;
456                 if (!sa || !denied)
457                         return error;
458         }
459
460         if (sa) {
461                 aad(sa)->label = &profile->label;
462                 aad(sa)->request = request;
463                 aad(sa)->denied = denied;
464                 aad(sa)->error = error;
465                 aa_audit_msg(type, sa, cb);
466         }
467
468         if (type == AUDIT_APPARMOR_ALLOWED)
469                 error = 0;
470
471         return error;
472 }
473
474
475 /**
476  * aa_policy_init - initialize a policy structure
477  * @policy: policy to initialize  (NOT NULL)
478  * @prefix: prefix name if any is required.  (MAYBE NULL)
479  * @name: name of the policy, init will make a copy of it  (NOT NULL)
480  * @gfp: allocation mode
481  *
482  * Note: this fn creates a copy of strings passed in
483  *
484  * Returns: true if policy init successful
485  */
486 bool aa_policy_init(struct aa_policy *policy, const char *prefix,
487                     const char *name, gfp_t gfp)
488 {
489         char *hname;
490
491         /* freed by policy_free */
492         if (prefix) {
493                 hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
494                 if (hname)
495                         sprintf(hname, "%s//%s", prefix, name);
496         } else {
497                 hname = aa_str_alloc(strlen(name) + 1, gfp);
498                 if (hname)
499                         strcpy(hname, name);
500         }
501         if (!hname)
502                 return false;
503         policy->hname = hname;
504         /* base.name is a substring of fqname */
505         policy->name = basename(policy->hname);
506         INIT_LIST_HEAD(&policy->list);
507         INIT_LIST_HEAD(&policy->profiles);
508
509         return true;
510 }
511
512 /**
513  * aa_policy_destroy - free the elements referenced by @policy
514  * @policy: policy that is to have its elements freed  (NOT NULL)
515  */
516 void aa_policy_destroy(struct aa_policy *policy)
517 {
518         AA_BUG(on_list_rcu(&policy->profiles));
519         AA_BUG(on_list_rcu(&policy->list));
520
521         /* don't free name as its a subset of hname */
522         aa_put_str(policy->hname);
523 }