services.c 87.3 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3
/*
 * Implementation of the security services.
 *
4
 * Authors : Stephen Smalley, <sds@tycho.nsa.gov>
5
 *	     James Morris <jmorris@redhat.com>
Linus Torvalds's avatar
Linus Torvalds committed
6 7 8 9
 *
 * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
 *
 *	Support for enhanced MLS infrastructure.
10
 *	Support for context based audit filters.
Linus Torvalds's avatar
Linus Torvalds committed
11 12 13
 *
 * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
 *
14
 *	Added conditional policy language extensions
Linus Torvalds's avatar
Linus Torvalds committed
15
 *
16
 * Updated: Hewlett-Packard <paul@paul-moore.com>
Venkat Yekkirala's avatar
Venkat Yekkirala committed
17 18
 *
 *      Added support for NetLabel
19
 *      Added support for the policy capability bitmap
Venkat Yekkirala's avatar
Venkat Yekkirala committed
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
Linus Torvalds's avatar
Linus Torvalds committed
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
Linus Torvalds's avatar
Linus Torvalds committed
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>
Paul Moore's avatar
Paul Moore committed
46
#include <linux/rcupdate.h>
Linus Torvalds's avatar
Linus Torvalds committed
47 48 49 50
#include <linux/errno.h>
#include <linux/in.h>
#include <linux/sched.h>
#include <linux/audit.h>
Ingo Molnar's avatar
Ingo Molnar committed
51
#include <linux/mutex.h>
52
#include <linux/selinux.h>
53
#include <linux/vmalloc.h>
Venkat Yekkirala's avatar
Venkat Yekkirala committed
54
#include <net/netlabel.h>
Ingo Molnar's avatar
Ingo Molnar committed
55

Linus Torvalds's avatar
Linus Torvalds committed
56 57 58 59 60 61 62 63 64 65
#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"
Venkat Yekkirala's avatar
Venkat Yekkirala committed
66
#include "objsec.h"
67
#include "netlabel.h"
68
#include "xfrm.h"
69
#include "ebitmap.h"
70
#include "audit.h"
Linus Torvalds's avatar
Linus Torvalds committed
71

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

82
static struct selinux_ss selinux_ss;
83

84 85 86 87 88 89
void selinux_ss_init(struct selinux_ss **ss)
{
	rwlock_init(&selinux_ss.policy_rwlock);
	mutex_init(&selinux_ss.status_lock);
	*ss = &selinux_ss;
}
Linus Torvalds's avatar
Linus Torvalds committed
90 91

/* Forward declaration. */
92 93 94
static int context_struct_to_string(struct policydb *policydb,
				    struct context *context,
				    char **scontext,
Linus Torvalds's avatar
Linus Torvalds committed
95 96
				    u32 *scontext_len);

97 98 99 100 101 102
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);
103 104 105

static int selinux_set_mapping(struct policydb *pol,
			       struct security_class_mapping *map,
106
			       struct selinux_map *out_map)
107 108 109 110 111 112 113 114 115 116 117 118 119
{
	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 */
120 121
	out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
	if (!out_map->mapping)
122 123 124 125 126 127
		return -ENOMEM;

	/* Store the raw class and permission values */
	j = 0;
	while (map[j].name) {
		struct security_class_mapping *p_in = map + (j++);
128
		struct selinux_mapping *p_out = out_map->mapping + j;
129 130 131 132 133 134 135 136 137

		/* 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) {
138
			pr_info("SELinux:  Class %s not defined in policy.\n",
139 140 141 142 143 144 145 146 147
			       p_in->name);
			if (pol->reject_unknown)
				goto err;
			p_out->num_perms = 0;
			print_unknown_handle = true;
			continue;
		}

		k = 0;
148
		while (p_in->perms[k]) {
149 150 151 152 153 154 155 156
			/* 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]) {
157
				pr_info("SELinux:  Permission %s in class %s not defined in policy.\n",
158 159 160 161 162 163 164 165 166 167 168 169
				       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)
170
		pr_info("SELinux: the above unknown classes and permissions will be %s\n",
171 172
		       pol->allow_unknown ? "allowed" : "denied");

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

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

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

	return tclass;
}

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

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

205
	return SECCLASS_NULL;
206 207
}

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

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

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

		for (i = 0, result = 0; i < n; i++) {
231
			if (avd->auditdeny & mapping->perms[i])
232
				result |= 1<<i;
233
			if (!allow_unknown && !mapping->perms[i])
234 235
				result |= 1<<i;
		}
236 237 238 239 240 241 242
		/*
		 * 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;
243 244 245 246
		avd->auditdeny = result;
	}
}

247
int security_mls_enabled(struct selinux_state *state)
248
{
249 250 251
	struct policydb *p = &state->ss->policydb;

	return p->mls_enabled;
252
}
253

Linus Torvalds's avatar
Linus Torvalds committed
254 255 256 257 258 259 260 261 262 263 264
/*
 * 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.
 */
265 266
static int constraint_expr_eval(struct policydb *policydb,
				struct context *scontext,
Linus Torvalds's avatar
Linus Torvalds committed
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
				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--;
288
			s[sp] &= s[sp + 1];
Linus Torvalds's avatar
Linus Torvalds committed
289 290 291 292
			break;
		case CEXPR_OR:
			BUG_ON(sp < 1);
			sp--;
293
			s[sp] |= s[sp + 1];
Linus Torvalds's avatar
Linus Torvalds committed
294 295
			break;
		case CEXPR_ATTR:
296
			if (sp == (CEXPR_MAXDEPTH - 1))
Linus Torvalds's avatar
Linus Torvalds committed
297 298 299 300 301 302 303 304 305 306 307 308 309
				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;
310 311
				r1 = policydb->role_val_to_struct[val1 - 1];
				r2 = policydb->role_val_to_struct[val2 - 1];
Linus Torvalds's avatar
Linus Torvalds committed
312 313 314 315 316 317 318 319 320 321
				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:
322 323 324 325
					s[++sp] = (!ebitmap_get_bit(&r1->dominates,
								    val2 - 1) &&
						   !ebitmap_get_bit(&r2->dominates,
								    val1 - 1));
Linus Torvalds's avatar
Linus Torvalds committed
326 327 328 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
					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];
}

440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
/*
 * 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;
}

456 457
static void security_dump_masked_av(struct policydb *policydb,
				    struct context *scontext,
458 459 460 461 462 463 464 465 466 467 468 469
				    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];
470 471
	int index;
	u32 length;
472 473 474 475 476
	bool need_comma = false;

	if (!permissions)
		return;

477 478
	tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1);
	tclass_dat = policydb->class_val_to_struct[tclass - 1];
479 480 481 482 483 484 485 486 487 488 489 490 491
	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 */
492
	if (context_struct_to_string(policydb, scontext,
493 494 495
				     &scontext_name, &length) < 0)
		goto out;

496
	if (context_struct_to_string(policydb, tcontext,
497 498 499 500
				     &tcontext_name, &length) < 0)
		goto out;

	/* audit a message */
501
	ab = audit_log_start(audit_context(),
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
			     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;
}

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

Kent Overstreet's avatar
Kent Overstreet committed
548
	source = policydb->type_val_to_struct_array[scontext->type - 1];
549 550
	BUG_ON(!source);

551 552 553
	if (!source->bounds)
		return;

Kent Overstreet's avatar
Kent Overstreet committed
554
	target = policydb->type_val_to_struct_array[tcontext->type - 1];
555 556
	BUG_ON(!target);

557
	memset(&lo_avd, 0, sizeof(lo_avd));
558

559 560
	memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
	lo_scontext.type = source->bounds;
561 562 563 564

	if (target->bounds) {
		memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
		lo_tcontext.type = target->bounds;
565
		tcontextp = &lo_tcontext;
566 567
	}

568
	context_struct_compute_av(policydb, &lo_scontext,
569 570 571 572
				  tcontextp,
				  tclass,
				  &lo_avd,
				  NULL);
573

574
	masked = ~lo_avd.allowed & avd->allowed;
575

576 577
	if (likely(!masked))
		return;		/* no masked permission */
578

579 580 581 582
	/* mask violated permissions */
	avd->allowed &= ~masked;

	/* audit masked permissions */
583
	security_dump_masked_av(policydb, scontext, tcontext,
584
				tclass, masked, "bounds");
585 586
}

Linus Torvalds's avatar
Linus Torvalds committed
587
/*
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
 * 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.
Linus Torvalds's avatar
Linus Torvalds committed
615
 */
616 617 618 619 620 621
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)
Linus Torvalds's avatar
Linus Torvalds committed
622 623 624 625
{
	struct constraint_node *constraint;
	struct role_allow *ra;
	struct avtab_key avkey;
626
	struct avtab_node *node;
Linus Torvalds's avatar
Linus Torvalds committed
627
	struct class_datum *tclass_datum;
628 629 630
	struct ebitmap *sattr, *tattr;
	struct ebitmap_node *snode, *tnode;
	unsigned int i, j;
Linus Torvalds's avatar
Linus Torvalds committed
631 632 633 634

	avd->allowed = 0;
	avd->auditallow = 0;
	avd->auditdeny = 0xffffffff;
635 636 637 638
	if (xperms) {
		memset(&xperms->drivers, 0, sizeof(xperms->drivers));
		xperms->len = 0;
	}
Linus Torvalds's avatar
Linus Torvalds committed
639

640
	if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
641
		if (printk_ratelimit())
642
			pr_warn("SELinux:  Invalid class %hu\n", tclass);
643
		return;
644
	}
645

646
	tclass_datum = policydb->class_val_to_struct[tclass - 1];
647

Linus Torvalds's avatar
Linus Torvalds committed
648 649 650 651 652
	/*
	 * If a specific type enforcement rule was defined for
	 * this permission check, then use it.
	 */
	avkey.target_class = tclass;
653
	avkey.specified = AVTAB_AV | AVTAB_XPERMS;
Kent Overstreet's avatar
Kent Overstreet committed
654
	sattr = &policydb->type_attr_map_array[scontext->type - 1];
655
	BUG_ON(!sattr);
Kent Overstreet's avatar
Kent Overstreet committed
656
	tattr = &policydb->type_attr_map_array[tcontext->type - 1];
657
	BUG_ON(!tattr);
658 659
	ebitmap_for_each_positive_bit(sattr, snode, i) {
		ebitmap_for_each_positive_bit(tattr, tnode, j) {
660 661
			avkey.source_type = i + 1;
			avkey.target_type = j + 1;
662 663
			for (node = avtab_search_node(&policydb->te_avtab,
						      &avkey);
664
			     node;
665 666
			     node = avtab_search_node_next(node, avkey.specified)) {
				if (node->key.specified == AVTAB_ALLOWED)
667
					avd->allowed |= node->datum.u.data;
668
				else if (node->key.specified == AVTAB_AUDITALLOW)
669
					avd->auditallow |= node->datum.u.data;
670
				else if (node->key.specified == AVTAB_AUDITDENY)
671 672 673
					avd->auditdeny &= node->datum.u.data;
				else if (xperms && (node->key.specified & AVTAB_XPERMS))
					services_compute_xperms_drivers(xperms, node);
674
			}
Linus Torvalds's avatar
Linus Torvalds committed
675

676
			/* Check conditional av table for additional permissions */
677
			cond_compute_av(&policydb->te_cond_avtab, &avkey,
678
					avd, xperms);
679 680 681

		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
682 683 684 685 686 687 688 689

	/*
	 * Remove any permissions prohibited by a constraint (this includes
	 * the MLS policy).
	 */
	constraint = tclass_datum->constraints;
	while (constraint) {
		if ((constraint->permissions & (avd->allowed)) &&
690
		    !constraint_expr_eval(policydb, scontext, tcontext, NULL,
Linus Torvalds's avatar
Linus Torvalds committed
691
					  constraint->expr)) {
KaiGai Kohei's avatar
KaiGai Kohei committed
692
			avd->allowed &= ~(constraint->permissions);
Linus Torvalds's avatar
Linus Torvalds committed
693 694 695 696 697 698 699 700 701
		}
		constraint = constraint->next;
	}

	/*
	 * If checking process transition permission and the
	 * role is changing, then check the (current_role, new_role)
	 * pair.
	 */
702 703
	if (tclass == policydb->process_class &&
	    (avd->allowed & policydb->process_trans_perms) &&
Linus Torvalds's avatar
Linus Torvalds committed
704
	    scontext->role != tcontext->role) {
705
		for (ra = policydb->role_allow; ra; ra = ra->next) {
Linus Torvalds's avatar
Linus Torvalds committed
706 707 708 709 710
			if (scontext->role == ra->role &&
			    tcontext->role == ra->new_role)
				break;
		}
		if (!ra)
711
			avd->allowed &= ~policydb->process_trans_perms;
Linus Torvalds's avatar
Linus Torvalds committed
712 713
	}

714 715 716 717 718
	/*
	 * 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.
	 */
719
	type_attribute_bounds_av(policydb, scontext, tcontext,
720
				 tclass, avd);
Linus Torvalds's avatar
Linus Torvalds committed
721 722
}

723 724
static int security_validtrans_handle_fail(struct selinux_state *state,
					   struct context *ocontext,
725 726 727
					   struct context *ncontext,
					   struct context *tcontext,
					   u16 tclass)
Linus Torvalds's avatar
Linus Torvalds committed
728
{
729
	struct policydb *p = &state->ss->policydb;
Linus Torvalds's avatar
Linus Torvalds committed
730 731 732
	char *o = NULL, *n = NULL, *t = NULL;
	u32 olen, nlen, tlen;

733
	if (context_struct_to_string(p, ocontext, &o, &olen))
Linus Torvalds's avatar
Linus Torvalds committed
734
		goto out;
735
	if (context_struct_to_string(p, ncontext, &n, &nlen))
Linus Torvalds's avatar
Linus Torvalds committed
736
		goto out;
737
	if (context_struct_to_string(p, tcontext, &t, &tlen))
Linus Torvalds's avatar
Linus Torvalds committed
738
		goto out;
739
	audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR,
740
		  "op=security_validate_transition seresult=denied"
741
		  " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
742
		  o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
Linus Torvalds's avatar
Linus Torvalds committed
743 744 745 746 747
out:
	kfree(o);
	kfree(n);
	kfree(t);

748
	if (!enforcing_enabled(state))
Linus Torvalds's avatar
Linus Torvalds committed
749 750 751 752
		return 0;
	return -EPERM;
}

753 754
static int security_compute_validatetrans(struct selinux_state *state,
					  u32 oldsid, u32 newsid, u32 tasksid,
755
					  u16 orig_tclass, bool user)
Linus Torvalds's avatar
Linus Torvalds committed
756
{
757 758
	struct policydb *policydb;
	struct sidtab *sidtab;
Linus Torvalds's avatar
Linus Torvalds committed
759 760 761 762 763
	struct context *ocontext;
	struct context *ncontext;
	struct context *tcontext;
	struct class_datum *tclass_datum;
	struct constraint_node *constraint;
764
	u16 tclass;
Linus Torvalds's avatar
Linus Torvalds committed
765 766
	int rc = 0;

767 768

	if (!state->initialized)
Linus Torvalds's avatar
Linus Torvalds committed
769 770
		return 0;

771 772 773
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
774
	sidtab = state->ss->sidtab;
Linus Torvalds's avatar
Linus Torvalds committed
775

776
	if (!user)
777
		tclass = unmap_class(&state->ss->map, orig_tclass);
778 779
	else
		tclass = orig_tclass;
780

781
	if (!tclass || tclass > policydb->p_classes.nprim) {
Linus Torvalds's avatar
Linus Torvalds committed
782 783 784
		rc = -EINVAL;
		goto out;
	}
785
	tclass_datum = policydb->class_val_to_struct[tclass - 1];
Linus Torvalds's avatar
Linus Torvalds committed
786

787
	ocontext = sidtab_search(sidtab, oldsid);
Linus Torvalds's avatar
Linus Torvalds committed
788
	if (!ocontext) {
789
		pr_err("SELinux: %s:  unrecognized SID %d\n",
Eric Paris's avatar
Eric Paris committed
790
			__func__, oldsid);
Linus Torvalds's avatar
Linus Torvalds committed
791 792 793 794
		rc = -EINVAL;
		goto out;
	}

795
	ncontext = sidtab_search(sidtab, newsid);
Linus Torvalds's avatar
Linus Torvalds committed
796
	if (!ncontext) {
797
		pr_err("SELinux: %s:  unrecognized SID %d\n",
Eric Paris's avatar
Eric Paris committed
798
			__func__, newsid);
Linus Torvalds's avatar
Linus Torvalds committed
799 800 801 802
		rc = -EINVAL;
		goto out;
	}

803
	tcontext = sidtab_search(sidtab, tasksid);
Linus Torvalds's avatar
Linus Torvalds committed
804
	if (!tcontext) {
805
		pr_err("SELinux: %s:  unrecognized SID %d\n",
Eric Paris's avatar
Eric Paris committed
806
			__func__, tasksid);
Linus Torvalds's avatar
Linus Torvalds committed
807 808 809 810 811 812
		rc = -EINVAL;
		goto out;
	}

	constraint = tclass_datum->validatetrans;
	while (constraint) {
813 814
		if (!constraint_expr_eval(policydb, ocontext, ncontext,
					  tcontext, constraint->expr)) {
815 816 817
			if (user)
				rc = -EPERM;
			else
818 819
				rc = security_validtrans_handle_fail(state,
								     ocontext,
820 821 822
								     ncontext,
								     tcontext,
								     tclass);
Linus Torvalds's avatar
Linus Torvalds committed
823 824 825 826 827 828
			goto out;
		}
		constraint = constraint->next;
	}

out:
829
	read_unlock(&state->ss->policy_rwlock);
Linus Torvalds's avatar
Linus Torvalds committed
830 831 832
	return rc;
}

833 834 835
int security_validate_transition_user(struct selinux_state *state,
				      u32 oldsid, u32 newsid, u32 tasksid,
				      u16 tclass)
836
{
837 838
	return security_compute_validatetrans(state, oldsid, newsid, tasksid,
					      tclass, true);
839 840
}

841 842
int security_validate_transition(struct selinux_state *state,
				 u32 oldsid, u32 newsid, u32 tasksid,
843 844
				 u16 orig_tclass)
{
845 846
	return security_compute_validatetrans(state, oldsid, newsid, tasksid,
					      orig_tclass, false);
847 848
}

849 850 851 852 853 854 855 856 857
/*
 * 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
 */
858 859
int security_bounded_transition(struct selinux_state *state,
				u32 old_sid, u32 new_sid)
860
{
861 862
	struct policydb *policydb;
	struct sidtab *sidtab;
863 864 865
	struct context *old_context, *new_context;
	struct type_datum *type;
	int index;
866
	int rc;
867

868
	if (!state->initialized)
869 870
		return 0;

871 872 873
	read_lock(&state->ss->policy_rwlock);

	policydb = &state->ss->policydb;
874
	sidtab = state->ss->sidtab;
875

876
	rc = -EINVAL;
877
	old_context = sidtab_search(sidtab, old_sid);
878
	if (!old_context) {
879
		pr_err("SELinux: %s: unrecognized SID %u\n",
880 881 882 883
		       __func__, old_sid);
		goto out;
	}

884
	rc = -EINVAL;
885
	new_context = sidtab_search(sidtab, new_sid);
886
	if (!new_context) {
887
		pr_err("SELinux: %s: unrecognized SID %u\n",
888 889 890 891
		       __func__, new_sid);
		goto out;
	}

892
	rc = 0;
893
	/* type/domain unchanged */
894
	if (old_context->type == new_context->type)
895 896 897 898
		goto out;

	index = new_context->type;
	while (true) {
Kent Overstreet's avatar
Kent Overstreet committed
899
		type = policydb->type_val_to_struct_array[index - 1];
900 901 902
		BUG_ON(!type);

		/* not bounded anymore */
903 904
		rc = -EPERM;
		if (!type->bounds)
905 906 907
			break;

		/* @newsid is bounded by @oldsid */
908 909
		rc = 0;
		if (type->bounds == old_context->type)
910
			break;
911

912 913
		index = type->bounds;
	}
914 915 916 917

	if (rc) {
		char *old_name = NULL;
		char *new_name = NULL;
918
		u32 length;
919

920
		if (!context_struct_to_string(policydb, old_context,
921
					      &old_name, &length) &&
922
		    !context_struct_to_string(policydb, new_context,
923
					      &new_name, &length)) {
924
			audit_log(audit_context(),
925 926
				  GFP_ATOMIC, AUDIT_SELINUX_ERR,
				  "op=security_bounded_transition "
927
				  "seresult=denied "
928 929 930 931 932 933
				  "oldcontext=%s newcontext=%s",
				  old_name, new_name);
		}
		kfree(new_name);
		kfree(old_name);
	}
934
out:
935
	read_unlock(&state->ss->policy_rwlock);
936 937 938 939

	return rc;
}

940
static void avd_init(struct selinux_state *state, struct av_decision *avd)
941
{
942 943 944
	avd->allowed = 0;
	avd->auditallow = 0;
	avd->auditdeny = 0xffffffff;
945
	avd->seqno = state->ss->latest_granting;
946
	avd->flags = 0;
947 948
}

949 950 951 952 953 954 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
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();
	}
}

1003 1004 1005 1006 1007 1008
void security_compute_xperms_decision(struct selinux_state *state,
				      u32 ssid,
				      u32 tsid,
				      u16 orig_tclass,
				      u8 driver,
				      struct extended_perms_decision *xpermd)
1009
{
1010 1011
	struct policydb *policydb;
	struct sidtab *sidtab;
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
	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));

1026 1027
	read_lock(&state->ss->policy_rwlock);
	if (!state->initialized)
1028 1029
		goto allow;

1030
	policydb = &state->ss->policydb;
1031
	sidtab = state->ss->sidtab;
1032 1033

	scontext = sidtab_search(sidtab, ssid);
1034
	if (!scontext) {
1035
		pr_err("SELinux: %s:  unrecognized SID %d\n",
1036 1037 1038 1039
		       __func__, ssid);
		goto out;
	}