Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * AppArmor security module
0004  *
0005  * This file contains basic common functions used in AppArmor
0006  *
0007  * Copyright (C) 1998-2008 Novell/SUSE
0008  * Copyright 2009-2010 Canonical Ltd.
0009  */
0010 
0011 #include <linux/ctype.h>
0012 #include <linux/mm.h>
0013 #include <linux/slab.h>
0014 #include <linux/string.h>
0015 #include <linux/vmalloc.h>
0016 
0017 #include "include/audit.h"
0018 #include "include/apparmor.h"
0019 #include "include/lib.h"
0020 #include "include/perms.h"
0021 #include "include/policy.h"
0022 
0023 struct aa_perms nullperms;
0024 struct aa_perms allperms = { .allow = ALL_PERMS_MASK,
0025                  .quiet = ALL_PERMS_MASK,
0026                  .hide = ALL_PERMS_MASK };
0027 
0028 /**
0029  * aa_split_fqname - split a fqname into a profile and namespace name
0030  * @fqname: a full qualified name in namespace profile format (NOT NULL)
0031  * @ns_name: pointer to portion of the string containing the ns name (NOT NULL)
0032  *
0033  * Returns: profile name or NULL if one is not specified
0034  *
0035  * Split a namespace name from a profile name (see policy.c for naming
0036  * description).  If a portion of the name is missing it returns NULL for
0037  * that portion.
0038  *
0039  * NOTE: may modify the @fqname string.  The pointers returned point
0040  *       into the @fqname string.
0041  */
0042 char *aa_split_fqname(char *fqname, char **ns_name)
0043 {
0044     char *name = strim(fqname);
0045 
0046     *ns_name = NULL;
0047     if (name[0] == ':') {
0048         char *split = strchr(&name[1], ':');
0049         *ns_name = skip_spaces(&name[1]);
0050         if (split) {
0051             /* overwrite ':' with \0 */
0052             *split++ = 0;
0053             if (strncmp(split, "//", 2) == 0)
0054                 split += 2;
0055             name = skip_spaces(split);
0056         } else
0057             /* a ns name without a following profile is allowed */
0058             name = NULL;
0059     }
0060     if (name && *name == 0)
0061         name = NULL;
0062 
0063     return name;
0064 }
0065 
0066 /**
0067  * skipn_spaces - Removes leading whitespace from @str.
0068  * @str: The string to be stripped.
0069  *
0070  * Returns a pointer to the first non-whitespace character in @str.
0071  * if all whitespace will return NULL
0072  */
0073 
0074 const char *skipn_spaces(const char *str, size_t n)
0075 {
0076     for (; n && isspace(*str); --n)
0077         ++str;
0078     if (n)
0079         return (char *)str;
0080     return NULL;
0081 }
0082 
0083 const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name,
0084                  size_t *ns_len)
0085 {
0086     const char *end = fqname + n;
0087     const char *name = skipn_spaces(fqname, n);
0088 
0089     *ns_name = NULL;
0090     *ns_len = 0;
0091 
0092     if (!name)
0093         return NULL;
0094 
0095     if (name[0] == ':') {
0096         char *split = strnchr(&name[1], end - &name[1], ':');
0097         *ns_name = skipn_spaces(&name[1], end - &name[1]);
0098         if (!*ns_name)
0099             return NULL;
0100         if (split) {
0101             *ns_len = split - *ns_name;
0102             if (*ns_len == 0)
0103                 *ns_name = NULL;
0104             split++;
0105             if (end - split > 1 && strncmp(split, "//", 2) == 0)
0106                 split += 2;
0107             name = skipn_spaces(split, end - split);
0108         } else {
0109             /* a ns name without a following profile is allowed */
0110             name = NULL;
0111             *ns_len = end - *ns_name;
0112         }
0113     }
0114     if (name && *name == 0)
0115         name = NULL;
0116 
0117     return name;
0118 }
0119 
0120 /**
0121  * aa_info_message - log a none profile related status message
0122  * @str: message to log
0123  */
0124 void aa_info_message(const char *str)
0125 {
0126     if (audit_enabled) {
0127         DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL);
0128 
0129         aad(&sa)->info = str;
0130         aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL);
0131     }
0132     printk(KERN_INFO "AppArmor: %s\n", str);
0133 }
0134 
0135 __counted char *aa_str_alloc(int size, gfp_t gfp)
0136 {
0137     struct counted_str *str;
0138 
0139     str = kmalloc(struct_size(str, name, size), gfp);
0140     if (!str)
0141         return NULL;
0142 
0143     kref_init(&str->count);
0144     return str->name;
0145 }
0146 
0147 void aa_str_kref(struct kref *kref)
0148 {
0149     kfree(container_of(kref, struct counted_str, count));
0150 }
0151 
0152 
0153 const char aa_file_perm_chrs[] = "xwracd         km l     ";
0154 const char *aa_file_perm_names[] = {
0155     "exec",
0156     "write",
0157     "read",
0158     "append",
0159 
0160     "create",
0161     "delete",
0162     "open",
0163     "rename",
0164 
0165     "setattr",
0166     "getattr",
0167     "setcred",
0168     "getcred",
0169 
0170     "chmod",
0171     "chown",
0172     "chgrp",
0173     "lock",
0174 
0175     "mmap",
0176     "mprot",
0177     "link",
0178     "snapshot",
0179 
0180     "unknown",
0181     "unknown",
0182     "unknown",
0183     "unknown",
0184 
0185     "unknown",
0186     "unknown",
0187     "unknown",
0188     "unknown",
0189 
0190     "stack",
0191     "change_onexec",
0192     "change_profile",
0193     "change_hat",
0194 };
0195 
0196 /**
0197  * aa_perm_mask_to_str - convert a perm mask to its short string
0198  * @str: character buffer to store string in (at least 10 characters)
0199  * @str_size: size of the @str buffer
0200  * @chrs: NUL-terminated character buffer of permission characters
0201  * @mask: permission mask to convert
0202  */
0203 void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask)
0204 {
0205     unsigned int i, perm = 1;
0206     size_t num_chrs = strlen(chrs);
0207 
0208     for (i = 0; i < num_chrs; perm <<= 1, i++) {
0209         if (mask & perm) {
0210             /* Ensure that one byte is left for NUL-termination */
0211             if (WARN_ON_ONCE(str_size <= 1))
0212                 break;
0213 
0214             *str++ = chrs[i];
0215             str_size--;
0216         }
0217     }
0218     *str = '\0';
0219 }
0220 
0221 void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names,
0222              u32 mask)
0223 {
0224     const char *fmt = "%s";
0225     unsigned int i, perm = 1;
0226     bool prev = false;
0227 
0228     for (i = 0; i < 32; perm <<= 1, i++) {
0229         if (mask & perm) {
0230             audit_log_format(ab, fmt, names[i]);
0231             if (!prev) {
0232                 prev = true;
0233                 fmt = " %s";
0234             }
0235         }
0236     }
0237 }
0238 
0239 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs,
0240             u32 chrsmask, const char * const *names, u32 namesmask)
0241 {
0242     char str[33];
0243 
0244     audit_log_format(ab, "\"");
0245     if ((mask & chrsmask) && chrs) {
0246         aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask);
0247         mask &= ~chrsmask;
0248         audit_log_format(ab, "%s", str);
0249         if (mask & namesmask)
0250             audit_log_format(ab, " ");
0251     }
0252     if ((mask & namesmask) && names)
0253         aa_audit_perm_names(ab, names, mask & namesmask);
0254     audit_log_format(ab, "\"");
0255 }
0256 
0257 /**
0258  * aa_audit_perms_cb - generic callback fn for auditing perms
0259  * @ab: audit buffer (NOT NULL)
0260  * @va: audit struct to audit values of (NOT NULL)
0261  */
0262 static void aa_audit_perms_cb(struct audit_buffer *ab, void *va)
0263 {
0264     struct common_audit_data *sa = va;
0265 
0266     if (aad(sa)->request) {
0267         audit_log_format(ab, " requested_mask=");
0268         aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs,
0269                    PERMS_CHRS_MASK, aa_file_perm_names,
0270                    PERMS_NAMES_MASK);
0271     }
0272     if (aad(sa)->denied) {
0273         audit_log_format(ab, "denied_mask=");
0274         aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs,
0275                    PERMS_CHRS_MASK, aa_file_perm_names,
0276                    PERMS_NAMES_MASK);
0277     }
0278     audit_log_format(ab, " peer=");
0279     aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
0280                       FLAGS_NONE, GFP_ATOMIC);
0281 }
0282 
0283 /**
0284  * aa_apply_modes_to_perms - apply namespace and profile flags to perms
0285  * @profile: that perms where computed from
0286  * @perms: perms to apply mode modifiers to
0287  *
0288  * TODO: split into profile and ns based flags for when accumulating perms
0289  */
0290 void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms)
0291 {
0292     switch (AUDIT_MODE(profile)) {
0293     case AUDIT_ALL:
0294         perms->audit = ALL_PERMS_MASK;
0295         fallthrough;
0296     case AUDIT_NOQUIET:
0297         perms->quiet = 0;
0298         break;
0299     case AUDIT_QUIET:
0300         perms->audit = 0;
0301         fallthrough;
0302     case AUDIT_QUIET_DENIED:
0303         perms->quiet = ALL_PERMS_MASK;
0304         break;
0305     }
0306 
0307     if (KILL_MODE(profile))
0308         perms->kill = ALL_PERMS_MASK;
0309     else if (COMPLAIN_MODE(profile))
0310         perms->complain = ALL_PERMS_MASK;
0311 /*
0312  *  TODO:
0313  *  else if (PROMPT_MODE(profile))
0314  *      perms->prompt = ALL_PERMS_MASK;
0315  */
0316 }
0317 
0318 static u32 map_other(u32 x)
0319 {
0320     return ((x & 0x3) << 8) |   /* SETATTR/GETATTR */
0321         ((x & 0x1c) << 18) |    /* ACCEPT/BIND/LISTEN */
0322         ((x & 0x60) << 19); /* SETOPT/GETOPT */
0323 }
0324 
0325 static u32 map_xbits(u32 x)
0326 {
0327     return ((x & 0x1) << 7) |
0328         ((x & 0x7e) << 9);
0329 }
0330 
0331 void aa_compute_perms(struct aa_dfa *dfa, unsigned int state,
0332               struct aa_perms *perms)
0333 {
0334     /* This mapping is convulated due to history.
0335      * v1-v4: only file perms
0336      * v5: added policydb which dropped in perm user conditional to
0337      *     gain new perm bits, but had to map around the xbits because
0338      *     the userspace compiler was still munging them.
0339      * v9: adds using the xbits in policydb because the compiler now
0340      *     supports treating policydb permission bits different.
0341      *     Unfortunately there is not way to force auditing on the
0342      *     perms represented by the xbits
0343      */
0344     *perms = (struct aa_perms) {
0345         .allow = dfa_user_allow(dfa, state) |
0346              map_xbits(dfa_user_xbits(dfa, state)),
0347         .audit = dfa_user_audit(dfa, state),
0348         .quiet = dfa_user_quiet(dfa, state) |
0349              map_xbits(dfa_other_xbits(dfa, state)),
0350     };
0351 
0352     /* for v5-v9 perm mapping in the policydb, the other set is used
0353      * to extend the general perm set
0354      */
0355     perms->allow |= map_other(dfa_other_allow(dfa, state));
0356     perms->audit |= map_other(dfa_other_audit(dfa, state));
0357     perms->quiet |= map_other(dfa_other_quiet(dfa, state));
0358 }
0359 
0360 /**
0361  * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms
0362  * @accum - perms struct to accumulate into
0363  * @addend - perms struct to add to @accum
0364  */
0365 void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend)
0366 {
0367     accum->deny |= addend->deny;
0368     accum->allow &= addend->allow & ~addend->deny;
0369     accum->audit |= addend->audit & addend->allow;
0370     accum->quiet &= addend->quiet & ~addend->allow;
0371     accum->kill |= addend->kill & ~addend->allow;
0372     accum->stop |= addend->stop & ~addend->allow;
0373     accum->complain |= addend->complain & ~addend->allow & ~addend->deny;
0374     accum->cond |= addend->cond & ~addend->allow & ~addend->deny;
0375     accum->hide &= addend->hide & ~addend->allow;
0376     accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny;
0377 }
0378 
0379 /**
0380  * aa_perms_accum - accumulate perms, masking off overlapping perms
0381  * @accum - perms struct to accumulate into
0382  * @addend - perms struct to add to @accum
0383  */
0384 void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend)
0385 {
0386     accum->deny |= addend->deny;
0387     accum->allow &= addend->allow & ~accum->deny;
0388     accum->audit |= addend->audit & accum->allow;
0389     accum->quiet &= addend->quiet & ~accum->allow;
0390     accum->kill |= addend->kill & ~accum->allow;
0391     accum->stop |= addend->stop & ~accum->allow;
0392     accum->complain |= addend->complain & ~accum->allow & ~accum->deny;
0393     accum->cond |= addend->cond & ~accum->allow & ~accum->deny;
0394     accum->hide &= addend->hide & ~accum->allow;
0395     accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny;
0396 }
0397 
0398 void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label,
0399                 int type, u32 request, struct aa_perms *perms)
0400 {
0401     /* TODO: doesn't yet handle extended types */
0402     unsigned int state;
0403 
0404     state = aa_dfa_next(profile->policy.dfa,
0405                 profile->policy.start[AA_CLASS_LABEL],
0406                 type);
0407     aa_label_match(profile, label, state, false, request, perms);
0408 }
0409 
0410 
0411 /* currently unused */
0412 int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target,
0413               u32 request, int type, u32 *deny,
0414               struct common_audit_data *sa)
0415 {
0416     struct aa_perms perms;
0417 
0418     aad(sa)->label = &profile->label;
0419     aad(sa)->peer = &target->label;
0420     aad(sa)->request = request;
0421 
0422     aa_profile_match_label(profile, &target->label, type, request, &perms);
0423     aa_apply_modes_to_perms(profile, &perms);
0424     *deny |= request & perms.deny;
0425     return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb);
0426 }
0427 
0428 /**
0429  * aa_check_perms - do audit mode selection based on perms set
0430  * @profile: profile being checked
0431  * @perms: perms computed for the request
0432  * @request: requested perms
0433  * @deny: Returns: explicit deny set
0434  * @sa: initialized audit structure (MAY BE NULL if not auditing)
0435  * @cb: callback fn for type specific fields (MAY BE NULL)
0436  *
0437  * Returns: 0 if permission else error code
0438  *
0439  * Note: profile audit modes need to be set before calling by setting the
0440  *       perm masks appropriately.
0441  *
0442  *       If not auditing then complain mode is not enabled and the
0443  *       error code will indicate whether there was an explicit deny
0444  *   with a positive value.
0445  */
0446 int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms,
0447            u32 request, struct common_audit_data *sa,
0448            void (*cb)(struct audit_buffer *, void *))
0449 {
0450     int type, error;
0451     u32 denied = request & (~perms->allow | perms->deny);
0452 
0453     if (likely(!denied)) {
0454         /* mask off perms that are not being force audited */
0455         request &= perms->audit;
0456         if (!request || !sa)
0457             return 0;
0458 
0459         type = AUDIT_APPARMOR_AUDIT;
0460         error = 0;
0461     } else {
0462         error = -EACCES;
0463 
0464         if (denied & perms->kill)
0465             type = AUDIT_APPARMOR_KILL;
0466         else if (denied == (denied & perms->complain))
0467             type = AUDIT_APPARMOR_ALLOWED;
0468         else
0469             type = AUDIT_APPARMOR_DENIED;
0470 
0471         if (denied == (denied & perms->hide))
0472             error = -ENOENT;
0473 
0474         denied &= ~perms->quiet;
0475         if (!sa || !denied)
0476             return error;
0477     }
0478 
0479     if (sa) {
0480         aad(sa)->label = &profile->label;
0481         aad(sa)->request = request;
0482         aad(sa)->denied = denied;
0483         aad(sa)->error = error;
0484         aa_audit_msg(type, sa, cb);
0485     }
0486 
0487     if (type == AUDIT_APPARMOR_ALLOWED)
0488         error = 0;
0489 
0490     return error;
0491 }
0492 
0493 
0494 /**
0495  * aa_policy_init - initialize a policy structure
0496  * @policy: policy to initialize  (NOT NULL)
0497  * @prefix: prefix name if any is required.  (MAYBE NULL)
0498  * @name: name of the policy, init will make a copy of it  (NOT NULL)
0499  * @gfp: allocation mode
0500  *
0501  * Note: this fn creates a copy of strings passed in
0502  *
0503  * Returns: true if policy init successful
0504  */
0505 bool aa_policy_init(struct aa_policy *policy, const char *prefix,
0506             const char *name, gfp_t gfp)
0507 {
0508     char *hname;
0509 
0510     /* freed by policy_free */
0511     if (prefix) {
0512         hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp);
0513         if (hname)
0514             sprintf(hname, "%s//%s", prefix, name);
0515     } else {
0516         hname = aa_str_alloc(strlen(name) + 1, gfp);
0517         if (hname)
0518             strcpy(hname, name);
0519     }
0520     if (!hname)
0521         return false;
0522     policy->hname = hname;
0523     /* base.name is a substring of fqname */
0524     policy->name = basename(policy->hname);
0525     INIT_LIST_HEAD(&policy->list);
0526     INIT_LIST_HEAD(&policy->profiles);
0527 
0528     return true;
0529 }
0530 
0531 /**
0532  * aa_policy_destroy - free the elements referenced by @policy
0533  * @policy: policy that is to have its elements freed  (NOT NULL)
0534  */
0535 void aa_policy_destroy(struct aa_policy *policy)
0536 {
0537     AA_BUG(on_list_rcu(&policy->profiles));
0538     AA_BUG(on_list_rcu(&policy->list));
0539 
0540     /* don't free name as its a subset of hname */
0541     aa_put_str(policy->hname);
0542 }