162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AppArmor security module 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file contains basic common functions used in AppArmor 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE 862306a36Sopenharmony_ci * Copyright 2009-2010 Canonical Ltd. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/ctype.h> 1262306a36Sopenharmony_ci#include <linux/mm.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/string.h> 1562306a36Sopenharmony_ci#include <linux/vmalloc.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "include/audit.h" 1862306a36Sopenharmony_ci#include "include/apparmor.h" 1962306a36Sopenharmony_ci#include "include/lib.h" 2062306a36Sopenharmony_ci#include "include/perms.h" 2162306a36Sopenharmony_ci#include "include/policy.h" 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct aa_perms nullperms; 2462306a36Sopenharmony_cistruct aa_perms allperms = { .allow = ALL_PERMS_MASK, 2562306a36Sopenharmony_ci .quiet = ALL_PERMS_MASK, 2662306a36Sopenharmony_ci .hide = ALL_PERMS_MASK }; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/** 2962306a36Sopenharmony_ci * aa_free_str_table - free entries str table 3062306a36Sopenharmony_ci * @t: the string table to free (MAYBE NULL) 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_civoid aa_free_str_table(struct aa_str_table *t) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci int i; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (t) { 3762306a36Sopenharmony_ci if (!t->table) 3862306a36Sopenharmony_ci return; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci for (i = 0; i < t->size; i++) 4162306a36Sopenharmony_ci kfree_sensitive(t->table[i]); 4262306a36Sopenharmony_ci kfree_sensitive(t->table); 4362306a36Sopenharmony_ci t->table = NULL; 4462306a36Sopenharmony_ci t->size = 0; 4562306a36Sopenharmony_ci } 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/** 4962306a36Sopenharmony_ci * aa_split_fqname - split a fqname into a profile and namespace name 5062306a36Sopenharmony_ci * @fqname: a full qualified name in namespace profile format (NOT NULL) 5162306a36Sopenharmony_ci * @ns_name: pointer to portion of the string containing the ns name (NOT NULL) 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * Returns: profile name or NULL if one is not specified 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * Split a namespace name from a profile name (see policy.c for naming 5662306a36Sopenharmony_ci * description). If a portion of the name is missing it returns NULL for 5762306a36Sopenharmony_ci * that portion. 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * NOTE: may modify the @fqname string. The pointers returned point 6062306a36Sopenharmony_ci * into the @fqname string. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_cichar *aa_split_fqname(char *fqname, char **ns_name) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci char *name = strim(fqname); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci *ns_name = NULL; 6762306a36Sopenharmony_ci if (name[0] == ':') { 6862306a36Sopenharmony_ci char *split = strchr(&name[1], ':'); 6962306a36Sopenharmony_ci *ns_name = skip_spaces(&name[1]); 7062306a36Sopenharmony_ci if (split) { 7162306a36Sopenharmony_ci /* overwrite ':' with \0 */ 7262306a36Sopenharmony_ci *split++ = 0; 7362306a36Sopenharmony_ci if (strncmp(split, "//", 2) == 0) 7462306a36Sopenharmony_ci split += 2; 7562306a36Sopenharmony_ci name = skip_spaces(split); 7662306a36Sopenharmony_ci } else 7762306a36Sopenharmony_ci /* a ns name without a following profile is allowed */ 7862306a36Sopenharmony_ci name = NULL; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci if (name && *name == 0) 8162306a36Sopenharmony_ci name = NULL; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return name; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/** 8762306a36Sopenharmony_ci * skipn_spaces - Removes leading whitespace from @str. 8862306a36Sopenharmony_ci * @str: The string to be stripped. 8962306a36Sopenharmony_ci * @n: length of str to parse, will stop at \0 if encountered before n 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * Returns a pointer to the first non-whitespace character in @str. 9262306a36Sopenharmony_ci * if all whitespace will return NULL 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciconst char *skipn_spaces(const char *str, size_t n) 9662306a36Sopenharmony_ci{ 9762306a36Sopenharmony_ci for (; n && isspace(*str); --n) 9862306a36Sopenharmony_ci ++str; 9962306a36Sopenharmony_ci if (n) 10062306a36Sopenharmony_ci return (char *)str; 10162306a36Sopenharmony_ci return NULL; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ciconst char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, 10562306a36Sopenharmony_ci size_t *ns_len) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci const char *end = fqname + n; 10862306a36Sopenharmony_ci const char *name = skipn_spaces(fqname, n); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci *ns_name = NULL; 11162306a36Sopenharmony_ci *ns_len = 0; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (!name) 11462306a36Sopenharmony_ci return NULL; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (name[0] == ':') { 11762306a36Sopenharmony_ci char *split = strnchr(&name[1], end - &name[1], ':'); 11862306a36Sopenharmony_ci *ns_name = skipn_spaces(&name[1], end - &name[1]); 11962306a36Sopenharmony_ci if (!*ns_name) 12062306a36Sopenharmony_ci return NULL; 12162306a36Sopenharmony_ci if (split) { 12262306a36Sopenharmony_ci *ns_len = split - *ns_name; 12362306a36Sopenharmony_ci if (*ns_len == 0) 12462306a36Sopenharmony_ci *ns_name = NULL; 12562306a36Sopenharmony_ci split++; 12662306a36Sopenharmony_ci if (end - split > 1 && strncmp(split, "//", 2) == 0) 12762306a36Sopenharmony_ci split += 2; 12862306a36Sopenharmony_ci name = skipn_spaces(split, end - split); 12962306a36Sopenharmony_ci } else { 13062306a36Sopenharmony_ci /* a ns name without a following profile is allowed */ 13162306a36Sopenharmony_ci name = NULL; 13262306a36Sopenharmony_ci *ns_len = end - *ns_name; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci if (name && *name == 0) 13662306a36Sopenharmony_ci name = NULL; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci return name; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/** 14262306a36Sopenharmony_ci * aa_info_message - log a none profile related status message 14362306a36Sopenharmony_ci * @str: message to log 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_civoid aa_info_message(const char *str) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci if (audit_enabled) { 14862306a36Sopenharmony_ci DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci ad.info = str; 15162306a36Sopenharmony_ci aa_audit_msg(AUDIT_APPARMOR_STATUS, &ad, NULL); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci printk(KERN_INFO "AppArmor: %s\n", str); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci__counted char *aa_str_alloc(int size, gfp_t gfp) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci struct counted_str *str; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci str = kmalloc(struct_size(str, name, size), gfp); 16162306a36Sopenharmony_ci if (!str) 16262306a36Sopenharmony_ci return NULL; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci kref_init(&str->count); 16562306a36Sopenharmony_ci return str->name; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_civoid aa_str_kref(struct kref *kref) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci kfree(container_of(kref, struct counted_str, count)); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ciconst char aa_file_perm_chrs[] = "xwracd km l "; 17562306a36Sopenharmony_ciconst char *aa_file_perm_names[] = { 17662306a36Sopenharmony_ci "exec", 17762306a36Sopenharmony_ci "write", 17862306a36Sopenharmony_ci "read", 17962306a36Sopenharmony_ci "append", 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci "create", 18262306a36Sopenharmony_ci "delete", 18362306a36Sopenharmony_ci "open", 18462306a36Sopenharmony_ci "rename", 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci "setattr", 18762306a36Sopenharmony_ci "getattr", 18862306a36Sopenharmony_ci "setcred", 18962306a36Sopenharmony_ci "getcred", 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci "chmod", 19262306a36Sopenharmony_ci "chown", 19362306a36Sopenharmony_ci "chgrp", 19462306a36Sopenharmony_ci "lock", 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci "mmap", 19762306a36Sopenharmony_ci "mprot", 19862306a36Sopenharmony_ci "link", 19962306a36Sopenharmony_ci "snapshot", 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci "unknown", 20262306a36Sopenharmony_ci "unknown", 20362306a36Sopenharmony_ci "unknown", 20462306a36Sopenharmony_ci "unknown", 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci "unknown", 20762306a36Sopenharmony_ci "unknown", 20862306a36Sopenharmony_ci "unknown", 20962306a36Sopenharmony_ci "unknown", 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci "stack", 21262306a36Sopenharmony_ci "change_onexec", 21362306a36Sopenharmony_ci "change_profile", 21462306a36Sopenharmony_ci "change_hat", 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/** 21862306a36Sopenharmony_ci * aa_perm_mask_to_str - convert a perm mask to its short string 21962306a36Sopenharmony_ci * @str: character buffer to store string in (at least 10 characters) 22062306a36Sopenharmony_ci * @str_size: size of the @str buffer 22162306a36Sopenharmony_ci * @chrs: NUL-terminated character buffer of permission characters 22262306a36Sopenharmony_ci * @mask: permission mask to convert 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_civoid aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci unsigned int i, perm = 1; 22762306a36Sopenharmony_ci size_t num_chrs = strlen(chrs); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci for (i = 0; i < num_chrs; perm <<= 1, i++) { 23062306a36Sopenharmony_ci if (mask & perm) { 23162306a36Sopenharmony_ci /* Ensure that one byte is left for NUL-termination */ 23262306a36Sopenharmony_ci if (WARN_ON_ONCE(str_size <= 1)) 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci *str++ = chrs[i]; 23662306a36Sopenharmony_ci str_size--; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci *str = '\0'; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_civoid aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, 24362306a36Sopenharmony_ci u32 mask) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci const char *fmt = "%s"; 24662306a36Sopenharmony_ci unsigned int i, perm = 1; 24762306a36Sopenharmony_ci bool prev = false; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci for (i = 0; i < 32; perm <<= 1, i++) { 25062306a36Sopenharmony_ci if (mask & perm) { 25162306a36Sopenharmony_ci audit_log_format(ab, fmt, names[i]); 25262306a36Sopenharmony_ci if (!prev) { 25362306a36Sopenharmony_ci prev = true; 25462306a36Sopenharmony_ci fmt = " %s"; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_civoid aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, 26162306a36Sopenharmony_ci u32 chrsmask, const char * const *names, u32 namesmask) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci char str[33]; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci audit_log_format(ab, "\""); 26662306a36Sopenharmony_ci if ((mask & chrsmask) && chrs) { 26762306a36Sopenharmony_ci aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask); 26862306a36Sopenharmony_ci mask &= ~chrsmask; 26962306a36Sopenharmony_ci audit_log_format(ab, "%s", str); 27062306a36Sopenharmony_ci if (mask & namesmask) 27162306a36Sopenharmony_ci audit_log_format(ab, " "); 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci if ((mask & namesmask) && names) 27462306a36Sopenharmony_ci aa_audit_perm_names(ab, names, mask & namesmask); 27562306a36Sopenharmony_ci audit_log_format(ab, "\""); 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci/** 27962306a36Sopenharmony_ci * aa_audit_perms_cb - generic callback fn for auditing perms 28062306a36Sopenharmony_ci * @ab: audit buffer (NOT NULL) 28162306a36Sopenharmony_ci * @va: audit struct to audit values of (NOT NULL) 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_cistatic void aa_audit_perms_cb(struct audit_buffer *ab, void *va) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct common_audit_data *sa = va; 28662306a36Sopenharmony_ci struct apparmor_audit_data *ad = aad(sa); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (ad->request) { 28962306a36Sopenharmony_ci audit_log_format(ab, " requested_mask="); 29062306a36Sopenharmony_ci aa_audit_perm_mask(ab, ad->request, aa_file_perm_chrs, 29162306a36Sopenharmony_ci PERMS_CHRS_MASK, aa_file_perm_names, 29262306a36Sopenharmony_ci PERMS_NAMES_MASK); 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci if (ad->denied) { 29562306a36Sopenharmony_ci audit_log_format(ab, "denied_mask="); 29662306a36Sopenharmony_ci aa_audit_perm_mask(ab, ad->denied, aa_file_perm_chrs, 29762306a36Sopenharmony_ci PERMS_CHRS_MASK, aa_file_perm_names, 29862306a36Sopenharmony_ci PERMS_NAMES_MASK); 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci audit_log_format(ab, " peer="); 30162306a36Sopenharmony_ci aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, 30262306a36Sopenharmony_ci FLAGS_NONE, GFP_ATOMIC); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci/** 30662306a36Sopenharmony_ci * aa_apply_modes_to_perms - apply namespace and profile flags to perms 30762306a36Sopenharmony_ci * @profile: that perms where computed from 30862306a36Sopenharmony_ci * @perms: perms to apply mode modifiers to 30962306a36Sopenharmony_ci * 31062306a36Sopenharmony_ci * TODO: split into profile and ns based flags for when accumulating perms 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_civoid aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci switch (AUDIT_MODE(profile)) { 31562306a36Sopenharmony_ci case AUDIT_ALL: 31662306a36Sopenharmony_ci perms->audit = ALL_PERMS_MASK; 31762306a36Sopenharmony_ci fallthrough; 31862306a36Sopenharmony_ci case AUDIT_NOQUIET: 31962306a36Sopenharmony_ci perms->quiet = 0; 32062306a36Sopenharmony_ci break; 32162306a36Sopenharmony_ci case AUDIT_QUIET: 32262306a36Sopenharmony_ci perms->audit = 0; 32362306a36Sopenharmony_ci fallthrough; 32462306a36Sopenharmony_ci case AUDIT_QUIET_DENIED: 32562306a36Sopenharmony_ci perms->quiet = ALL_PERMS_MASK; 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (KILL_MODE(profile)) 33062306a36Sopenharmony_ci perms->kill = ALL_PERMS_MASK; 33162306a36Sopenharmony_ci else if (COMPLAIN_MODE(profile)) 33262306a36Sopenharmony_ci perms->complain = ALL_PERMS_MASK; 33362306a36Sopenharmony_ci else if (USER_MODE(profile)) 33462306a36Sopenharmony_ci perms->prompt = ALL_PERMS_MASK; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_civoid aa_profile_match_label(struct aa_profile *profile, 33862306a36Sopenharmony_ci struct aa_ruleset *rules, 33962306a36Sopenharmony_ci struct aa_label *label, 34062306a36Sopenharmony_ci int type, u32 request, struct aa_perms *perms) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci /* TODO: doesn't yet handle extended types */ 34362306a36Sopenharmony_ci aa_state_t state; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci state = aa_dfa_next(rules->policy.dfa, 34662306a36Sopenharmony_ci rules->policy.start[AA_CLASS_LABEL], 34762306a36Sopenharmony_ci type); 34862306a36Sopenharmony_ci aa_label_match(profile, rules, label, state, false, request, perms); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/* currently unused */ 35362306a36Sopenharmony_ciint aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, 35462306a36Sopenharmony_ci u32 request, int type, u32 *deny, 35562306a36Sopenharmony_ci struct apparmor_audit_data *ad) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci struct aa_ruleset *rules = list_first_entry(&profile->rules, 35862306a36Sopenharmony_ci typeof(*rules), list); 35962306a36Sopenharmony_ci struct aa_perms perms; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ad->peer = &target->label; 36262306a36Sopenharmony_ci ad->request = request; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci aa_profile_match_label(profile, rules, &target->label, type, request, 36562306a36Sopenharmony_ci &perms); 36662306a36Sopenharmony_ci aa_apply_modes_to_perms(profile, &perms); 36762306a36Sopenharmony_ci *deny |= request & perms.deny; 36862306a36Sopenharmony_ci return aa_check_perms(profile, &perms, request, ad, aa_audit_perms_cb); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/** 37262306a36Sopenharmony_ci * aa_check_perms - do audit mode selection based on perms set 37362306a36Sopenharmony_ci * @profile: profile being checked 37462306a36Sopenharmony_ci * @perms: perms computed for the request 37562306a36Sopenharmony_ci * @request: requested perms 37662306a36Sopenharmony_ci * @ad: initialized audit structure (MAY BE NULL if not auditing) 37762306a36Sopenharmony_ci * @cb: callback fn for type specific fields (MAY BE NULL) 37862306a36Sopenharmony_ci * 37962306a36Sopenharmony_ci * Returns: 0 if permission else error code 38062306a36Sopenharmony_ci * 38162306a36Sopenharmony_ci * Note: profile audit modes need to be set before calling by setting the 38262306a36Sopenharmony_ci * perm masks appropriately. 38362306a36Sopenharmony_ci * 38462306a36Sopenharmony_ci * If not auditing then complain mode is not enabled and the 38562306a36Sopenharmony_ci * error code will indicate whether there was an explicit deny 38662306a36Sopenharmony_ci * with a positive value. 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_ciint aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, 38962306a36Sopenharmony_ci u32 request, struct apparmor_audit_data *ad, 39062306a36Sopenharmony_ci void (*cb)(struct audit_buffer *, void *)) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci int type, error; 39362306a36Sopenharmony_ci u32 denied = request & (~perms->allow | perms->deny); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (likely(!denied)) { 39662306a36Sopenharmony_ci /* mask off perms that are not being force audited */ 39762306a36Sopenharmony_ci request &= perms->audit; 39862306a36Sopenharmony_ci if (!request || !ad) 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci type = AUDIT_APPARMOR_AUDIT; 40262306a36Sopenharmony_ci error = 0; 40362306a36Sopenharmony_ci } else { 40462306a36Sopenharmony_ci error = -EACCES; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci if (denied & perms->kill) 40762306a36Sopenharmony_ci type = AUDIT_APPARMOR_KILL; 40862306a36Sopenharmony_ci else if (denied == (denied & perms->complain)) 40962306a36Sopenharmony_ci type = AUDIT_APPARMOR_ALLOWED; 41062306a36Sopenharmony_ci else 41162306a36Sopenharmony_ci type = AUDIT_APPARMOR_DENIED; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (denied == (denied & perms->hide)) 41462306a36Sopenharmony_ci error = -ENOENT; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci denied &= ~perms->quiet; 41762306a36Sopenharmony_ci if (!ad || !denied) 41862306a36Sopenharmony_ci return error; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (ad) { 42262306a36Sopenharmony_ci ad->subj_label = &profile->label; 42362306a36Sopenharmony_ci ad->request = request; 42462306a36Sopenharmony_ci ad->denied = denied; 42562306a36Sopenharmony_ci ad->error = error; 42662306a36Sopenharmony_ci aa_audit_msg(type, ad, cb); 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (type == AUDIT_APPARMOR_ALLOWED) 43062306a36Sopenharmony_ci error = 0; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return error; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci/** 43762306a36Sopenharmony_ci * aa_policy_init - initialize a policy structure 43862306a36Sopenharmony_ci * @policy: policy to initialize (NOT NULL) 43962306a36Sopenharmony_ci * @prefix: prefix name if any is required. (MAYBE NULL) 44062306a36Sopenharmony_ci * @name: name of the policy, init will make a copy of it (NOT NULL) 44162306a36Sopenharmony_ci * @gfp: allocation mode 44262306a36Sopenharmony_ci * 44362306a36Sopenharmony_ci * Note: this fn creates a copy of strings passed in 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * Returns: true if policy init successful 44662306a36Sopenharmony_ci */ 44762306a36Sopenharmony_cibool aa_policy_init(struct aa_policy *policy, const char *prefix, 44862306a36Sopenharmony_ci const char *name, gfp_t gfp) 44962306a36Sopenharmony_ci{ 45062306a36Sopenharmony_ci char *hname; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* freed by policy_free */ 45362306a36Sopenharmony_ci if (prefix) { 45462306a36Sopenharmony_ci hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp); 45562306a36Sopenharmony_ci if (hname) 45662306a36Sopenharmony_ci sprintf(hname, "%s//%s", prefix, name); 45762306a36Sopenharmony_ci } else { 45862306a36Sopenharmony_ci hname = aa_str_alloc(strlen(name) + 1, gfp); 45962306a36Sopenharmony_ci if (hname) 46062306a36Sopenharmony_ci strcpy(hname, name); 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci if (!hname) 46362306a36Sopenharmony_ci return false; 46462306a36Sopenharmony_ci policy->hname = hname; 46562306a36Sopenharmony_ci /* base.name is a substring of fqname */ 46662306a36Sopenharmony_ci policy->name = basename(policy->hname); 46762306a36Sopenharmony_ci INIT_LIST_HEAD(&policy->list); 46862306a36Sopenharmony_ci INIT_LIST_HEAD(&policy->profiles); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci return true; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci/** 47462306a36Sopenharmony_ci * aa_policy_destroy - free the elements referenced by @policy 47562306a36Sopenharmony_ci * @policy: policy that is to have its elements freed (NOT NULL) 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_civoid aa_policy_destroy(struct aa_policy *policy) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci AA_BUG(on_list_rcu(&policy->profiles)); 48062306a36Sopenharmony_ci AA_BUG(on_list_rcu(&policy->list)); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* don't free name as its a subset of hname */ 48362306a36Sopenharmony_ci aa_put_str(policy->hname); 48462306a36Sopenharmony_ci} 485