~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/apparmor/lib.c

Version: ~ [ linux-5.1-rc1 ] ~ [ linux-5.0.3 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.30 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.107 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.164 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.176 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.136 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.63 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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  * @str_size: size of the @str buffer
204  * @chrs: NUL-terminated character buffer of permission characters
205  * @mask: permission mask to convert
206  */
207 void 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 
225 void 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 
243 void 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  */
266 static 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  */
294 void 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 
322 static 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 
329 void 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  */
352 void 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  */
371 void 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 
385 void 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 */
399 int 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  */
433 int 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  */
492 bool 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  */
522 void 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 }
530 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp