18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AppArmor security module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains basic common functions used in AppArmor 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE 88c2ecf20Sopenharmony_ci * Copyright 2009-2010 Canonical Ltd. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/ctype.h> 128c2ecf20Sopenharmony_ci#include <linux/mm.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "include/audit.h" 188c2ecf20Sopenharmony_ci#include "include/apparmor.h" 198c2ecf20Sopenharmony_ci#include "include/lib.h" 208c2ecf20Sopenharmony_ci#include "include/perms.h" 218c2ecf20Sopenharmony_ci#include "include/policy.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct aa_perms nullperms; 248c2ecf20Sopenharmony_cistruct aa_perms allperms = { .allow = ALL_PERMS_MASK, 258c2ecf20Sopenharmony_ci .quiet = ALL_PERMS_MASK, 268c2ecf20Sopenharmony_ci .hide = ALL_PERMS_MASK }; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * aa_split_fqname - split a fqname into a profile and namespace name 308c2ecf20Sopenharmony_ci * @fqname: a full qualified name in namespace profile format (NOT NULL) 318c2ecf20Sopenharmony_ci * @ns_name: pointer to portion of the string containing the ns name (NOT NULL) 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Returns: profile name or NULL if one is not specified 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Split a namespace name from a profile name (see policy.c for naming 368c2ecf20Sopenharmony_ci * description). If a portion of the name is missing it returns NULL for 378c2ecf20Sopenharmony_ci * that portion. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * NOTE: may modify the @fqname string. The pointers returned point 408c2ecf20Sopenharmony_ci * into the @fqname string. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_cichar *aa_split_fqname(char *fqname, char **ns_name) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci char *name = strim(fqname); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci *ns_name = NULL; 478c2ecf20Sopenharmony_ci if (name[0] == ':') { 488c2ecf20Sopenharmony_ci char *split = strchr(&name[1], ':'); 498c2ecf20Sopenharmony_ci *ns_name = skip_spaces(&name[1]); 508c2ecf20Sopenharmony_ci if (split) { 518c2ecf20Sopenharmony_ci /* overwrite ':' with \0 */ 528c2ecf20Sopenharmony_ci *split++ = 0; 538c2ecf20Sopenharmony_ci if (strncmp(split, "//", 2) == 0) 548c2ecf20Sopenharmony_ci split += 2; 558c2ecf20Sopenharmony_ci name = skip_spaces(split); 568c2ecf20Sopenharmony_ci } else 578c2ecf20Sopenharmony_ci /* a ns name without a following profile is allowed */ 588c2ecf20Sopenharmony_ci name = NULL; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci if (name && *name == 0) 618c2ecf20Sopenharmony_ci name = NULL; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return name; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci/** 678c2ecf20Sopenharmony_ci * skipn_spaces - Removes leading whitespace from @str. 688c2ecf20Sopenharmony_ci * @str: The string to be stripped. 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * Returns a pointer to the first non-whitespace character in @str. 718c2ecf20Sopenharmony_ci * if all whitespace will return NULL 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciconst char *skipn_spaces(const char *str, size_t n) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci for (; n && isspace(*str); --n) 778c2ecf20Sopenharmony_ci ++str; 788c2ecf20Sopenharmony_ci if (n) 798c2ecf20Sopenharmony_ci return (char *)str; 808c2ecf20Sopenharmony_ci return NULL; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ciconst char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, 848c2ecf20Sopenharmony_ci size_t *ns_len) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci const char *end = fqname + n; 878c2ecf20Sopenharmony_ci const char *name = skipn_spaces(fqname, n); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci *ns_name = NULL; 908c2ecf20Sopenharmony_ci *ns_len = 0; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (!name) 938c2ecf20Sopenharmony_ci return NULL; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (name[0] == ':') { 968c2ecf20Sopenharmony_ci char *split = strnchr(&name[1], end - &name[1], ':'); 978c2ecf20Sopenharmony_ci *ns_name = skipn_spaces(&name[1], end - &name[1]); 988c2ecf20Sopenharmony_ci if (!*ns_name) 998c2ecf20Sopenharmony_ci return NULL; 1008c2ecf20Sopenharmony_ci if (split) { 1018c2ecf20Sopenharmony_ci *ns_len = split - *ns_name; 1028c2ecf20Sopenharmony_ci if (*ns_len == 0) 1038c2ecf20Sopenharmony_ci *ns_name = NULL; 1048c2ecf20Sopenharmony_ci split++; 1058c2ecf20Sopenharmony_ci if (end - split > 1 && strncmp(split, "//", 2) == 0) 1068c2ecf20Sopenharmony_ci split += 2; 1078c2ecf20Sopenharmony_ci name = skipn_spaces(split, end - split); 1088c2ecf20Sopenharmony_ci } else { 1098c2ecf20Sopenharmony_ci /* a ns name without a following profile is allowed */ 1108c2ecf20Sopenharmony_ci name = NULL; 1118c2ecf20Sopenharmony_ci *ns_len = end - *ns_name; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci if (name && *name == 0) 1158c2ecf20Sopenharmony_ci name = NULL; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return name; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/** 1218c2ecf20Sopenharmony_ci * aa_info_message - log a none profile related status message 1228c2ecf20Sopenharmony_ci * @str: message to log 1238c2ecf20Sopenharmony_ci */ 1248c2ecf20Sopenharmony_civoid aa_info_message(const char *str) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci if (audit_enabled) { 1278c2ecf20Sopenharmony_ci DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci aad(&sa)->info = str; 1308c2ecf20Sopenharmony_ci aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci printk(KERN_INFO "AppArmor: %s\n", str); 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci__counted char *aa_str_alloc(int size, gfp_t gfp) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct counted_str *str; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci str = kmalloc(sizeof(struct counted_str) + size, gfp); 1408c2ecf20Sopenharmony_ci if (!str) 1418c2ecf20Sopenharmony_ci return NULL; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci kref_init(&str->count); 1448c2ecf20Sopenharmony_ci return str->name; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_civoid aa_str_kref(struct kref *kref) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci kfree(container_of(kref, struct counted_str, count)); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciconst char aa_file_perm_chrs[] = "xwracd km l "; 1548c2ecf20Sopenharmony_ciconst char *aa_file_perm_names[] = { 1558c2ecf20Sopenharmony_ci "exec", 1568c2ecf20Sopenharmony_ci "write", 1578c2ecf20Sopenharmony_ci "read", 1588c2ecf20Sopenharmony_ci "append", 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci "create", 1618c2ecf20Sopenharmony_ci "delete", 1628c2ecf20Sopenharmony_ci "open", 1638c2ecf20Sopenharmony_ci "rename", 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci "setattr", 1668c2ecf20Sopenharmony_ci "getattr", 1678c2ecf20Sopenharmony_ci "setcred", 1688c2ecf20Sopenharmony_ci "getcred", 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci "chmod", 1718c2ecf20Sopenharmony_ci "chown", 1728c2ecf20Sopenharmony_ci "chgrp", 1738c2ecf20Sopenharmony_ci "lock", 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci "mmap", 1768c2ecf20Sopenharmony_ci "mprot", 1778c2ecf20Sopenharmony_ci "link", 1788c2ecf20Sopenharmony_ci "snapshot", 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci "unknown", 1818c2ecf20Sopenharmony_ci "unknown", 1828c2ecf20Sopenharmony_ci "unknown", 1838c2ecf20Sopenharmony_ci "unknown", 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci "unknown", 1868c2ecf20Sopenharmony_ci "unknown", 1878c2ecf20Sopenharmony_ci "unknown", 1888c2ecf20Sopenharmony_ci "unknown", 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci "stack", 1918c2ecf20Sopenharmony_ci "change_onexec", 1928c2ecf20Sopenharmony_ci "change_profile", 1938c2ecf20Sopenharmony_ci "change_hat", 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci/** 1978c2ecf20Sopenharmony_ci * aa_perm_mask_to_str - convert a perm mask to its short string 1988c2ecf20Sopenharmony_ci * @str: character buffer to store string in (at least 10 characters) 1998c2ecf20Sopenharmony_ci * @str_size: size of the @str buffer 2008c2ecf20Sopenharmony_ci * @chrs: NUL-terminated character buffer of permission characters 2018c2ecf20Sopenharmony_ci * @mask: permission mask to convert 2028c2ecf20Sopenharmony_ci */ 2038c2ecf20Sopenharmony_civoid aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci unsigned int i, perm = 1; 2068c2ecf20Sopenharmony_ci size_t num_chrs = strlen(chrs); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci for (i = 0; i < num_chrs; perm <<= 1, i++) { 2098c2ecf20Sopenharmony_ci if (mask & perm) { 2108c2ecf20Sopenharmony_ci /* Ensure that one byte is left for NUL-termination */ 2118c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(str_size <= 1)) 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci *str++ = chrs[i]; 2158c2ecf20Sopenharmony_ci str_size--; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci *str = '\0'; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_civoid aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, 2228c2ecf20Sopenharmony_ci u32 mask) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci const char *fmt = "%s"; 2258c2ecf20Sopenharmony_ci unsigned int i, perm = 1; 2268c2ecf20Sopenharmony_ci bool prev = false; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci for (i = 0; i < 32; perm <<= 1, i++) { 2298c2ecf20Sopenharmony_ci if (mask & perm) { 2308c2ecf20Sopenharmony_ci audit_log_format(ab, fmt, names[i]); 2318c2ecf20Sopenharmony_ci if (!prev) { 2328c2ecf20Sopenharmony_ci prev = true; 2338c2ecf20Sopenharmony_ci fmt = " %s"; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci} 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_civoid aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, 2408c2ecf20Sopenharmony_ci u32 chrsmask, const char * const *names, u32 namesmask) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci char str[33]; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci audit_log_format(ab, "\""); 2458c2ecf20Sopenharmony_ci if ((mask & chrsmask) && chrs) { 2468c2ecf20Sopenharmony_ci aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask); 2478c2ecf20Sopenharmony_ci mask &= ~chrsmask; 2488c2ecf20Sopenharmony_ci audit_log_format(ab, "%s", str); 2498c2ecf20Sopenharmony_ci if (mask & namesmask) 2508c2ecf20Sopenharmony_ci audit_log_format(ab, " "); 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci if ((mask & namesmask) && names) 2538c2ecf20Sopenharmony_ci aa_audit_perm_names(ab, names, mask & namesmask); 2548c2ecf20Sopenharmony_ci audit_log_format(ab, "\""); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/** 2588c2ecf20Sopenharmony_ci * aa_audit_perms_cb - generic callback fn for auditing perms 2598c2ecf20Sopenharmony_ci * @ab: audit buffer (NOT NULL) 2608c2ecf20Sopenharmony_ci * @va: audit struct to audit values of (NOT NULL) 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_cistatic void aa_audit_perms_cb(struct audit_buffer *ab, void *va) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct common_audit_data *sa = va; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (aad(sa)->request) { 2678c2ecf20Sopenharmony_ci audit_log_format(ab, " requested_mask="); 2688c2ecf20Sopenharmony_ci aa_audit_perm_mask(ab, aad(sa)->request, aa_file_perm_chrs, 2698c2ecf20Sopenharmony_ci PERMS_CHRS_MASK, aa_file_perm_names, 2708c2ecf20Sopenharmony_ci PERMS_NAMES_MASK); 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci if (aad(sa)->denied) { 2738c2ecf20Sopenharmony_ci audit_log_format(ab, "denied_mask="); 2748c2ecf20Sopenharmony_ci aa_audit_perm_mask(ab, aad(sa)->denied, aa_file_perm_chrs, 2758c2ecf20Sopenharmony_ci PERMS_CHRS_MASK, aa_file_perm_names, 2768c2ecf20Sopenharmony_ci PERMS_NAMES_MASK); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci audit_log_format(ab, " peer="); 2798c2ecf20Sopenharmony_ci aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, 2808c2ecf20Sopenharmony_ci FLAGS_NONE, GFP_ATOMIC); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/** 2848c2ecf20Sopenharmony_ci * aa_apply_modes_to_perms - apply namespace and profile flags to perms 2858c2ecf20Sopenharmony_ci * @profile: that perms where computed from 2868c2ecf20Sopenharmony_ci * @perms: perms to apply mode modifiers to 2878c2ecf20Sopenharmony_ci * 2888c2ecf20Sopenharmony_ci * TODO: split into profile and ns based flags for when accumulating perms 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_civoid aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci switch (AUDIT_MODE(profile)) { 2938c2ecf20Sopenharmony_ci case AUDIT_ALL: 2948c2ecf20Sopenharmony_ci perms->audit = ALL_PERMS_MASK; 2958c2ecf20Sopenharmony_ci fallthrough; 2968c2ecf20Sopenharmony_ci case AUDIT_NOQUIET: 2978c2ecf20Sopenharmony_ci perms->quiet = 0; 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci case AUDIT_QUIET: 3008c2ecf20Sopenharmony_ci perms->audit = 0; 3018c2ecf20Sopenharmony_ci fallthrough; 3028c2ecf20Sopenharmony_ci case AUDIT_QUIET_DENIED: 3038c2ecf20Sopenharmony_ci perms->quiet = ALL_PERMS_MASK; 3048c2ecf20Sopenharmony_ci break; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if (KILL_MODE(profile)) 3088c2ecf20Sopenharmony_ci perms->kill = ALL_PERMS_MASK; 3098c2ecf20Sopenharmony_ci else if (COMPLAIN_MODE(profile)) 3108c2ecf20Sopenharmony_ci perms->complain = ALL_PERMS_MASK; 3118c2ecf20Sopenharmony_ci/* 3128c2ecf20Sopenharmony_ci * TODO: 3138c2ecf20Sopenharmony_ci * else if (PROMPT_MODE(profile)) 3148c2ecf20Sopenharmony_ci * perms->prompt = ALL_PERMS_MASK; 3158c2ecf20Sopenharmony_ci */ 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic u32 map_other(u32 x) 3198c2ecf20Sopenharmony_ci{ 3208c2ecf20Sopenharmony_ci return ((x & 0x3) << 8) | /* SETATTR/GETATTR */ 3218c2ecf20Sopenharmony_ci ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */ 3228c2ecf20Sopenharmony_ci ((x & 0x60) << 19); /* SETOPT/GETOPT */ 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_civoid aa_compute_perms(struct aa_dfa *dfa, unsigned int state, 3268c2ecf20Sopenharmony_ci struct aa_perms *perms) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci *perms = (struct aa_perms) { 3298c2ecf20Sopenharmony_ci .allow = dfa_user_allow(dfa, state), 3308c2ecf20Sopenharmony_ci .audit = dfa_user_audit(dfa, state), 3318c2ecf20Sopenharmony_ci .quiet = dfa_user_quiet(dfa, state), 3328c2ecf20Sopenharmony_ci }; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* for v5 perm mapping in the policydb, the other set is used 3358c2ecf20Sopenharmony_ci * to extend the general perm set 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci perms->allow |= map_other(dfa_other_allow(dfa, state)); 3388c2ecf20Sopenharmony_ci perms->audit |= map_other(dfa_other_audit(dfa, state)); 3398c2ecf20Sopenharmony_ci perms->quiet |= map_other(dfa_other_quiet(dfa, state)); 3408c2ecf20Sopenharmony_ci// perms->xindex = dfa_user_xindex(dfa, state); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/** 3448c2ecf20Sopenharmony_ci * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms 3458c2ecf20Sopenharmony_ci * @accum - perms struct to accumulate into 3468c2ecf20Sopenharmony_ci * @addend - perms struct to add to @accum 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_civoid aa_perms_accum_raw(struct aa_perms *accum, struct aa_perms *addend) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci accum->deny |= addend->deny; 3518c2ecf20Sopenharmony_ci accum->allow &= addend->allow & ~addend->deny; 3528c2ecf20Sopenharmony_ci accum->audit |= addend->audit & addend->allow; 3538c2ecf20Sopenharmony_ci accum->quiet &= addend->quiet & ~addend->allow; 3548c2ecf20Sopenharmony_ci accum->kill |= addend->kill & ~addend->allow; 3558c2ecf20Sopenharmony_ci accum->stop |= addend->stop & ~addend->allow; 3568c2ecf20Sopenharmony_ci accum->complain |= addend->complain & ~addend->allow & ~addend->deny; 3578c2ecf20Sopenharmony_ci accum->cond |= addend->cond & ~addend->allow & ~addend->deny; 3588c2ecf20Sopenharmony_ci accum->hide &= addend->hide & ~addend->allow; 3598c2ecf20Sopenharmony_ci accum->prompt |= addend->prompt & ~addend->allow & ~addend->deny; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci/** 3638c2ecf20Sopenharmony_ci * aa_perms_accum - accumulate perms, masking off overlapping perms 3648c2ecf20Sopenharmony_ci * @accum - perms struct to accumulate into 3658c2ecf20Sopenharmony_ci * @addend - perms struct to add to @accum 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_civoid aa_perms_accum(struct aa_perms *accum, struct aa_perms *addend) 3688c2ecf20Sopenharmony_ci{ 3698c2ecf20Sopenharmony_ci accum->deny |= addend->deny; 3708c2ecf20Sopenharmony_ci accum->allow &= addend->allow & ~accum->deny; 3718c2ecf20Sopenharmony_ci accum->audit |= addend->audit & accum->allow; 3728c2ecf20Sopenharmony_ci accum->quiet &= addend->quiet & ~accum->allow; 3738c2ecf20Sopenharmony_ci accum->kill |= addend->kill & ~accum->allow; 3748c2ecf20Sopenharmony_ci accum->stop |= addend->stop & ~accum->allow; 3758c2ecf20Sopenharmony_ci accum->complain |= addend->complain & ~accum->allow & ~accum->deny; 3768c2ecf20Sopenharmony_ci accum->cond |= addend->cond & ~accum->allow & ~accum->deny; 3778c2ecf20Sopenharmony_ci accum->hide &= addend->hide & ~accum->allow; 3788c2ecf20Sopenharmony_ci accum->prompt |= addend->prompt & ~accum->allow & ~accum->deny; 3798c2ecf20Sopenharmony_ci} 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_civoid aa_profile_match_label(struct aa_profile *profile, struct aa_label *label, 3828c2ecf20Sopenharmony_ci int type, u32 request, struct aa_perms *perms) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci /* TODO: doesn't yet handle extended types */ 3858c2ecf20Sopenharmony_ci unsigned int state; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci state = aa_dfa_next(profile->policy.dfa, 3888c2ecf20Sopenharmony_ci profile->policy.start[AA_CLASS_LABEL], 3898c2ecf20Sopenharmony_ci type); 3908c2ecf20Sopenharmony_ci aa_label_match(profile, label, state, false, request, perms); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci/* currently unused */ 3958c2ecf20Sopenharmony_ciint aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, 3968c2ecf20Sopenharmony_ci u32 request, int type, u32 *deny, 3978c2ecf20Sopenharmony_ci struct common_audit_data *sa) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct aa_perms perms; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci aad(sa)->label = &profile->label; 4028c2ecf20Sopenharmony_ci aad(sa)->peer = &target->label; 4038c2ecf20Sopenharmony_ci aad(sa)->request = request; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci aa_profile_match_label(profile, &target->label, type, request, &perms); 4068c2ecf20Sopenharmony_ci aa_apply_modes_to_perms(profile, &perms); 4078c2ecf20Sopenharmony_ci *deny |= request & perms.deny; 4088c2ecf20Sopenharmony_ci return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb); 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci/** 4128c2ecf20Sopenharmony_ci * aa_check_perms - do audit mode selection based on perms set 4138c2ecf20Sopenharmony_ci * @profile: profile being checked 4148c2ecf20Sopenharmony_ci * @perms: perms computed for the request 4158c2ecf20Sopenharmony_ci * @request: requested perms 4168c2ecf20Sopenharmony_ci * @deny: Returns: explicit deny set 4178c2ecf20Sopenharmony_ci * @sa: initialized audit structure (MAY BE NULL if not auditing) 4188c2ecf20Sopenharmony_ci * @cb: callback fn for type specific fields (MAY BE NULL) 4198c2ecf20Sopenharmony_ci * 4208c2ecf20Sopenharmony_ci * Returns: 0 if permission else error code 4218c2ecf20Sopenharmony_ci * 4228c2ecf20Sopenharmony_ci * Note: profile audit modes need to be set before calling by setting the 4238c2ecf20Sopenharmony_ci * perm masks appropriately. 4248c2ecf20Sopenharmony_ci * 4258c2ecf20Sopenharmony_ci * If not auditing then complain mode is not enabled and the 4268c2ecf20Sopenharmony_ci * error code will indicate whether there was an explicit deny 4278c2ecf20Sopenharmony_ci * with a positive value. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ciint aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, 4308c2ecf20Sopenharmony_ci u32 request, struct common_audit_data *sa, 4318c2ecf20Sopenharmony_ci void (*cb)(struct audit_buffer *, void *)) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci int type, error; 4348c2ecf20Sopenharmony_ci u32 denied = request & (~perms->allow | perms->deny); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (likely(!denied)) { 4378c2ecf20Sopenharmony_ci /* mask off perms that are not being force audited */ 4388c2ecf20Sopenharmony_ci request &= perms->audit; 4398c2ecf20Sopenharmony_ci if (!request || !sa) 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci type = AUDIT_APPARMOR_AUDIT; 4438c2ecf20Sopenharmony_ci error = 0; 4448c2ecf20Sopenharmony_ci } else { 4458c2ecf20Sopenharmony_ci error = -EACCES; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (denied & perms->kill) 4488c2ecf20Sopenharmony_ci type = AUDIT_APPARMOR_KILL; 4498c2ecf20Sopenharmony_ci else if (denied == (denied & perms->complain)) 4508c2ecf20Sopenharmony_ci type = AUDIT_APPARMOR_ALLOWED; 4518c2ecf20Sopenharmony_ci else 4528c2ecf20Sopenharmony_ci type = AUDIT_APPARMOR_DENIED; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (denied == (denied & perms->hide)) 4558c2ecf20Sopenharmony_ci error = -ENOENT; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci denied &= ~perms->quiet; 4588c2ecf20Sopenharmony_ci if (!sa || !denied) 4598c2ecf20Sopenharmony_ci return error; 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (sa) { 4638c2ecf20Sopenharmony_ci aad(sa)->label = &profile->label; 4648c2ecf20Sopenharmony_ci aad(sa)->request = request; 4658c2ecf20Sopenharmony_ci aad(sa)->denied = denied; 4668c2ecf20Sopenharmony_ci aad(sa)->error = error; 4678c2ecf20Sopenharmony_ci aa_audit_msg(type, sa, cb); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci if (type == AUDIT_APPARMOR_ALLOWED) 4718c2ecf20Sopenharmony_ci error = 0; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci return error; 4748c2ecf20Sopenharmony_ci} 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci/** 4788c2ecf20Sopenharmony_ci * aa_policy_init - initialize a policy structure 4798c2ecf20Sopenharmony_ci * @policy: policy to initialize (NOT NULL) 4808c2ecf20Sopenharmony_ci * @prefix: prefix name if any is required. (MAYBE NULL) 4818c2ecf20Sopenharmony_ci * @name: name of the policy, init will make a copy of it (NOT NULL) 4828c2ecf20Sopenharmony_ci * @gfp: allocation mode 4838c2ecf20Sopenharmony_ci * 4848c2ecf20Sopenharmony_ci * Note: this fn creates a copy of strings passed in 4858c2ecf20Sopenharmony_ci * 4868c2ecf20Sopenharmony_ci * Returns: true if policy init successful 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_cibool aa_policy_init(struct aa_policy *policy, const char *prefix, 4898c2ecf20Sopenharmony_ci const char *name, gfp_t gfp) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci char *hname; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci /* freed by policy_free */ 4948c2ecf20Sopenharmony_ci if (prefix) { 4958c2ecf20Sopenharmony_ci hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp); 4968c2ecf20Sopenharmony_ci if (hname) 4978c2ecf20Sopenharmony_ci sprintf(hname, "%s//%s", prefix, name); 4988c2ecf20Sopenharmony_ci } else { 4998c2ecf20Sopenharmony_ci hname = aa_str_alloc(strlen(name) + 1, gfp); 5008c2ecf20Sopenharmony_ci if (hname) 5018c2ecf20Sopenharmony_ci strcpy(hname, name); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci if (!hname) 5048c2ecf20Sopenharmony_ci return false; 5058c2ecf20Sopenharmony_ci policy->hname = hname; 5068c2ecf20Sopenharmony_ci /* base.name is a substring of fqname */ 5078c2ecf20Sopenharmony_ci policy->name = basename(policy->hname); 5088c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&policy->list); 5098c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&policy->profiles); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci return true; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci/** 5158c2ecf20Sopenharmony_ci * aa_policy_destroy - free the elements referenced by @policy 5168c2ecf20Sopenharmony_ci * @policy: policy that is to have its elements freed (NOT NULL) 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_civoid aa_policy_destroy(struct aa_policy *policy) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci AA_BUG(on_list_rcu(&policy->profiles)); 5218c2ecf20Sopenharmony_ci AA_BUG(on_list_rcu(&policy->list)); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /* don't free name as its a subset of hname */ 5248c2ecf20Sopenharmony_ci aa_put_str(policy->hname); 5258c2ecf20Sopenharmony_ci} 526