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 * 253bb56b25SPaul Moore * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. 26376bd9cbSDarrel Goeddel * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 27b94c7e67SChad Sellers * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC 281da177e4SLinus Torvalds * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 291da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 301da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 311da177e4SLinus Torvalds * the Free Software Foundation, version 2. 321da177e4SLinus Torvalds */ 331da177e4SLinus Torvalds #include <linux/kernel.h> 341da177e4SLinus Torvalds #include <linux/slab.h> 351da177e4SLinus Torvalds #include <linux/string.h> 361da177e4SLinus Torvalds #include <linux/spinlock.h> 379f2ad665SPaul Moore #include <linux/rcupdate.h> 381da177e4SLinus Torvalds #include <linux/errno.h> 391da177e4SLinus Torvalds #include <linux/in.h> 401da177e4SLinus Torvalds #include <linux/sched.h> 411da177e4SLinus Torvalds #include <linux/audit.h> 42bb003079SIngo Molnar #include <linux/mutex.h> 430e55a004SAdrian Bunk #include <linux/selinux.h> 447420ed23SVenkat Yekkirala #include <net/netlabel.h> 45bb003079SIngo Molnar 461da177e4SLinus Torvalds #include "flask.h" 471da177e4SLinus Torvalds #include "avc.h" 481da177e4SLinus Torvalds #include "avc_ss.h" 491da177e4SLinus Torvalds #include "security.h" 501da177e4SLinus Torvalds #include "context.h" 511da177e4SLinus Torvalds #include "policydb.h" 521da177e4SLinus Torvalds #include "sidtab.h" 531da177e4SLinus Torvalds #include "services.h" 541da177e4SLinus Torvalds #include "conditional.h" 551da177e4SLinus Torvalds #include "mls.h" 567420ed23SVenkat Yekkirala #include "objsec.h" 57c60475bfSPaul Moore #include "netlabel.h" 583de4bab5SPaul Moore #include "xfrm.h" 5902752760SPaul Moore #include "ebitmap.h" 609d57a7f9SAhmed S. Darwish #include "audit.h" 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds extern void selnl_notify_policyload(u32 seqno); 631da177e4SLinus Torvalds unsigned int policydb_loaded_version; 641da177e4SLinus Torvalds 653bb56b25SPaul Moore int selinux_policycap_netpeer; 66b0c636b9SEric Paris int selinux_policycap_openperm; 673bb56b25SPaul Moore 68b94c7e67SChad Sellers /* 69b94c7e67SChad Sellers * This is declared in avc.c 70b94c7e67SChad Sellers */ 71b94c7e67SChad Sellers extern const struct selinux_class_perm selinux_class_perm; 72b94c7e67SChad Sellers 731da177e4SLinus Torvalds static DEFINE_RWLOCK(policy_rwlock); 741da177e4SLinus Torvalds #define POLICY_RDLOCK read_lock(&policy_rwlock) 751da177e4SLinus Torvalds #define POLICY_WRLOCK write_lock_irq(&policy_rwlock) 761da177e4SLinus Torvalds #define POLICY_RDUNLOCK read_unlock(&policy_rwlock) 771da177e4SLinus Torvalds #define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock) 781da177e4SLinus Torvalds 79bb003079SIngo Molnar static DEFINE_MUTEX(load_mutex); 80bb003079SIngo Molnar #define LOAD_LOCK mutex_lock(&load_mutex) 81bb003079SIngo Molnar #define LOAD_UNLOCK mutex_unlock(&load_mutex) 821da177e4SLinus Torvalds 831da177e4SLinus Torvalds static struct sidtab sidtab; 841da177e4SLinus Torvalds struct policydb policydb; 855d55a345SEric Paris int ss_initialized; 861da177e4SLinus Torvalds 871da177e4SLinus Torvalds /* 881da177e4SLinus Torvalds * The largest sequence number that has been used when 891da177e4SLinus Torvalds * providing an access decision to the access vector cache. 901da177e4SLinus Torvalds * The sequence number only changes when a policy change 911da177e4SLinus Torvalds * occurs. 921da177e4SLinus Torvalds */ 935d55a345SEric Paris static u32 latest_granting; 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds /* Forward declaration. */ 961da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, 971da177e4SLinus Torvalds u32 *scontext_len); 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds /* 1001da177e4SLinus Torvalds * Return the boolean value of a constraint expression 1011da177e4SLinus Torvalds * when it is applied to the specified source and target 1021da177e4SLinus Torvalds * security contexts. 1031da177e4SLinus Torvalds * 1041da177e4SLinus Torvalds * xcontext is a special beast... It is used by the validatetrans rules 1051da177e4SLinus Torvalds * only. For these rules, scontext is the context before the transition, 1061da177e4SLinus Torvalds * tcontext is the context after the transition, and xcontext is the context 1071da177e4SLinus Torvalds * of the process performing the transition. All other callers of 1081da177e4SLinus Torvalds * constraint_expr_eval should pass in NULL for xcontext. 1091da177e4SLinus Torvalds */ 1101da177e4SLinus Torvalds static int constraint_expr_eval(struct context *scontext, 1111da177e4SLinus Torvalds struct context *tcontext, 1121da177e4SLinus Torvalds struct context *xcontext, 1131da177e4SLinus Torvalds struct constraint_expr *cexpr) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds u32 val1, val2; 1161da177e4SLinus Torvalds struct context *c; 1171da177e4SLinus Torvalds struct role_datum *r1, *r2; 1181da177e4SLinus Torvalds struct mls_level *l1, *l2; 1191da177e4SLinus Torvalds struct constraint_expr *e; 1201da177e4SLinus Torvalds int s[CEXPR_MAXDEPTH]; 1211da177e4SLinus Torvalds int sp = -1; 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds for (e = cexpr; e; e = e->next) { 1241da177e4SLinus Torvalds switch (e->expr_type) { 1251da177e4SLinus Torvalds case CEXPR_NOT: 1261da177e4SLinus Torvalds BUG_ON(sp < 0); 1271da177e4SLinus Torvalds s[sp] = !s[sp]; 1281da177e4SLinus Torvalds break; 1291da177e4SLinus Torvalds case CEXPR_AND: 1301da177e4SLinus Torvalds BUG_ON(sp < 1); 1311da177e4SLinus Torvalds sp--; 1321da177e4SLinus Torvalds s[sp] &= s[sp+1]; 1331da177e4SLinus Torvalds break; 1341da177e4SLinus Torvalds case CEXPR_OR: 1351da177e4SLinus Torvalds BUG_ON(sp < 1); 1361da177e4SLinus Torvalds sp--; 1371da177e4SLinus Torvalds s[sp] |= s[sp+1]; 1381da177e4SLinus Torvalds break; 1391da177e4SLinus Torvalds case CEXPR_ATTR: 1401da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH-1)) 1411da177e4SLinus Torvalds return 0; 1421da177e4SLinus Torvalds switch (e->attr) { 1431da177e4SLinus Torvalds case CEXPR_USER: 1441da177e4SLinus Torvalds val1 = scontext->user; 1451da177e4SLinus Torvalds val2 = tcontext->user; 1461da177e4SLinus Torvalds break; 1471da177e4SLinus Torvalds case CEXPR_TYPE: 1481da177e4SLinus Torvalds val1 = scontext->type; 1491da177e4SLinus Torvalds val2 = tcontext->type; 1501da177e4SLinus Torvalds break; 1511da177e4SLinus Torvalds case CEXPR_ROLE: 1521da177e4SLinus Torvalds val1 = scontext->role; 1531da177e4SLinus Torvalds val2 = tcontext->role; 1541da177e4SLinus Torvalds r1 = policydb.role_val_to_struct[val1 - 1]; 1551da177e4SLinus Torvalds r2 = policydb.role_val_to_struct[val2 - 1]; 1561da177e4SLinus Torvalds switch (e->op) { 1571da177e4SLinus Torvalds case CEXPR_DOM: 1581da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r1->dominates, 1591da177e4SLinus Torvalds val2 - 1); 1601da177e4SLinus Torvalds continue; 1611da177e4SLinus Torvalds case CEXPR_DOMBY: 1621da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r2->dominates, 1631da177e4SLinus Torvalds val1 - 1); 1641da177e4SLinus Torvalds continue; 1651da177e4SLinus Torvalds case CEXPR_INCOMP: 1661da177e4SLinus Torvalds s[++sp] = (!ebitmap_get_bit(&r1->dominates, 1671da177e4SLinus Torvalds val2 - 1) && 1681da177e4SLinus Torvalds !ebitmap_get_bit(&r2->dominates, 1691da177e4SLinus Torvalds val1 - 1)); 1701da177e4SLinus Torvalds continue; 1711da177e4SLinus Torvalds default: 1721da177e4SLinus Torvalds break; 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds break; 1751da177e4SLinus Torvalds case CEXPR_L1L2: 1761da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 1771da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 1781da177e4SLinus Torvalds goto mls_ops; 1791da177e4SLinus Torvalds case CEXPR_L1H2: 1801da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 1811da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 1821da177e4SLinus Torvalds goto mls_ops; 1831da177e4SLinus Torvalds case CEXPR_H1L2: 1841da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 1851da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 1861da177e4SLinus Torvalds goto mls_ops; 1871da177e4SLinus Torvalds case CEXPR_H1H2: 1881da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 1891da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 1901da177e4SLinus Torvalds goto mls_ops; 1911da177e4SLinus Torvalds case CEXPR_L1H1: 1921da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 1931da177e4SLinus Torvalds l2 = &(scontext->range.level[1]); 1941da177e4SLinus Torvalds goto mls_ops; 1951da177e4SLinus Torvalds case CEXPR_L2H2: 1961da177e4SLinus Torvalds l1 = &(tcontext->range.level[0]); 1971da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 1981da177e4SLinus Torvalds goto mls_ops; 1991da177e4SLinus Torvalds mls_ops: 2001da177e4SLinus Torvalds switch (e->op) { 2011da177e4SLinus Torvalds case CEXPR_EQ: 2021da177e4SLinus Torvalds s[++sp] = mls_level_eq(l1, l2); 2031da177e4SLinus Torvalds continue; 2041da177e4SLinus Torvalds case CEXPR_NEQ: 2051da177e4SLinus Torvalds s[++sp] = !mls_level_eq(l1, l2); 2061da177e4SLinus Torvalds continue; 2071da177e4SLinus Torvalds case CEXPR_DOM: 2081da177e4SLinus Torvalds s[++sp] = mls_level_dom(l1, l2); 2091da177e4SLinus Torvalds continue; 2101da177e4SLinus Torvalds case CEXPR_DOMBY: 2111da177e4SLinus Torvalds s[++sp] = mls_level_dom(l2, l1); 2121da177e4SLinus Torvalds continue; 2131da177e4SLinus Torvalds case CEXPR_INCOMP: 2141da177e4SLinus Torvalds s[++sp] = mls_level_incomp(l2, l1); 2151da177e4SLinus Torvalds continue; 2161da177e4SLinus Torvalds default: 2171da177e4SLinus Torvalds BUG(); 2181da177e4SLinus Torvalds return 0; 2191da177e4SLinus Torvalds } 2201da177e4SLinus Torvalds break; 2211da177e4SLinus Torvalds default: 2221da177e4SLinus Torvalds BUG(); 2231da177e4SLinus Torvalds return 0; 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds 2261da177e4SLinus Torvalds switch (e->op) { 2271da177e4SLinus Torvalds case CEXPR_EQ: 2281da177e4SLinus Torvalds s[++sp] = (val1 == val2); 2291da177e4SLinus Torvalds break; 2301da177e4SLinus Torvalds case CEXPR_NEQ: 2311da177e4SLinus Torvalds s[++sp] = (val1 != val2); 2321da177e4SLinus Torvalds break; 2331da177e4SLinus Torvalds default: 2341da177e4SLinus Torvalds BUG(); 2351da177e4SLinus Torvalds return 0; 2361da177e4SLinus Torvalds } 2371da177e4SLinus Torvalds break; 2381da177e4SLinus Torvalds case CEXPR_NAMES: 2391da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH-1)) 2401da177e4SLinus Torvalds return 0; 2411da177e4SLinus Torvalds c = scontext; 2421da177e4SLinus Torvalds if (e->attr & CEXPR_TARGET) 2431da177e4SLinus Torvalds c = tcontext; 2441da177e4SLinus Torvalds else if (e->attr & CEXPR_XTARGET) { 2451da177e4SLinus Torvalds c = xcontext; 2461da177e4SLinus Torvalds if (!c) { 2471da177e4SLinus Torvalds BUG(); 2481da177e4SLinus Torvalds return 0; 2491da177e4SLinus Torvalds } 2501da177e4SLinus Torvalds } 2511da177e4SLinus Torvalds if (e->attr & CEXPR_USER) 2521da177e4SLinus Torvalds val1 = c->user; 2531da177e4SLinus Torvalds else if (e->attr & CEXPR_ROLE) 2541da177e4SLinus Torvalds val1 = c->role; 2551da177e4SLinus Torvalds else if (e->attr & CEXPR_TYPE) 2561da177e4SLinus Torvalds val1 = c->type; 2571da177e4SLinus Torvalds else { 2581da177e4SLinus Torvalds BUG(); 2591da177e4SLinus Torvalds return 0; 2601da177e4SLinus Torvalds } 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds switch (e->op) { 2631da177e4SLinus Torvalds case CEXPR_EQ: 2641da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); 2651da177e4SLinus Torvalds break; 2661da177e4SLinus Torvalds case CEXPR_NEQ: 2671da177e4SLinus Torvalds s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); 2681da177e4SLinus Torvalds break; 2691da177e4SLinus Torvalds default: 2701da177e4SLinus Torvalds BUG(); 2711da177e4SLinus Torvalds return 0; 2721da177e4SLinus Torvalds } 2731da177e4SLinus Torvalds break; 2741da177e4SLinus Torvalds default: 2751da177e4SLinus Torvalds BUG(); 2761da177e4SLinus Torvalds return 0; 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds BUG_ON(sp != 0); 2811da177e4SLinus Torvalds return s[0]; 2821da177e4SLinus Torvalds } 2831da177e4SLinus Torvalds 2841da177e4SLinus Torvalds /* 2851da177e4SLinus Torvalds * Compute access vectors based on a context structure pair for 2861da177e4SLinus Torvalds * the permissions in a particular class. 2871da177e4SLinus Torvalds */ 2881da177e4SLinus Torvalds static int context_struct_compute_av(struct context *scontext, 2891da177e4SLinus Torvalds struct context *tcontext, 2901da177e4SLinus Torvalds u16 tclass, 2911da177e4SLinus Torvalds u32 requested, 2921da177e4SLinus Torvalds struct av_decision *avd) 2931da177e4SLinus Torvalds { 2941da177e4SLinus Torvalds struct constraint_node *constraint; 2951da177e4SLinus Torvalds struct role_allow *ra; 2961da177e4SLinus Torvalds struct avtab_key avkey; 297782ebb99SStephen Smalley struct avtab_node *node; 2981da177e4SLinus Torvalds struct class_datum *tclass_datum; 299782ebb99SStephen Smalley struct ebitmap *sattr, *tattr; 300782ebb99SStephen Smalley struct ebitmap_node *snode, *tnode; 3013f12070eSEric Paris const struct selinux_class_perm *kdefs = &selinux_class_perm; 302782ebb99SStephen Smalley unsigned int i, j; 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds /* 3051da177e4SLinus Torvalds * Remap extended Netlink classes for old policy versions. 3061da177e4SLinus Torvalds * Do this here rather than socket_type_to_security_class() 3071da177e4SLinus Torvalds * in case a newer policy version is loaded, allowing sockets 3081da177e4SLinus Torvalds * to remain in the correct class. 3091da177e4SLinus Torvalds */ 3101da177e4SLinus Torvalds if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS) 3111da177e4SLinus Torvalds if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET && 3121da177e4SLinus Torvalds tclass <= SECCLASS_NETLINK_DNRT_SOCKET) 3131da177e4SLinus Torvalds tclass = SECCLASS_NETLINK_SOCKET; 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds /* 3161da177e4SLinus Torvalds * Initialize the access vectors to the default values. 3171da177e4SLinus Torvalds */ 3181da177e4SLinus Torvalds avd->allowed = 0; 3191da177e4SLinus Torvalds avd->decided = 0xffffffff; 3201da177e4SLinus Torvalds avd->auditallow = 0; 3211da177e4SLinus Torvalds avd->auditdeny = 0xffffffff; 3221da177e4SLinus Torvalds avd->seqno = latest_granting; 3231da177e4SLinus Torvalds 3241da177e4SLinus Torvalds /* 3253f12070eSEric Paris * Check for all the invalid cases. 3263f12070eSEric Paris * - tclass 0 3273f12070eSEric Paris * - tclass > policy and > kernel 3283f12070eSEric Paris * - tclass > policy but is a userspace class 3293f12070eSEric Paris * - tclass > policy but we do not allow unknowns 3303f12070eSEric Paris */ 3313f12070eSEric Paris if (unlikely(!tclass)) 3323f12070eSEric Paris goto inval_class; 3333f12070eSEric Paris if (unlikely(tclass > policydb.p_classes.nprim)) 3343f12070eSEric Paris if (tclass > kdefs->cts_len || 3353f12070eSEric Paris !kdefs->class_to_string[tclass - 1] || 3363f12070eSEric Paris !policydb.allow_unknown) 3373f12070eSEric Paris goto inval_class; 3383f12070eSEric Paris 3393f12070eSEric Paris /* 3403f12070eSEric Paris * Kernel class and we allow unknown so pad the allow decision 3413f12070eSEric Paris * the pad will be all 1 for unknown classes. 3423f12070eSEric Paris */ 3433f12070eSEric Paris if (tclass <= kdefs->cts_len && policydb.allow_unknown) 3443f12070eSEric Paris avd->allowed = policydb.undefined_perms[tclass - 1]; 3453f12070eSEric Paris 3463f12070eSEric Paris /* 3473f12070eSEric Paris * Not in policy. Since decision is completed (all 1 or all 0) return. 3483f12070eSEric Paris */ 3493f12070eSEric Paris if (unlikely(tclass > policydb.p_classes.nprim)) 3503f12070eSEric Paris return 0; 3513f12070eSEric Paris 3523f12070eSEric Paris tclass_datum = policydb.class_val_to_struct[tclass - 1]; 3533f12070eSEric Paris 3543f12070eSEric Paris /* 3551da177e4SLinus Torvalds * If a specific type enforcement rule was defined for 3561da177e4SLinus Torvalds * this permission check, then use it. 3571da177e4SLinus Torvalds */ 3581da177e4SLinus Torvalds avkey.target_class = tclass; 359782ebb99SStephen Smalley avkey.specified = AVTAB_AV; 360782ebb99SStephen Smalley sattr = &policydb.type_attr_map[scontext->type - 1]; 361782ebb99SStephen Smalley tattr = &policydb.type_attr_map[tcontext->type - 1]; 3629fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(sattr, snode, i) { 3639fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(tattr, tnode, j) { 364782ebb99SStephen Smalley avkey.source_type = i + 1; 365782ebb99SStephen Smalley avkey.target_type = j + 1; 366782ebb99SStephen Smalley for (node = avtab_search_node(&policydb.te_avtab, &avkey); 367782ebb99SStephen Smalley node != NULL; 368782ebb99SStephen Smalley node = avtab_search_node_next(node, avkey.specified)) { 369782ebb99SStephen Smalley if (node->key.specified == AVTAB_ALLOWED) 370782ebb99SStephen Smalley avd->allowed |= node->datum.data; 371782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITALLOW) 372782ebb99SStephen Smalley avd->auditallow |= node->datum.data; 373782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITDENY) 374782ebb99SStephen Smalley avd->auditdeny &= node->datum.data; 3751da177e4SLinus Torvalds } 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds /* Check conditional av table for additional permissions */ 3781da177e4SLinus Torvalds cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); 3791da177e4SLinus Torvalds 380782ebb99SStephen Smalley } 381782ebb99SStephen Smalley } 382782ebb99SStephen Smalley 3831da177e4SLinus Torvalds /* 3841da177e4SLinus Torvalds * Remove any permissions prohibited by a constraint (this includes 3851da177e4SLinus Torvalds * the MLS policy). 3861da177e4SLinus Torvalds */ 3871da177e4SLinus Torvalds constraint = tclass_datum->constraints; 3881da177e4SLinus Torvalds while (constraint) { 3891da177e4SLinus Torvalds if ((constraint->permissions & (avd->allowed)) && 3901da177e4SLinus Torvalds !constraint_expr_eval(scontext, tcontext, NULL, 3911da177e4SLinus Torvalds constraint->expr)) { 3921da177e4SLinus Torvalds avd->allowed = (avd->allowed) & ~(constraint->permissions); 3931da177e4SLinus Torvalds } 3941da177e4SLinus Torvalds constraint = constraint->next; 3951da177e4SLinus Torvalds } 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds /* 3981da177e4SLinus Torvalds * If checking process transition permission and the 3991da177e4SLinus Torvalds * role is changing, then check the (current_role, new_role) 4001da177e4SLinus Torvalds * pair. 4011da177e4SLinus Torvalds */ 4021da177e4SLinus Torvalds if (tclass == SECCLASS_PROCESS && 4031da177e4SLinus Torvalds (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) && 4041da177e4SLinus Torvalds scontext->role != tcontext->role) { 4051da177e4SLinus Torvalds for (ra = policydb.role_allow; ra; ra = ra->next) { 4061da177e4SLinus Torvalds if (scontext->role == ra->role && 4071da177e4SLinus Torvalds tcontext->role == ra->new_role) 4081da177e4SLinus Torvalds break; 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds if (!ra) 4111da177e4SLinus Torvalds avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION | 4121da177e4SLinus Torvalds PROCESS__DYNTRANSITION); 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds return 0; 4163f12070eSEric Paris 4173f12070eSEric Paris inval_class: 418744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", __func__, 419744ba35eSEric Paris tclass); 4203f12070eSEric Paris return -EINVAL; 4211da177e4SLinus Torvalds } 4221da177e4SLinus Torvalds 42364dbf074SEric Paris /* 42464dbf074SEric Paris * Given a sid find if the type has the permissive flag set 42564dbf074SEric Paris */ 42664dbf074SEric Paris int security_permissive_sid(u32 sid) 42764dbf074SEric Paris { 42864dbf074SEric Paris struct context *context; 42964dbf074SEric Paris u32 type; 43064dbf074SEric Paris int rc; 43164dbf074SEric Paris 43264dbf074SEric Paris POLICY_RDLOCK; 43364dbf074SEric Paris 43464dbf074SEric Paris context = sidtab_search(&sidtab, sid); 43564dbf074SEric Paris BUG_ON(!context); 43664dbf074SEric Paris 43764dbf074SEric Paris type = context->type; 43864dbf074SEric Paris /* 43964dbf074SEric Paris * we are intentionally using type here, not type-1, the 0th bit may 44064dbf074SEric Paris * someday indicate that we are globally setting permissive in policy. 44164dbf074SEric Paris */ 44264dbf074SEric Paris rc = ebitmap_get_bit(&policydb.permissive_map, type); 44364dbf074SEric Paris 44464dbf074SEric Paris POLICY_RDUNLOCK; 44564dbf074SEric Paris return rc; 44664dbf074SEric Paris } 44764dbf074SEric Paris 4481da177e4SLinus Torvalds static int security_validtrans_handle_fail(struct context *ocontext, 4491da177e4SLinus Torvalds struct context *ncontext, 4501da177e4SLinus Torvalds struct context *tcontext, 4511da177e4SLinus Torvalds u16 tclass) 4521da177e4SLinus Torvalds { 4531da177e4SLinus Torvalds char *o = NULL, *n = NULL, *t = NULL; 4541da177e4SLinus Torvalds u32 olen, nlen, tlen; 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds if (context_struct_to_string(ocontext, &o, &olen) < 0) 4571da177e4SLinus Torvalds goto out; 4581da177e4SLinus Torvalds if (context_struct_to_string(ncontext, &n, &nlen) < 0) 4591da177e4SLinus Torvalds goto out; 4601da177e4SLinus Torvalds if (context_struct_to_string(tcontext, &t, &tlen) < 0) 4611da177e4SLinus Torvalds goto out; 4629ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 4631da177e4SLinus Torvalds "security_validate_transition: denied for" 4641da177e4SLinus Torvalds " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", 4651da177e4SLinus Torvalds o, n, t, policydb.p_class_val_to_name[tclass-1]); 4661da177e4SLinus Torvalds out: 4671da177e4SLinus Torvalds kfree(o); 4681da177e4SLinus Torvalds kfree(n); 4691da177e4SLinus Torvalds kfree(t); 4701da177e4SLinus Torvalds 4711da177e4SLinus Torvalds if (!selinux_enforcing) 4721da177e4SLinus Torvalds return 0; 4731da177e4SLinus Torvalds return -EPERM; 4741da177e4SLinus Torvalds } 4751da177e4SLinus Torvalds 4761da177e4SLinus Torvalds int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, 4771da177e4SLinus Torvalds u16 tclass) 4781da177e4SLinus Torvalds { 4791da177e4SLinus Torvalds struct context *ocontext; 4801da177e4SLinus Torvalds struct context *ncontext; 4811da177e4SLinus Torvalds struct context *tcontext; 4821da177e4SLinus Torvalds struct class_datum *tclass_datum; 4831da177e4SLinus Torvalds struct constraint_node *constraint; 4841da177e4SLinus Torvalds int rc = 0; 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds if (!ss_initialized) 4871da177e4SLinus Torvalds return 0; 4881da177e4SLinus Torvalds 4891da177e4SLinus Torvalds POLICY_RDLOCK; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds /* 4921da177e4SLinus Torvalds * Remap extended Netlink classes for old policy versions. 4931da177e4SLinus Torvalds * Do this here rather than socket_type_to_security_class() 4941da177e4SLinus Torvalds * in case a newer policy version is loaded, allowing sockets 4951da177e4SLinus Torvalds * to remain in the correct class. 4961da177e4SLinus Torvalds */ 4971da177e4SLinus Torvalds if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS) 4981da177e4SLinus Torvalds if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET && 4991da177e4SLinus Torvalds tclass <= SECCLASS_NETLINK_DNRT_SOCKET) 5001da177e4SLinus Torvalds tclass = SECCLASS_NETLINK_SOCKET; 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds if (!tclass || tclass > policydb.p_classes.nprim) { 503744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized class %d\n", 504744ba35eSEric Paris __func__, tclass); 5051da177e4SLinus Torvalds rc = -EINVAL; 5061da177e4SLinus Torvalds goto out; 5071da177e4SLinus Torvalds } 5081da177e4SLinus Torvalds tclass_datum = policydb.class_val_to_struct[tclass - 1]; 5091da177e4SLinus Torvalds 5101da177e4SLinus Torvalds ocontext = sidtab_search(&sidtab, oldsid); 5111da177e4SLinus Torvalds if (!ocontext) { 512744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 513744ba35eSEric Paris __func__, oldsid); 5141da177e4SLinus Torvalds rc = -EINVAL; 5151da177e4SLinus Torvalds goto out; 5161da177e4SLinus Torvalds } 5171da177e4SLinus Torvalds 5181da177e4SLinus Torvalds ncontext = sidtab_search(&sidtab, newsid); 5191da177e4SLinus Torvalds if (!ncontext) { 520744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 521744ba35eSEric Paris __func__, newsid); 5221da177e4SLinus Torvalds rc = -EINVAL; 5231da177e4SLinus Torvalds goto out; 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds 5261da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tasksid); 5271da177e4SLinus Torvalds if (!tcontext) { 528744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 529744ba35eSEric Paris __func__, tasksid); 5301da177e4SLinus Torvalds rc = -EINVAL; 5311da177e4SLinus Torvalds goto out; 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds 5341da177e4SLinus Torvalds constraint = tclass_datum->validatetrans; 5351da177e4SLinus Torvalds while (constraint) { 5361da177e4SLinus Torvalds if (!constraint_expr_eval(ocontext, ncontext, tcontext, 5371da177e4SLinus Torvalds constraint->expr)) { 5381da177e4SLinus Torvalds rc = security_validtrans_handle_fail(ocontext, ncontext, 5391da177e4SLinus Torvalds tcontext, tclass); 5401da177e4SLinus Torvalds goto out; 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds constraint = constraint->next; 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 5451da177e4SLinus Torvalds out: 5461da177e4SLinus Torvalds POLICY_RDUNLOCK; 5471da177e4SLinus Torvalds return rc; 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds /** 5511da177e4SLinus Torvalds * security_compute_av - Compute access vector decisions. 5521da177e4SLinus Torvalds * @ssid: source security identifier 5531da177e4SLinus Torvalds * @tsid: target security identifier 5541da177e4SLinus Torvalds * @tclass: target security class 5551da177e4SLinus Torvalds * @requested: requested permissions 5561da177e4SLinus Torvalds * @avd: access vector decisions 5571da177e4SLinus Torvalds * 5581da177e4SLinus Torvalds * Compute a set of access vector decisions based on the 5591da177e4SLinus Torvalds * SID pair (@ssid, @tsid) for the permissions in @tclass. 5601da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid or %0 5611da177e4SLinus Torvalds * if the access vector decisions were computed successfully. 5621da177e4SLinus Torvalds */ 5631da177e4SLinus Torvalds int security_compute_av(u32 ssid, 5641da177e4SLinus Torvalds u32 tsid, 5651da177e4SLinus Torvalds u16 tclass, 5661da177e4SLinus Torvalds u32 requested, 5671da177e4SLinus Torvalds struct av_decision *avd) 5681da177e4SLinus Torvalds { 5691da177e4SLinus Torvalds struct context *scontext = NULL, *tcontext = NULL; 5701da177e4SLinus Torvalds int rc = 0; 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds if (!ss_initialized) { 5734c443d1bSStephen Smalley avd->allowed = 0xffffffff; 5744c443d1bSStephen Smalley avd->decided = 0xffffffff; 5751da177e4SLinus Torvalds avd->auditallow = 0; 5761da177e4SLinus Torvalds avd->auditdeny = 0xffffffff; 5771da177e4SLinus Torvalds avd->seqno = latest_granting; 5781da177e4SLinus Torvalds return 0; 5791da177e4SLinus Torvalds } 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds POLICY_RDLOCK; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds scontext = sidtab_search(&sidtab, ssid); 5841da177e4SLinus Torvalds if (!scontext) { 585744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 586744ba35eSEric Paris __func__, ssid); 5871da177e4SLinus Torvalds rc = -EINVAL; 5881da177e4SLinus Torvalds goto out; 5891da177e4SLinus Torvalds } 5901da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tsid); 5911da177e4SLinus Torvalds if (!tcontext) { 592744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 593744ba35eSEric Paris __func__, tsid); 5941da177e4SLinus Torvalds rc = -EINVAL; 5951da177e4SLinus Torvalds goto out; 5961da177e4SLinus Torvalds } 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds rc = context_struct_compute_av(scontext, tcontext, tclass, 5991da177e4SLinus Torvalds requested, avd); 6001da177e4SLinus Torvalds out: 6011da177e4SLinus Torvalds POLICY_RDUNLOCK; 6021da177e4SLinus Torvalds return rc; 6031da177e4SLinus Torvalds } 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds /* 6061da177e4SLinus Torvalds * Write the security context string representation of 6071da177e4SLinus Torvalds * the context structure `context' into a dynamically 6081da177e4SLinus Torvalds * allocated string of the correct size. Set `*scontext' 6091da177e4SLinus Torvalds * to point to this string and set `*scontext_len' to 6101da177e4SLinus Torvalds * the length of the string. 6111da177e4SLinus Torvalds */ 6121da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len) 6131da177e4SLinus Torvalds { 6141da177e4SLinus Torvalds char *scontextp; 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds *scontext = NULL; 6171da177e4SLinus Torvalds *scontext_len = 0; 6181da177e4SLinus Torvalds 6191da177e4SLinus Torvalds /* Compute the size of the context. */ 6201da177e4SLinus Torvalds *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1; 6211da177e4SLinus Torvalds *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1; 6221da177e4SLinus Torvalds *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1; 6231da177e4SLinus Torvalds *scontext_len += mls_compute_context_len(context); 6241da177e4SLinus Torvalds 6251da177e4SLinus Torvalds /* Allocate space for the context; caller must free this space. */ 6261da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 6275d55a345SEric Paris if (!scontextp) 6281da177e4SLinus Torvalds return -ENOMEM; 6291da177e4SLinus Torvalds *scontext = scontextp; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds /* 6321da177e4SLinus Torvalds * Copy the user name, role name and type name into the context. 6331da177e4SLinus Torvalds */ 6341da177e4SLinus Torvalds sprintf(scontextp, "%s:%s:%s", 6351da177e4SLinus Torvalds policydb.p_user_val_to_name[context->user - 1], 6361da177e4SLinus Torvalds policydb.p_role_val_to_name[context->role - 1], 6371da177e4SLinus Torvalds policydb.p_type_val_to_name[context->type - 1]); 6381da177e4SLinus Torvalds scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) + 6391da177e4SLinus Torvalds 1 + strlen(policydb.p_role_val_to_name[context->role - 1]) + 6401da177e4SLinus Torvalds 1 + strlen(policydb.p_type_val_to_name[context->type - 1]); 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds mls_sid_to_context(context, &scontextp); 6431da177e4SLinus Torvalds 6441da177e4SLinus Torvalds *scontextp = 0; 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds return 0; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds #include "initial_sid_to_string.h" 6501da177e4SLinus Torvalds 651f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid) 652f0ee2e46SJames Carter { 653f0ee2e46SJames Carter if (unlikely(sid > SECINITSID_NUM)) 654f0ee2e46SJames Carter return NULL; 655f0ee2e46SJames Carter return initial_sid_to_string[sid]; 656f0ee2e46SJames Carter } 657f0ee2e46SJames Carter 6581da177e4SLinus Torvalds /** 6591da177e4SLinus Torvalds * security_sid_to_context - Obtain a context for a given SID. 6601da177e4SLinus Torvalds * @sid: security identifier, SID 6611da177e4SLinus Torvalds * @scontext: security context 6621da177e4SLinus Torvalds * @scontext_len: length in bytes 6631da177e4SLinus Torvalds * 6641da177e4SLinus Torvalds * Write the string representation of the context associated with @sid 6651da177e4SLinus Torvalds * into a dynamically allocated string of the correct size. Set @scontext 6661da177e4SLinus Torvalds * to point to this string and set @scontext_len to the length of the string. 6671da177e4SLinus Torvalds */ 6681da177e4SLinus Torvalds int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) 6691da177e4SLinus Torvalds { 6701da177e4SLinus Torvalds struct context *context; 6711da177e4SLinus Torvalds int rc = 0; 6721da177e4SLinus Torvalds 6734f4acf3aSStephen Smalley *scontext = NULL; 6744f4acf3aSStephen Smalley *scontext_len = 0; 6754f4acf3aSStephen Smalley 6761da177e4SLinus Torvalds if (!ss_initialized) { 6771da177e4SLinus Torvalds if (sid <= SECINITSID_NUM) { 6781da177e4SLinus Torvalds char *scontextp; 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds *scontext_len = strlen(initial_sid_to_string[sid]) + 1; 6811da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 6820cccca06SSerge E. Hallyn if (!scontextp) { 6830cccca06SSerge E. Hallyn rc = -ENOMEM; 6840cccca06SSerge E. Hallyn goto out; 6850cccca06SSerge E. Hallyn } 6861da177e4SLinus Torvalds strcpy(scontextp, initial_sid_to_string[sid]); 6871da177e4SLinus Torvalds *scontext = scontextp; 6881da177e4SLinus Torvalds goto out; 6891da177e4SLinus Torvalds } 690744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: called before initial " 691744ba35eSEric Paris "load_policy on unknown SID %d\n", __func__, sid); 6921da177e4SLinus Torvalds rc = -EINVAL; 6931da177e4SLinus Torvalds goto out; 6941da177e4SLinus Torvalds } 6951da177e4SLinus Torvalds POLICY_RDLOCK; 6961da177e4SLinus Torvalds context = sidtab_search(&sidtab, sid); 6971da177e4SLinus Torvalds if (!context) { 698744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 699744ba35eSEric Paris __func__, sid); 7001da177e4SLinus Torvalds rc = -EINVAL; 7011da177e4SLinus Torvalds goto out_unlock; 7021da177e4SLinus Torvalds } 7031da177e4SLinus Torvalds rc = context_struct_to_string(context, scontext, scontext_len); 7041da177e4SLinus Torvalds out_unlock: 7051da177e4SLinus Torvalds POLICY_RDUNLOCK; 7061da177e4SLinus Torvalds out: 7071da177e4SLinus Torvalds return rc; 7081da177e4SLinus Torvalds 7091da177e4SLinus Torvalds } 7101da177e4SLinus Torvalds 7118f0cfa52SDavid Howells static int security_context_to_sid_core(const char *scontext, u32 scontext_len, 712869ab514SStephen Smalley u32 *sid, u32 def_sid, gfp_t gfp_flags) 7131da177e4SLinus Torvalds { 7141da177e4SLinus Torvalds char *scontext2; 7151da177e4SLinus Torvalds struct context context; 7161da177e4SLinus Torvalds struct role_datum *role; 7171da177e4SLinus Torvalds struct type_datum *typdatum; 7181da177e4SLinus Torvalds struct user_datum *usrdatum; 7191da177e4SLinus Torvalds char *scontextp, *p, oldc; 7201da177e4SLinus Torvalds int rc = 0; 7211da177e4SLinus Torvalds 7221da177e4SLinus Torvalds if (!ss_initialized) { 7231da177e4SLinus Torvalds int i; 7241da177e4SLinus Torvalds 7251da177e4SLinus Torvalds for (i = 1; i < SECINITSID_NUM; i++) { 7261da177e4SLinus Torvalds if (!strcmp(initial_sid_to_string[i], scontext)) { 7271da177e4SLinus Torvalds *sid = i; 7281da177e4SLinus Torvalds goto out; 7291da177e4SLinus Torvalds } 7301da177e4SLinus Torvalds } 7311da177e4SLinus Torvalds *sid = SECINITSID_KERNEL; 7321da177e4SLinus Torvalds goto out; 7331da177e4SLinus Torvalds } 7341da177e4SLinus Torvalds *sid = SECSID_NULL; 7351da177e4SLinus Torvalds 7361da177e4SLinus Torvalds /* Copy the string so that we can modify the copy as we parse it. 7371da177e4SLinus Torvalds The string should already by null terminated, but we append a 7381da177e4SLinus Torvalds null suffix to the copy to avoid problems with the existing 7391da177e4SLinus Torvalds attr package, which doesn't view the null terminator as part 7401da177e4SLinus Torvalds of the attribute value. */ 741869ab514SStephen Smalley scontext2 = kmalloc(scontext_len+1, gfp_flags); 7421da177e4SLinus Torvalds if (!scontext2) { 7431da177e4SLinus Torvalds rc = -ENOMEM; 7441da177e4SLinus Torvalds goto out; 7451da177e4SLinus Torvalds } 7461da177e4SLinus Torvalds memcpy(scontext2, scontext, scontext_len); 7471da177e4SLinus Torvalds scontext2[scontext_len] = 0; 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds context_init(&context); 7501da177e4SLinus Torvalds *sid = SECSID_NULL; 7511da177e4SLinus Torvalds 7521da177e4SLinus Torvalds POLICY_RDLOCK; 7531da177e4SLinus Torvalds 7541da177e4SLinus Torvalds /* Parse the security context. */ 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds rc = -EINVAL; 7571da177e4SLinus Torvalds scontextp = (char *) scontext2; 7581da177e4SLinus Torvalds 7591da177e4SLinus Torvalds /* Extract the user. */ 7601da177e4SLinus Torvalds p = scontextp; 7611da177e4SLinus Torvalds while (*p && *p != ':') 7621da177e4SLinus Torvalds p++; 7631da177e4SLinus Torvalds 7641da177e4SLinus Torvalds if (*p == 0) 7651da177e4SLinus Torvalds goto out_unlock; 7661da177e4SLinus Torvalds 7671da177e4SLinus Torvalds *p++ = 0; 7681da177e4SLinus Torvalds 7691da177e4SLinus Torvalds usrdatum = hashtab_search(policydb.p_users.table, scontextp); 7701da177e4SLinus Torvalds if (!usrdatum) 7711da177e4SLinus Torvalds goto out_unlock; 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds context.user = usrdatum->value; 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds /* Extract role. */ 7761da177e4SLinus Torvalds scontextp = p; 7771da177e4SLinus Torvalds while (*p && *p != ':') 7781da177e4SLinus Torvalds p++; 7791da177e4SLinus Torvalds 7801da177e4SLinus Torvalds if (*p == 0) 7811da177e4SLinus Torvalds goto out_unlock; 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds *p++ = 0; 7841da177e4SLinus Torvalds 7851da177e4SLinus Torvalds role = hashtab_search(policydb.p_roles.table, scontextp); 7861da177e4SLinus Torvalds if (!role) 7871da177e4SLinus Torvalds goto out_unlock; 7881da177e4SLinus Torvalds context.role = role->value; 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds /* Extract type. */ 7911da177e4SLinus Torvalds scontextp = p; 7921da177e4SLinus Torvalds while (*p && *p != ':') 7931da177e4SLinus Torvalds p++; 7941da177e4SLinus Torvalds oldc = *p; 7951da177e4SLinus Torvalds *p++ = 0; 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds typdatum = hashtab_search(policydb.p_types.table, scontextp); 7981da177e4SLinus Torvalds if (!typdatum) 7991da177e4SLinus Torvalds goto out_unlock; 8001da177e4SLinus Torvalds 8011da177e4SLinus Torvalds context.type = typdatum->value; 8021da177e4SLinus Torvalds 803f5c1d5b2SJames Morris rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid); 8041da177e4SLinus Torvalds if (rc) 8051da177e4SLinus Torvalds goto out_unlock; 8061da177e4SLinus Torvalds 8071da177e4SLinus Torvalds if ((p - scontext2) < scontext_len) { 8081da177e4SLinus Torvalds rc = -EINVAL; 8091da177e4SLinus Torvalds goto out_unlock; 8101da177e4SLinus Torvalds } 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds /* Check the validity of the new context. */ 8131da177e4SLinus Torvalds if (!policydb_context_isvalid(&policydb, &context)) { 8141da177e4SLinus Torvalds rc = -EINVAL; 8151da177e4SLinus Torvalds goto out_unlock; 8161da177e4SLinus Torvalds } 8171da177e4SLinus Torvalds /* Obtain the new sid. */ 8181da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &context, sid); 8191da177e4SLinus Torvalds out_unlock: 8201da177e4SLinus Torvalds POLICY_RDUNLOCK; 8211da177e4SLinus Torvalds context_destroy(&context); 8221da177e4SLinus Torvalds kfree(scontext2); 8231da177e4SLinus Torvalds out: 8241da177e4SLinus Torvalds return rc; 8251da177e4SLinus Torvalds } 8261da177e4SLinus Torvalds 827f5c1d5b2SJames Morris /** 828f5c1d5b2SJames Morris * security_context_to_sid - Obtain a SID for a given security context. 829f5c1d5b2SJames Morris * @scontext: security context 830f5c1d5b2SJames Morris * @scontext_len: length in bytes 831f5c1d5b2SJames Morris * @sid: security identifier, SID 832f5c1d5b2SJames Morris * 833f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 834f5c1d5b2SJames Morris * has the string representation specified by @scontext. 835f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 836f5c1d5b2SJames Morris * memory is available, or 0 on success. 837f5c1d5b2SJames Morris */ 8388f0cfa52SDavid Howells int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) 839f5c1d5b2SJames Morris { 840f5c1d5b2SJames Morris return security_context_to_sid_core(scontext, scontext_len, 841869ab514SStephen Smalley sid, SECSID_NULL, GFP_KERNEL); 842f5c1d5b2SJames Morris } 843f5c1d5b2SJames Morris 844f5c1d5b2SJames Morris /** 845f5c1d5b2SJames Morris * security_context_to_sid_default - Obtain a SID for a given security context, 846f5c1d5b2SJames Morris * falling back to specified default if needed. 847f5c1d5b2SJames Morris * 848f5c1d5b2SJames Morris * @scontext: security context 849f5c1d5b2SJames Morris * @scontext_len: length in bytes 850f5c1d5b2SJames Morris * @sid: security identifier, SID 851d133a960SGabriel Craciunescu * @def_sid: default SID to assign on error 852f5c1d5b2SJames Morris * 853f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 854f5c1d5b2SJames Morris * has the string representation specified by @scontext. 855f5c1d5b2SJames Morris * The default SID is passed to the MLS layer to be used to allow 856f5c1d5b2SJames Morris * kernel labeling of the MLS field if the MLS field is not present 857f5c1d5b2SJames Morris * (for upgrading to MLS without full relabel). 858f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 859f5c1d5b2SJames Morris * memory is available, or 0 on success. 860f5c1d5b2SJames Morris */ 8617bf570dcSDavid Howells int security_context_to_sid_default(const char *scontext, u32 scontext_len, 8627bf570dcSDavid Howells u32 *sid, u32 def_sid, gfp_t gfp_flags) 863f5c1d5b2SJames Morris { 864f5c1d5b2SJames Morris return security_context_to_sid_core(scontext, scontext_len, 865869ab514SStephen Smalley sid, def_sid, gfp_flags); 866f5c1d5b2SJames Morris } 867f5c1d5b2SJames Morris 8681da177e4SLinus Torvalds static int compute_sid_handle_invalid_context( 8691da177e4SLinus Torvalds struct context *scontext, 8701da177e4SLinus Torvalds struct context *tcontext, 8711da177e4SLinus Torvalds u16 tclass, 8721da177e4SLinus Torvalds struct context *newcontext) 8731da177e4SLinus Torvalds { 8741da177e4SLinus Torvalds char *s = NULL, *t = NULL, *n = NULL; 8751da177e4SLinus Torvalds u32 slen, tlen, nlen; 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds if (context_struct_to_string(scontext, &s, &slen) < 0) 8781da177e4SLinus Torvalds goto out; 8791da177e4SLinus Torvalds if (context_struct_to_string(tcontext, &t, &tlen) < 0) 8801da177e4SLinus Torvalds goto out; 8811da177e4SLinus Torvalds if (context_struct_to_string(newcontext, &n, &nlen) < 0) 8821da177e4SLinus Torvalds goto out; 8839ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 8841da177e4SLinus Torvalds "security_compute_sid: invalid context %s" 8851da177e4SLinus Torvalds " for scontext=%s" 8861da177e4SLinus Torvalds " tcontext=%s" 8871da177e4SLinus Torvalds " tclass=%s", 8881da177e4SLinus Torvalds n, s, t, policydb.p_class_val_to_name[tclass-1]); 8891da177e4SLinus Torvalds out: 8901da177e4SLinus Torvalds kfree(s); 8911da177e4SLinus Torvalds kfree(t); 8921da177e4SLinus Torvalds kfree(n); 8931da177e4SLinus Torvalds if (!selinux_enforcing) 8941da177e4SLinus Torvalds return 0; 8951da177e4SLinus Torvalds return -EACCES; 8961da177e4SLinus Torvalds } 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds static int security_compute_sid(u32 ssid, 8991da177e4SLinus Torvalds u32 tsid, 9001da177e4SLinus Torvalds u16 tclass, 9011da177e4SLinus Torvalds u32 specified, 9021da177e4SLinus Torvalds u32 *out_sid) 9031da177e4SLinus Torvalds { 9041da177e4SLinus Torvalds struct context *scontext = NULL, *tcontext = NULL, newcontext; 9051da177e4SLinus Torvalds struct role_trans *roletr = NULL; 9061da177e4SLinus Torvalds struct avtab_key avkey; 9071da177e4SLinus Torvalds struct avtab_datum *avdatum; 9081da177e4SLinus Torvalds struct avtab_node *node; 9091da177e4SLinus Torvalds int rc = 0; 9101da177e4SLinus Torvalds 9111da177e4SLinus Torvalds if (!ss_initialized) { 9121da177e4SLinus Torvalds switch (tclass) { 9131da177e4SLinus Torvalds case SECCLASS_PROCESS: 9141da177e4SLinus Torvalds *out_sid = ssid; 9151da177e4SLinus Torvalds break; 9161da177e4SLinus Torvalds default: 9171da177e4SLinus Torvalds *out_sid = tsid; 9181da177e4SLinus Torvalds break; 9191da177e4SLinus Torvalds } 9201da177e4SLinus Torvalds goto out; 9211da177e4SLinus Torvalds } 9221da177e4SLinus Torvalds 923851f8a69SVenkat Yekkirala context_init(&newcontext); 924851f8a69SVenkat Yekkirala 9251da177e4SLinus Torvalds POLICY_RDLOCK; 9261da177e4SLinus Torvalds 9271da177e4SLinus Torvalds scontext = sidtab_search(&sidtab, ssid); 9281da177e4SLinus Torvalds if (!scontext) { 929744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 930744ba35eSEric Paris __func__, ssid); 9311da177e4SLinus Torvalds rc = -EINVAL; 9321da177e4SLinus Torvalds goto out_unlock; 9331da177e4SLinus Torvalds } 9341da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tsid); 9351da177e4SLinus Torvalds if (!tcontext) { 936744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 937744ba35eSEric Paris __func__, tsid); 9381da177e4SLinus Torvalds rc = -EINVAL; 9391da177e4SLinus Torvalds goto out_unlock; 9401da177e4SLinus Torvalds } 9411da177e4SLinus Torvalds 9421da177e4SLinus Torvalds /* Set the user identity. */ 9431da177e4SLinus Torvalds switch (specified) { 9441da177e4SLinus Torvalds case AVTAB_TRANSITION: 9451da177e4SLinus Torvalds case AVTAB_CHANGE: 9461da177e4SLinus Torvalds /* Use the process user identity. */ 9471da177e4SLinus Torvalds newcontext.user = scontext->user; 9481da177e4SLinus Torvalds break; 9491da177e4SLinus Torvalds case AVTAB_MEMBER: 9501da177e4SLinus Torvalds /* Use the related object owner. */ 9511da177e4SLinus Torvalds newcontext.user = tcontext->user; 9521da177e4SLinus Torvalds break; 9531da177e4SLinus Torvalds } 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds /* Set the role and type to default values. */ 9561da177e4SLinus Torvalds switch (tclass) { 9571da177e4SLinus Torvalds case SECCLASS_PROCESS: 9581da177e4SLinus Torvalds /* Use the current role and type of process. */ 9591da177e4SLinus Torvalds newcontext.role = scontext->role; 9601da177e4SLinus Torvalds newcontext.type = scontext->type; 9611da177e4SLinus Torvalds break; 9621da177e4SLinus Torvalds default: 9631da177e4SLinus Torvalds /* Use the well-defined object role. */ 9641da177e4SLinus Torvalds newcontext.role = OBJECT_R_VAL; 9651da177e4SLinus Torvalds /* Use the type of the related object. */ 9661da177e4SLinus Torvalds newcontext.type = tcontext->type; 9671da177e4SLinus Torvalds } 9681da177e4SLinus Torvalds 9691da177e4SLinus Torvalds /* Look for a type transition/member/change rule. */ 9701da177e4SLinus Torvalds avkey.source_type = scontext->type; 9711da177e4SLinus Torvalds avkey.target_type = tcontext->type; 9721da177e4SLinus Torvalds avkey.target_class = tclass; 973782ebb99SStephen Smalley avkey.specified = specified; 974782ebb99SStephen Smalley avdatum = avtab_search(&policydb.te_avtab, &avkey); 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds /* If no permanent rule, also check for enabled conditional rules */ 9771da177e4SLinus Torvalds if (!avdatum) { 978782ebb99SStephen Smalley node = avtab_search_node(&policydb.te_cond_avtab, &avkey); 9791da177e4SLinus Torvalds for (; node != NULL; node = avtab_search_node_next(node, specified)) { 980782ebb99SStephen Smalley if (node->key.specified & AVTAB_ENABLED) { 9811da177e4SLinus Torvalds avdatum = &node->datum; 9821da177e4SLinus Torvalds break; 9831da177e4SLinus Torvalds } 9841da177e4SLinus Torvalds } 9851da177e4SLinus Torvalds } 9861da177e4SLinus Torvalds 987782ebb99SStephen Smalley if (avdatum) { 9881da177e4SLinus Torvalds /* Use the type from the type transition/member/change rule. */ 989782ebb99SStephen Smalley newcontext.type = avdatum->data; 9901da177e4SLinus Torvalds } 9911da177e4SLinus Torvalds 9921da177e4SLinus Torvalds /* Check for class-specific changes. */ 9931da177e4SLinus Torvalds switch (tclass) { 9941da177e4SLinus Torvalds case SECCLASS_PROCESS: 9951da177e4SLinus Torvalds if (specified & AVTAB_TRANSITION) { 9961da177e4SLinus Torvalds /* Look for a role transition rule. */ 9971da177e4SLinus Torvalds for (roletr = policydb.role_tr; roletr; 9981da177e4SLinus Torvalds roletr = roletr->next) { 9991da177e4SLinus Torvalds if (roletr->role == scontext->role && 10001da177e4SLinus Torvalds roletr->type == tcontext->type) { 10011da177e4SLinus Torvalds /* Use the role transition rule. */ 10021da177e4SLinus Torvalds newcontext.role = roletr->new_role; 10031da177e4SLinus Torvalds break; 10041da177e4SLinus Torvalds } 10051da177e4SLinus Torvalds } 10061da177e4SLinus Torvalds } 10071da177e4SLinus Torvalds break; 10081da177e4SLinus Torvalds default: 10091da177e4SLinus Torvalds break; 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds /* Set the MLS attributes. 10131da177e4SLinus Torvalds This is done last because it may allocate memory. */ 10141da177e4SLinus Torvalds rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext); 10151da177e4SLinus Torvalds if (rc) 10161da177e4SLinus Torvalds goto out_unlock; 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds /* Check the validity of the context. */ 10191da177e4SLinus Torvalds if (!policydb_context_isvalid(&policydb, &newcontext)) { 10201da177e4SLinus Torvalds rc = compute_sid_handle_invalid_context(scontext, 10211da177e4SLinus Torvalds tcontext, 10221da177e4SLinus Torvalds tclass, 10231da177e4SLinus Torvalds &newcontext); 10241da177e4SLinus Torvalds if (rc) 10251da177e4SLinus Torvalds goto out_unlock; 10261da177e4SLinus Torvalds } 10271da177e4SLinus Torvalds /* Obtain the sid for the context. */ 10281da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid); 10291da177e4SLinus Torvalds out_unlock: 10301da177e4SLinus Torvalds POLICY_RDUNLOCK; 10311da177e4SLinus Torvalds context_destroy(&newcontext); 10321da177e4SLinus Torvalds out: 10331da177e4SLinus Torvalds return rc; 10341da177e4SLinus Torvalds } 10351da177e4SLinus Torvalds 10361da177e4SLinus Torvalds /** 10371da177e4SLinus Torvalds * security_transition_sid - Compute the SID for a new subject/object. 10381da177e4SLinus Torvalds * @ssid: source security identifier 10391da177e4SLinus Torvalds * @tsid: target security identifier 10401da177e4SLinus Torvalds * @tclass: target security class 10411da177e4SLinus Torvalds * @out_sid: security identifier for new subject/object 10421da177e4SLinus Torvalds * 10431da177e4SLinus Torvalds * Compute a SID to use for labeling a new subject or object in the 10441da177e4SLinus Torvalds * class @tclass based on a SID pair (@ssid, @tsid). 10451da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 10461da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the new SID was 10471da177e4SLinus Torvalds * computed successfully. 10481da177e4SLinus Torvalds */ 10491da177e4SLinus Torvalds int security_transition_sid(u32 ssid, 10501da177e4SLinus Torvalds u32 tsid, 10511da177e4SLinus Torvalds u16 tclass, 10521da177e4SLinus Torvalds u32 *out_sid) 10531da177e4SLinus Torvalds { 10541da177e4SLinus Torvalds return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid); 10551da177e4SLinus Torvalds } 10561da177e4SLinus Torvalds 10571da177e4SLinus Torvalds /** 10581da177e4SLinus Torvalds * security_member_sid - Compute the SID for member selection. 10591da177e4SLinus Torvalds * @ssid: source security identifier 10601da177e4SLinus Torvalds * @tsid: target security identifier 10611da177e4SLinus Torvalds * @tclass: target security class 10621da177e4SLinus Torvalds * @out_sid: security identifier for selected member 10631da177e4SLinus Torvalds * 10641da177e4SLinus Torvalds * Compute a SID to use when selecting a member of a polyinstantiated 10651da177e4SLinus Torvalds * object of class @tclass based on a SID pair (@ssid, @tsid). 10661da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 10671da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 10681da177e4SLinus Torvalds * computed successfully. 10691da177e4SLinus Torvalds */ 10701da177e4SLinus Torvalds int security_member_sid(u32 ssid, 10711da177e4SLinus Torvalds u32 tsid, 10721da177e4SLinus Torvalds u16 tclass, 10731da177e4SLinus Torvalds u32 *out_sid) 10741da177e4SLinus Torvalds { 10751da177e4SLinus Torvalds return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid); 10761da177e4SLinus Torvalds } 10771da177e4SLinus Torvalds 10781da177e4SLinus Torvalds /** 10791da177e4SLinus Torvalds * security_change_sid - Compute the SID for object relabeling. 10801da177e4SLinus Torvalds * @ssid: source security identifier 10811da177e4SLinus Torvalds * @tsid: target security identifier 10821da177e4SLinus Torvalds * @tclass: target security class 10831da177e4SLinus Torvalds * @out_sid: security identifier for selected member 10841da177e4SLinus Torvalds * 10851da177e4SLinus Torvalds * Compute a SID to use for relabeling an object of class @tclass 10861da177e4SLinus Torvalds * based on a SID pair (@ssid, @tsid). 10871da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 10881da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 10891da177e4SLinus Torvalds * computed successfully. 10901da177e4SLinus Torvalds */ 10911da177e4SLinus Torvalds int security_change_sid(u32 ssid, 10921da177e4SLinus Torvalds u32 tsid, 10931da177e4SLinus Torvalds u16 tclass, 10941da177e4SLinus Torvalds u32 *out_sid) 10951da177e4SLinus Torvalds { 10961da177e4SLinus Torvalds return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid); 10971da177e4SLinus Torvalds } 10981da177e4SLinus Torvalds 1099b94c7e67SChad Sellers /* 1100b94c7e67SChad Sellers * Verify that each kernel class that is defined in the 1101b94c7e67SChad Sellers * policy is correct 1102b94c7e67SChad Sellers */ 1103b94c7e67SChad Sellers static int validate_classes(struct policydb *p) 1104b94c7e67SChad Sellers { 1105b94c7e67SChad Sellers int i, j; 1106b94c7e67SChad Sellers struct class_datum *cladatum; 1107b94c7e67SChad Sellers struct perm_datum *perdatum; 1108b94c7e67SChad Sellers u32 nprim, tmp, common_pts_len, perm_val, pol_val; 1109b94c7e67SChad Sellers u16 class_val; 1110b94c7e67SChad Sellers const struct selinux_class_perm *kdefs = &selinux_class_perm; 1111b94c7e67SChad Sellers const char *def_class, *def_perm, *pol_class; 1112b94c7e67SChad Sellers struct symtab *perms; 1113b94c7e67SChad Sellers 11143f12070eSEric Paris if (p->allow_unknown) { 11153f12070eSEric Paris u32 num_classes = kdefs->cts_len; 11163f12070eSEric Paris p->undefined_perms = kcalloc(num_classes, sizeof(u32), GFP_KERNEL); 11173f12070eSEric Paris if (!p->undefined_perms) 11183f12070eSEric Paris return -ENOMEM; 11193f12070eSEric Paris } 11203f12070eSEric Paris 1121b94c7e67SChad Sellers for (i = 1; i < kdefs->cts_len; i++) { 1122b94c7e67SChad Sellers def_class = kdefs->class_to_string[i]; 1123a764ae4bSStephen Smalley if (!def_class) 1124a764ae4bSStephen Smalley continue; 1125b94c7e67SChad Sellers if (i > p->p_classes.nprim) { 1126b94c7e67SChad Sellers printk(KERN_INFO 1127454d972cSJames Morris "SELinux: class %s not defined in policy\n", 1128b94c7e67SChad Sellers def_class); 11293f12070eSEric Paris if (p->reject_unknown) 11303f12070eSEric Paris return -EINVAL; 11313f12070eSEric Paris if (p->allow_unknown) 11323f12070eSEric Paris p->undefined_perms[i-1] = ~0U; 1133b94c7e67SChad Sellers continue; 1134b94c7e67SChad Sellers } 1135b94c7e67SChad Sellers pol_class = p->p_class_val_to_name[i-1]; 1136b94c7e67SChad Sellers if (strcmp(pol_class, def_class)) { 1137b94c7e67SChad Sellers printk(KERN_ERR 1138454d972cSJames Morris "SELinux: class %d is incorrect, found %s but should be %s\n", 1139b94c7e67SChad Sellers i, pol_class, def_class); 1140b94c7e67SChad Sellers return -EINVAL; 1141b94c7e67SChad Sellers } 1142b94c7e67SChad Sellers } 1143b94c7e67SChad Sellers for (i = 0; i < kdefs->av_pts_len; i++) { 1144b94c7e67SChad Sellers class_val = kdefs->av_perm_to_string[i].tclass; 1145b94c7e67SChad Sellers perm_val = kdefs->av_perm_to_string[i].value; 1146b94c7e67SChad Sellers def_perm = kdefs->av_perm_to_string[i].name; 1147b94c7e67SChad Sellers if (class_val > p->p_classes.nprim) 1148b94c7e67SChad Sellers continue; 1149b94c7e67SChad Sellers pol_class = p->p_class_val_to_name[class_val-1]; 1150b94c7e67SChad Sellers cladatum = hashtab_search(p->p_classes.table, pol_class); 1151b94c7e67SChad Sellers BUG_ON(!cladatum); 1152b94c7e67SChad Sellers perms = &cladatum->permissions; 1153b94c7e67SChad Sellers nprim = 1 << (perms->nprim - 1); 1154b94c7e67SChad Sellers if (perm_val > nprim) { 1155b94c7e67SChad Sellers printk(KERN_INFO 1156454d972cSJames Morris "SELinux: permission %s in class %s not defined in policy\n", 1157b94c7e67SChad Sellers def_perm, pol_class); 11583f12070eSEric Paris if (p->reject_unknown) 11593f12070eSEric Paris return -EINVAL; 11603f12070eSEric Paris if (p->allow_unknown) 11613f12070eSEric Paris p->undefined_perms[class_val-1] |= perm_val; 1162b94c7e67SChad Sellers continue; 1163b94c7e67SChad Sellers } 1164b94c7e67SChad Sellers perdatum = hashtab_search(perms->table, def_perm); 1165b94c7e67SChad Sellers if (perdatum == NULL) { 1166b94c7e67SChad Sellers printk(KERN_ERR 1167454d972cSJames Morris "SELinux: permission %s in class %s not found in policy, bad policy\n", 1168b94c7e67SChad Sellers def_perm, pol_class); 1169b94c7e67SChad Sellers return -EINVAL; 1170b94c7e67SChad Sellers } 1171b94c7e67SChad Sellers pol_val = 1 << (perdatum->value - 1); 1172b94c7e67SChad Sellers if (pol_val != perm_val) { 1173b94c7e67SChad Sellers printk(KERN_ERR 1174454d972cSJames Morris "SELinux: permission %s in class %s has incorrect value\n", 1175b94c7e67SChad Sellers def_perm, pol_class); 1176b94c7e67SChad Sellers return -EINVAL; 1177b94c7e67SChad Sellers } 1178b94c7e67SChad Sellers } 1179b94c7e67SChad Sellers for (i = 0; i < kdefs->av_inherit_len; i++) { 1180b94c7e67SChad Sellers class_val = kdefs->av_inherit[i].tclass; 1181b94c7e67SChad Sellers if (class_val > p->p_classes.nprim) 1182b94c7e67SChad Sellers continue; 1183b94c7e67SChad Sellers pol_class = p->p_class_val_to_name[class_val-1]; 1184b94c7e67SChad Sellers cladatum = hashtab_search(p->p_classes.table, pol_class); 1185b94c7e67SChad Sellers BUG_ON(!cladatum); 1186b94c7e67SChad Sellers if (!cladatum->comdatum) { 1187b94c7e67SChad Sellers printk(KERN_ERR 1188454d972cSJames Morris "SELinux: class %s should have an inherits clause but does not\n", 1189b94c7e67SChad Sellers pol_class); 1190b94c7e67SChad Sellers return -EINVAL; 1191b94c7e67SChad Sellers } 1192b94c7e67SChad Sellers tmp = kdefs->av_inherit[i].common_base; 1193b94c7e67SChad Sellers common_pts_len = 0; 1194b94c7e67SChad Sellers while (!(tmp & 0x01)) { 1195b94c7e67SChad Sellers common_pts_len++; 1196b94c7e67SChad Sellers tmp >>= 1; 1197b94c7e67SChad Sellers } 1198b94c7e67SChad Sellers perms = &cladatum->comdatum->permissions; 1199b94c7e67SChad Sellers for (j = 0; j < common_pts_len; j++) { 1200b94c7e67SChad Sellers def_perm = kdefs->av_inherit[i].common_pts[j]; 1201b94c7e67SChad Sellers if (j >= perms->nprim) { 1202b94c7e67SChad Sellers printk(KERN_INFO 1203454d972cSJames Morris "SELinux: permission %s in class %s not defined in policy\n", 1204b94c7e67SChad Sellers def_perm, pol_class); 12053f12070eSEric Paris if (p->reject_unknown) 12063f12070eSEric Paris return -EINVAL; 12073f12070eSEric Paris if (p->allow_unknown) 12083f12070eSEric Paris p->undefined_perms[class_val-1] |= (1 << j); 1209b94c7e67SChad Sellers continue; 1210b94c7e67SChad Sellers } 1211b94c7e67SChad Sellers perdatum = hashtab_search(perms->table, def_perm); 1212b94c7e67SChad Sellers if (perdatum == NULL) { 1213b94c7e67SChad Sellers printk(KERN_ERR 1214454d972cSJames Morris "SELinux: permission %s in class %s not found in policy, bad policy\n", 1215b94c7e67SChad Sellers def_perm, pol_class); 1216b94c7e67SChad Sellers return -EINVAL; 1217b94c7e67SChad Sellers } 1218b94c7e67SChad Sellers if (perdatum->value != j + 1) { 1219b94c7e67SChad Sellers printk(KERN_ERR 1220454d972cSJames Morris "SELinux: permission %s in class %s has incorrect value\n", 1221b94c7e67SChad Sellers def_perm, pol_class); 1222b94c7e67SChad Sellers return -EINVAL; 1223b94c7e67SChad Sellers } 1224b94c7e67SChad Sellers } 1225b94c7e67SChad Sellers } 1226b94c7e67SChad Sellers return 0; 1227b94c7e67SChad Sellers } 1228b94c7e67SChad Sellers 12291da177e4SLinus Torvalds /* Clone the SID into the new SID table. */ 12301da177e4SLinus Torvalds static int clone_sid(u32 sid, 12311da177e4SLinus Torvalds struct context *context, 12321da177e4SLinus Torvalds void *arg) 12331da177e4SLinus Torvalds { 12341da177e4SLinus Torvalds struct sidtab *s = arg; 12351da177e4SLinus Torvalds 12361da177e4SLinus Torvalds return sidtab_insert(s, sid, context); 12371da177e4SLinus Torvalds } 12381da177e4SLinus Torvalds 12391da177e4SLinus Torvalds static inline int convert_context_handle_invalid_context(struct context *context) 12401da177e4SLinus Torvalds { 12411da177e4SLinus Torvalds int rc = 0; 12421da177e4SLinus Torvalds 12431da177e4SLinus Torvalds if (selinux_enforcing) { 12441da177e4SLinus Torvalds rc = -EINVAL; 12451da177e4SLinus Torvalds } else { 12461da177e4SLinus Torvalds char *s; 12471da177e4SLinus Torvalds u32 len; 12481da177e4SLinus Torvalds 12491da177e4SLinus Torvalds context_struct_to_string(context, &s, &len); 1250454d972cSJames Morris printk(KERN_ERR "SELinux: context %s is invalid\n", s); 12511da177e4SLinus Torvalds kfree(s); 12521da177e4SLinus Torvalds } 12531da177e4SLinus Torvalds return rc; 12541da177e4SLinus Torvalds } 12551da177e4SLinus Torvalds 12561da177e4SLinus Torvalds struct convert_context_args { 12571da177e4SLinus Torvalds struct policydb *oldp; 12581da177e4SLinus Torvalds struct policydb *newp; 12591da177e4SLinus Torvalds }; 12601da177e4SLinus Torvalds 12611da177e4SLinus Torvalds /* 12621da177e4SLinus Torvalds * Convert the values in the security context 12631da177e4SLinus Torvalds * structure `c' from the values specified 12641da177e4SLinus Torvalds * in the policy `p->oldp' to the values specified 12651da177e4SLinus Torvalds * in the policy `p->newp'. Verify that the 12661da177e4SLinus Torvalds * context is valid under the new policy. 12671da177e4SLinus Torvalds */ 12681da177e4SLinus Torvalds static int convert_context(u32 key, 12691da177e4SLinus Torvalds struct context *c, 12701da177e4SLinus Torvalds void *p) 12711da177e4SLinus Torvalds { 12721da177e4SLinus Torvalds struct convert_context_args *args; 12731da177e4SLinus Torvalds struct context oldc; 12741da177e4SLinus Torvalds struct role_datum *role; 12751da177e4SLinus Torvalds struct type_datum *typdatum; 12761da177e4SLinus Torvalds struct user_datum *usrdatum; 12771da177e4SLinus Torvalds char *s; 12781da177e4SLinus Torvalds u32 len; 12791da177e4SLinus Torvalds int rc; 12801da177e4SLinus Torvalds 12811da177e4SLinus Torvalds args = p; 12821da177e4SLinus Torvalds 12831da177e4SLinus Torvalds rc = context_cpy(&oldc, c); 12841da177e4SLinus Torvalds if (rc) 12851da177e4SLinus Torvalds goto out; 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds rc = -EINVAL; 12881da177e4SLinus Torvalds 12891da177e4SLinus Torvalds /* Convert the user. */ 12901da177e4SLinus Torvalds usrdatum = hashtab_search(args->newp->p_users.table, 12911da177e4SLinus Torvalds args->oldp->p_user_val_to_name[c->user - 1]); 12925d55a345SEric Paris if (!usrdatum) 12931da177e4SLinus Torvalds goto bad; 12941da177e4SLinus Torvalds c->user = usrdatum->value; 12951da177e4SLinus Torvalds 12961da177e4SLinus Torvalds /* Convert the role. */ 12971da177e4SLinus Torvalds role = hashtab_search(args->newp->p_roles.table, 12981da177e4SLinus Torvalds args->oldp->p_role_val_to_name[c->role - 1]); 12995d55a345SEric Paris if (!role) 13001da177e4SLinus Torvalds goto bad; 13011da177e4SLinus Torvalds c->role = role->value; 13021da177e4SLinus Torvalds 13031da177e4SLinus Torvalds /* Convert the type. */ 13041da177e4SLinus Torvalds typdatum = hashtab_search(args->newp->p_types.table, 13051da177e4SLinus Torvalds args->oldp->p_type_val_to_name[c->type - 1]); 13065d55a345SEric Paris if (!typdatum) 13071da177e4SLinus Torvalds goto bad; 13081da177e4SLinus Torvalds c->type = typdatum->value; 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds rc = mls_convert_context(args->oldp, args->newp, c); 13111da177e4SLinus Torvalds if (rc) 13121da177e4SLinus Torvalds goto bad; 13131da177e4SLinus Torvalds 13141da177e4SLinus Torvalds /* Check the validity of the new context. */ 13151da177e4SLinus Torvalds if (!policydb_context_isvalid(args->newp, c)) { 13161da177e4SLinus Torvalds rc = convert_context_handle_invalid_context(&oldc); 13171da177e4SLinus Torvalds if (rc) 13181da177e4SLinus Torvalds goto bad; 13191da177e4SLinus Torvalds } 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds context_destroy(&oldc); 13221da177e4SLinus Torvalds out: 13231da177e4SLinus Torvalds return rc; 13241da177e4SLinus Torvalds bad: 13251da177e4SLinus Torvalds context_struct_to_string(&oldc, &s, &len); 13261da177e4SLinus Torvalds context_destroy(&oldc); 1327454d972cSJames Morris printk(KERN_ERR "SELinux: invalidating context %s\n", s); 13281da177e4SLinus Torvalds kfree(s); 13291da177e4SLinus Torvalds goto out; 13301da177e4SLinus Torvalds } 13311da177e4SLinus Torvalds 13323bb56b25SPaul Moore static void security_load_policycaps(void) 13333bb56b25SPaul Moore { 13343bb56b25SPaul Moore selinux_policycap_netpeer = ebitmap_get_bit(&policydb.policycaps, 13353bb56b25SPaul Moore POLICYDB_CAPABILITY_NETPEER); 1336b0c636b9SEric Paris selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps, 1337b0c636b9SEric Paris POLICYDB_CAPABILITY_OPENPERM); 13383bb56b25SPaul Moore } 13393bb56b25SPaul Moore 13401da177e4SLinus Torvalds extern void selinux_complete_init(void); 1341e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p); 13421da177e4SLinus Torvalds 13431da177e4SLinus Torvalds /** 13441da177e4SLinus Torvalds * security_load_policy - Load a security policy configuration. 13451da177e4SLinus Torvalds * @data: binary policy data 13461da177e4SLinus Torvalds * @len: length of data in bytes 13471da177e4SLinus Torvalds * 13481da177e4SLinus Torvalds * Load a new set of security policy configuration data, 13491da177e4SLinus Torvalds * validate it and convert the SID table as necessary. 13501da177e4SLinus Torvalds * This function will flush the access vector cache after 13511da177e4SLinus Torvalds * loading the new policy. 13521da177e4SLinus Torvalds */ 13531da177e4SLinus Torvalds int security_load_policy(void *data, size_t len) 13541da177e4SLinus Torvalds { 13551da177e4SLinus Torvalds struct policydb oldpolicydb, newpolicydb; 13561da177e4SLinus Torvalds struct sidtab oldsidtab, newsidtab; 13571da177e4SLinus Torvalds struct convert_context_args args; 13581da177e4SLinus Torvalds u32 seqno; 13591da177e4SLinus Torvalds int rc = 0; 13601da177e4SLinus Torvalds struct policy_file file = { data, len }, *fp = &file; 13611da177e4SLinus Torvalds 13621da177e4SLinus Torvalds LOAD_LOCK; 13631da177e4SLinus Torvalds 13641da177e4SLinus Torvalds if (!ss_initialized) { 13651da177e4SLinus Torvalds avtab_cache_init(); 13661da177e4SLinus Torvalds if (policydb_read(&policydb, fp)) { 13671da177e4SLinus Torvalds LOAD_UNLOCK; 13681da177e4SLinus Torvalds avtab_cache_destroy(); 13691da177e4SLinus Torvalds return -EINVAL; 13701da177e4SLinus Torvalds } 13711da177e4SLinus Torvalds if (policydb_load_isids(&policydb, &sidtab)) { 13721da177e4SLinus Torvalds LOAD_UNLOCK; 13731da177e4SLinus Torvalds policydb_destroy(&policydb); 13741da177e4SLinus Torvalds avtab_cache_destroy(); 13751da177e4SLinus Torvalds return -EINVAL; 13761da177e4SLinus Torvalds } 1377b94c7e67SChad Sellers /* Verify that the kernel defined classes are correct. */ 1378b94c7e67SChad Sellers if (validate_classes(&policydb)) { 1379b94c7e67SChad Sellers printk(KERN_ERR 1380454d972cSJames Morris "SELinux: the definition of a class is incorrect\n"); 1381b94c7e67SChad Sellers LOAD_UNLOCK; 1382b94c7e67SChad Sellers sidtab_destroy(&sidtab); 1383b94c7e67SChad Sellers policydb_destroy(&policydb); 1384b94c7e67SChad Sellers avtab_cache_destroy(); 1385b94c7e67SChad Sellers return -EINVAL; 1386b94c7e67SChad Sellers } 13873bb56b25SPaul Moore security_load_policycaps(); 13881da177e4SLinus Torvalds policydb_loaded_version = policydb.policyvers; 13891da177e4SLinus Torvalds ss_initialized = 1; 13904c443d1bSStephen Smalley seqno = ++latest_granting; 13911da177e4SLinus Torvalds LOAD_UNLOCK; 13921da177e4SLinus Torvalds selinux_complete_init(); 13934c443d1bSStephen Smalley avc_ss_reset(seqno); 13944c443d1bSStephen Smalley selnl_notify_policyload(seqno); 13957420ed23SVenkat Yekkirala selinux_netlbl_cache_invalidate(); 1396342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 13971da177e4SLinus Torvalds return 0; 13981da177e4SLinus Torvalds } 13991da177e4SLinus Torvalds 14001da177e4SLinus Torvalds #if 0 14011da177e4SLinus Torvalds sidtab_hash_eval(&sidtab, "sids"); 14021da177e4SLinus Torvalds #endif 14031da177e4SLinus Torvalds 14041da177e4SLinus Torvalds if (policydb_read(&newpolicydb, fp)) { 14051da177e4SLinus Torvalds LOAD_UNLOCK; 14061da177e4SLinus Torvalds return -EINVAL; 14071da177e4SLinus Torvalds } 14081da177e4SLinus Torvalds 14091da177e4SLinus Torvalds sidtab_init(&newsidtab); 14101da177e4SLinus Torvalds 1411b94c7e67SChad Sellers /* Verify that the kernel defined classes are correct. */ 1412b94c7e67SChad Sellers if (validate_classes(&newpolicydb)) { 1413b94c7e67SChad Sellers printk(KERN_ERR 1414454d972cSJames Morris "SELinux: the definition of a class is incorrect\n"); 1415b94c7e67SChad Sellers rc = -EINVAL; 1416b94c7e67SChad Sellers goto err; 1417b94c7e67SChad Sellers } 1418b94c7e67SChad Sellers 1419e900a7d9SStephen Smalley rc = security_preserve_bools(&newpolicydb); 1420e900a7d9SStephen Smalley if (rc) { 1421454d972cSJames Morris printk(KERN_ERR "SELinux: unable to preserve booleans\n"); 1422e900a7d9SStephen Smalley goto err; 1423e900a7d9SStephen Smalley } 1424e900a7d9SStephen Smalley 14251da177e4SLinus Torvalds /* Clone the SID table. */ 14261da177e4SLinus Torvalds sidtab_shutdown(&sidtab); 14271da177e4SLinus Torvalds if (sidtab_map(&sidtab, clone_sid, &newsidtab)) { 14281da177e4SLinus Torvalds rc = -ENOMEM; 14291da177e4SLinus Torvalds goto err; 14301da177e4SLinus Torvalds } 14311da177e4SLinus Torvalds 14321da177e4SLinus Torvalds /* Convert the internal representations of contexts 14331da177e4SLinus Torvalds in the new SID table and remove invalid SIDs. */ 14341da177e4SLinus Torvalds args.oldp = &policydb; 14351da177e4SLinus Torvalds args.newp = &newpolicydb; 14361da177e4SLinus Torvalds sidtab_map_remove_on_error(&newsidtab, convert_context, &args); 14371da177e4SLinus Torvalds 14381da177e4SLinus Torvalds /* Save the old policydb and SID table to free later. */ 14391da177e4SLinus Torvalds memcpy(&oldpolicydb, &policydb, sizeof policydb); 14401da177e4SLinus Torvalds sidtab_set(&oldsidtab, &sidtab); 14411da177e4SLinus Torvalds 14421da177e4SLinus Torvalds /* Install the new policydb and SID table. */ 14431da177e4SLinus Torvalds POLICY_WRLOCK; 14441da177e4SLinus Torvalds memcpy(&policydb, &newpolicydb, sizeof policydb); 14451da177e4SLinus Torvalds sidtab_set(&sidtab, &newsidtab); 14463bb56b25SPaul Moore security_load_policycaps(); 14471da177e4SLinus Torvalds seqno = ++latest_granting; 14481da177e4SLinus Torvalds policydb_loaded_version = policydb.policyvers; 14491da177e4SLinus Torvalds POLICY_WRUNLOCK; 14501da177e4SLinus Torvalds LOAD_UNLOCK; 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds /* Free the old policydb and SID table. */ 14531da177e4SLinus Torvalds policydb_destroy(&oldpolicydb); 14541da177e4SLinus Torvalds sidtab_destroy(&oldsidtab); 14551da177e4SLinus Torvalds 14561da177e4SLinus Torvalds avc_ss_reset(seqno); 14571da177e4SLinus Torvalds selnl_notify_policyload(seqno); 14587420ed23SVenkat Yekkirala selinux_netlbl_cache_invalidate(); 1459342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 14601da177e4SLinus Torvalds 14611da177e4SLinus Torvalds return 0; 14621da177e4SLinus Torvalds 14631da177e4SLinus Torvalds err: 14641da177e4SLinus Torvalds LOAD_UNLOCK; 14651da177e4SLinus Torvalds sidtab_destroy(&newsidtab); 14661da177e4SLinus Torvalds policydb_destroy(&newpolicydb); 14671da177e4SLinus Torvalds return rc; 14681da177e4SLinus Torvalds 14691da177e4SLinus Torvalds } 14701da177e4SLinus Torvalds 14711da177e4SLinus Torvalds /** 14721da177e4SLinus Torvalds * security_port_sid - Obtain the SID for a port. 14731da177e4SLinus Torvalds * @protocol: protocol number 14741da177e4SLinus Torvalds * @port: port number 14751da177e4SLinus Torvalds * @out_sid: security identifier 14761da177e4SLinus Torvalds */ 14773e112172SPaul Moore int security_port_sid(u8 protocol, u16 port, u32 *out_sid) 14781da177e4SLinus Torvalds { 14791da177e4SLinus Torvalds struct ocontext *c; 14801da177e4SLinus Torvalds int rc = 0; 14811da177e4SLinus Torvalds 14821da177e4SLinus Torvalds POLICY_RDLOCK; 14831da177e4SLinus Torvalds 14841da177e4SLinus Torvalds c = policydb.ocontexts[OCON_PORT]; 14851da177e4SLinus Torvalds while (c) { 14861da177e4SLinus Torvalds if (c->u.port.protocol == protocol && 14871da177e4SLinus Torvalds c->u.port.low_port <= port && 14881da177e4SLinus Torvalds c->u.port.high_port >= port) 14891da177e4SLinus Torvalds break; 14901da177e4SLinus Torvalds c = c->next; 14911da177e4SLinus Torvalds } 14921da177e4SLinus Torvalds 14931da177e4SLinus Torvalds if (c) { 14941da177e4SLinus Torvalds if (!c->sid[0]) { 14951da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 14961da177e4SLinus Torvalds &c->context[0], 14971da177e4SLinus Torvalds &c->sid[0]); 14981da177e4SLinus Torvalds if (rc) 14991da177e4SLinus Torvalds goto out; 15001da177e4SLinus Torvalds } 15011da177e4SLinus Torvalds *out_sid = c->sid[0]; 15021da177e4SLinus Torvalds } else { 15031da177e4SLinus Torvalds *out_sid = SECINITSID_PORT; 15041da177e4SLinus Torvalds } 15051da177e4SLinus Torvalds 15061da177e4SLinus Torvalds out: 15071da177e4SLinus Torvalds POLICY_RDUNLOCK; 15081da177e4SLinus Torvalds return rc; 15091da177e4SLinus Torvalds } 15101da177e4SLinus Torvalds 15111da177e4SLinus Torvalds /** 15121da177e4SLinus Torvalds * security_netif_sid - Obtain the SID for a network interface. 15131da177e4SLinus Torvalds * @name: interface name 15141da177e4SLinus Torvalds * @if_sid: interface SID 15151da177e4SLinus Torvalds */ 1516e8bfdb9dSPaul Moore int security_netif_sid(char *name, u32 *if_sid) 15171da177e4SLinus Torvalds { 15181da177e4SLinus Torvalds int rc = 0; 15191da177e4SLinus Torvalds struct ocontext *c; 15201da177e4SLinus Torvalds 15211da177e4SLinus Torvalds POLICY_RDLOCK; 15221da177e4SLinus Torvalds 15231da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NETIF]; 15241da177e4SLinus Torvalds while (c) { 15251da177e4SLinus Torvalds if (strcmp(name, c->u.name) == 0) 15261da177e4SLinus Torvalds break; 15271da177e4SLinus Torvalds c = c->next; 15281da177e4SLinus Torvalds } 15291da177e4SLinus Torvalds 15301da177e4SLinus Torvalds if (c) { 15311da177e4SLinus Torvalds if (!c->sid[0] || !c->sid[1]) { 15321da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 15331da177e4SLinus Torvalds &c->context[0], 15341da177e4SLinus Torvalds &c->sid[0]); 15351da177e4SLinus Torvalds if (rc) 15361da177e4SLinus Torvalds goto out; 15371da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 15381da177e4SLinus Torvalds &c->context[1], 15391da177e4SLinus Torvalds &c->sid[1]); 15401da177e4SLinus Torvalds if (rc) 15411da177e4SLinus Torvalds goto out; 15421da177e4SLinus Torvalds } 15431da177e4SLinus Torvalds *if_sid = c->sid[0]; 1544e8bfdb9dSPaul Moore } else 15451da177e4SLinus Torvalds *if_sid = SECINITSID_NETIF; 15461da177e4SLinus Torvalds 15471da177e4SLinus Torvalds out: 15481da177e4SLinus Torvalds POLICY_RDUNLOCK; 15491da177e4SLinus Torvalds return rc; 15501da177e4SLinus Torvalds } 15511da177e4SLinus Torvalds 15521da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) 15531da177e4SLinus Torvalds { 15541da177e4SLinus Torvalds int i, fail = 0; 15551da177e4SLinus Torvalds 15561da177e4SLinus Torvalds for (i = 0; i < 4; i++) 15571da177e4SLinus Torvalds if (addr[i] != (input[i] & mask[i])) { 15581da177e4SLinus Torvalds fail = 1; 15591da177e4SLinus Torvalds break; 15601da177e4SLinus Torvalds } 15611da177e4SLinus Torvalds 15621da177e4SLinus Torvalds return !fail; 15631da177e4SLinus Torvalds } 15641da177e4SLinus Torvalds 15651da177e4SLinus Torvalds /** 15661da177e4SLinus Torvalds * security_node_sid - Obtain the SID for a node (host). 15671da177e4SLinus Torvalds * @domain: communication domain aka address family 15681da177e4SLinus Torvalds * @addrp: address 15691da177e4SLinus Torvalds * @addrlen: address length in bytes 15701da177e4SLinus Torvalds * @out_sid: security identifier 15711da177e4SLinus Torvalds */ 15721da177e4SLinus Torvalds int security_node_sid(u16 domain, 15731da177e4SLinus Torvalds void *addrp, 15741da177e4SLinus Torvalds u32 addrlen, 15751da177e4SLinus Torvalds u32 *out_sid) 15761da177e4SLinus Torvalds { 15771da177e4SLinus Torvalds int rc = 0; 15781da177e4SLinus Torvalds struct ocontext *c; 15791da177e4SLinus Torvalds 15801da177e4SLinus Torvalds POLICY_RDLOCK; 15811da177e4SLinus Torvalds 15821da177e4SLinus Torvalds switch (domain) { 15831da177e4SLinus Torvalds case AF_INET: { 15841da177e4SLinus Torvalds u32 addr; 15851da177e4SLinus Torvalds 15861da177e4SLinus Torvalds if (addrlen != sizeof(u32)) { 15871da177e4SLinus Torvalds rc = -EINVAL; 15881da177e4SLinus Torvalds goto out; 15891da177e4SLinus Torvalds } 15901da177e4SLinus Torvalds 15911da177e4SLinus Torvalds addr = *((u32 *)addrp); 15921da177e4SLinus Torvalds 15931da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NODE]; 15941da177e4SLinus Torvalds while (c) { 15951da177e4SLinus Torvalds if (c->u.node.addr == (addr & c->u.node.mask)) 15961da177e4SLinus Torvalds break; 15971da177e4SLinus Torvalds c = c->next; 15981da177e4SLinus Torvalds } 15991da177e4SLinus Torvalds break; 16001da177e4SLinus Torvalds } 16011da177e4SLinus Torvalds 16021da177e4SLinus Torvalds case AF_INET6: 16031da177e4SLinus Torvalds if (addrlen != sizeof(u64) * 2) { 16041da177e4SLinus Torvalds rc = -EINVAL; 16051da177e4SLinus Torvalds goto out; 16061da177e4SLinus Torvalds } 16071da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NODE6]; 16081da177e4SLinus Torvalds while (c) { 16091da177e4SLinus Torvalds if (match_ipv6_addrmask(addrp, c->u.node6.addr, 16101da177e4SLinus Torvalds c->u.node6.mask)) 16111da177e4SLinus Torvalds break; 16121da177e4SLinus Torvalds c = c->next; 16131da177e4SLinus Torvalds } 16141da177e4SLinus Torvalds break; 16151da177e4SLinus Torvalds 16161da177e4SLinus Torvalds default: 16171da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 16181da177e4SLinus Torvalds goto out; 16191da177e4SLinus Torvalds } 16201da177e4SLinus Torvalds 16211da177e4SLinus Torvalds if (c) { 16221da177e4SLinus Torvalds if (!c->sid[0]) { 16231da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 16241da177e4SLinus Torvalds &c->context[0], 16251da177e4SLinus Torvalds &c->sid[0]); 16261da177e4SLinus Torvalds if (rc) 16271da177e4SLinus Torvalds goto out; 16281da177e4SLinus Torvalds } 16291da177e4SLinus Torvalds *out_sid = c->sid[0]; 16301da177e4SLinus Torvalds } else { 16311da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 16321da177e4SLinus Torvalds } 16331da177e4SLinus Torvalds 16341da177e4SLinus Torvalds out: 16351da177e4SLinus Torvalds POLICY_RDUNLOCK; 16361da177e4SLinus Torvalds return rc; 16371da177e4SLinus Torvalds } 16381da177e4SLinus Torvalds 16391da177e4SLinus Torvalds #define SIDS_NEL 25 16401da177e4SLinus Torvalds 16411da177e4SLinus Torvalds /** 16421da177e4SLinus Torvalds * security_get_user_sids - Obtain reachable SIDs for a user. 16431da177e4SLinus Torvalds * @fromsid: starting SID 16441da177e4SLinus Torvalds * @username: username 16451da177e4SLinus Torvalds * @sids: array of reachable SIDs for user 16461da177e4SLinus Torvalds * @nel: number of elements in @sids 16471da177e4SLinus Torvalds * 16481da177e4SLinus Torvalds * Generate the set of SIDs for legal security contexts 16491da177e4SLinus Torvalds * for a given user that can be reached by @fromsid. 16501da177e4SLinus Torvalds * Set *@sids to point to a dynamically allocated 16511da177e4SLinus Torvalds * array containing the set of SIDs. Set *@nel to the 16521da177e4SLinus Torvalds * number of elements in the array. 16531da177e4SLinus Torvalds */ 16541da177e4SLinus Torvalds 16551da177e4SLinus Torvalds int security_get_user_sids(u32 fromsid, 16561da177e4SLinus Torvalds char *username, 16571da177e4SLinus Torvalds u32 **sids, 16581da177e4SLinus Torvalds u32 *nel) 16591da177e4SLinus Torvalds { 16601da177e4SLinus Torvalds struct context *fromcon, usercon; 16612c3c05dbSStephen Smalley u32 *mysids = NULL, *mysids2, sid; 16621da177e4SLinus Torvalds u32 mynel = 0, maxnel = SIDS_NEL; 16631da177e4SLinus Torvalds struct user_datum *user; 16641da177e4SLinus Torvalds struct role_datum *role; 1665782ebb99SStephen Smalley struct ebitmap_node *rnode, *tnode; 16661da177e4SLinus Torvalds int rc = 0, i, j; 16671da177e4SLinus Torvalds 16681da177e4SLinus Torvalds *sids = NULL; 16691da177e4SLinus Torvalds *nel = 0; 16702c3c05dbSStephen Smalley 16712c3c05dbSStephen Smalley if (!ss_initialized) 16721da177e4SLinus Torvalds goto out; 16731da177e4SLinus Torvalds 16741da177e4SLinus Torvalds POLICY_RDLOCK; 16751da177e4SLinus Torvalds 16761da177e4SLinus Torvalds fromcon = sidtab_search(&sidtab, fromsid); 16771da177e4SLinus Torvalds if (!fromcon) { 16781da177e4SLinus Torvalds rc = -EINVAL; 16791da177e4SLinus Torvalds goto out_unlock; 16801da177e4SLinus Torvalds } 16811da177e4SLinus Torvalds 16821da177e4SLinus Torvalds user = hashtab_search(policydb.p_users.table, username); 16831da177e4SLinus Torvalds if (!user) { 16841da177e4SLinus Torvalds rc = -EINVAL; 16851da177e4SLinus Torvalds goto out_unlock; 16861da177e4SLinus Torvalds } 16871da177e4SLinus Torvalds usercon.user = user->value; 16881da177e4SLinus Torvalds 168989d155efSJames Morris mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC); 16901da177e4SLinus Torvalds if (!mysids) { 16911da177e4SLinus Torvalds rc = -ENOMEM; 16921da177e4SLinus Torvalds goto out_unlock; 16931da177e4SLinus Torvalds } 16941da177e4SLinus Torvalds 16959fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&user->roles, rnode, i) { 16961da177e4SLinus Torvalds role = policydb.role_val_to_struct[i]; 16971da177e4SLinus Torvalds usercon.role = i+1; 16989fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&role->types, tnode, j) { 16991da177e4SLinus Torvalds usercon.type = j+1; 17001da177e4SLinus Torvalds 17011da177e4SLinus Torvalds if (mls_setup_user_range(fromcon, user, &usercon)) 17021da177e4SLinus Torvalds continue; 17031da177e4SLinus Torvalds 17041da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); 17052c3c05dbSStephen Smalley if (rc) 17061da177e4SLinus Torvalds goto out_unlock; 17071da177e4SLinus Torvalds if (mynel < maxnel) { 17081da177e4SLinus Torvalds mysids[mynel++] = sid; 17091da177e4SLinus Torvalds } else { 17101da177e4SLinus Torvalds maxnel += SIDS_NEL; 171189d155efSJames Morris mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); 17121da177e4SLinus Torvalds if (!mysids2) { 17131da177e4SLinus Torvalds rc = -ENOMEM; 17141da177e4SLinus Torvalds goto out_unlock; 17151da177e4SLinus Torvalds } 17161da177e4SLinus Torvalds memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); 17171da177e4SLinus Torvalds kfree(mysids); 17181da177e4SLinus Torvalds mysids = mysids2; 17191da177e4SLinus Torvalds mysids[mynel++] = sid; 17201da177e4SLinus Torvalds } 17211da177e4SLinus Torvalds } 17221da177e4SLinus Torvalds } 17231da177e4SLinus Torvalds 17241da177e4SLinus Torvalds out_unlock: 17251da177e4SLinus Torvalds POLICY_RDUNLOCK; 17262c3c05dbSStephen Smalley if (rc || !mynel) { 17272c3c05dbSStephen Smalley kfree(mysids); 17282c3c05dbSStephen Smalley goto out; 17292c3c05dbSStephen Smalley } 17302c3c05dbSStephen Smalley 17312c3c05dbSStephen Smalley mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL); 17322c3c05dbSStephen Smalley if (!mysids2) { 17332c3c05dbSStephen Smalley rc = -ENOMEM; 17342c3c05dbSStephen Smalley kfree(mysids); 17352c3c05dbSStephen Smalley goto out; 17362c3c05dbSStephen Smalley } 17372c3c05dbSStephen Smalley for (i = 0, j = 0; i < mynel; i++) { 17382c3c05dbSStephen Smalley rc = avc_has_perm_noaudit(fromsid, mysids[i], 17392c3c05dbSStephen Smalley SECCLASS_PROCESS, 17402c3c05dbSStephen Smalley PROCESS__TRANSITION, AVC_STRICT, 17412c3c05dbSStephen Smalley NULL); 17422c3c05dbSStephen Smalley if (!rc) 17432c3c05dbSStephen Smalley mysids2[j++] = mysids[i]; 17442c3c05dbSStephen Smalley cond_resched(); 17452c3c05dbSStephen Smalley } 17462c3c05dbSStephen Smalley rc = 0; 17472c3c05dbSStephen Smalley kfree(mysids); 17482c3c05dbSStephen Smalley *sids = mysids2; 17492c3c05dbSStephen Smalley *nel = j; 17501da177e4SLinus Torvalds out: 17511da177e4SLinus Torvalds return rc; 17521da177e4SLinus Torvalds } 17531da177e4SLinus Torvalds 17541da177e4SLinus Torvalds /** 17551da177e4SLinus Torvalds * security_genfs_sid - Obtain a SID for a file in a filesystem 17561da177e4SLinus Torvalds * @fstype: filesystem type 17571da177e4SLinus Torvalds * @path: path from root of mount 17581da177e4SLinus Torvalds * @sclass: file security class 17591da177e4SLinus Torvalds * @sid: SID for path 17601da177e4SLinus Torvalds * 17611da177e4SLinus Torvalds * Obtain a SID to use for a file in a filesystem that 17621da177e4SLinus Torvalds * cannot support xattr or use a fixed labeling behavior like 17631da177e4SLinus Torvalds * transition SIDs or task SIDs. 17641da177e4SLinus Torvalds */ 17651da177e4SLinus Torvalds int security_genfs_sid(const char *fstype, 17661da177e4SLinus Torvalds char *path, 17671da177e4SLinus Torvalds u16 sclass, 17681da177e4SLinus Torvalds u32 *sid) 17691da177e4SLinus Torvalds { 17701da177e4SLinus Torvalds int len; 17711da177e4SLinus Torvalds struct genfs *genfs; 17721da177e4SLinus Torvalds struct ocontext *c; 17731da177e4SLinus Torvalds int rc = 0, cmp = 0; 17741da177e4SLinus Torvalds 1775b1aa5301SStephen Smalley while (path[0] == '/' && path[1] == '/') 1776b1aa5301SStephen Smalley path++; 1777b1aa5301SStephen Smalley 17781da177e4SLinus Torvalds POLICY_RDLOCK; 17791da177e4SLinus Torvalds 17801da177e4SLinus Torvalds for (genfs = policydb.genfs; genfs; genfs = genfs->next) { 17811da177e4SLinus Torvalds cmp = strcmp(fstype, genfs->fstype); 17821da177e4SLinus Torvalds if (cmp <= 0) 17831da177e4SLinus Torvalds break; 17841da177e4SLinus Torvalds } 17851da177e4SLinus Torvalds 17861da177e4SLinus Torvalds if (!genfs || cmp) { 17871da177e4SLinus Torvalds *sid = SECINITSID_UNLABELED; 17881da177e4SLinus Torvalds rc = -ENOENT; 17891da177e4SLinus Torvalds goto out; 17901da177e4SLinus Torvalds } 17911da177e4SLinus Torvalds 17921da177e4SLinus Torvalds for (c = genfs->head; c; c = c->next) { 17931da177e4SLinus Torvalds len = strlen(c->u.name); 17941da177e4SLinus Torvalds if ((!c->v.sclass || sclass == c->v.sclass) && 17951da177e4SLinus Torvalds (strncmp(c->u.name, path, len) == 0)) 17961da177e4SLinus Torvalds break; 17971da177e4SLinus Torvalds } 17981da177e4SLinus Torvalds 17991da177e4SLinus Torvalds if (!c) { 18001da177e4SLinus Torvalds *sid = SECINITSID_UNLABELED; 18011da177e4SLinus Torvalds rc = -ENOENT; 18021da177e4SLinus Torvalds goto out; 18031da177e4SLinus Torvalds } 18041da177e4SLinus Torvalds 18051da177e4SLinus Torvalds if (!c->sid[0]) { 18061da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 18071da177e4SLinus Torvalds &c->context[0], 18081da177e4SLinus Torvalds &c->sid[0]); 18091da177e4SLinus Torvalds if (rc) 18101da177e4SLinus Torvalds goto out; 18111da177e4SLinus Torvalds } 18121da177e4SLinus Torvalds 18131da177e4SLinus Torvalds *sid = c->sid[0]; 18141da177e4SLinus Torvalds out: 18151da177e4SLinus Torvalds POLICY_RDUNLOCK; 18161da177e4SLinus Torvalds return rc; 18171da177e4SLinus Torvalds } 18181da177e4SLinus Torvalds 18191da177e4SLinus Torvalds /** 18201da177e4SLinus Torvalds * security_fs_use - Determine how to handle labeling for a filesystem. 18211da177e4SLinus Torvalds * @fstype: filesystem type 18221da177e4SLinus Torvalds * @behavior: labeling behavior 18231da177e4SLinus Torvalds * @sid: SID for filesystem (superblock) 18241da177e4SLinus Torvalds */ 18251da177e4SLinus Torvalds int security_fs_use( 18261da177e4SLinus Torvalds const char *fstype, 18271da177e4SLinus Torvalds unsigned int *behavior, 18281da177e4SLinus Torvalds u32 *sid) 18291da177e4SLinus Torvalds { 18301da177e4SLinus Torvalds int rc = 0; 18311da177e4SLinus Torvalds struct ocontext *c; 18321da177e4SLinus Torvalds 18331da177e4SLinus Torvalds POLICY_RDLOCK; 18341da177e4SLinus Torvalds 18351da177e4SLinus Torvalds c = policydb.ocontexts[OCON_FSUSE]; 18361da177e4SLinus Torvalds while (c) { 18371da177e4SLinus Torvalds if (strcmp(fstype, c->u.name) == 0) 18381da177e4SLinus Torvalds break; 18391da177e4SLinus Torvalds c = c->next; 18401da177e4SLinus Torvalds } 18411da177e4SLinus Torvalds 18421da177e4SLinus Torvalds if (c) { 18431da177e4SLinus Torvalds *behavior = c->v.behavior; 18441da177e4SLinus Torvalds if (!c->sid[0]) { 18451da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 18461da177e4SLinus Torvalds &c->context[0], 18471da177e4SLinus Torvalds &c->sid[0]); 18481da177e4SLinus Torvalds if (rc) 18491da177e4SLinus Torvalds goto out; 18501da177e4SLinus Torvalds } 18511da177e4SLinus Torvalds *sid = c->sid[0]; 18521da177e4SLinus Torvalds } else { 18531da177e4SLinus Torvalds rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); 18541da177e4SLinus Torvalds if (rc) { 18551da177e4SLinus Torvalds *behavior = SECURITY_FS_USE_NONE; 18561da177e4SLinus Torvalds rc = 0; 18571da177e4SLinus Torvalds } else { 18581da177e4SLinus Torvalds *behavior = SECURITY_FS_USE_GENFS; 18591da177e4SLinus Torvalds } 18601da177e4SLinus Torvalds } 18611da177e4SLinus Torvalds 18621da177e4SLinus Torvalds out: 18631da177e4SLinus Torvalds POLICY_RDUNLOCK; 18641da177e4SLinus Torvalds return rc; 18651da177e4SLinus Torvalds } 18661da177e4SLinus Torvalds 18671da177e4SLinus Torvalds int security_get_bools(int *len, char ***names, int **values) 18681da177e4SLinus Torvalds { 18691da177e4SLinus Torvalds int i, rc = -ENOMEM; 18701da177e4SLinus Torvalds 18711da177e4SLinus Torvalds POLICY_RDLOCK; 18721da177e4SLinus Torvalds *names = NULL; 18731da177e4SLinus Torvalds *values = NULL; 18741da177e4SLinus Torvalds 18751da177e4SLinus Torvalds *len = policydb.p_bools.nprim; 18761da177e4SLinus Torvalds if (!*len) { 18771da177e4SLinus Torvalds rc = 0; 18781da177e4SLinus Torvalds goto out; 18791da177e4SLinus Torvalds } 18801da177e4SLinus Torvalds 1881e0795cf4SJesper Juhl *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC); 18821da177e4SLinus Torvalds if (!*names) 18831da177e4SLinus Torvalds goto err; 18841da177e4SLinus Torvalds 1885e0795cf4SJesper Juhl *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); 18861da177e4SLinus Torvalds if (!*values) 18871da177e4SLinus Torvalds goto err; 18881da177e4SLinus Torvalds 18891da177e4SLinus Torvalds for (i = 0; i < *len; i++) { 18901da177e4SLinus Torvalds size_t name_len; 18911da177e4SLinus Torvalds (*values)[i] = policydb.bool_val_to_struct[i]->state; 18921da177e4SLinus Torvalds name_len = strlen(policydb.p_bool_val_to_name[i]) + 1; 1893e0795cf4SJesper Juhl (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC); 18941da177e4SLinus Torvalds if (!(*names)[i]) 18951da177e4SLinus Torvalds goto err; 18961da177e4SLinus Torvalds strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len); 18971da177e4SLinus Torvalds (*names)[i][name_len - 1] = 0; 18981da177e4SLinus Torvalds } 18991da177e4SLinus Torvalds rc = 0; 19001da177e4SLinus Torvalds out: 19011da177e4SLinus Torvalds POLICY_RDUNLOCK; 19021da177e4SLinus Torvalds return rc; 19031da177e4SLinus Torvalds err: 19041da177e4SLinus Torvalds if (*names) { 19051da177e4SLinus Torvalds for (i = 0; i < *len; i++) 19061da177e4SLinus Torvalds kfree((*names)[i]); 19071da177e4SLinus Torvalds } 19081da177e4SLinus Torvalds kfree(*values); 19091da177e4SLinus Torvalds goto out; 19101da177e4SLinus Torvalds } 19111da177e4SLinus Torvalds 19121da177e4SLinus Torvalds 19131da177e4SLinus Torvalds int security_set_bools(int len, int *values) 19141da177e4SLinus Torvalds { 19151da177e4SLinus Torvalds int i, rc = 0; 19161da177e4SLinus Torvalds int lenp, seqno = 0; 19171da177e4SLinus Torvalds struct cond_node *cur; 19181da177e4SLinus Torvalds 19191da177e4SLinus Torvalds POLICY_WRLOCK; 19201da177e4SLinus Torvalds 19211da177e4SLinus Torvalds lenp = policydb.p_bools.nprim; 19221da177e4SLinus Torvalds if (len != lenp) { 19231da177e4SLinus Torvalds rc = -EFAULT; 19241da177e4SLinus Torvalds goto out; 19251da177e4SLinus Torvalds } 19261da177e4SLinus Torvalds 19271da177e4SLinus Torvalds for (i = 0; i < len; i++) { 1928af601e46SSteve Grubb if (!!values[i] != policydb.bool_val_to_struct[i]->state) { 1929af601e46SSteve Grubb audit_log(current->audit_context, GFP_ATOMIC, 1930af601e46SSteve Grubb AUDIT_MAC_CONFIG_CHANGE, 19314746ec5bSEric Paris "bool=%s val=%d old_val=%d auid=%u ses=%u", 1932af601e46SSteve Grubb policydb.p_bool_val_to_name[i], 1933af601e46SSteve Grubb !!values[i], 1934af601e46SSteve Grubb policydb.bool_val_to_struct[i]->state, 19354746ec5bSEric Paris audit_get_loginuid(current), 19364746ec5bSEric Paris audit_get_sessionid(current)); 1937af601e46SSteve Grubb } 19385d55a345SEric Paris if (values[i]) 19391da177e4SLinus Torvalds policydb.bool_val_to_struct[i]->state = 1; 19405d55a345SEric Paris else 19411da177e4SLinus Torvalds policydb.bool_val_to_struct[i]->state = 0; 19421da177e4SLinus Torvalds } 19431da177e4SLinus Torvalds 19441da177e4SLinus Torvalds for (cur = policydb.cond_list; cur != NULL; cur = cur->next) { 19451da177e4SLinus Torvalds rc = evaluate_cond_node(&policydb, cur); 19461da177e4SLinus Torvalds if (rc) 19471da177e4SLinus Torvalds goto out; 19481da177e4SLinus Torvalds } 19491da177e4SLinus Torvalds 19501da177e4SLinus Torvalds seqno = ++latest_granting; 19511da177e4SLinus Torvalds 19521da177e4SLinus Torvalds out: 19531da177e4SLinus Torvalds POLICY_WRUNLOCK; 19541da177e4SLinus Torvalds if (!rc) { 19551da177e4SLinus Torvalds avc_ss_reset(seqno); 19561da177e4SLinus Torvalds selnl_notify_policyload(seqno); 1957342a0cffSVenkat Yekkirala selinux_xfrm_notify_policyload(); 19581da177e4SLinus Torvalds } 19591da177e4SLinus Torvalds return rc; 19601da177e4SLinus Torvalds } 19611da177e4SLinus Torvalds 19621da177e4SLinus Torvalds int security_get_bool_value(int bool) 19631da177e4SLinus Torvalds { 19641da177e4SLinus Torvalds int rc = 0; 19651da177e4SLinus Torvalds int len; 19661da177e4SLinus Torvalds 19671da177e4SLinus Torvalds POLICY_RDLOCK; 19681da177e4SLinus Torvalds 19691da177e4SLinus Torvalds len = policydb.p_bools.nprim; 19701da177e4SLinus Torvalds if (bool >= len) { 19711da177e4SLinus Torvalds rc = -EFAULT; 19721da177e4SLinus Torvalds goto out; 19731da177e4SLinus Torvalds } 19741da177e4SLinus Torvalds 19751da177e4SLinus Torvalds rc = policydb.bool_val_to_struct[bool]->state; 19761da177e4SLinus Torvalds out: 19771da177e4SLinus Torvalds POLICY_RDUNLOCK; 19781da177e4SLinus Torvalds return rc; 19791da177e4SLinus Torvalds } 1980376bd9cbSDarrel Goeddel 1981e900a7d9SStephen Smalley static int security_preserve_bools(struct policydb *p) 1982e900a7d9SStephen Smalley { 1983e900a7d9SStephen Smalley int rc, nbools = 0, *bvalues = NULL, i; 1984e900a7d9SStephen Smalley char **bnames = NULL; 1985e900a7d9SStephen Smalley struct cond_bool_datum *booldatum; 1986e900a7d9SStephen Smalley struct cond_node *cur; 1987e900a7d9SStephen Smalley 1988e900a7d9SStephen Smalley rc = security_get_bools(&nbools, &bnames, &bvalues); 1989e900a7d9SStephen Smalley if (rc) 1990e900a7d9SStephen Smalley goto out; 1991e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) { 1992e900a7d9SStephen Smalley booldatum = hashtab_search(p->p_bools.table, bnames[i]); 1993e900a7d9SStephen Smalley if (booldatum) 1994e900a7d9SStephen Smalley booldatum->state = bvalues[i]; 1995e900a7d9SStephen Smalley } 1996e900a7d9SStephen Smalley for (cur = p->cond_list; cur != NULL; cur = cur->next) { 1997e900a7d9SStephen Smalley rc = evaluate_cond_node(p, cur); 1998e900a7d9SStephen Smalley if (rc) 1999e900a7d9SStephen Smalley goto out; 2000e900a7d9SStephen Smalley } 2001e900a7d9SStephen Smalley 2002e900a7d9SStephen Smalley out: 2003e900a7d9SStephen Smalley if (bnames) { 2004e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) 2005e900a7d9SStephen Smalley kfree(bnames[i]); 2006e900a7d9SStephen Smalley } 2007e900a7d9SStephen Smalley kfree(bnames); 2008e900a7d9SStephen Smalley kfree(bvalues); 2009e900a7d9SStephen Smalley return rc; 2010e900a7d9SStephen Smalley } 2011e900a7d9SStephen Smalley 201208554d6bSVenkat Yekkirala /* 201308554d6bSVenkat Yekkirala * security_sid_mls_copy() - computes a new sid based on the given 201408554d6bSVenkat Yekkirala * sid and the mls portion of mls_sid. 201508554d6bSVenkat Yekkirala */ 201608554d6bSVenkat Yekkirala int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid) 201708554d6bSVenkat Yekkirala { 201808554d6bSVenkat Yekkirala struct context *context1; 201908554d6bSVenkat Yekkirala struct context *context2; 202008554d6bSVenkat Yekkirala struct context newcon; 202108554d6bSVenkat Yekkirala char *s; 202208554d6bSVenkat Yekkirala u32 len; 202308554d6bSVenkat Yekkirala int rc = 0; 202408554d6bSVenkat Yekkirala 20254eb327b5SVenkat Yekkirala if (!ss_initialized || !selinux_mls_enabled) { 202608554d6bSVenkat Yekkirala *new_sid = sid; 202708554d6bSVenkat Yekkirala goto out; 202808554d6bSVenkat Yekkirala } 202908554d6bSVenkat Yekkirala 203008554d6bSVenkat Yekkirala context_init(&newcon); 203108554d6bSVenkat Yekkirala 203208554d6bSVenkat Yekkirala POLICY_RDLOCK; 203308554d6bSVenkat Yekkirala context1 = sidtab_search(&sidtab, sid); 203408554d6bSVenkat Yekkirala if (!context1) { 2035744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2036744ba35eSEric Paris __func__, sid); 203708554d6bSVenkat Yekkirala rc = -EINVAL; 203808554d6bSVenkat Yekkirala goto out_unlock; 203908554d6bSVenkat Yekkirala } 204008554d6bSVenkat Yekkirala 204108554d6bSVenkat Yekkirala context2 = sidtab_search(&sidtab, mls_sid); 204208554d6bSVenkat Yekkirala if (!context2) { 2043744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2044744ba35eSEric Paris __func__, mls_sid); 204508554d6bSVenkat Yekkirala rc = -EINVAL; 204608554d6bSVenkat Yekkirala goto out_unlock; 204708554d6bSVenkat Yekkirala } 204808554d6bSVenkat Yekkirala 204908554d6bSVenkat Yekkirala newcon.user = context1->user; 205008554d6bSVenkat Yekkirala newcon.role = context1->role; 205108554d6bSVenkat Yekkirala newcon.type = context1->type; 20520efc61eaSVenkat Yekkirala rc = mls_context_cpy(&newcon, context2); 205308554d6bSVenkat Yekkirala if (rc) 205408554d6bSVenkat Yekkirala goto out_unlock; 205508554d6bSVenkat Yekkirala 205608554d6bSVenkat Yekkirala /* Check the validity of the new context. */ 205708554d6bSVenkat Yekkirala if (!policydb_context_isvalid(&policydb, &newcon)) { 205808554d6bSVenkat Yekkirala rc = convert_context_handle_invalid_context(&newcon); 205908554d6bSVenkat Yekkirala if (rc) 206008554d6bSVenkat Yekkirala goto bad; 206108554d6bSVenkat Yekkirala } 206208554d6bSVenkat Yekkirala 206308554d6bSVenkat Yekkirala rc = sidtab_context_to_sid(&sidtab, &newcon, new_sid); 206408554d6bSVenkat Yekkirala goto out_unlock; 206508554d6bSVenkat Yekkirala 206608554d6bSVenkat Yekkirala bad: 206708554d6bSVenkat Yekkirala if (!context_struct_to_string(&newcon, &s, &len)) { 206808554d6bSVenkat Yekkirala audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 206908554d6bSVenkat Yekkirala "security_sid_mls_copy: invalid context %s", s); 207008554d6bSVenkat Yekkirala kfree(s); 207108554d6bSVenkat Yekkirala } 207208554d6bSVenkat Yekkirala 207308554d6bSVenkat Yekkirala out_unlock: 207408554d6bSVenkat Yekkirala POLICY_RDUNLOCK; 207508554d6bSVenkat Yekkirala context_destroy(&newcon); 207608554d6bSVenkat Yekkirala out: 207708554d6bSVenkat Yekkirala return rc; 207808554d6bSVenkat Yekkirala } 207908554d6bSVenkat Yekkirala 2080220deb96SPaul Moore /** 2081220deb96SPaul Moore * security_net_peersid_resolve - Compare and resolve two network peer SIDs 2082220deb96SPaul Moore * @nlbl_sid: NetLabel SID 2083220deb96SPaul Moore * @nlbl_type: NetLabel labeling protocol type 2084220deb96SPaul Moore * @xfrm_sid: XFRM SID 2085220deb96SPaul Moore * 2086220deb96SPaul Moore * Description: 2087220deb96SPaul Moore * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be 2088220deb96SPaul Moore * resolved into a single SID it is returned via @peer_sid and the function 2089220deb96SPaul Moore * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function 2090220deb96SPaul Moore * returns a negative value. A table summarizing the behavior is below: 2091220deb96SPaul Moore * 2092220deb96SPaul Moore * | function return | @sid 2093220deb96SPaul Moore * ------------------------------+-----------------+----------------- 2094220deb96SPaul Moore * no peer labels | 0 | SECSID_NULL 2095220deb96SPaul Moore * single peer label | 0 | <peer_label> 2096220deb96SPaul Moore * multiple, consistent labels | 0 | <peer_label> 2097220deb96SPaul Moore * multiple, inconsistent labels | -<errno> | SECSID_NULL 2098220deb96SPaul Moore * 2099220deb96SPaul Moore */ 2100220deb96SPaul Moore int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type, 2101220deb96SPaul Moore u32 xfrm_sid, 2102220deb96SPaul Moore u32 *peer_sid) 2103220deb96SPaul Moore { 2104220deb96SPaul Moore int rc; 2105220deb96SPaul Moore struct context *nlbl_ctx; 2106220deb96SPaul Moore struct context *xfrm_ctx; 2107220deb96SPaul Moore 2108220deb96SPaul Moore /* handle the common (which also happens to be the set of easy) cases 2109220deb96SPaul Moore * right away, these two if statements catch everything involving a 2110220deb96SPaul Moore * single or absent peer SID/label */ 2111220deb96SPaul Moore if (xfrm_sid == SECSID_NULL) { 2112220deb96SPaul Moore *peer_sid = nlbl_sid; 2113220deb96SPaul Moore return 0; 2114220deb96SPaul Moore } 2115220deb96SPaul Moore /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label 2116220deb96SPaul Moore * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label 2117220deb96SPaul Moore * is present */ 2118220deb96SPaul Moore if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) { 2119220deb96SPaul Moore *peer_sid = xfrm_sid; 2120220deb96SPaul Moore return 0; 2121220deb96SPaul Moore } 2122220deb96SPaul Moore 2123220deb96SPaul Moore /* we don't need to check ss_initialized here since the only way both 2124220deb96SPaul Moore * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the 2125220deb96SPaul Moore * security server was initialized and ss_initialized was true */ 2126220deb96SPaul Moore if (!selinux_mls_enabled) { 2127220deb96SPaul Moore *peer_sid = SECSID_NULL; 2128220deb96SPaul Moore return 0; 2129220deb96SPaul Moore } 2130220deb96SPaul Moore 2131220deb96SPaul Moore POLICY_RDLOCK; 2132220deb96SPaul Moore 2133220deb96SPaul Moore nlbl_ctx = sidtab_search(&sidtab, nlbl_sid); 2134220deb96SPaul Moore if (!nlbl_ctx) { 2135744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2136744ba35eSEric Paris __func__, nlbl_sid); 2137220deb96SPaul Moore rc = -EINVAL; 2138220deb96SPaul Moore goto out_slowpath; 2139220deb96SPaul Moore } 2140220deb96SPaul Moore xfrm_ctx = sidtab_search(&sidtab, xfrm_sid); 2141220deb96SPaul Moore if (!xfrm_ctx) { 2142744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", 2143744ba35eSEric Paris __func__, xfrm_sid); 2144220deb96SPaul Moore rc = -EINVAL; 2145220deb96SPaul Moore goto out_slowpath; 2146220deb96SPaul Moore } 2147220deb96SPaul Moore rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES); 2148220deb96SPaul Moore 2149220deb96SPaul Moore out_slowpath: 2150220deb96SPaul Moore POLICY_RDUNLOCK; 2151220deb96SPaul Moore if (rc == 0) 2152220deb96SPaul Moore /* at present NetLabel SIDs/labels really only carry MLS 2153220deb96SPaul Moore * information so if the MLS portion of the NetLabel SID 2154220deb96SPaul Moore * matches the MLS portion of the labeled XFRM SID/label 2155220deb96SPaul Moore * then pass along the XFRM SID as it is the most 2156220deb96SPaul Moore * expressive */ 2157220deb96SPaul Moore *peer_sid = xfrm_sid; 2158220deb96SPaul Moore else 2159220deb96SPaul Moore *peer_sid = SECSID_NULL; 2160220deb96SPaul Moore return rc; 2161220deb96SPaul Moore } 2162220deb96SPaul Moore 216355fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args) 216455fcf09bSChristopher J. PeBenito { 216555fcf09bSChristopher J. PeBenito struct class_datum *datum = d; 216655fcf09bSChristopher J. PeBenito char *name = k, **classes = args; 216755fcf09bSChristopher J. PeBenito int value = datum->value - 1; 216855fcf09bSChristopher J. PeBenito 216955fcf09bSChristopher J. PeBenito classes[value] = kstrdup(name, GFP_ATOMIC); 217055fcf09bSChristopher J. PeBenito if (!classes[value]) 217155fcf09bSChristopher J. PeBenito return -ENOMEM; 217255fcf09bSChristopher J. PeBenito 217355fcf09bSChristopher J. PeBenito return 0; 217455fcf09bSChristopher J. PeBenito } 217555fcf09bSChristopher J. PeBenito 217655fcf09bSChristopher J. PeBenito int security_get_classes(char ***classes, int *nclasses) 217755fcf09bSChristopher J. PeBenito { 217855fcf09bSChristopher J. PeBenito int rc = -ENOMEM; 217955fcf09bSChristopher J. PeBenito 218055fcf09bSChristopher J. PeBenito POLICY_RDLOCK; 218155fcf09bSChristopher J. PeBenito 218255fcf09bSChristopher J. PeBenito *nclasses = policydb.p_classes.nprim; 218355fcf09bSChristopher J. PeBenito *classes = kcalloc(*nclasses, sizeof(*classes), GFP_ATOMIC); 218455fcf09bSChristopher J. PeBenito if (!*classes) 218555fcf09bSChristopher J. PeBenito goto out; 218655fcf09bSChristopher J. PeBenito 218755fcf09bSChristopher J. PeBenito rc = hashtab_map(policydb.p_classes.table, get_classes_callback, 218855fcf09bSChristopher J. PeBenito *classes); 218955fcf09bSChristopher J. PeBenito if (rc < 0) { 219055fcf09bSChristopher J. PeBenito int i; 219155fcf09bSChristopher J. PeBenito for (i = 0; i < *nclasses; i++) 219255fcf09bSChristopher J. PeBenito kfree((*classes)[i]); 219355fcf09bSChristopher J. PeBenito kfree(*classes); 219455fcf09bSChristopher J. PeBenito } 219555fcf09bSChristopher J. PeBenito 219655fcf09bSChristopher J. PeBenito out: 219755fcf09bSChristopher J. PeBenito POLICY_RDUNLOCK; 219855fcf09bSChristopher J. PeBenito return rc; 219955fcf09bSChristopher J. PeBenito } 220055fcf09bSChristopher J. PeBenito 220155fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args) 220255fcf09bSChristopher J. PeBenito { 220355fcf09bSChristopher J. PeBenito struct perm_datum *datum = d; 220455fcf09bSChristopher J. PeBenito char *name = k, **perms = args; 220555fcf09bSChristopher J. PeBenito int value = datum->value - 1; 220655fcf09bSChristopher J. PeBenito 220755fcf09bSChristopher J. PeBenito perms[value] = kstrdup(name, GFP_ATOMIC); 220855fcf09bSChristopher J. PeBenito if (!perms[value]) 220955fcf09bSChristopher J. PeBenito return -ENOMEM; 221055fcf09bSChristopher J. PeBenito 221155fcf09bSChristopher J. PeBenito return 0; 221255fcf09bSChristopher J. PeBenito } 221355fcf09bSChristopher J. PeBenito 221455fcf09bSChristopher J. PeBenito int security_get_permissions(char *class, char ***perms, int *nperms) 221555fcf09bSChristopher J. PeBenito { 221655fcf09bSChristopher J. PeBenito int rc = -ENOMEM, i; 221755fcf09bSChristopher J. PeBenito struct class_datum *match; 221855fcf09bSChristopher J. PeBenito 221955fcf09bSChristopher J. PeBenito POLICY_RDLOCK; 222055fcf09bSChristopher J. PeBenito 222155fcf09bSChristopher J. PeBenito match = hashtab_search(policydb.p_classes.table, class); 222255fcf09bSChristopher J. PeBenito if (!match) { 2223744ba35eSEric Paris printk(KERN_ERR "SELinux: %s: unrecognized class %s\n", 2224dd6f953aSHarvey Harrison __func__, class); 222555fcf09bSChristopher J. PeBenito rc = -EINVAL; 222655fcf09bSChristopher J. PeBenito goto out; 222755fcf09bSChristopher J. PeBenito } 222855fcf09bSChristopher J. PeBenito 222955fcf09bSChristopher J. PeBenito *nperms = match->permissions.nprim; 223055fcf09bSChristopher J. PeBenito *perms = kcalloc(*nperms, sizeof(*perms), GFP_ATOMIC); 223155fcf09bSChristopher J. PeBenito if (!*perms) 223255fcf09bSChristopher J. PeBenito goto out; 223355fcf09bSChristopher J. PeBenito 223455fcf09bSChristopher J. PeBenito if (match->comdatum) { 223555fcf09bSChristopher J. PeBenito rc = hashtab_map(match->comdatum->permissions.table, 223655fcf09bSChristopher J. PeBenito get_permissions_callback, *perms); 223755fcf09bSChristopher J. PeBenito if (rc < 0) 223855fcf09bSChristopher J. PeBenito goto err; 223955fcf09bSChristopher J. PeBenito } 224055fcf09bSChristopher J. PeBenito 224155fcf09bSChristopher J. PeBenito rc = hashtab_map(match->permissions.table, get_permissions_callback, 224255fcf09bSChristopher J. PeBenito *perms); 224355fcf09bSChristopher J. PeBenito if (rc < 0) 224455fcf09bSChristopher J. PeBenito goto err; 224555fcf09bSChristopher J. PeBenito 224655fcf09bSChristopher J. PeBenito out: 224755fcf09bSChristopher J. PeBenito POLICY_RDUNLOCK; 224855fcf09bSChristopher J. PeBenito return rc; 224955fcf09bSChristopher J. PeBenito 225055fcf09bSChristopher J. PeBenito err: 225155fcf09bSChristopher J. PeBenito POLICY_RDUNLOCK; 225255fcf09bSChristopher J. PeBenito for (i = 0; i < *nperms; i++) 225355fcf09bSChristopher J. PeBenito kfree((*perms)[i]); 225455fcf09bSChristopher J. PeBenito kfree(*perms); 225555fcf09bSChristopher J. PeBenito return rc; 225655fcf09bSChristopher J. PeBenito } 225755fcf09bSChristopher J. PeBenito 22583f12070eSEric Paris int security_get_reject_unknown(void) 22593f12070eSEric Paris { 22603f12070eSEric Paris return policydb.reject_unknown; 22613f12070eSEric Paris } 22623f12070eSEric Paris 22633f12070eSEric Paris int security_get_allow_unknown(void) 22643f12070eSEric Paris { 22653f12070eSEric Paris return policydb.allow_unknown; 22663f12070eSEric Paris } 22673f12070eSEric Paris 22683bb56b25SPaul Moore /** 22693bb56b25SPaul Moore * security_policycap_supported - Check for a specific policy capability 22703bb56b25SPaul Moore * @req_cap: capability 22713bb56b25SPaul Moore * 22723bb56b25SPaul Moore * Description: 22733bb56b25SPaul Moore * This function queries the currently loaded policy to see if it supports the 22743bb56b25SPaul Moore * capability specified by @req_cap. Returns true (1) if the capability is 22753bb56b25SPaul Moore * supported, false (0) if it isn't supported. 22763bb56b25SPaul Moore * 22773bb56b25SPaul Moore */ 22783bb56b25SPaul Moore int security_policycap_supported(unsigned int req_cap) 22793bb56b25SPaul Moore { 22803bb56b25SPaul Moore int rc; 22813bb56b25SPaul Moore 22823bb56b25SPaul Moore POLICY_RDLOCK; 22833bb56b25SPaul Moore rc = ebitmap_get_bit(&policydb.policycaps, req_cap); 22843bb56b25SPaul Moore POLICY_RDUNLOCK; 22853bb56b25SPaul Moore 22863bb56b25SPaul Moore return rc; 22873bb56b25SPaul Moore } 22883bb56b25SPaul Moore 2289376bd9cbSDarrel Goeddel struct selinux_audit_rule { 2290376bd9cbSDarrel Goeddel u32 au_seqno; 2291376bd9cbSDarrel Goeddel struct context au_ctxt; 2292376bd9cbSDarrel Goeddel }; 2293376bd9cbSDarrel Goeddel 22949d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule) 2295376bd9cbSDarrel Goeddel { 22969d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule; 22979d57a7f9SAhmed S. Darwish 2298376bd9cbSDarrel Goeddel if (rule) { 2299376bd9cbSDarrel Goeddel context_destroy(&rule->au_ctxt); 2300376bd9cbSDarrel Goeddel kfree(rule); 2301376bd9cbSDarrel Goeddel } 2302376bd9cbSDarrel Goeddel } 2303376bd9cbSDarrel Goeddel 23049d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule) 2305376bd9cbSDarrel Goeddel { 2306376bd9cbSDarrel Goeddel struct selinux_audit_rule *tmprule; 2307376bd9cbSDarrel Goeddel struct role_datum *roledatum; 2308376bd9cbSDarrel Goeddel struct type_datum *typedatum; 2309376bd9cbSDarrel Goeddel struct user_datum *userdatum; 23109d57a7f9SAhmed S. Darwish struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule; 2311376bd9cbSDarrel Goeddel int rc = 0; 2312376bd9cbSDarrel Goeddel 2313376bd9cbSDarrel Goeddel *rule = NULL; 2314376bd9cbSDarrel Goeddel 2315376bd9cbSDarrel Goeddel if (!ss_initialized) 23163ad40d64SSteve G return -EOPNOTSUPP; 2317376bd9cbSDarrel Goeddel 2318376bd9cbSDarrel Goeddel switch (field) { 23193a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 23203a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 23213a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 23226e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 23236e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 23246e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 2325376bd9cbSDarrel Goeddel /* only 'equals' and 'not equals' fit user, role, and type */ 2326376bd9cbSDarrel Goeddel if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL) 2327376bd9cbSDarrel Goeddel return -EINVAL; 2328376bd9cbSDarrel Goeddel break; 23293a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 23303a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 23316e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 23326e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 2333376bd9cbSDarrel Goeddel /* we do not allow a range, indicated by the presense of '-' */ 2334376bd9cbSDarrel Goeddel if (strchr(rulestr, '-')) 2335376bd9cbSDarrel Goeddel return -EINVAL; 2336376bd9cbSDarrel Goeddel break; 2337376bd9cbSDarrel Goeddel default: 2338376bd9cbSDarrel Goeddel /* only the above fields are valid */ 2339376bd9cbSDarrel Goeddel return -EINVAL; 2340376bd9cbSDarrel Goeddel } 2341376bd9cbSDarrel Goeddel 2342376bd9cbSDarrel Goeddel tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL); 2343376bd9cbSDarrel Goeddel if (!tmprule) 2344376bd9cbSDarrel Goeddel return -ENOMEM; 2345376bd9cbSDarrel Goeddel 2346376bd9cbSDarrel Goeddel context_init(&tmprule->au_ctxt); 2347376bd9cbSDarrel Goeddel 2348376bd9cbSDarrel Goeddel POLICY_RDLOCK; 2349376bd9cbSDarrel Goeddel 2350376bd9cbSDarrel Goeddel tmprule->au_seqno = latest_granting; 2351376bd9cbSDarrel Goeddel 2352376bd9cbSDarrel Goeddel switch (field) { 23533a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 23546e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 2355376bd9cbSDarrel Goeddel userdatum = hashtab_search(policydb.p_users.table, rulestr); 2356376bd9cbSDarrel Goeddel if (!userdatum) 2357376bd9cbSDarrel Goeddel rc = -EINVAL; 2358376bd9cbSDarrel Goeddel else 2359376bd9cbSDarrel Goeddel tmprule->au_ctxt.user = userdatum->value; 2360376bd9cbSDarrel Goeddel break; 23613a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 23626e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 2363376bd9cbSDarrel Goeddel roledatum = hashtab_search(policydb.p_roles.table, rulestr); 2364376bd9cbSDarrel Goeddel if (!roledatum) 2365376bd9cbSDarrel Goeddel rc = -EINVAL; 2366376bd9cbSDarrel Goeddel else 2367376bd9cbSDarrel Goeddel tmprule->au_ctxt.role = roledatum->value; 2368376bd9cbSDarrel Goeddel break; 23693a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 23706e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 2371376bd9cbSDarrel Goeddel typedatum = hashtab_search(policydb.p_types.table, rulestr); 2372376bd9cbSDarrel Goeddel if (!typedatum) 2373376bd9cbSDarrel Goeddel rc = -EINVAL; 2374376bd9cbSDarrel Goeddel else 2375376bd9cbSDarrel Goeddel tmprule->au_ctxt.type = typedatum->value; 2376376bd9cbSDarrel Goeddel break; 23773a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 23783a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 23796e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 23806e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 2381376bd9cbSDarrel Goeddel rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC); 2382376bd9cbSDarrel Goeddel break; 2383376bd9cbSDarrel Goeddel } 2384376bd9cbSDarrel Goeddel 2385376bd9cbSDarrel Goeddel POLICY_RDUNLOCK; 2386376bd9cbSDarrel Goeddel 2387376bd9cbSDarrel Goeddel if (rc) { 2388376bd9cbSDarrel Goeddel selinux_audit_rule_free(tmprule); 2389376bd9cbSDarrel Goeddel tmprule = NULL; 2390376bd9cbSDarrel Goeddel } 2391376bd9cbSDarrel Goeddel 2392376bd9cbSDarrel Goeddel *rule = tmprule; 2393376bd9cbSDarrel Goeddel 2394376bd9cbSDarrel Goeddel return rc; 2395376bd9cbSDarrel Goeddel } 2396376bd9cbSDarrel Goeddel 23979d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */ 23989d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule) 23999d57a7f9SAhmed S. Darwish { 24009d57a7f9SAhmed S. Darwish int i; 24019d57a7f9SAhmed S. Darwish 24029d57a7f9SAhmed S. Darwish for (i = 0; i < rule->field_count; i++) { 24039d57a7f9SAhmed S. Darwish struct audit_field *f = &rule->fields[i]; 24049d57a7f9SAhmed S. Darwish switch (f->type) { 24059d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_USER: 24069d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_ROLE: 24079d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_TYPE: 24089d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_SEN: 24099d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_CLR: 24109d57a7f9SAhmed S. Darwish case AUDIT_OBJ_USER: 24119d57a7f9SAhmed S. Darwish case AUDIT_OBJ_ROLE: 24129d57a7f9SAhmed S. Darwish case AUDIT_OBJ_TYPE: 24139d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_LOW: 24149d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_HIGH: 24159d57a7f9SAhmed S. Darwish return 1; 24169d57a7f9SAhmed S. Darwish } 24179d57a7f9SAhmed S. Darwish } 24189d57a7f9SAhmed S. Darwish 24199d57a7f9SAhmed S. Darwish return 0; 24209d57a7f9SAhmed S. Darwish } 24219d57a7f9SAhmed S. Darwish 24229d57a7f9SAhmed S. Darwish int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule, 2423376bd9cbSDarrel Goeddel struct audit_context *actx) 2424376bd9cbSDarrel Goeddel { 2425376bd9cbSDarrel Goeddel struct context *ctxt; 2426376bd9cbSDarrel Goeddel struct mls_level *level; 24279d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule; 2428376bd9cbSDarrel Goeddel int match = 0; 2429376bd9cbSDarrel Goeddel 2430376bd9cbSDarrel Goeddel if (!rule) { 2431376bd9cbSDarrel Goeddel audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, 2432376bd9cbSDarrel Goeddel "selinux_audit_rule_match: missing rule\n"); 2433376bd9cbSDarrel Goeddel return -ENOENT; 2434376bd9cbSDarrel Goeddel } 2435376bd9cbSDarrel Goeddel 2436376bd9cbSDarrel Goeddel POLICY_RDLOCK; 2437376bd9cbSDarrel Goeddel 2438376bd9cbSDarrel Goeddel if (rule->au_seqno < latest_granting) { 2439376bd9cbSDarrel Goeddel audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, 2440376bd9cbSDarrel Goeddel "selinux_audit_rule_match: stale rule\n"); 2441376bd9cbSDarrel Goeddel match = -ESTALE; 2442376bd9cbSDarrel Goeddel goto out; 2443376bd9cbSDarrel Goeddel } 2444376bd9cbSDarrel Goeddel 24459a2f44f0SStephen Smalley ctxt = sidtab_search(&sidtab, sid); 2446376bd9cbSDarrel Goeddel if (!ctxt) { 2447376bd9cbSDarrel Goeddel audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, 2448376bd9cbSDarrel Goeddel "selinux_audit_rule_match: unrecognized SID %d\n", 24499a2f44f0SStephen Smalley sid); 2450376bd9cbSDarrel Goeddel match = -ENOENT; 2451376bd9cbSDarrel Goeddel goto out; 2452376bd9cbSDarrel Goeddel } 2453376bd9cbSDarrel Goeddel 2454376bd9cbSDarrel Goeddel /* a field/op pair that is not caught here will simply fall through 2455376bd9cbSDarrel Goeddel without a match */ 2456376bd9cbSDarrel Goeddel switch (field) { 24573a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER: 24586e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER: 2459376bd9cbSDarrel Goeddel switch (op) { 2460376bd9cbSDarrel Goeddel case AUDIT_EQUAL: 2461376bd9cbSDarrel Goeddel match = (ctxt->user == rule->au_ctxt.user); 2462376bd9cbSDarrel Goeddel break; 2463376bd9cbSDarrel Goeddel case AUDIT_NOT_EQUAL: 2464376bd9cbSDarrel Goeddel match = (ctxt->user != rule->au_ctxt.user); 2465376bd9cbSDarrel Goeddel break; 2466376bd9cbSDarrel Goeddel } 2467376bd9cbSDarrel Goeddel break; 24683a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE: 24696e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE: 2470376bd9cbSDarrel Goeddel switch (op) { 2471376bd9cbSDarrel Goeddel case AUDIT_EQUAL: 2472376bd9cbSDarrel Goeddel match = (ctxt->role == rule->au_ctxt.role); 2473376bd9cbSDarrel Goeddel break; 2474376bd9cbSDarrel Goeddel case AUDIT_NOT_EQUAL: 2475376bd9cbSDarrel Goeddel match = (ctxt->role != rule->au_ctxt.role); 2476376bd9cbSDarrel Goeddel break; 2477376bd9cbSDarrel Goeddel } 2478376bd9cbSDarrel Goeddel break; 24793a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE: 24806e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE: 2481376bd9cbSDarrel Goeddel switch (op) { 2482376bd9cbSDarrel Goeddel case AUDIT_EQUAL: 2483376bd9cbSDarrel Goeddel match = (ctxt->type == rule->au_ctxt.type); 2484376bd9cbSDarrel Goeddel break; 2485376bd9cbSDarrel Goeddel case AUDIT_NOT_EQUAL: 2486376bd9cbSDarrel Goeddel match = (ctxt->type != rule->au_ctxt.type); 2487376bd9cbSDarrel Goeddel break; 2488376bd9cbSDarrel Goeddel } 2489376bd9cbSDarrel Goeddel break; 24903a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN: 24913a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR: 24926e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW: 24936e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH: 24946e5a2d1dSDarrel Goeddel level = ((field == AUDIT_SUBJ_SEN || 24956e5a2d1dSDarrel Goeddel field == AUDIT_OBJ_LEV_LOW) ? 2496376bd9cbSDarrel Goeddel &ctxt->range.level[0] : &ctxt->range.level[1]); 2497376bd9cbSDarrel Goeddel switch (op) { 2498376bd9cbSDarrel Goeddel case AUDIT_EQUAL: 2499376bd9cbSDarrel Goeddel match = mls_level_eq(&rule->au_ctxt.range.level[0], 2500376bd9cbSDarrel Goeddel level); 2501376bd9cbSDarrel Goeddel break; 2502376bd9cbSDarrel Goeddel case AUDIT_NOT_EQUAL: 2503376bd9cbSDarrel Goeddel match = !mls_level_eq(&rule->au_ctxt.range.level[0], 2504376bd9cbSDarrel Goeddel level); 2505376bd9cbSDarrel Goeddel break; 2506376bd9cbSDarrel Goeddel case AUDIT_LESS_THAN: 2507376bd9cbSDarrel Goeddel match = (mls_level_dom(&rule->au_ctxt.range.level[0], 2508376bd9cbSDarrel Goeddel level) && 2509376bd9cbSDarrel Goeddel !mls_level_eq(&rule->au_ctxt.range.level[0], 2510376bd9cbSDarrel Goeddel level)); 2511376bd9cbSDarrel Goeddel break; 2512376bd9cbSDarrel Goeddel case AUDIT_LESS_THAN_OR_EQUAL: 2513376bd9cbSDarrel Goeddel match = mls_level_dom(&rule->au_ctxt.range.level[0], 2514376bd9cbSDarrel Goeddel level); 2515376bd9cbSDarrel Goeddel break; 2516376bd9cbSDarrel Goeddel case AUDIT_GREATER_THAN: 2517376bd9cbSDarrel Goeddel match = (mls_level_dom(level, 2518376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]) && 2519376bd9cbSDarrel Goeddel !mls_level_eq(level, 2520376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0])); 2521376bd9cbSDarrel Goeddel break; 2522376bd9cbSDarrel Goeddel case AUDIT_GREATER_THAN_OR_EQUAL: 2523376bd9cbSDarrel Goeddel match = mls_level_dom(level, 2524376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]); 2525376bd9cbSDarrel Goeddel break; 2526376bd9cbSDarrel Goeddel } 2527376bd9cbSDarrel Goeddel } 2528376bd9cbSDarrel Goeddel 2529376bd9cbSDarrel Goeddel out: 2530376bd9cbSDarrel Goeddel POLICY_RDUNLOCK; 2531376bd9cbSDarrel Goeddel return match; 2532376bd9cbSDarrel Goeddel } 2533376bd9cbSDarrel Goeddel 25349d57a7f9SAhmed S. Darwish static int (*aurule_callback)(void) = audit_update_lsm_rules; 2535376bd9cbSDarrel Goeddel 2536376bd9cbSDarrel Goeddel static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, 2537376bd9cbSDarrel Goeddel u16 class, u32 perms, u32 *retained) 2538376bd9cbSDarrel Goeddel { 2539376bd9cbSDarrel Goeddel int err = 0; 2540376bd9cbSDarrel Goeddel 2541376bd9cbSDarrel Goeddel if (event == AVC_CALLBACK_RESET && aurule_callback) 2542376bd9cbSDarrel Goeddel err = aurule_callback(); 2543376bd9cbSDarrel Goeddel return err; 2544376bd9cbSDarrel Goeddel } 2545376bd9cbSDarrel Goeddel 2546376bd9cbSDarrel Goeddel static int __init aurule_init(void) 2547376bd9cbSDarrel Goeddel { 2548376bd9cbSDarrel Goeddel int err; 2549376bd9cbSDarrel Goeddel 2550376bd9cbSDarrel Goeddel err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET, 2551376bd9cbSDarrel Goeddel SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); 2552376bd9cbSDarrel Goeddel if (err) 2553376bd9cbSDarrel Goeddel panic("avc_add_callback() failed, error %d\n", err); 2554376bd9cbSDarrel Goeddel 2555376bd9cbSDarrel Goeddel return err; 2556376bd9cbSDarrel Goeddel } 2557376bd9cbSDarrel Goeddel __initcall(aurule_init); 2558376bd9cbSDarrel Goeddel 25597420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL 25607420ed23SVenkat Yekkirala /** 25615778eabdSPaul Moore * security_netlbl_cache_add - Add an entry to the NetLabel cache 25625778eabdSPaul Moore * @secattr: the NetLabel packet security attributes 25635dbe1eb0SPaul Moore * @sid: the SELinux SID 25647420ed23SVenkat Yekkirala * 25657420ed23SVenkat Yekkirala * Description: 25667420ed23SVenkat Yekkirala * Attempt to cache the context in @ctx, which was derived from the packet in 25675778eabdSPaul Moore * @skb, in the NetLabel subsystem cache. This function assumes @secattr has 25685778eabdSPaul Moore * already been initialized. 25697420ed23SVenkat Yekkirala * 25707420ed23SVenkat Yekkirala */ 25715778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr, 25725dbe1eb0SPaul Moore u32 sid) 25737420ed23SVenkat Yekkirala { 25745dbe1eb0SPaul Moore u32 *sid_cache; 25757420ed23SVenkat Yekkirala 25765dbe1eb0SPaul Moore sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC); 25775dbe1eb0SPaul Moore if (sid_cache == NULL) 25785dbe1eb0SPaul Moore return; 25795778eabdSPaul Moore secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC); 25805dbe1eb0SPaul Moore if (secattr->cache == NULL) { 25815dbe1eb0SPaul Moore kfree(sid_cache); 25825778eabdSPaul Moore return; 25830ec8abd7SJesper Juhl } 25847420ed23SVenkat Yekkirala 25855dbe1eb0SPaul Moore *sid_cache = sid; 25865dbe1eb0SPaul Moore secattr->cache->free = kfree; 25875dbe1eb0SPaul Moore secattr->cache->data = sid_cache; 25885778eabdSPaul Moore secattr->flags |= NETLBL_SECATTR_CACHE; 25897420ed23SVenkat Yekkirala } 25907420ed23SVenkat Yekkirala 25917420ed23SVenkat Yekkirala /** 25925778eabdSPaul Moore * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID 25937420ed23SVenkat Yekkirala * @secattr: the NetLabel packet security attributes 25947420ed23SVenkat Yekkirala * @sid: the SELinux SID 25957420ed23SVenkat Yekkirala * 25967420ed23SVenkat Yekkirala * Description: 25975778eabdSPaul Moore * Convert the given NetLabel security attributes in @secattr into a 25987420ed23SVenkat Yekkirala * SELinux SID. If the @secattr field does not contain a full SELinux 25995dbe1eb0SPaul Moore * SID/context then use SECINITSID_NETMSG as the foundation. If possibile the 26005dbe1eb0SPaul Moore * 'cache' field of @secattr is set and the CACHE flag is set; this is to 26015dbe1eb0SPaul Moore * allow the @secattr to be used by NetLabel to cache the secattr to SID 26025dbe1eb0SPaul Moore * conversion for future lookups. Returns zero on success, negative values on 26035dbe1eb0SPaul Moore * failure. 26047420ed23SVenkat Yekkirala * 26057420ed23SVenkat Yekkirala */ 26065778eabdSPaul Moore int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr, 26077420ed23SVenkat Yekkirala u32 *sid) 26087420ed23SVenkat Yekkirala { 26097420ed23SVenkat Yekkirala int rc = -EIDRM; 26107420ed23SVenkat Yekkirala struct context *ctx; 26117420ed23SVenkat Yekkirala struct context ctx_new; 26125778eabdSPaul Moore 26135778eabdSPaul Moore if (!ss_initialized) { 26145778eabdSPaul Moore *sid = SECSID_NULL; 26155778eabdSPaul Moore return 0; 26165778eabdSPaul Moore } 26177420ed23SVenkat Yekkirala 26187420ed23SVenkat Yekkirala POLICY_RDLOCK; 26197420ed23SVenkat Yekkirala 2620701a90baSPaul Moore if (secattr->flags & NETLBL_SECATTR_CACHE) { 26215dbe1eb0SPaul Moore *sid = *(u32 *)secattr->cache->data; 26227420ed23SVenkat Yekkirala rc = 0; 262316efd454SPaul Moore } else if (secattr->flags & NETLBL_SECATTR_SECID) { 262416efd454SPaul Moore *sid = secattr->attr.secid; 262516efd454SPaul Moore rc = 0; 2626701a90baSPaul Moore } else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) { 26275dbe1eb0SPaul Moore ctx = sidtab_search(&sidtab, SECINITSID_NETMSG); 26287420ed23SVenkat Yekkirala if (ctx == NULL) 26297420ed23SVenkat Yekkirala goto netlbl_secattr_to_sid_return; 26307420ed23SVenkat Yekkirala 26317420ed23SVenkat Yekkirala ctx_new.user = ctx->user; 26327420ed23SVenkat Yekkirala ctx_new.role = ctx->role; 26337420ed23SVenkat Yekkirala ctx_new.type = ctx->type; 263402752760SPaul Moore mls_import_netlbl_lvl(&ctx_new, secattr); 2635701a90baSPaul Moore if (secattr->flags & NETLBL_SECATTR_MLS_CAT) { 263602752760SPaul Moore if (ebitmap_netlbl_import(&ctx_new.range.level[0].cat, 263716efd454SPaul Moore secattr->attr.mls.cat) != 0) 26387420ed23SVenkat Yekkirala goto netlbl_secattr_to_sid_return; 26397420ed23SVenkat Yekkirala ctx_new.range.level[1].cat.highbit = 26407420ed23SVenkat Yekkirala ctx_new.range.level[0].cat.highbit; 26417420ed23SVenkat Yekkirala ctx_new.range.level[1].cat.node = 26427420ed23SVenkat Yekkirala ctx_new.range.level[0].cat.node; 26437420ed23SVenkat Yekkirala } else { 26447420ed23SVenkat Yekkirala ebitmap_init(&ctx_new.range.level[0].cat); 26457420ed23SVenkat Yekkirala ebitmap_init(&ctx_new.range.level[1].cat); 26467420ed23SVenkat Yekkirala } 26477420ed23SVenkat Yekkirala if (mls_context_isvalid(&policydb, &ctx_new) != 1) 26487420ed23SVenkat Yekkirala goto netlbl_secattr_to_sid_return_cleanup; 26497420ed23SVenkat Yekkirala 26507420ed23SVenkat Yekkirala rc = sidtab_context_to_sid(&sidtab, &ctx_new, sid); 26517420ed23SVenkat Yekkirala if (rc != 0) 26527420ed23SVenkat Yekkirala goto netlbl_secattr_to_sid_return_cleanup; 26537420ed23SVenkat Yekkirala 26545dbe1eb0SPaul Moore security_netlbl_cache_add(secattr, *sid); 26555778eabdSPaul Moore 26567420ed23SVenkat Yekkirala ebitmap_destroy(&ctx_new.range.level[0].cat); 26577420ed23SVenkat Yekkirala } else { 2658388b2405Spaul.moore@hp.com *sid = SECSID_NULL; 26597420ed23SVenkat Yekkirala rc = 0; 26607420ed23SVenkat Yekkirala } 26617420ed23SVenkat Yekkirala 26627420ed23SVenkat Yekkirala netlbl_secattr_to_sid_return: 26637420ed23SVenkat Yekkirala POLICY_RDUNLOCK; 26647420ed23SVenkat Yekkirala return rc; 26657420ed23SVenkat Yekkirala netlbl_secattr_to_sid_return_cleanup: 26667420ed23SVenkat Yekkirala ebitmap_destroy(&ctx_new.range.level[0].cat); 26677420ed23SVenkat Yekkirala goto netlbl_secattr_to_sid_return; 26687420ed23SVenkat Yekkirala } 26697420ed23SVenkat Yekkirala 26707420ed23SVenkat Yekkirala /** 26715778eabdSPaul Moore * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr 26725778eabdSPaul Moore * @sid: the SELinux SID 26735778eabdSPaul Moore * @secattr: the NetLabel packet security attributes 26747420ed23SVenkat Yekkirala * 26757420ed23SVenkat Yekkirala * Description: 26765778eabdSPaul Moore * Convert the given SELinux SID in @sid into a NetLabel security attribute. 26775778eabdSPaul Moore * Returns zero on success, negative values on failure. 26787420ed23SVenkat Yekkirala * 26797420ed23SVenkat Yekkirala */ 26805778eabdSPaul Moore int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr) 26817420ed23SVenkat Yekkirala { 26827420ed23SVenkat Yekkirala int rc = -ENOENT; 26837420ed23SVenkat Yekkirala struct context *ctx; 26847420ed23SVenkat Yekkirala 26857420ed23SVenkat Yekkirala if (!ss_initialized) 26867420ed23SVenkat Yekkirala return 0; 26877420ed23SVenkat Yekkirala 26887420ed23SVenkat Yekkirala POLICY_RDLOCK; 26897420ed23SVenkat Yekkirala ctx = sidtab_search(&sidtab, sid); 26907420ed23SVenkat Yekkirala if (ctx == NULL) 26915778eabdSPaul Moore goto netlbl_sid_to_secattr_failure; 26925778eabdSPaul Moore secattr->domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1], 26937420ed23SVenkat Yekkirala GFP_ATOMIC); 269400447872SPaul Moore secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY; 26955778eabdSPaul Moore mls_export_netlbl_lvl(ctx, secattr); 26965778eabdSPaul Moore rc = mls_export_netlbl_cat(ctx, secattr); 2697bf0edf39SPaul Moore if (rc != 0) 26985778eabdSPaul Moore goto netlbl_sid_to_secattr_failure; 26997420ed23SVenkat Yekkirala POLICY_RDUNLOCK; 27007420ed23SVenkat Yekkirala 27017420ed23SVenkat Yekkirala return 0; 27027420ed23SVenkat Yekkirala 27035778eabdSPaul Moore netlbl_sid_to_secattr_failure: 27045778eabdSPaul Moore POLICY_RDUNLOCK; 2705f8687afeSPaul Moore return rc; 2706f8687afeSPaul Moore } 27077420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */ 2708