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 * 167420ed23SVenkat Yekkirala * Updated: Hewlett-Packard <paul.moore@hp.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 731da177e4SLinus Torvalds extern void selnl_notify_policyload(u32 seqno); 741da177e4SLinus Torvalds 753bb56b25SPaul Moore int selinux_policycap_netpeer; 76b0c636b9SEric Paris int selinux_policycap_openperm; 773bb56b25SPaul Moore 781da177e4SLinus Torvalds static DEFINE_RWLOCK(policy_rwlock); 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds static struct sidtab sidtab; 811da177e4SLinus Torvalds struct policydb policydb; 825d55a345SEric Paris int ss_initialized; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* 851da177e4SLinus Torvalds * The largest sequence number that has been used when 861da177e4SLinus Torvalds * providing an access decision to the access vector cache. 871da177e4SLinus Torvalds * The sequence number only changes when a policy change 881da177e4SLinus Torvalds * occurs. 891da177e4SLinus Torvalds */ 905d55a345SEric Paris static u32 latest_granting; 911da177e4SLinus Torvalds 921da177e4SLinus Torvalds /* Forward declaration. */ 931da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, 941da177e4SLinus Torvalds u32 *scontext_len); 951da177e4SLinus Torvalds 9619439d05SStephen Smalley static void context_struct_compute_av(struct context *scontext, 97d9250deaSKaiGai Kohei struct context *tcontext, 98d9250deaSKaiGai Kohei u16 tclass, 99d9250deaSKaiGai Kohei struct av_decision *avd); 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 204c6d3aaa4SStephen Smalley static void map_decision(u16 tclass, struct av_decision *avd, 205c6d3aaa4SStephen Smalley int allow_unknown) 206c6d3aaa4SStephen Smalley { 207c6d3aaa4SStephen Smalley if (tclass < current_mapping_size) { 208c6d3aaa4SStephen Smalley unsigned i, n = current_mapping[tclass].num_perms; 209c6d3aaa4SStephen Smalley u32 result; 210c6d3aaa4SStephen Smalley 211c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) { 212c6d3aaa4SStephen Smalley if (avd->allowed & current_mapping[tclass].perms[i]) 213c6d3aaa4SStephen Smalley result |= 1<<i; 214c6d3aaa4SStephen Smalley if (allow_unknown && !current_mapping[tclass].perms[i]) 215c6d3aaa4SStephen Smalley result |= 1<<i; 216c6d3aaa4SStephen Smalley } 217c6d3aaa4SStephen Smalley avd->allowed = result; 218c6d3aaa4SStephen Smalley 219c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) 220c6d3aaa4SStephen Smalley if (avd->auditallow & current_mapping[tclass].perms[i]) 221c6d3aaa4SStephen Smalley result |= 1<<i; 222c6d3aaa4SStephen Smalley avd->auditallow = result; 223c6d3aaa4SStephen Smalley 224c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) { 225c6d3aaa4SStephen Smalley if (avd->auditdeny & current_mapping[tclass].perms[i]) 226c6d3aaa4SStephen Smalley result |= 1<<i; 227c6d3aaa4SStephen Smalley if (!allow_unknown && !current_mapping[tclass].perms[i]) 228c6d3aaa4SStephen Smalley result |= 1<<i; 229c6d3aaa4SStephen Smalley } 2300bce9527SEric Paris /* 2310bce9527SEric Paris * In case the kernel has a bug and requests a permission 2320bce9527SEric Paris * between num_perms and the maximum permission number, we 2330bce9527SEric Paris * should audit that denial 2340bce9527SEric Paris */ 2350bce9527SEric Paris for (; i < (sizeof(u32)*8); i++) 2360bce9527SEric Paris result |= 1<<i; 237c6d3aaa4SStephen Smalley avd->auditdeny = result; 238c6d3aaa4SStephen Smalley } 239c6d3aaa4SStephen Smalley } 240c6d3aaa4SStephen Smalley 2410719aaf5SGuido Trentalancia int security_mls_enabled(void) 2420719aaf5SGuido Trentalancia { 2430719aaf5SGuido Trentalancia return policydb.mls_enabled; 2440719aaf5SGuido Trentalancia } 245c6d3aaa4SStephen Smalley 2461da177e4SLinus Torvalds /* 2471da177e4SLinus Torvalds * Return the boolean value of a constraint expression 2481da177e4SLinus Torvalds * when it is applied to the specified source and target 2491da177e4SLinus Torvalds * security contexts. 2501da177e4SLinus Torvalds * 2511da177e4SLinus Torvalds * xcontext is a special beast... It is used by the validatetrans rules 2521da177e4SLinus Torvalds * only. For these rules, scontext is the context before the transition, 2531da177e4SLinus Torvalds * tcontext is the context after the transition, and xcontext is the context 2541da177e4SLinus Torvalds * of the process performing the transition. All other callers of 2551da177e4SLinus Torvalds * constraint_expr_eval should pass in NULL for xcontext. 2561da177e4SLinus Torvalds */ 2571da177e4SLinus Torvalds static int constraint_expr_eval(struct context *scontext, 2581da177e4SLinus Torvalds struct context *tcontext, 2591da177e4SLinus Torvalds struct context *xcontext, 2601da177e4SLinus Torvalds struct constraint_expr *cexpr) 2611da177e4SLinus Torvalds { 2621da177e4SLinus Torvalds u32 val1, val2; 2631da177e4SLinus Torvalds struct context *c; 2641da177e4SLinus Torvalds struct role_datum *r1, *r2; 2651da177e4SLinus Torvalds struct mls_level *l1, *l2; 2661da177e4SLinus Torvalds struct constraint_expr *e; 2671da177e4SLinus Torvalds int s[CEXPR_MAXDEPTH]; 2681da177e4SLinus Torvalds int sp = -1; 2691da177e4SLinus Torvalds 2701da177e4SLinus Torvalds for (e = cexpr; e; e = e->next) { 2711da177e4SLinus Torvalds switch (e->expr_type) { 2721da177e4SLinus Torvalds case CEXPR_NOT: 2731da177e4SLinus Torvalds BUG_ON(sp < 0); 2741da177e4SLinus Torvalds s[sp] = !s[sp]; 2751da177e4SLinus Torvalds break; 2761da177e4SLinus Torvalds case CEXPR_AND: 2771da177e4SLinus Torvalds BUG_ON(sp < 1); 2781da177e4SLinus Torvalds sp--; 2791da177e4SLinus Torvalds s[sp] &= s[sp + 1]; 2801da177e4SLinus Torvalds break; 2811da177e4SLinus Torvalds case CEXPR_OR: 2821da177e4SLinus Torvalds BUG_ON(sp < 1); 2831da177e4SLinus Torvalds sp--; 2841da177e4SLinus Torvalds s[sp] |= s[sp + 1]; 2851da177e4SLinus Torvalds break; 2861da177e4SLinus Torvalds case CEXPR_ATTR: 2871da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH - 1)) 2881da177e4SLinus Torvalds return 0; 2891da177e4SLinus Torvalds switch (e->attr) { 2901da177e4SLinus Torvalds case CEXPR_USER: 2911da177e4SLinus Torvalds val1 = scontext->user; 2921da177e4SLinus Torvalds val2 = tcontext->user; 2931da177e4SLinus Torvalds break; 2941da177e4SLinus Torvalds case CEXPR_TYPE: 2951da177e4SLinus Torvalds val1 = scontext->type; 2961da177e4SLinus Torvalds val2 = tcontext->type; 2971da177e4SLinus Torvalds break; 2981da177e4SLinus Torvalds case CEXPR_ROLE: 2991da177e4SLinus Torvalds val1 = scontext->role; 3001da177e4SLinus Torvalds val2 = tcontext->role; 3011da177e4SLinus Torvalds r1 = policydb.role_val_to_struct[val1 - 1]; 3021da177e4SLinus Torvalds r2 = policydb.role_val_to_struct[val2 - 1]; 3031da177e4SLinus Torvalds switch (e->op) { 3041da177e4SLinus Torvalds case CEXPR_DOM: 3051da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r1->dominates, 3061da177e4SLinus Torvalds val2 - 1); 3071da177e4SLinus Torvalds continue; 3081da177e4SLinus Torvalds case CEXPR_DOMBY: 3091da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r2->dominates, 3101da177e4SLinus Torvalds val1 - 1); 3111da177e4SLinus Torvalds continue; 3121da177e4SLinus Torvalds case CEXPR_INCOMP: 3131da177e4SLinus Torvalds s[++sp] = (!ebitmap_get_bit(&r1->dominates, 3141da177e4SLinus Torvalds val2 - 1) && 3151da177e4SLinus Torvalds !ebitmap_get_bit(&r2->dominates, 3161da177e4SLinus Torvalds val1 - 1)); 3171da177e4SLinus Torvalds continue; 3181da177e4SLinus Torvalds default: 3191da177e4SLinus Torvalds break; 3201da177e4SLinus Torvalds } 3211da177e4SLinus Torvalds break; 3221da177e4SLinus Torvalds case CEXPR_L1L2: 3231da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3241da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 3251da177e4SLinus Torvalds goto mls_ops; 3261da177e4SLinus Torvalds case CEXPR_L1H2: 3271da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3281da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3291da177e4SLinus Torvalds goto mls_ops; 3301da177e4SLinus Torvalds case CEXPR_H1L2: 3311da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 3321da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 3331da177e4SLinus Torvalds goto mls_ops; 3341da177e4SLinus Torvalds case CEXPR_H1H2: 3351da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 3361da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3371da177e4SLinus Torvalds goto mls_ops; 3381da177e4SLinus Torvalds case CEXPR_L1H1: 3391da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 3401da177e4SLinus Torvalds l2 = &(scontext->range.level[1]); 3411da177e4SLinus Torvalds goto mls_ops; 3421da177e4SLinus Torvalds case CEXPR_L2H2: 3431da177e4SLinus Torvalds l1 = &(tcontext->range.level[0]); 3441da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 3451da177e4SLinus Torvalds goto mls_ops; 3461da177e4SLinus Torvalds mls_ops: 3471da177e4SLinus Torvalds switch (e->op) { 3481da177e4SLinus Torvalds case CEXPR_EQ: 3491da177e4SLinus Torvalds s[++sp] = mls_level_eq(l1, l2); 3501da177e4SLinus Torvalds continue; 3511da177e4SLinus Torvalds case CEXPR_NEQ: 3521da177e4SLinus Torvalds s[++sp] = !mls_level_eq(l1, l2); 3531da177e4SLinus Torvalds continue; 3541da177e4SLinus Torvalds case CEXPR_DOM: 3551da177e4SLinus Torvalds s[++sp] = mls_level_dom(l1, l2); 3561da177e4SLinus Torvalds continue; 3571da177e4SLinus Torvalds case CEXPR_DOMBY: 3581da177e4SLinus Torvalds s[++sp] = mls_level_dom(l2, l1); 3591da177e4SLinus Torvalds continue; 3601da177e4SLinus Torvalds case CEXPR_INCOMP: 3611da177e4SLinus Torvalds s[++sp] = mls_level_incomp(l2, l1); 3621da177e4SLinus Torvalds continue; 3631da177e4SLinus Torvalds default: 3641da177e4SLinus Torvalds BUG(); 3651da177e4SLinus Torvalds return 0; 3661da177e4SLinus Torvalds } 3671da177e4SLinus Torvalds break; 3681da177e4SLinus Torvalds default: 3691da177e4SLinus Torvalds BUG(); 3701da177e4SLinus Torvalds return 0; 3711da177e4SLinus Torvalds } 3721da177e4SLinus Torvalds 3731da177e4SLinus Torvalds switch (e->op) { 3741da177e4SLinus Torvalds case CEXPR_EQ: 3751da177e4SLinus Torvalds s[++sp] = (val1 == val2); 3761da177e4SLinus Torvalds break; 3771da177e4SLinus Torvalds case CEXPR_NEQ: 3781da177e4SLinus Torvalds s[++sp] = (val1 != val2); 3791da177e4SLinus Torvalds break; 3801da177e4SLinus Torvalds default: 3811da177e4SLinus Torvalds BUG(); 3821da177e4SLinus Torvalds return 0; 3831da177e4SLinus Torvalds } 3841da177e4SLinus Torvalds break; 3851da177e4SLinus Torvalds case CEXPR_NAMES: 3861da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH-1)) 3871da177e4SLinus Torvalds return 0; 3881da177e4SLinus Torvalds c = scontext; 3891da177e4SLinus Torvalds if (e->attr & CEXPR_TARGET) 3901da177e4SLinus Torvalds c = tcontext; 3911da177e4SLinus Torvalds else if (e->attr & CEXPR_XTARGET) { 3921da177e4SLinus Torvalds c = xcontext; 3931da177e4SLinus Torvalds if (!c) { 3941da177e4SLinus Torvalds BUG(); 3951da177e4SLinus Torvalds return 0; 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds if (e->attr & CEXPR_USER) 3991da177e4SLinus Torvalds val1 = c->user; 4001da177e4SLinus Torvalds else if (e->attr & CEXPR_ROLE) 4011da177e4SLinus Torvalds val1 = c->role; 4021da177e4SLinus Torvalds else if (e->attr & CEXPR_TYPE) 4031da177e4SLinus Torvalds val1 = c->type; 4041da177e4SLinus Torvalds else { 4051da177e4SLinus Torvalds BUG(); 4061da177e4SLinus Torvalds return 0; 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds 4091da177e4SLinus Torvalds switch (e->op) { 4101da177e4SLinus Torvalds case CEXPR_EQ: 4111da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); 4121da177e4SLinus Torvalds break; 4131da177e4SLinus Torvalds case CEXPR_NEQ: 4141da177e4SLinus Torvalds s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); 4151da177e4SLinus Torvalds break; 4161da177e4SLinus Torvalds default: 4171da177e4SLinus Torvalds BUG(); 4181da177e4SLinus Torvalds return 0; 4191da177e4SLinus Torvalds } 4201da177e4SLinus Torvalds break; 4211da177e4SLinus Torvalds default: 4221da177e4SLinus Torvalds BUG(); 4231da177e4SLinus Torvalds return 0; 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds } 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds BUG_ON(sp != 0); 4281da177e4SLinus Torvalds return s[0]; 4291da177e4SLinus Torvalds } 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds /* 43244c2d9bdSKaiGai Kohei * security_dump_masked_av - dumps masked permissions during 43344c2d9bdSKaiGai Kohei * security_compute_av due to RBAC, MLS/Constraint and Type bounds. 43444c2d9bdSKaiGai Kohei */ 43544c2d9bdSKaiGai Kohei static int dump_masked_av_helper(void *k, void *d, void *args) 43644c2d9bdSKaiGai Kohei { 43744c2d9bdSKaiGai Kohei struct perm_datum *pdatum = d; 43844c2d9bdSKaiGai Kohei char **permission_names = args; 43944c2d9bdSKaiGai Kohei 44044c2d9bdSKaiGai Kohei BUG_ON(pdatum->value < 1 || pdatum->value > 32); 44144c2d9bdSKaiGai Kohei 44244c2d9bdSKaiGai Kohei permission_names[pdatum->value - 1] = (char *)k; 44344c2d9bdSKaiGai Kohei 44444c2d9bdSKaiGai Kohei return 0; 44544c2d9bdSKaiGai Kohei } 44644c2d9bdSKaiGai Kohei 44744c2d9bdSKaiGai Kohei static void security_dump_masked_av(struct context *scontext, 44844c2d9bdSKaiGai Kohei struct context *tcontext, 44944c2d9bdSKaiGai Kohei u16 tclass, 45044c2d9bdSKaiGai Kohei u32 permissions, 45144c2d9bdSKaiGai Kohei const char *reason) 45244c2d9bdSKaiGai Kohei { 45344c2d9bdSKaiGai Kohei struct common_datum *common_dat; 45444c2d9bdSKaiGai Kohei struct class_datum *tclass_dat; 45544c2d9bdSKaiGai Kohei struct audit_buffer *ab; 45644c2d9bdSKaiGai Kohei char *tclass_name; 45744c2d9bdSKaiGai Kohei char *scontext_name = NULL; 45844c2d9bdSKaiGai Kohei char *tcontext_name = NULL; 45944c2d9bdSKaiGai Kohei char *permission_names[32]; 4602da5d31bSJames Morris int index; 4612da5d31bSJames Morris u32 length; 46244c2d9bdSKaiGai Kohei bool need_comma = false; 46344c2d9bdSKaiGai Kohei 46444c2d9bdSKaiGai Kohei if (!permissions) 46544c2d9bdSKaiGai Kohei return; 46644c2d9bdSKaiGai Kohei 467ac76c05bSEric Paris tclass_name = sym_name(&policydb, SYM_CLASSES, tclass - 1); 46844c2d9bdSKaiGai Kohei tclass_dat = policydb.class_val_to_struct[tclass - 1]; 46944c2d9bdSKaiGai Kohei common_dat = tclass_dat->comdatum; 47044c2d9bdSKaiGai Kohei 47144c2d9bdSKaiGai Kohei /* init permission_names */ 47244c2d9bdSKaiGai Kohei if (common_dat && 47344c2d9bdSKaiGai Kohei hashtab_map(common_dat->permissions.table, 47444c2d9bdSKaiGai Kohei dump_masked_av_helper, permission_names) < 0) 47544c2d9bdSKaiGai Kohei goto out; 47644c2d9bdSKaiGai Kohei 47744c2d9bdSKaiGai Kohei if (hashtab_map(tclass_dat->permissions.table, 47844c2d9bdSKaiGai Kohei dump_masked_av_helper, permission_names) < 0) 47944c2d9bdSKaiGai Kohei goto out; 48044c2d9bdSKaiGai Kohei 48144c2d9bdSKaiGai Kohei /* get scontext/tcontext in text form */ 48244c2d9bdSKaiGai Kohei if (context_struct_to_string(scontext, 48344c2d9bdSKaiGai Kohei &scontext_name, &length) < 0) 48444c2d9bdSKaiGai Kohei goto out; 48544c2d9bdSKaiGai Kohei 48644c2d9bdSKaiGai Kohei if (context_struct_to_string(tcontext, 48744c2d9bdSKaiGai Kohei &tcontext_name, &length) < 0) 48844c2d9bdSKaiGai Kohei goto out; 48944c2d9bdSKaiGai Kohei 49044c2d9bdSKaiGai Kohei /* audit a message */ 49144c2d9bdSKaiGai Kohei ab = audit_log_start(current->audit_context, 49244c2d9bdSKaiGai Kohei GFP_ATOMIC, AUDIT_SELINUX_ERR); 49344c2d9bdSKaiGai Kohei if (!ab) 49444c2d9bdSKaiGai Kohei goto out; 49544c2d9bdSKaiGai Kohei 49644c2d9bdSKaiGai Kohei audit_log_format(ab, "op=security_compute_av reason=%s " 49744c2d9bdSKaiGai Kohei "scontext=%s tcontext=%s tclass=%s perms=", 49844c2d9bdSKaiGai Kohei reason, scontext_name, tcontext_name, tclass_name); 49944c2d9bdSKaiGai Kohei 50044c2d9bdSKaiGai Kohei for (index = 0; index < 32; index++) { 50144c2d9bdSKaiGai Kohei u32 mask = (1 << index); 50244c2d9bdSKaiGai Kohei 50344c2d9bdSKaiGai Kohei if ((mask & permissions) == 0) 50444c2d9bdSKaiGai Kohei continue; 50544c2d9bdSKaiGai Kohei 50644c2d9bdSKaiGai Kohei audit_log_format(ab, "%s%s", 50744c2d9bdSKaiGai Kohei need_comma ? "," : "", 50844c2d9bdSKaiGai Kohei permission_names[index] 50944c2d9bdSKaiGai Kohei ? permission_names[index] : "????"); 51044c2d9bdSKaiGai Kohei need_comma = true; 51144c2d9bdSKaiGai Kohei } 51244c2d9bdSKaiGai Kohei audit_log_end(ab); 51344c2d9bdSKaiGai Kohei out: 51444c2d9bdSKaiGai Kohei /* release scontext/tcontext */ 51544c2d9bdSKaiGai Kohei kfree(tcontext_name); 51644c2d9bdSKaiGai Kohei kfree(scontext_name); 51744c2d9bdSKaiGai Kohei 51844c2d9bdSKaiGai Kohei return; 51944c2d9bdSKaiGai Kohei } 52044c2d9bdSKaiGai Kohei 52144c2d9bdSKaiGai Kohei /* 522d9250deaSKaiGai Kohei * security_boundary_permission - drops violated permissions 523d9250deaSKaiGai Kohei * on boundary constraint. 524d9250deaSKaiGai Kohei */ 525d9250deaSKaiGai Kohei static void type_attribute_bounds_av(struct context *scontext, 526d9250deaSKaiGai Kohei struct context *tcontext, 527d9250deaSKaiGai Kohei u16 tclass, 528d9250deaSKaiGai Kohei struct av_decision *avd) 529d9250deaSKaiGai Kohei { 5302ae3ba39SKaiGai Kohei struct context lo_scontext; 5312ae3ba39SKaiGai Kohei struct context lo_tcontext; 5322ae3ba39SKaiGai Kohei struct av_decision lo_avd; 53323bdecb0SEric Paris struct type_datum *source; 53423bdecb0SEric Paris struct type_datum *target; 5352ae3ba39SKaiGai Kohei u32 masked = 0; 536d9250deaSKaiGai Kohei 53723bdecb0SEric Paris source = flex_array_get_ptr(policydb.type_val_to_struct_array, 53823bdecb0SEric Paris scontext->type - 1); 53923bdecb0SEric Paris BUG_ON(!source); 54023bdecb0SEric Paris 54123bdecb0SEric Paris target = flex_array_get_ptr(policydb.type_val_to_struct_array, 54223bdecb0SEric Paris tcontext->type - 1); 54323bdecb0SEric Paris BUG_ON(!target); 54423bdecb0SEric Paris 545d9250deaSKaiGai Kohei if (source->bounds) { 546d9250deaSKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd)); 547d9250deaSKaiGai Kohei 548d9250deaSKaiGai Kohei memcpy(&lo_scontext, scontext, sizeof(lo_scontext)); 549d9250deaSKaiGai Kohei lo_scontext.type = source->bounds; 550d9250deaSKaiGai Kohei 551d9250deaSKaiGai Kohei context_struct_compute_av(&lo_scontext, 552d9250deaSKaiGai Kohei tcontext, 553d9250deaSKaiGai Kohei tclass, 554d9250deaSKaiGai Kohei &lo_avd); 555d9250deaSKaiGai Kohei if ((lo_avd.allowed & avd->allowed) == avd->allowed) 556d9250deaSKaiGai Kohei return; /* no masked permission */ 557d9250deaSKaiGai Kohei masked = ~lo_avd.allowed & avd->allowed; 5582ae3ba39SKaiGai Kohei } 559d9250deaSKaiGai Kohei 5602ae3ba39SKaiGai Kohei if (target->bounds) { 5612ae3ba39SKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd)); 5622ae3ba39SKaiGai Kohei 5632ae3ba39SKaiGai Kohei memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext)); 5642ae3ba39SKaiGai Kohei lo_tcontext.type = target->bounds; 5652ae3ba39SKaiGai Kohei 5662ae3ba39SKaiGai Kohei context_struct_compute_av(scontext, 5672ae3ba39SKaiGai Kohei &lo_tcontext, 5682ae3ba39SKaiGai Kohei tclass, 5692ae3ba39SKaiGai Kohei &lo_avd); 5702ae3ba39SKaiGai Kohei if ((lo_avd.allowed & avd->allowed) == avd->allowed) 5712ae3ba39SKaiGai Kohei return; /* no masked permission */ 5722ae3ba39SKaiGai Kohei masked = ~lo_avd.allowed & avd->allowed; 5732ae3ba39SKaiGai Kohei } 5742ae3ba39SKaiGai Kohei 5752ae3ba39SKaiGai Kohei if (source->bounds && target->bounds) { 5762ae3ba39SKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd)); 5772ae3ba39SKaiGai Kohei /* 5782ae3ba39SKaiGai Kohei * lo_scontext and lo_tcontext are already 5792ae3ba39SKaiGai Kohei * set up. 5802ae3ba39SKaiGai Kohei */ 5812ae3ba39SKaiGai Kohei 5822ae3ba39SKaiGai Kohei context_struct_compute_av(&lo_scontext, 5832ae3ba39SKaiGai Kohei &lo_tcontext, 5842ae3ba39SKaiGai Kohei tclass, 5852ae3ba39SKaiGai Kohei &lo_avd); 5862ae3ba39SKaiGai Kohei if ((lo_avd.allowed & avd->allowed) == avd->allowed) 5872ae3ba39SKaiGai Kohei return; /* no masked permission */ 5882ae3ba39SKaiGai Kohei masked = ~lo_avd.allowed & avd->allowed; 5892ae3ba39SKaiGai Kohei } 5902ae3ba39SKaiGai Kohei 5912ae3ba39SKaiGai Kohei if (masked) { 592d9250deaSKaiGai Kohei /* mask violated permissions */ 593d9250deaSKaiGai Kohei avd->allowed &= ~masked; 594d9250deaSKaiGai Kohei 59544c2d9bdSKaiGai Kohei /* audit masked permissions */ 59644c2d9bdSKaiGai Kohei security_dump_masked_av(scontext, tcontext, 59744c2d9bdSKaiGai Kohei tclass, masked, "bounds"); 598d9250deaSKaiGai Kohei } 599d9250deaSKaiGai Kohei } 600d9250deaSKaiGai Kohei 601d9250deaSKaiGai Kohei /* 6021da177e4SLinus Torvalds * Compute access vectors based on a context structure pair for 6031da177e4SLinus Torvalds * the permissions in a particular class. 6041da177e4SLinus Torvalds */ 60519439d05SStephen Smalley static void context_struct_compute_av(struct context *scontext, 6061da177e4SLinus Torvalds struct context *tcontext, 6071da177e4SLinus Torvalds u16 tclass, 6081da177e4SLinus Torvalds struct av_decision *avd) 6091da177e4SLinus Torvalds { 6101da177e4SLinus Torvalds struct constraint_node *constraint; 6111da177e4SLinus Torvalds struct role_allow *ra; 6121da177e4SLinus Torvalds struct avtab_key avkey; 613782ebb99SStephen Smalley struct avtab_node *node; 6141da177e4SLinus Torvalds struct class_datum *tclass_datum; 615782ebb99SStephen Smalley struct ebitmap *sattr, *tattr; 616782ebb99SStephen Smalley struct ebitmap_node *snode, *tnode; 617782ebb99SStephen Smalley unsigned int i, j; 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds avd->allowed = 0; 6201da177e4SLinus Torvalds avd->auditallow = 0; 6211da177e4SLinus Torvalds avd->auditdeny = 0xffffffff; 6221da177e4SLinus Torvalds 623c6d3aaa4SStephen Smalley if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { 624c6d3aaa4SStephen Smalley if (printk_ratelimit()) 625c6d3aaa4SStephen Smalley printk(KERN_WARNING "SELinux: Invalid class %hu\n", tclass); 62619439d05SStephen Smalley return; 627c6d3aaa4SStephen Smalley } 6283f12070eSEric Paris 6293f12070eSEric Paris tclass_datum = policydb.class_val_to_struct[tclass - 1]; 6303f12070eSEric Paris 6313f12070eSEric Paris /* 6321da177e4SLinus Torvalds * If a specific type enforcement rule was defined for 6331da177e4SLinus Torvalds * this permission check, then use it. 6341da177e4SLinus Torvalds */ 6351da177e4SLinus Torvalds avkey.target_class = tclass; 636782ebb99SStephen Smalley avkey.specified = AVTAB_AV; 6376371dcd3SEric Paris sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); 6386371dcd3SEric Paris BUG_ON(!sattr); 6396371dcd3SEric Paris tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); 6406371dcd3SEric Paris BUG_ON(!tattr); 6419fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(sattr, snode, i) { 6429fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(tattr, tnode, j) { 643782ebb99SStephen Smalley avkey.source_type = i + 1; 644782ebb99SStephen Smalley avkey.target_type = j + 1; 645782ebb99SStephen Smalley for (node = avtab_search_node(&policydb.te_avtab, &avkey); 646dbc74c65SVesa-Matti Kari node; 647782ebb99SStephen Smalley node = avtab_search_node_next(node, avkey.specified)) { 648782ebb99SStephen Smalley if (node->key.specified == AVTAB_ALLOWED) 649782ebb99SStephen Smalley avd->allowed |= node->datum.data; 650782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITALLOW) 651782ebb99SStephen Smalley avd->auditallow |= node->datum.data; 652782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITDENY) 653782ebb99SStephen Smalley avd->auditdeny &= node->datum.data; 6541da177e4SLinus Torvalds } 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds /* Check conditional av table for additional permissions */ 6571da177e4SLinus Torvalds cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); 6581da177e4SLinus Torvalds 659782ebb99SStephen Smalley } 660782ebb99SStephen Smalley } 661782ebb99SStephen Smalley 6621da177e4SLinus Torvalds /* 6631da177e4SLinus Torvalds * Remove any permissions prohibited by a constraint (this includes 6641da177e4SLinus Torvalds * the MLS policy). 6651da177e4SLinus Torvalds */ 6661da177e4SLinus Torvalds constraint = tclass_datum->constraints; 6671da177e4SLinus Torvalds while (constraint) { 6681da177e4SLinus Torvalds if ((constraint->permissions & (avd->allowed)) && 6691da177e4SLinus Torvalds !constraint_expr_eval(scontext, tcontext, NULL, 6701da177e4SLinus Torvalds constraint->expr)) { 671caabbdc0SKaiGai Kohei avd->allowed &= ~(constraint->permissions); 6721da177e4SLinus Torvalds } 6731da177e4SLinus Torvalds constraint = constraint->next; 6741da177e4SLinus Torvalds } 6751da177e4SLinus Torvalds 6761da177e4SLinus Torvalds /* 6771da177e4SLinus Torvalds * If checking process transition permission and the 6781da177e4SLinus Torvalds * role is changing, then check the (current_role, new_role) 6791da177e4SLinus Torvalds * pair. 6801da177e4SLinus Torvalds */ 681c6d3aaa4SStephen Smalley if (tclass == policydb.process_class && 682c6d3aaa4SStephen Smalley (avd->allowed & policydb.process_trans_perms) && 6831da177e4SLinus Torvalds scontext->role != tcontext->role) { 6841da177e4SLinus Torvalds for (ra = policydb.role_allow; ra; ra = ra->next) { 6851da177e4SLinus Torvalds if (scontext->role == ra->role && 6861da177e4SLinus Torvalds tcontext->role == ra->new_role) 6871da177e4SLinus Torvalds break; 6881da177e4SLinus Torvalds } 6891da177e4SLinus Torvalds if (!ra) 690c6d3aaa4SStephen Smalley avd->allowed &= ~policydb.process_trans_perms; 6911da177e4SLinus Torvalds } 6921da177e4SLinus Torvalds 693d9250deaSKaiGai Kohei /* 694d9250deaSKaiGai Kohei * If the given source and target types have boundary 695d9250deaSKaiGai Kohei * constraint, lazy checks have to mask any violated 696d9250deaSKaiGai Kohei * permission and notice it to userspace via audit. 697d9250deaSKaiGai Kohei */ 698d9250deaSKaiGai Kohei type_attribute_bounds_av(scontext, tcontext, 69919439d05SStephen Smalley tclass, avd); 70022df4adbSStephen Smalley } 70122df4adbSStephen Smalley 7021da177e4SLinus Torvalds static int security_validtrans_handle_fail(struct context *ocontext, 7031da177e4SLinus Torvalds struct context *ncontext, 7041da177e4SLinus Torvalds struct context *tcontext, 7051da177e4SLinus Torvalds u16 tclass) 7061da177e4SLinus Torvalds { 7071da177e4SLinus Torvalds char *o = NULL, *n = NULL, *t = NULL; 7081da177e4SLinus Torvalds u32 olen, nlen, tlen; 7091da177e4SLinus Torvalds 7104b02b524SEric Paris if (context_struct_to_string(ocontext, &o, &olen)) 7111da177e4SLinus Torvalds goto out; 7124b02b524SEric Paris if (context_struct_to_string(ncontext, &n, &nlen)) 7131da177e4SLinus Torvalds goto out; 7144b02b524SEric Paris if (context_struct_to_string(tcontext, &t, &tlen)) 7151da177e4SLinus Torvalds goto out; 7169ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 7171da177e4SLinus Torvalds "security_validate_transition: denied for" 7181da177e4SLinus Torvalds " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", 719ac76c05bSEric Paris o, n, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); 7201da177e4SLinus Torvalds out: 7211da177e4SLinus Torvalds kfree(o); 7221da177e4SLinus Torvalds kfree(n); 7231da177e4SLinus Torvalds kfree(t); 7241da177e4SLinus Torvalds 7251da177e4SLinus Torvalds if (!selinux_enforcing) 7261da177e4SLinus Torvalds return 0; 7271da177e4SLinus Torvalds return -EPERM; 7281da177e4SLinus Torvalds } 7291da177e4SLinus Torvalds 7301da177e4SLinus Torvalds int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, 731c6d3aaa4SStephen Smalley u16 orig_tclass) 7321da177e4SLinus Torvalds { 7331da177e4SLinus Torvalds struct context *ocontext; 7341da177e4SLinus Torvalds struct context *ncontext; 7351da177e4SLinus Torvalds struct context *tcontext; 7361da177e4SLinus Torvalds struct class_datum *tclass_datum; 7371da177e4SLinus Torvalds struct constraint_node *constraint; 738c6d3aaa4SStephen Smalley u16 tclass; 7391da177e4SLinus Torvalds int rc = 0; 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds if (!ss_initialized) 7421da177e4SLinus Torvalds return 0; 7431da177e4SLinus Torvalds 7440804d113SJames Morris read_lock(&policy_rwlock); 7451da177e4SLinus Torvalds 746c6d3aaa4SStephen Smalley tclass = unmap_class(orig_tclass); 747c6d3aaa4SStephen Smalley 7481da177e4SLinus Torvalds if (!tclass || tclass > policydb.p_classes.nprim) { 749744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", 750744ba35eSEric Paris __func__, tclass); 7511da177e4SLinus Torvalds rc = -EINVAL; 7521da177e4SLinus Torvalds goto out; 7531da177e4SLinus Torvalds } 7541da177e4SLinus Torvalds tclass_datum = policydb.class_val_to_struct[tclass - 1]; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds ocontext = sidtab_search(&sidtab, oldsid); 7571da177e4SLinus Torvalds if (!ocontext) { 758744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 759744ba35eSEric Paris __func__, oldsid); 7601da177e4SLinus Torvalds rc = -EINVAL; 7611da177e4SLinus Torvalds goto out; 7621da177e4SLinus Torvalds } 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds ncontext = sidtab_search(&sidtab, newsid); 7651da177e4SLinus Torvalds if (!ncontext) { 766744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 767744ba35eSEric Paris __func__, newsid); 7681da177e4SLinus Torvalds rc = -EINVAL; 7691da177e4SLinus Torvalds goto out; 7701da177e4SLinus Torvalds } 7711da177e4SLinus Torvalds 7721da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tasksid); 7731da177e4SLinus Torvalds if (!tcontext) { 774744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 775744ba35eSEric Paris __func__, tasksid); 7761da177e4SLinus Torvalds rc = -EINVAL; 7771da177e4SLinus Torvalds goto out; 7781da177e4SLinus Torvalds } 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds constraint = tclass_datum->validatetrans; 7811da177e4SLinus Torvalds while (constraint) { 7821da177e4SLinus Torvalds if (!constraint_expr_eval(ocontext, ncontext, tcontext, 7831da177e4SLinus Torvalds constraint->expr)) { 7841da177e4SLinus Torvalds rc = security_validtrans_handle_fail(ocontext, ncontext, 7851da177e4SLinus Torvalds tcontext, tclass); 7861da177e4SLinus Torvalds goto out; 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds constraint = constraint->next; 7891da177e4SLinus Torvalds } 7901da177e4SLinus Torvalds 7911da177e4SLinus Torvalds out: 7920804d113SJames Morris read_unlock(&policy_rwlock); 7931da177e4SLinus Torvalds return rc; 7941da177e4SLinus Torvalds } 7951da177e4SLinus Torvalds 796d9250deaSKaiGai Kohei /* 797d9250deaSKaiGai Kohei * security_bounded_transition - check whether the given 798d9250deaSKaiGai Kohei * transition is directed to bounded, or not. 799d9250deaSKaiGai Kohei * It returns 0, if @newsid is bounded by @oldsid. 800d9250deaSKaiGai Kohei * Otherwise, it returns error code. 801d9250deaSKaiGai Kohei * 802d9250deaSKaiGai Kohei * @oldsid : current security identifier 803d9250deaSKaiGai Kohei * @newsid : destinated security identifier 804d9250deaSKaiGai Kohei */ 805d9250deaSKaiGai Kohei int security_bounded_transition(u32 old_sid, u32 new_sid) 806d9250deaSKaiGai Kohei { 807d9250deaSKaiGai Kohei struct context *old_context, *new_context; 808d9250deaSKaiGai Kohei struct type_datum *type; 809d9250deaSKaiGai Kohei int index; 8104b02b524SEric Paris int rc; 811d9250deaSKaiGai Kohei 812d9250deaSKaiGai Kohei read_lock(&policy_rwlock); 813d9250deaSKaiGai Kohei 8144b02b524SEric Paris rc = -EINVAL; 815d9250deaSKaiGai Kohei old_context = sidtab_search(&sidtab, old_sid); 816d9250deaSKaiGai Kohei if (!old_context) { 817d9250deaSKaiGai Kohei printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", 818d9250deaSKaiGai Kohei __func__, old_sid); 819d9250deaSKaiGai Kohei goto out; 820d9250deaSKaiGai Kohei } 821d9250deaSKaiGai Kohei 8224b02b524SEric Paris rc = -EINVAL; 823d9250deaSKaiGai Kohei new_context = sidtab_search(&sidtab, new_sid); 824d9250deaSKaiGai Kohei if (!new_context) { 825d9250deaSKaiGai Kohei printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n", 826d9250deaSKaiGai Kohei __func__, new_sid); 827d9250deaSKaiGai Kohei goto out; 828d9250deaSKaiGai Kohei } 829d9250deaSKaiGai Kohei 830d9250deaSKaiGai Kohei rc = 0; 8314b02b524SEric Paris /* type/domain unchanged */ 8324b02b524SEric Paris if (old_context->type == new_context->type) 833d9250deaSKaiGai Kohei goto out; 834d9250deaSKaiGai Kohei 835d9250deaSKaiGai Kohei index = new_context->type; 836d9250deaSKaiGai Kohei while (true) { 83723bdecb0SEric Paris type = flex_array_get_ptr(policydb.type_val_to_struct_array, 83823bdecb0SEric Paris index - 1); 839d9250deaSKaiGai Kohei BUG_ON(!type); 840d9250deaSKaiGai Kohei 841d9250deaSKaiGai Kohei /* not bounded anymore */ 842d9250deaSKaiGai Kohei rc = -EPERM; 8434b02b524SEric Paris if (!type->bounds) 844d9250deaSKaiGai Kohei break; 845d9250deaSKaiGai Kohei 846d9250deaSKaiGai Kohei /* @newsid is bounded by @oldsid */ 847d9250deaSKaiGai Kohei rc = 0; 8484b02b524SEric Paris if (type->bounds == old_context->type) 849d9250deaSKaiGai Kohei break; 8504b02b524SEric Paris 851d9250deaSKaiGai Kohei index = type->bounds; 852d9250deaSKaiGai Kohei } 85344c2d9bdSKaiGai Kohei 85444c2d9bdSKaiGai Kohei if (rc) { 85544c2d9bdSKaiGai Kohei char *old_name = NULL; 85644c2d9bdSKaiGai Kohei char *new_name = NULL; 8572da5d31bSJames Morris u32 length; 85844c2d9bdSKaiGai Kohei 85944c2d9bdSKaiGai Kohei if (!context_struct_to_string(old_context, 86044c2d9bdSKaiGai Kohei &old_name, &length) && 86144c2d9bdSKaiGai Kohei !context_struct_to_string(new_context, 86244c2d9bdSKaiGai Kohei &new_name, &length)) { 86344c2d9bdSKaiGai Kohei audit_log(current->audit_context, 86444c2d9bdSKaiGai Kohei GFP_ATOMIC, AUDIT_SELINUX_ERR, 86544c2d9bdSKaiGai Kohei "op=security_bounded_transition " 86644c2d9bdSKaiGai Kohei "result=denied " 86744c2d9bdSKaiGai Kohei "oldcontext=%s newcontext=%s", 86844c2d9bdSKaiGai Kohei old_name, new_name); 86944c2d9bdSKaiGai Kohei } 87044c2d9bdSKaiGai Kohei kfree(new_name); 87144c2d9bdSKaiGai Kohei kfree(old_name); 87244c2d9bdSKaiGai Kohei } 873d9250deaSKaiGai Kohei out: 874d9250deaSKaiGai Kohei read_unlock(&policy_rwlock); 875d9250deaSKaiGai Kohei 876d9250deaSKaiGai Kohei return rc; 877d9250deaSKaiGai Kohei } 878d9250deaSKaiGai Kohei 87919439d05SStephen Smalley static void avd_init(struct av_decision *avd) 880c6d3aaa4SStephen Smalley { 88119439d05SStephen Smalley avd->allowed = 0; 88219439d05SStephen Smalley avd->auditallow = 0; 88319439d05SStephen Smalley avd->auditdeny = 0xffffffff; 88419439d05SStephen Smalley avd->seqno = latest_granting; 88519439d05SStephen Smalley avd->flags = 0; 886c6d3aaa4SStephen Smalley } 887c6d3aaa4SStephen Smalley 888c6d3aaa4SStephen Smalley 8891da177e4SLinus Torvalds /** 8901da177e4SLinus Torvalds * security_compute_av - Compute access vector decisions. 8911da177e4SLinus Torvalds * @ssid: source security identifier 8921da177e4SLinus Torvalds * @tsid: target security identifier 8931da177e4SLinus Torvalds * @tclass: target security class 8941da177e4SLinus Torvalds * @avd: access vector decisions 8951da177e4SLinus Torvalds * 8961da177e4SLinus Torvalds * Compute a set of access vector decisions based on the 8971da177e4SLinus Torvalds * SID pair (@ssid, @tsid) for the permissions in @tclass. 8981da177e4SLinus Torvalds */ 89919439d05SStephen Smalley void security_compute_av(u32 ssid, 9001da177e4SLinus Torvalds u32 tsid, 901c6d3aaa4SStephen Smalley u16 orig_tclass, 902c6d3aaa4SStephen Smalley struct av_decision *avd) 903c6d3aaa4SStephen Smalley { 904c6d3aaa4SStephen Smalley u16 tclass; 90519439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL; 906c6d3aaa4SStephen Smalley 907b7f3008aSStephen Smalley read_lock(&policy_rwlock); 90819439d05SStephen Smalley avd_init(avd); 909c6d3aaa4SStephen Smalley if (!ss_initialized) 910c6d3aaa4SStephen Smalley goto allow; 911c6d3aaa4SStephen Smalley 91219439d05SStephen Smalley scontext = sidtab_search(&sidtab, ssid); 91319439d05SStephen Smalley if (!scontext) { 91419439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 91519439d05SStephen Smalley __func__, ssid); 91619439d05SStephen Smalley goto out; 91719439d05SStephen Smalley } 91819439d05SStephen Smalley 91919439d05SStephen Smalley /* permissive domain? */ 92019439d05SStephen Smalley if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) 92119439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE; 92219439d05SStephen Smalley 92319439d05SStephen Smalley tcontext = sidtab_search(&sidtab, tsid); 92419439d05SStephen Smalley if (!tcontext) { 92519439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 92619439d05SStephen Smalley __func__, tsid); 92719439d05SStephen Smalley goto out; 92819439d05SStephen Smalley } 92919439d05SStephen Smalley 930c6d3aaa4SStephen Smalley tclass = unmap_class(orig_tclass); 931c6d3aaa4SStephen Smalley if (unlikely(orig_tclass && !tclass)) { 932c6d3aaa4SStephen Smalley if (policydb.allow_unknown) 933c6d3aaa4SStephen Smalley goto allow; 934b7f3008aSStephen Smalley goto out; 935c6d3aaa4SStephen Smalley } 93619439d05SStephen Smalley context_struct_compute_av(scontext, tcontext, tclass, avd); 937c6d3aaa4SStephen Smalley map_decision(orig_tclass, avd, policydb.allow_unknown); 938b7f3008aSStephen Smalley out: 939c6d3aaa4SStephen Smalley read_unlock(&policy_rwlock); 94019439d05SStephen Smalley return; 941c6d3aaa4SStephen Smalley allow: 942c6d3aaa4SStephen Smalley avd->allowed = 0xffffffff; 943b7f3008aSStephen Smalley goto out; 944c6d3aaa4SStephen Smalley } 945c6d3aaa4SStephen Smalley 94619439d05SStephen Smalley void security_compute_av_user(u32 ssid, 947c6d3aaa4SStephen Smalley u32 tsid, 9481da177e4SLinus Torvalds u16 tclass, 9491da177e4SLinus Torvalds struct av_decision *avd) 9501da177e4SLinus Torvalds { 95119439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL; 9521da177e4SLinus Torvalds 9530804d113SJames Morris read_lock(&policy_rwlock); 95419439d05SStephen Smalley avd_init(avd); 95519439d05SStephen Smalley if (!ss_initialized) 95619439d05SStephen Smalley goto allow; 95719439d05SStephen Smalley 95819439d05SStephen Smalley scontext = sidtab_search(&sidtab, ssid); 95919439d05SStephen Smalley if (!scontext) { 96019439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 96119439d05SStephen Smalley __func__, ssid); 96219439d05SStephen Smalley goto out; 96319439d05SStephen Smalley } 96419439d05SStephen Smalley 96519439d05SStephen Smalley /* permissive domain? */ 96619439d05SStephen Smalley if (ebitmap_get_bit(&policydb.permissive_map, scontext->type)) 96719439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE; 96819439d05SStephen Smalley 96919439d05SStephen Smalley tcontext = sidtab_search(&sidtab, tsid); 97019439d05SStephen Smalley if (!tcontext) { 97119439d05SStephen Smalley printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 97219439d05SStephen Smalley __func__, tsid); 97319439d05SStephen Smalley goto out; 97419439d05SStephen Smalley } 97519439d05SStephen Smalley 97619439d05SStephen Smalley if (unlikely(!tclass)) { 97719439d05SStephen Smalley if (policydb.allow_unknown) 97819439d05SStephen Smalley goto allow; 97919439d05SStephen Smalley goto out; 98019439d05SStephen Smalley } 98119439d05SStephen Smalley 98219439d05SStephen Smalley context_struct_compute_av(scontext, tcontext, tclass, avd); 98319439d05SStephen Smalley out: 9840804d113SJames Morris read_unlock(&policy_rwlock); 98519439d05SStephen Smalley return; 98619439d05SStephen Smalley allow: 98719439d05SStephen Smalley avd->allowed = 0xffffffff; 98819439d05SStephen Smalley goto out; 9891da177e4SLinus Torvalds } 9901da177e4SLinus Torvalds 9911da177e4SLinus Torvalds /* 9921da177e4SLinus Torvalds * Write the security context string representation of 9931da177e4SLinus Torvalds * the context structure `context' into a dynamically 9941da177e4SLinus Torvalds * allocated string of the correct size. Set `*scontext' 9951da177e4SLinus Torvalds * to point to this string and set `*scontext_len' to 9961da177e4SLinus Torvalds * the length of the string. 9971da177e4SLinus Torvalds */ 9981da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len) 9991da177e4SLinus Torvalds { 10001da177e4SLinus Torvalds char *scontextp; 10011da177e4SLinus Torvalds 1002d5630b9dSEric Paris if (scontext) 10031da177e4SLinus Torvalds *scontext = NULL; 10041da177e4SLinus Torvalds *scontext_len = 0; 10051da177e4SLinus Torvalds 100612b29f34SStephen Smalley if (context->len) { 100712b29f34SStephen Smalley *scontext_len = context->len; 100812b29f34SStephen Smalley *scontext = kstrdup(context->str, GFP_ATOMIC); 100912b29f34SStephen Smalley if (!(*scontext)) 101012b29f34SStephen Smalley return -ENOMEM; 101112b29f34SStephen Smalley return 0; 101212b29f34SStephen Smalley } 101312b29f34SStephen Smalley 10141da177e4SLinus Torvalds /* Compute the size of the context. */ 1015ac76c05bSEric Paris *scontext_len += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1; 1016ac76c05bSEric Paris *scontext_len += strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1; 1017ac76c05bSEric Paris *scontext_len += strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)) + 1; 10181da177e4SLinus Torvalds *scontext_len += mls_compute_context_len(context); 10191da177e4SLinus Torvalds 1020d5630b9dSEric Paris if (!scontext) 1021d5630b9dSEric Paris return 0; 1022d5630b9dSEric Paris 10231da177e4SLinus Torvalds /* Allocate space for the context; caller must free this space. */ 10241da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 10255d55a345SEric Paris if (!scontextp) 10261da177e4SLinus Torvalds return -ENOMEM; 10271da177e4SLinus Torvalds *scontext = scontextp; 10281da177e4SLinus Torvalds 10291da177e4SLinus Torvalds /* 10301da177e4SLinus Torvalds * Copy the user name, role name and type name into the context. 10311da177e4SLinus Torvalds */ 10321da177e4SLinus Torvalds sprintf(scontextp, "%s:%s:%s", 1033ac76c05bSEric Paris sym_name(&policydb, SYM_USERS, context->user - 1), 1034ac76c05bSEric Paris sym_name(&policydb, SYM_ROLES, context->role - 1), 1035ac76c05bSEric Paris sym_name(&policydb, SYM_TYPES, context->type - 1)); 1036ac76c05bSEric Paris scontextp += strlen(sym_name(&policydb, SYM_USERS, context->user - 1)) + 1037ac76c05bSEric Paris 1 + strlen(sym_name(&policydb, SYM_ROLES, context->role - 1)) + 1038ac76c05bSEric Paris 1 + strlen(sym_name(&policydb, SYM_TYPES, context->type - 1)); 10391da177e4SLinus Torvalds 10401da177e4SLinus Torvalds mls_sid_to_context(context, &scontextp); 10411da177e4SLinus Torvalds 10421da177e4SLinus Torvalds *scontextp = 0; 10431da177e4SLinus Torvalds 10441da177e4SLinus Torvalds return 0; 10451da177e4SLinus Torvalds } 10461da177e4SLinus Torvalds 10471da177e4SLinus Torvalds #include "initial_sid_to_string.h" 10481da177e4SLinus Torvalds 1049f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid) 1050f0ee2e46SJames Carter { 1051f0ee2e46SJames Carter if (unlikely(sid > SECINITSID_NUM)) 1052f0ee2e46SJames Carter return NULL; 1053f0ee2e46SJames Carter return initial_sid_to_string[sid]; 1054f0ee2e46SJames Carter } 1055f0ee2e46SJames Carter 105612b29f34SStephen Smalley static int security_sid_to_context_core(u32 sid, char **scontext, 105712b29f34SStephen Smalley u32 *scontext_len, int force) 10581da177e4SLinus Torvalds { 10591da177e4SLinus Torvalds struct context *context; 10601da177e4SLinus Torvalds int rc = 0; 10611da177e4SLinus Torvalds 1062d5630b9dSEric Paris if (scontext) 10634f4acf3aSStephen Smalley *scontext = NULL; 10644f4acf3aSStephen Smalley *scontext_len = 0; 10654f4acf3aSStephen Smalley 10661da177e4SLinus Torvalds if (!ss_initialized) { 10671da177e4SLinus Torvalds if (sid <= SECINITSID_NUM) { 10681da177e4SLinus Torvalds char *scontextp; 10691da177e4SLinus Torvalds 10701da177e4SLinus Torvalds *scontext_len = strlen(initial_sid_to_string[sid]) + 1; 1071d5630b9dSEric Paris if (!scontext) 1072d5630b9dSEric Paris goto out; 10731da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 10740cccca06SSerge E. Hallyn if (!scontextp) { 10750cccca06SSerge E. Hallyn rc = -ENOMEM; 10760cccca06SSerge E. Hallyn goto out; 10770cccca06SSerge E. Hallyn } 10781da177e4SLinus Torvalds strcpy(scontextp, initial_sid_to_string[sid]); 10791da177e4SLinus Torvalds *scontext = scontextp; 10801da177e4SLinus Torvalds goto out; 10811da177e4SLinus Torvalds } 1082744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: called before initial " 1083744ba35eSEric Paris "load_policy on unknown SID %d\n", __func__, sid); 10841da177e4SLinus Torvalds rc = -EINVAL; 10851da177e4SLinus Torvalds goto out; 10861da177e4SLinus Torvalds } 10870804d113SJames Morris read_lock(&policy_rwlock); 108812b29f34SStephen Smalley if (force) 108912b29f34SStephen Smalley context = sidtab_search_force(&sidtab, sid); 109012b29f34SStephen Smalley else 10911da177e4SLinus Torvalds context = sidtab_search(&sidtab, sid); 10921da177e4SLinus Torvalds if (!context) { 1093744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1094744ba35eSEric Paris __func__, sid); 10951da177e4SLinus Torvalds rc = -EINVAL; 10961da177e4SLinus Torvalds goto out_unlock; 10971da177e4SLinus Torvalds } 10981da177e4SLinus Torvalds rc = context_struct_to_string(context, scontext, scontext_len); 10991da177e4SLinus Torvalds out_unlock: 11000804d113SJames Morris read_unlock(&policy_rwlock); 11011da177e4SLinus Torvalds out: 11021da177e4SLinus Torvalds return rc; 11031da177e4SLinus Torvalds 11041da177e4SLinus Torvalds } 11051da177e4SLinus Torvalds 110612b29f34SStephen Smalley /** 110712b29f34SStephen Smalley * security_sid_to_context - Obtain a context for a given SID. 110812b29f34SStephen Smalley * @sid: security identifier, SID 110912b29f34SStephen Smalley * @scontext: security context 111012b29f34SStephen Smalley * @scontext_len: length in bytes 111112b29f34SStephen Smalley * 111212b29f34SStephen Smalley * Write the string representation of the context associated with @sid 111312b29f34SStephen Smalley * into a dynamically allocated string of the correct size. Set @scontext 111412b29f34SStephen Smalley * to point to this string and set @scontext_len to the length of the string. 111512b29f34SStephen Smalley */ 111612b29f34SStephen Smalley int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) 11171da177e4SLinus Torvalds { 111812b29f34SStephen Smalley return security_sid_to_context_core(sid, scontext, scontext_len, 0); 111912b29f34SStephen Smalley } 112012b29f34SStephen Smalley 112112b29f34SStephen Smalley int security_sid_to_context_force(u32 sid, char **scontext, u32 *scontext_len) 112212b29f34SStephen Smalley { 112312b29f34SStephen Smalley return security_sid_to_context_core(sid, scontext, scontext_len, 1); 112412b29f34SStephen Smalley } 112512b29f34SStephen Smalley 11269a59daa0SStephen Smalley /* 11279a59daa0SStephen Smalley * Caveat: Mutates scontext. 11289a59daa0SStephen Smalley */ 112912b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol, 113012b29f34SStephen Smalley struct sidtab *sidtabp, 11319a59daa0SStephen Smalley char *scontext, 113212b29f34SStephen Smalley u32 scontext_len, 113312b29f34SStephen Smalley struct context *ctx, 11349a59daa0SStephen Smalley u32 def_sid) 113512b29f34SStephen Smalley { 11361da177e4SLinus Torvalds struct role_datum *role; 11371da177e4SLinus Torvalds struct type_datum *typdatum; 11381da177e4SLinus Torvalds struct user_datum *usrdatum; 11391da177e4SLinus Torvalds char *scontextp, *p, oldc; 11401da177e4SLinus Torvalds int rc = 0; 11411da177e4SLinus Torvalds 114212b29f34SStephen Smalley context_init(ctx); 114312b29f34SStephen Smalley 114412b29f34SStephen Smalley /* Parse the security context. */ 114512b29f34SStephen Smalley 114612b29f34SStephen Smalley rc = -EINVAL; 11479a59daa0SStephen Smalley scontextp = (char *) scontext; 114812b29f34SStephen Smalley 114912b29f34SStephen Smalley /* Extract the user. */ 115012b29f34SStephen Smalley p = scontextp; 115112b29f34SStephen Smalley while (*p && *p != ':') 115212b29f34SStephen Smalley p++; 115312b29f34SStephen Smalley 115412b29f34SStephen Smalley if (*p == 0) 115512b29f34SStephen Smalley goto out; 115612b29f34SStephen Smalley 115712b29f34SStephen Smalley *p++ = 0; 115812b29f34SStephen Smalley 115912b29f34SStephen Smalley usrdatum = hashtab_search(pol->p_users.table, scontextp); 116012b29f34SStephen Smalley if (!usrdatum) 116112b29f34SStephen Smalley goto out; 116212b29f34SStephen Smalley 116312b29f34SStephen Smalley ctx->user = usrdatum->value; 116412b29f34SStephen Smalley 116512b29f34SStephen Smalley /* Extract role. */ 116612b29f34SStephen Smalley scontextp = p; 116712b29f34SStephen Smalley while (*p && *p != ':') 116812b29f34SStephen Smalley p++; 116912b29f34SStephen Smalley 117012b29f34SStephen Smalley if (*p == 0) 117112b29f34SStephen Smalley goto out; 117212b29f34SStephen Smalley 117312b29f34SStephen Smalley *p++ = 0; 117412b29f34SStephen Smalley 117512b29f34SStephen Smalley role = hashtab_search(pol->p_roles.table, scontextp); 117612b29f34SStephen Smalley if (!role) 117712b29f34SStephen Smalley goto out; 117812b29f34SStephen Smalley ctx->role = role->value; 117912b29f34SStephen Smalley 118012b29f34SStephen Smalley /* Extract type. */ 118112b29f34SStephen Smalley scontextp = p; 118212b29f34SStephen Smalley while (*p && *p != ':') 118312b29f34SStephen Smalley p++; 118412b29f34SStephen Smalley oldc = *p; 118512b29f34SStephen Smalley *p++ = 0; 118612b29f34SStephen Smalley 118712b29f34SStephen Smalley typdatum = hashtab_search(pol->p_types.table, scontextp); 1188d9250deaSKaiGai Kohei if (!typdatum || typdatum->attribute) 118912b29f34SStephen Smalley goto out; 119012b29f34SStephen Smalley 119112b29f34SStephen Smalley ctx->type = typdatum->value; 119212b29f34SStephen Smalley 119312b29f34SStephen Smalley rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid); 119412b29f34SStephen Smalley if (rc) 119512b29f34SStephen Smalley goto out; 119612b29f34SStephen Smalley 119712b29f34SStephen Smalley rc = -EINVAL; 11984b02b524SEric Paris if ((p - scontext) < scontext_len) 119912b29f34SStephen Smalley goto out; 120012b29f34SStephen Smalley 120112b29f34SStephen Smalley /* Check the validity of the new context. */ 12024b02b524SEric Paris if (!policydb_context_isvalid(pol, ctx)) 120312b29f34SStephen Smalley goto out; 120412b29f34SStephen Smalley rc = 0; 120512b29f34SStephen Smalley out: 12068e531af9SEric Paris if (rc) 12078e531af9SEric Paris context_destroy(ctx); 120812b29f34SStephen Smalley return rc; 120912b29f34SStephen Smalley } 121012b29f34SStephen Smalley 121112b29f34SStephen Smalley static int security_context_to_sid_core(const char *scontext, u32 scontext_len, 121212b29f34SStephen Smalley u32 *sid, u32 def_sid, gfp_t gfp_flags, 121312b29f34SStephen Smalley int force) 121412b29f34SStephen Smalley { 12159a59daa0SStephen Smalley char *scontext2, *str = NULL; 121612b29f34SStephen Smalley struct context context; 121712b29f34SStephen Smalley int rc = 0; 121812b29f34SStephen Smalley 12191da177e4SLinus Torvalds if (!ss_initialized) { 12201da177e4SLinus Torvalds int i; 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds for (i = 1; i < SECINITSID_NUM; i++) { 12231da177e4SLinus Torvalds if (!strcmp(initial_sid_to_string[i], scontext)) { 12241da177e4SLinus Torvalds *sid = i; 12259a59daa0SStephen Smalley return 0; 12261da177e4SLinus Torvalds } 12271da177e4SLinus Torvalds } 12281da177e4SLinus Torvalds *sid = SECINITSID_KERNEL; 12299a59daa0SStephen Smalley return 0; 12301da177e4SLinus Torvalds } 12311da177e4SLinus Torvalds *sid = SECSID_NULL; 12321da177e4SLinus Torvalds 12339a59daa0SStephen Smalley /* Copy the string so that we can modify the copy as we parse it. */ 12349a59daa0SStephen Smalley scontext2 = kmalloc(scontext_len + 1, gfp_flags); 12359a59daa0SStephen Smalley if (!scontext2) 12369a59daa0SStephen Smalley return -ENOMEM; 12379a59daa0SStephen Smalley memcpy(scontext2, scontext, scontext_len); 12389a59daa0SStephen Smalley scontext2[scontext_len] = 0; 12399a59daa0SStephen Smalley 12409a59daa0SStephen Smalley if (force) { 12419a59daa0SStephen Smalley /* Save another copy for storing in uninterpreted form */ 12424b02b524SEric Paris rc = -ENOMEM; 12439a59daa0SStephen Smalley str = kstrdup(scontext2, gfp_flags); 12444b02b524SEric Paris if (!str) 12454b02b524SEric Paris goto out; 12469a59daa0SStephen Smalley } 12479a59daa0SStephen Smalley 12480804d113SJames Morris read_lock(&policy_rwlock); 12494b02b524SEric Paris rc = string_to_context_struct(&policydb, &sidtab, scontext2, 12504b02b524SEric Paris scontext_len, &context, def_sid); 125112b29f34SStephen Smalley if (rc == -EINVAL && force) { 12529a59daa0SStephen Smalley context.str = str; 125312b29f34SStephen Smalley context.len = scontext_len; 12549a59daa0SStephen Smalley str = NULL; 125512b29f34SStephen Smalley } else if (rc) 12564b02b524SEric Paris goto out_unlock; 12571da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &context, sid); 12581da177e4SLinus Torvalds context_destroy(&context); 12594b02b524SEric Paris out_unlock: 12600804d113SJames Morris read_unlock(&policy_rwlock); 12614b02b524SEric Paris out: 12629a59daa0SStephen Smalley kfree(scontext2); 12639a59daa0SStephen Smalley kfree(str); 12641da177e4SLinus Torvalds return rc; 12651da177e4SLinus Torvalds } 12661da177e4SLinus Torvalds 1267f5c1d5b2SJames Morris /** 1268f5c1d5b2SJames Morris * security_context_to_sid - Obtain a SID for a given security context. 1269f5c1d5b2SJames Morris * @scontext: security context 1270f5c1d5b2SJames Morris * @scontext_len: length in bytes 1271f5c1d5b2SJames Morris * @sid: security identifier, SID 1272f5c1d5b2SJames Morris * 1273f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 1274f5c1d5b2SJames Morris * has the string representation specified by @scontext. 1275f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 1276f5c1d5b2SJames Morris * memory is available, or 0 on success. 1277f5c1d5b2SJames Morris */ 12788f0cfa52SDavid Howells int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) 1279f5c1d5b2SJames Morris { 1280f5c1d5b2SJames Morris return security_context_to_sid_core(scontext, scontext_len, 128112b29f34SStephen Smalley sid, SECSID_NULL, GFP_KERNEL, 0); 1282f5c1d5b2SJames Morris } 1283f5c1d5b2SJames Morris 1284f5c1d5b2SJames Morris /** 1285f5c1d5b2SJames Morris * security_context_to_sid_default - Obtain a SID for a given security context, 1286f5c1d5b2SJames Morris * falling back to specified default if needed. 1287f5c1d5b2SJames Morris * 1288f5c1d5b2SJames Morris * @scontext: security context 1289f5c1d5b2SJames Morris * @scontext_len: length in bytes 1290f5c1d5b2SJames Morris * @sid: security identifier, SID 1291d133a960SGabriel Craciunescu * @def_sid: default SID to assign on error 1292f5c1d5b2SJames Morris * 1293f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 1294f5c1d5b2SJames Morris * has the string representation specified by @scontext. 1295f5c1d5b2SJames Morris * The default SID is passed to the MLS layer to be used to allow 1296f5c1d5b2SJames Morris * kernel labeling of the MLS field if the MLS field is not present 1297f5c1d5b2SJames Morris * (for upgrading to MLS without full relabel). 129812b29f34SStephen Smalley * Implicitly forces adding of the context even if it cannot be mapped yet. 1299f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 1300f5c1d5b2SJames Morris * memory is available, or 0 on success. 1301f5c1d5b2SJames Morris */ 13027bf570dcSDavid Howells int security_context_to_sid_default(const char *scontext, u32 scontext_len, 13037bf570dcSDavid Howells u32 *sid, u32 def_sid, gfp_t gfp_flags) 1304f5c1d5b2SJames Morris { 1305f5c1d5b2SJames Morris return security_context_to_sid_core(scontext, scontext_len, 130612b29f34SStephen Smalley sid, def_sid, gfp_flags, 1); 130712b29f34SStephen Smalley } 130812b29f34SStephen Smalley 130912b29f34SStephen Smalley int security_context_to_sid_force(const char *scontext, u32 scontext_len, 131012b29f34SStephen Smalley u32 *sid) 131112b29f34SStephen Smalley { 131212b29f34SStephen Smalley return security_context_to_sid_core(scontext, scontext_len, 131312b29f34SStephen Smalley sid, SECSID_NULL, GFP_KERNEL, 1); 1314f5c1d5b2SJames Morris } 1315f5c1d5b2SJames Morris 13161da177e4SLinus Torvalds static int compute_sid_handle_invalid_context( 13171da177e4SLinus Torvalds struct context *scontext, 13181da177e4SLinus Torvalds struct context *tcontext, 13191da177e4SLinus Torvalds u16 tclass, 13201da177e4SLinus Torvalds struct context *newcontext) 13211da177e4SLinus Torvalds { 13221da177e4SLinus Torvalds char *s = NULL, *t = NULL, *n = NULL; 13231da177e4SLinus Torvalds u32 slen, tlen, nlen; 13241da177e4SLinus Torvalds 13254b02b524SEric Paris if (context_struct_to_string(scontext, &s, &slen)) 13261da177e4SLinus Torvalds goto out; 13274b02b524SEric Paris if (context_struct_to_string(tcontext, &t, &tlen)) 13281da177e4SLinus Torvalds goto out; 13294b02b524SEric Paris if (context_struct_to_string(newcontext, &n, &nlen)) 13301da177e4SLinus Torvalds goto out; 13319ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 13321da177e4SLinus Torvalds "security_compute_sid: invalid context %s" 13331da177e4SLinus Torvalds " for scontext=%s" 13341da177e4SLinus Torvalds " tcontext=%s" 13351da177e4SLinus Torvalds " tclass=%s", 1336ac76c05bSEric Paris n, s, t, sym_name(&policydb, SYM_CLASSES, tclass-1)); 13371da177e4SLinus Torvalds out: 13381da177e4SLinus Torvalds kfree(s); 13391da177e4SLinus Torvalds kfree(t); 13401da177e4SLinus Torvalds kfree(n); 13411da177e4SLinus Torvalds if (!selinux_enforcing) 13421da177e4SLinus Torvalds return 0; 13431da177e4SLinus Torvalds return -EACCES; 13441da177e4SLinus Torvalds } 13451da177e4SLinus Torvalds 13461da177e4SLinus Torvalds static int security_compute_sid(u32 ssid, 13471da177e4SLinus Torvalds u32 tsid, 1348c6d3aaa4SStephen Smalley u16 orig_tclass, 13491da177e4SLinus Torvalds u32 specified, 1350c6d3aaa4SStephen Smalley u32 *out_sid, 1351c6d3aaa4SStephen Smalley bool kern) 13521da177e4SLinus Torvalds { 13531da177e4SLinus Torvalds struct context *scontext = NULL, *tcontext = NULL, newcontext; 13541da177e4SLinus Torvalds struct role_trans *roletr = NULL; 13551da177e4SLinus Torvalds struct avtab_key avkey; 13561da177e4SLinus Torvalds struct avtab_datum *avdatum; 13571da177e4SLinus Torvalds struct avtab_node *node; 1358c6d3aaa4SStephen Smalley u16 tclass; 13591da177e4SLinus Torvalds int rc = 0; 13601da177e4SLinus Torvalds 13611da177e4SLinus Torvalds if (!ss_initialized) { 1362c6d3aaa4SStephen Smalley switch (orig_tclass) { 1363c6d3aaa4SStephen Smalley case SECCLASS_PROCESS: /* kernel value */ 13641da177e4SLinus Torvalds *out_sid = ssid; 13651da177e4SLinus Torvalds break; 13661da177e4SLinus Torvalds default: 13671da177e4SLinus Torvalds *out_sid = tsid; 13681da177e4SLinus Torvalds break; 13691da177e4SLinus Torvalds } 13701da177e4SLinus Torvalds goto out; 13711da177e4SLinus Torvalds } 13721da177e4SLinus Torvalds 1373851f8a69SVenkat Yekkirala context_init(&newcontext); 1374851f8a69SVenkat Yekkirala 13750804d113SJames Morris read_lock(&policy_rwlock); 13761da177e4SLinus Torvalds 1377c6d3aaa4SStephen Smalley if (kern) 1378c6d3aaa4SStephen Smalley tclass = unmap_class(orig_tclass); 1379c6d3aaa4SStephen Smalley else 1380c6d3aaa4SStephen Smalley tclass = orig_tclass; 1381c6d3aaa4SStephen Smalley 13821da177e4SLinus Torvalds scontext = sidtab_search(&sidtab, ssid); 13831da177e4SLinus Torvalds if (!scontext) { 1384744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1385744ba35eSEric Paris __func__, ssid); 13861da177e4SLinus Torvalds rc = -EINVAL; 13871da177e4SLinus Torvalds goto out_unlock; 13881da177e4SLinus Torvalds } 13891da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tsid); 13901da177e4SLinus Torvalds if (!tcontext) { 1391744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 1392744ba35eSEric Paris __func__, tsid); 13931da177e4SLinus Torvalds rc = -EINVAL; 13941da177e4SLinus Torvalds goto out_unlock; 13951da177e4SLinus Torvalds } 13961da177e4SLinus Torvalds 13971da177e4SLinus Torvalds /* Set the user identity. */ 13981da177e4SLinus Torvalds switch (specified) { 13991da177e4SLinus Torvalds case AVTAB_TRANSITION: 14001da177e4SLinus Torvalds case AVTAB_CHANGE: 14011da177e4SLinus Torvalds /* Use the process user identity. */ 14021da177e4SLinus Torvalds newcontext.user = scontext->user; 14031da177e4SLinus Torvalds break; 14041da177e4SLinus Torvalds case AVTAB_MEMBER: 14051da177e4SLinus Torvalds /* Use the related object owner. */ 14061da177e4SLinus Torvalds newcontext.user = tcontext->user; 14071da177e4SLinus Torvalds break; 14081da177e4SLinus Torvalds } 14091da177e4SLinus Torvalds 14101da177e4SLinus Torvalds /* Set the role and type to default values. */ 1411c6d3aaa4SStephen Smalley if (tclass == policydb.process_class) { 14121da177e4SLinus Torvalds /* Use the current role and type of process. */ 14131da177e4SLinus Torvalds newcontext.role = scontext->role; 14141da177e4SLinus Torvalds newcontext.type = scontext->type; 1415c6d3aaa4SStephen Smalley } else { 14161da177e4SLinus Torvalds /* Use the well-defined object role. */ 14171da177e4SLinus Torvalds newcontext.role = OBJECT_R_VAL; 14181da177e4SLinus Torvalds /* Use the type of the related object. */ 14191da177e4SLinus Torvalds newcontext.type = tcontext->type; 14201da177e4SLinus Torvalds } 14211da177e4SLinus Torvalds 14221da177e4SLinus Torvalds /* Look for a type transition/member/change rule. */ 14231da177e4SLinus Torvalds avkey.source_type = scontext->type; 14241da177e4SLinus Torvalds avkey.target_type = tcontext->type; 14251da177e4SLinus Torvalds avkey.target_class = tclass; 1426782ebb99SStephen Smalley avkey.specified = specified; 1427782ebb99SStephen Smalley avdatum = avtab_search(&policydb.te_avtab, &avkey); 14281da177e4SLinus Torvalds 14291da177e4SLinus Torvalds /* If no permanent rule, also check for enabled conditional rules */ 14301da177e4SLinus Torvalds if (!avdatum) { 1431782ebb99SStephen Smalley node = avtab_search_node(&policydb.te_cond_avtab, &avkey); 1432dbc74c65SVesa-Matti Kari for (; node; node = avtab_search_node_next(node, specified)) { 1433782ebb99SStephen Smalley if (node->key.specified & AVTAB_ENABLED) { 14341da177e4SLinus Torvalds avdatum = &node->datum; 14351da177e4SLinus Torvalds break; 14361da177e4SLinus Torvalds } 14371da177e4SLinus Torvalds } 14381da177e4SLinus Torvalds } 14391da177e4SLinus Torvalds 1440782ebb99SStephen Smalley if (avdatum) { 14411da177e4SLinus Torvalds /* Use the type from the type transition/member/change rule. */ 1442782ebb99SStephen Smalley newcontext.type = avdatum->data; 14431da177e4SLinus Torvalds } 14441da177e4SLinus Torvalds 14451da177e4SLinus Torvalds /* Check for class-specific changes. */ 1446c6d3aaa4SStephen Smalley if (tclass == policydb.process_class) { 14471da177e4SLinus Torvalds if (specified & AVTAB_TRANSITION) { 14481da177e4SLinus Torvalds /* Look for a role transition rule. */ 14491da177e4SLinus Torvalds for (roletr = policydb.role_tr; roletr; 14501da177e4SLinus Torvalds roletr = roletr->next) { 14511da177e4SLinus Torvalds if (roletr->role == scontext->role && 14521da177e4SLinus Torvalds roletr->type == tcontext->type) { 14531da177e4SLinus Torvalds /* Use the role transition rule. */ 14541da177e4SLinus Torvalds newcontext.role = roletr->new_role; 14551da177e4SLinus Torvalds break; 14561da177e4SLinus Torvalds } 14571da177e4SLinus Torvalds } 14581da177e4SLinus Torvalds } 14591da177e4SLinus Torvalds } 14601da177e4SLinus Torvalds 14611da177e4SLinus Torvalds /* Set the MLS attributes. 14621da177e4SLinus Torvalds This is done last because it may allocate memory. */ 14631da177e4SLinus Torvalds rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext); 14641da177e4SLinus Torvalds if (rc) 14651da177e4SLinus Torvalds goto out_unlock; 14661da177e4SLinus Torvalds 14671da177e4SLinus Torvalds /* Check the validity of the context. */ 14681da177e4SLinus Torvalds if (!policydb_context_isvalid(&policydb, &newcontext)) { 14691da177e4SLinus Torvalds rc = compute_sid_handle_invalid_context(scontext, 14701da177e4SLinus Torvalds tcontext, 14711da177e4SLinus Torvalds tclass, 14721da177e4SLinus Torvalds &newcontext); 14731da177e4SLinus Torvalds if (rc) 14741da177e4SLinus Torvalds goto out_unlock; 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds /* Obtain the sid for the context. */ 14771da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid); 14781da177e4SLinus Torvalds out_unlock: 14790804d113SJames Morris read_unlock(&policy_rwlock); 14801da177e4SLinus Torvalds context_destroy(&newcontext); 14811da177e4SLinus Torvalds out: 14821da177e4SLinus Torvalds return rc; 14831da177e4SLinus Torvalds } 14841da177e4SLinus Torvalds 14851da177e4SLinus Torvalds /** 14861da177e4SLinus Torvalds * security_transition_sid - Compute the SID for a new subject/object. 14871da177e4SLinus Torvalds * @ssid: source security identifier 14881da177e4SLinus Torvalds * @tsid: target security identifier 14891da177e4SLinus Torvalds * @tclass: target security class 14901da177e4SLinus Torvalds * @out_sid: security identifier for new subject/object 14911da177e4SLinus Torvalds * 14921da177e4SLinus Torvalds * Compute a SID to use for labeling a new subject or object in the 14931da177e4SLinus Torvalds * class @tclass based on a SID pair (@ssid, @tsid). 14941da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 14951da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the new SID was 14961da177e4SLinus Torvalds * computed successfully. 14971da177e4SLinus Torvalds */ 14981da177e4SLinus Torvalds int security_transition_sid(u32 ssid, 14991da177e4SLinus Torvalds u32 tsid, 15001da177e4SLinus Torvalds u16 tclass, 15011da177e4SLinus Torvalds u32 *out_sid) 15021da177e4SLinus Torvalds { 1503c6d3aaa4SStephen Smalley return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, 1504c6d3aaa4SStephen Smalley out_sid, true); 1505c6d3aaa4SStephen Smalley } 1506c6d3aaa4SStephen Smalley 1507c6d3aaa4SStephen Smalley int security_transition_sid_user(u32 ssid, 1508c6d3aaa4SStephen Smalley u32 tsid, 1509c6d3aaa4SStephen Smalley u16 tclass, 1510c6d3aaa4SStephen Smalley u32 *out_sid) 1511c6d3aaa4SStephen Smalley { 1512c6d3aaa4SStephen Smalley return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, 1513c6d3aaa4SStephen Smalley out_sid, false); 15141da177e4SLinus Torvalds } 15151da177e4SLinus Torvalds 15161da177e4SLinus Torvalds /** 15171da177e4SLinus Torvalds * security_member_sid - Compute the SID for member selection. 15181da177e4SLinus Torvalds * @ssid: source security identifier 15191da177e4SLinus Torvalds * @tsid: target security identifier 15201da177e4SLinus Torvalds * @tclass: target security class 15211da177e4SLinus Torvalds * @out_sid: security identifier for selected member 15221da177e4SLinus Torvalds * 15231da177e4SLinus Torvalds * Compute a SID to use when selecting a member of a polyinstantiated 15241da177e4SLinus Torvalds * object of class @tclass based on a SID pair (@ssid, @tsid). 15251da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 15261da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 15271da177e4SLinus Torvalds * computed successfully. 15281da177e4SLinus Torvalds */ 15291da177e4SLinus Torvalds int security_member_sid(u32 ssid, 15301da177e4SLinus Torvalds u32 tsid, 15311da177e4SLinus Torvalds u16 tclass, 15321da177e4SLinus Torvalds u32 *out_sid) 15331da177e4SLinus Torvalds { 1534c6d3aaa4SStephen Smalley return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid, 1535c6d3aaa4SStephen Smalley false); 15361da177e4SLinus Torvalds } 15371da177e4SLinus Torvalds 15381da177e4SLinus Torvalds /** 15391da177e4SLinus Torvalds * security_change_sid - Compute the SID for object relabeling. 15401da177e4SLinus Torvalds * @ssid: source security identifier 15411da177e4SLinus Torvalds * @tsid: target security identifier 15421da177e4SLinus Torvalds * @tclass: target security class 15431da177e4SLinus Torvalds * @out_sid: security identifier for selected member 15441da177e4SLinus Torvalds * 15451da177e4SLinus Torvalds * Compute a SID to use for relabeling an object of class @tclass 15461da177e4SLinus Torvalds * based on a SID pair (@ssid, @tsid). 15471da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 15481da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 15491da177e4SLinus Torvalds * computed successfully. 15501da177e4SLinus Torvalds */ 15511da177e4SLinus Torvalds int security_change_sid(u32 ssid, 15521da177e4SLinus Torvalds u32 tsid, 15531da177e4SLinus Torvalds u16 tclass, 15541da177e4SLinus Torvalds u32 *out_sid) 15551da177e4SLinus Torvalds { 1556c6d3aaa4SStephen Smalley return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid, 1557c6d3aaa4SStephen Smalley false); 1558b94c7e67SChad Sellers } 1559b94c7e67SChad Sellers 15601da177e4SLinus Torvalds /* Clone the SID into the new SID table. */ 15611da177e4SLinus Torvalds static int clone_sid(u32 sid, 15621da177e4SLinus Torvalds struct context *context, 15631da177e4SLinus Torvalds void *arg) 15641da177e4SLinus Torvalds { 15651da177e4SLinus Torvalds struct sidtab *s = arg; 15661da177e4SLinus Torvalds 156742596eafSGuido Trentalancia if (sid > SECINITSID_NUM) 15681da177e4SLinus Torvalds return sidtab_insert(s, sid, context); 156942596eafSGuido Trentalancia else 157042596eafSGuido Trentalancia return 0; 15711da177e4SLinus Torvalds } 15721da177e4SLinus Torvalds 15731da177e4SLinus Torvalds static inline int convert_context_handle_invalid_context(struct context *context) 15741da177e4SLinus Torvalds { 15751da177e4SLinus Torvalds char *s; 15761da177e4SLinus Torvalds u32 len; 15771da177e4SLinus Torvalds 15784b02b524SEric Paris if (selinux_enforcing) 15794b02b524SEric Paris return -EINVAL; 15804b02b524SEric Paris 158112b29f34SStephen Smalley if (!context_struct_to_string(context, &s, &len)) { 15824b02b524SEric Paris printk(KERN_WARNING "SELinux: Context %s would be invalid if enforcing\n", s); 15831da177e4SLinus Torvalds kfree(s); 15841da177e4SLinus Torvalds } 15854b02b524SEric Paris return 0; 15861da177e4SLinus Torvalds } 15871da177e4SLinus Torvalds 15881da177e4SLinus Torvalds struct convert_context_args { 15891da177e4SLinus Torvalds struct policydb *oldp; 15901da177e4SLinus Torvalds struct policydb *newp; 15911da177e4SLinus Torvalds }; 15921da177e4SLinus Torvalds 15931da177e4SLinus Torvalds /* 15941da177e4SLinus Torvalds * Convert the values in the security context 15951da177e4SLinus Torvalds * structure `c' from the values specified 15961da177e4SLinus Torvalds * in the policy `p->oldp' to the values specified 15971da177e4SLinus Torvalds * in the policy `p->newp'. Verify that the 15981da177e4SLinus Torvalds * context is valid under the new policy. 15991da177e4SLinus Torvalds */ 16001da177e4SLinus Torvalds static int convert_context(u32 key, 16011da177e4SLinus Torvalds struct context *c, 16021da177e4SLinus Torvalds void *p) 16031da177e4SLinus Torvalds { 16041da177e4SLinus Torvalds struct convert_context_args *args; 16051da177e4SLinus Torvalds struct context oldc; 16060719aaf5SGuido Trentalancia struct ocontext *oc; 16070719aaf5SGuido Trentalancia struct mls_range *range; 16081da177e4SLinus Torvalds struct role_datum *role; 16091da177e4SLinus Torvalds struct type_datum *typdatum; 16101da177e4SLinus Torvalds struct user_datum *usrdatum; 16111da177e4SLinus Torvalds char *s; 16121da177e4SLinus Torvalds u32 len; 161342596eafSGuido Trentalancia int rc = 0; 161442596eafSGuido Trentalancia 161542596eafSGuido Trentalancia if (key <= SECINITSID_NUM) 161642596eafSGuido Trentalancia goto out; 16171da177e4SLinus Torvalds 16181da177e4SLinus Torvalds args = p; 16191da177e4SLinus Torvalds 162012b29f34SStephen Smalley if (c->str) { 162112b29f34SStephen Smalley struct context ctx; 16224b02b524SEric Paris 16239a59daa0SStephen Smalley rc = -ENOMEM; 16244b02b524SEric Paris s = kstrdup(c->str, GFP_KERNEL); 16254b02b524SEric Paris if (!s) 16269a59daa0SStephen Smalley goto out; 16274b02b524SEric Paris 16289a59daa0SStephen Smalley rc = string_to_context_struct(args->newp, NULL, s, 16299a59daa0SStephen Smalley c->len, &ctx, SECSID_NULL); 16309a59daa0SStephen Smalley kfree(s); 163112b29f34SStephen Smalley if (!rc) { 16324b02b524SEric Paris printk(KERN_INFO "SELinux: Context %s became valid (mapped).\n", 163312b29f34SStephen Smalley c->str); 163412b29f34SStephen Smalley /* Replace string with mapped representation. */ 163512b29f34SStephen Smalley kfree(c->str); 163612b29f34SStephen Smalley memcpy(c, &ctx, sizeof(*c)); 163712b29f34SStephen Smalley goto out; 163812b29f34SStephen Smalley } else if (rc == -EINVAL) { 163912b29f34SStephen Smalley /* Retain string representation for later mapping. */ 164012b29f34SStephen Smalley rc = 0; 164112b29f34SStephen Smalley goto out; 164212b29f34SStephen Smalley } else { 164312b29f34SStephen Smalley /* Other error condition, e.g. ENOMEM. */ 16444b02b524SEric Paris printk(KERN_ERR "SELinux: Unable to map context %s, rc = %d.\n", 164512b29f34SStephen Smalley c->str, -rc); 164612b29f34SStephen Smalley goto out; 164712b29f34SStephen Smalley } 164812b29f34SStephen Smalley } 164912b29f34SStephen Smalley 16501da177e4SLinus Torvalds rc = context_cpy(&oldc, c); 16511da177e4SLinus Torvalds if (rc) 16521da177e4SLinus Torvalds goto out; 16531da177e4SLinus Torvalds 16541da177e4SLinus Torvalds /* Convert the user. */ 16554b02b524SEric Paris rc = -EINVAL; 16561da177e4SLinus Torvalds usrdatum = hashtab_search(args->newp->p_users.table, 1657ac76c05bSEric Paris sym_name(args->oldp, SYM_USERS, c->user - 1)); 16585d55a345SEric Paris if (!usrdatum) 16591da177e4SLinus Torvalds goto bad; 16601da177e4SLinus Torvalds c->user = usrdatum->value; 16611da177e4SLinus Torvalds 16621da177e4SLinus Torvalds /* Convert the role. */ 16634b02b524SEric Paris rc = -EINVAL; 16641da177e4SLinus Torvalds role = hashtab_search(args->newp->p_roles.table, 1665ac76c05bSEric Paris sym_name(args->oldp, SYM_ROLES, c->role - 1)); 16665d55a345SEric Paris if (!role) 16671da177e4SLinus Torvalds goto bad; 16681da177e4SLinus Torvalds c->role = role->value; 16691da177e4SLinus Torvalds 16701da177e4SLinus Torvalds /* Convert the type. */ 16714b02b524SEric Paris rc = -EINVAL; 16721da177e4SLinus Torvalds typdatum = hashtab_search(args->newp->p_types.table, 1673ac76c05bSEric Paris sym_name(args->oldp, SYM_TYPES, c->type - 1)); 16745d55a345SEric Paris if (!typdatum) 16751da177e4SLinus Torvalds goto bad; 16761da177e4SLinus Torvalds c->type = typdatum->value; 16771da177e4SLinus Torvalds 16780719aaf5SGuido Trentalancia /* Convert the MLS fields if dealing with MLS policies */ 16790719aaf5SGuido Trentalancia if (args->oldp->mls_enabled && args->newp->mls_enabled) { 16801da177e4SLinus Torvalds rc = mls_convert_context(args->oldp, args->newp, c); 16811da177e4SLinus Torvalds if (rc) 16821da177e4SLinus Torvalds goto bad; 16830719aaf5SGuido Trentalancia } else if (args->oldp->mls_enabled && !args->newp->mls_enabled) { 16840719aaf5SGuido Trentalancia /* 16850719aaf5SGuido Trentalancia * Switching between MLS and non-MLS policy: 16860719aaf5SGuido Trentalancia * free any storage used by the MLS fields in the 16870719aaf5SGuido Trentalancia * context for all existing entries in the sidtab. 16880719aaf5SGuido Trentalancia */ 16890719aaf5SGuido Trentalancia mls_context_destroy(c); 16900719aaf5SGuido Trentalancia } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) { 16910719aaf5SGuido Trentalancia /* 16920719aaf5SGuido Trentalancia * Switching between non-MLS and MLS policy: 16930719aaf5SGuido Trentalancia * ensure that the MLS fields of the context for all 16940719aaf5SGuido Trentalancia * existing entries in the sidtab are filled in with a 16950719aaf5SGuido Trentalancia * suitable default value, likely taken from one of the 16960719aaf5SGuido Trentalancia * initial SIDs. 16970719aaf5SGuido Trentalancia */ 16980719aaf5SGuido Trentalancia oc = args->newp->ocontexts[OCON_ISID]; 16990719aaf5SGuido Trentalancia while (oc && oc->sid[0] != SECINITSID_UNLABELED) 17000719aaf5SGuido Trentalancia oc = oc->next; 17014b02b524SEric Paris rc = -EINVAL; 17020719aaf5SGuido Trentalancia if (!oc) { 17030719aaf5SGuido Trentalancia printk(KERN_ERR "SELinux: unable to look up" 17040719aaf5SGuido Trentalancia " the initial SIDs list\n"); 17050719aaf5SGuido Trentalancia goto bad; 17060719aaf5SGuido Trentalancia } 17070719aaf5SGuido Trentalancia range = &oc->context[0].range; 17080719aaf5SGuido Trentalancia rc = mls_range_set(c, range); 17090719aaf5SGuido Trentalancia if (rc) 17100719aaf5SGuido Trentalancia goto bad; 17110719aaf5SGuido Trentalancia } 17121da177e4SLinus Torvalds 17131da177e4SLinus Torvalds /* Check the validity of the new context. */ 17141da177e4SLinus Torvalds if (!policydb_context_isvalid(args->newp, c)) { 17151da177e4SLinus Torvalds rc = convert_context_handle_invalid_context(&oldc); 17161da177e4SLinus Torvalds if (rc) 17171da177e4SLinus Torvalds goto bad; 17181da177e4SLinus Torvalds } 17191da177e4SLinus Torvalds 17201da177e4SLinus Torvalds context_destroy(&oldc); 17214b02b524SEric Paris 172212b29f34SStephen Smalley rc = 0; 17231da177e4SLinus Torvalds out: 17241da177e4SLinus Torvalds return rc; 17251da177e4SLinus Torvalds bad: 172612b29f34SStephen Smalley /* Map old representation to string and save it. */ 17274b02b524SEric Paris rc = context_struct_to_string(&oldc, &s, &len); 17284b02b524SEric Paris if (rc) 17294b02b524SEric Paris return rc; 17301da177e4SLinus Torvalds context_destroy(&oldc); 173112b29f34SStephen Smalley context_destroy(c); 173212b29f34SStephen Smalley c->str = s; 173312b29f34SStephen Smalley c->len = len; 17344b02b524SEric Paris printk(KERN_INFO "SELinux: Context %s became invalid (unmapped).\n", 173512b29f34SStephen Smalley c->str); 173612b29f34SStephen Smalley rc = 0; 17371da177e4SLinus Torvalds goto out; 17381da177e4SLinus Torvalds } 17391da177e4SLinus Torvalds 17403bb56b25SPaul Moore static void security_load_policycaps(void) 17413bb56b25SPaul Moore { 17423bb56b25SPaul Moore selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps, 17433bb56b25SPaul Moore POLICYDB_CAPABILITY_NETPEER); 1744b0c636b9SEric Paris selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, 1745b0c636b9SEric Paris POLICYDB_CAPABILITY_OPENPERM); 17463bb56b25SPaul Moore } 17473bb56b25SPaul Moore 17481da177e4SLinus Torvalds extern void selinux_complete_init(void); 1749e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p); 17501da177e4SLinus Torvalds 17511da177e4SLinus Torvalds /** 17521da177e4SLinus Torvalds * security_load_policy - Load a security policy configuration. 17531da177e4SLinus Torvalds * @data: binary policy data 17541da177e4SLinus Torvalds * @len: length of data in bytes 17551da177e4SLinus Torvalds * 17561da177e4SLinus Torvalds * Load a new set of security policy configuration data, 17571da177e4SLinus Torvalds * validate it and convert the SID table as necessary. 17581da177e4SLinus Torvalds * This function will flush the access vector cache after 17591da177e4SLinus Torvalds * loading the new policy. 17601da177e4SLinus Torvalds */ 17611da177e4SLinus Torvalds int security_load_policy(void *data, size_t len) 17621da177e4SLinus Torvalds { 17631da177e4SLinus Torvalds struct policydb oldpolicydb, newpolicydb; 17641da177e4SLinus Torvalds struct sidtab oldsidtab, newsidtab; 1765c6d3aaa4SStephen Smalley struct selinux_mapping *oldmap, *map = NULL; 17661da177e4SLinus Torvalds struct convert_context_args args; 17671da177e4SLinus Torvalds u32 seqno; 1768c6d3aaa4SStephen Smalley u16 map_size; 17691da177e4SLinus Torvalds int rc = 0; 17701da177e4SLinus Torvalds struct policy_file file = { data, len }, *fp = &file; 17711da177e4SLinus Torvalds 17721da177e4SLinus Torvalds if (!ss_initialized) { 17731da177e4SLinus Torvalds avtab_cache_init(); 1774a2000050SEric Paris rc = policydb_read(&policydb, fp); 1775a2000050SEric Paris if (rc) { 17761da177e4SLinus Torvalds avtab_cache_destroy(); 1777a2000050SEric Paris return rc; 17781da177e4SLinus Torvalds } 1779a2000050SEric Paris 1780cee74f47SEric Paris policydb.len = len; 1781a2000050SEric Paris rc = selinux_set_mapping(&policydb, secclass_map, 1782c6d3aaa4SStephen Smalley ¤t_mapping, 1783a2000050SEric Paris ¤t_mapping_size); 1784a2000050SEric Paris if (rc) { 17851da177e4SLinus Torvalds policydb_destroy(&policydb); 17861da177e4SLinus Torvalds avtab_cache_destroy(); 1787a2000050SEric Paris return rc; 17881da177e4SLinus Torvalds } 1789a2000050SEric Paris 1790a2000050SEric Paris rc = policydb_load_isids(&policydb, &sidtab); 1791a2000050SEric Paris if (rc) { 1792b94c7e67SChad Sellers policydb_destroy(&policydb); 1793b94c7e67SChad Sellers avtab_cache_destroy(); 1794a2000050SEric Paris return rc; 1795b94c7e67SChad Sellers } 1796a2000050SEric Paris 17973bb56b25SPaul Moore security_load_policycaps(); 17981da177e4SLinus Torvalds ss_initialized = 1; 17994c443d1bSStephen Smalley seqno = ++latest_granting; 18001da177e4SLinus Torvalds selinux_complete_init(); 18014c443d1bSStephen Smalley avc_ss_reset(seqno); 18024c443d1bSStephen Smalley selnl_notify_policyload(seqno); 180311904167SKaiGai Kohei selinux_status_update_policyload(seqno); 18047420ed23SVenkat Yekkirala selinux_netlbl_cache_invalidate(); 1805342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 18061da177e4SLinus Torvalds return 0; 18071da177e4SLinus Torvalds } 18081da177e4SLinus Torvalds 18091da177e4SLinus Torvalds #if 0 18101da177e4SLinus Torvalds sidtab_hash_eval(&sidtab, "sids"); 18111da177e4SLinus Torvalds #endif 18121da177e4SLinus Torvalds 1813a2000050SEric Paris rc = policydb_read(&newpolicydb, fp); 1814a2000050SEric Paris if (rc) 1815a2000050SEric Paris return rc; 18161da177e4SLinus Torvalds 1817cee74f47SEric Paris newpolicydb.len = len; 18180719aaf5SGuido Trentalancia /* If switching between different policy types, log MLS status */ 18190719aaf5SGuido Trentalancia if (policydb.mls_enabled && !newpolicydb.mls_enabled) 18200719aaf5SGuido Trentalancia printk(KERN_INFO "SELinux: Disabling MLS support...\n"); 18210719aaf5SGuido Trentalancia else if (!policydb.mls_enabled && newpolicydb.mls_enabled) 18220719aaf5SGuido Trentalancia printk(KERN_INFO "SELinux: Enabling MLS support...\n"); 18230719aaf5SGuido Trentalancia 182442596eafSGuido Trentalancia rc = policydb_load_isids(&newpolicydb, &newsidtab); 182542596eafSGuido Trentalancia if (rc) { 182642596eafSGuido Trentalancia printk(KERN_ERR "SELinux: unable to load the initial SIDs\n"); 182712b29f34SStephen Smalley policydb_destroy(&newpolicydb); 182842596eafSGuido Trentalancia return rc; 182912b29f34SStephen Smalley } 18301da177e4SLinus Torvalds 1831a2000050SEric Paris rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size); 1832a2000050SEric Paris if (rc) 1833b94c7e67SChad Sellers goto err; 1834b94c7e67SChad Sellers 1835e900a7d9SStephen Smalley rc = security_preserve_bools(&newpolicydb); 1836e900a7d9SStephen Smalley if (rc) { 1837454d972cSJames Morris printk(KERN_ERR "SELinux: unable to preserve booleans\n"); 1838e900a7d9SStephen Smalley goto err; 1839e900a7d9SStephen Smalley } 1840e900a7d9SStephen Smalley 18411da177e4SLinus Torvalds /* Clone the SID table. */ 18421da177e4SLinus Torvalds sidtab_shutdown(&sidtab); 1843a2000050SEric Paris 1844a2000050SEric Paris rc = sidtab_map(&sidtab, clone_sid, &newsidtab); 1845a2000050SEric Paris if (rc) 18461da177e4SLinus Torvalds goto err; 18471da177e4SLinus Torvalds 184812b29f34SStephen Smalley /* 184912b29f34SStephen Smalley * Convert the internal representations of contexts 185012b29f34SStephen Smalley * in the new SID table. 185112b29f34SStephen Smalley */ 18521da177e4SLinus Torvalds args.oldp = &policydb; 18531da177e4SLinus Torvalds args.newp = &newpolicydb; 185412b29f34SStephen Smalley rc = sidtab_map(&newsidtab, convert_context, &args); 18550719aaf5SGuido Trentalancia if (rc) { 18560719aaf5SGuido Trentalancia printk(KERN_ERR "SELinux: unable to convert the internal" 18570719aaf5SGuido Trentalancia " representation of contexts in the new SID" 18580719aaf5SGuido Trentalancia " table\n"); 185912b29f34SStephen Smalley goto err; 18600719aaf5SGuido Trentalancia } 18611da177e4SLinus Torvalds 18621da177e4SLinus Torvalds /* Save the old policydb and SID table to free later. */ 18631da177e4SLinus Torvalds memcpy(&oldpolicydb, &policydb, sizeof policydb); 18641da177e4SLinus Torvalds sidtab_set(&oldsidtab, &sidtab); 18651da177e4SLinus Torvalds 18661da177e4SLinus Torvalds /* Install the new policydb and SID table. */ 18670804d113SJames Morris write_lock_irq(&policy_rwlock); 18681da177e4SLinus Torvalds memcpy(&policydb, &newpolicydb, sizeof policydb); 18691da177e4SLinus Torvalds sidtab_set(&sidtab, &newsidtab); 18703bb56b25SPaul Moore security_load_policycaps(); 1871c6d3aaa4SStephen Smalley oldmap = current_mapping; 1872c6d3aaa4SStephen Smalley current_mapping = map; 1873c6d3aaa4SStephen Smalley current_mapping_size = map_size; 18741da177e4SLinus Torvalds seqno = ++latest_granting; 18750804d113SJames Morris write_unlock_irq(&policy_rwlock); 18761da177e4SLinus Torvalds 18771da177e4SLinus Torvalds /* Free the old policydb and SID table. */ 18781da177e4SLinus Torvalds policydb_destroy(&oldpolicydb); 18791da177e4SLinus Torvalds sidtab_destroy(&oldsidtab); 1880c6d3aaa4SStephen Smalley kfree(oldmap); 18811da177e4SLinus Torvalds 18821da177e4SLinus Torvalds avc_ss_reset(seqno); 18831da177e4SLinus Torvalds selnl_notify_policyload(seqno); 188411904167SKaiGai Kohei selinux_status_update_policyload(seqno); 18857420ed23SVenkat Yekkirala selinux_netlbl_cache_invalidate(); 1886342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds return 0; 18891da177e4SLinus Torvalds 18901da177e4SLinus Torvalds err: 1891c6d3aaa4SStephen Smalley kfree(map); 18921da177e4SLinus Torvalds sidtab_destroy(&newsidtab); 18931da177e4SLinus Torvalds policydb_destroy(&newpolicydb); 18941da177e4SLinus Torvalds return rc; 18951da177e4SLinus Torvalds 18961da177e4SLinus Torvalds } 18971da177e4SLinus Torvalds 1898cee74f47SEric Paris size_t security_policydb_len(void) 1899cee74f47SEric Paris { 1900cee74f47SEric Paris size_t len; 1901cee74f47SEric Paris 1902cee74f47SEric Paris read_lock(&policy_rwlock); 1903cee74f47SEric Paris len = policydb.len; 1904cee74f47SEric Paris read_unlock(&policy_rwlock); 1905cee74f47SEric Paris 1906cee74f47SEric Paris return len; 1907cee74f47SEric Paris } 1908cee74f47SEric Paris 19091da177e4SLinus Torvalds /** 19101da177e4SLinus Torvalds * security_port_sid - Obtain the SID for a port. 19111da177e4SLinus Torvalds * @protocol: protocol number 19121da177e4SLinus Torvalds * @port: port number 19131da177e4SLinus Torvalds * @out_sid: security identifier 19141da177e4SLinus Torvalds */ 19153e112172SPaul Moore int security_port_sid(u8 protocol, u16 port, u32 *out_sid) 19161da177e4SLinus Torvalds { 19171da177e4SLinus Torvalds struct ocontext *c; 19181da177e4SLinus Torvalds int rc = 0; 19191da177e4SLinus Torvalds 19200804d113SJames Morris read_lock(&policy_rwlock); 19211da177e4SLinus Torvalds 19221da177e4SLinus Torvalds c = policydb.ocontexts[OCON_PORT]; 19231da177e4SLinus Torvalds while (c) { 19241da177e4SLinus Torvalds if (c->u.port.protocol == protocol && 19251da177e4SLinus Torvalds c->u.port.low_port <= port && 19261da177e4SLinus Torvalds c->u.port.high_port >= port) 19271da177e4SLinus Torvalds break; 19281da177e4SLinus Torvalds c = c->next; 19291da177e4SLinus Torvalds } 19301da177e4SLinus Torvalds 19311da177e4SLinus Torvalds if (c) { 19321da177e4SLinus Torvalds if (!c->sid[0]) { 19331da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 19341da177e4SLinus Torvalds &c->context[0], 19351da177e4SLinus Torvalds &c->sid[0]); 19361da177e4SLinus Torvalds if (rc) 19371da177e4SLinus Torvalds goto out; 19381da177e4SLinus Torvalds } 19391da177e4SLinus Torvalds *out_sid = c->sid[0]; 19401da177e4SLinus Torvalds } else { 19411da177e4SLinus Torvalds *out_sid = SECINITSID_PORT; 19421da177e4SLinus Torvalds } 19431da177e4SLinus Torvalds 19441da177e4SLinus Torvalds out: 19450804d113SJames Morris read_unlock(&policy_rwlock); 19461da177e4SLinus Torvalds return rc; 19471da177e4SLinus Torvalds } 19481da177e4SLinus Torvalds 19491da177e4SLinus Torvalds /** 19501da177e4SLinus Torvalds * security_netif_sid - Obtain the SID for a network interface. 19511da177e4SLinus Torvalds * @name: interface name 19521da177e4SLinus Torvalds * @if_sid: interface SID 19531da177e4SLinus Torvalds */ 1954e8bfdb9dSPaul Moore int security_netif_sid(char *name, u32 *if_sid) 19551da177e4SLinus Torvalds { 19561da177e4SLinus Torvalds int rc = 0; 19571da177e4SLinus Torvalds struct ocontext *c; 19581da177e4SLinus Torvalds 19590804d113SJames Morris read_lock(&policy_rwlock); 19601da177e4SLinus Torvalds 19611da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NETIF]; 19621da177e4SLinus Torvalds while (c) { 19631da177e4SLinus Torvalds if (strcmp(name, c->u.name) == 0) 19641da177e4SLinus Torvalds break; 19651da177e4SLinus Torvalds c = c->next; 19661da177e4SLinus Torvalds } 19671da177e4SLinus Torvalds 19681da177e4SLinus Torvalds if (c) { 19691da177e4SLinus Torvalds if (!c->sid[0] || !c->sid[1]) { 19701da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 19711da177e4SLinus Torvalds &c->context[0], 19721da177e4SLinus Torvalds &c->sid[0]); 19731da177e4SLinus Torvalds if (rc) 19741da177e4SLinus Torvalds goto out; 19751da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 19761da177e4SLinus Torvalds &c->context[1], 19771da177e4SLinus Torvalds &c->sid[1]); 19781da177e4SLinus Torvalds if (rc) 19791da177e4SLinus Torvalds goto out; 19801da177e4SLinus Torvalds } 19811da177e4SLinus Torvalds *if_sid = c->sid[0]; 1982e8bfdb9dSPaul Moore } else 19831da177e4SLinus Torvalds *if_sid = SECINITSID_NETIF; 19841da177e4SLinus Torvalds 19851da177e4SLinus Torvalds out: 19860804d113SJames Morris read_unlock(&policy_rwlock); 19871da177e4SLinus Torvalds return rc; 19881da177e4SLinus Torvalds } 19891da177e4SLinus Torvalds 19901da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) 19911da177e4SLinus Torvalds { 19921da177e4SLinus Torvalds int i, fail = 0; 19931da177e4SLinus Torvalds 19941da177e4SLinus Torvalds for (i = 0; i < 4; i++) 19951da177e4SLinus Torvalds if (addr[i] != (input[i] & mask[i])) { 19961da177e4SLinus Torvalds fail = 1; 19971da177e4SLinus Torvalds break; 19981da177e4SLinus Torvalds } 19991da177e4SLinus Torvalds 20001da177e4SLinus Torvalds return !fail; 20011da177e4SLinus Torvalds } 20021da177e4SLinus Torvalds 20031da177e4SLinus Torvalds /** 20041da177e4SLinus Torvalds * security_node_sid - Obtain the SID for a node (host). 20051da177e4SLinus Torvalds * @domain: communication domain aka address family 20061da177e4SLinus Torvalds * @addrp: address 20071da177e4SLinus Torvalds * @addrlen: address length in bytes 20081da177e4SLinus Torvalds * @out_sid: security identifier 20091da177e4SLinus Torvalds */ 20101da177e4SLinus Torvalds int security_node_sid(u16 domain, 20111da177e4SLinus Torvalds void *addrp, 20121da177e4SLinus Torvalds u32 addrlen, 20131da177e4SLinus Torvalds u32 *out_sid) 20141da177e4SLinus Torvalds { 20154b02b524SEric Paris int rc; 20161da177e4SLinus Torvalds struct ocontext *c; 20171da177e4SLinus Torvalds 20180804d113SJames Morris read_lock(&policy_rwlock); 20191da177e4SLinus Torvalds 20201da177e4SLinus Torvalds switch (domain) { 20211da177e4SLinus Torvalds case AF_INET: { 20221da177e4SLinus Torvalds u32 addr; 20231da177e4SLinus Torvalds 20241da177e4SLinus Torvalds rc = -EINVAL; 20254b02b524SEric Paris if (addrlen != sizeof(u32)) 20261da177e4SLinus Torvalds goto out; 20271da177e4SLinus Torvalds 20281da177e4SLinus Torvalds addr = *((u32 *)addrp); 20291da177e4SLinus Torvalds 20301da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NODE]; 20311da177e4SLinus Torvalds while (c) { 20321da177e4SLinus Torvalds if (c->u.node.addr == (addr & c->u.node.mask)) 20331da177e4SLinus Torvalds break; 20341da177e4SLinus Torvalds c = c->next; 20351da177e4SLinus Torvalds } 20361da177e4SLinus Torvalds break; 20371da177e4SLinus Torvalds } 20381da177e4SLinus Torvalds 20391da177e4SLinus Torvalds case AF_INET6: 20401da177e4SLinus Torvalds rc = -EINVAL; 20414b02b524SEric Paris if (addrlen != sizeof(u64) * 2) 20421da177e4SLinus Torvalds goto out; 20431da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NODE6]; 20441da177e4SLinus Torvalds while (c) { 20451da177e4SLinus Torvalds if (match_ipv6_addrmask(addrp, c->u.node6.addr, 20461da177e4SLinus Torvalds c->u.node6.mask)) 20471da177e4SLinus Torvalds break; 20481da177e4SLinus Torvalds c = c->next; 20491da177e4SLinus Torvalds } 20501da177e4SLinus Torvalds break; 20511da177e4SLinus Torvalds 20521da177e4SLinus Torvalds default: 20534b02b524SEric Paris rc = 0; 20541da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 20551da177e4SLinus Torvalds goto out; 20561da177e4SLinus Torvalds } 20571da177e4SLinus Torvalds 20581da177e4SLinus Torvalds if (c) { 20591da177e4SLinus Torvalds if (!c->sid[0]) { 20601da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 20611da177e4SLinus Torvalds &c->context[0], 20621da177e4SLinus Torvalds &c->sid[0]); 20631da177e4SLinus Torvalds if (rc) 20641da177e4SLinus Torvalds goto out; 20651da177e4SLinus Torvalds } 20661da177e4SLinus Torvalds *out_sid = c->sid[0]; 20671da177e4SLinus Torvalds } else { 20681da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 20691da177e4SLinus Torvalds } 20701da177e4SLinus Torvalds 20714b02b524SEric Paris rc = 0; 20721da177e4SLinus Torvalds out: 20730804d113SJames Morris read_unlock(&policy_rwlock); 20741da177e4SLinus Torvalds return rc; 20751da177e4SLinus Torvalds } 20761da177e4SLinus Torvalds 20771da177e4SLinus Torvalds #define SIDS_NEL 25 20781da177e4SLinus Torvalds 20791da177e4SLinus Torvalds /** 20801da177e4SLinus Torvalds * security_get_user_sids - Obtain reachable SIDs for a user. 20811da177e4SLinus Torvalds * @fromsid: starting SID 20821da177e4SLinus Torvalds * @username: username 20831da177e4SLinus Torvalds * @sids: array of reachable SIDs for user 20841da177e4SLinus Torvalds * @nel: number of elements in @sids 20851da177e4SLinus Torvalds * 20861da177e4SLinus Torvalds * Generate the set of SIDs for legal security contexts 20871da177e4SLinus Torvalds * for a given user that can be reached by @fromsid. 20881da177e4SLinus Torvalds * Set *@sids to point to a dynamically allocated 20891da177e4SLinus Torvalds * array containing the set of SIDs. Set *@nel to the 20901da177e4SLinus Torvalds * number of elements in the array. 20911da177e4SLinus Torvalds */ 20921da177e4SLinus Torvalds 20931da177e4SLinus Torvalds int security_get_user_sids(u32 fromsid, 20941da177e4SLinus Torvalds char *username, 20951da177e4SLinus Torvalds u32 **sids, 20961da177e4SLinus Torvalds u32 *nel) 20971da177e4SLinus Torvalds { 20981da177e4SLinus Torvalds struct context *fromcon, usercon; 20992c3c05dbSStephen Smalley u32 *mysids = NULL, *mysids2, sid; 21001da177e4SLinus Torvalds u32 mynel = 0, maxnel = SIDS_NEL; 21011da177e4SLinus Torvalds struct user_datum *user; 21021da177e4SLinus Torvalds struct role_datum *role; 2103782ebb99SStephen Smalley struct ebitmap_node *rnode, *tnode; 21041da177e4SLinus Torvalds int rc = 0, i, j; 21051da177e4SLinus Torvalds 21061da177e4SLinus Torvalds *sids = NULL; 21071da177e4SLinus Torvalds *nel = 0; 21082c3c05dbSStephen Smalley 21092c3c05dbSStephen Smalley if (!ss_initialized) 21101da177e4SLinus Torvalds goto out; 21111da177e4SLinus Torvalds 21120804d113SJames Morris read_lock(&policy_rwlock); 21131da177e4SLinus Torvalds 211412b29f34SStephen Smalley context_init(&usercon); 211512b29f34SStephen Smalley 21164b02b524SEric Paris rc = -EINVAL; 21171da177e4SLinus Torvalds fromcon = sidtab_search(&sidtab, fromsid); 21184b02b524SEric Paris if (!fromcon) 21191da177e4SLinus Torvalds goto out_unlock; 21201da177e4SLinus Torvalds 21211da177e4SLinus Torvalds rc = -EINVAL; 21224b02b524SEric Paris user = hashtab_search(policydb.p_users.table, username); 21234b02b524SEric Paris if (!user) 21241da177e4SLinus Torvalds goto out_unlock; 21254b02b524SEric Paris 21261da177e4SLinus Torvalds usercon.user = user->value; 21271da177e4SLinus Torvalds 21281da177e4SLinus Torvalds rc = -ENOMEM; 21294b02b524SEric Paris mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC); 21304b02b524SEric Paris if (!mysids) 21311da177e4SLinus Torvalds goto out_unlock; 21321da177e4SLinus Torvalds 21339fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&user->roles, rnode, i) { 21341da177e4SLinus Torvalds role = policydb.role_val_to_struct[i]; 21351da177e4SLinus Torvalds usercon.role = i + 1; 21369fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&role->types, tnode, j) { 21371da177e4SLinus Torvalds usercon.type = j + 1; 21381da177e4SLinus Torvalds 21391da177e4SLinus Torvalds if (mls_setup_user_range(fromcon, user, &usercon)) 21401da177e4SLinus Torvalds continue; 21411da177e4SLinus Torvalds 21421da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); 21432c3c05dbSStephen Smalley if (rc) 21441da177e4SLinus Torvalds goto out_unlock; 21451da177e4SLinus Torvalds if (mynel < maxnel) { 21461da177e4SLinus Torvalds mysids[mynel++] = sid; 21471da177e4SLinus Torvalds } else { 21484b02b524SEric Paris rc = -ENOMEM; 21491da177e4SLinus Torvalds maxnel += SIDS_NEL; 215089d155efSJames Morris mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); 21514b02b524SEric Paris if (!mysids2) 21521da177e4SLinus Torvalds goto out_unlock; 21531da177e4SLinus Torvalds memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); 21541da177e4SLinus Torvalds kfree(mysids); 21551da177e4SLinus Torvalds mysids = mysids2; 21561da177e4SLinus Torvalds mysids[mynel++] = sid; 21571da177e4SLinus Torvalds } 21581da177e4SLinus Torvalds } 21591da177e4SLinus Torvalds } 21604b02b524SEric Paris rc = 0; 21611da177e4SLinus Torvalds out_unlock: 21620804d113SJames Morris read_unlock(&policy_rwlock); 21632c3c05dbSStephen Smalley if (rc || !mynel) { 21642c3c05dbSStephen Smalley kfree(mysids); 21652c3c05dbSStephen Smalley goto out; 21662c3c05dbSStephen Smalley } 21672c3c05dbSStephen Smalley 21684b02b524SEric Paris rc = -ENOMEM; 21692c3c05dbSStephen Smalley mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL); 21702c3c05dbSStephen Smalley if (!mysids2) { 21712c3c05dbSStephen Smalley kfree(mysids); 21722c3c05dbSStephen Smalley goto out; 21732c3c05dbSStephen Smalley } 21742c3c05dbSStephen Smalley for (i = 0, j = 0; i < mynel; i++) { 21752c3c05dbSStephen Smalley rc = avc_has_perm_noaudit(fromsid, mysids[i], 2176c6d3aaa4SStephen Smalley SECCLASS_PROCESS, /* kernel value */ 21772c3c05dbSStephen Smalley PROCESS__TRANSITION, AVC_STRICT, 21782c3c05dbSStephen Smalley NULL); 21792c3c05dbSStephen Smalley if (!rc) 21802c3c05dbSStephen Smalley mysids2[j++] = mysids[i]; 21812c3c05dbSStephen Smalley cond_resched(); 21822c3c05dbSStephen Smalley } 21832c3c05dbSStephen Smalley rc = 0; 21842c3c05dbSStephen Smalley kfree(mysids); 21852c3c05dbSStephen Smalley *sids = mysids2; 21862c3c05dbSStephen Smalley *nel = j; 21871da177e4SLinus Torvalds out: 21881da177e4SLinus Torvalds return rc; 21891da177e4SLinus Torvalds } 21901da177e4SLinus Torvalds 21911da177e4SLinus Torvalds /** 21921da177e4SLinus Torvalds * security_genfs_sid - Obtain a SID for a file in a filesystem 21931da177e4SLinus Torvalds * @fstype: filesystem type 21941da177e4SLinus Torvalds * @path: path from root of mount 21951da177e4SLinus Torvalds * @sclass: file security class 21961da177e4SLinus Torvalds * @sid: SID for path 21971da177e4SLinus Torvalds * 21981da177e4SLinus Torvalds * Obtain a SID to use for a file in a filesystem that 21991da177e4SLinus Torvalds * cannot support xattr or use a fixed labeling behavior like 22001da177e4SLinus Torvalds * transition SIDs or task SIDs. 22011da177e4SLinus Torvalds */ 22021da177e4SLinus Torvalds int security_genfs_sid(const char *fstype, 22031da177e4SLinus Torvalds char *path, 2204c6d3aaa4SStephen Smalley u16 orig_sclass, 22051da177e4SLinus Torvalds u32 *sid) 22061da177e4SLinus Torvalds { 22071da177e4SLinus Torvalds int len; 2208c6d3aaa4SStephen Smalley u16 sclass; 22091da177e4SLinus Torvalds struct genfs *genfs; 22101da177e4SLinus Torvalds struct ocontext *c; 22114b02b524SEric Paris int rc, cmp = 0; 22121da177e4SLinus Torvalds 2213b1aa5301SStephen Smalley while (path[0] == '/' && path[1] == '/') 2214b1aa5301SStephen Smalley path++; 2215b1aa5301SStephen Smalley 22160804d113SJames Morris read_lock(&policy_rwlock); 22171da177e4SLinus Torvalds 2218c6d3aaa4SStephen Smalley sclass = unmap_class(orig_sclass); 22194b02b524SEric Paris *sid = SECINITSID_UNLABELED; 2220c6d3aaa4SStephen Smalley 22211da177e4SLinus Torvalds for (genfs = policydb.genfs; genfs; genfs = genfs->next) { 22221da177e4SLinus Torvalds cmp = strcmp(fstype, genfs->fstype); 22231da177e4SLinus Torvalds if (cmp <= 0) 22241da177e4SLinus Torvalds break; 22251da177e4SLinus Torvalds } 22261da177e4SLinus Torvalds 22271da177e4SLinus Torvalds rc = -ENOENT; 22284b02b524SEric Paris if (!genfs || cmp) 22291da177e4SLinus Torvalds goto out; 22301da177e4SLinus Torvalds 22311da177e4SLinus Torvalds for (c = genfs->head; c; c = c->next) { 22321da177e4SLinus Torvalds len = strlen(c->u.name); 22331da177e4SLinus Torvalds if ((!c->v.sclass || sclass == c->v.sclass) && 22341da177e4SLinus Torvalds (strncmp(c->u.name, path, len) == 0)) 22351da177e4SLinus Torvalds break; 22361da177e4SLinus Torvalds } 22371da177e4SLinus Torvalds 22381da177e4SLinus Torvalds rc = -ENOENT; 22394b02b524SEric Paris if (!c) 22401da177e4SLinus Torvalds goto out; 22411da177e4SLinus Torvalds 22421da177e4SLinus Torvalds if (!c->sid[0]) { 22434b02b524SEric Paris rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]); 22441da177e4SLinus Torvalds if (rc) 22451da177e4SLinus Torvalds goto out; 22461da177e4SLinus Torvalds } 22471da177e4SLinus Torvalds 22481da177e4SLinus Torvalds *sid = c->sid[0]; 22494b02b524SEric Paris rc = 0; 22501da177e4SLinus Torvalds out: 22510804d113SJames Morris read_unlock(&policy_rwlock); 22521da177e4SLinus Torvalds return rc; 22531da177e4SLinus Torvalds } 22541da177e4SLinus Torvalds 22551da177e4SLinus Torvalds /** 22561da177e4SLinus Torvalds * security_fs_use - Determine how to handle labeling for a filesystem. 22571da177e4SLinus Torvalds * @fstype: filesystem type 22581da177e4SLinus Torvalds * @behavior: labeling behavior 22591da177e4SLinus Torvalds * @sid: SID for filesystem (superblock) 22601da177e4SLinus Torvalds */ 22611da177e4SLinus Torvalds int security_fs_use( 22621da177e4SLinus Torvalds const char *fstype, 22631da177e4SLinus Torvalds unsigned int *behavior, 2264089be43eSJames Morris u32 *sid) 22651da177e4SLinus Torvalds { 22661da177e4SLinus Torvalds int rc = 0; 22671da177e4SLinus Torvalds struct ocontext *c; 22681da177e4SLinus Torvalds 22690804d113SJames Morris read_lock(&policy_rwlock); 22701da177e4SLinus Torvalds 22711da177e4SLinus Torvalds c = policydb.ocontexts[OCON_FSUSE]; 22721da177e4SLinus Torvalds while (c) { 22731da177e4SLinus Torvalds if (strcmp(fstype, c->u.name) == 0) 22741da177e4SLinus Torvalds break; 22751da177e4SLinus Torvalds c = c->next; 22761da177e4SLinus Torvalds } 22771da177e4SLinus Torvalds 22781da177e4SLinus Torvalds if (c) { 22791da177e4SLinus Torvalds *behavior = c->v.behavior; 22801da177e4SLinus Torvalds if (!c->sid[0]) { 22814b02b524SEric Paris rc = sidtab_context_to_sid(&sidtab, &c->context[0], 22821da177e4SLinus Torvalds &c->sid[0]); 22831da177e4SLinus Torvalds if (rc) 22841da177e4SLinus Torvalds goto out; 22851da177e4SLinus Torvalds } 22861da177e4SLinus Torvalds *sid = c->sid[0]; 2287089be43eSJames Morris } else { 22881da177e4SLinus Torvalds rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); 22891da177e4SLinus Torvalds if (rc) { 22901da177e4SLinus Torvalds *behavior = SECURITY_FS_USE_NONE; 22911da177e4SLinus Torvalds rc = 0; 22921da177e4SLinus Torvalds } else { 22931da177e4SLinus Torvalds *behavior = SECURITY_FS_USE_GENFS; 22941da177e4SLinus Torvalds } 2295089be43eSJames Morris } 22961da177e4SLinus Torvalds 22971da177e4SLinus Torvalds out: 22980804d113SJames Morris read_unlock(&policy_rwlock); 22991da177e4SLinus Torvalds return rc; 23001da177e4SLinus Torvalds } 23011da177e4SLinus Torvalds 23021da177e4SLinus Torvalds int security_get_bools(int *len, char ***names, int **values) 23031da177e4SLinus Torvalds { 23044b02b524SEric Paris int i, rc; 23051da177e4SLinus Torvalds 23060804d113SJames Morris read_lock(&policy_rwlock); 23071da177e4SLinus Torvalds *names = NULL; 23081da177e4SLinus Torvalds *values = NULL; 23091da177e4SLinus Torvalds 23101da177e4SLinus Torvalds rc = 0; 23114b02b524SEric Paris *len = policydb.p_bools.nprim; 23124b02b524SEric Paris if (!*len) 23131da177e4SLinus Torvalds goto out; 23141da177e4SLinus Torvalds 23154b02b524SEric Paris rc = -ENOMEM; 2316e0795cf4SJesper Juhl *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); 23171da177e4SLinus Torvalds if (!*names) 23181da177e4SLinus Torvalds goto err; 23191da177e4SLinus Torvalds 23204b02b524SEric Paris rc = -ENOMEM; 2321e0795cf4SJesper Juhl *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); 23221da177e4SLinus Torvalds if (!*values) 23231da177e4SLinus Torvalds goto err; 23241da177e4SLinus Torvalds 23251da177e4SLinus Torvalds for (i = 0; i < *len; i++) { 23261da177e4SLinus Torvalds size_t name_len; 23274b02b524SEric Paris 23281da177e4SLinus Torvalds (*values)[i] = policydb.bool_val_to_struct[i]->state; 2329ac76c05bSEric Paris name_len = strlen(sym_name(&policydb, SYM_BOOLS, i)) + 1; 23304b02b524SEric Paris 23314b02b524SEric Paris rc = -ENOMEM; 2332e0795cf4SJesper Juhl (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC); 23331da177e4SLinus Torvalds if (!(*names)[i]) 23341da177e4SLinus Torvalds goto err; 23354b02b524SEric Paris 2336ac76c05bSEric Paris strncpy((*names)[i], sym_name(&policydb, SYM_BOOLS, i), name_len); 23371da177e4SLinus Torvalds (*names)[i][name_len - 1] = 0; 23381da177e4SLinus Torvalds } 23391da177e4SLinus Torvalds rc = 0; 23401da177e4SLinus Torvalds out: 23410804d113SJames Morris read_unlock(&policy_rwlock); 23421da177e4SLinus Torvalds return rc; 23431da177e4SLinus Torvalds err: 23441da177e4SLinus Torvalds if (*names) { 23451da177e4SLinus Torvalds for (i = 0; i < *len; i++) 23461da177e4SLinus Torvalds kfree((*names)[i]); 23471da177e4SLinus Torvalds } 23481da177e4SLinus Torvalds kfree(*values); 23491da177e4SLinus Torvalds goto out; 23501da177e4SLinus Torvalds } 23511da177e4SLinus Torvalds 23521da177e4SLinus Torvalds 23531da177e4SLinus Torvalds int security_set_bools(int len, int *values) 23541da177e4SLinus Torvalds { 23554b02b524SEric Paris int i, rc; 23561da177e4SLinus Torvalds int lenp, seqno = 0; 23571da177e4SLinus Torvalds struct cond_node *cur; 23581da177e4SLinus Torvalds 23590804d113SJames Morris write_lock_irq(&policy_rwlock); 23601da177e4SLinus Torvalds 23611da177e4SLinus Torvalds rc = -EFAULT; 23624b02b524SEric Paris lenp = policydb.p_bools.nprim; 23634b02b524SEric Paris if (len != lenp) 23641da177e4SLinus Torvalds goto out; 23651da177e4SLinus Torvalds 23661da177e4SLinus Torvalds for (i = 0; i < len; i++) { 2367af601e46SSteve Grubb if (!!values[i] != policydb.bool_val_to_struct[i]->state) { 2368af601e46SSteve Grubb audit_log(current->audit_context, GFP_ATOMIC, 2369af601e46SSteve Grubb AUDIT_MAC_CONFIG_CHANGE, 23704746ec5bSEric Paris "bool=%s val=%d old_val=%d auid=%u ses=%u", 2371ac76c05bSEric Paris sym_name(&policydb, SYM_BOOLS, i), 2372af601e46SSteve Grubb !!values[i], 2373af601e46SSteve Grubb policydb.bool_val_to_struct[i]->state, 23744746ec5bSEric Paris audit_get_loginuid(current), 23754746ec5bSEric Paris audit_get_sessionid(current)); 2376af601e46SSteve Grubb } 23775d55a345SEric Paris if (values[i]) 23781da177e4SLinus Torvalds policydb.bool_val_to_struct[i]->state = 1; 23795d55a345SEric Paris else 23801da177e4SLinus Torvalds policydb.bool_val_to_struct[i]->state = 0; 23811da177e4SLinus Torvalds } 23821da177e4SLinus Torvalds 2383dbc74c65SVesa-Matti Kari for (cur = policydb.cond_list; cur; cur = cur->next) { 23841da177e4SLinus Torvalds rc = evaluate_cond_node(&policydb, cur); 23851da177e4SLinus Torvalds if (rc) 23861da177e4SLinus Torvalds goto out; 23871da177e4SLinus Torvalds } 23881da177e4SLinus Torvalds 23891da177e4SLinus Torvalds seqno = ++latest_granting; 23904b02b524SEric Paris rc = 0; 23911da177e4SLinus Torvalds out: 23920804d113SJames Morris write_unlock_irq(&policy_rwlock); 23931da177e4SLinus Torvalds if (!rc) { 23941da177e4SLinus Torvalds avc_ss_reset(seqno); 23951da177e4SLinus Torvalds selnl_notify_policyload(seqno); 239611904167SKaiGai Kohei selinux_status_update_policyload(seqno); 2397342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 23981da177e4SLinus Torvalds } 23991da177e4SLinus Torvalds return rc; 24001da177e4SLinus Torvalds } 24011da177e4SLinus Torvalds 24021da177e4SLinus Torvalds int security_get_bool_value(int bool) 24031da177e4SLinus Torvalds { 24044b02b524SEric Paris int rc; 24051da177e4SLinus Torvalds int len; 24061da177e4SLinus Torvalds 24070804d113SJames Morris read_lock(&policy_rwlock); 24081da177e4SLinus Torvalds 24091da177e4SLinus Torvalds rc = -EFAULT; 24104b02b524SEric Paris len = policydb.p_bools.nprim; 24114b02b524SEric Paris if (bool >= len) 24121da177e4SLinus Torvalds goto out; 24131da177e4SLinus Torvalds 24141da177e4SLinus Torvalds rc = policydb.bool_val_to_struct[bool]->state; 24151da177e4SLinus Torvalds out: 24160804d113SJames Morris read_unlock(&policy_rwlock); 24171da177e4SLinus Torvalds return rc; 24181da177e4SLinus Torvalds } 2419376bd9cbSDarrel Goeddel 2420e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p) 2421e900a7d9SStephen Smalley { 2422e900a7d9SStephen Smalley int rc, nbools = 0, *bvalues = NULL, i; 2423e900a7d9SStephen Smalley char **bnames = NULL; 2424e900a7d9SStephen Smalley struct cond_bool_datum *booldatum; 2425e900a7d9SStephen Smalley struct cond_node *cur; 2426e900a7d9SStephen Smalley 2427e900a7d9SStephen Smalley rc = security_get_bools(&nbools, &bnames, &bvalues); 2428e900a7d9SStephen Smalley if (rc) 2429e900a7d9SStephen Smalley goto out; 2430e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) { 2431e900a7d9SStephen Smalley booldatum = hashtab_search(p->p_bools.table, bnames[i]); 2432e900a7d9SStephen Smalley if (booldatum) 2433e900a7d9SStephen Smalley booldatum->state = bvalues[i]; 2434e900a7d9SStephen Smalley } 2435dbc74c65SVesa-Matti Kari for (cur = p->cond_list; cur; cur = cur->next) { 2436e900a7d9SStephen Smalley rc = evaluate_cond_node(p, cur); 2437e900a7d9SStephen Smalley if (rc) 2438e900a7d9SStephen Smalley goto out; 2439e900a7d9SStephen Smalley } 2440e900a7d9SStephen Smalley 2441e900a7d9SStephen Smalley out: 2442e900a7d9SStephen Smalley if (bnames) { 2443e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) 2444e900a7d9SStephen Smalley kfree(bnames[i]); 2445e900a7d9SStephen Smalley } 2446e900a7d9SStephen Smalley kfree(bnames); 2447e900a7d9SStephen Smalley kfree(bvalues); 2448e900a7d9SStephen Smalley return rc; 2449e900a7d9SStephen Smalley } 2450e900a7d9SStephen Smalley 245108554d6bSVenkat Yekkirala /* 245208554d6bSVenkat Yekkirala * security_sid_mls_copy() - computes a new sid based on the given 245308554d6bSVenkat Yekkirala * sid and the mls portion of mls_sid. 245408554d6bSVenkat Yekkirala */ 245508554d6bSVenkat Yekkirala int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) 245608554d6bSVenkat Yekkirala { 245708554d6bSVenkat Yekkirala struct context *context1; 245808554d6bSVenkat Yekkirala struct context *context2; 245908554d6bSVenkat Yekkirala struct context newcon; 246008554d6bSVenkat Yekkirala char *s; 246108554d6bSVenkat Yekkirala u32 len; 24624b02b524SEric Paris int rc; 246308554d6bSVenkat Yekkirala 24644b02b524SEric Paris rc = 0; 24650719aaf5SGuido Trentalancia if (!ss_initialized || !policydb.mls_enabled) { 246608554d6bSVenkat Yekkirala *new_sid = sid; 246708554d6bSVenkat Yekkirala goto out; 246808554d6bSVenkat Yekkirala } 246908554d6bSVenkat Yekkirala 247008554d6bSVenkat Yekkirala context_init(&newcon); 247108554d6bSVenkat Yekkirala 24720804d113SJames Morris read_lock(&policy_rwlock); 24734b02b524SEric Paris 24744b02b524SEric Paris rc = -EINVAL; 247508554d6bSVenkat Yekkirala context1 = sidtab_search(&sidtab, sid); 247608554d6bSVenkat Yekkirala if (!context1) { 2477744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2478744ba35eSEric Paris __func__, sid); 247908554d6bSVenkat Yekkirala goto out_unlock; 248008554d6bSVenkat Yekkirala } 248108554d6bSVenkat Yekkirala 24824b02b524SEric Paris rc = -EINVAL; 248308554d6bSVenkat Yekkirala context2 = sidtab_search(&sidtab, mls_sid); 248408554d6bSVenkat Yekkirala if (!context2) { 2485744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2486744ba35eSEric Paris __func__, mls_sid); 248708554d6bSVenkat Yekkirala goto out_unlock; 248808554d6bSVenkat Yekkirala } 248908554d6bSVenkat Yekkirala 249008554d6bSVenkat Yekkirala newcon.user = context1->user; 249108554d6bSVenkat Yekkirala newcon.role = context1->role; 249208554d6bSVenkat Yekkirala newcon.type = context1->type; 24930efc61eaSVenkat Yekkirala rc = mls_context_cpy(&newcon, context2); 249408554d6bSVenkat Yekkirala if (rc) 249508554d6bSVenkat Yekkirala goto out_unlock; 249608554d6bSVenkat Yekkirala 249708554d6bSVenkat Yekkirala /* Check the validity of the new context. */ 249808554d6bSVenkat Yekkirala if (!policydb_context_isvalid(&policydb, &newcon)) { 249908554d6bSVenkat Yekkirala rc = convert_context_handle_invalid_context(&newcon); 25004b02b524SEric Paris if (rc) { 250108554d6bSVenkat Yekkirala if (!context_struct_to_string(&newcon, &s, &len)) { 250208554d6bSVenkat Yekkirala audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 250308554d6bSVenkat Yekkirala "security_sid_mls_copy: invalid context %s", s); 250408554d6bSVenkat Yekkirala kfree(s); 250508554d6bSVenkat Yekkirala } 25064b02b524SEric Paris goto out_unlock; 25074b02b524SEric Paris } 25084b02b524SEric Paris } 250908554d6bSVenkat Yekkirala 25104b02b524SEric Paris rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid); 251108554d6bSVenkat Yekkirala out_unlock: 25120804d113SJames Morris read_unlock(&policy_rwlock); 251308554d6bSVenkat Yekkirala context_destroy(&newcon); 251408554d6bSVenkat Yekkirala out: 251508554d6bSVenkat Yekkirala return rc; 251608554d6bSVenkat Yekkirala } 251708554d6bSVenkat Yekkirala 2518220deb96SPaul Moore /** 2519220deb96SPaul Moore * security_net_peersid_resolve - Compare and resolve two network peer SIDs 2520220deb96SPaul Moore * @nlbl_sid: NetLabel SID 2521220deb96SPaul Moore * @nlbl_type: NetLabel labeling protocol type 2522220deb96SPaul Moore * @xfrm_sid: XFRM SID 2523220deb96SPaul Moore * 2524220deb96SPaul Moore * Description: 2525220deb96SPaul Moore * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be 2526220deb96SPaul Moore * resolved into a single SID it is returned via @peer_sid and the function 2527220deb96SPaul Moore * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function 2528220deb96SPaul Moore * returns a negative value. A table summarizing the behavior is below: 2529220deb96SPaul Moore * 2530220deb96SPaul Moore * | function return | @sid 2531220deb96SPaul Moore * ------------------------------+-----------------+----------------- 2532220deb96SPaul Moore * no peer labels | 0 | SECSID_NULL 2533220deb96SPaul Moore * single peer label | 0 | <peer_label> 2534220deb96SPaul Moore * multiple, consistent labels | 0 | <peer_label> 2535220deb96SPaul Moore * multiple, inconsistent labels | -<errno> | SECSID_NULL 2536220deb96SPaul Moore * 2537220deb96SPaul Moore */ 2538220deb96SPaul Moore int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, 2539220deb96SPaul Moore u32 xfrm_sid, 2540220deb96SPaul Moore u32 *peer_sid) 2541220deb96SPaul Moore { 2542220deb96SPaul Moore int rc; 2543220deb96SPaul Moore struct context *nlbl_ctx; 2544220deb96SPaul Moore struct context *xfrm_ctx; 2545220deb96SPaul Moore 25464b02b524SEric Paris *peer_sid = SECSID_NULL; 25474b02b524SEric Paris 2548220deb96SPaul Moore /* handle the common (which also happens to be the set of easy) cases 2549220deb96SPaul Moore * right away, these two if statements catch everything involving a 2550220deb96SPaul Moore * single or absent peer SID/label */ 2551220deb96SPaul Moore if (xfrm_sid == SECSID_NULL) { 2552220deb96SPaul Moore *peer_sid = nlbl_sid; 2553220deb96SPaul Moore return 0; 2554220deb96SPaul Moore } 2555220deb96SPaul Moore /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label 2556220deb96SPaul Moore * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label 2557220deb96SPaul Moore * is present */ 2558220deb96SPaul Moore if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) { 2559220deb96SPaul Moore *peer_sid = xfrm_sid; 2560220deb96SPaul Moore return 0; 2561220deb96SPaul Moore } 2562220deb96SPaul Moore 2563220deb96SPaul Moore /* we don't need to check ss_initialized here since the only way both 2564220deb96SPaul Moore * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the 2565220deb96SPaul Moore * security server was initialized and ss_initialized was true */ 25664b02b524SEric Paris if (!policydb.mls_enabled) 2567220deb96SPaul Moore return 0; 2568220deb96SPaul Moore 25690804d113SJames Morris read_lock(&policy_rwlock); 2570220deb96SPaul Moore 25714b02b524SEric Paris rc = -EINVAL; 2572220deb96SPaul Moore nlbl_ctx = sidtab_search(&sidtab, nlbl_sid); 2573220deb96SPaul Moore if (!nlbl_ctx) { 2574744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2575744ba35eSEric Paris __func__, nlbl_sid); 25764b02b524SEric Paris goto out; 2577220deb96SPaul Moore } 25784b02b524SEric Paris rc = -EINVAL; 2579220deb96SPaul Moore xfrm_ctx = sidtab_search(&sidtab, xfrm_sid); 2580220deb96SPaul Moore if (!xfrm_ctx) { 2581744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2582744ba35eSEric Paris __func__, xfrm_sid); 25834b02b524SEric Paris goto out; 2584220deb96SPaul Moore } 2585220deb96SPaul Moore rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); 25864b02b524SEric Paris if (rc) 25874b02b524SEric Paris goto out; 2588220deb96SPaul Moore 2589220deb96SPaul Moore /* at present NetLabel SIDs/labels really only carry MLS 2590220deb96SPaul Moore * information so if the MLS portion of the NetLabel SID 2591220deb96SPaul Moore * matches the MLS portion of the labeled XFRM SID/label 2592220deb96SPaul Moore * then pass along the XFRM SID as it is the most 2593220deb96SPaul Moore * expressive */ 2594220deb96SPaul Moore *peer_sid = xfrm_sid; 25954b02b524SEric Paris out: 25964b02b524SEric Paris read_unlock(&policy_rwlock); 2597220deb96SPaul Moore return rc; 2598220deb96SPaul Moore } 2599220deb96SPaul Moore 260055fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args) 260155fcf09bSChristopher J. PeBenito { 260255fcf09bSChristopher J. PeBenito struct class_datum *datum = d; 260355fcf09bSChristopher J. PeBenito char *name = k, **classes = args; 260455fcf09bSChristopher J. PeBenito int value = datum->value - 1; 260555fcf09bSChristopher J. PeBenito 260655fcf09bSChristopher J. PeBenito classes[value] = kstrdup(name, GFP_ATOMIC); 260755fcf09bSChristopher J. PeBenito if (!classes[value]) 260855fcf09bSChristopher J. PeBenito return -ENOMEM; 260955fcf09bSChristopher J. PeBenito 261055fcf09bSChristopher J. PeBenito return 0; 261155fcf09bSChristopher J. PeBenito } 261255fcf09bSChristopher J. PeBenito 261355fcf09bSChristopher J. PeBenito int security_get_classes(char ***classes, int *nclasses) 261455fcf09bSChristopher J. PeBenito { 26154b02b524SEric Paris int rc; 261655fcf09bSChristopher J. PeBenito 26170804d113SJames Morris read_lock(&policy_rwlock); 261855fcf09bSChristopher J. PeBenito 26194b02b524SEric Paris rc = -ENOMEM; 262055fcf09bSChristopher J. PeBenito *nclasses = policydb.p_classes.nprim; 26219f59f90bSJulia Lawall *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC); 262255fcf09bSChristopher J. PeBenito if (!*classes) 262355fcf09bSChristopher J. PeBenito goto out; 262455fcf09bSChristopher J. PeBenito 262555fcf09bSChristopher J. PeBenito rc = hashtab_map(policydb.p_classes.table, get_classes_callback, 262655fcf09bSChristopher J. PeBenito *classes); 26274b02b524SEric Paris if (rc) { 262855fcf09bSChristopher J. PeBenito int i; 262955fcf09bSChristopher J. PeBenito for (i = 0; i < *nclasses; i++) 263055fcf09bSChristopher J. PeBenito kfree((*classes)[i]); 263155fcf09bSChristopher J. PeBenito kfree(*classes); 263255fcf09bSChristopher J. PeBenito } 263355fcf09bSChristopher J. PeBenito 263455fcf09bSChristopher J. PeBenito out: 26350804d113SJames Morris read_unlock(&policy_rwlock); 263655fcf09bSChristopher J. PeBenito return rc; 263755fcf09bSChristopher J. PeBenito } 263855fcf09bSChristopher J. PeBenito 263955fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args) 264055fcf09bSChristopher J. PeBenito { 264155fcf09bSChristopher J. PeBenito struct perm_datum *datum = d; 264255fcf09bSChristopher J. PeBenito char *name = k, **perms = args; 264355fcf09bSChristopher J. PeBenito int value = datum->value - 1; 264455fcf09bSChristopher J. PeBenito 264555fcf09bSChristopher J. PeBenito perms[value] = kstrdup(name, GFP_ATOMIC); 264655fcf09bSChristopher J. PeBenito if (!perms[value]) 264755fcf09bSChristopher J. PeBenito return -ENOMEM; 264855fcf09bSChristopher J. PeBenito 264955fcf09bSChristopher J. PeBenito return 0; 265055fcf09bSChristopher J. PeBenito } 265155fcf09bSChristopher J. PeBenito 265255fcf09bSChristopher J. PeBenito int security_get_permissions(char *class, char ***perms, int *nperms) 265355fcf09bSChristopher J. PeBenito { 26544b02b524SEric Paris int rc, i; 265555fcf09bSChristopher J. PeBenito struct class_datum *match; 265655fcf09bSChristopher J. PeBenito 26570804d113SJames Morris read_lock(&policy_rwlock); 265855fcf09bSChristopher J. PeBenito 26594b02b524SEric Paris rc = -EINVAL; 266055fcf09bSChristopher J. PeBenito match = hashtab_search(policydb.p_classes.table, class); 266155fcf09bSChristopher J. PeBenito if (!match) { 2662744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized class %s\n", 2663dd6f953aSHarvey Harrison __func__, class); 266455fcf09bSChristopher J. PeBenito goto out; 266555fcf09bSChristopher J. PeBenito } 266655fcf09bSChristopher J. PeBenito 26674b02b524SEric Paris rc = -ENOMEM; 266855fcf09bSChristopher J. PeBenito *nperms = match->permissions.nprim; 26699f59f90bSJulia Lawall *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC); 267055fcf09bSChristopher J. PeBenito if (!*perms) 267155fcf09bSChristopher J. PeBenito goto out; 267255fcf09bSChristopher J. PeBenito 267355fcf09bSChristopher J. PeBenito if (match->comdatum) { 267455fcf09bSChristopher J. PeBenito rc = hashtab_map(match->comdatum->permissions.table, 267555fcf09bSChristopher J. PeBenito get_permissions_callback, *perms); 26764b02b524SEric Paris if (rc) 267755fcf09bSChristopher J. PeBenito goto err; 267855fcf09bSChristopher J. PeBenito } 267955fcf09bSChristopher J. PeBenito 268055fcf09bSChristopher J. PeBenito rc = hashtab_map(match->permissions.table, get_permissions_callback, 268155fcf09bSChristopher J. PeBenito *perms); 26824b02b524SEric Paris if (rc) 268355fcf09bSChristopher J. PeBenito goto err; 268455fcf09bSChristopher J. PeBenito 268555fcf09bSChristopher J. PeBenito out: 26860804d113SJames Morris read_unlock(&policy_rwlock); 268755fcf09bSChristopher J. PeBenito return rc; 268855fcf09bSChristopher J. PeBenito 268955fcf09bSChristopher J. PeBenito err: 26900804d113SJames Morris read_unlock(&policy_rwlock); 269155fcf09bSChristopher J. PeBenito for (i = 0; i < *nperms; i++) 269255fcf09bSChristopher J. PeBenito kfree((*perms)[i]); 269355fcf09bSChristopher J. PeBenito kfree(*perms); 269455fcf09bSChristopher J. PeBenito return rc; 269555fcf09bSChristopher J. PeBenito } 269655fcf09bSChristopher J. PeBenito 26973f12070eSEric Paris int security_get_reject_unknown(void) 26983f12070eSEric Paris { 26993f12070eSEric Paris return policydb.reject_unknown; 27003f12070eSEric Paris } 27013f12070eSEric Paris 27023f12070eSEric Paris int security_get_allow_unknown(void) 27033f12070eSEric Paris { 27043f12070eSEric Paris return policydb.allow_unknown; 27053f12070eSEric Paris } 27063f12070eSEric Paris 27073bb56b25SPaul Moore /** 27083bb56b25SPaul Moore * security_policycap_supported - Check for a specific policy capability 27093bb56b25SPaul Moore * @req_cap: capability 27103bb56b25SPaul Moore * 27113bb56b25SPaul Moore * Description: 27123bb56b25SPaul Moore * This function queries the currently loaded policy to see if it supports the 27133bb56b25SPaul Moore * capability specified by @req_cap. Returns true (1) if the capability is 27143bb56b25SPaul Moore * supported, false (0) if it isn't supported. 27153bb56b25SPaul Moore * 27163bb56b25SPaul Moore */ 27173bb56b25SPaul Moore int security_policycap_supported(unsigned int req_cap) 27183bb56b25SPaul Moore { 27193bb56b25SPaul Moore int rc; 27203bb56b25SPaul Moore 27210804d113SJames Morris read_lock(&policy_rwlock); 27223bb56b25SPaul Moore rc = ebitmap_get_bit(&policydb.policycaps, req_cap); 27230804d113SJames Morris read_unlock(&policy_rwlock); 27243bb56b25SPaul Moore 27253bb56b25SPaul Moore return rc; 27263bb56b25SPaul Moore } 27273bb56b25SPaul Moore 2728376bd9cbSDarrel Goeddel struct selinux_audit_rule { 2729376bd9cbSDarrel Goeddel u32 au_seqno; 2730376bd9cbSDarrel Goeddel struct context au_ctxt; 2731376bd9cbSDarrel Goeddel }; 2732376bd9cbSDarrel Goeddel 27339d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule) 2734376bd9cbSDarrel Goeddel { 27359d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule; 27369d57a7f9SAhmed S. Darwish 2737376bd9cbSDarrel Goeddel if (rule) { 2738376bd9cbSDarrel Goeddel context_destroy(&rule->au_ctxt); 2739376bd9cbSDarrel Goeddel kfree(rule); 2740376bd9cbSDarrel Goeddel } 2741376bd9cbSDarrel Goeddel } 2742376bd9cbSDarrel Goeddel 27439d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) 2744376bd9cbSDarrel Goeddel { 2745376bd9cbSDarrel Goeddel struct selinux_audit_rule *tmprule; 2746376bd9cbSDarrel Goeddel struct role_datum *roledatum; 2747376bd9cbSDarrel Goeddel struct type_datum *typedatum; 2748376bd9cbSDarrel Goeddel struct user_datum *userdatum; 27499d57a7f9SAhmed S. Darwish struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule; 2750376bd9cbSDarrel Goeddel int rc = 0; 2751376bd9cbSDarrel Goeddel 2752376bd9cbSDarrel Goeddel *rule = NULL; 2753376bd9cbSDarrel Goeddel 2754376bd9cbSDarrel Goeddel if (!ss_initialized) 27553ad40d64SSteve G return -EOPNOTSUPP; 2756376bd9cbSDarrel Goeddel 2757376bd9cbSDarrel Goeddel switch (field) { 27583a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 27593a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 27603a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 27616e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 27626e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 27636e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 2764376bd9cbSDarrel Goeddel /* only 'equals' and 'not equals' fit user, role, and type */ 27655af75d8dSAl Viro if (op != Audit_equal && op != Audit_not_equal) 2766376bd9cbSDarrel Goeddel return -EINVAL; 2767376bd9cbSDarrel Goeddel break; 27683a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 27693a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 27706e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 27716e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 2772376bd9cbSDarrel Goeddel /* we do not allow a range, indicated by the presense of '-' */ 2773376bd9cbSDarrel Goeddel if (strchr(rulestr, '-')) 2774376bd9cbSDarrel Goeddel return -EINVAL; 2775376bd9cbSDarrel Goeddel break; 2776376bd9cbSDarrel Goeddel default: 2777376bd9cbSDarrel Goeddel /* only the above fields are valid */ 2778376bd9cbSDarrel Goeddel return -EINVAL; 2779376bd9cbSDarrel Goeddel } 2780376bd9cbSDarrel Goeddel 2781376bd9cbSDarrel Goeddel tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL); 2782376bd9cbSDarrel Goeddel if (!tmprule) 2783376bd9cbSDarrel Goeddel return -ENOMEM; 2784376bd9cbSDarrel Goeddel 2785376bd9cbSDarrel Goeddel context_init(&tmprule->au_ctxt); 2786376bd9cbSDarrel Goeddel 27870804d113SJames Morris read_lock(&policy_rwlock); 2788376bd9cbSDarrel Goeddel 2789376bd9cbSDarrel Goeddel tmprule->au_seqno = latest_granting; 2790376bd9cbSDarrel Goeddel 2791376bd9cbSDarrel Goeddel switch (field) { 27923a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 27936e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 27944b02b524SEric Paris rc = -EINVAL; 2795376bd9cbSDarrel Goeddel userdatum = hashtab_search(policydb.p_users.table, rulestr); 2796376bd9cbSDarrel Goeddel if (!userdatum) 27974b02b524SEric Paris goto out; 2798376bd9cbSDarrel Goeddel tmprule->au_ctxt.user = userdatum->value; 2799376bd9cbSDarrel Goeddel break; 28003a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 28016e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 28024b02b524SEric Paris rc = -EINVAL; 2803376bd9cbSDarrel Goeddel roledatum = hashtab_search(policydb.p_roles.table, rulestr); 2804376bd9cbSDarrel Goeddel if (!roledatum) 28054b02b524SEric Paris goto out; 2806376bd9cbSDarrel Goeddel tmprule->au_ctxt.role = roledatum->value; 2807376bd9cbSDarrel Goeddel break; 28083a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 28096e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 28104b02b524SEric Paris rc = -EINVAL; 2811376bd9cbSDarrel Goeddel typedatum = hashtab_search(policydb.p_types.table, rulestr); 2812376bd9cbSDarrel Goeddel if (!typedatum) 28134b02b524SEric Paris goto out; 2814376bd9cbSDarrel Goeddel tmprule->au_ctxt.type = typedatum->value; 2815376bd9cbSDarrel Goeddel break; 28163a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 28173a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 28186e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 28196e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 2820376bd9cbSDarrel Goeddel rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC); 28214b02b524SEric Paris if (rc) 28224b02b524SEric Paris goto out; 2823376bd9cbSDarrel Goeddel break; 2824376bd9cbSDarrel Goeddel } 28254b02b524SEric Paris rc = 0; 28264b02b524SEric Paris out: 28270804d113SJames Morris read_unlock(&policy_rwlock); 2828376bd9cbSDarrel Goeddel 2829376bd9cbSDarrel Goeddel if (rc) { 2830376bd9cbSDarrel Goeddel selinux_audit_rule_free(tmprule); 2831376bd9cbSDarrel Goeddel tmprule = NULL; 2832376bd9cbSDarrel Goeddel } 2833376bd9cbSDarrel Goeddel 2834376bd9cbSDarrel Goeddel *rule = tmprule; 2835376bd9cbSDarrel Goeddel 2836376bd9cbSDarrel Goeddel return rc; 2837376bd9cbSDarrel Goeddel } 2838376bd9cbSDarrel Goeddel 28399d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */ 28409d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule) 28419d57a7f9SAhmed S. Darwish { 28429d57a7f9SAhmed S. Darwish int i; 28439d57a7f9SAhmed S. Darwish 28449d57a7f9SAhmed S. Darwish for (i = 0; i < rule->field_count; i++) { 28459d57a7f9SAhmed S. Darwish struct audit_field *f = &rule->fields[i]; 28469d57a7f9SAhmed S. Darwish switch (f->type) { 28479d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_USER: 28489d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_ROLE: 28499d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_TYPE: 28509d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_SEN: 28519d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_CLR: 28529d57a7f9SAhmed S. Darwish case AUDIT_OBJ_USER: 28539d57a7f9SAhmed S. Darwish case AUDIT_OBJ_ROLE: 28549d57a7f9SAhmed S. Darwish case AUDIT_OBJ_TYPE: 28559d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_LOW: 28569d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_HIGH: 28579d57a7f9SAhmed S. Darwish return 1; 28589d57a7f9SAhmed S. Darwish } 28599d57a7f9SAhmed S. Darwish } 28609d57a7f9SAhmed S. Darwish 28619d57a7f9SAhmed S. Darwish return 0; 28629d57a7f9SAhmed S. Darwish } 28639d57a7f9SAhmed S. Darwish 28649d57a7f9SAhmed S. Darwish int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, 2865376bd9cbSDarrel Goeddel struct audit_context *actx) 2866376bd9cbSDarrel Goeddel { 2867376bd9cbSDarrel Goeddel struct context *ctxt; 2868376bd9cbSDarrel Goeddel struct mls_level *level; 28699d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule; 2870376bd9cbSDarrel Goeddel int match = 0; 2871376bd9cbSDarrel Goeddel 2872376bd9cbSDarrel Goeddel if (!rule) { 2873376bd9cbSDarrel Goeddel audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, 2874376bd9cbSDarrel Goeddel "selinux_audit_rule_match: missing rule\n"); 2875376bd9cbSDarrel Goeddel return -ENOENT; 2876376bd9cbSDarrel Goeddel } 2877376bd9cbSDarrel Goeddel 28780804d113SJames Morris read_lock(&policy_rwlock); 2879376bd9cbSDarrel Goeddel 2880376bd9cbSDarrel Goeddel if (rule->au_seqno < latest_granting) { 2881376bd9cbSDarrel Goeddel audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, 2882376bd9cbSDarrel Goeddel "selinux_audit_rule_match: stale rule\n"); 2883376bd9cbSDarrel Goeddel match = -ESTALE; 2884376bd9cbSDarrel Goeddel goto out; 2885376bd9cbSDarrel Goeddel } 2886376bd9cbSDarrel Goeddel 28879a2f44f0SStephen Smalley ctxt = sidtab_search(&sidtab, sid); 2888376bd9cbSDarrel Goeddel if (!ctxt) { 2889376bd9cbSDarrel Goeddel audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, 2890376bd9cbSDarrel Goeddel "selinux_audit_rule_match: unrecognized SID %d\n", 28919a2f44f0SStephen Smalley sid); 2892376bd9cbSDarrel Goeddel match = -ENOENT; 2893376bd9cbSDarrel Goeddel goto out; 2894376bd9cbSDarrel Goeddel } 2895376bd9cbSDarrel Goeddel 2896376bd9cbSDarrel Goeddel /* a field/op pair that is not caught here will simply fall through 2897376bd9cbSDarrel Goeddel without a match */ 2898376bd9cbSDarrel Goeddel switch (field) { 28993a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 29006e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 2901376bd9cbSDarrel Goeddel switch (op) { 29025af75d8dSAl Viro case Audit_equal: 2903376bd9cbSDarrel Goeddel match = (ctxt->user == rule->au_ctxt.user); 2904376bd9cbSDarrel Goeddel break; 29055af75d8dSAl Viro case Audit_not_equal: 2906376bd9cbSDarrel Goeddel match = (ctxt->user != rule->au_ctxt.user); 2907376bd9cbSDarrel Goeddel break; 2908376bd9cbSDarrel Goeddel } 2909376bd9cbSDarrel Goeddel break; 29103a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 29116e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 2912376bd9cbSDarrel Goeddel switch (op) { 29135af75d8dSAl Viro case Audit_equal: 2914376bd9cbSDarrel Goeddel match = (ctxt->role == rule->au_ctxt.role); 2915376bd9cbSDarrel Goeddel break; 29165af75d8dSAl Viro case Audit_not_equal: 2917376bd9cbSDarrel Goeddel match = (ctxt->role != rule->au_ctxt.role); 2918376bd9cbSDarrel Goeddel break; 2919376bd9cbSDarrel Goeddel } 2920376bd9cbSDarrel Goeddel break; 29213a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 29226e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 2923376bd9cbSDarrel Goeddel switch (op) { 29245af75d8dSAl Viro case Audit_equal: 2925376bd9cbSDarrel Goeddel match = (ctxt->type == rule->au_ctxt.type); 2926376bd9cbSDarrel Goeddel break; 29275af75d8dSAl Viro case Audit_not_equal: 2928376bd9cbSDarrel Goeddel match = (ctxt->type != rule->au_ctxt.type); 2929376bd9cbSDarrel Goeddel break; 2930376bd9cbSDarrel Goeddel } 2931376bd9cbSDarrel Goeddel break; 29323a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 29333a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 29346e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 29356e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 29366e5a2d1dSDarrel Goeddel level = ((field == AUDIT_SUBJ_SEN || 29376e5a2d1dSDarrel Goeddel field == AUDIT_OBJ_LEV_LOW) ? 2938376bd9cbSDarrel Goeddel &ctxt->range.level[0] : &ctxt->range.level[1]); 2939376bd9cbSDarrel Goeddel switch (op) { 29405af75d8dSAl Viro case Audit_equal: 2941376bd9cbSDarrel Goeddel match = mls_level_eq(&rule->au_ctxt.range.level[0], 2942376bd9cbSDarrel Goeddel level); 2943376bd9cbSDarrel Goeddel break; 29445af75d8dSAl Viro case Audit_not_equal: 2945376bd9cbSDarrel Goeddel match = !mls_level_eq(&rule->au_ctxt.range.level[0], 2946376bd9cbSDarrel Goeddel level); 2947376bd9cbSDarrel Goeddel break; 29485af75d8dSAl Viro case Audit_lt: 2949376bd9cbSDarrel Goeddel match = (mls_level_dom(&rule->au_ctxt.range.level[0], 2950376bd9cbSDarrel Goeddel level) && 2951376bd9cbSDarrel Goeddel !mls_level_eq(&rule->au_ctxt.range.level[0], 2952376bd9cbSDarrel Goeddel level)); 2953376bd9cbSDarrel Goeddel break; 29545af75d8dSAl Viro case Audit_le: 2955376bd9cbSDarrel Goeddel match = mls_level_dom(&rule->au_ctxt.range.level[0], 2956376bd9cbSDarrel Goeddel level); 2957376bd9cbSDarrel Goeddel break; 29585af75d8dSAl Viro case Audit_gt: 2959376bd9cbSDarrel Goeddel match = (mls_level_dom(level, 2960376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]) && 2961376bd9cbSDarrel Goeddel !mls_level_eq(level, 2962376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0])); 2963376bd9cbSDarrel Goeddel break; 29645af75d8dSAl Viro case Audit_ge: 2965376bd9cbSDarrel Goeddel match = mls_level_dom(level, 2966376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]); 2967376bd9cbSDarrel Goeddel break; 2968376bd9cbSDarrel Goeddel } 2969376bd9cbSDarrel Goeddel } 2970376bd9cbSDarrel Goeddel 2971376bd9cbSDarrel Goeddel out: 29720804d113SJames Morris read_unlock(&policy_rwlock); 2973376bd9cbSDarrel Goeddel return match; 2974376bd9cbSDarrel Goeddel } 2975376bd9cbSDarrel Goeddel 29769d57a7f9SAhmed S. Darwish static int (*aurule_callback)(void) = audit_update_lsm_rules; 2977376bd9cbSDarrel Goeddel 2978376bd9cbSDarrel Goeddel static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, 2979376bd9cbSDarrel Goeddel u16 class, u32 perms, u32 *retained) 2980376bd9cbSDarrel Goeddel { 2981376bd9cbSDarrel Goeddel int err = 0; 2982376bd9cbSDarrel Goeddel 2983376bd9cbSDarrel Goeddel if (event == AVC_CALLBACK_RESET && aurule_callback) 2984376bd9cbSDarrel Goeddel err = aurule_callback(); 2985376bd9cbSDarrel Goeddel return err; 2986376bd9cbSDarrel Goeddel } 2987376bd9cbSDarrel Goeddel 2988376bd9cbSDarrel Goeddel static int __init aurule_init(void) 2989376bd9cbSDarrel Goeddel { 2990376bd9cbSDarrel Goeddel int err; 2991376bd9cbSDarrel Goeddel 2992376bd9cbSDarrel Goeddel err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET, 2993376bd9cbSDarrel Goeddel SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); 2994376bd9cbSDarrel Goeddel if (err) 2995376bd9cbSDarrel Goeddel panic("avc_add_callback() failed, error %d\n", err); 2996376bd9cbSDarrel Goeddel 2997376bd9cbSDarrel Goeddel return err; 2998376bd9cbSDarrel Goeddel } 2999376bd9cbSDarrel Goeddel __initcall(aurule_init); 3000376bd9cbSDarrel Goeddel 30017420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL 30027420ed23SVenkat Yekkirala /** 30035778eabdSPaul Moore * security_netlbl_cache_add - Add an entry to the NetLabel cache 30045778eabdSPaul Moore * @secattr: the NetLabel packet security attributes 30055dbe1eb0SPaul Moore * @sid: the SELinux SID 30067420ed23SVenkat Yekkirala * 30077420ed23SVenkat Yekkirala * Description: 30087420ed23SVenkat Yekkirala * Attempt to cache the context in @ctx, which was derived from the packet in 30095778eabdSPaul Moore * @skb, in the NetLabel subsystem cache. This function assumes @secattr has 30105778eabdSPaul Moore * already been initialized. 30117420ed23SVenkat Yekkirala * 30127420ed23SVenkat Yekkirala */ 30135778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, 30145dbe1eb0SPaul Moore u32 sid) 30157420ed23SVenkat Yekkirala { 30165dbe1eb0SPaul Moore u32 *sid_cache; 30177420ed23SVenkat Yekkirala 30185dbe1eb0SPaul Moore sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC); 30195dbe1eb0SPaul Moore if (sid_cache == NULL) 30205dbe1eb0SPaul Moore return; 30215778eabdSPaul Moore secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); 30225dbe1eb0SPaul Moore if (secattr->cache == NULL) { 30235dbe1eb0SPaul Moore kfree(sid_cache); 30245778eabdSPaul Moore return; 30250ec8abd7SJesper Juhl } 30267420ed23SVenkat Yekkirala 30275dbe1eb0SPaul Moore *sid_cache = sid; 30285dbe1eb0SPaul Moore secattr->cache->free = kfree; 30295dbe1eb0SPaul Moore secattr->cache->data = sid_cache; 30305778eabdSPaul Moore secattr->flags |= NETLBL_SECATTR_CACHE; 30317420ed23SVenkat Yekkirala } 30327420ed23SVenkat Yekkirala 30337420ed23SVenkat Yekkirala /** 30345778eabdSPaul Moore * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID 30357420ed23SVenkat Yekkirala * @secattr: the NetLabel packet security attributes 30367420ed23SVenkat Yekkirala * @sid: the SELinux SID 30377420ed23SVenkat Yekkirala * 30387420ed23SVenkat Yekkirala * Description: 30395778eabdSPaul Moore * Convert the given NetLabel security attributes in @secattr into a 30407420ed23SVenkat Yekkirala * SELinux SID. If the @secattr field does not contain a full SELinux 30415dbe1eb0SPaul Moore * SID/context then use SECINITSID_NETMSG as the foundation. If possibile the 30425dbe1eb0SPaul Moore * 'cache' field of @secattr is set and the CACHE flag is set; this is to 30435dbe1eb0SPaul Moore * allow the @secattr to be used by NetLabel to cache the secattr to SID 30445dbe1eb0SPaul Moore * conversion for future lookups. Returns zero on success, negative values on 30455dbe1eb0SPaul Moore * failure. 30467420ed23SVenkat Yekkirala * 30477420ed23SVenkat Yekkirala */ 30485778eabdSPaul Moore int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, 30497420ed23SVenkat Yekkirala u32 *sid) 30507420ed23SVenkat Yekkirala { 30517ae9f23cSEric Paris int rc; 30527420ed23SVenkat Yekkirala struct context *ctx; 30537420ed23SVenkat Yekkirala struct context ctx_new; 30545778eabdSPaul Moore 30555778eabdSPaul Moore if (!ss_initialized) { 30565778eabdSPaul Moore *sid = SECSID_NULL; 30575778eabdSPaul Moore return 0; 30585778eabdSPaul Moore } 30597420ed23SVenkat Yekkirala 30600804d113SJames Morris read_lock(&policy_rwlock); 30617420ed23SVenkat Yekkirala 30627ae9f23cSEric Paris if (secattr->flags & NETLBL_SECATTR_CACHE) 30635dbe1eb0SPaul Moore *sid = *(u32 *)secattr->cache->data; 30647ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_SECID) 306516efd454SPaul Moore *sid = secattr->attr.secid; 30667ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { 30677ae9f23cSEric Paris rc = -EIDRM; 30685dbe1eb0SPaul Moore ctx = sidtab_search(&sidtab, SECINITSID_NETMSG); 30697420ed23SVenkat Yekkirala if (ctx == NULL) 30707ae9f23cSEric Paris goto out; 30717420ed23SVenkat Yekkirala 307281990fbdSPaul Moore context_init(&ctx_new); 30737420ed23SVenkat Yekkirala ctx_new.user = ctx->user; 30747420ed23SVenkat Yekkirala ctx_new.role = ctx->role; 30757420ed23SVenkat Yekkirala ctx_new.type = ctx->type; 307602752760SPaul Moore mls_import_netlbl_lvl(&ctx_new, secattr); 3077701a90baSPaul Moore if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 30787ae9f23cSEric Paris rc = ebitmap_netlbl_import(&ctx_new.range.level[0].cat, 30797ae9f23cSEric Paris secattr->attr.mls.cat); 30807ae9f23cSEric Paris if (rc) 30817ae9f23cSEric Paris goto out; 308281990fbdSPaul Moore memcpy(&ctx_new.range.level[1].cat, 308381990fbdSPaul Moore &ctx_new.range.level[0].cat, 308481990fbdSPaul Moore sizeof(ctx_new.range.level[0].cat)); 30857420ed23SVenkat Yekkirala } 30867ae9f23cSEric Paris rc = -EIDRM; 30877ae9f23cSEric Paris if (!mls_context_isvalid(&policydb, &ctx_new)) 30887ae9f23cSEric Paris goto out_free; 30897420ed23SVenkat Yekkirala 30907420ed23SVenkat Yekkirala rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid); 30917ae9f23cSEric Paris if (rc) 30927ae9f23cSEric Paris goto out_free; 30937420ed23SVenkat Yekkirala 30945dbe1eb0SPaul Moore security_netlbl_cache_add(secattr, *sid); 30955778eabdSPaul Moore 30967420ed23SVenkat Yekkirala ebitmap_destroy(&ctx_new.range.level[0].cat); 30977ae9f23cSEric Paris } else 3098388b2405Spaul.moore@hp.com *sid = SECSID_NULL; 30997420ed23SVenkat Yekkirala 31007ae9f23cSEric Paris read_unlock(&policy_rwlock); 31017ae9f23cSEric Paris return 0; 31027ae9f23cSEric Paris out_free: 31037ae9f23cSEric Paris ebitmap_destroy(&ctx_new.range.level[0].cat); 31047ae9f23cSEric Paris out: 31050804d113SJames Morris read_unlock(&policy_rwlock); 31067420ed23SVenkat Yekkirala return rc; 31077420ed23SVenkat Yekkirala } 31087420ed23SVenkat Yekkirala 31097420ed23SVenkat Yekkirala /** 31105778eabdSPaul Moore * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr 31115778eabdSPaul Moore * @sid: the SELinux SID 31125778eabdSPaul Moore * @secattr: the NetLabel packet security attributes 31137420ed23SVenkat Yekkirala * 31147420ed23SVenkat Yekkirala * Description: 31155778eabdSPaul Moore * Convert the given SELinux SID in @sid into a NetLabel security attribute. 31165778eabdSPaul Moore * Returns zero on success, negative values on failure. 31177420ed23SVenkat Yekkirala * 31187420ed23SVenkat Yekkirala */ 31195778eabdSPaul Moore int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) 31207420ed23SVenkat Yekkirala { 312199d854d2SPaul Moore int rc; 31227420ed23SVenkat Yekkirala struct context *ctx; 31237420ed23SVenkat Yekkirala 31247420ed23SVenkat Yekkirala if (!ss_initialized) 31257420ed23SVenkat Yekkirala return 0; 31267420ed23SVenkat Yekkirala 31270804d113SJames Morris read_lock(&policy_rwlock); 31284b02b524SEric Paris 312999d854d2SPaul Moore rc = -ENOENT; 31304b02b524SEric Paris ctx = sidtab_search(&sidtab, sid); 31314b02b524SEric Paris if (ctx == NULL) 31324b02b524SEric Paris goto out; 31334b02b524SEric Paris 31344b02b524SEric Paris rc = -ENOMEM; 3135ac76c05bSEric Paris secattr->domain = kstrdup(sym_name(&policydb, SYM_TYPES, ctx->type - 1), 31367420ed23SVenkat Yekkirala GFP_ATOMIC); 31374b02b524SEric Paris if (secattr->domain == NULL) 31384b02b524SEric Paris goto out; 31394b02b524SEric Paris 31408d75899dSPaul Moore secattr->attr.secid = sid; 31418d75899dSPaul Moore secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID; 31425778eabdSPaul Moore mls_export_netlbl_lvl(ctx, secattr); 31435778eabdSPaul Moore rc = mls_export_netlbl_cat(ctx, secattr); 31444b02b524SEric Paris out: 31450804d113SJames Morris read_unlock(&policy_rwlock); 3146f8687afeSPaul Moore return rc; 3147f8687afeSPaul Moore } 31487420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */ 3149cee74f47SEric Paris 3150cee74f47SEric Paris /** 3151cee74f47SEric Paris * security_read_policy - read the policy. 3152cee74f47SEric Paris * @data: binary policy data 3153cee74f47SEric Paris * @len: length of data in bytes 3154cee74f47SEric Paris * 3155cee74f47SEric Paris */ 3156cee74f47SEric Paris int security_read_policy(void **data, ssize_t *len) 3157cee74f47SEric Paris { 3158cee74f47SEric Paris int rc; 3159cee74f47SEric Paris struct policy_file fp; 3160cee74f47SEric Paris 3161cee74f47SEric Paris if (!ss_initialized) 3162cee74f47SEric Paris return -EINVAL; 3163cee74f47SEric Paris 3164cee74f47SEric Paris *len = security_policydb_len(); 3165cee74f47SEric Paris 3166845ca30fSEric Paris *data = vmalloc_user(*len); 3167cee74f47SEric Paris if (!*data) 3168cee74f47SEric Paris return -ENOMEM; 3169cee74f47SEric Paris 3170cee74f47SEric Paris fp.data = *data; 3171cee74f47SEric Paris fp.len = *len; 3172cee74f47SEric Paris 3173cee74f47SEric Paris read_lock(&policy_rwlock); 3174cee74f47SEric Paris rc = policydb_write(&policydb, &fp); 3175cee74f47SEric Paris read_unlock(&policy_rwlock); 3176cee74f47SEric Paris 3177cee74f47SEric Paris if (rc) 3178cee74f47SEric Paris return rc; 3179cee74f47SEric Paris 3180cee74f47SEric Paris *len = (unsigned long)fp.data - (unsigned long)*data; 3181cee74f47SEric Paris return 0; 3182cee74f47SEric Paris 3183cee74f47SEric Paris } 3184