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 * 16376bd9cbSDarrel Goeddel * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc. 171da177e4SLinus Torvalds * Copyright (C) 2003 - 2004 Tresys Technology, LLC 181da177e4SLinus Torvalds * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com> 191da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 201da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 211da177e4SLinus Torvalds * the Free Software Foundation, version 2. 221da177e4SLinus Torvalds */ 231da177e4SLinus Torvalds #include <linux/kernel.h> 241da177e4SLinus Torvalds #include <linux/slab.h> 251da177e4SLinus Torvalds #include <linux/string.h> 261da177e4SLinus Torvalds #include <linux/spinlock.h> 271da177e4SLinus Torvalds #include <linux/errno.h> 281da177e4SLinus Torvalds #include <linux/in.h> 291da177e4SLinus Torvalds #include <linux/sched.h> 301da177e4SLinus Torvalds #include <linux/audit.h> 31bb003079SIngo Molnar #include <linux/mutex.h> 32bb003079SIngo Molnar 331da177e4SLinus Torvalds #include "flask.h" 341da177e4SLinus Torvalds #include "avc.h" 351da177e4SLinus Torvalds #include "avc_ss.h" 361da177e4SLinus Torvalds #include "security.h" 371da177e4SLinus Torvalds #include "context.h" 381da177e4SLinus Torvalds #include "policydb.h" 391da177e4SLinus Torvalds #include "sidtab.h" 401da177e4SLinus Torvalds #include "services.h" 411da177e4SLinus Torvalds #include "conditional.h" 421da177e4SLinus Torvalds #include "mls.h" 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds extern void selnl_notify_policyload(u32 seqno); 451da177e4SLinus Torvalds unsigned int policydb_loaded_version; 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds static DEFINE_RWLOCK(policy_rwlock); 481da177e4SLinus Torvalds #define POLICY_RDLOCK read_lock(&policy_rwlock) 491da177e4SLinus Torvalds #define POLICY_WRLOCK write_lock_irq(&policy_rwlock) 501da177e4SLinus Torvalds #define POLICY_RDUNLOCK read_unlock(&policy_rwlock) 511da177e4SLinus Torvalds #define POLICY_WRUNLOCK write_unlock_irq(&policy_rwlock) 521da177e4SLinus Torvalds 53bb003079SIngo Molnar static DEFINE_MUTEX(load_mutex); 54bb003079SIngo Molnar #define LOAD_LOCK mutex_lock(&load_mutex) 55bb003079SIngo Molnar #define LOAD_UNLOCK mutex_unlock(&load_mutex) 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds static struct sidtab sidtab; 581da177e4SLinus Torvalds struct policydb policydb; 591da177e4SLinus Torvalds int ss_initialized = 0; 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds /* 621da177e4SLinus Torvalds * The largest sequence number that has been used when 631da177e4SLinus Torvalds * providing an access decision to the access vector cache. 641da177e4SLinus Torvalds * The sequence number only changes when a policy change 651da177e4SLinus Torvalds * occurs. 661da177e4SLinus Torvalds */ 671da177e4SLinus Torvalds static u32 latest_granting = 0; 681da177e4SLinus Torvalds 691da177e4SLinus Torvalds /* Forward declaration. */ 701da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, 711da177e4SLinus Torvalds u32 *scontext_len); 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds /* 741da177e4SLinus Torvalds * Return the boolean value of a constraint expression 751da177e4SLinus Torvalds * when it is applied to the specified source and target 761da177e4SLinus Torvalds * security contexts. 771da177e4SLinus Torvalds * 781da177e4SLinus Torvalds * xcontext is a special beast... It is used by the validatetrans rules 791da177e4SLinus Torvalds * only. For these rules, scontext is the context before the transition, 801da177e4SLinus Torvalds * tcontext is the context after the transition, and xcontext is the context 811da177e4SLinus Torvalds * of the process performing the transition. All other callers of 821da177e4SLinus Torvalds * constraint_expr_eval should pass in NULL for xcontext. 831da177e4SLinus Torvalds */ 841da177e4SLinus Torvalds static int constraint_expr_eval(struct context *scontext, 851da177e4SLinus Torvalds struct context *tcontext, 861da177e4SLinus Torvalds struct context *xcontext, 871da177e4SLinus Torvalds struct constraint_expr *cexpr) 881da177e4SLinus Torvalds { 891da177e4SLinus Torvalds u32 val1, val2; 901da177e4SLinus Torvalds struct context *c; 911da177e4SLinus Torvalds struct role_datum *r1, *r2; 921da177e4SLinus Torvalds struct mls_level *l1, *l2; 931da177e4SLinus Torvalds struct constraint_expr *e; 941da177e4SLinus Torvalds int s[CEXPR_MAXDEPTH]; 951da177e4SLinus Torvalds int sp = -1; 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds for (e = cexpr; e; e = e->next) { 981da177e4SLinus Torvalds switch (e->expr_type) { 991da177e4SLinus Torvalds case CEXPR_NOT: 1001da177e4SLinus Torvalds BUG_ON(sp < 0); 1011da177e4SLinus Torvalds s[sp] = !s[sp]; 1021da177e4SLinus Torvalds break; 1031da177e4SLinus Torvalds case CEXPR_AND: 1041da177e4SLinus Torvalds BUG_ON(sp < 1); 1051da177e4SLinus Torvalds sp--; 1061da177e4SLinus Torvalds s[sp] &= s[sp+1]; 1071da177e4SLinus Torvalds break; 1081da177e4SLinus Torvalds case CEXPR_OR: 1091da177e4SLinus Torvalds BUG_ON(sp < 1); 1101da177e4SLinus Torvalds sp--; 1111da177e4SLinus Torvalds s[sp] |= s[sp+1]; 1121da177e4SLinus Torvalds break; 1131da177e4SLinus Torvalds case CEXPR_ATTR: 1141da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH-1)) 1151da177e4SLinus Torvalds return 0; 1161da177e4SLinus Torvalds switch (e->attr) { 1171da177e4SLinus Torvalds case CEXPR_USER: 1181da177e4SLinus Torvalds val1 = scontext->user; 1191da177e4SLinus Torvalds val2 = tcontext->user; 1201da177e4SLinus Torvalds break; 1211da177e4SLinus Torvalds case CEXPR_TYPE: 1221da177e4SLinus Torvalds val1 = scontext->type; 1231da177e4SLinus Torvalds val2 = tcontext->type; 1241da177e4SLinus Torvalds break; 1251da177e4SLinus Torvalds case CEXPR_ROLE: 1261da177e4SLinus Torvalds val1 = scontext->role; 1271da177e4SLinus Torvalds val2 = tcontext->role; 1281da177e4SLinus Torvalds r1 = policydb.role_val_to_struct[val1 - 1]; 1291da177e4SLinus Torvalds r2 = policydb.role_val_to_struct[val2 - 1]; 1301da177e4SLinus Torvalds switch (e->op) { 1311da177e4SLinus Torvalds case CEXPR_DOM: 1321da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r1->dominates, 1331da177e4SLinus Torvalds val2 - 1); 1341da177e4SLinus Torvalds continue; 1351da177e4SLinus Torvalds case CEXPR_DOMBY: 1361da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r2->dominates, 1371da177e4SLinus Torvalds val1 - 1); 1381da177e4SLinus Torvalds continue; 1391da177e4SLinus Torvalds case CEXPR_INCOMP: 1401da177e4SLinus Torvalds s[++sp] = ( !ebitmap_get_bit(&r1->dominates, 1411da177e4SLinus Torvalds val2 - 1) && 1421da177e4SLinus Torvalds !ebitmap_get_bit(&r2->dominates, 1431da177e4SLinus Torvalds val1 - 1) ); 1441da177e4SLinus Torvalds continue; 1451da177e4SLinus Torvalds default: 1461da177e4SLinus Torvalds break; 1471da177e4SLinus Torvalds } 1481da177e4SLinus Torvalds break; 1491da177e4SLinus Torvalds case CEXPR_L1L2: 1501da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 1511da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 1521da177e4SLinus Torvalds goto mls_ops; 1531da177e4SLinus Torvalds case CEXPR_L1H2: 1541da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 1551da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 1561da177e4SLinus Torvalds goto mls_ops; 1571da177e4SLinus Torvalds case CEXPR_H1L2: 1581da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 1591da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]); 1601da177e4SLinus Torvalds goto mls_ops; 1611da177e4SLinus Torvalds case CEXPR_H1H2: 1621da177e4SLinus Torvalds l1 = &(scontext->range.level[1]); 1631da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 1641da177e4SLinus Torvalds goto mls_ops; 1651da177e4SLinus Torvalds case CEXPR_L1H1: 1661da177e4SLinus Torvalds l1 = &(scontext->range.level[0]); 1671da177e4SLinus Torvalds l2 = &(scontext->range.level[1]); 1681da177e4SLinus Torvalds goto mls_ops; 1691da177e4SLinus Torvalds case CEXPR_L2H2: 1701da177e4SLinus Torvalds l1 = &(tcontext->range.level[0]); 1711da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]); 1721da177e4SLinus Torvalds goto mls_ops; 1731da177e4SLinus Torvalds mls_ops: 1741da177e4SLinus Torvalds switch (e->op) { 1751da177e4SLinus Torvalds case CEXPR_EQ: 1761da177e4SLinus Torvalds s[++sp] = mls_level_eq(l1, l2); 1771da177e4SLinus Torvalds continue; 1781da177e4SLinus Torvalds case CEXPR_NEQ: 1791da177e4SLinus Torvalds s[++sp] = !mls_level_eq(l1, l2); 1801da177e4SLinus Torvalds continue; 1811da177e4SLinus Torvalds case CEXPR_DOM: 1821da177e4SLinus Torvalds s[++sp] = mls_level_dom(l1, l2); 1831da177e4SLinus Torvalds continue; 1841da177e4SLinus Torvalds case CEXPR_DOMBY: 1851da177e4SLinus Torvalds s[++sp] = mls_level_dom(l2, l1); 1861da177e4SLinus Torvalds continue; 1871da177e4SLinus Torvalds case CEXPR_INCOMP: 1881da177e4SLinus Torvalds s[++sp] = mls_level_incomp(l2, l1); 1891da177e4SLinus Torvalds continue; 1901da177e4SLinus Torvalds default: 1911da177e4SLinus Torvalds BUG(); 1921da177e4SLinus Torvalds return 0; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds break; 1951da177e4SLinus Torvalds default: 1961da177e4SLinus Torvalds BUG(); 1971da177e4SLinus Torvalds return 0; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds switch (e->op) { 2011da177e4SLinus Torvalds case CEXPR_EQ: 2021da177e4SLinus Torvalds s[++sp] = (val1 == val2); 2031da177e4SLinus Torvalds break; 2041da177e4SLinus Torvalds case CEXPR_NEQ: 2051da177e4SLinus Torvalds s[++sp] = (val1 != val2); 2061da177e4SLinus Torvalds break; 2071da177e4SLinus Torvalds default: 2081da177e4SLinus Torvalds BUG(); 2091da177e4SLinus Torvalds return 0; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds break; 2121da177e4SLinus Torvalds case CEXPR_NAMES: 2131da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH-1)) 2141da177e4SLinus Torvalds return 0; 2151da177e4SLinus Torvalds c = scontext; 2161da177e4SLinus Torvalds if (e->attr & CEXPR_TARGET) 2171da177e4SLinus Torvalds c = tcontext; 2181da177e4SLinus Torvalds else if (e->attr & CEXPR_XTARGET) { 2191da177e4SLinus Torvalds c = xcontext; 2201da177e4SLinus Torvalds if (!c) { 2211da177e4SLinus Torvalds BUG(); 2221da177e4SLinus Torvalds return 0; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds } 2251da177e4SLinus Torvalds if (e->attr & CEXPR_USER) 2261da177e4SLinus Torvalds val1 = c->user; 2271da177e4SLinus Torvalds else if (e->attr & CEXPR_ROLE) 2281da177e4SLinus Torvalds val1 = c->role; 2291da177e4SLinus Torvalds else if (e->attr & CEXPR_TYPE) 2301da177e4SLinus Torvalds val1 = c->type; 2311da177e4SLinus Torvalds else { 2321da177e4SLinus Torvalds BUG(); 2331da177e4SLinus Torvalds return 0; 2341da177e4SLinus Torvalds } 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds switch (e->op) { 2371da177e4SLinus Torvalds case CEXPR_EQ: 2381da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&e->names, val1 - 1); 2391da177e4SLinus Torvalds break; 2401da177e4SLinus Torvalds case CEXPR_NEQ: 2411da177e4SLinus Torvalds s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1); 2421da177e4SLinus Torvalds break; 2431da177e4SLinus Torvalds default: 2441da177e4SLinus Torvalds BUG(); 2451da177e4SLinus Torvalds return 0; 2461da177e4SLinus Torvalds } 2471da177e4SLinus Torvalds break; 2481da177e4SLinus Torvalds default: 2491da177e4SLinus Torvalds BUG(); 2501da177e4SLinus Torvalds return 0; 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds } 2531da177e4SLinus Torvalds 2541da177e4SLinus Torvalds BUG_ON(sp != 0); 2551da177e4SLinus Torvalds return s[0]; 2561da177e4SLinus Torvalds } 2571da177e4SLinus Torvalds 2581da177e4SLinus Torvalds /* 2591da177e4SLinus Torvalds * Compute access vectors based on a context structure pair for 2601da177e4SLinus Torvalds * the permissions in a particular class. 2611da177e4SLinus Torvalds */ 2621da177e4SLinus Torvalds static int context_struct_compute_av(struct context *scontext, 2631da177e4SLinus Torvalds struct context *tcontext, 2641da177e4SLinus Torvalds u16 tclass, 2651da177e4SLinus Torvalds u32 requested, 2661da177e4SLinus Torvalds struct av_decision *avd) 2671da177e4SLinus Torvalds { 2681da177e4SLinus Torvalds struct constraint_node *constraint; 2691da177e4SLinus Torvalds struct role_allow *ra; 2701da177e4SLinus Torvalds struct avtab_key avkey; 271782ebb99SStephen Smalley struct avtab_node *node; 2721da177e4SLinus Torvalds struct class_datum *tclass_datum; 273782ebb99SStephen Smalley struct ebitmap *sattr, *tattr; 274782ebb99SStephen Smalley struct ebitmap_node *snode, *tnode; 275782ebb99SStephen Smalley unsigned int i, j; 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds /* 2781da177e4SLinus Torvalds * Remap extended Netlink classes for old policy versions. 2791da177e4SLinus Torvalds * Do this here rather than socket_type_to_security_class() 2801da177e4SLinus Torvalds * in case a newer policy version is loaded, allowing sockets 2811da177e4SLinus Torvalds * to remain in the correct class. 2821da177e4SLinus Torvalds */ 2831da177e4SLinus Torvalds if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS) 2841da177e4SLinus Torvalds if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET && 2851da177e4SLinus Torvalds tclass <= SECCLASS_NETLINK_DNRT_SOCKET) 2861da177e4SLinus Torvalds tclass = SECCLASS_NETLINK_SOCKET; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds if (!tclass || tclass > policydb.p_classes.nprim) { 2891da177e4SLinus Torvalds printk(KERN_ERR "security_compute_av: unrecognized class %d\n", 2901da177e4SLinus Torvalds tclass); 2911da177e4SLinus Torvalds return -EINVAL; 2921da177e4SLinus Torvalds } 2931da177e4SLinus Torvalds tclass_datum = policydb.class_val_to_struct[tclass - 1]; 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds /* 2961da177e4SLinus Torvalds * Initialize the access vectors to the default values. 2971da177e4SLinus Torvalds */ 2981da177e4SLinus Torvalds avd->allowed = 0; 2991da177e4SLinus Torvalds avd->decided = 0xffffffff; 3001da177e4SLinus Torvalds avd->auditallow = 0; 3011da177e4SLinus Torvalds avd->auditdeny = 0xffffffff; 3021da177e4SLinus Torvalds avd->seqno = latest_granting; 3031da177e4SLinus Torvalds 3041da177e4SLinus Torvalds /* 3051da177e4SLinus Torvalds * If a specific type enforcement rule was defined for 3061da177e4SLinus Torvalds * this permission check, then use it. 3071da177e4SLinus Torvalds */ 3081da177e4SLinus Torvalds avkey.target_class = tclass; 309782ebb99SStephen Smalley avkey.specified = AVTAB_AV; 310782ebb99SStephen Smalley sattr = &policydb.type_attr_map[scontext->type - 1]; 311782ebb99SStephen Smalley tattr = &policydb.type_attr_map[tcontext->type - 1]; 312782ebb99SStephen Smalley ebitmap_for_each_bit(sattr, snode, i) { 313782ebb99SStephen Smalley if (!ebitmap_node_get_bit(snode, i)) 314782ebb99SStephen Smalley continue; 315782ebb99SStephen Smalley ebitmap_for_each_bit(tattr, tnode, j) { 316782ebb99SStephen Smalley if (!ebitmap_node_get_bit(tnode, j)) 317782ebb99SStephen Smalley continue; 318782ebb99SStephen Smalley avkey.source_type = i + 1; 319782ebb99SStephen Smalley avkey.target_type = j + 1; 320782ebb99SStephen Smalley for (node = avtab_search_node(&policydb.te_avtab, &avkey); 321782ebb99SStephen Smalley node != NULL; 322782ebb99SStephen Smalley node = avtab_search_node_next(node, avkey.specified)) { 323782ebb99SStephen Smalley if (node->key.specified == AVTAB_ALLOWED) 324782ebb99SStephen Smalley avd->allowed |= node->datum.data; 325782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITALLOW) 326782ebb99SStephen Smalley avd->auditallow |= node->datum.data; 327782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITDENY) 328782ebb99SStephen Smalley avd->auditdeny &= node->datum.data; 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds /* Check conditional av table for additional permissions */ 3321da177e4SLinus Torvalds cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); 3331da177e4SLinus Torvalds 334782ebb99SStephen Smalley } 335782ebb99SStephen Smalley } 336782ebb99SStephen Smalley 3371da177e4SLinus Torvalds /* 3381da177e4SLinus Torvalds * Remove any permissions prohibited by a constraint (this includes 3391da177e4SLinus Torvalds * the MLS policy). 3401da177e4SLinus Torvalds */ 3411da177e4SLinus Torvalds constraint = tclass_datum->constraints; 3421da177e4SLinus Torvalds while (constraint) { 3431da177e4SLinus Torvalds if ((constraint->permissions & (avd->allowed)) && 3441da177e4SLinus Torvalds !constraint_expr_eval(scontext, tcontext, NULL, 3451da177e4SLinus Torvalds constraint->expr)) { 3461da177e4SLinus Torvalds avd->allowed = (avd->allowed) & ~(constraint->permissions); 3471da177e4SLinus Torvalds } 3481da177e4SLinus Torvalds constraint = constraint->next; 3491da177e4SLinus Torvalds } 3501da177e4SLinus Torvalds 3511da177e4SLinus Torvalds /* 3521da177e4SLinus Torvalds * If checking process transition permission and the 3531da177e4SLinus Torvalds * role is changing, then check the (current_role, new_role) 3541da177e4SLinus Torvalds * pair. 3551da177e4SLinus Torvalds */ 3561da177e4SLinus Torvalds if (tclass == SECCLASS_PROCESS && 3571da177e4SLinus Torvalds (avd->allowed & (PROCESS__TRANSITION | PROCESS__DYNTRANSITION)) && 3581da177e4SLinus Torvalds scontext->role != tcontext->role) { 3591da177e4SLinus Torvalds for (ra = policydb.role_allow; ra; ra = ra->next) { 3601da177e4SLinus Torvalds if (scontext->role == ra->role && 3611da177e4SLinus Torvalds tcontext->role == ra->new_role) 3621da177e4SLinus Torvalds break; 3631da177e4SLinus Torvalds } 3641da177e4SLinus Torvalds if (!ra) 3651da177e4SLinus Torvalds avd->allowed = (avd->allowed) & ~(PROCESS__TRANSITION | 3661da177e4SLinus Torvalds PROCESS__DYNTRANSITION); 3671da177e4SLinus Torvalds } 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds return 0; 3701da177e4SLinus Torvalds } 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds static int security_validtrans_handle_fail(struct context *ocontext, 3731da177e4SLinus Torvalds struct context *ncontext, 3741da177e4SLinus Torvalds struct context *tcontext, 3751da177e4SLinus Torvalds u16 tclass) 3761da177e4SLinus Torvalds { 3771da177e4SLinus Torvalds char *o = NULL, *n = NULL, *t = NULL; 3781da177e4SLinus Torvalds u32 olen, nlen, tlen; 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds if (context_struct_to_string(ocontext, &o, &olen) < 0) 3811da177e4SLinus Torvalds goto out; 3821da177e4SLinus Torvalds if (context_struct_to_string(ncontext, &n, &nlen) < 0) 3831da177e4SLinus Torvalds goto out; 3841da177e4SLinus Torvalds if (context_struct_to_string(tcontext, &t, &tlen) < 0) 3851da177e4SLinus Torvalds goto out; 3869ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 3871da177e4SLinus Torvalds "security_validate_transition: denied for" 3881da177e4SLinus Torvalds " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s", 3891da177e4SLinus Torvalds o, n, t, policydb.p_class_val_to_name[tclass-1]); 3901da177e4SLinus Torvalds out: 3911da177e4SLinus Torvalds kfree(o); 3921da177e4SLinus Torvalds kfree(n); 3931da177e4SLinus Torvalds kfree(t); 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds if (!selinux_enforcing) 3961da177e4SLinus Torvalds return 0; 3971da177e4SLinus Torvalds return -EPERM; 3981da177e4SLinus Torvalds } 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid, 4011da177e4SLinus Torvalds u16 tclass) 4021da177e4SLinus Torvalds { 4031da177e4SLinus Torvalds struct context *ocontext; 4041da177e4SLinus Torvalds struct context *ncontext; 4051da177e4SLinus Torvalds struct context *tcontext; 4061da177e4SLinus Torvalds struct class_datum *tclass_datum; 4071da177e4SLinus Torvalds struct constraint_node *constraint; 4081da177e4SLinus Torvalds int rc = 0; 4091da177e4SLinus Torvalds 4101da177e4SLinus Torvalds if (!ss_initialized) 4111da177e4SLinus Torvalds return 0; 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds POLICY_RDLOCK; 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds /* 4161da177e4SLinus Torvalds * Remap extended Netlink classes for old policy versions. 4171da177e4SLinus Torvalds * Do this here rather than socket_type_to_security_class() 4181da177e4SLinus Torvalds * in case a newer policy version is loaded, allowing sockets 4191da177e4SLinus Torvalds * to remain in the correct class. 4201da177e4SLinus Torvalds */ 4211da177e4SLinus Torvalds if (policydb_loaded_version < POLICYDB_VERSION_NLCLASS) 4221da177e4SLinus Torvalds if (tclass >= SECCLASS_NETLINK_ROUTE_SOCKET && 4231da177e4SLinus Torvalds tclass <= SECCLASS_NETLINK_DNRT_SOCKET) 4241da177e4SLinus Torvalds tclass = SECCLASS_NETLINK_SOCKET; 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds if (!tclass || tclass > policydb.p_classes.nprim) { 4271da177e4SLinus Torvalds printk(KERN_ERR "security_validate_transition: " 4281da177e4SLinus Torvalds "unrecognized class %d\n", tclass); 4291da177e4SLinus Torvalds rc = -EINVAL; 4301da177e4SLinus Torvalds goto out; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds tclass_datum = policydb.class_val_to_struct[tclass - 1]; 4331da177e4SLinus Torvalds 4341da177e4SLinus Torvalds ocontext = sidtab_search(&sidtab, oldsid); 4351da177e4SLinus Torvalds if (!ocontext) { 4361da177e4SLinus Torvalds printk(KERN_ERR "security_validate_transition: " 4371da177e4SLinus Torvalds " unrecognized SID %d\n", oldsid); 4381da177e4SLinus Torvalds rc = -EINVAL; 4391da177e4SLinus Torvalds goto out; 4401da177e4SLinus Torvalds } 4411da177e4SLinus Torvalds 4421da177e4SLinus Torvalds ncontext = sidtab_search(&sidtab, newsid); 4431da177e4SLinus Torvalds if (!ncontext) { 4441da177e4SLinus Torvalds printk(KERN_ERR "security_validate_transition: " 4451da177e4SLinus Torvalds " unrecognized SID %d\n", newsid); 4461da177e4SLinus Torvalds rc = -EINVAL; 4471da177e4SLinus Torvalds goto out; 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tasksid); 4511da177e4SLinus Torvalds if (!tcontext) { 4521da177e4SLinus Torvalds printk(KERN_ERR "security_validate_transition: " 4531da177e4SLinus Torvalds " unrecognized SID %d\n", tasksid); 4541da177e4SLinus Torvalds rc = -EINVAL; 4551da177e4SLinus Torvalds goto out; 4561da177e4SLinus Torvalds } 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds constraint = tclass_datum->validatetrans; 4591da177e4SLinus Torvalds while (constraint) { 4601da177e4SLinus Torvalds if (!constraint_expr_eval(ocontext, ncontext, tcontext, 4611da177e4SLinus Torvalds constraint->expr)) { 4621da177e4SLinus Torvalds rc = security_validtrans_handle_fail(ocontext, ncontext, 4631da177e4SLinus Torvalds tcontext, tclass); 4641da177e4SLinus Torvalds goto out; 4651da177e4SLinus Torvalds } 4661da177e4SLinus Torvalds constraint = constraint->next; 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds out: 4701da177e4SLinus Torvalds POLICY_RDUNLOCK; 4711da177e4SLinus Torvalds return rc; 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds /** 4751da177e4SLinus Torvalds * security_compute_av - Compute access vector decisions. 4761da177e4SLinus Torvalds * @ssid: source security identifier 4771da177e4SLinus Torvalds * @tsid: target security identifier 4781da177e4SLinus Torvalds * @tclass: target security class 4791da177e4SLinus Torvalds * @requested: requested permissions 4801da177e4SLinus Torvalds * @avd: access vector decisions 4811da177e4SLinus Torvalds * 4821da177e4SLinus Torvalds * Compute a set of access vector decisions based on the 4831da177e4SLinus Torvalds * SID pair (@ssid, @tsid) for the permissions in @tclass. 4841da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid or %0 4851da177e4SLinus Torvalds * if the access vector decisions were computed successfully. 4861da177e4SLinus Torvalds */ 4871da177e4SLinus Torvalds int security_compute_av(u32 ssid, 4881da177e4SLinus Torvalds u32 tsid, 4891da177e4SLinus Torvalds u16 tclass, 4901da177e4SLinus Torvalds u32 requested, 4911da177e4SLinus Torvalds struct av_decision *avd) 4921da177e4SLinus Torvalds { 4931da177e4SLinus Torvalds struct context *scontext = NULL, *tcontext = NULL; 4941da177e4SLinus Torvalds int rc = 0; 4951da177e4SLinus Torvalds 4961da177e4SLinus Torvalds if (!ss_initialized) { 4974c443d1bSStephen Smalley avd->allowed = 0xffffffff; 4984c443d1bSStephen Smalley avd->decided = 0xffffffff; 4991da177e4SLinus Torvalds avd->auditallow = 0; 5001da177e4SLinus Torvalds avd->auditdeny = 0xffffffff; 5011da177e4SLinus Torvalds avd->seqno = latest_granting; 5021da177e4SLinus Torvalds return 0; 5031da177e4SLinus Torvalds } 5041da177e4SLinus Torvalds 5051da177e4SLinus Torvalds POLICY_RDLOCK; 5061da177e4SLinus Torvalds 5071da177e4SLinus Torvalds scontext = sidtab_search(&sidtab, ssid); 5081da177e4SLinus Torvalds if (!scontext) { 5091da177e4SLinus Torvalds printk(KERN_ERR "security_compute_av: unrecognized SID %d\n", 5101da177e4SLinus Torvalds ssid); 5111da177e4SLinus Torvalds rc = -EINVAL; 5121da177e4SLinus Torvalds goto out; 5131da177e4SLinus Torvalds } 5141da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tsid); 5151da177e4SLinus Torvalds if (!tcontext) { 5161da177e4SLinus Torvalds printk(KERN_ERR "security_compute_av: unrecognized SID %d\n", 5171da177e4SLinus Torvalds tsid); 5181da177e4SLinus Torvalds rc = -EINVAL; 5191da177e4SLinus Torvalds goto out; 5201da177e4SLinus Torvalds } 5211da177e4SLinus Torvalds 5221da177e4SLinus Torvalds rc = context_struct_compute_av(scontext, tcontext, tclass, 5231da177e4SLinus Torvalds requested, avd); 5241da177e4SLinus Torvalds out: 5251da177e4SLinus Torvalds POLICY_RDUNLOCK; 5261da177e4SLinus Torvalds return rc; 5271da177e4SLinus Torvalds } 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds /* 5301da177e4SLinus Torvalds * Write the security context string representation of 5311da177e4SLinus Torvalds * the context structure `context' into a dynamically 5321da177e4SLinus Torvalds * allocated string of the correct size. Set `*scontext' 5331da177e4SLinus Torvalds * to point to this string and set `*scontext_len' to 5341da177e4SLinus Torvalds * the length of the string. 5351da177e4SLinus Torvalds */ 5361da177e4SLinus Torvalds static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len) 5371da177e4SLinus Torvalds { 5381da177e4SLinus Torvalds char *scontextp; 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds *scontext = NULL; 5411da177e4SLinus Torvalds *scontext_len = 0; 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds /* Compute the size of the context. */ 5441da177e4SLinus Torvalds *scontext_len += strlen(policydb.p_user_val_to_name[context->user - 1]) + 1; 5451da177e4SLinus Torvalds *scontext_len += strlen(policydb.p_role_val_to_name[context->role - 1]) + 1; 5461da177e4SLinus Torvalds *scontext_len += strlen(policydb.p_type_val_to_name[context->type - 1]) + 1; 5471da177e4SLinus Torvalds *scontext_len += mls_compute_context_len(context); 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds /* Allocate space for the context; caller must free this space. */ 5501da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC); 5511da177e4SLinus Torvalds if (!scontextp) { 5521da177e4SLinus Torvalds return -ENOMEM; 5531da177e4SLinus Torvalds } 5541da177e4SLinus Torvalds *scontext = scontextp; 5551da177e4SLinus Torvalds 5561da177e4SLinus Torvalds /* 5571da177e4SLinus Torvalds * Copy the user name, role name and type name into the context. 5581da177e4SLinus Torvalds */ 5591da177e4SLinus Torvalds sprintf(scontextp, "%s:%s:%s", 5601da177e4SLinus Torvalds policydb.p_user_val_to_name[context->user - 1], 5611da177e4SLinus Torvalds policydb.p_role_val_to_name[context->role - 1], 5621da177e4SLinus Torvalds policydb.p_type_val_to_name[context->type - 1]); 5631da177e4SLinus Torvalds scontextp += strlen(policydb.p_user_val_to_name[context->user - 1]) + 5641da177e4SLinus Torvalds 1 + strlen(policydb.p_role_val_to_name[context->role - 1]) + 5651da177e4SLinus Torvalds 1 + strlen(policydb.p_type_val_to_name[context->type - 1]); 5661da177e4SLinus Torvalds 5671da177e4SLinus Torvalds mls_sid_to_context(context, &scontextp); 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds *scontextp = 0; 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds return 0; 5721da177e4SLinus Torvalds } 5731da177e4SLinus Torvalds 5741da177e4SLinus Torvalds #include "initial_sid_to_string.h" 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds /** 5771da177e4SLinus Torvalds * security_sid_to_context - Obtain a context for a given SID. 5781da177e4SLinus Torvalds * @sid: security identifier, SID 5791da177e4SLinus Torvalds * @scontext: security context 5801da177e4SLinus Torvalds * @scontext_len: length in bytes 5811da177e4SLinus Torvalds * 5821da177e4SLinus Torvalds * Write the string representation of the context associated with @sid 5831da177e4SLinus Torvalds * into a dynamically allocated string of the correct size. Set @scontext 5841da177e4SLinus Torvalds * to point to this string and set @scontext_len to the length of the string. 5851da177e4SLinus Torvalds */ 5861da177e4SLinus Torvalds int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len) 5871da177e4SLinus Torvalds { 5881da177e4SLinus Torvalds struct context *context; 5891da177e4SLinus Torvalds int rc = 0; 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds if (!ss_initialized) { 5921da177e4SLinus Torvalds if (sid <= SECINITSID_NUM) { 5931da177e4SLinus Torvalds char *scontextp; 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds *scontext_len = strlen(initial_sid_to_string[sid]) + 1; 5961da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len,GFP_ATOMIC); 5970cccca06SSerge E. Hallyn if (!scontextp) { 5980cccca06SSerge E. Hallyn rc = -ENOMEM; 5990cccca06SSerge E. Hallyn goto out; 6000cccca06SSerge E. Hallyn } 6011da177e4SLinus Torvalds strcpy(scontextp, initial_sid_to_string[sid]); 6021da177e4SLinus Torvalds *scontext = scontextp; 6031da177e4SLinus Torvalds goto out; 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds printk(KERN_ERR "security_sid_to_context: called before initial " 6061da177e4SLinus Torvalds "load_policy on unknown SID %d\n", sid); 6071da177e4SLinus Torvalds rc = -EINVAL; 6081da177e4SLinus Torvalds goto out; 6091da177e4SLinus Torvalds } 6101da177e4SLinus Torvalds POLICY_RDLOCK; 6111da177e4SLinus Torvalds context = sidtab_search(&sidtab, sid); 6121da177e4SLinus Torvalds if (!context) { 6131da177e4SLinus Torvalds printk(KERN_ERR "security_sid_to_context: unrecognized SID " 6141da177e4SLinus Torvalds "%d\n", sid); 6151da177e4SLinus Torvalds rc = -EINVAL; 6161da177e4SLinus Torvalds goto out_unlock; 6171da177e4SLinus Torvalds } 6181da177e4SLinus Torvalds rc = context_struct_to_string(context, scontext, scontext_len); 6191da177e4SLinus Torvalds out_unlock: 6201da177e4SLinus Torvalds POLICY_RDUNLOCK; 6211da177e4SLinus Torvalds out: 6221da177e4SLinus Torvalds return rc; 6231da177e4SLinus Torvalds 6241da177e4SLinus Torvalds } 6251da177e4SLinus Torvalds 626f5c1d5b2SJames Morris static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid) 6271da177e4SLinus Torvalds { 6281da177e4SLinus Torvalds char *scontext2; 6291da177e4SLinus Torvalds struct context context; 6301da177e4SLinus Torvalds struct role_datum *role; 6311da177e4SLinus Torvalds struct type_datum *typdatum; 6321da177e4SLinus Torvalds struct user_datum *usrdatum; 6331da177e4SLinus Torvalds char *scontextp, *p, oldc; 6341da177e4SLinus Torvalds int rc = 0; 6351da177e4SLinus Torvalds 6361da177e4SLinus Torvalds if (!ss_initialized) { 6371da177e4SLinus Torvalds int i; 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds for (i = 1; i < SECINITSID_NUM; i++) { 6401da177e4SLinus Torvalds if (!strcmp(initial_sid_to_string[i], scontext)) { 6411da177e4SLinus Torvalds *sid = i; 6421da177e4SLinus Torvalds goto out; 6431da177e4SLinus Torvalds } 6441da177e4SLinus Torvalds } 6451da177e4SLinus Torvalds *sid = SECINITSID_KERNEL; 6461da177e4SLinus Torvalds goto out; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds *sid = SECSID_NULL; 6491da177e4SLinus Torvalds 6501da177e4SLinus Torvalds /* Copy the string so that we can modify the copy as we parse it. 6511da177e4SLinus Torvalds The string should already by null terminated, but we append a 6521da177e4SLinus Torvalds null suffix to the copy to avoid problems with the existing 6531da177e4SLinus Torvalds attr package, which doesn't view the null terminator as part 6541da177e4SLinus Torvalds of the attribute value. */ 6551da177e4SLinus Torvalds scontext2 = kmalloc(scontext_len+1,GFP_KERNEL); 6561da177e4SLinus Torvalds if (!scontext2) { 6571da177e4SLinus Torvalds rc = -ENOMEM; 6581da177e4SLinus Torvalds goto out; 6591da177e4SLinus Torvalds } 6601da177e4SLinus Torvalds memcpy(scontext2, scontext, scontext_len); 6611da177e4SLinus Torvalds scontext2[scontext_len] = 0; 6621da177e4SLinus Torvalds 6631da177e4SLinus Torvalds context_init(&context); 6641da177e4SLinus Torvalds *sid = SECSID_NULL; 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds POLICY_RDLOCK; 6671da177e4SLinus Torvalds 6681da177e4SLinus Torvalds /* Parse the security context. */ 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds rc = -EINVAL; 6711da177e4SLinus Torvalds scontextp = (char *) scontext2; 6721da177e4SLinus Torvalds 6731da177e4SLinus Torvalds /* Extract the user. */ 6741da177e4SLinus Torvalds p = scontextp; 6751da177e4SLinus Torvalds while (*p && *p != ':') 6761da177e4SLinus Torvalds p++; 6771da177e4SLinus Torvalds 6781da177e4SLinus Torvalds if (*p == 0) 6791da177e4SLinus Torvalds goto out_unlock; 6801da177e4SLinus Torvalds 6811da177e4SLinus Torvalds *p++ = 0; 6821da177e4SLinus Torvalds 6831da177e4SLinus Torvalds usrdatum = hashtab_search(policydb.p_users.table, scontextp); 6841da177e4SLinus Torvalds if (!usrdatum) 6851da177e4SLinus Torvalds goto out_unlock; 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds context.user = usrdatum->value; 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds /* Extract role. */ 6901da177e4SLinus Torvalds scontextp = p; 6911da177e4SLinus Torvalds while (*p && *p != ':') 6921da177e4SLinus Torvalds p++; 6931da177e4SLinus Torvalds 6941da177e4SLinus Torvalds if (*p == 0) 6951da177e4SLinus Torvalds goto out_unlock; 6961da177e4SLinus Torvalds 6971da177e4SLinus Torvalds *p++ = 0; 6981da177e4SLinus Torvalds 6991da177e4SLinus Torvalds role = hashtab_search(policydb.p_roles.table, scontextp); 7001da177e4SLinus Torvalds if (!role) 7011da177e4SLinus Torvalds goto out_unlock; 7021da177e4SLinus Torvalds context.role = role->value; 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds /* Extract type. */ 7051da177e4SLinus Torvalds scontextp = p; 7061da177e4SLinus Torvalds while (*p && *p != ':') 7071da177e4SLinus Torvalds p++; 7081da177e4SLinus Torvalds oldc = *p; 7091da177e4SLinus Torvalds *p++ = 0; 7101da177e4SLinus Torvalds 7111da177e4SLinus Torvalds typdatum = hashtab_search(policydb.p_types.table, scontextp); 7121da177e4SLinus Torvalds if (!typdatum) 7131da177e4SLinus Torvalds goto out_unlock; 7141da177e4SLinus Torvalds 7151da177e4SLinus Torvalds context.type = typdatum->value; 7161da177e4SLinus Torvalds 717f5c1d5b2SJames Morris rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid); 7181da177e4SLinus Torvalds if (rc) 7191da177e4SLinus Torvalds goto out_unlock; 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds if ((p - scontext2) < scontext_len) { 7221da177e4SLinus Torvalds rc = -EINVAL; 7231da177e4SLinus Torvalds goto out_unlock; 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds /* Check the validity of the new context. */ 7271da177e4SLinus Torvalds if (!policydb_context_isvalid(&policydb, &context)) { 7281da177e4SLinus Torvalds rc = -EINVAL; 7291da177e4SLinus Torvalds goto out_unlock; 7301da177e4SLinus Torvalds } 7311da177e4SLinus Torvalds /* Obtain the new sid. */ 7321da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &context, sid); 7331da177e4SLinus Torvalds out_unlock: 7341da177e4SLinus Torvalds POLICY_RDUNLOCK; 7351da177e4SLinus Torvalds context_destroy(&context); 7361da177e4SLinus Torvalds kfree(scontext2); 7371da177e4SLinus Torvalds out: 7381da177e4SLinus Torvalds return rc; 7391da177e4SLinus Torvalds } 7401da177e4SLinus Torvalds 741f5c1d5b2SJames Morris /** 742f5c1d5b2SJames Morris * security_context_to_sid - Obtain a SID for a given security context. 743f5c1d5b2SJames Morris * @scontext: security context 744f5c1d5b2SJames Morris * @scontext_len: length in bytes 745f5c1d5b2SJames Morris * @sid: security identifier, SID 746f5c1d5b2SJames Morris * 747f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 748f5c1d5b2SJames Morris * has the string representation specified by @scontext. 749f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 750f5c1d5b2SJames Morris * memory is available, or 0 on success. 751f5c1d5b2SJames Morris */ 752f5c1d5b2SJames Morris int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid) 753f5c1d5b2SJames Morris { 754f5c1d5b2SJames Morris return security_context_to_sid_core(scontext, scontext_len, 755f5c1d5b2SJames Morris sid, SECSID_NULL); 756f5c1d5b2SJames Morris } 757f5c1d5b2SJames Morris 758f5c1d5b2SJames Morris /** 759f5c1d5b2SJames Morris * security_context_to_sid_default - Obtain a SID for a given security context, 760f5c1d5b2SJames Morris * falling back to specified default if needed. 761f5c1d5b2SJames Morris * 762f5c1d5b2SJames Morris * @scontext: security context 763f5c1d5b2SJames Morris * @scontext_len: length in bytes 764f5c1d5b2SJames Morris * @sid: security identifier, SID 765f5c1d5b2SJames Morris * @def_sid: default SID to assign on errror 766f5c1d5b2SJames Morris * 767f5c1d5b2SJames Morris * Obtains a SID associated with the security context that 768f5c1d5b2SJames Morris * has the string representation specified by @scontext. 769f5c1d5b2SJames Morris * The default SID is passed to the MLS layer to be used to allow 770f5c1d5b2SJames Morris * kernel labeling of the MLS field if the MLS field is not present 771f5c1d5b2SJames Morris * (for upgrading to MLS without full relabel). 772f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient 773f5c1d5b2SJames Morris * memory is available, or 0 on success. 774f5c1d5b2SJames Morris */ 775f5c1d5b2SJames Morris int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid) 776f5c1d5b2SJames Morris { 777f5c1d5b2SJames Morris return security_context_to_sid_core(scontext, scontext_len, 778f5c1d5b2SJames Morris sid, def_sid); 779f5c1d5b2SJames Morris } 780f5c1d5b2SJames Morris 7811da177e4SLinus Torvalds static int compute_sid_handle_invalid_context( 7821da177e4SLinus Torvalds struct context *scontext, 7831da177e4SLinus Torvalds struct context *tcontext, 7841da177e4SLinus Torvalds u16 tclass, 7851da177e4SLinus Torvalds struct context *newcontext) 7861da177e4SLinus Torvalds { 7871da177e4SLinus Torvalds char *s = NULL, *t = NULL, *n = NULL; 7881da177e4SLinus Torvalds u32 slen, tlen, nlen; 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds if (context_struct_to_string(scontext, &s, &slen) < 0) 7911da177e4SLinus Torvalds goto out; 7921da177e4SLinus Torvalds if (context_struct_to_string(tcontext, &t, &tlen) < 0) 7931da177e4SLinus Torvalds goto out; 7941da177e4SLinus Torvalds if (context_struct_to_string(newcontext, &n, &nlen) < 0) 7951da177e4SLinus Torvalds goto out; 7969ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR, 7971da177e4SLinus Torvalds "security_compute_sid: invalid context %s" 7981da177e4SLinus Torvalds " for scontext=%s" 7991da177e4SLinus Torvalds " tcontext=%s" 8001da177e4SLinus Torvalds " tclass=%s", 8011da177e4SLinus Torvalds n, s, t, policydb.p_class_val_to_name[tclass-1]); 8021da177e4SLinus Torvalds out: 8031da177e4SLinus Torvalds kfree(s); 8041da177e4SLinus Torvalds kfree(t); 8051da177e4SLinus Torvalds kfree(n); 8061da177e4SLinus Torvalds if (!selinux_enforcing) 8071da177e4SLinus Torvalds return 0; 8081da177e4SLinus Torvalds return -EACCES; 8091da177e4SLinus Torvalds } 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds static int security_compute_sid(u32 ssid, 8121da177e4SLinus Torvalds u32 tsid, 8131da177e4SLinus Torvalds u16 tclass, 8141da177e4SLinus Torvalds u32 specified, 8151da177e4SLinus Torvalds u32 *out_sid) 8161da177e4SLinus Torvalds { 8171da177e4SLinus Torvalds struct context *scontext = NULL, *tcontext = NULL, newcontext; 8181da177e4SLinus Torvalds struct role_trans *roletr = NULL; 8191da177e4SLinus Torvalds struct avtab_key avkey; 8201da177e4SLinus Torvalds struct avtab_datum *avdatum; 8211da177e4SLinus Torvalds struct avtab_node *node; 8221da177e4SLinus Torvalds int rc = 0; 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds if (!ss_initialized) { 8251da177e4SLinus Torvalds switch (tclass) { 8261da177e4SLinus Torvalds case SECCLASS_PROCESS: 8271da177e4SLinus Torvalds *out_sid = ssid; 8281da177e4SLinus Torvalds break; 8291da177e4SLinus Torvalds default: 8301da177e4SLinus Torvalds *out_sid = tsid; 8311da177e4SLinus Torvalds break; 8321da177e4SLinus Torvalds } 8331da177e4SLinus Torvalds goto out; 8341da177e4SLinus Torvalds } 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds POLICY_RDLOCK; 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds scontext = sidtab_search(&sidtab, ssid); 8391da177e4SLinus Torvalds if (!scontext) { 8401da177e4SLinus Torvalds printk(KERN_ERR "security_compute_sid: unrecognized SID %d\n", 8411da177e4SLinus Torvalds ssid); 8421da177e4SLinus Torvalds rc = -EINVAL; 8431da177e4SLinus Torvalds goto out_unlock; 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds tcontext = sidtab_search(&sidtab, tsid); 8461da177e4SLinus Torvalds if (!tcontext) { 8471da177e4SLinus Torvalds printk(KERN_ERR "security_compute_sid: unrecognized SID %d\n", 8481da177e4SLinus Torvalds tsid); 8491da177e4SLinus Torvalds rc = -EINVAL; 8501da177e4SLinus Torvalds goto out_unlock; 8511da177e4SLinus Torvalds } 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds context_init(&newcontext); 8541da177e4SLinus Torvalds 8551da177e4SLinus Torvalds /* Set the user identity. */ 8561da177e4SLinus Torvalds switch (specified) { 8571da177e4SLinus Torvalds case AVTAB_TRANSITION: 8581da177e4SLinus Torvalds case AVTAB_CHANGE: 8591da177e4SLinus Torvalds /* Use the process user identity. */ 8601da177e4SLinus Torvalds newcontext.user = scontext->user; 8611da177e4SLinus Torvalds break; 8621da177e4SLinus Torvalds case AVTAB_MEMBER: 8631da177e4SLinus Torvalds /* Use the related object owner. */ 8641da177e4SLinus Torvalds newcontext.user = tcontext->user; 8651da177e4SLinus Torvalds break; 8661da177e4SLinus Torvalds } 8671da177e4SLinus Torvalds 8681da177e4SLinus Torvalds /* Set the role and type to default values. */ 8691da177e4SLinus Torvalds switch (tclass) { 8701da177e4SLinus Torvalds case SECCLASS_PROCESS: 8711da177e4SLinus Torvalds /* Use the current role and type of process. */ 8721da177e4SLinus Torvalds newcontext.role = scontext->role; 8731da177e4SLinus Torvalds newcontext.type = scontext->type; 8741da177e4SLinus Torvalds break; 8751da177e4SLinus Torvalds default: 8761da177e4SLinus Torvalds /* Use the well-defined object role. */ 8771da177e4SLinus Torvalds newcontext.role = OBJECT_R_VAL; 8781da177e4SLinus Torvalds /* Use the type of the related object. */ 8791da177e4SLinus Torvalds newcontext.type = tcontext->type; 8801da177e4SLinus Torvalds } 8811da177e4SLinus Torvalds 8821da177e4SLinus Torvalds /* Look for a type transition/member/change rule. */ 8831da177e4SLinus Torvalds avkey.source_type = scontext->type; 8841da177e4SLinus Torvalds avkey.target_type = tcontext->type; 8851da177e4SLinus Torvalds avkey.target_class = tclass; 886782ebb99SStephen Smalley avkey.specified = specified; 887782ebb99SStephen Smalley avdatum = avtab_search(&policydb.te_avtab, &avkey); 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds /* If no permanent rule, also check for enabled conditional rules */ 8901da177e4SLinus Torvalds if(!avdatum) { 891782ebb99SStephen Smalley node = avtab_search_node(&policydb.te_cond_avtab, &avkey); 8921da177e4SLinus Torvalds for (; node != NULL; node = avtab_search_node_next(node, specified)) { 893782ebb99SStephen Smalley if (node->key.specified & AVTAB_ENABLED) { 8941da177e4SLinus Torvalds avdatum = &node->datum; 8951da177e4SLinus Torvalds break; 8961da177e4SLinus Torvalds } 8971da177e4SLinus Torvalds } 8981da177e4SLinus Torvalds } 8991da177e4SLinus Torvalds 900782ebb99SStephen Smalley if (avdatum) { 9011da177e4SLinus Torvalds /* Use the type from the type transition/member/change rule. */ 902782ebb99SStephen Smalley newcontext.type = avdatum->data; 9031da177e4SLinus Torvalds } 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds /* Check for class-specific changes. */ 9061da177e4SLinus Torvalds switch (tclass) { 9071da177e4SLinus Torvalds case SECCLASS_PROCESS: 9081da177e4SLinus Torvalds if (specified & AVTAB_TRANSITION) { 9091da177e4SLinus Torvalds /* Look for a role transition rule. */ 9101da177e4SLinus Torvalds for (roletr = policydb.role_tr; roletr; 9111da177e4SLinus Torvalds roletr = roletr->next) { 9121da177e4SLinus Torvalds if (roletr->role == scontext->role && 9131da177e4SLinus Torvalds roletr->type == tcontext->type) { 9141da177e4SLinus Torvalds /* Use the role transition rule. */ 9151da177e4SLinus Torvalds newcontext.role = roletr->new_role; 9161da177e4SLinus Torvalds break; 9171da177e4SLinus Torvalds } 9181da177e4SLinus Torvalds } 9191da177e4SLinus Torvalds } 9201da177e4SLinus Torvalds break; 9211da177e4SLinus Torvalds default: 9221da177e4SLinus Torvalds break; 9231da177e4SLinus Torvalds } 9241da177e4SLinus Torvalds 9251da177e4SLinus Torvalds /* Set the MLS attributes. 9261da177e4SLinus Torvalds This is done last because it may allocate memory. */ 9271da177e4SLinus Torvalds rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext); 9281da177e4SLinus Torvalds if (rc) 9291da177e4SLinus Torvalds goto out_unlock; 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds /* Check the validity of the context. */ 9321da177e4SLinus Torvalds if (!policydb_context_isvalid(&policydb, &newcontext)) { 9331da177e4SLinus Torvalds rc = compute_sid_handle_invalid_context(scontext, 9341da177e4SLinus Torvalds tcontext, 9351da177e4SLinus Torvalds tclass, 9361da177e4SLinus Torvalds &newcontext); 9371da177e4SLinus Torvalds if (rc) 9381da177e4SLinus Torvalds goto out_unlock; 9391da177e4SLinus Torvalds } 9401da177e4SLinus Torvalds /* Obtain the sid for the context. */ 9411da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid); 9421da177e4SLinus Torvalds out_unlock: 9431da177e4SLinus Torvalds POLICY_RDUNLOCK; 9441da177e4SLinus Torvalds context_destroy(&newcontext); 9451da177e4SLinus Torvalds out: 9461da177e4SLinus Torvalds return rc; 9471da177e4SLinus Torvalds } 9481da177e4SLinus Torvalds 9491da177e4SLinus Torvalds /** 9501da177e4SLinus Torvalds * security_transition_sid - Compute the SID for a new subject/object. 9511da177e4SLinus Torvalds * @ssid: source security identifier 9521da177e4SLinus Torvalds * @tsid: target security identifier 9531da177e4SLinus Torvalds * @tclass: target security class 9541da177e4SLinus Torvalds * @out_sid: security identifier for new subject/object 9551da177e4SLinus Torvalds * 9561da177e4SLinus Torvalds * Compute a SID to use for labeling a new subject or object in the 9571da177e4SLinus Torvalds * class @tclass based on a SID pair (@ssid, @tsid). 9581da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 9591da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the new SID was 9601da177e4SLinus Torvalds * computed successfully. 9611da177e4SLinus Torvalds */ 9621da177e4SLinus Torvalds int security_transition_sid(u32 ssid, 9631da177e4SLinus Torvalds u32 tsid, 9641da177e4SLinus Torvalds u16 tclass, 9651da177e4SLinus Torvalds u32 *out_sid) 9661da177e4SLinus Torvalds { 9671da177e4SLinus Torvalds return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid); 9681da177e4SLinus Torvalds } 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds /** 9711da177e4SLinus Torvalds * security_member_sid - Compute the SID for member selection. 9721da177e4SLinus Torvalds * @ssid: source security identifier 9731da177e4SLinus Torvalds * @tsid: target security identifier 9741da177e4SLinus Torvalds * @tclass: target security class 9751da177e4SLinus Torvalds * @out_sid: security identifier for selected member 9761da177e4SLinus Torvalds * 9771da177e4SLinus Torvalds * Compute a SID to use when selecting a member of a polyinstantiated 9781da177e4SLinus Torvalds * object of class @tclass based on a SID pair (@ssid, @tsid). 9791da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 9801da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 9811da177e4SLinus Torvalds * computed successfully. 9821da177e4SLinus Torvalds */ 9831da177e4SLinus Torvalds int security_member_sid(u32 ssid, 9841da177e4SLinus Torvalds u32 tsid, 9851da177e4SLinus Torvalds u16 tclass, 9861da177e4SLinus Torvalds u32 *out_sid) 9871da177e4SLinus Torvalds { 9881da177e4SLinus Torvalds return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid); 9891da177e4SLinus Torvalds } 9901da177e4SLinus Torvalds 9911da177e4SLinus Torvalds /** 9921da177e4SLinus Torvalds * security_change_sid - Compute the SID for object relabeling. 9931da177e4SLinus Torvalds * @ssid: source security identifier 9941da177e4SLinus Torvalds * @tsid: target security identifier 9951da177e4SLinus Torvalds * @tclass: target security class 9961da177e4SLinus Torvalds * @out_sid: security identifier for selected member 9971da177e4SLinus Torvalds * 9981da177e4SLinus Torvalds * Compute a SID to use for relabeling an object of class @tclass 9991da177e4SLinus Torvalds * based on a SID pair (@ssid, @tsid). 10001da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM 10011da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was 10021da177e4SLinus Torvalds * computed successfully. 10031da177e4SLinus Torvalds */ 10041da177e4SLinus Torvalds int security_change_sid(u32 ssid, 10051da177e4SLinus Torvalds u32 tsid, 10061da177e4SLinus Torvalds u16 tclass, 10071da177e4SLinus Torvalds u32 *out_sid) 10081da177e4SLinus Torvalds { 10091da177e4SLinus Torvalds return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid); 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds 10121da177e4SLinus Torvalds /* 10131da177e4SLinus Torvalds * Verify that each permission that is defined under the 10141da177e4SLinus Torvalds * existing policy is still defined with the same value 10151da177e4SLinus Torvalds * in the new policy. 10161da177e4SLinus Torvalds */ 10171da177e4SLinus Torvalds static int validate_perm(void *key, void *datum, void *p) 10181da177e4SLinus Torvalds { 10191da177e4SLinus Torvalds struct hashtab *h; 10201da177e4SLinus Torvalds struct perm_datum *perdatum, *perdatum2; 10211da177e4SLinus Torvalds int rc = 0; 10221da177e4SLinus Torvalds 10231da177e4SLinus Torvalds 10241da177e4SLinus Torvalds h = p; 10251da177e4SLinus Torvalds perdatum = datum; 10261da177e4SLinus Torvalds 10271da177e4SLinus Torvalds perdatum2 = hashtab_search(h, key); 10281da177e4SLinus Torvalds if (!perdatum2) { 10291da177e4SLinus Torvalds printk(KERN_ERR "security: permission %s disappeared", 10301da177e4SLinus Torvalds (char *)key); 10311da177e4SLinus Torvalds rc = -ENOENT; 10321da177e4SLinus Torvalds goto out; 10331da177e4SLinus Torvalds } 10341da177e4SLinus Torvalds if (perdatum->value != perdatum2->value) { 10351da177e4SLinus Torvalds printk(KERN_ERR "security: the value of permission %s changed", 10361da177e4SLinus Torvalds (char *)key); 10371da177e4SLinus Torvalds rc = -EINVAL; 10381da177e4SLinus Torvalds } 10391da177e4SLinus Torvalds out: 10401da177e4SLinus Torvalds return rc; 10411da177e4SLinus Torvalds } 10421da177e4SLinus Torvalds 10431da177e4SLinus Torvalds /* 10441da177e4SLinus Torvalds * Verify that each class that is defined under the 10451da177e4SLinus Torvalds * existing policy is still defined with the same 10461da177e4SLinus Torvalds * attributes in the new policy. 10471da177e4SLinus Torvalds */ 10481da177e4SLinus Torvalds static int validate_class(void *key, void *datum, void *p) 10491da177e4SLinus Torvalds { 10501da177e4SLinus Torvalds struct policydb *newp; 10511da177e4SLinus Torvalds struct class_datum *cladatum, *cladatum2; 10521da177e4SLinus Torvalds int rc; 10531da177e4SLinus Torvalds 10541da177e4SLinus Torvalds newp = p; 10551da177e4SLinus Torvalds cladatum = datum; 10561da177e4SLinus Torvalds 10571da177e4SLinus Torvalds cladatum2 = hashtab_search(newp->p_classes.table, key); 10581da177e4SLinus Torvalds if (!cladatum2) { 10591da177e4SLinus Torvalds printk(KERN_ERR "security: class %s disappeared\n", 10601da177e4SLinus Torvalds (char *)key); 10611da177e4SLinus Torvalds rc = -ENOENT; 10621da177e4SLinus Torvalds goto out; 10631da177e4SLinus Torvalds } 10641da177e4SLinus Torvalds if (cladatum->value != cladatum2->value) { 10651da177e4SLinus Torvalds printk(KERN_ERR "security: the value of class %s changed\n", 10661da177e4SLinus Torvalds (char *)key); 10671da177e4SLinus Torvalds rc = -EINVAL; 10681da177e4SLinus Torvalds goto out; 10691da177e4SLinus Torvalds } 10701da177e4SLinus Torvalds if ((cladatum->comdatum && !cladatum2->comdatum) || 10711da177e4SLinus Torvalds (!cladatum->comdatum && cladatum2->comdatum)) { 10721da177e4SLinus Torvalds printk(KERN_ERR "security: the inherits clause for the access " 10731da177e4SLinus Torvalds "vector definition for class %s changed\n", (char *)key); 10741da177e4SLinus Torvalds rc = -EINVAL; 10751da177e4SLinus Torvalds goto out; 10761da177e4SLinus Torvalds } 10771da177e4SLinus Torvalds if (cladatum->comdatum) { 10781da177e4SLinus Torvalds rc = hashtab_map(cladatum->comdatum->permissions.table, validate_perm, 10791da177e4SLinus Torvalds cladatum2->comdatum->permissions.table); 10801da177e4SLinus Torvalds if (rc) { 10811da177e4SLinus Torvalds printk(" in the access vector definition for class " 10821da177e4SLinus Torvalds "%s\n", (char *)key); 10831da177e4SLinus Torvalds goto out; 10841da177e4SLinus Torvalds } 10851da177e4SLinus Torvalds } 10861da177e4SLinus Torvalds rc = hashtab_map(cladatum->permissions.table, validate_perm, 10871da177e4SLinus Torvalds cladatum2->permissions.table); 10881da177e4SLinus Torvalds if (rc) 10891da177e4SLinus Torvalds printk(" in access vector definition for class %s\n", 10901da177e4SLinus Torvalds (char *)key); 10911da177e4SLinus Torvalds out: 10921da177e4SLinus Torvalds return rc; 10931da177e4SLinus Torvalds } 10941da177e4SLinus Torvalds 10951da177e4SLinus Torvalds /* Clone the SID into the new SID table. */ 10961da177e4SLinus Torvalds static int clone_sid(u32 sid, 10971da177e4SLinus Torvalds struct context *context, 10981da177e4SLinus Torvalds void *arg) 10991da177e4SLinus Torvalds { 11001da177e4SLinus Torvalds struct sidtab *s = arg; 11011da177e4SLinus Torvalds 11021da177e4SLinus Torvalds return sidtab_insert(s, sid, context); 11031da177e4SLinus Torvalds } 11041da177e4SLinus Torvalds 11051da177e4SLinus Torvalds static inline int convert_context_handle_invalid_context(struct context *context) 11061da177e4SLinus Torvalds { 11071da177e4SLinus Torvalds int rc = 0; 11081da177e4SLinus Torvalds 11091da177e4SLinus Torvalds if (selinux_enforcing) { 11101da177e4SLinus Torvalds rc = -EINVAL; 11111da177e4SLinus Torvalds } else { 11121da177e4SLinus Torvalds char *s; 11131da177e4SLinus Torvalds u32 len; 11141da177e4SLinus Torvalds 11151da177e4SLinus Torvalds context_struct_to_string(context, &s, &len); 11161da177e4SLinus Torvalds printk(KERN_ERR "security: context %s is invalid\n", s); 11171da177e4SLinus Torvalds kfree(s); 11181da177e4SLinus Torvalds } 11191da177e4SLinus Torvalds return rc; 11201da177e4SLinus Torvalds } 11211da177e4SLinus Torvalds 11221da177e4SLinus Torvalds struct convert_context_args { 11231da177e4SLinus Torvalds struct policydb *oldp; 11241da177e4SLinus Torvalds struct policydb *newp; 11251da177e4SLinus Torvalds }; 11261da177e4SLinus Torvalds 11271da177e4SLinus Torvalds /* 11281da177e4SLinus Torvalds * Convert the values in the security context 11291da177e4SLinus Torvalds * structure `c' from the values specified 11301da177e4SLinus Torvalds * in the policy `p->oldp' to the values specified 11311da177e4SLinus Torvalds * in the policy `p->newp'. Verify that the 11321da177e4SLinus Torvalds * context is valid under the new policy. 11331da177e4SLinus Torvalds */ 11341da177e4SLinus Torvalds static int convert_context(u32 key, 11351da177e4SLinus Torvalds struct context *c, 11361da177e4SLinus Torvalds void *p) 11371da177e4SLinus Torvalds { 11381da177e4SLinus Torvalds struct convert_context_args *args; 11391da177e4SLinus Torvalds struct context oldc; 11401da177e4SLinus Torvalds struct role_datum *role; 11411da177e4SLinus Torvalds struct type_datum *typdatum; 11421da177e4SLinus Torvalds struct user_datum *usrdatum; 11431da177e4SLinus Torvalds char *s; 11441da177e4SLinus Torvalds u32 len; 11451da177e4SLinus Torvalds int rc; 11461da177e4SLinus Torvalds 11471da177e4SLinus Torvalds args = p; 11481da177e4SLinus Torvalds 11491da177e4SLinus Torvalds rc = context_cpy(&oldc, c); 11501da177e4SLinus Torvalds if (rc) 11511da177e4SLinus Torvalds goto out; 11521da177e4SLinus Torvalds 11531da177e4SLinus Torvalds rc = -EINVAL; 11541da177e4SLinus Torvalds 11551da177e4SLinus Torvalds /* Convert the user. */ 11561da177e4SLinus Torvalds usrdatum = hashtab_search(args->newp->p_users.table, 11571da177e4SLinus Torvalds args->oldp->p_user_val_to_name[c->user - 1]); 11581da177e4SLinus Torvalds if (!usrdatum) { 11591da177e4SLinus Torvalds goto bad; 11601da177e4SLinus Torvalds } 11611da177e4SLinus Torvalds c->user = usrdatum->value; 11621da177e4SLinus Torvalds 11631da177e4SLinus Torvalds /* Convert the role. */ 11641da177e4SLinus Torvalds role = hashtab_search(args->newp->p_roles.table, 11651da177e4SLinus Torvalds args->oldp->p_role_val_to_name[c->role - 1]); 11661da177e4SLinus Torvalds if (!role) { 11671da177e4SLinus Torvalds goto bad; 11681da177e4SLinus Torvalds } 11691da177e4SLinus Torvalds c->role = role->value; 11701da177e4SLinus Torvalds 11711da177e4SLinus Torvalds /* Convert the type. */ 11721da177e4SLinus Torvalds typdatum = hashtab_search(args->newp->p_types.table, 11731da177e4SLinus Torvalds args->oldp->p_type_val_to_name[c->type - 1]); 11741da177e4SLinus Torvalds if (!typdatum) { 11751da177e4SLinus Torvalds goto bad; 11761da177e4SLinus Torvalds } 11771da177e4SLinus Torvalds c->type = typdatum->value; 11781da177e4SLinus Torvalds 11791da177e4SLinus Torvalds rc = mls_convert_context(args->oldp, args->newp, c); 11801da177e4SLinus Torvalds if (rc) 11811da177e4SLinus Torvalds goto bad; 11821da177e4SLinus Torvalds 11831da177e4SLinus Torvalds /* Check the validity of the new context. */ 11841da177e4SLinus Torvalds if (!policydb_context_isvalid(args->newp, c)) { 11851da177e4SLinus Torvalds rc = convert_context_handle_invalid_context(&oldc); 11861da177e4SLinus Torvalds if (rc) 11871da177e4SLinus Torvalds goto bad; 11881da177e4SLinus Torvalds } 11891da177e4SLinus Torvalds 11901da177e4SLinus Torvalds context_destroy(&oldc); 11911da177e4SLinus Torvalds out: 11921da177e4SLinus Torvalds return rc; 11931da177e4SLinus Torvalds bad: 11941da177e4SLinus Torvalds context_struct_to_string(&oldc, &s, &len); 11951da177e4SLinus Torvalds context_destroy(&oldc); 11961da177e4SLinus Torvalds printk(KERN_ERR "security: invalidating context %s\n", s); 11971da177e4SLinus Torvalds kfree(s); 11981da177e4SLinus Torvalds goto out; 11991da177e4SLinus Torvalds } 12001da177e4SLinus Torvalds 12011da177e4SLinus Torvalds extern void selinux_complete_init(void); 12021da177e4SLinus Torvalds 12031da177e4SLinus Torvalds /** 12041da177e4SLinus Torvalds * security_load_policy - Load a security policy configuration. 12051da177e4SLinus Torvalds * @data: binary policy data 12061da177e4SLinus Torvalds * @len: length of data in bytes 12071da177e4SLinus Torvalds * 12081da177e4SLinus Torvalds * Load a new set of security policy configuration data, 12091da177e4SLinus Torvalds * validate it and convert the SID table as necessary. 12101da177e4SLinus Torvalds * This function will flush the access vector cache after 12111da177e4SLinus Torvalds * loading the new policy. 12121da177e4SLinus Torvalds */ 12131da177e4SLinus Torvalds int security_load_policy(void *data, size_t len) 12141da177e4SLinus Torvalds { 12151da177e4SLinus Torvalds struct policydb oldpolicydb, newpolicydb; 12161da177e4SLinus Torvalds struct sidtab oldsidtab, newsidtab; 12171da177e4SLinus Torvalds struct convert_context_args args; 12181da177e4SLinus Torvalds u32 seqno; 12191da177e4SLinus Torvalds int rc = 0; 12201da177e4SLinus Torvalds struct policy_file file = { data, len }, *fp = &file; 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds LOAD_LOCK; 12231da177e4SLinus Torvalds 12241da177e4SLinus Torvalds if (!ss_initialized) { 12251da177e4SLinus Torvalds avtab_cache_init(); 12261da177e4SLinus Torvalds if (policydb_read(&policydb, fp)) { 12271da177e4SLinus Torvalds LOAD_UNLOCK; 12281da177e4SLinus Torvalds avtab_cache_destroy(); 12291da177e4SLinus Torvalds return -EINVAL; 12301da177e4SLinus Torvalds } 12311da177e4SLinus Torvalds if (policydb_load_isids(&policydb, &sidtab)) { 12321da177e4SLinus Torvalds LOAD_UNLOCK; 12331da177e4SLinus Torvalds policydb_destroy(&policydb); 12341da177e4SLinus Torvalds avtab_cache_destroy(); 12351da177e4SLinus Torvalds return -EINVAL; 12361da177e4SLinus Torvalds } 12371da177e4SLinus Torvalds policydb_loaded_version = policydb.policyvers; 12381da177e4SLinus Torvalds ss_initialized = 1; 12394c443d1bSStephen Smalley seqno = ++latest_granting; 12401da177e4SLinus Torvalds LOAD_UNLOCK; 12411da177e4SLinus Torvalds selinux_complete_init(); 12424c443d1bSStephen Smalley avc_ss_reset(seqno); 12434c443d1bSStephen Smalley selnl_notify_policyload(seqno); 12441da177e4SLinus Torvalds return 0; 12451da177e4SLinus Torvalds } 12461da177e4SLinus Torvalds 12471da177e4SLinus Torvalds #if 0 12481da177e4SLinus Torvalds sidtab_hash_eval(&sidtab, "sids"); 12491da177e4SLinus Torvalds #endif 12501da177e4SLinus Torvalds 12511da177e4SLinus Torvalds if (policydb_read(&newpolicydb, fp)) { 12521da177e4SLinus Torvalds LOAD_UNLOCK; 12531da177e4SLinus Torvalds return -EINVAL; 12541da177e4SLinus Torvalds } 12551da177e4SLinus Torvalds 12561da177e4SLinus Torvalds sidtab_init(&newsidtab); 12571da177e4SLinus Torvalds 12581da177e4SLinus Torvalds /* Verify that the existing classes did not change. */ 12591da177e4SLinus Torvalds if (hashtab_map(policydb.p_classes.table, validate_class, &newpolicydb)) { 12601da177e4SLinus Torvalds printk(KERN_ERR "security: the definition of an existing " 12611da177e4SLinus Torvalds "class changed\n"); 12621da177e4SLinus Torvalds rc = -EINVAL; 12631da177e4SLinus Torvalds goto err; 12641da177e4SLinus Torvalds } 12651da177e4SLinus Torvalds 12661da177e4SLinus Torvalds /* Clone the SID table. */ 12671da177e4SLinus Torvalds sidtab_shutdown(&sidtab); 12681da177e4SLinus Torvalds if (sidtab_map(&sidtab, clone_sid, &newsidtab)) { 12691da177e4SLinus Torvalds rc = -ENOMEM; 12701da177e4SLinus Torvalds goto err; 12711da177e4SLinus Torvalds } 12721da177e4SLinus Torvalds 12731da177e4SLinus Torvalds /* Convert the internal representations of contexts 12741da177e4SLinus Torvalds in the new SID table and remove invalid SIDs. */ 12751da177e4SLinus Torvalds args.oldp = &policydb; 12761da177e4SLinus Torvalds args.newp = &newpolicydb; 12771da177e4SLinus Torvalds sidtab_map_remove_on_error(&newsidtab, convert_context, &args); 12781da177e4SLinus Torvalds 12791da177e4SLinus Torvalds /* Save the old policydb and SID table to free later. */ 12801da177e4SLinus Torvalds memcpy(&oldpolicydb, &policydb, sizeof policydb); 12811da177e4SLinus Torvalds sidtab_set(&oldsidtab, &sidtab); 12821da177e4SLinus Torvalds 12831da177e4SLinus Torvalds /* Install the new policydb and SID table. */ 12841da177e4SLinus Torvalds POLICY_WRLOCK; 12851da177e4SLinus Torvalds memcpy(&policydb, &newpolicydb, sizeof policydb); 12861da177e4SLinus Torvalds sidtab_set(&sidtab, &newsidtab); 12871da177e4SLinus Torvalds seqno = ++latest_granting; 12881da177e4SLinus Torvalds policydb_loaded_version = policydb.policyvers; 12891da177e4SLinus Torvalds POLICY_WRUNLOCK; 12901da177e4SLinus Torvalds LOAD_UNLOCK; 12911da177e4SLinus Torvalds 12921da177e4SLinus Torvalds /* Free the old policydb and SID table. */ 12931da177e4SLinus Torvalds policydb_destroy(&oldpolicydb); 12941da177e4SLinus Torvalds sidtab_destroy(&oldsidtab); 12951da177e4SLinus Torvalds 12961da177e4SLinus Torvalds avc_ss_reset(seqno); 12971da177e4SLinus Torvalds selnl_notify_policyload(seqno); 12981da177e4SLinus Torvalds 12991da177e4SLinus Torvalds return 0; 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds err: 13021da177e4SLinus Torvalds LOAD_UNLOCK; 13031da177e4SLinus Torvalds sidtab_destroy(&newsidtab); 13041da177e4SLinus Torvalds policydb_destroy(&newpolicydb); 13051da177e4SLinus Torvalds return rc; 13061da177e4SLinus Torvalds 13071da177e4SLinus Torvalds } 13081da177e4SLinus Torvalds 13091da177e4SLinus Torvalds /** 13101da177e4SLinus Torvalds * security_port_sid - Obtain the SID for a port. 13111da177e4SLinus Torvalds * @domain: communication domain aka address family 13121da177e4SLinus Torvalds * @type: socket type 13131da177e4SLinus Torvalds * @protocol: protocol number 13141da177e4SLinus Torvalds * @port: port number 13151da177e4SLinus Torvalds * @out_sid: security identifier 13161da177e4SLinus Torvalds */ 13171da177e4SLinus Torvalds int security_port_sid(u16 domain, 13181da177e4SLinus Torvalds u16 type, 13191da177e4SLinus Torvalds u8 protocol, 13201da177e4SLinus Torvalds u16 port, 13211da177e4SLinus Torvalds u32 *out_sid) 13221da177e4SLinus Torvalds { 13231da177e4SLinus Torvalds struct ocontext *c; 13241da177e4SLinus Torvalds int rc = 0; 13251da177e4SLinus Torvalds 13261da177e4SLinus Torvalds POLICY_RDLOCK; 13271da177e4SLinus Torvalds 13281da177e4SLinus Torvalds c = policydb.ocontexts[OCON_PORT]; 13291da177e4SLinus Torvalds while (c) { 13301da177e4SLinus Torvalds if (c->u.port.protocol == protocol && 13311da177e4SLinus Torvalds c->u.port.low_port <= port && 13321da177e4SLinus Torvalds c->u.port.high_port >= port) 13331da177e4SLinus Torvalds break; 13341da177e4SLinus Torvalds c = c->next; 13351da177e4SLinus Torvalds } 13361da177e4SLinus Torvalds 13371da177e4SLinus Torvalds if (c) { 13381da177e4SLinus Torvalds if (!c->sid[0]) { 13391da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 13401da177e4SLinus Torvalds &c->context[0], 13411da177e4SLinus Torvalds &c->sid[0]); 13421da177e4SLinus Torvalds if (rc) 13431da177e4SLinus Torvalds goto out; 13441da177e4SLinus Torvalds } 13451da177e4SLinus Torvalds *out_sid = c->sid[0]; 13461da177e4SLinus Torvalds } else { 13471da177e4SLinus Torvalds *out_sid = SECINITSID_PORT; 13481da177e4SLinus Torvalds } 13491da177e4SLinus Torvalds 13501da177e4SLinus Torvalds out: 13511da177e4SLinus Torvalds POLICY_RDUNLOCK; 13521da177e4SLinus Torvalds return rc; 13531da177e4SLinus Torvalds } 13541da177e4SLinus Torvalds 13551da177e4SLinus Torvalds /** 13561da177e4SLinus Torvalds * security_netif_sid - Obtain the SID for a network interface. 13571da177e4SLinus Torvalds * @name: interface name 13581da177e4SLinus Torvalds * @if_sid: interface SID 13591da177e4SLinus Torvalds * @msg_sid: default SID for received packets 13601da177e4SLinus Torvalds */ 13611da177e4SLinus Torvalds int security_netif_sid(char *name, 13621da177e4SLinus Torvalds u32 *if_sid, 13631da177e4SLinus Torvalds u32 *msg_sid) 13641da177e4SLinus Torvalds { 13651da177e4SLinus Torvalds int rc = 0; 13661da177e4SLinus Torvalds struct ocontext *c; 13671da177e4SLinus Torvalds 13681da177e4SLinus Torvalds POLICY_RDLOCK; 13691da177e4SLinus Torvalds 13701da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NETIF]; 13711da177e4SLinus Torvalds while (c) { 13721da177e4SLinus Torvalds if (strcmp(name, c->u.name) == 0) 13731da177e4SLinus Torvalds break; 13741da177e4SLinus Torvalds c = c->next; 13751da177e4SLinus Torvalds } 13761da177e4SLinus Torvalds 13771da177e4SLinus Torvalds if (c) { 13781da177e4SLinus Torvalds if (!c->sid[0] || !c->sid[1]) { 13791da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 13801da177e4SLinus Torvalds &c->context[0], 13811da177e4SLinus Torvalds &c->sid[0]); 13821da177e4SLinus Torvalds if (rc) 13831da177e4SLinus Torvalds goto out; 13841da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 13851da177e4SLinus Torvalds &c->context[1], 13861da177e4SLinus Torvalds &c->sid[1]); 13871da177e4SLinus Torvalds if (rc) 13881da177e4SLinus Torvalds goto out; 13891da177e4SLinus Torvalds } 13901da177e4SLinus Torvalds *if_sid = c->sid[0]; 13911da177e4SLinus Torvalds *msg_sid = c->sid[1]; 13921da177e4SLinus Torvalds } else { 13931da177e4SLinus Torvalds *if_sid = SECINITSID_NETIF; 13941da177e4SLinus Torvalds *msg_sid = SECINITSID_NETMSG; 13951da177e4SLinus Torvalds } 13961da177e4SLinus Torvalds 13971da177e4SLinus Torvalds out: 13981da177e4SLinus Torvalds POLICY_RDUNLOCK; 13991da177e4SLinus Torvalds return rc; 14001da177e4SLinus Torvalds } 14011da177e4SLinus Torvalds 14021da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask) 14031da177e4SLinus Torvalds { 14041da177e4SLinus Torvalds int i, fail = 0; 14051da177e4SLinus Torvalds 14061da177e4SLinus Torvalds for(i = 0; i < 4; i++) 14071da177e4SLinus Torvalds if(addr[i] != (input[i] & mask[i])) { 14081da177e4SLinus Torvalds fail = 1; 14091da177e4SLinus Torvalds break; 14101da177e4SLinus Torvalds } 14111da177e4SLinus Torvalds 14121da177e4SLinus Torvalds return !fail; 14131da177e4SLinus Torvalds } 14141da177e4SLinus Torvalds 14151da177e4SLinus Torvalds /** 14161da177e4SLinus Torvalds * security_node_sid - Obtain the SID for a node (host). 14171da177e4SLinus Torvalds * @domain: communication domain aka address family 14181da177e4SLinus Torvalds * @addrp: address 14191da177e4SLinus Torvalds * @addrlen: address length in bytes 14201da177e4SLinus Torvalds * @out_sid: security identifier 14211da177e4SLinus Torvalds */ 14221da177e4SLinus Torvalds int security_node_sid(u16 domain, 14231da177e4SLinus Torvalds void *addrp, 14241da177e4SLinus Torvalds u32 addrlen, 14251da177e4SLinus Torvalds u32 *out_sid) 14261da177e4SLinus Torvalds { 14271da177e4SLinus Torvalds int rc = 0; 14281da177e4SLinus Torvalds struct ocontext *c; 14291da177e4SLinus Torvalds 14301da177e4SLinus Torvalds POLICY_RDLOCK; 14311da177e4SLinus Torvalds 14321da177e4SLinus Torvalds switch (domain) { 14331da177e4SLinus Torvalds case AF_INET: { 14341da177e4SLinus Torvalds u32 addr; 14351da177e4SLinus Torvalds 14361da177e4SLinus Torvalds if (addrlen != sizeof(u32)) { 14371da177e4SLinus Torvalds rc = -EINVAL; 14381da177e4SLinus Torvalds goto out; 14391da177e4SLinus Torvalds } 14401da177e4SLinus Torvalds 14411da177e4SLinus Torvalds addr = *((u32 *)addrp); 14421da177e4SLinus Torvalds 14431da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NODE]; 14441da177e4SLinus Torvalds while (c) { 14451da177e4SLinus Torvalds if (c->u.node.addr == (addr & c->u.node.mask)) 14461da177e4SLinus Torvalds break; 14471da177e4SLinus Torvalds c = c->next; 14481da177e4SLinus Torvalds } 14491da177e4SLinus Torvalds break; 14501da177e4SLinus Torvalds } 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds case AF_INET6: 14531da177e4SLinus Torvalds if (addrlen != sizeof(u64) * 2) { 14541da177e4SLinus Torvalds rc = -EINVAL; 14551da177e4SLinus Torvalds goto out; 14561da177e4SLinus Torvalds } 14571da177e4SLinus Torvalds c = policydb.ocontexts[OCON_NODE6]; 14581da177e4SLinus Torvalds while (c) { 14591da177e4SLinus Torvalds if (match_ipv6_addrmask(addrp, c->u.node6.addr, 14601da177e4SLinus Torvalds c->u.node6.mask)) 14611da177e4SLinus Torvalds break; 14621da177e4SLinus Torvalds c = c->next; 14631da177e4SLinus Torvalds } 14641da177e4SLinus Torvalds break; 14651da177e4SLinus Torvalds 14661da177e4SLinus Torvalds default: 14671da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 14681da177e4SLinus Torvalds goto out; 14691da177e4SLinus Torvalds } 14701da177e4SLinus Torvalds 14711da177e4SLinus Torvalds if (c) { 14721da177e4SLinus Torvalds if (!c->sid[0]) { 14731da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 14741da177e4SLinus Torvalds &c->context[0], 14751da177e4SLinus Torvalds &c->sid[0]); 14761da177e4SLinus Torvalds if (rc) 14771da177e4SLinus Torvalds goto out; 14781da177e4SLinus Torvalds } 14791da177e4SLinus Torvalds *out_sid = c->sid[0]; 14801da177e4SLinus Torvalds } else { 14811da177e4SLinus Torvalds *out_sid = SECINITSID_NODE; 14821da177e4SLinus Torvalds } 14831da177e4SLinus Torvalds 14841da177e4SLinus Torvalds out: 14851da177e4SLinus Torvalds POLICY_RDUNLOCK; 14861da177e4SLinus Torvalds return rc; 14871da177e4SLinus Torvalds } 14881da177e4SLinus Torvalds 14891da177e4SLinus Torvalds #define SIDS_NEL 25 14901da177e4SLinus Torvalds 14911da177e4SLinus Torvalds /** 14921da177e4SLinus Torvalds * security_get_user_sids - Obtain reachable SIDs for a user. 14931da177e4SLinus Torvalds * @fromsid: starting SID 14941da177e4SLinus Torvalds * @username: username 14951da177e4SLinus Torvalds * @sids: array of reachable SIDs for user 14961da177e4SLinus Torvalds * @nel: number of elements in @sids 14971da177e4SLinus Torvalds * 14981da177e4SLinus Torvalds * Generate the set of SIDs for legal security contexts 14991da177e4SLinus Torvalds * for a given user that can be reached by @fromsid. 15001da177e4SLinus Torvalds * Set *@sids to point to a dynamically allocated 15011da177e4SLinus Torvalds * array containing the set of SIDs. Set *@nel to the 15021da177e4SLinus Torvalds * number of elements in the array. 15031da177e4SLinus Torvalds */ 15041da177e4SLinus Torvalds 15051da177e4SLinus Torvalds int security_get_user_sids(u32 fromsid, 15061da177e4SLinus Torvalds char *username, 15071da177e4SLinus Torvalds u32 **sids, 15081da177e4SLinus Torvalds u32 *nel) 15091da177e4SLinus Torvalds { 15101da177e4SLinus Torvalds struct context *fromcon, usercon; 15111da177e4SLinus Torvalds u32 *mysids, *mysids2, sid; 15121da177e4SLinus Torvalds u32 mynel = 0, maxnel = SIDS_NEL; 15131da177e4SLinus Torvalds struct user_datum *user; 15141da177e4SLinus Torvalds struct role_datum *role; 15151da177e4SLinus Torvalds struct av_decision avd; 1516782ebb99SStephen Smalley struct ebitmap_node *rnode, *tnode; 15171da177e4SLinus Torvalds int rc = 0, i, j; 15181da177e4SLinus Torvalds 15191da177e4SLinus Torvalds if (!ss_initialized) { 15201da177e4SLinus Torvalds *sids = NULL; 15211da177e4SLinus Torvalds *nel = 0; 15221da177e4SLinus Torvalds goto out; 15231da177e4SLinus Torvalds } 15241da177e4SLinus Torvalds 15251da177e4SLinus Torvalds POLICY_RDLOCK; 15261da177e4SLinus Torvalds 15271da177e4SLinus Torvalds fromcon = sidtab_search(&sidtab, fromsid); 15281da177e4SLinus Torvalds if (!fromcon) { 15291da177e4SLinus Torvalds rc = -EINVAL; 15301da177e4SLinus Torvalds goto out_unlock; 15311da177e4SLinus Torvalds } 15321da177e4SLinus Torvalds 15331da177e4SLinus Torvalds user = hashtab_search(policydb.p_users.table, username); 15341da177e4SLinus Torvalds if (!user) { 15351da177e4SLinus Torvalds rc = -EINVAL; 15361da177e4SLinus Torvalds goto out_unlock; 15371da177e4SLinus Torvalds } 15381da177e4SLinus Torvalds usercon.user = user->value; 15391da177e4SLinus Torvalds 154089d155efSJames Morris mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC); 15411da177e4SLinus Torvalds if (!mysids) { 15421da177e4SLinus Torvalds rc = -ENOMEM; 15431da177e4SLinus Torvalds goto out_unlock; 15441da177e4SLinus Torvalds } 15451da177e4SLinus Torvalds 1546782ebb99SStephen Smalley ebitmap_for_each_bit(&user->roles, rnode, i) { 1547782ebb99SStephen Smalley if (!ebitmap_node_get_bit(rnode, i)) 15481da177e4SLinus Torvalds continue; 15491da177e4SLinus Torvalds role = policydb.role_val_to_struct[i]; 15501da177e4SLinus Torvalds usercon.role = i+1; 1551782ebb99SStephen Smalley ebitmap_for_each_bit(&role->types, tnode, j) { 1552782ebb99SStephen Smalley if (!ebitmap_node_get_bit(tnode, j)) 15531da177e4SLinus Torvalds continue; 15541da177e4SLinus Torvalds usercon.type = j+1; 15551da177e4SLinus Torvalds 15561da177e4SLinus Torvalds if (mls_setup_user_range(fromcon, user, &usercon)) 15571da177e4SLinus Torvalds continue; 15581da177e4SLinus Torvalds 15591da177e4SLinus Torvalds rc = context_struct_compute_av(fromcon, &usercon, 15601da177e4SLinus Torvalds SECCLASS_PROCESS, 15611da177e4SLinus Torvalds PROCESS__TRANSITION, 15621da177e4SLinus Torvalds &avd); 15631da177e4SLinus Torvalds if (rc || !(avd.allowed & PROCESS__TRANSITION)) 15641da177e4SLinus Torvalds continue; 15651da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, &usercon, &sid); 15661da177e4SLinus Torvalds if (rc) { 15671da177e4SLinus Torvalds kfree(mysids); 15681da177e4SLinus Torvalds goto out_unlock; 15691da177e4SLinus Torvalds } 15701da177e4SLinus Torvalds if (mynel < maxnel) { 15711da177e4SLinus Torvalds mysids[mynel++] = sid; 15721da177e4SLinus Torvalds } else { 15731da177e4SLinus Torvalds maxnel += SIDS_NEL; 157489d155efSJames Morris mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC); 15751da177e4SLinus Torvalds if (!mysids2) { 15761da177e4SLinus Torvalds rc = -ENOMEM; 15771da177e4SLinus Torvalds kfree(mysids); 15781da177e4SLinus Torvalds goto out_unlock; 15791da177e4SLinus Torvalds } 15801da177e4SLinus Torvalds memcpy(mysids2, mysids, mynel * sizeof(*mysids2)); 15811da177e4SLinus Torvalds kfree(mysids); 15821da177e4SLinus Torvalds mysids = mysids2; 15831da177e4SLinus Torvalds mysids[mynel++] = sid; 15841da177e4SLinus Torvalds } 15851da177e4SLinus Torvalds } 15861da177e4SLinus Torvalds } 15871da177e4SLinus Torvalds 15881da177e4SLinus Torvalds *sids = mysids; 15891da177e4SLinus Torvalds *nel = mynel; 15901da177e4SLinus Torvalds 15911da177e4SLinus Torvalds out_unlock: 15921da177e4SLinus Torvalds POLICY_RDUNLOCK; 15931da177e4SLinus Torvalds out: 15941da177e4SLinus Torvalds return rc; 15951da177e4SLinus Torvalds } 15961da177e4SLinus Torvalds 15971da177e4SLinus Torvalds /** 15981da177e4SLinus Torvalds * security_genfs_sid - Obtain a SID for a file in a filesystem 15991da177e4SLinus Torvalds * @fstype: filesystem type 16001da177e4SLinus Torvalds * @path: path from root of mount 16011da177e4SLinus Torvalds * @sclass: file security class 16021da177e4SLinus Torvalds * @sid: SID for path 16031da177e4SLinus Torvalds * 16041da177e4SLinus Torvalds * Obtain a SID to use for a file in a filesystem that 16051da177e4SLinus Torvalds * cannot support xattr or use a fixed labeling behavior like 16061da177e4SLinus Torvalds * transition SIDs or task SIDs. 16071da177e4SLinus Torvalds */ 16081da177e4SLinus Torvalds int security_genfs_sid(const char *fstype, 16091da177e4SLinus Torvalds char *path, 16101da177e4SLinus Torvalds u16 sclass, 16111da177e4SLinus Torvalds u32 *sid) 16121da177e4SLinus Torvalds { 16131da177e4SLinus Torvalds int len; 16141da177e4SLinus Torvalds struct genfs *genfs; 16151da177e4SLinus Torvalds struct ocontext *c; 16161da177e4SLinus Torvalds int rc = 0, cmp = 0; 16171da177e4SLinus Torvalds 16181da177e4SLinus Torvalds POLICY_RDLOCK; 16191da177e4SLinus Torvalds 16201da177e4SLinus Torvalds for (genfs = policydb.genfs; genfs; genfs = genfs->next) { 16211da177e4SLinus Torvalds cmp = strcmp(fstype, genfs->fstype); 16221da177e4SLinus Torvalds if (cmp <= 0) 16231da177e4SLinus Torvalds break; 16241da177e4SLinus Torvalds } 16251da177e4SLinus Torvalds 16261da177e4SLinus Torvalds if (!genfs || cmp) { 16271da177e4SLinus Torvalds *sid = SECINITSID_UNLABELED; 16281da177e4SLinus Torvalds rc = -ENOENT; 16291da177e4SLinus Torvalds goto out; 16301da177e4SLinus Torvalds } 16311da177e4SLinus Torvalds 16321da177e4SLinus Torvalds for (c = genfs->head; c; c = c->next) { 16331da177e4SLinus Torvalds len = strlen(c->u.name); 16341da177e4SLinus Torvalds if ((!c->v.sclass || sclass == c->v.sclass) && 16351da177e4SLinus Torvalds (strncmp(c->u.name, path, len) == 0)) 16361da177e4SLinus Torvalds break; 16371da177e4SLinus Torvalds } 16381da177e4SLinus Torvalds 16391da177e4SLinus Torvalds if (!c) { 16401da177e4SLinus Torvalds *sid = SECINITSID_UNLABELED; 16411da177e4SLinus Torvalds rc = -ENOENT; 16421da177e4SLinus Torvalds goto out; 16431da177e4SLinus Torvalds } 16441da177e4SLinus Torvalds 16451da177e4SLinus Torvalds if (!c->sid[0]) { 16461da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 16471da177e4SLinus Torvalds &c->context[0], 16481da177e4SLinus Torvalds &c->sid[0]); 16491da177e4SLinus Torvalds if (rc) 16501da177e4SLinus Torvalds goto out; 16511da177e4SLinus Torvalds } 16521da177e4SLinus Torvalds 16531da177e4SLinus Torvalds *sid = c->sid[0]; 16541da177e4SLinus Torvalds out: 16551da177e4SLinus Torvalds POLICY_RDUNLOCK; 16561da177e4SLinus Torvalds return rc; 16571da177e4SLinus Torvalds } 16581da177e4SLinus Torvalds 16591da177e4SLinus Torvalds /** 16601da177e4SLinus Torvalds * security_fs_use - Determine how to handle labeling for a filesystem. 16611da177e4SLinus Torvalds * @fstype: filesystem type 16621da177e4SLinus Torvalds * @behavior: labeling behavior 16631da177e4SLinus Torvalds * @sid: SID for filesystem (superblock) 16641da177e4SLinus Torvalds */ 16651da177e4SLinus Torvalds int security_fs_use( 16661da177e4SLinus Torvalds const char *fstype, 16671da177e4SLinus Torvalds unsigned int *behavior, 16681da177e4SLinus Torvalds u32 *sid) 16691da177e4SLinus Torvalds { 16701da177e4SLinus Torvalds int rc = 0; 16711da177e4SLinus Torvalds struct ocontext *c; 16721da177e4SLinus Torvalds 16731da177e4SLinus Torvalds POLICY_RDLOCK; 16741da177e4SLinus Torvalds 16751da177e4SLinus Torvalds c = policydb.ocontexts[OCON_FSUSE]; 16761da177e4SLinus Torvalds while (c) { 16771da177e4SLinus Torvalds if (strcmp(fstype, c->u.name) == 0) 16781da177e4SLinus Torvalds break; 16791da177e4SLinus Torvalds c = c->next; 16801da177e4SLinus Torvalds } 16811da177e4SLinus Torvalds 16821da177e4SLinus Torvalds if (c) { 16831da177e4SLinus Torvalds *behavior = c->v.behavior; 16841da177e4SLinus Torvalds if (!c->sid[0]) { 16851da177e4SLinus Torvalds rc = sidtab_context_to_sid(&sidtab, 16861da177e4SLinus Torvalds &c->context[0], 16871da177e4SLinus Torvalds &c->sid[0]); 16881da177e4SLinus Torvalds if (rc) 16891da177e4SLinus Torvalds goto out; 16901da177e4SLinus Torvalds } 16911da177e4SLinus Torvalds *sid = c->sid[0]; 16921da177e4SLinus Torvalds } else { 16931da177e4SLinus Torvalds rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); 16941da177e4SLinus Torvalds if (rc) { 16951da177e4SLinus Torvalds *behavior = SECURITY_FS_USE_NONE; 16961da177e4SLinus Torvalds rc = 0; 16971da177e4SLinus Torvalds } else { 16981da177e4SLinus Torvalds *behavior = SECURITY_FS_USE_GENFS; 16991da177e4SLinus Torvalds } 17001da177e4SLinus Torvalds } 17011da177e4SLinus Torvalds 17021da177e4SLinus Torvalds out: 17031da177e4SLinus Torvalds POLICY_RDUNLOCK; 17041da177e4SLinus Torvalds return rc; 17051da177e4SLinus Torvalds } 17061da177e4SLinus Torvalds 17071da177e4SLinus Torvalds int security_get_bools(int *len, char ***names, int **values) 17081da177e4SLinus Torvalds { 17091da177e4SLinus Torvalds int i, rc = -ENOMEM; 17101da177e4SLinus Torvalds 17111da177e4SLinus Torvalds POLICY_RDLOCK; 17121da177e4SLinus Torvalds *names = NULL; 17131da177e4SLinus Torvalds *values = NULL; 17141da177e4SLinus Torvalds 17151da177e4SLinus Torvalds *len = policydb.p_bools.nprim; 17161da177e4SLinus Torvalds if (!*len) { 17171da177e4SLinus Torvalds rc = 0; 17181da177e4SLinus Torvalds goto out; 17191da177e4SLinus Torvalds } 17201da177e4SLinus Torvalds 1721e0795cf4SJesper Juhl *names = kcalloc(*len, sizeof(char*), GFP_ATOMIC); 17221da177e4SLinus Torvalds if (!*names) 17231da177e4SLinus Torvalds goto err; 17241da177e4SLinus Torvalds 1725e0795cf4SJesper Juhl *values = kcalloc(*len, sizeof(int), GFP_ATOMIC); 17261da177e4SLinus Torvalds if (!*values) 17271da177e4SLinus Torvalds goto err; 17281da177e4SLinus Torvalds 17291da177e4SLinus Torvalds for (i = 0; i < *len; i++) { 17301da177e4SLinus Torvalds size_t name_len; 17311da177e4SLinus Torvalds (*values)[i] = policydb.bool_val_to_struct[i]->state; 17321da177e4SLinus Torvalds name_len = strlen(policydb.p_bool_val_to_name[i]) + 1; 1733e0795cf4SJesper Juhl (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC); 17341da177e4SLinus Torvalds if (!(*names)[i]) 17351da177e4SLinus Torvalds goto err; 17361da177e4SLinus Torvalds strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len); 17371da177e4SLinus Torvalds (*names)[i][name_len - 1] = 0; 17381da177e4SLinus Torvalds } 17391da177e4SLinus Torvalds rc = 0; 17401da177e4SLinus Torvalds out: 17411da177e4SLinus Torvalds POLICY_RDUNLOCK; 17421da177e4SLinus Torvalds return rc; 17431da177e4SLinus Torvalds err: 17441da177e4SLinus Torvalds if (*names) { 17451da177e4SLinus Torvalds for (i = 0; i < *len; i++) 17461da177e4SLinus Torvalds kfree((*names)[i]); 17471da177e4SLinus Torvalds } 17481da177e4SLinus Torvalds kfree(*values); 17491da177e4SLinus Torvalds goto out; 17501da177e4SLinus Torvalds } 17511da177e4SLinus Torvalds 17521da177e4SLinus Torvalds 17531da177e4SLinus Torvalds int security_set_bools(int len, int *values) 17541da177e4SLinus Torvalds { 17551da177e4SLinus Torvalds int i, rc = 0; 17561da177e4SLinus Torvalds int lenp, seqno = 0; 17571da177e4SLinus Torvalds struct cond_node *cur; 17581da177e4SLinus Torvalds 17591da177e4SLinus Torvalds POLICY_WRLOCK; 17601da177e4SLinus Torvalds 17611da177e4SLinus Torvalds lenp = policydb.p_bools.nprim; 17621da177e4SLinus Torvalds if (len != lenp) { 17631da177e4SLinus Torvalds rc = -EFAULT; 17641da177e4SLinus Torvalds goto out; 17651da177e4SLinus Torvalds } 17661da177e4SLinus Torvalds 17671da177e4SLinus Torvalds for (i = 0; i < len; i++) { 1768af601e46SSteve Grubb if (!!values[i] != policydb.bool_val_to_struct[i]->state) { 1769af601e46SSteve Grubb audit_log(current->audit_context, GFP_ATOMIC, 1770af601e46SSteve Grubb AUDIT_MAC_CONFIG_CHANGE, 1771af601e46SSteve Grubb "bool=%s val=%d old_val=%d auid=%u", 1772af601e46SSteve Grubb policydb.p_bool_val_to_name[i], 1773af601e46SSteve Grubb !!values[i], 1774af601e46SSteve Grubb policydb.bool_val_to_struct[i]->state, 1775af601e46SSteve Grubb audit_get_loginuid(current->audit_context)); 1776af601e46SSteve Grubb } 17771da177e4SLinus Torvalds if (values[i]) { 17781da177e4SLinus Torvalds policydb.bool_val_to_struct[i]->state = 1; 17791da177e4SLinus Torvalds } else { 17801da177e4SLinus Torvalds policydb.bool_val_to_struct[i]->state = 0; 17811da177e4SLinus Torvalds } 17821da177e4SLinus Torvalds } 17831da177e4SLinus Torvalds 17841da177e4SLinus Torvalds for (cur = policydb.cond_list; cur != NULL; cur = cur->next) { 17851da177e4SLinus Torvalds rc = evaluate_cond_node(&policydb, cur); 17861da177e4SLinus Torvalds if (rc) 17871da177e4SLinus Torvalds goto out; 17881da177e4SLinus Torvalds } 17891da177e4SLinus Torvalds 17901da177e4SLinus Torvalds seqno = ++latest_granting; 17911da177e4SLinus Torvalds 17921da177e4SLinus Torvalds out: 17931da177e4SLinus Torvalds POLICY_WRUNLOCK; 17941da177e4SLinus Torvalds if (!rc) { 17951da177e4SLinus Torvalds avc_ss_reset(seqno); 17961da177e4SLinus Torvalds selnl_notify_policyload(seqno); 17971da177e4SLinus Torvalds } 17981da177e4SLinus Torvalds return rc; 17991da177e4SLinus Torvalds } 18001da177e4SLinus Torvalds 18011da177e4SLinus Torvalds int security_get_bool_value(int bool) 18021da177e4SLinus Torvalds { 18031da177e4SLinus Torvalds int rc = 0; 18041da177e4SLinus Torvalds int len; 18051da177e4SLinus Torvalds 18061da177e4SLinus Torvalds POLICY_RDLOCK; 18071da177e4SLinus Torvalds 18081da177e4SLinus Torvalds len = policydb.p_bools.nprim; 18091da177e4SLinus Torvalds if (bool >= len) { 18101da177e4SLinus Torvalds rc = -EFAULT; 18111da177e4SLinus Torvalds goto out; 18121da177e4SLinus Torvalds } 18131da177e4SLinus Torvalds 18141da177e4SLinus Torvalds rc = policydb.bool_val_to_struct[bool]->state; 18151da177e4SLinus Torvalds out: 18161da177e4SLinus Torvalds POLICY_RDUNLOCK; 18171da177e4SLinus Torvalds return rc; 18181da177e4SLinus Torvalds } 1819376bd9cbSDarrel Goeddel 1820376bd9cbSDarrel Goeddel struct selinux_audit_rule { 1821376bd9cbSDarrel Goeddel u32 au_seqno; 1822376bd9cbSDarrel Goeddel struct context au_ctxt; 1823376bd9cbSDarrel Goeddel }; 1824376bd9cbSDarrel Goeddel 1825376bd9cbSDarrel Goeddel void selinux_audit_rule_free(struct selinux_audit_rule *rule) 1826376bd9cbSDarrel Goeddel { 1827376bd9cbSDarrel Goeddel if (rule) { 1828376bd9cbSDarrel Goeddel context_destroy(&rule->au_ctxt); 1829376bd9cbSDarrel Goeddel kfree(rule); 1830376bd9cbSDarrel Goeddel } 1831376bd9cbSDarrel Goeddel } 1832376bd9cbSDarrel Goeddel 1833376bd9cbSDarrel Goeddel int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, 1834376bd9cbSDarrel Goeddel struct selinux_audit_rule **rule) 1835376bd9cbSDarrel Goeddel { 1836376bd9cbSDarrel Goeddel struct selinux_audit_rule *tmprule; 1837376bd9cbSDarrel Goeddel struct role_datum *roledatum; 1838376bd9cbSDarrel Goeddel struct type_datum *typedatum; 1839376bd9cbSDarrel Goeddel struct user_datum *userdatum; 1840376bd9cbSDarrel Goeddel int rc = 0; 1841376bd9cbSDarrel Goeddel 1842376bd9cbSDarrel Goeddel *rule = NULL; 1843376bd9cbSDarrel Goeddel 1844376bd9cbSDarrel Goeddel if (!ss_initialized) 1845376bd9cbSDarrel Goeddel return -ENOTSUPP; 1846376bd9cbSDarrel Goeddel 1847376bd9cbSDarrel Goeddel switch (field) { 1848376bd9cbSDarrel Goeddel case AUDIT_SE_USER: 1849376bd9cbSDarrel Goeddel case AUDIT_SE_ROLE: 1850376bd9cbSDarrel Goeddel case AUDIT_SE_TYPE: 1851376bd9cbSDarrel Goeddel /* only 'equals' and 'not equals' fit user, role, and type */ 1852376bd9cbSDarrel Goeddel if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL) 1853376bd9cbSDarrel Goeddel return -EINVAL; 1854376bd9cbSDarrel Goeddel break; 1855376bd9cbSDarrel Goeddel case AUDIT_SE_SEN: 1856376bd9cbSDarrel Goeddel case AUDIT_SE_CLR: 1857376bd9cbSDarrel Goeddel /* we do not allow a range, indicated by the presense of '-' */ 1858376bd9cbSDarrel Goeddel if (strchr(rulestr, '-')) 1859376bd9cbSDarrel Goeddel return -EINVAL; 1860376bd9cbSDarrel Goeddel break; 1861376bd9cbSDarrel Goeddel default: 1862376bd9cbSDarrel Goeddel /* only the above fields are valid */ 1863376bd9cbSDarrel Goeddel return -EINVAL; 1864376bd9cbSDarrel Goeddel } 1865376bd9cbSDarrel Goeddel 1866376bd9cbSDarrel Goeddel tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL); 1867376bd9cbSDarrel Goeddel if (!tmprule) 1868376bd9cbSDarrel Goeddel return -ENOMEM; 1869376bd9cbSDarrel Goeddel 1870376bd9cbSDarrel Goeddel context_init(&tmprule->au_ctxt); 1871376bd9cbSDarrel Goeddel 1872376bd9cbSDarrel Goeddel POLICY_RDLOCK; 1873376bd9cbSDarrel Goeddel 1874376bd9cbSDarrel Goeddel tmprule->au_seqno = latest_granting; 1875376bd9cbSDarrel Goeddel 1876376bd9cbSDarrel Goeddel switch (field) { 1877376bd9cbSDarrel Goeddel case AUDIT_SE_USER: 1878376bd9cbSDarrel Goeddel userdatum = hashtab_search(policydb.p_users.table, rulestr); 1879376bd9cbSDarrel Goeddel if (!userdatum) 1880376bd9cbSDarrel Goeddel rc = -EINVAL; 1881376bd9cbSDarrel Goeddel else 1882376bd9cbSDarrel Goeddel tmprule->au_ctxt.user = userdatum->value; 1883376bd9cbSDarrel Goeddel break; 1884376bd9cbSDarrel Goeddel case AUDIT_SE_ROLE: 1885376bd9cbSDarrel Goeddel roledatum = hashtab_search(policydb.p_roles.table, rulestr); 1886376bd9cbSDarrel Goeddel if (!roledatum) 1887376bd9cbSDarrel Goeddel rc = -EINVAL; 1888376bd9cbSDarrel Goeddel else 1889376bd9cbSDarrel Goeddel tmprule->au_ctxt.role = roledatum->value; 1890376bd9cbSDarrel Goeddel break; 1891376bd9cbSDarrel Goeddel case AUDIT_SE_TYPE: 1892376bd9cbSDarrel Goeddel typedatum = hashtab_search(policydb.p_types.table, rulestr); 1893376bd9cbSDarrel Goeddel if (!typedatum) 1894376bd9cbSDarrel Goeddel rc = -EINVAL; 1895376bd9cbSDarrel Goeddel else 1896376bd9cbSDarrel Goeddel tmprule->au_ctxt.type = typedatum->value; 1897376bd9cbSDarrel Goeddel break; 1898376bd9cbSDarrel Goeddel case AUDIT_SE_SEN: 1899376bd9cbSDarrel Goeddel case AUDIT_SE_CLR: 1900376bd9cbSDarrel Goeddel rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC); 1901376bd9cbSDarrel Goeddel break; 1902376bd9cbSDarrel Goeddel } 1903376bd9cbSDarrel Goeddel 1904376bd9cbSDarrel Goeddel POLICY_RDUNLOCK; 1905376bd9cbSDarrel Goeddel 1906376bd9cbSDarrel Goeddel if (rc) { 1907376bd9cbSDarrel Goeddel selinux_audit_rule_free(tmprule); 1908376bd9cbSDarrel Goeddel tmprule = NULL; 1909376bd9cbSDarrel Goeddel } 1910376bd9cbSDarrel Goeddel 1911376bd9cbSDarrel Goeddel *rule = tmprule; 1912376bd9cbSDarrel Goeddel 1913376bd9cbSDarrel Goeddel return rc; 1914376bd9cbSDarrel Goeddel } 1915376bd9cbSDarrel Goeddel 1916376bd9cbSDarrel Goeddel int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op, 1917376bd9cbSDarrel Goeddel struct selinux_audit_rule *rule, 1918376bd9cbSDarrel Goeddel struct audit_context *actx) 1919376bd9cbSDarrel Goeddel { 1920376bd9cbSDarrel Goeddel struct context *ctxt; 1921376bd9cbSDarrel Goeddel struct mls_level *level; 1922376bd9cbSDarrel Goeddel int match = 0; 1923376bd9cbSDarrel Goeddel 1924376bd9cbSDarrel Goeddel if (!rule) { 1925376bd9cbSDarrel Goeddel audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, 1926376bd9cbSDarrel Goeddel "selinux_audit_rule_match: missing rule\n"); 1927376bd9cbSDarrel Goeddel return -ENOENT; 1928376bd9cbSDarrel Goeddel } 1929376bd9cbSDarrel Goeddel 1930376bd9cbSDarrel Goeddel POLICY_RDLOCK; 1931376bd9cbSDarrel Goeddel 1932376bd9cbSDarrel Goeddel if (rule->au_seqno < latest_granting) { 1933376bd9cbSDarrel Goeddel audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, 1934376bd9cbSDarrel Goeddel "selinux_audit_rule_match: stale rule\n"); 1935376bd9cbSDarrel Goeddel match = -ESTALE; 1936376bd9cbSDarrel Goeddel goto out; 1937376bd9cbSDarrel Goeddel } 1938376bd9cbSDarrel Goeddel 1939376bd9cbSDarrel Goeddel ctxt = sidtab_search(&sidtab, ctxid); 1940376bd9cbSDarrel Goeddel if (!ctxt) { 1941376bd9cbSDarrel Goeddel audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, 1942376bd9cbSDarrel Goeddel "selinux_audit_rule_match: unrecognized SID %d\n", 1943376bd9cbSDarrel Goeddel ctxid); 1944376bd9cbSDarrel Goeddel match = -ENOENT; 1945376bd9cbSDarrel Goeddel goto out; 1946376bd9cbSDarrel Goeddel } 1947376bd9cbSDarrel Goeddel 1948376bd9cbSDarrel Goeddel /* a field/op pair that is not caught here will simply fall through 1949376bd9cbSDarrel Goeddel without a match */ 1950376bd9cbSDarrel Goeddel switch (field) { 1951376bd9cbSDarrel Goeddel case AUDIT_SE_USER: 1952376bd9cbSDarrel Goeddel switch (op) { 1953376bd9cbSDarrel Goeddel case AUDIT_EQUAL: 1954376bd9cbSDarrel Goeddel match = (ctxt->user == rule->au_ctxt.user); 1955376bd9cbSDarrel Goeddel break; 1956376bd9cbSDarrel Goeddel case AUDIT_NOT_EQUAL: 1957376bd9cbSDarrel Goeddel match = (ctxt->user != rule->au_ctxt.user); 1958376bd9cbSDarrel Goeddel break; 1959376bd9cbSDarrel Goeddel } 1960376bd9cbSDarrel Goeddel break; 1961376bd9cbSDarrel Goeddel case AUDIT_SE_ROLE: 1962376bd9cbSDarrel Goeddel switch (op) { 1963376bd9cbSDarrel Goeddel case AUDIT_EQUAL: 1964376bd9cbSDarrel Goeddel match = (ctxt->role == rule->au_ctxt.role); 1965376bd9cbSDarrel Goeddel break; 1966376bd9cbSDarrel Goeddel case AUDIT_NOT_EQUAL: 1967376bd9cbSDarrel Goeddel match = (ctxt->role != rule->au_ctxt.role); 1968376bd9cbSDarrel Goeddel break; 1969376bd9cbSDarrel Goeddel } 1970376bd9cbSDarrel Goeddel break; 1971376bd9cbSDarrel Goeddel case AUDIT_SE_TYPE: 1972376bd9cbSDarrel Goeddel switch (op) { 1973376bd9cbSDarrel Goeddel case AUDIT_EQUAL: 1974376bd9cbSDarrel Goeddel match = (ctxt->type == rule->au_ctxt.type); 1975376bd9cbSDarrel Goeddel break; 1976376bd9cbSDarrel Goeddel case AUDIT_NOT_EQUAL: 1977376bd9cbSDarrel Goeddel match = (ctxt->type != rule->au_ctxt.type); 1978376bd9cbSDarrel Goeddel break; 1979376bd9cbSDarrel Goeddel } 1980376bd9cbSDarrel Goeddel break; 1981376bd9cbSDarrel Goeddel case AUDIT_SE_SEN: 1982376bd9cbSDarrel Goeddel case AUDIT_SE_CLR: 1983376bd9cbSDarrel Goeddel level = (op == AUDIT_SE_SEN ? 1984376bd9cbSDarrel Goeddel &ctxt->range.level[0] : &ctxt->range.level[1]); 1985376bd9cbSDarrel Goeddel switch (op) { 1986376bd9cbSDarrel Goeddel case AUDIT_EQUAL: 1987376bd9cbSDarrel Goeddel match = mls_level_eq(&rule->au_ctxt.range.level[0], 1988376bd9cbSDarrel Goeddel level); 1989376bd9cbSDarrel Goeddel break; 1990376bd9cbSDarrel Goeddel case AUDIT_NOT_EQUAL: 1991376bd9cbSDarrel Goeddel match = !mls_level_eq(&rule->au_ctxt.range.level[0], 1992376bd9cbSDarrel Goeddel level); 1993376bd9cbSDarrel Goeddel break; 1994376bd9cbSDarrel Goeddel case AUDIT_LESS_THAN: 1995376bd9cbSDarrel Goeddel match = (mls_level_dom(&rule->au_ctxt.range.level[0], 1996376bd9cbSDarrel Goeddel level) && 1997376bd9cbSDarrel Goeddel !mls_level_eq(&rule->au_ctxt.range.level[0], 1998376bd9cbSDarrel Goeddel level)); 1999376bd9cbSDarrel Goeddel break; 2000376bd9cbSDarrel Goeddel case AUDIT_LESS_THAN_OR_EQUAL: 2001376bd9cbSDarrel Goeddel match = mls_level_dom(&rule->au_ctxt.range.level[0], 2002376bd9cbSDarrel Goeddel level); 2003376bd9cbSDarrel Goeddel break; 2004376bd9cbSDarrel Goeddel case AUDIT_GREATER_THAN: 2005376bd9cbSDarrel Goeddel match = (mls_level_dom(level, 2006376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]) && 2007376bd9cbSDarrel Goeddel !mls_level_eq(level, 2008376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0])); 2009376bd9cbSDarrel Goeddel break; 2010376bd9cbSDarrel Goeddel case AUDIT_GREATER_THAN_OR_EQUAL: 2011376bd9cbSDarrel Goeddel match = mls_level_dom(level, 2012376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]); 2013376bd9cbSDarrel Goeddel break; 2014376bd9cbSDarrel Goeddel } 2015376bd9cbSDarrel Goeddel } 2016376bd9cbSDarrel Goeddel 2017376bd9cbSDarrel Goeddel out: 2018376bd9cbSDarrel Goeddel POLICY_RDUNLOCK; 2019376bd9cbSDarrel Goeddel return match; 2020376bd9cbSDarrel Goeddel } 2021376bd9cbSDarrel Goeddel 2022376bd9cbSDarrel Goeddel static int (*aurule_callback)(void) = NULL; 2023376bd9cbSDarrel Goeddel 2024376bd9cbSDarrel Goeddel static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, 2025376bd9cbSDarrel Goeddel u16 class, u32 perms, u32 *retained) 2026376bd9cbSDarrel Goeddel { 2027376bd9cbSDarrel Goeddel int err = 0; 2028376bd9cbSDarrel Goeddel 2029376bd9cbSDarrel Goeddel if (event == AVC_CALLBACK_RESET && aurule_callback) 2030376bd9cbSDarrel Goeddel err = aurule_callback(); 2031376bd9cbSDarrel Goeddel return err; 2032376bd9cbSDarrel Goeddel } 2033376bd9cbSDarrel Goeddel 2034376bd9cbSDarrel Goeddel static int __init aurule_init(void) 2035376bd9cbSDarrel Goeddel { 2036376bd9cbSDarrel Goeddel int err; 2037376bd9cbSDarrel Goeddel 2038376bd9cbSDarrel Goeddel err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET, 2039376bd9cbSDarrel Goeddel SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); 2040376bd9cbSDarrel Goeddel if (err) 2041376bd9cbSDarrel Goeddel panic("avc_add_callback() failed, error %d\n", err); 2042376bd9cbSDarrel Goeddel 2043376bd9cbSDarrel Goeddel return err; 2044376bd9cbSDarrel Goeddel } 2045376bd9cbSDarrel Goeddel __initcall(aurule_init); 2046376bd9cbSDarrel Goeddel 2047376bd9cbSDarrel Goeddel void selinux_audit_set_callback(int (*callback)(void)) 2048376bd9cbSDarrel Goeddel { 2049376bd9cbSDarrel Goeddel aurule_callback = callback; 2050376bd9cbSDarrel Goeddel } 2051