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