1 /* 2 * AppArmor security module 3 * 4 * This file contains basic common functions used in AppArmor 5 * 6 * Copyright (C) 1998-2008 Novell/SUSE 7 * Copyright 2009-2010 Canonical Ltd. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation, version 2 of the 12 * License. 13 */ 14 15 #include <linux/ctype.h> 16 #include <linux/mm.h> 17 #include <linux/slab.h> 18 #include <linux/string.h> 19 #include <linux/vmalloc.h> 20 21 #include "include/audit.h" 22 #include "include/apparmor.h" 23 #include "include/lib.h" 24 #include "include/perms.h" 25 #include "include/policy.h" 26 27 struct aa_perms nullperms; 28 struct aa_perms allperms = { .allow = ALL_PERMS_MASK, 29 .quiet = ALL_PERMS_MASK, 30 .hide = ALL_PERMS_MASK }; 31 32 /** 33 * aa_split_fqname - split a fqname into a profile and namespace name 34 * @fqname: a full qualified name in namespace profile format (NOT NULL) 35 * @ns_name: pointer to portion of the string containing the ns name (NOT NULL) 36 * 37 * Returns: profile name or NULL if one is not specified 38 * 39 * Split a namespace name from a profile name (see policy.c for naming 40 * description). If a portion of the name is missing it returns NULL for 41 * that portion. 42 * 43 * NOTE: may modify the @fqname string. The pointers returned point 44 * into the @fqname string. 45 */ 46 char *aa_split_fqname(char *fqname, char **ns_name) 47 { 48 char *name = strim(fqname); 49 50 *ns_name = NULL; 51 if (name[0] == ':') { 52 char *split = strchr(&name[1], ':'); 53 *ns_name = skip_spaces(&name[1]); 54 if (split) { 55 /* overwrite ':' with \0 */ 56 *split++ = 0; 57 if (strncmp(split, "//", 2) == 0) 58 split += 2; 59 name = skip_spaces(split); 60 } else 61 /* a ns name without a following profile is allowed */ 62 name = NULL; 63 } 64 if (name && *name == 0) 65 name = NULL; 66 67 return name; 68 } 69 70 /** 71 * skipn_spaces - Removes leading whitespace from @str. 72 * @str: The string to be stripped. 73 * 74 * Returns a pointer to the first non-whitespace character in @str. 75 * if all whitespace will return NULL 76 */ 77 78 const char *skipn_spaces(const char *str, size_t n) 79 { 80 for (; n && isspace(*str); --n) 81 ++str; 82 if (n) 83 return (char *)str; 84 return NULL; 85 } 86 87 const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, 88 size_t *ns_len) 89 { 90 const char *end = fqname + n; 91 const char *name = skipn_spaces(fqname, n); 92 93 if (!name) 94 return NULL; 95 *ns_name = NULL; 96 *ns_len = 0; 97 if (name[0] == ':') { 98 char *split = strnchr(&name[1], end - &name[1], ':'); 99 *ns_name = skipn_spaces(&name[1], end - &name[1]); 100 if (!*ns_name) 101 return NULL; 102 if (split) { 103 *ns_len = split - *ns_name; 104 if (*ns_len == 0) 105 *ns_name = NULL; 106 split++; 107 if (end - split > 1 && strncmp(split, "//", 2) == 0) 108 split += 2; 109 name = skipn_spaces(split, end - split); 110 } else { 111 /* a ns name without a following profile is allowed */ 112 name = NULL; 113 *ns_len = end - *ns_name; 114 } 115 } 116 if (name && *name == 0) 117 name = NULL; 118 119 return name; 120 } 121 122 /** 123 * aa_info_message - log a none profile related status message 124 * @str: message to log 125 */ 126 void aa_info_message(const char *str) 127 { 128 if (audit_enabled) { 129 DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, NULL); 130 131 aad(&sa)->info = str; 132 aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); 133 } 134 printk(KERN_INFO "AppArmor: %s\n", str); 135 } 136 137 const char aa_file_perm_chrs[] = "xwracd km l "; 138 const char *aa_file_perm_names[] = { 139 "exec", 140 "write", 141 "read", 142 "append", 143 144 "create", 145 "delete", 146 "open", 147 "rename", 148 149 "setattr", 150 "getattr", 151 "setcred", 152 "getcred", 153 154 "chmod", 155 "chown", 156 "chgrp", 157 "lock", 158 159 "mmap", 160 "mprot", 161 "link", 162 "snapshot", 163 164 "unknown", 165 "unknown", 166 "unknown", 167 "unknown", 168 169 "unknown", 170 "unknown", 171 "unknown", 172 "unknown", 173 174 "stack", 175 "change_onexec", 176 "change_profile", 177 "change_hat", 178 }; 179 180 /** 181 * aa_perm_mask_to_str - convert a perm mask to its short string 182 * @str: character buffer to store string in (at least 10 characters) 183 * @mask: permission mask to convert 184 */ 185 void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask) 186 { 187 unsigned int i, perm = 1; 188 189 for (i = 0; i < 32; perm <<= 1, i++) { 190 if (mask & perm) 191 *str++ = chrs[i]; 192 } 193 *str = '\0'; 194 } 195 196 void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask) 197 { 198 const char *fmt = "%s"; 199 unsigned int i, perm = 1; 200 bool prev = false; 201 202 for (i = 0; i < 32; perm <<= 1, i++) { 203 if (mask & perm) { 204 audit_log_format(ab, fmt, names[i]); 205 if (!prev) { 206 prev = true; 207 fmt = " %s"; 208 } 209 } 210 } 211 } 212 213 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, 214 u32 chrsmask, const char **names, u32 namesmask) 215 { 216 char str[33]; 217 218 audit_log_format(ab, "\""); 219 if ((mask & chrsmask) && chrs) { 220 aa_perm_mask_to_str(str, chrs, mask & chrsmask); 221 mask &= ~chrsmask; 222 audit_log_format(ab, "%s", str); 223 if (mask & namesmask) 224 audit_log_format(ab, " "); 225 } 226 if ((mask & namesmask) && names) 227 aa_audit_perm_names(ab, names, mask & namesmask); 228 audit_log_format(ab, "\""); 229 } 230 231 /** 232 * aa_apply_modes_to_perms - apply namespace and profile flags to perms 233 * @profile: that perms where computed from 234 * @perms: perms to apply mode modifiers to 235 * 236 * TODO: split into profile and ns based flags for when accumulating perms 237 */ 238 void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms) 239 { 240 switch (AUDIT_MODE(profile)) { 241 case AUDIT_ALL: 242 perms->audit = ALL_PERMS_MASK; 243 /* fall through */ 244 case AUDIT_NOQUIET: 245 perms->quiet = 0; 246 break; 247 case AUDIT_QUIET: 248 perms->audit = 0; 249 /* fall through */ 250 case AUDIT_QUIET_DENIED: 251 perms->quiet = ALL_PERMS_MASK; 252 break; 253 } 254 255 if (KILL_MODE(profile)) 256 perms->kill = ALL_PERMS_MASK; 257 else if (COMPLAIN_MODE(profile)) 258 perms->complain = ALL_PERMS_MASK; 259 /* 260 * TODO: 261 * else if (PROMPT_MODE(profile)) 262 * perms->prompt = ALL_PERMS_MASK; 263 */ 264 } 265 266 static u32 map_other(u32 x) 267 { 268 return ((x & 0x3) << 8) | /* SETATTR/GETATTR */ 269 ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */ 270 ((x & 0x60) << 19); /* SETOPT/GETOPT */ 271 } 272 273 void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, 274 struct aa_perms *perms) 275 { 276 perms->deny = 0; 277 perms->kill = perms->stop = 0; 278 perms->complain = perms->cond = 0; 279 perms->hide = 0; 280 perms->prompt = 0; 281 perms->allow = dfa_user_allow(dfa, state); 282 perms->audit = dfa_user_audit(dfa, state); 283 perms->quiet = dfa_user_quiet(dfa, state); 284 285 /* for v5 perm mapping in the policydb, the other set is used 286 * to extend the general perm set 287 */ 288 perms->allow |= map_other(dfa_other_allow(dfa, state)); 289 perms->audit |= map_other(dfa_other_audit(dfa, state)); 290 perms->quiet |= map_other(dfa_other_quiet(dfa, state)); 291 // perms->xindex = dfa_user_xindex(dfa, state); 292 } 293 294 /** 295 * aa_policy_init - initialize a policy structure 296 * @policy: policy to initialize (NOT NULL) 297 * @prefix: prefix name if any is required. (MAYBE NULL) 298 * @name: name of the policy, init will make a copy of it (NOT NULL) 299 * 300 * Note: this fn creates a copy of strings passed in 301 * 302 * Returns: true if policy init successful 303 */ 304 bool aa_policy_init(struct aa_policy *policy, const char *prefix, 305 const char *name, gfp_t gfp) 306 { 307 /* freed by policy_free */ 308 if (prefix) { 309 policy->hname = kmalloc(strlen(prefix) + strlen(name) + 3, 310 gfp); 311 if (policy->hname) 312 sprintf((char *)policy->hname, "%s//%s", prefix, name); 313 } else 314 policy->hname = kstrdup(name, gfp); 315 if (!policy->hname) 316 return false; 317 /* base.name is a substring of fqname */ 318 policy->name = basename(policy->hname); 319 INIT_LIST_HEAD(&policy->list); 320 INIT_LIST_HEAD(&policy->profiles); 321 322 return true; 323 } 324 325 /** 326 * aa_policy_destroy - free the elements referenced by @policy 327 * @policy: policy that is to have its elements freed (NOT NULL) 328 */ 329 void aa_policy_destroy(struct aa_policy *policy) 330 { 331 AA_BUG(on_list_rcu(&policy->profiles)); 332 AA_BUG(on_list_rcu(&policy->list)); 333 334 /* don't free name as its a subset of hname */ 335 kzfree(policy->hname); 336 } 337