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, 98fa1aa143SJeff Vander Stoep struct av_decision *avd, 99fa1aa143SJeff Vander Stoep struct extended_perms *xperms); 100c6d3aaa4SStephen Smalley 101c6d3aaa4SStephen Smalley struct selinux_mapping { 102c6d3aaa4SStephen Smalley u16 value; /* policy value */ 103c6d3aaa4SStephen Smalley unsigned num_perms; 104c6d3aaa4SStephen Smalley u32 perms[sizeof(u32) * 8]; 105c6d3aaa4SStephen Smalley }; 106c6d3aaa4SStephen Smalley 107c6d3aaa4SStephen Smalley static struct selinux_mapping *current_mapping; 108c6d3aaa4SStephen Smalley static u16 current_mapping_size; 109c6d3aaa4SStephen Smalley 110c6d3aaa4SStephen Smalley static int selinux_set_mapping(struct policydb *pol, 111c6d3aaa4SStephen Smalley struct security_class_mapping *map, 112c6d3aaa4SStephen Smalley struct selinux_mapping **out_map_p, 113c6d3aaa4SStephen Smalley u16 *out_map_size) 114c6d3aaa4SStephen Smalley { 115c6d3aaa4SStephen Smalley struct selinux_mapping *out_map = NULL; 116c6d3aaa4SStephen Smalley size_t size = sizeof(struct selinux_mapping); 117c6d3aaa4SStephen Smalley u16 i, j; 118c6d3aaa4SStephen Smalley unsigned k; 119c6d3aaa4SStephen Smalley bool print_unknown_handle = false; 120c6d3aaa4SStephen Smalley 121c6d3aaa4SStephen Smalley /* Find number of classes in the input mapping */ 122c6d3aaa4SStephen Smalley if (!map) 123c6d3aaa4SStephen Smalley return -EINVAL; 124c6d3aaa4SStephen Smalley i = 0; 125c6d3aaa4SStephen Smalley while (map[i].name) 126c6d3aaa4SStephen Smalley i++; 127c6d3aaa4SStephen Smalley 128c6d3aaa4SStephen Smalley /* Allocate space for the class records, plus one for class zero */ 129c6d3aaa4SStephen Smalley out_map = kcalloc(++i, size, GFP_ATOMIC); 130c6d3aaa4SStephen Smalley if (!out_map) 131c6d3aaa4SStephen Smalley return -ENOMEM; 132c6d3aaa4SStephen Smalley 133c6d3aaa4SStephen Smalley /* Store the raw class and permission values */ 134c6d3aaa4SStephen Smalley j = 0; 135c6d3aaa4SStephen Smalley while (map[j].name) { 136c6d3aaa4SStephen Smalley struct security_class_mapping *p_in = map + (j++); 137c6d3aaa4SStephen Smalley struct selinux_mapping *p_out = out_map + j; 138c6d3aaa4SStephen Smalley 139c6d3aaa4SStephen Smalley /* An empty class string skips ahead */ 140c6d3aaa4SStephen Smalley if (!strcmp(p_in->name, "")) { 141c6d3aaa4SStephen Smalley p_out->num_perms = 0; 142c6d3aaa4SStephen Smalley continue; 143c6d3aaa4SStephen Smalley } 144c6d3aaa4SStephen Smalley 145c6d3aaa4SStephen Smalley p_out->value = string_to_security_class(pol, p_in->name); 146c6d3aaa4SStephen Smalley if (!p_out->value) { 147c6d3aaa4SStephen Smalley printk(KERN_INFO 148c6d3aaa4SStephen Smalley "SELinux: Class %s not defined in policy.\n", 149c6d3aaa4SStephen Smalley p_in->name); 150c6d3aaa4SStephen Smalley if (pol->reject_unknown) 151c6d3aaa4SStephen Smalley goto err; 152c6d3aaa4SStephen Smalley p_out->num_perms = 0; 153c6d3aaa4SStephen Smalley print_unknown_handle = true; 154c6d3aaa4SStephen Smalley continue; 155c6d3aaa4SStephen Smalley } 156c6d3aaa4SStephen Smalley 157c6d3aaa4SStephen Smalley k = 0; 158c6d3aaa4SStephen Smalley while (p_in->perms && p_in->perms[k]) { 159c6d3aaa4SStephen Smalley /* An empty permission string skips ahead */ 160c6d3aaa4SStephen Smalley if (!*p_in->perms[k]) { 161c6d3aaa4SStephen Smalley k++; 162c6d3aaa4SStephen Smalley continue; 163c6d3aaa4SStephen Smalley } 164c6d3aaa4SStephen Smalley p_out->perms[k] = string_to_av_perm(pol, p_out->value, 165c6d3aaa4SStephen Smalley p_in->perms[k]); 166c6d3aaa4SStephen Smalley if (!p_out->perms[k]) { 167c6d3aaa4SStephen Smalley printk(KERN_INFO 168c6d3aaa4SStephen Smalley "SELinux: Permission %s in class %s not defined in policy.\n", 169c6d3aaa4SStephen Smalley p_in->perms[k], p_in->name); 170c6d3aaa4SStephen Smalley if (pol->reject_unknown) 171c6d3aaa4SStephen Smalley goto err; 172c6d3aaa4SStephen Smalley print_unknown_handle = true; 173c6d3aaa4SStephen Smalley } 174c6d3aaa4SStephen Smalley 175c6d3aaa4SStephen Smalley k++; 176c6d3aaa4SStephen Smalley } 177c6d3aaa4SStephen Smalley p_out->num_perms = k; 178c6d3aaa4SStephen Smalley } 179c6d3aaa4SStephen Smalley 180c6d3aaa4SStephen Smalley if (print_unknown_handle) 181c6d3aaa4SStephen Smalley printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n", 182c6d3aaa4SStephen Smalley pol->allow_unknown ? "allowed" : "denied"); 183c6d3aaa4SStephen Smalley 184c6d3aaa4SStephen Smalley *out_map_p = out_map; 185c6d3aaa4SStephen Smalley *out_map_size = i; 186c6d3aaa4SStephen Smalley return 0; 187c6d3aaa4SStephen Smalley err: 188c6d3aaa4SStephen Smalley kfree(out_map); 189c6d3aaa4SStephen Smalley return -EINVAL; 190c6d3aaa4SStephen Smalley } 191c6d3aaa4SStephen Smalley 192c6d3aaa4SStephen Smalley /* 193c6d3aaa4SStephen Smalley * Get real, policy values from mapped values 194c6d3aaa4SStephen Smalley */ 195c6d3aaa4SStephen Smalley 196c6d3aaa4SStephen Smalley static u16 unmap_class(u16 tclass) 197c6d3aaa4SStephen Smalley { 198c6d3aaa4SStephen Smalley if (tclass < current_mapping_size) 199c6d3aaa4SStephen Smalley return current_mapping[tclass].value; 200c6d3aaa4SStephen Smalley 201c6d3aaa4SStephen Smalley return tclass; 202c6d3aaa4SStephen Smalley } 203c6d3aaa4SStephen Smalley 2046f5317e7SHarry Ciao /* 2056f5317e7SHarry Ciao * Get kernel value for class from its policy value 2066f5317e7SHarry Ciao */ 2076f5317e7SHarry Ciao static u16 map_class(u16 pol_value) 2086f5317e7SHarry Ciao { 2096f5317e7SHarry Ciao u16 i; 2106f5317e7SHarry Ciao 2116f5317e7SHarry Ciao for (i = 1; i < current_mapping_size; i++) { 2126f5317e7SHarry Ciao if (current_mapping[i].value == pol_value) 2136f5317e7SHarry Ciao return i; 2146f5317e7SHarry Ciao } 2156f5317e7SHarry Ciao 21685cd6da5SStephen Smalley return SECCLASS_NULL; 2176f5317e7SHarry Ciao } 2186f5317e7SHarry Ciao 219c6d3aaa4SStephen Smalley static void map_decision(u16 tclass, struct av_decision *avd, 220c6d3aaa4SStephen Smalley int allow_unknown) 221c6d3aaa4SStephen Smalley { 222c6d3aaa4SStephen Smalley if (tclass < current_mapping_size) { 223c6d3aaa4SStephen Smalley unsigned i, n = current_mapping[tclass].num_perms; 224c6d3aaa4SStephen Smalley u32 result; 225c6d3aaa4SStephen Smalley 226c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) { 227c6d3aaa4SStephen Smalley if (avd->allowed & current_mapping[tclass].perms[i]) 228c6d3aaa4SStephen Smalley result |= 1<<i; 229c6d3aaa4SStephen Smalley if (allow_unknown && !current_mapping[tclass].perms[i]) 230c6d3aaa4SStephen Smalley result |= 1<<i; 231c6d3aaa4SStephen Smalley } 232c6d3aaa4SStephen Smalley avd->allowed = result; 233c6d3aaa4SStephen Smalley 234c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) 235c6d3aaa4SStephen Smalley if (avd->auditallow & current_mapping[tclass].perms[i]) 236c6d3aaa4SStephen Smalley result |= 1<<i; 237c6d3aaa4SStephen Smalley avd->auditallow = result; 238c6d3aaa4SStephen Smalley 239c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) { 240c6d3aaa4SStephen Smalley if (avd->auditdeny & current_mapping[tclass].perms[i]) 241c6d3aaa4SStephen Smalley result |= 1<<i; 242c6d3aaa4SStephen Smalley if (!allow_unknown && !current_mapping[tclass].perms[i]) 243c6d3aaa4SStephen Smalley result |= 1<<i; 244c6d3aaa4SStephen Smalley } 2450bce9527SEric Paris /* 2460bce9527SEric Paris * In case the kernel has a bug and requests a permission 2470bce9527SEric Paris * between num_perms and the maximum permission number, we 2480bce9527SEric Paris * should audit that denial 2490bce9527SEric Paris */ 2500bce9527SEric Paris for (; i < (sizeof(u32)*8); i++) 2510bce9527SEric Paris result |= 1<<i; 252c6d3aaa4SStephen Smalley avd->auditdeny = result; 253c6d3aaa4SStephen Smalley } 254c6d3aaa4SStephen Smalley } 255c6d3aaa4SStephen Smalley 2560719aaf5SGuido Trentalancia int security_mls_enabled(void) 2570719aaf5SGuido Trentalancia { 2580719aaf5SGuido Trentalancia return policydb.mls_enabled; 2590719aaf5SGuido Trentalancia } 260c6d3aaa4SStephen Smalley 2611da177e4SLinus Torvalds /* 2621da177e4SLinus Torvalds * Return the boolean value of a constraint expression 2631da177e4SLinus Torvalds * when it is applied to the specified source and target 2641da177e4SLinus Torvalds * security contexts. 2651da177e4SLinus Torvalds * 2661da177e4SLinus Torvalds * xcontext is a special beast... It is used by the validatetrans rules 2671da177e4SLinus Torvalds * only. For these rules, scontext is the context before the transition, 2681da177e4SLinus Torvalds * tcontext is the context after the transition, and xcontext is the context 2691da177e4SLinus Torvalds * of the process performing the transition. All other callers of 2701da177e4SLinus Torvalds * constraint_expr_eval should pass in NULL for xcontext. 2711da177e4SLinus Torvalds */ 2721da177e4SLinus Torvalds static int constraint_expr_eval(struct context *scontext, 2731da177e4SLinus Torvalds struct context *tcontext, 2741da177e4SLinus Torvalds struct context *xcontext, 2751da177e4SLinus Torvalds struct constraint_expr *cexpr) 2761da177e4SLinus Torvalds { 2771da177e4SLinus Torvalds u32 val1, val2; 2781da177e4SLinus Torvalds struct context *c; 2791da177e4SLinus Torvalds struct role_datum *r1, *r2; 2801da177e4SLinus Torvalds struct mls_level *l1, *l2; 2811da177e4SLinus Torvalds struct constraint_expr *e; 2821da177e4SLinus Torvalds int s[CEXPR_MAXDEPTH]; 2831da177e4SLinus Torvalds int sp = -1; 2841da177e4SLinus Torvalds 2851da177e4SLinus Torvalds for (e = cexpr; e; e = e->next) { 2861da177e4SLinus Torvalds switch (e->expr_type) { 2871da177e4SLinus Torvalds case CEXPR_NOT: 2881da177e4SLinus Torvalds BUG_ON(sp < 0); 2891da177e4SLinus Torvalds s[sp] = !s[sp]; 2901da177e4SLinus Torvalds break; 2911da177e4SLinus Torvalds case CEXPR_AND: 2921da177e4SLinus Torvalds BUG_ON(sp < 1); 2931da177e4SLinus Torvalds sp--; 2941da177e4SLinus Torvalds s[sp] &= s[sp + 1]; 2951da177e4SLinus Torvalds break; 2961da177e4SLinus Torvalds case CEXPR_OR: 2971da177e4SLinus Torvalds BUG_ON(sp < 1); 2981da177e4SLinus Torvalds sp--; 2991da177e4SLinus Torvalds s[sp] |= s[sp + 1]; 3001da177e4SLinus Torvalds break; 3011da177e4SLinus Torvalds case CEXPR_ATTR: 3021da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH - 1)) 3031da177e4SLinus Torvalds return 0; 3041da177e4SLinus Torvalds switch (e->attr) { 3051da177e4SLinus Torvalds case CEXPR_USER: 3061da177e4SLinus Torvalds val1 = scontext->user; 3071da177e4SLinus Torvalds val2 = tcontext->user; 3081da177e4SLinus Torvalds break; 3091da177e4SLinus Torvalds case CEXPR_TYPE: 3101da177e4SLinus Torvalds val1 = scontext->type; 3111da177e4SLinus Torvalds val2 = tcontext->type; 3121da177e4SLinus Torvalds break; 3131da177e4SLinus Torvalds case CEXPR_ROLE: 3141da177e4SLinus Torvalds val1 = scontext->role; 3151da177e4SLinus Torvalds val2 = tcontext->role; 3161da177e4SLinus Torvalds r1 = policydb.role_val_to_struct[val1 - 1]; 3171da177e4SLinus Torvalds r2 = policydb.role_val_to_struct[val2 - 1]; 3181da177e4SLinus Torvalds switch (e->op) { 3191da177e4SLinus Torvalds case CEXPR_DOM: 3201da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r1->dominates, 3211da177e4SLinus Torvalds val2 - 1); 3221da177e4SLinus Torvalds continue; 3231da177e4SLinus Torvalds case CEXPR_DOMBY: 3241da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r2->dominates, 3251da177e4SLinus Torvalds val1 - 1); 3261da177e4SLinus Torvalds continue; 3271da177e4SLinus Torvalds case CEXPR_INCOMP: 3281da177e4SLinus Torvalds s[++sp] = (!ebitmap_get_bit(&r1->dominates, 3291da177e4SLinus Torvalds val2 - 1) && 3301da177e4SLinus Torvalds !ebitmap_get_bit(&r2->dominates, 3311da177e4SLinus Torvalds val1 - 1)); 3321da177e4SLinus Torvalds continue; 3331da177e4SLinus Torvalds default: 3341da177e4SLinus Torvalds break; 3351da177e4SLinus Torvalds } 3361da177e4SLinus Torvalds break; 3371da177e4SLinus Torvalds case CEXPR_L1L2: 3381da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3391da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 3401da177e4SLinus Torvalds goto mls_ops; 3411da177e4SLinus Torvalds case CEXPR_L1H2: 3421da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3431da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3441da177e4SLinus Torvalds goto mls_ops; 3451da177e4SLinus Torvalds case CEXPR_H1L2: 3461da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 3471da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 3481da177e4SLinus Torvalds goto mls_ops; 3491da177e4SLinus Torvalds case CEXPR_H1H2: 3501da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 3511da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3521da177e4SLinus Torvalds goto mls_ops; 3531da177e4SLinus Torvalds case CEXPR_L1H1: 3541da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3551da177e4SLinus Torvalds l2 = &(scontext->range.level[1]); 3561da177e4SLinus Torvalds goto mls_ops; 3571da177e4SLinus Torvalds case CEXPR_L2H2: 3581da177e4SLinus Torvalds l1 = &(tcontext->range.level[0]); 3591da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3601da177e4SLinus Torvalds goto mls_ops; 3611da177e4SLinus Torvalds mls_ops: 3621da177e4SLinus Torvalds switch (e->op) { 3631da177e4SLinus Torvalds case CEXPR_EQ: 3641da177e4SLinus Torvalds s[++sp] = mls_level_eq(l1, l2); 3651da177e4SLinus Torvalds continue; 3661da177e4SLinus Torvalds case CEXPR_NEQ: 3671da177e4SLinus Torvalds s[++sp] = !mls_level_eq(l1, l2); 3681da177e4SLinus Torvalds continue; 3691da177e4SLinus Torvalds case CEXPR_DOM: 3701da177e4SLinus Torvalds s[++sp] = mls_level_dom(l1, l2); 3711da177e4SLinus Torvalds continue; 3721da177e4SLinus Torvalds case CEXPR_DOMBY: 3731da177e4SLinus Torvalds s[++sp] = mls_level_dom(l2, l1); 3741da177e4SLinus Torvalds continue; 3751da177e4SLinus Torvalds case CEXPR_INCOMP: 3761da177e4SLinus Torvalds s[++sp] = mls_level_incomp(l2, l1); 3771da177e4SLinus Torvalds continue; 3781da177e4SLinus Torvalds default: 3791da177e4SLinus Torvalds BUG(); 3801da177e4SLinus Torvalds return 0; 3811da177e4SLinus Torvalds } 3821da177e4SLinus Torvalds break; 3831da177e4SLinus Torvalds default: 3841da177e4SLinus Torvalds BUG(); 3851da177e4SLinus Torvalds return 0; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds switch (e->op) { 3891da177e4SLinus Torvalds case CEXPR_EQ: 3901da177e4SLinus Torvalds s[++sp] = (val1 == val2); 3911da177e4SLinus Torvalds break; 3921da177e4SLinus Torvalds case CEXPR_NEQ: 3931da177e4SLinus Torvalds s[++sp] = (val1 != val2); 3941da177e4SLinus Torvalds break; 3951da177e4SLinus Torvalds default: 3961da177e4SLinus Torvalds BUG(); 3971da177e4SLinus Torvalds return 0; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds break; 4001da177e4SLinus Torvalds case CEXPR_NAMES: 4011da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH-1)) 4021da177e4SLinus Torvalds return 0; 4031da177e4SLinus Torvalds c = scontext; 4041da177e4SLinus Torvalds if (e->attr & CEXPR_TARGET) 4051da177e4SLinus Torvalds c = tcontext; 4061da177e4SLinus Torvalds else if (e->attr & CEXPR_XTARGET) { 4071da177e4SLinus Torvalds c = xcontext; 4081da177e4SLinus Torvalds if (!c) { 4091da177e4SLinus Torvalds BUG(); 4101da177e4SLinus Torvalds return 0; 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds if (e->attr & CEXPR_USER) 4141da177e4SLinus Torvalds val1 = c->user; 4151da177e4SLinus Torvalds else if (e->attr & CEXPR_ROLE) 4161da177e4SLinus Torvalds val1 = c->role; 4171da177e4SLinus Torvalds else if (e->attr & CEXPR_TYPE) 4181da177e4SLinus Torvalds val1 = c->type; 4191da177e4SLinus Torvalds else { 4201da177e4SLinus Torvalds BUG(); 4211da177e4SLinus Torvalds return 0; 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds switch (e->op) { 4251da177e4SLinus Torvalds case CEXPR_EQ: 4261da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); 4271da177e4SLinus Torvalds break; 4281da177e4SLinus Torvalds case CEXPR_NEQ: 4291da177e4SLinus Torvalds s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); 4301da177e4SLinus Torvalds break; 4311da177e4SLinus Torvalds default: 4321da177e4SLinus Torvalds BUG(); 4331da177e4SLinus Torvalds return 0; 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds break; 4361da177e4SLinus Torvalds default: 4371da177e4SLinus Torvalds BUG(); 4381da177e4SLinus Torvalds return 0; 4391da177e4SLinus Torvalds } 4401da177e4SLinus Torvalds } 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds BUG_ON(sp != 0); 4431da177e4SLinus Torvalds return s[0]; 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds /* 44744c2d9bdSKaiGai Kohei * security_dump_masked_av - dumps masked permissions during 44844c2d9bdSKaiGai Kohei * security_compute_av due to RBAC, MLS/Constraint and Type bounds. 44944c2d9bdSKaiGai Kohei */ 45044c2d9bdSKaiGai Kohei static int dump_masked_av_helper(void *k, void *d, void *args) 45144c2d9bdSKaiGai Kohei { 45244c2d9bdSKaiGai Kohei struct perm_datum *pdatum = d; 45344c2d9bdSKaiGai Kohei char **permission_names = args; 45444c2d9bdSKaiGai Kohei 45544c2d9bdSKaiGai Kohei BUG_ON(pdatum->value < 1 || pdatum->value > 32); 45644c2d9bdSKaiGai Kohei 45744c2d9bdSKaiGai Kohei permission_names[pdatum->value - 1] = (char *)k; 45844c2d9bdSKaiGai Kohei 45944c2d9bdSKaiGai Kohei return 0; 46044c2d9bdSKaiGai Kohei } 46144c2d9bdSKaiGai Kohei 46244c2d9bdSKaiGai Kohei static void security_dump_masked_av(struct context *scontext, 46344c2d9bdSKaiGai Kohei struct context *tcontext, 46444c2d9bdSKaiGai Kohei u16 tclass, 46544c2d9bdSKaiGai Kohei u32 permissions, 46644c2d9bdSKaiGai Kohei const char *reason) 46744c2d9bdSKaiGai Kohei { 46844c2d9bdSKaiGai Kohei struct common_datum *common_dat; 46944c2d9bdSKaiGai Kohei struct class_datum *tclass_dat; 47044c2d9bdSKaiGai Kohei struct audit_buffer *ab; 47144c2d9bdSKaiGai Kohei char *tclass_name; 47244c2d9bdSKaiGai Kohei char *scontext_name = NULL; 47344c2d9bdSKaiGai Kohei char *tcontext_name = NULL; 47444c2d9bdSKaiGai Kohei char *permission_names[32]; 4752da5d31bSJames Morris int index; 4762da5d31bSJames Morris u32 length; 47744c2d9bdSKaiGai Kohei bool need_comma = false; 47844c2d9bdSKaiGai Kohei 47944c2d9bdSKaiGai Kohei if (!permissions) 48044c2d9bdSKaiGai Kohei return; 48144c2d9bdSKaiGai Kohei 482ac76c05bSEric Paris tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1); 48344c2d9bdSKaiGai Kohei tclass_dat = policydb.class_val_to_struct[tclass - 1]; 48444c2d9bdSKaiGai Kohei common_dat = tclass_dat->comdatum; 48544c2d9bdSKaiGai Kohei 48644c2d9bdSKaiGai Kohei /* init permission_names */ 48744c2d9bdSKaiGai Kohei if (common_dat && 48844c2d9bdSKaiGai Kohei hashtab_map(common_dat->permissions.table, 48944c2d9bdSKaiGai Kohei dump_masked_av_helper, permission_names) < 0) 49044c2d9bdSKaiGai Kohei goto out; 49144c2d9bdSKaiGai Kohei 49244c2d9bdSKaiGai Kohei if (hashtab_map(tclass_dat->permissions.table, 49344c2d9bdSKaiGai Kohei dump_masked_av_helper, permission_names) < 0) 49444c2d9bdSKaiGai Kohei goto out; 49544c2d9bdSKaiGai Kohei 49644c2d9bdSKaiGai Kohei /* get scontext/tcontext in text form */ 49744c2d9bdSKaiGai Kohei if (context_struct_to_string(scontext, 49844c2d9bdSKaiGai Kohei &scontext_name, &length) < 0) 49944c2d9bdSKaiGai Kohei goto out; 50044c2d9bdSKaiGai Kohei 50144c2d9bdSKaiGai Kohei if (context_struct_to_string(tcontext, 50244c2d9bdSKaiGai Kohei &tcontext_name, &length) < 0) 50344c2d9bdSKaiGai Kohei goto out; 50444c2d9bdSKaiGai Kohei 50544c2d9bdSKaiGai Kohei /* audit a message */ 50644c2d9bdSKaiGai Kohei ab = audit_log_start(current->audit_context, 50744c2d9bdSKaiGai Kohei GFP_ATOMIC, AUDIT_SELINUX_ERR); 50844c2d9bdSKaiGai Kohei if (!ab) 50944c2d9bdSKaiGai Kohei goto out; 51044c2d9bdSKaiGai Kohei 51144c2d9bdSKaiGai Kohei audit_log_format(ab, "op=security_compute_av reason=%s " 51244c2d9bdSKaiGai Kohei "scontext=%s tcontext=%s tclass=%s perms=", 51344c2d9bdSKaiGai Kohei reason, scontext_name, tcontext_name, tclass_name); 51444c2d9bdSKaiGai Kohei 51544c2d9bdSKaiGai Kohei for (index = 0; index < 32; index++) { 51644c2d9bdSKaiGai Kohei u32 mask = (1 << index); 51744c2d9bdSKaiGai Kohei 51844c2d9bdSKaiGai Kohei if ((mask & permissions) == 0) 51944c2d9bdSKaiGai Kohei continue; 52044c2d9bdSKaiGai Kohei 52144c2d9bdSKaiGai Kohei audit_log_format(ab, "%s%s", 52244c2d9bdSKaiGai Kohei need_comma ? "," : "", 52344c2d9bdSKaiGai Kohei permission_names[index] 52444c2d9bdSKaiGai Kohei ? permission_names[index] : "????"); 52544c2d9bdSKaiGai Kohei need_comma = true; 52644c2d9bdSKaiGai Kohei } 52744c2d9bdSKaiGai Kohei audit_log_end(ab); 52844c2d9bdSKaiGai Kohei out: 52944c2d9bdSKaiGai Kohei /* release scontext/tcontext */ 53044c2d9bdSKaiGai Kohei kfree(tcontext_name); 53144c2d9bdSKaiGai Kohei kfree(scontext_name); 53244c2d9bdSKaiGai Kohei 53344c2d9bdSKaiGai Kohei return; 53444c2d9bdSKaiGai Kohei } 53544c2d9bdSKaiGai Kohei 53644c2d9bdSKaiGai Kohei /* 537d9250deaSKaiGai Kohei * security_boundary_permission - drops violated permissions 538d9250deaSKaiGai Kohei * on boundary constraint. 539d9250deaSKaiGai Kohei */ 540d9250deaSKaiGai Kohei static void type_attribute_bounds_av(struct context *scontext, 541d9250deaSKaiGai Kohei struct context *tcontext, 542d9250deaSKaiGai Kohei u16 tclass, 543d9250deaSKaiGai Kohei struct av_decision *avd) 544d9250deaSKaiGai Kohei { 5452ae3ba39SKaiGai Kohei struct context lo_scontext; 5462ae3ba39SKaiGai Kohei struct context lo_tcontext; 5472ae3ba39SKaiGai Kohei struct av_decision lo_avd; 54823bdecb0SEric Paris struct type_datum *source; 54923bdecb0SEric Paris struct type_datum *target; 5502ae3ba39SKaiGai Kohei u32 masked = 0; 551d9250deaSKaiGai Kohei 55223bdecb0SEric Paris source = flex_array_get_ptr(policydb.type_val_to_struct_array, 55323bdecb0SEric Paris scontext->type - 1); 55423bdecb0SEric Paris BUG_ON(!source); 55523bdecb0SEric Paris 55623bdecb0SEric Paris target = flex_array_get_ptr(policydb.type_val_to_struct_array, 55723bdecb0SEric Paris tcontext->type - 1); 55823bdecb0SEric Paris BUG_ON(!target); 55923bdecb0SEric Paris 560d9250deaSKaiGai Kohei if (source->bounds) { 561d9250deaSKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd)); 562d9250deaSKaiGai Kohei 563d9250deaSKaiGai Kohei memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); 564d9250deaSKaiGai Kohei lo_scontext.type = source->bounds; 565d9250deaSKaiGai Kohei 566d9250deaSKaiGai Kohei context_struct_compute_av(&lo_scontext, 567d9250deaSKaiGai Kohei tcontext, 568d9250deaSKaiGai Kohei tclass, 569fa1aa143SJeff Vander Stoep &lo_avd, 570fa1aa143SJeff Vander Stoep NULL); 571d9250deaSKaiGai Kohei if ((lo_avd.allowed & avd->allowed) == avd->allowed) 572d9250deaSKaiGai Kohei return; /* no masked permission */ 573d9250deaSKaiGai Kohei masked = ~lo_avd.allowed & avd->allowed; 5742ae3ba39SKaiGai Kohei } 575d9250deaSKaiGai Kohei 5762ae3ba39SKaiGai Kohei if (target->bounds) { 5772ae3ba39SKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd)); 5782ae3ba39SKaiGai Kohei 5792ae3ba39SKaiGai Kohei memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); 5802ae3ba39SKaiGai Kohei lo_tcontext.type = target->bounds; 5812ae3ba39SKaiGai Kohei 5822ae3ba39SKaiGai Kohei context_struct_compute_av(scontext, 5832ae3ba39SKaiGai Kohei &lo_tcontext, 5842ae3ba39SKaiGai Kohei tclass, 585fa1aa143SJeff Vander Stoep &lo_avd, 586fa1aa143SJeff Vander Stoep NULL); 5872ae3ba39SKaiGai Kohei if ((lo_avd.allowed & avd->allowed) == avd->allowed) 5882ae3ba39SKaiGai Kohei return; /* no masked permission */ 5892ae3ba39SKaiGai Kohei masked = ~lo_avd.allowed & avd->allowed; 5902ae3ba39SKaiGai Kohei } 5912ae3ba39SKaiGai Kohei 5922ae3ba39SKaiGai Kohei if (source->bounds && target->bounds) { 5932ae3ba39SKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd)); 5942ae3ba39SKaiGai Kohei /* 5952ae3ba39SKaiGai Kohei * lo_scontext and lo_tcontext are already 5962ae3ba39SKaiGai Kohei * set up. 5972ae3ba39SKaiGai Kohei */ 5982ae3ba39SKaiGai Kohei 5992ae3ba39SKaiGai Kohei context_struct_compute_av(&lo_scontext, 6002ae3ba39SKaiGai Kohei &lo_tcontext, 6012ae3ba39SKaiGai Kohei tclass, 602fa1aa143SJeff Vander Stoep &lo_avd, 603fa1aa143SJeff Vander Stoep NULL); 6042ae3ba39SKaiGai Kohei if ((lo_avd.allowed & avd->allowed) == avd->allowed) 6052ae3ba39SKaiGai Kohei return; /* no masked permission */ 6062ae3ba39SKaiGai Kohei masked = ~lo_avd.allowed & avd->allowed; 6072ae3ba39SKaiGai Kohei } 6082ae3ba39SKaiGai Kohei 6092ae3ba39SKaiGai Kohei if (masked) { 610d9250deaSKaiGai Kohei /* mask violated permissions */ 611d9250deaSKaiGai Kohei avd->allowed &= ~masked; 612d9250deaSKaiGai Kohei 61344c2d9bdSKaiGai Kohei /* audit masked permissions */ 61444c2d9bdSKaiGai Kohei security_dump_masked_av(scontext, tcontext, 61544c2d9bdSKaiGai Kohei tclass, masked, "bounds"); 616d9250deaSKaiGai Kohei } 617d9250deaSKaiGai Kohei } 618d9250deaSKaiGai Kohei 619d9250deaSKaiGai Kohei /* 620fa1aa143SJeff Vander Stoep * flag which drivers have permissions 621fa1aa143SJeff Vander Stoep * only looking for ioctl based extended permssions 622fa1aa143SJeff Vander Stoep */ 623fa1aa143SJeff Vander Stoep void services_compute_xperms_drivers( 624fa1aa143SJeff Vander Stoep struct extended_perms *xperms, 625fa1aa143SJeff Vander Stoep struct avtab_node *node) 626fa1aa143SJeff Vander Stoep { 627fa1aa143SJeff Vander Stoep unsigned int i; 628fa1aa143SJeff Vander Stoep 629fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 630fa1aa143SJeff Vander Stoep /* if one or more driver has all permissions allowed */ 631fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) 632fa1aa143SJeff Vander Stoep xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; 633fa1aa143SJeff Vander Stoep } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 634fa1aa143SJeff Vander Stoep /* if allowing permissions within a driver */ 635fa1aa143SJeff Vander Stoep security_xperm_set(xperms->drivers.p, 636fa1aa143SJeff Vander Stoep node->datum.u.xperms->driver); 637fa1aa143SJeff Vander Stoep } 638fa1aa143SJeff Vander Stoep 639fa1aa143SJeff Vander Stoep /* If no ioctl commands are allowed, ignore auditallow and auditdeny */ 640fa1aa143SJeff Vander Stoep if (node->key.specified & AVTAB_XPERMS_ALLOWED) 641fa1aa143SJeff Vander Stoep xperms->len = 1; 642fa1aa143SJeff Vander Stoep } 643fa1aa143SJeff Vander Stoep 644fa1aa143SJeff Vander Stoep /* 645fa1aa143SJeff Vander Stoep * Compute access vectors and extended permissions based on a context 646fa1aa143SJeff Vander Stoep * structure pair for the permissions in a particular class. 6471da177e4SLinus Torvalds */ 64819439d05SStephen Smalley static void context_struct_compute_av(struct context *scontext, 6491da177e4SLinus Torvalds struct context *tcontext, 6501da177e4SLinus Torvalds u16 tclass, 651fa1aa143SJeff Vander Stoep struct av_decision *avd, 652fa1aa143SJeff Vander Stoep struct extended_perms *xperms) 6531da177e4SLinus Torvalds { 6541da177e4SLinus Torvalds struct constraint_node *constraint; 6551da177e4SLinus Torvalds struct role_allow *ra; 6561da177e4SLinus Torvalds struct avtab_key avkey; 657782ebb99SStephen Smalley struct avtab_node *node; 6581da177e4SLinus Torvalds struct class_datum *tclass_datum; 659782ebb99SStephen Smalley struct ebitmap *sattr, *tattr; 660782ebb99SStephen Smalley struct ebitmap_node *snode, *tnode; 661782ebb99SStephen Smalley unsigned int i, j; 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds avd->allowed = 0; 6641da177e4SLinus Torvalds avd->auditallow = 0; 6651da177e4SLinus Torvalds avd->auditdeny = 0xffffffff; 666fa1aa143SJeff Vander Stoep if (xperms) { 667fa1aa143SJeff Vander Stoep memset(&xperms->drivers, 0, sizeof(xperms->drivers)); 668fa1aa143SJeff Vander Stoep xperms->len = 0; 669fa1aa143SJeff Vander Stoep } 6701da177e4SLinus Torvalds 671c6d3aaa4SStephen Smalley if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { 672c6d3aaa4SStephen Smalley if (printk_ratelimit()) 673c6d3aaa4SStephen Smalley printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); 67419439d05SStephen Smalley return; 675c6d3aaa4SStephen Smalley } 6763f12070eSEric Paris 6773f12070eSEric Paris tclass_datum = policydb.class_val_to_struct[tclass - 1]; 6783f12070eSEric Paris 6793f12070eSEric Paris /* 6801da177e4SLinus Torvalds * If a specific type enforcement rule was defined for 6811da177e4SLinus Torvalds * this permission check, then use it. 6821da177e4SLinus Torvalds */ 6831da177e4SLinus Torvalds avkey.target_class = tclass; 684fa1aa143SJeff Vander Stoep avkey.specified = AVTAB_AV | AVTAB_XPERMS; 6856371dcd3SEric Paris sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); 6866371dcd3SEric Paris BUG_ON(!sattr); 6876371dcd3SEric Paris tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); 6886371dcd3SEric Paris BUG_ON(!tattr); 6899fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(sattr, snode, i) { 6909fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(tattr, tnode, j) { 691782ebb99SStephen Smalley avkey.source_type = i + 1; 692782ebb99SStephen Smalley avkey.target_type = j + 1; 693782ebb99SStephen Smalley for (node = avtab_search_node(&policydb.te_avtab, &avkey); 694dbc74c65SVesa-Matti Kari node; 695782ebb99SStephen Smalley node = avtab_search_node_next(node, avkey.specified)) { 696782ebb99SStephen Smalley if (node->key.specified == AVTAB_ALLOWED) 697fa1aa143SJeff Vander Stoep avd->allowed |= node->datum.u.data; 698782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITALLOW) 699fa1aa143SJeff Vander Stoep avd->auditallow |= node->datum.u.data; 700782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITDENY) 701fa1aa143SJeff Vander Stoep avd->auditdeny &= node->datum.u.data; 702fa1aa143SJeff Vander Stoep else if (xperms && (node->key.specified & AVTAB_XPERMS)) 703fa1aa143SJeff Vander Stoep services_compute_xperms_drivers(xperms, node); 7041da177e4SLinus Torvalds } 7051da177e4SLinus Torvalds 7061da177e4SLinus Torvalds /* Check conditional av table for additional permissions */ 707fa1aa143SJeff Vander Stoep cond_compute_av(&policydb.te_cond_avtab, &avkey, 708fa1aa143SJeff Vander Stoep avd, xperms); 7091da177e4SLinus Torvalds 710782ebb99SStephen Smalley } 711782ebb99SStephen Smalley } 712782ebb99SStephen Smalley 7131da177e4SLinus Torvalds /* 7141da177e4SLinus Torvalds * Remove any permissions prohibited by a constraint (this includes 7151da177e4SLinus Torvalds * the MLS policy). 7161da177e4SLinus Torvalds */ 7171da177e4SLinus Torvalds constraint = tclass_datum->constraints; 7181da177e4SLinus Torvalds while (constraint) { 7191da177e4SLinus Torvalds if ((constraint->permissions & (avd->allowed)) && 7201da177e4SLinus Torvalds !constraint_expr_eval(scontext, tcontext, NULL, 7211da177e4SLinus Torvalds constraint->expr)) { 722caabbdc0SKaiGai Kohei avd->allowed &= ~(constraint->permissions); 7231da177e4SLinus Torvalds } 7241da177e4SLinus Torvalds constraint = constraint->next; 7251da177e4SLinus Torvalds } 7261da177e4SLinus Torvalds 7271da177e4SLinus Torvalds /* 7281da177e4SLinus Torvalds * If checking process transition permission and the 7291da177e4SLinus Torvalds * role is changing, then check the (current_role, new_role) 7301da177e4SLinus Torvalds * pair. 7311da177e4SLinus Torvalds */ 732c6d3aaa4SStephen Smalley if (tclass == policydb.process_class && 733c6d3aaa4SStephen Smalley (avd->allowed & policydb.process_trans_perms) && 7341da177e4SLinus Torvalds scontext->role != tcontext->role) { 7351da177e4SLinus Torvalds for (ra = policydb.role_allow; ra; ra = ra->next) { 7361da177e4SLinus Torvalds if (scontext->role == ra->role && 7371da177e4SLinus Torvalds tcontext->role == ra->new_role) 7381da177e4SLinus Torvalds break; 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds if (!ra) 741c6d3aaa4SStephen Smalley avd->allowed &= ~policydb.process_trans_perms; 7421da177e4SLinus Torvalds } 7431da177e4SLinus Torvalds 744d9250deaSKaiGai Kohei /* 745d9250deaSKaiGai Kohei * If the given source and target types have boundary 746d9250deaSKaiGai Kohei * constraint, lazy checks have to mask any violated 747d9250deaSKaiGai Kohei * permission and notice it to userspace via audit. 748d9250deaSKaiGai Kohei */ 749d9250deaSKaiGai Kohei type_attribute_bounds_av(scontext, tcontext, 75019439d05SStephen Smalley tclass, avd); 75122df4adbSStephen Smalley } 75222df4adbSStephen Smalley 7531da177e4SLinus Torvalds static int security_validtrans_handle_fail(struct context *ocontext, 7541da177e4SLinus Torvalds struct context *ncontext, 7551da177e4SLinus Torvalds struct context *tcontext, 7561da177e4SLinus Torvalds u16 tclass) 7571da177e4SLinus Torvalds { 7581da177e4SLinus Torvalds char *o = NULL, *n = NULL, *t = NULL; 7591da177e4SLinus Torvalds u32 olen, nlen, tlen; 7601da177e4SLinus Torvalds 7614b02b524SEric Paris if (context_struct_to_string(ocontext, &o, &olen)) 7621da177e4SLinus Torvalds goto out; 7634b02b524SEric Paris if (context_struct_to_string(ncontext, &n, &nlen)) 7641da177e4SLinus Torvalds goto out; 7654b02b524SEric Paris if (context_struct_to_string(tcontext, &t, &tlen)) 7661da177e4SLinus Torvalds goto out; 7679ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 7684093a844SRichard Guy Briggs "op=security_validate_transition seresult=denied" 7691da177e4SLinus Torvalds " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", 770ac76c05bSEric Paris o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); 7711da177e4SLinus Torvalds out: 7721da177e4SLinus Torvalds kfree(o); 7731da177e4SLinus Torvalds kfree(n); 7741da177e4SLinus Torvalds kfree(t); 7751da177e4SLinus Torvalds 7761da177e4SLinus Torvalds if (!selinux_enforcing) 7771da177e4SLinus Torvalds return 0; 7781da177e4SLinus Torvalds return -EPERM; 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds 781f9df6458SAndrew Perepechko static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid, 782f9df6458SAndrew Perepechko u16 orig_tclass, bool user) 7831da177e4SLinus Torvalds { 7841da177e4SLinus Torvalds struct context *ocontext; 7851da177e4SLinus Torvalds struct context *ncontext; 7861da177e4SLinus Torvalds struct context *tcontext; 7871da177e4SLinus Torvalds struct class_datum *tclass_datum; 7881da177e4SLinus Torvalds struct constraint_node *constraint; 789c6d3aaa4SStephen Smalley u16 tclass; 7901da177e4SLinus Torvalds int rc = 0; 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds if (!ss_initialized) 7931da177e4SLinus Torvalds return 0; 7941da177e4SLinus Torvalds 7950804d113SJames Morris read_lock(&policy_rwlock); 7961da177e4SLinus Torvalds 797f9df6458SAndrew Perepechko if (!user) 798c6d3aaa4SStephen Smalley tclass = unmap_class(orig_tclass); 799f9df6458SAndrew Perepechko else 800f9df6458SAndrew Perepechko tclass = orig_tclass; 801c6d3aaa4SStephen Smalley 8021da177e4SLinus Torvalds if (!tclass || tclass > policydb.p_classes.nprim) { 8031da177e4SLinus Torvalds rc = -EINVAL; 8041da177e4SLinus Torvalds goto out; 8051da177e4SLinus Torvalds } 8061da177e4SLinus Torvalds tclass_datum = policydb.class_val_to_struct[tclass - 1]; 8071da177e4SLinus Torvalds 8081da177e4SLinus Torvalds ocontext = sidtab_search(&sidtab, oldsid); 8091da177e4SLinus Torvalds if (!ocontext) { 810744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 811744ba35eSEric Paris __func__, oldsid); 8121da177e4SLinus Torvalds rc = -EINVAL; 8131da177e4SLinus Torvalds goto out; 8141da177e4SLinus Torvalds } 8151da177e4SLinus Torvalds 8161da177e4SLinus Torvalds ncontext = sidtab_search(&sidtab, newsid); 8171da177e4SLinus Torvalds if (!ncontext) { 818744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 819744ba35eSEric Paris __func__, newsid); 8201da177e4SLinus Torvalds rc = -EINVAL; 8211da177e4SLinus Torvalds goto out; 8221da177e4SLinus Torvalds } 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tasksid); 8251da177e4SLinus Torvalds if (!tcontext) { 826744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 827744ba35eSEric Paris __func__, tasksid); 8281da177e4SLinus Torvalds rc = -EINVAL; 8291da177e4SLinus Torvalds goto out; 8301da177e4SLinus Torvalds } 8311da177e4SLinus Torvalds 8321da177e4SLinus Torvalds constraint = tclass_datum->validatetrans; 8331da177e4SLinus Torvalds while (constraint) { 8341da177e4SLinus Torvalds if (!constraint_expr_eval(ocontext, ncontext, tcontext, 8351da177e4SLinus Torvalds constraint->expr)) { 836f9df6458SAndrew Perepechko if (user) 837f9df6458SAndrew Perepechko rc = -EPERM; 838f9df6458SAndrew Perepechko else 839f9df6458SAndrew Perepechko rc = security_validtrans_handle_fail(ocontext, 840f9df6458SAndrew Perepechko ncontext, 841f9df6458SAndrew Perepechko tcontext, 842f9df6458SAndrew Perepechko tclass); 8431da177e4SLinus Torvalds goto out; 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds constraint = constraint->next; 8461da177e4SLinus Torvalds } 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds out: 8490804d113SJames Morris read_unlock(&policy_rwlock); 8501da177e4SLinus Torvalds return rc; 8511da177e4SLinus Torvalds } 8521da177e4SLinus Torvalds 853f9df6458SAndrew Perepechko int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid, 854f9df6458SAndrew Perepechko u16 tclass) 855f9df6458SAndrew Perepechko { 856f9df6458SAndrew Perepechko return security_compute_validatetrans(oldsid, newsid, tasksid, 857f9df6458SAndrew Perepechko tclass, true); 858f9df6458SAndrew Perepechko } 859f9df6458SAndrew Perepechko 860f9df6458SAndrew Perepechko int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, 861f9df6458SAndrew Perepechko u16 orig_tclass) 862f9df6458SAndrew Perepechko { 863f9df6458SAndrew Perepechko return security_compute_validatetrans(oldsid, newsid, tasksid, 864f9df6458SAndrew Perepechko orig_tclass, false); 865f9df6458SAndrew Perepechko } 866f9df6458SAndrew Perepechko 867d9250deaSKaiGai Kohei /* 868d9250deaSKaiGai Kohei * security_bounded_transition - check whether the given 869d9250deaSKaiGai Kohei * transition is directed to bounded, or not. 870d9250deaSKaiGai Kohei * It returns 0, if @newsid is bounded by @oldsid. 871d9250deaSKaiGai Kohei * Otherwise, it returns error code. 872d9250deaSKaiGai Kohei * 873d9250deaSKaiGai Kohei * @oldsid : current security identifier 874d9250deaSKaiGai Kohei * @newsid : destinated security identifier 875d9250deaSKaiGai Kohei */ 876d9250deaSKaiGai Kohei int security_bounded_transition(u32 old_sid, u32 new_sid) 877d9250deaSKaiGai Kohei { 878d9250deaSKaiGai Kohei struct context *old_context, *new_context; 879d9250deaSKaiGai Kohei struct type_datum *type; 880d9250deaSKaiGai Kohei int index; 8814b02b524SEric Paris int rc; 882d9250deaSKaiGai Kohei 883d9250deaSKaiGai Kohei read_lock(&policy_rwlock); 884d9250deaSKaiGai Kohei 8854b02b524SEric Paris rc = -EINVAL; 886d9250deaSKaiGai Kohei old_context = sidtab_search(&sidtab, old_sid); 887d9250deaSKaiGai Kohei if (!old_context) { 888d9250deaSKaiGai Kohei printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", 889d9250deaSKaiGai Kohei __func__, old_sid); 890d9250deaSKaiGai Kohei goto out; 891d9250deaSKaiGai Kohei } 892d9250deaSKaiGai Kohei 8934b02b524SEric Paris rc = -EINVAL; 894d9250deaSKaiGai Kohei new_context = sidtab_search(&sidtab, new_sid); 895d9250deaSKaiGai Kohei if (!new_context) { 896d9250deaSKaiGai Kohei printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", 897d9250deaSKaiGai Kohei __func__, new_sid); 898d9250deaSKaiGai Kohei goto out; 899d9250deaSKaiGai Kohei } 900d9250deaSKaiGai Kohei 901d9250deaSKaiGai Kohei rc = 0; 9024b02b524SEric Paris /* type/domain unchanged */ 9034b02b524SEric Paris if (old_context->type == new_context->type) 904d9250deaSKaiGai Kohei goto out; 905d9250deaSKaiGai Kohei 906d9250deaSKaiGai Kohei index = new_context->type; 907d9250deaSKaiGai Kohei while (true) { 90823bdecb0SEric Paris type = flex_array_get_ptr(policydb.type_val_to_struct_array, 90923bdecb0SEric Paris index - 1); 910d9250deaSKaiGai Kohei BUG_ON(!type); 911d9250deaSKaiGai Kohei 912d9250deaSKaiGai Kohei /* not bounded anymore */ 913d9250deaSKaiGai Kohei rc = -EPERM; 9144b02b524SEric Paris if (!type->bounds) 915d9250deaSKaiGai Kohei break; 916d9250deaSKaiGai Kohei 917d9250deaSKaiGai Kohei /* @newsid is bounded by @oldsid */ 918d9250deaSKaiGai Kohei rc = 0; 9194b02b524SEric Paris if (type->bounds == old_context->type) 920d9250deaSKaiGai Kohei break; 9214b02b524SEric Paris 922d9250deaSKaiGai Kohei index = type->bounds; 923d9250deaSKaiGai Kohei } 92444c2d9bdSKaiGai Kohei 92544c2d9bdSKaiGai Kohei if (rc) { 92644c2d9bdSKaiGai Kohei char *old_name = NULL; 92744c2d9bdSKaiGai Kohei char *new_name = NULL; 9282da5d31bSJames Morris u32 length; 92944c2d9bdSKaiGai Kohei 93044c2d9bdSKaiGai Kohei if (!context_struct_to_string(old_context, 93144c2d9bdSKaiGai Kohei &old_name, &length) && 93244c2d9bdSKaiGai Kohei !context_struct_to_string(new_context, 93344c2d9bdSKaiGai Kohei &new_name, &length)) { 93444c2d9bdSKaiGai Kohei audit_log(current->audit_context, 93544c2d9bdSKaiGai Kohei GFP_ATOMIC, AUDIT_SELINUX_ERR, 93644c2d9bdSKaiGai Kohei "op=security_bounded_transition " 9374093a844SRichard Guy Briggs "seresult=denied " 93844c2d9bdSKaiGai Kohei "oldcontext=%s newcontext=%s", 93944c2d9bdSKaiGai Kohei old_name, new_name); 94044c2d9bdSKaiGai Kohei } 94144c2d9bdSKaiGai Kohei kfree(new_name); 94244c2d9bdSKaiGai Kohei kfree(old_name); 94344c2d9bdSKaiGai Kohei } 944d9250deaSKaiGai Kohei out: 945d9250deaSKaiGai Kohei read_unlock(&policy_rwlock); 946d9250deaSKaiGai Kohei 947d9250deaSKaiGai Kohei return rc; 948d9250deaSKaiGai Kohei } 949d9250deaSKaiGai Kohei 95019439d05SStephen Smalley static void avd_init(struct av_decision *avd) 951c6d3aaa4SStephen Smalley { 95219439d05SStephen Smalley avd->allowed = 0; 95319439d05SStephen Smalley avd->auditallow = 0; 95419439d05SStephen Smalley avd->auditdeny = 0xffffffff; 95519439d05SStephen Smalley avd->seqno = latest_granting; 95619439d05SStephen Smalley avd->flags = 0; 957c6d3aaa4SStephen Smalley } 958c6d3aaa4SStephen Smalley 959fa1aa143SJeff Vander Stoep void services_compute_xperms_decision(struct extended_perms_decision *xpermd, 960fa1aa143SJeff Vander Stoep struct avtab_node *node) 961fa1aa143SJeff Vander Stoep { 962fa1aa143SJeff Vander Stoep unsigned int i; 963fa1aa143SJeff Vander Stoep 964fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 965fa1aa143SJeff Vander Stoep if (xpermd->driver != node->datum.u.xperms->driver) 966fa1aa143SJeff Vander Stoep return; 967fa1aa143SJeff Vander Stoep } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 968fa1aa143SJeff Vander Stoep if (!security_xperm_test(node->datum.u.xperms->perms.p, 969fa1aa143SJeff Vander Stoep xpermd->driver)) 970fa1aa143SJeff Vander Stoep return; 971fa1aa143SJeff Vander Stoep } else { 972fa1aa143SJeff Vander Stoep BUG(); 973fa1aa143SJeff Vander Stoep } 974fa1aa143SJeff Vander Stoep 975fa1aa143SJeff Vander Stoep if (node->key.specified == AVTAB_XPERMS_ALLOWED) { 976fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_ALLOWED; 977fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 978fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0xff, 979fa1aa143SJeff Vander Stoep sizeof(xpermd->allowed->p)); 980fa1aa143SJeff Vander Stoep } 981fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 982fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) 983fa1aa143SJeff Vander Stoep xpermd->allowed->p[i] |= 984fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i]; 985fa1aa143SJeff Vander Stoep } 986fa1aa143SJeff Vander Stoep } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { 987fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_AUDITALLOW; 988fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 989fa1aa143SJeff Vander Stoep memset(xpermd->auditallow->p, 0xff, 990fa1aa143SJeff Vander Stoep sizeof(xpermd->auditallow->p)); 991fa1aa143SJeff Vander Stoep } 992fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 993fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) 994fa1aa143SJeff Vander Stoep xpermd->auditallow->p[i] |= 995fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i]; 996fa1aa143SJeff Vander Stoep } 997fa1aa143SJeff Vander Stoep } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { 998fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_DONTAUDIT; 999fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { 1000fa1aa143SJeff Vander Stoep memset(xpermd->dontaudit->p, 0xff, 1001fa1aa143SJeff Vander Stoep sizeof(xpermd->dontaudit->p)); 1002fa1aa143SJeff Vander Stoep } 1003fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { 1004fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) 1005fa1aa143SJeff Vander Stoep xpermd->dontaudit->p[i] |= 1006fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i]; 1007fa1aa143SJeff Vander Stoep } 1008fa1aa143SJeff Vander Stoep } else { 1009fa1aa143SJeff Vander Stoep BUG(); 1010fa1aa143SJeff Vander Stoep } 1011fa1aa143SJeff Vander Stoep } 1012fa1aa143SJeff Vander Stoep 1013fa1aa143SJeff Vander Stoep void security_compute_xperms_decision(u32 ssid, 1014fa1aa143SJeff Vander Stoep u32 tsid, 1015fa1aa143SJeff Vander Stoep u16 orig_tclass, 1016fa1aa143SJeff Vander Stoep u8 driver, 1017fa1aa143SJeff Vander Stoep struct extended_perms_decision *xpermd) 1018fa1aa143SJeff Vander Stoep { 1019fa1aa143SJeff Vander Stoep u16 tclass; 1020fa1aa143SJeff Vander Stoep struct context *scontext, *tcontext; 1021fa1aa143SJeff Vander Stoep struct avtab_key avkey; 1022fa1aa143SJeff Vander Stoep struct avtab_node *node; 1023fa1aa143SJeff Vander Stoep struct ebitmap *sattr, *tattr; 1024fa1aa143SJeff Vander Stoep struct ebitmap_node *snode, *tnode; 1025fa1aa143SJeff Vander Stoep unsigned int i, j; 1026fa1aa143SJeff Vander Stoep 1027fa1aa143SJeff Vander Stoep xpermd->driver = driver; 1028fa1aa143SJeff Vander Stoep xpermd->used = 0; 1029fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p)); 1030fa1aa143SJeff Vander Stoep memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); 1031fa1aa143SJeff Vander Stoep memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); 1032fa1aa143SJeff Vander Stoep 1033fa1aa143SJeff Vander Stoep read_lock(&policy_rwlock); 1034fa1aa143SJeff Vander Stoep if (!ss_initialized) 1035fa1aa143SJeff Vander Stoep goto allow; 1036fa1aa143SJeff Vander Stoep 1037fa1aa143SJeff Vander Stoep scontext = sidtab_search(&sidtab, ssid); 1038fa1aa143SJeff Vander Stoep if (!scontext) { 1039fa1aa143SJeff Vander Stoep printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1040fa1aa143SJeff Vander Stoep __func__, ssid); 1041fa1aa143SJeff Vander Stoep goto out; 1042fa1aa143SJeff Vander Stoep } 1043fa1aa143SJeff Vander Stoep 1044fa1aa143SJeff Vander Stoep tcontext = sidtab_search(&sidtab, tsid); 1045fa1aa143SJeff Vander Stoep if (!tcontext) { 1046fa1aa143SJeff Vander Stoep printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1047fa1aa143SJeff Vander Stoep __func__, tsid); 1048fa1aa143SJeff Vander Stoep goto out; 1049fa1aa143SJeff Vander Stoep } 1050fa1aa143SJeff Vander Stoep 1051fa1aa143SJeff Vander Stoep tclass = unmap_class(orig_tclass); 1052fa1aa143SJeff Vander Stoep if (unlikely(orig_tclass && !tclass)) { 1053fa1aa143SJeff Vander Stoep if (policydb.allow_unknown) 1054fa1aa143SJeff Vander Stoep goto allow; 1055fa1aa143SJeff Vander Stoep goto out; 1056fa1aa143SJeff Vander Stoep } 1057fa1aa143SJeff Vander Stoep 1058fa1aa143SJeff Vander Stoep 1059fa1aa143SJeff Vander Stoep if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { 1060fa1aa143SJeff Vander Stoep pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass); 1061fa1aa143SJeff Vander Stoep goto out; 1062fa1aa143SJeff Vander Stoep } 1063fa1aa143SJeff Vander Stoep 1064fa1aa143SJeff Vander Stoep avkey.target_class = tclass; 1065fa1aa143SJeff Vander Stoep avkey.specified = AVTAB_XPERMS; 1066fa1aa143SJeff Vander Stoep sattr = flex_array_get(policydb.type_attr_map_array, 1067fa1aa143SJeff Vander Stoep scontext->type - 1); 1068fa1aa143SJeff Vander Stoep BUG_ON(!sattr); 1069fa1aa143SJeff Vander Stoep tattr = flex_array_get(policydb.type_attr_map_array, 1070fa1aa143SJeff Vander Stoep tcontext->type - 1); 1071fa1aa143SJeff Vander Stoep BUG_ON(!tattr); 1072fa1aa143SJeff Vander Stoep ebitmap_for_each_positive_bit(sattr, snode, i) { 1073fa1aa143SJeff Vander Stoep ebitmap_for_each_positive_bit(tattr, tnode, j) { 1074fa1aa143SJeff Vander Stoep avkey.source_type = i + 1; 1075fa1aa143SJeff Vander Stoep avkey.target_type = j + 1; 1076fa1aa143SJeff Vander Stoep for (node = avtab_search_node(&policydb.te_avtab, &avkey); 1077fa1aa143SJeff Vander Stoep node; 1078fa1aa143SJeff Vander Stoep node = avtab_search_node_next(node, avkey.specified)) 1079fa1aa143SJeff Vander Stoep services_compute_xperms_decision(xpermd, node); 1080fa1aa143SJeff Vander Stoep 1081fa1aa143SJeff Vander Stoep cond_compute_xperms(&policydb.te_cond_avtab, 1082fa1aa143SJeff Vander Stoep &avkey, xpermd); 1083fa1aa143SJeff Vander Stoep } 1084fa1aa143SJeff Vander Stoep } 1085fa1aa143SJeff Vander Stoep out: 1086fa1aa143SJeff Vander Stoep read_unlock(&policy_rwlock); 1087fa1aa143SJeff Vander Stoep return; 1088fa1aa143SJeff Vander Stoep allow: 1089fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); 1090fa1aa143SJeff Vander Stoep goto out; 1091fa1aa143SJeff Vander Stoep } 1092c6d3aaa4SStephen Smalley 10931da177e4SLinus Torvalds /** 10941da177e4SLinus Torvalds * security_compute_av - Compute access vector decisions. 10951da177e4SLinus Torvalds * @ssid: source security identifier 10961da177e4SLinus Torvalds * @tsid: target security identifier 10971da177e4SLinus Torvalds * @tclass: target security class 10981da177e4SLinus Torvalds * @avd: access vector decisions 1099fa1aa143SJeff Vander Stoep * @xperms: extended permissions 11001da177e4SLinus Torvalds * 11011da177e4SLinus Torvalds * Compute a set of access vector decisions based on the 11021da177e4SLinus Torvalds * SID pair (@ssid, @tsid) for the permissions in @tclass. 11031da177e4SLinus Torvalds */ 110419439d05SStephen Smalley void security_compute_av(u32 ssid, 11051da177e4SLinus Torvalds u32 tsid, 1106c6d3aaa4SStephen Smalley u16 orig_tclass, 1107fa1aa143SJeff Vander Stoep struct av_decision *avd, 1108fa1aa143SJeff Vander Stoep struct extended_perms *xperms) 1109c6d3aaa4SStephen Smalley { 1110c6d3aaa4SStephen Smalley u16 tclass; 111119439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL; 1112c6d3aaa4SStephen Smalley 1113b7f3008aSStephen Smalley read_lock(&policy_rwlock); 111419439d05SStephen Smalley avd_init(avd); 1115fa1aa143SJeff Vander Stoep xperms->len = 0; 1116c6d3aaa4SStephen Smalley if (!ss_initialized) 1117c6d3aaa4SStephen Smalley goto allow; 1118c6d3aaa4SStephen Smalley 111919439d05SStephen Smalley scontext = sidtab_search(&sidtab, ssid); 112019439d05SStephen Smalley if (!scontext) { 112119439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 112219439d05SStephen Smalley __func__, ssid); 112319439d05SStephen Smalley goto out; 112419439d05SStephen Smalley } 112519439d05SStephen Smalley 112619439d05SStephen Smalley /* permissive domain? */ 112719439d05SStephen Smalley if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) 112819439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE; 112919439d05SStephen Smalley 113019439d05SStephen Smalley tcontext = sidtab_search(&sidtab, tsid); 113119439d05SStephen Smalley if (!tcontext) { 113219439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 113319439d05SStephen Smalley __func__, tsid); 113419439d05SStephen Smalley goto out; 113519439d05SStephen Smalley } 113619439d05SStephen Smalley 1137c6d3aaa4SStephen Smalley tclass = unmap_class(orig_tclass); 1138c6d3aaa4SStephen Smalley if (unlikely(orig_tclass && !tclass)) { 1139c6d3aaa4SStephen Smalley if (policydb.allow_unknown) 1140c6d3aaa4SStephen Smalley goto allow; 1141b7f3008aSStephen Smalley goto out; 1142c6d3aaa4SStephen Smalley } 1143fa1aa143SJeff Vander Stoep context_struct_compute_av(scontext, tcontext, tclass, avd, xperms); 1144c6d3aaa4SStephen Smalley map_decision(orig_tclass, avd, policydb.allow_unknown); 1145b7f3008aSStephen Smalley out: 1146c6d3aaa4SStephen Smalley read_unlock(&policy_rwlock); 114719439d05SStephen Smalley return; 1148c6d3aaa4SStephen Smalley allow: 1149c6d3aaa4SStephen Smalley avd->allowed = 0xffffffff; 1150b7f3008aSStephen Smalley goto out; 1151c6d3aaa4SStephen Smalley } 1152c6d3aaa4SStephen Smalley 115319439d05SStephen Smalley void security_compute_av_user(u32 ssid, 1154c6d3aaa4SStephen Smalley u32 tsid, 11551da177e4SLinus Torvalds u16 tclass, 11561da177e4SLinus Torvalds struct av_decision *avd) 11571da177e4SLinus Torvalds { 115819439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL; 11591da177e4SLinus Torvalds 11600804d113SJames Morris read_lock(&policy_rwlock); 116119439d05SStephen Smalley avd_init(avd); 116219439d05SStephen Smalley if (!ss_initialized) 116319439d05SStephen Smalley goto allow; 116419439d05SStephen Smalley 116519439d05SStephen Smalley scontext = sidtab_search(&sidtab, ssid); 116619439d05SStephen Smalley if (!scontext) { 116719439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 116819439d05SStephen Smalley __func__, ssid); 116919439d05SStephen Smalley goto out; 117019439d05SStephen Smalley } 117119439d05SStephen Smalley 117219439d05SStephen Smalley /* permissive domain? */ 117319439d05SStephen Smalley if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) 117419439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE; 117519439d05SStephen Smalley 117619439d05SStephen Smalley tcontext = sidtab_search(&sidtab, tsid); 117719439d05SStephen Smalley if (!tcontext) { 117819439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 117919439d05SStephen Smalley __func__, tsid); 118019439d05SStephen Smalley goto out; 118119439d05SStephen Smalley } 118219439d05SStephen Smalley 118319439d05SStephen Smalley if (unlikely(!tclass)) { 118419439d05SStephen Smalley if (policydb.allow_unknown) 118519439d05SStephen Smalley goto allow; 118619439d05SStephen Smalley goto out; 118719439d05SStephen Smalley } 118819439d05SStephen Smalley 1189fa1aa143SJeff Vander Stoep context_struct_compute_av(scontext, tcontext, tclass, avd, NULL); 119019439d05SStephen Smalley out: 11910804d113SJames Morris read_unlock(&policy_rwlock); 119219439d05SStephen Smalley return; 119319439d05SStephen Smalley allow: 119419439d05SStephen Smalley avd->allowed = 0xffffffff; 119519439d05SStephen Smalley goto out; 11961da177e4SLinus Torvalds } 11971da177e4SLinus Torvalds 11981da177e4SLinus Torvalds /* 11991da177e4SLinus Torvalds * Write the security context string representation of 12001da177e4SLinus Torvalds * the context structure `context' into a dynamically 12011da177e4SLinus Torvalds * allocated string of the correct size. Set `*scontext' 12021da177e4SLinus Torvalds * to point to this string and set `*scontext_len' to 12031da177e4SLinus Torvalds * the length of the string. 12041da177e4SLinus Torvalds */ 12051da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len) 12061da177e4SLinus Torvalds { 12071da177e4SLinus Torvalds char *scontextp; 12081da177e4SLinus Torvalds 1209d5630b9dSEric Paris if (scontext) 12101da177e4SLinus Torvalds *scontext = NULL; 12111da177e4SLinus Torvalds *scontext_len = 0; 12121da177e4SLinus Torvalds 121312b29f34SStephen Smalley if (context->len) { 121412b29f34SStephen Smalley *scontext_len = context->len; 1215bb7081abSEric Paris if (scontext) { 121612b29f34SStephen Smalley *scontext = kstrdup(context->str, GFP_ATOMIC); 121712b29f34SStephen Smalley if (!(*scontext)) 121812b29f34SStephen Smalley return -ENOMEM; 1219bb7081abSEric Paris } 122012b29f34SStephen Smalley return 0; 122112b29f34SStephen Smalley } 122212b29f34SStephen Smalley 12231da177e4SLinus Torvalds /* Compute the size of the context. */ 1224ac76c05bSEric Paris *scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1; 1225ac76c05bSEric Paris *scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1; 1226ac76c05bSEric Paris *scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1; 12271da177e4SLinus Torvalds *scontext_len += mls_compute_context_len(context); 12281da177e4SLinus Torvalds 1229d5630b9dSEric Paris if (!scontext) 1230d5630b9dSEric Paris return 0; 1231d5630b9dSEric Paris 12321da177e4SLinus Torvalds /* Allocate space for the context; caller must free this space. */ 12331da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 12345d55a345SEric Paris if (!scontextp) 12351da177e4SLinus Torvalds return -ENOMEM; 12361da177e4SLinus Torvalds *scontext = scontextp; 12371da177e4SLinus Torvalds 12381da177e4SLinus Torvalds /* 12391da177e4SLinus Torvalds * Copy the user name, role name and type name into the context. 12401da177e4SLinus Torvalds */ 12419529c788SRasmus Villemoes scontextp += sprintf(scontextp, "%s:%s:%s", 1242ac76c05bSEric Paris sym_name(&policydb, SYM_USERS, context->user - 1), 1243ac76c05bSEric Paris sym_name(&policydb, SYM_ROLES, context->role - 1), 1244ac76c05bSEric Paris sym_name(&policydb, SYM_TYPES, context->type - 1)); 12451da177e4SLinus Torvalds 12461da177e4SLinus Torvalds mls_sid_to_context(context, &scontextp); 12471da177e4SLinus Torvalds 12481da177e4SLinus Torvalds *scontextp = 0; 12491da177e4SLinus Torvalds 12501da177e4SLinus Torvalds return 0; 12511da177e4SLinus Torvalds } 12521da177e4SLinus Torvalds 12531da177e4SLinus Torvalds #include "initial_sid_to_string.h" 12541da177e4SLinus Torvalds 1255f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid) 1256f0ee2e46SJames Carter { 1257f0ee2e46SJames Carter if (unlikely(sid > SECINITSID_NUM)) 1258f0ee2e46SJames Carter return NULL; 1259f0ee2e46SJames Carter return initial_sid_to_string[sid]; 1260f0ee2e46SJames Carter } 1261f0ee2e46SJames Carter 126212b29f34SStephen Smalley static int security_sid_to_context_core(u32 sid, char **scontext, 126312b29f34SStephen Smalley u32 *scontext_len, int force) 12641da177e4SLinus Torvalds { 12651da177e4SLinus Torvalds struct context *context; 12661da177e4SLinus Torvalds int rc = 0; 12671da177e4SLinus Torvalds 1268d5630b9dSEric Paris if (scontext) 12694f4acf3aSStephen Smalley *scontext = NULL; 12704f4acf3aSStephen Smalley *scontext_len = 0; 12714f4acf3aSStephen Smalley 12721da177e4SLinus Torvalds if (!ss_initialized) { 12731da177e4SLinus Torvalds if (sid <= SECINITSID_NUM) { 12741da177e4SLinus Torvalds char *scontextp; 12751da177e4SLinus Torvalds 12761da177e4SLinus Torvalds *scontext_len = strlen(initial_sid_to_string[sid]) + 1; 1277d5630b9dSEric Paris if (!scontext) 1278d5630b9dSEric Paris goto out; 1279aa736c36SRasmus Villemoes scontextp = kmemdup(initial_sid_to_string[sid], 1280aa736c36SRasmus Villemoes *scontext_len, GFP_ATOMIC); 12810cccca06SSerge E. Hallyn if (!scontextp) { 12820cccca06SSerge E. Hallyn rc = -ENOMEM; 12830cccca06SSerge E. Hallyn goto out; 12840cccca06SSerge E. Hallyn } 12851da177e4SLinus Torvalds *scontext = scontextp; 12861da177e4SLinus Torvalds goto out; 12871da177e4SLinus Torvalds } 1288744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: called before initial " 1289744ba35eSEric Paris "load_policy on unknown SID %d\n", __func__, sid); 12901da177e4SLinus Torvalds rc = -EINVAL; 12911da177e4SLinus Torvalds goto out; 12921da177e4SLinus Torvalds } 12930804d113SJames Morris read_lock(&policy_rwlock); 129412b29f34SStephen Smalley if (force) 129512b29f34SStephen Smalley context = sidtab_search_force(&sidtab, sid); 129612b29f34SStephen Smalley else 12971da177e4SLinus Torvalds context = sidtab_search(&sidtab, sid); 12981da177e4SLinus Torvalds if (!context) { 1299744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1300744ba35eSEric Paris __func__, sid); 13011da177e4SLinus Torvalds rc = -EINVAL; 13021da177e4SLinus Torvalds goto out_unlock; 13031da177e4SLinus Torvalds } 13041da177e4SLinus Torvalds rc = context_struct_to_string(context, scontext, scontext_len); 13051da177e4SLinus Torvalds out_unlock: 13060804d113SJames Morris read_unlock(&policy_rwlock); 13071da177e4SLinus Torvalds out: 13081da177e4SLinus Torvalds return rc; 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds } 13111da177e4SLinus Torvalds 131212b29f34SStephen Smalley /** 131312b29f34SStephen Smalley * security_sid_to_context - Obtain a context for a given SID. 131412b29f34SStephen Smalley * @sid: security identifier, SID 131512b29f34SStephen Smalley * @scontext: security context 131612b29f34SStephen Smalley * @scontext_len: length in bytes 131712b29f34SStephen Smalley * 131812b29f34SStephen Smalley * Write the string representation of the context associated with @sid 131912b29f34SStephen Smalley * into a dynamically allocated string of the correct size. Set @scontext 132012b29f34SStephen Smalley * to point to this string and set @scontext_len to the length of the string. 132112b29f34SStephen Smalley */ 132212b29f34SStephen Smalley int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) 13231da177e4SLinus Torvalds { 132412b29f34SStephen Smalley return security_sid_to_context_core(sid, scontext, scontext_len, 0); 132512b29f34SStephen Smalley } 132612b29f34SStephen Smalley 132712b29f34SStephen Smalley int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len) 132812b29f34SStephen Smalley { 132912b29f34SStephen Smalley return security_sid_to_context_core(sid, scontext, scontext_len, 1); 133012b29f34SStephen Smalley } 133112b29f34SStephen Smalley 13329a59daa0SStephen Smalley /* 13339a59daa0SStephen Smalley * Caveat: Mutates scontext. 13349a59daa0SStephen Smalley */ 133512b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol, 133612b29f34SStephen Smalley struct sidtab *sidtabp, 13379a59daa0SStephen Smalley char *scontext, 133812b29f34SStephen Smalley u32 scontext_len, 133912b29f34SStephen Smalley struct context *ctx, 13409a59daa0SStephen Smalley u32 def_sid) 134112b29f34SStephen Smalley { 13421da177e4SLinus Torvalds struct role_datum *role; 13431da177e4SLinus Torvalds struct type_datum *typdatum; 13441da177e4SLinus Torvalds struct user_datum *usrdatum; 13451da177e4SLinus Torvalds char *scontextp, *p, oldc; 13461da177e4SLinus Torvalds int rc = 0; 13471da177e4SLinus Torvalds 134812b29f34SStephen Smalley context_init(ctx); 134912b29f34SStephen Smalley 135012b29f34SStephen Smalley /* Parse the security context. */ 135112b29f34SStephen Smalley 135212b29f34SStephen Smalley rc = -EINVAL; 13539a59daa0SStephen Smalley scontextp = (char *) scontext; 135412b29f34SStephen Smalley 135512b29f34SStephen Smalley /* Extract the user. */ 135612b29f34SStephen Smalley p = scontextp; 135712b29f34SStephen Smalley while (*p && *p != ':') 135812b29f34SStephen Smalley p++; 135912b29f34SStephen Smalley 136012b29f34SStephen Smalley if (*p == 0) 136112b29f34SStephen Smalley goto out; 136212b29f34SStephen Smalley 136312b29f34SStephen Smalley *p++ = 0; 136412b29f34SStephen Smalley 136512b29f34SStephen Smalley usrdatum = hashtab_search(pol->p_users.table, scontextp); 136612b29f34SStephen Smalley if (!usrdatum) 136712b29f34SStephen Smalley goto out; 136812b29f34SStephen Smalley 136912b29f34SStephen Smalley ctx->user = usrdatum->value; 137012b29f34SStephen Smalley 137112b29f34SStephen Smalley /* Extract role. */ 137212b29f34SStephen Smalley scontextp = p; 137312b29f34SStephen Smalley while (*p && *p != ':') 137412b29f34SStephen Smalley p++; 137512b29f34SStephen Smalley 137612b29f34SStephen Smalley if (*p == 0) 137712b29f34SStephen Smalley goto out; 137812b29f34SStephen Smalley 137912b29f34SStephen Smalley *p++ = 0; 138012b29f34SStephen Smalley 138112b29f34SStephen Smalley role = hashtab_search(pol->p_roles.table, scontextp); 138212b29f34SStephen Smalley if (!role) 138312b29f34SStephen Smalley goto out; 138412b29f34SStephen Smalley ctx->role = role->value; 138512b29f34SStephen Smalley 138612b29f34SStephen Smalley /* Extract type. */ 138712b29f34SStephen Smalley scontextp = p; 138812b29f34SStephen Smalley while (*p && *p != ':') 138912b29f34SStephen Smalley p++; 139012b29f34SStephen Smalley oldc = *p; 139112b29f34SStephen Smalley *p++ = 0; 139212b29f34SStephen Smalley 139312b29f34SStephen Smalley typdatum = hashtab_search(pol->p_types.table, scontextp); 1394d9250deaSKaiGai Kohei if (!typdatum || typdatum->attribute) 139512b29f34SStephen Smalley goto out; 139612b29f34SStephen Smalley 139712b29f34SStephen Smalley ctx->type = typdatum->value; 139812b29f34SStephen Smalley 139912b29f34SStephen Smalley rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid); 140012b29f34SStephen Smalley if (rc) 140112b29f34SStephen Smalley goto out; 140212b29f34SStephen Smalley 140312b29f34SStephen Smalley rc = -EINVAL; 14044b02b524SEric Paris if ((p - scontext) < scontext_len) 140512b29f34SStephen Smalley goto out; 140612b29f34SStephen Smalley 140712b29f34SStephen Smalley /* Check the validity of the new context. */ 14084b02b524SEric Paris if (!policydb_context_isvalid(pol, ctx)) 140912b29f34SStephen Smalley goto out; 141012b29f34SStephen Smalley rc = 0; 141112b29f34SStephen Smalley out: 14128e531af9SEric Paris if (rc) 14138e531af9SEric Paris context_destroy(ctx); 141412b29f34SStephen Smalley return rc; 141512b29f34SStephen Smalley } 141612b29f34SStephen Smalley 141712b29f34SStephen Smalley static int security_context_to_sid_core(const char *scontext, u32 scontext_len, 141812b29f34SStephen Smalley u32 *sid, u32 def_sid, gfp_t gfp_flags, 141912b29f34SStephen Smalley int force) 142012b29f34SStephen Smalley { 14219a59daa0SStephen Smalley char *scontext2, *str = NULL; 142212b29f34SStephen Smalley struct context context; 142312b29f34SStephen Smalley int rc = 0; 142412b29f34SStephen Smalley 14252172fa70SStephen Smalley /* An empty security context is never valid. */ 14262172fa70SStephen Smalley if (!scontext_len) 14272172fa70SStephen Smalley return -EINVAL; 14282172fa70SStephen Smalley 14291da177e4SLinus Torvalds if (!ss_initialized) { 14301da177e4SLinus Torvalds int i; 14311da177e4SLinus Torvalds 14321da177e4SLinus Torvalds for (i = 1; i < SECINITSID_NUM; i++) { 14331da177e4SLinus Torvalds if (!strcmp(initial_sid_to_string[i], scontext)) { 14341da177e4SLinus Torvalds *sid = i; 14359a59daa0SStephen Smalley return 0; 14361da177e4SLinus Torvalds } 14371da177e4SLinus Torvalds } 14381da177e4SLinus Torvalds *sid = SECINITSID_KERNEL; 14399a59daa0SStephen Smalley return 0; 14401da177e4SLinus Torvalds } 14411da177e4SLinus Torvalds *sid = SECSID_NULL; 14421da177e4SLinus Torvalds 14439a59daa0SStephen Smalley /* Copy the string so that we can modify the copy as we parse it. */ 14449a59daa0SStephen Smalley scontext2 = kmalloc(scontext_len + 1, gfp_flags); 14459a59daa0SStephen Smalley if (!scontext2) 14469a59daa0SStephen Smalley return -ENOMEM; 14479a59daa0SStephen Smalley memcpy(scontext2, scontext, scontext_len); 14489a59daa0SStephen Smalley scontext2[scontext_len] = 0; 14499a59daa0SStephen Smalley 14509a59daa0SStephen Smalley if (force) { 14519a59daa0SStephen Smalley /* Save another copy for storing in uninterpreted form */ 14524b02b524SEric Paris rc = -ENOMEM; 14539a59daa0SStephen Smalley str = kstrdup(scontext2, gfp_flags); 14544b02b524SEric Paris if (!str) 14554b02b524SEric Paris goto out; 14569a59daa0SStephen Smalley } 14579a59daa0SStephen Smalley 14580804d113SJames Morris read_lock(&policy_rwlock); 14594b02b524SEric Paris rc = string_to_context_struct(&policydb, &sidtab, scontext2, 14604b02b524SEric Paris scontext_len, &context, def_sid); 146112b29f34SStephen Smalley if (rc == -EINVAL && force) { 14629a59daa0SStephen Smalley context.str = str; 146312b29f34SStephen Smalley context.len = scontext_len; 14649a59daa0SStephen Smalley str = NULL; 146512b29f34SStephen Smalley } else if (rc) 14664b02b524SEric Paris goto out_unlock; 14671da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &context, sid); 14681da177e4SLinus Torvalds context_destroy(&context); 14694b02b524SEric Paris out_unlock: 14700804d113SJames Morris read_unlock(&policy_rwlock); 14714b02b524SEric Paris out: 14729a59daa0SStephen Smalley kfree(scontext2); 14739a59daa0SStephen Smalley kfree(str); 14741da177e4SLinus Torvalds return rc; 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds 1477f5c1d5b2SJames Morris /** 1478f5c1d5b2SJames Morris * security_context_to_sid - Obtain a SID for a given security context. 1479f5c1d5b2SJames Morris * @scontext: security context 1480f5c1d5b2SJames Morris * @scontext_len: length in bytes 1481f5c1d5b2SJames Morris * @sid: security identifier, SID 148252a4c640SNikolay Aleksandrov * @gfp: context for the allocation 1483f5c1d5b2SJames Morris * 1484f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 1485f5c1d5b2SJames Morris * has the string representation specified by @scontext. 1486f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 1487f5c1d5b2SJames Morris * memory is available, or 0 on success. 1488f5c1d5b2SJames Morris */ 148952a4c640SNikolay Aleksandrov int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid, 149052a4c640SNikolay Aleksandrov gfp_t gfp) 1491f5c1d5b2SJames Morris { 1492f5c1d5b2SJames Morris return security_context_to_sid_core(scontext, scontext_len, 149352a4c640SNikolay Aleksandrov sid, SECSID_NULL, gfp, 0); 1494f5c1d5b2SJames Morris } 1495f5c1d5b2SJames Morris 149644be2f65SRasmus Villemoes int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp) 149744be2f65SRasmus Villemoes { 149844be2f65SRasmus Villemoes return security_context_to_sid(scontext, strlen(scontext), sid, gfp); 149944be2f65SRasmus Villemoes } 150044be2f65SRasmus Villemoes 1501f5c1d5b2SJames Morris /** 1502f5c1d5b2SJames Morris * security_context_to_sid_default - Obtain a SID for a given security context, 1503f5c1d5b2SJames Morris * falling back to specified default if needed. 1504f5c1d5b2SJames Morris * 1505f5c1d5b2SJames Morris * @scontext: security context 1506f5c1d5b2SJames Morris * @scontext_len: length in bytes 1507f5c1d5b2SJames Morris * @sid: security identifier, SID 1508d133a960SGabriel Craciunescu * @def_sid: default SID to assign on error 1509f5c1d5b2SJames Morris * 1510f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 1511f5c1d5b2SJames Morris * has the string representation specified by @scontext. 1512f5c1d5b2SJames Morris * The default SID is passed to the MLS layer to be used to allow 1513f5c1d5b2SJames Morris * kernel labeling of the MLS field if the MLS field is not present 1514f5c1d5b2SJames Morris * (for upgrading to MLS without full relabel). 151512b29f34SStephen Smalley * Implicitly forces adding of the context even if it cannot be mapped yet. 1516f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 1517f5c1d5b2SJames Morris * memory is available, or 0 on success. 1518f5c1d5b2SJames Morris */ 15197bf570dcSDavid Howells int security_context_to_sid_default(const char *scontext, u32 scontext_len, 15207bf570dcSDavid Howells u32 *sid, u32 def_sid, gfp_t gfp_flags) 1521f5c1d5b2SJames Morris { 1522f5c1d5b2SJames Morris return security_context_to_sid_core(scontext, scontext_len, 152312b29f34SStephen Smalley sid, def_sid, gfp_flags, 1); 152412b29f34SStephen Smalley } 152512b29f34SStephen Smalley 152612b29f34SStephen Smalley int security_context_to_sid_force(const char *scontext, u32 scontext_len, 152712b29f34SStephen Smalley u32 *sid) 152812b29f34SStephen Smalley { 152912b29f34SStephen Smalley return security_context_to_sid_core(scontext, scontext_len, 153012b29f34SStephen Smalley sid, SECSID_NULL, GFP_KERNEL, 1); 1531f5c1d5b2SJames Morris } 1532f5c1d5b2SJames Morris 15331da177e4SLinus Torvalds static int compute_sid_handle_invalid_context( 15341da177e4SLinus Torvalds struct context *scontext, 15351da177e4SLinus Torvalds struct context *tcontext, 15361da177e4SLinus Torvalds u16 tclass, 15371da177e4SLinus Torvalds struct context *newcontext) 15381da177e4SLinus Torvalds { 15391da177e4SLinus Torvalds char *s = NULL, *t = NULL, *n = NULL; 15401da177e4SLinus Torvalds u32 slen, tlen, nlen; 15411da177e4SLinus Torvalds 15424b02b524SEric Paris if (context_struct_to_string(scontext, &s, &slen)) 15431da177e4SLinus Torvalds goto out; 15444b02b524SEric Paris if (context_struct_to_string(tcontext, &t, &tlen)) 15451da177e4SLinus Torvalds goto out; 15464b02b524SEric Paris if (context_struct_to_string(newcontext, &n, &nlen)) 15471da177e4SLinus Torvalds goto out; 15489ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 15494093a844SRichard Guy Briggs "op=security_compute_sid invalid_context=%s" 15504093a844SRichard Guy Briggs " scontext=%s" 15511da177e4SLinus Torvalds " tcontext=%s" 15521da177e4SLinus Torvalds " tclass=%s", 1553ac76c05bSEric Paris n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); 15541da177e4SLinus Torvalds out: 15551da177e4SLinus Torvalds kfree(s); 15561da177e4SLinus Torvalds kfree(t); 15571da177e4SLinus Torvalds kfree(n); 15581da177e4SLinus Torvalds if (!selinux_enforcing) 15591da177e4SLinus Torvalds return 0; 15601da177e4SLinus Torvalds return -EACCES; 15611da177e4SLinus Torvalds } 15621da177e4SLinus Torvalds 1563652bb9b0SEric Paris static void filename_compute_type(struct policydb *p, struct context *newcontext, 15642667991fSEric Paris u32 stype, u32 ttype, u16 tclass, 1565f50a3ec9SKohei Kaigai const char *objname) 1566652bb9b0SEric Paris { 15672463c26dSEric Paris struct filename_trans ft; 15682463c26dSEric Paris struct filename_trans_datum *otype; 156903a4c018SEric Paris 157003a4c018SEric Paris /* 157103a4c018SEric Paris * Most filename trans rules are going to live in specific directories 157203a4c018SEric Paris * like /dev or /var/run. This bitmap will quickly skip rule searches 157303a4c018SEric Paris * if the ttype does not contain any rules. 157403a4c018SEric Paris */ 157503a4c018SEric Paris if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype)) 1576652bb9b0SEric Paris return; 157703a4c018SEric Paris 15782463c26dSEric Paris ft.stype = stype; 15792463c26dSEric Paris ft.ttype = ttype; 15802463c26dSEric Paris ft.tclass = tclass; 15812463c26dSEric Paris ft.name = objname; 15822463c26dSEric Paris 15832463c26dSEric Paris otype = hashtab_search(p->filename_trans, &ft); 15842463c26dSEric Paris if (otype) 15852463c26dSEric Paris newcontext->type = otype->otype; 1586652bb9b0SEric Paris } 1587652bb9b0SEric Paris 15881da177e4SLinus Torvalds static int security_compute_sid(u32 ssid, 15891da177e4SLinus Torvalds u32 tsid, 1590c6d3aaa4SStephen Smalley u16 orig_tclass, 15911da177e4SLinus Torvalds u32 specified, 1592f50a3ec9SKohei Kaigai const char *objname, 1593c6d3aaa4SStephen Smalley u32 *out_sid, 1594c6d3aaa4SStephen Smalley bool kern) 15951da177e4SLinus Torvalds { 1596aa893269SEric Paris struct class_datum *cladatum = NULL; 15971da177e4SLinus Torvalds struct context *scontext = NULL, *tcontext = NULL, newcontext; 15981da177e4SLinus Torvalds struct role_trans *roletr = NULL; 15991da177e4SLinus Torvalds struct avtab_key avkey; 16001da177e4SLinus Torvalds struct avtab_datum *avdatum; 16011da177e4SLinus Torvalds struct avtab_node *node; 1602c6d3aaa4SStephen Smalley u16 tclass; 16031da177e4SLinus Torvalds int rc = 0; 16046f5317e7SHarry Ciao bool sock; 16051da177e4SLinus Torvalds 16061da177e4SLinus Torvalds if (!ss_initialized) { 1607c6d3aaa4SStephen Smalley switch (orig_tclass) { 1608c6d3aaa4SStephen Smalley case SECCLASS_PROCESS: /* kernel value */ 16091da177e4SLinus Torvalds *out_sid = ssid; 16101da177e4SLinus Torvalds break; 16111da177e4SLinus Torvalds default: 16121da177e4SLinus Torvalds *out_sid = tsid; 16131da177e4SLinus Torvalds break; 16141da177e4SLinus Torvalds } 16151da177e4SLinus Torvalds goto out; 16161da177e4SLinus Torvalds } 16171da177e4SLinus Torvalds 1618851f8a69SVenkat Yekkirala context_init(&newcontext); 1619851f8a69SVenkat Yekkirala 16200804d113SJames Morris read_lock(&policy_rwlock); 16211da177e4SLinus Torvalds 16226f5317e7SHarry Ciao if (kern) { 1623c6d3aaa4SStephen Smalley tclass = unmap_class(orig_tclass); 16246f5317e7SHarry Ciao sock = security_is_socket_class(orig_tclass); 16256f5317e7SHarry Ciao } else { 1626c6d3aaa4SStephen Smalley tclass = orig_tclass; 16276f5317e7SHarry Ciao sock = security_is_socket_class(map_class(tclass)); 16286f5317e7SHarry Ciao } 1629c6d3aaa4SStephen Smalley 16301da177e4SLinus Torvalds scontext = sidtab_search(&sidtab, ssid); 16311da177e4SLinus Torvalds if (!scontext) { 1632744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1633744ba35eSEric Paris __func__, ssid); 16341da177e4SLinus Torvalds rc = -EINVAL; 16351da177e4SLinus Torvalds goto out_unlock; 16361da177e4SLinus Torvalds } 16371da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tsid); 16381da177e4SLinus Torvalds if (!tcontext) { 1639744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1640744ba35eSEric Paris __func__, tsid); 16411da177e4SLinus Torvalds rc = -EINVAL; 16421da177e4SLinus Torvalds goto out_unlock; 16431da177e4SLinus Torvalds } 16441da177e4SLinus Torvalds 1645aa893269SEric Paris if (tclass && tclass <= policydb.p_classes.nprim) 1646aa893269SEric Paris cladatum = policydb.class_val_to_struct[tclass - 1]; 1647aa893269SEric Paris 16481da177e4SLinus Torvalds /* Set the user identity. */ 16491da177e4SLinus Torvalds switch (specified) { 16501da177e4SLinus Torvalds case AVTAB_TRANSITION: 16511da177e4SLinus Torvalds case AVTAB_CHANGE: 1652aa893269SEric Paris if (cladatum && cladatum->default_user == DEFAULT_TARGET) { 1653aa893269SEric Paris newcontext.user = tcontext->user; 1654aa893269SEric Paris } else { 1655aa893269SEric Paris /* notice this gets both DEFAULT_SOURCE and unset */ 16561da177e4SLinus Torvalds /* Use the process user identity. */ 16571da177e4SLinus Torvalds newcontext.user = scontext->user; 1658aa893269SEric Paris } 16591da177e4SLinus Torvalds break; 16601da177e4SLinus Torvalds case AVTAB_MEMBER: 16611da177e4SLinus Torvalds /* Use the related object owner. */ 16621da177e4SLinus Torvalds newcontext.user = tcontext->user; 16631da177e4SLinus Torvalds break; 16641da177e4SLinus Torvalds } 16651da177e4SLinus Torvalds 1666aa893269SEric Paris /* Set the role to default values. */ 1667aa893269SEric Paris if (cladatum && cladatum->default_role == DEFAULT_SOURCE) { 16681da177e4SLinus Torvalds newcontext.role = scontext->role; 1669aa893269SEric Paris } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { 1670aa893269SEric Paris newcontext.role = tcontext->role; 1671aa893269SEric Paris } else { 1672aa893269SEric Paris if ((tclass == policydb.process_class) || (sock == true)) 1673aa893269SEric Paris newcontext.role = scontext->role; 1674aa893269SEric Paris else 1675aa893269SEric Paris newcontext.role = OBJECT_R_VAL; 1676aa893269SEric Paris } 1677aa893269SEric Paris 1678aa893269SEric Paris /* Set the type to default values. */ 1679eed7795dSEric Paris if (cladatum && cladatum->default_type == DEFAULT_SOURCE) { 1680eed7795dSEric Paris newcontext.type = scontext->type; 1681eed7795dSEric Paris } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) { 1682eed7795dSEric Paris newcontext.type = tcontext->type; 1683eed7795dSEric Paris } else { 1684aa893269SEric Paris if ((tclass == policydb.process_class) || (sock == true)) { 1685aa893269SEric Paris /* Use the type of process. */ 16861da177e4SLinus Torvalds newcontext.type = scontext->type; 1687c6d3aaa4SStephen Smalley } else { 16881da177e4SLinus Torvalds /* Use the type of the related object. */ 16891da177e4SLinus Torvalds newcontext.type = tcontext->type; 16901da177e4SLinus Torvalds } 1691eed7795dSEric Paris } 16921da177e4SLinus Torvalds 16931da177e4SLinus Torvalds /* Look for a type transition/member/change rule. */ 16941da177e4SLinus Torvalds avkey.source_type = scontext->type; 16951da177e4SLinus Torvalds avkey.target_type = tcontext->type; 16961da177e4SLinus Torvalds avkey.target_class = tclass; 1697782ebb99SStephen Smalley avkey.specified = specified; 1698782ebb99SStephen Smalley avdatum = avtab_search(&policydb.te_avtab, &avkey); 16991da177e4SLinus Torvalds 17001da177e4SLinus Torvalds /* If no permanent rule, also check for enabled conditional rules */ 17011da177e4SLinus Torvalds if (!avdatum) { 1702782ebb99SStephen Smalley node = avtab_search_node(&policydb.te_cond_avtab, &avkey); 1703dbc74c65SVesa-Matti Kari for (; node; node = avtab_search_node_next(node, specified)) { 1704782ebb99SStephen Smalley if (node->key.specified & AVTAB_ENABLED) { 17051da177e4SLinus Torvalds avdatum = &node->datum; 17061da177e4SLinus Torvalds break; 17071da177e4SLinus Torvalds } 17081da177e4SLinus Torvalds } 17091da177e4SLinus Torvalds } 17101da177e4SLinus Torvalds 1711782ebb99SStephen Smalley if (avdatum) { 17121da177e4SLinus Torvalds /* Use the type from the type transition/member/change rule. */ 1713fa1aa143SJeff Vander Stoep newcontext.type = avdatum->u.data; 17141da177e4SLinus Torvalds } 17151da177e4SLinus Torvalds 17164742600cSEric Paris /* if we have a objname this is a file trans check so check those rules */ 1717f50a3ec9SKohei Kaigai if (objname) 1718652bb9b0SEric Paris filename_compute_type(&policydb, &newcontext, scontext->type, 1719f50a3ec9SKohei Kaigai tcontext->type, tclass, objname); 1720652bb9b0SEric Paris 17211da177e4SLinus Torvalds /* Check for class-specific changes. */ 17221da177e4SLinus Torvalds if (specified & AVTAB_TRANSITION) { 17231da177e4SLinus Torvalds /* Look for a role transition rule. */ 172463a312caSHarry Ciao for (roletr = policydb.role_tr; roletr; roletr = roletr->next) { 172563a312caSHarry Ciao if ((roletr->role == scontext->role) && 172663a312caSHarry Ciao (roletr->type == tcontext->type) && 172763a312caSHarry Ciao (roletr->tclass == tclass)) { 17281da177e4SLinus Torvalds /* Use the role transition rule. */ 17291da177e4SLinus Torvalds newcontext.role = roletr->new_role; 17301da177e4SLinus Torvalds break; 17311da177e4SLinus Torvalds } 17321da177e4SLinus Torvalds } 17331da177e4SLinus Torvalds } 17341da177e4SLinus Torvalds 17351da177e4SLinus Torvalds /* Set the MLS attributes. 17361da177e4SLinus Torvalds This is done last because it may allocate memory. */ 17376f5317e7SHarry Ciao rc = mls_compute_sid(scontext, tcontext, tclass, specified, 17386f5317e7SHarry Ciao &newcontext, sock); 17391da177e4SLinus Torvalds if (rc) 17401da177e4SLinus Torvalds goto out_unlock; 17411da177e4SLinus Torvalds 17421da177e4SLinus Torvalds /* Check the validity of the context. */ 17431da177e4SLinus Torvalds if (!policydb_context_isvalid(&policydb, &newcontext)) { 17441da177e4SLinus Torvalds rc = compute_sid_handle_invalid_context(scontext, 17451da177e4SLinus Torvalds tcontext, 17461da177e4SLinus Torvalds tclass, 17471da177e4SLinus Torvalds &newcontext); 17481da177e4SLinus Torvalds if (rc) 17491da177e4SLinus Torvalds goto out_unlock; 17501da177e4SLinus Torvalds } 17511da177e4SLinus Torvalds /* Obtain the sid for the context. */ 17521da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid); 17531da177e4SLinus Torvalds out_unlock: 17540804d113SJames Morris read_unlock(&policy_rwlock); 17551da177e4SLinus Torvalds context_destroy(&newcontext); 17561da177e4SLinus Torvalds out: 17571da177e4SLinus Torvalds return rc; 17581da177e4SLinus Torvalds } 17591da177e4SLinus Torvalds 17601da177e4SLinus Torvalds /** 17611da177e4SLinus Torvalds * security_transition_sid - Compute the SID for a new subject/object. 17621da177e4SLinus Torvalds * @ssid: source security identifier 17631da177e4SLinus Torvalds * @tsid: target security identifier 17641da177e4SLinus Torvalds * @tclass: target security class 17651da177e4SLinus Torvalds * @out_sid: security identifier for new subject/object 17661da177e4SLinus Torvalds * 17671da177e4SLinus Torvalds * Compute a SID to use for labeling a new subject or object in the 17681da177e4SLinus Torvalds * class @tclass based on a SID pair (@ssid, @tsid). 17691da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 17701da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the new SID was 17711da177e4SLinus Torvalds * computed successfully. 17721da177e4SLinus Torvalds */ 1773652bb9b0SEric Paris int security_transition_sid(u32 ssid, u32 tsid, u16 tclass, 1774652bb9b0SEric Paris const struct qstr *qstr, u32 *out_sid) 17751da177e4SLinus Torvalds { 1776c6d3aaa4SStephen Smalley return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, 1777f50a3ec9SKohei Kaigai qstr ? qstr->name : NULL, out_sid, true); 1778c6d3aaa4SStephen Smalley } 1779c6d3aaa4SStephen Smalley 1780f50a3ec9SKohei Kaigai int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass, 1781f50a3ec9SKohei Kaigai const char *objname, u32 *out_sid) 1782c6d3aaa4SStephen Smalley { 1783c6d3aaa4SStephen Smalley return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, 1784f50a3ec9SKohei Kaigai objname, out_sid, false); 17851da177e4SLinus Torvalds } 17861da177e4SLinus Torvalds 17871da177e4SLinus Torvalds /** 17881da177e4SLinus Torvalds * security_member_sid - Compute the SID for member selection. 17891da177e4SLinus Torvalds * @ssid: source security identifier 17901da177e4SLinus Torvalds * @tsid: target security identifier 17911da177e4SLinus Torvalds * @tclass: target security class 17921da177e4SLinus Torvalds * @out_sid: security identifier for selected member 17931da177e4SLinus Torvalds * 17941da177e4SLinus Torvalds * Compute a SID to use when selecting a member of a polyinstantiated 17951da177e4SLinus Torvalds * object of class @tclass based on a SID pair (@ssid, @tsid). 17961da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 17971da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 17981da177e4SLinus Torvalds * computed successfully. 17991da177e4SLinus Torvalds */ 18001da177e4SLinus Torvalds int security_member_sid(u32 ssid, 18011da177e4SLinus Torvalds u32 tsid, 18021da177e4SLinus Torvalds u16 tclass, 18031da177e4SLinus Torvalds u32 *out_sid) 18041da177e4SLinus Torvalds { 1805652bb9b0SEric Paris return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, NULL, 1806652bb9b0SEric Paris out_sid, false); 18071da177e4SLinus Torvalds } 18081da177e4SLinus Torvalds 18091da177e4SLinus Torvalds /** 18101da177e4SLinus Torvalds * security_change_sid - Compute the SID for object relabeling. 18111da177e4SLinus Torvalds * @ssid: source security identifier 18121da177e4SLinus Torvalds * @tsid: target security identifier 18131da177e4SLinus Torvalds * @tclass: target security class 18141da177e4SLinus Torvalds * @out_sid: security identifier for selected member 18151da177e4SLinus Torvalds * 18161da177e4SLinus Torvalds * Compute a SID to use for relabeling an object of class @tclass 18171da177e4SLinus Torvalds * based on a SID pair (@ssid, @tsid). 18181da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 18191da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 18201da177e4SLinus Torvalds * computed successfully. 18211da177e4SLinus Torvalds */ 18221da177e4SLinus Torvalds int security_change_sid(u32 ssid, 18231da177e4SLinus Torvalds u32 tsid, 18241da177e4SLinus Torvalds u16 tclass, 18251da177e4SLinus Torvalds u32 *out_sid) 18261da177e4SLinus Torvalds { 1827652bb9b0SEric Paris return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL, 1828652bb9b0SEric Paris out_sid, false); 1829b94c7e67SChad Sellers } 1830b94c7e67SChad Sellers 18311da177e4SLinus Torvalds /* Clone the SID into the new SID table. */ 18321da177e4SLinus Torvalds static int clone_sid(u32 sid, 18331da177e4SLinus Torvalds struct context *context, 18341da177e4SLinus Torvalds void *arg) 18351da177e4SLinus Torvalds { 18361da177e4SLinus Torvalds struct sidtab *s = arg; 18371da177e4SLinus Torvalds 183842596eafSGuido Trentalancia if (sid > SECINITSID_NUM) 18391da177e4SLinus Torvalds return sidtab_insert(s, sid, context); 184042596eafSGuido Trentalancia else 184142596eafSGuido Trentalancia return 0; 18421da177e4SLinus Torvalds } 18431da177e4SLinus Torvalds 18441da177e4SLinus Torvalds static inline int convert_context_handle_invalid_context(struct context *context) 18451da177e4SLinus Torvalds { 18461da177e4SLinus Torvalds char *s; 18471da177e4SLinus Torvalds u32 len; 18481da177e4SLinus Torvalds 18494b02b524SEric Paris if (selinux_enforcing) 18504b02b524SEric Paris return -EINVAL; 18514b02b524SEric Paris 185212b29f34SStephen Smalley if (!context_struct_to_string(context, &s, &len)) { 18534b02b524SEric Paris printk(KERN_WARNING "SELinux: Context %s would be invalid if enforcing\n", s); 18541da177e4SLinus Torvalds kfree(s); 18551da177e4SLinus Torvalds } 18564b02b524SEric Paris return 0; 18571da177e4SLinus Torvalds } 18581da177e4SLinus Torvalds 18591da177e4SLinus Torvalds struct convert_context_args { 18601da177e4SLinus Torvalds struct policydb *oldp; 18611da177e4SLinus Torvalds struct policydb *newp; 18621da177e4SLinus Torvalds }; 18631da177e4SLinus Torvalds 18641da177e4SLinus Torvalds /* 18651da177e4SLinus Torvalds * Convert the values in the security context 18661da177e4SLinus Torvalds * structure `c' from the values specified 18671da177e4SLinus Torvalds * in the policy `p->oldp' to the values specified 18681da177e4SLinus Torvalds * in the policy `p->newp'. Verify that the 18691da177e4SLinus Torvalds * context is valid under the new policy. 18701da177e4SLinus Torvalds */ 18711da177e4SLinus Torvalds static int convert_context(u32 key, 18721da177e4SLinus Torvalds struct context *c, 18731da177e4SLinus Torvalds void *p) 18741da177e4SLinus Torvalds { 18751da177e4SLinus Torvalds struct convert_context_args *args; 18761da177e4SLinus Torvalds struct context oldc; 18770719aaf5SGuido Trentalancia struct ocontext *oc; 18780719aaf5SGuido Trentalancia struct mls_range *range; 18791da177e4SLinus Torvalds struct role_datum *role; 18801da177e4SLinus Torvalds struct type_datum *typdatum; 18811da177e4SLinus Torvalds struct user_datum *usrdatum; 18821da177e4SLinus Torvalds char *s; 18831da177e4SLinus Torvalds u32 len; 188442596eafSGuido Trentalancia int rc = 0; 188542596eafSGuido Trentalancia 188642596eafSGuido Trentalancia if (key <= SECINITSID_NUM) 188742596eafSGuido Trentalancia goto out; 18881da177e4SLinus Torvalds 18891da177e4SLinus Torvalds args = p; 18901da177e4SLinus Torvalds 189112b29f34SStephen Smalley if (c->str) { 189212b29f34SStephen Smalley struct context ctx; 18934b02b524SEric Paris 18949a59daa0SStephen Smalley rc = -ENOMEM; 18954b02b524SEric Paris s = kstrdup(c->str, GFP_KERNEL); 18964b02b524SEric Paris if (!s) 18979a59daa0SStephen Smalley goto out; 18984b02b524SEric Paris 18999a59daa0SStephen Smalley rc = string_to_context_struct(args->newp, NULL, s, 19009a59daa0SStephen Smalley c->len, &ctx, SECSID_NULL); 19019a59daa0SStephen Smalley kfree(s); 190212b29f34SStephen Smalley if (!rc) { 19034b02b524SEric Paris printk(KERN_INFO "SELinux: Context %s became valid (mapped).\n", 190412b29f34SStephen Smalley c->str); 190512b29f34SStephen Smalley /* Replace string with mapped representation. */ 190612b29f34SStephen Smalley kfree(c->str); 190712b29f34SStephen Smalley memcpy(c, &ctx, sizeof(*c)); 190812b29f34SStephen Smalley goto out; 190912b29f34SStephen Smalley } else if (rc == -EINVAL) { 191012b29f34SStephen Smalley /* Retain string representation for later mapping. */ 191112b29f34SStephen Smalley rc = 0; 191212b29f34SStephen Smalley goto out; 191312b29f34SStephen Smalley } else { 191412b29f34SStephen Smalley /* Other error condition, e.g. ENOMEM. */ 19154b02b524SEric Paris printk(KERN_ERR "SELinux: Unable to map context %s, rc = %d.\n", 191612b29f34SStephen Smalley c->str, -rc); 191712b29f34SStephen Smalley goto out; 191812b29f34SStephen Smalley } 191912b29f34SStephen Smalley } 192012b29f34SStephen Smalley 19211da177e4SLinus Torvalds rc = context_cpy(&oldc, c); 19221da177e4SLinus Torvalds if (rc) 19231da177e4SLinus Torvalds goto out; 19241da177e4SLinus Torvalds 19251da177e4SLinus Torvalds /* Convert the user. */ 19264b02b524SEric Paris rc = -EINVAL; 19271da177e4SLinus Torvalds usrdatum = hashtab_search(args->newp->p_users.table, 1928ac76c05bSEric Paris sym_name(args->oldp, SYM_USERS, c->user - 1)); 19295d55a345SEric Paris if (!usrdatum) 19301da177e4SLinus Torvalds goto bad; 19311da177e4SLinus Torvalds c->user = usrdatum->value; 19321da177e4SLinus Torvalds 19331da177e4SLinus Torvalds /* Convert the role. */ 19344b02b524SEric Paris rc = -EINVAL; 19351da177e4SLinus Torvalds role = hashtab_search(args->newp->p_roles.table, 1936ac76c05bSEric Paris sym_name(args->oldp, SYM_ROLES, c->role - 1)); 19375d55a345SEric Paris if (!role) 19381da177e4SLinus Torvalds goto bad; 19391da177e4SLinus Torvalds c->role = role->value; 19401da177e4SLinus Torvalds 19411da177e4SLinus Torvalds /* Convert the type. */ 19424b02b524SEric Paris rc = -EINVAL; 19431da177e4SLinus Torvalds typdatum = hashtab_search(args->newp->p_types.table, 1944ac76c05bSEric Paris sym_name(args->oldp, SYM_TYPES, c->type - 1)); 19455d55a345SEric Paris if (!typdatum) 19461da177e4SLinus Torvalds goto bad; 19471da177e4SLinus Torvalds c->type = typdatum->value; 19481da177e4SLinus Torvalds 19490719aaf5SGuido Trentalancia /* Convert the MLS fields if dealing with MLS policies */ 19500719aaf5SGuido Trentalancia if (args->oldp->mls_enabled && args->newp->mls_enabled) { 19511da177e4SLinus Torvalds rc = mls_convert_context(args->oldp, args->newp, c); 19521da177e4SLinus Torvalds if (rc) 19531da177e4SLinus Torvalds goto bad; 19540719aaf5SGuido Trentalancia } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) { 19550719aaf5SGuido Trentalancia /* 19560719aaf5SGuido Trentalancia * Switching between MLS and non-MLS policy: 19570719aaf5SGuido Trentalancia * free any storage used by the MLS fields in the 19580719aaf5SGuido Trentalancia * context for all existing entries in the sidtab. 19590719aaf5SGuido Trentalancia */ 19600719aaf5SGuido Trentalancia mls_context_destroy(c); 19610719aaf5SGuido Trentalancia } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { 19620719aaf5SGuido Trentalancia /* 19630719aaf5SGuido Trentalancia * Switching between non-MLS and MLS policy: 19640719aaf5SGuido Trentalancia * ensure that the MLS fields of the context for all 19650719aaf5SGuido Trentalancia * existing entries in the sidtab are filled in with a 19660719aaf5SGuido Trentalancia * suitable default value, likely taken from one of the 19670719aaf5SGuido Trentalancia * initial SIDs. 19680719aaf5SGuido Trentalancia */ 19690719aaf5SGuido Trentalancia oc = args->newp->ocontexts[OCON_ISID]; 19700719aaf5SGuido Trentalancia while (oc && oc->sid[0] != SECINITSID_UNLABELED) 19710719aaf5SGuido Trentalancia oc = oc->next; 19724b02b524SEric Paris rc = -EINVAL; 19730719aaf5SGuido Trentalancia if (!oc) { 19740719aaf5SGuido Trentalancia printk(KERN_ERR "SELinux: unable to look up" 19750719aaf5SGuido Trentalancia " the initial SIDs list\n"); 19760719aaf5SGuido Trentalancia goto bad; 19770719aaf5SGuido Trentalancia } 19780719aaf5SGuido Trentalancia range = &oc->context[0].range; 19790719aaf5SGuido Trentalancia rc = mls_range_set(c, range); 19800719aaf5SGuido Trentalancia if (rc) 19810719aaf5SGuido Trentalancia goto bad; 19820719aaf5SGuido Trentalancia } 19831da177e4SLinus Torvalds 19841da177e4SLinus Torvalds /* Check the validity of the new context. */ 19851da177e4SLinus Torvalds if (!policydb_context_isvalid(args->newp, c)) { 19861da177e4SLinus Torvalds rc = convert_context_handle_invalid_context(&oldc); 19871da177e4SLinus Torvalds if (rc) 19881da177e4SLinus Torvalds goto bad; 19891da177e4SLinus Torvalds } 19901da177e4SLinus Torvalds 19911da177e4SLinus Torvalds context_destroy(&oldc); 19924b02b524SEric Paris 199312b29f34SStephen Smalley rc = 0; 19941da177e4SLinus Torvalds out: 19951da177e4SLinus Torvalds return rc; 19961da177e4SLinus Torvalds bad: 199712b29f34SStephen Smalley /* Map old representation to string and save it. */ 19984b02b524SEric Paris rc = context_struct_to_string(&oldc, &s, &len); 19994b02b524SEric Paris if (rc) 20004b02b524SEric Paris return rc; 20011da177e4SLinus Torvalds context_destroy(&oldc); 200212b29f34SStephen Smalley context_destroy(c); 200312b29f34SStephen Smalley c->str = s; 200412b29f34SStephen Smalley c->len = len; 20054b02b524SEric Paris printk(KERN_INFO "SELinux: Context %s became invalid (unmapped).\n", 200612b29f34SStephen Smalley c->str); 200712b29f34SStephen Smalley rc = 0; 20081da177e4SLinus Torvalds goto out; 20091da177e4SLinus Torvalds } 20101da177e4SLinus Torvalds 20113bb56b25SPaul Moore static void security_load_policycaps(void) 20123bb56b25SPaul Moore { 20133bb56b25SPaul Moore selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps, 20143bb56b25SPaul Moore POLICYDB_CAPABILITY_NETPEER); 2015b0c636b9SEric Paris selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, 2016b0c636b9SEric Paris POLICYDB_CAPABILITY_OPENPERM); 20172be4d74fSChris PeBenito selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps, 20182be4d74fSChris PeBenito POLICYDB_CAPABILITY_ALWAYSNETWORK); 20193bb56b25SPaul Moore } 20203bb56b25SPaul Moore 2021e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p); 20221da177e4SLinus Torvalds 20231da177e4SLinus Torvalds /** 20241da177e4SLinus Torvalds * security_load_policy - Load a security policy configuration. 20251da177e4SLinus Torvalds * @data: binary policy data 20261da177e4SLinus Torvalds * @len: length of data in bytes 20271da177e4SLinus Torvalds * 20281da177e4SLinus Torvalds * Load a new set of security policy configuration data, 20291da177e4SLinus Torvalds * validate it and convert the SID table as necessary. 20301da177e4SLinus Torvalds * This function will flush the access vector cache after 20311da177e4SLinus Torvalds * loading the new policy. 20321da177e4SLinus Torvalds */ 20331da177e4SLinus Torvalds int security_load_policy(void *data, size_t len) 20341da177e4SLinus Torvalds { 2035b5495b42STim Gardner struct policydb *oldpolicydb, *newpolicydb; 20361da177e4SLinus Torvalds struct sidtab oldsidtab, newsidtab; 2037c6d3aaa4SStephen Smalley struct selinux_mapping *oldmap, *map = NULL; 20381da177e4SLinus Torvalds struct convert_context_args args; 20391da177e4SLinus Torvalds u32 seqno; 2040c6d3aaa4SStephen Smalley u16 map_size; 20411da177e4SLinus Torvalds int rc = 0; 20421da177e4SLinus Torvalds struct policy_file file = { data, len }, *fp = &file; 20431da177e4SLinus Torvalds 2044b5495b42STim Gardner oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL); 2045b5495b42STim Gardner if (!oldpolicydb) { 2046b5495b42STim Gardner rc = -ENOMEM; 2047b5495b42STim Gardner goto out; 2048b5495b42STim Gardner } 2049b5495b42STim Gardner newpolicydb = oldpolicydb + 1; 2050b5495b42STim Gardner 20511da177e4SLinus Torvalds if (!ss_initialized) { 20521da177e4SLinus Torvalds avtab_cache_init(); 2053a2000050SEric Paris rc = policydb_read(&policydb, fp); 2054a2000050SEric Paris if (rc) { 20551da177e4SLinus Torvalds avtab_cache_destroy(); 2056b5495b42STim Gardner goto out; 20571da177e4SLinus Torvalds } 2058a2000050SEric Paris 2059cee74f47SEric Paris policydb.len = len; 2060a2000050SEric Paris rc = selinux_set_mapping(&policydb, secclass_map, 2061c6d3aaa4SStephen Smalley ¤t_mapping, 2062a2000050SEric Paris ¤t_mapping_size); 2063a2000050SEric Paris if (rc) { 20641da177e4SLinus Torvalds policydb_destroy(&policydb); 20651da177e4SLinus Torvalds avtab_cache_destroy(); 2066b5495b42STim Gardner goto out; 20671da177e4SLinus Torvalds } 2068a2000050SEric Paris 2069a2000050SEric Paris rc = policydb_load_isids(&policydb, &sidtab); 2070a2000050SEric Paris if (rc) { 2071b94c7e67SChad Sellers policydb_destroy(&policydb); 2072b94c7e67SChad Sellers avtab_cache_destroy(); 2073b5495b42STim Gardner goto out; 2074b94c7e67SChad Sellers } 2075a2000050SEric Paris 20763bb56b25SPaul Moore security_load_policycaps(); 20771da177e4SLinus Torvalds ss_initialized = 1; 20784c443d1bSStephen Smalley seqno = ++latest_granting; 20791da177e4SLinus Torvalds selinux_complete_init(); 20804c443d1bSStephen Smalley avc_ss_reset(seqno); 20814c443d1bSStephen Smalley selnl_notify_policyload(seqno); 208211904167SKaiGai Kohei selinux_status_update_policyload(seqno); 20837420ed23SVenkat Yekkirala selinux_netlbl_cache_invalidate(); 2084342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 2085b5495b42STim Gardner goto out; 20861da177e4SLinus Torvalds } 20871da177e4SLinus Torvalds 20881da177e4SLinus Torvalds #if 0 20891da177e4SLinus Torvalds sidtab_hash_eval(&sidtab, "sids"); 20901da177e4SLinus Torvalds #endif 20911da177e4SLinus Torvalds 2092b5495b42STim Gardner rc = policydb_read(newpolicydb, fp); 2093a2000050SEric Paris if (rc) 2094b5495b42STim Gardner goto out; 20951da177e4SLinus Torvalds 2096b5495b42STim Gardner newpolicydb->len = len; 20970719aaf5SGuido Trentalancia /* If switching between different policy types, log MLS status */ 2098b5495b42STim Gardner if (policydb.mls_enabled && !newpolicydb->mls_enabled) 20990719aaf5SGuido Trentalancia printk(KERN_INFO "SELinux: Disabling MLS support...\n"); 2100b5495b42STim Gardner else if (!policydb.mls_enabled && newpolicydb->mls_enabled) 21010719aaf5SGuido Trentalancia printk(KERN_INFO "SELinux: Enabling MLS support...\n"); 21020719aaf5SGuido Trentalancia 2103b5495b42STim Gardner rc = policydb_load_isids(newpolicydb, &newsidtab); 210442596eafSGuido Trentalancia if (rc) { 210542596eafSGuido Trentalancia printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); 2106b5495b42STim Gardner policydb_destroy(newpolicydb); 2107b5495b42STim Gardner goto out; 210812b29f34SStephen Smalley } 21091da177e4SLinus Torvalds 2110b5495b42STim Gardner rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size); 2111a2000050SEric Paris if (rc) 2112b94c7e67SChad Sellers goto err; 2113b94c7e67SChad Sellers 2114b5495b42STim Gardner rc = security_preserve_bools(newpolicydb); 2115e900a7d9SStephen Smalley if (rc) { 2116454d972cSJames Morris printk(KERN_ERR "SELinux: unable to preserve booleans\n"); 2117e900a7d9SStephen Smalley goto err; 2118e900a7d9SStephen Smalley } 2119e900a7d9SStephen Smalley 21201da177e4SLinus Torvalds /* Clone the SID table. */ 21211da177e4SLinus Torvalds sidtab_shutdown(&sidtab); 2122a2000050SEric Paris 2123a2000050SEric Paris rc = sidtab_map(&sidtab, clone_sid, &newsidtab); 2124a2000050SEric Paris if (rc) 21251da177e4SLinus Torvalds goto err; 21261da177e4SLinus Torvalds 212712b29f34SStephen Smalley /* 212812b29f34SStephen Smalley * Convert the internal representations of contexts 212912b29f34SStephen Smalley * in the new SID table. 213012b29f34SStephen Smalley */ 21311da177e4SLinus Torvalds args.oldp = &policydb; 2132b5495b42STim Gardner args.newp = newpolicydb; 213312b29f34SStephen Smalley rc = sidtab_map(&newsidtab, convert_context, &args); 21340719aaf5SGuido Trentalancia if (rc) { 21350719aaf5SGuido Trentalancia printk(KERN_ERR "SELinux: unable to convert the internal" 21360719aaf5SGuido Trentalancia " representation of contexts in the new SID" 21370719aaf5SGuido Trentalancia " table\n"); 213812b29f34SStephen Smalley goto err; 21390719aaf5SGuido Trentalancia } 21401da177e4SLinus Torvalds 21411da177e4SLinus Torvalds /* Save the old policydb and SID table to free later. */ 2142b5495b42STim Gardner memcpy(oldpolicydb, &policydb, sizeof(policydb)); 21431da177e4SLinus Torvalds sidtab_set(&oldsidtab, &sidtab); 21441da177e4SLinus Torvalds 21451da177e4SLinus Torvalds /* Install the new policydb and SID table. */ 21460804d113SJames Morris write_lock_irq(&policy_rwlock); 2147b5495b42STim Gardner memcpy(&policydb, newpolicydb, sizeof(policydb)); 21481da177e4SLinus Torvalds sidtab_set(&sidtab, &newsidtab); 21493bb56b25SPaul Moore security_load_policycaps(); 2150c6d3aaa4SStephen Smalley oldmap = current_mapping; 2151c6d3aaa4SStephen Smalley current_mapping = map; 2152c6d3aaa4SStephen Smalley current_mapping_size = map_size; 21531da177e4SLinus Torvalds seqno = ++latest_granting; 21540804d113SJames Morris write_unlock_irq(&policy_rwlock); 21551da177e4SLinus Torvalds 21561da177e4SLinus Torvalds /* Free the old policydb and SID table. */ 2157b5495b42STim Gardner policydb_destroy(oldpolicydb); 21581da177e4SLinus Torvalds sidtab_destroy(&oldsidtab); 2159c6d3aaa4SStephen Smalley kfree(oldmap); 21601da177e4SLinus Torvalds 21611da177e4SLinus Torvalds avc_ss_reset(seqno); 21621da177e4SLinus Torvalds selnl_notify_policyload(seqno); 216311904167SKaiGai Kohei selinux_status_update_policyload(seqno); 21647420ed23SVenkat Yekkirala selinux_netlbl_cache_invalidate(); 2165342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 21661da177e4SLinus Torvalds 2167b5495b42STim Gardner rc = 0; 2168b5495b42STim Gardner goto out; 21691da177e4SLinus Torvalds 21701da177e4SLinus Torvalds err: 2171c6d3aaa4SStephen Smalley kfree(map); 21721da177e4SLinus Torvalds sidtab_destroy(&newsidtab); 2173b5495b42STim Gardner policydb_destroy(newpolicydb); 21741da177e4SLinus Torvalds 2175b5495b42STim Gardner out: 2176b5495b42STim Gardner kfree(oldpolicydb); 2177b5495b42STim Gardner return rc; 21781da177e4SLinus Torvalds } 21791da177e4SLinus Torvalds 2180cee74f47SEric Paris size_t security_policydb_len(void) 2181cee74f47SEric Paris { 2182cee74f47SEric Paris size_t len; 2183cee74f47SEric Paris 2184cee74f47SEric Paris read_lock(&policy_rwlock); 2185cee74f47SEric Paris len = policydb.len; 2186cee74f47SEric Paris read_unlock(&policy_rwlock); 2187cee74f47SEric Paris 2188cee74f47SEric Paris return len; 2189cee74f47SEric Paris } 2190cee74f47SEric Paris 21911da177e4SLinus Torvalds /** 21921da177e4SLinus Torvalds * security_port_sid - Obtain the SID for a port. 21931da177e4SLinus Torvalds * @protocol: protocol number 21941da177e4SLinus Torvalds * @port: port number 21951da177e4SLinus Torvalds * @out_sid: security identifier 21961da177e4SLinus Torvalds */ 21973e112172SPaul Moore int security_port_sid(u8 protocol, u16 port, u32 *out_sid) 21981da177e4SLinus Torvalds { 21991da177e4SLinus Torvalds struct ocontext *c; 22001da177e4SLinus Torvalds int rc = 0; 22011da177e4SLinus Torvalds 22020804d113SJames Morris read_lock(&policy_rwlock); 22031da177e4SLinus Torvalds 22041da177e4SLinus Torvalds c = policydb.ocontexts[OCON_PORT]; 22051da177e4SLinus Torvalds while (c) { 22061da177e4SLinus Torvalds if (c->u.port.protocol == protocol && 22071da177e4SLinus Torvalds c->u.port.low_port <= port && 22081da177e4SLinus Torvalds c->u.port.high_port >= port) 22091da177e4SLinus Torvalds break; 22101da177e4SLinus Torvalds c = c->next; 22111da177e4SLinus Torvalds } 22121da177e4SLinus Torvalds 22131da177e4SLinus Torvalds if (c) { 22141da177e4SLinus Torvalds if (!c->sid[0]) { 22151da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 22161da177e4SLinus Torvalds &c->context[0], 22171da177e4SLinus Torvalds &c->sid[0]); 22181da177e4SLinus Torvalds if (rc) 22191da177e4SLinus Torvalds goto out; 22201da177e4SLinus Torvalds } 22211da177e4SLinus Torvalds *out_sid = c->sid[0]; 22221da177e4SLinus Torvalds } else { 22231da177e4SLinus Torvalds *out_sid = SECINITSID_PORT; 22241da177e4SLinus Torvalds } 22251da177e4SLinus Torvalds 22261da177e4SLinus Torvalds out: 22270804d113SJames Morris read_unlock(&policy_rwlock); 22281da177e4SLinus Torvalds return rc; 22291da177e4SLinus Torvalds } 22301da177e4SLinus Torvalds 22311da177e4SLinus Torvalds /** 22321da177e4SLinus Torvalds * security_netif_sid - Obtain the SID for a network interface. 22331da177e4SLinus Torvalds * @name: interface name 22341da177e4SLinus Torvalds * @if_sid: interface SID 22351da177e4SLinus Torvalds */ 2236e8bfdb9dSPaul Moore int security_netif_sid(char *name, u32 *if_sid) 22371da177e4SLinus Torvalds { 22381da177e4SLinus Torvalds int rc = 0; 22391da177e4SLinus Torvalds struct ocontext *c; 22401da177e4SLinus Torvalds 22410804d113SJames Morris read_lock(&policy_rwlock); 22421da177e4SLinus Torvalds 22431da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NETIF]; 22441da177e4SLinus Torvalds while (c) { 22451da177e4SLinus Torvalds if (strcmp(name, c->u.name) == 0) 22461da177e4SLinus Torvalds break; 22471da177e4SLinus Torvalds c = c->next; 22481da177e4SLinus Torvalds } 22491da177e4SLinus Torvalds 22501da177e4SLinus Torvalds if (c) { 22511da177e4SLinus Torvalds if (!c->sid[0] || !c->sid[1]) { 22521da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 22531da177e4SLinus Torvalds &c->context[0], 22541da177e4SLinus Torvalds &c->sid[0]); 22551da177e4SLinus Torvalds if (rc) 22561da177e4SLinus Torvalds goto out; 22571da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 22581da177e4SLinus Torvalds &c->context[1], 22591da177e4SLinus Torvalds &c->sid[1]); 22601da177e4SLinus Torvalds if (rc) 22611da177e4SLinus Torvalds goto out; 22621da177e4SLinus Torvalds } 22631da177e4SLinus Torvalds *if_sid = c->sid[0]; 2264e8bfdb9dSPaul Moore } else 22651da177e4SLinus Torvalds *if_sid = SECINITSID_NETIF; 22661da177e4SLinus Torvalds 22671da177e4SLinus Torvalds out: 22680804d113SJames Morris read_unlock(&policy_rwlock); 22691da177e4SLinus Torvalds return rc; 22701da177e4SLinus Torvalds } 22711da177e4SLinus Torvalds 22721da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) 22731da177e4SLinus Torvalds { 22741da177e4SLinus Torvalds int i, fail = 0; 22751da177e4SLinus Torvalds 22761da177e4SLinus Torvalds for (i = 0; i < 4; i++) 22771da177e4SLinus Torvalds if (addr[i] != (input[i] & mask[i])) { 22781da177e4SLinus Torvalds fail = 1; 22791da177e4SLinus Torvalds break; 22801da177e4SLinus Torvalds } 22811da177e4SLinus Torvalds 22821da177e4SLinus Torvalds return !fail; 22831da177e4SLinus Torvalds } 22841da177e4SLinus Torvalds 22851da177e4SLinus Torvalds /** 22861da177e4SLinus Torvalds * security_node_sid - Obtain the SID for a node (host). 22871da177e4SLinus Torvalds * @domain: communication domain aka address family 22881da177e4SLinus Torvalds * @addrp: address 22891da177e4SLinus Torvalds * @addrlen: address length in bytes 22901da177e4SLinus Torvalds * @out_sid: security identifier 22911da177e4SLinus Torvalds */ 22921da177e4SLinus Torvalds int security_node_sid(u16 domain, 22931da177e4SLinus Torvalds void *addrp, 22941da177e4SLinus Torvalds u32 addrlen, 22951da177e4SLinus Torvalds u32 *out_sid) 22961da177e4SLinus Torvalds { 22974b02b524SEric Paris int rc; 22981da177e4SLinus Torvalds struct ocontext *c; 22991da177e4SLinus Torvalds 23000804d113SJames Morris read_lock(&policy_rwlock); 23011da177e4SLinus Torvalds 23021da177e4SLinus Torvalds switch (domain) { 23031da177e4SLinus Torvalds case AF_INET: { 23041da177e4SLinus Torvalds u32 addr; 23051da177e4SLinus Torvalds 23061da177e4SLinus Torvalds rc = -EINVAL; 23074b02b524SEric Paris if (addrlen != sizeof(u32)) 23081da177e4SLinus Torvalds goto out; 23091da177e4SLinus Torvalds 23101da177e4SLinus Torvalds addr = *((u32 *)addrp); 23111da177e4SLinus Torvalds 23121da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NODE]; 23131da177e4SLinus Torvalds while (c) { 23141da177e4SLinus Torvalds if (c->u.node.addr == (addr & c->u.node.mask)) 23151da177e4SLinus Torvalds break; 23161da177e4SLinus Torvalds c = c->next; 23171da177e4SLinus Torvalds } 23181da177e4SLinus Torvalds break; 23191da177e4SLinus Torvalds } 23201da177e4SLinus Torvalds 23211da177e4SLinus Torvalds case AF_INET6: 23221da177e4SLinus Torvalds rc = -EINVAL; 23234b02b524SEric Paris if (addrlen != sizeof(u64) * 2) 23241da177e4SLinus Torvalds goto out; 23251da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NODE6]; 23261da177e4SLinus Torvalds while (c) { 23271da177e4SLinus Torvalds if (match_ipv6_addrmask(addrp, c->u.node6.addr, 23281da177e4SLinus Torvalds c->u.node6.mask)) 23291da177e4SLinus Torvalds break; 23301da177e4SLinus Torvalds c = c->next; 23311da177e4SLinus Torvalds } 23321da177e4SLinus Torvalds break; 23331da177e4SLinus Torvalds 23341da177e4SLinus Torvalds default: 23354b02b524SEric Paris rc = 0; 23361da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 23371da177e4SLinus Torvalds goto out; 23381da177e4SLinus Torvalds } 23391da177e4SLinus Torvalds 23401da177e4SLinus Torvalds if (c) { 23411da177e4SLinus Torvalds if (!c->sid[0]) { 23421da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 23431da177e4SLinus Torvalds &c->context[0], 23441da177e4SLinus Torvalds &c->sid[0]); 23451da177e4SLinus Torvalds if (rc) 23461da177e4SLinus Torvalds goto out; 23471da177e4SLinus Torvalds } 23481da177e4SLinus Torvalds *out_sid = c->sid[0]; 23491da177e4SLinus Torvalds } else { 23501da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 23511da177e4SLinus Torvalds } 23521da177e4SLinus Torvalds 23534b02b524SEric Paris rc = 0; 23541da177e4SLinus Torvalds out: 23550804d113SJames Morris read_unlock(&policy_rwlock); 23561da177e4SLinus Torvalds return rc; 23571da177e4SLinus Torvalds } 23581da177e4SLinus Torvalds 23591da177e4SLinus Torvalds #define SIDS_NEL 25 23601da177e4SLinus Torvalds 23611da177e4SLinus Torvalds /** 23621da177e4SLinus Torvalds * security_get_user_sids - Obtain reachable SIDs for a user. 23631da177e4SLinus Torvalds * @fromsid: starting SID 23641da177e4SLinus Torvalds * @username: username 23651da177e4SLinus Torvalds * @sids: array of reachable SIDs for user 23661da177e4SLinus Torvalds * @nel: number of elements in @sids 23671da177e4SLinus Torvalds * 23681da177e4SLinus Torvalds * Generate the set of SIDs for legal security contexts 23691da177e4SLinus Torvalds * for a given user that can be reached by @fromsid. 23701da177e4SLinus Torvalds * Set *@sids to point to a dynamically allocated 23711da177e4SLinus Torvalds * array containing the set of SIDs. Set *@nel to the 23721da177e4SLinus Torvalds * number of elements in the array. 23731da177e4SLinus Torvalds */ 23741da177e4SLinus Torvalds 23751da177e4SLinus Torvalds int security_get_user_sids(u32 fromsid, 23761da177e4SLinus Torvalds char *username, 23771da177e4SLinus Torvalds u32 **sids, 23781da177e4SLinus Torvalds u32 *nel) 23791da177e4SLinus Torvalds { 23801da177e4SLinus Torvalds struct context *fromcon, usercon; 23812c3c05dbSStephen Smalley u32 *mysids = NULL, *mysids2, sid; 23821da177e4SLinus Torvalds u32 mynel = 0, maxnel = SIDS_NEL; 23831da177e4SLinus Torvalds struct user_datum *user; 23841da177e4SLinus Torvalds struct role_datum *role; 2385782ebb99SStephen Smalley struct ebitmap_node *rnode, *tnode; 23861da177e4SLinus Torvalds int rc = 0, i, j; 23871da177e4SLinus Torvalds 23881da177e4SLinus Torvalds *sids = NULL; 23891da177e4SLinus Torvalds *nel = 0; 23902c3c05dbSStephen Smalley 23912c3c05dbSStephen Smalley if (!ss_initialized) 23921da177e4SLinus Torvalds goto out; 23931da177e4SLinus Torvalds 23940804d113SJames Morris read_lock(&policy_rwlock); 23951da177e4SLinus Torvalds 239612b29f34SStephen Smalley context_init(&usercon); 239712b29f34SStephen Smalley 23984b02b524SEric Paris rc = -EINVAL; 23991da177e4SLinus Torvalds fromcon = sidtab_search(&sidtab, fromsid); 24004b02b524SEric Paris if (!fromcon) 24011da177e4SLinus Torvalds goto out_unlock; 24021da177e4SLinus Torvalds 24031da177e4SLinus Torvalds rc = -EINVAL; 24044b02b524SEric Paris user = hashtab_search(policydb.p_users.table, username); 24054b02b524SEric Paris if (!user) 24061da177e4SLinus Torvalds goto out_unlock; 24074b02b524SEric Paris 24081da177e4SLinus Torvalds usercon.user = user->value; 24091da177e4SLinus Torvalds 24101da177e4SLinus Torvalds rc = -ENOMEM; 24114b02b524SEric Paris mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC); 24124b02b524SEric Paris if (!mysids) 24131da177e4SLinus Torvalds goto out_unlock; 24141da177e4SLinus Torvalds 24159fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&user->roles, rnode, i) { 24161da177e4SLinus Torvalds role = policydb.role_val_to_struct[i]; 24171da177e4SLinus Torvalds usercon.role = i + 1; 24189fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&role->types, tnode, j) { 24191da177e4SLinus Torvalds usercon.type = j + 1; 24201da177e4SLinus Torvalds 24211da177e4SLinus Torvalds if (mls_setup_user_range(fromcon, user, &usercon)) 24221da177e4SLinus Torvalds continue; 24231da177e4SLinus Torvalds 24241da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); 24252c3c05dbSStephen Smalley if (rc) 24261da177e4SLinus Torvalds goto out_unlock; 24271da177e4SLinus Torvalds if (mynel < maxnel) { 24281da177e4SLinus Torvalds mysids[mynel++] = sid; 24291da177e4SLinus Torvalds } else { 24304b02b524SEric Paris rc = -ENOMEM; 24311da177e4SLinus Torvalds maxnel += SIDS_NEL; 243289d155efSJames Morris mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); 24334b02b524SEric Paris if (!mysids2) 24341da177e4SLinus Torvalds goto out_unlock; 24351da177e4SLinus Torvalds memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); 24361da177e4SLinus Torvalds kfree(mysids); 24371da177e4SLinus Torvalds mysids = mysids2; 24381da177e4SLinus Torvalds mysids[mynel++] = sid; 24391da177e4SLinus Torvalds } 24401da177e4SLinus Torvalds } 24411da177e4SLinus Torvalds } 24424b02b524SEric Paris rc = 0; 24431da177e4SLinus Torvalds out_unlock: 24440804d113SJames Morris read_unlock(&policy_rwlock); 24452c3c05dbSStephen Smalley if (rc || !mynel) { 24462c3c05dbSStephen Smalley kfree(mysids); 24472c3c05dbSStephen Smalley goto out; 24482c3c05dbSStephen Smalley } 24492c3c05dbSStephen Smalley 24504b02b524SEric Paris rc = -ENOMEM; 24512c3c05dbSStephen Smalley mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL); 24522c3c05dbSStephen Smalley if (!mysids2) { 24532c3c05dbSStephen Smalley kfree(mysids); 24542c3c05dbSStephen Smalley goto out; 24552c3c05dbSStephen Smalley } 24562c3c05dbSStephen Smalley for (i = 0, j = 0; i < mynel; i++) { 2457f01e1af4SLinus Torvalds struct av_decision dummy_avd; 24582c3c05dbSStephen Smalley rc = avc_has_perm_noaudit(fromsid, mysids[i], 2459c6d3aaa4SStephen Smalley SECCLASS_PROCESS, /* kernel value */ 24602c3c05dbSStephen Smalley PROCESS__TRANSITION, AVC_STRICT, 2461f01e1af4SLinus Torvalds &dummy_avd); 24622c3c05dbSStephen Smalley if (!rc) 24632c3c05dbSStephen Smalley mysids2[j++] = mysids[i]; 24642c3c05dbSStephen Smalley cond_resched(); 24652c3c05dbSStephen Smalley } 24662c3c05dbSStephen Smalley rc = 0; 24672c3c05dbSStephen Smalley kfree(mysids); 24682c3c05dbSStephen Smalley *sids = mysids2; 24692c3c05dbSStephen Smalley *nel = j; 24701da177e4SLinus Torvalds out: 24711da177e4SLinus Torvalds return rc; 24721da177e4SLinus Torvalds } 24731da177e4SLinus Torvalds 24741da177e4SLinus Torvalds /** 2475f31e7994SWaiman Long * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem 24761da177e4SLinus Torvalds * @fstype: filesystem type 24771da177e4SLinus Torvalds * @path: path from root of mount 24781da177e4SLinus Torvalds * @sclass: file security class 24791da177e4SLinus Torvalds * @sid: SID for path 24801da177e4SLinus Torvalds * 24811da177e4SLinus Torvalds * Obtain a SID to use for a file in a filesystem that 24821da177e4SLinus Torvalds * cannot support xattr or use a fixed labeling behavior like 24831da177e4SLinus Torvalds * transition SIDs or task SIDs. 2484f31e7994SWaiman Long * 2485f31e7994SWaiman Long * The caller must acquire the policy_rwlock before calling this function. 24861da177e4SLinus Torvalds */ 2487f31e7994SWaiman Long static inline int __security_genfs_sid(const char *fstype, 24881da177e4SLinus Torvalds char *path, 2489c6d3aaa4SStephen Smalley u16 orig_sclass, 24901da177e4SLinus Torvalds u32 *sid) 24911da177e4SLinus Torvalds { 24921da177e4SLinus Torvalds int len; 2493c6d3aaa4SStephen Smalley u16 sclass; 24941da177e4SLinus Torvalds struct genfs *genfs; 24951da177e4SLinus Torvalds struct ocontext *c; 24964b02b524SEric Paris int rc, cmp = 0; 24971da177e4SLinus Torvalds 2498b1aa5301SStephen Smalley while (path[0] == '/' && path[1] == '/') 2499b1aa5301SStephen Smalley path++; 2500b1aa5301SStephen Smalley 2501c6d3aaa4SStephen Smalley sclass = unmap_class(orig_sclass); 25024b02b524SEric Paris *sid = SECINITSID_UNLABELED; 2503c6d3aaa4SStephen Smalley 25041da177e4SLinus Torvalds for (genfs = policydb.genfs; genfs; genfs = genfs->next) { 25051da177e4SLinus Torvalds cmp = strcmp(fstype, genfs->fstype); 25061da177e4SLinus Torvalds if (cmp <= 0) 25071da177e4SLinus Torvalds break; 25081da177e4SLinus Torvalds } 25091da177e4SLinus Torvalds 25101da177e4SLinus Torvalds rc = -ENOENT; 25114b02b524SEric Paris if (!genfs || cmp) 25121da177e4SLinus Torvalds goto out; 25131da177e4SLinus Torvalds 25141da177e4SLinus Torvalds for (c = genfs->head; c; c = c->next) { 25151da177e4SLinus Torvalds len = strlen(c->u.name); 25161da177e4SLinus Torvalds if ((!c->v.sclass || sclass == c->v.sclass) && 25171da177e4SLinus Torvalds (strncmp(c->u.name, path, len) == 0)) 25181da177e4SLinus Torvalds break; 25191da177e4SLinus Torvalds } 25201da177e4SLinus Torvalds 25211da177e4SLinus Torvalds rc = -ENOENT; 25224b02b524SEric Paris if (!c) 25231da177e4SLinus Torvalds goto out; 25241da177e4SLinus Torvalds 25251da177e4SLinus Torvalds if (!c->sid[0]) { 25264b02b524SEric Paris rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]); 25271da177e4SLinus Torvalds if (rc) 25281da177e4SLinus Torvalds goto out; 25291da177e4SLinus Torvalds } 25301da177e4SLinus Torvalds 25311da177e4SLinus Torvalds *sid = c->sid[0]; 25324b02b524SEric Paris rc = 0; 25331da177e4SLinus Torvalds out: 25341da177e4SLinus Torvalds return rc; 25351da177e4SLinus Torvalds } 25361da177e4SLinus Torvalds 25371da177e4SLinus Torvalds /** 2538f31e7994SWaiman Long * security_genfs_sid - Obtain a SID for a file in a filesystem 2539f31e7994SWaiman Long * @fstype: filesystem type 2540f31e7994SWaiman Long * @path: path from root of mount 2541f31e7994SWaiman Long * @sclass: file security class 2542f31e7994SWaiman Long * @sid: SID for path 2543f31e7994SWaiman Long * 2544f31e7994SWaiman Long * Acquire policy_rwlock before calling __security_genfs_sid() and release 2545f31e7994SWaiman Long * it afterward. 2546f31e7994SWaiman Long */ 2547f31e7994SWaiman Long int security_genfs_sid(const char *fstype, 2548f31e7994SWaiman Long char *path, 2549f31e7994SWaiman Long u16 orig_sclass, 2550f31e7994SWaiman Long u32 *sid) 2551f31e7994SWaiman Long { 2552f31e7994SWaiman Long int retval; 2553f31e7994SWaiman Long 2554f31e7994SWaiman Long read_lock(&policy_rwlock); 2555f31e7994SWaiman Long retval = __security_genfs_sid(fstype, path, orig_sclass, sid); 2556f31e7994SWaiman Long read_unlock(&policy_rwlock); 2557f31e7994SWaiman Long return retval; 2558f31e7994SWaiman Long } 2559f31e7994SWaiman Long 2560f31e7994SWaiman Long /** 25611da177e4SLinus Torvalds * security_fs_use - Determine how to handle labeling for a filesystem. 2562a64c54cfSEric Paris * @sb: superblock in question 25631da177e4SLinus Torvalds */ 2564a64c54cfSEric Paris int security_fs_use(struct super_block *sb) 25651da177e4SLinus Torvalds { 25661da177e4SLinus Torvalds int rc = 0; 25671da177e4SLinus Torvalds struct ocontext *c; 2568a64c54cfSEric Paris struct superblock_security_struct *sbsec = sb->s_security; 2569a64c54cfSEric Paris const char *fstype = sb->s_type->name; 25701da177e4SLinus Torvalds 25710804d113SJames Morris read_lock(&policy_rwlock); 25721da177e4SLinus Torvalds 25734d546f81SPaul Moore c = policydb.ocontexts[OCON_FSUSE]; 25744d546f81SPaul Moore while (c) { 25754d546f81SPaul Moore if (strcmp(fstype, c->u.name) == 0) 25761da177e4SLinus Torvalds break; 25774d546f81SPaul Moore c = c->next; 25781da177e4SLinus Torvalds } 25791da177e4SLinus Torvalds 25801da177e4SLinus Torvalds if (c) { 2581a64c54cfSEric Paris sbsec->behavior = c->v.behavior; 25821da177e4SLinus Torvalds if (!c->sid[0]) { 25834b02b524SEric Paris rc = sidtab_context_to_sid(&sidtab, &c->context[0], 25841da177e4SLinus Torvalds &c->sid[0]); 25851da177e4SLinus Torvalds if (rc) 25861da177e4SLinus Torvalds goto out; 25871da177e4SLinus Torvalds } 2588a64c54cfSEric Paris sbsec->sid = c->sid[0]; 2589089be43eSJames Morris } else { 2590f31e7994SWaiman Long rc = __security_genfs_sid(fstype, "/", SECCLASS_DIR, 2591f31e7994SWaiman Long &sbsec->sid); 25921da177e4SLinus Torvalds if (rc) { 2593a64c54cfSEric Paris sbsec->behavior = SECURITY_FS_USE_NONE; 25941da177e4SLinus Torvalds rc = 0; 25951da177e4SLinus Torvalds } else { 2596a64c54cfSEric Paris sbsec->behavior = SECURITY_FS_USE_GENFS; 25971da177e4SLinus Torvalds } 2598089be43eSJames Morris } 25991da177e4SLinus Torvalds 26001da177e4SLinus Torvalds out: 26010804d113SJames Morris read_unlock(&policy_rwlock); 26021da177e4SLinus Torvalds return rc; 26031da177e4SLinus Torvalds } 26041da177e4SLinus Torvalds 26051da177e4SLinus Torvalds int security_get_bools(int *len, char ***names, int **values) 26061da177e4SLinus Torvalds { 26074b02b524SEric Paris int i, rc; 26081da177e4SLinus Torvalds 26090804d113SJames Morris read_lock(&policy_rwlock); 26101da177e4SLinus Torvalds *names = NULL; 26111da177e4SLinus Torvalds *values = NULL; 26121da177e4SLinus Torvalds 26131da177e4SLinus Torvalds rc = 0; 26144b02b524SEric Paris *len = policydb.p_bools.nprim; 26154b02b524SEric Paris if (!*len) 26161da177e4SLinus Torvalds goto out; 26171da177e4SLinus Torvalds 26184b02b524SEric Paris rc = -ENOMEM; 2619e0795cf4SJesper Juhl *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); 26201da177e4SLinus Torvalds if (!*names) 26211da177e4SLinus Torvalds goto err; 26221da177e4SLinus Torvalds 26234b02b524SEric Paris rc = -ENOMEM; 2624e0795cf4SJesper Juhl *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); 26251da177e4SLinus Torvalds if (!*values) 26261da177e4SLinus Torvalds goto err; 26271da177e4SLinus Torvalds 26281da177e4SLinus Torvalds for (i = 0; i < *len; i++) { 26291da177e4SLinus Torvalds (*values)[i] = policydb.bool_val_to_struct[i]->state; 26304b02b524SEric Paris 26314b02b524SEric Paris rc = -ENOMEM; 263221b76f19SRasmus Villemoes (*names)[i] = kstrdup(sym_name(&policydb, SYM_BOOLS, i), GFP_ATOMIC); 26331da177e4SLinus Torvalds if (!(*names)[i]) 26341da177e4SLinus Torvalds goto err; 26351da177e4SLinus Torvalds } 26361da177e4SLinus Torvalds rc = 0; 26371da177e4SLinus Torvalds out: 26380804d113SJames Morris read_unlock(&policy_rwlock); 26391da177e4SLinus Torvalds return rc; 26401da177e4SLinus Torvalds err: 26411da177e4SLinus Torvalds if (*names) { 26421da177e4SLinus Torvalds for (i = 0; i < *len; i++) 26431da177e4SLinus Torvalds kfree((*names)[i]); 26441da177e4SLinus Torvalds } 26451da177e4SLinus Torvalds kfree(*values); 26461da177e4SLinus Torvalds goto out; 26471da177e4SLinus Torvalds } 26481da177e4SLinus Torvalds 26491da177e4SLinus Torvalds 26501da177e4SLinus Torvalds int security_set_bools(int len, int *values) 26511da177e4SLinus Torvalds { 26524b02b524SEric Paris int i, rc; 26531da177e4SLinus Torvalds int lenp, seqno = 0; 26541da177e4SLinus Torvalds struct cond_node *cur; 26551da177e4SLinus Torvalds 26560804d113SJames Morris write_lock_irq(&policy_rwlock); 26571da177e4SLinus Torvalds 26581da177e4SLinus Torvalds rc = -EFAULT; 26594b02b524SEric Paris lenp = policydb.p_bools.nprim; 26604b02b524SEric Paris if (len != lenp) 26611da177e4SLinus Torvalds goto out; 26621da177e4SLinus Torvalds 26631da177e4SLinus Torvalds for (i = 0; i < len; i++) { 2664af601e46SSteve Grubb if (!!values[i] != policydb.bool_val_to_struct[i]->state) { 2665af601e46SSteve Grubb audit_log(current->audit_context, GFP_ATOMIC, 2666af601e46SSteve Grubb AUDIT_MAC_CONFIG_CHANGE, 26674746ec5bSEric Paris "bool=%s val=%d old_val=%d auid=%u ses=%u", 2668ac76c05bSEric Paris sym_name(&policydb, SYM_BOOLS, i), 2669af601e46SSteve Grubb !!values[i], 2670af601e46SSteve Grubb policydb.bool_val_to_struct[i]->state, 2671581abc09SEric W. Biederman from_kuid(&init_user_ns, audit_get_loginuid(current)), 26724746ec5bSEric Paris audit_get_sessionid(current)); 2673af601e46SSteve Grubb } 26745d55a345SEric Paris if (values[i]) 26751da177e4SLinus Torvalds policydb.bool_val_to_struct[i]->state = 1; 26765d55a345SEric Paris else 26771da177e4SLinus Torvalds policydb.bool_val_to_struct[i]->state = 0; 26781da177e4SLinus Torvalds } 26791da177e4SLinus Torvalds 2680dbc74c65SVesa-Matti Kari for (cur = policydb.cond_list; cur; cur = cur->next) { 26811da177e4SLinus Torvalds rc = evaluate_cond_node(&policydb, cur); 26821da177e4SLinus Torvalds if (rc) 26831da177e4SLinus Torvalds goto out; 26841da177e4SLinus Torvalds } 26851da177e4SLinus Torvalds 26861da177e4SLinus Torvalds seqno = ++latest_granting; 26874b02b524SEric Paris rc = 0; 26881da177e4SLinus Torvalds out: 26890804d113SJames Morris write_unlock_irq(&policy_rwlock); 26901da177e4SLinus Torvalds if (!rc) { 26911da177e4SLinus Torvalds avc_ss_reset(seqno); 26921da177e4SLinus Torvalds selnl_notify_policyload(seqno); 269311904167SKaiGai Kohei selinux_status_update_policyload(seqno); 2694342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 26951da177e4SLinus Torvalds } 26961da177e4SLinus Torvalds return rc; 26971da177e4SLinus Torvalds } 26981da177e4SLinus Torvalds 26990fd71a62SPrarit Bhargava int security_get_bool_value(int index) 27001da177e4SLinus Torvalds { 27014b02b524SEric Paris int rc; 27021da177e4SLinus Torvalds int len; 27031da177e4SLinus Torvalds 27040804d113SJames Morris read_lock(&policy_rwlock); 27051da177e4SLinus Torvalds 27061da177e4SLinus Torvalds rc = -EFAULT; 27074b02b524SEric Paris len = policydb.p_bools.nprim; 27080fd71a62SPrarit Bhargava if (index >= len) 27091da177e4SLinus Torvalds goto out; 27101da177e4SLinus Torvalds 27110fd71a62SPrarit Bhargava rc = policydb.bool_val_to_struct[index]->state; 27121da177e4SLinus Torvalds out: 27130804d113SJames Morris read_unlock(&policy_rwlock); 27141da177e4SLinus Torvalds return rc; 27151da177e4SLinus Torvalds } 2716376bd9cbSDarrel Goeddel 2717e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p) 2718e900a7d9SStephen Smalley { 2719e900a7d9SStephen Smalley int rc, nbools = 0, *bvalues = NULL, i; 2720e900a7d9SStephen Smalley char **bnames = NULL; 2721e900a7d9SStephen Smalley struct cond_bool_datum *booldatum; 2722e900a7d9SStephen Smalley struct cond_node *cur; 2723e900a7d9SStephen Smalley 2724e900a7d9SStephen Smalley rc = security_get_bools(&nbools, &bnames, &bvalues); 2725e900a7d9SStephen Smalley if (rc) 2726e900a7d9SStephen Smalley goto out; 2727e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) { 2728e900a7d9SStephen Smalley booldatum = hashtab_search(p->p_bools.table, bnames[i]); 2729e900a7d9SStephen Smalley if (booldatum) 2730e900a7d9SStephen Smalley booldatum->state = bvalues[i]; 2731e900a7d9SStephen Smalley } 2732dbc74c65SVesa-Matti Kari for (cur = p->cond_list; cur; cur = cur->next) { 2733e900a7d9SStephen Smalley rc = evaluate_cond_node(p, cur); 2734e900a7d9SStephen Smalley if (rc) 2735e900a7d9SStephen Smalley goto out; 2736e900a7d9SStephen Smalley } 2737e900a7d9SStephen Smalley 2738e900a7d9SStephen Smalley out: 2739e900a7d9SStephen Smalley if (bnames) { 2740e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) 2741e900a7d9SStephen Smalley kfree(bnames[i]); 2742e900a7d9SStephen Smalley } 2743e900a7d9SStephen Smalley kfree(bnames); 2744e900a7d9SStephen Smalley kfree(bvalues); 2745e900a7d9SStephen Smalley return rc; 2746e900a7d9SStephen Smalley } 2747e900a7d9SStephen Smalley 274808554d6bSVenkat Yekkirala /* 274908554d6bSVenkat Yekkirala * security_sid_mls_copy() - computes a new sid based on the given 275008554d6bSVenkat Yekkirala * sid and the mls portion of mls_sid. 275108554d6bSVenkat Yekkirala */ 275208554d6bSVenkat Yekkirala int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) 275308554d6bSVenkat Yekkirala { 275408554d6bSVenkat Yekkirala struct context *context1; 275508554d6bSVenkat Yekkirala struct context *context2; 275608554d6bSVenkat Yekkirala struct context newcon; 275708554d6bSVenkat Yekkirala char *s; 275808554d6bSVenkat Yekkirala u32 len; 27594b02b524SEric Paris int rc; 276008554d6bSVenkat Yekkirala 27614b02b524SEric Paris rc = 0; 27620719aaf5SGuido Trentalancia if (!ss_initialized || !policydb.mls_enabled) { 276308554d6bSVenkat Yekkirala *new_sid = sid; 276408554d6bSVenkat Yekkirala goto out; 276508554d6bSVenkat Yekkirala } 276608554d6bSVenkat Yekkirala 276708554d6bSVenkat Yekkirala context_init(&newcon); 276808554d6bSVenkat Yekkirala 27690804d113SJames Morris read_lock(&policy_rwlock); 27704b02b524SEric Paris 27714b02b524SEric Paris rc = -EINVAL; 277208554d6bSVenkat Yekkirala context1 = sidtab_search(&sidtab, sid); 277308554d6bSVenkat Yekkirala if (!context1) { 2774744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2775744ba35eSEric Paris __func__, sid); 277608554d6bSVenkat Yekkirala goto out_unlock; 277708554d6bSVenkat Yekkirala } 277808554d6bSVenkat Yekkirala 27794b02b524SEric Paris rc = -EINVAL; 278008554d6bSVenkat Yekkirala context2 = sidtab_search(&sidtab, mls_sid); 278108554d6bSVenkat Yekkirala if (!context2) { 2782744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2783744ba35eSEric Paris __func__, mls_sid); 278408554d6bSVenkat Yekkirala goto out_unlock; 278508554d6bSVenkat Yekkirala } 278608554d6bSVenkat Yekkirala 278708554d6bSVenkat Yekkirala newcon.user = context1->user; 278808554d6bSVenkat Yekkirala newcon.role = context1->role; 278908554d6bSVenkat Yekkirala newcon.type = context1->type; 27900efc61eaSVenkat Yekkirala rc = mls_context_cpy(&newcon, context2); 279108554d6bSVenkat Yekkirala if (rc) 279208554d6bSVenkat Yekkirala goto out_unlock; 279308554d6bSVenkat Yekkirala 279408554d6bSVenkat Yekkirala /* Check the validity of the new context. */ 279508554d6bSVenkat Yekkirala if (!policydb_context_isvalid(&policydb, &newcon)) { 279608554d6bSVenkat Yekkirala rc = convert_context_handle_invalid_context(&newcon); 27974b02b524SEric Paris if (rc) { 279808554d6bSVenkat Yekkirala if (!context_struct_to_string(&newcon, &s, &len)) { 27994093a844SRichard Guy Briggs audit_log(current->audit_context, 28004093a844SRichard Guy Briggs GFP_ATOMIC, AUDIT_SELINUX_ERR, 28014093a844SRichard Guy Briggs "op=security_sid_mls_copy " 28024093a844SRichard Guy Briggs "invalid_context=%s", s); 280308554d6bSVenkat Yekkirala kfree(s); 280408554d6bSVenkat Yekkirala } 28054b02b524SEric Paris goto out_unlock; 28064b02b524SEric Paris } 28074b02b524SEric Paris } 280808554d6bSVenkat Yekkirala 28094b02b524SEric Paris rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid); 281008554d6bSVenkat Yekkirala out_unlock: 28110804d113SJames Morris read_unlock(&policy_rwlock); 281208554d6bSVenkat Yekkirala context_destroy(&newcon); 281308554d6bSVenkat Yekkirala out: 281408554d6bSVenkat Yekkirala return rc; 281508554d6bSVenkat Yekkirala } 281608554d6bSVenkat Yekkirala 2817220deb96SPaul Moore /** 2818220deb96SPaul Moore * security_net_peersid_resolve - Compare and resolve two network peer SIDs 2819220deb96SPaul Moore * @nlbl_sid: NetLabel SID 2820220deb96SPaul Moore * @nlbl_type: NetLabel labeling protocol type 2821220deb96SPaul Moore * @xfrm_sid: XFRM SID 2822220deb96SPaul Moore * 2823220deb96SPaul Moore * Description: 2824220deb96SPaul Moore * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be 2825220deb96SPaul Moore * resolved into a single SID it is returned via @peer_sid and the function 2826220deb96SPaul Moore * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function 2827220deb96SPaul Moore * returns a negative value. A table summarizing the behavior is below: 2828220deb96SPaul Moore * 2829220deb96SPaul Moore * | function return | @sid 2830220deb96SPaul Moore * ------------------------------+-----------------+----------------- 2831220deb96SPaul Moore * no peer labels | 0 | SECSID_NULL 2832220deb96SPaul Moore * single peer label | 0 | <peer_label> 2833220deb96SPaul Moore * multiple, consistent labels | 0 | <peer_label> 2834220deb96SPaul Moore * multiple, inconsistent labels | -<errno> | SECSID_NULL 2835220deb96SPaul Moore * 2836220deb96SPaul Moore */ 2837220deb96SPaul Moore int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, 2838220deb96SPaul Moore u32 xfrm_sid, 2839220deb96SPaul Moore u32 *peer_sid) 2840220deb96SPaul Moore { 2841220deb96SPaul Moore int rc; 2842220deb96SPaul Moore struct context *nlbl_ctx; 2843220deb96SPaul Moore struct context *xfrm_ctx; 2844220deb96SPaul Moore 28454b02b524SEric Paris *peer_sid = SECSID_NULL; 28464b02b524SEric Paris 2847220deb96SPaul Moore /* handle the common (which also happens to be the set of easy) cases 2848220deb96SPaul Moore * right away, these two if statements catch everything involving a 2849220deb96SPaul Moore * single or absent peer SID/label */ 2850220deb96SPaul Moore if (xfrm_sid == SECSID_NULL) { 2851220deb96SPaul Moore *peer_sid = nlbl_sid; 2852220deb96SPaul Moore return 0; 2853220deb96SPaul Moore } 2854220deb96SPaul Moore /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label 2855220deb96SPaul Moore * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label 2856220deb96SPaul Moore * is present */ 2857220deb96SPaul Moore if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) { 2858220deb96SPaul Moore *peer_sid = xfrm_sid; 2859220deb96SPaul Moore return 0; 2860220deb96SPaul Moore } 2861220deb96SPaul Moore 2862220deb96SPaul Moore /* we don't need to check ss_initialized here since the only way both 2863220deb96SPaul Moore * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the 2864220deb96SPaul Moore * security server was initialized and ss_initialized was true */ 28654b02b524SEric Paris if (!policydb.mls_enabled) 2866220deb96SPaul Moore return 0; 2867220deb96SPaul Moore 28680804d113SJames Morris read_lock(&policy_rwlock); 2869220deb96SPaul Moore 28704b02b524SEric Paris rc = -EINVAL; 2871220deb96SPaul Moore nlbl_ctx = sidtab_search(&sidtab, nlbl_sid); 2872220deb96SPaul Moore if (!nlbl_ctx) { 2873744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2874744ba35eSEric Paris __func__, nlbl_sid); 28754b02b524SEric Paris goto out; 2876220deb96SPaul Moore } 28774b02b524SEric Paris rc = -EINVAL; 2878220deb96SPaul Moore xfrm_ctx = sidtab_search(&sidtab, xfrm_sid); 2879220deb96SPaul Moore if (!xfrm_ctx) { 2880744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2881744ba35eSEric Paris __func__, xfrm_sid); 28824b02b524SEric Paris goto out; 2883220deb96SPaul Moore } 2884220deb96SPaul Moore rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); 28854b02b524SEric Paris if (rc) 28864b02b524SEric Paris goto out; 2887220deb96SPaul Moore 2888220deb96SPaul Moore /* at present NetLabel SIDs/labels really only carry MLS 2889220deb96SPaul Moore * information so if the MLS portion of the NetLabel SID 2890220deb96SPaul Moore * matches the MLS portion of the labeled XFRM SID/label 2891220deb96SPaul Moore * then pass along the XFRM SID as it is the most 2892220deb96SPaul Moore * expressive */ 2893220deb96SPaul Moore *peer_sid = xfrm_sid; 28944b02b524SEric Paris out: 28954b02b524SEric Paris read_unlock(&policy_rwlock); 2896220deb96SPaul Moore return rc; 2897220deb96SPaul Moore } 2898220deb96SPaul Moore 289955fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args) 290055fcf09bSChristopher J. PeBenito { 290155fcf09bSChristopher J. PeBenito struct class_datum *datum = d; 290255fcf09bSChristopher J. PeBenito char *name = k, **classes = args; 290355fcf09bSChristopher J. PeBenito int value = datum->value - 1; 290455fcf09bSChristopher J. PeBenito 290555fcf09bSChristopher J. PeBenito classes[value] = kstrdup(name, GFP_ATOMIC); 290655fcf09bSChristopher J. PeBenito if (!classes[value]) 290755fcf09bSChristopher J. PeBenito return -ENOMEM; 290855fcf09bSChristopher J. PeBenito 290955fcf09bSChristopher J. PeBenito return 0; 291055fcf09bSChristopher J. PeBenito } 291155fcf09bSChristopher J. PeBenito 291255fcf09bSChristopher J. PeBenito int security_get_classes(char ***classes, int *nclasses) 291355fcf09bSChristopher J. PeBenito { 29144b02b524SEric Paris int rc; 291555fcf09bSChristopher J. PeBenito 29160804d113SJames Morris read_lock(&policy_rwlock); 291755fcf09bSChristopher J. PeBenito 29184b02b524SEric Paris rc = -ENOMEM; 291955fcf09bSChristopher J. PeBenito *nclasses = policydb.p_classes.nprim; 29209f59f90bSJulia Lawall *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); 292155fcf09bSChristopher J. PeBenito if (!*classes) 292255fcf09bSChristopher J. PeBenito goto out; 292355fcf09bSChristopher J. PeBenito 292455fcf09bSChristopher J. PeBenito rc = hashtab_map(policydb.p_classes.table, get_classes_callback, 292555fcf09bSChristopher J. PeBenito *classes); 29264b02b524SEric Paris if (rc) { 292755fcf09bSChristopher J. PeBenito int i; 292855fcf09bSChristopher J. PeBenito for (i = 0; i < *nclasses; i++) 292955fcf09bSChristopher J. PeBenito kfree((*classes)[i]); 293055fcf09bSChristopher J. PeBenito kfree(*classes); 293155fcf09bSChristopher J. PeBenito } 293255fcf09bSChristopher J. PeBenito 293355fcf09bSChristopher J. PeBenito out: 29340804d113SJames Morris read_unlock(&policy_rwlock); 293555fcf09bSChristopher J. PeBenito return rc; 293655fcf09bSChristopher J. PeBenito } 293755fcf09bSChristopher J. PeBenito 293855fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args) 293955fcf09bSChristopher J. PeBenito { 294055fcf09bSChristopher J. PeBenito struct perm_datum *datum = d; 294155fcf09bSChristopher J. PeBenito char *name = k, **perms = args; 294255fcf09bSChristopher J. PeBenito int value = datum->value - 1; 294355fcf09bSChristopher J. PeBenito 294455fcf09bSChristopher J. PeBenito perms[value] = kstrdup(name, GFP_ATOMIC); 294555fcf09bSChristopher J. PeBenito if (!perms[value]) 294655fcf09bSChristopher J. PeBenito return -ENOMEM; 294755fcf09bSChristopher J. PeBenito 294855fcf09bSChristopher J. PeBenito return 0; 294955fcf09bSChristopher J. PeBenito } 295055fcf09bSChristopher J. PeBenito 295155fcf09bSChristopher J. PeBenito int security_get_permissions(char *class, char ***perms, int *nperms) 295255fcf09bSChristopher J. PeBenito { 29534b02b524SEric Paris int rc, i; 295455fcf09bSChristopher J. PeBenito struct class_datum *match; 295555fcf09bSChristopher J. PeBenito 29560804d113SJames Morris read_lock(&policy_rwlock); 295755fcf09bSChristopher J. PeBenito 29584b02b524SEric Paris rc = -EINVAL; 295955fcf09bSChristopher J. PeBenito match = hashtab_search(policydb.p_classes.table, class); 296055fcf09bSChristopher J. PeBenito if (!match) { 2961744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized class %s\n", 2962dd6f953aSHarvey Harrison __func__, class); 296355fcf09bSChristopher J. PeBenito goto out; 296455fcf09bSChristopher J. PeBenito } 296555fcf09bSChristopher J. PeBenito 29664b02b524SEric Paris rc = -ENOMEM; 296755fcf09bSChristopher J. PeBenito *nperms = match->permissions.nprim; 29689f59f90bSJulia Lawall *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); 296955fcf09bSChristopher J. PeBenito if (!*perms) 297055fcf09bSChristopher J. PeBenito goto out; 297155fcf09bSChristopher J. PeBenito 297255fcf09bSChristopher J. PeBenito if (match->comdatum) { 297355fcf09bSChristopher J. PeBenito rc = hashtab_map(match->comdatum->permissions.table, 297455fcf09bSChristopher J. PeBenito get_permissions_callback, *perms); 29754b02b524SEric Paris if (rc) 297655fcf09bSChristopher J. PeBenito goto err; 297755fcf09bSChristopher J. PeBenito } 297855fcf09bSChristopher J. PeBenito 297955fcf09bSChristopher J. PeBenito rc = hashtab_map(match->permissions.table, get_permissions_callback, 298055fcf09bSChristopher J. PeBenito *perms); 29814b02b524SEric Paris if (rc) 298255fcf09bSChristopher J. PeBenito goto err; 298355fcf09bSChristopher J. PeBenito 298455fcf09bSChristopher J. PeBenito out: 29850804d113SJames Morris read_unlock(&policy_rwlock); 298655fcf09bSChristopher J. PeBenito return rc; 298755fcf09bSChristopher J. PeBenito 298855fcf09bSChristopher J. PeBenito err: 29890804d113SJames Morris read_unlock(&policy_rwlock); 299055fcf09bSChristopher J. PeBenito for (i = 0; i < *nperms; i++) 299155fcf09bSChristopher J. PeBenito kfree((*perms)[i]); 299255fcf09bSChristopher J. PeBenito kfree(*perms); 299355fcf09bSChristopher J. PeBenito return rc; 299455fcf09bSChristopher J. PeBenito } 299555fcf09bSChristopher J. PeBenito 29963f12070eSEric Paris int security_get_reject_unknown(void) 29973f12070eSEric Paris { 29983f12070eSEric Paris return policydb.reject_unknown; 29993f12070eSEric Paris } 30003f12070eSEric Paris 30013f12070eSEric Paris int security_get_allow_unknown(void) 30023f12070eSEric Paris { 30033f12070eSEric Paris return policydb.allow_unknown; 30043f12070eSEric Paris } 30053f12070eSEric Paris 30063bb56b25SPaul Moore /** 30073bb56b25SPaul Moore * security_policycap_supported - Check for a specific policy capability 30083bb56b25SPaul Moore * @req_cap: capability 30093bb56b25SPaul Moore * 30103bb56b25SPaul Moore * Description: 30113bb56b25SPaul Moore * This function queries the currently loaded policy to see if it supports the 30123bb56b25SPaul Moore * capability specified by @req_cap. Returns true (1) if the capability is 30133bb56b25SPaul Moore * supported, false (0) if it isn't supported. 30143bb56b25SPaul Moore * 30153bb56b25SPaul Moore */ 30163bb56b25SPaul Moore int security_policycap_supported(unsigned int req_cap) 30173bb56b25SPaul Moore { 30183bb56b25SPaul Moore int rc; 30193bb56b25SPaul Moore 30200804d113SJames Morris read_lock(&policy_rwlock); 30213bb56b25SPaul Moore rc = ebitmap_get_bit(&policydb.policycaps, req_cap); 30220804d113SJames Morris read_unlock(&policy_rwlock); 30233bb56b25SPaul Moore 30243bb56b25SPaul Moore return rc; 30253bb56b25SPaul Moore } 30263bb56b25SPaul Moore 3027376bd9cbSDarrel Goeddel struct selinux_audit_rule { 3028376bd9cbSDarrel Goeddel u32 au_seqno; 3029376bd9cbSDarrel Goeddel struct context au_ctxt; 3030376bd9cbSDarrel Goeddel }; 3031376bd9cbSDarrel Goeddel 30329d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule) 3033376bd9cbSDarrel Goeddel { 30349d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule; 30359d57a7f9SAhmed S. Darwish 3036376bd9cbSDarrel Goeddel if (rule) { 3037376bd9cbSDarrel Goeddel context_destroy(&rule->au_ctxt); 3038376bd9cbSDarrel Goeddel kfree(rule); 3039376bd9cbSDarrel Goeddel } 3040376bd9cbSDarrel Goeddel } 3041376bd9cbSDarrel Goeddel 30429d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) 3043376bd9cbSDarrel Goeddel { 3044376bd9cbSDarrel Goeddel struct selinux_audit_rule *tmprule; 3045376bd9cbSDarrel Goeddel struct role_datum *roledatum; 3046376bd9cbSDarrel Goeddel struct type_datum *typedatum; 3047376bd9cbSDarrel Goeddel struct user_datum *userdatum; 30489d57a7f9SAhmed S. Darwish struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule; 3049376bd9cbSDarrel Goeddel int rc = 0; 3050376bd9cbSDarrel Goeddel 3051376bd9cbSDarrel Goeddel *rule = NULL; 3052376bd9cbSDarrel Goeddel 3053376bd9cbSDarrel Goeddel if (!ss_initialized) 30543ad40d64SSteve G return -EOPNOTSUPP; 3055376bd9cbSDarrel Goeddel 3056376bd9cbSDarrel Goeddel switch (field) { 30573a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 30583a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 30593a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 30606e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 30616e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 30626e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 3063376bd9cbSDarrel Goeddel /* only 'equals' and 'not equals' fit user, role, and type */ 30645af75d8dSAl Viro if (op != Audit_equal && op != Audit_not_equal) 3065376bd9cbSDarrel Goeddel return -EINVAL; 3066376bd9cbSDarrel Goeddel break; 30673a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 30683a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 30696e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 30706e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 307125985edcSLucas De Marchi /* we do not allow a range, indicated by the presence of '-' */ 3072376bd9cbSDarrel Goeddel if (strchr(rulestr, '-')) 3073376bd9cbSDarrel Goeddel return -EINVAL; 3074376bd9cbSDarrel Goeddel break; 3075376bd9cbSDarrel Goeddel default: 3076376bd9cbSDarrel Goeddel /* only the above fields are valid */ 3077376bd9cbSDarrel Goeddel return -EINVAL; 3078376bd9cbSDarrel Goeddel } 3079376bd9cbSDarrel Goeddel 3080376bd9cbSDarrel Goeddel tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL); 3081376bd9cbSDarrel Goeddel if (!tmprule) 3082376bd9cbSDarrel Goeddel return -ENOMEM; 3083376bd9cbSDarrel Goeddel 3084376bd9cbSDarrel Goeddel context_init(&tmprule->au_ctxt); 3085376bd9cbSDarrel Goeddel 30860804d113SJames Morris read_lock(&policy_rwlock); 3087376bd9cbSDarrel Goeddel 3088376bd9cbSDarrel Goeddel tmprule->au_seqno = latest_granting; 3089376bd9cbSDarrel Goeddel 3090376bd9cbSDarrel Goeddel switch (field) { 30913a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 30926e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 30934b02b524SEric Paris rc = -EINVAL; 3094376bd9cbSDarrel Goeddel userdatum = hashtab_search(policydb.p_users.table, rulestr); 3095376bd9cbSDarrel Goeddel if (!userdatum) 30964b02b524SEric Paris goto out; 3097376bd9cbSDarrel Goeddel tmprule->au_ctxt.user = userdatum->value; 3098376bd9cbSDarrel Goeddel break; 30993a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 31006e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 31014b02b524SEric Paris rc = -EINVAL; 3102376bd9cbSDarrel Goeddel roledatum = hashtab_search(policydb.p_roles.table, rulestr); 3103376bd9cbSDarrel Goeddel if (!roledatum) 31044b02b524SEric Paris goto out; 3105376bd9cbSDarrel Goeddel tmprule->au_ctxt.role = roledatum->value; 3106376bd9cbSDarrel Goeddel break; 31073a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 31086e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 31094b02b524SEric Paris rc = -EINVAL; 3110376bd9cbSDarrel Goeddel typedatum = hashtab_search(policydb.p_types.table, rulestr); 3111376bd9cbSDarrel Goeddel if (!typedatum) 31124b02b524SEric Paris goto out; 3113376bd9cbSDarrel Goeddel tmprule->au_ctxt.type = typedatum->value; 3114376bd9cbSDarrel Goeddel break; 31153a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 31163a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 31176e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 31186e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 3119376bd9cbSDarrel Goeddel rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC); 31204b02b524SEric Paris if (rc) 31214b02b524SEric Paris goto out; 3122376bd9cbSDarrel Goeddel break; 3123376bd9cbSDarrel Goeddel } 31244b02b524SEric Paris rc = 0; 31254b02b524SEric Paris out: 31260804d113SJames Morris read_unlock(&policy_rwlock); 3127376bd9cbSDarrel Goeddel 3128376bd9cbSDarrel Goeddel if (rc) { 3129376bd9cbSDarrel Goeddel selinux_audit_rule_free(tmprule); 3130376bd9cbSDarrel Goeddel tmprule = NULL; 3131376bd9cbSDarrel Goeddel } 3132376bd9cbSDarrel Goeddel 3133376bd9cbSDarrel Goeddel *rule = tmprule; 3134376bd9cbSDarrel Goeddel 3135376bd9cbSDarrel Goeddel return rc; 3136376bd9cbSDarrel Goeddel } 3137376bd9cbSDarrel Goeddel 31389d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */ 31399d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule) 31409d57a7f9SAhmed S. Darwish { 31419d57a7f9SAhmed S. Darwish int i; 31429d57a7f9SAhmed S. Darwish 31439d57a7f9SAhmed S. Darwish for (i = 0; i < rule->field_count; i++) { 31449d57a7f9SAhmed S. Darwish struct audit_field *f = &rule->fields[i]; 31459d57a7f9SAhmed S. Darwish switch (f->type) { 31469d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_USER: 31479d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_ROLE: 31489d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_TYPE: 31499d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_SEN: 31509d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_CLR: 31519d57a7f9SAhmed S. Darwish case AUDIT_OBJ_USER: 31529d57a7f9SAhmed S. Darwish case AUDIT_OBJ_ROLE: 31539d57a7f9SAhmed S. Darwish case AUDIT_OBJ_TYPE: 31549d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_LOW: 31559d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_HIGH: 31569d57a7f9SAhmed S. Darwish return 1; 31579d57a7f9SAhmed S. Darwish } 31589d57a7f9SAhmed S. Darwish } 31599d57a7f9SAhmed S. Darwish 31609d57a7f9SAhmed S. Darwish return 0; 31619d57a7f9SAhmed S. Darwish } 31629d57a7f9SAhmed S. Darwish 31639d57a7f9SAhmed S. Darwish int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, 3164376bd9cbSDarrel Goeddel struct audit_context *actx) 3165376bd9cbSDarrel Goeddel { 3166376bd9cbSDarrel Goeddel struct context *ctxt; 3167376bd9cbSDarrel Goeddel struct mls_level *level; 31689d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule; 3169376bd9cbSDarrel Goeddel int match = 0; 3170376bd9cbSDarrel Goeddel 31719ad42a79SRichard Guy Briggs if (unlikely(!rule)) { 31729ad42a79SRichard Guy Briggs WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n"); 3173376bd9cbSDarrel Goeddel return -ENOENT; 3174376bd9cbSDarrel Goeddel } 3175376bd9cbSDarrel Goeddel 31760804d113SJames Morris read_lock(&policy_rwlock); 3177376bd9cbSDarrel Goeddel 3178376bd9cbSDarrel Goeddel if (rule->au_seqno < latest_granting) { 3179376bd9cbSDarrel Goeddel match = -ESTALE; 3180376bd9cbSDarrel Goeddel goto out; 3181376bd9cbSDarrel Goeddel } 3182376bd9cbSDarrel Goeddel 31839a2f44f0SStephen Smalley ctxt = sidtab_search(&sidtab, sid); 31849ad42a79SRichard Guy Briggs if (unlikely(!ctxt)) { 31859ad42a79SRichard Guy Briggs WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n", 31869a2f44f0SStephen Smalley sid); 3187376bd9cbSDarrel Goeddel match = -ENOENT; 3188376bd9cbSDarrel Goeddel goto out; 3189376bd9cbSDarrel Goeddel } 3190376bd9cbSDarrel Goeddel 3191376bd9cbSDarrel Goeddel /* a field/op pair that is not caught here will simply fall through 3192376bd9cbSDarrel Goeddel without a match */ 3193376bd9cbSDarrel Goeddel switch (field) { 31943a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 31956e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 3196376bd9cbSDarrel Goeddel switch (op) { 31975af75d8dSAl Viro case Audit_equal: 3198376bd9cbSDarrel Goeddel match = (ctxt->user == rule->au_ctxt.user); 3199376bd9cbSDarrel Goeddel break; 32005af75d8dSAl Viro case Audit_not_equal: 3201376bd9cbSDarrel Goeddel match = (ctxt->user != rule->au_ctxt.user); 3202376bd9cbSDarrel Goeddel break; 3203376bd9cbSDarrel Goeddel } 3204376bd9cbSDarrel Goeddel break; 32053a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 32066e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 3207376bd9cbSDarrel Goeddel switch (op) { 32085af75d8dSAl Viro case Audit_equal: 3209376bd9cbSDarrel Goeddel match = (ctxt->role == rule->au_ctxt.role); 3210376bd9cbSDarrel Goeddel break; 32115af75d8dSAl Viro case Audit_not_equal: 3212376bd9cbSDarrel Goeddel match = (ctxt->role != rule->au_ctxt.role); 3213376bd9cbSDarrel Goeddel break; 3214376bd9cbSDarrel Goeddel } 3215376bd9cbSDarrel Goeddel break; 32163a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 32176e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 3218376bd9cbSDarrel Goeddel switch (op) { 32195af75d8dSAl Viro case Audit_equal: 3220376bd9cbSDarrel Goeddel match = (ctxt->type == rule->au_ctxt.type); 3221376bd9cbSDarrel Goeddel break; 32225af75d8dSAl Viro case Audit_not_equal: 3223376bd9cbSDarrel Goeddel match = (ctxt->type != rule->au_ctxt.type); 3224376bd9cbSDarrel Goeddel break; 3225376bd9cbSDarrel Goeddel } 3226376bd9cbSDarrel Goeddel break; 32273a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 32283a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 32296e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 32306e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 32316e5a2d1dSDarrel Goeddel level = ((field == AUDIT_SUBJ_SEN || 32326e5a2d1dSDarrel Goeddel field == AUDIT_OBJ_LEV_LOW) ? 3233376bd9cbSDarrel Goeddel &ctxt->range.level[0] : &ctxt->range.level[1]); 3234376bd9cbSDarrel Goeddel switch (op) { 32355af75d8dSAl Viro case Audit_equal: 3236376bd9cbSDarrel Goeddel match = mls_level_eq(&rule->au_ctxt.range.level[0], 3237376bd9cbSDarrel Goeddel level); 3238376bd9cbSDarrel Goeddel break; 32395af75d8dSAl Viro case Audit_not_equal: 3240376bd9cbSDarrel Goeddel match = !mls_level_eq(&rule->au_ctxt.range.level[0], 3241376bd9cbSDarrel Goeddel level); 3242376bd9cbSDarrel Goeddel break; 32435af75d8dSAl Viro case Audit_lt: 3244376bd9cbSDarrel Goeddel match = (mls_level_dom(&rule->au_ctxt.range.level[0], 3245376bd9cbSDarrel Goeddel level) && 3246376bd9cbSDarrel Goeddel !mls_level_eq(&rule->au_ctxt.range.level[0], 3247376bd9cbSDarrel Goeddel level)); 3248376bd9cbSDarrel Goeddel break; 32495af75d8dSAl Viro case Audit_le: 3250376bd9cbSDarrel Goeddel match = mls_level_dom(&rule->au_ctxt.range.level[0], 3251376bd9cbSDarrel Goeddel level); 3252376bd9cbSDarrel Goeddel break; 32535af75d8dSAl Viro case Audit_gt: 3254376bd9cbSDarrel Goeddel match = (mls_level_dom(level, 3255376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]) && 3256376bd9cbSDarrel Goeddel !mls_level_eq(level, 3257376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0])); 3258376bd9cbSDarrel Goeddel break; 32595af75d8dSAl Viro case Audit_ge: 3260376bd9cbSDarrel Goeddel match = mls_level_dom(level, 3261376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]); 3262376bd9cbSDarrel Goeddel break; 3263376bd9cbSDarrel Goeddel } 3264376bd9cbSDarrel Goeddel } 3265376bd9cbSDarrel Goeddel 3266376bd9cbSDarrel Goeddel out: 32670804d113SJames Morris read_unlock(&policy_rwlock); 3268376bd9cbSDarrel Goeddel return match; 3269376bd9cbSDarrel Goeddel } 3270376bd9cbSDarrel Goeddel 32719d57a7f9SAhmed S. Darwish static int (*aurule_callback)(void) = audit_update_lsm_rules; 3272376bd9cbSDarrel Goeddel 3273562c99f2SWanlong Gao static int aurule_avc_callback(u32 event) 3274376bd9cbSDarrel Goeddel { 3275376bd9cbSDarrel Goeddel int err = 0; 3276376bd9cbSDarrel Goeddel 3277376bd9cbSDarrel Goeddel if (event == AVC_CALLBACK_RESET && aurule_callback) 3278376bd9cbSDarrel Goeddel err = aurule_callback(); 3279376bd9cbSDarrel Goeddel return err; 3280376bd9cbSDarrel Goeddel } 3281376bd9cbSDarrel Goeddel 3282376bd9cbSDarrel Goeddel static int __init aurule_init(void) 3283376bd9cbSDarrel Goeddel { 3284376bd9cbSDarrel Goeddel int err; 3285376bd9cbSDarrel Goeddel 3286562c99f2SWanlong Gao err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET); 3287376bd9cbSDarrel Goeddel if (err) 3288376bd9cbSDarrel Goeddel panic("avc_add_callback() failed, error %d\n", err); 3289376bd9cbSDarrel Goeddel 3290376bd9cbSDarrel Goeddel return err; 3291376bd9cbSDarrel Goeddel } 3292376bd9cbSDarrel Goeddel __initcall(aurule_init); 3293376bd9cbSDarrel Goeddel 32947420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL 32957420ed23SVenkat Yekkirala /** 32965778eabdSPaul Moore * security_netlbl_cache_add - Add an entry to the NetLabel cache 32975778eabdSPaul Moore * @secattr: the NetLabel packet security attributes 32985dbe1eb0SPaul Moore * @sid: the SELinux SID 32997420ed23SVenkat Yekkirala * 33007420ed23SVenkat Yekkirala * Description: 33017420ed23SVenkat Yekkirala * Attempt to cache the context in @ctx, which was derived from the packet in 33025778eabdSPaul Moore * @skb, in the NetLabel subsystem cache. This function assumes @secattr has 33035778eabdSPaul Moore * already been initialized. 33047420ed23SVenkat Yekkirala * 33057420ed23SVenkat Yekkirala */ 33065778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, 33075dbe1eb0SPaul Moore u32 sid) 33087420ed23SVenkat Yekkirala { 33095dbe1eb0SPaul Moore u32 *sid_cache; 33107420ed23SVenkat Yekkirala 33115dbe1eb0SPaul Moore sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC); 33125dbe1eb0SPaul Moore if (sid_cache == NULL) 33135dbe1eb0SPaul Moore return; 33145778eabdSPaul Moore secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); 33155dbe1eb0SPaul Moore if (secattr->cache == NULL) { 33165dbe1eb0SPaul Moore kfree(sid_cache); 33175778eabdSPaul Moore return; 33180ec8abd7SJesper Juhl } 33197420ed23SVenkat Yekkirala 33205dbe1eb0SPaul Moore *sid_cache = sid; 33215dbe1eb0SPaul Moore secattr->cache->free = kfree; 33225dbe1eb0SPaul Moore secattr->cache->data = sid_cache; 33235778eabdSPaul Moore secattr->flags |= NETLBL_SECATTR_CACHE; 33247420ed23SVenkat Yekkirala } 33257420ed23SVenkat Yekkirala 33267420ed23SVenkat Yekkirala /** 33275778eabdSPaul Moore * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID 33287420ed23SVenkat Yekkirala * @secattr: the NetLabel packet security attributes 33297420ed23SVenkat Yekkirala * @sid: the SELinux SID 33307420ed23SVenkat Yekkirala * 33317420ed23SVenkat Yekkirala * Description: 33325778eabdSPaul Moore * Convert the given NetLabel security attributes in @secattr into a 33337420ed23SVenkat Yekkirala * SELinux SID. If the @secattr field does not contain a full SELinux 333425985edcSLucas De Marchi * SID/context then use SECINITSID_NETMSG as the foundation. If possible the 33355dbe1eb0SPaul Moore * 'cache' field of @secattr is set and the CACHE flag is set; this is to 33365dbe1eb0SPaul Moore * allow the @secattr to be used by NetLabel to cache the secattr to SID 33375dbe1eb0SPaul Moore * conversion for future lookups. Returns zero on success, negative values on 33385dbe1eb0SPaul Moore * failure. 33397420ed23SVenkat Yekkirala * 33407420ed23SVenkat Yekkirala */ 33415778eabdSPaul Moore int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, 33427420ed23SVenkat Yekkirala u32 *sid) 33437420ed23SVenkat Yekkirala { 33447ae9f23cSEric Paris int rc; 33457420ed23SVenkat Yekkirala struct context *ctx; 33467420ed23SVenkat Yekkirala struct context ctx_new; 33475778eabdSPaul Moore 33485778eabdSPaul Moore if (!ss_initialized) { 33495778eabdSPaul Moore *sid = SECSID_NULL; 33505778eabdSPaul Moore return 0; 33515778eabdSPaul Moore } 33527420ed23SVenkat Yekkirala 33530804d113SJames Morris read_lock(&policy_rwlock); 33547420ed23SVenkat Yekkirala 33557ae9f23cSEric Paris if (secattr->flags & NETLBL_SECATTR_CACHE) 33565dbe1eb0SPaul Moore *sid = *(u32 *)secattr->cache->data; 33577ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_SECID) 335816efd454SPaul Moore *sid = secattr->attr.secid; 33597ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { 33607ae9f23cSEric Paris rc = -EIDRM; 33615dbe1eb0SPaul Moore ctx = sidtab_search(&sidtab, SECINITSID_NETMSG); 33627420ed23SVenkat Yekkirala if (ctx == NULL) 33637ae9f23cSEric Paris goto out; 33647420ed23SVenkat Yekkirala 336581990fbdSPaul Moore context_init(&ctx_new); 33667420ed23SVenkat Yekkirala ctx_new.user = ctx->user; 33677420ed23SVenkat Yekkirala ctx_new.role = ctx->role; 33687420ed23SVenkat Yekkirala ctx_new.type = ctx->type; 336902752760SPaul Moore mls_import_netlbl_lvl(&ctx_new, secattr); 3370701a90baSPaul Moore if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 3371da8026faSPaul Moore rc = mls_import_netlbl_cat(&ctx_new, secattr); 33727ae9f23cSEric Paris if (rc) 33737ae9f23cSEric Paris goto out; 33747420ed23SVenkat Yekkirala } 33757ae9f23cSEric Paris rc = -EIDRM; 33767ae9f23cSEric Paris if (!mls_context_isvalid(&policydb, &ctx_new)) 33777ae9f23cSEric Paris goto out_free; 33787420ed23SVenkat Yekkirala 33797420ed23SVenkat Yekkirala rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid); 33807ae9f23cSEric Paris if (rc) 33817ae9f23cSEric Paris goto out_free; 33827420ed23SVenkat Yekkirala 33835dbe1eb0SPaul Moore security_netlbl_cache_add(secattr, *sid); 33845778eabdSPaul Moore 33857420ed23SVenkat Yekkirala ebitmap_destroy(&ctx_new.range.level[0].cat); 33867ae9f23cSEric Paris } else 3387388b2405Spaul.moore@hp.com *sid = SECSID_NULL; 33887420ed23SVenkat Yekkirala 33897ae9f23cSEric Paris read_unlock(&policy_rwlock); 33907ae9f23cSEric Paris return 0; 33917ae9f23cSEric Paris out_free: 33927ae9f23cSEric Paris ebitmap_destroy(&ctx_new.range.level[0].cat); 33937ae9f23cSEric Paris out: 33940804d113SJames Morris read_unlock(&policy_rwlock); 33957420ed23SVenkat Yekkirala return rc; 33967420ed23SVenkat Yekkirala } 33977420ed23SVenkat Yekkirala 33987420ed23SVenkat Yekkirala /** 33995778eabdSPaul Moore * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr 34005778eabdSPaul Moore * @sid: the SELinux SID 34015778eabdSPaul Moore * @secattr: the NetLabel packet security attributes 34027420ed23SVenkat Yekkirala * 34037420ed23SVenkat Yekkirala * Description: 34045778eabdSPaul Moore * Convert the given SELinux SID in @sid into a NetLabel security attribute. 34055778eabdSPaul Moore * Returns zero on success, negative values on failure. 34067420ed23SVenkat Yekkirala * 34077420ed23SVenkat Yekkirala */ 34085778eabdSPaul Moore int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) 34097420ed23SVenkat Yekkirala { 341099d854d2SPaul Moore int rc; 34117420ed23SVenkat Yekkirala struct context *ctx; 34127420ed23SVenkat Yekkirala 34137420ed23SVenkat Yekkirala if (!ss_initialized) 34147420ed23SVenkat Yekkirala return 0; 34157420ed23SVenkat Yekkirala 34160804d113SJames Morris read_lock(&policy_rwlock); 34174b02b524SEric Paris 341899d854d2SPaul Moore rc = -ENOENT; 34194b02b524SEric Paris ctx = sidtab_search(&sidtab, sid); 34204b02b524SEric Paris if (ctx == NULL) 34214b02b524SEric Paris goto out; 34224b02b524SEric Paris 34234b02b524SEric Paris rc = -ENOMEM; 3424ac76c05bSEric Paris secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1), 34257420ed23SVenkat Yekkirala GFP_ATOMIC); 34264b02b524SEric Paris if (secattr->domain == NULL) 34274b02b524SEric Paris goto out; 34284b02b524SEric Paris 34298d75899dSPaul Moore secattr->attr.secid = sid; 34308d75899dSPaul Moore secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; 34315778eabdSPaul Moore mls_export_netlbl_lvl(ctx, secattr); 34325778eabdSPaul Moore rc = mls_export_netlbl_cat(ctx, secattr); 34334b02b524SEric Paris out: 34340804d113SJames Morris read_unlock(&policy_rwlock); 3435f8687afeSPaul Moore return rc; 3436f8687afeSPaul Moore } 34377420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */ 3438cee74f47SEric Paris 3439cee74f47SEric Paris /** 3440cee74f47SEric Paris * security_read_policy - read the policy. 3441cee74f47SEric Paris * @data: binary policy data 3442cee74f47SEric Paris * @len: length of data in bytes 3443cee74f47SEric Paris * 3444cee74f47SEric Paris */ 34456b697323SEric Paris int security_read_policy(void **data, size_t *len) 3446cee74f47SEric Paris { 3447cee74f47SEric Paris int rc; 3448cee74f47SEric Paris struct policy_file fp; 3449cee74f47SEric Paris 3450cee74f47SEric Paris if (!ss_initialized) 3451cee74f47SEric Paris return -EINVAL; 3452cee74f47SEric Paris 3453cee74f47SEric Paris *len = security_policydb_len(); 3454cee74f47SEric Paris 3455845ca30fSEric Paris *data = vmalloc_user(*len); 3456cee74f47SEric Paris if (!*data) 3457cee74f47SEric Paris return -ENOMEM; 3458cee74f47SEric Paris 3459cee74f47SEric Paris fp.data = *data; 3460cee74f47SEric Paris fp.len = *len; 3461cee74f47SEric Paris 3462cee74f47SEric Paris read_lock(&policy_rwlock); 3463cee74f47SEric Paris rc = policydb_write(&policydb, &fp); 3464cee74f47SEric Paris read_unlock(&policy_rwlock); 3465cee74f47SEric Paris 3466cee74f47SEric Paris if (rc) 3467cee74f47SEric Paris return rc; 3468cee74f47SEric Paris 3469cee74f47SEric Paris *len = (unsigned long)fp.data - (unsigned long)*data; 3470cee74f47SEric Paris return 0; 3471cee74f47SEric Paris 3472cee74f47SEric Paris } 3473