11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Implementation of the security services. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Authors : Stephen Smalley, <sds@epoch.ncsc.mil> 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> 520e55a004SAdrian Bunk #include <linux/selinux.h> 536371dcd3SEric Paris #include <linux/flex_array.h> 54f0d3d989SStephen Rothwell #include <linux/vmalloc.h> 557420ed23SVenkat Yekkirala #include <net/netlabel.h> 56bb003079SIngo Molnar 571da177e4SLinus Torvalds #include "flask.h" 581da177e4SLinus Torvalds #include "avc.h" 591da177e4SLinus Torvalds #include "avc_ss.h" 601da177e4SLinus Torvalds #include "security.h" 611da177e4SLinus Torvalds #include "context.h" 621da177e4SLinus Torvalds #include "policydb.h" 631da177e4SLinus Torvalds #include "sidtab.h" 641da177e4SLinus Torvalds #include "services.h" 651da177e4SLinus Torvalds #include "conditional.h" 661da177e4SLinus Torvalds #include "mls.h" 677420ed23SVenkat Yekkirala #include "objsec.h" 68c60475bfSPaul Moore #include "netlabel.h" 693de4bab5SPaul Moore #include "xfrm.h" 7002752760SPaul Moore #include "ebitmap.h" 719d57a7f9SAhmed S. Darwish #include "audit.h" 721da177e4SLinus Torvalds 733bb56b25SPaul Moore int selinux_policycap_netpeer; 74b0c636b9SEric Paris int selinux_policycap_openperm; 752be4d74fSChris PeBenito int selinux_policycap_alwaysnetwork; 763bb56b25SPaul Moore 771da177e4SLinus Torvalds static DEFINE_RWLOCK(policy_rwlock); 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds static struct sidtab sidtab; 801da177e4SLinus Torvalds struct policydb policydb; 815d55a345SEric Paris int ss_initialized; 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds /* 841da177e4SLinus Torvalds * The largest sequence number that has been used when 851da177e4SLinus Torvalds * providing an access decision to the access vector cache. 861da177e4SLinus Torvalds * The sequence number only changes when a policy change 871da177e4SLinus Torvalds * occurs. 881da177e4SLinus Torvalds */ 895d55a345SEric Paris static u32 latest_granting; 901da177e4SLinus Torvalds 911da177e4SLinus Torvalds /* Forward declaration. */ 921da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, 931da177e4SLinus Torvalds u32 *scontext_len); 941da177e4SLinus Torvalds 9519439d05SStephen Smalley static void context_struct_compute_av(struct context *scontext, 96d9250deaSKaiGai Kohei struct context *tcontext, 97d9250deaSKaiGai Kohei u16 tclass, 98d9250deaSKaiGai Kohei struct av_decision *avd); 99c6d3aaa4SStephen Smalley 100c6d3aaa4SStephen Smalley struct selinux_mapping { 101c6d3aaa4SStephen Smalley u16 value; /* policy value */ 102c6d3aaa4SStephen Smalley unsigned num_perms; 103c6d3aaa4SStephen Smalley u32 perms[sizeof(u32) * 8]; 104c6d3aaa4SStephen Smalley }; 105c6d3aaa4SStephen Smalley 106c6d3aaa4SStephen Smalley static struct selinux_mapping *current_mapping; 107c6d3aaa4SStephen Smalley static u16 current_mapping_size; 108c6d3aaa4SStephen Smalley 109c6d3aaa4SStephen Smalley static int selinux_set_mapping(struct policydb *pol, 110c6d3aaa4SStephen Smalley struct security_class_mapping *map, 111c6d3aaa4SStephen Smalley struct selinux_mapping **out_map_p, 112c6d3aaa4SStephen Smalley u16 *out_map_size) 113c6d3aaa4SStephen Smalley { 114c6d3aaa4SStephen Smalley struct selinux_mapping *out_map = NULL; 115c6d3aaa4SStephen Smalley size_t size = sizeof(struct selinux_mapping); 116c6d3aaa4SStephen Smalley u16 i, j; 117c6d3aaa4SStephen Smalley unsigned k; 118c6d3aaa4SStephen Smalley bool print_unknown_handle = false; 119c6d3aaa4SStephen Smalley 120c6d3aaa4SStephen Smalley /* Find number of classes in the input mapping */ 121c6d3aaa4SStephen Smalley if (!map) 122c6d3aaa4SStephen Smalley return -EINVAL; 123c6d3aaa4SStephen Smalley i = 0; 124c6d3aaa4SStephen Smalley while (map[i].name) 125c6d3aaa4SStephen Smalley i++; 126c6d3aaa4SStephen Smalley 127c6d3aaa4SStephen Smalley /* Allocate space for the class records, plus one for class zero */ 128c6d3aaa4SStephen Smalley out_map = kcalloc(++i, size, GFP_ATOMIC); 129c6d3aaa4SStephen Smalley if (!out_map) 130c6d3aaa4SStephen Smalley return -ENOMEM; 131c6d3aaa4SStephen Smalley 132c6d3aaa4SStephen Smalley /* Store the raw class and permission values */ 133c6d3aaa4SStephen Smalley j = 0; 134c6d3aaa4SStephen Smalley while (map[j].name) { 135c6d3aaa4SStephen Smalley struct security_class_mapping *p_in = map + (j++); 136c6d3aaa4SStephen Smalley struct selinux_mapping *p_out = out_map + j; 137c6d3aaa4SStephen Smalley 138c6d3aaa4SStephen Smalley /* An empty class string skips ahead */ 139c6d3aaa4SStephen Smalley if (!strcmp(p_in->name, "")) { 140c6d3aaa4SStephen Smalley p_out->num_perms = 0; 141c6d3aaa4SStephen Smalley continue; 142c6d3aaa4SStephen Smalley } 143c6d3aaa4SStephen Smalley 144c6d3aaa4SStephen Smalley p_out->value = string_to_security_class(pol, p_in->name); 145c6d3aaa4SStephen Smalley if (!p_out->value) { 146c6d3aaa4SStephen Smalley printk(KERN_INFO 147c6d3aaa4SStephen Smalley "SELinux: Class %s not defined in policy.\n", 148c6d3aaa4SStephen Smalley p_in->name); 149c6d3aaa4SStephen Smalley if (pol->reject_unknown) 150c6d3aaa4SStephen Smalley goto err; 151c6d3aaa4SStephen Smalley p_out->num_perms = 0; 152c6d3aaa4SStephen Smalley print_unknown_handle = true; 153c6d3aaa4SStephen Smalley continue; 154c6d3aaa4SStephen Smalley } 155c6d3aaa4SStephen Smalley 156c6d3aaa4SStephen Smalley k = 0; 157c6d3aaa4SStephen Smalley while (p_in->perms && p_in->perms[k]) { 158c6d3aaa4SStephen Smalley /* An empty permission string skips ahead */ 159c6d3aaa4SStephen Smalley if (!*p_in->perms[k]) { 160c6d3aaa4SStephen Smalley k++; 161c6d3aaa4SStephen Smalley continue; 162c6d3aaa4SStephen Smalley } 163c6d3aaa4SStephen Smalley p_out->perms[k] = string_to_av_perm(pol, p_out->value, 164c6d3aaa4SStephen Smalley p_in->perms[k]); 165c6d3aaa4SStephen Smalley if (!p_out->perms[k]) { 166c6d3aaa4SStephen Smalley printk(KERN_INFO 167c6d3aaa4SStephen Smalley "SELinux: Permission %s in class %s not defined in policy.\n", 168c6d3aaa4SStephen Smalley p_in->perms[k], p_in->name); 169c6d3aaa4SStephen Smalley if (pol->reject_unknown) 170c6d3aaa4SStephen Smalley goto err; 171c6d3aaa4SStephen Smalley print_unknown_handle = true; 172c6d3aaa4SStephen Smalley } 173c6d3aaa4SStephen Smalley 174c6d3aaa4SStephen Smalley k++; 175c6d3aaa4SStephen Smalley } 176c6d3aaa4SStephen Smalley p_out->num_perms = k; 177c6d3aaa4SStephen Smalley } 178c6d3aaa4SStephen Smalley 179c6d3aaa4SStephen Smalley if (print_unknown_handle) 180c6d3aaa4SStephen Smalley printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n", 181c6d3aaa4SStephen Smalley pol->allow_unknown ? "allowed" : "denied"); 182c6d3aaa4SStephen Smalley 183c6d3aaa4SStephen Smalley *out_map_p = out_map; 184c6d3aaa4SStephen Smalley *out_map_size = i; 185c6d3aaa4SStephen Smalley return 0; 186c6d3aaa4SStephen Smalley err: 187c6d3aaa4SStephen Smalley kfree(out_map); 188c6d3aaa4SStephen Smalley return -EINVAL; 189c6d3aaa4SStephen Smalley } 190c6d3aaa4SStephen Smalley 191c6d3aaa4SStephen Smalley /* 192c6d3aaa4SStephen Smalley * Get real, policy values from mapped values 193c6d3aaa4SStephen Smalley */ 194c6d3aaa4SStephen Smalley 195c6d3aaa4SStephen Smalley static u16 unmap_class(u16 tclass) 196c6d3aaa4SStephen Smalley { 197c6d3aaa4SStephen Smalley if (tclass < current_mapping_size) 198c6d3aaa4SStephen Smalley return current_mapping[tclass].value; 199c6d3aaa4SStephen Smalley 200c6d3aaa4SStephen Smalley return tclass; 201c6d3aaa4SStephen Smalley } 202c6d3aaa4SStephen Smalley 2036f5317e7SHarry Ciao /* 2046f5317e7SHarry Ciao * Get kernel value for class from its policy value 2056f5317e7SHarry Ciao */ 2066f5317e7SHarry Ciao static u16 map_class(u16 pol_value) 2076f5317e7SHarry Ciao { 2086f5317e7SHarry Ciao u16 i; 2096f5317e7SHarry Ciao 2106f5317e7SHarry Ciao for (i = 1; i < current_mapping_size; i++) { 2116f5317e7SHarry Ciao if (current_mapping[i].value == pol_value) 2126f5317e7SHarry Ciao return i; 2136f5317e7SHarry Ciao } 2146f5317e7SHarry Ciao 21585cd6da5SStephen Smalley return SECCLASS_NULL; 2166f5317e7SHarry Ciao } 2176f5317e7SHarry Ciao 218c6d3aaa4SStephen Smalley static void map_decision(u16 tclass, struct av_decision *avd, 219c6d3aaa4SStephen Smalley int allow_unknown) 220c6d3aaa4SStephen Smalley { 221c6d3aaa4SStephen Smalley if (tclass < current_mapping_size) { 222c6d3aaa4SStephen Smalley unsigned i, n = current_mapping[tclass].num_perms; 223c6d3aaa4SStephen Smalley u32 result; 224c6d3aaa4SStephen Smalley 225c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) { 226c6d3aaa4SStephen Smalley if (avd->allowed & current_mapping[tclass].perms[i]) 227c6d3aaa4SStephen Smalley result |= 1<<i; 228c6d3aaa4SStephen Smalley if (allow_unknown && !current_mapping[tclass].perms[i]) 229c6d3aaa4SStephen Smalley result |= 1<<i; 230c6d3aaa4SStephen Smalley } 231c6d3aaa4SStephen Smalley avd->allowed = result; 232c6d3aaa4SStephen Smalley 233c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) 234c6d3aaa4SStephen Smalley if (avd->auditallow & current_mapping[tclass].perms[i]) 235c6d3aaa4SStephen Smalley result |= 1<<i; 236c6d3aaa4SStephen Smalley avd->auditallow = result; 237c6d3aaa4SStephen Smalley 238c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) { 239c6d3aaa4SStephen Smalley if (avd->auditdeny & current_mapping[tclass].perms[i]) 240c6d3aaa4SStephen Smalley result |= 1<<i; 241c6d3aaa4SStephen Smalley if (!allow_unknown && !current_mapping[tclass].perms[i]) 242c6d3aaa4SStephen Smalley result |= 1<<i; 243c6d3aaa4SStephen Smalley } 2440bce9527SEric Paris /* 2450bce9527SEric Paris * In case the kernel has a bug and requests a permission 2460bce9527SEric Paris * between num_perms and the maximum permission number, we 2470bce9527SEric Paris * should audit that denial 2480bce9527SEric Paris */ 2490bce9527SEric Paris for (; i < (sizeof(u32)*8); i++) 2500bce9527SEric Paris result |= 1<<i; 251c6d3aaa4SStephen Smalley avd->auditdeny = result; 252c6d3aaa4SStephen Smalley } 253c6d3aaa4SStephen Smalley } 254c6d3aaa4SStephen Smalley 2550719aaf5SGuido Trentalancia int security_mls_enabled(void) 2560719aaf5SGuido Trentalancia { 2570719aaf5SGuido Trentalancia return policydb.mls_enabled; 2580719aaf5SGuido Trentalancia } 259c6d3aaa4SStephen Smalley 2601da177e4SLinus Torvalds /* 2611da177e4SLinus Torvalds * Return the boolean value of a constraint expression 2621da177e4SLinus Torvalds * when it is applied to the specified source and target 2631da177e4SLinus Torvalds * security contexts. 2641da177e4SLinus Torvalds * 2651da177e4SLinus Torvalds * xcontext is a special beast... It is used by the validatetrans rules 2661da177e4SLinus Torvalds * only. For these rules, scontext is the context before the transition, 2671da177e4SLinus Torvalds * tcontext is the context after the transition, and xcontext is the context 2681da177e4SLinus Torvalds * of the process performing the transition. All other callers of 2691da177e4SLinus Torvalds * constraint_expr_eval should pass in NULL for xcontext. 2701da177e4SLinus Torvalds */ 2711da177e4SLinus Torvalds static int constraint_expr_eval(struct context *scontext, 2721da177e4SLinus Torvalds struct context *tcontext, 2731da177e4SLinus Torvalds struct context *xcontext, 2741da177e4SLinus Torvalds struct constraint_expr *cexpr) 2751da177e4SLinus Torvalds { 2761da177e4SLinus Torvalds u32 val1, val2; 2771da177e4SLinus Torvalds struct context *c; 2781da177e4SLinus Torvalds struct role_datum *r1, *r2; 2791da177e4SLinus Torvalds struct mls_level *l1, *l2; 2801da177e4SLinus Torvalds struct constraint_expr *e; 2811da177e4SLinus Torvalds int s[CEXPR_MAXDEPTH]; 2821da177e4SLinus Torvalds int sp = -1; 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds for (e = cexpr; e; e = e->next) { 2851da177e4SLinus Torvalds switch (e->expr_type) { 2861da177e4SLinus Torvalds case CEXPR_NOT: 2871da177e4SLinus Torvalds BUG_ON(sp < 0); 2881da177e4SLinus Torvalds s[sp] = !s[sp]; 2891da177e4SLinus Torvalds break; 2901da177e4SLinus Torvalds case CEXPR_AND: 2911da177e4SLinus Torvalds BUG_ON(sp < 1); 2921da177e4SLinus Torvalds sp--; 2931da177e4SLinus Torvalds s[sp] &= s[sp + 1]; 2941da177e4SLinus Torvalds break; 2951da177e4SLinus Torvalds case CEXPR_OR: 2961da177e4SLinus Torvalds BUG_ON(sp < 1); 2971da177e4SLinus Torvalds sp--; 2981da177e4SLinus Torvalds s[sp] |= s[sp + 1]; 2991da177e4SLinus Torvalds break; 3001da177e4SLinus Torvalds case CEXPR_ATTR: 3011da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH - 1)) 3021da177e4SLinus Torvalds return 0; 3031da177e4SLinus Torvalds switch (e->attr) { 3041da177e4SLinus Torvalds case CEXPR_USER: 3051da177e4SLinus Torvalds val1 = scontext->user; 3061da177e4SLinus Torvalds val2 = tcontext->user; 3071da177e4SLinus Torvalds break; 3081da177e4SLinus Torvalds case CEXPR_TYPE: 3091da177e4SLinus Torvalds val1 = scontext->type; 3101da177e4SLinus Torvalds val2 = tcontext->type; 3111da177e4SLinus Torvalds break; 3121da177e4SLinus Torvalds case CEXPR_ROLE: 3131da177e4SLinus Torvalds val1 = scontext->role; 3141da177e4SLinus Torvalds val2 = tcontext->role; 3151da177e4SLinus Torvalds r1 = policydb.role_val_to_struct[val1 - 1]; 3161da177e4SLinus Torvalds r2 = policydb.role_val_to_struct[val2 - 1]; 3171da177e4SLinus Torvalds switch (e->op) { 3181da177e4SLinus Torvalds case CEXPR_DOM: 3191da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r1->dominates, 3201da177e4SLinus Torvalds val2 - 1); 3211da177e4SLinus Torvalds continue; 3221da177e4SLinus Torvalds case CEXPR_DOMBY: 3231da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r2->dominates, 3241da177e4SLinus Torvalds val1 - 1); 3251da177e4SLinus Torvalds continue; 3261da177e4SLinus Torvalds case CEXPR_INCOMP: 3271da177e4SLinus Torvalds s[++sp] = (!ebitmap_get_bit(&r1->dominates, 3281da177e4SLinus Torvalds val2 - 1) && 3291da177e4SLinus Torvalds !ebitmap_get_bit(&r2->dominates, 3301da177e4SLinus Torvalds val1 - 1)); 3311da177e4SLinus Torvalds continue; 3321da177e4SLinus Torvalds default: 3331da177e4SLinus Torvalds break; 3341da177e4SLinus Torvalds } 3351da177e4SLinus Torvalds break; 3361da177e4SLinus Torvalds case CEXPR_L1L2: 3371da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3381da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 3391da177e4SLinus Torvalds goto mls_ops; 3401da177e4SLinus Torvalds case CEXPR_L1H2: 3411da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3421da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3431da177e4SLinus Torvalds goto mls_ops; 3441da177e4SLinus Torvalds case CEXPR_H1L2: 3451da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 3461da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 3471da177e4SLinus Torvalds goto mls_ops; 3481da177e4SLinus Torvalds case CEXPR_H1H2: 3491da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 3501da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3511da177e4SLinus Torvalds goto mls_ops; 3521da177e4SLinus Torvalds case CEXPR_L1H1: 3531da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3541da177e4SLinus Torvalds l2 = &(scontext->range.level[1]); 3551da177e4SLinus Torvalds goto mls_ops; 3561da177e4SLinus Torvalds case CEXPR_L2H2: 3571da177e4SLinus Torvalds l1 = &(tcontext->range.level[0]); 3581da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3591da177e4SLinus Torvalds goto mls_ops; 3601da177e4SLinus Torvalds mls_ops: 3611da177e4SLinus Torvalds switch (e->op) { 3621da177e4SLinus Torvalds case CEXPR_EQ: 3631da177e4SLinus Torvalds s[++sp] = mls_level_eq(l1, l2); 3641da177e4SLinus Torvalds continue; 3651da177e4SLinus Torvalds case CEXPR_NEQ: 3661da177e4SLinus Torvalds s[++sp] = !mls_level_eq(l1, l2); 3671da177e4SLinus Torvalds continue; 3681da177e4SLinus Torvalds case CEXPR_DOM: 3691da177e4SLinus Torvalds s[++sp] = mls_level_dom(l1, l2); 3701da177e4SLinus Torvalds continue; 3711da177e4SLinus Torvalds case CEXPR_DOMBY: 3721da177e4SLinus Torvalds s[++sp] = mls_level_dom(l2, l1); 3731da177e4SLinus Torvalds continue; 3741da177e4SLinus Torvalds case CEXPR_INCOMP: 3751da177e4SLinus Torvalds s[++sp] = mls_level_incomp(l2, l1); 3761da177e4SLinus Torvalds continue; 3771da177e4SLinus Torvalds default: 3781da177e4SLinus Torvalds BUG(); 3791da177e4SLinus Torvalds return 0; 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds break; 3821da177e4SLinus Torvalds default: 3831da177e4SLinus Torvalds BUG(); 3841da177e4SLinus Torvalds return 0; 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds 3871da177e4SLinus Torvalds switch (e->op) { 3881da177e4SLinus Torvalds case CEXPR_EQ: 3891da177e4SLinus Torvalds s[++sp] = (val1 == val2); 3901da177e4SLinus Torvalds break; 3911da177e4SLinus Torvalds case CEXPR_NEQ: 3921da177e4SLinus Torvalds s[++sp] = (val1 != val2); 3931da177e4SLinus Torvalds break; 3941da177e4SLinus Torvalds default: 3951da177e4SLinus Torvalds BUG(); 3961da177e4SLinus Torvalds return 0; 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds break; 3991da177e4SLinus Torvalds case CEXPR_NAMES: 4001da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH-1)) 4011da177e4SLinus Torvalds return 0; 4021da177e4SLinus Torvalds c = scontext; 4031da177e4SLinus Torvalds if (e->attr & CEXPR_TARGET) 4041da177e4SLinus Torvalds c = tcontext; 4051da177e4SLinus Torvalds else if (e->attr & CEXPR_XTARGET) { 4061da177e4SLinus Torvalds c = xcontext; 4071da177e4SLinus Torvalds if (!c) { 4081da177e4SLinus Torvalds BUG(); 4091da177e4SLinus Torvalds return 0; 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds if (e->attr & CEXPR_USER) 4131da177e4SLinus Torvalds val1 = c->user; 4141da177e4SLinus Torvalds else if (e->attr & CEXPR_ROLE) 4151da177e4SLinus Torvalds val1 = c->role; 4161da177e4SLinus Torvalds else if (e->attr & CEXPR_TYPE) 4171da177e4SLinus Torvalds val1 = c->type; 4181da177e4SLinus Torvalds else { 4191da177e4SLinus Torvalds BUG(); 4201da177e4SLinus Torvalds return 0; 4211da177e4SLinus Torvalds } 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds switch (e->op) { 4241da177e4SLinus Torvalds case CEXPR_EQ: 4251da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); 4261da177e4SLinus Torvalds break; 4271da177e4SLinus Torvalds case CEXPR_NEQ: 4281da177e4SLinus Torvalds s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); 4291da177e4SLinus Torvalds break; 4301da177e4SLinus Torvalds default: 4311da177e4SLinus Torvalds BUG(); 4321da177e4SLinus Torvalds return 0; 4331da177e4SLinus Torvalds } 4341da177e4SLinus Torvalds break; 4351da177e4SLinus Torvalds default: 4361da177e4SLinus Torvalds BUG(); 4371da177e4SLinus Torvalds return 0; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds } 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds BUG_ON(sp != 0); 4421da177e4SLinus Torvalds return s[0]; 4431da177e4SLinus Torvalds } 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds /* 44644c2d9bdSKaiGai Kohei * security_dump_masked_av - dumps masked permissions during 44744c2d9bdSKaiGai Kohei * security_compute_av due to RBAC, MLS/Constraint and Type bounds. 44844c2d9bdSKaiGai Kohei */ 44944c2d9bdSKaiGai Kohei static int dump_masked_av_helper(void *k, void *d, void *args) 45044c2d9bdSKaiGai Kohei { 45144c2d9bdSKaiGai Kohei struct perm_datum *pdatum = d; 45244c2d9bdSKaiGai Kohei char **permission_names = args; 45344c2d9bdSKaiGai Kohei 45444c2d9bdSKaiGai Kohei BUG_ON(pdatum->value < 1 || pdatum->value > 32); 45544c2d9bdSKaiGai Kohei 45644c2d9bdSKaiGai Kohei permission_names[pdatum->value - 1] = (char *)k; 45744c2d9bdSKaiGai Kohei 45844c2d9bdSKaiGai Kohei return 0; 45944c2d9bdSKaiGai Kohei } 46044c2d9bdSKaiGai Kohei 46144c2d9bdSKaiGai Kohei static void security_dump_masked_av(struct context *scontext, 46244c2d9bdSKaiGai Kohei struct context *tcontext, 46344c2d9bdSKaiGai Kohei u16 tclass, 46444c2d9bdSKaiGai Kohei u32 permissions, 46544c2d9bdSKaiGai Kohei const char *reason) 46644c2d9bdSKaiGai Kohei { 46744c2d9bdSKaiGai Kohei struct common_datum *common_dat; 46844c2d9bdSKaiGai Kohei struct class_datum *tclass_dat; 46944c2d9bdSKaiGai Kohei struct audit_buffer *ab; 47044c2d9bdSKaiGai Kohei char *tclass_name; 47144c2d9bdSKaiGai Kohei char *scontext_name = NULL; 47244c2d9bdSKaiGai Kohei char *tcontext_name = NULL; 47344c2d9bdSKaiGai Kohei char *permission_names[32]; 4742da5d31bSJames Morris int index; 4752da5d31bSJames Morris u32 length; 47644c2d9bdSKaiGai Kohei bool need_comma = false; 47744c2d9bdSKaiGai Kohei 47844c2d9bdSKaiGai Kohei if (!permissions) 47944c2d9bdSKaiGai Kohei return; 48044c2d9bdSKaiGai Kohei 481ac76c05bSEric Paris tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1); 48244c2d9bdSKaiGai Kohei tclass_dat = policydb.class_val_to_struct[tclass - 1]; 48344c2d9bdSKaiGai Kohei common_dat = tclass_dat->comdatum; 48444c2d9bdSKaiGai Kohei 48544c2d9bdSKaiGai Kohei /* init permission_names */ 48644c2d9bdSKaiGai Kohei if (common_dat && 48744c2d9bdSKaiGai Kohei hashtab_map(common_dat->permissions.table, 48844c2d9bdSKaiGai Kohei dump_masked_av_helper, permission_names) < 0) 48944c2d9bdSKaiGai Kohei goto out; 49044c2d9bdSKaiGai Kohei 49144c2d9bdSKaiGai Kohei if (hashtab_map(tclass_dat->permissions.table, 49244c2d9bdSKaiGai Kohei dump_masked_av_helper, permission_names) < 0) 49344c2d9bdSKaiGai Kohei goto out; 49444c2d9bdSKaiGai Kohei 49544c2d9bdSKaiGai Kohei /* get scontext/tcontext in text form */ 49644c2d9bdSKaiGai Kohei if (context_struct_to_string(scontext, 49744c2d9bdSKaiGai Kohei &scontext_name, &length) < 0) 49844c2d9bdSKaiGai Kohei goto out; 49944c2d9bdSKaiGai Kohei 50044c2d9bdSKaiGai Kohei if (context_struct_to_string(tcontext, 50144c2d9bdSKaiGai Kohei &tcontext_name, &length) < 0) 50244c2d9bdSKaiGai Kohei goto out; 50344c2d9bdSKaiGai Kohei 50444c2d9bdSKaiGai Kohei /* audit a message */ 50544c2d9bdSKaiGai Kohei ab = audit_log_start(current->audit_context, 50644c2d9bdSKaiGai Kohei GFP_ATOMIC, AUDIT_SELINUX_ERR); 50744c2d9bdSKaiGai Kohei if (!ab) 50844c2d9bdSKaiGai Kohei goto out; 50944c2d9bdSKaiGai Kohei 51044c2d9bdSKaiGai Kohei audit_log_format(ab, "op=security_compute_av reason=%s " 51144c2d9bdSKaiGai Kohei "scontext=%s tcontext=%s tclass=%s perms=", 51244c2d9bdSKaiGai Kohei reason, scontext_name, tcontext_name, tclass_name); 51344c2d9bdSKaiGai Kohei 51444c2d9bdSKaiGai Kohei for (index = 0; index < 32; index++) { 51544c2d9bdSKaiGai Kohei u32 mask = (1 << index); 51644c2d9bdSKaiGai Kohei 51744c2d9bdSKaiGai Kohei if ((mask & permissions) == 0) 51844c2d9bdSKaiGai Kohei continue; 51944c2d9bdSKaiGai Kohei 52044c2d9bdSKaiGai Kohei audit_log_format(ab, "%s%s", 52144c2d9bdSKaiGai Kohei need_comma ? "," : "", 52244c2d9bdSKaiGai Kohei permission_names[index] 52344c2d9bdSKaiGai Kohei ? permission_names[index] : "????"); 52444c2d9bdSKaiGai Kohei need_comma = true; 52544c2d9bdSKaiGai Kohei } 52644c2d9bdSKaiGai Kohei audit_log_end(ab); 52744c2d9bdSKaiGai Kohei out: 52844c2d9bdSKaiGai Kohei /* release scontext/tcontext */ 52944c2d9bdSKaiGai Kohei kfree(tcontext_name); 53044c2d9bdSKaiGai Kohei kfree(scontext_name); 53144c2d9bdSKaiGai Kohei 53244c2d9bdSKaiGai Kohei return; 53344c2d9bdSKaiGai Kohei } 53444c2d9bdSKaiGai Kohei 53544c2d9bdSKaiGai Kohei /* 536d9250deaSKaiGai Kohei * security_boundary_permission - drops violated permissions 537d9250deaSKaiGai Kohei * on boundary constraint. 538d9250deaSKaiGai Kohei */ 539d9250deaSKaiGai Kohei static void type_attribute_bounds_av(struct context *scontext, 540d9250deaSKaiGai Kohei struct context *tcontext, 541d9250deaSKaiGai Kohei u16 tclass, 542d9250deaSKaiGai Kohei struct av_decision *avd) 543d9250deaSKaiGai Kohei { 5442ae3ba39SKaiGai Kohei struct context lo_scontext; 5452ae3ba39SKaiGai Kohei struct context lo_tcontext; 5462ae3ba39SKaiGai Kohei struct av_decision lo_avd; 54723bdecb0SEric Paris struct type_datum *source; 54823bdecb0SEric Paris struct type_datum *target; 5492ae3ba39SKaiGai Kohei u32 masked = 0; 550d9250deaSKaiGai Kohei 55123bdecb0SEric Paris source = flex_array_get_ptr(policydb.type_val_to_struct_array, 55223bdecb0SEric Paris scontext->type - 1); 55323bdecb0SEric Paris BUG_ON(!source); 55423bdecb0SEric Paris 55523bdecb0SEric Paris target = flex_array_get_ptr(policydb.type_val_to_struct_array, 55623bdecb0SEric Paris tcontext->type - 1); 55723bdecb0SEric Paris BUG_ON(!target); 55823bdecb0SEric Paris 559d9250deaSKaiGai Kohei if (source->bounds) { 560d9250deaSKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd)); 561d9250deaSKaiGai Kohei 562d9250deaSKaiGai Kohei memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); 563d9250deaSKaiGai Kohei lo_scontext.type = source->bounds; 564d9250deaSKaiGai Kohei 565d9250deaSKaiGai Kohei context_struct_compute_av(&lo_scontext, 566d9250deaSKaiGai Kohei tcontext, 567d9250deaSKaiGai Kohei tclass, 568d9250deaSKaiGai Kohei &lo_avd); 569d9250deaSKaiGai Kohei if ((lo_avd.allowed & avd->allowed) == avd->allowed) 570d9250deaSKaiGai Kohei return; /* no masked permission */ 571d9250deaSKaiGai Kohei masked = ~lo_avd.allowed & avd->allowed; 5722ae3ba39SKaiGai Kohei } 573d9250deaSKaiGai Kohei 5742ae3ba39SKaiGai Kohei if (target->bounds) { 5752ae3ba39SKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd)); 5762ae3ba39SKaiGai Kohei 5772ae3ba39SKaiGai Kohei memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); 5782ae3ba39SKaiGai Kohei lo_tcontext.type = target->bounds; 5792ae3ba39SKaiGai Kohei 5802ae3ba39SKaiGai Kohei context_struct_compute_av(scontext, 5812ae3ba39SKaiGai Kohei &lo_tcontext, 5822ae3ba39SKaiGai Kohei tclass, 5832ae3ba39SKaiGai Kohei &lo_avd); 5842ae3ba39SKaiGai Kohei if ((lo_avd.allowed & avd->allowed) == avd->allowed) 5852ae3ba39SKaiGai Kohei return; /* no masked permission */ 5862ae3ba39SKaiGai Kohei masked = ~lo_avd.allowed & avd->allowed; 5872ae3ba39SKaiGai Kohei } 5882ae3ba39SKaiGai Kohei 5892ae3ba39SKaiGai Kohei if (source->bounds && target->bounds) { 5902ae3ba39SKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd)); 5912ae3ba39SKaiGai Kohei /* 5922ae3ba39SKaiGai Kohei * lo_scontext and lo_tcontext are already 5932ae3ba39SKaiGai Kohei * set up. 5942ae3ba39SKaiGai Kohei */ 5952ae3ba39SKaiGai Kohei 5962ae3ba39SKaiGai Kohei context_struct_compute_av(&lo_scontext, 5972ae3ba39SKaiGai Kohei &lo_tcontext, 5982ae3ba39SKaiGai Kohei tclass, 5992ae3ba39SKaiGai Kohei &lo_avd); 6002ae3ba39SKaiGai Kohei if ((lo_avd.allowed & avd->allowed) == avd->allowed) 6012ae3ba39SKaiGai Kohei return; /* no masked permission */ 6022ae3ba39SKaiGai Kohei masked = ~lo_avd.allowed & avd->allowed; 6032ae3ba39SKaiGai Kohei } 6042ae3ba39SKaiGai Kohei 6052ae3ba39SKaiGai Kohei if (masked) { 606d9250deaSKaiGai Kohei /* mask violated permissions */ 607d9250deaSKaiGai Kohei avd->allowed &= ~masked; 608d9250deaSKaiGai Kohei 60944c2d9bdSKaiGai Kohei /* audit masked permissions */ 61044c2d9bdSKaiGai Kohei security_dump_masked_av(scontext, tcontext, 61144c2d9bdSKaiGai Kohei tclass, masked, "bounds"); 612d9250deaSKaiGai Kohei } 613d9250deaSKaiGai Kohei } 614d9250deaSKaiGai Kohei 615d9250deaSKaiGai Kohei /* 6161da177e4SLinus Torvalds * Compute access vectors based on a context structure pair for 6171da177e4SLinus Torvalds * the permissions in a particular class. 6181da177e4SLinus Torvalds */ 61919439d05SStephen Smalley static void context_struct_compute_av(struct context *scontext, 6201da177e4SLinus Torvalds struct context *tcontext, 6211da177e4SLinus Torvalds u16 tclass, 6221da177e4SLinus Torvalds struct av_decision *avd) 6231da177e4SLinus Torvalds { 6241da177e4SLinus Torvalds struct constraint_node *constraint; 6251da177e4SLinus Torvalds struct role_allow *ra; 6261da177e4SLinus Torvalds struct avtab_key avkey; 627782ebb99SStephen Smalley struct avtab_node *node; 6281da177e4SLinus Torvalds struct class_datum *tclass_datum; 629782ebb99SStephen Smalley struct ebitmap *sattr, *tattr; 630782ebb99SStephen Smalley struct ebitmap_node *snode, *tnode; 631782ebb99SStephen Smalley unsigned int i, j; 6321da177e4SLinus Torvalds 6331da177e4SLinus Torvalds avd->allowed = 0; 6341da177e4SLinus Torvalds avd->auditallow = 0; 6351da177e4SLinus Torvalds avd->auditdeny = 0xffffffff; 6361da177e4SLinus Torvalds 637c6d3aaa4SStephen Smalley if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { 638c6d3aaa4SStephen Smalley if (printk_ratelimit()) 639c6d3aaa4SStephen Smalley printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); 64019439d05SStephen Smalley return; 641c6d3aaa4SStephen Smalley } 6423f12070eSEric Paris 6433f12070eSEric Paris tclass_datum = policydb.class_val_to_struct[tclass - 1]; 6443f12070eSEric Paris 6453f12070eSEric Paris /* 6461da177e4SLinus Torvalds * If a specific type enforcement rule was defined for 6471da177e4SLinus Torvalds * this permission check, then use it. 6481da177e4SLinus Torvalds */ 6491da177e4SLinus Torvalds avkey.target_class = tclass; 650782ebb99SStephen Smalley avkey.specified = AVTAB_AV; 6516371dcd3SEric Paris sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); 6526371dcd3SEric Paris BUG_ON(!sattr); 6536371dcd3SEric Paris tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); 6546371dcd3SEric Paris BUG_ON(!tattr); 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; 659782ebb99SStephen Smalley for (node = avtab_search_node(&policydb.te_avtab, &avkey); 660dbc74c65SVesa-Matti Kari node; 661782ebb99SStephen Smalley node = avtab_search_node_next(node, avkey.specified)) { 662782ebb99SStephen Smalley if (node->key.specified == AVTAB_ALLOWED) 663782ebb99SStephen Smalley avd->allowed |= node->datum.data; 664782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITALLOW) 665782ebb99SStephen Smalley avd->auditallow |= node->datum.data; 666782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITDENY) 667782ebb99SStephen Smalley avd->auditdeny &= node->datum.data; 6681da177e4SLinus Torvalds } 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds /* Check conditional av table for additional permissions */ 6711da177e4SLinus Torvalds cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); 6721da177e4SLinus Torvalds 673782ebb99SStephen Smalley } 674782ebb99SStephen Smalley } 675782ebb99SStephen Smalley 6761da177e4SLinus Torvalds /* 6771da177e4SLinus Torvalds * Remove any permissions prohibited by a constraint (this includes 6781da177e4SLinus Torvalds * the MLS policy). 6791da177e4SLinus Torvalds */ 6801da177e4SLinus Torvalds constraint = tclass_datum->constraints; 6811da177e4SLinus Torvalds while (constraint) { 6821da177e4SLinus Torvalds if ((constraint->permissions & (avd->allowed)) && 6831da177e4SLinus Torvalds !constraint_expr_eval(scontext, tcontext, NULL, 6841da177e4SLinus Torvalds constraint->expr)) { 685caabbdc0SKaiGai Kohei avd->allowed &= ~(constraint->permissions); 6861da177e4SLinus Torvalds } 6871da177e4SLinus Torvalds constraint = constraint->next; 6881da177e4SLinus Torvalds } 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds /* 6911da177e4SLinus Torvalds * If checking process transition permission and the 6921da177e4SLinus Torvalds * role is changing, then check the (current_role, new_role) 6931da177e4SLinus Torvalds * pair. 6941da177e4SLinus Torvalds */ 695c6d3aaa4SStephen Smalley if (tclass == policydb.process_class && 696c6d3aaa4SStephen Smalley (avd->allowed & policydb.process_trans_perms) && 6971da177e4SLinus Torvalds scontext->role != tcontext->role) { 6981da177e4SLinus Torvalds for (ra = policydb.role_allow; ra; ra = ra->next) { 6991da177e4SLinus Torvalds if (scontext->role == ra->role && 7001da177e4SLinus Torvalds tcontext->role == ra->new_role) 7011da177e4SLinus Torvalds break; 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds if (!ra) 704c6d3aaa4SStephen Smalley avd->allowed &= ~policydb.process_trans_perms; 7051da177e4SLinus Torvalds } 7061da177e4SLinus Torvalds 707d9250deaSKaiGai Kohei /* 708d9250deaSKaiGai Kohei * If the given source and target types have boundary 709d9250deaSKaiGai Kohei * constraint, lazy checks have to mask any violated 710d9250deaSKaiGai Kohei * permission and notice it to userspace via audit. 711d9250deaSKaiGai Kohei */ 712d9250deaSKaiGai Kohei type_attribute_bounds_av(scontext, tcontext, 71319439d05SStephen Smalley tclass, avd); 71422df4adbSStephen Smalley } 71522df4adbSStephen Smalley 7161da177e4SLinus Torvalds static int security_validtrans_handle_fail(struct context *ocontext, 7171da177e4SLinus Torvalds struct context *ncontext, 7181da177e4SLinus Torvalds struct context *tcontext, 7191da177e4SLinus Torvalds u16 tclass) 7201da177e4SLinus Torvalds { 7211da177e4SLinus Torvalds char *o = NULL, *n = NULL, *t = NULL; 7221da177e4SLinus Torvalds u32 olen, nlen, tlen; 7231da177e4SLinus Torvalds 7244b02b524SEric Paris if (context_struct_to_string(ocontext, &o, &olen)) 7251da177e4SLinus Torvalds goto out; 7264b02b524SEric Paris if (context_struct_to_string(ncontext, &n, &nlen)) 7271da177e4SLinus Torvalds goto out; 7284b02b524SEric Paris if (context_struct_to_string(tcontext, &t, &tlen)) 7291da177e4SLinus Torvalds goto out; 7309ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 7311da177e4SLinus Torvalds "security_validate_transition: denied for" 7321da177e4SLinus Torvalds " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", 733ac76c05bSEric Paris o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); 7341da177e4SLinus Torvalds out: 7351da177e4SLinus Torvalds kfree(o); 7361da177e4SLinus Torvalds kfree(n); 7371da177e4SLinus Torvalds kfree(t); 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds if (!selinux_enforcing) 7401da177e4SLinus Torvalds return 0; 7411da177e4SLinus Torvalds return -EPERM; 7421da177e4SLinus Torvalds } 7431da177e4SLinus Torvalds 7441da177e4SLinus Torvalds int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, 745c6d3aaa4SStephen Smalley u16 orig_tclass) 7461da177e4SLinus Torvalds { 7471da177e4SLinus Torvalds struct context *ocontext; 7481da177e4SLinus Torvalds struct context *ncontext; 7491da177e4SLinus Torvalds struct context *tcontext; 7501da177e4SLinus Torvalds struct class_datum *tclass_datum; 7511da177e4SLinus Torvalds struct constraint_node *constraint; 752c6d3aaa4SStephen Smalley u16 tclass; 7531da177e4SLinus Torvalds int rc = 0; 7541da177e4SLinus Torvalds 7551da177e4SLinus Torvalds if (!ss_initialized) 7561da177e4SLinus Torvalds return 0; 7571da177e4SLinus Torvalds 7580804d113SJames Morris read_lock(&policy_rwlock); 7591da177e4SLinus Torvalds 760c6d3aaa4SStephen Smalley tclass = unmap_class(orig_tclass); 761c6d3aaa4SStephen Smalley 7621da177e4SLinus Torvalds if (!tclass || tclass > policydb.p_classes.nprim) { 763744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", 764744ba35eSEric Paris __func__, tclass); 7651da177e4SLinus Torvalds rc = -EINVAL; 7661da177e4SLinus Torvalds goto out; 7671da177e4SLinus Torvalds } 7681da177e4SLinus Torvalds tclass_datum = policydb.class_val_to_struct[tclass - 1]; 7691da177e4SLinus Torvalds 7701da177e4SLinus Torvalds ocontext = sidtab_search(&sidtab, oldsid); 7711da177e4SLinus Torvalds if (!ocontext) { 772744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 773744ba35eSEric Paris __func__, oldsid); 7741da177e4SLinus Torvalds rc = -EINVAL; 7751da177e4SLinus Torvalds goto out; 7761da177e4SLinus Torvalds } 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds ncontext = sidtab_search(&sidtab, newsid); 7791da177e4SLinus Torvalds if (!ncontext) { 780744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 781744ba35eSEric Paris __func__, newsid); 7821da177e4SLinus Torvalds rc = -EINVAL; 7831da177e4SLinus Torvalds goto out; 7841da177e4SLinus Torvalds } 7851da177e4SLinus Torvalds 7861da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tasksid); 7871da177e4SLinus Torvalds if (!tcontext) { 788744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 789744ba35eSEric Paris __func__, tasksid); 7901da177e4SLinus Torvalds rc = -EINVAL; 7911da177e4SLinus Torvalds goto out; 7921da177e4SLinus Torvalds } 7931da177e4SLinus Torvalds 7941da177e4SLinus Torvalds constraint = tclass_datum->validatetrans; 7951da177e4SLinus Torvalds while (constraint) { 7961da177e4SLinus Torvalds if (!constraint_expr_eval(ocontext, ncontext, tcontext, 7971da177e4SLinus Torvalds constraint->expr)) { 7981da177e4SLinus Torvalds rc = security_validtrans_handle_fail(ocontext, ncontext, 7991da177e4SLinus Torvalds tcontext, tclass); 8001da177e4SLinus Torvalds goto out; 8011da177e4SLinus Torvalds } 8021da177e4SLinus Torvalds constraint = constraint->next; 8031da177e4SLinus Torvalds } 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds out: 8060804d113SJames Morris read_unlock(&policy_rwlock); 8071da177e4SLinus Torvalds return rc; 8081da177e4SLinus Torvalds } 8091da177e4SLinus Torvalds 810d9250deaSKaiGai Kohei /* 811d9250deaSKaiGai Kohei * security_bounded_transition - check whether the given 812d9250deaSKaiGai Kohei * transition is directed to bounded, or not. 813d9250deaSKaiGai Kohei * It returns 0, if @newsid is bounded by @oldsid. 814d9250deaSKaiGai Kohei * Otherwise, it returns error code. 815d9250deaSKaiGai Kohei * 816d9250deaSKaiGai Kohei * @oldsid : current security identifier 817d9250deaSKaiGai Kohei * @newsid : destinated security identifier 818d9250deaSKaiGai Kohei */ 819d9250deaSKaiGai Kohei int security_bounded_transition(u32 old_sid, u32 new_sid) 820d9250deaSKaiGai Kohei { 821d9250deaSKaiGai Kohei struct context *old_context, *new_context; 822d9250deaSKaiGai Kohei struct type_datum *type; 823d9250deaSKaiGai Kohei int index; 8244b02b524SEric Paris int rc; 825d9250deaSKaiGai Kohei 826d9250deaSKaiGai Kohei read_lock(&policy_rwlock); 827d9250deaSKaiGai Kohei 8284b02b524SEric Paris rc = -EINVAL; 829d9250deaSKaiGai Kohei old_context = sidtab_search(&sidtab, old_sid); 830d9250deaSKaiGai Kohei if (!old_context) { 831d9250deaSKaiGai Kohei printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", 832d9250deaSKaiGai Kohei __func__, old_sid); 833d9250deaSKaiGai Kohei goto out; 834d9250deaSKaiGai Kohei } 835d9250deaSKaiGai Kohei 8364b02b524SEric Paris rc = -EINVAL; 837d9250deaSKaiGai Kohei new_context = sidtab_search(&sidtab, new_sid); 838d9250deaSKaiGai Kohei if (!new_context) { 839d9250deaSKaiGai Kohei printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", 840d9250deaSKaiGai Kohei __func__, new_sid); 841d9250deaSKaiGai Kohei goto out; 842d9250deaSKaiGai Kohei } 843d9250deaSKaiGai Kohei 844d9250deaSKaiGai Kohei rc = 0; 8454b02b524SEric Paris /* type/domain unchanged */ 8464b02b524SEric Paris if (old_context->type == new_context->type) 847d9250deaSKaiGai Kohei goto out; 848d9250deaSKaiGai Kohei 849d9250deaSKaiGai Kohei index = new_context->type; 850d9250deaSKaiGai Kohei while (true) { 85123bdecb0SEric Paris type = flex_array_get_ptr(policydb.type_val_to_struct_array, 85223bdecb0SEric Paris index - 1); 853d9250deaSKaiGai Kohei BUG_ON(!type); 854d9250deaSKaiGai Kohei 855d9250deaSKaiGai Kohei /* not bounded anymore */ 856d9250deaSKaiGai Kohei rc = -EPERM; 8574b02b524SEric Paris if (!type->bounds) 858d9250deaSKaiGai Kohei break; 859d9250deaSKaiGai Kohei 860d9250deaSKaiGai Kohei /* @newsid is bounded by @oldsid */ 861d9250deaSKaiGai Kohei rc = 0; 8624b02b524SEric Paris if (type->bounds == old_context->type) 863d9250deaSKaiGai Kohei break; 8644b02b524SEric Paris 865d9250deaSKaiGai Kohei index = type->bounds; 866d9250deaSKaiGai Kohei } 86744c2d9bdSKaiGai Kohei 86844c2d9bdSKaiGai Kohei if (rc) { 86944c2d9bdSKaiGai Kohei char *old_name = NULL; 87044c2d9bdSKaiGai Kohei char *new_name = NULL; 8712da5d31bSJames Morris u32 length; 87244c2d9bdSKaiGai Kohei 87344c2d9bdSKaiGai Kohei if (!context_struct_to_string(old_context, 87444c2d9bdSKaiGai Kohei &old_name, &length) && 87544c2d9bdSKaiGai Kohei !context_struct_to_string(new_context, 87644c2d9bdSKaiGai Kohei &new_name, &length)) { 87744c2d9bdSKaiGai Kohei audit_log(current->audit_context, 87844c2d9bdSKaiGai Kohei GFP_ATOMIC, AUDIT_SELINUX_ERR, 87944c2d9bdSKaiGai Kohei "op=security_bounded_transition " 88044c2d9bdSKaiGai Kohei "result=denied " 88144c2d9bdSKaiGai Kohei "oldcontext=%s newcontext=%s", 88244c2d9bdSKaiGai Kohei old_name, new_name); 88344c2d9bdSKaiGai Kohei } 88444c2d9bdSKaiGai Kohei kfree(new_name); 88544c2d9bdSKaiGai Kohei kfree(old_name); 88644c2d9bdSKaiGai Kohei } 887d9250deaSKaiGai Kohei out: 888d9250deaSKaiGai Kohei read_unlock(&policy_rwlock); 889d9250deaSKaiGai Kohei 890d9250deaSKaiGai Kohei return rc; 891d9250deaSKaiGai Kohei } 892d9250deaSKaiGai Kohei 89319439d05SStephen Smalley static void avd_init(struct av_decision *avd) 894c6d3aaa4SStephen Smalley { 89519439d05SStephen Smalley avd->allowed = 0; 89619439d05SStephen Smalley avd->auditallow = 0; 89719439d05SStephen Smalley avd->auditdeny = 0xffffffff; 89819439d05SStephen Smalley avd->seqno = latest_granting; 89919439d05SStephen Smalley avd->flags = 0; 900c6d3aaa4SStephen Smalley } 901c6d3aaa4SStephen Smalley 902c6d3aaa4SStephen Smalley 9031da177e4SLinus Torvalds /** 9041da177e4SLinus Torvalds * security_compute_av - Compute access vector decisions. 9051da177e4SLinus Torvalds * @ssid: source security identifier 9061da177e4SLinus Torvalds * @tsid: target security identifier 9071da177e4SLinus Torvalds * @tclass: target security class 9081da177e4SLinus Torvalds * @avd: access vector decisions 9091da177e4SLinus Torvalds * 9101da177e4SLinus Torvalds * Compute a set of access vector decisions based on the 9111da177e4SLinus Torvalds * SID pair (@ssid, @tsid) for the permissions in @tclass. 9121da177e4SLinus Torvalds */ 91319439d05SStephen Smalley void security_compute_av(u32 ssid, 9141da177e4SLinus Torvalds u32 tsid, 915c6d3aaa4SStephen Smalley u16 orig_tclass, 916c6d3aaa4SStephen Smalley struct av_decision *avd) 917c6d3aaa4SStephen Smalley { 918c6d3aaa4SStephen Smalley u16 tclass; 91919439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL; 920c6d3aaa4SStephen Smalley 921b7f3008aSStephen Smalley read_lock(&policy_rwlock); 92219439d05SStephen Smalley avd_init(avd); 923c6d3aaa4SStephen Smalley if (!ss_initialized) 924c6d3aaa4SStephen Smalley goto allow; 925c6d3aaa4SStephen Smalley 92619439d05SStephen Smalley scontext = sidtab_search(&sidtab, ssid); 92719439d05SStephen Smalley if (!scontext) { 92819439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 92919439d05SStephen Smalley __func__, ssid); 93019439d05SStephen Smalley goto out; 93119439d05SStephen Smalley } 93219439d05SStephen Smalley 93319439d05SStephen Smalley /* permissive domain? */ 93419439d05SStephen Smalley if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) 93519439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE; 93619439d05SStephen Smalley 93719439d05SStephen Smalley tcontext = sidtab_search(&sidtab, tsid); 93819439d05SStephen Smalley if (!tcontext) { 93919439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 94019439d05SStephen Smalley __func__, tsid); 94119439d05SStephen Smalley goto out; 94219439d05SStephen Smalley } 94319439d05SStephen Smalley 944c6d3aaa4SStephen Smalley tclass = unmap_class(orig_tclass); 945c6d3aaa4SStephen Smalley if (unlikely(orig_tclass && !tclass)) { 946c6d3aaa4SStephen Smalley if (policydb.allow_unknown) 947c6d3aaa4SStephen Smalley goto allow; 948b7f3008aSStephen Smalley goto out; 949c6d3aaa4SStephen Smalley } 95019439d05SStephen Smalley context_struct_compute_av(scontext, tcontext, tclass, avd); 951c6d3aaa4SStephen Smalley map_decision(orig_tclass, avd, policydb.allow_unknown); 952b7f3008aSStephen Smalley out: 953c6d3aaa4SStephen Smalley read_unlock(&policy_rwlock); 95419439d05SStephen Smalley return; 955c6d3aaa4SStephen Smalley allow: 956c6d3aaa4SStephen Smalley avd->allowed = 0xffffffff; 957b7f3008aSStephen Smalley goto out; 958c6d3aaa4SStephen Smalley } 959c6d3aaa4SStephen Smalley 96019439d05SStephen Smalley void security_compute_av_user(u32 ssid, 961c6d3aaa4SStephen Smalley u32 tsid, 9621da177e4SLinus Torvalds u16 tclass, 9631da177e4SLinus Torvalds struct av_decision *avd) 9641da177e4SLinus Torvalds { 96519439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL; 9661da177e4SLinus Torvalds 9670804d113SJames Morris read_lock(&policy_rwlock); 96819439d05SStephen Smalley avd_init(avd); 96919439d05SStephen Smalley if (!ss_initialized) 97019439d05SStephen Smalley goto allow; 97119439d05SStephen Smalley 97219439d05SStephen Smalley scontext = sidtab_search(&sidtab, ssid); 97319439d05SStephen Smalley if (!scontext) { 97419439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 97519439d05SStephen Smalley __func__, ssid); 97619439d05SStephen Smalley goto out; 97719439d05SStephen Smalley } 97819439d05SStephen Smalley 97919439d05SStephen Smalley /* permissive domain? */ 98019439d05SStephen Smalley if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) 98119439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE; 98219439d05SStephen Smalley 98319439d05SStephen Smalley tcontext = sidtab_search(&sidtab, tsid); 98419439d05SStephen Smalley if (!tcontext) { 98519439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 98619439d05SStephen Smalley __func__, tsid); 98719439d05SStephen Smalley goto out; 98819439d05SStephen Smalley } 98919439d05SStephen Smalley 99019439d05SStephen Smalley if (unlikely(!tclass)) { 99119439d05SStephen Smalley if (policydb.allow_unknown) 99219439d05SStephen Smalley goto allow; 99319439d05SStephen Smalley goto out; 99419439d05SStephen Smalley } 99519439d05SStephen Smalley 99619439d05SStephen Smalley context_struct_compute_av(scontext, tcontext, tclass, avd); 99719439d05SStephen Smalley out: 9980804d113SJames Morris read_unlock(&policy_rwlock); 99919439d05SStephen Smalley return; 100019439d05SStephen Smalley allow: 100119439d05SStephen Smalley avd->allowed = 0xffffffff; 100219439d05SStephen Smalley goto out; 10031da177e4SLinus Torvalds } 10041da177e4SLinus Torvalds 10051da177e4SLinus Torvalds /* 10061da177e4SLinus Torvalds * Write the security context string representation of 10071da177e4SLinus Torvalds * the context structure `context' into a dynamically 10081da177e4SLinus Torvalds * allocated string of the correct size. Set `*scontext' 10091da177e4SLinus Torvalds * to point to this string and set `*scontext_len' to 10101da177e4SLinus Torvalds * the length of the string. 10111da177e4SLinus Torvalds */ 10121da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len) 10131da177e4SLinus Torvalds { 10141da177e4SLinus Torvalds char *scontextp; 10151da177e4SLinus Torvalds 1016d5630b9dSEric Paris if (scontext) 10171da177e4SLinus Torvalds *scontext = NULL; 10181da177e4SLinus Torvalds *scontext_len = 0; 10191da177e4SLinus Torvalds 102012b29f34SStephen Smalley if (context->len) { 102112b29f34SStephen Smalley *scontext_len = context->len; 1022bb7081abSEric Paris if (scontext) { 102312b29f34SStephen Smalley *scontext = kstrdup(context->str, GFP_ATOMIC); 102412b29f34SStephen Smalley if (!(*scontext)) 102512b29f34SStephen Smalley return -ENOMEM; 1026bb7081abSEric Paris } 102712b29f34SStephen Smalley return 0; 102812b29f34SStephen Smalley } 102912b29f34SStephen Smalley 10301da177e4SLinus Torvalds /* Compute the size of the context. */ 1031ac76c05bSEric Paris *scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1; 1032ac76c05bSEric Paris *scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1; 1033ac76c05bSEric Paris *scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1; 10341da177e4SLinus Torvalds *scontext_len += mls_compute_context_len(context); 10351da177e4SLinus Torvalds 1036d5630b9dSEric Paris if (!scontext) 1037d5630b9dSEric Paris return 0; 1038d5630b9dSEric Paris 10391da177e4SLinus Torvalds /* Allocate space for the context; caller must free this space. */ 10401da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 10415d55a345SEric Paris if (!scontextp) 10421da177e4SLinus Torvalds return -ENOMEM; 10431da177e4SLinus Torvalds *scontext = scontextp; 10441da177e4SLinus Torvalds 10451da177e4SLinus Torvalds /* 10461da177e4SLinus Torvalds * Copy the user name, role name and type name into the context. 10471da177e4SLinus Torvalds */ 10481da177e4SLinus Torvalds sprintf(scontextp, "%s:%s:%s", 1049ac76c05bSEric Paris sym_name(&policydb, SYM_USERS, context->user - 1), 1050ac76c05bSEric Paris sym_name(&policydb, SYM_ROLES, context->role - 1), 1051ac76c05bSEric Paris sym_name(&policydb, SYM_TYPES, context->type - 1)); 1052ac76c05bSEric Paris scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1053ac76c05bSEric Paris 1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1054ac76c05bSEric Paris 1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)); 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds mls_sid_to_context(context, &scontextp); 10571da177e4SLinus Torvalds 10581da177e4SLinus Torvalds *scontextp = 0; 10591da177e4SLinus Torvalds 10601da177e4SLinus Torvalds return 0; 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds 10631da177e4SLinus Torvalds #include "initial_sid_to_string.h" 10641da177e4SLinus Torvalds 1065f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid) 1066f0ee2e46SJames Carter { 1067f0ee2e46SJames Carter if (unlikely(sid > SECINITSID_NUM)) 1068f0ee2e46SJames Carter return NULL; 1069f0ee2e46SJames Carter return initial_sid_to_string[sid]; 1070f0ee2e46SJames Carter } 1071f0ee2e46SJames Carter 107212b29f34SStephen Smalley static int security_sid_to_context_core(u32 sid, char **scontext, 107312b29f34SStephen Smalley u32 *scontext_len, int force) 10741da177e4SLinus Torvalds { 10751da177e4SLinus Torvalds struct context *context; 10761da177e4SLinus Torvalds int rc = 0; 10771da177e4SLinus Torvalds 1078d5630b9dSEric Paris if (scontext) 10794f4acf3aSStephen Smalley *scontext = NULL; 10804f4acf3aSStephen Smalley *scontext_len = 0; 10814f4acf3aSStephen Smalley 10821da177e4SLinus Torvalds if (!ss_initialized) { 10831da177e4SLinus Torvalds if (sid <= SECINITSID_NUM) { 10841da177e4SLinus Torvalds char *scontextp; 10851da177e4SLinus Torvalds 10861da177e4SLinus Torvalds *scontext_len = strlen(initial_sid_to_string[sid]) + 1; 1087d5630b9dSEric Paris if (!scontext) 1088d5630b9dSEric Paris goto out; 10891da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 10900cccca06SSerge E. Hallyn if (!scontextp) { 10910cccca06SSerge E. Hallyn rc = -ENOMEM; 10920cccca06SSerge E. Hallyn goto out; 10930cccca06SSerge E. Hallyn } 10941da177e4SLinus Torvalds strcpy(scontextp, initial_sid_to_string[sid]); 10951da177e4SLinus Torvalds *scontext = scontextp; 10961da177e4SLinus Torvalds goto out; 10971da177e4SLinus Torvalds } 1098744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: called before initial " 1099744ba35eSEric Paris "load_policy on unknown SID %d\n", __func__, sid); 11001da177e4SLinus Torvalds rc = -EINVAL; 11011da177e4SLinus Torvalds goto out; 11021da177e4SLinus Torvalds } 11030804d113SJames Morris read_lock(&policy_rwlock); 110412b29f34SStephen Smalley if (force) 110512b29f34SStephen Smalley context = sidtab_search_force(&sidtab, sid); 110612b29f34SStephen Smalley else 11071da177e4SLinus Torvalds context = sidtab_search(&sidtab, sid); 11081da177e4SLinus Torvalds if (!context) { 1109744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1110744ba35eSEric Paris __func__, sid); 11111da177e4SLinus Torvalds rc = -EINVAL; 11121da177e4SLinus Torvalds goto out_unlock; 11131da177e4SLinus Torvalds } 11141da177e4SLinus Torvalds rc = context_struct_to_string(context, scontext, scontext_len); 11151da177e4SLinus Torvalds out_unlock: 11160804d113SJames Morris read_unlock(&policy_rwlock); 11171da177e4SLinus Torvalds out: 11181da177e4SLinus Torvalds return rc; 11191da177e4SLinus Torvalds 11201da177e4SLinus Torvalds } 11211da177e4SLinus Torvalds 112212b29f34SStephen Smalley /** 112312b29f34SStephen Smalley * security_sid_to_context - Obtain a context for a given SID. 112412b29f34SStephen Smalley * @sid: security identifier, SID 112512b29f34SStephen Smalley * @scontext: security context 112612b29f34SStephen Smalley * @scontext_len: length in bytes 112712b29f34SStephen Smalley * 112812b29f34SStephen Smalley * Write the string representation of the context associated with @sid 112912b29f34SStephen Smalley * into a dynamically allocated string of the correct size. Set @scontext 113012b29f34SStephen Smalley * to point to this string and set @scontext_len to the length of the string. 113112b29f34SStephen Smalley */ 113212b29f34SStephen Smalley int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) 11331da177e4SLinus Torvalds { 113412b29f34SStephen Smalley return security_sid_to_context_core(sid, scontext, scontext_len, 0); 113512b29f34SStephen Smalley } 113612b29f34SStephen Smalley 113712b29f34SStephen Smalley int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len) 113812b29f34SStephen Smalley { 113912b29f34SStephen Smalley return security_sid_to_context_core(sid, scontext, scontext_len, 1); 114012b29f34SStephen Smalley } 114112b29f34SStephen Smalley 11429a59daa0SStephen Smalley /* 11439a59daa0SStephen Smalley * Caveat: Mutates scontext. 11449a59daa0SStephen Smalley */ 114512b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol, 114612b29f34SStephen Smalley struct sidtab *sidtabp, 11479a59daa0SStephen Smalley char *scontext, 114812b29f34SStephen Smalley u32 scontext_len, 114912b29f34SStephen Smalley struct context *ctx, 11509a59daa0SStephen Smalley u32 def_sid) 115112b29f34SStephen Smalley { 11521da177e4SLinus Torvalds struct role_datum *role; 11531da177e4SLinus Torvalds struct type_datum *typdatum; 11541da177e4SLinus Torvalds struct user_datum *usrdatum; 11551da177e4SLinus Torvalds char *scontextp, *p, oldc; 11561da177e4SLinus Torvalds int rc = 0; 11571da177e4SLinus Torvalds 115812b29f34SStephen Smalley context_init(ctx); 115912b29f34SStephen Smalley 116012b29f34SStephen Smalley /* Parse the security context. */ 116112b29f34SStephen Smalley 116212b29f34SStephen Smalley rc = -EINVAL; 11639a59daa0SStephen Smalley scontextp = (char *) scontext; 116412b29f34SStephen Smalley 116512b29f34SStephen Smalley /* Extract the user. */ 116612b29f34SStephen Smalley p = scontextp; 116712b29f34SStephen Smalley while (*p && *p != ':') 116812b29f34SStephen Smalley p++; 116912b29f34SStephen Smalley 117012b29f34SStephen Smalley if (*p == 0) 117112b29f34SStephen Smalley goto out; 117212b29f34SStephen Smalley 117312b29f34SStephen Smalley *p++ = 0; 117412b29f34SStephen Smalley 117512b29f34SStephen Smalley usrdatum = hashtab_search(pol->p_users.table, scontextp); 117612b29f34SStephen Smalley if (!usrdatum) 117712b29f34SStephen Smalley goto out; 117812b29f34SStephen Smalley 117912b29f34SStephen Smalley ctx->user = usrdatum->value; 118012b29f34SStephen Smalley 118112b29f34SStephen Smalley /* Extract role. */ 118212b29f34SStephen Smalley scontextp = p; 118312b29f34SStephen Smalley while (*p && *p != ':') 118412b29f34SStephen Smalley p++; 118512b29f34SStephen Smalley 118612b29f34SStephen Smalley if (*p == 0) 118712b29f34SStephen Smalley goto out; 118812b29f34SStephen Smalley 118912b29f34SStephen Smalley *p++ = 0; 119012b29f34SStephen Smalley 119112b29f34SStephen Smalley role = hashtab_search(pol->p_roles.table, scontextp); 119212b29f34SStephen Smalley if (!role) 119312b29f34SStephen Smalley goto out; 119412b29f34SStephen Smalley ctx->role = role->value; 119512b29f34SStephen Smalley 119612b29f34SStephen Smalley /* Extract type. */ 119712b29f34SStephen Smalley scontextp = p; 119812b29f34SStephen Smalley while (*p && *p != ':') 119912b29f34SStephen Smalley p++; 120012b29f34SStephen Smalley oldc = *p; 120112b29f34SStephen Smalley *p++ = 0; 120212b29f34SStephen Smalley 120312b29f34SStephen Smalley typdatum = hashtab_search(pol->p_types.table, scontextp); 1204d9250deaSKaiGai Kohei if (!typdatum || typdatum->attribute) 120512b29f34SStephen Smalley goto out; 120612b29f34SStephen Smalley 120712b29f34SStephen Smalley ctx->type = typdatum->value; 120812b29f34SStephen Smalley 120912b29f34SStephen Smalley rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid); 121012b29f34SStephen Smalley if (rc) 121112b29f34SStephen Smalley goto out; 121212b29f34SStephen Smalley 121312b29f34SStephen Smalley rc = -EINVAL; 12144b02b524SEric Paris if ((p - scontext) < scontext_len) 121512b29f34SStephen Smalley goto out; 121612b29f34SStephen Smalley 121712b29f34SStephen Smalley /* Check the validity of the new context. */ 12184b02b524SEric Paris if (!policydb_context_isvalid(pol, ctx)) 121912b29f34SStephen Smalley goto out; 122012b29f34SStephen Smalley rc = 0; 122112b29f34SStephen Smalley out: 12228e531af9SEric Paris if (rc) 12238e531af9SEric Paris context_destroy(ctx); 122412b29f34SStephen Smalley return rc; 122512b29f34SStephen Smalley } 122612b29f34SStephen Smalley 122712b29f34SStephen Smalley static int security_context_to_sid_core(const char *scontext, u32 scontext_len, 122812b29f34SStephen Smalley u32 *sid, u32 def_sid, gfp_t gfp_flags, 122912b29f34SStephen Smalley int force) 123012b29f34SStephen Smalley { 12319a59daa0SStephen Smalley char *scontext2, *str = NULL; 123212b29f34SStephen Smalley struct context context; 123312b29f34SStephen Smalley int rc = 0; 123412b29f34SStephen Smalley 12352172fa70SStephen Smalley /* An empty security context is never valid. */ 12362172fa70SStephen Smalley if (!scontext_len) 12372172fa70SStephen Smalley return -EINVAL; 12382172fa70SStephen Smalley 12391da177e4SLinus Torvalds if (!ss_initialized) { 12401da177e4SLinus Torvalds int i; 12411da177e4SLinus Torvalds 12421da177e4SLinus Torvalds for (i = 1; i < SECINITSID_NUM; i++) { 12431da177e4SLinus Torvalds if (!strcmp(initial_sid_to_string[i], scontext)) { 12441da177e4SLinus Torvalds *sid = i; 12459a59daa0SStephen Smalley return 0; 12461da177e4SLinus Torvalds } 12471da177e4SLinus Torvalds } 12481da177e4SLinus Torvalds *sid = SECINITSID_KERNEL; 12499a59daa0SStephen Smalley return 0; 12501da177e4SLinus Torvalds } 12511da177e4SLinus Torvalds *sid = SECSID_NULL; 12521da177e4SLinus Torvalds 12539a59daa0SStephen Smalley /* Copy the string so that we can modify the copy as we parse it. */ 12549a59daa0SStephen Smalley scontext2 = kmalloc(scontext_len + 1, gfp_flags); 12559a59daa0SStephen Smalley if (!scontext2) 12569a59daa0SStephen Smalley return -ENOMEM; 12579a59daa0SStephen Smalley memcpy(scontext2, scontext, scontext_len); 12589a59daa0SStephen Smalley scontext2[scontext_len] = 0; 12599a59daa0SStephen Smalley 12609a59daa0SStephen Smalley if (force) { 12619a59daa0SStephen Smalley /* Save another copy for storing in uninterpreted form */ 12624b02b524SEric Paris rc = -ENOMEM; 12639a59daa0SStephen Smalley str = kstrdup(scontext2, gfp_flags); 12644b02b524SEric Paris if (!str) 12654b02b524SEric Paris goto out; 12669a59daa0SStephen Smalley } 12679a59daa0SStephen Smalley 12680804d113SJames Morris read_lock(&policy_rwlock); 12694b02b524SEric Paris rc = string_to_context_struct(&policydb, &sidtab, scontext2, 12704b02b524SEric Paris scontext_len, &context, def_sid); 127112b29f34SStephen Smalley if (rc == -EINVAL && force) { 12729a59daa0SStephen Smalley context.str = str; 127312b29f34SStephen Smalley context.len = scontext_len; 12749a59daa0SStephen Smalley str = NULL; 127512b29f34SStephen Smalley } else if (rc) 12764b02b524SEric Paris goto out_unlock; 12771da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &context, sid); 12781da177e4SLinus Torvalds context_destroy(&context); 12794b02b524SEric Paris out_unlock: 12800804d113SJames Morris read_unlock(&policy_rwlock); 12814b02b524SEric Paris out: 12829a59daa0SStephen Smalley kfree(scontext2); 12839a59daa0SStephen Smalley kfree(str); 12841da177e4SLinus Torvalds return rc; 12851da177e4SLinus Torvalds } 12861da177e4SLinus Torvalds 1287f5c1d5b2SJames Morris /** 1288f5c1d5b2SJames Morris * security_context_to_sid - Obtain a SID for a given security context. 1289f5c1d5b2SJames Morris * @scontext: security context 1290f5c1d5b2SJames Morris * @scontext_len: length in bytes 1291f5c1d5b2SJames Morris * @sid: security identifier, SID 129252a4c640SNikolay Aleksandrov * @gfp: context for the allocation 1293f5c1d5b2SJames Morris * 1294f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 1295f5c1d5b2SJames Morris * has the string representation specified by @scontext. 1296f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 1297f5c1d5b2SJames Morris * memory is available, or 0 on success. 1298f5c1d5b2SJames Morris */ 129952a4c640SNikolay Aleksandrov int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid, 130052a4c640SNikolay Aleksandrov gfp_t gfp) 1301f5c1d5b2SJames Morris { 1302f5c1d5b2SJames Morris return security_context_to_sid_core(scontext, scontext_len, 130352a4c640SNikolay Aleksandrov sid, SECSID_NULL, gfp, 0); 1304f5c1d5b2SJames Morris } 1305f5c1d5b2SJames Morris 1306f5c1d5b2SJames Morris /** 1307f5c1d5b2SJames Morris * security_context_to_sid_default - Obtain a SID for a given security context, 1308f5c1d5b2SJames Morris * falling back to specified default if needed. 1309f5c1d5b2SJames Morris * 1310f5c1d5b2SJames Morris * @scontext: security context 1311f5c1d5b2SJames Morris * @scontext_len: length in bytes 1312f5c1d5b2SJames Morris * @sid: security identifier, SID 1313d133a960SGabriel Craciunescu * @def_sid: default SID to assign on error 1314f5c1d5b2SJames Morris * 1315f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 1316f5c1d5b2SJames Morris * has the string representation specified by @scontext. 1317f5c1d5b2SJames Morris * The default SID is passed to the MLS layer to be used to allow 1318f5c1d5b2SJames Morris * kernel labeling of the MLS field if the MLS field is not present 1319f5c1d5b2SJames Morris * (for upgrading to MLS without full relabel). 132012b29f34SStephen Smalley * Implicitly forces adding of the context even if it cannot be mapped yet. 1321f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 1322f5c1d5b2SJames Morris * memory is available, or 0 on success. 1323f5c1d5b2SJames Morris */ 13247bf570dcSDavid Howells int security_context_to_sid_default(const char *scontext, u32 scontext_len, 13257bf570dcSDavid Howells u32 *sid, u32 def_sid, gfp_t gfp_flags) 1326f5c1d5b2SJames Morris { 1327f5c1d5b2SJames Morris return security_context_to_sid_core(scontext, scontext_len, 132812b29f34SStephen Smalley sid, def_sid, gfp_flags, 1); 132912b29f34SStephen Smalley } 133012b29f34SStephen Smalley 133112b29f34SStephen Smalley int security_context_to_sid_force(const char *scontext, u32 scontext_len, 133212b29f34SStephen Smalley u32 *sid) 133312b29f34SStephen Smalley { 133412b29f34SStephen Smalley return security_context_to_sid_core(scontext, scontext_len, 133512b29f34SStephen Smalley sid, SECSID_NULL, GFP_KERNEL, 1); 1336f5c1d5b2SJames Morris } 1337f5c1d5b2SJames Morris 13381da177e4SLinus Torvalds static int compute_sid_handle_invalid_context( 13391da177e4SLinus Torvalds struct context *scontext, 13401da177e4SLinus Torvalds struct context *tcontext, 13411da177e4SLinus Torvalds u16 tclass, 13421da177e4SLinus Torvalds struct context *newcontext) 13431da177e4SLinus Torvalds { 13441da177e4SLinus Torvalds char *s = NULL, *t = NULL, *n = NULL; 13451da177e4SLinus Torvalds u32 slen, tlen, nlen; 13461da177e4SLinus Torvalds 13474b02b524SEric Paris if (context_struct_to_string(scontext, &s, &slen)) 13481da177e4SLinus Torvalds goto out; 13494b02b524SEric Paris if (context_struct_to_string(tcontext, &t, &tlen)) 13501da177e4SLinus Torvalds goto out; 13514b02b524SEric Paris if (context_struct_to_string(newcontext, &n, &nlen)) 13521da177e4SLinus Torvalds goto out; 13539ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 13541da177e4SLinus Torvalds "security_compute_sid: invalid context %s" 13551da177e4SLinus Torvalds " for scontext=%s" 13561da177e4SLinus Torvalds " tcontext=%s" 13571da177e4SLinus Torvalds " tclass=%s", 1358ac76c05bSEric Paris n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); 13591da177e4SLinus Torvalds out: 13601da177e4SLinus Torvalds kfree(s); 13611da177e4SLinus Torvalds kfree(t); 13621da177e4SLinus Torvalds kfree(n); 13631da177e4SLinus Torvalds if (!selinux_enforcing) 13641da177e4SLinus Torvalds return 0; 13651da177e4SLinus Torvalds return -EACCES; 13661da177e4SLinus Torvalds } 13671da177e4SLinus Torvalds 1368652bb9b0SEric Paris static void filename_compute_type(struct policydb *p, struct context *newcontext, 13692667991fSEric Paris u32 stype, u32 ttype, u16 tclass, 1370f50a3ec9SKohei Kaigai const char *objname) 1371652bb9b0SEric Paris { 13722463c26dSEric Paris struct filename_trans ft; 13732463c26dSEric Paris struct filename_trans_datum *otype; 137403a4c018SEric Paris 137503a4c018SEric Paris /* 137603a4c018SEric Paris * Most filename trans rules are going to live in specific directories 137703a4c018SEric Paris * like /dev or /var/run. This bitmap will quickly skip rule searches 137803a4c018SEric Paris * if the ttype does not contain any rules. 137903a4c018SEric Paris */ 138003a4c018SEric Paris if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype)) 1381652bb9b0SEric Paris return; 138203a4c018SEric Paris 13832463c26dSEric Paris ft.stype = stype; 13842463c26dSEric Paris ft.ttype = ttype; 13852463c26dSEric Paris ft.tclass = tclass; 13862463c26dSEric Paris ft.name = objname; 13872463c26dSEric Paris 13882463c26dSEric Paris otype = hashtab_search(p->filename_trans, &ft); 13892463c26dSEric Paris if (otype) 13902463c26dSEric Paris newcontext->type = otype->otype; 1391652bb9b0SEric Paris } 1392652bb9b0SEric Paris 13931da177e4SLinus Torvalds static int security_compute_sid(u32 ssid, 13941da177e4SLinus Torvalds u32 tsid, 1395c6d3aaa4SStephen Smalley u16 orig_tclass, 13961da177e4SLinus Torvalds u32 specified, 1397f50a3ec9SKohei Kaigai const char *objname, 1398c6d3aaa4SStephen Smalley u32 *out_sid, 1399c6d3aaa4SStephen Smalley bool kern) 14001da177e4SLinus Torvalds { 1401aa893269SEric Paris struct class_datum *cladatum = NULL; 14021da177e4SLinus Torvalds struct context *scontext = NULL, *tcontext = NULL, newcontext; 14031da177e4SLinus Torvalds struct role_trans *roletr = NULL; 14041da177e4SLinus Torvalds struct avtab_key avkey; 14051da177e4SLinus Torvalds struct avtab_datum *avdatum; 14061da177e4SLinus Torvalds struct avtab_node *node; 1407c6d3aaa4SStephen Smalley u16 tclass; 14081da177e4SLinus Torvalds int rc = 0; 14096f5317e7SHarry Ciao bool sock; 14101da177e4SLinus Torvalds 14111da177e4SLinus Torvalds if (!ss_initialized) { 1412c6d3aaa4SStephen Smalley switch (orig_tclass) { 1413c6d3aaa4SStephen Smalley case SECCLASS_PROCESS: /* kernel value */ 14141da177e4SLinus Torvalds *out_sid = ssid; 14151da177e4SLinus Torvalds break; 14161da177e4SLinus Torvalds default: 14171da177e4SLinus Torvalds *out_sid = tsid; 14181da177e4SLinus Torvalds break; 14191da177e4SLinus Torvalds } 14201da177e4SLinus Torvalds goto out; 14211da177e4SLinus Torvalds } 14221da177e4SLinus Torvalds 1423851f8a69SVenkat Yekkirala context_init(&newcontext); 1424851f8a69SVenkat Yekkirala 14250804d113SJames Morris read_lock(&policy_rwlock); 14261da177e4SLinus Torvalds 14276f5317e7SHarry Ciao if (kern) { 1428c6d3aaa4SStephen Smalley tclass = unmap_class(orig_tclass); 14296f5317e7SHarry Ciao sock = security_is_socket_class(orig_tclass); 14306f5317e7SHarry Ciao } else { 1431c6d3aaa4SStephen Smalley tclass = orig_tclass; 14326f5317e7SHarry Ciao sock = security_is_socket_class(map_class(tclass)); 14336f5317e7SHarry Ciao } 1434c6d3aaa4SStephen Smalley 14351da177e4SLinus Torvalds scontext = sidtab_search(&sidtab, ssid); 14361da177e4SLinus Torvalds if (!scontext) { 1437744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1438744ba35eSEric Paris __func__, ssid); 14391da177e4SLinus Torvalds rc = -EINVAL; 14401da177e4SLinus Torvalds goto out_unlock; 14411da177e4SLinus Torvalds } 14421da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tsid); 14431da177e4SLinus Torvalds if (!tcontext) { 1444744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1445744ba35eSEric Paris __func__, tsid); 14461da177e4SLinus Torvalds rc = -EINVAL; 14471da177e4SLinus Torvalds goto out_unlock; 14481da177e4SLinus Torvalds } 14491da177e4SLinus Torvalds 1450aa893269SEric Paris if (tclass && tclass <= policydb.p_classes.nprim) 1451aa893269SEric Paris cladatum = policydb.class_val_to_struct[tclass - 1]; 1452aa893269SEric Paris 14531da177e4SLinus Torvalds /* Set the user identity. */ 14541da177e4SLinus Torvalds switch (specified) { 14551da177e4SLinus Torvalds case AVTAB_TRANSITION: 14561da177e4SLinus Torvalds case AVTAB_CHANGE: 1457aa893269SEric Paris if (cladatum && cladatum->default_user == DEFAULT_TARGET) { 1458aa893269SEric Paris newcontext.user = tcontext->user; 1459aa893269SEric Paris } else { 1460aa893269SEric Paris /* notice this gets both DEFAULT_SOURCE and unset */ 14611da177e4SLinus Torvalds /* Use the process user identity. */ 14621da177e4SLinus Torvalds newcontext.user = scontext->user; 1463aa893269SEric Paris } 14641da177e4SLinus Torvalds break; 14651da177e4SLinus Torvalds case AVTAB_MEMBER: 14661da177e4SLinus Torvalds /* Use the related object owner. */ 14671da177e4SLinus Torvalds newcontext.user = tcontext->user; 14681da177e4SLinus Torvalds break; 14691da177e4SLinus Torvalds } 14701da177e4SLinus Torvalds 1471aa893269SEric Paris /* Set the role to default values. */ 1472aa893269SEric Paris if (cladatum && cladatum->default_role == DEFAULT_SOURCE) { 14731da177e4SLinus Torvalds newcontext.role = scontext->role; 1474aa893269SEric Paris } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { 1475aa893269SEric Paris newcontext.role = tcontext->role; 1476aa893269SEric Paris } else { 1477aa893269SEric Paris if ((tclass == policydb.process_class) || (sock == true)) 1478aa893269SEric Paris newcontext.role = scontext->role; 1479aa893269SEric Paris else 1480aa893269SEric Paris newcontext.role = OBJECT_R_VAL; 1481aa893269SEric Paris } 1482aa893269SEric Paris 1483aa893269SEric Paris /* Set the type to default values. */ 1484eed7795dSEric Paris if (cladatum && cladatum->default_type == DEFAULT_SOURCE) { 1485eed7795dSEric Paris newcontext.type = scontext->type; 1486eed7795dSEric Paris } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) { 1487eed7795dSEric Paris newcontext.type = tcontext->type; 1488eed7795dSEric Paris } else { 1489aa893269SEric Paris if ((tclass == policydb.process_class) || (sock == true)) { 1490aa893269SEric Paris /* Use the type of process. */ 14911da177e4SLinus Torvalds newcontext.type = scontext->type; 1492c6d3aaa4SStephen Smalley } else { 14931da177e4SLinus Torvalds /* Use the type of the related object. */ 14941da177e4SLinus Torvalds newcontext.type = tcontext->type; 14951da177e4SLinus Torvalds } 1496eed7795dSEric Paris } 14971da177e4SLinus Torvalds 14981da177e4SLinus Torvalds /* Look for a type transition/member/change rule. */ 14991da177e4SLinus Torvalds avkey.source_type = scontext->type; 15001da177e4SLinus Torvalds avkey.target_type = tcontext->type; 15011da177e4SLinus Torvalds avkey.target_class = tclass; 1502782ebb99SStephen Smalley avkey.specified = specified; 1503782ebb99SStephen Smalley avdatum = avtab_search(&policydb.te_avtab, &avkey); 15041da177e4SLinus Torvalds 15051da177e4SLinus Torvalds /* If no permanent rule, also check for enabled conditional rules */ 15061da177e4SLinus Torvalds if (!avdatum) { 1507782ebb99SStephen Smalley node = avtab_search_node(&policydb.te_cond_avtab, &avkey); 1508dbc74c65SVesa-Matti Kari for (; node; node = avtab_search_node_next(node, specified)) { 1509782ebb99SStephen Smalley if (node->key.specified & AVTAB_ENABLED) { 15101da177e4SLinus Torvalds avdatum = &node->datum; 15111da177e4SLinus Torvalds break; 15121da177e4SLinus Torvalds } 15131da177e4SLinus Torvalds } 15141da177e4SLinus Torvalds } 15151da177e4SLinus Torvalds 1516782ebb99SStephen Smalley if (avdatum) { 15171da177e4SLinus Torvalds /* Use the type from the type transition/member/change rule. */ 1518782ebb99SStephen Smalley newcontext.type = avdatum->data; 15191da177e4SLinus Torvalds } 15201da177e4SLinus Torvalds 15214742600cSEric Paris /* if we have a objname this is a file trans check so check those rules */ 1522f50a3ec9SKohei Kaigai if (objname) 1523652bb9b0SEric Paris filename_compute_type(&policydb, &newcontext, scontext->type, 1524f50a3ec9SKohei Kaigai tcontext->type, tclass, objname); 1525652bb9b0SEric Paris 15261da177e4SLinus Torvalds /* Check for class-specific changes. */ 15271da177e4SLinus Torvalds if (specified & AVTAB_TRANSITION) { 15281da177e4SLinus Torvalds /* Look for a role transition rule. */ 152963a312caSHarry Ciao for (roletr = policydb.role_tr; roletr; roletr = roletr->next) { 153063a312caSHarry Ciao if ((roletr->role == scontext->role) && 153163a312caSHarry Ciao (roletr->type == tcontext->type) && 153263a312caSHarry Ciao (roletr->tclass == tclass)) { 15331da177e4SLinus Torvalds /* Use the role transition rule. */ 15341da177e4SLinus Torvalds newcontext.role = roletr->new_role; 15351da177e4SLinus Torvalds break; 15361da177e4SLinus Torvalds } 15371da177e4SLinus Torvalds } 15381da177e4SLinus Torvalds } 15391da177e4SLinus Torvalds 15401da177e4SLinus Torvalds /* Set the MLS attributes. 15411da177e4SLinus Torvalds This is done last because it may allocate memory. */ 15426f5317e7SHarry Ciao rc = mls_compute_sid(scontext, tcontext, tclass, specified, 15436f5317e7SHarry Ciao &newcontext, sock); 15441da177e4SLinus Torvalds if (rc) 15451da177e4SLinus Torvalds goto out_unlock; 15461da177e4SLinus Torvalds 15471da177e4SLinus Torvalds /* Check the validity of the context. */ 15481da177e4SLinus Torvalds if (!policydb_context_isvalid(&policydb, &newcontext)) { 15491da177e4SLinus Torvalds rc = compute_sid_handle_invalid_context(scontext, 15501da177e4SLinus Torvalds tcontext, 15511da177e4SLinus Torvalds tclass, 15521da177e4SLinus Torvalds &newcontext); 15531da177e4SLinus Torvalds if (rc) 15541da177e4SLinus Torvalds goto out_unlock; 15551da177e4SLinus Torvalds } 15561da177e4SLinus Torvalds /* Obtain the sid for the context. */ 15571da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid); 15581da177e4SLinus Torvalds out_unlock: 15590804d113SJames Morris read_unlock(&policy_rwlock); 15601da177e4SLinus Torvalds context_destroy(&newcontext); 15611da177e4SLinus Torvalds out: 15621da177e4SLinus Torvalds return rc; 15631da177e4SLinus Torvalds } 15641da177e4SLinus Torvalds 15651da177e4SLinus Torvalds /** 15661da177e4SLinus Torvalds * security_transition_sid - Compute the SID for a new subject/object. 15671da177e4SLinus Torvalds * @ssid: source security identifier 15681da177e4SLinus Torvalds * @tsid: target security identifier 15691da177e4SLinus Torvalds * @tclass: target security class 15701da177e4SLinus Torvalds * @out_sid: security identifier for new subject/object 15711da177e4SLinus Torvalds * 15721da177e4SLinus Torvalds * Compute a SID to use for labeling a new subject or object in the 15731da177e4SLinus Torvalds * class @tclass based on a SID pair (@ssid, @tsid). 15741da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 15751da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the new SID was 15761da177e4SLinus Torvalds * computed successfully. 15771da177e4SLinus Torvalds */ 1578652bb9b0SEric Paris int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, 1579652bb9b0SEric Paris const struct qstr *qstr, u32 *out_sid) 15801da177e4SLinus Torvalds { 1581c6d3aaa4SStephen Smalley return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, 1582f50a3ec9SKohei Kaigai qstr ? qstr->name : NULL, out_sid, true); 1583c6d3aaa4SStephen Smalley } 1584c6d3aaa4SStephen Smalley 1585f50a3ec9SKohei Kaigai int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, 1586f50a3ec9SKohei Kaigai const char *objname, u32 *out_sid) 1587c6d3aaa4SStephen Smalley { 1588c6d3aaa4SStephen Smalley return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, 1589f50a3ec9SKohei Kaigai objname, out_sid, false); 15901da177e4SLinus Torvalds } 15911da177e4SLinus Torvalds 15921da177e4SLinus Torvalds /** 15931da177e4SLinus Torvalds * security_member_sid - Compute the SID for member selection. 15941da177e4SLinus Torvalds * @ssid: source security identifier 15951da177e4SLinus Torvalds * @tsid: target security identifier 15961da177e4SLinus Torvalds * @tclass: target security class 15971da177e4SLinus Torvalds * @out_sid: security identifier for selected member 15981da177e4SLinus Torvalds * 15991da177e4SLinus Torvalds * Compute a SID to use when selecting a member of a polyinstantiated 16001da177e4SLinus Torvalds * object of class @tclass based on a SID pair (@ssid, @tsid). 16011da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 16021da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 16031da177e4SLinus Torvalds * computed successfully. 16041da177e4SLinus Torvalds */ 16051da177e4SLinus Torvalds int security_member_sid(u32 ssid, 16061da177e4SLinus Torvalds u32 tsid, 16071da177e4SLinus Torvalds u16 tclass, 16081da177e4SLinus Torvalds u32 *out_sid) 16091da177e4SLinus Torvalds { 1610652bb9b0SEric Paris return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL, 1611652bb9b0SEric Paris out_sid, false); 16121da177e4SLinus Torvalds } 16131da177e4SLinus Torvalds 16141da177e4SLinus Torvalds /** 16151da177e4SLinus Torvalds * security_change_sid - Compute the SID for object relabeling. 16161da177e4SLinus Torvalds * @ssid: source security identifier 16171da177e4SLinus Torvalds * @tsid: target security identifier 16181da177e4SLinus Torvalds * @tclass: target security class 16191da177e4SLinus Torvalds * @out_sid: security identifier for selected member 16201da177e4SLinus Torvalds * 16211da177e4SLinus Torvalds * Compute a SID to use for relabeling an object of class @tclass 16221da177e4SLinus Torvalds * based on a SID pair (@ssid, @tsid). 16231da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 16241da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 16251da177e4SLinus Torvalds * computed successfully. 16261da177e4SLinus Torvalds */ 16271da177e4SLinus Torvalds int security_change_sid(u32 ssid, 16281da177e4SLinus Torvalds u32 tsid, 16291da177e4SLinus Torvalds u16 tclass, 16301da177e4SLinus Torvalds u32 *out_sid) 16311da177e4SLinus Torvalds { 1632652bb9b0SEric Paris return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL, 1633652bb9b0SEric Paris out_sid, false); 1634b94c7e67SChad Sellers } 1635b94c7e67SChad Sellers 16361da177e4SLinus Torvalds /* Clone the SID into the new SID table. */ 16371da177e4SLinus Torvalds static int clone_sid(u32 sid, 16381da177e4SLinus Torvalds struct context *context, 16391da177e4SLinus Torvalds void *arg) 16401da177e4SLinus Torvalds { 16411da177e4SLinus Torvalds struct sidtab *s = arg; 16421da177e4SLinus Torvalds 164342596eafSGuido Trentalancia if (sid > SECINITSID_NUM) 16441da177e4SLinus Torvalds return sidtab_insert(s, sid, context); 164542596eafSGuido Trentalancia else 164642596eafSGuido Trentalancia return 0; 16471da177e4SLinus Torvalds } 16481da177e4SLinus Torvalds 16491da177e4SLinus Torvalds static inline int convert_context_handle_invalid_context(struct context *context) 16501da177e4SLinus Torvalds { 16511da177e4SLinus Torvalds char *s; 16521da177e4SLinus Torvalds u32 len; 16531da177e4SLinus Torvalds 16544b02b524SEric Paris if (selinux_enforcing) 16554b02b524SEric Paris return -EINVAL; 16564b02b524SEric Paris 165712b29f34SStephen Smalley if (!context_struct_to_string(context, &s, &len)) { 16584b02b524SEric Paris printk(KERN_WARNING "SELinux: Context %s would be invalid if enforcing\n", s); 16591da177e4SLinus Torvalds kfree(s); 16601da177e4SLinus Torvalds } 16614b02b524SEric Paris return 0; 16621da177e4SLinus Torvalds } 16631da177e4SLinus Torvalds 16641da177e4SLinus Torvalds struct convert_context_args { 16651da177e4SLinus Torvalds struct policydb *oldp; 16661da177e4SLinus Torvalds struct policydb *newp; 16671da177e4SLinus Torvalds }; 16681da177e4SLinus Torvalds 16691da177e4SLinus Torvalds /* 16701da177e4SLinus Torvalds * Convert the values in the security context 16711da177e4SLinus Torvalds * structure `c' from the values specified 16721da177e4SLinus Torvalds * in the policy `p->oldp' to the values specified 16731da177e4SLinus Torvalds * in the policy `p->newp'. Verify that the 16741da177e4SLinus Torvalds * context is valid under the new policy. 16751da177e4SLinus Torvalds */ 16761da177e4SLinus Torvalds static int convert_context(u32 key, 16771da177e4SLinus Torvalds struct context *c, 16781da177e4SLinus Torvalds void *p) 16791da177e4SLinus Torvalds { 16801da177e4SLinus Torvalds struct convert_context_args *args; 16811da177e4SLinus Torvalds struct context oldc; 16820719aaf5SGuido Trentalancia struct ocontext *oc; 16830719aaf5SGuido Trentalancia struct mls_range *range; 16841da177e4SLinus Torvalds struct role_datum *role; 16851da177e4SLinus Torvalds struct type_datum *typdatum; 16861da177e4SLinus Torvalds struct user_datum *usrdatum; 16871da177e4SLinus Torvalds char *s; 16881da177e4SLinus Torvalds u32 len; 168942596eafSGuido Trentalancia int rc = 0; 169042596eafSGuido Trentalancia 169142596eafSGuido Trentalancia if (key <= SECINITSID_NUM) 169242596eafSGuido Trentalancia goto out; 16931da177e4SLinus Torvalds 16941da177e4SLinus Torvalds args = p; 16951da177e4SLinus Torvalds 169612b29f34SStephen Smalley if (c->str) { 169712b29f34SStephen Smalley struct context ctx; 16984b02b524SEric Paris 16999a59daa0SStephen Smalley rc = -ENOMEM; 17004b02b524SEric Paris s = kstrdup(c->str, GFP_KERNEL); 17014b02b524SEric Paris if (!s) 17029a59daa0SStephen Smalley goto out; 17034b02b524SEric Paris 17049a59daa0SStephen Smalley rc = string_to_context_struct(args->newp, NULL, s, 17059a59daa0SStephen Smalley c->len, &ctx, SECSID_NULL); 17069a59daa0SStephen Smalley kfree(s); 170712b29f34SStephen Smalley if (!rc) { 17084b02b524SEric Paris printk(KERN_INFO "SELinux: Context %s became valid (mapped).\n", 170912b29f34SStephen Smalley c->str); 171012b29f34SStephen Smalley /* Replace string with mapped representation. */ 171112b29f34SStephen Smalley kfree(c->str); 171212b29f34SStephen Smalley memcpy(c, &ctx, sizeof(*c)); 171312b29f34SStephen Smalley goto out; 171412b29f34SStephen Smalley } else if (rc == -EINVAL) { 171512b29f34SStephen Smalley /* Retain string representation for later mapping. */ 171612b29f34SStephen Smalley rc = 0; 171712b29f34SStephen Smalley goto out; 171812b29f34SStephen Smalley } else { 171912b29f34SStephen Smalley /* Other error condition, e.g. ENOMEM. */ 17204b02b524SEric Paris printk(KERN_ERR "SELinux: Unable to map context %s, rc = %d.\n", 172112b29f34SStephen Smalley c->str, -rc); 172212b29f34SStephen Smalley goto out; 172312b29f34SStephen Smalley } 172412b29f34SStephen Smalley } 172512b29f34SStephen Smalley 17261da177e4SLinus Torvalds rc = context_cpy(&oldc, c); 17271da177e4SLinus Torvalds if (rc) 17281da177e4SLinus Torvalds goto out; 17291da177e4SLinus Torvalds 17301da177e4SLinus Torvalds /* Convert the user. */ 17314b02b524SEric Paris rc = -EINVAL; 17321da177e4SLinus Torvalds usrdatum = hashtab_search(args->newp->p_users.table, 1733ac76c05bSEric Paris sym_name(args->oldp, SYM_USERS, c->user - 1)); 17345d55a345SEric Paris if (!usrdatum) 17351da177e4SLinus Torvalds goto bad; 17361da177e4SLinus Torvalds c->user = usrdatum->value; 17371da177e4SLinus Torvalds 17381da177e4SLinus Torvalds /* Convert the role. */ 17394b02b524SEric Paris rc = -EINVAL; 17401da177e4SLinus Torvalds role = hashtab_search(args->newp->p_roles.table, 1741ac76c05bSEric Paris sym_name(args->oldp, SYM_ROLES, c->role - 1)); 17425d55a345SEric Paris if (!role) 17431da177e4SLinus Torvalds goto bad; 17441da177e4SLinus Torvalds c->role = role->value; 17451da177e4SLinus Torvalds 17461da177e4SLinus Torvalds /* Convert the type. */ 17474b02b524SEric Paris rc = -EINVAL; 17481da177e4SLinus Torvalds typdatum = hashtab_search(args->newp->p_types.table, 1749ac76c05bSEric Paris sym_name(args->oldp, SYM_TYPES, c->type - 1)); 17505d55a345SEric Paris if (!typdatum) 17511da177e4SLinus Torvalds goto bad; 17521da177e4SLinus Torvalds c->type = typdatum->value; 17531da177e4SLinus Torvalds 17540719aaf5SGuido Trentalancia /* Convert the MLS fields if dealing with MLS policies */ 17550719aaf5SGuido Trentalancia if (args->oldp->mls_enabled && args->newp->mls_enabled) { 17561da177e4SLinus Torvalds rc = mls_convert_context(args->oldp, args->newp, c); 17571da177e4SLinus Torvalds if (rc) 17581da177e4SLinus Torvalds goto bad; 17590719aaf5SGuido Trentalancia } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) { 17600719aaf5SGuido Trentalancia /* 17610719aaf5SGuido Trentalancia * Switching between MLS and non-MLS policy: 17620719aaf5SGuido Trentalancia * free any storage used by the MLS fields in the 17630719aaf5SGuido Trentalancia * context for all existing entries in the sidtab. 17640719aaf5SGuido Trentalancia */ 17650719aaf5SGuido Trentalancia mls_context_destroy(c); 17660719aaf5SGuido Trentalancia } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { 17670719aaf5SGuido Trentalancia /* 17680719aaf5SGuido Trentalancia * Switching between non-MLS and MLS policy: 17690719aaf5SGuido Trentalancia * ensure that the MLS fields of the context for all 17700719aaf5SGuido Trentalancia * existing entries in the sidtab are filled in with a 17710719aaf5SGuido Trentalancia * suitable default value, likely taken from one of the 17720719aaf5SGuido Trentalancia * initial SIDs. 17730719aaf5SGuido Trentalancia */ 17740719aaf5SGuido Trentalancia oc = args->newp->ocontexts[OCON_ISID]; 17750719aaf5SGuido Trentalancia while (oc && oc->sid[0] != SECINITSID_UNLABELED) 17760719aaf5SGuido Trentalancia oc = oc->next; 17774b02b524SEric Paris rc = -EINVAL; 17780719aaf5SGuido Trentalancia if (!oc) { 17790719aaf5SGuido Trentalancia printk(KERN_ERR "SELinux: unable to look up" 17800719aaf5SGuido Trentalancia " the initial SIDs list\n"); 17810719aaf5SGuido Trentalancia goto bad; 17820719aaf5SGuido Trentalancia } 17830719aaf5SGuido Trentalancia range = &oc->context[0].range; 17840719aaf5SGuido Trentalancia rc = mls_range_set(c, range); 17850719aaf5SGuido Trentalancia if (rc) 17860719aaf5SGuido Trentalancia goto bad; 17870719aaf5SGuido Trentalancia } 17881da177e4SLinus Torvalds 17891da177e4SLinus Torvalds /* Check the validity of the new context. */ 17901da177e4SLinus Torvalds if (!policydb_context_isvalid(args->newp, c)) { 17911da177e4SLinus Torvalds rc = convert_context_handle_invalid_context(&oldc); 17921da177e4SLinus Torvalds if (rc) 17931da177e4SLinus Torvalds goto bad; 17941da177e4SLinus Torvalds } 17951da177e4SLinus Torvalds 17961da177e4SLinus Torvalds context_destroy(&oldc); 17974b02b524SEric Paris 179812b29f34SStephen Smalley rc = 0; 17991da177e4SLinus Torvalds out: 18001da177e4SLinus Torvalds return rc; 18011da177e4SLinus Torvalds bad: 180212b29f34SStephen Smalley /* Map old representation to string and save it. */ 18034b02b524SEric Paris rc = context_struct_to_string(&oldc, &s, &len); 18044b02b524SEric Paris if (rc) 18054b02b524SEric Paris return rc; 18061da177e4SLinus Torvalds context_destroy(&oldc); 180712b29f34SStephen Smalley context_destroy(c); 180812b29f34SStephen Smalley c->str = s; 180912b29f34SStephen Smalley c->len = len; 18104b02b524SEric Paris printk(KERN_INFO "SELinux: Context %s became invalid (unmapped).\n", 181112b29f34SStephen Smalley c->str); 181212b29f34SStephen Smalley rc = 0; 18131da177e4SLinus Torvalds goto out; 18141da177e4SLinus Torvalds } 18151da177e4SLinus Torvalds 18163bb56b25SPaul Moore static void security_load_policycaps(void) 18173bb56b25SPaul Moore { 18183bb56b25SPaul Moore selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps, 18193bb56b25SPaul Moore POLICYDB_CAPABILITY_NETPEER); 1820b0c636b9SEric Paris selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, 1821b0c636b9SEric Paris POLICYDB_CAPABILITY_OPENPERM); 18222be4d74fSChris PeBenito selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps, 18232be4d74fSChris PeBenito POLICYDB_CAPABILITY_ALWAYSNETWORK); 18243bb56b25SPaul Moore } 18253bb56b25SPaul Moore 1826e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p); 18271da177e4SLinus Torvalds 18281da177e4SLinus Torvalds /** 18291da177e4SLinus Torvalds * security_load_policy - Load a security policy configuration. 18301da177e4SLinus Torvalds * @data: binary policy data 18311da177e4SLinus Torvalds * @len: length of data in bytes 18321da177e4SLinus Torvalds * 18331da177e4SLinus Torvalds * Load a new set of security policy configuration data, 18341da177e4SLinus Torvalds * validate it and convert the SID table as necessary. 18351da177e4SLinus Torvalds * This function will flush the access vector cache after 18361da177e4SLinus Torvalds * loading the new policy. 18371da177e4SLinus Torvalds */ 18381da177e4SLinus Torvalds int security_load_policy(void *data, size_t len) 18391da177e4SLinus Torvalds { 1840b5495b42STim Gardner struct policydb *oldpolicydb, *newpolicydb; 18411da177e4SLinus Torvalds struct sidtab oldsidtab, newsidtab; 1842c6d3aaa4SStephen Smalley struct selinux_mapping *oldmap, *map = NULL; 18431da177e4SLinus Torvalds struct convert_context_args args; 18441da177e4SLinus Torvalds u32 seqno; 1845c6d3aaa4SStephen Smalley u16 map_size; 18461da177e4SLinus Torvalds int rc = 0; 18471da177e4SLinus Torvalds struct policy_file file = { data, len }, *fp = &file; 18481da177e4SLinus Torvalds 1849b5495b42STim Gardner oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL); 1850b5495b42STim Gardner if (!oldpolicydb) { 1851b5495b42STim Gardner rc = -ENOMEM; 1852b5495b42STim Gardner goto out; 1853b5495b42STim Gardner } 1854b5495b42STim Gardner newpolicydb = oldpolicydb + 1; 1855b5495b42STim Gardner 18561da177e4SLinus Torvalds if (!ss_initialized) { 18571da177e4SLinus Torvalds avtab_cache_init(); 1858a2000050SEric Paris rc = policydb_read(&policydb, fp); 1859a2000050SEric Paris if (rc) { 18601da177e4SLinus Torvalds avtab_cache_destroy(); 1861b5495b42STim Gardner goto out; 18621da177e4SLinus Torvalds } 1863a2000050SEric Paris 1864cee74f47SEric Paris policydb.len = len; 1865a2000050SEric Paris rc = selinux_set_mapping(&policydb, secclass_map, 1866c6d3aaa4SStephen Smalley ¤t_mapping, 1867a2000050SEric Paris ¤t_mapping_size); 1868a2000050SEric Paris if (rc) { 18691da177e4SLinus Torvalds policydb_destroy(&policydb); 18701da177e4SLinus Torvalds avtab_cache_destroy(); 1871b5495b42STim Gardner goto out; 18721da177e4SLinus Torvalds } 1873a2000050SEric Paris 1874a2000050SEric Paris rc = policydb_load_isids(&policydb, &sidtab); 1875a2000050SEric Paris if (rc) { 1876b94c7e67SChad Sellers policydb_destroy(&policydb); 1877b94c7e67SChad Sellers avtab_cache_destroy(); 1878b5495b42STim Gardner goto out; 1879b94c7e67SChad Sellers } 1880a2000050SEric Paris 18813bb56b25SPaul Moore security_load_policycaps(); 18821da177e4SLinus Torvalds ss_initialized = 1; 18834c443d1bSStephen Smalley seqno = ++latest_granting; 18841da177e4SLinus Torvalds selinux_complete_init(); 18854c443d1bSStephen Smalley avc_ss_reset(seqno); 18864c443d1bSStephen Smalley selnl_notify_policyload(seqno); 188711904167SKaiGai Kohei selinux_status_update_policyload(seqno); 18887420ed23SVenkat Yekkirala selinux_netlbl_cache_invalidate(); 1889342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 1890b5495b42STim Gardner goto out; 18911da177e4SLinus Torvalds } 18921da177e4SLinus Torvalds 18931da177e4SLinus Torvalds #if 0 18941da177e4SLinus Torvalds sidtab_hash_eval(&sidtab, "sids"); 18951da177e4SLinus Torvalds #endif 18961da177e4SLinus Torvalds 1897b5495b42STim Gardner rc = policydb_read(newpolicydb, fp); 1898a2000050SEric Paris if (rc) 1899b5495b42STim Gardner goto out; 19001da177e4SLinus Torvalds 1901b5495b42STim Gardner newpolicydb->len = len; 19020719aaf5SGuido Trentalancia /* If switching between different policy types, log MLS status */ 1903b5495b42STim Gardner if (policydb.mls_enabled && !newpolicydb->mls_enabled) 19040719aaf5SGuido Trentalancia printk(KERN_INFO "SELinux: Disabling MLS support...\n"); 1905b5495b42STim Gardner else if (!policydb.mls_enabled && newpolicydb->mls_enabled) 19060719aaf5SGuido Trentalancia printk(KERN_INFO "SELinux: Enabling MLS support...\n"); 19070719aaf5SGuido Trentalancia 1908b5495b42STim Gardner rc = policydb_load_isids(newpolicydb, &newsidtab); 190942596eafSGuido Trentalancia if (rc) { 191042596eafSGuido Trentalancia printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); 1911b5495b42STim Gardner policydb_destroy(newpolicydb); 1912b5495b42STim Gardner goto out; 191312b29f34SStephen Smalley } 19141da177e4SLinus Torvalds 1915b5495b42STim Gardner rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size); 1916a2000050SEric Paris if (rc) 1917b94c7e67SChad Sellers goto err; 1918b94c7e67SChad Sellers 1919b5495b42STim Gardner rc = security_preserve_bools(newpolicydb); 1920e900a7d9SStephen Smalley if (rc) { 1921454d972cSJames Morris printk(KERN_ERR "SELinux: unable to preserve booleans\n"); 1922e900a7d9SStephen Smalley goto err; 1923e900a7d9SStephen Smalley } 1924e900a7d9SStephen Smalley 19251da177e4SLinus Torvalds /* Clone the SID table. */ 19261da177e4SLinus Torvalds sidtab_shutdown(&sidtab); 1927a2000050SEric Paris 1928a2000050SEric Paris rc = sidtab_map(&sidtab, clone_sid, &newsidtab); 1929a2000050SEric Paris if (rc) 19301da177e4SLinus Torvalds goto err; 19311da177e4SLinus Torvalds 193212b29f34SStephen Smalley /* 193312b29f34SStephen Smalley * Convert the internal representations of contexts 193412b29f34SStephen Smalley * in the new SID table. 193512b29f34SStephen Smalley */ 19361da177e4SLinus Torvalds args.oldp = &policydb; 1937b5495b42STim Gardner args.newp = newpolicydb; 193812b29f34SStephen Smalley rc = sidtab_map(&newsidtab, convert_context, &args); 19390719aaf5SGuido Trentalancia if (rc) { 19400719aaf5SGuido Trentalancia printk(KERN_ERR "SELinux: unable to convert the internal" 19410719aaf5SGuido Trentalancia " representation of contexts in the new SID" 19420719aaf5SGuido Trentalancia " table\n"); 194312b29f34SStephen Smalley goto err; 19440719aaf5SGuido Trentalancia } 19451da177e4SLinus Torvalds 19461da177e4SLinus Torvalds /* Save the old policydb and SID table to free later. */ 1947b5495b42STim Gardner memcpy(oldpolicydb, &policydb, sizeof(policydb)); 19481da177e4SLinus Torvalds sidtab_set(&oldsidtab, &sidtab); 19491da177e4SLinus Torvalds 19501da177e4SLinus Torvalds /* Install the new policydb and SID table. */ 19510804d113SJames Morris write_lock_irq(&policy_rwlock); 1952b5495b42STim Gardner memcpy(&policydb, newpolicydb, sizeof(policydb)); 19531da177e4SLinus Torvalds sidtab_set(&sidtab, &newsidtab); 19543bb56b25SPaul Moore security_load_policycaps(); 1955c6d3aaa4SStephen Smalley oldmap = current_mapping; 1956c6d3aaa4SStephen Smalley current_mapping = map; 1957c6d3aaa4SStephen Smalley current_mapping_size = map_size; 19581da177e4SLinus Torvalds seqno = ++latest_granting; 19590804d113SJames Morris write_unlock_irq(&policy_rwlock); 19601da177e4SLinus Torvalds 19611da177e4SLinus Torvalds /* Free the old policydb and SID table. */ 1962b5495b42STim Gardner policydb_destroy(oldpolicydb); 19631da177e4SLinus Torvalds sidtab_destroy(&oldsidtab); 1964c6d3aaa4SStephen Smalley kfree(oldmap); 19651da177e4SLinus Torvalds 19661da177e4SLinus Torvalds avc_ss_reset(seqno); 19671da177e4SLinus Torvalds selnl_notify_policyload(seqno); 196811904167SKaiGai Kohei selinux_status_update_policyload(seqno); 19697420ed23SVenkat Yekkirala selinux_netlbl_cache_invalidate(); 1970342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 19711da177e4SLinus Torvalds 1972b5495b42STim Gardner rc = 0; 1973b5495b42STim Gardner goto out; 19741da177e4SLinus Torvalds 19751da177e4SLinus Torvalds err: 1976c6d3aaa4SStephen Smalley kfree(map); 19771da177e4SLinus Torvalds sidtab_destroy(&newsidtab); 1978b5495b42STim Gardner policydb_destroy(newpolicydb); 19791da177e4SLinus Torvalds 1980b5495b42STim Gardner out: 1981b5495b42STim Gardner kfree(oldpolicydb); 1982b5495b42STim Gardner return rc; 19831da177e4SLinus Torvalds } 19841da177e4SLinus Torvalds 1985cee74f47SEric Paris size_t security_policydb_len(void) 1986cee74f47SEric Paris { 1987cee74f47SEric Paris size_t len; 1988cee74f47SEric Paris 1989cee74f47SEric Paris read_lock(&policy_rwlock); 1990cee74f47SEric Paris len = policydb.len; 1991cee74f47SEric Paris read_unlock(&policy_rwlock); 1992cee74f47SEric Paris 1993cee74f47SEric Paris return len; 1994cee74f47SEric Paris } 1995cee74f47SEric Paris 19961da177e4SLinus Torvalds /** 19971da177e4SLinus Torvalds * security_port_sid - Obtain the SID for a port. 19981da177e4SLinus Torvalds * @protocol: protocol number 19991da177e4SLinus Torvalds * @port: port number 20001da177e4SLinus Torvalds * @out_sid: security identifier 20011da177e4SLinus Torvalds */ 20023e112172SPaul Moore int security_port_sid(u8 protocol, u16 port, u32 *out_sid) 20031da177e4SLinus Torvalds { 20041da177e4SLinus Torvalds struct ocontext *c; 20051da177e4SLinus Torvalds int rc = 0; 20061da177e4SLinus Torvalds 20070804d113SJames Morris read_lock(&policy_rwlock); 20081da177e4SLinus Torvalds 20091da177e4SLinus Torvalds c = policydb.ocontexts[OCON_PORT]; 20101da177e4SLinus Torvalds while (c) { 20111da177e4SLinus Torvalds if (c->u.port.protocol == protocol && 20121da177e4SLinus Torvalds c->u.port.low_port <= port && 20131da177e4SLinus Torvalds c->u.port.high_port >= port) 20141da177e4SLinus Torvalds break; 20151da177e4SLinus Torvalds c = c->next; 20161da177e4SLinus Torvalds } 20171da177e4SLinus Torvalds 20181da177e4SLinus Torvalds if (c) { 20191da177e4SLinus Torvalds if (!c->sid[0]) { 20201da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 20211da177e4SLinus Torvalds &c->context[0], 20221da177e4SLinus Torvalds &c->sid[0]); 20231da177e4SLinus Torvalds if (rc) 20241da177e4SLinus Torvalds goto out; 20251da177e4SLinus Torvalds } 20261da177e4SLinus Torvalds *out_sid = c->sid[0]; 20271da177e4SLinus Torvalds } else { 20281da177e4SLinus Torvalds *out_sid = SECINITSID_PORT; 20291da177e4SLinus Torvalds } 20301da177e4SLinus Torvalds 20311da177e4SLinus Torvalds out: 20320804d113SJames Morris read_unlock(&policy_rwlock); 20331da177e4SLinus Torvalds return rc; 20341da177e4SLinus Torvalds } 20351da177e4SLinus Torvalds 20361da177e4SLinus Torvalds /** 20371da177e4SLinus Torvalds * security_netif_sid - Obtain the SID for a network interface. 20381da177e4SLinus Torvalds * @name: interface name 20391da177e4SLinus Torvalds * @if_sid: interface SID 20401da177e4SLinus Torvalds */ 2041e8bfdb9dSPaul Moore int security_netif_sid(char *name, u32 *if_sid) 20421da177e4SLinus Torvalds { 20431da177e4SLinus Torvalds int rc = 0; 20441da177e4SLinus Torvalds struct ocontext *c; 20451da177e4SLinus Torvalds 20460804d113SJames Morris read_lock(&policy_rwlock); 20471da177e4SLinus Torvalds 20481da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NETIF]; 20491da177e4SLinus Torvalds while (c) { 20501da177e4SLinus Torvalds if (strcmp(name, c->u.name) == 0) 20511da177e4SLinus Torvalds break; 20521da177e4SLinus Torvalds c = c->next; 20531da177e4SLinus Torvalds } 20541da177e4SLinus Torvalds 20551da177e4SLinus Torvalds if (c) { 20561da177e4SLinus Torvalds if (!c->sid[0] || !c->sid[1]) { 20571da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 20581da177e4SLinus Torvalds &c->context[0], 20591da177e4SLinus Torvalds &c->sid[0]); 20601da177e4SLinus Torvalds if (rc) 20611da177e4SLinus Torvalds goto out; 20621da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 20631da177e4SLinus Torvalds &c->context[1], 20641da177e4SLinus Torvalds &c->sid[1]); 20651da177e4SLinus Torvalds if (rc) 20661da177e4SLinus Torvalds goto out; 20671da177e4SLinus Torvalds } 20681da177e4SLinus Torvalds *if_sid = c->sid[0]; 2069e8bfdb9dSPaul Moore } else 20701da177e4SLinus Torvalds *if_sid = SECINITSID_NETIF; 20711da177e4SLinus Torvalds 20721da177e4SLinus Torvalds out: 20730804d113SJames Morris read_unlock(&policy_rwlock); 20741da177e4SLinus Torvalds return rc; 20751da177e4SLinus Torvalds } 20761da177e4SLinus Torvalds 20771da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) 20781da177e4SLinus Torvalds { 20791da177e4SLinus Torvalds int i, fail = 0; 20801da177e4SLinus Torvalds 20811da177e4SLinus Torvalds for (i = 0; i < 4; i++) 20821da177e4SLinus Torvalds if (addr[i] != (input[i] & mask[i])) { 20831da177e4SLinus Torvalds fail = 1; 20841da177e4SLinus Torvalds break; 20851da177e4SLinus Torvalds } 20861da177e4SLinus Torvalds 20871da177e4SLinus Torvalds return !fail; 20881da177e4SLinus Torvalds } 20891da177e4SLinus Torvalds 20901da177e4SLinus Torvalds /** 20911da177e4SLinus Torvalds * security_node_sid - Obtain the SID for a node (host). 20921da177e4SLinus Torvalds * @domain: communication domain aka address family 20931da177e4SLinus Torvalds * @addrp: address 20941da177e4SLinus Torvalds * @addrlen: address length in bytes 20951da177e4SLinus Torvalds * @out_sid: security identifier 20961da177e4SLinus Torvalds */ 20971da177e4SLinus Torvalds int security_node_sid(u16 domain, 20981da177e4SLinus Torvalds void *addrp, 20991da177e4SLinus Torvalds u32 addrlen, 21001da177e4SLinus Torvalds u32 *out_sid) 21011da177e4SLinus Torvalds { 21024b02b524SEric Paris int rc; 21031da177e4SLinus Torvalds struct ocontext *c; 21041da177e4SLinus Torvalds 21050804d113SJames Morris read_lock(&policy_rwlock); 21061da177e4SLinus Torvalds 21071da177e4SLinus Torvalds switch (domain) { 21081da177e4SLinus Torvalds case AF_INET: { 21091da177e4SLinus Torvalds u32 addr; 21101da177e4SLinus Torvalds 21111da177e4SLinus Torvalds rc = -EINVAL; 21124b02b524SEric Paris if (addrlen != sizeof(u32)) 21131da177e4SLinus Torvalds goto out; 21141da177e4SLinus Torvalds 21151da177e4SLinus Torvalds addr = *((u32 *)addrp); 21161da177e4SLinus Torvalds 21171da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NODE]; 21181da177e4SLinus Torvalds while (c) { 21191da177e4SLinus Torvalds if (c->u.node.addr == (addr & c->u.node.mask)) 21201da177e4SLinus Torvalds break; 21211da177e4SLinus Torvalds c = c->next; 21221da177e4SLinus Torvalds } 21231da177e4SLinus Torvalds break; 21241da177e4SLinus Torvalds } 21251da177e4SLinus Torvalds 21261da177e4SLinus Torvalds case AF_INET6: 21271da177e4SLinus Torvalds rc = -EINVAL; 21284b02b524SEric Paris if (addrlen != sizeof(u64) * 2) 21291da177e4SLinus Torvalds goto out; 21301da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NODE6]; 21311da177e4SLinus Torvalds while (c) { 21321da177e4SLinus Torvalds if (match_ipv6_addrmask(addrp, c->u.node6.addr, 21331da177e4SLinus Torvalds c->u.node6.mask)) 21341da177e4SLinus Torvalds break; 21351da177e4SLinus Torvalds c = c->next; 21361da177e4SLinus Torvalds } 21371da177e4SLinus Torvalds break; 21381da177e4SLinus Torvalds 21391da177e4SLinus Torvalds default: 21404b02b524SEric Paris rc = 0; 21411da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 21421da177e4SLinus Torvalds goto out; 21431da177e4SLinus Torvalds } 21441da177e4SLinus Torvalds 21451da177e4SLinus Torvalds if (c) { 21461da177e4SLinus Torvalds if (!c->sid[0]) { 21471da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 21481da177e4SLinus Torvalds &c->context[0], 21491da177e4SLinus Torvalds &c->sid[0]); 21501da177e4SLinus Torvalds if (rc) 21511da177e4SLinus Torvalds goto out; 21521da177e4SLinus Torvalds } 21531da177e4SLinus Torvalds *out_sid = c->sid[0]; 21541da177e4SLinus Torvalds } else { 21551da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 21561da177e4SLinus Torvalds } 21571da177e4SLinus Torvalds 21584b02b524SEric Paris rc = 0; 21591da177e4SLinus Torvalds out: 21600804d113SJames Morris read_unlock(&policy_rwlock); 21611da177e4SLinus Torvalds return rc; 21621da177e4SLinus Torvalds } 21631da177e4SLinus Torvalds 21641da177e4SLinus Torvalds #define SIDS_NEL 25 21651da177e4SLinus Torvalds 21661da177e4SLinus Torvalds /** 21671da177e4SLinus Torvalds * security_get_user_sids - Obtain reachable SIDs for a user. 21681da177e4SLinus Torvalds * @fromsid: starting SID 21691da177e4SLinus Torvalds * @username: username 21701da177e4SLinus Torvalds * @sids: array of reachable SIDs for user 21711da177e4SLinus Torvalds * @nel: number of elements in @sids 21721da177e4SLinus Torvalds * 21731da177e4SLinus Torvalds * Generate the set of SIDs for legal security contexts 21741da177e4SLinus Torvalds * for a given user that can be reached by @fromsid. 21751da177e4SLinus Torvalds * Set *@sids to point to a dynamically allocated 21761da177e4SLinus Torvalds * array containing the set of SIDs. Set *@nel to the 21771da177e4SLinus Torvalds * number of elements in the array. 21781da177e4SLinus Torvalds */ 21791da177e4SLinus Torvalds 21801da177e4SLinus Torvalds int security_get_user_sids(u32 fromsid, 21811da177e4SLinus Torvalds char *username, 21821da177e4SLinus Torvalds u32 **sids, 21831da177e4SLinus Torvalds u32 *nel) 21841da177e4SLinus Torvalds { 21851da177e4SLinus Torvalds struct context *fromcon, usercon; 21862c3c05dbSStephen Smalley u32 *mysids = NULL, *mysids2, sid; 21871da177e4SLinus Torvalds u32 mynel = 0, maxnel = SIDS_NEL; 21881da177e4SLinus Torvalds struct user_datum *user; 21891da177e4SLinus Torvalds struct role_datum *role; 2190782ebb99SStephen Smalley struct ebitmap_node *rnode, *tnode; 21911da177e4SLinus Torvalds int rc = 0, i, j; 21921da177e4SLinus Torvalds 21931da177e4SLinus Torvalds *sids = NULL; 21941da177e4SLinus Torvalds *nel = 0; 21952c3c05dbSStephen Smalley 21962c3c05dbSStephen Smalley if (!ss_initialized) 21971da177e4SLinus Torvalds goto out; 21981da177e4SLinus Torvalds 21990804d113SJames Morris read_lock(&policy_rwlock); 22001da177e4SLinus Torvalds 220112b29f34SStephen Smalley context_init(&usercon); 220212b29f34SStephen Smalley 22034b02b524SEric Paris rc = -EINVAL; 22041da177e4SLinus Torvalds fromcon = sidtab_search(&sidtab, fromsid); 22054b02b524SEric Paris if (!fromcon) 22061da177e4SLinus Torvalds goto out_unlock; 22071da177e4SLinus Torvalds 22081da177e4SLinus Torvalds rc = -EINVAL; 22094b02b524SEric Paris user = hashtab_search(policydb.p_users.table, username); 22104b02b524SEric Paris if (!user) 22111da177e4SLinus Torvalds goto out_unlock; 22124b02b524SEric Paris 22131da177e4SLinus Torvalds usercon.user = user->value; 22141da177e4SLinus Torvalds 22151da177e4SLinus Torvalds rc = -ENOMEM; 22164b02b524SEric Paris mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC); 22174b02b524SEric Paris if (!mysids) 22181da177e4SLinus Torvalds goto out_unlock; 22191da177e4SLinus Torvalds 22209fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&user->roles, rnode, i) { 22211da177e4SLinus Torvalds role = policydb.role_val_to_struct[i]; 22221da177e4SLinus Torvalds usercon.role = i + 1; 22239fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&role->types, tnode, j) { 22241da177e4SLinus Torvalds usercon.type = j + 1; 22251da177e4SLinus Torvalds 22261da177e4SLinus Torvalds if (mls_setup_user_range(fromcon, user, &usercon)) 22271da177e4SLinus Torvalds continue; 22281da177e4SLinus Torvalds 22291da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); 22302c3c05dbSStephen Smalley if (rc) 22311da177e4SLinus Torvalds goto out_unlock; 22321da177e4SLinus Torvalds if (mynel < maxnel) { 22331da177e4SLinus Torvalds mysids[mynel++] = sid; 22341da177e4SLinus Torvalds } else { 22354b02b524SEric Paris rc = -ENOMEM; 22361da177e4SLinus Torvalds maxnel += SIDS_NEL; 223789d155efSJames Morris mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); 22384b02b524SEric Paris if (!mysids2) 22391da177e4SLinus Torvalds goto out_unlock; 22401da177e4SLinus Torvalds memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); 22411da177e4SLinus Torvalds kfree(mysids); 22421da177e4SLinus Torvalds mysids = mysids2; 22431da177e4SLinus Torvalds mysids[mynel++] = sid; 22441da177e4SLinus Torvalds } 22451da177e4SLinus Torvalds } 22461da177e4SLinus Torvalds } 22474b02b524SEric Paris rc = 0; 22481da177e4SLinus Torvalds out_unlock: 22490804d113SJames Morris read_unlock(&policy_rwlock); 22502c3c05dbSStephen Smalley if (rc || !mynel) { 22512c3c05dbSStephen Smalley kfree(mysids); 22522c3c05dbSStephen Smalley goto out; 22532c3c05dbSStephen Smalley } 22542c3c05dbSStephen Smalley 22554b02b524SEric Paris rc = -ENOMEM; 22562c3c05dbSStephen Smalley mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL); 22572c3c05dbSStephen Smalley if (!mysids2) { 22582c3c05dbSStephen Smalley kfree(mysids); 22592c3c05dbSStephen Smalley goto out; 22602c3c05dbSStephen Smalley } 22612c3c05dbSStephen Smalley for (i = 0, j = 0; i < mynel; i++) { 2262f01e1af4SLinus Torvalds struct av_decision dummy_avd; 22632c3c05dbSStephen Smalley rc = avc_has_perm_noaudit(fromsid, mysids[i], 2264c6d3aaa4SStephen Smalley SECCLASS_PROCESS, /* kernel value */ 22652c3c05dbSStephen Smalley PROCESS__TRANSITION, AVC_STRICT, 2266f01e1af4SLinus Torvalds &dummy_avd); 22672c3c05dbSStephen Smalley if (!rc) 22682c3c05dbSStephen Smalley mysids2[j++] = mysids[i]; 22692c3c05dbSStephen Smalley cond_resched(); 22702c3c05dbSStephen Smalley } 22712c3c05dbSStephen Smalley rc = 0; 22722c3c05dbSStephen Smalley kfree(mysids); 22732c3c05dbSStephen Smalley *sids = mysids2; 22742c3c05dbSStephen Smalley *nel = j; 22751da177e4SLinus Torvalds out: 22761da177e4SLinus Torvalds return rc; 22771da177e4SLinus Torvalds } 22781da177e4SLinus Torvalds 22791da177e4SLinus Torvalds /** 2280*f31e7994SWaiman Long * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem 22811da177e4SLinus Torvalds * @fstype: filesystem type 22821da177e4SLinus Torvalds * @path: path from root of mount 22831da177e4SLinus Torvalds * @sclass: file security class 22841da177e4SLinus Torvalds * @sid: SID for path 22851da177e4SLinus Torvalds * 22861da177e4SLinus Torvalds * Obtain a SID to use for a file in a filesystem that 22871da177e4SLinus Torvalds * cannot support xattr or use a fixed labeling behavior like 22881da177e4SLinus Torvalds * transition SIDs or task SIDs. 2289*f31e7994SWaiman Long * 2290*f31e7994SWaiman Long * The caller must acquire the policy_rwlock before calling this function. 22911da177e4SLinus Torvalds */ 2292*f31e7994SWaiman Long static inline int __security_genfs_sid(const char *fstype, 22931da177e4SLinus Torvalds char *path, 2294c6d3aaa4SStephen Smalley u16 orig_sclass, 22951da177e4SLinus Torvalds u32 *sid) 22961da177e4SLinus Torvalds { 22971da177e4SLinus Torvalds int len; 2298c6d3aaa4SStephen Smalley u16 sclass; 22991da177e4SLinus Torvalds struct genfs *genfs; 23001da177e4SLinus Torvalds struct ocontext *c; 23014b02b524SEric Paris int rc, cmp = 0; 23021da177e4SLinus Torvalds 2303b1aa5301SStephen Smalley while (path[0] == '/' && path[1] == '/') 2304b1aa5301SStephen Smalley path++; 2305b1aa5301SStephen Smalley 2306c6d3aaa4SStephen Smalley sclass = unmap_class(orig_sclass); 23074b02b524SEric Paris *sid = SECINITSID_UNLABELED; 2308c6d3aaa4SStephen Smalley 23091da177e4SLinus Torvalds for (genfs = policydb.genfs; genfs; genfs = genfs->next) { 23101da177e4SLinus Torvalds cmp = strcmp(fstype, genfs->fstype); 23111da177e4SLinus Torvalds if (cmp <= 0) 23121da177e4SLinus Torvalds break; 23131da177e4SLinus Torvalds } 23141da177e4SLinus Torvalds 23151da177e4SLinus Torvalds rc = -ENOENT; 23164b02b524SEric Paris if (!genfs || cmp) 23171da177e4SLinus Torvalds goto out; 23181da177e4SLinus Torvalds 23191da177e4SLinus Torvalds for (c = genfs->head; c; c = c->next) { 23201da177e4SLinus Torvalds len = strlen(c->u.name); 23211da177e4SLinus Torvalds if ((!c->v.sclass || sclass == c->v.sclass) && 23221da177e4SLinus Torvalds (strncmp(c->u.name, path, len) == 0)) 23231da177e4SLinus Torvalds break; 23241da177e4SLinus Torvalds } 23251da177e4SLinus Torvalds 23261da177e4SLinus Torvalds rc = -ENOENT; 23274b02b524SEric Paris if (!c) 23281da177e4SLinus Torvalds goto out; 23291da177e4SLinus Torvalds 23301da177e4SLinus Torvalds if (!c->sid[0]) { 23314b02b524SEric Paris rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]); 23321da177e4SLinus Torvalds if (rc) 23331da177e4SLinus Torvalds goto out; 23341da177e4SLinus Torvalds } 23351da177e4SLinus Torvalds 23361da177e4SLinus Torvalds *sid = c->sid[0]; 23374b02b524SEric Paris rc = 0; 23381da177e4SLinus Torvalds out: 23391da177e4SLinus Torvalds return rc; 23401da177e4SLinus Torvalds } 23411da177e4SLinus Torvalds 23421da177e4SLinus Torvalds /** 2343*f31e7994SWaiman Long * security_genfs_sid - Obtain a SID for a file in a filesystem 2344*f31e7994SWaiman Long * @fstype: filesystem type 2345*f31e7994SWaiman Long * @path: path from root of mount 2346*f31e7994SWaiman Long * @sclass: file security class 2347*f31e7994SWaiman Long * @sid: SID for path 2348*f31e7994SWaiman Long * 2349*f31e7994SWaiman Long * Acquire policy_rwlock before calling __security_genfs_sid() and release 2350*f31e7994SWaiman Long * it afterward. 2351*f31e7994SWaiman Long */ 2352*f31e7994SWaiman Long int security_genfs_sid(const char *fstype, 2353*f31e7994SWaiman Long char *path, 2354*f31e7994SWaiman Long u16 orig_sclass, 2355*f31e7994SWaiman Long u32 *sid) 2356*f31e7994SWaiman Long { 2357*f31e7994SWaiman Long int retval; 2358*f31e7994SWaiman Long 2359*f31e7994SWaiman Long read_lock(&policy_rwlock); 2360*f31e7994SWaiman Long retval = __security_genfs_sid(fstype, path, orig_sclass, sid); 2361*f31e7994SWaiman Long read_unlock(&policy_rwlock); 2362*f31e7994SWaiman Long return retval; 2363*f31e7994SWaiman Long } 2364*f31e7994SWaiman Long 2365*f31e7994SWaiman Long /** 23661da177e4SLinus Torvalds * security_fs_use - Determine how to handle labeling for a filesystem. 2367a64c54cfSEric Paris * @sb: superblock in question 23681da177e4SLinus Torvalds */ 2369a64c54cfSEric Paris int security_fs_use(struct super_block *sb) 23701da177e4SLinus Torvalds { 23711da177e4SLinus Torvalds int rc = 0; 23721da177e4SLinus Torvalds struct ocontext *c; 2373a64c54cfSEric Paris struct superblock_security_struct *sbsec = sb->s_security; 2374a64c54cfSEric Paris const char *fstype = sb->s_type->name; 23751da177e4SLinus Torvalds 23760804d113SJames Morris read_lock(&policy_rwlock); 23771da177e4SLinus Torvalds 23784d546f81SPaul Moore c = policydb.ocontexts[OCON_FSUSE]; 23794d546f81SPaul Moore while (c) { 23804d546f81SPaul Moore if (strcmp(fstype, c->u.name) == 0) 23811da177e4SLinus Torvalds break; 23824d546f81SPaul Moore c = c->next; 23831da177e4SLinus Torvalds } 23841da177e4SLinus Torvalds 23851da177e4SLinus Torvalds if (c) { 2386a64c54cfSEric Paris sbsec->behavior = c->v.behavior; 23871da177e4SLinus Torvalds if (!c->sid[0]) { 23884b02b524SEric Paris rc = sidtab_context_to_sid(&sidtab, &c->context[0], 23891da177e4SLinus Torvalds &c->sid[0]); 23901da177e4SLinus Torvalds if (rc) 23911da177e4SLinus Torvalds goto out; 23921da177e4SLinus Torvalds } 2393a64c54cfSEric Paris sbsec->sid = c->sid[0]; 2394089be43eSJames Morris } else { 2395*f31e7994SWaiman Long rc = __security_genfs_sid(fstype, "/", SECCLASS_DIR, 2396*f31e7994SWaiman Long &sbsec->sid); 23971da177e4SLinus Torvalds if (rc) { 2398a64c54cfSEric Paris sbsec->behavior = SECURITY_FS_USE_NONE; 23991da177e4SLinus Torvalds rc = 0; 24001da177e4SLinus Torvalds } else { 2401a64c54cfSEric Paris sbsec->behavior = SECURITY_FS_USE_GENFS; 24021da177e4SLinus Torvalds } 2403089be43eSJames Morris } 24041da177e4SLinus Torvalds 24051da177e4SLinus Torvalds out: 24060804d113SJames Morris read_unlock(&policy_rwlock); 24071da177e4SLinus Torvalds return rc; 24081da177e4SLinus Torvalds } 24091da177e4SLinus Torvalds 24101da177e4SLinus Torvalds int security_get_bools(int *len, char ***names, int **values) 24111da177e4SLinus Torvalds { 24124b02b524SEric Paris int i, rc; 24131da177e4SLinus Torvalds 24140804d113SJames Morris read_lock(&policy_rwlock); 24151da177e4SLinus Torvalds *names = NULL; 24161da177e4SLinus Torvalds *values = NULL; 24171da177e4SLinus Torvalds 24181da177e4SLinus Torvalds rc = 0; 24194b02b524SEric Paris *len = policydb.p_bools.nprim; 24204b02b524SEric Paris if (!*len) 24211da177e4SLinus Torvalds goto out; 24221da177e4SLinus Torvalds 24234b02b524SEric Paris rc = -ENOMEM; 2424e0795cf4SJesper Juhl *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); 24251da177e4SLinus Torvalds if (!*names) 24261da177e4SLinus Torvalds goto err; 24271da177e4SLinus Torvalds 24284b02b524SEric Paris rc = -ENOMEM; 2429e0795cf4SJesper Juhl *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); 24301da177e4SLinus Torvalds if (!*values) 24311da177e4SLinus Torvalds goto err; 24321da177e4SLinus Torvalds 24331da177e4SLinus Torvalds for (i = 0; i < *len; i++) { 24341da177e4SLinus Torvalds size_t name_len; 24354b02b524SEric Paris 24361da177e4SLinus Torvalds (*values)[i] = policydb.bool_val_to_struct[i]->state; 2437ac76c05bSEric Paris name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1; 24384b02b524SEric Paris 24394b02b524SEric Paris rc = -ENOMEM; 2440e0795cf4SJesper Juhl (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC); 24411da177e4SLinus Torvalds if (!(*names)[i]) 24421da177e4SLinus Torvalds goto err; 24434b02b524SEric Paris 2444ac76c05bSEric Paris strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len); 24451da177e4SLinus Torvalds (*names)[i][name_len - 1] = 0; 24461da177e4SLinus Torvalds } 24471da177e4SLinus Torvalds rc = 0; 24481da177e4SLinus Torvalds out: 24490804d113SJames Morris read_unlock(&policy_rwlock); 24501da177e4SLinus Torvalds return rc; 24511da177e4SLinus Torvalds err: 24521da177e4SLinus Torvalds if (*names) { 24531da177e4SLinus Torvalds for (i = 0; i < *len; i++) 24541da177e4SLinus Torvalds kfree((*names)[i]); 24551da177e4SLinus Torvalds } 24561da177e4SLinus Torvalds kfree(*values); 24571da177e4SLinus Torvalds goto out; 24581da177e4SLinus Torvalds } 24591da177e4SLinus Torvalds 24601da177e4SLinus Torvalds 24611da177e4SLinus Torvalds int security_set_bools(int len, int *values) 24621da177e4SLinus Torvalds { 24634b02b524SEric Paris int i, rc; 24641da177e4SLinus Torvalds int lenp, seqno = 0; 24651da177e4SLinus Torvalds struct cond_node *cur; 24661da177e4SLinus Torvalds 24670804d113SJames Morris write_lock_irq(&policy_rwlock); 24681da177e4SLinus Torvalds 24691da177e4SLinus Torvalds rc = -EFAULT; 24704b02b524SEric Paris lenp = policydb.p_bools.nprim; 24714b02b524SEric Paris if (len != lenp) 24721da177e4SLinus Torvalds goto out; 24731da177e4SLinus Torvalds 24741da177e4SLinus Torvalds for (i = 0; i < len; i++) { 2475af601e46SSteve Grubb if (!!values[i] != policydb.bool_val_to_struct[i]->state) { 2476af601e46SSteve Grubb audit_log(current->audit_context, GFP_ATOMIC, 2477af601e46SSteve Grubb AUDIT_MAC_CONFIG_CHANGE, 24784746ec5bSEric Paris "bool=%s val=%d old_val=%d auid=%u ses=%u", 2479ac76c05bSEric Paris sym_name(&policydb, SYM_BOOLS, i), 2480af601e46SSteve Grubb !!values[i], 2481af601e46SSteve Grubb policydb.bool_val_to_struct[i]->state, 2482581abc09SEric W. Biederman from_kuid(&init_user_ns, audit_get_loginuid(current)), 24834746ec5bSEric Paris audit_get_sessionid(current)); 2484af601e46SSteve Grubb } 24855d55a345SEric Paris if (values[i]) 24861da177e4SLinus Torvalds policydb.bool_val_to_struct[i]->state = 1; 24875d55a345SEric Paris else 24881da177e4SLinus Torvalds policydb.bool_val_to_struct[i]->state = 0; 24891da177e4SLinus Torvalds } 24901da177e4SLinus Torvalds 2491dbc74c65SVesa-Matti Kari for (cur = policydb.cond_list; cur; cur = cur->next) { 24921da177e4SLinus Torvalds rc = evaluate_cond_node(&policydb, cur); 24931da177e4SLinus Torvalds if (rc) 24941da177e4SLinus Torvalds goto out; 24951da177e4SLinus Torvalds } 24961da177e4SLinus Torvalds 24971da177e4SLinus Torvalds seqno = ++latest_granting; 24984b02b524SEric Paris rc = 0; 24991da177e4SLinus Torvalds out: 25000804d113SJames Morris write_unlock_irq(&policy_rwlock); 25011da177e4SLinus Torvalds if (!rc) { 25021da177e4SLinus Torvalds avc_ss_reset(seqno); 25031da177e4SLinus Torvalds selnl_notify_policyload(seqno); 250411904167SKaiGai Kohei selinux_status_update_policyload(seqno); 2505342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 25061da177e4SLinus Torvalds } 25071da177e4SLinus Torvalds return rc; 25081da177e4SLinus Torvalds } 25091da177e4SLinus Torvalds 25101da177e4SLinus Torvalds int security_get_bool_value(int bool) 25111da177e4SLinus Torvalds { 25124b02b524SEric Paris int rc; 25131da177e4SLinus Torvalds int len; 25141da177e4SLinus Torvalds 25150804d113SJames Morris read_lock(&policy_rwlock); 25161da177e4SLinus Torvalds 25171da177e4SLinus Torvalds rc = -EFAULT; 25184b02b524SEric Paris len = policydb.p_bools.nprim; 25194b02b524SEric Paris if (bool >= len) 25201da177e4SLinus Torvalds goto out; 25211da177e4SLinus Torvalds 25221da177e4SLinus Torvalds rc = policydb.bool_val_to_struct[bool]->state; 25231da177e4SLinus Torvalds out: 25240804d113SJames Morris read_unlock(&policy_rwlock); 25251da177e4SLinus Torvalds return rc; 25261da177e4SLinus Torvalds } 2527376bd9cbSDarrel Goeddel 2528e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p) 2529e900a7d9SStephen Smalley { 2530e900a7d9SStephen Smalley int rc, nbools = 0, *bvalues = NULL, i; 2531e900a7d9SStephen Smalley char **bnames = NULL; 2532e900a7d9SStephen Smalley struct cond_bool_datum *booldatum; 2533e900a7d9SStephen Smalley struct cond_node *cur; 2534e900a7d9SStephen Smalley 2535e900a7d9SStephen Smalley rc = security_get_bools(&nbools, &bnames, &bvalues); 2536e900a7d9SStephen Smalley if (rc) 2537e900a7d9SStephen Smalley goto out; 2538e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) { 2539e900a7d9SStephen Smalley booldatum = hashtab_search(p->p_bools.table, bnames[i]); 2540e900a7d9SStephen Smalley if (booldatum) 2541e900a7d9SStephen Smalley booldatum->state = bvalues[i]; 2542e900a7d9SStephen Smalley } 2543dbc74c65SVesa-Matti Kari for (cur = p->cond_list; cur; cur = cur->next) { 2544e900a7d9SStephen Smalley rc = evaluate_cond_node(p, cur); 2545e900a7d9SStephen Smalley if (rc) 2546e900a7d9SStephen Smalley goto out; 2547e900a7d9SStephen Smalley } 2548e900a7d9SStephen Smalley 2549e900a7d9SStephen Smalley out: 2550e900a7d9SStephen Smalley if (bnames) { 2551e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) 2552e900a7d9SStephen Smalley kfree(bnames[i]); 2553e900a7d9SStephen Smalley } 2554e900a7d9SStephen Smalley kfree(bnames); 2555e900a7d9SStephen Smalley kfree(bvalues); 2556e900a7d9SStephen Smalley return rc; 2557e900a7d9SStephen Smalley } 2558e900a7d9SStephen Smalley 255908554d6bSVenkat Yekkirala /* 256008554d6bSVenkat Yekkirala * security_sid_mls_copy() - computes a new sid based on the given 256108554d6bSVenkat Yekkirala * sid and the mls portion of mls_sid. 256208554d6bSVenkat Yekkirala */ 256308554d6bSVenkat Yekkirala int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) 256408554d6bSVenkat Yekkirala { 256508554d6bSVenkat Yekkirala struct context *context1; 256608554d6bSVenkat Yekkirala struct context *context2; 256708554d6bSVenkat Yekkirala struct context newcon; 256808554d6bSVenkat Yekkirala char *s; 256908554d6bSVenkat Yekkirala u32 len; 25704b02b524SEric Paris int rc; 257108554d6bSVenkat Yekkirala 25724b02b524SEric Paris rc = 0; 25730719aaf5SGuido Trentalancia if (!ss_initialized || !policydb.mls_enabled) { 257408554d6bSVenkat Yekkirala *new_sid = sid; 257508554d6bSVenkat Yekkirala goto out; 257608554d6bSVenkat Yekkirala } 257708554d6bSVenkat Yekkirala 257808554d6bSVenkat Yekkirala context_init(&newcon); 257908554d6bSVenkat Yekkirala 25800804d113SJames Morris read_lock(&policy_rwlock); 25814b02b524SEric Paris 25824b02b524SEric Paris rc = -EINVAL; 258308554d6bSVenkat Yekkirala context1 = sidtab_search(&sidtab, sid); 258408554d6bSVenkat Yekkirala if (!context1) { 2585744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2586744ba35eSEric Paris __func__, sid); 258708554d6bSVenkat Yekkirala goto out_unlock; 258808554d6bSVenkat Yekkirala } 258908554d6bSVenkat Yekkirala 25904b02b524SEric Paris rc = -EINVAL; 259108554d6bSVenkat Yekkirala context2 = sidtab_search(&sidtab, mls_sid); 259208554d6bSVenkat Yekkirala if (!context2) { 2593744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2594744ba35eSEric Paris __func__, mls_sid); 259508554d6bSVenkat Yekkirala goto out_unlock; 259608554d6bSVenkat Yekkirala } 259708554d6bSVenkat Yekkirala 259808554d6bSVenkat Yekkirala newcon.user = context1->user; 259908554d6bSVenkat Yekkirala newcon.role = context1->role; 260008554d6bSVenkat Yekkirala newcon.type = context1->type; 26010efc61eaSVenkat Yekkirala rc = mls_context_cpy(&newcon, context2); 260208554d6bSVenkat Yekkirala if (rc) 260308554d6bSVenkat Yekkirala goto out_unlock; 260408554d6bSVenkat Yekkirala 260508554d6bSVenkat Yekkirala /* Check the validity of the new context. */ 260608554d6bSVenkat Yekkirala if (!policydb_context_isvalid(&policydb, &newcon)) { 260708554d6bSVenkat Yekkirala rc = convert_context_handle_invalid_context(&newcon); 26084b02b524SEric Paris if (rc) { 260908554d6bSVenkat Yekkirala if (!context_struct_to_string(&newcon, &s, &len)) { 261008554d6bSVenkat Yekkirala audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 261108554d6bSVenkat Yekkirala "security_sid_mls_copy: invalid context %s", s); 261208554d6bSVenkat Yekkirala kfree(s); 261308554d6bSVenkat Yekkirala } 26144b02b524SEric Paris goto out_unlock; 26154b02b524SEric Paris } 26164b02b524SEric Paris } 261708554d6bSVenkat Yekkirala 26184b02b524SEric Paris rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid); 261908554d6bSVenkat Yekkirala out_unlock: 26200804d113SJames Morris read_unlock(&policy_rwlock); 262108554d6bSVenkat Yekkirala context_destroy(&newcon); 262208554d6bSVenkat Yekkirala out: 262308554d6bSVenkat Yekkirala return rc; 262408554d6bSVenkat Yekkirala } 262508554d6bSVenkat Yekkirala 2626220deb96SPaul Moore /** 2627220deb96SPaul Moore * security_net_peersid_resolve - Compare and resolve two network peer SIDs 2628220deb96SPaul Moore * @nlbl_sid: NetLabel SID 2629220deb96SPaul Moore * @nlbl_type: NetLabel labeling protocol type 2630220deb96SPaul Moore * @xfrm_sid: XFRM SID 2631220deb96SPaul Moore * 2632220deb96SPaul Moore * Description: 2633220deb96SPaul Moore * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be 2634220deb96SPaul Moore * resolved into a single SID it is returned via @peer_sid and the function 2635220deb96SPaul Moore * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function 2636220deb96SPaul Moore * returns a negative value. A table summarizing the behavior is below: 2637220deb96SPaul Moore * 2638220deb96SPaul Moore * | function return | @sid 2639220deb96SPaul Moore * ------------------------------+-----------------+----------------- 2640220deb96SPaul Moore * no peer labels | 0 | SECSID_NULL 2641220deb96SPaul Moore * single peer label | 0 | <peer_label> 2642220deb96SPaul Moore * multiple, consistent labels | 0 | <peer_label> 2643220deb96SPaul Moore * multiple, inconsistent labels | -<errno> | SECSID_NULL 2644220deb96SPaul Moore * 2645220deb96SPaul Moore */ 2646220deb96SPaul Moore int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, 2647220deb96SPaul Moore u32 xfrm_sid, 2648220deb96SPaul Moore u32 *peer_sid) 2649220deb96SPaul Moore { 2650220deb96SPaul Moore int rc; 2651220deb96SPaul Moore struct context *nlbl_ctx; 2652220deb96SPaul Moore struct context *xfrm_ctx; 2653220deb96SPaul Moore 26544b02b524SEric Paris *peer_sid = SECSID_NULL; 26554b02b524SEric Paris 2656220deb96SPaul Moore /* handle the common (which also happens to be the set of easy) cases 2657220deb96SPaul Moore * right away, these two if statements catch everything involving a 2658220deb96SPaul Moore * single or absent peer SID/label */ 2659220deb96SPaul Moore if (xfrm_sid == SECSID_NULL) { 2660220deb96SPaul Moore *peer_sid = nlbl_sid; 2661220deb96SPaul Moore return 0; 2662220deb96SPaul Moore } 2663220deb96SPaul Moore /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label 2664220deb96SPaul Moore * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label 2665220deb96SPaul Moore * is present */ 2666220deb96SPaul Moore if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) { 2667220deb96SPaul Moore *peer_sid = xfrm_sid; 2668220deb96SPaul Moore return 0; 2669220deb96SPaul Moore } 2670220deb96SPaul Moore 2671220deb96SPaul Moore /* we don't need to check ss_initialized here since the only way both 2672220deb96SPaul Moore * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the 2673220deb96SPaul Moore * security server was initialized and ss_initialized was true */ 26744b02b524SEric Paris if (!policydb.mls_enabled) 2675220deb96SPaul Moore return 0; 2676220deb96SPaul Moore 26770804d113SJames Morris read_lock(&policy_rwlock); 2678220deb96SPaul Moore 26794b02b524SEric Paris rc = -EINVAL; 2680220deb96SPaul Moore nlbl_ctx = sidtab_search(&sidtab, nlbl_sid); 2681220deb96SPaul Moore if (!nlbl_ctx) { 2682744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2683744ba35eSEric Paris __func__, nlbl_sid); 26844b02b524SEric Paris goto out; 2685220deb96SPaul Moore } 26864b02b524SEric Paris rc = -EINVAL; 2687220deb96SPaul Moore xfrm_ctx = sidtab_search(&sidtab, xfrm_sid); 2688220deb96SPaul Moore if (!xfrm_ctx) { 2689744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2690744ba35eSEric Paris __func__, xfrm_sid); 26914b02b524SEric Paris goto out; 2692220deb96SPaul Moore } 2693220deb96SPaul Moore rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); 26944b02b524SEric Paris if (rc) 26954b02b524SEric Paris goto out; 2696220deb96SPaul Moore 2697220deb96SPaul Moore /* at present NetLabel SIDs/labels really only carry MLS 2698220deb96SPaul Moore * information so if the MLS portion of the NetLabel SID 2699220deb96SPaul Moore * matches the MLS portion of the labeled XFRM SID/label 2700220deb96SPaul Moore * then pass along the XFRM SID as it is the most 2701220deb96SPaul Moore * expressive */ 2702220deb96SPaul Moore *peer_sid = xfrm_sid; 27034b02b524SEric Paris out: 27044b02b524SEric Paris read_unlock(&policy_rwlock); 2705220deb96SPaul Moore return rc; 2706220deb96SPaul Moore } 2707220deb96SPaul Moore 270855fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args) 270955fcf09bSChristopher J. PeBenito { 271055fcf09bSChristopher J. PeBenito struct class_datum *datum = d; 271155fcf09bSChristopher J. PeBenito char *name = k, **classes = args; 271255fcf09bSChristopher J. PeBenito int value = datum->value - 1; 271355fcf09bSChristopher J. PeBenito 271455fcf09bSChristopher J. PeBenito classes[value] = kstrdup(name, GFP_ATOMIC); 271555fcf09bSChristopher J. PeBenito if (!classes[value]) 271655fcf09bSChristopher J. PeBenito return -ENOMEM; 271755fcf09bSChristopher J. PeBenito 271855fcf09bSChristopher J. PeBenito return 0; 271955fcf09bSChristopher J. PeBenito } 272055fcf09bSChristopher J. PeBenito 272155fcf09bSChristopher J. PeBenito int security_get_classes(char ***classes, int *nclasses) 272255fcf09bSChristopher J. PeBenito { 27234b02b524SEric Paris int rc; 272455fcf09bSChristopher J. PeBenito 27250804d113SJames Morris read_lock(&policy_rwlock); 272655fcf09bSChristopher J. PeBenito 27274b02b524SEric Paris rc = -ENOMEM; 272855fcf09bSChristopher J. PeBenito *nclasses = policydb.p_classes.nprim; 27299f59f90bSJulia Lawall *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); 273055fcf09bSChristopher J. PeBenito if (!*classes) 273155fcf09bSChristopher J. PeBenito goto out; 273255fcf09bSChristopher J. PeBenito 273355fcf09bSChristopher J. PeBenito rc = hashtab_map(policydb.p_classes.table, get_classes_callback, 273455fcf09bSChristopher J. PeBenito *classes); 27354b02b524SEric Paris if (rc) { 273655fcf09bSChristopher J. PeBenito int i; 273755fcf09bSChristopher J. PeBenito for (i = 0; i < *nclasses; i++) 273855fcf09bSChristopher J. PeBenito kfree((*classes)[i]); 273955fcf09bSChristopher J. PeBenito kfree(*classes); 274055fcf09bSChristopher J. PeBenito } 274155fcf09bSChristopher J. PeBenito 274255fcf09bSChristopher J. PeBenito out: 27430804d113SJames Morris read_unlock(&policy_rwlock); 274455fcf09bSChristopher J. PeBenito return rc; 274555fcf09bSChristopher J. PeBenito } 274655fcf09bSChristopher J. PeBenito 274755fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args) 274855fcf09bSChristopher J. PeBenito { 274955fcf09bSChristopher J. PeBenito struct perm_datum *datum = d; 275055fcf09bSChristopher J. PeBenito char *name = k, **perms = args; 275155fcf09bSChristopher J. PeBenito int value = datum->value - 1; 275255fcf09bSChristopher J. PeBenito 275355fcf09bSChristopher J. PeBenito perms[value] = kstrdup(name, GFP_ATOMIC); 275455fcf09bSChristopher J. PeBenito if (!perms[value]) 275555fcf09bSChristopher J. PeBenito return -ENOMEM; 275655fcf09bSChristopher J. PeBenito 275755fcf09bSChristopher J. PeBenito return 0; 275855fcf09bSChristopher J. PeBenito } 275955fcf09bSChristopher J. PeBenito 276055fcf09bSChristopher J. PeBenito int security_get_permissions(char *class, char ***perms, int *nperms) 276155fcf09bSChristopher J. PeBenito { 27624b02b524SEric Paris int rc, i; 276355fcf09bSChristopher J. PeBenito struct class_datum *match; 276455fcf09bSChristopher J. PeBenito 27650804d113SJames Morris read_lock(&policy_rwlock); 276655fcf09bSChristopher J. PeBenito 27674b02b524SEric Paris rc = -EINVAL; 276855fcf09bSChristopher J. PeBenito match = hashtab_search(policydb.p_classes.table, class); 276955fcf09bSChristopher J. PeBenito if (!match) { 2770744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized class %s\n", 2771dd6f953aSHarvey Harrison __func__, class); 277255fcf09bSChristopher J. PeBenito goto out; 277355fcf09bSChristopher J. PeBenito } 277455fcf09bSChristopher J. PeBenito 27754b02b524SEric Paris rc = -ENOMEM; 277655fcf09bSChristopher J. PeBenito *nperms = match->permissions.nprim; 27779f59f90bSJulia Lawall *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); 277855fcf09bSChristopher J. PeBenito if (!*perms) 277955fcf09bSChristopher J. PeBenito goto out; 278055fcf09bSChristopher J. PeBenito 278155fcf09bSChristopher J. PeBenito if (match->comdatum) { 278255fcf09bSChristopher J. PeBenito rc = hashtab_map(match->comdatum->permissions.table, 278355fcf09bSChristopher J. PeBenito get_permissions_callback, *perms); 27844b02b524SEric Paris if (rc) 278555fcf09bSChristopher J. PeBenito goto err; 278655fcf09bSChristopher J. PeBenito } 278755fcf09bSChristopher J. PeBenito 278855fcf09bSChristopher J. PeBenito rc = hashtab_map(match->permissions.table, get_permissions_callback, 278955fcf09bSChristopher J. PeBenito *perms); 27904b02b524SEric Paris if (rc) 279155fcf09bSChristopher J. PeBenito goto err; 279255fcf09bSChristopher J. PeBenito 279355fcf09bSChristopher J. PeBenito out: 27940804d113SJames Morris read_unlock(&policy_rwlock); 279555fcf09bSChristopher J. PeBenito return rc; 279655fcf09bSChristopher J. PeBenito 279755fcf09bSChristopher J. PeBenito err: 27980804d113SJames Morris read_unlock(&policy_rwlock); 279955fcf09bSChristopher J. PeBenito for (i = 0; i < *nperms; i++) 280055fcf09bSChristopher J. PeBenito kfree((*perms)[i]); 280155fcf09bSChristopher J. PeBenito kfree(*perms); 280255fcf09bSChristopher J. PeBenito return rc; 280355fcf09bSChristopher J. PeBenito } 280455fcf09bSChristopher J. PeBenito 28053f12070eSEric Paris int security_get_reject_unknown(void) 28063f12070eSEric Paris { 28073f12070eSEric Paris return policydb.reject_unknown; 28083f12070eSEric Paris } 28093f12070eSEric Paris 28103f12070eSEric Paris int security_get_allow_unknown(void) 28113f12070eSEric Paris { 28123f12070eSEric Paris return policydb.allow_unknown; 28133f12070eSEric Paris } 28143f12070eSEric Paris 28153bb56b25SPaul Moore /** 28163bb56b25SPaul Moore * security_policycap_supported - Check for a specific policy capability 28173bb56b25SPaul Moore * @req_cap: capability 28183bb56b25SPaul Moore * 28193bb56b25SPaul Moore * Description: 28203bb56b25SPaul Moore * This function queries the currently loaded policy to see if it supports the 28213bb56b25SPaul Moore * capability specified by @req_cap. Returns true (1) if the capability is 28223bb56b25SPaul Moore * supported, false (0) if it isn't supported. 28233bb56b25SPaul Moore * 28243bb56b25SPaul Moore */ 28253bb56b25SPaul Moore int security_policycap_supported(unsigned int req_cap) 28263bb56b25SPaul Moore { 28273bb56b25SPaul Moore int rc; 28283bb56b25SPaul Moore 28290804d113SJames Morris read_lock(&policy_rwlock); 28303bb56b25SPaul Moore rc = ebitmap_get_bit(&policydb.policycaps, req_cap); 28310804d113SJames Morris read_unlock(&policy_rwlock); 28323bb56b25SPaul Moore 28333bb56b25SPaul Moore return rc; 28343bb56b25SPaul Moore } 28353bb56b25SPaul Moore 2836376bd9cbSDarrel Goeddel struct selinux_audit_rule { 2837376bd9cbSDarrel Goeddel u32 au_seqno; 2838376bd9cbSDarrel Goeddel struct context au_ctxt; 2839376bd9cbSDarrel Goeddel }; 2840376bd9cbSDarrel Goeddel 28419d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule) 2842376bd9cbSDarrel Goeddel { 28439d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule; 28449d57a7f9SAhmed S. Darwish 2845376bd9cbSDarrel Goeddel if (rule) { 2846376bd9cbSDarrel Goeddel context_destroy(&rule->au_ctxt); 2847376bd9cbSDarrel Goeddel kfree(rule); 2848376bd9cbSDarrel Goeddel } 2849376bd9cbSDarrel Goeddel } 2850376bd9cbSDarrel Goeddel 28519d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) 2852376bd9cbSDarrel Goeddel { 2853376bd9cbSDarrel Goeddel struct selinux_audit_rule *tmprule; 2854376bd9cbSDarrel Goeddel struct role_datum *roledatum; 2855376bd9cbSDarrel Goeddel struct type_datum *typedatum; 2856376bd9cbSDarrel Goeddel struct user_datum *userdatum; 28579d57a7f9SAhmed S. Darwish struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule; 2858376bd9cbSDarrel Goeddel int rc = 0; 2859376bd9cbSDarrel Goeddel 2860376bd9cbSDarrel Goeddel *rule = NULL; 2861376bd9cbSDarrel Goeddel 2862376bd9cbSDarrel Goeddel if (!ss_initialized) 28633ad40d64SSteve G return -EOPNOTSUPP; 2864376bd9cbSDarrel Goeddel 2865376bd9cbSDarrel Goeddel switch (field) { 28663a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 28673a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 28683a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 28696e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 28706e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 28716e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 2872376bd9cbSDarrel Goeddel /* only 'equals' and 'not equals' fit user, role, and type */ 28735af75d8dSAl Viro if (op != Audit_equal && op != Audit_not_equal) 2874376bd9cbSDarrel Goeddel return -EINVAL; 2875376bd9cbSDarrel Goeddel break; 28763a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 28773a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 28786e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 28796e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 288025985edcSLucas De Marchi /* we do not allow a range, indicated by the presence of '-' */ 2881376bd9cbSDarrel Goeddel if (strchr(rulestr, '-')) 2882376bd9cbSDarrel Goeddel return -EINVAL; 2883376bd9cbSDarrel Goeddel break; 2884376bd9cbSDarrel Goeddel default: 2885376bd9cbSDarrel Goeddel /* only the above fields are valid */ 2886376bd9cbSDarrel Goeddel return -EINVAL; 2887376bd9cbSDarrel Goeddel } 2888376bd9cbSDarrel Goeddel 2889376bd9cbSDarrel Goeddel tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL); 2890376bd9cbSDarrel Goeddel if (!tmprule) 2891376bd9cbSDarrel Goeddel return -ENOMEM; 2892376bd9cbSDarrel Goeddel 2893376bd9cbSDarrel Goeddel context_init(&tmprule->au_ctxt); 2894376bd9cbSDarrel Goeddel 28950804d113SJames Morris read_lock(&policy_rwlock); 2896376bd9cbSDarrel Goeddel 2897376bd9cbSDarrel Goeddel tmprule->au_seqno = latest_granting; 2898376bd9cbSDarrel Goeddel 2899376bd9cbSDarrel Goeddel switch (field) { 29003a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 29016e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 29024b02b524SEric Paris rc = -EINVAL; 2903376bd9cbSDarrel Goeddel userdatum = hashtab_search(policydb.p_users.table, rulestr); 2904376bd9cbSDarrel Goeddel if (!userdatum) 29054b02b524SEric Paris goto out; 2906376bd9cbSDarrel Goeddel tmprule->au_ctxt.user = userdatum->value; 2907376bd9cbSDarrel Goeddel break; 29083a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 29096e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 29104b02b524SEric Paris rc = -EINVAL; 2911376bd9cbSDarrel Goeddel roledatum = hashtab_search(policydb.p_roles.table, rulestr); 2912376bd9cbSDarrel Goeddel if (!roledatum) 29134b02b524SEric Paris goto out; 2914376bd9cbSDarrel Goeddel tmprule->au_ctxt.role = roledatum->value; 2915376bd9cbSDarrel Goeddel break; 29163a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 29176e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 29184b02b524SEric Paris rc = -EINVAL; 2919376bd9cbSDarrel Goeddel typedatum = hashtab_search(policydb.p_types.table, rulestr); 2920376bd9cbSDarrel Goeddel if (!typedatum) 29214b02b524SEric Paris goto out; 2922376bd9cbSDarrel Goeddel tmprule->au_ctxt.type = typedatum->value; 2923376bd9cbSDarrel Goeddel break; 29243a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 29253a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 29266e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 29276e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 2928376bd9cbSDarrel Goeddel rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC); 29294b02b524SEric Paris if (rc) 29304b02b524SEric Paris goto out; 2931376bd9cbSDarrel Goeddel break; 2932376bd9cbSDarrel Goeddel } 29334b02b524SEric Paris rc = 0; 29344b02b524SEric Paris out: 29350804d113SJames Morris read_unlock(&policy_rwlock); 2936376bd9cbSDarrel Goeddel 2937376bd9cbSDarrel Goeddel if (rc) { 2938376bd9cbSDarrel Goeddel selinux_audit_rule_free(tmprule); 2939376bd9cbSDarrel Goeddel tmprule = NULL; 2940376bd9cbSDarrel Goeddel } 2941376bd9cbSDarrel Goeddel 2942376bd9cbSDarrel Goeddel *rule = tmprule; 2943376bd9cbSDarrel Goeddel 2944376bd9cbSDarrel Goeddel return rc; 2945376bd9cbSDarrel Goeddel } 2946376bd9cbSDarrel Goeddel 29479d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */ 29489d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule) 29499d57a7f9SAhmed S. Darwish { 29509d57a7f9SAhmed S. Darwish int i; 29519d57a7f9SAhmed S. Darwish 29529d57a7f9SAhmed S. Darwish for (i = 0; i < rule->field_count; i++) { 29539d57a7f9SAhmed S. Darwish struct audit_field *f = &rule->fields[i]; 29549d57a7f9SAhmed S. Darwish switch (f->type) { 29559d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_USER: 29569d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_ROLE: 29579d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_TYPE: 29589d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_SEN: 29599d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_CLR: 29609d57a7f9SAhmed S. Darwish case AUDIT_OBJ_USER: 29619d57a7f9SAhmed S. Darwish case AUDIT_OBJ_ROLE: 29629d57a7f9SAhmed S. Darwish case AUDIT_OBJ_TYPE: 29639d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_LOW: 29649d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_HIGH: 29659d57a7f9SAhmed S. Darwish return 1; 29669d57a7f9SAhmed S. Darwish } 29679d57a7f9SAhmed S. Darwish } 29689d57a7f9SAhmed S. Darwish 29699d57a7f9SAhmed S. Darwish return 0; 29709d57a7f9SAhmed S. Darwish } 29719d57a7f9SAhmed S. Darwish 29729d57a7f9SAhmed S. Darwish int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, 2973376bd9cbSDarrel Goeddel struct audit_context *actx) 2974376bd9cbSDarrel Goeddel { 2975376bd9cbSDarrel Goeddel struct context *ctxt; 2976376bd9cbSDarrel Goeddel struct mls_level *level; 29779d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule; 2978376bd9cbSDarrel Goeddel int match = 0; 2979376bd9cbSDarrel Goeddel 29809ad42a79SRichard Guy Briggs if (unlikely(!rule)) { 29819ad42a79SRichard Guy Briggs WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n"); 2982376bd9cbSDarrel Goeddel return -ENOENT; 2983376bd9cbSDarrel Goeddel } 2984376bd9cbSDarrel Goeddel 29850804d113SJames Morris read_lock(&policy_rwlock); 2986376bd9cbSDarrel Goeddel 2987376bd9cbSDarrel Goeddel if (rule->au_seqno < latest_granting) { 2988376bd9cbSDarrel Goeddel match = -ESTALE; 2989376bd9cbSDarrel Goeddel goto out; 2990376bd9cbSDarrel Goeddel } 2991376bd9cbSDarrel Goeddel 29929a2f44f0SStephen Smalley ctxt = sidtab_search(&sidtab, sid); 29939ad42a79SRichard Guy Briggs if (unlikely(!ctxt)) { 29949ad42a79SRichard Guy Briggs WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", 29959a2f44f0SStephen Smalley sid); 2996376bd9cbSDarrel Goeddel match = -ENOENT; 2997376bd9cbSDarrel Goeddel goto out; 2998376bd9cbSDarrel Goeddel } 2999376bd9cbSDarrel Goeddel 3000376bd9cbSDarrel Goeddel /* a field/op pair that is not caught here will simply fall through 3001376bd9cbSDarrel Goeddel without a match */ 3002376bd9cbSDarrel Goeddel switch (field) { 30033a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 30046e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 3005376bd9cbSDarrel Goeddel switch (op) { 30065af75d8dSAl Viro case Audit_equal: 3007376bd9cbSDarrel Goeddel match = (ctxt->user == rule->au_ctxt.user); 3008376bd9cbSDarrel Goeddel break; 30095af75d8dSAl Viro case Audit_not_equal: 3010376bd9cbSDarrel Goeddel match = (ctxt->user != rule->au_ctxt.user); 3011376bd9cbSDarrel Goeddel break; 3012376bd9cbSDarrel Goeddel } 3013376bd9cbSDarrel Goeddel break; 30143a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 30156e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 3016376bd9cbSDarrel Goeddel switch (op) { 30175af75d8dSAl Viro case Audit_equal: 3018376bd9cbSDarrel Goeddel match = (ctxt->role == rule->au_ctxt.role); 3019376bd9cbSDarrel Goeddel break; 30205af75d8dSAl Viro case Audit_not_equal: 3021376bd9cbSDarrel Goeddel match = (ctxt->role != rule->au_ctxt.role); 3022376bd9cbSDarrel Goeddel break; 3023376bd9cbSDarrel Goeddel } 3024376bd9cbSDarrel Goeddel break; 30253a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 30266e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 3027376bd9cbSDarrel Goeddel switch (op) { 30285af75d8dSAl Viro case Audit_equal: 3029376bd9cbSDarrel Goeddel match = (ctxt->type == rule->au_ctxt.type); 3030376bd9cbSDarrel Goeddel break; 30315af75d8dSAl Viro case Audit_not_equal: 3032376bd9cbSDarrel Goeddel match = (ctxt->type != rule->au_ctxt.type); 3033376bd9cbSDarrel Goeddel break; 3034376bd9cbSDarrel Goeddel } 3035376bd9cbSDarrel Goeddel break; 30363a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 30373a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 30386e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 30396e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 30406e5a2d1dSDarrel Goeddel level = ((field == AUDIT_SUBJ_SEN || 30416e5a2d1dSDarrel Goeddel field == AUDIT_OBJ_LEV_LOW) ? 3042376bd9cbSDarrel Goeddel &ctxt->range.level[0] : &ctxt->range.level[1]); 3043376bd9cbSDarrel Goeddel switch (op) { 30445af75d8dSAl Viro case Audit_equal: 3045376bd9cbSDarrel Goeddel match = mls_level_eq(&rule->au_ctxt.range.level[0], 3046376bd9cbSDarrel Goeddel level); 3047376bd9cbSDarrel Goeddel break; 30485af75d8dSAl Viro case Audit_not_equal: 3049376bd9cbSDarrel Goeddel match = !mls_level_eq(&rule->au_ctxt.range.level[0], 3050376bd9cbSDarrel Goeddel level); 3051376bd9cbSDarrel Goeddel break; 30525af75d8dSAl Viro case Audit_lt: 3053376bd9cbSDarrel Goeddel match = (mls_level_dom(&rule->au_ctxt.range.level[0], 3054376bd9cbSDarrel Goeddel level) && 3055376bd9cbSDarrel Goeddel !mls_level_eq(&rule->au_ctxt.range.level[0], 3056376bd9cbSDarrel Goeddel level)); 3057376bd9cbSDarrel Goeddel break; 30585af75d8dSAl Viro case Audit_le: 3059376bd9cbSDarrel Goeddel match = mls_level_dom(&rule->au_ctxt.range.level[0], 3060376bd9cbSDarrel Goeddel level); 3061376bd9cbSDarrel Goeddel break; 30625af75d8dSAl Viro case Audit_gt: 3063376bd9cbSDarrel Goeddel match = (mls_level_dom(level, 3064376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]) && 3065376bd9cbSDarrel Goeddel !mls_level_eq(level, 3066376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0])); 3067376bd9cbSDarrel Goeddel break; 30685af75d8dSAl Viro case Audit_ge: 3069376bd9cbSDarrel Goeddel match = mls_level_dom(level, 3070376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]); 3071376bd9cbSDarrel Goeddel break; 3072376bd9cbSDarrel Goeddel } 3073376bd9cbSDarrel Goeddel } 3074376bd9cbSDarrel Goeddel 3075376bd9cbSDarrel Goeddel out: 30760804d113SJames Morris read_unlock(&policy_rwlock); 3077376bd9cbSDarrel Goeddel return match; 3078376bd9cbSDarrel Goeddel } 3079376bd9cbSDarrel Goeddel 30809d57a7f9SAhmed S. Darwish static int (*aurule_callback)(void) = audit_update_lsm_rules; 3081376bd9cbSDarrel Goeddel 3082562c99f2SWanlong Gao static int aurule_avc_callback(u32 event) 3083376bd9cbSDarrel Goeddel { 3084376bd9cbSDarrel Goeddel int err = 0; 3085376bd9cbSDarrel Goeddel 3086376bd9cbSDarrel Goeddel if (event == AVC_CALLBACK_RESET && aurule_callback) 3087376bd9cbSDarrel Goeddel err = aurule_callback(); 3088376bd9cbSDarrel Goeddel return err; 3089376bd9cbSDarrel Goeddel } 3090376bd9cbSDarrel Goeddel 3091376bd9cbSDarrel Goeddel static int __init aurule_init(void) 3092376bd9cbSDarrel Goeddel { 3093376bd9cbSDarrel Goeddel int err; 3094376bd9cbSDarrel Goeddel 3095562c99f2SWanlong Gao err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET); 3096376bd9cbSDarrel Goeddel if (err) 3097376bd9cbSDarrel Goeddel panic("avc_add_callback() failed, error %d\n", err); 3098376bd9cbSDarrel Goeddel 3099376bd9cbSDarrel Goeddel return err; 3100376bd9cbSDarrel Goeddel } 3101376bd9cbSDarrel Goeddel __initcall(aurule_init); 3102376bd9cbSDarrel Goeddel 31037420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL 31047420ed23SVenkat Yekkirala /** 31055778eabdSPaul Moore * security_netlbl_cache_add - Add an entry to the NetLabel cache 31065778eabdSPaul Moore * @secattr: the NetLabel packet security attributes 31075dbe1eb0SPaul Moore * @sid: the SELinux SID 31087420ed23SVenkat Yekkirala * 31097420ed23SVenkat Yekkirala * Description: 31107420ed23SVenkat Yekkirala * Attempt to cache the context in @ctx, which was derived from the packet in 31115778eabdSPaul Moore * @skb, in the NetLabel subsystem cache. This function assumes @secattr has 31125778eabdSPaul Moore * already been initialized. 31137420ed23SVenkat Yekkirala * 31147420ed23SVenkat Yekkirala */ 31155778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, 31165dbe1eb0SPaul Moore u32 sid) 31177420ed23SVenkat Yekkirala { 31185dbe1eb0SPaul Moore u32 *sid_cache; 31197420ed23SVenkat Yekkirala 31205dbe1eb0SPaul Moore sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC); 31215dbe1eb0SPaul Moore if (sid_cache == NULL) 31225dbe1eb0SPaul Moore return; 31235778eabdSPaul Moore secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); 31245dbe1eb0SPaul Moore if (secattr->cache == NULL) { 31255dbe1eb0SPaul Moore kfree(sid_cache); 31265778eabdSPaul Moore return; 31270ec8abd7SJesper Juhl } 31287420ed23SVenkat Yekkirala 31295dbe1eb0SPaul Moore *sid_cache = sid; 31305dbe1eb0SPaul Moore secattr->cache->free = kfree; 31315dbe1eb0SPaul Moore secattr->cache->data = sid_cache; 31325778eabdSPaul Moore secattr->flags |= NETLBL_SECATTR_CACHE; 31337420ed23SVenkat Yekkirala } 31347420ed23SVenkat Yekkirala 31357420ed23SVenkat Yekkirala /** 31365778eabdSPaul Moore * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID 31377420ed23SVenkat Yekkirala * @secattr: the NetLabel packet security attributes 31387420ed23SVenkat Yekkirala * @sid: the SELinux SID 31397420ed23SVenkat Yekkirala * 31407420ed23SVenkat Yekkirala * Description: 31415778eabdSPaul Moore * Convert the given NetLabel security attributes in @secattr into a 31427420ed23SVenkat Yekkirala * SELinux SID. If the @secattr field does not contain a full SELinux 314325985edcSLucas De Marchi * SID/context then use SECINITSID_NETMSG as the foundation. If possible the 31445dbe1eb0SPaul Moore * 'cache' field of @secattr is set and the CACHE flag is set; this is to 31455dbe1eb0SPaul Moore * allow the @secattr to be used by NetLabel to cache the secattr to SID 31465dbe1eb0SPaul Moore * conversion for future lookups. Returns zero on success, negative values on 31475dbe1eb0SPaul Moore * failure. 31487420ed23SVenkat Yekkirala * 31497420ed23SVenkat Yekkirala */ 31505778eabdSPaul Moore int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, 31517420ed23SVenkat Yekkirala u32 *sid) 31527420ed23SVenkat Yekkirala { 31537ae9f23cSEric Paris int rc; 31547420ed23SVenkat Yekkirala struct context *ctx; 31557420ed23SVenkat Yekkirala struct context ctx_new; 31565778eabdSPaul Moore 31575778eabdSPaul Moore if (!ss_initialized) { 31585778eabdSPaul Moore *sid = SECSID_NULL; 31595778eabdSPaul Moore return 0; 31605778eabdSPaul Moore } 31617420ed23SVenkat Yekkirala 31620804d113SJames Morris read_lock(&policy_rwlock); 31637420ed23SVenkat Yekkirala 31647ae9f23cSEric Paris if (secattr->flags & NETLBL_SECATTR_CACHE) 31655dbe1eb0SPaul Moore *sid = *(u32 *)secattr->cache->data; 31667ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_SECID) 316716efd454SPaul Moore *sid = secattr->attr.secid; 31687ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { 31697ae9f23cSEric Paris rc = -EIDRM; 31705dbe1eb0SPaul Moore ctx = sidtab_search(&sidtab, SECINITSID_NETMSG); 31717420ed23SVenkat Yekkirala if (ctx == NULL) 31727ae9f23cSEric Paris goto out; 31737420ed23SVenkat Yekkirala 317481990fbdSPaul Moore context_init(&ctx_new); 31757420ed23SVenkat Yekkirala ctx_new.user = ctx->user; 31767420ed23SVenkat Yekkirala ctx_new.role = ctx->role; 31777420ed23SVenkat Yekkirala ctx_new.type = ctx->type; 317802752760SPaul Moore mls_import_netlbl_lvl(&ctx_new, secattr); 3179701a90baSPaul Moore if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 31807ae9f23cSEric Paris rc = ebitmap_netlbl_import(&ctx_new.range.level[0].cat, 31817ae9f23cSEric Paris secattr->attr.mls.cat); 31827ae9f23cSEric Paris if (rc) 31837ae9f23cSEric Paris goto out; 318481990fbdSPaul Moore memcpy(&ctx_new.range.level[1].cat, 318581990fbdSPaul Moore &ctx_new.range.level[0].cat, 318681990fbdSPaul Moore sizeof(ctx_new.range.level[0].cat)); 31877420ed23SVenkat Yekkirala } 31887ae9f23cSEric Paris rc = -EIDRM; 31897ae9f23cSEric Paris if (!mls_context_isvalid(&policydb, &ctx_new)) 31907ae9f23cSEric Paris goto out_free; 31917420ed23SVenkat Yekkirala 31927420ed23SVenkat Yekkirala rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid); 31937ae9f23cSEric Paris if (rc) 31947ae9f23cSEric Paris goto out_free; 31957420ed23SVenkat Yekkirala 31965dbe1eb0SPaul Moore security_netlbl_cache_add(secattr, *sid); 31975778eabdSPaul Moore 31987420ed23SVenkat Yekkirala ebitmap_destroy(&ctx_new.range.level[0].cat); 31997ae9f23cSEric Paris } else 3200388b2405Spaul.moore@hp.com *sid = SECSID_NULL; 32017420ed23SVenkat Yekkirala 32027ae9f23cSEric Paris read_unlock(&policy_rwlock); 32037ae9f23cSEric Paris return 0; 32047ae9f23cSEric Paris out_free: 32057ae9f23cSEric Paris ebitmap_destroy(&ctx_new.range.level[0].cat); 32067ae9f23cSEric Paris out: 32070804d113SJames Morris read_unlock(&policy_rwlock); 32087420ed23SVenkat Yekkirala return rc; 32097420ed23SVenkat Yekkirala } 32107420ed23SVenkat Yekkirala 32117420ed23SVenkat Yekkirala /** 32125778eabdSPaul Moore * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr 32135778eabdSPaul Moore * @sid: the SELinux SID 32145778eabdSPaul Moore * @secattr: the NetLabel packet security attributes 32157420ed23SVenkat Yekkirala * 32167420ed23SVenkat Yekkirala * Description: 32175778eabdSPaul Moore * Convert the given SELinux SID in @sid into a NetLabel security attribute. 32185778eabdSPaul Moore * Returns zero on success, negative values on failure. 32197420ed23SVenkat Yekkirala * 32207420ed23SVenkat Yekkirala */ 32215778eabdSPaul Moore int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) 32227420ed23SVenkat Yekkirala { 322399d854d2SPaul Moore int rc; 32247420ed23SVenkat Yekkirala struct context *ctx; 32257420ed23SVenkat Yekkirala 32267420ed23SVenkat Yekkirala if (!ss_initialized) 32277420ed23SVenkat Yekkirala return 0; 32287420ed23SVenkat Yekkirala 32290804d113SJames Morris read_lock(&policy_rwlock); 32304b02b524SEric Paris 323199d854d2SPaul Moore rc = -ENOENT; 32324b02b524SEric Paris ctx = sidtab_search(&sidtab, sid); 32334b02b524SEric Paris if (ctx == NULL) 32344b02b524SEric Paris goto out; 32354b02b524SEric Paris 32364b02b524SEric Paris rc = -ENOMEM; 3237ac76c05bSEric Paris secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1), 32387420ed23SVenkat Yekkirala GFP_ATOMIC); 32394b02b524SEric Paris if (secattr->domain == NULL) 32404b02b524SEric Paris goto out; 32414b02b524SEric Paris 32428d75899dSPaul Moore secattr->attr.secid = sid; 32438d75899dSPaul Moore secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; 32445778eabdSPaul Moore mls_export_netlbl_lvl(ctx, secattr); 32455778eabdSPaul Moore rc = mls_export_netlbl_cat(ctx, secattr); 32464b02b524SEric Paris out: 32470804d113SJames Morris read_unlock(&policy_rwlock); 3248f8687afeSPaul Moore return rc; 3249f8687afeSPaul Moore } 32507420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */ 3251cee74f47SEric Paris 3252cee74f47SEric Paris /** 3253cee74f47SEric Paris * security_read_policy - read the policy. 3254cee74f47SEric Paris * @data: binary policy data 3255cee74f47SEric Paris * @len: length of data in bytes 3256cee74f47SEric Paris * 3257cee74f47SEric Paris */ 32586b697323SEric Paris int security_read_policy(void **data, size_t *len) 3259cee74f47SEric Paris { 3260cee74f47SEric Paris int rc; 3261cee74f47SEric Paris struct policy_file fp; 3262cee74f47SEric Paris 3263cee74f47SEric Paris if (!ss_initialized) 3264cee74f47SEric Paris return -EINVAL; 3265cee74f47SEric Paris 3266cee74f47SEric Paris *len = security_policydb_len(); 3267cee74f47SEric Paris 3268845ca30fSEric Paris *data = vmalloc_user(*len); 3269cee74f47SEric Paris if (!*data) 3270cee74f47SEric Paris return -ENOMEM; 3271cee74f47SEric Paris 3272cee74f47SEric Paris fp.data = *data; 3273cee74f47SEric Paris fp.len = *len; 3274cee74f47SEric Paris 3275cee74f47SEric Paris read_lock(&policy_rwlock); 3276cee74f47SEric Paris rc = policydb_write(&policydb, &fp); 3277cee74f47SEric Paris read_unlock(&policy_rwlock); 3278cee74f47SEric Paris 3279cee74f47SEric Paris if (rc) 3280cee74f47SEric Paris return rc; 3281cee74f47SEric Paris 3282cee74f47SEric Paris *len = (unsigned long)fp.data - (unsigned long)*data; 3283cee74f47SEric Paris return 0; 3284cee74f47SEric Paris 3285cee74f47SEric Paris } 3286