services.c 88.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * Implementation of the security services.
 *
4
 * Authors : Stephen Smalley, <sds@tycho.nsa.gov>
5
 *	     James Morris <jmorris@redhat.com>
L
Linus Torvalds 已提交
6 7 8 9
 *
 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
 *
 *	Support for enhanced MLS infrastructure.
10
 *	Support for context based audit filters.
L
Linus Torvalds 已提交
11 12 13
 *
 * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
 *
14
 *	Added conditional policy language extensions
L
Linus Torvalds 已提交
15
 *
16
 * Updated: Hewlett-Packard <paul@paul-moore.com>
V
Venkat Yekkirala 已提交
17 18
 *
 *      Added support for NetLabel
19
 *      Added support for the policy capability bitmap
V
Venkat Yekkirala 已提交
20
 *
21 22 23 24
 * Updated: Chad Sellers <csellers@tresys.com>
 *
 *  Added validation of kernel classes and permissions
 *
25 26 27 28
 * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
 *
 *  Added support for bounds domain and audit messaged on masked permissions
 *
29 30 31 32
 * Updated: Guido Trentalancia <guido@trentalancia.com>
 *
 *  Added support for runtime switching of the policy type
 *
33
 * Copyright (C) 2008, 2009 NEC Corporation
34
 * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
35
 * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
36
 * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
L
Linus Torvalds 已提交
37 38
 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
 *	This program is free software; you can redistribute it and/or modify
39
 *	it under the terms of the GNU General Public License as published by
L
Linus Torvalds 已提交
40 41 42 43 44 45
 *	the Free Software Foundation, version 2.
 */
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/spinlock.h>
P
Paul Moore 已提交
46
#include <linux/rcupdate.h>
L
Linus Torvalds 已提交
47 48 49 50
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/sched.h>
#include <linux/audit.h>
I
Ingo Molnar 已提交
51
#include <linux/mutex.h>
52
#include <linux/selinux.h>
53
#include <linux/flex_array.h>
54
#include <linux/vmalloc.h>
V
Venkat Yekkirala 已提交
55
#include <net/netlabel.h>
I
Ingo Molnar 已提交
56

L
Linus Torvalds 已提交
57 58 59 60 61 62 63 64 65 66
#include "flask.h"
#include "avc.h"
#include "avc_ss.h"
#include "security.h"
#include "context.h"
#include "policydb.h"
#include "sidtab.h"
#include "services.h"
#include "conditional.h"
#include "mls.h"
V
Venkat Yekkirala 已提交
67
#include "objsec.h"
68
#include "netlabel.h"
69
#include "xfrm.h"
70
#include "ebitmap.h"
71
#include "audit.h"
L
Linus Torvalds 已提交
72

73 74 75 76 77 78
/* Policy capability names */
char *selinux_policycap_names[__POLICYDB_CAPABILITY_MAX] = {
	"network_peer_controls",
	"open_perms",
	"extended_socket_class",
	"always_check_network",
79 80
	"cgroup_seclabel",
	"nnp_nosuid_transition"
81 82
};

83
static struct selinux_ss selinux_ss;
84

85 86 87 88 89 90
void selinux_ss_init(struct selinux_ss **ss)
{
	rwlock_init(&selinux_ss.policy_rwlock);
	mutex_init(&selinux_ss.status_lock);
	*ss = &selinux_ss;
}
L
Linus Torvalds 已提交
91 92

/* Forward declaration. */
93 94 95
static int context_struct_to_string(struct policydb *policydb,
				    struct context *context,
				    char **scontext,
L
Linus Torvalds 已提交
96 97
				    u32 *scontext_len);

98 99 100 101 102 103
static void context_struct_compute_av(struct policydb *policydb,
				      struct context *scontext,
				      struct context *tcontext,
				      u16 tclass,
				      struct av_decision *avd,
				      struct extended_perms *xperms);
104 105 106

static int selinux_set_mapping(struct policydb *pol,
			       struct security_class_mapping *map,
107
			       struct selinux_map *out_map)
108 109 110 111 112 113 114 115 116 117 118 119 120
{
	u16 i, j;
	unsigned k;
	bool print_unknown_handle = false;

	/* Find number of classes in the input mapping */
	if (!map)
		return -EINVAL;
	i = 0;
	while (map[i].name)
		i++;

	/* Allocate space for the class records, plus one for class zero */
121 122
	out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
	if (!out_map->mapping)
123 124 125 126 127 128
		return -ENOMEM;

	/* Store the raw class and permission values */
	j = 0;
	while (map[j].name) {
		struct security_class_mapping *p_in = map + (j++);
129
		struct selinux_mapping *p_out = out_map->mapping + j;
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149

		/* An empty class string skips ahead */
		if (!strcmp(p_in->name, "")) {
			p_out->num_perms = 0;
			continue;
		}

		p_out->value = string_to_security_class(pol, p_in->name);
		if (!p_out->value) {
			printk(KERN_INFO
			       "SELinux:  Class %s not defined in policy.\n",
			       p_in->name);
			if (pol->reject_unknown)
				goto err;
			p_out->num_perms = 0;
			print_unknown_handle = true;
			continue;
		}

		k = 0;
150
		while (p_in->perms[k]) {
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
			/* An empty permission string skips ahead */
			if (!*p_in->perms[k]) {
				k++;
				continue;
			}
			p_out->perms[k] = string_to_av_perm(pol, p_out->value,
							    p_in->perms[k]);
			if (!p_out->perms[k]) {
				printk(KERN_INFO
				       "SELinux:  Permission %s in class %s not defined in policy.\n",
				       p_in->perms[k], p_in->name);
				if (pol->reject_unknown)
					goto err;
				print_unknown_handle = true;
			}

			k++;
		}
		p_out->num_perms = k;
	}

	if (print_unknown_handle)
		printk(KERN_INFO "SELinux: the above unknown classes and permissions will be %s\n",
		       pol->allow_unknown ? "allowed" : "denied");

176
	out_map->size = i;
177 178
	return 0;
err:
179 180
	kfree(out_map->mapping);
	out_map->mapping = NULL;
181 182 183 184 185 186 187
	return -EINVAL;
}

/*
 * Get real, policy values from mapped values
 */

188
static u16 unmap_class(struct selinux_map *map, u16 tclass)
189
{
190 191
	if (tclass < map->size)
		return map->mapping[tclass].value;
192 193 194 195

	return tclass;
}

196 197 198
/*
 * Get kernel value for class from its policy value
 */
199
static u16 map_class(struct selinux_map *map, u16 pol_value)
200 201 202
{
	u16 i;

203 204
	for (i = 1; i < map->size; i++) {
		if (map->mapping[i].value == pol_value)
205 206 207
			return i;
	}

208
	return SECCLASS_NULL;
209 210
}

211 212
static void map_decision(struct selinux_map *map,
			 u16 tclass, struct av_decision *avd,
213 214
			 int allow_unknown)
{
215 216 217
	if (tclass < map->size) {
		struct selinux_mapping *mapping = &map->mapping[tclass];
		unsigned int i, n = mapping->num_perms;
218 219 220
		u32 result;

		for (i = 0, result = 0; i < n; i++) {
221
			if (avd->allowed & mapping->perms[i])
222
				result |= 1<<i;
223
			if (allow_unknown && !mapping->perms[i])
224 225 226 227 228
				result |= 1<<i;
		}
		avd->allowed = result;

		for (i = 0, result = 0; i < n; i++)
229
			if (avd->auditallow & mapping->perms[i])
230 231 232 233
				result |= 1<<i;
		avd->auditallow = result;

		for (i = 0, result = 0; i < n; i++) {
234
			if (avd->auditdeny & mapping->perms[i])
235
				result |= 1<<i;
236
			if (!allow_unknown && !mapping->perms[i])
237 238
				result |= 1<<i;
		}
239 240 241 242 243 244 245
		/*
		 * In case the kernel has a bug and requests a permission
		 * between num_perms and the maximum permission number, we
		 * should audit that denial
		 */
		for (; i < (sizeof(u32)*8); i++)
			result |= 1<<i;
246 247 248 249
		avd->auditdeny = result;
	}
}

250
int security_mls_enabled(struct selinux_state *state)
251
{
252 253 254
	struct policydb *p = &state->ss->policydb;

	return p->mls_enabled;
255
}
256

L
Linus Torvalds 已提交
257 258 259 260 261 262 263 264 265 266 267
/*
 * Return the boolean value of a constraint expression
 * when it is applied to the specified source and target
 * security contexts.
 *
 * xcontext is a special beast...  It is used by the validatetrans rules
 * only.  For these rules, scontext is the context before the transition,
 * tcontext is the context after the transition, and xcontext is the context
 * of the process performing the transition.  All other callers of
 * constraint_expr_eval should pass in NULL for xcontext.
 */
268 269
static int constraint_expr_eval(struct policydb *policydb,
				struct context *scontext,
L
Linus Torvalds 已提交
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
				struct context *tcontext,
				struct context *xcontext,
				struct constraint_expr *cexpr)
{
	u32 val1, val2;
	struct context *c;
	struct role_datum *r1, *r2;
	struct mls_level *l1, *l2;
	struct constraint_expr *e;
	int s[CEXPR_MAXDEPTH];
	int sp = -1;

	for (e = cexpr; e; e = e->next) {
		switch (e->expr_type) {
		case CEXPR_NOT:
			BUG_ON(sp < 0);
			s[sp] = !s[sp];
			break;
		case CEXPR_AND:
			BUG_ON(sp < 1);
			sp--;
291
			s[sp] &= s[sp + 1];
L
Linus Torvalds 已提交
292 293 294 295
			break;
		case CEXPR_OR:
			BUG_ON(sp < 1);
			sp--;
296
			s[sp] |= s[sp + 1];
L
Linus Torvalds 已提交
297 298
			break;
		case CEXPR_ATTR:
299
			if (sp == (CEXPR_MAXDEPTH - 1))
L
Linus Torvalds 已提交
300 301 302 303 304 305 306 307 308 309 310 311 312
				return 0;
			switch (e->attr) {
			case CEXPR_USER:
				val1 = scontext->user;
				val2 = tcontext->user;
				break;
			case CEXPR_TYPE:
				val1 = scontext->type;
				val2 = tcontext->type;
				break;
			case CEXPR_ROLE:
				val1 = scontext->role;
				val2 = tcontext->role;
313 314
				r1 = policydb->role_val_to_struct[val1 - 1];
				r2 = policydb->role_val_to_struct[val2 - 1];
L
Linus Torvalds 已提交
315 316 317 318 319 320 321 322 323 324
				switch (e->op) {
				case CEXPR_DOM:
					s[++sp] = ebitmap_get_bit(&r1->dominates,
								  val2 - 1);
					continue;
				case CEXPR_DOMBY:
					s[++sp] = ebitmap_get_bit(&r2->dominates,
								  val1 - 1);
					continue;
				case CEXPR_INCOMP:
325 326 327 328
					s[++sp] = (!ebitmap_get_bit(&r1->dominates,
								    val2 - 1) &&
						   !ebitmap_get_bit(&r2->dominates,
								    val1 - 1));
L
Linus Torvalds 已提交
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
					continue;
				default:
					break;
				}
				break;
			case CEXPR_L1L2:
				l1 = &(scontext->range.level[0]);
				l2 = &(tcontext->range.level[0]);
				goto mls_ops;
			case CEXPR_L1H2:
				l1 = &(scontext->range.level[0]);
				l2 = &(tcontext->range.level[1]);
				goto mls_ops;
			case CEXPR_H1L2:
				l1 = &(scontext->range.level[1]);
				l2 = &(tcontext->range.level[0]);
				goto mls_ops;
			case CEXPR_H1H2:
				l1 = &(scontext->range.level[1]);
				l2 = &(tcontext->range.level[1]);
				goto mls_ops;
			case CEXPR_L1H1:
				l1 = &(scontext->range.level[0]);
				l2 = &(scontext->range.level[1]);
				goto mls_ops;
			case CEXPR_L2H2:
				l1 = &(tcontext->range.level[0]);
				l2 = &(tcontext->range.level[1]);
				goto mls_ops;
mls_ops:
			switch (e->op) {
			case CEXPR_EQ:
				s[++sp] = mls_level_eq(l1, l2);
				continue;
			case CEXPR_NEQ:
				s[++sp] = !mls_level_eq(l1, l2);
				continue;
			case CEXPR_DOM:
				s[++sp] = mls_level_dom(l1, l2);
				continue;
			case CEXPR_DOMBY:
				s[++sp] = mls_level_dom(l2, l1);
				continue;
			case CEXPR_INCOMP:
				s[++sp] = mls_level_incomp(l2, l1);
				continue;
			default:
				BUG();
				return 0;
			}
			break;
			default:
				BUG();
				return 0;
			}

			switch (e->op) {
			case CEXPR_EQ:
				s[++sp] = (val1 == val2);
				break;
			case CEXPR_NEQ:
				s[++sp] = (val1 != val2);
				break;
			default:
				BUG();
				return 0;
			}
			break;
		case CEXPR_NAMES:
			if (sp == (CEXPR_MAXDEPTH-1))
				return 0;
			c = scontext;
			if (e->attr & CEXPR_TARGET)
				c = tcontext;
			else if (e->attr & CEXPR_XTARGET) {
				c = xcontext;
				if (!c) {
					BUG();
					return 0;
				}
			}
			if (e->attr & CEXPR_USER)
				val1 = c->user;
			else if (e->attr & CEXPR_ROLE)
				val1 = c->role;
			else if (e->attr & CEXPR_TYPE)
				val1 = c->type;
			else {
				BUG();
				return 0;
			}

			switch (e->op) {
			case CEXPR_EQ:
				s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
				break;
			case CEXPR_NEQ:
				s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
				break;
			default:
				BUG();
				return 0;
			}
			break;
		default:
			BUG();
			return 0;
		}
	}

	BUG_ON(sp != 0);
	return s[0];
}

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
/*
 * security_dump_masked_av - dumps masked permissions during
 * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
 */
static int dump_masked_av_helper(void *k, void *d, void *args)
{
	struct perm_datum *pdatum = d;
	char **permission_names = args;

	BUG_ON(pdatum->value < 1 || pdatum->value > 32);

	permission_names[pdatum->value - 1] = (char *)k;

	return 0;
}

459 460
static void security_dump_masked_av(struct policydb *policydb,
				    struct context *scontext,
461 462 463 464 465 466 467 468 469 470 471 472
				    struct context *tcontext,
				    u16 tclass,
				    u32 permissions,
				    const char *reason)
{
	struct common_datum *common_dat;
	struct class_datum *tclass_dat;
	struct audit_buffer *ab;
	char *tclass_name;
	char *scontext_name = NULL;
	char *tcontext_name = NULL;
	char *permission_names[32];
473 474
	int index;
	u32 length;
475 476 477 478 479
	bool need_comma = false;

	if (!permissions)
		return;

480 481
	tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1);
	tclass_dat = policydb->class_val_to_struct[tclass - 1];
482 483 484 485 486 487 488 489 490 491 492 493 494
	common_dat = tclass_dat->comdatum;

	/* init permission_names */
	if (common_dat &&
	    hashtab_map(common_dat->permissions.table,
			dump_masked_av_helper, permission_names) < 0)
		goto out;

	if (hashtab_map(tclass_dat->permissions.table,
			dump_masked_av_helper, permission_names) < 0)
		goto out;

	/* get scontext/tcontext in text form */
495
	if (context_struct_to_string(policydb, scontext,
496 497 498
				     &scontext_name, &length) < 0)
		goto out;

499
	if (context_struct_to_string(policydb, tcontext,
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
				     &tcontext_name, &length) < 0)
		goto out;

	/* audit a message */
	ab = audit_log_start(current->audit_context,
			     GFP_ATOMIC, AUDIT_SELINUX_ERR);
	if (!ab)
		goto out;

	audit_log_format(ab, "op=security_compute_av reason=%s "
			 "scontext=%s tcontext=%s tclass=%s perms=",
			 reason, scontext_name, tcontext_name, tclass_name);

	for (index = 0; index < 32; index++) {
		u32 mask = (1 << index);

		if ((mask & permissions) == 0)
			continue;

		audit_log_format(ab, "%s%s",
				 need_comma ? "," : "",
				 permission_names[index]
				 ? permission_names[index] : "????");
		need_comma = true;
	}
	audit_log_end(ab);
out:
	/* release scontext/tcontext */
	kfree(tcontext_name);
	kfree(scontext_name);

	return;
}

534 535 536 537
/*
 * security_boundary_permission - drops violated permissions
 * on boundary constraint.
 */
538 539
static void type_attribute_bounds_av(struct policydb *policydb,
				     struct context *scontext,
540 541 542 543
				     struct context *tcontext,
				     u16 tclass,
				     struct av_decision *avd)
{
544
	struct context lo_scontext;
545
	struct context lo_tcontext, *tcontextp = tcontext;
546
	struct av_decision lo_avd;
547 548
	struct type_datum *source;
	struct type_datum *target;
549
	u32 masked = 0;
550

551
	source = flex_array_get_ptr(policydb->type_val_to_struct_array,
552 553 554
				    scontext->type - 1);
	BUG_ON(!source);

555 556 557
	if (!source->bounds)
		return;

558
	target = flex_array_get_ptr(policydb->type_val_to_struct_array,
559 560 561
				    tcontext->type - 1);
	BUG_ON(!target);

562
	memset(&lo_avd, 0, sizeof(lo_avd));
563

564 565
	memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
	lo_scontext.type = source->bounds;
566 567 568 569

	if (target->bounds) {
		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
		lo_tcontext.type = target->bounds;
570
		tcontextp = &lo_tcontext;
571 572
	}

573
	context_struct_compute_av(policydb, &lo_scontext,
574 575 576 577
				  tcontextp,
				  tclass,
				  &lo_avd,
				  NULL);
578

579
	masked = ~lo_avd.allowed & avd->allowed;
580

581 582
	if (likely(!masked))
		return;		/* no masked permission */
583

584 585 586 587
	/* mask violated permissions */
	avd->allowed &= ~masked;

	/* audit masked permissions */
588
	security_dump_masked_av(policydb, scontext, tcontext,
589
				tclass, masked, "bounds");
590 591
}

L
Linus Torvalds 已提交
592
/*
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
 * flag which drivers have permissions
 * only looking for ioctl based extended permssions
 */
void services_compute_xperms_drivers(
		struct extended_perms *xperms,
		struct avtab_node *node)
{
	unsigned int i;

	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
		/* if one or more driver has all permissions allowed */
		for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
			xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
		/* if allowing permissions within a driver */
		security_xperm_set(xperms->drivers.p,
					node->datum.u.xperms->driver);
	}

	/* If no ioctl commands are allowed, ignore auditallow and auditdeny */
	if (node->key.specified & AVTAB_XPERMS_ALLOWED)
		xperms->len = 1;
}

/*
 * Compute access vectors and extended permissions based on a context
 * structure pair for the permissions in a particular class.
L
Linus Torvalds 已提交
620
 */
621 622 623 624 625 626
static void context_struct_compute_av(struct policydb *policydb,
				      struct context *scontext,
				      struct context *tcontext,
				      u16 tclass,
				      struct av_decision *avd,
				      struct extended_perms *xperms)
L
Linus Torvalds 已提交
627 628 629 630
{
	struct constraint_node *constraint;
	struct role_allow *ra;
	struct avtab_key avkey;
631
	struct avtab_node *node;
L
Linus Torvalds 已提交
632
	struct class_datum *tclass_datum;
633 634 635
	struct ebitmap *sattr, *tattr;
	struct ebitmap_node *snode, *tnode;
	unsigned int i, j;
L
Linus Torvalds 已提交
636 637 638 639

	avd->allowed = 0;
	avd->auditallow = 0;
	avd->auditdeny = 0xffffffff;
640 641 642 643
	if (xperms) {
		memset(&xperms->drivers, 0, sizeof(xperms->drivers));
		xperms->len = 0;
	}
L
Linus Torvalds 已提交
644

645
	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
646 647
		if (printk_ratelimit())
			printk(KERN_WARNING "SELinux:  Invalid class %hu\n", tclass);
648
		return;
649
	}
650

651
	tclass_datum = policydb->class_val_to_struct[tclass - 1];
652

L
Linus Torvalds 已提交
653 654 655 656 657
	/*
	 * If a specific type enforcement rule was defined for
	 * this permission check, then use it.
	 */
	avkey.target_class = tclass;
658
	avkey.specified = AVTAB_AV | AVTAB_XPERMS;
659 660
	sattr = flex_array_get(policydb->type_attr_map_array,
			       scontext->type - 1);
661
	BUG_ON(!sattr);
662 663
	tattr = flex_array_get(policydb->type_attr_map_array,
			       tcontext->type - 1);
664
	BUG_ON(!tattr);
665 666
	ebitmap_for_each_positive_bit(sattr, snode, i) {
		ebitmap_for_each_positive_bit(tattr, tnode, j) {
667 668
			avkey.source_type = i + 1;
			avkey.target_type = j + 1;
669 670
			for (node = avtab_search_node(&policydb->te_avtab,
						      &avkey);
671
			     node;
672 673
			     node = avtab_search_node_next(node, avkey.specified)) {
				if (node->key.specified == AVTAB_ALLOWED)
674
					avd->allowed |= node->datum.u.data;
675
				else if (node->key.specified == AVTAB_AUDITALLOW)
676
					avd->auditallow |= node->datum.u.data;
677
				else if (node->key.specified == AVTAB_AUDITDENY)
678 679 680
					avd->auditdeny &= node->datum.u.data;
				else if (xperms && (node->key.specified & AVTAB_XPERMS))
					services_compute_xperms_drivers(xperms, node);
681
			}
L
Linus Torvalds 已提交
682

683
			/* Check conditional av table for additional permissions */
684
			cond_compute_av(&policydb->te_cond_avtab, &avkey,
685
					avd, xperms);
686 687 688

		}
	}
L
Linus Torvalds 已提交
689 690 691 692 693 694 695 696

	/*
	 * Remove any permissions prohibited by a constraint (this includes
	 * the MLS policy).
	 */
	constraint = tclass_datum->constraints;
	while (constraint) {
		if ((constraint->permissions & (avd->allowed)) &&
697
		    !constraint_expr_eval(policydb, scontext, tcontext, NULL,
L
Linus Torvalds 已提交
698
					  constraint->expr)) {
K
KaiGai Kohei 已提交
699
			avd->allowed &= ~(constraint->permissions);
L
Linus Torvalds 已提交
700 701 702 703 704 705 706 707 708
		}
		constraint = constraint->next;
	}

	/*
	 * If checking process transition permission and the
	 * role is changing, then check the (current_role, new_role)
	 * pair.
	 */
709 710
	if (tclass == policydb->process_class &&
	    (avd->allowed & policydb->process_trans_perms) &&
L
Linus Torvalds 已提交
711
	    scontext->role != tcontext->role) {
712
		for (ra = policydb->role_allow; ra; ra = ra->next) {
L
Linus Torvalds 已提交
713 714 715 716 717
			if (scontext->role == ra->role &&
			    tcontext->role == ra->new_role)
				break;
		}
		if (!ra)
718
			avd->allowed &= ~policydb->process_trans_perms;
L
Linus Torvalds 已提交
719 720
	}

721 722 723 724 725
	/*
	 * If the given source and target types have boundary
	 * constraint, lazy checks have to mask any violated
	 * permission and notice it to userspace via audit.
	 */
726
	type_attribute_bounds_av(policydb, scontext, tcontext,
727
				 tclass, avd);
L
Linus Torvalds 已提交
728 729
}

730 731
static int security_validtrans_handle_fail(struct selinux_state *state,
					   struct context *ocontext,
732 733 734
					   struct context *ncontext,
					   struct context *tcontext,
					   u16 tclass)
L
Linus Torvalds 已提交
735
{
736
	struct policydb *p = &state->ss->policydb;
L
Linus Torvalds 已提交
737 738 739
	char *o = NULL, *n = NULL, *t = NULL;
	u32 olen, nlen, tlen;

740
	if (context_struct_to_string(p, ocontext, &o, &olen))
L
Linus Torvalds 已提交
741
		goto out;
742
	if (context_struct_to_string(p, ncontext, &n, &nlen))
L
Linus Torvalds 已提交
743
		goto out;
744
	if (context_struct_to_string(p, tcontext, &t, &tlen))
L
Linus Torvalds 已提交
745
		goto out;
746
	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
747
		  "op=security_validate_transition seresult=denied"
748
		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
749
		  o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
L
Linus Torvalds 已提交
750 751 752 753 754
out:
	kfree(o);
	kfree(n);
	kfree(t);

755
	if (!is_enforcing(state))
L
Linus Torvalds 已提交
756 757 758 759
		return 0;
	return -EPERM;
}

760 761
static int security_compute_validatetrans(struct selinux_state *state,
					  u32 oldsid, u32 newsid, u32 tasksid,
762
					  u16 orig_tclass, bool user)
L
Linus Torvalds 已提交
763
{
764 765
	struct policydb *policydb;
	struct sidtab *sidtab;
L
Linus Torvalds 已提交
766 767 768 769 770
	struct context *ocontext;
	struct context *ncontext;
	struct context *tcontext;
	struct class_datum *tclass_datum;
	struct constraint_node *constraint;
771
	u16 tclass;
L
Linus Torvalds 已提交
772 773
	int rc = 0;

774 775

	if (!state->initialized)
L
Linus Torvalds 已提交
776 777
		return 0;

778 779 780 781
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;
L
Linus Torvalds 已提交
782

783
	if (!user)
784
		tclass = unmap_class(&state->ss->map, orig_tclass);
785 786
	else
		tclass = orig_tclass;
787

788
	if (!tclass || tclass > policydb->p_classes.nprim) {
L
Linus Torvalds 已提交
789 790 791
		rc = -EINVAL;
		goto out;
	}
792
	tclass_datum = policydb->class_val_to_struct[tclass - 1];
L
Linus Torvalds 已提交
793

794
	ocontext = sidtab_search(sidtab, oldsid);
L
Linus Torvalds 已提交
795
	if (!ocontext) {
E
Eric Paris 已提交
796 797
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
			__func__, oldsid);
L
Linus Torvalds 已提交
798 799 800 801
		rc = -EINVAL;
		goto out;
	}

802
	ncontext = sidtab_search(sidtab, newsid);
L
Linus Torvalds 已提交
803
	if (!ncontext) {
E
Eric Paris 已提交
804 805
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
			__func__, newsid);
L
Linus Torvalds 已提交
806 807 808 809
		rc = -EINVAL;
		goto out;
	}

810
	tcontext = sidtab_search(sidtab, tasksid);
L
Linus Torvalds 已提交
811
	if (!tcontext) {
E
Eric Paris 已提交
812 813
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
			__func__, tasksid);
L
Linus Torvalds 已提交
814 815 816 817 818 819
		rc = -EINVAL;
		goto out;
	}

	constraint = tclass_datum->validatetrans;
	while (constraint) {
820 821
		if (!constraint_expr_eval(policydb, ocontext, ncontext,
					  tcontext, constraint->expr)) {
822 823 824
			if (user)
				rc = -EPERM;
			else
825 826
				rc = security_validtrans_handle_fail(state,
								     ocontext,
827 828 829
								     ncontext,
								     tcontext,
								     tclass);
L
Linus Torvalds 已提交
830 831 832 833 834 835
			goto out;
		}
		constraint = constraint->next;
	}

out:
836
	read_unlock(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
837 838 839
	return rc;
}

840 841 842
int security_validate_transition_user(struct selinux_state *state,
				      u32 oldsid, u32 newsid, u32 tasksid,
				      u16 tclass)
843
{
844 845
	return security_compute_validatetrans(state, oldsid, newsid, tasksid,
					      tclass, true);
846 847
}

848 849
int security_validate_transition(struct selinux_state *state,
				 u32 oldsid, u32 newsid, u32 tasksid,
850 851
				 u16 orig_tclass)
{
852 853
	return security_compute_validatetrans(state, oldsid, newsid, tasksid,
					      orig_tclass, false);
854 855
}

856 857 858 859 860 861 862 863 864
/*
 * security_bounded_transition - check whether the given
 * transition is directed to bounded, or not.
 * It returns 0, if @newsid is bounded by @oldsid.
 * Otherwise, it returns error code.
 *
 * @oldsid : current security identifier
 * @newsid : destinated security identifier
 */
865 866
int security_bounded_transition(struct selinux_state *state,
				u32 old_sid, u32 new_sid)
867
{
868 869
	struct policydb *policydb;
	struct sidtab *sidtab;
870 871 872
	struct context *old_context, *new_context;
	struct type_datum *type;
	int index;
873
	int rc;
874

875
	if (!state->initialized)
876 877
		return 0;

878 879 880 881
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;
882

883
	rc = -EINVAL;
884
	old_context = sidtab_search(sidtab, old_sid);
885 886 887 888 889 890
	if (!old_context) {
		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
		       __func__, old_sid);
		goto out;
	}

891
	rc = -EINVAL;
892
	new_context = sidtab_search(sidtab, new_sid);
893 894 895 896 897 898
	if (!new_context) {
		printk(KERN_ERR "SELinux: %s: unrecognized SID %u\n",
		       __func__, new_sid);
		goto out;
	}

899
	rc = 0;
900
	/* type/domain unchanged */
901
	if (old_context->type == new_context->type)
902 903 904 905
		goto out;

	index = new_context->type;
	while (true) {
906
		type = flex_array_get_ptr(policydb->type_val_to_struct_array,
907
					  index - 1);
908 909 910
		BUG_ON(!type);

		/* not bounded anymore */
911 912
		rc = -EPERM;
		if (!type->bounds)
913 914 915
			break;

		/* @newsid is bounded by @oldsid */
916 917
		rc = 0;
		if (type->bounds == old_context->type)
918
			break;
919

920 921
		index = type->bounds;
	}
922 923 924 925

	if (rc) {
		char *old_name = NULL;
		char *new_name = NULL;
926
		u32 length;
927

928
		if (!context_struct_to_string(policydb, old_context,
929
					      &old_name, &length) &&
930
		    !context_struct_to_string(policydb, new_context,
931 932 933 934
					      &new_name, &length)) {
			audit_log(current->audit_context,
				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
				  "op=security_bounded_transition "
935
				  "seresult=denied "
936 937 938 939 940 941
				  "oldcontext=%s newcontext=%s",
				  old_name, new_name);
		}
		kfree(new_name);
		kfree(old_name);
	}
942
out:
943
	read_unlock(&state->ss->policy_rwlock);
944 945 946 947

	return rc;
}

948
static void avd_init(struct selinux_state *state, struct av_decision *avd)
949
{
950 951 952
	avd->allowed = 0;
	avd->auditallow = 0;
	avd->auditdeny = 0xffffffff;
953
	avd->seqno = state->ss->latest_granting;
954
	avd->flags = 0;
955 956
}

957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
					struct avtab_node *node)
{
	unsigned int i;

	if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
		if (xpermd->driver != node->datum.u.xperms->driver)
			return;
	} else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
		if (!security_xperm_test(node->datum.u.xperms->perms.p,
					xpermd->driver))
			return;
	} else {
		BUG();
	}

	if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
		xpermd->used |= XPERMS_ALLOWED;
		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
			memset(xpermd->allowed->p, 0xff,
					sizeof(xpermd->allowed->p));
		}
		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
			for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
				xpermd->allowed->p[i] |=
					node->datum.u.xperms->perms.p[i];
		}
	} else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
		xpermd->used |= XPERMS_AUDITALLOW;
		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
			memset(xpermd->auditallow->p, 0xff,
					sizeof(xpermd->auditallow->p));
		}
		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
			for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
				xpermd->auditallow->p[i] |=
					node->datum.u.xperms->perms.p[i];
		}
	} else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
		xpermd->used |= XPERMS_DONTAUDIT;
		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
			memset(xpermd->dontaudit->p, 0xff,
					sizeof(xpermd->dontaudit->p));
		}
		if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
			for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
				xpermd->dontaudit->p[i] |=
					node->datum.u.xperms->perms.p[i];
		}
	} else {
		BUG();
	}
}

1011 1012 1013 1014 1015 1016
void security_compute_xperms_decision(struct selinux_state *state,
				      u32 ssid,
				      u32 tsid,
				      u16 orig_tclass,
				      u8 driver,
				      struct extended_perms_decision *xpermd)
1017
{
1018 1019
	struct policydb *policydb;
	struct sidtab *sidtab;
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033
	u16 tclass;
	struct context *scontext, *tcontext;
	struct avtab_key avkey;
	struct avtab_node *node;
	struct ebitmap *sattr, *tattr;
	struct ebitmap_node *snode, *tnode;
	unsigned int i, j;

	xpermd->driver = driver;
	xpermd->used = 0;
	memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
	memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
	memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));

1034 1035
	read_lock(&state->ss->policy_rwlock);
	if (!state->initialized)
1036 1037
		goto allow;

1038 1039 1040 1041
	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;

	scontext = sidtab_search(sidtab, ssid);
1042 1043 1044 1045 1046 1047
	if (!scontext) {
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
		       __func__, ssid);
		goto out;
	}

1048
	tcontext = sidtab_search(sidtab, tsid);
1049 1050 1051 1052 1053 1054
	if (!tcontext) {
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
		       __func__, tsid);
		goto out;
	}

1055
	tclass = unmap_class(&state->ss->map, orig_tclass);
1056
	if (unlikely(orig_tclass && !tclass)) {
1057
		if (policydb->allow_unknown)
1058 1059 1060 1061 1062
			goto allow;
		goto out;
	}


1063
	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
1064 1065 1066 1067 1068 1069
		pr_warn_ratelimited("SELinux:  Invalid class %hu\n", tclass);
		goto out;
	}

	avkey.target_class = tclass;
	avkey.specified = AVTAB_XPERMS;
1070
	sattr = flex_array_get(policydb->type_attr_map_array,
1071 1072
				scontext->type - 1);
	BUG_ON(!sattr);
1073
	tattr = flex_array_get(policydb->type_attr_map_array,
1074 1075 1076 1077 1078 1079
				tcontext->type - 1);
	BUG_ON(!tattr);
	ebitmap_for_each_positive_bit(sattr, snode, i) {
		ebitmap_for_each_positive_bit(tattr, tnode, j) {
			avkey.source_type = i + 1;
			avkey.target_type = j + 1;
1080 1081
			for (node = avtab_search_node(&policydb->te_avtab,
						      &avkey);
1082 1083 1084 1085
			     node;
			     node = avtab_search_node_next(node, avkey.specified))
				services_compute_xperms_decision(xpermd, node);

1086
			cond_compute_xperms(&policydb->te_cond_avtab,
1087 1088 1089 1090
						&avkey, xpermd);
		}
	}
out:
1091
	read_unlock(&state->ss->policy_rwlock);
1092 1093 1094 1095 1096
	return;
allow:
	memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
	goto out;
}
1097

L
Linus Torvalds 已提交
1098 1099 1100 1101 1102 1103
/**
 * security_compute_av - Compute access vector decisions.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 * @avd: access vector decisions
1104
 * @xperms: extended permissions
L
Linus Torvalds 已提交
1105 1106 1107 1108
 *
 * Compute a set of access vector decisions based on the
 * SID pair (@ssid, @tsid) for the permissions in @tclass.
 */
1109 1110
void security_compute_av(struct selinux_state *state,
			 u32 ssid,
1111 1112
			 u32 tsid,
			 u16 orig_tclass,
1113 1114
			 struct av_decision *avd,
			 struct extended_perms *xperms)
L
Linus Torvalds 已提交
1115
{
1116 1117
	struct policydb *policydb;
	struct sidtab *sidtab;
1118
	u16 tclass;
1119
	struct context *scontext = NULL, *tcontext = NULL;
1120

1121 1122
	read_lock(&state->ss->policy_rwlock);
	avd_init(state, avd);
1123
	xperms->len = 0;
1124
	if (!state->initialized)
1125 1126
		goto allow;

1127 1128 1129 1130
	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;

	scontext = sidtab_search(sidtab, ssid);
1131 1132 1133 1134 1135 1136 1137
	if (!scontext) {
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
		       __func__, ssid);
		goto out;
	}

	/* permissive domain? */
1138
	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
1139 1140
		avd->flags |= AVD_FLAGS_PERMISSIVE;

1141
	tcontext = sidtab_search(sidtab, tsid);
1142 1143 1144 1145 1146 1147
	if (!tcontext) {
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
		       __func__, tsid);
		goto out;
	}

1148
	tclass = unmap_class(&state->ss->map, orig_tclass);
1149
	if (unlikely(orig_tclass && !tclass)) {
1150
		if (policydb->allow_unknown)
1151
			goto allow;
1152
		goto out;
1153
	}
1154 1155 1156 1157
	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
				  xperms);
	map_decision(&state->ss->map, orig_tclass, avd,
		     policydb->allow_unknown);
1158
out:
1159
	read_unlock(&state->ss->policy_rwlock);
1160
	return;
1161 1162
allow:
	avd->allowed = 0xffffffff;
1163
	goto out;
1164 1165
}

1166 1167
void security_compute_av_user(struct selinux_state *state,
			      u32 ssid,
1168 1169 1170
			      u32 tsid,
			      u16 tclass,
			      struct av_decision *avd)
1171
{
1172 1173
	struct policydb *policydb;
	struct sidtab *sidtab;
1174
	struct context *scontext = NULL, *tcontext = NULL;
L
Linus Torvalds 已提交
1175

1176 1177 1178
	read_lock(&state->ss->policy_rwlock);
	avd_init(state, avd);
	if (!state->initialized)
1179 1180
		goto allow;

1181 1182 1183 1184
	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;

	scontext = sidtab_search(sidtab, ssid);
1185 1186 1187 1188
	if (!scontext) {
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
		       __func__, ssid);
		goto out;
L
Linus Torvalds 已提交
1189 1190
	}

1191
	/* permissive domain? */
1192
	if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
1193 1194
		avd->flags |= AVD_FLAGS_PERMISSIVE;

1195
	tcontext = sidtab_search(sidtab, tsid);
1196 1197 1198 1199 1200 1201 1202
	if (!tcontext) {
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
		       __func__, tsid);
		goto out;
	}

	if (unlikely(!tclass)) {
1203
		if (policydb->allow_unknown)
1204 1205 1206 1207
			goto allow;
		goto out;
	}

1208 1209
	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
				  NULL);
1210
 out:
1211
	read_unlock(&state->ss->policy_rwlock);
1212 1213 1214 1215
	return;
allow:
	avd->allowed = 0xffffffff;
	goto out;
L
Linus Torvalds 已提交
1216 1217 1218 1219 1220 1221 1222 1223 1224
}

/*
 * Write the security context string representation of
 * the context structure `context' into a dynamically
 * allocated string of the correct size.  Set `*scontext'
 * to point to this string and set `*scontext_len' to
 * the length of the string.
 */
1225 1226 1227
static int context_struct_to_string(struct policydb *p,
				    struct context *context,
				    char **scontext, u32 *scontext_len)
L
Linus Torvalds 已提交
1228 1229 1230
{
	char *scontextp;

1231 1232
	if (scontext)
		*scontext = NULL;
L
Linus Torvalds 已提交
1233 1234
	*scontext_len = 0;

1235 1236
	if (context->len) {
		*scontext_len = context->len;
1237 1238 1239 1240 1241
		if (scontext) {
			*scontext = kstrdup(context->str, GFP_ATOMIC);
			if (!(*scontext))
				return -ENOMEM;
		}
1242 1243 1244
		return 0;
	}

L
Linus Torvalds 已提交
1245
	/* Compute the size of the context. */
1246 1247 1248 1249
	*scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
	*scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
	*scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
	*scontext_len += mls_compute_context_len(p, context);
L
Linus Torvalds 已提交
1250

1251 1252 1253
	if (!scontext)
		return 0;

L
Linus Torvalds 已提交
1254 1255
	/* Allocate space for the context; caller must free this space. */
	scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
1256
	if (!scontextp)
L
Linus Torvalds 已提交
1257 1258 1259 1260 1261 1262
		return -ENOMEM;
	*scontext = scontextp;

	/*
	 * Copy the user name, role name and type name into the context.
	 */
1263
	scontextp += sprintf(scontextp, "%s:%s:%s",
1264 1265 1266
		sym_name(p, SYM_USERS, context->user - 1),
		sym_name(p, SYM_ROLES, context->role - 1),
		sym_name(p, SYM_TYPES, context->type - 1));
L
Linus Torvalds 已提交
1267

1268
	mls_sid_to_context(p, context, &scontextp);
L
Linus Torvalds 已提交
1269 1270 1271 1272 1273 1274 1275 1276

	*scontextp = 0;

	return 0;
}

#include "initial_sid_to_string.h"

1277 1278 1279 1280 1281 1282 1283
const char *security_get_initial_sid_context(u32 sid)
{
	if (unlikely(sid > SECINITSID_NUM))
		return NULL;
	return initial_sid_to_string[sid];
}

1284 1285
static int security_sid_to_context_core(struct selinux_state *state,
					u32 sid, char **scontext,
1286
					u32 *scontext_len, int force)
L
Linus Torvalds 已提交
1287
{
1288 1289
	struct policydb *policydb;
	struct sidtab *sidtab;
L
Linus Torvalds 已提交
1290 1291 1292
	struct context *context;
	int rc = 0;

1293 1294
	if (scontext)
		*scontext = NULL;
1295 1296
	*scontext_len  = 0;

1297
	if (!state->initialized) {
L
Linus Torvalds 已提交
1298 1299 1300 1301
		if (sid <= SECINITSID_NUM) {
			char *scontextp;

			*scontext_len = strlen(initial_sid_to_string[sid]) + 1;
1302 1303
			if (!scontext)
				goto out;
1304 1305
			scontextp = kmemdup(initial_sid_to_string[sid],
					    *scontext_len, GFP_ATOMIC);
1306 1307 1308 1309
			if (!scontextp) {
				rc = -ENOMEM;
				goto out;
			}
L
Linus Torvalds 已提交
1310 1311 1312
			*scontext = scontextp;
			goto out;
		}
E
Eric Paris 已提交
1313 1314
		printk(KERN_ERR "SELinux: %s:  called before initial "
		       "load_policy on unknown SID %d\n", __func__, sid);
L
Linus Torvalds 已提交
1315 1316 1317
		rc = -EINVAL;
		goto out;
	}
1318 1319 1320
	read_lock(&state->ss->policy_rwlock);
	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;
1321
	if (force)
1322
		context = sidtab_search_force(sidtab, sid);
1323
	else
1324
		context = sidtab_search(sidtab, sid);
L
Linus Torvalds 已提交
1325
	if (!context) {
E
Eric Paris 已提交
1326 1327
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
			__func__, sid);
L
Linus Torvalds 已提交
1328 1329 1330
		rc = -EINVAL;
		goto out_unlock;
	}
1331 1332
	rc = context_struct_to_string(policydb, context, scontext,
				      scontext_len);
L
Linus Torvalds 已提交
1333
out_unlock:
1334
	read_unlock(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
1335 1336 1337 1338 1339
out:
	return rc;

}

1340 1341 1342 1343 1344 1345 1346 1347 1348 1349
/**
 * security_sid_to_context - Obtain a context for a given SID.
 * @sid: security identifier, SID
 * @scontext: security context
 * @scontext_len: length in bytes
 *
 * Write the string representation of the context associated with @sid
 * into a dynamically allocated string of the correct size.  Set @scontext
 * to point to this string and set @scontext_len to the length of the string.
 */
1350 1351
int security_sid_to_context(struct selinux_state *state,
			    u32 sid, char **scontext, u32 *scontext_len)
L
Linus Torvalds 已提交
1352
{
1353 1354
	return security_sid_to_context_core(state, sid, scontext,
					    scontext_len, 0);
1355 1356
}

1357 1358
int security_sid_to_context_force(struct selinux_state *state, u32 sid,
				  char **scontext, u32 *scontext_len)
1359
{
1360 1361
	return security_sid_to_context_core(state, sid, scontext,
					    scontext_len, 1);
1362 1363
}

1364 1365 1366
/*
 * Caveat:  Mutates scontext.
 */
1367 1368
static int string_to_context_struct(struct policydb *pol,
				    struct sidtab *sidtabp,
1369
				    char *scontext,
1370 1371
				    u32 scontext_len,
				    struct context *ctx,
1372
				    u32 def_sid)
1373
{
L
Linus Torvalds 已提交
1374 1375 1376 1377 1378 1379
	struct role_datum *role;
	struct type_datum *typdatum;
	struct user_datum *usrdatum;
	char *scontextp, *p, oldc;
	int rc = 0;

1380
	context_init(ctx);
L
Linus Torvalds 已提交
1381 1382 1383 1384

	/* Parse the security context. */

	rc = -EINVAL;
1385
	scontextp = (char *) scontext;
L
Linus Torvalds 已提交
1386 1387 1388 1389 1390 1391 1392

	/* Extract the user. */
	p = scontextp;
	while (*p && *p != ':')
		p++;

	if (*p == 0)
1393
		goto out;
L
Linus Torvalds 已提交
1394 1395 1396

	*p++ = 0;

1397
	usrdatum = hashtab_search(pol->p_users.table, scontextp);
L
Linus Torvalds 已提交
1398
	if (!usrdatum)
1399
		goto out;
L
Linus Torvalds 已提交
1400

1401
	ctx->user = usrdatum->value;
L
Linus Torvalds 已提交
1402 1403 1404 1405 1406 1407 1408

	/* Extract role. */
	scontextp = p;
	while (*p && *p != ':')
		p++;

	if (*p == 0)
1409
		goto out;
L
Linus Torvalds 已提交
1410 1411 1412

	*p++ = 0;

1413
	role = hashtab_search(pol->p_roles.table, scontextp);
L
Linus Torvalds 已提交
1414
	if (!role)
1415 1416
		goto out;
	ctx->role = role->value;
L
Linus Torvalds 已提交
1417 1418 1419 1420 1421 1422 1423 1424

	/* Extract type. */
	scontextp = p;
	while (*p && *p != ':')
		p++;
	oldc = *p;
	*p++ = 0;

1425
	typdatum = hashtab_search(pol->p_types.table, scontextp);
1426
	if (!typdatum || typdatum->attribute)
1427
		goto out;
L
Linus Torvalds 已提交
1428

1429
	ctx->type = typdatum->value;
L
Linus Torvalds 已提交
1430

1431
	rc = mls_context_to_sid(pol, oldc, &p, ctx, sidtabp, def_sid);
L
Linus Torvalds 已提交
1432
	if (rc)
1433
		goto out;
L
Linus Torvalds 已提交
1434

1435 1436
	rc = -EINVAL;
	if ((p - scontext) < scontext_len)
1437
		goto out;
L
Linus Torvalds 已提交
1438 1439

	/* Check the validity of the new context. */
1440
	if (!policydb_context_isvalid(pol, ctx))
1441 1442 1443
		goto out;
	rc = 0;
out:
1444 1445
	if (rc)
		context_destroy(ctx);
1446 1447 1448
	return rc;
}

1449 1450
static int security_context_to_sid_core(struct selinux_state *state,
					const char *scontext, u32 scontext_len,
1451 1452 1453
					u32 *sid, u32 def_sid, gfp_t gfp_flags,
					int force)
{
1454 1455
	struct policydb *policydb;
	struct sidtab *sidtab;
1456
	char *scontext2, *str = NULL;
1457 1458 1459
	struct context context;
	int rc = 0;

1460 1461 1462 1463
	/* An empty security context is never valid. */
	if (!scontext_len)
		return -EINVAL;

1464 1465 1466 1467 1468
	/* Copy the string to allow changes and ensure a NUL terminator */
	scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
	if (!scontext2)
		return -ENOMEM;

1469
	if (!state->initialized) {
1470 1471 1472
		int i;

		for (i = 1; i < SECINITSID_NUM; i++) {
1473
			if (!strcmp(initial_sid_to_string[i], scontext2)) {
1474
				*sid = i;
1475
				goto out;
1476 1477 1478
			}
		}
		*sid = SECINITSID_KERNEL;
1479
		goto out;
1480 1481 1482
	}
	*sid = SECSID_NULL;

1483 1484
	if (force) {
		/* Save another copy for storing in uninterpreted form */
1485
		rc = -ENOMEM;
1486
		str = kstrdup(scontext2, gfp_flags);
1487 1488
		if (!str)
			goto out;
1489
	}
1490 1491 1492 1493
	read_lock(&state->ss->policy_rwlock);
	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;
	rc = string_to_context_struct(policydb, sidtab, scontext2,
1494
				      scontext_len, &context, def_sid);
1495
	if (rc == -EINVAL && force) {
1496
		context.str = str;
1497
		context.len = scontext_len;
1498
		str = NULL;
1499
	} else if (rc)
1500
		goto out_unlock;
1501
	rc = sidtab_context_to_sid(sidtab, &context, sid);
1502
	context_destroy(&context);
1503
out_unlock:
1504
	read_unlock(&state->ss->policy_rwlock);
1505
out:
1506 1507
	kfree(scontext2);
	kfree(str);
L
Linus Torvalds 已提交
1508 1509 1510
	return rc;
}

1511 1512 1513 1514 1515
/**
 * security_context_to_sid - Obtain a SID for a given security context.
 * @scontext: security context
 * @scontext_len: length in bytes
 * @sid: security identifier, SID
1516
 * @gfp: context for the allocation
1517 1518 1519 1520 1521 1522
 *
 * Obtains a SID associated with the security context that
 * has the string representation specified by @scontext.
 * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
 * memory is available, or 0 on success.
 */
1523 1524
int security_context_to_sid(struct selinux_state *state,
			    const char *scontext, u32 scontext_len, u32 *sid,
1525
			    gfp_t gfp)
1526
{
1527
	return security_context_to_sid_core(state, scontext, scontext_len,
1528
					    sid, SECSID_NULL, gfp, 0);
1529 1530
}

1531 1532
int security_context_str_to_sid(struct selinux_state *state,
				const char *scontext, u32 *sid, gfp_t gfp)
1533
{
1534 1535
	return security_context_to_sid(state, scontext, strlen(scontext),
				       sid, gfp);
1536 1537 1538 1539 1540 1541 1542 1543 1544
}

/**
 * security_context_to_sid_default - Obtain a SID for a given security context,
 * falling back to specified default if needed.
 *
 * @scontext: security context
 * @scontext_len: length in bytes
 * @sid: security identifier, SID
G
Gabriel Craciunescu 已提交
1545
 * @def_sid: default SID to assign on error
1546 1547 1548 1549 1550 1551
 *
 * Obtains a SID associated with the security context that
 * has the string representation specified by @scontext.
 * The default SID is passed to the MLS layer to be used to allow
 * kernel labeling of the MLS field if the MLS field is not present
 * (for upgrading to MLS without full relabel).
1552
 * Implicitly forces adding of the context even if it cannot be mapped yet.
1553 1554 1555
 * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
 * memory is available, or 0 on success.
 */
1556 1557
int security_context_to_sid_default(struct selinux_state *state,
				    const char *scontext, u32 scontext_len,
1558
				    u32 *sid, u32 def_sid, gfp_t gfp_flags)
1559
{
1560
	return security_context_to_sid_core(state, scontext, scontext_len,
1561 1562 1563
					    sid, def_sid, gfp_flags, 1);
}

1564 1565
int security_context_to_sid_force(struct selinux_state *state,
				  const char *scontext, u32 scontext_len,
1566 1567
				  u32 *sid)
{
1568
	return security_context_to_sid_core(state, scontext, scontext_len,
1569
					    sid, SECSID_NULL, GFP_KERNEL, 1);
1570 1571
}

L
Linus Torvalds 已提交
1572
static int compute_sid_handle_invalid_context(
1573
	struct selinux_state *state,
L
Linus Torvalds 已提交
1574 1575 1576 1577 1578
	struct context *scontext,
	struct context *tcontext,
	u16 tclass,
	struct context *newcontext)
{
1579
	struct policydb *policydb = &state->ss->policydb;
L
Linus Torvalds 已提交
1580 1581 1582
	char *s = NULL, *t = NULL, *n = NULL;
	u32 slen, tlen, nlen;

1583
	if (context_struct_to_string(policydb, scontext, &s, &slen))
L
Linus Torvalds 已提交
1584
		goto out;
1585
	if (context_struct_to_string(policydb, tcontext, &t, &tlen))
L
Linus Torvalds 已提交
1586
		goto out;
1587
	if (context_struct_to_string(policydb, newcontext, &n, &nlen))
L
Linus Torvalds 已提交
1588
		goto out;
1589
	audit_log(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR,
1590 1591
		  "op=security_compute_sid invalid_context=%s"
		  " scontext=%s"
L
Linus Torvalds 已提交
1592 1593
		  " tcontext=%s"
		  " tclass=%s",
1594
		  n, s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
L
Linus Torvalds 已提交
1595 1596 1597 1598
out:
	kfree(s);
	kfree(t);
	kfree(n);
1599
	if (!is_enforcing(state))
L
Linus Torvalds 已提交
1600 1601 1602 1603
		return 0;
	return -EACCES;
}

1604 1605
static void filename_compute_type(struct policydb *policydb,
				  struct context *newcontext,
1606
				  u32 stype, u32 ttype, u16 tclass,
1607
				  const char *objname)
1608
{
1609 1610
	struct filename_trans ft;
	struct filename_trans_datum *otype;
1611 1612 1613 1614 1615 1616

	/*
	 * Most filename trans rules are going to live in specific directories
	 * like /dev or /var/run.  This bitmap will quickly skip rule searches
	 * if the ttype does not contain any rules.
	 */
1617
	if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
1618 1619
		return;

1620 1621 1622 1623 1624
	ft.stype = stype;
	ft.ttype = ttype;
	ft.tclass = tclass;
	ft.name = objname;

1625
	otype = hashtab_search(policydb->filename_trans, &ft);
1626 1627
	if (otype)
		newcontext->type = otype->otype;
1628 1629
}

1630 1631
static int security_compute_sid(struct selinux_state *state,
				u32 ssid,
L
Linus Torvalds 已提交
1632
				u32 tsid,
1633
				u16 orig_tclass,
L
Linus Torvalds 已提交
1634
				u32 specified,
1635
				const char *objname,
1636 1637
				u32 *out_sid,
				bool kern)
L
Linus Torvalds 已提交
1638
{
1639 1640
	struct policydb *policydb;
	struct sidtab *sidtab;
1641
	struct class_datum *cladatum = NULL;
L
Linus Torvalds 已提交
1642 1643 1644 1645 1646
	struct context *scontext = NULL, *tcontext = NULL, newcontext;
	struct role_trans *roletr = NULL;
	struct avtab_key avkey;
	struct avtab_datum *avdatum;
	struct avtab_node *node;
1647
	u16 tclass;
L
Linus Torvalds 已提交
1648
	int rc = 0;
1649
	bool sock;
L
Linus Torvalds 已提交
1650

1651
	if (!state->initialized) {
1652 1653
		switch (orig_tclass) {
		case SECCLASS_PROCESS: /* kernel value */
L
Linus Torvalds 已提交
1654 1655 1656 1657 1658 1659 1660 1661 1662
			*out_sid = ssid;
			break;
		default:
			*out_sid = tsid;
			break;
		}
		goto out;
	}

1663 1664
	context_init(&newcontext);

1665
	read_lock(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
1666

1667
	if (kern) {
1668
		tclass = unmap_class(&state->ss->map, orig_tclass);
1669 1670
		sock = security_is_socket_class(orig_tclass);
	} else {
1671
		tclass = orig_tclass;
1672 1673
		sock = security_is_socket_class(map_class(&state->ss->map,
							  tclass));
1674
	}
1675

1676 1677 1678 1679
	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;

	scontext = sidtab_search(sidtab, ssid);
L
Linus Torvalds 已提交
1680
	if (!scontext) {
E
Eric Paris 已提交
1681 1682
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
		       __func__, ssid);
L
Linus Torvalds 已提交
1683 1684 1685
		rc = -EINVAL;
		goto out_unlock;
	}
1686
	tcontext = sidtab_search(sidtab, tsid);
L
Linus Torvalds 已提交
1687
	if (!tcontext) {
E
Eric Paris 已提交
1688 1689
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
		       __func__, tsid);
L
Linus Torvalds 已提交
1690 1691 1692 1693
		rc = -EINVAL;
		goto out_unlock;
	}

1694 1695
	if (tclass && tclass <= policydb->p_classes.nprim)
		cladatum = policydb->class_val_to_struct[tclass - 1];
1696

L
Linus Torvalds 已提交
1697 1698 1699 1700
	/* Set the user identity. */
	switch (specified) {
	case AVTAB_TRANSITION:
	case AVTAB_CHANGE:
1701 1702 1703 1704 1705 1706 1707
		if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
			newcontext.user = tcontext->user;
		} else {
			/* notice this gets both DEFAULT_SOURCE and unset */
			/* Use the process user identity. */
			newcontext.user = scontext->user;
		}
L
Linus Torvalds 已提交
1708 1709 1710 1711 1712 1713 1714
		break;
	case AVTAB_MEMBER:
		/* Use the related object owner. */
		newcontext.user = tcontext->user;
		break;
	}

1715 1716
	/* Set the role to default values. */
	if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
L
Linus Torvalds 已提交
1717
		newcontext.role = scontext->role;
1718 1719 1720
	} else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
		newcontext.role = tcontext->role;
	} else {
1721
		if ((tclass == policydb->process_class) || (sock == true))
1722 1723 1724 1725 1726 1727
			newcontext.role = scontext->role;
		else
			newcontext.role = OBJECT_R_VAL;
	}

	/* Set the type to default values. */
1728
	if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
L
Linus Torvalds 已提交
1729
		newcontext.type = scontext->type;
1730
	} else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
L
Linus Torvalds 已提交
1731
		newcontext.type = tcontext->type;
1732
	} else {
1733
		if ((tclass == policydb->process_class) || (sock == true)) {
1734 1735 1736 1737 1738 1739
			/* Use the type of process. */
			newcontext.type = scontext->type;
		} else {
			/* Use the type of the related object. */
			newcontext.type = tcontext->type;
		}
L
Linus Torvalds 已提交
1740 1741 1742 1743 1744 1745
	}

	/* Look for a type transition/member/change rule. */
	avkey.source_type = scontext->type;
	avkey.target_type = tcontext->type;
	avkey.target_class = tclass;
1746
	avkey.specified = specified;
1747
	avdatum = avtab_search(&policydb->te_avtab, &avkey);
L
Linus Torvalds 已提交
1748 1749

	/* If no permanent rule, also check for enabled conditional rules */
1750
	if (!avdatum) {
1751
		node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
1752
		for (; node; node = avtab_search_node_next(node, specified)) {
1753
			if (node->key.specified & AVTAB_ENABLED) {
L
Linus Torvalds 已提交
1754 1755 1756 1757 1758 1759
				avdatum = &node->datum;
				break;
			}
		}
	}

1760
	if (avdatum) {
L
Linus Torvalds 已提交
1761
		/* Use the type from the type transition/member/change rule. */
1762
		newcontext.type = avdatum->u.data;
L
Linus Torvalds 已提交
1763 1764
	}

1765
	/* if we have a objname this is a file trans check so check those rules */
1766
	if (objname)
1767
		filename_compute_type(policydb, &newcontext, scontext->type,
1768
				      tcontext->type, tclass, objname);
1769

L
Linus Torvalds 已提交
1770
	/* Check for class-specific changes. */
1771 1772
	if (specified & AVTAB_TRANSITION) {
		/* Look for a role transition rule. */
1773 1774
		for (roletr = policydb->role_tr; roletr;
		     roletr = roletr->next) {
1775 1776 1777 1778 1779 1780
			if ((roletr->role == scontext->role) &&
			    (roletr->type == tcontext->type) &&
			    (roletr->tclass == tclass)) {
				/* Use the role transition rule. */
				newcontext.role = roletr->new_role;
				break;
L
Linus Torvalds 已提交
1781 1782 1783 1784 1785 1786
			}
		}
	}

	/* Set the MLS attributes.
	   This is done last because it may allocate memory. */
1787
	rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
1788
			     &newcontext, sock);
L
Linus Torvalds 已提交
1789 1790 1791 1792
	if (rc)
		goto out_unlock;

	/* Check the validity of the context. */
1793 1794
	if (!policydb_context_isvalid(policydb, &newcontext)) {
		rc = compute_sid_handle_invalid_context(state, scontext,
L
Linus Torvalds 已提交
1795 1796 1797 1798 1799 1800 1801
							tcontext,
							tclass,
							&newcontext);
		if (rc)
			goto out_unlock;
	}
	/* Obtain the sid for the context. */
1802
	rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
L
Linus Torvalds 已提交
1803
out_unlock:
1804
	read_unlock(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822
	context_destroy(&newcontext);
out:
	return rc;
}

/**
 * security_transition_sid - Compute the SID for a new subject/object.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 * @out_sid: security identifier for new subject/object
 *
 * Compute a SID to use for labeling a new subject or object in the
 * class @tclass based on a SID pair (@ssid, @tsid).
 * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
 * if insufficient memory is available, or %0 if the new SID was
 * computed successfully.
 */
1823 1824
int security_transition_sid(struct selinux_state *state,
			    u32 ssid, u32 tsid, u16 tclass,
1825
			    const struct qstr *qstr, u32 *out_sid)
L
Linus Torvalds 已提交
1826
{
1827 1828
	return security_compute_sid(state, ssid, tsid, tclass,
				    AVTAB_TRANSITION,
1829
				    qstr ? qstr->name : NULL, out_sid, true);
1830 1831
}

1832 1833
int security_transition_sid_user(struct selinux_state *state,
				 u32 ssid, u32 tsid, u16 tclass,
1834
				 const char *objname, u32 *out_sid)
1835
{
1836 1837
	return security_compute_sid(state, ssid, tsid, tclass,
				    AVTAB_TRANSITION,
1838
				    objname, out_sid, false);
L
Linus Torvalds 已提交
1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853
}

/**
 * security_member_sid - Compute the SID for member selection.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 * @out_sid: security identifier for selected member
 *
 * Compute a SID to use when selecting a member of a polyinstantiated
 * object of class @tclass based on a SID pair (@ssid, @tsid).
 * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
 * if insufficient memory is available, or %0 if the SID was
 * computed successfully.
 */
1854 1855
int security_member_sid(struct selinux_state *state,
			u32 ssid,
L
Linus Torvalds 已提交
1856 1857 1858 1859
			u32 tsid,
			u16 tclass,
			u32 *out_sid)
{
1860 1861
	return security_compute_sid(state, ssid, tsid, tclass,
				    AVTAB_MEMBER, NULL,
1862
				    out_sid, false);
L
Linus Torvalds 已提交
1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877
}

/**
 * security_change_sid - Compute the SID for object relabeling.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 * @out_sid: security identifier for selected member
 *
 * Compute a SID to use for relabeling an object of class @tclass
 * based on a SID pair (@ssid, @tsid).
 * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
 * if insufficient memory is available, or %0 if the SID was
 * computed successfully.
 */
1878 1879
int security_change_sid(struct selinux_state *state,
			u32 ssid,
L
Linus Torvalds 已提交
1880 1881 1882 1883
			u32 tsid,
			u16 tclass,
			u32 *out_sid)
{
1884 1885
	return security_compute_sid(state,
				    ssid, tsid, tclass, AVTAB_CHANGE, NULL,
1886
				    out_sid, false);
1887 1888
}

L
Linus Torvalds 已提交
1889 1890 1891 1892 1893 1894 1895
/* Clone the SID into the new SID table. */
static int clone_sid(u32 sid,
		     struct context *context,
		     void *arg)
{
	struct sidtab *s = arg;

1896 1897 1898 1899
	if (sid > SECINITSID_NUM)
		return sidtab_insert(s, sid, context);
	else
		return 0;
L
Linus Torvalds 已提交
1900 1901
}

1902 1903 1904
static inline int convert_context_handle_invalid_context(
	struct selinux_state *state,
	struct context *context)
L
Linus Torvalds 已提交
1905
{
1906
	struct policydb *policydb = &state->ss->policydb;
1907 1908
	char *s;
	u32 len;
L
Linus Torvalds 已提交
1909

1910
	if (is_enforcing(state))
1911 1912
		return -EINVAL;

1913
	if (!context_struct_to_string(policydb, context, &s, &len)) {
1914 1915
		printk(KERN_WARNING "SELinux:  Context %s would be invalid if enforcing\n", s);
		kfree(s);
L
Linus Torvalds 已提交
1916
	}
1917
	return 0;
L
Linus Torvalds 已提交
1918 1919 1920
}

struct convert_context_args {
1921
	struct selinux_state *state;
L
Linus Torvalds 已提交
1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938
	struct policydb *oldp;
	struct policydb *newp;
};

/*
 * Convert the values in the security context
 * structure `c' from the values specified
 * in the policy `p->oldp' to the values specified
 * in the policy `p->newp'.  Verify that the
 * context is valid under the new policy.
 */
static int convert_context(u32 key,
			   struct context *c,
			   void *p)
{
	struct convert_context_args *args;
	struct context oldc;
1939 1940
	struct ocontext *oc;
	struct mls_range *range;
L
Linus Torvalds 已提交
1941 1942 1943 1944 1945
	struct role_datum *role;
	struct type_datum *typdatum;
	struct user_datum *usrdatum;
	char *s;
	u32 len;
1946 1947 1948 1949
	int rc = 0;

	if (key <= SECINITSID_NUM)
		goto out;
L
Linus Torvalds 已提交
1950 1951 1952

	args = p;

1953 1954
	if (c->str) {
		struct context ctx;
1955 1956

		rc = -ENOMEM;
1957
		s = kstrdup(c->str, GFP_KERNEL);
1958
		if (!s)
1959
			goto out;
1960

1961 1962 1963
		rc = string_to_context_struct(args->newp, NULL, s,
					      c->len, &ctx, SECSID_NULL);
		kfree(s);
1964
		if (!rc) {
1965
			printk(KERN_INFO "SELinux:  Context %s became valid (mapped).\n",
1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976
			       c->str);
			/* Replace string with mapped representation. */
			kfree(c->str);
			memcpy(c, &ctx, sizeof(*c));
			goto out;
		} else if (rc == -EINVAL) {
			/* Retain string representation for later mapping. */
			rc = 0;
			goto out;
		} else {
			/* Other error condition, e.g. ENOMEM. */
1977
			printk(KERN_ERR "SELinux:   Unable to map context %s, rc = %d.\n",
1978 1979 1980 1981 1982
			       c->str, -rc);
			goto out;
		}
	}

L
Linus Torvalds 已提交
1983 1984 1985 1986 1987
	rc = context_cpy(&oldc, c);
	if (rc)
		goto out;

	/* Convert the user. */
1988
	rc = -EINVAL;
L
Linus Torvalds 已提交
1989
	usrdatum = hashtab_search(args->newp->p_users.table,
1990
				  sym_name(args->oldp, SYM_USERS, c->user - 1));
1991
	if (!usrdatum)
L
Linus Torvalds 已提交
1992 1993 1994 1995
		goto bad;
	c->user = usrdatum->value;

	/* Convert the role. */
1996
	rc = -EINVAL;
L
Linus Torvalds 已提交
1997
	role = hashtab_search(args->newp->p_roles.table,
1998
			      sym_name(args->oldp, SYM_ROLES, c->role - 1));
1999
	if (!role)
L
Linus Torvalds 已提交
2000 2001 2002 2003
		goto bad;
	c->role = role->value;

	/* Convert the type. */
2004
	rc = -EINVAL;
L
Linus Torvalds 已提交
2005
	typdatum = hashtab_search(args->newp->p_types.table,
2006
				  sym_name(args->oldp, SYM_TYPES, c->type - 1));
2007
	if (!typdatum)
L
Linus Torvalds 已提交
2008 2009 2010
		goto bad;
	c->type = typdatum->value;

2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033
	/* Convert the MLS fields if dealing with MLS policies */
	if (args->oldp->mls_enabled && args->newp->mls_enabled) {
		rc = mls_convert_context(args->oldp, args->newp, c);
		if (rc)
			goto bad;
	} else if (args->oldp->mls_enabled && !args->newp->mls_enabled) {
		/*
		 * Switching between MLS and non-MLS policy:
		 * free any storage used by the MLS fields in the
		 * context for all existing entries in the sidtab.
		 */
		mls_context_destroy(c);
	} else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
		/*
		 * Switching between non-MLS and MLS policy:
		 * ensure that the MLS fields of the context for all
		 * existing entries in the sidtab are filled in with a
		 * suitable default value, likely taken from one of the
		 * initial SIDs.
		 */
		oc = args->newp->ocontexts[OCON_ISID];
		while (oc && oc->sid[0] != SECINITSID_UNLABELED)
			oc = oc->next;
2034
		rc = -EINVAL;
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044
		if (!oc) {
			printk(KERN_ERR "SELinux:  unable to look up"
				" the initial SIDs list\n");
			goto bad;
		}
		range = &oc->context[0].range;
		rc = mls_range_set(c, range);
		if (rc)
			goto bad;
	}
L
Linus Torvalds 已提交
2045 2046 2047

	/* Check the validity of the new context. */
	if (!policydb_context_isvalid(args->newp, c)) {
2048 2049
		rc = convert_context_handle_invalid_context(args->state,
							    &oldc);
L
Linus Torvalds 已提交
2050 2051 2052 2053 2054
		if (rc)
			goto bad;
	}

	context_destroy(&oldc);
2055

2056
	rc = 0;
L
Linus Torvalds 已提交
2057 2058 2059
out:
	return rc;
bad:
2060
	/* Map old representation to string and save it. */
2061
	rc = context_struct_to_string(args->oldp, &oldc, &s, &len);
2062 2063
	if (rc)
		return rc;
L
Linus Torvalds 已提交
2064
	context_destroy(&oldc);
2065 2066 2067
	context_destroy(c);
	c->str = s;
	c->len = len;
2068
	printk(KERN_INFO "SELinux:  Context %s became invalid (unmapped).\n",
2069 2070
	       c->str);
	rc = 0;
L
Linus Torvalds 已提交
2071 2072 2073
	goto out;
}

2074
static void security_load_policycaps(struct selinux_state *state)
2075
{
2076
	struct policydb *p = &state->ss->policydb;
2077 2078 2079
	unsigned int i;
	struct ebitmap_node *node;

2080 2081
	for (i = 0; i < ARRAY_SIZE(state->policycap); i++)
		state->policycap[i] = ebitmap_get_bit(&p->policycaps, i);
2082 2083 2084 2085

	for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
		pr_info("SELinux:  policy capability %s=%d\n",
			selinux_policycap_names[i],
2086
			ebitmap_get_bit(&p->policycaps, i));
2087

2088
	ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
2089 2090 2091 2092
		if (i >= ARRAY_SIZE(selinux_policycap_names))
			pr_info("SELinux:  unknown policy capability %u\n",
				i);
	}
2093 2094
}

2095 2096
static int security_preserve_bools(struct selinux_state *state,
				   struct policydb *newpolicydb);
L
Linus Torvalds 已提交
2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107

/**
 * security_load_policy - Load a security policy configuration.
 * @data: binary policy data
 * @len: length of data in bytes
 *
 * Load a new set of security policy configuration data,
 * validate it and convert the SID table as necessary.
 * This function will flush the access vector cache after
 * loading the new policy.
 */
2108
int security_load_policy(struct selinux_state *state, void *data, size_t len)
L
Linus Torvalds 已提交
2109
{
2110 2111
	struct policydb *policydb;
	struct sidtab *sidtab;
2112
	struct policydb *oldpolicydb, *newpolicydb;
L
Linus Torvalds 已提交
2113
	struct sidtab oldsidtab, newsidtab;
2114 2115
	struct selinux_mapping *oldmapping;
	struct selinux_map newmap;
L
Linus Torvalds 已提交
2116 2117 2118 2119 2120
	struct convert_context_args args;
	u32 seqno;
	int rc = 0;
	struct policy_file file = { data, len }, *fp = &file;

2121 2122 2123 2124 2125 2126 2127
	oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL);
	if (!oldpolicydb) {
		rc = -ENOMEM;
		goto out;
	}
	newpolicydb = oldpolicydb + 1;

2128 2129 2130 2131 2132 2133
	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;

	if (!state->initialized) {
		rc = policydb_read(policydb, fp);
		if (rc)
2134
			goto out;
2135

2136 2137 2138
		policydb->len = len;
		rc = selinux_set_mapping(policydb, secclass_map,
					 &state->ss->map);
2139
		if (rc) {
2140
			policydb_destroy(policydb);
2141
			goto out;
L
Linus Torvalds 已提交
2142
		}
2143

2144
		rc = policydb_load_isids(policydb, sidtab);
2145
		if (rc) {
2146
			policydb_destroy(policydb);
2147
			goto out;
2148
		}
2149

2150 2151 2152
		security_load_policycaps(state);
		state->initialized = 1;
		seqno = ++state->ss->latest_granting;
L
Linus Torvalds 已提交
2153
		selinux_complete_init();
2154 2155
		avc_ss_reset(seqno);
		selnl_notify_policyload(seqno);
2156
		selinux_status_update_policyload(state, seqno);
V
Venkat Yekkirala 已提交
2157
		selinux_netlbl_cache_invalidate();
2158
		selinux_xfrm_notify_policyload();
2159
		goto out;
L
Linus Torvalds 已提交
2160 2161 2162
	}

#if 0
2163
	sidtab_hash_eval(sidtab, "sids");
L
Linus Torvalds 已提交
2164 2165
#endif

2166
	rc = policydb_read(newpolicydb, fp);
2167
	if (rc)
2168
		goto out;
L
Linus Torvalds 已提交
2169

2170
	newpolicydb->len = len;
2171
	/* If switching between different policy types, log MLS status */
2172
	if (policydb->mls_enabled && !newpolicydb->mls_enabled)
2173
		printk(KERN_INFO "SELinux: Disabling MLS support...\n");
2174
	else if (!policydb->mls_enabled && newpolicydb->mls_enabled)
2175 2176
		printk(KERN_INFO "SELinux: Enabling MLS support...\n");

2177
	rc = policydb_load_isids(newpolicydb, &newsidtab);
2178 2179
	if (rc) {
		printk(KERN_ERR "SELinux:  unable to load the initial SIDs\n");
2180 2181
		policydb_destroy(newpolicydb);
		goto out;
2182
	}
L
Linus Torvalds 已提交
2183

2184
	rc = selinux_set_mapping(newpolicydb, secclass_map, &newmap);
2185
	if (rc)
2186 2187
		goto err;

2188
	rc = security_preserve_bools(state, newpolicydb);
2189
	if (rc) {
J
James Morris 已提交
2190
		printk(KERN_ERR "SELinux:  unable to preserve booleans\n");
2191 2192 2193
		goto err;
	}

L
Linus Torvalds 已提交
2194
	/* Clone the SID table. */
2195
	sidtab_shutdown(sidtab);
2196

2197
	rc = sidtab_map(sidtab, clone_sid, &newsidtab);
2198
	if (rc)
L
Linus Torvalds 已提交
2199 2200
		goto err;

2201 2202 2203 2204
	/*
	 * Convert the internal representations of contexts
	 * in the new SID table.
	 */
2205 2206
	args.state = state;
	args.oldp = policydb;
2207
	args.newp = newpolicydb;
2208
	rc = sidtab_map(&newsidtab, convert_context, &args);
2209 2210 2211 2212
	if (rc) {
		printk(KERN_ERR "SELinux:  unable to convert the internal"
			" representation of contexts in the new SID"
			" table\n");
2213
		goto err;
2214
	}
L
Linus Torvalds 已提交
2215 2216

	/* Save the old policydb and SID table to free later. */
2217 2218
	memcpy(oldpolicydb, policydb, sizeof(*policydb));
	sidtab_set(&oldsidtab, sidtab);
L
Linus Torvalds 已提交
2219 2220

	/* Install the new policydb and SID table. */
2221 2222 2223 2224 2225 2226 2227 2228 2229
	write_lock_irq(&state->ss->policy_rwlock);
	memcpy(policydb, newpolicydb, sizeof(*policydb));
	sidtab_set(sidtab, &newsidtab);
	security_load_policycaps(state);
	oldmapping = state->ss->map.mapping;
	state->ss->map.mapping = newmap.mapping;
	state->ss->map.size = newmap.size;
	seqno = ++state->ss->latest_granting;
	write_unlock_irq(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
2230 2231

	/* Free the old policydb and SID table. */
2232
	policydb_destroy(oldpolicydb);
L
Linus Torvalds 已提交
2233
	sidtab_destroy(&oldsidtab);
2234
	kfree(oldmapping);
L
Linus Torvalds 已提交
2235 2236 2237

	avc_ss_reset(seqno);
	selnl_notify_policyload(seqno);
2238
	selinux_status_update_policyload(state, seqno);
V
Venkat Yekkirala 已提交
2239
	selinux_netlbl_cache_invalidate();
2240
	selinux_xfrm_notify_policyload();
L
Linus Torvalds 已提交
2241

2242 2243
	rc = 0;
	goto out;
L
Linus Torvalds 已提交
2244 2245

err:
2246
	kfree(newmap.mapping);
L
Linus Torvalds 已提交
2247
	sidtab_destroy(&newsidtab);
2248
	policydb_destroy(newpolicydb);
L
Linus Torvalds 已提交
2249

2250 2251 2252
out:
	kfree(oldpolicydb);
	return rc;
L
Linus Torvalds 已提交
2253 2254
}

2255
size_t security_policydb_len(struct selinux_state *state)
2256
{
2257
	struct policydb *p = &state->ss->policydb;
2258 2259
	size_t len;

2260 2261 2262
	read_lock(&state->ss->policy_rwlock);
	len = p->len;
	read_unlock(&state->ss->policy_rwlock);
2263 2264 2265 2266

	return len;
}

L
Linus Torvalds 已提交
2267 2268 2269 2270 2271 2272
/**
 * security_port_sid - Obtain the SID for a port.
 * @protocol: protocol number
 * @port: port number
 * @out_sid: security identifier
 */
2273 2274
int security_port_sid(struct selinux_state *state,
		      u8 protocol, u16 port, u32 *out_sid)
L
Linus Torvalds 已提交
2275
{
2276 2277
	struct policydb *policydb;
	struct sidtab *sidtab;
L
Linus Torvalds 已提交
2278 2279 2280
	struct ocontext *c;
	int rc = 0;

2281 2282 2283 2284
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;
L
Linus Torvalds 已提交
2285

2286
	c = policydb->ocontexts[OCON_PORT];
L
Linus Torvalds 已提交
2287 2288 2289 2290 2291 2292 2293 2294 2295 2296
	while (c) {
		if (c->u.port.protocol == protocol &&
		    c->u.port.low_port <= port &&
		    c->u.port.high_port >= port)
			break;
		c = c->next;
	}

	if (c) {
		if (!c->sid[0]) {
2297
			rc = sidtab_context_to_sid(sidtab,
L
Linus Torvalds 已提交
2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308
						   &c->context[0],
						   &c->sid[0]);
			if (rc)
				goto out;
		}
		*out_sid = c->sid[0];
	} else {
		*out_sid = SECINITSID_PORT;
	}

out:
2309
	read_unlock(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
2310 2311 2312
	return rc;
}

2313 2314 2315 2316 2317 2318
/**
 * security_pkey_sid - Obtain the SID for a pkey.
 * @subnet_prefix: Subnet Prefix
 * @pkey_num: pkey number
 * @out_sid: security identifier
 */
2319 2320
int security_ib_pkey_sid(struct selinux_state *state,
			 u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
2321
{
2322 2323
	struct policydb *policydb;
	struct sidtab *sidtab;
2324 2325 2326
	struct ocontext *c;
	int rc = 0;

2327 2328 2329 2330
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;
2331

2332
	c = policydb->ocontexts[OCON_IBPKEY];
2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343
	while (c) {
		if (c->u.ibpkey.low_pkey <= pkey_num &&
		    c->u.ibpkey.high_pkey >= pkey_num &&
		    c->u.ibpkey.subnet_prefix == subnet_prefix)
			break;

		c = c->next;
	}

	if (c) {
		if (!c->sid[0]) {
2344
			rc = sidtab_context_to_sid(sidtab,
2345 2346 2347 2348 2349 2350 2351 2352 2353 2354
						   &c->context[0],
						   &c->sid[0]);
			if (rc)
				goto out;
		}
		*out_sid = c->sid[0];
	} else
		*out_sid = SECINITSID_UNLABELED;

out:
2355
	read_unlock(&state->ss->policy_rwlock);
2356 2357 2358
	return rc;
}

2359 2360 2361 2362 2363 2364
/**
 * security_ib_endport_sid - Obtain the SID for a subnet management interface.
 * @dev_name: device name
 * @port: port number
 * @out_sid: security identifier
 */
2365 2366
int security_ib_endport_sid(struct selinux_state *state,
			    const char *dev_name, u8 port_num, u32 *out_sid)
2367
{
2368 2369
	struct policydb *policydb;
	struct sidtab *sidtab;
2370 2371 2372
	struct ocontext *c;
	int rc = 0;

2373
	read_lock(&state->ss->policy_rwlock);
2374

2375 2376 2377 2378
	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;

	c = policydb->ocontexts[OCON_IBENDPORT];
2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390
	while (c) {
		if (c->u.ibendport.port == port_num &&
		    !strncmp(c->u.ibendport.dev_name,
			     dev_name,
			     IB_DEVICE_NAME_MAX))
			break;

		c = c->next;
	}

	if (c) {
		if (!c->sid[0]) {
2391
			rc = sidtab_context_to_sid(sidtab,
2392 2393 2394 2395 2396 2397 2398 2399 2400 2401
						   &c->context[0],
						   &c->sid[0]);
			if (rc)
				goto out;
		}
		*out_sid = c->sid[0];
	} else
		*out_sid = SECINITSID_UNLABELED;

out:
2402
	read_unlock(&state->ss->policy_rwlock);
2403 2404 2405
	return rc;
}

L
Linus Torvalds 已提交
2406 2407 2408 2409 2410
/**
 * security_netif_sid - Obtain the SID for a network interface.
 * @name: interface name
 * @if_sid: interface SID
 */
2411 2412
int security_netif_sid(struct selinux_state *state,
		       char *name, u32 *if_sid)
L
Linus Torvalds 已提交
2413
{
2414 2415
	struct policydb *policydb;
	struct sidtab *sidtab;
L
Linus Torvalds 已提交
2416 2417 2418
	int rc = 0;
	struct ocontext *c;

2419 2420 2421 2422
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;
L
Linus Torvalds 已提交
2423

2424
	c = policydb->ocontexts[OCON_NETIF];
L
Linus Torvalds 已提交
2425 2426 2427 2428 2429 2430 2431 2432
	while (c) {
		if (strcmp(name, c->u.name) == 0)
			break;
		c = c->next;
	}

	if (c) {
		if (!c->sid[0] || !c->sid[1]) {
2433
			rc = sidtab_context_to_sid(sidtab,
L
Linus Torvalds 已提交
2434 2435 2436 2437
						  &c->context[0],
						  &c->sid[0]);
			if (rc)
				goto out;
2438
			rc = sidtab_context_to_sid(sidtab,
L
Linus Torvalds 已提交
2439 2440 2441 2442 2443 2444
						   &c->context[1],
						   &c->sid[1]);
			if (rc)
				goto out;
		}
		*if_sid = c->sid[0];
2445
	} else
L
Linus Torvalds 已提交
2446 2447 2448
		*if_sid = SECINITSID_NETIF;

out:
2449
	read_unlock(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
2450 2451 2452 2453 2454 2455 2456
	return rc;
}

static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
{
	int i, fail = 0;

2457 2458
	for (i = 0; i < 4; i++)
		if (addr[i] != (input[i] & mask[i])) {
L
Linus Torvalds 已提交
2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472
			fail = 1;
			break;
		}

	return !fail;
}

/**
 * security_node_sid - Obtain the SID for a node (host).
 * @domain: communication domain aka address family
 * @addrp: address
 * @addrlen: address length in bytes
 * @out_sid: security identifier
 */
2473 2474
int security_node_sid(struct selinux_state *state,
		      u16 domain,
L
Linus Torvalds 已提交
2475 2476 2477 2478
		      void *addrp,
		      u32 addrlen,
		      u32 *out_sid)
{
2479 2480
	struct policydb *policydb;
	struct sidtab *sidtab;
2481
	int rc;
L
Linus Torvalds 已提交
2482 2483
	struct ocontext *c;

2484 2485 2486 2487
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;
L
Linus Torvalds 已提交
2488 2489 2490 2491 2492

	switch (domain) {
	case AF_INET: {
		u32 addr;

2493 2494
		rc = -EINVAL;
		if (addrlen != sizeof(u32))
L
Linus Torvalds 已提交
2495 2496 2497 2498
			goto out;

		addr = *((u32 *)addrp);

2499
		c = policydb->ocontexts[OCON_NODE];
L
Linus Torvalds 已提交
2500 2501 2502 2503 2504 2505 2506 2507 2508
		while (c) {
			if (c->u.node.addr == (addr & c->u.node.mask))
				break;
			c = c->next;
		}
		break;
	}

	case AF_INET6:
2509 2510
		rc = -EINVAL;
		if (addrlen != sizeof(u64) * 2)
L
Linus Torvalds 已提交
2511
			goto out;
2512
		c = policydb->ocontexts[OCON_NODE6];
L
Linus Torvalds 已提交
2513 2514 2515 2516 2517 2518 2519 2520 2521
		while (c) {
			if (match_ipv6_addrmask(addrp, c->u.node6.addr,
						c->u.node6.mask))
				break;
			c = c->next;
		}
		break;

	default:
2522
		rc = 0;
L
Linus Torvalds 已提交
2523 2524 2525 2526 2527 2528
		*out_sid = SECINITSID_NODE;
		goto out;
	}

	if (c) {
		if (!c->sid[0]) {
2529
			rc = sidtab_context_to_sid(sidtab,
L
Linus Torvalds 已提交
2530 2531 2532 2533 2534 2535 2536 2537 2538 2539
						   &c->context[0],
						   &c->sid[0]);
			if (rc)
				goto out;
		}
		*out_sid = c->sid[0];
	} else {
		*out_sid = SECINITSID_NODE;
	}

2540
	rc = 0;
L
Linus Torvalds 已提交
2541
out:
2542
	read_unlock(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561
	return rc;
}

#define SIDS_NEL 25

/**
 * security_get_user_sids - Obtain reachable SIDs for a user.
 * @fromsid: starting SID
 * @username: username
 * @sids: array of reachable SIDs for user
 * @nel: number of elements in @sids
 *
 * Generate the set of SIDs for legal security contexts
 * for a given user that can be reached by @fromsid.
 * Set *@sids to point to a dynamically allocated
 * array containing the set of SIDs.  Set *@nel to the
 * number of elements in the array.
 */

2562 2563
int security_get_user_sids(struct selinux_state *state,
			   u32 fromsid,
2564
			   char *username,
L
Linus Torvalds 已提交
2565 2566 2567
			   u32 **sids,
			   u32 *nel)
{
2568 2569
	struct policydb *policydb;
	struct sidtab *sidtab;
L
Linus Torvalds 已提交
2570
	struct context *fromcon, usercon;
2571
	u32 *mysids = NULL, *mysids2, sid;
L
Linus Torvalds 已提交
2572 2573 2574
	u32 mynel = 0, maxnel = SIDS_NEL;
	struct user_datum *user;
	struct role_datum *role;
2575
	struct ebitmap_node *rnode, *tnode;
L
Linus Torvalds 已提交
2576 2577
	int rc = 0, i, j;

2578 2579 2580
	*sids = NULL;
	*nel = 0;

2581
	if (!state->initialized)
L
Linus Torvalds 已提交
2582 2583
		goto out;

2584 2585 2586 2587
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;
L
Linus Torvalds 已提交
2588

2589 2590
	context_init(&usercon);

2591
	rc = -EINVAL;
2592
	fromcon = sidtab_search(sidtab, fromsid);
2593
	if (!fromcon)
L
Linus Torvalds 已提交
2594 2595
		goto out_unlock;

2596
	rc = -EINVAL;
2597
	user = hashtab_search(policydb->p_users.table, username);
2598
	if (!user)
L
Linus Torvalds 已提交
2599
		goto out_unlock;
2600

L
Linus Torvalds 已提交
2601 2602
	usercon.user = user->value;

2603
	rc = -ENOMEM;
J
James Morris 已提交
2604
	mysids = kcalloc(maxnel, sizeof(*mysids), GFP_ATOMIC);
2605
	if (!mysids)
L
Linus Torvalds 已提交
2606 2607
		goto out_unlock;

2608
	ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
2609
		role = policydb->role_val_to_struct[i];
2610
		usercon.role = i + 1;
2611
		ebitmap_for_each_positive_bit(&role->types, tnode, j) {
2612
			usercon.type = j + 1;
L
Linus Torvalds 已提交
2613

2614 2615
			if (mls_setup_user_range(policydb, fromcon, user,
						 &usercon))
L
Linus Torvalds 已提交
2616 2617
				continue;

2618
			rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
2619
			if (rc)
L
Linus Torvalds 已提交
2620 2621 2622 2623
				goto out_unlock;
			if (mynel < maxnel) {
				mysids[mynel++] = sid;
			} else {
2624
				rc = -ENOMEM;
L
Linus Torvalds 已提交
2625
				maxnel += SIDS_NEL;
J
James Morris 已提交
2626
				mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
2627
				if (!mysids2)
L
Linus Torvalds 已提交
2628 2629 2630 2631 2632 2633 2634 2635
					goto out_unlock;
				memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
				kfree(mysids);
				mysids = mysids2;
				mysids[mynel++] = sid;
			}
		}
	}
2636
	rc = 0;
L
Linus Torvalds 已提交
2637
out_unlock:
2638
	read_unlock(&state->ss->policy_rwlock);
2639 2640 2641 2642 2643
	if (rc || !mynel) {
		kfree(mysids);
		goto out;
	}

2644
	rc = -ENOMEM;
2645 2646 2647 2648 2649 2650
	mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
	if (!mysids2) {
		kfree(mysids);
		goto out;
	}
	for (i = 0, j = 0; i < mynel; i++) {
2651
		struct av_decision dummy_avd;
2652
		rc = avc_has_perm_noaudit(fromsid, mysids[i],
2653
					  SECCLASS_PROCESS, /* kernel value */
2654
					  PROCESS__TRANSITION, AVC_STRICT,
2655
					  &dummy_avd);
2656 2657 2658 2659 2660 2661 2662 2663
		if (!rc)
			mysids2[j++] = mysids[i];
		cond_resched();
	}
	rc = 0;
	kfree(mysids);
	*sids = mysids2;
	*nel = j;
L
Linus Torvalds 已提交
2664 2665 2666 2667 2668
out:
	return rc;
}

/**
2669
 * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
L
Linus Torvalds 已提交
2670 2671 2672 2673 2674 2675 2676 2677
 * @fstype: filesystem type
 * @path: path from root of mount
 * @sclass: file security class
 * @sid: SID for path
 *
 * Obtain a SID to use for a file in a filesystem that
 * cannot support xattr or use a fixed labeling behavior like
 * transition SIDs or task SIDs.
2678 2679
 *
 * The caller must acquire the policy_rwlock before calling this function.
L
Linus Torvalds 已提交
2680
 */
2681 2682
static inline int __security_genfs_sid(struct selinux_state *state,
				       const char *fstype,
2683 2684 2685
				       char *path,
				       u16 orig_sclass,
				       u32 *sid)
L
Linus Torvalds 已提交
2686
{
2687 2688
	struct policydb *policydb = &state->ss->policydb;
	struct sidtab *sidtab = &state->ss->sidtab;
L
Linus Torvalds 已提交
2689
	int len;
2690
	u16 sclass;
L
Linus Torvalds 已提交
2691 2692
	struct genfs *genfs;
	struct ocontext *c;
2693
	int rc, cmp = 0;
L
Linus Torvalds 已提交
2694

2695 2696 2697
	while (path[0] == '/' && path[1] == '/')
		path++;

2698
	sclass = unmap_class(&state->ss->map, orig_sclass);
2699
	*sid = SECINITSID_UNLABELED;
2700

2701
	for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
L
Linus Torvalds 已提交
2702 2703 2704 2705 2706
		cmp = strcmp(fstype, genfs->fstype);
		if (cmp <= 0)
			break;
	}

2707 2708
	rc = -ENOENT;
	if (!genfs || cmp)
L
Linus Torvalds 已提交
2709 2710 2711 2712 2713 2714 2715 2716 2717
		goto out;

	for (c = genfs->head; c; c = c->next) {
		len = strlen(c->u.name);
		if ((!c->v.sclass || sclass == c->v.sclass) &&
		    (strncmp(c->u.name, path, len) == 0))
			break;
	}

2718 2719
	rc = -ENOENT;
	if (!c)
L
Linus Torvalds 已提交
2720 2721 2722
		goto out;

	if (!c->sid[0]) {
2723
		rc = sidtab_context_to_sid(sidtab, &c->context[0], &c->sid[0]);
L
Linus Torvalds 已提交
2724 2725 2726 2727 2728
		if (rc)
			goto out;
	}

	*sid = c->sid[0];
2729
	rc = 0;
L
Linus Torvalds 已提交
2730 2731 2732 2733
out:
	return rc;
}

2734 2735 2736 2737 2738 2739 2740 2741 2742 2743
/**
 * security_genfs_sid - Obtain a SID for a file in a filesystem
 * @fstype: filesystem type
 * @path: path from root of mount
 * @sclass: file security class
 * @sid: SID for path
 *
 * Acquire policy_rwlock before calling __security_genfs_sid() and release
 * it afterward.
 */
2744 2745
int security_genfs_sid(struct selinux_state *state,
		       const char *fstype,
2746 2747 2748 2749 2750 2751
		       char *path,
		       u16 orig_sclass,
		       u32 *sid)
{
	int retval;

2752 2753 2754
	read_lock(&state->ss->policy_rwlock);
	retval = __security_genfs_sid(state, fstype, path, orig_sclass, sid);
	read_unlock(&state->ss->policy_rwlock);
2755 2756 2757
	return retval;
}

L
Linus Torvalds 已提交
2758 2759
/**
 * security_fs_use - Determine how to handle labeling for a filesystem.
2760
 * @sb: superblock in question
L
Linus Torvalds 已提交
2761
 */
2762
int security_fs_use(struct selinux_state *state, struct super_block *sb)
L
Linus Torvalds 已提交
2763
{
2764 2765
	struct policydb *policydb;
	struct sidtab *sidtab;
L
Linus Torvalds 已提交
2766 2767
	int rc = 0;
	struct ocontext *c;
2768 2769
	struct superblock_security_struct *sbsec = sb->s_security;
	const char *fstype = sb->s_type->name;
L
Linus Torvalds 已提交
2770

2771 2772 2773 2774
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
	sidtab = &state->ss->sidtab;
L
Linus Torvalds 已提交
2775

2776
	c = policydb->ocontexts[OCON_FSUSE];
2777 2778
	while (c) {
		if (strcmp(fstype, c->u.name) == 0)
L
Linus Torvalds 已提交
2779
			break;
2780
		c = c->next;
L
Linus Torvalds 已提交
2781 2782 2783
	}

	if (c) {
2784
		sbsec->behavior = c->v.behavior;
L
Linus Torvalds 已提交
2785
		if (!c->sid[0]) {
2786
			rc = sidtab_context_to_sid(sidtab, &c->context[0],
L
Linus Torvalds 已提交
2787 2788 2789 2790
						   &c->sid[0]);
			if (rc)
				goto out;
		}
2791
		sbsec->sid = c->sid[0];
L
Linus Torvalds 已提交
2792
	} else {
2793
		rc = __security_genfs_sid(state, fstype, "/", SECCLASS_DIR,
2794
					  &sbsec->sid);
2795
		if (rc) {
2796
			sbsec->behavior = SECURITY_FS_USE_NONE;
2797 2798
			rc = 0;
		} else {
2799
			sbsec->behavior = SECURITY_FS_USE_GENFS;
2800
		}
L
Linus Torvalds 已提交
2801 2802 2803
	}

out:
2804
	read_unlock(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
2805 2806 2807
	return rc;
}

2808 2809
int security_get_bools(struct selinux_state *state,
		       int *len, char ***names, int **values)
L
Linus Torvalds 已提交
2810
{
2811
	struct policydb *policydb;
2812
	int i, rc;
L
Linus Torvalds 已提交
2813

2814 2815 2816 2817
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;

L
Linus Torvalds 已提交
2818 2819 2820
	*names = NULL;
	*values = NULL;

2821
	rc = 0;
2822
	*len = policydb->p_bools.nprim;
2823
	if (!*len)
L
Linus Torvalds 已提交
2824 2825
		goto out;

2826 2827
	rc = -ENOMEM;
	*names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
L
Linus Torvalds 已提交
2828 2829 2830
	if (!*names)
		goto err;

2831 2832
	rc = -ENOMEM;
	*values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
L
Linus Torvalds 已提交
2833 2834 2835 2836
	if (!*values)
		goto err;

	for (i = 0; i < *len; i++) {
2837
		(*values)[i] = policydb->bool_val_to_struct[i]->state;
2838 2839

		rc = -ENOMEM;
2840 2841
		(*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
				      GFP_ATOMIC);
L
Linus Torvalds 已提交
2842 2843 2844 2845 2846
		if (!(*names)[i])
			goto err;
	}
	rc = 0;
out:
2847
	read_unlock(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
2848 2849 2850 2851
	return rc;
err:
	if (*names) {
		for (i = 0; i < *len; i++)
J
Jesper Juhl 已提交
2852
			kfree((*names)[i]);
L
Linus Torvalds 已提交
2853
	}
J
Jesper Juhl 已提交
2854
	kfree(*values);
L
Linus Torvalds 已提交
2855 2856 2857 2858
	goto out;
}


2859
int security_set_bools(struct selinux_state *state, int len, int *values)
L
Linus Torvalds 已提交
2860
{
2861
	struct policydb *policydb;
2862
	int i, rc;
L
Linus Torvalds 已提交
2863 2864 2865
	int lenp, seqno = 0;
	struct cond_node *cur;

2866 2867 2868
	write_lock_irq(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
L
Linus Torvalds 已提交
2869

2870
	rc = -EFAULT;
2871
	lenp = policydb->p_bools.nprim;
2872
	if (len != lenp)
L
Linus Torvalds 已提交
2873 2874 2875
		goto out;

	for (i = 0; i < len; i++) {
2876
		if (!!values[i] != policydb->bool_val_to_struct[i]->state) {
S
Steve Grubb 已提交
2877 2878
			audit_log(current->audit_context, GFP_ATOMIC,
				AUDIT_MAC_CONFIG_CHANGE,
2879
				"bool=%s val=%d old_val=%d auid=%u ses=%u",
2880
				sym_name(policydb, SYM_BOOLS, i),
S
Steve Grubb 已提交
2881
				!!values[i],
2882
				policydb->bool_val_to_struct[i]->state,
2883
				from_kuid(&init_user_ns, audit_get_loginuid(current)),
2884
				audit_get_sessionid(current));
S
Steve Grubb 已提交
2885
		}
2886
		if (values[i])
2887
			policydb->bool_val_to_struct[i]->state = 1;
2888
		else
2889
			policydb->bool_val_to_struct[i]->state = 0;
L
Linus Torvalds 已提交
2890 2891
	}

2892 2893
	for (cur = policydb->cond_list; cur; cur = cur->next) {
		rc = evaluate_cond_node(policydb, cur);
L
Linus Torvalds 已提交
2894 2895 2896 2897
		if (rc)
			goto out;
	}

2898
	seqno = ++state->ss->latest_granting;
2899
	rc = 0;
L
Linus Torvalds 已提交
2900
out:
2901
	write_unlock_irq(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
2902 2903 2904
	if (!rc) {
		avc_ss_reset(seqno);
		selnl_notify_policyload(seqno);
2905
		selinux_status_update_policyload(state, seqno);
2906
		selinux_xfrm_notify_policyload();
L
Linus Torvalds 已提交
2907 2908 2909 2910
	}
	return rc;
}

2911 2912
int security_get_bool_value(struct selinux_state *state,
			    int index)
L
Linus Torvalds 已提交
2913
{
2914
	struct policydb *policydb;
2915
	int rc;
L
Linus Torvalds 已提交
2916 2917
	int len;

2918 2919 2920
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
L
Linus Torvalds 已提交
2921

2922
	rc = -EFAULT;
2923
	len = policydb->p_bools.nprim;
2924
	if (index >= len)
L
Linus Torvalds 已提交
2925 2926
		goto out;

2927
	rc = policydb->bool_val_to_struct[index]->state;
L
Linus Torvalds 已提交
2928
out:
2929
	read_unlock(&state->ss->policy_rwlock);
L
Linus Torvalds 已提交
2930 2931
	return rc;
}
2932

2933 2934
static int security_preserve_bools(struct selinux_state *state,
				   struct policydb *policydb)
2935 2936 2937 2938 2939 2940
{
	int rc, nbools = 0, *bvalues = NULL, i;
	char **bnames = NULL;
	struct cond_bool_datum *booldatum;
	struct cond_node *cur;

2941
	rc = security_get_bools(state, &nbools, &bnames, &bvalues);
2942 2943 2944
	if (rc)
		goto out;
	for (i = 0; i < nbools; i++) {
2945
		booldatum = hashtab_search(policydb->p_bools.table, bnames[i]);
2946 2947 2948
		if (booldatum)
			booldatum->state = bvalues[i];
	}
2949 2950
	for (cur = policydb->cond_list; cur; cur = cur->next) {
		rc = evaluate_cond_node(policydb, cur);
2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964
		if (rc)
			goto out;
	}

out:
	if (bnames) {
		for (i = 0; i < nbools; i++)
			kfree(bnames[i]);
	}
	kfree(bnames);
	kfree(bvalues);
	return rc;
}

2965 2966 2967 2968
/*
 * security_sid_mls_copy() - computes a new sid based on the given
 * sid and the mls portion of mls_sid.
 */
2969 2970
int security_sid_mls_copy(struct selinux_state *state,
			  u32 sid, u32 mls_sid, u32 *new_sid)
2971
{
2972 2973
	struct policydb *policydb = &state->ss->policydb;
	struct sidtab *sidtab = &state->ss->sidtab;
2974 2975 2976 2977 2978
	struct context *context1;
	struct context *context2;
	struct context newcon;
	char *s;
	u32 len;
2979
	int rc;
2980

2981
	rc = 0;
2982
	if (!state->initialized || !policydb->mls_enabled) {
2983 2984 2985 2986 2987 2988
		*new_sid = sid;
		goto out;
	}

	context_init(&newcon);

2989
	read_lock(&state->ss->policy_rwlock);
2990 2991

	rc = -EINVAL;
2992
	context1 = sidtab_search(sidtab, sid);
2993
	if (!context1) {
E
Eric Paris 已提交
2994 2995
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
			__func__, sid);
2996 2997 2998
		goto out_unlock;
	}

2999
	rc = -EINVAL;
3000
	context2 = sidtab_search(sidtab, mls_sid);
3001
	if (!context2) {
E
Eric Paris 已提交
3002 3003
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
			__func__, mls_sid);
3004 3005 3006 3007 3008 3009
		goto out_unlock;
	}

	newcon.user = context1->user;
	newcon.role = context1->role;
	newcon.type = context1->type;
3010
	rc = mls_context_cpy(&newcon, context2);
3011 3012 3013 3014
	if (rc)
		goto out_unlock;

	/* Check the validity of the new context. */
3015 3016
	if (!policydb_context_isvalid(policydb, &newcon)) {
		rc = convert_context_handle_invalid_context(state, &newcon);
3017
		if (rc) {
3018 3019
			if (!context_struct_to_string(policydb, &newcon, &s,
						      &len)) {
3020 3021 3022 3023
				audit_log(current->audit_context,
					  GFP_ATOMIC, AUDIT_SELINUX_ERR,
					  "op=security_sid_mls_copy "
					  "invalid_context=%s", s);
3024 3025 3026 3027
				kfree(s);
			}
			goto out_unlock;
		}
3028 3029
	}

3030
	rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
3031
out_unlock:
3032
	read_unlock(&state->ss->policy_rwlock);
3033 3034 3035 3036 3037
	context_destroy(&newcon);
out:
	return rc;
}

3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057
/**
 * security_net_peersid_resolve - Compare and resolve two network peer SIDs
 * @nlbl_sid: NetLabel SID
 * @nlbl_type: NetLabel labeling protocol type
 * @xfrm_sid: XFRM SID
 *
 * Description:
 * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
 * resolved into a single SID it is returned via @peer_sid and the function
 * returns zero.  Otherwise @peer_sid is set to SECSID_NULL and the function
 * returns a negative value.  A table summarizing the behavior is below:
 *
 *                                 | function return |      @sid
 *   ------------------------------+-----------------+-----------------
 *   no peer labels                |        0        |    SECSID_NULL
 *   single peer label             |        0        |    <peer_label>
 *   multiple, consistent labels   |        0        |    <peer_label>
 *   multiple, inconsistent labels |    -<errno>     |    SECSID_NULL
 *
 */
3058 3059
int security_net_peersid_resolve(struct selinux_state *state,
				 u32 nlbl_sid, u32 nlbl_type,
3060 3061 3062
				 u32 xfrm_sid,
				 u32 *peer_sid)
{
3063 3064
	struct policydb *policydb = &state->ss->policydb;
	struct sidtab *sidtab = &state->ss->sidtab;
3065 3066 3067 3068
	int rc;
	struct context *nlbl_ctx;
	struct context *xfrm_ctx;

3069 3070
	*peer_sid = SECSID_NULL;

3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085
	/* handle the common (which also happens to be the set of easy) cases
	 * right away, these two if statements catch everything involving a
	 * single or absent peer SID/label */
	if (xfrm_sid == SECSID_NULL) {
		*peer_sid = nlbl_sid;
		return 0;
	}
	/* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
	 * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
	 * is present */
	if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
		*peer_sid = xfrm_sid;
		return 0;
	}

3086 3087
	/*
	 * We don't need to check initialized here since the only way both
3088
	 * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
3089 3090 3091
	 * security server was initialized and state->initialized was true.
	 */
	if (!policydb->mls_enabled)
3092 3093
		return 0;

3094
	read_lock(&state->ss->policy_rwlock);
3095

3096
	rc = -EINVAL;
3097
	nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
3098
	if (!nlbl_ctx) {
E
Eric Paris 已提交
3099 3100
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
		       __func__, nlbl_sid);
3101
		goto out;
3102
	}
3103
	rc = -EINVAL;
3104
	xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
3105
	if (!xfrm_ctx) {
E
Eric Paris 已提交
3106 3107
		printk(KERN_ERR "SELinux: %s:  unrecognized SID %d\n",
		       __func__, xfrm_sid);
3108
		goto out;
3109 3110
	}
	rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
3111 3112
	if (rc)
		goto out;
3113

3114 3115 3116 3117 3118 3119 3120
	/* at present NetLabel SIDs/labels really only carry MLS
	 * information so if the MLS portion of the NetLabel SID
	 * matches the MLS portion of the labeled XFRM SID/label
	 * then pass along the XFRM SID as it is the most
	 * expressive */
	*peer_sid = xfrm_sid;
out:
3121
	read_unlock(&state->ss->policy_rwlock);
3122 3123 3124
	return rc;
}

3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137
static int get_classes_callback(void *k, void *d, void *args)
{
	struct class_datum *datum = d;
	char *name = k, **classes = args;
	int value = datum->value - 1;

	classes[value] = kstrdup(name, GFP_ATOMIC);
	if (!classes[value])
		return -ENOMEM;

	return 0;
}

3138 3139
int security_get_classes(struct selinux_state *state,
			 char ***classes, int *nclasses)
3140
{
3141
	struct policydb *policydb = &state->ss->policydb;
3142
	int rc;
3143

3144
	read_lock(&state->ss->policy_rwlock);
3145

3146
	rc = -ENOMEM;
3147
	*nclasses = policydb->p_classes.nprim;
3148
	*classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
3149 3150 3151
	if (!*classes)
		goto out;

3152
	rc = hashtab_map(policydb->p_classes.table, get_classes_callback,
3153
			*classes);
3154
	if (rc) {
3155 3156 3157 3158 3159 3160 3161
		int i;
		for (i = 0; i < *nclasses; i++)
			kfree((*classes)[i]);
		kfree(*classes);
	}

out:
3162
	read_unlock(&state->ss->policy_rwlock);
3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178
	return rc;
}

static int get_permissions_callback(void *k, void *d, void *args)
{
	struct perm_datum *datum = d;
	char *name = k, **perms = args;
	int value = datum->value - 1;

	perms[value] = kstrdup(name, GFP_ATOMIC);
	if (!perms[value])
		return -ENOMEM;

	return 0;
}

3179 3180
int security_get_permissions(struct selinux_state *state,
			     char *class, char ***perms, int *nperms)
3181
{
3182
	struct policydb *policydb = &state->ss->policydb;
3183
	int rc, i;
3184 3185
	struct class_datum *match;

3186
	read_lock(&state->ss->policy_rwlock);
3187

3188
	rc = -EINVAL;
3189
	match = hashtab_search(policydb->p_classes.table, class);
3190
	if (!match) {
E
Eric Paris 已提交
3191
		printk(KERN_ERR "SELinux: %s:  unrecognized class %s\n",
3192
			__func__, class);
3193 3194 3195
		goto out;
	}

3196
	rc = -ENOMEM;
3197
	*nperms = match->permissions.nprim;
3198
	*perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
3199 3200 3201 3202 3203 3204
	if (!*perms)
		goto out;

	if (match->comdatum) {
		rc = hashtab_map(match->comdatum->permissions.table,
				get_permissions_callback, *perms);
3205
		if (rc)
3206 3207 3208 3209 3210
			goto err;
	}

	rc = hashtab_map(match->permissions.table, get_permissions_callback,
			*perms);
3211
	if (rc)
3212 3213 3214
		goto err;

out:
3215
	read_unlock(&state->ss->policy_rwlock);
3216 3217 3218
	return rc;

err:
3219
	read_unlock(&state->ss->policy_rwlock);
3220 3221 3222 3223 3224 3225
	for (i = 0; i < *nperms; i++)
		kfree((*perms)[i]);
	kfree(*perms);
	return rc;
}

3226
int security_get_reject_unknown(struct selinux_state *state)
3227
{
3228
	return state->ss->policydb.reject_unknown;
3229 3230
}

3231
int security_get_allow_unknown(struct selinux_state *state)
3232
{
3233
	return state->ss->policydb.allow_unknown;
3234 3235
}

3236 3237 3238 3239 3240 3241 3242 3243 3244 3245
/**
 * security_policycap_supported - Check for a specific policy capability
 * @req_cap: capability
 *
 * Description:
 * This function queries the currently loaded policy to see if it supports the
 * capability specified by @req_cap.  Returns true (1) if the capability is
 * supported, false (0) if it isn't supported.
 *
 */
3246 3247
int security_policycap_supported(struct selinux_state *state,
				 unsigned int req_cap)
3248
{
3249
	struct policydb *policydb = &state->ss->policydb;
3250 3251
	int rc;

3252 3253 3254
	read_lock(&state->ss->policy_rwlock);
	rc = ebitmap_get_bit(&policydb->policycaps, req_cap);
	read_unlock(&state->ss->policy_rwlock);
3255 3256 3257 3258

	return rc;
}

3259 3260 3261 3262 3263
struct selinux_audit_rule {
	u32 au_seqno;
	struct context au_ctxt;
};

3264
void selinux_audit_rule_free(void *vrule)
3265
{
3266 3267
	struct selinux_audit_rule *rule = vrule;

3268 3269 3270 3271 3272 3273
	if (rule) {
		context_destroy(&rule->au_ctxt);
		kfree(rule);
	}
}

3274
int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
3275
{
3276 3277
	struct selinux_state *state = &selinux_state;
	struct policydb *policydb = &state->ss->policydb;
3278 3279 3280 3281
	struct selinux_audit_rule *tmprule;
	struct role_datum *roledatum;
	struct type_datum *typedatum;
	struct user_datum *userdatum;
3282
	struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
3283 3284 3285 3286
	int rc = 0;

	*rule = NULL;

3287
	if (!state->initialized)
3288
		return -EOPNOTSUPP;
3289 3290

	switch (field) {
3291 3292 3293
	case AUDIT_SUBJ_USER:
	case AUDIT_SUBJ_ROLE:
	case AUDIT_SUBJ_TYPE:
3294 3295 3296
	case AUDIT_OBJ_USER:
	case AUDIT_OBJ_ROLE:
	case AUDIT_OBJ_TYPE:
3297
		/* only 'equals' and 'not equals' fit user, role, and type */
3298
		if (op != Audit_equal && op != Audit_not_equal)
3299 3300
			return -EINVAL;
		break;
3301 3302
	case AUDIT_SUBJ_SEN:
	case AUDIT_SUBJ_CLR:
3303 3304
	case AUDIT_OBJ_LEV_LOW:
	case AUDIT_OBJ_LEV_HIGH:
L
Lucas De Marchi 已提交
3305
		/* we do not allow a range, indicated by the presence of '-' */
3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319
		if (strchr(rulestr, '-'))
			return -EINVAL;
		break;
	default:
		/* only the above fields are valid */
		return -EINVAL;
	}

	tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
	if (!tmprule)
		return -ENOMEM;

	context_init(&tmprule->au_ctxt);

3320
	read_lock(&state->ss->policy_rwlock);
3321

3322
	tmprule->au_seqno = state->ss->latest_granting;
3323 3324

	switch (field) {
3325
	case AUDIT_SUBJ_USER:
3326
	case AUDIT_OBJ_USER:
3327
		rc = -EINVAL;
3328
		userdatum = hashtab_search(policydb->p_users.table, rulestr);
3329
		if (!userdatum)
3330 3331
			goto out;
		tmprule->au_ctxt.user = userdatum->value;
3332
		break;
3333
	case AUDIT_SUBJ_ROLE:
3334
	case AUDIT_OBJ_ROLE:
3335
		rc = -EINVAL;
3336
		roledatum = hashtab_search(policydb->p_roles.table, rulestr);
3337
		if (!roledatum)
3338 3339
			goto out;
		tmprule->au_ctxt.role = roledatum->value;
3340
		break;
3341
	case AUDIT_SUBJ_TYPE:
3342
	case AUDIT_OBJ_TYPE:
3343
		rc = -EINVAL;
3344
		typedatum = hashtab_search(policydb->p_types.table, rulestr);
3345
		if (!typedatum)
3346 3347
			goto out;
		tmprule->au_ctxt.type = typedatum->value;
3348
		break;
3349 3350
	case AUDIT_SUBJ_SEN:
	case AUDIT_SUBJ_CLR:
3351 3352
	case AUDIT_OBJ_LEV_LOW:
	case AUDIT_OBJ_LEV_HIGH:
3353 3354
		rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
				     GFP_ATOMIC);
3355 3356
		if (rc)
			goto out;
3357 3358
		break;
	}
3359 3360
	rc = 0;
out:
3361
	read_unlock(&state->ss->policy_rwlock);
3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372

	if (rc) {
		selinux_audit_rule_free(tmprule);
		tmprule = NULL;
	}

	*rule = tmprule;

	return rc;
}

3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398
/* Check to see if the rule contains any selinux fields */
int selinux_audit_rule_known(struct audit_krule *rule)
{
	int i;

	for (i = 0; i < rule->field_count; i++) {
		struct audit_field *f = &rule->fields[i];
		switch (f->type) {
		case AUDIT_SUBJ_USER:
		case AUDIT_SUBJ_ROLE:
		case AUDIT_SUBJ_TYPE:
		case AUDIT_SUBJ_SEN:
		case AUDIT_SUBJ_CLR:
		case AUDIT_OBJ_USER:
		case AUDIT_OBJ_ROLE:
		case AUDIT_OBJ_TYPE:
		case AUDIT_OBJ_LEV_LOW:
		case AUDIT_OBJ_LEV_HIGH:
			return 1;
		}
	}

	return 0;
}

int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,
3399
			     struct audit_context *actx)
3400
{
3401
	struct selinux_state *state = &selinux_state;
3402 3403
	struct context *ctxt;
	struct mls_level *level;
3404
	struct selinux_audit_rule *rule = vrule;
3405 3406
	int match = 0;

3407 3408
	if (unlikely(!rule)) {
		WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
3409 3410 3411
		return -ENOENT;
	}

3412
	read_lock(&state->ss->policy_rwlock);
3413

3414
	if (rule->au_seqno < state->ss->latest_granting) {
3415 3416 3417 3418
		match = -ESTALE;
		goto out;
	}

3419
	ctxt = sidtab_search(&state->ss->sidtab, sid);
3420 3421
	if (unlikely(!ctxt)) {
		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
3422
			  sid);
3423 3424 3425 3426 3427 3428 3429
		match = -ENOENT;
		goto out;
	}

	/* a field/op pair that is not caught here will simply fall through
	   without a match */
	switch (field) {
3430
	case AUDIT_SUBJ_USER:
3431
	case AUDIT_OBJ_USER:
3432
		switch (op) {
3433
		case Audit_equal:
3434 3435
			match = (ctxt->user == rule->au_ctxt.user);
			break;
3436
		case Audit_not_equal:
3437 3438 3439 3440
			match = (ctxt->user != rule->au_ctxt.user);
			break;
		}
		break;
3441
	case AUDIT_SUBJ_ROLE:
3442
	case AUDIT_OBJ_ROLE:
3443
		switch (op) {
3444
		case Audit_equal:
3445 3446
			match = (ctxt->role == rule->au_ctxt.role);
			break;
3447
		case Audit_not_equal:
3448 3449 3450 3451
			match = (ctxt->role != rule->au_ctxt.role);
			break;
		}
		break;
3452
	case AUDIT_SUBJ_TYPE:
3453
	case AUDIT_OBJ_TYPE:
3454
		switch (op) {
3455
		case Audit_equal:
3456 3457
			match = (ctxt->type == rule->au_ctxt.type);
			break;
3458
		case Audit_not_equal:
3459 3460 3461 3462
			match = (ctxt->type != rule->au_ctxt.type);
			break;
		}
		break;
3463 3464
	case AUDIT_SUBJ_SEN:
	case AUDIT_SUBJ_CLR:
3465 3466 3467
	case AUDIT_OBJ_LEV_LOW:
	case AUDIT_OBJ_LEV_HIGH:
		level = ((field == AUDIT_SUBJ_SEN ||
3468 3469
			  field == AUDIT_OBJ_LEV_LOW) ?
			 &ctxt->range.level[0] : &ctxt->range.level[1]);
3470
		switch (op) {
3471
		case Audit_equal:
3472
			match = mls_level_eq(&rule->au_ctxt.range.level[0],
3473
					     level);
3474
			break;
3475
		case Audit_not_equal:
3476
			match = !mls_level_eq(&rule->au_ctxt.range.level[0],
3477
					      level);
3478
			break;
3479
		case Audit_lt:
3480
			match = (mls_level_dom(&rule->au_ctxt.range.level[0],
3481 3482 3483
					       level) &&
				 !mls_level_eq(&rule->au_ctxt.range.level[0],
					       level));
3484
			break;
3485
		case Audit_le:
3486
			match = mls_level_dom(&rule->au_ctxt.range.level[0],
3487
					      level);
3488
			break;
3489
		case Audit_gt:
3490
			match = (mls_level_dom(level,
3491 3492 3493
					      &rule->au_ctxt.range.level[0]) &&
				 !mls_level_eq(level,
					       &rule->au_ctxt.range.level[0]));
3494
			break;
3495
		case Audit_ge:
3496
			match = mls_level_dom(level,
3497
					      &rule->au_ctxt.range.level[0]);
3498 3499 3500 3501 3502
			break;
		}
	}

out:
3503
	read_unlock(&state->ss->policy_rwlock);
3504 3505 3506
	return match;
}

3507
static int (*aurule_callback)(void) = audit_update_lsm_rules;
3508

3509
static int aurule_avc_callback(u32 event)
3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521
{
	int err = 0;

	if (event == AVC_CALLBACK_RESET && aurule_callback)
		err = aurule_callback();
	return err;
}

static int __init aurule_init(void)
{
	int err;

3522
	err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
3523 3524 3525 3526 3527 3528 3529
	if (err)
		panic("avc_add_callback() failed, error %d\n", err);

	return err;
}
__initcall(aurule_init);

V
Venkat Yekkirala 已提交
3530 3531
#ifdef CONFIG_NETLABEL
/**
3532 3533
 * security_netlbl_cache_add - Add an entry to the NetLabel cache
 * @secattr: the NetLabel packet security attributes
3534
 * @sid: the SELinux SID
V
Venkat Yekkirala 已提交
3535 3536 3537
 *
 * Description:
 * Attempt to cache the context in @ctx, which was derived from the packet in
3538 3539
 * @skb, in the NetLabel subsystem cache.  This function assumes @secattr has
 * already been initialized.
V
Venkat Yekkirala 已提交
3540 3541
 *
 */
3542
static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
3543
				      u32 sid)
V
Venkat Yekkirala 已提交
3544
{
3545
	u32 *sid_cache;
V
Venkat Yekkirala 已提交
3546

3547 3548
	sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
	if (sid_cache == NULL)
3549
		return;
3550 3551 3552
	secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
	if (secattr->cache == NULL) {
		kfree(sid_cache);
3553
		return;
3554
	}
V
Venkat Yekkirala 已提交
3555

3556 3557 3558
	*sid_cache = sid;
	secattr->cache->free = kfree;
	secattr->cache->data = sid_cache;
3559
	secattr->flags |= NETLBL_SECATTR_CACHE;
V
Venkat Yekkirala 已提交
3560 3561 3562
}

/**
3563
 * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
V
Venkat Yekkirala 已提交
3564 3565 3566 3567
 * @secattr: the NetLabel packet security attributes
 * @sid: the SELinux SID
 *
 * Description:
3568
 * Convert the given NetLabel security attributes in @secattr into a
V
Venkat Yekkirala 已提交
3569
 * SELinux SID.  If the @secattr field does not contain a full SELinux
L
Lucas De Marchi 已提交
3570
 * SID/context then use SECINITSID_NETMSG as the foundation.  If possible the
3571 3572 3573 3574
 * 'cache' field of @secattr is set and the CACHE flag is set; this is to
 * allow the @secattr to be used by NetLabel to cache the secattr to SID
 * conversion for future lookups.  Returns zero on success, negative values on
 * failure.
V
Venkat Yekkirala 已提交
3575 3576
 *
 */
3577 3578
int security_netlbl_secattr_to_sid(struct selinux_state *state,
				   struct netlbl_lsm_secattr *secattr,
3579
				   u32 *sid)
V
Venkat Yekkirala 已提交
3580
{
3581 3582
	struct policydb *policydb = &state->ss->policydb;
	struct sidtab *sidtab = &state->ss->sidtab;
3583
	int rc;
V
Venkat Yekkirala 已提交
3584 3585
	struct context *ctx;
	struct context ctx_new;
3586

3587
	if (!state->initialized) {
3588 3589 3590
		*sid = SECSID_NULL;
		return 0;
	}
V
Venkat Yekkirala 已提交
3591

3592
	read_lock(&state->ss->policy_rwlock);
V
Venkat Yekkirala 已提交
3593

3594
	if (secattr->flags & NETLBL_SECATTR_CACHE)
3595
		*sid = *(u32 *)secattr->cache->data;
3596
	else if (secattr->flags & NETLBL_SECATTR_SECID)
3597
		*sid = secattr->attr.secid;
3598 3599
	else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
		rc = -EIDRM;
3600
		ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
V
Venkat Yekkirala 已提交
3601
		if (ctx == NULL)
3602
			goto out;
V
Venkat Yekkirala 已提交
3603

3604
		context_init(&ctx_new);
V
Venkat Yekkirala 已提交
3605 3606 3607
		ctx_new.user = ctx->user;
		ctx_new.role = ctx->role;
		ctx_new.type = ctx->type;
3608
		mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
3609
		if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
3610
			rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
3611 3612
			if (rc)
				goto out;
V
Venkat Yekkirala 已提交
3613
		}
3614
		rc = -EIDRM;
3615
		if (!mls_context_isvalid(policydb, &ctx_new))
3616
			goto out_free;
V
Venkat Yekkirala 已提交
3617

3618
		rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
3619 3620
		if (rc)
			goto out_free;
V
Venkat Yekkirala 已提交
3621

3622
		security_netlbl_cache_add(secattr, *sid);
3623

V
Venkat Yekkirala 已提交
3624
		ebitmap_destroy(&ctx_new.range.level[0].cat);
3625
	} else
3626
		*sid = SECSID_NULL;
V
Venkat Yekkirala 已提交
3627

3628
	read_unlock(&state->ss->policy_rwlock);
3629 3630
	return 0;
out_free:
V
Venkat Yekkirala 已提交
3631
	ebitmap_destroy(&ctx_new.range.level[0].cat);
3632
out:
3633
	read_unlock(&state->ss->policy_rwlock);
3634
	return rc;
V
Venkat Yekkirala 已提交
3635 3636 3637
}

/**
3638 3639 3640
 * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
 * @sid: the SELinux SID
 * @secattr: the NetLabel packet security attributes
V
Venkat Yekkirala 已提交
3641 3642
 *
 * Description:
3643 3644
 * Convert the given SELinux SID in @sid into a NetLabel security attribute.
 * Returns zero on success, negative values on failure.
V
Venkat Yekkirala 已提交
3645 3646
 *
 */
3647 3648
int security_netlbl_sid_to_secattr(struct selinux_state *state,
				   u32 sid, struct netlbl_lsm_secattr *secattr)
V
Venkat Yekkirala 已提交
3649
{
3650
	struct policydb *policydb = &state->ss->policydb;
3651
	int rc;
V
Venkat Yekkirala 已提交
3652 3653
	struct context *ctx;

3654
	if (!state->initialized)
V
Venkat Yekkirala 已提交
3655 3656
		return 0;

3657
	read_lock(&state->ss->policy_rwlock);
3658 3659

	rc = -ENOENT;
3660
	ctx = sidtab_search(&state->ss->sidtab, sid);
3661 3662 3663 3664
	if (ctx == NULL)
		goto out;

	rc = -ENOMEM;
3665
	secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
3666
				  GFP_ATOMIC);
3667 3668 3669
	if (secattr->domain == NULL)
		goto out;

3670 3671
	secattr->attr.secid = sid;
	secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
3672 3673
	mls_export_netlbl_lvl(policydb, ctx, secattr);
	rc = mls_export_netlbl_cat(policydb, ctx, secattr);
3674
out:
3675
	read_unlock(&state->ss->policy_rwlock);
3676 3677
	return rc;
}
V
Venkat Yekkirala 已提交
3678
#endif /* CONFIG_NETLABEL */
3679 3680 3681 3682 3683 3684 3685

/**
 * security_read_policy - read the policy.
 * @data: binary policy data
 * @len: length of data in bytes
 *
 */
3686 3687
int security_read_policy(struct selinux_state *state,
			 void **data, size_t *len)
3688
{
3689
	struct policydb *policydb = &state->ss->policydb;
3690 3691 3692
	int rc;
	struct policy_file fp;

3693
	if (!state->initialized)
3694 3695
		return -EINVAL;

3696
	*len = security_policydb_len(state);
3697

3698
	*data = vmalloc_user(*len);
3699 3700 3701 3702 3703 3704
	if (!*data)
		return -ENOMEM;

	fp.data = *data;
	fp.len = *len;

3705 3706 3707
	read_lock(&state->ss->policy_rwlock);
	rc = policydb_write(policydb, &fp);
	read_unlock(&state->ss->policy_rwlock);
3708 3709 3710 3711 3712 3713 3714 3715

	if (rc)
		return rc;

	*len = (unsigned long)fp.data - (unsigned long)*data;
	return 0;

}