162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Implementation of the security services. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Authors : Stephen Smalley, <stephen.smalley.work@gmail.com> 662306a36Sopenharmony_ci * James Morris <jmorris@redhat.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Support for enhanced MLS infrastructure. 1162306a36Sopenharmony_ci * Support for context based audit filters. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Added conditional policy language extensions 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Updated: Hewlett-Packard <paul@paul-moore.com> 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * Added support for NetLabel 2062306a36Sopenharmony_ci * Added support for the policy capability bitmap 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Updated: Chad Sellers <csellers@tresys.com> 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Added validation of kernel classes and permissions 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com> 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * Added support for bounds domain and audit messaged on masked permissions 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * Updated: Guido Trentalancia <guido@trentalancia.com> 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * Added support for runtime switching of the policy type 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * Copyright (C) 2008, 2009 NEC Corporation 3562306a36Sopenharmony_ci * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. 3662306a36Sopenharmony_ci * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 3762306a36Sopenharmony_ci * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC 3862306a36Sopenharmony_ci * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 3962306a36Sopenharmony_ci */ 4062306a36Sopenharmony_ci#include <linux/kernel.h> 4162306a36Sopenharmony_ci#include <linux/slab.h> 4262306a36Sopenharmony_ci#include <linux/string.h> 4362306a36Sopenharmony_ci#include <linux/spinlock.h> 4462306a36Sopenharmony_ci#include <linux/rcupdate.h> 4562306a36Sopenharmony_ci#include <linux/errno.h> 4662306a36Sopenharmony_ci#include <linux/in.h> 4762306a36Sopenharmony_ci#include <linux/sched.h> 4862306a36Sopenharmony_ci#include <linux/audit.h> 4962306a36Sopenharmony_ci#include <linux/vmalloc.h> 5062306a36Sopenharmony_ci#include <linux/lsm_hooks.h> 5162306a36Sopenharmony_ci#include <net/netlabel.h> 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#include "flask.h" 5462306a36Sopenharmony_ci#include "avc.h" 5562306a36Sopenharmony_ci#include "avc_ss.h" 5662306a36Sopenharmony_ci#include "security.h" 5762306a36Sopenharmony_ci#include "context.h" 5862306a36Sopenharmony_ci#include "policydb.h" 5962306a36Sopenharmony_ci#include "sidtab.h" 6062306a36Sopenharmony_ci#include "services.h" 6162306a36Sopenharmony_ci#include "conditional.h" 6262306a36Sopenharmony_ci#include "mls.h" 6362306a36Sopenharmony_ci#include "objsec.h" 6462306a36Sopenharmony_ci#include "netlabel.h" 6562306a36Sopenharmony_ci#include "xfrm.h" 6662306a36Sopenharmony_ci#include "ebitmap.h" 6762306a36Sopenharmony_ci#include "audit.h" 6862306a36Sopenharmony_ci#include "policycap_names.h" 6962306a36Sopenharmony_ci#include "ima.h" 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct selinux_policy_convert_data { 7262306a36Sopenharmony_ci struct convert_context_args args; 7362306a36Sopenharmony_ci struct sidtab_convert_params sidtab_params; 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* Forward declaration. */ 7762306a36Sopenharmony_cistatic int context_struct_to_string(struct policydb *policydb, 7862306a36Sopenharmony_ci struct context *context, 7962306a36Sopenharmony_ci char **scontext, 8062306a36Sopenharmony_ci u32 *scontext_len); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int sidtab_entry_to_string(struct policydb *policydb, 8362306a36Sopenharmony_ci struct sidtab *sidtab, 8462306a36Sopenharmony_ci struct sidtab_entry *entry, 8562306a36Sopenharmony_ci char **scontext, 8662306a36Sopenharmony_ci u32 *scontext_len); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void context_struct_compute_av(struct policydb *policydb, 8962306a36Sopenharmony_ci struct context *scontext, 9062306a36Sopenharmony_ci struct context *tcontext, 9162306a36Sopenharmony_ci u16 tclass, 9262306a36Sopenharmony_ci struct av_decision *avd, 9362306a36Sopenharmony_ci struct extended_perms *xperms); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int selinux_set_mapping(struct policydb *pol, 9662306a36Sopenharmony_ci const struct security_class_mapping *map, 9762306a36Sopenharmony_ci struct selinux_map *out_map) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci u16 i, j; 10062306a36Sopenharmony_ci bool print_unknown_handle = false; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* Find number of classes in the input mapping */ 10362306a36Sopenharmony_ci if (!map) 10462306a36Sopenharmony_ci return -EINVAL; 10562306a36Sopenharmony_ci i = 0; 10662306a36Sopenharmony_ci while (map[i].name) 10762306a36Sopenharmony_ci i++; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Allocate space for the class records, plus one for class zero */ 11062306a36Sopenharmony_ci out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC); 11162306a36Sopenharmony_ci if (!out_map->mapping) 11262306a36Sopenharmony_ci return -ENOMEM; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* Store the raw class and permission values */ 11562306a36Sopenharmony_ci j = 0; 11662306a36Sopenharmony_ci while (map[j].name) { 11762306a36Sopenharmony_ci const struct security_class_mapping *p_in = map + (j++); 11862306a36Sopenharmony_ci struct selinux_mapping *p_out = out_map->mapping + j; 11962306a36Sopenharmony_ci u16 k; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* An empty class string skips ahead */ 12262306a36Sopenharmony_ci if (!strcmp(p_in->name, "")) { 12362306a36Sopenharmony_ci p_out->num_perms = 0; 12462306a36Sopenharmony_ci continue; 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci p_out->value = string_to_security_class(pol, p_in->name); 12862306a36Sopenharmony_ci if (!p_out->value) { 12962306a36Sopenharmony_ci pr_info("SELinux: Class %s not defined in policy.\n", 13062306a36Sopenharmony_ci p_in->name); 13162306a36Sopenharmony_ci if (pol->reject_unknown) 13262306a36Sopenharmony_ci goto err; 13362306a36Sopenharmony_ci p_out->num_perms = 0; 13462306a36Sopenharmony_ci print_unknown_handle = true; 13562306a36Sopenharmony_ci continue; 13662306a36Sopenharmony_ci } 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci k = 0; 13962306a36Sopenharmony_ci while (p_in->perms[k]) { 14062306a36Sopenharmony_ci /* An empty permission string skips ahead */ 14162306a36Sopenharmony_ci if (!*p_in->perms[k]) { 14262306a36Sopenharmony_ci k++; 14362306a36Sopenharmony_ci continue; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci p_out->perms[k] = string_to_av_perm(pol, p_out->value, 14662306a36Sopenharmony_ci p_in->perms[k]); 14762306a36Sopenharmony_ci if (!p_out->perms[k]) { 14862306a36Sopenharmony_ci pr_info("SELinux: Permission %s in class %s not defined in policy.\n", 14962306a36Sopenharmony_ci p_in->perms[k], p_in->name); 15062306a36Sopenharmony_ci if (pol->reject_unknown) 15162306a36Sopenharmony_ci goto err; 15262306a36Sopenharmony_ci print_unknown_handle = true; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci k++; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci p_out->num_perms = k; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (print_unknown_handle) 16162306a36Sopenharmony_ci pr_info("SELinux: the above unknown classes and permissions will be %s\n", 16262306a36Sopenharmony_ci pol->allow_unknown ? "allowed" : "denied"); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci out_map->size = i; 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_cierr: 16762306a36Sopenharmony_ci kfree(out_map->mapping); 16862306a36Sopenharmony_ci out_map->mapping = NULL; 16962306a36Sopenharmony_ci return -EINVAL; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci * Get real, policy values from mapped values 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic u16 unmap_class(struct selinux_map *map, u16 tclass) 17762306a36Sopenharmony_ci{ 17862306a36Sopenharmony_ci if (tclass < map->size) 17962306a36Sopenharmony_ci return map->mapping[tclass].value; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return tclass; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* 18562306a36Sopenharmony_ci * Get kernel value for class from its policy value 18662306a36Sopenharmony_ci */ 18762306a36Sopenharmony_cistatic u16 map_class(struct selinux_map *map, u16 pol_value) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci u16 i; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci for (i = 1; i < map->size; i++) { 19262306a36Sopenharmony_ci if (map->mapping[i].value == pol_value) 19362306a36Sopenharmony_ci return i; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return SECCLASS_NULL; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void map_decision(struct selinux_map *map, 20062306a36Sopenharmony_ci u16 tclass, struct av_decision *avd, 20162306a36Sopenharmony_ci int allow_unknown) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci if (tclass < map->size) { 20462306a36Sopenharmony_ci struct selinux_mapping *mapping = &map->mapping[tclass]; 20562306a36Sopenharmony_ci unsigned int i, n = mapping->num_perms; 20662306a36Sopenharmony_ci u32 result; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci for (i = 0, result = 0; i < n; i++) { 20962306a36Sopenharmony_ci if (avd->allowed & mapping->perms[i]) 21062306a36Sopenharmony_ci result |= (u32)1<<i; 21162306a36Sopenharmony_ci if (allow_unknown && !mapping->perms[i]) 21262306a36Sopenharmony_ci result |= (u32)1<<i; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci avd->allowed = result; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci for (i = 0, result = 0; i < n; i++) 21762306a36Sopenharmony_ci if (avd->auditallow & mapping->perms[i]) 21862306a36Sopenharmony_ci result |= (u32)1<<i; 21962306a36Sopenharmony_ci avd->auditallow = result; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci for (i = 0, result = 0; i < n; i++) { 22262306a36Sopenharmony_ci if (avd->auditdeny & mapping->perms[i]) 22362306a36Sopenharmony_ci result |= (u32)1<<i; 22462306a36Sopenharmony_ci if (!allow_unknown && !mapping->perms[i]) 22562306a36Sopenharmony_ci result |= (u32)1<<i; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci /* 22862306a36Sopenharmony_ci * In case the kernel has a bug and requests a permission 22962306a36Sopenharmony_ci * between num_perms and the maximum permission number, we 23062306a36Sopenharmony_ci * should audit that denial 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci for (; i < (sizeof(u32)*8); i++) 23362306a36Sopenharmony_ci result |= (u32)1<<i; 23462306a36Sopenharmony_ci avd->auditdeny = result; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ciint security_mls_enabled(void) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci int mls_enabled; 24162306a36Sopenharmony_ci struct selinux_policy *policy; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (!selinux_initialized()) 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci rcu_read_lock(); 24762306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 24862306a36Sopenharmony_ci mls_enabled = policy->policydb.mls_enabled; 24962306a36Sopenharmony_ci rcu_read_unlock(); 25062306a36Sopenharmony_ci return mls_enabled; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/* 25462306a36Sopenharmony_ci * Return the boolean value of a constraint expression 25562306a36Sopenharmony_ci * when it is applied to the specified source and target 25662306a36Sopenharmony_ci * security contexts. 25762306a36Sopenharmony_ci * 25862306a36Sopenharmony_ci * xcontext is a special beast... It is used by the validatetrans rules 25962306a36Sopenharmony_ci * only. For these rules, scontext is the context before the transition, 26062306a36Sopenharmony_ci * tcontext is the context after the transition, and xcontext is the context 26162306a36Sopenharmony_ci * of the process performing the transition. All other callers of 26262306a36Sopenharmony_ci * constraint_expr_eval should pass in NULL for xcontext. 26362306a36Sopenharmony_ci */ 26462306a36Sopenharmony_cistatic int constraint_expr_eval(struct policydb *policydb, 26562306a36Sopenharmony_ci struct context *scontext, 26662306a36Sopenharmony_ci struct context *tcontext, 26762306a36Sopenharmony_ci struct context *xcontext, 26862306a36Sopenharmony_ci struct constraint_expr *cexpr) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci u32 val1, val2; 27162306a36Sopenharmony_ci struct context *c; 27262306a36Sopenharmony_ci struct role_datum *r1, *r2; 27362306a36Sopenharmony_ci struct mls_level *l1, *l2; 27462306a36Sopenharmony_ci struct constraint_expr *e; 27562306a36Sopenharmony_ci int s[CEXPR_MAXDEPTH]; 27662306a36Sopenharmony_ci int sp = -1; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci for (e = cexpr; e; e = e->next) { 27962306a36Sopenharmony_ci switch (e->expr_type) { 28062306a36Sopenharmony_ci case CEXPR_NOT: 28162306a36Sopenharmony_ci BUG_ON(sp < 0); 28262306a36Sopenharmony_ci s[sp] = !s[sp]; 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci case CEXPR_AND: 28562306a36Sopenharmony_ci BUG_ON(sp < 1); 28662306a36Sopenharmony_ci sp--; 28762306a36Sopenharmony_ci s[sp] &= s[sp + 1]; 28862306a36Sopenharmony_ci break; 28962306a36Sopenharmony_ci case CEXPR_OR: 29062306a36Sopenharmony_ci BUG_ON(sp < 1); 29162306a36Sopenharmony_ci sp--; 29262306a36Sopenharmony_ci s[sp] |= s[sp + 1]; 29362306a36Sopenharmony_ci break; 29462306a36Sopenharmony_ci case CEXPR_ATTR: 29562306a36Sopenharmony_ci if (sp == (CEXPR_MAXDEPTH - 1)) 29662306a36Sopenharmony_ci return 0; 29762306a36Sopenharmony_ci switch (e->attr) { 29862306a36Sopenharmony_ci case CEXPR_USER: 29962306a36Sopenharmony_ci val1 = scontext->user; 30062306a36Sopenharmony_ci val2 = tcontext->user; 30162306a36Sopenharmony_ci break; 30262306a36Sopenharmony_ci case CEXPR_TYPE: 30362306a36Sopenharmony_ci val1 = scontext->type; 30462306a36Sopenharmony_ci val2 = tcontext->type; 30562306a36Sopenharmony_ci break; 30662306a36Sopenharmony_ci case CEXPR_ROLE: 30762306a36Sopenharmony_ci val1 = scontext->role; 30862306a36Sopenharmony_ci val2 = tcontext->role; 30962306a36Sopenharmony_ci r1 = policydb->role_val_to_struct[val1 - 1]; 31062306a36Sopenharmony_ci r2 = policydb->role_val_to_struct[val2 - 1]; 31162306a36Sopenharmony_ci switch (e->op) { 31262306a36Sopenharmony_ci case CEXPR_DOM: 31362306a36Sopenharmony_ci s[++sp] = ebitmap_get_bit(&r1->dominates, 31462306a36Sopenharmony_ci val2 - 1); 31562306a36Sopenharmony_ci continue; 31662306a36Sopenharmony_ci case CEXPR_DOMBY: 31762306a36Sopenharmony_ci s[++sp] = ebitmap_get_bit(&r2->dominates, 31862306a36Sopenharmony_ci val1 - 1); 31962306a36Sopenharmony_ci continue; 32062306a36Sopenharmony_ci case CEXPR_INCOMP: 32162306a36Sopenharmony_ci s[++sp] = (!ebitmap_get_bit(&r1->dominates, 32262306a36Sopenharmony_ci val2 - 1) && 32362306a36Sopenharmony_ci !ebitmap_get_bit(&r2->dominates, 32462306a36Sopenharmony_ci val1 - 1)); 32562306a36Sopenharmony_ci continue; 32662306a36Sopenharmony_ci default: 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci case CEXPR_L1L2: 33162306a36Sopenharmony_ci l1 = &(scontext->range.level[0]); 33262306a36Sopenharmony_ci l2 = &(tcontext->range.level[0]); 33362306a36Sopenharmony_ci goto mls_ops; 33462306a36Sopenharmony_ci case CEXPR_L1H2: 33562306a36Sopenharmony_ci l1 = &(scontext->range.level[0]); 33662306a36Sopenharmony_ci l2 = &(tcontext->range.level[1]); 33762306a36Sopenharmony_ci goto mls_ops; 33862306a36Sopenharmony_ci case CEXPR_H1L2: 33962306a36Sopenharmony_ci l1 = &(scontext->range.level[1]); 34062306a36Sopenharmony_ci l2 = &(tcontext->range.level[0]); 34162306a36Sopenharmony_ci goto mls_ops; 34262306a36Sopenharmony_ci case CEXPR_H1H2: 34362306a36Sopenharmony_ci l1 = &(scontext->range.level[1]); 34462306a36Sopenharmony_ci l2 = &(tcontext->range.level[1]); 34562306a36Sopenharmony_ci goto mls_ops; 34662306a36Sopenharmony_ci case CEXPR_L1H1: 34762306a36Sopenharmony_ci l1 = &(scontext->range.level[0]); 34862306a36Sopenharmony_ci l2 = &(scontext->range.level[1]); 34962306a36Sopenharmony_ci goto mls_ops; 35062306a36Sopenharmony_ci case CEXPR_L2H2: 35162306a36Sopenharmony_ci l1 = &(tcontext->range.level[0]); 35262306a36Sopenharmony_ci l2 = &(tcontext->range.level[1]); 35362306a36Sopenharmony_ci goto mls_ops; 35462306a36Sopenharmony_cimls_ops: 35562306a36Sopenharmony_ci switch (e->op) { 35662306a36Sopenharmony_ci case CEXPR_EQ: 35762306a36Sopenharmony_ci s[++sp] = mls_level_eq(l1, l2); 35862306a36Sopenharmony_ci continue; 35962306a36Sopenharmony_ci case CEXPR_NEQ: 36062306a36Sopenharmony_ci s[++sp] = !mls_level_eq(l1, l2); 36162306a36Sopenharmony_ci continue; 36262306a36Sopenharmony_ci case CEXPR_DOM: 36362306a36Sopenharmony_ci s[++sp] = mls_level_dom(l1, l2); 36462306a36Sopenharmony_ci continue; 36562306a36Sopenharmony_ci case CEXPR_DOMBY: 36662306a36Sopenharmony_ci s[++sp] = mls_level_dom(l2, l1); 36762306a36Sopenharmony_ci continue; 36862306a36Sopenharmony_ci case CEXPR_INCOMP: 36962306a36Sopenharmony_ci s[++sp] = mls_level_incomp(l2, l1); 37062306a36Sopenharmony_ci continue; 37162306a36Sopenharmony_ci default: 37262306a36Sopenharmony_ci BUG(); 37362306a36Sopenharmony_ci return 0; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci break; 37662306a36Sopenharmony_ci default: 37762306a36Sopenharmony_ci BUG(); 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci switch (e->op) { 38262306a36Sopenharmony_ci case CEXPR_EQ: 38362306a36Sopenharmony_ci s[++sp] = (val1 == val2); 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci case CEXPR_NEQ: 38662306a36Sopenharmony_ci s[++sp] = (val1 != val2); 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci default: 38962306a36Sopenharmony_ci BUG(); 39062306a36Sopenharmony_ci return 0; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci break; 39362306a36Sopenharmony_ci case CEXPR_NAMES: 39462306a36Sopenharmony_ci if (sp == (CEXPR_MAXDEPTH-1)) 39562306a36Sopenharmony_ci return 0; 39662306a36Sopenharmony_ci c = scontext; 39762306a36Sopenharmony_ci if (e->attr & CEXPR_TARGET) 39862306a36Sopenharmony_ci c = tcontext; 39962306a36Sopenharmony_ci else if (e->attr & CEXPR_XTARGET) { 40062306a36Sopenharmony_ci c = xcontext; 40162306a36Sopenharmony_ci if (!c) { 40262306a36Sopenharmony_ci BUG(); 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci if (e->attr & CEXPR_USER) 40762306a36Sopenharmony_ci val1 = c->user; 40862306a36Sopenharmony_ci else if (e->attr & CEXPR_ROLE) 40962306a36Sopenharmony_ci val1 = c->role; 41062306a36Sopenharmony_ci else if (e->attr & CEXPR_TYPE) 41162306a36Sopenharmony_ci val1 = c->type; 41262306a36Sopenharmony_ci else { 41362306a36Sopenharmony_ci BUG(); 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci switch (e->op) { 41862306a36Sopenharmony_ci case CEXPR_EQ: 41962306a36Sopenharmony_ci s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); 42062306a36Sopenharmony_ci break; 42162306a36Sopenharmony_ci case CEXPR_NEQ: 42262306a36Sopenharmony_ci s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci default: 42562306a36Sopenharmony_ci BUG(); 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci default: 43062306a36Sopenharmony_ci BUG(); 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci BUG_ON(sp != 0); 43662306a36Sopenharmony_ci return s[0]; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/* 44062306a36Sopenharmony_ci * security_dump_masked_av - dumps masked permissions during 44162306a36Sopenharmony_ci * security_compute_av due to RBAC, MLS/Constraint and Type bounds. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_cistatic int dump_masked_av_helper(void *k, void *d, void *args) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct perm_datum *pdatum = d; 44662306a36Sopenharmony_ci char **permission_names = args; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci BUG_ON(pdatum->value < 1 || pdatum->value > 32); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci permission_names[pdatum->value - 1] = (char *)k; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return 0; 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic void security_dump_masked_av(struct policydb *policydb, 45662306a36Sopenharmony_ci struct context *scontext, 45762306a36Sopenharmony_ci struct context *tcontext, 45862306a36Sopenharmony_ci u16 tclass, 45962306a36Sopenharmony_ci u32 permissions, 46062306a36Sopenharmony_ci const char *reason) 46162306a36Sopenharmony_ci{ 46262306a36Sopenharmony_ci struct common_datum *common_dat; 46362306a36Sopenharmony_ci struct class_datum *tclass_dat; 46462306a36Sopenharmony_ci struct audit_buffer *ab; 46562306a36Sopenharmony_ci char *tclass_name; 46662306a36Sopenharmony_ci char *scontext_name = NULL; 46762306a36Sopenharmony_ci char *tcontext_name = NULL; 46862306a36Sopenharmony_ci char *permission_names[32]; 46962306a36Sopenharmony_ci int index; 47062306a36Sopenharmony_ci u32 length; 47162306a36Sopenharmony_ci bool need_comma = false; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (!permissions) 47462306a36Sopenharmony_ci return; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1); 47762306a36Sopenharmony_ci tclass_dat = policydb->class_val_to_struct[tclass - 1]; 47862306a36Sopenharmony_ci common_dat = tclass_dat->comdatum; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* init permission_names */ 48162306a36Sopenharmony_ci if (common_dat && 48262306a36Sopenharmony_ci hashtab_map(&common_dat->permissions.table, 48362306a36Sopenharmony_ci dump_masked_av_helper, permission_names) < 0) 48462306a36Sopenharmony_ci goto out; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci if (hashtab_map(&tclass_dat->permissions.table, 48762306a36Sopenharmony_ci dump_masked_av_helper, permission_names) < 0) 48862306a36Sopenharmony_ci goto out; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* get scontext/tcontext in text form */ 49162306a36Sopenharmony_ci if (context_struct_to_string(policydb, scontext, 49262306a36Sopenharmony_ci &scontext_name, &length) < 0) 49362306a36Sopenharmony_ci goto out; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (context_struct_to_string(policydb, tcontext, 49662306a36Sopenharmony_ci &tcontext_name, &length) < 0) 49762306a36Sopenharmony_ci goto out; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* audit a message */ 50062306a36Sopenharmony_ci ab = audit_log_start(audit_context(), 50162306a36Sopenharmony_ci GFP_ATOMIC, AUDIT_SELINUX_ERR); 50262306a36Sopenharmony_ci if (!ab) 50362306a36Sopenharmony_ci goto out; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci audit_log_format(ab, "op=security_compute_av reason=%s " 50662306a36Sopenharmony_ci "scontext=%s tcontext=%s tclass=%s perms=", 50762306a36Sopenharmony_ci reason, scontext_name, tcontext_name, tclass_name); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci for (index = 0; index < 32; index++) { 51062306a36Sopenharmony_ci u32 mask = (1 << index); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if ((mask & permissions) == 0) 51362306a36Sopenharmony_ci continue; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci audit_log_format(ab, "%s%s", 51662306a36Sopenharmony_ci need_comma ? "," : "", 51762306a36Sopenharmony_ci permission_names[index] 51862306a36Sopenharmony_ci ? permission_names[index] : "????"); 51962306a36Sopenharmony_ci need_comma = true; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci audit_log_end(ab); 52262306a36Sopenharmony_ciout: 52362306a36Sopenharmony_ci /* release scontext/tcontext */ 52462306a36Sopenharmony_ci kfree(tcontext_name); 52562306a36Sopenharmony_ci kfree(scontext_name); 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci/* 52962306a36Sopenharmony_ci * security_boundary_permission - drops violated permissions 53062306a36Sopenharmony_ci * on boundary constraint. 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_cistatic void type_attribute_bounds_av(struct policydb *policydb, 53362306a36Sopenharmony_ci struct context *scontext, 53462306a36Sopenharmony_ci struct context *tcontext, 53562306a36Sopenharmony_ci u16 tclass, 53662306a36Sopenharmony_ci struct av_decision *avd) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct context lo_scontext; 53962306a36Sopenharmony_ci struct context lo_tcontext, *tcontextp = tcontext; 54062306a36Sopenharmony_ci struct av_decision lo_avd; 54162306a36Sopenharmony_ci struct type_datum *source; 54262306a36Sopenharmony_ci struct type_datum *target; 54362306a36Sopenharmony_ci u32 masked = 0; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci source = policydb->type_val_to_struct[scontext->type - 1]; 54662306a36Sopenharmony_ci BUG_ON(!source); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci if (!source->bounds) 54962306a36Sopenharmony_ci return; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci target = policydb->type_val_to_struct[tcontext->type - 1]; 55262306a36Sopenharmony_ci BUG_ON(!target); 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci memset(&lo_avd, 0, sizeof(lo_avd)); 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); 55762306a36Sopenharmony_ci lo_scontext.type = source->bounds; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (target->bounds) { 56062306a36Sopenharmony_ci memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); 56162306a36Sopenharmony_ci lo_tcontext.type = target->bounds; 56262306a36Sopenharmony_ci tcontextp = &lo_tcontext; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci context_struct_compute_av(policydb, &lo_scontext, 56662306a36Sopenharmony_ci tcontextp, 56762306a36Sopenharmony_ci tclass, 56862306a36Sopenharmony_ci &lo_avd, 56962306a36Sopenharmony_ci NULL); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci masked = ~lo_avd.allowed & avd->allowed; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (likely(!masked)) 57462306a36Sopenharmony_ci return; /* no masked permission */ 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci /* mask violated permissions */ 57762306a36Sopenharmony_ci avd->allowed &= ~masked; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci /* audit masked permissions */ 58062306a36Sopenharmony_ci security_dump_masked_av(policydb, scontext, tcontext, 58162306a36Sopenharmony_ci tclass, masked, "bounds"); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci/* 58562306a36Sopenharmony_ci * flag which drivers have permissions 58662306a36Sopenharmony_ci * only looking for ioctl based extended permissions 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_civoid services_compute_xperms_drivers( 58962306a36Sopenharmony_ci struct extended_perms *xperms, 59062306a36Sopenharmony_ci struct avtab_node *node) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci unsigned int i; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 59562306a36Sopenharmony_ci /* if one or more driver has all permissions allowed */ 59662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) 59762306a36Sopenharmony_ci xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; 59862306a36Sopenharmony_ci } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 59962306a36Sopenharmony_ci /* if allowing permissions within a driver */ 60062306a36Sopenharmony_ci security_xperm_set(xperms->drivers.p, 60162306a36Sopenharmony_ci node->datum.u.xperms->driver); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci xperms->len = 1; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci/* 60862306a36Sopenharmony_ci * Compute access vectors and extended permissions based on a context 60962306a36Sopenharmony_ci * structure pair for the permissions in a particular class. 61062306a36Sopenharmony_ci */ 61162306a36Sopenharmony_cistatic void context_struct_compute_av(struct policydb *policydb, 61262306a36Sopenharmony_ci struct context *scontext, 61362306a36Sopenharmony_ci struct context *tcontext, 61462306a36Sopenharmony_ci u16 tclass, 61562306a36Sopenharmony_ci struct av_decision *avd, 61662306a36Sopenharmony_ci struct extended_perms *xperms) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct constraint_node *constraint; 61962306a36Sopenharmony_ci struct role_allow *ra; 62062306a36Sopenharmony_ci struct avtab_key avkey; 62162306a36Sopenharmony_ci struct avtab_node *node; 62262306a36Sopenharmony_ci struct class_datum *tclass_datum; 62362306a36Sopenharmony_ci struct ebitmap *sattr, *tattr; 62462306a36Sopenharmony_ci struct ebitmap_node *snode, *tnode; 62562306a36Sopenharmony_ci unsigned int i, j; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci avd->allowed = 0; 62862306a36Sopenharmony_ci avd->auditallow = 0; 62962306a36Sopenharmony_ci avd->auditdeny = 0xffffffff; 63062306a36Sopenharmony_ci if (xperms) { 63162306a36Sopenharmony_ci memset(&xperms->drivers, 0, sizeof(xperms->drivers)); 63262306a36Sopenharmony_ci xperms->len = 0; 63362306a36Sopenharmony_ci } 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) { 63662306a36Sopenharmony_ci if (printk_ratelimit()) 63762306a36Sopenharmony_ci pr_warn("SELinux: Invalid class %hu\n", tclass); 63862306a36Sopenharmony_ci return; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci tclass_datum = policydb->class_val_to_struct[tclass - 1]; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* 64462306a36Sopenharmony_ci * If a specific type enforcement rule was defined for 64562306a36Sopenharmony_ci * this permission check, then use it. 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_ci avkey.target_class = tclass; 64862306a36Sopenharmony_ci avkey.specified = AVTAB_AV | AVTAB_XPERMS; 64962306a36Sopenharmony_ci sattr = &policydb->type_attr_map_array[scontext->type - 1]; 65062306a36Sopenharmony_ci tattr = &policydb->type_attr_map_array[tcontext->type - 1]; 65162306a36Sopenharmony_ci ebitmap_for_each_positive_bit(sattr, snode, i) { 65262306a36Sopenharmony_ci ebitmap_for_each_positive_bit(tattr, tnode, j) { 65362306a36Sopenharmony_ci avkey.source_type = i + 1; 65462306a36Sopenharmony_ci avkey.target_type = j + 1; 65562306a36Sopenharmony_ci for (node = avtab_search_node(&policydb->te_avtab, 65662306a36Sopenharmony_ci &avkey); 65762306a36Sopenharmony_ci node; 65862306a36Sopenharmony_ci node = avtab_search_node_next(node, avkey.specified)) { 65962306a36Sopenharmony_ci if (node->key.specified == AVTAB_ALLOWED) 66062306a36Sopenharmony_ci avd->allowed |= node->datum.u.data; 66162306a36Sopenharmony_ci else if (node->key.specified == AVTAB_AUDITALLOW) 66262306a36Sopenharmony_ci avd->auditallow |= node->datum.u.data; 66362306a36Sopenharmony_ci else if (node->key.specified == AVTAB_AUDITDENY) 66462306a36Sopenharmony_ci avd->auditdeny &= node->datum.u.data; 66562306a36Sopenharmony_ci else if (xperms && (node->key.specified & AVTAB_XPERMS)) 66662306a36Sopenharmony_ci services_compute_xperms_drivers(xperms, node); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* Check conditional av table for additional permissions */ 67062306a36Sopenharmony_ci cond_compute_av(&policydb->te_cond_avtab, &avkey, 67162306a36Sopenharmony_ci avd, xperms); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci /* 67762306a36Sopenharmony_ci * Remove any permissions prohibited by a constraint (this includes 67862306a36Sopenharmony_ci * the MLS policy). 67962306a36Sopenharmony_ci */ 68062306a36Sopenharmony_ci constraint = tclass_datum->constraints; 68162306a36Sopenharmony_ci while (constraint) { 68262306a36Sopenharmony_ci if ((constraint->permissions & (avd->allowed)) && 68362306a36Sopenharmony_ci !constraint_expr_eval(policydb, scontext, tcontext, NULL, 68462306a36Sopenharmony_ci constraint->expr)) { 68562306a36Sopenharmony_ci avd->allowed &= ~(constraint->permissions); 68662306a36Sopenharmony_ci } 68762306a36Sopenharmony_ci constraint = constraint->next; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* 69162306a36Sopenharmony_ci * If checking process transition permission and the 69262306a36Sopenharmony_ci * role is changing, then check the (current_role, new_role) 69362306a36Sopenharmony_ci * pair. 69462306a36Sopenharmony_ci */ 69562306a36Sopenharmony_ci if (tclass == policydb->process_class && 69662306a36Sopenharmony_ci (avd->allowed & policydb->process_trans_perms) && 69762306a36Sopenharmony_ci scontext->role != tcontext->role) { 69862306a36Sopenharmony_ci for (ra = policydb->role_allow; ra; ra = ra->next) { 69962306a36Sopenharmony_ci if (scontext->role == ra->role && 70062306a36Sopenharmony_ci tcontext->role == ra->new_role) 70162306a36Sopenharmony_ci break; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci if (!ra) 70462306a36Sopenharmony_ci avd->allowed &= ~policydb->process_trans_perms; 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci /* 70862306a36Sopenharmony_ci * If the given source and target types have boundary 70962306a36Sopenharmony_ci * constraint, lazy checks have to mask any violated 71062306a36Sopenharmony_ci * permission and notice it to userspace via audit. 71162306a36Sopenharmony_ci */ 71262306a36Sopenharmony_ci type_attribute_bounds_av(policydb, scontext, tcontext, 71362306a36Sopenharmony_ci tclass, avd); 71462306a36Sopenharmony_ci} 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_cistatic int security_validtrans_handle_fail(struct selinux_policy *policy, 71762306a36Sopenharmony_ci struct sidtab_entry *oentry, 71862306a36Sopenharmony_ci struct sidtab_entry *nentry, 71962306a36Sopenharmony_ci struct sidtab_entry *tentry, 72062306a36Sopenharmony_ci u16 tclass) 72162306a36Sopenharmony_ci{ 72262306a36Sopenharmony_ci struct policydb *p = &policy->policydb; 72362306a36Sopenharmony_ci struct sidtab *sidtab = policy->sidtab; 72462306a36Sopenharmony_ci char *o = NULL, *n = NULL, *t = NULL; 72562306a36Sopenharmony_ci u32 olen, nlen, tlen; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (sidtab_entry_to_string(p, sidtab, oentry, &o, &olen)) 72862306a36Sopenharmony_ci goto out; 72962306a36Sopenharmony_ci if (sidtab_entry_to_string(p, sidtab, nentry, &n, &nlen)) 73062306a36Sopenharmony_ci goto out; 73162306a36Sopenharmony_ci if (sidtab_entry_to_string(p, sidtab, tentry, &t, &tlen)) 73262306a36Sopenharmony_ci goto out; 73362306a36Sopenharmony_ci audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR, 73462306a36Sopenharmony_ci "op=security_validate_transition seresult=denied" 73562306a36Sopenharmony_ci " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", 73662306a36Sopenharmony_ci o, n, t, sym_name(p, SYM_CLASSES, tclass-1)); 73762306a36Sopenharmony_ciout: 73862306a36Sopenharmony_ci kfree(o); 73962306a36Sopenharmony_ci kfree(n); 74062306a36Sopenharmony_ci kfree(t); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (!enforcing_enabled()) 74362306a36Sopenharmony_ci return 0; 74462306a36Sopenharmony_ci return -EPERM; 74562306a36Sopenharmony_ci} 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_cistatic int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid, 74862306a36Sopenharmony_ci u16 orig_tclass, bool user) 74962306a36Sopenharmony_ci{ 75062306a36Sopenharmony_ci struct selinux_policy *policy; 75162306a36Sopenharmony_ci struct policydb *policydb; 75262306a36Sopenharmony_ci struct sidtab *sidtab; 75362306a36Sopenharmony_ci struct sidtab_entry *oentry; 75462306a36Sopenharmony_ci struct sidtab_entry *nentry; 75562306a36Sopenharmony_ci struct sidtab_entry *tentry; 75662306a36Sopenharmony_ci struct class_datum *tclass_datum; 75762306a36Sopenharmony_ci struct constraint_node *constraint; 75862306a36Sopenharmony_ci u16 tclass; 75962306a36Sopenharmony_ci int rc = 0; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (!selinux_initialized()) 76362306a36Sopenharmony_ci return 0; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci rcu_read_lock(); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 76862306a36Sopenharmony_ci policydb = &policy->policydb; 76962306a36Sopenharmony_ci sidtab = policy->sidtab; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (!user) 77262306a36Sopenharmony_ci tclass = unmap_class(&policy->map, orig_tclass); 77362306a36Sopenharmony_ci else 77462306a36Sopenharmony_ci tclass = orig_tclass; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci if (!tclass || tclass > policydb->p_classes.nprim) { 77762306a36Sopenharmony_ci rc = -EINVAL; 77862306a36Sopenharmony_ci goto out; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci tclass_datum = policydb->class_val_to_struct[tclass - 1]; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci oentry = sidtab_search_entry(sidtab, oldsid); 78362306a36Sopenharmony_ci if (!oentry) { 78462306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 78562306a36Sopenharmony_ci __func__, oldsid); 78662306a36Sopenharmony_ci rc = -EINVAL; 78762306a36Sopenharmony_ci goto out; 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci nentry = sidtab_search_entry(sidtab, newsid); 79162306a36Sopenharmony_ci if (!nentry) { 79262306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 79362306a36Sopenharmony_ci __func__, newsid); 79462306a36Sopenharmony_ci rc = -EINVAL; 79562306a36Sopenharmony_ci goto out; 79662306a36Sopenharmony_ci } 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci tentry = sidtab_search_entry(sidtab, tasksid); 79962306a36Sopenharmony_ci if (!tentry) { 80062306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 80162306a36Sopenharmony_ci __func__, tasksid); 80262306a36Sopenharmony_ci rc = -EINVAL; 80362306a36Sopenharmony_ci goto out; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci constraint = tclass_datum->validatetrans; 80762306a36Sopenharmony_ci while (constraint) { 80862306a36Sopenharmony_ci if (!constraint_expr_eval(policydb, &oentry->context, 80962306a36Sopenharmony_ci &nentry->context, &tentry->context, 81062306a36Sopenharmony_ci constraint->expr)) { 81162306a36Sopenharmony_ci if (user) 81262306a36Sopenharmony_ci rc = -EPERM; 81362306a36Sopenharmony_ci else 81462306a36Sopenharmony_ci rc = security_validtrans_handle_fail(policy, 81562306a36Sopenharmony_ci oentry, 81662306a36Sopenharmony_ci nentry, 81762306a36Sopenharmony_ci tentry, 81862306a36Sopenharmony_ci tclass); 81962306a36Sopenharmony_ci goto out; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci constraint = constraint->next; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ciout: 82562306a36Sopenharmony_ci rcu_read_unlock(); 82662306a36Sopenharmony_ci return rc; 82762306a36Sopenharmony_ci} 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ciint security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid, 83062306a36Sopenharmony_ci u16 tclass) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci return security_compute_validatetrans(oldsid, newsid, tasksid, 83362306a36Sopenharmony_ci tclass, true); 83462306a36Sopenharmony_ci} 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ciint security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, 83762306a36Sopenharmony_ci u16 orig_tclass) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci return security_compute_validatetrans(oldsid, newsid, tasksid, 84062306a36Sopenharmony_ci orig_tclass, false); 84162306a36Sopenharmony_ci} 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci/* 84462306a36Sopenharmony_ci * security_bounded_transition - check whether the given 84562306a36Sopenharmony_ci * transition is directed to bounded, or not. 84662306a36Sopenharmony_ci * It returns 0, if @newsid is bounded by @oldsid. 84762306a36Sopenharmony_ci * Otherwise, it returns error code. 84862306a36Sopenharmony_ci * 84962306a36Sopenharmony_ci * @oldsid : current security identifier 85062306a36Sopenharmony_ci * @newsid : destinated security identifier 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_ciint security_bounded_transition(u32 old_sid, u32 new_sid) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci struct selinux_policy *policy; 85562306a36Sopenharmony_ci struct policydb *policydb; 85662306a36Sopenharmony_ci struct sidtab *sidtab; 85762306a36Sopenharmony_ci struct sidtab_entry *old_entry, *new_entry; 85862306a36Sopenharmony_ci struct type_datum *type; 85962306a36Sopenharmony_ci u32 index; 86062306a36Sopenharmony_ci int rc; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci if (!selinux_initialized()) 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci rcu_read_lock(); 86662306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 86762306a36Sopenharmony_ci policydb = &policy->policydb; 86862306a36Sopenharmony_ci sidtab = policy->sidtab; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci rc = -EINVAL; 87162306a36Sopenharmony_ci old_entry = sidtab_search_entry(sidtab, old_sid); 87262306a36Sopenharmony_ci if (!old_entry) { 87362306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %u\n", 87462306a36Sopenharmony_ci __func__, old_sid); 87562306a36Sopenharmony_ci goto out; 87662306a36Sopenharmony_ci } 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci rc = -EINVAL; 87962306a36Sopenharmony_ci new_entry = sidtab_search_entry(sidtab, new_sid); 88062306a36Sopenharmony_ci if (!new_entry) { 88162306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %u\n", 88262306a36Sopenharmony_ci __func__, new_sid); 88362306a36Sopenharmony_ci goto out; 88462306a36Sopenharmony_ci } 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci rc = 0; 88762306a36Sopenharmony_ci /* type/domain unchanged */ 88862306a36Sopenharmony_ci if (old_entry->context.type == new_entry->context.type) 88962306a36Sopenharmony_ci goto out; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci index = new_entry->context.type; 89262306a36Sopenharmony_ci while (true) { 89362306a36Sopenharmony_ci type = policydb->type_val_to_struct[index - 1]; 89462306a36Sopenharmony_ci BUG_ON(!type); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* not bounded anymore */ 89762306a36Sopenharmony_ci rc = -EPERM; 89862306a36Sopenharmony_ci if (!type->bounds) 89962306a36Sopenharmony_ci break; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci /* @newsid is bounded by @oldsid */ 90262306a36Sopenharmony_ci rc = 0; 90362306a36Sopenharmony_ci if (type->bounds == old_entry->context.type) 90462306a36Sopenharmony_ci break; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci index = type->bounds; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (rc) { 91062306a36Sopenharmony_ci char *old_name = NULL; 91162306a36Sopenharmony_ci char *new_name = NULL; 91262306a36Sopenharmony_ci u32 length; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci if (!sidtab_entry_to_string(policydb, sidtab, old_entry, 91562306a36Sopenharmony_ci &old_name, &length) && 91662306a36Sopenharmony_ci !sidtab_entry_to_string(policydb, sidtab, new_entry, 91762306a36Sopenharmony_ci &new_name, &length)) { 91862306a36Sopenharmony_ci audit_log(audit_context(), 91962306a36Sopenharmony_ci GFP_ATOMIC, AUDIT_SELINUX_ERR, 92062306a36Sopenharmony_ci "op=security_bounded_transition " 92162306a36Sopenharmony_ci "seresult=denied " 92262306a36Sopenharmony_ci "oldcontext=%s newcontext=%s", 92362306a36Sopenharmony_ci old_name, new_name); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci kfree(new_name); 92662306a36Sopenharmony_ci kfree(old_name); 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ciout: 92962306a36Sopenharmony_ci rcu_read_unlock(); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci return rc; 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic void avd_init(struct selinux_policy *policy, struct av_decision *avd) 93562306a36Sopenharmony_ci{ 93662306a36Sopenharmony_ci avd->allowed = 0; 93762306a36Sopenharmony_ci avd->auditallow = 0; 93862306a36Sopenharmony_ci avd->auditdeny = 0xffffffff; 93962306a36Sopenharmony_ci if (policy) 94062306a36Sopenharmony_ci avd->seqno = policy->latest_granting; 94162306a36Sopenharmony_ci else 94262306a36Sopenharmony_ci avd->seqno = 0; 94362306a36Sopenharmony_ci avd->flags = 0; 94462306a36Sopenharmony_ci} 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_civoid services_compute_xperms_decision(struct extended_perms_decision *xpermd, 94762306a36Sopenharmony_ci struct avtab_node *node) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci unsigned int i; 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 95262306a36Sopenharmony_ci if (xpermd->driver != node->datum.u.xperms->driver) 95362306a36Sopenharmony_ci return; 95462306a36Sopenharmony_ci } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 95562306a36Sopenharmony_ci if (!security_xperm_test(node->datum.u.xperms->perms.p, 95662306a36Sopenharmony_ci xpermd->driver)) 95762306a36Sopenharmony_ci return; 95862306a36Sopenharmony_ci } else { 95962306a36Sopenharmony_ci BUG(); 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci if (node->key.specified == AVTAB_XPERMS_ALLOWED) { 96362306a36Sopenharmony_ci xpermd->used |= XPERMS_ALLOWED; 96462306a36Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 96562306a36Sopenharmony_ci memset(xpermd->allowed->p, 0xff, 96662306a36Sopenharmony_ci sizeof(xpermd->allowed->p)); 96762306a36Sopenharmony_ci } 96862306a36Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 96962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) 97062306a36Sopenharmony_ci xpermd->allowed->p[i] |= 97162306a36Sopenharmony_ci node->datum.u.xperms->perms.p[i]; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { 97462306a36Sopenharmony_ci xpermd->used |= XPERMS_AUDITALLOW; 97562306a36Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 97662306a36Sopenharmony_ci memset(xpermd->auditallow->p, 0xff, 97762306a36Sopenharmony_ci sizeof(xpermd->auditallow->p)); 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 98062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) 98162306a36Sopenharmony_ci xpermd->auditallow->p[i] |= 98262306a36Sopenharmony_ci node->datum.u.xperms->perms.p[i]; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { 98562306a36Sopenharmony_ci xpermd->used |= XPERMS_DONTAUDIT; 98662306a36Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 98762306a36Sopenharmony_ci memset(xpermd->dontaudit->p, 0xff, 98862306a36Sopenharmony_ci sizeof(xpermd->dontaudit->p)); 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 99162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) 99262306a36Sopenharmony_ci xpermd->dontaudit->p[i] |= 99362306a36Sopenharmony_ci node->datum.u.xperms->perms.p[i]; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci } else { 99662306a36Sopenharmony_ci BUG(); 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_civoid security_compute_xperms_decision(u32 ssid, 100162306a36Sopenharmony_ci u32 tsid, 100262306a36Sopenharmony_ci u16 orig_tclass, 100362306a36Sopenharmony_ci u8 driver, 100462306a36Sopenharmony_ci struct extended_perms_decision *xpermd) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci struct selinux_policy *policy; 100762306a36Sopenharmony_ci struct policydb *policydb; 100862306a36Sopenharmony_ci struct sidtab *sidtab; 100962306a36Sopenharmony_ci u16 tclass; 101062306a36Sopenharmony_ci struct context *scontext, *tcontext; 101162306a36Sopenharmony_ci struct avtab_key avkey; 101262306a36Sopenharmony_ci struct avtab_node *node; 101362306a36Sopenharmony_ci struct ebitmap *sattr, *tattr; 101462306a36Sopenharmony_ci struct ebitmap_node *snode, *tnode; 101562306a36Sopenharmony_ci unsigned int i, j; 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci xpermd->driver = driver; 101862306a36Sopenharmony_ci xpermd->used = 0; 101962306a36Sopenharmony_ci memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p)); 102062306a36Sopenharmony_ci memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); 102162306a36Sopenharmony_ci memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci rcu_read_lock(); 102462306a36Sopenharmony_ci if (!selinux_initialized()) 102562306a36Sopenharmony_ci goto allow; 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 102862306a36Sopenharmony_ci policydb = &policy->policydb; 102962306a36Sopenharmony_ci sidtab = policy->sidtab; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci scontext = sidtab_search(sidtab, ssid); 103262306a36Sopenharmony_ci if (!scontext) { 103362306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 103462306a36Sopenharmony_ci __func__, ssid); 103562306a36Sopenharmony_ci goto out; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci tcontext = sidtab_search(sidtab, tsid); 103962306a36Sopenharmony_ci if (!tcontext) { 104062306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 104162306a36Sopenharmony_ci __func__, tsid); 104262306a36Sopenharmony_ci goto out; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci tclass = unmap_class(&policy->map, orig_tclass); 104662306a36Sopenharmony_ci if (unlikely(orig_tclass && !tclass)) { 104762306a36Sopenharmony_ci if (policydb->allow_unknown) 104862306a36Sopenharmony_ci goto allow; 104962306a36Sopenharmony_ci goto out; 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) { 105462306a36Sopenharmony_ci pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass); 105562306a36Sopenharmony_ci goto out; 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci avkey.target_class = tclass; 105962306a36Sopenharmony_ci avkey.specified = AVTAB_XPERMS; 106062306a36Sopenharmony_ci sattr = &policydb->type_attr_map_array[scontext->type - 1]; 106162306a36Sopenharmony_ci tattr = &policydb->type_attr_map_array[tcontext->type - 1]; 106262306a36Sopenharmony_ci ebitmap_for_each_positive_bit(sattr, snode, i) { 106362306a36Sopenharmony_ci ebitmap_for_each_positive_bit(tattr, tnode, j) { 106462306a36Sopenharmony_ci avkey.source_type = i + 1; 106562306a36Sopenharmony_ci avkey.target_type = j + 1; 106662306a36Sopenharmony_ci for (node = avtab_search_node(&policydb->te_avtab, 106762306a36Sopenharmony_ci &avkey); 106862306a36Sopenharmony_ci node; 106962306a36Sopenharmony_ci node = avtab_search_node_next(node, avkey.specified)) 107062306a36Sopenharmony_ci services_compute_xperms_decision(xpermd, node); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci cond_compute_xperms(&policydb->te_cond_avtab, 107362306a36Sopenharmony_ci &avkey, xpermd); 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ciout: 107762306a36Sopenharmony_ci rcu_read_unlock(); 107862306a36Sopenharmony_ci return; 107962306a36Sopenharmony_ciallow: 108062306a36Sopenharmony_ci memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); 108162306a36Sopenharmony_ci goto out; 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci/** 108562306a36Sopenharmony_ci * security_compute_av - Compute access vector decisions. 108662306a36Sopenharmony_ci * @ssid: source security identifier 108762306a36Sopenharmony_ci * @tsid: target security identifier 108862306a36Sopenharmony_ci * @orig_tclass: target security class 108962306a36Sopenharmony_ci * @avd: access vector decisions 109062306a36Sopenharmony_ci * @xperms: extended permissions 109162306a36Sopenharmony_ci * 109262306a36Sopenharmony_ci * Compute a set of access vector decisions based on the 109362306a36Sopenharmony_ci * SID pair (@ssid, @tsid) for the permissions in @tclass. 109462306a36Sopenharmony_ci */ 109562306a36Sopenharmony_civoid security_compute_av(u32 ssid, 109662306a36Sopenharmony_ci u32 tsid, 109762306a36Sopenharmony_ci u16 orig_tclass, 109862306a36Sopenharmony_ci struct av_decision *avd, 109962306a36Sopenharmony_ci struct extended_perms *xperms) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci struct selinux_policy *policy; 110262306a36Sopenharmony_ci struct policydb *policydb; 110362306a36Sopenharmony_ci struct sidtab *sidtab; 110462306a36Sopenharmony_ci u16 tclass; 110562306a36Sopenharmony_ci struct context *scontext = NULL, *tcontext = NULL; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci rcu_read_lock(); 110862306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 110962306a36Sopenharmony_ci avd_init(policy, avd); 111062306a36Sopenharmony_ci xperms->len = 0; 111162306a36Sopenharmony_ci if (!selinux_initialized()) 111262306a36Sopenharmony_ci goto allow; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci policydb = &policy->policydb; 111562306a36Sopenharmony_ci sidtab = policy->sidtab; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci scontext = sidtab_search(sidtab, ssid); 111862306a36Sopenharmony_ci if (!scontext) { 111962306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 112062306a36Sopenharmony_ci __func__, ssid); 112162306a36Sopenharmony_ci goto out; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci /* permissive domain? */ 112562306a36Sopenharmony_ci if (ebitmap_get_bit(&policydb->permissive_map, scontext->type)) 112662306a36Sopenharmony_ci avd->flags |= AVD_FLAGS_PERMISSIVE; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci tcontext = sidtab_search(sidtab, tsid); 112962306a36Sopenharmony_ci if (!tcontext) { 113062306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 113162306a36Sopenharmony_ci __func__, tsid); 113262306a36Sopenharmony_ci goto out; 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci tclass = unmap_class(&policy->map, orig_tclass); 113662306a36Sopenharmony_ci if (unlikely(orig_tclass && !tclass)) { 113762306a36Sopenharmony_ci if (policydb->allow_unknown) 113862306a36Sopenharmony_ci goto allow; 113962306a36Sopenharmony_ci goto out; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci context_struct_compute_av(policydb, scontext, tcontext, tclass, avd, 114262306a36Sopenharmony_ci xperms); 114362306a36Sopenharmony_ci map_decision(&policy->map, orig_tclass, avd, 114462306a36Sopenharmony_ci policydb->allow_unknown); 114562306a36Sopenharmony_ciout: 114662306a36Sopenharmony_ci rcu_read_unlock(); 114762306a36Sopenharmony_ci return; 114862306a36Sopenharmony_ciallow: 114962306a36Sopenharmony_ci avd->allowed = 0xffffffff; 115062306a36Sopenharmony_ci goto out; 115162306a36Sopenharmony_ci} 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_civoid security_compute_av_user(u32 ssid, 115462306a36Sopenharmony_ci u32 tsid, 115562306a36Sopenharmony_ci u16 tclass, 115662306a36Sopenharmony_ci struct av_decision *avd) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci struct selinux_policy *policy; 115962306a36Sopenharmony_ci struct policydb *policydb; 116062306a36Sopenharmony_ci struct sidtab *sidtab; 116162306a36Sopenharmony_ci struct context *scontext = NULL, *tcontext = NULL; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci rcu_read_lock(); 116462306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 116562306a36Sopenharmony_ci avd_init(policy, avd); 116662306a36Sopenharmony_ci if (!selinux_initialized()) 116762306a36Sopenharmony_ci goto allow; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci policydb = &policy->policydb; 117062306a36Sopenharmony_ci sidtab = policy->sidtab; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci scontext = sidtab_search(sidtab, ssid); 117362306a36Sopenharmony_ci if (!scontext) { 117462306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 117562306a36Sopenharmony_ci __func__, ssid); 117662306a36Sopenharmony_ci goto out; 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci /* permissive domain? */ 118062306a36Sopenharmony_ci if (ebitmap_get_bit(&policydb->permissive_map, scontext->type)) 118162306a36Sopenharmony_ci avd->flags |= AVD_FLAGS_PERMISSIVE; 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci tcontext = sidtab_search(sidtab, tsid); 118462306a36Sopenharmony_ci if (!tcontext) { 118562306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 118662306a36Sopenharmony_ci __func__, tsid); 118762306a36Sopenharmony_ci goto out; 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci if (unlikely(!tclass)) { 119162306a36Sopenharmony_ci if (policydb->allow_unknown) 119262306a36Sopenharmony_ci goto allow; 119362306a36Sopenharmony_ci goto out; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci context_struct_compute_av(policydb, scontext, tcontext, tclass, avd, 119762306a36Sopenharmony_ci NULL); 119862306a36Sopenharmony_ci out: 119962306a36Sopenharmony_ci rcu_read_unlock(); 120062306a36Sopenharmony_ci return; 120162306a36Sopenharmony_ciallow: 120262306a36Sopenharmony_ci avd->allowed = 0xffffffff; 120362306a36Sopenharmony_ci goto out; 120462306a36Sopenharmony_ci} 120562306a36Sopenharmony_ci 120662306a36Sopenharmony_ci/* 120762306a36Sopenharmony_ci * Write the security context string representation of 120862306a36Sopenharmony_ci * the context structure `context' into a dynamically 120962306a36Sopenharmony_ci * allocated string of the correct size. Set `*scontext' 121062306a36Sopenharmony_ci * to point to this string and set `*scontext_len' to 121162306a36Sopenharmony_ci * the length of the string. 121262306a36Sopenharmony_ci */ 121362306a36Sopenharmony_cistatic int context_struct_to_string(struct policydb *p, 121462306a36Sopenharmony_ci struct context *context, 121562306a36Sopenharmony_ci char **scontext, u32 *scontext_len) 121662306a36Sopenharmony_ci{ 121762306a36Sopenharmony_ci char *scontextp; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci if (scontext) 122062306a36Sopenharmony_ci *scontext = NULL; 122162306a36Sopenharmony_ci *scontext_len = 0; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (context->len) { 122462306a36Sopenharmony_ci *scontext_len = context->len; 122562306a36Sopenharmony_ci if (scontext) { 122662306a36Sopenharmony_ci *scontext = kstrdup(context->str, GFP_ATOMIC); 122762306a36Sopenharmony_ci if (!(*scontext)) 122862306a36Sopenharmony_ci return -ENOMEM; 122962306a36Sopenharmony_ci } 123062306a36Sopenharmony_ci return 0; 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* Compute the size of the context. */ 123462306a36Sopenharmony_ci *scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1; 123562306a36Sopenharmony_ci *scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1; 123662306a36Sopenharmony_ci *scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1; 123762306a36Sopenharmony_ci *scontext_len += mls_compute_context_len(p, context); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci if (!scontext) 124062306a36Sopenharmony_ci return 0; 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci /* Allocate space for the context; caller must free this space. */ 124362306a36Sopenharmony_ci scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 124462306a36Sopenharmony_ci if (!scontextp) 124562306a36Sopenharmony_ci return -ENOMEM; 124662306a36Sopenharmony_ci *scontext = scontextp; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci /* 124962306a36Sopenharmony_ci * Copy the user name, role name and type name into the context. 125062306a36Sopenharmony_ci */ 125162306a36Sopenharmony_ci scontextp += sprintf(scontextp, "%s:%s:%s", 125262306a36Sopenharmony_ci sym_name(p, SYM_USERS, context->user - 1), 125362306a36Sopenharmony_ci sym_name(p, SYM_ROLES, context->role - 1), 125462306a36Sopenharmony_ci sym_name(p, SYM_TYPES, context->type - 1)); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci mls_sid_to_context(p, context, &scontextp); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci *scontextp = 0; 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_ci return 0; 126162306a36Sopenharmony_ci} 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_cistatic int sidtab_entry_to_string(struct policydb *p, 126462306a36Sopenharmony_ci struct sidtab *sidtab, 126562306a36Sopenharmony_ci struct sidtab_entry *entry, 126662306a36Sopenharmony_ci char **scontext, u32 *scontext_len) 126762306a36Sopenharmony_ci{ 126862306a36Sopenharmony_ci int rc = sidtab_sid2str_get(sidtab, entry, scontext, scontext_len); 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci if (rc != -ENOENT) 127162306a36Sopenharmony_ci return rc; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci rc = context_struct_to_string(p, &entry->context, scontext, 127462306a36Sopenharmony_ci scontext_len); 127562306a36Sopenharmony_ci if (!rc && scontext) 127662306a36Sopenharmony_ci sidtab_sid2str_put(sidtab, entry, *scontext, *scontext_len); 127762306a36Sopenharmony_ci return rc; 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci#include "initial_sid_to_string.h" 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ciint security_sidtab_hash_stats(char *page) 128362306a36Sopenharmony_ci{ 128462306a36Sopenharmony_ci struct selinux_policy *policy; 128562306a36Sopenharmony_ci int rc; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci if (!selinux_initialized()) { 128862306a36Sopenharmony_ci pr_err("SELinux: %s: called before initial load_policy\n", 128962306a36Sopenharmony_ci __func__); 129062306a36Sopenharmony_ci return -EINVAL; 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci rcu_read_lock(); 129462306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 129562306a36Sopenharmony_ci rc = sidtab_hash_stats(policy->sidtab, page); 129662306a36Sopenharmony_ci rcu_read_unlock(); 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci return rc; 129962306a36Sopenharmony_ci} 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ciconst char *security_get_initial_sid_context(u32 sid) 130262306a36Sopenharmony_ci{ 130362306a36Sopenharmony_ci if (unlikely(sid > SECINITSID_NUM)) 130462306a36Sopenharmony_ci return NULL; 130562306a36Sopenharmony_ci return initial_sid_to_string[sid]; 130662306a36Sopenharmony_ci} 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_cistatic int security_sid_to_context_core(u32 sid, char **scontext, 130962306a36Sopenharmony_ci u32 *scontext_len, int force, 131062306a36Sopenharmony_ci int only_invalid) 131162306a36Sopenharmony_ci{ 131262306a36Sopenharmony_ci struct selinux_policy *policy; 131362306a36Sopenharmony_ci struct policydb *policydb; 131462306a36Sopenharmony_ci struct sidtab *sidtab; 131562306a36Sopenharmony_ci struct sidtab_entry *entry; 131662306a36Sopenharmony_ci int rc = 0; 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci if (scontext) 131962306a36Sopenharmony_ci *scontext = NULL; 132062306a36Sopenharmony_ci *scontext_len = 0; 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_ci if (!selinux_initialized()) { 132362306a36Sopenharmony_ci if (sid <= SECINITSID_NUM) { 132462306a36Sopenharmony_ci char *scontextp; 132562306a36Sopenharmony_ci const char *s = initial_sid_to_string[sid]; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci if (!s) 132862306a36Sopenharmony_ci return -EINVAL; 132962306a36Sopenharmony_ci *scontext_len = strlen(s) + 1; 133062306a36Sopenharmony_ci if (!scontext) 133162306a36Sopenharmony_ci return 0; 133262306a36Sopenharmony_ci scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC); 133362306a36Sopenharmony_ci if (!scontextp) 133462306a36Sopenharmony_ci return -ENOMEM; 133562306a36Sopenharmony_ci *scontext = scontextp; 133662306a36Sopenharmony_ci return 0; 133762306a36Sopenharmony_ci } 133862306a36Sopenharmony_ci pr_err("SELinux: %s: called before initial " 133962306a36Sopenharmony_ci "load_policy on unknown SID %d\n", __func__, sid); 134062306a36Sopenharmony_ci return -EINVAL; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci rcu_read_lock(); 134362306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 134462306a36Sopenharmony_ci policydb = &policy->policydb; 134562306a36Sopenharmony_ci sidtab = policy->sidtab; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci if (force) 134862306a36Sopenharmony_ci entry = sidtab_search_entry_force(sidtab, sid); 134962306a36Sopenharmony_ci else 135062306a36Sopenharmony_ci entry = sidtab_search_entry(sidtab, sid); 135162306a36Sopenharmony_ci if (!entry) { 135262306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 135362306a36Sopenharmony_ci __func__, sid); 135462306a36Sopenharmony_ci rc = -EINVAL; 135562306a36Sopenharmony_ci goto out_unlock; 135662306a36Sopenharmony_ci } 135762306a36Sopenharmony_ci if (only_invalid && !entry->context.len) 135862306a36Sopenharmony_ci goto out_unlock; 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci rc = sidtab_entry_to_string(policydb, sidtab, entry, scontext, 136162306a36Sopenharmony_ci scontext_len); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ciout_unlock: 136462306a36Sopenharmony_ci rcu_read_unlock(); 136562306a36Sopenharmony_ci return rc; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci} 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci/** 137062306a36Sopenharmony_ci * security_sid_to_context - Obtain a context for a given SID. 137162306a36Sopenharmony_ci * @sid: security identifier, SID 137262306a36Sopenharmony_ci * @scontext: security context 137362306a36Sopenharmony_ci * @scontext_len: length in bytes 137462306a36Sopenharmony_ci * 137562306a36Sopenharmony_ci * Write the string representation of the context associated with @sid 137662306a36Sopenharmony_ci * into a dynamically allocated string of the correct size. Set @scontext 137762306a36Sopenharmony_ci * to point to this string and set @scontext_len to the length of the string. 137862306a36Sopenharmony_ci */ 137962306a36Sopenharmony_ciint security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) 138062306a36Sopenharmony_ci{ 138162306a36Sopenharmony_ci return security_sid_to_context_core(sid, scontext, 138262306a36Sopenharmony_ci scontext_len, 0, 0); 138362306a36Sopenharmony_ci} 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ciint security_sid_to_context_force(u32 sid, 138662306a36Sopenharmony_ci char **scontext, u32 *scontext_len) 138762306a36Sopenharmony_ci{ 138862306a36Sopenharmony_ci return security_sid_to_context_core(sid, scontext, 138962306a36Sopenharmony_ci scontext_len, 1, 0); 139062306a36Sopenharmony_ci} 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci/** 139362306a36Sopenharmony_ci * security_sid_to_context_inval - Obtain a context for a given SID if it 139462306a36Sopenharmony_ci * is invalid. 139562306a36Sopenharmony_ci * @sid: security identifier, SID 139662306a36Sopenharmony_ci * @scontext: security context 139762306a36Sopenharmony_ci * @scontext_len: length in bytes 139862306a36Sopenharmony_ci * 139962306a36Sopenharmony_ci * Write the string representation of the context associated with @sid 140062306a36Sopenharmony_ci * into a dynamically allocated string of the correct size, but only if the 140162306a36Sopenharmony_ci * context is invalid in the current policy. Set @scontext to point to 140262306a36Sopenharmony_ci * this string (or NULL if the context is valid) and set @scontext_len to 140362306a36Sopenharmony_ci * the length of the string (or 0 if the context is valid). 140462306a36Sopenharmony_ci */ 140562306a36Sopenharmony_ciint security_sid_to_context_inval(u32 sid, 140662306a36Sopenharmony_ci char **scontext, u32 *scontext_len) 140762306a36Sopenharmony_ci{ 140862306a36Sopenharmony_ci return security_sid_to_context_core(sid, scontext, 140962306a36Sopenharmony_ci scontext_len, 1, 1); 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci/* 141362306a36Sopenharmony_ci * Caveat: Mutates scontext. 141462306a36Sopenharmony_ci */ 141562306a36Sopenharmony_cistatic int string_to_context_struct(struct policydb *pol, 141662306a36Sopenharmony_ci struct sidtab *sidtabp, 141762306a36Sopenharmony_ci char *scontext, 141862306a36Sopenharmony_ci struct context *ctx, 141962306a36Sopenharmony_ci u32 def_sid) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci struct role_datum *role; 142262306a36Sopenharmony_ci struct type_datum *typdatum; 142362306a36Sopenharmony_ci struct user_datum *usrdatum; 142462306a36Sopenharmony_ci char *scontextp, *p, oldc; 142562306a36Sopenharmony_ci int rc = 0; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci context_init(ctx); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci /* Parse the security context. */ 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci rc = -EINVAL; 143262306a36Sopenharmony_ci scontextp = scontext; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci /* Extract the user. */ 143562306a36Sopenharmony_ci p = scontextp; 143662306a36Sopenharmony_ci while (*p && *p != ':') 143762306a36Sopenharmony_ci p++; 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (*p == 0) 144062306a36Sopenharmony_ci goto out; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci *p++ = 0; 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci usrdatum = symtab_search(&pol->p_users, scontextp); 144562306a36Sopenharmony_ci if (!usrdatum) 144662306a36Sopenharmony_ci goto out; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci ctx->user = usrdatum->value; 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci /* Extract role. */ 145162306a36Sopenharmony_ci scontextp = p; 145262306a36Sopenharmony_ci while (*p && *p != ':') 145362306a36Sopenharmony_ci p++; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci if (*p == 0) 145662306a36Sopenharmony_ci goto out; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci *p++ = 0; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci role = symtab_search(&pol->p_roles, scontextp); 146162306a36Sopenharmony_ci if (!role) 146262306a36Sopenharmony_ci goto out; 146362306a36Sopenharmony_ci ctx->role = role->value; 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci /* Extract type. */ 146662306a36Sopenharmony_ci scontextp = p; 146762306a36Sopenharmony_ci while (*p && *p != ':') 146862306a36Sopenharmony_ci p++; 146962306a36Sopenharmony_ci oldc = *p; 147062306a36Sopenharmony_ci *p++ = 0; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci typdatum = symtab_search(&pol->p_types, scontextp); 147362306a36Sopenharmony_ci if (!typdatum || typdatum->attribute) 147462306a36Sopenharmony_ci goto out; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci ctx->type = typdatum->value; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid); 147962306a36Sopenharmony_ci if (rc) 148062306a36Sopenharmony_ci goto out; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci /* Check the validity of the new context. */ 148362306a36Sopenharmony_ci rc = -EINVAL; 148462306a36Sopenharmony_ci if (!policydb_context_isvalid(pol, ctx)) 148562306a36Sopenharmony_ci goto out; 148662306a36Sopenharmony_ci rc = 0; 148762306a36Sopenharmony_ciout: 148862306a36Sopenharmony_ci if (rc) 148962306a36Sopenharmony_ci context_destroy(ctx); 149062306a36Sopenharmony_ci return rc; 149162306a36Sopenharmony_ci} 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_cistatic int security_context_to_sid_core(const char *scontext, u32 scontext_len, 149462306a36Sopenharmony_ci u32 *sid, u32 def_sid, gfp_t gfp_flags, 149562306a36Sopenharmony_ci int force) 149662306a36Sopenharmony_ci{ 149762306a36Sopenharmony_ci struct selinux_policy *policy; 149862306a36Sopenharmony_ci struct policydb *policydb; 149962306a36Sopenharmony_ci struct sidtab *sidtab; 150062306a36Sopenharmony_ci char *scontext2, *str = NULL; 150162306a36Sopenharmony_ci struct context context; 150262306a36Sopenharmony_ci int rc = 0; 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ci /* An empty security context is never valid. */ 150562306a36Sopenharmony_ci if (!scontext_len) 150662306a36Sopenharmony_ci return -EINVAL; 150762306a36Sopenharmony_ci 150862306a36Sopenharmony_ci /* Copy the string to allow changes and ensure a NUL terminator */ 150962306a36Sopenharmony_ci scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags); 151062306a36Sopenharmony_ci if (!scontext2) 151162306a36Sopenharmony_ci return -ENOMEM; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci if (!selinux_initialized()) { 151462306a36Sopenharmony_ci u32 i; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci for (i = 1; i < SECINITSID_NUM; i++) { 151762306a36Sopenharmony_ci const char *s = initial_sid_to_string[i]; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci if (s && !strcmp(s, scontext2)) { 152062306a36Sopenharmony_ci *sid = i; 152162306a36Sopenharmony_ci goto out; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci } 152462306a36Sopenharmony_ci *sid = SECINITSID_KERNEL; 152562306a36Sopenharmony_ci goto out; 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci *sid = SECSID_NULL; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci if (force) { 153062306a36Sopenharmony_ci /* Save another copy for storing in uninterpreted form */ 153162306a36Sopenharmony_ci rc = -ENOMEM; 153262306a36Sopenharmony_ci str = kstrdup(scontext2, gfp_flags); 153362306a36Sopenharmony_ci if (!str) 153462306a36Sopenharmony_ci goto out; 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ciretry: 153762306a36Sopenharmony_ci rcu_read_lock(); 153862306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 153962306a36Sopenharmony_ci policydb = &policy->policydb; 154062306a36Sopenharmony_ci sidtab = policy->sidtab; 154162306a36Sopenharmony_ci rc = string_to_context_struct(policydb, sidtab, scontext2, 154262306a36Sopenharmony_ci &context, def_sid); 154362306a36Sopenharmony_ci if (rc == -EINVAL && force) { 154462306a36Sopenharmony_ci context.str = str; 154562306a36Sopenharmony_ci context.len = strlen(str) + 1; 154662306a36Sopenharmony_ci str = NULL; 154762306a36Sopenharmony_ci } else if (rc) 154862306a36Sopenharmony_ci goto out_unlock; 154962306a36Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &context, sid); 155062306a36Sopenharmony_ci if (rc == -ESTALE) { 155162306a36Sopenharmony_ci rcu_read_unlock(); 155262306a36Sopenharmony_ci if (context.str) { 155362306a36Sopenharmony_ci str = context.str; 155462306a36Sopenharmony_ci context.str = NULL; 155562306a36Sopenharmony_ci } 155662306a36Sopenharmony_ci context_destroy(&context); 155762306a36Sopenharmony_ci goto retry; 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci context_destroy(&context); 156062306a36Sopenharmony_ciout_unlock: 156162306a36Sopenharmony_ci rcu_read_unlock(); 156262306a36Sopenharmony_ciout: 156362306a36Sopenharmony_ci kfree(scontext2); 156462306a36Sopenharmony_ci kfree(str); 156562306a36Sopenharmony_ci return rc; 156662306a36Sopenharmony_ci} 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci/** 156962306a36Sopenharmony_ci * security_context_to_sid - Obtain a SID for a given security context. 157062306a36Sopenharmony_ci * @scontext: security context 157162306a36Sopenharmony_ci * @scontext_len: length in bytes 157262306a36Sopenharmony_ci * @sid: security identifier, SID 157362306a36Sopenharmony_ci * @gfp: context for the allocation 157462306a36Sopenharmony_ci * 157562306a36Sopenharmony_ci * Obtains a SID associated with the security context that 157662306a36Sopenharmony_ci * has the string representation specified by @scontext. 157762306a36Sopenharmony_ci * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 157862306a36Sopenharmony_ci * memory is available, or 0 on success. 157962306a36Sopenharmony_ci */ 158062306a36Sopenharmony_ciint security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid, 158162306a36Sopenharmony_ci gfp_t gfp) 158262306a36Sopenharmony_ci{ 158362306a36Sopenharmony_ci return security_context_to_sid_core(scontext, scontext_len, 158462306a36Sopenharmony_ci sid, SECSID_NULL, gfp, 0); 158562306a36Sopenharmony_ci} 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ciint security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp) 158862306a36Sopenharmony_ci{ 158962306a36Sopenharmony_ci return security_context_to_sid(scontext, strlen(scontext), 159062306a36Sopenharmony_ci sid, gfp); 159162306a36Sopenharmony_ci} 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci/** 159462306a36Sopenharmony_ci * security_context_to_sid_default - Obtain a SID for a given security context, 159562306a36Sopenharmony_ci * falling back to specified default if needed. 159662306a36Sopenharmony_ci * 159762306a36Sopenharmony_ci * @scontext: security context 159862306a36Sopenharmony_ci * @scontext_len: length in bytes 159962306a36Sopenharmony_ci * @sid: security identifier, SID 160062306a36Sopenharmony_ci * @def_sid: default SID to assign on error 160162306a36Sopenharmony_ci * @gfp_flags: the allocator get-free-page (GFP) flags 160262306a36Sopenharmony_ci * 160362306a36Sopenharmony_ci * Obtains a SID associated with the security context that 160462306a36Sopenharmony_ci * has the string representation specified by @scontext. 160562306a36Sopenharmony_ci * The default SID is passed to the MLS layer to be used to allow 160662306a36Sopenharmony_ci * kernel labeling of the MLS field if the MLS field is not present 160762306a36Sopenharmony_ci * (for upgrading to MLS without full relabel). 160862306a36Sopenharmony_ci * Implicitly forces adding of the context even if it cannot be mapped yet. 160962306a36Sopenharmony_ci * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 161062306a36Sopenharmony_ci * memory is available, or 0 on success. 161162306a36Sopenharmony_ci */ 161262306a36Sopenharmony_ciint security_context_to_sid_default(const char *scontext, u32 scontext_len, 161362306a36Sopenharmony_ci u32 *sid, u32 def_sid, gfp_t gfp_flags) 161462306a36Sopenharmony_ci{ 161562306a36Sopenharmony_ci return security_context_to_sid_core(scontext, scontext_len, 161662306a36Sopenharmony_ci sid, def_sid, gfp_flags, 1); 161762306a36Sopenharmony_ci} 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ciint security_context_to_sid_force(const char *scontext, u32 scontext_len, 162062306a36Sopenharmony_ci u32 *sid) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci return security_context_to_sid_core(scontext, scontext_len, 162362306a36Sopenharmony_ci sid, SECSID_NULL, GFP_KERNEL, 1); 162462306a36Sopenharmony_ci} 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_cistatic int compute_sid_handle_invalid_context( 162762306a36Sopenharmony_ci struct selinux_policy *policy, 162862306a36Sopenharmony_ci struct sidtab_entry *sentry, 162962306a36Sopenharmony_ci struct sidtab_entry *tentry, 163062306a36Sopenharmony_ci u16 tclass, 163162306a36Sopenharmony_ci struct context *newcontext) 163262306a36Sopenharmony_ci{ 163362306a36Sopenharmony_ci struct policydb *policydb = &policy->policydb; 163462306a36Sopenharmony_ci struct sidtab *sidtab = policy->sidtab; 163562306a36Sopenharmony_ci char *s = NULL, *t = NULL, *n = NULL; 163662306a36Sopenharmony_ci u32 slen, tlen, nlen; 163762306a36Sopenharmony_ci struct audit_buffer *ab; 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci if (sidtab_entry_to_string(policydb, sidtab, sentry, &s, &slen)) 164062306a36Sopenharmony_ci goto out; 164162306a36Sopenharmony_ci if (sidtab_entry_to_string(policydb, sidtab, tentry, &t, &tlen)) 164262306a36Sopenharmony_ci goto out; 164362306a36Sopenharmony_ci if (context_struct_to_string(policydb, newcontext, &n, &nlen)) 164462306a36Sopenharmony_ci goto out; 164562306a36Sopenharmony_ci ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR); 164662306a36Sopenharmony_ci if (!ab) 164762306a36Sopenharmony_ci goto out; 164862306a36Sopenharmony_ci audit_log_format(ab, 164962306a36Sopenharmony_ci "op=security_compute_sid invalid_context="); 165062306a36Sopenharmony_ci /* no need to record the NUL with untrusted strings */ 165162306a36Sopenharmony_ci audit_log_n_untrustedstring(ab, n, nlen - 1); 165262306a36Sopenharmony_ci audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s", 165362306a36Sopenharmony_ci s, t, sym_name(policydb, SYM_CLASSES, tclass-1)); 165462306a36Sopenharmony_ci audit_log_end(ab); 165562306a36Sopenharmony_ciout: 165662306a36Sopenharmony_ci kfree(s); 165762306a36Sopenharmony_ci kfree(t); 165862306a36Sopenharmony_ci kfree(n); 165962306a36Sopenharmony_ci if (!enforcing_enabled()) 166062306a36Sopenharmony_ci return 0; 166162306a36Sopenharmony_ci return -EACCES; 166262306a36Sopenharmony_ci} 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_cistatic void filename_compute_type(struct policydb *policydb, 166562306a36Sopenharmony_ci struct context *newcontext, 166662306a36Sopenharmony_ci u32 stype, u32 ttype, u16 tclass, 166762306a36Sopenharmony_ci const char *objname) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci struct filename_trans_key ft; 167062306a36Sopenharmony_ci struct filename_trans_datum *datum; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci /* 167362306a36Sopenharmony_ci * Most filename trans rules are going to live in specific directories 167462306a36Sopenharmony_ci * like /dev or /var/run. This bitmap will quickly skip rule searches 167562306a36Sopenharmony_ci * if the ttype does not contain any rules. 167662306a36Sopenharmony_ci */ 167762306a36Sopenharmony_ci if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype)) 167862306a36Sopenharmony_ci return; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci ft.ttype = ttype; 168162306a36Sopenharmony_ci ft.tclass = tclass; 168262306a36Sopenharmony_ci ft.name = objname; 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci datum = policydb_filenametr_search(policydb, &ft); 168562306a36Sopenharmony_ci while (datum) { 168662306a36Sopenharmony_ci if (ebitmap_get_bit(&datum->stypes, stype - 1)) { 168762306a36Sopenharmony_ci newcontext->type = datum->otype; 168862306a36Sopenharmony_ci return; 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci datum = datum->next; 169162306a36Sopenharmony_ci } 169262306a36Sopenharmony_ci} 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_cistatic int security_compute_sid(u32 ssid, 169562306a36Sopenharmony_ci u32 tsid, 169662306a36Sopenharmony_ci u16 orig_tclass, 169762306a36Sopenharmony_ci u16 specified, 169862306a36Sopenharmony_ci const char *objname, 169962306a36Sopenharmony_ci u32 *out_sid, 170062306a36Sopenharmony_ci bool kern) 170162306a36Sopenharmony_ci{ 170262306a36Sopenharmony_ci struct selinux_policy *policy; 170362306a36Sopenharmony_ci struct policydb *policydb; 170462306a36Sopenharmony_ci struct sidtab *sidtab; 170562306a36Sopenharmony_ci struct class_datum *cladatum; 170662306a36Sopenharmony_ci struct context *scontext, *tcontext, newcontext; 170762306a36Sopenharmony_ci struct sidtab_entry *sentry, *tentry; 170862306a36Sopenharmony_ci struct avtab_key avkey; 170962306a36Sopenharmony_ci struct avtab_node *avnode, *node; 171062306a36Sopenharmony_ci u16 tclass; 171162306a36Sopenharmony_ci int rc = 0; 171262306a36Sopenharmony_ci bool sock; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci if (!selinux_initialized()) { 171562306a36Sopenharmony_ci switch (orig_tclass) { 171662306a36Sopenharmony_ci case SECCLASS_PROCESS: /* kernel value */ 171762306a36Sopenharmony_ci *out_sid = ssid; 171862306a36Sopenharmony_ci break; 171962306a36Sopenharmony_ci default: 172062306a36Sopenharmony_ci *out_sid = tsid; 172162306a36Sopenharmony_ci break; 172262306a36Sopenharmony_ci } 172362306a36Sopenharmony_ci goto out; 172462306a36Sopenharmony_ci } 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ciretry: 172762306a36Sopenharmony_ci cladatum = NULL; 172862306a36Sopenharmony_ci context_init(&newcontext); 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci rcu_read_lock(); 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci if (kern) { 173562306a36Sopenharmony_ci tclass = unmap_class(&policy->map, orig_tclass); 173662306a36Sopenharmony_ci sock = security_is_socket_class(orig_tclass); 173762306a36Sopenharmony_ci } else { 173862306a36Sopenharmony_ci tclass = orig_tclass; 173962306a36Sopenharmony_ci sock = security_is_socket_class(map_class(&policy->map, 174062306a36Sopenharmony_ci tclass)); 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci policydb = &policy->policydb; 174462306a36Sopenharmony_ci sidtab = policy->sidtab; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci sentry = sidtab_search_entry(sidtab, ssid); 174762306a36Sopenharmony_ci if (!sentry) { 174862306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 174962306a36Sopenharmony_ci __func__, ssid); 175062306a36Sopenharmony_ci rc = -EINVAL; 175162306a36Sopenharmony_ci goto out_unlock; 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci tentry = sidtab_search_entry(sidtab, tsid); 175462306a36Sopenharmony_ci if (!tentry) { 175562306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 175662306a36Sopenharmony_ci __func__, tsid); 175762306a36Sopenharmony_ci rc = -EINVAL; 175862306a36Sopenharmony_ci goto out_unlock; 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci scontext = &sentry->context; 176262306a36Sopenharmony_ci tcontext = &tentry->context; 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci if (tclass && tclass <= policydb->p_classes.nprim) 176562306a36Sopenharmony_ci cladatum = policydb->class_val_to_struct[tclass - 1]; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci /* Set the user identity. */ 176862306a36Sopenharmony_ci switch (specified) { 176962306a36Sopenharmony_ci case AVTAB_TRANSITION: 177062306a36Sopenharmony_ci case AVTAB_CHANGE: 177162306a36Sopenharmony_ci if (cladatum && cladatum->default_user == DEFAULT_TARGET) { 177262306a36Sopenharmony_ci newcontext.user = tcontext->user; 177362306a36Sopenharmony_ci } else { 177462306a36Sopenharmony_ci /* notice this gets both DEFAULT_SOURCE and unset */ 177562306a36Sopenharmony_ci /* Use the process user identity. */ 177662306a36Sopenharmony_ci newcontext.user = scontext->user; 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci break; 177962306a36Sopenharmony_ci case AVTAB_MEMBER: 178062306a36Sopenharmony_ci /* Use the related object owner. */ 178162306a36Sopenharmony_ci newcontext.user = tcontext->user; 178262306a36Sopenharmony_ci break; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci /* Set the role to default values. */ 178662306a36Sopenharmony_ci if (cladatum && cladatum->default_role == DEFAULT_SOURCE) { 178762306a36Sopenharmony_ci newcontext.role = scontext->role; 178862306a36Sopenharmony_ci } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { 178962306a36Sopenharmony_ci newcontext.role = tcontext->role; 179062306a36Sopenharmony_ci } else { 179162306a36Sopenharmony_ci if ((tclass == policydb->process_class) || sock) 179262306a36Sopenharmony_ci newcontext.role = scontext->role; 179362306a36Sopenharmony_ci else 179462306a36Sopenharmony_ci newcontext.role = OBJECT_R_VAL; 179562306a36Sopenharmony_ci } 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci /* Set the type to default values. */ 179862306a36Sopenharmony_ci if (cladatum && cladatum->default_type == DEFAULT_SOURCE) { 179962306a36Sopenharmony_ci newcontext.type = scontext->type; 180062306a36Sopenharmony_ci } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) { 180162306a36Sopenharmony_ci newcontext.type = tcontext->type; 180262306a36Sopenharmony_ci } else { 180362306a36Sopenharmony_ci if ((tclass == policydb->process_class) || sock) { 180462306a36Sopenharmony_ci /* Use the type of process. */ 180562306a36Sopenharmony_ci newcontext.type = scontext->type; 180662306a36Sopenharmony_ci } else { 180762306a36Sopenharmony_ci /* Use the type of the related object. */ 180862306a36Sopenharmony_ci newcontext.type = tcontext->type; 180962306a36Sopenharmony_ci } 181062306a36Sopenharmony_ci } 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci /* Look for a type transition/member/change rule. */ 181362306a36Sopenharmony_ci avkey.source_type = scontext->type; 181462306a36Sopenharmony_ci avkey.target_type = tcontext->type; 181562306a36Sopenharmony_ci avkey.target_class = tclass; 181662306a36Sopenharmony_ci avkey.specified = specified; 181762306a36Sopenharmony_ci avnode = avtab_search_node(&policydb->te_avtab, &avkey); 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci /* If no permanent rule, also check for enabled conditional rules */ 182062306a36Sopenharmony_ci if (!avnode) { 182162306a36Sopenharmony_ci node = avtab_search_node(&policydb->te_cond_avtab, &avkey); 182262306a36Sopenharmony_ci for (; node; node = avtab_search_node_next(node, specified)) { 182362306a36Sopenharmony_ci if (node->key.specified & AVTAB_ENABLED) { 182462306a36Sopenharmony_ci avnode = node; 182562306a36Sopenharmony_ci break; 182662306a36Sopenharmony_ci } 182762306a36Sopenharmony_ci } 182862306a36Sopenharmony_ci } 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci if (avnode) { 183162306a36Sopenharmony_ci /* Use the type from the type transition/member/change rule. */ 183262306a36Sopenharmony_ci newcontext.type = avnode->datum.u.data; 183362306a36Sopenharmony_ci } 183462306a36Sopenharmony_ci 183562306a36Sopenharmony_ci /* if we have a objname this is a file trans check so check those rules */ 183662306a36Sopenharmony_ci if (objname) 183762306a36Sopenharmony_ci filename_compute_type(policydb, &newcontext, scontext->type, 183862306a36Sopenharmony_ci tcontext->type, tclass, objname); 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci /* Check for class-specific changes. */ 184162306a36Sopenharmony_ci if (specified & AVTAB_TRANSITION) { 184262306a36Sopenharmony_ci /* Look for a role transition rule. */ 184362306a36Sopenharmony_ci struct role_trans_datum *rtd; 184462306a36Sopenharmony_ci struct role_trans_key rtk = { 184562306a36Sopenharmony_ci .role = scontext->role, 184662306a36Sopenharmony_ci .type = tcontext->type, 184762306a36Sopenharmony_ci .tclass = tclass, 184862306a36Sopenharmony_ci }; 184962306a36Sopenharmony_ci 185062306a36Sopenharmony_ci rtd = policydb_roletr_search(policydb, &rtk); 185162306a36Sopenharmony_ci if (rtd) 185262306a36Sopenharmony_ci newcontext.role = rtd->new_role; 185362306a36Sopenharmony_ci } 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci /* Set the MLS attributes. 185662306a36Sopenharmony_ci This is done last because it may allocate memory. */ 185762306a36Sopenharmony_ci rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified, 185862306a36Sopenharmony_ci &newcontext, sock); 185962306a36Sopenharmony_ci if (rc) 186062306a36Sopenharmony_ci goto out_unlock; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci /* Check the validity of the context. */ 186362306a36Sopenharmony_ci if (!policydb_context_isvalid(policydb, &newcontext)) { 186462306a36Sopenharmony_ci rc = compute_sid_handle_invalid_context(policy, sentry, 186562306a36Sopenharmony_ci tentry, tclass, 186662306a36Sopenharmony_ci &newcontext); 186762306a36Sopenharmony_ci if (rc) 186862306a36Sopenharmony_ci goto out_unlock; 186962306a36Sopenharmony_ci } 187062306a36Sopenharmony_ci /* Obtain the sid for the context. */ 187162306a36Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid); 187262306a36Sopenharmony_ci if (rc == -ESTALE) { 187362306a36Sopenharmony_ci rcu_read_unlock(); 187462306a36Sopenharmony_ci context_destroy(&newcontext); 187562306a36Sopenharmony_ci goto retry; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ciout_unlock: 187862306a36Sopenharmony_ci rcu_read_unlock(); 187962306a36Sopenharmony_ci context_destroy(&newcontext); 188062306a36Sopenharmony_ciout: 188162306a36Sopenharmony_ci return rc; 188262306a36Sopenharmony_ci} 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci/** 188562306a36Sopenharmony_ci * security_transition_sid - Compute the SID for a new subject/object. 188662306a36Sopenharmony_ci * @ssid: source security identifier 188762306a36Sopenharmony_ci * @tsid: target security identifier 188862306a36Sopenharmony_ci * @tclass: target security class 188962306a36Sopenharmony_ci * @qstr: object name 189062306a36Sopenharmony_ci * @out_sid: security identifier for new subject/object 189162306a36Sopenharmony_ci * 189262306a36Sopenharmony_ci * Compute a SID to use for labeling a new subject or object in the 189362306a36Sopenharmony_ci * class @tclass based on a SID pair (@ssid, @tsid). 189462306a36Sopenharmony_ci * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 189562306a36Sopenharmony_ci * if insufficient memory is available, or %0 if the new SID was 189662306a36Sopenharmony_ci * computed successfully. 189762306a36Sopenharmony_ci */ 189862306a36Sopenharmony_ciint security_transition_sid(u32 ssid, u32 tsid, u16 tclass, 189962306a36Sopenharmony_ci const struct qstr *qstr, u32 *out_sid) 190062306a36Sopenharmony_ci{ 190162306a36Sopenharmony_ci return security_compute_sid(ssid, tsid, tclass, 190262306a36Sopenharmony_ci AVTAB_TRANSITION, 190362306a36Sopenharmony_ci qstr ? qstr->name : NULL, out_sid, true); 190462306a36Sopenharmony_ci} 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ciint security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, 190762306a36Sopenharmony_ci const char *objname, u32 *out_sid) 190862306a36Sopenharmony_ci{ 190962306a36Sopenharmony_ci return security_compute_sid(ssid, tsid, tclass, 191062306a36Sopenharmony_ci AVTAB_TRANSITION, 191162306a36Sopenharmony_ci objname, out_sid, false); 191262306a36Sopenharmony_ci} 191362306a36Sopenharmony_ci 191462306a36Sopenharmony_ci/** 191562306a36Sopenharmony_ci * security_member_sid - Compute the SID for member selection. 191662306a36Sopenharmony_ci * @ssid: source security identifier 191762306a36Sopenharmony_ci * @tsid: target security identifier 191862306a36Sopenharmony_ci * @tclass: target security class 191962306a36Sopenharmony_ci * @out_sid: security identifier for selected member 192062306a36Sopenharmony_ci * 192162306a36Sopenharmony_ci * Compute a SID to use when selecting a member of a polyinstantiated 192262306a36Sopenharmony_ci * object of class @tclass based on a SID pair (@ssid, @tsid). 192362306a36Sopenharmony_ci * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 192462306a36Sopenharmony_ci * if insufficient memory is available, or %0 if the SID was 192562306a36Sopenharmony_ci * computed successfully. 192662306a36Sopenharmony_ci */ 192762306a36Sopenharmony_ciint security_member_sid(u32 ssid, 192862306a36Sopenharmony_ci u32 tsid, 192962306a36Sopenharmony_ci u16 tclass, 193062306a36Sopenharmony_ci u32 *out_sid) 193162306a36Sopenharmony_ci{ 193262306a36Sopenharmony_ci return security_compute_sid(ssid, tsid, tclass, 193362306a36Sopenharmony_ci AVTAB_MEMBER, NULL, 193462306a36Sopenharmony_ci out_sid, false); 193562306a36Sopenharmony_ci} 193662306a36Sopenharmony_ci 193762306a36Sopenharmony_ci/** 193862306a36Sopenharmony_ci * security_change_sid - Compute the SID for object relabeling. 193962306a36Sopenharmony_ci * @ssid: source security identifier 194062306a36Sopenharmony_ci * @tsid: target security identifier 194162306a36Sopenharmony_ci * @tclass: target security class 194262306a36Sopenharmony_ci * @out_sid: security identifier for selected member 194362306a36Sopenharmony_ci * 194462306a36Sopenharmony_ci * Compute a SID to use for relabeling an object of class @tclass 194562306a36Sopenharmony_ci * based on a SID pair (@ssid, @tsid). 194662306a36Sopenharmony_ci * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 194762306a36Sopenharmony_ci * if insufficient memory is available, or %0 if the SID was 194862306a36Sopenharmony_ci * computed successfully. 194962306a36Sopenharmony_ci */ 195062306a36Sopenharmony_ciint security_change_sid(u32 ssid, 195162306a36Sopenharmony_ci u32 tsid, 195262306a36Sopenharmony_ci u16 tclass, 195362306a36Sopenharmony_ci u32 *out_sid) 195462306a36Sopenharmony_ci{ 195562306a36Sopenharmony_ci return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL, 195662306a36Sopenharmony_ci out_sid, false); 195762306a36Sopenharmony_ci} 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_cistatic inline int convert_context_handle_invalid_context( 196062306a36Sopenharmony_ci struct policydb *policydb, 196162306a36Sopenharmony_ci struct context *context) 196262306a36Sopenharmony_ci{ 196362306a36Sopenharmony_ci char *s; 196462306a36Sopenharmony_ci u32 len; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci if (enforcing_enabled()) 196762306a36Sopenharmony_ci return -EINVAL; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci if (!context_struct_to_string(policydb, context, &s, &len)) { 197062306a36Sopenharmony_ci pr_warn("SELinux: Context %s would be invalid if enforcing\n", 197162306a36Sopenharmony_ci s); 197262306a36Sopenharmony_ci kfree(s); 197362306a36Sopenharmony_ci } 197462306a36Sopenharmony_ci return 0; 197562306a36Sopenharmony_ci} 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci/** 197862306a36Sopenharmony_ci * services_convert_context - Convert a security context across policies. 197962306a36Sopenharmony_ci * @args: populated convert_context_args struct 198062306a36Sopenharmony_ci * @oldc: original context 198162306a36Sopenharmony_ci * @newc: converted context 198262306a36Sopenharmony_ci * @gfp_flags: allocation flags 198362306a36Sopenharmony_ci * 198462306a36Sopenharmony_ci * Convert the values in the security context structure @oldc from the values 198562306a36Sopenharmony_ci * specified in the policy @args->oldp to the values specified in the policy 198662306a36Sopenharmony_ci * @args->newp, storing the new context in @newc, and verifying that the 198762306a36Sopenharmony_ci * context is valid under the new policy. 198862306a36Sopenharmony_ci */ 198962306a36Sopenharmony_ciint services_convert_context(struct convert_context_args *args, 199062306a36Sopenharmony_ci struct context *oldc, struct context *newc, 199162306a36Sopenharmony_ci gfp_t gfp_flags) 199262306a36Sopenharmony_ci{ 199362306a36Sopenharmony_ci struct ocontext *oc; 199462306a36Sopenharmony_ci struct role_datum *role; 199562306a36Sopenharmony_ci struct type_datum *typdatum; 199662306a36Sopenharmony_ci struct user_datum *usrdatum; 199762306a36Sopenharmony_ci char *s; 199862306a36Sopenharmony_ci u32 len; 199962306a36Sopenharmony_ci int rc; 200062306a36Sopenharmony_ci 200162306a36Sopenharmony_ci if (oldc->str) { 200262306a36Sopenharmony_ci s = kstrdup(oldc->str, gfp_flags); 200362306a36Sopenharmony_ci if (!s) 200462306a36Sopenharmony_ci return -ENOMEM; 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci rc = string_to_context_struct(args->newp, NULL, s, newc, SECSID_NULL); 200762306a36Sopenharmony_ci if (rc == -EINVAL) { 200862306a36Sopenharmony_ci /* 200962306a36Sopenharmony_ci * Retain string representation for later mapping. 201062306a36Sopenharmony_ci * 201162306a36Sopenharmony_ci * IMPORTANT: We need to copy the contents of oldc->str 201262306a36Sopenharmony_ci * back into s again because string_to_context_struct() 201362306a36Sopenharmony_ci * may have garbled it. 201462306a36Sopenharmony_ci */ 201562306a36Sopenharmony_ci memcpy(s, oldc->str, oldc->len); 201662306a36Sopenharmony_ci context_init(newc); 201762306a36Sopenharmony_ci newc->str = s; 201862306a36Sopenharmony_ci newc->len = oldc->len; 201962306a36Sopenharmony_ci return 0; 202062306a36Sopenharmony_ci } 202162306a36Sopenharmony_ci kfree(s); 202262306a36Sopenharmony_ci if (rc) { 202362306a36Sopenharmony_ci /* Other error condition, e.g. ENOMEM. */ 202462306a36Sopenharmony_ci pr_err("SELinux: Unable to map context %s, rc = %d.\n", 202562306a36Sopenharmony_ci oldc->str, -rc); 202662306a36Sopenharmony_ci return rc; 202762306a36Sopenharmony_ci } 202862306a36Sopenharmony_ci pr_info("SELinux: Context %s became valid (mapped).\n", 202962306a36Sopenharmony_ci oldc->str); 203062306a36Sopenharmony_ci return 0; 203162306a36Sopenharmony_ci } 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci context_init(newc); 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci /* Convert the user. */ 203662306a36Sopenharmony_ci usrdatum = symtab_search(&args->newp->p_users, 203762306a36Sopenharmony_ci sym_name(args->oldp, SYM_USERS, oldc->user - 1)); 203862306a36Sopenharmony_ci if (!usrdatum) 203962306a36Sopenharmony_ci goto bad; 204062306a36Sopenharmony_ci newc->user = usrdatum->value; 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci /* Convert the role. */ 204362306a36Sopenharmony_ci role = symtab_search(&args->newp->p_roles, 204462306a36Sopenharmony_ci sym_name(args->oldp, SYM_ROLES, oldc->role - 1)); 204562306a36Sopenharmony_ci if (!role) 204662306a36Sopenharmony_ci goto bad; 204762306a36Sopenharmony_ci newc->role = role->value; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci /* Convert the type. */ 205062306a36Sopenharmony_ci typdatum = symtab_search(&args->newp->p_types, 205162306a36Sopenharmony_ci sym_name(args->oldp, SYM_TYPES, oldc->type - 1)); 205262306a36Sopenharmony_ci if (!typdatum) 205362306a36Sopenharmony_ci goto bad; 205462306a36Sopenharmony_ci newc->type = typdatum->value; 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_ci /* Convert the MLS fields if dealing with MLS policies */ 205762306a36Sopenharmony_ci if (args->oldp->mls_enabled && args->newp->mls_enabled) { 205862306a36Sopenharmony_ci rc = mls_convert_context(args->oldp, args->newp, oldc, newc); 205962306a36Sopenharmony_ci if (rc) 206062306a36Sopenharmony_ci goto bad; 206162306a36Sopenharmony_ci } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { 206262306a36Sopenharmony_ci /* 206362306a36Sopenharmony_ci * Switching between non-MLS and MLS policy: 206462306a36Sopenharmony_ci * ensure that the MLS fields of the context for all 206562306a36Sopenharmony_ci * existing entries in the sidtab are filled in with a 206662306a36Sopenharmony_ci * suitable default value, likely taken from one of the 206762306a36Sopenharmony_ci * initial SIDs. 206862306a36Sopenharmony_ci */ 206962306a36Sopenharmony_ci oc = args->newp->ocontexts[OCON_ISID]; 207062306a36Sopenharmony_ci while (oc && oc->sid[0] != SECINITSID_UNLABELED) 207162306a36Sopenharmony_ci oc = oc->next; 207262306a36Sopenharmony_ci if (!oc) { 207362306a36Sopenharmony_ci pr_err("SELinux: unable to look up" 207462306a36Sopenharmony_ci " the initial SIDs list\n"); 207562306a36Sopenharmony_ci goto bad; 207662306a36Sopenharmony_ci } 207762306a36Sopenharmony_ci rc = mls_range_set(newc, &oc->context[0].range); 207862306a36Sopenharmony_ci if (rc) 207962306a36Sopenharmony_ci goto bad; 208062306a36Sopenharmony_ci } 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci /* Check the validity of the new context. */ 208362306a36Sopenharmony_ci if (!policydb_context_isvalid(args->newp, newc)) { 208462306a36Sopenharmony_ci rc = convert_context_handle_invalid_context(args->oldp, oldc); 208562306a36Sopenharmony_ci if (rc) 208662306a36Sopenharmony_ci goto bad; 208762306a36Sopenharmony_ci } 208862306a36Sopenharmony_ci 208962306a36Sopenharmony_ci return 0; 209062306a36Sopenharmony_cibad: 209162306a36Sopenharmony_ci /* Map old representation to string and save it. */ 209262306a36Sopenharmony_ci rc = context_struct_to_string(args->oldp, oldc, &s, &len); 209362306a36Sopenharmony_ci if (rc) 209462306a36Sopenharmony_ci return rc; 209562306a36Sopenharmony_ci context_destroy(newc); 209662306a36Sopenharmony_ci newc->str = s; 209762306a36Sopenharmony_ci newc->len = len; 209862306a36Sopenharmony_ci pr_info("SELinux: Context %s became invalid (unmapped).\n", 209962306a36Sopenharmony_ci newc->str); 210062306a36Sopenharmony_ci return 0; 210162306a36Sopenharmony_ci} 210262306a36Sopenharmony_ci 210362306a36Sopenharmony_cistatic void security_load_policycaps(struct selinux_policy *policy) 210462306a36Sopenharmony_ci{ 210562306a36Sopenharmony_ci struct policydb *p; 210662306a36Sopenharmony_ci unsigned int i; 210762306a36Sopenharmony_ci struct ebitmap_node *node; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci p = &policy->policydb; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++) 211262306a36Sopenharmony_ci WRITE_ONCE(selinux_state.policycap[i], 211362306a36Sopenharmony_ci ebitmap_get_bit(&p->policycaps, i)); 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++) 211662306a36Sopenharmony_ci pr_info("SELinux: policy capability %s=%d\n", 211762306a36Sopenharmony_ci selinux_policycap_names[i], 211862306a36Sopenharmony_ci ebitmap_get_bit(&p->policycaps, i)); 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci ebitmap_for_each_positive_bit(&p->policycaps, node, i) { 212162306a36Sopenharmony_ci if (i >= ARRAY_SIZE(selinux_policycap_names)) 212262306a36Sopenharmony_ci pr_info("SELinux: unknown policy capability %u\n", 212362306a36Sopenharmony_ci i); 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci} 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_cistatic int security_preserve_bools(struct selinux_policy *oldpolicy, 212862306a36Sopenharmony_ci struct selinux_policy *newpolicy); 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_cistatic void selinux_policy_free(struct selinux_policy *policy) 213162306a36Sopenharmony_ci{ 213262306a36Sopenharmony_ci if (!policy) 213362306a36Sopenharmony_ci return; 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_ci sidtab_destroy(policy->sidtab); 213662306a36Sopenharmony_ci kfree(policy->map.mapping); 213762306a36Sopenharmony_ci policydb_destroy(&policy->policydb); 213862306a36Sopenharmony_ci kfree(policy->sidtab); 213962306a36Sopenharmony_ci kfree(policy); 214062306a36Sopenharmony_ci} 214162306a36Sopenharmony_ci 214262306a36Sopenharmony_cistatic void selinux_policy_cond_free(struct selinux_policy *policy) 214362306a36Sopenharmony_ci{ 214462306a36Sopenharmony_ci cond_policydb_destroy_dup(&policy->policydb); 214562306a36Sopenharmony_ci kfree(policy); 214662306a36Sopenharmony_ci} 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_civoid selinux_policy_cancel(struct selinux_load_state *load_state) 214962306a36Sopenharmony_ci{ 215062306a36Sopenharmony_ci struct selinux_state *state = &selinux_state; 215162306a36Sopenharmony_ci struct selinux_policy *oldpolicy; 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci oldpolicy = rcu_dereference_protected(state->policy, 215462306a36Sopenharmony_ci lockdep_is_held(&state->policy_mutex)); 215562306a36Sopenharmony_ci 215662306a36Sopenharmony_ci sidtab_cancel_convert(oldpolicy->sidtab); 215762306a36Sopenharmony_ci selinux_policy_free(load_state->policy); 215862306a36Sopenharmony_ci kfree(load_state->convert_data); 215962306a36Sopenharmony_ci} 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_cistatic void selinux_notify_policy_change(u32 seqno) 216262306a36Sopenharmony_ci{ 216362306a36Sopenharmony_ci /* Flush external caches and notify userspace of policy load */ 216462306a36Sopenharmony_ci avc_ss_reset(seqno); 216562306a36Sopenharmony_ci selnl_notify_policyload(seqno); 216662306a36Sopenharmony_ci selinux_status_update_policyload(seqno); 216762306a36Sopenharmony_ci selinux_netlbl_cache_invalidate(); 216862306a36Sopenharmony_ci selinux_xfrm_notify_policyload(); 216962306a36Sopenharmony_ci selinux_ima_measure_state_locked(); 217062306a36Sopenharmony_ci} 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_civoid selinux_policy_commit(struct selinux_load_state *load_state) 217362306a36Sopenharmony_ci{ 217462306a36Sopenharmony_ci struct selinux_state *state = &selinux_state; 217562306a36Sopenharmony_ci struct selinux_policy *oldpolicy, *newpolicy = load_state->policy; 217662306a36Sopenharmony_ci unsigned long flags; 217762306a36Sopenharmony_ci u32 seqno; 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci oldpolicy = rcu_dereference_protected(state->policy, 218062306a36Sopenharmony_ci lockdep_is_held(&state->policy_mutex)); 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci /* If switching between different policy types, log MLS status */ 218362306a36Sopenharmony_ci if (oldpolicy) { 218462306a36Sopenharmony_ci if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled) 218562306a36Sopenharmony_ci pr_info("SELinux: Disabling MLS support...\n"); 218662306a36Sopenharmony_ci else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled) 218762306a36Sopenharmony_ci pr_info("SELinux: Enabling MLS support...\n"); 218862306a36Sopenharmony_ci } 218962306a36Sopenharmony_ci 219062306a36Sopenharmony_ci /* Set latest granting seqno for new policy. */ 219162306a36Sopenharmony_ci if (oldpolicy) 219262306a36Sopenharmony_ci newpolicy->latest_granting = oldpolicy->latest_granting + 1; 219362306a36Sopenharmony_ci else 219462306a36Sopenharmony_ci newpolicy->latest_granting = 1; 219562306a36Sopenharmony_ci seqno = newpolicy->latest_granting; 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci /* Install the new policy. */ 219862306a36Sopenharmony_ci if (oldpolicy) { 219962306a36Sopenharmony_ci sidtab_freeze_begin(oldpolicy->sidtab, &flags); 220062306a36Sopenharmony_ci rcu_assign_pointer(state->policy, newpolicy); 220162306a36Sopenharmony_ci sidtab_freeze_end(oldpolicy->sidtab, &flags); 220262306a36Sopenharmony_ci } else { 220362306a36Sopenharmony_ci rcu_assign_pointer(state->policy, newpolicy); 220462306a36Sopenharmony_ci } 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci /* Load the policycaps from the new policy */ 220762306a36Sopenharmony_ci security_load_policycaps(newpolicy); 220862306a36Sopenharmony_ci 220962306a36Sopenharmony_ci if (!selinux_initialized()) { 221062306a36Sopenharmony_ci /* 221162306a36Sopenharmony_ci * After first policy load, the security server is 221262306a36Sopenharmony_ci * marked as initialized and ready to handle requests and 221362306a36Sopenharmony_ci * any objects created prior to policy load are then labeled. 221462306a36Sopenharmony_ci */ 221562306a36Sopenharmony_ci selinux_mark_initialized(); 221662306a36Sopenharmony_ci selinux_complete_init(); 221762306a36Sopenharmony_ci } 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci /* Free the old policy */ 222062306a36Sopenharmony_ci synchronize_rcu(); 222162306a36Sopenharmony_ci selinux_policy_free(oldpolicy); 222262306a36Sopenharmony_ci kfree(load_state->convert_data); 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci /* Notify others of the policy change */ 222562306a36Sopenharmony_ci selinux_notify_policy_change(seqno); 222662306a36Sopenharmony_ci} 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci/** 222962306a36Sopenharmony_ci * security_load_policy - Load a security policy configuration. 223062306a36Sopenharmony_ci * @data: binary policy data 223162306a36Sopenharmony_ci * @len: length of data in bytes 223262306a36Sopenharmony_ci * @load_state: policy load state 223362306a36Sopenharmony_ci * 223462306a36Sopenharmony_ci * Load a new set of security policy configuration data, 223562306a36Sopenharmony_ci * validate it and convert the SID table as necessary. 223662306a36Sopenharmony_ci * This function will flush the access vector cache after 223762306a36Sopenharmony_ci * loading the new policy. 223862306a36Sopenharmony_ci */ 223962306a36Sopenharmony_ciint security_load_policy(void *data, size_t len, 224062306a36Sopenharmony_ci struct selinux_load_state *load_state) 224162306a36Sopenharmony_ci{ 224262306a36Sopenharmony_ci struct selinux_state *state = &selinux_state; 224362306a36Sopenharmony_ci struct selinux_policy *newpolicy, *oldpolicy; 224462306a36Sopenharmony_ci struct selinux_policy_convert_data *convert_data; 224562306a36Sopenharmony_ci int rc = 0; 224662306a36Sopenharmony_ci struct policy_file file = { data, len }, *fp = &file; 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL); 224962306a36Sopenharmony_ci if (!newpolicy) 225062306a36Sopenharmony_ci return -ENOMEM; 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL); 225362306a36Sopenharmony_ci if (!newpolicy->sidtab) { 225462306a36Sopenharmony_ci rc = -ENOMEM; 225562306a36Sopenharmony_ci goto err_policy; 225662306a36Sopenharmony_ci } 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci rc = policydb_read(&newpolicy->policydb, fp); 225962306a36Sopenharmony_ci if (rc) 226062306a36Sopenharmony_ci goto err_sidtab; 226162306a36Sopenharmony_ci 226262306a36Sopenharmony_ci newpolicy->policydb.len = len; 226362306a36Sopenharmony_ci rc = selinux_set_mapping(&newpolicy->policydb, secclass_map, 226462306a36Sopenharmony_ci &newpolicy->map); 226562306a36Sopenharmony_ci if (rc) 226662306a36Sopenharmony_ci goto err_policydb; 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab); 226962306a36Sopenharmony_ci if (rc) { 227062306a36Sopenharmony_ci pr_err("SELinux: unable to load the initial SIDs\n"); 227162306a36Sopenharmony_ci goto err_mapping; 227262306a36Sopenharmony_ci } 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci if (!selinux_initialized()) { 227562306a36Sopenharmony_ci /* First policy load, so no need to preserve state from old policy */ 227662306a36Sopenharmony_ci load_state->policy = newpolicy; 227762306a36Sopenharmony_ci load_state->convert_data = NULL; 227862306a36Sopenharmony_ci return 0; 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci oldpolicy = rcu_dereference_protected(state->policy, 228262306a36Sopenharmony_ci lockdep_is_held(&state->policy_mutex)); 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci /* Preserve active boolean values from the old policy */ 228562306a36Sopenharmony_ci rc = security_preserve_bools(oldpolicy, newpolicy); 228662306a36Sopenharmony_ci if (rc) { 228762306a36Sopenharmony_ci pr_err("SELinux: unable to preserve booleans\n"); 228862306a36Sopenharmony_ci goto err_free_isids; 228962306a36Sopenharmony_ci } 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci /* 229262306a36Sopenharmony_ci * Convert the internal representations of contexts 229362306a36Sopenharmony_ci * in the new SID table. 229462306a36Sopenharmony_ci */ 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL); 229762306a36Sopenharmony_ci if (!convert_data) { 229862306a36Sopenharmony_ci rc = -ENOMEM; 229962306a36Sopenharmony_ci goto err_free_isids; 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci convert_data->args.oldp = &oldpolicy->policydb; 230362306a36Sopenharmony_ci convert_data->args.newp = &newpolicy->policydb; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci convert_data->sidtab_params.args = &convert_data->args; 230662306a36Sopenharmony_ci convert_data->sidtab_params.target = newpolicy->sidtab; 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params); 230962306a36Sopenharmony_ci if (rc) { 231062306a36Sopenharmony_ci pr_err("SELinux: unable to convert the internal" 231162306a36Sopenharmony_ci " representation of contexts in the new SID" 231262306a36Sopenharmony_ci " table\n"); 231362306a36Sopenharmony_ci goto err_free_convert_data; 231462306a36Sopenharmony_ci } 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci load_state->policy = newpolicy; 231762306a36Sopenharmony_ci load_state->convert_data = convert_data; 231862306a36Sopenharmony_ci return 0; 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_cierr_free_convert_data: 232162306a36Sopenharmony_ci kfree(convert_data); 232262306a36Sopenharmony_cierr_free_isids: 232362306a36Sopenharmony_ci sidtab_destroy(newpolicy->sidtab); 232462306a36Sopenharmony_cierr_mapping: 232562306a36Sopenharmony_ci kfree(newpolicy->map.mapping); 232662306a36Sopenharmony_cierr_policydb: 232762306a36Sopenharmony_ci policydb_destroy(&newpolicy->policydb); 232862306a36Sopenharmony_cierr_sidtab: 232962306a36Sopenharmony_ci kfree(newpolicy->sidtab); 233062306a36Sopenharmony_cierr_policy: 233162306a36Sopenharmony_ci kfree(newpolicy); 233262306a36Sopenharmony_ci 233362306a36Sopenharmony_ci return rc; 233462306a36Sopenharmony_ci} 233562306a36Sopenharmony_ci 233662306a36Sopenharmony_ci/** 233762306a36Sopenharmony_ci * ocontext_to_sid - Helper to safely get sid for an ocontext 233862306a36Sopenharmony_ci * @sidtab: SID table 233962306a36Sopenharmony_ci * @c: ocontext structure 234062306a36Sopenharmony_ci * @index: index of the context entry (0 or 1) 234162306a36Sopenharmony_ci * @out_sid: pointer to the resulting SID value 234262306a36Sopenharmony_ci * 234362306a36Sopenharmony_ci * For all ocontexts except OCON_ISID the SID fields are populated 234462306a36Sopenharmony_ci * on-demand when needed. Since updating the SID value is an SMP-sensitive 234562306a36Sopenharmony_ci * operation, this helper must be used to do that safely. 234662306a36Sopenharmony_ci * 234762306a36Sopenharmony_ci * WARNING: This function may return -ESTALE, indicating that the caller 234862306a36Sopenharmony_ci * must retry the operation after re-acquiring the policy pointer! 234962306a36Sopenharmony_ci */ 235062306a36Sopenharmony_cistatic int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c, 235162306a36Sopenharmony_ci size_t index, u32 *out_sid) 235262306a36Sopenharmony_ci{ 235362306a36Sopenharmony_ci int rc; 235462306a36Sopenharmony_ci u32 sid; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci /* Ensure the associated sidtab entry is visible to this thread. */ 235762306a36Sopenharmony_ci sid = smp_load_acquire(&c->sid[index]); 235862306a36Sopenharmony_ci if (!sid) { 235962306a36Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid); 236062306a36Sopenharmony_ci if (rc) 236162306a36Sopenharmony_ci return rc; 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci /* 236462306a36Sopenharmony_ci * Ensure the new sidtab entry is visible to other threads 236562306a36Sopenharmony_ci * when they see the SID. 236662306a36Sopenharmony_ci */ 236762306a36Sopenharmony_ci smp_store_release(&c->sid[index], sid); 236862306a36Sopenharmony_ci } 236962306a36Sopenharmony_ci *out_sid = sid; 237062306a36Sopenharmony_ci return 0; 237162306a36Sopenharmony_ci} 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci/** 237462306a36Sopenharmony_ci * security_port_sid - Obtain the SID for a port. 237562306a36Sopenharmony_ci * @protocol: protocol number 237662306a36Sopenharmony_ci * @port: port number 237762306a36Sopenharmony_ci * @out_sid: security identifier 237862306a36Sopenharmony_ci */ 237962306a36Sopenharmony_ciint security_port_sid(u8 protocol, u16 port, u32 *out_sid) 238062306a36Sopenharmony_ci{ 238162306a36Sopenharmony_ci struct selinux_policy *policy; 238262306a36Sopenharmony_ci struct policydb *policydb; 238362306a36Sopenharmony_ci struct sidtab *sidtab; 238462306a36Sopenharmony_ci struct ocontext *c; 238562306a36Sopenharmony_ci int rc; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci if (!selinux_initialized()) { 238862306a36Sopenharmony_ci *out_sid = SECINITSID_PORT; 238962306a36Sopenharmony_ci return 0; 239062306a36Sopenharmony_ci } 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ciretry: 239362306a36Sopenharmony_ci rc = 0; 239462306a36Sopenharmony_ci rcu_read_lock(); 239562306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 239662306a36Sopenharmony_ci policydb = &policy->policydb; 239762306a36Sopenharmony_ci sidtab = policy->sidtab; 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci c = policydb->ocontexts[OCON_PORT]; 240062306a36Sopenharmony_ci while (c) { 240162306a36Sopenharmony_ci if (c->u.port.protocol == protocol && 240262306a36Sopenharmony_ci c->u.port.low_port <= port && 240362306a36Sopenharmony_ci c->u.port.high_port >= port) 240462306a36Sopenharmony_ci break; 240562306a36Sopenharmony_ci c = c->next; 240662306a36Sopenharmony_ci } 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci if (c) { 240962306a36Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, out_sid); 241062306a36Sopenharmony_ci if (rc == -ESTALE) { 241162306a36Sopenharmony_ci rcu_read_unlock(); 241262306a36Sopenharmony_ci goto retry; 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci if (rc) 241562306a36Sopenharmony_ci goto out; 241662306a36Sopenharmony_ci } else { 241762306a36Sopenharmony_ci *out_sid = SECINITSID_PORT; 241862306a36Sopenharmony_ci } 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ciout: 242162306a36Sopenharmony_ci rcu_read_unlock(); 242262306a36Sopenharmony_ci return rc; 242362306a36Sopenharmony_ci} 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci/** 242662306a36Sopenharmony_ci * security_ib_pkey_sid - Obtain the SID for a pkey. 242762306a36Sopenharmony_ci * @subnet_prefix: Subnet Prefix 242862306a36Sopenharmony_ci * @pkey_num: pkey number 242962306a36Sopenharmony_ci * @out_sid: security identifier 243062306a36Sopenharmony_ci */ 243162306a36Sopenharmony_ciint security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid) 243262306a36Sopenharmony_ci{ 243362306a36Sopenharmony_ci struct selinux_policy *policy; 243462306a36Sopenharmony_ci struct policydb *policydb; 243562306a36Sopenharmony_ci struct sidtab *sidtab; 243662306a36Sopenharmony_ci struct ocontext *c; 243762306a36Sopenharmony_ci int rc; 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci if (!selinux_initialized()) { 244062306a36Sopenharmony_ci *out_sid = SECINITSID_UNLABELED; 244162306a36Sopenharmony_ci return 0; 244262306a36Sopenharmony_ci } 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ciretry: 244562306a36Sopenharmony_ci rc = 0; 244662306a36Sopenharmony_ci rcu_read_lock(); 244762306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 244862306a36Sopenharmony_ci policydb = &policy->policydb; 244962306a36Sopenharmony_ci sidtab = policy->sidtab; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci c = policydb->ocontexts[OCON_IBPKEY]; 245262306a36Sopenharmony_ci while (c) { 245362306a36Sopenharmony_ci if (c->u.ibpkey.low_pkey <= pkey_num && 245462306a36Sopenharmony_ci c->u.ibpkey.high_pkey >= pkey_num && 245562306a36Sopenharmony_ci c->u.ibpkey.subnet_prefix == subnet_prefix) 245662306a36Sopenharmony_ci break; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci c = c->next; 245962306a36Sopenharmony_ci } 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_ci if (c) { 246262306a36Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, out_sid); 246362306a36Sopenharmony_ci if (rc == -ESTALE) { 246462306a36Sopenharmony_ci rcu_read_unlock(); 246562306a36Sopenharmony_ci goto retry; 246662306a36Sopenharmony_ci } 246762306a36Sopenharmony_ci if (rc) 246862306a36Sopenharmony_ci goto out; 246962306a36Sopenharmony_ci } else 247062306a36Sopenharmony_ci *out_sid = SECINITSID_UNLABELED; 247162306a36Sopenharmony_ci 247262306a36Sopenharmony_ciout: 247362306a36Sopenharmony_ci rcu_read_unlock(); 247462306a36Sopenharmony_ci return rc; 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci/** 247862306a36Sopenharmony_ci * security_ib_endport_sid - Obtain the SID for a subnet management interface. 247962306a36Sopenharmony_ci * @dev_name: device name 248062306a36Sopenharmony_ci * @port_num: port number 248162306a36Sopenharmony_ci * @out_sid: security identifier 248262306a36Sopenharmony_ci */ 248362306a36Sopenharmony_ciint security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid) 248462306a36Sopenharmony_ci{ 248562306a36Sopenharmony_ci struct selinux_policy *policy; 248662306a36Sopenharmony_ci struct policydb *policydb; 248762306a36Sopenharmony_ci struct sidtab *sidtab; 248862306a36Sopenharmony_ci struct ocontext *c; 248962306a36Sopenharmony_ci int rc; 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci if (!selinux_initialized()) { 249262306a36Sopenharmony_ci *out_sid = SECINITSID_UNLABELED; 249362306a36Sopenharmony_ci return 0; 249462306a36Sopenharmony_ci } 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ciretry: 249762306a36Sopenharmony_ci rc = 0; 249862306a36Sopenharmony_ci rcu_read_lock(); 249962306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 250062306a36Sopenharmony_ci policydb = &policy->policydb; 250162306a36Sopenharmony_ci sidtab = policy->sidtab; 250262306a36Sopenharmony_ci 250362306a36Sopenharmony_ci c = policydb->ocontexts[OCON_IBENDPORT]; 250462306a36Sopenharmony_ci while (c) { 250562306a36Sopenharmony_ci if (c->u.ibendport.port == port_num && 250662306a36Sopenharmony_ci !strncmp(c->u.ibendport.dev_name, 250762306a36Sopenharmony_ci dev_name, 250862306a36Sopenharmony_ci IB_DEVICE_NAME_MAX)) 250962306a36Sopenharmony_ci break; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ci c = c->next; 251262306a36Sopenharmony_ci } 251362306a36Sopenharmony_ci 251462306a36Sopenharmony_ci if (c) { 251562306a36Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, out_sid); 251662306a36Sopenharmony_ci if (rc == -ESTALE) { 251762306a36Sopenharmony_ci rcu_read_unlock(); 251862306a36Sopenharmony_ci goto retry; 251962306a36Sopenharmony_ci } 252062306a36Sopenharmony_ci if (rc) 252162306a36Sopenharmony_ci goto out; 252262306a36Sopenharmony_ci } else 252362306a36Sopenharmony_ci *out_sid = SECINITSID_UNLABELED; 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ciout: 252662306a36Sopenharmony_ci rcu_read_unlock(); 252762306a36Sopenharmony_ci return rc; 252862306a36Sopenharmony_ci} 252962306a36Sopenharmony_ci 253062306a36Sopenharmony_ci/** 253162306a36Sopenharmony_ci * security_netif_sid - Obtain the SID for a network interface. 253262306a36Sopenharmony_ci * @name: interface name 253362306a36Sopenharmony_ci * @if_sid: interface SID 253462306a36Sopenharmony_ci */ 253562306a36Sopenharmony_ciint security_netif_sid(char *name, u32 *if_sid) 253662306a36Sopenharmony_ci{ 253762306a36Sopenharmony_ci struct selinux_policy *policy; 253862306a36Sopenharmony_ci struct policydb *policydb; 253962306a36Sopenharmony_ci struct sidtab *sidtab; 254062306a36Sopenharmony_ci int rc; 254162306a36Sopenharmony_ci struct ocontext *c; 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci if (!selinux_initialized()) { 254462306a36Sopenharmony_ci *if_sid = SECINITSID_NETIF; 254562306a36Sopenharmony_ci return 0; 254662306a36Sopenharmony_ci } 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ciretry: 254962306a36Sopenharmony_ci rc = 0; 255062306a36Sopenharmony_ci rcu_read_lock(); 255162306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 255262306a36Sopenharmony_ci policydb = &policy->policydb; 255362306a36Sopenharmony_ci sidtab = policy->sidtab; 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci c = policydb->ocontexts[OCON_NETIF]; 255662306a36Sopenharmony_ci while (c) { 255762306a36Sopenharmony_ci if (strcmp(name, c->u.name) == 0) 255862306a36Sopenharmony_ci break; 255962306a36Sopenharmony_ci c = c->next; 256062306a36Sopenharmony_ci } 256162306a36Sopenharmony_ci 256262306a36Sopenharmony_ci if (c) { 256362306a36Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, if_sid); 256462306a36Sopenharmony_ci if (rc == -ESTALE) { 256562306a36Sopenharmony_ci rcu_read_unlock(); 256662306a36Sopenharmony_ci goto retry; 256762306a36Sopenharmony_ci } 256862306a36Sopenharmony_ci if (rc) 256962306a36Sopenharmony_ci goto out; 257062306a36Sopenharmony_ci } else 257162306a36Sopenharmony_ci *if_sid = SECINITSID_NETIF; 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ciout: 257462306a36Sopenharmony_ci rcu_read_unlock(); 257562306a36Sopenharmony_ci return rc; 257662306a36Sopenharmony_ci} 257762306a36Sopenharmony_ci 257862306a36Sopenharmony_cistatic int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) 257962306a36Sopenharmony_ci{ 258062306a36Sopenharmony_ci int i, fail = 0; 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci for (i = 0; i < 4; i++) 258362306a36Sopenharmony_ci if (addr[i] != (input[i] & mask[i])) { 258462306a36Sopenharmony_ci fail = 1; 258562306a36Sopenharmony_ci break; 258662306a36Sopenharmony_ci } 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci return !fail; 258962306a36Sopenharmony_ci} 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci/** 259262306a36Sopenharmony_ci * security_node_sid - Obtain the SID for a node (host). 259362306a36Sopenharmony_ci * @domain: communication domain aka address family 259462306a36Sopenharmony_ci * @addrp: address 259562306a36Sopenharmony_ci * @addrlen: address length in bytes 259662306a36Sopenharmony_ci * @out_sid: security identifier 259762306a36Sopenharmony_ci */ 259862306a36Sopenharmony_ciint security_node_sid(u16 domain, 259962306a36Sopenharmony_ci void *addrp, 260062306a36Sopenharmony_ci u32 addrlen, 260162306a36Sopenharmony_ci u32 *out_sid) 260262306a36Sopenharmony_ci{ 260362306a36Sopenharmony_ci struct selinux_policy *policy; 260462306a36Sopenharmony_ci struct policydb *policydb; 260562306a36Sopenharmony_ci struct sidtab *sidtab; 260662306a36Sopenharmony_ci int rc; 260762306a36Sopenharmony_ci struct ocontext *c; 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci if (!selinux_initialized()) { 261062306a36Sopenharmony_ci *out_sid = SECINITSID_NODE; 261162306a36Sopenharmony_ci return 0; 261262306a36Sopenharmony_ci } 261362306a36Sopenharmony_ci 261462306a36Sopenharmony_ciretry: 261562306a36Sopenharmony_ci rcu_read_lock(); 261662306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 261762306a36Sopenharmony_ci policydb = &policy->policydb; 261862306a36Sopenharmony_ci sidtab = policy->sidtab; 261962306a36Sopenharmony_ci 262062306a36Sopenharmony_ci switch (domain) { 262162306a36Sopenharmony_ci case AF_INET: { 262262306a36Sopenharmony_ci u32 addr; 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci rc = -EINVAL; 262562306a36Sopenharmony_ci if (addrlen != sizeof(u32)) 262662306a36Sopenharmony_ci goto out; 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci addr = *((u32 *)addrp); 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci c = policydb->ocontexts[OCON_NODE]; 263162306a36Sopenharmony_ci while (c) { 263262306a36Sopenharmony_ci if (c->u.node.addr == (addr & c->u.node.mask)) 263362306a36Sopenharmony_ci break; 263462306a36Sopenharmony_ci c = c->next; 263562306a36Sopenharmony_ci } 263662306a36Sopenharmony_ci break; 263762306a36Sopenharmony_ci } 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci case AF_INET6: 264062306a36Sopenharmony_ci rc = -EINVAL; 264162306a36Sopenharmony_ci if (addrlen != sizeof(u64) * 2) 264262306a36Sopenharmony_ci goto out; 264362306a36Sopenharmony_ci c = policydb->ocontexts[OCON_NODE6]; 264462306a36Sopenharmony_ci while (c) { 264562306a36Sopenharmony_ci if (match_ipv6_addrmask(addrp, c->u.node6.addr, 264662306a36Sopenharmony_ci c->u.node6.mask)) 264762306a36Sopenharmony_ci break; 264862306a36Sopenharmony_ci c = c->next; 264962306a36Sopenharmony_ci } 265062306a36Sopenharmony_ci break; 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci default: 265362306a36Sopenharmony_ci rc = 0; 265462306a36Sopenharmony_ci *out_sid = SECINITSID_NODE; 265562306a36Sopenharmony_ci goto out; 265662306a36Sopenharmony_ci } 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci if (c) { 265962306a36Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, out_sid); 266062306a36Sopenharmony_ci if (rc == -ESTALE) { 266162306a36Sopenharmony_ci rcu_read_unlock(); 266262306a36Sopenharmony_ci goto retry; 266362306a36Sopenharmony_ci } 266462306a36Sopenharmony_ci if (rc) 266562306a36Sopenharmony_ci goto out; 266662306a36Sopenharmony_ci } else { 266762306a36Sopenharmony_ci *out_sid = SECINITSID_NODE; 266862306a36Sopenharmony_ci } 266962306a36Sopenharmony_ci 267062306a36Sopenharmony_ci rc = 0; 267162306a36Sopenharmony_ciout: 267262306a36Sopenharmony_ci rcu_read_unlock(); 267362306a36Sopenharmony_ci return rc; 267462306a36Sopenharmony_ci} 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci#define SIDS_NEL 25 267762306a36Sopenharmony_ci 267862306a36Sopenharmony_ci/** 267962306a36Sopenharmony_ci * security_get_user_sids - Obtain reachable SIDs for a user. 268062306a36Sopenharmony_ci * @fromsid: starting SID 268162306a36Sopenharmony_ci * @username: username 268262306a36Sopenharmony_ci * @sids: array of reachable SIDs for user 268362306a36Sopenharmony_ci * @nel: number of elements in @sids 268462306a36Sopenharmony_ci * 268562306a36Sopenharmony_ci * Generate the set of SIDs for legal security contexts 268662306a36Sopenharmony_ci * for a given user that can be reached by @fromsid. 268762306a36Sopenharmony_ci * Set *@sids to point to a dynamically allocated 268862306a36Sopenharmony_ci * array containing the set of SIDs. Set *@nel to the 268962306a36Sopenharmony_ci * number of elements in the array. 269062306a36Sopenharmony_ci */ 269162306a36Sopenharmony_ci 269262306a36Sopenharmony_ciint security_get_user_sids(u32 fromsid, 269362306a36Sopenharmony_ci char *username, 269462306a36Sopenharmony_ci u32 **sids, 269562306a36Sopenharmony_ci u32 *nel) 269662306a36Sopenharmony_ci{ 269762306a36Sopenharmony_ci struct selinux_policy *policy; 269862306a36Sopenharmony_ci struct policydb *policydb; 269962306a36Sopenharmony_ci struct sidtab *sidtab; 270062306a36Sopenharmony_ci struct context *fromcon, usercon; 270162306a36Sopenharmony_ci u32 *mysids = NULL, *mysids2, sid; 270262306a36Sopenharmony_ci u32 i, j, mynel, maxnel = SIDS_NEL; 270362306a36Sopenharmony_ci struct user_datum *user; 270462306a36Sopenharmony_ci struct role_datum *role; 270562306a36Sopenharmony_ci struct ebitmap_node *rnode, *tnode; 270662306a36Sopenharmony_ci int rc; 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci *sids = NULL; 270962306a36Sopenharmony_ci *nel = 0; 271062306a36Sopenharmony_ci 271162306a36Sopenharmony_ci if (!selinux_initialized()) 271262306a36Sopenharmony_ci return 0; 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL); 271562306a36Sopenharmony_ci if (!mysids) 271662306a36Sopenharmony_ci return -ENOMEM; 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ciretry: 271962306a36Sopenharmony_ci mynel = 0; 272062306a36Sopenharmony_ci rcu_read_lock(); 272162306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 272262306a36Sopenharmony_ci policydb = &policy->policydb; 272362306a36Sopenharmony_ci sidtab = policy->sidtab; 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci context_init(&usercon); 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_ci rc = -EINVAL; 272862306a36Sopenharmony_ci fromcon = sidtab_search(sidtab, fromsid); 272962306a36Sopenharmony_ci if (!fromcon) 273062306a36Sopenharmony_ci goto out_unlock; 273162306a36Sopenharmony_ci 273262306a36Sopenharmony_ci rc = -EINVAL; 273362306a36Sopenharmony_ci user = symtab_search(&policydb->p_users, username); 273462306a36Sopenharmony_ci if (!user) 273562306a36Sopenharmony_ci goto out_unlock; 273662306a36Sopenharmony_ci 273762306a36Sopenharmony_ci usercon.user = user->value; 273862306a36Sopenharmony_ci 273962306a36Sopenharmony_ci ebitmap_for_each_positive_bit(&user->roles, rnode, i) { 274062306a36Sopenharmony_ci role = policydb->role_val_to_struct[i]; 274162306a36Sopenharmony_ci usercon.role = i + 1; 274262306a36Sopenharmony_ci ebitmap_for_each_positive_bit(&role->types, tnode, j) { 274362306a36Sopenharmony_ci usercon.type = j + 1; 274462306a36Sopenharmony_ci 274562306a36Sopenharmony_ci if (mls_setup_user_range(policydb, fromcon, user, 274662306a36Sopenharmony_ci &usercon)) 274762306a36Sopenharmony_ci continue; 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &usercon, &sid); 275062306a36Sopenharmony_ci if (rc == -ESTALE) { 275162306a36Sopenharmony_ci rcu_read_unlock(); 275262306a36Sopenharmony_ci goto retry; 275362306a36Sopenharmony_ci } 275462306a36Sopenharmony_ci if (rc) 275562306a36Sopenharmony_ci goto out_unlock; 275662306a36Sopenharmony_ci if (mynel < maxnel) { 275762306a36Sopenharmony_ci mysids[mynel++] = sid; 275862306a36Sopenharmony_ci } else { 275962306a36Sopenharmony_ci rc = -ENOMEM; 276062306a36Sopenharmony_ci maxnel += SIDS_NEL; 276162306a36Sopenharmony_ci mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); 276262306a36Sopenharmony_ci if (!mysids2) 276362306a36Sopenharmony_ci goto out_unlock; 276462306a36Sopenharmony_ci memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); 276562306a36Sopenharmony_ci kfree(mysids); 276662306a36Sopenharmony_ci mysids = mysids2; 276762306a36Sopenharmony_ci mysids[mynel++] = sid; 276862306a36Sopenharmony_ci } 276962306a36Sopenharmony_ci } 277062306a36Sopenharmony_ci } 277162306a36Sopenharmony_ci rc = 0; 277262306a36Sopenharmony_ciout_unlock: 277362306a36Sopenharmony_ci rcu_read_unlock(); 277462306a36Sopenharmony_ci if (rc || !mynel) { 277562306a36Sopenharmony_ci kfree(mysids); 277662306a36Sopenharmony_ci return rc; 277762306a36Sopenharmony_ci } 277862306a36Sopenharmony_ci 277962306a36Sopenharmony_ci rc = -ENOMEM; 278062306a36Sopenharmony_ci mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL); 278162306a36Sopenharmony_ci if (!mysids2) { 278262306a36Sopenharmony_ci kfree(mysids); 278362306a36Sopenharmony_ci return rc; 278462306a36Sopenharmony_ci } 278562306a36Sopenharmony_ci for (i = 0, j = 0; i < mynel; i++) { 278662306a36Sopenharmony_ci struct av_decision dummy_avd; 278762306a36Sopenharmony_ci rc = avc_has_perm_noaudit(fromsid, mysids[i], 278862306a36Sopenharmony_ci SECCLASS_PROCESS, /* kernel value */ 278962306a36Sopenharmony_ci PROCESS__TRANSITION, AVC_STRICT, 279062306a36Sopenharmony_ci &dummy_avd); 279162306a36Sopenharmony_ci if (!rc) 279262306a36Sopenharmony_ci mysids2[j++] = mysids[i]; 279362306a36Sopenharmony_ci cond_resched(); 279462306a36Sopenharmony_ci } 279562306a36Sopenharmony_ci kfree(mysids); 279662306a36Sopenharmony_ci *sids = mysids2; 279762306a36Sopenharmony_ci *nel = j; 279862306a36Sopenharmony_ci return 0; 279962306a36Sopenharmony_ci} 280062306a36Sopenharmony_ci 280162306a36Sopenharmony_ci/** 280262306a36Sopenharmony_ci * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem 280362306a36Sopenharmony_ci * @policy: policy 280462306a36Sopenharmony_ci * @fstype: filesystem type 280562306a36Sopenharmony_ci * @path: path from root of mount 280662306a36Sopenharmony_ci * @orig_sclass: file security class 280762306a36Sopenharmony_ci * @sid: SID for path 280862306a36Sopenharmony_ci * 280962306a36Sopenharmony_ci * Obtain a SID to use for a file in a filesystem that 281062306a36Sopenharmony_ci * cannot support xattr or use a fixed labeling behavior like 281162306a36Sopenharmony_ci * transition SIDs or task SIDs. 281262306a36Sopenharmony_ci * 281362306a36Sopenharmony_ci * WARNING: This function may return -ESTALE, indicating that the caller 281462306a36Sopenharmony_ci * must retry the operation after re-acquiring the policy pointer! 281562306a36Sopenharmony_ci */ 281662306a36Sopenharmony_cistatic inline int __security_genfs_sid(struct selinux_policy *policy, 281762306a36Sopenharmony_ci const char *fstype, 281862306a36Sopenharmony_ci const char *path, 281962306a36Sopenharmony_ci u16 orig_sclass, 282062306a36Sopenharmony_ci u32 *sid) 282162306a36Sopenharmony_ci{ 282262306a36Sopenharmony_ci struct policydb *policydb = &policy->policydb; 282362306a36Sopenharmony_ci struct sidtab *sidtab = policy->sidtab; 282462306a36Sopenharmony_ci u16 sclass; 282562306a36Sopenharmony_ci struct genfs *genfs; 282662306a36Sopenharmony_ci struct ocontext *c; 282762306a36Sopenharmony_ci int cmp = 0; 282862306a36Sopenharmony_ci 282962306a36Sopenharmony_ci while (path[0] == '/' && path[1] == '/') 283062306a36Sopenharmony_ci path++; 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci sclass = unmap_class(&policy->map, orig_sclass); 283362306a36Sopenharmony_ci *sid = SECINITSID_UNLABELED; 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci for (genfs = policydb->genfs; genfs; genfs = genfs->next) { 283662306a36Sopenharmony_ci cmp = strcmp(fstype, genfs->fstype); 283762306a36Sopenharmony_ci if (cmp <= 0) 283862306a36Sopenharmony_ci break; 283962306a36Sopenharmony_ci } 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci if (!genfs || cmp) 284262306a36Sopenharmony_ci return -ENOENT; 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci for (c = genfs->head; c; c = c->next) { 284562306a36Sopenharmony_ci size_t len = strlen(c->u.name); 284662306a36Sopenharmony_ci if ((!c->v.sclass || sclass == c->v.sclass) && 284762306a36Sopenharmony_ci (strncmp(c->u.name, path, len) == 0)) 284862306a36Sopenharmony_ci break; 284962306a36Sopenharmony_ci } 285062306a36Sopenharmony_ci 285162306a36Sopenharmony_ci if (!c) 285262306a36Sopenharmony_ci return -ENOENT; 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci return ocontext_to_sid(sidtab, c, 0, sid); 285562306a36Sopenharmony_ci} 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_ci/** 285862306a36Sopenharmony_ci * security_genfs_sid - Obtain a SID for a file in a filesystem 285962306a36Sopenharmony_ci * @fstype: filesystem type 286062306a36Sopenharmony_ci * @path: path from root of mount 286162306a36Sopenharmony_ci * @orig_sclass: file security class 286262306a36Sopenharmony_ci * @sid: SID for path 286362306a36Sopenharmony_ci * 286462306a36Sopenharmony_ci * Acquire policy_rwlock before calling __security_genfs_sid() and release 286562306a36Sopenharmony_ci * it afterward. 286662306a36Sopenharmony_ci */ 286762306a36Sopenharmony_ciint security_genfs_sid(const char *fstype, 286862306a36Sopenharmony_ci const char *path, 286962306a36Sopenharmony_ci u16 orig_sclass, 287062306a36Sopenharmony_ci u32 *sid) 287162306a36Sopenharmony_ci{ 287262306a36Sopenharmony_ci struct selinux_policy *policy; 287362306a36Sopenharmony_ci int retval; 287462306a36Sopenharmony_ci 287562306a36Sopenharmony_ci if (!selinux_initialized()) { 287662306a36Sopenharmony_ci *sid = SECINITSID_UNLABELED; 287762306a36Sopenharmony_ci return 0; 287862306a36Sopenharmony_ci } 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_ci do { 288162306a36Sopenharmony_ci rcu_read_lock(); 288262306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 288362306a36Sopenharmony_ci retval = __security_genfs_sid(policy, fstype, path, 288462306a36Sopenharmony_ci orig_sclass, sid); 288562306a36Sopenharmony_ci rcu_read_unlock(); 288662306a36Sopenharmony_ci } while (retval == -ESTALE); 288762306a36Sopenharmony_ci return retval; 288862306a36Sopenharmony_ci} 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ciint selinux_policy_genfs_sid(struct selinux_policy *policy, 289162306a36Sopenharmony_ci const char *fstype, 289262306a36Sopenharmony_ci const char *path, 289362306a36Sopenharmony_ci u16 orig_sclass, 289462306a36Sopenharmony_ci u32 *sid) 289562306a36Sopenharmony_ci{ 289662306a36Sopenharmony_ci /* no lock required, policy is not yet accessible by other threads */ 289762306a36Sopenharmony_ci return __security_genfs_sid(policy, fstype, path, orig_sclass, sid); 289862306a36Sopenharmony_ci} 289962306a36Sopenharmony_ci 290062306a36Sopenharmony_ci/** 290162306a36Sopenharmony_ci * security_fs_use - Determine how to handle labeling for a filesystem. 290262306a36Sopenharmony_ci * @sb: superblock in question 290362306a36Sopenharmony_ci */ 290462306a36Sopenharmony_ciint security_fs_use(struct super_block *sb) 290562306a36Sopenharmony_ci{ 290662306a36Sopenharmony_ci struct selinux_policy *policy; 290762306a36Sopenharmony_ci struct policydb *policydb; 290862306a36Sopenharmony_ci struct sidtab *sidtab; 290962306a36Sopenharmony_ci int rc; 291062306a36Sopenharmony_ci struct ocontext *c; 291162306a36Sopenharmony_ci struct superblock_security_struct *sbsec = selinux_superblock(sb); 291262306a36Sopenharmony_ci const char *fstype = sb->s_type->name; 291362306a36Sopenharmony_ci 291462306a36Sopenharmony_ci if (!selinux_initialized()) { 291562306a36Sopenharmony_ci sbsec->behavior = SECURITY_FS_USE_NONE; 291662306a36Sopenharmony_ci sbsec->sid = SECINITSID_UNLABELED; 291762306a36Sopenharmony_ci return 0; 291862306a36Sopenharmony_ci } 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_ciretry: 292162306a36Sopenharmony_ci rcu_read_lock(); 292262306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 292362306a36Sopenharmony_ci policydb = &policy->policydb; 292462306a36Sopenharmony_ci sidtab = policy->sidtab; 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci c = policydb->ocontexts[OCON_FSUSE]; 292762306a36Sopenharmony_ci while (c) { 292862306a36Sopenharmony_ci if (strcmp(fstype, c->u.name) == 0) 292962306a36Sopenharmony_ci break; 293062306a36Sopenharmony_ci c = c->next; 293162306a36Sopenharmony_ci } 293262306a36Sopenharmony_ci 293362306a36Sopenharmony_ci if (c) { 293462306a36Sopenharmony_ci sbsec->behavior = c->v.behavior; 293562306a36Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid); 293662306a36Sopenharmony_ci if (rc == -ESTALE) { 293762306a36Sopenharmony_ci rcu_read_unlock(); 293862306a36Sopenharmony_ci goto retry; 293962306a36Sopenharmony_ci } 294062306a36Sopenharmony_ci if (rc) 294162306a36Sopenharmony_ci goto out; 294262306a36Sopenharmony_ci } else { 294362306a36Sopenharmony_ci rc = __security_genfs_sid(policy, fstype, "/", 294462306a36Sopenharmony_ci SECCLASS_DIR, &sbsec->sid); 294562306a36Sopenharmony_ci if (rc == -ESTALE) { 294662306a36Sopenharmony_ci rcu_read_unlock(); 294762306a36Sopenharmony_ci goto retry; 294862306a36Sopenharmony_ci } 294962306a36Sopenharmony_ci if (rc) { 295062306a36Sopenharmony_ci sbsec->behavior = SECURITY_FS_USE_NONE; 295162306a36Sopenharmony_ci rc = 0; 295262306a36Sopenharmony_ci } else { 295362306a36Sopenharmony_ci sbsec->behavior = SECURITY_FS_USE_GENFS; 295462306a36Sopenharmony_ci } 295562306a36Sopenharmony_ci } 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ciout: 295862306a36Sopenharmony_ci rcu_read_unlock(); 295962306a36Sopenharmony_ci return rc; 296062306a36Sopenharmony_ci} 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ciint security_get_bools(struct selinux_policy *policy, 296362306a36Sopenharmony_ci u32 *len, char ***names, int **values) 296462306a36Sopenharmony_ci{ 296562306a36Sopenharmony_ci struct policydb *policydb; 296662306a36Sopenharmony_ci u32 i; 296762306a36Sopenharmony_ci int rc; 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci policydb = &policy->policydb; 297062306a36Sopenharmony_ci 297162306a36Sopenharmony_ci *names = NULL; 297262306a36Sopenharmony_ci *values = NULL; 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci rc = 0; 297562306a36Sopenharmony_ci *len = policydb->p_bools.nprim; 297662306a36Sopenharmony_ci if (!*len) 297762306a36Sopenharmony_ci goto out; 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci rc = -ENOMEM; 298062306a36Sopenharmony_ci *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); 298162306a36Sopenharmony_ci if (!*names) 298262306a36Sopenharmony_ci goto err; 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_ci rc = -ENOMEM; 298562306a36Sopenharmony_ci *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); 298662306a36Sopenharmony_ci if (!*values) 298762306a36Sopenharmony_ci goto err; 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci for (i = 0; i < *len; i++) { 299062306a36Sopenharmony_ci (*values)[i] = policydb->bool_val_to_struct[i]->state; 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci rc = -ENOMEM; 299362306a36Sopenharmony_ci (*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i), 299462306a36Sopenharmony_ci GFP_ATOMIC); 299562306a36Sopenharmony_ci if (!(*names)[i]) 299662306a36Sopenharmony_ci goto err; 299762306a36Sopenharmony_ci } 299862306a36Sopenharmony_ci rc = 0; 299962306a36Sopenharmony_ciout: 300062306a36Sopenharmony_ci return rc; 300162306a36Sopenharmony_cierr: 300262306a36Sopenharmony_ci if (*names) { 300362306a36Sopenharmony_ci for (i = 0; i < *len; i++) 300462306a36Sopenharmony_ci kfree((*names)[i]); 300562306a36Sopenharmony_ci kfree(*names); 300662306a36Sopenharmony_ci } 300762306a36Sopenharmony_ci kfree(*values); 300862306a36Sopenharmony_ci *len = 0; 300962306a36Sopenharmony_ci *names = NULL; 301062306a36Sopenharmony_ci *values = NULL; 301162306a36Sopenharmony_ci goto out; 301262306a36Sopenharmony_ci} 301362306a36Sopenharmony_ci 301462306a36Sopenharmony_ci 301562306a36Sopenharmony_ciint security_set_bools(u32 len, int *values) 301662306a36Sopenharmony_ci{ 301762306a36Sopenharmony_ci struct selinux_state *state = &selinux_state; 301862306a36Sopenharmony_ci struct selinux_policy *newpolicy, *oldpolicy; 301962306a36Sopenharmony_ci int rc; 302062306a36Sopenharmony_ci u32 i, seqno = 0; 302162306a36Sopenharmony_ci 302262306a36Sopenharmony_ci if (!selinux_initialized()) 302362306a36Sopenharmony_ci return -EINVAL; 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_ci oldpolicy = rcu_dereference_protected(state->policy, 302662306a36Sopenharmony_ci lockdep_is_held(&state->policy_mutex)); 302762306a36Sopenharmony_ci 302862306a36Sopenharmony_ci /* Consistency check on number of booleans, should never fail */ 302962306a36Sopenharmony_ci if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim)) 303062306a36Sopenharmony_ci return -EINVAL; 303162306a36Sopenharmony_ci 303262306a36Sopenharmony_ci newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL); 303362306a36Sopenharmony_ci if (!newpolicy) 303462306a36Sopenharmony_ci return -ENOMEM; 303562306a36Sopenharmony_ci 303662306a36Sopenharmony_ci /* 303762306a36Sopenharmony_ci * Deep copy only the parts of the policydb that might be 303862306a36Sopenharmony_ci * modified as a result of changing booleans. 303962306a36Sopenharmony_ci */ 304062306a36Sopenharmony_ci rc = cond_policydb_dup(&newpolicy->policydb, &oldpolicy->policydb); 304162306a36Sopenharmony_ci if (rc) { 304262306a36Sopenharmony_ci kfree(newpolicy); 304362306a36Sopenharmony_ci return -ENOMEM; 304462306a36Sopenharmony_ci } 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci /* Update the boolean states in the copy */ 304762306a36Sopenharmony_ci for (i = 0; i < len; i++) { 304862306a36Sopenharmony_ci int new_state = !!values[i]; 304962306a36Sopenharmony_ci int old_state = newpolicy->policydb.bool_val_to_struct[i]->state; 305062306a36Sopenharmony_ci 305162306a36Sopenharmony_ci if (new_state != old_state) { 305262306a36Sopenharmony_ci audit_log(audit_context(), GFP_ATOMIC, 305362306a36Sopenharmony_ci AUDIT_MAC_CONFIG_CHANGE, 305462306a36Sopenharmony_ci "bool=%s val=%d old_val=%d auid=%u ses=%u", 305562306a36Sopenharmony_ci sym_name(&newpolicy->policydb, SYM_BOOLS, i), 305662306a36Sopenharmony_ci new_state, 305762306a36Sopenharmony_ci old_state, 305862306a36Sopenharmony_ci from_kuid(&init_user_ns, audit_get_loginuid(current)), 305962306a36Sopenharmony_ci audit_get_sessionid(current)); 306062306a36Sopenharmony_ci newpolicy->policydb.bool_val_to_struct[i]->state = new_state; 306162306a36Sopenharmony_ci } 306262306a36Sopenharmony_ci } 306362306a36Sopenharmony_ci 306462306a36Sopenharmony_ci /* Re-evaluate the conditional rules in the copy */ 306562306a36Sopenharmony_ci evaluate_cond_nodes(&newpolicy->policydb); 306662306a36Sopenharmony_ci 306762306a36Sopenharmony_ci /* Set latest granting seqno for new policy */ 306862306a36Sopenharmony_ci newpolicy->latest_granting = oldpolicy->latest_granting + 1; 306962306a36Sopenharmony_ci seqno = newpolicy->latest_granting; 307062306a36Sopenharmony_ci 307162306a36Sopenharmony_ci /* Install the new policy */ 307262306a36Sopenharmony_ci rcu_assign_pointer(state->policy, newpolicy); 307362306a36Sopenharmony_ci 307462306a36Sopenharmony_ci /* 307562306a36Sopenharmony_ci * Free the conditional portions of the old policydb 307662306a36Sopenharmony_ci * that were copied for the new policy, and the oldpolicy 307762306a36Sopenharmony_ci * structure itself but not what it references. 307862306a36Sopenharmony_ci */ 307962306a36Sopenharmony_ci synchronize_rcu(); 308062306a36Sopenharmony_ci selinux_policy_cond_free(oldpolicy); 308162306a36Sopenharmony_ci 308262306a36Sopenharmony_ci /* Notify others of the policy change */ 308362306a36Sopenharmony_ci selinux_notify_policy_change(seqno); 308462306a36Sopenharmony_ci return 0; 308562306a36Sopenharmony_ci} 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ciint security_get_bool_value(u32 index) 308862306a36Sopenharmony_ci{ 308962306a36Sopenharmony_ci struct selinux_policy *policy; 309062306a36Sopenharmony_ci struct policydb *policydb; 309162306a36Sopenharmony_ci int rc; 309262306a36Sopenharmony_ci u32 len; 309362306a36Sopenharmony_ci 309462306a36Sopenharmony_ci if (!selinux_initialized()) 309562306a36Sopenharmony_ci return 0; 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_ci rcu_read_lock(); 309862306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 309962306a36Sopenharmony_ci policydb = &policy->policydb; 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci rc = -EFAULT; 310262306a36Sopenharmony_ci len = policydb->p_bools.nprim; 310362306a36Sopenharmony_ci if (index >= len) 310462306a36Sopenharmony_ci goto out; 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci rc = policydb->bool_val_to_struct[index]->state; 310762306a36Sopenharmony_ciout: 310862306a36Sopenharmony_ci rcu_read_unlock(); 310962306a36Sopenharmony_ci return rc; 311062306a36Sopenharmony_ci} 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_cistatic int security_preserve_bools(struct selinux_policy *oldpolicy, 311362306a36Sopenharmony_ci struct selinux_policy *newpolicy) 311462306a36Sopenharmony_ci{ 311562306a36Sopenharmony_ci int rc, *bvalues = NULL; 311662306a36Sopenharmony_ci char **bnames = NULL; 311762306a36Sopenharmony_ci struct cond_bool_datum *booldatum; 311862306a36Sopenharmony_ci u32 i, nbools = 0; 311962306a36Sopenharmony_ci 312062306a36Sopenharmony_ci rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues); 312162306a36Sopenharmony_ci if (rc) 312262306a36Sopenharmony_ci goto out; 312362306a36Sopenharmony_ci for (i = 0; i < nbools; i++) { 312462306a36Sopenharmony_ci booldatum = symtab_search(&newpolicy->policydb.p_bools, 312562306a36Sopenharmony_ci bnames[i]); 312662306a36Sopenharmony_ci if (booldatum) 312762306a36Sopenharmony_ci booldatum->state = bvalues[i]; 312862306a36Sopenharmony_ci } 312962306a36Sopenharmony_ci evaluate_cond_nodes(&newpolicy->policydb); 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_ciout: 313262306a36Sopenharmony_ci if (bnames) { 313362306a36Sopenharmony_ci for (i = 0; i < nbools; i++) 313462306a36Sopenharmony_ci kfree(bnames[i]); 313562306a36Sopenharmony_ci } 313662306a36Sopenharmony_ci kfree(bnames); 313762306a36Sopenharmony_ci kfree(bvalues); 313862306a36Sopenharmony_ci return rc; 313962306a36Sopenharmony_ci} 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ci/* 314262306a36Sopenharmony_ci * security_sid_mls_copy() - computes a new sid based on the given 314362306a36Sopenharmony_ci * sid and the mls portion of mls_sid. 314462306a36Sopenharmony_ci */ 314562306a36Sopenharmony_ciint security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) 314662306a36Sopenharmony_ci{ 314762306a36Sopenharmony_ci struct selinux_policy *policy; 314862306a36Sopenharmony_ci struct policydb *policydb; 314962306a36Sopenharmony_ci struct sidtab *sidtab; 315062306a36Sopenharmony_ci struct context *context1; 315162306a36Sopenharmony_ci struct context *context2; 315262306a36Sopenharmony_ci struct context newcon; 315362306a36Sopenharmony_ci char *s; 315462306a36Sopenharmony_ci u32 len; 315562306a36Sopenharmony_ci int rc; 315662306a36Sopenharmony_ci 315762306a36Sopenharmony_ci if (!selinux_initialized()) { 315862306a36Sopenharmony_ci *new_sid = sid; 315962306a36Sopenharmony_ci return 0; 316062306a36Sopenharmony_ci } 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ciretry: 316362306a36Sopenharmony_ci rc = 0; 316462306a36Sopenharmony_ci context_init(&newcon); 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci rcu_read_lock(); 316762306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 316862306a36Sopenharmony_ci policydb = &policy->policydb; 316962306a36Sopenharmony_ci sidtab = policy->sidtab; 317062306a36Sopenharmony_ci 317162306a36Sopenharmony_ci if (!policydb->mls_enabled) { 317262306a36Sopenharmony_ci *new_sid = sid; 317362306a36Sopenharmony_ci goto out_unlock; 317462306a36Sopenharmony_ci } 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci rc = -EINVAL; 317762306a36Sopenharmony_ci context1 = sidtab_search(sidtab, sid); 317862306a36Sopenharmony_ci if (!context1) { 317962306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 318062306a36Sopenharmony_ci __func__, sid); 318162306a36Sopenharmony_ci goto out_unlock; 318262306a36Sopenharmony_ci } 318362306a36Sopenharmony_ci 318462306a36Sopenharmony_ci rc = -EINVAL; 318562306a36Sopenharmony_ci context2 = sidtab_search(sidtab, mls_sid); 318662306a36Sopenharmony_ci if (!context2) { 318762306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 318862306a36Sopenharmony_ci __func__, mls_sid); 318962306a36Sopenharmony_ci goto out_unlock; 319062306a36Sopenharmony_ci } 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_ci newcon.user = context1->user; 319362306a36Sopenharmony_ci newcon.role = context1->role; 319462306a36Sopenharmony_ci newcon.type = context1->type; 319562306a36Sopenharmony_ci rc = mls_context_cpy(&newcon, context2); 319662306a36Sopenharmony_ci if (rc) 319762306a36Sopenharmony_ci goto out_unlock; 319862306a36Sopenharmony_ci 319962306a36Sopenharmony_ci /* Check the validity of the new context. */ 320062306a36Sopenharmony_ci if (!policydb_context_isvalid(policydb, &newcon)) { 320162306a36Sopenharmony_ci rc = convert_context_handle_invalid_context(policydb, 320262306a36Sopenharmony_ci &newcon); 320362306a36Sopenharmony_ci if (rc) { 320462306a36Sopenharmony_ci if (!context_struct_to_string(policydb, &newcon, &s, 320562306a36Sopenharmony_ci &len)) { 320662306a36Sopenharmony_ci struct audit_buffer *ab; 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_ci ab = audit_log_start(audit_context(), 320962306a36Sopenharmony_ci GFP_ATOMIC, 321062306a36Sopenharmony_ci AUDIT_SELINUX_ERR); 321162306a36Sopenharmony_ci audit_log_format(ab, 321262306a36Sopenharmony_ci "op=security_sid_mls_copy invalid_context="); 321362306a36Sopenharmony_ci /* don't record NUL with untrusted strings */ 321462306a36Sopenharmony_ci audit_log_n_untrustedstring(ab, s, len - 1); 321562306a36Sopenharmony_ci audit_log_end(ab); 321662306a36Sopenharmony_ci kfree(s); 321762306a36Sopenharmony_ci } 321862306a36Sopenharmony_ci goto out_unlock; 321962306a36Sopenharmony_ci } 322062306a36Sopenharmony_ci } 322162306a36Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &newcon, new_sid); 322262306a36Sopenharmony_ci if (rc == -ESTALE) { 322362306a36Sopenharmony_ci rcu_read_unlock(); 322462306a36Sopenharmony_ci context_destroy(&newcon); 322562306a36Sopenharmony_ci goto retry; 322662306a36Sopenharmony_ci } 322762306a36Sopenharmony_ciout_unlock: 322862306a36Sopenharmony_ci rcu_read_unlock(); 322962306a36Sopenharmony_ci context_destroy(&newcon); 323062306a36Sopenharmony_ci return rc; 323162306a36Sopenharmony_ci} 323262306a36Sopenharmony_ci 323362306a36Sopenharmony_ci/** 323462306a36Sopenharmony_ci * security_net_peersid_resolve - Compare and resolve two network peer SIDs 323562306a36Sopenharmony_ci * @nlbl_sid: NetLabel SID 323662306a36Sopenharmony_ci * @nlbl_type: NetLabel labeling protocol type 323762306a36Sopenharmony_ci * @xfrm_sid: XFRM SID 323862306a36Sopenharmony_ci * @peer_sid: network peer sid 323962306a36Sopenharmony_ci * 324062306a36Sopenharmony_ci * Description: 324162306a36Sopenharmony_ci * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be 324262306a36Sopenharmony_ci * resolved into a single SID it is returned via @peer_sid and the function 324362306a36Sopenharmony_ci * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function 324462306a36Sopenharmony_ci * returns a negative value. A table summarizing the behavior is below: 324562306a36Sopenharmony_ci * 324662306a36Sopenharmony_ci * | function return | @sid 324762306a36Sopenharmony_ci * ------------------------------+-----------------+----------------- 324862306a36Sopenharmony_ci * no peer labels | 0 | SECSID_NULL 324962306a36Sopenharmony_ci * single peer label | 0 | <peer_label> 325062306a36Sopenharmony_ci * multiple, consistent labels | 0 | <peer_label> 325162306a36Sopenharmony_ci * multiple, inconsistent labels | -<errno> | SECSID_NULL 325262306a36Sopenharmony_ci * 325362306a36Sopenharmony_ci */ 325462306a36Sopenharmony_ciint security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, 325562306a36Sopenharmony_ci u32 xfrm_sid, 325662306a36Sopenharmony_ci u32 *peer_sid) 325762306a36Sopenharmony_ci{ 325862306a36Sopenharmony_ci struct selinux_policy *policy; 325962306a36Sopenharmony_ci struct policydb *policydb; 326062306a36Sopenharmony_ci struct sidtab *sidtab; 326162306a36Sopenharmony_ci int rc; 326262306a36Sopenharmony_ci struct context *nlbl_ctx; 326362306a36Sopenharmony_ci struct context *xfrm_ctx; 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci *peer_sid = SECSID_NULL; 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_ci /* handle the common (which also happens to be the set of easy) cases 326862306a36Sopenharmony_ci * right away, these two if statements catch everything involving a 326962306a36Sopenharmony_ci * single or absent peer SID/label */ 327062306a36Sopenharmony_ci if (xfrm_sid == SECSID_NULL) { 327162306a36Sopenharmony_ci *peer_sid = nlbl_sid; 327262306a36Sopenharmony_ci return 0; 327362306a36Sopenharmony_ci } 327462306a36Sopenharmony_ci /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label 327562306a36Sopenharmony_ci * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label 327662306a36Sopenharmony_ci * is present */ 327762306a36Sopenharmony_ci if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) { 327862306a36Sopenharmony_ci *peer_sid = xfrm_sid; 327962306a36Sopenharmony_ci return 0; 328062306a36Sopenharmony_ci } 328162306a36Sopenharmony_ci 328262306a36Sopenharmony_ci if (!selinux_initialized()) 328362306a36Sopenharmony_ci return 0; 328462306a36Sopenharmony_ci 328562306a36Sopenharmony_ci rcu_read_lock(); 328662306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 328762306a36Sopenharmony_ci policydb = &policy->policydb; 328862306a36Sopenharmony_ci sidtab = policy->sidtab; 328962306a36Sopenharmony_ci 329062306a36Sopenharmony_ci /* 329162306a36Sopenharmony_ci * We don't need to check initialized here since the only way both 329262306a36Sopenharmony_ci * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the 329362306a36Sopenharmony_ci * security server was initialized and state->initialized was true. 329462306a36Sopenharmony_ci */ 329562306a36Sopenharmony_ci if (!policydb->mls_enabled) { 329662306a36Sopenharmony_ci rc = 0; 329762306a36Sopenharmony_ci goto out; 329862306a36Sopenharmony_ci } 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci rc = -EINVAL; 330162306a36Sopenharmony_ci nlbl_ctx = sidtab_search(sidtab, nlbl_sid); 330262306a36Sopenharmony_ci if (!nlbl_ctx) { 330362306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 330462306a36Sopenharmony_ci __func__, nlbl_sid); 330562306a36Sopenharmony_ci goto out; 330662306a36Sopenharmony_ci } 330762306a36Sopenharmony_ci rc = -EINVAL; 330862306a36Sopenharmony_ci xfrm_ctx = sidtab_search(sidtab, xfrm_sid); 330962306a36Sopenharmony_ci if (!xfrm_ctx) { 331062306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 331162306a36Sopenharmony_ci __func__, xfrm_sid); 331262306a36Sopenharmony_ci goto out; 331362306a36Sopenharmony_ci } 331462306a36Sopenharmony_ci rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); 331562306a36Sopenharmony_ci if (rc) 331662306a36Sopenharmony_ci goto out; 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci /* at present NetLabel SIDs/labels really only carry MLS 331962306a36Sopenharmony_ci * information so if the MLS portion of the NetLabel SID 332062306a36Sopenharmony_ci * matches the MLS portion of the labeled XFRM SID/label 332162306a36Sopenharmony_ci * then pass along the XFRM SID as it is the most 332262306a36Sopenharmony_ci * expressive */ 332362306a36Sopenharmony_ci *peer_sid = xfrm_sid; 332462306a36Sopenharmony_ciout: 332562306a36Sopenharmony_ci rcu_read_unlock(); 332662306a36Sopenharmony_ci return rc; 332762306a36Sopenharmony_ci} 332862306a36Sopenharmony_ci 332962306a36Sopenharmony_cistatic int get_classes_callback(void *k, void *d, void *args) 333062306a36Sopenharmony_ci{ 333162306a36Sopenharmony_ci struct class_datum *datum = d; 333262306a36Sopenharmony_ci char *name = k, **classes = args; 333362306a36Sopenharmony_ci u32 value = datum->value - 1; 333462306a36Sopenharmony_ci 333562306a36Sopenharmony_ci classes[value] = kstrdup(name, GFP_ATOMIC); 333662306a36Sopenharmony_ci if (!classes[value]) 333762306a36Sopenharmony_ci return -ENOMEM; 333862306a36Sopenharmony_ci 333962306a36Sopenharmony_ci return 0; 334062306a36Sopenharmony_ci} 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ciint security_get_classes(struct selinux_policy *policy, 334362306a36Sopenharmony_ci char ***classes, u32 *nclasses) 334462306a36Sopenharmony_ci{ 334562306a36Sopenharmony_ci struct policydb *policydb; 334662306a36Sopenharmony_ci int rc; 334762306a36Sopenharmony_ci 334862306a36Sopenharmony_ci policydb = &policy->policydb; 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci rc = -ENOMEM; 335162306a36Sopenharmony_ci *nclasses = policydb->p_classes.nprim; 335262306a36Sopenharmony_ci *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); 335362306a36Sopenharmony_ci if (!*classes) 335462306a36Sopenharmony_ci goto out; 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci rc = hashtab_map(&policydb->p_classes.table, get_classes_callback, 335762306a36Sopenharmony_ci *classes); 335862306a36Sopenharmony_ci if (rc) { 335962306a36Sopenharmony_ci u32 i; 336062306a36Sopenharmony_ci 336162306a36Sopenharmony_ci for (i = 0; i < *nclasses; i++) 336262306a36Sopenharmony_ci kfree((*classes)[i]); 336362306a36Sopenharmony_ci kfree(*classes); 336462306a36Sopenharmony_ci } 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ciout: 336762306a36Sopenharmony_ci return rc; 336862306a36Sopenharmony_ci} 336962306a36Sopenharmony_ci 337062306a36Sopenharmony_cistatic int get_permissions_callback(void *k, void *d, void *args) 337162306a36Sopenharmony_ci{ 337262306a36Sopenharmony_ci struct perm_datum *datum = d; 337362306a36Sopenharmony_ci char *name = k, **perms = args; 337462306a36Sopenharmony_ci u32 value = datum->value - 1; 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_ci perms[value] = kstrdup(name, GFP_ATOMIC); 337762306a36Sopenharmony_ci if (!perms[value]) 337862306a36Sopenharmony_ci return -ENOMEM; 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci return 0; 338162306a36Sopenharmony_ci} 338262306a36Sopenharmony_ci 338362306a36Sopenharmony_ciint security_get_permissions(struct selinux_policy *policy, 338462306a36Sopenharmony_ci const char *class, char ***perms, u32 *nperms) 338562306a36Sopenharmony_ci{ 338662306a36Sopenharmony_ci struct policydb *policydb; 338762306a36Sopenharmony_ci u32 i; 338862306a36Sopenharmony_ci int rc; 338962306a36Sopenharmony_ci struct class_datum *match; 339062306a36Sopenharmony_ci 339162306a36Sopenharmony_ci policydb = &policy->policydb; 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_ci rc = -EINVAL; 339462306a36Sopenharmony_ci match = symtab_search(&policydb->p_classes, class); 339562306a36Sopenharmony_ci if (!match) { 339662306a36Sopenharmony_ci pr_err("SELinux: %s: unrecognized class %s\n", 339762306a36Sopenharmony_ci __func__, class); 339862306a36Sopenharmony_ci goto out; 339962306a36Sopenharmony_ci } 340062306a36Sopenharmony_ci 340162306a36Sopenharmony_ci rc = -ENOMEM; 340262306a36Sopenharmony_ci *nperms = match->permissions.nprim; 340362306a36Sopenharmony_ci *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); 340462306a36Sopenharmony_ci if (!*perms) 340562306a36Sopenharmony_ci goto out; 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci if (match->comdatum) { 340862306a36Sopenharmony_ci rc = hashtab_map(&match->comdatum->permissions.table, 340962306a36Sopenharmony_ci get_permissions_callback, *perms); 341062306a36Sopenharmony_ci if (rc) 341162306a36Sopenharmony_ci goto err; 341262306a36Sopenharmony_ci } 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci rc = hashtab_map(&match->permissions.table, get_permissions_callback, 341562306a36Sopenharmony_ci *perms); 341662306a36Sopenharmony_ci if (rc) 341762306a36Sopenharmony_ci goto err; 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_ciout: 342062306a36Sopenharmony_ci return rc; 342162306a36Sopenharmony_ci 342262306a36Sopenharmony_cierr: 342362306a36Sopenharmony_ci for (i = 0; i < *nperms; i++) 342462306a36Sopenharmony_ci kfree((*perms)[i]); 342562306a36Sopenharmony_ci kfree(*perms); 342662306a36Sopenharmony_ci return rc; 342762306a36Sopenharmony_ci} 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ciint security_get_reject_unknown(void) 343062306a36Sopenharmony_ci{ 343162306a36Sopenharmony_ci struct selinux_policy *policy; 343262306a36Sopenharmony_ci int value; 343362306a36Sopenharmony_ci 343462306a36Sopenharmony_ci if (!selinux_initialized()) 343562306a36Sopenharmony_ci return 0; 343662306a36Sopenharmony_ci 343762306a36Sopenharmony_ci rcu_read_lock(); 343862306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 343962306a36Sopenharmony_ci value = policy->policydb.reject_unknown; 344062306a36Sopenharmony_ci rcu_read_unlock(); 344162306a36Sopenharmony_ci return value; 344262306a36Sopenharmony_ci} 344362306a36Sopenharmony_ci 344462306a36Sopenharmony_ciint security_get_allow_unknown(void) 344562306a36Sopenharmony_ci{ 344662306a36Sopenharmony_ci struct selinux_policy *policy; 344762306a36Sopenharmony_ci int value; 344862306a36Sopenharmony_ci 344962306a36Sopenharmony_ci if (!selinux_initialized()) 345062306a36Sopenharmony_ci return 0; 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_ci rcu_read_lock(); 345362306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 345462306a36Sopenharmony_ci value = policy->policydb.allow_unknown; 345562306a36Sopenharmony_ci rcu_read_unlock(); 345662306a36Sopenharmony_ci return value; 345762306a36Sopenharmony_ci} 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_ci/** 346062306a36Sopenharmony_ci * security_policycap_supported - Check for a specific policy capability 346162306a36Sopenharmony_ci * @req_cap: capability 346262306a36Sopenharmony_ci * 346362306a36Sopenharmony_ci * Description: 346462306a36Sopenharmony_ci * This function queries the currently loaded policy to see if it supports the 346562306a36Sopenharmony_ci * capability specified by @req_cap. Returns true (1) if the capability is 346662306a36Sopenharmony_ci * supported, false (0) if it isn't supported. 346762306a36Sopenharmony_ci * 346862306a36Sopenharmony_ci */ 346962306a36Sopenharmony_ciint security_policycap_supported(unsigned int req_cap) 347062306a36Sopenharmony_ci{ 347162306a36Sopenharmony_ci struct selinux_policy *policy; 347262306a36Sopenharmony_ci int rc; 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci if (!selinux_initialized()) 347562306a36Sopenharmony_ci return 0; 347662306a36Sopenharmony_ci 347762306a36Sopenharmony_ci rcu_read_lock(); 347862306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 347962306a36Sopenharmony_ci rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap); 348062306a36Sopenharmony_ci rcu_read_unlock(); 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci return rc; 348362306a36Sopenharmony_ci} 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_cistruct selinux_audit_rule { 348662306a36Sopenharmony_ci u32 au_seqno; 348762306a36Sopenharmony_ci struct context au_ctxt; 348862306a36Sopenharmony_ci}; 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_civoid selinux_audit_rule_free(void *vrule) 349162306a36Sopenharmony_ci{ 349262306a36Sopenharmony_ci struct selinux_audit_rule *rule = vrule; 349362306a36Sopenharmony_ci 349462306a36Sopenharmony_ci if (rule) { 349562306a36Sopenharmony_ci context_destroy(&rule->au_ctxt); 349662306a36Sopenharmony_ci kfree(rule); 349762306a36Sopenharmony_ci } 349862306a36Sopenharmony_ci} 349962306a36Sopenharmony_ci 350062306a36Sopenharmony_ciint selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) 350162306a36Sopenharmony_ci{ 350262306a36Sopenharmony_ci struct selinux_state *state = &selinux_state; 350362306a36Sopenharmony_ci struct selinux_policy *policy; 350462306a36Sopenharmony_ci struct policydb *policydb; 350562306a36Sopenharmony_ci struct selinux_audit_rule *tmprule; 350662306a36Sopenharmony_ci struct role_datum *roledatum; 350762306a36Sopenharmony_ci struct type_datum *typedatum; 350862306a36Sopenharmony_ci struct user_datum *userdatum; 350962306a36Sopenharmony_ci struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule; 351062306a36Sopenharmony_ci int rc = 0; 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci *rule = NULL; 351362306a36Sopenharmony_ci 351462306a36Sopenharmony_ci if (!selinux_initialized()) 351562306a36Sopenharmony_ci return -EOPNOTSUPP; 351662306a36Sopenharmony_ci 351762306a36Sopenharmony_ci switch (field) { 351862306a36Sopenharmony_ci case AUDIT_SUBJ_USER: 351962306a36Sopenharmony_ci case AUDIT_SUBJ_ROLE: 352062306a36Sopenharmony_ci case AUDIT_SUBJ_TYPE: 352162306a36Sopenharmony_ci case AUDIT_OBJ_USER: 352262306a36Sopenharmony_ci case AUDIT_OBJ_ROLE: 352362306a36Sopenharmony_ci case AUDIT_OBJ_TYPE: 352462306a36Sopenharmony_ci /* only 'equals' and 'not equals' fit user, role, and type */ 352562306a36Sopenharmony_ci if (op != Audit_equal && op != Audit_not_equal) 352662306a36Sopenharmony_ci return -EINVAL; 352762306a36Sopenharmony_ci break; 352862306a36Sopenharmony_ci case AUDIT_SUBJ_SEN: 352962306a36Sopenharmony_ci case AUDIT_SUBJ_CLR: 353062306a36Sopenharmony_ci case AUDIT_OBJ_LEV_LOW: 353162306a36Sopenharmony_ci case AUDIT_OBJ_LEV_HIGH: 353262306a36Sopenharmony_ci /* we do not allow a range, indicated by the presence of '-' */ 353362306a36Sopenharmony_ci if (strchr(rulestr, '-')) 353462306a36Sopenharmony_ci return -EINVAL; 353562306a36Sopenharmony_ci break; 353662306a36Sopenharmony_ci default: 353762306a36Sopenharmony_ci /* only the above fields are valid */ 353862306a36Sopenharmony_ci return -EINVAL; 353962306a36Sopenharmony_ci } 354062306a36Sopenharmony_ci 354162306a36Sopenharmony_ci tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL); 354262306a36Sopenharmony_ci if (!tmprule) 354362306a36Sopenharmony_ci return -ENOMEM; 354462306a36Sopenharmony_ci context_init(&tmprule->au_ctxt); 354562306a36Sopenharmony_ci 354662306a36Sopenharmony_ci rcu_read_lock(); 354762306a36Sopenharmony_ci policy = rcu_dereference(state->policy); 354862306a36Sopenharmony_ci policydb = &policy->policydb; 354962306a36Sopenharmony_ci tmprule->au_seqno = policy->latest_granting; 355062306a36Sopenharmony_ci switch (field) { 355162306a36Sopenharmony_ci case AUDIT_SUBJ_USER: 355262306a36Sopenharmony_ci case AUDIT_OBJ_USER: 355362306a36Sopenharmony_ci userdatum = symtab_search(&policydb->p_users, rulestr); 355462306a36Sopenharmony_ci if (!userdatum) { 355562306a36Sopenharmony_ci rc = -EINVAL; 355662306a36Sopenharmony_ci goto err; 355762306a36Sopenharmony_ci } 355862306a36Sopenharmony_ci tmprule->au_ctxt.user = userdatum->value; 355962306a36Sopenharmony_ci break; 356062306a36Sopenharmony_ci case AUDIT_SUBJ_ROLE: 356162306a36Sopenharmony_ci case AUDIT_OBJ_ROLE: 356262306a36Sopenharmony_ci roledatum = symtab_search(&policydb->p_roles, rulestr); 356362306a36Sopenharmony_ci if (!roledatum) { 356462306a36Sopenharmony_ci rc = -EINVAL; 356562306a36Sopenharmony_ci goto err; 356662306a36Sopenharmony_ci } 356762306a36Sopenharmony_ci tmprule->au_ctxt.role = roledatum->value; 356862306a36Sopenharmony_ci break; 356962306a36Sopenharmony_ci case AUDIT_SUBJ_TYPE: 357062306a36Sopenharmony_ci case AUDIT_OBJ_TYPE: 357162306a36Sopenharmony_ci typedatum = symtab_search(&policydb->p_types, rulestr); 357262306a36Sopenharmony_ci if (!typedatum) { 357362306a36Sopenharmony_ci rc = -EINVAL; 357462306a36Sopenharmony_ci goto err; 357562306a36Sopenharmony_ci } 357662306a36Sopenharmony_ci tmprule->au_ctxt.type = typedatum->value; 357762306a36Sopenharmony_ci break; 357862306a36Sopenharmony_ci case AUDIT_SUBJ_SEN: 357962306a36Sopenharmony_ci case AUDIT_SUBJ_CLR: 358062306a36Sopenharmony_ci case AUDIT_OBJ_LEV_LOW: 358162306a36Sopenharmony_ci case AUDIT_OBJ_LEV_HIGH: 358262306a36Sopenharmony_ci rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt, 358362306a36Sopenharmony_ci GFP_ATOMIC); 358462306a36Sopenharmony_ci if (rc) 358562306a36Sopenharmony_ci goto err; 358662306a36Sopenharmony_ci break; 358762306a36Sopenharmony_ci } 358862306a36Sopenharmony_ci rcu_read_unlock(); 358962306a36Sopenharmony_ci 359062306a36Sopenharmony_ci *rule = tmprule; 359162306a36Sopenharmony_ci return 0; 359262306a36Sopenharmony_ci 359362306a36Sopenharmony_cierr: 359462306a36Sopenharmony_ci rcu_read_unlock(); 359562306a36Sopenharmony_ci selinux_audit_rule_free(tmprule); 359662306a36Sopenharmony_ci *rule = NULL; 359762306a36Sopenharmony_ci return rc; 359862306a36Sopenharmony_ci} 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci/* Check to see if the rule contains any selinux fields */ 360162306a36Sopenharmony_ciint selinux_audit_rule_known(struct audit_krule *rule) 360262306a36Sopenharmony_ci{ 360362306a36Sopenharmony_ci u32 i; 360462306a36Sopenharmony_ci 360562306a36Sopenharmony_ci for (i = 0; i < rule->field_count; i++) { 360662306a36Sopenharmony_ci struct audit_field *f = &rule->fields[i]; 360762306a36Sopenharmony_ci switch (f->type) { 360862306a36Sopenharmony_ci case AUDIT_SUBJ_USER: 360962306a36Sopenharmony_ci case AUDIT_SUBJ_ROLE: 361062306a36Sopenharmony_ci case AUDIT_SUBJ_TYPE: 361162306a36Sopenharmony_ci case AUDIT_SUBJ_SEN: 361262306a36Sopenharmony_ci case AUDIT_SUBJ_CLR: 361362306a36Sopenharmony_ci case AUDIT_OBJ_USER: 361462306a36Sopenharmony_ci case AUDIT_OBJ_ROLE: 361562306a36Sopenharmony_ci case AUDIT_OBJ_TYPE: 361662306a36Sopenharmony_ci case AUDIT_OBJ_LEV_LOW: 361762306a36Sopenharmony_ci case AUDIT_OBJ_LEV_HIGH: 361862306a36Sopenharmony_ci return 1; 361962306a36Sopenharmony_ci } 362062306a36Sopenharmony_ci } 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci return 0; 362362306a36Sopenharmony_ci} 362462306a36Sopenharmony_ci 362562306a36Sopenharmony_ciint selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) 362662306a36Sopenharmony_ci{ 362762306a36Sopenharmony_ci struct selinux_state *state = &selinux_state; 362862306a36Sopenharmony_ci struct selinux_policy *policy; 362962306a36Sopenharmony_ci struct context *ctxt; 363062306a36Sopenharmony_ci struct mls_level *level; 363162306a36Sopenharmony_ci struct selinux_audit_rule *rule = vrule; 363262306a36Sopenharmony_ci int match = 0; 363362306a36Sopenharmony_ci 363462306a36Sopenharmony_ci if (unlikely(!rule)) { 363562306a36Sopenharmony_ci WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n"); 363662306a36Sopenharmony_ci return -ENOENT; 363762306a36Sopenharmony_ci } 363862306a36Sopenharmony_ci 363962306a36Sopenharmony_ci if (!selinux_initialized()) 364062306a36Sopenharmony_ci return 0; 364162306a36Sopenharmony_ci 364262306a36Sopenharmony_ci rcu_read_lock(); 364362306a36Sopenharmony_ci 364462306a36Sopenharmony_ci policy = rcu_dereference(state->policy); 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_ci if (rule->au_seqno < policy->latest_granting) { 364762306a36Sopenharmony_ci match = -ESTALE; 364862306a36Sopenharmony_ci goto out; 364962306a36Sopenharmony_ci } 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci ctxt = sidtab_search(policy->sidtab, sid); 365262306a36Sopenharmony_ci if (unlikely(!ctxt)) { 365362306a36Sopenharmony_ci WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", 365462306a36Sopenharmony_ci sid); 365562306a36Sopenharmony_ci match = -ENOENT; 365662306a36Sopenharmony_ci goto out; 365762306a36Sopenharmony_ci } 365862306a36Sopenharmony_ci 365962306a36Sopenharmony_ci /* a field/op pair that is not caught here will simply fall through 366062306a36Sopenharmony_ci without a match */ 366162306a36Sopenharmony_ci switch (field) { 366262306a36Sopenharmony_ci case AUDIT_SUBJ_USER: 366362306a36Sopenharmony_ci case AUDIT_OBJ_USER: 366462306a36Sopenharmony_ci switch (op) { 366562306a36Sopenharmony_ci case Audit_equal: 366662306a36Sopenharmony_ci match = (ctxt->user == rule->au_ctxt.user); 366762306a36Sopenharmony_ci break; 366862306a36Sopenharmony_ci case Audit_not_equal: 366962306a36Sopenharmony_ci match = (ctxt->user != rule->au_ctxt.user); 367062306a36Sopenharmony_ci break; 367162306a36Sopenharmony_ci } 367262306a36Sopenharmony_ci break; 367362306a36Sopenharmony_ci case AUDIT_SUBJ_ROLE: 367462306a36Sopenharmony_ci case AUDIT_OBJ_ROLE: 367562306a36Sopenharmony_ci switch (op) { 367662306a36Sopenharmony_ci case Audit_equal: 367762306a36Sopenharmony_ci match = (ctxt->role == rule->au_ctxt.role); 367862306a36Sopenharmony_ci break; 367962306a36Sopenharmony_ci case Audit_not_equal: 368062306a36Sopenharmony_ci match = (ctxt->role != rule->au_ctxt.role); 368162306a36Sopenharmony_ci break; 368262306a36Sopenharmony_ci } 368362306a36Sopenharmony_ci break; 368462306a36Sopenharmony_ci case AUDIT_SUBJ_TYPE: 368562306a36Sopenharmony_ci case AUDIT_OBJ_TYPE: 368662306a36Sopenharmony_ci switch (op) { 368762306a36Sopenharmony_ci case Audit_equal: 368862306a36Sopenharmony_ci match = (ctxt->type == rule->au_ctxt.type); 368962306a36Sopenharmony_ci break; 369062306a36Sopenharmony_ci case Audit_not_equal: 369162306a36Sopenharmony_ci match = (ctxt->type != rule->au_ctxt.type); 369262306a36Sopenharmony_ci break; 369362306a36Sopenharmony_ci } 369462306a36Sopenharmony_ci break; 369562306a36Sopenharmony_ci case AUDIT_SUBJ_SEN: 369662306a36Sopenharmony_ci case AUDIT_SUBJ_CLR: 369762306a36Sopenharmony_ci case AUDIT_OBJ_LEV_LOW: 369862306a36Sopenharmony_ci case AUDIT_OBJ_LEV_HIGH: 369962306a36Sopenharmony_ci level = ((field == AUDIT_SUBJ_SEN || 370062306a36Sopenharmony_ci field == AUDIT_OBJ_LEV_LOW) ? 370162306a36Sopenharmony_ci &ctxt->range.level[0] : &ctxt->range.level[1]); 370262306a36Sopenharmony_ci switch (op) { 370362306a36Sopenharmony_ci case Audit_equal: 370462306a36Sopenharmony_ci match = mls_level_eq(&rule->au_ctxt.range.level[0], 370562306a36Sopenharmony_ci level); 370662306a36Sopenharmony_ci break; 370762306a36Sopenharmony_ci case Audit_not_equal: 370862306a36Sopenharmony_ci match = !mls_level_eq(&rule->au_ctxt.range.level[0], 370962306a36Sopenharmony_ci level); 371062306a36Sopenharmony_ci break; 371162306a36Sopenharmony_ci case Audit_lt: 371262306a36Sopenharmony_ci match = (mls_level_dom(&rule->au_ctxt.range.level[0], 371362306a36Sopenharmony_ci level) && 371462306a36Sopenharmony_ci !mls_level_eq(&rule->au_ctxt.range.level[0], 371562306a36Sopenharmony_ci level)); 371662306a36Sopenharmony_ci break; 371762306a36Sopenharmony_ci case Audit_le: 371862306a36Sopenharmony_ci match = mls_level_dom(&rule->au_ctxt.range.level[0], 371962306a36Sopenharmony_ci level); 372062306a36Sopenharmony_ci break; 372162306a36Sopenharmony_ci case Audit_gt: 372262306a36Sopenharmony_ci match = (mls_level_dom(level, 372362306a36Sopenharmony_ci &rule->au_ctxt.range.level[0]) && 372462306a36Sopenharmony_ci !mls_level_eq(level, 372562306a36Sopenharmony_ci &rule->au_ctxt.range.level[0])); 372662306a36Sopenharmony_ci break; 372762306a36Sopenharmony_ci case Audit_ge: 372862306a36Sopenharmony_ci match = mls_level_dom(level, 372962306a36Sopenharmony_ci &rule->au_ctxt.range.level[0]); 373062306a36Sopenharmony_ci break; 373162306a36Sopenharmony_ci } 373262306a36Sopenharmony_ci } 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_ciout: 373562306a36Sopenharmony_ci rcu_read_unlock(); 373662306a36Sopenharmony_ci return match; 373762306a36Sopenharmony_ci} 373862306a36Sopenharmony_ci 373962306a36Sopenharmony_cistatic int aurule_avc_callback(u32 event) 374062306a36Sopenharmony_ci{ 374162306a36Sopenharmony_ci if (event == AVC_CALLBACK_RESET) 374262306a36Sopenharmony_ci return audit_update_lsm_rules(); 374362306a36Sopenharmony_ci return 0; 374462306a36Sopenharmony_ci} 374562306a36Sopenharmony_ci 374662306a36Sopenharmony_cistatic int __init aurule_init(void) 374762306a36Sopenharmony_ci{ 374862306a36Sopenharmony_ci int err; 374962306a36Sopenharmony_ci 375062306a36Sopenharmony_ci err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET); 375162306a36Sopenharmony_ci if (err) 375262306a36Sopenharmony_ci panic("avc_add_callback() failed, error %d\n", err); 375362306a36Sopenharmony_ci 375462306a36Sopenharmony_ci return err; 375562306a36Sopenharmony_ci} 375662306a36Sopenharmony_ci__initcall(aurule_init); 375762306a36Sopenharmony_ci 375862306a36Sopenharmony_ci#ifdef CONFIG_NETLABEL 375962306a36Sopenharmony_ci/** 376062306a36Sopenharmony_ci * security_netlbl_cache_add - Add an entry to the NetLabel cache 376162306a36Sopenharmony_ci * @secattr: the NetLabel packet security attributes 376262306a36Sopenharmony_ci * @sid: the SELinux SID 376362306a36Sopenharmony_ci * 376462306a36Sopenharmony_ci * Description: 376562306a36Sopenharmony_ci * Attempt to cache the context in @ctx, which was derived from the packet in 376662306a36Sopenharmony_ci * @skb, in the NetLabel subsystem cache. This function assumes @secattr has 376762306a36Sopenharmony_ci * already been initialized. 376862306a36Sopenharmony_ci * 376962306a36Sopenharmony_ci */ 377062306a36Sopenharmony_cistatic void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, 377162306a36Sopenharmony_ci u32 sid) 377262306a36Sopenharmony_ci{ 377362306a36Sopenharmony_ci u32 *sid_cache; 377462306a36Sopenharmony_ci 377562306a36Sopenharmony_ci sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC); 377662306a36Sopenharmony_ci if (sid_cache == NULL) 377762306a36Sopenharmony_ci return; 377862306a36Sopenharmony_ci secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); 377962306a36Sopenharmony_ci if (secattr->cache == NULL) { 378062306a36Sopenharmony_ci kfree(sid_cache); 378162306a36Sopenharmony_ci return; 378262306a36Sopenharmony_ci } 378362306a36Sopenharmony_ci 378462306a36Sopenharmony_ci *sid_cache = sid; 378562306a36Sopenharmony_ci secattr->cache->free = kfree; 378662306a36Sopenharmony_ci secattr->cache->data = sid_cache; 378762306a36Sopenharmony_ci secattr->flags |= NETLBL_SECATTR_CACHE; 378862306a36Sopenharmony_ci} 378962306a36Sopenharmony_ci 379062306a36Sopenharmony_ci/** 379162306a36Sopenharmony_ci * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID 379262306a36Sopenharmony_ci * @secattr: the NetLabel packet security attributes 379362306a36Sopenharmony_ci * @sid: the SELinux SID 379462306a36Sopenharmony_ci * 379562306a36Sopenharmony_ci * Description: 379662306a36Sopenharmony_ci * Convert the given NetLabel security attributes in @secattr into a 379762306a36Sopenharmony_ci * SELinux SID. If the @secattr field does not contain a full SELinux 379862306a36Sopenharmony_ci * SID/context then use SECINITSID_NETMSG as the foundation. If possible the 379962306a36Sopenharmony_ci * 'cache' field of @secattr is set and the CACHE flag is set; this is to 380062306a36Sopenharmony_ci * allow the @secattr to be used by NetLabel to cache the secattr to SID 380162306a36Sopenharmony_ci * conversion for future lookups. Returns zero on success, negative values on 380262306a36Sopenharmony_ci * failure. 380362306a36Sopenharmony_ci * 380462306a36Sopenharmony_ci */ 380562306a36Sopenharmony_ciint security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, 380662306a36Sopenharmony_ci u32 *sid) 380762306a36Sopenharmony_ci{ 380862306a36Sopenharmony_ci struct selinux_policy *policy; 380962306a36Sopenharmony_ci struct policydb *policydb; 381062306a36Sopenharmony_ci struct sidtab *sidtab; 381162306a36Sopenharmony_ci int rc; 381262306a36Sopenharmony_ci struct context *ctx; 381362306a36Sopenharmony_ci struct context ctx_new; 381462306a36Sopenharmony_ci 381562306a36Sopenharmony_ci if (!selinux_initialized()) { 381662306a36Sopenharmony_ci *sid = SECSID_NULL; 381762306a36Sopenharmony_ci return 0; 381862306a36Sopenharmony_ci } 381962306a36Sopenharmony_ci 382062306a36Sopenharmony_ciretry: 382162306a36Sopenharmony_ci rc = 0; 382262306a36Sopenharmony_ci rcu_read_lock(); 382362306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 382462306a36Sopenharmony_ci policydb = &policy->policydb; 382562306a36Sopenharmony_ci sidtab = policy->sidtab; 382662306a36Sopenharmony_ci 382762306a36Sopenharmony_ci if (secattr->flags & NETLBL_SECATTR_CACHE) 382862306a36Sopenharmony_ci *sid = *(u32 *)secattr->cache->data; 382962306a36Sopenharmony_ci else if (secattr->flags & NETLBL_SECATTR_SECID) 383062306a36Sopenharmony_ci *sid = secattr->attr.secid; 383162306a36Sopenharmony_ci else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { 383262306a36Sopenharmony_ci rc = -EIDRM; 383362306a36Sopenharmony_ci ctx = sidtab_search(sidtab, SECINITSID_NETMSG); 383462306a36Sopenharmony_ci if (ctx == NULL) 383562306a36Sopenharmony_ci goto out; 383662306a36Sopenharmony_ci 383762306a36Sopenharmony_ci context_init(&ctx_new); 383862306a36Sopenharmony_ci ctx_new.user = ctx->user; 383962306a36Sopenharmony_ci ctx_new.role = ctx->role; 384062306a36Sopenharmony_ci ctx_new.type = ctx->type; 384162306a36Sopenharmony_ci mls_import_netlbl_lvl(policydb, &ctx_new, secattr); 384262306a36Sopenharmony_ci if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 384362306a36Sopenharmony_ci rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr); 384462306a36Sopenharmony_ci if (rc) 384562306a36Sopenharmony_ci goto out; 384662306a36Sopenharmony_ci } 384762306a36Sopenharmony_ci rc = -EIDRM; 384862306a36Sopenharmony_ci if (!mls_context_isvalid(policydb, &ctx_new)) { 384962306a36Sopenharmony_ci ebitmap_destroy(&ctx_new.range.level[0].cat); 385062306a36Sopenharmony_ci goto out; 385162306a36Sopenharmony_ci } 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &ctx_new, sid); 385462306a36Sopenharmony_ci ebitmap_destroy(&ctx_new.range.level[0].cat); 385562306a36Sopenharmony_ci if (rc == -ESTALE) { 385662306a36Sopenharmony_ci rcu_read_unlock(); 385762306a36Sopenharmony_ci goto retry; 385862306a36Sopenharmony_ci } 385962306a36Sopenharmony_ci if (rc) 386062306a36Sopenharmony_ci goto out; 386162306a36Sopenharmony_ci 386262306a36Sopenharmony_ci security_netlbl_cache_add(secattr, *sid); 386362306a36Sopenharmony_ci } else 386462306a36Sopenharmony_ci *sid = SECSID_NULL; 386562306a36Sopenharmony_ci 386662306a36Sopenharmony_ciout: 386762306a36Sopenharmony_ci rcu_read_unlock(); 386862306a36Sopenharmony_ci return rc; 386962306a36Sopenharmony_ci} 387062306a36Sopenharmony_ci 387162306a36Sopenharmony_ci/** 387262306a36Sopenharmony_ci * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr 387362306a36Sopenharmony_ci * @sid: the SELinux SID 387462306a36Sopenharmony_ci * @secattr: the NetLabel packet security attributes 387562306a36Sopenharmony_ci * 387662306a36Sopenharmony_ci * Description: 387762306a36Sopenharmony_ci * Convert the given SELinux SID in @sid into a NetLabel security attribute. 387862306a36Sopenharmony_ci * Returns zero on success, negative values on failure. 387962306a36Sopenharmony_ci * 388062306a36Sopenharmony_ci */ 388162306a36Sopenharmony_ciint security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) 388262306a36Sopenharmony_ci{ 388362306a36Sopenharmony_ci struct selinux_policy *policy; 388462306a36Sopenharmony_ci struct policydb *policydb; 388562306a36Sopenharmony_ci int rc; 388662306a36Sopenharmony_ci struct context *ctx; 388762306a36Sopenharmony_ci 388862306a36Sopenharmony_ci if (!selinux_initialized()) 388962306a36Sopenharmony_ci return 0; 389062306a36Sopenharmony_ci 389162306a36Sopenharmony_ci rcu_read_lock(); 389262306a36Sopenharmony_ci policy = rcu_dereference(selinux_state.policy); 389362306a36Sopenharmony_ci policydb = &policy->policydb; 389462306a36Sopenharmony_ci 389562306a36Sopenharmony_ci rc = -ENOENT; 389662306a36Sopenharmony_ci ctx = sidtab_search(policy->sidtab, sid); 389762306a36Sopenharmony_ci if (ctx == NULL) 389862306a36Sopenharmony_ci goto out; 389962306a36Sopenharmony_ci 390062306a36Sopenharmony_ci rc = -ENOMEM; 390162306a36Sopenharmony_ci secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1), 390262306a36Sopenharmony_ci GFP_ATOMIC); 390362306a36Sopenharmony_ci if (secattr->domain == NULL) 390462306a36Sopenharmony_ci goto out; 390562306a36Sopenharmony_ci 390662306a36Sopenharmony_ci secattr->attr.secid = sid; 390762306a36Sopenharmony_ci secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; 390862306a36Sopenharmony_ci mls_export_netlbl_lvl(policydb, ctx, secattr); 390962306a36Sopenharmony_ci rc = mls_export_netlbl_cat(policydb, ctx, secattr); 391062306a36Sopenharmony_ciout: 391162306a36Sopenharmony_ci rcu_read_unlock(); 391262306a36Sopenharmony_ci return rc; 391362306a36Sopenharmony_ci} 391462306a36Sopenharmony_ci#endif /* CONFIG_NETLABEL */ 391562306a36Sopenharmony_ci 391662306a36Sopenharmony_ci/** 391762306a36Sopenharmony_ci * __security_read_policy - read the policy. 391862306a36Sopenharmony_ci * @policy: SELinux policy 391962306a36Sopenharmony_ci * @data: binary policy data 392062306a36Sopenharmony_ci * @len: length of data in bytes 392162306a36Sopenharmony_ci * 392262306a36Sopenharmony_ci */ 392362306a36Sopenharmony_cistatic int __security_read_policy(struct selinux_policy *policy, 392462306a36Sopenharmony_ci void *data, size_t *len) 392562306a36Sopenharmony_ci{ 392662306a36Sopenharmony_ci int rc; 392762306a36Sopenharmony_ci struct policy_file fp; 392862306a36Sopenharmony_ci 392962306a36Sopenharmony_ci fp.data = data; 393062306a36Sopenharmony_ci fp.len = *len; 393162306a36Sopenharmony_ci 393262306a36Sopenharmony_ci rc = policydb_write(&policy->policydb, &fp); 393362306a36Sopenharmony_ci if (rc) 393462306a36Sopenharmony_ci return rc; 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci *len = (unsigned long)fp.data - (unsigned long)data; 393762306a36Sopenharmony_ci return 0; 393862306a36Sopenharmony_ci} 393962306a36Sopenharmony_ci 394062306a36Sopenharmony_ci/** 394162306a36Sopenharmony_ci * security_read_policy - read the policy. 394262306a36Sopenharmony_ci * @data: binary policy data 394362306a36Sopenharmony_ci * @len: length of data in bytes 394462306a36Sopenharmony_ci * 394562306a36Sopenharmony_ci */ 394662306a36Sopenharmony_ciint security_read_policy(void **data, size_t *len) 394762306a36Sopenharmony_ci{ 394862306a36Sopenharmony_ci struct selinux_state *state = &selinux_state; 394962306a36Sopenharmony_ci struct selinux_policy *policy; 395062306a36Sopenharmony_ci 395162306a36Sopenharmony_ci policy = rcu_dereference_protected( 395262306a36Sopenharmony_ci state->policy, lockdep_is_held(&state->policy_mutex)); 395362306a36Sopenharmony_ci if (!policy) 395462306a36Sopenharmony_ci return -EINVAL; 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_ci *len = policy->policydb.len; 395762306a36Sopenharmony_ci *data = vmalloc_user(*len); 395862306a36Sopenharmony_ci if (!*data) 395962306a36Sopenharmony_ci return -ENOMEM; 396062306a36Sopenharmony_ci 396162306a36Sopenharmony_ci return __security_read_policy(policy, *data, len); 396262306a36Sopenharmony_ci} 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci/** 396562306a36Sopenharmony_ci * security_read_state_kernel - read the policy. 396662306a36Sopenharmony_ci * @data: binary policy data 396762306a36Sopenharmony_ci * @len: length of data in bytes 396862306a36Sopenharmony_ci * 396962306a36Sopenharmony_ci * Allocates kernel memory for reading SELinux policy. 397062306a36Sopenharmony_ci * This function is for internal use only and should not 397162306a36Sopenharmony_ci * be used for returning data to user space. 397262306a36Sopenharmony_ci * 397362306a36Sopenharmony_ci * This function must be called with policy_mutex held. 397462306a36Sopenharmony_ci */ 397562306a36Sopenharmony_ciint security_read_state_kernel(void **data, size_t *len) 397662306a36Sopenharmony_ci{ 397762306a36Sopenharmony_ci int err; 397862306a36Sopenharmony_ci struct selinux_state *state = &selinux_state; 397962306a36Sopenharmony_ci struct selinux_policy *policy; 398062306a36Sopenharmony_ci 398162306a36Sopenharmony_ci policy = rcu_dereference_protected( 398262306a36Sopenharmony_ci state->policy, lockdep_is_held(&state->policy_mutex)); 398362306a36Sopenharmony_ci if (!policy) 398462306a36Sopenharmony_ci return -EINVAL; 398562306a36Sopenharmony_ci 398662306a36Sopenharmony_ci *len = policy->policydb.len; 398762306a36Sopenharmony_ci *data = vmalloc(*len); 398862306a36Sopenharmony_ci if (!*data) 398962306a36Sopenharmony_ci return -ENOMEM; 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci err = __security_read_policy(policy, *data, len); 399262306a36Sopenharmony_ci if (err) { 399362306a36Sopenharmony_ci vfree(*data); 399462306a36Sopenharmony_ci *data = NULL; 399562306a36Sopenharmony_ci *len = 0; 399662306a36Sopenharmony_ci } 399762306a36Sopenharmony_ci return err; 399862306a36Sopenharmony_ci} 3999