1cdff2642SJohn Johansen /* 2cdff2642SJohn Johansen * AppArmor security module 3cdff2642SJohn Johansen * 4cdff2642SJohn Johansen * This file contains basic common functions used in AppArmor 5cdff2642SJohn Johansen * 6cdff2642SJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 7cdff2642SJohn Johansen * Copyright 2009-2010 Canonical Ltd. 8cdff2642SJohn Johansen * 9cdff2642SJohn Johansen * This program is free software; you can redistribute it and/or 10cdff2642SJohn Johansen * modify it under the terms of the GNU General Public License as 11cdff2642SJohn Johansen * published by the Free Software Foundation, version 2 of the 12cdff2642SJohn Johansen * License. 13cdff2642SJohn Johansen */ 14cdff2642SJohn Johansen 153b0aaf58SJohn Johansen #include <linux/ctype.h> 16b7f080cfSAlexey Dobriyan #include <linux/mm.h> 17cdff2642SJohn Johansen #include <linux/slab.h> 18cdff2642SJohn Johansen #include <linux/string.h> 19cdff2642SJohn Johansen #include <linux/vmalloc.h> 20cdff2642SJohn Johansen 21cdff2642SJohn Johansen #include "include/audit.h" 2232c3df63SJames Morris #include "include/apparmor.h" 2312557dcbSJohn Johansen #include "include/lib.h" 24fc7e0b26SJohn Johansen #include "include/perms.h" 25fe6bb31fSJohn Johansen #include "include/policy.h" 26cdff2642SJohn Johansen 272d679f3cSJohn Johansen struct aa_perms nullperms; 28aa9aeea8SJohn Johansen struct aa_perms allperms = { .allow = ALL_PERMS_MASK, 29aa9aeea8SJohn Johansen .quiet = ALL_PERMS_MASK, 30aa9aeea8SJohn Johansen .hide = ALL_PERMS_MASK }; 31aa9aeea8SJohn Johansen 32cdff2642SJohn Johansen /** 33cdff2642SJohn Johansen * aa_split_fqname - split a fqname into a profile and namespace name 34cdff2642SJohn Johansen * @fqname: a full qualified name in namespace profile format (NOT NULL) 35cdff2642SJohn Johansen * @ns_name: pointer to portion of the string containing the ns name (NOT NULL) 36cdff2642SJohn Johansen * 37cdff2642SJohn Johansen * Returns: profile name or NULL if one is not specified 38cdff2642SJohn Johansen * 39cdff2642SJohn Johansen * Split a namespace name from a profile name (see policy.c for naming 40cdff2642SJohn Johansen * description). If a portion of the name is missing it returns NULL for 41cdff2642SJohn Johansen * that portion. 42cdff2642SJohn Johansen * 43cdff2642SJohn Johansen * NOTE: may modify the @fqname string. The pointers returned point 44cdff2642SJohn Johansen * into the @fqname string. 45cdff2642SJohn Johansen */ 46cdff2642SJohn Johansen char *aa_split_fqname(char *fqname, char **ns_name) 47cdff2642SJohn Johansen { 48cdff2642SJohn Johansen char *name = strim(fqname); 49cdff2642SJohn Johansen 50cdff2642SJohn Johansen *ns_name = NULL; 51cdff2642SJohn Johansen if (name[0] == ':') { 52cdff2642SJohn Johansen char *split = strchr(&name[1], ':'); 5304ccd53fSJohn Johansen *ns_name = skip_spaces(&name[1]); 54cdff2642SJohn Johansen if (split) { 55cdff2642SJohn Johansen /* overwrite ':' with \0 */ 562654bfbcSJohn Johansen *split++ = 0; 572654bfbcSJohn Johansen if (strncmp(split, "//", 2) == 0) 582654bfbcSJohn Johansen split += 2; 592654bfbcSJohn Johansen name = skip_spaces(split); 60cdff2642SJohn Johansen } else 61cdff2642SJohn Johansen /* a ns name without a following profile is allowed */ 62cdff2642SJohn Johansen name = NULL; 63cdff2642SJohn Johansen } 64cdff2642SJohn Johansen if (name && *name == 0) 65cdff2642SJohn Johansen name = NULL; 66cdff2642SJohn Johansen 67cdff2642SJohn Johansen return name; 68cdff2642SJohn Johansen } 69cdff2642SJohn Johansen 70cdff2642SJohn Johansen /** 713b0aaf58SJohn Johansen * skipn_spaces - Removes leading whitespace from @str. 723b0aaf58SJohn Johansen * @str: The string to be stripped. 733b0aaf58SJohn Johansen * 743b0aaf58SJohn Johansen * Returns a pointer to the first non-whitespace character in @str. 753b0aaf58SJohn Johansen * if all whitespace will return NULL 763b0aaf58SJohn Johansen */ 773b0aaf58SJohn Johansen 78b91deb9dSJohn Johansen const char *skipn_spaces(const char *str, size_t n) 793b0aaf58SJohn Johansen { 803b0aaf58SJohn Johansen for (; n && isspace(*str); --n) 813b0aaf58SJohn Johansen ++str; 823b0aaf58SJohn Johansen if (n) 833b0aaf58SJohn Johansen return (char *)str; 843b0aaf58SJohn Johansen return NULL; 853b0aaf58SJohn Johansen } 863b0aaf58SJohn Johansen 873b0aaf58SJohn Johansen const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, 883b0aaf58SJohn Johansen size_t *ns_len) 893b0aaf58SJohn Johansen { 903b0aaf58SJohn Johansen const char *end = fqname + n; 913b0aaf58SJohn Johansen const char *name = skipn_spaces(fqname, n); 923b0aaf58SJohn Johansen 933b0aaf58SJohn Johansen *ns_name = NULL; 943b0aaf58SJohn Johansen *ns_len = 0; 95*250f2da4SZubin Mithra 96*250f2da4SZubin Mithra if (!name) 97*250f2da4SZubin Mithra return NULL; 98*250f2da4SZubin Mithra 993b0aaf58SJohn Johansen if (name[0] == ':') { 1003b0aaf58SJohn Johansen char *split = strnchr(&name[1], end - &name[1], ':'); 1013b0aaf58SJohn Johansen *ns_name = skipn_spaces(&name[1], end - &name[1]); 1023b0aaf58SJohn Johansen if (!*ns_name) 1033b0aaf58SJohn Johansen return NULL; 1043b0aaf58SJohn Johansen if (split) { 1053b0aaf58SJohn Johansen *ns_len = split - *ns_name; 1063b0aaf58SJohn Johansen if (*ns_len == 0) 1073b0aaf58SJohn Johansen *ns_name = NULL; 1083b0aaf58SJohn Johansen split++; 1093b0aaf58SJohn Johansen if (end - split > 1 && strncmp(split, "//", 2) == 0) 1103b0aaf58SJohn Johansen split += 2; 1113b0aaf58SJohn Johansen name = skipn_spaces(split, end - split); 1123b0aaf58SJohn Johansen } else { 1133b0aaf58SJohn Johansen /* a ns name without a following profile is allowed */ 1143b0aaf58SJohn Johansen name = NULL; 1153b0aaf58SJohn Johansen *ns_len = end - *ns_name; 1163b0aaf58SJohn Johansen } 1173b0aaf58SJohn Johansen } 1183b0aaf58SJohn Johansen if (name && *name == 0) 1193b0aaf58SJohn Johansen name = NULL; 1203b0aaf58SJohn Johansen 1213b0aaf58SJohn Johansen return name; 1223b0aaf58SJohn Johansen } 1233b0aaf58SJohn Johansen 1243b0aaf58SJohn Johansen /** 125cdff2642SJohn Johansen * aa_info_message - log a none profile related status message 126cdff2642SJohn Johansen * @str: message to log 127cdff2642SJohn Johansen */ 128cdff2642SJohn Johansen void aa_info_message(const char *str) 129cdff2642SJohn Johansen { 130cdff2642SJohn Johansen if (audit_enabled) { 131ef88a7acSJohn Johansen DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL); 132ef88a7acSJohn Johansen 133ef88a7acSJohn Johansen aad(&sa)->info = str; 134cdff2642SJohn Johansen aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); 135cdff2642SJohn Johansen } 136cdff2642SJohn Johansen printk(KERN_INFO "AppArmor: %s\n", str); 137cdff2642SJohn Johansen } 138cdff2642SJohn Johansen 139a1bd627bSJohn Johansen __counted char *aa_str_alloc(int size, gfp_t gfp) 140a1bd627bSJohn Johansen { 141a1bd627bSJohn Johansen struct counted_str *str; 142a1bd627bSJohn Johansen 143a1bd627bSJohn Johansen str = kmalloc(sizeof(struct counted_str) + size, gfp); 144a1bd627bSJohn Johansen if (!str) 145a1bd627bSJohn Johansen return NULL; 146a1bd627bSJohn Johansen 147a1bd627bSJohn Johansen kref_init(&str->count); 148a1bd627bSJohn Johansen return str->name; 149a1bd627bSJohn Johansen } 150a1bd627bSJohn Johansen 151a1bd627bSJohn Johansen void aa_str_kref(struct kref *kref) 152a1bd627bSJohn Johansen { 153a1bd627bSJohn Johansen kfree(container_of(kref, struct counted_str, count)); 154a1bd627bSJohn Johansen } 155a1bd627bSJohn Johansen 156a1bd627bSJohn Johansen 157e53cfe6cSJohn Johansen const char aa_file_perm_chrs[] = "xwracd km l "; 158e53cfe6cSJohn Johansen const char *aa_file_perm_names[] = { 159e53cfe6cSJohn Johansen "exec", 160e53cfe6cSJohn Johansen "write", 161e53cfe6cSJohn Johansen "read", 162e53cfe6cSJohn Johansen "append", 163e53cfe6cSJohn Johansen 164e53cfe6cSJohn Johansen "create", 165e53cfe6cSJohn Johansen "delete", 166e53cfe6cSJohn Johansen "open", 167e53cfe6cSJohn Johansen "rename", 168e53cfe6cSJohn Johansen 169e53cfe6cSJohn Johansen "setattr", 170e53cfe6cSJohn Johansen "getattr", 171e53cfe6cSJohn Johansen "setcred", 172e53cfe6cSJohn Johansen "getcred", 173e53cfe6cSJohn Johansen 174e53cfe6cSJohn Johansen "chmod", 175e53cfe6cSJohn Johansen "chown", 176e53cfe6cSJohn Johansen "chgrp", 177e53cfe6cSJohn Johansen "lock", 178e53cfe6cSJohn Johansen 179e53cfe6cSJohn Johansen "mmap", 180e53cfe6cSJohn Johansen "mprot", 181e53cfe6cSJohn Johansen "link", 182e53cfe6cSJohn Johansen "snapshot", 183e53cfe6cSJohn Johansen 184e53cfe6cSJohn Johansen "unknown", 185e53cfe6cSJohn Johansen "unknown", 186e53cfe6cSJohn Johansen "unknown", 187e53cfe6cSJohn Johansen "unknown", 188e53cfe6cSJohn Johansen 189e53cfe6cSJohn Johansen "unknown", 190e53cfe6cSJohn Johansen "unknown", 191e53cfe6cSJohn Johansen "unknown", 192e53cfe6cSJohn Johansen "unknown", 193e53cfe6cSJohn Johansen 194e53cfe6cSJohn Johansen "stack", 195e53cfe6cSJohn Johansen "change_onexec", 196e53cfe6cSJohn Johansen "change_profile", 197e53cfe6cSJohn Johansen "change_hat", 198e53cfe6cSJohn Johansen }; 199e53cfe6cSJohn Johansen 200e53cfe6cSJohn Johansen /** 201e53cfe6cSJohn Johansen * aa_perm_mask_to_str - convert a perm mask to its short string 202e53cfe6cSJohn Johansen * @str: character buffer to store string in (at least 10 characters) 2037f3ebcf2STyler Hicks * @str_size: size of the @str buffer 2047f3ebcf2STyler Hicks * @chrs: NUL-terminated character buffer of permission characters 205e53cfe6cSJohn Johansen * @mask: permission mask to convert 206e53cfe6cSJohn Johansen */ 2077f3ebcf2STyler Hicks void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask) 208e53cfe6cSJohn Johansen { 209e53cfe6cSJohn Johansen unsigned int i, perm = 1; 2107f3ebcf2STyler Hicks size_t num_chrs = strlen(chrs); 211e53cfe6cSJohn Johansen 2127f3ebcf2STyler Hicks for (i = 0; i < num_chrs; perm <<= 1, i++) { 2137f3ebcf2STyler Hicks if (mask & perm) { 2147f3ebcf2STyler Hicks /* Ensure that one byte is left for NUL-termination */ 2157f3ebcf2STyler Hicks if (WARN_ON_ONCE(str_size <= 1)) 2167f3ebcf2STyler Hicks break; 2177f3ebcf2STyler Hicks 218e53cfe6cSJohn Johansen *str++ = chrs[i]; 2197f3ebcf2STyler Hicks str_size--; 2207f3ebcf2STyler Hicks } 221e53cfe6cSJohn Johansen } 222e53cfe6cSJohn Johansen *str = '\0'; 223e53cfe6cSJohn Johansen } 224e53cfe6cSJohn Johansen 22556974a6fSJohn Johansen void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, 22656974a6fSJohn Johansen u32 mask) 227aa9aeea8SJohn Johansen { 228aa9aeea8SJohn Johansen const char *fmt = "%s"; 229aa9aeea8SJohn Johansen unsigned int i, perm = 1; 230aa9aeea8SJohn Johansen bool prev = false; 231aa9aeea8SJohn Johansen 232aa9aeea8SJohn Johansen for (i = 0; i < 32; perm <<= 1, i++) { 233aa9aeea8SJohn Johansen if (mask & perm) { 234aa9aeea8SJohn Johansen audit_log_format(ab, fmt, names[i]); 235aa9aeea8SJohn Johansen if (!prev) { 236aa9aeea8SJohn Johansen prev = true; 237aa9aeea8SJohn Johansen fmt = " %s"; 238aa9aeea8SJohn Johansen } 239aa9aeea8SJohn Johansen } 240aa9aeea8SJohn Johansen } 241aa9aeea8SJohn Johansen } 242aa9aeea8SJohn Johansen 243aa9aeea8SJohn Johansen void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, 24456974a6fSJohn Johansen u32 chrsmask, const char * const *names, u32 namesmask) 245aa9aeea8SJohn Johansen { 246aa9aeea8SJohn Johansen char str[33]; 247aa9aeea8SJohn Johansen 248aa9aeea8SJohn Johansen audit_log_format(ab, "\""); 249aa9aeea8SJohn Johansen if ((mask & chrsmask) && chrs) { 2507f3ebcf2STyler Hicks aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask); 251aa9aeea8SJohn Johansen mask &= ~chrsmask; 252aa9aeea8SJohn Johansen audit_log_format(ab, "%s", str); 253aa9aeea8SJohn Johansen if (mask & namesmask) 254aa9aeea8SJohn Johansen audit_log_format(ab, " "); 255aa9aeea8SJohn Johansen } 256aa9aeea8SJohn Johansen if ((mask & namesmask) && names) 257aa9aeea8SJohn Johansen aa_audit_perm_names(ab, names, mask & namesmask); 258aa9aeea8SJohn Johansen audit_log_format(ab, "\""); 259aa9aeea8SJohn Johansen } 260aa9aeea8SJohn Johansen 261aa9aeea8SJohn Johansen /** 262637f688dSJohn Johansen * aa_audit_perms_cb - generic callback fn for auditing perms 263637f688dSJohn Johansen * @ab: audit buffer (NOT NULL) 264637f688dSJohn Johansen * @va: audit struct to audit values of (NOT NULL) 265637f688dSJohn Johansen */ 266637f688dSJohn Johansen static void aa_audit_perms_cb(struct audit_buffer *ab, void *va) 267637f688dSJohn Johansen { 268637f688dSJohn Johansen struct common_audit_data *sa = va; 269637f688dSJohn Johansen 270637f688dSJohn Johansen if (aad(sa)->request) { 271637f688dSJohn Johansen audit_log_format(ab, " requested_mask="); 272637f688dSJohn Johansen aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs, 273637f688dSJohn Johansen PERMS_CHRS_MASK, aa_file_perm_names, 274637f688dSJohn Johansen PERMS_NAMES_MASK); 275637f688dSJohn Johansen } 276637f688dSJohn Johansen if (aad(sa)->denied) { 277637f688dSJohn Johansen audit_log_format(ab, "denied_mask="); 278637f688dSJohn Johansen aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs, 279637f688dSJohn Johansen PERMS_CHRS_MASK, aa_file_perm_names, 280637f688dSJohn Johansen PERMS_NAMES_MASK); 281637f688dSJohn Johansen } 282637f688dSJohn Johansen audit_log_format(ab, " peer="); 283637f688dSJohn Johansen aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, 284637f688dSJohn Johansen FLAGS_NONE, GFP_ATOMIC); 285637f688dSJohn Johansen } 286637f688dSJohn Johansen 287637f688dSJohn Johansen /** 288aa9aeea8SJohn Johansen * aa_apply_modes_to_perms - apply namespace and profile flags to perms 289aa9aeea8SJohn Johansen * @profile: that perms where computed from 290aa9aeea8SJohn Johansen * @perms: perms to apply mode modifiers to 291aa9aeea8SJohn Johansen * 292aa9aeea8SJohn Johansen * TODO: split into profile and ns based flags for when accumulating perms 293aa9aeea8SJohn Johansen */ 294aa9aeea8SJohn Johansen void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms) 295aa9aeea8SJohn Johansen { 296aa9aeea8SJohn Johansen switch (AUDIT_MODE(profile)) { 297aa9aeea8SJohn Johansen case AUDIT_ALL: 298aa9aeea8SJohn Johansen perms->audit = ALL_PERMS_MASK; 299aa9aeea8SJohn Johansen /* fall through */ 300aa9aeea8SJohn Johansen case AUDIT_NOQUIET: 301aa9aeea8SJohn Johansen perms->quiet = 0; 302aa9aeea8SJohn Johansen break; 303aa9aeea8SJohn Johansen case AUDIT_QUIET: 304aa9aeea8SJohn Johansen perms->audit = 0; 305aa9aeea8SJohn Johansen /* fall through */ 306aa9aeea8SJohn Johansen case AUDIT_QUIET_DENIED: 307aa9aeea8SJohn Johansen perms->quiet = ALL_PERMS_MASK; 308aa9aeea8SJohn Johansen break; 309aa9aeea8SJohn Johansen } 310aa9aeea8SJohn Johansen 311aa9aeea8SJohn Johansen if (KILL_MODE(profile)) 312aa9aeea8SJohn Johansen perms->kill = ALL_PERMS_MASK; 313aa9aeea8SJohn Johansen else if (COMPLAIN_MODE(profile)) 314aa9aeea8SJohn Johansen perms->complain = ALL_PERMS_MASK; 315aa9aeea8SJohn Johansen /* 316aa9aeea8SJohn Johansen * TODO: 317aa9aeea8SJohn Johansen * else if (PROMPT_MODE(profile)) 318aa9aeea8SJohn Johansen * perms->prompt = ALL_PERMS_MASK; 319aa9aeea8SJohn Johansen */ 320aa9aeea8SJohn Johansen } 321aa9aeea8SJohn Johansen 322aa9aeea8SJohn Johansen static u32 map_other(u32 x) 323aa9aeea8SJohn Johansen { 324aa9aeea8SJohn Johansen return ((x & 0x3) << 8) | /* SETATTR/GETATTR */ 325aa9aeea8SJohn Johansen ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */ 326aa9aeea8SJohn Johansen ((x & 0x60) << 19); /* SETOPT/GETOPT */ 327aa9aeea8SJohn Johansen } 328aa9aeea8SJohn Johansen 329aa9aeea8SJohn Johansen void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, 330aa9aeea8SJohn Johansen struct aa_perms *perms) 331aa9aeea8SJohn Johansen { 3327bba39aeSArnd Bergmann *perms = (struct aa_perms) { 3337bba39aeSArnd Bergmann .allow = dfa_user_allow(dfa, state), 3347bba39aeSArnd Bergmann .audit = dfa_user_audit(dfa, state), 3357bba39aeSArnd Bergmann .quiet = dfa_user_quiet(dfa, state), 3367bba39aeSArnd Bergmann }; 337aa9aeea8SJohn Johansen 338aa9aeea8SJohn Johansen /* for v5 perm mapping in the policydb, the other set is used 339aa9aeea8SJohn Johansen * to extend the general perm set 340aa9aeea8SJohn Johansen */ 341aa9aeea8SJohn Johansen perms->allow |= map_other(dfa_other_allow(dfa, state)); 342aa9aeea8SJohn Johansen perms->audit |= map_other(dfa_other_audit(dfa, state)); 343aa9aeea8SJohn Johansen perms->quiet |= map_other(dfa_other_quiet(dfa, state)); 344aa9aeea8SJohn Johansen // perms->xindex = dfa_user_xindex(dfa, state); 345aa9aeea8SJohn Johansen } 346aa9aeea8SJohn Johansen 347cdff2642SJohn Johansen /** 348637f688dSJohn Johansen * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms 349637f688dSJohn Johansen * @accum - perms struct to accumulate into 350637f688dSJohn Johansen * @addend - perms struct to add to @accum 351637f688dSJohn Johansen */ 352637f688dSJohn Johansen void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend) 353637f688dSJohn Johansen { 354637f688dSJohn Johansen accum->deny |= addend->deny; 355637f688dSJohn Johansen accum->allow &= addend->allow & ~addend->deny; 356637f688dSJohn Johansen accum->audit |= addend->audit & addend->allow; 357637f688dSJohn Johansen accum->quiet &= addend->quiet & ~addend->allow; 358637f688dSJohn Johansen accum->kill |= addend->kill & ~addend->allow; 359637f688dSJohn Johansen accum->stop |= addend->stop & ~addend->allow; 360637f688dSJohn Johansen accum->complain |= addend->complain & ~addend->allow & ~addend->deny; 361637f688dSJohn Johansen accum->cond |= addend->cond & ~addend->allow & ~addend->deny; 362637f688dSJohn Johansen accum->hide &= addend->hide & ~addend->allow; 363637f688dSJohn Johansen accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny; 364637f688dSJohn Johansen } 365637f688dSJohn Johansen 366637f688dSJohn Johansen /** 367637f688dSJohn Johansen * aa_perms_accum - accumulate perms, masking off overlapping perms 368637f688dSJohn Johansen * @accum - perms struct to accumulate into 369637f688dSJohn Johansen * @addend - perms struct to add to @accum 370637f688dSJohn Johansen */ 371637f688dSJohn Johansen void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend) 372637f688dSJohn Johansen { 373637f688dSJohn Johansen accum->deny |= addend->deny; 374637f688dSJohn Johansen accum->allow &= addend->allow & ~accum->deny; 375637f688dSJohn Johansen accum->audit |= addend->audit & accum->allow; 376637f688dSJohn Johansen accum->quiet &= addend->quiet & ~accum->allow; 377637f688dSJohn Johansen accum->kill |= addend->kill & ~accum->allow; 378637f688dSJohn Johansen accum->stop |= addend->stop & ~accum->allow; 379637f688dSJohn Johansen accum->complain |= addend->complain & ~accum->allow & ~accum->deny; 380637f688dSJohn Johansen accum->cond |= addend->cond & ~accum->allow & ~accum->deny; 381637f688dSJohn Johansen accum->hide &= addend->hide & ~accum->allow; 382637f688dSJohn Johansen accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny; 383637f688dSJohn Johansen } 384637f688dSJohn Johansen 385637f688dSJohn Johansen void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label, 386637f688dSJohn Johansen int type, u32 request, struct aa_perms *perms) 387637f688dSJohn Johansen { 388637f688dSJohn Johansen /* TODO: doesn't yet handle extended types */ 389637f688dSJohn Johansen unsigned int state; 390637f688dSJohn Johansen 391637f688dSJohn Johansen state = aa_dfa_next(profile->policy.dfa, 392637f688dSJohn Johansen profile->policy.start[AA_CLASS_LABEL], 393637f688dSJohn Johansen type); 394637f688dSJohn Johansen aa_label_match(profile, label, state, false, request, perms); 395637f688dSJohn Johansen } 396637f688dSJohn Johansen 397637f688dSJohn Johansen 398637f688dSJohn Johansen /* currently unused */ 399637f688dSJohn Johansen int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, 400637f688dSJohn Johansen u32 request, int type, u32 *deny, 401637f688dSJohn Johansen struct common_audit_data *sa) 402637f688dSJohn Johansen { 403637f688dSJohn Johansen struct aa_perms perms; 404637f688dSJohn Johansen 405637f688dSJohn Johansen aad(sa)->label = &profile->label; 406637f688dSJohn Johansen aad(sa)->peer = &target->label; 407637f688dSJohn Johansen aad(sa)->request = request; 408637f688dSJohn Johansen 409637f688dSJohn Johansen aa_profile_match_label(profile, &target->label, type, request, &perms); 410637f688dSJohn Johansen aa_apply_modes_to_perms(profile, &perms); 411637f688dSJohn Johansen *deny |= request & perms.deny; 412637f688dSJohn Johansen return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb); 413637f688dSJohn Johansen } 414637f688dSJohn Johansen 415637f688dSJohn Johansen /** 416637f688dSJohn Johansen * aa_check_perms - do audit mode selection based on perms set 417637f688dSJohn Johansen * @profile: profile being checked 418637f688dSJohn Johansen * @perms: perms computed for the request 419637f688dSJohn Johansen * @request: requested perms 420637f688dSJohn Johansen * @deny: Returns: explicit deny set 421637f688dSJohn Johansen * @sa: initialized audit structure (MAY BE NULL if not auditing) 42269ad4a44SZygmunt Krynicki * @cb: callback fn for type specific fields (MAY BE NULL) 423637f688dSJohn Johansen * 424637f688dSJohn Johansen * Returns: 0 if permission else error code 425637f688dSJohn Johansen * 426637f688dSJohn Johansen * Note: profile audit modes need to be set before calling by setting the 427637f688dSJohn Johansen * perm masks appropriately. 428637f688dSJohn Johansen * 429637f688dSJohn Johansen * If not auditing then complain mode is not enabled and the 430637f688dSJohn Johansen * error code will indicate whether there was an explicit deny 431637f688dSJohn Johansen * with a positive value. 432637f688dSJohn Johansen */ 433637f688dSJohn Johansen int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, 434637f688dSJohn Johansen u32 request, struct common_audit_data *sa, 435637f688dSJohn Johansen void (*cb)(struct audit_buffer *, void *)) 436637f688dSJohn Johansen { 437637f688dSJohn Johansen int type, error; 438637f688dSJohn Johansen u32 denied = request & (~perms->allow | perms->deny); 439637f688dSJohn Johansen 440637f688dSJohn Johansen if (likely(!denied)) { 441637f688dSJohn Johansen /* mask off perms that are not being force audited */ 442637f688dSJohn Johansen request &= perms->audit; 443637f688dSJohn Johansen if (!request || !sa) 444637f688dSJohn Johansen return 0; 445637f688dSJohn Johansen 446637f688dSJohn Johansen type = AUDIT_APPARMOR_AUDIT; 447637f688dSJohn Johansen error = 0; 448637f688dSJohn Johansen } else { 449637f688dSJohn Johansen error = -EACCES; 450637f688dSJohn Johansen 451637f688dSJohn Johansen if (denied & perms->kill) 452637f688dSJohn Johansen type = AUDIT_APPARMOR_KILL; 453637f688dSJohn Johansen else if (denied == (denied & perms->complain)) 454637f688dSJohn Johansen type = AUDIT_APPARMOR_ALLOWED; 455637f688dSJohn Johansen else 456637f688dSJohn Johansen type = AUDIT_APPARMOR_DENIED; 457637f688dSJohn Johansen 458637f688dSJohn Johansen if (denied == (denied & perms->hide)) 459637f688dSJohn Johansen error = -ENOENT; 460637f688dSJohn Johansen 461637f688dSJohn Johansen denied &= ~perms->quiet; 462637f688dSJohn Johansen if (!sa || !denied) 463637f688dSJohn Johansen return error; 464637f688dSJohn Johansen } 465637f688dSJohn Johansen 466637f688dSJohn Johansen if (sa) { 467637f688dSJohn Johansen aad(sa)->label = &profile->label; 468637f688dSJohn Johansen aad(sa)->request = request; 469637f688dSJohn Johansen aad(sa)->denied = denied; 470637f688dSJohn Johansen aad(sa)->error = error; 471637f688dSJohn Johansen aa_audit_msg(type, sa, cb); 472637f688dSJohn Johansen } 473637f688dSJohn Johansen 474637f688dSJohn Johansen if (type == AUDIT_APPARMOR_ALLOWED) 475637f688dSJohn Johansen error = 0; 476637f688dSJohn Johansen 477637f688dSJohn Johansen return error; 478637f688dSJohn Johansen } 479637f688dSJohn Johansen 480637f688dSJohn Johansen 481637f688dSJohn Johansen /** 482fe6bb31fSJohn Johansen * aa_policy_init - initialize a policy structure 483fe6bb31fSJohn Johansen * @policy: policy to initialize (NOT NULL) 484fe6bb31fSJohn Johansen * @prefix: prefix name if any is required. (MAYBE NULL) 485fe6bb31fSJohn Johansen * @name: name of the policy, init will make a copy of it (NOT NULL) 486a1bd627bSJohn Johansen * @gfp: allocation mode 487fe6bb31fSJohn Johansen * 488fe6bb31fSJohn Johansen * Note: this fn creates a copy of strings passed in 489fe6bb31fSJohn Johansen * 490fe6bb31fSJohn Johansen * Returns: true if policy init successful 491fe6bb31fSJohn Johansen */ 492fe6bb31fSJohn Johansen bool aa_policy_init(struct aa_policy *policy, const char *prefix, 493d102d895SJohn Johansen const char *name, gfp_t gfp) 494fe6bb31fSJohn Johansen { 495a1bd627bSJohn Johansen char *hname; 496a1bd627bSJohn Johansen 497fe6bb31fSJohn Johansen /* freed by policy_free */ 498fe6bb31fSJohn Johansen if (prefix) { 499a1bd627bSJohn Johansen hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp); 500a1bd627bSJohn Johansen if (hname) 501a1bd627bSJohn Johansen sprintf(hname, "%s//%s", prefix, name); 502a1bd627bSJohn Johansen } else { 503a1bd627bSJohn Johansen hname = aa_str_alloc(strlen(name) + 1, gfp); 504a1bd627bSJohn Johansen if (hname) 505a1bd627bSJohn Johansen strcpy(hname, name); 506a1bd627bSJohn Johansen } 507a1bd627bSJohn Johansen if (!hname) 508b9c42ac7Skbuild test robot return false; 509a1bd627bSJohn Johansen policy->hname = hname; 510fe6bb31fSJohn Johansen /* base.name is a substring of fqname */ 511d102d895SJohn Johansen policy->name = basename(policy->hname); 512fe6bb31fSJohn Johansen INIT_LIST_HEAD(&policy->list); 513fe6bb31fSJohn Johansen INIT_LIST_HEAD(&policy->profiles); 514fe6bb31fSJohn Johansen 515b9c42ac7Skbuild test robot return true; 516fe6bb31fSJohn Johansen } 517fe6bb31fSJohn Johansen 518fe6bb31fSJohn Johansen /** 519fe6bb31fSJohn Johansen * aa_policy_destroy - free the elements referenced by @policy 520fe6bb31fSJohn Johansen * @policy: policy that is to have its elements freed (NOT NULL) 521fe6bb31fSJohn Johansen */ 522fe6bb31fSJohn Johansen void aa_policy_destroy(struct aa_policy *policy) 523fe6bb31fSJohn Johansen { 5245fd1b95fSJohn Johansen AA_BUG(on_list_rcu(&policy->profiles)); 5255fd1b95fSJohn Johansen AA_BUG(on_list_rcu(&policy->list)); 526fe6bb31fSJohn Johansen 527fe6bb31fSJohn Johansen /* don't free name as its a subset of hname */ 528a1bd627bSJohn Johansen aa_put_str(policy->hname); 529fe6bb31fSJohn Johansen } 530