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