xref: /openbmc/linux/security/selinux/ss/services.c (revision 376bd9cb)
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);
5971da177e4SLinus Torvalds 			strcpy(scontextp, initial_sid_to_string[sid]);
5981da177e4SLinus Torvalds 			*scontext = scontextp;
5991da177e4SLinus Torvalds 			goto out;
6001da177e4SLinus Torvalds 		}
6011da177e4SLinus Torvalds 		printk(KERN_ERR "security_sid_to_context:  called before initial "
6021da177e4SLinus Torvalds 		       "load_policy on unknown SID %d\n", sid);
6031da177e4SLinus Torvalds 		rc = -EINVAL;
6041da177e4SLinus Torvalds 		goto out;
6051da177e4SLinus Torvalds 	}
6061da177e4SLinus Torvalds 	POLICY_RDLOCK;
6071da177e4SLinus Torvalds 	context = sidtab_search(&sidtab, sid);
6081da177e4SLinus Torvalds 	if (!context) {
6091da177e4SLinus Torvalds 		printk(KERN_ERR "security_sid_to_context:  unrecognized SID "
6101da177e4SLinus Torvalds 		       "%d\n", sid);
6111da177e4SLinus Torvalds 		rc = -EINVAL;
6121da177e4SLinus Torvalds 		goto out_unlock;
6131da177e4SLinus Torvalds 	}
6141da177e4SLinus Torvalds 	rc = context_struct_to_string(context, scontext, scontext_len);
6151da177e4SLinus Torvalds out_unlock:
6161da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
6171da177e4SLinus Torvalds out:
6181da177e4SLinus Torvalds 	return rc;
6191da177e4SLinus Torvalds 
6201da177e4SLinus Torvalds }
6211da177e4SLinus Torvalds 
622f5c1d5b2SJames Morris static int security_context_to_sid_core(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid)
6231da177e4SLinus Torvalds {
6241da177e4SLinus Torvalds 	char *scontext2;
6251da177e4SLinus Torvalds 	struct context context;
6261da177e4SLinus Torvalds 	struct role_datum *role;
6271da177e4SLinus Torvalds 	struct type_datum *typdatum;
6281da177e4SLinus Torvalds 	struct user_datum *usrdatum;
6291da177e4SLinus Torvalds 	char *scontextp, *p, oldc;
6301da177e4SLinus Torvalds 	int rc = 0;
6311da177e4SLinus Torvalds 
6321da177e4SLinus Torvalds 	if (!ss_initialized) {
6331da177e4SLinus Torvalds 		int i;
6341da177e4SLinus Torvalds 
6351da177e4SLinus Torvalds 		for (i = 1; i < SECINITSID_NUM; i++) {
6361da177e4SLinus Torvalds 			if (!strcmp(initial_sid_to_string[i], scontext)) {
6371da177e4SLinus Torvalds 				*sid = i;
6381da177e4SLinus Torvalds 				goto out;
6391da177e4SLinus Torvalds 			}
6401da177e4SLinus Torvalds 		}
6411da177e4SLinus Torvalds 		*sid = SECINITSID_KERNEL;
6421da177e4SLinus Torvalds 		goto out;
6431da177e4SLinus Torvalds 	}
6441da177e4SLinus Torvalds 	*sid = SECSID_NULL;
6451da177e4SLinus Torvalds 
6461da177e4SLinus Torvalds 	/* Copy the string so that we can modify the copy as we parse it.
6471da177e4SLinus Torvalds 	   The string should already by null terminated, but we append a
6481da177e4SLinus Torvalds 	   null suffix to the copy to avoid problems with the existing
6491da177e4SLinus Torvalds 	   attr package, which doesn't view the null terminator as part
6501da177e4SLinus Torvalds 	   of the attribute value. */
6511da177e4SLinus Torvalds 	scontext2 = kmalloc(scontext_len+1,GFP_KERNEL);
6521da177e4SLinus Torvalds 	if (!scontext2) {
6531da177e4SLinus Torvalds 		rc = -ENOMEM;
6541da177e4SLinus Torvalds 		goto out;
6551da177e4SLinus Torvalds 	}
6561da177e4SLinus Torvalds 	memcpy(scontext2, scontext, scontext_len);
6571da177e4SLinus Torvalds 	scontext2[scontext_len] = 0;
6581da177e4SLinus Torvalds 
6591da177e4SLinus Torvalds 	context_init(&context);
6601da177e4SLinus Torvalds 	*sid = SECSID_NULL;
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds 	POLICY_RDLOCK;
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	/* Parse the security context. */
6651da177e4SLinus Torvalds 
6661da177e4SLinus Torvalds 	rc = -EINVAL;
6671da177e4SLinus Torvalds 	scontextp = (char *) scontext2;
6681da177e4SLinus Torvalds 
6691da177e4SLinus Torvalds 	/* Extract the user. */
6701da177e4SLinus Torvalds 	p = scontextp;
6711da177e4SLinus Torvalds 	while (*p && *p != ':')
6721da177e4SLinus Torvalds 		p++;
6731da177e4SLinus Torvalds 
6741da177e4SLinus Torvalds 	if (*p == 0)
6751da177e4SLinus Torvalds 		goto out_unlock;
6761da177e4SLinus Torvalds 
6771da177e4SLinus Torvalds 	*p++ = 0;
6781da177e4SLinus Torvalds 
6791da177e4SLinus Torvalds 	usrdatum = hashtab_search(policydb.p_users.table, scontextp);
6801da177e4SLinus Torvalds 	if (!usrdatum)
6811da177e4SLinus Torvalds 		goto out_unlock;
6821da177e4SLinus Torvalds 
6831da177e4SLinus Torvalds 	context.user = usrdatum->value;
6841da177e4SLinus Torvalds 
6851da177e4SLinus Torvalds 	/* Extract role. */
6861da177e4SLinus Torvalds 	scontextp = p;
6871da177e4SLinus Torvalds 	while (*p && *p != ':')
6881da177e4SLinus Torvalds 		p++;
6891da177e4SLinus Torvalds 
6901da177e4SLinus Torvalds 	if (*p == 0)
6911da177e4SLinus Torvalds 		goto out_unlock;
6921da177e4SLinus Torvalds 
6931da177e4SLinus Torvalds 	*p++ = 0;
6941da177e4SLinus Torvalds 
6951da177e4SLinus Torvalds 	role = hashtab_search(policydb.p_roles.table, scontextp);
6961da177e4SLinus Torvalds 	if (!role)
6971da177e4SLinus Torvalds 		goto out_unlock;
6981da177e4SLinus Torvalds 	context.role = role->value;
6991da177e4SLinus Torvalds 
7001da177e4SLinus Torvalds 	/* Extract type. */
7011da177e4SLinus Torvalds 	scontextp = p;
7021da177e4SLinus Torvalds 	while (*p && *p != ':')
7031da177e4SLinus Torvalds 		p++;
7041da177e4SLinus Torvalds 	oldc = *p;
7051da177e4SLinus Torvalds 	*p++ = 0;
7061da177e4SLinus Torvalds 
7071da177e4SLinus Torvalds 	typdatum = hashtab_search(policydb.p_types.table, scontextp);
7081da177e4SLinus Torvalds 	if (!typdatum)
7091da177e4SLinus Torvalds 		goto out_unlock;
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 	context.type = typdatum->value;
7121da177e4SLinus Torvalds 
713f5c1d5b2SJames Morris 	rc = mls_context_to_sid(oldc, &p, &context, &sidtab, def_sid);
7141da177e4SLinus Torvalds 	if (rc)
7151da177e4SLinus Torvalds 		goto out_unlock;
7161da177e4SLinus Torvalds 
7171da177e4SLinus Torvalds 	if ((p - scontext2) < scontext_len) {
7181da177e4SLinus Torvalds 		rc = -EINVAL;
7191da177e4SLinus Torvalds 		goto out_unlock;
7201da177e4SLinus Torvalds 	}
7211da177e4SLinus Torvalds 
7221da177e4SLinus Torvalds 	/* Check the validity of the new context. */
7231da177e4SLinus Torvalds 	if (!policydb_context_isvalid(&policydb, &context)) {
7241da177e4SLinus Torvalds 		rc = -EINVAL;
7251da177e4SLinus Torvalds 		goto out_unlock;
7261da177e4SLinus Torvalds 	}
7271da177e4SLinus Torvalds 	/* Obtain the new sid. */
7281da177e4SLinus Torvalds 	rc = sidtab_context_to_sid(&sidtab, &context, sid);
7291da177e4SLinus Torvalds out_unlock:
7301da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
7311da177e4SLinus Torvalds 	context_destroy(&context);
7321da177e4SLinus Torvalds 	kfree(scontext2);
7331da177e4SLinus Torvalds out:
7341da177e4SLinus Torvalds 	return rc;
7351da177e4SLinus Torvalds }
7361da177e4SLinus Torvalds 
737f5c1d5b2SJames Morris /**
738f5c1d5b2SJames Morris  * security_context_to_sid - Obtain a SID for a given security context.
739f5c1d5b2SJames Morris  * @scontext: security context
740f5c1d5b2SJames Morris  * @scontext_len: length in bytes
741f5c1d5b2SJames Morris  * @sid: security identifier, SID
742f5c1d5b2SJames Morris  *
743f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
744f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
745f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
746f5c1d5b2SJames Morris  * memory is available, or 0 on success.
747f5c1d5b2SJames Morris  */
748f5c1d5b2SJames Morris int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
749f5c1d5b2SJames Morris {
750f5c1d5b2SJames Morris 	return security_context_to_sid_core(scontext, scontext_len,
751f5c1d5b2SJames Morris 	                                    sid, SECSID_NULL);
752f5c1d5b2SJames Morris }
753f5c1d5b2SJames Morris 
754f5c1d5b2SJames Morris /**
755f5c1d5b2SJames Morris  * security_context_to_sid_default - Obtain a SID for a given security context,
756f5c1d5b2SJames Morris  * falling back to specified default if needed.
757f5c1d5b2SJames Morris  *
758f5c1d5b2SJames Morris  * @scontext: security context
759f5c1d5b2SJames Morris  * @scontext_len: length in bytes
760f5c1d5b2SJames Morris  * @sid: security identifier, SID
761f5c1d5b2SJames Morris  * @def_sid: default SID to assign on errror
762f5c1d5b2SJames Morris  *
763f5c1d5b2SJames Morris  * Obtains a SID associated with the security context that
764f5c1d5b2SJames Morris  * has the string representation specified by @scontext.
765f5c1d5b2SJames Morris  * The default SID is passed to the MLS layer to be used to allow
766f5c1d5b2SJames Morris  * kernel labeling of the MLS field if the MLS field is not present
767f5c1d5b2SJames Morris  * (for upgrading to MLS without full relabel).
768f5c1d5b2SJames Morris  * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
769f5c1d5b2SJames Morris  * memory is available, or 0 on success.
770f5c1d5b2SJames Morris  */
771f5c1d5b2SJames Morris int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid, u32 def_sid)
772f5c1d5b2SJames Morris {
773f5c1d5b2SJames Morris 	return security_context_to_sid_core(scontext, scontext_len,
774f5c1d5b2SJames Morris 	                                    sid, def_sid);
775f5c1d5b2SJames Morris }
776f5c1d5b2SJames Morris 
7771da177e4SLinus Torvalds static int compute_sid_handle_invalid_context(
7781da177e4SLinus Torvalds 	struct context *scontext,
7791da177e4SLinus Torvalds 	struct context *tcontext,
7801da177e4SLinus Torvalds 	u16 tclass,
7811da177e4SLinus Torvalds 	struct context *newcontext)
7821da177e4SLinus Torvalds {
7831da177e4SLinus Torvalds 	char *s = NULL, *t = NULL, *n = NULL;
7841da177e4SLinus Torvalds 	u32 slen, tlen, nlen;
7851da177e4SLinus Torvalds 
7861da177e4SLinus Torvalds 	if (context_struct_to_string(scontext, &s, &slen) < 0)
7871da177e4SLinus Torvalds 		goto out;
7881da177e4SLinus Torvalds 	if (context_struct_to_string(tcontext, &t, &tlen) < 0)
7891da177e4SLinus Torvalds 		goto out;
7901da177e4SLinus Torvalds 	if (context_struct_to_string(newcontext, &n, &nlen) < 0)
7911da177e4SLinus Torvalds 		goto out;
7929ad9ad38SDavid Woodhouse 	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
7931da177e4SLinus Torvalds 		  "security_compute_sid:  invalid context %s"
7941da177e4SLinus Torvalds 		  " for scontext=%s"
7951da177e4SLinus Torvalds 		  " tcontext=%s"
7961da177e4SLinus Torvalds 		  " tclass=%s",
7971da177e4SLinus Torvalds 		  n, s, t, policydb.p_class_val_to_name[tclass-1]);
7981da177e4SLinus Torvalds out:
7991da177e4SLinus Torvalds 	kfree(s);
8001da177e4SLinus Torvalds 	kfree(t);
8011da177e4SLinus Torvalds 	kfree(n);
8021da177e4SLinus Torvalds 	if (!selinux_enforcing)
8031da177e4SLinus Torvalds 		return 0;
8041da177e4SLinus Torvalds 	return -EACCES;
8051da177e4SLinus Torvalds }
8061da177e4SLinus Torvalds 
8071da177e4SLinus Torvalds static int security_compute_sid(u32 ssid,
8081da177e4SLinus Torvalds 				u32 tsid,
8091da177e4SLinus Torvalds 				u16 tclass,
8101da177e4SLinus Torvalds 				u32 specified,
8111da177e4SLinus Torvalds 				u32 *out_sid)
8121da177e4SLinus Torvalds {
8131da177e4SLinus Torvalds 	struct context *scontext = NULL, *tcontext = NULL, newcontext;
8141da177e4SLinus Torvalds 	struct role_trans *roletr = NULL;
8151da177e4SLinus Torvalds 	struct avtab_key avkey;
8161da177e4SLinus Torvalds 	struct avtab_datum *avdatum;
8171da177e4SLinus Torvalds 	struct avtab_node *node;
8181da177e4SLinus Torvalds 	int rc = 0;
8191da177e4SLinus Torvalds 
8201da177e4SLinus Torvalds 	if (!ss_initialized) {
8211da177e4SLinus Torvalds 		switch (tclass) {
8221da177e4SLinus Torvalds 		case SECCLASS_PROCESS:
8231da177e4SLinus Torvalds 			*out_sid = ssid;
8241da177e4SLinus Torvalds 			break;
8251da177e4SLinus Torvalds 		default:
8261da177e4SLinus Torvalds 			*out_sid = tsid;
8271da177e4SLinus Torvalds 			break;
8281da177e4SLinus Torvalds 		}
8291da177e4SLinus Torvalds 		goto out;
8301da177e4SLinus Torvalds 	}
8311da177e4SLinus Torvalds 
8321da177e4SLinus Torvalds 	POLICY_RDLOCK;
8331da177e4SLinus Torvalds 
8341da177e4SLinus Torvalds 	scontext = sidtab_search(&sidtab, ssid);
8351da177e4SLinus Torvalds 	if (!scontext) {
8361da177e4SLinus Torvalds 		printk(KERN_ERR "security_compute_sid:  unrecognized SID %d\n",
8371da177e4SLinus Torvalds 		       ssid);
8381da177e4SLinus Torvalds 		rc = -EINVAL;
8391da177e4SLinus Torvalds 		goto out_unlock;
8401da177e4SLinus Torvalds 	}
8411da177e4SLinus Torvalds 	tcontext = sidtab_search(&sidtab, tsid);
8421da177e4SLinus Torvalds 	if (!tcontext) {
8431da177e4SLinus Torvalds 		printk(KERN_ERR "security_compute_sid:  unrecognized SID %d\n",
8441da177e4SLinus Torvalds 		       tsid);
8451da177e4SLinus Torvalds 		rc = -EINVAL;
8461da177e4SLinus Torvalds 		goto out_unlock;
8471da177e4SLinus Torvalds 	}
8481da177e4SLinus Torvalds 
8491da177e4SLinus Torvalds 	context_init(&newcontext);
8501da177e4SLinus Torvalds 
8511da177e4SLinus Torvalds 	/* Set the user identity. */
8521da177e4SLinus Torvalds 	switch (specified) {
8531da177e4SLinus Torvalds 	case AVTAB_TRANSITION:
8541da177e4SLinus Torvalds 	case AVTAB_CHANGE:
8551da177e4SLinus Torvalds 		/* Use the process user identity. */
8561da177e4SLinus Torvalds 		newcontext.user = scontext->user;
8571da177e4SLinus Torvalds 		break;
8581da177e4SLinus Torvalds 	case AVTAB_MEMBER:
8591da177e4SLinus Torvalds 		/* Use the related object owner. */
8601da177e4SLinus Torvalds 		newcontext.user = tcontext->user;
8611da177e4SLinus Torvalds 		break;
8621da177e4SLinus Torvalds 	}
8631da177e4SLinus Torvalds 
8641da177e4SLinus Torvalds 	/* Set the role and type to default values. */
8651da177e4SLinus Torvalds 	switch (tclass) {
8661da177e4SLinus Torvalds 	case SECCLASS_PROCESS:
8671da177e4SLinus Torvalds 		/* Use the current role and type of process. */
8681da177e4SLinus Torvalds 		newcontext.role = scontext->role;
8691da177e4SLinus Torvalds 		newcontext.type = scontext->type;
8701da177e4SLinus Torvalds 		break;
8711da177e4SLinus Torvalds 	default:
8721da177e4SLinus Torvalds 		/* Use the well-defined object role. */
8731da177e4SLinus Torvalds 		newcontext.role = OBJECT_R_VAL;
8741da177e4SLinus Torvalds 		/* Use the type of the related object. */
8751da177e4SLinus Torvalds 		newcontext.type = tcontext->type;
8761da177e4SLinus Torvalds 	}
8771da177e4SLinus Torvalds 
8781da177e4SLinus Torvalds 	/* Look for a type transition/member/change rule. */
8791da177e4SLinus Torvalds 	avkey.source_type = scontext->type;
8801da177e4SLinus Torvalds 	avkey.target_type = tcontext->type;
8811da177e4SLinus Torvalds 	avkey.target_class = tclass;
882782ebb99SStephen Smalley 	avkey.specified = specified;
883782ebb99SStephen Smalley 	avdatum = avtab_search(&policydb.te_avtab, &avkey);
8841da177e4SLinus Torvalds 
8851da177e4SLinus Torvalds 	/* If no permanent rule, also check for enabled conditional rules */
8861da177e4SLinus Torvalds 	if(!avdatum) {
887782ebb99SStephen Smalley 		node = avtab_search_node(&policydb.te_cond_avtab, &avkey);
8881da177e4SLinus Torvalds 		for (; node != NULL; node = avtab_search_node_next(node, specified)) {
889782ebb99SStephen Smalley 			if (node->key.specified & AVTAB_ENABLED) {
8901da177e4SLinus Torvalds 				avdatum = &node->datum;
8911da177e4SLinus Torvalds 				break;
8921da177e4SLinus Torvalds 			}
8931da177e4SLinus Torvalds 		}
8941da177e4SLinus Torvalds 	}
8951da177e4SLinus Torvalds 
896782ebb99SStephen Smalley 	if (avdatum) {
8971da177e4SLinus Torvalds 		/* Use the type from the type transition/member/change rule. */
898782ebb99SStephen Smalley 		newcontext.type = avdatum->data;
8991da177e4SLinus Torvalds 	}
9001da177e4SLinus Torvalds 
9011da177e4SLinus Torvalds 	/* Check for class-specific changes. */
9021da177e4SLinus Torvalds 	switch (tclass) {
9031da177e4SLinus Torvalds 	case SECCLASS_PROCESS:
9041da177e4SLinus Torvalds 		if (specified & AVTAB_TRANSITION) {
9051da177e4SLinus Torvalds 			/* Look for a role transition rule. */
9061da177e4SLinus Torvalds 			for (roletr = policydb.role_tr; roletr;
9071da177e4SLinus Torvalds 			     roletr = roletr->next) {
9081da177e4SLinus Torvalds 				if (roletr->role == scontext->role &&
9091da177e4SLinus Torvalds 				    roletr->type == tcontext->type) {
9101da177e4SLinus Torvalds 					/* Use the role transition rule. */
9111da177e4SLinus Torvalds 					newcontext.role = roletr->new_role;
9121da177e4SLinus Torvalds 					break;
9131da177e4SLinus Torvalds 				}
9141da177e4SLinus Torvalds 			}
9151da177e4SLinus Torvalds 		}
9161da177e4SLinus Torvalds 		break;
9171da177e4SLinus Torvalds 	default:
9181da177e4SLinus Torvalds 		break;
9191da177e4SLinus Torvalds 	}
9201da177e4SLinus Torvalds 
9211da177e4SLinus Torvalds 	/* Set the MLS attributes.
9221da177e4SLinus Torvalds 	   This is done last because it may allocate memory. */
9231da177e4SLinus Torvalds 	rc = mls_compute_sid(scontext, tcontext, tclass, specified, &newcontext);
9241da177e4SLinus Torvalds 	if (rc)
9251da177e4SLinus Torvalds 		goto out_unlock;
9261da177e4SLinus Torvalds 
9271da177e4SLinus Torvalds 	/* Check the validity of the context. */
9281da177e4SLinus Torvalds 	if (!policydb_context_isvalid(&policydb, &newcontext)) {
9291da177e4SLinus Torvalds 		rc = compute_sid_handle_invalid_context(scontext,
9301da177e4SLinus Torvalds 							tcontext,
9311da177e4SLinus Torvalds 							tclass,
9321da177e4SLinus Torvalds 							&newcontext);
9331da177e4SLinus Torvalds 		if (rc)
9341da177e4SLinus Torvalds 			goto out_unlock;
9351da177e4SLinus Torvalds 	}
9361da177e4SLinus Torvalds 	/* Obtain the sid for the context. */
9371da177e4SLinus Torvalds 	rc = sidtab_context_to_sid(&sidtab, &newcontext, out_sid);
9381da177e4SLinus Torvalds out_unlock:
9391da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
9401da177e4SLinus Torvalds 	context_destroy(&newcontext);
9411da177e4SLinus Torvalds out:
9421da177e4SLinus Torvalds 	return rc;
9431da177e4SLinus Torvalds }
9441da177e4SLinus Torvalds 
9451da177e4SLinus Torvalds /**
9461da177e4SLinus Torvalds  * security_transition_sid - Compute the SID for a new subject/object.
9471da177e4SLinus Torvalds  * @ssid: source security identifier
9481da177e4SLinus Torvalds  * @tsid: target security identifier
9491da177e4SLinus Torvalds  * @tclass: target security class
9501da177e4SLinus Torvalds  * @out_sid: security identifier for new subject/object
9511da177e4SLinus Torvalds  *
9521da177e4SLinus Torvalds  * Compute a SID to use for labeling a new subject or object in the
9531da177e4SLinus Torvalds  * class @tclass based on a SID pair (@ssid, @tsid).
9541da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
9551da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the new SID was
9561da177e4SLinus Torvalds  * computed successfully.
9571da177e4SLinus Torvalds  */
9581da177e4SLinus Torvalds int security_transition_sid(u32 ssid,
9591da177e4SLinus Torvalds 			    u32 tsid,
9601da177e4SLinus Torvalds 			    u16 tclass,
9611da177e4SLinus Torvalds 			    u32 *out_sid)
9621da177e4SLinus Torvalds {
9631da177e4SLinus Torvalds 	return security_compute_sid(ssid, tsid, tclass, AVTAB_TRANSITION, out_sid);
9641da177e4SLinus Torvalds }
9651da177e4SLinus Torvalds 
9661da177e4SLinus Torvalds /**
9671da177e4SLinus Torvalds  * security_member_sid - Compute the SID for member selection.
9681da177e4SLinus Torvalds  * @ssid: source security identifier
9691da177e4SLinus Torvalds  * @tsid: target security identifier
9701da177e4SLinus Torvalds  * @tclass: target security class
9711da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
9721da177e4SLinus Torvalds  *
9731da177e4SLinus Torvalds  * Compute a SID to use when selecting a member of a polyinstantiated
9741da177e4SLinus Torvalds  * object of class @tclass based on a SID pair (@ssid, @tsid).
9751da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
9761da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
9771da177e4SLinus Torvalds  * computed successfully.
9781da177e4SLinus Torvalds  */
9791da177e4SLinus Torvalds int security_member_sid(u32 ssid,
9801da177e4SLinus Torvalds 			u32 tsid,
9811da177e4SLinus Torvalds 			u16 tclass,
9821da177e4SLinus Torvalds 			u32 *out_sid)
9831da177e4SLinus Torvalds {
9841da177e4SLinus Torvalds 	return security_compute_sid(ssid, tsid, tclass, AVTAB_MEMBER, out_sid);
9851da177e4SLinus Torvalds }
9861da177e4SLinus Torvalds 
9871da177e4SLinus Torvalds /**
9881da177e4SLinus Torvalds  * security_change_sid - Compute the SID for object relabeling.
9891da177e4SLinus Torvalds  * @ssid: source security identifier
9901da177e4SLinus Torvalds  * @tsid: target security identifier
9911da177e4SLinus Torvalds  * @tclass: target security class
9921da177e4SLinus Torvalds  * @out_sid: security identifier for selected member
9931da177e4SLinus Torvalds  *
9941da177e4SLinus Torvalds  * Compute a SID to use for relabeling an object of class @tclass
9951da177e4SLinus Torvalds  * based on a SID pair (@ssid, @tsid).
9961da177e4SLinus Torvalds  * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
9971da177e4SLinus Torvalds  * if insufficient memory is available, or %0 if the SID was
9981da177e4SLinus Torvalds  * computed successfully.
9991da177e4SLinus Torvalds  */
10001da177e4SLinus Torvalds int security_change_sid(u32 ssid,
10011da177e4SLinus Torvalds 			u32 tsid,
10021da177e4SLinus Torvalds 			u16 tclass,
10031da177e4SLinus Torvalds 			u32 *out_sid)
10041da177e4SLinus Torvalds {
10051da177e4SLinus Torvalds 	return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, out_sid);
10061da177e4SLinus Torvalds }
10071da177e4SLinus Torvalds 
10081da177e4SLinus Torvalds /*
10091da177e4SLinus Torvalds  * Verify that each permission that is defined under the
10101da177e4SLinus Torvalds  * existing policy is still defined with the same value
10111da177e4SLinus Torvalds  * in the new policy.
10121da177e4SLinus Torvalds  */
10131da177e4SLinus Torvalds static int validate_perm(void *key, void *datum, void *p)
10141da177e4SLinus Torvalds {
10151da177e4SLinus Torvalds 	struct hashtab *h;
10161da177e4SLinus Torvalds 	struct perm_datum *perdatum, *perdatum2;
10171da177e4SLinus Torvalds 	int rc = 0;
10181da177e4SLinus Torvalds 
10191da177e4SLinus Torvalds 
10201da177e4SLinus Torvalds 	h = p;
10211da177e4SLinus Torvalds 	perdatum = datum;
10221da177e4SLinus Torvalds 
10231da177e4SLinus Torvalds 	perdatum2 = hashtab_search(h, key);
10241da177e4SLinus Torvalds 	if (!perdatum2) {
10251da177e4SLinus Torvalds 		printk(KERN_ERR "security:  permission %s disappeared",
10261da177e4SLinus Torvalds 		       (char *)key);
10271da177e4SLinus Torvalds 		rc = -ENOENT;
10281da177e4SLinus Torvalds 		goto out;
10291da177e4SLinus Torvalds 	}
10301da177e4SLinus Torvalds 	if (perdatum->value != perdatum2->value) {
10311da177e4SLinus Torvalds 		printk(KERN_ERR "security:  the value of permission %s changed",
10321da177e4SLinus Torvalds 		       (char *)key);
10331da177e4SLinus Torvalds 		rc = -EINVAL;
10341da177e4SLinus Torvalds 	}
10351da177e4SLinus Torvalds out:
10361da177e4SLinus Torvalds 	return rc;
10371da177e4SLinus Torvalds }
10381da177e4SLinus Torvalds 
10391da177e4SLinus Torvalds /*
10401da177e4SLinus Torvalds  * Verify that each class that is defined under the
10411da177e4SLinus Torvalds  * existing policy is still defined with the same
10421da177e4SLinus Torvalds  * attributes in the new policy.
10431da177e4SLinus Torvalds  */
10441da177e4SLinus Torvalds static int validate_class(void *key, void *datum, void *p)
10451da177e4SLinus Torvalds {
10461da177e4SLinus Torvalds 	struct policydb *newp;
10471da177e4SLinus Torvalds 	struct class_datum *cladatum, *cladatum2;
10481da177e4SLinus Torvalds 	int rc;
10491da177e4SLinus Torvalds 
10501da177e4SLinus Torvalds 	newp = p;
10511da177e4SLinus Torvalds 	cladatum = datum;
10521da177e4SLinus Torvalds 
10531da177e4SLinus Torvalds 	cladatum2 = hashtab_search(newp->p_classes.table, key);
10541da177e4SLinus Torvalds 	if (!cladatum2) {
10551da177e4SLinus Torvalds 		printk(KERN_ERR "security:  class %s disappeared\n",
10561da177e4SLinus Torvalds 		       (char *)key);
10571da177e4SLinus Torvalds 		rc = -ENOENT;
10581da177e4SLinus Torvalds 		goto out;
10591da177e4SLinus Torvalds 	}
10601da177e4SLinus Torvalds 	if (cladatum->value != cladatum2->value) {
10611da177e4SLinus Torvalds 		printk(KERN_ERR "security:  the value of class %s changed\n",
10621da177e4SLinus Torvalds 		       (char *)key);
10631da177e4SLinus Torvalds 		rc = -EINVAL;
10641da177e4SLinus Torvalds 		goto out;
10651da177e4SLinus Torvalds 	}
10661da177e4SLinus Torvalds 	if ((cladatum->comdatum && !cladatum2->comdatum) ||
10671da177e4SLinus Torvalds 	    (!cladatum->comdatum && cladatum2->comdatum)) {
10681da177e4SLinus Torvalds 		printk(KERN_ERR "security:  the inherits clause for the access "
10691da177e4SLinus Torvalds 		       "vector definition for class %s changed\n", (char *)key);
10701da177e4SLinus Torvalds 		rc = -EINVAL;
10711da177e4SLinus Torvalds 		goto out;
10721da177e4SLinus Torvalds 	}
10731da177e4SLinus Torvalds 	if (cladatum->comdatum) {
10741da177e4SLinus Torvalds 		rc = hashtab_map(cladatum->comdatum->permissions.table, validate_perm,
10751da177e4SLinus Torvalds 		                 cladatum2->comdatum->permissions.table);
10761da177e4SLinus Torvalds 		if (rc) {
10771da177e4SLinus Torvalds 			printk(" in the access vector definition for class "
10781da177e4SLinus Torvalds 			       "%s\n", (char *)key);
10791da177e4SLinus Torvalds 			goto out;
10801da177e4SLinus Torvalds 		}
10811da177e4SLinus Torvalds 	}
10821da177e4SLinus Torvalds 	rc = hashtab_map(cladatum->permissions.table, validate_perm,
10831da177e4SLinus Torvalds 	                 cladatum2->permissions.table);
10841da177e4SLinus Torvalds 	if (rc)
10851da177e4SLinus Torvalds 		printk(" in access vector definition for class %s\n",
10861da177e4SLinus Torvalds 		       (char *)key);
10871da177e4SLinus Torvalds out:
10881da177e4SLinus Torvalds 	return rc;
10891da177e4SLinus Torvalds }
10901da177e4SLinus Torvalds 
10911da177e4SLinus Torvalds /* Clone the SID into the new SID table. */
10921da177e4SLinus Torvalds static int clone_sid(u32 sid,
10931da177e4SLinus Torvalds 		     struct context *context,
10941da177e4SLinus Torvalds 		     void *arg)
10951da177e4SLinus Torvalds {
10961da177e4SLinus Torvalds 	struct sidtab *s = arg;
10971da177e4SLinus Torvalds 
10981da177e4SLinus Torvalds 	return sidtab_insert(s, sid, context);
10991da177e4SLinus Torvalds }
11001da177e4SLinus Torvalds 
11011da177e4SLinus Torvalds static inline int convert_context_handle_invalid_context(struct context *context)
11021da177e4SLinus Torvalds {
11031da177e4SLinus Torvalds 	int rc = 0;
11041da177e4SLinus Torvalds 
11051da177e4SLinus Torvalds 	if (selinux_enforcing) {
11061da177e4SLinus Torvalds 		rc = -EINVAL;
11071da177e4SLinus Torvalds 	} else {
11081da177e4SLinus Torvalds 		char *s;
11091da177e4SLinus Torvalds 		u32 len;
11101da177e4SLinus Torvalds 
11111da177e4SLinus Torvalds 		context_struct_to_string(context, &s, &len);
11121da177e4SLinus Torvalds 		printk(KERN_ERR "security:  context %s is invalid\n", s);
11131da177e4SLinus Torvalds 		kfree(s);
11141da177e4SLinus Torvalds 	}
11151da177e4SLinus Torvalds 	return rc;
11161da177e4SLinus Torvalds }
11171da177e4SLinus Torvalds 
11181da177e4SLinus Torvalds struct convert_context_args {
11191da177e4SLinus Torvalds 	struct policydb *oldp;
11201da177e4SLinus Torvalds 	struct policydb *newp;
11211da177e4SLinus Torvalds };
11221da177e4SLinus Torvalds 
11231da177e4SLinus Torvalds /*
11241da177e4SLinus Torvalds  * Convert the values in the security context
11251da177e4SLinus Torvalds  * structure `c' from the values specified
11261da177e4SLinus Torvalds  * in the policy `p->oldp' to the values specified
11271da177e4SLinus Torvalds  * in the policy `p->newp'.  Verify that the
11281da177e4SLinus Torvalds  * context is valid under the new policy.
11291da177e4SLinus Torvalds  */
11301da177e4SLinus Torvalds static int convert_context(u32 key,
11311da177e4SLinus Torvalds 			   struct context *c,
11321da177e4SLinus Torvalds 			   void *p)
11331da177e4SLinus Torvalds {
11341da177e4SLinus Torvalds 	struct convert_context_args *args;
11351da177e4SLinus Torvalds 	struct context oldc;
11361da177e4SLinus Torvalds 	struct role_datum *role;
11371da177e4SLinus Torvalds 	struct type_datum *typdatum;
11381da177e4SLinus Torvalds 	struct user_datum *usrdatum;
11391da177e4SLinus Torvalds 	char *s;
11401da177e4SLinus Torvalds 	u32 len;
11411da177e4SLinus Torvalds 	int rc;
11421da177e4SLinus Torvalds 
11431da177e4SLinus Torvalds 	args = p;
11441da177e4SLinus Torvalds 
11451da177e4SLinus Torvalds 	rc = context_cpy(&oldc, c);
11461da177e4SLinus Torvalds 	if (rc)
11471da177e4SLinus Torvalds 		goto out;
11481da177e4SLinus Torvalds 
11491da177e4SLinus Torvalds 	rc = -EINVAL;
11501da177e4SLinus Torvalds 
11511da177e4SLinus Torvalds 	/* Convert the user. */
11521da177e4SLinus Torvalds 	usrdatum = hashtab_search(args->newp->p_users.table,
11531da177e4SLinus Torvalds 	                          args->oldp->p_user_val_to_name[c->user - 1]);
11541da177e4SLinus Torvalds 	if (!usrdatum) {
11551da177e4SLinus Torvalds 		goto bad;
11561da177e4SLinus Torvalds 	}
11571da177e4SLinus Torvalds 	c->user = usrdatum->value;
11581da177e4SLinus Torvalds 
11591da177e4SLinus Torvalds 	/* Convert the role. */
11601da177e4SLinus Torvalds 	role = hashtab_search(args->newp->p_roles.table,
11611da177e4SLinus Torvalds 	                      args->oldp->p_role_val_to_name[c->role - 1]);
11621da177e4SLinus Torvalds 	if (!role) {
11631da177e4SLinus Torvalds 		goto bad;
11641da177e4SLinus Torvalds 	}
11651da177e4SLinus Torvalds 	c->role = role->value;
11661da177e4SLinus Torvalds 
11671da177e4SLinus Torvalds 	/* Convert the type. */
11681da177e4SLinus Torvalds 	typdatum = hashtab_search(args->newp->p_types.table,
11691da177e4SLinus Torvalds 	                          args->oldp->p_type_val_to_name[c->type - 1]);
11701da177e4SLinus Torvalds 	if (!typdatum) {
11711da177e4SLinus Torvalds 		goto bad;
11721da177e4SLinus Torvalds 	}
11731da177e4SLinus Torvalds 	c->type = typdatum->value;
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds 	rc = mls_convert_context(args->oldp, args->newp, c);
11761da177e4SLinus Torvalds 	if (rc)
11771da177e4SLinus Torvalds 		goto bad;
11781da177e4SLinus Torvalds 
11791da177e4SLinus Torvalds 	/* Check the validity of the new context. */
11801da177e4SLinus Torvalds 	if (!policydb_context_isvalid(args->newp, c)) {
11811da177e4SLinus Torvalds 		rc = convert_context_handle_invalid_context(&oldc);
11821da177e4SLinus Torvalds 		if (rc)
11831da177e4SLinus Torvalds 			goto bad;
11841da177e4SLinus Torvalds 	}
11851da177e4SLinus Torvalds 
11861da177e4SLinus Torvalds 	context_destroy(&oldc);
11871da177e4SLinus Torvalds out:
11881da177e4SLinus Torvalds 	return rc;
11891da177e4SLinus Torvalds bad:
11901da177e4SLinus Torvalds 	context_struct_to_string(&oldc, &s, &len);
11911da177e4SLinus Torvalds 	context_destroy(&oldc);
11921da177e4SLinus Torvalds 	printk(KERN_ERR "security:  invalidating context %s\n", s);
11931da177e4SLinus Torvalds 	kfree(s);
11941da177e4SLinus Torvalds 	goto out;
11951da177e4SLinus Torvalds }
11961da177e4SLinus Torvalds 
11971da177e4SLinus Torvalds extern void selinux_complete_init(void);
11981da177e4SLinus Torvalds 
11991da177e4SLinus Torvalds /**
12001da177e4SLinus Torvalds  * security_load_policy - Load a security policy configuration.
12011da177e4SLinus Torvalds  * @data: binary policy data
12021da177e4SLinus Torvalds  * @len: length of data in bytes
12031da177e4SLinus Torvalds  *
12041da177e4SLinus Torvalds  * Load a new set of security policy configuration data,
12051da177e4SLinus Torvalds  * validate it and convert the SID table as necessary.
12061da177e4SLinus Torvalds  * This function will flush the access vector cache after
12071da177e4SLinus Torvalds  * loading the new policy.
12081da177e4SLinus Torvalds  */
12091da177e4SLinus Torvalds int security_load_policy(void *data, size_t len)
12101da177e4SLinus Torvalds {
12111da177e4SLinus Torvalds 	struct policydb oldpolicydb, newpolicydb;
12121da177e4SLinus Torvalds 	struct sidtab oldsidtab, newsidtab;
12131da177e4SLinus Torvalds 	struct convert_context_args args;
12141da177e4SLinus Torvalds 	u32 seqno;
12151da177e4SLinus Torvalds 	int rc = 0;
12161da177e4SLinus Torvalds 	struct policy_file file = { data, len }, *fp = &file;
12171da177e4SLinus Torvalds 
12181da177e4SLinus Torvalds 	LOAD_LOCK;
12191da177e4SLinus Torvalds 
12201da177e4SLinus Torvalds 	if (!ss_initialized) {
12211da177e4SLinus Torvalds 		avtab_cache_init();
12221da177e4SLinus Torvalds 		if (policydb_read(&policydb, fp)) {
12231da177e4SLinus Torvalds 			LOAD_UNLOCK;
12241da177e4SLinus Torvalds 			avtab_cache_destroy();
12251da177e4SLinus Torvalds 			return -EINVAL;
12261da177e4SLinus Torvalds 		}
12271da177e4SLinus Torvalds 		if (policydb_load_isids(&policydb, &sidtab)) {
12281da177e4SLinus Torvalds 			LOAD_UNLOCK;
12291da177e4SLinus Torvalds 			policydb_destroy(&policydb);
12301da177e4SLinus Torvalds 			avtab_cache_destroy();
12311da177e4SLinus Torvalds 			return -EINVAL;
12321da177e4SLinus Torvalds 		}
12331da177e4SLinus Torvalds 		policydb_loaded_version = policydb.policyvers;
12341da177e4SLinus Torvalds 		ss_initialized = 1;
12354c443d1bSStephen Smalley 		seqno = ++latest_granting;
12361da177e4SLinus Torvalds 		LOAD_UNLOCK;
12371da177e4SLinus Torvalds 		selinux_complete_init();
12384c443d1bSStephen Smalley 		avc_ss_reset(seqno);
12394c443d1bSStephen Smalley 		selnl_notify_policyload(seqno);
12401da177e4SLinus Torvalds 		return 0;
12411da177e4SLinus Torvalds 	}
12421da177e4SLinus Torvalds 
12431da177e4SLinus Torvalds #if 0
12441da177e4SLinus Torvalds 	sidtab_hash_eval(&sidtab, "sids");
12451da177e4SLinus Torvalds #endif
12461da177e4SLinus Torvalds 
12471da177e4SLinus Torvalds 	if (policydb_read(&newpolicydb, fp)) {
12481da177e4SLinus Torvalds 		LOAD_UNLOCK;
12491da177e4SLinus Torvalds 		return -EINVAL;
12501da177e4SLinus Torvalds 	}
12511da177e4SLinus Torvalds 
12521da177e4SLinus Torvalds 	sidtab_init(&newsidtab);
12531da177e4SLinus Torvalds 
12541da177e4SLinus Torvalds 	/* Verify that the existing classes did not change. */
12551da177e4SLinus Torvalds 	if (hashtab_map(policydb.p_classes.table, validate_class, &newpolicydb)) {
12561da177e4SLinus Torvalds 		printk(KERN_ERR "security:  the definition of an existing "
12571da177e4SLinus Torvalds 		       "class changed\n");
12581da177e4SLinus Torvalds 		rc = -EINVAL;
12591da177e4SLinus Torvalds 		goto err;
12601da177e4SLinus Torvalds 	}
12611da177e4SLinus Torvalds 
12621da177e4SLinus Torvalds 	/* Clone the SID table. */
12631da177e4SLinus Torvalds 	sidtab_shutdown(&sidtab);
12641da177e4SLinus Torvalds 	if (sidtab_map(&sidtab, clone_sid, &newsidtab)) {
12651da177e4SLinus Torvalds 		rc = -ENOMEM;
12661da177e4SLinus Torvalds 		goto err;
12671da177e4SLinus Torvalds 	}
12681da177e4SLinus Torvalds 
12691da177e4SLinus Torvalds 	/* Convert the internal representations of contexts
12701da177e4SLinus Torvalds 	   in the new SID table and remove invalid SIDs. */
12711da177e4SLinus Torvalds 	args.oldp = &policydb;
12721da177e4SLinus Torvalds 	args.newp = &newpolicydb;
12731da177e4SLinus Torvalds 	sidtab_map_remove_on_error(&newsidtab, convert_context, &args);
12741da177e4SLinus Torvalds 
12751da177e4SLinus Torvalds 	/* Save the old policydb and SID table to free later. */
12761da177e4SLinus Torvalds 	memcpy(&oldpolicydb, &policydb, sizeof policydb);
12771da177e4SLinus Torvalds 	sidtab_set(&oldsidtab, &sidtab);
12781da177e4SLinus Torvalds 
12791da177e4SLinus Torvalds 	/* Install the new policydb and SID table. */
12801da177e4SLinus Torvalds 	POLICY_WRLOCK;
12811da177e4SLinus Torvalds 	memcpy(&policydb, &newpolicydb, sizeof policydb);
12821da177e4SLinus Torvalds 	sidtab_set(&sidtab, &newsidtab);
12831da177e4SLinus Torvalds 	seqno = ++latest_granting;
12841da177e4SLinus Torvalds 	policydb_loaded_version = policydb.policyvers;
12851da177e4SLinus Torvalds 	POLICY_WRUNLOCK;
12861da177e4SLinus Torvalds 	LOAD_UNLOCK;
12871da177e4SLinus Torvalds 
12881da177e4SLinus Torvalds 	/* Free the old policydb and SID table. */
12891da177e4SLinus Torvalds 	policydb_destroy(&oldpolicydb);
12901da177e4SLinus Torvalds 	sidtab_destroy(&oldsidtab);
12911da177e4SLinus Torvalds 
12921da177e4SLinus Torvalds 	avc_ss_reset(seqno);
12931da177e4SLinus Torvalds 	selnl_notify_policyload(seqno);
12941da177e4SLinus Torvalds 
12951da177e4SLinus Torvalds 	return 0;
12961da177e4SLinus Torvalds 
12971da177e4SLinus Torvalds err:
12981da177e4SLinus Torvalds 	LOAD_UNLOCK;
12991da177e4SLinus Torvalds 	sidtab_destroy(&newsidtab);
13001da177e4SLinus Torvalds 	policydb_destroy(&newpolicydb);
13011da177e4SLinus Torvalds 	return rc;
13021da177e4SLinus Torvalds 
13031da177e4SLinus Torvalds }
13041da177e4SLinus Torvalds 
13051da177e4SLinus Torvalds /**
13061da177e4SLinus Torvalds  * security_port_sid - Obtain the SID for a port.
13071da177e4SLinus Torvalds  * @domain: communication domain aka address family
13081da177e4SLinus Torvalds  * @type: socket type
13091da177e4SLinus Torvalds  * @protocol: protocol number
13101da177e4SLinus Torvalds  * @port: port number
13111da177e4SLinus Torvalds  * @out_sid: security identifier
13121da177e4SLinus Torvalds  */
13131da177e4SLinus Torvalds int security_port_sid(u16 domain,
13141da177e4SLinus Torvalds 		      u16 type,
13151da177e4SLinus Torvalds 		      u8 protocol,
13161da177e4SLinus Torvalds 		      u16 port,
13171da177e4SLinus Torvalds 		      u32 *out_sid)
13181da177e4SLinus Torvalds {
13191da177e4SLinus Torvalds 	struct ocontext *c;
13201da177e4SLinus Torvalds 	int rc = 0;
13211da177e4SLinus Torvalds 
13221da177e4SLinus Torvalds 	POLICY_RDLOCK;
13231da177e4SLinus Torvalds 
13241da177e4SLinus Torvalds 	c = policydb.ocontexts[OCON_PORT];
13251da177e4SLinus Torvalds 	while (c) {
13261da177e4SLinus Torvalds 		if (c->u.port.protocol == protocol &&
13271da177e4SLinus Torvalds 		    c->u.port.low_port <= port &&
13281da177e4SLinus Torvalds 		    c->u.port.high_port >= port)
13291da177e4SLinus Torvalds 			break;
13301da177e4SLinus Torvalds 		c = c->next;
13311da177e4SLinus Torvalds 	}
13321da177e4SLinus Torvalds 
13331da177e4SLinus Torvalds 	if (c) {
13341da177e4SLinus Torvalds 		if (!c->sid[0]) {
13351da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
13361da177e4SLinus Torvalds 						   &c->context[0],
13371da177e4SLinus Torvalds 						   &c->sid[0]);
13381da177e4SLinus Torvalds 			if (rc)
13391da177e4SLinus Torvalds 				goto out;
13401da177e4SLinus Torvalds 		}
13411da177e4SLinus Torvalds 		*out_sid = c->sid[0];
13421da177e4SLinus Torvalds 	} else {
13431da177e4SLinus Torvalds 		*out_sid = SECINITSID_PORT;
13441da177e4SLinus Torvalds 	}
13451da177e4SLinus Torvalds 
13461da177e4SLinus Torvalds out:
13471da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
13481da177e4SLinus Torvalds 	return rc;
13491da177e4SLinus Torvalds }
13501da177e4SLinus Torvalds 
13511da177e4SLinus Torvalds /**
13521da177e4SLinus Torvalds  * security_netif_sid - Obtain the SID for a network interface.
13531da177e4SLinus Torvalds  * @name: interface name
13541da177e4SLinus Torvalds  * @if_sid: interface SID
13551da177e4SLinus Torvalds  * @msg_sid: default SID for received packets
13561da177e4SLinus Torvalds  */
13571da177e4SLinus Torvalds int security_netif_sid(char *name,
13581da177e4SLinus Torvalds 		       u32 *if_sid,
13591da177e4SLinus Torvalds 		       u32 *msg_sid)
13601da177e4SLinus Torvalds {
13611da177e4SLinus Torvalds 	int rc = 0;
13621da177e4SLinus Torvalds 	struct ocontext *c;
13631da177e4SLinus Torvalds 
13641da177e4SLinus Torvalds 	POLICY_RDLOCK;
13651da177e4SLinus Torvalds 
13661da177e4SLinus Torvalds 	c = policydb.ocontexts[OCON_NETIF];
13671da177e4SLinus Torvalds 	while (c) {
13681da177e4SLinus Torvalds 		if (strcmp(name, c->u.name) == 0)
13691da177e4SLinus Torvalds 			break;
13701da177e4SLinus Torvalds 		c = c->next;
13711da177e4SLinus Torvalds 	}
13721da177e4SLinus Torvalds 
13731da177e4SLinus Torvalds 	if (c) {
13741da177e4SLinus Torvalds 		if (!c->sid[0] || !c->sid[1]) {
13751da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
13761da177e4SLinus Torvalds 						  &c->context[0],
13771da177e4SLinus Torvalds 						  &c->sid[0]);
13781da177e4SLinus Torvalds 			if (rc)
13791da177e4SLinus Torvalds 				goto out;
13801da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
13811da177e4SLinus Torvalds 						   &c->context[1],
13821da177e4SLinus Torvalds 						   &c->sid[1]);
13831da177e4SLinus Torvalds 			if (rc)
13841da177e4SLinus Torvalds 				goto out;
13851da177e4SLinus Torvalds 		}
13861da177e4SLinus Torvalds 		*if_sid = c->sid[0];
13871da177e4SLinus Torvalds 		*msg_sid = c->sid[1];
13881da177e4SLinus Torvalds 	} else {
13891da177e4SLinus Torvalds 		*if_sid = SECINITSID_NETIF;
13901da177e4SLinus Torvalds 		*msg_sid = SECINITSID_NETMSG;
13911da177e4SLinus Torvalds 	}
13921da177e4SLinus Torvalds 
13931da177e4SLinus Torvalds out:
13941da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
13951da177e4SLinus Torvalds 	return rc;
13961da177e4SLinus Torvalds }
13971da177e4SLinus Torvalds 
13981da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
13991da177e4SLinus Torvalds {
14001da177e4SLinus Torvalds 	int i, fail = 0;
14011da177e4SLinus Torvalds 
14021da177e4SLinus Torvalds 	for(i = 0; i < 4; i++)
14031da177e4SLinus Torvalds 		if(addr[i] != (input[i] & mask[i])) {
14041da177e4SLinus Torvalds 			fail = 1;
14051da177e4SLinus Torvalds 			break;
14061da177e4SLinus Torvalds 		}
14071da177e4SLinus Torvalds 
14081da177e4SLinus Torvalds 	return !fail;
14091da177e4SLinus Torvalds }
14101da177e4SLinus Torvalds 
14111da177e4SLinus Torvalds /**
14121da177e4SLinus Torvalds  * security_node_sid - Obtain the SID for a node (host).
14131da177e4SLinus Torvalds  * @domain: communication domain aka address family
14141da177e4SLinus Torvalds  * @addrp: address
14151da177e4SLinus Torvalds  * @addrlen: address length in bytes
14161da177e4SLinus Torvalds  * @out_sid: security identifier
14171da177e4SLinus Torvalds  */
14181da177e4SLinus Torvalds int security_node_sid(u16 domain,
14191da177e4SLinus Torvalds 		      void *addrp,
14201da177e4SLinus Torvalds 		      u32 addrlen,
14211da177e4SLinus Torvalds 		      u32 *out_sid)
14221da177e4SLinus Torvalds {
14231da177e4SLinus Torvalds 	int rc = 0;
14241da177e4SLinus Torvalds 	struct ocontext *c;
14251da177e4SLinus Torvalds 
14261da177e4SLinus Torvalds 	POLICY_RDLOCK;
14271da177e4SLinus Torvalds 
14281da177e4SLinus Torvalds 	switch (domain) {
14291da177e4SLinus Torvalds 	case AF_INET: {
14301da177e4SLinus Torvalds 		u32 addr;
14311da177e4SLinus Torvalds 
14321da177e4SLinus Torvalds 		if (addrlen != sizeof(u32)) {
14331da177e4SLinus Torvalds 			rc = -EINVAL;
14341da177e4SLinus Torvalds 			goto out;
14351da177e4SLinus Torvalds 		}
14361da177e4SLinus Torvalds 
14371da177e4SLinus Torvalds 		addr = *((u32 *)addrp);
14381da177e4SLinus Torvalds 
14391da177e4SLinus Torvalds 		c = policydb.ocontexts[OCON_NODE];
14401da177e4SLinus Torvalds 		while (c) {
14411da177e4SLinus Torvalds 			if (c->u.node.addr == (addr & c->u.node.mask))
14421da177e4SLinus Torvalds 				break;
14431da177e4SLinus Torvalds 			c = c->next;
14441da177e4SLinus Torvalds 		}
14451da177e4SLinus Torvalds 		break;
14461da177e4SLinus Torvalds 	}
14471da177e4SLinus Torvalds 
14481da177e4SLinus Torvalds 	case AF_INET6:
14491da177e4SLinus Torvalds 		if (addrlen != sizeof(u64) * 2) {
14501da177e4SLinus Torvalds 			rc = -EINVAL;
14511da177e4SLinus Torvalds 			goto out;
14521da177e4SLinus Torvalds 		}
14531da177e4SLinus Torvalds 		c = policydb.ocontexts[OCON_NODE6];
14541da177e4SLinus Torvalds 		while (c) {
14551da177e4SLinus Torvalds 			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
14561da177e4SLinus Torvalds 						c->u.node6.mask))
14571da177e4SLinus Torvalds 				break;
14581da177e4SLinus Torvalds 			c = c->next;
14591da177e4SLinus Torvalds 		}
14601da177e4SLinus Torvalds 		break;
14611da177e4SLinus Torvalds 
14621da177e4SLinus Torvalds 	default:
14631da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
14641da177e4SLinus Torvalds 		goto out;
14651da177e4SLinus Torvalds 	}
14661da177e4SLinus Torvalds 
14671da177e4SLinus Torvalds 	if (c) {
14681da177e4SLinus Torvalds 		if (!c->sid[0]) {
14691da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
14701da177e4SLinus Torvalds 						   &c->context[0],
14711da177e4SLinus Torvalds 						   &c->sid[0]);
14721da177e4SLinus Torvalds 			if (rc)
14731da177e4SLinus Torvalds 				goto out;
14741da177e4SLinus Torvalds 		}
14751da177e4SLinus Torvalds 		*out_sid = c->sid[0];
14761da177e4SLinus Torvalds 	} else {
14771da177e4SLinus Torvalds 		*out_sid = SECINITSID_NODE;
14781da177e4SLinus Torvalds 	}
14791da177e4SLinus Torvalds 
14801da177e4SLinus Torvalds out:
14811da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
14821da177e4SLinus Torvalds 	return rc;
14831da177e4SLinus Torvalds }
14841da177e4SLinus Torvalds 
14851da177e4SLinus Torvalds #define SIDS_NEL 25
14861da177e4SLinus Torvalds 
14871da177e4SLinus Torvalds /**
14881da177e4SLinus Torvalds  * security_get_user_sids - Obtain reachable SIDs for a user.
14891da177e4SLinus Torvalds  * @fromsid: starting SID
14901da177e4SLinus Torvalds  * @username: username
14911da177e4SLinus Torvalds  * @sids: array of reachable SIDs for user
14921da177e4SLinus Torvalds  * @nel: number of elements in @sids
14931da177e4SLinus Torvalds  *
14941da177e4SLinus Torvalds  * Generate the set of SIDs for legal security contexts
14951da177e4SLinus Torvalds  * for a given user that can be reached by @fromsid.
14961da177e4SLinus Torvalds  * Set *@sids to point to a dynamically allocated
14971da177e4SLinus Torvalds  * array containing the set of SIDs.  Set *@nel to the
14981da177e4SLinus Torvalds  * number of elements in the array.
14991da177e4SLinus Torvalds  */
15001da177e4SLinus Torvalds 
15011da177e4SLinus Torvalds int security_get_user_sids(u32 fromsid,
15021da177e4SLinus Torvalds 	                   char *username,
15031da177e4SLinus Torvalds 			   u32 **sids,
15041da177e4SLinus Torvalds 			   u32 *nel)
15051da177e4SLinus Torvalds {
15061da177e4SLinus Torvalds 	struct context *fromcon, usercon;
15071da177e4SLinus Torvalds 	u32 *mysids, *mysids2, sid;
15081da177e4SLinus Torvalds 	u32 mynel = 0, maxnel = SIDS_NEL;
15091da177e4SLinus Torvalds 	struct user_datum *user;
15101da177e4SLinus Torvalds 	struct role_datum *role;
15111da177e4SLinus Torvalds 	struct av_decision avd;
1512782ebb99SStephen Smalley 	struct ebitmap_node *rnode, *tnode;
15131da177e4SLinus Torvalds 	int rc = 0, i, j;
15141da177e4SLinus Torvalds 
15151da177e4SLinus Torvalds 	if (!ss_initialized) {
15161da177e4SLinus Torvalds 		*sids = NULL;
15171da177e4SLinus Torvalds 		*nel = 0;
15181da177e4SLinus Torvalds 		goto out;
15191da177e4SLinus Torvalds 	}
15201da177e4SLinus Torvalds 
15211da177e4SLinus Torvalds 	POLICY_RDLOCK;
15221da177e4SLinus Torvalds 
15231da177e4SLinus Torvalds 	fromcon = sidtab_search(&sidtab, fromsid);
15241da177e4SLinus Torvalds 	if (!fromcon) {
15251da177e4SLinus Torvalds 		rc = -EINVAL;
15261da177e4SLinus Torvalds 		goto out_unlock;
15271da177e4SLinus Torvalds 	}
15281da177e4SLinus Torvalds 
15291da177e4SLinus Torvalds 	user = hashtab_search(policydb.p_users.table, username);
15301da177e4SLinus Torvalds 	if (!user) {
15311da177e4SLinus Torvalds 		rc = -EINVAL;
15321da177e4SLinus Torvalds 		goto out_unlock;
15331da177e4SLinus Torvalds 	}
15341da177e4SLinus Torvalds 	usercon.user = user->value;
15351da177e4SLinus Torvalds 
153689d155efSJames Morris 	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
15371da177e4SLinus Torvalds 	if (!mysids) {
15381da177e4SLinus Torvalds 		rc = -ENOMEM;
15391da177e4SLinus Torvalds 		goto out_unlock;
15401da177e4SLinus Torvalds 	}
15411da177e4SLinus Torvalds 
1542782ebb99SStephen Smalley 	ebitmap_for_each_bit(&user->roles, rnode, i) {
1543782ebb99SStephen Smalley 		if (!ebitmap_node_get_bit(rnode, i))
15441da177e4SLinus Torvalds 			continue;
15451da177e4SLinus Torvalds 		role = policydb.role_val_to_struct[i];
15461da177e4SLinus Torvalds 		usercon.role = i+1;
1547782ebb99SStephen Smalley 		ebitmap_for_each_bit(&role->types, tnode, j) {
1548782ebb99SStephen Smalley 			if (!ebitmap_node_get_bit(tnode, j))
15491da177e4SLinus Torvalds 				continue;
15501da177e4SLinus Torvalds 			usercon.type = j+1;
15511da177e4SLinus Torvalds 
15521da177e4SLinus Torvalds 			if (mls_setup_user_range(fromcon, user, &usercon))
15531da177e4SLinus Torvalds 				continue;
15541da177e4SLinus Torvalds 
15551da177e4SLinus Torvalds 			rc = context_struct_compute_av(fromcon, &usercon,
15561da177e4SLinus Torvalds 						       SECCLASS_PROCESS,
15571da177e4SLinus Torvalds 						       PROCESS__TRANSITION,
15581da177e4SLinus Torvalds 						       &avd);
15591da177e4SLinus Torvalds 			if (rc ||  !(avd.allowed & PROCESS__TRANSITION))
15601da177e4SLinus Torvalds 				continue;
15611da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab, &usercon, &sid);
15621da177e4SLinus Torvalds 			if (rc) {
15631da177e4SLinus Torvalds 				kfree(mysids);
15641da177e4SLinus Torvalds 				goto out_unlock;
15651da177e4SLinus Torvalds 			}
15661da177e4SLinus Torvalds 			if (mynel < maxnel) {
15671da177e4SLinus Torvalds 				mysids[mynel++] = sid;
15681da177e4SLinus Torvalds 			} else {
15691da177e4SLinus Torvalds 				maxnel += SIDS_NEL;
157089d155efSJames Morris 				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
15711da177e4SLinus Torvalds 				if (!mysids2) {
15721da177e4SLinus Torvalds 					rc = -ENOMEM;
15731da177e4SLinus Torvalds 					kfree(mysids);
15741da177e4SLinus Torvalds 					goto out_unlock;
15751da177e4SLinus Torvalds 				}
15761da177e4SLinus Torvalds 				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
15771da177e4SLinus Torvalds 				kfree(mysids);
15781da177e4SLinus Torvalds 				mysids = mysids2;
15791da177e4SLinus Torvalds 				mysids[mynel++] = sid;
15801da177e4SLinus Torvalds 			}
15811da177e4SLinus Torvalds 		}
15821da177e4SLinus Torvalds 	}
15831da177e4SLinus Torvalds 
15841da177e4SLinus Torvalds 	*sids = mysids;
15851da177e4SLinus Torvalds 	*nel = mynel;
15861da177e4SLinus Torvalds 
15871da177e4SLinus Torvalds out_unlock:
15881da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
15891da177e4SLinus Torvalds out:
15901da177e4SLinus Torvalds 	return rc;
15911da177e4SLinus Torvalds }
15921da177e4SLinus Torvalds 
15931da177e4SLinus Torvalds /**
15941da177e4SLinus Torvalds  * security_genfs_sid - Obtain a SID for a file in a filesystem
15951da177e4SLinus Torvalds  * @fstype: filesystem type
15961da177e4SLinus Torvalds  * @path: path from root of mount
15971da177e4SLinus Torvalds  * @sclass: file security class
15981da177e4SLinus Torvalds  * @sid: SID for path
15991da177e4SLinus Torvalds  *
16001da177e4SLinus Torvalds  * Obtain a SID to use for a file in a filesystem that
16011da177e4SLinus Torvalds  * cannot support xattr or use a fixed labeling behavior like
16021da177e4SLinus Torvalds  * transition SIDs or task SIDs.
16031da177e4SLinus Torvalds  */
16041da177e4SLinus Torvalds int security_genfs_sid(const char *fstype,
16051da177e4SLinus Torvalds 	               char *path,
16061da177e4SLinus Torvalds 		       u16 sclass,
16071da177e4SLinus Torvalds 		       u32 *sid)
16081da177e4SLinus Torvalds {
16091da177e4SLinus Torvalds 	int len;
16101da177e4SLinus Torvalds 	struct genfs *genfs;
16111da177e4SLinus Torvalds 	struct ocontext *c;
16121da177e4SLinus Torvalds 	int rc = 0, cmp = 0;
16131da177e4SLinus Torvalds 
16141da177e4SLinus Torvalds 	POLICY_RDLOCK;
16151da177e4SLinus Torvalds 
16161da177e4SLinus Torvalds 	for (genfs = policydb.genfs; genfs; genfs = genfs->next) {
16171da177e4SLinus Torvalds 		cmp = strcmp(fstype, genfs->fstype);
16181da177e4SLinus Torvalds 		if (cmp <= 0)
16191da177e4SLinus Torvalds 			break;
16201da177e4SLinus Torvalds 	}
16211da177e4SLinus Torvalds 
16221da177e4SLinus Torvalds 	if (!genfs || cmp) {
16231da177e4SLinus Torvalds 		*sid = SECINITSID_UNLABELED;
16241da177e4SLinus Torvalds 		rc = -ENOENT;
16251da177e4SLinus Torvalds 		goto out;
16261da177e4SLinus Torvalds 	}
16271da177e4SLinus Torvalds 
16281da177e4SLinus Torvalds 	for (c = genfs->head; c; c = c->next) {
16291da177e4SLinus Torvalds 		len = strlen(c->u.name);
16301da177e4SLinus Torvalds 		if ((!c->v.sclass || sclass == c->v.sclass) &&
16311da177e4SLinus Torvalds 		    (strncmp(c->u.name, path, len) == 0))
16321da177e4SLinus Torvalds 			break;
16331da177e4SLinus Torvalds 	}
16341da177e4SLinus Torvalds 
16351da177e4SLinus Torvalds 	if (!c) {
16361da177e4SLinus Torvalds 		*sid = SECINITSID_UNLABELED;
16371da177e4SLinus Torvalds 		rc = -ENOENT;
16381da177e4SLinus Torvalds 		goto out;
16391da177e4SLinus Torvalds 	}
16401da177e4SLinus Torvalds 
16411da177e4SLinus Torvalds 	if (!c->sid[0]) {
16421da177e4SLinus Torvalds 		rc = sidtab_context_to_sid(&sidtab,
16431da177e4SLinus Torvalds 					   &c->context[0],
16441da177e4SLinus Torvalds 					   &c->sid[0]);
16451da177e4SLinus Torvalds 		if (rc)
16461da177e4SLinus Torvalds 			goto out;
16471da177e4SLinus Torvalds 	}
16481da177e4SLinus Torvalds 
16491da177e4SLinus Torvalds 	*sid = c->sid[0];
16501da177e4SLinus Torvalds out:
16511da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
16521da177e4SLinus Torvalds 	return rc;
16531da177e4SLinus Torvalds }
16541da177e4SLinus Torvalds 
16551da177e4SLinus Torvalds /**
16561da177e4SLinus Torvalds  * security_fs_use - Determine how to handle labeling for a filesystem.
16571da177e4SLinus Torvalds  * @fstype: filesystem type
16581da177e4SLinus Torvalds  * @behavior: labeling behavior
16591da177e4SLinus Torvalds  * @sid: SID for filesystem (superblock)
16601da177e4SLinus Torvalds  */
16611da177e4SLinus Torvalds int security_fs_use(
16621da177e4SLinus Torvalds 	const char *fstype,
16631da177e4SLinus Torvalds 	unsigned int *behavior,
16641da177e4SLinus Torvalds 	u32 *sid)
16651da177e4SLinus Torvalds {
16661da177e4SLinus Torvalds 	int rc = 0;
16671da177e4SLinus Torvalds 	struct ocontext *c;
16681da177e4SLinus Torvalds 
16691da177e4SLinus Torvalds 	POLICY_RDLOCK;
16701da177e4SLinus Torvalds 
16711da177e4SLinus Torvalds 	c = policydb.ocontexts[OCON_FSUSE];
16721da177e4SLinus Torvalds 	while (c) {
16731da177e4SLinus Torvalds 		if (strcmp(fstype, c->u.name) == 0)
16741da177e4SLinus Torvalds 			break;
16751da177e4SLinus Torvalds 		c = c->next;
16761da177e4SLinus Torvalds 	}
16771da177e4SLinus Torvalds 
16781da177e4SLinus Torvalds 	if (c) {
16791da177e4SLinus Torvalds 		*behavior = c->v.behavior;
16801da177e4SLinus Torvalds 		if (!c->sid[0]) {
16811da177e4SLinus Torvalds 			rc = sidtab_context_to_sid(&sidtab,
16821da177e4SLinus Torvalds 						   &c->context[0],
16831da177e4SLinus Torvalds 						   &c->sid[0]);
16841da177e4SLinus Torvalds 			if (rc)
16851da177e4SLinus Torvalds 				goto out;
16861da177e4SLinus Torvalds 		}
16871da177e4SLinus Torvalds 		*sid = c->sid[0];
16881da177e4SLinus Torvalds 	} else {
16891da177e4SLinus Torvalds 		rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid);
16901da177e4SLinus Torvalds 		if (rc) {
16911da177e4SLinus Torvalds 			*behavior = SECURITY_FS_USE_NONE;
16921da177e4SLinus Torvalds 			rc = 0;
16931da177e4SLinus Torvalds 		} else {
16941da177e4SLinus Torvalds 			*behavior = SECURITY_FS_USE_GENFS;
16951da177e4SLinus Torvalds 		}
16961da177e4SLinus Torvalds 	}
16971da177e4SLinus Torvalds 
16981da177e4SLinus Torvalds out:
16991da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
17001da177e4SLinus Torvalds 	return rc;
17011da177e4SLinus Torvalds }
17021da177e4SLinus Torvalds 
17031da177e4SLinus Torvalds int security_get_bools(int *len, char ***names, int **values)
17041da177e4SLinus Torvalds {
17051da177e4SLinus Torvalds 	int i, rc = -ENOMEM;
17061da177e4SLinus Torvalds 
17071da177e4SLinus Torvalds 	POLICY_RDLOCK;
17081da177e4SLinus Torvalds 	*names = NULL;
17091da177e4SLinus Torvalds 	*values = NULL;
17101da177e4SLinus Torvalds 
17111da177e4SLinus Torvalds 	*len = policydb.p_bools.nprim;
17121da177e4SLinus Torvalds 	if (!*len) {
17131da177e4SLinus Torvalds 		rc = 0;
17141da177e4SLinus Torvalds 		goto out;
17151da177e4SLinus Torvalds 	}
17161da177e4SLinus Torvalds 
1717e0795cf4SJesper Juhl        *names = kcalloc(*len, sizeof(char*), GFP_ATOMIC);
17181da177e4SLinus Torvalds 	if (!*names)
17191da177e4SLinus Torvalds 		goto err;
17201da177e4SLinus Torvalds 
1721e0795cf4SJesper Juhl        *values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
17221da177e4SLinus Torvalds 	if (!*values)
17231da177e4SLinus Torvalds 		goto err;
17241da177e4SLinus Torvalds 
17251da177e4SLinus Torvalds 	for (i = 0; i < *len; i++) {
17261da177e4SLinus Torvalds 		size_t name_len;
17271da177e4SLinus Torvalds 		(*values)[i] = policydb.bool_val_to_struct[i]->state;
17281da177e4SLinus Torvalds 		name_len = strlen(policydb.p_bool_val_to_name[i]) + 1;
1729e0795cf4SJesper Juhl                (*names)[i] = kmalloc(sizeof(char) * name_len, GFP_ATOMIC);
17301da177e4SLinus Torvalds 		if (!(*names)[i])
17311da177e4SLinus Torvalds 			goto err;
17321da177e4SLinus Torvalds 		strncpy((*names)[i], policydb.p_bool_val_to_name[i], name_len);
17331da177e4SLinus Torvalds 		(*names)[i][name_len - 1] = 0;
17341da177e4SLinus Torvalds 	}
17351da177e4SLinus Torvalds 	rc = 0;
17361da177e4SLinus Torvalds out:
17371da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
17381da177e4SLinus Torvalds 	return rc;
17391da177e4SLinus Torvalds err:
17401da177e4SLinus Torvalds 	if (*names) {
17411da177e4SLinus Torvalds 		for (i = 0; i < *len; i++)
17421da177e4SLinus Torvalds 			kfree((*names)[i]);
17431da177e4SLinus Torvalds 	}
17441da177e4SLinus Torvalds 	kfree(*values);
17451da177e4SLinus Torvalds 	goto out;
17461da177e4SLinus Torvalds }
17471da177e4SLinus Torvalds 
17481da177e4SLinus Torvalds 
17491da177e4SLinus Torvalds int security_set_bools(int len, int *values)
17501da177e4SLinus Torvalds {
17511da177e4SLinus Torvalds 	int i, rc = 0;
17521da177e4SLinus Torvalds 	int lenp, seqno = 0;
17531da177e4SLinus Torvalds 	struct cond_node *cur;
17541da177e4SLinus Torvalds 
17551da177e4SLinus Torvalds 	POLICY_WRLOCK;
17561da177e4SLinus Torvalds 
17571da177e4SLinus Torvalds 	lenp = policydb.p_bools.nprim;
17581da177e4SLinus Torvalds 	if (len != lenp) {
17591da177e4SLinus Torvalds 		rc = -EFAULT;
17601da177e4SLinus Torvalds 		goto out;
17611da177e4SLinus Torvalds 	}
17621da177e4SLinus Torvalds 
17631da177e4SLinus Torvalds 	for (i = 0; i < len; i++) {
1764af601e46SSteve Grubb 		if (!!values[i] != policydb.bool_val_to_struct[i]->state) {
1765af601e46SSteve Grubb 			audit_log(current->audit_context, GFP_ATOMIC,
1766af601e46SSteve Grubb 				AUDIT_MAC_CONFIG_CHANGE,
1767af601e46SSteve Grubb 				"bool=%s val=%d old_val=%d auid=%u",
1768af601e46SSteve Grubb 				policydb.p_bool_val_to_name[i],
1769af601e46SSteve Grubb 				!!values[i],
1770af601e46SSteve Grubb 				policydb.bool_val_to_struct[i]->state,
1771af601e46SSteve Grubb 				audit_get_loginuid(current->audit_context));
1772af601e46SSteve Grubb 		}
17731da177e4SLinus Torvalds 		if (values[i]) {
17741da177e4SLinus Torvalds 			policydb.bool_val_to_struct[i]->state = 1;
17751da177e4SLinus Torvalds 		} else {
17761da177e4SLinus Torvalds 			policydb.bool_val_to_struct[i]->state = 0;
17771da177e4SLinus Torvalds 		}
17781da177e4SLinus Torvalds 	}
17791da177e4SLinus Torvalds 
17801da177e4SLinus Torvalds 	for (cur = policydb.cond_list; cur != NULL; cur = cur->next) {
17811da177e4SLinus Torvalds 		rc = evaluate_cond_node(&policydb, cur);
17821da177e4SLinus Torvalds 		if (rc)
17831da177e4SLinus Torvalds 			goto out;
17841da177e4SLinus Torvalds 	}
17851da177e4SLinus Torvalds 
17861da177e4SLinus Torvalds 	seqno = ++latest_granting;
17871da177e4SLinus Torvalds 
17881da177e4SLinus Torvalds out:
17891da177e4SLinus Torvalds 	POLICY_WRUNLOCK;
17901da177e4SLinus Torvalds 	if (!rc) {
17911da177e4SLinus Torvalds 		avc_ss_reset(seqno);
17921da177e4SLinus Torvalds 		selnl_notify_policyload(seqno);
17931da177e4SLinus Torvalds 	}
17941da177e4SLinus Torvalds 	return rc;
17951da177e4SLinus Torvalds }
17961da177e4SLinus Torvalds 
17971da177e4SLinus Torvalds int security_get_bool_value(int bool)
17981da177e4SLinus Torvalds {
17991da177e4SLinus Torvalds 	int rc = 0;
18001da177e4SLinus Torvalds 	int len;
18011da177e4SLinus Torvalds 
18021da177e4SLinus Torvalds 	POLICY_RDLOCK;
18031da177e4SLinus Torvalds 
18041da177e4SLinus Torvalds 	len = policydb.p_bools.nprim;
18051da177e4SLinus Torvalds 	if (bool >= len) {
18061da177e4SLinus Torvalds 		rc = -EFAULT;
18071da177e4SLinus Torvalds 		goto out;
18081da177e4SLinus Torvalds 	}
18091da177e4SLinus Torvalds 
18101da177e4SLinus Torvalds 	rc = policydb.bool_val_to_struct[bool]->state;
18111da177e4SLinus Torvalds out:
18121da177e4SLinus Torvalds 	POLICY_RDUNLOCK;
18131da177e4SLinus Torvalds 	return rc;
18141da177e4SLinus Torvalds }
1815376bd9cbSDarrel Goeddel 
1816376bd9cbSDarrel Goeddel struct selinux_audit_rule {
1817376bd9cbSDarrel Goeddel 	u32 au_seqno;
1818376bd9cbSDarrel Goeddel 	struct context au_ctxt;
1819376bd9cbSDarrel Goeddel };
1820376bd9cbSDarrel Goeddel 
1821376bd9cbSDarrel Goeddel void selinux_audit_rule_free(struct selinux_audit_rule *rule)
1822376bd9cbSDarrel Goeddel {
1823376bd9cbSDarrel Goeddel 	if (rule) {
1824376bd9cbSDarrel Goeddel 		context_destroy(&rule->au_ctxt);
1825376bd9cbSDarrel Goeddel 		kfree(rule);
1826376bd9cbSDarrel Goeddel 	}
1827376bd9cbSDarrel Goeddel }
1828376bd9cbSDarrel Goeddel 
1829376bd9cbSDarrel Goeddel int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
1830376bd9cbSDarrel Goeddel                             struct selinux_audit_rule **rule)
1831376bd9cbSDarrel Goeddel {
1832376bd9cbSDarrel Goeddel 	struct selinux_audit_rule *tmprule;
1833376bd9cbSDarrel Goeddel 	struct role_datum *roledatum;
1834376bd9cbSDarrel Goeddel 	struct type_datum *typedatum;
1835376bd9cbSDarrel Goeddel 	struct user_datum *userdatum;
1836376bd9cbSDarrel Goeddel 	int rc = 0;
1837376bd9cbSDarrel Goeddel 
1838376bd9cbSDarrel Goeddel 	*rule = NULL;
1839376bd9cbSDarrel Goeddel 
1840376bd9cbSDarrel Goeddel 	if (!ss_initialized)
1841376bd9cbSDarrel Goeddel 		return -ENOTSUPP;
1842376bd9cbSDarrel Goeddel 
1843376bd9cbSDarrel Goeddel 	switch (field) {
1844376bd9cbSDarrel Goeddel 	case AUDIT_SE_USER:
1845376bd9cbSDarrel Goeddel 	case AUDIT_SE_ROLE:
1846376bd9cbSDarrel Goeddel 	case AUDIT_SE_TYPE:
1847376bd9cbSDarrel Goeddel 		/* only 'equals' and 'not equals' fit user, role, and type */
1848376bd9cbSDarrel Goeddel 		if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
1849376bd9cbSDarrel Goeddel 			return -EINVAL;
1850376bd9cbSDarrel Goeddel 		break;
1851376bd9cbSDarrel Goeddel 	case AUDIT_SE_SEN:
1852376bd9cbSDarrel Goeddel 	case AUDIT_SE_CLR:
1853376bd9cbSDarrel Goeddel 		/* we do not allow a range, indicated by the presense of '-' */
1854376bd9cbSDarrel Goeddel 		if (strchr(rulestr, '-'))
1855376bd9cbSDarrel Goeddel 			return -EINVAL;
1856376bd9cbSDarrel Goeddel 		break;
1857376bd9cbSDarrel Goeddel 	default:
1858376bd9cbSDarrel Goeddel 		/* only the above fields are valid */
1859376bd9cbSDarrel Goeddel 		return -EINVAL;
1860376bd9cbSDarrel Goeddel 	}
1861376bd9cbSDarrel Goeddel 
1862376bd9cbSDarrel Goeddel 	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
1863376bd9cbSDarrel Goeddel 	if (!tmprule)
1864376bd9cbSDarrel Goeddel 		return -ENOMEM;
1865376bd9cbSDarrel Goeddel 
1866376bd9cbSDarrel Goeddel 	context_init(&tmprule->au_ctxt);
1867376bd9cbSDarrel Goeddel 
1868376bd9cbSDarrel Goeddel 	POLICY_RDLOCK;
1869376bd9cbSDarrel Goeddel 
1870376bd9cbSDarrel Goeddel 	tmprule->au_seqno = latest_granting;
1871376bd9cbSDarrel Goeddel 
1872376bd9cbSDarrel Goeddel 	switch (field) {
1873376bd9cbSDarrel Goeddel 	case AUDIT_SE_USER:
1874376bd9cbSDarrel Goeddel 		userdatum = hashtab_search(policydb.p_users.table, rulestr);
1875376bd9cbSDarrel Goeddel 		if (!userdatum)
1876376bd9cbSDarrel Goeddel 			rc = -EINVAL;
1877376bd9cbSDarrel Goeddel 		else
1878376bd9cbSDarrel Goeddel 			tmprule->au_ctxt.user = userdatum->value;
1879376bd9cbSDarrel Goeddel 		break;
1880376bd9cbSDarrel Goeddel 	case AUDIT_SE_ROLE:
1881376bd9cbSDarrel Goeddel 		roledatum = hashtab_search(policydb.p_roles.table, rulestr);
1882376bd9cbSDarrel Goeddel 		if (!roledatum)
1883376bd9cbSDarrel Goeddel 			rc = -EINVAL;
1884376bd9cbSDarrel Goeddel 		else
1885376bd9cbSDarrel Goeddel 			tmprule->au_ctxt.role = roledatum->value;
1886376bd9cbSDarrel Goeddel 		break;
1887376bd9cbSDarrel Goeddel 	case AUDIT_SE_TYPE:
1888376bd9cbSDarrel Goeddel 		typedatum = hashtab_search(policydb.p_types.table, rulestr);
1889376bd9cbSDarrel Goeddel 		if (!typedatum)
1890376bd9cbSDarrel Goeddel 			rc = -EINVAL;
1891376bd9cbSDarrel Goeddel 		else
1892376bd9cbSDarrel Goeddel 			tmprule->au_ctxt.type = typedatum->value;
1893376bd9cbSDarrel Goeddel 		break;
1894376bd9cbSDarrel Goeddel 	case AUDIT_SE_SEN:
1895376bd9cbSDarrel Goeddel 	case AUDIT_SE_CLR:
1896376bd9cbSDarrel Goeddel 		rc = mls_from_string(rulestr, &tmprule->au_ctxt, GFP_ATOMIC);
1897376bd9cbSDarrel Goeddel 		break;
1898376bd9cbSDarrel Goeddel 	}
1899376bd9cbSDarrel Goeddel 
1900376bd9cbSDarrel Goeddel 	POLICY_RDUNLOCK;
1901376bd9cbSDarrel Goeddel 
1902376bd9cbSDarrel Goeddel 	if (rc) {
1903376bd9cbSDarrel Goeddel 		selinux_audit_rule_free(tmprule);
1904376bd9cbSDarrel Goeddel 		tmprule = NULL;
1905376bd9cbSDarrel Goeddel 	}
1906376bd9cbSDarrel Goeddel 
1907376bd9cbSDarrel Goeddel 	*rule = tmprule;
1908376bd9cbSDarrel Goeddel 
1909376bd9cbSDarrel Goeddel 	return rc;
1910376bd9cbSDarrel Goeddel }
1911376bd9cbSDarrel Goeddel 
1912376bd9cbSDarrel Goeddel int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
1913376bd9cbSDarrel Goeddel                              struct selinux_audit_rule *rule,
1914376bd9cbSDarrel Goeddel                              struct audit_context *actx)
1915376bd9cbSDarrel Goeddel {
1916376bd9cbSDarrel Goeddel 	struct context *ctxt;
1917376bd9cbSDarrel Goeddel 	struct mls_level *level;
1918376bd9cbSDarrel Goeddel 	int match = 0;
1919376bd9cbSDarrel Goeddel 
1920376bd9cbSDarrel Goeddel 	if (!rule) {
1921376bd9cbSDarrel Goeddel 		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
1922376bd9cbSDarrel Goeddel 		          "selinux_audit_rule_match: missing rule\n");
1923376bd9cbSDarrel Goeddel 		return -ENOENT;
1924376bd9cbSDarrel Goeddel 	}
1925376bd9cbSDarrel Goeddel 
1926376bd9cbSDarrel Goeddel 	POLICY_RDLOCK;
1927376bd9cbSDarrel Goeddel 
1928376bd9cbSDarrel Goeddel 	if (rule->au_seqno < latest_granting) {
1929376bd9cbSDarrel Goeddel 		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
1930376bd9cbSDarrel Goeddel 		          "selinux_audit_rule_match: stale rule\n");
1931376bd9cbSDarrel Goeddel 		match = -ESTALE;
1932376bd9cbSDarrel Goeddel 		goto out;
1933376bd9cbSDarrel Goeddel 	}
1934376bd9cbSDarrel Goeddel 
1935376bd9cbSDarrel Goeddel 	ctxt = sidtab_search(&sidtab, ctxid);
1936376bd9cbSDarrel Goeddel 	if (!ctxt) {
1937376bd9cbSDarrel Goeddel 		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
1938376bd9cbSDarrel Goeddel 		          "selinux_audit_rule_match: unrecognized SID %d\n",
1939376bd9cbSDarrel Goeddel 		          ctxid);
1940376bd9cbSDarrel Goeddel 		match = -ENOENT;
1941376bd9cbSDarrel Goeddel 		goto out;
1942376bd9cbSDarrel Goeddel 	}
1943376bd9cbSDarrel Goeddel 
1944376bd9cbSDarrel Goeddel 	/* a field/op pair that is not caught here will simply fall through
1945376bd9cbSDarrel Goeddel 	   without a match */
1946376bd9cbSDarrel Goeddel 	switch (field) {
1947376bd9cbSDarrel Goeddel 	case AUDIT_SE_USER:
1948376bd9cbSDarrel Goeddel 		switch (op) {
1949376bd9cbSDarrel Goeddel 		case AUDIT_EQUAL:
1950376bd9cbSDarrel Goeddel 			match = (ctxt->user == rule->au_ctxt.user);
1951376bd9cbSDarrel Goeddel 			break;
1952376bd9cbSDarrel Goeddel 		case AUDIT_NOT_EQUAL:
1953376bd9cbSDarrel Goeddel 			match = (ctxt->user != rule->au_ctxt.user);
1954376bd9cbSDarrel Goeddel 			break;
1955376bd9cbSDarrel Goeddel 		}
1956376bd9cbSDarrel Goeddel 		break;
1957376bd9cbSDarrel Goeddel 	case AUDIT_SE_ROLE:
1958376bd9cbSDarrel Goeddel 		switch (op) {
1959376bd9cbSDarrel Goeddel 		case AUDIT_EQUAL:
1960376bd9cbSDarrel Goeddel 			match = (ctxt->role == rule->au_ctxt.role);
1961376bd9cbSDarrel Goeddel 			break;
1962376bd9cbSDarrel Goeddel 		case AUDIT_NOT_EQUAL:
1963376bd9cbSDarrel Goeddel 			match = (ctxt->role != rule->au_ctxt.role);
1964376bd9cbSDarrel Goeddel 			break;
1965376bd9cbSDarrel Goeddel 		}
1966376bd9cbSDarrel Goeddel 		break;
1967376bd9cbSDarrel Goeddel 	case AUDIT_SE_TYPE:
1968376bd9cbSDarrel Goeddel 		switch (op) {
1969376bd9cbSDarrel Goeddel 		case AUDIT_EQUAL:
1970376bd9cbSDarrel Goeddel 			match = (ctxt->type == rule->au_ctxt.type);
1971376bd9cbSDarrel Goeddel 			break;
1972376bd9cbSDarrel Goeddel 		case AUDIT_NOT_EQUAL:
1973376bd9cbSDarrel Goeddel 			match = (ctxt->type != rule->au_ctxt.type);
1974376bd9cbSDarrel Goeddel 			break;
1975376bd9cbSDarrel Goeddel 		}
1976376bd9cbSDarrel Goeddel 		break;
1977376bd9cbSDarrel Goeddel 	case AUDIT_SE_SEN:
1978376bd9cbSDarrel Goeddel 	case AUDIT_SE_CLR:
1979376bd9cbSDarrel Goeddel 		level = (op == AUDIT_SE_SEN ?
1980376bd9cbSDarrel Goeddel 		         &ctxt->range.level[0] : &ctxt->range.level[1]);
1981376bd9cbSDarrel Goeddel 		switch (op) {
1982376bd9cbSDarrel Goeddel 		case AUDIT_EQUAL:
1983376bd9cbSDarrel Goeddel 			match = mls_level_eq(&rule->au_ctxt.range.level[0],
1984376bd9cbSDarrel Goeddel 			                     level);
1985376bd9cbSDarrel Goeddel 			break;
1986376bd9cbSDarrel Goeddel 		case AUDIT_NOT_EQUAL:
1987376bd9cbSDarrel Goeddel 			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
1988376bd9cbSDarrel Goeddel 			                      level);
1989376bd9cbSDarrel Goeddel 			break;
1990376bd9cbSDarrel Goeddel 		case AUDIT_LESS_THAN:
1991376bd9cbSDarrel Goeddel 			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
1992376bd9cbSDarrel Goeddel 			                       level) &&
1993376bd9cbSDarrel Goeddel 			         !mls_level_eq(&rule->au_ctxt.range.level[0],
1994376bd9cbSDarrel Goeddel 			                       level));
1995376bd9cbSDarrel Goeddel 			break;
1996376bd9cbSDarrel Goeddel 		case AUDIT_LESS_THAN_OR_EQUAL:
1997376bd9cbSDarrel Goeddel 			match = mls_level_dom(&rule->au_ctxt.range.level[0],
1998376bd9cbSDarrel Goeddel 			                      level);
1999376bd9cbSDarrel Goeddel 			break;
2000376bd9cbSDarrel Goeddel 		case AUDIT_GREATER_THAN:
2001376bd9cbSDarrel Goeddel 			match = (mls_level_dom(level,
2002376bd9cbSDarrel Goeddel 			                      &rule->au_ctxt.range.level[0]) &&
2003376bd9cbSDarrel Goeddel 			         !mls_level_eq(level,
2004376bd9cbSDarrel Goeddel 			                       &rule->au_ctxt.range.level[0]));
2005376bd9cbSDarrel Goeddel 			break;
2006376bd9cbSDarrel Goeddel 		case AUDIT_GREATER_THAN_OR_EQUAL:
2007376bd9cbSDarrel Goeddel 			match = mls_level_dom(level,
2008376bd9cbSDarrel Goeddel 			                      &rule->au_ctxt.range.level[0]);
2009376bd9cbSDarrel Goeddel 			break;
2010376bd9cbSDarrel Goeddel 		}
2011376bd9cbSDarrel Goeddel 	}
2012376bd9cbSDarrel Goeddel 
2013376bd9cbSDarrel Goeddel out:
2014376bd9cbSDarrel Goeddel 	POLICY_RDUNLOCK;
2015376bd9cbSDarrel Goeddel 	return match;
2016376bd9cbSDarrel Goeddel }
2017376bd9cbSDarrel Goeddel 
2018376bd9cbSDarrel Goeddel static int (*aurule_callback)(void) = NULL;
2019376bd9cbSDarrel Goeddel 
2020376bd9cbSDarrel Goeddel static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid,
2021376bd9cbSDarrel Goeddel                                u16 class, u32 perms, u32 *retained)
2022376bd9cbSDarrel Goeddel {
2023376bd9cbSDarrel Goeddel 	int err = 0;
2024376bd9cbSDarrel Goeddel 
2025376bd9cbSDarrel Goeddel 	if (event == AVC_CALLBACK_RESET && aurule_callback)
2026376bd9cbSDarrel Goeddel 		err = aurule_callback();
2027376bd9cbSDarrel Goeddel 	return err;
2028376bd9cbSDarrel Goeddel }
2029376bd9cbSDarrel Goeddel 
2030376bd9cbSDarrel Goeddel static int __init aurule_init(void)
2031376bd9cbSDarrel Goeddel {
2032376bd9cbSDarrel Goeddel 	int err;
2033376bd9cbSDarrel Goeddel 
2034376bd9cbSDarrel Goeddel 	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET,
2035376bd9cbSDarrel Goeddel 	                       SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0);
2036376bd9cbSDarrel Goeddel 	if (err)
2037376bd9cbSDarrel Goeddel 		panic("avc_add_callback() failed, error %d\n", err);
2038376bd9cbSDarrel Goeddel 
2039376bd9cbSDarrel Goeddel 	return err;
2040376bd9cbSDarrel Goeddel }
2041376bd9cbSDarrel Goeddel __initcall(aurule_init);
2042376bd9cbSDarrel Goeddel 
2043376bd9cbSDarrel Goeddel void selinux_audit_set_callback(int (*callback)(void))
2044376bd9cbSDarrel Goeddel {
2045376bd9cbSDarrel Goeddel 	aurule_callback = callback;
2046376bd9cbSDarrel Goeddel }
2047