selinuxfs.c 43.6 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
	"open_perms",
48
	"extended_socket_class",
49 50
	"always_check_network",
	"cgroup_seclabel"
51 52
};

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

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

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

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

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

76 77
static char policy_opened;

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

L
Linus Torvalds 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
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 */
96
	SEL_COMPAT_NET,	/* whether to use old compat network packet controls */
97 98
	SEL_REJECT_UNKNOWN, /* export unknown reject handling to userspace */
	SEL_DENY_UNKNOWN, /* export unknown deny handling to userspace */
99
	SEL_STATUS,	/* export current status using mmap() */
100
	SEL_POLICY,	/* allow userspace to read the in kernel policy */
101
	SEL_VALIDATE_TRANS, /* compute validatetrans decision */
102
	SEL_INO_NEXT,	/* The next inode number to use */
L
Linus Torvalds 已提交
103 104
};

105 106
static unsigned long sel_last_ino = SEL_INO_NEXT - 1;

107 108 109 110 111
#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
112

L
Linus Torvalds 已提交
113 114 115 116 117 118 119 120 121 122 123 124
#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
125
static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
L
Linus Torvalds 已提交
126 127 128
				 size_t count, loff_t *ppos)

{
129
	char *page = NULL;
L
Linus Torvalds 已提交
130 131 132
	ssize_t length;
	int new_value;

133
	if (count >= PAGE_SIZE)
A
Al Viro 已提交
134
		return -ENOMEM;
135 136 137

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

A
Al Viro 已提交
140 141 142
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page))
		return PTR_ERR(page);
L
Linus Torvalds 已提交
143 144 145 146 147

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

148 149
	new_value = !!new_value;

L
Linus Torvalds 已提交
150
	if (new_value != selinux_enforcing) {
151 152 153
		length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
				      SECCLASS_SECURITY, SECURITY__SETENFORCE,
				      NULL);
L
Linus Torvalds 已提交
154 155
		if (length)
			goto out;
S
Steve Grubb 已提交
156
		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
157 158
			"enforcing=%d old_enforcing=%d auid=%u ses=%u",
			new_value, selinux_enforcing,
159
			from_kuid(&init_user_ns, audit_get_loginuid(current)),
160
			audit_get_sessionid(current));
L
Linus Torvalds 已提交
161 162 163 164
		selinux_enforcing = new_value;
		if (selinux_enforcing)
			avc_ss_reset(0);
		selnl_notify_setenforce(selinux_enforcing);
165
		selinux_status_update_setenforce(selinux_enforcing);
L
Linus Torvalds 已提交
166 167 168
	}
	length = count;
out:
A
Al Viro 已提交
169
	kfree(page);
L
Linus Torvalds 已提交
170 171 172 173 174 175
	return length;
}
#else
#define sel_write_enforce NULL
#endif

176
static const struct file_operations sel_enforce_ops = {
L
Linus Torvalds 已提交
177 178
	.read		= sel_read_enforce,
	.write		= sel_write_enforce,
A
Arnd Bergmann 已提交
179
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
180 181
};

182 183 184 185 186
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 已提交
187
	ino_t ino = file_inode(filp)->i_ino;
188 189 190 191 192 193 194 195 196
	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 已提交
197
	.llseek		= generic_file_llseek,
198 199
};

200 201 202 203 204 205 206 207 208 209 210 211 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
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 已提交
253
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
254
static ssize_t sel_write_disable(struct file *file, const char __user *buf,
L
Linus Torvalds 已提交
255 256 257
				 size_t count, loff_t *ppos)

{
A
Al Viro 已提交
258
	char *page;
L
Linus Torvalds 已提交
259 260 261
	ssize_t length;
	int new_value;

262
	if (count >= PAGE_SIZE)
A
Al Viro 已提交
263
		return -ENOMEM;
264 265 266

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

A
Al Viro 已提交
269 270 271
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page))
		return PTR_ERR(page);
L
Linus Torvalds 已提交
272 273 274 275 276 277 278

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

	if (new_value) {
		length = selinux_disable();
279
		if (length)
L
Linus Torvalds 已提交
280
			goto out;
S
Steve Grubb 已提交
281
		audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
282
			"selinux=0 auid=%u ses=%u",
283
			from_kuid(&init_user_ns, audit_get_loginuid(current)),
284
			audit_get_sessionid(current));
L
Linus Torvalds 已提交
285 286 287 288
	}

	length = count;
out:
A
Al Viro 已提交
289
	kfree(page);
L
Linus Torvalds 已提交
290 291 292 293 294 295
	return length;
}
#else
#define sel_write_disable NULL
#endif

296
static const struct file_operations sel_disable_ops = {
L
Linus Torvalds 已提交
297
	.write		= sel_write_disable,
A
Arnd Bergmann 已提交
298
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
299 300 301
};

static ssize_t sel_read_policyvers(struct file *filp, char __user *buf,
302
				   size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
303 304 305 306 307 308 309 310
{
	char tmpbuf[TMPBUFLEN];
	ssize_t length;

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

311
static const struct file_operations sel_policyvers_ops = {
L
Linus Torvalds 已提交
312
	.read		= sel_read_policyvers,
A
Arnd Bergmann 已提交
313
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
314 315 316 317
};

/* declaration for sel_write_load */
static int sel_make_bools(void);
318
static int sel_make_classes(void);
319
static int sel_make_policycap(void);
320 321

/* declaration for sel_make_class_dirs */
322
static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
323
			unsigned long *ino);
L
Linus Torvalds 已提交
324 325 326 327 328 329 330

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

331 332
	length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
			   security_mls_enabled());
L
Linus Torvalds 已提交
333 334 335
	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}

336
static const struct file_operations sel_mls_ops = {
L
Linus Torvalds 已提交
337
	.read		= sel_read_mls,
A
Arnd Bergmann 已提交
338
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
339 340
};

341 342 343 344 345 346 347 348 349 350 351 352 353 354
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);

355 356
	rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			  SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
357 358 359 360 361 362 363 364 365 366 367 368 369
	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 已提交
370
		inode_lock(inode);
371
		i_size_write(inode, security_policydb_len());
A
Al Viro 已提交
372
		inode_unlock(inode);
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
	}

	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);

417 418
	ret = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			  SECCLASS_SECURITY, SECURITY__READ_POLICY, NULL);
419 420 421 422 423 424 425 426 427
	if (ret)
		goto out;

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

428
static int sel_mmap_policy_fault(struct vm_fault *vmf)
429
{
430
	struct policy_load_memory *plm = vmf->vma->vm_file->private_data;
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
	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;
}

449
static const struct vm_operations_struct sel_mmap_policy_ops = {
450 451 452 453
	.fault = sel_mmap_policy_fault,
	.page_mkwrite = sel_mmap_policy_fault,
};

454
static int sel_mmap_policy(struct file *filp, struct vm_area_struct *vma)
455 456 457 458 459 460 461 462 463
{
	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;
	}

464
	vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
465 466 467 468 469
	vma->vm_ops = &sel_mmap_policy_ops;

	return 0;
}

470 471 472
static const struct file_operations sel_policy_ops = {
	.open		= sel_open_policy,
	.read		= sel_read_policy,
473
	.mmap		= sel_mmap_policy,
474
	.release	= sel_release_policy,
475
	.llseek		= generic_file_llseek,
476 477
};

478
static ssize_t sel_write_load(struct file *file, const char __user *buf,
L
Linus Torvalds 已提交
479 480 481 482 483 484
			      size_t count, loff_t *ppos)

{
	ssize_t length;
	void *data = NULL;

I
Ingo Molnar 已提交
485
	mutex_lock(&sel_mutex);
L
Linus Torvalds 已提交
486

487 488
	length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			      SECCLASS_SECURITY, SECURITY__LOAD_POLICY, NULL);
L
Linus Torvalds 已提交
489 490 491
	if (length)
		goto out;

492 493 494
	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
L
Linus Torvalds 已提交
495 496
		goto out;

497 498 499 500 501 502 503
	length = -EFBIG;
	if (count > 64 * 1024 * 1024)
		goto out;

	length = -ENOMEM;
	data = vmalloc(count);
	if (!data)
L
Linus Torvalds 已提交
504 505 506 507 508 509 510
		goto out;

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

	length = security_load_policy(data, count);
511 512
	if (length) {
		pr_warn_ratelimited("SELinux: failed to load policy\n");
L
Linus Torvalds 已提交
513
		goto out;
514
	}
L
Linus Torvalds 已提交
515

516
	length = sel_make_bools();
517 518
	if (length) {
		pr_err("SELinux: failed to load policy booleans\n");
519
		goto out1;
520
	}
521

522
	length = sel_make_classes();
523 524
	if (length) {
		pr_err("SELinux: failed to load policy classes\n");
525
		goto out1;
526
	}
527

528
	length = sel_make_policycap();
529 530
	if (length) {
		pr_err("SELinux: failed to load policy capabilities\n");
531
		goto out1;
532
	}
533 534

	length = count;
535 536

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

547
static const struct file_operations sel_load_ops = {
L
Linus Torvalds 已提交
548
	.write		= sel_write_load,
A
Arnd Bergmann 已提交
549
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
550 551
};

552
static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
L
Linus Torvalds 已提交
553
{
554
	char *canon = NULL;
555
	u32 sid, len;
L
Linus Torvalds 已提交
556 557
	ssize_t length;

558 559
	length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			      SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
L
Linus Torvalds 已提交
560
	if (length)
561
		goto out;
L
Linus Torvalds 已提交
562

563
	length = security_context_to_sid(buf, size, &sid, GFP_KERNEL);
564 565
	if (length)
		goto out;
L
Linus Torvalds 已提交
566

567
	length = security_sid_to_context(sid, &canon, &len);
568 569
	if (length)
		goto out;
570

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

578 579
	memcpy(buf, canon, len);
	length = len;
L
Linus Torvalds 已提交
580
out:
581
	kfree(canon);
L
Linus Torvalds 已提交
582 583 584 585 586 587 588 589 590 591 592 593 594
	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);
}

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

602 603 604
	length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			      SECCLASS_SECURITY, SECURITY__SETCHECKREQPROT,
			      NULL);
L
Linus Torvalds 已提交
605
	if (length)
A
Al Viro 已提交
606
		return length;
L
Linus Torvalds 已提交
607

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

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

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

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

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

635 636 637 638 639 640 641 642 643 644
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;

645 646
	rc = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			  SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
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
	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
	u32 ssid, tsid;
	u16 tclass;
	struct av_decision avd;
	ssize_t length;

773 774
	length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			      SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
L
Linus Torvalds 已提交
775
	if (length)
776
		goto out;
L
Linus Torvalds 已提交
777 778

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

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

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

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

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

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

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

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

824 825 826
	length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			      SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
			      NULL);
L
Linus Torvalds 已提交
827
	if (length)
828
		goto out;
L
Linus Torvalds 已提交
829 830

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

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

840 841 842 843 844
	length = -ENOMEM;
	namebuf = kzalloc(size + 1, GFP_KERNEL);
	if (!namebuf)
		goto out;

L
Linus Torvalds 已提交
845
	length = -EINVAL;
846 847
	nargs = sscanf(buf, "%s %s %hu %s", scon, tcon, &tclass, namebuf);
	if (nargs < 3 || nargs > 4)
848
		goto out;
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
	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 == '%') {
866 867
				c1 = hex_to_bin(*r++);
				if (c1 < 0)
868
					goto out;
869 870
				c2 = hex_to_bin(*r++);
				if (c2 < 0)
871 872 873 874 875 876
					goto out;
				c1 = (c1 << 4) | c2;
			}
			*w++ = c1;
		} while (c1 != '\0');

877
		objname = namebuf;
878
	}
L
Linus Torvalds 已提交
879

880
	length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
881 882 883
	if (length)
		goto out;

884
	length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
885 886
	if (length)
		goto out;
L
Linus Torvalds 已提交
887

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

	length = security_sid_to_context(newsid, &newcon, &len);
894 895
	if (length)
		goto out;
L
Linus Torvalds 已提交
896

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

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

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

923 924 925
	length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			      SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
			      NULL);
L
Linus Torvalds 已提交
926
	if (length)
927
		goto out;
L
Linus Torvalds 已提交
928 929

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

934
	length = -ENOMEM;
935
	tcon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
936 937 938 939 940
	if (!tcon)
		goto out;

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

943
	length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
944 945 946
	if (length)
		goto out;

947
	length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
948 949
	if (length)
		goto out;
L
Linus Torvalds 已提交
950 951

	length = security_change_sid(ssid, tsid, tclass, &newsid);
952 953
	if (length)
		goto out;
L
Linus Torvalds 已提交
954 955

	length = security_sid_to_context(newsid, &newcon, &len);
956 957
	if (length)
		goto out;
L
Linus Torvalds 已提交
958

959 960 961
	length = -ERANGE;
	if (len > SIMPLE_TRANSACTION_LIMIT)
		goto out;
L
Linus Torvalds 已提交
962 963 964

	memcpy(buf, newcon, len);
	length = len;
965
out:
L
Linus Torvalds 已提交
966 967 968 969 970 971
	kfree(newcon);
	kfree(tcon);
	kfree(scon);
	return length;
}

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

981 982 983
	length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			      SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
			      NULL);
L
Linus Torvalds 已提交
984
	if (length)
985
		goto out;
L
Linus Torvalds 已提交
986 987

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

992
	length = -ENOMEM;
993
	user = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
994 995 996 997 998
	if (!user)
		goto out;

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

1001
	length = security_context_str_to_sid(con, &sid, GFP_KERNEL);
1002 1003
	if (length)
		goto out;
L
Linus Torvalds 已提交
1004 1005

	length = security_get_user_sids(sid, user, &sids, &nsids);
1006 1007
	if (length)
		goto out;
L
Linus Torvalds 已提交
1008 1009 1010 1011 1012 1013 1014

	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;
1015
			goto out;
L
Linus Torvalds 已提交
1016 1017 1018 1019
		}
		if ((length + len) >= SIMPLE_TRANSACTION_LIMIT) {
			kfree(newcon);
			length = -ERANGE;
1020
			goto out;
L
Linus Torvalds 已提交
1021 1022 1023 1024 1025 1026
		}
		memcpy(ptr, newcon, len);
		kfree(newcon);
		ptr += len;
		length += len;
	}
1027
out:
L
Linus Torvalds 已提交
1028 1029 1030 1031 1032 1033
	kfree(sids);
	kfree(user);
	kfree(con);
	return length;
}

1034
static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
L
Linus Torvalds 已提交
1035
{
1036
	char *scon = NULL, *tcon = NULL;
L
Linus Torvalds 已提交
1037 1038 1039
	u32 ssid, tsid, newsid;
	u16 tclass;
	ssize_t length;
1040
	char *newcon = NULL;
L
Linus Torvalds 已提交
1041 1042
	u32 len;

1043 1044 1045
	length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			      SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
			      NULL);
L
Linus Torvalds 已提交
1046
	if (length)
1047
		goto out;
L
Linus Torvalds 已提交
1048 1049

	length = -ENOMEM;
1050
	scon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
1051
	if (!scon)
1052
		goto out;
L
Linus Torvalds 已提交
1053

1054
	length = -ENOMEM;
1055
	tcon = kzalloc(size + 1, GFP_KERNEL);
L
Linus Torvalds 已提交
1056 1057 1058 1059 1060
	if (!tcon)
		goto out;

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

1063
	length = security_context_str_to_sid(scon, &ssid, GFP_KERNEL);
1064 1065 1066
	if (length)
		goto out;

1067
	length = security_context_str_to_sid(tcon, &tsid, GFP_KERNEL);
1068 1069
	if (length)
		goto out;
L
Linus Torvalds 已提交
1070 1071

	length = security_member_sid(ssid, tsid, tclass, &newsid);
1072 1073
	if (length)
		goto out;
L
Linus Torvalds 已提交
1074 1075

	length = security_sid_to_context(newsid, &newcon, &len);
1076 1077
	if (length)
		goto out;
L
Linus Torvalds 已提交
1078

1079
	length = -ERANGE;
L
Linus Torvalds 已提交
1080
	if (len > SIMPLE_TRANSACTION_LIMIT) {
E
Eric Paris 已提交
1081 1082
		printk(KERN_ERR "SELinux: %s:  context size (%u) exceeds "
			"payload max\n", __func__, len);
1083
		goto out;
L
Linus Torvalds 已提交
1084 1085 1086 1087
	}

	memcpy(buf, newcon, len);
	length = len;
1088
out:
L
Linus Torvalds 已提交
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100
	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;
1101
		ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
L
Linus Torvalds 已提交
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
	}
	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 已提交
1113
	unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
S
Stephen Smalley 已提交
1114
	const char *name = filep->f_path.dentry->d_name.name;
L
Linus Torvalds 已提交
1115

I
Ingo Molnar 已提交
1116
	mutex_lock(&sel_mutex);
L
Linus Torvalds 已提交
1117

1118 1119
	ret = -EINVAL;
	if (index >= bool_num || strcmp(name, bool_pending_names[index]))
S
Stephen Smalley 已提交
1120
		goto out;
L
Linus Torvalds 已提交
1121

1122
	ret = -ENOMEM;
1123
	page = (char *)get_zeroed_page(GFP_KERNEL);
1124
	if (!page)
L
Linus Torvalds 已提交
1125 1126
		goto out;

S
Stephen Smalley 已提交
1127
	cur_enforcing = security_get_bool_value(index);
L
Linus Torvalds 已提交
1128 1129 1130 1131 1132
	if (cur_enforcing < 0) {
		ret = cur_enforcing;
		goto out;
	}
	length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
S
Stephen Smalley 已提交
1133
			  bool_pending_values[index]);
1134
	ret = simple_read_from_buffer(buf, count, ppos, page, length);
L
Linus Torvalds 已提交
1135
out:
I
Ingo Molnar 已提交
1136
	mutex_unlock(&sel_mutex);
1137
	free_page((unsigned long)page);
L
Linus Torvalds 已提交
1138 1139 1140 1141 1142 1143 1144
	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 已提交
1145
	ssize_t length;
L
Linus Torvalds 已提交
1146
	int new_value;
A
Al Viro 已提交
1147
	unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
S
Stephen Smalley 已提交
1148
	const char *name = filep->f_path.dentry->d_name.name;
L
Linus Torvalds 已提交
1149

I
Ingo Molnar 已提交
1150
	mutex_lock(&sel_mutex);
L
Linus Torvalds 已提交
1151

1152 1153 1154
	length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			      SECCLASS_SECURITY, SECURITY__SETBOOL,
			      NULL);
L
Linus Torvalds 已提交
1155 1156 1157
	if (length)
		goto out;

1158 1159
	length = -EINVAL;
	if (index >= bool_num || strcmp(name, bool_pending_names[index]))
S
Stephen Smalley 已提交
1160 1161
		goto out;

1162 1163
	length = -ENOMEM;
	if (count >= PAGE_SIZE)
L
Linus Torvalds 已提交
1164
		goto out;
S
Stephen Smalley 已提交
1165

1166 1167 1168
	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
L
Linus Torvalds 已提交
1169
		goto out;
1170

A
Al Viro 已提交
1171 1172 1173 1174
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page)) {
		length = PTR_ERR(page);
		page = NULL;
L
Linus Torvalds 已提交
1175
		goto out;
A
Al Viro 已提交
1176
	}
L
Linus Torvalds 已提交
1177 1178 1179 1180 1181 1182 1183 1184

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

	if (new_value)
		new_value = 1;

S
Stephen Smalley 已提交
1185
	bool_pending_values[index] = new_value;
L
Linus Torvalds 已提交
1186 1187 1188
	length = count;

out:
I
Ingo Molnar 已提交
1189
	mutex_unlock(&sel_mutex);
A
Al Viro 已提交
1190
	kfree(page);
L
Linus Torvalds 已提交
1191 1192 1193
	return length;
}

1194
static const struct file_operations sel_bool_ops = {
1195 1196
	.read		= sel_read_bool,
	.write		= sel_write_bool,
A
Arnd Bergmann 已提交
1197
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
1198 1199 1200 1201 1202 1203 1204
};

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 已提交
1205
	ssize_t length;
L
Linus Torvalds 已提交
1206 1207
	int new_value;

I
Ingo Molnar 已提交
1208
	mutex_lock(&sel_mutex);
L
Linus Torvalds 已提交
1209

1210 1211 1212
	length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			      SECCLASS_SECURITY, SECURITY__SETBOOL,
			      NULL);
L
Linus Torvalds 已提交
1213 1214 1215
	if (length)
		goto out;

1216 1217
	length = -ENOMEM;
	if (count >= PAGE_SIZE)
L
Linus Torvalds 已提交
1218
		goto out;
1219 1220 1221 1222

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

A
Al Viro 已提交
1225 1226 1227 1228
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page)) {
		length = PTR_ERR(page);
		page = NULL;
L
Linus Torvalds 已提交
1229
		goto out;
A
Al Viro 已提交
1230
	}
L
Linus Torvalds 已提交
1231 1232 1233 1234 1235

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

1236
	length = 0;
1237
	if (new_value && bool_pending_values)
1238
		length = security_set_bools(bool_num, bool_pending_values);
L
Linus Torvalds 已提交
1239

1240 1241
	if (!length)
		length = count;
L
Linus Torvalds 已提交
1242 1243

out:
I
Ingo Molnar 已提交
1244
	mutex_unlock(&sel_mutex);
A
Al Viro 已提交
1245
	kfree(page);
L
Linus Torvalds 已提交
1246 1247 1248
	return length;
}

1249
static const struct file_operations sel_commit_bools_ops = {
1250
	.write		= sel_commit_bools_write,
A
Arnd Bergmann 已提交
1251
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
1252 1253
};

1254
static void sel_remove_entries(struct dentry *de)
L
Linus Torvalds 已提交
1255
{
1256 1257
	d_genocide(de);
	shrink_dcache_parent(de);
L
Linus Torvalds 已提交
1258 1259 1260 1261 1262 1263
}

#define BOOL_DIR_NAME "booleans"

static int sel_make_bools(void)
{
1264
	int i, ret;
L
Linus Torvalds 已提交
1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275
	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 */
1276 1277
	for (i = 0; i < bool_num; i++)
		kfree(bool_pending_names[i]);
S
Stephen Smalley 已提交
1278
	kfree(bool_pending_names);
J
Jesper Juhl 已提交
1279
	kfree(bool_pending_values);
1280
	bool_num = 0;
S
Stephen Smalley 已提交
1281
	bool_pending_names = NULL;
1282
	bool_pending_values = NULL;
L
Linus Torvalds 已提交
1283

1284
	sel_remove_entries(dir);
L
Linus Torvalds 已提交
1285

1286
	ret = -ENOMEM;
1287 1288
	page = (char *)get_zeroed_page(GFP_KERNEL);
	if (!page)
1289
		goto out;
L
Linus Torvalds 已提交
1290 1291

	ret = security_get_bools(&num, &names, &values);
1292
	if (ret)
L
Linus Torvalds 已提交
1293 1294 1295
		goto out;

	for (i = 0; i < num; i++) {
1296
		ret = -ENOMEM;
L
Linus Torvalds 已提交
1297
		dentry = d_alloc_name(dir, names[i]);
1298 1299 1300 1301
		if (!dentry)
			goto out;

		ret = -ENOMEM;
L
Linus Torvalds 已提交
1302
		inode = sel_make_inode(dir->d_sb, S_IFREG | S_IRUGO | S_IWUSR);
1303 1304
		if (!inode)
			goto out;
L
Linus Torvalds 已提交
1305

1306
		ret = -ENAMETOOLONG;
A
Al Viro 已提交
1307
		len = snprintf(page, PAGE_SIZE, "/%s/%s", BOOL_DIR_NAME, names[i]);
1308 1309 1310
		if (len >= PAGE_SIZE)
			goto out;

1311 1312
		isec = (struct inode_security_struct *)inode->i_security;
		ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid);
1313
		if (ret) {
1314 1315 1316
			pr_warn_ratelimited("SELinux: no sid found, defaulting to security isid for %s\n",
					   page);
			sid = SECINITSID_SECURITY;
1317 1318
		}

L
Linus Torvalds 已提交
1319
		isec->sid = sid;
A
Andreas Gruenbacher 已提交
1320
		isec->initialized = LABEL_INITIALIZED;
L
Linus Torvalds 已提交
1321
		inode->i_fop = &sel_bool_ops;
1322
		inode->i_ino = i|SEL_BOOL_INO_OFFSET;
L
Linus Torvalds 已提交
1323 1324 1325
		d_add(dentry, inode);
	}
	bool_num = num;
S
Stephen Smalley 已提交
1326
	bool_pending_names = names;
L
Linus Torvalds 已提交
1327
	bool_pending_values = values;
1328 1329 1330

	free_page((unsigned long)page);
	return 0;
L
Linus Torvalds 已提交
1331 1332
out:
	free_page((unsigned long)page);
1333

L
Linus Torvalds 已提交
1334
	if (names) {
J
Jesper Juhl 已提交
1335 1336
		for (i = 0; i < num; i++)
			kfree(names[i]);
L
Linus Torvalds 已提交
1337 1338
		kfree(names);
	}
1339
	kfree(values);
1340
	sel_remove_entries(dir);
1341 1342

	return ret;
L
Linus Torvalds 已提交
1343 1344 1345 1346
}

#define NULL_FILE_NAME "null"

1347
struct path selinux_null;
L
Linus Torvalds 已提交
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358

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);
}

1359 1360
static ssize_t sel_write_avc_cache_threshold(struct file *file,
					     const char __user *buf,
L
Linus Torvalds 已提交
1361 1362 1363
					     size_t count, loff_t *ppos)

{
A
Al Viro 已提交
1364
	char *page;
L
Linus Torvalds 已提交
1365
	ssize_t ret;
H
Heinrich Schuchardt 已提交
1366
	unsigned int new_value;
L
Linus Torvalds 已提交
1367

1368 1369 1370
	ret = avc_has_perm(current_sid(), SECINITSID_SECURITY,
			   SECCLASS_SECURITY, SECURITY__SETSECPARAM,
			   NULL);
1371
	if (ret)
A
Al Viro 已提交
1372
		return ret;
L
Linus Torvalds 已提交
1373

1374
	if (count >= PAGE_SIZE)
A
Al Viro 已提交
1375
		return -ENOMEM;
L
Linus Torvalds 已提交
1376

1377 1378
	/* No partial writes. */
	if (*ppos != 0)
A
Al Viro 已提交
1379
		return -EINVAL;
L
Linus Torvalds 已提交
1380

A
Al Viro 已提交
1381 1382 1383
	page = memdup_user_nul(buf, count);
	if (IS_ERR(page))
		return PTR_ERR(page);
L
Linus Torvalds 已提交
1384

1385 1386
	ret = -EINVAL;
	if (sscanf(page, "%u", &new_value) != 1)
L
Linus Torvalds 已提交
1387 1388
		goto out;

1389 1390
	avc_cache_threshold = new_value;

L
Linus Torvalds 已提交
1391 1392
	ret = count;
out:
A
Al Viro 已提交
1393
	kfree(page);
L
Linus Torvalds 已提交
1394 1395 1396 1397 1398 1399 1400
	return ret;
}

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

	page = (char *)__get_free_page(GFP_KERNEL);
1404 1405 1406 1407 1408 1409
	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 已提交
1410
	free_page((unsigned long)page);
1411 1412

	return length;
L
Linus Torvalds 已提交
1413 1414
}

1415
static const struct file_operations sel_avc_cache_threshold_ops = {
L
Linus Torvalds 已提交
1416 1417
	.read		= sel_read_avc_cache_threshold,
	.write		= sel_write_avc_cache_threshold,
A
Arnd Bergmann 已提交
1418
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
1419 1420
};

1421
static const struct file_operations sel_avc_hash_stats_ops = {
L
Linus Torvalds 已提交
1422
	.read		= sel_read_avc_hash_stats,
A
Arnd Bergmann 已提交
1423
	.llseek		= generic_file_llseek,
L
Linus Torvalds 已提交
1424 1425 1426 1427 1428 1429 1430
};

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

1431
	for (cpu = *idx; cpu < nr_cpu_ids; ++cpu) {
L
Linus Torvalds 已提交
1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
		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");
1462 1463 1464 1465 1466 1467
	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 已提交
1468
			   st->reclaims, st->frees);
1469
	}
L
Linus Torvalds 已提交
1470 1471 1472 1473 1474 1475
	return 0;
}

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

1476
static const struct seq_operations sel_avc_cache_stats_seq_ops = {
L
Linus Torvalds 已提交
1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
	.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);
}

1488
static const struct file_operations sel_avc_cache_stats_ops = {
L
Linus Torvalds 已提交
1489 1490 1491 1492 1493 1494 1495 1496 1497
	.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)
{
1498
	int i;
1499
	static const struct tree_descr files[] = {
L
Linus Torvalds 已提交
1500 1501 1502 1503 1504 1505 1506 1507
		{ "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
	};

1508
	for (i = 0; i < ARRAY_SIZE(files); i++) {
L
Linus Torvalds 已提交
1509 1510 1511 1512
		struct inode *inode;
		struct dentry *dentry;

		dentry = d_alloc_name(dir, files[i].name);
1513 1514
		if (!dentry)
			return -ENOMEM;
L
Linus Torvalds 已提交
1515 1516

		inode = sel_make_inode(dir->d_sb, S_IFREG|files[i].mode);
1517 1518 1519
		if (!inode)
			return -ENOMEM;

L
Linus Torvalds 已提交
1520
		inode->i_fop = files[i].ops;
1521
		inode->i_ino = ++sel_last_ino;
L
Linus Torvalds 已提交
1522 1523
		d_add(dentry, inode);
	}
1524 1525

	return 0;
L
Linus Torvalds 已提交
1526 1527
}

1528
static ssize_t sel_read_initcon(struct file *file, char __user *buf,
1529 1530 1531 1532 1533 1534
				size_t count, loff_t *ppos)
{
	char *con;
	u32 sid, len;
	ssize_t ret;

A
Al Viro 已提交
1535
	sid = file_inode(file)->i_ino&SEL_INO_MASK;
1536
	ret = security_sid_to_context(sid, &con, &len);
1537
	if (ret)
1538 1539 1540 1541 1542 1543 1544 1545 1546
		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 已提交
1547
	.llseek		= generic_file_llseek,
1548 1549 1550 1551
};

static int sel_make_initcon_files(struct dentry *dir)
{
1552
	int i;
1553 1554 1555 1556 1557

	for (i = 1; i <= SECINITSID_NUM; i++) {
		struct inode *inode;
		struct dentry *dentry;
		dentry = d_alloc_name(dir, security_get_initial_sid_context(i));
1558 1559
		if (!dentry)
			return -ENOMEM;
1560 1561

		inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
1562 1563 1564
		if (!inode)
			return -ENOMEM;

1565 1566 1567 1568
		inode->i_fop = &sel_initcon_ops;
		inode->i_ino = i|SEL_INITCON_INO_OFFSET;
		d_add(dentry, inode);
	}
1569 1570

	return 0;
1571 1572
}

1573 1574 1575 1576 1577 1578 1579
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)
{
1580
	return (ino & SEL_INO_MASK) / (SEL_VEC_MAX + 1);
1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
}

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);
}

1593
static ssize_t sel_read_class(struct file *file, char __user *buf,
1594 1595
				size_t count, loff_t *ppos)
{
A
Al Viro 已提交
1596
	unsigned long ino = file_inode(file)->i_ino;
A
Al Viro 已提交
1597 1598 1599
	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);
1600 1601 1602 1603
}

static const struct file_operations sel_class_ops = {
	.read		= sel_read_class,
A
Arnd Bergmann 已提交
1604
	.llseek		= generic_file_llseek,
1605 1606
};

1607
static ssize_t sel_read_perm(struct file *file, char __user *buf,
1608 1609
				size_t count, loff_t *ppos)
{
A
Al Viro 已提交
1610
	unsigned long ino = file_inode(file)->i_ino;
A
Al Viro 已提交
1611 1612 1613
	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);
1614 1615 1616 1617
}

static const struct file_operations sel_perm_ops = {
	.read		= sel_read_perm,
A
Arnd Bergmann 已提交
1618
	.llseek		= generic_file_llseek,
1619 1620
};

1621 1622 1623 1624 1625 1626
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 已提交
1627
	unsigned long i_ino = file_inode(file)->i_ino;
1628 1629 1630 1631 1632 1633 1634 1635 1636

	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 已提交
1637
	.llseek		= generic_file_llseek,
1638 1639
};

1640 1641 1642
static int sel_make_perm_files(char *objclass, int classvalue,
				struct dentry *dir)
{
1643
	int i, rc, nperms;
1644 1645 1646 1647
	char **perms;

	rc = security_get_permissions(objclass, &perms, &nperms);
	if (rc)
1648
		return rc;
1649 1650 1651 1652 1653

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

1654
		rc = -ENOMEM;
1655
		dentry = d_alloc_name(dir, perms[i]);
1656 1657
		if (!dentry)
			goto out;
1658

1659
		rc = -ENOMEM;
1660
		inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
1661 1662 1663
		if (!inode)
			goto out;

1664 1665
		inode->i_fop = &sel_perm_ops;
		/* i+1 since perm values are 1-indexed */
1666
		inode->i_ino = sel_perm_to_ino(classvalue, i + 1);
1667 1668
		d_add(dentry, inode);
	}
1669 1670
	rc = 0;
out:
1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684
	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");
1685 1686
	if (!dentry)
		return -ENOMEM;
1687 1688

	inode = sel_make_inode(dir->d_sb, S_IFREG|S_IRUGO);
1689 1690
	if (!inode)
		return -ENOMEM;
1691 1692 1693 1694 1695

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

1696 1697 1698
	dentry = sel_make_dir(dir, "perms", &last_class_ino);
	if (IS_ERR(dentry))
		return PTR_ERR(dentry);
1699 1700 1701 1702 1703 1704 1705 1706

	rc = sel_make_perm_files(classname, index, dentry);

	return rc;
}

static int sel_make_classes(void)
{
1707
	int rc, nclasses, i;
1708 1709 1710
	char **classes;

	/* delete any existing entries */
1711
	sel_remove_entries(class_dir);
1712 1713

	rc = security_get_classes(&classes, &nclasses);
1714 1715
	if (rc)
		return rc;
1716 1717

	/* +2 since classes are 1-indexed */
1718
	last_class_ino = sel_class_to_ino(nclasses + 2);
1719 1720 1721 1722

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

1723
		class_name_dir = sel_make_dir(class_dir, classes[i],
1724
				&last_class_ino);
1725 1726
		if (IS_ERR(class_name_dir)) {
			rc = PTR_ERR(class_name_dir);
1727
			goto out;
1728
		}
1729 1730

		/* i+1 since class values are 1-indexed */
1731
		rc = sel_make_class_dir_entries(classes[i], i + 1,
1732 1733
				class_name_dir);
		if (rc)
1734
			goto out;
1735
	}
1736 1737
	rc = 0;
out:
1738 1739 1740 1741 1742 1743
	for (i = 0; i < nclasses; i++)
		kfree(classes[i]);
	kfree(classes);
	return rc;
}

1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773
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;
}

1774
static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
1775
			unsigned long *ino)
L
Linus Torvalds 已提交
1776
{
1777
	struct dentry *dentry = d_alloc_name(dir, name);
L
Linus Torvalds 已提交
1778 1779
	struct inode *inode;

1780 1781 1782 1783 1784 1785 1786 1787
	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);
	}
1788

L
Linus Torvalds 已提交
1789 1790
	inode->i_op = &simple_dir_inode_operations;
	inode->i_fop = &simple_dir_operations;
1791
	inode->i_ino = ++(*ino);
1792
	/* directory inodes start off with i_nlink == 2 (for "." entry) */
1793
	inc_nlink(inode);
L
Linus Torvalds 已提交
1794
	d_add(dentry, inode);
1795
	/* bump link count on parent directory, too */
1796
	inc_nlink(d_inode(dir));
1797

1798
	return dentry;
L
Linus Torvalds 已提交
1799 1800
}

1801
static int sel_fill_super(struct super_block *sb, void *data, int silent)
L
Linus Torvalds 已提交
1802 1803 1804
{
	int ret;
	struct dentry *dentry;
1805
	struct inode *inode;
L
Linus Torvalds 已提交
1806 1807
	struct inode_security_struct *isec;

1808
	static const struct tree_descr selinux_files[] = {
L
Linus Torvalds 已提交
1809 1810
		[SEL_LOAD] = {"load", &sel_load_ops, S_IRUSR|S_IWUSR},
		[SEL_ENFORCE] = {"enforce", &sel_enforce_ops, S_IRUGO|S_IWUSR},
1811
		[SEL_CONTEXT] = {"context", &transaction_ops, S_IRUGO|S_IWUGO},
L
Linus Torvalds 已提交
1812 1813 1814 1815 1816 1817 1818 1819 1820 1821
		[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},
1822 1823
		[SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO},
		[SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO},
1824
		[SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO},
1825
		[SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO},
1826 1827
		[SEL_VALIDATE_TRANS] = {"validatetrans", &sel_transition_ops,
					S_IWUGO},
L
Linus Torvalds 已提交
1828 1829 1830 1831
		/* last one */ {""}
	};
	ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files);
	if (ret)
1832
		goto err;
L
Linus Torvalds 已提交
1833

1834 1835 1836 1837
	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;
1838
		goto err;
1839
	}
L
Linus Torvalds 已提交
1840

1841
	ret = -ENOMEM;
L
Linus Torvalds 已提交
1842
	dentry = d_alloc_name(sb->s_root, NULL_FILE_NAME);
1843
	if (!dentry)
1844
		goto err;
L
Linus Torvalds 已提交
1845

1846
	ret = -ENOMEM;
L
Linus Torvalds 已提交
1847
	inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
1848
	if (!inode)
1849
		goto err;
1850

1851
	inode->i_ino = ++sel_last_ino;
1852
	isec = (struct inode_security_struct *)inode->i_security;
L
Linus Torvalds 已提交
1853 1854
	isec->sid = SECINITSID_DEVNULL;
	isec->sclass = SECCLASS_CHR_FILE;
A
Andreas Gruenbacher 已提交
1855
	isec->initialized = LABEL_INITIALIZED;
L
Linus Torvalds 已提交
1856 1857 1858

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

1861 1862 1863
	dentry = sel_make_dir(sb->s_root, "avc", &sel_last_ino);
	if (IS_ERR(dentry)) {
		ret = PTR_ERR(dentry);
1864
		goto err;
1865
	}
L
Linus Torvalds 已提交
1866 1867 1868

	ret = sel_make_avc_files(dentry);
	if (ret)
1869
		goto err;
1870

1871 1872 1873
	dentry = sel_make_dir(sb->s_root, "initial_contexts", &sel_last_ino);
	if (IS_ERR(dentry)) {
		ret = PTR_ERR(dentry);
1874
		goto err;
1875
	}
1876 1877 1878 1879 1880

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

1881 1882 1883 1884
	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;
1885
		goto err;
1886
	}
1887

1888 1889 1890 1891
	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;
1892
		goto err;
1893
	}
1894
	return 0;
1895
err:
E
Eric Paris 已提交
1896 1897
	printk(KERN_ERR "SELinux: %s:  failed while creating inodes\n",
		__func__);
1898
	return ret;
L
Linus Torvalds 已提交
1899 1900
}

A
Al Viro 已提交
1901 1902
static struct dentry *sel_mount(struct file_system_type *fs_type,
		      int flags, const char *dev_name, void *data)
L
Linus Torvalds 已提交
1903
{
A
Al Viro 已提交
1904
	return mount_single(fs_type, flags, data, sel_fill_super);
L
Linus Torvalds 已提交
1905 1906 1907 1908
}

static struct file_system_type sel_fs_type = {
	.name		= "selinuxfs",
A
Al Viro 已提交
1909
	.mount		= sel_mount,
L
Linus Torvalds 已提交
1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920
	.kill_sb	= kill_litter_super,
};

struct vfsmount *selinuxfs_mount;

static int __init init_sel_fs(void)
{
	int err;

	if (!selinux_enabled)
		return 0;
1921

1922 1923 1924
	err = sysfs_create_mount_point(fs_kobj, "selinux");
	if (err)
		return err;
1925

L
Linus Torvalds 已提交
1926
	err = register_filesystem(&sel_fs_type);
1927
	if (err) {
1928
		sysfs_remove_mount_point(fs_kobj, "selinux");
1929
		return err;
1930
	}
1931

1932
	selinux_null.mnt = selinuxfs_mount = kern_mount(&sel_fs_type);
1933 1934 1935 1936
	if (IS_ERR(selinuxfs_mount)) {
		printk(KERN_ERR "selinuxfs:  could not mount!\n");
		err = PTR_ERR(selinuxfs_mount);
		selinuxfs_mount = NULL;
L
Linus Torvalds 已提交
1937
	}
1938

L
Linus Torvalds 已提交
1939 1940 1941 1942 1943 1944 1945 1946
	return err;
}

__initcall(init_sel_fs);

#ifdef CONFIG_SECURITY_SELINUX_DISABLE
void exit_sel_fs(void)
{
1947
	sysfs_remove_mount_point(fs_kobj, "selinux");
1948
	kern_unmount(selinuxfs_mount);
L
Linus Torvalds 已提交
1949 1950 1951
	unregister_filesystem(&sel_fs_type);
}
#endif