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 __counted char *aa_str_alloc(int size, gfp_t gfp) 138 { 139 struct counted_str *str; 140 141 str = kmalloc(sizeof(struct counted_str) + size, gfp); 142 if (!str) 143 return NULL; 144 145 kref_init(&str->count); 146 return str->name; 147 } 148 149 void aa_str_kref(struct kref *kref) 150 { 151 kfree(container_of(kref, struct counted_str, count)); 152 } 153 154 155 const char aa_file_perm_chrs[] = "xwracd km l "; 156 const char *aa_file_perm_names[] = { 157 "exec", 158 "write", 159 "read", 160 "append", 161 162 "create", 163 "delete", 164 "open", 165 "rename", 166 167 "setattr", 168 "getattr", 169 "setcred", 170 "getcred", 171 172 "chmod", 173 "chown", 174 "chgrp", 175 "lock", 176 177 "mmap", 178 "mprot", 179 "link", 180 "snapshot", 181 182 "unknown", 183 "unknown", 184 "unknown", 185 "unknown", 186 187 "unknown", 188 "unknown", 189 "unknown", 190 "unknown", 191 192 "stack", 193 "change_onexec", 194 "change_profile", 195 "change_hat", 196 }; 197 198 /** 199 * aa_perm_mask_to_str - convert a perm mask to its short string 200 * @str: character buffer to store string in (at least 10 characters) 201 * @mask: permission mask to convert 202 */ 203 void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask) 204 { 205 unsigned int i, perm = 1; 206 207 for (i = 0; i < 32; perm <<= 1, i++) { 208 if (mask & perm) 209 *str++ = chrs[i]; 210 } 211 *str = '\0'; 212 } 213 214 void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask) 215 { 216 const char *fmt = "%s"; 217 unsigned int i, perm = 1; 218 bool prev = false; 219 220 for (i = 0; i < 32; perm <<= 1, i++) { 221 if (mask & perm) { 222 audit_log_format(ab, fmt, names[i]); 223 if (!prev) { 224 prev = true; 225 fmt = " %s"; 226 } 227 } 228 } 229 } 230 231 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, 232 u32 chrsmask, const char **names, u32 namesmask) 233 { 234 char str[33]; 235 236 audit_log_format(ab, "\""); 237 if ((mask & chrsmask) && chrs) { 238 aa_perm_mask_to_str(str, chrs, mask & chrsmask); 239 mask &= ~chrsmask; 240 audit_log_format(ab, "%s", str); 241 if (mask & namesmask) 242 audit_log_format(ab, " "); 243 } 244 if ((mask & namesmask) && names) 245 aa_audit_perm_names(ab, names, mask & namesmask); 246 audit_log_format(ab, "\""); 247 } 248 249 /** 250 * aa_apply_modes_to_perms - apply namespace and profile flags to perms 251 * @profile: that perms where computed from 252 * @perms: perms to apply mode modifiers to 253 * 254 * TODO: split into profile and ns based flags for when accumulating perms 255 */ 256 void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms) 257 { 258 switch (AUDIT_MODE(profile)) { 259 case AUDIT_ALL: 260 perms->audit = ALL_PERMS_MASK; 261 /* fall through */ 262 case AUDIT_NOQUIET: 263 perms->quiet = 0; 264 break; 265 case AUDIT_QUIET: 266 perms->audit = 0; 267 /* fall through */ 268 case AUDIT_QUIET_DENIED: 269 perms->quiet = ALL_PERMS_MASK; 270 break; 271 } 272 273 if (KILL_MODE(profile)) 274 perms->kill = ALL_PERMS_MASK; 275 else if (COMPLAIN_MODE(profile)) 276 perms->complain = ALL_PERMS_MASK; 277 /* 278 * TODO: 279 * else if (PROMPT_MODE(profile)) 280 * perms->prompt = ALL_PERMS_MASK; 281 */ 282 } 283 284 static u32 map_other(u32 x) 285 { 286 return ((x & 0x3) << 8) | /* SETATTR/GETATTR */ 287 ((x & 0x1c) << 18) | /* ACCEPT/BIND/LISTEN */ 288 ((x & 0x60) << 19); /* SETOPT/GETOPT */ 289 } 290 291 void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, 292 struct aa_perms *perms) 293 { 294 perms->deny = 0; 295 perms->kill = perms->stop = 0; 296 perms->complain = perms->cond = 0; 297 perms->hide = 0; 298 perms->prompt = 0; 299 perms->allow = dfa_user_allow(dfa, state); 300 perms->audit = dfa_user_audit(dfa, state); 301 perms->quiet = dfa_user_quiet(dfa, state); 302 303 /* for v5 perm mapping in the policydb, the other set is used 304 * to extend the general perm set 305 */ 306 perms->allow |= map_other(dfa_other_allow(dfa, state)); 307 perms->audit |= map_other(dfa_other_audit(dfa, state)); 308 perms->quiet |= map_other(dfa_other_quiet(dfa, state)); 309 // perms->xindex = dfa_user_xindex(dfa, state); 310 } 311 312 /** 313 * aa_policy_init - initialize a policy structure 314 * @policy: policy to initialize (NOT NULL) 315 * @prefix: prefix name if any is required. (MAYBE NULL) 316 * @name: name of the policy, init will make a copy of it (NOT NULL) 317 * @gfp: allocation mode 318 * 319 * Note: this fn creates a copy of strings passed in 320 * 321 * Returns: true if policy init successful 322 */ 323 bool aa_policy_init(struct aa_policy *policy, const char *prefix, 324 const char *name, gfp_t gfp) 325 { 326 char *hname; 327 328 /* freed by policy_free */ 329 if (prefix) { 330 hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp); 331 if (hname) 332 sprintf(hname, "%s//%s", prefix, name); 333 } else { 334 hname = aa_str_alloc(strlen(name) + 1, gfp); 335 if (hname) 336 strcpy(hname, name); 337 } 338 if (!hname) 339 return false; 340 policy->hname = hname; 341 /* base.name is a substring of fqname */ 342 policy->name = basename(policy->hname); 343 INIT_LIST_HEAD(&policy->list); 344 INIT_LIST_HEAD(&policy->profiles); 345 346 return true; 347 } 348 349 /** 350 * aa_policy_destroy - free the elements referenced by @policy 351 * @policy: policy that is to have its elements freed (NOT NULL) 352 */ 353 void aa_policy_destroy(struct aa_policy *policy) 354 { 355 AA_BUG(on_list_rcu(&policy->profiles)); 356 AA_BUG(on_list_rcu(&policy->list)); 357 358 /* don't free name as its a subset of hname */ 359 aa_put_str(policy->hname); 360 } 361