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, struct aa_label *label, 335 int type, u32 request, struct aa_perms *perms) 336 { 337 /* TODO: doesn't yet handle extended types */ 338 aa_state_t state; 339 340 state = aa_dfa_next(profile->policy.dfa, 341 profile->policy.start[AA_CLASS_LABEL], 342 type); 343 aa_label_match(profile, label, state, false, request, perms); 344 } 345 346 347 /* currently unused */ 348 int aa_profile_label_perm(struct aa_profile *profile, struct aa_profile *target, 349 u32 request, int type, u32 *deny, 350 struct common_audit_data *sa) 351 { 352 struct aa_perms perms; 353 354 aad(sa)->label = &profile->label; 355 aad(sa)->peer = &target->label; 356 aad(sa)->request = request; 357 358 aa_profile_match_label(profile, &target->label, type, request, &perms); 359 aa_apply_modes_to_perms(profile, &perms); 360 *deny |= request & perms.deny; 361 return aa_check_perms(profile, &perms, request, sa, aa_audit_perms_cb); 362 } 363 364 /** 365 * aa_check_perms - do audit mode selection based on perms set 366 * @profile: profile being checked 367 * @perms: perms computed for the request 368 * @request: requested perms 369 * @deny: Returns: explicit deny set 370 * @sa: initialized audit structure (MAY BE NULL if not auditing) 371 * @cb: callback fn for type specific fields (MAY BE NULL) 372 * 373 * Returns: 0 if permission else error code 374 * 375 * Note: profile audit modes need to be set before calling by setting the 376 * perm masks appropriately. 377 * 378 * If not auditing then complain mode is not enabled and the 379 * error code will indicate whether there was an explicit deny 380 * with a positive value. 381 */ 382 int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, 383 u32 request, struct common_audit_data *sa, 384 void (*cb)(struct audit_buffer *, void *)) 385 { 386 int type, error; 387 u32 denied = request & (~perms->allow | perms->deny); 388 389 if (likely(!denied)) { 390 /* mask off perms that are not being force audited */ 391 request &= perms->audit; 392 if (!request || !sa) 393 return 0; 394 395 type = AUDIT_APPARMOR_AUDIT; 396 error = 0; 397 } else { 398 error = -EACCES; 399 400 if (denied & perms->kill) 401 type = AUDIT_APPARMOR_KILL; 402 else if (denied == (denied & perms->complain)) 403 type = AUDIT_APPARMOR_ALLOWED; 404 else 405 type = AUDIT_APPARMOR_DENIED; 406 407 if (denied == (denied & perms->hide)) 408 error = -ENOENT; 409 410 denied &= ~perms->quiet; 411 if (!sa || !denied) 412 return error; 413 } 414 415 if (sa) { 416 aad(sa)->label = &profile->label; 417 aad(sa)->request = request; 418 aad(sa)->denied = denied; 419 aad(sa)->error = error; 420 aa_audit_msg(type, sa, cb); 421 } 422 423 if (type == AUDIT_APPARMOR_ALLOWED) 424 error = 0; 425 426 return error; 427 } 428 429 430 /** 431 * aa_policy_init - initialize a policy structure 432 * @policy: policy to initialize (NOT NULL) 433 * @prefix: prefix name if any is required. (MAYBE NULL) 434 * @name: name of the policy, init will make a copy of it (NOT NULL) 435 * @gfp: allocation mode 436 * 437 * Note: this fn creates a copy of strings passed in 438 * 439 * Returns: true if policy init successful 440 */ 441 bool aa_policy_init(struct aa_policy *policy, const char *prefix, 442 const char *name, gfp_t gfp) 443 { 444 char *hname; 445 446 /* freed by policy_free */ 447 if (prefix) { 448 hname = aa_str_alloc(strlen(prefix) + strlen(name) + 3, gfp); 449 if (hname) 450 sprintf(hname, "%s//%s", prefix, name); 451 } else { 452 hname = aa_str_alloc(strlen(name) + 1, gfp); 453 if (hname) 454 strcpy(hname, name); 455 } 456 if (!hname) 457 return false; 458 policy->hname = hname; 459 /* base.name is a substring of fqname */ 460 policy->name = basename(policy->hname); 461 INIT_LIST_HEAD(&policy->list); 462 INIT_LIST_HEAD(&policy->profiles); 463 464 return true; 465 } 466 467 /** 468 * aa_policy_destroy - free the elements referenced by @policy 469 * @policy: policy that is to have its elements freed (NOT NULL) 470 */ 471 void aa_policy_destroy(struct aa_policy *policy) 472 { 473 AA_BUG(on_list_rcu(&policy->profiles)); 474 AA_BUG(on_list_rcu(&policy->list)); 475 476 /* don't free name as its a subset of hname */ 477 aa_put_str(policy->hname); 478 } 479