avc.c 33.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * Implementation of the kernel access vector cache (AVC).
 *
4
 * Authors:  Stephen Smalley, <sds@tycho.nsa.gov>
5
 *	     James Morris <jmorris@redhat.com>
L
Linus Torvalds 已提交
6 7
 *
 * Update:   KaiGai, Kohei <kaigai@ak.jp.nec.com>
8
 *	Replaced the avc_lock spinlock by RCU.
L
Linus Torvalds 已提交
9 10 11 12 13
 *
 * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License version 2,
14
 *	as published by the Free Software Foundation.
L
Linus Torvalds 已提交
15 16 17 18 19 20 21 22 23 24
 */
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/dcache.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/percpu.h>
25
#include <linux/list.h>
L
Linus Torvalds 已提交
26 27 28 29 30 31 32 33 34
#include <net/sock.h>
#include <linux/un.h>
#include <net/af_unix.h>
#include <linux/ip.h>
#include <linux/audit.h>
#include <linux/ipv6.h>
#include <net/ipv6.h>
#include "avc.h"
#include "avc_ss.h"
35
#include "classmap.h"
36

L
Linus Torvalds 已提交
37 38 39 40 41
#define AVC_CACHE_SLOTS			512
#define AVC_DEF_CACHE_THRESHOLD		512
#define AVC_CACHE_RECLAIM		16

#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
42
#define avc_cache_stats_incr(field)	this_cpu_inc(avc_cache_stats.field)
L
Linus Torvalds 已提交
43 44 45 46 47 48 49 50 51
#else
#define avc_cache_stats_incr(field)	do {} while (0)
#endif

struct avc_entry {
	u32			ssid;
	u32			tsid;
	u16			tclass;
	struct av_decision	avd;
52
	struct avc_xperms_node	*xp_node;
L
Linus Torvalds 已提交
53 54 55 56
};

struct avc_node {
	struct avc_entry	ae;
57
	struct hlist_node	list; /* anchored in avc_cache->slots[i] */
58
	struct rcu_head		rhead;
L
Linus Torvalds 已提交
59 60
};

61 62 63 64 65 66 67 68 69 70
struct avc_xperms_decision_node {
	struct extended_perms_decision xpd;
	struct list_head xpd_list; /* list of extended_perms_decision */
};

struct avc_xperms_node {
	struct extended_perms xp;
	struct list_head xpd_head; /* list head of extended_perms_decision */
};

L
Linus Torvalds 已提交
71
struct avc_cache {
72
	struct hlist_head	slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */
L
Linus Torvalds 已提交
73 74 75 76 77 78 79
	spinlock_t		slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */
	atomic_t		lru_hint;	/* LRU hint for reclaim scan */
	atomic_t		active_nodes;
	u32			latest_notif;	/* latest revocation notification */
};

struct avc_callback_node {
80
	int (*callback) (u32 event);
L
Linus Torvalds 已提交
81 82 83 84 85 86 87 88
	u32 events;
	struct avc_callback_node *next;
};

#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 };
#endif

S
Stephen Smalley 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
struct selinux_avc {
	unsigned int avc_cache_threshold;
	struct avc_cache avc_cache;
};

static struct selinux_avc selinux_avc;

void selinux_avc_init(struct selinux_avc **avc)
{
	int i;

	selinux_avc.avc_cache_threshold = AVC_DEF_CACHE_THRESHOLD;
	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
		INIT_HLIST_HEAD(&selinux_avc.avc_cache.slots[i]);
		spin_lock_init(&selinux_avc.avc_cache.slots_lock[i]);
	}
	atomic_set(&selinux_avc.avc_cache.active_nodes, 0);
	atomic_set(&selinux_avc.avc_cache.lru_hint, 0);
	*avc = &selinux_avc;
}

unsigned int avc_get_cache_threshold(struct selinux_avc *avc)
{
	return avc->avc_cache_threshold;
}

void avc_set_cache_threshold(struct selinux_avc *avc,
			     unsigned int cache_threshold)
{
	avc->avc_cache_threshold = cache_threshold;
}

L
Linus Torvalds 已提交
121
static struct avc_callback_node *avc_callbacks;
122
static struct kmem_cache *avc_node_cachep;
123 124 125
static struct kmem_cache *avc_xperms_data_cachep;
static struct kmem_cache *avc_xperms_decision_cachep;
static struct kmem_cache *avc_xperms_cachep;
L
Linus Torvalds 已提交
126 127 128 129 130 131 132 133 134 135 136

static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass)
{
	return (ssid ^ (tsid<<2) ^ (tclass<<4)) & (AVC_CACHE_SLOTS - 1);
}

/**
 * avc_dump_av - Display an access vector in human-readable form.
 * @tclass: target security class
 * @av: access vector
 */
137
static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av)
L
Linus Torvalds 已提交
138
{
139 140
	const char **perms;
	int i, perm;
L
Linus Torvalds 已提交
141 142 143 144 145 146

	if (av == 0) {
		audit_log_format(ab, " null");
		return;
	}

147
	BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map));
148
	perms = secclass_map[tclass-1].perms;
L
Linus Torvalds 已提交
149 150 151 152

	audit_log_format(ab, " {");
	i = 0;
	perm = 1;
153
	while (i < (sizeof(av) * 8)) {
154
		if ((perm & av) && perms[i]) {
155
			audit_log_format(ab, " %s", perms[i]);
L
Linus Torvalds 已提交
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
			av &= ~perm;
		}
		i++;
		perm <<= 1;
	}

	if (av)
		audit_log_format(ab, " 0x%x", av);

	audit_log_format(ab, " }");
}

/**
 * avc_dump_query - Display a SID pair and a class in human-readable form.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 */
S
Stephen Smalley 已提交
174 175
static void avc_dump_query(struct audit_buffer *ab, struct selinux_state *state,
			   u32 ssid, u32 tsid, u16 tclass)
L
Linus Torvalds 已提交
176 177 178 179 180
{
	int rc;
	char *scontext;
	u32 scontext_len;

S
Stephen Smalley 已提交
181
	rc = security_sid_to_context(state, ssid, &scontext, &scontext_len);
L
Linus Torvalds 已提交
182 183 184 185 186 187 188
	if (rc)
		audit_log_format(ab, "ssid=%d", ssid);
	else {
		audit_log_format(ab, "scontext=%s", scontext);
		kfree(scontext);
	}

S
Stephen Smalley 已提交
189
	rc = security_sid_to_context(state, tsid, &scontext, &scontext_len);
L
Linus Torvalds 已提交
190 191 192 193 194 195
	if (rc)
		audit_log_format(ab, " tsid=%d", tsid);
	else {
		audit_log_format(ab, " tcontext=%s", scontext);
		kfree(scontext);
	}
196

197
	BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map));
198
	audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name);
L
Linus Torvalds 已提交
199 200 201 202 203 204 205 206 207 208
}

/**
 * avc_init - Initialize the AVC.
 *
 * Initialize the access vector cache.
 */
void __init avc_init(void)
{
	avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node),
209 210 211 212 213 214 215 216 217 218 219
					0, SLAB_PANIC, NULL);
	avc_xperms_cachep = kmem_cache_create("avc_xperms_node",
					sizeof(struct avc_xperms_node),
					0, SLAB_PANIC, NULL);
	avc_xperms_decision_cachep = kmem_cache_create(
					"avc_xperms_decision_node",
					sizeof(struct avc_xperms_decision_node),
					0, SLAB_PANIC, NULL);
	avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data",
					sizeof(struct extended_perms_data),
					0, SLAB_PANIC, NULL);
L
Linus Torvalds 已提交
220 221
}

S
Stephen Smalley 已提交
222
int avc_get_hash_stats(struct selinux_avc *avc, char *page)
L
Linus Torvalds 已提交
223 224 225
{
	int i, chain_len, max_chain_len, slots_used;
	struct avc_node *node;
226
	struct hlist_head *head;
L
Linus Torvalds 已提交
227 228 229 230 231 232

	rcu_read_lock();

	slots_used = 0;
	max_chain_len = 0;
	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
S
Stephen Smalley 已提交
233
		head = &avc->avc_cache.slots[i];
234
		if (!hlist_empty(head)) {
L
Linus Torvalds 已提交
235 236
			slots_used++;
			chain_len = 0;
237
			hlist_for_each_entry_rcu(node, head, list)
L
Linus Torvalds 已提交
238 239 240 241 242 243 244 245 246 247
				chain_len++;
			if (chain_len > max_chain_len)
				max_chain_len = chain_len;
		}
	}

	rcu_read_unlock();

	return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
			 "longest chain: %d\n",
S
Stephen Smalley 已提交
248
			 atomic_read(&avc->avc_cache.active_nodes),
L
Linus Torvalds 已提交
249 250 251
			 slots_used, AVC_CACHE_SLOTS, max_chain_len);
}

252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 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
/*
 * using a linked list for extended_perms_decision lookup because the list is
 * always small. i.e. less than 5, typically 1
 */
static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver,
					struct avc_xperms_node *xp_node)
{
	struct avc_xperms_decision_node *xpd_node;

	list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) {
		if (xpd_node->xpd.driver == driver)
			return &xpd_node->xpd;
	}
	return NULL;
}

static inline unsigned int
avc_xperms_has_perm(struct extended_perms_decision *xpd,
					u8 perm, u8 which)
{
	unsigned int rc = 0;

	if ((which == XPERMS_ALLOWED) &&
			(xpd->used & XPERMS_ALLOWED))
		rc = security_xperm_test(xpd->allowed->p, perm);
	else if ((which == XPERMS_AUDITALLOW) &&
			(xpd->used & XPERMS_AUDITALLOW))
		rc = security_xperm_test(xpd->auditallow->p, perm);
	else if ((which == XPERMS_DONTAUDIT) &&
			(xpd->used & XPERMS_DONTAUDIT))
		rc = security_xperm_test(xpd->dontaudit->p, perm);
	return rc;
}

static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node,
				u8 driver, u8 perm)
{
	struct extended_perms_decision *xpd;
	security_xperm_set(xp_node->xp.drivers.p, driver);
	xpd = avc_xperms_decision_lookup(driver, xp_node);
	if (xpd && xpd->allowed)
		security_xperm_set(xpd->allowed->p, perm);
}

static void avc_xperms_decision_free(struct avc_xperms_decision_node *xpd_node)
{
	struct extended_perms_decision *xpd;

	xpd = &xpd_node->xpd;
	if (xpd->allowed)
		kmem_cache_free(avc_xperms_data_cachep, xpd->allowed);
	if (xpd->auditallow)
		kmem_cache_free(avc_xperms_data_cachep, xpd->auditallow);
	if (xpd->dontaudit)
		kmem_cache_free(avc_xperms_data_cachep, xpd->dontaudit);
	kmem_cache_free(avc_xperms_decision_cachep, xpd_node);
}

static void avc_xperms_free(struct avc_xperms_node *xp_node)
{
	struct avc_xperms_decision_node *xpd_node, *tmp;

	if (!xp_node)
		return;

	list_for_each_entry_safe(xpd_node, tmp, &xp_node->xpd_head, xpd_list) {
		list_del(&xpd_node->xpd_list);
		avc_xperms_decision_free(xpd_node);
	}
	kmem_cache_free(avc_xperms_cachep, xp_node);
}

static void avc_copy_xperms_decision(struct extended_perms_decision *dest,
					struct extended_perms_decision *src)
{
	dest->driver = src->driver;
	dest->used = src->used;
	if (dest->used & XPERMS_ALLOWED)
		memcpy(dest->allowed->p, src->allowed->p,
				sizeof(src->allowed->p));
	if (dest->used & XPERMS_AUDITALLOW)
		memcpy(dest->auditallow->p, src->auditallow->p,
				sizeof(src->auditallow->p));
	if (dest->used & XPERMS_DONTAUDIT)
		memcpy(dest->dontaudit->p, src->dontaudit->p,
				sizeof(src->dontaudit->p));
}

/*
 * similar to avc_copy_xperms_decision, but only copy decision
 * information relevant to this perm
 */
static inline void avc_quick_copy_xperms_decision(u8 perm,
			struct extended_perms_decision *dest,
			struct extended_perms_decision *src)
{
	/*
	 * compute index of the u32 of the 256 bits (8 u32s) that contain this
	 * command permission
	 */
	u8 i = perm >> 5;

	dest->used = src->used;
	if (dest->used & XPERMS_ALLOWED)
		dest->allowed->p[i] = src->allowed->p[i];
	if (dest->used & XPERMS_AUDITALLOW)
		dest->auditallow->p[i] = src->auditallow->p[i];
	if (dest->used & XPERMS_DONTAUDIT)
		dest->dontaudit->p[i] = src->dontaudit->p[i];
}

static struct avc_xperms_decision_node
		*avc_xperms_decision_alloc(u8 which)
{
	struct avc_xperms_decision_node *xpd_node;
	struct extended_perms_decision *xpd;

369
	xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, GFP_NOWAIT);
370 371 372 373 374 375
	if (!xpd_node)
		return NULL;

	xpd = &xpd_node->xpd;
	if (which & XPERMS_ALLOWED) {
		xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep,
376
						GFP_NOWAIT);
377 378 379 380 381
		if (!xpd->allowed)
			goto error;
	}
	if (which & XPERMS_AUDITALLOW) {
		xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep,
382
						GFP_NOWAIT);
383 384 385 386 387
		if (!xpd->auditallow)
			goto error;
	}
	if (which & XPERMS_DONTAUDIT) {
		xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep,
388
						GFP_NOWAIT);
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
		if (!xpd->dontaudit)
			goto error;
	}
	return xpd_node;
error:
	avc_xperms_decision_free(xpd_node);
	return NULL;
}

static int avc_add_xperms_decision(struct avc_node *node,
			struct extended_perms_decision *src)
{
	struct avc_xperms_decision_node *dest_xpd;

	node->ae.xp_node->xp.len++;
	dest_xpd = avc_xperms_decision_alloc(src->used);
	if (!dest_xpd)
		return -ENOMEM;
	avc_copy_xperms_decision(&dest_xpd->xpd, src);
	list_add(&dest_xpd->xpd_list, &node->ae.xp_node->xpd_head);
	return 0;
}

static struct avc_xperms_node *avc_xperms_alloc(void)
{
	struct avc_xperms_node *xp_node;

416
	xp_node = kmem_cache_zalloc(avc_xperms_cachep, GFP_NOWAIT);
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 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
	if (!xp_node)
		return xp_node;
	INIT_LIST_HEAD(&xp_node->xpd_head);
	return xp_node;
}

static int avc_xperms_populate(struct avc_node *node,
				struct avc_xperms_node *src)
{
	struct avc_xperms_node *dest;
	struct avc_xperms_decision_node *dest_xpd;
	struct avc_xperms_decision_node *src_xpd;

	if (src->xp.len == 0)
		return 0;
	dest = avc_xperms_alloc();
	if (!dest)
		return -ENOMEM;

	memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p));
	dest->xp.len = src->xp.len;

	/* for each source xpd allocate a destination xpd and copy */
	list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) {
		dest_xpd = avc_xperms_decision_alloc(src_xpd->xpd.used);
		if (!dest_xpd)
			goto error;
		avc_copy_xperms_decision(&dest_xpd->xpd, &src_xpd->xpd);
		list_add(&dest_xpd->xpd_list, &dest->xpd_head);
	}
	node->ae.xp_node = dest;
	return 0;
error:
	avc_xperms_free(dest);
	return -ENOMEM;

}

static inline u32 avc_xperms_audit_required(u32 requested,
					struct av_decision *avd,
					struct extended_perms_decision *xpd,
					u8 perm,
					int result,
					u32 *deniedp)
{
	u32 denied, audited;

	denied = requested & ~avd->allowed;
	if (unlikely(denied)) {
		audited = denied & avd->auditdeny;
		if (audited && xpd) {
			if (avc_xperms_has_perm(xpd, perm, XPERMS_DONTAUDIT))
				audited &= ~requested;
		}
	} else if (result) {
		audited = denied = requested;
	} else {
		audited = requested & avd->auditallow;
		if (audited && xpd) {
			if (!avc_xperms_has_perm(xpd, perm, XPERMS_AUDITALLOW))
				audited &= ~requested;
		}
	}

	*deniedp = denied;
	return audited;
}

S
Stephen Smalley 已提交
485 486 487 488 489 490
static inline int avc_xperms_audit(struct selinux_state *state,
				   u32 ssid, u32 tsid, u16 tclass,
				   u32 requested, struct av_decision *avd,
				   struct extended_perms_decision *xpd,
				   u8 perm, int result,
				   struct common_audit_data *ad)
491 492 493 494 495 496 497
{
	u32 audited, denied;

	audited = avc_xperms_audit_required(
			requested, avd, xpd, perm, result, &denied);
	if (likely(!audited))
		return 0;
S
Stephen Smalley 已提交
498
	return slow_avc_audit(state, ssid, tsid, tclass, requested,
499 500 501
			audited, denied, result, ad, 0);
}

L
Linus Torvalds 已提交
502 503 504
static void avc_node_free(struct rcu_head *rhead)
{
	struct avc_node *node = container_of(rhead, struct avc_node, rhead);
505
	avc_xperms_free(node->ae.xp_node);
L
Linus Torvalds 已提交
506 507 508 509
	kmem_cache_free(avc_node_cachep, node);
	avc_cache_stats_incr(frees);
}

S
Stephen Smalley 已提交
510
static void avc_node_delete(struct selinux_avc *avc, struct avc_node *node)
L
Linus Torvalds 已提交
511
{
512
	hlist_del_rcu(&node->list);
L
Linus Torvalds 已提交
513
	call_rcu(&node->rhead, avc_node_free);
S
Stephen Smalley 已提交
514
	atomic_dec(&avc->avc_cache.active_nodes);
L
Linus Torvalds 已提交
515 516
}

S
Stephen Smalley 已提交
517
static void avc_node_kill(struct selinux_avc *avc, struct avc_node *node)
L
Linus Torvalds 已提交
518
{
519
	avc_xperms_free(node->ae.xp_node);
L
Linus Torvalds 已提交
520 521
	kmem_cache_free(avc_node_cachep, node);
	avc_cache_stats_incr(frees);
S
Stephen Smalley 已提交
522
	atomic_dec(&avc->avc_cache.active_nodes);
L
Linus Torvalds 已提交
523 524
}

S
Stephen Smalley 已提交
525 526
static void avc_node_replace(struct selinux_avc *avc,
			     struct avc_node *new, struct avc_node *old)
L
Linus Torvalds 已提交
527
{
528
	hlist_replace_rcu(&old->list, &new->list);
L
Linus Torvalds 已提交
529
	call_rcu(&old->rhead, avc_node_free);
S
Stephen Smalley 已提交
530
	atomic_dec(&avc->avc_cache.active_nodes);
L
Linus Torvalds 已提交
531 532
}

S
Stephen Smalley 已提交
533
static inline int avc_reclaim_node(struct selinux_avc *avc)
L
Linus Torvalds 已提交
534 535 536 537
{
	struct avc_node *node;
	int hvalue, try, ecx;
	unsigned long flags;
538
	struct hlist_head *head;
539
	spinlock_t *lock;
L
Linus Torvalds 已提交
540

541
	for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) {
S
Stephen Smalley 已提交
542 543 544 545
		hvalue = atomic_inc_return(&avc->avc_cache.lru_hint) &
			(AVC_CACHE_SLOTS - 1);
		head = &avc->avc_cache.slots[hvalue];
		lock = &avc->avc_cache.slots_lock[hvalue];
L
Linus Torvalds 已提交
546

547
		if (!spin_trylock_irqsave(lock, flags))
L
Linus Torvalds 已提交
548 549
			continue;

550
		rcu_read_lock();
551
		hlist_for_each_entry(node, head, list) {
S
Stephen Smalley 已提交
552
			avc_node_delete(avc, node);
E
Eric Paris 已提交
553 554 555 556
			avc_cache_stats_incr(reclaims);
			ecx++;
			if (ecx >= AVC_CACHE_RECLAIM) {
				rcu_read_unlock();
557
				spin_unlock_irqrestore(lock, flags);
E
Eric Paris 已提交
558
				goto out;
L
Linus Torvalds 已提交
559 560
			}
		}
561
		rcu_read_unlock();
562
		spin_unlock_irqrestore(lock, flags);
L
Linus Torvalds 已提交
563 564 565 566 567
	}
out:
	return ecx;
}

S
Stephen Smalley 已提交
568
static struct avc_node *avc_alloc_node(struct selinux_avc *avc)
L
Linus Torvalds 已提交
569 570 571
{
	struct avc_node *node;

572
	node = kmem_cache_zalloc(avc_node_cachep, GFP_NOWAIT);
L
Linus Torvalds 已提交
573 574 575
	if (!node)
		goto out;

576
	INIT_HLIST_NODE(&node->list);
L
Linus Torvalds 已提交
577 578
	avc_cache_stats_incr(allocations);

S
Stephen Smalley 已提交
579 580 581
	if (atomic_inc_return(&avc->avc_cache.active_nodes) >
	    avc->avc_cache_threshold)
		avc_reclaim_node(avc);
L
Linus Torvalds 已提交
582 583 584 585 586

out:
	return node;
}

587
static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
L
Linus Torvalds 已提交
588 589 590 591
{
	node->ae.ssid = ssid;
	node->ae.tsid = tsid;
	node->ae.tclass = tclass;
592
	memcpy(&node->ae.avd, avd, sizeof(node->ae.avd));
L
Linus Torvalds 已提交
593 594
}

S
Stephen Smalley 已提交
595 596
static inline struct avc_node *avc_search_node(struct selinux_avc *avc,
					       u32 ssid, u32 tsid, u16 tclass)
L
Linus Torvalds 已提交
597 598 599
{
	struct avc_node *node, *ret = NULL;
	int hvalue;
600
	struct hlist_head *head;
L
Linus Torvalds 已提交
601 602

	hvalue = avc_hash(ssid, tsid, tclass);
S
Stephen Smalley 已提交
603
	head = &avc->avc_cache.slots[hvalue];
604
	hlist_for_each_entry_rcu(node, head, list) {
L
Linus Torvalds 已提交
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
		if (ssid == node->ae.ssid &&
		    tclass == node->ae.tclass &&
		    tsid == node->ae.tsid) {
			ret = node;
			break;
		}
	}

	return ret;
}

/**
 * avc_lookup - Look up an AVC entry.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 *
 * Look up an AVC entry that is valid for the
 * (@ssid, @tsid), interpreting the permissions
 * based on @tclass.  If a valid AVC entry exists,
J
Justin P. Mattock 已提交
625
 * then this function returns the avc_node.
L
Linus Torvalds 已提交
626 627
 * Otherwise, this function returns NULL.
 */
S
Stephen Smalley 已提交
628 629
static struct avc_node *avc_lookup(struct selinux_avc *avc,
				   u32 ssid, u32 tsid, u16 tclass)
L
Linus Torvalds 已提交
630 631 632 633
{
	struct avc_node *node;

	avc_cache_stats_incr(lookups);
S
Stephen Smalley 已提交
634
	node = avc_search_node(avc, ssid, tsid, tclass);
L
Linus Torvalds 已提交
635

636
	if (node)
637
		return node;
L
Linus Torvalds 已提交
638

639 640
	avc_cache_stats_incr(misses);
	return NULL;
L
Linus Torvalds 已提交
641 642
}

S
Stephen Smalley 已提交
643 644
static int avc_latest_notif_update(struct selinux_avc *avc,
				   int seqno, int is_insert)
L
Linus Torvalds 已提交
645 646 647 648 649 650 651
{
	int ret = 0;
	static DEFINE_SPINLOCK(notif_lock);
	unsigned long flag;

	spin_lock_irqsave(&notif_lock, flag);
	if (is_insert) {
S
Stephen Smalley 已提交
652
		if (seqno < avc->avc_cache.latest_notif) {
653
			pr_warn("SELinux: avc:  seqno %d < latest_notif %d\n",
S
Stephen Smalley 已提交
654
			       seqno, avc->avc_cache.latest_notif);
L
Linus Torvalds 已提交
655 656 657
			ret = -EAGAIN;
		}
	} else {
S
Stephen Smalley 已提交
658 659
		if (seqno > avc->avc_cache.latest_notif)
			avc->avc_cache.latest_notif = seqno;
L
Linus Torvalds 已提交
660 661 662 663 664 665 666 667 668 669 670
	}
	spin_unlock_irqrestore(&notif_lock, flag);

	return ret;
}

/**
 * avc_insert - Insert an AVC entry.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
671
 * @avd: resulting av decision
672
 * @xp_node: resulting extended permissions
L
Linus Torvalds 已提交
673 674 675 676 677 678
 *
 * Insert an AVC entry for the SID pair
 * (@ssid, @tsid) and class @tclass.
 * The access vectors and the sequence number are
 * normally provided by the security server in
 * response to a security_compute_av() call.  If the
679
 * sequence number @avd->seqno is not less than the latest
L
Linus Torvalds 已提交
680 681 682 683
 * revocation notification, then the function copies
 * the access vectors into a cache entry, returns
 * avc_node inserted. Otherwise, this function returns NULL.
 */
S
Stephen Smalley 已提交
684 685 686 687
static struct avc_node *avc_insert(struct selinux_avc *avc,
				   u32 ssid, u32 tsid, u16 tclass,
				   struct av_decision *avd,
				   struct avc_xperms_node *xp_node)
L
Linus Torvalds 已提交
688 689 690 691 692
{
	struct avc_node *pos, *node = NULL;
	int hvalue;
	unsigned long flag;

S
Stephen Smalley 已提交
693
	if (avc_latest_notif_update(avc, avd->seqno, 1))
L
Linus Torvalds 已提交
694 695
		goto out;

S
Stephen Smalley 已提交
696
	node = avc_alloc_node(avc);
L
Linus Torvalds 已提交
697
	if (node) {
698
		struct hlist_head *head;
699
		spinlock_t *lock;
700
		int rc = 0;
701

L
Linus Torvalds 已提交
702
		hvalue = avc_hash(ssid, tsid, tclass);
703
		avc_node_populate(node, ssid, tsid, tclass, avd);
704 705 706 707 708
		rc = avc_xperms_populate(node, xp_node);
		if (rc) {
			kmem_cache_free(avc_node_cachep, node);
			return NULL;
		}
S
Stephen Smalley 已提交
709 710
		head = &avc->avc_cache.slots[hvalue];
		lock = &avc->avc_cache.slots_lock[hvalue];
711 712

		spin_lock_irqsave(lock, flag);
713
		hlist_for_each_entry(pos, head, list) {
L
Linus Torvalds 已提交
714 715 716
			if (pos->ae.ssid == ssid &&
			    pos->ae.tsid == tsid &&
			    pos->ae.tclass == tclass) {
S
Stephen Smalley 已提交
717
				avc_node_replace(avc, node, pos);
L
Linus Torvalds 已提交
718 719 720
				goto found;
			}
		}
721
		hlist_add_head_rcu(&node->list, head);
L
Linus Torvalds 已提交
722
found:
723
		spin_unlock_irqrestore(lock, flag);
L
Linus Torvalds 已提交
724 725 726 727 728
	}
out:
	return node;
}

729 730 731 732 733 734 735
/**
 * avc_audit_pre_callback - SELinux specific information
 * will be called by generic audit code
 * @ab: the audit buffer
 * @a: audit_data
 */
static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
L
Linus Torvalds 已提交
736
{
737 738
	struct common_audit_data *ad = a;
	audit_log_format(ab, "avc:  %s ",
739 740 741
			 ad->selinux_audit_data->denied ? "denied" : "granted");
	avc_dump_av(ab, ad->selinux_audit_data->tclass,
			ad->selinux_audit_data->audited);
742
	audit_log_format(ab, " for ");
L
Linus Torvalds 已提交
743 744
}

745 746 747 748 749 750 751
/**
 * avc_audit_post_callback - SELinux specific information
 * will be called by generic audit code
 * @ab: the audit buffer
 * @a: audit_data
 */
static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
L
Linus Torvalds 已提交
752
{
753 754
	struct common_audit_data *ad = a;
	audit_log_format(ab, " ");
S
Stephen Smalley 已提交
755 756 757 758
	avc_dump_query(ab, ad->selinux_audit_data->state,
		       ad->selinux_audit_data->ssid,
		       ad->selinux_audit_data->tsid,
		       ad->selinux_audit_data->tclass);
759 760 761 762
	if (ad->selinux_audit_data->denied) {
		audit_log_format(ab, " permissive=%u",
				 ad->selinux_audit_data->result ? 0 : 1);
	}
L
Linus Torvalds 已提交
763 764
}

765
/* This is the slow part of avc audit with big stack footprint */
S
Stephen Smalley 已提交
766 767 768 769 770
noinline int slow_avc_audit(struct selinux_state *state,
			    u32 ssid, u32 tsid, u16 tclass,
			    u32 requested, u32 audited, u32 denied, int result,
			    struct common_audit_data *a,
			    unsigned int flags)
771 772
{
	struct common_audit_data stack_data;
773
	struct selinux_audit_data sad;
774 775 776

	if (!a) {
		a = &stack_data;
777
		a->type = LSM_AUDIT_DATA_NONE;
778 779 780 781 782 783 784 785 786 787 788 789 790
	}

	/*
	 * When in a RCU walk do the audit on the RCU retry.  This is because
	 * the collection of the dname in an inode audit message is not RCU
	 * safe.  Note this may drop some audits when the situation changes
	 * during retry. However this is logically just as if the operation
	 * happened a little later.
	 */
	if ((a->type == LSM_AUDIT_DATA_INODE) &&
	    (flags & MAY_NOT_BLOCK))
		return -ECHILD;

791 792 793 794 795 796
	sad.tclass = tclass;
	sad.requested = requested;
	sad.ssid = ssid;
	sad.tsid = tsid;
	sad.audited = audited;
	sad.denied = denied;
797
	sad.result = result;
S
Stephen Smalley 已提交
798
	sad.state = state;
799 800

	a->selinux_audit_data = &sad;
801

802
	common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback);
803 804 805
	return 0;
}

L
Linus Torvalds 已提交
806 807 808 809 810
/**
 * avc_add_callback - Register a callback for security events.
 * @callback: callback function
 * @events: security events
 *
811 812 813
 * Register a callback function for events in the set @events.
 * Returns %0 on success or -%ENOMEM if insufficient memory
 * exists to add the callback.
L
Linus Torvalds 已提交
814
 */
815
int __init avc_add_callback(int (*callback)(u32 event), u32 events)
L
Linus Torvalds 已提交
816 817 818 819
{
	struct avc_callback_node *c;
	int rc = 0;

820
	c = kmalloc(sizeof(*c), GFP_KERNEL);
L
Linus Torvalds 已提交
821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
	if (!c) {
		rc = -ENOMEM;
		goto out;
	}

	c->callback = callback;
	c->events = events;
	c->next = avc_callbacks;
	avc_callbacks = c;
out:
	return rc;
}

/**
 * avc_update_node Update an AVC entry
 * @event : Updating event
 * @perms : Permission mask bits
 * @ssid,@tsid,@tclass : identifier of an AVC entry
839
 * @seqno : sequence number when decision was made
840
 * @xpd: extended_perms_decision to be added to the node
841
 * @flags: the AVC_* flags, e.g. AVC_NONBLOCKING, AVC_EXTENDED_PERMS, or 0.
L
Linus Torvalds 已提交
842 843 844
 *
 * if a valid AVC entry doesn't exist,this function returns -ENOENT.
 * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
J
Justin P. Mattock 已提交
845
 * otherwise, this function updates the AVC entry. The original AVC-entry object
L
Linus Torvalds 已提交
846 847
 * will release later by RCU.
 */
S
Stephen Smalley 已提交
848 849 850 851 852
static int avc_update_node(struct selinux_avc *avc,
			   u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
			   u32 tsid, u16 tclass, u32 seqno,
			   struct extended_perms_decision *xpd,
			   u32 flags)
L
Linus Torvalds 已提交
853 854 855 856
{
	int hvalue, rc = 0;
	unsigned long flag;
	struct avc_node *pos, *node, *orig = NULL;
857
	struct hlist_head *head;
858
	spinlock_t *lock;
L
Linus Torvalds 已提交
859

860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
	/*
	 * If we are in a non-blocking code path, e.g. VFS RCU walk,
	 * then we must not add permissions to a cache entry
	 * because we cannot safely audit the denial.  Otherwise,
	 * during the subsequent blocking retry (e.g. VFS ref walk), we
	 * will find the permissions already granted in the cache entry
	 * and won't audit anything at all, leading to silent denials in
	 * permissive mode that only appear when in enforcing mode.
	 *
	 * See the corresponding handling in slow_avc_audit(), and the
	 * logic in selinux_inode_follow_link and selinux_inode_permission
	 * for the VFS MAY_NOT_BLOCK flag, which is transliterated into
	 * AVC_NONBLOCKING for avc_has_perm_noaudit().
	 */
	if (flags & AVC_NONBLOCKING)
		return 0;

S
Stephen Smalley 已提交
877
	node = avc_alloc_node(avc);
L
Linus Torvalds 已提交
878 879 880 881 882 883 884 885
	if (!node) {
		rc = -ENOMEM;
		goto out;
	}

	/* Lock the target slot */
	hvalue = avc_hash(ssid, tsid, tclass);

S
Stephen Smalley 已提交
886 887
	head = &avc->avc_cache.slots[hvalue];
	lock = &avc->avc_cache.slots_lock[hvalue];
888 889 890

	spin_lock_irqsave(lock, flag);

891
	hlist_for_each_entry(pos, head, list) {
892 893
		if (ssid == pos->ae.ssid &&
		    tsid == pos->ae.tsid &&
894 895
		    tclass == pos->ae.tclass &&
		    seqno == pos->ae.avd.seqno){
L
Linus Torvalds 已提交
896 897 898 899 900 901 902
			orig = pos;
			break;
		}
	}

	if (!orig) {
		rc = -ENOENT;
S
Stephen Smalley 已提交
903
		avc_node_kill(avc, node);
L
Linus Torvalds 已提交
904 905 906 907 908 909 910
		goto out_unlock;
	}

	/*
	 * Copy and replace original node.
	 */

911
	avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd);
L
Linus Torvalds 已提交
912

913 914 915 916 917 918 919 920
	if (orig->ae.xp_node) {
		rc = avc_xperms_populate(node, orig->ae.xp_node);
		if (rc) {
			kmem_cache_free(avc_node_cachep, node);
			goto out_unlock;
		}
	}

L
Linus Torvalds 已提交
921 922 923
	switch (event) {
	case AVC_CALLBACK_GRANT:
		node->ae.avd.allowed |= perms;
924 925
		if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS))
			avc_xperms_allow_perm(node->ae.xp_node, driver, xperm);
L
Linus Torvalds 已提交
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
		break;
	case AVC_CALLBACK_TRY_REVOKE:
	case AVC_CALLBACK_REVOKE:
		node->ae.avd.allowed &= ~perms;
		break;
	case AVC_CALLBACK_AUDITALLOW_ENABLE:
		node->ae.avd.auditallow |= perms;
		break;
	case AVC_CALLBACK_AUDITALLOW_DISABLE:
		node->ae.avd.auditallow &= ~perms;
		break;
	case AVC_CALLBACK_AUDITDENY_ENABLE:
		node->ae.avd.auditdeny |= perms;
		break;
	case AVC_CALLBACK_AUDITDENY_DISABLE:
		node->ae.avd.auditdeny &= ~perms;
		break;
943 944 945
	case AVC_CALLBACK_ADD_XPERMS:
		avc_add_xperms_decision(node, xpd);
		break;
L
Linus Torvalds 已提交
946
	}
S
Stephen Smalley 已提交
947
	avc_node_replace(avc, node, orig);
L
Linus Torvalds 已提交
948
out_unlock:
949
	spin_unlock_irqrestore(lock, flag);
L
Linus Torvalds 已提交
950 951 952 953 954
out:
	return rc;
}

/**
955
 * avc_flush - Flush the cache
L
Linus Torvalds 已提交
956
 */
S
Stephen Smalley 已提交
957
static void avc_flush(struct selinux_avc *avc)
L
Linus Torvalds 已提交
958
{
959
	struct hlist_head *head;
960
	struct avc_node *node;
961
	spinlock_t *lock;
962 963
	unsigned long flag;
	int i;
L
Linus Torvalds 已提交
964 965

	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
S
Stephen Smalley 已提交
966 967
		head = &avc->avc_cache.slots[i];
		lock = &avc->avc_cache.slots_lock[i];
968 969

		spin_lock_irqsave(lock, flag);
970 971 972 973 974
		/*
		 * With preemptable RCU, the outer spinlock does not
		 * prevent RCU grace periods from ending.
		 */
		rcu_read_lock();
975
		hlist_for_each_entry(node, head, list)
S
Stephen Smalley 已提交
976
			avc_node_delete(avc, node);
977
		rcu_read_unlock();
978
		spin_unlock_irqrestore(lock, flag);
L
Linus Torvalds 已提交
979
	}
980 981 982 983 984 985
}

/**
 * avc_ss_reset - Flush the cache and revalidate migrated permissions.
 * @seqno: policy sequence number
 */
S
Stephen Smalley 已提交
986
int avc_ss_reset(struct selinux_avc *avc, u32 seqno)
987 988 989 990
{
	struct avc_callback_node *c;
	int rc = 0, tmprc;

S
Stephen Smalley 已提交
991
	avc_flush(avc);
L
Linus Torvalds 已提交
992 993 994

	for (c = avc_callbacks; c; c = c->next) {
		if (c->events & AVC_CALLBACK_RESET) {
995
			tmprc = c->callback(AVC_CALLBACK_RESET);
996 997 998 999
			/* save the first error encountered for the return
			   value and continue processing the callbacks */
			if (!rc)
				rc = tmprc;
L
Linus Torvalds 已提交
1000 1001 1002
		}
	}

S
Stephen Smalley 已提交
1003
	avc_latest_notif_update(avc, seqno, 0);
L
Linus Torvalds 已提交
1004 1005 1006
	return rc;
}

1007 1008 1009 1010 1011 1012 1013 1014 1015
/*
 * Slow-path helper function for avc_has_perm_noaudit,
 * when the avc_node lookup fails. We get called with
 * the RCU read lock held, and need to return with it
 * still held, but drop if for the security compute.
 *
 * Don't inline this, since it's the slow-path and just
 * results in a bigger stack frame.
 */
S
Stephen Smalley 已提交
1016 1017 1018 1019 1020
static noinline
struct avc_node *avc_compute_av(struct selinux_state *state,
				u32 ssid, u32 tsid,
				u16 tclass, struct av_decision *avd,
				struct avc_xperms_node *xp_node)
1021 1022
{
	rcu_read_unlock();
1023
	INIT_LIST_HEAD(&xp_node->xpd_head);
S
Stephen Smalley 已提交
1024
	security_compute_av(state, ssid, tsid, tclass, avd, &xp_node->xp);
1025
	rcu_read_lock();
S
Stephen Smalley 已提交
1026
	return avc_insert(state->avc, ssid, tsid, tclass, avd, xp_node);
1027 1028
}

S
Stephen Smalley 已提交
1029 1030 1031 1032 1033
static noinline int avc_denied(struct selinux_state *state,
			       u32 ssid, u32 tsid,
			       u16 tclass, u32 requested,
			       u8 driver, u8 xperm, unsigned int flags,
			       struct av_decision *avd)
1034 1035 1036 1037
{
	if (flags & AVC_STRICT)
		return -EACCES;

S
Stephen Smalley 已提交
1038
	if (enforcing_enabled(state) &&
1039
	    !(avd->flags & AVD_FLAGS_PERMISSIVE))
1040 1041
		return -EACCES;

S
Stephen Smalley 已提交
1042 1043
	avc_update_node(state->avc, AVC_CALLBACK_GRANT, requested, driver,
			xperm, ssid, tsid, tclass, avd->seqno, NULL, flags);
1044 1045 1046
	return 0;
}

1047 1048 1049 1050 1051 1052 1053
/*
 * The avc extended permissions logic adds an additional 256 bits of
 * permissions to an avc node when extended permissions for that node are
 * specified in the avtab. If the additional 256 permissions is not adequate,
 * as-is the case with ioctls, then multiple may be chained together and the
 * driver field is used to specify which set contains the permission.
 */
S
Stephen Smalley 已提交
1054 1055 1056
int avc_has_extended_perms(struct selinux_state *state,
			   u32 ssid, u32 tsid, u16 tclass, u32 requested,
			   u8 driver, u8 xperm, struct common_audit_data *ad)
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
{
	struct avc_node *node;
	struct av_decision avd;
	u32 denied;
	struct extended_perms_decision local_xpd;
	struct extended_perms_decision *xpd = NULL;
	struct extended_perms_data allowed;
	struct extended_perms_data auditallow;
	struct extended_perms_data dontaudit;
	struct avc_xperms_node local_xp_node;
	struct avc_xperms_node *xp_node;
	int rc = 0, rc2;

	xp_node = &local_xp_node;
	BUG_ON(!requested);

	rcu_read_lock();

S
Stephen Smalley 已提交
1075
	node = avc_lookup(state->avc, ssid, tsid, tclass);
1076
	if (unlikely(!node)) {
S
Stephen Smalley 已提交
1077
		node = avc_compute_av(state, ssid, tsid, tclass, &avd, xp_node);
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
	} else {
		memcpy(&avd, &node->ae.avd, sizeof(avd));
		xp_node = node->ae.xp_node;
	}
	/* if extended permissions are not defined, only consider av_decision */
	if (!xp_node || !xp_node->xp.len)
		goto decision;

	local_xpd.allowed = &allowed;
	local_xpd.auditallow = &auditallow;
	local_xpd.dontaudit = &dontaudit;

	xpd = avc_xperms_decision_lookup(driver, xp_node);
	if (unlikely(!xpd)) {
		/*
		 * Compute the extended_perms_decision only if the driver
		 * is flagged
		 */
		if (!security_xperm_test(xp_node->xp.drivers.p, driver)) {
			avd.allowed &= ~requested;
			goto decision;
		}
		rcu_read_unlock();
S
Stephen Smalley 已提交
1101 1102
		security_compute_xperms_decision(state, ssid, tsid, tclass,
						 driver, &local_xpd);
1103
		rcu_read_lock();
S
Stephen Smalley 已提交
1104 1105 1106
		avc_update_node(state->avc, AVC_CALLBACK_ADD_XPERMS, requested,
				driver, xperm, ssid, tsid, tclass, avd.seqno,
				&local_xpd, 0);
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
	} else {
		avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd);
	}
	xpd = &local_xpd;

	if (!avc_xperms_has_perm(xpd, xperm, XPERMS_ALLOWED))
		avd.allowed &= ~requested;

decision:
	denied = requested & ~(avd.allowed);
	if (unlikely(denied))
S
Stephen Smalley 已提交
1118 1119
		rc = avc_denied(state, ssid, tsid, tclass, requested,
				driver, xperm, AVC_EXTENDED_PERMS, &avd);
1120 1121 1122

	rcu_read_unlock();

S
Stephen Smalley 已提交
1123
	rc2 = avc_xperms_audit(state, ssid, tsid, tclass, requested,
1124 1125 1126 1127 1128
			&avd, xpd, xperm, rc, ad);
	if (rc2)
		return rc2;
	return rc;
}
1129

L
Linus Torvalds 已提交
1130 1131 1132 1133 1134 1135
/**
 * avc_has_perm_noaudit - Check permissions but perform no auditing.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 * @requested: requested permissions, interpreted based on @tclass
1136
 * @flags:  AVC_STRICT, AVC_NONBLOCKING, or 0
L
Linus Torvalds 已提交
1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
 * @avd: access vector decisions
 *
 * Check the AVC to determine whether the @requested permissions are granted
 * for the SID pair (@ssid, @tsid), interpreting the permissions
 * based on @tclass, and call the security server on a cache miss to obtain
 * a new decision and add it to the cache.  Return a copy of the decisions
 * in @avd.  Return %0 if all @requested permissions are granted,
 * -%EACCES if any permissions are denied, or another -errno upon
 * other errors.  This function is typically called by avc_has_perm(),
 * but may also be called directly to separate permission checking from
 * auditing, e.g. in cases where a lock must be held for the check but
 * should be released for the auditing.
 */
S
Stephen Smalley 已提交
1150 1151 1152 1153 1154
inline int avc_has_perm_noaudit(struct selinux_state *state,
				u32 ssid, u32 tsid,
				u16 tclass, u32 requested,
				unsigned int flags,
				struct av_decision *avd)
L
Linus Torvalds 已提交
1155 1156
{
	struct avc_node *node;
1157
	struct avc_xperms_node xp_node;
L
Linus Torvalds 已提交
1158 1159 1160
	int rc = 0;
	u32 denied;

1161 1162
	BUG_ON(!requested);

L
Linus Torvalds 已提交
1163 1164
	rcu_read_lock();

S
Stephen Smalley 已提交
1165
	node = avc_lookup(state->avc, ssid, tsid, tclass);
1166
	if (unlikely(!node))
S
Stephen Smalley 已提交
1167
		node = avc_compute_av(state, ssid, tsid, tclass, avd, &xp_node);
1168
	else
1169
		memcpy(avd, &node->ae.avd, sizeof(*avd));
L
Linus Torvalds 已提交
1170

1171
	denied = requested & ~(avd->allowed);
1172
	if (unlikely(denied))
S
Stephen Smalley 已提交
1173 1174
		rc = avc_denied(state, ssid, tsid, tclass, requested, 0, 0,
				flags, avd);
L
Linus Torvalds 已提交
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195

	rcu_read_unlock();
	return rc;
}

/**
 * avc_has_perm - Check permissions and perform any appropriate auditing.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 * @requested: requested permissions, interpreted based on @tclass
 * @auditdata: auxiliary audit data
 *
 * Check the AVC to determine whether the @requested permissions are granted
 * for the SID pair (@ssid, @tsid), interpreting the permissions
 * based on @tclass, and call the security server on a cache miss to obtain
 * a new decision and add it to the cache.  Audit the granting or denial of
 * permissions in accordance with the policy.  Return %0 if all @requested
 * permissions are granted, -%EACCES if any permissions are denied, or
 * another -errno upon other errors.
 */
S
Stephen Smalley 已提交
1196
int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
1197
		 u32 requested, struct common_audit_data *auditdata)
L
Linus Torvalds 已提交
1198 1199
{
	struct av_decision avd;
1200
	int rc, rc2;
L
Linus Torvalds 已提交
1201

S
Stephen Smalley 已提交
1202 1203
	rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0,
				  &avd);
1204

S
Stephen Smalley 已提交
1205 1206
	rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
			auditdata, 0);
1207 1208 1209 1210 1211
	if (rc2)
		return rc2;
	return rc;
}

S
Stephen Smalley 已提交
1212 1213 1214
int avc_has_perm_flags(struct selinux_state *state,
		       u32 ssid, u32 tsid, u16 tclass, u32 requested,
		       struct common_audit_data *auditdata,
1215 1216 1217 1218 1219
		       int flags)
{
	struct av_decision avd;
	int rc, rc2;

1220 1221
	rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested,
				  (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0,
S
Stephen Smalley 已提交
1222
				  &avd);
1223

S
Stephen Smalley 已提交
1224
	rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
1225
			auditdata, flags);
1226 1227
	if (rc2)
		return rc2;
L
Linus Torvalds 已提交
1228 1229
	return rc;
}
1230

S
Stephen Smalley 已提交
1231
u32 avc_policy_seqno(struct selinux_state *state)
1232
{
S
Stephen Smalley 已提交
1233
	return state->avc->avc_cache.latest_notif;
1234
}
1235 1236 1237

void avc_disable(void)
{
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249
	/*
	 * If you are looking at this because you have realized that we are
	 * not destroying the avc_node_cachep it might be easy to fix, but
	 * I don't know the memory barrier semantics well enough to know.  It's
	 * possible that some other task dereferenced security_ops when
	 * it still pointed to selinux operations.  If that is the case it's
	 * possible that it is about to use the avc and is about to need the
	 * avc_node_cachep.  I know I could wrap the security.c security_ops call
	 * in an rcu_lock, but seriously, it's not worth it.  Instead I just flush
	 * the cache and get that memory back.
	 */
	if (avc_node_cachep) {
S
Stephen Smalley 已提交
1250
		avc_flush(selinux_state.avc);
1251 1252
		/* kmem_cache_destroy(avc_node_cachep); */
	}
1253
}