xref: /openbmc/linux/security/selinux/hooks.c (revision da3d76abb2e74c07b1cd620ee5e3b31227846c7c)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  NSA Security-Enhanced Linux (SELinux) security module
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  *  This file contains the SELinux hook function implementations.
51da177e4SLinus Torvalds  *
67efbb60bSStephen Smalley  *  Authors:  Stephen Smalley, <sds@tycho.nsa.gov>
71da177e4SLinus Torvalds  *	      Chris Vance, <cvance@nai.com>
81da177e4SLinus Torvalds  *	      Wayne Salamon, <wsalamon@nai.com>
91da177e4SLinus Torvalds  *	      James Morris <jmorris@redhat.com>
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  *  Copyright (C) 2001,2002 Networks Associates Technology, Inc.
122069f457SEric Paris  *  Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
132069f457SEric Paris  *					   Eric Paris <eparis@redhat.com>
141da177e4SLinus Torvalds  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
151da177e4SLinus Torvalds  *			    <dgoeddel@trustedcs.com>
16ed6d76e4SPaul Moore  *  Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
1782c21bfaSPaul Moore  *	Paul Moore <paul@paul-moore.com>
18788e7dd4SYuichi Nakamura  *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
19788e7dd4SYuichi Nakamura  *		       Yuichi Nakamura <ynakam@hitachisoft.jp>
203a976fa6SDaniel Jurgens  *  Copyright (C) 2016 Mellanox Technologies
211da177e4SLinus Torvalds  *
221da177e4SLinus Torvalds  *	This program is free software; you can redistribute it and/or modify
231da177e4SLinus Torvalds  *	it under the terms of the GNU General Public License version 2,
241da177e4SLinus Torvalds  *	as published by the Free Software Foundation.
251da177e4SLinus Torvalds  */
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds #include <linux/init.h>
280b24dcb7SEric Paris #include <linux/kd.h>
291da177e4SLinus Torvalds #include <linux/kernel.h>
300d094efeSRoland McGrath #include <linux/tracehook.h>
311da177e4SLinus Torvalds #include <linux/errno.h>
323f07c014SIngo Molnar #include <linux/sched/signal.h>
3329930025SIngo Molnar #include <linux/sched/task.h>
343c4ed7bdSCasey Schaufler #include <linux/lsm_hooks.h>
351da177e4SLinus Torvalds #include <linux/xattr.h>
361da177e4SLinus Torvalds #include <linux/capability.h>
371da177e4SLinus Torvalds #include <linux/unistd.h>
381da177e4SLinus Torvalds #include <linux/mm.h>
391da177e4SLinus Torvalds #include <linux/mman.h>
401da177e4SLinus Torvalds #include <linux/slab.h>
411da177e4SLinus Torvalds #include <linux/pagemap.h>
420b24dcb7SEric Paris #include <linux/proc_fs.h>
431da177e4SLinus Torvalds #include <linux/swap.h>
441da177e4SLinus Torvalds #include <linux/spinlock.h>
451da177e4SLinus Torvalds #include <linux/syscalls.h>
462a7dba39SEric Paris #include <linux/dcache.h>
471da177e4SLinus Torvalds #include <linux/file.h>
489f3acc31SAl Viro #include <linux/fdtable.h>
491da177e4SLinus Torvalds #include <linux/namei.h>
501da177e4SLinus Torvalds #include <linux/mount.h>
511da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h>
521da177e4SLinus Torvalds #include <linux/netfilter_ipv6.h>
531da177e4SLinus Torvalds #include <linux/tty.h>
541da177e4SLinus Torvalds #include <net/icmp.h>
55227b60f5SStephen Hemminger #include <net/ip.h>		/* for local_port_range[] */
561da177e4SLinus Torvalds #include <net/tcp.h>		/* struct or_callable used in sock_rcv_skb */
5747180068SPaul Moore #include <net/inet_connection_sock.h>
58220deb96SPaul Moore #include <net/net_namespace.h>
59d621d35eSPaul Moore #include <net/netlabel.h>
60f5269710SEric Paris #include <linux/uaccess.h>
611da177e4SLinus Torvalds #include <asm/ioctls.h>
6260063497SArun Sharma #include <linux/atomic.h>
631da177e4SLinus Torvalds #include <linux/bitops.h>
641da177e4SLinus Torvalds #include <linux/interrupt.h>
651da177e4SLinus Torvalds #include <linux/netdevice.h>	/* for network interface checks */
6677954983SHong zhi guo #include <net/netlink.h>
671da177e4SLinus Torvalds #include <linux/tcp.h>
681da177e4SLinus Torvalds #include <linux/udp.h>
692ee92d46SJames Morris #include <linux/dccp.h>
70d452930fSRichard Haines #include <linux/sctp.h>
71d452930fSRichard Haines #include <net/sctp/structs.h>
721da177e4SLinus Torvalds #include <linux/quota.h>
731da177e4SLinus Torvalds #include <linux/un.h>		/* for Unix socket types */
741da177e4SLinus Torvalds #include <net/af_unix.h>	/* for Unix socket types */
751da177e4SLinus Torvalds #include <linux/parser.h>
761da177e4SLinus Torvalds #include <linux/nfs_mount.h>
771da177e4SLinus Torvalds #include <net/ipv6.h>
781da177e4SLinus Torvalds #include <linux/hugetlb.h>
791da177e4SLinus Torvalds #include <linux/personality.h>
801da177e4SLinus Torvalds #include <linux/audit.h>
816931dfc9SEric Paris #include <linux/string.h>
82877ce7c1SCatherine Zhang #include <linux/selinux.h>
8323970741SEric Paris #include <linux/mutex.h>
84f06febc9SFrank Mayhar #include <linux/posix-timers.h>
8500234592SKees Cook #include <linux/syslog.h>
863486740aSSerge E. Hallyn #include <linux/user_namespace.h>
8744fc7ea0SPaul Gortmaker #include <linux/export.h>
8840401530SAl Viro #include <linux/msg.h>
8940401530SAl Viro #include <linux/shm.h>
90ec27c356SChenbo Feng #include <linux/bpf.h>
91e262e32dSDavid Howells #include <uapi/linux/mount.h>
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds #include "avc.h"
941da177e4SLinus Torvalds #include "objsec.h"
951da177e4SLinus Torvalds #include "netif.h"
96224dfbd8SPaul Moore #include "netnode.h"
973e112172SPaul Moore #include "netport.h"
98409dcf31SDaniel Jurgens #include "ibpkey.h"
99d28d1e08STrent Jaeger #include "xfrm.h"
100c60475bfSPaul Moore #include "netlabel.h"
1019d57a7f9SAhmed S. Darwish #include "audit.h"
1027b98a585SJames Morris #include "avc_ss.h"
1031da177e4SLinus Torvalds 
104aa8e712cSStephen Smalley struct selinux_state selinux_state;
105aa8e712cSStephen Smalley 
106d621d35eSPaul Moore /* SECMARK reference count */
10756a4ca99SJames Morris static atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
108d621d35eSPaul Moore 
1091da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
110aa8e712cSStephen Smalley static int selinux_enforcing_boot;
1111da177e4SLinus Torvalds 
1121da177e4SLinus Torvalds static int __init enforcing_setup(char *str)
1131da177e4SLinus Torvalds {
114f5269710SEric Paris 	unsigned long enforcing;
11529707b20SJingoo Han 	if (!kstrtoul(str, 0, &enforcing))
116aa8e712cSStephen Smalley 		selinux_enforcing_boot = enforcing ? 1 : 0;
1171da177e4SLinus Torvalds 	return 1;
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds __setup("enforcing=", enforcing_setup);
120aa8e712cSStephen Smalley #else
121aa8e712cSStephen Smalley #define selinux_enforcing_boot 1
1221da177e4SLinus Torvalds #endif
1231da177e4SLinus Torvalds 
1241da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
1251da177e4SLinus Torvalds int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE;
1261da177e4SLinus Torvalds 
1271da177e4SLinus Torvalds static int __init selinux_enabled_setup(char *str)
1281da177e4SLinus Torvalds {
129f5269710SEric Paris 	unsigned long enabled;
13029707b20SJingoo Han 	if (!kstrtoul(str, 0, &enabled))
131f5269710SEric Paris 		selinux_enabled = enabled ? 1 : 0;
1321da177e4SLinus Torvalds 	return 1;
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds __setup("selinux=", selinux_enabled_setup);
13530d55280SStephen Smalley #else
13630d55280SStephen Smalley int selinux_enabled = 1;
1371da177e4SLinus Torvalds #endif
1381da177e4SLinus Torvalds 
139aa8e712cSStephen Smalley static unsigned int selinux_checkreqprot_boot =
140aa8e712cSStephen Smalley 	CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
141aa8e712cSStephen Smalley 
142aa8e712cSStephen Smalley static int __init checkreqprot_setup(char *str)
143aa8e712cSStephen Smalley {
144aa8e712cSStephen Smalley 	unsigned long checkreqprot;
145aa8e712cSStephen Smalley 
146aa8e712cSStephen Smalley 	if (!kstrtoul(str, 0, &checkreqprot))
147aa8e712cSStephen Smalley 		selinux_checkreqprot_boot = checkreqprot ? 1 : 0;
148aa8e712cSStephen Smalley 	return 1;
149aa8e712cSStephen Smalley }
150aa8e712cSStephen Smalley __setup("checkreqprot=", checkreqprot_setup);
151aa8e712cSStephen Smalley 
152e18b890bSChristoph Lameter static struct kmem_cache *sel_inode_cache;
15363205654SSangwoo static struct kmem_cache *file_security_cache;
1547cae7e26SJames Morris 
155d621d35eSPaul Moore /**
156d621d35eSPaul Moore  * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
157d621d35eSPaul Moore  *
158d621d35eSPaul Moore  * Description:
159d621d35eSPaul Moore  * This function checks the SECMARK reference counter to see if any SECMARK
160d621d35eSPaul Moore  * targets are currently configured, if the reference counter is greater than
161d621d35eSPaul Moore  * zero SECMARK is considered to be enabled.  Returns true (1) if SECMARK is
1622be4d74fSChris PeBenito  * enabled, false (0) if SECMARK is disabled.  If the always_check_network
1632be4d74fSChris PeBenito  * policy capability is enabled, SECMARK is always considered enabled.
164d621d35eSPaul Moore  *
165d621d35eSPaul Moore  */
166d621d35eSPaul Moore static int selinux_secmark_enabled(void)
167d621d35eSPaul Moore {
168aa8e712cSStephen Smalley 	return (selinux_policycap_alwaysnetwork() ||
169aa8e712cSStephen Smalley 		atomic_read(&selinux_secmark_refcount));
1702be4d74fSChris PeBenito }
1712be4d74fSChris PeBenito 
1722be4d74fSChris PeBenito /**
1732be4d74fSChris PeBenito  * selinux_peerlbl_enabled - Check to see if peer labeling is currently enabled
1742be4d74fSChris PeBenito  *
1752be4d74fSChris PeBenito  * Description:
1762be4d74fSChris PeBenito  * This function checks if NetLabel or labeled IPSEC is enabled.  Returns true
1772be4d74fSChris PeBenito  * (1) if any are enabled or false (0) if neither are enabled.  If the
1782be4d74fSChris PeBenito  * always_check_network policy capability is enabled, peer labeling
1792be4d74fSChris PeBenito  * is always considered enabled.
1802be4d74fSChris PeBenito  *
1812be4d74fSChris PeBenito  */
1822be4d74fSChris PeBenito static int selinux_peerlbl_enabled(void)
1832be4d74fSChris PeBenito {
184aa8e712cSStephen Smalley 	return (selinux_policycap_alwaysnetwork() ||
185aa8e712cSStephen Smalley 		netlbl_enabled() || selinux_xfrm_enabled());
186d621d35eSPaul Moore }
187d621d35eSPaul Moore 
188615e51fdSPaul Moore static int selinux_netcache_avc_callback(u32 event)
189615e51fdSPaul Moore {
190615e51fdSPaul Moore 	if (event == AVC_CALLBACK_RESET) {
191615e51fdSPaul Moore 		sel_netif_flush();
192615e51fdSPaul Moore 		sel_netnode_flush();
193615e51fdSPaul Moore 		sel_netport_flush();
194615e51fdSPaul Moore 		synchronize_net();
195615e51fdSPaul Moore 	}
196615e51fdSPaul Moore 	return 0;
197615e51fdSPaul Moore }
198615e51fdSPaul Moore 
1998f408ab6SDaniel Jurgens static int selinux_lsm_notifier_avc_callback(u32 event)
2008f408ab6SDaniel Jurgens {
201409dcf31SDaniel Jurgens 	if (event == AVC_CALLBACK_RESET) {
202409dcf31SDaniel Jurgens 		sel_ib_pkey_flush();
2038f408ab6SDaniel Jurgens 		call_lsm_notifier(LSM_POLICY_CHANGE, NULL);
204409dcf31SDaniel Jurgens 	}
2058f408ab6SDaniel Jurgens 
2068f408ab6SDaniel Jurgens 	return 0;
2078f408ab6SDaniel Jurgens }
2088f408ab6SDaniel Jurgens 
209d84f4f99SDavid Howells /*
210d84f4f99SDavid Howells  * initialise the security for the init task
211d84f4f99SDavid Howells  */
212d84f4f99SDavid Howells static void cred_init_security(void)
2131da177e4SLinus Torvalds {
2143b11a1deSDavid Howells 	struct cred *cred = (struct cred *) current->real_cred;
2151da177e4SLinus Torvalds 	struct task_security_struct *tsec;
2161da177e4SLinus Torvalds 
21789d155efSJames Morris 	tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL);
2181da177e4SLinus Torvalds 	if (!tsec)
219d84f4f99SDavid Howells 		panic("SELinux:  Failed to initialize initial task.\n");
2201da177e4SLinus Torvalds 
221d84f4f99SDavid Howells 	tsec->osid = tsec->sid = SECINITSID_KERNEL;
222f1752eecSDavid Howells 	cred->security = tsec;
2231da177e4SLinus Torvalds }
2241da177e4SLinus Torvalds 
225275bb41eSDavid Howells /*
22688e67f3bSDavid Howells  * get the security ID of a set of credentials
22788e67f3bSDavid Howells  */
22888e67f3bSDavid Howells static inline u32 cred_sid(const struct cred *cred)
22988e67f3bSDavid Howells {
23088e67f3bSDavid Howells 	const struct task_security_struct *tsec;
23188e67f3bSDavid Howells 
23288e67f3bSDavid Howells 	tsec = cred->security;
23388e67f3bSDavid Howells 	return tsec->sid;
23488e67f3bSDavid Howells }
23588e67f3bSDavid Howells 
23688e67f3bSDavid Howells /*
2373b11a1deSDavid Howells  * get the objective security ID of a task
238275bb41eSDavid Howells  */
239275bb41eSDavid Howells static inline u32 task_sid(const struct task_struct *task)
240275bb41eSDavid Howells {
241275bb41eSDavid Howells 	u32 sid;
242275bb41eSDavid Howells 
243275bb41eSDavid Howells 	rcu_read_lock();
24488e67f3bSDavid Howells 	sid = cred_sid(__task_cred(task));
245275bb41eSDavid Howells 	rcu_read_unlock();
246275bb41eSDavid Howells 	return sid;
247275bb41eSDavid Howells }
248275bb41eSDavid Howells 
24988e67f3bSDavid Howells /* Allocate and free functions for each kind of security blob. */
25088e67f3bSDavid Howells 
2511da177e4SLinus Torvalds static int inode_alloc_security(struct inode *inode)
2521da177e4SLinus Torvalds {
2531da177e4SLinus Torvalds 	struct inode_security_struct *isec;
254275bb41eSDavid Howells 	u32 sid = current_sid();
2551da177e4SLinus Torvalds 
256a02fe132SJosef Bacik 	isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS);
2571da177e4SLinus Torvalds 	if (!isec)
2581da177e4SLinus Torvalds 		return -ENOMEM;
2591da177e4SLinus Torvalds 
2609287aed2SAndreas Gruenbacher 	spin_lock_init(&isec->lock);
2611da177e4SLinus Torvalds 	INIT_LIST_HEAD(&isec->list);
2621da177e4SLinus Torvalds 	isec->inode = inode;
2631da177e4SLinus Torvalds 	isec->sid = SECINITSID_UNLABELED;
2641da177e4SLinus Torvalds 	isec->sclass = SECCLASS_FILE;
265275bb41eSDavid Howells 	isec->task_sid = sid;
26642059112SAndreas Gruenbacher 	isec->initialized = LABEL_INVALID;
2671da177e4SLinus Torvalds 	inode->i_security = isec;
2681da177e4SLinus Torvalds 
2691da177e4SLinus Torvalds 	return 0;
2701da177e4SLinus Torvalds }
2711da177e4SLinus Torvalds 
2725d226df4SAndreas Gruenbacher static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
2735d226df4SAndreas Gruenbacher 
2745d226df4SAndreas Gruenbacher /*
2755d226df4SAndreas Gruenbacher  * Try reloading inode security labels that have been marked as invalid.  The
2765d226df4SAndreas Gruenbacher  * @may_sleep parameter indicates when sleeping and thus reloading labels is
27742059112SAndreas Gruenbacher  * allowed; when set to false, returns -ECHILD when the label is
278e9193288SAl Viro  * invalid.  The @dentry parameter should be set to a dentry of the inode.
2795d226df4SAndreas Gruenbacher  */
2805d226df4SAndreas Gruenbacher static int __inode_security_revalidate(struct inode *inode,
281e9193288SAl Viro 				       struct dentry *dentry,
2825d226df4SAndreas Gruenbacher 				       bool may_sleep)
2835d226df4SAndreas Gruenbacher {
2845d226df4SAndreas Gruenbacher 	struct inode_security_struct *isec = inode->i_security;
2855d226df4SAndreas Gruenbacher 
2865d226df4SAndreas Gruenbacher 	might_sleep_if(may_sleep);
2875d226df4SAndreas Gruenbacher 
288aa8e712cSStephen Smalley 	if (selinux_state.initialized &&
289aa8e712cSStephen Smalley 	    isec->initialized != LABEL_INITIALIZED) {
2905d226df4SAndreas Gruenbacher 		if (!may_sleep)
2915d226df4SAndreas Gruenbacher 			return -ECHILD;
2925d226df4SAndreas Gruenbacher 
2935d226df4SAndreas Gruenbacher 		/*
2945d226df4SAndreas Gruenbacher 		 * Try reloading the inode security label.  This will fail if
2955d226df4SAndreas Gruenbacher 		 * @opt_dentry is NULL and no dentry for this inode can be
2965d226df4SAndreas Gruenbacher 		 * found; in that case, continue using the old label.
2975d226df4SAndreas Gruenbacher 		 */
298e9193288SAl Viro 		inode_doinit_with_dentry(inode, dentry);
2995d226df4SAndreas Gruenbacher 	}
3005d226df4SAndreas Gruenbacher 	return 0;
3015d226df4SAndreas Gruenbacher }
3025d226df4SAndreas Gruenbacher 
3035d226df4SAndreas Gruenbacher static struct inode_security_struct *inode_security_novalidate(struct inode *inode)
3045d226df4SAndreas Gruenbacher {
3055d226df4SAndreas Gruenbacher 	return inode->i_security;
3065d226df4SAndreas Gruenbacher }
3075d226df4SAndreas Gruenbacher 
3085d226df4SAndreas Gruenbacher static struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu)
3095d226df4SAndreas Gruenbacher {
3105d226df4SAndreas Gruenbacher 	int error;
3115d226df4SAndreas Gruenbacher 
3125d226df4SAndreas Gruenbacher 	error = __inode_security_revalidate(inode, NULL, !rcu);
3135d226df4SAndreas Gruenbacher 	if (error)
3145d226df4SAndreas Gruenbacher 		return ERR_PTR(error);
3155d226df4SAndreas Gruenbacher 	return inode->i_security;
3165d226df4SAndreas Gruenbacher }
3175d226df4SAndreas Gruenbacher 
31883da53c5SAndreas Gruenbacher /*
31983da53c5SAndreas Gruenbacher  * Get the security label of an inode.
32083da53c5SAndreas Gruenbacher  */
32183da53c5SAndreas Gruenbacher static struct inode_security_struct *inode_security(struct inode *inode)
32283da53c5SAndreas Gruenbacher {
3235d226df4SAndreas Gruenbacher 	__inode_security_revalidate(inode, NULL, true);
32483da53c5SAndreas Gruenbacher 	return inode->i_security;
32583da53c5SAndreas Gruenbacher }
32683da53c5SAndreas Gruenbacher 
3272c97165bSPaul Moore static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry)
3282c97165bSPaul Moore {
3292c97165bSPaul Moore 	struct inode *inode = d_backing_inode(dentry);
3302c97165bSPaul Moore 
3312c97165bSPaul Moore 	return inode->i_security;
3322c97165bSPaul Moore }
3332c97165bSPaul Moore 
33483da53c5SAndreas Gruenbacher /*
33583da53c5SAndreas Gruenbacher  * Get the security label of a dentry's backing inode.
33683da53c5SAndreas Gruenbacher  */
33783da53c5SAndreas Gruenbacher static struct inode_security_struct *backing_inode_security(struct dentry *dentry)
33883da53c5SAndreas Gruenbacher {
33983da53c5SAndreas Gruenbacher 	struct inode *inode = d_backing_inode(dentry);
34083da53c5SAndreas Gruenbacher 
3415d226df4SAndreas Gruenbacher 	__inode_security_revalidate(inode, dentry, true);
34283da53c5SAndreas Gruenbacher 	return inode->i_security;
34383da53c5SAndreas Gruenbacher }
34483da53c5SAndreas Gruenbacher 
3453dc91d43SSteven Rostedt static void inode_free_rcu(struct rcu_head *head)
3463dc91d43SSteven Rostedt {
3473dc91d43SSteven Rostedt 	struct inode_security_struct *isec;
3483dc91d43SSteven Rostedt 
3493dc91d43SSteven Rostedt 	isec = container_of(head, struct inode_security_struct, rcu);
3503dc91d43SSteven Rostedt 	kmem_cache_free(sel_inode_cache, isec);
3513dc91d43SSteven Rostedt }
3523dc91d43SSteven Rostedt 
3531da177e4SLinus Torvalds static void inode_free_security(struct inode *inode)
3541da177e4SLinus Torvalds {
3551da177e4SLinus Torvalds 	struct inode_security_struct *isec = inode->i_security;
3561da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec = inode->i_sb->s_security;
3571da177e4SLinus Torvalds 
3589629d04aSWaiman Long 	/*
3599629d04aSWaiman Long 	 * As not all inode security structures are in a list, we check for
3609629d04aSWaiman Long 	 * empty list outside of the lock to make sure that we won't waste
3619629d04aSWaiman Long 	 * time taking a lock doing nothing.
3629629d04aSWaiman Long 	 *
3639629d04aSWaiman Long 	 * The list_del_init() function can be safely called more than once.
3649629d04aSWaiman Long 	 * It should not be possible for this function to be called with
3659629d04aSWaiman Long 	 * concurrent list_add(), but for better safety against future changes
3669629d04aSWaiman Long 	 * in the code, we use list_empty_careful() here.
3679629d04aSWaiman Long 	 */
3689629d04aSWaiman Long 	if (!list_empty_careful(&isec->list)) {
3691da177e4SLinus Torvalds 		spin_lock(&sbsec->isec_lock);
3701da177e4SLinus Torvalds 		list_del_init(&isec->list);
3711da177e4SLinus Torvalds 		spin_unlock(&sbsec->isec_lock);
3729629d04aSWaiman Long 	}
3731da177e4SLinus Torvalds 
3743dc91d43SSteven Rostedt 	/*
3753dc91d43SSteven Rostedt 	 * The inode may still be referenced in a path walk and
3763dc91d43SSteven Rostedt 	 * a call to selinux_inode_permission() can be made
3773dc91d43SSteven Rostedt 	 * after inode_free_security() is called. Ideally, the VFS
3783dc91d43SSteven Rostedt 	 * wouldn't do this, but fixing that is a much harder
3793dc91d43SSteven Rostedt 	 * job. For now, simply free the i_security via RCU, and
3803dc91d43SSteven Rostedt 	 * leave the current inode->i_security pointer intact.
3813dc91d43SSteven Rostedt 	 * The inode will be freed after the RCU grace period too.
3823dc91d43SSteven Rostedt 	 */
3833dc91d43SSteven Rostedt 	call_rcu(&isec->rcu, inode_free_rcu);
3841da177e4SLinus Torvalds }
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds static int file_alloc_security(struct file *file)
3871da177e4SLinus Torvalds {
3881da177e4SLinus Torvalds 	struct file_security_struct *fsec;
389275bb41eSDavid Howells 	u32 sid = current_sid();
3901da177e4SLinus Torvalds 
39163205654SSangwoo 	fsec = kmem_cache_zalloc(file_security_cache, GFP_KERNEL);
3921da177e4SLinus Torvalds 	if (!fsec)
3931da177e4SLinus Torvalds 		return -ENOMEM;
3941da177e4SLinus Torvalds 
395275bb41eSDavid Howells 	fsec->sid = sid;
396275bb41eSDavid Howells 	fsec->fown_sid = sid;
3971da177e4SLinus Torvalds 	file->f_security = fsec;
3981da177e4SLinus Torvalds 
3991da177e4SLinus Torvalds 	return 0;
4001da177e4SLinus Torvalds }
4011da177e4SLinus Torvalds 
4021da177e4SLinus Torvalds static void file_free_security(struct file *file)
4031da177e4SLinus Torvalds {
4041da177e4SLinus Torvalds 	struct file_security_struct *fsec = file->f_security;
4051da177e4SLinus Torvalds 	file->f_security = NULL;
40663205654SSangwoo 	kmem_cache_free(file_security_cache, fsec);
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds 
4091da177e4SLinus Torvalds static int superblock_alloc_security(struct super_block *sb)
4101da177e4SLinus Torvalds {
4111da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec;
4121da177e4SLinus Torvalds 
41389d155efSJames Morris 	sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
4141da177e4SLinus Torvalds 	if (!sbsec)
4151da177e4SLinus Torvalds 		return -ENOMEM;
4161da177e4SLinus Torvalds 
417bc7e982bSEric Paris 	mutex_init(&sbsec->lock);
4181da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sbsec->isec_head);
4191da177e4SLinus Torvalds 	spin_lock_init(&sbsec->isec_lock);
4201da177e4SLinus Torvalds 	sbsec->sb = sb;
4211da177e4SLinus Torvalds 	sbsec->sid = SECINITSID_UNLABELED;
4221da177e4SLinus Torvalds 	sbsec->def_sid = SECINITSID_FILE;
423c312feb2SEric Paris 	sbsec->mntpoint_sid = SECINITSID_UNLABELED;
4241da177e4SLinus Torvalds 	sb->s_security = sbsec;
4251da177e4SLinus Torvalds 
4261da177e4SLinus Torvalds 	return 0;
4271da177e4SLinus Torvalds }
4281da177e4SLinus Torvalds 
4291da177e4SLinus Torvalds static void superblock_free_security(struct super_block *sb)
4301da177e4SLinus Torvalds {
4311da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec = sb->s_security;
4321da177e4SLinus Torvalds 	sb->s_security = NULL;
4331da177e4SLinus Torvalds 	kfree(sbsec);
4341da177e4SLinus Torvalds }
4351da177e4SLinus Torvalds 
436bd323655SAl Viro struct selinux_mnt_opts {
437bd323655SAl Viro 	const char *fscontext, *context, *rootcontext, *defcontext;
438bd323655SAl Viro };
439bd323655SAl Viro 
440204cc0ccSAl Viro static void selinux_free_mnt_opts(void *mnt_opts)
441204cc0ccSAl Viro {
442bd323655SAl Viro 	struct selinux_mnt_opts *opts = mnt_opts;
443bd323655SAl Viro 	kfree(opts->fscontext);
444bd323655SAl Viro 	kfree(opts->context);
445bd323655SAl Viro 	kfree(opts->rootcontext);
446bd323655SAl Viro 	kfree(opts->defcontext);
447204cc0ccSAl Viro 	kfree(opts);
448204cc0ccSAl Viro }
449204cc0ccSAl Viro 
4501da177e4SLinus Torvalds static inline int inode_doinit(struct inode *inode)
4511da177e4SLinus Torvalds {
4521da177e4SLinus Torvalds 	return inode_doinit_with_dentry(inode, NULL);
4531da177e4SLinus Torvalds }
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds enum {
45631e87930SEric Paris 	Opt_error = -1,
4571da177e4SLinus Torvalds 	Opt_context = 1,
4581da177e4SLinus Torvalds 	Opt_fscontext = 2,
459c9180a57SEric Paris 	Opt_defcontext = 3,
460c9180a57SEric Paris 	Opt_rootcontext = 4,
461*da3d76abSAl Viro 	Opt_seclabel = 5,
4621da177e4SLinus Torvalds };
4631da177e4SLinus Torvalds 
464*da3d76abSAl Viro #define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg}
465169d68efSAl Viro static struct {
466169d68efSAl Viro 	const char *name;
467169d68efSAl Viro 	int len;
468169d68efSAl Viro 	int opt;
469169d68efSAl Viro 	bool has_arg;
470169d68efSAl Viro } tokens[] = {
471*da3d76abSAl Viro 	A(context, true),
472*da3d76abSAl Viro 	A(fscontext, true),
473*da3d76abSAl Viro 	A(defcontext, true),
474*da3d76abSAl Viro 	A(rootcontext, true),
475*da3d76abSAl Viro 	A(seclabel, false),
4761da177e4SLinus Torvalds };
477169d68efSAl Viro #undef A
478169d68efSAl Viro 
479169d68efSAl Viro static int match_opt_prefix(char *s, int l, char **arg)
480169d68efSAl Viro {
481169d68efSAl Viro 	int i;
482169d68efSAl Viro 
483169d68efSAl Viro 	for (i = 0; i < ARRAY_SIZE(tokens); i++) {
484169d68efSAl Viro 		size_t len = tokens[i].len;
485169d68efSAl Viro 		if (len > l || memcmp(s, tokens[i].name, len))
486169d68efSAl Viro 			continue;
487169d68efSAl Viro 		if (tokens[i].has_arg) {
488169d68efSAl Viro 			if (len == l || s[len] != '=')
489169d68efSAl Viro 				continue;
490169d68efSAl Viro 			*arg = s + len + 1;
491169d68efSAl Viro 		} else if (len != l)
492169d68efSAl Viro 			continue;
493169d68efSAl Viro 		return tokens[i].opt;
494169d68efSAl Viro 	}
495169d68efSAl Viro 	return Opt_error;
496169d68efSAl Viro }
4971da177e4SLinus Torvalds 
4981da177e4SLinus Torvalds #define SEL_MOUNT_FAIL_MSG "SELinux:  duplicate or incompatible mount options\n"
4991da177e4SLinus Torvalds 
500c312feb2SEric Paris static int may_context_mount_sb_relabel(u32 sid,
501c312feb2SEric Paris 			struct superblock_security_struct *sbsec,
502275bb41eSDavid Howells 			const struct cred *cred)
503c312feb2SEric Paris {
504275bb41eSDavid Howells 	const struct task_security_struct *tsec = cred->security;
505c312feb2SEric Paris 	int rc;
506c312feb2SEric Paris 
5076b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
5086b6bc620SStephen Smalley 			  tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
509c312feb2SEric Paris 			  FILESYSTEM__RELABELFROM, NULL);
510c312feb2SEric Paris 	if (rc)
511c312feb2SEric Paris 		return rc;
512c312feb2SEric Paris 
5136b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
5146b6bc620SStephen Smalley 			  tsec->sid, sid, SECCLASS_FILESYSTEM,
515c312feb2SEric Paris 			  FILESYSTEM__RELABELTO, NULL);
516c312feb2SEric Paris 	return rc;
517c312feb2SEric Paris }
518c312feb2SEric Paris 
5190808925eSEric Paris static int may_context_mount_inode_relabel(u32 sid,
5200808925eSEric Paris 			struct superblock_security_struct *sbsec,
521275bb41eSDavid Howells 			const struct cred *cred)
5220808925eSEric Paris {
523275bb41eSDavid Howells 	const struct task_security_struct *tsec = cred->security;
5240808925eSEric Paris 	int rc;
5256b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
5266b6bc620SStephen Smalley 			  tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
5270808925eSEric Paris 			  FILESYSTEM__RELABELFROM, NULL);
5280808925eSEric Paris 	if (rc)
5290808925eSEric Paris 		return rc;
5300808925eSEric Paris 
5316b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
5326b6bc620SStephen Smalley 			  sid, sbsec->sid, SECCLASS_FILESYSTEM,
5330808925eSEric Paris 			  FILESYSTEM__ASSOCIATE, NULL);
5340808925eSEric Paris 	return rc;
5350808925eSEric Paris }
5360808925eSEric Paris 
537b43e725dSEric Paris static int selinux_is_sblabel_mnt(struct super_block *sb)
538b43e725dSEric Paris {
539b43e725dSEric Paris 	struct superblock_security_struct *sbsec = sb->s_security;
540b43e725dSEric Paris 
541d5f3a5f6SMark Salyzyn 	return sbsec->behavior == SECURITY_FS_USE_XATTR ||
542b43e725dSEric Paris 		sbsec->behavior == SECURITY_FS_USE_TRANS ||
543d5f3a5f6SMark Salyzyn 		sbsec->behavior == SECURITY_FS_USE_TASK ||
5449fc2b4b4SJ. Bruce Fields 		sbsec->behavior == SECURITY_FS_USE_NATIVE ||
545d5f3a5f6SMark Salyzyn 		/* Special handling. Genfs but also in-core setxattr handler */
546d5f3a5f6SMark Salyzyn 		!strcmp(sb->s_type->name, "sysfs") ||
547d5f3a5f6SMark Salyzyn 		!strcmp(sb->s_type->name, "pstore") ||
548d5f3a5f6SMark Salyzyn 		!strcmp(sb->s_type->name, "debugfs") ||
549a2c7c6fbSYongqin Liu 		!strcmp(sb->s_type->name, "tracefs") ||
5502651225bSStephen Smalley 		!strcmp(sb->s_type->name, "rootfs") ||
551aa8e712cSStephen Smalley 		(selinux_policycap_cgroupseclabel() &&
5522651225bSStephen Smalley 		 (!strcmp(sb->s_type->name, "cgroup") ||
5532651225bSStephen Smalley 		  !strcmp(sb->s_type->name, "cgroup2")));
554b43e725dSEric Paris }
555b43e725dSEric Paris 
556c9180a57SEric Paris static int sb_finish_set_opts(struct super_block *sb)
5571da177e4SLinus Torvalds {
5581da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec = sb->s_security;
5591da177e4SLinus Torvalds 	struct dentry *root = sb->s_root;
560c6f493d6SDavid Howells 	struct inode *root_inode = d_backing_inode(root);
5611da177e4SLinus Torvalds 	int rc = 0;
5621da177e4SLinus Torvalds 
5631da177e4SLinus Torvalds 	if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
5641da177e4SLinus Torvalds 		/* Make sure that the xattr handler exists and that no
5651da177e4SLinus Torvalds 		   error other than -ENODATA is returned by getxattr on
5661da177e4SLinus Torvalds 		   the root directory.  -ENODATA is ok, as this may be
5671da177e4SLinus Torvalds 		   the first boot of the SELinux kernel before we have
5681da177e4SLinus Torvalds 		   assigned xattr values to the filesystem. */
5695d6c3191SAndreas Gruenbacher 		if (!(root_inode->i_opflags & IOP_XATTR)) {
570c103a91eSpeter enderborg 			pr_warn("SELinux: (dev %s, type %s) has no "
57129b1deb2SLinus Torvalds 			       "xattr support\n", sb->s_id, sb->s_type->name);
5721da177e4SLinus Torvalds 			rc = -EOPNOTSUPP;
5731da177e4SLinus Torvalds 			goto out;
5741da177e4SLinus Torvalds 		}
5755d6c3191SAndreas Gruenbacher 
5765d6c3191SAndreas Gruenbacher 		rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
5771da177e4SLinus Torvalds 		if (rc < 0 && rc != -ENODATA) {
5781da177e4SLinus Torvalds 			if (rc == -EOPNOTSUPP)
579c103a91eSpeter enderborg 				pr_warn("SELinux: (dev %s, type "
58029b1deb2SLinus Torvalds 				       "%s) has no security xattr handler\n",
58129b1deb2SLinus Torvalds 				       sb->s_id, sb->s_type->name);
5821da177e4SLinus Torvalds 			else
583c103a91eSpeter enderborg 				pr_warn("SELinux: (dev %s, type "
58429b1deb2SLinus Torvalds 				       "%s) getxattr errno %d\n", sb->s_id,
58529b1deb2SLinus Torvalds 				       sb->s_type->name, -rc);
5861da177e4SLinus Torvalds 			goto out;
5871da177e4SLinus Torvalds 		}
5881da177e4SLinus Torvalds 	}
5891da177e4SLinus Torvalds 
590eadcabc6SEric Paris 	sbsec->flags |= SE_SBINITIALIZED;
5910b4d3452SScott Mayhew 
5920b4d3452SScott Mayhew 	/*
5930b4d3452SScott Mayhew 	 * Explicitly set or clear SBLABEL_MNT.  It's not sufficient to simply
5940b4d3452SScott Mayhew 	 * leave the flag untouched because sb_clone_mnt_opts might be handing
5950b4d3452SScott Mayhew 	 * us a superblock that needs the flag to be cleared.
5960b4d3452SScott Mayhew 	 */
597b43e725dSEric Paris 	if (selinux_is_sblabel_mnt(sb))
59812f348b9SEric Paris 		sbsec->flags |= SBLABEL_MNT;
5990b4d3452SScott Mayhew 	else
6000b4d3452SScott Mayhew 		sbsec->flags &= ~SBLABEL_MNT;
601ddd29ec6SDavid P. Quigley 
6021da177e4SLinus Torvalds 	/* Initialize the root inode. */
603c9180a57SEric Paris 	rc = inode_doinit_with_dentry(root_inode, root);
6041da177e4SLinus Torvalds 
6051da177e4SLinus Torvalds 	/* Initialize any other inodes associated with the superblock, e.g.
6061da177e4SLinus Torvalds 	   inodes created prior to initial policy load or inodes created
6071da177e4SLinus Torvalds 	   during get_sb by a pseudo filesystem that directly
6081da177e4SLinus Torvalds 	   populates itself. */
6091da177e4SLinus Torvalds 	spin_lock(&sbsec->isec_lock);
6108d64124aSAl Viro 	while (!list_empty(&sbsec->isec_head)) {
6111da177e4SLinus Torvalds 		struct inode_security_struct *isec =
6128d64124aSAl Viro 				list_first_entry(&sbsec->isec_head,
6131da177e4SLinus Torvalds 					   struct inode_security_struct, list);
6141da177e4SLinus Torvalds 		struct inode *inode = isec->inode;
615923190d3SStephen Smalley 		list_del_init(&isec->list);
6161da177e4SLinus Torvalds 		spin_unlock(&sbsec->isec_lock);
6171da177e4SLinus Torvalds 		inode = igrab(inode);
6181da177e4SLinus Torvalds 		if (inode) {
6191da177e4SLinus Torvalds 			if (!IS_PRIVATE(inode))
6201da177e4SLinus Torvalds 				inode_doinit(inode);
6211da177e4SLinus Torvalds 			iput(inode);
6221da177e4SLinus Torvalds 		}
6231da177e4SLinus Torvalds 		spin_lock(&sbsec->isec_lock);
6241da177e4SLinus Torvalds 	}
6251da177e4SLinus Torvalds 	spin_unlock(&sbsec->isec_lock);
6261da177e4SLinus Torvalds out:
627c9180a57SEric Paris 	return rc;
628c9180a57SEric Paris }
629c9180a57SEric Paris 
630c9180a57SEric Paris static int bad_option(struct superblock_security_struct *sbsec, char flag,
631c9180a57SEric Paris 		      u32 old_sid, u32 new_sid)
632c9180a57SEric Paris {
6330d90a7ecSDavid P. Quigley 	char mnt_flags = sbsec->flags & SE_MNTMASK;
6340d90a7ecSDavid P. Quigley 
635c9180a57SEric Paris 	/* check if the old mount command had the same options */
6360d90a7ecSDavid P. Quigley 	if (sbsec->flags & SE_SBINITIALIZED)
637c9180a57SEric Paris 		if (!(sbsec->flags & flag) ||
638c9180a57SEric Paris 		    (old_sid != new_sid))
639c9180a57SEric Paris 			return 1;
640c9180a57SEric Paris 
641c9180a57SEric Paris 	/* check if we were passed the same options twice,
642c9180a57SEric Paris 	 * aka someone passed context=a,context=b
643c9180a57SEric Paris 	 */
6440d90a7ecSDavid P. Quigley 	if (!(sbsec->flags & SE_SBINITIALIZED))
6450d90a7ecSDavid P. Quigley 		if (mnt_flags & flag)
646c9180a57SEric Paris 			return 1;
647c9180a57SEric Paris 	return 0;
648c9180a57SEric Paris }
649e0007529SEric Paris 
650bd323655SAl Viro static int parse_sid(struct super_block *sb, const char *s, u32 *sid)
651bd323655SAl Viro {
652bd323655SAl Viro 	int rc = security_context_str_to_sid(&selinux_state, s,
653bd323655SAl Viro 					     sid, GFP_KERNEL);
654bd323655SAl Viro 	if (rc)
655bd323655SAl Viro 		pr_warn("SELinux: security_context_str_to_sid"
656bd323655SAl Viro 		       "(%s) failed for (dev %s, type %s) errno=%d\n",
657bd323655SAl Viro 		       s, sb->s_id, sb->s_type->name, rc);
658bd323655SAl Viro 	return rc;
659bd323655SAl Viro }
660bd323655SAl Viro 
661c9180a57SEric Paris /*
662c9180a57SEric Paris  * Allow filesystems with binary mount data to explicitly set mount point
663c9180a57SEric Paris  * labeling information.
664c9180a57SEric Paris  */
665e0007529SEric Paris static int selinux_set_mnt_opts(struct super_block *sb,
666204cc0ccSAl Viro 				void *mnt_opts,
667649f6e77SDavid Quigley 				unsigned long kern_flags,
668649f6e77SDavid Quigley 				unsigned long *set_kern_flags)
669c9180a57SEric Paris {
670275bb41eSDavid Howells 	const struct cred *cred = current_cred();
671c9180a57SEric Paris 	struct superblock_security_struct *sbsec = sb->s_security;
67283da53c5SAndreas Gruenbacher 	struct dentry *root = sbsec->sb->s_root;
673bd323655SAl Viro 	struct selinux_mnt_opts *opts = mnt_opts;
6742c97165bSPaul Moore 	struct inode_security_struct *root_isec;
675c9180a57SEric Paris 	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
676c9180a57SEric Paris 	u32 defcontext_sid = 0;
677bd323655SAl Viro 	int rc = 0;
678c9180a57SEric Paris 
679c9180a57SEric Paris 	mutex_lock(&sbsec->lock);
680c9180a57SEric Paris 
681aa8e712cSStephen Smalley 	if (!selinux_state.initialized) {
682bd323655SAl Viro 		if (!opts) {
683c9180a57SEric Paris 			/* Defer initialization until selinux_complete_init,
684c9180a57SEric Paris 			   after the initial policy is loaded and the security
685c9180a57SEric Paris 			   server is ready to handle calls. */
686c9180a57SEric Paris 			goto out;
687c9180a57SEric Paris 		}
688c9180a57SEric Paris 		rc = -EINVAL;
689c103a91eSpeter enderborg 		pr_warn("SELinux: Unable to set superblock options "
690744ba35eSEric Paris 			"before the security server is initialized\n");
691c9180a57SEric Paris 		goto out;
692c9180a57SEric Paris 	}
693649f6e77SDavid Quigley 	if (kern_flags && !set_kern_flags) {
694649f6e77SDavid Quigley 		/* Specifying internal flags without providing a place to
695649f6e77SDavid Quigley 		 * place the results is not allowed */
696649f6e77SDavid Quigley 		rc = -EINVAL;
697649f6e77SDavid Quigley 		goto out;
698649f6e77SDavid Quigley 	}
699c9180a57SEric Paris 
700c9180a57SEric Paris 	/*
701e0007529SEric Paris 	 * Binary mount data FS will come through this function twice.  Once
702e0007529SEric Paris 	 * from an explicit call and once from the generic calls from the vfs.
703e0007529SEric Paris 	 * Since the generic VFS calls will not contain any security mount data
704e0007529SEric Paris 	 * we need to skip the double mount verification.
705e0007529SEric Paris 	 *
706e0007529SEric Paris 	 * This does open a hole in which we will not notice if the first
707e0007529SEric Paris 	 * mount using this sb set explict options and a second mount using
708e0007529SEric Paris 	 * this sb does not set any security options.  (The first options
709e0007529SEric Paris 	 * will be used for both mounts)
710e0007529SEric Paris 	 */
7110d90a7ecSDavid P. Quigley 	if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
712bd323655SAl Viro 	    && !opts)
713e0007529SEric Paris 		goto out;
714e0007529SEric Paris 
7152c97165bSPaul Moore 	root_isec = backing_inode_security_novalidate(root);
7162c97165bSPaul Moore 
717e0007529SEric Paris 	/*
718c9180a57SEric Paris 	 * parse the mount options, check if they are valid sids.
719c9180a57SEric Paris 	 * also check if someone is trying to mount the same sb more
720c9180a57SEric Paris 	 * than once with different security options.
721c9180a57SEric Paris 	 */
722bd323655SAl Viro 	if (opts) {
723bd323655SAl Viro 		if (opts->fscontext) {
724bd323655SAl Viro 			rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
725bd323655SAl Viro 			if (rc)
726c9180a57SEric Paris 				goto out;
727c9180a57SEric Paris 			if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
728c9180a57SEric Paris 					fscontext_sid))
729c9180a57SEric Paris 				goto out_double_mount;
730c9180a57SEric Paris 			sbsec->flags |= FSCONTEXT_MNT;
731bd323655SAl Viro 		}
732bd323655SAl Viro 		if (opts->context) {
733bd323655SAl Viro 			rc = parse_sid(sb, opts->context, &context_sid);
734bd323655SAl Viro 			if (rc)
735bd323655SAl Viro 				goto out;
736c9180a57SEric Paris 			if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
737c9180a57SEric Paris 					context_sid))
738c9180a57SEric Paris 				goto out_double_mount;
739c9180a57SEric Paris 			sbsec->flags |= CONTEXT_MNT;
740bd323655SAl Viro 		}
741bd323655SAl Viro 		if (opts->rootcontext) {
742bd323655SAl Viro 			rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
743bd323655SAl Viro 			if (rc)
744bd323655SAl Viro 				goto out;
745c9180a57SEric Paris 			if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
746c9180a57SEric Paris 					rootcontext_sid))
747c9180a57SEric Paris 				goto out_double_mount;
748c9180a57SEric Paris 			sbsec->flags |= ROOTCONTEXT_MNT;
749bd323655SAl Viro 		}
750bd323655SAl Viro 		if (opts->defcontext) {
751bd323655SAl Viro 			rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
752bd323655SAl Viro 			if (rc)
753bd323655SAl Viro 				goto out;
754c9180a57SEric Paris 			if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
755c9180a57SEric Paris 					defcontext_sid))
756c9180a57SEric Paris 				goto out_double_mount;
757c9180a57SEric Paris 			sbsec->flags |= DEFCONTEXT_MNT;
758c9180a57SEric Paris 		}
759c9180a57SEric Paris 	}
760c9180a57SEric Paris 
7610d90a7ecSDavid P. Quigley 	if (sbsec->flags & SE_SBINITIALIZED) {
762c9180a57SEric Paris 		/* previously mounted with options, but not on this attempt? */
763bd323655SAl Viro 		if ((sbsec->flags & SE_MNTMASK) && !opts)
764c9180a57SEric Paris 			goto out_double_mount;
765c9180a57SEric Paris 		rc = 0;
766c9180a57SEric Paris 		goto out;
767c9180a57SEric Paris 	}
768c9180a57SEric Paris 
769089be43eSJames Morris 	if (strcmp(sb->s_type->name, "proc") == 0)
770134509d5SStephen Smalley 		sbsec->flags |= SE_SBPROC | SE_SBGENFS;
771134509d5SStephen Smalley 
7728e014720SStephen Smalley 	if (!strcmp(sb->s_type->name, "debugfs") ||
7736a391183SJeff Vander Stoep 	    !strcmp(sb->s_type->name, "tracefs") ||
7748e014720SStephen Smalley 	    !strcmp(sb->s_type->name, "sysfs") ||
775901ef845SAntonio Murdaca 	    !strcmp(sb->s_type->name, "pstore") ||
776901ef845SAntonio Murdaca 	    !strcmp(sb->s_type->name, "cgroup") ||
777901ef845SAntonio Murdaca 	    !strcmp(sb->s_type->name, "cgroup2"))
778134509d5SStephen Smalley 		sbsec->flags |= SE_SBGENFS;
779c9180a57SEric Paris 
780eb9ae686SDavid Quigley 	if (!sbsec->behavior) {
781eb9ae686SDavid Quigley 		/*
782eb9ae686SDavid Quigley 		 * Determine the labeling behavior to use for this
783eb9ae686SDavid Quigley 		 * filesystem type.
784eb9ae686SDavid Quigley 		 */
785aa8e712cSStephen Smalley 		rc = security_fs_use(&selinux_state, sb);
786c9180a57SEric Paris 		if (rc) {
787c103a91eSpeter enderborg 			pr_warn("%s: security_fs_use(%s) returned %d\n",
788089be43eSJames Morris 					__func__, sb->s_type->name, rc);
789c9180a57SEric Paris 			goto out;
790c9180a57SEric Paris 		}
791eb9ae686SDavid Quigley 	}
792aad82892SSeth Forshee 
793aad82892SSeth Forshee 	/*
79401593d32SStephen Smalley 	 * If this is a user namespace mount and the filesystem type is not
79501593d32SStephen Smalley 	 * explicitly whitelisted, then no contexts are allowed on the command
79601593d32SStephen Smalley 	 * line and security labels must be ignored.
797aad82892SSeth Forshee 	 */
79801593d32SStephen Smalley 	if (sb->s_user_ns != &init_user_ns &&
79901593d32SStephen Smalley 	    strcmp(sb->s_type->name, "tmpfs") &&
80001593d32SStephen Smalley 	    strcmp(sb->s_type->name, "ramfs") &&
80101593d32SStephen Smalley 	    strcmp(sb->s_type->name, "devpts")) {
802aad82892SSeth Forshee 		if (context_sid || fscontext_sid || rootcontext_sid ||
803aad82892SSeth Forshee 		    defcontext_sid) {
804aad82892SSeth Forshee 			rc = -EACCES;
805aad82892SSeth Forshee 			goto out;
806aad82892SSeth Forshee 		}
807aad82892SSeth Forshee 		if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
808aad82892SSeth Forshee 			sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
809aa8e712cSStephen Smalley 			rc = security_transition_sid(&selinux_state,
810aa8e712cSStephen Smalley 						     current_sid(),
811aa8e712cSStephen Smalley 						     current_sid(),
812aad82892SSeth Forshee 						     SECCLASS_FILE, NULL,
813aad82892SSeth Forshee 						     &sbsec->mntpoint_sid);
814aad82892SSeth Forshee 			if (rc)
815aad82892SSeth Forshee 				goto out;
816aad82892SSeth Forshee 		}
817aad82892SSeth Forshee 		goto out_set_opts;
818aad82892SSeth Forshee 	}
819aad82892SSeth Forshee 
820c9180a57SEric Paris 	/* sets the context of the superblock for the fs being mounted. */
821c9180a57SEric Paris 	if (fscontext_sid) {
822275bb41eSDavid Howells 		rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
823c9180a57SEric Paris 		if (rc)
824c9180a57SEric Paris 			goto out;
825c9180a57SEric Paris 
826c9180a57SEric Paris 		sbsec->sid = fscontext_sid;
827c9180a57SEric Paris 	}
828c9180a57SEric Paris 
829c9180a57SEric Paris 	/*
830c9180a57SEric Paris 	 * Switch to using mount point labeling behavior.
831c9180a57SEric Paris 	 * sets the label used on all file below the mountpoint, and will set
832c9180a57SEric Paris 	 * the superblock context if not already set.
833c9180a57SEric Paris 	 */
834eb9ae686SDavid Quigley 	if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
835eb9ae686SDavid Quigley 		sbsec->behavior = SECURITY_FS_USE_NATIVE;
836eb9ae686SDavid Quigley 		*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
837eb9ae686SDavid Quigley 	}
838eb9ae686SDavid Quigley 
839c9180a57SEric Paris 	if (context_sid) {
840c9180a57SEric Paris 		if (!fscontext_sid) {
841275bb41eSDavid Howells 			rc = may_context_mount_sb_relabel(context_sid, sbsec,
842275bb41eSDavid Howells 							  cred);
843c9180a57SEric Paris 			if (rc)
844c9180a57SEric Paris 				goto out;
845c9180a57SEric Paris 			sbsec->sid = context_sid;
846c9180a57SEric Paris 		} else {
847275bb41eSDavid Howells 			rc = may_context_mount_inode_relabel(context_sid, sbsec,
848275bb41eSDavid Howells 							     cred);
849c9180a57SEric Paris 			if (rc)
850c9180a57SEric Paris 				goto out;
851c9180a57SEric Paris 		}
852c9180a57SEric Paris 		if (!rootcontext_sid)
853c9180a57SEric Paris 			rootcontext_sid = context_sid;
854c9180a57SEric Paris 
855c9180a57SEric Paris 		sbsec->mntpoint_sid = context_sid;
856c9180a57SEric Paris 		sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
857c9180a57SEric Paris 	}
858c9180a57SEric Paris 
859c9180a57SEric Paris 	if (rootcontext_sid) {
860275bb41eSDavid Howells 		rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
861275bb41eSDavid Howells 						     cred);
862c9180a57SEric Paris 		if (rc)
863c9180a57SEric Paris 			goto out;
864c9180a57SEric Paris 
865c9180a57SEric Paris 		root_isec->sid = rootcontext_sid;
8666f3be9f5SAndreas Gruenbacher 		root_isec->initialized = LABEL_INITIALIZED;
867c9180a57SEric Paris 	}
868c9180a57SEric Paris 
869c9180a57SEric Paris 	if (defcontext_sid) {
870eb9ae686SDavid Quigley 		if (sbsec->behavior != SECURITY_FS_USE_XATTR &&
871eb9ae686SDavid Quigley 			sbsec->behavior != SECURITY_FS_USE_NATIVE) {
872c9180a57SEric Paris 			rc = -EINVAL;
873c103a91eSpeter enderborg 			pr_warn("SELinux: defcontext option is "
874c9180a57SEric Paris 			       "invalid for this filesystem type\n");
875c9180a57SEric Paris 			goto out;
876c9180a57SEric Paris 		}
877c9180a57SEric Paris 
878c9180a57SEric Paris 		if (defcontext_sid != sbsec->def_sid) {
879c9180a57SEric Paris 			rc = may_context_mount_inode_relabel(defcontext_sid,
880275bb41eSDavid Howells 							     sbsec, cred);
881c9180a57SEric Paris 			if (rc)
882c9180a57SEric Paris 				goto out;
883c9180a57SEric Paris 		}
884c9180a57SEric Paris 
885c9180a57SEric Paris 		sbsec->def_sid = defcontext_sid;
886c9180a57SEric Paris 	}
887c9180a57SEric Paris 
888aad82892SSeth Forshee out_set_opts:
889c9180a57SEric Paris 	rc = sb_finish_set_opts(sb);
890c9180a57SEric Paris out:
891bc7e982bSEric Paris 	mutex_unlock(&sbsec->lock);
8921da177e4SLinus Torvalds 	return rc;
893c9180a57SEric Paris out_double_mount:
894c9180a57SEric Paris 	rc = -EINVAL;
895c103a91eSpeter enderborg 	pr_warn("SELinux: mount invalid.  Same superblock, different "
896bd323655SAl Viro 	       "security settings for (dev %s, type %s)\n", sb->s_id,
897bd323655SAl Viro 	       sb->s_type->name);
898c9180a57SEric Paris 	goto out;
899c9180a57SEric Paris }
900c9180a57SEric Paris 
901094f7b69SJeff Layton static int selinux_cmp_sb_context(const struct super_block *oldsb,
902094f7b69SJeff Layton 				    const struct super_block *newsb)
903094f7b69SJeff Layton {
904094f7b69SJeff Layton 	struct superblock_security_struct *old = oldsb->s_security;
905094f7b69SJeff Layton 	struct superblock_security_struct *new = newsb->s_security;
906094f7b69SJeff Layton 	char oldflags = old->flags & SE_MNTMASK;
907094f7b69SJeff Layton 	char newflags = new->flags & SE_MNTMASK;
908094f7b69SJeff Layton 
909094f7b69SJeff Layton 	if (oldflags != newflags)
910094f7b69SJeff Layton 		goto mismatch;
911094f7b69SJeff Layton 	if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid)
912094f7b69SJeff Layton 		goto mismatch;
913094f7b69SJeff Layton 	if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid)
914094f7b69SJeff Layton 		goto mismatch;
915094f7b69SJeff Layton 	if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid)
916094f7b69SJeff Layton 		goto mismatch;
917094f7b69SJeff Layton 	if (oldflags & ROOTCONTEXT_MNT) {
91883da53c5SAndreas Gruenbacher 		struct inode_security_struct *oldroot = backing_inode_security(oldsb->s_root);
91983da53c5SAndreas Gruenbacher 		struct inode_security_struct *newroot = backing_inode_security(newsb->s_root);
920094f7b69SJeff Layton 		if (oldroot->sid != newroot->sid)
921094f7b69SJeff Layton 			goto mismatch;
922094f7b69SJeff Layton 	}
923094f7b69SJeff Layton 	return 0;
924094f7b69SJeff Layton mismatch:
925c103a91eSpeter enderborg 	pr_warn("SELinux: mount invalid.  Same superblock, "
926094f7b69SJeff Layton 			    "different security settings for (dev %s, "
927094f7b69SJeff Layton 			    "type %s)\n", newsb->s_id, newsb->s_type->name);
928094f7b69SJeff Layton 	return -EBUSY;
929094f7b69SJeff Layton }
930094f7b69SJeff Layton 
931094f7b69SJeff Layton static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
9320b4d3452SScott Mayhew 					struct super_block *newsb,
9330b4d3452SScott Mayhew 					unsigned long kern_flags,
9340b4d3452SScott Mayhew 					unsigned long *set_kern_flags)
935c9180a57SEric Paris {
9360b4d3452SScott Mayhew 	int rc = 0;
937c9180a57SEric Paris 	const struct superblock_security_struct *oldsbsec = oldsb->s_security;
938c9180a57SEric Paris 	struct superblock_security_struct *newsbsec = newsb->s_security;
939c9180a57SEric Paris 
940c9180a57SEric Paris 	int set_fscontext =	(oldsbsec->flags & FSCONTEXT_MNT);
941c9180a57SEric Paris 	int set_context =	(oldsbsec->flags & CONTEXT_MNT);
942c9180a57SEric Paris 	int set_rootcontext =	(oldsbsec->flags & ROOTCONTEXT_MNT);
943c9180a57SEric Paris 
9440f5e6420SEric Paris 	/*
9450f5e6420SEric Paris 	 * if the parent was able to be mounted it clearly had no special lsm
946e8c26255SAl Viro 	 * mount options.  thus we can safely deal with this superblock later
9470f5e6420SEric Paris 	 */
948aa8e712cSStephen Smalley 	if (!selinux_state.initialized)
949094f7b69SJeff Layton 		return 0;
950c9180a57SEric Paris 
9510b4d3452SScott Mayhew 	/*
9520b4d3452SScott Mayhew 	 * Specifying internal flags without providing a place to
9530b4d3452SScott Mayhew 	 * place the results is not allowed.
9540b4d3452SScott Mayhew 	 */
9550b4d3452SScott Mayhew 	if (kern_flags && !set_kern_flags)
9560b4d3452SScott Mayhew 		return -EINVAL;
9570b4d3452SScott Mayhew 
958c9180a57SEric Paris 	/* how can we clone if the old one wasn't set up?? */
9590d90a7ecSDavid P. Quigley 	BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
960c9180a57SEric Paris 
961094f7b69SJeff Layton 	/* if fs is reusing a sb, make sure that the contexts match */
9620d90a7ecSDavid P. Quigley 	if (newsbsec->flags & SE_SBINITIALIZED)
963094f7b69SJeff Layton 		return selinux_cmp_sb_context(oldsb, newsb);
9645a552617SEric Paris 
965c9180a57SEric Paris 	mutex_lock(&newsbsec->lock);
966c9180a57SEric Paris 
967c9180a57SEric Paris 	newsbsec->flags = oldsbsec->flags;
968c9180a57SEric Paris 
969c9180a57SEric Paris 	newsbsec->sid = oldsbsec->sid;
970c9180a57SEric Paris 	newsbsec->def_sid = oldsbsec->def_sid;
971c9180a57SEric Paris 	newsbsec->behavior = oldsbsec->behavior;
972c9180a57SEric Paris 
9730b4d3452SScott Mayhew 	if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
9740b4d3452SScott Mayhew 		!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
975aa8e712cSStephen Smalley 		rc = security_fs_use(&selinux_state, newsb);
9760b4d3452SScott Mayhew 		if (rc)
9770b4d3452SScott Mayhew 			goto out;
9780b4d3452SScott Mayhew 	}
9790b4d3452SScott Mayhew 
9800b4d3452SScott Mayhew 	if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !set_context) {
9810b4d3452SScott Mayhew 		newsbsec->behavior = SECURITY_FS_USE_NATIVE;
9820b4d3452SScott Mayhew 		*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
9830b4d3452SScott Mayhew 	}
9840b4d3452SScott Mayhew 
985c9180a57SEric Paris 	if (set_context) {
986c9180a57SEric Paris 		u32 sid = oldsbsec->mntpoint_sid;
987c9180a57SEric Paris 
988c9180a57SEric Paris 		if (!set_fscontext)
989c9180a57SEric Paris 			newsbsec->sid = sid;
990c9180a57SEric Paris 		if (!set_rootcontext) {
99183da53c5SAndreas Gruenbacher 			struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
992c9180a57SEric Paris 			newisec->sid = sid;
993c9180a57SEric Paris 		}
994c9180a57SEric Paris 		newsbsec->mntpoint_sid = sid;
995c9180a57SEric Paris 	}
996c9180a57SEric Paris 	if (set_rootcontext) {
99783da53c5SAndreas Gruenbacher 		const struct inode_security_struct *oldisec = backing_inode_security(oldsb->s_root);
99883da53c5SAndreas Gruenbacher 		struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
999c9180a57SEric Paris 
1000c9180a57SEric Paris 		newisec->sid = oldisec->sid;
1001c9180a57SEric Paris 	}
1002c9180a57SEric Paris 
1003c9180a57SEric Paris 	sb_finish_set_opts(newsb);
10040b4d3452SScott Mayhew out:
1005c9180a57SEric Paris 	mutex_unlock(&newsbsec->lock);
10060b4d3452SScott Mayhew 	return rc;
1007c9180a57SEric Paris }
1008c9180a57SEric Paris 
1009ba641862SAl Viro static int selinux_add_opt(int token, const char *s, void **mnt_opts)
1010ba641862SAl Viro {
1011ba641862SAl Viro 	struct selinux_mnt_opts *opts = *mnt_opts;
1012ba641862SAl Viro 
1013*da3d76abSAl Viro 	if (token == Opt_seclabel)	/* eaten and completely ignored */
1014169d68efSAl Viro 		return 0;
1015169d68efSAl Viro 
1016ba641862SAl Viro 	if (!opts) {
1017ba641862SAl Viro 		opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
1018ba641862SAl Viro 		if (!opts)
1019ba641862SAl Viro 			return -ENOMEM;
1020ba641862SAl Viro 		*mnt_opts = opts;
1021ba641862SAl Viro 	}
1022ba641862SAl Viro 	if (!s)
1023ba641862SAl Viro 		return -ENOMEM;
1024ba641862SAl Viro 	switch (token) {
1025ba641862SAl Viro 	case Opt_context:
1026ba641862SAl Viro 		if (opts->context || opts->defcontext)
1027ba641862SAl Viro 			goto Einval;
1028ba641862SAl Viro 		opts->context = s;
1029ba641862SAl Viro 		break;
1030ba641862SAl Viro 	case Opt_fscontext:
1031ba641862SAl Viro 		if (opts->fscontext)
1032ba641862SAl Viro 			goto Einval;
1033ba641862SAl Viro 		opts->fscontext = s;
1034ba641862SAl Viro 		break;
1035ba641862SAl Viro 	case Opt_rootcontext:
1036ba641862SAl Viro 		if (opts->rootcontext)
1037ba641862SAl Viro 			goto Einval;
1038ba641862SAl Viro 		opts->rootcontext = s;
1039ba641862SAl Viro 		break;
1040ba641862SAl Viro 	case Opt_defcontext:
1041ba641862SAl Viro 		if (opts->context || opts->defcontext)
1042ba641862SAl Viro 			goto Einval;
1043ba641862SAl Viro 		opts->defcontext = s;
1044ba641862SAl Viro 		break;
1045ba641862SAl Viro 	}
1046ba641862SAl Viro 	return 0;
1047ba641862SAl Viro Einval:
1048ba641862SAl Viro 	pr_warn(SEL_MOUNT_FAIL_MSG);
1049ba641862SAl Viro 	return -EINVAL;
1050ba641862SAl Viro }
1051ba641862SAl Viro 
10522e1479d9SAdrian Bunk static int selinux_parse_opts_str(char *options,
1053204cc0ccSAl Viro 				  void **mnt_opts)
1054c9180a57SEric Paris {
1055169d68efSAl Viro 	char *p = options, *next;
1056169d68efSAl Viro 	int rc;
1057c9180a57SEric Paris 
1058c9180a57SEric Paris 	/* Standard string-based options. */
1059169d68efSAl Viro 	for (p = options; *p; p = next) {
1060169d68efSAl Viro 		int token, len;
1061169d68efSAl Viro 		char *arg = NULL;
1062c9180a57SEric Paris 
1063169d68efSAl Viro 		next = strchr(p, '|');
1064169d68efSAl Viro 		if (next) {
1065169d68efSAl Viro 			len = next++ - p;
1066169d68efSAl Viro 		} else {
1067169d68efSAl Viro 			len = strlen(p);
1068169d68efSAl Viro 			next = p + len;
1069169d68efSAl Viro 		}
1070169d68efSAl Viro 
1071169d68efSAl Viro 		if (!len)
1072c9180a57SEric Paris 			continue;
1073c9180a57SEric Paris 
1074169d68efSAl Viro 		token = match_opt_prefix(p, len, &arg);
1075169d68efSAl Viro 		if (arg)
1076169d68efSAl Viro 			arg = kmemdup_nul(arg, p + len - arg, GFP_KERNEL);
1077ba641862SAl Viro 		rc = selinux_add_opt(token, arg, mnt_opts);
1078169d68efSAl Viro 		if (rc) {
1079ba641862SAl Viro 			kfree(arg);
1080ba641862SAl Viro 			selinux_free_mnt_opts(*mnt_opts);
1081ba641862SAl Viro 			*mnt_opts = NULL;
1082c9180a57SEric Paris 			return rc;
10831da177e4SLinus Torvalds 		}
1084ba641862SAl Viro 	}
1085ba641862SAl Viro 	return 0;
1086ba641862SAl Viro }
10871da177e4SLinus Torvalds 
1088e3489f89SAl Viro static int show_sid(struct seq_file *m, u32 sid)
10892069f457SEric Paris {
1090e3489f89SAl Viro 	char *context = NULL;
1091e3489f89SAl Viro 	u32 len;
1092e3489f89SAl Viro 	int rc;
10932069f457SEric Paris 
1094e3489f89SAl Viro 	rc = security_sid_to_context(&selinux_state, sid,
1095e3489f89SAl Viro 					     &context, &len);
1096e3489f89SAl Viro 	if (!rc) {
1097e3489f89SAl Viro 		bool has_comma = context && strchr(context, ',');
109811689d47SDavid P. Quigley 
10992069f457SEric Paris 		if (has_comma)
11002069f457SEric Paris 			seq_putc(m, '\"');
1101e3489f89SAl Viro 		seq_escape(m, context, "\"\n\\");
11022069f457SEric Paris 		if (has_comma)
11032069f457SEric Paris 			seq_putc(m, '\"');
11042069f457SEric Paris 	}
1105e3489f89SAl Viro 	kfree(context);
1106e3489f89SAl Viro 	return rc;
11072069f457SEric Paris }
11082069f457SEric Paris 
11092069f457SEric Paris static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
11102069f457SEric Paris {
1111e3489f89SAl Viro 	struct superblock_security_struct *sbsec = sb->s_security;
11122069f457SEric Paris 	int rc;
11132069f457SEric Paris 
1114e3489f89SAl Viro 	if (!(sbsec->flags & SE_SBINITIALIZED))
1115e3489f89SAl Viro 		return 0;
1116e3489f89SAl Viro 
1117e3489f89SAl Viro 	if (!selinux_state.initialized)
1118e3489f89SAl Viro 		return 0;
1119e3489f89SAl Viro 
1120e3489f89SAl Viro 	if (sbsec->flags & FSCONTEXT_MNT) {
1121e3489f89SAl Viro 		seq_putc(m, ',');
1122e3489f89SAl Viro 		seq_puts(m, FSCONTEXT_STR);
1123e3489f89SAl Viro 		rc = show_sid(m, sbsec->sid);
1124e3489f89SAl Viro 		if (rc)
11252069f457SEric Paris 			return rc;
1126383795c2SEric Paris 	}
1127e3489f89SAl Viro 	if (sbsec->flags & CONTEXT_MNT) {
1128e3489f89SAl Viro 		seq_putc(m, ',');
1129e3489f89SAl Viro 		seq_puts(m, CONTEXT_STR);
1130e3489f89SAl Viro 		rc = show_sid(m, sbsec->mntpoint_sid);
1131e3489f89SAl Viro 		if (rc)
11322069f457SEric Paris 			return rc;
11332069f457SEric Paris 	}
1134e3489f89SAl Viro 	if (sbsec->flags & DEFCONTEXT_MNT) {
1135e3489f89SAl Viro 		seq_putc(m, ',');
1136e3489f89SAl Viro 		seq_puts(m, DEFCONTEXT_STR);
1137e3489f89SAl Viro 		rc = show_sid(m, sbsec->def_sid);
1138e3489f89SAl Viro 		if (rc)
1139e3489f89SAl Viro 			return rc;
1140e3489f89SAl Viro 	}
1141e3489f89SAl Viro 	if (sbsec->flags & ROOTCONTEXT_MNT) {
1142e3489f89SAl Viro 		struct dentry *root = sbsec->sb->s_root;
1143e3489f89SAl Viro 		struct inode_security_struct *isec = backing_inode_security(root);
1144e3489f89SAl Viro 		seq_putc(m, ',');
1145e3489f89SAl Viro 		seq_puts(m, ROOTCONTEXT_STR);
1146e3489f89SAl Viro 		rc = show_sid(m, isec->sid);
1147e3489f89SAl Viro 		if (rc)
1148e3489f89SAl Viro 			return rc;
1149e3489f89SAl Viro 	}
1150e3489f89SAl Viro 	if (sbsec->flags & SBLABEL_MNT) {
1151e3489f89SAl Viro 		seq_putc(m, ',');
1152e3489f89SAl Viro 		seq_puts(m, LABELSUPP_STR);
1153e3489f89SAl Viro 	}
1154e3489f89SAl Viro 	return 0;
1155e3489f89SAl Viro }
11562069f457SEric Paris 
11571da177e4SLinus Torvalds static inline u16 inode_mode_to_security_class(umode_t mode)
11581da177e4SLinus Torvalds {
11591da177e4SLinus Torvalds 	switch (mode & S_IFMT) {
11601da177e4SLinus Torvalds 	case S_IFSOCK:
11611da177e4SLinus Torvalds 		return SECCLASS_SOCK_FILE;
11621da177e4SLinus Torvalds 	case S_IFLNK:
11631da177e4SLinus Torvalds 		return SECCLASS_LNK_FILE;
11641da177e4SLinus Torvalds 	case S_IFREG:
11651da177e4SLinus Torvalds 		return SECCLASS_FILE;
11661da177e4SLinus Torvalds 	case S_IFBLK:
11671da177e4SLinus Torvalds 		return SECCLASS_BLK_FILE;
11681da177e4SLinus Torvalds 	case S_IFDIR:
11691da177e4SLinus Torvalds 		return SECCLASS_DIR;
11701da177e4SLinus Torvalds 	case S_IFCHR:
11711da177e4SLinus Torvalds 		return SECCLASS_CHR_FILE;
11721da177e4SLinus Torvalds 	case S_IFIFO:
11731da177e4SLinus Torvalds 		return SECCLASS_FIFO_FILE;
11741da177e4SLinus Torvalds 
11751da177e4SLinus Torvalds 	}
11761da177e4SLinus Torvalds 
11771da177e4SLinus Torvalds 	return SECCLASS_FILE;
11781da177e4SLinus Torvalds }
11791da177e4SLinus Torvalds 
118013402580SJames Morris static inline int default_protocol_stream(int protocol)
118113402580SJames Morris {
118213402580SJames Morris 	return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
118313402580SJames Morris }
118413402580SJames Morris 
118513402580SJames Morris static inline int default_protocol_dgram(int protocol)
118613402580SJames Morris {
118713402580SJames Morris 	return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
118813402580SJames Morris }
118913402580SJames Morris 
11901da177e4SLinus Torvalds static inline u16 socket_type_to_security_class(int family, int type, int protocol)
11911da177e4SLinus Torvalds {
1192aa8e712cSStephen Smalley 	int extsockclass = selinux_policycap_extsockclass();
1193da69a530SStephen Smalley 
11941da177e4SLinus Torvalds 	switch (family) {
11951da177e4SLinus Torvalds 	case PF_UNIX:
11961da177e4SLinus Torvalds 		switch (type) {
11971da177e4SLinus Torvalds 		case SOCK_STREAM:
11981da177e4SLinus Torvalds 		case SOCK_SEQPACKET:
11991da177e4SLinus Torvalds 			return SECCLASS_UNIX_STREAM_SOCKET;
12001da177e4SLinus Torvalds 		case SOCK_DGRAM:
12012a764b52SLuis Ressel 		case SOCK_RAW:
12021da177e4SLinus Torvalds 			return SECCLASS_UNIX_DGRAM_SOCKET;
12031da177e4SLinus Torvalds 		}
12041da177e4SLinus Torvalds 		break;
12051da177e4SLinus Torvalds 	case PF_INET:
12061da177e4SLinus Torvalds 	case PF_INET6:
12071da177e4SLinus Torvalds 		switch (type) {
12081da177e4SLinus Torvalds 		case SOCK_STREAM:
1209da69a530SStephen Smalley 		case SOCK_SEQPACKET:
121013402580SJames Morris 			if (default_protocol_stream(protocol))
12111da177e4SLinus Torvalds 				return SECCLASS_TCP_SOCKET;
1212da69a530SStephen Smalley 			else if (extsockclass && protocol == IPPROTO_SCTP)
1213da69a530SStephen Smalley 				return SECCLASS_SCTP_SOCKET;
121413402580SJames Morris 			else
121513402580SJames Morris 				return SECCLASS_RAWIP_SOCKET;
12161da177e4SLinus Torvalds 		case SOCK_DGRAM:
121713402580SJames Morris 			if (default_protocol_dgram(protocol))
12181da177e4SLinus Torvalds 				return SECCLASS_UDP_SOCKET;
1219ef37979aSStephen Smalley 			else if (extsockclass && (protocol == IPPROTO_ICMP ||
1220ef37979aSStephen Smalley 						  protocol == IPPROTO_ICMPV6))
1221da69a530SStephen Smalley 				return SECCLASS_ICMP_SOCKET;
122213402580SJames Morris 			else
122313402580SJames Morris 				return SECCLASS_RAWIP_SOCKET;
12242ee92d46SJames Morris 		case SOCK_DCCP:
12252ee92d46SJames Morris 			return SECCLASS_DCCP_SOCKET;
122613402580SJames Morris 		default:
12271da177e4SLinus Torvalds 			return SECCLASS_RAWIP_SOCKET;
12281da177e4SLinus Torvalds 		}
12291da177e4SLinus Torvalds 		break;
12301da177e4SLinus Torvalds 	case PF_NETLINK:
12311da177e4SLinus Torvalds 		switch (protocol) {
12321da177e4SLinus Torvalds 		case NETLINK_ROUTE:
12331da177e4SLinus Torvalds 			return SECCLASS_NETLINK_ROUTE_SOCKET;
12347f1fb60cSPavel Emelyanov 		case NETLINK_SOCK_DIAG:
12351da177e4SLinus Torvalds 			return SECCLASS_NETLINK_TCPDIAG_SOCKET;
12361da177e4SLinus Torvalds 		case NETLINK_NFLOG:
12371da177e4SLinus Torvalds 			return SECCLASS_NETLINK_NFLOG_SOCKET;
12381da177e4SLinus Torvalds 		case NETLINK_XFRM:
12391da177e4SLinus Torvalds 			return SECCLASS_NETLINK_XFRM_SOCKET;
12401da177e4SLinus Torvalds 		case NETLINK_SELINUX:
12411da177e4SLinus Torvalds 			return SECCLASS_NETLINK_SELINUX_SOCKET;
12426c6d2e9bSStephen Smalley 		case NETLINK_ISCSI:
12436c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_ISCSI_SOCKET;
12441da177e4SLinus Torvalds 		case NETLINK_AUDIT:
12451da177e4SLinus Torvalds 			return SECCLASS_NETLINK_AUDIT_SOCKET;
12466c6d2e9bSStephen Smalley 		case NETLINK_FIB_LOOKUP:
12476c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_FIB_LOOKUP_SOCKET;
12486c6d2e9bSStephen Smalley 		case NETLINK_CONNECTOR:
12496c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_CONNECTOR_SOCKET;
12506c6d2e9bSStephen Smalley 		case NETLINK_NETFILTER:
12516c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_NETFILTER_SOCKET;
12521da177e4SLinus Torvalds 		case NETLINK_DNRTMSG:
12531da177e4SLinus Torvalds 			return SECCLASS_NETLINK_DNRT_SOCKET;
12540c9b7942SJames Morris 		case NETLINK_KOBJECT_UEVENT:
12550c9b7942SJames Morris 			return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
12566c6d2e9bSStephen Smalley 		case NETLINK_GENERIC:
12576c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_GENERIC_SOCKET;
12586c6d2e9bSStephen Smalley 		case NETLINK_SCSITRANSPORT:
12596c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_SCSITRANSPORT_SOCKET;
12606c6d2e9bSStephen Smalley 		case NETLINK_RDMA:
12616c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_RDMA_SOCKET;
12626c6d2e9bSStephen Smalley 		case NETLINK_CRYPTO:
12636c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_CRYPTO_SOCKET;
12641da177e4SLinus Torvalds 		default:
12651da177e4SLinus Torvalds 			return SECCLASS_NETLINK_SOCKET;
12661da177e4SLinus Torvalds 		}
12671da177e4SLinus Torvalds 	case PF_PACKET:
12681da177e4SLinus Torvalds 		return SECCLASS_PACKET_SOCKET;
12691da177e4SLinus Torvalds 	case PF_KEY:
12701da177e4SLinus Torvalds 		return SECCLASS_KEY_SOCKET;
12713e3ff15eSChristopher J. PeBenito 	case PF_APPLETALK:
12723e3ff15eSChristopher J. PeBenito 		return SECCLASS_APPLETALK_SOCKET;
12731da177e4SLinus Torvalds 	}
12741da177e4SLinus Torvalds 
1275da69a530SStephen Smalley 	if (extsockclass) {
1276da69a530SStephen Smalley 		switch (family) {
1277da69a530SStephen Smalley 		case PF_AX25:
1278da69a530SStephen Smalley 			return SECCLASS_AX25_SOCKET;
1279da69a530SStephen Smalley 		case PF_IPX:
1280da69a530SStephen Smalley 			return SECCLASS_IPX_SOCKET;
1281da69a530SStephen Smalley 		case PF_NETROM:
1282da69a530SStephen Smalley 			return SECCLASS_NETROM_SOCKET;
1283da69a530SStephen Smalley 		case PF_ATMPVC:
1284da69a530SStephen Smalley 			return SECCLASS_ATMPVC_SOCKET;
1285da69a530SStephen Smalley 		case PF_X25:
1286da69a530SStephen Smalley 			return SECCLASS_X25_SOCKET;
1287da69a530SStephen Smalley 		case PF_ROSE:
1288da69a530SStephen Smalley 			return SECCLASS_ROSE_SOCKET;
1289da69a530SStephen Smalley 		case PF_DECnet:
1290da69a530SStephen Smalley 			return SECCLASS_DECNET_SOCKET;
1291da69a530SStephen Smalley 		case PF_ATMSVC:
1292da69a530SStephen Smalley 			return SECCLASS_ATMSVC_SOCKET;
1293da69a530SStephen Smalley 		case PF_RDS:
1294da69a530SStephen Smalley 			return SECCLASS_RDS_SOCKET;
1295da69a530SStephen Smalley 		case PF_IRDA:
1296da69a530SStephen Smalley 			return SECCLASS_IRDA_SOCKET;
1297da69a530SStephen Smalley 		case PF_PPPOX:
1298da69a530SStephen Smalley 			return SECCLASS_PPPOX_SOCKET;
1299da69a530SStephen Smalley 		case PF_LLC:
1300da69a530SStephen Smalley 			return SECCLASS_LLC_SOCKET;
1301da69a530SStephen Smalley 		case PF_CAN:
1302da69a530SStephen Smalley 			return SECCLASS_CAN_SOCKET;
1303da69a530SStephen Smalley 		case PF_TIPC:
1304da69a530SStephen Smalley 			return SECCLASS_TIPC_SOCKET;
1305da69a530SStephen Smalley 		case PF_BLUETOOTH:
1306da69a530SStephen Smalley 			return SECCLASS_BLUETOOTH_SOCKET;
1307da69a530SStephen Smalley 		case PF_IUCV:
1308da69a530SStephen Smalley 			return SECCLASS_IUCV_SOCKET;
1309da69a530SStephen Smalley 		case PF_RXRPC:
1310da69a530SStephen Smalley 			return SECCLASS_RXRPC_SOCKET;
1311da69a530SStephen Smalley 		case PF_ISDN:
1312da69a530SStephen Smalley 			return SECCLASS_ISDN_SOCKET;
1313da69a530SStephen Smalley 		case PF_PHONET:
1314da69a530SStephen Smalley 			return SECCLASS_PHONET_SOCKET;
1315da69a530SStephen Smalley 		case PF_IEEE802154:
1316da69a530SStephen Smalley 			return SECCLASS_IEEE802154_SOCKET;
1317da69a530SStephen Smalley 		case PF_CAIF:
1318da69a530SStephen Smalley 			return SECCLASS_CAIF_SOCKET;
1319da69a530SStephen Smalley 		case PF_ALG:
1320da69a530SStephen Smalley 			return SECCLASS_ALG_SOCKET;
1321da69a530SStephen Smalley 		case PF_NFC:
1322da69a530SStephen Smalley 			return SECCLASS_NFC_SOCKET;
1323da69a530SStephen Smalley 		case PF_VSOCK:
1324da69a530SStephen Smalley 			return SECCLASS_VSOCK_SOCKET;
1325da69a530SStephen Smalley 		case PF_KCM:
1326da69a530SStephen Smalley 			return SECCLASS_KCM_SOCKET;
1327da69a530SStephen Smalley 		case PF_QIPCRTR:
1328da69a530SStephen Smalley 			return SECCLASS_QIPCRTR_SOCKET;
13293051bf36SLinus Torvalds 		case PF_SMC:
13303051bf36SLinus Torvalds 			return SECCLASS_SMC_SOCKET;
133168e8b849SBjörn Töpel 		case PF_XDP:
133268e8b849SBjörn Töpel 			return SECCLASS_XDP_SOCKET;
133368e8b849SBjörn Töpel #if PF_MAX > 45
1334da69a530SStephen Smalley #error New address family defined, please update this function.
1335da69a530SStephen Smalley #endif
1336da69a530SStephen Smalley 		}
1337da69a530SStephen Smalley 	}
1338da69a530SStephen Smalley 
13391da177e4SLinus Torvalds 	return SECCLASS_SOCKET;
13401da177e4SLinus Torvalds }
13411da177e4SLinus Torvalds 
1342134509d5SStephen Smalley static int selinux_genfs_get_sid(struct dentry *dentry,
13431da177e4SLinus Torvalds 				 u16 tclass,
1344134509d5SStephen Smalley 				 u16 flags,
13451da177e4SLinus Torvalds 				 u32 *sid)
13461da177e4SLinus Torvalds {
13478e6c9693SLucian Adrian Grijincu 	int rc;
1348fc64005cSAl Viro 	struct super_block *sb = dentry->d_sb;
13498e6c9693SLucian Adrian Grijincu 	char *buffer, *path;
13501da177e4SLinus Torvalds 
13511da177e4SLinus Torvalds 	buffer = (char *)__get_free_page(GFP_KERNEL);
13521da177e4SLinus Torvalds 	if (!buffer)
13531da177e4SLinus Torvalds 		return -ENOMEM;
13541da177e4SLinus Torvalds 
13558e6c9693SLucian Adrian Grijincu 	path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
13568e6c9693SLucian Adrian Grijincu 	if (IS_ERR(path))
13578e6c9693SLucian Adrian Grijincu 		rc = PTR_ERR(path);
13588e6c9693SLucian Adrian Grijincu 	else {
1359134509d5SStephen Smalley 		if (flags & SE_SBPROC) {
13608e6c9693SLucian Adrian Grijincu 			/* each process gets a /proc/PID/ entry. Strip off the
13618e6c9693SLucian Adrian Grijincu 			 * PID part to get a valid selinux labeling.
13628e6c9693SLucian Adrian Grijincu 			 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
13638e6c9693SLucian Adrian Grijincu 			while (path[1] >= '0' && path[1] <= '9') {
13648e6c9693SLucian Adrian Grijincu 				path[1] = '/';
13658e6c9693SLucian Adrian Grijincu 				path++;
13661da177e4SLinus Torvalds 			}
1367134509d5SStephen Smalley 		}
1368aa8e712cSStephen Smalley 		rc = security_genfs_sid(&selinux_state, sb->s_type->name,
1369aa8e712cSStephen Smalley 					path, tclass, sid);
13707bb185edSStephen Smalley 		if (rc == -ENOENT) {
13717bb185edSStephen Smalley 			/* No match in policy, mark as unlabeled. */
13727bb185edSStephen Smalley 			*sid = SECINITSID_UNLABELED;
13737bb185edSStephen Smalley 			rc = 0;
13747bb185edSStephen Smalley 		}
13758e6c9693SLucian Adrian Grijincu 	}
13761da177e4SLinus Torvalds 	free_page((unsigned long)buffer);
13771da177e4SLinus Torvalds 	return rc;
13781da177e4SLinus Torvalds }
13791da177e4SLinus Torvalds 
13801da177e4SLinus Torvalds /* The inode's security attributes must be initialized before first use. */
13811da177e4SLinus Torvalds static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
13821da177e4SLinus Torvalds {
13831da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec = NULL;
13841da177e4SLinus Torvalds 	struct inode_security_struct *isec = inode->i_security;
13859287aed2SAndreas Gruenbacher 	u32 task_sid, sid = 0;
13869287aed2SAndreas Gruenbacher 	u16 sclass;
13871da177e4SLinus Torvalds 	struct dentry *dentry;
13881da177e4SLinus Torvalds #define INITCONTEXTLEN 255
13891da177e4SLinus Torvalds 	char *context = NULL;
13901da177e4SLinus Torvalds 	unsigned len = 0;
13911da177e4SLinus Torvalds 	int rc = 0;
13921da177e4SLinus Torvalds 
13936f3be9f5SAndreas Gruenbacher 	if (isec->initialized == LABEL_INITIALIZED)
139413457d07SAndreas Gruenbacher 		return 0;
13951da177e4SLinus Torvalds 
13969287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
13976f3be9f5SAndreas Gruenbacher 	if (isec->initialized == LABEL_INITIALIZED)
139823970741SEric Paris 		goto out_unlock;
13991da177e4SLinus Torvalds 
140013457d07SAndreas Gruenbacher 	if (isec->sclass == SECCLASS_FILE)
140113457d07SAndreas Gruenbacher 		isec->sclass = inode_mode_to_security_class(inode->i_mode);
140213457d07SAndreas Gruenbacher 
14031da177e4SLinus Torvalds 	sbsec = inode->i_sb->s_security;
14040d90a7ecSDavid P. Quigley 	if (!(sbsec->flags & SE_SBINITIALIZED)) {
14051da177e4SLinus Torvalds 		/* Defer initialization until selinux_complete_init,
14061da177e4SLinus Torvalds 		   after the initial policy is loaded and the security
14071da177e4SLinus Torvalds 		   server is ready to handle calls. */
14081da177e4SLinus Torvalds 		spin_lock(&sbsec->isec_lock);
14091da177e4SLinus Torvalds 		if (list_empty(&isec->list))
14101da177e4SLinus Torvalds 			list_add(&isec->list, &sbsec->isec_head);
14111da177e4SLinus Torvalds 		spin_unlock(&sbsec->isec_lock);
141223970741SEric Paris 		goto out_unlock;
14131da177e4SLinus Torvalds 	}
14141da177e4SLinus Torvalds 
14159287aed2SAndreas Gruenbacher 	sclass = isec->sclass;
14169287aed2SAndreas Gruenbacher 	task_sid = isec->task_sid;
14179287aed2SAndreas Gruenbacher 	sid = isec->sid;
14189287aed2SAndreas Gruenbacher 	isec->initialized = LABEL_PENDING;
14199287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
14209287aed2SAndreas Gruenbacher 
14211da177e4SLinus Torvalds 	switch (sbsec->behavior) {
1422eb9ae686SDavid Quigley 	case SECURITY_FS_USE_NATIVE:
1423eb9ae686SDavid Quigley 		break;
14241da177e4SLinus Torvalds 	case SECURITY_FS_USE_XATTR:
14255d6c3191SAndreas Gruenbacher 		if (!(inode->i_opflags & IOP_XATTR)) {
14269287aed2SAndreas Gruenbacher 			sid = sbsec->def_sid;
14271da177e4SLinus Torvalds 			break;
14281da177e4SLinus Torvalds 		}
14291da177e4SLinus Torvalds 		/* Need a dentry, since the xattr API requires one.
14301da177e4SLinus Torvalds 		   Life would be simpler if we could just pass the inode. */
14311da177e4SLinus Torvalds 		if (opt_dentry) {
14321da177e4SLinus Torvalds 			/* Called from d_instantiate or d_splice_alias. */
14331da177e4SLinus Torvalds 			dentry = dget(opt_dentry);
14341da177e4SLinus Torvalds 		} else {
1435b127125dSAl Viro 			/*
1436b127125dSAl Viro 			 * Called from selinux_complete_init, try to find a dentry.
1437b127125dSAl Viro 			 * Some filesystems really want a connected one, so try
1438b127125dSAl Viro 			 * that first.  We could split SECURITY_FS_USE_XATTR in
1439b127125dSAl Viro 			 * two, depending upon that...
1440b127125dSAl Viro 			 */
14411da177e4SLinus Torvalds 			dentry = d_find_alias(inode);
1442b127125dSAl Viro 			if (!dentry)
1443b127125dSAl Viro 				dentry = d_find_any_alias(inode);
14441da177e4SLinus Torvalds 		}
14451da177e4SLinus Torvalds 		if (!dentry) {
1446df7f54c0SEric Paris 			/*
1447df7f54c0SEric Paris 			 * this is can be hit on boot when a file is accessed
1448df7f54c0SEric Paris 			 * before the policy is loaded.  When we load policy we
1449df7f54c0SEric Paris 			 * may find inodes that have no dentry on the
1450df7f54c0SEric Paris 			 * sbsec->isec_head list.  No reason to complain as these
1451df7f54c0SEric Paris 			 * will get fixed up the next time we go through
1452df7f54c0SEric Paris 			 * inode_doinit with a dentry, before these inodes could
1453df7f54c0SEric Paris 			 * be used again by userspace.
1454df7f54c0SEric Paris 			 */
14559287aed2SAndreas Gruenbacher 			goto out;
14561da177e4SLinus Torvalds 		}
14571da177e4SLinus Torvalds 
14581da177e4SLinus Torvalds 		len = INITCONTEXTLEN;
14594cb912f1SEric Paris 		context = kmalloc(len+1, GFP_NOFS);
14601da177e4SLinus Torvalds 		if (!context) {
14611da177e4SLinus Torvalds 			rc = -ENOMEM;
14621da177e4SLinus Torvalds 			dput(dentry);
14639287aed2SAndreas Gruenbacher 			goto out;
14641da177e4SLinus Torvalds 		}
14654cb912f1SEric Paris 		context[len] = '\0';
14665d6c3191SAndreas Gruenbacher 		rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
14671da177e4SLinus Torvalds 		if (rc == -ERANGE) {
1468314dabb8SJames Morris 			kfree(context);
1469314dabb8SJames Morris 
14701da177e4SLinus Torvalds 			/* Need a larger buffer.  Query for the right size. */
14715d6c3191SAndreas Gruenbacher 			rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0);
14721da177e4SLinus Torvalds 			if (rc < 0) {
14731da177e4SLinus Torvalds 				dput(dentry);
14749287aed2SAndreas Gruenbacher 				goto out;
14751da177e4SLinus Torvalds 			}
14761da177e4SLinus Torvalds 			len = rc;
14774cb912f1SEric Paris 			context = kmalloc(len+1, GFP_NOFS);
14781da177e4SLinus Torvalds 			if (!context) {
14791da177e4SLinus Torvalds 				rc = -ENOMEM;
14801da177e4SLinus Torvalds 				dput(dentry);
14819287aed2SAndreas Gruenbacher 				goto out;
14821da177e4SLinus Torvalds 			}
14834cb912f1SEric Paris 			context[len] = '\0';
14845d6c3191SAndreas Gruenbacher 			rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
14851da177e4SLinus Torvalds 		}
14861da177e4SLinus Torvalds 		dput(dentry);
14871da177e4SLinus Torvalds 		if (rc < 0) {
14881da177e4SLinus Torvalds 			if (rc != -ENODATA) {
1489c103a91eSpeter enderborg 				pr_warn("SELinux: %s:  getxattr returned "
1490dd6f953aSHarvey Harrison 				       "%d for dev=%s ino=%ld\n", __func__,
14911da177e4SLinus Torvalds 				       -rc, inode->i_sb->s_id, inode->i_ino);
14921da177e4SLinus Torvalds 				kfree(context);
14939287aed2SAndreas Gruenbacher 				goto out;
14941da177e4SLinus Torvalds 			}
14951da177e4SLinus Torvalds 			/* Map ENODATA to the default file SID */
14961da177e4SLinus Torvalds 			sid = sbsec->def_sid;
14971da177e4SLinus Torvalds 			rc = 0;
14981da177e4SLinus Torvalds 		} else {
1499aa8e712cSStephen Smalley 			rc = security_context_to_sid_default(&selinux_state,
1500aa8e712cSStephen Smalley 							     context, rc, &sid,
1501869ab514SStephen Smalley 							     sbsec->def_sid,
1502869ab514SStephen Smalley 							     GFP_NOFS);
15031da177e4SLinus Torvalds 			if (rc) {
15044ba0a8adSEric Paris 				char *dev = inode->i_sb->s_id;
15054ba0a8adSEric Paris 				unsigned long ino = inode->i_ino;
15064ba0a8adSEric Paris 
15074ba0a8adSEric Paris 				if (rc == -EINVAL) {
15084ba0a8adSEric Paris 					if (printk_ratelimit())
1509c103a91eSpeter enderborg 						pr_notice("SELinux: inode=%lu on dev=%s was found to have an invalid "
15104ba0a8adSEric Paris 							"context=%s.  This indicates you may need to relabel the inode or the "
15114ba0a8adSEric Paris 							"filesystem in question.\n", ino, dev, context);
15124ba0a8adSEric Paris 				} else {
1513c103a91eSpeter enderborg 					pr_warn("SELinux: %s:  context_to_sid(%s) "
15141da177e4SLinus Torvalds 					       "returned %d for dev=%s ino=%ld\n",
15154ba0a8adSEric Paris 					       __func__, context, -rc, dev, ino);
15164ba0a8adSEric Paris 				}
15171da177e4SLinus Torvalds 				kfree(context);
15181da177e4SLinus Torvalds 				/* Leave with the unlabeled SID */
15191da177e4SLinus Torvalds 				rc = 0;
15201da177e4SLinus Torvalds 				break;
15211da177e4SLinus Torvalds 			}
15221da177e4SLinus Torvalds 		}
15231da177e4SLinus Torvalds 		kfree(context);
15241da177e4SLinus Torvalds 		break;
15251da177e4SLinus Torvalds 	case SECURITY_FS_USE_TASK:
15269287aed2SAndreas Gruenbacher 		sid = task_sid;
15271da177e4SLinus Torvalds 		break;
15281da177e4SLinus Torvalds 	case SECURITY_FS_USE_TRANS:
15291da177e4SLinus Torvalds 		/* Default to the fs SID. */
15309287aed2SAndreas Gruenbacher 		sid = sbsec->sid;
15311da177e4SLinus Torvalds 
15321da177e4SLinus Torvalds 		/* Try to obtain a transition SID. */
1533aa8e712cSStephen Smalley 		rc = security_transition_sid(&selinux_state, task_sid, sid,
1534aa8e712cSStephen Smalley 					     sclass, NULL, &sid);
15351da177e4SLinus Torvalds 		if (rc)
15369287aed2SAndreas Gruenbacher 			goto out;
15371da177e4SLinus Torvalds 		break;
1538c312feb2SEric Paris 	case SECURITY_FS_USE_MNTPOINT:
15399287aed2SAndreas Gruenbacher 		sid = sbsec->mntpoint_sid;
1540c312feb2SEric Paris 		break;
15411da177e4SLinus Torvalds 	default:
1542c312feb2SEric Paris 		/* Default to the fs superblock SID. */
15439287aed2SAndreas Gruenbacher 		sid = sbsec->sid;
15441da177e4SLinus Torvalds 
1545134509d5SStephen Smalley 		if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
1546f64410ecSPaul Moore 			/* We must have a dentry to determine the label on
1547f64410ecSPaul Moore 			 * procfs inodes */
1548b127125dSAl Viro 			if (opt_dentry) {
1549f64410ecSPaul Moore 				/* Called from d_instantiate or
1550f64410ecSPaul Moore 				 * d_splice_alias. */
1551f64410ecSPaul Moore 				dentry = dget(opt_dentry);
1552b127125dSAl Viro 			} else {
1553f64410ecSPaul Moore 				/* Called from selinux_complete_init, try to
1554b127125dSAl Viro 				 * find a dentry.  Some filesystems really want
1555b127125dSAl Viro 				 * a connected one, so try that first.
1556b127125dSAl Viro 				 */
1557f64410ecSPaul Moore 				dentry = d_find_alias(inode);
1558b127125dSAl Viro 				if (!dentry)
1559b127125dSAl Viro 					dentry = d_find_any_alias(inode);
1560b127125dSAl Viro 			}
1561f64410ecSPaul Moore 			/*
1562f64410ecSPaul Moore 			 * This can be hit on boot when a file is accessed
1563f64410ecSPaul Moore 			 * before the policy is loaded.  When we load policy we
1564f64410ecSPaul Moore 			 * may find inodes that have no dentry on the
1565f64410ecSPaul Moore 			 * sbsec->isec_head list.  No reason to complain as
1566f64410ecSPaul Moore 			 * these will get fixed up the next time we go through
1567f64410ecSPaul Moore 			 * inode_doinit() with a dentry, before these inodes
1568f64410ecSPaul Moore 			 * could be used again by userspace.
1569f64410ecSPaul Moore 			 */
1570f64410ecSPaul Moore 			if (!dentry)
15719287aed2SAndreas Gruenbacher 				goto out;
15729287aed2SAndreas Gruenbacher 			rc = selinux_genfs_get_sid(dentry, sclass,
1573134509d5SStephen Smalley 						   sbsec->flags, &sid);
1574f64410ecSPaul Moore 			dput(dentry);
15751da177e4SLinus Torvalds 			if (rc)
15769287aed2SAndreas Gruenbacher 				goto out;
15771da177e4SLinus Torvalds 		}
15781da177e4SLinus Torvalds 		break;
15791da177e4SLinus Torvalds 	}
15801da177e4SLinus Torvalds 
15819287aed2SAndreas Gruenbacher out:
15829287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
15839287aed2SAndreas Gruenbacher 	if (isec->initialized == LABEL_PENDING) {
15849287aed2SAndreas Gruenbacher 		if (!sid || rc) {
15859287aed2SAndreas Gruenbacher 			isec->initialized = LABEL_INVALID;
15869287aed2SAndreas Gruenbacher 			goto out_unlock;
15879287aed2SAndreas Gruenbacher 		}
15889287aed2SAndreas Gruenbacher 
15896f3be9f5SAndreas Gruenbacher 		isec->initialized = LABEL_INITIALIZED;
15909287aed2SAndreas Gruenbacher 		isec->sid = sid;
15919287aed2SAndreas Gruenbacher 	}
15921da177e4SLinus Torvalds 
159323970741SEric Paris out_unlock:
15949287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
15951da177e4SLinus Torvalds 	return rc;
15961da177e4SLinus Torvalds }
15971da177e4SLinus Torvalds 
15981da177e4SLinus Torvalds /* Convert a Linux signal to an access vector. */
15991da177e4SLinus Torvalds static inline u32 signal_to_av(int sig)
16001da177e4SLinus Torvalds {
16011da177e4SLinus Torvalds 	u32 perm = 0;
16021da177e4SLinus Torvalds 
16031da177e4SLinus Torvalds 	switch (sig) {
16041da177e4SLinus Torvalds 	case SIGCHLD:
16051da177e4SLinus Torvalds 		/* Commonly granted from child to parent. */
16061da177e4SLinus Torvalds 		perm = PROCESS__SIGCHLD;
16071da177e4SLinus Torvalds 		break;
16081da177e4SLinus Torvalds 	case SIGKILL:
16091da177e4SLinus Torvalds 		/* Cannot be caught or ignored */
16101da177e4SLinus Torvalds 		perm = PROCESS__SIGKILL;
16111da177e4SLinus Torvalds 		break;
16121da177e4SLinus Torvalds 	case SIGSTOP:
16131da177e4SLinus Torvalds 		/* Cannot be caught or ignored */
16141da177e4SLinus Torvalds 		perm = PROCESS__SIGSTOP;
16151da177e4SLinus Torvalds 		break;
16161da177e4SLinus Torvalds 	default:
16171da177e4SLinus Torvalds 		/* All other signals. */
16181da177e4SLinus Torvalds 		perm = PROCESS__SIGNAL;
16191da177e4SLinus Torvalds 		break;
16201da177e4SLinus Torvalds 	}
16211da177e4SLinus Torvalds 
16221da177e4SLinus Torvalds 	return perm;
16231da177e4SLinus Torvalds }
16241da177e4SLinus Torvalds 
1625b68e418cSStephen Smalley #if CAP_LAST_CAP > 63
1626b68e418cSStephen Smalley #error Fix SELinux to handle capabilities > 63.
1627b68e418cSStephen Smalley #endif
1628b68e418cSStephen Smalley 
16291da177e4SLinus Torvalds /* Check whether a task is allowed to use a capability. */
16306a9de491SEric Paris static int cred_has_capability(const struct cred *cred,
16318e4ff6f2SStephen Smalley 			       int cap, int audit, bool initns)
16321da177e4SLinus Torvalds {
16332bf49690SThomas Liu 	struct common_audit_data ad;
163406112163SEric Paris 	struct av_decision avd;
1635b68e418cSStephen Smalley 	u16 sclass;
16363699c53cSDavid Howells 	u32 sid = cred_sid(cred);
1637b68e418cSStephen Smalley 	u32 av = CAP_TO_MASK(cap);
163806112163SEric Paris 	int rc;
16391da177e4SLinus Torvalds 
164050c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_CAP;
16411da177e4SLinus Torvalds 	ad.u.cap = cap;
16421da177e4SLinus Torvalds 
1643b68e418cSStephen Smalley 	switch (CAP_TO_INDEX(cap)) {
1644b68e418cSStephen Smalley 	case 0:
16458e4ff6f2SStephen Smalley 		sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS;
1646b68e418cSStephen Smalley 		break;
1647b68e418cSStephen Smalley 	case 1:
16488e4ff6f2SStephen Smalley 		sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS;
1649b68e418cSStephen Smalley 		break;
1650b68e418cSStephen Smalley 	default:
1651c103a91eSpeter enderborg 		pr_err("SELinux:  out of range capability %d\n", cap);
1652b68e418cSStephen Smalley 		BUG();
1653a35c6c83SEric Paris 		return -EINVAL;
1654b68e418cSStephen Smalley 	}
165506112163SEric Paris 
16566b6bc620SStephen Smalley 	rc = avc_has_perm_noaudit(&selinux_state,
16576b6bc620SStephen Smalley 				  sid, sid, sclass, av, 0, &avd);
16589ade0cf4SEric Paris 	if (audit == SECURITY_CAP_AUDIT) {
16596b6bc620SStephen Smalley 		int rc2 = avc_audit(&selinux_state,
16606b6bc620SStephen Smalley 				    sid, sid, sclass, av, &avd, rc, &ad, 0);
16619ade0cf4SEric Paris 		if (rc2)
16629ade0cf4SEric Paris 			return rc2;
16639ade0cf4SEric Paris 	}
166406112163SEric Paris 	return rc;
16651da177e4SLinus Torvalds }
16661da177e4SLinus Torvalds 
16671da177e4SLinus Torvalds /* Check whether a task has a particular permission to an inode.
16681da177e4SLinus Torvalds    The 'adp' parameter is optional and allows other audit
16691da177e4SLinus Torvalds    data to be passed (e.g. the dentry). */
167088e67f3bSDavid Howells static int inode_has_perm(const struct cred *cred,
16711da177e4SLinus Torvalds 			  struct inode *inode,
16721da177e4SLinus Torvalds 			  u32 perms,
167319e49834SLinus Torvalds 			  struct common_audit_data *adp)
16741da177e4SLinus Torvalds {
16751da177e4SLinus Torvalds 	struct inode_security_struct *isec;
1676275bb41eSDavid Howells 	u32 sid;
16771da177e4SLinus Torvalds 
1678e0e81739SDavid Howells 	validate_creds(cred);
1679e0e81739SDavid Howells 
1680bbaca6c2SStephen Smalley 	if (unlikely(IS_PRIVATE(inode)))
1681bbaca6c2SStephen Smalley 		return 0;
1682bbaca6c2SStephen Smalley 
168388e67f3bSDavid Howells 	sid = cred_sid(cred);
16841da177e4SLinus Torvalds 	isec = inode->i_security;
16851da177e4SLinus Torvalds 
16866b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
16876b6bc620SStephen Smalley 			    sid, isec->sid, isec->sclass, perms, adp);
16881da177e4SLinus Torvalds }
16891da177e4SLinus Torvalds 
16901da177e4SLinus Torvalds /* Same as inode_has_perm, but pass explicit audit data containing
16911da177e4SLinus Torvalds    the dentry to help the auditing code to more easily generate the
16921da177e4SLinus Torvalds    pathname if needed. */
169388e67f3bSDavid Howells static inline int dentry_has_perm(const struct cred *cred,
16941da177e4SLinus Torvalds 				  struct dentry *dentry,
16951da177e4SLinus Torvalds 				  u32 av)
16961da177e4SLinus Torvalds {
1697c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(dentry);
16982bf49690SThomas Liu 	struct common_audit_data ad;
169988e67f3bSDavid Howells 
170050c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
17012875fa00SEric Paris 	ad.u.dentry = dentry;
17025d226df4SAndreas Gruenbacher 	__inode_security_revalidate(inode, dentry, true);
170319e49834SLinus Torvalds 	return inode_has_perm(cred, inode, av, &ad);
17042875fa00SEric Paris }
17052875fa00SEric Paris 
17062875fa00SEric Paris /* Same as inode_has_perm, but pass explicit audit data containing
17072875fa00SEric Paris    the path to help the auditing code to more easily generate the
17082875fa00SEric Paris    pathname if needed. */
17092875fa00SEric Paris static inline int path_has_perm(const struct cred *cred,
17103f7036a0SAl Viro 				const struct path *path,
17112875fa00SEric Paris 				u32 av)
17122875fa00SEric Paris {
1713c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(path->dentry);
17142875fa00SEric Paris 	struct common_audit_data ad;
17152875fa00SEric Paris 
171650c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_PATH;
17172875fa00SEric Paris 	ad.u.path = *path;
17185d226df4SAndreas Gruenbacher 	__inode_security_revalidate(inode, path->dentry, true);
171919e49834SLinus Torvalds 	return inode_has_perm(cred, inode, av, &ad);
17201da177e4SLinus Torvalds }
17211da177e4SLinus Torvalds 
172213f8e981SDavid Howells /* Same as path_has_perm, but uses the inode from the file struct. */
172313f8e981SDavid Howells static inline int file_path_has_perm(const struct cred *cred,
172413f8e981SDavid Howells 				     struct file *file,
172513f8e981SDavid Howells 				     u32 av)
172613f8e981SDavid Howells {
172713f8e981SDavid Howells 	struct common_audit_data ad;
172813f8e981SDavid Howells 
172943af5de7SVivek Goyal 	ad.type = LSM_AUDIT_DATA_FILE;
173043af5de7SVivek Goyal 	ad.u.file = file;
173119e49834SLinus Torvalds 	return inode_has_perm(cred, file_inode(file), av, &ad);
173213f8e981SDavid Howells }
173313f8e981SDavid Howells 
1734f66e448cSChenbo Feng #ifdef CONFIG_BPF_SYSCALL
1735f66e448cSChenbo Feng static int bpf_fd_pass(struct file *file, u32 sid);
1736f66e448cSChenbo Feng #endif
1737f66e448cSChenbo Feng 
17381da177e4SLinus Torvalds /* Check whether a task can use an open file descriptor to
17391da177e4SLinus Torvalds    access an inode in a given way.  Check access to the
17401da177e4SLinus Torvalds    descriptor itself, and then use dentry_has_perm to
17411da177e4SLinus Torvalds    check a particular permission to the file.
17421da177e4SLinus Torvalds    Access to the descriptor is implicitly granted if it
17431da177e4SLinus Torvalds    has the same SID as the process.  If av is zero, then
17441da177e4SLinus Torvalds    access to the file is not checked, e.g. for cases
17451da177e4SLinus Torvalds    where only the descriptor is affected like seek. */
174688e67f3bSDavid Howells static int file_has_perm(const struct cred *cred,
17471da177e4SLinus Torvalds 			 struct file *file,
17481da177e4SLinus Torvalds 			 u32 av)
17491da177e4SLinus Torvalds {
17501da177e4SLinus Torvalds 	struct file_security_struct *fsec = file->f_security;
1751496ad9aaSAl Viro 	struct inode *inode = file_inode(file);
17522bf49690SThomas Liu 	struct common_audit_data ad;
175388e67f3bSDavid Howells 	u32 sid = cred_sid(cred);
17541da177e4SLinus Torvalds 	int rc;
17551da177e4SLinus Torvalds 
175643af5de7SVivek Goyal 	ad.type = LSM_AUDIT_DATA_FILE;
175743af5de7SVivek Goyal 	ad.u.file = file;
17581da177e4SLinus Torvalds 
1759275bb41eSDavid Howells 	if (sid != fsec->sid) {
17606b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
17616b6bc620SStephen Smalley 				  sid, fsec->sid,
17621da177e4SLinus Torvalds 				  SECCLASS_FD,
17631da177e4SLinus Torvalds 				  FD__USE,
17641da177e4SLinus Torvalds 				  &ad);
17651da177e4SLinus Torvalds 		if (rc)
176688e67f3bSDavid Howells 			goto out;
17671da177e4SLinus Torvalds 	}
17681da177e4SLinus Torvalds 
1769f66e448cSChenbo Feng #ifdef CONFIG_BPF_SYSCALL
1770f66e448cSChenbo Feng 	rc = bpf_fd_pass(file, cred_sid(cred));
1771f66e448cSChenbo Feng 	if (rc)
1772f66e448cSChenbo Feng 		return rc;
1773f66e448cSChenbo Feng #endif
1774f66e448cSChenbo Feng 
17751da177e4SLinus Torvalds 	/* av is zero if only checking access to the descriptor. */
177688e67f3bSDavid Howells 	rc = 0;
17771da177e4SLinus Torvalds 	if (av)
177819e49834SLinus Torvalds 		rc = inode_has_perm(cred, inode, av, &ad);
17791da177e4SLinus Torvalds 
178088e67f3bSDavid Howells out:
178188e67f3bSDavid Howells 	return rc;
17821da177e4SLinus Torvalds }
17831da177e4SLinus Torvalds 
1784c3c188b2SDavid Howells /*
1785c3c188b2SDavid Howells  * Determine the label for an inode that might be unioned.
1786c3c188b2SDavid Howells  */
1787c957f6dfSVivek Goyal static int
1788c957f6dfSVivek Goyal selinux_determine_inode_label(const struct task_security_struct *tsec,
1789c957f6dfSVivek Goyal 				 struct inode *dir,
1790c957f6dfSVivek Goyal 				 const struct qstr *name, u16 tclass,
1791c3c188b2SDavid Howells 				 u32 *_new_isid)
1792c3c188b2SDavid Howells {
1793c3c188b2SDavid Howells 	const struct superblock_security_struct *sbsec = dir->i_sb->s_security;
1794c3c188b2SDavid Howells 
1795c3c188b2SDavid Howells 	if ((sbsec->flags & SE_SBINITIALIZED) &&
1796c3c188b2SDavid Howells 	    (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) {
1797c3c188b2SDavid Howells 		*_new_isid = sbsec->mntpoint_sid;
1798c3c188b2SDavid Howells 	} else if ((sbsec->flags & SBLABEL_MNT) &&
1799c3c188b2SDavid Howells 		   tsec->create_sid) {
1800c3c188b2SDavid Howells 		*_new_isid = tsec->create_sid;
1801c3c188b2SDavid Howells 	} else {
180220cdef8dSPaul Moore 		const struct inode_security_struct *dsec = inode_security(dir);
1803aa8e712cSStephen Smalley 		return security_transition_sid(&selinux_state, tsec->sid,
1804aa8e712cSStephen Smalley 					       dsec->sid, tclass,
1805c3c188b2SDavid Howells 					       name, _new_isid);
1806c3c188b2SDavid Howells 	}
1807c3c188b2SDavid Howells 
1808c3c188b2SDavid Howells 	return 0;
1809c3c188b2SDavid Howells }
1810c3c188b2SDavid Howells 
18111da177e4SLinus Torvalds /* Check whether a task can create a file. */
18121da177e4SLinus Torvalds static int may_create(struct inode *dir,
18131da177e4SLinus Torvalds 		      struct dentry *dentry,
18141da177e4SLinus Torvalds 		      u16 tclass)
18151da177e4SLinus Torvalds {
18165fb49870SPaul Moore 	const struct task_security_struct *tsec = current_security();
18171da177e4SLinus Torvalds 	struct inode_security_struct *dsec;
18181da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec;
1819275bb41eSDavid Howells 	u32 sid, newsid;
18202bf49690SThomas Liu 	struct common_audit_data ad;
18211da177e4SLinus Torvalds 	int rc;
18221da177e4SLinus Torvalds 
182383da53c5SAndreas Gruenbacher 	dsec = inode_security(dir);
18241da177e4SLinus Torvalds 	sbsec = dir->i_sb->s_security;
18251da177e4SLinus Torvalds 
1826275bb41eSDavid Howells 	sid = tsec->sid;
1827275bb41eSDavid Howells 
182850c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
1829a269434dSEric Paris 	ad.u.dentry = dentry;
18301da177e4SLinus Torvalds 
18316b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
18326b6bc620SStephen Smalley 			  sid, dsec->sid, SECCLASS_DIR,
18331da177e4SLinus Torvalds 			  DIR__ADD_NAME | DIR__SEARCH,
18341da177e4SLinus Torvalds 			  &ad);
18351da177e4SLinus Torvalds 	if (rc)
18361da177e4SLinus Torvalds 		return rc;
18371da177e4SLinus Torvalds 
1838c957f6dfSVivek Goyal 	rc = selinux_determine_inode_label(current_security(), dir,
1839c957f6dfSVivek Goyal 					   &dentry->d_name, tclass, &newsid);
18401da177e4SLinus Torvalds 	if (rc)
18411da177e4SLinus Torvalds 		return rc;
18421da177e4SLinus Torvalds 
18436b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
18446b6bc620SStephen Smalley 			  sid, newsid, tclass, FILE__CREATE, &ad);
18451da177e4SLinus Torvalds 	if (rc)
18461da177e4SLinus Torvalds 		return rc;
18471da177e4SLinus Torvalds 
18486b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
18496b6bc620SStephen Smalley 			    newsid, sbsec->sid,
18501da177e4SLinus Torvalds 			    SECCLASS_FILESYSTEM,
18511da177e4SLinus Torvalds 			    FILESYSTEM__ASSOCIATE, &ad);
18521da177e4SLinus Torvalds }
18531da177e4SLinus Torvalds 
18541da177e4SLinus Torvalds #define MAY_LINK	0
18551da177e4SLinus Torvalds #define MAY_UNLINK	1
18561da177e4SLinus Torvalds #define MAY_RMDIR	2
18571da177e4SLinus Torvalds 
18581da177e4SLinus Torvalds /* Check whether a task can link, unlink, or rmdir a file/directory. */
18591da177e4SLinus Torvalds static int may_link(struct inode *dir,
18601da177e4SLinus Torvalds 		    struct dentry *dentry,
18611da177e4SLinus Torvalds 		    int kind)
18621da177e4SLinus Torvalds 
18631da177e4SLinus Torvalds {
18641da177e4SLinus Torvalds 	struct inode_security_struct *dsec, *isec;
18652bf49690SThomas Liu 	struct common_audit_data ad;
1866275bb41eSDavid Howells 	u32 sid = current_sid();
18671da177e4SLinus Torvalds 	u32 av;
18681da177e4SLinus Torvalds 	int rc;
18691da177e4SLinus Torvalds 
187083da53c5SAndreas Gruenbacher 	dsec = inode_security(dir);
187183da53c5SAndreas Gruenbacher 	isec = backing_inode_security(dentry);
18721da177e4SLinus Torvalds 
187350c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
1874a269434dSEric Paris 	ad.u.dentry = dentry;
18751da177e4SLinus Torvalds 
18761da177e4SLinus Torvalds 	av = DIR__SEARCH;
18771da177e4SLinus Torvalds 	av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
18786b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
18796b6bc620SStephen Smalley 			  sid, dsec->sid, SECCLASS_DIR, av, &ad);
18801da177e4SLinus Torvalds 	if (rc)
18811da177e4SLinus Torvalds 		return rc;
18821da177e4SLinus Torvalds 
18831da177e4SLinus Torvalds 	switch (kind) {
18841da177e4SLinus Torvalds 	case MAY_LINK:
18851da177e4SLinus Torvalds 		av = FILE__LINK;
18861da177e4SLinus Torvalds 		break;
18871da177e4SLinus Torvalds 	case MAY_UNLINK:
18881da177e4SLinus Torvalds 		av = FILE__UNLINK;
18891da177e4SLinus Torvalds 		break;
18901da177e4SLinus Torvalds 	case MAY_RMDIR:
18911da177e4SLinus Torvalds 		av = DIR__RMDIR;
18921da177e4SLinus Torvalds 		break;
18931da177e4SLinus Torvalds 	default:
1894c103a91eSpeter enderborg 		pr_warn("SELinux: %s:  unrecognized kind %d\n",
1895744ba35eSEric Paris 			__func__, kind);
18961da177e4SLinus Torvalds 		return 0;
18971da177e4SLinus Torvalds 	}
18981da177e4SLinus Torvalds 
18996b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
19006b6bc620SStephen Smalley 			  sid, isec->sid, isec->sclass, av, &ad);
19011da177e4SLinus Torvalds 	return rc;
19021da177e4SLinus Torvalds }
19031da177e4SLinus Torvalds 
19041da177e4SLinus Torvalds static inline int may_rename(struct inode *old_dir,
19051da177e4SLinus Torvalds 			     struct dentry *old_dentry,
19061da177e4SLinus Torvalds 			     struct inode *new_dir,
19071da177e4SLinus Torvalds 			     struct dentry *new_dentry)
19081da177e4SLinus Torvalds {
19091da177e4SLinus Torvalds 	struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
19102bf49690SThomas Liu 	struct common_audit_data ad;
1911275bb41eSDavid Howells 	u32 sid = current_sid();
19121da177e4SLinus Torvalds 	u32 av;
19131da177e4SLinus Torvalds 	int old_is_dir, new_is_dir;
19141da177e4SLinus Torvalds 	int rc;
19151da177e4SLinus Torvalds 
191683da53c5SAndreas Gruenbacher 	old_dsec = inode_security(old_dir);
191783da53c5SAndreas Gruenbacher 	old_isec = backing_inode_security(old_dentry);
1918e36cb0b8SDavid Howells 	old_is_dir = d_is_dir(old_dentry);
191983da53c5SAndreas Gruenbacher 	new_dsec = inode_security(new_dir);
19201da177e4SLinus Torvalds 
192150c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
19221da177e4SLinus Torvalds 
1923a269434dSEric Paris 	ad.u.dentry = old_dentry;
19246b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
19256b6bc620SStephen Smalley 			  sid, old_dsec->sid, SECCLASS_DIR,
19261da177e4SLinus Torvalds 			  DIR__REMOVE_NAME | DIR__SEARCH, &ad);
19271da177e4SLinus Torvalds 	if (rc)
19281da177e4SLinus Torvalds 		return rc;
19296b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
19306b6bc620SStephen Smalley 			  sid, old_isec->sid,
19311da177e4SLinus Torvalds 			  old_isec->sclass, FILE__RENAME, &ad);
19321da177e4SLinus Torvalds 	if (rc)
19331da177e4SLinus Torvalds 		return rc;
19341da177e4SLinus Torvalds 	if (old_is_dir && new_dir != old_dir) {
19356b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
19366b6bc620SStephen Smalley 				  sid, old_isec->sid,
19371da177e4SLinus Torvalds 				  old_isec->sclass, DIR__REPARENT, &ad);
19381da177e4SLinus Torvalds 		if (rc)
19391da177e4SLinus Torvalds 			return rc;
19401da177e4SLinus Torvalds 	}
19411da177e4SLinus Torvalds 
1942a269434dSEric Paris 	ad.u.dentry = new_dentry;
19431da177e4SLinus Torvalds 	av = DIR__ADD_NAME | DIR__SEARCH;
19442c616d4dSDavid Howells 	if (d_is_positive(new_dentry))
19451da177e4SLinus Torvalds 		av |= DIR__REMOVE_NAME;
19466b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
19476b6bc620SStephen Smalley 			  sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
19481da177e4SLinus Torvalds 	if (rc)
19491da177e4SLinus Torvalds 		return rc;
19502c616d4dSDavid Howells 	if (d_is_positive(new_dentry)) {
195183da53c5SAndreas Gruenbacher 		new_isec = backing_inode_security(new_dentry);
1952e36cb0b8SDavid Howells 		new_is_dir = d_is_dir(new_dentry);
19536b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
19546b6bc620SStephen Smalley 				  sid, new_isec->sid,
19551da177e4SLinus Torvalds 				  new_isec->sclass,
19561da177e4SLinus Torvalds 				  (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
19571da177e4SLinus Torvalds 		if (rc)
19581da177e4SLinus Torvalds 			return rc;
19591da177e4SLinus Torvalds 	}
19601da177e4SLinus Torvalds 
19611da177e4SLinus Torvalds 	return 0;
19621da177e4SLinus Torvalds }
19631da177e4SLinus Torvalds 
19641da177e4SLinus Torvalds /* Check whether a task can perform a filesystem operation. */
196588e67f3bSDavid Howells static int superblock_has_perm(const struct cred *cred,
19661da177e4SLinus Torvalds 			       struct super_block *sb,
19671da177e4SLinus Torvalds 			       u32 perms,
19682bf49690SThomas Liu 			       struct common_audit_data *ad)
19691da177e4SLinus Torvalds {
19701da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec;
197188e67f3bSDavid Howells 	u32 sid = cred_sid(cred);
19721da177e4SLinus Torvalds 
19731da177e4SLinus Torvalds 	sbsec = sb->s_security;
19746b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
19756b6bc620SStephen Smalley 			    sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
19761da177e4SLinus Torvalds }
19771da177e4SLinus Torvalds 
19781da177e4SLinus Torvalds /* Convert a Linux mode and permission mask to an access vector. */
19791da177e4SLinus Torvalds static inline u32 file_mask_to_av(int mode, int mask)
19801da177e4SLinus Torvalds {
19811da177e4SLinus Torvalds 	u32 av = 0;
19821da177e4SLinus Torvalds 
1983dba19c60SAl Viro 	if (!S_ISDIR(mode)) {
19841da177e4SLinus Torvalds 		if (mask & MAY_EXEC)
19851da177e4SLinus Torvalds 			av |= FILE__EXECUTE;
19861da177e4SLinus Torvalds 		if (mask & MAY_READ)
19871da177e4SLinus Torvalds 			av |= FILE__READ;
19881da177e4SLinus Torvalds 
19891da177e4SLinus Torvalds 		if (mask & MAY_APPEND)
19901da177e4SLinus Torvalds 			av |= FILE__APPEND;
19911da177e4SLinus Torvalds 		else if (mask & MAY_WRITE)
19921da177e4SLinus Torvalds 			av |= FILE__WRITE;
19931da177e4SLinus Torvalds 
19941da177e4SLinus Torvalds 	} else {
19951da177e4SLinus Torvalds 		if (mask & MAY_EXEC)
19961da177e4SLinus Torvalds 			av |= DIR__SEARCH;
19971da177e4SLinus Torvalds 		if (mask & MAY_WRITE)
19981da177e4SLinus Torvalds 			av |= DIR__WRITE;
19991da177e4SLinus Torvalds 		if (mask & MAY_READ)
20001da177e4SLinus Torvalds 			av |= DIR__READ;
20011da177e4SLinus Torvalds 	}
20021da177e4SLinus Torvalds 
20031da177e4SLinus Torvalds 	return av;
20041da177e4SLinus Torvalds }
20051da177e4SLinus Torvalds 
20061da177e4SLinus Torvalds /* Convert a Linux file to an access vector. */
20071da177e4SLinus Torvalds static inline u32 file_to_av(struct file *file)
20081da177e4SLinus Torvalds {
20091da177e4SLinus Torvalds 	u32 av = 0;
20101da177e4SLinus Torvalds 
20111da177e4SLinus Torvalds 	if (file->f_mode & FMODE_READ)
20121da177e4SLinus Torvalds 		av |= FILE__READ;
20131da177e4SLinus Torvalds 	if (file->f_mode & FMODE_WRITE) {
20141da177e4SLinus Torvalds 		if (file->f_flags & O_APPEND)
20151da177e4SLinus Torvalds 			av |= FILE__APPEND;
20161da177e4SLinus Torvalds 		else
20171da177e4SLinus Torvalds 			av |= FILE__WRITE;
20181da177e4SLinus Torvalds 	}
20190794c66dSStephen Smalley 	if (!av) {
20200794c66dSStephen Smalley 		/*
20210794c66dSStephen Smalley 		 * Special file opened with flags 3 for ioctl-only use.
20220794c66dSStephen Smalley 		 */
20230794c66dSStephen Smalley 		av = FILE__IOCTL;
20240794c66dSStephen Smalley 	}
20251da177e4SLinus Torvalds 
20261da177e4SLinus Torvalds 	return av;
20271da177e4SLinus Torvalds }
20281da177e4SLinus Torvalds 
20298b6a5a37SEric Paris /*
20308b6a5a37SEric Paris  * Convert a file to an access vector and include the correct open
20318b6a5a37SEric Paris  * open permission.
20328b6a5a37SEric Paris  */
20338b6a5a37SEric Paris static inline u32 open_file_to_av(struct file *file)
20348b6a5a37SEric Paris {
20358b6a5a37SEric Paris 	u32 av = file_to_av(file);
2036ccb54478SStephen Smalley 	struct inode *inode = file_inode(file);
20378b6a5a37SEric Paris 
2038aa8e712cSStephen Smalley 	if (selinux_policycap_openperm() &&
2039aa8e712cSStephen Smalley 	    inode->i_sb->s_magic != SOCKFS_MAGIC)
20408b6a5a37SEric Paris 		av |= FILE__OPEN;
204149b7b8deSEric Paris 
20428b6a5a37SEric Paris 	return av;
20438b6a5a37SEric Paris }
20448b6a5a37SEric Paris 
20451da177e4SLinus Torvalds /* Hook functions begin here. */
20461da177e4SLinus Torvalds 
204779af7307SStephen Smalley static int selinux_binder_set_context_mgr(struct task_struct *mgr)
204879af7307SStephen Smalley {
204979af7307SStephen Smalley 	u32 mysid = current_sid();
205079af7307SStephen Smalley 	u32 mgrsid = task_sid(mgr);
205179af7307SStephen Smalley 
20526b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
20536b6bc620SStephen Smalley 			    mysid, mgrsid, SECCLASS_BINDER,
205479af7307SStephen Smalley 			    BINDER__SET_CONTEXT_MGR, NULL);
205579af7307SStephen Smalley }
205679af7307SStephen Smalley 
205779af7307SStephen Smalley static int selinux_binder_transaction(struct task_struct *from,
205879af7307SStephen Smalley 				      struct task_struct *to)
205979af7307SStephen Smalley {
206079af7307SStephen Smalley 	u32 mysid = current_sid();
206179af7307SStephen Smalley 	u32 fromsid = task_sid(from);
206279af7307SStephen Smalley 	u32 tosid = task_sid(to);
206379af7307SStephen Smalley 	int rc;
206479af7307SStephen Smalley 
206579af7307SStephen Smalley 	if (mysid != fromsid) {
20666b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
20676b6bc620SStephen Smalley 				  mysid, fromsid, SECCLASS_BINDER,
206879af7307SStephen Smalley 				  BINDER__IMPERSONATE, NULL);
206979af7307SStephen Smalley 		if (rc)
207079af7307SStephen Smalley 			return rc;
207179af7307SStephen Smalley 	}
207279af7307SStephen Smalley 
20736b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
20746b6bc620SStephen Smalley 			    fromsid, tosid, SECCLASS_BINDER, BINDER__CALL,
207579af7307SStephen Smalley 			    NULL);
207679af7307SStephen Smalley }
207779af7307SStephen Smalley 
207879af7307SStephen Smalley static int selinux_binder_transfer_binder(struct task_struct *from,
207979af7307SStephen Smalley 					  struct task_struct *to)
208079af7307SStephen Smalley {
208179af7307SStephen Smalley 	u32 fromsid = task_sid(from);
208279af7307SStephen Smalley 	u32 tosid = task_sid(to);
208379af7307SStephen Smalley 
20846b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
20856b6bc620SStephen Smalley 			    fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER,
208679af7307SStephen Smalley 			    NULL);
208779af7307SStephen Smalley }
208879af7307SStephen Smalley 
208979af7307SStephen Smalley static int selinux_binder_transfer_file(struct task_struct *from,
209079af7307SStephen Smalley 					struct task_struct *to,
209179af7307SStephen Smalley 					struct file *file)
209279af7307SStephen Smalley {
209379af7307SStephen Smalley 	u32 sid = task_sid(to);
209479af7307SStephen Smalley 	struct file_security_struct *fsec = file->f_security;
209583da53c5SAndreas Gruenbacher 	struct dentry *dentry = file->f_path.dentry;
209620cdef8dSPaul Moore 	struct inode_security_struct *isec;
209779af7307SStephen Smalley 	struct common_audit_data ad;
209879af7307SStephen Smalley 	int rc;
209979af7307SStephen Smalley 
210079af7307SStephen Smalley 	ad.type = LSM_AUDIT_DATA_PATH;
210179af7307SStephen Smalley 	ad.u.path = file->f_path;
210279af7307SStephen Smalley 
210379af7307SStephen Smalley 	if (sid != fsec->sid) {
21046b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
21056b6bc620SStephen Smalley 				  sid, fsec->sid,
210679af7307SStephen Smalley 				  SECCLASS_FD,
210779af7307SStephen Smalley 				  FD__USE,
210879af7307SStephen Smalley 				  &ad);
210979af7307SStephen Smalley 		if (rc)
211079af7307SStephen Smalley 			return rc;
211179af7307SStephen Smalley 	}
211279af7307SStephen Smalley 
2113f66e448cSChenbo Feng #ifdef CONFIG_BPF_SYSCALL
2114f66e448cSChenbo Feng 	rc = bpf_fd_pass(file, sid);
2115f66e448cSChenbo Feng 	if (rc)
2116f66e448cSChenbo Feng 		return rc;
2117f66e448cSChenbo Feng #endif
2118f66e448cSChenbo Feng 
211983da53c5SAndreas Gruenbacher 	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
212079af7307SStephen Smalley 		return 0;
212179af7307SStephen Smalley 
212220cdef8dSPaul Moore 	isec = backing_inode_security(dentry);
21236b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
21246b6bc620SStephen Smalley 			    sid, isec->sid, isec->sclass, file_to_av(file),
212579af7307SStephen Smalley 			    &ad);
212679af7307SStephen Smalley }
212779af7307SStephen Smalley 
21289e48858fSIngo Molnar static int selinux_ptrace_access_check(struct task_struct *child,
2129006ebb40SStephen Smalley 				     unsigned int mode)
21301da177e4SLinus Torvalds {
2131275bb41eSDavid Howells 	u32 sid = current_sid();
2132275bb41eSDavid Howells 	u32 csid = task_sid(child);
2133006ebb40SStephen Smalley 
2134be0554c9SStephen Smalley 	if (mode & PTRACE_MODE_READ)
21356b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
21366b6bc620SStephen Smalley 				    sid, csid, SECCLASS_FILE, FILE__READ, NULL);
2137be0554c9SStephen Smalley 
21386b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
21396b6bc620SStephen Smalley 			    sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
21405cd9c58fSDavid Howells }
21415cd9c58fSDavid Howells 
21425cd9c58fSDavid Howells static int selinux_ptrace_traceme(struct task_struct *parent)
21435cd9c58fSDavid Howells {
21446b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
21456b6bc620SStephen Smalley 			    task_sid(parent), current_sid(), SECCLASS_PROCESS,
2146be0554c9SStephen Smalley 			    PROCESS__PTRACE, NULL);
21471da177e4SLinus Torvalds }
21481da177e4SLinus Torvalds 
21491da177e4SLinus Torvalds static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
21501da177e4SLinus Torvalds 			  kernel_cap_t *inheritable, kernel_cap_t *permitted)
21511da177e4SLinus Torvalds {
21526b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
21536b6bc620SStephen Smalley 			    current_sid(), task_sid(target), SECCLASS_PROCESS,
2154be0554c9SStephen Smalley 			    PROCESS__GETCAP, NULL);
21551da177e4SLinus Torvalds }
21561da177e4SLinus Torvalds 
2157d84f4f99SDavid Howells static int selinux_capset(struct cred *new, const struct cred *old,
2158d84f4f99SDavid Howells 			  const kernel_cap_t *effective,
215915a2460eSDavid Howells 			  const kernel_cap_t *inheritable,
216015a2460eSDavid Howells 			  const kernel_cap_t *permitted)
21611da177e4SLinus Torvalds {
21626b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
21636b6bc620SStephen Smalley 			    cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
2164be0554c9SStephen Smalley 			    PROCESS__SETCAP, NULL);
21651da177e4SLinus Torvalds }
21661da177e4SLinus Torvalds 
21675626d3e8SJames Morris /*
21685626d3e8SJames Morris  * (This comment used to live with the selinux_task_setuid hook,
21695626d3e8SJames Morris  * which was removed).
21705626d3e8SJames Morris  *
21715626d3e8SJames Morris  * Since setuid only affects the current process, and since the SELinux
21725626d3e8SJames Morris  * controls are not based on the Linux identity attributes, SELinux does not
21735626d3e8SJames Morris  * need to control this operation.  However, SELinux does control the use of
21745626d3e8SJames Morris  * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
21755626d3e8SJames Morris  */
21765626d3e8SJames Morris 
21776a9de491SEric Paris static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
21786a9de491SEric Paris 			   int cap, int audit)
21791da177e4SLinus Torvalds {
21808e4ff6f2SStephen Smalley 	return cred_has_capability(cred, cap, audit, ns == &init_user_ns);
21811da177e4SLinus Torvalds }
21821da177e4SLinus Torvalds 
21831da177e4SLinus Torvalds static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
21841da177e4SLinus Torvalds {
218588e67f3bSDavid Howells 	const struct cred *cred = current_cred();
21861da177e4SLinus Torvalds 	int rc = 0;
21871da177e4SLinus Torvalds 
21881da177e4SLinus Torvalds 	if (!sb)
21891da177e4SLinus Torvalds 		return 0;
21901da177e4SLinus Torvalds 
21911da177e4SLinus Torvalds 	switch (cmds) {
21921da177e4SLinus Torvalds 	case Q_SYNC:
21931da177e4SLinus Torvalds 	case Q_QUOTAON:
21941da177e4SLinus Torvalds 	case Q_QUOTAOFF:
21951da177e4SLinus Torvalds 	case Q_SETINFO:
21961da177e4SLinus Torvalds 	case Q_SETQUOTA:
219788e67f3bSDavid Howells 		rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
21981da177e4SLinus Torvalds 		break;
21991da177e4SLinus Torvalds 	case Q_GETFMT:
22001da177e4SLinus Torvalds 	case Q_GETINFO:
22011da177e4SLinus Torvalds 	case Q_GETQUOTA:
220288e67f3bSDavid Howells 		rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
22031da177e4SLinus Torvalds 		break;
22041da177e4SLinus Torvalds 	default:
22051da177e4SLinus Torvalds 		rc = 0;  /* let the kernel handle invalid cmds */
22061da177e4SLinus Torvalds 		break;
22071da177e4SLinus Torvalds 	}
22081da177e4SLinus Torvalds 	return rc;
22091da177e4SLinus Torvalds }
22101da177e4SLinus Torvalds 
22111da177e4SLinus Torvalds static int selinux_quota_on(struct dentry *dentry)
22121da177e4SLinus Torvalds {
221388e67f3bSDavid Howells 	const struct cred *cred = current_cred();
221488e67f3bSDavid Howells 
22152875fa00SEric Paris 	return dentry_has_perm(cred, dentry, FILE__QUOTAON);
22161da177e4SLinus Torvalds }
22171da177e4SLinus Torvalds 
221812b3052cSEric Paris static int selinux_syslog(int type)
22191da177e4SLinus Torvalds {
22201da177e4SLinus Torvalds 	switch (type) {
2221d78ca3cdSKees Cook 	case SYSLOG_ACTION_READ_ALL:	/* Read last kernel messages */
2222d78ca3cdSKees Cook 	case SYSLOG_ACTION_SIZE_BUFFER:	/* Return size of the log buffer */
22236b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
22246b6bc620SStephen Smalley 				    current_sid(), SECINITSID_KERNEL,
2225be0554c9SStephen Smalley 				    SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL);
2226d78ca3cdSKees Cook 	case SYSLOG_ACTION_CONSOLE_OFF:	/* Disable logging to console */
2227d78ca3cdSKees Cook 	case SYSLOG_ACTION_CONSOLE_ON:	/* Enable logging to console */
2228d78ca3cdSKees Cook 	/* Set level of messages printed to console */
2229d78ca3cdSKees Cook 	case SYSLOG_ACTION_CONSOLE_LEVEL:
22306b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
22316b6bc620SStephen Smalley 				    current_sid(), SECINITSID_KERNEL,
2232be0554c9SStephen Smalley 				    SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
2233be0554c9SStephen Smalley 				    NULL);
22341da177e4SLinus Torvalds 	}
2235be0554c9SStephen Smalley 	/* All other syslog types */
22366b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
22376b6bc620SStephen Smalley 			    current_sid(), SECINITSID_KERNEL,
2238be0554c9SStephen Smalley 			    SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
22391da177e4SLinus Torvalds }
22401da177e4SLinus Torvalds 
22411da177e4SLinus Torvalds /*
22421da177e4SLinus Torvalds  * Check that a process has enough memory to allocate a new virtual
22431da177e4SLinus Torvalds  * mapping. 0 means there is enough memory for the allocation to
22441da177e4SLinus Torvalds  * succeed and -ENOMEM implies there is not.
22451da177e4SLinus Torvalds  *
22461da177e4SLinus Torvalds  * Do not audit the selinux permission check, as this is applied to all
22471da177e4SLinus Torvalds  * processes that allocate mappings.
22481da177e4SLinus Torvalds  */
224934b4e4aaSAlan Cox static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
22501da177e4SLinus Torvalds {
22511da177e4SLinus Torvalds 	int rc, cap_sys_admin = 0;
22521da177e4SLinus Torvalds 
2253b1d9e6b0SCasey Schaufler 	rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
22548e4ff6f2SStephen Smalley 				 SECURITY_CAP_NOAUDIT, true);
22551da177e4SLinus Torvalds 	if (rc == 0)
22561da177e4SLinus Torvalds 		cap_sys_admin = 1;
22571da177e4SLinus Torvalds 
2258b1d9e6b0SCasey Schaufler 	return cap_sys_admin;
22591da177e4SLinus Torvalds }
22601da177e4SLinus Torvalds 
22611da177e4SLinus Torvalds /* binprm security operations */
22621da177e4SLinus Torvalds 
2263be0554c9SStephen Smalley static u32 ptrace_parent_sid(void)
22640c6181cbSPaul Moore {
22650c6181cbSPaul Moore 	u32 sid = 0;
22660c6181cbSPaul Moore 	struct task_struct *tracer;
22670c6181cbSPaul Moore 
22680c6181cbSPaul Moore 	rcu_read_lock();
2269be0554c9SStephen Smalley 	tracer = ptrace_parent(current);
22700c6181cbSPaul Moore 	if (tracer)
22710c6181cbSPaul Moore 		sid = task_sid(tracer);
22720c6181cbSPaul Moore 	rcu_read_unlock();
22730c6181cbSPaul Moore 
22740c6181cbSPaul Moore 	return sid;
22750c6181cbSPaul Moore }
22760c6181cbSPaul Moore 
22777b0d0b40SStephen Smalley static int check_nnp_nosuid(const struct linux_binprm *bprm,
22787b0d0b40SStephen Smalley 			    const struct task_security_struct *old_tsec,
22797b0d0b40SStephen Smalley 			    const struct task_security_struct *new_tsec)
22807b0d0b40SStephen Smalley {
22817b0d0b40SStephen Smalley 	int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
2282380cf5baSAndy Lutomirski 	int nosuid = !mnt_may_suid(bprm->file->f_path.mnt);
22837b0d0b40SStephen Smalley 	int rc;
2284af63f419SStephen Smalley 	u32 av;
22857b0d0b40SStephen Smalley 
22867b0d0b40SStephen Smalley 	if (!nnp && !nosuid)
22877b0d0b40SStephen Smalley 		return 0; /* neither NNP nor nosuid */
22887b0d0b40SStephen Smalley 
22897b0d0b40SStephen Smalley 	if (new_tsec->sid == old_tsec->sid)
22907b0d0b40SStephen Smalley 		return 0; /* No change in credentials */
22917b0d0b40SStephen Smalley 
22927b0d0b40SStephen Smalley 	/*
2293af63f419SStephen Smalley 	 * If the policy enables the nnp_nosuid_transition policy capability,
2294af63f419SStephen Smalley 	 * then we permit transitions under NNP or nosuid if the
2295af63f419SStephen Smalley 	 * policy allows the corresponding permission between
2296af63f419SStephen Smalley 	 * the old and new contexts.
2297af63f419SStephen Smalley 	 */
2298aa8e712cSStephen Smalley 	if (selinux_policycap_nnp_nosuid_transition()) {
2299af63f419SStephen Smalley 		av = 0;
2300af63f419SStephen Smalley 		if (nnp)
2301af63f419SStephen Smalley 			av |= PROCESS2__NNP_TRANSITION;
2302af63f419SStephen Smalley 		if (nosuid)
2303af63f419SStephen Smalley 			av |= PROCESS2__NOSUID_TRANSITION;
23046b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
23056b6bc620SStephen Smalley 				  old_tsec->sid, new_tsec->sid,
2306af63f419SStephen Smalley 				  SECCLASS_PROCESS2, av, NULL);
2307af63f419SStephen Smalley 		if (!rc)
2308af63f419SStephen Smalley 			return 0;
2309af63f419SStephen Smalley 	}
2310af63f419SStephen Smalley 
2311af63f419SStephen Smalley 	/*
2312af63f419SStephen Smalley 	 * We also permit NNP or nosuid transitions to bounded SIDs,
2313af63f419SStephen Smalley 	 * i.e. SIDs that are guaranteed to only be allowed a subset
2314af63f419SStephen Smalley 	 * of the permissions of the current SID.
23157b0d0b40SStephen Smalley 	 */
2316aa8e712cSStephen Smalley 	rc = security_bounded_transition(&selinux_state, old_tsec->sid,
2317aa8e712cSStephen Smalley 					 new_tsec->sid);
2318af63f419SStephen Smalley 	if (!rc)
2319af63f419SStephen Smalley 		return 0;
2320af63f419SStephen Smalley 
23217b0d0b40SStephen Smalley 	/*
23227b0d0b40SStephen Smalley 	 * On failure, preserve the errno values for NNP vs nosuid.
23237b0d0b40SStephen Smalley 	 * NNP:  Operation not permitted for caller.
23247b0d0b40SStephen Smalley 	 * nosuid:  Permission denied to file.
23257b0d0b40SStephen Smalley 	 */
23267b0d0b40SStephen Smalley 	if (nnp)
23277b0d0b40SStephen Smalley 		return -EPERM;
23287b0d0b40SStephen Smalley 	return -EACCES;
23297b0d0b40SStephen Smalley }
23307b0d0b40SStephen Smalley 
2331a6f76f23SDavid Howells static int selinux_bprm_set_creds(struct linux_binprm *bprm)
23321da177e4SLinus Torvalds {
2333a6f76f23SDavid Howells 	const struct task_security_struct *old_tsec;
2334a6f76f23SDavid Howells 	struct task_security_struct *new_tsec;
23351da177e4SLinus Torvalds 	struct inode_security_struct *isec;
23362bf49690SThomas Liu 	struct common_audit_data ad;
2337496ad9aaSAl Viro 	struct inode *inode = file_inode(bprm->file);
23381da177e4SLinus Torvalds 	int rc;
23391da177e4SLinus Torvalds 
2340a6f76f23SDavid Howells 	/* SELinux context only depends on initial program or script and not
2341a6f76f23SDavid Howells 	 * the script interpreter */
2342ddb4a144SKees Cook 	if (bprm->called_set_creds)
23431da177e4SLinus Torvalds 		return 0;
23441da177e4SLinus Torvalds 
2345a6f76f23SDavid Howells 	old_tsec = current_security();
2346a6f76f23SDavid Howells 	new_tsec = bprm->cred->security;
234783da53c5SAndreas Gruenbacher 	isec = inode_security(inode);
23481da177e4SLinus Torvalds 
23491da177e4SLinus Torvalds 	/* Default to the current task SID. */
2350a6f76f23SDavid Howells 	new_tsec->sid = old_tsec->sid;
2351a6f76f23SDavid Howells 	new_tsec->osid = old_tsec->sid;
23521da177e4SLinus Torvalds 
235328eba5bfSMichael LeMay 	/* Reset fs, key, and sock SIDs on execve. */
2354a6f76f23SDavid Howells 	new_tsec->create_sid = 0;
2355a6f76f23SDavid Howells 	new_tsec->keycreate_sid = 0;
2356a6f76f23SDavid Howells 	new_tsec->sockcreate_sid = 0;
23571da177e4SLinus Torvalds 
2358a6f76f23SDavid Howells 	if (old_tsec->exec_sid) {
2359a6f76f23SDavid Howells 		new_tsec->sid = old_tsec->exec_sid;
23601da177e4SLinus Torvalds 		/* Reset exec SID on execve. */
2361a6f76f23SDavid Howells 		new_tsec->exec_sid = 0;
2362259e5e6cSAndy Lutomirski 
23637b0d0b40SStephen Smalley 		/* Fail on NNP or nosuid if not an allowed transition. */
23647b0d0b40SStephen Smalley 		rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
23657b0d0b40SStephen Smalley 		if (rc)
23667b0d0b40SStephen Smalley 			return rc;
23671da177e4SLinus Torvalds 	} else {
23681da177e4SLinus Torvalds 		/* Check for a default transition on this program. */
2369aa8e712cSStephen Smalley 		rc = security_transition_sid(&selinux_state, old_tsec->sid,
2370aa8e712cSStephen Smalley 					     isec->sid, SECCLASS_PROCESS, NULL,
2371652bb9b0SEric Paris 					     &new_tsec->sid);
23721da177e4SLinus Torvalds 		if (rc)
23731da177e4SLinus Torvalds 			return rc;
23747b0d0b40SStephen Smalley 
23757b0d0b40SStephen Smalley 		/*
23767b0d0b40SStephen Smalley 		 * Fallback to old SID on NNP or nosuid if not an allowed
23777b0d0b40SStephen Smalley 		 * transition.
23787b0d0b40SStephen Smalley 		 */
23797b0d0b40SStephen Smalley 		rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
23807b0d0b40SStephen Smalley 		if (rc)
23817b0d0b40SStephen Smalley 			new_tsec->sid = old_tsec->sid;
23821da177e4SLinus Torvalds 	}
23831da177e4SLinus Torvalds 
238443af5de7SVivek Goyal 	ad.type = LSM_AUDIT_DATA_FILE;
238543af5de7SVivek Goyal 	ad.u.file = bprm->file;
23861da177e4SLinus Torvalds 
2387a6f76f23SDavid Howells 	if (new_tsec->sid == old_tsec->sid) {
23886b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
23896b6bc620SStephen Smalley 				  old_tsec->sid, isec->sid,
23901da177e4SLinus Torvalds 				  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
23911da177e4SLinus Torvalds 		if (rc)
23921da177e4SLinus Torvalds 			return rc;
23931da177e4SLinus Torvalds 	} else {
23941da177e4SLinus Torvalds 		/* Check permissions for the transition. */
23956b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
23966b6bc620SStephen Smalley 				  old_tsec->sid, new_tsec->sid,
23971da177e4SLinus Torvalds 				  SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
23981da177e4SLinus Torvalds 		if (rc)
23991da177e4SLinus Torvalds 			return rc;
24001da177e4SLinus Torvalds 
24016b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
24026b6bc620SStephen Smalley 				  new_tsec->sid, isec->sid,
24031da177e4SLinus Torvalds 				  SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
24041da177e4SLinus Torvalds 		if (rc)
24051da177e4SLinus Torvalds 			return rc;
24061da177e4SLinus Torvalds 
2407a6f76f23SDavid Howells 		/* Check for shared state */
2408a6f76f23SDavid Howells 		if (bprm->unsafe & LSM_UNSAFE_SHARE) {
24096b6bc620SStephen Smalley 			rc = avc_has_perm(&selinux_state,
24106b6bc620SStephen Smalley 					  old_tsec->sid, new_tsec->sid,
2411a6f76f23SDavid Howells 					  SECCLASS_PROCESS, PROCESS__SHARE,
2412a6f76f23SDavid Howells 					  NULL);
2413a6f76f23SDavid Howells 			if (rc)
2414a6f76f23SDavid Howells 				return -EPERM;
24151da177e4SLinus Torvalds 		}
24161da177e4SLinus Torvalds 
2417a6f76f23SDavid Howells 		/* Make sure that anyone attempting to ptrace over a task that
2418a6f76f23SDavid Howells 		 * changes its SID has the appropriate permit */
24199227dd2aSEric W. Biederman 		if (bprm->unsafe & LSM_UNSAFE_PTRACE) {
2420be0554c9SStephen Smalley 			u32 ptsid = ptrace_parent_sid();
2421a6f76f23SDavid Howells 			if (ptsid != 0) {
24226b6bc620SStephen Smalley 				rc = avc_has_perm(&selinux_state,
24236b6bc620SStephen Smalley 						  ptsid, new_tsec->sid,
2424a6f76f23SDavid Howells 						  SECCLASS_PROCESS,
2425a6f76f23SDavid Howells 						  PROCESS__PTRACE, NULL);
2426a6f76f23SDavid Howells 				if (rc)
2427a6f76f23SDavid Howells 					return -EPERM;
2428a6f76f23SDavid Howells 			}
2429a6f76f23SDavid Howells 		}
2430a6f76f23SDavid Howells 
2431a6f76f23SDavid Howells 		/* Clear any possibly unsafe personality bits on exec: */
2432a6f76f23SDavid Howells 		bprm->per_clear |= PER_CLEAR_ON_SETID;
2433a6f76f23SDavid Howells 
24341da177e4SLinus Torvalds 		/* Enable secure mode for SIDs transitions unless
24351da177e4SLinus Torvalds 		   the noatsecure permission is granted between
24361da177e4SLinus Torvalds 		   the two SIDs, i.e. ahp returns 0. */
24376b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
24386b6bc620SStephen Smalley 				  old_tsec->sid, new_tsec->sid,
243962874c3aSKees Cook 				  SECCLASS_PROCESS, PROCESS__NOATSECURE,
244062874c3aSKees Cook 				  NULL);
244162874c3aSKees Cook 		bprm->secureexec |= !!rc;
24421da177e4SLinus Torvalds 	}
24431da177e4SLinus Torvalds 
244462874c3aSKees Cook 	return 0;
24451da177e4SLinus Torvalds }
24461da177e4SLinus Torvalds 
2447c3c073f8SAl Viro static int match_file(const void *p, struct file *file, unsigned fd)
2448c3c073f8SAl Viro {
2449c3c073f8SAl Viro 	return file_has_perm(p, file, file_to_av(file)) ? fd + 1 : 0;
2450c3c073f8SAl Viro }
2451c3c073f8SAl Viro 
24521da177e4SLinus Torvalds /* Derived from fs/exec.c:flush_old_files. */
2453745ca247SDavid Howells static inline void flush_unauthorized_files(const struct cred *cred,
2454745ca247SDavid Howells 					    struct files_struct *files)
24551da177e4SLinus Torvalds {
24561da177e4SLinus Torvalds 	struct file *file, *devnull = NULL;
2457b20c8122SStephen Smalley 	struct tty_struct *tty;
245824ec839cSPeter Zijlstra 	int drop_tty = 0;
2459c3c073f8SAl Viro 	unsigned n;
24601da177e4SLinus Torvalds 
246124ec839cSPeter Zijlstra 	tty = get_current_tty();
24621da177e4SLinus Torvalds 	if (tty) {
24634a510969SPeter Hurley 		spin_lock(&tty->files_lock);
246437dd0bd0SEric Paris 		if (!list_empty(&tty->tty_files)) {
2465d996b62aSNick Piggin 			struct tty_file_private *file_priv;
246637dd0bd0SEric Paris 
24671da177e4SLinus Torvalds 			/* Revalidate access to controlling tty.
246813f8e981SDavid Howells 			   Use file_path_has_perm on the tty path directly
246913f8e981SDavid Howells 			   rather than using file_has_perm, as this particular
247013f8e981SDavid Howells 			   open file may belong to another process and we are
247113f8e981SDavid Howells 			   only interested in the inode-based check here. */
2472d996b62aSNick Piggin 			file_priv = list_first_entry(&tty->tty_files,
2473d996b62aSNick Piggin 						struct tty_file_private, list);
2474d996b62aSNick Piggin 			file = file_priv->file;
247513f8e981SDavid Howells 			if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE))
247624ec839cSPeter Zijlstra 				drop_tty = 1;
24771da177e4SLinus Torvalds 		}
24784a510969SPeter Hurley 		spin_unlock(&tty->files_lock);
2479452a00d2SAlan Cox 		tty_kref_put(tty);
24801da177e4SLinus Torvalds 	}
248198a27ba4SEric W. Biederman 	/* Reset controlling tty. */
248298a27ba4SEric W. Biederman 	if (drop_tty)
248398a27ba4SEric W. Biederman 		no_tty();
24841da177e4SLinus Torvalds 
24851da177e4SLinus Torvalds 	/* Revalidate access to inherited open files. */
2486c3c073f8SAl Viro 	n = iterate_fd(files, 0, match_file, cred);
2487c3c073f8SAl Viro 	if (!n) /* none found? */
2488c3c073f8SAl Viro 		return;
24891da177e4SLinus Torvalds 
2490c3c073f8SAl Viro 	devnull = dentry_open(&selinux_null, O_RDWR, cred);
249145525b26SAl Viro 	if (IS_ERR(devnull))
249245525b26SAl Viro 		devnull = NULL;
2493c3c073f8SAl Viro 	/* replace all the matching ones with this */
2494c3c073f8SAl Viro 	do {
249545525b26SAl Viro 		replace_fd(n - 1, devnull, 0);
2496c3c073f8SAl Viro 	} while ((n = iterate_fd(files, n, match_file, cred)) != 0);
249745525b26SAl Viro 	if (devnull)
2498c3c073f8SAl Viro 		fput(devnull);
24991da177e4SLinus Torvalds }
25001da177e4SLinus Torvalds 
25011da177e4SLinus Torvalds /*
2502a6f76f23SDavid Howells  * Prepare a process for imminent new credential changes due to exec
25031da177e4SLinus Torvalds  */
2504a6f76f23SDavid Howells static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
25051da177e4SLinus Torvalds {
2506a6f76f23SDavid Howells 	struct task_security_struct *new_tsec;
25071da177e4SLinus Torvalds 	struct rlimit *rlim, *initrlim;
25081da177e4SLinus Torvalds 	int rc, i;
25091da177e4SLinus Torvalds 
2510a6f76f23SDavid Howells 	new_tsec = bprm->cred->security;
2511a6f76f23SDavid Howells 	if (new_tsec->sid == new_tsec->osid)
25121da177e4SLinus Torvalds 		return;
25131da177e4SLinus Torvalds 
25141da177e4SLinus Torvalds 	/* Close files for which the new task SID is not authorized. */
2515a6f76f23SDavid Howells 	flush_unauthorized_files(bprm->cred, current->files);
25161da177e4SLinus Torvalds 
2517a6f76f23SDavid Howells 	/* Always clear parent death signal on SID transitions. */
2518a6f76f23SDavid Howells 	current->pdeath_signal = 0;
2519a6f76f23SDavid Howells 
2520a6f76f23SDavid Howells 	/* Check whether the new SID can inherit resource limits from the old
2521a6f76f23SDavid Howells 	 * SID.  If not, reset all soft limits to the lower of the current
2522a6f76f23SDavid Howells 	 * task's hard limit and the init task's soft limit.
2523a6f76f23SDavid Howells 	 *
2524a6f76f23SDavid Howells 	 * Note that the setting of hard limits (even to lower them) can be
2525a6f76f23SDavid Howells 	 * controlled by the setrlimit check.  The inclusion of the init task's
2526a6f76f23SDavid Howells 	 * soft limit into the computation is to avoid resetting soft limits
2527a6f76f23SDavid Howells 	 * higher than the default soft limit for cases where the default is
2528a6f76f23SDavid Howells 	 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2529a6f76f23SDavid Howells 	 */
25306b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
25316b6bc620SStephen Smalley 			  new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2532a6f76f23SDavid Howells 			  PROCESS__RLIMITINH, NULL);
2533a6f76f23SDavid Howells 	if (rc) {
2534eb2d55a3SOleg Nesterov 		/* protect against do_prlimit() */
2535eb2d55a3SOleg Nesterov 		task_lock(current);
2536a6f76f23SDavid Howells 		for (i = 0; i < RLIM_NLIMITS; i++) {
2537a6f76f23SDavid Howells 			rlim = current->signal->rlim + i;
2538a6f76f23SDavid Howells 			initrlim = init_task.signal->rlim + i;
2539a6f76f23SDavid Howells 			rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2540a6f76f23SDavid Howells 		}
2541eb2d55a3SOleg Nesterov 		task_unlock(current);
2542baa73d9eSNicolas Pitre 		if (IS_ENABLED(CONFIG_POSIX_TIMERS))
2543eb2d55a3SOleg Nesterov 			update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
2544a6f76f23SDavid Howells 	}
2545a6f76f23SDavid Howells }
2546a6f76f23SDavid Howells 
2547a6f76f23SDavid Howells /*
2548a6f76f23SDavid Howells  * Clean up the process immediately after the installation of new credentials
2549a6f76f23SDavid Howells  * due to exec
2550a6f76f23SDavid Howells  */
2551a6f76f23SDavid Howells static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2552a6f76f23SDavid Howells {
2553a6f76f23SDavid Howells 	const struct task_security_struct *tsec = current_security();
2554a6f76f23SDavid Howells 	struct itimerval itimer;
2555a6f76f23SDavid Howells 	u32 osid, sid;
2556a6f76f23SDavid Howells 	int rc, i;
2557a6f76f23SDavid Howells 
2558a6f76f23SDavid Howells 	osid = tsec->osid;
2559a6f76f23SDavid Howells 	sid = tsec->sid;
2560a6f76f23SDavid Howells 
2561a6f76f23SDavid Howells 	if (sid == osid)
2562a6f76f23SDavid Howells 		return;
2563a6f76f23SDavid Howells 
2564a6f76f23SDavid Howells 	/* Check whether the new SID can inherit signal state from the old SID.
2565a6f76f23SDavid Howells 	 * If not, clear itimers to avoid subsequent signal generation and
2566a6f76f23SDavid Howells 	 * flush and unblock signals.
2567a6f76f23SDavid Howells 	 *
2568a6f76f23SDavid Howells 	 * This must occur _after_ the task SID has been updated so that any
2569a6f76f23SDavid Howells 	 * kill done after the flush will be checked against the new SID.
2570a6f76f23SDavid Howells 	 */
25716b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
25726b6bc620SStephen Smalley 			  osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
25731da177e4SLinus Torvalds 	if (rc) {
2574baa73d9eSNicolas Pitre 		if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
25751da177e4SLinus Torvalds 			memset(&itimer, 0, sizeof itimer);
25761da177e4SLinus Torvalds 			for (i = 0; i < 3; i++)
25771da177e4SLinus Torvalds 				do_setitimer(i, &itimer, NULL);
2578baa73d9eSNicolas Pitre 		}
25791da177e4SLinus Torvalds 		spin_lock_irq(&current->sighand->siglock);
25809e7c8f8cSOleg Nesterov 		if (!fatal_signal_pending(current)) {
25819e7c8f8cSOleg Nesterov 			flush_sigqueue(&current->pending);
25829e7c8f8cSOleg Nesterov 			flush_sigqueue(&current->signal->shared_pending);
25831da177e4SLinus Torvalds 			flush_signal_handlers(current, 1);
25841da177e4SLinus Torvalds 			sigemptyset(&current->blocked);
25859e7c8f8cSOleg Nesterov 			recalc_sigpending();
25863bcac026SDavid Howells 		}
25871da177e4SLinus Torvalds 		spin_unlock_irq(&current->sighand->siglock);
25881da177e4SLinus Torvalds 	}
25891da177e4SLinus Torvalds 
2590a6f76f23SDavid Howells 	/* Wake up the parent if it is waiting so that it can recheck
2591a6f76f23SDavid Howells 	 * wait permission to the new task SID. */
2592ecd6de3cSOleg Nesterov 	read_lock(&tasklist_lock);
25930b7570e7SOleg Nesterov 	__wake_up_parent(current, current->real_parent);
2594ecd6de3cSOleg Nesterov 	read_unlock(&tasklist_lock);
25951da177e4SLinus Torvalds }
25961da177e4SLinus Torvalds 
25971da177e4SLinus Torvalds /* superblock security operations */
25981da177e4SLinus Torvalds 
25991da177e4SLinus Torvalds static int selinux_sb_alloc_security(struct super_block *sb)
26001da177e4SLinus Torvalds {
26011da177e4SLinus Torvalds 	return superblock_alloc_security(sb);
26021da177e4SLinus Torvalds }
26031da177e4SLinus Torvalds 
26041da177e4SLinus Torvalds static void selinux_sb_free_security(struct super_block *sb)
26051da177e4SLinus Torvalds {
26061da177e4SLinus Torvalds 	superblock_free_security(sb);
26071da177e4SLinus Torvalds }
26081da177e4SLinus Torvalds 
26091da177e4SLinus Torvalds static inline int match_prefix(char *prefix, int plen, char *option, int olen)
26101da177e4SLinus Torvalds {
26111da177e4SLinus Torvalds 	if (plen > olen)
26121da177e4SLinus Torvalds 		return 0;
26131da177e4SLinus Torvalds 
26141da177e4SLinus Torvalds 	return !memcmp(prefix, option, plen);
26151da177e4SLinus Torvalds }
26161da177e4SLinus Torvalds 
26171da177e4SLinus Torvalds static inline int selinux_option(char *option, int len)
26181da177e4SLinus Torvalds {
2619832cbd9aSEric Paris 	return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) ||
2620832cbd9aSEric Paris 		match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) ||
2621832cbd9aSEric Paris 		match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) ||
262211689d47SDavid P. Quigley 		match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) ||
262311689d47SDavid P. Quigley 		match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len));
26241da177e4SLinus Torvalds }
26251da177e4SLinus Torvalds 
26261da177e4SLinus Torvalds static inline void take_option(char **to, char *from, int *first, int len)
26271da177e4SLinus Torvalds {
26281da177e4SLinus Torvalds 	if (!*first) {
26291da177e4SLinus Torvalds 		**to = ',';
26301da177e4SLinus Torvalds 		*to += 1;
26313528a953SCory Olmo 	} else
26321da177e4SLinus Torvalds 		*first = 0;
26331da177e4SLinus Torvalds 	memcpy(*to, from, len);
26341da177e4SLinus Torvalds 	*to += len;
26351da177e4SLinus Torvalds }
26361da177e4SLinus Torvalds 
26373528a953SCory Olmo static inline void take_selinux_option(char **to, char *from, int *first,
26383528a953SCory Olmo 				       int len)
26393528a953SCory Olmo {
26403528a953SCory Olmo 	int current_size = 0;
26413528a953SCory Olmo 
26423528a953SCory Olmo 	if (!*first) {
26433528a953SCory Olmo 		**to = '|';
26443528a953SCory Olmo 		*to += 1;
2645828dfe1dSEric Paris 	} else
26463528a953SCory Olmo 		*first = 0;
26473528a953SCory Olmo 
26483528a953SCory Olmo 	while (current_size < len) {
26493528a953SCory Olmo 		if (*from != '"') {
26503528a953SCory Olmo 			**to = *from;
26513528a953SCory Olmo 			*to += 1;
26523528a953SCory Olmo 		}
26533528a953SCory Olmo 		from += 1;
26543528a953SCory Olmo 		current_size += 1;
26553528a953SCory Olmo 	}
26563528a953SCory Olmo }
26573528a953SCory Olmo 
2658e0007529SEric Paris static int selinux_sb_copy_data(char *orig, char *copy)
26591da177e4SLinus Torvalds {
26601da177e4SLinus Torvalds 	int fnosec, fsec, rc = 0;
26611da177e4SLinus Torvalds 	char *in_save, *in_curr, *in_end;
26621da177e4SLinus Torvalds 	char *sec_curr, *nosec_save, *nosec;
26633528a953SCory Olmo 	int open_quote = 0;
26641da177e4SLinus Torvalds 
26651da177e4SLinus Torvalds 	in_curr = orig;
26661da177e4SLinus Torvalds 	sec_curr = copy;
26671da177e4SLinus Torvalds 
26681da177e4SLinus Torvalds 	nosec = (char *)get_zeroed_page(GFP_KERNEL);
26691da177e4SLinus Torvalds 	if (!nosec) {
26701da177e4SLinus Torvalds 		rc = -ENOMEM;
26711da177e4SLinus Torvalds 		goto out;
26721da177e4SLinus Torvalds 	}
26731da177e4SLinus Torvalds 
26741da177e4SLinus Torvalds 	nosec_save = nosec;
26751da177e4SLinus Torvalds 	fnosec = fsec = 1;
26761da177e4SLinus Torvalds 	in_save = in_end = orig;
26771da177e4SLinus Torvalds 
26781da177e4SLinus Torvalds 	do {
26793528a953SCory Olmo 		if (*in_end == '"')
26803528a953SCory Olmo 			open_quote = !open_quote;
26813528a953SCory Olmo 		if ((*in_end == ',' && open_quote == 0) ||
26823528a953SCory Olmo 				*in_end == '\0') {
26831da177e4SLinus Torvalds 			int len = in_end - in_curr;
26841da177e4SLinus Torvalds 
26851da177e4SLinus Torvalds 			if (selinux_option(in_curr, len))
26863528a953SCory Olmo 				take_selinux_option(&sec_curr, in_curr, &fsec, len);
26871da177e4SLinus Torvalds 			else
26881da177e4SLinus Torvalds 				take_option(&nosec, in_curr, &fnosec, len);
26891da177e4SLinus Torvalds 
26901da177e4SLinus Torvalds 			in_curr = in_end + 1;
26911da177e4SLinus Torvalds 		}
26921da177e4SLinus Torvalds 	} while (*in_end++);
26931da177e4SLinus Torvalds 
26946931dfc9SEric Paris 	strcpy(in_save, nosec_save);
2695da3caa20SGerald Schaefer 	free_page((unsigned long)nosec_save);
26961da177e4SLinus Torvalds out:
26971da177e4SLinus Torvalds 	return rc;
26981da177e4SLinus Torvalds }
26991da177e4SLinus Torvalds 
2700204cc0ccSAl Viro static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
27015b400239SAl Viro {
27025b400239SAl Viro 	char *s = (char *)get_zeroed_page(GFP_KERNEL);
27035b400239SAl Viro 	int err;
27045b400239SAl Viro 
27055b400239SAl Viro 	if (!s)
27065b400239SAl Viro 		return -ENOMEM;
27075b400239SAl Viro 	err = selinux_sb_copy_data(options, s);
27085b400239SAl Viro 	if (!err)
2709204cc0ccSAl Viro 		err = selinux_parse_opts_str(s, mnt_opts);
27105b400239SAl Viro 	free_page((unsigned long)s);
27115b400239SAl Viro 	return err;
27125b400239SAl Viro }
27135b400239SAl Viro 
2714204cc0ccSAl Viro static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
2715026eb167SEric Paris {
2716bd323655SAl Viro 	struct selinux_mnt_opts *opts = mnt_opts;
2717026eb167SEric Paris 	struct superblock_security_struct *sbsec = sb->s_security;
2718bd323655SAl Viro 	u32 sid;
2719bd323655SAl Viro 	int rc;
2720026eb167SEric Paris 
2721026eb167SEric Paris 	if (!(sbsec->flags & SE_SBINITIALIZED))
2722026eb167SEric Paris 		return 0;
2723026eb167SEric Paris 
2724204cc0ccSAl Viro 	if (!opts)
2725204cc0ccSAl Viro 		return 0;
2726204cc0ccSAl Viro 
2727bd323655SAl Viro 	if (opts->fscontext) {
2728bd323655SAl Viro 		rc = parse_sid(sb, opts->fscontext, &sid);
2729bd323655SAl Viro 		if (rc)
2730c039bc3cSAl Viro 			return rc;
2731026eb167SEric Paris 		if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2732026eb167SEric Paris 			goto out_bad_option;
2733bd323655SAl Viro 	}
2734bd323655SAl Viro 	if (opts->context) {
2735bd323655SAl Viro 		rc = parse_sid(sb, opts->context, &sid);
2736bd323655SAl Viro 		if (rc)
2737bd323655SAl Viro 			return rc;
2738026eb167SEric Paris 		if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2739026eb167SEric Paris 			goto out_bad_option;
2740bd323655SAl Viro 	}
2741bd323655SAl Viro 	if (opts->rootcontext) {
2742026eb167SEric Paris 		struct inode_security_struct *root_isec;
274383da53c5SAndreas Gruenbacher 		root_isec = backing_inode_security(sb->s_root);
2744bd323655SAl Viro 		rc = parse_sid(sb, opts->rootcontext, &sid);
2745bd323655SAl Viro 		if (rc)
2746bd323655SAl Viro 			return rc;
2747026eb167SEric Paris 		if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2748026eb167SEric Paris 			goto out_bad_option;
2749026eb167SEric Paris 	}
2750bd323655SAl Viro 	if (opts->defcontext) {
2751bd323655SAl Viro 		rc = parse_sid(sb, opts->defcontext, &sid);
2752bd323655SAl Viro 		if (rc)
2753bd323655SAl Viro 			return rc;
2754026eb167SEric Paris 		if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2755026eb167SEric Paris 			goto out_bad_option;
2756026eb167SEric Paris 	}
2757c039bc3cSAl Viro 	return 0;
2758026eb167SEric Paris 
2759026eb167SEric Paris out_bad_option:
2760c103a91eSpeter enderborg 	pr_warn("SELinux: unable to change security options "
276129b1deb2SLinus Torvalds 	       "during remount (dev %s, type=%s)\n", sb->s_id,
276229b1deb2SLinus Torvalds 	       sb->s_type->name);
2763c039bc3cSAl Viro 	return -EINVAL;
2764026eb167SEric Paris }
2765026eb167SEric Paris 
2766a10d7c22SAl Viro static int selinux_sb_kern_mount(struct super_block *sb)
27671da177e4SLinus Torvalds {
276888e67f3bSDavid Howells 	const struct cred *cred = current_cred();
27692bf49690SThomas Liu 	struct common_audit_data ad;
277074192246SJames Morris 
277150c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
2772a269434dSEric Paris 	ad.u.dentry = sb->s_root;
277388e67f3bSDavid Howells 	return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
27741da177e4SLinus Torvalds }
27751da177e4SLinus Torvalds 
2776726c3342SDavid Howells static int selinux_sb_statfs(struct dentry *dentry)
27771da177e4SLinus Torvalds {
277888e67f3bSDavid Howells 	const struct cred *cred = current_cred();
27792bf49690SThomas Liu 	struct common_audit_data ad;
27801da177e4SLinus Torvalds 
278150c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
2782a269434dSEric Paris 	ad.u.dentry = dentry->d_sb->s_root;
278388e67f3bSDavid Howells 	return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
27841da177e4SLinus Torvalds }
27851da177e4SLinus Torvalds 
2786808d4e3cSAl Viro static int selinux_mount(const char *dev_name,
27878a04c43bSAl Viro 			 const struct path *path,
2788808d4e3cSAl Viro 			 const char *type,
27891da177e4SLinus Torvalds 			 unsigned long flags,
27901da177e4SLinus Torvalds 			 void *data)
27911da177e4SLinus Torvalds {
279288e67f3bSDavid Howells 	const struct cred *cred = current_cred();
27931da177e4SLinus Torvalds 
27941da177e4SLinus Torvalds 	if (flags & MS_REMOUNT)
2795d8c9584eSAl Viro 		return superblock_has_perm(cred, path->dentry->d_sb,
27961da177e4SLinus Torvalds 					   FILESYSTEM__REMOUNT, NULL);
27971da177e4SLinus Torvalds 	else
27982875fa00SEric Paris 		return path_has_perm(cred, path, FILE__MOUNTON);
27991da177e4SLinus Torvalds }
28001da177e4SLinus Torvalds 
28011da177e4SLinus Torvalds static int selinux_umount(struct vfsmount *mnt, int flags)
28021da177e4SLinus Torvalds {
280388e67f3bSDavid Howells 	const struct cred *cred = current_cred();
28041da177e4SLinus Torvalds 
280588e67f3bSDavid Howells 	return superblock_has_perm(cred, mnt->mnt_sb,
28061da177e4SLinus Torvalds 				   FILESYSTEM__UNMOUNT, NULL);
28071da177e4SLinus Torvalds }
28081da177e4SLinus Torvalds 
28091da177e4SLinus Torvalds /* inode security operations */
28101da177e4SLinus Torvalds 
28111da177e4SLinus Torvalds static int selinux_inode_alloc_security(struct inode *inode)
28121da177e4SLinus Torvalds {
28131da177e4SLinus Torvalds 	return inode_alloc_security(inode);
28141da177e4SLinus Torvalds }
28151da177e4SLinus Torvalds 
28161da177e4SLinus Torvalds static void selinux_inode_free_security(struct inode *inode)
28171da177e4SLinus Torvalds {
28181da177e4SLinus Torvalds 	inode_free_security(inode);
28191da177e4SLinus Torvalds }
28201da177e4SLinus Torvalds 
2821d47be3dfSDavid Quigley static int selinux_dentry_init_security(struct dentry *dentry, int mode,
28224f3ccd76SAl Viro 					const struct qstr *name, void **ctx,
2823d47be3dfSDavid Quigley 					u32 *ctxlen)
2824d47be3dfSDavid Quigley {
2825d47be3dfSDavid Quigley 	u32 newsid;
2826d47be3dfSDavid Quigley 	int rc;
2827d47be3dfSDavid Quigley 
2828c957f6dfSVivek Goyal 	rc = selinux_determine_inode_label(current_security(),
2829c957f6dfSVivek Goyal 					   d_inode(dentry->d_parent), name,
2830d47be3dfSDavid Quigley 					   inode_mode_to_security_class(mode),
2831d47be3dfSDavid Quigley 					   &newsid);
2832c3c188b2SDavid Howells 	if (rc)
2833d47be3dfSDavid Quigley 		return rc;
2834d47be3dfSDavid Quigley 
2835aa8e712cSStephen Smalley 	return security_sid_to_context(&selinux_state, newsid, (char **)ctx,
2836aa8e712cSStephen Smalley 				       ctxlen);
2837d47be3dfSDavid Quigley }
2838d47be3dfSDavid Quigley 
2839a518b0a5SVivek Goyal static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
2840a518b0a5SVivek Goyal 					  struct qstr *name,
2841a518b0a5SVivek Goyal 					  const struct cred *old,
2842a518b0a5SVivek Goyal 					  struct cred *new)
2843a518b0a5SVivek Goyal {
2844a518b0a5SVivek Goyal 	u32 newsid;
2845a518b0a5SVivek Goyal 	int rc;
2846a518b0a5SVivek Goyal 	struct task_security_struct *tsec;
2847a518b0a5SVivek Goyal 
2848a518b0a5SVivek Goyal 	rc = selinux_determine_inode_label(old->security,
2849a518b0a5SVivek Goyal 					   d_inode(dentry->d_parent), name,
2850a518b0a5SVivek Goyal 					   inode_mode_to_security_class(mode),
2851a518b0a5SVivek Goyal 					   &newsid);
2852a518b0a5SVivek Goyal 	if (rc)
2853a518b0a5SVivek Goyal 		return rc;
2854a518b0a5SVivek Goyal 
2855a518b0a5SVivek Goyal 	tsec = new->security;
2856a518b0a5SVivek Goyal 	tsec->create_sid = newsid;
2857a518b0a5SVivek Goyal 	return 0;
2858a518b0a5SVivek Goyal }
2859a518b0a5SVivek Goyal 
28605e41ff9eSStephen Smalley static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
28619548906bSTetsuo Handa 				       const struct qstr *qstr,
28629548906bSTetsuo Handa 				       const char **name,
28632a7dba39SEric Paris 				       void **value, size_t *len)
28645e41ff9eSStephen Smalley {
28655fb49870SPaul Moore 	const struct task_security_struct *tsec = current_security();
28665e41ff9eSStephen Smalley 	struct superblock_security_struct *sbsec;
2867c0d4f464SCorentin LABBE 	u32 newsid, clen;
28685e41ff9eSStephen Smalley 	int rc;
28699548906bSTetsuo Handa 	char *context;
28705e41ff9eSStephen Smalley 
28715e41ff9eSStephen Smalley 	sbsec = dir->i_sb->s_security;
28725e41ff9eSStephen Smalley 
28735e41ff9eSStephen Smalley 	newsid = tsec->create_sid;
2874275bb41eSDavid Howells 
2875c957f6dfSVivek Goyal 	rc = selinux_determine_inode_label(current_security(),
2876c3c188b2SDavid Howells 		dir, qstr,
28775e41ff9eSStephen Smalley 		inode_mode_to_security_class(inode->i_mode),
2878c3c188b2SDavid Howells 		&newsid);
2879c3c188b2SDavid Howells 	if (rc)
28805e41ff9eSStephen Smalley 		return rc;
28815e41ff9eSStephen Smalley 
2882296fddf7SEric Paris 	/* Possibly defer initialization to selinux_complete_init. */
28830d90a7ecSDavid P. Quigley 	if (sbsec->flags & SE_SBINITIALIZED) {
2884296fddf7SEric Paris 		struct inode_security_struct *isec = inode->i_security;
2885296fddf7SEric Paris 		isec->sclass = inode_mode_to_security_class(inode->i_mode);
2886296fddf7SEric Paris 		isec->sid = newsid;
28876f3be9f5SAndreas Gruenbacher 		isec->initialized = LABEL_INITIALIZED;
2888296fddf7SEric Paris 	}
28895e41ff9eSStephen Smalley 
2890aa8e712cSStephen Smalley 	if (!selinux_state.initialized || !(sbsec->flags & SBLABEL_MNT))
289125a74f3bSStephen Smalley 		return -EOPNOTSUPP;
289225a74f3bSStephen Smalley 
28939548906bSTetsuo Handa 	if (name)
28949548906bSTetsuo Handa 		*name = XATTR_SELINUX_SUFFIX;
28955e41ff9eSStephen Smalley 
2896570bc1c2SStephen Smalley 	if (value && len) {
2897aa8e712cSStephen Smalley 		rc = security_sid_to_context_force(&selinux_state, newsid,
2898aa8e712cSStephen Smalley 						   &context, &clen);
28999548906bSTetsuo Handa 		if (rc)
29005e41ff9eSStephen Smalley 			return rc;
29015e41ff9eSStephen Smalley 		*value = context;
2902570bc1c2SStephen Smalley 		*len = clen;
2903570bc1c2SStephen Smalley 	}
29045e41ff9eSStephen Smalley 
29055e41ff9eSStephen Smalley 	return 0;
29065e41ff9eSStephen Smalley }
29075e41ff9eSStephen Smalley 
29084acdaf27SAl Viro static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
29091da177e4SLinus Torvalds {
29101da177e4SLinus Torvalds 	return may_create(dir, dentry, SECCLASS_FILE);
29111da177e4SLinus Torvalds }
29121da177e4SLinus Torvalds 
29131da177e4SLinus Torvalds static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
29141da177e4SLinus Torvalds {
29151da177e4SLinus Torvalds 	return may_link(dir, old_dentry, MAY_LINK);
29161da177e4SLinus Torvalds }
29171da177e4SLinus Torvalds 
29181da177e4SLinus Torvalds static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
29191da177e4SLinus Torvalds {
29201da177e4SLinus Torvalds 	return may_link(dir, dentry, MAY_UNLINK);
29211da177e4SLinus Torvalds }
29221da177e4SLinus Torvalds 
29231da177e4SLinus Torvalds static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
29241da177e4SLinus Torvalds {
29251da177e4SLinus Torvalds 	return may_create(dir, dentry, SECCLASS_LNK_FILE);
29261da177e4SLinus Torvalds }
29271da177e4SLinus Torvalds 
292818bb1db3SAl Viro static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
29291da177e4SLinus Torvalds {
29301da177e4SLinus Torvalds 	return may_create(dir, dentry, SECCLASS_DIR);
29311da177e4SLinus Torvalds }
29321da177e4SLinus Torvalds 
29331da177e4SLinus Torvalds static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
29341da177e4SLinus Torvalds {
29351da177e4SLinus Torvalds 	return may_link(dir, dentry, MAY_RMDIR);
29361da177e4SLinus Torvalds }
29371da177e4SLinus Torvalds 
29381a67aafbSAl Viro static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
29391da177e4SLinus Torvalds {
29401da177e4SLinus Torvalds 	return may_create(dir, dentry, inode_mode_to_security_class(mode));
29411da177e4SLinus Torvalds }
29421da177e4SLinus Torvalds 
29431da177e4SLinus Torvalds static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
29441da177e4SLinus Torvalds 				struct inode *new_inode, struct dentry *new_dentry)
29451da177e4SLinus Torvalds {
29461da177e4SLinus Torvalds 	return may_rename(old_inode, old_dentry, new_inode, new_dentry);
29471da177e4SLinus Torvalds }
29481da177e4SLinus Torvalds 
29491da177e4SLinus Torvalds static int selinux_inode_readlink(struct dentry *dentry)
29501da177e4SLinus Torvalds {
295188e67f3bSDavid Howells 	const struct cred *cred = current_cred();
295288e67f3bSDavid Howells 
29532875fa00SEric Paris 	return dentry_has_perm(cred, dentry, FILE__READ);
29541da177e4SLinus Torvalds }
29551da177e4SLinus Torvalds 
2956bda0be7aSNeilBrown static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
2957bda0be7aSNeilBrown 				     bool rcu)
29581da177e4SLinus Torvalds {
295988e67f3bSDavid Howells 	const struct cred *cred = current_cred();
2960bda0be7aSNeilBrown 	struct common_audit_data ad;
2961bda0be7aSNeilBrown 	struct inode_security_struct *isec;
2962bda0be7aSNeilBrown 	u32 sid;
29631da177e4SLinus Torvalds 
2964bda0be7aSNeilBrown 	validate_creds(cred);
2965bda0be7aSNeilBrown 
2966bda0be7aSNeilBrown 	ad.type = LSM_AUDIT_DATA_DENTRY;
2967bda0be7aSNeilBrown 	ad.u.dentry = dentry;
2968bda0be7aSNeilBrown 	sid = cred_sid(cred);
29695d226df4SAndreas Gruenbacher 	isec = inode_security_rcu(inode, rcu);
29705d226df4SAndreas Gruenbacher 	if (IS_ERR(isec))
29715d226df4SAndreas Gruenbacher 		return PTR_ERR(isec);
2972bda0be7aSNeilBrown 
29736b6bc620SStephen Smalley 	return avc_has_perm_flags(&selinux_state,
29746b6bc620SStephen Smalley 				  sid, isec->sid, isec->sclass, FILE__READ, &ad,
2975bda0be7aSNeilBrown 				  rcu ? MAY_NOT_BLOCK : 0);
29761da177e4SLinus Torvalds }
29771da177e4SLinus Torvalds 
2978d4cf970dSEric Paris static noinline int audit_inode_permission(struct inode *inode,
2979d4cf970dSEric Paris 					   u32 perms, u32 audited, u32 denied,
2980626b9740SStephen Smalley 					   int result,
2981d4cf970dSEric Paris 					   unsigned flags)
2982d4cf970dSEric Paris {
2983d4cf970dSEric Paris 	struct common_audit_data ad;
2984d4cf970dSEric Paris 	struct inode_security_struct *isec = inode->i_security;
2985d4cf970dSEric Paris 	int rc;
2986d4cf970dSEric Paris 
298750c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_INODE;
2988d4cf970dSEric Paris 	ad.u.inode = inode;
2989d4cf970dSEric Paris 
29906b6bc620SStephen Smalley 	rc = slow_avc_audit(&selinux_state,
29916b6bc620SStephen Smalley 			    current_sid(), isec->sid, isec->sclass, perms,
2992626b9740SStephen Smalley 			    audited, denied, result, &ad, flags);
2993d4cf970dSEric Paris 	if (rc)
2994d4cf970dSEric Paris 		return rc;
2995d4cf970dSEric Paris 	return 0;
2996d4cf970dSEric Paris }
2997d4cf970dSEric Paris 
2998e74f71ebSAl Viro static int selinux_inode_permission(struct inode *inode, int mask)
29991da177e4SLinus Torvalds {
300088e67f3bSDavid Howells 	const struct cred *cred = current_cred();
3001b782e0a6SEric Paris 	u32 perms;
3002b782e0a6SEric Paris 	bool from_access;
3003cf1dd1daSAl Viro 	unsigned flags = mask & MAY_NOT_BLOCK;
30042e334057SEric Paris 	struct inode_security_struct *isec;
30052e334057SEric Paris 	u32 sid;
30062e334057SEric Paris 	struct av_decision avd;
30072e334057SEric Paris 	int rc, rc2;
30082e334057SEric Paris 	u32 audited, denied;
30091da177e4SLinus Torvalds 
3010b782e0a6SEric Paris 	from_access = mask & MAY_ACCESS;
3011d09ca739SEric Paris 	mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
3012d09ca739SEric Paris 
30131da177e4SLinus Torvalds 	/* No permission to check.  Existence test. */
3014b782e0a6SEric Paris 	if (!mask)
30151da177e4SLinus Torvalds 		return 0;
30161da177e4SLinus Torvalds 
30172e334057SEric Paris 	validate_creds(cred);
3018b782e0a6SEric Paris 
30192e334057SEric Paris 	if (unlikely(IS_PRIVATE(inode)))
30202e334057SEric Paris 		return 0;
3021b782e0a6SEric Paris 
3022b782e0a6SEric Paris 	perms = file_mask_to_av(inode->i_mode, mask);
3023b782e0a6SEric Paris 
30242e334057SEric Paris 	sid = cred_sid(cred);
30255d226df4SAndreas Gruenbacher 	isec = inode_security_rcu(inode, flags & MAY_NOT_BLOCK);
30265d226df4SAndreas Gruenbacher 	if (IS_ERR(isec))
30275d226df4SAndreas Gruenbacher 		return PTR_ERR(isec);
30282e334057SEric Paris 
30296b6bc620SStephen Smalley 	rc = avc_has_perm_noaudit(&selinux_state,
30306b6bc620SStephen Smalley 				  sid, isec->sid, isec->sclass, perms, 0, &avd);
30312e334057SEric Paris 	audited = avc_audit_required(perms, &avd, rc,
30322e334057SEric Paris 				     from_access ? FILE__AUDIT_ACCESS : 0,
30332e334057SEric Paris 				     &denied);
30342e334057SEric Paris 	if (likely(!audited))
30352e334057SEric Paris 		return rc;
30362e334057SEric Paris 
3037626b9740SStephen Smalley 	rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags);
30382e334057SEric Paris 	if (rc2)
30392e334057SEric Paris 		return rc2;
30402e334057SEric Paris 	return rc;
30411da177e4SLinus Torvalds }
30421da177e4SLinus Torvalds 
30431da177e4SLinus Torvalds static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
30441da177e4SLinus Torvalds {
304588e67f3bSDavid Howells 	const struct cred *cred = current_cred();
3046ccb54478SStephen Smalley 	struct inode *inode = d_backing_inode(dentry);
3047bc6a6008SAmerigo Wang 	unsigned int ia_valid = iattr->ia_valid;
304895dbf739SEric Paris 	__u32 av = FILE__WRITE;
30491da177e4SLinus Torvalds 
3050bc6a6008SAmerigo Wang 	/* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
3051bc6a6008SAmerigo Wang 	if (ia_valid & ATTR_FORCE) {
3052bc6a6008SAmerigo Wang 		ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
3053bc6a6008SAmerigo Wang 			      ATTR_FORCE);
3054bc6a6008SAmerigo Wang 		if (!ia_valid)
30551da177e4SLinus Torvalds 			return 0;
3056bc6a6008SAmerigo Wang 	}
30571da177e4SLinus Torvalds 
3058bc6a6008SAmerigo Wang 	if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
3059bc6a6008SAmerigo Wang 			ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
30602875fa00SEric Paris 		return dentry_has_perm(cred, dentry, FILE__SETATTR);
30611da177e4SLinus Torvalds 
3062aa8e712cSStephen Smalley 	if (selinux_policycap_openperm() &&
3063ccb54478SStephen Smalley 	    inode->i_sb->s_magic != SOCKFS_MAGIC &&
3064ccb54478SStephen Smalley 	    (ia_valid & ATTR_SIZE) &&
3065ccb54478SStephen Smalley 	    !(ia_valid & ATTR_FILE))
306695dbf739SEric Paris 		av |= FILE__OPEN;
306795dbf739SEric Paris 
306895dbf739SEric Paris 	return dentry_has_perm(cred, dentry, av);
30691da177e4SLinus Torvalds }
30701da177e4SLinus Torvalds 
30713f7036a0SAl Viro static int selinux_inode_getattr(const struct path *path)
30721da177e4SLinus Torvalds {
30733f7036a0SAl Viro 	return path_has_perm(current_cred(), path, FILE__GETATTR);
30741da177e4SLinus Torvalds }
30751da177e4SLinus Torvalds 
3076db59000aSStephen Smalley static bool has_cap_mac_admin(bool audit)
3077db59000aSStephen Smalley {
3078db59000aSStephen Smalley 	const struct cred *cred = current_cred();
3079db59000aSStephen Smalley 	int cap_audit = audit ? SECURITY_CAP_AUDIT : SECURITY_CAP_NOAUDIT;
3080db59000aSStephen Smalley 
3081db59000aSStephen Smalley 	if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, cap_audit))
3082db59000aSStephen Smalley 		return false;
3083db59000aSStephen Smalley 	if (cred_has_capability(cred, CAP_MAC_ADMIN, cap_audit, true))
3084db59000aSStephen Smalley 		return false;
3085db59000aSStephen Smalley 	return true;
3086db59000aSStephen Smalley }
3087db59000aSStephen Smalley 
30888f0cfa52SDavid Howells static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
30898f0cfa52SDavid Howells 				  const void *value, size_t size, int flags)
30901da177e4SLinus Torvalds {
3091c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(dentry);
309220cdef8dSPaul Moore 	struct inode_security_struct *isec;
30931da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec;
30942bf49690SThomas Liu 	struct common_audit_data ad;
3095275bb41eSDavid Howells 	u32 newsid, sid = current_sid();
30961da177e4SLinus Torvalds 	int rc = 0;
30971da177e4SLinus Torvalds 
30986b240306SEric W. Biederman 	if (strcmp(name, XATTR_NAME_SELINUX)) {
30996b240306SEric W. Biederman 		rc = cap_inode_setxattr(dentry, name, value, size, flags);
31006b240306SEric W. Biederman 		if (rc)
31016b240306SEric W. Biederman 			return rc;
31026b240306SEric W. Biederman 
31036b240306SEric W. Biederman 		/* Not an attribute we recognize, so just check the
31046b240306SEric W. Biederman 		   ordinary setattr permission. */
31056b240306SEric W. Biederman 		return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
31066b240306SEric W. Biederman 	}
31071da177e4SLinus Torvalds 
31081da177e4SLinus Torvalds 	sbsec = inode->i_sb->s_security;
310912f348b9SEric Paris 	if (!(sbsec->flags & SBLABEL_MNT))
31101da177e4SLinus Torvalds 		return -EOPNOTSUPP;
31111da177e4SLinus Torvalds 
31122e149670SSerge E. Hallyn 	if (!inode_owner_or_capable(inode))
31131da177e4SLinus Torvalds 		return -EPERM;
31141da177e4SLinus Torvalds 
311550c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
3116a269434dSEric Paris 	ad.u.dentry = dentry;
31171da177e4SLinus Torvalds 
311820cdef8dSPaul Moore 	isec = backing_inode_security(dentry);
31196b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
31206b6bc620SStephen Smalley 			  sid, isec->sid, isec->sclass,
31211da177e4SLinus Torvalds 			  FILE__RELABELFROM, &ad);
31221da177e4SLinus Torvalds 	if (rc)
31231da177e4SLinus Torvalds 		return rc;
31241da177e4SLinus Torvalds 
3125aa8e712cSStephen Smalley 	rc = security_context_to_sid(&selinux_state, value, size, &newsid,
3126aa8e712cSStephen Smalley 				     GFP_KERNEL);
312712b29f34SStephen Smalley 	if (rc == -EINVAL) {
3128db59000aSStephen Smalley 		if (!has_cap_mac_admin(true)) {
3129d6ea83ecSEric Paris 			struct audit_buffer *ab;
3130d6ea83ecSEric Paris 			size_t audit_size;
3131d6ea83ecSEric Paris 
3132d6ea83ecSEric Paris 			/* We strip a nul only if it is at the end, otherwise the
3133d6ea83ecSEric Paris 			 * context contains a nul and we should audit that */
3134e3fea3f7SAl Viro 			if (value) {
3135add24372SColin Ian King 				const char *str = value;
3136add24372SColin Ian King 
3137d6ea83ecSEric Paris 				if (str[size - 1] == '\0')
3138d6ea83ecSEric Paris 					audit_size = size - 1;
3139d6ea83ecSEric Paris 				else
3140d6ea83ecSEric Paris 					audit_size = size;
3141e3fea3f7SAl Viro 			} else {
3142e3fea3f7SAl Viro 				audit_size = 0;
3143e3fea3f7SAl Viro 			}
3144cdfb6b34SRichard Guy Briggs 			ab = audit_log_start(audit_context(),
3145cdfb6b34SRichard Guy Briggs 					     GFP_ATOMIC, AUDIT_SELINUX_ERR);
3146d6ea83ecSEric Paris 			audit_log_format(ab, "op=setxattr invalid_context=");
3147d6ea83ecSEric Paris 			audit_log_n_untrustedstring(ab, value, audit_size);
3148d6ea83ecSEric Paris 			audit_log_end(ab);
3149d6ea83ecSEric Paris 
315012b29f34SStephen Smalley 			return rc;
3151d6ea83ecSEric Paris 		}
3152aa8e712cSStephen Smalley 		rc = security_context_to_sid_force(&selinux_state, value,
3153aa8e712cSStephen Smalley 						   size, &newsid);
315412b29f34SStephen Smalley 	}
31551da177e4SLinus Torvalds 	if (rc)
31561da177e4SLinus Torvalds 		return rc;
31571da177e4SLinus Torvalds 
31586b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
31596b6bc620SStephen Smalley 			  sid, newsid, isec->sclass,
31601da177e4SLinus Torvalds 			  FILE__RELABELTO, &ad);
31611da177e4SLinus Torvalds 	if (rc)
31621da177e4SLinus Torvalds 		return rc;
31631da177e4SLinus Torvalds 
3164aa8e712cSStephen Smalley 	rc = security_validate_transition(&selinux_state, isec->sid, newsid,
3165aa8e712cSStephen Smalley 					  sid, isec->sclass);
31661da177e4SLinus Torvalds 	if (rc)
31671da177e4SLinus Torvalds 		return rc;
31681da177e4SLinus Torvalds 
31696b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
31706b6bc620SStephen Smalley 			    newsid,
31711da177e4SLinus Torvalds 			    sbsec->sid,
31721da177e4SLinus Torvalds 			    SECCLASS_FILESYSTEM,
31731da177e4SLinus Torvalds 			    FILESYSTEM__ASSOCIATE,
31741da177e4SLinus Torvalds 			    &ad);
31751da177e4SLinus Torvalds }
31761da177e4SLinus Torvalds 
31778f0cfa52SDavid Howells static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
31788f0cfa52SDavid Howells 					const void *value, size_t size,
31798f0cfa52SDavid Howells 					int flags)
31801da177e4SLinus Torvalds {
3181c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(dentry);
318220cdef8dSPaul Moore 	struct inode_security_struct *isec;
31831da177e4SLinus Torvalds 	u32 newsid;
31841da177e4SLinus Torvalds 	int rc;
31851da177e4SLinus Torvalds 
31861da177e4SLinus Torvalds 	if (strcmp(name, XATTR_NAME_SELINUX)) {
31871da177e4SLinus Torvalds 		/* Not an attribute we recognize, so nothing to do. */
31881da177e4SLinus Torvalds 		return;
31891da177e4SLinus Torvalds 	}
31901da177e4SLinus Torvalds 
3191aa8e712cSStephen Smalley 	rc = security_context_to_sid_force(&selinux_state, value, size,
3192aa8e712cSStephen Smalley 					   &newsid);
31931da177e4SLinus Torvalds 	if (rc) {
3194c103a91eSpeter enderborg 		pr_err("SELinux:  unable to map context to SID"
319512b29f34SStephen Smalley 		       "for (%s, %lu), rc=%d\n",
319612b29f34SStephen Smalley 		       inode->i_sb->s_id, inode->i_ino, -rc);
31971da177e4SLinus Torvalds 		return;
31981da177e4SLinus Torvalds 	}
31991da177e4SLinus Torvalds 
320020cdef8dSPaul Moore 	isec = backing_inode_security(dentry);
32019287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
3202aa9c2669SDavid Quigley 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
32031da177e4SLinus Torvalds 	isec->sid = newsid;
32046f3be9f5SAndreas Gruenbacher 	isec->initialized = LABEL_INITIALIZED;
32059287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
3206aa9c2669SDavid Quigley 
32071da177e4SLinus Torvalds 	return;
32081da177e4SLinus Torvalds }
32091da177e4SLinus Torvalds 
32108f0cfa52SDavid Howells static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
32111da177e4SLinus Torvalds {
321288e67f3bSDavid Howells 	const struct cred *cred = current_cred();
321388e67f3bSDavid Howells 
32142875fa00SEric Paris 	return dentry_has_perm(cred, dentry, FILE__GETATTR);
32151da177e4SLinus Torvalds }
32161da177e4SLinus Torvalds 
32171da177e4SLinus Torvalds static int selinux_inode_listxattr(struct dentry *dentry)
32181da177e4SLinus Torvalds {
321988e67f3bSDavid Howells 	const struct cred *cred = current_cred();
322088e67f3bSDavid Howells 
32212875fa00SEric Paris 	return dentry_has_perm(cred, dentry, FILE__GETATTR);
32221da177e4SLinus Torvalds }
32231da177e4SLinus Torvalds 
32248f0cfa52SDavid Howells static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
32251da177e4SLinus Torvalds {
32266b240306SEric W. Biederman 	if (strcmp(name, XATTR_NAME_SELINUX)) {
32276b240306SEric W. Biederman 		int rc = cap_inode_removexattr(dentry, name);
32286b240306SEric W. Biederman 		if (rc)
32296b240306SEric W. Biederman 			return rc;
32306b240306SEric W. Biederman 
32316b240306SEric W. Biederman 		/* Not an attribute we recognize, so just check the
32326b240306SEric W. Biederman 		   ordinary setattr permission. */
32336b240306SEric W. Biederman 		return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
32346b240306SEric W. Biederman 	}
32351da177e4SLinus Torvalds 
32361da177e4SLinus Torvalds 	/* No one is allowed to remove a SELinux security label.
32371da177e4SLinus Torvalds 	   You can change the label, but all data must be labeled. */
32381da177e4SLinus Torvalds 	return -EACCES;
32391da177e4SLinus Torvalds }
32401da177e4SLinus Torvalds 
3241d381d8a9SJames Morris /*
3242abc69bb6SStephen Smalley  * Copy the inode security context value to the user.
3243d381d8a9SJames Morris  *
3244d381d8a9SJames Morris  * Permission check is handled by selinux_inode_getxattr hook.
3245d381d8a9SJames Morris  */
3246ea861dfdSAndreas Gruenbacher static int selinux_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc)
32471da177e4SLinus Torvalds {
324842492594SDavid P. Quigley 	u32 size;
324942492594SDavid P. Quigley 	int error;
325042492594SDavid P. Quigley 	char *context = NULL;
325120cdef8dSPaul Moore 	struct inode_security_struct *isec;
32521da177e4SLinus Torvalds 
32538c8570fbSDustin Kirkland 	if (strcmp(name, XATTR_SELINUX_SUFFIX))
32548c8570fbSDustin Kirkland 		return -EOPNOTSUPP;
32551da177e4SLinus Torvalds 
3256abc69bb6SStephen Smalley 	/*
3257abc69bb6SStephen Smalley 	 * If the caller has CAP_MAC_ADMIN, then get the raw context
3258abc69bb6SStephen Smalley 	 * value even if it is not defined by current policy; otherwise,
3259abc69bb6SStephen Smalley 	 * use the in-core value under current policy.
3260abc69bb6SStephen Smalley 	 * Use the non-auditing forms of the permission checks since
3261abc69bb6SStephen Smalley 	 * getxattr may be called by unprivileged processes commonly
3262abc69bb6SStephen Smalley 	 * and lack of permission just means that we fall back to the
3263abc69bb6SStephen Smalley 	 * in-core context value, not a denial.
3264abc69bb6SStephen Smalley 	 */
326520cdef8dSPaul Moore 	isec = inode_security(inode);
3266db59000aSStephen Smalley 	if (has_cap_mac_admin(false))
3267aa8e712cSStephen Smalley 		error = security_sid_to_context_force(&selinux_state,
3268aa8e712cSStephen Smalley 						      isec->sid, &context,
3269abc69bb6SStephen Smalley 						      &size);
3270abc69bb6SStephen Smalley 	else
3271aa8e712cSStephen Smalley 		error = security_sid_to_context(&selinux_state, isec->sid,
3272aa8e712cSStephen Smalley 						&context, &size);
327342492594SDavid P. Quigley 	if (error)
327442492594SDavid P. Quigley 		return error;
327542492594SDavid P. Quigley 	error = size;
327642492594SDavid P. Quigley 	if (alloc) {
327742492594SDavid P. Quigley 		*buffer = context;
327842492594SDavid P. Quigley 		goto out_nofree;
327942492594SDavid P. Quigley 	}
328042492594SDavid P. Quigley 	kfree(context);
328142492594SDavid P. Quigley out_nofree:
328242492594SDavid P. Quigley 	return error;
32831da177e4SLinus Torvalds }
32841da177e4SLinus Torvalds 
32851da177e4SLinus Torvalds static int selinux_inode_setsecurity(struct inode *inode, const char *name,
32861da177e4SLinus Torvalds 				     const void *value, size_t size, int flags)
32871da177e4SLinus Torvalds {
32882c97165bSPaul Moore 	struct inode_security_struct *isec = inode_security_novalidate(inode);
32891da177e4SLinus Torvalds 	u32 newsid;
32901da177e4SLinus Torvalds 	int rc;
32911da177e4SLinus Torvalds 
32921da177e4SLinus Torvalds 	if (strcmp(name, XATTR_SELINUX_SUFFIX))
32931da177e4SLinus Torvalds 		return -EOPNOTSUPP;
32941da177e4SLinus Torvalds 
32951da177e4SLinus Torvalds 	if (!value || !size)
32961da177e4SLinus Torvalds 		return -EACCES;
32971da177e4SLinus Torvalds 
3298aa8e712cSStephen Smalley 	rc = security_context_to_sid(&selinux_state, value, size, &newsid,
3299aa8e712cSStephen Smalley 				     GFP_KERNEL);
33001da177e4SLinus Torvalds 	if (rc)
33011da177e4SLinus Torvalds 		return rc;
33021da177e4SLinus Torvalds 
33039287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
3304aa9c2669SDavid Quigley 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
33051da177e4SLinus Torvalds 	isec->sid = newsid;
33066f3be9f5SAndreas Gruenbacher 	isec->initialized = LABEL_INITIALIZED;
33079287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
33081da177e4SLinus Torvalds 	return 0;
33091da177e4SLinus Torvalds }
33101da177e4SLinus Torvalds 
33111da177e4SLinus Torvalds static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
33121da177e4SLinus Torvalds {
33131da177e4SLinus Torvalds 	const int len = sizeof(XATTR_NAME_SELINUX);
33141da177e4SLinus Torvalds 	if (buffer && len <= buffer_size)
33151da177e4SLinus Torvalds 		memcpy(buffer, XATTR_NAME_SELINUX, len);
33161da177e4SLinus Torvalds 	return len;
33171da177e4SLinus Torvalds }
33181da177e4SLinus Torvalds 
3319d6335d77SAndreas Gruenbacher static void selinux_inode_getsecid(struct inode *inode, u32 *secid)
3320713a04aeSAhmed S. Darwish {
3321e817c2f3SAndreas Gruenbacher 	struct inode_security_struct *isec = inode_security_novalidate(inode);
3322713a04aeSAhmed S. Darwish 	*secid = isec->sid;
3323713a04aeSAhmed S. Darwish }
3324713a04aeSAhmed S. Darwish 
332556909eb3SVivek Goyal static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
332656909eb3SVivek Goyal {
332756909eb3SVivek Goyal 	u32 sid;
332856909eb3SVivek Goyal 	struct task_security_struct *tsec;
332956909eb3SVivek Goyal 	struct cred *new_creds = *new;
333056909eb3SVivek Goyal 
333156909eb3SVivek Goyal 	if (new_creds == NULL) {
333256909eb3SVivek Goyal 		new_creds = prepare_creds();
333356909eb3SVivek Goyal 		if (!new_creds)
333456909eb3SVivek Goyal 			return -ENOMEM;
333556909eb3SVivek Goyal 	}
333656909eb3SVivek Goyal 
333756909eb3SVivek Goyal 	tsec = new_creds->security;
333856909eb3SVivek Goyal 	/* Get label from overlay inode and set it in create_sid */
333956909eb3SVivek Goyal 	selinux_inode_getsecid(d_inode(src), &sid);
334056909eb3SVivek Goyal 	tsec->create_sid = sid;
334156909eb3SVivek Goyal 	*new = new_creds;
334256909eb3SVivek Goyal 	return 0;
334356909eb3SVivek Goyal }
334456909eb3SVivek Goyal 
334519472b69SVivek Goyal static int selinux_inode_copy_up_xattr(const char *name)
334619472b69SVivek Goyal {
334719472b69SVivek Goyal 	/* The copy_up hook above sets the initial context on an inode, but we
334819472b69SVivek Goyal 	 * don't then want to overwrite it by blindly copying all the lower
334919472b69SVivek Goyal 	 * xattrs up.  Instead, we have to filter out SELinux-related xattrs.
335019472b69SVivek Goyal 	 */
335119472b69SVivek Goyal 	if (strcmp(name, XATTR_NAME_SELINUX) == 0)
335219472b69SVivek Goyal 		return 1; /* Discard */
335319472b69SVivek Goyal 	/*
335419472b69SVivek Goyal 	 * Any other attribute apart from SELINUX is not claimed, supported
335519472b69SVivek Goyal 	 * by selinux.
335619472b69SVivek Goyal 	 */
335719472b69SVivek Goyal 	return -EOPNOTSUPP;
335819472b69SVivek Goyal }
335919472b69SVivek Goyal 
33601da177e4SLinus Torvalds /* file security operations */
33611da177e4SLinus Torvalds 
3362788e7dd4SYuichi Nakamura static int selinux_revalidate_file_permission(struct file *file, int mask)
33631da177e4SLinus Torvalds {
336488e67f3bSDavid Howells 	const struct cred *cred = current_cred();
3365496ad9aaSAl Viro 	struct inode *inode = file_inode(file);
33661da177e4SLinus Torvalds 
33671da177e4SLinus Torvalds 	/* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
33681da177e4SLinus Torvalds 	if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
33691da177e4SLinus Torvalds 		mask |= MAY_APPEND;
33701da177e4SLinus Torvalds 
3371389fb800SPaul Moore 	return file_has_perm(cred, file,
33721da177e4SLinus Torvalds 			     file_mask_to_av(inode->i_mode, mask));
33731da177e4SLinus Torvalds }
33741da177e4SLinus Torvalds 
3375788e7dd4SYuichi Nakamura static int selinux_file_permission(struct file *file, int mask)
3376788e7dd4SYuichi Nakamura {
3377496ad9aaSAl Viro 	struct inode *inode = file_inode(file);
337820dda18bSStephen Smalley 	struct file_security_struct *fsec = file->f_security;
3379b197367eSAndreas Gruenbacher 	struct inode_security_struct *isec;
338020dda18bSStephen Smalley 	u32 sid = current_sid();
338120dda18bSStephen Smalley 
3382389fb800SPaul Moore 	if (!mask)
3383788e7dd4SYuichi Nakamura 		/* No permission to check.  Existence test. */
3384788e7dd4SYuichi Nakamura 		return 0;
3385788e7dd4SYuichi Nakamura 
3386b197367eSAndreas Gruenbacher 	isec = inode_security(inode);
338720dda18bSStephen Smalley 	if (sid == fsec->sid && fsec->isid == isec->sid &&
33886b6bc620SStephen Smalley 	    fsec->pseqno == avc_policy_seqno(&selinux_state))
338983d49856SEric Paris 		/* No change since file_open check. */
339020dda18bSStephen Smalley 		return 0;
339120dda18bSStephen Smalley 
3392788e7dd4SYuichi Nakamura 	return selinux_revalidate_file_permission(file, mask);
3393788e7dd4SYuichi Nakamura }
3394788e7dd4SYuichi Nakamura 
33951da177e4SLinus Torvalds static int selinux_file_alloc_security(struct file *file)
33961da177e4SLinus Torvalds {
33971da177e4SLinus Torvalds 	return file_alloc_security(file);
33981da177e4SLinus Torvalds }
33991da177e4SLinus Torvalds 
34001da177e4SLinus Torvalds static void selinux_file_free_security(struct file *file)
34011da177e4SLinus Torvalds {
34021da177e4SLinus Torvalds 	file_free_security(file);
34031da177e4SLinus Torvalds }
34041da177e4SLinus Torvalds 
3405fa1aa143SJeff Vander Stoep /*
3406fa1aa143SJeff Vander Stoep  * Check whether a task has the ioctl permission and cmd
3407fa1aa143SJeff Vander Stoep  * operation to an inode.
3408fa1aa143SJeff Vander Stoep  */
34091d2a168aSGeliang Tang static int ioctl_has_perm(const struct cred *cred, struct file *file,
3410fa1aa143SJeff Vander Stoep 		u32 requested, u16 cmd)
3411fa1aa143SJeff Vander Stoep {
3412fa1aa143SJeff Vander Stoep 	struct common_audit_data ad;
3413fa1aa143SJeff Vander Stoep 	struct file_security_struct *fsec = file->f_security;
3414fa1aa143SJeff Vander Stoep 	struct inode *inode = file_inode(file);
341520cdef8dSPaul Moore 	struct inode_security_struct *isec;
3416fa1aa143SJeff Vander Stoep 	struct lsm_ioctlop_audit ioctl;
3417fa1aa143SJeff Vander Stoep 	u32 ssid = cred_sid(cred);
3418fa1aa143SJeff Vander Stoep 	int rc;
3419fa1aa143SJeff Vander Stoep 	u8 driver = cmd >> 8;
3420fa1aa143SJeff Vander Stoep 	u8 xperm = cmd & 0xff;
3421fa1aa143SJeff Vander Stoep 
3422fa1aa143SJeff Vander Stoep 	ad.type = LSM_AUDIT_DATA_IOCTL_OP;
3423fa1aa143SJeff Vander Stoep 	ad.u.op = &ioctl;
3424fa1aa143SJeff Vander Stoep 	ad.u.op->cmd = cmd;
3425fa1aa143SJeff Vander Stoep 	ad.u.op->path = file->f_path;
3426fa1aa143SJeff Vander Stoep 
3427fa1aa143SJeff Vander Stoep 	if (ssid != fsec->sid) {
34286b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
34296b6bc620SStephen Smalley 				  ssid, fsec->sid,
3430fa1aa143SJeff Vander Stoep 				SECCLASS_FD,
3431fa1aa143SJeff Vander Stoep 				FD__USE,
3432fa1aa143SJeff Vander Stoep 				&ad);
3433fa1aa143SJeff Vander Stoep 		if (rc)
3434fa1aa143SJeff Vander Stoep 			goto out;
3435fa1aa143SJeff Vander Stoep 	}
3436fa1aa143SJeff Vander Stoep 
3437fa1aa143SJeff Vander Stoep 	if (unlikely(IS_PRIVATE(inode)))
3438fa1aa143SJeff Vander Stoep 		return 0;
3439fa1aa143SJeff Vander Stoep 
344020cdef8dSPaul Moore 	isec = inode_security(inode);
34416b6bc620SStephen Smalley 	rc = avc_has_extended_perms(&selinux_state,
34426b6bc620SStephen Smalley 				    ssid, isec->sid, isec->sclass,
3443fa1aa143SJeff Vander Stoep 				    requested, driver, xperm, &ad);
3444fa1aa143SJeff Vander Stoep out:
3445fa1aa143SJeff Vander Stoep 	return rc;
3446fa1aa143SJeff Vander Stoep }
3447fa1aa143SJeff Vander Stoep 
34481da177e4SLinus Torvalds static int selinux_file_ioctl(struct file *file, unsigned int cmd,
34491da177e4SLinus Torvalds 			      unsigned long arg)
34501da177e4SLinus Torvalds {
345188e67f3bSDavid Howells 	const struct cred *cred = current_cred();
34520b24dcb7SEric Paris 	int error = 0;
34531da177e4SLinus Torvalds 
34540b24dcb7SEric Paris 	switch (cmd) {
34550b24dcb7SEric Paris 	case FIONREAD:
34560b24dcb7SEric Paris 	/* fall through */
34570b24dcb7SEric Paris 	case FIBMAP:
34580b24dcb7SEric Paris 	/* fall through */
34590b24dcb7SEric Paris 	case FIGETBSZ:
34600b24dcb7SEric Paris 	/* fall through */
34612f99c369SAl Viro 	case FS_IOC_GETFLAGS:
34620b24dcb7SEric Paris 	/* fall through */
34632f99c369SAl Viro 	case FS_IOC_GETVERSION:
34640b24dcb7SEric Paris 		error = file_has_perm(cred, file, FILE__GETATTR);
34650b24dcb7SEric Paris 		break;
34661da177e4SLinus Torvalds 
34672f99c369SAl Viro 	case FS_IOC_SETFLAGS:
34680b24dcb7SEric Paris 	/* fall through */
34692f99c369SAl Viro 	case FS_IOC_SETVERSION:
34700b24dcb7SEric Paris 		error = file_has_perm(cred, file, FILE__SETATTR);
34710b24dcb7SEric Paris 		break;
34720b24dcb7SEric Paris 
34730b24dcb7SEric Paris 	/* sys_ioctl() checks */
34740b24dcb7SEric Paris 	case FIONBIO:
34750b24dcb7SEric Paris 	/* fall through */
34760b24dcb7SEric Paris 	case FIOASYNC:
34770b24dcb7SEric Paris 		error = file_has_perm(cred, file, 0);
34780b24dcb7SEric Paris 		break;
34790b24dcb7SEric Paris 
34800b24dcb7SEric Paris 	case KDSKBENT:
34810b24dcb7SEric Paris 	case KDSKBSENT:
34826a9de491SEric Paris 		error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
34838e4ff6f2SStephen Smalley 					    SECURITY_CAP_AUDIT, true);
34840b24dcb7SEric Paris 		break;
34850b24dcb7SEric Paris 
34860b24dcb7SEric Paris 	/* default case assumes that the command will go
34870b24dcb7SEric Paris 	 * to the file's ioctl() function.
34880b24dcb7SEric Paris 	 */
34890b24dcb7SEric Paris 	default:
3490fa1aa143SJeff Vander Stoep 		error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
34910b24dcb7SEric Paris 	}
34920b24dcb7SEric Paris 	return error;
34931da177e4SLinus Torvalds }
34941da177e4SLinus Torvalds 
3495fcaaade1SStephen Smalley static int default_noexec;
3496fcaaade1SStephen Smalley 
34971da177e4SLinus Torvalds static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
34981da177e4SLinus Torvalds {
349988e67f3bSDavid Howells 	const struct cred *cred = current_cred();
3500be0554c9SStephen Smalley 	u32 sid = cred_sid(cred);
3501d84f4f99SDavid Howells 	int rc = 0;
350288e67f3bSDavid Howells 
3503fcaaade1SStephen Smalley 	if (default_noexec &&
3504892e8cacSStephen Smalley 	    (prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) ||
3505892e8cacSStephen Smalley 				   (!shared && (prot & PROT_WRITE)))) {
35061da177e4SLinus Torvalds 		/*
35071da177e4SLinus Torvalds 		 * We are making executable an anonymous mapping or a
35081da177e4SLinus Torvalds 		 * private file mapping that will also be writable.
35091da177e4SLinus Torvalds 		 * This has an additional check.
35101da177e4SLinus Torvalds 		 */
35116b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
35126b6bc620SStephen Smalley 				  sid, sid, SECCLASS_PROCESS,
3513be0554c9SStephen Smalley 				  PROCESS__EXECMEM, NULL);
35141da177e4SLinus Torvalds 		if (rc)
3515d84f4f99SDavid Howells 			goto error;
35161da177e4SLinus Torvalds 	}
35171da177e4SLinus Torvalds 
35181da177e4SLinus Torvalds 	if (file) {
35191da177e4SLinus Torvalds 		/* read access is always possible with a mapping */
35201da177e4SLinus Torvalds 		u32 av = FILE__READ;
35211da177e4SLinus Torvalds 
35221da177e4SLinus Torvalds 		/* write access only matters if the mapping is shared */
35231da177e4SLinus Torvalds 		if (shared && (prot & PROT_WRITE))
35241da177e4SLinus Torvalds 			av |= FILE__WRITE;
35251da177e4SLinus Torvalds 
35261da177e4SLinus Torvalds 		if (prot & PROT_EXEC)
35271da177e4SLinus Torvalds 			av |= FILE__EXECUTE;
35281da177e4SLinus Torvalds 
352988e67f3bSDavid Howells 		return file_has_perm(cred, file, av);
35301da177e4SLinus Torvalds 	}
3531d84f4f99SDavid Howells 
3532d84f4f99SDavid Howells error:
3533d84f4f99SDavid Howells 	return rc;
35341da177e4SLinus Torvalds }
35351da177e4SLinus Torvalds 
3536e5467859SAl Viro static int selinux_mmap_addr(unsigned long addr)
35371da177e4SLinus Torvalds {
3538b1d9e6b0SCasey Schaufler 	int rc = 0;
353998883bfdSPaul Moore 
354098883bfdSPaul Moore 	if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
354198883bfdSPaul Moore 		u32 sid = current_sid();
35426b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
35436b6bc620SStephen Smalley 				  sid, sid, SECCLASS_MEMPROTECT,
354498883bfdSPaul Moore 				  MEMPROTECT__MMAP_ZERO, NULL);
354598883bfdSPaul Moore 	}
354698883bfdSPaul Moore 
354798883bfdSPaul Moore 	return rc;
3548e5467859SAl Viro }
35491da177e4SLinus Torvalds 
3550e5467859SAl Viro static int selinux_mmap_file(struct file *file, unsigned long reqprot,
3551e5467859SAl Viro 			     unsigned long prot, unsigned long flags)
3552e5467859SAl Viro {
35533ba4bf5fSStephen Smalley 	struct common_audit_data ad;
35543ba4bf5fSStephen Smalley 	int rc;
35553ba4bf5fSStephen Smalley 
35563ba4bf5fSStephen Smalley 	if (file) {
35573ba4bf5fSStephen Smalley 		ad.type = LSM_AUDIT_DATA_FILE;
35583ba4bf5fSStephen Smalley 		ad.u.file = file;
35593ba4bf5fSStephen Smalley 		rc = inode_has_perm(current_cred(), file_inode(file),
35603ba4bf5fSStephen Smalley 				    FILE__MAP, &ad);
35613ba4bf5fSStephen Smalley 		if (rc)
35623ba4bf5fSStephen Smalley 			return rc;
35633ba4bf5fSStephen Smalley 	}
35643ba4bf5fSStephen Smalley 
3565aa8e712cSStephen Smalley 	if (selinux_state.checkreqprot)
35661da177e4SLinus Torvalds 		prot = reqprot;
35671da177e4SLinus Torvalds 
35681da177e4SLinus Torvalds 	return file_map_prot_check(file, prot,
35691da177e4SLinus Torvalds 				   (flags & MAP_TYPE) == MAP_SHARED);
35701da177e4SLinus Torvalds }
35711da177e4SLinus Torvalds 
35721da177e4SLinus Torvalds static int selinux_file_mprotect(struct vm_area_struct *vma,
35731da177e4SLinus Torvalds 				 unsigned long reqprot,
35741da177e4SLinus Torvalds 				 unsigned long prot)
35751da177e4SLinus Torvalds {
357688e67f3bSDavid Howells 	const struct cred *cred = current_cred();
3577be0554c9SStephen Smalley 	u32 sid = cred_sid(cred);
35781da177e4SLinus Torvalds 
3579aa8e712cSStephen Smalley 	if (selinux_state.checkreqprot)
35801da177e4SLinus Torvalds 		prot = reqprot;
35811da177e4SLinus Torvalds 
3582fcaaade1SStephen Smalley 	if (default_noexec &&
3583fcaaade1SStephen Smalley 	    (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
3584d541bbeeSJames Morris 		int rc = 0;
3585db4c9641SStephen Smalley 		if (vma->vm_start >= vma->vm_mm->start_brk &&
3586db4c9641SStephen Smalley 		    vma->vm_end <= vma->vm_mm->brk) {
35876b6bc620SStephen Smalley 			rc = avc_has_perm(&selinux_state,
35886b6bc620SStephen Smalley 					  sid, sid, SECCLASS_PROCESS,
3589be0554c9SStephen Smalley 					  PROCESS__EXECHEAP, NULL);
3590db4c9641SStephen Smalley 		} else if (!vma->vm_file &&
3591c2316dbfSStephen Smalley 			   ((vma->vm_start <= vma->vm_mm->start_stack &&
3592c2316dbfSStephen Smalley 			     vma->vm_end >= vma->vm_mm->start_stack) ||
3593d17af505SAndy Lutomirski 			    vma_is_stack_for_current(vma))) {
35946b6bc620SStephen Smalley 			rc = avc_has_perm(&selinux_state,
35956b6bc620SStephen Smalley 					  sid, sid, SECCLASS_PROCESS,
3596be0554c9SStephen Smalley 					  PROCESS__EXECSTACK, NULL);
3597db4c9641SStephen Smalley 		} else if (vma->vm_file && vma->anon_vma) {
3598db4c9641SStephen Smalley 			/*
3599db4c9641SStephen Smalley 			 * We are making executable a file mapping that has
3600db4c9641SStephen Smalley 			 * had some COW done. Since pages might have been
3601db4c9641SStephen Smalley 			 * written, check ability to execute the possibly
3602db4c9641SStephen Smalley 			 * modified content.  This typically should only
3603db4c9641SStephen Smalley 			 * occur for text relocations.
3604db4c9641SStephen Smalley 			 */
3605d84f4f99SDavid Howells 			rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
3606db4c9641SStephen Smalley 		}
36076b992197SLorenzo Hernandez García-Hierro 		if (rc)
36086b992197SLorenzo Hernandez García-Hierro 			return rc;
36096b992197SLorenzo Hernandez García-Hierro 	}
36101da177e4SLinus Torvalds 
36111da177e4SLinus Torvalds 	return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
36121da177e4SLinus Torvalds }
36131da177e4SLinus Torvalds 
36141da177e4SLinus Torvalds static int selinux_file_lock(struct file *file, unsigned int cmd)
36151da177e4SLinus Torvalds {
361688e67f3bSDavid Howells 	const struct cred *cred = current_cred();
361788e67f3bSDavid Howells 
361888e67f3bSDavid Howells 	return file_has_perm(cred, file, FILE__LOCK);
36191da177e4SLinus Torvalds }
36201da177e4SLinus Torvalds 
36211da177e4SLinus Torvalds static int selinux_file_fcntl(struct file *file, unsigned int cmd,
36221da177e4SLinus Torvalds 			      unsigned long arg)
36231da177e4SLinus Torvalds {
362488e67f3bSDavid Howells 	const struct cred *cred = current_cred();
36251da177e4SLinus Torvalds 	int err = 0;
36261da177e4SLinus Torvalds 
36271da177e4SLinus Torvalds 	switch (cmd) {
36281da177e4SLinus Torvalds 	case F_SETFL:
36291da177e4SLinus Torvalds 		if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
363088e67f3bSDavid Howells 			err = file_has_perm(cred, file, FILE__WRITE);
36311da177e4SLinus Torvalds 			break;
36321da177e4SLinus Torvalds 		}
36331da177e4SLinus Torvalds 		/* fall through */
36341da177e4SLinus Torvalds 	case F_SETOWN:
36351da177e4SLinus Torvalds 	case F_SETSIG:
36361da177e4SLinus Torvalds 	case F_GETFL:
36371da177e4SLinus Torvalds 	case F_GETOWN:
36381da177e4SLinus Torvalds 	case F_GETSIG:
36391d151c33SCyrill Gorcunov 	case F_GETOWNER_UIDS:
36401da177e4SLinus Torvalds 		/* Just check FD__USE permission */
364188e67f3bSDavid Howells 		err = file_has_perm(cred, file, 0);
36421da177e4SLinus Torvalds 		break;
36431da177e4SLinus Torvalds 	case F_GETLK:
36441da177e4SLinus Torvalds 	case F_SETLK:
36451da177e4SLinus Torvalds 	case F_SETLKW:
36460d3f7a2dSJeff Layton 	case F_OFD_GETLK:
36470d3f7a2dSJeff Layton 	case F_OFD_SETLK:
36480d3f7a2dSJeff Layton 	case F_OFD_SETLKW:
36491da177e4SLinus Torvalds #if BITS_PER_LONG == 32
36501da177e4SLinus Torvalds 	case F_GETLK64:
36511da177e4SLinus Torvalds 	case F_SETLK64:
36521da177e4SLinus Torvalds 	case F_SETLKW64:
36531da177e4SLinus Torvalds #endif
365488e67f3bSDavid Howells 		err = file_has_perm(cred, file, FILE__LOCK);
36551da177e4SLinus Torvalds 		break;
36561da177e4SLinus Torvalds 	}
36571da177e4SLinus Torvalds 
36581da177e4SLinus Torvalds 	return err;
36591da177e4SLinus Torvalds }
36601da177e4SLinus Torvalds 
3661e0b93eddSJeff Layton static void selinux_file_set_fowner(struct file *file)
36621da177e4SLinus Torvalds {
36631da177e4SLinus Torvalds 	struct file_security_struct *fsec;
36641da177e4SLinus Torvalds 
36651da177e4SLinus Torvalds 	fsec = file->f_security;
3666275bb41eSDavid Howells 	fsec->fown_sid = current_sid();
36671da177e4SLinus Torvalds }
36681da177e4SLinus Torvalds 
36691da177e4SLinus Torvalds static int selinux_file_send_sigiotask(struct task_struct *tsk,
36701da177e4SLinus Torvalds 				       struct fown_struct *fown, int signum)
36711da177e4SLinus Torvalds {
36721da177e4SLinus Torvalds 	struct file *file;
367365c90bcaSStephen Smalley 	u32 sid = task_sid(tsk);
36741da177e4SLinus Torvalds 	u32 perm;
36751da177e4SLinus Torvalds 	struct file_security_struct *fsec;
36761da177e4SLinus Torvalds 
36771da177e4SLinus Torvalds 	/* struct fown_struct is never outside the context of a struct file */
3678b385a144SRobert P. J. Day 	file = container_of(fown, struct file, f_owner);
36791da177e4SLinus Torvalds 
36801da177e4SLinus Torvalds 	fsec = file->f_security;
36811da177e4SLinus Torvalds 
36821da177e4SLinus Torvalds 	if (!signum)
36831da177e4SLinus Torvalds 		perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
36841da177e4SLinus Torvalds 	else
36851da177e4SLinus Torvalds 		perm = signal_to_av(signum);
36861da177e4SLinus Torvalds 
36876b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
36886b6bc620SStephen Smalley 			    fsec->fown_sid, sid,
36891da177e4SLinus Torvalds 			    SECCLASS_PROCESS, perm, NULL);
36901da177e4SLinus Torvalds }
36911da177e4SLinus Torvalds 
36921da177e4SLinus Torvalds static int selinux_file_receive(struct file *file)
36931da177e4SLinus Torvalds {
369488e67f3bSDavid Howells 	const struct cred *cred = current_cred();
369588e67f3bSDavid Howells 
369688e67f3bSDavid Howells 	return file_has_perm(cred, file, file_to_av(file));
36971da177e4SLinus Torvalds }
36981da177e4SLinus Torvalds 
369994817692SAl Viro static int selinux_file_open(struct file *file)
3700788e7dd4SYuichi Nakamura {
3701788e7dd4SYuichi Nakamura 	struct file_security_struct *fsec;
3702788e7dd4SYuichi Nakamura 	struct inode_security_struct *isec;
3703d84f4f99SDavid Howells 
3704788e7dd4SYuichi Nakamura 	fsec = file->f_security;
370583da53c5SAndreas Gruenbacher 	isec = inode_security(file_inode(file));
3706788e7dd4SYuichi Nakamura 	/*
3707788e7dd4SYuichi Nakamura 	 * Save inode label and policy sequence number
3708788e7dd4SYuichi Nakamura 	 * at open-time so that selinux_file_permission
3709788e7dd4SYuichi Nakamura 	 * can determine whether revalidation is necessary.
3710788e7dd4SYuichi Nakamura 	 * Task label is already saved in the file security
3711788e7dd4SYuichi Nakamura 	 * struct as its SID.
3712788e7dd4SYuichi Nakamura 	 */
3713788e7dd4SYuichi Nakamura 	fsec->isid = isec->sid;
37146b6bc620SStephen Smalley 	fsec->pseqno = avc_policy_seqno(&selinux_state);
3715788e7dd4SYuichi Nakamura 	/*
3716788e7dd4SYuichi Nakamura 	 * Since the inode label or policy seqno may have changed
3717788e7dd4SYuichi Nakamura 	 * between the selinux_inode_permission check and the saving
3718788e7dd4SYuichi Nakamura 	 * of state above, recheck that access is still permitted.
3719788e7dd4SYuichi Nakamura 	 * Otherwise, access might never be revalidated against the
3720788e7dd4SYuichi Nakamura 	 * new inode label or new policy.
3721788e7dd4SYuichi Nakamura 	 * This check is not redundant - do not remove.
3722788e7dd4SYuichi Nakamura 	 */
372394817692SAl Viro 	return file_path_has_perm(file->f_cred, file, open_file_to_av(file));
3724788e7dd4SYuichi Nakamura }
3725788e7dd4SYuichi Nakamura 
37261da177e4SLinus Torvalds /* task security operations */
37271da177e4SLinus Torvalds 
3728a79be238STetsuo Handa static int selinux_task_alloc(struct task_struct *task,
3729a79be238STetsuo Handa 			      unsigned long clone_flags)
37301da177e4SLinus Torvalds {
3731be0554c9SStephen Smalley 	u32 sid = current_sid();
3732be0554c9SStephen Smalley 
37336b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
37346b6bc620SStephen Smalley 			    sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
37351da177e4SLinus Torvalds }
37361da177e4SLinus Torvalds 
3737f1752eecSDavid Howells /*
3738ee18d64cSDavid Howells  * allocate the SELinux part of blank credentials
3739ee18d64cSDavid Howells  */
3740ee18d64cSDavid Howells static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp)
3741ee18d64cSDavid Howells {
3742ee18d64cSDavid Howells 	struct task_security_struct *tsec;
3743ee18d64cSDavid Howells 
3744ee18d64cSDavid Howells 	tsec = kzalloc(sizeof(struct task_security_struct), gfp);
3745ee18d64cSDavid Howells 	if (!tsec)
3746ee18d64cSDavid Howells 		return -ENOMEM;
3747ee18d64cSDavid Howells 
3748ee18d64cSDavid Howells 	cred->security = tsec;
3749ee18d64cSDavid Howells 	return 0;
3750ee18d64cSDavid Howells }
3751ee18d64cSDavid Howells 
3752ee18d64cSDavid Howells /*
3753f1752eecSDavid Howells  * detach and free the LSM part of a set of credentials
3754f1752eecSDavid Howells  */
3755f1752eecSDavid Howells static void selinux_cred_free(struct cred *cred)
37561da177e4SLinus Torvalds {
3757f1752eecSDavid Howells 	struct task_security_struct *tsec = cred->security;
3758e0e81739SDavid Howells 
37592edeaa34STetsuo Handa 	/*
37602edeaa34STetsuo Handa 	 * cred->security == NULL if security_cred_alloc_blank() or
37612edeaa34STetsuo Handa 	 * security_prepare_creds() returned an error.
37622edeaa34STetsuo Handa 	 */
37632edeaa34STetsuo Handa 	BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE);
3764e0e81739SDavid Howells 	cred->security = (void *) 0x7UL;
3765f1752eecSDavid Howells 	kfree(tsec);
37661da177e4SLinus Torvalds }
37671da177e4SLinus Torvalds 
3768d84f4f99SDavid Howells /*
3769d84f4f99SDavid Howells  * prepare a new set of credentials for modification
3770d84f4f99SDavid Howells  */
3771d84f4f99SDavid Howells static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3772d84f4f99SDavid Howells 				gfp_t gfp)
3773d84f4f99SDavid Howells {
3774d84f4f99SDavid Howells 	const struct task_security_struct *old_tsec;
3775d84f4f99SDavid Howells 	struct task_security_struct *tsec;
3776d84f4f99SDavid Howells 
3777d84f4f99SDavid Howells 	old_tsec = old->security;
3778d84f4f99SDavid Howells 
3779d84f4f99SDavid Howells 	tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp);
3780d84f4f99SDavid Howells 	if (!tsec)
3781d84f4f99SDavid Howells 		return -ENOMEM;
3782d84f4f99SDavid Howells 
3783d84f4f99SDavid Howells 	new->security = tsec;
3784d84f4f99SDavid Howells 	return 0;
3785d84f4f99SDavid Howells }
3786d84f4f99SDavid Howells 
3787d84f4f99SDavid Howells /*
3788ee18d64cSDavid Howells  * transfer the SELinux data to a blank set of creds
3789ee18d64cSDavid Howells  */
3790ee18d64cSDavid Howells static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3791ee18d64cSDavid Howells {
3792ee18d64cSDavid Howells 	const struct task_security_struct *old_tsec = old->security;
3793ee18d64cSDavid Howells 	struct task_security_struct *tsec = new->security;
3794ee18d64cSDavid Howells 
3795ee18d64cSDavid Howells 	*tsec = *old_tsec;
3796ee18d64cSDavid Howells }
3797ee18d64cSDavid Howells 
37983ec30113SMatthew Garrett static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
37993ec30113SMatthew Garrett {
38003ec30113SMatthew Garrett 	*secid = cred_sid(c);
38013ec30113SMatthew Garrett }
38023ec30113SMatthew Garrett 
3803ee18d64cSDavid Howells /*
38043a3b7ce9SDavid Howells  * set the security data for a kernel service
38053a3b7ce9SDavid Howells  * - all the creation contexts are set to unlabelled
38063a3b7ce9SDavid Howells  */
38073a3b7ce9SDavid Howells static int selinux_kernel_act_as(struct cred *new, u32 secid)
38083a3b7ce9SDavid Howells {
38093a3b7ce9SDavid Howells 	struct task_security_struct *tsec = new->security;
38103a3b7ce9SDavid Howells 	u32 sid = current_sid();
38113a3b7ce9SDavid Howells 	int ret;
38123a3b7ce9SDavid Howells 
38136b6bc620SStephen Smalley 	ret = avc_has_perm(&selinux_state,
38146b6bc620SStephen Smalley 			   sid, secid,
38153a3b7ce9SDavid Howells 			   SECCLASS_KERNEL_SERVICE,
38163a3b7ce9SDavid Howells 			   KERNEL_SERVICE__USE_AS_OVERRIDE,
38173a3b7ce9SDavid Howells 			   NULL);
38183a3b7ce9SDavid Howells 	if (ret == 0) {
38193a3b7ce9SDavid Howells 		tsec->sid = secid;
38203a3b7ce9SDavid Howells 		tsec->create_sid = 0;
38213a3b7ce9SDavid Howells 		tsec->keycreate_sid = 0;
38223a3b7ce9SDavid Howells 		tsec->sockcreate_sid = 0;
38233a3b7ce9SDavid Howells 	}
38243a3b7ce9SDavid Howells 	return ret;
38253a3b7ce9SDavid Howells }
38263a3b7ce9SDavid Howells 
38273a3b7ce9SDavid Howells /*
38283a3b7ce9SDavid Howells  * set the file creation context in a security record to the same as the
38293a3b7ce9SDavid Howells  * objective context of the specified inode
38303a3b7ce9SDavid Howells  */
38313a3b7ce9SDavid Howells static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
38323a3b7ce9SDavid Howells {
383383da53c5SAndreas Gruenbacher 	struct inode_security_struct *isec = inode_security(inode);
38343a3b7ce9SDavid Howells 	struct task_security_struct *tsec = new->security;
38353a3b7ce9SDavid Howells 	u32 sid = current_sid();
38363a3b7ce9SDavid Howells 	int ret;
38373a3b7ce9SDavid Howells 
38386b6bc620SStephen Smalley 	ret = avc_has_perm(&selinux_state,
38396b6bc620SStephen Smalley 			   sid, isec->sid,
38403a3b7ce9SDavid Howells 			   SECCLASS_KERNEL_SERVICE,
38413a3b7ce9SDavid Howells 			   KERNEL_SERVICE__CREATE_FILES_AS,
38423a3b7ce9SDavid Howells 			   NULL);
38433a3b7ce9SDavid Howells 
38443a3b7ce9SDavid Howells 	if (ret == 0)
38453a3b7ce9SDavid Howells 		tsec->create_sid = isec->sid;
3846ef57471aSDavid Howells 	return ret;
38473a3b7ce9SDavid Howells }
38483a3b7ce9SDavid Howells 
3849dd8dbf2eSEric Paris static int selinux_kernel_module_request(char *kmod_name)
385025354c4fSEric Paris {
3851dd8dbf2eSEric Paris 	struct common_audit_data ad;
3852dd8dbf2eSEric Paris 
385350c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_KMOD;
3854dd8dbf2eSEric Paris 	ad.u.kmod_name = kmod_name;
3855dd8dbf2eSEric Paris 
38566b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
38576b6bc620SStephen Smalley 			    current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
3858dd8dbf2eSEric Paris 			    SYSTEM__MODULE_REQUEST, &ad);
385925354c4fSEric Paris }
386025354c4fSEric Paris 
386161d612eaSJeff Vander Stoep static int selinux_kernel_module_from_file(struct file *file)
386261d612eaSJeff Vander Stoep {
386361d612eaSJeff Vander Stoep 	struct common_audit_data ad;
386461d612eaSJeff Vander Stoep 	struct inode_security_struct *isec;
386561d612eaSJeff Vander Stoep 	struct file_security_struct *fsec;
386661d612eaSJeff Vander Stoep 	u32 sid = current_sid();
386761d612eaSJeff Vander Stoep 	int rc;
386861d612eaSJeff Vander Stoep 
386961d612eaSJeff Vander Stoep 	/* init_module */
387061d612eaSJeff Vander Stoep 	if (file == NULL)
38716b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
38726b6bc620SStephen Smalley 				    sid, sid, SECCLASS_SYSTEM,
387361d612eaSJeff Vander Stoep 					SYSTEM__MODULE_LOAD, NULL);
387461d612eaSJeff Vander Stoep 
387561d612eaSJeff Vander Stoep 	/* finit_module */
387620cdef8dSPaul Moore 
387743af5de7SVivek Goyal 	ad.type = LSM_AUDIT_DATA_FILE;
387843af5de7SVivek Goyal 	ad.u.file = file;
387961d612eaSJeff Vander Stoep 
388061d612eaSJeff Vander Stoep 	fsec = file->f_security;
388161d612eaSJeff Vander Stoep 	if (sid != fsec->sid) {
38826b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
38836b6bc620SStephen Smalley 				  sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
388461d612eaSJeff Vander Stoep 		if (rc)
388561d612eaSJeff Vander Stoep 			return rc;
388661d612eaSJeff Vander Stoep 	}
388761d612eaSJeff Vander Stoep 
388820cdef8dSPaul Moore 	isec = inode_security(file_inode(file));
38896b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
38906b6bc620SStephen Smalley 			    sid, isec->sid, SECCLASS_SYSTEM,
389161d612eaSJeff Vander Stoep 				SYSTEM__MODULE_LOAD, &ad);
389261d612eaSJeff Vander Stoep }
389361d612eaSJeff Vander Stoep 
389461d612eaSJeff Vander Stoep static int selinux_kernel_read_file(struct file *file,
389561d612eaSJeff Vander Stoep 				    enum kernel_read_file_id id)
389661d612eaSJeff Vander Stoep {
389761d612eaSJeff Vander Stoep 	int rc = 0;
389861d612eaSJeff Vander Stoep 
389961d612eaSJeff Vander Stoep 	switch (id) {
390061d612eaSJeff Vander Stoep 	case READING_MODULE:
390161d612eaSJeff Vander Stoep 		rc = selinux_kernel_module_from_file(file);
390261d612eaSJeff Vander Stoep 		break;
390361d612eaSJeff Vander Stoep 	default:
390461d612eaSJeff Vander Stoep 		break;
390561d612eaSJeff Vander Stoep 	}
390661d612eaSJeff Vander Stoep 
390761d612eaSJeff Vander Stoep 	return rc;
390861d612eaSJeff Vander Stoep }
390961d612eaSJeff Vander Stoep 
3910c77b8cdfSMimi Zohar static int selinux_kernel_load_data(enum kernel_load_data_id id)
3911c77b8cdfSMimi Zohar {
3912c77b8cdfSMimi Zohar 	int rc = 0;
3913c77b8cdfSMimi Zohar 
3914c77b8cdfSMimi Zohar 	switch (id) {
3915c77b8cdfSMimi Zohar 	case LOADING_MODULE:
3916c77b8cdfSMimi Zohar 		rc = selinux_kernel_module_from_file(NULL);
3917c77b8cdfSMimi Zohar 	default:
3918c77b8cdfSMimi Zohar 		break;
3919c77b8cdfSMimi Zohar 	}
3920c77b8cdfSMimi Zohar 
3921c77b8cdfSMimi Zohar 	return rc;
3922c77b8cdfSMimi Zohar }
3923c77b8cdfSMimi Zohar 
39241da177e4SLinus Torvalds static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
39251da177e4SLinus Torvalds {
39266b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39276b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
3928be0554c9SStephen Smalley 			    PROCESS__SETPGID, NULL);
39291da177e4SLinus Torvalds }
39301da177e4SLinus Torvalds 
39311da177e4SLinus Torvalds static int selinux_task_getpgid(struct task_struct *p)
39321da177e4SLinus Torvalds {
39336b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39346b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
3935be0554c9SStephen Smalley 			    PROCESS__GETPGID, NULL);
39361da177e4SLinus Torvalds }
39371da177e4SLinus Torvalds 
39381da177e4SLinus Torvalds static int selinux_task_getsid(struct task_struct *p)
39391da177e4SLinus Torvalds {
39406b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39416b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
3942be0554c9SStephen Smalley 			    PROCESS__GETSESSION, NULL);
39431da177e4SLinus Torvalds }
39441da177e4SLinus Torvalds 
3945f9008e4cSDavid Quigley static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
3946f9008e4cSDavid Quigley {
3947275bb41eSDavid Howells 	*secid = task_sid(p);
3948f9008e4cSDavid Quigley }
3949f9008e4cSDavid Quigley 
39501da177e4SLinus Torvalds static int selinux_task_setnice(struct task_struct *p, int nice)
39511da177e4SLinus Torvalds {
39526b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39536b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
3954be0554c9SStephen Smalley 			    PROCESS__SETSCHED, NULL);
39551da177e4SLinus Torvalds }
39561da177e4SLinus Torvalds 
395703e68060SJames Morris static int selinux_task_setioprio(struct task_struct *p, int ioprio)
395803e68060SJames Morris {
39596b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39606b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
3961be0554c9SStephen Smalley 			    PROCESS__SETSCHED, NULL);
396203e68060SJames Morris }
396303e68060SJames Morris 
3964a1836a42SDavid Quigley static int selinux_task_getioprio(struct task_struct *p)
3965a1836a42SDavid Quigley {
39666b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39676b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
3968be0554c9SStephen Smalley 			    PROCESS__GETSCHED, NULL);
3969a1836a42SDavid Quigley }
3970a1836a42SDavid Quigley 
39714298555dSCorentin LABBE static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred,
3972791ec491SStephen Smalley 				unsigned int flags)
3973791ec491SStephen Smalley {
3974791ec491SStephen Smalley 	u32 av = 0;
3975791ec491SStephen Smalley 
397684e6885eSStephen Smalley 	if (!flags)
397784e6885eSStephen Smalley 		return 0;
3978791ec491SStephen Smalley 	if (flags & LSM_PRLIMIT_WRITE)
3979791ec491SStephen Smalley 		av |= PROCESS__SETRLIMIT;
3980791ec491SStephen Smalley 	if (flags & LSM_PRLIMIT_READ)
3981791ec491SStephen Smalley 		av |= PROCESS__GETRLIMIT;
39826b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39836b6bc620SStephen Smalley 			    cred_sid(cred), cred_sid(tcred),
3984791ec491SStephen Smalley 			    SECCLASS_PROCESS, av, NULL);
3985791ec491SStephen Smalley }
3986791ec491SStephen Smalley 
39878fd00b4dSJiri Slaby static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
39888fd00b4dSJiri Slaby 		struct rlimit *new_rlim)
39891da177e4SLinus Torvalds {
39908fd00b4dSJiri Slaby 	struct rlimit *old_rlim = p->signal->rlim + resource;
39911da177e4SLinus Torvalds 
39921da177e4SLinus Torvalds 	/* Control the ability to change the hard limit (whether
39931da177e4SLinus Torvalds 	   lowering or raising it), so that the hard limit can
39941da177e4SLinus Torvalds 	   later be used as a safe reset point for the soft limit
3995d84f4f99SDavid Howells 	   upon context transitions.  See selinux_bprm_committing_creds. */
39961da177e4SLinus Torvalds 	if (old_rlim->rlim_max != new_rlim->rlim_max)
39976b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
39986b6bc620SStephen Smalley 				    current_sid(), task_sid(p),
3999be0554c9SStephen Smalley 				    SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
40001da177e4SLinus Torvalds 
40011da177e4SLinus Torvalds 	return 0;
40021da177e4SLinus Torvalds }
40031da177e4SLinus Torvalds 
4004b0ae1981SKOSAKI Motohiro static int selinux_task_setscheduler(struct task_struct *p)
40051da177e4SLinus Torvalds {
40066b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40076b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
4008be0554c9SStephen Smalley 			    PROCESS__SETSCHED, NULL);
40091da177e4SLinus Torvalds }
40101da177e4SLinus Torvalds 
40111da177e4SLinus Torvalds static int selinux_task_getscheduler(struct task_struct *p)
40121da177e4SLinus Torvalds {
40136b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40146b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
4015be0554c9SStephen Smalley 			    PROCESS__GETSCHED, NULL);
40161da177e4SLinus Torvalds }
40171da177e4SLinus Torvalds 
401835601547SDavid Quigley static int selinux_task_movememory(struct task_struct *p)
401935601547SDavid Quigley {
40206b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40216b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
4022be0554c9SStephen Smalley 			    PROCESS__SETSCHED, NULL);
402335601547SDavid Quigley }
402435601547SDavid Quigley 
4025ae7795bcSEric W. Biederman static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
40266b4f3d01SStephen Smalley 				int sig, const struct cred *cred)
40271da177e4SLinus Torvalds {
40286b4f3d01SStephen Smalley 	u32 secid;
40291da177e4SLinus Torvalds 	u32 perm;
40301da177e4SLinus Torvalds 
40311da177e4SLinus Torvalds 	if (!sig)
40321da177e4SLinus Torvalds 		perm = PROCESS__SIGNULL; /* null signal; existence test */
40331da177e4SLinus Torvalds 	else
40341da177e4SLinus Torvalds 		perm = signal_to_av(sig);
40356b4f3d01SStephen Smalley 	if (!cred)
4036be0554c9SStephen Smalley 		secid = current_sid();
40376b4f3d01SStephen Smalley 	else
40386b4f3d01SStephen Smalley 		secid = cred_sid(cred);
40396b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40406b6bc620SStephen Smalley 			    secid, task_sid(p), SECCLASS_PROCESS, perm, NULL);
40411da177e4SLinus Torvalds }
40421da177e4SLinus Torvalds 
40431da177e4SLinus Torvalds static void selinux_task_to_inode(struct task_struct *p,
40441da177e4SLinus Torvalds 				  struct inode *inode)
40451da177e4SLinus Torvalds {
40461da177e4SLinus Torvalds 	struct inode_security_struct *isec = inode->i_security;
4047275bb41eSDavid Howells 	u32 sid = task_sid(p);
40481da177e4SLinus Torvalds 
40499287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
4050db978da8SAndreas Gruenbacher 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
4051275bb41eSDavid Howells 	isec->sid = sid;
40526f3be9f5SAndreas Gruenbacher 	isec->initialized = LABEL_INITIALIZED;
40539287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
40541da177e4SLinus Torvalds }
40551da177e4SLinus Torvalds 
40561da177e4SLinus Torvalds /* Returns error only if unable to parse addresses */
405767f83cbfSVenkat Yekkirala static int selinux_parse_skb_ipv4(struct sk_buff *skb,
40582bf49690SThomas Liu 			struct common_audit_data *ad, u8 *proto)
40591da177e4SLinus Torvalds {
40601da177e4SLinus Torvalds 	int offset, ihlen, ret = -EINVAL;
40611da177e4SLinus Torvalds 	struct iphdr _iph, *ih;
40621da177e4SLinus Torvalds 
4063bbe735e4SArnaldo Carvalho de Melo 	offset = skb_network_offset(skb);
40641da177e4SLinus Torvalds 	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
40651da177e4SLinus Torvalds 	if (ih == NULL)
40661da177e4SLinus Torvalds 		goto out;
40671da177e4SLinus Torvalds 
40681da177e4SLinus Torvalds 	ihlen = ih->ihl * 4;
40691da177e4SLinus Torvalds 	if (ihlen < sizeof(_iph))
40701da177e4SLinus Torvalds 		goto out;
40711da177e4SLinus Torvalds 
407248c62af6SEric Paris 	ad->u.net->v4info.saddr = ih->saddr;
407348c62af6SEric Paris 	ad->u.net->v4info.daddr = ih->daddr;
40741da177e4SLinus Torvalds 	ret = 0;
40751da177e4SLinus Torvalds 
407667f83cbfSVenkat Yekkirala 	if (proto)
407767f83cbfSVenkat Yekkirala 		*proto = ih->protocol;
407867f83cbfSVenkat Yekkirala 
40791da177e4SLinus Torvalds 	switch (ih->protocol) {
40801da177e4SLinus Torvalds 	case IPPROTO_TCP: {
40811da177e4SLinus Torvalds 		struct tcphdr _tcph, *th;
40821da177e4SLinus Torvalds 
40831da177e4SLinus Torvalds 		if (ntohs(ih->frag_off) & IP_OFFSET)
40841da177e4SLinus Torvalds 			break;
40851da177e4SLinus Torvalds 
40861da177e4SLinus Torvalds 		offset += ihlen;
40871da177e4SLinus Torvalds 		th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
40881da177e4SLinus Torvalds 		if (th == NULL)
40891da177e4SLinus Torvalds 			break;
40901da177e4SLinus Torvalds 
409148c62af6SEric Paris 		ad->u.net->sport = th->source;
409248c62af6SEric Paris 		ad->u.net->dport = th->dest;
40931da177e4SLinus Torvalds 		break;
40941da177e4SLinus Torvalds 	}
40951da177e4SLinus Torvalds 
40961da177e4SLinus Torvalds 	case IPPROTO_UDP: {
40971da177e4SLinus Torvalds 		struct udphdr _udph, *uh;
40981da177e4SLinus Torvalds 
40991da177e4SLinus Torvalds 		if (ntohs(ih->frag_off) & IP_OFFSET)
41001da177e4SLinus Torvalds 			break;
41011da177e4SLinus Torvalds 
41021da177e4SLinus Torvalds 		offset += ihlen;
41031da177e4SLinus Torvalds 		uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
41041da177e4SLinus Torvalds 		if (uh == NULL)
41051da177e4SLinus Torvalds 			break;
41061da177e4SLinus Torvalds 
410748c62af6SEric Paris 		ad->u.net->sport = uh->source;
410848c62af6SEric Paris 		ad->u.net->dport = uh->dest;
41091da177e4SLinus Torvalds 		break;
41101da177e4SLinus Torvalds 	}
41111da177e4SLinus Torvalds 
41122ee92d46SJames Morris 	case IPPROTO_DCCP: {
41132ee92d46SJames Morris 		struct dccp_hdr _dccph, *dh;
41142ee92d46SJames Morris 
41152ee92d46SJames Morris 		if (ntohs(ih->frag_off) & IP_OFFSET)
41162ee92d46SJames Morris 			break;
41172ee92d46SJames Morris 
41182ee92d46SJames Morris 		offset += ihlen;
41192ee92d46SJames Morris 		dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
41202ee92d46SJames Morris 		if (dh == NULL)
41212ee92d46SJames Morris 			break;
41222ee92d46SJames Morris 
412348c62af6SEric Paris 		ad->u.net->sport = dh->dccph_sport;
412448c62af6SEric Paris 		ad->u.net->dport = dh->dccph_dport;
41252ee92d46SJames Morris 		break;
41262ee92d46SJames Morris 	}
41272ee92d46SJames Morris 
4128d452930fSRichard Haines #if IS_ENABLED(CONFIG_IP_SCTP)
4129d452930fSRichard Haines 	case IPPROTO_SCTP: {
4130d452930fSRichard Haines 		struct sctphdr _sctph, *sh;
4131d452930fSRichard Haines 
4132d452930fSRichard Haines 		if (ntohs(ih->frag_off) & IP_OFFSET)
4133d452930fSRichard Haines 			break;
4134d452930fSRichard Haines 
4135d452930fSRichard Haines 		offset += ihlen;
4136d452930fSRichard Haines 		sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
4137d452930fSRichard Haines 		if (sh == NULL)
4138d452930fSRichard Haines 			break;
4139d452930fSRichard Haines 
4140d452930fSRichard Haines 		ad->u.net->sport = sh->source;
4141d452930fSRichard Haines 		ad->u.net->dport = sh->dest;
4142d452930fSRichard Haines 		break;
4143d452930fSRichard Haines 	}
4144d452930fSRichard Haines #endif
41451da177e4SLinus Torvalds 	default:
41461da177e4SLinus Torvalds 		break;
41471da177e4SLinus Torvalds 	}
41481da177e4SLinus Torvalds out:
41491da177e4SLinus Torvalds 	return ret;
41501da177e4SLinus Torvalds }
41511da177e4SLinus Torvalds 
41521a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
41531da177e4SLinus Torvalds 
41541da177e4SLinus Torvalds /* Returns error only if unable to parse addresses */
415567f83cbfSVenkat Yekkirala static int selinux_parse_skb_ipv6(struct sk_buff *skb,
41562bf49690SThomas Liu 			struct common_audit_data *ad, u8 *proto)
41571da177e4SLinus Torvalds {
41581da177e4SLinus Torvalds 	u8 nexthdr;
41591da177e4SLinus Torvalds 	int ret = -EINVAL, offset;
41601da177e4SLinus Torvalds 	struct ipv6hdr _ipv6h, *ip6;
416175f2811cSJesse Gross 	__be16 frag_off;
41621da177e4SLinus Torvalds 
4163bbe735e4SArnaldo Carvalho de Melo 	offset = skb_network_offset(skb);
41641da177e4SLinus Torvalds 	ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
41651da177e4SLinus Torvalds 	if (ip6 == NULL)
41661da177e4SLinus Torvalds 		goto out;
41671da177e4SLinus Torvalds 
416848c62af6SEric Paris 	ad->u.net->v6info.saddr = ip6->saddr;
416948c62af6SEric Paris 	ad->u.net->v6info.daddr = ip6->daddr;
41701da177e4SLinus Torvalds 	ret = 0;
41711da177e4SLinus Torvalds 
41721da177e4SLinus Torvalds 	nexthdr = ip6->nexthdr;
41731da177e4SLinus Torvalds 	offset += sizeof(_ipv6h);
417475f2811cSJesse Gross 	offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
41751da177e4SLinus Torvalds 	if (offset < 0)
41761da177e4SLinus Torvalds 		goto out;
41771da177e4SLinus Torvalds 
417867f83cbfSVenkat Yekkirala 	if (proto)
417967f83cbfSVenkat Yekkirala 		*proto = nexthdr;
418067f83cbfSVenkat Yekkirala 
41811da177e4SLinus Torvalds 	switch (nexthdr) {
41821da177e4SLinus Torvalds 	case IPPROTO_TCP: {
41831da177e4SLinus Torvalds 		struct tcphdr _tcph, *th;
41841da177e4SLinus Torvalds 
41851da177e4SLinus Torvalds 		th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
41861da177e4SLinus Torvalds 		if (th == NULL)
41871da177e4SLinus Torvalds 			break;
41881da177e4SLinus Torvalds 
418948c62af6SEric Paris 		ad->u.net->sport = th->source;
419048c62af6SEric Paris 		ad->u.net->dport = th->dest;
41911da177e4SLinus Torvalds 		break;
41921da177e4SLinus Torvalds 	}
41931da177e4SLinus Torvalds 
41941da177e4SLinus Torvalds 	case IPPROTO_UDP: {
41951da177e4SLinus Torvalds 		struct udphdr _udph, *uh;
41961da177e4SLinus Torvalds 
41971da177e4SLinus Torvalds 		uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
41981da177e4SLinus Torvalds 		if (uh == NULL)
41991da177e4SLinus Torvalds 			break;
42001da177e4SLinus Torvalds 
420148c62af6SEric Paris 		ad->u.net->sport = uh->source;
420248c62af6SEric Paris 		ad->u.net->dport = uh->dest;
42031da177e4SLinus Torvalds 		break;
42041da177e4SLinus Torvalds 	}
42051da177e4SLinus Torvalds 
42062ee92d46SJames Morris 	case IPPROTO_DCCP: {
42072ee92d46SJames Morris 		struct dccp_hdr _dccph, *dh;
42082ee92d46SJames Morris 
42092ee92d46SJames Morris 		dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
42102ee92d46SJames Morris 		if (dh == NULL)
42112ee92d46SJames Morris 			break;
42122ee92d46SJames Morris 
421348c62af6SEric Paris 		ad->u.net->sport = dh->dccph_sport;
421448c62af6SEric Paris 		ad->u.net->dport = dh->dccph_dport;
42152ee92d46SJames Morris 		break;
42162ee92d46SJames Morris 	}
42172ee92d46SJames Morris 
4218d452930fSRichard Haines #if IS_ENABLED(CONFIG_IP_SCTP)
4219d452930fSRichard Haines 	case IPPROTO_SCTP: {
4220d452930fSRichard Haines 		struct sctphdr _sctph, *sh;
4221d452930fSRichard Haines 
4222d452930fSRichard Haines 		sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
4223d452930fSRichard Haines 		if (sh == NULL)
4224d452930fSRichard Haines 			break;
4225d452930fSRichard Haines 
4226d452930fSRichard Haines 		ad->u.net->sport = sh->source;
4227d452930fSRichard Haines 		ad->u.net->dport = sh->dest;
4228d452930fSRichard Haines 		break;
4229d452930fSRichard Haines 	}
4230d452930fSRichard Haines #endif
42311da177e4SLinus Torvalds 	/* includes fragments */
42321da177e4SLinus Torvalds 	default:
42331da177e4SLinus Torvalds 		break;
42341da177e4SLinus Torvalds 	}
42351da177e4SLinus Torvalds out:
42361da177e4SLinus Torvalds 	return ret;
42371da177e4SLinus Torvalds }
42381da177e4SLinus Torvalds 
42391da177e4SLinus Torvalds #endif /* IPV6 */
42401da177e4SLinus Torvalds 
42412bf49690SThomas Liu static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
4242cf9481e2SDavid Howells 			     char **_addrp, int src, u8 *proto)
42431da177e4SLinus Torvalds {
4244cf9481e2SDavid Howells 	char *addrp;
4245cf9481e2SDavid Howells 	int ret;
42461da177e4SLinus Torvalds 
424748c62af6SEric Paris 	switch (ad->u.net->family) {
42481da177e4SLinus Torvalds 	case PF_INET:
424967f83cbfSVenkat Yekkirala 		ret = selinux_parse_skb_ipv4(skb, ad, proto);
4250cf9481e2SDavid Howells 		if (ret)
4251cf9481e2SDavid Howells 			goto parse_error;
425248c62af6SEric Paris 		addrp = (char *)(src ? &ad->u.net->v4info.saddr :
425348c62af6SEric Paris 				       &ad->u.net->v4info.daddr);
4254cf9481e2SDavid Howells 		goto okay;
42551da177e4SLinus Torvalds 
42561a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
42571da177e4SLinus Torvalds 	case PF_INET6:
425867f83cbfSVenkat Yekkirala 		ret = selinux_parse_skb_ipv6(skb, ad, proto);
4259cf9481e2SDavid Howells 		if (ret)
4260cf9481e2SDavid Howells 			goto parse_error;
426148c62af6SEric Paris 		addrp = (char *)(src ? &ad->u.net->v6info.saddr :
426248c62af6SEric Paris 				       &ad->u.net->v6info.daddr);
4263cf9481e2SDavid Howells 		goto okay;
42641da177e4SLinus Torvalds #endif	/* IPV6 */
42651da177e4SLinus Torvalds 	default:
4266cf9481e2SDavid Howells 		addrp = NULL;
4267cf9481e2SDavid Howells 		goto okay;
42681da177e4SLinus Torvalds 	}
42691da177e4SLinus Torvalds 
4270cf9481e2SDavid Howells parse_error:
4271c103a91eSpeter enderborg 	pr_warn(
427271f1cb05SPaul Moore 	       "SELinux: failure in selinux_parse_skb(),"
427371f1cb05SPaul Moore 	       " unable to parse packet\n");
42741da177e4SLinus Torvalds 	return ret;
4275cf9481e2SDavid Howells 
4276cf9481e2SDavid Howells okay:
4277cf9481e2SDavid Howells 	if (_addrp)
4278cf9481e2SDavid Howells 		*_addrp = addrp;
4279cf9481e2SDavid Howells 	return 0;
42801da177e4SLinus Torvalds }
42811da177e4SLinus Torvalds 
42824f6a993fSPaul Moore /**
4283220deb96SPaul Moore  * selinux_skb_peerlbl_sid - Determine the peer label of a packet
42844f6a993fSPaul Moore  * @skb: the packet
428575e22910SPaul Moore  * @family: protocol family
4286220deb96SPaul Moore  * @sid: the packet's peer label SID
42874f6a993fSPaul Moore  *
42884f6a993fSPaul Moore  * Description:
4289220deb96SPaul Moore  * Check the various different forms of network peer labeling and determine
4290220deb96SPaul Moore  * the peer label/SID for the packet; most of the magic actually occurs in
4291220deb96SPaul Moore  * the security server function security_net_peersid_cmp().  The function
4292220deb96SPaul Moore  * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
4293220deb96SPaul Moore  * or -EACCES if @sid is invalid due to inconsistencies with the different
4294220deb96SPaul Moore  * peer labels.
42954f6a993fSPaul Moore  *
42964f6a993fSPaul Moore  */
4297220deb96SPaul Moore static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
42984f6a993fSPaul Moore {
429971f1cb05SPaul Moore 	int err;
43004f6a993fSPaul Moore 	u32 xfrm_sid;
43014f6a993fSPaul Moore 	u32 nlbl_sid;
4302220deb96SPaul Moore 	u32 nlbl_type;
43034f6a993fSPaul Moore 
4304817eff71SPaul Moore 	err = selinux_xfrm_skb_sid(skb, &xfrm_sid);
4305bed4d7efSPaul Moore 	if (unlikely(err))
4306bed4d7efSPaul Moore 		return -EACCES;
4307bed4d7efSPaul Moore 	err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
4308bed4d7efSPaul Moore 	if (unlikely(err))
4309bed4d7efSPaul Moore 		return -EACCES;
4310220deb96SPaul Moore 
4311aa8e712cSStephen Smalley 	err = security_net_peersid_resolve(&selinux_state, nlbl_sid,
4312aa8e712cSStephen Smalley 					   nlbl_type, xfrm_sid, sid);
431371f1cb05SPaul Moore 	if (unlikely(err)) {
4314c103a91eSpeter enderborg 		pr_warn(
431571f1cb05SPaul Moore 		       "SELinux: failure in selinux_skb_peerlbl_sid(),"
431671f1cb05SPaul Moore 		       " unable to determine packet's peer label\n");
4317220deb96SPaul Moore 		return -EACCES;
431871f1cb05SPaul Moore 	}
4319220deb96SPaul Moore 
4320220deb96SPaul Moore 	return 0;
43214f6a993fSPaul Moore }
43224f6a993fSPaul Moore 
4323446b8024SPaul Moore /**
4324446b8024SPaul Moore  * selinux_conn_sid - Determine the child socket label for a connection
4325446b8024SPaul Moore  * @sk_sid: the parent socket's SID
4326446b8024SPaul Moore  * @skb_sid: the packet's SID
4327446b8024SPaul Moore  * @conn_sid: the resulting connection SID
4328446b8024SPaul Moore  *
4329446b8024SPaul Moore  * If @skb_sid is valid then the user:role:type information from @sk_sid is
4330446b8024SPaul Moore  * combined with the MLS information from @skb_sid in order to create
4331446b8024SPaul Moore  * @conn_sid.  If @skb_sid is not valid then then @conn_sid is simply a copy
4332446b8024SPaul Moore  * of @sk_sid.  Returns zero on success, negative values on failure.
4333446b8024SPaul Moore  *
4334446b8024SPaul Moore  */
4335446b8024SPaul Moore static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
4336446b8024SPaul Moore {
4337446b8024SPaul Moore 	int err = 0;
4338446b8024SPaul Moore 
4339446b8024SPaul Moore 	if (skb_sid != SECSID_NULL)
4340aa8e712cSStephen Smalley 		err = security_sid_mls_copy(&selinux_state, sk_sid, skb_sid,
4341aa8e712cSStephen Smalley 					    conn_sid);
4342446b8024SPaul Moore 	else
4343446b8024SPaul Moore 		*conn_sid = sk_sid;
4344446b8024SPaul Moore 
4345446b8024SPaul Moore 	return err;
4346446b8024SPaul Moore }
4347446b8024SPaul Moore 
43481da177e4SLinus Torvalds /* socket security operations */
4349d4f2d978SPaul Moore 
43502ad18bdfSHarry Ciao static int socket_sockcreate_sid(const struct task_security_struct *tsec,
43512ad18bdfSHarry Ciao 				 u16 secclass, u32 *socksid)
4352d4f2d978SPaul Moore {
43532ad18bdfSHarry Ciao 	if (tsec->sockcreate_sid > SECSID_NULL) {
43542ad18bdfSHarry Ciao 		*socksid = tsec->sockcreate_sid;
43552ad18bdfSHarry Ciao 		return 0;
43562ad18bdfSHarry Ciao 	}
43572ad18bdfSHarry Ciao 
4358aa8e712cSStephen Smalley 	return security_transition_sid(&selinux_state, tsec->sid, tsec->sid,
4359aa8e712cSStephen Smalley 				       secclass, NULL, socksid);
4360d4f2d978SPaul Moore }
4361d4f2d978SPaul Moore 
4362be0554c9SStephen Smalley static int sock_has_perm(struct sock *sk, u32 perms)
43631da177e4SLinus Torvalds {
4364253bfae6SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
43652bf49690SThomas Liu 	struct common_audit_data ad;
436648c62af6SEric Paris 	struct lsm_network_audit net = {0,};
43671da177e4SLinus Torvalds 
4368253bfae6SPaul Moore 	if (sksec->sid == SECINITSID_KERNEL)
4369253bfae6SPaul Moore 		return 0;
43701da177e4SLinus Torvalds 
437150c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
437248c62af6SEric Paris 	ad.u.net = &net;
437348c62af6SEric Paris 	ad.u.net->sk = sk;
43741da177e4SLinus Torvalds 
43756b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
43766b6bc620SStephen Smalley 			    current_sid(), sksec->sid, sksec->sclass, perms,
4377be0554c9SStephen Smalley 			    &ad);
43781da177e4SLinus Torvalds }
43791da177e4SLinus Torvalds 
43801da177e4SLinus Torvalds static int selinux_socket_create(int family, int type,
43811da177e4SLinus Torvalds 				 int protocol, int kern)
43821da177e4SLinus Torvalds {
43835fb49870SPaul Moore 	const struct task_security_struct *tsec = current_security();
4384d4f2d978SPaul Moore 	u32 newsid;
4385275bb41eSDavid Howells 	u16 secclass;
43862ad18bdfSHarry Ciao 	int rc;
43871da177e4SLinus Torvalds 
43881da177e4SLinus Torvalds 	if (kern)
4389d4f2d978SPaul Moore 		return 0;
43901da177e4SLinus Torvalds 
4391275bb41eSDavid Howells 	secclass = socket_type_to_security_class(family, type, protocol);
43922ad18bdfSHarry Ciao 	rc = socket_sockcreate_sid(tsec, secclass, &newsid);
43932ad18bdfSHarry Ciao 	if (rc)
43942ad18bdfSHarry Ciao 		return rc;
43952ad18bdfSHarry Ciao 
43966b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
43976b6bc620SStephen Smalley 			    tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
43981da177e4SLinus Torvalds }
43991da177e4SLinus Torvalds 
44007420ed23SVenkat Yekkirala static int selinux_socket_post_create(struct socket *sock, int family,
44011da177e4SLinus Torvalds 				      int type, int protocol, int kern)
44021da177e4SLinus Torvalds {
44035fb49870SPaul Moore 	const struct task_security_struct *tsec = current_security();
44045d226df4SAndreas Gruenbacher 	struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock));
4405892c141eSVenkat Yekkirala 	struct sk_security_struct *sksec;
44069287aed2SAndreas Gruenbacher 	u16 sclass = socket_type_to_security_class(family, type, protocol);
44079287aed2SAndreas Gruenbacher 	u32 sid = SECINITSID_KERNEL;
4408275bb41eSDavid Howells 	int err = 0;
4409275bb41eSDavid Howells 
44109287aed2SAndreas Gruenbacher 	if (!kern) {
44119287aed2SAndreas Gruenbacher 		err = socket_sockcreate_sid(tsec, sclass, &sid);
44122ad18bdfSHarry Ciao 		if (err)
44132ad18bdfSHarry Ciao 			return err;
44142ad18bdfSHarry Ciao 	}
4415275bb41eSDavid Howells 
44169287aed2SAndreas Gruenbacher 	isec->sclass = sclass;
44179287aed2SAndreas Gruenbacher 	isec->sid = sid;
44186f3be9f5SAndreas Gruenbacher 	isec->initialized = LABEL_INITIALIZED;
44191da177e4SLinus Torvalds 
4420892c141eSVenkat Yekkirala 	if (sock->sk) {
4421892c141eSVenkat Yekkirala 		sksec = sock->sk->sk_security;
44229287aed2SAndreas Gruenbacher 		sksec->sclass = sclass;
44239287aed2SAndreas Gruenbacher 		sksec->sid = sid;
4424d452930fSRichard Haines 		/* Allows detection of the first association on this socket */
4425d452930fSRichard Haines 		if (sksec->sclass == SECCLASS_SCTP_SOCKET)
4426d452930fSRichard Haines 			sksec->sctp_assoc_state = SCTP_ASSOC_UNSET;
4427d452930fSRichard Haines 
4428389fb800SPaul Moore 		err = selinux_netlbl_socket_post_create(sock->sk, family);
4429892c141eSVenkat Yekkirala 	}
4430892c141eSVenkat Yekkirala 
44317420ed23SVenkat Yekkirala 	return err;
44321da177e4SLinus Torvalds }
44331da177e4SLinus Torvalds 
44340b811db2SDavid Herrmann static int selinux_socket_socketpair(struct socket *socka,
44350b811db2SDavid Herrmann 				     struct socket *sockb)
44360b811db2SDavid Herrmann {
44370b811db2SDavid Herrmann 	struct sk_security_struct *sksec_a = socka->sk->sk_security;
44380b811db2SDavid Herrmann 	struct sk_security_struct *sksec_b = sockb->sk->sk_security;
44390b811db2SDavid Herrmann 
44400b811db2SDavid Herrmann 	sksec_a->peer_sid = sksec_b->sid;
44410b811db2SDavid Herrmann 	sksec_b->peer_sid = sksec_a->sid;
44420b811db2SDavid Herrmann 
44430b811db2SDavid Herrmann 	return 0;
44440b811db2SDavid Herrmann }
44450b811db2SDavid Herrmann 
44461da177e4SLinus Torvalds /* Range of port numbers used to automatically bind.
44471da177e4SLinus Torvalds    Need to determine whether we should perform a name_bind
44481da177e4SLinus Torvalds    permission check between the socket and the port number. */
44491da177e4SLinus Torvalds 
44501da177e4SLinus Torvalds static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
44511da177e4SLinus Torvalds {
4452253bfae6SPaul Moore 	struct sock *sk = sock->sk;
44530f8db8ccSAlexey Kodanev 	struct sk_security_struct *sksec = sk->sk_security;
44541da177e4SLinus Torvalds 	u16 family;
44551da177e4SLinus Torvalds 	int err;
44561da177e4SLinus Torvalds 
4457be0554c9SStephen Smalley 	err = sock_has_perm(sk, SOCKET__BIND);
44581da177e4SLinus Torvalds 	if (err)
44591da177e4SLinus Torvalds 		goto out;
44601da177e4SLinus Torvalds 
4461d452930fSRichard Haines 	/* If PF_INET or PF_INET6, check name_bind permission for the port. */
4462253bfae6SPaul Moore 	family = sk->sk_family;
44631da177e4SLinus Torvalds 	if (family == PF_INET || family == PF_INET6) {
44641da177e4SLinus Torvalds 		char *addrp;
44652bf49690SThomas Liu 		struct common_audit_data ad;
446648c62af6SEric Paris 		struct lsm_network_audit net = {0,};
44671da177e4SLinus Torvalds 		struct sockaddr_in *addr4 = NULL;
44681da177e4SLinus Torvalds 		struct sockaddr_in6 *addr6 = NULL;
44690f8db8ccSAlexey Kodanev 		u16 family_sa = address->sa_family;
44701da177e4SLinus Torvalds 		unsigned short snum;
4471e399f982SJames Morris 		u32 sid, node_perm;
44721da177e4SLinus Torvalds 
4473d452930fSRichard Haines 		/*
4474d452930fSRichard Haines 		 * sctp_bindx(3) calls via selinux_sctp_bind_connect()
4475d452930fSRichard Haines 		 * that validates multiple binding addresses. Because of this
4476d452930fSRichard Haines 		 * need to check address->sa_family as it is possible to have
4477d452930fSRichard Haines 		 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
4478d452930fSRichard Haines 		 */
44790f8db8ccSAlexey Kodanev 		switch (family_sa) {
44800f8db8ccSAlexey Kodanev 		case AF_UNSPEC:
448168741a8aSRichard Haines 		case AF_INET:
448268741a8aSRichard Haines 			if (addrlen < sizeof(struct sockaddr_in))
448368741a8aSRichard Haines 				return -EINVAL;
44841da177e4SLinus Torvalds 			addr4 = (struct sockaddr_in *)address;
44850f8db8ccSAlexey Kodanev 			if (family_sa == AF_UNSPEC) {
44860f8db8ccSAlexey Kodanev 				/* see __inet_bind(), we only want to allow
44870f8db8ccSAlexey Kodanev 				 * AF_UNSPEC if the address is INADDR_ANY
44880f8db8ccSAlexey Kodanev 				 */
44890f8db8ccSAlexey Kodanev 				if (addr4->sin_addr.s_addr != htonl(INADDR_ANY))
44900f8db8ccSAlexey Kodanev 					goto err_af;
44910f8db8ccSAlexey Kodanev 				family_sa = AF_INET;
44920f8db8ccSAlexey Kodanev 			}
44931da177e4SLinus Torvalds 			snum = ntohs(addr4->sin_port);
44941da177e4SLinus Torvalds 			addrp = (char *)&addr4->sin_addr.s_addr;
449568741a8aSRichard Haines 			break;
449668741a8aSRichard Haines 		case AF_INET6:
449768741a8aSRichard Haines 			if (addrlen < SIN6_LEN_RFC2133)
449868741a8aSRichard Haines 				return -EINVAL;
44991da177e4SLinus Torvalds 			addr6 = (struct sockaddr_in6 *)address;
45001da177e4SLinus Torvalds 			snum = ntohs(addr6->sin6_port);
45011da177e4SLinus Torvalds 			addrp = (char *)&addr6->sin6_addr.s6_addr;
450268741a8aSRichard Haines 			break;
450368741a8aSRichard Haines 		default:
45040f8db8ccSAlexey Kodanev 			goto err_af;
45051da177e4SLinus Torvalds 		}
45061da177e4SLinus Torvalds 
450788b7d370SAlexey Kodanev 		ad.type = LSM_AUDIT_DATA_NET;
450888b7d370SAlexey Kodanev 		ad.u.net = &net;
450988b7d370SAlexey Kodanev 		ad.u.net->sport = htons(snum);
451088b7d370SAlexey Kodanev 		ad.u.net->family = family_sa;
451188b7d370SAlexey Kodanev 
4512227b60f5SStephen Hemminger 		if (snum) {
4513227b60f5SStephen Hemminger 			int low, high;
4514227b60f5SStephen Hemminger 
45150bbf87d8SEric W. Biederman 			inet_get_local_port_range(sock_net(sk), &low, &high);
4516227b60f5SStephen Hemminger 
45174548b683SKrister Johansen 			if (snum < max(inet_prot_sock(sock_net(sk)), low) ||
45184548b683SKrister Johansen 			    snum > high) {
45193e112172SPaul Moore 				err = sel_netport_sid(sk->sk_protocol,
45203e112172SPaul Moore 						      snum, &sid);
45211da177e4SLinus Torvalds 				if (err)
45221da177e4SLinus Torvalds 					goto out;
45236b6bc620SStephen Smalley 				err = avc_has_perm(&selinux_state,
45246b6bc620SStephen Smalley 						   sksec->sid, sid,
4525253bfae6SPaul Moore 						   sksec->sclass,
45261da177e4SLinus Torvalds 						   SOCKET__NAME_BIND, &ad);
45271da177e4SLinus Torvalds 				if (err)
45281da177e4SLinus Torvalds 					goto out;
45291da177e4SLinus Torvalds 			}
4530227b60f5SStephen Hemminger 		}
45311da177e4SLinus Torvalds 
4532253bfae6SPaul Moore 		switch (sksec->sclass) {
453313402580SJames Morris 		case SECCLASS_TCP_SOCKET:
45341da177e4SLinus Torvalds 			node_perm = TCP_SOCKET__NODE_BIND;
45351da177e4SLinus Torvalds 			break;
45361da177e4SLinus Torvalds 
453713402580SJames Morris 		case SECCLASS_UDP_SOCKET:
45381da177e4SLinus Torvalds 			node_perm = UDP_SOCKET__NODE_BIND;
45391da177e4SLinus Torvalds 			break;
45401da177e4SLinus Torvalds 
45412ee92d46SJames Morris 		case SECCLASS_DCCP_SOCKET:
45422ee92d46SJames Morris 			node_perm = DCCP_SOCKET__NODE_BIND;
45432ee92d46SJames Morris 			break;
45442ee92d46SJames Morris 
4545d452930fSRichard Haines 		case SECCLASS_SCTP_SOCKET:
4546d452930fSRichard Haines 			node_perm = SCTP_SOCKET__NODE_BIND;
4547d452930fSRichard Haines 			break;
4548d452930fSRichard Haines 
45491da177e4SLinus Torvalds 		default:
45501da177e4SLinus Torvalds 			node_perm = RAWIP_SOCKET__NODE_BIND;
45511da177e4SLinus Torvalds 			break;
45521da177e4SLinus Torvalds 		}
45531da177e4SLinus Torvalds 
455488b7d370SAlexey Kodanev 		err = sel_netnode_sid(addrp, family_sa, &sid);
45551da177e4SLinus Torvalds 		if (err)
45561da177e4SLinus Torvalds 			goto out;
45571da177e4SLinus Torvalds 
45580f8db8ccSAlexey Kodanev 		if (family_sa == AF_INET)
455948c62af6SEric Paris 			ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
45601da177e4SLinus Torvalds 		else
456148c62af6SEric Paris 			ad.u.net->v6info.saddr = addr6->sin6_addr;
45621da177e4SLinus Torvalds 
45636b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
45646b6bc620SStephen Smalley 				   sksec->sid, sid,
4565253bfae6SPaul Moore 				   sksec->sclass, node_perm, &ad);
45661da177e4SLinus Torvalds 		if (err)
45671da177e4SLinus Torvalds 			goto out;
45681da177e4SLinus Torvalds 	}
45691da177e4SLinus Torvalds out:
45701da177e4SLinus Torvalds 	return err;
45710f8db8ccSAlexey Kodanev err_af:
45720f8db8ccSAlexey Kodanev 	/* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */
45730f8db8ccSAlexey Kodanev 	if (sksec->sclass == SECCLASS_SCTP_SOCKET)
45740f8db8ccSAlexey Kodanev 		return -EINVAL;
45750f8db8ccSAlexey Kodanev 	return -EAFNOSUPPORT;
45761da177e4SLinus Torvalds }
45771da177e4SLinus Torvalds 
4578d452930fSRichard Haines /* This supports connect(2) and SCTP connect services such as sctp_connectx(3)
45795fb94e9cSMauro Carvalho Chehab  * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.rst
4580d452930fSRichard Haines  */
4581d452930fSRichard Haines static int selinux_socket_connect_helper(struct socket *sock,
4582d452930fSRichard Haines 					 struct sockaddr *address, int addrlen)
45831da177e4SLinus Torvalds {
4584014ab19aSPaul Moore 	struct sock *sk = sock->sk;
4585253bfae6SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
45861da177e4SLinus Torvalds 	int err;
45871da177e4SLinus Torvalds 
4588be0554c9SStephen Smalley 	err = sock_has_perm(sk, SOCKET__CONNECT);
45891da177e4SLinus Torvalds 	if (err)
45901da177e4SLinus Torvalds 		return err;
45911da177e4SLinus Torvalds 
45921da177e4SLinus Torvalds 	/*
4593d452930fSRichard Haines 	 * If a TCP, DCCP or SCTP socket, check name_connect permission
4594d452930fSRichard Haines 	 * for the port.
45951da177e4SLinus Torvalds 	 */
4596253bfae6SPaul Moore 	if (sksec->sclass == SECCLASS_TCP_SOCKET ||
4597d452930fSRichard Haines 	    sksec->sclass == SECCLASS_DCCP_SOCKET ||
4598d452930fSRichard Haines 	    sksec->sclass == SECCLASS_SCTP_SOCKET) {
45992bf49690SThomas Liu 		struct common_audit_data ad;
460048c62af6SEric Paris 		struct lsm_network_audit net = {0,};
46011da177e4SLinus Torvalds 		struct sockaddr_in *addr4 = NULL;
46021da177e4SLinus Torvalds 		struct sockaddr_in6 *addr6 = NULL;
46031da177e4SLinus Torvalds 		unsigned short snum;
46042ee92d46SJames Morris 		u32 sid, perm;
46051da177e4SLinus Torvalds 
4606d452930fSRichard Haines 		/* sctp_connectx(3) calls via selinux_sctp_bind_connect()
4607d452930fSRichard Haines 		 * that validates multiple connect addresses. Because of this
4608d452930fSRichard Haines 		 * need to check address->sa_family as it is possible to have
4609d452930fSRichard Haines 		 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
4610d452930fSRichard Haines 		 */
461168741a8aSRichard Haines 		switch (address->sa_family) {
461268741a8aSRichard Haines 		case AF_INET:
46131da177e4SLinus Torvalds 			addr4 = (struct sockaddr_in *)address;
4614911656f8SStephen Smalley 			if (addrlen < sizeof(struct sockaddr_in))
46151da177e4SLinus Torvalds 				return -EINVAL;
46161da177e4SLinus Torvalds 			snum = ntohs(addr4->sin_port);
461768741a8aSRichard Haines 			break;
461868741a8aSRichard Haines 		case AF_INET6:
46191da177e4SLinus Torvalds 			addr6 = (struct sockaddr_in6 *)address;
4620911656f8SStephen Smalley 			if (addrlen < SIN6_LEN_RFC2133)
46211da177e4SLinus Torvalds 				return -EINVAL;
46221da177e4SLinus Torvalds 			snum = ntohs(addr6->sin6_port);
462368741a8aSRichard Haines 			break;
462468741a8aSRichard Haines 		default:
462568741a8aSRichard Haines 			/* Note that SCTP services expect -EINVAL, whereas
462668741a8aSRichard Haines 			 * others expect -EAFNOSUPPORT.
462768741a8aSRichard Haines 			 */
462868741a8aSRichard Haines 			if (sksec->sclass == SECCLASS_SCTP_SOCKET)
462968741a8aSRichard Haines 				return -EINVAL;
463068741a8aSRichard Haines 			else
463168741a8aSRichard Haines 				return -EAFNOSUPPORT;
46321da177e4SLinus Torvalds 		}
46331da177e4SLinus Torvalds 
46343e112172SPaul Moore 		err = sel_netport_sid(sk->sk_protocol, snum, &sid);
46351da177e4SLinus Torvalds 		if (err)
4636d452930fSRichard Haines 			return err;
46371da177e4SLinus Torvalds 
4638d452930fSRichard Haines 		switch (sksec->sclass) {
4639d452930fSRichard Haines 		case SECCLASS_TCP_SOCKET:
4640d452930fSRichard Haines 			perm = TCP_SOCKET__NAME_CONNECT;
4641d452930fSRichard Haines 			break;
4642d452930fSRichard Haines 		case SECCLASS_DCCP_SOCKET:
4643d452930fSRichard Haines 			perm = DCCP_SOCKET__NAME_CONNECT;
4644d452930fSRichard Haines 			break;
4645d452930fSRichard Haines 		case SECCLASS_SCTP_SOCKET:
4646d452930fSRichard Haines 			perm = SCTP_SOCKET__NAME_CONNECT;
4647d452930fSRichard Haines 			break;
4648d452930fSRichard Haines 		}
46492ee92d46SJames Morris 
465050c205f5SEric Paris 		ad.type = LSM_AUDIT_DATA_NET;
465148c62af6SEric Paris 		ad.u.net = &net;
465248c62af6SEric Paris 		ad.u.net->dport = htons(snum);
465388b7d370SAlexey Kodanev 		ad.u.net->family = address->sa_family;
46546b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
46556b6bc620SStephen Smalley 				   sksec->sid, sid, sksec->sclass, perm, &ad);
46561da177e4SLinus Torvalds 		if (err)
4657d452930fSRichard Haines 			return err;
46581da177e4SLinus Torvalds 	}
46591da177e4SLinus Torvalds 
4660d452930fSRichard Haines 	return 0;
4661d452930fSRichard Haines }
4662014ab19aSPaul Moore 
4663d452930fSRichard Haines /* Supports connect(2), see comments in selinux_socket_connect_helper() */
4664d452930fSRichard Haines static int selinux_socket_connect(struct socket *sock,
4665d452930fSRichard Haines 				  struct sockaddr *address, int addrlen)
4666d452930fSRichard Haines {
4667d452930fSRichard Haines 	int err;
4668d452930fSRichard Haines 	struct sock *sk = sock->sk;
4669d452930fSRichard Haines 
4670d452930fSRichard Haines 	err = selinux_socket_connect_helper(sock, address, addrlen);
4671d452930fSRichard Haines 	if (err)
46721da177e4SLinus Torvalds 		return err;
4673d452930fSRichard Haines 
4674d452930fSRichard Haines 	return selinux_netlbl_socket_connect(sk, address);
46751da177e4SLinus Torvalds }
46761da177e4SLinus Torvalds 
46771da177e4SLinus Torvalds static int selinux_socket_listen(struct socket *sock, int backlog)
46781da177e4SLinus Torvalds {
4679be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__LISTEN);
46801da177e4SLinus Torvalds }
46811da177e4SLinus Torvalds 
46821da177e4SLinus Torvalds static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
46831da177e4SLinus Torvalds {
46841da177e4SLinus Torvalds 	int err;
46851da177e4SLinus Torvalds 	struct inode_security_struct *isec;
46861da177e4SLinus Torvalds 	struct inode_security_struct *newisec;
46879287aed2SAndreas Gruenbacher 	u16 sclass;
46889287aed2SAndreas Gruenbacher 	u32 sid;
46891da177e4SLinus Torvalds 
4690be0554c9SStephen Smalley 	err = sock_has_perm(sock->sk, SOCKET__ACCEPT);
46911da177e4SLinus Torvalds 	if (err)
46921da177e4SLinus Torvalds 		return err;
46931da177e4SLinus Torvalds 
46945d226df4SAndreas Gruenbacher 	isec = inode_security_novalidate(SOCK_INODE(sock));
46959287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
46969287aed2SAndreas Gruenbacher 	sclass = isec->sclass;
46979287aed2SAndreas Gruenbacher 	sid = isec->sid;
46989287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
46999287aed2SAndreas Gruenbacher 
47009287aed2SAndreas Gruenbacher 	newisec = inode_security_novalidate(SOCK_INODE(newsock));
47019287aed2SAndreas Gruenbacher 	newisec->sclass = sclass;
47029287aed2SAndreas Gruenbacher 	newisec->sid = sid;
47036f3be9f5SAndreas Gruenbacher 	newisec->initialized = LABEL_INITIALIZED;
47041da177e4SLinus Torvalds 
47051da177e4SLinus Torvalds 	return 0;
47061da177e4SLinus Torvalds }
47071da177e4SLinus Torvalds 
47081da177e4SLinus Torvalds static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
47091da177e4SLinus Torvalds 				  int size)
47101da177e4SLinus Torvalds {
4711be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__WRITE);
47121da177e4SLinus Torvalds }
47131da177e4SLinus Torvalds 
47141da177e4SLinus Torvalds static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
47151da177e4SLinus Torvalds 				  int size, int flags)
47161da177e4SLinus Torvalds {
4717be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__READ);
47181da177e4SLinus Torvalds }
47191da177e4SLinus Torvalds 
47201da177e4SLinus Torvalds static int selinux_socket_getsockname(struct socket *sock)
47211da177e4SLinus Torvalds {
4722be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__GETATTR);
47231da177e4SLinus Torvalds }
47241da177e4SLinus Torvalds 
47251da177e4SLinus Torvalds static int selinux_socket_getpeername(struct socket *sock)
47261da177e4SLinus Torvalds {
4727be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__GETATTR);
47281da177e4SLinus Torvalds }
47291da177e4SLinus Torvalds 
47301da177e4SLinus Torvalds static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
47311da177e4SLinus Torvalds {
4732f8687afeSPaul Moore 	int err;
4733f8687afeSPaul Moore 
4734be0554c9SStephen Smalley 	err = sock_has_perm(sock->sk, SOCKET__SETOPT);
4735f8687afeSPaul Moore 	if (err)
4736f8687afeSPaul Moore 		return err;
4737f8687afeSPaul Moore 
4738f8687afeSPaul Moore 	return selinux_netlbl_socket_setsockopt(sock, level, optname);
47391da177e4SLinus Torvalds }
47401da177e4SLinus Torvalds 
47411da177e4SLinus Torvalds static int selinux_socket_getsockopt(struct socket *sock, int level,
47421da177e4SLinus Torvalds 				     int optname)
47431da177e4SLinus Torvalds {
4744be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__GETOPT);
47451da177e4SLinus Torvalds }
47461da177e4SLinus Torvalds 
47471da177e4SLinus Torvalds static int selinux_socket_shutdown(struct socket *sock, int how)
47481da177e4SLinus Torvalds {
4749be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__SHUTDOWN);
47501da177e4SLinus Torvalds }
47511da177e4SLinus Torvalds 
47523610cda5SDavid S. Miller static int selinux_socket_unix_stream_connect(struct sock *sock,
47533610cda5SDavid S. Miller 					      struct sock *other,
47541da177e4SLinus Torvalds 					      struct sock *newsk)
47551da177e4SLinus Torvalds {
47563610cda5SDavid S. Miller 	struct sk_security_struct *sksec_sock = sock->sk_security;
47573610cda5SDavid S. Miller 	struct sk_security_struct *sksec_other = other->sk_security;
47584d1e2451SPaul Moore 	struct sk_security_struct *sksec_new = newsk->sk_security;
47592bf49690SThomas Liu 	struct common_audit_data ad;
476048c62af6SEric Paris 	struct lsm_network_audit net = {0,};
47611da177e4SLinus Torvalds 	int err;
47621da177e4SLinus Torvalds 
476350c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
476448c62af6SEric Paris 	ad.u.net = &net;
476548c62af6SEric Paris 	ad.u.net->sk = other;
47661da177e4SLinus Torvalds 
47676b6bc620SStephen Smalley 	err = avc_has_perm(&selinux_state,
47686b6bc620SStephen Smalley 			   sksec_sock->sid, sksec_other->sid,
47694d1e2451SPaul Moore 			   sksec_other->sclass,
47701da177e4SLinus Torvalds 			   UNIX_STREAM_SOCKET__CONNECTTO, &ad);
47711da177e4SLinus Torvalds 	if (err)
47721da177e4SLinus Torvalds 		return err;
47731da177e4SLinus Torvalds 
47741da177e4SLinus Torvalds 	/* server child socket */
47754d1e2451SPaul Moore 	sksec_new->peer_sid = sksec_sock->sid;
4776aa8e712cSStephen Smalley 	err = security_sid_mls_copy(&selinux_state, sksec_other->sid,
4777aa8e712cSStephen Smalley 				    sksec_sock->sid, &sksec_new->sid);
47784d1e2451SPaul Moore 	if (err)
47794237c75cSVenkat Yekkirala 		return err;
47804d1e2451SPaul Moore 
47814d1e2451SPaul Moore 	/* connecting socket */
47824d1e2451SPaul Moore 	sksec_sock->peer_sid = sksec_new->sid;
47834d1e2451SPaul Moore 
47844d1e2451SPaul Moore 	return 0;
47851da177e4SLinus Torvalds }
47861da177e4SLinus Torvalds 
47871da177e4SLinus Torvalds static int selinux_socket_unix_may_send(struct socket *sock,
47881da177e4SLinus Torvalds 					struct socket *other)
47891da177e4SLinus Torvalds {
4790253bfae6SPaul Moore 	struct sk_security_struct *ssec = sock->sk->sk_security;
4791253bfae6SPaul Moore 	struct sk_security_struct *osec = other->sk->sk_security;
47922bf49690SThomas Liu 	struct common_audit_data ad;
479348c62af6SEric Paris 	struct lsm_network_audit net = {0,};
47941da177e4SLinus Torvalds 
479550c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
479648c62af6SEric Paris 	ad.u.net = &net;
479748c62af6SEric Paris 	ad.u.net->sk = other->sk;
47981da177e4SLinus Torvalds 
47996b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
48006b6bc620SStephen Smalley 			    ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
4801253bfae6SPaul Moore 			    &ad);
48021da177e4SLinus Torvalds }
48031da177e4SLinus Torvalds 
4804cbe0d6e8SPaul Moore static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
4805cbe0d6e8SPaul Moore 				    char *addrp, u16 family, u32 peer_sid,
48062bf49690SThomas Liu 				    struct common_audit_data *ad)
4807effad8dfSPaul Moore {
4808effad8dfSPaul Moore 	int err;
4809effad8dfSPaul Moore 	u32 if_sid;
4810effad8dfSPaul Moore 	u32 node_sid;
4811effad8dfSPaul Moore 
4812cbe0d6e8SPaul Moore 	err = sel_netif_sid(ns, ifindex, &if_sid);
4813effad8dfSPaul Moore 	if (err)
4814effad8dfSPaul Moore 		return err;
48156b6bc620SStephen Smalley 	err = avc_has_perm(&selinux_state,
48166b6bc620SStephen Smalley 			   peer_sid, if_sid,
4817effad8dfSPaul Moore 			   SECCLASS_NETIF, NETIF__INGRESS, ad);
4818effad8dfSPaul Moore 	if (err)
4819effad8dfSPaul Moore 		return err;
4820effad8dfSPaul Moore 
4821effad8dfSPaul Moore 	err = sel_netnode_sid(addrp, family, &node_sid);
4822effad8dfSPaul Moore 	if (err)
4823effad8dfSPaul Moore 		return err;
48246b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
48256b6bc620SStephen Smalley 			    peer_sid, node_sid,
4826effad8dfSPaul Moore 			    SECCLASS_NODE, NODE__RECVFROM, ad);
4827effad8dfSPaul Moore }
4828effad8dfSPaul Moore 
4829220deb96SPaul Moore static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
4830d8395c87SPaul Moore 				       u16 family)
4831220deb96SPaul Moore {
4832277d342fSPaul Moore 	int err = 0;
4833220deb96SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
4834220deb96SPaul Moore 	u32 sk_sid = sksec->sid;
48352bf49690SThomas Liu 	struct common_audit_data ad;
483648c62af6SEric Paris 	struct lsm_network_audit net = {0,};
4837d8395c87SPaul Moore 	char *addrp;
4838d8395c87SPaul Moore 
483950c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
484048c62af6SEric Paris 	ad.u.net = &net;
484148c62af6SEric Paris 	ad.u.net->netif = skb->skb_iif;
484248c62af6SEric Paris 	ad.u.net->family = family;
4843d8395c87SPaul Moore 	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4844d8395c87SPaul Moore 	if (err)
4845d8395c87SPaul Moore 		return err;
4846220deb96SPaul Moore 
484758bfbb51SPaul Moore 	if (selinux_secmark_enabled()) {
48486b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
48496b6bc620SStephen Smalley 				   sk_sid, skb->secmark, SECCLASS_PACKET,
4850d8395c87SPaul Moore 				   PACKET__RECV, &ad);
4851220deb96SPaul Moore 		if (err)
4852220deb96SPaul Moore 			return err;
485358bfbb51SPaul Moore 	}
4854220deb96SPaul Moore 
4855d8395c87SPaul Moore 	err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
4856220deb96SPaul Moore 	if (err)
4857220deb96SPaul Moore 		return err;
4858d8395c87SPaul Moore 	err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
4859220deb96SPaul Moore 
48604e5ab4cbSJames Morris 	return err;
48614e5ab4cbSJames Morris }
4862d28d1e08STrent Jaeger 
48634e5ab4cbSJames Morris static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
48644e5ab4cbSJames Morris {
4865220deb96SPaul Moore 	int err;
48664237c75cSVenkat Yekkirala 	struct sk_security_struct *sksec = sk->sk_security;
4867220deb96SPaul Moore 	u16 family = sk->sk_family;
4868220deb96SPaul Moore 	u32 sk_sid = sksec->sid;
48692bf49690SThomas Liu 	struct common_audit_data ad;
487048c62af6SEric Paris 	struct lsm_network_audit net = {0,};
4871220deb96SPaul Moore 	char *addrp;
4872d8395c87SPaul Moore 	u8 secmark_active;
4873d8395c87SPaul Moore 	u8 peerlbl_active;
48744e5ab4cbSJames Morris 
48754e5ab4cbSJames Morris 	if (family != PF_INET && family != PF_INET6)
4876220deb96SPaul Moore 		return 0;
48774e5ab4cbSJames Morris 
48784e5ab4cbSJames Morris 	/* Handle mapped IPv4 packets arriving via IPv6 sockets */
487987fcd70dSAl Viro 	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
48804e5ab4cbSJames Morris 		family = PF_INET;
48814e5ab4cbSJames Morris 
4882d8395c87SPaul Moore 	/* If any sort of compatibility mode is enabled then handoff processing
4883d8395c87SPaul Moore 	 * to the selinux_sock_rcv_skb_compat() function to deal with the
4884d8395c87SPaul Moore 	 * special handling.  We do this in an attempt to keep this function
4885d8395c87SPaul Moore 	 * as fast and as clean as possible. */
4886aa8e712cSStephen Smalley 	if (!selinux_policycap_netpeer())
4887d8395c87SPaul Moore 		return selinux_sock_rcv_skb_compat(sk, skb, family);
4888d8395c87SPaul Moore 
4889d8395c87SPaul Moore 	secmark_active = selinux_secmark_enabled();
48902be4d74fSChris PeBenito 	peerlbl_active = selinux_peerlbl_enabled();
4891d8395c87SPaul Moore 	if (!secmark_active && !peerlbl_active)
4892d8395c87SPaul Moore 		return 0;
4893d8395c87SPaul Moore 
489450c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
489548c62af6SEric Paris 	ad.u.net = &net;
489648c62af6SEric Paris 	ad.u.net->netif = skb->skb_iif;
489748c62af6SEric Paris 	ad.u.net->family = family;
4898224dfbd8SPaul Moore 	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
48994e5ab4cbSJames Morris 	if (err)
4900220deb96SPaul Moore 		return err;
49014e5ab4cbSJames Morris 
4902d8395c87SPaul Moore 	if (peerlbl_active) {
4903d621d35eSPaul Moore 		u32 peer_sid;
4904220deb96SPaul Moore 
4905220deb96SPaul Moore 		err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4906220deb96SPaul Moore 		if (err)
4907220deb96SPaul Moore 			return err;
4908cbe0d6e8SPaul Moore 		err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
4909cbe0d6e8SPaul Moore 					       addrp, family, peer_sid, &ad);
4910dfaebe98SPaul Moore 		if (err) {
4911a04e71f6SHuw Davies 			selinux_netlbl_err(skb, family, err, 0);
4912effad8dfSPaul Moore 			return err;
4913dfaebe98SPaul Moore 		}
49146b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
49156b6bc620SStephen Smalley 				   sk_sid, peer_sid, SECCLASS_PEER,
4916d621d35eSPaul Moore 				   PEER__RECV, &ad);
491746d01d63SChad Hanson 		if (err) {
4918a04e71f6SHuw Davies 			selinux_netlbl_err(skb, family, err, 0);
491946d01d63SChad Hanson 			return err;
492046d01d63SChad Hanson 		}
4921d621d35eSPaul Moore 	}
4922d621d35eSPaul Moore 
4923d8395c87SPaul Moore 	if (secmark_active) {
49246b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
49256b6bc620SStephen Smalley 				   sk_sid, skb->secmark, SECCLASS_PACKET,
4926effad8dfSPaul Moore 				   PACKET__RECV, &ad);
4927effad8dfSPaul Moore 		if (err)
4928effad8dfSPaul Moore 			return err;
4929effad8dfSPaul Moore 	}
4930effad8dfSPaul Moore 
4931d621d35eSPaul Moore 	return err;
49321da177e4SLinus Torvalds }
49331da177e4SLinus Torvalds 
49342c7946a7SCatherine Zhang static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
49351da177e4SLinus Torvalds 					    int __user *optlen, unsigned len)
49361da177e4SLinus Torvalds {
49371da177e4SLinus Torvalds 	int err = 0;
49381da177e4SLinus Torvalds 	char *scontext;
49391da177e4SLinus Torvalds 	u32 scontext_len;
4940253bfae6SPaul Moore 	struct sk_security_struct *sksec = sock->sk->sk_security;
49413de4bab5SPaul Moore 	u32 peer_sid = SECSID_NULL;
49421da177e4SLinus Torvalds 
4943253bfae6SPaul Moore 	if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
4944d452930fSRichard Haines 	    sksec->sclass == SECCLASS_TCP_SOCKET ||
4945d452930fSRichard Haines 	    sksec->sclass == SECCLASS_SCTP_SOCKET)
4946dd3e7836SEric Paris 		peer_sid = sksec->peer_sid;
4947253bfae6SPaul Moore 	if (peer_sid == SECSID_NULL)
4948253bfae6SPaul Moore 		return -ENOPROTOOPT;
49491da177e4SLinus Torvalds 
4950aa8e712cSStephen Smalley 	err = security_sid_to_context(&selinux_state, peer_sid, &scontext,
4951aa8e712cSStephen Smalley 				      &scontext_len);
49521da177e4SLinus Torvalds 	if (err)
4953253bfae6SPaul Moore 		return err;
49541da177e4SLinus Torvalds 
49551da177e4SLinus Torvalds 	if (scontext_len > len) {
49561da177e4SLinus Torvalds 		err = -ERANGE;
49571da177e4SLinus Torvalds 		goto out_len;
49581da177e4SLinus Torvalds 	}
49591da177e4SLinus Torvalds 
49601da177e4SLinus Torvalds 	if (copy_to_user(optval, scontext, scontext_len))
49611da177e4SLinus Torvalds 		err = -EFAULT;
49621da177e4SLinus Torvalds 
49631da177e4SLinus Torvalds out_len:
49641da177e4SLinus Torvalds 	if (put_user(scontext_len, optlen))
49651da177e4SLinus Torvalds 		err = -EFAULT;
49661da177e4SLinus Torvalds 	kfree(scontext);
49671da177e4SLinus Torvalds 	return err;
49681da177e4SLinus Torvalds }
49691da177e4SLinus Torvalds 
4970dc49c1f9SCatherine Zhang static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
49712c7946a7SCatherine Zhang {
4972dc49c1f9SCatherine Zhang 	u32 peer_secid = SECSID_NULL;
497375e22910SPaul Moore 	u16 family;
4974899134f2SPaul Moore 	struct inode_security_struct *isec;
4975877ce7c1SCatherine Zhang 
4976aa862900SPaul Moore 	if (skb && skb->protocol == htons(ETH_P_IP))
4977aa862900SPaul Moore 		family = PF_INET;
4978aa862900SPaul Moore 	else if (skb && skb->protocol == htons(ETH_P_IPV6))
4979aa862900SPaul Moore 		family = PF_INET6;
4980aa862900SPaul Moore 	else if (sock)
498175e22910SPaul Moore 		family = sock->sk->sk_family;
498275e22910SPaul Moore 	else
498375e22910SPaul Moore 		goto out;
498475e22910SPaul Moore 
4985899134f2SPaul Moore 	if (sock && family == PF_UNIX) {
4986899134f2SPaul Moore 		isec = inode_security_novalidate(SOCK_INODE(sock));
4987899134f2SPaul Moore 		peer_secid = isec->sid;
4988899134f2SPaul Moore 	} else if (skb)
4989220deb96SPaul Moore 		selinux_skb_peerlbl_sid(skb, family, &peer_secid);
49902c7946a7SCatherine Zhang 
499175e22910SPaul Moore out:
4992dc49c1f9SCatherine Zhang 	*secid = peer_secid;
499375e22910SPaul Moore 	if (peer_secid == SECSID_NULL)
499475e22910SPaul Moore 		return -EINVAL;
499575e22910SPaul Moore 	return 0;
49962c7946a7SCatherine Zhang }
49972c7946a7SCatherine Zhang 
49987d877f3bSAl Viro static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
49991da177e4SLinus Torvalds {
500084914b7eSPaul Moore 	struct sk_security_struct *sksec;
500184914b7eSPaul Moore 
500284914b7eSPaul Moore 	sksec = kzalloc(sizeof(*sksec), priority);
500384914b7eSPaul Moore 	if (!sksec)
500484914b7eSPaul Moore 		return -ENOMEM;
500584914b7eSPaul Moore 
500684914b7eSPaul Moore 	sksec->peer_sid = SECINITSID_UNLABELED;
500784914b7eSPaul Moore 	sksec->sid = SECINITSID_UNLABELED;
50085dee25d0SStephen Smalley 	sksec->sclass = SECCLASS_SOCKET;
500984914b7eSPaul Moore 	selinux_netlbl_sk_security_reset(sksec);
501084914b7eSPaul Moore 	sk->sk_security = sksec;
501184914b7eSPaul Moore 
501284914b7eSPaul Moore 	return 0;
50131da177e4SLinus Torvalds }
50141da177e4SLinus Torvalds 
50151da177e4SLinus Torvalds static void selinux_sk_free_security(struct sock *sk)
50161da177e4SLinus Torvalds {
501784914b7eSPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
501884914b7eSPaul Moore 
501984914b7eSPaul Moore 	sk->sk_security = NULL;
502084914b7eSPaul Moore 	selinux_netlbl_sk_security_free(sksec);
502184914b7eSPaul Moore 	kfree(sksec);
50221da177e4SLinus Torvalds }
50231da177e4SLinus Torvalds 
5024892c141eSVenkat Yekkirala static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
5025892c141eSVenkat Yekkirala {
5026dd3e7836SEric Paris 	struct sk_security_struct *sksec = sk->sk_security;
5027dd3e7836SEric Paris 	struct sk_security_struct *newsksec = newsk->sk_security;
5028892c141eSVenkat Yekkirala 
5029dd3e7836SEric Paris 	newsksec->sid = sksec->sid;
5030dd3e7836SEric Paris 	newsksec->peer_sid = sksec->peer_sid;
5031dd3e7836SEric Paris 	newsksec->sclass = sksec->sclass;
503299f59ed0SPaul Moore 
5033dd3e7836SEric Paris 	selinux_netlbl_sk_security_reset(newsksec);
5034892c141eSVenkat Yekkirala }
5035892c141eSVenkat Yekkirala 
5036beb8d13bSVenkat Yekkirala static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
5037d28d1e08STrent Jaeger {
5038d28d1e08STrent Jaeger 	if (!sk)
5039beb8d13bSVenkat Yekkirala 		*secid = SECINITSID_ANY_SOCKET;
5040892c141eSVenkat Yekkirala 	else {
5041892c141eSVenkat Yekkirala 		struct sk_security_struct *sksec = sk->sk_security;
5042d28d1e08STrent Jaeger 
5043beb8d13bSVenkat Yekkirala 		*secid = sksec->sid;
5044892c141eSVenkat Yekkirala 	}
5045d28d1e08STrent Jaeger }
5046d28d1e08STrent Jaeger 
50479a673e56SAdrian Bunk static void selinux_sock_graft(struct sock *sk, struct socket *parent)
50484237c75cSVenkat Yekkirala {
50495d226df4SAndreas Gruenbacher 	struct inode_security_struct *isec =
50505d226df4SAndreas Gruenbacher 		inode_security_novalidate(SOCK_INODE(parent));
50514237c75cSVenkat Yekkirala 	struct sk_security_struct *sksec = sk->sk_security;
50524237c75cSVenkat Yekkirala 
50532873ead7SPaul Moore 	if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
50542873ead7SPaul Moore 	    sk->sk_family == PF_UNIX)
50554237c75cSVenkat Yekkirala 		isec->sid = sksec->sid;
5056220deb96SPaul Moore 	sksec->sclass = isec->sclass;
50574237c75cSVenkat Yekkirala }
50584237c75cSVenkat Yekkirala 
5059d452930fSRichard Haines /* Called whenever SCTP receives an INIT chunk. This happens when an incoming
5060d452930fSRichard Haines  * connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association
5061d452930fSRichard Haines  * already present).
5062d452930fSRichard Haines  */
5063d452930fSRichard Haines static int selinux_sctp_assoc_request(struct sctp_endpoint *ep,
5064d452930fSRichard Haines 				      struct sk_buff *skb)
5065d452930fSRichard Haines {
5066d452930fSRichard Haines 	struct sk_security_struct *sksec = ep->base.sk->sk_security;
5067d452930fSRichard Haines 	struct common_audit_data ad;
5068d452930fSRichard Haines 	struct lsm_network_audit net = {0,};
5069d452930fSRichard Haines 	u8 peerlbl_active;
5070d452930fSRichard Haines 	u32 peer_sid = SECINITSID_UNLABELED;
5071d452930fSRichard Haines 	u32 conn_sid;
5072d452930fSRichard Haines 	int err = 0;
5073d452930fSRichard Haines 
5074aa8e712cSStephen Smalley 	if (!selinux_policycap_extsockclass())
5075d452930fSRichard Haines 		return 0;
5076d452930fSRichard Haines 
5077d452930fSRichard Haines 	peerlbl_active = selinux_peerlbl_enabled();
5078d452930fSRichard Haines 
5079d452930fSRichard Haines 	if (peerlbl_active) {
5080d452930fSRichard Haines 		/* This will return peer_sid = SECSID_NULL if there are
5081d452930fSRichard Haines 		 * no peer labels, see security_net_peersid_resolve().
5082d452930fSRichard Haines 		 */
5083d452930fSRichard Haines 		err = selinux_skb_peerlbl_sid(skb, ep->base.sk->sk_family,
5084d452930fSRichard Haines 					      &peer_sid);
5085d452930fSRichard Haines 		if (err)
5086d452930fSRichard Haines 			return err;
5087d452930fSRichard Haines 
5088d452930fSRichard Haines 		if (peer_sid == SECSID_NULL)
5089d452930fSRichard Haines 			peer_sid = SECINITSID_UNLABELED;
5090d452930fSRichard Haines 	}
5091d452930fSRichard Haines 
5092d452930fSRichard Haines 	if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
5093d452930fSRichard Haines 		sksec->sctp_assoc_state = SCTP_ASSOC_SET;
5094d452930fSRichard Haines 
5095d452930fSRichard Haines 		/* Here as first association on socket. As the peer SID
5096d452930fSRichard Haines 		 * was allowed by peer recv (and the netif/node checks),
5097d452930fSRichard Haines 		 * then it is approved by policy and used as the primary
5098d452930fSRichard Haines 		 * peer SID for getpeercon(3).
5099d452930fSRichard Haines 		 */
5100d452930fSRichard Haines 		sksec->peer_sid = peer_sid;
5101d452930fSRichard Haines 	} else if  (sksec->peer_sid != peer_sid) {
5102d452930fSRichard Haines 		/* Other association peer SIDs are checked to enforce
5103d452930fSRichard Haines 		 * consistency among the peer SIDs.
5104d452930fSRichard Haines 		 */
5105d452930fSRichard Haines 		ad.type = LSM_AUDIT_DATA_NET;
5106d452930fSRichard Haines 		ad.u.net = &net;
5107d452930fSRichard Haines 		ad.u.net->sk = ep->base.sk;
51086b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
51096b6bc620SStephen Smalley 				   sksec->peer_sid, peer_sid, sksec->sclass,
5110d452930fSRichard Haines 				   SCTP_SOCKET__ASSOCIATION, &ad);
5111d452930fSRichard Haines 		if (err)
5112d452930fSRichard Haines 			return err;
5113d452930fSRichard Haines 	}
5114d452930fSRichard Haines 
5115d452930fSRichard Haines 	/* Compute the MLS component for the connection and store
5116d452930fSRichard Haines 	 * the information in ep. This will be used by SCTP TCP type
5117d452930fSRichard Haines 	 * sockets and peeled off connections as they cause a new
5118d452930fSRichard Haines 	 * socket to be generated. selinux_sctp_sk_clone() will then
5119d452930fSRichard Haines 	 * plug this into the new socket.
5120d452930fSRichard Haines 	 */
5121d452930fSRichard Haines 	err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid);
5122d452930fSRichard Haines 	if (err)
5123d452930fSRichard Haines 		return err;
5124d452930fSRichard Haines 
5125d452930fSRichard Haines 	ep->secid = conn_sid;
5126d452930fSRichard Haines 	ep->peer_secid = peer_sid;
5127d452930fSRichard Haines 
5128d452930fSRichard Haines 	/* Set any NetLabel labels including CIPSO/CALIPSO options. */
5129d452930fSRichard Haines 	return selinux_netlbl_sctp_assoc_request(ep, skb);
5130d452930fSRichard Haines }
5131d452930fSRichard Haines 
5132d452930fSRichard Haines /* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting
5133d452930fSRichard Haines  * based on their @optname.
5134d452930fSRichard Haines  */
5135d452930fSRichard Haines static int selinux_sctp_bind_connect(struct sock *sk, int optname,
5136d452930fSRichard Haines 				     struct sockaddr *address,
5137d452930fSRichard Haines 				     int addrlen)
5138d452930fSRichard Haines {
5139d452930fSRichard Haines 	int len, err = 0, walk_size = 0;
5140d452930fSRichard Haines 	void *addr_buf;
5141d452930fSRichard Haines 	struct sockaddr *addr;
5142d452930fSRichard Haines 	struct socket *sock;
5143d452930fSRichard Haines 
5144aa8e712cSStephen Smalley 	if (!selinux_policycap_extsockclass())
5145d452930fSRichard Haines 		return 0;
5146d452930fSRichard Haines 
5147d452930fSRichard Haines 	/* Process one or more addresses that may be IPv4 or IPv6 */
5148d452930fSRichard Haines 	sock = sk->sk_socket;
5149d452930fSRichard Haines 	addr_buf = address;
5150d452930fSRichard Haines 
5151d452930fSRichard Haines 	while (walk_size < addrlen) {
5152d452930fSRichard Haines 		addr = addr_buf;
5153d452930fSRichard Haines 		switch (addr->sa_family) {
51544152dc91SAlexey Kodanev 		case AF_UNSPEC:
5155d452930fSRichard Haines 		case AF_INET:
5156d452930fSRichard Haines 			len = sizeof(struct sockaddr_in);
5157d452930fSRichard Haines 			break;
5158d452930fSRichard Haines 		case AF_INET6:
5159d452930fSRichard Haines 			len = sizeof(struct sockaddr_in6);
5160d452930fSRichard Haines 			break;
5161d452930fSRichard Haines 		default:
51624152dc91SAlexey Kodanev 			return -EINVAL;
5163d452930fSRichard Haines 		}
5164d452930fSRichard Haines 
5165d452930fSRichard Haines 		err = -EINVAL;
5166d452930fSRichard Haines 		switch (optname) {
5167d452930fSRichard Haines 		/* Bind checks */
5168d452930fSRichard Haines 		case SCTP_PRIMARY_ADDR:
5169d452930fSRichard Haines 		case SCTP_SET_PEER_PRIMARY_ADDR:
5170d452930fSRichard Haines 		case SCTP_SOCKOPT_BINDX_ADD:
5171d452930fSRichard Haines 			err = selinux_socket_bind(sock, addr, len);
5172d452930fSRichard Haines 			break;
5173d452930fSRichard Haines 		/* Connect checks */
5174d452930fSRichard Haines 		case SCTP_SOCKOPT_CONNECTX:
5175d452930fSRichard Haines 		case SCTP_PARAM_SET_PRIMARY:
5176d452930fSRichard Haines 		case SCTP_PARAM_ADD_IP:
5177d452930fSRichard Haines 		case SCTP_SENDMSG_CONNECT:
5178d452930fSRichard Haines 			err = selinux_socket_connect_helper(sock, addr, len);
5179d452930fSRichard Haines 			if (err)
5180d452930fSRichard Haines 				return err;
5181d452930fSRichard Haines 
5182d452930fSRichard Haines 			/* As selinux_sctp_bind_connect() is called by the
5183d452930fSRichard Haines 			 * SCTP protocol layer, the socket is already locked,
5184d452930fSRichard Haines 			 * therefore selinux_netlbl_socket_connect_locked() is
5185d452930fSRichard Haines 			 * is called here. The situations handled are:
5186d452930fSRichard Haines 			 * sctp_connectx(3), sctp_sendmsg(3), sendmsg(2),
5187d452930fSRichard Haines 			 * whenever a new IP address is added or when a new
5188d452930fSRichard Haines 			 * primary address is selected.
5189d452930fSRichard Haines 			 * Note that an SCTP connect(2) call happens before
5190d452930fSRichard Haines 			 * the SCTP protocol layer and is handled via
5191d452930fSRichard Haines 			 * selinux_socket_connect().
5192d452930fSRichard Haines 			 */
5193d452930fSRichard Haines 			err = selinux_netlbl_socket_connect_locked(sk, addr);
5194d452930fSRichard Haines 			break;
5195d452930fSRichard Haines 		}
5196d452930fSRichard Haines 
5197d452930fSRichard Haines 		if (err)
5198d452930fSRichard Haines 			return err;
5199d452930fSRichard Haines 
5200d452930fSRichard Haines 		addr_buf += len;
5201d452930fSRichard Haines 		walk_size += len;
5202d452930fSRichard Haines 	}
5203d452930fSRichard Haines 
5204d452930fSRichard Haines 	return 0;
5205d452930fSRichard Haines }
5206d452930fSRichard Haines 
5207d452930fSRichard Haines /* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */
5208d452930fSRichard Haines static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
5209d452930fSRichard Haines 				  struct sock *newsk)
5210d452930fSRichard Haines {
5211d452930fSRichard Haines 	struct sk_security_struct *sksec = sk->sk_security;
5212d452930fSRichard Haines 	struct sk_security_struct *newsksec = newsk->sk_security;
5213d452930fSRichard Haines 
5214d452930fSRichard Haines 	/* If policy does not support SECCLASS_SCTP_SOCKET then call
5215d452930fSRichard Haines 	 * the non-sctp clone version.
5216d452930fSRichard Haines 	 */
5217aa8e712cSStephen Smalley 	if (!selinux_policycap_extsockclass())
5218d452930fSRichard Haines 		return selinux_sk_clone_security(sk, newsk);
5219d452930fSRichard Haines 
5220d452930fSRichard Haines 	newsksec->sid = ep->secid;
5221d452930fSRichard Haines 	newsksec->peer_sid = ep->peer_secid;
5222d452930fSRichard Haines 	newsksec->sclass = sksec->sclass;
5223d452930fSRichard Haines 	selinux_netlbl_sctp_sk_clone(sk, newsk);
5224d452930fSRichard Haines }
5225d452930fSRichard Haines 
52269a673e56SAdrian Bunk static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
52274237c75cSVenkat Yekkirala 				     struct request_sock *req)
52284237c75cSVenkat Yekkirala {
52294237c75cSVenkat Yekkirala 	struct sk_security_struct *sksec = sk->sk_security;
52304237c75cSVenkat Yekkirala 	int err;
52310b1f24e6SPaul Moore 	u16 family = req->rsk_ops->family;
5232446b8024SPaul Moore 	u32 connsid;
52334237c75cSVenkat Yekkirala 	u32 peersid;
52344237c75cSVenkat Yekkirala 
5235aa862900SPaul Moore 	err = selinux_skb_peerlbl_sid(skb, family, &peersid);
5236220deb96SPaul Moore 	if (err)
5237220deb96SPaul Moore 		return err;
5238446b8024SPaul Moore 	err = selinux_conn_sid(sksec->sid, peersid, &connsid);
52394237c75cSVenkat Yekkirala 	if (err)
52404237c75cSVenkat Yekkirala 		return err;
5241446b8024SPaul Moore 	req->secid = connsid;
52426b877699SVenkat Yekkirala 	req->peer_secid = peersid;
5243389fb800SPaul Moore 
5244389fb800SPaul Moore 	return selinux_netlbl_inet_conn_request(req, family);
52454237c75cSVenkat Yekkirala }
52464237c75cSVenkat Yekkirala 
52479a673e56SAdrian Bunk static void selinux_inet_csk_clone(struct sock *newsk,
52489a673e56SAdrian Bunk 				   const struct request_sock *req)
52494237c75cSVenkat Yekkirala {
52504237c75cSVenkat Yekkirala 	struct sk_security_struct *newsksec = newsk->sk_security;
52514237c75cSVenkat Yekkirala 
52524237c75cSVenkat Yekkirala 	newsksec->sid = req->secid;
52536b877699SVenkat Yekkirala 	newsksec->peer_sid = req->peer_secid;
52544237c75cSVenkat Yekkirala 	/* NOTE: Ideally, we should also get the isec->sid for the
52554237c75cSVenkat Yekkirala 	   new socket in sync, but we don't have the isec available yet.
52564237c75cSVenkat Yekkirala 	   So we will wait until sock_graft to do it, by which
52574237c75cSVenkat Yekkirala 	   time it will have been created and available. */
525899f59ed0SPaul Moore 
52599f2ad665SPaul Moore 	/* We don't need to take any sort of lock here as we are the only
52609f2ad665SPaul Moore 	 * thread with access to newsksec */
5261389fb800SPaul Moore 	selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
52624237c75cSVenkat Yekkirala }
52634237c75cSVenkat Yekkirala 
5264014ab19aSPaul Moore static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
52656b877699SVenkat Yekkirala {
5266aa862900SPaul Moore 	u16 family = sk->sk_family;
52676b877699SVenkat Yekkirala 	struct sk_security_struct *sksec = sk->sk_security;
52686b877699SVenkat Yekkirala 
5269aa862900SPaul Moore 	/* handle mapped IPv4 packets arriving via IPv6 sockets */
5270aa862900SPaul Moore 	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
5271aa862900SPaul Moore 		family = PF_INET;
5272aa862900SPaul Moore 
5273aa862900SPaul Moore 	selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
52746b877699SVenkat Yekkirala }
52756b877699SVenkat Yekkirala 
52762606fd1fSEric Paris static int selinux_secmark_relabel_packet(u32 sid)
52772606fd1fSEric Paris {
52782606fd1fSEric Paris 	const struct task_security_struct *__tsec;
52792606fd1fSEric Paris 	u32 tsid;
52802606fd1fSEric Paris 
52812606fd1fSEric Paris 	__tsec = current_security();
52822606fd1fSEric Paris 	tsid = __tsec->sid;
52832606fd1fSEric Paris 
52846b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
52856b6bc620SStephen Smalley 			    tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
52866b6bc620SStephen Smalley 			    NULL);
52872606fd1fSEric Paris }
52882606fd1fSEric Paris 
52892606fd1fSEric Paris static void selinux_secmark_refcount_inc(void)
52902606fd1fSEric Paris {
52912606fd1fSEric Paris 	atomic_inc(&selinux_secmark_refcount);
52922606fd1fSEric Paris }
52932606fd1fSEric Paris 
52942606fd1fSEric Paris static void selinux_secmark_refcount_dec(void)
52952606fd1fSEric Paris {
52962606fd1fSEric Paris 	atomic_dec(&selinux_secmark_refcount);
52972606fd1fSEric Paris }
52982606fd1fSEric Paris 
52999a673e56SAdrian Bunk static void selinux_req_classify_flow(const struct request_sock *req,
53009a673e56SAdrian Bunk 				      struct flowi *fl)
53014237c75cSVenkat Yekkirala {
53021d28f42cSDavid S. Miller 	fl->flowi_secid = req->secid;
53034237c75cSVenkat Yekkirala }
53044237c75cSVenkat Yekkirala 
53055dbbaf2dSPaul Moore static int selinux_tun_dev_alloc_security(void **security)
53065dbbaf2dSPaul Moore {
53075dbbaf2dSPaul Moore 	struct tun_security_struct *tunsec;
53085dbbaf2dSPaul Moore 
53095dbbaf2dSPaul Moore 	tunsec = kzalloc(sizeof(*tunsec), GFP_KERNEL);
53105dbbaf2dSPaul Moore 	if (!tunsec)
53115dbbaf2dSPaul Moore 		return -ENOMEM;
53125dbbaf2dSPaul Moore 	tunsec->sid = current_sid();
53135dbbaf2dSPaul Moore 
53145dbbaf2dSPaul Moore 	*security = tunsec;
53155dbbaf2dSPaul Moore 	return 0;
53165dbbaf2dSPaul Moore }
53175dbbaf2dSPaul Moore 
53185dbbaf2dSPaul Moore static void selinux_tun_dev_free_security(void *security)
53195dbbaf2dSPaul Moore {
53205dbbaf2dSPaul Moore 	kfree(security);
53215dbbaf2dSPaul Moore }
53225dbbaf2dSPaul Moore 
5323ed6d76e4SPaul Moore static int selinux_tun_dev_create(void)
5324ed6d76e4SPaul Moore {
5325ed6d76e4SPaul Moore 	u32 sid = current_sid();
5326ed6d76e4SPaul Moore 
5327ed6d76e4SPaul Moore 	/* we aren't taking into account the "sockcreate" SID since the socket
5328ed6d76e4SPaul Moore 	 * that is being created here is not a socket in the traditional sense,
5329ed6d76e4SPaul Moore 	 * instead it is a private sock, accessible only to the kernel, and
5330ed6d76e4SPaul Moore 	 * representing a wide range of network traffic spanning multiple
5331ed6d76e4SPaul Moore 	 * connections unlike traditional sockets - check the TUN driver to
5332ed6d76e4SPaul Moore 	 * get a better understanding of why this socket is special */
5333ed6d76e4SPaul Moore 
53346b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
53356b6bc620SStephen Smalley 			    sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
5336ed6d76e4SPaul Moore 			    NULL);
5337ed6d76e4SPaul Moore }
5338ed6d76e4SPaul Moore 
53395dbbaf2dSPaul Moore static int selinux_tun_dev_attach_queue(void *security)
5340ed6d76e4SPaul Moore {
53415dbbaf2dSPaul Moore 	struct tun_security_struct *tunsec = security;
53425dbbaf2dSPaul Moore 
53436b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
53446b6bc620SStephen Smalley 			    current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
53455dbbaf2dSPaul Moore 			    TUN_SOCKET__ATTACH_QUEUE, NULL);
53465dbbaf2dSPaul Moore }
53475dbbaf2dSPaul Moore 
53485dbbaf2dSPaul Moore static int selinux_tun_dev_attach(struct sock *sk, void *security)
53495dbbaf2dSPaul Moore {
53505dbbaf2dSPaul Moore 	struct tun_security_struct *tunsec = security;
5351ed6d76e4SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
5352ed6d76e4SPaul Moore 
5353ed6d76e4SPaul Moore 	/* we don't currently perform any NetLabel based labeling here and it
5354ed6d76e4SPaul Moore 	 * isn't clear that we would want to do so anyway; while we could apply
5355ed6d76e4SPaul Moore 	 * labeling without the support of the TUN user the resulting labeled
5356ed6d76e4SPaul Moore 	 * traffic from the other end of the connection would almost certainly
5357ed6d76e4SPaul Moore 	 * cause confusion to the TUN user that had no idea network labeling
5358ed6d76e4SPaul Moore 	 * protocols were being used */
5359ed6d76e4SPaul Moore 
53605dbbaf2dSPaul Moore 	sksec->sid = tunsec->sid;
5361ed6d76e4SPaul Moore 	sksec->sclass = SECCLASS_TUN_SOCKET;
53625dbbaf2dSPaul Moore 
53635dbbaf2dSPaul Moore 	return 0;
5364ed6d76e4SPaul Moore }
5365ed6d76e4SPaul Moore 
53665dbbaf2dSPaul Moore static int selinux_tun_dev_open(void *security)
5367ed6d76e4SPaul Moore {
53685dbbaf2dSPaul Moore 	struct tun_security_struct *tunsec = security;
5369ed6d76e4SPaul Moore 	u32 sid = current_sid();
5370ed6d76e4SPaul Moore 	int err;
5371ed6d76e4SPaul Moore 
53726b6bc620SStephen Smalley 	err = avc_has_perm(&selinux_state,
53736b6bc620SStephen Smalley 			   sid, tunsec->sid, SECCLASS_TUN_SOCKET,
5374ed6d76e4SPaul Moore 			   TUN_SOCKET__RELABELFROM, NULL);
5375ed6d76e4SPaul Moore 	if (err)
5376ed6d76e4SPaul Moore 		return err;
53776b6bc620SStephen Smalley 	err = avc_has_perm(&selinux_state,
53786b6bc620SStephen Smalley 			   sid, sid, SECCLASS_TUN_SOCKET,
5379ed6d76e4SPaul Moore 			   TUN_SOCKET__RELABELTO, NULL);
5380ed6d76e4SPaul Moore 	if (err)
5381ed6d76e4SPaul Moore 		return err;
53825dbbaf2dSPaul Moore 	tunsec->sid = sid;
5383ed6d76e4SPaul Moore 
5384ed6d76e4SPaul Moore 	return 0;
5385ed6d76e4SPaul Moore }
5386ed6d76e4SPaul Moore 
53871da177e4SLinus Torvalds static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
53881da177e4SLinus Torvalds {
53891da177e4SLinus Torvalds 	int err = 0;
53901da177e4SLinus Torvalds 	u32 perm;
53911da177e4SLinus Torvalds 	struct nlmsghdr *nlh;
5392253bfae6SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
53931da177e4SLinus Torvalds 
539477954983SHong zhi guo 	if (skb->len < NLMSG_HDRLEN) {
53951da177e4SLinus Torvalds 		err = -EINVAL;
53961da177e4SLinus Torvalds 		goto out;
53971da177e4SLinus Torvalds 	}
5398b529ccf2SArnaldo Carvalho de Melo 	nlh = nlmsg_hdr(skb);
53991da177e4SLinus Torvalds 
5400253bfae6SPaul Moore 	err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
54011da177e4SLinus Torvalds 	if (err) {
54021da177e4SLinus Torvalds 		if (err == -EINVAL) {
540376319946SVladis Dronov 			pr_warn_ratelimited("SELinux: unrecognized netlink"
540476319946SVladis Dronov 			       " message: protocol=%hu nlmsg_type=%hu sclass=%s"
540576319946SVladis Dronov 			       " pig=%d comm=%s\n",
5406cded3fffSMarek Milkovic 			       sk->sk_protocol, nlh->nlmsg_type,
540776319946SVladis Dronov 			       secclass_map[sksec->sclass - 1].name,
540876319946SVladis Dronov 			       task_pid_nr(current), current->comm);
5409e5a5ca96SPaul Moore 			if (!enforcing_enabled(&selinux_state) ||
5410aa8e712cSStephen Smalley 			    security_get_allow_unknown(&selinux_state))
54111da177e4SLinus Torvalds 				err = 0;
54121da177e4SLinus Torvalds 		}
54131da177e4SLinus Torvalds 
54141da177e4SLinus Torvalds 		/* Ignore */
54151da177e4SLinus Torvalds 		if (err == -ENOENT)
54161da177e4SLinus Torvalds 			err = 0;
54171da177e4SLinus Torvalds 		goto out;
54181da177e4SLinus Torvalds 	}
54191da177e4SLinus Torvalds 
5420be0554c9SStephen Smalley 	err = sock_has_perm(sk, perm);
54211da177e4SLinus Torvalds out:
54221da177e4SLinus Torvalds 	return err;
54231da177e4SLinus Torvalds }
54241da177e4SLinus Torvalds 
54251da177e4SLinus Torvalds #ifdef CONFIG_NETFILTER
54261da177e4SLinus Torvalds 
5427cbe0d6e8SPaul Moore static unsigned int selinux_ip_forward(struct sk_buff *skb,
5428cbe0d6e8SPaul Moore 				       const struct net_device *indev,
5429effad8dfSPaul Moore 				       u16 family)
54301da177e4SLinus Torvalds {
5431dfaebe98SPaul Moore 	int err;
5432effad8dfSPaul Moore 	char *addrp;
5433effad8dfSPaul Moore 	u32 peer_sid;
54342bf49690SThomas Liu 	struct common_audit_data ad;
543548c62af6SEric Paris 	struct lsm_network_audit net = {0,};
5436effad8dfSPaul Moore 	u8 secmark_active;
5437948bf85cSPaul Moore 	u8 netlbl_active;
5438effad8dfSPaul Moore 	u8 peerlbl_active;
54394237c75cSVenkat Yekkirala 
5440aa8e712cSStephen Smalley 	if (!selinux_policycap_netpeer())
5441effad8dfSPaul Moore 		return NF_ACCEPT;
54424237c75cSVenkat Yekkirala 
5443effad8dfSPaul Moore 	secmark_active = selinux_secmark_enabled();
5444948bf85cSPaul Moore 	netlbl_active = netlbl_enabled();
54452be4d74fSChris PeBenito 	peerlbl_active = selinux_peerlbl_enabled();
5446effad8dfSPaul Moore 	if (!secmark_active && !peerlbl_active)
5447effad8dfSPaul Moore 		return NF_ACCEPT;
54484237c75cSVenkat Yekkirala 
5449d8395c87SPaul Moore 	if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
5450d8395c87SPaul Moore 		return NF_DROP;
5451d8395c87SPaul Moore 
545250c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
545348c62af6SEric Paris 	ad.u.net = &net;
5454cbe0d6e8SPaul Moore 	ad.u.net->netif = indev->ifindex;
545548c62af6SEric Paris 	ad.u.net->family = family;
5456effad8dfSPaul Moore 	if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
5457effad8dfSPaul Moore 		return NF_DROP;
54581da177e4SLinus Torvalds 
5459dfaebe98SPaul Moore 	if (peerlbl_active) {
5460cbe0d6e8SPaul Moore 		err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
5461cbe0d6e8SPaul Moore 					       addrp, family, peer_sid, &ad);
5462dfaebe98SPaul Moore 		if (err) {
5463a04e71f6SHuw Davies 			selinux_netlbl_err(skb, family, err, 1);
5464effad8dfSPaul Moore 			return NF_DROP;
5465dfaebe98SPaul Moore 		}
5466dfaebe98SPaul Moore 	}
5467effad8dfSPaul Moore 
5468effad8dfSPaul Moore 	if (secmark_active)
54696b6bc620SStephen Smalley 		if (avc_has_perm(&selinux_state,
54706b6bc620SStephen Smalley 				 peer_sid, skb->secmark,
5471effad8dfSPaul Moore 				 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
5472effad8dfSPaul Moore 			return NF_DROP;
5473effad8dfSPaul Moore 
5474948bf85cSPaul Moore 	if (netlbl_active)
5475948bf85cSPaul Moore 		/* we do this in the FORWARD path and not the POST_ROUTING
5476948bf85cSPaul Moore 		 * path because we want to make sure we apply the necessary
5477948bf85cSPaul Moore 		 * labeling before IPsec is applied so we can leverage AH
5478948bf85cSPaul Moore 		 * protection */
5479948bf85cSPaul Moore 		if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
5480948bf85cSPaul Moore 			return NF_DROP;
5481948bf85cSPaul Moore 
5482effad8dfSPaul Moore 	return NF_ACCEPT;
5483effad8dfSPaul Moore }
5484effad8dfSPaul Moore 
548506198b34SEric W. Biederman static unsigned int selinux_ipv4_forward(void *priv,
5486effad8dfSPaul Moore 					 struct sk_buff *skb,
5487238e54c9SDavid S. Miller 					 const struct nf_hook_state *state)
5488effad8dfSPaul Moore {
5489238e54c9SDavid S. Miller 	return selinux_ip_forward(skb, state->in, PF_INET);
5490effad8dfSPaul Moore }
5491effad8dfSPaul Moore 
54921a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
549306198b34SEric W. Biederman static unsigned int selinux_ipv6_forward(void *priv,
5494effad8dfSPaul Moore 					 struct sk_buff *skb,
5495238e54c9SDavid S. Miller 					 const struct nf_hook_state *state)
5496effad8dfSPaul Moore {
5497238e54c9SDavid S. Miller 	return selinux_ip_forward(skb, state->in, PF_INET6);
5498effad8dfSPaul Moore }
5499effad8dfSPaul Moore #endif	/* IPV6 */
5500effad8dfSPaul Moore 
5501948bf85cSPaul Moore static unsigned int selinux_ip_output(struct sk_buff *skb,
5502948bf85cSPaul Moore 				      u16 family)
5503948bf85cSPaul Moore {
550447180068SPaul Moore 	struct sock *sk;
5505948bf85cSPaul Moore 	u32 sid;
5506948bf85cSPaul Moore 
5507948bf85cSPaul Moore 	if (!netlbl_enabled())
5508948bf85cSPaul Moore 		return NF_ACCEPT;
5509948bf85cSPaul Moore 
5510948bf85cSPaul Moore 	/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
5511948bf85cSPaul Moore 	 * because we want to make sure we apply the necessary labeling
5512948bf85cSPaul Moore 	 * before IPsec is applied so we can leverage AH protection */
551347180068SPaul Moore 	sk = skb->sk;
551447180068SPaul Moore 	if (sk) {
551547180068SPaul Moore 		struct sk_security_struct *sksec;
551647180068SPaul Moore 
5517e446f9dfSEric Dumazet 		if (sk_listener(sk))
551847180068SPaul Moore 			/* if the socket is the listening state then this
551947180068SPaul Moore 			 * packet is a SYN-ACK packet which means it needs to
552047180068SPaul Moore 			 * be labeled based on the connection/request_sock and
552147180068SPaul Moore 			 * not the parent socket.  unfortunately, we can't
552247180068SPaul Moore 			 * lookup the request_sock yet as it isn't queued on
552347180068SPaul Moore 			 * the parent socket until after the SYN-ACK is sent.
552447180068SPaul Moore 			 * the "solution" is to simply pass the packet as-is
552547180068SPaul Moore 			 * as any IP option based labeling should be copied
552647180068SPaul Moore 			 * from the initial connection request (in the IP
552747180068SPaul Moore 			 * layer).  it is far from ideal, but until we get a
552847180068SPaul Moore 			 * security label in the packet itself this is the
552947180068SPaul Moore 			 * best we can do. */
553047180068SPaul Moore 			return NF_ACCEPT;
553147180068SPaul Moore 
553247180068SPaul Moore 		/* standard practice, label using the parent socket */
553347180068SPaul Moore 		sksec = sk->sk_security;
5534948bf85cSPaul Moore 		sid = sksec->sid;
5535948bf85cSPaul Moore 	} else
5536948bf85cSPaul Moore 		sid = SECINITSID_KERNEL;
5537948bf85cSPaul Moore 	if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
5538948bf85cSPaul Moore 		return NF_DROP;
5539948bf85cSPaul Moore 
5540948bf85cSPaul Moore 	return NF_ACCEPT;
5541948bf85cSPaul Moore }
5542948bf85cSPaul Moore 
554306198b34SEric W. Biederman static unsigned int selinux_ipv4_output(void *priv,
5544948bf85cSPaul Moore 					struct sk_buff *skb,
5545238e54c9SDavid S. Miller 					const struct nf_hook_state *state)
5546948bf85cSPaul Moore {
5547948bf85cSPaul Moore 	return selinux_ip_output(skb, PF_INET);
5548948bf85cSPaul Moore }
5549948bf85cSPaul Moore 
55501a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
55512917f57bSHuw Davies static unsigned int selinux_ipv6_output(void *priv,
55522917f57bSHuw Davies 					struct sk_buff *skb,
55532917f57bSHuw Davies 					const struct nf_hook_state *state)
55542917f57bSHuw Davies {
55552917f57bSHuw Davies 	return selinux_ip_output(skb, PF_INET6);
55562917f57bSHuw Davies }
55572917f57bSHuw Davies #endif	/* IPV6 */
55582917f57bSHuw Davies 
5559effad8dfSPaul Moore static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
5560effad8dfSPaul Moore 						int ifindex,
5561d8395c87SPaul Moore 						u16 family)
55624e5ab4cbSJames Morris {
556354abc686SEric Dumazet 	struct sock *sk = skb_to_full_sk(skb);
55644237c75cSVenkat Yekkirala 	struct sk_security_struct *sksec;
55652bf49690SThomas Liu 	struct common_audit_data ad;
556648c62af6SEric Paris 	struct lsm_network_audit net = {0,};
5567d8395c87SPaul Moore 	char *addrp;
5568d8395c87SPaul Moore 	u8 proto;
55694e5ab4cbSJames Morris 
5570effad8dfSPaul Moore 	if (sk == NULL)
5571effad8dfSPaul Moore 		return NF_ACCEPT;
55724237c75cSVenkat Yekkirala 	sksec = sk->sk_security;
55734e5ab4cbSJames Morris 
557450c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
557548c62af6SEric Paris 	ad.u.net = &net;
557648c62af6SEric Paris 	ad.u.net->netif = ifindex;
557748c62af6SEric Paris 	ad.u.net->family = family;
5578d8395c87SPaul Moore 	if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
5579d8395c87SPaul Moore 		return NF_DROP;
5580d8395c87SPaul Moore 
558158bfbb51SPaul Moore 	if (selinux_secmark_enabled())
55826b6bc620SStephen Smalley 		if (avc_has_perm(&selinux_state,
55836b6bc620SStephen Smalley 				 sksec->sid, skb->secmark,
5584d8395c87SPaul Moore 				 SECCLASS_PACKET, PACKET__SEND, &ad))
55852fe66ec2SEric Paris 			return NF_DROP_ERR(-ECONNREFUSED);
55861da177e4SLinus Torvalds 
5587d8395c87SPaul Moore 	if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
55882fe66ec2SEric Paris 		return NF_DROP_ERR(-ECONNREFUSED);
5589effad8dfSPaul Moore 
5590effad8dfSPaul Moore 	return NF_ACCEPT;
5591effad8dfSPaul Moore }
5592effad8dfSPaul Moore 
5593cbe0d6e8SPaul Moore static unsigned int selinux_ip_postroute(struct sk_buff *skb,
5594cbe0d6e8SPaul Moore 					 const struct net_device *outdev,
5595effad8dfSPaul Moore 					 u16 family)
5596effad8dfSPaul Moore {
5597effad8dfSPaul Moore 	u32 secmark_perm;
5598effad8dfSPaul Moore 	u32 peer_sid;
5599cbe0d6e8SPaul Moore 	int ifindex = outdev->ifindex;
5600effad8dfSPaul Moore 	struct sock *sk;
56012bf49690SThomas Liu 	struct common_audit_data ad;
560248c62af6SEric Paris 	struct lsm_network_audit net = {0,};
5603effad8dfSPaul Moore 	char *addrp;
5604effad8dfSPaul Moore 	u8 secmark_active;
5605effad8dfSPaul Moore 	u8 peerlbl_active;
5606effad8dfSPaul Moore 
5607effad8dfSPaul Moore 	/* If any sort of compatibility mode is enabled then handoff processing
5608effad8dfSPaul Moore 	 * to the selinux_ip_postroute_compat() function to deal with the
5609effad8dfSPaul Moore 	 * special handling.  We do this in an attempt to keep this function
5610effad8dfSPaul Moore 	 * as fast and as clean as possible. */
5611aa8e712cSStephen Smalley 	if (!selinux_policycap_netpeer())
5612d8395c87SPaul Moore 		return selinux_ip_postroute_compat(skb, ifindex, family);
5613c0828e50SPaul Moore 
5614effad8dfSPaul Moore 	secmark_active = selinux_secmark_enabled();
56152be4d74fSChris PeBenito 	peerlbl_active = selinux_peerlbl_enabled();
5616effad8dfSPaul Moore 	if (!secmark_active && !peerlbl_active)
5617effad8dfSPaul Moore 		return NF_ACCEPT;
5618effad8dfSPaul Moore 
561954abc686SEric Dumazet 	sk = skb_to_full_sk(skb);
5620c0828e50SPaul Moore 
5621effad8dfSPaul Moore #ifdef CONFIG_XFRM
5622effad8dfSPaul Moore 	/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
5623effad8dfSPaul Moore 	 * packet transformation so allow the packet to pass without any checks
5624effad8dfSPaul Moore 	 * since we'll have another chance to perform access control checks
5625effad8dfSPaul Moore 	 * when the packet is on it's final way out.
5626effad8dfSPaul Moore 	 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
5627c0828e50SPaul Moore 	 *       is NULL, in this case go ahead and apply access control.
5628c0828e50SPaul Moore 	 * NOTE: if this is a local socket (skb->sk != NULL) that is in the
5629c0828e50SPaul Moore 	 *       TCP listening state we cannot wait until the XFRM processing
5630c0828e50SPaul Moore 	 *       is done as we will miss out on the SA label if we do;
5631c0828e50SPaul Moore 	 *       unfortunately, this means more work, but it is only once per
5632c0828e50SPaul Moore 	 *       connection. */
5633c0828e50SPaul Moore 	if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL &&
5634e446f9dfSEric Dumazet 	    !(sk && sk_listener(sk)))
5635effad8dfSPaul Moore 		return NF_ACCEPT;
5636effad8dfSPaul Moore #endif
5637effad8dfSPaul Moore 
5638d8395c87SPaul Moore 	if (sk == NULL) {
5639446b8024SPaul Moore 		/* Without an associated socket the packet is either coming
5640446b8024SPaul Moore 		 * from the kernel or it is being forwarded; check the packet
5641446b8024SPaul Moore 		 * to determine which and if the packet is being forwarded
5642446b8024SPaul Moore 		 * query the packet directly to determine the security label. */
56434a7ab3dcSSteffen Klassert 		if (skb->skb_iif) {
5644d8395c87SPaul Moore 			secmark_perm = PACKET__FORWARD_OUT;
5645d8395c87SPaul Moore 			if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
564604f6d70fSEric Paris 				return NF_DROP;
56474a7ab3dcSSteffen Klassert 		} else {
56484a7ab3dcSSteffen Klassert 			secmark_perm = PACKET__SEND;
5649d8395c87SPaul Moore 			peer_sid = SECINITSID_KERNEL;
56504a7ab3dcSSteffen Klassert 		}
5651e446f9dfSEric Dumazet 	} else if (sk_listener(sk)) {
5652446b8024SPaul Moore 		/* Locally generated packet but the associated socket is in the
5653446b8024SPaul Moore 		 * listening state which means this is a SYN-ACK packet.  In
5654446b8024SPaul Moore 		 * this particular case the correct security label is assigned
5655446b8024SPaul Moore 		 * to the connection/request_sock but unfortunately we can't
5656446b8024SPaul Moore 		 * query the request_sock as it isn't queued on the parent
5657446b8024SPaul Moore 		 * socket until after the SYN-ACK packet is sent; the only
5658446b8024SPaul Moore 		 * viable choice is to regenerate the label like we do in
5659446b8024SPaul Moore 		 * selinux_inet_conn_request().  See also selinux_ip_output()
5660446b8024SPaul Moore 		 * for similar problems. */
5661446b8024SPaul Moore 		u32 skb_sid;
5662e446f9dfSEric Dumazet 		struct sk_security_struct *sksec;
5663e446f9dfSEric Dumazet 
5664e446f9dfSEric Dumazet 		sksec = sk->sk_security;
5665446b8024SPaul Moore 		if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
5666446b8024SPaul Moore 			return NF_DROP;
5667c0828e50SPaul Moore 		/* At this point, if the returned skb peerlbl is SECSID_NULL
5668c0828e50SPaul Moore 		 * and the packet has been through at least one XFRM
5669c0828e50SPaul Moore 		 * transformation then we must be dealing with the "final"
5670c0828e50SPaul Moore 		 * form of labeled IPsec packet; since we've already applied
5671c0828e50SPaul Moore 		 * all of our access controls on this packet we can safely
5672c0828e50SPaul Moore 		 * pass the packet. */
5673c0828e50SPaul Moore 		if (skb_sid == SECSID_NULL) {
5674c0828e50SPaul Moore 			switch (family) {
5675c0828e50SPaul Moore 			case PF_INET:
5676c0828e50SPaul Moore 				if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
5677c0828e50SPaul Moore 					return NF_ACCEPT;
5678c0828e50SPaul Moore 				break;
5679c0828e50SPaul Moore 			case PF_INET6:
5680c0828e50SPaul Moore 				if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
5681c0828e50SPaul Moore 					return NF_ACCEPT;
5682a7a91a19SPaul Moore 				break;
5683c0828e50SPaul Moore 			default:
5684c0828e50SPaul Moore 				return NF_DROP_ERR(-ECONNREFUSED);
5685c0828e50SPaul Moore 			}
5686c0828e50SPaul Moore 		}
5687446b8024SPaul Moore 		if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid))
5688446b8024SPaul Moore 			return NF_DROP;
5689446b8024SPaul Moore 		secmark_perm = PACKET__SEND;
5690d8395c87SPaul Moore 	} else {
5691446b8024SPaul Moore 		/* Locally generated packet, fetch the security label from the
5692446b8024SPaul Moore 		 * associated socket. */
5693effad8dfSPaul Moore 		struct sk_security_struct *sksec = sk->sk_security;
5694effad8dfSPaul Moore 		peer_sid = sksec->sid;
5695effad8dfSPaul Moore 		secmark_perm = PACKET__SEND;
5696effad8dfSPaul Moore 	}
5697effad8dfSPaul Moore 
569850c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
569948c62af6SEric Paris 	ad.u.net = &net;
570048c62af6SEric Paris 	ad.u.net->netif = ifindex;
570148c62af6SEric Paris 	ad.u.net->family = family;
5702d8395c87SPaul Moore 	if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
570304f6d70fSEric Paris 		return NF_DROP;
5704d8395c87SPaul Moore 
5705effad8dfSPaul Moore 	if (secmark_active)
57066b6bc620SStephen Smalley 		if (avc_has_perm(&selinux_state,
57076b6bc620SStephen Smalley 				 peer_sid, skb->secmark,
5708effad8dfSPaul Moore 				 SECCLASS_PACKET, secmark_perm, &ad))
57091f1aaf82SEric Paris 			return NF_DROP_ERR(-ECONNREFUSED);
5710effad8dfSPaul Moore 
5711effad8dfSPaul Moore 	if (peerlbl_active) {
5712effad8dfSPaul Moore 		u32 if_sid;
5713effad8dfSPaul Moore 		u32 node_sid;
5714effad8dfSPaul Moore 
5715cbe0d6e8SPaul Moore 		if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
571604f6d70fSEric Paris 			return NF_DROP;
57176b6bc620SStephen Smalley 		if (avc_has_perm(&selinux_state,
57186b6bc620SStephen Smalley 				 peer_sid, if_sid,
5719effad8dfSPaul Moore 				 SECCLASS_NETIF, NETIF__EGRESS, &ad))
57201f1aaf82SEric Paris 			return NF_DROP_ERR(-ECONNREFUSED);
5721effad8dfSPaul Moore 
5722effad8dfSPaul Moore 		if (sel_netnode_sid(addrp, family, &node_sid))
572304f6d70fSEric Paris 			return NF_DROP;
57246b6bc620SStephen Smalley 		if (avc_has_perm(&selinux_state,
57256b6bc620SStephen Smalley 				 peer_sid, node_sid,
5726effad8dfSPaul Moore 				 SECCLASS_NODE, NODE__SENDTO, &ad))
57271f1aaf82SEric Paris 			return NF_DROP_ERR(-ECONNREFUSED);
5728effad8dfSPaul Moore 	}
5729effad8dfSPaul Moore 
5730effad8dfSPaul Moore 	return NF_ACCEPT;
5731effad8dfSPaul Moore }
5732effad8dfSPaul Moore 
573306198b34SEric W. Biederman static unsigned int selinux_ipv4_postroute(void *priv,
5734a224be76SDavid S. Miller 					   struct sk_buff *skb,
5735238e54c9SDavid S. Miller 					   const struct nf_hook_state *state)
57361da177e4SLinus Torvalds {
5737238e54c9SDavid S. Miller 	return selinux_ip_postroute(skb, state->out, PF_INET);
57381da177e4SLinus Torvalds }
57391da177e4SLinus Torvalds 
57401a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
574106198b34SEric W. Biederman static unsigned int selinux_ipv6_postroute(void *priv,
5742a224be76SDavid S. Miller 					   struct sk_buff *skb,
5743238e54c9SDavid S. Miller 					   const struct nf_hook_state *state)
57441da177e4SLinus Torvalds {
5745238e54c9SDavid S. Miller 	return selinux_ip_postroute(skb, state->out, PF_INET6);
57461da177e4SLinus Torvalds }
57471da177e4SLinus Torvalds #endif	/* IPV6 */
57481da177e4SLinus Torvalds 
57491da177e4SLinus Torvalds #endif	/* CONFIG_NETFILTER */
57501da177e4SLinus Torvalds 
57511da177e4SLinus Torvalds static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
57521da177e4SLinus Torvalds {
5753941fc5b2SStephen Smalley 	return selinux_nlmsg_perm(sk, skb);
57541da177e4SLinus Torvalds }
57551da177e4SLinus Torvalds 
5756be0554c9SStephen Smalley static int ipc_alloc_security(struct kern_ipc_perm *perm,
57571da177e4SLinus Torvalds 			      u16 sclass)
57581da177e4SLinus Torvalds {
57591da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
57601da177e4SLinus Torvalds 
576189d155efSJames Morris 	isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
57621da177e4SLinus Torvalds 	if (!isec)
57631da177e4SLinus Torvalds 		return -ENOMEM;
57641da177e4SLinus Torvalds 
57651da177e4SLinus Torvalds 	isec->sclass = sclass;
5766be0554c9SStephen Smalley 	isec->sid = current_sid();
57671da177e4SLinus Torvalds 	perm->security = isec;
57681da177e4SLinus Torvalds 
57691da177e4SLinus Torvalds 	return 0;
57701da177e4SLinus Torvalds }
57711da177e4SLinus Torvalds 
57721da177e4SLinus Torvalds static void ipc_free_security(struct kern_ipc_perm *perm)
57731da177e4SLinus Torvalds {
57741da177e4SLinus Torvalds 	struct ipc_security_struct *isec = perm->security;
57751da177e4SLinus Torvalds 	perm->security = NULL;
57761da177e4SLinus Torvalds 	kfree(isec);
57771da177e4SLinus Torvalds }
57781da177e4SLinus Torvalds 
57791da177e4SLinus Torvalds static int msg_msg_alloc_security(struct msg_msg *msg)
57801da177e4SLinus Torvalds {
57811da177e4SLinus Torvalds 	struct msg_security_struct *msec;
57821da177e4SLinus Torvalds 
578389d155efSJames Morris 	msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL);
57841da177e4SLinus Torvalds 	if (!msec)
57851da177e4SLinus Torvalds 		return -ENOMEM;
57861da177e4SLinus Torvalds 
57871da177e4SLinus Torvalds 	msec->sid = SECINITSID_UNLABELED;
57881da177e4SLinus Torvalds 	msg->security = msec;
57891da177e4SLinus Torvalds 
57901da177e4SLinus Torvalds 	return 0;
57911da177e4SLinus Torvalds }
57921da177e4SLinus Torvalds 
57931da177e4SLinus Torvalds static void msg_msg_free_security(struct msg_msg *msg)
57941da177e4SLinus Torvalds {
57951da177e4SLinus Torvalds 	struct msg_security_struct *msec = msg->security;
57961da177e4SLinus Torvalds 
57971da177e4SLinus Torvalds 	msg->security = NULL;
57981da177e4SLinus Torvalds 	kfree(msec);
57991da177e4SLinus Torvalds }
58001da177e4SLinus Torvalds 
58011da177e4SLinus Torvalds static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
58026af963f1SStephen Smalley 			u32 perms)
58031da177e4SLinus Torvalds {
58041da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
58052bf49690SThomas Liu 	struct common_audit_data ad;
5806275bb41eSDavid Howells 	u32 sid = current_sid();
58071da177e4SLinus Torvalds 
58081da177e4SLinus Torvalds 	isec = ipc_perms->security;
58091da177e4SLinus Torvalds 
581050c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
58111da177e4SLinus Torvalds 	ad.u.ipc_id = ipc_perms->key;
58121da177e4SLinus Torvalds 
58136b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
58146b6bc620SStephen Smalley 			    sid, isec->sid, isec->sclass, perms, &ad);
58151da177e4SLinus Torvalds }
58161da177e4SLinus Torvalds 
58171da177e4SLinus Torvalds static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
58181da177e4SLinus Torvalds {
58191da177e4SLinus Torvalds 	return msg_msg_alloc_security(msg);
58201da177e4SLinus Torvalds }
58211da177e4SLinus Torvalds 
58221da177e4SLinus Torvalds static void selinux_msg_msg_free_security(struct msg_msg *msg)
58231da177e4SLinus Torvalds {
58241da177e4SLinus Torvalds 	msg_msg_free_security(msg);
58251da177e4SLinus Torvalds }
58261da177e4SLinus Torvalds 
58271da177e4SLinus Torvalds /* message queue security operations */
5828d8c6e854SEric W. Biederman static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
58291da177e4SLinus Torvalds {
58301da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
58312bf49690SThomas Liu 	struct common_audit_data ad;
5832275bb41eSDavid Howells 	u32 sid = current_sid();
58331da177e4SLinus Torvalds 	int rc;
58341da177e4SLinus Torvalds 
5835d8c6e854SEric W. Biederman 	rc = ipc_alloc_security(msq, SECCLASS_MSGQ);
58361da177e4SLinus Torvalds 	if (rc)
58371da177e4SLinus Torvalds 		return rc;
58381da177e4SLinus Torvalds 
5839d8c6e854SEric W. Biederman 	isec = msq->security;
58401da177e4SLinus Torvalds 
584150c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
5842d8c6e854SEric W. Biederman 	ad.u.ipc_id = msq->key;
58431da177e4SLinus Torvalds 
58446b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
58456b6bc620SStephen Smalley 			  sid, isec->sid, SECCLASS_MSGQ,
58461da177e4SLinus Torvalds 			  MSGQ__CREATE, &ad);
58471da177e4SLinus Torvalds 	if (rc) {
5848d8c6e854SEric W. Biederman 		ipc_free_security(msq);
58491da177e4SLinus Torvalds 		return rc;
58501da177e4SLinus Torvalds 	}
58511da177e4SLinus Torvalds 	return 0;
58521da177e4SLinus Torvalds }
58531da177e4SLinus Torvalds 
5854d8c6e854SEric W. Biederman static void selinux_msg_queue_free_security(struct kern_ipc_perm *msq)
58551da177e4SLinus Torvalds {
5856d8c6e854SEric W. Biederman 	ipc_free_security(msq);
58571da177e4SLinus Torvalds }
58581da177e4SLinus Torvalds 
5859d8c6e854SEric W. Biederman static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
58601da177e4SLinus Torvalds {
58611da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
58622bf49690SThomas Liu 	struct common_audit_data ad;
5863275bb41eSDavid Howells 	u32 sid = current_sid();
58641da177e4SLinus Torvalds 
5865d8c6e854SEric W. Biederman 	isec = msq->security;
58661da177e4SLinus Torvalds 
586750c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
5868d8c6e854SEric W. Biederman 	ad.u.ipc_id = msq->key;
58691da177e4SLinus Torvalds 
58706b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
58716b6bc620SStephen Smalley 			    sid, isec->sid, SECCLASS_MSGQ,
58721da177e4SLinus Torvalds 			    MSGQ__ASSOCIATE, &ad);
58731da177e4SLinus Torvalds }
58741da177e4SLinus Torvalds 
5875d8c6e854SEric W. Biederman static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
58761da177e4SLinus Torvalds {
58771da177e4SLinus Torvalds 	int err;
58781da177e4SLinus Torvalds 	int perms;
58791da177e4SLinus Torvalds 
58801da177e4SLinus Torvalds 	switch (cmd) {
58811da177e4SLinus Torvalds 	case IPC_INFO:
58821da177e4SLinus Torvalds 	case MSG_INFO:
58831da177e4SLinus Torvalds 		/* No specific object, just general system-wide information. */
58846b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
58856b6bc620SStephen Smalley 				    current_sid(), SECINITSID_KERNEL,
5886be0554c9SStephen Smalley 				    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
58871da177e4SLinus Torvalds 	case IPC_STAT:
58881da177e4SLinus Torvalds 	case MSG_STAT:
588923c8cec8SDavidlohr Bueso 	case MSG_STAT_ANY:
58901da177e4SLinus Torvalds 		perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
58911da177e4SLinus Torvalds 		break;
58921da177e4SLinus Torvalds 	case IPC_SET:
58931da177e4SLinus Torvalds 		perms = MSGQ__SETATTR;
58941da177e4SLinus Torvalds 		break;
58951da177e4SLinus Torvalds 	case IPC_RMID:
58961da177e4SLinus Torvalds 		perms = MSGQ__DESTROY;
58971da177e4SLinus Torvalds 		break;
58981da177e4SLinus Torvalds 	default:
58991da177e4SLinus Torvalds 		return 0;
59001da177e4SLinus Torvalds 	}
59011da177e4SLinus Torvalds 
5902d8c6e854SEric W. Biederman 	err = ipc_has_perm(msq, perms);
59031da177e4SLinus Torvalds 	return err;
59041da177e4SLinus Torvalds }
59051da177e4SLinus Torvalds 
5906d8c6e854SEric W. Biederman static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg)
59071da177e4SLinus Torvalds {
59081da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
59091da177e4SLinus Torvalds 	struct msg_security_struct *msec;
59102bf49690SThomas Liu 	struct common_audit_data ad;
5911275bb41eSDavid Howells 	u32 sid = current_sid();
59121da177e4SLinus Torvalds 	int rc;
59131da177e4SLinus Torvalds 
5914d8c6e854SEric W. Biederman 	isec = msq->security;
59151da177e4SLinus Torvalds 	msec = msg->security;
59161da177e4SLinus Torvalds 
59171da177e4SLinus Torvalds 	/*
59181da177e4SLinus Torvalds 	 * First time through, need to assign label to the message
59191da177e4SLinus Torvalds 	 */
59201da177e4SLinus Torvalds 	if (msec->sid == SECINITSID_UNLABELED) {
59211da177e4SLinus Torvalds 		/*
59221da177e4SLinus Torvalds 		 * Compute new sid based on current process and
59231da177e4SLinus Torvalds 		 * message queue this message will be stored in
59241da177e4SLinus Torvalds 		 */
5925aa8e712cSStephen Smalley 		rc = security_transition_sid(&selinux_state, sid, isec->sid,
5926aa8e712cSStephen Smalley 					     SECCLASS_MSG, NULL, &msec->sid);
59271da177e4SLinus Torvalds 		if (rc)
59281da177e4SLinus Torvalds 			return rc;
59291da177e4SLinus Torvalds 	}
59301da177e4SLinus Torvalds 
593150c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
5932d8c6e854SEric W. Biederman 	ad.u.ipc_id = msq->key;
59331da177e4SLinus Torvalds 
59341da177e4SLinus Torvalds 	/* Can this process write to the queue? */
59356b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
59366b6bc620SStephen Smalley 			  sid, isec->sid, SECCLASS_MSGQ,
59371da177e4SLinus Torvalds 			  MSGQ__WRITE, &ad);
59381da177e4SLinus Torvalds 	if (!rc)
59391da177e4SLinus Torvalds 		/* Can this process send the message */
59406b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
59416b6bc620SStephen Smalley 				  sid, msec->sid, SECCLASS_MSG,
5942275bb41eSDavid Howells 				  MSG__SEND, &ad);
59431da177e4SLinus Torvalds 	if (!rc)
59441da177e4SLinus Torvalds 		/* Can the message be put in the queue? */
59456b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
59466b6bc620SStephen Smalley 				  msec->sid, isec->sid, SECCLASS_MSGQ,
5947275bb41eSDavid Howells 				  MSGQ__ENQUEUE, &ad);
59481da177e4SLinus Torvalds 
59491da177e4SLinus Torvalds 	return rc;
59501da177e4SLinus Torvalds }
59511da177e4SLinus Torvalds 
5952d8c6e854SEric W. Biederman static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg,
59531da177e4SLinus Torvalds 				    struct task_struct *target,
59541da177e4SLinus Torvalds 				    long type, int mode)
59551da177e4SLinus Torvalds {
59561da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
59571da177e4SLinus Torvalds 	struct msg_security_struct *msec;
59582bf49690SThomas Liu 	struct common_audit_data ad;
5959275bb41eSDavid Howells 	u32 sid = task_sid(target);
59601da177e4SLinus Torvalds 	int rc;
59611da177e4SLinus Torvalds 
5962d8c6e854SEric W. Biederman 	isec = msq->security;
59631da177e4SLinus Torvalds 	msec = msg->security;
59641da177e4SLinus Torvalds 
596550c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
5966d8c6e854SEric W. Biederman 	ad.u.ipc_id = msq->key;
59671da177e4SLinus Torvalds 
59686b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
59696b6bc620SStephen Smalley 			  sid, isec->sid,
59701da177e4SLinus Torvalds 			  SECCLASS_MSGQ, MSGQ__READ, &ad);
59711da177e4SLinus Torvalds 	if (!rc)
59726b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
59736b6bc620SStephen Smalley 				  sid, msec->sid,
59741da177e4SLinus Torvalds 				  SECCLASS_MSG, MSG__RECEIVE, &ad);
59751da177e4SLinus Torvalds 	return rc;
59761da177e4SLinus Torvalds }
59771da177e4SLinus Torvalds 
59781da177e4SLinus Torvalds /* Shared Memory security operations */
59797191adffSEric W. Biederman static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
59801da177e4SLinus Torvalds {
59811da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
59822bf49690SThomas Liu 	struct common_audit_data ad;
5983275bb41eSDavid Howells 	u32 sid = current_sid();
59841da177e4SLinus Torvalds 	int rc;
59851da177e4SLinus Torvalds 
59867191adffSEric W. Biederman 	rc = ipc_alloc_security(shp, SECCLASS_SHM);
59871da177e4SLinus Torvalds 	if (rc)
59881da177e4SLinus Torvalds 		return rc;
59891da177e4SLinus Torvalds 
59907191adffSEric W. Biederman 	isec = shp->security;
59911da177e4SLinus Torvalds 
599250c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
59937191adffSEric W. Biederman 	ad.u.ipc_id = shp->key;
59941da177e4SLinus Torvalds 
59956b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
59966b6bc620SStephen Smalley 			  sid, isec->sid, SECCLASS_SHM,
59971da177e4SLinus Torvalds 			  SHM__CREATE, &ad);
59981da177e4SLinus Torvalds 	if (rc) {
59997191adffSEric W. Biederman 		ipc_free_security(shp);
60001da177e4SLinus Torvalds 		return rc;
60011da177e4SLinus Torvalds 	}
60021da177e4SLinus Torvalds 	return 0;
60031da177e4SLinus Torvalds }
60041da177e4SLinus Torvalds 
60057191adffSEric W. Biederman static void selinux_shm_free_security(struct kern_ipc_perm *shp)
60061da177e4SLinus Torvalds {
60077191adffSEric W. Biederman 	ipc_free_security(shp);
60081da177e4SLinus Torvalds }
60091da177e4SLinus Torvalds 
60107191adffSEric W. Biederman static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
60111da177e4SLinus Torvalds {
60121da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
60132bf49690SThomas Liu 	struct common_audit_data ad;
6014275bb41eSDavid Howells 	u32 sid = current_sid();
60151da177e4SLinus Torvalds 
60167191adffSEric W. Biederman 	isec = shp->security;
60171da177e4SLinus Torvalds 
601850c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
60197191adffSEric W. Biederman 	ad.u.ipc_id = shp->key;
60201da177e4SLinus Torvalds 
60216b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
60226b6bc620SStephen Smalley 			    sid, isec->sid, SECCLASS_SHM,
60231da177e4SLinus Torvalds 			    SHM__ASSOCIATE, &ad);
60241da177e4SLinus Torvalds }
60251da177e4SLinus Torvalds 
60261da177e4SLinus Torvalds /* Note, at this point, shp is locked down */
60277191adffSEric W. Biederman static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
60281da177e4SLinus Torvalds {
60291da177e4SLinus Torvalds 	int perms;
60301da177e4SLinus Torvalds 	int err;
60311da177e4SLinus Torvalds 
60321da177e4SLinus Torvalds 	switch (cmd) {
60331da177e4SLinus Torvalds 	case IPC_INFO:
60341da177e4SLinus Torvalds 	case SHM_INFO:
60351da177e4SLinus Torvalds 		/* No specific object, just general system-wide information. */
60366b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
60376b6bc620SStephen Smalley 				    current_sid(), SECINITSID_KERNEL,
6038be0554c9SStephen Smalley 				    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
60391da177e4SLinus Torvalds 	case IPC_STAT:
60401da177e4SLinus Torvalds 	case SHM_STAT:
6041c21a6970SDavidlohr Bueso 	case SHM_STAT_ANY:
60421da177e4SLinus Torvalds 		perms = SHM__GETATTR | SHM__ASSOCIATE;
60431da177e4SLinus Torvalds 		break;
60441da177e4SLinus Torvalds 	case IPC_SET:
60451da177e4SLinus Torvalds 		perms = SHM__SETATTR;
60461da177e4SLinus Torvalds 		break;
60471da177e4SLinus Torvalds 	case SHM_LOCK:
60481da177e4SLinus Torvalds 	case SHM_UNLOCK:
60491da177e4SLinus Torvalds 		perms = SHM__LOCK;
60501da177e4SLinus Torvalds 		break;
60511da177e4SLinus Torvalds 	case IPC_RMID:
60521da177e4SLinus Torvalds 		perms = SHM__DESTROY;
60531da177e4SLinus Torvalds 		break;
60541da177e4SLinus Torvalds 	default:
60551da177e4SLinus Torvalds 		return 0;
60561da177e4SLinus Torvalds 	}
60571da177e4SLinus Torvalds 
60587191adffSEric W. Biederman 	err = ipc_has_perm(shp, perms);
60591da177e4SLinus Torvalds 	return err;
60601da177e4SLinus Torvalds }
60611da177e4SLinus Torvalds 
60627191adffSEric W. Biederman static int selinux_shm_shmat(struct kern_ipc_perm *shp,
60631da177e4SLinus Torvalds 			     char __user *shmaddr, int shmflg)
60641da177e4SLinus Torvalds {
60651da177e4SLinus Torvalds 	u32 perms;
60661da177e4SLinus Torvalds 
60671da177e4SLinus Torvalds 	if (shmflg & SHM_RDONLY)
60681da177e4SLinus Torvalds 		perms = SHM__READ;
60691da177e4SLinus Torvalds 	else
60701da177e4SLinus Torvalds 		perms = SHM__READ | SHM__WRITE;
60711da177e4SLinus Torvalds 
60727191adffSEric W. Biederman 	return ipc_has_perm(shp, perms);
60731da177e4SLinus Torvalds }
60741da177e4SLinus Torvalds 
60751da177e4SLinus Torvalds /* Semaphore security operations */
6076aefad959SEric W. Biederman static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
60771da177e4SLinus Torvalds {
60781da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
60792bf49690SThomas Liu 	struct common_audit_data ad;
6080275bb41eSDavid Howells 	u32 sid = current_sid();
60811da177e4SLinus Torvalds 	int rc;
60821da177e4SLinus Torvalds 
6083aefad959SEric W. Biederman 	rc = ipc_alloc_security(sma, SECCLASS_SEM);
60841da177e4SLinus Torvalds 	if (rc)
60851da177e4SLinus Torvalds 		return rc;
60861da177e4SLinus Torvalds 
6087aefad959SEric W. Biederman 	isec = sma->security;
60881da177e4SLinus Torvalds 
608950c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
6090aefad959SEric W. Biederman 	ad.u.ipc_id = sma->key;
60911da177e4SLinus Torvalds 
60926b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
60936b6bc620SStephen Smalley 			  sid, isec->sid, SECCLASS_SEM,
60941da177e4SLinus Torvalds 			  SEM__CREATE, &ad);
60951da177e4SLinus Torvalds 	if (rc) {
6096aefad959SEric W. Biederman 		ipc_free_security(sma);
60971da177e4SLinus Torvalds 		return rc;
60981da177e4SLinus Torvalds 	}
60991da177e4SLinus Torvalds 	return 0;
61001da177e4SLinus Torvalds }
61011da177e4SLinus Torvalds 
6102aefad959SEric W. Biederman static void selinux_sem_free_security(struct kern_ipc_perm *sma)
61031da177e4SLinus Torvalds {
6104aefad959SEric W. Biederman 	ipc_free_security(sma);
61051da177e4SLinus Torvalds }
61061da177e4SLinus Torvalds 
6107aefad959SEric W. Biederman static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
61081da177e4SLinus Torvalds {
61091da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
61102bf49690SThomas Liu 	struct common_audit_data ad;
6111275bb41eSDavid Howells 	u32 sid = current_sid();
61121da177e4SLinus Torvalds 
6113aefad959SEric W. Biederman 	isec = sma->security;
61141da177e4SLinus Torvalds 
611550c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
6116aefad959SEric W. Biederman 	ad.u.ipc_id = sma->key;
61171da177e4SLinus Torvalds 
61186b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
61196b6bc620SStephen Smalley 			    sid, isec->sid, SECCLASS_SEM,
61201da177e4SLinus Torvalds 			    SEM__ASSOCIATE, &ad);
61211da177e4SLinus Torvalds }
61221da177e4SLinus Torvalds 
61231da177e4SLinus Torvalds /* Note, at this point, sma is locked down */
6124aefad959SEric W. Biederman static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
61251da177e4SLinus Torvalds {
61261da177e4SLinus Torvalds 	int err;
61271da177e4SLinus Torvalds 	u32 perms;
61281da177e4SLinus Torvalds 
61291da177e4SLinus Torvalds 	switch (cmd) {
61301da177e4SLinus Torvalds 	case IPC_INFO:
61311da177e4SLinus Torvalds 	case SEM_INFO:
61321da177e4SLinus Torvalds 		/* No specific object, just general system-wide information. */
61336b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
61346b6bc620SStephen Smalley 				    current_sid(), SECINITSID_KERNEL,
6135be0554c9SStephen Smalley 				    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
61361da177e4SLinus Torvalds 	case GETPID:
61371da177e4SLinus Torvalds 	case GETNCNT:
61381da177e4SLinus Torvalds 	case GETZCNT:
61391da177e4SLinus Torvalds 		perms = SEM__GETATTR;
61401da177e4SLinus Torvalds 		break;
61411da177e4SLinus Torvalds 	case GETVAL:
61421da177e4SLinus Torvalds 	case GETALL:
61431da177e4SLinus Torvalds 		perms = SEM__READ;
61441da177e4SLinus Torvalds 		break;
61451da177e4SLinus Torvalds 	case SETVAL:
61461da177e4SLinus Torvalds 	case SETALL:
61471da177e4SLinus Torvalds 		perms = SEM__WRITE;
61481da177e4SLinus Torvalds 		break;
61491da177e4SLinus Torvalds 	case IPC_RMID:
61501da177e4SLinus Torvalds 		perms = SEM__DESTROY;
61511da177e4SLinus Torvalds 		break;
61521da177e4SLinus Torvalds 	case IPC_SET:
61531da177e4SLinus Torvalds 		perms = SEM__SETATTR;
61541da177e4SLinus Torvalds 		break;
61551da177e4SLinus Torvalds 	case IPC_STAT:
61561da177e4SLinus Torvalds 	case SEM_STAT:
6157a280d6dcSDavidlohr Bueso 	case SEM_STAT_ANY:
61581da177e4SLinus Torvalds 		perms = SEM__GETATTR | SEM__ASSOCIATE;
61591da177e4SLinus Torvalds 		break;
61601da177e4SLinus Torvalds 	default:
61611da177e4SLinus Torvalds 		return 0;
61621da177e4SLinus Torvalds 	}
61631da177e4SLinus Torvalds 
6164aefad959SEric W. Biederman 	err = ipc_has_perm(sma, perms);
61651da177e4SLinus Torvalds 	return err;
61661da177e4SLinus Torvalds }
61671da177e4SLinus Torvalds 
6168aefad959SEric W. Biederman static int selinux_sem_semop(struct kern_ipc_perm *sma,
61691da177e4SLinus Torvalds 			     struct sembuf *sops, unsigned nsops, int alter)
61701da177e4SLinus Torvalds {
61711da177e4SLinus Torvalds 	u32 perms;
61721da177e4SLinus Torvalds 
61731da177e4SLinus Torvalds 	if (alter)
61741da177e4SLinus Torvalds 		perms = SEM__READ | SEM__WRITE;
61751da177e4SLinus Torvalds 	else
61761da177e4SLinus Torvalds 		perms = SEM__READ;
61771da177e4SLinus Torvalds 
6178aefad959SEric W. Biederman 	return ipc_has_perm(sma, perms);
61791da177e4SLinus Torvalds }
61801da177e4SLinus Torvalds 
61811da177e4SLinus Torvalds static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
61821da177e4SLinus Torvalds {
61831da177e4SLinus Torvalds 	u32 av = 0;
61841da177e4SLinus Torvalds 
61851da177e4SLinus Torvalds 	av = 0;
61861da177e4SLinus Torvalds 	if (flag & S_IRUGO)
61871da177e4SLinus Torvalds 		av |= IPC__UNIX_READ;
61881da177e4SLinus Torvalds 	if (flag & S_IWUGO)
61891da177e4SLinus Torvalds 		av |= IPC__UNIX_WRITE;
61901da177e4SLinus Torvalds 
61911da177e4SLinus Torvalds 	if (av == 0)
61921da177e4SLinus Torvalds 		return 0;
61931da177e4SLinus Torvalds 
61946af963f1SStephen Smalley 	return ipc_has_perm(ipcp, av);
61951da177e4SLinus Torvalds }
61961da177e4SLinus Torvalds 
6197713a04aeSAhmed S. Darwish static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
6198713a04aeSAhmed S. Darwish {
6199713a04aeSAhmed S. Darwish 	struct ipc_security_struct *isec = ipcp->security;
6200713a04aeSAhmed S. Darwish 	*secid = isec->sid;
6201713a04aeSAhmed S. Darwish }
6202713a04aeSAhmed S. Darwish 
62031da177e4SLinus Torvalds static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
62041da177e4SLinus Torvalds {
62051da177e4SLinus Torvalds 	if (inode)
62061da177e4SLinus Torvalds 		inode_doinit_with_dentry(inode, dentry);
62071da177e4SLinus Torvalds }
62081da177e4SLinus Torvalds 
62091da177e4SLinus Torvalds static int selinux_getprocattr(struct task_struct *p,
621004ff9708SAl Viro 			       char *name, char **value)
62111da177e4SLinus Torvalds {
6212275bb41eSDavid Howells 	const struct task_security_struct *__tsec;
62138c8570fbSDustin Kirkland 	u32 sid;
62141da177e4SLinus Torvalds 	int error;
621504ff9708SAl Viro 	unsigned len;
62161da177e4SLinus Torvalds 
6217275bb41eSDavid Howells 	rcu_read_lock();
6218275bb41eSDavid Howells 	__tsec = __task_cred(p)->security;
62191da177e4SLinus Torvalds 
6220be0554c9SStephen Smalley 	if (current != p) {
62216b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62226b6bc620SStephen Smalley 				     current_sid(), __tsec->sid,
6223be0554c9SStephen Smalley 				     SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
6224be0554c9SStephen Smalley 		if (error)
6225be0554c9SStephen Smalley 			goto bad;
6226be0554c9SStephen Smalley 	}
6227be0554c9SStephen Smalley 
62281da177e4SLinus Torvalds 	if (!strcmp(name, "current"))
6229275bb41eSDavid Howells 		sid = __tsec->sid;
62301da177e4SLinus Torvalds 	else if (!strcmp(name, "prev"))
6231275bb41eSDavid Howells 		sid = __tsec->osid;
62321da177e4SLinus Torvalds 	else if (!strcmp(name, "exec"))
6233275bb41eSDavid Howells 		sid = __tsec->exec_sid;
62341da177e4SLinus Torvalds 	else if (!strcmp(name, "fscreate"))
6235275bb41eSDavid Howells 		sid = __tsec->create_sid;
62364eb582cfSMichael LeMay 	else if (!strcmp(name, "keycreate"))
6237275bb41eSDavid Howells 		sid = __tsec->keycreate_sid;
623842c3e03eSEric Paris 	else if (!strcmp(name, "sockcreate"))
6239275bb41eSDavid Howells 		sid = __tsec->sockcreate_sid;
6240be0554c9SStephen Smalley 	else {
6241be0554c9SStephen Smalley 		error = -EINVAL;
6242be0554c9SStephen Smalley 		goto bad;
6243be0554c9SStephen Smalley 	}
6244275bb41eSDavid Howells 	rcu_read_unlock();
62451da177e4SLinus Torvalds 
62461da177e4SLinus Torvalds 	if (!sid)
62471da177e4SLinus Torvalds 		return 0;
62481da177e4SLinus Torvalds 
6249aa8e712cSStephen Smalley 	error = security_sid_to_context(&selinux_state, sid, value, &len);
625004ff9708SAl Viro 	if (error)
625104ff9708SAl Viro 		return error;
625204ff9708SAl Viro 	return len;
6253275bb41eSDavid Howells 
6254be0554c9SStephen Smalley bad:
6255275bb41eSDavid Howells 	rcu_read_unlock();
6256be0554c9SStephen Smalley 	return error;
62571da177e4SLinus Torvalds }
62581da177e4SLinus Torvalds 
6259b21507e2SStephen Smalley static int selinux_setprocattr(const char *name, void *value, size_t size)
62601da177e4SLinus Torvalds {
62611da177e4SLinus Torvalds 	struct task_security_struct *tsec;
6262d84f4f99SDavid Howells 	struct cred *new;
6263be0554c9SStephen Smalley 	u32 mysid = current_sid(), sid = 0, ptsid;
62641da177e4SLinus Torvalds 	int error;
62651da177e4SLinus Torvalds 	char *str = value;
62661da177e4SLinus Torvalds 
62671da177e4SLinus Torvalds 	/*
62681da177e4SLinus Torvalds 	 * Basic control over ability to set these attributes at all.
62691da177e4SLinus Torvalds 	 */
62701da177e4SLinus Torvalds 	if (!strcmp(name, "exec"))
62716b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62726b6bc620SStephen Smalley 				     mysid, mysid, SECCLASS_PROCESS,
6273be0554c9SStephen Smalley 				     PROCESS__SETEXEC, NULL);
62741da177e4SLinus Torvalds 	else if (!strcmp(name, "fscreate"))
62756b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62766b6bc620SStephen Smalley 				     mysid, mysid, SECCLASS_PROCESS,
6277be0554c9SStephen Smalley 				     PROCESS__SETFSCREATE, NULL);
62784eb582cfSMichael LeMay 	else if (!strcmp(name, "keycreate"))
62796b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62806b6bc620SStephen Smalley 				     mysid, mysid, SECCLASS_PROCESS,
6281be0554c9SStephen Smalley 				     PROCESS__SETKEYCREATE, NULL);
628242c3e03eSEric Paris 	else if (!strcmp(name, "sockcreate"))
62836b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62846b6bc620SStephen Smalley 				     mysid, mysid, SECCLASS_PROCESS,
6285be0554c9SStephen Smalley 				     PROCESS__SETSOCKCREATE, NULL);
62861da177e4SLinus Torvalds 	else if (!strcmp(name, "current"))
62876b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62886b6bc620SStephen Smalley 				     mysid, mysid, SECCLASS_PROCESS,
6289be0554c9SStephen Smalley 				     PROCESS__SETCURRENT, NULL);
62901da177e4SLinus Torvalds 	else
62911da177e4SLinus Torvalds 		error = -EINVAL;
62921da177e4SLinus Torvalds 	if (error)
62931da177e4SLinus Torvalds 		return error;
62941da177e4SLinus Torvalds 
62951da177e4SLinus Torvalds 	/* Obtain a SID for the context, if one was specified. */
6296a050a570SStephen Smalley 	if (size && str[0] && str[0] != '\n') {
62971da177e4SLinus Torvalds 		if (str[size-1] == '\n') {
62981da177e4SLinus Torvalds 			str[size-1] = 0;
62991da177e4SLinus Torvalds 			size--;
63001da177e4SLinus Torvalds 		}
6301aa8e712cSStephen Smalley 		error = security_context_to_sid(&selinux_state, value, size,
6302aa8e712cSStephen Smalley 						&sid, GFP_KERNEL);
630312b29f34SStephen Smalley 		if (error == -EINVAL && !strcmp(name, "fscreate")) {
6304db59000aSStephen Smalley 			if (!has_cap_mac_admin(true)) {
6305d6ea83ecSEric Paris 				struct audit_buffer *ab;
6306d6ea83ecSEric Paris 				size_t audit_size;
6307d6ea83ecSEric Paris 
6308d6ea83ecSEric Paris 				/* We strip a nul only if it is at the end, otherwise the
6309d6ea83ecSEric Paris 				 * context contains a nul and we should audit that */
6310d6ea83ecSEric Paris 				if (str[size - 1] == '\0')
6311d6ea83ecSEric Paris 					audit_size = size - 1;
6312d6ea83ecSEric Paris 				else
6313d6ea83ecSEric Paris 					audit_size = size;
6314cdfb6b34SRichard Guy Briggs 				ab = audit_log_start(audit_context(),
6315cdfb6b34SRichard Guy Briggs 						     GFP_ATOMIC,
6316cdfb6b34SRichard Guy Briggs 						     AUDIT_SELINUX_ERR);
6317d6ea83ecSEric Paris 				audit_log_format(ab, "op=fscreate invalid_context=");
6318d6ea83ecSEric Paris 				audit_log_n_untrustedstring(ab, value, audit_size);
6319d6ea83ecSEric Paris 				audit_log_end(ab);
6320d6ea83ecSEric Paris 
632112b29f34SStephen Smalley 				return error;
6322d6ea83ecSEric Paris 			}
6323aa8e712cSStephen Smalley 			error = security_context_to_sid_force(
6324aa8e712cSStephen Smalley 						      &selinux_state,
6325aa8e712cSStephen Smalley 						      value, size, &sid);
632612b29f34SStephen Smalley 		}
63271da177e4SLinus Torvalds 		if (error)
63281da177e4SLinus Torvalds 			return error;
63291da177e4SLinus Torvalds 	}
63301da177e4SLinus Torvalds 
6331d84f4f99SDavid Howells 	new = prepare_creds();
6332d84f4f99SDavid Howells 	if (!new)
6333d84f4f99SDavid Howells 		return -ENOMEM;
6334d84f4f99SDavid Howells 
63351da177e4SLinus Torvalds 	/* Permission checking based on the specified context is
63361da177e4SLinus Torvalds 	   performed during the actual operation (execve,
63371da177e4SLinus Torvalds 	   open/mkdir/...), when we know the full context of the
6338d84f4f99SDavid Howells 	   operation.  See selinux_bprm_set_creds for the execve
63391da177e4SLinus Torvalds 	   checks and may_create for the file creation checks. The
63401da177e4SLinus Torvalds 	   operation will then fail if the context is not permitted. */
6341d84f4f99SDavid Howells 	tsec = new->security;
6342d84f4f99SDavid Howells 	if (!strcmp(name, "exec")) {
63431da177e4SLinus Torvalds 		tsec->exec_sid = sid;
6344d84f4f99SDavid Howells 	} else if (!strcmp(name, "fscreate")) {
63451da177e4SLinus Torvalds 		tsec->create_sid = sid;
6346d84f4f99SDavid Howells 	} else if (!strcmp(name, "keycreate")) {
63476b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
63486b6bc620SStephen Smalley 				     mysid, sid, SECCLASS_KEY, KEY__CREATE,
6349be0554c9SStephen Smalley 				     NULL);
63504eb582cfSMichael LeMay 		if (error)
6351d84f4f99SDavid Howells 			goto abort_change;
63524eb582cfSMichael LeMay 		tsec->keycreate_sid = sid;
6353d84f4f99SDavid Howells 	} else if (!strcmp(name, "sockcreate")) {
635442c3e03eSEric Paris 		tsec->sockcreate_sid = sid;
6355d84f4f99SDavid Howells 	} else if (!strcmp(name, "current")) {
6356d84f4f99SDavid Howells 		error = -EINVAL;
63571da177e4SLinus Torvalds 		if (sid == 0)
6358d84f4f99SDavid Howells 			goto abort_change;
6359d9250deaSKaiGai Kohei 
6360d84f4f99SDavid Howells 		/* Only allow single threaded processes to change context */
6361d84f4f99SDavid Howells 		error = -EPERM;
63625bb459bbSOleg Nesterov 		if (!current_is_single_threaded()) {
6363aa8e712cSStephen Smalley 			error = security_bounded_transition(&selinux_state,
6364aa8e712cSStephen Smalley 							    tsec->sid, sid);
6365d84f4f99SDavid Howells 			if (error)
6366d84f4f99SDavid Howells 				goto abort_change;
63671da177e4SLinus Torvalds 		}
63681da177e4SLinus Torvalds 
63691da177e4SLinus Torvalds 		/* Check permissions for the transition. */
63706b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
63716b6bc620SStephen Smalley 				     tsec->sid, sid, SECCLASS_PROCESS,
63721da177e4SLinus Torvalds 				     PROCESS__DYNTRANSITION, NULL);
63731da177e4SLinus Torvalds 		if (error)
6374d84f4f99SDavid Howells 			goto abort_change;
63751da177e4SLinus Torvalds 
63761da177e4SLinus Torvalds 		/* Check for ptracing, and update the task SID if ok.
63771da177e4SLinus Torvalds 		   Otherwise, leave SID unchanged and fail. */
6378be0554c9SStephen Smalley 		ptsid = ptrace_parent_sid();
63790c6181cbSPaul Moore 		if (ptsid != 0) {
63806b6bc620SStephen Smalley 			error = avc_has_perm(&selinux_state,
63816b6bc620SStephen Smalley 					     ptsid, sid, SECCLASS_PROCESS,
6382d84f4f99SDavid Howells 					     PROCESS__PTRACE, NULL);
6383d84f4f99SDavid Howells 			if (error)
6384d84f4f99SDavid Howells 				goto abort_change;
6385d84f4f99SDavid Howells 		}
6386d84f4f99SDavid Howells 
6387d84f4f99SDavid Howells 		tsec->sid = sid;
6388d84f4f99SDavid Howells 	} else {
6389d84f4f99SDavid Howells 		error = -EINVAL;
6390d84f4f99SDavid Howells 		goto abort_change;
6391d84f4f99SDavid Howells 	}
6392d84f4f99SDavid Howells 
6393d84f4f99SDavid Howells 	commit_creds(new);
63941da177e4SLinus Torvalds 	return size;
6395d84f4f99SDavid Howells 
6396d84f4f99SDavid Howells abort_change:
6397d84f4f99SDavid Howells 	abort_creds(new);
6398d84f4f99SDavid Howells 	return error;
63991da177e4SLinus Torvalds }
64001da177e4SLinus Torvalds 
6401746df9b5SDavid Quigley static int selinux_ismaclabel(const char *name)
6402746df9b5SDavid Quigley {
6403746df9b5SDavid Quigley 	return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
6404746df9b5SDavid Quigley }
6405746df9b5SDavid Quigley 
6406dc49c1f9SCatherine Zhang static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
6407dc49c1f9SCatherine Zhang {
6408aa8e712cSStephen Smalley 	return security_sid_to_context(&selinux_state, secid,
6409aa8e712cSStephen Smalley 				       secdata, seclen);
6410dc49c1f9SCatherine Zhang }
6411dc49c1f9SCatherine Zhang 
64127bf570dcSDavid Howells static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
641363cb3449SDavid Howells {
6414aa8e712cSStephen Smalley 	return security_context_to_sid(&selinux_state, secdata, seclen,
6415aa8e712cSStephen Smalley 				       secid, GFP_KERNEL);
641663cb3449SDavid Howells }
641763cb3449SDavid Howells 
6418dc49c1f9SCatherine Zhang static void selinux_release_secctx(char *secdata, u32 seclen)
6419dc49c1f9SCatherine Zhang {
6420dc49c1f9SCatherine Zhang 	kfree(secdata);
6421dc49c1f9SCatherine Zhang }
6422dc49c1f9SCatherine Zhang 
64236f3be9f5SAndreas Gruenbacher static void selinux_inode_invalidate_secctx(struct inode *inode)
64246f3be9f5SAndreas Gruenbacher {
64256f3be9f5SAndreas Gruenbacher 	struct inode_security_struct *isec = inode->i_security;
64266f3be9f5SAndreas Gruenbacher 
64279287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
64286f3be9f5SAndreas Gruenbacher 	isec->initialized = LABEL_INVALID;
64299287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
64306f3be9f5SAndreas Gruenbacher }
64316f3be9f5SAndreas Gruenbacher 
64321ee65e37SDavid P. Quigley /*
64331ee65e37SDavid P. Quigley  *	called with inode->i_mutex locked
64341ee65e37SDavid P. Quigley  */
64351ee65e37SDavid P. Quigley static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
64361ee65e37SDavid P. Quigley {
64371ee65e37SDavid P. Quigley 	return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
64381ee65e37SDavid P. Quigley }
64391ee65e37SDavid P. Quigley 
64401ee65e37SDavid P. Quigley /*
64411ee65e37SDavid P. Quigley  *	called with inode->i_mutex locked
64421ee65e37SDavid P. Quigley  */
64431ee65e37SDavid P. Quigley static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
64441ee65e37SDavid P. Quigley {
64451ee65e37SDavid P. Quigley 	return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
64461ee65e37SDavid P. Quigley }
64471ee65e37SDavid P. Quigley 
64481ee65e37SDavid P. Quigley static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
64491ee65e37SDavid P. Quigley {
64501ee65e37SDavid P. Quigley 	int len = 0;
64511ee65e37SDavid P. Quigley 	len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
64521ee65e37SDavid P. Quigley 						ctx, true);
64531ee65e37SDavid P. Quigley 	if (len < 0)
64541ee65e37SDavid P. Quigley 		return len;
64551ee65e37SDavid P. Quigley 	*ctxlen = len;
64561ee65e37SDavid P. Quigley 	return 0;
64571ee65e37SDavid P. Quigley }
6458d720024eSMichael LeMay #ifdef CONFIG_KEYS
6459d720024eSMichael LeMay 
6460d84f4f99SDavid Howells static int selinux_key_alloc(struct key *k, const struct cred *cred,
64617e047ef5SDavid Howells 			     unsigned long flags)
6462d720024eSMichael LeMay {
6463d84f4f99SDavid Howells 	const struct task_security_struct *tsec;
6464d720024eSMichael LeMay 	struct key_security_struct *ksec;
6465d720024eSMichael LeMay 
6466d720024eSMichael LeMay 	ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
6467d720024eSMichael LeMay 	if (!ksec)
6468d720024eSMichael LeMay 		return -ENOMEM;
6469d720024eSMichael LeMay 
6470d84f4f99SDavid Howells 	tsec = cred->security;
6471d84f4f99SDavid Howells 	if (tsec->keycreate_sid)
6472d84f4f99SDavid Howells 		ksec->sid = tsec->keycreate_sid;
64734eb582cfSMichael LeMay 	else
6474d84f4f99SDavid Howells 		ksec->sid = tsec->sid;
6475d720024eSMichael LeMay 
6476275bb41eSDavid Howells 	k->security = ksec;
6477d720024eSMichael LeMay 	return 0;
6478d720024eSMichael LeMay }
6479d720024eSMichael LeMay 
6480d720024eSMichael LeMay static void selinux_key_free(struct key *k)
6481d720024eSMichael LeMay {
6482d720024eSMichael LeMay 	struct key_security_struct *ksec = k->security;
6483d720024eSMichael LeMay 
6484d720024eSMichael LeMay 	k->security = NULL;
6485d720024eSMichael LeMay 	kfree(ksec);
6486d720024eSMichael LeMay }
6487d720024eSMichael LeMay 
6488d720024eSMichael LeMay static int selinux_key_permission(key_ref_t key_ref,
6489d84f4f99SDavid Howells 				  const struct cred *cred,
6490f5895943SDavid Howells 				  unsigned perm)
6491d720024eSMichael LeMay {
6492d720024eSMichael LeMay 	struct key *key;
6493d720024eSMichael LeMay 	struct key_security_struct *ksec;
6494275bb41eSDavid Howells 	u32 sid;
6495d720024eSMichael LeMay 
6496d720024eSMichael LeMay 	/* if no specific permissions are requested, we skip the
6497d720024eSMichael LeMay 	   permission check. No serious, additional covert channels
6498d720024eSMichael LeMay 	   appear to be created. */
6499d720024eSMichael LeMay 	if (perm == 0)
6500d720024eSMichael LeMay 		return 0;
6501d720024eSMichael LeMay 
6502d84f4f99SDavid Howells 	sid = cred_sid(cred);
6503275bb41eSDavid Howells 
6504275bb41eSDavid Howells 	key = key_ref_to_ptr(key_ref);
6505275bb41eSDavid Howells 	ksec = key->security;
6506275bb41eSDavid Howells 
65076b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
65086b6bc620SStephen Smalley 			    sid, ksec->sid, SECCLASS_KEY, perm, NULL);
6509d720024eSMichael LeMay }
6510d720024eSMichael LeMay 
651170a5bb72SDavid Howells static int selinux_key_getsecurity(struct key *key, char **_buffer)
651270a5bb72SDavid Howells {
651370a5bb72SDavid Howells 	struct key_security_struct *ksec = key->security;
651470a5bb72SDavid Howells 	char *context = NULL;
651570a5bb72SDavid Howells 	unsigned len;
651670a5bb72SDavid Howells 	int rc;
651770a5bb72SDavid Howells 
6518aa8e712cSStephen Smalley 	rc = security_sid_to_context(&selinux_state, ksec->sid,
6519aa8e712cSStephen Smalley 				     &context, &len);
652070a5bb72SDavid Howells 	if (!rc)
652170a5bb72SDavid Howells 		rc = len;
652270a5bb72SDavid Howells 	*_buffer = context;
652370a5bb72SDavid Howells 	return rc;
652470a5bb72SDavid Howells }
65253a976fa6SDaniel Jurgens #endif
652670a5bb72SDavid Howells 
65273a976fa6SDaniel Jurgens #ifdef CONFIG_SECURITY_INFINIBAND
6528cfc4d882SDaniel Jurgens static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val)
6529cfc4d882SDaniel Jurgens {
6530cfc4d882SDaniel Jurgens 	struct common_audit_data ad;
6531cfc4d882SDaniel Jurgens 	int err;
6532cfc4d882SDaniel Jurgens 	u32 sid = 0;
6533cfc4d882SDaniel Jurgens 	struct ib_security_struct *sec = ib_sec;
6534cfc4d882SDaniel Jurgens 	struct lsm_ibpkey_audit ibpkey;
6535cfc4d882SDaniel Jurgens 
6536409dcf31SDaniel Jurgens 	err = sel_ib_pkey_sid(subnet_prefix, pkey_val, &sid);
6537cfc4d882SDaniel Jurgens 	if (err)
6538cfc4d882SDaniel Jurgens 		return err;
6539cfc4d882SDaniel Jurgens 
6540cfc4d882SDaniel Jurgens 	ad.type = LSM_AUDIT_DATA_IBPKEY;
6541cfc4d882SDaniel Jurgens 	ibpkey.subnet_prefix = subnet_prefix;
6542cfc4d882SDaniel Jurgens 	ibpkey.pkey = pkey_val;
6543cfc4d882SDaniel Jurgens 	ad.u.ibpkey = &ibpkey;
65446b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
65456b6bc620SStephen Smalley 			    sec->sid, sid,
6546cfc4d882SDaniel Jurgens 			    SECCLASS_INFINIBAND_PKEY,
6547cfc4d882SDaniel Jurgens 			    INFINIBAND_PKEY__ACCESS, &ad);
6548cfc4d882SDaniel Jurgens }
6549cfc4d882SDaniel Jurgens 
6550ab861dfcSDaniel Jurgens static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
6551ab861dfcSDaniel Jurgens 					    u8 port_num)
6552ab861dfcSDaniel Jurgens {
6553ab861dfcSDaniel Jurgens 	struct common_audit_data ad;
6554ab861dfcSDaniel Jurgens 	int err;
6555ab861dfcSDaniel Jurgens 	u32 sid = 0;
6556ab861dfcSDaniel Jurgens 	struct ib_security_struct *sec = ib_sec;
6557ab861dfcSDaniel Jurgens 	struct lsm_ibendport_audit ibendport;
6558ab861dfcSDaniel Jurgens 
6559aa8e712cSStephen Smalley 	err = security_ib_endport_sid(&selinux_state, dev_name, port_num,
6560aa8e712cSStephen Smalley 				      &sid);
6561ab861dfcSDaniel Jurgens 
6562ab861dfcSDaniel Jurgens 	if (err)
6563ab861dfcSDaniel Jurgens 		return err;
6564ab861dfcSDaniel Jurgens 
6565ab861dfcSDaniel Jurgens 	ad.type = LSM_AUDIT_DATA_IBENDPORT;
6566ab861dfcSDaniel Jurgens 	strncpy(ibendport.dev_name, dev_name, sizeof(ibendport.dev_name));
6567ab861dfcSDaniel Jurgens 	ibendport.port = port_num;
6568ab861dfcSDaniel Jurgens 	ad.u.ibendport = &ibendport;
65696b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
65706b6bc620SStephen Smalley 			    sec->sid, sid,
6571ab861dfcSDaniel Jurgens 			    SECCLASS_INFINIBAND_ENDPORT,
6572ab861dfcSDaniel Jurgens 			    INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
6573ab861dfcSDaniel Jurgens }
6574ab861dfcSDaniel Jurgens 
65753a976fa6SDaniel Jurgens static int selinux_ib_alloc_security(void **ib_sec)
65763a976fa6SDaniel Jurgens {
65773a976fa6SDaniel Jurgens 	struct ib_security_struct *sec;
65783a976fa6SDaniel Jurgens 
65793a976fa6SDaniel Jurgens 	sec = kzalloc(sizeof(*sec), GFP_KERNEL);
65803a976fa6SDaniel Jurgens 	if (!sec)
65813a976fa6SDaniel Jurgens 		return -ENOMEM;
65823a976fa6SDaniel Jurgens 	sec->sid = current_sid();
65833a976fa6SDaniel Jurgens 
65843a976fa6SDaniel Jurgens 	*ib_sec = sec;
65853a976fa6SDaniel Jurgens 	return 0;
65863a976fa6SDaniel Jurgens }
65873a976fa6SDaniel Jurgens 
65883a976fa6SDaniel Jurgens static void selinux_ib_free_security(void *ib_sec)
65893a976fa6SDaniel Jurgens {
65903a976fa6SDaniel Jurgens 	kfree(ib_sec);
65913a976fa6SDaniel Jurgens }
6592d720024eSMichael LeMay #endif
6593d720024eSMichael LeMay 
6594ec27c356SChenbo Feng #ifdef CONFIG_BPF_SYSCALL
6595ec27c356SChenbo Feng static int selinux_bpf(int cmd, union bpf_attr *attr,
6596ec27c356SChenbo Feng 				     unsigned int size)
6597ec27c356SChenbo Feng {
6598ec27c356SChenbo Feng 	u32 sid = current_sid();
6599ec27c356SChenbo Feng 	int ret;
6600ec27c356SChenbo Feng 
6601ec27c356SChenbo Feng 	switch (cmd) {
6602ec27c356SChenbo Feng 	case BPF_MAP_CREATE:
66036b6bc620SStephen Smalley 		ret = avc_has_perm(&selinux_state,
66046b6bc620SStephen Smalley 				   sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
6605ec27c356SChenbo Feng 				   NULL);
6606ec27c356SChenbo Feng 		break;
6607ec27c356SChenbo Feng 	case BPF_PROG_LOAD:
66086b6bc620SStephen Smalley 		ret = avc_has_perm(&selinux_state,
66096b6bc620SStephen Smalley 				   sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
6610ec27c356SChenbo Feng 				   NULL);
6611ec27c356SChenbo Feng 		break;
6612ec27c356SChenbo Feng 	default:
6613ec27c356SChenbo Feng 		ret = 0;
6614ec27c356SChenbo Feng 		break;
6615ec27c356SChenbo Feng 	}
6616ec27c356SChenbo Feng 
6617ec27c356SChenbo Feng 	return ret;
6618ec27c356SChenbo Feng }
6619ec27c356SChenbo Feng 
6620ec27c356SChenbo Feng static u32 bpf_map_fmode_to_av(fmode_t fmode)
6621ec27c356SChenbo Feng {
6622ec27c356SChenbo Feng 	u32 av = 0;
6623ec27c356SChenbo Feng 
6624ec27c356SChenbo Feng 	if (fmode & FMODE_READ)
6625ec27c356SChenbo Feng 		av |= BPF__MAP_READ;
6626ec27c356SChenbo Feng 	if (fmode & FMODE_WRITE)
6627ec27c356SChenbo Feng 		av |= BPF__MAP_WRITE;
6628ec27c356SChenbo Feng 	return av;
6629ec27c356SChenbo Feng }
6630ec27c356SChenbo Feng 
6631f66e448cSChenbo Feng /* This function will check the file pass through unix socket or binder to see
6632f66e448cSChenbo Feng  * if it is a bpf related object. And apply correspinding checks on the bpf
6633f66e448cSChenbo Feng  * object based on the type. The bpf maps and programs, not like other files and
6634f66e448cSChenbo Feng  * socket, are using a shared anonymous inode inside the kernel as their inode.
6635f66e448cSChenbo Feng  * So checking that inode cannot identify if the process have privilege to
6636f66e448cSChenbo Feng  * access the bpf object and that's why we have to add this additional check in
6637f66e448cSChenbo Feng  * selinux_file_receive and selinux_binder_transfer_files.
6638f66e448cSChenbo Feng  */
6639f66e448cSChenbo Feng static int bpf_fd_pass(struct file *file, u32 sid)
6640f66e448cSChenbo Feng {
6641f66e448cSChenbo Feng 	struct bpf_security_struct *bpfsec;
6642f66e448cSChenbo Feng 	struct bpf_prog *prog;
6643f66e448cSChenbo Feng 	struct bpf_map *map;
6644f66e448cSChenbo Feng 	int ret;
6645f66e448cSChenbo Feng 
6646f66e448cSChenbo Feng 	if (file->f_op == &bpf_map_fops) {
6647f66e448cSChenbo Feng 		map = file->private_data;
6648f66e448cSChenbo Feng 		bpfsec = map->security;
66496b6bc620SStephen Smalley 		ret = avc_has_perm(&selinux_state,
66506b6bc620SStephen Smalley 				   sid, bpfsec->sid, SECCLASS_BPF,
6651f66e448cSChenbo Feng 				   bpf_map_fmode_to_av(file->f_mode), NULL);
6652f66e448cSChenbo Feng 		if (ret)
6653f66e448cSChenbo Feng 			return ret;
6654f66e448cSChenbo Feng 	} else if (file->f_op == &bpf_prog_fops) {
6655f66e448cSChenbo Feng 		prog = file->private_data;
6656f66e448cSChenbo Feng 		bpfsec = prog->aux->security;
66576b6bc620SStephen Smalley 		ret = avc_has_perm(&selinux_state,
66586b6bc620SStephen Smalley 				   sid, bpfsec->sid, SECCLASS_BPF,
6659f66e448cSChenbo Feng 				   BPF__PROG_RUN, NULL);
6660f66e448cSChenbo Feng 		if (ret)
6661f66e448cSChenbo Feng 			return ret;
6662f66e448cSChenbo Feng 	}
6663f66e448cSChenbo Feng 	return 0;
6664f66e448cSChenbo Feng }
6665f66e448cSChenbo Feng 
6666ec27c356SChenbo Feng static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
6667ec27c356SChenbo Feng {
6668ec27c356SChenbo Feng 	u32 sid = current_sid();
6669ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec;
6670ec27c356SChenbo Feng 
6671ec27c356SChenbo Feng 	bpfsec = map->security;
66726b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
66736b6bc620SStephen Smalley 			    sid, bpfsec->sid, SECCLASS_BPF,
6674ec27c356SChenbo Feng 			    bpf_map_fmode_to_av(fmode), NULL);
6675ec27c356SChenbo Feng }
6676ec27c356SChenbo Feng 
6677ec27c356SChenbo Feng static int selinux_bpf_prog(struct bpf_prog *prog)
6678ec27c356SChenbo Feng {
6679ec27c356SChenbo Feng 	u32 sid = current_sid();
6680ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec;
6681ec27c356SChenbo Feng 
6682ec27c356SChenbo Feng 	bpfsec = prog->aux->security;
66836b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
66846b6bc620SStephen Smalley 			    sid, bpfsec->sid, SECCLASS_BPF,
6685ec27c356SChenbo Feng 			    BPF__PROG_RUN, NULL);
6686ec27c356SChenbo Feng }
6687ec27c356SChenbo Feng 
6688ec27c356SChenbo Feng static int selinux_bpf_map_alloc(struct bpf_map *map)
6689ec27c356SChenbo Feng {
6690ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec;
6691ec27c356SChenbo Feng 
6692ec27c356SChenbo Feng 	bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
6693ec27c356SChenbo Feng 	if (!bpfsec)
6694ec27c356SChenbo Feng 		return -ENOMEM;
6695ec27c356SChenbo Feng 
6696ec27c356SChenbo Feng 	bpfsec->sid = current_sid();
6697ec27c356SChenbo Feng 	map->security = bpfsec;
6698ec27c356SChenbo Feng 
6699ec27c356SChenbo Feng 	return 0;
6700ec27c356SChenbo Feng }
6701ec27c356SChenbo Feng 
6702ec27c356SChenbo Feng static void selinux_bpf_map_free(struct bpf_map *map)
6703ec27c356SChenbo Feng {
6704ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec = map->security;
6705ec27c356SChenbo Feng 
6706ec27c356SChenbo Feng 	map->security = NULL;
6707ec27c356SChenbo Feng 	kfree(bpfsec);
6708ec27c356SChenbo Feng }
6709ec27c356SChenbo Feng 
6710ec27c356SChenbo Feng static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
6711ec27c356SChenbo Feng {
6712ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec;
6713ec27c356SChenbo Feng 
6714ec27c356SChenbo Feng 	bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
6715ec27c356SChenbo Feng 	if (!bpfsec)
6716ec27c356SChenbo Feng 		return -ENOMEM;
6717ec27c356SChenbo Feng 
6718ec27c356SChenbo Feng 	bpfsec->sid = current_sid();
6719ec27c356SChenbo Feng 	aux->security = bpfsec;
6720ec27c356SChenbo Feng 
6721ec27c356SChenbo Feng 	return 0;
6722ec27c356SChenbo Feng }
6723ec27c356SChenbo Feng 
6724ec27c356SChenbo Feng static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
6725ec27c356SChenbo Feng {
6726ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec = aux->security;
6727ec27c356SChenbo Feng 
6728ec27c356SChenbo Feng 	aux->security = NULL;
6729ec27c356SChenbo Feng 	kfree(bpfsec);
6730ec27c356SChenbo Feng }
6731ec27c356SChenbo Feng #endif
6732ec27c356SChenbo Feng 
6733ca97d939SJames Morris static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
6734e20b043aSCasey Schaufler 	LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
6735e20b043aSCasey Schaufler 	LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
6736e20b043aSCasey Schaufler 	LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
6737e20b043aSCasey Schaufler 	LSM_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file),
6738076c54c5SAhmed S. Darwish 
6739e20b043aSCasey Schaufler 	LSM_HOOK_INIT(ptrace_access_check, selinux_ptrace_access_check),
6740e20b043aSCasey Schaufler 	LSM_HOOK_INIT(ptrace_traceme, selinux_ptrace_traceme),
6741e20b043aSCasey Schaufler 	LSM_HOOK_INIT(capget, selinux_capget),
6742e20b043aSCasey Schaufler 	LSM_HOOK_INIT(capset, selinux_capset),
6743e20b043aSCasey Schaufler 	LSM_HOOK_INIT(capable, selinux_capable),
6744e20b043aSCasey Schaufler 	LSM_HOOK_INIT(quotactl, selinux_quotactl),
6745e20b043aSCasey Schaufler 	LSM_HOOK_INIT(quota_on, selinux_quota_on),
6746e20b043aSCasey Schaufler 	LSM_HOOK_INIT(syslog, selinux_syslog),
6747e20b043aSCasey Schaufler 	LSM_HOOK_INIT(vm_enough_memory, selinux_vm_enough_memory),
674879af7307SStephen Smalley 
6749e20b043aSCasey Schaufler 	LSM_HOOK_INIT(netlink_send, selinux_netlink_send),
67501da177e4SLinus Torvalds 
6751e20b043aSCasey Schaufler 	LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds),
6752e20b043aSCasey Schaufler 	LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
6753e20b043aSCasey Schaufler 	LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
67541da177e4SLinus Torvalds 
6755e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
6756e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
67575b400239SAl Viro 	LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
6758204cc0ccSAl Viro 	LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
6759e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
6760e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
6761e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
6762e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs),
6763e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_mount, selinux_mount),
6764e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_umount, selinux_umount),
6765e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts),
6766e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts),
6767e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str),
67681da177e4SLinus Torvalds 
6769e20b043aSCasey Schaufler 	LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security),
6770a518b0a5SVivek Goyal 	LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as),
6771e0007529SEric Paris 
6772e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
6773e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security),
6774e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security),
6775e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_create, selinux_inode_create),
6776e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_link, selinux_inode_link),
6777e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink),
6778e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_symlink, selinux_inode_symlink),
6779e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_mkdir, selinux_inode_mkdir),
6780e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_rmdir, selinux_inode_rmdir),
6781e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_mknod, selinux_inode_mknod),
6782e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_rename, selinux_inode_rename),
6783e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_readlink, selinux_inode_readlink),
6784e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_follow_link, selinux_inode_follow_link),
6785e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_permission, selinux_inode_permission),
6786e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr),
6787e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr),
6788e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr),
6789e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr),
6790e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
6791e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr),
6792e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr),
6793e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
6794e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
6795e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
6796e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
679756909eb3SVivek Goyal 	LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
679819472b69SVivek Goyal 	LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
67991da177e4SLinus Torvalds 
6800e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_permission, selinux_file_permission),
6801e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
6802e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_free_security, selinux_file_free_security),
6803e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
6804e20b043aSCasey Schaufler 	LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
6805e20b043aSCasey Schaufler 	LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
6806e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
6807e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_lock, selinux_file_lock),
6808e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_fcntl, selinux_file_fcntl),
6809e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_set_fowner, selinux_file_set_fowner),
6810e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_send_sigiotask, selinux_file_send_sigiotask),
6811e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_receive, selinux_file_receive),
68121da177e4SLinus Torvalds 
6813e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_open, selinux_file_open),
68141da177e4SLinus Torvalds 
6815a79be238STetsuo Handa 	LSM_HOOK_INIT(task_alloc, selinux_task_alloc),
6816e20b043aSCasey Schaufler 	LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank),
6817e20b043aSCasey Schaufler 	LSM_HOOK_INIT(cred_free, selinux_cred_free),
6818e20b043aSCasey Schaufler 	LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
6819e20b043aSCasey Schaufler 	LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
68203ec30113SMatthew Garrett 	LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
6821e20b043aSCasey Schaufler 	LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
6822e20b043aSCasey Schaufler 	LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
6823e20b043aSCasey Schaufler 	LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
6824c77b8cdfSMimi Zohar 	LSM_HOOK_INIT(kernel_load_data, selinux_kernel_load_data),
682561d612eaSJeff Vander Stoep 	LSM_HOOK_INIT(kernel_read_file, selinux_kernel_read_file),
6826e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
6827e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
6828e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
6829e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_getsecid, selinux_task_getsecid),
6830e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
6831e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
6832e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
6833791ec491SStephen Smalley 	LSM_HOOK_INIT(task_prlimit, selinux_task_prlimit),
6834e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_setrlimit, selinux_task_setrlimit),
6835e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_setscheduler, selinux_task_setscheduler),
6836e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler),
6837e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_movememory, selinux_task_movememory),
6838e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_kill, selinux_task_kill),
6839e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode),
6840788e7dd4SYuichi Nakamura 
6841e20b043aSCasey Schaufler 	LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
6842e20b043aSCasey Schaufler 	LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
68431da177e4SLinus Torvalds 
6844e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security),
6845e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_msg_free_security, selinux_msg_msg_free_security),
68461da177e4SLinus Torvalds 
6847e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_alloc_security,
6848e20b043aSCasey Schaufler 			selinux_msg_queue_alloc_security),
6849e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_free_security, selinux_msg_queue_free_security),
6850e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
6851e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
6852e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd),
6853e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv),
68541da177e4SLinus Torvalds 
6855e20b043aSCasey Schaufler 	LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
6856e20b043aSCasey Schaufler 	LSM_HOOK_INIT(shm_free_security, selinux_shm_free_security),
6857e20b043aSCasey Schaufler 	LSM_HOOK_INIT(shm_associate, selinux_shm_associate),
6858e20b043aSCasey Schaufler 	LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl),
6859e20b043aSCasey Schaufler 	LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat),
68601da177e4SLinus Torvalds 
6861e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
6862e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sem_free_security, selinux_sem_free_security),
6863e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sem_associate, selinux_sem_associate),
6864e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl),
6865e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sem_semop, selinux_sem_semop),
68661da177e4SLinus Torvalds 
6867e20b043aSCasey Schaufler 	LSM_HOOK_INIT(d_instantiate, selinux_d_instantiate),
68681da177e4SLinus Torvalds 
6869e20b043aSCasey Schaufler 	LSM_HOOK_INIT(getprocattr, selinux_getprocattr),
6870e20b043aSCasey Schaufler 	LSM_HOOK_INIT(setprocattr, selinux_setprocattr),
68711da177e4SLinus Torvalds 
6872e20b043aSCasey Schaufler 	LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
6873e20b043aSCasey Schaufler 	LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
6874e20b043aSCasey Schaufler 	LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
6875e20b043aSCasey Schaufler 	LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
68766f3be9f5SAndreas Gruenbacher 	LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
6877e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
6878e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
6879e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
68801da177e4SLinus Torvalds 
6881e20b043aSCasey Schaufler 	LSM_HOOK_INIT(unix_stream_connect, selinux_socket_unix_stream_connect),
6882e20b043aSCasey Schaufler 	LSM_HOOK_INIT(unix_may_send, selinux_socket_unix_may_send),
6883dc49c1f9SCatherine Zhang 
6884e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_create, selinux_socket_create),
6885e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_post_create, selinux_socket_post_create),
68860b811db2SDavid Herrmann 	LSM_HOOK_INIT(socket_socketpair, selinux_socket_socketpair),
6887e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_bind, selinux_socket_bind),
6888e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_connect, selinux_socket_connect),
6889e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_listen, selinux_socket_listen),
6890e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_accept, selinux_socket_accept),
6891e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_sendmsg, selinux_socket_sendmsg),
6892e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_recvmsg, selinux_socket_recvmsg),
6893e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_getsockname, selinux_socket_getsockname),
6894e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_getpeername, selinux_socket_getpeername),
6895e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt),
6896e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt),
6897e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_shutdown, selinux_socket_shutdown),
6898e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb),
6899e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_getpeersec_stream,
6900e20b043aSCasey Schaufler 			selinux_socket_getpeersec_stream),
6901e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_getpeersec_dgram, selinux_socket_getpeersec_dgram),
6902e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
6903e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sk_free_security, selinux_sk_free_security),
6904e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security),
6905e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid),
6906e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sock_graft, selinux_sock_graft),
6907d452930fSRichard Haines 	LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request),
6908d452930fSRichard Haines 	LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
6909d452930fSRichard Haines 	LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
6910e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
6911e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
6912e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
6913e20b043aSCasey Schaufler 	LSM_HOOK_INIT(secmark_relabel_packet, selinux_secmark_relabel_packet),
6914e20b043aSCasey Schaufler 	LSM_HOOK_INIT(secmark_refcount_inc, selinux_secmark_refcount_inc),
6915e20b043aSCasey Schaufler 	LSM_HOOK_INIT(secmark_refcount_dec, selinux_secmark_refcount_dec),
6916e20b043aSCasey Schaufler 	LSM_HOOK_INIT(req_classify_flow, selinux_req_classify_flow),
6917e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),
6918e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_free_security, selinux_tun_dev_free_security),
6919e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_create, selinux_tun_dev_create),
6920e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue),
6921e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach),
6922e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open),
69233a976fa6SDaniel Jurgens #ifdef CONFIG_SECURITY_INFINIBAND
6924cfc4d882SDaniel Jurgens 	LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access),
6925ab861dfcSDaniel Jurgens 	LSM_HOOK_INIT(ib_endport_manage_subnet,
6926ab861dfcSDaniel Jurgens 		      selinux_ib_endport_manage_subnet),
69273a976fa6SDaniel Jurgens 	LSM_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security),
69283a976fa6SDaniel Jurgens 	LSM_HOOK_INIT(ib_free_security, selinux_ib_free_security),
69293a976fa6SDaniel Jurgens #endif
6930d28d1e08STrent Jaeger #ifdef CONFIG_SECURITY_NETWORK_XFRM
6931e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc),
6932e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone),
6933e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_policy_free_security, selinux_xfrm_policy_free),
6934e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_policy_delete_security, selinux_xfrm_policy_delete),
6935e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_state_alloc, selinux_xfrm_state_alloc),
6936e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_state_alloc_acquire,
6937e20b043aSCasey Schaufler 			selinux_xfrm_state_alloc_acquire),
6938e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_state_free_security, selinux_xfrm_state_free),
6939e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_state_delete_security, selinux_xfrm_state_delete),
6940e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_policy_lookup, selinux_xfrm_policy_lookup),
6941e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_state_pol_flow_match,
6942e20b043aSCasey Schaufler 			selinux_xfrm_state_pol_flow_match),
6943e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_decode_session, selinux_xfrm_decode_session),
69441da177e4SLinus Torvalds #endif
6945d720024eSMichael LeMay 
6946d720024eSMichael LeMay #ifdef CONFIG_KEYS
6947e20b043aSCasey Schaufler 	LSM_HOOK_INIT(key_alloc, selinux_key_alloc),
6948e20b043aSCasey Schaufler 	LSM_HOOK_INIT(key_free, selinux_key_free),
6949e20b043aSCasey Schaufler 	LSM_HOOK_INIT(key_permission, selinux_key_permission),
6950e20b043aSCasey Schaufler 	LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
6951d720024eSMichael LeMay #endif
69529d57a7f9SAhmed S. Darwish 
69539d57a7f9SAhmed S. Darwish #ifdef CONFIG_AUDIT
6954e20b043aSCasey Schaufler 	LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init),
6955e20b043aSCasey Schaufler 	LSM_HOOK_INIT(audit_rule_known, selinux_audit_rule_known),
6956e20b043aSCasey Schaufler 	LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
6957e20b043aSCasey Schaufler 	LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
69589d57a7f9SAhmed S. Darwish #endif
6959ec27c356SChenbo Feng 
6960ec27c356SChenbo Feng #ifdef CONFIG_BPF_SYSCALL
6961ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf, selinux_bpf),
6962ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
6963ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
6964ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
6965ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
6966ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
6967ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
6968ec27c356SChenbo Feng #endif
69691da177e4SLinus Torvalds };
69701da177e4SLinus Torvalds 
69711da177e4SLinus Torvalds static __init int selinux_init(void)
69721da177e4SLinus Torvalds {
6973b1d9e6b0SCasey Schaufler 	if (!security_module_enable("selinux")) {
6974076c54c5SAhmed S. Darwish 		selinux_enabled = 0;
6975076c54c5SAhmed S. Darwish 		return 0;
6976076c54c5SAhmed S. Darwish 	}
6977076c54c5SAhmed S. Darwish 
69781da177e4SLinus Torvalds 	if (!selinux_enabled) {
6979c103a91eSpeter enderborg 		pr_info("SELinux:  Disabled at boot.\n");
69801da177e4SLinus Torvalds 		return 0;
69811da177e4SLinus Torvalds 	}
69821da177e4SLinus Torvalds 
6983c103a91eSpeter enderborg 	pr_info("SELinux:  Initializing.\n");
69841da177e4SLinus Torvalds 
6985aa8e712cSStephen Smalley 	memset(&selinux_state, 0, sizeof(selinux_state));
6986e5a5ca96SPaul Moore 	enforcing_set(&selinux_state, selinux_enforcing_boot);
6987aa8e712cSStephen Smalley 	selinux_state.checkreqprot = selinux_checkreqprot_boot;
6988aa8e712cSStephen Smalley 	selinux_ss_init(&selinux_state.ss);
69896b6bc620SStephen Smalley 	selinux_avc_init(&selinux_state.avc);
6990aa8e712cSStephen Smalley 
69911da177e4SLinus Torvalds 	/* Set the security state for the initial task. */
6992d84f4f99SDavid Howells 	cred_init_security();
69931da177e4SLinus Torvalds 
6994fcaaade1SStephen Smalley 	default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
6995fcaaade1SStephen Smalley 
69967cae7e26SJames Morris 	sel_inode_cache = kmem_cache_create("selinux_inode_security",
69977cae7e26SJames Morris 					    sizeof(struct inode_security_struct),
699820c2df83SPaul Mundt 					    0, SLAB_PANIC, NULL);
699963205654SSangwoo 	file_security_cache = kmem_cache_create("selinux_file_security",
700063205654SSangwoo 					    sizeof(struct file_security_struct),
700163205654SSangwoo 					    0, SLAB_PANIC, NULL);
70021da177e4SLinus Torvalds 	avc_init();
70031da177e4SLinus Torvalds 
7004aa8e712cSStephen Smalley 	avtab_cache_init();
7005aa8e712cSStephen Smalley 
7006aa8e712cSStephen Smalley 	ebitmap_cache_init();
7007aa8e712cSStephen Smalley 
7008aa8e712cSStephen Smalley 	hashtab_cache_init();
7009aa8e712cSStephen Smalley 
7010d69dece5SCasey Schaufler 	security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
70111da177e4SLinus Torvalds 
7012615e51fdSPaul Moore 	if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
7013615e51fdSPaul Moore 		panic("SELinux: Unable to register AVC netcache callback\n");
7014615e51fdSPaul Moore 
70158f408ab6SDaniel Jurgens 	if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET))
70168f408ab6SDaniel Jurgens 		panic("SELinux: Unable to register AVC LSM notifier callback\n");
70178f408ab6SDaniel Jurgens 
7018aa8e712cSStephen Smalley 	if (selinux_enforcing_boot)
7019c103a91eSpeter enderborg 		pr_debug("SELinux:  Starting in enforcing mode\n");
7020828dfe1dSEric Paris 	else
7021c103a91eSpeter enderborg 		pr_debug("SELinux:  Starting in permissive mode\n");
7022d720024eSMichael LeMay 
70231da177e4SLinus Torvalds 	return 0;
70241da177e4SLinus Torvalds }
70251da177e4SLinus Torvalds 
7026e8c26255SAl Viro static void delayed_superblock_init(struct super_block *sb, void *unused)
7027e8c26255SAl Viro {
7028204cc0ccSAl Viro 	selinux_set_mnt_opts(sb, NULL, 0, NULL);
7029e8c26255SAl Viro }
7030e8c26255SAl Viro 
70311da177e4SLinus Torvalds void selinux_complete_init(void)
70321da177e4SLinus Torvalds {
7033c103a91eSpeter enderborg 	pr_debug("SELinux:  Completing initialization.\n");
70341da177e4SLinus Torvalds 
70351da177e4SLinus Torvalds 	/* Set up any superblocks initialized prior to the policy load. */
7036c103a91eSpeter enderborg 	pr_debug("SELinux:  Setting up existing superblocks.\n");
7037e8c26255SAl Viro 	iterate_supers(delayed_superblock_init, NULL);
70381da177e4SLinus Torvalds }
70391da177e4SLinus Torvalds 
70401da177e4SLinus Torvalds /* SELinux requires early initialization in order to label
70411da177e4SLinus Torvalds    all processes and objects when they are created. */
70423d6e5f6dSKees Cook DEFINE_LSM(selinux) = {
704307aed2f2SKees Cook 	.name = "selinux",
70443d6e5f6dSKees Cook 	.init = selinux_init,
70453d6e5f6dSKees Cook };
70461da177e4SLinus Torvalds 
7047c2b507fdSStephen Smalley #if defined(CONFIG_NETFILTER)
70481da177e4SLinus Torvalds 
7049591bb278SFlorian Westphal static const struct nf_hook_ops selinux_nf_ops[] = {
7050effad8dfSPaul Moore 	{
7051effad8dfSPaul Moore 		.hook =		selinux_ipv4_postroute,
70522597a834SAlban Crequy 		.pf =		NFPROTO_IPV4,
70536e23ae2aSPatrick McHardy 		.hooknum =	NF_INET_POST_ROUTING,
70541da177e4SLinus Torvalds 		.priority =	NF_IP_PRI_SELINUX_LAST,
7055effad8dfSPaul Moore 	},
7056effad8dfSPaul Moore 	{
7057effad8dfSPaul Moore 		.hook =		selinux_ipv4_forward,
70582597a834SAlban Crequy 		.pf =		NFPROTO_IPV4,
7059effad8dfSPaul Moore 		.hooknum =	NF_INET_FORWARD,
7060effad8dfSPaul Moore 		.priority =	NF_IP_PRI_SELINUX_FIRST,
7061948bf85cSPaul Moore 	},
7062948bf85cSPaul Moore 	{
7063948bf85cSPaul Moore 		.hook =		selinux_ipv4_output,
70642597a834SAlban Crequy 		.pf =		NFPROTO_IPV4,
7065948bf85cSPaul Moore 		.hooknum =	NF_INET_LOCAL_OUT,
7066948bf85cSPaul Moore 		.priority =	NF_IP_PRI_SELINUX_FIRST,
706725db6beaSJiri Pirko 	},
70681a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
7069effad8dfSPaul Moore 	{
7070effad8dfSPaul Moore 		.hook =		selinux_ipv6_postroute,
70712597a834SAlban Crequy 		.pf =		NFPROTO_IPV6,
70726e23ae2aSPatrick McHardy 		.hooknum =	NF_INET_POST_ROUTING,
70731da177e4SLinus Torvalds 		.priority =	NF_IP6_PRI_SELINUX_LAST,
7074effad8dfSPaul Moore 	},
7075effad8dfSPaul Moore 	{
7076effad8dfSPaul Moore 		.hook =		selinux_ipv6_forward,
70772597a834SAlban Crequy 		.pf =		NFPROTO_IPV6,
7078effad8dfSPaul Moore 		.hooknum =	NF_INET_FORWARD,
7079effad8dfSPaul Moore 		.priority =	NF_IP6_PRI_SELINUX_FIRST,
708025db6beaSJiri Pirko 	},
70812917f57bSHuw Davies 	{
70822917f57bSHuw Davies 		.hook =		selinux_ipv6_output,
70832917f57bSHuw Davies 		.pf =		NFPROTO_IPV6,
70842917f57bSHuw Davies 		.hooknum =	NF_INET_LOCAL_OUT,
70852917f57bSHuw Davies 		.priority =	NF_IP6_PRI_SELINUX_FIRST,
70862917f57bSHuw Davies 	},
70871da177e4SLinus Torvalds #endif	/* IPV6 */
708825db6beaSJiri Pirko };
70891da177e4SLinus Torvalds 
70908e71bf75SFlorian Westphal static int __net_init selinux_nf_register(struct net *net)
70918e71bf75SFlorian Westphal {
70928e71bf75SFlorian Westphal 	return nf_register_net_hooks(net, selinux_nf_ops,
70938e71bf75SFlorian Westphal 				     ARRAY_SIZE(selinux_nf_ops));
70948e71bf75SFlorian Westphal }
70958e71bf75SFlorian Westphal 
70968e71bf75SFlorian Westphal static void __net_exit selinux_nf_unregister(struct net *net)
70978e71bf75SFlorian Westphal {
70988e71bf75SFlorian Westphal 	nf_unregister_net_hooks(net, selinux_nf_ops,
70998e71bf75SFlorian Westphal 				ARRAY_SIZE(selinux_nf_ops));
71008e71bf75SFlorian Westphal }
71018e71bf75SFlorian Westphal 
71028e71bf75SFlorian Westphal static struct pernet_operations selinux_net_ops = {
71038e71bf75SFlorian Westphal 	.init = selinux_nf_register,
71048e71bf75SFlorian Westphal 	.exit = selinux_nf_unregister,
71058e71bf75SFlorian Westphal };
71068e71bf75SFlorian Westphal 
71071da177e4SLinus Torvalds static int __init selinux_nf_ip_init(void)
71081da177e4SLinus Torvalds {
710925db6beaSJiri Pirko 	int err;
71101da177e4SLinus Torvalds 
71111da177e4SLinus Torvalds 	if (!selinux_enabled)
711225db6beaSJiri Pirko 		return 0;
71131da177e4SLinus Torvalds 
7114c103a91eSpeter enderborg 	pr_debug("SELinux:  Registering netfilter hooks\n");
71151da177e4SLinus Torvalds 
71168e71bf75SFlorian Westphal 	err = register_pernet_subsys(&selinux_net_ops);
71171da177e4SLinus Torvalds 	if (err)
71188e71bf75SFlorian Westphal 		panic("SELinux: register_pernet_subsys: error %d\n", err);
71191da177e4SLinus Torvalds 
712025db6beaSJiri Pirko 	return 0;
71211da177e4SLinus Torvalds }
71221da177e4SLinus Torvalds __initcall(selinux_nf_ip_init);
71231da177e4SLinus Torvalds 
71241da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE
71251da177e4SLinus Torvalds static void selinux_nf_ip_exit(void)
71261da177e4SLinus Torvalds {
7127c103a91eSpeter enderborg 	pr_debug("SELinux:  Unregistering netfilter hooks\n");
71281da177e4SLinus Torvalds 
71298e71bf75SFlorian Westphal 	unregister_pernet_subsys(&selinux_net_ops);
71301da177e4SLinus Torvalds }
71311da177e4SLinus Torvalds #endif
71321da177e4SLinus Torvalds 
7133c2b507fdSStephen Smalley #else /* CONFIG_NETFILTER */
71341da177e4SLinus Torvalds 
71351da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE
71361da177e4SLinus Torvalds #define selinux_nf_ip_exit()
71371da177e4SLinus Torvalds #endif
71381da177e4SLinus Torvalds 
7139c2b507fdSStephen Smalley #endif /* CONFIG_NETFILTER */
71401da177e4SLinus Torvalds 
71411da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE
7142aa8e712cSStephen Smalley int selinux_disable(struct selinux_state *state)
71431da177e4SLinus Torvalds {
7144aa8e712cSStephen Smalley 	if (state->initialized) {
71451da177e4SLinus Torvalds 		/* Not permitted after initial policy load. */
71461da177e4SLinus Torvalds 		return -EINVAL;
71471da177e4SLinus Torvalds 	}
71481da177e4SLinus Torvalds 
7149aa8e712cSStephen Smalley 	if (state->disabled) {
71501da177e4SLinus Torvalds 		/* Only do this once. */
71511da177e4SLinus Torvalds 		return -EINVAL;
71521da177e4SLinus Torvalds 	}
71531da177e4SLinus Torvalds 
7154aa8e712cSStephen Smalley 	state->disabled = 1;
7155aa8e712cSStephen Smalley 
7156c103a91eSpeter enderborg 	pr_info("SELinux:  Disabled at runtime.\n");
71571da177e4SLinus Torvalds 
715830d55280SStephen Smalley 	selinux_enabled = 0;
71591da177e4SLinus Torvalds 
7160b1d9e6b0SCasey Schaufler 	security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
71611da177e4SLinus Torvalds 
7162af8ff049SEric Paris 	/* Try to destroy the avc node cache */
7163af8ff049SEric Paris 	avc_disable();
7164af8ff049SEric Paris 
71651da177e4SLinus Torvalds 	/* Unregister netfilter hooks. */
71661da177e4SLinus Torvalds 	selinux_nf_ip_exit();
71671da177e4SLinus Torvalds 
71681da177e4SLinus Torvalds 	/* Unregister selinuxfs. */
71691da177e4SLinus Torvalds 	exit_sel_fs();
71701da177e4SLinus Torvalds 
71711da177e4SLinus Torvalds 	return 0;
71721da177e4SLinus Torvalds }
71731da177e4SLinus Torvalds #endif
7174