1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * AppArmor security module 4 * 5 * This file contains basic common functions used in AppArmor 6 * 7 * Copyright (C) 1998-2008 Novell/SUSE 8 * Copyright 2009-2010 Canonical Ltd. 9 */ 10 11 #include <linux/ctype.h> 12 #include <linux/mm.h> 13 #include <linux/slab.h> 14 #include <linux/string.h> 15 #include <linux/vmalloc.h> 16 17 #include "include/audit.h" 18 #include "include/apparmor.h" 19 #include "include/lib.h" 20 #include "include/perms.h" 21 #include "include/policy.h" 22 23 struct aa_perms nullperms; 24 struct aa_perms allperms = { .allow = ALL_PERMS_MASK, 25 .quiet = ALL_PERMS_MASK, 26 .hide = ALL_PERMS_MASK }; 27 28 struct val_table_ent { 29 const char *str; 30 int value; 31 }; 32 33 static struct val_table_ent debug_values_table[] = { 34 { "N", DEBUG_NONE }, 35 { "none", DEBUG_NONE }, 36 { "n", DEBUG_NONE }, 37 { "0", DEBUG_NONE }, 38 { "all", DEBUG_ALL }, 39 { "Y", DEBUG_ALL }, 40 { "y", DEBUG_ALL }, 41 { "1", DEBUG_ALL }, 42 { "abs_root", DEBUG_LABEL_ABS_ROOT }, 43 { "label", DEBUG_LABEL }, 44 { "domain", DEBUG_DOMAIN }, 45 { "policy", DEBUG_POLICY }, 46 { "interface", DEBUG_INTERFACE }, 47 { "unpack", DEBUG_UNPACK }, 48 { NULL, 0 } 49 }; 50 51 static struct val_table_ent *val_table_find_ent(struct val_table_ent *table, 52 const char *name, size_t len) 53 { 54 struct val_table_ent *entry; 55 56 for (entry = table; entry->str != NULL; entry++) { 57 if (strncmp(entry->str, name, len) == 0 && 58 strlen(entry->str) == len) 59 return entry; 60 } 61 return NULL; 62 } 63 64 int aa_parse_debug_params(const char *str) 65 { 66 struct val_table_ent *ent; 67 const char *next; 68 int val = 0; 69 70 do { 71 size_t n = strcspn(str, "\r\n,"); 72 73 next = str + n; 74 ent = val_table_find_ent(debug_values_table, str, next - str); 75 if (ent) 76 val |= ent->value; 77 else 78 AA_DEBUG(DEBUG_INTERFACE, "unknown debug type '%.*s'", 79 (int)(next - str), str); 80 str = next + 1; 81 } while (*next != 0); 82 return val; 83 } 84 85 /** 86 * val_mask_to_str - convert a perm mask to its short string 87 * @str: character buffer to store string in (at least 10 characters) 88 * @size: size of the @str buffer 89 * @table: NUL-terminated character buffer of permission characters (NOT NULL) 90 * @mask: permission mask to convert 91 */ 92 static int val_mask_to_str(char *str, size_t size, 93 const struct val_table_ent *table, u32 mask) 94 { 95 const struct val_table_ent *ent; 96 int total = 0; 97 98 for (ent = table; ent->str; ent++) { 99 if (ent->value && (ent->value & mask) == ent->value) { 100 int len = scnprintf(str, size, "%s%s", total ? "," : "", 101 ent->str); 102 size -= len; 103 str += len; 104 total += len; 105 mask &= ~ent->value; 106 } 107 } 108 109 return total; 110 } 111 112 int aa_print_debug_params(char *buffer) 113 { 114 if (!aa_g_debug) 115 return sprintf(buffer, "N"); 116 return val_mask_to_str(buffer, PAGE_SIZE, debug_values_table, 117 aa_g_debug); 118 } 119 120 bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp) 121 { 122 struct aa_str_table_ent *n; 123 int i; 124 125 if (t->size == newsize) 126 return true; 127 n = kcalloc(newsize, sizeof(*n), gfp); 128 if (!n) 129 return false; 130 for (i = 0; i < min(t->size, newsize); i++) 131 n[i] = t->table[i]; 132 for (; i < t->size; i++) 133 kfree_sensitive(t->table[i].strs); 134 if (newsize > t->size) 135 memset(&n[t->size], 0, (newsize-t->size)*sizeof(*n)); 136 kfree_sensitive(t->table); 137 t->table = n; 138 t->size = newsize; 139 140 return true; 141 } 142 143 /** 144 * aa_destroy_str_table - free entries str table 145 * @t: the string table to free (MAYBE NULL) 146 */ 147 void aa_destroy_str_table(struct aa_str_table *t) 148 { 149 int i; 150 151 if (t) { 152 if (!t->table) 153 return; 154 155 for (i = 0; i < t->size; i++) 156 kfree_sensitive(t->table[i].strs); 157 kfree_sensitive(t->table); 158 t->table = NULL; 159 t->size = 0; 160 } 161 } 162 163 /** 164 * skipn_spaces - Removes leading whitespace from @str. 165 * @str: The string to be stripped. 166 * @n: length of str to parse, will stop at \0 if encountered before n 167 * 168 * Returns a pointer to the first non-whitespace character in @str. 169 * if all whitespace will return NULL 170 */ 171 172 const char *skipn_spaces(const char *str, size_t n) 173 { 174 for (; n && isspace(*str); --n) 175 ++str; 176 if (n) 177 return (char *)str; 178 return NULL; 179 } 180 181 const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, 182 size_t *ns_len) 183 { 184 const char *end = fqname + n; 185 const char *name = skipn_spaces(fqname, n); 186 187 *ns_name = NULL; 188 *ns_len = 0; 189 190 if (!name) 191 return NULL; 192 193 if (name[0] == ':') { 194 char *split = strnchr(&name[1], end - &name[1], ':'); 195 *ns_name = skipn_spaces(&name[1], end - &name[1]); 196 if (!*ns_name) 197 return NULL; 198 if (split) { 199 *ns_len = split - *ns_name; 200 if (*ns_len == 0) 201 *ns_name = NULL; 202 split++; 203 if (end - split > 1 && strncmp(split, "//", 2) == 0) 204 split += 2; 205 name = skipn_spaces(split, end - split); 206 } else { 207 /* a ns name without a following profile is allowed */ 208 name = NULL; 209 *ns_len = end - *ns_name; 210 } 211 } 212 if (name && *name == 0) 213 name = NULL; 214 215 return name; 216 } 217 218 /** 219 * aa_info_message - log a none profile related status message 220 * @str: message to log 221 */ 222 void aa_info_message(const char *str) 223 { 224 if (audit_enabled) { 225 DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, NULL); 226 227 ad.info = str; 228 aa_audit_msg(AUDIT_APPARMOR_STATUS, &ad, NULL); 229 } 230 printk(KERN_INFO "AppArmor: %s\n", str); 231 } 232 233 __counted char *aa_str_alloc(int size, gfp_t gfp) 234 { 235 struct counted_str *str; 236 237 str = kmalloc(struct_size(str, name, size), gfp); 238 if (!str) 239 return NULL; 240 241 kref_init(&str->count); 242 return str->name; 243 } 244 245 void aa_str_kref(struct kref *kref) 246 { 247 kfree(container_of(kref, struct counted_str, count)); 248 } 249 250 251 const char aa_file_perm_chrs[] = "xwracd km l "; 252 const char *aa_file_perm_names[] = { 253 "exec", 254 "write", 255 "read", 256 "append", 257 258 "create", 259 "delete", 260 "open", 261 "rename", 262 263 "setattr", 264 "getattr", 265 "setcred", 266 "getcred", 267 268 "chmod", 269 "chown", 270 "chgrp", 271 "lock", 272 273 "mmap", 274 "mprot", 275 "link", 276 "snapshot", 277 278 "unknown", 279 "unknown", 280 "unknown", 281 "unknown", 282 283 "unknown", 284 "unknown", 285 "unknown", 286 "unknown", 287 288 "stack", 289 "change_onexec", 290 "change_profile", 291 "change_hat", 292 }; 293 294 /** 295 * aa_perm_mask_to_str - convert a perm mask to its short string 296 * @str: character buffer to store string in (at least 10 characters) 297 * @str_size: size of the @str buffer 298 * @chrs: NUL-terminated character buffer of permission characters 299 * @mask: permission mask to convert 300 */ 301 void aa_perm_mask_to_str(char *str, size_t str_size, const char *chrs, u32 mask) 302 { 303 unsigned int i, perm = 1; 304 size_t num_chrs = strlen(chrs); 305 306 for (i = 0; i < num_chrs; perm <<= 1, i++) { 307 if (mask & perm) { 308 /* Ensure that one byte is left for NUL-termination */ 309 if (WARN_ON_ONCE(str_size <= 1)) 310 break; 311 312 *str++ = chrs[i]; 313 str_size--; 314 } 315 } 316 *str = '\0'; 317 } 318 319 void aa_audit_perm_names(struct audit_buffer *ab, const char * const *names, 320 u32 mask) 321 { 322 const char *fmt = "%s"; 323 unsigned int i, perm = 1; 324 bool prev = false; 325 326 for (i = 0; i < 32; perm <<= 1, i++) { 327 if (mask & perm) { 328 audit_log_format(ab, fmt, names[i]); 329 if (!prev) { 330 prev = true; 331 fmt = " %s"; 332 } 333 } 334 } 335 } 336 337 void aa_audit_perm_mask(struct audit_buffer *ab, u32 mask, const char *chrs, 338 u32 chrsmask, const char * const *names, u32 namesmask) 339 { 340 char str[33]; 341 342 audit_log_format(ab, "\""); 343 if ((mask & chrsmask) && chrs) { 344 aa_perm_mask_to_str(str, sizeof(str), chrs, mask & chrsmask); 345 mask &= ~chrsmask; 346 audit_log_format(ab, "%s", str); 347 if (mask & namesmask) 348 audit_log_format(ab, " "); 349 } 350 if ((mask & namesmask) && names) 351 aa_audit_perm_names(ab, names, mask & namesmask); 352 audit_log_format(ab, "\""); 353 } 354 355 /** 356 * aa_apply_modes_to_perms - apply namespace and profile flags to perms 357 * @profile: that perms where computed from 358 * @perms: perms to apply mode modifiers to 359 * 360 * TODO: split into profile and ns based flags for when accumulating perms 361 */ 362 void aa_apply_modes_to_perms(struct aa_profile *profile, struct aa_perms *perms) 363 { 364 switch (AUDIT_MODE(profile)) { 365 case AUDIT_ALL: 366 perms->audit = ALL_PERMS_MASK; 367 fallthrough; 368 case AUDIT_NOQUIET: 369 perms->quiet = 0; 370 break; 371 case AUDIT_QUIET: 372 perms->audit = 0; 373 fallthrough; 374 case AUDIT_QUIET_DENIED: 375 perms->quiet = ALL_PERMS_MASK; 376 break; 377 } 378 379 if (KILL_MODE(profile)) 380 perms->kill = ALL_PERMS_MASK; 381 else if (COMPLAIN_MODE(profile)) 382 perms->complain = ALL_PERMS_MASK; 383 else if (USER_MODE(profile)) 384 perms->prompt = ALL_PERMS_MASK; 385 } 386 387 void aa_profile_match_label(struct aa_profile *profile, 388 struct aa_ruleset *rules, 389 struct aa_label *label, 390 int type, u32 request, struct aa_perms *perms) 391 { 392 /* TODO: doesn't yet handle extended types */ 393 aa_state_t state; 394 395 state = aa_dfa_next(rules->policy->dfa, 396 rules->policy->start[AA_CLASS_LABEL], 397 type); 398 aa_label_match(profile, rules, label, state, false, request, perms); 399 } 400 401 402 /** 403 * aa_check_perms - do audit mode selection based on perms set 404 * @profile: profile being checked 405 * @perms: perms computed for the request 406 * @request: requested perms 407 * @ad: initialized audit structure (MAY BE NULL if not auditing) 408 * @cb: callback fn for type specific fields (MAY BE NULL) 409 * 410 * Returns: 0 if permission else error code 411 * 412 * Note: profile audit modes need to be set before calling by setting the 413 * perm masks appropriately. 414 * 415 * If not auditing then complain mode is not enabled and the 416 * error code will indicate whether there was an explicit deny 417 * with a positive value. 418 */ 419 int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, 420 u32 request, struct apparmor_audit_data *ad, 421 void (*cb)(struct audit_buffer *, void *)) 422 { 423 int type, error; 424 u32 denied = request & (~perms->allow | perms->deny); 425 426 if (likely(!denied)) { 427 /* mask off perms that are not being force audited */ 428 request &= perms->audit; 429 if (!request || !ad) 430 return 0; 431 432 type = AUDIT_APPARMOR_AUDIT; 433 error = 0; 434 } else { 435 error = -EACCES; 436 437 if (denied & perms->kill) 438 type = AUDIT_APPARMOR_KILL; 439 else if (denied == (denied & perms->complain)) 440 type = AUDIT_APPARMOR_ALLOWED; 441 else 442 type = AUDIT_APPARMOR_DENIED; 443 444 if (denied == (denied & perms->hide)) 445 error = -ENOENT; 446 447 denied &= ~perms->quiet; 448 if (!ad || !denied) 449 return error; 450 } 451 452 if (ad) { 453 ad->subj_label = &profile->label; 454 ad->request = request; 455 ad->denied = denied; 456 ad->error = error; 457 aa_audit_msg(type, ad, cb); 458 } 459 460 if (type == AUDIT_APPARMOR_ALLOWED) 461 error = 0; 462 463 return error; 464 } 465 466 467 /** 468 * aa_policy_init - initialize a policy structure 469 * @policy: policy to initialize (NOT NULL) 470 * @prefix: prefix name if any is required. (MAYBE NULL) 471 * @name: name of the policy, init will make a copy of it (NOT NULL) 472 * @gfp: allocation mode 473 * 474 * Note: this fn creates a copy of strings passed in 475 * 476 * Returns: true if policy init successful 477 */ 478 bool aa_policy_init(struct aa_policy *policy, const char *prefix, 479 const char *name, gfp_t gfp) 480 { 481 char *hname; 482 size_t hname_sz; 483 484 hname_sz = (prefix ? strlen(prefix) + 2 : 0) + strlen(name) + 1; 485 /* freed by policy_free */ 486 hname = aa_str_alloc(hname_sz, gfp); 487 if (!hname) 488 return false; 489 if (prefix) 490 scnprintf(hname, hname_sz, "%s//%s", prefix, name); 491 else 492 strscpy(hname, name, hname_sz); 493 policy->hname = hname; 494 /* base.name is a substring of fqname */ 495 policy->name = basename(policy->hname); 496 INIT_LIST_HEAD(&policy->list); 497 INIT_LIST_HEAD(&policy->profiles); 498 499 return true; 500 } 501 502 /** 503 * aa_policy_destroy - free the elements referenced by @policy 504 * @policy: policy that is to have its elements freed (NOT NULL) 505 */ 506 void aa_policy_destroy(struct aa_policy *policy) 507 { 508 AA_BUG(on_list_rcu(&policy->profiles)); 509 AA_BUG(on_list_rcu(&policy->list)); 510 511 /* don't free name as its a subset of hname */ 512 aa_put_str(policy->hname); 513 } 514