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