hooks.c 159 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
2
3
4
5
6
/*
 *  NSA Security-Enhanced Linux (SELinux) security module
 *
 *  This file contains the SELinux hook function implementations.
 *
 *  Authors:  Stephen Smalley, <sds@epoch.ncsc.mil>
7
8
9
 *	      Chris Vance, <cvance@nai.com>
 *	      Wayne Salamon, <wsalamon@nai.com>
 *	      James Morris <jmorris@redhat.com>
Linus Torvalds's avatar
Linus Torvalds committed
10
11
 *
 *  Copyright (C) 2001,2002 Networks Associates Technology, Inc.
12
13
 *  Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
 *					   Eric Paris <eparis@redhat.com>
Linus Torvalds's avatar
Linus Torvalds committed
14
 *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
15
 *			    <dgoeddel@trustedcs.com>
16
 *  Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
17
 *	Paul Moore <paul@paul-moore.com>
18
 *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
19
 *		       Yuichi Nakamura <ynakam@hitachisoft.jp>
Linus Torvalds's avatar
Linus Torvalds committed
20
21
22
 *
 *	This program is free software; you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License version 2,
23
 *	as published by the Free Software Foundation.
Linus Torvalds's avatar
Linus Torvalds committed
24
25
26
 */

#include <linux/init.h>
27
#include <linux/kd.h>
Linus Torvalds's avatar
Linus Torvalds committed
28
#include <linux/kernel.h>
29
#include <linux/tracehook.h>
Linus Torvalds's avatar
Linus Torvalds committed
30
31
#include <linux/errno.h>
#include <linux/sched.h>
Casey Schaufler's avatar
Casey Schaufler committed
32
#include <linux/lsm_hooks.h>
Linus Torvalds's avatar
Linus Torvalds committed
33
34
35
36
37
38
39
#include <linux/xattr.h>
#include <linux/capability.h>
#include <linux/unistd.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/slab.h>
#include <linux/pagemap.h>
40
#include <linux/proc_fs.h>
Linus Torvalds's avatar
Linus Torvalds committed
41
42
43
#include <linux/swap.h>
#include <linux/spinlock.h>
#include <linux/syscalls.h>
44
#include <linux/dcache.h>
Linus Torvalds's avatar
Linus Torvalds committed
45
#include <linux/file.h>
Al Viro's avatar
Al Viro committed
46
#include <linux/fdtable.h>
Linus Torvalds's avatar
Linus Torvalds committed
47
48
49
50
51
52
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/tty.h>
#include <net/icmp.h>
53
#include <net/ip.h>		/* for local_port_range[] */
Linus Torvalds's avatar
Linus Torvalds committed
54
#include <net/tcp.h>		/* struct or_callable used in sock_rcv_skb */
55
#include <net/inet_connection_sock.h>
56
#include <net/net_namespace.h>
57
#include <net/netlabel.h>
58
#include <linux/uaccess.h>
Linus Torvalds's avatar
Linus Torvalds committed
59
#include <asm/ioctls.h>
Arun Sharma's avatar
Arun Sharma committed
60
#include <linux/atomic.h>
Linus Torvalds's avatar
Linus Torvalds committed
61
62
63
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>	/* for network interface checks */
64
#include <net/netlink.h>
Linus Torvalds's avatar
Linus Torvalds committed
65
66
#include <linux/tcp.h>
#include <linux/udp.h>
James Morris's avatar
James Morris committed
67
#include <linux/dccp.h>
Linus Torvalds's avatar
Linus Torvalds committed
68
69
70
71
72
73
74
75
76
#include <linux/quota.h>
#include <linux/un.h>		/* for Unix socket types */
#include <net/af_unix.h>	/* for Unix socket types */
#include <linux/parser.h>
#include <linux/nfs_mount.h>
#include <net/ipv6.h>
#include <linux/hugetlb.h>
#include <linux/personality.h>
#include <linux/audit.h>
77
#include <linux/string.h>
78
#include <linux/selinux.h>
79
#include <linux/mutex.h>
80
#include <linux/posix-timers.h>
81
#include <linux/syslog.h>
82
#include <linux/user_namespace.h>
83
#include <linux/export.h>
Al Viro's avatar
Al Viro committed
84
85
#include <linux/msg.h>
#include <linux/shm.h>
Linus Torvalds's avatar
Linus Torvalds committed
86
87
88
89

#include "avc.h"
#include "objsec.h"
#include "netif.h"
90
#include "netnode.h"
91
#include "netport.h"
92
#include "xfrm.h"
93
#include "netlabel.h"
94
#include "audit.h"
95
#include "avc_ss.h"
Linus Torvalds's avatar
Linus Torvalds committed
96

97
/* SECMARK reference count */
98
static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
99

Linus Torvalds's avatar
Linus Torvalds committed
100
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
101
int selinux_enforcing;
Linus Torvalds's avatar
Linus Torvalds committed
102
103
104

static int __init enforcing_setup(char *str)
{
105
	unsigned long enforcing;
106
	if (!kstrtoul(str, 0, &enforcing))
107
		selinux_enforcing = enforcing ? 1 : 0;
Linus Torvalds's avatar
Linus Torvalds committed
108
109
110
111
112
113
114
115
116
117
	return 1;
}
__setup("enforcing=", enforcing_setup);
#endif

#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;

static int __init selinux_enabled_setup(char *str)
{
118
	unsigned long enabled;
119
	if (!kstrtoul(str, 0, &enabled))
120
		selinux_enabled = enabled ? 1 : 0;
Linus Torvalds's avatar
Linus Torvalds committed
121
122
123
	return 1;
}
__setup("selinux=", selinux_enabled_setup);
124
125
#else
int selinux_enabled = 1;
Linus Torvalds's avatar
Linus Torvalds committed
126
127
#endif

128
static struct kmem_cache *sel_inode_cache;
129
static struct kmem_cache *file_security_cache;
130

131
132
133
134
135
136
137
/**
 * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
 *
 * Description:
 * This function checks the SECMARK reference counter to see if any SECMARK
 * targets are currently configured, if the reference counter is greater than
 * zero SECMARK is considered to be enabled.  Returns true (1) if SECMARK is
138
139
 * enabled, false (0) if SECMARK is disabled.  If the always_check_network
 * policy capability is enabled, SECMARK is always considered enabled.
140
141
142
143
 *
 */
static int selinux_secmark_enabled(void)
{
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
	return (selinux_policycap_alwaysnetwork || atomic_read(&selinux_secmark_refcount));
}

/**
 * selinux_peerlbl_enabled - Check to see if peer labeling is currently enabled
 *
 * Description:
 * This function checks if NetLabel or labeled IPSEC is enabled.  Returns true
 * (1) if any are enabled or false (0) if neither are enabled.  If the
 * always_check_network policy capability is enabled, peer labeling
 * is always considered enabled.
 *
 */
static int selinux_peerlbl_enabled(void)
{
	return (selinux_policycap_alwaysnetwork || netlbl_enabled() || selinux_xfrm_enabled());
160
161
}

162
163
164
165
166
167
168
169
170
171
172
static int selinux_netcache_avc_callback(u32 event)
{
	if (event == AVC_CALLBACK_RESET) {
		sel_netif_flush();
		sel_netnode_flush();
		sel_netport_flush();
		synchronize_net();
	}
	return 0;
}

173
174
175
176
/*
 * initialise the security for the init task
 */
static void cred_init_security(void)
Linus Torvalds's avatar
Linus Torvalds committed
177
{
178
	struct cred *cred = (struct cred *) current->real_cred;
Linus Torvalds's avatar
Linus Torvalds committed
179
180
	struct task_security_struct *tsec;

181
	tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
182
	if (!tsec)
183
		panic("SELinux:  Failed to initialize initial task.\n");
Linus Torvalds's avatar
Linus Torvalds committed
184

185
	tsec->osid = tsec->sid = SECINITSID_KERNEL;
186
	cred->security = tsec;
Linus Torvalds's avatar
Linus Torvalds committed
187
188
}

189
190
191
192
193
194
195
196
197
198
199
/*
 * get the security ID of a set of credentials
 */
static inline u32 cred_sid(const struct cred *cred)
{
	const struct task_security_struct *tsec;

	tsec = cred->security;
	return tsec->sid;
}

200
/*
201
 * get the objective security ID of a task
202
203
204
205
206
207
 */
static inline u32 task_sid(const struct task_struct *task)
{
	u32 sid;

	rcu_read_lock();
208
	sid = cred_sid(__task_cred(task));
209
210
211
212
213
	rcu_read_unlock();
	return sid;
}

/*
214
 * get the subjective security ID of the current task
215
216
217
 */
static inline u32 current_sid(void)
{
218
	const struct task_security_struct *tsec = current_security();
219
220
221
222

	return tsec->sid;
}

223
224
/* Allocate and free functions for each kind of security blob. */

Linus Torvalds's avatar
Linus Torvalds committed
225
226
227
static int inode_alloc_security(struct inode *inode)
{
	struct inode_security_struct *isec;
228
	u32 sid = current_sid();
Linus Torvalds's avatar
Linus Torvalds committed
229

230
	isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
Linus Torvalds's avatar
Linus Torvalds committed
231
232
233
	if (!isec)
		return -ENOMEM;

234
	mutex_init(&isec->lock);
Linus Torvalds's avatar
Linus Torvalds committed
235
236
237
238
	INIT_LIST_HEAD(&isec->list);
	isec->inode = inode;
	isec->sid = SECINITSID_UNLABELED;
	isec->sclass = SECCLASS_FILE;
239
	isec->task_sid = sid;
Linus Torvalds's avatar
Linus Torvalds committed
240
241
242
243
244
	inode->i_security = isec;

	return 0;
}

245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);

/*
 * Try reloading inode security labels that have been marked as invalid.  The
 * @may_sleep parameter indicates when sleeping and thus reloading labels is
 * allowed; when set to false, returns ERR_PTR(-ECHILD) when the label is
 * invalid.  The @opt_dentry parameter should be set to a dentry of the inode;
 * when no dentry is available, set it to NULL instead.
 */
static int __inode_security_revalidate(struct inode *inode,
				       struct dentry *opt_dentry,
				       bool may_sleep)
{
	struct inode_security_struct *isec = inode->i_security;

	might_sleep_if(may_sleep);

	if (isec->initialized == LABEL_INVALID) {
		if (!may_sleep)
			return -ECHILD;

		/*
		 * Try reloading the inode security label.  This will fail if
		 * @opt_dentry is NULL and no dentry for this inode can be
		 * found; in that case, continue using the old label.
		 */
		inode_doinit_with_dentry(inode, opt_dentry);
	}
	return 0;
}

static struct inode_security_struct *inode_security_novalidate(struct inode *inode)
{
	return inode->i_security;
}

static struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu)
{
	int error;

	error = __inode_security_revalidate(inode, NULL, !rcu);
	if (error)
		return ERR_PTR(error);
	return inode->i_security;
}

291
292
293
294
295
/*
 * Get the security label of an inode.
 */
static struct inode_security_struct *inode_security(struct inode *inode)
{
296
	__inode_security_revalidate(inode, NULL, true);
297
298
299
300
301
302
303
304
305
306
	return inode->i_security;
}

/*
 * Get the security label of a dentry's backing inode.
 */
static struct inode_security_struct *backing_inode_security(struct dentry *dentry)
{
	struct inode *inode = d_backing_inode(dentry);

307
	__inode_security_revalidate(inode, dentry, true);
308
309
310
	return inode->i_security;
}

311
312
313
314
315
316
317
318
static void inode_free_rcu(struct rcu_head *head)
{
	struct inode_security_struct *isec;

	isec = container_of(head, struct inode_security_struct, rcu);
	kmem_cache_free(sel_inode_cache, isec);
}

Linus Torvalds's avatar
Linus Torvalds committed
319
320
321
322
323
static void inode_free_security(struct inode *inode)
{
	struct inode_security_struct *isec = inode->i_security;
	struct superblock_security_struct *sbsec = inode->i_sb->s_security;

324
325
326
327
328
329
330
331
332
333
334
335
	/*
	 * As not all inode security structures are in a list, we check for
	 * empty list outside of the lock to make sure that we won't waste
	 * time taking a lock doing nothing.
	 *
	 * The list_del_init() function can be safely called more than once.
	 * It should not be possible for this function to be called with
	 * concurrent list_add(), but for better safety against future changes
	 * in the code, we use list_empty_careful() here.
	 */
	if (!list_empty_careful(&isec->list)) {
		spin_lock(&sbsec->isec_lock);
Linus Torvalds's avatar
Linus Torvalds committed
336
		list_del_init(&isec->list);
337
338
		spin_unlock(&sbsec->isec_lock);
	}
Linus Torvalds's avatar
Linus Torvalds committed
339

340
341
342
343
344
345
346
347
348
349
	/*
	 * The inode may still be referenced in a path walk and
	 * a call to selinux_inode_permission() can be made
	 * after inode_free_security() is called. Ideally, the VFS
	 * wouldn't do this, but fixing that is a much harder
	 * job. For now, simply free the i_security via RCU, and
	 * leave the current inode->i_security pointer intact.
	 * The inode will be freed after the RCU grace period too.
	 */
	call_rcu(&isec->rcu, inode_free_rcu);
Linus Torvalds's avatar
Linus Torvalds committed
350
351
352
353
354
}

static int file_alloc_security(struct file *file)
{
	struct file_security_struct *fsec;
355
	u32 sid = current_sid();
Linus Torvalds's avatar
Linus Torvalds committed
356

357
	fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
358
359
360
	if (!fsec)
		return -ENOMEM;

361
362
	fsec->sid = sid;
	fsec->fown_sid = sid;
Linus Torvalds's avatar
Linus Torvalds committed
363
364
365
366
367
368
369
370
371
	file->f_security = fsec;

	return 0;
}

static void file_free_security(struct file *file)
{
	struct file_security_struct *fsec = file->f_security;
	file->f_security = NULL;
372
	kmem_cache_free(file_security_cache, fsec);
Linus Torvalds's avatar
Linus Torvalds committed
373
374
375
376
377
378
}

static int superblock_alloc_security(struct super_block *sb)
{
	struct superblock_security_struct *sbsec;

379
	sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
380
381
382
	if (!sbsec)
		return -ENOMEM;

383
	mutex_init(&sbsec->lock);
Linus Torvalds's avatar
Linus Torvalds committed
384
385
386
387
388
	INIT_LIST_HEAD(&sbsec->isec_head);
	spin_lock_init(&sbsec->isec_lock);
	sbsec->sb = sb;
	sbsec->sid = SECINITSID_UNLABELED;
	sbsec->def_sid = SECINITSID_FILE;
389
	sbsec->mntpoint_sid = SECINITSID_UNLABELED;
Linus Torvalds's avatar
Linus Torvalds committed
390
391
392
393
394
395
396
397
398
399
400
401
402
403
	sb->s_security = sbsec;

	return 0;
}

static void superblock_free_security(struct super_block *sb)
{
	struct superblock_security_struct *sbsec = sb->s_security;
	sb->s_security = NULL;
	kfree(sbsec);
}

/* The file system's label must be initialized prior to use. */

404
static const char *labeling_behaviors[7] = {
Linus Torvalds's avatar
Linus Torvalds committed
405
406
407
408
409
410
	"uses xattr",
	"uses transition SIDs",
	"uses task SIDs",
	"uses genfs_contexts",
	"not configured for labeling",
	"uses mountpoint labeling",
411
	"uses native labeling",
Linus Torvalds's avatar
Linus Torvalds committed
412
413
414
415
416
417
418
419
};

static inline int inode_doinit(struct inode *inode)
{
	return inode_doinit_with_dentry(inode, NULL);
}

enum {
420
	Opt_error = -1,
Linus Torvalds's avatar
Linus Torvalds committed
421
422
	Opt_context = 1,
	Opt_fscontext = 2,
423
424
	Opt_defcontext = 3,
	Opt_rootcontext = 4,
425
	Opt_labelsupport = 5,
426
	Opt_nextmntopt = 6,
Linus Torvalds's avatar
Linus Torvalds committed
427
428
};

429
430
#define NUM_SEL_MNT_OPTS	(Opt_nextmntopt - 1)

431
static const match_table_t tokens = {
432
433
434
435
	{Opt_context, CONTEXT_STR "%s"},
	{Opt_fscontext, FSCONTEXT_STR "%s"},
	{Opt_defcontext, DEFCONTEXT_STR "%s"},
	{Opt_rootcontext, ROOTCONTEXT_STR "%s"},
436
	{Opt_labelsupport, LABELSUPP_STR},
437
	{Opt_error, NULL},
Linus Torvalds's avatar
Linus Torvalds committed
438
439
440
441
};

#define SEL_MOUNT_FAIL_MSG "SELinux:  duplicate or incompatible mount options\n"

442
443
static int may_context_mount_sb_relabel(u32 sid,
			struct superblock_security_struct *sbsec,
444
			const struct cred *cred)
445
{
446
	const struct task_security_struct *tsec = cred->security;
447
448
449
450
451
452
453
454
455
456
457
458
	int rc;

	rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
			  FILESYSTEM__RELABELFROM, NULL);
	if (rc)
		return rc;

	rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
			  FILESYSTEM__RELABELTO, NULL);
	return rc;
}

459
460
static int may_context_mount_inode_relabel(u32 sid,
			struct superblock_security_struct *sbsec,
461
			const struct cred *cred)
462
{
463
	const struct task_security_struct *tsec = cred->security;
464
465
466
467
468
469
470
471
472
473
474
	int rc;
	rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
			  FILESYSTEM__RELABELFROM, NULL);
	if (rc)
		return rc;

	rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
			  FILESYSTEM__ASSOCIATE, NULL);
	return rc;
}

475
476
477
478
static int selinux_is_sblabel_mnt(struct super_block *sb)
{
	struct superblock_security_struct *sbsec = sb->s_security;

479
480
481
	return sbsec->behavior == SECURITY_FS_USE_XATTR ||
		sbsec->behavior == SECURITY_FS_USE_TRANS ||
		sbsec->behavior == SECURITY_FS_USE_TASK ||
482
		sbsec->behavior == SECURITY_FS_USE_NATIVE ||
483
484
485
486
487
		/* Special handling. Genfs but also in-core setxattr handler */
		!strcmp(sb->s_type->name, "sysfs") ||
		!strcmp(sb->s_type->name, "pstore") ||
		!strcmp(sb->s_type->name, "debugfs") ||
		!strcmp(sb->s_type->name, "rootfs");
488
489
}

490
static int sb_finish_set_opts(struct super_block *sb)
Linus Torvalds's avatar
Linus Torvalds committed
491
492
{
	struct superblock_security_struct *sbsec = sb->s_security;
493
	struct dentry *root = sb->s_root;
494
	struct inode *root_inode = d_backing_inode(root);
495
	int rc = 0;
Linus Torvalds's avatar
Linus Torvalds committed
496

497
498
499
500
501
502
503
	if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
		/* Make sure that the xattr handler exists and that no
		   error other than -ENODATA is returned by getxattr on
		   the root directory.  -ENODATA is ok, as this may be
		   the first boot of the SELinux kernel before we have
		   assigned xattr values to the filesystem. */
		if (!root_inode->i_op->getxattr) {
504
505
			printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
			       "xattr support\n", sb->s_id, sb->s_type->name);
506
507
508
509
510
511
512
			rc = -EOPNOTSUPP;
			goto out;
		}
		rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0);
		if (rc < 0 && rc != -ENODATA) {
			if (rc == -EOPNOTSUPP)
				printk(KERN_WARNING "SELinux: (dev %s, type "
513
514
				       "%s) has no security xattr handler\n",
				       sb->s_id, sb->s_type->name);
515
516
			else
				printk(KERN_WARNING "SELinux: (dev %s, type "
517
518
				       "%s) getxattr errno %d\n", sb->s_id,
				       sb->s_type->name, -rc);
519
520
521
			goto out;
		}
	}
Linus Torvalds's avatar
Linus Torvalds committed
522

523
	if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors))
524
525
		printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n",
		       sb->s_id, sb->s_type->name);
Linus Torvalds's avatar
Linus Torvalds committed
526

527
	sbsec->flags |= SE_SBINITIALIZED;
528
	if (selinux_is_sblabel_mnt(sb))
529
		sbsec->flags |= SBLABEL_MNT;
530

531
532
	/* Initialize the root inode. */
	rc = inode_doinit_with_dentry(root_inode, root);
Linus Torvalds's avatar
Linus Torvalds committed
533

534
535
536
537
538
539
540
541
542
543
544
	/* Initialize any other inodes associated with the superblock, e.g.
	   inodes created prior to initial policy load or inodes created
	   during get_sb by a pseudo filesystem that directly
	   populates itself. */
	spin_lock(&sbsec->isec_lock);
next_inode:
	if (!list_empty(&sbsec->isec_head)) {
		struct inode_security_struct *isec =
				list_entry(sbsec->isec_head.next,
					   struct inode_security_struct, list);
		struct inode *inode = isec->inode;
545
		list_del_init(&isec->list);
546
547
548
549
550
551
552
553
554
555
556
557
558
559
		spin_unlock(&sbsec->isec_lock);
		inode = igrab(inode);
		if (inode) {
			if (!IS_PRIVATE(inode))
				inode_doinit(inode);
			iput(inode);
		}
		spin_lock(&sbsec->isec_lock);
		goto next_inode;
	}
	spin_unlock(&sbsec->isec_lock);
out:
	return rc;
}
Linus Torvalds's avatar
Linus Torvalds committed
560

561
562
563
564
565
566
/*
 * This function should allow an FS to ask what it's mount security
 * options were so it can use those later for submounts, displaying
 * mount options, or whatever.
 */
static int selinux_get_mnt_opts(const struct super_block *sb,
567
				struct security_mnt_opts *opts)
568
569
570
571
572
573
{
	int rc = 0, i;
	struct superblock_security_struct *sbsec = sb->s_security;
	char *context = NULL;
	u32 len;
	char tmp;
Linus Torvalds's avatar
Linus Torvalds committed
574

575
	security_init_mnt_opts(opts);
Linus Torvalds's avatar
Linus Torvalds committed
576

577
	if (!(sbsec->flags & SE_SBINITIALIZED))
578
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
579

580
581
	if (!ss_initialized)
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
582

583
584
585
	/* make sure we always check enough bits to cover the mask */
	BUILD_BUG_ON(SE_MNTMASK >= (1 << NUM_SEL_MNT_OPTS));

586
	tmp = sbsec->flags & SE_MNTMASK;
587
	/* count the number of mount options for this sb */
588
	for (i = 0; i < NUM_SEL_MNT_OPTS; i++) {
589
		if (tmp & 0x01)
590
			opts->num_mnt_opts++;
591
592
		tmp >>= 1;
	}
593
	/* Check if the Label support flag is set */
594
	if (sbsec->flags & SBLABEL_MNT)
595
		opts->num_mnt_opts++;
Linus Torvalds's avatar
Linus Torvalds committed
596

597
598
	opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC);
	if (!opts->mnt_opts) {
599
600
601
		rc = -ENOMEM;
		goto out_free;
	}
Linus Torvalds's avatar
Linus Torvalds committed
602

603
604
	opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC);
	if (!opts->mnt_opts_flags) {
605
606
607
		rc = -ENOMEM;
		goto out_free;
	}
Linus Torvalds's avatar
Linus Torvalds committed
608

609
610
611
612
613
	i = 0;
	if (sbsec->flags & FSCONTEXT_MNT) {
		rc = security_sid_to_context(sbsec->sid, &context, &len);
		if (rc)
			goto out_free;
614
615
		opts->mnt_opts[i] = context;
		opts->mnt_opts_flags[i++] = FSCONTEXT_MNT;
616
617
618
619
620
	}
	if (sbsec->flags & CONTEXT_MNT) {
		rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len);
		if (rc)
			goto out_free;
621
622
		opts->mnt_opts[i] = context;
		opts->mnt_opts_flags[i++] = CONTEXT_MNT;
623
624
625
626
627
	}
	if (sbsec->flags & DEFCONTEXT_MNT) {
		rc = security_sid_to_context(sbsec->def_sid, &context, &len);
		if (rc)
			goto out_free;
628
629
		opts->mnt_opts[i] = context;
		opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT;
630
631
	}
	if (sbsec->flags & ROOTCONTEXT_MNT) {
632
633
		struct dentry *root = sbsec->sb->s_root;
		struct inode_security_struct *isec = backing_inode_security(root);
634

635
636
637
		rc = security_sid_to_context(isec->sid, &context, &len);
		if (rc)
			goto out_free;
638
639
		opts->mnt_opts[i] = context;
		opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT;
640
	}
641
	if (sbsec->flags & SBLABEL_MNT) {
642
		opts->mnt_opts[i] = NULL;
643
		opts->mnt_opts_flags[i++] = SBLABEL_MNT;
644
	}
Linus Torvalds's avatar
Linus Torvalds committed
645

646
	BUG_ON(i != opts->num_mnt_opts);
Linus Torvalds's avatar
Linus Torvalds committed
647

648
649
650
	return 0;

out_free:
651
	security_free_mnt_opts(opts);
652
653
	return rc;
}
Linus Torvalds's avatar
Linus Torvalds committed
654

655
656
657
static int bad_option(struct superblock_security_struct *sbsec, char flag,
		      u32 old_sid, u32 new_sid)
{
658
659
	char mnt_flags = sbsec->flags & SE_MNTMASK;

660
	/* check if the old mount command had the same options */
661
	if (sbsec->flags & SE_SBINITIALIZED)
662
663
664
665
666
667
668
		if (!(sbsec->flags & flag) ||
		    (old_sid != new_sid))
			return 1;

	/* check if we were passed the same options twice,
	 * aka someone passed context=a,context=b
	 */
669
670
	if (!(sbsec->flags & SE_SBINITIALIZED))
		if (mnt_flags & flag)
671
672
673
			return 1;
	return 0;
}
674

675
676
677
678
/*
 * Allow filesystems with binary mount data to explicitly set mount point
 * labeling information.
 */
679
static int selinux_set_mnt_opts(struct super_block *sb,
680
681
682
				struct security_mnt_opts *opts,
				unsigned long kern_flags,
				unsigned long *set_kern_flags)
683
{
684
	const struct cred *cred = current_cred();
685
686
	int rc = 0, i;
	struct superblock_security_struct *sbsec = sb->s_security;
687
	const char *name = sb->s_type->name;
688
689
	struct dentry *root = sbsec->sb->s_root;
	struct inode_security_struct *root_isec = backing_inode_security(root);
690
691
	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
	u32 defcontext_sid = 0;
692
693
694
	char **mount_options = opts->mnt_opts;
	int *flags = opts->mnt_opts_flags;
	int num_opts = opts->num_mnt_opts;
695
696
697
698
699
700
701
702
703
704
705

	mutex_lock(&sbsec->lock);

	if (!ss_initialized) {
		if (!num_opts) {
			/* Defer initialization until selinux_complete_init,
			   after the initial policy is loaded and the security
			   server is ready to handle calls. */
			goto out;
		}
		rc = -EINVAL;
Eric Paris's avatar
Eric Paris committed
706
707
		printk(KERN_WARNING "SELinux: Unable to set superblock options "
			"before the security server is initialized\n");
Linus Torvalds's avatar
Linus Torvalds committed
708
		goto out;
709
	}
710
711
712
713
714
715
	if (kern_flags && !set_kern_flags) {
		/* Specifying internal flags without providing a place to
		 * place the results is not allowed */
		rc = -EINVAL;
		goto out;
	}
Linus Torvalds's avatar
Linus Torvalds committed
716

717
718
719
720
721
722
723
724
725
726
727
	/*
	 * Binary mount data FS will come through this function twice.  Once
	 * from an explicit call and once from the generic calls from the vfs.
	 * Since the generic VFS calls will not contain any security mount data
	 * we need to skip the double mount verification.
	 *
	 * This does open a hole in which we will not notice if the first
	 * mount using this sb set explict options and a second mount using
	 * this sb does not set any security options.  (The first options
	 * will be used for both mounts)
	 */
728
	if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
729
	    && (num_opts == 0))
730
		goto out;
731

732
733
734
735
736
737
738
	/*
	 * parse the mount options, check if they are valid sids.
	 * also check if someone is trying to mount the same sb more
	 * than once with different security options.
	 */
	for (i = 0; i < num_opts; i++) {
		u32 sid;
739

740
		if (flags[i] == SBLABEL_MNT)
741
			continue;
742
		rc = security_context_str_to_sid(mount_options[i], &sid, GFP_KERNEL);
Linus Torvalds's avatar
Linus Torvalds committed
743
		if (rc) {
744
			printk(KERN_WARNING "SELinux: security_context_str_to_sid"
745
746
			       "(%s) failed for (dev %s, type %s) errno=%d\n",
			       mount_options[i], sb->s_id, name, rc);
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
			goto out;
		}
		switch (flags[i]) {
		case FSCONTEXT_MNT:
			fscontext_sid = sid;

			if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
					fscontext_sid))
				goto out_double_mount;

			sbsec->flags |= FSCONTEXT_MNT;
			break;
		case CONTEXT_MNT:
			context_sid = sid;

			if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
					context_sid))
				goto out_double_mount;

			sbsec->flags |= CONTEXT_MNT;
			break;
		case ROOTCONTEXT_MNT:
			rootcontext_sid = sid;

			if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
					rootcontext_sid))
				goto out_double_mount;

			sbsec->flags |= ROOTCONTEXT_MNT;

			break;
		case DEFCONTEXT_MNT:
			defcontext_sid = sid;

			if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
					defcontext_sid))
				goto out_double_mount;

			sbsec->flags |= DEFCONTEXT_MNT;

			break;
		default:
			rc = -EINVAL;
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
791
		}
792
793
	}

794
	if (sbsec->flags & SE_SBINITIALIZED) {
795
		/* previously mounted with options, but not on this attempt? */
796
		if ((sbsec->flags & SE_MNTMASK) && !num_opts)
797
798
799
800
801
			goto out_double_mount;
		rc = 0;
		goto out;
	}

802
	if (strcmp(sb->s_type->name, "proc") == 0)
803
804
		sbsec->flags |= SE_SBPROC | SE_SBGENFS;

805
806
807
	if (!strcmp(sb->s_type->name, "debugfs") ||
	    !strcmp(sb->s_type->name, "sysfs") ||
	    !strcmp(sb->s_type->name, "pstore"))
808
		sbsec->flags |= SE_SBGENFS;
809

810
811
812
813
814
	if (!sbsec->behavior) {
		/*
		 * Determine the labeling behavior to use for this
		 * filesystem type.
		 */
815
		rc = security_fs_use(sb);
816
817
818
819
820
821
		if (rc) {
			printk(KERN_WARNING
				"%s: security_fs_use(%s) returned %d\n",
					__func__, sb->s_type->name, rc);
			goto out;
		}
822
823
824
	}
	/* sets the context of the superblock for the fs being mounted. */
	if (fscontext_sid) {
825
		rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
Linus Torvalds's avatar
Linus Torvalds committed
826
		if (rc)
827
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
828

829
		sbsec->sid = fscontext_sid;
830
831
832
833
834
835
836
	}

	/*
	 * Switch to using mount point labeling behavior.
	 * sets the label used on all file below the mountpoint, and will set
	 * the superblock context if not already set.
	 */
837
838
839
840
841
	if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
		sbsec->behavior = SECURITY_FS_USE_NATIVE;
		*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
	}

842
843
	if (context_sid) {
		if (!fscontext_sid) {
844
845
			rc = may_context_mount_sb_relabel(context_sid, sbsec,
							  cred);
846
			if (rc)
847
848
				goto out;
			sbsec->sid = context_sid;
849
		} else {
850
851
			rc = may_context_mount_inode_relabel(context_sid, sbsec,
							     cred);
852
			if (rc)
853
				goto out;
854
		}
855
856
		if (!rootcontext_sid)
			rootcontext_sid = context_sid;
Linus Torvalds's avatar
Linus Torvalds committed
857

858
		sbsec->mntpoint_sid = context_sid;
859
		sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
Linus Torvalds's avatar
Linus Torvalds committed
860
861
	}

862
	if (rootcontext_sid) {
863
864
		rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
						     cred);
865
		if (rc)
866
			goto out;
867

868
		root_isec->sid = rootcontext_sid;
869
		root_isec->initialized = LABEL_INITIALIZED;
870
871
	}

872
	if (defcontext_sid) {
873
874
		if (sbsec->behavior != SECURITY_FS_USE_XATTR &&
			sbsec->behavior != SECURITY_FS_USE_NATIVE) {
875
876
877
878
			rc = -EINVAL;
			printk(KERN_WARNING "SELinux: defcontext option is "
			       "invalid for this filesystem type\n");
			goto out;
Linus Torvalds's avatar
Linus Torvalds committed
879
880
		}

881
882
		if (defcontext_sid != sbsec->def_sid) {
			rc = may_context_mount_inode_relabel(defcontext_sid,
883
							     sbsec, cred);
884
885
886
			if (rc)
				goto out;
		}
Linus Torvalds's avatar
Linus Torvalds committed
887

888
		sbsec->def_sid = defcontext_sid;
Linus Torvalds's avatar
Linus Torvalds committed
889
890
	}

891
	rc = sb_finish_set_opts(sb);
Linus Torvalds's avatar
Linus Torvalds committed
892
out:
893
	mutex_unlock(&sbsec->lock);
Linus Torvalds's avatar
Linus Torvalds committed
894
	return rc;
895
896
897
out_double_mount:
	rc = -EINVAL;
	printk(KERN_WARNING "SELinux: mount invalid.  Same superblock, different "
898
	       "security settings for (dev %s, type %s)\n", sb->s_id, name);
899
	goto out;
Linus Torvalds's avatar
Linus Torvalds committed
900
901
}

902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
static int selinux_cmp_sb_context(const struct super_block *oldsb,
				    const struct super_block *newsb)
{
	struct superblock_security_struct *old = oldsb->s_security;
	struct superblock_security_struct *new = newsb->s_security;
	char oldflags = old->flags & SE_MNTMASK;
	char newflags = new->flags & SE_MNTMASK;

	if (oldflags != newflags)
		goto mismatch;
	if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid)
		goto mismatch;
	if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid)
		goto mismatch;
	if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid)
		goto mismatch;
	if (oldflags & ROOTCONTEXT_MNT) {
919
920
		struct inode_security_struct *oldroot = backing_inode_security(oldsb->s_root);
		struct inode_security_struct *newroot = backing_inode_security(newsb->s_root);
921
922
923
924
925
926
927
928
929
930
931
932
		if (oldroot->sid != newroot->sid)
			goto mismatch;
	}
	return 0;
mismatch:
	printk(KERN_WARNING "SELinux: mount invalid.  Same superblock, "
			    "different security settings for (dev %s, "
			    "type %s)\n", newsb->s_id, newsb->s_type->name);
	return -EBUSY;
}

static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
933
					struct super_block *newsb)
Linus Torvalds's avatar
Linus Torvalds committed
934
{
935
936
	const struct superblock_security_struct *oldsbsec = oldsb->s_security;
	struct superblock_security_struct *newsbsec = newsb->s_security;
Linus Torvalds's avatar
Linus Torvalds committed
937

938
939
940
	int set_fscontext =	(oldsbsec->flags & FSCONTEXT_MNT);
	int set_context =	(oldsbsec->flags & CONTEXT_MNT);
	int set_rootcontext =	(oldsbsec->flags & ROOTCONTEXT_MNT);
Linus Torvalds's avatar
Linus Torvalds committed
941

942
943
	/*
	 * if the parent was able to be mounted it clearly had no special lsm
944
	 * mount options.  thus we can safely deal with this superblock later
945
	 */
946
	if (!ss_initialized)
947
		return 0;
948
949

	/* how can we clone if the old one wasn't set up?? */
950
	BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
951

952
	/* if fs is reusing a sb, make sure that the contexts match */
953
	if (newsbsec->flags & SE_SBINITIALIZED)
954
		return selinux_cmp_sb_context(oldsb, newsb);
955

956
957
958
959
960
961
962
963
964
965
966
967
968
969
	mutex_lock(&newsbsec->lock);

	newsbsec->flags = oldsbsec->flags;

	newsbsec->sid = oldsbsec->sid;
	newsbsec->def_sid = oldsbsec->def_sid;
	newsbsec->behavior = oldsbsec->behavior;

	if (set_context) {
		u32 sid = oldsbsec->mntpoint_sid;

		if (!set_fscontext)
			newsbsec->sid = sid;
		if (!set_rootcontext) {
970
			struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
971
972
973
			newisec->sid = sid;
		}
		newsbsec->mntpoint_sid = sid;
Linus Torvalds's avatar
Linus Torvalds committed
974
	}
975
	if (set_rootcontext) {
976
977
		const struct inode_security_struct *oldisec = backing_inode_security(oldsb->s_root);
		struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
Linus Torvalds's avatar
Linus Torvalds committed
978

979
		newisec->sid = oldisec->sid;
Linus Torvalds's avatar
Linus Torvalds committed
980
981
	}

982
983
	sb_finish_set_opts(newsb);
	mutex_unlock(&newsbsec->lock);
984
	return 0;
985
986
}

987
988
static int selinux_parse_opts_str(char *options,
				  struct security_mnt_opts *opts)
989
{
990
	char *p;
991
992
	char *context = NULL, *defcontext = NULL;
	char *fscontext = NULL, *rootcontext = NULL;
993
	int rc, num_mnt_opts = 0;
Linus Torvalds's avatar
Linus Torvalds committed
994

995
	opts->num_mnt_opts = 0;
Linus Torvalds's avatar
Linus Torvalds committed
996

997
998
999
1000
	/* Standard string-based options. */
	while ((p = strsep(&options, "|")) != NULL) {
		int token;
		substring_t args[MAX_OPT_ARGS];
Linus Torvalds's avatar
Linus Torvalds committed
1001

1002
1003
		if (!*p)
			continue;
Linus Torvalds's avatar
Linus Torvalds committed
1004

1005
		token = match_token(p, tokens, args);
Linus Torvalds's avatar
Linus Torvalds committed
1006

1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
		switch (token) {
		case Opt_context:
			if (context || defcontext) {
				rc = -EINVAL;
				printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
				goto out_err;
			}
			context = match_strdup(&args[0]);
			if (!context) {
				rc = -ENOMEM;
				goto out_err;
			}
			break;

		case Opt_fscontext:
			if (fscontext) {
				rc = -EINVAL;
				printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
				goto out_err;
			}
			fscontext = match_strdup(&args[0]);
			if (!fscontext) {
				rc = -ENOMEM;
				goto out_err;
			}
			break;

		case Opt_rootcontext:
			if (rootcontext) {
				rc = -EINVAL;
				printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
				goto out_err;
			}
			rootcontext = match_strdup(&args[0]);
			if (!rootcontext) {
				rc = -ENOMEM;
				goto out_err;
			}
			break;

		case Opt_defcontext:
			if (context || defcontext) {
				rc = -EINVAL;
				printk(KERN_WARNING SEL_MOUNT_FAIL_MSG);
				goto out_err;
			}
			defcontext = match_strdup(&args[0]);
			if (!defcontext) {
				rc = -ENOMEM;
				goto out_err;
			}
			break;
1059
1060
		case Opt_labelsupport:
			break;
1061
1062
1063
1064
		default:
			rc = -EINVAL;
			printk(KERN_WARNING "SELinux:  unknown mount option\n");
			goto out_err;
Linus Torvalds's avatar
Linus Torvalds committed
1065
1066
1067

		}
	}
1068

1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
	rc = -ENOMEM;
	opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC);
	if (!opts->mnt_opts)
		goto out_err;

	opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC);
	if (!opts->mnt_opts_flags) {
		kfree(opts->mnt_opts);
		goto out_err;
	}

1080
	if (fscontext) {
1081
1082
		opts->mnt_opts[num_mnt_opts] = fscontext;
		opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT;
1083
1084
	}
	if (context) {
1085
1086
		opts->mnt_opts[num_mnt_opts] = context;
		opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT;
1087
1088
	}
	if (rootcontext) {
1089
1090
		opts->mnt_opts[num_mnt_opts] = rootcontext;
		opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT;
1091
1092
	}
	if (defcontext) {
1093
1094
		opts->mnt_opts[num_mnt_opts] = defcontext;
		opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT;
1095
1096
	}

1097
1098
1099
	opts->num_mnt_opts = num_mnt_opts;
	return 0;

1100
1101
1102
1103
1104
out_err:
	kfree(context);
	kfree(defcontext);
	kfree(fscontext);
	kfree(rootcontext);
Linus Torvalds's avatar
Linus Torvalds committed
1105
1106
	return rc;
}
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
/*
 * string mount options parsing and call set the sbsec
 */
static int superblock_doinit(struct super_block *sb, void *data)
{
	int rc = 0;
	char *options = data;
	struct security_mnt_opts opts;

	security_init_mnt_opts(&opts);

	if (!data)
		goto out;

	BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA);

	rc = selinux_parse_opts_str(options, &opts);
	if (rc)
		goto out_err;

out:
1128
	rc = selinux_set_mnt_opts(sb, &opts, 0, NULL);
1129
1130
1131
1132
1133

out_err:
	security_free_mnt_opts(&opts);
	return rc;
}
Linus Torvalds's avatar
Linus Torvalds committed
1134

Adrian Bunk's avatar
Adrian Bunk committed
1135
1136
static void selinux_write_opts(struct seq_file *m,
			       struct security_mnt_opts *opts)
1137
1138
1139
1140
1141
{
	int i;
	char *prefix;

	for (i = 0; i < opts->num_mnt_opts; i++) {
1142
1143
1144
1145
1146
1147
		char *has_comma;

		if (opts->mnt_opts[i])
			has_comma = strchr(opts->mnt_opts[i], ',');
		else
			has_comma = NULL;
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161

		switch (opts->mnt_opts_flags[i]) {
		case CONTEXT_MNT:
			prefix = CONTEXT_STR;
			break;
		case FSCONTEXT_MNT:
			prefix = FSCONTEXT_STR;
			break;
		case ROOTCONTEXT_MNT:
			prefix = ROOTCONTEXT_STR;
			break;
		case DEFCONTEXT_MNT:
			prefix = DEFCONTEXT_STR;
			break;
1162
		case SBLABEL_MNT:
1163
1164
1165
			seq_putc(m, ',');
			seq_puts(m, LABELSUPP_STR);
			continue;
1166
1167
		default:
			BUG();
1168
			return;
1169
1170
1171
1172
1173
1174
		};
		/* we need a comma before each option */
		seq_putc(m, ',');
		seq_puts(m, prefix);
		if (has_comma)
			seq_putc(m, '\"');
1175
		seq_escape(m, opts->mnt_opts[i], "\"\n\\");
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
		if (has_comma)
			seq_putc(m, '\"');
	}
}

static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
{
	struct security_mnt_opts opts;
	int rc;

	rc = selinux_get_mnt_opts(sb, &opts);
1187
1188
1189
1190
	if (rc) {
		/* before policy load we may get EINVAL, don't show anything */
		if (rc == -EINVAL)
			rc = 0;
1191
		return rc;
1192
	}
1193
1194
1195
1196
1197
1198
1199
1200

	selinux_write_opts(m, &opts);

	security_free_mnt_opts(&opts);

	return rc;
}

Linus Torvalds's avatar
Linus Torvalds committed
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
static inline u16 inode_mode_to_security_class(umode_t mode)
{
	switch (mode & S_IFMT) {
	case S_IFSOCK:
		return SECCLASS_SOCK_FILE;
	case S_IFLNK:
		return SECCLASS_LNK_FILE;
	case S_IFREG:
		return SECCLASS_FILE;
	case S_IFBLK:
		return SECCLASS_BLK_FILE;
	case S_IFDIR:
		return SECCLASS_DIR;
	case S_IFCHR:
		return SECCLASS_CHR_FILE;
	case S_IFIFO:
		return SECCLASS_FIFO_FILE;

	}

	return SECCLASS_FILE;
}