11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Implementation of the security services. 31da177e4SLinus Torvalds * 47efbb60bSStephen Smalley * Authors : Stephen Smalley, <sds@tycho.nsa.gov> 51da177e4SLinus Torvalds * James Morris <jmorris@redhat.com> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Support for enhanced MLS infrastructure. 10376bd9cbSDarrel Goeddel * Support for context based audit filters. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * Added conditional policy language extensions 151da177e4SLinus Torvalds * 1682c21bfaSPaul Moore * Updated: Hewlett-Packard <paul@paul-moore.com> 177420ed23SVenkat Yekkirala * 187420ed23SVenkat Yekkirala * Added support for NetLabel 193bb56b25SPaul Moore * Added support for the policy capability bitmap 207420ed23SVenkat Yekkirala * 21b94c7e67SChad Sellers * Updated: Chad Sellers <csellers@tresys.com> 22b94c7e67SChad Sellers * 23b94c7e67SChad Sellers * Added validation of kernel classes and permissions 24b94c7e67SChad Sellers * 2544c2d9bdSKaiGai Kohei * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com> 2644c2d9bdSKaiGai Kohei * 2744c2d9bdSKaiGai Kohei * Added support for bounds domain and audit messaged on masked permissions 2844c2d9bdSKaiGai Kohei * 290719aaf5SGuido Trentalancia * Updated: Guido Trentalancia <guido@trentalancia.com> 300719aaf5SGuido Trentalancia * 310719aaf5SGuido Trentalancia * Added support for runtime switching of the policy type 320719aaf5SGuido Trentalancia * 3344c2d9bdSKaiGai Kohei * Copyright (C) 2008, 2009 NEC Corporation 343bb56b25SPaul Moore * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. 35376bd9cbSDarrel Goeddel * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 36b94c7e67SChad Sellers * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC 371da177e4SLinus Torvalds * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 381da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 391da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 401da177e4SLinus Torvalds * the Free Software Foundation, version 2. 411da177e4SLinus Torvalds */ 421da177e4SLinus Torvalds #include <linux/kernel.h> 431da177e4SLinus Torvalds #include <linux/slab.h> 441da177e4SLinus Torvalds #include <linux/string.h> 451da177e4SLinus Torvalds #include <linux/spinlock.h> 469f2ad665SPaul Moore #include <linux/rcupdate.h> 471da177e4SLinus Torvalds #include <linux/errno.h> 481da177e4SLinus Torvalds #include <linux/in.h> 491da177e4SLinus Torvalds #include <linux/sched.h> 501da177e4SLinus Torvalds #include <linux/audit.h> 51bb003079SIngo Molnar #include <linux/mutex.h> 52f0d3d989SStephen Rothwell #include <linux/vmalloc.h> 537420ed23SVenkat Yekkirala #include <net/netlabel.h> 54bb003079SIngo Molnar 551da177e4SLinus Torvalds #include "flask.h" 561da177e4SLinus Torvalds #include "avc.h" 571da177e4SLinus Torvalds #include "avc_ss.h" 581da177e4SLinus Torvalds #include "security.h" 591da177e4SLinus Torvalds #include "context.h" 601da177e4SLinus Torvalds #include "policydb.h" 611da177e4SLinus Torvalds #include "sidtab.h" 621da177e4SLinus Torvalds #include "services.h" 631da177e4SLinus Torvalds #include "conditional.h" 641da177e4SLinus Torvalds #include "mls.h" 657420ed23SVenkat Yekkirala #include "objsec.h" 66c60475bfSPaul Moore #include "netlabel.h" 673de4bab5SPaul Moore #include "xfrm.h" 6802752760SPaul Moore #include "ebitmap.h" 699d57a7f9SAhmed S. Darwish #include "audit.h" 701da177e4SLinus Torvalds 714dc2fce3SStephen Smalley /* Policy capability names */ 7289f5bebcSAlexey Dobriyan const char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = { 734dc2fce3SStephen Smalley "network_peer_controls", 744dc2fce3SStephen Smalley "open_perms", 754dc2fce3SStephen Smalley "extended_socket_class", 764dc2fce3SStephen Smalley "always_check_network", 77af63f419SStephen Smalley "cgroup_seclabel", 78af63f419SStephen Smalley "nnp_nosuid_transition" 794dc2fce3SStephen Smalley }; 804dc2fce3SStephen Smalley 81aa8e712cSStephen Smalley static struct selinux_ss selinux_ss; 823bb56b25SPaul Moore 83aa8e712cSStephen Smalley void selinux_ss_init(struct selinux_ss **ss) 84aa8e712cSStephen Smalley { 85aa8e712cSStephen Smalley rwlock_init(&selinux_ss.policy_rwlock); 86aa8e712cSStephen Smalley mutex_init(&selinux_ss.status_lock); 87aa8e712cSStephen Smalley *ss = &selinux_ss; 88aa8e712cSStephen Smalley } 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds /* Forward declaration. */ 91aa8e712cSStephen Smalley static int context_struct_to_string(struct policydb *policydb, 92aa8e712cSStephen Smalley struct context *context, 93aa8e712cSStephen Smalley char **scontext, 941da177e4SLinus Torvalds u32 *scontext_len); 951da177e4SLinus Torvalds 96aa8e712cSStephen Smalley static void context_struct_compute_av(struct policydb *policydb, 97aa8e712cSStephen Smalley struct context *scontext, 98d9250deaSKaiGai Kohei struct context *tcontext, 99d9250deaSKaiGai Kohei u16 tclass, 100fa1aa143SJeff Vander Stoep struct av_decision *avd, 101fa1aa143SJeff Vander Stoep struct extended_perms *xperms); 102c6d3aaa4SStephen Smalley 103c6d3aaa4SStephen Smalley static int selinux_set_mapping(struct policydb *pol, 104c6d3aaa4SStephen Smalley struct security_class_mapping *map, 105aa8e712cSStephen Smalley struct selinux_map *out_map) 106c6d3aaa4SStephen Smalley { 107c6d3aaa4SStephen Smalley u16 i, j; 108c6d3aaa4SStephen Smalley unsigned k; 109c6d3aaa4SStephen Smalley bool print_unknown_handle = false; 110c6d3aaa4SStephen Smalley 111c6d3aaa4SStephen Smalley /* Find number of classes in the input mapping */ 112c6d3aaa4SStephen Smalley if (!map) 113c6d3aaa4SStephen Smalley return -EINVAL; 114c6d3aaa4SStephen Smalley i = 0; 115c6d3aaa4SStephen Smalley while (map[i].name) 116c6d3aaa4SStephen Smalley i++; 117c6d3aaa4SStephen Smalley 118c6d3aaa4SStephen Smalley /* Allocate space for the class records, plus one for class zero */ 119aa8e712cSStephen Smalley out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC); 120aa8e712cSStephen Smalley if (!out_map->mapping) 121c6d3aaa4SStephen Smalley return -ENOMEM; 122c6d3aaa4SStephen Smalley 123c6d3aaa4SStephen Smalley /* Store the raw class and permission values */ 124c6d3aaa4SStephen Smalley j = 0; 125c6d3aaa4SStephen Smalley while (map[j].name) { 126c6d3aaa4SStephen Smalley struct security_class_mapping *p_in = map + (j++); 127aa8e712cSStephen Smalley struct selinux_mapping *p_out = out_map->mapping + j; 128c6d3aaa4SStephen Smalley 129c6d3aaa4SStephen Smalley /* An empty class string skips ahead */ 130c6d3aaa4SStephen Smalley if (!strcmp(p_in->name, "")) { 131c6d3aaa4SStephen Smalley p_out->num_perms = 0; 132c6d3aaa4SStephen Smalley continue; 133c6d3aaa4SStephen Smalley } 134c6d3aaa4SStephen Smalley 135c6d3aaa4SStephen Smalley p_out->value = string_to_security_class(pol, p_in->name); 136c6d3aaa4SStephen Smalley if (!p_out->value) { 137b54c85c1Speter enderborg pr_info("SELinux: Class %s not defined in policy.\n", 138c6d3aaa4SStephen Smalley p_in->name); 139c6d3aaa4SStephen Smalley if (pol->reject_unknown) 140c6d3aaa4SStephen Smalley goto err; 141c6d3aaa4SStephen Smalley p_out->num_perms = 0; 142c6d3aaa4SStephen Smalley print_unknown_handle = true; 143c6d3aaa4SStephen Smalley continue; 144c6d3aaa4SStephen Smalley } 145c6d3aaa4SStephen Smalley 146c6d3aaa4SStephen Smalley k = 0; 147342e9157SMatthias Kaehlcke while (p_in->perms[k]) { 148c6d3aaa4SStephen Smalley /* An empty permission string skips ahead */ 149c6d3aaa4SStephen Smalley if (!*p_in->perms[k]) { 150c6d3aaa4SStephen Smalley k++; 151c6d3aaa4SStephen Smalley continue; 152c6d3aaa4SStephen Smalley } 153c6d3aaa4SStephen Smalley p_out->perms[k] = string_to_av_perm(pol, p_out->value, 154c6d3aaa4SStephen Smalley p_in->perms[k]); 155c6d3aaa4SStephen Smalley if (!p_out->perms[k]) { 156b54c85c1Speter enderborg pr_info("SELinux: Permission %s in class %s not defined in policy.\n", 157c6d3aaa4SStephen Smalley p_in->perms[k], p_in->name); 158c6d3aaa4SStephen Smalley if (pol->reject_unknown) 159c6d3aaa4SStephen Smalley goto err; 160c6d3aaa4SStephen Smalley print_unknown_handle = true; 161c6d3aaa4SStephen Smalley } 162c6d3aaa4SStephen Smalley 163c6d3aaa4SStephen Smalley k++; 164c6d3aaa4SStephen Smalley } 165c6d3aaa4SStephen Smalley p_out->num_perms = k; 166c6d3aaa4SStephen Smalley } 167c6d3aaa4SStephen Smalley 168c6d3aaa4SStephen Smalley if (print_unknown_handle) 169b54c85c1Speter enderborg pr_info("SELinux: the above unknown classes and permissions will be %s\n", 170c6d3aaa4SStephen Smalley pol->allow_unknown ? "allowed" : "denied"); 171c6d3aaa4SStephen Smalley 172aa8e712cSStephen Smalley out_map->size = i; 173c6d3aaa4SStephen Smalley return 0; 174c6d3aaa4SStephen Smalley err: 175aa8e712cSStephen Smalley kfree(out_map->mapping); 176aa8e712cSStephen Smalley out_map->mapping = NULL; 177c6d3aaa4SStephen Smalley return -EINVAL; 178c6d3aaa4SStephen Smalley } 179c6d3aaa4SStephen Smalley 180c6d3aaa4SStephen Smalley /* 181c6d3aaa4SStephen Smalley * Get real, policy values from mapped values 182c6d3aaa4SStephen Smalley */ 183c6d3aaa4SStephen Smalley 184aa8e712cSStephen Smalley static u16 unmap_class(struct selinux_map *map, u16 tclass) 185c6d3aaa4SStephen Smalley { 186aa8e712cSStephen Smalley if (tclass < map->size) 187aa8e712cSStephen Smalley return map->mapping[tclass].value; 188c6d3aaa4SStephen Smalley 189c6d3aaa4SStephen Smalley return tclass; 190c6d3aaa4SStephen Smalley } 191c6d3aaa4SStephen Smalley 1926f5317e7SHarry Ciao /* 1936f5317e7SHarry Ciao * Get kernel value for class from its policy value 1946f5317e7SHarry Ciao */ 195aa8e712cSStephen Smalley static u16 map_class(struct selinux_map *map, u16 pol_value) 1966f5317e7SHarry Ciao { 1976f5317e7SHarry Ciao u16 i; 1986f5317e7SHarry Ciao 199aa8e712cSStephen Smalley for (i = 1; i < map->size; i++) { 200aa8e712cSStephen Smalley if (map->mapping[i].value == pol_value) 2016f5317e7SHarry Ciao return i; 2026f5317e7SHarry Ciao } 2036f5317e7SHarry Ciao 20485cd6da5SStephen Smalley return SECCLASS_NULL; 2056f5317e7SHarry Ciao } 2066f5317e7SHarry Ciao 207aa8e712cSStephen Smalley static void map_decision(struct selinux_map *map, 208aa8e712cSStephen Smalley u16 tclass, struct av_decision *avd, 209c6d3aaa4SStephen Smalley int allow_unknown) 210c6d3aaa4SStephen Smalley { 211aa8e712cSStephen Smalley if (tclass < map->size) { 212aa8e712cSStephen Smalley struct selinux_mapping *mapping = &map->mapping[tclass]; 213aa8e712cSStephen Smalley unsigned int i, n = mapping->num_perms; 214c6d3aaa4SStephen Smalley u32 result; 215c6d3aaa4SStephen Smalley 216c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) { 217aa8e712cSStephen Smalley if (avd->allowed & mapping->perms[i]) 218c6d3aaa4SStephen Smalley result |= 1<<i; 219aa8e712cSStephen Smalley if (allow_unknown && !mapping->perms[i]) 220c6d3aaa4SStephen Smalley result |= 1<<i; 221c6d3aaa4SStephen Smalley } 222c6d3aaa4SStephen Smalley avd->allowed = result; 223c6d3aaa4SStephen Smalley 224c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) 225aa8e712cSStephen Smalley if (avd->auditallow & mapping->perms[i]) 226c6d3aaa4SStephen Smalley result |= 1<<i; 227c6d3aaa4SStephen Smalley avd->auditallow = result; 228c6d3aaa4SStephen Smalley 229c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) { 230aa8e712cSStephen Smalley if (avd->auditdeny & mapping->perms[i]) 231c6d3aaa4SStephen Smalley result |= 1<<i; 232aa8e712cSStephen Smalley if (!allow_unknown && !mapping->perms[i]) 233c6d3aaa4SStephen Smalley result |= 1<<i; 234c6d3aaa4SStephen Smalley } 2350bce9527SEric Paris /* 2360bce9527SEric Paris * In case the kernel has a bug and requests a permission 2370bce9527SEric Paris * between num_perms and the maximum permission number, we 2380bce9527SEric Paris * should audit that denial 2390bce9527SEric Paris */ 2400bce9527SEric Paris for (; i < (sizeof(u32)*8); i++) 2410bce9527SEric Paris result |= 1<<i; 242c6d3aaa4SStephen Smalley avd->auditdeny = result; 243c6d3aaa4SStephen Smalley } 244c6d3aaa4SStephen Smalley } 245c6d3aaa4SStephen Smalley 246aa8e712cSStephen Smalley int security_mls_enabled(struct selinux_state *state) 2470719aaf5SGuido Trentalancia { 248aa8e712cSStephen Smalley struct policydb *p = &state->ss->policydb; 249aa8e712cSStephen Smalley 250aa8e712cSStephen Smalley return p->mls_enabled; 2510719aaf5SGuido Trentalancia } 252c6d3aaa4SStephen Smalley 2531da177e4SLinus Torvalds /* 2541da177e4SLinus Torvalds * Return the boolean value of a constraint expression 2551da177e4SLinus Torvalds * when it is applied to the specified source and target 2561da177e4SLinus Torvalds * security contexts. 2571da177e4SLinus Torvalds * 2581da177e4SLinus Torvalds * xcontext is a special beast... It is used by the validatetrans rules 2591da177e4SLinus Torvalds * only. For these rules, scontext is the context before the transition, 2601da177e4SLinus Torvalds * tcontext is the context after the transition, and xcontext is the context 2611da177e4SLinus Torvalds * of the process performing the transition. All other callers of 2621da177e4SLinus Torvalds * constraint_expr_eval should pass in NULL for xcontext. 2631da177e4SLinus Torvalds */ 264aa8e712cSStephen Smalley static int constraint_expr_eval(struct policydb *policydb, 265aa8e712cSStephen Smalley struct context *scontext, 2661da177e4SLinus Torvalds struct context *tcontext, 2671da177e4SLinus Torvalds struct context *xcontext, 2681da177e4SLinus Torvalds struct constraint_expr *cexpr) 2691da177e4SLinus Torvalds { 2701da177e4SLinus Torvalds u32 val1, val2; 2711da177e4SLinus Torvalds struct context *c; 2721da177e4SLinus Torvalds struct role_datum *r1, *r2; 2731da177e4SLinus Torvalds struct mls_level *l1, *l2; 2741da177e4SLinus Torvalds struct constraint_expr *e; 2751da177e4SLinus Torvalds int s[CEXPR_MAXDEPTH]; 2761da177e4SLinus Torvalds int sp = -1; 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds for (e = cexpr; e; e = e->next) { 2791da177e4SLinus Torvalds switch (e->expr_type) { 2801da177e4SLinus Torvalds case CEXPR_NOT: 2811da177e4SLinus Torvalds BUG_ON(sp < 0); 2821da177e4SLinus Torvalds s[sp] = !s[sp]; 2831da177e4SLinus Torvalds break; 2841da177e4SLinus Torvalds case CEXPR_AND: 2851da177e4SLinus Torvalds BUG_ON(sp < 1); 2861da177e4SLinus Torvalds sp--; 2871da177e4SLinus Torvalds s[sp] &= s[sp + 1]; 2881da177e4SLinus Torvalds break; 2891da177e4SLinus Torvalds case CEXPR_OR: 2901da177e4SLinus Torvalds BUG_ON(sp < 1); 2911da177e4SLinus Torvalds sp--; 2921da177e4SLinus Torvalds s[sp] |= s[sp + 1]; 2931da177e4SLinus Torvalds break; 2941da177e4SLinus Torvalds case CEXPR_ATTR: 2951da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH - 1)) 2961da177e4SLinus Torvalds return 0; 2971da177e4SLinus Torvalds switch (e->attr) { 2981da177e4SLinus Torvalds case CEXPR_USER: 2991da177e4SLinus Torvalds val1 = scontext->user; 3001da177e4SLinus Torvalds val2 = tcontext->user; 3011da177e4SLinus Torvalds break; 3021da177e4SLinus Torvalds case CEXPR_TYPE: 3031da177e4SLinus Torvalds val1 = scontext->type; 3041da177e4SLinus Torvalds val2 = tcontext->type; 3051da177e4SLinus Torvalds break; 3061da177e4SLinus Torvalds case CEXPR_ROLE: 3071da177e4SLinus Torvalds val1 = scontext->role; 3081da177e4SLinus Torvalds val2 = tcontext->role; 309aa8e712cSStephen Smalley r1 = policydb->role_val_to_struct[val1 - 1]; 310aa8e712cSStephen Smalley r2 = policydb->role_val_to_struct[val2 - 1]; 3111da177e4SLinus Torvalds switch (e->op) { 3121da177e4SLinus Torvalds case CEXPR_DOM: 3131da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r1->dominates, 3141da177e4SLinus Torvalds val2 - 1); 3151da177e4SLinus Torvalds continue; 3161da177e4SLinus Torvalds case CEXPR_DOMBY: 3171da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r2->dominates, 3181da177e4SLinus Torvalds val1 - 1); 3191da177e4SLinus Torvalds continue; 3201da177e4SLinus Torvalds case CEXPR_INCOMP: 3211da177e4SLinus Torvalds s[++sp] = (!ebitmap_get_bit(&r1->dominates, 3221da177e4SLinus Torvalds val2 - 1) && 3231da177e4SLinus Torvalds !ebitmap_get_bit(&r2->dominates, 3241da177e4SLinus Torvalds val1 - 1)); 3251da177e4SLinus Torvalds continue; 3261da177e4SLinus Torvalds default: 3271da177e4SLinus Torvalds break; 3281da177e4SLinus Torvalds } 3291da177e4SLinus Torvalds break; 3301da177e4SLinus Torvalds case CEXPR_L1L2: 3311da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3321da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 3331da177e4SLinus Torvalds goto mls_ops; 3341da177e4SLinus Torvalds case CEXPR_L1H2: 3351da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3361da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3371da177e4SLinus Torvalds goto mls_ops; 3381da177e4SLinus Torvalds case CEXPR_H1L2: 3391da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 3401da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 3411da177e4SLinus Torvalds goto mls_ops; 3421da177e4SLinus Torvalds case CEXPR_H1H2: 3431da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 3441da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3451da177e4SLinus Torvalds goto mls_ops; 3461da177e4SLinus Torvalds case CEXPR_L1H1: 3471da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3481da177e4SLinus Torvalds l2 = &(scontext->range.level[1]); 3491da177e4SLinus Torvalds goto mls_ops; 3501da177e4SLinus Torvalds case CEXPR_L2H2: 3511da177e4SLinus Torvalds l1 = &(tcontext->range.level[0]); 3521da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3531da177e4SLinus Torvalds goto mls_ops; 3541da177e4SLinus Torvalds mls_ops: 3551da177e4SLinus Torvalds switch (e->op) { 3561da177e4SLinus Torvalds case CEXPR_EQ: 3571da177e4SLinus Torvalds s[++sp] = mls_level_eq(l1, l2); 3581da177e4SLinus Torvalds continue; 3591da177e4SLinus Torvalds case CEXPR_NEQ: 3601da177e4SLinus Torvalds s[++sp] = !mls_level_eq(l1, l2); 3611da177e4SLinus Torvalds continue; 3621da177e4SLinus Torvalds case CEXPR_DOM: 3631da177e4SLinus Torvalds s[++sp] = mls_level_dom(l1, l2); 3641da177e4SLinus Torvalds continue; 3651da177e4SLinus Torvalds case CEXPR_DOMBY: 3661da177e4SLinus Torvalds s[++sp] = mls_level_dom(l2, l1); 3671da177e4SLinus Torvalds continue; 3681da177e4SLinus Torvalds case CEXPR_INCOMP: 3691da177e4SLinus Torvalds s[++sp] = mls_level_incomp(l2, l1); 3701da177e4SLinus Torvalds continue; 3711da177e4SLinus Torvalds default: 3721da177e4SLinus Torvalds BUG(); 3731da177e4SLinus Torvalds return 0; 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds break; 3761da177e4SLinus Torvalds default: 3771da177e4SLinus Torvalds BUG(); 3781da177e4SLinus Torvalds return 0; 3791da177e4SLinus Torvalds } 3801da177e4SLinus Torvalds 3811da177e4SLinus Torvalds switch (e->op) { 3821da177e4SLinus Torvalds case CEXPR_EQ: 3831da177e4SLinus Torvalds s[++sp] = (val1 == val2); 3841da177e4SLinus Torvalds break; 3851da177e4SLinus Torvalds case CEXPR_NEQ: 3861da177e4SLinus Torvalds s[++sp] = (val1 != val2); 3871da177e4SLinus Torvalds break; 3881da177e4SLinus Torvalds default: 3891da177e4SLinus Torvalds BUG(); 3901da177e4SLinus Torvalds return 0; 3911da177e4SLinus Torvalds } 3921da177e4SLinus Torvalds break; 3931da177e4SLinus Torvalds case CEXPR_NAMES: 3941da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH-1)) 3951da177e4SLinus Torvalds return 0; 3961da177e4SLinus Torvalds c = scontext; 3971da177e4SLinus Torvalds if (e->attr & CEXPR_TARGET) 3981da177e4SLinus Torvalds c = tcontext; 3991da177e4SLinus Torvalds else if (e->attr & CEXPR_XTARGET) { 4001da177e4SLinus Torvalds c = xcontext; 4011da177e4SLinus Torvalds if (!c) { 4021da177e4SLinus Torvalds BUG(); 4031da177e4SLinus Torvalds return 0; 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds } 4061da177e4SLinus Torvalds if (e->attr & CEXPR_USER) 4071da177e4SLinus Torvalds val1 = c->user; 4081da177e4SLinus Torvalds else if (e->attr & CEXPR_ROLE) 4091da177e4SLinus Torvalds val1 = c->role; 4101da177e4SLinus Torvalds else if (e->attr & CEXPR_TYPE) 4111da177e4SLinus Torvalds val1 = c->type; 4121da177e4SLinus Torvalds else { 4131da177e4SLinus Torvalds BUG(); 4141da177e4SLinus Torvalds return 0; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds switch (e->op) { 4181da177e4SLinus Torvalds case CEXPR_EQ: 4191da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); 4201da177e4SLinus Torvalds break; 4211da177e4SLinus Torvalds case CEXPR_NEQ: 4221da177e4SLinus Torvalds s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); 4231da177e4SLinus Torvalds break; 4241da177e4SLinus Torvalds default: 4251da177e4SLinus Torvalds BUG(); 4261da177e4SLinus Torvalds return 0; 4271da177e4SLinus Torvalds } 4281da177e4SLinus Torvalds break; 4291da177e4SLinus Torvalds default: 4301da177e4SLinus Torvalds BUG(); 4311da177e4SLinus Torvalds return 0; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds } 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds BUG_ON(sp != 0); 4361da177e4SLinus Torvalds return s[0]; 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds /* 44044c2d9bdSKaiGai Kohei * security_dump_masked_av - dumps masked permissions during 44144c2d9bdSKaiGai Kohei * security_compute_av due to RBAC, MLS/Constraint and Type bounds. 44244c2d9bdSKaiGai Kohei */ 44344c2d9bdSKaiGai Kohei static int dump_masked_av_helper(void *k, void *d, void *args) 44444c2d9bdSKaiGai Kohei { 44544c2d9bdSKaiGai Kohei struct perm_datum *pdatum = d; 44644c2d9bdSKaiGai Kohei char **permission_names = args; 44744c2d9bdSKaiGai Kohei 44844c2d9bdSKaiGai Kohei BUG_ON(pdatum->value < 1 || pdatum->value > 32); 44944c2d9bdSKaiGai Kohei 45044c2d9bdSKaiGai Kohei permission_names[pdatum->value - 1] = (char *)k; 45144c2d9bdSKaiGai Kohei 45244c2d9bdSKaiGai Kohei return 0; 45344c2d9bdSKaiGai Kohei } 45444c2d9bdSKaiGai Kohei 455aa8e712cSStephen Smalley static void security_dump_masked_av(struct policydb *policydb, 456aa8e712cSStephen Smalley struct context *scontext, 45744c2d9bdSKaiGai Kohei struct context *tcontext, 45844c2d9bdSKaiGai Kohei u16 tclass, 45944c2d9bdSKaiGai Kohei u32 permissions, 46044c2d9bdSKaiGai Kohei const char *reason) 46144c2d9bdSKaiGai Kohei { 46244c2d9bdSKaiGai Kohei struct common_datum *common_dat; 46344c2d9bdSKaiGai Kohei struct class_datum *tclass_dat; 46444c2d9bdSKaiGai Kohei struct audit_buffer *ab; 46544c2d9bdSKaiGai Kohei char *tclass_name; 46644c2d9bdSKaiGai Kohei char *scontext_name = NULL; 46744c2d9bdSKaiGai Kohei char *tcontext_name = NULL; 46844c2d9bdSKaiGai Kohei char *permission_names[32]; 4692da5d31bSJames Morris int index; 4702da5d31bSJames Morris u32 length; 47144c2d9bdSKaiGai Kohei bool need_comma = false; 47244c2d9bdSKaiGai Kohei 47344c2d9bdSKaiGai Kohei if (!permissions) 47444c2d9bdSKaiGai Kohei return; 47544c2d9bdSKaiGai Kohei 476aa8e712cSStephen Smalley tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1); 477aa8e712cSStephen Smalley tclass_dat = policydb->class_val_to_struct[tclass - 1]; 47844c2d9bdSKaiGai Kohei common_dat = tclass_dat->comdatum; 47944c2d9bdSKaiGai Kohei 48044c2d9bdSKaiGai Kohei /* init permission_names */ 48144c2d9bdSKaiGai Kohei if (common_dat && 48244c2d9bdSKaiGai Kohei hashtab_map(common_dat->permissions.table, 48344c2d9bdSKaiGai Kohei dump_masked_av_helper, permission_names) < 0) 48444c2d9bdSKaiGai Kohei goto out; 48544c2d9bdSKaiGai Kohei 48644c2d9bdSKaiGai Kohei if (hashtab_map(tclass_dat->permissions.table, 48744c2d9bdSKaiGai Kohei dump_masked_av_helper, permission_names) < 0) 48844c2d9bdSKaiGai Kohei goto out; 48944c2d9bdSKaiGai Kohei 49044c2d9bdSKaiGai Kohei /* get scontext/tcontext in text form */ 491aa8e712cSStephen Smalley if (context_struct_to_string(policydb, scontext, 49244c2d9bdSKaiGai Kohei &scontext_name, &length) < 0) 49344c2d9bdSKaiGai Kohei goto out; 49444c2d9bdSKaiGai Kohei 495aa8e712cSStephen Smalley if (context_struct_to_string(policydb, tcontext, 49644c2d9bdSKaiGai Kohei &tcontext_name, &length) < 0) 49744c2d9bdSKaiGai Kohei goto out; 49844c2d9bdSKaiGai Kohei 49944c2d9bdSKaiGai Kohei /* audit a message */ 500cdfb6b34SRichard Guy Briggs ab = audit_log_start(audit_context(), 50144c2d9bdSKaiGai Kohei GFP_ATOMIC, AUDIT_SELINUX_ERR); 50244c2d9bdSKaiGai Kohei if (!ab) 50344c2d9bdSKaiGai Kohei goto out; 50444c2d9bdSKaiGai Kohei 50544c2d9bdSKaiGai Kohei audit_log_format(ab, "op=security_compute_av reason=%s " 50644c2d9bdSKaiGai Kohei "scontext=%s tcontext=%s tclass=%s perms=", 50744c2d9bdSKaiGai Kohei reason, scontext_name, tcontext_name, tclass_name); 50844c2d9bdSKaiGai Kohei 50944c2d9bdSKaiGai Kohei for (index = 0; index < 32; index++) { 51044c2d9bdSKaiGai Kohei u32 mask = (1 << index); 51144c2d9bdSKaiGai Kohei 51244c2d9bdSKaiGai Kohei if ((mask & permissions) == 0) 51344c2d9bdSKaiGai Kohei continue; 51444c2d9bdSKaiGai Kohei 51544c2d9bdSKaiGai Kohei audit_log_format(ab, "%s%s", 51644c2d9bdSKaiGai Kohei need_comma ? "," : "", 51744c2d9bdSKaiGai Kohei permission_names[index] 51844c2d9bdSKaiGai Kohei ? permission_names[index] : "????"); 51944c2d9bdSKaiGai Kohei need_comma = true; 52044c2d9bdSKaiGai Kohei } 52144c2d9bdSKaiGai Kohei audit_log_end(ab); 52244c2d9bdSKaiGai Kohei out: 52344c2d9bdSKaiGai Kohei /* release scontext/tcontext */ 52444c2d9bdSKaiGai Kohei kfree(tcontext_name); 52544c2d9bdSKaiGai Kohei kfree(scontext_name); 52644c2d9bdSKaiGai Kohei 52744c2d9bdSKaiGai Kohei return; 52844c2d9bdSKaiGai Kohei } 52944c2d9bdSKaiGai Kohei 53044c2d9bdSKaiGai Kohei /* 531d9250deaSKaiGai Kohei * security_boundary_permission - drops violated permissions 532d9250deaSKaiGai Kohei * on boundary constraint. 533d9250deaSKaiGai Kohei */ 534aa8e712cSStephen Smalley static void type_attribute_bounds_av(struct policydb *policydb, 535aa8e712cSStephen Smalley struct context *scontext, 536d9250deaSKaiGai Kohei struct context *tcontext, 537d9250deaSKaiGai Kohei u16 tclass, 538d9250deaSKaiGai Kohei struct av_decision *avd) 539d9250deaSKaiGai Kohei { 5402ae3ba39SKaiGai Kohei struct context lo_scontext; 5417ea59202SStephen Smalley struct context lo_tcontext, *tcontextp = tcontext; 5422ae3ba39SKaiGai Kohei struct av_decision lo_avd; 54323bdecb0SEric Paris struct type_datum *source; 54423bdecb0SEric Paris struct type_datum *target; 5452ae3ba39SKaiGai Kohei u32 masked = 0; 546d9250deaSKaiGai Kohei 547f07ea1d4SOndrej Mosnacek source = policydb->type_val_to_struct[scontext->type - 1]; 54823bdecb0SEric Paris BUG_ON(!source); 54923bdecb0SEric Paris 5507ea59202SStephen Smalley if (!source->bounds) 5517ea59202SStephen Smalley return; 5527ea59202SStephen Smalley 553f07ea1d4SOndrej Mosnacek target = policydb->type_val_to_struct[tcontext->type - 1]; 55423bdecb0SEric Paris BUG_ON(!target); 55523bdecb0SEric Paris 556d9250deaSKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd)); 557d9250deaSKaiGai Kohei 558d9250deaSKaiGai Kohei memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); 559d9250deaSKaiGai Kohei lo_scontext.type = source->bounds; 560d9250deaSKaiGai Kohei 5612ae3ba39SKaiGai Kohei if (target->bounds) { 5622ae3ba39SKaiGai Kohei memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); 5632ae3ba39SKaiGai Kohei lo_tcontext.type = target->bounds; 5647ea59202SStephen Smalley tcontextp = &lo_tcontext; 5652ae3ba39SKaiGai Kohei } 5662ae3ba39SKaiGai Kohei 567aa8e712cSStephen Smalley context_struct_compute_av(policydb, &lo_scontext, 5687ea59202SStephen Smalley tcontextp, 5692ae3ba39SKaiGai Kohei tclass, 570fa1aa143SJeff Vander Stoep &lo_avd, 571fa1aa143SJeff Vander Stoep NULL); 5722ae3ba39SKaiGai Kohei 5737ea59202SStephen Smalley masked = ~lo_avd.allowed & avd->allowed; 5747ea59202SStephen Smalley 5757ea59202SStephen Smalley if (likely(!masked)) 5767ea59202SStephen Smalley return; /* no masked permission */ 5777ea59202SStephen Smalley 578d9250deaSKaiGai Kohei /* mask violated permissions */ 579d9250deaSKaiGai Kohei avd->allowed &= ~masked; 580d9250deaSKaiGai Kohei 58144c2d9bdSKaiGai Kohei /* audit masked permissions */ 582aa8e712cSStephen Smalley security_dump_masked_av(policydb, scontext, tcontext, 58344c2d9bdSKaiGai Kohei tclass, masked, "bounds"); 584d9250deaSKaiGai Kohei } 585d9250deaSKaiGai Kohei 586d9250deaSKaiGai Kohei /* 587fa1aa143SJeff Vander Stoep * flag which drivers have permissions 588fa1aa143SJeff Vander Stoep * only looking for ioctl based extended permssions 589fa1aa143SJeff Vander Stoep */ 590fa1aa143SJeff Vander Stoep void services_compute_xperms_drivers( 591fa1aa143SJeff Vander Stoep struct extended_perms *xperms, 592fa1aa143SJeff Vander Stoep struct avtab_node *node) 593fa1aa143SJeff Vander Stoep { 594fa1aa143SJeff Vander Stoep unsigned int i; 595fa1aa143SJeff Vander Stoep 596fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 597fa1aa143SJeff Vander Stoep /* if one or more driver has all permissions allowed */ 598fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) 599fa1aa143SJeff Vander Stoep xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; 600fa1aa143SJeff Vander Stoep } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 601fa1aa143SJeff Vander Stoep /* if allowing permissions within a driver */ 602fa1aa143SJeff Vander Stoep security_xperm_set(xperms->drivers.p, 603fa1aa143SJeff Vander Stoep node->datum.u.xperms->driver); 604fa1aa143SJeff Vander Stoep } 605fa1aa143SJeff Vander Stoep 606fa1aa143SJeff Vander Stoep /* If no ioctl commands are allowed, ignore auditallow and auditdeny */ 607fa1aa143SJeff Vander Stoep if (node->key.specified & AVTAB_XPERMS_ALLOWED) 608fa1aa143SJeff Vander Stoep xperms->len = 1; 609fa1aa143SJeff Vander Stoep } 610fa1aa143SJeff Vander Stoep 611fa1aa143SJeff Vander Stoep /* 612fa1aa143SJeff Vander Stoep * Compute access vectors and extended permissions based on a context 613fa1aa143SJeff Vander Stoep * structure pair for the permissions in a particular class. 6141da177e4SLinus Torvalds */ 615aa8e712cSStephen Smalley static void context_struct_compute_av(struct policydb *policydb, 616aa8e712cSStephen Smalley struct context *scontext, 6171da177e4SLinus Torvalds struct context *tcontext, 6181da177e4SLinus Torvalds u16 tclass, 619fa1aa143SJeff Vander Stoep struct av_decision *avd, 620fa1aa143SJeff Vander Stoep struct extended_perms *xperms) 6211da177e4SLinus Torvalds { 6221da177e4SLinus Torvalds struct constraint_node *constraint; 6231da177e4SLinus Torvalds struct role_allow *ra; 6241da177e4SLinus Torvalds struct avtab_key avkey; 625782ebb99SStephen Smalley struct avtab_node *node; 6261da177e4SLinus Torvalds struct class_datum *tclass_datum; 627782ebb99SStephen Smalley struct ebitmap *sattr, *tattr; 628782ebb99SStephen Smalley struct ebitmap_node *snode, *tnode; 629782ebb99SStephen Smalley unsigned int i, j; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds avd->allowed = 0; 6321da177e4SLinus Torvalds avd->auditallow = 0; 6331da177e4SLinus Torvalds avd->auditdeny = 0xffffffff; 634fa1aa143SJeff Vander Stoep if (xperms) { 635fa1aa143SJeff Vander Stoep memset(&xperms->drivers, 0, sizeof(xperms->drivers)); 636fa1aa143SJeff Vander Stoep xperms->len = 0; 637fa1aa143SJeff Vander Stoep } 6381da177e4SLinus Torvalds 639aa8e712cSStephen Smalley if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) { 640c6d3aaa4SStephen Smalley if (printk_ratelimit()) 641b54c85c1Speter enderborg pr_warn("SELinux: Invalid class %hu\n", tclass); 64219439d05SStephen Smalley return; 643c6d3aaa4SStephen Smalley } 6443f12070eSEric Paris 645aa8e712cSStephen Smalley tclass_datum = policydb->class_val_to_struct[tclass - 1]; 6463f12070eSEric Paris 6473f12070eSEric Paris /* 6481da177e4SLinus Torvalds * If a specific type enforcement rule was defined for 6491da177e4SLinus Torvalds * this permission check, then use it. 6501da177e4SLinus Torvalds */ 6511da177e4SLinus Torvalds avkey.target_class = tclass; 652fa1aa143SJeff Vander Stoep avkey.specified = AVTAB_AV | AVTAB_XPERMS; 653acdf52d9SKent Overstreet sattr = &policydb->type_attr_map_array[scontext->type - 1]; 654acdf52d9SKent Overstreet tattr = &policydb->type_attr_map_array[tcontext->type - 1]; 6559fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(sattr, snode, i) { 6569fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(tattr, tnode, j) { 657782ebb99SStephen Smalley avkey.source_type = i + 1; 658782ebb99SStephen Smalley avkey.target_type = j + 1; 659aa8e712cSStephen Smalley for (node = avtab_search_node(&policydb->te_avtab, 660aa8e712cSStephen Smalley &avkey); 661dbc74c65SVesa-Matti Kari node; 662782ebb99SStephen Smalley node = avtab_search_node_next(node, avkey.specified)) { 663782ebb99SStephen Smalley if (node->key.specified == AVTAB_ALLOWED) 664fa1aa143SJeff Vander Stoep avd->allowed |= node->datum.u.data; 665782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITALLOW) 666fa1aa143SJeff Vander Stoep avd->auditallow |= node->datum.u.data; 667782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITDENY) 668fa1aa143SJeff Vander Stoep avd->auditdeny &= node->datum.u.data; 669fa1aa143SJeff Vander Stoep else if (xperms && (node->key.specified & AVTAB_XPERMS)) 670fa1aa143SJeff Vander Stoep services_compute_xperms_drivers(xperms, node); 6711da177e4SLinus Torvalds } 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds /* Check conditional av table for additional permissions */ 674aa8e712cSStephen Smalley cond_compute_av(&policydb->te_cond_avtab, &avkey, 675fa1aa143SJeff Vander Stoep avd, xperms); 6761da177e4SLinus Torvalds 677782ebb99SStephen Smalley } 678782ebb99SStephen Smalley } 679782ebb99SStephen Smalley 6801da177e4SLinus Torvalds /* 6811da177e4SLinus Torvalds * Remove any permissions prohibited by a constraint (this includes 6821da177e4SLinus Torvalds * the MLS policy). 6831da177e4SLinus Torvalds */ 6841da177e4SLinus Torvalds constraint = tclass_datum->constraints; 6851da177e4SLinus Torvalds while (constraint) { 6861da177e4SLinus Torvalds if ((constraint->permissions & (avd->allowed)) && 687aa8e712cSStephen Smalley !constraint_expr_eval(policydb, scontext, tcontext, NULL, 6881da177e4SLinus Torvalds constraint->expr)) { 689caabbdc0SKaiGai Kohei avd->allowed &= ~(constraint->permissions); 6901da177e4SLinus Torvalds } 6911da177e4SLinus Torvalds constraint = constraint->next; 6921da177e4SLinus Torvalds } 6931da177e4SLinus Torvalds 6941da177e4SLinus Torvalds /* 6951da177e4SLinus Torvalds * If checking process transition permission and the 6961da177e4SLinus Torvalds * role is changing, then check the (current_role, new_role) 6971da177e4SLinus Torvalds * pair. 6981da177e4SLinus Torvalds */ 699aa8e712cSStephen Smalley if (tclass == policydb->process_class && 700aa8e712cSStephen Smalley (avd->allowed & policydb->process_trans_perms) && 7011da177e4SLinus Torvalds scontext->role != tcontext->role) { 702aa8e712cSStephen Smalley for (ra = policydb->role_allow; ra; ra = ra->next) { 7031da177e4SLinus Torvalds if (scontext->role == ra->role && 7041da177e4SLinus Torvalds tcontext->role == ra->new_role) 7051da177e4SLinus Torvalds break; 7061da177e4SLinus Torvalds } 7071da177e4SLinus Torvalds if (!ra) 708aa8e712cSStephen Smalley avd->allowed &= ~policydb->process_trans_perms; 7091da177e4SLinus Torvalds } 7101da177e4SLinus Torvalds 711d9250deaSKaiGai Kohei /* 712d9250deaSKaiGai Kohei * If the given source and target types have boundary 713d9250deaSKaiGai Kohei * constraint, lazy checks have to mask any violated 714d9250deaSKaiGai Kohei * permission and notice it to userspace via audit. 715d9250deaSKaiGai Kohei */ 716aa8e712cSStephen Smalley type_attribute_bounds_av(policydb, scontext, tcontext, 71719439d05SStephen Smalley tclass, avd); 71822df4adbSStephen Smalley } 71922df4adbSStephen Smalley 720aa8e712cSStephen Smalley static int security_validtrans_handle_fail(struct selinux_state *state, 721aa8e712cSStephen Smalley struct context *ocontext, 7221da177e4SLinus Torvalds struct context *ncontext, 7231da177e4SLinus Torvalds struct context *tcontext, 7241da177e4SLinus Torvalds u16 tclass) 7251da177e4SLinus Torvalds { 726aa8e712cSStephen Smalley struct policydb *p = &state->ss->policydb; 7271da177e4SLinus Torvalds char *o = NULL, *n = NULL, *t = NULL; 7281da177e4SLinus Torvalds u32 olen, nlen, tlen; 7291da177e4SLinus Torvalds 730aa8e712cSStephen Smalley if (context_struct_to_string(p, ocontext, &o, &olen)) 7311da177e4SLinus Torvalds goto out; 732aa8e712cSStephen Smalley if (context_struct_to_string(p, ncontext, &n, &nlen)) 7331da177e4SLinus Torvalds goto out; 734aa8e712cSStephen Smalley if (context_struct_to_string(p, tcontext, &t, &tlen)) 7351da177e4SLinus Torvalds goto out; 736cdfb6b34SRichard Guy Briggs audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR, 7374093a844SRichard Guy Briggs "op=security_validate_transition seresult=denied" 7381da177e4SLinus Torvalds " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", 739aa8e712cSStephen Smalley o, n, t, sym_name(p, SYM_CLASSES, tclass-1)); 7401da177e4SLinus Torvalds out: 7411da177e4SLinus Torvalds kfree(o); 7421da177e4SLinus Torvalds kfree(n); 7431da177e4SLinus Torvalds kfree(t); 7441da177e4SLinus Torvalds 745e5a5ca96SPaul Moore if (!enforcing_enabled(state)) 7461da177e4SLinus Torvalds return 0; 7471da177e4SLinus Torvalds return -EPERM; 7481da177e4SLinus Torvalds } 7491da177e4SLinus Torvalds 750aa8e712cSStephen Smalley static int security_compute_validatetrans(struct selinux_state *state, 751aa8e712cSStephen Smalley u32 oldsid, u32 newsid, u32 tasksid, 752f9df6458SAndrew Perepechko u16 orig_tclass, bool user) 7531da177e4SLinus Torvalds { 754aa8e712cSStephen Smalley struct policydb *policydb; 755aa8e712cSStephen Smalley struct sidtab *sidtab; 7561da177e4SLinus Torvalds struct context *ocontext; 7571da177e4SLinus Torvalds struct context *ncontext; 7581da177e4SLinus Torvalds struct context *tcontext; 7591da177e4SLinus Torvalds struct class_datum *tclass_datum; 7601da177e4SLinus Torvalds struct constraint_node *constraint; 761c6d3aaa4SStephen Smalley u16 tclass; 7621da177e4SLinus Torvalds int rc = 0; 7631da177e4SLinus Torvalds 764aa8e712cSStephen Smalley 765aa8e712cSStephen Smalley if (!state->initialized) 7661da177e4SLinus Torvalds return 0; 7671da177e4SLinus Torvalds 768aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 769aa8e712cSStephen Smalley 770aa8e712cSStephen Smalley policydb = &state->ss->policydb; 77124ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 7721da177e4SLinus Torvalds 773f9df6458SAndrew Perepechko if (!user) 774aa8e712cSStephen Smalley tclass = unmap_class(&state->ss->map, orig_tclass); 775f9df6458SAndrew Perepechko else 776f9df6458SAndrew Perepechko tclass = orig_tclass; 777c6d3aaa4SStephen Smalley 778aa8e712cSStephen Smalley if (!tclass || tclass > policydb->p_classes.nprim) { 7791da177e4SLinus Torvalds rc = -EINVAL; 7801da177e4SLinus Torvalds goto out; 7811da177e4SLinus Torvalds } 782aa8e712cSStephen Smalley tclass_datum = policydb->class_val_to_struct[tclass - 1]; 7831da177e4SLinus Torvalds 784aa8e712cSStephen Smalley ocontext = sidtab_search(sidtab, oldsid); 7851da177e4SLinus Torvalds if (!ocontext) { 786b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 787744ba35eSEric Paris __func__, oldsid); 7881da177e4SLinus Torvalds rc = -EINVAL; 7891da177e4SLinus Torvalds goto out; 7901da177e4SLinus Torvalds } 7911da177e4SLinus Torvalds 792aa8e712cSStephen Smalley ncontext = sidtab_search(sidtab, newsid); 7931da177e4SLinus Torvalds if (!ncontext) { 794b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 795744ba35eSEric Paris __func__, newsid); 7961da177e4SLinus Torvalds rc = -EINVAL; 7971da177e4SLinus Torvalds goto out; 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds 800aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tasksid); 8011da177e4SLinus Torvalds if (!tcontext) { 802b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 803744ba35eSEric Paris __func__, tasksid); 8041da177e4SLinus Torvalds rc = -EINVAL; 8051da177e4SLinus Torvalds goto out; 8061da177e4SLinus Torvalds } 8071da177e4SLinus Torvalds 8081da177e4SLinus Torvalds constraint = tclass_datum->validatetrans; 8091da177e4SLinus Torvalds while (constraint) { 810aa8e712cSStephen Smalley if (!constraint_expr_eval(policydb, ocontext, ncontext, 811aa8e712cSStephen Smalley tcontext, constraint->expr)) { 812f9df6458SAndrew Perepechko if (user) 813f9df6458SAndrew Perepechko rc = -EPERM; 814f9df6458SAndrew Perepechko else 815aa8e712cSStephen Smalley rc = security_validtrans_handle_fail(state, 816aa8e712cSStephen Smalley ocontext, 817f9df6458SAndrew Perepechko ncontext, 818f9df6458SAndrew Perepechko tcontext, 819f9df6458SAndrew Perepechko tclass); 8201da177e4SLinus Torvalds goto out; 8211da177e4SLinus Torvalds } 8221da177e4SLinus Torvalds constraint = constraint->next; 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds 8251da177e4SLinus Torvalds out: 826aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 8271da177e4SLinus Torvalds return rc; 8281da177e4SLinus Torvalds } 8291da177e4SLinus Torvalds 830aa8e712cSStephen Smalley int security_validate_transition_user(struct selinux_state *state, 831aa8e712cSStephen Smalley u32 oldsid, u32 newsid, u32 tasksid, 832f9df6458SAndrew Perepechko u16 tclass) 833f9df6458SAndrew Perepechko { 834aa8e712cSStephen Smalley return security_compute_validatetrans(state, oldsid, newsid, tasksid, 835f9df6458SAndrew Perepechko tclass, true); 836f9df6458SAndrew Perepechko } 837f9df6458SAndrew Perepechko 838aa8e712cSStephen Smalley int security_validate_transition(struct selinux_state *state, 839aa8e712cSStephen Smalley u32 oldsid, u32 newsid, u32 tasksid, 840f9df6458SAndrew Perepechko u16 orig_tclass) 841f9df6458SAndrew Perepechko { 842aa8e712cSStephen Smalley return security_compute_validatetrans(state, oldsid, newsid, tasksid, 843f9df6458SAndrew Perepechko orig_tclass, false); 844f9df6458SAndrew Perepechko } 845f9df6458SAndrew Perepechko 846d9250deaSKaiGai Kohei /* 847d9250deaSKaiGai Kohei * security_bounded_transition - check whether the given 848d9250deaSKaiGai Kohei * transition is directed to bounded, or not. 849d9250deaSKaiGai Kohei * It returns 0, if @newsid is bounded by @oldsid. 850d9250deaSKaiGai Kohei * Otherwise, it returns error code. 851d9250deaSKaiGai Kohei * 852d9250deaSKaiGai Kohei * @oldsid : current security identifier 853d9250deaSKaiGai Kohei * @newsid : destinated security identifier 854d9250deaSKaiGai Kohei */ 855aa8e712cSStephen Smalley int security_bounded_transition(struct selinux_state *state, 856aa8e712cSStephen Smalley u32 old_sid, u32 new_sid) 857d9250deaSKaiGai Kohei { 858aa8e712cSStephen Smalley struct policydb *policydb; 859aa8e712cSStephen Smalley struct sidtab *sidtab; 860d9250deaSKaiGai Kohei struct context *old_context, *new_context; 861d9250deaSKaiGai Kohei struct type_datum *type; 862d9250deaSKaiGai Kohei int index; 8634b02b524SEric Paris int rc; 864d9250deaSKaiGai Kohei 865aa8e712cSStephen Smalley if (!state->initialized) 8664b14752eSPaul Moore return 0; 8674b14752eSPaul Moore 868aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 869aa8e712cSStephen Smalley 870aa8e712cSStephen Smalley policydb = &state->ss->policydb; 87124ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 872d9250deaSKaiGai Kohei 8734b02b524SEric Paris rc = -EINVAL; 874aa8e712cSStephen Smalley old_context = sidtab_search(sidtab, old_sid); 875d9250deaSKaiGai Kohei if (!old_context) { 876b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %u\n", 877d9250deaSKaiGai Kohei __func__, old_sid); 878d9250deaSKaiGai Kohei goto out; 879d9250deaSKaiGai Kohei } 880d9250deaSKaiGai Kohei 8814b02b524SEric Paris rc = -EINVAL; 882aa8e712cSStephen Smalley new_context = sidtab_search(sidtab, new_sid); 883d9250deaSKaiGai Kohei if (!new_context) { 884b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %u\n", 885d9250deaSKaiGai Kohei __func__, new_sid); 886d9250deaSKaiGai Kohei goto out; 887d9250deaSKaiGai Kohei } 888d9250deaSKaiGai Kohei 889d9250deaSKaiGai Kohei rc = 0; 8904b02b524SEric Paris /* type/domain unchanged */ 8914b02b524SEric Paris if (old_context->type == new_context->type) 892d9250deaSKaiGai Kohei goto out; 893d9250deaSKaiGai Kohei 894d9250deaSKaiGai Kohei index = new_context->type; 895d9250deaSKaiGai Kohei while (true) { 896f07ea1d4SOndrej Mosnacek type = policydb->type_val_to_struct[index - 1]; 897d9250deaSKaiGai Kohei BUG_ON(!type); 898d9250deaSKaiGai Kohei 899d9250deaSKaiGai Kohei /* not bounded anymore */ 900d9250deaSKaiGai Kohei rc = -EPERM; 9014b02b524SEric Paris if (!type->bounds) 902d9250deaSKaiGai Kohei break; 903d9250deaSKaiGai Kohei 904d9250deaSKaiGai Kohei /* @newsid is bounded by @oldsid */ 905d9250deaSKaiGai Kohei rc = 0; 9064b02b524SEric Paris if (type->bounds == old_context->type) 907d9250deaSKaiGai Kohei break; 9084b02b524SEric Paris 909d9250deaSKaiGai Kohei index = type->bounds; 910d9250deaSKaiGai Kohei } 91144c2d9bdSKaiGai Kohei 91244c2d9bdSKaiGai Kohei if (rc) { 91344c2d9bdSKaiGai Kohei char *old_name = NULL; 91444c2d9bdSKaiGai Kohei char *new_name = NULL; 9152da5d31bSJames Morris u32 length; 91644c2d9bdSKaiGai Kohei 917aa8e712cSStephen Smalley if (!context_struct_to_string(policydb, old_context, 91844c2d9bdSKaiGai Kohei &old_name, &length) && 919aa8e712cSStephen Smalley !context_struct_to_string(policydb, new_context, 92044c2d9bdSKaiGai Kohei &new_name, &length)) { 921cdfb6b34SRichard Guy Briggs audit_log(audit_context(), 92244c2d9bdSKaiGai Kohei GFP_ATOMIC, AUDIT_SELINUX_ERR, 92344c2d9bdSKaiGai Kohei "op=security_bounded_transition " 9244093a844SRichard Guy Briggs "seresult=denied " 92544c2d9bdSKaiGai Kohei "oldcontext=%s newcontext=%s", 92644c2d9bdSKaiGai Kohei old_name, new_name); 92744c2d9bdSKaiGai Kohei } 92844c2d9bdSKaiGai Kohei kfree(new_name); 92944c2d9bdSKaiGai Kohei kfree(old_name); 93044c2d9bdSKaiGai Kohei } 931d9250deaSKaiGai Kohei out: 932aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 933d9250deaSKaiGai Kohei 934d9250deaSKaiGai Kohei return rc; 935d9250deaSKaiGai Kohei } 936d9250deaSKaiGai Kohei 937aa8e712cSStephen Smalley static void avd_init(struct selinux_state *state, struct av_decision *avd) 938c6d3aaa4SStephen Smalley { 93919439d05SStephen Smalley avd->allowed = 0; 94019439d05SStephen Smalley avd->auditallow = 0; 94119439d05SStephen Smalley avd->auditdeny = 0xffffffff; 942aa8e712cSStephen Smalley avd->seqno = state->ss->latest_granting; 94319439d05SStephen Smalley avd->flags = 0; 944c6d3aaa4SStephen Smalley } 945c6d3aaa4SStephen Smalley 946fa1aa143SJeff Vander Stoep void services_compute_xperms_decision(struct extended_perms_decision *xpermd, 947fa1aa143SJeff Vander Stoep struct avtab_node *node) 948fa1aa143SJeff Vander Stoep { 949fa1aa143SJeff Vander Stoep unsigned int i; 950fa1aa143SJeff Vander Stoep 951fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 952fa1aa143SJeff Vander Stoep if (xpermd->driver != node->datum.u.xperms->driver) 953fa1aa143SJeff Vander Stoep return; 954fa1aa143SJeff Vander Stoep } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 955fa1aa143SJeff Vander Stoep if (!security_xperm_test(node->datum.u.xperms->perms.p, 956fa1aa143SJeff Vander Stoep xpermd->driver)) 957fa1aa143SJeff Vander Stoep return; 958fa1aa143SJeff Vander Stoep } else { 959fa1aa143SJeff Vander Stoep BUG(); 960fa1aa143SJeff Vander Stoep } 961fa1aa143SJeff Vander Stoep 962fa1aa143SJeff Vander Stoep if (node->key.specified == AVTAB_XPERMS_ALLOWED) { 963fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_ALLOWED; 964fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 965fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0xff, 966fa1aa143SJeff Vander Stoep sizeof(xpermd->allowed->p)); 967fa1aa143SJeff Vander Stoep } 968fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 969fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) 970fa1aa143SJeff Vander Stoep xpermd->allowed->p[i] |= 971fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i]; 972fa1aa143SJeff Vander Stoep } 973fa1aa143SJeff Vander Stoep } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { 974fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_AUDITALLOW; 975fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 976fa1aa143SJeff Vander Stoep memset(xpermd->auditallow->p, 0xff, 977fa1aa143SJeff Vander Stoep sizeof(xpermd->auditallow->p)); 978fa1aa143SJeff Vander Stoep } 979fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 980fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) 981fa1aa143SJeff Vander Stoep xpermd->auditallow->p[i] |= 982fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i]; 983fa1aa143SJeff Vander Stoep } 984fa1aa143SJeff Vander Stoep } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { 985fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_DONTAUDIT; 986fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 987fa1aa143SJeff Vander Stoep memset(xpermd->dontaudit->p, 0xff, 988fa1aa143SJeff Vander Stoep sizeof(xpermd->dontaudit->p)); 989fa1aa143SJeff Vander Stoep } 990fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 991fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) 992fa1aa143SJeff Vander Stoep xpermd->dontaudit->p[i] |= 993fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i]; 994fa1aa143SJeff Vander Stoep } 995fa1aa143SJeff Vander Stoep } else { 996fa1aa143SJeff Vander Stoep BUG(); 997fa1aa143SJeff Vander Stoep } 998fa1aa143SJeff Vander Stoep } 999fa1aa143SJeff Vander Stoep 1000aa8e712cSStephen Smalley void security_compute_xperms_decision(struct selinux_state *state, 1001aa8e712cSStephen Smalley u32 ssid, 1002fa1aa143SJeff Vander Stoep u32 tsid, 1003fa1aa143SJeff Vander Stoep u16 orig_tclass, 1004fa1aa143SJeff Vander Stoep u8 driver, 1005fa1aa143SJeff Vander Stoep struct extended_perms_decision *xpermd) 1006fa1aa143SJeff Vander Stoep { 1007aa8e712cSStephen Smalley struct policydb *policydb; 1008aa8e712cSStephen Smalley struct sidtab *sidtab; 1009fa1aa143SJeff Vander Stoep u16 tclass; 1010fa1aa143SJeff Vander Stoep struct context *scontext, *tcontext; 1011fa1aa143SJeff Vander Stoep struct avtab_key avkey; 1012fa1aa143SJeff Vander Stoep struct avtab_node *node; 1013fa1aa143SJeff Vander Stoep struct ebitmap *sattr, *tattr; 1014fa1aa143SJeff Vander Stoep struct ebitmap_node *snode, *tnode; 1015fa1aa143SJeff Vander Stoep unsigned int i, j; 1016fa1aa143SJeff Vander Stoep 1017fa1aa143SJeff Vander Stoep xpermd->driver = driver; 1018fa1aa143SJeff Vander Stoep xpermd->used = 0; 1019fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p)); 1020fa1aa143SJeff Vander Stoep memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); 1021fa1aa143SJeff Vander Stoep memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); 1022fa1aa143SJeff Vander Stoep 1023aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 1024aa8e712cSStephen Smalley if (!state->initialized) 1025fa1aa143SJeff Vander Stoep goto allow; 1026fa1aa143SJeff Vander Stoep 1027aa8e712cSStephen Smalley policydb = &state->ss->policydb; 102824ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 1029aa8e712cSStephen Smalley 1030aa8e712cSStephen Smalley scontext = sidtab_search(sidtab, ssid); 1031fa1aa143SJeff Vander Stoep if (!scontext) { 1032b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 1033fa1aa143SJeff Vander Stoep __func__, ssid); 1034fa1aa143SJeff Vander Stoep goto out; 1035fa1aa143SJeff Vander Stoep } 1036fa1aa143SJeff Vander Stoep 1037aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tsid); 1038fa1aa143SJeff Vander Stoep if (!tcontext) { 1039b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 1040fa1aa143SJeff Vander Stoep __func__, tsid); 1041fa1aa143SJeff Vander Stoep goto out; 1042fa1aa143SJeff Vander Stoep } 1043fa1aa143SJeff Vander Stoep 1044aa8e712cSStephen Smalley tclass = unmap_class(&state->ss->map, orig_tclass); 1045fa1aa143SJeff Vander Stoep if (unlikely(orig_tclass && !tclass)) { 1046aa8e712cSStephen Smalley if (policydb->allow_unknown) 1047fa1aa143SJeff Vander Stoep goto allow; 1048fa1aa143SJeff Vander Stoep goto out; 1049fa1aa143SJeff Vander Stoep } 1050fa1aa143SJeff Vander Stoep 1051fa1aa143SJeff Vander Stoep 1052aa8e712cSStephen Smalley if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) { 1053fa1aa143SJeff Vander Stoep pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass); 1054fa1aa143SJeff Vander Stoep goto out; 1055fa1aa143SJeff Vander Stoep } 1056fa1aa143SJeff Vander Stoep 1057fa1aa143SJeff Vander Stoep avkey.target_class = tclass; 1058fa1aa143SJeff Vander Stoep avkey.specified = AVTAB_XPERMS; 1059acdf52d9SKent Overstreet sattr = &policydb->type_attr_map_array[scontext->type - 1]; 1060acdf52d9SKent Overstreet tattr = &policydb->type_attr_map_array[tcontext->type - 1]; 1061fa1aa143SJeff Vander Stoep ebitmap_for_each_positive_bit(sattr, snode, i) { 1062fa1aa143SJeff Vander Stoep ebitmap_for_each_positive_bit(tattr, tnode, j) { 1063fa1aa143SJeff Vander Stoep avkey.source_type = i + 1; 1064fa1aa143SJeff Vander Stoep avkey.target_type = j + 1; 1065aa8e712cSStephen Smalley for (node = avtab_search_node(&policydb->te_avtab, 1066aa8e712cSStephen Smalley &avkey); 1067fa1aa143SJeff Vander Stoep node; 1068fa1aa143SJeff Vander Stoep node = avtab_search_node_next(node, avkey.specified)) 1069fa1aa143SJeff Vander Stoep services_compute_xperms_decision(xpermd, node); 1070fa1aa143SJeff Vander Stoep 1071aa8e712cSStephen Smalley cond_compute_xperms(&policydb->te_cond_avtab, 1072fa1aa143SJeff Vander Stoep &avkey, xpermd); 1073fa1aa143SJeff Vander Stoep } 1074fa1aa143SJeff Vander Stoep } 1075fa1aa143SJeff Vander Stoep out: 1076aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 1077fa1aa143SJeff Vander Stoep return; 1078fa1aa143SJeff Vander Stoep allow: 1079fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); 1080fa1aa143SJeff Vander Stoep goto out; 1081fa1aa143SJeff Vander Stoep } 1082c6d3aaa4SStephen Smalley 10831da177e4SLinus Torvalds /** 10841da177e4SLinus Torvalds * security_compute_av - Compute access vector decisions. 10851da177e4SLinus Torvalds * @ssid: source security identifier 10861da177e4SLinus Torvalds * @tsid: target security identifier 10871da177e4SLinus Torvalds * @tclass: target security class 10881da177e4SLinus Torvalds * @avd: access vector decisions 1089fa1aa143SJeff Vander Stoep * @xperms: extended permissions 10901da177e4SLinus Torvalds * 10911da177e4SLinus Torvalds * Compute a set of access vector decisions based on the 10921da177e4SLinus Torvalds * SID pair (@ssid, @tsid) for the permissions in @tclass. 10931da177e4SLinus Torvalds */ 1094aa8e712cSStephen Smalley void security_compute_av(struct selinux_state *state, 1095aa8e712cSStephen Smalley u32 ssid, 10961da177e4SLinus Torvalds u32 tsid, 1097c6d3aaa4SStephen Smalley u16 orig_tclass, 1098fa1aa143SJeff Vander Stoep struct av_decision *avd, 1099fa1aa143SJeff Vander Stoep struct extended_perms *xperms) 1100c6d3aaa4SStephen Smalley { 1101aa8e712cSStephen Smalley struct policydb *policydb; 1102aa8e712cSStephen Smalley struct sidtab *sidtab; 1103c6d3aaa4SStephen Smalley u16 tclass; 110419439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL; 1105c6d3aaa4SStephen Smalley 1106aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 1107aa8e712cSStephen Smalley avd_init(state, avd); 1108fa1aa143SJeff Vander Stoep xperms->len = 0; 1109aa8e712cSStephen Smalley if (!state->initialized) 1110c6d3aaa4SStephen Smalley goto allow; 1111c6d3aaa4SStephen Smalley 1112aa8e712cSStephen Smalley policydb = &state->ss->policydb; 111324ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 1114aa8e712cSStephen Smalley 1115aa8e712cSStephen Smalley scontext = sidtab_search(sidtab, ssid); 111619439d05SStephen Smalley if (!scontext) { 1117b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 111819439d05SStephen Smalley __func__, ssid); 111919439d05SStephen Smalley goto out; 112019439d05SStephen Smalley } 112119439d05SStephen Smalley 112219439d05SStephen Smalley /* permissive domain? */ 1123aa8e712cSStephen Smalley if (ebitmap_get_bit(&policydb->permissive_map, scontext->type)) 112419439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE; 112519439d05SStephen Smalley 1126aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tsid); 112719439d05SStephen Smalley if (!tcontext) { 1128b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 112919439d05SStephen Smalley __func__, tsid); 113019439d05SStephen Smalley goto out; 113119439d05SStephen Smalley } 113219439d05SStephen Smalley 1133aa8e712cSStephen Smalley tclass = unmap_class(&state->ss->map, orig_tclass); 1134c6d3aaa4SStephen Smalley if (unlikely(orig_tclass && !tclass)) { 1135aa8e712cSStephen Smalley if (policydb->allow_unknown) 1136c6d3aaa4SStephen Smalley goto allow; 1137b7f3008aSStephen Smalley goto out; 1138c6d3aaa4SStephen Smalley } 1139aa8e712cSStephen Smalley context_struct_compute_av(policydb, scontext, tcontext, tclass, avd, 1140aa8e712cSStephen Smalley xperms); 1141aa8e712cSStephen Smalley map_decision(&state->ss->map, orig_tclass, avd, 1142aa8e712cSStephen Smalley policydb->allow_unknown); 1143b7f3008aSStephen Smalley out: 1144aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 114519439d05SStephen Smalley return; 1146c6d3aaa4SStephen Smalley allow: 1147c6d3aaa4SStephen Smalley avd->allowed = 0xffffffff; 1148b7f3008aSStephen Smalley goto out; 1149c6d3aaa4SStephen Smalley } 1150c6d3aaa4SStephen Smalley 1151aa8e712cSStephen Smalley void security_compute_av_user(struct selinux_state *state, 1152aa8e712cSStephen Smalley u32 ssid, 1153c6d3aaa4SStephen Smalley u32 tsid, 11541da177e4SLinus Torvalds u16 tclass, 11551da177e4SLinus Torvalds struct av_decision *avd) 11561da177e4SLinus Torvalds { 1157aa8e712cSStephen Smalley struct policydb *policydb; 1158aa8e712cSStephen Smalley struct sidtab *sidtab; 115919439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL; 11601da177e4SLinus Torvalds 1161aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 1162aa8e712cSStephen Smalley avd_init(state, avd); 1163aa8e712cSStephen Smalley if (!state->initialized) 116419439d05SStephen Smalley goto allow; 116519439d05SStephen Smalley 1166aa8e712cSStephen Smalley policydb = &state->ss->policydb; 116724ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 1168aa8e712cSStephen Smalley 1169aa8e712cSStephen Smalley scontext = sidtab_search(sidtab, ssid); 117019439d05SStephen Smalley if (!scontext) { 1171b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 117219439d05SStephen Smalley __func__, ssid); 117319439d05SStephen Smalley goto out; 117419439d05SStephen Smalley } 117519439d05SStephen Smalley 117619439d05SStephen Smalley /* permissive domain? */ 1177aa8e712cSStephen Smalley if (ebitmap_get_bit(&policydb->permissive_map, scontext->type)) 117819439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE; 117919439d05SStephen Smalley 1180aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tsid); 118119439d05SStephen Smalley if (!tcontext) { 1182b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 118319439d05SStephen Smalley __func__, tsid); 118419439d05SStephen Smalley goto out; 118519439d05SStephen Smalley } 118619439d05SStephen Smalley 118719439d05SStephen Smalley if (unlikely(!tclass)) { 1188aa8e712cSStephen Smalley if (policydb->allow_unknown) 118919439d05SStephen Smalley goto allow; 119019439d05SStephen Smalley goto out; 119119439d05SStephen Smalley } 119219439d05SStephen Smalley 1193aa8e712cSStephen Smalley context_struct_compute_av(policydb, scontext, tcontext, tclass, avd, 1194aa8e712cSStephen Smalley NULL); 119519439d05SStephen Smalley out: 1196aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 119719439d05SStephen Smalley return; 119819439d05SStephen Smalley allow: 119919439d05SStephen Smalley avd->allowed = 0xffffffff; 120019439d05SStephen Smalley goto out; 12011da177e4SLinus Torvalds } 12021da177e4SLinus Torvalds 12031da177e4SLinus Torvalds /* 12041da177e4SLinus Torvalds * Write the security context string representation of 12051da177e4SLinus Torvalds * the context structure `context' into a dynamically 12061da177e4SLinus Torvalds * allocated string of the correct size. Set `*scontext' 12071da177e4SLinus Torvalds * to point to this string and set `*scontext_len' to 12081da177e4SLinus Torvalds * the length of the string. 12091da177e4SLinus Torvalds */ 1210aa8e712cSStephen Smalley static int context_struct_to_string(struct policydb *p, 1211aa8e712cSStephen Smalley struct context *context, 1212aa8e712cSStephen Smalley char **scontext, u32 *scontext_len) 12131da177e4SLinus Torvalds { 12141da177e4SLinus Torvalds char *scontextp; 12151da177e4SLinus Torvalds 1216d5630b9dSEric Paris if (scontext) 12171da177e4SLinus Torvalds *scontext = NULL; 12181da177e4SLinus Torvalds *scontext_len = 0; 12191da177e4SLinus Torvalds 122012b29f34SStephen Smalley if (context->len) { 122112b29f34SStephen Smalley *scontext_len = context->len; 1222bb7081abSEric Paris if (scontext) { 122312b29f34SStephen Smalley *scontext = kstrdup(context->str, GFP_ATOMIC); 122412b29f34SStephen Smalley if (!(*scontext)) 122512b29f34SStephen Smalley return -ENOMEM; 1226bb7081abSEric Paris } 122712b29f34SStephen Smalley return 0; 122812b29f34SStephen Smalley } 122912b29f34SStephen Smalley 12301da177e4SLinus Torvalds /* Compute the size of the context. */ 1231aa8e712cSStephen Smalley *scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1; 1232aa8e712cSStephen Smalley *scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1; 1233aa8e712cSStephen Smalley *scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1; 1234aa8e712cSStephen Smalley *scontext_len += mls_compute_context_len(p, context); 12351da177e4SLinus Torvalds 1236d5630b9dSEric Paris if (!scontext) 1237d5630b9dSEric Paris return 0; 1238d5630b9dSEric Paris 12391da177e4SLinus Torvalds /* Allocate space for the context; caller must free this space. */ 12401da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 12415d55a345SEric Paris if (!scontextp) 12421da177e4SLinus Torvalds return -ENOMEM; 12431da177e4SLinus Torvalds *scontext = scontextp; 12441da177e4SLinus Torvalds 12451da177e4SLinus Torvalds /* 12461da177e4SLinus Torvalds * Copy the user name, role name and type name into the context. 12471da177e4SLinus Torvalds */ 12489529c788SRasmus Villemoes scontextp += sprintf(scontextp, "%s:%s:%s", 1249aa8e712cSStephen Smalley sym_name(p, SYM_USERS, context->user - 1), 1250aa8e712cSStephen Smalley sym_name(p, SYM_ROLES, context->role - 1), 1251aa8e712cSStephen Smalley sym_name(p, SYM_TYPES, context->type - 1)); 12521da177e4SLinus Torvalds 1253aa8e712cSStephen Smalley mls_sid_to_context(p, context, &scontextp); 12541da177e4SLinus Torvalds 12551da177e4SLinus Torvalds *scontextp = 0; 12561da177e4SLinus Torvalds 12571da177e4SLinus Torvalds return 0; 12581da177e4SLinus Torvalds } 12591da177e4SLinus Torvalds 12601da177e4SLinus Torvalds #include "initial_sid_to_string.h" 12611da177e4SLinus Torvalds 1262f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid) 1263f0ee2e46SJames Carter { 1264f0ee2e46SJames Carter if (unlikely(sid > SECINITSID_NUM)) 1265f0ee2e46SJames Carter return NULL; 1266f0ee2e46SJames Carter return initial_sid_to_string[sid]; 1267f0ee2e46SJames Carter } 1268f0ee2e46SJames Carter 1269aa8e712cSStephen Smalley static int security_sid_to_context_core(struct selinux_state *state, 1270aa8e712cSStephen Smalley u32 sid, char **scontext, 1271fede1483SOndrej Mosnacek u32 *scontext_len, int force, 1272fede1483SOndrej Mosnacek int only_invalid) 12731da177e4SLinus Torvalds { 1274aa8e712cSStephen Smalley struct policydb *policydb; 1275aa8e712cSStephen Smalley struct sidtab *sidtab; 12761da177e4SLinus Torvalds struct context *context; 12771da177e4SLinus Torvalds int rc = 0; 12781da177e4SLinus Torvalds 1279d5630b9dSEric Paris if (scontext) 12804f4acf3aSStephen Smalley *scontext = NULL; 12814f4acf3aSStephen Smalley *scontext_len = 0; 12824f4acf3aSStephen Smalley 1283aa8e712cSStephen Smalley if (!state->initialized) { 12841da177e4SLinus Torvalds if (sid <= SECINITSID_NUM) { 12851da177e4SLinus Torvalds char *scontextp; 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds *scontext_len = strlen(initial_sid_to_string[sid]) + 1; 1288d5630b9dSEric Paris if (!scontext) 1289d5630b9dSEric Paris goto out; 1290aa736c36SRasmus Villemoes scontextp = kmemdup(initial_sid_to_string[sid], 1291aa736c36SRasmus Villemoes *scontext_len, GFP_ATOMIC); 12920cccca06SSerge E. Hallyn if (!scontextp) { 12930cccca06SSerge E. Hallyn rc = -ENOMEM; 12940cccca06SSerge E. Hallyn goto out; 12950cccca06SSerge E. Hallyn } 12961da177e4SLinus Torvalds *scontext = scontextp; 12971da177e4SLinus Torvalds goto out; 12981da177e4SLinus Torvalds } 1299b54c85c1Speter enderborg pr_err("SELinux: %s: called before initial " 1300744ba35eSEric Paris "load_policy on unknown SID %d\n", __func__, sid); 13011da177e4SLinus Torvalds rc = -EINVAL; 13021da177e4SLinus Torvalds goto out; 13031da177e4SLinus Torvalds } 1304aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 1305aa8e712cSStephen Smalley policydb = &state->ss->policydb; 130624ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 130712b29f34SStephen Smalley if (force) 1308aa8e712cSStephen Smalley context = sidtab_search_force(sidtab, sid); 130912b29f34SStephen Smalley else 1310aa8e712cSStephen Smalley context = sidtab_search(sidtab, sid); 13111da177e4SLinus Torvalds if (!context) { 1312b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 1313744ba35eSEric Paris __func__, sid); 13141da177e4SLinus Torvalds rc = -EINVAL; 13151da177e4SLinus Torvalds goto out_unlock; 13161da177e4SLinus Torvalds } 13179e0cfe28SOndrej Mosnacek if (only_invalid && !context->len) 1318fede1483SOndrej Mosnacek rc = 0; 13199e0cfe28SOndrej Mosnacek else 1320aa8e712cSStephen Smalley rc = context_struct_to_string(policydb, context, scontext, 1321aa8e712cSStephen Smalley scontext_len); 13221da177e4SLinus Torvalds out_unlock: 1323aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 13241da177e4SLinus Torvalds out: 13251da177e4SLinus Torvalds return rc; 13261da177e4SLinus Torvalds 13271da177e4SLinus Torvalds } 13281da177e4SLinus Torvalds 132912b29f34SStephen Smalley /** 133012b29f34SStephen Smalley * security_sid_to_context - Obtain a context for a given SID. 133112b29f34SStephen Smalley * @sid: security identifier, SID 133212b29f34SStephen Smalley * @scontext: security context 133312b29f34SStephen Smalley * @scontext_len: length in bytes 133412b29f34SStephen Smalley * 133512b29f34SStephen Smalley * Write the string representation of the context associated with @sid 133612b29f34SStephen Smalley * into a dynamically allocated string of the correct size. Set @scontext 133712b29f34SStephen Smalley * to point to this string and set @scontext_len to the length of the string. 133812b29f34SStephen Smalley */ 1339aa8e712cSStephen Smalley int security_sid_to_context(struct selinux_state *state, 1340aa8e712cSStephen Smalley u32 sid, char **scontext, u32 *scontext_len) 13411da177e4SLinus Torvalds { 1342aa8e712cSStephen Smalley return security_sid_to_context_core(state, sid, scontext, 1343fede1483SOndrej Mosnacek scontext_len, 0, 0); 134412b29f34SStephen Smalley } 134512b29f34SStephen Smalley 1346aa8e712cSStephen Smalley int security_sid_to_context_force(struct selinux_state *state, u32 sid, 1347aa8e712cSStephen Smalley char **scontext, u32 *scontext_len) 134812b29f34SStephen Smalley { 1349aa8e712cSStephen Smalley return security_sid_to_context_core(state, sid, scontext, 1350fede1483SOndrej Mosnacek scontext_len, 1, 0); 1351fede1483SOndrej Mosnacek } 1352fede1483SOndrej Mosnacek 1353fede1483SOndrej Mosnacek /** 1354fede1483SOndrej Mosnacek * security_sid_to_context_inval - Obtain a context for a given SID if it 1355fede1483SOndrej Mosnacek * is invalid. 1356fede1483SOndrej Mosnacek * @sid: security identifier, SID 1357fede1483SOndrej Mosnacek * @scontext: security context 1358fede1483SOndrej Mosnacek * @scontext_len: length in bytes 1359fede1483SOndrej Mosnacek * 1360fede1483SOndrej Mosnacek * Write the string representation of the context associated with @sid 1361fede1483SOndrej Mosnacek * into a dynamically allocated string of the correct size, but only if the 1362fede1483SOndrej Mosnacek * context is invalid in the current policy. Set @scontext to point to 1363fede1483SOndrej Mosnacek * this string (or NULL if the context is valid) and set @scontext_len to 1364fede1483SOndrej Mosnacek * the length of the string (or 0 if the context is valid). 1365fede1483SOndrej Mosnacek */ 1366fede1483SOndrej Mosnacek int security_sid_to_context_inval(struct selinux_state *state, u32 sid, 1367fede1483SOndrej Mosnacek char **scontext, u32 *scontext_len) 1368fede1483SOndrej Mosnacek { 1369fede1483SOndrej Mosnacek return security_sid_to_context_core(state, sid, scontext, 1370fede1483SOndrej Mosnacek scontext_len, 1, 1); 137112b29f34SStephen Smalley } 137212b29f34SStephen Smalley 13739a59daa0SStephen Smalley /* 13749a59daa0SStephen Smalley * Caveat: Mutates scontext. 13759a59daa0SStephen Smalley */ 137612b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol, 137712b29f34SStephen Smalley struct sidtab *sidtabp, 13789a59daa0SStephen Smalley char *scontext, 137912b29f34SStephen Smalley struct context *ctx, 13809a59daa0SStephen Smalley u32 def_sid) 138112b29f34SStephen Smalley { 13821da177e4SLinus Torvalds struct role_datum *role; 13831da177e4SLinus Torvalds struct type_datum *typdatum; 13841da177e4SLinus Torvalds struct user_datum *usrdatum; 13851da177e4SLinus Torvalds char *scontextp, *p, oldc; 13861da177e4SLinus Torvalds int rc = 0; 13871da177e4SLinus Torvalds 138812b29f34SStephen Smalley context_init(ctx); 138912b29f34SStephen Smalley 139012b29f34SStephen Smalley /* Parse the security context. */ 139112b29f34SStephen Smalley 139212b29f34SStephen Smalley rc = -EINVAL; 13939a59daa0SStephen Smalley scontextp = (char *) scontext; 139412b29f34SStephen Smalley 139512b29f34SStephen Smalley /* Extract the user. */ 139612b29f34SStephen Smalley p = scontextp; 139712b29f34SStephen Smalley while (*p && *p != ':') 139812b29f34SStephen Smalley p++; 139912b29f34SStephen Smalley 140012b29f34SStephen Smalley if (*p == 0) 140112b29f34SStephen Smalley goto out; 140212b29f34SStephen Smalley 140312b29f34SStephen Smalley *p++ = 0; 140412b29f34SStephen Smalley 140512b29f34SStephen Smalley usrdatum = hashtab_search(pol->p_users.table, scontextp); 140612b29f34SStephen Smalley if (!usrdatum) 140712b29f34SStephen Smalley goto out; 140812b29f34SStephen Smalley 140912b29f34SStephen Smalley ctx->user = usrdatum->value; 141012b29f34SStephen Smalley 141112b29f34SStephen Smalley /* Extract role. */ 141212b29f34SStephen Smalley scontextp = p; 141312b29f34SStephen Smalley while (*p && *p != ':') 141412b29f34SStephen Smalley p++; 141512b29f34SStephen Smalley 141612b29f34SStephen Smalley if (*p == 0) 141712b29f34SStephen Smalley goto out; 141812b29f34SStephen Smalley 141912b29f34SStephen Smalley *p++ = 0; 142012b29f34SStephen Smalley 142112b29f34SStephen Smalley role = hashtab_search(pol->p_roles.table, scontextp); 142212b29f34SStephen Smalley if (!role) 142312b29f34SStephen Smalley goto out; 142412b29f34SStephen Smalley ctx->role = role->value; 142512b29f34SStephen Smalley 142612b29f34SStephen Smalley /* Extract type. */ 142712b29f34SStephen Smalley scontextp = p; 142812b29f34SStephen Smalley while (*p && *p != ':') 142912b29f34SStephen Smalley p++; 143012b29f34SStephen Smalley oldc = *p; 143112b29f34SStephen Smalley *p++ = 0; 143212b29f34SStephen Smalley 143312b29f34SStephen Smalley typdatum = hashtab_search(pol->p_types.table, scontextp); 1434d9250deaSKaiGai Kohei if (!typdatum || typdatum->attribute) 143512b29f34SStephen Smalley goto out; 143612b29f34SStephen Smalley 143712b29f34SStephen Smalley ctx->type = typdatum->value; 143812b29f34SStephen Smalley 143995ffe194SJann Horn rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid); 144012b29f34SStephen Smalley if (rc) 144112b29f34SStephen Smalley goto out; 144212b29f34SStephen Smalley 144312b29f34SStephen Smalley /* Check the validity of the new context. */ 144495ffe194SJann Horn rc = -EINVAL; 14454b02b524SEric Paris if (!policydb_context_isvalid(pol, ctx)) 144612b29f34SStephen Smalley goto out; 144712b29f34SStephen Smalley rc = 0; 144812b29f34SStephen Smalley out: 14498e531af9SEric Paris if (rc) 14508e531af9SEric Paris context_destroy(ctx); 145112b29f34SStephen Smalley return rc; 145212b29f34SStephen Smalley } 145312b29f34SStephen Smalley 1454aa8e712cSStephen Smalley static int security_context_to_sid_core(struct selinux_state *state, 1455aa8e712cSStephen Smalley const char *scontext, u32 scontext_len, 145612b29f34SStephen Smalley u32 *sid, u32 def_sid, gfp_t gfp_flags, 145712b29f34SStephen Smalley int force) 145812b29f34SStephen Smalley { 1459aa8e712cSStephen Smalley struct policydb *policydb; 1460aa8e712cSStephen Smalley struct sidtab *sidtab; 14619a59daa0SStephen Smalley char *scontext2, *str = NULL; 146212b29f34SStephen Smalley struct context context; 146312b29f34SStephen Smalley int rc = 0; 146412b29f34SStephen Smalley 14652172fa70SStephen Smalley /* An empty security context is never valid. */ 14662172fa70SStephen Smalley if (!scontext_len) 14672172fa70SStephen Smalley return -EINVAL; 14682172fa70SStephen Smalley 1469ef28df55SPaul Moore /* Copy the string to allow changes and ensure a NUL terminator */ 1470ef28df55SPaul Moore scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags); 1471ef28df55SPaul Moore if (!scontext2) 1472ef28df55SPaul Moore return -ENOMEM; 1473ef28df55SPaul Moore 1474aa8e712cSStephen Smalley if (!state->initialized) { 14751da177e4SLinus Torvalds int i; 14761da177e4SLinus Torvalds 14771da177e4SLinus Torvalds for (i = 1; i < SECINITSID_NUM; i++) { 1478ef28df55SPaul Moore if (!strcmp(initial_sid_to_string[i], scontext2)) { 14791da177e4SLinus Torvalds *sid = i; 1480ef28df55SPaul Moore goto out; 14811da177e4SLinus Torvalds } 14821da177e4SLinus Torvalds } 14831da177e4SLinus Torvalds *sid = SECINITSID_KERNEL; 1484ef28df55SPaul Moore goto out; 14851da177e4SLinus Torvalds } 14861da177e4SLinus Torvalds *sid = SECSID_NULL; 14871da177e4SLinus Torvalds 14889a59daa0SStephen Smalley if (force) { 14899a59daa0SStephen Smalley /* Save another copy for storing in uninterpreted form */ 14904b02b524SEric Paris rc = -ENOMEM; 14919a59daa0SStephen Smalley str = kstrdup(scontext2, gfp_flags); 14924b02b524SEric Paris if (!str) 14934b02b524SEric Paris goto out; 14949a59daa0SStephen Smalley } 1495aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 1496aa8e712cSStephen Smalley policydb = &state->ss->policydb; 149724ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 1498aa8e712cSStephen Smalley rc = string_to_context_struct(policydb, sidtab, scontext2, 149995ffe194SJann Horn &context, def_sid); 150012b29f34SStephen Smalley if (rc == -EINVAL && force) { 15019a59daa0SStephen Smalley context.str = str; 1502efe3de79SSachin Grover context.len = strlen(str) + 1; 15039a59daa0SStephen Smalley str = NULL; 150412b29f34SStephen Smalley } else if (rc) 15054b02b524SEric Paris goto out_unlock; 1506aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, &context, sid); 15071da177e4SLinus Torvalds context_destroy(&context); 15084b02b524SEric Paris out_unlock: 1509aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 15104b02b524SEric Paris out: 15119a59daa0SStephen Smalley kfree(scontext2); 15129a59daa0SStephen Smalley kfree(str); 15131da177e4SLinus Torvalds return rc; 15141da177e4SLinus Torvalds } 15151da177e4SLinus Torvalds 1516f5c1d5b2SJames Morris /** 1517f5c1d5b2SJames Morris * security_context_to_sid - Obtain a SID for a given security context. 1518f5c1d5b2SJames Morris * @scontext: security context 1519f5c1d5b2SJames Morris * @scontext_len: length in bytes 1520f5c1d5b2SJames Morris * @sid: security identifier, SID 152152a4c640SNikolay Aleksandrov * @gfp: context for the allocation 1522f5c1d5b2SJames Morris * 1523f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 1524f5c1d5b2SJames Morris * has the string representation specified by @scontext. 1525f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 1526f5c1d5b2SJames Morris * memory is available, or 0 on success. 1527f5c1d5b2SJames Morris */ 1528aa8e712cSStephen Smalley int security_context_to_sid(struct selinux_state *state, 1529aa8e712cSStephen Smalley const char *scontext, u32 scontext_len, u32 *sid, 153052a4c640SNikolay Aleksandrov gfp_t gfp) 1531f5c1d5b2SJames Morris { 1532aa8e712cSStephen Smalley return security_context_to_sid_core(state, scontext, scontext_len, 153352a4c640SNikolay Aleksandrov sid, SECSID_NULL, gfp, 0); 1534f5c1d5b2SJames Morris } 1535f5c1d5b2SJames Morris 1536aa8e712cSStephen Smalley int security_context_str_to_sid(struct selinux_state *state, 1537aa8e712cSStephen Smalley const char *scontext, u32 *sid, gfp_t gfp) 153844be2f65SRasmus Villemoes { 1539aa8e712cSStephen Smalley return security_context_to_sid(state, scontext, strlen(scontext), 1540aa8e712cSStephen Smalley sid, gfp); 154144be2f65SRasmus Villemoes } 154244be2f65SRasmus Villemoes 1543f5c1d5b2SJames Morris /** 1544f5c1d5b2SJames Morris * security_context_to_sid_default - Obtain a SID for a given security context, 1545f5c1d5b2SJames Morris * falling back to specified default if needed. 1546f5c1d5b2SJames Morris * 1547f5c1d5b2SJames Morris * @scontext: security context 1548f5c1d5b2SJames Morris * @scontext_len: length in bytes 1549f5c1d5b2SJames Morris * @sid: security identifier, SID 1550d133a960SGabriel Craciunescu * @def_sid: default SID to assign on error 1551f5c1d5b2SJames Morris * 1552f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 1553f5c1d5b2SJames Morris * has the string representation specified by @scontext. 1554f5c1d5b2SJames Morris * The default SID is passed to the MLS layer to be used to allow 1555f5c1d5b2SJames Morris * kernel labeling of the MLS field if the MLS field is not present 1556f5c1d5b2SJames Morris * (for upgrading to MLS without full relabel). 155712b29f34SStephen Smalley * Implicitly forces adding of the context even if it cannot be mapped yet. 1558f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 1559f5c1d5b2SJames Morris * memory is available, or 0 on success. 1560f5c1d5b2SJames Morris */ 1561aa8e712cSStephen Smalley int security_context_to_sid_default(struct selinux_state *state, 1562aa8e712cSStephen Smalley const char *scontext, u32 scontext_len, 15637bf570dcSDavid Howells u32 *sid, u32 def_sid, gfp_t gfp_flags) 1564f5c1d5b2SJames Morris { 1565aa8e712cSStephen Smalley return security_context_to_sid_core(state, scontext, scontext_len, 156612b29f34SStephen Smalley sid, def_sid, gfp_flags, 1); 156712b29f34SStephen Smalley } 156812b29f34SStephen Smalley 1569aa8e712cSStephen Smalley int security_context_to_sid_force(struct selinux_state *state, 1570aa8e712cSStephen Smalley const char *scontext, u32 scontext_len, 157112b29f34SStephen Smalley u32 *sid) 157212b29f34SStephen Smalley { 1573aa8e712cSStephen Smalley return security_context_to_sid_core(state, scontext, scontext_len, 157412b29f34SStephen Smalley sid, SECSID_NULL, GFP_KERNEL, 1); 1575f5c1d5b2SJames Morris } 1576f5c1d5b2SJames Morris 15771da177e4SLinus Torvalds static int compute_sid_handle_invalid_context( 1578aa8e712cSStephen Smalley struct selinux_state *state, 15791da177e4SLinus Torvalds struct context *scontext, 15801da177e4SLinus Torvalds struct context *tcontext, 15811da177e4SLinus Torvalds u16 tclass, 15821da177e4SLinus Torvalds struct context *newcontext) 15831da177e4SLinus Torvalds { 1584aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 15851da177e4SLinus Torvalds char *s = NULL, *t = NULL, *n = NULL; 15861da177e4SLinus Torvalds u32 slen, tlen, nlen; 1587ea74a685SRichard Guy Briggs struct audit_buffer *ab; 15881da177e4SLinus Torvalds 1589aa8e712cSStephen Smalley if (context_struct_to_string(policydb, scontext, &s, &slen)) 15901da177e4SLinus Torvalds goto out; 1591aa8e712cSStephen Smalley if (context_struct_to_string(policydb, tcontext, &t, &tlen)) 15921da177e4SLinus Torvalds goto out; 1593aa8e712cSStephen Smalley if (context_struct_to_string(policydb, newcontext, &n, &nlen)) 15941da177e4SLinus Torvalds goto out; 1595ea74a685SRichard Guy Briggs ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR); 1596ea74a685SRichard Guy Briggs audit_log_format(ab, 1597ea74a685SRichard Guy Briggs "op=security_compute_sid invalid_context="); 1598ea74a685SRichard Guy Briggs /* no need to record the NUL with untrusted strings */ 1599ea74a685SRichard Guy Briggs audit_log_n_untrustedstring(ab, n, nlen - 1); 1600ea74a685SRichard Guy Briggs audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s", 1601ea74a685SRichard Guy Briggs s, t, sym_name(policydb, SYM_CLASSES, tclass-1)); 1602ea74a685SRichard Guy Briggs audit_log_end(ab); 16031da177e4SLinus Torvalds out: 16041da177e4SLinus Torvalds kfree(s); 16051da177e4SLinus Torvalds kfree(t); 16061da177e4SLinus Torvalds kfree(n); 1607e5a5ca96SPaul Moore if (!enforcing_enabled(state)) 16081da177e4SLinus Torvalds return 0; 16091da177e4SLinus Torvalds return -EACCES; 16101da177e4SLinus Torvalds } 16111da177e4SLinus Torvalds 1612aa8e712cSStephen Smalley static void filename_compute_type(struct policydb *policydb, 1613aa8e712cSStephen Smalley struct context *newcontext, 16142667991fSEric Paris u32 stype, u32 ttype, u16 tclass, 1615f50a3ec9SKohei Kaigai const char *objname) 1616652bb9b0SEric Paris { 16172463c26dSEric Paris struct filename_trans ft; 16182463c26dSEric Paris struct filename_trans_datum *otype; 161903a4c018SEric Paris 162003a4c018SEric Paris /* 162103a4c018SEric Paris * Most filename trans rules are going to live in specific directories 162203a4c018SEric Paris * like /dev or /var/run. This bitmap will quickly skip rule searches 162303a4c018SEric Paris * if the ttype does not contain any rules. 162403a4c018SEric Paris */ 1625aa8e712cSStephen Smalley if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype)) 1626652bb9b0SEric Paris return; 162703a4c018SEric Paris 16282463c26dSEric Paris ft.stype = stype; 16292463c26dSEric Paris ft.ttype = ttype; 16302463c26dSEric Paris ft.tclass = tclass; 16312463c26dSEric Paris ft.name = objname; 16322463c26dSEric Paris 1633aa8e712cSStephen Smalley otype = hashtab_search(policydb->filename_trans, &ft); 16342463c26dSEric Paris if (otype) 16352463c26dSEric Paris newcontext->type = otype->otype; 1636652bb9b0SEric Paris } 1637652bb9b0SEric Paris 1638aa8e712cSStephen Smalley static int security_compute_sid(struct selinux_state *state, 1639aa8e712cSStephen Smalley u32 ssid, 16401da177e4SLinus Torvalds u32 tsid, 1641c6d3aaa4SStephen Smalley u16 orig_tclass, 16421da177e4SLinus Torvalds u32 specified, 1643f50a3ec9SKohei Kaigai const char *objname, 1644c6d3aaa4SStephen Smalley u32 *out_sid, 1645c6d3aaa4SStephen Smalley bool kern) 16461da177e4SLinus Torvalds { 1647aa8e712cSStephen Smalley struct policydb *policydb; 1648aa8e712cSStephen Smalley struct sidtab *sidtab; 1649aa893269SEric Paris struct class_datum *cladatum = NULL; 16501da177e4SLinus Torvalds struct context *scontext = NULL, *tcontext = NULL, newcontext; 16511da177e4SLinus Torvalds struct role_trans *roletr = NULL; 16521da177e4SLinus Torvalds struct avtab_key avkey; 16531da177e4SLinus Torvalds struct avtab_datum *avdatum; 16541da177e4SLinus Torvalds struct avtab_node *node; 1655c6d3aaa4SStephen Smalley u16 tclass; 16561da177e4SLinus Torvalds int rc = 0; 16576f5317e7SHarry Ciao bool sock; 16581da177e4SLinus Torvalds 1659aa8e712cSStephen Smalley if (!state->initialized) { 1660c6d3aaa4SStephen Smalley switch (orig_tclass) { 1661c6d3aaa4SStephen Smalley case SECCLASS_PROCESS: /* kernel value */ 16621da177e4SLinus Torvalds *out_sid = ssid; 16631da177e4SLinus Torvalds break; 16641da177e4SLinus Torvalds default: 16651da177e4SLinus Torvalds *out_sid = tsid; 16661da177e4SLinus Torvalds break; 16671da177e4SLinus Torvalds } 16681da177e4SLinus Torvalds goto out; 16691da177e4SLinus Torvalds } 16701da177e4SLinus Torvalds 1671851f8a69SVenkat Yekkirala context_init(&newcontext); 1672851f8a69SVenkat Yekkirala 1673aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 16741da177e4SLinus Torvalds 16756f5317e7SHarry Ciao if (kern) { 1676aa8e712cSStephen Smalley tclass = unmap_class(&state->ss->map, orig_tclass); 16776f5317e7SHarry Ciao sock = security_is_socket_class(orig_tclass); 16786f5317e7SHarry Ciao } else { 1679c6d3aaa4SStephen Smalley tclass = orig_tclass; 1680aa8e712cSStephen Smalley sock = security_is_socket_class(map_class(&state->ss->map, 1681aa8e712cSStephen Smalley tclass)); 16826f5317e7SHarry Ciao } 1683c6d3aaa4SStephen Smalley 1684aa8e712cSStephen Smalley policydb = &state->ss->policydb; 168524ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 1686aa8e712cSStephen Smalley 1687aa8e712cSStephen Smalley scontext = sidtab_search(sidtab, ssid); 16881da177e4SLinus Torvalds if (!scontext) { 1689b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 1690744ba35eSEric Paris __func__, ssid); 16911da177e4SLinus Torvalds rc = -EINVAL; 16921da177e4SLinus Torvalds goto out_unlock; 16931da177e4SLinus Torvalds } 1694aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tsid); 16951da177e4SLinus Torvalds if (!tcontext) { 1696b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 1697744ba35eSEric Paris __func__, tsid); 16981da177e4SLinus Torvalds rc = -EINVAL; 16991da177e4SLinus Torvalds goto out_unlock; 17001da177e4SLinus Torvalds } 17011da177e4SLinus Torvalds 1702aa8e712cSStephen Smalley if (tclass && tclass <= policydb->p_classes.nprim) 1703aa8e712cSStephen Smalley cladatum = policydb->class_val_to_struct[tclass - 1]; 1704aa893269SEric Paris 17051da177e4SLinus Torvalds /* Set the user identity. */ 17061da177e4SLinus Torvalds switch (specified) { 17071da177e4SLinus Torvalds case AVTAB_TRANSITION: 17081da177e4SLinus Torvalds case AVTAB_CHANGE: 1709aa893269SEric Paris if (cladatum && cladatum->default_user == DEFAULT_TARGET) { 1710aa893269SEric Paris newcontext.user = tcontext->user; 1711aa893269SEric Paris } else { 1712aa893269SEric Paris /* notice this gets both DEFAULT_SOURCE and unset */ 17131da177e4SLinus Torvalds /* Use the process user identity. */ 17141da177e4SLinus Torvalds newcontext.user = scontext->user; 1715aa893269SEric Paris } 17161da177e4SLinus Torvalds break; 17171da177e4SLinus Torvalds case AVTAB_MEMBER: 17181da177e4SLinus Torvalds /* Use the related object owner. */ 17191da177e4SLinus Torvalds newcontext.user = tcontext->user; 17201da177e4SLinus Torvalds break; 17211da177e4SLinus Torvalds } 17221da177e4SLinus Torvalds 1723aa893269SEric Paris /* Set the role to default values. */ 1724aa893269SEric Paris if (cladatum && cladatum->default_role == DEFAULT_SOURCE) { 17251da177e4SLinus Torvalds newcontext.role = scontext->role; 1726aa893269SEric Paris } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { 1727aa893269SEric Paris newcontext.role = tcontext->role; 1728aa893269SEric Paris } else { 1729aa8e712cSStephen Smalley if ((tclass == policydb->process_class) || (sock == true)) 1730aa893269SEric Paris newcontext.role = scontext->role; 1731aa893269SEric Paris else 1732aa893269SEric Paris newcontext.role = OBJECT_R_VAL; 1733aa893269SEric Paris } 1734aa893269SEric Paris 1735aa893269SEric Paris /* Set the type to default values. */ 1736eed7795dSEric Paris if (cladatum && cladatum->default_type == DEFAULT_SOURCE) { 1737eed7795dSEric Paris newcontext.type = scontext->type; 1738eed7795dSEric Paris } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) { 1739eed7795dSEric Paris newcontext.type = tcontext->type; 1740eed7795dSEric Paris } else { 1741aa8e712cSStephen Smalley if ((tclass == policydb->process_class) || (sock == true)) { 1742aa893269SEric Paris /* Use the type of process. */ 17431da177e4SLinus Torvalds newcontext.type = scontext->type; 1744c6d3aaa4SStephen Smalley } else { 17451da177e4SLinus Torvalds /* Use the type of the related object. */ 17461da177e4SLinus Torvalds newcontext.type = tcontext->type; 17471da177e4SLinus Torvalds } 1748eed7795dSEric Paris } 17491da177e4SLinus Torvalds 17501da177e4SLinus Torvalds /* Look for a type transition/member/change rule. */ 17511da177e4SLinus Torvalds avkey.source_type = scontext->type; 17521da177e4SLinus Torvalds avkey.target_type = tcontext->type; 17531da177e4SLinus Torvalds avkey.target_class = tclass; 1754782ebb99SStephen Smalley avkey.specified = specified; 1755aa8e712cSStephen Smalley avdatum = avtab_search(&policydb->te_avtab, &avkey); 17561da177e4SLinus Torvalds 17571da177e4SLinus Torvalds /* If no permanent rule, also check for enabled conditional rules */ 17581da177e4SLinus Torvalds if (!avdatum) { 1759aa8e712cSStephen Smalley node = avtab_search_node(&policydb->te_cond_avtab, &avkey); 1760dbc74c65SVesa-Matti Kari for (; node; node = avtab_search_node_next(node, specified)) { 1761782ebb99SStephen Smalley if (node->key.specified & AVTAB_ENABLED) { 17621da177e4SLinus Torvalds avdatum = &node->datum; 17631da177e4SLinus Torvalds break; 17641da177e4SLinus Torvalds } 17651da177e4SLinus Torvalds } 17661da177e4SLinus Torvalds } 17671da177e4SLinus Torvalds 1768782ebb99SStephen Smalley if (avdatum) { 17691da177e4SLinus Torvalds /* Use the type from the type transition/member/change rule. */ 1770fa1aa143SJeff Vander Stoep newcontext.type = avdatum->u.data; 17711da177e4SLinus Torvalds } 17721da177e4SLinus Torvalds 17734742600cSEric Paris /* if we have a objname this is a file trans check so check those rules */ 1774f50a3ec9SKohei Kaigai if (objname) 1775aa8e712cSStephen Smalley filename_compute_type(policydb, &newcontext, scontext->type, 1776f50a3ec9SKohei Kaigai tcontext->type, tclass, objname); 1777652bb9b0SEric Paris 17781da177e4SLinus Torvalds /* Check for class-specific changes. */ 17791da177e4SLinus Torvalds if (specified & AVTAB_TRANSITION) { 17801da177e4SLinus Torvalds /* Look for a role transition rule. */ 1781aa8e712cSStephen Smalley for (roletr = policydb->role_tr; roletr; 1782aa8e712cSStephen Smalley roletr = roletr->next) { 178363a312caSHarry Ciao if ((roletr->role == scontext->role) && 178463a312caSHarry Ciao (roletr->type == tcontext->type) && 178563a312caSHarry Ciao (roletr->tclass == tclass)) { 17861da177e4SLinus Torvalds /* Use the role transition rule. */ 17871da177e4SLinus Torvalds newcontext.role = roletr->new_role; 17881da177e4SLinus Torvalds break; 17891da177e4SLinus Torvalds } 17901da177e4SLinus Torvalds } 17911da177e4SLinus Torvalds } 17921da177e4SLinus Torvalds 17931da177e4SLinus Torvalds /* Set the MLS attributes. 17941da177e4SLinus Torvalds This is done last because it may allocate memory. */ 1795aa8e712cSStephen Smalley rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified, 17966f5317e7SHarry Ciao &newcontext, sock); 17971da177e4SLinus Torvalds if (rc) 17981da177e4SLinus Torvalds goto out_unlock; 17991da177e4SLinus Torvalds 18001da177e4SLinus Torvalds /* Check the validity of the context. */ 1801aa8e712cSStephen Smalley if (!policydb_context_isvalid(policydb, &newcontext)) { 1802aa8e712cSStephen Smalley rc = compute_sid_handle_invalid_context(state, scontext, 18031da177e4SLinus Torvalds tcontext, 18041da177e4SLinus Torvalds tclass, 18051da177e4SLinus Torvalds &newcontext); 18061da177e4SLinus Torvalds if (rc) 18071da177e4SLinus Torvalds goto out_unlock; 18081da177e4SLinus Torvalds } 18091da177e4SLinus Torvalds /* Obtain the sid for the context. */ 1810aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid); 18111da177e4SLinus Torvalds out_unlock: 1812aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 18131da177e4SLinus Torvalds context_destroy(&newcontext); 18141da177e4SLinus Torvalds out: 18151da177e4SLinus Torvalds return rc; 18161da177e4SLinus Torvalds } 18171da177e4SLinus Torvalds 18181da177e4SLinus Torvalds /** 18191da177e4SLinus Torvalds * security_transition_sid - Compute the SID for a new subject/object. 18201da177e4SLinus Torvalds * @ssid: source security identifier 18211da177e4SLinus Torvalds * @tsid: target security identifier 18221da177e4SLinus Torvalds * @tclass: target security class 18231da177e4SLinus Torvalds * @out_sid: security identifier for new subject/object 18241da177e4SLinus Torvalds * 18251da177e4SLinus Torvalds * Compute a SID to use for labeling a new subject or object in the 18261da177e4SLinus Torvalds * class @tclass based on a SID pair (@ssid, @tsid). 18271da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 18281da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the new SID was 18291da177e4SLinus Torvalds * computed successfully. 18301da177e4SLinus Torvalds */ 1831aa8e712cSStephen Smalley int security_transition_sid(struct selinux_state *state, 1832aa8e712cSStephen Smalley u32 ssid, u32 tsid, u16 tclass, 1833652bb9b0SEric Paris const struct qstr *qstr, u32 *out_sid) 18341da177e4SLinus Torvalds { 1835aa8e712cSStephen Smalley return security_compute_sid(state, ssid, tsid, tclass, 1836aa8e712cSStephen Smalley AVTAB_TRANSITION, 1837f50a3ec9SKohei Kaigai qstr ? qstr->name : NULL, out_sid, true); 1838c6d3aaa4SStephen Smalley } 1839c6d3aaa4SStephen Smalley 1840aa8e712cSStephen Smalley int security_transition_sid_user(struct selinux_state *state, 1841aa8e712cSStephen Smalley u32 ssid, u32 tsid, u16 tclass, 1842f50a3ec9SKohei Kaigai const char *objname, u32 *out_sid) 1843c6d3aaa4SStephen Smalley { 1844aa8e712cSStephen Smalley return security_compute_sid(state, ssid, tsid, tclass, 1845aa8e712cSStephen Smalley AVTAB_TRANSITION, 1846f50a3ec9SKohei Kaigai objname, out_sid, false); 18471da177e4SLinus Torvalds } 18481da177e4SLinus Torvalds 18491da177e4SLinus Torvalds /** 18501da177e4SLinus Torvalds * security_member_sid - Compute the SID for member selection. 18511da177e4SLinus Torvalds * @ssid: source security identifier 18521da177e4SLinus Torvalds * @tsid: target security identifier 18531da177e4SLinus Torvalds * @tclass: target security class 18541da177e4SLinus Torvalds * @out_sid: security identifier for selected member 18551da177e4SLinus Torvalds * 18561da177e4SLinus Torvalds * Compute a SID to use when selecting a member of a polyinstantiated 18571da177e4SLinus Torvalds * object of class @tclass based on a SID pair (@ssid, @tsid). 18581da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 18591da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 18601da177e4SLinus Torvalds * computed successfully. 18611da177e4SLinus Torvalds */ 1862aa8e712cSStephen Smalley int security_member_sid(struct selinux_state *state, 1863aa8e712cSStephen Smalley u32 ssid, 18641da177e4SLinus Torvalds u32 tsid, 18651da177e4SLinus Torvalds u16 tclass, 18661da177e4SLinus Torvalds u32 *out_sid) 18671da177e4SLinus Torvalds { 1868aa8e712cSStephen Smalley return security_compute_sid(state, ssid, tsid, tclass, 1869aa8e712cSStephen Smalley AVTAB_MEMBER, NULL, 1870652bb9b0SEric Paris out_sid, false); 18711da177e4SLinus Torvalds } 18721da177e4SLinus Torvalds 18731da177e4SLinus Torvalds /** 18741da177e4SLinus Torvalds * security_change_sid - Compute the SID for object relabeling. 18751da177e4SLinus Torvalds * @ssid: source security identifier 18761da177e4SLinus Torvalds * @tsid: target security identifier 18771da177e4SLinus Torvalds * @tclass: target security class 18781da177e4SLinus Torvalds * @out_sid: security identifier for selected member 18791da177e4SLinus Torvalds * 18801da177e4SLinus Torvalds * Compute a SID to use for relabeling an object of class @tclass 18811da177e4SLinus Torvalds * based on a SID pair (@ssid, @tsid). 18821da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 18831da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 18841da177e4SLinus Torvalds * computed successfully. 18851da177e4SLinus Torvalds */ 1886aa8e712cSStephen Smalley int security_change_sid(struct selinux_state *state, 1887aa8e712cSStephen Smalley u32 ssid, 18881da177e4SLinus Torvalds u32 tsid, 18891da177e4SLinus Torvalds u16 tclass, 18901da177e4SLinus Torvalds u32 *out_sid) 18911da177e4SLinus Torvalds { 1892aa8e712cSStephen Smalley return security_compute_sid(state, 1893aa8e712cSStephen Smalley ssid, tsid, tclass, AVTAB_CHANGE, NULL, 1894652bb9b0SEric Paris out_sid, false); 1895b94c7e67SChad Sellers } 1896b94c7e67SChad Sellers 1897aa8e712cSStephen Smalley static inline int convert_context_handle_invalid_context( 1898aa8e712cSStephen Smalley struct selinux_state *state, 1899aa8e712cSStephen Smalley struct context *context) 19001da177e4SLinus Torvalds { 1901aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 19021da177e4SLinus Torvalds char *s; 19031da177e4SLinus Torvalds u32 len; 19041da177e4SLinus Torvalds 1905e5a5ca96SPaul Moore if (enforcing_enabled(state)) 19064b02b524SEric Paris return -EINVAL; 19074b02b524SEric Paris 1908aa8e712cSStephen Smalley if (!context_struct_to_string(policydb, context, &s, &len)) { 1909b54c85c1Speter enderborg pr_warn("SELinux: Context %s would be invalid if enforcing\n", 1910b54c85c1Speter enderborg s); 19111da177e4SLinus Torvalds kfree(s); 19121da177e4SLinus Torvalds } 19134b02b524SEric Paris return 0; 19141da177e4SLinus Torvalds } 19151da177e4SLinus Torvalds 19161da177e4SLinus Torvalds struct convert_context_args { 1917aa8e712cSStephen Smalley struct selinux_state *state; 19181da177e4SLinus Torvalds struct policydb *oldp; 19191da177e4SLinus Torvalds struct policydb *newp; 19201da177e4SLinus Torvalds }; 19211da177e4SLinus Torvalds 19221da177e4SLinus Torvalds /* 19231da177e4SLinus Torvalds * Convert the values in the security context 1924ee1a84fdSOndrej Mosnacek * structure `oldc' from the values specified 19251da177e4SLinus Torvalds * in the policy `p->oldp' to the values specified 1926ee1a84fdSOndrej Mosnacek * in the policy `p->newp', storing the new context 1927ee1a84fdSOndrej Mosnacek * in `newc'. Verify that the context is valid 1928ee1a84fdSOndrej Mosnacek * under the new policy. 19291da177e4SLinus Torvalds */ 1930ee1a84fdSOndrej Mosnacek static int convert_context(struct context *oldc, struct context *newc, void *p) 19311da177e4SLinus Torvalds { 19321da177e4SLinus Torvalds struct convert_context_args *args; 19330719aaf5SGuido Trentalancia struct ocontext *oc; 19341da177e4SLinus Torvalds struct role_datum *role; 19351da177e4SLinus Torvalds struct type_datum *typdatum; 19361da177e4SLinus Torvalds struct user_datum *usrdatum; 19371da177e4SLinus Torvalds char *s; 19381da177e4SLinus Torvalds u32 len; 193924ed7fdaSOndrej Mosnacek int rc; 19401da177e4SLinus Torvalds 19411da177e4SLinus Torvalds args = p; 19421da177e4SLinus Torvalds 1943ee1a84fdSOndrej Mosnacek if (oldc->str) { 1944ee1a84fdSOndrej Mosnacek s = kstrdup(oldc->str, GFP_KERNEL); 19454b02b524SEric Paris if (!s) 1946ee1a84fdSOndrej Mosnacek return -ENOMEM; 19474b02b524SEric Paris 19489a59daa0SStephen Smalley rc = string_to_context_struct(args->newp, NULL, s, 1949ee1a84fdSOndrej Mosnacek newc, SECSID_NULL); 1950ee1a84fdSOndrej Mosnacek if (rc == -EINVAL) { 195112b29f34SStephen Smalley /* Retain string representation for later mapping. */ 1952ee1a84fdSOndrej Mosnacek context_init(newc); 1953ee1a84fdSOndrej Mosnacek newc->str = s; 1954ee1a84fdSOndrej Mosnacek newc->len = oldc->len; 1955ee1a84fdSOndrej Mosnacek return 0; 1956ee1a84fdSOndrej Mosnacek } 1957ee1a84fdSOndrej Mosnacek kfree(s); 1958ee1a84fdSOndrej Mosnacek if (rc) { 195912b29f34SStephen Smalley /* Other error condition, e.g. ENOMEM. */ 1960b54c85c1Speter enderborg pr_err("SELinux: Unable to map context %s, rc = %d.\n", 1961ee1a84fdSOndrej Mosnacek oldc->str, -rc); 1962ee1a84fdSOndrej Mosnacek return rc; 196312b29f34SStephen Smalley } 1964ee1a84fdSOndrej Mosnacek pr_info("SELinux: Context %s became valid (mapped).\n", 1965ee1a84fdSOndrej Mosnacek oldc->str); 1966ee1a84fdSOndrej Mosnacek return 0; 196712b29f34SStephen Smalley } 196812b29f34SStephen Smalley 1969ee1a84fdSOndrej Mosnacek context_init(newc); 19701da177e4SLinus Torvalds 19711da177e4SLinus Torvalds /* Convert the user. */ 19724b02b524SEric Paris rc = -EINVAL; 19731da177e4SLinus Torvalds usrdatum = hashtab_search(args->newp->p_users.table, 1974ee1a84fdSOndrej Mosnacek sym_name(args->oldp, 1975ee1a84fdSOndrej Mosnacek SYM_USERS, oldc->user - 1)); 19765d55a345SEric Paris if (!usrdatum) 19771da177e4SLinus Torvalds goto bad; 1978ee1a84fdSOndrej Mosnacek newc->user = usrdatum->value; 19791da177e4SLinus Torvalds 19801da177e4SLinus Torvalds /* Convert the role. */ 19814b02b524SEric Paris rc = -EINVAL; 19821da177e4SLinus Torvalds role = hashtab_search(args->newp->p_roles.table, 1983ee1a84fdSOndrej Mosnacek sym_name(args->oldp, SYM_ROLES, oldc->role - 1)); 19845d55a345SEric Paris if (!role) 19851da177e4SLinus Torvalds goto bad; 1986ee1a84fdSOndrej Mosnacek newc->role = role->value; 19871da177e4SLinus Torvalds 19881da177e4SLinus Torvalds /* Convert the type. */ 19894b02b524SEric Paris rc = -EINVAL; 19901da177e4SLinus Torvalds typdatum = hashtab_search(args->newp->p_types.table, 1991ee1a84fdSOndrej Mosnacek sym_name(args->oldp, 1992ee1a84fdSOndrej Mosnacek SYM_TYPES, oldc->type - 1)); 19935d55a345SEric Paris if (!typdatum) 19941da177e4SLinus Torvalds goto bad; 1995ee1a84fdSOndrej Mosnacek newc->type = typdatum->value; 19961da177e4SLinus Torvalds 19970719aaf5SGuido Trentalancia /* Convert the MLS fields if dealing with MLS policies */ 19980719aaf5SGuido Trentalancia if (args->oldp->mls_enabled && args->newp->mls_enabled) { 1999ee1a84fdSOndrej Mosnacek rc = mls_convert_context(args->oldp, args->newp, oldc, newc); 20001da177e4SLinus Torvalds if (rc) 20011da177e4SLinus Torvalds goto bad; 20020719aaf5SGuido Trentalancia } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { 20030719aaf5SGuido Trentalancia /* 20040719aaf5SGuido Trentalancia * Switching between non-MLS and MLS policy: 20050719aaf5SGuido Trentalancia * ensure that the MLS fields of the context for all 20060719aaf5SGuido Trentalancia * existing entries in the sidtab are filled in with a 20070719aaf5SGuido Trentalancia * suitable default value, likely taken from one of the 20080719aaf5SGuido Trentalancia * initial SIDs. 20090719aaf5SGuido Trentalancia */ 20100719aaf5SGuido Trentalancia oc = args->newp->ocontexts[OCON_ISID]; 20110719aaf5SGuido Trentalancia while (oc && oc->sid[0] != SECINITSID_UNLABELED) 20120719aaf5SGuido Trentalancia oc = oc->next; 20134b02b524SEric Paris rc = -EINVAL; 20140719aaf5SGuido Trentalancia if (!oc) { 2015b54c85c1Speter enderborg pr_err("SELinux: unable to look up" 20160719aaf5SGuido Trentalancia " the initial SIDs list\n"); 20170719aaf5SGuido Trentalancia goto bad; 20180719aaf5SGuido Trentalancia } 2019ee1a84fdSOndrej Mosnacek rc = mls_range_set(newc, &oc->context[0].range); 20200719aaf5SGuido Trentalancia if (rc) 20210719aaf5SGuido Trentalancia goto bad; 20220719aaf5SGuido Trentalancia } 20231da177e4SLinus Torvalds 20241da177e4SLinus Torvalds /* Check the validity of the new context. */ 2025ee1a84fdSOndrej Mosnacek if (!policydb_context_isvalid(args->newp, newc)) { 2026ee1a84fdSOndrej Mosnacek rc = convert_context_handle_invalid_context(args->state, oldc); 20271da177e4SLinus Torvalds if (rc) 20281da177e4SLinus Torvalds goto bad; 20291da177e4SLinus Torvalds } 20301da177e4SLinus Torvalds 2031ee1a84fdSOndrej Mosnacek return 0; 20321da177e4SLinus Torvalds bad: 203312b29f34SStephen Smalley /* Map old representation to string and save it. */ 2034ee1a84fdSOndrej Mosnacek rc = context_struct_to_string(args->oldp, oldc, &s, &len); 20354b02b524SEric Paris if (rc) 20364b02b524SEric Paris return rc; 2037ee1a84fdSOndrej Mosnacek context_destroy(newc); 2038ee1a84fdSOndrej Mosnacek newc->str = s; 2039ee1a84fdSOndrej Mosnacek newc->len = len; 2040b54c85c1Speter enderborg pr_info("SELinux: Context %s became invalid (unmapped).\n", 2041ee1a84fdSOndrej Mosnacek newc->str); 2042ee1a84fdSOndrej Mosnacek return 0; 20431da177e4SLinus Torvalds } 20441da177e4SLinus Torvalds 2045aa8e712cSStephen Smalley static void security_load_policycaps(struct selinux_state *state) 20463bb56b25SPaul Moore { 2047aa8e712cSStephen Smalley struct policydb *p = &state->ss->policydb; 20484dc2fce3SStephen Smalley unsigned int i; 20494dc2fce3SStephen Smalley struct ebitmap_node *node; 20504dc2fce3SStephen Smalley 2051aa8e712cSStephen Smalley for (i = 0; i < ARRAY_SIZE(state->policycap); i++) 2052aa8e712cSStephen Smalley state->policycap[i] = ebitmap_get_bit(&p->policycaps, i); 20534dc2fce3SStephen Smalley 20544dc2fce3SStephen Smalley for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++) 20554dc2fce3SStephen Smalley pr_info("SELinux: policy capability %s=%d\n", 20564dc2fce3SStephen Smalley selinux_policycap_names[i], 2057aa8e712cSStephen Smalley ebitmap_get_bit(&p->policycaps, i)); 20584dc2fce3SStephen Smalley 2059aa8e712cSStephen Smalley ebitmap_for_each_positive_bit(&p->policycaps, node, i) { 20604dc2fce3SStephen Smalley if (i >= ARRAY_SIZE(selinux_policycap_names)) 20614dc2fce3SStephen Smalley pr_info("SELinux: unknown policy capability %u\n", 20624dc2fce3SStephen Smalley i); 20634dc2fce3SStephen Smalley } 20643bb56b25SPaul Moore } 20653bb56b25SPaul Moore 2066aa8e712cSStephen Smalley static int security_preserve_bools(struct selinux_state *state, 2067aa8e712cSStephen Smalley struct policydb *newpolicydb); 20681da177e4SLinus Torvalds 20691da177e4SLinus Torvalds /** 20701da177e4SLinus Torvalds * security_load_policy - Load a security policy configuration. 20711da177e4SLinus Torvalds * @data: binary policy data 20721da177e4SLinus Torvalds * @len: length of data in bytes 20731da177e4SLinus Torvalds * 20741da177e4SLinus Torvalds * Load a new set of security policy configuration data, 20751da177e4SLinus Torvalds * validate it and convert the SID table as necessary. 20761da177e4SLinus Torvalds * This function will flush the access vector cache after 20771da177e4SLinus Torvalds * loading the new policy. 20781da177e4SLinus Torvalds */ 2079aa8e712cSStephen Smalley int security_load_policy(struct selinux_state *state, void *data, size_t len) 20801da177e4SLinus Torvalds { 2081aa8e712cSStephen Smalley struct policydb *policydb; 208224ed7fdaSOndrej Mosnacek struct sidtab *oldsidtab, *newsidtab; 2083b5495b42STim Gardner struct policydb *oldpolicydb, *newpolicydb; 2084aa8e712cSStephen Smalley struct selinux_mapping *oldmapping; 2085aa8e712cSStephen Smalley struct selinux_map newmap; 2086ee1a84fdSOndrej Mosnacek struct sidtab_convert_params convert_params; 20871da177e4SLinus Torvalds struct convert_context_args args; 20881da177e4SLinus Torvalds u32 seqno; 20891da177e4SLinus Torvalds int rc = 0; 20901da177e4SLinus Torvalds struct policy_file file = { data, len }, *fp = &file; 20911da177e4SLinus Torvalds 20926396bb22SKees Cook oldpolicydb = kcalloc(2, sizeof(*oldpolicydb), GFP_KERNEL); 2093b5495b42STim Gardner if (!oldpolicydb) { 2094b5495b42STim Gardner rc = -ENOMEM; 2095b5495b42STim Gardner goto out; 2096b5495b42STim Gardner } 2097b5495b42STim Gardner newpolicydb = oldpolicydb + 1; 2098b5495b42STim Gardner 2099aa8e712cSStephen Smalley policydb = &state->ss->policydb; 210024ed7fdaSOndrej Mosnacek 210124ed7fdaSOndrej Mosnacek newsidtab = kmalloc(sizeof(*newsidtab), GFP_KERNEL); 210224ed7fdaSOndrej Mosnacek if (!newsidtab) { 210324ed7fdaSOndrej Mosnacek rc = -ENOMEM; 210424ed7fdaSOndrej Mosnacek goto out; 210524ed7fdaSOndrej Mosnacek } 2106aa8e712cSStephen Smalley 2107aa8e712cSStephen Smalley if (!state->initialized) { 2108aa8e712cSStephen Smalley rc = policydb_read(policydb, fp); 210924ed7fdaSOndrej Mosnacek if (rc) { 211024ed7fdaSOndrej Mosnacek kfree(newsidtab); 2111aa8e712cSStephen Smalley goto out; 211224ed7fdaSOndrej Mosnacek } 2113aa8e712cSStephen Smalley 2114aa8e712cSStephen Smalley policydb->len = len; 2115aa8e712cSStephen Smalley rc = selinux_set_mapping(policydb, secclass_map, 2116aa8e712cSStephen Smalley &state->ss->map); 2117a2000050SEric Paris if (rc) { 211824ed7fdaSOndrej Mosnacek kfree(newsidtab); 2119aa8e712cSStephen Smalley policydb_destroy(policydb); 2120b5495b42STim Gardner goto out; 21211da177e4SLinus Torvalds } 2122a2000050SEric Paris 212324ed7fdaSOndrej Mosnacek rc = policydb_load_isids(policydb, newsidtab); 2124a2000050SEric Paris if (rc) { 212524ed7fdaSOndrej Mosnacek kfree(newsidtab); 2126aa8e712cSStephen Smalley policydb_destroy(policydb); 2127b5495b42STim Gardner goto out; 21281da177e4SLinus Torvalds } 2129a2000050SEric Paris 213024ed7fdaSOndrej Mosnacek state->ss->sidtab = newsidtab; 2131aa8e712cSStephen Smalley security_load_policycaps(state); 2132aa8e712cSStephen Smalley state->initialized = 1; 2133aa8e712cSStephen Smalley seqno = ++state->ss->latest_granting; 21341da177e4SLinus Torvalds selinux_complete_init(); 21356b6bc620SStephen Smalley avc_ss_reset(state->avc, seqno); 21364c443d1bSStephen Smalley selnl_notify_policyload(seqno); 2137aa8e712cSStephen Smalley selinux_status_update_policyload(state, seqno); 21387420ed23SVenkat Yekkirala selinux_netlbl_cache_invalidate(); 2139342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 2140b5495b42STim Gardner goto out; 21411da177e4SLinus Torvalds } 21421da177e4SLinus Torvalds 2143b5495b42STim Gardner rc = policydb_read(newpolicydb, fp); 214424ed7fdaSOndrej Mosnacek if (rc) { 214524ed7fdaSOndrej Mosnacek kfree(newsidtab); 2146b5495b42STim Gardner goto out; 214724ed7fdaSOndrej Mosnacek } 21481da177e4SLinus Torvalds 2149b5495b42STim Gardner newpolicydb->len = len; 21500719aaf5SGuido Trentalancia /* If switching between different policy types, log MLS status */ 2151aa8e712cSStephen Smalley if (policydb->mls_enabled && !newpolicydb->mls_enabled) 2152b54c85c1Speter enderborg pr_info("SELinux: Disabling MLS support...\n"); 2153aa8e712cSStephen Smalley else if (!policydb->mls_enabled && newpolicydb->mls_enabled) 2154b54c85c1Speter enderborg pr_info("SELinux: Enabling MLS support...\n"); 21550719aaf5SGuido Trentalancia 215624ed7fdaSOndrej Mosnacek rc = policydb_load_isids(newpolicydb, newsidtab); 215742596eafSGuido Trentalancia if (rc) { 2158b54c85c1Speter enderborg pr_err("SELinux: unable to load the initial SIDs\n"); 2159b5495b42STim Gardner policydb_destroy(newpolicydb); 216024ed7fdaSOndrej Mosnacek kfree(newsidtab); 2161b5495b42STim Gardner goto out; 216212b29f34SStephen Smalley } 21631da177e4SLinus Torvalds 2164aa8e712cSStephen Smalley rc = selinux_set_mapping(newpolicydb, secclass_map, &newmap); 2165a2000050SEric Paris if (rc) 2166b94c7e67SChad Sellers goto err; 2167b94c7e67SChad Sellers 2168aa8e712cSStephen Smalley rc = security_preserve_bools(state, newpolicydb); 2169e900a7d9SStephen Smalley if (rc) { 2170b54c85c1Speter enderborg pr_err("SELinux: unable to preserve booleans\n"); 2171e900a7d9SStephen Smalley goto err; 2172e900a7d9SStephen Smalley } 2173e900a7d9SStephen Smalley 2174ee1a84fdSOndrej Mosnacek oldsidtab = state->ss->sidtab; 2175ee1a84fdSOndrej Mosnacek 217612b29f34SStephen Smalley /* 217712b29f34SStephen Smalley * Convert the internal representations of contexts 217812b29f34SStephen Smalley * in the new SID table. 217912b29f34SStephen Smalley */ 2180aa8e712cSStephen Smalley args.state = state; 2181aa8e712cSStephen Smalley args.oldp = policydb; 2182b5495b42STim Gardner args.newp = newpolicydb; 2183ee1a84fdSOndrej Mosnacek 2184ee1a84fdSOndrej Mosnacek convert_params.func = convert_context; 2185ee1a84fdSOndrej Mosnacek convert_params.args = &args; 2186ee1a84fdSOndrej Mosnacek convert_params.target = newsidtab; 2187ee1a84fdSOndrej Mosnacek 2188ee1a84fdSOndrej Mosnacek rc = sidtab_convert(oldsidtab, &convert_params); 21890719aaf5SGuido Trentalancia if (rc) { 2190b54c85c1Speter enderborg pr_err("SELinux: unable to convert the internal" 21910719aaf5SGuido Trentalancia " representation of contexts in the new SID" 21920719aaf5SGuido Trentalancia " table\n"); 219312b29f34SStephen Smalley goto err; 21940719aaf5SGuido Trentalancia } 21951da177e4SLinus Torvalds 21961da177e4SLinus Torvalds /* Save the old policydb and SID table to free later. */ 2197aa8e712cSStephen Smalley memcpy(oldpolicydb, policydb, sizeof(*policydb)); 21981da177e4SLinus Torvalds 21991da177e4SLinus Torvalds /* Install the new policydb and SID table. */ 2200aa8e712cSStephen Smalley write_lock_irq(&state->ss->policy_rwlock); 2201aa8e712cSStephen Smalley memcpy(policydb, newpolicydb, sizeof(*policydb)); 220224ed7fdaSOndrej Mosnacek state->ss->sidtab = newsidtab; 2203aa8e712cSStephen Smalley security_load_policycaps(state); 2204aa8e712cSStephen Smalley oldmapping = state->ss->map.mapping; 2205aa8e712cSStephen Smalley state->ss->map.mapping = newmap.mapping; 2206aa8e712cSStephen Smalley state->ss->map.size = newmap.size; 2207aa8e712cSStephen Smalley seqno = ++state->ss->latest_granting; 2208aa8e712cSStephen Smalley write_unlock_irq(&state->ss->policy_rwlock); 22091da177e4SLinus Torvalds 22101da177e4SLinus Torvalds /* Free the old policydb and SID table. */ 2211b5495b42STim Gardner policydb_destroy(oldpolicydb); 221224ed7fdaSOndrej Mosnacek sidtab_destroy(oldsidtab); 221324ed7fdaSOndrej Mosnacek kfree(oldsidtab); 2214aa8e712cSStephen Smalley kfree(oldmapping); 22151da177e4SLinus Torvalds 22166b6bc620SStephen Smalley avc_ss_reset(state->avc, seqno); 22171da177e4SLinus Torvalds selnl_notify_policyload(seqno); 2218aa8e712cSStephen Smalley selinux_status_update_policyload(state, seqno); 22197420ed23SVenkat Yekkirala selinux_netlbl_cache_invalidate(); 2220342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 22211da177e4SLinus Torvalds 2222b5495b42STim Gardner rc = 0; 2223b5495b42STim Gardner goto out; 22241da177e4SLinus Torvalds 22251da177e4SLinus Torvalds err: 2226aa8e712cSStephen Smalley kfree(newmap.mapping); 222724ed7fdaSOndrej Mosnacek sidtab_destroy(newsidtab); 222824ed7fdaSOndrej Mosnacek kfree(newsidtab); 2229b5495b42STim Gardner policydb_destroy(newpolicydb); 22301da177e4SLinus Torvalds 2231b5495b42STim Gardner out: 2232b5495b42STim Gardner kfree(oldpolicydb); 2233b5495b42STim Gardner return rc; 22341da177e4SLinus Torvalds } 22351da177e4SLinus Torvalds 2236aa8e712cSStephen Smalley size_t security_policydb_len(struct selinux_state *state) 2237cee74f47SEric Paris { 2238aa8e712cSStephen Smalley struct policydb *p = &state->ss->policydb; 2239cee74f47SEric Paris size_t len; 2240cee74f47SEric Paris 2241aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 2242aa8e712cSStephen Smalley len = p->len; 2243aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 2244cee74f47SEric Paris 2245cee74f47SEric Paris return len; 2246cee74f47SEric Paris } 2247cee74f47SEric Paris 22481da177e4SLinus Torvalds /** 22491da177e4SLinus Torvalds * security_port_sid - Obtain the SID for a port. 22501da177e4SLinus Torvalds * @protocol: protocol number 22511da177e4SLinus Torvalds * @port: port number 22521da177e4SLinus Torvalds * @out_sid: security identifier 22531da177e4SLinus Torvalds */ 2254aa8e712cSStephen Smalley int security_port_sid(struct selinux_state *state, 2255aa8e712cSStephen Smalley u8 protocol, u16 port, u32 *out_sid) 22561da177e4SLinus Torvalds { 2257aa8e712cSStephen Smalley struct policydb *policydb; 2258aa8e712cSStephen Smalley struct sidtab *sidtab; 22591da177e4SLinus Torvalds struct ocontext *c; 22601da177e4SLinus Torvalds int rc = 0; 22611da177e4SLinus Torvalds 2262aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 22631da177e4SLinus Torvalds 2264aa8e712cSStephen Smalley policydb = &state->ss->policydb; 226524ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 2266aa8e712cSStephen Smalley 2267aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_PORT]; 22681da177e4SLinus Torvalds while (c) { 22691da177e4SLinus Torvalds if (c->u.port.protocol == protocol && 22701da177e4SLinus Torvalds c->u.port.low_port <= port && 22711da177e4SLinus Torvalds c->u.port.high_port >= port) 22721da177e4SLinus Torvalds break; 22731da177e4SLinus Torvalds c = c->next; 22741da177e4SLinus Torvalds } 22751da177e4SLinus Torvalds 22761da177e4SLinus Torvalds if (c) { 22771da177e4SLinus Torvalds if (!c->sid[0]) { 2278aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, 22791da177e4SLinus Torvalds &c->context[0], 22801da177e4SLinus Torvalds &c->sid[0]); 22811da177e4SLinus Torvalds if (rc) 22821da177e4SLinus Torvalds goto out; 22831da177e4SLinus Torvalds } 22841da177e4SLinus Torvalds *out_sid = c->sid[0]; 22851da177e4SLinus Torvalds } else { 22861da177e4SLinus Torvalds *out_sid = SECINITSID_PORT; 22871da177e4SLinus Torvalds } 22881da177e4SLinus Torvalds 22891da177e4SLinus Torvalds out: 2290aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 22911da177e4SLinus Torvalds return rc; 22921da177e4SLinus Torvalds } 22931da177e4SLinus Torvalds 22941da177e4SLinus Torvalds /** 2295cfc4d882SDaniel Jurgens * security_pkey_sid - Obtain the SID for a pkey. 2296cfc4d882SDaniel Jurgens * @subnet_prefix: Subnet Prefix 2297cfc4d882SDaniel Jurgens * @pkey_num: pkey number 2298cfc4d882SDaniel Jurgens * @out_sid: security identifier 2299cfc4d882SDaniel Jurgens */ 2300aa8e712cSStephen Smalley int security_ib_pkey_sid(struct selinux_state *state, 2301aa8e712cSStephen Smalley u64 subnet_prefix, u16 pkey_num, u32 *out_sid) 2302cfc4d882SDaniel Jurgens { 2303aa8e712cSStephen Smalley struct policydb *policydb; 2304aa8e712cSStephen Smalley struct sidtab *sidtab; 2305cfc4d882SDaniel Jurgens struct ocontext *c; 2306cfc4d882SDaniel Jurgens int rc = 0; 2307cfc4d882SDaniel Jurgens 2308aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 2309cfc4d882SDaniel Jurgens 2310aa8e712cSStephen Smalley policydb = &state->ss->policydb; 231124ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 2312aa8e712cSStephen Smalley 2313aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_IBPKEY]; 2314cfc4d882SDaniel Jurgens while (c) { 2315cfc4d882SDaniel Jurgens if (c->u.ibpkey.low_pkey <= pkey_num && 2316cfc4d882SDaniel Jurgens c->u.ibpkey.high_pkey >= pkey_num && 2317cfc4d882SDaniel Jurgens c->u.ibpkey.subnet_prefix == subnet_prefix) 2318cfc4d882SDaniel Jurgens break; 2319cfc4d882SDaniel Jurgens 2320cfc4d882SDaniel Jurgens c = c->next; 2321cfc4d882SDaniel Jurgens } 2322cfc4d882SDaniel Jurgens 2323cfc4d882SDaniel Jurgens if (c) { 2324cfc4d882SDaniel Jurgens if (!c->sid[0]) { 2325aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, 2326cfc4d882SDaniel Jurgens &c->context[0], 2327cfc4d882SDaniel Jurgens &c->sid[0]); 2328cfc4d882SDaniel Jurgens if (rc) 2329cfc4d882SDaniel Jurgens goto out; 2330cfc4d882SDaniel Jurgens } 2331cfc4d882SDaniel Jurgens *out_sid = c->sid[0]; 2332cfc4d882SDaniel Jurgens } else 2333cfc4d882SDaniel Jurgens *out_sid = SECINITSID_UNLABELED; 2334cfc4d882SDaniel Jurgens 2335cfc4d882SDaniel Jurgens out: 2336aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 2337cfc4d882SDaniel Jurgens return rc; 2338cfc4d882SDaniel Jurgens } 2339cfc4d882SDaniel Jurgens 2340cfc4d882SDaniel Jurgens /** 2341ab861dfcSDaniel Jurgens * security_ib_endport_sid - Obtain the SID for a subnet management interface. 2342ab861dfcSDaniel Jurgens * @dev_name: device name 2343ab861dfcSDaniel Jurgens * @port: port number 2344ab861dfcSDaniel Jurgens * @out_sid: security identifier 2345ab861dfcSDaniel Jurgens */ 2346aa8e712cSStephen Smalley int security_ib_endport_sid(struct selinux_state *state, 2347aa8e712cSStephen Smalley const char *dev_name, u8 port_num, u32 *out_sid) 2348ab861dfcSDaniel Jurgens { 2349aa8e712cSStephen Smalley struct policydb *policydb; 2350aa8e712cSStephen Smalley struct sidtab *sidtab; 2351ab861dfcSDaniel Jurgens struct ocontext *c; 2352ab861dfcSDaniel Jurgens int rc = 0; 2353ab861dfcSDaniel Jurgens 2354aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 2355ab861dfcSDaniel Jurgens 2356aa8e712cSStephen Smalley policydb = &state->ss->policydb; 235724ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 2358aa8e712cSStephen Smalley 2359aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_IBENDPORT]; 2360ab861dfcSDaniel Jurgens while (c) { 2361ab861dfcSDaniel Jurgens if (c->u.ibendport.port == port_num && 2362ab861dfcSDaniel Jurgens !strncmp(c->u.ibendport.dev_name, 2363ab861dfcSDaniel Jurgens dev_name, 2364ab861dfcSDaniel Jurgens IB_DEVICE_NAME_MAX)) 2365ab861dfcSDaniel Jurgens break; 2366ab861dfcSDaniel Jurgens 2367ab861dfcSDaniel Jurgens c = c->next; 2368ab861dfcSDaniel Jurgens } 2369ab861dfcSDaniel Jurgens 2370ab861dfcSDaniel Jurgens if (c) { 2371ab861dfcSDaniel Jurgens if (!c->sid[0]) { 2372aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, 2373ab861dfcSDaniel Jurgens &c->context[0], 2374ab861dfcSDaniel Jurgens &c->sid[0]); 2375ab861dfcSDaniel Jurgens if (rc) 2376ab861dfcSDaniel Jurgens goto out; 2377ab861dfcSDaniel Jurgens } 2378ab861dfcSDaniel Jurgens *out_sid = c->sid[0]; 2379ab861dfcSDaniel Jurgens } else 2380ab861dfcSDaniel Jurgens *out_sid = SECINITSID_UNLABELED; 2381ab861dfcSDaniel Jurgens 2382ab861dfcSDaniel Jurgens out: 2383aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 2384ab861dfcSDaniel Jurgens return rc; 2385ab861dfcSDaniel Jurgens } 2386ab861dfcSDaniel Jurgens 2387ab861dfcSDaniel Jurgens /** 23881da177e4SLinus Torvalds * security_netif_sid - Obtain the SID for a network interface. 23891da177e4SLinus Torvalds * @name: interface name 23901da177e4SLinus Torvalds * @if_sid: interface SID 23911da177e4SLinus Torvalds */ 2392aa8e712cSStephen Smalley int security_netif_sid(struct selinux_state *state, 2393aa8e712cSStephen Smalley char *name, u32 *if_sid) 23941da177e4SLinus Torvalds { 2395aa8e712cSStephen Smalley struct policydb *policydb; 2396aa8e712cSStephen Smalley struct sidtab *sidtab; 23971da177e4SLinus Torvalds int rc = 0; 23981da177e4SLinus Torvalds struct ocontext *c; 23991da177e4SLinus Torvalds 2400aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 24011da177e4SLinus Torvalds 2402aa8e712cSStephen Smalley policydb = &state->ss->policydb; 240324ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 2404aa8e712cSStephen Smalley 2405aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_NETIF]; 24061da177e4SLinus Torvalds while (c) { 24071da177e4SLinus Torvalds if (strcmp(name, c->u.name) == 0) 24081da177e4SLinus Torvalds break; 24091da177e4SLinus Torvalds c = c->next; 24101da177e4SLinus Torvalds } 24111da177e4SLinus Torvalds 24121da177e4SLinus Torvalds if (c) { 24131da177e4SLinus Torvalds if (!c->sid[0] || !c->sid[1]) { 2414aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, 24151da177e4SLinus Torvalds &c->context[0], 24161da177e4SLinus Torvalds &c->sid[0]); 24171da177e4SLinus Torvalds if (rc) 24181da177e4SLinus Torvalds goto out; 2419aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, 24201da177e4SLinus Torvalds &c->context[1], 24211da177e4SLinus Torvalds &c->sid[1]); 24221da177e4SLinus Torvalds if (rc) 24231da177e4SLinus Torvalds goto out; 24241da177e4SLinus Torvalds } 24251da177e4SLinus Torvalds *if_sid = c->sid[0]; 2426e8bfdb9dSPaul Moore } else 24271da177e4SLinus Torvalds *if_sid = SECINITSID_NETIF; 24281da177e4SLinus Torvalds 24291da177e4SLinus Torvalds out: 2430aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 24311da177e4SLinus Torvalds return rc; 24321da177e4SLinus Torvalds } 24331da177e4SLinus Torvalds 24341da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) 24351da177e4SLinus Torvalds { 24361da177e4SLinus Torvalds int i, fail = 0; 24371da177e4SLinus Torvalds 24381da177e4SLinus Torvalds for (i = 0; i < 4; i++) 24391da177e4SLinus Torvalds if (addr[i] != (input[i] & mask[i])) { 24401da177e4SLinus Torvalds fail = 1; 24411da177e4SLinus Torvalds break; 24421da177e4SLinus Torvalds } 24431da177e4SLinus Torvalds 24441da177e4SLinus Torvalds return !fail; 24451da177e4SLinus Torvalds } 24461da177e4SLinus Torvalds 24471da177e4SLinus Torvalds /** 24481da177e4SLinus Torvalds * security_node_sid - Obtain the SID for a node (host). 24491da177e4SLinus Torvalds * @domain: communication domain aka address family 24501da177e4SLinus Torvalds * @addrp: address 24511da177e4SLinus Torvalds * @addrlen: address length in bytes 24521da177e4SLinus Torvalds * @out_sid: security identifier 24531da177e4SLinus Torvalds */ 2454aa8e712cSStephen Smalley int security_node_sid(struct selinux_state *state, 2455aa8e712cSStephen Smalley u16 domain, 24561da177e4SLinus Torvalds void *addrp, 24571da177e4SLinus Torvalds u32 addrlen, 24581da177e4SLinus Torvalds u32 *out_sid) 24591da177e4SLinus Torvalds { 2460aa8e712cSStephen Smalley struct policydb *policydb; 2461aa8e712cSStephen Smalley struct sidtab *sidtab; 24624b02b524SEric Paris int rc; 24631da177e4SLinus Torvalds struct ocontext *c; 24641da177e4SLinus Torvalds 2465aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 2466aa8e712cSStephen Smalley 2467aa8e712cSStephen Smalley policydb = &state->ss->policydb; 246824ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 24691da177e4SLinus Torvalds 24701da177e4SLinus Torvalds switch (domain) { 24711da177e4SLinus Torvalds case AF_INET: { 24721da177e4SLinus Torvalds u32 addr; 24731da177e4SLinus Torvalds 24741da177e4SLinus Torvalds rc = -EINVAL; 24754b02b524SEric Paris if (addrlen != sizeof(u32)) 24761da177e4SLinus Torvalds goto out; 24771da177e4SLinus Torvalds 24781da177e4SLinus Torvalds addr = *((u32 *)addrp); 24791da177e4SLinus Torvalds 2480aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_NODE]; 24811da177e4SLinus Torvalds while (c) { 24821da177e4SLinus Torvalds if (c->u.node.addr == (addr & c->u.node.mask)) 24831da177e4SLinus Torvalds break; 24841da177e4SLinus Torvalds c = c->next; 24851da177e4SLinus Torvalds } 24861da177e4SLinus Torvalds break; 24871da177e4SLinus Torvalds } 24881da177e4SLinus Torvalds 24891da177e4SLinus Torvalds case AF_INET6: 24901da177e4SLinus Torvalds rc = -EINVAL; 24914b02b524SEric Paris if (addrlen != sizeof(u64) * 2) 24921da177e4SLinus Torvalds goto out; 2493aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_NODE6]; 24941da177e4SLinus Torvalds while (c) { 24951da177e4SLinus Torvalds if (match_ipv6_addrmask(addrp, c->u.node6.addr, 24961da177e4SLinus Torvalds c->u.node6.mask)) 24971da177e4SLinus Torvalds break; 24981da177e4SLinus Torvalds c = c->next; 24991da177e4SLinus Torvalds } 25001da177e4SLinus Torvalds break; 25011da177e4SLinus Torvalds 25021da177e4SLinus Torvalds default: 25034b02b524SEric Paris rc = 0; 25041da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 25051da177e4SLinus Torvalds goto out; 25061da177e4SLinus Torvalds } 25071da177e4SLinus Torvalds 25081da177e4SLinus Torvalds if (c) { 25091da177e4SLinus Torvalds if (!c->sid[0]) { 2510aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, 25111da177e4SLinus Torvalds &c->context[0], 25121da177e4SLinus Torvalds &c->sid[0]); 25131da177e4SLinus Torvalds if (rc) 25141da177e4SLinus Torvalds goto out; 25151da177e4SLinus Torvalds } 25161da177e4SLinus Torvalds *out_sid = c->sid[0]; 25171da177e4SLinus Torvalds } else { 25181da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 25191da177e4SLinus Torvalds } 25201da177e4SLinus Torvalds 25214b02b524SEric Paris rc = 0; 25221da177e4SLinus Torvalds out: 2523aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 25241da177e4SLinus Torvalds return rc; 25251da177e4SLinus Torvalds } 25261da177e4SLinus Torvalds 25271da177e4SLinus Torvalds #define SIDS_NEL 25 25281da177e4SLinus Torvalds 25291da177e4SLinus Torvalds /** 25301da177e4SLinus Torvalds * security_get_user_sids - Obtain reachable SIDs for a user. 25311da177e4SLinus Torvalds * @fromsid: starting SID 25321da177e4SLinus Torvalds * @username: username 25331da177e4SLinus Torvalds * @sids: array of reachable SIDs for user 25341da177e4SLinus Torvalds * @nel: number of elements in @sids 25351da177e4SLinus Torvalds * 25361da177e4SLinus Torvalds * Generate the set of SIDs for legal security contexts 25371da177e4SLinus Torvalds * for a given user that can be reached by @fromsid. 25381da177e4SLinus Torvalds * Set *@sids to point to a dynamically allocated 25391da177e4SLinus Torvalds * array containing the set of SIDs. Set *@nel to the 25401da177e4SLinus Torvalds * number of elements in the array. 25411da177e4SLinus Torvalds */ 25421da177e4SLinus Torvalds 2543aa8e712cSStephen Smalley int security_get_user_sids(struct selinux_state *state, 2544aa8e712cSStephen Smalley u32 fromsid, 25451da177e4SLinus Torvalds char *username, 25461da177e4SLinus Torvalds u32 **sids, 25471da177e4SLinus Torvalds u32 *nel) 25481da177e4SLinus Torvalds { 2549aa8e712cSStephen Smalley struct policydb *policydb; 2550aa8e712cSStephen Smalley struct sidtab *sidtab; 25511da177e4SLinus Torvalds struct context *fromcon, usercon; 25522c3c05dbSStephen Smalley u32 *mysids = NULL, *mysids2, sid; 25531da177e4SLinus Torvalds u32 mynel = 0, maxnel = SIDS_NEL; 25541da177e4SLinus Torvalds struct user_datum *user; 25551da177e4SLinus Torvalds struct role_datum *role; 2556782ebb99SStephen Smalley struct ebitmap_node *rnode, *tnode; 25571da177e4SLinus Torvalds int rc = 0, i, j; 25581da177e4SLinus Torvalds 25591da177e4SLinus Torvalds *sids = NULL; 25601da177e4SLinus Torvalds *nel = 0; 25612c3c05dbSStephen Smalley 2562aa8e712cSStephen Smalley if (!state->initialized) 25631da177e4SLinus Torvalds goto out; 25641da177e4SLinus Torvalds 2565aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 2566aa8e712cSStephen Smalley 2567aa8e712cSStephen Smalley policydb = &state->ss->policydb; 256824ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 25691da177e4SLinus Torvalds 257012b29f34SStephen Smalley context_init(&usercon); 257112b29f34SStephen Smalley 25724b02b524SEric Paris rc = -EINVAL; 2573aa8e712cSStephen Smalley fromcon = sidtab_search(sidtab, fromsid); 25744b02b524SEric Paris if (!fromcon) 25751da177e4SLinus Torvalds goto out_unlock; 25761da177e4SLinus Torvalds 25771da177e4SLinus Torvalds rc = -EINVAL; 2578aa8e712cSStephen Smalley user = hashtab_search(policydb->p_users.table, username); 25794b02b524SEric Paris if (!user) 25801da177e4SLinus Torvalds goto out_unlock; 25814b02b524SEric Paris 25821da177e4SLinus Torvalds usercon.user = user->value; 25831da177e4SLinus Torvalds 25841da177e4SLinus Torvalds rc = -ENOMEM; 25854b02b524SEric Paris mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC); 25864b02b524SEric Paris if (!mysids) 25871da177e4SLinus Torvalds goto out_unlock; 25881da177e4SLinus Torvalds 25899fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&user->roles, rnode, i) { 2590aa8e712cSStephen Smalley role = policydb->role_val_to_struct[i]; 25911da177e4SLinus Torvalds usercon.role = i + 1; 25929fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&role->types, tnode, j) { 25931da177e4SLinus Torvalds usercon.type = j + 1; 25941da177e4SLinus Torvalds 2595aa8e712cSStephen Smalley if (mls_setup_user_range(policydb, fromcon, user, 2596aa8e712cSStephen Smalley &usercon)) 25971da177e4SLinus Torvalds continue; 25981da177e4SLinus Torvalds 2599aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, &usercon, &sid); 26002c3c05dbSStephen Smalley if (rc) 26011da177e4SLinus Torvalds goto out_unlock; 26021da177e4SLinus Torvalds if (mynel < maxnel) { 26031da177e4SLinus Torvalds mysids[mynel++] = sid; 26041da177e4SLinus Torvalds } else { 26054b02b524SEric Paris rc = -ENOMEM; 26061da177e4SLinus Torvalds maxnel += SIDS_NEL; 260789d155efSJames Morris mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); 26084b02b524SEric Paris if (!mysids2) 26091da177e4SLinus Torvalds goto out_unlock; 26101da177e4SLinus Torvalds memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); 26111da177e4SLinus Torvalds kfree(mysids); 26121da177e4SLinus Torvalds mysids = mysids2; 26131da177e4SLinus Torvalds mysids[mynel++] = sid; 26141da177e4SLinus Torvalds } 26151da177e4SLinus Torvalds } 26161da177e4SLinus Torvalds } 26174b02b524SEric Paris rc = 0; 26181da177e4SLinus Torvalds out_unlock: 2619aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 26202c3c05dbSStephen Smalley if (rc || !mynel) { 26212c3c05dbSStephen Smalley kfree(mysids); 26222c3c05dbSStephen Smalley goto out; 26232c3c05dbSStephen Smalley } 26242c3c05dbSStephen Smalley 26254b02b524SEric Paris rc = -ENOMEM; 26262c3c05dbSStephen Smalley mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL); 26272c3c05dbSStephen Smalley if (!mysids2) { 26282c3c05dbSStephen Smalley kfree(mysids); 26292c3c05dbSStephen Smalley goto out; 26302c3c05dbSStephen Smalley } 26312c3c05dbSStephen Smalley for (i = 0, j = 0; i < mynel; i++) { 2632f01e1af4SLinus Torvalds struct av_decision dummy_avd; 26336b6bc620SStephen Smalley rc = avc_has_perm_noaudit(state, 26346b6bc620SStephen Smalley fromsid, mysids[i], 2635c6d3aaa4SStephen Smalley SECCLASS_PROCESS, /* kernel value */ 26362c3c05dbSStephen Smalley PROCESS__TRANSITION, AVC_STRICT, 2637f01e1af4SLinus Torvalds &dummy_avd); 26382c3c05dbSStephen Smalley if (!rc) 26392c3c05dbSStephen Smalley mysids2[j++] = mysids[i]; 26402c3c05dbSStephen Smalley cond_resched(); 26412c3c05dbSStephen Smalley } 26422c3c05dbSStephen Smalley rc = 0; 26432c3c05dbSStephen Smalley kfree(mysids); 26442c3c05dbSStephen Smalley *sids = mysids2; 26452c3c05dbSStephen Smalley *nel = j; 26461da177e4SLinus Torvalds out: 26471da177e4SLinus Torvalds return rc; 26481da177e4SLinus Torvalds } 26491da177e4SLinus Torvalds 26501da177e4SLinus Torvalds /** 2651f31e7994SWaiman Long * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem 26521da177e4SLinus Torvalds * @fstype: filesystem type 26531da177e4SLinus Torvalds * @path: path from root of mount 26541da177e4SLinus Torvalds * @sclass: file security class 26551da177e4SLinus Torvalds * @sid: SID for path 26561da177e4SLinus Torvalds * 26571da177e4SLinus Torvalds * Obtain a SID to use for a file in a filesystem that 26581da177e4SLinus Torvalds * cannot support xattr or use a fixed labeling behavior like 26591da177e4SLinus Torvalds * transition SIDs or task SIDs. 2660f31e7994SWaiman Long * 2661f31e7994SWaiman Long * The caller must acquire the policy_rwlock before calling this function. 26621da177e4SLinus Torvalds */ 2663aa8e712cSStephen Smalley static inline int __security_genfs_sid(struct selinux_state *state, 2664aa8e712cSStephen Smalley const char *fstype, 26651da177e4SLinus Torvalds char *path, 2666c6d3aaa4SStephen Smalley u16 orig_sclass, 26671da177e4SLinus Torvalds u32 *sid) 26681da177e4SLinus Torvalds { 2669aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 267024ed7fdaSOndrej Mosnacek struct sidtab *sidtab = state->ss->sidtab; 26711da177e4SLinus Torvalds int len; 2672c6d3aaa4SStephen Smalley u16 sclass; 26731da177e4SLinus Torvalds struct genfs *genfs; 26741da177e4SLinus Torvalds struct ocontext *c; 26754b02b524SEric Paris int rc, cmp = 0; 26761da177e4SLinus Torvalds 2677b1aa5301SStephen Smalley while (path[0] == '/' && path[1] == '/') 2678b1aa5301SStephen Smalley path++; 2679b1aa5301SStephen Smalley 2680aa8e712cSStephen Smalley sclass = unmap_class(&state->ss->map, orig_sclass); 26814b02b524SEric Paris *sid = SECINITSID_UNLABELED; 2682c6d3aaa4SStephen Smalley 2683aa8e712cSStephen Smalley for (genfs = policydb->genfs; genfs; genfs = genfs->next) { 26841da177e4SLinus Torvalds cmp = strcmp(fstype, genfs->fstype); 26851da177e4SLinus Torvalds if (cmp <= 0) 26861da177e4SLinus Torvalds break; 26871da177e4SLinus Torvalds } 26881da177e4SLinus Torvalds 26891da177e4SLinus Torvalds rc = -ENOENT; 26904b02b524SEric Paris if (!genfs || cmp) 26911da177e4SLinus Torvalds goto out; 26921da177e4SLinus Torvalds 26931da177e4SLinus Torvalds for (c = genfs->head; c; c = c->next) { 26941da177e4SLinus Torvalds len = strlen(c->u.name); 26951da177e4SLinus Torvalds if ((!c->v.sclass || sclass == c->v.sclass) && 26961da177e4SLinus Torvalds (strncmp(c->u.name, path, len) == 0)) 26971da177e4SLinus Torvalds break; 26981da177e4SLinus Torvalds } 26991da177e4SLinus Torvalds 27001da177e4SLinus Torvalds rc = -ENOENT; 27014b02b524SEric Paris if (!c) 27021da177e4SLinus Torvalds goto out; 27031da177e4SLinus Torvalds 27041da177e4SLinus Torvalds if (!c->sid[0]) { 2705aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]); 27061da177e4SLinus Torvalds if (rc) 27071da177e4SLinus Torvalds goto out; 27081da177e4SLinus Torvalds } 27091da177e4SLinus Torvalds 27101da177e4SLinus Torvalds *sid = c->sid[0]; 27114b02b524SEric Paris rc = 0; 27121da177e4SLinus Torvalds out: 27131da177e4SLinus Torvalds return rc; 27141da177e4SLinus Torvalds } 27151da177e4SLinus Torvalds 27161da177e4SLinus Torvalds /** 2717f31e7994SWaiman Long * security_genfs_sid - Obtain a SID for a file in a filesystem 2718f31e7994SWaiman Long * @fstype: filesystem type 2719f31e7994SWaiman Long * @path: path from root of mount 2720f31e7994SWaiman Long * @sclass: file security class 2721f31e7994SWaiman Long * @sid: SID for path 2722f31e7994SWaiman Long * 2723f31e7994SWaiman Long * Acquire policy_rwlock before calling __security_genfs_sid() and release 2724f31e7994SWaiman Long * it afterward. 2725f31e7994SWaiman Long */ 2726aa8e712cSStephen Smalley int security_genfs_sid(struct selinux_state *state, 2727aa8e712cSStephen Smalley const char *fstype, 2728f31e7994SWaiman Long char *path, 2729f31e7994SWaiman Long u16 orig_sclass, 2730f31e7994SWaiman Long u32 *sid) 2731f31e7994SWaiman Long { 2732f31e7994SWaiman Long int retval; 2733f31e7994SWaiman Long 2734aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 2735aa8e712cSStephen Smalley retval = __security_genfs_sid(state, fstype, path, orig_sclass, sid); 2736aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 2737f31e7994SWaiman Long return retval; 2738f31e7994SWaiman Long } 2739f31e7994SWaiman Long 2740f31e7994SWaiman Long /** 27411da177e4SLinus Torvalds * security_fs_use - Determine how to handle labeling for a filesystem. 2742a64c54cfSEric Paris * @sb: superblock in question 27431da177e4SLinus Torvalds */ 2744aa8e712cSStephen Smalley int security_fs_use(struct selinux_state *state, struct super_block *sb) 27451da177e4SLinus Torvalds { 2746aa8e712cSStephen Smalley struct policydb *policydb; 2747aa8e712cSStephen Smalley struct sidtab *sidtab; 27481da177e4SLinus Torvalds int rc = 0; 27491da177e4SLinus Torvalds struct ocontext *c; 2750a64c54cfSEric Paris struct superblock_security_struct *sbsec = sb->s_security; 2751a64c54cfSEric Paris const char *fstype = sb->s_type->name; 27521da177e4SLinus Torvalds 2753aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 27541da177e4SLinus Torvalds 2755aa8e712cSStephen Smalley policydb = &state->ss->policydb; 275624ed7fdaSOndrej Mosnacek sidtab = state->ss->sidtab; 2757aa8e712cSStephen Smalley 2758aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_FSUSE]; 27594d546f81SPaul Moore while (c) { 27604d546f81SPaul Moore if (strcmp(fstype, c->u.name) == 0) 27611da177e4SLinus Torvalds break; 27624d546f81SPaul Moore c = c->next; 27631da177e4SLinus Torvalds } 27641da177e4SLinus Torvalds 27651da177e4SLinus Torvalds if (c) { 2766a64c54cfSEric Paris sbsec->behavior = c->v.behavior; 27671da177e4SLinus Torvalds if (!c->sid[0]) { 2768aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, &c->context[0], 27691da177e4SLinus Torvalds &c->sid[0]); 27701da177e4SLinus Torvalds if (rc) 27711da177e4SLinus Torvalds goto out; 27721da177e4SLinus Torvalds } 2773a64c54cfSEric Paris sbsec->sid = c->sid[0]; 2774089be43eSJames Morris } else { 2775aa8e712cSStephen Smalley rc = __security_genfs_sid(state, fstype, "/", SECCLASS_DIR, 2776f31e7994SWaiman Long &sbsec->sid); 27771da177e4SLinus Torvalds if (rc) { 2778a64c54cfSEric Paris sbsec->behavior = SECURITY_FS_USE_NONE; 27791da177e4SLinus Torvalds rc = 0; 27801da177e4SLinus Torvalds } else { 2781a64c54cfSEric Paris sbsec->behavior = SECURITY_FS_USE_GENFS; 27821da177e4SLinus Torvalds } 2783089be43eSJames Morris } 27841da177e4SLinus Torvalds 27851da177e4SLinus Torvalds out: 2786aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 27871da177e4SLinus Torvalds return rc; 27881da177e4SLinus Torvalds } 27891da177e4SLinus Torvalds 2790aa8e712cSStephen Smalley int security_get_bools(struct selinux_state *state, 2791aa8e712cSStephen Smalley int *len, char ***names, int **values) 27921da177e4SLinus Torvalds { 2793aa8e712cSStephen Smalley struct policydb *policydb; 27944b02b524SEric Paris int i, rc; 27951da177e4SLinus Torvalds 2796274f62e1SStephen Smalley if (!state->initialized) { 2797274f62e1SStephen Smalley *len = 0; 2798274f62e1SStephen Smalley *names = NULL; 2799274f62e1SStephen Smalley *values = NULL; 2800274f62e1SStephen Smalley return 0; 2801274f62e1SStephen Smalley } 2802274f62e1SStephen Smalley 2803aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 2804aa8e712cSStephen Smalley 2805aa8e712cSStephen Smalley policydb = &state->ss->policydb; 2806aa8e712cSStephen Smalley 28071da177e4SLinus Torvalds *names = NULL; 28081da177e4SLinus Torvalds *values = NULL; 28091da177e4SLinus Torvalds 28101da177e4SLinus Torvalds rc = 0; 2811aa8e712cSStephen Smalley *len = policydb->p_bools.nprim; 28124b02b524SEric Paris if (!*len) 28131da177e4SLinus Torvalds goto out; 28141da177e4SLinus Torvalds 28154b02b524SEric Paris rc = -ENOMEM; 2816e0795cf4SJesper Juhl *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); 28171da177e4SLinus Torvalds if (!*names) 28181da177e4SLinus Torvalds goto err; 28191da177e4SLinus Torvalds 28204b02b524SEric Paris rc = -ENOMEM; 2821e0795cf4SJesper Juhl *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); 28221da177e4SLinus Torvalds if (!*values) 28231da177e4SLinus Torvalds goto err; 28241da177e4SLinus Torvalds 28251da177e4SLinus Torvalds for (i = 0; i < *len; i++) { 2826aa8e712cSStephen Smalley (*values)[i] = policydb->bool_val_to_struct[i]->state; 28274b02b524SEric Paris 28284b02b524SEric Paris rc = -ENOMEM; 2829aa8e712cSStephen Smalley (*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i), 2830aa8e712cSStephen Smalley GFP_ATOMIC); 28311da177e4SLinus Torvalds if (!(*names)[i]) 28321da177e4SLinus Torvalds goto err; 28331da177e4SLinus Torvalds } 28341da177e4SLinus Torvalds rc = 0; 28351da177e4SLinus Torvalds out: 2836aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 28371da177e4SLinus Torvalds return rc; 28381da177e4SLinus Torvalds err: 28391da177e4SLinus Torvalds if (*names) { 28401da177e4SLinus Torvalds for (i = 0; i < *len; i++) 28411da177e4SLinus Torvalds kfree((*names)[i]); 28421da177e4SLinus Torvalds } 28431da177e4SLinus Torvalds kfree(*values); 28441da177e4SLinus Torvalds goto out; 28451da177e4SLinus Torvalds } 28461da177e4SLinus Torvalds 28471da177e4SLinus Torvalds 2848aa8e712cSStephen Smalley int security_set_bools(struct selinux_state *state, int len, int *values) 28491da177e4SLinus Torvalds { 2850aa8e712cSStephen Smalley struct policydb *policydb; 28514b02b524SEric Paris int i, rc; 28521da177e4SLinus Torvalds int lenp, seqno = 0; 28531da177e4SLinus Torvalds struct cond_node *cur; 28541da177e4SLinus Torvalds 2855aa8e712cSStephen Smalley write_lock_irq(&state->ss->policy_rwlock); 2856aa8e712cSStephen Smalley 2857aa8e712cSStephen Smalley policydb = &state->ss->policydb; 28581da177e4SLinus Torvalds 28591da177e4SLinus Torvalds rc = -EFAULT; 2860aa8e712cSStephen Smalley lenp = policydb->p_bools.nprim; 28614b02b524SEric Paris if (len != lenp) 28621da177e4SLinus Torvalds goto out; 28631da177e4SLinus Torvalds 28641da177e4SLinus Torvalds for (i = 0; i < len; i++) { 2865aa8e712cSStephen Smalley if (!!values[i] != policydb->bool_val_to_struct[i]->state) { 2866cdfb6b34SRichard Guy Briggs audit_log(audit_context(), GFP_ATOMIC, 2867af601e46SSteve Grubb AUDIT_MAC_CONFIG_CHANGE, 28684746ec5bSEric Paris "bool=%s val=%d old_val=%d auid=%u ses=%u", 2869aa8e712cSStephen Smalley sym_name(policydb, SYM_BOOLS, i), 2870af601e46SSteve Grubb !!values[i], 2871aa8e712cSStephen Smalley policydb->bool_val_to_struct[i]->state, 2872581abc09SEric W. Biederman from_kuid(&init_user_ns, audit_get_loginuid(current)), 28734746ec5bSEric Paris audit_get_sessionid(current)); 2874af601e46SSteve Grubb } 28755d55a345SEric Paris if (values[i]) 2876aa8e712cSStephen Smalley policydb->bool_val_to_struct[i]->state = 1; 28775d55a345SEric Paris else 2878aa8e712cSStephen Smalley policydb->bool_val_to_struct[i]->state = 0; 28791da177e4SLinus Torvalds } 28801da177e4SLinus Torvalds 2881aa8e712cSStephen Smalley for (cur = policydb->cond_list; cur; cur = cur->next) { 2882aa8e712cSStephen Smalley rc = evaluate_cond_node(policydb, cur); 28831da177e4SLinus Torvalds if (rc) 28841da177e4SLinus Torvalds goto out; 28851da177e4SLinus Torvalds } 28861da177e4SLinus Torvalds 2887aa8e712cSStephen Smalley seqno = ++state->ss->latest_granting; 28884b02b524SEric Paris rc = 0; 28891da177e4SLinus Torvalds out: 2890aa8e712cSStephen Smalley write_unlock_irq(&state->ss->policy_rwlock); 28911da177e4SLinus Torvalds if (!rc) { 28926b6bc620SStephen Smalley avc_ss_reset(state->avc, seqno); 28931da177e4SLinus Torvalds selnl_notify_policyload(seqno); 2894aa8e712cSStephen Smalley selinux_status_update_policyload(state, seqno); 2895342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 28961da177e4SLinus Torvalds } 28971da177e4SLinus Torvalds return rc; 28981da177e4SLinus Torvalds } 28991da177e4SLinus Torvalds 2900aa8e712cSStephen Smalley int security_get_bool_value(struct selinux_state *state, 2901aa8e712cSStephen Smalley int index) 29021da177e4SLinus Torvalds { 2903aa8e712cSStephen Smalley struct policydb *policydb; 29044b02b524SEric Paris int rc; 29051da177e4SLinus Torvalds int len; 29061da177e4SLinus Torvalds 2907aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 2908aa8e712cSStephen Smalley 2909aa8e712cSStephen Smalley policydb = &state->ss->policydb; 29101da177e4SLinus Torvalds 29111da177e4SLinus Torvalds rc = -EFAULT; 2912aa8e712cSStephen Smalley len = policydb->p_bools.nprim; 29130fd71a62SPrarit Bhargava if (index >= len) 29141da177e4SLinus Torvalds goto out; 29151da177e4SLinus Torvalds 2916aa8e712cSStephen Smalley rc = policydb->bool_val_to_struct[index]->state; 29171da177e4SLinus Torvalds out: 2918aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 29191da177e4SLinus Torvalds return rc; 29201da177e4SLinus Torvalds } 2921376bd9cbSDarrel Goeddel 2922aa8e712cSStephen Smalley static int security_preserve_bools(struct selinux_state *state, 2923aa8e712cSStephen Smalley struct policydb *policydb) 2924e900a7d9SStephen Smalley { 2925e900a7d9SStephen Smalley int rc, nbools = 0, *bvalues = NULL, i; 2926e900a7d9SStephen Smalley char **bnames = NULL; 2927e900a7d9SStephen Smalley struct cond_bool_datum *booldatum; 2928e900a7d9SStephen Smalley struct cond_node *cur; 2929e900a7d9SStephen Smalley 2930aa8e712cSStephen Smalley rc = security_get_bools(state, &nbools, &bnames, &bvalues); 2931e900a7d9SStephen Smalley if (rc) 2932e900a7d9SStephen Smalley goto out; 2933e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) { 2934aa8e712cSStephen Smalley booldatum = hashtab_search(policydb->p_bools.table, bnames[i]); 2935e900a7d9SStephen Smalley if (booldatum) 2936e900a7d9SStephen Smalley booldatum->state = bvalues[i]; 2937e900a7d9SStephen Smalley } 2938aa8e712cSStephen Smalley for (cur = policydb->cond_list; cur; cur = cur->next) { 2939aa8e712cSStephen Smalley rc = evaluate_cond_node(policydb, cur); 2940e900a7d9SStephen Smalley if (rc) 2941e900a7d9SStephen Smalley goto out; 2942e900a7d9SStephen Smalley } 2943e900a7d9SStephen Smalley 2944e900a7d9SStephen Smalley out: 2945e900a7d9SStephen Smalley if (bnames) { 2946e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) 2947e900a7d9SStephen Smalley kfree(bnames[i]); 2948e900a7d9SStephen Smalley } 2949e900a7d9SStephen Smalley kfree(bnames); 2950e900a7d9SStephen Smalley kfree(bvalues); 2951e900a7d9SStephen Smalley return rc; 2952e900a7d9SStephen Smalley } 2953e900a7d9SStephen Smalley 295408554d6bSVenkat Yekkirala /* 295508554d6bSVenkat Yekkirala * security_sid_mls_copy() - computes a new sid based on the given 295608554d6bSVenkat Yekkirala * sid and the mls portion of mls_sid. 295708554d6bSVenkat Yekkirala */ 2958aa8e712cSStephen Smalley int security_sid_mls_copy(struct selinux_state *state, 2959aa8e712cSStephen Smalley u32 sid, u32 mls_sid, u32 *new_sid) 296008554d6bSVenkat Yekkirala { 2961aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 296224ed7fdaSOndrej Mosnacek struct sidtab *sidtab = state->ss->sidtab; 296308554d6bSVenkat Yekkirala struct context *context1; 296408554d6bSVenkat Yekkirala struct context *context2; 296508554d6bSVenkat Yekkirala struct context newcon; 296608554d6bSVenkat Yekkirala char *s; 296708554d6bSVenkat Yekkirala u32 len; 29684b02b524SEric Paris int rc; 296908554d6bSVenkat Yekkirala 29704b02b524SEric Paris rc = 0; 2971aa8e712cSStephen Smalley if (!state->initialized || !policydb->mls_enabled) { 297208554d6bSVenkat Yekkirala *new_sid = sid; 297308554d6bSVenkat Yekkirala goto out; 297408554d6bSVenkat Yekkirala } 297508554d6bSVenkat Yekkirala 297608554d6bSVenkat Yekkirala context_init(&newcon); 297708554d6bSVenkat Yekkirala 2978aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 29794b02b524SEric Paris 29804b02b524SEric Paris rc = -EINVAL; 2981aa8e712cSStephen Smalley context1 = sidtab_search(sidtab, sid); 298208554d6bSVenkat Yekkirala if (!context1) { 2983b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 2984744ba35eSEric Paris __func__, sid); 298508554d6bSVenkat Yekkirala goto out_unlock; 298608554d6bSVenkat Yekkirala } 298708554d6bSVenkat Yekkirala 29884b02b524SEric Paris rc = -EINVAL; 2989aa8e712cSStephen Smalley context2 = sidtab_search(sidtab, mls_sid); 299008554d6bSVenkat Yekkirala if (!context2) { 2991b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 2992744ba35eSEric Paris __func__, mls_sid); 299308554d6bSVenkat Yekkirala goto out_unlock; 299408554d6bSVenkat Yekkirala } 299508554d6bSVenkat Yekkirala 299608554d6bSVenkat Yekkirala newcon.user = context1->user; 299708554d6bSVenkat Yekkirala newcon.role = context1->role; 299808554d6bSVenkat Yekkirala newcon.type = context1->type; 29990efc61eaSVenkat Yekkirala rc = mls_context_cpy(&newcon, context2); 300008554d6bSVenkat Yekkirala if (rc) 300108554d6bSVenkat Yekkirala goto out_unlock; 300208554d6bSVenkat Yekkirala 300308554d6bSVenkat Yekkirala /* Check the validity of the new context. */ 3004aa8e712cSStephen Smalley if (!policydb_context_isvalid(policydb, &newcon)) { 3005aa8e712cSStephen Smalley rc = convert_context_handle_invalid_context(state, &newcon); 30064b02b524SEric Paris if (rc) { 3007aa8e712cSStephen Smalley if (!context_struct_to_string(policydb, &newcon, &s, 3008aa8e712cSStephen Smalley &len)) { 3009ea74a685SRichard Guy Briggs struct audit_buffer *ab; 3010ea74a685SRichard Guy Briggs 3011ea74a685SRichard Guy Briggs ab = audit_log_start(audit_context(), 3012ea74a685SRichard Guy Briggs GFP_ATOMIC, 3013ea74a685SRichard Guy Briggs AUDIT_SELINUX_ERR); 3014ea74a685SRichard Guy Briggs audit_log_format(ab, 3015ea74a685SRichard Guy Briggs "op=security_sid_mls_copy invalid_context="); 3016ea74a685SRichard Guy Briggs /* don't record NUL with untrusted strings */ 3017ea74a685SRichard Guy Briggs audit_log_n_untrustedstring(ab, s, len - 1); 3018ea74a685SRichard Guy Briggs audit_log_end(ab); 301908554d6bSVenkat Yekkirala kfree(s); 302008554d6bSVenkat Yekkirala } 30214b02b524SEric Paris goto out_unlock; 30224b02b524SEric Paris } 30234b02b524SEric Paris } 302408554d6bSVenkat Yekkirala 3025aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, &newcon, new_sid); 302608554d6bSVenkat Yekkirala out_unlock: 3027aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 302808554d6bSVenkat Yekkirala context_destroy(&newcon); 302908554d6bSVenkat Yekkirala out: 303008554d6bSVenkat Yekkirala return rc; 303108554d6bSVenkat Yekkirala } 303208554d6bSVenkat Yekkirala 3033220deb96SPaul Moore /** 3034220deb96SPaul Moore * security_net_peersid_resolve - Compare and resolve two network peer SIDs 3035220deb96SPaul Moore * @nlbl_sid: NetLabel SID 3036220deb96SPaul Moore * @nlbl_type: NetLabel labeling protocol type 3037220deb96SPaul Moore * @xfrm_sid: XFRM SID 3038220deb96SPaul Moore * 3039220deb96SPaul Moore * Description: 3040220deb96SPaul Moore * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be 3041220deb96SPaul Moore * resolved into a single SID it is returned via @peer_sid and the function 3042220deb96SPaul Moore * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function 3043220deb96SPaul Moore * returns a negative value. A table summarizing the behavior is below: 3044220deb96SPaul Moore * 3045220deb96SPaul Moore * | function return | @sid 3046220deb96SPaul Moore * ------------------------------+-----------------+----------------- 3047220deb96SPaul Moore * no peer labels | 0 | SECSID_NULL 3048220deb96SPaul Moore * single peer label | 0 | <peer_label> 3049220deb96SPaul Moore * multiple, consistent labels | 0 | <peer_label> 3050220deb96SPaul Moore * multiple, inconsistent labels | -<errno> | SECSID_NULL 3051220deb96SPaul Moore * 3052220deb96SPaul Moore */ 3053aa8e712cSStephen Smalley int security_net_peersid_resolve(struct selinux_state *state, 3054aa8e712cSStephen Smalley u32 nlbl_sid, u32 nlbl_type, 3055220deb96SPaul Moore u32 xfrm_sid, 3056220deb96SPaul Moore u32 *peer_sid) 3057220deb96SPaul Moore { 3058aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 305924ed7fdaSOndrej Mosnacek struct sidtab *sidtab = state->ss->sidtab; 3060220deb96SPaul Moore int rc; 3061220deb96SPaul Moore struct context *nlbl_ctx; 3062220deb96SPaul Moore struct context *xfrm_ctx; 3063220deb96SPaul Moore 30644b02b524SEric Paris *peer_sid = SECSID_NULL; 30654b02b524SEric Paris 3066220deb96SPaul Moore /* handle the common (which also happens to be the set of easy) cases 3067220deb96SPaul Moore * right away, these two if statements catch everything involving a 3068220deb96SPaul Moore * single or absent peer SID/label */ 3069220deb96SPaul Moore if (xfrm_sid == SECSID_NULL) { 3070220deb96SPaul Moore *peer_sid = nlbl_sid; 3071220deb96SPaul Moore return 0; 3072220deb96SPaul Moore } 3073220deb96SPaul Moore /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label 3074220deb96SPaul Moore * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label 3075220deb96SPaul Moore * is present */ 3076220deb96SPaul Moore if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) { 3077220deb96SPaul Moore *peer_sid = xfrm_sid; 3078220deb96SPaul Moore return 0; 3079220deb96SPaul Moore } 3080220deb96SPaul Moore 3081aa8e712cSStephen Smalley /* 3082aa8e712cSStephen Smalley * We don't need to check initialized here since the only way both 3083220deb96SPaul Moore * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the 3084aa8e712cSStephen Smalley * security server was initialized and state->initialized was true. 3085aa8e712cSStephen Smalley */ 3086aa8e712cSStephen Smalley if (!policydb->mls_enabled) 3087220deb96SPaul Moore return 0; 3088220deb96SPaul Moore 3089aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 3090220deb96SPaul Moore 30914b02b524SEric Paris rc = -EINVAL; 3092aa8e712cSStephen Smalley nlbl_ctx = sidtab_search(sidtab, nlbl_sid); 3093220deb96SPaul Moore if (!nlbl_ctx) { 3094b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 3095744ba35eSEric Paris __func__, nlbl_sid); 30964b02b524SEric Paris goto out; 3097220deb96SPaul Moore } 30984b02b524SEric Paris rc = -EINVAL; 3099aa8e712cSStephen Smalley xfrm_ctx = sidtab_search(sidtab, xfrm_sid); 3100220deb96SPaul Moore if (!xfrm_ctx) { 3101b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n", 3102744ba35eSEric Paris __func__, xfrm_sid); 31034b02b524SEric Paris goto out; 3104220deb96SPaul Moore } 3105220deb96SPaul Moore rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); 31064b02b524SEric Paris if (rc) 31074b02b524SEric Paris goto out; 3108220deb96SPaul Moore 3109220deb96SPaul Moore /* at present NetLabel SIDs/labels really only carry MLS 3110220deb96SPaul Moore * information so if the MLS portion of the NetLabel SID 3111220deb96SPaul Moore * matches the MLS portion of the labeled XFRM SID/label 3112220deb96SPaul Moore * then pass along the XFRM SID as it is the most 3113220deb96SPaul Moore * expressive */ 3114220deb96SPaul Moore *peer_sid = xfrm_sid; 31154b02b524SEric Paris out: 3116aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 3117220deb96SPaul Moore return rc; 3118220deb96SPaul Moore } 3119220deb96SPaul Moore 312055fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args) 312155fcf09bSChristopher J. PeBenito { 312255fcf09bSChristopher J. PeBenito struct class_datum *datum = d; 312355fcf09bSChristopher J. PeBenito char *name = k, **classes = args; 312455fcf09bSChristopher J. PeBenito int value = datum->value - 1; 312555fcf09bSChristopher J. PeBenito 312655fcf09bSChristopher J. PeBenito classes[value] = kstrdup(name, GFP_ATOMIC); 312755fcf09bSChristopher J. PeBenito if (!classes[value]) 312855fcf09bSChristopher J. PeBenito return -ENOMEM; 312955fcf09bSChristopher J. PeBenito 313055fcf09bSChristopher J. PeBenito return 0; 313155fcf09bSChristopher J. PeBenito } 313255fcf09bSChristopher J. PeBenito 3133aa8e712cSStephen Smalley int security_get_classes(struct selinux_state *state, 3134aa8e712cSStephen Smalley char ***classes, int *nclasses) 313555fcf09bSChristopher J. PeBenito { 3136aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 31374b02b524SEric Paris int rc; 313855fcf09bSChristopher J. PeBenito 3139274f62e1SStephen Smalley if (!state->initialized) { 3140274f62e1SStephen Smalley *nclasses = 0; 3141274f62e1SStephen Smalley *classes = NULL; 3142274f62e1SStephen Smalley return 0; 3143274f62e1SStephen Smalley } 3144274f62e1SStephen Smalley 3145aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 314655fcf09bSChristopher J. PeBenito 31474b02b524SEric Paris rc = -ENOMEM; 3148aa8e712cSStephen Smalley *nclasses = policydb->p_classes.nprim; 31499f59f90bSJulia Lawall *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); 315055fcf09bSChristopher J. PeBenito if (!*classes) 315155fcf09bSChristopher J. PeBenito goto out; 315255fcf09bSChristopher J. PeBenito 3153aa8e712cSStephen Smalley rc = hashtab_map(policydb->p_classes.table, get_classes_callback, 315455fcf09bSChristopher J. PeBenito *classes); 31554b02b524SEric Paris if (rc) { 315655fcf09bSChristopher J. PeBenito int i; 315755fcf09bSChristopher J. PeBenito for (i = 0; i < *nclasses; i++) 315855fcf09bSChristopher J. PeBenito kfree((*classes)[i]); 315955fcf09bSChristopher J. PeBenito kfree(*classes); 316055fcf09bSChristopher J. PeBenito } 316155fcf09bSChristopher J. PeBenito 316255fcf09bSChristopher J. PeBenito out: 3163aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 316455fcf09bSChristopher J. PeBenito return rc; 316555fcf09bSChristopher J. PeBenito } 316655fcf09bSChristopher J. PeBenito 316755fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args) 316855fcf09bSChristopher J. PeBenito { 316955fcf09bSChristopher J. PeBenito struct perm_datum *datum = d; 317055fcf09bSChristopher J. PeBenito char *name = k, **perms = args; 317155fcf09bSChristopher J. PeBenito int value = datum->value - 1; 317255fcf09bSChristopher J. PeBenito 317355fcf09bSChristopher J. PeBenito perms[value] = kstrdup(name, GFP_ATOMIC); 317455fcf09bSChristopher J. PeBenito if (!perms[value]) 317555fcf09bSChristopher J. PeBenito return -ENOMEM; 317655fcf09bSChristopher J. PeBenito 317755fcf09bSChristopher J. PeBenito return 0; 317855fcf09bSChristopher J. PeBenito } 317955fcf09bSChristopher J. PeBenito 3180aa8e712cSStephen Smalley int security_get_permissions(struct selinux_state *state, 3181aa8e712cSStephen Smalley char *class, char ***perms, int *nperms) 318255fcf09bSChristopher J. PeBenito { 3183aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 31844b02b524SEric Paris int rc, i; 318555fcf09bSChristopher J. PeBenito struct class_datum *match; 318655fcf09bSChristopher J. PeBenito 3187aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 318855fcf09bSChristopher J. PeBenito 31894b02b524SEric Paris rc = -EINVAL; 3190aa8e712cSStephen Smalley match = hashtab_search(policydb->p_classes.table, class); 319155fcf09bSChristopher J. PeBenito if (!match) { 3192b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized class %s\n", 3193dd6f953aSHarvey Harrison __func__, class); 319455fcf09bSChristopher J. PeBenito goto out; 319555fcf09bSChristopher J. PeBenito } 319655fcf09bSChristopher J. PeBenito 31974b02b524SEric Paris rc = -ENOMEM; 319855fcf09bSChristopher J. PeBenito *nperms = match->permissions.nprim; 31999f59f90bSJulia Lawall *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); 320055fcf09bSChristopher J. PeBenito if (!*perms) 320155fcf09bSChristopher J. PeBenito goto out; 320255fcf09bSChristopher J. PeBenito 320355fcf09bSChristopher J. PeBenito if (match->comdatum) { 320455fcf09bSChristopher J. PeBenito rc = hashtab_map(match->comdatum->permissions.table, 320555fcf09bSChristopher J. PeBenito get_permissions_callback, *perms); 32064b02b524SEric Paris if (rc) 320755fcf09bSChristopher J. PeBenito goto err; 320855fcf09bSChristopher J. PeBenito } 320955fcf09bSChristopher J. PeBenito 321055fcf09bSChristopher J. PeBenito rc = hashtab_map(match->permissions.table, get_permissions_callback, 321155fcf09bSChristopher J. PeBenito *perms); 32124b02b524SEric Paris if (rc) 321355fcf09bSChristopher J. PeBenito goto err; 321455fcf09bSChristopher J. PeBenito 321555fcf09bSChristopher J. PeBenito out: 3216aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 321755fcf09bSChristopher J. PeBenito return rc; 321855fcf09bSChristopher J. PeBenito 321955fcf09bSChristopher J. PeBenito err: 3220aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 322155fcf09bSChristopher J. PeBenito for (i = 0; i < *nperms; i++) 322255fcf09bSChristopher J. PeBenito kfree((*perms)[i]); 322355fcf09bSChristopher J. PeBenito kfree(*perms); 322455fcf09bSChristopher J. PeBenito return rc; 322555fcf09bSChristopher J. PeBenito } 322655fcf09bSChristopher J. PeBenito 3227aa8e712cSStephen Smalley int security_get_reject_unknown(struct selinux_state *state) 32283f12070eSEric Paris { 3229aa8e712cSStephen Smalley return state->ss->policydb.reject_unknown; 32303f12070eSEric Paris } 32313f12070eSEric Paris 3232aa8e712cSStephen Smalley int security_get_allow_unknown(struct selinux_state *state) 32333f12070eSEric Paris { 3234aa8e712cSStephen Smalley return state->ss->policydb.allow_unknown; 32353f12070eSEric Paris } 32363f12070eSEric Paris 32373bb56b25SPaul Moore /** 32383bb56b25SPaul Moore * security_policycap_supported - Check for a specific policy capability 32393bb56b25SPaul Moore * @req_cap: capability 32403bb56b25SPaul Moore * 32413bb56b25SPaul Moore * Description: 32423bb56b25SPaul Moore * This function queries the currently loaded policy to see if it supports the 32433bb56b25SPaul Moore * capability specified by @req_cap. Returns true (1) if the capability is 32443bb56b25SPaul Moore * supported, false (0) if it isn't supported. 32453bb56b25SPaul Moore * 32463bb56b25SPaul Moore */ 3247aa8e712cSStephen Smalley int security_policycap_supported(struct selinux_state *state, 3248aa8e712cSStephen Smalley unsigned int req_cap) 32493bb56b25SPaul Moore { 3250aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 32513bb56b25SPaul Moore int rc; 32523bb56b25SPaul Moore 3253aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 3254aa8e712cSStephen Smalley rc = ebitmap_get_bit(&policydb->policycaps, req_cap); 3255aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 32563bb56b25SPaul Moore 32573bb56b25SPaul Moore return rc; 32583bb56b25SPaul Moore } 32593bb56b25SPaul Moore 3260376bd9cbSDarrel Goeddel struct selinux_audit_rule { 3261376bd9cbSDarrel Goeddel u32 au_seqno; 3262376bd9cbSDarrel Goeddel struct context au_ctxt; 3263376bd9cbSDarrel Goeddel }; 3264376bd9cbSDarrel Goeddel 32659d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule) 3266376bd9cbSDarrel Goeddel { 32679d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule; 32689d57a7f9SAhmed S. Darwish 3269376bd9cbSDarrel Goeddel if (rule) { 3270376bd9cbSDarrel Goeddel context_destroy(&rule->au_ctxt); 3271376bd9cbSDarrel Goeddel kfree(rule); 3272376bd9cbSDarrel Goeddel } 3273376bd9cbSDarrel Goeddel } 3274376bd9cbSDarrel Goeddel 32759d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) 3276376bd9cbSDarrel Goeddel { 3277aa8e712cSStephen Smalley struct selinux_state *state = &selinux_state; 3278aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 3279376bd9cbSDarrel Goeddel struct selinux_audit_rule *tmprule; 3280376bd9cbSDarrel Goeddel struct role_datum *roledatum; 3281376bd9cbSDarrel Goeddel struct type_datum *typedatum; 3282376bd9cbSDarrel Goeddel struct user_datum *userdatum; 32839d57a7f9SAhmed S. Darwish struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule; 3284376bd9cbSDarrel Goeddel int rc = 0; 3285376bd9cbSDarrel Goeddel 3286376bd9cbSDarrel Goeddel *rule = NULL; 3287376bd9cbSDarrel Goeddel 3288aa8e712cSStephen Smalley if (!state->initialized) 32893ad40d64SSteve G return -EOPNOTSUPP; 3290376bd9cbSDarrel Goeddel 3291376bd9cbSDarrel Goeddel switch (field) { 32923a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 32933a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 32943a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 32956e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 32966e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 32976e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 3298376bd9cbSDarrel Goeddel /* only 'equals' and 'not equals' fit user, role, and type */ 32995af75d8dSAl Viro if (op != Audit_equal && op != Audit_not_equal) 3300376bd9cbSDarrel Goeddel return -EINVAL; 3301376bd9cbSDarrel Goeddel break; 33023a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 33033a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 33046e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 33056e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 330625985edcSLucas De Marchi /* we do not allow a range, indicated by the presence of '-' */ 3307376bd9cbSDarrel Goeddel if (strchr(rulestr, '-')) 3308376bd9cbSDarrel Goeddel return -EINVAL; 3309376bd9cbSDarrel Goeddel break; 3310376bd9cbSDarrel Goeddel default: 3311376bd9cbSDarrel Goeddel /* only the above fields are valid */ 3312376bd9cbSDarrel Goeddel return -EINVAL; 3313376bd9cbSDarrel Goeddel } 3314376bd9cbSDarrel Goeddel 3315376bd9cbSDarrel Goeddel tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL); 3316376bd9cbSDarrel Goeddel if (!tmprule) 3317376bd9cbSDarrel Goeddel return -ENOMEM; 3318376bd9cbSDarrel Goeddel 3319376bd9cbSDarrel Goeddel context_init(&tmprule->au_ctxt); 3320376bd9cbSDarrel Goeddel 3321aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 3322376bd9cbSDarrel Goeddel 3323aa8e712cSStephen Smalley tmprule->au_seqno = state->ss->latest_granting; 3324376bd9cbSDarrel Goeddel 3325376bd9cbSDarrel Goeddel switch (field) { 33263a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 33276e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 33284b02b524SEric Paris rc = -EINVAL; 3329aa8e712cSStephen Smalley userdatum = hashtab_search(policydb->p_users.table, rulestr); 3330376bd9cbSDarrel Goeddel if (!userdatum) 33314b02b524SEric Paris goto out; 3332376bd9cbSDarrel Goeddel tmprule->au_ctxt.user = userdatum->value; 3333376bd9cbSDarrel Goeddel break; 33343a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 33356e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 33364b02b524SEric Paris rc = -EINVAL; 3337aa8e712cSStephen Smalley roledatum = hashtab_search(policydb->p_roles.table, rulestr); 3338376bd9cbSDarrel Goeddel if (!roledatum) 33394b02b524SEric Paris goto out; 3340376bd9cbSDarrel Goeddel tmprule->au_ctxt.role = roledatum->value; 3341376bd9cbSDarrel Goeddel break; 33423a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 33436e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 33444b02b524SEric Paris rc = -EINVAL; 3345aa8e712cSStephen Smalley typedatum = hashtab_search(policydb->p_types.table, rulestr); 3346376bd9cbSDarrel Goeddel if (!typedatum) 33474b02b524SEric Paris goto out; 3348376bd9cbSDarrel Goeddel tmprule->au_ctxt.type = typedatum->value; 3349376bd9cbSDarrel Goeddel break; 33503a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 33513a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 33526e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 33536e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 3354aa8e712cSStephen Smalley rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt, 3355aa8e712cSStephen Smalley GFP_ATOMIC); 33564b02b524SEric Paris if (rc) 33574b02b524SEric Paris goto out; 3358376bd9cbSDarrel Goeddel break; 3359376bd9cbSDarrel Goeddel } 33604b02b524SEric Paris rc = 0; 33614b02b524SEric Paris out: 3362aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 3363376bd9cbSDarrel Goeddel 3364376bd9cbSDarrel Goeddel if (rc) { 3365376bd9cbSDarrel Goeddel selinux_audit_rule_free(tmprule); 3366376bd9cbSDarrel Goeddel tmprule = NULL; 3367376bd9cbSDarrel Goeddel } 3368376bd9cbSDarrel Goeddel 3369376bd9cbSDarrel Goeddel *rule = tmprule; 3370376bd9cbSDarrel Goeddel 3371376bd9cbSDarrel Goeddel return rc; 3372376bd9cbSDarrel Goeddel } 3373376bd9cbSDarrel Goeddel 33749d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */ 33759d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule) 33769d57a7f9SAhmed S. Darwish { 33779d57a7f9SAhmed S. Darwish int i; 33789d57a7f9SAhmed S. Darwish 33799d57a7f9SAhmed S. Darwish for (i = 0; i < rule->field_count; i++) { 33809d57a7f9SAhmed S. Darwish struct audit_field *f = &rule->fields[i]; 33819d57a7f9SAhmed S. Darwish switch (f->type) { 33829d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_USER: 33839d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_ROLE: 33849d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_TYPE: 33859d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_SEN: 33869d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_CLR: 33879d57a7f9SAhmed S. Darwish case AUDIT_OBJ_USER: 33889d57a7f9SAhmed S. Darwish case AUDIT_OBJ_ROLE: 33899d57a7f9SAhmed S. Darwish case AUDIT_OBJ_TYPE: 33909d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_LOW: 33919d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_HIGH: 33929d57a7f9SAhmed S. Darwish return 1; 33939d57a7f9SAhmed S. Darwish } 33949d57a7f9SAhmed S. Darwish } 33959d57a7f9SAhmed S. Darwish 33969d57a7f9SAhmed S. Darwish return 0; 33979d57a7f9SAhmed S. Darwish } 33989d57a7f9SAhmed S. Darwish 339990462a5bSRichard Guy Briggs int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule) 3400376bd9cbSDarrel Goeddel { 3401aa8e712cSStephen Smalley struct selinux_state *state = &selinux_state; 3402376bd9cbSDarrel Goeddel struct context *ctxt; 3403376bd9cbSDarrel Goeddel struct mls_level *level; 34049d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule; 3405376bd9cbSDarrel Goeddel int match = 0; 3406376bd9cbSDarrel Goeddel 34079ad42a79SRichard Guy Briggs if (unlikely(!rule)) { 34089ad42a79SRichard Guy Briggs WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n"); 3409376bd9cbSDarrel Goeddel return -ENOENT; 3410376bd9cbSDarrel Goeddel } 3411376bd9cbSDarrel Goeddel 3412aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 3413376bd9cbSDarrel Goeddel 3414aa8e712cSStephen Smalley if (rule->au_seqno < state->ss->latest_granting) { 3415376bd9cbSDarrel Goeddel match = -ESTALE; 3416376bd9cbSDarrel Goeddel goto out; 3417376bd9cbSDarrel Goeddel } 3418376bd9cbSDarrel Goeddel 341924ed7fdaSOndrej Mosnacek ctxt = sidtab_search(state->ss->sidtab, sid); 34209ad42a79SRichard Guy Briggs if (unlikely(!ctxt)) { 34219ad42a79SRichard Guy Briggs WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", 34229a2f44f0SStephen Smalley sid); 3423376bd9cbSDarrel Goeddel match = -ENOENT; 3424376bd9cbSDarrel Goeddel goto out; 3425376bd9cbSDarrel Goeddel } 3426376bd9cbSDarrel Goeddel 3427376bd9cbSDarrel Goeddel /* a field/op pair that is not caught here will simply fall through 3428376bd9cbSDarrel Goeddel without a match */ 3429376bd9cbSDarrel Goeddel switch (field) { 34303a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 34316e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 3432376bd9cbSDarrel Goeddel switch (op) { 34335af75d8dSAl Viro case Audit_equal: 3434376bd9cbSDarrel Goeddel match = (ctxt->user == rule->au_ctxt.user); 3435376bd9cbSDarrel Goeddel break; 34365af75d8dSAl Viro case Audit_not_equal: 3437376bd9cbSDarrel Goeddel match = (ctxt->user != rule->au_ctxt.user); 3438376bd9cbSDarrel Goeddel break; 3439376bd9cbSDarrel Goeddel } 3440376bd9cbSDarrel Goeddel break; 34413a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 34426e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 3443376bd9cbSDarrel Goeddel switch (op) { 34445af75d8dSAl Viro case Audit_equal: 3445376bd9cbSDarrel Goeddel match = (ctxt->role == rule->au_ctxt.role); 3446376bd9cbSDarrel Goeddel break; 34475af75d8dSAl Viro case Audit_not_equal: 3448376bd9cbSDarrel Goeddel match = (ctxt->role != rule->au_ctxt.role); 3449376bd9cbSDarrel Goeddel break; 3450376bd9cbSDarrel Goeddel } 3451376bd9cbSDarrel Goeddel break; 34523a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 34536e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 3454376bd9cbSDarrel Goeddel switch (op) { 34555af75d8dSAl Viro case Audit_equal: 3456376bd9cbSDarrel Goeddel match = (ctxt->type == rule->au_ctxt.type); 3457376bd9cbSDarrel Goeddel break; 34585af75d8dSAl Viro case Audit_not_equal: 3459376bd9cbSDarrel Goeddel match = (ctxt->type != rule->au_ctxt.type); 3460376bd9cbSDarrel Goeddel break; 3461376bd9cbSDarrel Goeddel } 3462376bd9cbSDarrel Goeddel break; 34633a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 34643a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 34656e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 34666e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 34676e5a2d1dSDarrel Goeddel level = ((field == AUDIT_SUBJ_SEN || 34686e5a2d1dSDarrel Goeddel field == AUDIT_OBJ_LEV_LOW) ? 3469376bd9cbSDarrel Goeddel &ctxt->range.level[0] : &ctxt->range.level[1]); 3470376bd9cbSDarrel Goeddel switch (op) { 34715af75d8dSAl Viro case Audit_equal: 3472376bd9cbSDarrel Goeddel match = mls_level_eq(&rule->au_ctxt.range.level[0], 3473376bd9cbSDarrel Goeddel level); 3474376bd9cbSDarrel Goeddel break; 34755af75d8dSAl Viro case Audit_not_equal: 3476376bd9cbSDarrel Goeddel match = !mls_level_eq(&rule->au_ctxt.range.level[0], 3477376bd9cbSDarrel Goeddel level); 3478376bd9cbSDarrel Goeddel break; 34795af75d8dSAl Viro case Audit_lt: 3480376bd9cbSDarrel Goeddel match = (mls_level_dom(&rule->au_ctxt.range.level[0], 3481376bd9cbSDarrel Goeddel level) && 3482376bd9cbSDarrel Goeddel !mls_level_eq(&rule->au_ctxt.range.level[0], 3483376bd9cbSDarrel Goeddel level)); 3484376bd9cbSDarrel Goeddel break; 34855af75d8dSAl Viro case Audit_le: 3486376bd9cbSDarrel Goeddel match = mls_level_dom(&rule->au_ctxt.range.level[0], 3487376bd9cbSDarrel Goeddel level); 3488376bd9cbSDarrel Goeddel break; 34895af75d8dSAl Viro case Audit_gt: 3490376bd9cbSDarrel Goeddel match = (mls_level_dom(level, 3491376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]) && 3492376bd9cbSDarrel Goeddel !mls_level_eq(level, 3493376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0])); 3494376bd9cbSDarrel Goeddel break; 34955af75d8dSAl Viro case Audit_ge: 3496376bd9cbSDarrel Goeddel match = mls_level_dom(level, 3497376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]); 3498376bd9cbSDarrel Goeddel break; 3499376bd9cbSDarrel Goeddel } 3500376bd9cbSDarrel Goeddel } 3501376bd9cbSDarrel Goeddel 3502376bd9cbSDarrel Goeddel out: 3503aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 3504376bd9cbSDarrel Goeddel return match; 3505376bd9cbSDarrel Goeddel } 3506376bd9cbSDarrel Goeddel 35079d57a7f9SAhmed S. Darwish static int (*aurule_callback)(void) = audit_update_lsm_rules; 3508376bd9cbSDarrel Goeddel 3509562c99f2SWanlong Gao static int aurule_avc_callback(u32 event) 3510376bd9cbSDarrel Goeddel { 3511376bd9cbSDarrel Goeddel int err = 0; 3512376bd9cbSDarrel Goeddel 3513376bd9cbSDarrel Goeddel if (event == AVC_CALLBACK_RESET && aurule_callback) 3514376bd9cbSDarrel Goeddel err = aurule_callback(); 3515376bd9cbSDarrel Goeddel return err; 3516376bd9cbSDarrel Goeddel } 3517376bd9cbSDarrel Goeddel 3518376bd9cbSDarrel Goeddel static int __init aurule_init(void) 3519376bd9cbSDarrel Goeddel { 3520376bd9cbSDarrel Goeddel int err; 3521376bd9cbSDarrel Goeddel 3522562c99f2SWanlong Gao err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET); 3523376bd9cbSDarrel Goeddel if (err) 3524376bd9cbSDarrel Goeddel panic("avc_add_callback() failed, error %d\n", err); 3525376bd9cbSDarrel Goeddel 3526376bd9cbSDarrel Goeddel return err; 3527376bd9cbSDarrel Goeddel } 3528376bd9cbSDarrel Goeddel __initcall(aurule_init); 3529376bd9cbSDarrel Goeddel 35307420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL 35317420ed23SVenkat Yekkirala /** 35325778eabdSPaul Moore * security_netlbl_cache_add - Add an entry to the NetLabel cache 35335778eabdSPaul Moore * @secattr: the NetLabel packet security attributes 35345dbe1eb0SPaul Moore * @sid: the SELinux SID 35357420ed23SVenkat Yekkirala * 35367420ed23SVenkat Yekkirala * Description: 35377420ed23SVenkat Yekkirala * Attempt to cache the context in @ctx, which was derived from the packet in 35385778eabdSPaul Moore * @skb, in the NetLabel subsystem cache. This function assumes @secattr has 35395778eabdSPaul Moore * already been initialized. 35407420ed23SVenkat Yekkirala * 35417420ed23SVenkat Yekkirala */ 35425778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, 35435dbe1eb0SPaul Moore u32 sid) 35447420ed23SVenkat Yekkirala { 35455dbe1eb0SPaul Moore u32 *sid_cache; 35467420ed23SVenkat Yekkirala 35475dbe1eb0SPaul Moore sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC); 35485dbe1eb0SPaul Moore if (sid_cache == NULL) 35495dbe1eb0SPaul Moore return; 35505778eabdSPaul Moore secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); 35515dbe1eb0SPaul Moore if (secattr->cache == NULL) { 35525dbe1eb0SPaul Moore kfree(sid_cache); 35535778eabdSPaul Moore return; 35540ec8abd7SJesper Juhl } 35557420ed23SVenkat Yekkirala 35565dbe1eb0SPaul Moore *sid_cache = sid; 35575dbe1eb0SPaul Moore secattr->cache->free = kfree; 35585dbe1eb0SPaul Moore secattr->cache->data = sid_cache; 35595778eabdSPaul Moore secattr->flags |= NETLBL_SECATTR_CACHE; 35607420ed23SVenkat Yekkirala } 35617420ed23SVenkat Yekkirala 35627420ed23SVenkat Yekkirala /** 35635778eabdSPaul Moore * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID 35647420ed23SVenkat Yekkirala * @secattr: the NetLabel packet security attributes 35657420ed23SVenkat Yekkirala * @sid: the SELinux SID 35667420ed23SVenkat Yekkirala * 35677420ed23SVenkat Yekkirala * Description: 35685778eabdSPaul Moore * Convert the given NetLabel security attributes in @secattr into a 35697420ed23SVenkat Yekkirala * SELinux SID. If the @secattr field does not contain a full SELinux 357025985edcSLucas De Marchi * SID/context then use SECINITSID_NETMSG as the foundation. If possible the 35715dbe1eb0SPaul Moore * 'cache' field of @secattr is set and the CACHE flag is set; this is to 35725dbe1eb0SPaul Moore * allow the @secattr to be used by NetLabel to cache the secattr to SID 35735dbe1eb0SPaul Moore * conversion for future lookups. Returns zero on success, negative values on 35745dbe1eb0SPaul Moore * failure. 35757420ed23SVenkat Yekkirala * 35767420ed23SVenkat Yekkirala */ 3577aa8e712cSStephen Smalley int security_netlbl_secattr_to_sid(struct selinux_state *state, 3578aa8e712cSStephen Smalley struct netlbl_lsm_secattr *secattr, 35797420ed23SVenkat Yekkirala u32 *sid) 35807420ed23SVenkat Yekkirala { 3581aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 358224ed7fdaSOndrej Mosnacek struct sidtab *sidtab = state->ss->sidtab; 35837ae9f23cSEric Paris int rc; 35847420ed23SVenkat Yekkirala struct context *ctx; 35857420ed23SVenkat Yekkirala struct context ctx_new; 35865778eabdSPaul Moore 3587aa8e712cSStephen Smalley if (!state->initialized) { 35885778eabdSPaul Moore *sid = SECSID_NULL; 35895778eabdSPaul Moore return 0; 35905778eabdSPaul Moore } 35917420ed23SVenkat Yekkirala 3592aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 35937420ed23SVenkat Yekkirala 35947ae9f23cSEric Paris if (secattr->flags & NETLBL_SECATTR_CACHE) 35955dbe1eb0SPaul Moore *sid = *(u32 *)secattr->cache->data; 35967ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_SECID) 359716efd454SPaul Moore *sid = secattr->attr.secid; 35987ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { 35997ae9f23cSEric Paris rc = -EIDRM; 3600aa8e712cSStephen Smalley ctx = sidtab_search(sidtab, SECINITSID_NETMSG); 36017420ed23SVenkat Yekkirala if (ctx == NULL) 36027ae9f23cSEric Paris goto out; 36037420ed23SVenkat Yekkirala 360481990fbdSPaul Moore context_init(&ctx_new); 36057420ed23SVenkat Yekkirala ctx_new.user = ctx->user; 36067420ed23SVenkat Yekkirala ctx_new.role = ctx->role; 36077420ed23SVenkat Yekkirala ctx_new.type = ctx->type; 3608aa8e712cSStephen Smalley mls_import_netlbl_lvl(policydb, &ctx_new, secattr); 3609701a90baSPaul Moore if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 3610aa8e712cSStephen Smalley rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr); 36117ae9f23cSEric Paris if (rc) 36127ae9f23cSEric Paris goto out; 36137420ed23SVenkat Yekkirala } 36147ae9f23cSEric Paris rc = -EIDRM; 3615aa8e712cSStephen Smalley if (!mls_context_isvalid(policydb, &ctx_new)) 36167ae9f23cSEric Paris goto out_free; 36177420ed23SVenkat Yekkirala 3618aa8e712cSStephen Smalley rc = sidtab_context_to_sid(sidtab, &ctx_new, sid); 36197ae9f23cSEric Paris if (rc) 36207ae9f23cSEric Paris goto out_free; 36217420ed23SVenkat Yekkirala 36225dbe1eb0SPaul Moore security_netlbl_cache_add(secattr, *sid); 36235778eabdSPaul Moore 36247420ed23SVenkat Yekkirala ebitmap_destroy(&ctx_new.range.level[0].cat); 36257ae9f23cSEric Paris } else 3626388b2405Spaul.moore@hp.com *sid = SECSID_NULL; 36277420ed23SVenkat Yekkirala 3628aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 36297ae9f23cSEric Paris return 0; 36307ae9f23cSEric Paris out_free: 36317ae9f23cSEric Paris ebitmap_destroy(&ctx_new.range.level[0].cat); 36327ae9f23cSEric Paris out: 3633aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 36347420ed23SVenkat Yekkirala return rc; 36357420ed23SVenkat Yekkirala } 36367420ed23SVenkat Yekkirala 36377420ed23SVenkat Yekkirala /** 36385778eabdSPaul Moore * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr 36395778eabdSPaul Moore * @sid: the SELinux SID 36405778eabdSPaul Moore * @secattr: the NetLabel packet security attributes 36417420ed23SVenkat Yekkirala * 36427420ed23SVenkat Yekkirala * Description: 36435778eabdSPaul Moore * Convert the given SELinux SID in @sid into a NetLabel security attribute. 36445778eabdSPaul Moore * Returns zero on success, negative values on failure. 36457420ed23SVenkat Yekkirala * 36467420ed23SVenkat Yekkirala */ 3647aa8e712cSStephen Smalley int security_netlbl_sid_to_secattr(struct selinux_state *state, 3648aa8e712cSStephen Smalley u32 sid, struct netlbl_lsm_secattr *secattr) 36497420ed23SVenkat Yekkirala { 3650aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 365199d854d2SPaul Moore int rc; 36527420ed23SVenkat Yekkirala struct context *ctx; 36537420ed23SVenkat Yekkirala 3654aa8e712cSStephen Smalley if (!state->initialized) 36557420ed23SVenkat Yekkirala return 0; 36567420ed23SVenkat Yekkirala 3657aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 36584b02b524SEric Paris 365999d854d2SPaul Moore rc = -ENOENT; 366024ed7fdaSOndrej Mosnacek ctx = sidtab_search(state->ss->sidtab, sid); 36614b02b524SEric Paris if (ctx == NULL) 36624b02b524SEric Paris goto out; 36634b02b524SEric Paris 36644b02b524SEric Paris rc = -ENOMEM; 3665aa8e712cSStephen Smalley secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1), 36667420ed23SVenkat Yekkirala GFP_ATOMIC); 36674b02b524SEric Paris if (secattr->domain == NULL) 36684b02b524SEric Paris goto out; 36694b02b524SEric Paris 36708d75899dSPaul Moore secattr->attr.secid = sid; 36718d75899dSPaul Moore secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; 3672aa8e712cSStephen Smalley mls_export_netlbl_lvl(policydb, ctx, secattr); 3673aa8e712cSStephen Smalley rc = mls_export_netlbl_cat(policydb, ctx, secattr); 36744b02b524SEric Paris out: 3675aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 3676f8687afeSPaul Moore return rc; 3677f8687afeSPaul Moore } 36787420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */ 3679cee74f47SEric Paris 3680cee74f47SEric Paris /** 3681cee74f47SEric Paris * security_read_policy - read the policy. 3682cee74f47SEric Paris * @data: binary policy data 3683cee74f47SEric Paris * @len: length of data in bytes 3684cee74f47SEric Paris * 3685cee74f47SEric Paris */ 3686aa8e712cSStephen Smalley int security_read_policy(struct selinux_state *state, 3687aa8e712cSStephen Smalley void **data, size_t *len) 3688cee74f47SEric Paris { 3689aa8e712cSStephen Smalley struct policydb *policydb = &state->ss->policydb; 3690cee74f47SEric Paris int rc; 3691cee74f47SEric Paris struct policy_file fp; 3692cee74f47SEric Paris 3693aa8e712cSStephen Smalley if (!state->initialized) 3694cee74f47SEric Paris return -EINVAL; 3695cee74f47SEric Paris 3696aa8e712cSStephen Smalley *len = security_policydb_len(state); 3697cee74f47SEric Paris 3698845ca30fSEric Paris *data = vmalloc_user(*len); 3699cee74f47SEric Paris if (!*data) 3700cee74f47SEric Paris return -ENOMEM; 3701cee74f47SEric Paris 3702cee74f47SEric Paris fp.data = *data; 3703cee74f47SEric Paris fp.len = *len; 3704cee74f47SEric Paris 3705aa8e712cSStephen Smalley read_lock(&state->ss->policy_rwlock); 3706aa8e712cSStephen Smalley rc = policydb_write(policydb, &fp); 3707aa8e712cSStephen Smalley read_unlock(&state->ss->policy_rwlock); 3708cee74f47SEric Paris 3709cee74f47SEric Paris if (rc) 3710cee74f47SEric Paris return rc; 3711cee74f47SEric Paris 3712cee74f47SEric Paris *len = (unsigned long)fp.data - (unsigned long)*data; 3713cee74f47SEric Paris return 0; 3714cee74f47SEric Paris 3715cee74f47SEric Paris } 3716