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" 24fe6bb31fSJohn Johansen #include "include/policy.h" 25cdff2642SJohn Johansen 26cdff2642SJohn Johansen /** 27cdff2642SJohn Johansen * aa_split_fqname - split a fqname into a profile and namespace name 28cdff2642SJohn Johansen * @fqname: a full qualified name in namespace profile format (NOT NULL) 29cdff2642SJohn Johansen * @ns_name: pointer to portion of the string containing the ns name (NOT NULL) 30cdff2642SJohn Johansen * 31cdff2642SJohn Johansen * Returns: profile name or NULL if one is not specified 32cdff2642SJohn Johansen * 33cdff2642SJohn Johansen * Split a namespace name from a profile name (see policy.c for naming 34cdff2642SJohn Johansen * description). If a portion of the name is missing it returns NULL for 35cdff2642SJohn Johansen * that portion. 36cdff2642SJohn Johansen * 37cdff2642SJohn Johansen * NOTE: may modify the @fqname string. The pointers returned point 38cdff2642SJohn Johansen * into the @fqname string. 39cdff2642SJohn Johansen */ 40cdff2642SJohn Johansen char *aa_split_fqname(char *fqname, char **ns_name) 41cdff2642SJohn Johansen { 42cdff2642SJohn Johansen char *name = strim(fqname); 43cdff2642SJohn Johansen 44cdff2642SJohn Johansen *ns_name = NULL; 45cdff2642SJohn Johansen if (name[0] == ':') { 46cdff2642SJohn Johansen char *split = strchr(&name[1], ':'); 4704ccd53fSJohn Johansen *ns_name = skip_spaces(&name[1]); 48cdff2642SJohn Johansen if (split) { 49cdff2642SJohn Johansen /* overwrite ':' with \0 */ 502654bfbcSJohn Johansen *split++ = 0; 512654bfbcSJohn Johansen if (strncmp(split, "//", 2) == 0) 522654bfbcSJohn Johansen split += 2; 532654bfbcSJohn Johansen name = skip_spaces(split); 54cdff2642SJohn Johansen } else 55cdff2642SJohn Johansen /* a ns name without a following profile is allowed */ 56cdff2642SJohn Johansen name = NULL; 57cdff2642SJohn Johansen } 58cdff2642SJohn Johansen if (name && *name == 0) 59cdff2642SJohn Johansen name = NULL; 60cdff2642SJohn Johansen 61cdff2642SJohn Johansen return name; 62cdff2642SJohn Johansen } 63cdff2642SJohn Johansen 64cdff2642SJohn Johansen /** 653b0aaf58SJohn Johansen * skipn_spaces - Removes leading whitespace from @str. 663b0aaf58SJohn Johansen * @str: The string to be stripped. 673b0aaf58SJohn Johansen * 683b0aaf58SJohn Johansen * Returns a pointer to the first non-whitespace character in @str. 693b0aaf58SJohn Johansen * if all whitespace will return NULL 703b0aaf58SJohn Johansen */ 713b0aaf58SJohn Johansen 723b0aaf58SJohn Johansen static const char *skipn_spaces(const char *str, size_t n) 733b0aaf58SJohn Johansen { 743b0aaf58SJohn Johansen for (; n && isspace(*str); --n) 753b0aaf58SJohn Johansen ++str; 763b0aaf58SJohn Johansen if (n) 773b0aaf58SJohn Johansen return (char *)str; 783b0aaf58SJohn Johansen return NULL; 793b0aaf58SJohn Johansen } 803b0aaf58SJohn Johansen 813b0aaf58SJohn Johansen const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, 823b0aaf58SJohn Johansen size_t *ns_len) 833b0aaf58SJohn Johansen { 843b0aaf58SJohn Johansen const char *end = fqname + n; 853b0aaf58SJohn Johansen const char *name = skipn_spaces(fqname, n); 863b0aaf58SJohn Johansen 873b0aaf58SJohn Johansen if (!name) 883b0aaf58SJohn Johansen return NULL; 893b0aaf58SJohn Johansen *ns_name = NULL; 903b0aaf58SJohn Johansen *ns_len = 0; 913b0aaf58SJohn Johansen if (name[0] == ':') { 923b0aaf58SJohn Johansen char *split = strnchr(&name[1], end - &name[1], ':'); 933b0aaf58SJohn Johansen *ns_name = skipn_spaces(&name[1], end - &name[1]); 943b0aaf58SJohn Johansen if (!*ns_name) 953b0aaf58SJohn Johansen return NULL; 963b0aaf58SJohn Johansen if (split) { 973b0aaf58SJohn Johansen *ns_len = split - *ns_name; 983b0aaf58SJohn Johansen if (*ns_len == 0) 993b0aaf58SJohn Johansen *ns_name = NULL; 1003b0aaf58SJohn Johansen split++; 1013b0aaf58SJohn Johansen if (end - split > 1 && strncmp(split, "//", 2) == 0) 1023b0aaf58SJohn Johansen split += 2; 1033b0aaf58SJohn Johansen name = skipn_spaces(split, end - split); 1043b0aaf58SJohn Johansen } else { 1053b0aaf58SJohn Johansen /* a ns name without a following profile is allowed */ 1063b0aaf58SJohn Johansen name = NULL; 1073b0aaf58SJohn Johansen *ns_len = end - *ns_name; 1083b0aaf58SJohn Johansen } 1093b0aaf58SJohn Johansen } 1103b0aaf58SJohn Johansen if (name && *name == 0) 1113b0aaf58SJohn Johansen name = NULL; 1123b0aaf58SJohn Johansen 1133b0aaf58SJohn Johansen return name; 1143b0aaf58SJohn Johansen } 1153b0aaf58SJohn Johansen 1163b0aaf58SJohn Johansen /** 117cdff2642SJohn Johansen * aa_info_message - log a none profile related status message 118cdff2642SJohn Johansen * @str: message to log 119cdff2642SJohn Johansen */ 120cdff2642SJohn Johansen void aa_info_message(const char *str) 121cdff2642SJohn Johansen { 122cdff2642SJohn Johansen if (audit_enabled) { 123cdff2642SJohn Johansen struct common_audit_data sa; 1243b3b0e4fSEric Paris struct apparmor_audit_data aad = {0,}; 12550c205f5SEric Paris sa.type = LSM_AUDIT_DATA_NONE; 1263b3b0e4fSEric Paris sa.aad = &aad; 1273b3b0e4fSEric Paris aad.info = str; 128cdff2642SJohn Johansen aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); 129cdff2642SJohn Johansen } 130cdff2642SJohn Johansen printk(KERN_INFO "AppArmor: %s\n", str); 131cdff2642SJohn Johansen } 132cdff2642SJohn Johansen 133cdff2642SJohn Johansen /** 1340ca554b9SJohn Johansen * __aa_kvmalloc - do allocation preferring kmalloc but falling back to vmalloc 1350ca554b9SJohn Johansen * @size: how many bytes of memory are required 1360ca554b9SJohn Johansen * @flags: the type of memory to allocate (see kmalloc). 137cdff2642SJohn Johansen * 138cdff2642SJohn Johansen * Return: allocated buffer or NULL if failed 139cdff2642SJohn Johansen * 140cdff2642SJohn Johansen * It is possible that policy being loaded from the user is larger than 141cdff2642SJohn Johansen * what can be allocated by kmalloc, in those cases fall back to vmalloc. 142cdff2642SJohn Johansen */ 1430ca554b9SJohn Johansen void *__aa_kvmalloc(size_t size, gfp_t flags) 144cdff2642SJohn Johansen { 145cdff2642SJohn Johansen void *buffer = NULL; 146cdff2642SJohn Johansen 147cdff2642SJohn Johansen if (size == 0) 148cdff2642SJohn Johansen return NULL; 149cdff2642SJohn Johansen 150cdff2642SJohn Johansen /* do not attempt kmalloc if we need more than 16 pages at once */ 151cdff2642SJohn Johansen if (size <= (16*PAGE_SIZE)) 152a7f6c1b6STetsuo Handa buffer = kmalloc(size, flags | GFP_KERNEL | __GFP_NORETRY | 153a7f6c1b6STetsuo Handa __GFP_NOWARN); 154cdff2642SJohn Johansen if (!buffer) { 1550ca554b9SJohn Johansen if (flags & __GFP_ZERO) 1560ca554b9SJohn Johansen buffer = vzalloc(size); 1570ca554b9SJohn Johansen else 158cdff2642SJohn Johansen buffer = vmalloc(size); 159cdff2642SJohn Johansen } 160cdff2642SJohn Johansen return buffer; 161cdff2642SJohn Johansen } 162fe6bb31fSJohn Johansen 163fe6bb31fSJohn Johansen /** 164fe6bb31fSJohn Johansen * aa_policy_init - initialize a policy structure 165fe6bb31fSJohn Johansen * @policy: policy to initialize (NOT NULL) 166fe6bb31fSJohn Johansen * @prefix: prefix name if any is required. (MAYBE NULL) 167fe6bb31fSJohn Johansen * @name: name of the policy, init will make a copy of it (NOT NULL) 168fe6bb31fSJohn Johansen * 169fe6bb31fSJohn Johansen * Note: this fn creates a copy of strings passed in 170fe6bb31fSJohn Johansen * 171fe6bb31fSJohn Johansen * Returns: true if policy init successful 172fe6bb31fSJohn Johansen */ 173fe6bb31fSJohn Johansen bool aa_policy_init(struct aa_policy *policy, const char *prefix, 174*d102d895SJohn Johansen const char *name, gfp_t gfp) 175fe6bb31fSJohn Johansen { 176fe6bb31fSJohn Johansen /* freed by policy_free */ 177fe6bb31fSJohn Johansen if (prefix) { 178fe6bb31fSJohn Johansen policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3, 179*d102d895SJohn Johansen gfp); 180fe6bb31fSJohn Johansen if (policy->hname) 181bbe4a7c8SJohn Johansen sprintf((char *)policy->hname, "%s//%s", prefix, name); 182fe6bb31fSJohn Johansen } else 183*d102d895SJohn Johansen policy->hname = kstrdup(name, gfp); 184fe6bb31fSJohn Johansen if (!policy->hname) 185fe6bb31fSJohn Johansen return 0; 186fe6bb31fSJohn Johansen /* base.name is a substring of fqname */ 187*d102d895SJohn Johansen policy->name = basename(policy->hname); 188fe6bb31fSJohn Johansen INIT_LIST_HEAD(&policy->list); 189fe6bb31fSJohn Johansen INIT_LIST_HEAD(&policy->profiles); 190fe6bb31fSJohn Johansen 191fe6bb31fSJohn Johansen return 1; 192fe6bb31fSJohn Johansen } 193fe6bb31fSJohn Johansen 194fe6bb31fSJohn Johansen /** 195fe6bb31fSJohn Johansen * aa_policy_destroy - free the elements referenced by @policy 196fe6bb31fSJohn Johansen * @policy: policy that is to have its elements freed (NOT NULL) 197fe6bb31fSJohn Johansen */ 198fe6bb31fSJohn Johansen void aa_policy_destroy(struct aa_policy *policy) 199fe6bb31fSJohn Johansen { 200fe6bb31fSJohn Johansen /* still contains profiles -- invalid */ 201fe6bb31fSJohn Johansen if (on_list_rcu(&policy->profiles)) { 202fe6bb31fSJohn Johansen AA_ERROR("%s: internal error, policy '%s' contains profiles\n", 203fe6bb31fSJohn Johansen __func__, policy->name); 204fe6bb31fSJohn Johansen } 205fe6bb31fSJohn Johansen if (on_list_rcu(&policy->list)) { 206fe6bb31fSJohn Johansen AA_ERROR("%s: internal error, policy '%s' still on list\n", 207fe6bb31fSJohn Johansen __func__, policy->name); 208fe6bb31fSJohn Johansen } 209fe6bb31fSJohn Johansen 210fe6bb31fSJohn Johansen /* don't free name as its a subset of hname */ 211fe6bb31fSJohn Johansen kzfree(policy->hname); 212fe6bb31fSJohn Johansen } 213