18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Implementation of the security services. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Authors : Stephen Smalley, <sds@tycho.nsa.gov> 68c2ecf20Sopenharmony_ci * James Morris <jmorris@redhat.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Support for enhanced MLS infrastructure. 118c2ecf20Sopenharmony_ci * Support for context based audit filters. 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Added conditional policy language extensions 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Updated: Hewlett-Packard <paul@paul-moore.com> 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Added support for NetLabel 208c2ecf20Sopenharmony_ci * Added support for the policy capability bitmap 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Updated: Chad Sellers <csellers@tresys.com> 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Added validation of kernel classes and permissions 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com> 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * Added support for bounds domain and audit messaged on masked permissions 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Updated: Guido Trentalancia <guido@trentalancia.com> 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Added support for runtime switching of the policy type 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Copyright (C) 2008, 2009 NEC Corporation 358c2ecf20Sopenharmony_ci * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. 368c2ecf20Sopenharmony_ci * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 378c2ecf20Sopenharmony_ci * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC 388c2ecf20Sopenharmony_ci * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci#include <linux/kernel.h> 418c2ecf20Sopenharmony_ci#include <linux/slab.h> 428c2ecf20Sopenharmony_ci#include <linux/string.h> 438c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 448c2ecf20Sopenharmony_ci#include <linux/rcupdate.h> 458c2ecf20Sopenharmony_ci#include <linux/errno.h> 468c2ecf20Sopenharmony_ci#include <linux/in.h> 478c2ecf20Sopenharmony_ci#include <linux/sched.h> 488c2ecf20Sopenharmony_ci#include <linux/audit.h> 498c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 508c2ecf20Sopenharmony_ci#include <net/netlabel.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#include "flask.h" 538c2ecf20Sopenharmony_ci#include "avc.h" 548c2ecf20Sopenharmony_ci#include "avc_ss.h" 558c2ecf20Sopenharmony_ci#include "security.h" 568c2ecf20Sopenharmony_ci#include "context.h" 578c2ecf20Sopenharmony_ci#include "policydb.h" 588c2ecf20Sopenharmony_ci#include "sidtab.h" 598c2ecf20Sopenharmony_ci#include "services.h" 608c2ecf20Sopenharmony_ci#include "conditional.h" 618c2ecf20Sopenharmony_ci#include "mls.h" 628c2ecf20Sopenharmony_ci#include "objsec.h" 638c2ecf20Sopenharmony_ci#include "netlabel.h" 648c2ecf20Sopenharmony_ci#include "xfrm.h" 658c2ecf20Sopenharmony_ci#include "ebitmap.h" 668c2ecf20Sopenharmony_ci#include "audit.h" 678c2ecf20Sopenharmony_ci#include "policycap_names.h" 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistruct convert_context_args { 708c2ecf20Sopenharmony_ci struct selinux_state *state; 718c2ecf20Sopenharmony_ci struct policydb *oldp; 728c2ecf20Sopenharmony_ci struct policydb *newp; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistruct selinux_policy_convert_data { 768c2ecf20Sopenharmony_ci struct convert_context_args args; 778c2ecf20Sopenharmony_ci struct sidtab_convert_params sidtab_params; 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* Forward declaration. */ 818c2ecf20Sopenharmony_cistatic int context_struct_to_string(struct policydb *policydb, 828c2ecf20Sopenharmony_ci struct context *context, 838c2ecf20Sopenharmony_ci char **scontext, 848c2ecf20Sopenharmony_ci u32 *scontext_len); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic int sidtab_entry_to_string(struct policydb *policydb, 878c2ecf20Sopenharmony_ci struct sidtab *sidtab, 888c2ecf20Sopenharmony_ci struct sidtab_entry *entry, 898c2ecf20Sopenharmony_ci char **scontext, 908c2ecf20Sopenharmony_ci u32 *scontext_len); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic void context_struct_compute_av(struct policydb *policydb, 938c2ecf20Sopenharmony_ci struct context *scontext, 948c2ecf20Sopenharmony_ci struct context *tcontext, 958c2ecf20Sopenharmony_ci u16 tclass, 968c2ecf20Sopenharmony_ci struct av_decision *avd, 978c2ecf20Sopenharmony_ci struct extended_perms *xperms); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int selinux_set_mapping(struct policydb *pol, 1008c2ecf20Sopenharmony_ci struct security_class_mapping *map, 1018c2ecf20Sopenharmony_ci struct selinux_map *out_map) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci u16 i, j; 1048c2ecf20Sopenharmony_ci unsigned k; 1058c2ecf20Sopenharmony_ci bool print_unknown_handle = false; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci /* Find number of classes in the input mapping */ 1088c2ecf20Sopenharmony_ci if (!map) 1098c2ecf20Sopenharmony_ci return -EINVAL; 1108c2ecf20Sopenharmony_ci i = 0; 1118c2ecf20Sopenharmony_ci while (map[i].name) 1128c2ecf20Sopenharmony_ci i++; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Allocate space for the class records, plus one for class zero */ 1158c2ecf20Sopenharmony_ci out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC); 1168c2ecf20Sopenharmony_ci if (!out_map->mapping) 1178c2ecf20Sopenharmony_ci return -ENOMEM; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* Store the raw class and permission values */ 1208c2ecf20Sopenharmony_ci j = 0; 1218c2ecf20Sopenharmony_ci while (map[j].name) { 1228c2ecf20Sopenharmony_ci struct security_class_mapping *p_in = map + (j++); 1238c2ecf20Sopenharmony_ci struct selinux_mapping *p_out = out_map->mapping + j; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci /* An empty class string skips ahead */ 1268c2ecf20Sopenharmony_ci if (!strcmp(p_in->name, "")) { 1278c2ecf20Sopenharmony_ci p_out->num_perms = 0; 1288c2ecf20Sopenharmony_ci continue; 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci p_out->value = string_to_security_class(pol, p_in->name); 1328c2ecf20Sopenharmony_ci if (!p_out->value) { 1338c2ecf20Sopenharmony_ci pr_info("SELinux: Class %s not defined in policy.\n", 1348c2ecf20Sopenharmony_ci p_in->name); 1358c2ecf20Sopenharmony_ci if (pol->reject_unknown) 1368c2ecf20Sopenharmony_ci goto err; 1378c2ecf20Sopenharmony_ci p_out->num_perms = 0; 1388c2ecf20Sopenharmony_ci print_unknown_handle = true; 1398c2ecf20Sopenharmony_ci continue; 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci k = 0; 1438c2ecf20Sopenharmony_ci while (p_in->perms[k]) { 1448c2ecf20Sopenharmony_ci /* An empty permission string skips ahead */ 1458c2ecf20Sopenharmony_ci if (!*p_in->perms[k]) { 1468c2ecf20Sopenharmony_ci k++; 1478c2ecf20Sopenharmony_ci continue; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci p_out->perms[k] = string_to_av_perm(pol, p_out->value, 1508c2ecf20Sopenharmony_ci p_in->perms[k]); 1518c2ecf20Sopenharmony_ci if (!p_out->perms[k]) { 1528c2ecf20Sopenharmony_ci pr_info("SELinux: Permission %s in class %s not defined in policy.\n", 1538c2ecf20Sopenharmony_ci p_in->perms[k], p_in->name); 1548c2ecf20Sopenharmony_ci if (pol->reject_unknown) 1558c2ecf20Sopenharmony_ci goto err; 1568c2ecf20Sopenharmony_ci print_unknown_handle = true; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci k++; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci p_out->num_perms = k; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci if (print_unknown_handle) 1658c2ecf20Sopenharmony_ci pr_info("SELinux: the above unknown classes and permissions will be %s\n", 1668c2ecf20Sopenharmony_ci pol->allow_unknown ? "allowed" : "denied"); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci out_map->size = i; 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_cierr: 1718c2ecf20Sopenharmony_ci kfree(out_map->mapping); 1728c2ecf20Sopenharmony_ci out_map->mapping = NULL; 1738c2ecf20Sopenharmony_ci return -EINVAL; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci/* 1778c2ecf20Sopenharmony_ci * Get real, policy values from mapped values 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic u16 unmap_class(struct selinux_map *map, u16 tclass) 1818c2ecf20Sopenharmony_ci{ 1828c2ecf20Sopenharmony_ci if (tclass < map->size) 1838c2ecf20Sopenharmony_ci return map->mapping[tclass].value; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return tclass; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci/* 1898c2ecf20Sopenharmony_ci * Get kernel value for class from its policy value 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_cistatic u16 map_class(struct selinux_map *map, u16 pol_value) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci u16 i; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci for (i = 1; i < map->size; i++) { 1968c2ecf20Sopenharmony_ci if (map->mapping[i].value == pol_value) 1978c2ecf20Sopenharmony_ci return i; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return SECCLASS_NULL; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic void map_decision(struct selinux_map *map, 2048c2ecf20Sopenharmony_ci u16 tclass, struct av_decision *avd, 2058c2ecf20Sopenharmony_ci int allow_unknown) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci if (tclass < map->size) { 2088c2ecf20Sopenharmony_ci struct selinux_mapping *mapping = &map->mapping[tclass]; 2098c2ecf20Sopenharmony_ci unsigned int i, n = mapping->num_perms; 2108c2ecf20Sopenharmony_ci u32 result; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci for (i = 0, result = 0; i < n; i++) { 2138c2ecf20Sopenharmony_ci if (avd->allowed & mapping->perms[i]) 2148c2ecf20Sopenharmony_ci result |= 1<<i; 2158c2ecf20Sopenharmony_ci if (allow_unknown && !mapping->perms[i]) 2168c2ecf20Sopenharmony_ci result |= 1<<i; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci avd->allowed = result; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci for (i = 0, result = 0; i < n; i++) 2218c2ecf20Sopenharmony_ci if (avd->auditallow & mapping->perms[i]) 2228c2ecf20Sopenharmony_ci result |= 1<<i; 2238c2ecf20Sopenharmony_ci avd->auditallow = result; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci for (i = 0, result = 0; i < n; i++) { 2268c2ecf20Sopenharmony_ci if (avd->auditdeny & mapping->perms[i]) 2278c2ecf20Sopenharmony_ci result |= 1<<i; 2288c2ecf20Sopenharmony_ci if (!allow_unknown && !mapping->perms[i]) 2298c2ecf20Sopenharmony_ci result |= 1<<i; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * In case the kernel has a bug and requests a permission 2338c2ecf20Sopenharmony_ci * between num_perms and the maximum permission number, we 2348c2ecf20Sopenharmony_ci * should audit that denial 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci for (; i < (sizeof(u32)*8); i++) 2378c2ecf20Sopenharmony_ci result |= 1<<i; 2388c2ecf20Sopenharmony_ci avd->auditdeny = result; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciint security_mls_enabled(struct selinux_state *state) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci int mls_enabled; 2458c2ecf20Sopenharmony_ci struct selinux_policy *policy; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 2488c2ecf20Sopenharmony_ci return 0; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci rcu_read_lock(); 2518c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 2528c2ecf20Sopenharmony_ci mls_enabled = policy->policydb.mls_enabled; 2538c2ecf20Sopenharmony_ci rcu_read_unlock(); 2548c2ecf20Sopenharmony_ci return mls_enabled; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci/* 2588c2ecf20Sopenharmony_ci * Return the boolean value of a constraint expression 2598c2ecf20Sopenharmony_ci * when it is applied to the specified source and target 2608c2ecf20Sopenharmony_ci * security contexts. 2618c2ecf20Sopenharmony_ci * 2628c2ecf20Sopenharmony_ci * xcontext is a special beast... It is used by the validatetrans rules 2638c2ecf20Sopenharmony_ci * only. For these rules, scontext is the context before the transition, 2648c2ecf20Sopenharmony_ci * tcontext is the context after the transition, and xcontext is the context 2658c2ecf20Sopenharmony_ci * of the process performing the transition. All other callers of 2668c2ecf20Sopenharmony_ci * constraint_expr_eval should pass in NULL for xcontext. 2678c2ecf20Sopenharmony_ci */ 2688c2ecf20Sopenharmony_cistatic int constraint_expr_eval(struct policydb *policydb, 2698c2ecf20Sopenharmony_ci struct context *scontext, 2708c2ecf20Sopenharmony_ci struct context *tcontext, 2718c2ecf20Sopenharmony_ci struct context *xcontext, 2728c2ecf20Sopenharmony_ci struct constraint_expr *cexpr) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci u32 val1, val2; 2758c2ecf20Sopenharmony_ci struct context *c; 2768c2ecf20Sopenharmony_ci struct role_datum *r1, *r2; 2778c2ecf20Sopenharmony_ci struct mls_level *l1, *l2; 2788c2ecf20Sopenharmony_ci struct constraint_expr *e; 2798c2ecf20Sopenharmony_ci int s[CEXPR_MAXDEPTH]; 2808c2ecf20Sopenharmony_ci int sp = -1; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci for (e = cexpr; e; e = e->next) { 2838c2ecf20Sopenharmony_ci switch (e->expr_type) { 2848c2ecf20Sopenharmony_ci case CEXPR_NOT: 2858c2ecf20Sopenharmony_ci BUG_ON(sp < 0); 2868c2ecf20Sopenharmony_ci s[sp] = !s[sp]; 2878c2ecf20Sopenharmony_ci break; 2888c2ecf20Sopenharmony_ci case CEXPR_AND: 2898c2ecf20Sopenharmony_ci BUG_ON(sp < 1); 2908c2ecf20Sopenharmony_ci sp--; 2918c2ecf20Sopenharmony_ci s[sp] &= s[sp + 1]; 2928c2ecf20Sopenharmony_ci break; 2938c2ecf20Sopenharmony_ci case CEXPR_OR: 2948c2ecf20Sopenharmony_ci BUG_ON(sp < 1); 2958c2ecf20Sopenharmony_ci sp--; 2968c2ecf20Sopenharmony_ci s[sp] |= s[sp + 1]; 2978c2ecf20Sopenharmony_ci break; 2988c2ecf20Sopenharmony_ci case CEXPR_ATTR: 2998c2ecf20Sopenharmony_ci if (sp == (CEXPR_MAXDEPTH - 1)) 3008c2ecf20Sopenharmony_ci return 0; 3018c2ecf20Sopenharmony_ci switch (e->attr) { 3028c2ecf20Sopenharmony_ci case CEXPR_USER: 3038c2ecf20Sopenharmony_ci val1 = scontext->user; 3048c2ecf20Sopenharmony_ci val2 = tcontext->user; 3058c2ecf20Sopenharmony_ci break; 3068c2ecf20Sopenharmony_ci case CEXPR_TYPE: 3078c2ecf20Sopenharmony_ci val1 = scontext->type; 3088c2ecf20Sopenharmony_ci val2 = tcontext->type; 3098c2ecf20Sopenharmony_ci break; 3108c2ecf20Sopenharmony_ci case CEXPR_ROLE: 3118c2ecf20Sopenharmony_ci val1 = scontext->role; 3128c2ecf20Sopenharmony_ci val2 = tcontext->role; 3138c2ecf20Sopenharmony_ci r1 = policydb->role_val_to_struct[val1 - 1]; 3148c2ecf20Sopenharmony_ci r2 = policydb->role_val_to_struct[val2 - 1]; 3158c2ecf20Sopenharmony_ci switch (e->op) { 3168c2ecf20Sopenharmony_ci case CEXPR_DOM: 3178c2ecf20Sopenharmony_ci s[++sp] = ebitmap_get_bit(&r1->dominates, 3188c2ecf20Sopenharmony_ci val2 - 1); 3198c2ecf20Sopenharmony_ci continue; 3208c2ecf20Sopenharmony_ci case CEXPR_DOMBY: 3218c2ecf20Sopenharmony_ci s[++sp] = ebitmap_get_bit(&r2->dominates, 3228c2ecf20Sopenharmony_ci val1 - 1); 3238c2ecf20Sopenharmony_ci continue; 3248c2ecf20Sopenharmony_ci case CEXPR_INCOMP: 3258c2ecf20Sopenharmony_ci s[++sp] = (!ebitmap_get_bit(&r1->dominates, 3268c2ecf20Sopenharmony_ci val2 - 1) && 3278c2ecf20Sopenharmony_ci !ebitmap_get_bit(&r2->dominates, 3288c2ecf20Sopenharmony_ci val1 - 1)); 3298c2ecf20Sopenharmony_ci continue; 3308c2ecf20Sopenharmony_ci default: 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci case CEXPR_L1L2: 3358c2ecf20Sopenharmony_ci l1 = &(scontext->range.level[0]); 3368c2ecf20Sopenharmony_ci l2 = &(tcontext->range.level[0]); 3378c2ecf20Sopenharmony_ci goto mls_ops; 3388c2ecf20Sopenharmony_ci case CEXPR_L1H2: 3398c2ecf20Sopenharmony_ci l1 = &(scontext->range.level[0]); 3408c2ecf20Sopenharmony_ci l2 = &(tcontext->range.level[1]); 3418c2ecf20Sopenharmony_ci goto mls_ops; 3428c2ecf20Sopenharmony_ci case CEXPR_H1L2: 3438c2ecf20Sopenharmony_ci l1 = &(scontext->range.level[1]); 3448c2ecf20Sopenharmony_ci l2 = &(tcontext->range.level[0]); 3458c2ecf20Sopenharmony_ci goto mls_ops; 3468c2ecf20Sopenharmony_ci case CEXPR_H1H2: 3478c2ecf20Sopenharmony_ci l1 = &(scontext->range.level[1]); 3488c2ecf20Sopenharmony_ci l2 = &(tcontext->range.level[1]); 3498c2ecf20Sopenharmony_ci goto mls_ops; 3508c2ecf20Sopenharmony_ci case CEXPR_L1H1: 3518c2ecf20Sopenharmony_ci l1 = &(scontext->range.level[0]); 3528c2ecf20Sopenharmony_ci l2 = &(scontext->range.level[1]); 3538c2ecf20Sopenharmony_ci goto mls_ops; 3548c2ecf20Sopenharmony_ci case CEXPR_L2H2: 3558c2ecf20Sopenharmony_ci l1 = &(tcontext->range.level[0]); 3568c2ecf20Sopenharmony_ci l2 = &(tcontext->range.level[1]); 3578c2ecf20Sopenharmony_ci goto mls_ops; 3588c2ecf20Sopenharmony_cimls_ops: 3598c2ecf20Sopenharmony_ci switch (e->op) { 3608c2ecf20Sopenharmony_ci case CEXPR_EQ: 3618c2ecf20Sopenharmony_ci s[++sp] = mls_level_eq(l1, l2); 3628c2ecf20Sopenharmony_ci continue; 3638c2ecf20Sopenharmony_ci case CEXPR_NEQ: 3648c2ecf20Sopenharmony_ci s[++sp] = !mls_level_eq(l1, l2); 3658c2ecf20Sopenharmony_ci continue; 3668c2ecf20Sopenharmony_ci case CEXPR_DOM: 3678c2ecf20Sopenharmony_ci s[++sp] = mls_level_dom(l1, l2); 3688c2ecf20Sopenharmony_ci continue; 3698c2ecf20Sopenharmony_ci case CEXPR_DOMBY: 3708c2ecf20Sopenharmony_ci s[++sp] = mls_level_dom(l2, l1); 3718c2ecf20Sopenharmony_ci continue; 3728c2ecf20Sopenharmony_ci case CEXPR_INCOMP: 3738c2ecf20Sopenharmony_ci s[++sp] = mls_level_incomp(l2, l1); 3748c2ecf20Sopenharmony_ci continue; 3758c2ecf20Sopenharmony_ci default: 3768c2ecf20Sopenharmony_ci BUG(); 3778c2ecf20Sopenharmony_ci return 0; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci break; 3808c2ecf20Sopenharmony_ci default: 3818c2ecf20Sopenharmony_ci BUG(); 3828c2ecf20Sopenharmony_ci return 0; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci switch (e->op) { 3868c2ecf20Sopenharmony_ci case CEXPR_EQ: 3878c2ecf20Sopenharmony_ci s[++sp] = (val1 == val2); 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci case CEXPR_NEQ: 3908c2ecf20Sopenharmony_ci s[++sp] = (val1 != val2); 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci default: 3938c2ecf20Sopenharmony_ci BUG(); 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci case CEXPR_NAMES: 3988c2ecf20Sopenharmony_ci if (sp == (CEXPR_MAXDEPTH-1)) 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ci c = scontext; 4018c2ecf20Sopenharmony_ci if (e->attr & CEXPR_TARGET) 4028c2ecf20Sopenharmony_ci c = tcontext; 4038c2ecf20Sopenharmony_ci else if (e->attr & CEXPR_XTARGET) { 4048c2ecf20Sopenharmony_ci c = xcontext; 4058c2ecf20Sopenharmony_ci if (!c) { 4068c2ecf20Sopenharmony_ci BUG(); 4078c2ecf20Sopenharmony_ci return 0; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci if (e->attr & CEXPR_USER) 4118c2ecf20Sopenharmony_ci val1 = c->user; 4128c2ecf20Sopenharmony_ci else if (e->attr & CEXPR_ROLE) 4138c2ecf20Sopenharmony_ci val1 = c->role; 4148c2ecf20Sopenharmony_ci else if (e->attr & CEXPR_TYPE) 4158c2ecf20Sopenharmony_ci val1 = c->type; 4168c2ecf20Sopenharmony_ci else { 4178c2ecf20Sopenharmony_ci BUG(); 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci switch (e->op) { 4228c2ecf20Sopenharmony_ci case CEXPR_EQ: 4238c2ecf20Sopenharmony_ci s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci case CEXPR_NEQ: 4268c2ecf20Sopenharmony_ci s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci default: 4298c2ecf20Sopenharmony_ci BUG(); 4308c2ecf20Sopenharmony_ci return 0; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci default: 4348c2ecf20Sopenharmony_ci BUG(); 4358c2ecf20Sopenharmony_ci return 0; 4368c2ecf20Sopenharmony_ci } 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci BUG_ON(sp != 0); 4408c2ecf20Sopenharmony_ci return s[0]; 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci/* 4448c2ecf20Sopenharmony_ci * security_dump_masked_av - dumps masked permissions during 4458c2ecf20Sopenharmony_ci * security_compute_av due to RBAC, MLS/Constraint and Type bounds. 4468c2ecf20Sopenharmony_ci */ 4478c2ecf20Sopenharmony_cistatic int dump_masked_av_helper(void *k, void *d, void *args) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct perm_datum *pdatum = d; 4508c2ecf20Sopenharmony_ci char **permission_names = args; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci BUG_ON(pdatum->value < 1 || pdatum->value > 32); 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci permission_names[pdatum->value - 1] = (char *)k; 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci return 0; 4578c2ecf20Sopenharmony_ci} 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic void security_dump_masked_av(struct policydb *policydb, 4608c2ecf20Sopenharmony_ci struct context *scontext, 4618c2ecf20Sopenharmony_ci struct context *tcontext, 4628c2ecf20Sopenharmony_ci u16 tclass, 4638c2ecf20Sopenharmony_ci u32 permissions, 4648c2ecf20Sopenharmony_ci const char *reason) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci struct common_datum *common_dat; 4678c2ecf20Sopenharmony_ci struct class_datum *tclass_dat; 4688c2ecf20Sopenharmony_ci struct audit_buffer *ab; 4698c2ecf20Sopenharmony_ci char *tclass_name; 4708c2ecf20Sopenharmony_ci char *scontext_name = NULL; 4718c2ecf20Sopenharmony_ci char *tcontext_name = NULL; 4728c2ecf20Sopenharmony_ci char *permission_names[32]; 4738c2ecf20Sopenharmony_ci int index; 4748c2ecf20Sopenharmony_ci u32 length; 4758c2ecf20Sopenharmony_ci bool need_comma = false; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (!permissions) 4788c2ecf20Sopenharmony_ci return; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1); 4818c2ecf20Sopenharmony_ci tclass_dat = policydb->class_val_to_struct[tclass - 1]; 4828c2ecf20Sopenharmony_ci common_dat = tclass_dat->comdatum; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* init permission_names */ 4858c2ecf20Sopenharmony_ci if (common_dat && 4868c2ecf20Sopenharmony_ci hashtab_map(&common_dat->permissions.table, 4878c2ecf20Sopenharmony_ci dump_masked_av_helper, permission_names) < 0) 4888c2ecf20Sopenharmony_ci goto out; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (hashtab_map(&tclass_dat->permissions.table, 4918c2ecf20Sopenharmony_ci dump_masked_av_helper, permission_names) < 0) 4928c2ecf20Sopenharmony_ci goto out; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci /* get scontext/tcontext in text form */ 4958c2ecf20Sopenharmony_ci if (context_struct_to_string(policydb, scontext, 4968c2ecf20Sopenharmony_ci &scontext_name, &length) < 0) 4978c2ecf20Sopenharmony_ci goto out; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (context_struct_to_string(policydb, tcontext, 5008c2ecf20Sopenharmony_ci &tcontext_name, &length) < 0) 5018c2ecf20Sopenharmony_ci goto out; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* audit a message */ 5048c2ecf20Sopenharmony_ci ab = audit_log_start(audit_context(), 5058c2ecf20Sopenharmony_ci GFP_ATOMIC, AUDIT_SELINUX_ERR); 5068c2ecf20Sopenharmony_ci if (!ab) 5078c2ecf20Sopenharmony_ci goto out; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci audit_log_format(ab, "op=security_compute_av reason=%s " 5108c2ecf20Sopenharmony_ci "scontext=%s tcontext=%s tclass=%s perms=", 5118c2ecf20Sopenharmony_ci reason, scontext_name, tcontext_name, tclass_name); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci for (index = 0; index < 32; index++) { 5148c2ecf20Sopenharmony_ci u32 mask = (1 << index); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if ((mask & permissions) == 0) 5178c2ecf20Sopenharmony_ci continue; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci audit_log_format(ab, "%s%s", 5208c2ecf20Sopenharmony_ci need_comma ? "," : "", 5218c2ecf20Sopenharmony_ci permission_names[index] 5228c2ecf20Sopenharmony_ci ? permission_names[index] : "????"); 5238c2ecf20Sopenharmony_ci need_comma = true; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci audit_log_end(ab); 5268c2ecf20Sopenharmony_ciout: 5278c2ecf20Sopenharmony_ci /* release scontext/tcontext */ 5288c2ecf20Sopenharmony_ci kfree(tcontext_name); 5298c2ecf20Sopenharmony_ci kfree(scontext_name); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci return; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/* 5358c2ecf20Sopenharmony_ci * security_boundary_permission - drops violated permissions 5368c2ecf20Sopenharmony_ci * on boundary constraint. 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_cistatic void type_attribute_bounds_av(struct policydb *policydb, 5398c2ecf20Sopenharmony_ci struct context *scontext, 5408c2ecf20Sopenharmony_ci struct context *tcontext, 5418c2ecf20Sopenharmony_ci u16 tclass, 5428c2ecf20Sopenharmony_ci struct av_decision *avd) 5438c2ecf20Sopenharmony_ci{ 5448c2ecf20Sopenharmony_ci struct context lo_scontext; 5458c2ecf20Sopenharmony_ci struct context lo_tcontext, *tcontextp = tcontext; 5468c2ecf20Sopenharmony_ci struct av_decision lo_avd; 5478c2ecf20Sopenharmony_ci struct type_datum *source; 5488c2ecf20Sopenharmony_ci struct type_datum *target; 5498c2ecf20Sopenharmony_ci u32 masked = 0; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci source = policydb->type_val_to_struct[scontext->type - 1]; 5528c2ecf20Sopenharmony_ci BUG_ON(!source); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci if (!source->bounds) 5558c2ecf20Sopenharmony_ci return; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci target = policydb->type_val_to_struct[tcontext->type - 1]; 5588c2ecf20Sopenharmony_ci BUG_ON(!target); 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci memset(&lo_avd, 0, sizeof(lo_avd)); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); 5638c2ecf20Sopenharmony_ci lo_scontext.type = source->bounds; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (target->bounds) { 5668c2ecf20Sopenharmony_ci memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); 5678c2ecf20Sopenharmony_ci lo_tcontext.type = target->bounds; 5688c2ecf20Sopenharmony_ci tcontextp = &lo_tcontext; 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci context_struct_compute_av(policydb, &lo_scontext, 5728c2ecf20Sopenharmony_ci tcontextp, 5738c2ecf20Sopenharmony_ci tclass, 5748c2ecf20Sopenharmony_ci &lo_avd, 5758c2ecf20Sopenharmony_ci NULL); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci masked = ~lo_avd.allowed & avd->allowed; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (likely(!masked)) 5808c2ecf20Sopenharmony_ci return; /* no masked permission */ 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci /* mask violated permissions */ 5838c2ecf20Sopenharmony_ci avd->allowed &= ~masked; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* audit masked permissions */ 5868c2ecf20Sopenharmony_ci security_dump_masked_av(policydb, scontext, tcontext, 5878c2ecf20Sopenharmony_ci tclass, masked, "bounds"); 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci/* 5918c2ecf20Sopenharmony_ci * flag which drivers have permissions 5928c2ecf20Sopenharmony_ci * only looking for ioctl based extended permssions 5938c2ecf20Sopenharmony_ci */ 5948c2ecf20Sopenharmony_civoid services_compute_xperms_drivers( 5958c2ecf20Sopenharmony_ci struct extended_perms *xperms, 5968c2ecf20Sopenharmony_ci struct avtab_node *node) 5978c2ecf20Sopenharmony_ci{ 5988c2ecf20Sopenharmony_ci unsigned int i; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 6018c2ecf20Sopenharmony_ci /* if one or more driver has all permissions allowed */ 6028c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) 6038c2ecf20Sopenharmony_ci xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; 6048c2ecf20Sopenharmony_ci } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 6058c2ecf20Sopenharmony_ci /* if allowing permissions within a driver */ 6068c2ecf20Sopenharmony_ci security_xperm_set(xperms->drivers.p, 6078c2ecf20Sopenharmony_ci node->datum.u.xperms->driver); 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci /* If no ioctl commands are allowed, ignore auditallow and auditdeny */ 6118c2ecf20Sopenharmony_ci if (node->key.specified & AVTAB_XPERMS_ALLOWED) 6128c2ecf20Sopenharmony_ci xperms->len = 1; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci/* 6168c2ecf20Sopenharmony_ci * Compute access vectors and extended permissions based on a context 6178c2ecf20Sopenharmony_ci * structure pair for the permissions in a particular class. 6188c2ecf20Sopenharmony_ci */ 6198c2ecf20Sopenharmony_cistatic void context_struct_compute_av(struct policydb *policydb, 6208c2ecf20Sopenharmony_ci struct context *scontext, 6218c2ecf20Sopenharmony_ci struct context *tcontext, 6228c2ecf20Sopenharmony_ci u16 tclass, 6238c2ecf20Sopenharmony_ci struct av_decision *avd, 6248c2ecf20Sopenharmony_ci struct extended_perms *xperms) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci struct constraint_node *constraint; 6278c2ecf20Sopenharmony_ci struct role_allow *ra; 6288c2ecf20Sopenharmony_ci struct avtab_key avkey; 6298c2ecf20Sopenharmony_ci struct avtab_node *node; 6308c2ecf20Sopenharmony_ci struct class_datum *tclass_datum; 6318c2ecf20Sopenharmony_ci struct ebitmap *sattr, *tattr; 6328c2ecf20Sopenharmony_ci struct ebitmap_node *snode, *tnode; 6338c2ecf20Sopenharmony_ci unsigned int i, j; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci avd->allowed = 0; 6368c2ecf20Sopenharmony_ci avd->auditallow = 0; 6378c2ecf20Sopenharmony_ci avd->auditdeny = 0xffffffff; 6388c2ecf20Sopenharmony_ci if (xperms) { 6398c2ecf20Sopenharmony_ci memset(&xperms->drivers, 0, sizeof(xperms->drivers)); 6408c2ecf20Sopenharmony_ci xperms->len = 0; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) { 6448c2ecf20Sopenharmony_ci if (printk_ratelimit()) 6458c2ecf20Sopenharmony_ci pr_warn("SELinux: Invalid class %hu\n", tclass); 6468c2ecf20Sopenharmony_ci return; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci tclass_datum = policydb->class_val_to_struct[tclass - 1]; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci /* 6528c2ecf20Sopenharmony_ci * If a specific type enforcement rule was defined for 6538c2ecf20Sopenharmony_ci * this permission check, then use it. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci avkey.target_class = tclass; 6568c2ecf20Sopenharmony_ci avkey.specified = AVTAB_AV | AVTAB_XPERMS; 6578c2ecf20Sopenharmony_ci sattr = &policydb->type_attr_map_array[scontext->type - 1]; 6588c2ecf20Sopenharmony_ci tattr = &policydb->type_attr_map_array[tcontext->type - 1]; 6598c2ecf20Sopenharmony_ci ebitmap_for_each_positive_bit(sattr, snode, i) { 6608c2ecf20Sopenharmony_ci ebitmap_for_each_positive_bit(tattr, tnode, j) { 6618c2ecf20Sopenharmony_ci avkey.source_type = i + 1; 6628c2ecf20Sopenharmony_ci avkey.target_type = j + 1; 6638c2ecf20Sopenharmony_ci for (node = avtab_search_node(&policydb->te_avtab, 6648c2ecf20Sopenharmony_ci &avkey); 6658c2ecf20Sopenharmony_ci node; 6668c2ecf20Sopenharmony_ci node = avtab_search_node_next(node, avkey.specified)) { 6678c2ecf20Sopenharmony_ci if (node->key.specified == AVTAB_ALLOWED) 6688c2ecf20Sopenharmony_ci avd->allowed |= node->datum.u.data; 6698c2ecf20Sopenharmony_ci else if (node->key.specified == AVTAB_AUDITALLOW) 6708c2ecf20Sopenharmony_ci avd->auditallow |= node->datum.u.data; 6718c2ecf20Sopenharmony_ci else if (node->key.specified == AVTAB_AUDITDENY) 6728c2ecf20Sopenharmony_ci avd->auditdeny &= node->datum.u.data; 6738c2ecf20Sopenharmony_ci else if (xperms && (node->key.specified & AVTAB_XPERMS)) 6748c2ecf20Sopenharmony_ci services_compute_xperms_drivers(xperms, node); 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* Check conditional av table for additional permissions */ 6788c2ecf20Sopenharmony_ci cond_compute_av(&policydb->te_cond_avtab, &avkey, 6798c2ecf20Sopenharmony_ci avd, xperms); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci /* 6858c2ecf20Sopenharmony_ci * Remove any permissions prohibited by a constraint (this includes 6868c2ecf20Sopenharmony_ci * the MLS policy). 6878c2ecf20Sopenharmony_ci */ 6888c2ecf20Sopenharmony_ci constraint = tclass_datum->constraints; 6898c2ecf20Sopenharmony_ci while (constraint) { 6908c2ecf20Sopenharmony_ci if ((constraint->permissions & (avd->allowed)) && 6918c2ecf20Sopenharmony_ci !constraint_expr_eval(policydb, scontext, tcontext, NULL, 6928c2ecf20Sopenharmony_ci constraint->expr)) { 6938c2ecf20Sopenharmony_ci avd->allowed &= ~(constraint->permissions); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci constraint = constraint->next; 6968c2ecf20Sopenharmony_ci } 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci /* 6998c2ecf20Sopenharmony_ci * If checking process transition permission and the 7008c2ecf20Sopenharmony_ci * role is changing, then check the (current_role, new_role) 7018c2ecf20Sopenharmony_ci * pair. 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_ci if (tclass == policydb->process_class && 7048c2ecf20Sopenharmony_ci (avd->allowed & policydb->process_trans_perms) && 7058c2ecf20Sopenharmony_ci scontext->role != tcontext->role) { 7068c2ecf20Sopenharmony_ci for (ra = policydb->role_allow; ra; ra = ra->next) { 7078c2ecf20Sopenharmony_ci if (scontext->role == ra->role && 7088c2ecf20Sopenharmony_ci tcontext->role == ra->new_role) 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci if (!ra) 7128c2ecf20Sopenharmony_ci avd->allowed &= ~policydb->process_trans_perms; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* 7168c2ecf20Sopenharmony_ci * If the given source and target types have boundary 7178c2ecf20Sopenharmony_ci * constraint, lazy checks have to mask any violated 7188c2ecf20Sopenharmony_ci * permission and notice it to userspace via audit. 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_ci type_attribute_bounds_av(policydb, scontext, tcontext, 7218c2ecf20Sopenharmony_ci tclass, avd); 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic int security_validtrans_handle_fail(struct selinux_state *state, 7258c2ecf20Sopenharmony_ci struct selinux_policy *policy, 7268c2ecf20Sopenharmony_ci struct sidtab_entry *oentry, 7278c2ecf20Sopenharmony_ci struct sidtab_entry *nentry, 7288c2ecf20Sopenharmony_ci struct sidtab_entry *tentry, 7298c2ecf20Sopenharmony_ci u16 tclass) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci struct policydb *p = &policy->policydb; 7328c2ecf20Sopenharmony_ci struct sidtab *sidtab = policy->sidtab; 7338c2ecf20Sopenharmony_ci char *o = NULL, *n = NULL, *t = NULL; 7348c2ecf20Sopenharmony_ci u32 olen, nlen, tlen; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci if (sidtab_entry_to_string(p, sidtab, oentry, &o, &olen)) 7378c2ecf20Sopenharmony_ci goto out; 7388c2ecf20Sopenharmony_ci if (sidtab_entry_to_string(p, sidtab, nentry, &n, &nlen)) 7398c2ecf20Sopenharmony_ci goto out; 7408c2ecf20Sopenharmony_ci if (sidtab_entry_to_string(p, sidtab, tentry, &t, &tlen)) 7418c2ecf20Sopenharmony_ci goto out; 7428c2ecf20Sopenharmony_ci audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR, 7438c2ecf20Sopenharmony_ci "op=security_validate_transition seresult=denied" 7448c2ecf20Sopenharmony_ci " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", 7458c2ecf20Sopenharmony_ci o, n, t, sym_name(p, SYM_CLASSES, tclass-1)); 7468c2ecf20Sopenharmony_ciout: 7478c2ecf20Sopenharmony_ci kfree(o); 7488c2ecf20Sopenharmony_ci kfree(n); 7498c2ecf20Sopenharmony_ci kfree(t); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci if (!enforcing_enabled(state)) 7528c2ecf20Sopenharmony_ci return 0; 7538c2ecf20Sopenharmony_ci return -EPERM; 7548c2ecf20Sopenharmony_ci} 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_cistatic int security_compute_validatetrans(struct selinux_state *state, 7578c2ecf20Sopenharmony_ci u32 oldsid, u32 newsid, u32 tasksid, 7588c2ecf20Sopenharmony_ci u16 orig_tclass, bool user) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct selinux_policy *policy; 7618c2ecf20Sopenharmony_ci struct policydb *policydb; 7628c2ecf20Sopenharmony_ci struct sidtab *sidtab; 7638c2ecf20Sopenharmony_ci struct sidtab_entry *oentry; 7648c2ecf20Sopenharmony_ci struct sidtab_entry *nentry; 7658c2ecf20Sopenharmony_ci struct sidtab_entry *tentry; 7668c2ecf20Sopenharmony_ci struct class_datum *tclass_datum; 7678c2ecf20Sopenharmony_ci struct constraint_node *constraint; 7688c2ecf20Sopenharmony_ci u16 tclass; 7698c2ecf20Sopenharmony_ci int rc = 0; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 7738c2ecf20Sopenharmony_ci return 0; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci rcu_read_lock(); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 7788c2ecf20Sopenharmony_ci policydb = &policy->policydb; 7798c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (!user) 7828c2ecf20Sopenharmony_ci tclass = unmap_class(&policy->map, orig_tclass); 7838c2ecf20Sopenharmony_ci else 7848c2ecf20Sopenharmony_ci tclass = orig_tclass; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (!tclass || tclass > policydb->p_classes.nprim) { 7878c2ecf20Sopenharmony_ci rc = -EINVAL; 7888c2ecf20Sopenharmony_ci goto out; 7898c2ecf20Sopenharmony_ci } 7908c2ecf20Sopenharmony_ci tclass_datum = policydb->class_val_to_struct[tclass - 1]; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci oentry = sidtab_search_entry(sidtab, oldsid); 7938c2ecf20Sopenharmony_ci if (!oentry) { 7948c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 7958c2ecf20Sopenharmony_ci __func__, oldsid); 7968c2ecf20Sopenharmony_ci rc = -EINVAL; 7978c2ecf20Sopenharmony_ci goto out; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci nentry = sidtab_search_entry(sidtab, newsid); 8018c2ecf20Sopenharmony_ci if (!nentry) { 8028c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 8038c2ecf20Sopenharmony_ci __func__, newsid); 8048c2ecf20Sopenharmony_ci rc = -EINVAL; 8058c2ecf20Sopenharmony_ci goto out; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci tentry = sidtab_search_entry(sidtab, tasksid); 8098c2ecf20Sopenharmony_ci if (!tentry) { 8108c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 8118c2ecf20Sopenharmony_ci __func__, tasksid); 8128c2ecf20Sopenharmony_ci rc = -EINVAL; 8138c2ecf20Sopenharmony_ci goto out; 8148c2ecf20Sopenharmony_ci } 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_ci constraint = tclass_datum->validatetrans; 8178c2ecf20Sopenharmony_ci while (constraint) { 8188c2ecf20Sopenharmony_ci if (!constraint_expr_eval(policydb, &oentry->context, 8198c2ecf20Sopenharmony_ci &nentry->context, &tentry->context, 8208c2ecf20Sopenharmony_ci constraint->expr)) { 8218c2ecf20Sopenharmony_ci if (user) 8228c2ecf20Sopenharmony_ci rc = -EPERM; 8238c2ecf20Sopenharmony_ci else 8248c2ecf20Sopenharmony_ci rc = security_validtrans_handle_fail(state, 8258c2ecf20Sopenharmony_ci policy, 8268c2ecf20Sopenharmony_ci oentry, 8278c2ecf20Sopenharmony_ci nentry, 8288c2ecf20Sopenharmony_ci tentry, 8298c2ecf20Sopenharmony_ci tclass); 8308c2ecf20Sopenharmony_ci goto out; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci constraint = constraint->next; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ciout: 8368c2ecf20Sopenharmony_ci rcu_read_unlock(); 8378c2ecf20Sopenharmony_ci return rc; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ciint security_validate_transition_user(struct selinux_state *state, 8418c2ecf20Sopenharmony_ci u32 oldsid, u32 newsid, u32 tasksid, 8428c2ecf20Sopenharmony_ci u16 tclass) 8438c2ecf20Sopenharmony_ci{ 8448c2ecf20Sopenharmony_ci return security_compute_validatetrans(state, oldsid, newsid, tasksid, 8458c2ecf20Sopenharmony_ci tclass, true); 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ciint security_validate_transition(struct selinux_state *state, 8498c2ecf20Sopenharmony_ci u32 oldsid, u32 newsid, u32 tasksid, 8508c2ecf20Sopenharmony_ci u16 orig_tclass) 8518c2ecf20Sopenharmony_ci{ 8528c2ecf20Sopenharmony_ci return security_compute_validatetrans(state, oldsid, newsid, tasksid, 8538c2ecf20Sopenharmony_ci orig_tclass, false); 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci/* 8578c2ecf20Sopenharmony_ci * security_bounded_transition - check whether the given 8588c2ecf20Sopenharmony_ci * transition is directed to bounded, or not. 8598c2ecf20Sopenharmony_ci * It returns 0, if @newsid is bounded by @oldsid. 8608c2ecf20Sopenharmony_ci * Otherwise, it returns error code. 8618c2ecf20Sopenharmony_ci * 8628c2ecf20Sopenharmony_ci * @oldsid : current security identifier 8638c2ecf20Sopenharmony_ci * @newsid : destinated security identifier 8648c2ecf20Sopenharmony_ci */ 8658c2ecf20Sopenharmony_ciint security_bounded_transition(struct selinux_state *state, 8668c2ecf20Sopenharmony_ci u32 old_sid, u32 new_sid) 8678c2ecf20Sopenharmony_ci{ 8688c2ecf20Sopenharmony_ci struct selinux_policy *policy; 8698c2ecf20Sopenharmony_ci struct policydb *policydb; 8708c2ecf20Sopenharmony_ci struct sidtab *sidtab; 8718c2ecf20Sopenharmony_ci struct sidtab_entry *old_entry, *new_entry; 8728c2ecf20Sopenharmony_ci struct type_datum *type; 8738c2ecf20Sopenharmony_ci int index; 8748c2ecf20Sopenharmony_ci int rc; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 8778c2ecf20Sopenharmony_ci return 0; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci rcu_read_lock(); 8808c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 8818c2ecf20Sopenharmony_ci policydb = &policy->policydb; 8828c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci rc = -EINVAL; 8858c2ecf20Sopenharmony_ci old_entry = sidtab_search_entry(sidtab, old_sid); 8868c2ecf20Sopenharmony_ci if (!old_entry) { 8878c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %u\n", 8888c2ecf20Sopenharmony_ci __func__, old_sid); 8898c2ecf20Sopenharmony_ci goto out; 8908c2ecf20Sopenharmony_ci } 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci rc = -EINVAL; 8938c2ecf20Sopenharmony_ci new_entry = sidtab_search_entry(sidtab, new_sid); 8948c2ecf20Sopenharmony_ci if (!new_entry) { 8958c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %u\n", 8968c2ecf20Sopenharmony_ci __func__, new_sid); 8978c2ecf20Sopenharmony_ci goto out; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci rc = 0; 9018c2ecf20Sopenharmony_ci /* type/domain unchanged */ 9028c2ecf20Sopenharmony_ci if (old_entry->context.type == new_entry->context.type) 9038c2ecf20Sopenharmony_ci goto out; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci index = new_entry->context.type; 9068c2ecf20Sopenharmony_ci while (true) { 9078c2ecf20Sopenharmony_ci type = policydb->type_val_to_struct[index - 1]; 9088c2ecf20Sopenharmony_ci BUG_ON(!type); 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci /* not bounded anymore */ 9118c2ecf20Sopenharmony_ci rc = -EPERM; 9128c2ecf20Sopenharmony_ci if (!type->bounds) 9138c2ecf20Sopenharmony_ci break; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci /* @newsid is bounded by @oldsid */ 9168c2ecf20Sopenharmony_ci rc = 0; 9178c2ecf20Sopenharmony_ci if (type->bounds == old_entry->context.type) 9188c2ecf20Sopenharmony_ci break; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci index = type->bounds; 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (rc) { 9248c2ecf20Sopenharmony_ci char *old_name = NULL; 9258c2ecf20Sopenharmony_ci char *new_name = NULL; 9268c2ecf20Sopenharmony_ci u32 length; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (!sidtab_entry_to_string(policydb, sidtab, old_entry, 9298c2ecf20Sopenharmony_ci &old_name, &length) && 9308c2ecf20Sopenharmony_ci !sidtab_entry_to_string(policydb, sidtab, new_entry, 9318c2ecf20Sopenharmony_ci &new_name, &length)) { 9328c2ecf20Sopenharmony_ci audit_log(audit_context(), 9338c2ecf20Sopenharmony_ci GFP_ATOMIC, AUDIT_SELINUX_ERR, 9348c2ecf20Sopenharmony_ci "op=security_bounded_transition " 9358c2ecf20Sopenharmony_ci "seresult=denied " 9368c2ecf20Sopenharmony_ci "oldcontext=%s newcontext=%s", 9378c2ecf20Sopenharmony_ci old_name, new_name); 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci kfree(new_name); 9408c2ecf20Sopenharmony_ci kfree(old_name); 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ciout: 9438c2ecf20Sopenharmony_ci rcu_read_unlock(); 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci return rc; 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic void avd_init(struct selinux_policy *policy, struct av_decision *avd) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci avd->allowed = 0; 9518c2ecf20Sopenharmony_ci avd->auditallow = 0; 9528c2ecf20Sopenharmony_ci avd->auditdeny = 0xffffffff; 9538c2ecf20Sopenharmony_ci if (policy) 9548c2ecf20Sopenharmony_ci avd->seqno = policy->latest_granting; 9558c2ecf20Sopenharmony_ci else 9568c2ecf20Sopenharmony_ci avd->seqno = 0; 9578c2ecf20Sopenharmony_ci avd->flags = 0; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_civoid services_compute_xperms_decision(struct extended_perms_decision *xpermd, 9618c2ecf20Sopenharmony_ci struct avtab_node *node) 9628c2ecf20Sopenharmony_ci{ 9638c2ecf20Sopenharmony_ci unsigned int i; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 9668c2ecf20Sopenharmony_ci if (xpermd->driver != node->datum.u.xperms->driver) 9678c2ecf20Sopenharmony_ci return; 9688c2ecf20Sopenharmony_ci } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 9698c2ecf20Sopenharmony_ci if (!security_xperm_test(node->datum.u.xperms->perms.p, 9708c2ecf20Sopenharmony_ci xpermd->driver)) 9718c2ecf20Sopenharmony_ci return; 9728c2ecf20Sopenharmony_ci } else { 9738c2ecf20Sopenharmony_ci BUG(); 9748c2ecf20Sopenharmony_ci } 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (node->key.specified == AVTAB_XPERMS_ALLOWED) { 9778c2ecf20Sopenharmony_ci xpermd->used |= XPERMS_ALLOWED; 9788c2ecf20Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 9798c2ecf20Sopenharmony_ci memset(xpermd->allowed->p, 0xff, 9808c2ecf20Sopenharmony_ci sizeof(xpermd->allowed->p)); 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 9838c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) 9848c2ecf20Sopenharmony_ci xpermd->allowed->p[i] |= 9858c2ecf20Sopenharmony_ci node->datum.u.xperms->perms.p[i]; 9868c2ecf20Sopenharmony_ci } 9878c2ecf20Sopenharmony_ci } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { 9888c2ecf20Sopenharmony_ci xpermd->used |= XPERMS_AUDITALLOW; 9898c2ecf20Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 9908c2ecf20Sopenharmony_ci memset(xpermd->auditallow->p, 0xff, 9918c2ecf20Sopenharmony_ci sizeof(xpermd->auditallow->p)); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 9948c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) 9958c2ecf20Sopenharmony_ci xpermd->auditallow->p[i] |= 9968c2ecf20Sopenharmony_ci node->datum.u.xperms->perms.p[i]; 9978c2ecf20Sopenharmony_ci } 9988c2ecf20Sopenharmony_ci } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { 9998c2ecf20Sopenharmony_ci xpermd->used |= XPERMS_DONTAUDIT; 10008c2ecf20Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 10018c2ecf20Sopenharmony_ci memset(xpermd->dontaudit->p, 0xff, 10028c2ecf20Sopenharmony_ci sizeof(xpermd->dontaudit->p)); 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 10058c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) 10068c2ecf20Sopenharmony_ci xpermd->dontaudit->p[i] |= 10078c2ecf20Sopenharmony_ci node->datum.u.xperms->perms.p[i]; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci } else { 10108c2ecf20Sopenharmony_ci BUG(); 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci} 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_civoid security_compute_xperms_decision(struct selinux_state *state, 10158c2ecf20Sopenharmony_ci u32 ssid, 10168c2ecf20Sopenharmony_ci u32 tsid, 10178c2ecf20Sopenharmony_ci u16 orig_tclass, 10188c2ecf20Sopenharmony_ci u8 driver, 10198c2ecf20Sopenharmony_ci struct extended_perms_decision *xpermd) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct selinux_policy *policy; 10228c2ecf20Sopenharmony_ci struct policydb *policydb; 10238c2ecf20Sopenharmony_ci struct sidtab *sidtab; 10248c2ecf20Sopenharmony_ci u16 tclass; 10258c2ecf20Sopenharmony_ci struct context *scontext, *tcontext; 10268c2ecf20Sopenharmony_ci struct avtab_key avkey; 10278c2ecf20Sopenharmony_ci struct avtab_node *node; 10288c2ecf20Sopenharmony_ci struct ebitmap *sattr, *tattr; 10298c2ecf20Sopenharmony_ci struct ebitmap_node *snode, *tnode; 10308c2ecf20Sopenharmony_ci unsigned int i, j; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci xpermd->driver = driver; 10338c2ecf20Sopenharmony_ci xpermd->used = 0; 10348c2ecf20Sopenharmony_ci memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p)); 10358c2ecf20Sopenharmony_ci memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); 10368c2ecf20Sopenharmony_ci memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci rcu_read_lock(); 10398c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 10408c2ecf20Sopenharmony_ci goto allow; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 10438c2ecf20Sopenharmony_ci policydb = &policy->policydb; 10448c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci scontext = sidtab_search(sidtab, ssid); 10478c2ecf20Sopenharmony_ci if (!scontext) { 10488c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 10498c2ecf20Sopenharmony_ci __func__, ssid); 10508c2ecf20Sopenharmony_ci goto out; 10518c2ecf20Sopenharmony_ci } 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci tcontext = sidtab_search(sidtab, tsid); 10548c2ecf20Sopenharmony_ci if (!tcontext) { 10558c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 10568c2ecf20Sopenharmony_ci __func__, tsid); 10578c2ecf20Sopenharmony_ci goto out; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci tclass = unmap_class(&policy->map, orig_tclass); 10618c2ecf20Sopenharmony_ci if (unlikely(orig_tclass && !tclass)) { 10628c2ecf20Sopenharmony_ci if (policydb->allow_unknown) 10638c2ecf20Sopenharmony_ci goto allow; 10648c2ecf20Sopenharmony_ci goto out; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) { 10698c2ecf20Sopenharmony_ci pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass); 10708c2ecf20Sopenharmony_ci goto out; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci avkey.target_class = tclass; 10748c2ecf20Sopenharmony_ci avkey.specified = AVTAB_XPERMS; 10758c2ecf20Sopenharmony_ci sattr = &policydb->type_attr_map_array[scontext->type - 1]; 10768c2ecf20Sopenharmony_ci tattr = &policydb->type_attr_map_array[tcontext->type - 1]; 10778c2ecf20Sopenharmony_ci ebitmap_for_each_positive_bit(sattr, snode, i) { 10788c2ecf20Sopenharmony_ci ebitmap_for_each_positive_bit(tattr, tnode, j) { 10798c2ecf20Sopenharmony_ci avkey.source_type = i + 1; 10808c2ecf20Sopenharmony_ci avkey.target_type = j + 1; 10818c2ecf20Sopenharmony_ci for (node = avtab_search_node(&policydb->te_avtab, 10828c2ecf20Sopenharmony_ci &avkey); 10838c2ecf20Sopenharmony_ci node; 10848c2ecf20Sopenharmony_ci node = avtab_search_node_next(node, avkey.specified)) 10858c2ecf20Sopenharmony_ci services_compute_xperms_decision(xpermd, node); 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci cond_compute_xperms(&policydb->te_cond_avtab, 10888c2ecf20Sopenharmony_ci &avkey, xpermd); 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ciout: 10928c2ecf20Sopenharmony_ci rcu_read_unlock(); 10938c2ecf20Sopenharmony_ci return; 10948c2ecf20Sopenharmony_ciallow: 10958c2ecf20Sopenharmony_ci memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); 10968c2ecf20Sopenharmony_ci goto out; 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci/** 11008c2ecf20Sopenharmony_ci * security_compute_av - Compute access vector decisions. 11018c2ecf20Sopenharmony_ci * @ssid: source security identifier 11028c2ecf20Sopenharmony_ci * @tsid: target security identifier 11038c2ecf20Sopenharmony_ci * @tclass: target security class 11048c2ecf20Sopenharmony_ci * @avd: access vector decisions 11058c2ecf20Sopenharmony_ci * @xperms: extended permissions 11068c2ecf20Sopenharmony_ci * 11078c2ecf20Sopenharmony_ci * Compute a set of access vector decisions based on the 11088c2ecf20Sopenharmony_ci * SID pair (@ssid, @tsid) for the permissions in @tclass. 11098c2ecf20Sopenharmony_ci */ 11108c2ecf20Sopenharmony_civoid security_compute_av(struct selinux_state *state, 11118c2ecf20Sopenharmony_ci u32 ssid, 11128c2ecf20Sopenharmony_ci u32 tsid, 11138c2ecf20Sopenharmony_ci u16 orig_tclass, 11148c2ecf20Sopenharmony_ci struct av_decision *avd, 11158c2ecf20Sopenharmony_ci struct extended_perms *xperms) 11168c2ecf20Sopenharmony_ci{ 11178c2ecf20Sopenharmony_ci struct selinux_policy *policy; 11188c2ecf20Sopenharmony_ci struct policydb *policydb; 11198c2ecf20Sopenharmony_ci struct sidtab *sidtab; 11208c2ecf20Sopenharmony_ci u16 tclass; 11218c2ecf20Sopenharmony_ci struct context *scontext = NULL, *tcontext = NULL; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci rcu_read_lock(); 11248c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 11258c2ecf20Sopenharmony_ci avd_init(policy, avd); 11268c2ecf20Sopenharmony_ci xperms->len = 0; 11278c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 11288c2ecf20Sopenharmony_ci goto allow; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci policydb = &policy->policydb; 11318c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci scontext = sidtab_search(sidtab, ssid); 11348c2ecf20Sopenharmony_ci if (!scontext) { 11358c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 11368c2ecf20Sopenharmony_ci __func__, ssid); 11378c2ecf20Sopenharmony_ci goto out; 11388c2ecf20Sopenharmony_ci } 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci /* permissive domain? */ 11418c2ecf20Sopenharmony_ci if (ebitmap_get_bit(&policydb->permissive_map, scontext->type)) 11428c2ecf20Sopenharmony_ci avd->flags |= AVD_FLAGS_PERMISSIVE; 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci tcontext = sidtab_search(sidtab, tsid); 11458c2ecf20Sopenharmony_ci if (!tcontext) { 11468c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 11478c2ecf20Sopenharmony_ci __func__, tsid); 11488c2ecf20Sopenharmony_ci goto out; 11498c2ecf20Sopenharmony_ci } 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci tclass = unmap_class(&policy->map, orig_tclass); 11528c2ecf20Sopenharmony_ci if (unlikely(orig_tclass && !tclass)) { 11538c2ecf20Sopenharmony_ci if (policydb->allow_unknown) 11548c2ecf20Sopenharmony_ci goto allow; 11558c2ecf20Sopenharmony_ci goto out; 11568c2ecf20Sopenharmony_ci } 11578c2ecf20Sopenharmony_ci context_struct_compute_av(policydb, scontext, tcontext, tclass, avd, 11588c2ecf20Sopenharmony_ci xperms); 11598c2ecf20Sopenharmony_ci map_decision(&policy->map, orig_tclass, avd, 11608c2ecf20Sopenharmony_ci policydb->allow_unknown); 11618c2ecf20Sopenharmony_ciout: 11628c2ecf20Sopenharmony_ci rcu_read_unlock(); 11638c2ecf20Sopenharmony_ci return; 11648c2ecf20Sopenharmony_ciallow: 11658c2ecf20Sopenharmony_ci avd->allowed = 0xffffffff; 11668c2ecf20Sopenharmony_ci goto out; 11678c2ecf20Sopenharmony_ci} 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_civoid security_compute_av_user(struct selinux_state *state, 11708c2ecf20Sopenharmony_ci u32 ssid, 11718c2ecf20Sopenharmony_ci u32 tsid, 11728c2ecf20Sopenharmony_ci u16 tclass, 11738c2ecf20Sopenharmony_ci struct av_decision *avd) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci struct selinux_policy *policy; 11768c2ecf20Sopenharmony_ci struct policydb *policydb; 11778c2ecf20Sopenharmony_ci struct sidtab *sidtab; 11788c2ecf20Sopenharmony_ci struct context *scontext = NULL, *tcontext = NULL; 11798c2ecf20Sopenharmony_ci 11808c2ecf20Sopenharmony_ci rcu_read_lock(); 11818c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 11828c2ecf20Sopenharmony_ci avd_init(policy, avd); 11838c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 11848c2ecf20Sopenharmony_ci goto allow; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci policydb = &policy->policydb; 11878c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci scontext = sidtab_search(sidtab, ssid); 11908c2ecf20Sopenharmony_ci if (!scontext) { 11918c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 11928c2ecf20Sopenharmony_ci __func__, ssid); 11938c2ecf20Sopenharmony_ci goto out; 11948c2ecf20Sopenharmony_ci } 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* permissive domain? */ 11978c2ecf20Sopenharmony_ci if (ebitmap_get_bit(&policydb->permissive_map, scontext->type)) 11988c2ecf20Sopenharmony_ci avd->flags |= AVD_FLAGS_PERMISSIVE; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci tcontext = sidtab_search(sidtab, tsid); 12018c2ecf20Sopenharmony_ci if (!tcontext) { 12028c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 12038c2ecf20Sopenharmony_ci __func__, tsid); 12048c2ecf20Sopenharmony_ci goto out; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (unlikely(!tclass)) { 12088c2ecf20Sopenharmony_ci if (policydb->allow_unknown) 12098c2ecf20Sopenharmony_ci goto allow; 12108c2ecf20Sopenharmony_ci goto out; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci context_struct_compute_av(policydb, scontext, tcontext, tclass, avd, 12148c2ecf20Sopenharmony_ci NULL); 12158c2ecf20Sopenharmony_ci out: 12168c2ecf20Sopenharmony_ci rcu_read_unlock(); 12178c2ecf20Sopenharmony_ci return; 12188c2ecf20Sopenharmony_ciallow: 12198c2ecf20Sopenharmony_ci avd->allowed = 0xffffffff; 12208c2ecf20Sopenharmony_ci goto out; 12218c2ecf20Sopenharmony_ci} 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci/* 12248c2ecf20Sopenharmony_ci * Write the security context string representation of 12258c2ecf20Sopenharmony_ci * the context structure `context' into a dynamically 12268c2ecf20Sopenharmony_ci * allocated string of the correct size. Set `*scontext' 12278c2ecf20Sopenharmony_ci * to point to this string and set `*scontext_len' to 12288c2ecf20Sopenharmony_ci * the length of the string. 12298c2ecf20Sopenharmony_ci */ 12308c2ecf20Sopenharmony_cistatic int context_struct_to_string(struct policydb *p, 12318c2ecf20Sopenharmony_ci struct context *context, 12328c2ecf20Sopenharmony_ci char **scontext, u32 *scontext_len) 12338c2ecf20Sopenharmony_ci{ 12348c2ecf20Sopenharmony_ci char *scontextp; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci if (scontext) 12378c2ecf20Sopenharmony_ci *scontext = NULL; 12388c2ecf20Sopenharmony_ci *scontext_len = 0; 12398c2ecf20Sopenharmony_ci 12408c2ecf20Sopenharmony_ci if (context->len) { 12418c2ecf20Sopenharmony_ci *scontext_len = context->len; 12428c2ecf20Sopenharmony_ci if (scontext) { 12438c2ecf20Sopenharmony_ci *scontext = kstrdup(context->str, GFP_ATOMIC); 12448c2ecf20Sopenharmony_ci if (!(*scontext)) 12458c2ecf20Sopenharmony_ci return -ENOMEM; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci return 0; 12488c2ecf20Sopenharmony_ci } 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci /* Compute the size of the context. */ 12518c2ecf20Sopenharmony_ci *scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1; 12528c2ecf20Sopenharmony_ci *scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1; 12538c2ecf20Sopenharmony_ci *scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1; 12548c2ecf20Sopenharmony_ci *scontext_len += mls_compute_context_len(p, context); 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci if (!scontext) 12578c2ecf20Sopenharmony_ci return 0; 12588c2ecf20Sopenharmony_ci 12598c2ecf20Sopenharmony_ci /* Allocate space for the context; caller must free this space. */ 12608c2ecf20Sopenharmony_ci scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 12618c2ecf20Sopenharmony_ci if (!scontextp) 12628c2ecf20Sopenharmony_ci return -ENOMEM; 12638c2ecf20Sopenharmony_ci *scontext = scontextp; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci /* 12668c2ecf20Sopenharmony_ci * Copy the user name, role name and type name into the context. 12678c2ecf20Sopenharmony_ci */ 12688c2ecf20Sopenharmony_ci scontextp += sprintf(scontextp, "%s:%s:%s", 12698c2ecf20Sopenharmony_ci sym_name(p, SYM_USERS, context->user - 1), 12708c2ecf20Sopenharmony_ci sym_name(p, SYM_ROLES, context->role - 1), 12718c2ecf20Sopenharmony_ci sym_name(p, SYM_TYPES, context->type - 1)); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci mls_sid_to_context(p, context, &scontextp); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci *scontextp = 0; 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci return 0; 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic int sidtab_entry_to_string(struct policydb *p, 12818c2ecf20Sopenharmony_ci struct sidtab *sidtab, 12828c2ecf20Sopenharmony_ci struct sidtab_entry *entry, 12838c2ecf20Sopenharmony_ci char **scontext, u32 *scontext_len) 12848c2ecf20Sopenharmony_ci{ 12858c2ecf20Sopenharmony_ci int rc = sidtab_sid2str_get(sidtab, entry, scontext, scontext_len); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci if (rc != -ENOENT) 12888c2ecf20Sopenharmony_ci return rc; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci rc = context_struct_to_string(p, &entry->context, scontext, 12918c2ecf20Sopenharmony_ci scontext_len); 12928c2ecf20Sopenharmony_ci if (!rc && scontext) 12938c2ecf20Sopenharmony_ci sidtab_sid2str_put(sidtab, entry, *scontext, *scontext_len); 12948c2ecf20Sopenharmony_ci return rc; 12958c2ecf20Sopenharmony_ci} 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci#include "initial_sid_to_string.h" 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ciint security_sidtab_hash_stats(struct selinux_state *state, char *page) 13008c2ecf20Sopenharmony_ci{ 13018c2ecf20Sopenharmony_ci struct selinux_policy *policy; 13028c2ecf20Sopenharmony_ci int rc; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 13058c2ecf20Sopenharmony_ci pr_err("SELinux: %s: called before initial load_policy\n", 13068c2ecf20Sopenharmony_ci __func__); 13078c2ecf20Sopenharmony_ci return -EINVAL; 13088c2ecf20Sopenharmony_ci } 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci rcu_read_lock(); 13118c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 13128c2ecf20Sopenharmony_ci rc = sidtab_hash_stats(policy->sidtab, page); 13138c2ecf20Sopenharmony_ci rcu_read_unlock(); 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci return rc; 13168c2ecf20Sopenharmony_ci} 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ciconst char *security_get_initial_sid_context(u32 sid) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci if (unlikely(sid > SECINITSID_NUM)) 13218c2ecf20Sopenharmony_ci return NULL; 13228c2ecf20Sopenharmony_ci return initial_sid_to_string[sid]; 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_cistatic int security_sid_to_context_core(struct selinux_state *state, 13268c2ecf20Sopenharmony_ci u32 sid, char **scontext, 13278c2ecf20Sopenharmony_ci u32 *scontext_len, int force, 13288c2ecf20Sopenharmony_ci int only_invalid) 13298c2ecf20Sopenharmony_ci{ 13308c2ecf20Sopenharmony_ci struct selinux_policy *policy; 13318c2ecf20Sopenharmony_ci struct policydb *policydb; 13328c2ecf20Sopenharmony_ci struct sidtab *sidtab; 13338c2ecf20Sopenharmony_ci struct sidtab_entry *entry; 13348c2ecf20Sopenharmony_ci int rc = 0; 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci if (scontext) 13378c2ecf20Sopenharmony_ci *scontext = NULL; 13388c2ecf20Sopenharmony_ci *scontext_len = 0; 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 13418c2ecf20Sopenharmony_ci if (sid <= SECINITSID_NUM) { 13428c2ecf20Sopenharmony_ci char *scontextp; 13438c2ecf20Sopenharmony_ci const char *s = initial_sid_to_string[sid]; 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci if (!s) 13468c2ecf20Sopenharmony_ci return -EINVAL; 13478c2ecf20Sopenharmony_ci *scontext_len = strlen(s) + 1; 13488c2ecf20Sopenharmony_ci if (!scontext) 13498c2ecf20Sopenharmony_ci return 0; 13508c2ecf20Sopenharmony_ci scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC); 13518c2ecf20Sopenharmony_ci if (!scontextp) 13528c2ecf20Sopenharmony_ci return -ENOMEM; 13538c2ecf20Sopenharmony_ci *scontext = scontextp; 13548c2ecf20Sopenharmony_ci return 0; 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci pr_err("SELinux: %s: called before initial " 13578c2ecf20Sopenharmony_ci "load_policy on unknown SID %d\n", __func__, sid); 13588c2ecf20Sopenharmony_ci return -EINVAL; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci rcu_read_lock(); 13618c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 13628c2ecf20Sopenharmony_ci policydb = &policy->policydb; 13638c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci if (force) 13668c2ecf20Sopenharmony_ci entry = sidtab_search_entry_force(sidtab, sid); 13678c2ecf20Sopenharmony_ci else 13688c2ecf20Sopenharmony_ci entry = sidtab_search_entry(sidtab, sid); 13698c2ecf20Sopenharmony_ci if (!entry) { 13708c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 13718c2ecf20Sopenharmony_ci __func__, sid); 13728c2ecf20Sopenharmony_ci rc = -EINVAL; 13738c2ecf20Sopenharmony_ci goto out_unlock; 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci if (only_invalid && !entry->context.len) 13768c2ecf20Sopenharmony_ci goto out_unlock; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci rc = sidtab_entry_to_string(policydb, sidtab, entry, scontext, 13798c2ecf20Sopenharmony_ci scontext_len); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ciout_unlock: 13828c2ecf20Sopenharmony_ci rcu_read_unlock(); 13838c2ecf20Sopenharmony_ci return rc; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci} 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci/** 13888c2ecf20Sopenharmony_ci * security_sid_to_context - Obtain a context for a given SID. 13898c2ecf20Sopenharmony_ci * @sid: security identifier, SID 13908c2ecf20Sopenharmony_ci * @scontext: security context 13918c2ecf20Sopenharmony_ci * @scontext_len: length in bytes 13928c2ecf20Sopenharmony_ci * 13938c2ecf20Sopenharmony_ci * Write the string representation of the context associated with @sid 13948c2ecf20Sopenharmony_ci * into a dynamically allocated string of the correct size. Set @scontext 13958c2ecf20Sopenharmony_ci * to point to this string and set @scontext_len to the length of the string. 13968c2ecf20Sopenharmony_ci */ 13978c2ecf20Sopenharmony_ciint security_sid_to_context(struct selinux_state *state, 13988c2ecf20Sopenharmony_ci u32 sid, char **scontext, u32 *scontext_len) 13998c2ecf20Sopenharmony_ci{ 14008c2ecf20Sopenharmony_ci return security_sid_to_context_core(state, sid, scontext, 14018c2ecf20Sopenharmony_ci scontext_len, 0, 0); 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ciint security_sid_to_context_force(struct selinux_state *state, u32 sid, 14058c2ecf20Sopenharmony_ci char **scontext, u32 *scontext_len) 14068c2ecf20Sopenharmony_ci{ 14078c2ecf20Sopenharmony_ci return security_sid_to_context_core(state, sid, scontext, 14088c2ecf20Sopenharmony_ci scontext_len, 1, 0); 14098c2ecf20Sopenharmony_ci} 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci/** 14128c2ecf20Sopenharmony_ci * security_sid_to_context_inval - Obtain a context for a given SID if it 14138c2ecf20Sopenharmony_ci * is invalid. 14148c2ecf20Sopenharmony_ci * @sid: security identifier, SID 14158c2ecf20Sopenharmony_ci * @scontext: security context 14168c2ecf20Sopenharmony_ci * @scontext_len: length in bytes 14178c2ecf20Sopenharmony_ci * 14188c2ecf20Sopenharmony_ci * Write the string representation of the context associated with @sid 14198c2ecf20Sopenharmony_ci * into a dynamically allocated string of the correct size, but only if the 14208c2ecf20Sopenharmony_ci * context is invalid in the current policy. Set @scontext to point to 14218c2ecf20Sopenharmony_ci * this string (or NULL if the context is valid) and set @scontext_len to 14228c2ecf20Sopenharmony_ci * the length of the string (or 0 if the context is valid). 14238c2ecf20Sopenharmony_ci */ 14248c2ecf20Sopenharmony_ciint security_sid_to_context_inval(struct selinux_state *state, u32 sid, 14258c2ecf20Sopenharmony_ci char **scontext, u32 *scontext_len) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci return security_sid_to_context_core(state, sid, scontext, 14288c2ecf20Sopenharmony_ci scontext_len, 1, 1); 14298c2ecf20Sopenharmony_ci} 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci/* 14328c2ecf20Sopenharmony_ci * Caveat: Mutates scontext. 14338c2ecf20Sopenharmony_ci */ 14348c2ecf20Sopenharmony_cistatic int string_to_context_struct(struct policydb *pol, 14358c2ecf20Sopenharmony_ci struct sidtab *sidtabp, 14368c2ecf20Sopenharmony_ci char *scontext, 14378c2ecf20Sopenharmony_ci struct context *ctx, 14388c2ecf20Sopenharmony_ci u32 def_sid) 14398c2ecf20Sopenharmony_ci{ 14408c2ecf20Sopenharmony_ci struct role_datum *role; 14418c2ecf20Sopenharmony_ci struct type_datum *typdatum; 14428c2ecf20Sopenharmony_ci struct user_datum *usrdatum; 14438c2ecf20Sopenharmony_ci char *scontextp, *p, oldc; 14448c2ecf20Sopenharmony_ci int rc = 0; 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci context_init(ctx); 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci /* Parse the security context. */ 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci rc = -EINVAL; 14518c2ecf20Sopenharmony_ci scontextp = (char *) scontext; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci /* Extract the user. */ 14548c2ecf20Sopenharmony_ci p = scontextp; 14558c2ecf20Sopenharmony_ci while (*p && *p != ':') 14568c2ecf20Sopenharmony_ci p++; 14578c2ecf20Sopenharmony_ci 14588c2ecf20Sopenharmony_ci if (*p == 0) 14598c2ecf20Sopenharmony_ci goto out; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci *p++ = 0; 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci usrdatum = symtab_search(&pol->p_users, scontextp); 14648c2ecf20Sopenharmony_ci if (!usrdatum) 14658c2ecf20Sopenharmony_ci goto out; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci ctx->user = usrdatum->value; 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_ci /* Extract role. */ 14708c2ecf20Sopenharmony_ci scontextp = p; 14718c2ecf20Sopenharmony_ci while (*p && *p != ':') 14728c2ecf20Sopenharmony_ci p++; 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_ci if (*p == 0) 14758c2ecf20Sopenharmony_ci goto out; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci *p++ = 0; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci role = symtab_search(&pol->p_roles, scontextp); 14808c2ecf20Sopenharmony_ci if (!role) 14818c2ecf20Sopenharmony_ci goto out; 14828c2ecf20Sopenharmony_ci ctx->role = role->value; 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci /* Extract type. */ 14858c2ecf20Sopenharmony_ci scontextp = p; 14868c2ecf20Sopenharmony_ci while (*p && *p != ':') 14878c2ecf20Sopenharmony_ci p++; 14888c2ecf20Sopenharmony_ci oldc = *p; 14898c2ecf20Sopenharmony_ci *p++ = 0; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci typdatum = symtab_search(&pol->p_types, scontextp); 14928c2ecf20Sopenharmony_ci if (!typdatum || typdatum->attribute) 14938c2ecf20Sopenharmony_ci goto out; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci ctx->type = typdatum->value; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid); 14988c2ecf20Sopenharmony_ci if (rc) 14998c2ecf20Sopenharmony_ci goto out; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci /* Check the validity of the new context. */ 15028c2ecf20Sopenharmony_ci rc = -EINVAL; 15038c2ecf20Sopenharmony_ci if (!policydb_context_isvalid(pol, ctx)) 15048c2ecf20Sopenharmony_ci goto out; 15058c2ecf20Sopenharmony_ci rc = 0; 15068c2ecf20Sopenharmony_ciout: 15078c2ecf20Sopenharmony_ci if (rc) 15088c2ecf20Sopenharmony_ci context_destroy(ctx); 15098c2ecf20Sopenharmony_ci return rc; 15108c2ecf20Sopenharmony_ci} 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_cistatic int security_context_to_sid_core(struct selinux_state *state, 15138c2ecf20Sopenharmony_ci const char *scontext, u32 scontext_len, 15148c2ecf20Sopenharmony_ci u32 *sid, u32 def_sid, gfp_t gfp_flags, 15158c2ecf20Sopenharmony_ci int force) 15168c2ecf20Sopenharmony_ci{ 15178c2ecf20Sopenharmony_ci struct selinux_policy *policy; 15188c2ecf20Sopenharmony_ci struct policydb *policydb; 15198c2ecf20Sopenharmony_ci struct sidtab *sidtab; 15208c2ecf20Sopenharmony_ci char *scontext2, *str = NULL; 15218c2ecf20Sopenharmony_ci struct context context; 15228c2ecf20Sopenharmony_ci int rc = 0; 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci /* An empty security context is never valid. */ 15258c2ecf20Sopenharmony_ci if (!scontext_len) 15268c2ecf20Sopenharmony_ci return -EINVAL; 15278c2ecf20Sopenharmony_ci 15288c2ecf20Sopenharmony_ci /* Copy the string to allow changes and ensure a NUL terminator */ 15298c2ecf20Sopenharmony_ci scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags); 15308c2ecf20Sopenharmony_ci if (!scontext2) 15318c2ecf20Sopenharmony_ci return -ENOMEM; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 15348c2ecf20Sopenharmony_ci int i; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci for (i = 1; i < SECINITSID_NUM; i++) { 15378c2ecf20Sopenharmony_ci const char *s = initial_sid_to_string[i]; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci if (s && !strcmp(s, scontext2)) { 15408c2ecf20Sopenharmony_ci *sid = i; 15418c2ecf20Sopenharmony_ci goto out; 15428c2ecf20Sopenharmony_ci } 15438c2ecf20Sopenharmony_ci } 15448c2ecf20Sopenharmony_ci *sid = SECINITSID_KERNEL; 15458c2ecf20Sopenharmony_ci goto out; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci *sid = SECSID_NULL; 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (force) { 15508c2ecf20Sopenharmony_ci /* Save another copy for storing in uninterpreted form */ 15518c2ecf20Sopenharmony_ci rc = -ENOMEM; 15528c2ecf20Sopenharmony_ci str = kstrdup(scontext2, gfp_flags); 15538c2ecf20Sopenharmony_ci if (!str) 15548c2ecf20Sopenharmony_ci goto out; 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ciretry: 15578c2ecf20Sopenharmony_ci rcu_read_lock(); 15588c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 15598c2ecf20Sopenharmony_ci policydb = &policy->policydb; 15608c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 15618c2ecf20Sopenharmony_ci rc = string_to_context_struct(policydb, sidtab, scontext2, 15628c2ecf20Sopenharmony_ci &context, def_sid); 15638c2ecf20Sopenharmony_ci if (rc == -EINVAL && force) { 15648c2ecf20Sopenharmony_ci context.str = str; 15658c2ecf20Sopenharmony_ci context.len = strlen(str) + 1; 15668c2ecf20Sopenharmony_ci str = NULL; 15678c2ecf20Sopenharmony_ci } else if (rc) 15688c2ecf20Sopenharmony_ci goto out_unlock; 15698c2ecf20Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &context, sid); 15708c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 15718c2ecf20Sopenharmony_ci rcu_read_unlock(); 15728c2ecf20Sopenharmony_ci if (context.str) { 15738c2ecf20Sopenharmony_ci str = context.str; 15748c2ecf20Sopenharmony_ci context.str = NULL; 15758c2ecf20Sopenharmony_ci } 15768c2ecf20Sopenharmony_ci context_destroy(&context); 15778c2ecf20Sopenharmony_ci goto retry; 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci context_destroy(&context); 15808c2ecf20Sopenharmony_ciout_unlock: 15818c2ecf20Sopenharmony_ci rcu_read_unlock(); 15828c2ecf20Sopenharmony_ciout: 15838c2ecf20Sopenharmony_ci kfree(scontext2); 15848c2ecf20Sopenharmony_ci kfree(str); 15858c2ecf20Sopenharmony_ci return rc; 15868c2ecf20Sopenharmony_ci} 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci/** 15898c2ecf20Sopenharmony_ci * security_context_to_sid - Obtain a SID for a given security context. 15908c2ecf20Sopenharmony_ci * @scontext: security context 15918c2ecf20Sopenharmony_ci * @scontext_len: length in bytes 15928c2ecf20Sopenharmony_ci * @sid: security identifier, SID 15938c2ecf20Sopenharmony_ci * @gfp: context for the allocation 15948c2ecf20Sopenharmony_ci * 15958c2ecf20Sopenharmony_ci * Obtains a SID associated with the security context that 15968c2ecf20Sopenharmony_ci * has the string representation specified by @scontext. 15978c2ecf20Sopenharmony_ci * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 15988c2ecf20Sopenharmony_ci * memory is available, or 0 on success. 15998c2ecf20Sopenharmony_ci */ 16008c2ecf20Sopenharmony_ciint security_context_to_sid(struct selinux_state *state, 16018c2ecf20Sopenharmony_ci const char *scontext, u32 scontext_len, u32 *sid, 16028c2ecf20Sopenharmony_ci gfp_t gfp) 16038c2ecf20Sopenharmony_ci{ 16048c2ecf20Sopenharmony_ci return security_context_to_sid_core(state, scontext, scontext_len, 16058c2ecf20Sopenharmony_ci sid, SECSID_NULL, gfp, 0); 16068c2ecf20Sopenharmony_ci} 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ciint security_context_str_to_sid(struct selinux_state *state, 16098c2ecf20Sopenharmony_ci const char *scontext, u32 *sid, gfp_t gfp) 16108c2ecf20Sopenharmony_ci{ 16118c2ecf20Sopenharmony_ci return security_context_to_sid(state, scontext, strlen(scontext), 16128c2ecf20Sopenharmony_ci sid, gfp); 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci/** 16168c2ecf20Sopenharmony_ci * security_context_to_sid_default - Obtain a SID for a given security context, 16178c2ecf20Sopenharmony_ci * falling back to specified default if needed. 16188c2ecf20Sopenharmony_ci * 16198c2ecf20Sopenharmony_ci * @scontext: security context 16208c2ecf20Sopenharmony_ci * @scontext_len: length in bytes 16218c2ecf20Sopenharmony_ci * @sid: security identifier, SID 16228c2ecf20Sopenharmony_ci * @def_sid: default SID to assign on error 16238c2ecf20Sopenharmony_ci * 16248c2ecf20Sopenharmony_ci * Obtains a SID associated with the security context that 16258c2ecf20Sopenharmony_ci * has the string representation specified by @scontext. 16268c2ecf20Sopenharmony_ci * The default SID is passed to the MLS layer to be used to allow 16278c2ecf20Sopenharmony_ci * kernel labeling of the MLS field if the MLS field is not present 16288c2ecf20Sopenharmony_ci * (for upgrading to MLS without full relabel). 16298c2ecf20Sopenharmony_ci * Implicitly forces adding of the context even if it cannot be mapped yet. 16308c2ecf20Sopenharmony_ci * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 16318c2ecf20Sopenharmony_ci * memory is available, or 0 on success. 16328c2ecf20Sopenharmony_ci */ 16338c2ecf20Sopenharmony_ciint security_context_to_sid_default(struct selinux_state *state, 16348c2ecf20Sopenharmony_ci const char *scontext, u32 scontext_len, 16358c2ecf20Sopenharmony_ci u32 *sid, u32 def_sid, gfp_t gfp_flags) 16368c2ecf20Sopenharmony_ci{ 16378c2ecf20Sopenharmony_ci return security_context_to_sid_core(state, scontext, scontext_len, 16388c2ecf20Sopenharmony_ci sid, def_sid, gfp_flags, 1); 16398c2ecf20Sopenharmony_ci} 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ciint security_context_to_sid_force(struct selinux_state *state, 16428c2ecf20Sopenharmony_ci const char *scontext, u32 scontext_len, 16438c2ecf20Sopenharmony_ci u32 *sid) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci return security_context_to_sid_core(state, scontext, scontext_len, 16468c2ecf20Sopenharmony_ci sid, SECSID_NULL, GFP_KERNEL, 1); 16478c2ecf20Sopenharmony_ci} 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_cistatic int compute_sid_handle_invalid_context( 16508c2ecf20Sopenharmony_ci struct selinux_state *state, 16518c2ecf20Sopenharmony_ci struct selinux_policy *policy, 16528c2ecf20Sopenharmony_ci struct sidtab_entry *sentry, 16538c2ecf20Sopenharmony_ci struct sidtab_entry *tentry, 16548c2ecf20Sopenharmony_ci u16 tclass, 16558c2ecf20Sopenharmony_ci struct context *newcontext) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci struct policydb *policydb = &policy->policydb; 16588c2ecf20Sopenharmony_ci struct sidtab *sidtab = policy->sidtab; 16598c2ecf20Sopenharmony_ci char *s = NULL, *t = NULL, *n = NULL; 16608c2ecf20Sopenharmony_ci u32 slen, tlen, nlen; 16618c2ecf20Sopenharmony_ci struct audit_buffer *ab; 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ci if (sidtab_entry_to_string(policydb, sidtab, sentry, &s, &slen)) 16648c2ecf20Sopenharmony_ci goto out; 16658c2ecf20Sopenharmony_ci if (sidtab_entry_to_string(policydb, sidtab, tentry, &t, &tlen)) 16668c2ecf20Sopenharmony_ci goto out; 16678c2ecf20Sopenharmony_ci if (context_struct_to_string(policydb, newcontext, &n, &nlen)) 16688c2ecf20Sopenharmony_ci goto out; 16698c2ecf20Sopenharmony_ci ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR); 16708c2ecf20Sopenharmony_ci audit_log_format(ab, 16718c2ecf20Sopenharmony_ci "op=security_compute_sid invalid_context="); 16728c2ecf20Sopenharmony_ci /* no need to record the NUL with untrusted strings */ 16738c2ecf20Sopenharmony_ci audit_log_n_untrustedstring(ab, n, nlen - 1); 16748c2ecf20Sopenharmony_ci audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s", 16758c2ecf20Sopenharmony_ci s, t, sym_name(policydb, SYM_CLASSES, tclass-1)); 16768c2ecf20Sopenharmony_ci audit_log_end(ab); 16778c2ecf20Sopenharmony_ciout: 16788c2ecf20Sopenharmony_ci kfree(s); 16798c2ecf20Sopenharmony_ci kfree(t); 16808c2ecf20Sopenharmony_ci kfree(n); 16818c2ecf20Sopenharmony_ci if (!enforcing_enabled(state)) 16828c2ecf20Sopenharmony_ci return 0; 16838c2ecf20Sopenharmony_ci return -EACCES; 16848c2ecf20Sopenharmony_ci} 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_cistatic void filename_compute_type(struct policydb *policydb, 16878c2ecf20Sopenharmony_ci struct context *newcontext, 16888c2ecf20Sopenharmony_ci u32 stype, u32 ttype, u16 tclass, 16898c2ecf20Sopenharmony_ci const char *objname) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci struct filename_trans_key ft; 16928c2ecf20Sopenharmony_ci struct filename_trans_datum *datum; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci /* 16958c2ecf20Sopenharmony_ci * Most filename trans rules are going to live in specific directories 16968c2ecf20Sopenharmony_ci * like /dev or /var/run. This bitmap will quickly skip rule searches 16978c2ecf20Sopenharmony_ci * if the ttype does not contain any rules. 16988c2ecf20Sopenharmony_ci */ 16998c2ecf20Sopenharmony_ci if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype)) 17008c2ecf20Sopenharmony_ci return; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci ft.ttype = ttype; 17038c2ecf20Sopenharmony_ci ft.tclass = tclass; 17048c2ecf20Sopenharmony_ci ft.name = objname; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci datum = policydb_filenametr_search(policydb, &ft); 17078c2ecf20Sopenharmony_ci while (datum) { 17088c2ecf20Sopenharmony_ci if (ebitmap_get_bit(&datum->stypes, stype - 1)) { 17098c2ecf20Sopenharmony_ci newcontext->type = datum->otype; 17108c2ecf20Sopenharmony_ci return; 17118c2ecf20Sopenharmony_ci } 17128c2ecf20Sopenharmony_ci datum = datum->next; 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci} 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_cistatic int security_compute_sid(struct selinux_state *state, 17178c2ecf20Sopenharmony_ci u32 ssid, 17188c2ecf20Sopenharmony_ci u32 tsid, 17198c2ecf20Sopenharmony_ci u16 orig_tclass, 17208c2ecf20Sopenharmony_ci u32 specified, 17218c2ecf20Sopenharmony_ci const char *objname, 17228c2ecf20Sopenharmony_ci u32 *out_sid, 17238c2ecf20Sopenharmony_ci bool kern) 17248c2ecf20Sopenharmony_ci{ 17258c2ecf20Sopenharmony_ci struct selinux_policy *policy; 17268c2ecf20Sopenharmony_ci struct policydb *policydb; 17278c2ecf20Sopenharmony_ci struct sidtab *sidtab; 17288c2ecf20Sopenharmony_ci struct class_datum *cladatum; 17298c2ecf20Sopenharmony_ci struct context *scontext, *tcontext, newcontext; 17308c2ecf20Sopenharmony_ci struct sidtab_entry *sentry, *tentry; 17318c2ecf20Sopenharmony_ci struct avtab_key avkey; 17328c2ecf20Sopenharmony_ci struct avtab_datum *avdatum; 17338c2ecf20Sopenharmony_ci struct avtab_node *node; 17348c2ecf20Sopenharmony_ci u16 tclass; 17358c2ecf20Sopenharmony_ci int rc = 0; 17368c2ecf20Sopenharmony_ci bool sock; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 17398c2ecf20Sopenharmony_ci switch (orig_tclass) { 17408c2ecf20Sopenharmony_ci case SECCLASS_PROCESS: /* kernel value */ 17418c2ecf20Sopenharmony_ci *out_sid = ssid; 17428c2ecf20Sopenharmony_ci break; 17438c2ecf20Sopenharmony_ci default: 17448c2ecf20Sopenharmony_ci *out_sid = tsid; 17458c2ecf20Sopenharmony_ci break; 17468c2ecf20Sopenharmony_ci } 17478c2ecf20Sopenharmony_ci goto out; 17488c2ecf20Sopenharmony_ci } 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ciretry: 17518c2ecf20Sopenharmony_ci cladatum = NULL; 17528c2ecf20Sopenharmony_ci context_init(&newcontext); 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci rcu_read_lock(); 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci if (kern) { 17598c2ecf20Sopenharmony_ci tclass = unmap_class(&policy->map, orig_tclass); 17608c2ecf20Sopenharmony_ci sock = security_is_socket_class(orig_tclass); 17618c2ecf20Sopenharmony_ci } else { 17628c2ecf20Sopenharmony_ci tclass = orig_tclass; 17638c2ecf20Sopenharmony_ci sock = security_is_socket_class(map_class(&policy->map, 17648c2ecf20Sopenharmony_ci tclass)); 17658c2ecf20Sopenharmony_ci } 17668c2ecf20Sopenharmony_ci 17678c2ecf20Sopenharmony_ci policydb = &policy->policydb; 17688c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 17698c2ecf20Sopenharmony_ci 17708c2ecf20Sopenharmony_ci sentry = sidtab_search_entry(sidtab, ssid); 17718c2ecf20Sopenharmony_ci if (!sentry) { 17728c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 17738c2ecf20Sopenharmony_ci __func__, ssid); 17748c2ecf20Sopenharmony_ci rc = -EINVAL; 17758c2ecf20Sopenharmony_ci goto out_unlock; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci tentry = sidtab_search_entry(sidtab, tsid); 17788c2ecf20Sopenharmony_ci if (!tentry) { 17798c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 17808c2ecf20Sopenharmony_ci __func__, tsid); 17818c2ecf20Sopenharmony_ci rc = -EINVAL; 17828c2ecf20Sopenharmony_ci goto out_unlock; 17838c2ecf20Sopenharmony_ci } 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci scontext = &sentry->context; 17868c2ecf20Sopenharmony_ci tcontext = &tentry->context; 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci if (tclass && tclass <= policydb->p_classes.nprim) 17898c2ecf20Sopenharmony_ci cladatum = policydb->class_val_to_struct[tclass - 1]; 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci /* Set the user identity. */ 17928c2ecf20Sopenharmony_ci switch (specified) { 17938c2ecf20Sopenharmony_ci case AVTAB_TRANSITION: 17948c2ecf20Sopenharmony_ci case AVTAB_CHANGE: 17958c2ecf20Sopenharmony_ci if (cladatum && cladatum->default_user == DEFAULT_TARGET) { 17968c2ecf20Sopenharmony_ci newcontext.user = tcontext->user; 17978c2ecf20Sopenharmony_ci } else { 17988c2ecf20Sopenharmony_ci /* notice this gets both DEFAULT_SOURCE and unset */ 17998c2ecf20Sopenharmony_ci /* Use the process user identity. */ 18008c2ecf20Sopenharmony_ci newcontext.user = scontext->user; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci break; 18038c2ecf20Sopenharmony_ci case AVTAB_MEMBER: 18048c2ecf20Sopenharmony_ci /* Use the related object owner. */ 18058c2ecf20Sopenharmony_ci newcontext.user = tcontext->user; 18068c2ecf20Sopenharmony_ci break; 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_ci /* Set the role to default values. */ 18108c2ecf20Sopenharmony_ci if (cladatum && cladatum->default_role == DEFAULT_SOURCE) { 18118c2ecf20Sopenharmony_ci newcontext.role = scontext->role; 18128c2ecf20Sopenharmony_ci } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { 18138c2ecf20Sopenharmony_ci newcontext.role = tcontext->role; 18148c2ecf20Sopenharmony_ci } else { 18158c2ecf20Sopenharmony_ci if ((tclass == policydb->process_class) || sock) 18168c2ecf20Sopenharmony_ci newcontext.role = scontext->role; 18178c2ecf20Sopenharmony_ci else 18188c2ecf20Sopenharmony_ci newcontext.role = OBJECT_R_VAL; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_ci /* Set the type to default values. */ 18228c2ecf20Sopenharmony_ci if (cladatum && cladatum->default_type == DEFAULT_SOURCE) { 18238c2ecf20Sopenharmony_ci newcontext.type = scontext->type; 18248c2ecf20Sopenharmony_ci } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) { 18258c2ecf20Sopenharmony_ci newcontext.type = tcontext->type; 18268c2ecf20Sopenharmony_ci } else { 18278c2ecf20Sopenharmony_ci if ((tclass == policydb->process_class) || sock) { 18288c2ecf20Sopenharmony_ci /* Use the type of process. */ 18298c2ecf20Sopenharmony_ci newcontext.type = scontext->type; 18308c2ecf20Sopenharmony_ci } else { 18318c2ecf20Sopenharmony_ci /* Use the type of the related object. */ 18328c2ecf20Sopenharmony_ci newcontext.type = tcontext->type; 18338c2ecf20Sopenharmony_ci } 18348c2ecf20Sopenharmony_ci } 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci /* Look for a type transition/member/change rule. */ 18378c2ecf20Sopenharmony_ci avkey.source_type = scontext->type; 18388c2ecf20Sopenharmony_ci avkey.target_type = tcontext->type; 18398c2ecf20Sopenharmony_ci avkey.target_class = tclass; 18408c2ecf20Sopenharmony_ci avkey.specified = specified; 18418c2ecf20Sopenharmony_ci avdatum = avtab_search(&policydb->te_avtab, &avkey); 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci /* If no permanent rule, also check for enabled conditional rules */ 18448c2ecf20Sopenharmony_ci if (!avdatum) { 18458c2ecf20Sopenharmony_ci node = avtab_search_node(&policydb->te_cond_avtab, &avkey); 18468c2ecf20Sopenharmony_ci for (; node; node = avtab_search_node_next(node, specified)) { 18478c2ecf20Sopenharmony_ci if (node->key.specified & AVTAB_ENABLED) { 18488c2ecf20Sopenharmony_ci avdatum = &node->datum; 18498c2ecf20Sopenharmony_ci break; 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci } 18528c2ecf20Sopenharmony_ci } 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci if (avdatum) { 18558c2ecf20Sopenharmony_ci /* Use the type from the type transition/member/change rule. */ 18568c2ecf20Sopenharmony_ci newcontext.type = avdatum->u.data; 18578c2ecf20Sopenharmony_ci } 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci /* if we have a objname this is a file trans check so check those rules */ 18608c2ecf20Sopenharmony_ci if (objname) 18618c2ecf20Sopenharmony_ci filename_compute_type(policydb, &newcontext, scontext->type, 18628c2ecf20Sopenharmony_ci tcontext->type, tclass, objname); 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci /* Check for class-specific changes. */ 18658c2ecf20Sopenharmony_ci if (specified & AVTAB_TRANSITION) { 18668c2ecf20Sopenharmony_ci /* Look for a role transition rule. */ 18678c2ecf20Sopenharmony_ci struct role_trans_datum *rtd; 18688c2ecf20Sopenharmony_ci struct role_trans_key rtk = { 18698c2ecf20Sopenharmony_ci .role = scontext->role, 18708c2ecf20Sopenharmony_ci .type = tcontext->type, 18718c2ecf20Sopenharmony_ci .tclass = tclass, 18728c2ecf20Sopenharmony_ci }; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci rtd = policydb_roletr_search(policydb, &rtk); 18758c2ecf20Sopenharmony_ci if (rtd) 18768c2ecf20Sopenharmony_ci newcontext.role = rtd->new_role; 18778c2ecf20Sopenharmony_ci } 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci /* Set the MLS attributes. 18808c2ecf20Sopenharmony_ci This is done last because it may allocate memory. */ 18818c2ecf20Sopenharmony_ci rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified, 18828c2ecf20Sopenharmony_ci &newcontext, sock); 18838c2ecf20Sopenharmony_ci if (rc) 18848c2ecf20Sopenharmony_ci goto out_unlock; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci /* Check the validity of the context. */ 18878c2ecf20Sopenharmony_ci if (!policydb_context_isvalid(policydb, &newcontext)) { 18888c2ecf20Sopenharmony_ci rc = compute_sid_handle_invalid_context(state, policy, sentry, 18898c2ecf20Sopenharmony_ci tentry, tclass, 18908c2ecf20Sopenharmony_ci &newcontext); 18918c2ecf20Sopenharmony_ci if (rc) 18928c2ecf20Sopenharmony_ci goto out_unlock; 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci /* Obtain the sid for the context. */ 18958c2ecf20Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid); 18968c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 18978c2ecf20Sopenharmony_ci rcu_read_unlock(); 18988c2ecf20Sopenharmony_ci context_destroy(&newcontext); 18998c2ecf20Sopenharmony_ci goto retry; 19008c2ecf20Sopenharmony_ci } 19018c2ecf20Sopenharmony_ciout_unlock: 19028c2ecf20Sopenharmony_ci rcu_read_unlock(); 19038c2ecf20Sopenharmony_ci context_destroy(&newcontext); 19048c2ecf20Sopenharmony_ciout: 19058c2ecf20Sopenharmony_ci return rc; 19068c2ecf20Sopenharmony_ci} 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci/** 19098c2ecf20Sopenharmony_ci * security_transition_sid - Compute the SID for a new subject/object. 19108c2ecf20Sopenharmony_ci * @ssid: source security identifier 19118c2ecf20Sopenharmony_ci * @tsid: target security identifier 19128c2ecf20Sopenharmony_ci * @tclass: target security class 19138c2ecf20Sopenharmony_ci * @out_sid: security identifier for new subject/object 19148c2ecf20Sopenharmony_ci * 19158c2ecf20Sopenharmony_ci * Compute a SID to use for labeling a new subject or object in the 19168c2ecf20Sopenharmony_ci * class @tclass based on a SID pair (@ssid, @tsid). 19178c2ecf20Sopenharmony_ci * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 19188c2ecf20Sopenharmony_ci * if insufficient memory is available, or %0 if the new SID was 19198c2ecf20Sopenharmony_ci * computed successfully. 19208c2ecf20Sopenharmony_ci */ 19218c2ecf20Sopenharmony_ciint security_transition_sid(struct selinux_state *state, 19228c2ecf20Sopenharmony_ci u32 ssid, u32 tsid, u16 tclass, 19238c2ecf20Sopenharmony_ci const struct qstr *qstr, u32 *out_sid) 19248c2ecf20Sopenharmony_ci{ 19258c2ecf20Sopenharmony_ci return security_compute_sid(state, ssid, tsid, tclass, 19268c2ecf20Sopenharmony_ci AVTAB_TRANSITION, 19278c2ecf20Sopenharmony_ci qstr ? qstr->name : NULL, out_sid, true); 19288c2ecf20Sopenharmony_ci} 19298c2ecf20Sopenharmony_ci 19308c2ecf20Sopenharmony_ciint security_transition_sid_user(struct selinux_state *state, 19318c2ecf20Sopenharmony_ci u32 ssid, u32 tsid, u16 tclass, 19328c2ecf20Sopenharmony_ci const char *objname, u32 *out_sid) 19338c2ecf20Sopenharmony_ci{ 19348c2ecf20Sopenharmony_ci return security_compute_sid(state, ssid, tsid, tclass, 19358c2ecf20Sopenharmony_ci AVTAB_TRANSITION, 19368c2ecf20Sopenharmony_ci objname, out_sid, false); 19378c2ecf20Sopenharmony_ci} 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci/** 19408c2ecf20Sopenharmony_ci * security_member_sid - Compute the SID for member selection. 19418c2ecf20Sopenharmony_ci * @ssid: source security identifier 19428c2ecf20Sopenharmony_ci * @tsid: target security identifier 19438c2ecf20Sopenharmony_ci * @tclass: target security class 19448c2ecf20Sopenharmony_ci * @out_sid: security identifier for selected member 19458c2ecf20Sopenharmony_ci * 19468c2ecf20Sopenharmony_ci * Compute a SID to use when selecting a member of a polyinstantiated 19478c2ecf20Sopenharmony_ci * object of class @tclass based on a SID pair (@ssid, @tsid). 19488c2ecf20Sopenharmony_ci * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 19498c2ecf20Sopenharmony_ci * if insufficient memory is available, or %0 if the SID was 19508c2ecf20Sopenharmony_ci * computed successfully. 19518c2ecf20Sopenharmony_ci */ 19528c2ecf20Sopenharmony_ciint security_member_sid(struct selinux_state *state, 19538c2ecf20Sopenharmony_ci u32 ssid, 19548c2ecf20Sopenharmony_ci u32 tsid, 19558c2ecf20Sopenharmony_ci u16 tclass, 19568c2ecf20Sopenharmony_ci u32 *out_sid) 19578c2ecf20Sopenharmony_ci{ 19588c2ecf20Sopenharmony_ci return security_compute_sid(state, ssid, tsid, tclass, 19598c2ecf20Sopenharmony_ci AVTAB_MEMBER, NULL, 19608c2ecf20Sopenharmony_ci out_sid, false); 19618c2ecf20Sopenharmony_ci} 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci/** 19648c2ecf20Sopenharmony_ci * security_change_sid - Compute the SID for object relabeling. 19658c2ecf20Sopenharmony_ci * @ssid: source security identifier 19668c2ecf20Sopenharmony_ci * @tsid: target security identifier 19678c2ecf20Sopenharmony_ci * @tclass: target security class 19688c2ecf20Sopenharmony_ci * @out_sid: security identifier for selected member 19698c2ecf20Sopenharmony_ci * 19708c2ecf20Sopenharmony_ci * Compute a SID to use for relabeling an object of class @tclass 19718c2ecf20Sopenharmony_ci * based on a SID pair (@ssid, @tsid). 19728c2ecf20Sopenharmony_ci * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 19738c2ecf20Sopenharmony_ci * if insufficient memory is available, or %0 if the SID was 19748c2ecf20Sopenharmony_ci * computed successfully. 19758c2ecf20Sopenharmony_ci */ 19768c2ecf20Sopenharmony_ciint security_change_sid(struct selinux_state *state, 19778c2ecf20Sopenharmony_ci u32 ssid, 19788c2ecf20Sopenharmony_ci u32 tsid, 19798c2ecf20Sopenharmony_ci u16 tclass, 19808c2ecf20Sopenharmony_ci u32 *out_sid) 19818c2ecf20Sopenharmony_ci{ 19828c2ecf20Sopenharmony_ci return security_compute_sid(state, 19838c2ecf20Sopenharmony_ci ssid, tsid, tclass, AVTAB_CHANGE, NULL, 19848c2ecf20Sopenharmony_ci out_sid, false); 19858c2ecf20Sopenharmony_ci} 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_cistatic inline int convert_context_handle_invalid_context( 19888c2ecf20Sopenharmony_ci struct selinux_state *state, 19898c2ecf20Sopenharmony_ci struct policydb *policydb, 19908c2ecf20Sopenharmony_ci struct context *context) 19918c2ecf20Sopenharmony_ci{ 19928c2ecf20Sopenharmony_ci char *s; 19938c2ecf20Sopenharmony_ci u32 len; 19948c2ecf20Sopenharmony_ci 19958c2ecf20Sopenharmony_ci if (enforcing_enabled(state)) 19968c2ecf20Sopenharmony_ci return -EINVAL; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci if (!context_struct_to_string(policydb, context, &s, &len)) { 19998c2ecf20Sopenharmony_ci pr_warn("SELinux: Context %s would be invalid if enforcing\n", 20008c2ecf20Sopenharmony_ci s); 20018c2ecf20Sopenharmony_ci kfree(s); 20028c2ecf20Sopenharmony_ci } 20038c2ecf20Sopenharmony_ci return 0; 20048c2ecf20Sopenharmony_ci} 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci/* 20078c2ecf20Sopenharmony_ci * Convert the values in the security context 20088c2ecf20Sopenharmony_ci * structure `oldc' from the values specified 20098c2ecf20Sopenharmony_ci * in the policy `p->oldp' to the values specified 20108c2ecf20Sopenharmony_ci * in the policy `p->newp', storing the new context 20118c2ecf20Sopenharmony_ci * in `newc'. Verify that the context is valid 20128c2ecf20Sopenharmony_ci * under the new policy. 20138c2ecf20Sopenharmony_ci */ 20148c2ecf20Sopenharmony_cistatic int convert_context(struct context *oldc, struct context *newc, void *p, 20158c2ecf20Sopenharmony_ci gfp_t gfp_flags) 20168c2ecf20Sopenharmony_ci{ 20178c2ecf20Sopenharmony_ci struct convert_context_args *args; 20188c2ecf20Sopenharmony_ci struct ocontext *oc; 20198c2ecf20Sopenharmony_ci struct role_datum *role; 20208c2ecf20Sopenharmony_ci struct type_datum *typdatum; 20218c2ecf20Sopenharmony_ci struct user_datum *usrdatum; 20228c2ecf20Sopenharmony_ci char *s; 20238c2ecf20Sopenharmony_ci u32 len; 20248c2ecf20Sopenharmony_ci int rc; 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci args = p; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci if (oldc->str) { 20298c2ecf20Sopenharmony_ci s = kstrdup(oldc->str, gfp_flags); 20308c2ecf20Sopenharmony_ci if (!s) 20318c2ecf20Sopenharmony_ci return -ENOMEM; 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_ci rc = string_to_context_struct(args->newp, NULL, s, 20348c2ecf20Sopenharmony_ci newc, SECSID_NULL); 20358c2ecf20Sopenharmony_ci if (rc == -EINVAL) { 20368c2ecf20Sopenharmony_ci /* 20378c2ecf20Sopenharmony_ci * Retain string representation for later mapping. 20388c2ecf20Sopenharmony_ci * 20398c2ecf20Sopenharmony_ci * IMPORTANT: We need to copy the contents of oldc->str 20408c2ecf20Sopenharmony_ci * back into s again because string_to_context_struct() 20418c2ecf20Sopenharmony_ci * may have garbled it. 20428c2ecf20Sopenharmony_ci */ 20438c2ecf20Sopenharmony_ci memcpy(s, oldc->str, oldc->len); 20448c2ecf20Sopenharmony_ci context_init(newc); 20458c2ecf20Sopenharmony_ci newc->str = s; 20468c2ecf20Sopenharmony_ci newc->len = oldc->len; 20478c2ecf20Sopenharmony_ci return 0; 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci kfree(s); 20508c2ecf20Sopenharmony_ci if (rc) { 20518c2ecf20Sopenharmony_ci /* Other error condition, e.g. ENOMEM. */ 20528c2ecf20Sopenharmony_ci pr_err("SELinux: Unable to map context %s, rc = %d.\n", 20538c2ecf20Sopenharmony_ci oldc->str, -rc); 20548c2ecf20Sopenharmony_ci return rc; 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci pr_info("SELinux: Context %s became valid (mapped).\n", 20578c2ecf20Sopenharmony_ci oldc->str); 20588c2ecf20Sopenharmony_ci return 0; 20598c2ecf20Sopenharmony_ci } 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci context_init(newc); 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci /* Convert the user. */ 20648c2ecf20Sopenharmony_ci rc = -EINVAL; 20658c2ecf20Sopenharmony_ci usrdatum = symtab_search(&args->newp->p_users, 20668c2ecf20Sopenharmony_ci sym_name(args->oldp, 20678c2ecf20Sopenharmony_ci SYM_USERS, oldc->user - 1)); 20688c2ecf20Sopenharmony_ci if (!usrdatum) 20698c2ecf20Sopenharmony_ci goto bad; 20708c2ecf20Sopenharmony_ci newc->user = usrdatum->value; 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci /* Convert the role. */ 20738c2ecf20Sopenharmony_ci rc = -EINVAL; 20748c2ecf20Sopenharmony_ci role = symtab_search(&args->newp->p_roles, 20758c2ecf20Sopenharmony_ci sym_name(args->oldp, SYM_ROLES, oldc->role - 1)); 20768c2ecf20Sopenharmony_ci if (!role) 20778c2ecf20Sopenharmony_ci goto bad; 20788c2ecf20Sopenharmony_ci newc->role = role->value; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci /* Convert the type. */ 20818c2ecf20Sopenharmony_ci rc = -EINVAL; 20828c2ecf20Sopenharmony_ci typdatum = symtab_search(&args->newp->p_types, 20838c2ecf20Sopenharmony_ci sym_name(args->oldp, 20848c2ecf20Sopenharmony_ci SYM_TYPES, oldc->type - 1)); 20858c2ecf20Sopenharmony_ci if (!typdatum) 20868c2ecf20Sopenharmony_ci goto bad; 20878c2ecf20Sopenharmony_ci newc->type = typdatum->value; 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci /* Convert the MLS fields if dealing with MLS policies */ 20908c2ecf20Sopenharmony_ci if (args->oldp->mls_enabled && args->newp->mls_enabled) { 20918c2ecf20Sopenharmony_ci rc = mls_convert_context(args->oldp, args->newp, oldc, newc); 20928c2ecf20Sopenharmony_ci if (rc) 20938c2ecf20Sopenharmony_ci goto bad; 20948c2ecf20Sopenharmony_ci } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { 20958c2ecf20Sopenharmony_ci /* 20968c2ecf20Sopenharmony_ci * Switching between non-MLS and MLS policy: 20978c2ecf20Sopenharmony_ci * ensure that the MLS fields of the context for all 20988c2ecf20Sopenharmony_ci * existing entries in the sidtab are filled in with a 20998c2ecf20Sopenharmony_ci * suitable default value, likely taken from one of the 21008c2ecf20Sopenharmony_ci * initial SIDs. 21018c2ecf20Sopenharmony_ci */ 21028c2ecf20Sopenharmony_ci oc = args->newp->ocontexts[OCON_ISID]; 21038c2ecf20Sopenharmony_ci while (oc && oc->sid[0] != SECINITSID_UNLABELED) 21048c2ecf20Sopenharmony_ci oc = oc->next; 21058c2ecf20Sopenharmony_ci rc = -EINVAL; 21068c2ecf20Sopenharmony_ci if (!oc) { 21078c2ecf20Sopenharmony_ci pr_err("SELinux: unable to look up" 21088c2ecf20Sopenharmony_ci " the initial SIDs list\n"); 21098c2ecf20Sopenharmony_ci goto bad; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci rc = mls_range_set(newc, &oc->context[0].range); 21128c2ecf20Sopenharmony_ci if (rc) 21138c2ecf20Sopenharmony_ci goto bad; 21148c2ecf20Sopenharmony_ci } 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci /* Check the validity of the new context. */ 21178c2ecf20Sopenharmony_ci if (!policydb_context_isvalid(args->newp, newc)) { 21188c2ecf20Sopenharmony_ci rc = convert_context_handle_invalid_context(args->state, 21198c2ecf20Sopenharmony_ci args->oldp, 21208c2ecf20Sopenharmony_ci oldc); 21218c2ecf20Sopenharmony_ci if (rc) 21228c2ecf20Sopenharmony_ci goto bad; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci 21258c2ecf20Sopenharmony_ci return 0; 21268c2ecf20Sopenharmony_cibad: 21278c2ecf20Sopenharmony_ci /* Map old representation to string and save it. */ 21288c2ecf20Sopenharmony_ci rc = context_struct_to_string(args->oldp, oldc, &s, &len); 21298c2ecf20Sopenharmony_ci if (rc) 21308c2ecf20Sopenharmony_ci return rc; 21318c2ecf20Sopenharmony_ci context_destroy(newc); 21328c2ecf20Sopenharmony_ci newc->str = s; 21338c2ecf20Sopenharmony_ci newc->len = len; 21348c2ecf20Sopenharmony_ci pr_info("SELinux: Context %s became invalid (unmapped).\n", 21358c2ecf20Sopenharmony_ci newc->str); 21368c2ecf20Sopenharmony_ci return 0; 21378c2ecf20Sopenharmony_ci} 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_cistatic void security_load_policycaps(struct selinux_state *state, 21408c2ecf20Sopenharmony_ci struct selinux_policy *policy) 21418c2ecf20Sopenharmony_ci{ 21428c2ecf20Sopenharmony_ci struct policydb *p; 21438c2ecf20Sopenharmony_ci unsigned int i; 21448c2ecf20Sopenharmony_ci struct ebitmap_node *node; 21458c2ecf20Sopenharmony_ci 21468c2ecf20Sopenharmony_ci p = &policy->policydb; 21478c2ecf20Sopenharmony_ci 21488c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(state->policycap); i++) 21498c2ecf20Sopenharmony_ci WRITE_ONCE(state->policycap[i], 21508c2ecf20Sopenharmony_ci ebitmap_get_bit(&p->policycaps, i)); 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++) 21538c2ecf20Sopenharmony_ci pr_info("SELinux: policy capability %s=%d\n", 21548c2ecf20Sopenharmony_ci selinux_policycap_names[i], 21558c2ecf20Sopenharmony_ci ebitmap_get_bit(&p->policycaps, i)); 21568c2ecf20Sopenharmony_ci 21578c2ecf20Sopenharmony_ci ebitmap_for_each_positive_bit(&p->policycaps, node, i) { 21588c2ecf20Sopenharmony_ci if (i >= ARRAY_SIZE(selinux_policycap_names)) 21598c2ecf20Sopenharmony_ci pr_info("SELinux: unknown policy capability %u\n", 21608c2ecf20Sopenharmony_ci i); 21618c2ecf20Sopenharmony_ci } 21628c2ecf20Sopenharmony_ci} 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_cistatic int security_preserve_bools(struct selinux_policy *oldpolicy, 21658c2ecf20Sopenharmony_ci struct selinux_policy *newpolicy); 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_cistatic void selinux_policy_free(struct selinux_policy *policy) 21688c2ecf20Sopenharmony_ci{ 21698c2ecf20Sopenharmony_ci if (!policy) 21708c2ecf20Sopenharmony_ci return; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci sidtab_destroy(policy->sidtab); 21738c2ecf20Sopenharmony_ci kfree(policy->map.mapping); 21748c2ecf20Sopenharmony_ci policydb_destroy(&policy->policydb); 21758c2ecf20Sopenharmony_ci kfree(policy->sidtab); 21768c2ecf20Sopenharmony_ci kfree(policy); 21778c2ecf20Sopenharmony_ci} 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_cistatic void selinux_policy_cond_free(struct selinux_policy *policy) 21808c2ecf20Sopenharmony_ci{ 21818c2ecf20Sopenharmony_ci cond_policydb_destroy_dup(&policy->policydb); 21828c2ecf20Sopenharmony_ci kfree(policy); 21838c2ecf20Sopenharmony_ci} 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_civoid selinux_policy_cancel(struct selinux_state *state, 21868c2ecf20Sopenharmony_ci struct selinux_load_state *load_state) 21878c2ecf20Sopenharmony_ci{ 21888c2ecf20Sopenharmony_ci struct selinux_policy *oldpolicy; 21898c2ecf20Sopenharmony_ci 21908c2ecf20Sopenharmony_ci oldpolicy = rcu_dereference_protected(state->policy, 21918c2ecf20Sopenharmony_ci lockdep_is_held(&state->policy_mutex)); 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci sidtab_cancel_convert(oldpolicy->sidtab); 21948c2ecf20Sopenharmony_ci selinux_policy_free(load_state->policy); 21958c2ecf20Sopenharmony_ci kfree(load_state->convert_data); 21968c2ecf20Sopenharmony_ci} 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_cistatic void selinux_notify_policy_change(struct selinux_state *state, 21998c2ecf20Sopenharmony_ci u32 seqno) 22008c2ecf20Sopenharmony_ci{ 22018c2ecf20Sopenharmony_ci /* Flush external caches and notify userspace of policy load */ 22028c2ecf20Sopenharmony_ci avc_ss_reset(state->avc, seqno); 22038c2ecf20Sopenharmony_ci selnl_notify_policyload(seqno); 22048c2ecf20Sopenharmony_ci selinux_status_update_policyload(state, seqno); 22058c2ecf20Sopenharmony_ci selinux_netlbl_cache_invalidate(); 22068c2ecf20Sopenharmony_ci selinux_xfrm_notify_policyload(); 22078c2ecf20Sopenharmony_ci} 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_civoid selinux_policy_commit(struct selinux_state *state, 22108c2ecf20Sopenharmony_ci struct selinux_load_state *load_state) 22118c2ecf20Sopenharmony_ci{ 22128c2ecf20Sopenharmony_ci struct selinux_policy *oldpolicy, *newpolicy = load_state->policy; 22138c2ecf20Sopenharmony_ci unsigned long flags; 22148c2ecf20Sopenharmony_ci u32 seqno; 22158c2ecf20Sopenharmony_ci 22168c2ecf20Sopenharmony_ci oldpolicy = rcu_dereference_protected(state->policy, 22178c2ecf20Sopenharmony_ci lockdep_is_held(&state->policy_mutex)); 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci /* If switching between different policy types, log MLS status */ 22208c2ecf20Sopenharmony_ci if (oldpolicy) { 22218c2ecf20Sopenharmony_ci if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled) 22228c2ecf20Sopenharmony_ci pr_info("SELinux: Disabling MLS support...\n"); 22238c2ecf20Sopenharmony_ci else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled) 22248c2ecf20Sopenharmony_ci pr_info("SELinux: Enabling MLS support...\n"); 22258c2ecf20Sopenharmony_ci } 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci /* Set latest granting seqno for new policy. */ 22288c2ecf20Sopenharmony_ci if (oldpolicy) 22298c2ecf20Sopenharmony_ci newpolicy->latest_granting = oldpolicy->latest_granting + 1; 22308c2ecf20Sopenharmony_ci else 22318c2ecf20Sopenharmony_ci newpolicy->latest_granting = 1; 22328c2ecf20Sopenharmony_ci seqno = newpolicy->latest_granting; 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_ci /* Install the new policy. */ 22358c2ecf20Sopenharmony_ci if (oldpolicy) { 22368c2ecf20Sopenharmony_ci sidtab_freeze_begin(oldpolicy->sidtab, &flags); 22378c2ecf20Sopenharmony_ci rcu_assign_pointer(state->policy, newpolicy); 22388c2ecf20Sopenharmony_ci sidtab_freeze_end(oldpolicy->sidtab, &flags); 22398c2ecf20Sopenharmony_ci } else { 22408c2ecf20Sopenharmony_ci rcu_assign_pointer(state->policy, newpolicy); 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci /* Load the policycaps from the new policy */ 22448c2ecf20Sopenharmony_ci security_load_policycaps(state, newpolicy); 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 22478c2ecf20Sopenharmony_ci /* 22488c2ecf20Sopenharmony_ci * After first policy load, the security server is 22498c2ecf20Sopenharmony_ci * marked as initialized and ready to handle requests and 22508c2ecf20Sopenharmony_ci * any objects created prior to policy load are then labeled. 22518c2ecf20Sopenharmony_ci */ 22528c2ecf20Sopenharmony_ci selinux_mark_initialized(state); 22538c2ecf20Sopenharmony_ci selinux_complete_init(); 22548c2ecf20Sopenharmony_ci } 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_ci /* Free the old policy */ 22578c2ecf20Sopenharmony_ci synchronize_rcu(); 22588c2ecf20Sopenharmony_ci selinux_policy_free(oldpolicy); 22598c2ecf20Sopenharmony_ci kfree(load_state->convert_data); 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci /* Notify others of the policy change */ 22628c2ecf20Sopenharmony_ci selinux_notify_policy_change(state, seqno); 22638c2ecf20Sopenharmony_ci} 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci/** 22668c2ecf20Sopenharmony_ci * security_load_policy - Load a security policy configuration. 22678c2ecf20Sopenharmony_ci * @data: binary policy data 22688c2ecf20Sopenharmony_ci * @len: length of data in bytes 22698c2ecf20Sopenharmony_ci * 22708c2ecf20Sopenharmony_ci * Load a new set of security policy configuration data, 22718c2ecf20Sopenharmony_ci * validate it and convert the SID table as necessary. 22728c2ecf20Sopenharmony_ci * This function will flush the access vector cache after 22738c2ecf20Sopenharmony_ci * loading the new policy. 22748c2ecf20Sopenharmony_ci */ 22758c2ecf20Sopenharmony_ciint security_load_policy(struct selinux_state *state, void *data, size_t len, 22768c2ecf20Sopenharmony_ci struct selinux_load_state *load_state) 22778c2ecf20Sopenharmony_ci{ 22788c2ecf20Sopenharmony_ci struct selinux_policy *newpolicy, *oldpolicy; 22798c2ecf20Sopenharmony_ci struct selinux_policy_convert_data *convert_data; 22808c2ecf20Sopenharmony_ci int rc = 0; 22818c2ecf20Sopenharmony_ci struct policy_file file = { data, len }, *fp = &file; 22828c2ecf20Sopenharmony_ci 22838c2ecf20Sopenharmony_ci newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL); 22848c2ecf20Sopenharmony_ci if (!newpolicy) 22858c2ecf20Sopenharmony_ci return -ENOMEM; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL); 22888c2ecf20Sopenharmony_ci if (!newpolicy->sidtab) { 22898c2ecf20Sopenharmony_ci rc = -ENOMEM; 22908c2ecf20Sopenharmony_ci goto err_policy; 22918c2ecf20Sopenharmony_ci } 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci rc = policydb_read(&newpolicy->policydb, fp); 22948c2ecf20Sopenharmony_ci if (rc) 22958c2ecf20Sopenharmony_ci goto err_sidtab; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci newpolicy->policydb.len = len; 22988c2ecf20Sopenharmony_ci rc = selinux_set_mapping(&newpolicy->policydb, secclass_map, 22998c2ecf20Sopenharmony_ci &newpolicy->map); 23008c2ecf20Sopenharmony_ci if (rc) 23018c2ecf20Sopenharmony_ci goto err_policydb; 23028c2ecf20Sopenharmony_ci 23038c2ecf20Sopenharmony_ci rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab); 23048c2ecf20Sopenharmony_ci if (rc) { 23058c2ecf20Sopenharmony_ci pr_err("SELinux: unable to load the initial SIDs\n"); 23068c2ecf20Sopenharmony_ci goto err_mapping; 23078c2ecf20Sopenharmony_ci } 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 23108c2ecf20Sopenharmony_ci /* First policy load, so no need to preserve state from old policy */ 23118c2ecf20Sopenharmony_ci load_state->policy = newpolicy; 23128c2ecf20Sopenharmony_ci load_state->convert_data = NULL; 23138c2ecf20Sopenharmony_ci return 0; 23148c2ecf20Sopenharmony_ci } 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci oldpolicy = rcu_dereference_protected(state->policy, 23178c2ecf20Sopenharmony_ci lockdep_is_held(&state->policy_mutex)); 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_ci /* Preserve active boolean values from the old policy */ 23208c2ecf20Sopenharmony_ci rc = security_preserve_bools(oldpolicy, newpolicy); 23218c2ecf20Sopenharmony_ci if (rc) { 23228c2ecf20Sopenharmony_ci pr_err("SELinux: unable to preserve booleans\n"); 23238c2ecf20Sopenharmony_ci goto err_free_isids; 23248c2ecf20Sopenharmony_ci } 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL); 23278c2ecf20Sopenharmony_ci if (!convert_data) { 23288c2ecf20Sopenharmony_ci rc = -ENOMEM; 23298c2ecf20Sopenharmony_ci goto err_free_isids; 23308c2ecf20Sopenharmony_ci } 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci /* 23338c2ecf20Sopenharmony_ci * Convert the internal representations of contexts 23348c2ecf20Sopenharmony_ci * in the new SID table. 23358c2ecf20Sopenharmony_ci */ 23368c2ecf20Sopenharmony_ci convert_data->args.state = state; 23378c2ecf20Sopenharmony_ci convert_data->args.oldp = &oldpolicy->policydb; 23388c2ecf20Sopenharmony_ci convert_data->args.newp = &newpolicy->policydb; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci convert_data->sidtab_params.func = convert_context; 23418c2ecf20Sopenharmony_ci convert_data->sidtab_params.args = &convert_data->args; 23428c2ecf20Sopenharmony_ci convert_data->sidtab_params.target = newpolicy->sidtab; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params); 23458c2ecf20Sopenharmony_ci if (rc) { 23468c2ecf20Sopenharmony_ci pr_err("SELinux: unable to convert the internal" 23478c2ecf20Sopenharmony_ci " representation of contexts in the new SID" 23488c2ecf20Sopenharmony_ci " table\n"); 23498c2ecf20Sopenharmony_ci goto err_free_convert_data; 23508c2ecf20Sopenharmony_ci } 23518c2ecf20Sopenharmony_ci 23528c2ecf20Sopenharmony_ci load_state->policy = newpolicy; 23538c2ecf20Sopenharmony_ci load_state->convert_data = convert_data; 23548c2ecf20Sopenharmony_ci return 0; 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_cierr_free_convert_data: 23578c2ecf20Sopenharmony_ci kfree(convert_data); 23588c2ecf20Sopenharmony_cierr_free_isids: 23598c2ecf20Sopenharmony_ci sidtab_destroy(newpolicy->sidtab); 23608c2ecf20Sopenharmony_cierr_mapping: 23618c2ecf20Sopenharmony_ci kfree(newpolicy->map.mapping); 23628c2ecf20Sopenharmony_cierr_policydb: 23638c2ecf20Sopenharmony_ci policydb_destroy(&newpolicy->policydb); 23648c2ecf20Sopenharmony_cierr_sidtab: 23658c2ecf20Sopenharmony_ci kfree(newpolicy->sidtab); 23668c2ecf20Sopenharmony_cierr_policy: 23678c2ecf20Sopenharmony_ci kfree(newpolicy); 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci return rc; 23708c2ecf20Sopenharmony_ci} 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci/** 23738c2ecf20Sopenharmony_ci * ocontext_to_sid - Helper to safely get sid for an ocontext 23748c2ecf20Sopenharmony_ci * @sidtab: SID table 23758c2ecf20Sopenharmony_ci * @c: ocontext structure 23768c2ecf20Sopenharmony_ci * @index: index of the context entry (0 or 1) 23778c2ecf20Sopenharmony_ci * @out_sid: pointer to the resulting SID value 23788c2ecf20Sopenharmony_ci * 23798c2ecf20Sopenharmony_ci * For all ocontexts except OCON_ISID the SID fields are populated 23808c2ecf20Sopenharmony_ci * on-demand when needed. Since updating the SID value is an SMP-sensitive 23818c2ecf20Sopenharmony_ci * operation, this helper must be used to do that safely. 23828c2ecf20Sopenharmony_ci * 23838c2ecf20Sopenharmony_ci * WARNING: This function may return -ESTALE, indicating that the caller 23848c2ecf20Sopenharmony_ci * must retry the operation after re-acquiring the policy pointer! 23858c2ecf20Sopenharmony_ci */ 23868c2ecf20Sopenharmony_cistatic int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c, 23878c2ecf20Sopenharmony_ci size_t index, u32 *out_sid) 23888c2ecf20Sopenharmony_ci{ 23898c2ecf20Sopenharmony_ci int rc; 23908c2ecf20Sopenharmony_ci u32 sid; 23918c2ecf20Sopenharmony_ci 23928c2ecf20Sopenharmony_ci /* Ensure the associated sidtab entry is visible to this thread. */ 23938c2ecf20Sopenharmony_ci sid = smp_load_acquire(&c->sid[index]); 23948c2ecf20Sopenharmony_ci if (!sid) { 23958c2ecf20Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid); 23968c2ecf20Sopenharmony_ci if (rc) 23978c2ecf20Sopenharmony_ci return rc; 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci /* 24008c2ecf20Sopenharmony_ci * Ensure the new sidtab entry is visible to other threads 24018c2ecf20Sopenharmony_ci * when they see the SID. 24028c2ecf20Sopenharmony_ci */ 24038c2ecf20Sopenharmony_ci smp_store_release(&c->sid[index], sid); 24048c2ecf20Sopenharmony_ci } 24058c2ecf20Sopenharmony_ci *out_sid = sid; 24068c2ecf20Sopenharmony_ci return 0; 24078c2ecf20Sopenharmony_ci} 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci/** 24108c2ecf20Sopenharmony_ci * security_port_sid - Obtain the SID for a port. 24118c2ecf20Sopenharmony_ci * @protocol: protocol number 24128c2ecf20Sopenharmony_ci * @port: port number 24138c2ecf20Sopenharmony_ci * @out_sid: security identifier 24148c2ecf20Sopenharmony_ci */ 24158c2ecf20Sopenharmony_ciint security_port_sid(struct selinux_state *state, 24168c2ecf20Sopenharmony_ci u8 protocol, u16 port, u32 *out_sid) 24178c2ecf20Sopenharmony_ci{ 24188c2ecf20Sopenharmony_ci struct selinux_policy *policy; 24198c2ecf20Sopenharmony_ci struct policydb *policydb; 24208c2ecf20Sopenharmony_ci struct sidtab *sidtab; 24218c2ecf20Sopenharmony_ci struct ocontext *c; 24228c2ecf20Sopenharmony_ci int rc; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 24258c2ecf20Sopenharmony_ci *out_sid = SECINITSID_PORT; 24268c2ecf20Sopenharmony_ci return 0; 24278c2ecf20Sopenharmony_ci } 24288c2ecf20Sopenharmony_ci 24298c2ecf20Sopenharmony_ciretry: 24308c2ecf20Sopenharmony_ci rc = 0; 24318c2ecf20Sopenharmony_ci rcu_read_lock(); 24328c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 24338c2ecf20Sopenharmony_ci policydb = &policy->policydb; 24348c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci c = policydb->ocontexts[OCON_PORT]; 24378c2ecf20Sopenharmony_ci while (c) { 24388c2ecf20Sopenharmony_ci if (c->u.port.protocol == protocol && 24398c2ecf20Sopenharmony_ci c->u.port.low_port <= port && 24408c2ecf20Sopenharmony_ci c->u.port.high_port >= port) 24418c2ecf20Sopenharmony_ci break; 24428c2ecf20Sopenharmony_ci c = c->next; 24438c2ecf20Sopenharmony_ci } 24448c2ecf20Sopenharmony_ci 24458c2ecf20Sopenharmony_ci if (c) { 24468c2ecf20Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, out_sid); 24478c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 24488c2ecf20Sopenharmony_ci rcu_read_unlock(); 24498c2ecf20Sopenharmony_ci goto retry; 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci if (rc) 24528c2ecf20Sopenharmony_ci goto out; 24538c2ecf20Sopenharmony_ci } else { 24548c2ecf20Sopenharmony_ci *out_sid = SECINITSID_PORT; 24558c2ecf20Sopenharmony_ci } 24568c2ecf20Sopenharmony_ci 24578c2ecf20Sopenharmony_ciout: 24588c2ecf20Sopenharmony_ci rcu_read_unlock(); 24598c2ecf20Sopenharmony_ci return rc; 24608c2ecf20Sopenharmony_ci} 24618c2ecf20Sopenharmony_ci 24628c2ecf20Sopenharmony_ci/** 24638c2ecf20Sopenharmony_ci * security_pkey_sid - Obtain the SID for a pkey. 24648c2ecf20Sopenharmony_ci * @subnet_prefix: Subnet Prefix 24658c2ecf20Sopenharmony_ci * @pkey_num: pkey number 24668c2ecf20Sopenharmony_ci * @out_sid: security identifier 24678c2ecf20Sopenharmony_ci */ 24688c2ecf20Sopenharmony_ciint security_ib_pkey_sid(struct selinux_state *state, 24698c2ecf20Sopenharmony_ci u64 subnet_prefix, u16 pkey_num, u32 *out_sid) 24708c2ecf20Sopenharmony_ci{ 24718c2ecf20Sopenharmony_ci struct selinux_policy *policy; 24728c2ecf20Sopenharmony_ci struct policydb *policydb; 24738c2ecf20Sopenharmony_ci struct sidtab *sidtab; 24748c2ecf20Sopenharmony_ci struct ocontext *c; 24758c2ecf20Sopenharmony_ci int rc; 24768c2ecf20Sopenharmony_ci 24778c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 24788c2ecf20Sopenharmony_ci *out_sid = SECINITSID_UNLABELED; 24798c2ecf20Sopenharmony_ci return 0; 24808c2ecf20Sopenharmony_ci } 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ciretry: 24838c2ecf20Sopenharmony_ci rc = 0; 24848c2ecf20Sopenharmony_ci rcu_read_lock(); 24858c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 24868c2ecf20Sopenharmony_ci policydb = &policy->policydb; 24878c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci c = policydb->ocontexts[OCON_IBPKEY]; 24908c2ecf20Sopenharmony_ci while (c) { 24918c2ecf20Sopenharmony_ci if (c->u.ibpkey.low_pkey <= pkey_num && 24928c2ecf20Sopenharmony_ci c->u.ibpkey.high_pkey >= pkey_num && 24938c2ecf20Sopenharmony_ci c->u.ibpkey.subnet_prefix == subnet_prefix) 24948c2ecf20Sopenharmony_ci break; 24958c2ecf20Sopenharmony_ci 24968c2ecf20Sopenharmony_ci c = c->next; 24978c2ecf20Sopenharmony_ci } 24988c2ecf20Sopenharmony_ci 24998c2ecf20Sopenharmony_ci if (c) { 25008c2ecf20Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, out_sid); 25018c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 25028c2ecf20Sopenharmony_ci rcu_read_unlock(); 25038c2ecf20Sopenharmony_ci goto retry; 25048c2ecf20Sopenharmony_ci } 25058c2ecf20Sopenharmony_ci if (rc) 25068c2ecf20Sopenharmony_ci goto out; 25078c2ecf20Sopenharmony_ci } else 25088c2ecf20Sopenharmony_ci *out_sid = SECINITSID_UNLABELED; 25098c2ecf20Sopenharmony_ci 25108c2ecf20Sopenharmony_ciout: 25118c2ecf20Sopenharmony_ci rcu_read_unlock(); 25128c2ecf20Sopenharmony_ci return rc; 25138c2ecf20Sopenharmony_ci} 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci/** 25168c2ecf20Sopenharmony_ci * security_ib_endport_sid - Obtain the SID for a subnet management interface. 25178c2ecf20Sopenharmony_ci * @dev_name: device name 25188c2ecf20Sopenharmony_ci * @port: port number 25198c2ecf20Sopenharmony_ci * @out_sid: security identifier 25208c2ecf20Sopenharmony_ci */ 25218c2ecf20Sopenharmony_ciint security_ib_endport_sid(struct selinux_state *state, 25228c2ecf20Sopenharmony_ci const char *dev_name, u8 port_num, u32 *out_sid) 25238c2ecf20Sopenharmony_ci{ 25248c2ecf20Sopenharmony_ci struct selinux_policy *policy; 25258c2ecf20Sopenharmony_ci struct policydb *policydb; 25268c2ecf20Sopenharmony_ci struct sidtab *sidtab; 25278c2ecf20Sopenharmony_ci struct ocontext *c; 25288c2ecf20Sopenharmony_ci int rc; 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 25318c2ecf20Sopenharmony_ci *out_sid = SECINITSID_UNLABELED; 25328c2ecf20Sopenharmony_ci return 0; 25338c2ecf20Sopenharmony_ci } 25348c2ecf20Sopenharmony_ci 25358c2ecf20Sopenharmony_ciretry: 25368c2ecf20Sopenharmony_ci rc = 0; 25378c2ecf20Sopenharmony_ci rcu_read_lock(); 25388c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 25398c2ecf20Sopenharmony_ci policydb = &policy->policydb; 25408c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci c = policydb->ocontexts[OCON_IBENDPORT]; 25438c2ecf20Sopenharmony_ci while (c) { 25448c2ecf20Sopenharmony_ci if (c->u.ibendport.port == port_num && 25458c2ecf20Sopenharmony_ci !strncmp(c->u.ibendport.dev_name, 25468c2ecf20Sopenharmony_ci dev_name, 25478c2ecf20Sopenharmony_ci IB_DEVICE_NAME_MAX)) 25488c2ecf20Sopenharmony_ci break; 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_ci c = c->next; 25518c2ecf20Sopenharmony_ci } 25528c2ecf20Sopenharmony_ci 25538c2ecf20Sopenharmony_ci if (c) { 25548c2ecf20Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, out_sid); 25558c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 25568c2ecf20Sopenharmony_ci rcu_read_unlock(); 25578c2ecf20Sopenharmony_ci goto retry; 25588c2ecf20Sopenharmony_ci } 25598c2ecf20Sopenharmony_ci if (rc) 25608c2ecf20Sopenharmony_ci goto out; 25618c2ecf20Sopenharmony_ci } else 25628c2ecf20Sopenharmony_ci *out_sid = SECINITSID_UNLABELED; 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ciout: 25658c2ecf20Sopenharmony_ci rcu_read_unlock(); 25668c2ecf20Sopenharmony_ci return rc; 25678c2ecf20Sopenharmony_ci} 25688c2ecf20Sopenharmony_ci 25698c2ecf20Sopenharmony_ci/** 25708c2ecf20Sopenharmony_ci * security_netif_sid - Obtain the SID for a network interface. 25718c2ecf20Sopenharmony_ci * @name: interface name 25728c2ecf20Sopenharmony_ci * @if_sid: interface SID 25738c2ecf20Sopenharmony_ci */ 25748c2ecf20Sopenharmony_ciint security_netif_sid(struct selinux_state *state, 25758c2ecf20Sopenharmony_ci char *name, u32 *if_sid) 25768c2ecf20Sopenharmony_ci{ 25778c2ecf20Sopenharmony_ci struct selinux_policy *policy; 25788c2ecf20Sopenharmony_ci struct policydb *policydb; 25798c2ecf20Sopenharmony_ci struct sidtab *sidtab; 25808c2ecf20Sopenharmony_ci int rc; 25818c2ecf20Sopenharmony_ci struct ocontext *c; 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 25848c2ecf20Sopenharmony_ci *if_sid = SECINITSID_NETIF; 25858c2ecf20Sopenharmony_ci return 0; 25868c2ecf20Sopenharmony_ci } 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ciretry: 25898c2ecf20Sopenharmony_ci rc = 0; 25908c2ecf20Sopenharmony_ci rcu_read_lock(); 25918c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 25928c2ecf20Sopenharmony_ci policydb = &policy->policydb; 25938c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci c = policydb->ocontexts[OCON_NETIF]; 25968c2ecf20Sopenharmony_ci while (c) { 25978c2ecf20Sopenharmony_ci if (strcmp(name, c->u.name) == 0) 25988c2ecf20Sopenharmony_ci break; 25998c2ecf20Sopenharmony_ci c = c->next; 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci if (c) { 26038c2ecf20Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, if_sid); 26048c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 26058c2ecf20Sopenharmony_ci rcu_read_unlock(); 26068c2ecf20Sopenharmony_ci goto retry; 26078c2ecf20Sopenharmony_ci } 26088c2ecf20Sopenharmony_ci if (rc) 26098c2ecf20Sopenharmony_ci goto out; 26108c2ecf20Sopenharmony_ci } else 26118c2ecf20Sopenharmony_ci *if_sid = SECINITSID_NETIF; 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ciout: 26148c2ecf20Sopenharmony_ci rcu_read_unlock(); 26158c2ecf20Sopenharmony_ci return rc; 26168c2ecf20Sopenharmony_ci} 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_cistatic int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) 26198c2ecf20Sopenharmony_ci{ 26208c2ecf20Sopenharmony_ci int i, fail = 0; 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) 26238c2ecf20Sopenharmony_ci if (addr[i] != (input[i] & mask[i])) { 26248c2ecf20Sopenharmony_ci fail = 1; 26258c2ecf20Sopenharmony_ci break; 26268c2ecf20Sopenharmony_ci } 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci return !fail; 26298c2ecf20Sopenharmony_ci} 26308c2ecf20Sopenharmony_ci 26318c2ecf20Sopenharmony_ci/** 26328c2ecf20Sopenharmony_ci * security_node_sid - Obtain the SID for a node (host). 26338c2ecf20Sopenharmony_ci * @domain: communication domain aka address family 26348c2ecf20Sopenharmony_ci * @addrp: address 26358c2ecf20Sopenharmony_ci * @addrlen: address length in bytes 26368c2ecf20Sopenharmony_ci * @out_sid: security identifier 26378c2ecf20Sopenharmony_ci */ 26388c2ecf20Sopenharmony_ciint security_node_sid(struct selinux_state *state, 26398c2ecf20Sopenharmony_ci u16 domain, 26408c2ecf20Sopenharmony_ci void *addrp, 26418c2ecf20Sopenharmony_ci u32 addrlen, 26428c2ecf20Sopenharmony_ci u32 *out_sid) 26438c2ecf20Sopenharmony_ci{ 26448c2ecf20Sopenharmony_ci struct selinux_policy *policy; 26458c2ecf20Sopenharmony_ci struct policydb *policydb; 26468c2ecf20Sopenharmony_ci struct sidtab *sidtab; 26478c2ecf20Sopenharmony_ci int rc; 26488c2ecf20Sopenharmony_ci struct ocontext *c; 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 26518c2ecf20Sopenharmony_ci *out_sid = SECINITSID_NODE; 26528c2ecf20Sopenharmony_ci return 0; 26538c2ecf20Sopenharmony_ci } 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ciretry: 26568c2ecf20Sopenharmony_ci rcu_read_lock(); 26578c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 26588c2ecf20Sopenharmony_ci policydb = &policy->policydb; 26598c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci switch (domain) { 26628c2ecf20Sopenharmony_ci case AF_INET: { 26638c2ecf20Sopenharmony_ci u32 addr; 26648c2ecf20Sopenharmony_ci 26658c2ecf20Sopenharmony_ci rc = -EINVAL; 26668c2ecf20Sopenharmony_ci if (addrlen != sizeof(u32)) 26678c2ecf20Sopenharmony_ci goto out; 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci addr = *((u32 *)addrp); 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci c = policydb->ocontexts[OCON_NODE]; 26728c2ecf20Sopenharmony_ci while (c) { 26738c2ecf20Sopenharmony_ci if (c->u.node.addr == (addr & c->u.node.mask)) 26748c2ecf20Sopenharmony_ci break; 26758c2ecf20Sopenharmony_ci c = c->next; 26768c2ecf20Sopenharmony_ci } 26778c2ecf20Sopenharmony_ci break; 26788c2ecf20Sopenharmony_ci } 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci case AF_INET6: 26818c2ecf20Sopenharmony_ci rc = -EINVAL; 26828c2ecf20Sopenharmony_ci if (addrlen != sizeof(u64) * 2) 26838c2ecf20Sopenharmony_ci goto out; 26848c2ecf20Sopenharmony_ci c = policydb->ocontexts[OCON_NODE6]; 26858c2ecf20Sopenharmony_ci while (c) { 26868c2ecf20Sopenharmony_ci if (match_ipv6_addrmask(addrp, c->u.node6.addr, 26878c2ecf20Sopenharmony_ci c->u.node6.mask)) 26888c2ecf20Sopenharmony_ci break; 26898c2ecf20Sopenharmony_ci c = c->next; 26908c2ecf20Sopenharmony_ci } 26918c2ecf20Sopenharmony_ci break; 26928c2ecf20Sopenharmony_ci 26938c2ecf20Sopenharmony_ci default: 26948c2ecf20Sopenharmony_ci rc = 0; 26958c2ecf20Sopenharmony_ci *out_sid = SECINITSID_NODE; 26968c2ecf20Sopenharmony_ci goto out; 26978c2ecf20Sopenharmony_ci } 26988c2ecf20Sopenharmony_ci 26998c2ecf20Sopenharmony_ci if (c) { 27008c2ecf20Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, out_sid); 27018c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 27028c2ecf20Sopenharmony_ci rcu_read_unlock(); 27038c2ecf20Sopenharmony_ci goto retry; 27048c2ecf20Sopenharmony_ci } 27058c2ecf20Sopenharmony_ci if (rc) 27068c2ecf20Sopenharmony_ci goto out; 27078c2ecf20Sopenharmony_ci } else { 27088c2ecf20Sopenharmony_ci *out_sid = SECINITSID_NODE; 27098c2ecf20Sopenharmony_ci } 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci rc = 0; 27128c2ecf20Sopenharmony_ciout: 27138c2ecf20Sopenharmony_ci rcu_read_unlock(); 27148c2ecf20Sopenharmony_ci return rc; 27158c2ecf20Sopenharmony_ci} 27168c2ecf20Sopenharmony_ci 27178c2ecf20Sopenharmony_ci#define SIDS_NEL 25 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci/** 27208c2ecf20Sopenharmony_ci * security_get_user_sids - Obtain reachable SIDs for a user. 27218c2ecf20Sopenharmony_ci * @fromsid: starting SID 27228c2ecf20Sopenharmony_ci * @username: username 27238c2ecf20Sopenharmony_ci * @sids: array of reachable SIDs for user 27248c2ecf20Sopenharmony_ci * @nel: number of elements in @sids 27258c2ecf20Sopenharmony_ci * 27268c2ecf20Sopenharmony_ci * Generate the set of SIDs for legal security contexts 27278c2ecf20Sopenharmony_ci * for a given user that can be reached by @fromsid. 27288c2ecf20Sopenharmony_ci * Set *@sids to point to a dynamically allocated 27298c2ecf20Sopenharmony_ci * array containing the set of SIDs. Set *@nel to the 27308c2ecf20Sopenharmony_ci * number of elements in the array. 27318c2ecf20Sopenharmony_ci */ 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ciint security_get_user_sids(struct selinux_state *state, 27348c2ecf20Sopenharmony_ci u32 fromsid, 27358c2ecf20Sopenharmony_ci char *username, 27368c2ecf20Sopenharmony_ci u32 **sids, 27378c2ecf20Sopenharmony_ci u32 *nel) 27388c2ecf20Sopenharmony_ci{ 27398c2ecf20Sopenharmony_ci struct selinux_policy *policy; 27408c2ecf20Sopenharmony_ci struct policydb *policydb; 27418c2ecf20Sopenharmony_ci struct sidtab *sidtab; 27428c2ecf20Sopenharmony_ci struct context *fromcon, usercon; 27438c2ecf20Sopenharmony_ci u32 *mysids = NULL, *mysids2, sid; 27448c2ecf20Sopenharmony_ci u32 i, j, mynel, maxnel = SIDS_NEL; 27458c2ecf20Sopenharmony_ci struct user_datum *user; 27468c2ecf20Sopenharmony_ci struct role_datum *role; 27478c2ecf20Sopenharmony_ci struct ebitmap_node *rnode, *tnode; 27488c2ecf20Sopenharmony_ci int rc; 27498c2ecf20Sopenharmony_ci 27508c2ecf20Sopenharmony_ci *sids = NULL; 27518c2ecf20Sopenharmony_ci *nel = 0; 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 27548c2ecf20Sopenharmony_ci return 0; 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL); 27578c2ecf20Sopenharmony_ci if (!mysids) 27588c2ecf20Sopenharmony_ci return -ENOMEM; 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ciretry: 27618c2ecf20Sopenharmony_ci mynel = 0; 27628c2ecf20Sopenharmony_ci rcu_read_lock(); 27638c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 27648c2ecf20Sopenharmony_ci policydb = &policy->policydb; 27658c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci context_init(&usercon); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci rc = -EINVAL; 27708c2ecf20Sopenharmony_ci fromcon = sidtab_search(sidtab, fromsid); 27718c2ecf20Sopenharmony_ci if (!fromcon) 27728c2ecf20Sopenharmony_ci goto out_unlock; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci rc = -EINVAL; 27758c2ecf20Sopenharmony_ci user = symtab_search(&policydb->p_users, username); 27768c2ecf20Sopenharmony_ci if (!user) 27778c2ecf20Sopenharmony_ci goto out_unlock; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci usercon.user = user->value; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci ebitmap_for_each_positive_bit(&user->roles, rnode, i) { 27828c2ecf20Sopenharmony_ci role = policydb->role_val_to_struct[i]; 27838c2ecf20Sopenharmony_ci usercon.role = i + 1; 27848c2ecf20Sopenharmony_ci ebitmap_for_each_positive_bit(&role->types, tnode, j) { 27858c2ecf20Sopenharmony_ci usercon.type = j + 1; 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci if (mls_setup_user_range(policydb, fromcon, user, 27888c2ecf20Sopenharmony_ci &usercon)) 27898c2ecf20Sopenharmony_ci continue; 27908c2ecf20Sopenharmony_ci 27918c2ecf20Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &usercon, &sid); 27928c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 27938c2ecf20Sopenharmony_ci rcu_read_unlock(); 27948c2ecf20Sopenharmony_ci goto retry; 27958c2ecf20Sopenharmony_ci } 27968c2ecf20Sopenharmony_ci if (rc) 27978c2ecf20Sopenharmony_ci goto out_unlock; 27988c2ecf20Sopenharmony_ci if (mynel < maxnel) { 27998c2ecf20Sopenharmony_ci mysids[mynel++] = sid; 28008c2ecf20Sopenharmony_ci } else { 28018c2ecf20Sopenharmony_ci rc = -ENOMEM; 28028c2ecf20Sopenharmony_ci maxnel += SIDS_NEL; 28038c2ecf20Sopenharmony_ci mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); 28048c2ecf20Sopenharmony_ci if (!mysids2) 28058c2ecf20Sopenharmony_ci goto out_unlock; 28068c2ecf20Sopenharmony_ci memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); 28078c2ecf20Sopenharmony_ci kfree(mysids); 28088c2ecf20Sopenharmony_ci mysids = mysids2; 28098c2ecf20Sopenharmony_ci mysids[mynel++] = sid; 28108c2ecf20Sopenharmony_ci } 28118c2ecf20Sopenharmony_ci } 28128c2ecf20Sopenharmony_ci } 28138c2ecf20Sopenharmony_ci rc = 0; 28148c2ecf20Sopenharmony_ciout_unlock: 28158c2ecf20Sopenharmony_ci rcu_read_unlock(); 28168c2ecf20Sopenharmony_ci if (rc || !mynel) { 28178c2ecf20Sopenharmony_ci kfree(mysids); 28188c2ecf20Sopenharmony_ci return rc; 28198c2ecf20Sopenharmony_ci } 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci rc = -ENOMEM; 28228c2ecf20Sopenharmony_ci mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL); 28238c2ecf20Sopenharmony_ci if (!mysids2) { 28248c2ecf20Sopenharmony_ci kfree(mysids); 28258c2ecf20Sopenharmony_ci return rc; 28268c2ecf20Sopenharmony_ci } 28278c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < mynel; i++) { 28288c2ecf20Sopenharmony_ci struct av_decision dummy_avd; 28298c2ecf20Sopenharmony_ci rc = avc_has_perm_noaudit(state, 28308c2ecf20Sopenharmony_ci fromsid, mysids[i], 28318c2ecf20Sopenharmony_ci SECCLASS_PROCESS, /* kernel value */ 28328c2ecf20Sopenharmony_ci PROCESS__TRANSITION, AVC_STRICT, 28338c2ecf20Sopenharmony_ci &dummy_avd); 28348c2ecf20Sopenharmony_ci if (!rc) 28358c2ecf20Sopenharmony_ci mysids2[j++] = mysids[i]; 28368c2ecf20Sopenharmony_ci cond_resched(); 28378c2ecf20Sopenharmony_ci } 28388c2ecf20Sopenharmony_ci kfree(mysids); 28398c2ecf20Sopenharmony_ci *sids = mysids2; 28408c2ecf20Sopenharmony_ci *nel = j; 28418c2ecf20Sopenharmony_ci return 0; 28428c2ecf20Sopenharmony_ci} 28438c2ecf20Sopenharmony_ci 28448c2ecf20Sopenharmony_ci/** 28458c2ecf20Sopenharmony_ci * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem 28468c2ecf20Sopenharmony_ci * @fstype: filesystem type 28478c2ecf20Sopenharmony_ci * @path: path from root of mount 28488c2ecf20Sopenharmony_ci * @sclass: file security class 28498c2ecf20Sopenharmony_ci * @sid: SID for path 28508c2ecf20Sopenharmony_ci * 28518c2ecf20Sopenharmony_ci * Obtain a SID to use for a file in a filesystem that 28528c2ecf20Sopenharmony_ci * cannot support xattr or use a fixed labeling behavior like 28538c2ecf20Sopenharmony_ci * transition SIDs or task SIDs. 28548c2ecf20Sopenharmony_ci * 28558c2ecf20Sopenharmony_ci * WARNING: This function may return -ESTALE, indicating that the caller 28568c2ecf20Sopenharmony_ci * must retry the operation after re-acquiring the policy pointer! 28578c2ecf20Sopenharmony_ci */ 28588c2ecf20Sopenharmony_cistatic inline int __security_genfs_sid(struct selinux_policy *policy, 28598c2ecf20Sopenharmony_ci const char *fstype, 28608c2ecf20Sopenharmony_ci char *path, 28618c2ecf20Sopenharmony_ci u16 orig_sclass, 28628c2ecf20Sopenharmony_ci u32 *sid) 28638c2ecf20Sopenharmony_ci{ 28648c2ecf20Sopenharmony_ci struct policydb *policydb = &policy->policydb; 28658c2ecf20Sopenharmony_ci struct sidtab *sidtab = policy->sidtab; 28668c2ecf20Sopenharmony_ci int len; 28678c2ecf20Sopenharmony_ci u16 sclass; 28688c2ecf20Sopenharmony_ci struct genfs *genfs; 28698c2ecf20Sopenharmony_ci struct ocontext *c; 28708c2ecf20Sopenharmony_ci int cmp = 0; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci while (path[0] == '/' && path[1] == '/') 28738c2ecf20Sopenharmony_ci path++; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci sclass = unmap_class(&policy->map, orig_sclass); 28768c2ecf20Sopenharmony_ci *sid = SECINITSID_UNLABELED; 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci for (genfs = policydb->genfs; genfs; genfs = genfs->next) { 28798c2ecf20Sopenharmony_ci cmp = strcmp(fstype, genfs->fstype); 28808c2ecf20Sopenharmony_ci if (cmp <= 0) 28818c2ecf20Sopenharmony_ci break; 28828c2ecf20Sopenharmony_ci } 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_ci if (!genfs || cmp) 28858c2ecf20Sopenharmony_ci return -ENOENT; 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci for (c = genfs->head; c; c = c->next) { 28888c2ecf20Sopenharmony_ci len = strlen(c->u.name); 28898c2ecf20Sopenharmony_ci if ((!c->v.sclass || sclass == c->v.sclass) && 28908c2ecf20Sopenharmony_ci (strncmp(c->u.name, path, len) == 0)) 28918c2ecf20Sopenharmony_ci break; 28928c2ecf20Sopenharmony_ci } 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci if (!c) 28958c2ecf20Sopenharmony_ci return -ENOENT; 28968c2ecf20Sopenharmony_ci 28978c2ecf20Sopenharmony_ci return ocontext_to_sid(sidtab, c, 0, sid); 28988c2ecf20Sopenharmony_ci} 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci/** 29018c2ecf20Sopenharmony_ci * security_genfs_sid - Obtain a SID for a file in a filesystem 29028c2ecf20Sopenharmony_ci * @fstype: filesystem type 29038c2ecf20Sopenharmony_ci * @path: path from root of mount 29048c2ecf20Sopenharmony_ci * @sclass: file security class 29058c2ecf20Sopenharmony_ci * @sid: SID for path 29068c2ecf20Sopenharmony_ci * 29078c2ecf20Sopenharmony_ci * Acquire policy_rwlock before calling __security_genfs_sid() and release 29088c2ecf20Sopenharmony_ci * it afterward. 29098c2ecf20Sopenharmony_ci */ 29108c2ecf20Sopenharmony_ciint security_genfs_sid(struct selinux_state *state, 29118c2ecf20Sopenharmony_ci const char *fstype, 29128c2ecf20Sopenharmony_ci char *path, 29138c2ecf20Sopenharmony_ci u16 orig_sclass, 29148c2ecf20Sopenharmony_ci u32 *sid) 29158c2ecf20Sopenharmony_ci{ 29168c2ecf20Sopenharmony_ci struct selinux_policy *policy; 29178c2ecf20Sopenharmony_ci int retval; 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 29208c2ecf20Sopenharmony_ci *sid = SECINITSID_UNLABELED; 29218c2ecf20Sopenharmony_ci return 0; 29228c2ecf20Sopenharmony_ci } 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci do { 29258c2ecf20Sopenharmony_ci rcu_read_lock(); 29268c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 29278c2ecf20Sopenharmony_ci retval = __security_genfs_sid(policy, fstype, path, 29288c2ecf20Sopenharmony_ci orig_sclass, sid); 29298c2ecf20Sopenharmony_ci rcu_read_unlock(); 29308c2ecf20Sopenharmony_ci } while (retval == -ESTALE); 29318c2ecf20Sopenharmony_ci return retval; 29328c2ecf20Sopenharmony_ci} 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ciint selinux_policy_genfs_sid(struct selinux_policy *policy, 29358c2ecf20Sopenharmony_ci const char *fstype, 29368c2ecf20Sopenharmony_ci char *path, 29378c2ecf20Sopenharmony_ci u16 orig_sclass, 29388c2ecf20Sopenharmony_ci u32 *sid) 29398c2ecf20Sopenharmony_ci{ 29408c2ecf20Sopenharmony_ci /* no lock required, policy is not yet accessible by other threads */ 29418c2ecf20Sopenharmony_ci return __security_genfs_sid(policy, fstype, path, orig_sclass, sid); 29428c2ecf20Sopenharmony_ci} 29438c2ecf20Sopenharmony_ci 29448c2ecf20Sopenharmony_ci/** 29458c2ecf20Sopenharmony_ci * security_fs_use - Determine how to handle labeling for a filesystem. 29468c2ecf20Sopenharmony_ci * @sb: superblock in question 29478c2ecf20Sopenharmony_ci */ 29488c2ecf20Sopenharmony_ciint security_fs_use(struct selinux_state *state, struct super_block *sb) 29498c2ecf20Sopenharmony_ci{ 29508c2ecf20Sopenharmony_ci struct selinux_policy *policy; 29518c2ecf20Sopenharmony_ci struct policydb *policydb; 29528c2ecf20Sopenharmony_ci struct sidtab *sidtab; 29538c2ecf20Sopenharmony_ci int rc; 29548c2ecf20Sopenharmony_ci struct ocontext *c; 29558c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec = sb->s_security; 29568c2ecf20Sopenharmony_ci const char *fstype = sb->s_type->name; 29578c2ecf20Sopenharmony_ci 29588c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 29598c2ecf20Sopenharmony_ci sbsec->behavior = SECURITY_FS_USE_NONE; 29608c2ecf20Sopenharmony_ci sbsec->sid = SECINITSID_UNLABELED; 29618c2ecf20Sopenharmony_ci return 0; 29628c2ecf20Sopenharmony_ci } 29638c2ecf20Sopenharmony_ci 29648c2ecf20Sopenharmony_ciretry: 29658c2ecf20Sopenharmony_ci rc = 0; 29668c2ecf20Sopenharmony_ci rcu_read_lock(); 29678c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 29688c2ecf20Sopenharmony_ci policydb = &policy->policydb; 29698c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_ci c = policydb->ocontexts[OCON_FSUSE]; 29728c2ecf20Sopenharmony_ci while (c) { 29738c2ecf20Sopenharmony_ci if (strcmp(fstype, c->u.name) == 0) 29748c2ecf20Sopenharmony_ci break; 29758c2ecf20Sopenharmony_ci c = c->next; 29768c2ecf20Sopenharmony_ci } 29778c2ecf20Sopenharmony_ci 29788c2ecf20Sopenharmony_ci if (c) { 29798c2ecf20Sopenharmony_ci sbsec->behavior = c->v.behavior; 29808c2ecf20Sopenharmony_ci rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid); 29818c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 29828c2ecf20Sopenharmony_ci rcu_read_unlock(); 29838c2ecf20Sopenharmony_ci goto retry; 29848c2ecf20Sopenharmony_ci } 29858c2ecf20Sopenharmony_ci if (rc) 29868c2ecf20Sopenharmony_ci goto out; 29878c2ecf20Sopenharmony_ci } else { 29888c2ecf20Sopenharmony_ci rc = __security_genfs_sid(policy, fstype, "/", 29898c2ecf20Sopenharmony_ci SECCLASS_DIR, &sbsec->sid); 29908c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 29918c2ecf20Sopenharmony_ci rcu_read_unlock(); 29928c2ecf20Sopenharmony_ci goto retry; 29938c2ecf20Sopenharmony_ci } 29948c2ecf20Sopenharmony_ci if (rc) { 29958c2ecf20Sopenharmony_ci sbsec->behavior = SECURITY_FS_USE_NONE; 29968c2ecf20Sopenharmony_ci rc = 0; 29978c2ecf20Sopenharmony_ci } else { 29988c2ecf20Sopenharmony_ci sbsec->behavior = SECURITY_FS_USE_GENFS; 29998c2ecf20Sopenharmony_ci } 30008c2ecf20Sopenharmony_ci } 30018c2ecf20Sopenharmony_ci 30028c2ecf20Sopenharmony_ciout: 30038c2ecf20Sopenharmony_ci rcu_read_unlock(); 30048c2ecf20Sopenharmony_ci return rc; 30058c2ecf20Sopenharmony_ci} 30068c2ecf20Sopenharmony_ci 30078c2ecf20Sopenharmony_ciint security_get_bools(struct selinux_policy *policy, 30088c2ecf20Sopenharmony_ci u32 *len, char ***names, int **values) 30098c2ecf20Sopenharmony_ci{ 30108c2ecf20Sopenharmony_ci struct policydb *policydb; 30118c2ecf20Sopenharmony_ci u32 i; 30128c2ecf20Sopenharmony_ci int rc; 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci policydb = &policy->policydb; 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_ci *names = NULL; 30178c2ecf20Sopenharmony_ci *values = NULL; 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci rc = 0; 30208c2ecf20Sopenharmony_ci *len = policydb->p_bools.nprim; 30218c2ecf20Sopenharmony_ci if (!*len) 30228c2ecf20Sopenharmony_ci goto out; 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci rc = -ENOMEM; 30258c2ecf20Sopenharmony_ci *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); 30268c2ecf20Sopenharmony_ci if (!*names) 30278c2ecf20Sopenharmony_ci goto err; 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci rc = -ENOMEM; 30308c2ecf20Sopenharmony_ci *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); 30318c2ecf20Sopenharmony_ci if (!*values) 30328c2ecf20Sopenharmony_ci goto err; 30338c2ecf20Sopenharmony_ci 30348c2ecf20Sopenharmony_ci for (i = 0; i < *len; i++) { 30358c2ecf20Sopenharmony_ci (*values)[i] = policydb->bool_val_to_struct[i]->state; 30368c2ecf20Sopenharmony_ci 30378c2ecf20Sopenharmony_ci rc = -ENOMEM; 30388c2ecf20Sopenharmony_ci (*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i), 30398c2ecf20Sopenharmony_ci GFP_ATOMIC); 30408c2ecf20Sopenharmony_ci if (!(*names)[i]) 30418c2ecf20Sopenharmony_ci goto err; 30428c2ecf20Sopenharmony_ci } 30438c2ecf20Sopenharmony_ci rc = 0; 30448c2ecf20Sopenharmony_ciout: 30458c2ecf20Sopenharmony_ci return rc; 30468c2ecf20Sopenharmony_cierr: 30478c2ecf20Sopenharmony_ci if (*names) { 30488c2ecf20Sopenharmony_ci for (i = 0; i < *len; i++) 30498c2ecf20Sopenharmony_ci kfree((*names)[i]); 30508c2ecf20Sopenharmony_ci kfree(*names); 30518c2ecf20Sopenharmony_ci } 30528c2ecf20Sopenharmony_ci kfree(*values); 30538c2ecf20Sopenharmony_ci *len = 0; 30548c2ecf20Sopenharmony_ci *names = NULL; 30558c2ecf20Sopenharmony_ci *values = NULL; 30568c2ecf20Sopenharmony_ci goto out; 30578c2ecf20Sopenharmony_ci} 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_ciint security_set_bools(struct selinux_state *state, u32 len, int *values) 30618c2ecf20Sopenharmony_ci{ 30628c2ecf20Sopenharmony_ci struct selinux_policy *newpolicy, *oldpolicy; 30638c2ecf20Sopenharmony_ci int rc; 30648c2ecf20Sopenharmony_ci u32 i, seqno = 0; 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 30678c2ecf20Sopenharmony_ci return -EINVAL; 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci oldpolicy = rcu_dereference_protected(state->policy, 30708c2ecf20Sopenharmony_ci lockdep_is_held(&state->policy_mutex)); 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_ci /* Consistency check on number of booleans, should never fail */ 30738c2ecf20Sopenharmony_ci if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim)) 30748c2ecf20Sopenharmony_ci return -EINVAL; 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_ci newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL); 30778c2ecf20Sopenharmony_ci if (!newpolicy) 30788c2ecf20Sopenharmony_ci return -ENOMEM; 30798c2ecf20Sopenharmony_ci 30808c2ecf20Sopenharmony_ci /* 30818c2ecf20Sopenharmony_ci * Deep copy only the parts of the policydb that might be 30828c2ecf20Sopenharmony_ci * modified as a result of changing booleans. 30838c2ecf20Sopenharmony_ci */ 30848c2ecf20Sopenharmony_ci rc = cond_policydb_dup(&newpolicy->policydb, &oldpolicy->policydb); 30858c2ecf20Sopenharmony_ci if (rc) { 30868c2ecf20Sopenharmony_ci kfree(newpolicy); 30878c2ecf20Sopenharmony_ci return -ENOMEM; 30888c2ecf20Sopenharmony_ci } 30898c2ecf20Sopenharmony_ci 30908c2ecf20Sopenharmony_ci /* Update the boolean states in the copy */ 30918c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 30928c2ecf20Sopenharmony_ci int new_state = !!values[i]; 30938c2ecf20Sopenharmony_ci int old_state = newpolicy->policydb.bool_val_to_struct[i]->state; 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci if (new_state != old_state) { 30968c2ecf20Sopenharmony_ci audit_log(audit_context(), GFP_ATOMIC, 30978c2ecf20Sopenharmony_ci AUDIT_MAC_CONFIG_CHANGE, 30988c2ecf20Sopenharmony_ci "bool=%s val=%d old_val=%d auid=%u ses=%u", 30998c2ecf20Sopenharmony_ci sym_name(&newpolicy->policydb, SYM_BOOLS, i), 31008c2ecf20Sopenharmony_ci new_state, 31018c2ecf20Sopenharmony_ci old_state, 31028c2ecf20Sopenharmony_ci from_kuid(&init_user_ns, audit_get_loginuid(current)), 31038c2ecf20Sopenharmony_ci audit_get_sessionid(current)); 31048c2ecf20Sopenharmony_ci newpolicy->policydb.bool_val_to_struct[i]->state = new_state; 31058c2ecf20Sopenharmony_ci } 31068c2ecf20Sopenharmony_ci } 31078c2ecf20Sopenharmony_ci 31088c2ecf20Sopenharmony_ci /* Re-evaluate the conditional rules in the copy */ 31098c2ecf20Sopenharmony_ci evaluate_cond_nodes(&newpolicy->policydb); 31108c2ecf20Sopenharmony_ci 31118c2ecf20Sopenharmony_ci /* Set latest granting seqno for new policy */ 31128c2ecf20Sopenharmony_ci newpolicy->latest_granting = oldpolicy->latest_granting + 1; 31138c2ecf20Sopenharmony_ci seqno = newpolicy->latest_granting; 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci /* Install the new policy */ 31168c2ecf20Sopenharmony_ci rcu_assign_pointer(state->policy, newpolicy); 31178c2ecf20Sopenharmony_ci 31188c2ecf20Sopenharmony_ci /* 31198c2ecf20Sopenharmony_ci * Free the conditional portions of the old policydb 31208c2ecf20Sopenharmony_ci * that were copied for the new policy, and the oldpolicy 31218c2ecf20Sopenharmony_ci * structure itself but not what it references. 31228c2ecf20Sopenharmony_ci */ 31238c2ecf20Sopenharmony_ci synchronize_rcu(); 31248c2ecf20Sopenharmony_ci selinux_policy_cond_free(oldpolicy); 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_ci /* Notify others of the policy change */ 31278c2ecf20Sopenharmony_ci selinux_notify_policy_change(state, seqno); 31288c2ecf20Sopenharmony_ci return 0; 31298c2ecf20Sopenharmony_ci} 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ciint security_get_bool_value(struct selinux_state *state, 31328c2ecf20Sopenharmony_ci u32 index) 31338c2ecf20Sopenharmony_ci{ 31348c2ecf20Sopenharmony_ci struct selinux_policy *policy; 31358c2ecf20Sopenharmony_ci struct policydb *policydb; 31368c2ecf20Sopenharmony_ci int rc; 31378c2ecf20Sopenharmony_ci u32 len; 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 31408c2ecf20Sopenharmony_ci return 0; 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci rcu_read_lock(); 31438c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 31448c2ecf20Sopenharmony_ci policydb = &policy->policydb; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci rc = -EFAULT; 31478c2ecf20Sopenharmony_ci len = policydb->p_bools.nprim; 31488c2ecf20Sopenharmony_ci if (index >= len) 31498c2ecf20Sopenharmony_ci goto out; 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci rc = policydb->bool_val_to_struct[index]->state; 31528c2ecf20Sopenharmony_ciout: 31538c2ecf20Sopenharmony_ci rcu_read_unlock(); 31548c2ecf20Sopenharmony_ci return rc; 31558c2ecf20Sopenharmony_ci} 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_cistatic int security_preserve_bools(struct selinux_policy *oldpolicy, 31588c2ecf20Sopenharmony_ci struct selinux_policy *newpolicy) 31598c2ecf20Sopenharmony_ci{ 31608c2ecf20Sopenharmony_ci int rc, *bvalues = NULL; 31618c2ecf20Sopenharmony_ci char **bnames = NULL; 31628c2ecf20Sopenharmony_ci struct cond_bool_datum *booldatum; 31638c2ecf20Sopenharmony_ci u32 i, nbools = 0; 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues); 31668c2ecf20Sopenharmony_ci if (rc) 31678c2ecf20Sopenharmony_ci goto out; 31688c2ecf20Sopenharmony_ci for (i = 0; i < nbools; i++) { 31698c2ecf20Sopenharmony_ci booldatum = symtab_search(&newpolicy->policydb.p_bools, 31708c2ecf20Sopenharmony_ci bnames[i]); 31718c2ecf20Sopenharmony_ci if (booldatum) 31728c2ecf20Sopenharmony_ci booldatum->state = bvalues[i]; 31738c2ecf20Sopenharmony_ci } 31748c2ecf20Sopenharmony_ci evaluate_cond_nodes(&newpolicy->policydb); 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ciout: 31778c2ecf20Sopenharmony_ci if (bnames) { 31788c2ecf20Sopenharmony_ci for (i = 0; i < nbools; i++) 31798c2ecf20Sopenharmony_ci kfree(bnames[i]); 31808c2ecf20Sopenharmony_ci } 31818c2ecf20Sopenharmony_ci kfree(bnames); 31828c2ecf20Sopenharmony_ci kfree(bvalues); 31838c2ecf20Sopenharmony_ci return rc; 31848c2ecf20Sopenharmony_ci} 31858c2ecf20Sopenharmony_ci 31868c2ecf20Sopenharmony_ci/* 31878c2ecf20Sopenharmony_ci * security_sid_mls_copy() - computes a new sid based on the given 31888c2ecf20Sopenharmony_ci * sid and the mls portion of mls_sid. 31898c2ecf20Sopenharmony_ci */ 31908c2ecf20Sopenharmony_ciint security_sid_mls_copy(struct selinux_state *state, 31918c2ecf20Sopenharmony_ci u32 sid, u32 mls_sid, u32 *new_sid) 31928c2ecf20Sopenharmony_ci{ 31938c2ecf20Sopenharmony_ci struct selinux_policy *policy; 31948c2ecf20Sopenharmony_ci struct policydb *policydb; 31958c2ecf20Sopenharmony_ci struct sidtab *sidtab; 31968c2ecf20Sopenharmony_ci struct context *context1; 31978c2ecf20Sopenharmony_ci struct context *context2; 31988c2ecf20Sopenharmony_ci struct context newcon; 31998c2ecf20Sopenharmony_ci char *s; 32008c2ecf20Sopenharmony_ci u32 len; 32018c2ecf20Sopenharmony_ci int rc; 32028c2ecf20Sopenharmony_ci 32038c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 32048c2ecf20Sopenharmony_ci *new_sid = sid; 32058c2ecf20Sopenharmony_ci return 0; 32068c2ecf20Sopenharmony_ci } 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ciretry: 32098c2ecf20Sopenharmony_ci rc = 0; 32108c2ecf20Sopenharmony_ci context_init(&newcon); 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci rcu_read_lock(); 32138c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 32148c2ecf20Sopenharmony_ci policydb = &policy->policydb; 32158c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci if (!policydb->mls_enabled) { 32188c2ecf20Sopenharmony_ci *new_sid = sid; 32198c2ecf20Sopenharmony_ci goto out_unlock; 32208c2ecf20Sopenharmony_ci } 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci rc = -EINVAL; 32238c2ecf20Sopenharmony_ci context1 = sidtab_search(sidtab, sid); 32248c2ecf20Sopenharmony_ci if (!context1) { 32258c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 32268c2ecf20Sopenharmony_ci __func__, sid); 32278c2ecf20Sopenharmony_ci goto out_unlock; 32288c2ecf20Sopenharmony_ci } 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci rc = -EINVAL; 32318c2ecf20Sopenharmony_ci context2 = sidtab_search(sidtab, mls_sid); 32328c2ecf20Sopenharmony_ci if (!context2) { 32338c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 32348c2ecf20Sopenharmony_ci __func__, mls_sid); 32358c2ecf20Sopenharmony_ci goto out_unlock; 32368c2ecf20Sopenharmony_ci } 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ci newcon.user = context1->user; 32398c2ecf20Sopenharmony_ci newcon.role = context1->role; 32408c2ecf20Sopenharmony_ci newcon.type = context1->type; 32418c2ecf20Sopenharmony_ci rc = mls_context_cpy(&newcon, context2); 32428c2ecf20Sopenharmony_ci if (rc) 32438c2ecf20Sopenharmony_ci goto out_unlock; 32448c2ecf20Sopenharmony_ci 32458c2ecf20Sopenharmony_ci /* Check the validity of the new context. */ 32468c2ecf20Sopenharmony_ci if (!policydb_context_isvalid(policydb, &newcon)) { 32478c2ecf20Sopenharmony_ci rc = convert_context_handle_invalid_context(state, policydb, 32488c2ecf20Sopenharmony_ci &newcon); 32498c2ecf20Sopenharmony_ci if (rc) { 32508c2ecf20Sopenharmony_ci if (!context_struct_to_string(policydb, &newcon, &s, 32518c2ecf20Sopenharmony_ci &len)) { 32528c2ecf20Sopenharmony_ci struct audit_buffer *ab; 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci ab = audit_log_start(audit_context(), 32558c2ecf20Sopenharmony_ci GFP_ATOMIC, 32568c2ecf20Sopenharmony_ci AUDIT_SELINUX_ERR); 32578c2ecf20Sopenharmony_ci audit_log_format(ab, 32588c2ecf20Sopenharmony_ci "op=security_sid_mls_copy invalid_context="); 32598c2ecf20Sopenharmony_ci /* don't record NUL with untrusted strings */ 32608c2ecf20Sopenharmony_ci audit_log_n_untrustedstring(ab, s, len - 1); 32618c2ecf20Sopenharmony_ci audit_log_end(ab); 32628c2ecf20Sopenharmony_ci kfree(s); 32638c2ecf20Sopenharmony_ci } 32648c2ecf20Sopenharmony_ci goto out_unlock; 32658c2ecf20Sopenharmony_ci } 32668c2ecf20Sopenharmony_ci } 32678c2ecf20Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &newcon, new_sid); 32688c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 32698c2ecf20Sopenharmony_ci rcu_read_unlock(); 32708c2ecf20Sopenharmony_ci context_destroy(&newcon); 32718c2ecf20Sopenharmony_ci goto retry; 32728c2ecf20Sopenharmony_ci } 32738c2ecf20Sopenharmony_ciout_unlock: 32748c2ecf20Sopenharmony_ci rcu_read_unlock(); 32758c2ecf20Sopenharmony_ci context_destroy(&newcon); 32768c2ecf20Sopenharmony_ci return rc; 32778c2ecf20Sopenharmony_ci} 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci/** 32808c2ecf20Sopenharmony_ci * security_net_peersid_resolve - Compare and resolve two network peer SIDs 32818c2ecf20Sopenharmony_ci * @nlbl_sid: NetLabel SID 32828c2ecf20Sopenharmony_ci * @nlbl_type: NetLabel labeling protocol type 32838c2ecf20Sopenharmony_ci * @xfrm_sid: XFRM SID 32848c2ecf20Sopenharmony_ci * 32858c2ecf20Sopenharmony_ci * Description: 32868c2ecf20Sopenharmony_ci * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be 32878c2ecf20Sopenharmony_ci * resolved into a single SID it is returned via @peer_sid and the function 32888c2ecf20Sopenharmony_ci * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function 32898c2ecf20Sopenharmony_ci * returns a negative value. A table summarizing the behavior is below: 32908c2ecf20Sopenharmony_ci * 32918c2ecf20Sopenharmony_ci * | function return | @sid 32928c2ecf20Sopenharmony_ci * ------------------------------+-----------------+----------------- 32938c2ecf20Sopenharmony_ci * no peer labels | 0 | SECSID_NULL 32948c2ecf20Sopenharmony_ci * single peer label | 0 | <peer_label> 32958c2ecf20Sopenharmony_ci * multiple, consistent labels | 0 | <peer_label> 32968c2ecf20Sopenharmony_ci * multiple, inconsistent labels | -<errno> | SECSID_NULL 32978c2ecf20Sopenharmony_ci * 32988c2ecf20Sopenharmony_ci */ 32998c2ecf20Sopenharmony_ciint security_net_peersid_resolve(struct selinux_state *state, 33008c2ecf20Sopenharmony_ci u32 nlbl_sid, u32 nlbl_type, 33018c2ecf20Sopenharmony_ci u32 xfrm_sid, 33028c2ecf20Sopenharmony_ci u32 *peer_sid) 33038c2ecf20Sopenharmony_ci{ 33048c2ecf20Sopenharmony_ci struct selinux_policy *policy; 33058c2ecf20Sopenharmony_ci struct policydb *policydb; 33068c2ecf20Sopenharmony_ci struct sidtab *sidtab; 33078c2ecf20Sopenharmony_ci int rc; 33088c2ecf20Sopenharmony_ci struct context *nlbl_ctx; 33098c2ecf20Sopenharmony_ci struct context *xfrm_ctx; 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci *peer_sid = SECSID_NULL; 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ci /* handle the common (which also happens to be the set of easy) cases 33148c2ecf20Sopenharmony_ci * right away, these two if statements catch everything involving a 33158c2ecf20Sopenharmony_ci * single or absent peer SID/label */ 33168c2ecf20Sopenharmony_ci if (xfrm_sid == SECSID_NULL) { 33178c2ecf20Sopenharmony_ci *peer_sid = nlbl_sid; 33188c2ecf20Sopenharmony_ci return 0; 33198c2ecf20Sopenharmony_ci } 33208c2ecf20Sopenharmony_ci /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label 33218c2ecf20Sopenharmony_ci * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label 33228c2ecf20Sopenharmony_ci * is present */ 33238c2ecf20Sopenharmony_ci if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) { 33248c2ecf20Sopenharmony_ci *peer_sid = xfrm_sid; 33258c2ecf20Sopenharmony_ci return 0; 33268c2ecf20Sopenharmony_ci } 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 33298c2ecf20Sopenharmony_ci return 0; 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci rcu_read_lock(); 33328c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 33338c2ecf20Sopenharmony_ci policydb = &policy->policydb; 33348c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 33358c2ecf20Sopenharmony_ci 33368c2ecf20Sopenharmony_ci /* 33378c2ecf20Sopenharmony_ci * We don't need to check initialized here since the only way both 33388c2ecf20Sopenharmony_ci * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the 33398c2ecf20Sopenharmony_ci * security server was initialized and state->initialized was true. 33408c2ecf20Sopenharmony_ci */ 33418c2ecf20Sopenharmony_ci if (!policydb->mls_enabled) { 33428c2ecf20Sopenharmony_ci rc = 0; 33438c2ecf20Sopenharmony_ci goto out; 33448c2ecf20Sopenharmony_ci } 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_ci rc = -EINVAL; 33478c2ecf20Sopenharmony_ci nlbl_ctx = sidtab_search(sidtab, nlbl_sid); 33488c2ecf20Sopenharmony_ci if (!nlbl_ctx) { 33498c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 33508c2ecf20Sopenharmony_ci __func__, nlbl_sid); 33518c2ecf20Sopenharmony_ci goto out; 33528c2ecf20Sopenharmony_ci } 33538c2ecf20Sopenharmony_ci rc = -EINVAL; 33548c2ecf20Sopenharmony_ci xfrm_ctx = sidtab_search(sidtab, xfrm_sid); 33558c2ecf20Sopenharmony_ci if (!xfrm_ctx) { 33568c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized SID %d\n", 33578c2ecf20Sopenharmony_ci __func__, xfrm_sid); 33588c2ecf20Sopenharmony_ci goto out; 33598c2ecf20Sopenharmony_ci } 33608c2ecf20Sopenharmony_ci rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); 33618c2ecf20Sopenharmony_ci if (rc) 33628c2ecf20Sopenharmony_ci goto out; 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci /* at present NetLabel SIDs/labels really only carry MLS 33658c2ecf20Sopenharmony_ci * information so if the MLS portion of the NetLabel SID 33668c2ecf20Sopenharmony_ci * matches the MLS portion of the labeled XFRM SID/label 33678c2ecf20Sopenharmony_ci * then pass along the XFRM SID as it is the most 33688c2ecf20Sopenharmony_ci * expressive */ 33698c2ecf20Sopenharmony_ci *peer_sid = xfrm_sid; 33708c2ecf20Sopenharmony_ciout: 33718c2ecf20Sopenharmony_ci rcu_read_unlock(); 33728c2ecf20Sopenharmony_ci return rc; 33738c2ecf20Sopenharmony_ci} 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_cistatic int get_classes_callback(void *k, void *d, void *args) 33768c2ecf20Sopenharmony_ci{ 33778c2ecf20Sopenharmony_ci struct class_datum *datum = d; 33788c2ecf20Sopenharmony_ci char *name = k, **classes = args; 33798c2ecf20Sopenharmony_ci int value = datum->value - 1; 33808c2ecf20Sopenharmony_ci 33818c2ecf20Sopenharmony_ci classes[value] = kstrdup(name, GFP_ATOMIC); 33828c2ecf20Sopenharmony_ci if (!classes[value]) 33838c2ecf20Sopenharmony_ci return -ENOMEM; 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci return 0; 33868c2ecf20Sopenharmony_ci} 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ciint security_get_classes(struct selinux_policy *policy, 33898c2ecf20Sopenharmony_ci char ***classes, int *nclasses) 33908c2ecf20Sopenharmony_ci{ 33918c2ecf20Sopenharmony_ci struct policydb *policydb; 33928c2ecf20Sopenharmony_ci int rc; 33938c2ecf20Sopenharmony_ci 33948c2ecf20Sopenharmony_ci policydb = &policy->policydb; 33958c2ecf20Sopenharmony_ci 33968c2ecf20Sopenharmony_ci rc = -ENOMEM; 33978c2ecf20Sopenharmony_ci *nclasses = policydb->p_classes.nprim; 33988c2ecf20Sopenharmony_ci *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); 33998c2ecf20Sopenharmony_ci if (!*classes) 34008c2ecf20Sopenharmony_ci goto out; 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci rc = hashtab_map(&policydb->p_classes.table, get_classes_callback, 34038c2ecf20Sopenharmony_ci *classes); 34048c2ecf20Sopenharmony_ci if (rc) { 34058c2ecf20Sopenharmony_ci int i; 34068c2ecf20Sopenharmony_ci for (i = 0; i < *nclasses; i++) 34078c2ecf20Sopenharmony_ci kfree((*classes)[i]); 34088c2ecf20Sopenharmony_ci kfree(*classes); 34098c2ecf20Sopenharmony_ci } 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ciout: 34128c2ecf20Sopenharmony_ci return rc; 34138c2ecf20Sopenharmony_ci} 34148c2ecf20Sopenharmony_ci 34158c2ecf20Sopenharmony_cistatic int get_permissions_callback(void *k, void *d, void *args) 34168c2ecf20Sopenharmony_ci{ 34178c2ecf20Sopenharmony_ci struct perm_datum *datum = d; 34188c2ecf20Sopenharmony_ci char *name = k, **perms = args; 34198c2ecf20Sopenharmony_ci int value = datum->value - 1; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci perms[value] = kstrdup(name, GFP_ATOMIC); 34228c2ecf20Sopenharmony_ci if (!perms[value]) 34238c2ecf20Sopenharmony_ci return -ENOMEM; 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ci return 0; 34268c2ecf20Sopenharmony_ci} 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ciint security_get_permissions(struct selinux_policy *policy, 34298c2ecf20Sopenharmony_ci char *class, char ***perms, int *nperms) 34308c2ecf20Sopenharmony_ci{ 34318c2ecf20Sopenharmony_ci struct policydb *policydb; 34328c2ecf20Sopenharmony_ci int rc, i; 34338c2ecf20Sopenharmony_ci struct class_datum *match; 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci policydb = &policy->policydb; 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci rc = -EINVAL; 34388c2ecf20Sopenharmony_ci match = symtab_search(&policydb->p_classes, class); 34398c2ecf20Sopenharmony_ci if (!match) { 34408c2ecf20Sopenharmony_ci pr_err("SELinux: %s: unrecognized class %s\n", 34418c2ecf20Sopenharmony_ci __func__, class); 34428c2ecf20Sopenharmony_ci goto out; 34438c2ecf20Sopenharmony_ci } 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_ci rc = -ENOMEM; 34468c2ecf20Sopenharmony_ci *nperms = match->permissions.nprim; 34478c2ecf20Sopenharmony_ci *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); 34488c2ecf20Sopenharmony_ci if (!*perms) 34498c2ecf20Sopenharmony_ci goto out; 34508c2ecf20Sopenharmony_ci 34518c2ecf20Sopenharmony_ci if (match->comdatum) { 34528c2ecf20Sopenharmony_ci rc = hashtab_map(&match->comdatum->permissions.table, 34538c2ecf20Sopenharmony_ci get_permissions_callback, *perms); 34548c2ecf20Sopenharmony_ci if (rc) 34558c2ecf20Sopenharmony_ci goto err; 34568c2ecf20Sopenharmony_ci } 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci rc = hashtab_map(&match->permissions.table, get_permissions_callback, 34598c2ecf20Sopenharmony_ci *perms); 34608c2ecf20Sopenharmony_ci if (rc) 34618c2ecf20Sopenharmony_ci goto err; 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_ciout: 34648c2ecf20Sopenharmony_ci return rc; 34658c2ecf20Sopenharmony_ci 34668c2ecf20Sopenharmony_cierr: 34678c2ecf20Sopenharmony_ci for (i = 0; i < *nperms; i++) 34688c2ecf20Sopenharmony_ci kfree((*perms)[i]); 34698c2ecf20Sopenharmony_ci kfree(*perms); 34708c2ecf20Sopenharmony_ci return rc; 34718c2ecf20Sopenharmony_ci} 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ciint security_get_reject_unknown(struct selinux_state *state) 34748c2ecf20Sopenharmony_ci{ 34758c2ecf20Sopenharmony_ci struct selinux_policy *policy; 34768c2ecf20Sopenharmony_ci int value; 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 34798c2ecf20Sopenharmony_ci return 0; 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci rcu_read_lock(); 34828c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 34838c2ecf20Sopenharmony_ci value = policy->policydb.reject_unknown; 34848c2ecf20Sopenharmony_ci rcu_read_unlock(); 34858c2ecf20Sopenharmony_ci return value; 34868c2ecf20Sopenharmony_ci} 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ciint security_get_allow_unknown(struct selinux_state *state) 34898c2ecf20Sopenharmony_ci{ 34908c2ecf20Sopenharmony_ci struct selinux_policy *policy; 34918c2ecf20Sopenharmony_ci int value; 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 34948c2ecf20Sopenharmony_ci return 0; 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci rcu_read_lock(); 34978c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 34988c2ecf20Sopenharmony_ci value = policy->policydb.allow_unknown; 34998c2ecf20Sopenharmony_ci rcu_read_unlock(); 35008c2ecf20Sopenharmony_ci return value; 35018c2ecf20Sopenharmony_ci} 35028c2ecf20Sopenharmony_ci 35038c2ecf20Sopenharmony_ci/** 35048c2ecf20Sopenharmony_ci * security_policycap_supported - Check for a specific policy capability 35058c2ecf20Sopenharmony_ci * @req_cap: capability 35068c2ecf20Sopenharmony_ci * 35078c2ecf20Sopenharmony_ci * Description: 35088c2ecf20Sopenharmony_ci * This function queries the currently loaded policy to see if it supports the 35098c2ecf20Sopenharmony_ci * capability specified by @req_cap. Returns true (1) if the capability is 35108c2ecf20Sopenharmony_ci * supported, false (0) if it isn't supported. 35118c2ecf20Sopenharmony_ci * 35128c2ecf20Sopenharmony_ci */ 35138c2ecf20Sopenharmony_ciint security_policycap_supported(struct selinux_state *state, 35148c2ecf20Sopenharmony_ci unsigned int req_cap) 35158c2ecf20Sopenharmony_ci{ 35168c2ecf20Sopenharmony_ci struct selinux_policy *policy; 35178c2ecf20Sopenharmony_ci int rc; 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 35208c2ecf20Sopenharmony_ci return 0; 35218c2ecf20Sopenharmony_ci 35228c2ecf20Sopenharmony_ci rcu_read_lock(); 35238c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 35248c2ecf20Sopenharmony_ci rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap); 35258c2ecf20Sopenharmony_ci rcu_read_unlock(); 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_ci return rc; 35288c2ecf20Sopenharmony_ci} 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_cistruct selinux_audit_rule { 35318c2ecf20Sopenharmony_ci u32 au_seqno; 35328c2ecf20Sopenharmony_ci struct context au_ctxt; 35338c2ecf20Sopenharmony_ci}; 35348c2ecf20Sopenharmony_ci 35358c2ecf20Sopenharmony_civoid selinux_audit_rule_free(void *vrule) 35368c2ecf20Sopenharmony_ci{ 35378c2ecf20Sopenharmony_ci struct selinux_audit_rule *rule = vrule; 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_ci if (rule) { 35408c2ecf20Sopenharmony_ci context_destroy(&rule->au_ctxt); 35418c2ecf20Sopenharmony_ci kfree(rule); 35428c2ecf20Sopenharmony_ci } 35438c2ecf20Sopenharmony_ci} 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_ciint selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) 35468c2ecf20Sopenharmony_ci{ 35478c2ecf20Sopenharmony_ci struct selinux_state *state = &selinux_state; 35488c2ecf20Sopenharmony_ci struct selinux_policy *policy; 35498c2ecf20Sopenharmony_ci struct policydb *policydb; 35508c2ecf20Sopenharmony_ci struct selinux_audit_rule *tmprule; 35518c2ecf20Sopenharmony_ci struct role_datum *roledatum; 35528c2ecf20Sopenharmony_ci struct type_datum *typedatum; 35538c2ecf20Sopenharmony_ci struct user_datum *userdatum; 35548c2ecf20Sopenharmony_ci struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule; 35558c2ecf20Sopenharmony_ci int rc = 0; 35568c2ecf20Sopenharmony_ci 35578c2ecf20Sopenharmony_ci *rule = NULL; 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 35608c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ci switch (field) { 35638c2ecf20Sopenharmony_ci case AUDIT_SUBJ_USER: 35648c2ecf20Sopenharmony_ci case AUDIT_SUBJ_ROLE: 35658c2ecf20Sopenharmony_ci case AUDIT_SUBJ_TYPE: 35668c2ecf20Sopenharmony_ci case AUDIT_OBJ_USER: 35678c2ecf20Sopenharmony_ci case AUDIT_OBJ_ROLE: 35688c2ecf20Sopenharmony_ci case AUDIT_OBJ_TYPE: 35698c2ecf20Sopenharmony_ci /* only 'equals' and 'not equals' fit user, role, and type */ 35708c2ecf20Sopenharmony_ci if (op != Audit_equal && op != Audit_not_equal) 35718c2ecf20Sopenharmony_ci return -EINVAL; 35728c2ecf20Sopenharmony_ci break; 35738c2ecf20Sopenharmony_ci case AUDIT_SUBJ_SEN: 35748c2ecf20Sopenharmony_ci case AUDIT_SUBJ_CLR: 35758c2ecf20Sopenharmony_ci case AUDIT_OBJ_LEV_LOW: 35768c2ecf20Sopenharmony_ci case AUDIT_OBJ_LEV_HIGH: 35778c2ecf20Sopenharmony_ci /* we do not allow a range, indicated by the presence of '-' */ 35788c2ecf20Sopenharmony_ci if (strchr(rulestr, '-')) 35798c2ecf20Sopenharmony_ci return -EINVAL; 35808c2ecf20Sopenharmony_ci break; 35818c2ecf20Sopenharmony_ci default: 35828c2ecf20Sopenharmony_ci /* only the above fields are valid */ 35838c2ecf20Sopenharmony_ci return -EINVAL; 35848c2ecf20Sopenharmony_ci } 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL); 35878c2ecf20Sopenharmony_ci if (!tmprule) 35888c2ecf20Sopenharmony_ci return -ENOMEM; 35898c2ecf20Sopenharmony_ci 35908c2ecf20Sopenharmony_ci context_init(&tmprule->au_ctxt); 35918c2ecf20Sopenharmony_ci 35928c2ecf20Sopenharmony_ci rcu_read_lock(); 35938c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 35948c2ecf20Sopenharmony_ci policydb = &policy->policydb; 35958c2ecf20Sopenharmony_ci 35968c2ecf20Sopenharmony_ci tmprule->au_seqno = policy->latest_granting; 35978c2ecf20Sopenharmony_ci 35988c2ecf20Sopenharmony_ci switch (field) { 35998c2ecf20Sopenharmony_ci case AUDIT_SUBJ_USER: 36008c2ecf20Sopenharmony_ci case AUDIT_OBJ_USER: 36018c2ecf20Sopenharmony_ci rc = -EINVAL; 36028c2ecf20Sopenharmony_ci userdatum = symtab_search(&policydb->p_users, rulestr); 36038c2ecf20Sopenharmony_ci if (!userdatum) 36048c2ecf20Sopenharmony_ci goto out; 36058c2ecf20Sopenharmony_ci tmprule->au_ctxt.user = userdatum->value; 36068c2ecf20Sopenharmony_ci break; 36078c2ecf20Sopenharmony_ci case AUDIT_SUBJ_ROLE: 36088c2ecf20Sopenharmony_ci case AUDIT_OBJ_ROLE: 36098c2ecf20Sopenharmony_ci rc = -EINVAL; 36108c2ecf20Sopenharmony_ci roledatum = symtab_search(&policydb->p_roles, rulestr); 36118c2ecf20Sopenharmony_ci if (!roledatum) 36128c2ecf20Sopenharmony_ci goto out; 36138c2ecf20Sopenharmony_ci tmprule->au_ctxt.role = roledatum->value; 36148c2ecf20Sopenharmony_ci break; 36158c2ecf20Sopenharmony_ci case AUDIT_SUBJ_TYPE: 36168c2ecf20Sopenharmony_ci case AUDIT_OBJ_TYPE: 36178c2ecf20Sopenharmony_ci rc = -EINVAL; 36188c2ecf20Sopenharmony_ci typedatum = symtab_search(&policydb->p_types, rulestr); 36198c2ecf20Sopenharmony_ci if (!typedatum) 36208c2ecf20Sopenharmony_ci goto out; 36218c2ecf20Sopenharmony_ci tmprule->au_ctxt.type = typedatum->value; 36228c2ecf20Sopenharmony_ci break; 36238c2ecf20Sopenharmony_ci case AUDIT_SUBJ_SEN: 36248c2ecf20Sopenharmony_ci case AUDIT_SUBJ_CLR: 36258c2ecf20Sopenharmony_ci case AUDIT_OBJ_LEV_LOW: 36268c2ecf20Sopenharmony_ci case AUDIT_OBJ_LEV_HIGH: 36278c2ecf20Sopenharmony_ci rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt, 36288c2ecf20Sopenharmony_ci GFP_ATOMIC); 36298c2ecf20Sopenharmony_ci if (rc) 36308c2ecf20Sopenharmony_ci goto out; 36318c2ecf20Sopenharmony_ci break; 36328c2ecf20Sopenharmony_ci } 36338c2ecf20Sopenharmony_ci rc = 0; 36348c2ecf20Sopenharmony_ciout: 36358c2ecf20Sopenharmony_ci rcu_read_unlock(); 36368c2ecf20Sopenharmony_ci 36378c2ecf20Sopenharmony_ci if (rc) { 36388c2ecf20Sopenharmony_ci selinux_audit_rule_free(tmprule); 36398c2ecf20Sopenharmony_ci tmprule = NULL; 36408c2ecf20Sopenharmony_ci } 36418c2ecf20Sopenharmony_ci 36428c2ecf20Sopenharmony_ci *rule = tmprule; 36438c2ecf20Sopenharmony_ci 36448c2ecf20Sopenharmony_ci return rc; 36458c2ecf20Sopenharmony_ci} 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci/* Check to see if the rule contains any selinux fields */ 36488c2ecf20Sopenharmony_ciint selinux_audit_rule_known(struct audit_krule *rule) 36498c2ecf20Sopenharmony_ci{ 36508c2ecf20Sopenharmony_ci int i; 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci for (i = 0; i < rule->field_count; i++) { 36538c2ecf20Sopenharmony_ci struct audit_field *f = &rule->fields[i]; 36548c2ecf20Sopenharmony_ci switch (f->type) { 36558c2ecf20Sopenharmony_ci case AUDIT_SUBJ_USER: 36568c2ecf20Sopenharmony_ci case AUDIT_SUBJ_ROLE: 36578c2ecf20Sopenharmony_ci case AUDIT_SUBJ_TYPE: 36588c2ecf20Sopenharmony_ci case AUDIT_SUBJ_SEN: 36598c2ecf20Sopenharmony_ci case AUDIT_SUBJ_CLR: 36608c2ecf20Sopenharmony_ci case AUDIT_OBJ_USER: 36618c2ecf20Sopenharmony_ci case AUDIT_OBJ_ROLE: 36628c2ecf20Sopenharmony_ci case AUDIT_OBJ_TYPE: 36638c2ecf20Sopenharmony_ci case AUDIT_OBJ_LEV_LOW: 36648c2ecf20Sopenharmony_ci case AUDIT_OBJ_LEV_HIGH: 36658c2ecf20Sopenharmony_ci return 1; 36668c2ecf20Sopenharmony_ci } 36678c2ecf20Sopenharmony_ci } 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_ci return 0; 36708c2ecf20Sopenharmony_ci} 36718c2ecf20Sopenharmony_ci 36728c2ecf20Sopenharmony_ciint selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) 36738c2ecf20Sopenharmony_ci{ 36748c2ecf20Sopenharmony_ci struct selinux_state *state = &selinux_state; 36758c2ecf20Sopenharmony_ci struct selinux_policy *policy; 36768c2ecf20Sopenharmony_ci struct context *ctxt; 36778c2ecf20Sopenharmony_ci struct mls_level *level; 36788c2ecf20Sopenharmony_ci struct selinux_audit_rule *rule = vrule; 36798c2ecf20Sopenharmony_ci int match = 0; 36808c2ecf20Sopenharmony_ci 36818c2ecf20Sopenharmony_ci if (unlikely(!rule)) { 36828c2ecf20Sopenharmony_ci WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n"); 36838c2ecf20Sopenharmony_ci return -ENOENT; 36848c2ecf20Sopenharmony_ci } 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 36878c2ecf20Sopenharmony_ci return 0; 36888c2ecf20Sopenharmony_ci 36898c2ecf20Sopenharmony_ci rcu_read_lock(); 36908c2ecf20Sopenharmony_ci 36918c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ci if (rule->au_seqno < policy->latest_granting) { 36948c2ecf20Sopenharmony_ci match = -ESTALE; 36958c2ecf20Sopenharmony_ci goto out; 36968c2ecf20Sopenharmony_ci } 36978c2ecf20Sopenharmony_ci 36988c2ecf20Sopenharmony_ci ctxt = sidtab_search(policy->sidtab, sid); 36998c2ecf20Sopenharmony_ci if (unlikely(!ctxt)) { 37008c2ecf20Sopenharmony_ci WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", 37018c2ecf20Sopenharmony_ci sid); 37028c2ecf20Sopenharmony_ci match = -ENOENT; 37038c2ecf20Sopenharmony_ci goto out; 37048c2ecf20Sopenharmony_ci } 37058c2ecf20Sopenharmony_ci 37068c2ecf20Sopenharmony_ci /* a field/op pair that is not caught here will simply fall through 37078c2ecf20Sopenharmony_ci without a match */ 37088c2ecf20Sopenharmony_ci switch (field) { 37098c2ecf20Sopenharmony_ci case AUDIT_SUBJ_USER: 37108c2ecf20Sopenharmony_ci case AUDIT_OBJ_USER: 37118c2ecf20Sopenharmony_ci switch (op) { 37128c2ecf20Sopenharmony_ci case Audit_equal: 37138c2ecf20Sopenharmony_ci match = (ctxt->user == rule->au_ctxt.user); 37148c2ecf20Sopenharmony_ci break; 37158c2ecf20Sopenharmony_ci case Audit_not_equal: 37168c2ecf20Sopenharmony_ci match = (ctxt->user != rule->au_ctxt.user); 37178c2ecf20Sopenharmony_ci break; 37188c2ecf20Sopenharmony_ci } 37198c2ecf20Sopenharmony_ci break; 37208c2ecf20Sopenharmony_ci case AUDIT_SUBJ_ROLE: 37218c2ecf20Sopenharmony_ci case AUDIT_OBJ_ROLE: 37228c2ecf20Sopenharmony_ci switch (op) { 37238c2ecf20Sopenharmony_ci case Audit_equal: 37248c2ecf20Sopenharmony_ci match = (ctxt->role == rule->au_ctxt.role); 37258c2ecf20Sopenharmony_ci break; 37268c2ecf20Sopenharmony_ci case Audit_not_equal: 37278c2ecf20Sopenharmony_ci match = (ctxt->role != rule->au_ctxt.role); 37288c2ecf20Sopenharmony_ci break; 37298c2ecf20Sopenharmony_ci } 37308c2ecf20Sopenharmony_ci break; 37318c2ecf20Sopenharmony_ci case AUDIT_SUBJ_TYPE: 37328c2ecf20Sopenharmony_ci case AUDIT_OBJ_TYPE: 37338c2ecf20Sopenharmony_ci switch (op) { 37348c2ecf20Sopenharmony_ci case Audit_equal: 37358c2ecf20Sopenharmony_ci match = (ctxt->type == rule->au_ctxt.type); 37368c2ecf20Sopenharmony_ci break; 37378c2ecf20Sopenharmony_ci case Audit_not_equal: 37388c2ecf20Sopenharmony_ci match = (ctxt->type != rule->au_ctxt.type); 37398c2ecf20Sopenharmony_ci break; 37408c2ecf20Sopenharmony_ci } 37418c2ecf20Sopenharmony_ci break; 37428c2ecf20Sopenharmony_ci case AUDIT_SUBJ_SEN: 37438c2ecf20Sopenharmony_ci case AUDIT_SUBJ_CLR: 37448c2ecf20Sopenharmony_ci case AUDIT_OBJ_LEV_LOW: 37458c2ecf20Sopenharmony_ci case AUDIT_OBJ_LEV_HIGH: 37468c2ecf20Sopenharmony_ci level = ((field == AUDIT_SUBJ_SEN || 37478c2ecf20Sopenharmony_ci field == AUDIT_OBJ_LEV_LOW) ? 37488c2ecf20Sopenharmony_ci &ctxt->range.level[0] : &ctxt->range.level[1]); 37498c2ecf20Sopenharmony_ci switch (op) { 37508c2ecf20Sopenharmony_ci case Audit_equal: 37518c2ecf20Sopenharmony_ci match = mls_level_eq(&rule->au_ctxt.range.level[0], 37528c2ecf20Sopenharmony_ci level); 37538c2ecf20Sopenharmony_ci break; 37548c2ecf20Sopenharmony_ci case Audit_not_equal: 37558c2ecf20Sopenharmony_ci match = !mls_level_eq(&rule->au_ctxt.range.level[0], 37568c2ecf20Sopenharmony_ci level); 37578c2ecf20Sopenharmony_ci break; 37588c2ecf20Sopenharmony_ci case Audit_lt: 37598c2ecf20Sopenharmony_ci match = (mls_level_dom(&rule->au_ctxt.range.level[0], 37608c2ecf20Sopenharmony_ci level) && 37618c2ecf20Sopenharmony_ci !mls_level_eq(&rule->au_ctxt.range.level[0], 37628c2ecf20Sopenharmony_ci level)); 37638c2ecf20Sopenharmony_ci break; 37648c2ecf20Sopenharmony_ci case Audit_le: 37658c2ecf20Sopenharmony_ci match = mls_level_dom(&rule->au_ctxt.range.level[0], 37668c2ecf20Sopenharmony_ci level); 37678c2ecf20Sopenharmony_ci break; 37688c2ecf20Sopenharmony_ci case Audit_gt: 37698c2ecf20Sopenharmony_ci match = (mls_level_dom(level, 37708c2ecf20Sopenharmony_ci &rule->au_ctxt.range.level[0]) && 37718c2ecf20Sopenharmony_ci !mls_level_eq(level, 37728c2ecf20Sopenharmony_ci &rule->au_ctxt.range.level[0])); 37738c2ecf20Sopenharmony_ci break; 37748c2ecf20Sopenharmony_ci case Audit_ge: 37758c2ecf20Sopenharmony_ci match = mls_level_dom(level, 37768c2ecf20Sopenharmony_ci &rule->au_ctxt.range.level[0]); 37778c2ecf20Sopenharmony_ci break; 37788c2ecf20Sopenharmony_ci } 37798c2ecf20Sopenharmony_ci } 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ciout: 37828c2ecf20Sopenharmony_ci rcu_read_unlock(); 37838c2ecf20Sopenharmony_ci return match; 37848c2ecf20Sopenharmony_ci} 37858c2ecf20Sopenharmony_ci 37868c2ecf20Sopenharmony_cistatic int (*aurule_callback)(void) = audit_update_lsm_rules; 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_cistatic int aurule_avc_callback(u32 event) 37898c2ecf20Sopenharmony_ci{ 37908c2ecf20Sopenharmony_ci int err = 0; 37918c2ecf20Sopenharmony_ci 37928c2ecf20Sopenharmony_ci if (event == AVC_CALLBACK_RESET && aurule_callback) 37938c2ecf20Sopenharmony_ci err = aurule_callback(); 37948c2ecf20Sopenharmony_ci return err; 37958c2ecf20Sopenharmony_ci} 37968c2ecf20Sopenharmony_ci 37978c2ecf20Sopenharmony_cistatic int __init aurule_init(void) 37988c2ecf20Sopenharmony_ci{ 37998c2ecf20Sopenharmony_ci int err; 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_ci err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET); 38028c2ecf20Sopenharmony_ci if (err) 38038c2ecf20Sopenharmony_ci panic("avc_add_callback() failed, error %d\n", err); 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci return err; 38068c2ecf20Sopenharmony_ci} 38078c2ecf20Sopenharmony_ci__initcall(aurule_init); 38088c2ecf20Sopenharmony_ci 38098c2ecf20Sopenharmony_ci#ifdef CONFIG_NETLABEL 38108c2ecf20Sopenharmony_ci/** 38118c2ecf20Sopenharmony_ci * security_netlbl_cache_add - Add an entry to the NetLabel cache 38128c2ecf20Sopenharmony_ci * @secattr: the NetLabel packet security attributes 38138c2ecf20Sopenharmony_ci * @sid: the SELinux SID 38148c2ecf20Sopenharmony_ci * 38158c2ecf20Sopenharmony_ci * Description: 38168c2ecf20Sopenharmony_ci * Attempt to cache the context in @ctx, which was derived from the packet in 38178c2ecf20Sopenharmony_ci * @skb, in the NetLabel subsystem cache. This function assumes @secattr has 38188c2ecf20Sopenharmony_ci * already been initialized. 38198c2ecf20Sopenharmony_ci * 38208c2ecf20Sopenharmony_ci */ 38218c2ecf20Sopenharmony_cistatic void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, 38228c2ecf20Sopenharmony_ci u32 sid) 38238c2ecf20Sopenharmony_ci{ 38248c2ecf20Sopenharmony_ci u32 *sid_cache; 38258c2ecf20Sopenharmony_ci 38268c2ecf20Sopenharmony_ci sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC); 38278c2ecf20Sopenharmony_ci if (sid_cache == NULL) 38288c2ecf20Sopenharmony_ci return; 38298c2ecf20Sopenharmony_ci secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); 38308c2ecf20Sopenharmony_ci if (secattr->cache == NULL) { 38318c2ecf20Sopenharmony_ci kfree(sid_cache); 38328c2ecf20Sopenharmony_ci return; 38338c2ecf20Sopenharmony_ci } 38348c2ecf20Sopenharmony_ci 38358c2ecf20Sopenharmony_ci *sid_cache = sid; 38368c2ecf20Sopenharmony_ci secattr->cache->free = kfree; 38378c2ecf20Sopenharmony_ci secattr->cache->data = sid_cache; 38388c2ecf20Sopenharmony_ci secattr->flags |= NETLBL_SECATTR_CACHE; 38398c2ecf20Sopenharmony_ci} 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci/** 38428c2ecf20Sopenharmony_ci * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID 38438c2ecf20Sopenharmony_ci * @secattr: the NetLabel packet security attributes 38448c2ecf20Sopenharmony_ci * @sid: the SELinux SID 38458c2ecf20Sopenharmony_ci * 38468c2ecf20Sopenharmony_ci * Description: 38478c2ecf20Sopenharmony_ci * Convert the given NetLabel security attributes in @secattr into a 38488c2ecf20Sopenharmony_ci * SELinux SID. If the @secattr field does not contain a full SELinux 38498c2ecf20Sopenharmony_ci * SID/context then use SECINITSID_NETMSG as the foundation. If possible the 38508c2ecf20Sopenharmony_ci * 'cache' field of @secattr is set and the CACHE flag is set; this is to 38518c2ecf20Sopenharmony_ci * allow the @secattr to be used by NetLabel to cache the secattr to SID 38528c2ecf20Sopenharmony_ci * conversion for future lookups. Returns zero on success, negative values on 38538c2ecf20Sopenharmony_ci * failure. 38548c2ecf20Sopenharmony_ci * 38558c2ecf20Sopenharmony_ci */ 38568c2ecf20Sopenharmony_ciint security_netlbl_secattr_to_sid(struct selinux_state *state, 38578c2ecf20Sopenharmony_ci struct netlbl_lsm_secattr *secattr, 38588c2ecf20Sopenharmony_ci u32 *sid) 38598c2ecf20Sopenharmony_ci{ 38608c2ecf20Sopenharmony_ci struct selinux_policy *policy; 38618c2ecf20Sopenharmony_ci struct policydb *policydb; 38628c2ecf20Sopenharmony_ci struct sidtab *sidtab; 38638c2ecf20Sopenharmony_ci int rc; 38648c2ecf20Sopenharmony_ci struct context *ctx; 38658c2ecf20Sopenharmony_ci struct context ctx_new; 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) { 38688c2ecf20Sopenharmony_ci *sid = SECSID_NULL; 38698c2ecf20Sopenharmony_ci return 0; 38708c2ecf20Sopenharmony_ci } 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ciretry: 38738c2ecf20Sopenharmony_ci rc = 0; 38748c2ecf20Sopenharmony_ci rcu_read_lock(); 38758c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 38768c2ecf20Sopenharmony_ci policydb = &policy->policydb; 38778c2ecf20Sopenharmony_ci sidtab = policy->sidtab; 38788c2ecf20Sopenharmony_ci 38798c2ecf20Sopenharmony_ci if (secattr->flags & NETLBL_SECATTR_CACHE) 38808c2ecf20Sopenharmony_ci *sid = *(u32 *)secattr->cache->data; 38818c2ecf20Sopenharmony_ci else if (secattr->flags & NETLBL_SECATTR_SECID) 38828c2ecf20Sopenharmony_ci *sid = secattr->attr.secid; 38838c2ecf20Sopenharmony_ci else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { 38848c2ecf20Sopenharmony_ci rc = -EIDRM; 38858c2ecf20Sopenharmony_ci ctx = sidtab_search(sidtab, SECINITSID_NETMSG); 38868c2ecf20Sopenharmony_ci if (ctx == NULL) 38878c2ecf20Sopenharmony_ci goto out; 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci context_init(&ctx_new); 38908c2ecf20Sopenharmony_ci ctx_new.user = ctx->user; 38918c2ecf20Sopenharmony_ci ctx_new.role = ctx->role; 38928c2ecf20Sopenharmony_ci ctx_new.type = ctx->type; 38938c2ecf20Sopenharmony_ci mls_import_netlbl_lvl(policydb, &ctx_new, secattr); 38948c2ecf20Sopenharmony_ci if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 38958c2ecf20Sopenharmony_ci rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr); 38968c2ecf20Sopenharmony_ci if (rc) 38978c2ecf20Sopenharmony_ci goto out; 38988c2ecf20Sopenharmony_ci } 38998c2ecf20Sopenharmony_ci rc = -EIDRM; 39008c2ecf20Sopenharmony_ci if (!mls_context_isvalid(policydb, &ctx_new)) { 39018c2ecf20Sopenharmony_ci ebitmap_destroy(&ctx_new.range.level[0].cat); 39028c2ecf20Sopenharmony_ci goto out; 39038c2ecf20Sopenharmony_ci } 39048c2ecf20Sopenharmony_ci 39058c2ecf20Sopenharmony_ci rc = sidtab_context_to_sid(sidtab, &ctx_new, sid); 39068c2ecf20Sopenharmony_ci ebitmap_destroy(&ctx_new.range.level[0].cat); 39078c2ecf20Sopenharmony_ci if (rc == -ESTALE) { 39088c2ecf20Sopenharmony_ci rcu_read_unlock(); 39098c2ecf20Sopenharmony_ci goto retry; 39108c2ecf20Sopenharmony_ci } 39118c2ecf20Sopenharmony_ci if (rc) 39128c2ecf20Sopenharmony_ci goto out; 39138c2ecf20Sopenharmony_ci 39148c2ecf20Sopenharmony_ci security_netlbl_cache_add(secattr, *sid); 39158c2ecf20Sopenharmony_ci } else 39168c2ecf20Sopenharmony_ci *sid = SECSID_NULL; 39178c2ecf20Sopenharmony_ci 39188c2ecf20Sopenharmony_ciout: 39198c2ecf20Sopenharmony_ci rcu_read_unlock(); 39208c2ecf20Sopenharmony_ci return rc; 39218c2ecf20Sopenharmony_ci} 39228c2ecf20Sopenharmony_ci 39238c2ecf20Sopenharmony_ci/** 39248c2ecf20Sopenharmony_ci * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr 39258c2ecf20Sopenharmony_ci * @sid: the SELinux SID 39268c2ecf20Sopenharmony_ci * @secattr: the NetLabel packet security attributes 39278c2ecf20Sopenharmony_ci * 39288c2ecf20Sopenharmony_ci * Description: 39298c2ecf20Sopenharmony_ci * Convert the given SELinux SID in @sid into a NetLabel security attribute. 39308c2ecf20Sopenharmony_ci * Returns zero on success, negative values on failure. 39318c2ecf20Sopenharmony_ci * 39328c2ecf20Sopenharmony_ci */ 39338c2ecf20Sopenharmony_ciint security_netlbl_sid_to_secattr(struct selinux_state *state, 39348c2ecf20Sopenharmony_ci u32 sid, struct netlbl_lsm_secattr *secattr) 39358c2ecf20Sopenharmony_ci{ 39368c2ecf20Sopenharmony_ci struct selinux_policy *policy; 39378c2ecf20Sopenharmony_ci struct policydb *policydb; 39388c2ecf20Sopenharmony_ci int rc; 39398c2ecf20Sopenharmony_ci struct context *ctx; 39408c2ecf20Sopenharmony_ci 39418c2ecf20Sopenharmony_ci if (!selinux_initialized(state)) 39428c2ecf20Sopenharmony_ci return 0; 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_ci rcu_read_lock(); 39458c2ecf20Sopenharmony_ci policy = rcu_dereference(state->policy); 39468c2ecf20Sopenharmony_ci policydb = &policy->policydb; 39478c2ecf20Sopenharmony_ci 39488c2ecf20Sopenharmony_ci rc = -ENOENT; 39498c2ecf20Sopenharmony_ci ctx = sidtab_search(policy->sidtab, sid); 39508c2ecf20Sopenharmony_ci if (ctx == NULL) 39518c2ecf20Sopenharmony_ci goto out; 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci rc = -ENOMEM; 39548c2ecf20Sopenharmony_ci secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1), 39558c2ecf20Sopenharmony_ci GFP_ATOMIC); 39568c2ecf20Sopenharmony_ci if (secattr->domain == NULL) 39578c2ecf20Sopenharmony_ci goto out; 39588c2ecf20Sopenharmony_ci 39598c2ecf20Sopenharmony_ci secattr->attr.secid = sid; 39608c2ecf20Sopenharmony_ci secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; 39618c2ecf20Sopenharmony_ci mls_export_netlbl_lvl(policydb, ctx, secattr); 39628c2ecf20Sopenharmony_ci rc = mls_export_netlbl_cat(policydb, ctx, secattr); 39638c2ecf20Sopenharmony_ciout: 39648c2ecf20Sopenharmony_ci rcu_read_unlock(); 39658c2ecf20Sopenharmony_ci return rc; 39668c2ecf20Sopenharmony_ci} 39678c2ecf20Sopenharmony_ci#endif /* CONFIG_NETLABEL */ 39688c2ecf20Sopenharmony_ci 39698c2ecf20Sopenharmony_ci/** 39708c2ecf20Sopenharmony_ci * security_read_policy - read the policy. 39718c2ecf20Sopenharmony_ci * @data: binary policy data 39728c2ecf20Sopenharmony_ci * @len: length of data in bytes 39738c2ecf20Sopenharmony_ci * 39748c2ecf20Sopenharmony_ci */ 39758c2ecf20Sopenharmony_ciint security_read_policy(struct selinux_state *state, 39768c2ecf20Sopenharmony_ci void **data, size_t *len) 39778c2ecf20Sopenharmony_ci{ 39788c2ecf20Sopenharmony_ci struct selinux_policy *policy; 39798c2ecf20Sopenharmony_ci int rc; 39808c2ecf20Sopenharmony_ci struct policy_file fp; 39818c2ecf20Sopenharmony_ci 39828c2ecf20Sopenharmony_ci policy = rcu_dereference_protected( 39838c2ecf20Sopenharmony_ci state->policy, lockdep_is_held(&state->policy_mutex)); 39848c2ecf20Sopenharmony_ci if (!policy) 39858c2ecf20Sopenharmony_ci return -EINVAL; 39868c2ecf20Sopenharmony_ci 39878c2ecf20Sopenharmony_ci *len = policy->policydb.len; 39888c2ecf20Sopenharmony_ci *data = vmalloc_user(*len); 39898c2ecf20Sopenharmony_ci if (!*data) 39908c2ecf20Sopenharmony_ci return -ENOMEM; 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci fp.data = *data; 39938c2ecf20Sopenharmony_ci fp.len = *len; 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ci rc = policydb_write(&policy->policydb, &fp); 39968c2ecf20Sopenharmony_ci if (rc) 39978c2ecf20Sopenharmony_ci return rc; 39988c2ecf20Sopenharmony_ci 39998c2ecf20Sopenharmony_ci *len = (unsigned long)fp.data - (unsigned long)*data; 40008c2ecf20Sopenharmony_ci return 0; 40018c2ecf20Sopenharmony_ci 40028c2ecf20Sopenharmony_ci} 4003