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