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