selinuxfs.c 42.7 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/* Updated: Karl MacMillan <kmacmillan@tresys.com>
 *
3
 *	Added conditional policy language extensions
L
Linus Torvalds 已提交
4
 *
5
 *  Updated: Hewlett-Packard <paul@paul-moore.com>
6
 *
7
 *	Added support for the policy capability bitmap
8 9
 *
 * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
L
Linus Torvalds 已提交
10 11 12
 * Copyright (C) 2003 - 2004 Tresys Technology, LLC
 * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
 *	This program is free software; you can redistribute it and/or modify
13
 *	it under the terms of the GNU General Public License as published by
L
Linus Torvalds 已提交
14 15 16 17 18 19 20 21
 *	the Free Software Foundation, version 2.
 */

#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
I
Ingo Molnar 已提交
22
#include <linux/mutex.h>
L
Linus Torvalds 已提交
23 24 25 26 27 28
#include <linux/init.h>
#include <linux/string.h>
#include <linux/security.h>
#include <linux/major.h>
#include <linux/seq_file.h>
#include <linux/percpu.h>
S
Steve Grubb 已提交
29
#include <linux/audit.h>
30
#include <linux/uaccess.h>
31
#include <linux/kobject.h>
32
#include <linux/ctype.h>
L
Linus Torvalds 已提交
33 34 35 36 37 38 39 40 41 42 43

/* selinuxfs pseudo filesystem for exporting the security policy API.
   Based on the proc code and the fs/nfsd/nfsctl.c code. */

#include "flask.h"
#include "avc.h"
#include "avc_ss.h"
#include "security.h"
#include "objsec.h"
#include "conditional.h"

44 45
/* Policy capability filenames */
static char *policycap_names[] = {
E
Eric Paris 已提交
46
	"network_peer_controls",
47 48 49
	"open_perms",
	"redhat1",
	"always_check_network"
50 51
};

L
Linus Torvalds 已提交
52 53 54 55
unsigned int selinux_checkreqprot = CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;

static int __init checkreqprot_setup(char *str)
{
56
	unsigned long checkreqprot;
57
	if (!kstrtoul(str, 0, &checkreqprot))
58
		selinux_checkreqprot = checkreqprot ? 1 : 0;
L
Linus Torvalds 已提交
59 60 61 62
	return 1;
}
__setup("checkreqprot=", checkreqprot_setup);

I
Ingo Molnar 已提交
63
static DEFINE_MUTEX(sel_mutex);
L
Linus Torvalds 已提交
64 65

/* global data for booleans */
66 67
static struct dentry *bool_dir;
static int bool_num;
S
Stephen Smalley 已提交
68
static char **bool_pending_names;
69
static int *bool_pending_values;
L
Linus Torvalds 已提交
70

71
/* global data for classes */
72
static struct dentry *class_dir;
73 74
static unsigned long last_class_ino;

75 76
static char policy_opened;

77
/* global data for policy capabilities */
78
static struct dentry *policycap_dir;
79

L
Linus Torvalds 已提交
80 81 82 83
/* Check whether a task is allowed to use a security operation. */
static int task_has_security(struct task_struct *tsk,
			     u32 perms)
{
84 85 86 87 88 89 90 91
	const struct task_security_struct *tsec;
	u32 sid = 0;

	rcu_read_lock();
	tsec = __task_cred(tsk)->security;
	if (tsec)
		sid = tsec->sid;
	rcu_read_unlock();
L
Linus Torvalds 已提交
92 93 94
	if (!tsec)
		return -EACCES;

95
	return avc_has_perm(sid, SECINITSID_SECURITY,
L
Linus Torvalds 已提交
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
			    SECCLASS_SECURITY, perms, NULL);
}

enum sel_inos {
	SEL_ROOT_INO = 2,
	SEL_LOAD,	/* load policy */
	SEL_ENFORCE,	/* get or set enforcing status */
	SEL_CONTEXT,	/* validate context */
	SEL_ACCESS,	/* compute access decision */
	SEL_CREATE,	/* compute create labeling decision */
	SEL_RELABEL,	/* compute relabeling decision */
	SEL_USER,	/* compute reachable user contexts */
	SEL_POLICYVERS,	/* return policy version for this kernel */
	SEL_COMMIT_BOOLS, /* commit new boolean values */
	SEL_MLS,	/* return if MLS policy is enabled */
	SEL_DISABLE,	/* disable SELinux until next reboot */
	SEL_MEMBER,	/* compute polyinstantiation membership decision */
	SEL_CHECKREQPROT, /* check requested protection, not kernel-applied one */
114
	SEL_COMPAT_NET,	/* whether to use old compat network packet controls */
115 116
	SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
	SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
117
	SEL_STATUS,	/* export current status using mmap() */
118
	SEL_POLICY,	/* allow userspace to read the in kernel policy */
119
	SEL_VALIDATE_TRANS, /* compute validatetrans decision */
120
	SEL_INO_NEXT,	/* The next inode number to use */
L
Linus Torvalds 已提交
121 122
};

123 124
static unsigned long sel_last_ino = SEL_INO_NEXT - 1;

125 126 127 128 129
#define SEL_INITCON_INO_OFFSET		0x01000000
#define SEL_BOOL_INO_OFFSET		0x02000000
#define SEL_CLASS_INO_OFFSET		0x04000000
#define SEL_POLICYCAP_INO_OFFSET	0x08000000
#define SEL_INO_MASK			0x00ffffff
130

L
Linus Torvalds 已提交
131 132 133 134 135 136 137 138 139 140 141 142
#define TMPBUFLEN	12
static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
				size_t count, loff_t *ppos)
{
	char tmpbuf[TMPBUFLEN];
	ssize_t length;

	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", selinux_enforcing);
	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}

#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
143
static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
L
Linus Torvalds 已提交
144 145 146
				 size_t count, loff_t *ppos)

{
147
	char *page = NULL;
L
Linus Torvalds 已提交
148 149 150
	ssize_t length;
	int new_value;

151
	if (count >= PAGE_SIZE)
A
Al Viro 已提交
152
		return -ENOMEM;
153 154 155

	/* No partial writes. */
	if (*ppos != 0)
A
Al Viro 已提交
156
		return -EINVAL;
157

A
Al Viro 已提交
158 159 160
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page))
		return PTR_ERR(page);
L
Linus Torvalds 已提交
161 162 163 164 165 166 167 168 169

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;

	if (new_value != selinux_enforcing) {
		length = task_has_security(current, SECURITY__SETENFORCE);
		if (length)
			goto out;
S
Steve Grubb 已提交
170
		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
171 172
			"enforcing=%d old_enforcing=%d auid=%u ses=%u",
			new_value, selinux_enforcing,
173
			from_kuid(&init_user_ns, audit_get_loginuid(current)),
174
			audit_get_sessionid(current));
L
Linus Torvalds 已提交
175 176 177 178
		selinux_enforcing = new_value;
		if (selinux_enforcing)
			avc_ss_reset(0);
		selnl_notify_setenforce(selinux_enforcing);
179
		selinux_status_update_setenforce(selinux_enforcing);
L
Linus Torvalds 已提交
180 181 182
	}
	length = count;
out:
A
Al Viro 已提交
183
	kfree(page);
L
Linus Torvalds 已提交
184 185 186 187 188 189
	return length;
}
#else
#define sel_write_enforce NULL
#endif

190
static const struct file_operations sel_enforce_ops = {
L
Linus Torvalds 已提交
191 192
	.read		= sel_read_enforce,
	.write		= sel_write_enforce,
A
Arnd Bergmann 已提交
193
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
194 195
};

196 197 198 199 200
static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
					size_t count, loff_t *ppos)
{
	char tmpbuf[TMPBUFLEN];
	ssize_t length;
A
Al Viro 已提交
201
	ino_t ino = file_inode(filp)->i_ino;
202 203 204 205 206 207 208 209 210
	int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
		security_get_reject_unknown() : !security_get_allow_unknown();

	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", handle_unknown);
	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}

static const struct file_operations sel_handle_unknown_ops = {
	.read		= sel_read_handle_unknown,
A
Arnd Bergmann 已提交
211
	.llseek		= generic_file_llseek,
212 213
};

214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
static int sel_open_handle_status(struct inode *inode, struct file *filp)
{
	struct page    *status = selinux_kernel_status_page();

	if (!status)
		return -ENOMEM;

	filp->private_data = status;

	return 0;
}

static ssize_t sel_read_handle_status(struct file *filp, char __user *buf,
				      size_t count, loff_t *ppos)
{
	struct page    *status = filp->private_data;

	BUG_ON(!status);

	return simple_read_from_buffer(buf, count, ppos,
				       page_address(status),
				       sizeof(struct selinux_kernel_status));
}

static int sel_mmap_handle_status(struct file *filp,
				  struct vm_area_struct *vma)
{
	struct page    *status = filp->private_data;
	unsigned long	size = vma->vm_end - vma->vm_start;

	BUG_ON(!status);

	/* only allows one page from the head */
	if (vma->vm_pgoff > 0 || size != PAGE_SIZE)
		return -EIO;
	/* disallow writable mapping */
	if (vma->vm_flags & VM_WRITE)
		return -EPERM;
	/* disallow mprotect() turns it into writable */
	vma->vm_flags &= ~VM_MAYWRITE;

	return remap_pfn_range(vma, vma->vm_start,
			       page_to_pfn(status),
			       size, vma->vm_page_prot);
}

static const struct file_operations sel_handle_status_ops = {
	.open		= sel_open_handle_status,
	.read		= sel_read_handle_status,
	.mmap		= sel_mmap_handle_status,
	.llseek		= generic_file_llseek,
};

L
Linus Torvalds 已提交
267
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
268
static ssize_t sel_write_disable(struct file *file, const char __user *buf,
L
Linus Torvalds 已提交
269 270 271
				 size_t count, loff_t *ppos)

{
A
Al Viro 已提交
272
	char *page;
L
Linus Torvalds 已提交
273 274 275
	ssize_t length;
	int new_value;

276
	if (count >= PAGE_SIZE)
A
Al Viro 已提交
277
		return -ENOMEM;
278 279 280

	/* No partial writes. */
	if (*ppos != 0)
A
Al Viro 已提交
281
		return -EINVAL;
282

A
Al Viro 已提交
283 284 285
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page))
		return PTR_ERR(page);
L
Linus Torvalds 已提交
286 287 288 289 290 291 292

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;

	if (new_value) {
		length = selinux_disable();
293
		if (length)
L
Linus Torvalds 已提交
294
			goto out;
S
Steve Grubb 已提交
295
		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
296
			"selinux=0 auid=%u ses=%u",
297
			from_kuid(&init_user_ns, audit_get_loginuid(current)),
298
			audit_get_sessionid(current));
L
Linus Torvalds 已提交
299 300 301 302
	}

	length = count;
out:
A
Al Viro 已提交
303
	kfree(page);
L
Linus Torvalds 已提交
304 305 306 307 308 309
	return length;
}
#else
#define sel_write_disable NULL
#endif

310
static const struct file_operations sel_disable_ops = {
L
Linus Torvalds 已提交
311
	.write		= sel_write_disable,
A
Arnd Bergmann 已提交
312
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
313 314 315
};

static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
316
				   size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
317 318 319 320 321 322 323 324
{
	char tmpbuf[TMPBUFLEN];
	ssize_t length;

	length = scnprintf(tmpbuf, TMPBUFLEN, "%u", POLICYDB_VERSION_MAX);
	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}

325
static const struct file_operations sel_policyvers_ops = {
L
Linus Torvalds 已提交
326
	.read		= sel_read_policyvers,
A
Arnd Bergmann 已提交
327
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
328 329 330 331
};

/* declaration for sel_write_load */
static int sel_make_bools(void);
332
static int sel_make_classes(void);
333
static int sel_make_policycap(void);
334 335

/* declaration for sel_make_class_dirs */
336
static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
337
			unsigned long *ino);
L
Linus Torvalds 已提交
338 339 340 341 342 343 344

static ssize_t sel_read_mls(struct file *filp, char __user *buf,
				size_t count, loff_t *ppos)
{
	char tmpbuf[TMPBUFLEN];
	ssize_t length;

345 346
	length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
			   security_mls_enabled());
L
Linus Torvalds 已提交
347 348 349
	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}

350
static const struct file_operations sel_mls_ops = {
L
Linus Torvalds 已提交
351
	.read		= sel_read_mls,
A
Arnd Bergmann 已提交
352
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
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
struct policy_load_memory {
	size_t len;
	void *data;
};

static int sel_open_policy(struct inode *inode, struct file *filp)
{
	struct policy_load_memory *plm = NULL;
	int rc;

	BUG_ON(filp->private_data);

	mutex_lock(&sel_mutex);

	rc = task_has_security(current, SECURITY__READ_POLICY);
	if (rc)
		goto err;

	rc = -EBUSY;
	if (policy_opened)
		goto err;

	rc = -ENOMEM;
	plm = kzalloc(sizeof(*plm), GFP_KERNEL);
	if (!plm)
		goto err;

	if (i_size_read(inode) != security_policydb_len()) {
A
Al Viro 已提交
383
		inode_lock(inode);
384
		i_size_write(inode, security_policydb_len());
A
Al Viro 已提交
385
		inode_unlock(inode);
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
	}

	rc = security_read_policy(&plm->data, &plm->len);
	if (rc)
		goto err;

	policy_opened = 1;

	filp->private_data = plm;

	mutex_unlock(&sel_mutex);

	return 0;
err:
	mutex_unlock(&sel_mutex);

	if (plm)
		vfree(plm->data);
	kfree(plm);
	return rc;
}

static int sel_release_policy(struct inode *inode, struct file *filp)
{
	struct policy_load_memory *plm = filp->private_data;

	BUG_ON(!plm);

	policy_opened = 0;

	vfree(plm->data);
	kfree(plm);

	return 0;
}

static ssize_t sel_read_policy(struct file *filp, char __user *buf,
			       size_t count, loff_t *ppos)
{
	struct policy_load_memory *plm = filp->private_data;
	int ret;

	mutex_lock(&sel_mutex);

	ret = task_has_security(current, SECURITY__READ_POLICY);
	if (ret)
		goto out;

	ret = simple_read_from_buffer(buf, count, ppos, plm->data, plm->len);
out:
	mutex_unlock(&sel_mutex);
	return ret;
}

440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
static int sel_mmap_policy_fault(struct vm_area_struct *vma,
				 struct vm_fault *vmf)
{
	struct policy_load_memory *plm = vma->vm_file->private_data;
	unsigned long offset;
	struct page *page;

	if (vmf->flags & (FAULT_FLAG_MKWRITE | FAULT_FLAG_WRITE))
		return VM_FAULT_SIGBUS;

	offset = vmf->pgoff << PAGE_SHIFT;
	if (offset >= roundup(plm->len, PAGE_SIZE))
		return VM_FAULT_SIGBUS;

	page = vmalloc_to_page(plm->data + offset);
	get_page(page);

	vmf->page = page;

	return 0;
}

462
static const struct vm_operations_struct sel_mmap_policy_ops = {
463 464 465 466
	.fault = sel_mmap_policy_fault,
	.page_mkwrite = sel_mmap_policy_fault,
};

467
static int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma)
468 469 470 471 472 473 474 475 476
{
	if (vma->vm_flags & VM_SHARED) {
		/* do not allow mprotect to make mapping writable */
		vma->vm_flags &= ~VM_MAYWRITE;

		if (vma->vm_flags & VM_WRITE)
			return -EACCES;
	}

477
	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
478 479 480 481 482
	vma->vm_ops = &sel_mmap_policy_ops;

	return 0;
}

483 484 485
static const struct file_operations sel_policy_ops = {
	.open		= sel_open_policy,
	.read		= sel_read_policy,
486
	.mmap		= sel_mmap_policy,
487
	.release	= sel_release_policy,
488
	.llseek		= generic_file_llseek,
489 490
};

491
static ssize_t sel_write_load(struct file *file, const char __user *buf,
L
Linus Torvalds 已提交
492 493 494 495 496 497
			      size_t count, loff_t *ppos)

{
	ssize_t length;
	void *data = NULL;

I
Ingo Molnar 已提交
498
	mutex_lock(&sel_mutex);
L
Linus Torvalds 已提交
499 500 501 502 503

	length = task_has_security(current, SECURITY__LOAD_POLICY);
	if (length)
		goto out;

504 505 506
	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
L
Linus Torvalds 已提交
507 508
		goto out;

509 510 511 512 513 514 515
	length = -EFBIG;
	if (count > 64 * 1024 * 1024)
		goto out;

	length = -ENOMEM;
	data = vmalloc(count);
	if (!data)
L
Linus Torvalds 已提交
516 517 518 519 520 521 522 523 524 525
		goto out;

	length = -EFAULT;
	if (copy_from_user(data, buf, count) != 0)
		goto out;

	length = security_load_policy(data, count);
	if (length)
		goto out;

526 527
	length = sel_make_bools();
	if (length)
528 529
		goto out1;

530 531
	length = sel_make_classes();
	if (length)
532 533
		goto out1;

534 535 536 537 538
	length = sel_make_policycap();
	if (length)
		goto out1;

	length = count;
539 540

out1:
S
Steve Grubb 已提交
541
	audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
542
		"policy loaded auid=%u ses=%u",
543
		from_kuid(&init_user_ns, audit_get_loginuid(current)),
544
		audit_get_sessionid(current));
L
Linus Torvalds 已提交
545
out:
I
Ingo Molnar 已提交
546
	mutex_unlock(&sel_mutex);
L
Linus Torvalds 已提交
547 548 549 550
	vfree(data);
	return length;
}

551
static const struct file_operations sel_load_ops = {
L
Linus Torvalds 已提交
552
	.write		= sel_write_load,
A
Arnd Bergmann 已提交
553
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
554 555
};

556
static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
L
Linus Torvalds 已提交
557
{
558
	char *canon = NULL;
559
	u32 sid, len;
L
Linus Torvalds 已提交
560 561 562 563
	ssize_t length;

	length = task_has_security(current, SECURITY__CHECK_CONTEXT);
	if (length)
564
		goto out;
L
Linus Torvalds 已提交
565

566
	length = security_context_to_sid(buf, size, &sid, GFP_KERNEL);
567 568
	if (length)
		goto out;
L
Linus Torvalds 已提交
569

570
	length = security_sid_to_context(sid, &canon, &len);
571 572
	if (length)
		goto out;
573

574
	length = -ERANGE;
575
	if (len > SIMPLE_TRANSACTION_LIMIT) {
E
Eric Paris 已提交
576 577
		printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
			"payload max\n", __func__, len);
L
Linus Torvalds 已提交
578
		goto out;
579
	}
L
Linus Torvalds 已提交
580

581 582
	memcpy(buf, canon, len);
	length = len;
L
Linus Torvalds 已提交
583
out:
584
	kfree(canon);
L
Linus Torvalds 已提交
585 586 587 588 589 590 591 592 593 594 595 596 597
	return length;
}

static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
				     size_t count, loff_t *ppos)
{
	char tmpbuf[TMPBUFLEN];
	ssize_t length;

	length = scnprintf(tmpbuf, TMPBUFLEN, "%u", selinux_checkreqprot);
	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}

598
static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
L
Linus Torvalds 已提交
599 600
				      size_t count, loff_t *ppos)
{
A
Al Viro 已提交
601
	char *page;
L
Linus Torvalds 已提交
602 603 604 605 606
	ssize_t length;
	unsigned int new_value;

	length = task_has_security(current, SECURITY__SETCHECKREQPROT);
	if (length)
A
Al Viro 已提交
607
		return length;
L
Linus Torvalds 已提交
608

609
	if (count >= PAGE_SIZE)
A
Al Viro 已提交
610
		return -ENOMEM;
611 612 613

	/* No partial writes. */
	if (*ppos != 0)
A
Al Viro 已提交
614
		return -EINVAL;
615

A
Al Viro 已提交
616 617 618
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page))
		return PTR_ERR(page);
L
Linus Torvalds 已提交
619 620 621 622 623 624 625 626

	length = -EINVAL;
	if (sscanf(page, "%u", &new_value) != 1)
		goto out;

	selinux_checkreqprot = new_value ? 1 : 0;
	length = count;
out:
A
Al Viro 已提交
627
	kfree(page);
L
Linus Torvalds 已提交
628 629
	return length;
}
630
static const struct file_operations sel_checkreqprot_ops = {
L
Linus Torvalds 已提交
631 632
	.read		= sel_read_checkreqprot,
	.write		= sel_write_checkreqprot,
A
Arnd Bergmann 已提交
633
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
634 635
};

636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
static ssize_t sel_write_validatetrans(struct file *file,
					const char __user *buf,
					size_t count, loff_t *ppos)
{
	char *oldcon = NULL, *newcon = NULL, *taskcon = NULL;
	char *req = NULL;
	u32 osid, nsid, tsid;
	u16 tclass;
	int rc;

	rc = task_has_security(current, SECURITY__VALIDATE_TRANS);
	if (rc)
		goto out;

	rc = -ENOMEM;
	if (count >= PAGE_SIZE)
		goto out;

	/* No partial writes. */
	rc = -EINVAL;
	if (*ppos != 0)
		goto out;

	rc = -ENOMEM;
	req = kzalloc(count + 1, GFP_KERNEL);
	if (!req)
		goto out;

	rc = -EFAULT;
	if (copy_from_user(req, buf, count))
		goto out;

	rc = -ENOMEM;
	oldcon = kzalloc(count + 1, GFP_KERNEL);
	if (!oldcon)
		goto out;

	newcon = kzalloc(count + 1, GFP_KERNEL);
	if (!newcon)
		goto out;

	taskcon = kzalloc(count + 1, GFP_KERNEL);
	if (!taskcon)
		goto out;

	rc = -EINVAL;
	if (sscanf(req, "%s %s %hu %s", oldcon, newcon, &tclass, taskcon) != 4)
		goto out;

	rc = security_context_str_to_sid(oldcon, &osid, GFP_KERNEL);
	if (rc)
		goto out;

	rc = security_context_str_to_sid(newcon, &nsid, GFP_KERNEL);
	if (rc)
		goto out;

	rc = security_context_str_to_sid(taskcon, &tsid, GFP_KERNEL);
	if (rc)
		goto out;

	rc = security_validate_transition_user(osid, nsid, tsid, tclass);
	if (!rc)
		rc = count;
out:
	kfree(req);
	kfree(oldcon);
	kfree(newcon);
	kfree(taskcon);
	return rc;
}

static const struct file_operations sel_transition_ops = {
	.write		= sel_write_validatetrans,
	.llseek		= generic_file_llseek,
};

L
Linus Torvalds 已提交
713 714 715
/*
 * Remaining nodes use transaction based IO methods like nfsd/nfsctl.c
 */
716 717 718 719 720
static ssize_t sel_write_access(struct file *file, char *buf, size_t size);
static ssize_t sel_write_create(struct file *file, char *buf, size_t size);
static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size);
static ssize_t sel_write_user(struct file *file, char *buf, size_t size);
static ssize_t sel_write_member(struct file *file, char *buf, size_t size);
L
Linus Torvalds 已提交
721 722 723 724 725 726 727

static ssize_t (*write_op[])(struct file *, char *, size_t) = {
	[SEL_ACCESS] = sel_write_access,
	[SEL_CREATE] = sel_write_create,
	[SEL_RELABEL] = sel_write_relabel,
	[SEL_USER] = sel_write_user,
	[SEL_MEMBER] = sel_write_member,
728
	[SEL_CONTEXT] = sel_write_context,
L
Linus Torvalds 已提交
729 730 731 732
};

static ssize_t selinux_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
{
A
Al Viro 已提交
733
	ino_t ino = file_inode(file)->i_ino;
L
Linus Torvalds 已提交
734 735 736
	char *data;
	ssize_t rv;

737
	if (ino >= ARRAY_SIZE(write_op) || !write_op[ino])
L
Linus Torvalds 已提交
738 739 740 741 742 743
		return -EINVAL;

	data = simple_transaction_get(file, buf, size);
	if (IS_ERR(data))
		return PTR_ERR(data);

744 745
	rv = write_op[ino](file, data, size);
	if (rv > 0) {
L
Linus Torvalds 已提交
746 747 748 749 750 751
		simple_transaction_set(file, rv);
		rv = size;
	}
	return rv;
}

752
static const struct file_operations transaction_ops = {
L
Linus Torvalds 已提交
753 754 755
	.write		= selinux_transaction_write,
	.read		= simple_transaction_read,
	.release	= simple_transaction_release,
A
Arnd Bergmann 已提交
756
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
757 758 759 760 761 762 763 764
};

/*
 * payload - write methods
 * If the method has a response, the response should be put in buf,
 * and the length returned.  Otherwise return 0 or and -error.
 */

765
static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
L
Linus Torvalds 已提交
766
{
767
	char *scon = NULL, *tcon = NULL;
L
Linus Torvalds 已提交
768 769 770 771 772 773 774
	u32 ssid, tsid;
	u16 tclass;
	struct av_decision avd;
	ssize_t length;

	length = task_has_security(current, SECURITY__COMPUTE_AV);
	if (length)
775
		goto out;
L
Linus Torvalds 已提交
776 777

	length = -ENOMEM;
778
	scon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
779
	if (!scon)
780
		goto out;
L
Linus Torvalds 已提交
781

782
	length = -ENOMEM;
783
	tcon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
784 785 786 787
	if (!tcon)
		goto out;

	length = -EINVAL;
788
	if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
789
		goto out;
L
Linus Torvalds 已提交
790

791
	length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
792 793 794
	if (length)
		goto out;

795
	length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
796 797
	if (length)
		goto out;
L
Linus Torvalds 已提交
798

799
	security_compute_av_user(ssid, tsid, tclass, &avd);
L
Linus Torvalds 已提交
800 801

	length = scnprintf(buf, SIMPLE_TRANSACTION_LIMIT,
802
			  "%x %x %x %x %u %x",
803
			  avd.allowed, 0xffffffff,
L
Linus Torvalds 已提交
804
			  avd.auditallow, avd.auditdeny,
805
			  avd.seqno, avd.flags);
L
Linus Torvalds 已提交
806
out:
807
	kfree(tcon);
L
Linus Torvalds 已提交
808 809 810 811
	kfree(scon);
	return length;
}

812
static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
L
Linus Torvalds 已提交
813
{
814
	char *scon = NULL, *tcon = NULL;
815
	char *namebuf = NULL, *objname = NULL;
L
Linus Torvalds 已提交
816 817 818
	u32 ssid, tsid, newsid;
	u16 tclass;
	ssize_t length;
819
	char *newcon = NULL;
L
Linus Torvalds 已提交
820
	u32 len;
821
	int nargs;
L
Linus Torvalds 已提交
822 823 824

	length = task_has_security(current, SECURITY__COMPUTE_CREATE);
	if (length)
825
		goto out;
L
Linus Torvalds 已提交
826 827

	length = -ENOMEM;
828
	scon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
829
	if (!scon)
830
		goto out;
L
Linus Torvalds 已提交
831

832
	length = -ENOMEM;
833
	tcon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
834 835 836
	if (!tcon)
		goto out;

837 838 839 840 841
	length = -ENOMEM;
	namebuf = kzalloc(size + 1, GFP_KERNEL);
	if (!namebuf)
		goto out;

L
Linus Torvalds 已提交
842
	length = -EINVAL;
843 844
	nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
	if (nargs < 3 || nargs > 4)
845
		goto out;
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862
	if (nargs == 4) {
		/*
		 * If and when the name of new object to be queried contains
		 * either whitespace or multibyte characters, they shall be
		 * encoded based on the percentage-encoding rule.
		 * If not encoded, the sscanf logic picks up only left-half
		 * of the supplied name; splitted by a whitespace unexpectedly.
		 */
		char   *r, *w;
		int     c1, c2;

		r = w = namebuf;
		do {
			c1 = *r++;
			if (c1 == '+')
				c1 = ' ';
			else if (c1 == '%') {
863 864
				c1 = hex_to_bin(*r++);
				if (c1 < 0)
865
					goto out;
866 867
				c2 = hex_to_bin(*r++);
				if (c2 < 0)
868 869 870 871 872 873
					goto out;
				c1 = (c1 << 4) | c2;
			}
			*w++ = c1;
		} while (c1 != '\0');

874
		objname = namebuf;
875
	}
L
Linus Torvalds 已提交
876

877
	length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
878 879 880
	if (length)
		goto out;

881
	length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
882 883
	if (length)
		goto out;
L
Linus Torvalds 已提交
884

885 886
	length = security_transition_sid_user(ssid, tsid, tclass,
					      objname, &newsid);
887 888
	if (length)
		goto out;
L
Linus Torvalds 已提交
889 890

	length = security_sid_to_context(newsid, &newcon, &len);
891 892
	if (length)
		goto out;
L
Linus Torvalds 已提交
893

894
	length = -ERANGE;
L
Linus Torvalds 已提交
895
	if (len > SIMPLE_TRANSACTION_LIMIT) {
E
Eric Paris 已提交
896 897
		printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
			"payload max\n", __func__, len);
898
		goto out;
L
Linus Torvalds 已提交
899 900 901 902
	}

	memcpy(buf, newcon, len);
	length = len;
903
out:
L
Linus Torvalds 已提交
904
	kfree(newcon);
905
	kfree(namebuf);
L
Linus Torvalds 已提交
906 907 908 909 910
	kfree(tcon);
	kfree(scon);
	return length;
}

911
static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
L
Linus Torvalds 已提交
912
{
913
	char *scon = NULL, *tcon = NULL;
L
Linus Torvalds 已提交
914 915 916
	u32 ssid, tsid, newsid;
	u16 tclass;
	ssize_t length;
917
	char *newcon = NULL;
L
Linus Torvalds 已提交
918 919 920 921
	u32 len;

	length = task_has_security(current, SECURITY__COMPUTE_RELABEL);
	if (length)
922
		goto out;
L
Linus Torvalds 已提交
923 924

	length = -ENOMEM;
925
	scon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
926
	if (!scon)
927
		goto out;
L
Linus Torvalds 已提交
928

929
	length = -ENOMEM;
930
	tcon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
931 932 933 934 935
	if (!tcon)
		goto out;

	length = -EINVAL;
	if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
936
		goto out;
L
Linus Torvalds 已提交
937

938
	length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
939 940 941
	if (length)
		goto out;

942
	length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
943 944
	if (length)
		goto out;
L
Linus Torvalds 已提交
945 946

	length = security_change_sid(ssid, tsid, tclass, &newsid);
947 948
	if (length)
		goto out;
L
Linus Torvalds 已提交
949 950

	length = security_sid_to_context(newsid, &newcon, &len);
951 952
	if (length)
		goto out;
L
Linus Torvalds 已提交
953

954 955 956
	length = -ERANGE;
	if (len > SIMPLE_TRANSACTION_LIMIT)
		goto out;
L
Linus Torvalds 已提交
957 958 959

	memcpy(buf, newcon, len);
	length = len;
960
out:
L
Linus Torvalds 已提交
961 962 963 964 965 966
	kfree(newcon);
	kfree(tcon);
	kfree(scon);
	return length;
}

967
static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
L
Linus Torvalds 已提交
968
{
969 970
	char *con = NULL, *user = NULL, *ptr;
	u32 sid, *sids = NULL;
L
Linus Torvalds 已提交
971 972 973 974 975 976 977
	ssize_t length;
	char *newcon;
	int i, rc;
	u32 len, nsids;

	length = task_has_security(current, SECURITY__COMPUTE_USER);
	if (length)
978
		goto out;
L
Linus Torvalds 已提交
979 980

	length = -ENOMEM;
981
	con = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
982
	if (!con)
983
		goto out;
L
Linus Torvalds 已提交
984

985
	length = -ENOMEM;
986
	user = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
987 988 989 990 991
	if (!user)
		goto out;

	length = -EINVAL;
	if (sscanf(buf, "%s %s", con, user) != 2)
992
		goto out;
L
Linus Torvalds 已提交
993

994
	length = security_context_str_to_sid(con, &sid, GFP_KERNEL);
995 996
	if (length)
		goto out;
L
Linus Torvalds 已提交
997 998

	length = security_get_user_sids(sid, user, &sids, &nsids);
999 1000
	if (length)
		goto out;
L
Linus Torvalds 已提交
1001 1002 1003 1004 1005 1006 1007

	length = sprintf(buf, "%u", nsids) + 1;
	ptr = buf + length;
	for (i = 0; i < nsids; i++) {
		rc = security_sid_to_context(sids[i], &newcon, &len);
		if (rc) {
			length = rc;
1008
			goto out;
L
Linus Torvalds 已提交
1009 1010 1011 1012
		}
		if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) {
			kfree(newcon);
			length = -ERANGE;
1013
			goto out;
L
Linus Torvalds 已提交
1014 1015 1016 1017 1018 1019
		}
		memcpy(ptr, newcon, len);
		kfree(newcon);
		ptr += len;
		length += len;
	}
1020
out:
L
Linus Torvalds 已提交
1021 1022 1023 1024 1025 1026
	kfree(sids);
	kfree(user);
	kfree(con);
	return length;
}

1027
static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
L
Linus Torvalds 已提交
1028
{
1029
	char *scon = NULL, *tcon = NULL;
L
Linus Torvalds 已提交
1030 1031 1032
	u32 ssid, tsid, newsid;
	u16 tclass;
	ssize_t length;
1033
	char *newcon = NULL;
L
Linus Torvalds 已提交
1034 1035 1036 1037
	u32 len;

	length = task_has_security(current, SECURITY__COMPUTE_MEMBER);
	if (length)
1038
		goto out;
L
Linus Torvalds 已提交
1039 1040

	length = -ENOMEM;
1041
	scon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
1042
	if (!scon)
1043
		goto out;
L
Linus Torvalds 已提交
1044

1045
	length = -ENOMEM;
1046
	tcon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
1047 1048 1049 1050 1051
	if (!tcon)
		goto out;

	length = -EINVAL;
	if (sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3)
1052
		goto out;
L
Linus Torvalds 已提交
1053

1054
	length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
1055 1056 1057
	if (length)
		goto out;

1058
	length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
1059 1060
	if (length)
		goto out;
L
Linus Torvalds 已提交
1061 1062

	length = security_member_sid(ssid, tsid, tclass, &newsid);
1063 1064
	if (length)
		goto out;
L
Linus Torvalds 已提交
1065 1066

	length = security_sid_to_context(newsid, &newcon, &len);
1067 1068
	if (length)
		goto out;
L
Linus Torvalds 已提交
1069

1070
	length = -ERANGE;
L
Linus Torvalds 已提交
1071
	if (len > SIMPLE_TRANSACTION_LIMIT) {
E
Eric Paris 已提交
1072 1073
		printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
			"payload max\n", __func__, len);
1074
		goto out;
L
Linus Torvalds 已提交
1075 1076 1077 1078
	}

	memcpy(buf, newcon, len);
	length = len;
1079
out:
L
Linus Torvalds 已提交
1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
	kfree(newcon);
	kfree(tcon);
	kfree(scon);
	return length;
}

static struct inode *sel_make_inode(struct super_block *sb, int mode)
{
	struct inode *ret = new_inode(sb);

	if (ret) {
		ret->i_mode = mode;
1092
		ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
L
Linus Torvalds 已提交
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
	}
	return ret;
}

static ssize_t sel_read_bool(struct file *filep, char __user *buf,
			     size_t count, loff_t *ppos)
{
	char *page = NULL;
	ssize_t length;
	ssize_t ret;
	int cur_enforcing;
A
Al Viro 已提交
1104
	unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
S
Stephen Smalley 已提交
1105
	const char *name = filep->f_path.dentry->d_name.name;
L
Linus Torvalds 已提交
1106

I
Ingo Molnar 已提交
1107
	mutex_lock(&sel_mutex);
L
Linus Torvalds 已提交
1108

1109 1110
	ret = -EINVAL;
	if (index >= bool_num || strcmp(name, bool_pending_names[index]))
S
Stephen Smalley 已提交
1111
		goto out;
L
Linus Torvalds 已提交
1112

1113
	ret = -ENOMEM;
1114
	page = (char *)get_zeroed_page(GFP_KERNEL);
1115
	if (!page)
L
Linus Torvalds 已提交
1116 1117
		goto out;

S
Stephen Smalley 已提交
1118
	cur_enforcing = security_get_bool_value(index);
L
Linus Torvalds 已提交
1119 1120 1121 1122 1123
	if (cur_enforcing < 0) {
		ret = cur_enforcing;
		goto out;
	}
	length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
S
Stephen Smalley 已提交
1124
			  bool_pending_values[index]);
1125
	ret = simple_read_from_buffer(buf, count, ppos, page, length);
L
Linus Torvalds 已提交
1126
out:
I
Ingo Molnar 已提交
1127
	mutex_unlock(&sel_mutex);
1128
	free_page((unsigned long)page);
L
Linus Torvalds 已提交
1129 1130 1131 1132 1133 1134 1135
	return ret;
}

static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
			      size_t count, loff_t *ppos)
{
	char *page = NULL;
S
Stephen Smalley 已提交
1136
	ssize_t length;
L
Linus Torvalds 已提交
1137
	int new_value;
A
Al Viro 已提交
1138
	unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
S
Stephen Smalley 已提交
1139
	const char *name = filep->f_path.dentry->d_name.name;
L
Linus Torvalds 已提交
1140

I
Ingo Molnar 已提交
1141
	mutex_lock(&sel_mutex);
L
Linus Torvalds 已提交
1142 1143 1144 1145 1146

	length = task_has_security(current, SECURITY__SETBOOL);
	if (length)
		goto out;

1147 1148
	length = -EINVAL;
	if (index >= bool_num || strcmp(name, bool_pending_names[index]))
S
Stephen Smalley 已提交
1149 1150
		goto out;

1151 1152
	length = -ENOMEM;
	if (count >= PAGE_SIZE)
L
Linus Torvalds 已提交
1153
		goto out;
S
Stephen Smalley 已提交
1154

1155 1156 1157
	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
L
Linus Torvalds 已提交
1158
		goto out;
1159

A
Al Viro 已提交
1160 1161 1162 1163
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page)) {
		length = PTR_ERR(page);
		page = NULL;
L
Linus Torvalds 已提交
1164
		goto out;
A
Al Viro 已提交
1165
	}
L
Linus Torvalds 已提交
1166 1167 1168 1169 1170 1171 1172 1173

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;

	if (new_value)
		new_value = 1;

S
Stephen Smalley 已提交
1174
	bool_pending_values[index] = new_value;
L
Linus Torvalds 已提交
1175 1176 1177
	length = count;

out:
I
Ingo Molnar 已提交
1178
	mutex_unlock(&sel_mutex);
A
Al Viro 已提交
1179
	kfree(page);
L
Linus Torvalds 已提交
1180 1181 1182
	return length;
}

1183
static const struct file_operations sel_bool_ops = {
1184 1185
	.read		= sel_read_bool,
	.write		= sel_write_bool,
A
Arnd Bergmann 已提交
1186
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
1187 1188 1189 1190 1191 1192 1193
};

static ssize_t sel_commit_bools_write(struct file *filep,
				      const char __user *buf,
				      size_t count, loff_t *ppos)
{
	char *page = NULL;
S
Stephen Smalley 已提交
1194
	ssize_t length;
L
Linus Torvalds 已提交
1195 1196
	int new_value;

I
Ingo Molnar 已提交
1197
	mutex_lock(&sel_mutex);
L
Linus Torvalds 已提交
1198 1199 1200 1201 1202

	length = task_has_security(current, SECURITY__SETBOOL);
	if (length)
		goto out;

1203 1204
	length = -ENOMEM;
	if (count >= PAGE_SIZE)
L
Linus Torvalds 已提交
1205
		goto out;
1206 1207 1208 1209

	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
L
Linus Torvalds 已提交
1210
		goto out;
1211

A
Al Viro 已提交
1212 1213 1214 1215
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page)) {
		length = PTR_ERR(page);
		page = NULL;
L
Linus Torvalds 已提交
1216
		goto out;
A
Al Viro 已提交
1217
	}
L
Linus Torvalds 已提交
1218 1219 1220 1221 1222

	length = -EINVAL;
	if (sscanf(page, "%d", &new_value) != 1)
		goto out;

1223
	length = 0;
1224
	if (new_value && bool_pending_values)
1225
		length = security_set_bools(bool_num, bool_pending_values);
L
Linus Torvalds 已提交
1226

1227 1228
	if (!length)
		length = count;
L
Linus Torvalds 已提交
1229 1230

out:
I
Ingo Molnar 已提交
1231
	mutex_unlock(&sel_mutex);
A
Al Viro 已提交
1232
	kfree(page);
L
Linus Torvalds 已提交
1233 1234 1235
	return length;
}

1236
static const struct file_operations sel_commit_bools_ops = {
1237
	.write		= sel_commit_bools_write,
A
Arnd Bergmann 已提交
1238
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
1239 1240
};

1241
static void sel_remove_entries(struct dentry *de)
L
Linus Torvalds 已提交
1242
{
1243 1244
	d_genocide(de);
	shrink_dcache_parent(de);
L
Linus Torvalds 已提交
1245 1246 1247 1248 1249 1250
}

#define BOOL_DIR_NAME "booleans"

static int sel_make_bools(void)
{
1251
	int i, ret;
L
Linus Torvalds 已提交
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
	ssize_t len;
	struct dentry *dentry = NULL;
	struct dentry *dir = bool_dir;
	struct inode *inode = NULL;
	struct inode_security_struct *isec;
	char **names = NULL, *page;
	int num;
	int *values = NULL;
	u32 sid;

	/* remove any existing files */
1263 1264
	for (i = 0; i < bool_num; i++)
		kfree(bool_pending_names[i]);
S
Stephen Smalley 已提交
1265
	kfree(bool_pending_names);
J
Jesper Juhl 已提交
1266
	kfree(bool_pending_values);
1267
	bool_num = 0;
S
Stephen Smalley 已提交
1268
	bool_pending_names = NULL;
1269
	bool_pending_values = NULL;
L
Linus Torvalds 已提交
1270

1271
	sel_remove_entries(dir);
L
Linus Torvalds 已提交
1272

1273
	ret = -ENOMEM;
1274 1275
	page = (char *)get_zeroed_page(GFP_KERNEL);
	if (!page)
1276
		goto out;
L
Linus Torvalds 已提交
1277 1278

	ret = security_get_bools(&num, &names, &values);
1279
	if (ret)
L
Linus Torvalds 已提交
1280 1281 1282
		goto out;

	for (i = 0; i < num; i++) {
1283
		ret = -ENOMEM;
L
Linus Torvalds 已提交
1284
		dentry = d_alloc_name(dir, names[i]);
1285 1286 1287 1288
		if (!dentry)
			goto out;

		ret = -ENOMEM;
L
Linus Torvalds 已提交
1289
		inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
1290 1291
		if (!inode)
			goto out;
L
Linus Torvalds 已提交
1292

1293
		ret = -ENAMETOOLONG;
A
Al Viro 已提交
1294
		len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
1295 1296 1297
		if (len >= PAGE_SIZE)
			goto out;

1298 1299 1300
		isec = (struct inode_security_struct *)inode->i_security;
		ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid);
		if (ret)
1301 1302
			goto out;

L
Linus Torvalds 已提交
1303
		isec->sid = sid;
A
Andreas Gruenbacher 已提交
1304
		isec->initialized = LABEL_INITIALIZED;
L
Linus Torvalds 已提交
1305
		inode->i_fop = &sel_bool_ops;
1306
		inode->i_ino = i|SEL_BOOL_INO_OFFSET;
L
Linus Torvalds 已提交
1307 1308 1309
		d_add(dentry, inode);
	}
	bool_num = num;
S
Stephen Smalley 已提交
1310
	bool_pending_names = names;
L
Linus Torvalds 已提交
1311
	bool_pending_values = values;
1312 1313 1314

	free_page((unsigned long)page);
	return 0;
L
Linus Torvalds 已提交
1315 1316
out:
	free_page((unsigned long)page);
1317

L
Linus Torvalds 已提交
1318
	if (names) {
J
Jesper Juhl 已提交
1319 1320
		for (i = 0; i < num; i++)
			kfree(names[i]);
L
Linus Torvalds 已提交
1321 1322
		kfree(names);
	}
1323
	kfree(values);
1324
	sel_remove_entries(dir);
1325 1326

	return ret;
L
Linus Torvalds 已提交
1327 1328 1329 1330
}

#define NULL_FILE_NAME "null"

1331
struct path selinux_null;
L
Linus Torvalds 已提交
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342

static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
					    size_t count, loff_t *ppos)
{
	char tmpbuf[TMPBUFLEN];
	ssize_t length;

	length = scnprintf(tmpbuf, TMPBUFLEN, "%u", avc_cache_threshold);
	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}

1343 1344
static ssize_t sel_write_avc_cache_threshold(struct file *file,
					     const char __user *buf,
L
Linus Torvalds 已提交
1345 1346 1347
					     size_t count, loff_t *ppos)

{
A
Al Viro 已提交
1348
	char *page;
L
Linus Torvalds 已提交
1349
	ssize_t ret;
H
Heinrich Schuchardt 已提交
1350
	unsigned int new_value;
L
Linus Torvalds 已提交
1351

1352 1353
	ret = task_has_security(current, SECURITY__SETSECPARAM);
	if (ret)
A
Al Viro 已提交
1354
		return ret;
L
Linus Torvalds 已提交
1355

1356
	if (count >= PAGE_SIZE)
A
Al Viro 已提交
1357
		return -ENOMEM;
L
Linus Torvalds 已提交
1358

1359 1360
	/* No partial writes. */
	if (*ppos != 0)
A
Al Viro 已提交
1361
		return -EINVAL;
L
Linus Torvalds 已提交
1362

A
Al Viro 已提交
1363 1364 1365
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page))
		return PTR_ERR(page);
L
Linus Torvalds 已提交
1366

1367 1368
	ret = -EINVAL;
	if (sscanf(page, "%u", &new_value) != 1)
L
Linus Torvalds 已提交
1369 1370
		goto out;

1371 1372
	avc_cache_threshold = new_value;

L
Linus Torvalds 已提交
1373 1374
	ret = count;
out:
A
Al Viro 已提交
1375
	kfree(page);
L
Linus Torvalds 已提交
1376 1377 1378 1379 1380 1381 1382
	return ret;
}

static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
				       size_t count, loff_t *ppos)
{
	char *page;
1383
	ssize_t length;
L
Linus Torvalds 已提交
1384 1385

	page = (char *)__get_free_page(GFP_KERNEL);
1386 1387 1388 1389 1390 1391
	if (!page)
		return -ENOMEM;

	length = avc_get_hash_stats(page);
	if (length >= 0)
		length = simple_read_from_buffer(buf, count, ppos, page, length);
L
Linus Torvalds 已提交
1392
	free_page((unsigned long)page);
1393 1394

	return length;
L
Linus Torvalds 已提交
1395 1396
}

1397
static const struct file_operations sel_avc_cache_threshold_ops = {
L
Linus Torvalds 已提交
1398 1399
	.read		= sel_read_avc_cache_threshold,
	.write		= sel_write_avc_cache_threshold,
A
Arnd Bergmann 已提交
1400
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
1401 1402
};

1403
static const struct file_operations sel_avc_hash_stats_ops = {
L
Linus Torvalds 已提交
1404
	.read		= sel_read_avc_hash_stats,
A
Arnd Bergmann 已提交
1405
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
1406 1407 1408 1409 1410 1411 1412
};

#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
static struct avc_cache_stats *sel_avc_get_stat_idx(loff_t *idx)
{
	int cpu;

1413
	for (cpu = *idx; cpu < nr_cpu_ids; ++cpu) {
L
Linus Torvalds 已提交
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
		if (!cpu_possible(cpu))
			continue;
		*idx = cpu + 1;
		return &per_cpu(avc_cache_stats, cpu);
	}
	return NULL;
}

static void *sel_avc_stats_seq_start(struct seq_file *seq, loff_t *pos)
{
	loff_t n = *pos - 1;

	if (*pos == 0)
		return SEQ_START_TOKEN;

	return sel_avc_get_stat_idx(&n);
}

static void *sel_avc_stats_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
	return sel_avc_get_stat_idx(pos);
}

static int sel_avc_stats_seq_show(struct seq_file *seq, void *v)
{
	struct avc_cache_stats *st = v;

	if (v == SEQ_START_TOKEN)
		seq_printf(seq, "lookups hits misses allocations reclaims "
			   "frees\n");
1444 1445 1446 1447 1448 1449
	else {
		unsigned int lookups = st->lookups;
		unsigned int misses = st->misses;
		unsigned int hits = lookups - misses;
		seq_printf(seq, "%u %u %u %u %u %u\n", lookups,
			   hits, misses, st->allocations,
L
Linus Torvalds 已提交
1450
			   st->reclaims, st->frees);
1451
	}
L
Linus Torvalds 已提交
1452 1453 1454 1455 1456 1457
	return 0;
}

static void sel_avc_stats_seq_stop(struct seq_file *seq, void *v)
{ }

1458
static const struct seq_operations sel_avc_cache_stats_seq_ops = {
L
Linus Torvalds 已提交
1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469
	.start		= sel_avc_stats_seq_start,
	.next		= sel_avc_stats_seq_next,
	.show		= sel_avc_stats_seq_show,
	.stop		= sel_avc_stats_seq_stop,
};

static int sel_open_avc_cache_stats(struct inode *inode, struct file *file)
{
	return seq_open(file, &sel_avc_cache_stats_seq_ops);
}

1470
static const struct file_operations sel_avc_cache_stats_ops = {
L
Linus Torvalds 已提交
1471 1472 1473 1474 1475 1476 1477 1478 1479
	.open		= sel_open_avc_cache_stats,
	.read		= seq_read,
	.llseek		= seq_lseek,
	.release	= seq_release,
};
#endif

static int sel_make_avc_files(struct dentry *dir)
{
1480
	int i;
L
Linus Torvalds 已提交
1481 1482 1483 1484 1485 1486 1487 1488 1489
	static struct tree_descr files[] = {
		{ "cache_threshold",
		  &sel_avc_cache_threshold_ops, S_IRUGO|S_IWUSR },
		{ "hash_stats", &sel_avc_hash_stats_ops, S_IRUGO },
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
		{ "cache_stats", &sel_avc_cache_stats_ops, S_IRUGO },
#endif
	};

1490
	for (i = 0; i < ARRAY_SIZE(files); i++) {
L
Linus Torvalds 已提交
1491 1492 1493 1494
		struct inode *inode;
		struct dentry *dentry;

		dentry = d_alloc_name(dir, files[i].name);
1495 1496
		if (!dentry)
			return -ENOMEM;
L
Linus Torvalds 已提交
1497 1498

		inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
1499 1500 1501
		if (!inode)
			return -ENOMEM;

L
Linus Torvalds 已提交
1502
		inode->i_fop = files[i].ops;
1503
		inode->i_ino = ++sel_last_ino;
L
Linus Torvalds 已提交
1504 1505
		d_add(dentry, inode);
	}
1506 1507

	return 0;
L
Linus Torvalds 已提交
1508 1509
}

1510
static ssize_t sel_read_initcon(struct file *file, char __user *buf,
1511 1512 1513 1514 1515 1516
				size_t count, loff_t *ppos)
{
	char *con;
	u32 sid, len;
	ssize_t ret;

A
Al Viro 已提交
1517
	sid = file_inode(file)->i_ino&SEL_INO_MASK;
1518
	ret = security_sid_to_context(sid, &con, &len);
1519
	if (ret)
1520 1521 1522 1523 1524 1525 1526 1527 1528
		return ret;

	ret = simple_read_from_buffer(buf, count, ppos, con, len);
	kfree(con);
	return ret;
}

static const struct file_operations sel_initcon_ops = {
	.read		= sel_read_initcon,
A
Arnd Bergmann 已提交
1529
	.llseek		= generic_file_llseek,
1530 1531 1532 1533
};

static int sel_make_initcon_files(struct dentry *dir)
{
1534
	int i;
1535 1536 1537 1538 1539

	for (i = 1; i <= SECINITSID_NUM; i++) {
		struct inode *inode;
		struct dentry *dentry;
		dentry = d_alloc_name(dir, security_get_initial_sid_context(i));
1540 1541
		if (!dentry)
			return -ENOMEM;
1542 1543

		inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
1544 1545 1546
		if (!inode)
			return -ENOMEM;

1547 1548 1549 1550
		inode->i_fop = &sel_initcon_ops;
		inode->i_ino = i|SEL_INITCON_INO_OFFSET;
		d_add(dentry, inode);
	}
1551 1552

	return 0;
1553 1554
}

1555 1556 1557 1558 1559 1560 1561
static inline unsigned long sel_class_to_ino(u16 class)
{
	return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET;
}

static inline u16 sel_ino_to_class(unsigned long ino)
{
1562
	return (ino & SEL_INO_MASK) / (SEL_VEC_MAX + 1);
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574
}

static inline unsigned long sel_perm_to_ino(u16 class, u32 perm)
{
	return (class * (SEL_VEC_MAX + 1) + perm) | SEL_CLASS_INO_OFFSET;
}

static inline u32 sel_ino_to_perm(unsigned long ino)
{
	return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1);
}

1575
static ssize_t sel_read_class(struct file *file, char __user *buf,
1576 1577
				size_t count, loff_t *ppos)
{
A
Al Viro 已提交
1578
	unsigned long ino = file_inode(file)->i_ino;
A
Al Viro 已提交
1579 1580 1581
	char res[TMPBUFLEN];
	ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_class(ino));
	return simple_read_from_buffer(buf, count, ppos, res, len);
1582 1583 1584 1585
}

static const struct file_operations sel_class_ops = {
	.read		= sel_read_class,
A
Arnd Bergmann 已提交
1586
	.llseek		= generic_file_llseek,
1587 1588
};

1589
static ssize_t sel_read_perm(struct file *file, char __user *buf,
1590 1591
				size_t count, loff_t *ppos)
{
A
Al Viro 已提交
1592
	unsigned long ino = file_inode(file)->i_ino;
A
Al Viro 已提交
1593 1594 1595
	char res[TMPBUFLEN];
	ssize_t len = snprintf(res, sizeof(res), "%d", sel_ino_to_perm(ino));
	return simple_read_from_buffer(buf, count, ppos, res, len);
1596 1597 1598 1599
}

static const struct file_operations sel_perm_ops = {
	.read		= sel_read_perm,
A
Arnd Bergmann 已提交
1600
	.llseek		= generic_file_llseek,
1601 1602
};

1603 1604 1605 1606 1607 1608
static ssize_t sel_read_policycap(struct file *file, char __user *buf,
				  size_t count, loff_t *ppos)
{
	int value;
	char tmpbuf[TMPBUFLEN];
	ssize_t length;
A
Al Viro 已提交
1609
	unsigned long i_ino = file_inode(file)->i_ino;
1610 1611 1612 1613 1614 1615 1616 1617 1618

	value = security_policycap_supported(i_ino & SEL_INO_MASK);
	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);

	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}

static const struct file_operations sel_policycap_ops = {
	.read		= sel_read_policycap,
A
Arnd Bergmann 已提交
1619
	.llseek		= generic_file_llseek,
1620 1621
};

1622 1623 1624
static int sel_make_perm_files(char *objclass, int classvalue,
				struct dentry *dir)
{
1625
	int i, rc, nperms;
1626 1627 1628 1629
	char **perms;

	rc = security_get_permissions(objclass, &perms, &nperms);
	if (rc)
1630
		return rc;
1631 1632 1633 1634 1635

	for (i = 0; i < nperms; i++) {
		struct inode *inode;
		struct dentry *dentry;

1636
		rc = -ENOMEM;
1637
		dentry = d_alloc_name(dir, perms[i]);
1638 1639
		if (!dentry)
			goto out;
1640

1641
		rc = -ENOMEM;
1642
		inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
1643 1644 1645
		if (!inode)
			goto out;

1646 1647
		inode->i_fop = &sel_perm_ops;
		/* i+1 since perm values are 1-indexed */
1648
		inode->i_ino = sel_perm_to_ino(classvalue, i + 1);
1649 1650
		d_add(dentry, inode);
	}
1651 1652
	rc = 0;
out:
1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666
	for (i = 0; i < nperms; i++)
		kfree(perms[i]);
	kfree(perms);
	return rc;
}

static int sel_make_class_dir_entries(char *classname, int index,
					struct dentry *dir)
{
	struct dentry *dentry = NULL;
	struct inode *inode = NULL;
	int rc;

	dentry = d_alloc_name(dir, "index");
1667 1668
	if (!dentry)
		return -ENOMEM;
1669 1670

	inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
1671 1672
	if (!inode)
		return -ENOMEM;
1673 1674 1675 1676 1677

	inode->i_fop = &sel_class_ops;
	inode->i_ino = sel_class_to_ino(index);
	d_add(dentry, inode);

1678 1679 1680
	dentry = sel_make_dir(dir, "perms", &last_class_ino);
	if (IS_ERR(dentry))
		return PTR_ERR(dentry);
1681 1682 1683 1684 1685 1686 1687 1688

	rc = sel_make_perm_files(classname, index, dentry);

	return rc;
}

static int sel_make_classes(void)
{
1689
	int rc, nclasses, i;
1690 1691 1692
	char **classes;

	/* delete any existing entries */
1693
	sel_remove_entries(class_dir);
1694 1695

	rc = security_get_classes(&classes, &nclasses);
1696 1697
	if (rc)
		return rc;
1698 1699

	/* +2 since classes are 1-indexed */
1700
	last_class_ino = sel_class_to_ino(nclasses + 2);
1701 1702 1703 1704

	for (i = 0; i < nclasses; i++) {
		struct dentry *class_name_dir;

1705
		class_name_dir = sel_make_dir(class_dir, classes[i],
1706
				&last_class_ino);
1707 1708
		if (IS_ERR(class_name_dir)) {
			rc = PTR_ERR(class_name_dir);
1709
			goto out;
1710
		}
1711 1712

		/* i+1 since class values are 1-indexed */
1713
		rc = sel_make_class_dir_entries(classes[i], i + 1,
1714 1715
				class_name_dir);
		if (rc)
1716
			goto out;
1717
	}
1718 1719
	rc = 0;
out:
1720 1721 1722 1723 1724 1725
	for (i = 0; i < nclasses; i++)
		kfree(classes[i]);
	kfree(classes);
	return rc;
}

1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755
static int sel_make_policycap(void)
{
	unsigned int iter;
	struct dentry *dentry = NULL;
	struct inode *inode = NULL;

	sel_remove_entries(policycap_dir);

	for (iter = 0; iter <= POLICYDB_CAPABILITY_MAX; iter++) {
		if (iter < ARRAY_SIZE(policycap_names))
			dentry = d_alloc_name(policycap_dir,
					      policycap_names[iter]);
		else
			dentry = d_alloc_name(policycap_dir, "unknown");

		if (dentry == NULL)
			return -ENOMEM;

		inode = sel_make_inode(policycap_dir->d_sb, S_IFREG | S_IRUGO);
		if (inode == NULL)
			return -ENOMEM;

		inode->i_fop = &sel_policycap_ops;
		inode->i_ino = iter | SEL_POLICYCAP_INO_OFFSET;
		d_add(dentry, inode);
	}

	return 0;
}

1756
static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
1757
			unsigned long *ino)
L
Linus Torvalds 已提交
1758
{
1759
	struct dentry *dentry = d_alloc_name(dir, name);
L
Linus Torvalds 已提交
1760 1761
	struct inode *inode;

1762 1763 1764 1765 1766 1767 1768 1769
	if (!dentry)
		return ERR_PTR(-ENOMEM);

	inode = sel_make_inode(dir->d_sb, S_IFDIR | S_IRUGO | S_IXUGO);
	if (!inode) {
		dput(dentry);
		return ERR_PTR(-ENOMEM);
	}
1770

L
Linus Torvalds 已提交
1771 1772
	inode->i_op = &simple_dir_inode_operations;
	inode->i_fop = &simple_dir_operations;
1773
	inode->i_ino = ++(*ino);
1774
	/* directory inodes start off with i_nlink == 2 (for "." entry) */
1775
	inc_nlink(inode);
L
Linus Torvalds 已提交
1776
	d_add(dentry, inode);
1777
	/* bump link count on parent directory, too */
1778
	inc_nlink(d_inode(dir));
1779

1780
	return dentry;
L
Linus Torvalds 已提交
1781 1782
}

1783
static int sel_fill_super(struct super_block *sb, void *data, int silent)
L
Linus Torvalds 已提交
1784 1785 1786
{
	int ret;
	struct dentry *dentry;
1787
	struct inode *inode;
L
Linus Torvalds 已提交
1788 1789 1790 1791 1792
	struct inode_security_struct *isec;

	static struct tree_descr selinux_files[] = {
		[SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
		[SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR},
1793
		[SEL_CONTEXT] = {"context", &transaction_ops, S_IRUGO|S_IWUGO},
L
Linus Torvalds 已提交
1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
		[SEL_ACCESS] = {"access", &transaction_ops, S_IRUGO|S_IWUGO},
		[SEL_CREATE] = {"create", &transaction_ops, S_IRUGO|S_IWUGO},
		[SEL_RELABEL] = {"relabel", &transaction_ops, S_IRUGO|S_IWUGO},
		[SEL_USER] = {"user", &transaction_ops, S_IRUGO|S_IWUGO},
		[SEL_POLICYVERS] = {"policyvers", &sel_policyvers_ops, S_IRUGO},
		[SEL_COMMIT_BOOLS] = {"commit_pending_bools", &sel_commit_bools_ops, S_IWUSR},
		[SEL_MLS] = {"mls", &sel_mls_ops, S_IRUGO},
		[SEL_DISABLE] = {"disable", &sel_disable_ops, S_IWUSR},
		[SEL_MEMBER] = {"member", &transaction_ops, S_IRUGO|S_IWUGO},
		[SEL_CHECKREQPROT] = {"checkreqprot", &sel_checkreqprot_ops, S_IRUGO|S_IWUSR},
1804 1805
		[SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
		[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
1806
		[SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
1807
		[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
1808 1809
		[SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
					S_IWUGO},
L
Linus Torvalds 已提交
1810 1811 1812 1813
		/* last one */ {""}
	};
	ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
	if (ret)
1814
		goto err;
L
Linus Torvalds 已提交
1815

1816 1817 1818 1819
	bool_dir = sel_make_dir(sb->s_root, BOOL_DIR_NAME, &sel_last_ino);
	if (IS_ERR(bool_dir)) {
		ret = PTR_ERR(bool_dir);
		bool_dir = NULL;
1820
		goto err;
1821
	}
L
Linus Torvalds 已提交
1822

1823
	ret = -ENOMEM;
L
Linus Torvalds 已提交
1824
	dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
1825
	if (!dentry)
1826
		goto err;
L
Linus Torvalds 已提交
1827

1828
	ret = -ENOMEM;
L
Linus Torvalds 已提交
1829
	inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
1830
	if (!inode)
1831
		goto err;
1832

1833
	inode->i_ino = ++sel_last_ino;
1834
	isec = (struct inode_security_struct *)inode->i_security;
L
Linus Torvalds 已提交
1835 1836
	isec->sid = SECINITSID_DEVNULL;
	isec->sclass = SECCLASS_CHR_FILE;
A
Andreas Gruenbacher 已提交
1837
	isec->initialized = LABEL_INITIALIZED;
L
Linus Torvalds 已提交
1838 1839 1840

	init_special_inode(inode, S_IFCHR | S_IRUGO | S_IWUGO, MKDEV(MEM_MAJOR, 3));
	d_add(dentry, inode);
1841
	selinux_null.dentry = dentry;
L
Linus Torvalds 已提交
1842

1843 1844 1845
	dentry = sel_make_dir(sb->s_root, "avc", &sel_last_ino);
	if (IS_ERR(dentry)) {
		ret = PTR_ERR(dentry);
1846
		goto err;
1847
	}
L
Linus Torvalds 已提交
1848 1849 1850

	ret = sel_make_avc_files(dentry);
	if (ret)
1851
		goto err;
1852

1853 1854 1855
	dentry = sel_make_dir(sb->s_root, "initial_contexts", &sel_last_ino);
	if (IS_ERR(dentry)) {
		ret = PTR_ERR(dentry);
1856
		goto err;
1857
	}
1858 1859 1860 1861 1862

	ret = sel_make_initcon_files(dentry);
	if (ret)
		goto err;

1863 1864 1865 1866
	class_dir = sel_make_dir(sb->s_root, "class", &sel_last_ino);
	if (IS_ERR(class_dir)) {
		ret = PTR_ERR(class_dir);
		class_dir = NULL;
1867
		goto err;
1868
	}
1869

1870 1871 1872 1873
	policycap_dir = sel_make_dir(sb->s_root, "policy_capabilities", &sel_last_ino);
	if (IS_ERR(policycap_dir)) {
		ret = PTR_ERR(policycap_dir);
		policycap_dir = NULL;
1874
		goto err;
1875
	}
1876
	return 0;
1877
err:
E
Eric Paris 已提交
1878 1879
	printk(KERN_ERR "SELinux: %s:  failed while creating inodes\n",
		__func__);
1880
	return ret;
L
Linus Torvalds 已提交
1881 1882
}

A
Al Viro 已提交
1883 1884
static struct dentry *sel_mount(struct file_system_type *fs_type,
		      int flags, const char *dev_name, void *data)
L
Linus Torvalds 已提交
1885
{
A
Al Viro 已提交
1886
	return mount_single(fs_type, flags, data, sel_fill_super);
L
Linus Torvalds 已提交
1887 1888 1889 1890
}

static struct file_system_type sel_fs_type = {
	.name		= "selinuxfs",
A
Al Viro 已提交
1891
	.mount		= sel_mount,
L
Linus Torvalds 已提交
1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902
	.kill_sb	= kill_litter_super,
};

struct vfsmount *selinuxfs_mount;

static int __init init_sel_fs(void)
{
	int err;

	if (!selinux_enabled)
		return 0;
1903

1904 1905 1906
	err = sysfs_create_mount_point(fs_kobj, "selinux");
	if (err)
		return err;
1907

L
Linus Torvalds 已提交
1908
	err = register_filesystem(&sel_fs_type);
1909
	if (err) {
1910
		sysfs_remove_mount_point(fs_kobj, "selinux");
1911
		return err;
1912
	}
1913

1914
	selinux_null.mnt = selinuxfs_mount = kern_mount(&sel_fs_type);
1915 1916 1917 1918
	if (IS_ERR(selinuxfs_mount)) {
		printk(KERN_ERR "selinuxfs:  could not mount!\n");
		err = PTR_ERR(selinuxfs_mount);
		selinuxfs_mount = NULL;
L
Linus Torvalds 已提交
1919
	}
1920

L
Linus Torvalds 已提交
1921 1922 1923 1924 1925 1926 1927 1928
	return err;
}

__initcall(init_sel_fs);

#ifdef CONFIG_SECURITY_SELINUX_DISABLE
void exit_sel_fs(void)
{
1929
	sysfs_remove_mount_point(fs_kobj, "selinux");
1930
	kern_unmount(selinuxfs_mount);
L
Linus Torvalds 已提交
1931 1932 1933
	unregister_filesystem(&sel_fs_type);
}
#endif