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