1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2cdff2642SJohn Johansen /* 3cdff2642SJohn Johansen * AppArmor security module 4cdff2642SJohn Johansen * 5cdff2642SJohn Johansen * This file contains basic common functions used in AppArmor 6cdff2642SJohn Johansen * 7cdff2642SJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 8cdff2642SJohn Johansen * Copyright 2009-2010 Canonical Ltd. 9cdff2642SJohn Johansen */ 10cdff2642SJohn Johansen 113b0aaf58SJohn Johansen #include <linux/ctype.h> 12b7f080cfSAlexey Dobriyan #include <linux/mm.h> 13cdff2642SJohn Johansen #include <linux/slab.h> 14cdff2642SJohn Johansen #include <linux/string.h> 15cdff2642SJohn Johansen #include <linux/vmalloc.h> 16cdff2642SJohn Johansen 17cdff2642SJohn Johansen #include "include/audit.h" 1832c3df63SJames Morris #include "include/apparmor.h" 1912557dcbSJohn Johansen #include "include/lib.h" 20fc7e0b26SJohn Johansen #include "include/perms.h" 21fe6bb31fSJohn Johansen #include "include/policy.h" 22cdff2642SJohn Johansen 232d679f3cSJohn Johansen struct aa_perms nullperms; 24aa9aeea8SJohn Johansen struct aa_perms allperms = { .allow = ALL_PERMS_MASK, 25aa9aeea8SJohn Johansen .quiet = ALL_PERMS_MASK, 26aa9aeea8SJohn Johansen .hide = ALL_PERMS_MASK }; 27aa9aeea8SJohn Johansen 28cdff2642SJohn Johansen /** 29*90917d5bSJohn Johansen * aa_free_str_table - free entries str table 30*90917d5bSJohn Johansen * @str: the string table to free (MAYBE NULL) 31*90917d5bSJohn Johansen */ 32*90917d5bSJohn Johansen void aa_free_str_table(struct aa_str_table *t) 33*90917d5bSJohn Johansen { 34*90917d5bSJohn Johansen int i; 35*90917d5bSJohn Johansen 36*90917d5bSJohn Johansen if (t) { 37*90917d5bSJohn Johansen if (!t->table) 38*90917d5bSJohn Johansen return; 39*90917d5bSJohn Johansen 40*90917d5bSJohn Johansen for (i = 0; i < t->size; i++) 41*90917d5bSJohn Johansen kfree_sensitive(t->table[i]); 42*90917d5bSJohn Johansen kfree_sensitive(t->table); 43*90917d5bSJohn Johansen t->table = NULL; 44*90917d5bSJohn Johansen } 45*90917d5bSJohn Johansen } 46*90917d5bSJohn Johansen 47*90917d5bSJohn Johansen /** 48cdff2642SJohn Johansen * aa_split_fqname - split a fqname into a profile and namespace name 49cdff2642SJohn Johansen * @fqname: a full qualified name in namespace profile format (NOT NULL) 50cdff2642SJohn Johansen * @ns_name: pointer to portion of the string containing the ns name (NOT NULL) 51cdff2642SJohn Johansen * 52cdff2642SJohn Johansen * Returns: profile name or NULL if one is not specified 53cdff2642SJohn Johansen * 54cdff2642SJohn Johansen * Split a namespace name from a profile name (see policy.c for naming 55cdff2642SJohn Johansen * description). If a portion of the name is missing it returns NULL for 56cdff2642SJohn Johansen * that portion. 57cdff2642SJohn Johansen * 58cdff2642SJohn Johansen * NOTE: may modify the @fqname string. The pointers returned point 59cdff2642SJohn Johansen * into the @fqname string. 60cdff2642SJohn Johansen */ 61cdff2642SJohn Johansen char *aa_split_fqname(char *fqname, char **ns_name) 62cdff2642SJohn Johansen { 63cdff2642SJohn Johansen char *name = strim(fqname); 64cdff2642SJohn Johansen 65cdff2642SJohn Johansen *ns_name = NULL; 66cdff2642SJohn Johansen if (name[0] == ':') { 67cdff2642SJohn Johansen char *split = strchr(&name[1], ':'); 6804ccd53fSJohn Johansen *ns_name = skip_spaces(&name[1]); 69cdff2642SJohn Johansen if (split) { 70cdff2642SJohn Johansen /* overwrite ':' with \0 */ 712654bfbcSJohn Johansen *split++ = 0; 722654bfbcSJohn Johansen if (strncmp(split, "//", 2) == 0) 732654bfbcSJohn Johansen split += 2; 742654bfbcSJohn Johansen name = skip_spaces(split); 75cdff2642SJohn Johansen } else 76cdff2642SJohn Johansen /* a ns name without a following profile is allowed */ 77cdff2642SJohn Johansen name = NULL; 78cdff2642SJohn Johansen } 79cdff2642SJohn Johansen if (name && *name == 0) 80cdff2642SJohn Johansen name = NULL; 81cdff2642SJohn Johansen 82cdff2642SJohn Johansen return name; 83cdff2642SJohn Johansen } 84cdff2642SJohn Johansen 85cdff2642SJohn Johansen /** 863b0aaf58SJohn Johansen * skipn_spaces - Removes leading whitespace from @str. 873b0aaf58SJohn Johansen * @str: The string to be stripped. 883b0aaf58SJohn Johansen * 893b0aaf58SJohn Johansen * Returns a pointer to the first non-whitespace character in @str. 903b0aaf58SJohn Johansen * if all whitespace will return NULL 913b0aaf58SJohn Johansen */ 923b0aaf58SJohn Johansen 93b91deb9dSJohn Johansen const char *skipn_spaces(const char *str, size_t n) 943b0aaf58SJohn Johansen { 953b0aaf58SJohn Johansen for (; n && isspace(*str); --n) 963b0aaf58SJohn Johansen ++str; 973b0aaf58SJohn Johansen if (n) 983b0aaf58SJohn Johansen return (char *)str; 993b0aaf58SJohn Johansen return NULL; 1003b0aaf58SJohn Johansen } 1013b0aaf58SJohn Johansen 1023b0aaf58SJohn Johansen const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, 1033b0aaf58SJohn Johansen size_t *ns_len) 1043b0aaf58SJohn Johansen { 1053b0aaf58SJohn Johansen const char *end = fqname + n; 1063b0aaf58SJohn Johansen const char *name = skipn_spaces(fqname, n); 1073b0aaf58SJohn Johansen 1083b0aaf58SJohn Johansen *ns_name = NULL; 1093b0aaf58SJohn Johansen *ns_len = 0; 110250f2da4SZubin Mithra 111250f2da4SZubin Mithra if (!name) 112250f2da4SZubin Mithra return NULL; 113250f2da4SZubin Mithra 1143b0aaf58SJohn Johansen if (name[0] == ':') { 1153b0aaf58SJohn Johansen char *split = strnchr(&name[1], end - &name[1], ':'); 1163b0aaf58SJohn Johansen *ns_name = skipn_spaces(&name[1], end - &name[1]); 1173b0aaf58SJohn Johansen if (!*ns_name) 1183b0aaf58SJohn Johansen return NULL; 1193b0aaf58SJohn Johansen if (split) { 1203b0aaf58SJohn Johansen *ns_len = split - *ns_name; 1213b0aaf58SJohn Johansen if (*ns_len == 0) 1223b0aaf58SJohn Johansen *ns_name = NULL; 1233b0aaf58SJohn Johansen split++; 1243b0aaf58SJohn Johansen if (end - split > 1 && strncmp(split, "//", 2) == 0) 1253b0aaf58SJohn Johansen split += 2; 1263b0aaf58SJohn Johansen name = skipn_spaces(split, end - split); 1273b0aaf58SJohn Johansen } else { 1283b0aaf58SJohn Johansen /* a ns name without a following profile is allowed */ 1293b0aaf58SJohn Johansen name = NULL; 1303b0aaf58SJohn Johansen *ns_len = end - *ns_name; 1313b0aaf58SJohn Johansen } 1323b0aaf58SJohn Johansen } 1333b0aaf58SJohn Johansen if (name && *name == 0) 1343b0aaf58SJohn Johansen name = NULL; 1353b0aaf58SJohn Johansen 1363b0aaf58SJohn Johansen return name; 1373b0aaf58SJohn Johansen } 1383b0aaf58SJohn Johansen 1393b0aaf58SJohn Johansen /** 140cdff2642SJohn Johansen * aa_info_message - log a none profile related status message 141cdff2642SJohn Johansen * @str: message to log 142cdff2642SJohn Johansen */ 143cdff2642SJohn Johansen void aa_info_message(const char *str) 144cdff2642SJohn Johansen { 145cdff2642SJohn Johansen if (audit_enabled) { 146ef88a7acSJohn Johansen DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL); 147ef88a7acSJohn Johansen 148ef88a7acSJohn Johansen aad(&sa)->info = str; 149cdff2642SJohn Johansen aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); 150cdff2642SJohn Johansen } 151cdff2642SJohn Johansen printk(KERN_INFO "AppArmor: %s\n", str); 152cdff2642SJohn Johansen } 153cdff2642SJohn Johansen 154a1bd627bSJohn Johansen __counted char *aa_str_alloc(int size, gfp_t gfp) 155a1bd627bSJohn Johansen { 156a1bd627bSJohn Johansen struct counted_str *str; 157a1bd627bSJohn Johansen 158c0ea4b91SGustavo A. R. Silva str = kmalloc(struct_size(str, name, size), gfp); 159a1bd627bSJohn Johansen if (!str) 160a1bd627bSJohn Johansen return NULL; 161a1bd627bSJohn Johansen 162a1bd627bSJohn Johansen kref_init(&str->count); 163a1bd627bSJohn Johansen return str->name; 164a1bd627bSJohn Johansen } 165a1bd627bSJohn Johansen 166a1bd627bSJohn Johansen void aa_str_kref(struct kref *kref) 167a1bd627bSJohn Johansen { 168a1bd627bSJohn Johansen kfree(container_of(kref, struct counted_str, count)); 169a1bd627bSJohn Johansen } 170a1bd627bSJohn Johansen 171a1bd627bSJohn Johansen 172e53cfe6cSJohn Johansen const char aa_file_perm_chrs[] = "xwracd km l "; 173e53cfe6cSJohn Johansen const char *aa_file_perm_names[] = { 174e53cfe6cSJohn Johansen "exec", 175e53cfe6cSJohn Johansen "write", 176e53cfe6cSJohn Johansen "read", 177e53cfe6cSJohn Johansen "append", 178e53cfe6cSJohn Johansen 179e53cfe6cSJohn Johansen "create", 180e53cfe6cSJohn Johansen "delete", 181e53cfe6cSJohn Johansen "open", 182e53cfe6cSJohn Johansen "rename", 183e53cfe6cSJohn Johansen 184e53cfe6cSJohn Johansen "setattr", 185e53cfe6cSJohn Johansen "getattr", 186e53cfe6cSJohn Johansen "setcred", 187e53cfe6cSJohn Johansen "getcred", 188e53cfe6cSJohn Johansen 189e53cfe6cSJohn Johansen "chmod", 190e53cfe6cSJohn Johansen "chown", 191e53cfe6cSJohn Johansen "chgrp", 192e53cfe6cSJohn Johansen "lock", 193e53cfe6cSJohn Johansen 194e53cfe6cSJohn Johansen "mmap", 195e53cfe6cSJohn Johansen "mprot", 196e53cfe6cSJohn Johansen "link", 197e53cfe6cSJohn Johansen "snapshot", 198e53cfe6cSJohn Johansen 199e53cfe6cSJohn Johansen "unknown", 200e53cfe6cSJohn Johansen "unknown", 201e53cfe6cSJohn Johansen "unknown", 202e53cfe6cSJohn Johansen "unknown", 203e53cfe6cSJohn Johansen 204e53cfe6cSJohn Johansen "unknown", 205e53cfe6cSJohn Johansen "unknown", 206e53cfe6cSJohn Johansen "unknown", 207e53cfe6cSJohn Johansen "unknown", 208e53cfe6cSJohn Johansen 209e53cfe6cSJohn Johansen "stack", 210e53cfe6cSJohn Johansen "change_onexec", 211e53cfe6cSJohn Johansen "change_profile", 212e53cfe6cSJohn Johansen "change_hat", 213e53cfe6cSJohn Johansen }; 214e53cfe6cSJohn Johansen 215e53cfe6cSJohn Johansen /** 216e53cfe6cSJohn Johansen * aa_perm_mask_to_str - convert a perm mask to its short string 217e53cfe6cSJohn Johansen * @str: character buffer to store string in (at least 10 characters) 2187f3ebcf2STyler Hicks * @str_size: size of the @str buffer 2197f3ebcf2STyler Hicks * @chrs: NUL-terminated character buffer of permission characters 220e53cfe6cSJohn Johansen * @mask: permission mask to convert 221e53cfe6cSJohn Johansen */ 2227f3ebcf2STyler Hicks void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask) 223e53cfe6cSJohn Johansen { 224e53cfe6cSJohn Johansen unsigned int i, perm = 1; 2257f3ebcf2STyler Hicks size_t num_chrs = strlen(chrs); 226e53cfe6cSJohn Johansen 2277f3ebcf2STyler Hicks for (i = 0; i < num_chrs; perm <<= 1, i++) { 2287f3ebcf2STyler Hicks if (mask & perm) { 2297f3ebcf2STyler Hicks /* Ensure that one byte is left for NUL-termination */ 2307f3ebcf2STyler Hicks if (WARN_ON_ONCE(str_size <= 1)) 2317f3ebcf2STyler Hicks break; 2327f3ebcf2STyler Hicks 233e53cfe6cSJohn Johansen *str++ = chrs[i]; 2347f3ebcf2STyler Hicks str_size--; 2357f3ebcf2STyler Hicks } 236e53cfe6cSJohn Johansen } 237e53cfe6cSJohn Johansen *str = '\0'; 238e53cfe6cSJohn Johansen } 239e53cfe6cSJohn Johansen 24056974a6fSJohn Johansen void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, 24156974a6fSJohn Johansen u32 mask) 242aa9aeea8SJohn Johansen { 243aa9aeea8SJohn Johansen const char *fmt = "%s"; 244aa9aeea8SJohn Johansen unsigned int i, perm = 1; 245aa9aeea8SJohn Johansen bool prev = false; 246aa9aeea8SJohn Johansen 247aa9aeea8SJohn Johansen for (i = 0; i < 32; perm <<= 1, i++) { 248aa9aeea8SJohn Johansen if (mask & perm) { 249aa9aeea8SJohn Johansen audit_log_format(ab, fmt, names[i]); 250aa9aeea8SJohn Johansen if (!prev) { 251aa9aeea8SJohn Johansen prev = true; 252aa9aeea8SJohn Johansen fmt = " %s"; 253aa9aeea8SJohn Johansen } 254aa9aeea8SJohn Johansen } 255aa9aeea8SJohn Johansen } 256aa9aeea8SJohn Johansen } 257aa9aeea8SJohn Johansen 258aa9aeea8SJohn Johansen void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, 25956974a6fSJohn Johansen u32 chrsmask, const char * const *names, u32 namesmask) 260aa9aeea8SJohn Johansen { 261aa9aeea8SJohn Johansen char str[33]; 262aa9aeea8SJohn Johansen 263aa9aeea8SJohn Johansen audit_log_format(ab, "\""); 264aa9aeea8SJohn Johansen if ((mask & chrsmask) && chrs) { 2657f3ebcf2STyler Hicks aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask); 266aa9aeea8SJohn Johansen mask &= ~chrsmask; 267aa9aeea8SJohn Johansen audit_log_format(ab, "%s", str); 268aa9aeea8SJohn Johansen if (mask & namesmask) 269aa9aeea8SJohn Johansen audit_log_format(ab, " "); 270aa9aeea8SJohn Johansen } 271aa9aeea8SJohn Johansen if ((mask & namesmask) && names) 272aa9aeea8SJohn Johansen aa_audit_perm_names(ab, names, mask & namesmask); 273aa9aeea8SJohn Johansen audit_log_format(ab, "\""); 274aa9aeea8SJohn Johansen } 275aa9aeea8SJohn Johansen 276aa9aeea8SJohn Johansen /** 277637f688dSJohn Johansen * aa_audit_perms_cb - generic callback fn for auditing perms 278637f688dSJohn Johansen * @ab: audit buffer (NOT NULL) 279637f688dSJohn Johansen * @va: audit struct to audit values of (NOT NULL) 280637f688dSJohn Johansen */ 281637f688dSJohn Johansen static void aa_audit_perms_cb(struct audit_buffer *ab, void *va) 282637f688dSJohn Johansen { 283637f688dSJohn Johansen struct common_audit_data *sa = va; 284637f688dSJohn Johansen 285637f688dSJohn Johansen if (aad(sa)->request) { 286637f688dSJohn Johansen audit_log_format(ab, " requested_mask="); 287637f688dSJohn Johansen aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs, 288637f688dSJohn Johansen PERMS_CHRS_MASK, aa_file_perm_names, 289637f688dSJohn Johansen PERMS_NAMES_MASK); 290637f688dSJohn Johansen } 291637f688dSJohn Johansen if (aad(sa)->denied) { 292637f688dSJohn Johansen audit_log_format(ab, "denied_mask="); 293637f688dSJohn Johansen aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs, 294637f688dSJohn Johansen PERMS_CHRS_MASK, aa_file_perm_names, 295637f688dSJohn Johansen PERMS_NAMES_MASK); 296637f688dSJohn Johansen } 297637f688dSJohn Johansen audit_log_format(ab, " peer="); 298637f688dSJohn Johansen aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, 299637f688dSJohn Johansen FLAGS_NONE, GFP_ATOMIC); 300637f688dSJohn Johansen } 301637f688dSJohn Johansen 302637f688dSJohn Johansen /** 303aa9aeea8SJohn Johansen * aa_apply_modes_to_perms - apply namespace and profile flags to perms 304aa9aeea8SJohn Johansen * @profile: that perms where computed from 305aa9aeea8SJohn Johansen * @perms: perms to apply mode modifiers to 306aa9aeea8SJohn Johansen * 307aa9aeea8SJohn Johansen * TODO: split into profile and ns based flags for when accumulating perms 308aa9aeea8SJohn Johansen */ 309aa9aeea8SJohn Johansen void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms) 310aa9aeea8SJohn Johansen { 311aa9aeea8SJohn Johansen switch (AUDIT_MODE(profile)) { 312aa9aeea8SJohn Johansen case AUDIT_ALL: 313aa9aeea8SJohn Johansen perms->audit = ALL_PERMS_MASK; 314df561f66SGustavo A. R. Silva fallthrough; 315aa9aeea8SJohn Johansen case AUDIT_NOQUIET: 316aa9aeea8SJohn Johansen perms->quiet = 0; 317aa9aeea8SJohn Johansen break; 318aa9aeea8SJohn Johansen case AUDIT_QUIET: 319aa9aeea8SJohn Johansen perms->audit = 0; 320df561f66SGustavo A. R. Silva fallthrough; 321aa9aeea8SJohn Johansen case AUDIT_QUIET_DENIED: 322aa9aeea8SJohn Johansen perms->quiet = ALL_PERMS_MASK; 323aa9aeea8SJohn Johansen break; 324aa9aeea8SJohn Johansen } 325aa9aeea8SJohn Johansen 326aa9aeea8SJohn Johansen if (KILL_MODE(profile)) 327aa9aeea8SJohn Johansen perms->kill = ALL_PERMS_MASK; 328aa9aeea8SJohn Johansen else if (COMPLAIN_MODE(profile)) 329aa9aeea8SJohn Johansen perms->complain = ALL_PERMS_MASK; 330aa9aeea8SJohn Johansen /* 331aa9aeea8SJohn Johansen * TODO: 332aa9aeea8SJohn Johansen * else if (PROMPT_MODE(profile)) 333aa9aeea8SJohn Johansen * perms->prompt = ALL_PERMS_MASK; 334aa9aeea8SJohn Johansen */ 335aa9aeea8SJohn Johansen } 336aa9aeea8SJohn Johansen 337cdff2642SJohn Johansen /** 338637f688dSJohn Johansen * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms 339637f688dSJohn Johansen * @accum - perms struct to accumulate into 340637f688dSJohn Johansen * @addend - perms struct to add to @accum 341637f688dSJohn Johansen */ 342637f688dSJohn Johansen void aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend) 343637f688dSJohn Johansen { 344637f688dSJohn Johansen accum->deny |= addend->deny; 345637f688dSJohn Johansen accum->allow &= addend->allow & ~addend->deny; 346637f688dSJohn Johansen accum->audit |= addend->audit & addend->allow; 347637f688dSJohn Johansen accum->quiet &= addend->quiet & ~addend->allow; 348637f688dSJohn Johansen accum->kill |= addend->kill & ~addend->allow; 349637f688dSJohn Johansen accum->complain |= addend->complain & ~addend->allow & ~addend->deny; 350637f688dSJohn Johansen accum->cond |= addend->cond & ~addend->allow & ~addend->deny; 351637f688dSJohn Johansen accum->hide &= addend->hide & ~addend->allow; 352637f688dSJohn Johansen accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny; 353bf690f59SJohn Johansen accum->subtree |= addend->subtree & ~addend->deny; 354637f688dSJohn Johansen } 355637f688dSJohn Johansen 356637f688dSJohn Johansen /** 357637f688dSJohn Johansen * aa_perms_accum - accumulate perms, masking off overlapping perms 358637f688dSJohn Johansen * @accum - perms struct to accumulate into 359637f688dSJohn Johansen * @addend - perms struct to add to @accum 360637f688dSJohn Johansen */ 361637f688dSJohn Johansen void aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend) 362637f688dSJohn Johansen { 363637f688dSJohn Johansen accum->deny |= addend->deny; 364637f688dSJohn Johansen accum->allow &= addend->allow & ~accum->deny; 365637f688dSJohn Johansen accum->audit |= addend->audit & accum->allow; 366637f688dSJohn Johansen accum->quiet &= addend->quiet & ~accum->allow; 367637f688dSJohn Johansen accum->kill |= addend->kill & ~accum->allow; 368637f688dSJohn Johansen accum->complain |= addend->complain & ~accum->allow & ~accum->deny; 369637f688dSJohn Johansen accum->cond |= addend->cond & ~accum->allow & ~accum->deny; 370637f688dSJohn Johansen accum->hide &= addend->hide & ~accum->allow; 371637f688dSJohn Johansen accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny; 372bf690f59SJohn Johansen accum->subtree &= addend->subtree & ~accum->deny; 373637f688dSJohn Johansen } 374637f688dSJohn Johansen 375637f688dSJohn Johansen void aa_profile_match_label(struct aa_profile *profile, struct aa_label *label, 376637f688dSJohn Johansen int type, u32 request, struct aa_perms *perms) 377637f688dSJohn Johansen { 378637f688dSJohn Johansen /* TODO: doesn't yet handle extended types */ 37933fc95d8SJohn Johansen aa_state_t state; 380637f688dSJohn Johansen 381637f688dSJohn Johansen state = aa_dfa_next(profile->policy.dfa, 382637f688dSJohn Johansen profile->policy.start[AA_CLASS_LABEL], 383637f688dSJohn Johansen type); 384637f688dSJohn Johansen aa_label_match(profile, label, state, false, request, perms); 385637f688dSJohn Johansen } 386637f688dSJohn Johansen 387637f688dSJohn Johansen 388637f688dSJohn Johansen /* currently unused */ 389637f688dSJohn Johansen int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, 390637f688dSJohn Johansen u32 request, int type, u32 *deny, 391637f688dSJohn Johansen struct common_audit_data *sa) 392637f688dSJohn Johansen { 393637f688dSJohn Johansen struct aa_perms perms; 394637f688dSJohn Johansen 395637f688dSJohn Johansen aad(sa)->label = &profile->label; 396637f688dSJohn Johansen aad(sa)->peer = &target->label; 397637f688dSJohn Johansen aad(sa)->request = request; 398637f688dSJohn Johansen 399637f688dSJohn Johansen aa_profile_match_label(profile, &target->label, type, request, &perms); 400637f688dSJohn Johansen aa_apply_modes_to_perms(profile, &perms); 401637f688dSJohn Johansen *deny |= request & perms.deny; 402637f688dSJohn Johansen return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb); 403637f688dSJohn Johansen } 404637f688dSJohn Johansen 405637f688dSJohn Johansen /** 406637f688dSJohn Johansen * aa_check_perms - do audit mode selection based on perms set 407637f688dSJohn Johansen * @profile: profile being checked 408637f688dSJohn Johansen * @perms: perms computed for the request 409637f688dSJohn Johansen * @request: requested perms 410637f688dSJohn Johansen * @deny: Returns: explicit deny set 411637f688dSJohn Johansen * @sa: initialized audit structure (MAY BE NULL if not auditing) 41269ad4a44SZygmunt Krynicki * @cb: callback fn for type specific fields (MAY BE NULL) 413637f688dSJohn Johansen * 414637f688dSJohn Johansen * Returns: 0 if permission else error code 415637f688dSJohn Johansen * 416637f688dSJohn Johansen * Note: profile audit modes need to be set before calling by setting the 417637f688dSJohn Johansen * perm masks appropriately. 418637f688dSJohn Johansen * 419637f688dSJohn Johansen * If not auditing then complain mode is not enabled and the 420637f688dSJohn Johansen * error code will indicate whether there was an explicit deny 421637f688dSJohn Johansen * with a positive value. 422637f688dSJohn Johansen */ 423637f688dSJohn Johansen int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, 424637f688dSJohn Johansen u32 request, struct common_audit_data *sa, 425637f688dSJohn Johansen void (*cb)(struct audit_buffer *, void *)) 426637f688dSJohn Johansen { 427637f688dSJohn Johansen int type, error; 428637f688dSJohn Johansen u32 denied = request & (~perms->allow | perms->deny); 429637f688dSJohn Johansen 430637f688dSJohn Johansen if (likely(!denied)) { 431637f688dSJohn Johansen /* mask off perms that are not being force audited */ 432637f688dSJohn Johansen request &= perms->audit; 433637f688dSJohn Johansen if (!request || !sa) 434637f688dSJohn Johansen return 0; 435637f688dSJohn Johansen 436637f688dSJohn Johansen type = AUDIT_APPARMOR_AUDIT; 437637f688dSJohn Johansen error = 0; 438637f688dSJohn Johansen } else { 439637f688dSJohn Johansen error = -EACCES; 440637f688dSJohn Johansen 441637f688dSJohn Johansen if (denied & perms->kill) 442637f688dSJohn Johansen type = AUDIT_APPARMOR_KILL; 443637f688dSJohn Johansen else if (denied == (denied & perms->complain)) 444637f688dSJohn Johansen type = AUDIT_APPARMOR_ALLOWED; 445637f688dSJohn Johansen else 446637f688dSJohn Johansen type = AUDIT_APPARMOR_DENIED; 447637f688dSJohn Johansen 448637f688dSJohn Johansen if (denied == (denied & perms->hide)) 449637f688dSJohn Johansen error = -ENOENT; 450637f688dSJohn Johansen 451637f688dSJohn Johansen denied &= ~perms->quiet; 452637f688dSJohn Johansen if (!sa || !denied) 453637f688dSJohn Johansen return error; 454637f688dSJohn Johansen } 455637f688dSJohn Johansen 456637f688dSJohn Johansen if (sa) { 457637f688dSJohn Johansen aad(sa)->label = &profile->label; 458637f688dSJohn Johansen aad(sa)->request = request; 459637f688dSJohn Johansen aad(sa)->denied = denied; 460637f688dSJohn Johansen aad(sa)->error = error; 461637f688dSJohn Johansen aa_audit_msg(type, sa, cb); 462637f688dSJohn Johansen } 463637f688dSJohn Johansen 464637f688dSJohn Johansen if (type == AUDIT_APPARMOR_ALLOWED) 465637f688dSJohn Johansen error = 0; 466637f688dSJohn Johansen 467637f688dSJohn Johansen return error; 468637f688dSJohn Johansen } 469637f688dSJohn Johansen 470637f688dSJohn Johansen 471637f688dSJohn Johansen /** 472fe6bb31fSJohn Johansen * aa_policy_init - initialize a policy structure 473fe6bb31fSJohn Johansen * @policy: policy to initialize (NOT NULL) 474fe6bb31fSJohn Johansen * @prefix: prefix name if any is required. (MAYBE NULL) 475fe6bb31fSJohn Johansen * @name: name of the policy, init will make a copy of it (NOT NULL) 476a1bd627bSJohn Johansen * @gfp: allocation mode 477fe6bb31fSJohn Johansen * 478fe6bb31fSJohn Johansen * Note: this fn creates a copy of strings passed in 479fe6bb31fSJohn Johansen * 480fe6bb31fSJohn Johansen * Returns: true if policy init successful 481fe6bb31fSJohn Johansen */ 482fe6bb31fSJohn Johansen bool aa_policy_init(struct aa_policy *policy, const char *prefix, 483d102d895SJohn Johansen const char *name, gfp_t gfp) 484fe6bb31fSJohn Johansen { 485a1bd627bSJohn Johansen char *hname; 486a1bd627bSJohn Johansen 487fe6bb31fSJohn Johansen /* freed by policy_free */ 488fe6bb31fSJohn Johansen if (prefix) { 489a1bd627bSJohn Johansen hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp); 490a1bd627bSJohn Johansen if (hname) 491a1bd627bSJohn Johansen sprintf(hname, "%s//%s", prefix, name); 492a1bd627bSJohn Johansen } else { 493a1bd627bSJohn Johansen hname = aa_str_alloc(strlen(name) + 1, gfp); 494a1bd627bSJohn Johansen if (hname) 495a1bd627bSJohn Johansen strcpy(hname, name); 496a1bd627bSJohn Johansen } 497a1bd627bSJohn Johansen if (!hname) 498b9c42ac7Skbuild test robot return false; 499a1bd627bSJohn Johansen policy->hname = hname; 500fe6bb31fSJohn Johansen /* base.name is a substring of fqname */ 501d102d895SJohn Johansen policy->name = basename(policy->hname); 502fe6bb31fSJohn Johansen INIT_LIST_HEAD(&policy->list); 503fe6bb31fSJohn Johansen INIT_LIST_HEAD(&policy->profiles); 504fe6bb31fSJohn Johansen 505b9c42ac7Skbuild test robot return true; 506fe6bb31fSJohn Johansen } 507fe6bb31fSJohn Johansen 508fe6bb31fSJohn Johansen /** 509fe6bb31fSJohn Johansen * aa_policy_destroy - free the elements referenced by @policy 510fe6bb31fSJohn Johansen * @policy: policy that is to have its elements freed (NOT NULL) 511fe6bb31fSJohn Johansen */ 512fe6bb31fSJohn Johansen void aa_policy_destroy(struct aa_policy *policy) 513fe6bb31fSJohn Johansen { 5145fd1b95fSJohn Johansen AA_BUG(on_list_rcu(&policy->profiles)); 5155fd1b95fSJohn Johansen AA_BUG(on_list_rcu(&policy->list)); 516fe6bb31fSJohn Johansen 517fe6bb31fSJohn Johansen /* don't free name as its a subset of hname */ 518a1bd627bSJohn Johansen aa_put_str(policy->hname); 519fe6bb31fSJohn Johansen } 520