xref: /openbmc/linux/security/selinux/hooks.c (revision 028db3e290f15ac509084c0fc3b9d021f668f877)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  NSA Security-Enhanced Linux (SELinux) security module
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  This file contains the SELinux hook function implementations.
61da177e4SLinus Torvalds  *
77efbb60bSStephen Smalley  *  Authors:  Stephen Smalley, <sds@tycho.nsa.gov>
81da177e4SLinus Torvalds  *	      Chris Vance, <cvance@nai.com>
91da177e4SLinus Torvalds  *	      Wayne Salamon, <wsalamon@nai.com>
101da177e4SLinus Torvalds  *	      James Morris <jmorris@redhat.com>
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  *  Copyright (C) 2001,2002 Networks Associates Technology, Inc.
132069f457SEric Paris  *  Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
142069f457SEric Paris  *					   Eric Paris <eparis@redhat.com>
151da177e4SLinus Torvalds  *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
161da177e4SLinus Torvalds  *			    <dgoeddel@trustedcs.com>
17ed6d76e4SPaul Moore  *  Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
1882c21bfaSPaul Moore  *	Paul Moore <paul@paul-moore.com>
19788e7dd4SYuichi Nakamura  *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
20788e7dd4SYuichi Nakamura  *		       Yuichi Nakamura <ynakam@hitachisoft.jp>
213a976fa6SDaniel Jurgens  *  Copyright (C) 2016 Mellanox Technologies
221da177e4SLinus Torvalds  */
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds #include <linux/init.h>
250b24dcb7SEric Paris #include <linux/kd.h>
261da177e4SLinus Torvalds #include <linux/kernel.h>
270d094efeSRoland McGrath #include <linux/tracehook.h>
281da177e4SLinus Torvalds #include <linux/errno.h>
293f07c014SIngo Molnar #include <linux/sched/signal.h>
3029930025SIngo Molnar #include <linux/sched/task.h>
313c4ed7bdSCasey Schaufler #include <linux/lsm_hooks.h>
321da177e4SLinus Torvalds #include <linux/xattr.h>
331da177e4SLinus Torvalds #include <linux/capability.h>
341da177e4SLinus Torvalds #include <linux/unistd.h>
351da177e4SLinus Torvalds #include <linux/mm.h>
361da177e4SLinus Torvalds #include <linux/mman.h>
371da177e4SLinus Torvalds #include <linux/slab.h>
381da177e4SLinus Torvalds #include <linux/pagemap.h>
390b24dcb7SEric Paris #include <linux/proc_fs.h>
401da177e4SLinus Torvalds #include <linux/swap.h>
411da177e4SLinus Torvalds #include <linux/spinlock.h>
421da177e4SLinus Torvalds #include <linux/syscalls.h>
432a7dba39SEric Paris #include <linux/dcache.h>
441da177e4SLinus Torvalds #include <linux/file.h>
459f3acc31SAl Viro #include <linux/fdtable.h>
461da177e4SLinus Torvalds #include <linux/namei.h>
471da177e4SLinus Torvalds #include <linux/mount.h>
48442155c1SDavid Howells #include <linux/fs_context.h>
49442155c1SDavid Howells #include <linux/fs_parser.h>
501da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h>
511da177e4SLinus Torvalds #include <linux/netfilter_ipv6.h>
521da177e4SLinus Torvalds #include <linux/tty.h>
531da177e4SLinus Torvalds #include <net/icmp.h>
54227b60f5SStephen Hemminger #include <net/ip.h>		/* for local_port_range[] */
551da177e4SLinus Torvalds #include <net/tcp.h>		/* struct or_callable used in sock_rcv_skb */
5647180068SPaul Moore #include <net/inet_connection_sock.h>
57220deb96SPaul Moore #include <net/net_namespace.h>
58d621d35eSPaul Moore #include <net/netlabel.h>
59f5269710SEric Paris #include <linux/uaccess.h>
601da177e4SLinus Torvalds #include <asm/ioctls.h>
6160063497SArun Sharma #include <linux/atomic.h>
621da177e4SLinus Torvalds #include <linux/bitops.h>
631da177e4SLinus Torvalds #include <linux/interrupt.h>
641da177e4SLinus Torvalds #include <linux/netdevice.h>	/* for network interface checks */
6577954983SHong zhi guo #include <net/netlink.h>
661da177e4SLinus Torvalds #include <linux/tcp.h>
671da177e4SLinus Torvalds #include <linux/udp.h>
682ee92d46SJames Morris #include <linux/dccp.h>
69d452930fSRichard Haines #include <linux/sctp.h>
70d452930fSRichard Haines #include <net/sctp/structs.h>
711da177e4SLinus Torvalds #include <linux/quota.h>
721da177e4SLinus Torvalds #include <linux/un.h>		/* for Unix socket types */
731da177e4SLinus Torvalds #include <net/af_unix.h>	/* for Unix socket types */
741da177e4SLinus Torvalds #include <linux/parser.h>
751da177e4SLinus Torvalds #include <linux/nfs_mount.h>
761da177e4SLinus Torvalds #include <net/ipv6.h>
771da177e4SLinus Torvalds #include <linux/hugetlb.h>
781da177e4SLinus Torvalds #include <linux/personality.h>
791da177e4SLinus Torvalds #include <linux/audit.h>
806931dfc9SEric Paris #include <linux/string.h>
8123970741SEric Paris #include <linux/mutex.h>
82f06febc9SFrank Mayhar #include <linux/posix-timers.h>
8300234592SKees Cook #include <linux/syslog.h>
843486740aSSerge E. Hallyn #include <linux/user_namespace.h>
8544fc7ea0SPaul Gortmaker #include <linux/export.h>
8640401530SAl Viro #include <linux/msg.h>
8740401530SAl Viro #include <linux/shm.h>
88ec27c356SChenbo Feng #include <linux/bpf.h>
89ec882da5SOndrej Mosnacek #include <linux/kernfs.h>
90ec882da5SOndrej Mosnacek #include <linux/stringhash.h>	/* for hashlen_string() */
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 
124be6ec88fSKees Cook int selinux_enabled __lsm_ro_after_init = 1;
1251da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
1261da177e4SLinus Torvalds static int __init selinux_enabled_setup(char *str)
1271da177e4SLinus Torvalds {
128f5269710SEric Paris 	unsigned long enabled;
12929707b20SJingoo Han 	if (!kstrtoul(str, 0, &enabled))
130f5269710SEric Paris 		selinux_enabled = enabled ? 1 : 0;
1311da177e4SLinus Torvalds 	return 1;
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds __setup("selinux=", selinux_enabled_setup);
1341da177e4SLinus Torvalds #endif
1351da177e4SLinus Torvalds 
136aa8e712cSStephen Smalley static unsigned int selinux_checkreqprot_boot =
137aa8e712cSStephen Smalley 	CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE;
138aa8e712cSStephen Smalley 
139aa8e712cSStephen Smalley static int __init checkreqprot_setup(char *str)
140aa8e712cSStephen Smalley {
141aa8e712cSStephen Smalley 	unsigned long checkreqprot;
142aa8e712cSStephen Smalley 
143aa8e712cSStephen Smalley 	if (!kstrtoul(str, 0, &checkreqprot))
144aa8e712cSStephen Smalley 		selinux_checkreqprot_boot = checkreqprot ? 1 : 0;
145aa8e712cSStephen Smalley 	return 1;
146aa8e712cSStephen Smalley }
147aa8e712cSStephen Smalley __setup("checkreqprot=", checkreqprot_setup);
148aa8e712cSStephen Smalley 
149d621d35eSPaul Moore /**
150d621d35eSPaul Moore  * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
151d621d35eSPaul Moore  *
152d621d35eSPaul Moore  * Description:
153d621d35eSPaul Moore  * This function checks the SECMARK reference counter to see if any SECMARK
154d621d35eSPaul Moore  * targets are currently configured, if the reference counter is greater than
155d621d35eSPaul Moore  * zero SECMARK is considered to be enabled.  Returns true (1) if SECMARK is
1562be4d74fSChris PeBenito  * enabled, false (0) if SECMARK is disabled.  If the always_check_network
1572be4d74fSChris PeBenito  * policy capability is enabled, SECMARK is always considered enabled.
158d621d35eSPaul Moore  *
159d621d35eSPaul Moore  */
160d621d35eSPaul Moore static int selinux_secmark_enabled(void)
161d621d35eSPaul Moore {
162aa8e712cSStephen Smalley 	return (selinux_policycap_alwaysnetwork() ||
163aa8e712cSStephen Smalley 		atomic_read(&selinux_secmark_refcount));
1642be4d74fSChris PeBenito }
1652be4d74fSChris PeBenito 
1662be4d74fSChris PeBenito /**
1672be4d74fSChris PeBenito  * selinux_peerlbl_enabled - Check to see if peer labeling is currently enabled
1682be4d74fSChris PeBenito  *
1692be4d74fSChris PeBenito  * Description:
1702be4d74fSChris PeBenito  * This function checks if NetLabel or labeled IPSEC is enabled.  Returns true
1712be4d74fSChris PeBenito  * (1) if any are enabled or false (0) if neither are enabled.  If the
1722be4d74fSChris PeBenito  * always_check_network policy capability is enabled, peer labeling
1732be4d74fSChris PeBenito  * is always considered enabled.
1742be4d74fSChris PeBenito  *
1752be4d74fSChris PeBenito  */
1762be4d74fSChris PeBenito static int selinux_peerlbl_enabled(void)
1772be4d74fSChris PeBenito {
178aa8e712cSStephen Smalley 	return (selinux_policycap_alwaysnetwork() ||
179aa8e712cSStephen Smalley 		netlbl_enabled() || selinux_xfrm_enabled());
180d621d35eSPaul Moore }
181d621d35eSPaul Moore 
182615e51fdSPaul Moore static int selinux_netcache_avc_callback(u32 event)
183615e51fdSPaul Moore {
184615e51fdSPaul Moore 	if (event == AVC_CALLBACK_RESET) {
185615e51fdSPaul Moore 		sel_netif_flush();
186615e51fdSPaul Moore 		sel_netnode_flush();
187615e51fdSPaul Moore 		sel_netport_flush();
188615e51fdSPaul Moore 		synchronize_net();
189615e51fdSPaul Moore 	}
190615e51fdSPaul Moore 	return 0;
191615e51fdSPaul Moore }
192615e51fdSPaul Moore 
1938f408ab6SDaniel Jurgens static int selinux_lsm_notifier_avc_callback(u32 event)
1948f408ab6SDaniel Jurgens {
195409dcf31SDaniel Jurgens 	if (event == AVC_CALLBACK_RESET) {
196409dcf31SDaniel Jurgens 		sel_ib_pkey_flush();
19742df744cSJanne Karhunen 		call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL);
198409dcf31SDaniel Jurgens 	}
1998f408ab6SDaniel Jurgens 
2008f408ab6SDaniel Jurgens 	return 0;
2018f408ab6SDaniel Jurgens }
2028f408ab6SDaniel Jurgens 
203d84f4f99SDavid Howells /*
204d84f4f99SDavid Howells  * initialise the security for the init task
205d84f4f99SDavid Howells  */
206d84f4f99SDavid Howells static void cred_init_security(void)
2071da177e4SLinus Torvalds {
2083b11a1deSDavid Howells 	struct cred *cred = (struct cred *) current->real_cred;
2091da177e4SLinus Torvalds 	struct task_security_struct *tsec;
2101da177e4SLinus Torvalds 
211bbd3662aSCasey Schaufler 	tsec = selinux_cred(cred);
212d84f4f99SDavid Howells 	tsec->osid = tsec->sid = SECINITSID_KERNEL;
2131da177e4SLinus Torvalds }
2141da177e4SLinus Torvalds 
215275bb41eSDavid Howells /*
21688e67f3bSDavid Howells  * get the security ID of a set of credentials
21788e67f3bSDavid Howells  */
21888e67f3bSDavid Howells static inline u32 cred_sid(const struct cred *cred)
21988e67f3bSDavid Howells {
22088e67f3bSDavid Howells 	const struct task_security_struct *tsec;
22188e67f3bSDavid Howells 
2220c6cfa62SCasey Schaufler 	tsec = selinux_cred(cred);
22388e67f3bSDavid Howells 	return tsec->sid;
22488e67f3bSDavid Howells }
22588e67f3bSDavid Howells 
22688e67f3bSDavid Howells /*
2273b11a1deSDavid Howells  * get the objective security ID of a task
228275bb41eSDavid Howells  */
229275bb41eSDavid Howells static inline u32 task_sid(const struct task_struct *task)
230275bb41eSDavid Howells {
231275bb41eSDavid Howells 	u32 sid;
232275bb41eSDavid Howells 
233275bb41eSDavid Howells 	rcu_read_lock();
23488e67f3bSDavid Howells 	sid = cred_sid(__task_cred(task));
235275bb41eSDavid Howells 	rcu_read_unlock();
236275bb41eSDavid Howells 	return sid;
237275bb41eSDavid Howells }
238275bb41eSDavid Howells 
23988e67f3bSDavid Howells /* Allocate and free functions for each kind of security blob. */
24088e67f3bSDavid Howells 
2411da177e4SLinus Torvalds static int inode_alloc_security(struct inode *inode)
2421da177e4SLinus Torvalds {
243afb1cbe3SCasey Schaufler 	struct inode_security_struct *isec = selinux_inode(inode);
244275bb41eSDavid Howells 	u32 sid = current_sid();
2451da177e4SLinus Torvalds 
2469287aed2SAndreas Gruenbacher 	spin_lock_init(&isec->lock);
2471da177e4SLinus Torvalds 	INIT_LIST_HEAD(&isec->list);
2481da177e4SLinus Torvalds 	isec->inode = inode;
2491da177e4SLinus Torvalds 	isec->sid = SECINITSID_UNLABELED;
2501da177e4SLinus Torvalds 	isec->sclass = SECCLASS_FILE;
251275bb41eSDavid Howells 	isec->task_sid = sid;
25242059112SAndreas Gruenbacher 	isec->initialized = LABEL_INVALID;
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	return 0;
2551da177e4SLinus Torvalds }
2561da177e4SLinus Torvalds 
2575d226df4SAndreas Gruenbacher static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
2585d226df4SAndreas Gruenbacher 
2595d226df4SAndreas Gruenbacher /*
2605d226df4SAndreas Gruenbacher  * Try reloading inode security labels that have been marked as invalid.  The
2615d226df4SAndreas Gruenbacher  * @may_sleep parameter indicates when sleeping and thus reloading labels is
26242059112SAndreas Gruenbacher  * allowed; when set to false, returns -ECHILD when the label is
263e9193288SAl Viro  * invalid.  The @dentry parameter should be set to a dentry of the inode.
2645d226df4SAndreas Gruenbacher  */
2655d226df4SAndreas Gruenbacher static int __inode_security_revalidate(struct inode *inode,
266e9193288SAl Viro 				       struct dentry *dentry,
2675d226df4SAndreas Gruenbacher 				       bool may_sleep)
2685d226df4SAndreas Gruenbacher {
26980788c22SCasey Schaufler 	struct inode_security_struct *isec = selinux_inode(inode);
2705d226df4SAndreas Gruenbacher 
2715d226df4SAndreas Gruenbacher 	might_sleep_if(may_sleep);
2725d226df4SAndreas Gruenbacher 
273aa8e712cSStephen Smalley 	if (selinux_state.initialized &&
274aa8e712cSStephen Smalley 	    isec->initialized != LABEL_INITIALIZED) {
2755d226df4SAndreas Gruenbacher 		if (!may_sleep)
2765d226df4SAndreas Gruenbacher 			return -ECHILD;
2775d226df4SAndreas Gruenbacher 
2785d226df4SAndreas Gruenbacher 		/*
2795d226df4SAndreas Gruenbacher 		 * Try reloading the inode security label.  This will fail if
2805d226df4SAndreas Gruenbacher 		 * @opt_dentry is NULL and no dentry for this inode can be
2815d226df4SAndreas Gruenbacher 		 * found; in that case, continue using the old label.
2825d226df4SAndreas Gruenbacher 		 */
283e9193288SAl Viro 		inode_doinit_with_dentry(inode, dentry);
2845d226df4SAndreas Gruenbacher 	}
2855d226df4SAndreas Gruenbacher 	return 0;
2865d226df4SAndreas Gruenbacher }
2875d226df4SAndreas Gruenbacher 
2885d226df4SAndreas Gruenbacher static struct inode_security_struct *inode_security_novalidate(struct inode *inode)
2895d226df4SAndreas Gruenbacher {
29080788c22SCasey Schaufler 	return selinux_inode(inode);
2915d226df4SAndreas Gruenbacher }
2925d226df4SAndreas Gruenbacher 
2935d226df4SAndreas Gruenbacher static struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu)
2945d226df4SAndreas Gruenbacher {
2955d226df4SAndreas Gruenbacher 	int error;
2965d226df4SAndreas Gruenbacher 
2975d226df4SAndreas Gruenbacher 	error = __inode_security_revalidate(inode, NULL, !rcu);
2985d226df4SAndreas Gruenbacher 	if (error)
2995d226df4SAndreas Gruenbacher 		return ERR_PTR(error);
30080788c22SCasey Schaufler 	return selinux_inode(inode);
3015d226df4SAndreas Gruenbacher }
3025d226df4SAndreas Gruenbacher 
30383da53c5SAndreas Gruenbacher /*
30483da53c5SAndreas Gruenbacher  * Get the security label of an inode.
30583da53c5SAndreas Gruenbacher  */
30683da53c5SAndreas Gruenbacher static struct inode_security_struct *inode_security(struct inode *inode)
30783da53c5SAndreas Gruenbacher {
3085d226df4SAndreas Gruenbacher 	__inode_security_revalidate(inode, NULL, true);
30980788c22SCasey Schaufler 	return selinux_inode(inode);
31083da53c5SAndreas Gruenbacher }
31183da53c5SAndreas Gruenbacher 
3122c97165bSPaul Moore static struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry)
3132c97165bSPaul Moore {
3142c97165bSPaul Moore 	struct inode *inode = d_backing_inode(dentry);
3152c97165bSPaul Moore 
31680788c22SCasey Schaufler 	return selinux_inode(inode);
3172c97165bSPaul Moore }
3182c97165bSPaul Moore 
31983da53c5SAndreas Gruenbacher /*
32083da53c5SAndreas Gruenbacher  * Get the security label of a dentry's backing inode.
32183da53c5SAndreas Gruenbacher  */
32283da53c5SAndreas Gruenbacher static struct inode_security_struct *backing_inode_security(struct dentry *dentry)
32383da53c5SAndreas Gruenbacher {
32483da53c5SAndreas Gruenbacher 	struct inode *inode = d_backing_inode(dentry);
32583da53c5SAndreas Gruenbacher 
3265d226df4SAndreas Gruenbacher 	__inode_security_revalidate(inode, dentry, true);
32780788c22SCasey Schaufler 	return selinux_inode(inode);
32883da53c5SAndreas Gruenbacher }
32983da53c5SAndreas Gruenbacher 
3301da177e4SLinus Torvalds static void inode_free_security(struct inode *inode)
3311da177e4SLinus Torvalds {
33280788c22SCasey Schaufler 	struct inode_security_struct *isec = selinux_inode(inode);
333afb1cbe3SCasey Schaufler 	struct superblock_security_struct *sbsec;
3341da177e4SLinus Torvalds 
335afb1cbe3SCasey Schaufler 	if (!isec)
336afb1cbe3SCasey Schaufler 		return;
337afb1cbe3SCasey Schaufler 	sbsec = inode->i_sb->s_security;
3389629d04aSWaiman Long 	/*
3399629d04aSWaiman Long 	 * As not all inode security structures are in a list, we check for
3409629d04aSWaiman Long 	 * empty list outside of the lock to make sure that we won't waste
3419629d04aSWaiman Long 	 * time taking a lock doing nothing.
3429629d04aSWaiman Long 	 *
3439629d04aSWaiman Long 	 * The list_del_init() function can be safely called more than once.
3449629d04aSWaiman Long 	 * It should not be possible for this function to be called with
3459629d04aSWaiman Long 	 * concurrent list_add(), but for better safety against future changes
3469629d04aSWaiman Long 	 * in the code, we use list_empty_careful() here.
3479629d04aSWaiman Long 	 */
3489629d04aSWaiman Long 	if (!list_empty_careful(&isec->list)) {
3491da177e4SLinus Torvalds 		spin_lock(&sbsec->isec_lock);
3501da177e4SLinus Torvalds 		list_del_init(&isec->list);
3511da177e4SLinus Torvalds 		spin_unlock(&sbsec->isec_lock);
3529629d04aSWaiman Long 	}
3531da177e4SLinus Torvalds }
3541da177e4SLinus Torvalds 
3551da177e4SLinus Torvalds static int file_alloc_security(struct file *file)
3561da177e4SLinus Torvalds {
35733bf60caSCasey Schaufler 	struct file_security_struct *fsec = selinux_file(file);
358275bb41eSDavid Howells 	u32 sid = current_sid();
3591da177e4SLinus Torvalds 
360275bb41eSDavid Howells 	fsec->sid = sid;
361275bb41eSDavid Howells 	fsec->fown_sid = sid;
3621da177e4SLinus Torvalds 
3631da177e4SLinus Torvalds 	return 0;
3641da177e4SLinus Torvalds }
3651da177e4SLinus Torvalds 
3661da177e4SLinus Torvalds static int superblock_alloc_security(struct super_block *sb)
3671da177e4SLinus Torvalds {
3681da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec;
3691da177e4SLinus Torvalds 
37089d155efSJames Morris 	sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
3711da177e4SLinus Torvalds 	if (!sbsec)
3721da177e4SLinus Torvalds 		return -ENOMEM;
3731da177e4SLinus Torvalds 
374bc7e982bSEric Paris 	mutex_init(&sbsec->lock);
3751da177e4SLinus Torvalds 	INIT_LIST_HEAD(&sbsec->isec_head);
3761da177e4SLinus Torvalds 	spin_lock_init(&sbsec->isec_lock);
3771da177e4SLinus Torvalds 	sbsec->sb = sb;
3781da177e4SLinus Torvalds 	sbsec->sid = SECINITSID_UNLABELED;
3791da177e4SLinus Torvalds 	sbsec->def_sid = SECINITSID_FILE;
380c312feb2SEric Paris 	sbsec->mntpoint_sid = SECINITSID_UNLABELED;
3811da177e4SLinus Torvalds 	sb->s_security = sbsec;
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 	return 0;
3841da177e4SLinus Torvalds }
3851da177e4SLinus Torvalds 
3861da177e4SLinus Torvalds static void superblock_free_security(struct super_block *sb)
3871da177e4SLinus Torvalds {
3881da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec = sb->s_security;
3891da177e4SLinus Torvalds 	sb->s_security = NULL;
3901da177e4SLinus Torvalds 	kfree(sbsec);
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds 
393bd323655SAl Viro struct selinux_mnt_opts {
394bd323655SAl Viro 	const char *fscontext, *context, *rootcontext, *defcontext;
395bd323655SAl Viro };
396bd323655SAl Viro 
397204cc0ccSAl Viro static void selinux_free_mnt_opts(void *mnt_opts)
398204cc0ccSAl Viro {
399bd323655SAl Viro 	struct selinux_mnt_opts *opts = mnt_opts;
400bd323655SAl Viro 	kfree(opts->fscontext);
401bd323655SAl Viro 	kfree(opts->context);
402bd323655SAl Viro 	kfree(opts->rootcontext);
403bd323655SAl Viro 	kfree(opts->defcontext);
404204cc0ccSAl Viro 	kfree(opts);
405204cc0ccSAl Viro }
406204cc0ccSAl Viro 
4071da177e4SLinus Torvalds static inline int inode_doinit(struct inode *inode)
4081da177e4SLinus Torvalds {
4091da177e4SLinus Torvalds 	return inode_doinit_with_dentry(inode, NULL);
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds 
4121da177e4SLinus Torvalds enum {
41331e87930SEric Paris 	Opt_error = -1,
414442155c1SDavid Howells 	Opt_context = 0,
415442155c1SDavid Howells 	Opt_defcontext = 1,
4161da177e4SLinus Torvalds 	Opt_fscontext = 2,
417442155c1SDavid Howells 	Opt_rootcontext = 3,
418442155c1SDavid Howells 	Opt_seclabel = 4,
4191da177e4SLinus Torvalds };
4201da177e4SLinus Torvalds 
421da3d76abSAl Viro #define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg}
422169d68efSAl Viro static struct {
423169d68efSAl Viro 	const char *name;
424169d68efSAl Viro 	int len;
425169d68efSAl Viro 	int opt;
426169d68efSAl Viro 	bool has_arg;
427169d68efSAl Viro } tokens[] = {
428da3d76abSAl Viro 	A(context, true),
429da3d76abSAl Viro 	A(fscontext, true),
430da3d76abSAl Viro 	A(defcontext, true),
431da3d76abSAl Viro 	A(rootcontext, true),
432da3d76abSAl Viro 	A(seclabel, false),
4331da177e4SLinus Torvalds };
434169d68efSAl Viro #undef A
435169d68efSAl Viro 
436169d68efSAl Viro static int match_opt_prefix(char *s, int l, char **arg)
437169d68efSAl Viro {
438169d68efSAl Viro 	int i;
439169d68efSAl Viro 
440169d68efSAl Viro 	for (i = 0; i < ARRAY_SIZE(tokens); i++) {
441169d68efSAl Viro 		size_t len = tokens[i].len;
442169d68efSAl Viro 		if (len > l || memcmp(s, tokens[i].name, len))
443169d68efSAl Viro 			continue;
444169d68efSAl Viro 		if (tokens[i].has_arg) {
445169d68efSAl Viro 			if (len == l || s[len] != '=')
446169d68efSAl Viro 				continue;
447169d68efSAl Viro 			*arg = s + len + 1;
448169d68efSAl Viro 		} else if (len != l)
449169d68efSAl Viro 			continue;
450169d68efSAl Viro 		return tokens[i].opt;
451169d68efSAl Viro 	}
452169d68efSAl Viro 	return Opt_error;
453169d68efSAl Viro }
4541da177e4SLinus Torvalds 
4551da177e4SLinus Torvalds #define SEL_MOUNT_FAIL_MSG "SELinux:  duplicate or incompatible mount options\n"
4561da177e4SLinus Torvalds 
457c312feb2SEric Paris static int may_context_mount_sb_relabel(u32 sid,
458c312feb2SEric Paris 			struct superblock_security_struct *sbsec,
459275bb41eSDavid Howells 			const struct cred *cred)
460c312feb2SEric Paris {
4610c6cfa62SCasey Schaufler 	const struct task_security_struct *tsec = selinux_cred(cred);
462c312feb2SEric Paris 	int rc;
463c312feb2SEric Paris 
4646b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
4656b6bc620SStephen Smalley 			  tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
466c312feb2SEric Paris 			  FILESYSTEM__RELABELFROM, NULL);
467c312feb2SEric Paris 	if (rc)
468c312feb2SEric Paris 		return rc;
469c312feb2SEric Paris 
4706b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
4716b6bc620SStephen Smalley 			  tsec->sid, sid, SECCLASS_FILESYSTEM,
472c312feb2SEric Paris 			  FILESYSTEM__RELABELTO, NULL);
473c312feb2SEric Paris 	return rc;
474c312feb2SEric Paris }
475c312feb2SEric Paris 
4760808925eSEric Paris static int may_context_mount_inode_relabel(u32 sid,
4770808925eSEric Paris 			struct superblock_security_struct *sbsec,
478275bb41eSDavid Howells 			const struct cred *cred)
4790808925eSEric Paris {
4800c6cfa62SCasey Schaufler 	const struct task_security_struct *tsec = selinux_cred(cred);
4810808925eSEric Paris 	int rc;
4826b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
4836b6bc620SStephen Smalley 			  tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
4840808925eSEric Paris 			  FILESYSTEM__RELABELFROM, NULL);
4850808925eSEric Paris 	if (rc)
4860808925eSEric Paris 		return rc;
4870808925eSEric Paris 
4886b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
4896b6bc620SStephen Smalley 			  sid, sbsec->sid, SECCLASS_FILESYSTEM,
4900808925eSEric Paris 			  FILESYSTEM__ASSOCIATE, NULL);
4910808925eSEric Paris 	return rc;
4920808925eSEric Paris }
4930808925eSEric Paris 
494a83d6ddaSOndrej Mosnacek static int selinux_is_genfs_special_handling(struct super_block *sb)
495b43e725dSEric Paris {
496d5f3a5f6SMark Salyzyn 	/* Special handling. Genfs but also in-core setxattr handler */
497a83d6ddaSOndrej Mosnacek 	return	!strcmp(sb->s_type->name, "sysfs") ||
498d5f3a5f6SMark Salyzyn 		!strcmp(sb->s_type->name, "pstore") ||
499d5f3a5f6SMark Salyzyn 		!strcmp(sb->s_type->name, "debugfs") ||
500a2c7c6fbSYongqin Liu 		!strcmp(sb->s_type->name, "tracefs") ||
5012651225bSStephen Smalley 		!strcmp(sb->s_type->name, "rootfs") ||
502aa8e712cSStephen Smalley 		(selinux_policycap_cgroupseclabel() &&
5032651225bSStephen Smalley 		 (!strcmp(sb->s_type->name, "cgroup") ||
5042651225bSStephen Smalley 		  !strcmp(sb->s_type->name, "cgroup2")));
505b43e725dSEric Paris }
506b43e725dSEric Paris 
507a83d6ddaSOndrej Mosnacek static int selinux_is_sblabel_mnt(struct super_block *sb)
508a83d6ddaSOndrej Mosnacek {
509a83d6ddaSOndrej Mosnacek 	struct superblock_security_struct *sbsec = sb->s_security;
510a83d6ddaSOndrej Mosnacek 
511a83d6ddaSOndrej Mosnacek 	/*
512a83d6ddaSOndrej Mosnacek 	 * IMPORTANT: Double-check logic in this function when adding a new
513a83d6ddaSOndrej Mosnacek 	 * SECURITY_FS_USE_* definition!
514a83d6ddaSOndrej Mosnacek 	 */
515a83d6ddaSOndrej Mosnacek 	BUILD_BUG_ON(SECURITY_FS_USE_MAX != 7);
516a83d6ddaSOndrej Mosnacek 
517a83d6ddaSOndrej Mosnacek 	switch (sbsec->behavior) {
518a83d6ddaSOndrej Mosnacek 	case SECURITY_FS_USE_XATTR:
519a83d6ddaSOndrej Mosnacek 	case SECURITY_FS_USE_TRANS:
520a83d6ddaSOndrej Mosnacek 	case SECURITY_FS_USE_TASK:
521a83d6ddaSOndrej Mosnacek 	case SECURITY_FS_USE_NATIVE:
522a83d6ddaSOndrej Mosnacek 		return 1;
523a83d6ddaSOndrej Mosnacek 
524a83d6ddaSOndrej Mosnacek 	case SECURITY_FS_USE_GENFS:
525a83d6ddaSOndrej Mosnacek 		return selinux_is_genfs_special_handling(sb);
526a83d6ddaSOndrej Mosnacek 
527a83d6ddaSOndrej Mosnacek 	/* Never allow relabeling on context mounts */
528a83d6ddaSOndrej Mosnacek 	case SECURITY_FS_USE_MNTPOINT:
529a83d6ddaSOndrej Mosnacek 	case SECURITY_FS_USE_NONE:
530a83d6ddaSOndrej Mosnacek 	default:
531a83d6ddaSOndrej Mosnacek 		return 0;
532a83d6ddaSOndrej Mosnacek 	}
533a83d6ddaSOndrej Mosnacek }
534a83d6ddaSOndrej Mosnacek 
535c9180a57SEric Paris static int sb_finish_set_opts(struct super_block *sb)
5361da177e4SLinus Torvalds {
5371da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec = sb->s_security;
5381da177e4SLinus Torvalds 	struct dentry *root = sb->s_root;
539c6f493d6SDavid Howells 	struct inode *root_inode = d_backing_inode(root);
5401da177e4SLinus Torvalds 	int rc = 0;
5411da177e4SLinus Torvalds 
5421da177e4SLinus Torvalds 	if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
5431da177e4SLinus Torvalds 		/* Make sure that the xattr handler exists and that no
5441da177e4SLinus Torvalds 		   error other than -ENODATA is returned by getxattr on
5451da177e4SLinus Torvalds 		   the root directory.  -ENODATA is ok, as this may be
5461da177e4SLinus Torvalds 		   the first boot of the SELinux kernel before we have
5471da177e4SLinus Torvalds 		   assigned xattr values to the filesystem. */
5485d6c3191SAndreas Gruenbacher 		if (!(root_inode->i_opflags & IOP_XATTR)) {
549c103a91eSpeter enderborg 			pr_warn("SELinux: (dev %s, type %s) has no "
55029b1deb2SLinus Torvalds 			       "xattr support\n", sb->s_id, sb->s_type->name);
5511da177e4SLinus Torvalds 			rc = -EOPNOTSUPP;
5521da177e4SLinus Torvalds 			goto out;
5531da177e4SLinus Torvalds 		}
5545d6c3191SAndreas Gruenbacher 
5555d6c3191SAndreas Gruenbacher 		rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
5561da177e4SLinus Torvalds 		if (rc < 0 && rc != -ENODATA) {
5571da177e4SLinus Torvalds 			if (rc == -EOPNOTSUPP)
558c103a91eSpeter enderborg 				pr_warn("SELinux: (dev %s, type "
55929b1deb2SLinus Torvalds 				       "%s) has no security xattr handler\n",
56029b1deb2SLinus Torvalds 				       sb->s_id, sb->s_type->name);
5611da177e4SLinus Torvalds 			else
562c103a91eSpeter enderborg 				pr_warn("SELinux: (dev %s, type "
56329b1deb2SLinus Torvalds 				       "%s) getxattr errno %d\n", sb->s_id,
56429b1deb2SLinus Torvalds 				       sb->s_type->name, -rc);
5651da177e4SLinus Torvalds 			goto out;
5661da177e4SLinus Torvalds 		}
5671da177e4SLinus Torvalds 	}
5681da177e4SLinus Torvalds 
569eadcabc6SEric Paris 	sbsec->flags |= SE_SBINITIALIZED;
5700b4d3452SScott Mayhew 
5710b4d3452SScott Mayhew 	/*
5720b4d3452SScott Mayhew 	 * Explicitly set or clear SBLABEL_MNT.  It's not sufficient to simply
5730b4d3452SScott Mayhew 	 * leave the flag untouched because sb_clone_mnt_opts might be handing
5740b4d3452SScott Mayhew 	 * us a superblock that needs the flag to be cleared.
5750b4d3452SScott Mayhew 	 */
576b43e725dSEric Paris 	if (selinux_is_sblabel_mnt(sb))
57712f348b9SEric Paris 		sbsec->flags |= SBLABEL_MNT;
5780b4d3452SScott Mayhew 	else
5790b4d3452SScott Mayhew 		sbsec->flags &= ~SBLABEL_MNT;
580ddd29ec6SDavid P. Quigley 
5811da177e4SLinus Torvalds 	/* Initialize the root inode. */
582c9180a57SEric Paris 	rc = inode_doinit_with_dentry(root_inode, root);
5831da177e4SLinus Torvalds 
5841da177e4SLinus Torvalds 	/* Initialize any other inodes associated with the superblock, e.g.
5851da177e4SLinus Torvalds 	   inodes created prior to initial policy load or inodes created
5861da177e4SLinus Torvalds 	   during get_sb by a pseudo filesystem that directly
5871da177e4SLinus Torvalds 	   populates itself. */
5881da177e4SLinus Torvalds 	spin_lock(&sbsec->isec_lock);
5898d64124aSAl Viro 	while (!list_empty(&sbsec->isec_head)) {
5901da177e4SLinus Torvalds 		struct inode_security_struct *isec =
5918d64124aSAl Viro 				list_first_entry(&sbsec->isec_head,
5921da177e4SLinus Torvalds 					   struct inode_security_struct, list);
5931da177e4SLinus Torvalds 		struct inode *inode = isec->inode;
594923190d3SStephen Smalley 		list_del_init(&isec->list);
5951da177e4SLinus Torvalds 		spin_unlock(&sbsec->isec_lock);
5961da177e4SLinus Torvalds 		inode = igrab(inode);
5971da177e4SLinus Torvalds 		if (inode) {
5981da177e4SLinus Torvalds 			if (!IS_PRIVATE(inode))
5991da177e4SLinus Torvalds 				inode_doinit(inode);
6001da177e4SLinus Torvalds 			iput(inode);
6011da177e4SLinus Torvalds 		}
6021da177e4SLinus Torvalds 		spin_lock(&sbsec->isec_lock);
6031da177e4SLinus Torvalds 	}
6041da177e4SLinus Torvalds 	spin_unlock(&sbsec->isec_lock);
6051da177e4SLinus Torvalds out:
606c9180a57SEric Paris 	return rc;
607c9180a57SEric Paris }
608c9180a57SEric Paris 
609c9180a57SEric Paris static int bad_option(struct superblock_security_struct *sbsec, char flag,
610c9180a57SEric Paris 		      u32 old_sid, u32 new_sid)
611c9180a57SEric Paris {
6120d90a7ecSDavid P. Quigley 	char mnt_flags = sbsec->flags & SE_MNTMASK;
6130d90a7ecSDavid P. Quigley 
614c9180a57SEric Paris 	/* check if the old mount command had the same options */
6150d90a7ecSDavid P. Quigley 	if (sbsec->flags & SE_SBINITIALIZED)
616c9180a57SEric Paris 		if (!(sbsec->flags & flag) ||
617c9180a57SEric Paris 		    (old_sid != new_sid))
618c9180a57SEric Paris 			return 1;
619c9180a57SEric Paris 
620c9180a57SEric Paris 	/* check if we were passed the same options twice,
621c9180a57SEric Paris 	 * aka someone passed context=a,context=b
622c9180a57SEric Paris 	 */
6230d90a7ecSDavid P. Quigley 	if (!(sbsec->flags & SE_SBINITIALIZED))
6240d90a7ecSDavid P. Quigley 		if (mnt_flags & flag)
625c9180a57SEric Paris 			return 1;
626c9180a57SEric Paris 	return 0;
627c9180a57SEric Paris }
628e0007529SEric Paris 
629bd323655SAl Viro static int parse_sid(struct super_block *sb, const char *s, u32 *sid)
630bd323655SAl Viro {
631bd323655SAl Viro 	int rc = security_context_str_to_sid(&selinux_state, s,
632bd323655SAl Viro 					     sid, GFP_KERNEL);
633bd323655SAl Viro 	if (rc)
634bd323655SAl Viro 		pr_warn("SELinux: security_context_str_to_sid"
635bd323655SAl Viro 		       "(%s) failed for (dev %s, type %s) errno=%d\n",
636bd323655SAl Viro 		       s, sb->s_id, sb->s_type->name, rc);
637bd323655SAl Viro 	return rc;
638bd323655SAl Viro }
639bd323655SAl Viro 
640c9180a57SEric Paris /*
641c9180a57SEric Paris  * Allow filesystems with binary mount data to explicitly set mount point
642c9180a57SEric Paris  * labeling information.
643c9180a57SEric Paris  */
644e0007529SEric Paris static int selinux_set_mnt_opts(struct super_block *sb,
645204cc0ccSAl Viro 				void *mnt_opts,
646649f6e77SDavid Quigley 				unsigned long kern_flags,
647649f6e77SDavid Quigley 				unsigned long *set_kern_flags)
648c9180a57SEric Paris {
649275bb41eSDavid Howells 	const struct cred *cred = current_cred();
650c9180a57SEric Paris 	struct superblock_security_struct *sbsec = sb->s_security;
65183da53c5SAndreas Gruenbacher 	struct dentry *root = sbsec->sb->s_root;
652bd323655SAl Viro 	struct selinux_mnt_opts *opts = mnt_opts;
6532c97165bSPaul Moore 	struct inode_security_struct *root_isec;
654c9180a57SEric Paris 	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
655c9180a57SEric Paris 	u32 defcontext_sid = 0;
656bd323655SAl Viro 	int rc = 0;
657c9180a57SEric Paris 
658c9180a57SEric Paris 	mutex_lock(&sbsec->lock);
659c9180a57SEric Paris 
660aa8e712cSStephen Smalley 	if (!selinux_state.initialized) {
661bd323655SAl Viro 		if (!opts) {
662c9180a57SEric Paris 			/* Defer initialization until selinux_complete_init,
663c9180a57SEric Paris 			   after the initial policy is loaded and the security
664c9180a57SEric Paris 			   server is ready to handle calls. */
665c9180a57SEric Paris 			goto out;
666c9180a57SEric Paris 		}
667c9180a57SEric Paris 		rc = -EINVAL;
668c103a91eSpeter enderborg 		pr_warn("SELinux: Unable to set superblock options "
669744ba35eSEric Paris 			"before the security server is initialized\n");
670c9180a57SEric Paris 		goto out;
671c9180a57SEric Paris 	}
672649f6e77SDavid Quigley 	if (kern_flags && !set_kern_flags) {
673649f6e77SDavid Quigley 		/* Specifying internal flags without providing a place to
674649f6e77SDavid Quigley 		 * place the results is not allowed */
675649f6e77SDavid Quigley 		rc = -EINVAL;
676649f6e77SDavid Quigley 		goto out;
677649f6e77SDavid Quigley 	}
678c9180a57SEric Paris 
679c9180a57SEric Paris 	/*
680e0007529SEric Paris 	 * Binary mount data FS will come through this function twice.  Once
681e0007529SEric Paris 	 * from an explicit call and once from the generic calls from the vfs.
682e0007529SEric Paris 	 * Since the generic VFS calls will not contain any security mount data
683e0007529SEric Paris 	 * we need to skip the double mount verification.
684e0007529SEric Paris 	 *
685e0007529SEric Paris 	 * This does open a hole in which we will not notice if the first
686e0007529SEric Paris 	 * mount using this sb set explict options and a second mount using
687e0007529SEric Paris 	 * this sb does not set any security options.  (The first options
688e0007529SEric Paris 	 * will be used for both mounts)
689e0007529SEric Paris 	 */
6900d90a7ecSDavid P. Quigley 	if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
691bd323655SAl Viro 	    && !opts)
692e0007529SEric Paris 		goto out;
693e0007529SEric Paris 
6942c97165bSPaul Moore 	root_isec = backing_inode_security_novalidate(root);
6952c97165bSPaul Moore 
696e0007529SEric Paris 	/*
697c9180a57SEric Paris 	 * parse the mount options, check if they are valid sids.
698c9180a57SEric Paris 	 * also check if someone is trying to mount the same sb more
699c9180a57SEric Paris 	 * than once with different security options.
700c9180a57SEric Paris 	 */
701bd323655SAl Viro 	if (opts) {
702bd323655SAl Viro 		if (opts->fscontext) {
703bd323655SAl Viro 			rc = parse_sid(sb, opts->fscontext, &fscontext_sid);
704bd323655SAl Viro 			if (rc)
705c9180a57SEric Paris 				goto out;
706c9180a57SEric Paris 			if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
707c9180a57SEric Paris 					fscontext_sid))
708c9180a57SEric Paris 				goto out_double_mount;
709c9180a57SEric Paris 			sbsec->flags |= FSCONTEXT_MNT;
710bd323655SAl Viro 		}
711bd323655SAl Viro 		if (opts->context) {
712bd323655SAl Viro 			rc = parse_sid(sb, opts->context, &context_sid);
713bd323655SAl Viro 			if (rc)
714bd323655SAl Viro 				goto out;
715c9180a57SEric Paris 			if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
716c9180a57SEric Paris 					context_sid))
717c9180a57SEric Paris 				goto out_double_mount;
718c9180a57SEric Paris 			sbsec->flags |= CONTEXT_MNT;
719bd323655SAl Viro 		}
720bd323655SAl Viro 		if (opts->rootcontext) {
721bd323655SAl Viro 			rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid);
722bd323655SAl Viro 			if (rc)
723bd323655SAl Viro 				goto out;
724c9180a57SEric Paris 			if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
725c9180a57SEric Paris 					rootcontext_sid))
726c9180a57SEric Paris 				goto out_double_mount;
727c9180a57SEric Paris 			sbsec->flags |= ROOTCONTEXT_MNT;
728bd323655SAl Viro 		}
729bd323655SAl Viro 		if (opts->defcontext) {
730bd323655SAl Viro 			rc = parse_sid(sb, opts->defcontext, &defcontext_sid);
731bd323655SAl Viro 			if (rc)
732bd323655SAl Viro 				goto out;
733c9180a57SEric Paris 			if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
734c9180a57SEric Paris 					defcontext_sid))
735c9180a57SEric Paris 				goto out_double_mount;
736c9180a57SEric Paris 			sbsec->flags |= DEFCONTEXT_MNT;
737c9180a57SEric Paris 		}
738c9180a57SEric Paris 	}
739c9180a57SEric Paris 
7400d90a7ecSDavid P. Quigley 	if (sbsec->flags & SE_SBINITIALIZED) {
741c9180a57SEric Paris 		/* previously mounted with options, but not on this attempt? */
742bd323655SAl Viro 		if ((sbsec->flags & SE_MNTMASK) && !opts)
743c9180a57SEric Paris 			goto out_double_mount;
744c9180a57SEric Paris 		rc = 0;
745c9180a57SEric Paris 		goto out;
746c9180a57SEric Paris 	}
747c9180a57SEric Paris 
748089be43eSJames Morris 	if (strcmp(sb->s_type->name, "proc") == 0)
749134509d5SStephen Smalley 		sbsec->flags |= SE_SBPROC | SE_SBGENFS;
750134509d5SStephen Smalley 
7518e014720SStephen Smalley 	if (!strcmp(sb->s_type->name, "debugfs") ||
7526a391183SJeff Vander Stoep 	    !strcmp(sb->s_type->name, "tracefs") ||
753b754026bSOndrej Mosnacek 	    !strcmp(sb->s_type->name, "pstore"))
754b754026bSOndrej Mosnacek 		sbsec->flags |= SE_SBGENFS;
755b754026bSOndrej Mosnacek 
756b754026bSOndrej Mosnacek 	if (!strcmp(sb->s_type->name, "sysfs") ||
757901ef845SAntonio Murdaca 	    !strcmp(sb->s_type->name, "cgroup") ||
758901ef845SAntonio Murdaca 	    !strcmp(sb->s_type->name, "cgroup2"))
759b754026bSOndrej Mosnacek 		sbsec->flags |= SE_SBGENFS | SE_SBGENFS_XATTR;
760c9180a57SEric Paris 
761eb9ae686SDavid Quigley 	if (!sbsec->behavior) {
762eb9ae686SDavid Quigley 		/*
763eb9ae686SDavid Quigley 		 * Determine the labeling behavior to use for this
764eb9ae686SDavid Quigley 		 * filesystem type.
765eb9ae686SDavid Quigley 		 */
766aa8e712cSStephen Smalley 		rc = security_fs_use(&selinux_state, sb);
767c9180a57SEric Paris 		if (rc) {
768c103a91eSpeter enderborg 			pr_warn("%s: security_fs_use(%s) returned %d\n",
769089be43eSJames Morris 					__func__, sb->s_type->name, rc);
770c9180a57SEric Paris 			goto out;
771c9180a57SEric Paris 		}
772eb9ae686SDavid Quigley 	}
773aad82892SSeth Forshee 
774aad82892SSeth Forshee 	/*
77501593d32SStephen Smalley 	 * If this is a user namespace mount and the filesystem type is not
77601593d32SStephen Smalley 	 * explicitly whitelisted, then no contexts are allowed on the command
77701593d32SStephen Smalley 	 * line and security labels must be ignored.
778aad82892SSeth Forshee 	 */
77901593d32SStephen Smalley 	if (sb->s_user_ns != &init_user_ns &&
78001593d32SStephen Smalley 	    strcmp(sb->s_type->name, "tmpfs") &&
78101593d32SStephen Smalley 	    strcmp(sb->s_type->name, "ramfs") &&
78201593d32SStephen Smalley 	    strcmp(sb->s_type->name, "devpts")) {
783aad82892SSeth Forshee 		if (context_sid || fscontext_sid || rootcontext_sid ||
784aad82892SSeth Forshee 		    defcontext_sid) {
785aad82892SSeth Forshee 			rc = -EACCES;
786aad82892SSeth Forshee 			goto out;
787aad82892SSeth Forshee 		}
788aad82892SSeth Forshee 		if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
789aad82892SSeth Forshee 			sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
790aa8e712cSStephen Smalley 			rc = security_transition_sid(&selinux_state,
791aa8e712cSStephen Smalley 						     current_sid(),
792aa8e712cSStephen Smalley 						     current_sid(),
793aad82892SSeth Forshee 						     SECCLASS_FILE, NULL,
794aad82892SSeth Forshee 						     &sbsec->mntpoint_sid);
795aad82892SSeth Forshee 			if (rc)
796aad82892SSeth Forshee 				goto out;
797aad82892SSeth Forshee 		}
798aad82892SSeth Forshee 		goto out_set_opts;
799aad82892SSeth Forshee 	}
800aad82892SSeth Forshee 
801c9180a57SEric Paris 	/* sets the context of the superblock for the fs being mounted. */
802c9180a57SEric Paris 	if (fscontext_sid) {
803275bb41eSDavid Howells 		rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
804c9180a57SEric Paris 		if (rc)
805c9180a57SEric Paris 			goto out;
806c9180a57SEric Paris 
807c9180a57SEric Paris 		sbsec->sid = fscontext_sid;
808c9180a57SEric Paris 	}
809c9180a57SEric Paris 
810c9180a57SEric Paris 	/*
811c9180a57SEric Paris 	 * Switch to using mount point labeling behavior.
812c9180a57SEric Paris 	 * sets the label used on all file below the mountpoint, and will set
813c9180a57SEric Paris 	 * the superblock context if not already set.
814c9180a57SEric Paris 	 */
815eb9ae686SDavid Quigley 	if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
816eb9ae686SDavid Quigley 		sbsec->behavior = SECURITY_FS_USE_NATIVE;
817eb9ae686SDavid Quigley 		*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
818eb9ae686SDavid Quigley 	}
819eb9ae686SDavid Quigley 
820c9180a57SEric Paris 	if (context_sid) {
821c9180a57SEric Paris 		if (!fscontext_sid) {
822275bb41eSDavid Howells 			rc = may_context_mount_sb_relabel(context_sid, sbsec,
823275bb41eSDavid Howells 							  cred);
824c9180a57SEric Paris 			if (rc)
825c9180a57SEric Paris 				goto out;
826c9180a57SEric Paris 			sbsec->sid = context_sid;
827c9180a57SEric Paris 		} else {
828275bb41eSDavid Howells 			rc = may_context_mount_inode_relabel(context_sid, sbsec,
829275bb41eSDavid Howells 							     cred);
830c9180a57SEric Paris 			if (rc)
831c9180a57SEric Paris 				goto out;
832c9180a57SEric Paris 		}
833c9180a57SEric Paris 		if (!rootcontext_sid)
834c9180a57SEric Paris 			rootcontext_sid = context_sid;
835c9180a57SEric Paris 
836c9180a57SEric Paris 		sbsec->mntpoint_sid = context_sid;
837c9180a57SEric Paris 		sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
838c9180a57SEric Paris 	}
839c9180a57SEric Paris 
840c9180a57SEric Paris 	if (rootcontext_sid) {
841275bb41eSDavid Howells 		rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
842275bb41eSDavid Howells 						     cred);
843c9180a57SEric Paris 		if (rc)
844c9180a57SEric Paris 			goto out;
845c9180a57SEric Paris 
846c9180a57SEric Paris 		root_isec->sid = rootcontext_sid;
8476f3be9f5SAndreas Gruenbacher 		root_isec->initialized = LABEL_INITIALIZED;
848c9180a57SEric Paris 	}
849c9180a57SEric Paris 
850c9180a57SEric Paris 	if (defcontext_sid) {
851eb9ae686SDavid Quigley 		if (sbsec->behavior != SECURITY_FS_USE_XATTR &&
852eb9ae686SDavid Quigley 			sbsec->behavior != SECURITY_FS_USE_NATIVE) {
853c9180a57SEric Paris 			rc = -EINVAL;
854c103a91eSpeter enderborg 			pr_warn("SELinux: defcontext option is "
855c9180a57SEric Paris 			       "invalid for this filesystem type\n");
856c9180a57SEric Paris 			goto out;
857c9180a57SEric Paris 		}
858c9180a57SEric Paris 
859c9180a57SEric Paris 		if (defcontext_sid != sbsec->def_sid) {
860c9180a57SEric Paris 			rc = may_context_mount_inode_relabel(defcontext_sid,
861275bb41eSDavid Howells 							     sbsec, cred);
862c9180a57SEric Paris 			if (rc)
863c9180a57SEric Paris 				goto out;
864c9180a57SEric Paris 		}
865c9180a57SEric Paris 
866c9180a57SEric Paris 		sbsec->def_sid = defcontext_sid;
867c9180a57SEric Paris 	}
868c9180a57SEric Paris 
869aad82892SSeth Forshee out_set_opts:
870c9180a57SEric Paris 	rc = sb_finish_set_opts(sb);
871c9180a57SEric Paris out:
872bc7e982bSEric Paris 	mutex_unlock(&sbsec->lock);
8731da177e4SLinus Torvalds 	return rc;
874c9180a57SEric Paris out_double_mount:
875c9180a57SEric Paris 	rc = -EINVAL;
876c103a91eSpeter enderborg 	pr_warn("SELinux: mount invalid.  Same superblock, different "
877bd323655SAl Viro 	       "security settings for (dev %s, type %s)\n", sb->s_id,
878bd323655SAl Viro 	       sb->s_type->name);
879c9180a57SEric Paris 	goto out;
880c9180a57SEric Paris }
881c9180a57SEric Paris 
882094f7b69SJeff Layton static int selinux_cmp_sb_context(const struct super_block *oldsb,
883094f7b69SJeff Layton 				    const struct super_block *newsb)
884094f7b69SJeff Layton {
885094f7b69SJeff Layton 	struct superblock_security_struct *old = oldsb->s_security;
886094f7b69SJeff Layton 	struct superblock_security_struct *new = newsb->s_security;
887094f7b69SJeff Layton 	char oldflags = old->flags & SE_MNTMASK;
888094f7b69SJeff Layton 	char newflags = new->flags & SE_MNTMASK;
889094f7b69SJeff Layton 
890094f7b69SJeff Layton 	if (oldflags != newflags)
891094f7b69SJeff Layton 		goto mismatch;
892094f7b69SJeff Layton 	if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid)
893094f7b69SJeff Layton 		goto mismatch;
894094f7b69SJeff Layton 	if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid)
895094f7b69SJeff Layton 		goto mismatch;
896094f7b69SJeff Layton 	if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid)
897094f7b69SJeff Layton 		goto mismatch;
898094f7b69SJeff Layton 	if (oldflags & ROOTCONTEXT_MNT) {
89983da53c5SAndreas Gruenbacher 		struct inode_security_struct *oldroot = backing_inode_security(oldsb->s_root);
90083da53c5SAndreas Gruenbacher 		struct inode_security_struct *newroot = backing_inode_security(newsb->s_root);
901094f7b69SJeff Layton 		if (oldroot->sid != newroot->sid)
902094f7b69SJeff Layton 			goto mismatch;
903094f7b69SJeff Layton 	}
904094f7b69SJeff Layton 	return 0;
905094f7b69SJeff Layton mismatch:
906c103a91eSpeter enderborg 	pr_warn("SELinux: mount invalid.  Same superblock, "
907094f7b69SJeff Layton 			    "different security settings for (dev %s, "
908094f7b69SJeff Layton 			    "type %s)\n", newsb->s_id, newsb->s_type->name);
909094f7b69SJeff Layton 	return -EBUSY;
910094f7b69SJeff Layton }
911094f7b69SJeff Layton 
912094f7b69SJeff Layton static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
9130b4d3452SScott Mayhew 					struct super_block *newsb,
9140b4d3452SScott Mayhew 					unsigned long kern_flags,
9150b4d3452SScott Mayhew 					unsigned long *set_kern_flags)
916c9180a57SEric Paris {
9170b4d3452SScott Mayhew 	int rc = 0;
918c9180a57SEric Paris 	const struct superblock_security_struct *oldsbsec = oldsb->s_security;
919c9180a57SEric Paris 	struct superblock_security_struct *newsbsec = newsb->s_security;
920c9180a57SEric Paris 
921c9180a57SEric Paris 	int set_fscontext =	(oldsbsec->flags & FSCONTEXT_MNT);
922c9180a57SEric Paris 	int set_context =	(oldsbsec->flags & CONTEXT_MNT);
923c9180a57SEric Paris 	int set_rootcontext =	(oldsbsec->flags & ROOTCONTEXT_MNT);
924c9180a57SEric Paris 
9250f5e6420SEric Paris 	/*
9260f5e6420SEric Paris 	 * if the parent was able to be mounted it clearly had no special lsm
927e8c26255SAl Viro 	 * mount options.  thus we can safely deal with this superblock later
9280f5e6420SEric Paris 	 */
929aa8e712cSStephen Smalley 	if (!selinux_state.initialized)
930094f7b69SJeff Layton 		return 0;
931c9180a57SEric Paris 
9320b4d3452SScott Mayhew 	/*
9330b4d3452SScott Mayhew 	 * Specifying internal flags without providing a place to
9340b4d3452SScott Mayhew 	 * place the results is not allowed.
9350b4d3452SScott Mayhew 	 */
9360b4d3452SScott Mayhew 	if (kern_flags && !set_kern_flags)
9370b4d3452SScott Mayhew 		return -EINVAL;
9380b4d3452SScott Mayhew 
939c9180a57SEric Paris 	/* how can we clone if the old one wasn't set up?? */
9400d90a7ecSDavid P. Quigley 	BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
941c9180a57SEric Paris 
942094f7b69SJeff Layton 	/* if fs is reusing a sb, make sure that the contexts match */
9433815a245SJ. Bruce Fields 	if (newsbsec->flags & SE_SBINITIALIZED) {
9443815a245SJ. Bruce Fields 		if ((kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context)
9453815a245SJ. Bruce Fields 			*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
946094f7b69SJeff Layton 		return selinux_cmp_sb_context(oldsb, newsb);
9473815a245SJ. Bruce Fields 	}
9485a552617SEric Paris 
949c9180a57SEric Paris 	mutex_lock(&newsbsec->lock);
950c9180a57SEric Paris 
951c9180a57SEric Paris 	newsbsec->flags = oldsbsec->flags;
952c9180a57SEric Paris 
953c9180a57SEric Paris 	newsbsec->sid = oldsbsec->sid;
954c9180a57SEric Paris 	newsbsec->def_sid = oldsbsec->def_sid;
955c9180a57SEric Paris 	newsbsec->behavior = oldsbsec->behavior;
956c9180a57SEric Paris 
9570b4d3452SScott Mayhew 	if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
9580b4d3452SScott Mayhew 		!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
959aa8e712cSStephen Smalley 		rc = security_fs_use(&selinux_state, newsb);
9600b4d3452SScott Mayhew 		if (rc)
9610b4d3452SScott Mayhew 			goto out;
9620b4d3452SScott Mayhew 	}
9630b4d3452SScott Mayhew 
9640b4d3452SScott Mayhew 	if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !set_context) {
9650b4d3452SScott Mayhew 		newsbsec->behavior = SECURITY_FS_USE_NATIVE;
9660b4d3452SScott Mayhew 		*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
9670b4d3452SScott Mayhew 	}
9680b4d3452SScott Mayhew 
969c9180a57SEric Paris 	if (set_context) {
970c9180a57SEric Paris 		u32 sid = oldsbsec->mntpoint_sid;
971c9180a57SEric Paris 
972c9180a57SEric Paris 		if (!set_fscontext)
973c9180a57SEric Paris 			newsbsec->sid = sid;
974c9180a57SEric Paris 		if (!set_rootcontext) {
97583da53c5SAndreas Gruenbacher 			struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
976c9180a57SEric Paris 			newisec->sid = sid;
977c9180a57SEric Paris 		}
978c9180a57SEric Paris 		newsbsec->mntpoint_sid = sid;
979c9180a57SEric Paris 	}
980c9180a57SEric Paris 	if (set_rootcontext) {
98183da53c5SAndreas Gruenbacher 		const struct inode_security_struct *oldisec = backing_inode_security(oldsb->s_root);
98283da53c5SAndreas Gruenbacher 		struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
983c9180a57SEric Paris 
984c9180a57SEric Paris 		newisec->sid = oldisec->sid;
985c9180a57SEric Paris 	}
986c9180a57SEric Paris 
987c9180a57SEric Paris 	sb_finish_set_opts(newsb);
9880b4d3452SScott Mayhew out:
989c9180a57SEric Paris 	mutex_unlock(&newsbsec->lock);
9900b4d3452SScott Mayhew 	return rc;
991c9180a57SEric Paris }
992c9180a57SEric Paris 
993ba641862SAl Viro static int selinux_add_opt(int token, const char *s, void **mnt_opts)
994c9180a57SEric Paris {
995ba641862SAl Viro 	struct selinux_mnt_opts *opts = *mnt_opts;
996c9180a57SEric Paris 
997da3d76abSAl Viro 	if (token == Opt_seclabel)	/* eaten and completely ignored */
998e0007529SEric Paris 		return 0;
999e0007529SEric Paris 
1000ba641862SAl Viro 	if (!opts) {
1001ba641862SAl Viro 		opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
1002ba641862SAl Viro 		if (!opts)
1003ba641862SAl Viro 			return -ENOMEM;
1004ba641862SAl Viro 		*mnt_opts = opts;
1005ba641862SAl Viro 	}
1006ba641862SAl Viro 	if (!s)
1007ba641862SAl Viro 		return -ENOMEM;
1008ba641862SAl Viro 	switch (token) {
1009ba641862SAl Viro 	case Opt_context:
1010ba641862SAl Viro 		if (opts->context || opts->defcontext)
1011ba641862SAl Viro 			goto Einval;
1012ba641862SAl Viro 		opts->context = s;
1013ba641862SAl Viro 		break;
1014ba641862SAl Viro 	case Opt_fscontext:
1015ba641862SAl Viro 		if (opts->fscontext)
1016ba641862SAl Viro 			goto Einval;
1017ba641862SAl Viro 		opts->fscontext = s;
1018ba641862SAl Viro 		break;
1019ba641862SAl Viro 	case Opt_rootcontext:
1020ba641862SAl Viro 		if (opts->rootcontext)
1021ba641862SAl Viro 			goto Einval;
1022ba641862SAl Viro 		opts->rootcontext = s;
1023ba641862SAl Viro 		break;
1024ba641862SAl Viro 	case Opt_defcontext:
1025ba641862SAl Viro 		if (opts->context || opts->defcontext)
1026ba641862SAl Viro 			goto Einval;
1027ba641862SAl Viro 		opts->defcontext = s;
1028ba641862SAl Viro 		break;
1029ba641862SAl Viro 	}
1030ba641862SAl Viro 	return 0;
1031ba641862SAl Viro Einval:
1032ba641862SAl Viro 	pr_warn(SEL_MOUNT_FAIL_MSG);
1033ba641862SAl Viro 	return -EINVAL;
1034ba641862SAl Viro }
1035ba641862SAl Viro 
1036757cbe59SAl Viro static int selinux_add_mnt_opt(const char *option, const char *val, int len,
1037204cc0ccSAl Viro 			       void **mnt_opts)
1038c9180a57SEric Paris {
1039757cbe59SAl Viro 	int token = Opt_error;
1040757cbe59SAl Viro 	int rc, i;
1041c9180a57SEric Paris 
1042757cbe59SAl Viro 	for (i = 0; i < ARRAY_SIZE(tokens); i++) {
1043757cbe59SAl Viro 		if (strcmp(option, tokens[i].name) == 0) {
1044757cbe59SAl Viro 			token = tokens[i].opt;
1045757cbe59SAl Viro 			break;
1046757cbe59SAl Viro 		}
1047169d68efSAl Viro 	}
1048169d68efSAl Viro 
1049757cbe59SAl Viro 	if (token == Opt_error)
1050757cbe59SAl Viro 		return -EINVAL;
1051c9180a57SEric Paris 
1052e2e0e097SGen Zhang 	if (token != Opt_seclabel) {
1053757cbe59SAl Viro 		val = kmemdup_nul(val, len, GFP_KERNEL);
1054e2e0e097SGen Zhang 		if (!val) {
1055e2e0e097SGen Zhang 			rc = -ENOMEM;
1056e2e0e097SGen Zhang 			goto free_opt;
1057e2e0e097SGen Zhang 		}
1058e2e0e097SGen Zhang 	}
1059757cbe59SAl Viro 	rc = selinux_add_opt(token, val, mnt_opts);
1060757cbe59SAl Viro 	if (unlikely(rc)) {
1061757cbe59SAl Viro 		kfree(val);
1062e2e0e097SGen Zhang 		goto free_opt;
1063e2e0e097SGen Zhang 	}
1064e2e0e097SGen Zhang 	return rc;
1065e2e0e097SGen Zhang 
1066e2e0e097SGen Zhang free_opt:
1067757cbe59SAl Viro 	if (*mnt_opts) {
1068ba641862SAl Viro 		selinux_free_mnt_opts(*mnt_opts);
1069ba641862SAl Viro 		*mnt_opts = NULL;
1070757cbe59SAl Viro 	}
1071c9180a57SEric Paris 	return rc;
10721da177e4SLinus Torvalds }
10731da177e4SLinus Torvalds 
1074e3489f89SAl Viro static int show_sid(struct seq_file *m, u32 sid)
10752069f457SEric Paris {
1076e3489f89SAl Viro 	char *context = NULL;
1077e3489f89SAl Viro 	u32 len;
1078e3489f89SAl Viro 	int rc;
10792069f457SEric Paris 
1080e3489f89SAl Viro 	rc = security_sid_to_context(&selinux_state, sid,
1081e3489f89SAl Viro 					     &context, &len);
1082e3489f89SAl Viro 	if (!rc) {
1083e3489f89SAl Viro 		bool has_comma = context && strchr(context, ',');
108411689d47SDavid P. Quigley 
1085442155c1SDavid Howells 		seq_putc(m, '=');
10862069f457SEric Paris 		if (has_comma)
10872069f457SEric Paris 			seq_putc(m, '\"');
1088e3489f89SAl Viro 		seq_escape(m, context, "\"\n\\");
10892069f457SEric Paris 		if (has_comma)
10902069f457SEric Paris 			seq_putc(m, '\"');
10912069f457SEric Paris 	}
10921da177e4SLinus Torvalds 	kfree(context);
10931da177e4SLinus Torvalds 	return rc;
10941da177e4SLinus Torvalds }
10952069f457SEric Paris 
10962069f457SEric Paris static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
10972069f457SEric Paris {
1098e3489f89SAl Viro 	struct superblock_security_struct *sbsec = sb->s_security;
10992069f457SEric Paris 	int rc;
11002069f457SEric Paris 
1101e3489f89SAl Viro 	if (!(sbsec->flags & SE_SBINITIALIZED))
1102e3489f89SAl Viro 		return 0;
1103e3489f89SAl Viro 
1104e3489f89SAl Viro 	if (!selinux_state.initialized)
1105e3489f89SAl Viro 		return 0;
1106e3489f89SAl Viro 
1107e3489f89SAl Viro 	if (sbsec->flags & FSCONTEXT_MNT) {
1108e3489f89SAl Viro 		seq_putc(m, ',');
1109e3489f89SAl Viro 		seq_puts(m, FSCONTEXT_STR);
1110e3489f89SAl Viro 		rc = show_sid(m, sbsec->sid);
1111e3489f89SAl Viro 		if (rc)
11122069f457SEric Paris 			return rc;
1113383795c2SEric Paris 	}
1114e3489f89SAl Viro 	if (sbsec->flags & CONTEXT_MNT) {
1115e3489f89SAl Viro 		seq_putc(m, ',');
1116e3489f89SAl Viro 		seq_puts(m, CONTEXT_STR);
1117e3489f89SAl Viro 		rc = show_sid(m, sbsec->mntpoint_sid);
1118e3489f89SAl Viro 		if (rc)
11192069f457SEric Paris 			return rc;
11202069f457SEric Paris 	}
1121e3489f89SAl Viro 	if (sbsec->flags & DEFCONTEXT_MNT) {
1122e3489f89SAl Viro 		seq_putc(m, ',');
1123e3489f89SAl Viro 		seq_puts(m, DEFCONTEXT_STR);
1124e3489f89SAl Viro 		rc = show_sid(m, sbsec->def_sid);
1125e3489f89SAl Viro 		if (rc)
1126e3489f89SAl Viro 			return rc;
1127e3489f89SAl Viro 	}
1128e3489f89SAl Viro 	if (sbsec->flags & ROOTCONTEXT_MNT) {
1129e3489f89SAl Viro 		struct dentry *root = sbsec->sb->s_root;
1130e3489f89SAl Viro 		struct inode_security_struct *isec = backing_inode_security(root);
1131e3489f89SAl Viro 		seq_putc(m, ',');
1132e3489f89SAl Viro 		seq_puts(m, ROOTCONTEXT_STR);
1133e3489f89SAl Viro 		rc = show_sid(m, isec->sid);
1134e3489f89SAl Viro 		if (rc)
1135e3489f89SAl Viro 			return rc;
1136e3489f89SAl Viro 	}
1137e3489f89SAl Viro 	if (sbsec->flags & SBLABEL_MNT) {
1138e3489f89SAl Viro 		seq_putc(m, ',');
1139442155c1SDavid Howells 		seq_puts(m, SECLABEL_STR);
1140e3489f89SAl Viro 	}
1141e3489f89SAl Viro 	return 0;
1142e3489f89SAl Viro }
11432069f457SEric Paris 
11441da177e4SLinus Torvalds static inline u16 inode_mode_to_security_class(umode_t mode)
11451da177e4SLinus Torvalds {
11461da177e4SLinus Torvalds 	switch (mode & S_IFMT) {
11471da177e4SLinus Torvalds 	case S_IFSOCK:
11481da177e4SLinus Torvalds 		return SECCLASS_SOCK_FILE;
11491da177e4SLinus Torvalds 	case S_IFLNK:
11501da177e4SLinus Torvalds 		return SECCLASS_LNK_FILE;
11511da177e4SLinus Torvalds 	case S_IFREG:
11521da177e4SLinus Torvalds 		return SECCLASS_FILE;
11531da177e4SLinus Torvalds 	case S_IFBLK:
11541da177e4SLinus Torvalds 		return SECCLASS_BLK_FILE;
11551da177e4SLinus Torvalds 	case S_IFDIR:
11561da177e4SLinus Torvalds 		return SECCLASS_DIR;
11571da177e4SLinus Torvalds 	case S_IFCHR:
11581da177e4SLinus Torvalds 		return SECCLASS_CHR_FILE;
11591da177e4SLinus Torvalds 	case S_IFIFO:
11601da177e4SLinus Torvalds 		return SECCLASS_FIFO_FILE;
11611da177e4SLinus Torvalds 
11621da177e4SLinus Torvalds 	}
11631da177e4SLinus Torvalds 
11641da177e4SLinus Torvalds 	return SECCLASS_FILE;
11651da177e4SLinus Torvalds }
11661da177e4SLinus Torvalds 
116713402580SJames Morris static inline int default_protocol_stream(int protocol)
116813402580SJames Morris {
116913402580SJames Morris 	return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP);
117013402580SJames Morris }
117113402580SJames Morris 
117213402580SJames Morris static inline int default_protocol_dgram(int protocol)
117313402580SJames Morris {
117413402580SJames Morris 	return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
117513402580SJames Morris }
117613402580SJames Morris 
11771da177e4SLinus Torvalds static inline u16 socket_type_to_security_class(int family, int type, int protocol)
11781da177e4SLinus Torvalds {
1179aa8e712cSStephen Smalley 	int extsockclass = selinux_policycap_extsockclass();
1180da69a530SStephen Smalley 
11811da177e4SLinus Torvalds 	switch (family) {
11821da177e4SLinus Torvalds 	case PF_UNIX:
11831da177e4SLinus Torvalds 		switch (type) {
11841da177e4SLinus Torvalds 		case SOCK_STREAM:
11851da177e4SLinus Torvalds 		case SOCK_SEQPACKET:
11861da177e4SLinus Torvalds 			return SECCLASS_UNIX_STREAM_SOCKET;
11871da177e4SLinus Torvalds 		case SOCK_DGRAM:
11882a764b52SLuis Ressel 		case SOCK_RAW:
11891da177e4SLinus Torvalds 			return SECCLASS_UNIX_DGRAM_SOCKET;
11901da177e4SLinus Torvalds 		}
11911da177e4SLinus Torvalds 		break;
11921da177e4SLinus Torvalds 	case PF_INET:
11931da177e4SLinus Torvalds 	case PF_INET6:
11941da177e4SLinus Torvalds 		switch (type) {
11951da177e4SLinus Torvalds 		case SOCK_STREAM:
1196da69a530SStephen Smalley 		case SOCK_SEQPACKET:
119713402580SJames Morris 			if (default_protocol_stream(protocol))
11981da177e4SLinus Torvalds 				return SECCLASS_TCP_SOCKET;
1199da69a530SStephen Smalley 			else if (extsockclass && protocol == IPPROTO_SCTP)
1200da69a530SStephen Smalley 				return SECCLASS_SCTP_SOCKET;
120113402580SJames Morris 			else
120213402580SJames Morris 				return SECCLASS_RAWIP_SOCKET;
12031da177e4SLinus Torvalds 		case SOCK_DGRAM:
120413402580SJames Morris 			if (default_protocol_dgram(protocol))
12051da177e4SLinus Torvalds 				return SECCLASS_UDP_SOCKET;
1206ef37979aSStephen Smalley 			else if (extsockclass && (protocol == IPPROTO_ICMP ||
1207ef37979aSStephen Smalley 						  protocol == IPPROTO_ICMPV6))
1208da69a530SStephen Smalley 				return SECCLASS_ICMP_SOCKET;
120913402580SJames Morris 			else
121013402580SJames Morris 				return SECCLASS_RAWIP_SOCKET;
12112ee92d46SJames Morris 		case SOCK_DCCP:
12122ee92d46SJames Morris 			return SECCLASS_DCCP_SOCKET;
121313402580SJames Morris 		default:
12141da177e4SLinus Torvalds 			return SECCLASS_RAWIP_SOCKET;
12151da177e4SLinus Torvalds 		}
12161da177e4SLinus Torvalds 		break;
12171da177e4SLinus Torvalds 	case PF_NETLINK:
12181da177e4SLinus Torvalds 		switch (protocol) {
12191da177e4SLinus Torvalds 		case NETLINK_ROUTE:
12201da177e4SLinus Torvalds 			return SECCLASS_NETLINK_ROUTE_SOCKET;
12217f1fb60cSPavel Emelyanov 		case NETLINK_SOCK_DIAG:
12221da177e4SLinus Torvalds 			return SECCLASS_NETLINK_TCPDIAG_SOCKET;
12231da177e4SLinus Torvalds 		case NETLINK_NFLOG:
12241da177e4SLinus Torvalds 			return SECCLASS_NETLINK_NFLOG_SOCKET;
12251da177e4SLinus Torvalds 		case NETLINK_XFRM:
12261da177e4SLinus Torvalds 			return SECCLASS_NETLINK_XFRM_SOCKET;
12271da177e4SLinus Torvalds 		case NETLINK_SELINUX:
12281da177e4SLinus Torvalds 			return SECCLASS_NETLINK_SELINUX_SOCKET;
12296c6d2e9bSStephen Smalley 		case NETLINK_ISCSI:
12306c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_ISCSI_SOCKET;
12311da177e4SLinus Torvalds 		case NETLINK_AUDIT:
12321da177e4SLinus Torvalds 			return SECCLASS_NETLINK_AUDIT_SOCKET;
12336c6d2e9bSStephen Smalley 		case NETLINK_FIB_LOOKUP:
12346c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_FIB_LOOKUP_SOCKET;
12356c6d2e9bSStephen Smalley 		case NETLINK_CONNECTOR:
12366c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_CONNECTOR_SOCKET;
12376c6d2e9bSStephen Smalley 		case NETLINK_NETFILTER:
12386c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_NETFILTER_SOCKET;
12391da177e4SLinus Torvalds 		case NETLINK_DNRTMSG:
12401da177e4SLinus Torvalds 			return SECCLASS_NETLINK_DNRT_SOCKET;
12410c9b7942SJames Morris 		case NETLINK_KOBJECT_UEVENT:
12420c9b7942SJames Morris 			return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
12436c6d2e9bSStephen Smalley 		case NETLINK_GENERIC:
12446c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_GENERIC_SOCKET;
12456c6d2e9bSStephen Smalley 		case NETLINK_SCSITRANSPORT:
12466c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_SCSITRANSPORT_SOCKET;
12476c6d2e9bSStephen Smalley 		case NETLINK_RDMA:
12486c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_RDMA_SOCKET;
12496c6d2e9bSStephen Smalley 		case NETLINK_CRYPTO:
12506c6d2e9bSStephen Smalley 			return SECCLASS_NETLINK_CRYPTO_SOCKET;
12511da177e4SLinus Torvalds 		default:
12521da177e4SLinus Torvalds 			return SECCLASS_NETLINK_SOCKET;
12531da177e4SLinus Torvalds 		}
12541da177e4SLinus Torvalds 	case PF_PACKET:
12551da177e4SLinus Torvalds 		return SECCLASS_PACKET_SOCKET;
12561da177e4SLinus Torvalds 	case PF_KEY:
12571da177e4SLinus Torvalds 		return SECCLASS_KEY_SOCKET;
12583e3ff15eSChristopher J. PeBenito 	case PF_APPLETALK:
12593e3ff15eSChristopher J. PeBenito 		return SECCLASS_APPLETALK_SOCKET;
12601da177e4SLinus Torvalds 	}
12611da177e4SLinus Torvalds 
1262da69a530SStephen Smalley 	if (extsockclass) {
1263da69a530SStephen Smalley 		switch (family) {
1264da69a530SStephen Smalley 		case PF_AX25:
1265da69a530SStephen Smalley 			return SECCLASS_AX25_SOCKET;
1266da69a530SStephen Smalley 		case PF_IPX:
1267da69a530SStephen Smalley 			return SECCLASS_IPX_SOCKET;
1268da69a530SStephen Smalley 		case PF_NETROM:
1269da69a530SStephen Smalley 			return SECCLASS_NETROM_SOCKET;
1270da69a530SStephen Smalley 		case PF_ATMPVC:
1271da69a530SStephen Smalley 			return SECCLASS_ATMPVC_SOCKET;
1272da69a530SStephen Smalley 		case PF_X25:
1273da69a530SStephen Smalley 			return SECCLASS_X25_SOCKET;
1274da69a530SStephen Smalley 		case PF_ROSE:
1275da69a530SStephen Smalley 			return SECCLASS_ROSE_SOCKET;
1276da69a530SStephen Smalley 		case PF_DECnet:
1277da69a530SStephen Smalley 			return SECCLASS_DECNET_SOCKET;
1278da69a530SStephen Smalley 		case PF_ATMSVC:
1279da69a530SStephen Smalley 			return SECCLASS_ATMSVC_SOCKET;
1280da69a530SStephen Smalley 		case PF_RDS:
1281da69a530SStephen Smalley 			return SECCLASS_RDS_SOCKET;
1282da69a530SStephen Smalley 		case PF_IRDA:
1283da69a530SStephen Smalley 			return SECCLASS_IRDA_SOCKET;
1284da69a530SStephen Smalley 		case PF_PPPOX:
1285da69a530SStephen Smalley 			return SECCLASS_PPPOX_SOCKET;
1286da69a530SStephen Smalley 		case PF_LLC:
1287da69a530SStephen Smalley 			return SECCLASS_LLC_SOCKET;
1288da69a530SStephen Smalley 		case PF_CAN:
1289da69a530SStephen Smalley 			return SECCLASS_CAN_SOCKET;
1290da69a530SStephen Smalley 		case PF_TIPC:
1291da69a530SStephen Smalley 			return SECCLASS_TIPC_SOCKET;
1292da69a530SStephen Smalley 		case PF_BLUETOOTH:
1293da69a530SStephen Smalley 			return SECCLASS_BLUETOOTH_SOCKET;
1294da69a530SStephen Smalley 		case PF_IUCV:
1295da69a530SStephen Smalley 			return SECCLASS_IUCV_SOCKET;
1296da69a530SStephen Smalley 		case PF_RXRPC:
1297da69a530SStephen Smalley 			return SECCLASS_RXRPC_SOCKET;
1298da69a530SStephen Smalley 		case PF_ISDN:
1299da69a530SStephen Smalley 			return SECCLASS_ISDN_SOCKET;
1300da69a530SStephen Smalley 		case PF_PHONET:
1301da69a530SStephen Smalley 			return SECCLASS_PHONET_SOCKET;
1302da69a530SStephen Smalley 		case PF_IEEE802154:
1303da69a530SStephen Smalley 			return SECCLASS_IEEE802154_SOCKET;
1304da69a530SStephen Smalley 		case PF_CAIF:
1305da69a530SStephen Smalley 			return SECCLASS_CAIF_SOCKET;
1306da69a530SStephen Smalley 		case PF_ALG:
1307da69a530SStephen Smalley 			return SECCLASS_ALG_SOCKET;
1308da69a530SStephen Smalley 		case PF_NFC:
1309da69a530SStephen Smalley 			return SECCLASS_NFC_SOCKET;
1310da69a530SStephen Smalley 		case PF_VSOCK:
1311da69a530SStephen Smalley 			return SECCLASS_VSOCK_SOCKET;
1312da69a530SStephen Smalley 		case PF_KCM:
1313da69a530SStephen Smalley 			return SECCLASS_KCM_SOCKET;
1314da69a530SStephen Smalley 		case PF_QIPCRTR:
1315da69a530SStephen Smalley 			return SECCLASS_QIPCRTR_SOCKET;
13163051bf36SLinus Torvalds 		case PF_SMC:
13173051bf36SLinus Torvalds 			return SECCLASS_SMC_SOCKET;
131868e8b849SBjörn Töpel 		case PF_XDP:
131968e8b849SBjörn Töpel 			return SECCLASS_XDP_SOCKET;
132068e8b849SBjörn Töpel #if PF_MAX > 45
1321da69a530SStephen Smalley #error New address family defined, please update this function.
1322da69a530SStephen Smalley #endif
1323da69a530SStephen Smalley 		}
1324da69a530SStephen Smalley 	}
1325da69a530SStephen Smalley 
13261da177e4SLinus Torvalds 	return SECCLASS_SOCKET;
13271da177e4SLinus Torvalds }
13281da177e4SLinus Torvalds 
1329134509d5SStephen Smalley static int selinux_genfs_get_sid(struct dentry *dentry,
13301da177e4SLinus Torvalds 				 u16 tclass,
1331134509d5SStephen Smalley 				 u16 flags,
13321da177e4SLinus Torvalds 				 u32 *sid)
13331da177e4SLinus Torvalds {
13348e6c9693SLucian Adrian Grijincu 	int rc;
1335fc64005cSAl Viro 	struct super_block *sb = dentry->d_sb;
13368e6c9693SLucian Adrian Grijincu 	char *buffer, *path;
13371da177e4SLinus Torvalds 
13381da177e4SLinus Torvalds 	buffer = (char *)__get_free_page(GFP_KERNEL);
13391da177e4SLinus Torvalds 	if (!buffer)
13401da177e4SLinus Torvalds 		return -ENOMEM;
13411da177e4SLinus Torvalds 
13428e6c9693SLucian Adrian Grijincu 	path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
13438e6c9693SLucian Adrian Grijincu 	if (IS_ERR(path))
13448e6c9693SLucian Adrian Grijincu 		rc = PTR_ERR(path);
13458e6c9693SLucian Adrian Grijincu 	else {
1346134509d5SStephen Smalley 		if (flags & SE_SBPROC) {
13478e6c9693SLucian Adrian Grijincu 			/* each process gets a /proc/PID/ entry. Strip off the
13488e6c9693SLucian Adrian Grijincu 			 * PID part to get a valid selinux labeling.
13498e6c9693SLucian Adrian Grijincu 			 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
13508e6c9693SLucian Adrian Grijincu 			while (path[1] >= '0' && path[1] <= '9') {
13518e6c9693SLucian Adrian Grijincu 				path[1] = '/';
13528e6c9693SLucian Adrian Grijincu 				path++;
13531da177e4SLinus Torvalds 			}
1354134509d5SStephen Smalley 		}
1355aa8e712cSStephen Smalley 		rc = security_genfs_sid(&selinux_state, sb->s_type->name,
1356aa8e712cSStephen Smalley 					path, tclass, sid);
13577bb185edSStephen Smalley 		if (rc == -ENOENT) {
13587bb185edSStephen Smalley 			/* No match in policy, mark as unlabeled. */
13597bb185edSStephen Smalley 			*sid = SECINITSID_UNLABELED;
13607bb185edSStephen Smalley 			rc = 0;
13617bb185edSStephen Smalley 		}
13628e6c9693SLucian Adrian Grijincu 	}
13631da177e4SLinus Torvalds 	free_page((unsigned long)buffer);
13641da177e4SLinus Torvalds 	return rc;
13651da177e4SLinus Torvalds }
13661da177e4SLinus Torvalds 
1367b754026bSOndrej Mosnacek static int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
1368b754026bSOndrej Mosnacek 				  u32 def_sid, u32 *sid)
1369b754026bSOndrej Mosnacek {
1370b754026bSOndrej Mosnacek #define INITCONTEXTLEN 255
1371b754026bSOndrej Mosnacek 	char *context;
1372b754026bSOndrej Mosnacek 	unsigned int len;
1373b754026bSOndrej Mosnacek 	int rc;
1374b754026bSOndrej Mosnacek 
1375b754026bSOndrej Mosnacek 	len = INITCONTEXTLEN;
1376b754026bSOndrej Mosnacek 	context = kmalloc(len + 1, GFP_NOFS);
1377b754026bSOndrej Mosnacek 	if (!context)
1378b754026bSOndrej Mosnacek 		return -ENOMEM;
1379b754026bSOndrej Mosnacek 
1380b754026bSOndrej Mosnacek 	context[len] = '\0';
1381b754026bSOndrej Mosnacek 	rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
1382b754026bSOndrej Mosnacek 	if (rc == -ERANGE) {
1383b754026bSOndrej Mosnacek 		kfree(context);
1384b754026bSOndrej Mosnacek 
1385b754026bSOndrej Mosnacek 		/* Need a larger buffer.  Query for the right size. */
1386b754026bSOndrej Mosnacek 		rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0);
1387b754026bSOndrej Mosnacek 		if (rc < 0)
1388b754026bSOndrej Mosnacek 			return rc;
1389b754026bSOndrej Mosnacek 
1390b754026bSOndrej Mosnacek 		len = rc;
1391b754026bSOndrej Mosnacek 		context = kmalloc(len + 1, GFP_NOFS);
1392b754026bSOndrej Mosnacek 		if (!context)
1393b754026bSOndrej Mosnacek 			return -ENOMEM;
1394b754026bSOndrej Mosnacek 
1395b754026bSOndrej Mosnacek 		context[len] = '\0';
1396b754026bSOndrej Mosnacek 		rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX,
1397b754026bSOndrej Mosnacek 				    context, len);
1398b754026bSOndrej Mosnacek 	}
1399b754026bSOndrej Mosnacek 	if (rc < 0) {
1400b754026bSOndrej Mosnacek 		kfree(context);
1401b754026bSOndrej Mosnacek 		if (rc != -ENODATA) {
1402b754026bSOndrej Mosnacek 			pr_warn("SELinux: %s:  getxattr returned %d for dev=%s ino=%ld\n",
1403b754026bSOndrej Mosnacek 				__func__, -rc, inode->i_sb->s_id, inode->i_ino);
1404b754026bSOndrej Mosnacek 			return rc;
1405b754026bSOndrej Mosnacek 		}
1406b754026bSOndrej Mosnacek 		*sid = def_sid;
1407b754026bSOndrej Mosnacek 		return 0;
1408b754026bSOndrej Mosnacek 	}
1409b754026bSOndrej Mosnacek 
1410b754026bSOndrej Mosnacek 	rc = security_context_to_sid_default(&selinux_state, context, rc, sid,
1411b754026bSOndrej Mosnacek 					     def_sid, GFP_NOFS);
1412b754026bSOndrej Mosnacek 	if (rc) {
1413b754026bSOndrej Mosnacek 		char *dev = inode->i_sb->s_id;
1414b754026bSOndrej Mosnacek 		unsigned long ino = inode->i_ino;
1415b754026bSOndrej Mosnacek 
1416b754026bSOndrej Mosnacek 		if (rc == -EINVAL) {
1417b754026bSOndrej Mosnacek 			pr_notice_ratelimited("SELinux: inode=%lu on dev=%s was found to have an invalid context=%s.  This indicates you may need to relabel the inode or the filesystem in question.\n",
1418b754026bSOndrej Mosnacek 					      ino, dev, context);
1419b754026bSOndrej Mosnacek 		} else {
1420b754026bSOndrej Mosnacek 			pr_warn("SELinux: %s:  context_to_sid(%s) returned %d for dev=%s ino=%ld\n",
1421b754026bSOndrej Mosnacek 				__func__, context, -rc, dev, ino);
1422b754026bSOndrej Mosnacek 		}
1423b754026bSOndrej Mosnacek 	}
1424b754026bSOndrej Mosnacek 	kfree(context);
1425b754026bSOndrej Mosnacek 	return 0;
1426b754026bSOndrej Mosnacek }
1427b754026bSOndrej Mosnacek 
14281da177e4SLinus Torvalds /* The inode's security attributes must be initialized before first use. */
14291da177e4SLinus Torvalds static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
14301da177e4SLinus Torvalds {
14311da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec = NULL;
143280788c22SCasey Schaufler 	struct inode_security_struct *isec = selinux_inode(inode);
14339287aed2SAndreas Gruenbacher 	u32 task_sid, sid = 0;
14349287aed2SAndreas Gruenbacher 	u16 sclass;
14351da177e4SLinus Torvalds 	struct dentry *dentry;
14361da177e4SLinus Torvalds 	int rc = 0;
14371da177e4SLinus Torvalds 
14386f3be9f5SAndreas Gruenbacher 	if (isec->initialized == LABEL_INITIALIZED)
143913457d07SAndreas Gruenbacher 		return 0;
14401da177e4SLinus Torvalds 
14419287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
14426f3be9f5SAndreas Gruenbacher 	if (isec->initialized == LABEL_INITIALIZED)
144323970741SEric Paris 		goto out_unlock;
14441da177e4SLinus Torvalds 
144513457d07SAndreas Gruenbacher 	if (isec->sclass == SECCLASS_FILE)
144613457d07SAndreas Gruenbacher 		isec->sclass = inode_mode_to_security_class(inode->i_mode);
144713457d07SAndreas Gruenbacher 
14481da177e4SLinus Torvalds 	sbsec = inode->i_sb->s_security;
14490d90a7ecSDavid P. Quigley 	if (!(sbsec->flags & SE_SBINITIALIZED)) {
14501da177e4SLinus Torvalds 		/* Defer initialization until selinux_complete_init,
14511da177e4SLinus Torvalds 		   after the initial policy is loaded and the security
14521da177e4SLinus Torvalds 		   server is ready to handle calls. */
14531da177e4SLinus Torvalds 		spin_lock(&sbsec->isec_lock);
14541da177e4SLinus Torvalds 		if (list_empty(&isec->list))
14551da177e4SLinus Torvalds 			list_add(&isec->list, &sbsec->isec_head);
14561da177e4SLinus Torvalds 		spin_unlock(&sbsec->isec_lock);
145723970741SEric Paris 		goto out_unlock;
14581da177e4SLinus Torvalds 	}
14591da177e4SLinus Torvalds 
14609287aed2SAndreas Gruenbacher 	sclass = isec->sclass;
14619287aed2SAndreas Gruenbacher 	task_sid = isec->task_sid;
14629287aed2SAndreas Gruenbacher 	sid = isec->sid;
14639287aed2SAndreas Gruenbacher 	isec->initialized = LABEL_PENDING;
14649287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
14659287aed2SAndreas Gruenbacher 
14661da177e4SLinus Torvalds 	switch (sbsec->behavior) {
1467eb9ae686SDavid Quigley 	case SECURITY_FS_USE_NATIVE:
1468eb9ae686SDavid Quigley 		break;
14691da177e4SLinus Torvalds 	case SECURITY_FS_USE_XATTR:
14705d6c3191SAndreas Gruenbacher 		if (!(inode->i_opflags & IOP_XATTR)) {
14719287aed2SAndreas Gruenbacher 			sid = sbsec->def_sid;
14721da177e4SLinus Torvalds 			break;
14731da177e4SLinus Torvalds 		}
14741da177e4SLinus Torvalds 		/* Need a dentry, since the xattr API requires one.
14751da177e4SLinus Torvalds 		   Life would be simpler if we could just pass the inode. */
14761da177e4SLinus Torvalds 		if (opt_dentry) {
14771da177e4SLinus Torvalds 			/* Called from d_instantiate or d_splice_alias. */
14781da177e4SLinus Torvalds 			dentry = dget(opt_dentry);
14791da177e4SLinus Torvalds 		} else {
1480b127125dSAl Viro 			/*
1481b127125dSAl Viro 			 * Called from selinux_complete_init, try to find a dentry.
1482b127125dSAl Viro 			 * Some filesystems really want a connected one, so try
1483b127125dSAl Viro 			 * that first.  We could split SECURITY_FS_USE_XATTR in
1484b127125dSAl Viro 			 * two, depending upon that...
1485b127125dSAl Viro 			 */
14861da177e4SLinus Torvalds 			dentry = d_find_alias(inode);
1487b127125dSAl Viro 			if (!dentry)
1488b127125dSAl Viro 				dentry = d_find_any_alias(inode);
14891da177e4SLinus Torvalds 		}
14901da177e4SLinus Torvalds 		if (!dentry) {
1491df7f54c0SEric Paris 			/*
1492df7f54c0SEric Paris 			 * this is can be hit on boot when a file is accessed
1493df7f54c0SEric Paris 			 * before the policy is loaded.  When we load policy we
1494df7f54c0SEric Paris 			 * may find inodes that have no dentry on the
1495df7f54c0SEric Paris 			 * sbsec->isec_head list.  No reason to complain as these
1496df7f54c0SEric Paris 			 * will get fixed up the next time we go through
1497df7f54c0SEric Paris 			 * inode_doinit with a dentry, before these inodes could
1498df7f54c0SEric Paris 			 * be used again by userspace.
1499df7f54c0SEric Paris 			 */
15009287aed2SAndreas Gruenbacher 			goto out;
15011da177e4SLinus Torvalds 		}
15021da177e4SLinus Torvalds 
1503b754026bSOndrej Mosnacek 		rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid,
1504b754026bSOndrej Mosnacek 					    &sid);
15051da177e4SLinus Torvalds 		dput(dentry);
1506b754026bSOndrej Mosnacek 		if (rc)
15079287aed2SAndreas Gruenbacher 			goto out;
15081da177e4SLinus Torvalds 		break;
15091da177e4SLinus Torvalds 	case SECURITY_FS_USE_TASK:
15109287aed2SAndreas Gruenbacher 		sid = task_sid;
15111da177e4SLinus Torvalds 		break;
15121da177e4SLinus Torvalds 	case SECURITY_FS_USE_TRANS:
15131da177e4SLinus Torvalds 		/* Default to the fs SID. */
15149287aed2SAndreas Gruenbacher 		sid = sbsec->sid;
15151da177e4SLinus Torvalds 
15161da177e4SLinus Torvalds 		/* Try to obtain a transition SID. */
1517aa8e712cSStephen Smalley 		rc = security_transition_sid(&selinux_state, task_sid, sid,
1518aa8e712cSStephen Smalley 					     sclass, NULL, &sid);
15191da177e4SLinus Torvalds 		if (rc)
15209287aed2SAndreas Gruenbacher 			goto out;
15211da177e4SLinus Torvalds 		break;
1522c312feb2SEric Paris 	case SECURITY_FS_USE_MNTPOINT:
15239287aed2SAndreas Gruenbacher 		sid = sbsec->mntpoint_sid;
1524c312feb2SEric Paris 		break;
15251da177e4SLinus Torvalds 	default:
1526c312feb2SEric Paris 		/* Default to the fs superblock SID. */
15279287aed2SAndreas Gruenbacher 		sid = sbsec->sid;
15281da177e4SLinus Torvalds 
1529134509d5SStephen Smalley 		if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) {
1530f64410ecSPaul Moore 			/* We must have a dentry to determine the label on
1531f64410ecSPaul Moore 			 * procfs inodes */
1532b127125dSAl Viro 			if (opt_dentry) {
1533f64410ecSPaul Moore 				/* Called from d_instantiate or
1534f64410ecSPaul Moore 				 * d_splice_alias. */
1535f64410ecSPaul Moore 				dentry = dget(opt_dentry);
1536b127125dSAl Viro 			} else {
1537f64410ecSPaul Moore 				/* Called from selinux_complete_init, try to
1538b127125dSAl Viro 				 * find a dentry.  Some filesystems really want
1539b127125dSAl Viro 				 * a connected one, so try that first.
1540b127125dSAl Viro 				 */
1541f64410ecSPaul Moore 				dentry = d_find_alias(inode);
1542b127125dSAl Viro 				if (!dentry)
1543b127125dSAl Viro 					dentry = d_find_any_alias(inode);
1544b127125dSAl Viro 			}
1545f64410ecSPaul Moore 			/*
1546f64410ecSPaul Moore 			 * This can be hit on boot when a file is accessed
1547f64410ecSPaul Moore 			 * before the policy is loaded.  When we load policy we
1548f64410ecSPaul Moore 			 * may find inodes that have no dentry on the
1549f64410ecSPaul Moore 			 * sbsec->isec_head list.  No reason to complain as
1550f64410ecSPaul Moore 			 * these will get fixed up the next time we go through
1551f64410ecSPaul Moore 			 * inode_doinit() with a dentry, before these inodes
1552f64410ecSPaul Moore 			 * could be used again by userspace.
1553f64410ecSPaul Moore 			 */
1554f64410ecSPaul Moore 			if (!dentry)
15559287aed2SAndreas Gruenbacher 				goto out;
15569287aed2SAndreas Gruenbacher 			rc = selinux_genfs_get_sid(dentry, sclass,
1557134509d5SStephen Smalley 						   sbsec->flags, &sid);
1558b754026bSOndrej Mosnacek 			if (rc) {
1559f64410ecSPaul Moore 				dput(dentry);
15609287aed2SAndreas Gruenbacher 				goto out;
15611da177e4SLinus Torvalds 			}
1562b754026bSOndrej Mosnacek 
1563b754026bSOndrej Mosnacek 			if ((sbsec->flags & SE_SBGENFS_XATTR) &&
1564b754026bSOndrej Mosnacek 			    (inode->i_opflags & IOP_XATTR)) {
1565b754026bSOndrej Mosnacek 				rc = inode_doinit_use_xattr(inode, dentry,
1566b754026bSOndrej Mosnacek 							    sid, &sid);
1567b754026bSOndrej Mosnacek 				if (rc) {
1568b754026bSOndrej Mosnacek 					dput(dentry);
1569b754026bSOndrej Mosnacek 					goto out;
1570b754026bSOndrej Mosnacek 				}
1571b754026bSOndrej Mosnacek 			}
1572b754026bSOndrej Mosnacek 			dput(dentry);
1573b754026bSOndrej Mosnacek 		}
15741da177e4SLinus Torvalds 		break;
15751da177e4SLinus Torvalds 	}
15761da177e4SLinus Torvalds 
15779287aed2SAndreas Gruenbacher out:
15789287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
15799287aed2SAndreas Gruenbacher 	if (isec->initialized == LABEL_PENDING) {
15809287aed2SAndreas Gruenbacher 		if (!sid || rc) {
15819287aed2SAndreas Gruenbacher 			isec->initialized = LABEL_INVALID;
15829287aed2SAndreas Gruenbacher 			goto out_unlock;
15839287aed2SAndreas Gruenbacher 		}
15849287aed2SAndreas Gruenbacher 
15856f3be9f5SAndreas Gruenbacher 		isec->initialized = LABEL_INITIALIZED;
15869287aed2SAndreas Gruenbacher 		isec->sid = sid;
15879287aed2SAndreas Gruenbacher 	}
15881da177e4SLinus Torvalds 
158923970741SEric Paris out_unlock:
15909287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
15911da177e4SLinus Torvalds 	return rc;
15921da177e4SLinus Torvalds }
15931da177e4SLinus Torvalds 
15941da177e4SLinus Torvalds /* Convert a Linux signal to an access vector. */
15951da177e4SLinus Torvalds static inline u32 signal_to_av(int sig)
15961da177e4SLinus Torvalds {
15971da177e4SLinus Torvalds 	u32 perm = 0;
15981da177e4SLinus Torvalds 
15991da177e4SLinus Torvalds 	switch (sig) {
16001da177e4SLinus Torvalds 	case SIGCHLD:
16011da177e4SLinus Torvalds 		/* Commonly granted from child to parent. */
16021da177e4SLinus Torvalds 		perm = PROCESS__SIGCHLD;
16031da177e4SLinus Torvalds 		break;
16041da177e4SLinus Torvalds 	case SIGKILL:
16051da177e4SLinus Torvalds 		/* Cannot be caught or ignored */
16061da177e4SLinus Torvalds 		perm = PROCESS__SIGKILL;
16071da177e4SLinus Torvalds 		break;
16081da177e4SLinus Torvalds 	case SIGSTOP:
16091da177e4SLinus Torvalds 		/* Cannot be caught or ignored */
16101da177e4SLinus Torvalds 		perm = PROCESS__SIGSTOP;
16111da177e4SLinus Torvalds 		break;
16121da177e4SLinus Torvalds 	default:
16131da177e4SLinus Torvalds 		/* All other signals. */
16141da177e4SLinus Torvalds 		perm = PROCESS__SIGNAL;
16151da177e4SLinus Torvalds 		break;
16161da177e4SLinus Torvalds 	}
16171da177e4SLinus Torvalds 
16181da177e4SLinus Torvalds 	return perm;
16191da177e4SLinus Torvalds }
16201da177e4SLinus Torvalds 
1621b68e418cSStephen Smalley #if CAP_LAST_CAP > 63
1622b68e418cSStephen Smalley #error Fix SELinux to handle capabilities > 63.
1623b68e418cSStephen Smalley #endif
1624b68e418cSStephen Smalley 
16251da177e4SLinus Torvalds /* Check whether a task is allowed to use a capability. */
16266a9de491SEric Paris static int cred_has_capability(const struct cred *cred,
1627c1a85a00SMicah Morton 			       int cap, unsigned int opts, bool initns)
16281da177e4SLinus Torvalds {
16292bf49690SThomas Liu 	struct common_audit_data ad;
163006112163SEric Paris 	struct av_decision avd;
1631b68e418cSStephen Smalley 	u16 sclass;
16323699c53cSDavid Howells 	u32 sid = cred_sid(cred);
1633b68e418cSStephen Smalley 	u32 av = CAP_TO_MASK(cap);
163406112163SEric Paris 	int rc;
16351da177e4SLinus Torvalds 
163650c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_CAP;
16371da177e4SLinus Torvalds 	ad.u.cap = cap;
16381da177e4SLinus Torvalds 
1639b68e418cSStephen Smalley 	switch (CAP_TO_INDEX(cap)) {
1640b68e418cSStephen Smalley 	case 0:
16418e4ff6f2SStephen Smalley 		sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS;
1642b68e418cSStephen Smalley 		break;
1643b68e418cSStephen Smalley 	case 1:
16448e4ff6f2SStephen Smalley 		sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS;
1645b68e418cSStephen Smalley 		break;
1646b68e418cSStephen Smalley 	default:
1647c103a91eSpeter enderborg 		pr_err("SELinux:  out of range capability %d\n", cap);
1648b68e418cSStephen Smalley 		BUG();
1649a35c6c83SEric Paris 		return -EINVAL;
1650b68e418cSStephen Smalley 	}
165106112163SEric Paris 
16526b6bc620SStephen Smalley 	rc = avc_has_perm_noaudit(&selinux_state,
16536b6bc620SStephen Smalley 				  sid, sid, sclass, av, 0, &avd);
1654c1a85a00SMicah Morton 	if (!(opts & CAP_OPT_NOAUDIT)) {
16556b6bc620SStephen Smalley 		int rc2 = avc_audit(&selinux_state,
16566b6bc620SStephen Smalley 				    sid, sid, sclass, av, &avd, rc, &ad, 0);
16579ade0cf4SEric Paris 		if (rc2)
16589ade0cf4SEric Paris 			return rc2;
16599ade0cf4SEric Paris 	}
166006112163SEric Paris 	return rc;
16611da177e4SLinus Torvalds }
16621da177e4SLinus Torvalds 
16631da177e4SLinus Torvalds /* Check whether a task has a particular permission to an inode.
16641da177e4SLinus Torvalds    The 'adp' parameter is optional and allows other audit
16651da177e4SLinus Torvalds    data to be passed (e.g. the dentry). */
166688e67f3bSDavid Howells static int inode_has_perm(const struct cred *cred,
16671da177e4SLinus Torvalds 			  struct inode *inode,
16681da177e4SLinus Torvalds 			  u32 perms,
166919e49834SLinus Torvalds 			  struct common_audit_data *adp)
16701da177e4SLinus Torvalds {
16711da177e4SLinus Torvalds 	struct inode_security_struct *isec;
1672275bb41eSDavid Howells 	u32 sid;
16731da177e4SLinus Torvalds 
1674e0e81739SDavid Howells 	validate_creds(cred);
1675e0e81739SDavid Howells 
1676bbaca6c2SStephen Smalley 	if (unlikely(IS_PRIVATE(inode)))
1677bbaca6c2SStephen Smalley 		return 0;
1678bbaca6c2SStephen Smalley 
167988e67f3bSDavid Howells 	sid = cred_sid(cred);
168080788c22SCasey Schaufler 	isec = selinux_inode(inode);
16811da177e4SLinus Torvalds 
16826b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
16836b6bc620SStephen Smalley 			    sid, isec->sid, isec->sclass, perms, adp);
16841da177e4SLinus Torvalds }
16851da177e4SLinus Torvalds 
16861da177e4SLinus Torvalds /* Same as inode_has_perm, but pass explicit audit data containing
16871da177e4SLinus Torvalds    the dentry to help the auditing code to more easily generate the
16881da177e4SLinus Torvalds    pathname if needed. */
168988e67f3bSDavid Howells static inline int dentry_has_perm(const struct cred *cred,
16901da177e4SLinus Torvalds 				  struct dentry *dentry,
16911da177e4SLinus Torvalds 				  u32 av)
16921da177e4SLinus Torvalds {
1693c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(dentry);
16942bf49690SThomas Liu 	struct common_audit_data ad;
169588e67f3bSDavid Howells 
169650c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
16972875fa00SEric Paris 	ad.u.dentry = dentry;
16985d226df4SAndreas Gruenbacher 	__inode_security_revalidate(inode, dentry, true);
169919e49834SLinus Torvalds 	return inode_has_perm(cred, inode, av, &ad);
17002875fa00SEric Paris }
17012875fa00SEric Paris 
17022875fa00SEric Paris /* Same as inode_has_perm, but pass explicit audit data containing
17032875fa00SEric Paris    the path to help the auditing code to more easily generate the
17042875fa00SEric Paris    pathname if needed. */
17052875fa00SEric Paris static inline int path_has_perm(const struct cred *cred,
17063f7036a0SAl Viro 				const struct path *path,
17072875fa00SEric Paris 				u32 av)
17082875fa00SEric Paris {
1709c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(path->dentry);
17102875fa00SEric Paris 	struct common_audit_data ad;
17112875fa00SEric Paris 
171250c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_PATH;
17132875fa00SEric Paris 	ad.u.path = *path;
17145d226df4SAndreas Gruenbacher 	__inode_security_revalidate(inode, path->dentry, true);
171519e49834SLinus Torvalds 	return inode_has_perm(cred, inode, av, &ad);
17161da177e4SLinus Torvalds }
17171da177e4SLinus Torvalds 
171813f8e981SDavid Howells /* Same as path_has_perm, but uses the inode from the file struct. */
171913f8e981SDavid Howells static inline int file_path_has_perm(const struct cred *cred,
172013f8e981SDavid Howells 				     struct file *file,
172113f8e981SDavid Howells 				     u32 av)
172213f8e981SDavid Howells {
172313f8e981SDavid Howells 	struct common_audit_data ad;
172413f8e981SDavid Howells 
172543af5de7SVivek Goyal 	ad.type = LSM_AUDIT_DATA_FILE;
172643af5de7SVivek Goyal 	ad.u.file = file;
172719e49834SLinus Torvalds 	return inode_has_perm(cred, file_inode(file), av, &ad);
172813f8e981SDavid Howells }
172913f8e981SDavid Howells 
1730f66e448cSChenbo Feng #ifdef CONFIG_BPF_SYSCALL
1731f66e448cSChenbo Feng static int bpf_fd_pass(struct file *file, u32 sid);
1732f66e448cSChenbo Feng #endif
1733f66e448cSChenbo Feng 
17341da177e4SLinus Torvalds /* Check whether a task can use an open file descriptor to
17351da177e4SLinus Torvalds    access an inode in a given way.  Check access to the
17361da177e4SLinus Torvalds    descriptor itself, and then use dentry_has_perm to
17371da177e4SLinus Torvalds    check a particular permission to the file.
17381da177e4SLinus Torvalds    Access to the descriptor is implicitly granted if it
17391da177e4SLinus Torvalds    has the same SID as the process.  If av is zero, then
17401da177e4SLinus Torvalds    access to the file is not checked, e.g. for cases
17411da177e4SLinus Torvalds    where only the descriptor is affected like seek. */
174288e67f3bSDavid Howells static int file_has_perm(const struct cred *cred,
17431da177e4SLinus Torvalds 			 struct file *file,
17441da177e4SLinus Torvalds 			 u32 av)
17451da177e4SLinus Torvalds {
1746bb6c6b02SCasey Schaufler 	struct file_security_struct *fsec = selinux_file(file);
1747496ad9aaSAl Viro 	struct inode *inode = file_inode(file);
17482bf49690SThomas Liu 	struct common_audit_data ad;
174988e67f3bSDavid Howells 	u32 sid = cred_sid(cred);
17501da177e4SLinus Torvalds 	int rc;
17511da177e4SLinus Torvalds 
175243af5de7SVivek Goyal 	ad.type = LSM_AUDIT_DATA_FILE;
175343af5de7SVivek Goyal 	ad.u.file = file;
17541da177e4SLinus Torvalds 
1755275bb41eSDavid Howells 	if (sid != fsec->sid) {
17566b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
17576b6bc620SStephen Smalley 				  sid, fsec->sid,
17581da177e4SLinus Torvalds 				  SECCLASS_FD,
17591da177e4SLinus Torvalds 				  FD__USE,
17601da177e4SLinus Torvalds 				  &ad);
17611da177e4SLinus Torvalds 		if (rc)
176288e67f3bSDavid Howells 			goto out;
17631da177e4SLinus Torvalds 	}
17641da177e4SLinus Torvalds 
1765f66e448cSChenbo Feng #ifdef CONFIG_BPF_SYSCALL
1766f66e448cSChenbo Feng 	rc = bpf_fd_pass(file, cred_sid(cred));
1767f66e448cSChenbo Feng 	if (rc)
1768f66e448cSChenbo Feng 		return rc;
1769f66e448cSChenbo Feng #endif
1770f66e448cSChenbo Feng 
17711da177e4SLinus Torvalds 	/* av is zero if only checking access to the descriptor. */
177288e67f3bSDavid Howells 	rc = 0;
17731da177e4SLinus Torvalds 	if (av)
177419e49834SLinus Torvalds 		rc = inode_has_perm(cred, inode, av, &ad);
17751da177e4SLinus Torvalds 
177688e67f3bSDavid Howells out:
177788e67f3bSDavid Howells 	return rc;
17781da177e4SLinus Torvalds }
17791da177e4SLinus Torvalds 
1780c3c188b2SDavid Howells /*
1781c3c188b2SDavid Howells  * Determine the label for an inode that might be unioned.
1782c3c188b2SDavid Howells  */
1783c957f6dfSVivek Goyal static int
1784c957f6dfSVivek Goyal selinux_determine_inode_label(const struct task_security_struct *tsec,
1785c957f6dfSVivek Goyal 				 struct inode *dir,
1786c957f6dfSVivek Goyal 				 const struct qstr *name, u16 tclass,
1787c3c188b2SDavid Howells 				 u32 *_new_isid)
1788c3c188b2SDavid Howells {
1789c3c188b2SDavid Howells 	const struct superblock_security_struct *sbsec = dir->i_sb->s_security;
1790c3c188b2SDavid Howells 
1791c3c188b2SDavid Howells 	if ((sbsec->flags & SE_SBINITIALIZED) &&
1792c3c188b2SDavid Howells 	    (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) {
1793c3c188b2SDavid Howells 		*_new_isid = sbsec->mntpoint_sid;
1794c3c188b2SDavid Howells 	} else if ((sbsec->flags & SBLABEL_MNT) &&
1795c3c188b2SDavid Howells 		   tsec->create_sid) {
1796c3c188b2SDavid Howells 		*_new_isid = tsec->create_sid;
1797c3c188b2SDavid Howells 	} else {
179820cdef8dSPaul Moore 		const struct inode_security_struct *dsec = inode_security(dir);
1799aa8e712cSStephen Smalley 		return security_transition_sid(&selinux_state, tsec->sid,
1800aa8e712cSStephen Smalley 					       dsec->sid, tclass,
1801c3c188b2SDavid Howells 					       name, _new_isid);
1802c3c188b2SDavid Howells 	}
1803c3c188b2SDavid Howells 
1804c3c188b2SDavid Howells 	return 0;
1805c3c188b2SDavid Howells }
1806c3c188b2SDavid Howells 
18071da177e4SLinus Torvalds /* Check whether a task can create a file. */
18081da177e4SLinus Torvalds static int may_create(struct inode *dir,
18091da177e4SLinus Torvalds 		      struct dentry *dentry,
18101da177e4SLinus Torvalds 		      u16 tclass)
18111da177e4SLinus Torvalds {
18120c6cfa62SCasey Schaufler 	const struct task_security_struct *tsec = selinux_cred(current_cred());
18131da177e4SLinus Torvalds 	struct inode_security_struct *dsec;
18141da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec;
1815275bb41eSDavid Howells 	u32 sid, newsid;
18162bf49690SThomas Liu 	struct common_audit_data ad;
18171da177e4SLinus Torvalds 	int rc;
18181da177e4SLinus Torvalds 
181983da53c5SAndreas Gruenbacher 	dsec = inode_security(dir);
18201da177e4SLinus Torvalds 	sbsec = dir->i_sb->s_security;
18211da177e4SLinus Torvalds 
1822275bb41eSDavid Howells 	sid = tsec->sid;
1823275bb41eSDavid Howells 
182450c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
1825a269434dSEric Paris 	ad.u.dentry = dentry;
18261da177e4SLinus Torvalds 
18276b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
18286b6bc620SStephen Smalley 			  sid, dsec->sid, SECCLASS_DIR,
18291da177e4SLinus Torvalds 			  DIR__ADD_NAME | DIR__SEARCH,
18301da177e4SLinus Torvalds 			  &ad);
18311da177e4SLinus Torvalds 	if (rc)
18321da177e4SLinus Torvalds 		return rc;
18331da177e4SLinus Torvalds 
18340c6cfa62SCasey Schaufler 	rc = selinux_determine_inode_label(selinux_cred(current_cred()), dir,
1835c957f6dfSVivek Goyal 					   &dentry->d_name, tclass, &newsid);
18361da177e4SLinus Torvalds 	if (rc)
18371da177e4SLinus Torvalds 		return rc;
18381da177e4SLinus Torvalds 
18396b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
18406b6bc620SStephen Smalley 			  sid, newsid, tclass, FILE__CREATE, &ad);
18411da177e4SLinus Torvalds 	if (rc)
18421da177e4SLinus Torvalds 		return rc;
18431da177e4SLinus Torvalds 
18446b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
18456b6bc620SStephen Smalley 			    newsid, sbsec->sid,
18461da177e4SLinus Torvalds 			    SECCLASS_FILESYSTEM,
18471da177e4SLinus Torvalds 			    FILESYSTEM__ASSOCIATE, &ad);
18481da177e4SLinus Torvalds }
18491da177e4SLinus Torvalds 
18501da177e4SLinus Torvalds #define MAY_LINK	0
18511da177e4SLinus Torvalds #define MAY_UNLINK	1
18521da177e4SLinus Torvalds #define MAY_RMDIR	2
18531da177e4SLinus Torvalds 
18541da177e4SLinus Torvalds /* Check whether a task can link, unlink, or rmdir a file/directory. */
18551da177e4SLinus Torvalds static int may_link(struct inode *dir,
18561da177e4SLinus Torvalds 		    struct dentry *dentry,
18571da177e4SLinus Torvalds 		    int kind)
18581da177e4SLinus Torvalds 
18591da177e4SLinus Torvalds {
18601da177e4SLinus Torvalds 	struct inode_security_struct *dsec, *isec;
18612bf49690SThomas Liu 	struct common_audit_data ad;
1862275bb41eSDavid Howells 	u32 sid = current_sid();
18631da177e4SLinus Torvalds 	u32 av;
18641da177e4SLinus Torvalds 	int rc;
18651da177e4SLinus Torvalds 
186683da53c5SAndreas Gruenbacher 	dsec = inode_security(dir);
186783da53c5SAndreas Gruenbacher 	isec = backing_inode_security(dentry);
18681da177e4SLinus Torvalds 
186950c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
1870a269434dSEric Paris 	ad.u.dentry = dentry;
18711da177e4SLinus Torvalds 
18721da177e4SLinus Torvalds 	av = DIR__SEARCH;
18731da177e4SLinus Torvalds 	av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
18746b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
18756b6bc620SStephen Smalley 			  sid, dsec->sid, SECCLASS_DIR, av, &ad);
18761da177e4SLinus Torvalds 	if (rc)
18771da177e4SLinus Torvalds 		return rc;
18781da177e4SLinus Torvalds 
18791da177e4SLinus Torvalds 	switch (kind) {
18801da177e4SLinus Torvalds 	case MAY_LINK:
18811da177e4SLinus Torvalds 		av = FILE__LINK;
18821da177e4SLinus Torvalds 		break;
18831da177e4SLinus Torvalds 	case MAY_UNLINK:
18841da177e4SLinus Torvalds 		av = FILE__UNLINK;
18851da177e4SLinus Torvalds 		break;
18861da177e4SLinus Torvalds 	case MAY_RMDIR:
18871da177e4SLinus Torvalds 		av = DIR__RMDIR;
18881da177e4SLinus Torvalds 		break;
18891da177e4SLinus Torvalds 	default:
1890c103a91eSpeter enderborg 		pr_warn("SELinux: %s:  unrecognized kind %d\n",
1891744ba35eSEric Paris 			__func__, kind);
18921da177e4SLinus Torvalds 		return 0;
18931da177e4SLinus Torvalds 	}
18941da177e4SLinus Torvalds 
18956b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
18966b6bc620SStephen Smalley 			  sid, isec->sid, isec->sclass, av, &ad);
18971da177e4SLinus Torvalds 	return rc;
18981da177e4SLinus Torvalds }
18991da177e4SLinus Torvalds 
19001da177e4SLinus Torvalds static inline int may_rename(struct inode *old_dir,
19011da177e4SLinus Torvalds 			     struct dentry *old_dentry,
19021da177e4SLinus Torvalds 			     struct inode *new_dir,
19031da177e4SLinus Torvalds 			     struct dentry *new_dentry)
19041da177e4SLinus Torvalds {
19051da177e4SLinus Torvalds 	struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
19062bf49690SThomas Liu 	struct common_audit_data ad;
1907275bb41eSDavid Howells 	u32 sid = current_sid();
19081da177e4SLinus Torvalds 	u32 av;
19091da177e4SLinus Torvalds 	int old_is_dir, new_is_dir;
19101da177e4SLinus Torvalds 	int rc;
19111da177e4SLinus Torvalds 
191283da53c5SAndreas Gruenbacher 	old_dsec = inode_security(old_dir);
191383da53c5SAndreas Gruenbacher 	old_isec = backing_inode_security(old_dentry);
1914e36cb0b8SDavid Howells 	old_is_dir = d_is_dir(old_dentry);
191583da53c5SAndreas Gruenbacher 	new_dsec = inode_security(new_dir);
19161da177e4SLinus Torvalds 
191750c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
19181da177e4SLinus Torvalds 
1919a269434dSEric Paris 	ad.u.dentry = old_dentry;
19206b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
19216b6bc620SStephen Smalley 			  sid, old_dsec->sid, SECCLASS_DIR,
19221da177e4SLinus Torvalds 			  DIR__REMOVE_NAME | DIR__SEARCH, &ad);
19231da177e4SLinus Torvalds 	if (rc)
19241da177e4SLinus Torvalds 		return rc;
19256b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
19266b6bc620SStephen Smalley 			  sid, old_isec->sid,
19271da177e4SLinus Torvalds 			  old_isec->sclass, FILE__RENAME, &ad);
19281da177e4SLinus Torvalds 	if (rc)
19291da177e4SLinus Torvalds 		return rc;
19301da177e4SLinus Torvalds 	if (old_is_dir && new_dir != old_dir) {
19316b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
19326b6bc620SStephen Smalley 				  sid, old_isec->sid,
19331da177e4SLinus Torvalds 				  old_isec->sclass, DIR__REPARENT, &ad);
19341da177e4SLinus Torvalds 		if (rc)
19351da177e4SLinus Torvalds 			return rc;
19361da177e4SLinus Torvalds 	}
19371da177e4SLinus Torvalds 
1938a269434dSEric Paris 	ad.u.dentry = new_dentry;
19391da177e4SLinus Torvalds 	av = DIR__ADD_NAME | DIR__SEARCH;
19402c616d4dSDavid Howells 	if (d_is_positive(new_dentry))
19411da177e4SLinus Torvalds 		av |= DIR__REMOVE_NAME;
19426b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
19436b6bc620SStephen Smalley 			  sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
19441da177e4SLinus Torvalds 	if (rc)
19451da177e4SLinus Torvalds 		return rc;
19462c616d4dSDavid Howells 	if (d_is_positive(new_dentry)) {
194783da53c5SAndreas Gruenbacher 		new_isec = backing_inode_security(new_dentry);
1948e36cb0b8SDavid Howells 		new_is_dir = d_is_dir(new_dentry);
19496b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
19506b6bc620SStephen Smalley 				  sid, new_isec->sid,
19511da177e4SLinus Torvalds 				  new_isec->sclass,
19521da177e4SLinus Torvalds 				  (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
19531da177e4SLinus Torvalds 		if (rc)
19541da177e4SLinus Torvalds 			return rc;
19551da177e4SLinus Torvalds 	}
19561da177e4SLinus Torvalds 
19571da177e4SLinus Torvalds 	return 0;
19581da177e4SLinus Torvalds }
19591da177e4SLinus Torvalds 
19601da177e4SLinus Torvalds /* Check whether a task can perform a filesystem operation. */
196188e67f3bSDavid Howells static int superblock_has_perm(const struct cred *cred,
19621da177e4SLinus Torvalds 			       struct super_block *sb,
19631da177e4SLinus Torvalds 			       u32 perms,
19642bf49690SThomas Liu 			       struct common_audit_data *ad)
19651da177e4SLinus Torvalds {
19661da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec;
196788e67f3bSDavid Howells 	u32 sid = cred_sid(cred);
19681da177e4SLinus Torvalds 
19691da177e4SLinus Torvalds 	sbsec = sb->s_security;
19706b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
19716b6bc620SStephen Smalley 			    sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
19721da177e4SLinus Torvalds }
19731da177e4SLinus Torvalds 
19741da177e4SLinus Torvalds /* Convert a Linux mode and permission mask to an access vector. */
19751da177e4SLinus Torvalds static inline u32 file_mask_to_av(int mode, int mask)
19761da177e4SLinus Torvalds {
19771da177e4SLinus Torvalds 	u32 av = 0;
19781da177e4SLinus Torvalds 
1979dba19c60SAl Viro 	if (!S_ISDIR(mode)) {
19801da177e4SLinus Torvalds 		if (mask & MAY_EXEC)
19811da177e4SLinus Torvalds 			av |= FILE__EXECUTE;
19821da177e4SLinus Torvalds 		if (mask & MAY_READ)
19831da177e4SLinus Torvalds 			av |= FILE__READ;
19841da177e4SLinus Torvalds 
19851da177e4SLinus Torvalds 		if (mask & MAY_APPEND)
19861da177e4SLinus Torvalds 			av |= FILE__APPEND;
19871da177e4SLinus Torvalds 		else if (mask & MAY_WRITE)
19881da177e4SLinus Torvalds 			av |= FILE__WRITE;
19891da177e4SLinus Torvalds 
19901da177e4SLinus Torvalds 	} else {
19911da177e4SLinus Torvalds 		if (mask & MAY_EXEC)
19921da177e4SLinus Torvalds 			av |= DIR__SEARCH;
19931da177e4SLinus Torvalds 		if (mask & MAY_WRITE)
19941da177e4SLinus Torvalds 			av |= DIR__WRITE;
19951da177e4SLinus Torvalds 		if (mask & MAY_READ)
19961da177e4SLinus Torvalds 			av |= DIR__READ;
19971da177e4SLinus Torvalds 	}
19981da177e4SLinus Torvalds 
19991da177e4SLinus Torvalds 	return av;
20001da177e4SLinus Torvalds }
20011da177e4SLinus Torvalds 
20021da177e4SLinus Torvalds /* Convert a Linux file to an access vector. */
20031da177e4SLinus Torvalds static inline u32 file_to_av(struct file *file)
20041da177e4SLinus Torvalds {
20051da177e4SLinus Torvalds 	u32 av = 0;
20061da177e4SLinus Torvalds 
20071da177e4SLinus Torvalds 	if (file->f_mode & FMODE_READ)
20081da177e4SLinus Torvalds 		av |= FILE__READ;
20091da177e4SLinus Torvalds 	if (file->f_mode & FMODE_WRITE) {
20101da177e4SLinus Torvalds 		if (file->f_flags & O_APPEND)
20111da177e4SLinus Torvalds 			av |= FILE__APPEND;
20121da177e4SLinus Torvalds 		else
20131da177e4SLinus Torvalds 			av |= FILE__WRITE;
20141da177e4SLinus Torvalds 	}
20150794c66dSStephen Smalley 	if (!av) {
20160794c66dSStephen Smalley 		/*
20170794c66dSStephen Smalley 		 * Special file opened with flags 3 for ioctl-only use.
20180794c66dSStephen Smalley 		 */
20190794c66dSStephen Smalley 		av = FILE__IOCTL;
20200794c66dSStephen Smalley 	}
20211da177e4SLinus Torvalds 
20221da177e4SLinus Torvalds 	return av;
20231da177e4SLinus Torvalds }
20241da177e4SLinus Torvalds 
20258b6a5a37SEric Paris /*
20268b6a5a37SEric Paris  * Convert a file to an access vector and include the correct open
20278b6a5a37SEric Paris  * open permission.
20288b6a5a37SEric Paris  */
20298b6a5a37SEric Paris static inline u32 open_file_to_av(struct file *file)
20308b6a5a37SEric Paris {
20318b6a5a37SEric Paris 	u32 av = file_to_av(file);
2032ccb54478SStephen Smalley 	struct inode *inode = file_inode(file);
20338b6a5a37SEric Paris 
2034aa8e712cSStephen Smalley 	if (selinux_policycap_openperm() &&
2035aa8e712cSStephen Smalley 	    inode->i_sb->s_magic != SOCKFS_MAGIC)
20368b6a5a37SEric Paris 		av |= FILE__OPEN;
203749b7b8deSEric Paris 
20388b6a5a37SEric Paris 	return av;
20398b6a5a37SEric Paris }
20408b6a5a37SEric Paris 
20411da177e4SLinus Torvalds /* Hook functions begin here. */
20421da177e4SLinus Torvalds 
204379af7307SStephen Smalley static int selinux_binder_set_context_mgr(struct task_struct *mgr)
204479af7307SStephen Smalley {
204579af7307SStephen Smalley 	u32 mysid = current_sid();
204679af7307SStephen Smalley 	u32 mgrsid = task_sid(mgr);
204779af7307SStephen Smalley 
20486b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
20496b6bc620SStephen Smalley 			    mysid, mgrsid, SECCLASS_BINDER,
205079af7307SStephen Smalley 			    BINDER__SET_CONTEXT_MGR, NULL);
205179af7307SStephen Smalley }
205279af7307SStephen Smalley 
205379af7307SStephen Smalley static int selinux_binder_transaction(struct task_struct *from,
205479af7307SStephen Smalley 				      struct task_struct *to)
205579af7307SStephen Smalley {
205679af7307SStephen Smalley 	u32 mysid = current_sid();
205779af7307SStephen Smalley 	u32 fromsid = task_sid(from);
205879af7307SStephen Smalley 	u32 tosid = task_sid(to);
205979af7307SStephen Smalley 	int rc;
206079af7307SStephen Smalley 
206179af7307SStephen Smalley 	if (mysid != fromsid) {
20626b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
20636b6bc620SStephen Smalley 				  mysid, fromsid, SECCLASS_BINDER,
206479af7307SStephen Smalley 				  BINDER__IMPERSONATE, NULL);
206579af7307SStephen Smalley 		if (rc)
206679af7307SStephen Smalley 			return rc;
206779af7307SStephen Smalley 	}
206879af7307SStephen Smalley 
20696b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
20706b6bc620SStephen Smalley 			    fromsid, tosid, SECCLASS_BINDER, BINDER__CALL,
207179af7307SStephen Smalley 			    NULL);
207279af7307SStephen Smalley }
207379af7307SStephen Smalley 
207479af7307SStephen Smalley static int selinux_binder_transfer_binder(struct task_struct *from,
207579af7307SStephen Smalley 					  struct task_struct *to)
207679af7307SStephen Smalley {
207779af7307SStephen Smalley 	u32 fromsid = task_sid(from);
207879af7307SStephen Smalley 	u32 tosid = task_sid(to);
207979af7307SStephen Smalley 
20806b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
20816b6bc620SStephen Smalley 			    fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER,
208279af7307SStephen Smalley 			    NULL);
208379af7307SStephen Smalley }
208479af7307SStephen Smalley 
208579af7307SStephen Smalley static int selinux_binder_transfer_file(struct task_struct *from,
208679af7307SStephen Smalley 					struct task_struct *to,
208779af7307SStephen Smalley 					struct file *file)
208879af7307SStephen Smalley {
208979af7307SStephen Smalley 	u32 sid = task_sid(to);
2090bb6c6b02SCasey Schaufler 	struct file_security_struct *fsec = selinux_file(file);
209183da53c5SAndreas Gruenbacher 	struct dentry *dentry = file->f_path.dentry;
209220cdef8dSPaul Moore 	struct inode_security_struct *isec;
209379af7307SStephen Smalley 	struct common_audit_data ad;
209479af7307SStephen Smalley 	int rc;
209579af7307SStephen Smalley 
209679af7307SStephen Smalley 	ad.type = LSM_AUDIT_DATA_PATH;
209779af7307SStephen Smalley 	ad.u.path = file->f_path;
209879af7307SStephen Smalley 
209979af7307SStephen Smalley 	if (sid != fsec->sid) {
21006b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
21016b6bc620SStephen Smalley 				  sid, fsec->sid,
210279af7307SStephen Smalley 				  SECCLASS_FD,
210379af7307SStephen Smalley 				  FD__USE,
210479af7307SStephen Smalley 				  &ad);
210579af7307SStephen Smalley 		if (rc)
210679af7307SStephen Smalley 			return rc;
210779af7307SStephen Smalley 	}
210879af7307SStephen Smalley 
2109f66e448cSChenbo Feng #ifdef CONFIG_BPF_SYSCALL
2110f66e448cSChenbo Feng 	rc = bpf_fd_pass(file, sid);
2111f66e448cSChenbo Feng 	if (rc)
2112f66e448cSChenbo Feng 		return rc;
2113f66e448cSChenbo Feng #endif
2114f66e448cSChenbo Feng 
211583da53c5SAndreas Gruenbacher 	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
211679af7307SStephen Smalley 		return 0;
211779af7307SStephen Smalley 
211820cdef8dSPaul Moore 	isec = backing_inode_security(dentry);
21196b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
21206b6bc620SStephen Smalley 			    sid, isec->sid, isec->sclass, file_to_av(file),
212179af7307SStephen Smalley 			    &ad);
212279af7307SStephen Smalley }
212379af7307SStephen Smalley 
21249e48858fSIngo Molnar static int selinux_ptrace_access_check(struct task_struct *child,
2125006ebb40SStephen Smalley 				     unsigned int mode)
21261da177e4SLinus Torvalds {
2127275bb41eSDavid Howells 	u32 sid = current_sid();
2128275bb41eSDavid Howells 	u32 csid = task_sid(child);
2129006ebb40SStephen Smalley 
2130be0554c9SStephen Smalley 	if (mode & PTRACE_MODE_READ)
21316b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
21326b6bc620SStephen Smalley 				    sid, csid, SECCLASS_FILE, FILE__READ, NULL);
2133be0554c9SStephen Smalley 
21346b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
21356b6bc620SStephen Smalley 			    sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
21365cd9c58fSDavid Howells }
21375cd9c58fSDavid Howells 
21385cd9c58fSDavid Howells static int selinux_ptrace_traceme(struct task_struct *parent)
21395cd9c58fSDavid Howells {
21406b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
21416b6bc620SStephen Smalley 			    task_sid(parent), current_sid(), SECCLASS_PROCESS,
2142be0554c9SStephen Smalley 			    PROCESS__PTRACE, NULL);
21431da177e4SLinus Torvalds }
21441da177e4SLinus Torvalds 
21451da177e4SLinus Torvalds static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
21461da177e4SLinus Torvalds 			  kernel_cap_t *inheritable, kernel_cap_t *permitted)
21471da177e4SLinus Torvalds {
21486b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
21496b6bc620SStephen Smalley 			    current_sid(), task_sid(target), SECCLASS_PROCESS,
2150be0554c9SStephen Smalley 			    PROCESS__GETCAP, NULL);
21511da177e4SLinus Torvalds }
21521da177e4SLinus Torvalds 
2153d84f4f99SDavid Howells static int selinux_capset(struct cred *new, const struct cred *old,
2154d84f4f99SDavid Howells 			  const kernel_cap_t *effective,
215515a2460eSDavid Howells 			  const kernel_cap_t *inheritable,
215615a2460eSDavid Howells 			  const kernel_cap_t *permitted)
21571da177e4SLinus Torvalds {
21586b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
21596b6bc620SStephen Smalley 			    cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
2160be0554c9SStephen Smalley 			    PROCESS__SETCAP, NULL);
21611da177e4SLinus Torvalds }
21621da177e4SLinus Torvalds 
21635626d3e8SJames Morris /*
21645626d3e8SJames Morris  * (This comment used to live with the selinux_task_setuid hook,
21655626d3e8SJames Morris  * which was removed).
21665626d3e8SJames Morris  *
21675626d3e8SJames Morris  * Since setuid only affects the current process, and since the SELinux
21685626d3e8SJames Morris  * controls are not based on the Linux identity attributes, SELinux does not
21695626d3e8SJames Morris  * need to control this operation.  However, SELinux does control the use of
21705626d3e8SJames Morris  * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
21715626d3e8SJames Morris  */
21725626d3e8SJames Morris 
21736a9de491SEric Paris static int selinux_capable(const struct cred *cred, struct user_namespace *ns,
2174c1a85a00SMicah Morton 			   int cap, unsigned int opts)
21751da177e4SLinus Torvalds {
2176c1a85a00SMicah Morton 	return cred_has_capability(cred, cap, opts, ns == &init_user_ns);
21771da177e4SLinus Torvalds }
21781da177e4SLinus Torvalds 
21791da177e4SLinus Torvalds static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
21801da177e4SLinus Torvalds {
218188e67f3bSDavid Howells 	const struct cred *cred = current_cred();
21821da177e4SLinus Torvalds 	int rc = 0;
21831da177e4SLinus Torvalds 
21841da177e4SLinus Torvalds 	if (!sb)
21851da177e4SLinus Torvalds 		return 0;
21861da177e4SLinus Torvalds 
21871da177e4SLinus Torvalds 	switch (cmds) {
21881da177e4SLinus Torvalds 	case Q_SYNC:
21891da177e4SLinus Torvalds 	case Q_QUOTAON:
21901da177e4SLinus Torvalds 	case Q_QUOTAOFF:
21911da177e4SLinus Torvalds 	case Q_SETINFO:
21921da177e4SLinus Torvalds 	case Q_SETQUOTA:
219388e67f3bSDavid Howells 		rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
21941da177e4SLinus Torvalds 		break;
21951da177e4SLinus Torvalds 	case Q_GETFMT:
21961da177e4SLinus Torvalds 	case Q_GETINFO:
21971da177e4SLinus Torvalds 	case Q_GETQUOTA:
219888e67f3bSDavid Howells 		rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
21991da177e4SLinus Torvalds 		break;
22001da177e4SLinus Torvalds 	default:
22011da177e4SLinus Torvalds 		rc = 0;  /* let the kernel handle invalid cmds */
22021da177e4SLinus Torvalds 		break;
22031da177e4SLinus Torvalds 	}
22041da177e4SLinus Torvalds 	return rc;
22051da177e4SLinus Torvalds }
22061da177e4SLinus Torvalds 
22071da177e4SLinus Torvalds static int selinux_quota_on(struct dentry *dentry)
22081da177e4SLinus Torvalds {
220988e67f3bSDavid Howells 	const struct cred *cred = current_cred();
221088e67f3bSDavid Howells 
22112875fa00SEric Paris 	return dentry_has_perm(cred, dentry, FILE__QUOTAON);
22121da177e4SLinus Torvalds }
22131da177e4SLinus Torvalds 
221412b3052cSEric Paris static int selinux_syslog(int type)
22151da177e4SLinus Torvalds {
22161da177e4SLinus Torvalds 	switch (type) {
2217d78ca3cdSKees Cook 	case SYSLOG_ACTION_READ_ALL:	/* Read last kernel messages */
2218d78ca3cdSKees Cook 	case SYSLOG_ACTION_SIZE_BUFFER:	/* Return size of the log buffer */
22196b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
22206b6bc620SStephen Smalley 				    current_sid(), SECINITSID_KERNEL,
2221be0554c9SStephen Smalley 				    SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL);
2222d78ca3cdSKees Cook 	case SYSLOG_ACTION_CONSOLE_OFF:	/* Disable logging to console */
2223d78ca3cdSKees Cook 	case SYSLOG_ACTION_CONSOLE_ON:	/* Enable logging to console */
2224d78ca3cdSKees Cook 	/* Set level of messages printed to console */
2225d78ca3cdSKees Cook 	case SYSLOG_ACTION_CONSOLE_LEVEL:
22266b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
22276b6bc620SStephen Smalley 				    current_sid(), SECINITSID_KERNEL,
2228be0554c9SStephen Smalley 				    SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
2229be0554c9SStephen Smalley 				    NULL);
22301da177e4SLinus Torvalds 	}
2231be0554c9SStephen Smalley 	/* All other syslog types */
22326b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
22336b6bc620SStephen Smalley 			    current_sid(), SECINITSID_KERNEL,
2234be0554c9SStephen Smalley 			    SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
22351da177e4SLinus Torvalds }
22361da177e4SLinus Torvalds 
22371da177e4SLinus Torvalds /*
22381da177e4SLinus Torvalds  * Check that a process has enough memory to allocate a new virtual
22391da177e4SLinus Torvalds  * mapping. 0 means there is enough memory for the allocation to
22401da177e4SLinus Torvalds  * succeed and -ENOMEM implies there is not.
22411da177e4SLinus Torvalds  *
22421da177e4SLinus Torvalds  * Do not audit the selinux permission check, as this is applied to all
22431da177e4SLinus Torvalds  * processes that allocate mappings.
22441da177e4SLinus Torvalds  */
224534b4e4aaSAlan Cox static int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
22461da177e4SLinus Torvalds {
22471da177e4SLinus Torvalds 	int rc, cap_sys_admin = 0;
22481da177e4SLinus Torvalds 
2249b1d9e6b0SCasey Schaufler 	rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
2250c1a85a00SMicah Morton 				 CAP_OPT_NOAUDIT, true);
22511da177e4SLinus Torvalds 	if (rc == 0)
22521da177e4SLinus Torvalds 		cap_sys_admin = 1;
22531da177e4SLinus Torvalds 
2254b1d9e6b0SCasey Schaufler 	return cap_sys_admin;
22551da177e4SLinus Torvalds }
22561da177e4SLinus Torvalds 
22571da177e4SLinus Torvalds /* binprm security operations */
22581da177e4SLinus Torvalds 
2259be0554c9SStephen Smalley static u32 ptrace_parent_sid(void)
22600c6181cbSPaul Moore {
22610c6181cbSPaul Moore 	u32 sid = 0;
22620c6181cbSPaul Moore 	struct task_struct *tracer;
22630c6181cbSPaul Moore 
22640c6181cbSPaul Moore 	rcu_read_lock();
2265be0554c9SStephen Smalley 	tracer = ptrace_parent(current);
22660c6181cbSPaul Moore 	if (tracer)
22670c6181cbSPaul Moore 		sid = task_sid(tracer);
22680c6181cbSPaul Moore 	rcu_read_unlock();
22690c6181cbSPaul Moore 
22700c6181cbSPaul Moore 	return sid;
22710c6181cbSPaul Moore }
22720c6181cbSPaul Moore 
22737b0d0b40SStephen Smalley static int check_nnp_nosuid(const struct linux_binprm *bprm,
22747b0d0b40SStephen Smalley 			    const struct task_security_struct *old_tsec,
22757b0d0b40SStephen Smalley 			    const struct task_security_struct *new_tsec)
22767b0d0b40SStephen Smalley {
22777b0d0b40SStephen Smalley 	int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
2278380cf5baSAndy Lutomirski 	int nosuid = !mnt_may_suid(bprm->file->f_path.mnt);
22797b0d0b40SStephen Smalley 	int rc;
2280af63f419SStephen Smalley 	u32 av;
22817b0d0b40SStephen Smalley 
22827b0d0b40SStephen Smalley 	if (!nnp && !nosuid)
22837b0d0b40SStephen Smalley 		return 0; /* neither NNP nor nosuid */
22847b0d0b40SStephen Smalley 
22857b0d0b40SStephen Smalley 	if (new_tsec->sid == old_tsec->sid)
22867b0d0b40SStephen Smalley 		return 0; /* No change in credentials */
22877b0d0b40SStephen Smalley 
22887b0d0b40SStephen Smalley 	/*
2289af63f419SStephen Smalley 	 * If the policy enables the nnp_nosuid_transition policy capability,
2290af63f419SStephen Smalley 	 * then we permit transitions under NNP or nosuid if the
2291af63f419SStephen Smalley 	 * policy allows the corresponding permission between
2292af63f419SStephen Smalley 	 * the old and new contexts.
2293af63f419SStephen Smalley 	 */
2294aa8e712cSStephen Smalley 	if (selinux_policycap_nnp_nosuid_transition()) {
2295af63f419SStephen Smalley 		av = 0;
2296af63f419SStephen Smalley 		if (nnp)
2297af63f419SStephen Smalley 			av |= PROCESS2__NNP_TRANSITION;
2298af63f419SStephen Smalley 		if (nosuid)
2299af63f419SStephen Smalley 			av |= PROCESS2__NOSUID_TRANSITION;
23006b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
23016b6bc620SStephen Smalley 				  old_tsec->sid, new_tsec->sid,
2302af63f419SStephen Smalley 				  SECCLASS_PROCESS2, av, NULL);
2303af63f419SStephen Smalley 		if (!rc)
2304af63f419SStephen Smalley 			return 0;
2305af63f419SStephen Smalley 	}
2306af63f419SStephen Smalley 
2307af63f419SStephen Smalley 	/*
2308af63f419SStephen Smalley 	 * We also permit NNP or nosuid transitions to bounded SIDs,
2309af63f419SStephen Smalley 	 * i.e. SIDs that are guaranteed to only be allowed a subset
2310af63f419SStephen Smalley 	 * of the permissions of the current SID.
23117b0d0b40SStephen Smalley 	 */
2312aa8e712cSStephen Smalley 	rc = security_bounded_transition(&selinux_state, old_tsec->sid,
2313aa8e712cSStephen Smalley 					 new_tsec->sid);
2314af63f419SStephen Smalley 	if (!rc)
2315af63f419SStephen Smalley 		return 0;
2316af63f419SStephen Smalley 
23177b0d0b40SStephen Smalley 	/*
23187b0d0b40SStephen Smalley 	 * On failure, preserve the errno values for NNP vs nosuid.
23197b0d0b40SStephen Smalley 	 * NNP:  Operation not permitted for caller.
23207b0d0b40SStephen Smalley 	 * nosuid:  Permission denied to file.
23217b0d0b40SStephen Smalley 	 */
23227b0d0b40SStephen Smalley 	if (nnp)
23237b0d0b40SStephen Smalley 		return -EPERM;
23247b0d0b40SStephen Smalley 	return -EACCES;
23257b0d0b40SStephen Smalley }
23267b0d0b40SStephen Smalley 
2327a6f76f23SDavid Howells static int selinux_bprm_set_creds(struct linux_binprm *bprm)
23281da177e4SLinus Torvalds {
2329a6f76f23SDavid Howells 	const struct task_security_struct *old_tsec;
2330a6f76f23SDavid Howells 	struct task_security_struct *new_tsec;
23311da177e4SLinus Torvalds 	struct inode_security_struct *isec;
23322bf49690SThomas Liu 	struct common_audit_data ad;
2333496ad9aaSAl Viro 	struct inode *inode = file_inode(bprm->file);
23341da177e4SLinus Torvalds 	int rc;
23351da177e4SLinus Torvalds 
2336a6f76f23SDavid Howells 	/* SELinux context only depends on initial program or script and not
2337a6f76f23SDavid Howells 	 * the script interpreter */
2338ddb4a144SKees Cook 	if (bprm->called_set_creds)
23391da177e4SLinus Torvalds 		return 0;
23401da177e4SLinus Torvalds 
23410c6cfa62SCasey Schaufler 	old_tsec = selinux_cred(current_cred());
23420c6cfa62SCasey Schaufler 	new_tsec = selinux_cred(bprm->cred);
234383da53c5SAndreas Gruenbacher 	isec = inode_security(inode);
23441da177e4SLinus Torvalds 
23451da177e4SLinus Torvalds 	/* Default to the current task SID. */
2346a6f76f23SDavid Howells 	new_tsec->sid = old_tsec->sid;
2347a6f76f23SDavid Howells 	new_tsec->osid = old_tsec->sid;
23481da177e4SLinus Torvalds 
234928eba5bfSMichael LeMay 	/* Reset fs, key, and sock SIDs on execve. */
2350a6f76f23SDavid Howells 	new_tsec->create_sid = 0;
2351a6f76f23SDavid Howells 	new_tsec->keycreate_sid = 0;
2352a6f76f23SDavid Howells 	new_tsec->sockcreate_sid = 0;
23531da177e4SLinus Torvalds 
2354a6f76f23SDavid Howells 	if (old_tsec->exec_sid) {
2355a6f76f23SDavid Howells 		new_tsec->sid = old_tsec->exec_sid;
23561da177e4SLinus Torvalds 		/* Reset exec SID on execve. */
2357a6f76f23SDavid Howells 		new_tsec->exec_sid = 0;
2358259e5e6cSAndy Lutomirski 
23597b0d0b40SStephen Smalley 		/* Fail on NNP or nosuid if not an allowed transition. */
23607b0d0b40SStephen Smalley 		rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
23617b0d0b40SStephen Smalley 		if (rc)
23627b0d0b40SStephen Smalley 			return rc;
23631da177e4SLinus Torvalds 	} else {
23641da177e4SLinus Torvalds 		/* Check for a default transition on this program. */
2365aa8e712cSStephen Smalley 		rc = security_transition_sid(&selinux_state, old_tsec->sid,
2366aa8e712cSStephen Smalley 					     isec->sid, SECCLASS_PROCESS, NULL,
2367652bb9b0SEric Paris 					     &new_tsec->sid);
23681da177e4SLinus Torvalds 		if (rc)
23691da177e4SLinus Torvalds 			return rc;
23707b0d0b40SStephen Smalley 
23717b0d0b40SStephen Smalley 		/*
23727b0d0b40SStephen Smalley 		 * Fallback to old SID on NNP or nosuid if not an allowed
23737b0d0b40SStephen Smalley 		 * transition.
23747b0d0b40SStephen Smalley 		 */
23757b0d0b40SStephen Smalley 		rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
23767b0d0b40SStephen Smalley 		if (rc)
23777b0d0b40SStephen Smalley 			new_tsec->sid = old_tsec->sid;
23781da177e4SLinus Torvalds 	}
23791da177e4SLinus Torvalds 
238043af5de7SVivek Goyal 	ad.type = LSM_AUDIT_DATA_FILE;
238143af5de7SVivek Goyal 	ad.u.file = bprm->file;
23821da177e4SLinus Torvalds 
2383a6f76f23SDavid Howells 	if (new_tsec->sid == old_tsec->sid) {
23846b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
23856b6bc620SStephen Smalley 				  old_tsec->sid, isec->sid,
23861da177e4SLinus Torvalds 				  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
23871da177e4SLinus Torvalds 		if (rc)
23881da177e4SLinus Torvalds 			return rc;
23891da177e4SLinus Torvalds 	} else {
23901da177e4SLinus Torvalds 		/* Check permissions for the transition. */
23916b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
23926b6bc620SStephen Smalley 				  old_tsec->sid, new_tsec->sid,
23931da177e4SLinus Torvalds 				  SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
23941da177e4SLinus Torvalds 		if (rc)
23951da177e4SLinus Torvalds 			return rc;
23961da177e4SLinus Torvalds 
23976b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
23986b6bc620SStephen Smalley 				  new_tsec->sid, isec->sid,
23991da177e4SLinus Torvalds 				  SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
24001da177e4SLinus Torvalds 		if (rc)
24011da177e4SLinus Torvalds 			return rc;
24021da177e4SLinus Torvalds 
2403a6f76f23SDavid Howells 		/* Check for shared state */
2404a6f76f23SDavid Howells 		if (bprm->unsafe & LSM_UNSAFE_SHARE) {
24056b6bc620SStephen Smalley 			rc = avc_has_perm(&selinux_state,
24066b6bc620SStephen Smalley 					  old_tsec->sid, new_tsec->sid,
2407a6f76f23SDavid Howells 					  SECCLASS_PROCESS, PROCESS__SHARE,
2408a6f76f23SDavid Howells 					  NULL);
2409a6f76f23SDavid Howells 			if (rc)
2410a6f76f23SDavid Howells 				return -EPERM;
24111da177e4SLinus Torvalds 		}
24121da177e4SLinus Torvalds 
2413a6f76f23SDavid Howells 		/* Make sure that anyone attempting to ptrace over a task that
2414a6f76f23SDavid Howells 		 * changes its SID has the appropriate permit */
24159227dd2aSEric W. Biederman 		if (bprm->unsafe & LSM_UNSAFE_PTRACE) {
2416be0554c9SStephen Smalley 			u32 ptsid = ptrace_parent_sid();
2417a6f76f23SDavid Howells 			if (ptsid != 0) {
24186b6bc620SStephen Smalley 				rc = avc_has_perm(&selinux_state,
24196b6bc620SStephen Smalley 						  ptsid, new_tsec->sid,
2420a6f76f23SDavid Howells 						  SECCLASS_PROCESS,
2421a6f76f23SDavid Howells 						  PROCESS__PTRACE, NULL);
2422a6f76f23SDavid Howells 				if (rc)
2423a6f76f23SDavid Howells 					return -EPERM;
2424a6f76f23SDavid Howells 			}
2425a6f76f23SDavid Howells 		}
2426a6f76f23SDavid Howells 
2427a6f76f23SDavid Howells 		/* Clear any possibly unsafe personality bits on exec: */
2428a6f76f23SDavid Howells 		bprm->per_clear |= PER_CLEAR_ON_SETID;
2429a6f76f23SDavid Howells 
24301da177e4SLinus Torvalds 		/* Enable secure mode for SIDs transitions unless
24311da177e4SLinus Torvalds 		   the noatsecure permission is granted between
24321da177e4SLinus Torvalds 		   the two SIDs, i.e. ahp returns 0. */
24336b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
24346b6bc620SStephen Smalley 				  old_tsec->sid, new_tsec->sid,
243562874c3aSKees Cook 				  SECCLASS_PROCESS, PROCESS__NOATSECURE,
243662874c3aSKees Cook 				  NULL);
243762874c3aSKees Cook 		bprm->secureexec |= !!rc;
24381da177e4SLinus Torvalds 	}
24391da177e4SLinus Torvalds 
244062874c3aSKees Cook 	return 0;
24411da177e4SLinus Torvalds }
24421da177e4SLinus Torvalds 
2443c3c073f8SAl Viro static int match_file(const void *p, struct file *file, unsigned fd)
2444c3c073f8SAl Viro {
2445c3c073f8SAl Viro 	return file_has_perm(p, file, file_to_av(file)) ? fd + 1 : 0;
2446c3c073f8SAl Viro }
2447c3c073f8SAl Viro 
24481da177e4SLinus Torvalds /* Derived from fs/exec.c:flush_old_files. */
2449745ca247SDavid Howells static inline void flush_unauthorized_files(const struct cred *cred,
2450745ca247SDavid Howells 					    struct files_struct *files)
24511da177e4SLinus Torvalds {
24521da177e4SLinus Torvalds 	struct file *file, *devnull = NULL;
2453b20c8122SStephen Smalley 	struct tty_struct *tty;
245424ec839cSPeter Zijlstra 	int drop_tty = 0;
2455c3c073f8SAl Viro 	unsigned n;
24561da177e4SLinus Torvalds 
245724ec839cSPeter Zijlstra 	tty = get_current_tty();
24581da177e4SLinus Torvalds 	if (tty) {
24594a510969SPeter Hurley 		spin_lock(&tty->files_lock);
246037dd0bd0SEric Paris 		if (!list_empty(&tty->tty_files)) {
2461d996b62aSNick Piggin 			struct tty_file_private *file_priv;
246237dd0bd0SEric Paris 
24631da177e4SLinus Torvalds 			/* Revalidate access to controlling tty.
246413f8e981SDavid Howells 			   Use file_path_has_perm on the tty path directly
246513f8e981SDavid Howells 			   rather than using file_has_perm, as this particular
246613f8e981SDavid Howells 			   open file may belong to another process and we are
246713f8e981SDavid Howells 			   only interested in the inode-based check here. */
2468d996b62aSNick Piggin 			file_priv = list_first_entry(&tty->tty_files,
2469d996b62aSNick Piggin 						struct tty_file_private, list);
2470d996b62aSNick Piggin 			file = file_priv->file;
247113f8e981SDavid Howells 			if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE))
247224ec839cSPeter Zijlstra 				drop_tty = 1;
24731da177e4SLinus Torvalds 		}
24744a510969SPeter Hurley 		spin_unlock(&tty->files_lock);
2475452a00d2SAlan Cox 		tty_kref_put(tty);
24761da177e4SLinus Torvalds 	}
247798a27ba4SEric W. Biederman 	/* Reset controlling tty. */
247898a27ba4SEric W. Biederman 	if (drop_tty)
247998a27ba4SEric W. Biederman 		no_tty();
24801da177e4SLinus Torvalds 
24811da177e4SLinus Torvalds 	/* Revalidate access to inherited open files. */
2482c3c073f8SAl Viro 	n = iterate_fd(files, 0, match_file, cred);
2483c3c073f8SAl Viro 	if (!n) /* none found? */
2484c3c073f8SAl Viro 		return;
24851da177e4SLinus Torvalds 
2486c3c073f8SAl Viro 	devnull = dentry_open(&selinux_null, O_RDWR, cred);
248745525b26SAl Viro 	if (IS_ERR(devnull))
248845525b26SAl Viro 		devnull = NULL;
2489c3c073f8SAl Viro 	/* replace all the matching ones with this */
2490c3c073f8SAl Viro 	do {
249145525b26SAl Viro 		replace_fd(n - 1, devnull, 0);
2492c3c073f8SAl Viro 	} while ((n = iterate_fd(files, n, match_file, cred)) != 0);
249345525b26SAl Viro 	if (devnull)
2494c3c073f8SAl Viro 		fput(devnull);
24951da177e4SLinus Torvalds }
24961da177e4SLinus Torvalds 
24971da177e4SLinus Torvalds /*
2498a6f76f23SDavid Howells  * Prepare a process for imminent new credential changes due to exec
24991da177e4SLinus Torvalds  */
2500a6f76f23SDavid Howells static void selinux_bprm_committing_creds(struct linux_binprm *bprm)
25011da177e4SLinus Torvalds {
2502a6f76f23SDavid Howells 	struct task_security_struct *new_tsec;
25031da177e4SLinus Torvalds 	struct rlimit *rlim, *initrlim;
25041da177e4SLinus Torvalds 	int rc, i;
25051da177e4SLinus Torvalds 
25060c6cfa62SCasey Schaufler 	new_tsec = selinux_cred(bprm->cred);
2507a6f76f23SDavid Howells 	if (new_tsec->sid == new_tsec->osid)
25081da177e4SLinus Torvalds 		return;
25091da177e4SLinus Torvalds 
25101da177e4SLinus Torvalds 	/* Close files for which the new task SID is not authorized. */
2511a6f76f23SDavid Howells 	flush_unauthorized_files(bprm->cred, current->files);
25121da177e4SLinus Torvalds 
2513a6f76f23SDavid Howells 	/* Always clear parent death signal on SID transitions. */
2514a6f76f23SDavid Howells 	current->pdeath_signal = 0;
2515a6f76f23SDavid Howells 
2516a6f76f23SDavid Howells 	/* Check whether the new SID can inherit resource limits from the old
2517a6f76f23SDavid Howells 	 * SID.  If not, reset all soft limits to the lower of the current
2518a6f76f23SDavid Howells 	 * task's hard limit and the init task's soft limit.
2519a6f76f23SDavid Howells 	 *
2520a6f76f23SDavid Howells 	 * Note that the setting of hard limits (even to lower them) can be
2521a6f76f23SDavid Howells 	 * controlled by the setrlimit check.  The inclusion of the init task's
2522a6f76f23SDavid Howells 	 * soft limit into the computation is to avoid resetting soft limits
2523a6f76f23SDavid Howells 	 * higher than the default soft limit for cases where the default is
2524a6f76f23SDavid Howells 	 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
2525a6f76f23SDavid Howells 	 */
25266b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
25276b6bc620SStephen Smalley 			  new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
2528a6f76f23SDavid Howells 			  PROCESS__RLIMITINH, NULL);
2529a6f76f23SDavid Howells 	if (rc) {
2530eb2d55a3SOleg Nesterov 		/* protect against do_prlimit() */
2531eb2d55a3SOleg Nesterov 		task_lock(current);
2532a6f76f23SDavid Howells 		for (i = 0; i < RLIM_NLIMITS; i++) {
2533a6f76f23SDavid Howells 			rlim = current->signal->rlim + i;
2534a6f76f23SDavid Howells 			initrlim = init_task.signal->rlim + i;
2535a6f76f23SDavid Howells 			rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
2536a6f76f23SDavid Howells 		}
2537eb2d55a3SOleg Nesterov 		task_unlock(current);
2538baa73d9eSNicolas Pitre 		if (IS_ENABLED(CONFIG_POSIX_TIMERS))
2539eb2d55a3SOleg Nesterov 			update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
2540a6f76f23SDavid Howells 	}
2541a6f76f23SDavid Howells }
2542a6f76f23SDavid Howells 
2543a6f76f23SDavid Howells /*
2544a6f76f23SDavid Howells  * Clean up the process immediately after the installation of new credentials
2545a6f76f23SDavid Howells  * due to exec
2546a6f76f23SDavid Howells  */
2547a6f76f23SDavid Howells static void selinux_bprm_committed_creds(struct linux_binprm *bprm)
2548a6f76f23SDavid Howells {
25490c6cfa62SCasey Schaufler 	const struct task_security_struct *tsec = selinux_cred(current_cred());
2550a6f76f23SDavid Howells 	struct itimerval itimer;
2551a6f76f23SDavid Howells 	u32 osid, sid;
2552a6f76f23SDavid Howells 	int rc, i;
2553a6f76f23SDavid Howells 
2554a6f76f23SDavid Howells 	osid = tsec->osid;
2555a6f76f23SDavid Howells 	sid = tsec->sid;
2556a6f76f23SDavid Howells 
2557a6f76f23SDavid Howells 	if (sid == osid)
2558a6f76f23SDavid Howells 		return;
2559a6f76f23SDavid Howells 
2560a6f76f23SDavid Howells 	/* Check whether the new SID can inherit signal state from the old SID.
2561a6f76f23SDavid Howells 	 * If not, clear itimers to avoid subsequent signal generation and
2562a6f76f23SDavid Howells 	 * flush and unblock signals.
2563a6f76f23SDavid Howells 	 *
2564a6f76f23SDavid Howells 	 * This must occur _after_ the task SID has been updated so that any
2565a6f76f23SDavid Howells 	 * kill done after the flush will be checked against the new SID.
2566a6f76f23SDavid Howells 	 */
25676b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
25686b6bc620SStephen Smalley 			  osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
25691da177e4SLinus Torvalds 	if (rc) {
2570baa73d9eSNicolas Pitre 		if (IS_ENABLED(CONFIG_POSIX_TIMERS)) {
25711da177e4SLinus Torvalds 			memset(&itimer, 0, sizeof itimer);
25721da177e4SLinus Torvalds 			for (i = 0; i < 3; i++)
25731da177e4SLinus Torvalds 				do_setitimer(i, &itimer, NULL);
2574baa73d9eSNicolas Pitre 		}
25751da177e4SLinus Torvalds 		spin_lock_irq(&current->sighand->siglock);
25769e7c8f8cSOleg Nesterov 		if (!fatal_signal_pending(current)) {
25779e7c8f8cSOleg Nesterov 			flush_sigqueue(&current->pending);
25789e7c8f8cSOleg Nesterov 			flush_sigqueue(&current->signal->shared_pending);
25791da177e4SLinus Torvalds 			flush_signal_handlers(current, 1);
25801da177e4SLinus Torvalds 			sigemptyset(&current->blocked);
25819e7c8f8cSOleg Nesterov 			recalc_sigpending();
25823bcac026SDavid Howells 		}
25831da177e4SLinus Torvalds 		spin_unlock_irq(&current->sighand->siglock);
25841da177e4SLinus Torvalds 	}
25851da177e4SLinus Torvalds 
2586a6f76f23SDavid Howells 	/* Wake up the parent if it is waiting so that it can recheck
2587a6f76f23SDavid Howells 	 * wait permission to the new task SID. */
2588ecd6de3cSOleg Nesterov 	read_lock(&tasklist_lock);
25890b7570e7SOleg Nesterov 	__wake_up_parent(current, current->real_parent);
2590ecd6de3cSOleg Nesterov 	read_unlock(&tasklist_lock);
25911da177e4SLinus Torvalds }
25921da177e4SLinus Torvalds 
25931da177e4SLinus Torvalds /* superblock security operations */
25941da177e4SLinus Torvalds 
25951da177e4SLinus Torvalds static int selinux_sb_alloc_security(struct super_block *sb)
25961da177e4SLinus Torvalds {
25971da177e4SLinus Torvalds 	return superblock_alloc_security(sb);
25981da177e4SLinus Torvalds }
25991da177e4SLinus Torvalds 
26001da177e4SLinus Torvalds static void selinux_sb_free_security(struct super_block *sb)
26011da177e4SLinus Torvalds {
26021da177e4SLinus Torvalds 	superblock_free_security(sb);
26031da177e4SLinus Torvalds }
26041da177e4SLinus Torvalds 
260599dbbb59SAl Viro static inline int opt_len(const char *s)
26061da177e4SLinus Torvalds {
260799dbbb59SAl Viro 	bool open_quote = false;
260899dbbb59SAl Viro 	int len;
260999dbbb59SAl Viro 	char c;
26101da177e4SLinus Torvalds 
261199dbbb59SAl Viro 	for (len = 0; (c = s[len]) != '\0'; len++) {
261299dbbb59SAl Viro 		if (c == '"')
26133528a953SCory Olmo 			open_quote = !open_quote;
261499dbbb59SAl Viro 		if (c == ',' && !open_quote)
261599dbbb59SAl Viro 			break;
26161da177e4SLinus Torvalds 	}
261799dbbb59SAl Viro 	return len;
26181da177e4SLinus Torvalds }
26191da177e4SLinus Torvalds 
2620204cc0ccSAl Viro static int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
26215b400239SAl Viro {
262299dbbb59SAl Viro 	char *from = options;
262399dbbb59SAl Viro 	char *to = options;
262499dbbb59SAl Viro 	bool first = true;
2625fec63753SGen Zhang 	int rc;
26265b400239SAl Viro 
262799dbbb59SAl Viro 	while (1) {
262899dbbb59SAl Viro 		int len = opt_len(from);
2629fec63753SGen Zhang 		int token;
263099dbbb59SAl Viro 		char *arg = NULL;
263199dbbb59SAl Viro 
263299dbbb59SAl Viro 		token = match_opt_prefix(from, len, &arg);
263399dbbb59SAl Viro 
263499dbbb59SAl Viro 		if (token != Opt_error) {
263599dbbb59SAl Viro 			char *p, *q;
263699dbbb59SAl Viro 
263799dbbb59SAl Viro 			/* strip quotes */
263899dbbb59SAl Viro 			if (arg) {
263999dbbb59SAl Viro 				for (p = q = arg; p < from + len; p++) {
264099dbbb59SAl Viro 					char c = *p;
264199dbbb59SAl Viro 					if (c != '"')
264299dbbb59SAl Viro 						*q++ = c;
264399dbbb59SAl Viro 				}
264499dbbb59SAl Viro 				arg = kmemdup_nul(arg, q - arg, GFP_KERNEL);
2645fec63753SGen Zhang 				if (!arg) {
2646fec63753SGen Zhang 					rc = -ENOMEM;
2647fec63753SGen Zhang 					goto free_opt;
2648fec63753SGen Zhang 				}
264999dbbb59SAl Viro 			}
265099dbbb59SAl Viro 			rc = selinux_add_opt(token, arg, mnt_opts);
265199dbbb59SAl Viro 			if (unlikely(rc)) {
265299dbbb59SAl Viro 				kfree(arg);
2653fec63753SGen Zhang 				goto free_opt;
26541da177e4SLinus Torvalds 			}
265599dbbb59SAl Viro 		} else {
265699dbbb59SAl Viro 			if (!first) {	// copy with preceding comma
265799dbbb59SAl Viro 				from--;
265899dbbb59SAl Viro 				len++;
265999dbbb59SAl Viro 			}
266099dbbb59SAl Viro 			if (to != from)
266199dbbb59SAl Viro 				memmove(to, from, len);
266299dbbb59SAl Viro 			to += len;
266399dbbb59SAl Viro 			first = false;
266499dbbb59SAl Viro 		}
266599dbbb59SAl Viro 		if (!from[len])
266699dbbb59SAl Viro 			break;
266799dbbb59SAl Viro 		from += len + 1;
266899dbbb59SAl Viro 	}
266999dbbb59SAl Viro 	*to = '\0';
267099dbbb59SAl Viro 	return 0;
2671fec63753SGen Zhang 
2672fec63753SGen Zhang free_opt:
2673fec63753SGen Zhang 	if (*mnt_opts) {
2674fec63753SGen Zhang 		selinux_free_mnt_opts(*mnt_opts);
2675fec63753SGen Zhang 		*mnt_opts = NULL;
2676fec63753SGen Zhang 	}
2677fec63753SGen Zhang 	return rc;
26785b400239SAl Viro }
26791da177e4SLinus Torvalds 
2680204cc0ccSAl Viro static int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
2681026eb167SEric Paris {
2682bd323655SAl Viro 	struct selinux_mnt_opts *opts = mnt_opts;
2683026eb167SEric Paris 	struct superblock_security_struct *sbsec = sb->s_security;
2684bd323655SAl Viro 	u32 sid;
2685bd323655SAl Viro 	int rc;
2686026eb167SEric Paris 
2687026eb167SEric Paris 	if (!(sbsec->flags & SE_SBINITIALIZED))
2688026eb167SEric Paris 		return 0;
2689026eb167SEric Paris 
2690204cc0ccSAl Viro 	if (!opts)
2691026eb167SEric Paris 		return 0;
2692026eb167SEric Paris 
2693bd323655SAl Viro 	if (opts->fscontext) {
2694bd323655SAl Viro 		rc = parse_sid(sb, opts->fscontext, &sid);
2695026eb167SEric Paris 		if (rc)
2696c039bc3cSAl Viro 			return rc;
2697026eb167SEric Paris 		if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid))
2698026eb167SEric Paris 			goto out_bad_option;
2699bd323655SAl Viro 	}
2700bd323655SAl Viro 	if (opts->context) {
2701bd323655SAl Viro 		rc = parse_sid(sb, opts->context, &sid);
2702bd323655SAl Viro 		if (rc)
2703bd323655SAl Viro 			return rc;
2704026eb167SEric Paris 		if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid))
2705026eb167SEric Paris 			goto out_bad_option;
2706bd323655SAl Viro 	}
2707bd323655SAl Viro 	if (opts->rootcontext) {
2708026eb167SEric Paris 		struct inode_security_struct *root_isec;
270983da53c5SAndreas Gruenbacher 		root_isec = backing_inode_security(sb->s_root);
2710bd323655SAl Viro 		rc = parse_sid(sb, opts->rootcontext, &sid);
2711bd323655SAl Viro 		if (rc)
2712bd323655SAl Viro 			return rc;
2713026eb167SEric Paris 		if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid))
2714026eb167SEric Paris 			goto out_bad_option;
2715026eb167SEric Paris 	}
2716bd323655SAl Viro 	if (opts->defcontext) {
2717bd323655SAl Viro 		rc = parse_sid(sb, opts->defcontext, &sid);
2718bd323655SAl Viro 		if (rc)
2719bd323655SAl Viro 			return rc;
2720026eb167SEric Paris 		if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid))
2721026eb167SEric Paris 			goto out_bad_option;
2722026eb167SEric Paris 	}
2723c039bc3cSAl Viro 	return 0;
2724026eb167SEric Paris 
2725026eb167SEric Paris out_bad_option:
2726c103a91eSpeter enderborg 	pr_warn("SELinux: unable to change security options "
272729b1deb2SLinus Torvalds 	       "during remount (dev %s, type=%s)\n", sb->s_id,
272829b1deb2SLinus Torvalds 	       sb->s_type->name);
2729c039bc3cSAl Viro 	return -EINVAL;
2730026eb167SEric Paris }
2731026eb167SEric Paris 
2732a10d7c22SAl Viro static int selinux_sb_kern_mount(struct super_block *sb)
27331da177e4SLinus Torvalds {
273488e67f3bSDavid Howells 	const struct cred *cred = current_cred();
27352bf49690SThomas Liu 	struct common_audit_data ad;
273674192246SJames Morris 
273750c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
2738a269434dSEric Paris 	ad.u.dentry = sb->s_root;
273988e67f3bSDavid Howells 	return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
27401da177e4SLinus Torvalds }
27411da177e4SLinus Torvalds 
2742726c3342SDavid Howells static int selinux_sb_statfs(struct dentry *dentry)
27431da177e4SLinus Torvalds {
274488e67f3bSDavid Howells 	const struct cred *cred = current_cred();
27452bf49690SThomas Liu 	struct common_audit_data ad;
27461da177e4SLinus Torvalds 
274750c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
2748a269434dSEric Paris 	ad.u.dentry = dentry->d_sb->s_root;
274988e67f3bSDavid Howells 	return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
27501da177e4SLinus Torvalds }
27511da177e4SLinus Torvalds 
2752808d4e3cSAl Viro static int selinux_mount(const char *dev_name,
27538a04c43bSAl Viro 			 const struct path *path,
2754808d4e3cSAl Viro 			 const char *type,
27551da177e4SLinus Torvalds 			 unsigned long flags,
27561da177e4SLinus Torvalds 			 void *data)
27571da177e4SLinus Torvalds {
275888e67f3bSDavid Howells 	const struct cred *cred = current_cred();
27591da177e4SLinus Torvalds 
27601da177e4SLinus Torvalds 	if (flags & MS_REMOUNT)
2761d8c9584eSAl Viro 		return superblock_has_perm(cred, path->dentry->d_sb,
27621da177e4SLinus Torvalds 					   FILESYSTEM__REMOUNT, NULL);
27631da177e4SLinus Torvalds 	else
27642875fa00SEric Paris 		return path_has_perm(cred, path, FILE__MOUNTON);
27651da177e4SLinus Torvalds }
27661da177e4SLinus Torvalds 
27671da177e4SLinus Torvalds static int selinux_umount(struct vfsmount *mnt, int flags)
27681da177e4SLinus Torvalds {
276988e67f3bSDavid Howells 	const struct cred *cred = current_cred();
27701da177e4SLinus Torvalds 
277188e67f3bSDavid Howells 	return superblock_has_perm(cred, mnt->mnt_sb,
27721da177e4SLinus Torvalds 				   FILESYSTEM__UNMOUNT, NULL);
27731da177e4SLinus Torvalds }
27741da177e4SLinus Torvalds 
27750b52075eSAl Viro static int selinux_fs_context_dup(struct fs_context *fc,
27760b52075eSAl Viro 				  struct fs_context *src_fc)
27770b52075eSAl Viro {
27780b52075eSAl Viro 	const struct selinux_mnt_opts *src = src_fc->security;
27790b52075eSAl Viro 	struct selinux_mnt_opts *opts;
27800b52075eSAl Viro 
27810b52075eSAl Viro 	if (!src)
27820b52075eSAl Viro 		return 0;
27830b52075eSAl Viro 
27840b52075eSAl Viro 	fc->security = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL);
27850b52075eSAl Viro 	if (!fc->security)
27860b52075eSAl Viro 		return -ENOMEM;
27870b52075eSAl Viro 
27880b52075eSAl Viro 	opts = fc->security;
27890b52075eSAl Viro 
27900b52075eSAl Viro 	if (src->fscontext) {
27910b52075eSAl Viro 		opts->fscontext = kstrdup(src->fscontext, GFP_KERNEL);
27920b52075eSAl Viro 		if (!opts->fscontext)
27930b52075eSAl Viro 			return -ENOMEM;
27940b52075eSAl Viro 	}
27950b52075eSAl Viro 	if (src->context) {
27960b52075eSAl Viro 		opts->context = kstrdup(src->context, GFP_KERNEL);
27970b52075eSAl Viro 		if (!opts->context)
27980b52075eSAl Viro 			return -ENOMEM;
27990b52075eSAl Viro 	}
28000b52075eSAl Viro 	if (src->rootcontext) {
28010b52075eSAl Viro 		opts->rootcontext = kstrdup(src->rootcontext, GFP_KERNEL);
28020b52075eSAl Viro 		if (!opts->rootcontext)
28030b52075eSAl Viro 			return -ENOMEM;
28040b52075eSAl Viro 	}
28050b52075eSAl Viro 	if (src->defcontext) {
28060b52075eSAl Viro 		opts->defcontext = kstrdup(src->defcontext, GFP_KERNEL);
28070b52075eSAl Viro 		if (!opts->defcontext)
28080b52075eSAl Viro 			return -ENOMEM;
28090b52075eSAl Viro 	}
28100b52075eSAl Viro 	return 0;
28110b52075eSAl Viro }
28120b52075eSAl Viro 
2813442155c1SDavid Howells static const struct fs_parameter_spec selinux_param_specs[] = {
2814442155c1SDavid Howells 	fsparam_string(CONTEXT_STR,	Opt_context),
2815442155c1SDavid Howells 	fsparam_string(DEFCONTEXT_STR,	Opt_defcontext),
2816442155c1SDavid Howells 	fsparam_string(FSCONTEXT_STR,	Opt_fscontext),
2817442155c1SDavid Howells 	fsparam_string(ROOTCONTEXT_STR,	Opt_rootcontext),
2818442155c1SDavid Howells 	fsparam_flag  (SECLABEL_STR,	Opt_seclabel),
2819442155c1SDavid Howells 	{}
2820442155c1SDavid Howells };
2821442155c1SDavid Howells 
2822442155c1SDavid Howells static const struct fs_parameter_description selinux_fs_parameters = {
2823442155c1SDavid Howells 	.name		= "SELinux",
2824442155c1SDavid Howells 	.specs		= selinux_param_specs,
2825442155c1SDavid Howells };
2826442155c1SDavid Howells 
2827442155c1SDavid Howells static int selinux_fs_context_parse_param(struct fs_context *fc,
2828442155c1SDavid Howells 					  struct fs_parameter *param)
2829442155c1SDavid Howells {
2830442155c1SDavid Howells 	struct fs_parse_result result;
2831442155c1SDavid Howells 	int opt, rc;
2832442155c1SDavid Howells 
2833442155c1SDavid Howells 	opt = fs_parse(fc, &selinux_fs_parameters, param, &result);
2834442155c1SDavid Howells 	if (opt < 0)
2835442155c1SDavid Howells 		return opt;
2836442155c1SDavid Howells 
2837442155c1SDavid Howells 	rc = selinux_add_opt(opt, param->string, &fc->security);
2838442155c1SDavid Howells 	if (!rc) {
2839442155c1SDavid Howells 		param->string = NULL;
2840442155c1SDavid Howells 		rc = 1;
2841442155c1SDavid Howells 	}
2842442155c1SDavid Howells 	return rc;
2843442155c1SDavid Howells }
2844442155c1SDavid Howells 
28451da177e4SLinus Torvalds /* inode security operations */
28461da177e4SLinus Torvalds 
28471da177e4SLinus Torvalds static int selinux_inode_alloc_security(struct inode *inode)
28481da177e4SLinus Torvalds {
28491da177e4SLinus Torvalds 	return inode_alloc_security(inode);
28501da177e4SLinus Torvalds }
28511da177e4SLinus Torvalds 
28521da177e4SLinus Torvalds static void selinux_inode_free_security(struct inode *inode)
28531da177e4SLinus Torvalds {
28541da177e4SLinus Torvalds 	inode_free_security(inode);
28551da177e4SLinus Torvalds }
28561da177e4SLinus Torvalds 
2857d47be3dfSDavid Quigley static int selinux_dentry_init_security(struct dentry *dentry, int mode,
28584f3ccd76SAl Viro 					const struct qstr *name, void **ctx,
2859d47be3dfSDavid Quigley 					u32 *ctxlen)
2860d47be3dfSDavid Quigley {
2861d47be3dfSDavid Quigley 	u32 newsid;
2862d47be3dfSDavid Quigley 	int rc;
2863d47be3dfSDavid Quigley 
28640c6cfa62SCasey Schaufler 	rc = selinux_determine_inode_label(selinux_cred(current_cred()),
2865c957f6dfSVivek Goyal 					   d_inode(dentry->d_parent), name,
2866d47be3dfSDavid Quigley 					   inode_mode_to_security_class(mode),
2867d47be3dfSDavid Quigley 					   &newsid);
2868c3c188b2SDavid Howells 	if (rc)
2869d47be3dfSDavid Quigley 		return rc;
2870d47be3dfSDavid Quigley 
2871aa8e712cSStephen Smalley 	return security_sid_to_context(&selinux_state, newsid, (char **)ctx,
2872aa8e712cSStephen Smalley 				       ctxlen);
2873d47be3dfSDavid Quigley }
2874d47be3dfSDavid Quigley 
2875a518b0a5SVivek Goyal static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
2876a518b0a5SVivek Goyal 					  struct qstr *name,
2877a518b0a5SVivek Goyal 					  const struct cred *old,
2878a518b0a5SVivek Goyal 					  struct cred *new)
2879a518b0a5SVivek Goyal {
2880a518b0a5SVivek Goyal 	u32 newsid;
2881a518b0a5SVivek Goyal 	int rc;
2882a518b0a5SVivek Goyal 	struct task_security_struct *tsec;
2883a518b0a5SVivek Goyal 
28840c6cfa62SCasey Schaufler 	rc = selinux_determine_inode_label(selinux_cred(old),
2885a518b0a5SVivek Goyal 					   d_inode(dentry->d_parent), name,
2886a518b0a5SVivek Goyal 					   inode_mode_to_security_class(mode),
2887a518b0a5SVivek Goyal 					   &newsid);
2888a518b0a5SVivek Goyal 	if (rc)
2889a518b0a5SVivek Goyal 		return rc;
2890a518b0a5SVivek Goyal 
28910c6cfa62SCasey Schaufler 	tsec = selinux_cred(new);
2892a518b0a5SVivek Goyal 	tsec->create_sid = newsid;
2893a518b0a5SVivek Goyal 	return 0;
2894a518b0a5SVivek Goyal }
2895a518b0a5SVivek Goyal 
28965e41ff9eSStephen Smalley static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
28979548906bSTetsuo Handa 				       const struct qstr *qstr,
28989548906bSTetsuo Handa 				       const char **name,
28992a7dba39SEric Paris 				       void **value, size_t *len)
29005e41ff9eSStephen Smalley {
29010c6cfa62SCasey Schaufler 	const struct task_security_struct *tsec = selinux_cred(current_cred());
29025e41ff9eSStephen Smalley 	struct superblock_security_struct *sbsec;
2903c0d4f464SCorentin LABBE 	u32 newsid, clen;
29045e41ff9eSStephen Smalley 	int rc;
29059548906bSTetsuo Handa 	char *context;
29065e41ff9eSStephen Smalley 
29075e41ff9eSStephen Smalley 	sbsec = dir->i_sb->s_security;
29085e41ff9eSStephen Smalley 
29095e41ff9eSStephen Smalley 	newsid = tsec->create_sid;
2910275bb41eSDavid Howells 
29110c6cfa62SCasey Schaufler 	rc = selinux_determine_inode_label(selinux_cred(current_cred()),
2912c3c188b2SDavid Howells 		dir, qstr,
29135e41ff9eSStephen Smalley 		inode_mode_to_security_class(inode->i_mode),
2914c3c188b2SDavid Howells 		&newsid);
2915c3c188b2SDavid Howells 	if (rc)
29165e41ff9eSStephen Smalley 		return rc;
29175e41ff9eSStephen Smalley 
2918296fddf7SEric Paris 	/* Possibly defer initialization to selinux_complete_init. */
29190d90a7ecSDavid P. Quigley 	if (sbsec->flags & SE_SBINITIALIZED) {
292080788c22SCasey Schaufler 		struct inode_security_struct *isec = selinux_inode(inode);
2921296fddf7SEric Paris 		isec->sclass = inode_mode_to_security_class(inode->i_mode);
2922296fddf7SEric Paris 		isec->sid = newsid;
29236f3be9f5SAndreas Gruenbacher 		isec->initialized = LABEL_INITIALIZED;
2924296fddf7SEric Paris 	}
29255e41ff9eSStephen Smalley 
2926aa8e712cSStephen Smalley 	if (!selinux_state.initialized || !(sbsec->flags & SBLABEL_MNT))
292725a74f3bSStephen Smalley 		return -EOPNOTSUPP;
292825a74f3bSStephen Smalley 
29299548906bSTetsuo Handa 	if (name)
29309548906bSTetsuo Handa 		*name = XATTR_SELINUX_SUFFIX;
29315e41ff9eSStephen Smalley 
2932570bc1c2SStephen Smalley 	if (value && len) {
2933aa8e712cSStephen Smalley 		rc = security_sid_to_context_force(&selinux_state, newsid,
2934aa8e712cSStephen Smalley 						   &context, &clen);
29359548906bSTetsuo Handa 		if (rc)
29365e41ff9eSStephen Smalley 			return rc;
29375e41ff9eSStephen Smalley 		*value = context;
2938570bc1c2SStephen Smalley 		*len = clen;
2939570bc1c2SStephen Smalley 	}
29405e41ff9eSStephen Smalley 
29415e41ff9eSStephen Smalley 	return 0;
29425e41ff9eSStephen Smalley }
29435e41ff9eSStephen Smalley 
29444acdaf27SAl Viro static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
29451da177e4SLinus Torvalds {
29461da177e4SLinus Torvalds 	return may_create(dir, dentry, SECCLASS_FILE);
29471da177e4SLinus Torvalds }
29481da177e4SLinus Torvalds 
29491da177e4SLinus Torvalds static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
29501da177e4SLinus Torvalds {
29511da177e4SLinus Torvalds 	return may_link(dir, old_dentry, MAY_LINK);
29521da177e4SLinus Torvalds }
29531da177e4SLinus Torvalds 
29541da177e4SLinus Torvalds static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
29551da177e4SLinus Torvalds {
29561da177e4SLinus Torvalds 	return may_link(dir, dentry, MAY_UNLINK);
29571da177e4SLinus Torvalds }
29581da177e4SLinus Torvalds 
29591da177e4SLinus Torvalds static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
29601da177e4SLinus Torvalds {
29611da177e4SLinus Torvalds 	return may_create(dir, dentry, SECCLASS_LNK_FILE);
29621da177e4SLinus Torvalds }
29631da177e4SLinus Torvalds 
296418bb1db3SAl Viro static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
29651da177e4SLinus Torvalds {
29661da177e4SLinus Torvalds 	return may_create(dir, dentry, SECCLASS_DIR);
29671da177e4SLinus Torvalds }
29681da177e4SLinus Torvalds 
29691da177e4SLinus Torvalds static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
29701da177e4SLinus Torvalds {
29711da177e4SLinus Torvalds 	return may_link(dir, dentry, MAY_RMDIR);
29721da177e4SLinus Torvalds }
29731da177e4SLinus Torvalds 
29741a67aafbSAl Viro static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
29751da177e4SLinus Torvalds {
29761da177e4SLinus Torvalds 	return may_create(dir, dentry, inode_mode_to_security_class(mode));
29771da177e4SLinus Torvalds }
29781da177e4SLinus Torvalds 
29791da177e4SLinus Torvalds static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
29801da177e4SLinus Torvalds 				struct inode *new_inode, struct dentry *new_dentry)
29811da177e4SLinus Torvalds {
29821da177e4SLinus Torvalds 	return may_rename(old_inode, old_dentry, new_inode, new_dentry);
29831da177e4SLinus Torvalds }
29841da177e4SLinus Torvalds 
29851da177e4SLinus Torvalds static int selinux_inode_readlink(struct dentry *dentry)
29861da177e4SLinus Torvalds {
298788e67f3bSDavid Howells 	const struct cred *cred = current_cred();
298888e67f3bSDavid Howells 
29892875fa00SEric Paris 	return dentry_has_perm(cred, dentry, FILE__READ);
29901da177e4SLinus Torvalds }
29911da177e4SLinus Torvalds 
2992bda0be7aSNeilBrown static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
2993bda0be7aSNeilBrown 				     bool rcu)
29941da177e4SLinus Torvalds {
299588e67f3bSDavid Howells 	const struct cred *cred = current_cred();
2996bda0be7aSNeilBrown 	struct common_audit_data ad;
2997bda0be7aSNeilBrown 	struct inode_security_struct *isec;
2998bda0be7aSNeilBrown 	u32 sid;
29991da177e4SLinus Torvalds 
3000bda0be7aSNeilBrown 	validate_creds(cred);
3001bda0be7aSNeilBrown 
3002bda0be7aSNeilBrown 	ad.type = LSM_AUDIT_DATA_DENTRY;
3003bda0be7aSNeilBrown 	ad.u.dentry = dentry;
3004bda0be7aSNeilBrown 	sid = cred_sid(cred);
30055d226df4SAndreas Gruenbacher 	isec = inode_security_rcu(inode, rcu);
30065d226df4SAndreas Gruenbacher 	if (IS_ERR(isec))
30075d226df4SAndreas Gruenbacher 		return PTR_ERR(isec);
3008bda0be7aSNeilBrown 
3009e46e01eeSStephen Smalley 	return avc_has_perm(&selinux_state,
3010e46e01eeSStephen Smalley 			    sid, isec->sid, isec->sclass, FILE__READ, &ad);
30111da177e4SLinus Torvalds }
30121da177e4SLinus Torvalds 
3013d4cf970dSEric Paris static noinline int audit_inode_permission(struct inode *inode,
3014d4cf970dSEric Paris 					   u32 perms, u32 audited, u32 denied,
3015626b9740SStephen Smalley 					   int result,
3016d4cf970dSEric Paris 					   unsigned flags)
3017d4cf970dSEric Paris {
3018d4cf970dSEric Paris 	struct common_audit_data ad;
301980788c22SCasey Schaufler 	struct inode_security_struct *isec = selinux_inode(inode);
3020d4cf970dSEric Paris 	int rc;
3021d4cf970dSEric Paris 
302250c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_INODE;
3023d4cf970dSEric Paris 	ad.u.inode = inode;
3024d4cf970dSEric Paris 
30256b6bc620SStephen Smalley 	rc = slow_avc_audit(&selinux_state,
30266b6bc620SStephen Smalley 			    current_sid(), isec->sid, isec->sclass, perms,
3027626b9740SStephen Smalley 			    audited, denied, result, &ad, flags);
3028d4cf970dSEric Paris 	if (rc)
3029d4cf970dSEric Paris 		return rc;
3030d4cf970dSEric Paris 	return 0;
3031d4cf970dSEric Paris }
3032d4cf970dSEric Paris 
3033e74f71ebSAl Viro static int selinux_inode_permission(struct inode *inode, int mask)
30341da177e4SLinus Torvalds {
303588e67f3bSDavid Howells 	const struct cred *cred = current_cred();
3036b782e0a6SEric Paris 	u32 perms;
3037b782e0a6SEric Paris 	bool from_access;
3038cf1dd1daSAl Viro 	unsigned flags = mask & MAY_NOT_BLOCK;
30392e334057SEric Paris 	struct inode_security_struct *isec;
30402e334057SEric Paris 	u32 sid;
30412e334057SEric Paris 	struct av_decision avd;
30422e334057SEric Paris 	int rc, rc2;
30432e334057SEric Paris 	u32 audited, denied;
30441da177e4SLinus Torvalds 
3045b782e0a6SEric Paris 	from_access = mask & MAY_ACCESS;
3046d09ca739SEric Paris 	mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
3047d09ca739SEric Paris 
30481da177e4SLinus Torvalds 	/* No permission to check.  Existence test. */
3049b782e0a6SEric Paris 	if (!mask)
30501da177e4SLinus Torvalds 		return 0;
30511da177e4SLinus Torvalds 
30522e334057SEric Paris 	validate_creds(cred);
3053b782e0a6SEric Paris 
30542e334057SEric Paris 	if (unlikely(IS_PRIVATE(inode)))
30552e334057SEric Paris 		return 0;
3056b782e0a6SEric Paris 
3057b782e0a6SEric Paris 	perms = file_mask_to_av(inode->i_mode, mask);
3058b782e0a6SEric Paris 
30592e334057SEric Paris 	sid = cred_sid(cred);
30605d226df4SAndreas Gruenbacher 	isec = inode_security_rcu(inode, flags & MAY_NOT_BLOCK);
30615d226df4SAndreas Gruenbacher 	if (IS_ERR(isec))
30625d226df4SAndreas Gruenbacher 		return PTR_ERR(isec);
30632e334057SEric Paris 
30646b6bc620SStephen Smalley 	rc = avc_has_perm_noaudit(&selinux_state,
30653a28cff3SStephen Smalley 				  sid, isec->sid, isec->sclass, perms,
30663a28cff3SStephen Smalley 				  (flags & MAY_NOT_BLOCK) ? AVC_NONBLOCKING : 0,
30673a28cff3SStephen Smalley 				  &avd);
30682e334057SEric Paris 	audited = avc_audit_required(perms, &avd, rc,
30692e334057SEric Paris 				     from_access ? FILE__AUDIT_ACCESS : 0,
30702e334057SEric Paris 				     &denied);
30712e334057SEric Paris 	if (likely(!audited))
30722e334057SEric Paris 		return rc;
30732e334057SEric Paris 
3074626b9740SStephen Smalley 	rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags);
30752e334057SEric Paris 	if (rc2)
30762e334057SEric Paris 		return rc2;
30772e334057SEric Paris 	return rc;
30781da177e4SLinus Torvalds }
30791da177e4SLinus Torvalds 
30801da177e4SLinus Torvalds static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
30811da177e4SLinus Torvalds {
308288e67f3bSDavid Howells 	const struct cred *cred = current_cred();
3083ccb54478SStephen Smalley 	struct inode *inode = d_backing_inode(dentry);
3084bc6a6008SAmerigo Wang 	unsigned int ia_valid = iattr->ia_valid;
308595dbf739SEric Paris 	__u32 av = FILE__WRITE;
30861da177e4SLinus Torvalds 
3087bc6a6008SAmerigo Wang 	/* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
3088bc6a6008SAmerigo Wang 	if (ia_valid & ATTR_FORCE) {
3089bc6a6008SAmerigo Wang 		ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
3090bc6a6008SAmerigo Wang 			      ATTR_FORCE);
3091bc6a6008SAmerigo Wang 		if (!ia_valid)
30921da177e4SLinus Torvalds 			return 0;
3093bc6a6008SAmerigo Wang 	}
30941da177e4SLinus Torvalds 
3095bc6a6008SAmerigo Wang 	if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
3096bc6a6008SAmerigo Wang 			ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
30972875fa00SEric Paris 		return dentry_has_perm(cred, dentry, FILE__SETATTR);
30981da177e4SLinus Torvalds 
3099aa8e712cSStephen Smalley 	if (selinux_policycap_openperm() &&
3100ccb54478SStephen Smalley 	    inode->i_sb->s_magic != SOCKFS_MAGIC &&
3101ccb54478SStephen Smalley 	    (ia_valid & ATTR_SIZE) &&
3102ccb54478SStephen Smalley 	    !(ia_valid & ATTR_FILE))
310395dbf739SEric Paris 		av |= FILE__OPEN;
310495dbf739SEric Paris 
310595dbf739SEric Paris 	return dentry_has_perm(cred, dentry, av);
31061da177e4SLinus Torvalds }
31071da177e4SLinus Torvalds 
31083f7036a0SAl Viro static int selinux_inode_getattr(const struct path *path)
31091da177e4SLinus Torvalds {
31103f7036a0SAl Viro 	return path_has_perm(current_cred(), path, FILE__GETATTR);
31111da177e4SLinus Torvalds }
31121da177e4SLinus Torvalds 
3113db59000aSStephen Smalley static bool has_cap_mac_admin(bool audit)
3114db59000aSStephen Smalley {
3115db59000aSStephen Smalley 	const struct cred *cred = current_cred();
3116c1a85a00SMicah Morton 	unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT;
3117db59000aSStephen Smalley 
3118c1a85a00SMicah Morton 	if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts))
3119db59000aSStephen Smalley 		return false;
3120c1a85a00SMicah Morton 	if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true))
3121db59000aSStephen Smalley 		return false;
3122db59000aSStephen Smalley 	return true;
3123db59000aSStephen Smalley }
3124db59000aSStephen Smalley 
31258f0cfa52SDavid Howells static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
31268f0cfa52SDavid Howells 				  const void *value, size_t size, int flags)
31271da177e4SLinus Torvalds {
3128c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(dentry);
312920cdef8dSPaul Moore 	struct inode_security_struct *isec;
31301da177e4SLinus Torvalds 	struct superblock_security_struct *sbsec;
31312bf49690SThomas Liu 	struct common_audit_data ad;
3132275bb41eSDavid Howells 	u32 newsid, sid = current_sid();
31331da177e4SLinus Torvalds 	int rc = 0;
31341da177e4SLinus Torvalds 
31356b240306SEric W. Biederman 	if (strcmp(name, XATTR_NAME_SELINUX)) {
31366b240306SEric W. Biederman 		rc = cap_inode_setxattr(dentry, name, value, size, flags);
31376b240306SEric W. Biederman 		if (rc)
31386b240306SEric W. Biederman 			return rc;
31396b240306SEric W. Biederman 
31406b240306SEric W. Biederman 		/* Not an attribute we recognize, so just check the
31416b240306SEric W. Biederman 		   ordinary setattr permission. */
31426b240306SEric W. Biederman 		return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
31436b240306SEric W. Biederman 	}
31441da177e4SLinus Torvalds 
31451da177e4SLinus Torvalds 	sbsec = inode->i_sb->s_security;
314612f348b9SEric Paris 	if (!(sbsec->flags & SBLABEL_MNT))
31471da177e4SLinus Torvalds 		return -EOPNOTSUPP;
31481da177e4SLinus Torvalds 
31492e149670SSerge E. Hallyn 	if (!inode_owner_or_capable(inode))
31501da177e4SLinus Torvalds 		return -EPERM;
31511da177e4SLinus Torvalds 
315250c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_DENTRY;
3153a269434dSEric Paris 	ad.u.dentry = dentry;
31541da177e4SLinus Torvalds 
315520cdef8dSPaul Moore 	isec = backing_inode_security(dentry);
31566b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
31576b6bc620SStephen Smalley 			  sid, isec->sid, isec->sclass,
31581da177e4SLinus Torvalds 			  FILE__RELABELFROM, &ad);
31591da177e4SLinus Torvalds 	if (rc)
31601da177e4SLinus Torvalds 		return rc;
31611da177e4SLinus Torvalds 
3162aa8e712cSStephen Smalley 	rc = security_context_to_sid(&selinux_state, value, size, &newsid,
3163aa8e712cSStephen Smalley 				     GFP_KERNEL);
316412b29f34SStephen Smalley 	if (rc == -EINVAL) {
3165db59000aSStephen Smalley 		if (!has_cap_mac_admin(true)) {
3166d6ea83ecSEric Paris 			struct audit_buffer *ab;
3167d6ea83ecSEric Paris 			size_t audit_size;
3168d6ea83ecSEric Paris 
3169d6ea83ecSEric Paris 			/* We strip a nul only if it is at the end, otherwise the
3170d6ea83ecSEric Paris 			 * context contains a nul and we should audit that */
3171e3fea3f7SAl Viro 			if (value) {
3172add24372SColin Ian King 				const char *str = value;
3173add24372SColin Ian King 
3174d6ea83ecSEric Paris 				if (str[size - 1] == '\0')
3175d6ea83ecSEric Paris 					audit_size = size - 1;
3176d6ea83ecSEric Paris 				else
3177d6ea83ecSEric Paris 					audit_size = size;
3178e3fea3f7SAl Viro 			} else {
3179e3fea3f7SAl Viro 				audit_size = 0;
3180e3fea3f7SAl Viro 			}
3181cdfb6b34SRichard Guy Briggs 			ab = audit_log_start(audit_context(),
3182cdfb6b34SRichard Guy Briggs 					     GFP_ATOMIC, AUDIT_SELINUX_ERR);
3183d6ea83ecSEric Paris 			audit_log_format(ab, "op=setxattr invalid_context=");
3184d6ea83ecSEric Paris 			audit_log_n_untrustedstring(ab, value, audit_size);
3185d6ea83ecSEric Paris 			audit_log_end(ab);
3186d6ea83ecSEric Paris 
318712b29f34SStephen Smalley 			return rc;
3188d6ea83ecSEric Paris 		}
3189aa8e712cSStephen Smalley 		rc = security_context_to_sid_force(&selinux_state, value,
3190aa8e712cSStephen Smalley 						   size, &newsid);
319112b29f34SStephen Smalley 	}
31921da177e4SLinus Torvalds 	if (rc)
31931da177e4SLinus Torvalds 		return rc;
31941da177e4SLinus Torvalds 
31956b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
31966b6bc620SStephen Smalley 			  sid, newsid, isec->sclass,
31971da177e4SLinus Torvalds 			  FILE__RELABELTO, &ad);
31981da177e4SLinus Torvalds 	if (rc)
31991da177e4SLinus Torvalds 		return rc;
32001da177e4SLinus Torvalds 
3201aa8e712cSStephen Smalley 	rc = security_validate_transition(&selinux_state, isec->sid, newsid,
3202aa8e712cSStephen Smalley 					  sid, isec->sclass);
32031da177e4SLinus Torvalds 	if (rc)
32041da177e4SLinus Torvalds 		return rc;
32051da177e4SLinus Torvalds 
32066b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
32076b6bc620SStephen Smalley 			    newsid,
32081da177e4SLinus Torvalds 			    sbsec->sid,
32091da177e4SLinus Torvalds 			    SECCLASS_FILESYSTEM,
32101da177e4SLinus Torvalds 			    FILESYSTEM__ASSOCIATE,
32111da177e4SLinus Torvalds 			    &ad);
32121da177e4SLinus Torvalds }
32131da177e4SLinus Torvalds 
32148f0cfa52SDavid Howells static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
32158f0cfa52SDavid Howells 					const void *value, size_t size,
32168f0cfa52SDavid Howells 					int flags)
32171da177e4SLinus Torvalds {
3218c6f493d6SDavid Howells 	struct inode *inode = d_backing_inode(dentry);
321920cdef8dSPaul Moore 	struct inode_security_struct *isec;
32201da177e4SLinus Torvalds 	u32 newsid;
32211da177e4SLinus Torvalds 	int rc;
32221da177e4SLinus Torvalds 
32231da177e4SLinus Torvalds 	if (strcmp(name, XATTR_NAME_SELINUX)) {
32241da177e4SLinus Torvalds 		/* Not an attribute we recognize, so nothing to do. */
32251da177e4SLinus Torvalds 		return;
32261da177e4SLinus Torvalds 	}
32271da177e4SLinus Torvalds 
3228aa8e712cSStephen Smalley 	rc = security_context_to_sid_force(&selinux_state, value, size,
3229aa8e712cSStephen Smalley 					   &newsid);
32301da177e4SLinus Torvalds 	if (rc) {
3231c103a91eSpeter enderborg 		pr_err("SELinux:  unable to map context to SID"
323212b29f34SStephen Smalley 		       "for (%s, %lu), rc=%d\n",
323312b29f34SStephen Smalley 		       inode->i_sb->s_id, inode->i_ino, -rc);
32341da177e4SLinus Torvalds 		return;
32351da177e4SLinus Torvalds 	}
32361da177e4SLinus Torvalds 
323720cdef8dSPaul Moore 	isec = backing_inode_security(dentry);
32389287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
3239aa9c2669SDavid Quigley 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
32401da177e4SLinus Torvalds 	isec->sid = newsid;
32416f3be9f5SAndreas Gruenbacher 	isec->initialized = LABEL_INITIALIZED;
32429287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
3243aa9c2669SDavid Quigley 
32441da177e4SLinus Torvalds 	return;
32451da177e4SLinus Torvalds }
32461da177e4SLinus Torvalds 
32478f0cfa52SDavid Howells static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
32481da177e4SLinus Torvalds {
324988e67f3bSDavid Howells 	const struct cred *cred = current_cred();
325088e67f3bSDavid Howells 
32512875fa00SEric Paris 	return dentry_has_perm(cred, dentry, FILE__GETATTR);
32521da177e4SLinus Torvalds }
32531da177e4SLinus Torvalds 
32541da177e4SLinus Torvalds static int selinux_inode_listxattr(struct dentry *dentry)
32551da177e4SLinus Torvalds {
325688e67f3bSDavid Howells 	const struct cred *cred = current_cred();
325788e67f3bSDavid Howells 
32582875fa00SEric Paris 	return dentry_has_perm(cred, dentry, FILE__GETATTR);
32591da177e4SLinus Torvalds }
32601da177e4SLinus Torvalds 
32618f0cfa52SDavid Howells static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
32621da177e4SLinus Torvalds {
32636b240306SEric W. Biederman 	if (strcmp(name, XATTR_NAME_SELINUX)) {
32646b240306SEric W. Biederman 		int rc = cap_inode_removexattr(dentry, name);
32656b240306SEric W. Biederman 		if (rc)
32666b240306SEric W. Biederman 			return rc;
32676b240306SEric W. Biederman 
32686b240306SEric W. Biederman 		/* Not an attribute we recognize, so just check the
32696b240306SEric W. Biederman 		   ordinary setattr permission. */
32706b240306SEric W. Biederman 		return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
32716b240306SEric W. Biederman 	}
32721da177e4SLinus Torvalds 
32731da177e4SLinus Torvalds 	/* No one is allowed to remove a SELinux security label.
32741da177e4SLinus Torvalds 	   You can change the label, but all data must be labeled. */
32751da177e4SLinus Torvalds 	return -EACCES;
32761da177e4SLinus Torvalds }
32771da177e4SLinus Torvalds 
3278d381d8a9SJames Morris /*
3279abc69bb6SStephen Smalley  * Copy the inode security context value to the user.
3280d381d8a9SJames Morris  *
3281d381d8a9SJames Morris  * Permission check is handled by selinux_inode_getxattr hook.
3282d381d8a9SJames Morris  */
3283ea861dfdSAndreas Gruenbacher static int selinux_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc)
32841da177e4SLinus Torvalds {
328542492594SDavid P. Quigley 	u32 size;
328642492594SDavid P. Quigley 	int error;
328742492594SDavid P. Quigley 	char *context = NULL;
328820cdef8dSPaul Moore 	struct inode_security_struct *isec;
32891da177e4SLinus Torvalds 
32908c8570fbSDustin Kirkland 	if (strcmp(name, XATTR_SELINUX_SUFFIX))
32918c8570fbSDustin Kirkland 		return -EOPNOTSUPP;
32921da177e4SLinus Torvalds 
3293abc69bb6SStephen Smalley 	/*
3294abc69bb6SStephen Smalley 	 * If the caller has CAP_MAC_ADMIN, then get the raw context
3295abc69bb6SStephen Smalley 	 * value even if it is not defined by current policy; otherwise,
3296abc69bb6SStephen Smalley 	 * use the in-core value under current policy.
3297abc69bb6SStephen Smalley 	 * Use the non-auditing forms of the permission checks since
3298abc69bb6SStephen Smalley 	 * getxattr may be called by unprivileged processes commonly
3299abc69bb6SStephen Smalley 	 * and lack of permission just means that we fall back to the
3300abc69bb6SStephen Smalley 	 * in-core context value, not a denial.
3301abc69bb6SStephen Smalley 	 */
330220cdef8dSPaul Moore 	isec = inode_security(inode);
3303db59000aSStephen Smalley 	if (has_cap_mac_admin(false))
3304aa8e712cSStephen Smalley 		error = security_sid_to_context_force(&selinux_state,
3305aa8e712cSStephen Smalley 						      isec->sid, &context,
3306abc69bb6SStephen Smalley 						      &size);
3307abc69bb6SStephen Smalley 	else
3308aa8e712cSStephen Smalley 		error = security_sid_to_context(&selinux_state, isec->sid,
3309aa8e712cSStephen Smalley 						&context, &size);
331042492594SDavid P. Quigley 	if (error)
331142492594SDavid P. Quigley 		return error;
331242492594SDavid P. Quigley 	error = size;
331342492594SDavid P. Quigley 	if (alloc) {
331442492594SDavid P. Quigley 		*buffer = context;
331542492594SDavid P. Quigley 		goto out_nofree;
331642492594SDavid P. Quigley 	}
331742492594SDavid P. Quigley 	kfree(context);
331842492594SDavid P. Quigley out_nofree:
331942492594SDavid P. Quigley 	return error;
33201da177e4SLinus Torvalds }
33211da177e4SLinus Torvalds 
33221da177e4SLinus Torvalds static int selinux_inode_setsecurity(struct inode *inode, const char *name,
33231da177e4SLinus Torvalds 				     const void *value, size_t size, int flags)
33241da177e4SLinus Torvalds {
33252c97165bSPaul Moore 	struct inode_security_struct *isec = inode_security_novalidate(inode);
332653e0c2aaSOndrej Mosnacek 	struct superblock_security_struct *sbsec = inode->i_sb->s_security;
33271da177e4SLinus Torvalds 	u32 newsid;
33281da177e4SLinus Torvalds 	int rc;
33291da177e4SLinus Torvalds 
33301da177e4SLinus Torvalds 	if (strcmp(name, XATTR_SELINUX_SUFFIX))
33311da177e4SLinus Torvalds 		return -EOPNOTSUPP;
33321da177e4SLinus Torvalds 
333353e0c2aaSOndrej Mosnacek 	if (!(sbsec->flags & SBLABEL_MNT))
333453e0c2aaSOndrej Mosnacek 		return -EOPNOTSUPP;
333553e0c2aaSOndrej Mosnacek 
33361da177e4SLinus Torvalds 	if (!value || !size)
33371da177e4SLinus Torvalds 		return -EACCES;
33381da177e4SLinus Torvalds 
3339aa8e712cSStephen Smalley 	rc = security_context_to_sid(&selinux_state, value, size, &newsid,
3340aa8e712cSStephen Smalley 				     GFP_KERNEL);
33411da177e4SLinus Torvalds 	if (rc)
33421da177e4SLinus Torvalds 		return rc;
33431da177e4SLinus Torvalds 
33449287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
3345aa9c2669SDavid Quigley 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
33461da177e4SLinus Torvalds 	isec->sid = newsid;
33476f3be9f5SAndreas Gruenbacher 	isec->initialized = LABEL_INITIALIZED;
33489287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
33491da177e4SLinus Torvalds 	return 0;
33501da177e4SLinus Torvalds }
33511da177e4SLinus Torvalds 
33521da177e4SLinus Torvalds static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
33531da177e4SLinus Torvalds {
33541da177e4SLinus Torvalds 	const int len = sizeof(XATTR_NAME_SELINUX);
33551da177e4SLinus Torvalds 	if (buffer && len <= buffer_size)
33561da177e4SLinus Torvalds 		memcpy(buffer, XATTR_NAME_SELINUX, len);
33571da177e4SLinus Torvalds 	return len;
33581da177e4SLinus Torvalds }
33591da177e4SLinus Torvalds 
3360d6335d77SAndreas Gruenbacher static void selinux_inode_getsecid(struct inode *inode, u32 *secid)
3361713a04aeSAhmed S. Darwish {
3362e817c2f3SAndreas Gruenbacher 	struct inode_security_struct *isec = inode_security_novalidate(inode);
3363713a04aeSAhmed S. Darwish 	*secid = isec->sid;
3364713a04aeSAhmed S. Darwish }
3365713a04aeSAhmed S. Darwish 
336656909eb3SVivek Goyal static int selinux_inode_copy_up(struct dentry *src, struct cred **new)
336756909eb3SVivek Goyal {
336856909eb3SVivek Goyal 	u32 sid;
336956909eb3SVivek Goyal 	struct task_security_struct *tsec;
337056909eb3SVivek Goyal 	struct cred *new_creds = *new;
337156909eb3SVivek Goyal 
337256909eb3SVivek Goyal 	if (new_creds == NULL) {
337356909eb3SVivek Goyal 		new_creds = prepare_creds();
337456909eb3SVivek Goyal 		if (!new_creds)
337556909eb3SVivek Goyal 			return -ENOMEM;
337656909eb3SVivek Goyal 	}
337756909eb3SVivek Goyal 
33780c6cfa62SCasey Schaufler 	tsec = selinux_cred(new_creds);
337956909eb3SVivek Goyal 	/* Get label from overlay inode and set it in create_sid */
338056909eb3SVivek Goyal 	selinux_inode_getsecid(d_inode(src), &sid);
338156909eb3SVivek Goyal 	tsec->create_sid = sid;
338256909eb3SVivek Goyal 	*new = new_creds;
338356909eb3SVivek Goyal 	return 0;
338456909eb3SVivek Goyal }
338556909eb3SVivek Goyal 
338619472b69SVivek Goyal static int selinux_inode_copy_up_xattr(const char *name)
338719472b69SVivek Goyal {
338819472b69SVivek Goyal 	/* The copy_up hook above sets the initial context on an inode, but we
338919472b69SVivek Goyal 	 * don't then want to overwrite it by blindly copying all the lower
339019472b69SVivek Goyal 	 * xattrs up.  Instead, we have to filter out SELinux-related xattrs.
339119472b69SVivek Goyal 	 */
339219472b69SVivek Goyal 	if (strcmp(name, XATTR_NAME_SELINUX) == 0)
339319472b69SVivek Goyal 		return 1; /* Discard */
339419472b69SVivek Goyal 	/*
339519472b69SVivek Goyal 	 * Any other attribute apart from SELINUX is not claimed, supported
339619472b69SVivek Goyal 	 * by selinux.
339719472b69SVivek Goyal 	 */
339819472b69SVivek Goyal 	return -EOPNOTSUPP;
339919472b69SVivek Goyal }
340019472b69SVivek Goyal 
3401ec882da5SOndrej Mosnacek /* kernfs node operations */
3402ec882da5SOndrej Mosnacek 
3403c72c4cdeSYueHaibing static int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
3404ec882da5SOndrej Mosnacek 					struct kernfs_node *kn)
3405ec882da5SOndrej Mosnacek {
3406ec882da5SOndrej Mosnacek 	const struct task_security_struct *tsec = current_security();
3407ec882da5SOndrej Mosnacek 	u32 parent_sid, newsid, clen;
3408ec882da5SOndrej Mosnacek 	int rc;
3409ec882da5SOndrej Mosnacek 	char *context;
3410ec882da5SOndrej Mosnacek 
34111537ad15SOndrej Mosnacek 	rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, NULL, 0);
3412ec882da5SOndrej Mosnacek 	if (rc == -ENODATA)
3413ec882da5SOndrej Mosnacek 		return 0;
3414ec882da5SOndrej Mosnacek 	else if (rc < 0)
3415ec882da5SOndrej Mosnacek 		return rc;
3416ec882da5SOndrej Mosnacek 
3417ec882da5SOndrej Mosnacek 	clen = (u32)rc;
3418ec882da5SOndrej Mosnacek 	context = kmalloc(clen, GFP_KERNEL);
3419ec882da5SOndrej Mosnacek 	if (!context)
3420ec882da5SOndrej Mosnacek 		return -ENOMEM;
3421ec882da5SOndrej Mosnacek 
34221537ad15SOndrej Mosnacek 	rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, context, clen);
3423ec882da5SOndrej Mosnacek 	if (rc < 0) {
3424ec882da5SOndrej Mosnacek 		kfree(context);
3425ec882da5SOndrej Mosnacek 		return rc;
3426ec882da5SOndrej Mosnacek 	}
3427ec882da5SOndrej Mosnacek 
3428ec882da5SOndrej Mosnacek 	rc = security_context_to_sid(&selinux_state, context, clen, &parent_sid,
3429ec882da5SOndrej Mosnacek 				     GFP_KERNEL);
3430ec882da5SOndrej Mosnacek 	kfree(context);
3431ec882da5SOndrej Mosnacek 	if (rc)
3432ec882da5SOndrej Mosnacek 		return rc;
3433ec882da5SOndrej Mosnacek 
3434ec882da5SOndrej Mosnacek 	if (tsec->create_sid) {
3435ec882da5SOndrej Mosnacek 		newsid = tsec->create_sid;
3436ec882da5SOndrej Mosnacek 	} else {
3437ec882da5SOndrej Mosnacek 		u16 secclass = inode_mode_to_security_class(kn->mode);
3438ec882da5SOndrej Mosnacek 		struct qstr q;
3439ec882da5SOndrej Mosnacek 
3440ec882da5SOndrej Mosnacek 		q.name = kn->name;
3441ec882da5SOndrej Mosnacek 		q.hash_len = hashlen_string(kn_dir, kn->name);
3442ec882da5SOndrej Mosnacek 
3443ec882da5SOndrej Mosnacek 		rc = security_transition_sid(&selinux_state, tsec->sid,
3444ec882da5SOndrej Mosnacek 					     parent_sid, secclass, &q,
3445ec882da5SOndrej Mosnacek 					     &newsid);
3446ec882da5SOndrej Mosnacek 		if (rc)
3447ec882da5SOndrej Mosnacek 			return rc;
3448ec882da5SOndrej Mosnacek 	}
3449ec882da5SOndrej Mosnacek 
3450ec882da5SOndrej Mosnacek 	rc = security_sid_to_context_force(&selinux_state, newsid,
3451ec882da5SOndrej Mosnacek 					   &context, &clen);
3452ec882da5SOndrej Mosnacek 	if (rc)
3453ec882da5SOndrej Mosnacek 		return rc;
3454ec882da5SOndrej Mosnacek 
34551537ad15SOndrej Mosnacek 	rc = kernfs_xattr_set(kn, XATTR_NAME_SELINUX, context, clen,
3456ec882da5SOndrej Mosnacek 			      XATTR_CREATE);
3457ec882da5SOndrej Mosnacek 	kfree(context);
3458ec882da5SOndrej Mosnacek 	return rc;
3459ec882da5SOndrej Mosnacek }
3460ec882da5SOndrej Mosnacek 
3461ec882da5SOndrej Mosnacek 
34621da177e4SLinus Torvalds /* file security operations */
34631da177e4SLinus Torvalds 
3464788e7dd4SYuichi Nakamura static int selinux_revalidate_file_permission(struct file *file, int mask)
34651da177e4SLinus Torvalds {
346688e67f3bSDavid Howells 	const struct cred *cred = current_cred();
3467496ad9aaSAl Viro 	struct inode *inode = file_inode(file);
34681da177e4SLinus Torvalds 
34691da177e4SLinus Torvalds 	/* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
34701da177e4SLinus Torvalds 	if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
34711da177e4SLinus Torvalds 		mask |= MAY_APPEND;
34721da177e4SLinus Torvalds 
3473389fb800SPaul Moore 	return file_has_perm(cred, file,
34741da177e4SLinus Torvalds 			     file_mask_to_av(inode->i_mode, mask));
34751da177e4SLinus Torvalds }
34761da177e4SLinus Torvalds 
3477788e7dd4SYuichi Nakamura static int selinux_file_permission(struct file *file, int mask)
3478788e7dd4SYuichi Nakamura {
3479496ad9aaSAl Viro 	struct inode *inode = file_inode(file);
3480bb6c6b02SCasey Schaufler 	struct file_security_struct *fsec = selinux_file(file);
3481b197367eSAndreas Gruenbacher 	struct inode_security_struct *isec;
348220dda18bSStephen Smalley 	u32 sid = current_sid();
348320dda18bSStephen Smalley 
3484389fb800SPaul Moore 	if (!mask)
3485788e7dd4SYuichi Nakamura 		/* No permission to check.  Existence test. */
3486788e7dd4SYuichi Nakamura 		return 0;
3487788e7dd4SYuichi Nakamura 
3488b197367eSAndreas Gruenbacher 	isec = inode_security(inode);
348920dda18bSStephen Smalley 	if (sid == fsec->sid && fsec->isid == isec->sid &&
34906b6bc620SStephen Smalley 	    fsec->pseqno == avc_policy_seqno(&selinux_state))
349183d49856SEric Paris 		/* No change since file_open check. */
349220dda18bSStephen Smalley 		return 0;
349320dda18bSStephen Smalley 
3494788e7dd4SYuichi Nakamura 	return selinux_revalidate_file_permission(file, mask);
3495788e7dd4SYuichi Nakamura }
3496788e7dd4SYuichi Nakamura 
34971da177e4SLinus Torvalds static int selinux_file_alloc_security(struct file *file)
34981da177e4SLinus Torvalds {
34991da177e4SLinus Torvalds 	return file_alloc_security(file);
35001da177e4SLinus Torvalds }
35011da177e4SLinus Torvalds 
3502fa1aa143SJeff Vander Stoep /*
3503fa1aa143SJeff Vander Stoep  * Check whether a task has the ioctl permission and cmd
3504fa1aa143SJeff Vander Stoep  * operation to an inode.
3505fa1aa143SJeff Vander Stoep  */
35061d2a168aSGeliang Tang static int ioctl_has_perm(const struct cred *cred, struct file *file,
3507fa1aa143SJeff Vander Stoep 		u32 requested, u16 cmd)
3508fa1aa143SJeff Vander Stoep {
3509fa1aa143SJeff Vander Stoep 	struct common_audit_data ad;
3510bb6c6b02SCasey Schaufler 	struct file_security_struct *fsec = selinux_file(file);
3511fa1aa143SJeff Vander Stoep 	struct inode *inode = file_inode(file);
351220cdef8dSPaul Moore 	struct inode_security_struct *isec;
3513fa1aa143SJeff Vander Stoep 	struct lsm_ioctlop_audit ioctl;
3514fa1aa143SJeff Vander Stoep 	u32 ssid = cred_sid(cred);
3515fa1aa143SJeff Vander Stoep 	int rc;
3516fa1aa143SJeff Vander Stoep 	u8 driver = cmd >> 8;
3517fa1aa143SJeff Vander Stoep 	u8 xperm = cmd & 0xff;
3518fa1aa143SJeff Vander Stoep 
3519fa1aa143SJeff Vander Stoep 	ad.type = LSM_AUDIT_DATA_IOCTL_OP;
3520fa1aa143SJeff Vander Stoep 	ad.u.op = &ioctl;
3521fa1aa143SJeff Vander Stoep 	ad.u.op->cmd = cmd;
3522fa1aa143SJeff Vander Stoep 	ad.u.op->path = file->f_path;
3523fa1aa143SJeff Vander Stoep 
3524fa1aa143SJeff Vander Stoep 	if (ssid != fsec->sid) {
35256b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
35266b6bc620SStephen Smalley 				  ssid, fsec->sid,
3527fa1aa143SJeff Vander Stoep 				SECCLASS_FD,
3528fa1aa143SJeff Vander Stoep 				FD__USE,
3529fa1aa143SJeff Vander Stoep 				&ad);
3530fa1aa143SJeff Vander Stoep 		if (rc)
3531fa1aa143SJeff Vander Stoep 			goto out;
3532fa1aa143SJeff Vander Stoep 	}
3533fa1aa143SJeff Vander Stoep 
3534fa1aa143SJeff Vander Stoep 	if (unlikely(IS_PRIVATE(inode)))
3535fa1aa143SJeff Vander Stoep 		return 0;
3536fa1aa143SJeff Vander Stoep 
353720cdef8dSPaul Moore 	isec = inode_security(inode);
35386b6bc620SStephen Smalley 	rc = avc_has_extended_perms(&selinux_state,
35396b6bc620SStephen Smalley 				    ssid, isec->sid, isec->sclass,
3540fa1aa143SJeff Vander Stoep 				    requested, driver, xperm, &ad);
3541fa1aa143SJeff Vander Stoep out:
3542fa1aa143SJeff Vander Stoep 	return rc;
3543fa1aa143SJeff Vander Stoep }
3544fa1aa143SJeff Vander Stoep 
35451da177e4SLinus Torvalds static int selinux_file_ioctl(struct file *file, unsigned int cmd,
35461da177e4SLinus Torvalds 			      unsigned long arg)
35471da177e4SLinus Torvalds {
354888e67f3bSDavid Howells 	const struct cred *cred = current_cred();
35490b24dcb7SEric Paris 	int error = 0;
35501da177e4SLinus Torvalds 
35510b24dcb7SEric Paris 	switch (cmd) {
35520b24dcb7SEric Paris 	case FIONREAD:
35530b24dcb7SEric Paris 	/* fall through */
35540b24dcb7SEric Paris 	case FIBMAP:
35550b24dcb7SEric Paris 	/* fall through */
35560b24dcb7SEric Paris 	case FIGETBSZ:
35570b24dcb7SEric Paris 	/* fall through */
35582f99c369SAl Viro 	case FS_IOC_GETFLAGS:
35590b24dcb7SEric Paris 	/* fall through */
35602f99c369SAl Viro 	case FS_IOC_GETVERSION:
35610b24dcb7SEric Paris 		error = file_has_perm(cred, file, FILE__GETATTR);
35620b24dcb7SEric Paris 		break;
35631da177e4SLinus Torvalds 
35642f99c369SAl Viro 	case FS_IOC_SETFLAGS:
35650b24dcb7SEric Paris 	/* fall through */
35662f99c369SAl Viro 	case FS_IOC_SETVERSION:
35670b24dcb7SEric Paris 		error = file_has_perm(cred, file, FILE__SETATTR);
35680b24dcb7SEric Paris 		break;
35690b24dcb7SEric Paris 
35700b24dcb7SEric Paris 	/* sys_ioctl() checks */
35710b24dcb7SEric Paris 	case FIONBIO:
35720b24dcb7SEric Paris 	/* fall through */
35730b24dcb7SEric Paris 	case FIOASYNC:
35740b24dcb7SEric Paris 		error = file_has_perm(cred, file, 0);
35750b24dcb7SEric Paris 		break;
35760b24dcb7SEric Paris 
35770b24dcb7SEric Paris 	case KDSKBENT:
35780b24dcb7SEric Paris 	case KDSKBSENT:
35796a9de491SEric Paris 		error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
3580c1a85a00SMicah Morton 					    CAP_OPT_NONE, true);
35810b24dcb7SEric Paris 		break;
35820b24dcb7SEric Paris 
35830b24dcb7SEric Paris 	/* default case assumes that the command will go
35840b24dcb7SEric Paris 	 * to the file's ioctl() function.
35850b24dcb7SEric Paris 	 */
35860b24dcb7SEric Paris 	default:
3587fa1aa143SJeff Vander Stoep 		error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
35880b24dcb7SEric Paris 	}
35890b24dcb7SEric Paris 	return error;
35901da177e4SLinus Torvalds }
35911da177e4SLinus Torvalds 
3592fcaaade1SStephen Smalley static int default_noexec;
3593fcaaade1SStephen Smalley 
35941da177e4SLinus Torvalds static int file_map_prot_check(struct file *file, unsigned long prot, int shared)
35951da177e4SLinus Torvalds {
359688e67f3bSDavid Howells 	const struct cred *cred = current_cred();
3597be0554c9SStephen Smalley 	u32 sid = cred_sid(cred);
3598d84f4f99SDavid Howells 	int rc = 0;
359988e67f3bSDavid Howells 
3600fcaaade1SStephen Smalley 	if (default_noexec &&
3601892e8cacSStephen Smalley 	    (prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) ||
3602892e8cacSStephen Smalley 				   (!shared && (prot & PROT_WRITE)))) {
36031da177e4SLinus Torvalds 		/*
36041da177e4SLinus Torvalds 		 * We are making executable an anonymous mapping or a
36051da177e4SLinus Torvalds 		 * private file mapping that will also be writable.
36061da177e4SLinus Torvalds 		 * This has an additional check.
36071da177e4SLinus Torvalds 		 */
36086b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
36096b6bc620SStephen Smalley 				  sid, sid, SECCLASS_PROCESS,
3610be0554c9SStephen Smalley 				  PROCESS__EXECMEM, NULL);
36111da177e4SLinus Torvalds 		if (rc)
3612d84f4f99SDavid Howells 			goto error;
36131da177e4SLinus Torvalds 	}
36141da177e4SLinus Torvalds 
36151da177e4SLinus Torvalds 	if (file) {
36161da177e4SLinus Torvalds 		/* read access is always possible with a mapping */
36171da177e4SLinus Torvalds 		u32 av = FILE__READ;
36181da177e4SLinus Torvalds 
36191da177e4SLinus Torvalds 		/* write access only matters if the mapping is shared */
36201da177e4SLinus Torvalds 		if (shared && (prot & PROT_WRITE))
36211da177e4SLinus Torvalds 			av |= FILE__WRITE;
36221da177e4SLinus Torvalds 
36231da177e4SLinus Torvalds 		if (prot & PROT_EXEC)
36241da177e4SLinus Torvalds 			av |= FILE__EXECUTE;
36251da177e4SLinus Torvalds 
362688e67f3bSDavid Howells 		return file_has_perm(cred, file, av);
36271da177e4SLinus Torvalds 	}
3628d84f4f99SDavid Howells 
3629d84f4f99SDavid Howells error:
3630d84f4f99SDavid Howells 	return rc;
36311da177e4SLinus Torvalds }
36321da177e4SLinus Torvalds 
3633e5467859SAl Viro static int selinux_mmap_addr(unsigned long addr)
36341da177e4SLinus Torvalds {
3635b1d9e6b0SCasey Schaufler 	int rc = 0;
363698883bfdSPaul Moore 
363798883bfdSPaul Moore 	if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
363898883bfdSPaul Moore 		u32 sid = current_sid();
36396b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
36406b6bc620SStephen Smalley 				  sid, sid, SECCLASS_MEMPROTECT,
364198883bfdSPaul Moore 				  MEMPROTECT__MMAP_ZERO, NULL);
364298883bfdSPaul Moore 	}
364398883bfdSPaul Moore 
364498883bfdSPaul Moore 	return rc;
3645e5467859SAl Viro }
36461da177e4SLinus Torvalds 
3647e5467859SAl Viro static int selinux_mmap_file(struct file *file, unsigned long reqprot,
3648e5467859SAl Viro 			     unsigned long prot, unsigned long flags)
3649e5467859SAl Viro {
36503ba4bf5fSStephen Smalley 	struct common_audit_data ad;
36513ba4bf5fSStephen Smalley 	int rc;
36523ba4bf5fSStephen Smalley 
36533ba4bf5fSStephen Smalley 	if (file) {
36543ba4bf5fSStephen Smalley 		ad.type = LSM_AUDIT_DATA_FILE;
36553ba4bf5fSStephen Smalley 		ad.u.file = file;
36563ba4bf5fSStephen Smalley 		rc = inode_has_perm(current_cred(), file_inode(file),
36573ba4bf5fSStephen Smalley 				    FILE__MAP, &ad);
36583ba4bf5fSStephen Smalley 		if (rc)
36593ba4bf5fSStephen Smalley 			return rc;
36603ba4bf5fSStephen Smalley 	}
36613ba4bf5fSStephen Smalley 
3662aa8e712cSStephen Smalley 	if (selinux_state.checkreqprot)
36631da177e4SLinus Torvalds 		prot = reqprot;
36641da177e4SLinus Torvalds 
36651da177e4SLinus Torvalds 	return file_map_prot_check(file, prot,
36661da177e4SLinus Torvalds 				   (flags & MAP_TYPE) == MAP_SHARED);
36671da177e4SLinus Torvalds }
36681da177e4SLinus Torvalds 
36691da177e4SLinus Torvalds static int selinux_file_mprotect(struct vm_area_struct *vma,
36701da177e4SLinus Torvalds 				 unsigned long reqprot,
36711da177e4SLinus Torvalds 				 unsigned long prot)
36721da177e4SLinus Torvalds {
367388e67f3bSDavid Howells 	const struct cred *cred = current_cred();
3674be0554c9SStephen Smalley 	u32 sid = cred_sid(cred);
36751da177e4SLinus Torvalds 
3676aa8e712cSStephen Smalley 	if (selinux_state.checkreqprot)
36771da177e4SLinus Torvalds 		prot = reqprot;
36781da177e4SLinus Torvalds 
3679fcaaade1SStephen Smalley 	if (default_noexec &&
3680fcaaade1SStephen Smalley 	    (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
3681d541bbeeSJames Morris 		int rc = 0;
3682db4c9641SStephen Smalley 		if (vma->vm_start >= vma->vm_mm->start_brk &&
3683db4c9641SStephen Smalley 		    vma->vm_end <= vma->vm_mm->brk) {
36846b6bc620SStephen Smalley 			rc = avc_has_perm(&selinux_state,
36856b6bc620SStephen Smalley 					  sid, sid, SECCLASS_PROCESS,
3686be0554c9SStephen Smalley 					  PROCESS__EXECHEAP, NULL);
3687db4c9641SStephen Smalley 		} else if (!vma->vm_file &&
3688c2316dbfSStephen Smalley 			   ((vma->vm_start <= vma->vm_mm->start_stack &&
3689c2316dbfSStephen Smalley 			     vma->vm_end >= vma->vm_mm->start_stack) ||
3690d17af505SAndy Lutomirski 			    vma_is_stack_for_current(vma))) {
36916b6bc620SStephen Smalley 			rc = avc_has_perm(&selinux_state,
36926b6bc620SStephen Smalley 					  sid, sid, SECCLASS_PROCESS,
3693be0554c9SStephen Smalley 					  PROCESS__EXECSTACK, NULL);
3694db4c9641SStephen Smalley 		} else if (vma->vm_file && vma->anon_vma) {
3695db4c9641SStephen Smalley 			/*
3696db4c9641SStephen Smalley 			 * We are making executable a file mapping that has
3697db4c9641SStephen Smalley 			 * had some COW done. Since pages might have been
3698db4c9641SStephen Smalley 			 * written, check ability to execute the possibly
3699db4c9641SStephen Smalley 			 * modified content.  This typically should only
3700db4c9641SStephen Smalley 			 * occur for text relocations.
3701db4c9641SStephen Smalley 			 */
3702d84f4f99SDavid Howells 			rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
3703db4c9641SStephen Smalley 		}
37046b992197SLorenzo Hernandez García-Hierro 		if (rc)
37056b992197SLorenzo Hernandez García-Hierro 			return rc;
37066b992197SLorenzo Hernandez García-Hierro 	}
37071da177e4SLinus Torvalds 
37081da177e4SLinus Torvalds 	return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
37091da177e4SLinus Torvalds }
37101da177e4SLinus Torvalds 
37111da177e4SLinus Torvalds static int selinux_file_lock(struct file *file, unsigned int cmd)
37121da177e4SLinus Torvalds {
371388e67f3bSDavid Howells 	const struct cred *cred = current_cred();
371488e67f3bSDavid Howells 
371588e67f3bSDavid Howells 	return file_has_perm(cred, file, FILE__LOCK);
37161da177e4SLinus Torvalds }
37171da177e4SLinus Torvalds 
37181da177e4SLinus Torvalds static int selinux_file_fcntl(struct file *file, unsigned int cmd,
37191da177e4SLinus Torvalds 			      unsigned long arg)
37201da177e4SLinus Torvalds {
372188e67f3bSDavid Howells 	const struct cred *cred = current_cred();
37221da177e4SLinus Torvalds 	int err = 0;
37231da177e4SLinus Torvalds 
37241da177e4SLinus Torvalds 	switch (cmd) {
37251da177e4SLinus Torvalds 	case F_SETFL:
37261da177e4SLinus Torvalds 		if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
372788e67f3bSDavid Howells 			err = file_has_perm(cred, file, FILE__WRITE);
37281da177e4SLinus Torvalds 			break;
37291da177e4SLinus Torvalds 		}
37301da177e4SLinus Torvalds 		/* fall through */
37311da177e4SLinus Torvalds 	case F_SETOWN:
37321da177e4SLinus Torvalds 	case F_SETSIG:
37331da177e4SLinus Torvalds 	case F_GETFL:
37341da177e4SLinus Torvalds 	case F_GETOWN:
37351da177e4SLinus Torvalds 	case F_GETSIG:
37361d151c33SCyrill Gorcunov 	case F_GETOWNER_UIDS:
37371da177e4SLinus Torvalds 		/* Just check FD__USE permission */
373888e67f3bSDavid Howells 		err = file_has_perm(cred, file, 0);
37391da177e4SLinus Torvalds 		break;
37401da177e4SLinus Torvalds 	case F_GETLK:
37411da177e4SLinus Torvalds 	case F_SETLK:
37421da177e4SLinus Torvalds 	case F_SETLKW:
37430d3f7a2dSJeff Layton 	case F_OFD_GETLK:
37440d3f7a2dSJeff Layton 	case F_OFD_SETLK:
37450d3f7a2dSJeff Layton 	case F_OFD_SETLKW:
37461da177e4SLinus Torvalds #if BITS_PER_LONG == 32
37471da177e4SLinus Torvalds 	case F_GETLK64:
37481da177e4SLinus Torvalds 	case F_SETLK64:
37491da177e4SLinus Torvalds 	case F_SETLKW64:
37501da177e4SLinus Torvalds #endif
375188e67f3bSDavid Howells 		err = file_has_perm(cred, file, FILE__LOCK);
37521da177e4SLinus Torvalds 		break;
37531da177e4SLinus Torvalds 	}
37541da177e4SLinus Torvalds 
37551da177e4SLinus Torvalds 	return err;
37561da177e4SLinus Torvalds }
37571da177e4SLinus Torvalds 
3758e0b93eddSJeff Layton static void selinux_file_set_fowner(struct file *file)
37591da177e4SLinus Torvalds {
37601da177e4SLinus Torvalds 	struct file_security_struct *fsec;
37611da177e4SLinus Torvalds 
3762bb6c6b02SCasey Schaufler 	fsec = selinux_file(file);
3763275bb41eSDavid Howells 	fsec->fown_sid = current_sid();
37641da177e4SLinus Torvalds }
37651da177e4SLinus Torvalds 
37661da177e4SLinus Torvalds static int selinux_file_send_sigiotask(struct task_struct *tsk,
37671da177e4SLinus Torvalds 				       struct fown_struct *fown, int signum)
37681da177e4SLinus Torvalds {
37691da177e4SLinus Torvalds 	struct file *file;
377065c90bcaSStephen Smalley 	u32 sid = task_sid(tsk);
37711da177e4SLinus Torvalds 	u32 perm;
37721da177e4SLinus Torvalds 	struct file_security_struct *fsec;
37731da177e4SLinus Torvalds 
37741da177e4SLinus Torvalds 	/* struct fown_struct is never outside the context of a struct file */
3775b385a144SRobert P. J. Day 	file = container_of(fown, struct file, f_owner);
37761da177e4SLinus Torvalds 
3777bb6c6b02SCasey Schaufler 	fsec = selinux_file(file);
37781da177e4SLinus Torvalds 
37791da177e4SLinus Torvalds 	if (!signum)
37801da177e4SLinus Torvalds 		perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
37811da177e4SLinus Torvalds 	else
37821da177e4SLinus Torvalds 		perm = signal_to_av(signum);
37831da177e4SLinus Torvalds 
37846b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
37856b6bc620SStephen Smalley 			    fsec->fown_sid, sid,
37861da177e4SLinus Torvalds 			    SECCLASS_PROCESS, perm, NULL);
37871da177e4SLinus Torvalds }
37881da177e4SLinus Torvalds 
37891da177e4SLinus Torvalds static int selinux_file_receive(struct file *file)
37901da177e4SLinus Torvalds {
379188e67f3bSDavid Howells 	const struct cred *cred = current_cred();
379288e67f3bSDavid Howells 
379388e67f3bSDavid Howells 	return file_has_perm(cred, file, file_to_av(file));
37941da177e4SLinus Torvalds }
37951da177e4SLinus Torvalds 
379694817692SAl Viro static int selinux_file_open(struct file *file)
3797788e7dd4SYuichi Nakamura {
3798788e7dd4SYuichi Nakamura 	struct file_security_struct *fsec;
3799788e7dd4SYuichi Nakamura 	struct inode_security_struct *isec;
3800d84f4f99SDavid Howells 
3801bb6c6b02SCasey Schaufler 	fsec = selinux_file(file);
380283da53c5SAndreas Gruenbacher 	isec = inode_security(file_inode(file));
3803788e7dd4SYuichi Nakamura 	/*
3804788e7dd4SYuichi Nakamura 	 * Save inode label and policy sequence number
3805788e7dd4SYuichi Nakamura 	 * at open-time so that selinux_file_permission
3806788e7dd4SYuichi Nakamura 	 * can determine whether revalidation is necessary.
3807788e7dd4SYuichi Nakamura 	 * Task label is already saved in the file security
3808788e7dd4SYuichi Nakamura 	 * struct as its SID.
3809788e7dd4SYuichi Nakamura 	 */
3810788e7dd4SYuichi Nakamura 	fsec->isid = isec->sid;
38116b6bc620SStephen Smalley 	fsec->pseqno = avc_policy_seqno(&selinux_state);
3812788e7dd4SYuichi Nakamura 	/*
3813788e7dd4SYuichi Nakamura 	 * Since the inode label or policy seqno may have changed
3814788e7dd4SYuichi Nakamura 	 * between the selinux_inode_permission check and the saving
3815788e7dd4SYuichi Nakamura 	 * of state above, recheck that access is still permitted.
3816788e7dd4SYuichi Nakamura 	 * Otherwise, access might never be revalidated against the
3817788e7dd4SYuichi Nakamura 	 * new inode label or new policy.
3818788e7dd4SYuichi Nakamura 	 * This check is not redundant - do not remove.
3819788e7dd4SYuichi Nakamura 	 */
382094817692SAl Viro 	return file_path_has_perm(file->f_cred, file, open_file_to_av(file));
3821788e7dd4SYuichi Nakamura }
3822788e7dd4SYuichi Nakamura 
38231da177e4SLinus Torvalds /* task security operations */
38241da177e4SLinus Torvalds 
3825a79be238STetsuo Handa static int selinux_task_alloc(struct task_struct *task,
3826a79be238STetsuo Handa 			      unsigned long clone_flags)
38271da177e4SLinus Torvalds {
3828be0554c9SStephen Smalley 	u32 sid = current_sid();
3829be0554c9SStephen Smalley 
38306b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
38316b6bc620SStephen Smalley 			    sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
38321da177e4SLinus Torvalds }
38331da177e4SLinus Torvalds 
3834f1752eecSDavid Howells /*
3835d84f4f99SDavid Howells  * prepare a new set of credentials for modification
3836d84f4f99SDavid Howells  */
3837d84f4f99SDavid Howells static int selinux_cred_prepare(struct cred *new, const struct cred *old,
3838d84f4f99SDavid Howells 				gfp_t gfp)
3839d84f4f99SDavid Howells {
3840bbd3662aSCasey Schaufler 	const struct task_security_struct *old_tsec = selinux_cred(old);
3841bbd3662aSCasey Schaufler 	struct task_security_struct *tsec = selinux_cred(new);
3842d84f4f99SDavid Howells 
3843bbd3662aSCasey Schaufler 	*tsec = *old_tsec;
3844d84f4f99SDavid Howells 	return 0;
3845d84f4f99SDavid Howells }
3846d84f4f99SDavid Howells 
3847d84f4f99SDavid Howells /*
3848ee18d64cSDavid Howells  * transfer the SELinux data to a blank set of creds
3849ee18d64cSDavid Howells  */
3850ee18d64cSDavid Howells static void selinux_cred_transfer(struct cred *new, const struct cred *old)
3851ee18d64cSDavid Howells {
38520c6cfa62SCasey Schaufler 	const struct task_security_struct *old_tsec = selinux_cred(old);
38530c6cfa62SCasey Schaufler 	struct task_security_struct *tsec = selinux_cred(new);
3854ee18d64cSDavid Howells 
3855ee18d64cSDavid Howells 	*tsec = *old_tsec;
3856ee18d64cSDavid Howells }
3857ee18d64cSDavid Howells 
38583ec30113SMatthew Garrett static void selinux_cred_getsecid(const struct cred *c, u32 *secid)
38593ec30113SMatthew Garrett {
38603ec30113SMatthew Garrett 	*secid = cred_sid(c);
38613ec30113SMatthew Garrett }
38623ec30113SMatthew Garrett 
3863ee18d64cSDavid Howells /*
38643a3b7ce9SDavid Howells  * set the security data for a kernel service
38653a3b7ce9SDavid Howells  * - all the creation contexts are set to unlabelled
38663a3b7ce9SDavid Howells  */
38673a3b7ce9SDavid Howells static int selinux_kernel_act_as(struct cred *new, u32 secid)
38683a3b7ce9SDavid Howells {
38690c6cfa62SCasey Schaufler 	struct task_security_struct *tsec = selinux_cred(new);
38703a3b7ce9SDavid Howells 	u32 sid = current_sid();
38713a3b7ce9SDavid Howells 	int ret;
38723a3b7ce9SDavid Howells 
38736b6bc620SStephen Smalley 	ret = avc_has_perm(&selinux_state,
38746b6bc620SStephen Smalley 			   sid, secid,
38753a3b7ce9SDavid Howells 			   SECCLASS_KERNEL_SERVICE,
38763a3b7ce9SDavid Howells 			   KERNEL_SERVICE__USE_AS_OVERRIDE,
38773a3b7ce9SDavid Howells 			   NULL);
38783a3b7ce9SDavid Howells 	if (ret == 0) {
38793a3b7ce9SDavid Howells 		tsec->sid = secid;
38803a3b7ce9SDavid Howells 		tsec->create_sid = 0;
38813a3b7ce9SDavid Howells 		tsec->keycreate_sid = 0;
38823a3b7ce9SDavid Howells 		tsec->sockcreate_sid = 0;
38833a3b7ce9SDavid Howells 	}
38843a3b7ce9SDavid Howells 	return ret;
38853a3b7ce9SDavid Howells }
38863a3b7ce9SDavid Howells 
38873a3b7ce9SDavid Howells /*
38883a3b7ce9SDavid Howells  * set the file creation context in a security record to the same as the
38893a3b7ce9SDavid Howells  * objective context of the specified inode
38903a3b7ce9SDavid Howells  */
38913a3b7ce9SDavid Howells static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
38923a3b7ce9SDavid Howells {
389383da53c5SAndreas Gruenbacher 	struct inode_security_struct *isec = inode_security(inode);
38940c6cfa62SCasey Schaufler 	struct task_security_struct *tsec = selinux_cred(new);
38953a3b7ce9SDavid Howells 	u32 sid = current_sid();
38963a3b7ce9SDavid Howells 	int ret;
38973a3b7ce9SDavid Howells 
38986b6bc620SStephen Smalley 	ret = avc_has_perm(&selinux_state,
38996b6bc620SStephen Smalley 			   sid, isec->sid,
39003a3b7ce9SDavid Howells 			   SECCLASS_KERNEL_SERVICE,
39013a3b7ce9SDavid Howells 			   KERNEL_SERVICE__CREATE_FILES_AS,
39023a3b7ce9SDavid Howells 			   NULL);
39033a3b7ce9SDavid Howells 
39043a3b7ce9SDavid Howells 	if (ret == 0)
39053a3b7ce9SDavid Howells 		tsec->create_sid = isec->sid;
3906ef57471aSDavid Howells 	return ret;
39073a3b7ce9SDavid Howells }
39083a3b7ce9SDavid Howells 
3909dd8dbf2eSEric Paris static int selinux_kernel_module_request(char *kmod_name)
391025354c4fSEric Paris {
3911dd8dbf2eSEric Paris 	struct common_audit_data ad;
3912dd8dbf2eSEric Paris 
391350c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_KMOD;
3914dd8dbf2eSEric Paris 	ad.u.kmod_name = kmod_name;
3915dd8dbf2eSEric Paris 
39166b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39176b6bc620SStephen Smalley 			    current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
3918dd8dbf2eSEric Paris 			    SYSTEM__MODULE_REQUEST, &ad);
391925354c4fSEric Paris }
392025354c4fSEric Paris 
392161d612eaSJeff Vander Stoep static int selinux_kernel_module_from_file(struct file *file)
392261d612eaSJeff Vander Stoep {
392361d612eaSJeff Vander Stoep 	struct common_audit_data ad;
392461d612eaSJeff Vander Stoep 	struct inode_security_struct *isec;
392561d612eaSJeff Vander Stoep 	struct file_security_struct *fsec;
392661d612eaSJeff Vander Stoep 	u32 sid = current_sid();
392761d612eaSJeff Vander Stoep 	int rc;
392861d612eaSJeff Vander Stoep 
392961d612eaSJeff Vander Stoep 	/* init_module */
393061d612eaSJeff Vander Stoep 	if (file == NULL)
39316b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
39326b6bc620SStephen Smalley 				    sid, sid, SECCLASS_SYSTEM,
393361d612eaSJeff Vander Stoep 					SYSTEM__MODULE_LOAD, NULL);
393461d612eaSJeff Vander Stoep 
393561d612eaSJeff Vander Stoep 	/* finit_module */
393620cdef8dSPaul Moore 
393743af5de7SVivek Goyal 	ad.type = LSM_AUDIT_DATA_FILE;
393843af5de7SVivek Goyal 	ad.u.file = file;
393961d612eaSJeff Vander Stoep 
3940bb6c6b02SCasey Schaufler 	fsec = selinux_file(file);
394161d612eaSJeff Vander Stoep 	if (sid != fsec->sid) {
39426b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
39436b6bc620SStephen Smalley 				  sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
394461d612eaSJeff Vander Stoep 		if (rc)
394561d612eaSJeff Vander Stoep 			return rc;
394661d612eaSJeff Vander Stoep 	}
394761d612eaSJeff Vander Stoep 
394820cdef8dSPaul Moore 	isec = inode_security(file_inode(file));
39496b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39506b6bc620SStephen Smalley 			    sid, isec->sid, SECCLASS_SYSTEM,
395161d612eaSJeff Vander Stoep 				SYSTEM__MODULE_LOAD, &ad);
395261d612eaSJeff Vander Stoep }
395361d612eaSJeff Vander Stoep 
395461d612eaSJeff Vander Stoep static int selinux_kernel_read_file(struct file *file,
395561d612eaSJeff Vander Stoep 				    enum kernel_read_file_id id)
395661d612eaSJeff Vander Stoep {
395761d612eaSJeff Vander Stoep 	int rc = 0;
395861d612eaSJeff Vander Stoep 
395961d612eaSJeff Vander Stoep 	switch (id) {
396061d612eaSJeff Vander Stoep 	case READING_MODULE:
396161d612eaSJeff Vander Stoep 		rc = selinux_kernel_module_from_file(file);
396261d612eaSJeff Vander Stoep 		break;
396361d612eaSJeff Vander Stoep 	default:
396461d612eaSJeff Vander Stoep 		break;
396561d612eaSJeff Vander Stoep 	}
396661d612eaSJeff Vander Stoep 
396761d612eaSJeff Vander Stoep 	return rc;
396861d612eaSJeff Vander Stoep }
396961d612eaSJeff Vander Stoep 
3970c77b8cdfSMimi Zohar static int selinux_kernel_load_data(enum kernel_load_data_id id)
3971c77b8cdfSMimi Zohar {
3972c77b8cdfSMimi Zohar 	int rc = 0;
3973c77b8cdfSMimi Zohar 
3974c77b8cdfSMimi Zohar 	switch (id) {
3975c77b8cdfSMimi Zohar 	case LOADING_MODULE:
3976c77b8cdfSMimi Zohar 		rc = selinux_kernel_module_from_file(NULL);
3977c77b8cdfSMimi Zohar 	default:
3978c77b8cdfSMimi Zohar 		break;
3979c77b8cdfSMimi Zohar 	}
3980c77b8cdfSMimi Zohar 
3981c77b8cdfSMimi Zohar 	return rc;
3982c77b8cdfSMimi Zohar }
3983c77b8cdfSMimi Zohar 
39841da177e4SLinus Torvalds static int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
39851da177e4SLinus Torvalds {
39866b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39876b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
3988be0554c9SStephen Smalley 			    PROCESS__SETPGID, NULL);
39891da177e4SLinus Torvalds }
39901da177e4SLinus Torvalds 
39911da177e4SLinus Torvalds static int selinux_task_getpgid(struct task_struct *p)
39921da177e4SLinus Torvalds {
39936b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
39946b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
3995be0554c9SStephen Smalley 			    PROCESS__GETPGID, NULL);
39961da177e4SLinus Torvalds }
39971da177e4SLinus Torvalds 
39981da177e4SLinus Torvalds static int selinux_task_getsid(struct task_struct *p)
39991da177e4SLinus Torvalds {
40006b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40016b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
4002be0554c9SStephen Smalley 			    PROCESS__GETSESSION, NULL);
40031da177e4SLinus Torvalds }
40041da177e4SLinus Torvalds 
4005f9008e4cSDavid Quigley static void selinux_task_getsecid(struct task_struct *p, u32 *secid)
4006f9008e4cSDavid Quigley {
4007275bb41eSDavid Howells 	*secid = task_sid(p);
4008f9008e4cSDavid Quigley }
4009f9008e4cSDavid Quigley 
40101da177e4SLinus Torvalds static int selinux_task_setnice(struct task_struct *p, int nice)
40111da177e4SLinus Torvalds {
40126b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40136b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
4014be0554c9SStephen Smalley 			    PROCESS__SETSCHED, NULL);
40151da177e4SLinus Torvalds }
40161da177e4SLinus Torvalds 
401703e68060SJames Morris static int selinux_task_setioprio(struct task_struct *p, int ioprio)
401803e68060SJames Morris {
40196b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40206b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
4021be0554c9SStephen Smalley 			    PROCESS__SETSCHED, NULL);
402203e68060SJames Morris }
402303e68060SJames Morris 
4024a1836a42SDavid Quigley static int selinux_task_getioprio(struct task_struct *p)
4025a1836a42SDavid Quigley {
40266b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40276b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
4028be0554c9SStephen Smalley 			    PROCESS__GETSCHED, NULL);
4029a1836a42SDavid Quigley }
4030a1836a42SDavid Quigley 
40314298555dSCorentin LABBE static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred,
4032791ec491SStephen Smalley 				unsigned int flags)
4033791ec491SStephen Smalley {
4034791ec491SStephen Smalley 	u32 av = 0;
4035791ec491SStephen Smalley 
403684e6885eSStephen Smalley 	if (!flags)
403784e6885eSStephen Smalley 		return 0;
4038791ec491SStephen Smalley 	if (flags & LSM_PRLIMIT_WRITE)
4039791ec491SStephen Smalley 		av |= PROCESS__SETRLIMIT;
4040791ec491SStephen Smalley 	if (flags & LSM_PRLIMIT_READ)
4041791ec491SStephen Smalley 		av |= PROCESS__GETRLIMIT;
40426b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40436b6bc620SStephen Smalley 			    cred_sid(cred), cred_sid(tcred),
4044791ec491SStephen Smalley 			    SECCLASS_PROCESS, av, NULL);
4045791ec491SStephen Smalley }
4046791ec491SStephen Smalley 
40478fd00b4dSJiri Slaby static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
40488fd00b4dSJiri Slaby 		struct rlimit *new_rlim)
40491da177e4SLinus Torvalds {
40508fd00b4dSJiri Slaby 	struct rlimit *old_rlim = p->signal->rlim + resource;
40511da177e4SLinus Torvalds 
40521da177e4SLinus Torvalds 	/* Control the ability to change the hard limit (whether
40531da177e4SLinus Torvalds 	   lowering or raising it), so that the hard limit can
40541da177e4SLinus Torvalds 	   later be used as a safe reset point for the soft limit
4055d84f4f99SDavid Howells 	   upon context transitions.  See selinux_bprm_committing_creds. */
40561da177e4SLinus Torvalds 	if (old_rlim->rlim_max != new_rlim->rlim_max)
40576b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
40586b6bc620SStephen Smalley 				    current_sid(), task_sid(p),
4059be0554c9SStephen Smalley 				    SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
40601da177e4SLinus Torvalds 
40611da177e4SLinus Torvalds 	return 0;
40621da177e4SLinus Torvalds }
40631da177e4SLinus Torvalds 
4064b0ae1981SKOSAKI Motohiro static int selinux_task_setscheduler(struct task_struct *p)
40651da177e4SLinus Torvalds {
40666b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40676b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
4068be0554c9SStephen Smalley 			    PROCESS__SETSCHED, NULL);
40691da177e4SLinus Torvalds }
40701da177e4SLinus Torvalds 
40711da177e4SLinus Torvalds static int selinux_task_getscheduler(struct task_struct *p)
40721da177e4SLinus Torvalds {
40736b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40746b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
4075be0554c9SStephen Smalley 			    PROCESS__GETSCHED, NULL);
40761da177e4SLinus Torvalds }
40771da177e4SLinus Torvalds 
407835601547SDavid Quigley static int selinux_task_movememory(struct task_struct *p)
407935601547SDavid Quigley {
40806b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
40816b6bc620SStephen Smalley 			    current_sid(), task_sid(p), SECCLASS_PROCESS,
4082be0554c9SStephen Smalley 			    PROCESS__SETSCHED, NULL);
408335601547SDavid Quigley }
408435601547SDavid Quigley 
4085ae7795bcSEric W. Biederman static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
40866b4f3d01SStephen Smalley 				int sig, const struct cred *cred)
40871da177e4SLinus Torvalds {
40886b4f3d01SStephen Smalley 	u32 secid;
40891da177e4SLinus Torvalds 	u32 perm;
40901da177e4SLinus Torvalds 
40911da177e4SLinus Torvalds 	if (!sig)
40921da177e4SLinus Torvalds 		perm = PROCESS__SIGNULL; /* null signal; existence test */
40931da177e4SLinus Torvalds 	else
40941da177e4SLinus Torvalds 		perm = signal_to_av(sig);
40956b4f3d01SStephen Smalley 	if (!cred)
4096be0554c9SStephen Smalley 		secid = current_sid();
40976b4f3d01SStephen Smalley 	else
40986b4f3d01SStephen Smalley 		secid = cred_sid(cred);
40996b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
41006b6bc620SStephen Smalley 			    secid, task_sid(p), SECCLASS_PROCESS, perm, NULL);
41011da177e4SLinus Torvalds }
41021da177e4SLinus Torvalds 
41031da177e4SLinus Torvalds static void selinux_task_to_inode(struct task_struct *p,
41041da177e4SLinus Torvalds 				  struct inode *inode)
41051da177e4SLinus Torvalds {
410680788c22SCasey Schaufler 	struct inode_security_struct *isec = selinux_inode(inode);
4107275bb41eSDavid Howells 	u32 sid = task_sid(p);
41081da177e4SLinus Torvalds 
41099287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
4110db978da8SAndreas Gruenbacher 	isec->sclass = inode_mode_to_security_class(inode->i_mode);
4111275bb41eSDavid Howells 	isec->sid = sid;
41126f3be9f5SAndreas Gruenbacher 	isec->initialized = LABEL_INITIALIZED;
41139287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
41141da177e4SLinus Torvalds }
41151da177e4SLinus Torvalds 
41161da177e4SLinus Torvalds /* Returns error only if unable to parse addresses */
411767f83cbfSVenkat Yekkirala static int selinux_parse_skb_ipv4(struct sk_buff *skb,
41182bf49690SThomas Liu 			struct common_audit_data *ad, u8 *proto)
41191da177e4SLinus Torvalds {
41201da177e4SLinus Torvalds 	int offset, ihlen, ret = -EINVAL;
41211da177e4SLinus Torvalds 	struct iphdr _iph, *ih;
41221da177e4SLinus Torvalds 
4123bbe735e4SArnaldo Carvalho de Melo 	offset = skb_network_offset(skb);
41241da177e4SLinus Torvalds 	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
41251da177e4SLinus Torvalds 	if (ih == NULL)
41261da177e4SLinus Torvalds 		goto out;
41271da177e4SLinus Torvalds 
41281da177e4SLinus Torvalds 	ihlen = ih->ihl * 4;
41291da177e4SLinus Torvalds 	if (ihlen < sizeof(_iph))
41301da177e4SLinus Torvalds 		goto out;
41311da177e4SLinus Torvalds 
413248c62af6SEric Paris 	ad->u.net->v4info.saddr = ih->saddr;
413348c62af6SEric Paris 	ad->u.net->v4info.daddr = ih->daddr;
41341da177e4SLinus Torvalds 	ret = 0;
41351da177e4SLinus Torvalds 
413667f83cbfSVenkat Yekkirala 	if (proto)
413767f83cbfSVenkat Yekkirala 		*proto = ih->protocol;
413867f83cbfSVenkat Yekkirala 
41391da177e4SLinus Torvalds 	switch (ih->protocol) {
41401da177e4SLinus Torvalds 	case IPPROTO_TCP: {
41411da177e4SLinus Torvalds 		struct tcphdr _tcph, *th;
41421da177e4SLinus Torvalds 
41431da177e4SLinus Torvalds 		if (ntohs(ih->frag_off) & IP_OFFSET)
41441da177e4SLinus Torvalds 			break;
41451da177e4SLinus Torvalds 
41461da177e4SLinus Torvalds 		offset += ihlen;
41471da177e4SLinus Torvalds 		th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
41481da177e4SLinus Torvalds 		if (th == NULL)
41491da177e4SLinus Torvalds 			break;
41501da177e4SLinus Torvalds 
415148c62af6SEric Paris 		ad->u.net->sport = th->source;
415248c62af6SEric Paris 		ad->u.net->dport = th->dest;
41531da177e4SLinus Torvalds 		break;
41541da177e4SLinus Torvalds 	}
41551da177e4SLinus Torvalds 
41561da177e4SLinus Torvalds 	case IPPROTO_UDP: {
41571da177e4SLinus Torvalds 		struct udphdr _udph, *uh;
41581da177e4SLinus Torvalds 
41591da177e4SLinus Torvalds 		if (ntohs(ih->frag_off) & IP_OFFSET)
41601da177e4SLinus Torvalds 			break;
41611da177e4SLinus Torvalds 
41621da177e4SLinus Torvalds 		offset += ihlen;
41631da177e4SLinus Torvalds 		uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
41641da177e4SLinus Torvalds 		if (uh == NULL)
41651da177e4SLinus Torvalds 			break;
41661da177e4SLinus Torvalds 
416748c62af6SEric Paris 		ad->u.net->sport = uh->source;
416848c62af6SEric Paris 		ad->u.net->dport = uh->dest;
41691da177e4SLinus Torvalds 		break;
41701da177e4SLinus Torvalds 	}
41711da177e4SLinus Torvalds 
41722ee92d46SJames Morris 	case IPPROTO_DCCP: {
41732ee92d46SJames Morris 		struct dccp_hdr _dccph, *dh;
41742ee92d46SJames Morris 
41752ee92d46SJames Morris 		if (ntohs(ih->frag_off) & IP_OFFSET)
41762ee92d46SJames Morris 			break;
41772ee92d46SJames Morris 
41782ee92d46SJames Morris 		offset += ihlen;
41792ee92d46SJames Morris 		dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
41802ee92d46SJames Morris 		if (dh == NULL)
41812ee92d46SJames Morris 			break;
41822ee92d46SJames Morris 
418348c62af6SEric Paris 		ad->u.net->sport = dh->dccph_sport;
418448c62af6SEric Paris 		ad->u.net->dport = dh->dccph_dport;
41852ee92d46SJames Morris 		break;
41862ee92d46SJames Morris 	}
41872ee92d46SJames Morris 
4188d452930fSRichard Haines #if IS_ENABLED(CONFIG_IP_SCTP)
4189d452930fSRichard Haines 	case IPPROTO_SCTP: {
4190d452930fSRichard Haines 		struct sctphdr _sctph, *sh;
4191d452930fSRichard Haines 
4192d452930fSRichard Haines 		if (ntohs(ih->frag_off) & IP_OFFSET)
4193d452930fSRichard Haines 			break;
4194d452930fSRichard Haines 
4195d452930fSRichard Haines 		offset += ihlen;
4196d452930fSRichard Haines 		sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
4197d452930fSRichard Haines 		if (sh == NULL)
4198d452930fSRichard Haines 			break;
4199d452930fSRichard Haines 
4200d452930fSRichard Haines 		ad->u.net->sport = sh->source;
4201d452930fSRichard Haines 		ad->u.net->dport = sh->dest;
4202d452930fSRichard Haines 		break;
4203d452930fSRichard Haines 	}
4204d452930fSRichard Haines #endif
42051da177e4SLinus Torvalds 	default:
42061da177e4SLinus Torvalds 		break;
42071da177e4SLinus Torvalds 	}
42081da177e4SLinus Torvalds out:
42091da177e4SLinus Torvalds 	return ret;
42101da177e4SLinus Torvalds }
42111da177e4SLinus Torvalds 
42121a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
42131da177e4SLinus Torvalds 
42141da177e4SLinus Torvalds /* Returns error only if unable to parse addresses */
421567f83cbfSVenkat Yekkirala static int selinux_parse_skb_ipv6(struct sk_buff *skb,
42162bf49690SThomas Liu 			struct common_audit_data *ad, u8 *proto)
42171da177e4SLinus Torvalds {
42181da177e4SLinus Torvalds 	u8 nexthdr;
42191da177e4SLinus Torvalds 	int ret = -EINVAL, offset;
42201da177e4SLinus Torvalds 	struct ipv6hdr _ipv6h, *ip6;
422175f2811cSJesse Gross 	__be16 frag_off;
42221da177e4SLinus Torvalds 
4223bbe735e4SArnaldo Carvalho de Melo 	offset = skb_network_offset(skb);
42241da177e4SLinus Torvalds 	ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
42251da177e4SLinus Torvalds 	if (ip6 == NULL)
42261da177e4SLinus Torvalds 		goto out;
42271da177e4SLinus Torvalds 
422848c62af6SEric Paris 	ad->u.net->v6info.saddr = ip6->saddr;
422948c62af6SEric Paris 	ad->u.net->v6info.daddr = ip6->daddr;
42301da177e4SLinus Torvalds 	ret = 0;
42311da177e4SLinus Torvalds 
42321da177e4SLinus Torvalds 	nexthdr = ip6->nexthdr;
42331da177e4SLinus Torvalds 	offset += sizeof(_ipv6h);
423475f2811cSJesse Gross 	offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
42351da177e4SLinus Torvalds 	if (offset < 0)
42361da177e4SLinus Torvalds 		goto out;
42371da177e4SLinus Torvalds 
423867f83cbfSVenkat Yekkirala 	if (proto)
423967f83cbfSVenkat Yekkirala 		*proto = nexthdr;
424067f83cbfSVenkat Yekkirala 
42411da177e4SLinus Torvalds 	switch (nexthdr) {
42421da177e4SLinus Torvalds 	case IPPROTO_TCP: {
42431da177e4SLinus Torvalds 		struct tcphdr _tcph, *th;
42441da177e4SLinus Torvalds 
42451da177e4SLinus Torvalds 		th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
42461da177e4SLinus Torvalds 		if (th == NULL)
42471da177e4SLinus Torvalds 			break;
42481da177e4SLinus Torvalds 
424948c62af6SEric Paris 		ad->u.net->sport = th->source;
425048c62af6SEric Paris 		ad->u.net->dport = th->dest;
42511da177e4SLinus Torvalds 		break;
42521da177e4SLinus Torvalds 	}
42531da177e4SLinus Torvalds 
42541da177e4SLinus Torvalds 	case IPPROTO_UDP: {
42551da177e4SLinus Torvalds 		struct udphdr _udph, *uh;
42561da177e4SLinus Torvalds 
42571da177e4SLinus Torvalds 		uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
42581da177e4SLinus Torvalds 		if (uh == NULL)
42591da177e4SLinus Torvalds 			break;
42601da177e4SLinus Torvalds 
426148c62af6SEric Paris 		ad->u.net->sport = uh->source;
426248c62af6SEric Paris 		ad->u.net->dport = uh->dest;
42631da177e4SLinus Torvalds 		break;
42641da177e4SLinus Torvalds 	}
42651da177e4SLinus Torvalds 
42662ee92d46SJames Morris 	case IPPROTO_DCCP: {
42672ee92d46SJames Morris 		struct dccp_hdr _dccph, *dh;
42682ee92d46SJames Morris 
42692ee92d46SJames Morris 		dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
42702ee92d46SJames Morris 		if (dh == NULL)
42712ee92d46SJames Morris 			break;
42722ee92d46SJames Morris 
427348c62af6SEric Paris 		ad->u.net->sport = dh->dccph_sport;
427448c62af6SEric Paris 		ad->u.net->dport = dh->dccph_dport;
42752ee92d46SJames Morris 		break;
42762ee92d46SJames Morris 	}
42772ee92d46SJames Morris 
4278d452930fSRichard Haines #if IS_ENABLED(CONFIG_IP_SCTP)
4279d452930fSRichard Haines 	case IPPROTO_SCTP: {
4280d452930fSRichard Haines 		struct sctphdr _sctph, *sh;
4281d452930fSRichard Haines 
4282d452930fSRichard Haines 		sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
4283d452930fSRichard Haines 		if (sh == NULL)
4284d452930fSRichard Haines 			break;
4285d452930fSRichard Haines 
4286d452930fSRichard Haines 		ad->u.net->sport = sh->source;
4287d452930fSRichard Haines 		ad->u.net->dport = sh->dest;
4288d452930fSRichard Haines 		break;
4289d452930fSRichard Haines 	}
4290d452930fSRichard Haines #endif
42911da177e4SLinus Torvalds 	/* includes fragments */
42921da177e4SLinus Torvalds 	default:
42931da177e4SLinus Torvalds 		break;
42941da177e4SLinus Torvalds 	}
42951da177e4SLinus Torvalds out:
42961da177e4SLinus Torvalds 	return ret;
42971da177e4SLinus Torvalds }
42981da177e4SLinus Torvalds 
42991da177e4SLinus Torvalds #endif /* IPV6 */
43001da177e4SLinus Torvalds 
43012bf49690SThomas Liu static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
4302cf9481e2SDavid Howells 			     char **_addrp, int src, u8 *proto)
43031da177e4SLinus Torvalds {
4304cf9481e2SDavid Howells 	char *addrp;
4305cf9481e2SDavid Howells 	int ret;
43061da177e4SLinus Torvalds 
430748c62af6SEric Paris 	switch (ad->u.net->family) {
43081da177e4SLinus Torvalds 	case PF_INET:
430967f83cbfSVenkat Yekkirala 		ret = selinux_parse_skb_ipv4(skb, ad, proto);
4310cf9481e2SDavid Howells 		if (ret)
4311cf9481e2SDavid Howells 			goto parse_error;
431248c62af6SEric Paris 		addrp = (char *)(src ? &ad->u.net->v4info.saddr :
431348c62af6SEric Paris 				       &ad->u.net->v4info.daddr);
4314cf9481e2SDavid Howells 		goto okay;
43151da177e4SLinus Torvalds 
43161a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
43171da177e4SLinus Torvalds 	case PF_INET6:
431867f83cbfSVenkat Yekkirala 		ret = selinux_parse_skb_ipv6(skb, ad, proto);
4319cf9481e2SDavid Howells 		if (ret)
4320cf9481e2SDavid Howells 			goto parse_error;
432148c62af6SEric Paris 		addrp = (char *)(src ? &ad->u.net->v6info.saddr :
432248c62af6SEric Paris 				       &ad->u.net->v6info.daddr);
4323cf9481e2SDavid Howells 		goto okay;
43241da177e4SLinus Torvalds #endif	/* IPV6 */
43251da177e4SLinus Torvalds 	default:
4326cf9481e2SDavid Howells 		addrp = NULL;
4327cf9481e2SDavid Howells 		goto okay;
43281da177e4SLinus Torvalds 	}
43291da177e4SLinus Torvalds 
4330cf9481e2SDavid Howells parse_error:
4331c103a91eSpeter enderborg 	pr_warn(
433271f1cb05SPaul Moore 	       "SELinux: failure in selinux_parse_skb(),"
433371f1cb05SPaul Moore 	       " unable to parse packet\n");
43341da177e4SLinus Torvalds 	return ret;
4335cf9481e2SDavid Howells 
4336cf9481e2SDavid Howells okay:
4337cf9481e2SDavid Howells 	if (_addrp)
4338cf9481e2SDavid Howells 		*_addrp = addrp;
4339cf9481e2SDavid Howells 	return 0;
43401da177e4SLinus Torvalds }
43411da177e4SLinus Torvalds 
43424f6a993fSPaul Moore /**
4343220deb96SPaul Moore  * selinux_skb_peerlbl_sid - Determine the peer label of a packet
43444f6a993fSPaul Moore  * @skb: the packet
434575e22910SPaul Moore  * @family: protocol family
4346220deb96SPaul Moore  * @sid: the packet's peer label SID
43474f6a993fSPaul Moore  *
43484f6a993fSPaul Moore  * Description:
4349220deb96SPaul Moore  * Check the various different forms of network peer labeling and determine
4350220deb96SPaul Moore  * the peer label/SID for the packet; most of the magic actually occurs in
4351220deb96SPaul Moore  * the security server function security_net_peersid_cmp().  The function
4352220deb96SPaul Moore  * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
4353220deb96SPaul Moore  * or -EACCES if @sid is invalid due to inconsistencies with the different
4354220deb96SPaul Moore  * peer labels.
43554f6a993fSPaul Moore  *
43564f6a993fSPaul Moore  */
4357220deb96SPaul Moore static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
43584f6a993fSPaul Moore {
435971f1cb05SPaul Moore 	int err;
43604f6a993fSPaul Moore 	u32 xfrm_sid;
43614f6a993fSPaul Moore 	u32 nlbl_sid;
4362220deb96SPaul Moore 	u32 nlbl_type;
43634f6a993fSPaul Moore 
4364817eff71SPaul Moore 	err = selinux_xfrm_skb_sid(skb, &xfrm_sid);
4365bed4d7efSPaul Moore 	if (unlikely(err))
4366bed4d7efSPaul Moore 		return -EACCES;
4367bed4d7efSPaul Moore 	err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
4368bed4d7efSPaul Moore 	if (unlikely(err))
4369bed4d7efSPaul Moore 		return -EACCES;
4370220deb96SPaul Moore 
4371aa8e712cSStephen Smalley 	err = security_net_peersid_resolve(&selinux_state, nlbl_sid,
4372aa8e712cSStephen Smalley 					   nlbl_type, xfrm_sid, sid);
437371f1cb05SPaul Moore 	if (unlikely(err)) {
4374c103a91eSpeter enderborg 		pr_warn(
437571f1cb05SPaul Moore 		       "SELinux: failure in selinux_skb_peerlbl_sid(),"
437671f1cb05SPaul Moore 		       " unable to determine packet's peer label\n");
4377220deb96SPaul Moore 		return -EACCES;
437871f1cb05SPaul Moore 	}
4379220deb96SPaul Moore 
4380220deb96SPaul Moore 	return 0;
43814f6a993fSPaul Moore }
43824f6a993fSPaul Moore 
4383446b8024SPaul Moore /**
4384446b8024SPaul Moore  * selinux_conn_sid - Determine the child socket label for a connection
4385446b8024SPaul Moore  * @sk_sid: the parent socket's SID
4386446b8024SPaul Moore  * @skb_sid: the packet's SID
4387446b8024SPaul Moore  * @conn_sid: the resulting connection SID
4388446b8024SPaul Moore  *
4389446b8024SPaul Moore  * If @skb_sid is valid then the user:role:type information from @sk_sid is
4390446b8024SPaul Moore  * combined with the MLS information from @skb_sid in order to create
4391446b8024SPaul Moore  * @conn_sid.  If @skb_sid is not valid then then @conn_sid is simply a copy
4392446b8024SPaul Moore  * of @sk_sid.  Returns zero on success, negative values on failure.
4393446b8024SPaul Moore  *
4394446b8024SPaul Moore  */
4395446b8024SPaul Moore static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
4396446b8024SPaul Moore {
4397446b8024SPaul Moore 	int err = 0;
4398446b8024SPaul Moore 
4399446b8024SPaul Moore 	if (skb_sid != SECSID_NULL)
4400aa8e712cSStephen Smalley 		err = security_sid_mls_copy(&selinux_state, sk_sid, skb_sid,
4401aa8e712cSStephen Smalley 					    conn_sid);
4402446b8024SPaul Moore 	else
4403446b8024SPaul Moore 		*conn_sid = sk_sid;
4404446b8024SPaul Moore 
4405446b8024SPaul Moore 	return err;
4406446b8024SPaul Moore }
4407446b8024SPaul Moore 
44081da177e4SLinus Torvalds /* socket security operations */
4409d4f2d978SPaul Moore 
44102ad18bdfSHarry Ciao static int socket_sockcreate_sid(const struct task_security_struct *tsec,
44112ad18bdfSHarry Ciao 				 u16 secclass, u32 *socksid)
4412d4f2d978SPaul Moore {
44132ad18bdfSHarry Ciao 	if (tsec->sockcreate_sid > SECSID_NULL) {
44142ad18bdfSHarry Ciao 		*socksid = tsec->sockcreate_sid;
44152ad18bdfSHarry Ciao 		return 0;
44162ad18bdfSHarry Ciao 	}
44172ad18bdfSHarry Ciao 
4418aa8e712cSStephen Smalley 	return security_transition_sid(&selinux_state, tsec->sid, tsec->sid,
4419aa8e712cSStephen Smalley 				       secclass, NULL, socksid);
4420d4f2d978SPaul Moore }
4421d4f2d978SPaul Moore 
4422be0554c9SStephen Smalley static int sock_has_perm(struct sock *sk, u32 perms)
44231da177e4SLinus Torvalds {
4424253bfae6SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
44252bf49690SThomas Liu 	struct common_audit_data ad;
442648c62af6SEric Paris 	struct lsm_network_audit net = {0,};
44271da177e4SLinus Torvalds 
4428253bfae6SPaul Moore 	if (sksec->sid == SECINITSID_KERNEL)
4429253bfae6SPaul Moore 		return 0;
44301da177e4SLinus Torvalds 
443150c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
443248c62af6SEric Paris 	ad.u.net = &net;
443348c62af6SEric Paris 	ad.u.net->sk = sk;
44341da177e4SLinus Torvalds 
44356b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
44366b6bc620SStephen Smalley 			    current_sid(), sksec->sid, sksec->sclass, perms,
4437be0554c9SStephen Smalley 			    &ad);
44381da177e4SLinus Torvalds }
44391da177e4SLinus Torvalds 
44401da177e4SLinus Torvalds static int selinux_socket_create(int family, int type,
44411da177e4SLinus Torvalds 				 int protocol, int kern)
44421da177e4SLinus Torvalds {
44430c6cfa62SCasey Schaufler 	const struct task_security_struct *tsec = selinux_cred(current_cred());
4444d4f2d978SPaul Moore 	u32 newsid;
4445275bb41eSDavid Howells 	u16 secclass;
44462ad18bdfSHarry Ciao 	int rc;
44471da177e4SLinus Torvalds 
44481da177e4SLinus Torvalds 	if (kern)
4449d4f2d978SPaul Moore 		return 0;
44501da177e4SLinus Torvalds 
4451275bb41eSDavid Howells 	secclass = socket_type_to_security_class(family, type, protocol);
44522ad18bdfSHarry Ciao 	rc = socket_sockcreate_sid(tsec, secclass, &newsid);
44532ad18bdfSHarry Ciao 	if (rc)
44542ad18bdfSHarry Ciao 		return rc;
44552ad18bdfSHarry Ciao 
44566b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
44576b6bc620SStephen Smalley 			    tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
44581da177e4SLinus Torvalds }
44591da177e4SLinus Torvalds 
44607420ed23SVenkat Yekkirala static int selinux_socket_post_create(struct socket *sock, int family,
44611da177e4SLinus Torvalds 				      int type, int protocol, int kern)
44621da177e4SLinus Torvalds {
44630c6cfa62SCasey Schaufler 	const struct task_security_struct *tsec = selinux_cred(current_cred());
44645d226df4SAndreas Gruenbacher 	struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock));
4465892c141eSVenkat Yekkirala 	struct sk_security_struct *sksec;
44669287aed2SAndreas Gruenbacher 	u16 sclass = socket_type_to_security_class(family, type, protocol);
44679287aed2SAndreas Gruenbacher 	u32 sid = SECINITSID_KERNEL;
4468275bb41eSDavid Howells 	int err = 0;
4469275bb41eSDavid Howells 
44709287aed2SAndreas Gruenbacher 	if (!kern) {
44719287aed2SAndreas Gruenbacher 		err = socket_sockcreate_sid(tsec, sclass, &sid);
44722ad18bdfSHarry Ciao 		if (err)
44732ad18bdfSHarry Ciao 			return err;
44742ad18bdfSHarry Ciao 	}
4475275bb41eSDavid Howells 
44769287aed2SAndreas Gruenbacher 	isec->sclass = sclass;
44779287aed2SAndreas Gruenbacher 	isec->sid = sid;
44786f3be9f5SAndreas Gruenbacher 	isec->initialized = LABEL_INITIALIZED;
44791da177e4SLinus Torvalds 
4480892c141eSVenkat Yekkirala 	if (sock->sk) {
4481892c141eSVenkat Yekkirala 		sksec = sock->sk->sk_security;
44829287aed2SAndreas Gruenbacher 		sksec->sclass = sclass;
44839287aed2SAndreas Gruenbacher 		sksec->sid = sid;
4484d452930fSRichard Haines 		/* Allows detection of the first association on this socket */
4485d452930fSRichard Haines 		if (sksec->sclass == SECCLASS_SCTP_SOCKET)
4486d452930fSRichard Haines 			sksec->sctp_assoc_state = SCTP_ASSOC_UNSET;
4487d452930fSRichard Haines 
4488389fb800SPaul Moore 		err = selinux_netlbl_socket_post_create(sock->sk, family);
4489892c141eSVenkat Yekkirala 	}
4490892c141eSVenkat Yekkirala 
44917420ed23SVenkat Yekkirala 	return err;
44921da177e4SLinus Torvalds }
44931da177e4SLinus Torvalds 
44940b811db2SDavid Herrmann static int selinux_socket_socketpair(struct socket *socka,
44950b811db2SDavid Herrmann 				     struct socket *sockb)
44960b811db2SDavid Herrmann {
44970b811db2SDavid Herrmann 	struct sk_security_struct *sksec_a = socka->sk->sk_security;
44980b811db2SDavid Herrmann 	struct sk_security_struct *sksec_b = sockb->sk->sk_security;
44990b811db2SDavid Herrmann 
45000b811db2SDavid Herrmann 	sksec_a->peer_sid = sksec_b->sid;
45010b811db2SDavid Herrmann 	sksec_b->peer_sid = sksec_a->sid;
45020b811db2SDavid Herrmann 
45030b811db2SDavid Herrmann 	return 0;
45040b811db2SDavid Herrmann }
45050b811db2SDavid Herrmann 
45061da177e4SLinus Torvalds /* Range of port numbers used to automatically bind.
45071da177e4SLinus Torvalds    Need to determine whether we should perform a name_bind
45081da177e4SLinus Torvalds    permission check between the socket and the port number. */
45091da177e4SLinus Torvalds 
45101da177e4SLinus Torvalds static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
45111da177e4SLinus Torvalds {
4512253bfae6SPaul Moore 	struct sock *sk = sock->sk;
45130f8db8ccSAlexey Kodanev 	struct sk_security_struct *sksec = sk->sk_security;
45141da177e4SLinus Torvalds 	u16 family;
45151da177e4SLinus Torvalds 	int err;
45161da177e4SLinus Torvalds 
4517be0554c9SStephen Smalley 	err = sock_has_perm(sk, SOCKET__BIND);
45181da177e4SLinus Torvalds 	if (err)
45191da177e4SLinus Torvalds 		goto out;
45201da177e4SLinus Torvalds 
4521d452930fSRichard Haines 	/* If PF_INET or PF_INET6, check name_bind permission for the port. */
4522253bfae6SPaul Moore 	family = sk->sk_family;
45231da177e4SLinus Torvalds 	if (family == PF_INET || family == PF_INET6) {
45241da177e4SLinus Torvalds 		char *addrp;
45252bf49690SThomas Liu 		struct common_audit_data ad;
452648c62af6SEric Paris 		struct lsm_network_audit net = {0,};
45271da177e4SLinus Torvalds 		struct sockaddr_in *addr4 = NULL;
45281da177e4SLinus Torvalds 		struct sockaddr_in6 *addr6 = NULL;
4529c750e692STetsuo Handa 		u16 family_sa;
45301da177e4SLinus Torvalds 		unsigned short snum;
4531e399f982SJames Morris 		u32 sid, node_perm;
45321da177e4SLinus Torvalds 
4533d452930fSRichard Haines 		/*
4534d452930fSRichard Haines 		 * sctp_bindx(3) calls via selinux_sctp_bind_connect()
4535d452930fSRichard Haines 		 * that validates multiple binding addresses. Because of this
4536d452930fSRichard Haines 		 * need to check address->sa_family as it is possible to have
4537d452930fSRichard Haines 		 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
4538d452930fSRichard Haines 		 */
4539c750e692STetsuo Handa 		if (addrlen < offsetofend(struct sockaddr, sa_family))
4540c750e692STetsuo Handa 			return -EINVAL;
4541c750e692STetsuo Handa 		family_sa = address->sa_family;
45420f8db8ccSAlexey Kodanev 		switch (family_sa) {
45430f8db8ccSAlexey Kodanev 		case AF_UNSPEC:
454468741a8aSRichard Haines 		case AF_INET:
454568741a8aSRichard Haines 			if (addrlen < sizeof(struct sockaddr_in))
454668741a8aSRichard Haines 				return -EINVAL;
45471da177e4SLinus Torvalds 			addr4 = (struct sockaddr_in *)address;
45480f8db8ccSAlexey Kodanev 			if (family_sa == AF_UNSPEC) {
45490f8db8ccSAlexey Kodanev 				/* see __inet_bind(), we only want to allow
45500f8db8ccSAlexey Kodanev 				 * AF_UNSPEC if the address is INADDR_ANY
45510f8db8ccSAlexey Kodanev 				 */
45520f8db8ccSAlexey Kodanev 				if (addr4->sin_addr.s_addr != htonl(INADDR_ANY))
45530f8db8ccSAlexey Kodanev 					goto err_af;
45540f8db8ccSAlexey Kodanev 				family_sa = AF_INET;
45550f8db8ccSAlexey Kodanev 			}
45561da177e4SLinus Torvalds 			snum = ntohs(addr4->sin_port);
45571da177e4SLinus Torvalds 			addrp = (char *)&addr4->sin_addr.s_addr;
455868741a8aSRichard Haines 			break;
455968741a8aSRichard Haines 		case AF_INET6:
456068741a8aSRichard Haines 			if (addrlen < SIN6_LEN_RFC2133)
456168741a8aSRichard Haines 				return -EINVAL;
45621da177e4SLinus Torvalds 			addr6 = (struct sockaddr_in6 *)address;
45631da177e4SLinus Torvalds 			snum = ntohs(addr6->sin6_port);
45641da177e4SLinus Torvalds 			addrp = (char *)&addr6->sin6_addr.s6_addr;
456568741a8aSRichard Haines 			break;
456668741a8aSRichard Haines 		default:
45670f8db8ccSAlexey Kodanev 			goto err_af;
45681da177e4SLinus Torvalds 		}
45691da177e4SLinus Torvalds 
457088b7d370SAlexey Kodanev 		ad.type = LSM_AUDIT_DATA_NET;
457188b7d370SAlexey Kodanev 		ad.u.net = &net;
457288b7d370SAlexey Kodanev 		ad.u.net->sport = htons(snum);
457388b7d370SAlexey Kodanev 		ad.u.net->family = family_sa;
457488b7d370SAlexey Kodanev 
4575227b60f5SStephen Hemminger 		if (snum) {
4576227b60f5SStephen Hemminger 			int low, high;
4577227b60f5SStephen Hemminger 
45780bbf87d8SEric W. Biederman 			inet_get_local_port_range(sock_net(sk), &low, &high);
4579227b60f5SStephen Hemminger 
45804548b683SKrister Johansen 			if (snum < max(inet_prot_sock(sock_net(sk)), low) ||
45814548b683SKrister Johansen 			    snum > high) {
45823e112172SPaul Moore 				err = sel_netport_sid(sk->sk_protocol,
45833e112172SPaul Moore 						      snum, &sid);
45841da177e4SLinus Torvalds 				if (err)
45851da177e4SLinus Torvalds 					goto out;
45866b6bc620SStephen Smalley 				err = avc_has_perm(&selinux_state,
45876b6bc620SStephen Smalley 						   sksec->sid, sid,
4588253bfae6SPaul Moore 						   sksec->sclass,
45891da177e4SLinus Torvalds 						   SOCKET__NAME_BIND, &ad);
45901da177e4SLinus Torvalds 				if (err)
45911da177e4SLinus Torvalds 					goto out;
45921da177e4SLinus Torvalds 			}
4593227b60f5SStephen Hemminger 		}
45941da177e4SLinus Torvalds 
4595253bfae6SPaul Moore 		switch (sksec->sclass) {
459613402580SJames Morris 		case SECCLASS_TCP_SOCKET:
45971da177e4SLinus Torvalds 			node_perm = TCP_SOCKET__NODE_BIND;
45981da177e4SLinus Torvalds 			break;
45991da177e4SLinus Torvalds 
460013402580SJames Morris 		case SECCLASS_UDP_SOCKET:
46011da177e4SLinus Torvalds 			node_perm = UDP_SOCKET__NODE_BIND;
46021da177e4SLinus Torvalds 			break;
46031da177e4SLinus Torvalds 
46042ee92d46SJames Morris 		case SECCLASS_DCCP_SOCKET:
46052ee92d46SJames Morris 			node_perm = DCCP_SOCKET__NODE_BIND;
46062ee92d46SJames Morris 			break;
46072ee92d46SJames Morris 
4608d452930fSRichard Haines 		case SECCLASS_SCTP_SOCKET:
4609d452930fSRichard Haines 			node_perm = SCTP_SOCKET__NODE_BIND;
4610d452930fSRichard Haines 			break;
4611d452930fSRichard Haines 
46121da177e4SLinus Torvalds 		default:
46131da177e4SLinus Torvalds 			node_perm = RAWIP_SOCKET__NODE_BIND;
46141da177e4SLinus Torvalds 			break;
46151da177e4SLinus Torvalds 		}
46161da177e4SLinus Torvalds 
461788b7d370SAlexey Kodanev 		err = sel_netnode_sid(addrp, family_sa, &sid);
46181da177e4SLinus Torvalds 		if (err)
46191da177e4SLinus Torvalds 			goto out;
46201da177e4SLinus Torvalds 
46210f8db8ccSAlexey Kodanev 		if (family_sa == AF_INET)
462248c62af6SEric Paris 			ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
46231da177e4SLinus Torvalds 		else
462448c62af6SEric Paris 			ad.u.net->v6info.saddr = addr6->sin6_addr;
46251da177e4SLinus Torvalds 
46266b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
46276b6bc620SStephen Smalley 				   sksec->sid, sid,
4628253bfae6SPaul Moore 				   sksec->sclass, node_perm, &ad);
46291da177e4SLinus Torvalds 		if (err)
46301da177e4SLinus Torvalds 			goto out;
46311da177e4SLinus Torvalds 	}
46321da177e4SLinus Torvalds out:
46331da177e4SLinus Torvalds 	return err;
46340f8db8ccSAlexey Kodanev err_af:
46350f8db8ccSAlexey Kodanev 	/* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */
46360f8db8ccSAlexey Kodanev 	if (sksec->sclass == SECCLASS_SCTP_SOCKET)
46370f8db8ccSAlexey Kodanev 		return -EINVAL;
46380f8db8ccSAlexey Kodanev 	return -EAFNOSUPPORT;
46391da177e4SLinus Torvalds }
46401da177e4SLinus Torvalds 
4641d452930fSRichard Haines /* This supports connect(2) and SCTP connect services such as sctp_connectx(3)
4642d61330c6SKees Cook  * and sctp_sendmsg(3) as described in Documentation/security/SCTP.rst
4643d452930fSRichard Haines  */
4644d452930fSRichard Haines static int selinux_socket_connect_helper(struct socket *sock,
4645d452930fSRichard Haines 					 struct sockaddr *address, int addrlen)
46461da177e4SLinus Torvalds {
4647014ab19aSPaul Moore 	struct sock *sk = sock->sk;
4648253bfae6SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
46491da177e4SLinus Torvalds 	int err;
46501da177e4SLinus Torvalds 
4651be0554c9SStephen Smalley 	err = sock_has_perm(sk, SOCKET__CONNECT);
46521da177e4SLinus Torvalds 	if (err)
46531da177e4SLinus Torvalds 		return err;
465405174c95SPaolo Abeni 	if (addrlen < offsetofend(struct sockaddr, sa_family))
465505174c95SPaolo Abeni 		return -EINVAL;
465605174c95SPaolo Abeni 
465705174c95SPaolo Abeni 	/* connect(AF_UNSPEC) has special handling, as it is a documented
465805174c95SPaolo Abeni 	 * way to disconnect the socket
465905174c95SPaolo Abeni 	 */
466005174c95SPaolo Abeni 	if (address->sa_family == AF_UNSPEC)
466105174c95SPaolo Abeni 		return 0;
46621da177e4SLinus Torvalds 
46631da177e4SLinus Torvalds 	/*
4664d452930fSRichard Haines 	 * If a TCP, DCCP or SCTP socket, check name_connect permission
4665d452930fSRichard Haines 	 * for the port.
46661da177e4SLinus Torvalds 	 */
4667253bfae6SPaul Moore 	if (sksec->sclass == SECCLASS_TCP_SOCKET ||
4668d452930fSRichard Haines 	    sksec->sclass == SECCLASS_DCCP_SOCKET ||
4669d452930fSRichard Haines 	    sksec->sclass == SECCLASS_SCTP_SOCKET) {
46702bf49690SThomas Liu 		struct common_audit_data ad;
467148c62af6SEric Paris 		struct lsm_network_audit net = {0,};
46721da177e4SLinus Torvalds 		struct sockaddr_in *addr4 = NULL;
46731da177e4SLinus Torvalds 		struct sockaddr_in6 *addr6 = NULL;
46741da177e4SLinus Torvalds 		unsigned short snum;
46752ee92d46SJames Morris 		u32 sid, perm;
46761da177e4SLinus Torvalds 
4677d452930fSRichard Haines 		/* sctp_connectx(3) calls via selinux_sctp_bind_connect()
4678d452930fSRichard Haines 		 * that validates multiple connect addresses. Because of this
4679d452930fSRichard Haines 		 * need to check address->sa_family as it is possible to have
4680d452930fSRichard Haines 		 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
4681d452930fSRichard Haines 		 */
468268741a8aSRichard Haines 		switch (address->sa_family) {
468368741a8aSRichard Haines 		case AF_INET:
46841da177e4SLinus Torvalds 			addr4 = (struct sockaddr_in *)address;
4685911656f8SStephen Smalley 			if (addrlen < sizeof(struct sockaddr_in))
46861da177e4SLinus Torvalds 				return -EINVAL;
46871da177e4SLinus Torvalds 			snum = ntohs(addr4->sin_port);
468868741a8aSRichard Haines 			break;
468968741a8aSRichard Haines 		case AF_INET6:
46901da177e4SLinus Torvalds 			addr6 = (struct sockaddr_in6 *)address;
4691911656f8SStephen Smalley 			if (addrlen < SIN6_LEN_RFC2133)
46921da177e4SLinus Torvalds 				return -EINVAL;
46931da177e4SLinus Torvalds 			snum = ntohs(addr6->sin6_port);
469468741a8aSRichard Haines 			break;
469568741a8aSRichard Haines 		default:
469668741a8aSRichard Haines 			/* Note that SCTP services expect -EINVAL, whereas
469768741a8aSRichard Haines 			 * others expect -EAFNOSUPPORT.
469868741a8aSRichard Haines 			 */
469968741a8aSRichard Haines 			if (sksec->sclass == SECCLASS_SCTP_SOCKET)
470068741a8aSRichard Haines 				return -EINVAL;
470168741a8aSRichard Haines 			else
470268741a8aSRichard Haines 				return -EAFNOSUPPORT;
47031da177e4SLinus Torvalds 		}
47041da177e4SLinus Torvalds 
47053e112172SPaul Moore 		err = sel_netport_sid(sk->sk_protocol, snum, &sid);
47061da177e4SLinus Torvalds 		if (err)
4707d452930fSRichard Haines 			return err;
47081da177e4SLinus Torvalds 
4709d452930fSRichard Haines 		switch (sksec->sclass) {
4710d452930fSRichard Haines 		case SECCLASS_TCP_SOCKET:
4711d452930fSRichard Haines 			perm = TCP_SOCKET__NAME_CONNECT;
4712d452930fSRichard Haines 			break;
4713d452930fSRichard Haines 		case SECCLASS_DCCP_SOCKET:
4714d452930fSRichard Haines 			perm = DCCP_SOCKET__NAME_CONNECT;
4715d452930fSRichard Haines 			break;
4716d452930fSRichard Haines 		case SECCLASS_SCTP_SOCKET:
4717d452930fSRichard Haines 			perm = SCTP_SOCKET__NAME_CONNECT;
4718d452930fSRichard Haines 			break;
4719d452930fSRichard Haines 		}
47202ee92d46SJames Morris 
472150c205f5SEric Paris 		ad.type = LSM_AUDIT_DATA_NET;
472248c62af6SEric Paris 		ad.u.net = &net;
472348c62af6SEric Paris 		ad.u.net->dport = htons(snum);
472488b7d370SAlexey Kodanev 		ad.u.net->family = address->sa_family;
47256b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
47266b6bc620SStephen Smalley 				   sksec->sid, sid, sksec->sclass, perm, &ad);
47271da177e4SLinus Torvalds 		if (err)
4728d452930fSRichard Haines 			return err;
47291da177e4SLinus Torvalds 	}
47301da177e4SLinus Torvalds 
4731d452930fSRichard Haines 	return 0;
4732d452930fSRichard Haines }
4733014ab19aSPaul Moore 
4734d452930fSRichard Haines /* Supports connect(2), see comments in selinux_socket_connect_helper() */
4735d452930fSRichard Haines static int selinux_socket_connect(struct socket *sock,
4736d452930fSRichard Haines 				  struct sockaddr *address, int addrlen)
4737d452930fSRichard Haines {
4738d452930fSRichard Haines 	int err;
4739d452930fSRichard Haines 	struct sock *sk = sock->sk;
4740d452930fSRichard Haines 
4741d452930fSRichard Haines 	err = selinux_socket_connect_helper(sock, address, addrlen);
4742d452930fSRichard Haines 	if (err)
47431da177e4SLinus Torvalds 		return err;
4744d452930fSRichard Haines 
4745d452930fSRichard Haines 	return selinux_netlbl_socket_connect(sk, address);
47461da177e4SLinus Torvalds }
47471da177e4SLinus Torvalds 
47481da177e4SLinus Torvalds static int selinux_socket_listen(struct socket *sock, int backlog)
47491da177e4SLinus Torvalds {
4750be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__LISTEN);
47511da177e4SLinus Torvalds }
47521da177e4SLinus Torvalds 
47531da177e4SLinus Torvalds static int selinux_socket_accept(struct socket *sock, struct socket *newsock)
47541da177e4SLinus Torvalds {
47551da177e4SLinus Torvalds 	int err;
47561da177e4SLinus Torvalds 	struct inode_security_struct *isec;
47571da177e4SLinus Torvalds 	struct inode_security_struct *newisec;
47589287aed2SAndreas Gruenbacher 	u16 sclass;
47599287aed2SAndreas Gruenbacher 	u32 sid;
47601da177e4SLinus Torvalds 
4761be0554c9SStephen Smalley 	err = sock_has_perm(sock->sk, SOCKET__ACCEPT);
47621da177e4SLinus Torvalds 	if (err)
47631da177e4SLinus Torvalds 		return err;
47641da177e4SLinus Torvalds 
47655d226df4SAndreas Gruenbacher 	isec = inode_security_novalidate(SOCK_INODE(sock));
47669287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
47679287aed2SAndreas Gruenbacher 	sclass = isec->sclass;
47689287aed2SAndreas Gruenbacher 	sid = isec->sid;
47699287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
47709287aed2SAndreas Gruenbacher 
47719287aed2SAndreas Gruenbacher 	newisec = inode_security_novalidate(SOCK_INODE(newsock));
47729287aed2SAndreas Gruenbacher 	newisec->sclass = sclass;
47739287aed2SAndreas Gruenbacher 	newisec->sid = sid;
47746f3be9f5SAndreas Gruenbacher 	newisec->initialized = LABEL_INITIALIZED;
47751da177e4SLinus Torvalds 
47761da177e4SLinus Torvalds 	return 0;
47771da177e4SLinus Torvalds }
47781da177e4SLinus Torvalds 
47791da177e4SLinus Torvalds static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
47801da177e4SLinus Torvalds 				  int size)
47811da177e4SLinus Torvalds {
4782be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__WRITE);
47831da177e4SLinus Torvalds }
47841da177e4SLinus Torvalds 
47851da177e4SLinus Torvalds static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
47861da177e4SLinus Torvalds 				  int size, int flags)
47871da177e4SLinus Torvalds {
4788be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__READ);
47891da177e4SLinus Torvalds }
47901da177e4SLinus Torvalds 
47911da177e4SLinus Torvalds static int selinux_socket_getsockname(struct socket *sock)
47921da177e4SLinus Torvalds {
4793be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__GETATTR);
47941da177e4SLinus Torvalds }
47951da177e4SLinus Torvalds 
47961da177e4SLinus Torvalds static int selinux_socket_getpeername(struct socket *sock)
47971da177e4SLinus Torvalds {
4798be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__GETATTR);
47991da177e4SLinus Torvalds }
48001da177e4SLinus Torvalds 
48011da177e4SLinus Torvalds static int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
48021da177e4SLinus Torvalds {
4803f8687afeSPaul Moore 	int err;
4804f8687afeSPaul Moore 
4805be0554c9SStephen Smalley 	err = sock_has_perm(sock->sk, SOCKET__SETOPT);
4806f8687afeSPaul Moore 	if (err)
4807f8687afeSPaul Moore 		return err;
4808f8687afeSPaul Moore 
4809f8687afeSPaul Moore 	return selinux_netlbl_socket_setsockopt(sock, level, optname);
48101da177e4SLinus Torvalds }
48111da177e4SLinus Torvalds 
48121da177e4SLinus Torvalds static int selinux_socket_getsockopt(struct socket *sock, int level,
48131da177e4SLinus Torvalds 				     int optname)
48141da177e4SLinus Torvalds {
4815be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__GETOPT);
48161da177e4SLinus Torvalds }
48171da177e4SLinus Torvalds 
48181da177e4SLinus Torvalds static int selinux_socket_shutdown(struct socket *sock, int how)
48191da177e4SLinus Torvalds {
4820be0554c9SStephen Smalley 	return sock_has_perm(sock->sk, SOCKET__SHUTDOWN);
48211da177e4SLinus Torvalds }
48221da177e4SLinus Torvalds 
48233610cda5SDavid S. Miller static int selinux_socket_unix_stream_connect(struct sock *sock,
48243610cda5SDavid S. Miller 					      struct sock *other,
48251da177e4SLinus Torvalds 					      struct sock *newsk)
48261da177e4SLinus Torvalds {
48273610cda5SDavid S. Miller 	struct sk_security_struct *sksec_sock = sock->sk_security;
48283610cda5SDavid S. Miller 	struct sk_security_struct *sksec_other = other->sk_security;
48294d1e2451SPaul Moore 	struct sk_security_struct *sksec_new = newsk->sk_security;
48302bf49690SThomas Liu 	struct common_audit_data ad;
483148c62af6SEric Paris 	struct lsm_network_audit net = {0,};
48321da177e4SLinus Torvalds 	int err;
48331da177e4SLinus Torvalds 
483450c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
483548c62af6SEric Paris 	ad.u.net = &net;
483648c62af6SEric Paris 	ad.u.net->sk = other;
48371da177e4SLinus Torvalds 
48386b6bc620SStephen Smalley 	err = avc_has_perm(&selinux_state,
48396b6bc620SStephen Smalley 			   sksec_sock->sid, sksec_other->sid,
48404d1e2451SPaul Moore 			   sksec_other->sclass,
48411da177e4SLinus Torvalds 			   UNIX_STREAM_SOCKET__CONNECTTO, &ad);
48421da177e4SLinus Torvalds 	if (err)
48431da177e4SLinus Torvalds 		return err;
48441da177e4SLinus Torvalds 
48451da177e4SLinus Torvalds 	/* server child socket */
48464d1e2451SPaul Moore 	sksec_new->peer_sid = sksec_sock->sid;
4847aa8e712cSStephen Smalley 	err = security_sid_mls_copy(&selinux_state, sksec_other->sid,
4848aa8e712cSStephen Smalley 				    sksec_sock->sid, &sksec_new->sid);
48494d1e2451SPaul Moore 	if (err)
48504237c75cSVenkat Yekkirala 		return err;
48514d1e2451SPaul Moore 
48524d1e2451SPaul Moore 	/* connecting socket */
48534d1e2451SPaul Moore 	sksec_sock->peer_sid = sksec_new->sid;
48544d1e2451SPaul Moore 
48554d1e2451SPaul Moore 	return 0;
48561da177e4SLinus Torvalds }
48571da177e4SLinus Torvalds 
48581da177e4SLinus Torvalds static int selinux_socket_unix_may_send(struct socket *sock,
48591da177e4SLinus Torvalds 					struct socket *other)
48601da177e4SLinus Torvalds {
4861253bfae6SPaul Moore 	struct sk_security_struct *ssec = sock->sk->sk_security;
4862253bfae6SPaul Moore 	struct sk_security_struct *osec = other->sk->sk_security;
48632bf49690SThomas Liu 	struct common_audit_data ad;
486448c62af6SEric Paris 	struct lsm_network_audit net = {0,};
48651da177e4SLinus Torvalds 
486650c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
486748c62af6SEric Paris 	ad.u.net = &net;
486848c62af6SEric Paris 	ad.u.net->sk = other->sk;
48691da177e4SLinus Torvalds 
48706b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
48716b6bc620SStephen Smalley 			    ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
4872253bfae6SPaul Moore 			    &ad);
48731da177e4SLinus Torvalds }
48741da177e4SLinus Torvalds 
4875cbe0d6e8SPaul Moore static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
4876cbe0d6e8SPaul Moore 				    char *addrp, u16 family, u32 peer_sid,
48772bf49690SThomas Liu 				    struct common_audit_data *ad)
4878effad8dfSPaul Moore {
4879effad8dfSPaul Moore 	int err;
4880effad8dfSPaul Moore 	u32 if_sid;
4881effad8dfSPaul Moore 	u32 node_sid;
4882effad8dfSPaul Moore 
4883cbe0d6e8SPaul Moore 	err = sel_netif_sid(ns, ifindex, &if_sid);
4884effad8dfSPaul Moore 	if (err)
4885effad8dfSPaul Moore 		return err;
48866b6bc620SStephen Smalley 	err = avc_has_perm(&selinux_state,
48876b6bc620SStephen Smalley 			   peer_sid, if_sid,
4888effad8dfSPaul Moore 			   SECCLASS_NETIF, NETIF__INGRESS, ad);
4889effad8dfSPaul Moore 	if (err)
4890effad8dfSPaul Moore 		return err;
4891effad8dfSPaul Moore 
4892effad8dfSPaul Moore 	err = sel_netnode_sid(addrp, family, &node_sid);
4893effad8dfSPaul Moore 	if (err)
4894effad8dfSPaul Moore 		return err;
48956b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
48966b6bc620SStephen Smalley 			    peer_sid, node_sid,
4897effad8dfSPaul Moore 			    SECCLASS_NODE, NODE__RECVFROM, ad);
4898effad8dfSPaul Moore }
4899effad8dfSPaul Moore 
4900220deb96SPaul Moore static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
4901d8395c87SPaul Moore 				       u16 family)
4902220deb96SPaul Moore {
4903277d342fSPaul Moore 	int err = 0;
4904220deb96SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
4905220deb96SPaul Moore 	u32 sk_sid = sksec->sid;
49062bf49690SThomas Liu 	struct common_audit_data ad;
490748c62af6SEric Paris 	struct lsm_network_audit net = {0,};
4908d8395c87SPaul Moore 	char *addrp;
4909d8395c87SPaul Moore 
491050c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
491148c62af6SEric Paris 	ad.u.net = &net;
491248c62af6SEric Paris 	ad.u.net->netif = skb->skb_iif;
491348c62af6SEric Paris 	ad.u.net->family = family;
4914d8395c87SPaul Moore 	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
4915d8395c87SPaul Moore 	if (err)
4916d8395c87SPaul Moore 		return err;
4917220deb96SPaul Moore 
491858bfbb51SPaul Moore 	if (selinux_secmark_enabled()) {
49196b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
49206b6bc620SStephen Smalley 				   sk_sid, skb->secmark, SECCLASS_PACKET,
4921d8395c87SPaul Moore 				   PACKET__RECV, &ad);
4922220deb96SPaul Moore 		if (err)
4923220deb96SPaul Moore 			return err;
492458bfbb51SPaul Moore 	}
4925220deb96SPaul Moore 
4926d8395c87SPaul Moore 	err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
4927220deb96SPaul Moore 	if (err)
4928220deb96SPaul Moore 		return err;
4929d8395c87SPaul Moore 	err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
4930220deb96SPaul Moore 
49314e5ab4cbSJames Morris 	return err;
49324e5ab4cbSJames Morris }
4933d28d1e08STrent Jaeger 
49344e5ab4cbSJames Morris static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
49354e5ab4cbSJames Morris {
4936220deb96SPaul Moore 	int err;
49374237c75cSVenkat Yekkirala 	struct sk_security_struct *sksec = sk->sk_security;
4938220deb96SPaul Moore 	u16 family = sk->sk_family;
4939220deb96SPaul Moore 	u32 sk_sid = sksec->sid;
49402bf49690SThomas Liu 	struct common_audit_data ad;
494148c62af6SEric Paris 	struct lsm_network_audit net = {0,};
4942220deb96SPaul Moore 	char *addrp;
4943d8395c87SPaul Moore 	u8 secmark_active;
4944d8395c87SPaul Moore 	u8 peerlbl_active;
49454e5ab4cbSJames Morris 
49464e5ab4cbSJames Morris 	if (family != PF_INET && family != PF_INET6)
4947220deb96SPaul Moore 		return 0;
49484e5ab4cbSJames Morris 
49494e5ab4cbSJames Morris 	/* Handle mapped IPv4 packets arriving via IPv6 sockets */
495087fcd70dSAl Viro 	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
49514e5ab4cbSJames Morris 		family = PF_INET;
49524e5ab4cbSJames Morris 
4953d8395c87SPaul Moore 	/* If any sort of compatibility mode is enabled then handoff processing
4954d8395c87SPaul Moore 	 * to the selinux_sock_rcv_skb_compat() function to deal with the
4955d8395c87SPaul Moore 	 * special handling.  We do this in an attempt to keep this function
4956d8395c87SPaul Moore 	 * as fast and as clean as possible. */
4957aa8e712cSStephen Smalley 	if (!selinux_policycap_netpeer())
4958d8395c87SPaul Moore 		return selinux_sock_rcv_skb_compat(sk, skb, family);
4959d8395c87SPaul Moore 
4960d8395c87SPaul Moore 	secmark_active = selinux_secmark_enabled();
49612be4d74fSChris PeBenito 	peerlbl_active = selinux_peerlbl_enabled();
4962d8395c87SPaul Moore 	if (!secmark_active && !peerlbl_active)
4963d8395c87SPaul Moore 		return 0;
4964d8395c87SPaul Moore 
496550c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
496648c62af6SEric Paris 	ad.u.net = &net;
496748c62af6SEric Paris 	ad.u.net->netif = skb->skb_iif;
496848c62af6SEric Paris 	ad.u.net->family = family;
4969224dfbd8SPaul Moore 	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
49704e5ab4cbSJames Morris 	if (err)
4971220deb96SPaul Moore 		return err;
49724e5ab4cbSJames Morris 
4973d8395c87SPaul Moore 	if (peerlbl_active) {
4974d621d35eSPaul Moore 		u32 peer_sid;
4975220deb96SPaul Moore 
4976220deb96SPaul Moore 		err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
4977220deb96SPaul Moore 		if (err)
4978220deb96SPaul Moore 			return err;
4979cbe0d6e8SPaul Moore 		err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
4980cbe0d6e8SPaul Moore 					       addrp, family, peer_sid, &ad);
4981dfaebe98SPaul Moore 		if (err) {
4982a04e71f6SHuw Davies 			selinux_netlbl_err(skb, family, err, 0);
4983effad8dfSPaul Moore 			return err;
4984dfaebe98SPaul Moore 		}
49856b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
49866b6bc620SStephen Smalley 				   sk_sid, peer_sid, SECCLASS_PEER,
4987d621d35eSPaul Moore 				   PEER__RECV, &ad);
498846d01d63SChad Hanson 		if (err) {
4989a04e71f6SHuw Davies 			selinux_netlbl_err(skb, family, err, 0);
499046d01d63SChad Hanson 			return err;
499146d01d63SChad Hanson 		}
4992d621d35eSPaul Moore 	}
4993d621d35eSPaul Moore 
4994d8395c87SPaul Moore 	if (secmark_active) {
49956b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
49966b6bc620SStephen Smalley 				   sk_sid, skb->secmark, SECCLASS_PACKET,
4997effad8dfSPaul Moore 				   PACKET__RECV, &ad);
4998effad8dfSPaul Moore 		if (err)
4999effad8dfSPaul Moore 			return err;
5000effad8dfSPaul Moore 	}
5001effad8dfSPaul Moore 
5002d621d35eSPaul Moore 	return err;
50031da177e4SLinus Torvalds }
50041da177e4SLinus Torvalds 
50052c7946a7SCatherine Zhang static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
50061da177e4SLinus Torvalds 					    int __user *optlen, unsigned len)
50071da177e4SLinus Torvalds {
50081da177e4SLinus Torvalds 	int err = 0;
50091da177e4SLinus Torvalds 	char *scontext;
50101da177e4SLinus Torvalds 	u32 scontext_len;
5011253bfae6SPaul Moore 	struct sk_security_struct *sksec = sock->sk->sk_security;
50123de4bab5SPaul Moore 	u32 peer_sid = SECSID_NULL;
50131da177e4SLinus Torvalds 
5014253bfae6SPaul Moore 	if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
5015d452930fSRichard Haines 	    sksec->sclass == SECCLASS_TCP_SOCKET ||
5016d452930fSRichard Haines 	    sksec->sclass == SECCLASS_SCTP_SOCKET)
5017dd3e7836SEric Paris 		peer_sid = sksec->peer_sid;
5018253bfae6SPaul Moore 	if (peer_sid == SECSID_NULL)
5019253bfae6SPaul Moore 		return -ENOPROTOOPT;
50201da177e4SLinus Torvalds 
5021aa8e712cSStephen Smalley 	err = security_sid_to_context(&selinux_state, peer_sid, &scontext,
5022aa8e712cSStephen Smalley 				      &scontext_len);
50231da177e4SLinus Torvalds 	if (err)
5024253bfae6SPaul Moore 		return err;
50251da177e4SLinus Torvalds 
50261da177e4SLinus Torvalds 	if (scontext_len > len) {
50271da177e4SLinus Torvalds 		err = -ERANGE;
50281da177e4SLinus Torvalds 		goto out_len;
50291da177e4SLinus Torvalds 	}
50301da177e4SLinus Torvalds 
50311da177e4SLinus Torvalds 	if (copy_to_user(optval, scontext, scontext_len))
50321da177e4SLinus Torvalds 		err = -EFAULT;
50331da177e4SLinus Torvalds 
50341da177e4SLinus Torvalds out_len:
50351da177e4SLinus Torvalds 	if (put_user(scontext_len, optlen))
50361da177e4SLinus Torvalds 		err = -EFAULT;
50371da177e4SLinus Torvalds 	kfree(scontext);
50381da177e4SLinus Torvalds 	return err;
50391da177e4SLinus Torvalds }
50401da177e4SLinus Torvalds 
5041dc49c1f9SCatherine Zhang static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
50422c7946a7SCatherine Zhang {
5043dc49c1f9SCatherine Zhang 	u32 peer_secid = SECSID_NULL;
504475e22910SPaul Moore 	u16 family;
5045899134f2SPaul Moore 	struct inode_security_struct *isec;
5046877ce7c1SCatherine Zhang 
5047aa862900SPaul Moore 	if (skb && skb->protocol == htons(ETH_P_IP))
5048aa862900SPaul Moore 		family = PF_INET;
5049aa862900SPaul Moore 	else if (skb && skb->protocol == htons(ETH_P_IPV6))
5050aa862900SPaul Moore 		family = PF_INET6;
5051aa862900SPaul Moore 	else if (sock)
505275e22910SPaul Moore 		family = sock->sk->sk_family;
505375e22910SPaul Moore 	else
505475e22910SPaul Moore 		goto out;
505575e22910SPaul Moore 
5056899134f2SPaul Moore 	if (sock && family == PF_UNIX) {
5057899134f2SPaul Moore 		isec = inode_security_novalidate(SOCK_INODE(sock));
5058899134f2SPaul Moore 		peer_secid = isec->sid;
5059899134f2SPaul Moore 	} else if (skb)
5060220deb96SPaul Moore 		selinux_skb_peerlbl_sid(skb, family, &peer_secid);
50612c7946a7SCatherine Zhang 
506275e22910SPaul Moore out:
5063dc49c1f9SCatherine Zhang 	*secid = peer_secid;
506475e22910SPaul Moore 	if (peer_secid == SECSID_NULL)
506575e22910SPaul Moore 		return -EINVAL;
506675e22910SPaul Moore 	return 0;
50672c7946a7SCatherine Zhang }
50682c7946a7SCatherine Zhang 
50697d877f3bSAl Viro static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
50701da177e4SLinus Torvalds {
507184914b7eSPaul Moore 	struct sk_security_struct *sksec;
507284914b7eSPaul Moore 
507384914b7eSPaul Moore 	sksec = kzalloc(sizeof(*sksec), priority);
507484914b7eSPaul Moore 	if (!sksec)
507584914b7eSPaul Moore 		return -ENOMEM;
507684914b7eSPaul Moore 
507784914b7eSPaul Moore 	sksec->peer_sid = SECINITSID_UNLABELED;
507884914b7eSPaul Moore 	sksec->sid = SECINITSID_UNLABELED;
50795dee25d0SStephen Smalley 	sksec->sclass = SECCLASS_SOCKET;
508084914b7eSPaul Moore 	selinux_netlbl_sk_security_reset(sksec);
508184914b7eSPaul Moore 	sk->sk_security = sksec;
508284914b7eSPaul Moore 
508384914b7eSPaul Moore 	return 0;
50841da177e4SLinus Torvalds }
50851da177e4SLinus Torvalds 
50861da177e4SLinus Torvalds static void selinux_sk_free_security(struct sock *sk)
50871da177e4SLinus Torvalds {
508884914b7eSPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
508984914b7eSPaul Moore 
509084914b7eSPaul Moore 	sk->sk_security = NULL;
509184914b7eSPaul Moore 	selinux_netlbl_sk_security_free(sksec);
509284914b7eSPaul Moore 	kfree(sksec);
50931da177e4SLinus Torvalds }
50941da177e4SLinus Torvalds 
5095892c141eSVenkat Yekkirala static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
5096892c141eSVenkat Yekkirala {
5097dd3e7836SEric Paris 	struct sk_security_struct *sksec = sk->sk_security;
5098dd3e7836SEric Paris 	struct sk_security_struct *newsksec = newsk->sk_security;
5099892c141eSVenkat Yekkirala 
5100dd3e7836SEric Paris 	newsksec->sid = sksec->sid;
5101dd3e7836SEric Paris 	newsksec->peer_sid = sksec->peer_sid;
5102dd3e7836SEric Paris 	newsksec->sclass = sksec->sclass;
510399f59ed0SPaul Moore 
5104dd3e7836SEric Paris 	selinux_netlbl_sk_security_reset(newsksec);
5105892c141eSVenkat Yekkirala }
5106892c141eSVenkat Yekkirala 
5107beb8d13bSVenkat Yekkirala static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
5108d28d1e08STrent Jaeger {
5109d28d1e08STrent Jaeger 	if (!sk)
5110beb8d13bSVenkat Yekkirala 		*secid = SECINITSID_ANY_SOCKET;
5111892c141eSVenkat Yekkirala 	else {
5112892c141eSVenkat Yekkirala 		struct sk_security_struct *sksec = sk->sk_security;
5113d28d1e08STrent Jaeger 
5114beb8d13bSVenkat Yekkirala 		*secid = sksec->sid;
5115892c141eSVenkat Yekkirala 	}
5116d28d1e08STrent Jaeger }
5117d28d1e08STrent Jaeger 
51189a673e56SAdrian Bunk static void selinux_sock_graft(struct sock *sk, struct socket *parent)
51194237c75cSVenkat Yekkirala {
51205d226df4SAndreas Gruenbacher 	struct inode_security_struct *isec =
51215d226df4SAndreas Gruenbacher 		inode_security_novalidate(SOCK_INODE(parent));
51224237c75cSVenkat Yekkirala 	struct sk_security_struct *sksec = sk->sk_security;
51234237c75cSVenkat Yekkirala 
51242873ead7SPaul Moore 	if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
51252873ead7SPaul Moore 	    sk->sk_family == PF_UNIX)
51264237c75cSVenkat Yekkirala 		isec->sid = sksec->sid;
5127220deb96SPaul Moore 	sksec->sclass = isec->sclass;
51284237c75cSVenkat Yekkirala }
51294237c75cSVenkat Yekkirala 
5130d452930fSRichard Haines /* Called whenever SCTP receives an INIT chunk. This happens when an incoming
5131d452930fSRichard Haines  * connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association
5132d452930fSRichard Haines  * already present).
5133d452930fSRichard Haines  */
5134d452930fSRichard Haines static int selinux_sctp_assoc_request(struct sctp_endpoint *ep,
5135d452930fSRichard Haines 				      struct sk_buff *skb)
5136d452930fSRichard Haines {
5137d452930fSRichard Haines 	struct sk_security_struct *sksec = ep->base.sk->sk_security;
5138d452930fSRichard Haines 	struct common_audit_data ad;
5139d452930fSRichard Haines 	struct lsm_network_audit net = {0,};
5140d452930fSRichard Haines 	u8 peerlbl_active;
5141d452930fSRichard Haines 	u32 peer_sid = SECINITSID_UNLABELED;
5142d452930fSRichard Haines 	u32 conn_sid;
5143d452930fSRichard Haines 	int err = 0;
5144d452930fSRichard Haines 
5145aa8e712cSStephen Smalley 	if (!selinux_policycap_extsockclass())
5146d452930fSRichard Haines 		return 0;
5147d452930fSRichard Haines 
5148d452930fSRichard Haines 	peerlbl_active = selinux_peerlbl_enabled();
5149d452930fSRichard Haines 
5150d452930fSRichard Haines 	if (peerlbl_active) {
5151d452930fSRichard Haines 		/* This will return peer_sid = SECSID_NULL if there are
5152d452930fSRichard Haines 		 * no peer labels, see security_net_peersid_resolve().
5153d452930fSRichard Haines 		 */
5154d452930fSRichard Haines 		err = selinux_skb_peerlbl_sid(skb, ep->base.sk->sk_family,
5155d452930fSRichard Haines 					      &peer_sid);
5156d452930fSRichard Haines 		if (err)
5157d452930fSRichard Haines 			return err;
5158d452930fSRichard Haines 
5159d452930fSRichard Haines 		if (peer_sid == SECSID_NULL)
5160d452930fSRichard Haines 			peer_sid = SECINITSID_UNLABELED;
5161d452930fSRichard Haines 	}
5162d452930fSRichard Haines 
5163d452930fSRichard Haines 	if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
5164d452930fSRichard Haines 		sksec->sctp_assoc_state = SCTP_ASSOC_SET;
5165d452930fSRichard Haines 
5166d452930fSRichard Haines 		/* Here as first association on socket. As the peer SID
5167d452930fSRichard Haines 		 * was allowed by peer recv (and the netif/node checks),
5168d452930fSRichard Haines 		 * then it is approved by policy and used as the primary
5169d452930fSRichard Haines 		 * peer SID for getpeercon(3).
5170d452930fSRichard Haines 		 */
5171d452930fSRichard Haines 		sksec->peer_sid = peer_sid;
5172d452930fSRichard Haines 	} else if  (sksec->peer_sid != peer_sid) {
5173d452930fSRichard Haines 		/* Other association peer SIDs are checked to enforce
5174d452930fSRichard Haines 		 * consistency among the peer SIDs.
5175d452930fSRichard Haines 		 */
5176d452930fSRichard Haines 		ad.type = LSM_AUDIT_DATA_NET;
5177d452930fSRichard Haines 		ad.u.net = &net;
5178d452930fSRichard Haines 		ad.u.net->sk = ep->base.sk;
51796b6bc620SStephen Smalley 		err = avc_has_perm(&selinux_state,
51806b6bc620SStephen Smalley 				   sksec->peer_sid, peer_sid, sksec->sclass,
5181d452930fSRichard Haines 				   SCTP_SOCKET__ASSOCIATION, &ad);
5182d452930fSRichard Haines 		if (err)
5183d452930fSRichard Haines 			return err;
5184d452930fSRichard Haines 	}
5185d452930fSRichard Haines 
5186d452930fSRichard Haines 	/* Compute the MLS component for the connection and store
5187d452930fSRichard Haines 	 * the information in ep. This will be used by SCTP TCP type
5188d452930fSRichard Haines 	 * sockets and peeled off connections as they cause a new
5189d452930fSRichard Haines 	 * socket to be generated. selinux_sctp_sk_clone() will then
5190d452930fSRichard Haines 	 * plug this into the new socket.
5191d452930fSRichard Haines 	 */
5192d452930fSRichard Haines 	err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid);
5193d452930fSRichard Haines 	if (err)
5194d452930fSRichard Haines 		return err;
5195d452930fSRichard Haines 
5196d452930fSRichard Haines 	ep->secid = conn_sid;
5197d452930fSRichard Haines 	ep->peer_secid = peer_sid;
5198d452930fSRichard Haines 
5199d452930fSRichard Haines 	/* Set any NetLabel labels including CIPSO/CALIPSO options. */
5200d452930fSRichard Haines 	return selinux_netlbl_sctp_assoc_request(ep, skb);
5201d452930fSRichard Haines }
5202d452930fSRichard Haines 
5203d452930fSRichard Haines /* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting
5204d452930fSRichard Haines  * based on their @optname.
5205d452930fSRichard Haines  */
5206d452930fSRichard Haines static int selinux_sctp_bind_connect(struct sock *sk, int optname,
5207d452930fSRichard Haines 				     struct sockaddr *address,
5208d452930fSRichard Haines 				     int addrlen)
5209d452930fSRichard Haines {
5210d452930fSRichard Haines 	int len, err = 0, walk_size = 0;
5211d452930fSRichard Haines 	void *addr_buf;
5212d452930fSRichard Haines 	struct sockaddr *addr;
5213d452930fSRichard Haines 	struct socket *sock;
5214d452930fSRichard Haines 
5215aa8e712cSStephen Smalley 	if (!selinux_policycap_extsockclass())
5216d452930fSRichard Haines 		return 0;
5217d452930fSRichard Haines 
5218d452930fSRichard Haines 	/* Process one or more addresses that may be IPv4 or IPv6 */
5219d452930fSRichard Haines 	sock = sk->sk_socket;
5220d452930fSRichard Haines 	addr_buf = address;
5221d452930fSRichard Haines 
5222d452930fSRichard Haines 	while (walk_size < addrlen) {
5223c138325fSOndrej Mosnacek 		if (walk_size + sizeof(sa_family_t) > addrlen)
5224c138325fSOndrej Mosnacek 			return -EINVAL;
5225c138325fSOndrej Mosnacek 
5226d452930fSRichard Haines 		addr = addr_buf;
5227d452930fSRichard Haines 		switch (addr->sa_family) {
52284152dc91SAlexey Kodanev 		case AF_UNSPEC:
5229d452930fSRichard Haines 		case AF_INET:
5230d452930fSRichard Haines 			len = sizeof(struct sockaddr_in);
5231d452930fSRichard Haines 			break;
5232d452930fSRichard Haines 		case AF_INET6:
5233d452930fSRichard Haines 			len = sizeof(struct sockaddr_in6);
5234d452930fSRichard Haines 			break;
5235d452930fSRichard Haines 		default:
52364152dc91SAlexey Kodanev 			return -EINVAL;
5237d452930fSRichard Haines 		}
5238d452930fSRichard Haines 
5239292c997aSXin Long 		if (walk_size + len > addrlen)
5240292c997aSXin Long 			return -EINVAL;
5241292c997aSXin Long 
5242d452930fSRichard Haines 		err = -EINVAL;
5243d452930fSRichard Haines 		switch (optname) {
5244d452930fSRichard Haines 		/* Bind checks */
5245d452930fSRichard Haines 		case SCTP_PRIMARY_ADDR:
5246d452930fSRichard Haines 		case SCTP_SET_PEER_PRIMARY_ADDR:
5247d452930fSRichard Haines 		case SCTP_SOCKOPT_BINDX_ADD:
5248d452930fSRichard Haines 			err = selinux_socket_bind(sock, addr, len);
5249d452930fSRichard Haines 			break;
5250d452930fSRichard Haines 		/* Connect checks */
5251d452930fSRichard Haines 		case SCTP_SOCKOPT_CONNECTX:
5252d452930fSRichard Haines 		case SCTP_PARAM_SET_PRIMARY:
5253d452930fSRichard Haines 		case SCTP_PARAM_ADD_IP:
5254d452930fSRichard Haines 		case SCTP_SENDMSG_CONNECT:
5255d452930fSRichard Haines 			err = selinux_socket_connect_helper(sock, addr, len);
5256d452930fSRichard Haines 			if (err)
5257d452930fSRichard Haines 				return err;
5258d452930fSRichard Haines 
5259d452930fSRichard Haines 			/* As selinux_sctp_bind_connect() is called by the
5260d452930fSRichard Haines 			 * SCTP protocol layer, the socket is already locked,
5261d452930fSRichard Haines 			 * therefore selinux_netlbl_socket_connect_locked() is
5262d452930fSRichard Haines 			 * is called here. The situations handled are:
5263d452930fSRichard Haines 			 * sctp_connectx(3), sctp_sendmsg(3), sendmsg(2),
5264d452930fSRichard Haines 			 * whenever a new IP address is added or when a new
5265d452930fSRichard Haines 			 * primary address is selected.
5266d452930fSRichard Haines 			 * Note that an SCTP connect(2) call happens before
5267d452930fSRichard Haines 			 * the SCTP protocol layer and is handled via
5268d452930fSRichard Haines 			 * selinux_socket_connect().
5269d452930fSRichard Haines 			 */
5270d452930fSRichard Haines 			err = selinux_netlbl_socket_connect_locked(sk, addr);
5271d452930fSRichard Haines 			break;
5272d452930fSRichard Haines 		}
5273d452930fSRichard Haines 
5274d452930fSRichard Haines 		if (err)
5275d452930fSRichard Haines 			return err;
5276d452930fSRichard Haines 
5277d452930fSRichard Haines 		addr_buf += len;
5278d452930fSRichard Haines 		walk_size += len;
5279d452930fSRichard Haines 	}
5280d452930fSRichard Haines 
5281d452930fSRichard Haines 	return 0;
5282d452930fSRichard Haines }
5283d452930fSRichard Haines 
5284d452930fSRichard Haines /* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */
5285d452930fSRichard Haines static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
5286d452930fSRichard Haines 				  struct sock *newsk)
5287d452930fSRichard Haines {
5288d452930fSRichard Haines 	struct sk_security_struct *sksec = sk->sk_security;
5289d452930fSRichard Haines 	struct sk_security_struct *newsksec = newsk->sk_security;
5290d452930fSRichard Haines 
5291d452930fSRichard Haines 	/* If policy does not support SECCLASS_SCTP_SOCKET then call
5292d452930fSRichard Haines 	 * the non-sctp clone version.
5293d452930fSRichard Haines 	 */
5294aa8e712cSStephen Smalley 	if (!selinux_policycap_extsockclass())
5295d452930fSRichard Haines 		return selinux_sk_clone_security(sk, newsk);
5296d452930fSRichard Haines 
5297d452930fSRichard Haines 	newsksec->sid = ep->secid;
5298d452930fSRichard Haines 	newsksec->peer_sid = ep->peer_secid;
5299d452930fSRichard Haines 	newsksec->sclass = sksec->sclass;
5300d452930fSRichard Haines 	selinux_netlbl_sctp_sk_clone(sk, newsk);
5301d452930fSRichard Haines }
5302d452930fSRichard Haines 
53039a673e56SAdrian Bunk static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
53044237c75cSVenkat Yekkirala 				     struct request_sock *req)
53054237c75cSVenkat Yekkirala {
53064237c75cSVenkat Yekkirala 	struct sk_security_struct *sksec = sk->sk_security;
53074237c75cSVenkat Yekkirala 	int err;
53080b1f24e6SPaul Moore 	u16 family = req->rsk_ops->family;
5309446b8024SPaul Moore 	u32 connsid;
53104237c75cSVenkat Yekkirala 	u32 peersid;
53114237c75cSVenkat Yekkirala 
5312aa862900SPaul Moore 	err = selinux_skb_peerlbl_sid(skb, family, &peersid);
5313220deb96SPaul Moore 	if (err)
5314220deb96SPaul Moore 		return err;
5315446b8024SPaul Moore 	err = selinux_conn_sid(sksec->sid, peersid, &connsid);
53164237c75cSVenkat Yekkirala 	if (err)
53174237c75cSVenkat Yekkirala 		return err;
5318446b8024SPaul Moore 	req->secid = connsid;
53196b877699SVenkat Yekkirala 	req->peer_secid = peersid;
5320389fb800SPaul Moore 
5321389fb800SPaul Moore 	return selinux_netlbl_inet_conn_request(req, family);
53224237c75cSVenkat Yekkirala }
53234237c75cSVenkat Yekkirala 
53249a673e56SAdrian Bunk static void selinux_inet_csk_clone(struct sock *newsk,
53259a673e56SAdrian Bunk 				   const struct request_sock *req)
53264237c75cSVenkat Yekkirala {
53274237c75cSVenkat Yekkirala 	struct sk_security_struct *newsksec = newsk->sk_security;
53284237c75cSVenkat Yekkirala 
53294237c75cSVenkat Yekkirala 	newsksec->sid = req->secid;
53306b877699SVenkat Yekkirala 	newsksec->peer_sid = req->peer_secid;
53314237c75cSVenkat Yekkirala 	/* NOTE: Ideally, we should also get the isec->sid for the
53324237c75cSVenkat Yekkirala 	   new socket in sync, but we don't have the isec available yet.
53334237c75cSVenkat Yekkirala 	   So we will wait until sock_graft to do it, by which
53344237c75cSVenkat Yekkirala 	   time it will have been created and available. */
533599f59ed0SPaul Moore 
53369f2ad665SPaul Moore 	/* We don't need to take any sort of lock here as we are the only
53379f2ad665SPaul Moore 	 * thread with access to newsksec */
5338389fb800SPaul Moore 	selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
53394237c75cSVenkat Yekkirala }
53404237c75cSVenkat Yekkirala 
5341014ab19aSPaul Moore static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
53426b877699SVenkat Yekkirala {
5343aa862900SPaul Moore 	u16 family = sk->sk_family;
53446b877699SVenkat Yekkirala 	struct sk_security_struct *sksec = sk->sk_security;
53456b877699SVenkat Yekkirala 
5346aa862900SPaul Moore 	/* handle mapped IPv4 packets arriving via IPv6 sockets */
5347aa862900SPaul Moore 	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
5348aa862900SPaul Moore 		family = PF_INET;
5349aa862900SPaul Moore 
5350aa862900SPaul Moore 	selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
53516b877699SVenkat Yekkirala }
53526b877699SVenkat Yekkirala 
53532606fd1fSEric Paris static int selinux_secmark_relabel_packet(u32 sid)
53542606fd1fSEric Paris {
53552606fd1fSEric Paris 	const struct task_security_struct *__tsec;
53562606fd1fSEric Paris 	u32 tsid;
53572606fd1fSEric Paris 
53580c6cfa62SCasey Schaufler 	__tsec = selinux_cred(current_cred());
53592606fd1fSEric Paris 	tsid = __tsec->sid;
53602606fd1fSEric Paris 
53616b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
53626b6bc620SStephen Smalley 			    tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
53636b6bc620SStephen Smalley 			    NULL);
53642606fd1fSEric Paris }
53652606fd1fSEric Paris 
53662606fd1fSEric Paris static void selinux_secmark_refcount_inc(void)
53672606fd1fSEric Paris {
53682606fd1fSEric Paris 	atomic_inc(&selinux_secmark_refcount);
53692606fd1fSEric Paris }
53702606fd1fSEric Paris 
53712606fd1fSEric Paris static void selinux_secmark_refcount_dec(void)
53722606fd1fSEric Paris {
53732606fd1fSEric Paris 	atomic_dec(&selinux_secmark_refcount);
53742606fd1fSEric Paris }
53752606fd1fSEric Paris 
53769a673e56SAdrian Bunk static void selinux_req_classify_flow(const struct request_sock *req,
53779a673e56SAdrian Bunk 				      struct flowi *fl)
53784237c75cSVenkat Yekkirala {
53791d28f42cSDavid S. Miller 	fl->flowi_secid = req->secid;
53804237c75cSVenkat Yekkirala }
53814237c75cSVenkat Yekkirala 
53825dbbaf2dSPaul Moore static int selinux_tun_dev_alloc_security(void **security)
53835dbbaf2dSPaul Moore {
53845dbbaf2dSPaul Moore 	struct tun_security_struct *tunsec;
53855dbbaf2dSPaul Moore 
53865dbbaf2dSPaul Moore 	tunsec = kzalloc(sizeof(*tunsec), GFP_KERNEL);
53875dbbaf2dSPaul Moore 	if (!tunsec)
53885dbbaf2dSPaul Moore 		return -ENOMEM;
53895dbbaf2dSPaul Moore 	tunsec->sid = current_sid();
53905dbbaf2dSPaul Moore 
53915dbbaf2dSPaul Moore 	*security = tunsec;
53925dbbaf2dSPaul Moore 	return 0;
53935dbbaf2dSPaul Moore }
53945dbbaf2dSPaul Moore 
53955dbbaf2dSPaul Moore static void selinux_tun_dev_free_security(void *security)
53965dbbaf2dSPaul Moore {
53975dbbaf2dSPaul Moore 	kfree(security);
53985dbbaf2dSPaul Moore }
53995dbbaf2dSPaul Moore 
5400ed6d76e4SPaul Moore static int selinux_tun_dev_create(void)
5401ed6d76e4SPaul Moore {
5402ed6d76e4SPaul Moore 	u32 sid = current_sid();
5403ed6d76e4SPaul Moore 
5404ed6d76e4SPaul Moore 	/* we aren't taking into account the "sockcreate" SID since the socket
5405ed6d76e4SPaul Moore 	 * that is being created here is not a socket in the traditional sense,
5406ed6d76e4SPaul Moore 	 * instead it is a private sock, accessible only to the kernel, and
5407ed6d76e4SPaul Moore 	 * representing a wide range of network traffic spanning multiple
5408ed6d76e4SPaul Moore 	 * connections unlike traditional sockets - check the TUN driver to
5409ed6d76e4SPaul Moore 	 * get a better understanding of why this socket is special */
5410ed6d76e4SPaul Moore 
54116b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
54126b6bc620SStephen Smalley 			    sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
5413ed6d76e4SPaul Moore 			    NULL);
5414ed6d76e4SPaul Moore }
5415ed6d76e4SPaul Moore 
54165dbbaf2dSPaul Moore static int selinux_tun_dev_attach_queue(void *security)
5417ed6d76e4SPaul Moore {
54185dbbaf2dSPaul Moore 	struct tun_security_struct *tunsec = security;
54195dbbaf2dSPaul Moore 
54206b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
54216b6bc620SStephen Smalley 			    current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
54225dbbaf2dSPaul Moore 			    TUN_SOCKET__ATTACH_QUEUE, NULL);
54235dbbaf2dSPaul Moore }
54245dbbaf2dSPaul Moore 
54255dbbaf2dSPaul Moore static int selinux_tun_dev_attach(struct sock *sk, void *security)
54265dbbaf2dSPaul Moore {
54275dbbaf2dSPaul Moore 	struct tun_security_struct *tunsec = security;
5428ed6d76e4SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
5429ed6d76e4SPaul Moore 
5430ed6d76e4SPaul Moore 	/* we don't currently perform any NetLabel based labeling here and it
5431ed6d76e4SPaul Moore 	 * isn't clear that we would want to do so anyway; while we could apply
5432ed6d76e4SPaul Moore 	 * labeling without the support of the TUN user the resulting labeled
5433ed6d76e4SPaul Moore 	 * traffic from the other end of the connection would almost certainly
5434ed6d76e4SPaul Moore 	 * cause confusion to the TUN user that had no idea network labeling
5435ed6d76e4SPaul Moore 	 * protocols were being used */
5436ed6d76e4SPaul Moore 
54375dbbaf2dSPaul Moore 	sksec->sid = tunsec->sid;
5438ed6d76e4SPaul Moore 	sksec->sclass = SECCLASS_TUN_SOCKET;
54395dbbaf2dSPaul Moore 
54405dbbaf2dSPaul Moore 	return 0;
5441ed6d76e4SPaul Moore }
5442ed6d76e4SPaul Moore 
54435dbbaf2dSPaul Moore static int selinux_tun_dev_open(void *security)
5444ed6d76e4SPaul Moore {
54455dbbaf2dSPaul Moore 	struct tun_security_struct *tunsec = security;
5446ed6d76e4SPaul Moore 	u32 sid = current_sid();
5447ed6d76e4SPaul Moore 	int err;
5448ed6d76e4SPaul Moore 
54496b6bc620SStephen Smalley 	err = avc_has_perm(&selinux_state,
54506b6bc620SStephen Smalley 			   sid, tunsec->sid, SECCLASS_TUN_SOCKET,
5451ed6d76e4SPaul Moore 			   TUN_SOCKET__RELABELFROM, NULL);
5452ed6d76e4SPaul Moore 	if (err)
5453ed6d76e4SPaul Moore 		return err;
54546b6bc620SStephen Smalley 	err = avc_has_perm(&selinux_state,
54556b6bc620SStephen Smalley 			   sid, sid, SECCLASS_TUN_SOCKET,
5456ed6d76e4SPaul Moore 			   TUN_SOCKET__RELABELTO, NULL);
5457ed6d76e4SPaul Moore 	if (err)
5458ed6d76e4SPaul Moore 		return err;
54595dbbaf2dSPaul Moore 	tunsec->sid = sid;
5460ed6d76e4SPaul Moore 
5461ed6d76e4SPaul Moore 	return 0;
5462ed6d76e4SPaul Moore }
5463ed6d76e4SPaul Moore 
54641da177e4SLinus Torvalds static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
54651da177e4SLinus Torvalds {
54661da177e4SLinus Torvalds 	int err = 0;
54671da177e4SLinus Torvalds 	u32 perm;
54681da177e4SLinus Torvalds 	struct nlmsghdr *nlh;
5469253bfae6SPaul Moore 	struct sk_security_struct *sksec = sk->sk_security;
54701da177e4SLinus Torvalds 
547177954983SHong zhi guo 	if (skb->len < NLMSG_HDRLEN) {
54721da177e4SLinus Torvalds 		err = -EINVAL;
54731da177e4SLinus Torvalds 		goto out;
54741da177e4SLinus Torvalds 	}
5475b529ccf2SArnaldo Carvalho de Melo 	nlh = nlmsg_hdr(skb);
54761da177e4SLinus Torvalds 
5477253bfae6SPaul Moore 	err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm);
54781da177e4SLinus Torvalds 	if (err) {
54791da177e4SLinus Torvalds 		if (err == -EINVAL) {
548076319946SVladis Dronov 			pr_warn_ratelimited("SELinux: unrecognized netlink"
548176319946SVladis Dronov 			       " message: protocol=%hu nlmsg_type=%hu sclass=%s"
548276319946SVladis Dronov 			       " pig=%d comm=%s\n",
5483cded3fffSMarek Milkovic 			       sk->sk_protocol, nlh->nlmsg_type,
548476319946SVladis Dronov 			       secclass_map[sksec->sclass - 1].name,
548576319946SVladis Dronov 			       task_pid_nr(current), current->comm);
5486e5a5ca96SPaul Moore 			if (!enforcing_enabled(&selinux_state) ||
5487aa8e712cSStephen Smalley 			    security_get_allow_unknown(&selinux_state))
54881da177e4SLinus Torvalds 				err = 0;
54891da177e4SLinus Torvalds 		}
54901da177e4SLinus Torvalds 
54911da177e4SLinus Torvalds 		/* Ignore */
54921da177e4SLinus Torvalds 		if (err == -ENOENT)
54931da177e4SLinus Torvalds 			err = 0;
54941da177e4SLinus Torvalds 		goto out;
54951da177e4SLinus Torvalds 	}
54961da177e4SLinus Torvalds 
5497be0554c9SStephen Smalley 	err = sock_has_perm(sk, perm);
54981da177e4SLinus Torvalds out:
54991da177e4SLinus Torvalds 	return err;
55001da177e4SLinus Torvalds }
55011da177e4SLinus Torvalds 
55021da177e4SLinus Torvalds #ifdef CONFIG_NETFILTER
55031da177e4SLinus Torvalds 
5504cbe0d6e8SPaul Moore static unsigned int selinux_ip_forward(struct sk_buff *skb,
5505cbe0d6e8SPaul Moore 				       const struct net_device *indev,
5506effad8dfSPaul Moore 				       u16 family)
55071da177e4SLinus Torvalds {
5508dfaebe98SPaul Moore 	int err;
5509effad8dfSPaul Moore 	char *addrp;
5510effad8dfSPaul Moore 	u32 peer_sid;
55112bf49690SThomas Liu 	struct common_audit_data ad;
551248c62af6SEric Paris 	struct lsm_network_audit net = {0,};
5513effad8dfSPaul Moore 	u8 secmark_active;
5514948bf85cSPaul Moore 	u8 netlbl_active;
5515effad8dfSPaul Moore 	u8 peerlbl_active;
55164237c75cSVenkat Yekkirala 
5517aa8e712cSStephen Smalley 	if (!selinux_policycap_netpeer())
5518effad8dfSPaul Moore 		return NF_ACCEPT;
55194237c75cSVenkat Yekkirala 
5520effad8dfSPaul Moore 	secmark_active = selinux_secmark_enabled();
5521948bf85cSPaul Moore 	netlbl_active = netlbl_enabled();
55222be4d74fSChris PeBenito 	peerlbl_active = selinux_peerlbl_enabled();
5523effad8dfSPaul Moore 	if (!secmark_active && !peerlbl_active)
5524effad8dfSPaul Moore 		return NF_ACCEPT;
55254237c75cSVenkat Yekkirala 
5526d8395c87SPaul Moore 	if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
5527d8395c87SPaul Moore 		return NF_DROP;
5528d8395c87SPaul Moore 
552950c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
553048c62af6SEric Paris 	ad.u.net = &net;
5531cbe0d6e8SPaul Moore 	ad.u.net->netif = indev->ifindex;
553248c62af6SEric Paris 	ad.u.net->family = family;
5533effad8dfSPaul Moore 	if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
5534effad8dfSPaul Moore 		return NF_DROP;
55351da177e4SLinus Torvalds 
5536dfaebe98SPaul Moore 	if (peerlbl_active) {
5537cbe0d6e8SPaul Moore 		err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex,
5538cbe0d6e8SPaul Moore 					       addrp, family, peer_sid, &ad);
5539dfaebe98SPaul Moore 		if (err) {
5540a04e71f6SHuw Davies 			selinux_netlbl_err(skb, family, err, 1);
5541effad8dfSPaul Moore 			return NF_DROP;
5542dfaebe98SPaul Moore 		}
5543dfaebe98SPaul Moore 	}
5544effad8dfSPaul Moore 
5545effad8dfSPaul Moore 	if (secmark_active)
55466b6bc620SStephen Smalley 		if (avc_has_perm(&selinux_state,
55476b6bc620SStephen Smalley 				 peer_sid, skb->secmark,
5548effad8dfSPaul Moore 				 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
5549effad8dfSPaul Moore 			return NF_DROP;
5550effad8dfSPaul Moore 
5551948bf85cSPaul Moore 	if (netlbl_active)
5552948bf85cSPaul Moore 		/* we do this in the FORWARD path and not the POST_ROUTING
5553948bf85cSPaul Moore 		 * path because we want to make sure we apply the necessary
5554948bf85cSPaul Moore 		 * labeling before IPsec is applied so we can leverage AH
5555948bf85cSPaul Moore 		 * protection */
5556948bf85cSPaul Moore 		if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
5557948bf85cSPaul Moore 			return NF_DROP;
5558948bf85cSPaul Moore 
5559effad8dfSPaul Moore 	return NF_ACCEPT;
5560effad8dfSPaul Moore }
5561effad8dfSPaul Moore 
556206198b34SEric W. Biederman static unsigned int selinux_ipv4_forward(void *priv,
5563effad8dfSPaul Moore 					 struct sk_buff *skb,
5564238e54c9SDavid S. Miller 					 const struct nf_hook_state *state)
5565effad8dfSPaul Moore {
5566238e54c9SDavid S. Miller 	return selinux_ip_forward(skb, state->in, PF_INET);
5567effad8dfSPaul Moore }
5568effad8dfSPaul Moore 
55691a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
557006198b34SEric W. Biederman static unsigned int selinux_ipv6_forward(void *priv,
5571effad8dfSPaul Moore 					 struct sk_buff *skb,
5572238e54c9SDavid S. Miller 					 const struct nf_hook_state *state)
5573effad8dfSPaul Moore {
5574238e54c9SDavid S. Miller 	return selinux_ip_forward(skb, state->in, PF_INET6);
5575effad8dfSPaul Moore }
5576effad8dfSPaul Moore #endif	/* IPV6 */
5577effad8dfSPaul Moore 
5578948bf85cSPaul Moore static unsigned int selinux_ip_output(struct sk_buff *skb,
5579948bf85cSPaul Moore 				      u16 family)
5580948bf85cSPaul Moore {
558147180068SPaul Moore 	struct sock *sk;
5582948bf85cSPaul Moore 	u32 sid;
5583948bf85cSPaul Moore 
5584948bf85cSPaul Moore 	if (!netlbl_enabled())
5585948bf85cSPaul Moore 		return NF_ACCEPT;
5586948bf85cSPaul Moore 
5587948bf85cSPaul Moore 	/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
5588948bf85cSPaul Moore 	 * because we want to make sure we apply the necessary labeling
5589948bf85cSPaul Moore 	 * before IPsec is applied so we can leverage AH protection */
559047180068SPaul Moore 	sk = skb->sk;
559147180068SPaul Moore 	if (sk) {
559247180068SPaul Moore 		struct sk_security_struct *sksec;
559347180068SPaul Moore 
5594e446f9dfSEric Dumazet 		if (sk_listener(sk))
559547180068SPaul Moore 			/* if the socket is the listening state then this
559647180068SPaul Moore 			 * packet is a SYN-ACK packet which means it needs to
559747180068SPaul Moore 			 * be labeled based on the connection/request_sock and
559847180068SPaul Moore 			 * not the parent socket.  unfortunately, we can't
559947180068SPaul Moore 			 * lookup the request_sock yet as it isn't queued on
560047180068SPaul Moore 			 * the parent socket until after the SYN-ACK is sent.
560147180068SPaul Moore 			 * the "solution" is to simply pass the packet as-is
560247180068SPaul Moore 			 * as any IP option based labeling should be copied
560347180068SPaul Moore 			 * from the initial connection request (in the IP
560447180068SPaul Moore 			 * layer).  it is far from ideal, but until we get a
560547180068SPaul Moore 			 * security label in the packet itself this is the
560647180068SPaul Moore 			 * best we can do. */
560747180068SPaul Moore 			return NF_ACCEPT;
560847180068SPaul Moore 
560947180068SPaul Moore 		/* standard practice, label using the parent socket */
561047180068SPaul Moore 		sksec = sk->sk_security;
5611948bf85cSPaul Moore 		sid = sksec->sid;
5612948bf85cSPaul Moore 	} else
5613948bf85cSPaul Moore 		sid = SECINITSID_KERNEL;
5614948bf85cSPaul Moore 	if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0)
5615948bf85cSPaul Moore 		return NF_DROP;
5616948bf85cSPaul Moore 
5617948bf85cSPaul Moore 	return NF_ACCEPT;
5618948bf85cSPaul Moore }
5619948bf85cSPaul Moore 
562006198b34SEric W. Biederman static unsigned int selinux_ipv4_output(void *priv,
5621948bf85cSPaul Moore 					struct sk_buff *skb,
5622238e54c9SDavid S. Miller 					const struct nf_hook_state *state)
5623948bf85cSPaul Moore {
5624948bf85cSPaul Moore 	return selinux_ip_output(skb, PF_INET);
5625948bf85cSPaul Moore }
5626948bf85cSPaul Moore 
56271a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
56282917f57bSHuw Davies static unsigned int selinux_ipv6_output(void *priv,
56292917f57bSHuw Davies 					struct sk_buff *skb,
56302917f57bSHuw Davies 					const struct nf_hook_state *state)
56312917f57bSHuw Davies {
56322917f57bSHuw Davies 	return selinux_ip_output(skb, PF_INET6);
56332917f57bSHuw Davies }
56342917f57bSHuw Davies #endif	/* IPV6 */
56352917f57bSHuw Davies 
5636effad8dfSPaul Moore static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
5637effad8dfSPaul Moore 						int ifindex,
5638d8395c87SPaul Moore 						u16 family)
56394e5ab4cbSJames Morris {
564054abc686SEric Dumazet 	struct sock *sk = skb_to_full_sk(skb);
56414237c75cSVenkat Yekkirala 	struct sk_security_struct *sksec;
56422bf49690SThomas Liu 	struct common_audit_data ad;
564348c62af6SEric Paris 	struct lsm_network_audit net = {0,};
5644d8395c87SPaul Moore 	char *addrp;
5645d8395c87SPaul Moore 	u8 proto;
56464e5ab4cbSJames Morris 
5647effad8dfSPaul Moore 	if (sk == NULL)
5648effad8dfSPaul Moore 		return NF_ACCEPT;
56494237c75cSVenkat Yekkirala 	sksec = sk->sk_security;
56504e5ab4cbSJames Morris 
565150c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
565248c62af6SEric Paris 	ad.u.net = &net;
565348c62af6SEric Paris 	ad.u.net->netif = ifindex;
565448c62af6SEric Paris 	ad.u.net->family = family;
5655d8395c87SPaul Moore 	if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto))
5656d8395c87SPaul Moore 		return NF_DROP;
5657d8395c87SPaul Moore 
565858bfbb51SPaul Moore 	if (selinux_secmark_enabled())
56596b6bc620SStephen Smalley 		if (avc_has_perm(&selinux_state,
56606b6bc620SStephen Smalley 				 sksec->sid, skb->secmark,
5661d8395c87SPaul Moore 				 SECCLASS_PACKET, PACKET__SEND, &ad))
56622fe66ec2SEric Paris 			return NF_DROP_ERR(-ECONNREFUSED);
56631da177e4SLinus Torvalds 
5664d8395c87SPaul Moore 	if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
56652fe66ec2SEric Paris 		return NF_DROP_ERR(-ECONNREFUSED);
5666effad8dfSPaul Moore 
5667effad8dfSPaul Moore 	return NF_ACCEPT;
5668effad8dfSPaul Moore }
5669effad8dfSPaul Moore 
5670cbe0d6e8SPaul Moore static unsigned int selinux_ip_postroute(struct sk_buff *skb,
5671cbe0d6e8SPaul Moore 					 const struct net_device *outdev,
5672effad8dfSPaul Moore 					 u16 family)
5673effad8dfSPaul Moore {
5674effad8dfSPaul Moore 	u32 secmark_perm;
5675effad8dfSPaul Moore 	u32 peer_sid;
5676cbe0d6e8SPaul Moore 	int ifindex = outdev->ifindex;
5677effad8dfSPaul Moore 	struct sock *sk;
56782bf49690SThomas Liu 	struct common_audit_data ad;
567948c62af6SEric Paris 	struct lsm_network_audit net = {0,};
5680effad8dfSPaul Moore 	char *addrp;
5681effad8dfSPaul Moore 	u8 secmark_active;
5682effad8dfSPaul Moore 	u8 peerlbl_active;
5683effad8dfSPaul Moore 
5684effad8dfSPaul Moore 	/* If any sort of compatibility mode is enabled then handoff processing
5685effad8dfSPaul Moore 	 * to the selinux_ip_postroute_compat() function to deal with the
5686effad8dfSPaul Moore 	 * special handling.  We do this in an attempt to keep this function
5687effad8dfSPaul Moore 	 * as fast and as clean as possible. */
5688aa8e712cSStephen Smalley 	if (!selinux_policycap_netpeer())
5689d8395c87SPaul Moore 		return selinux_ip_postroute_compat(skb, ifindex, family);
5690c0828e50SPaul Moore 
5691effad8dfSPaul Moore 	secmark_active = selinux_secmark_enabled();
56922be4d74fSChris PeBenito 	peerlbl_active = selinux_peerlbl_enabled();
5693effad8dfSPaul Moore 	if (!secmark_active && !peerlbl_active)
5694effad8dfSPaul Moore 		return NF_ACCEPT;
5695effad8dfSPaul Moore 
569654abc686SEric Dumazet 	sk = skb_to_full_sk(skb);
5697c0828e50SPaul Moore 
5698effad8dfSPaul Moore #ifdef CONFIG_XFRM
5699effad8dfSPaul Moore 	/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
5700effad8dfSPaul Moore 	 * packet transformation so allow the packet to pass without any checks
5701effad8dfSPaul Moore 	 * since we'll have another chance to perform access control checks
5702effad8dfSPaul Moore 	 * when the packet is on it's final way out.
5703effad8dfSPaul Moore 	 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
5704c0828e50SPaul Moore 	 *       is NULL, in this case go ahead and apply access control.
5705c0828e50SPaul Moore 	 * NOTE: if this is a local socket (skb->sk != NULL) that is in the
5706c0828e50SPaul Moore 	 *       TCP listening state we cannot wait until the XFRM processing
5707c0828e50SPaul Moore 	 *       is done as we will miss out on the SA label if we do;
5708c0828e50SPaul Moore 	 *       unfortunately, this means more work, but it is only once per
5709c0828e50SPaul Moore 	 *       connection. */
5710c0828e50SPaul Moore 	if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL &&
5711e446f9dfSEric Dumazet 	    !(sk && sk_listener(sk)))
5712effad8dfSPaul Moore 		return NF_ACCEPT;
5713effad8dfSPaul Moore #endif
5714effad8dfSPaul Moore 
5715d8395c87SPaul Moore 	if (sk == NULL) {
5716446b8024SPaul Moore 		/* Without an associated socket the packet is either coming
5717446b8024SPaul Moore 		 * from the kernel or it is being forwarded; check the packet
5718446b8024SPaul Moore 		 * to determine which and if the packet is being forwarded
5719446b8024SPaul Moore 		 * query the packet directly to determine the security label. */
57204a7ab3dcSSteffen Klassert 		if (skb->skb_iif) {
5721d8395c87SPaul Moore 			secmark_perm = PACKET__FORWARD_OUT;
5722d8395c87SPaul Moore 			if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
572304f6d70fSEric Paris 				return NF_DROP;
57244a7ab3dcSSteffen Klassert 		} else {
57254a7ab3dcSSteffen Klassert 			secmark_perm = PACKET__SEND;
5726d8395c87SPaul Moore 			peer_sid = SECINITSID_KERNEL;
57274a7ab3dcSSteffen Klassert 		}
5728e446f9dfSEric Dumazet 	} else if (sk_listener(sk)) {
5729446b8024SPaul Moore 		/* Locally generated packet but the associated socket is in the
5730446b8024SPaul Moore 		 * listening state which means this is a SYN-ACK packet.  In
5731446b8024SPaul Moore 		 * this particular case the correct security label is assigned
5732446b8024SPaul Moore 		 * to the connection/request_sock but unfortunately we can't
5733446b8024SPaul Moore 		 * query the request_sock as it isn't queued on the parent
5734446b8024SPaul Moore 		 * socket until after the SYN-ACK packet is sent; the only
5735446b8024SPaul Moore 		 * viable choice is to regenerate the label like we do in
5736446b8024SPaul Moore 		 * selinux_inet_conn_request().  See also selinux_ip_output()
5737446b8024SPaul Moore 		 * for similar problems. */
5738446b8024SPaul Moore 		u32 skb_sid;
5739e446f9dfSEric Dumazet 		struct sk_security_struct *sksec;
5740e446f9dfSEric Dumazet 
5741e446f9dfSEric Dumazet 		sksec = sk->sk_security;
5742446b8024SPaul Moore 		if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
5743446b8024SPaul Moore 			return NF_DROP;
5744c0828e50SPaul Moore 		/* At this point, if the returned skb peerlbl is SECSID_NULL
5745c0828e50SPaul Moore 		 * and the packet has been through at least one XFRM
5746c0828e50SPaul Moore 		 * transformation then we must be dealing with the "final"
5747c0828e50SPaul Moore 		 * form of labeled IPsec packet; since we've already applied
5748c0828e50SPaul Moore 		 * all of our access controls on this packet we can safely
5749c0828e50SPaul Moore 		 * pass the packet. */
5750c0828e50SPaul Moore 		if (skb_sid == SECSID_NULL) {
5751c0828e50SPaul Moore 			switch (family) {
5752c0828e50SPaul Moore 			case PF_INET:
5753c0828e50SPaul Moore 				if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
5754c0828e50SPaul Moore 					return NF_ACCEPT;
5755c0828e50SPaul Moore 				break;
5756c0828e50SPaul Moore 			case PF_INET6:
5757c0828e50SPaul Moore 				if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
5758c0828e50SPaul Moore 					return NF_ACCEPT;
5759a7a91a19SPaul Moore 				break;
5760c0828e50SPaul Moore 			default:
5761c0828e50SPaul Moore 				return NF_DROP_ERR(-ECONNREFUSED);
5762c0828e50SPaul Moore 			}
5763c0828e50SPaul Moore 		}
5764446b8024SPaul Moore 		if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid))
5765446b8024SPaul Moore 			return NF_DROP;
5766446b8024SPaul Moore 		secmark_perm = PACKET__SEND;
5767d8395c87SPaul Moore 	} else {
5768446b8024SPaul Moore 		/* Locally generated packet, fetch the security label from the
5769446b8024SPaul Moore 		 * associated socket. */
5770effad8dfSPaul Moore 		struct sk_security_struct *sksec = sk->sk_security;
5771effad8dfSPaul Moore 		peer_sid = sksec->sid;
5772effad8dfSPaul Moore 		secmark_perm = PACKET__SEND;
5773effad8dfSPaul Moore 	}
5774effad8dfSPaul Moore 
577550c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_NET;
577648c62af6SEric Paris 	ad.u.net = &net;
577748c62af6SEric Paris 	ad.u.net->netif = ifindex;
577848c62af6SEric Paris 	ad.u.net->family = family;
5779d8395c87SPaul Moore 	if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
578004f6d70fSEric Paris 		return NF_DROP;
5781d8395c87SPaul Moore 
5782effad8dfSPaul Moore 	if (secmark_active)
57836b6bc620SStephen Smalley 		if (avc_has_perm(&selinux_state,
57846b6bc620SStephen Smalley 				 peer_sid, skb->secmark,
5785effad8dfSPaul Moore 				 SECCLASS_PACKET, secmark_perm, &ad))
57861f1aaf82SEric Paris 			return NF_DROP_ERR(-ECONNREFUSED);
5787effad8dfSPaul Moore 
5788effad8dfSPaul Moore 	if (peerlbl_active) {
5789effad8dfSPaul Moore 		u32 if_sid;
5790effad8dfSPaul Moore 		u32 node_sid;
5791effad8dfSPaul Moore 
5792cbe0d6e8SPaul Moore 		if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid))
579304f6d70fSEric Paris 			return NF_DROP;
57946b6bc620SStephen Smalley 		if (avc_has_perm(&selinux_state,
57956b6bc620SStephen Smalley 				 peer_sid, if_sid,
5796effad8dfSPaul Moore 				 SECCLASS_NETIF, NETIF__EGRESS, &ad))
57971f1aaf82SEric Paris 			return NF_DROP_ERR(-ECONNREFUSED);
5798effad8dfSPaul Moore 
5799effad8dfSPaul Moore 		if (sel_netnode_sid(addrp, family, &node_sid))
580004f6d70fSEric Paris 			return NF_DROP;
58016b6bc620SStephen Smalley 		if (avc_has_perm(&selinux_state,
58026b6bc620SStephen Smalley 				 peer_sid, node_sid,
5803effad8dfSPaul Moore 				 SECCLASS_NODE, NODE__SENDTO, &ad))
58041f1aaf82SEric Paris 			return NF_DROP_ERR(-ECONNREFUSED);
5805effad8dfSPaul Moore 	}
5806effad8dfSPaul Moore 
5807effad8dfSPaul Moore 	return NF_ACCEPT;
5808effad8dfSPaul Moore }
5809effad8dfSPaul Moore 
581006198b34SEric W. Biederman static unsigned int selinux_ipv4_postroute(void *priv,
5811a224be76SDavid S. Miller 					   struct sk_buff *skb,
5812238e54c9SDavid S. Miller 					   const struct nf_hook_state *state)
58131da177e4SLinus Torvalds {
5814238e54c9SDavid S. Miller 	return selinux_ip_postroute(skb, state->out, PF_INET);
58151da177e4SLinus Torvalds }
58161da177e4SLinus Torvalds 
58171a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
581806198b34SEric W. Biederman static unsigned int selinux_ipv6_postroute(void *priv,
5819a224be76SDavid S. Miller 					   struct sk_buff *skb,
5820238e54c9SDavid S. Miller 					   const struct nf_hook_state *state)
58211da177e4SLinus Torvalds {
5822238e54c9SDavid S. Miller 	return selinux_ip_postroute(skb, state->out, PF_INET6);
58231da177e4SLinus Torvalds }
58241da177e4SLinus Torvalds #endif	/* IPV6 */
58251da177e4SLinus Torvalds 
58261da177e4SLinus Torvalds #endif	/* CONFIG_NETFILTER */
58271da177e4SLinus Torvalds 
58281da177e4SLinus Torvalds static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
58291da177e4SLinus Torvalds {
5830941fc5b2SStephen Smalley 	return selinux_nlmsg_perm(sk, skb);
58311da177e4SLinus Torvalds }
58321da177e4SLinus Torvalds 
5833ecd5f82eSCasey Schaufler static void ipc_init_security(struct ipc_security_struct *isec, u16 sclass)
58341da177e4SLinus Torvalds {
58351da177e4SLinus Torvalds 	isec->sclass = sclass;
5836be0554c9SStephen Smalley 	isec->sid = current_sid();
58371da177e4SLinus Torvalds }
58381da177e4SLinus Torvalds 
58391da177e4SLinus Torvalds static int msg_msg_alloc_security(struct msg_msg *msg)
58401da177e4SLinus Torvalds {
58411da177e4SLinus Torvalds 	struct msg_security_struct *msec;
58421da177e4SLinus Torvalds 
5843ecd5f82eSCasey Schaufler 	msec = selinux_msg_msg(msg);
58441da177e4SLinus Torvalds 	msec->sid = SECINITSID_UNLABELED;
58451da177e4SLinus Torvalds 
58461da177e4SLinus Torvalds 	return 0;
58471da177e4SLinus Torvalds }
58481da177e4SLinus Torvalds 
58491da177e4SLinus Torvalds static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
58506af963f1SStephen Smalley 			u32 perms)
58511da177e4SLinus Torvalds {
58521da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
58532bf49690SThomas Liu 	struct common_audit_data ad;
5854275bb41eSDavid Howells 	u32 sid = current_sid();
58551da177e4SLinus Torvalds 
58567c653828SCasey Schaufler 	isec = selinux_ipc(ipc_perms);
58571da177e4SLinus Torvalds 
585850c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
58591da177e4SLinus Torvalds 	ad.u.ipc_id = ipc_perms->key;
58601da177e4SLinus Torvalds 
58616b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
58626b6bc620SStephen Smalley 			    sid, isec->sid, isec->sclass, perms, &ad);
58631da177e4SLinus Torvalds }
58641da177e4SLinus Torvalds 
58651da177e4SLinus Torvalds static int selinux_msg_msg_alloc_security(struct msg_msg *msg)
58661da177e4SLinus Torvalds {
58671da177e4SLinus Torvalds 	return msg_msg_alloc_security(msg);
58681da177e4SLinus Torvalds }
58691da177e4SLinus Torvalds 
58701da177e4SLinus Torvalds /* message queue security operations */
5871d8c6e854SEric W. Biederman static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
58721da177e4SLinus Torvalds {
58731da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
58742bf49690SThomas Liu 	struct common_audit_data ad;
5875275bb41eSDavid Howells 	u32 sid = current_sid();
58761da177e4SLinus Torvalds 	int rc;
58771da177e4SLinus Torvalds 
5878ecd5f82eSCasey Schaufler 	isec = selinux_ipc(msq);
5879ecd5f82eSCasey Schaufler 	ipc_init_security(isec, SECCLASS_MSGQ);
58801da177e4SLinus Torvalds 
588150c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
5882d8c6e854SEric W. Biederman 	ad.u.ipc_id = msq->key;
58831da177e4SLinus Torvalds 
58846b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
58856b6bc620SStephen Smalley 			  sid, isec->sid, SECCLASS_MSGQ,
58861da177e4SLinus Torvalds 			  MSGQ__CREATE, &ad);
58871da177e4SLinus Torvalds 	return rc;
58881da177e4SLinus Torvalds }
58891da177e4SLinus Torvalds 
5890d8c6e854SEric W. Biederman static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
58911da177e4SLinus Torvalds {
58921da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
58932bf49690SThomas Liu 	struct common_audit_data ad;
5894275bb41eSDavid Howells 	u32 sid = current_sid();
58951da177e4SLinus Torvalds 
58967c653828SCasey Schaufler 	isec = selinux_ipc(msq);
58971da177e4SLinus Torvalds 
589850c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
5899d8c6e854SEric W. Biederman 	ad.u.ipc_id = msq->key;
59001da177e4SLinus Torvalds 
59016b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
59026b6bc620SStephen Smalley 			    sid, isec->sid, SECCLASS_MSGQ,
59031da177e4SLinus Torvalds 			    MSGQ__ASSOCIATE, &ad);
59041da177e4SLinus Torvalds }
59051da177e4SLinus Torvalds 
5906d8c6e854SEric W. Biederman static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
59071da177e4SLinus Torvalds {
59081da177e4SLinus Torvalds 	int err;
59091da177e4SLinus Torvalds 	int perms;
59101da177e4SLinus Torvalds 
59111da177e4SLinus Torvalds 	switch (cmd) {
59121da177e4SLinus Torvalds 	case IPC_INFO:
59131da177e4SLinus Torvalds 	case MSG_INFO:
59141da177e4SLinus Torvalds 		/* No specific object, just general system-wide information. */
59156b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
59166b6bc620SStephen Smalley 				    current_sid(), SECINITSID_KERNEL,
5917be0554c9SStephen Smalley 				    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
59181da177e4SLinus Torvalds 	case IPC_STAT:
59191da177e4SLinus Torvalds 	case MSG_STAT:
592023c8cec8SDavidlohr Bueso 	case MSG_STAT_ANY:
59211da177e4SLinus Torvalds 		perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
59221da177e4SLinus Torvalds 		break;
59231da177e4SLinus Torvalds 	case IPC_SET:
59241da177e4SLinus Torvalds 		perms = MSGQ__SETATTR;
59251da177e4SLinus Torvalds 		break;
59261da177e4SLinus Torvalds 	case IPC_RMID:
59271da177e4SLinus Torvalds 		perms = MSGQ__DESTROY;
59281da177e4SLinus Torvalds 		break;
59291da177e4SLinus Torvalds 	default:
59301da177e4SLinus Torvalds 		return 0;
59311da177e4SLinus Torvalds 	}
59321da177e4SLinus Torvalds 
5933d8c6e854SEric W. Biederman 	err = ipc_has_perm(msq, perms);
59341da177e4SLinus Torvalds 	return err;
59351da177e4SLinus Torvalds }
59361da177e4SLinus Torvalds 
5937d8c6e854SEric W. Biederman static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg)
59381da177e4SLinus Torvalds {
59391da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
59401da177e4SLinus Torvalds 	struct msg_security_struct *msec;
59412bf49690SThomas Liu 	struct common_audit_data ad;
5942275bb41eSDavid Howells 	u32 sid = current_sid();
59431da177e4SLinus Torvalds 	int rc;
59441da177e4SLinus Torvalds 
59457c653828SCasey Schaufler 	isec = selinux_ipc(msq);
59467c653828SCasey Schaufler 	msec = selinux_msg_msg(msg);
59471da177e4SLinus Torvalds 
59481da177e4SLinus Torvalds 	/*
59491da177e4SLinus Torvalds 	 * First time through, need to assign label to the message
59501da177e4SLinus Torvalds 	 */
59511da177e4SLinus Torvalds 	if (msec->sid == SECINITSID_UNLABELED) {
59521da177e4SLinus Torvalds 		/*
59531da177e4SLinus Torvalds 		 * Compute new sid based on current process and
59541da177e4SLinus Torvalds 		 * message queue this message will be stored in
59551da177e4SLinus Torvalds 		 */
5956aa8e712cSStephen Smalley 		rc = security_transition_sid(&selinux_state, sid, isec->sid,
5957aa8e712cSStephen Smalley 					     SECCLASS_MSG, NULL, &msec->sid);
59581da177e4SLinus Torvalds 		if (rc)
59591da177e4SLinus Torvalds 			return rc;
59601da177e4SLinus Torvalds 	}
59611da177e4SLinus Torvalds 
596250c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
5963d8c6e854SEric W. Biederman 	ad.u.ipc_id = msq->key;
59641da177e4SLinus Torvalds 
59651da177e4SLinus Torvalds 	/* Can this process write to the queue? */
59666b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
59676b6bc620SStephen Smalley 			  sid, isec->sid, SECCLASS_MSGQ,
59681da177e4SLinus Torvalds 			  MSGQ__WRITE, &ad);
59691da177e4SLinus Torvalds 	if (!rc)
59701da177e4SLinus Torvalds 		/* Can this process send the message */
59716b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
59726b6bc620SStephen Smalley 				  sid, msec->sid, SECCLASS_MSG,
5973275bb41eSDavid Howells 				  MSG__SEND, &ad);
59741da177e4SLinus Torvalds 	if (!rc)
59751da177e4SLinus Torvalds 		/* Can the message be put in the queue? */
59766b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
59776b6bc620SStephen Smalley 				  msec->sid, isec->sid, SECCLASS_MSGQ,
5978275bb41eSDavid Howells 				  MSGQ__ENQUEUE, &ad);
59791da177e4SLinus Torvalds 
59801da177e4SLinus Torvalds 	return rc;
59811da177e4SLinus Torvalds }
59821da177e4SLinus Torvalds 
5983d8c6e854SEric W. Biederman static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg,
59841da177e4SLinus Torvalds 				    struct task_struct *target,
59851da177e4SLinus Torvalds 				    long type, int mode)
59861da177e4SLinus Torvalds {
59871da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
59881da177e4SLinus Torvalds 	struct msg_security_struct *msec;
59892bf49690SThomas Liu 	struct common_audit_data ad;
5990275bb41eSDavid Howells 	u32 sid = task_sid(target);
59911da177e4SLinus Torvalds 	int rc;
59921da177e4SLinus Torvalds 
59937c653828SCasey Schaufler 	isec = selinux_ipc(msq);
59947c653828SCasey Schaufler 	msec = selinux_msg_msg(msg);
59951da177e4SLinus Torvalds 
599650c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
5997d8c6e854SEric W. Biederman 	ad.u.ipc_id = msq->key;
59981da177e4SLinus Torvalds 
59996b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
60006b6bc620SStephen Smalley 			  sid, isec->sid,
60011da177e4SLinus Torvalds 			  SECCLASS_MSGQ, MSGQ__READ, &ad);
60021da177e4SLinus Torvalds 	if (!rc)
60036b6bc620SStephen Smalley 		rc = avc_has_perm(&selinux_state,
60046b6bc620SStephen Smalley 				  sid, msec->sid,
60051da177e4SLinus Torvalds 				  SECCLASS_MSG, MSG__RECEIVE, &ad);
60061da177e4SLinus Torvalds 	return rc;
60071da177e4SLinus Torvalds }
60081da177e4SLinus Torvalds 
60091da177e4SLinus Torvalds /* Shared Memory security operations */
60107191adffSEric W. Biederman static int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
60111da177e4SLinus Torvalds {
60121da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
60132bf49690SThomas Liu 	struct common_audit_data ad;
6014275bb41eSDavid Howells 	u32 sid = current_sid();
60151da177e4SLinus Torvalds 	int rc;
60161da177e4SLinus Torvalds 
6017ecd5f82eSCasey Schaufler 	isec = selinux_ipc(shp);
6018ecd5f82eSCasey Schaufler 	ipc_init_security(isec, SECCLASS_SHM);
60191da177e4SLinus Torvalds 
602050c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
60217191adffSEric W. Biederman 	ad.u.ipc_id = shp->key;
60221da177e4SLinus Torvalds 
60236b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
60246b6bc620SStephen Smalley 			  sid, isec->sid, SECCLASS_SHM,
60251da177e4SLinus Torvalds 			  SHM__CREATE, &ad);
60261da177e4SLinus Torvalds 	return rc;
60271da177e4SLinus Torvalds }
60281da177e4SLinus Torvalds 
60297191adffSEric W. Biederman static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
60301da177e4SLinus Torvalds {
60311da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
60322bf49690SThomas Liu 	struct common_audit_data ad;
6033275bb41eSDavid Howells 	u32 sid = current_sid();
60341da177e4SLinus Torvalds 
60357c653828SCasey Schaufler 	isec = selinux_ipc(shp);
60361da177e4SLinus Torvalds 
603750c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
60387191adffSEric W. Biederman 	ad.u.ipc_id = shp->key;
60391da177e4SLinus Torvalds 
60406b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
60416b6bc620SStephen Smalley 			    sid, isec->sid, SECCLASS_SHM,
60421da177e4SLinus Torvalds 			    SHM__ASSOCIATE, &ad);
60431da177e4SLinus Torvalds }
60441da177e4SLinus Torvalds 
60451da177e4SLinus Torvalds /* Note, at this point, shp is locked down */
60467191adffSEric W. Biederman static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
60471da177e4SLinus Torvalds {
60481da177e4SLinus Torvalds 	int perms;
60491da177e4SLinus Torvalds 	int err;
60501da177e4SLinus Torvalds 
60511da177e4SLinus Torvalds 	switch (cmd) {
60521da177e4SLinus Torvalds 	case IPC_INFO:
60531da177e4SLinus Torvalds 	case SHM_INFO:
60541da177e4SLinus Torvalds 		/* No specific object, just general system-wide information. */
60556b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
60566b6bc620SStephen Smalley 				    current_sid(), SECINITSID_KERNEL,
6057be0554c9SStephen Smalley 				    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
60581da177e4SLinus Torvalds 	case IPC_STAT:
60591da177e4SLinus Torvalds 	case SHM_STAT:
6060c21a6970SDavidlohr Bueso 	case SHM_STAT_ANY:
60611da177e4SLinus Torvalds 		perms = SHM__GETATTR | SHM__ASSOCIATE;
60621da177e4SLinus Torvalds 		break;
60631da177e4SLinus Torvalds 	case IPC_SET:
60641da177e4SLinus Torvalds 		perms = SHM__SETATTR;
60651da177e4SLinus Torvalds 		break;
60661da177e4SLinus Torvalds 	case SHM_LOCK:
60671da177e4SLinus Torvalds 	case SHM_UNLOCK:
60681da177e4SLinus Torvalds 		perms = SHM__LOCK;
60691da177e4SLinus Torvalds 		break;
60701da177e4SLinus Torvalds 	case IPC_RMID:
60711da177e4SLinus Torvalds 		perms = SHM__DESTROY;
60721da177e4SLinus Torvalds 		break;
60731da177e4SLinus Torvalds 	default:
60741da177e4SLinus Torvalds 		return 0;
60751da177e4SLinus Torvalds 	}
60761da177e4SLinus Torvalds 
60777191adffSEric W. Biederman 	err = ipc_has_perm(shp, perms);
60781da177e4SLinus Torvalds 	return err;
60791da177e4SLinus Torvalds }
60801da177e4SLinus Torvalds 
60817191adffSEric W. Biederman static int selinux_shm_shmat(struct kern_ipc_perm *shp,
60821da177e4SLinus Torvalds 			     char __user *shmaddr, int shmflg)
60831da177e4SLinus Torvalds {
60841da177e4SLinus Torvalds 	u32 perms;
60851da177e4SLinus Torvalds 
60861da177e4SLinus Torvalds 	if (shmflg & SHM_RDONLY)
60871da177e4SLinus Torvalds 		perms = SHM__READ;
60881da177e4SLinus Torvalds 	else
60891da177e4SLinus Torvalds 		perms = SHM__READ | SHM__WRITE;
60901da177e4SLinus Torvalds 
60917191adffSEric W. Biederman 	return ipc_has_perm(shp, perms);
60921da177e4SLinus Torvalds }
60931da177e4SLinus Torvalds 
60941da177e4SLinus Torvalds /* Semaphore security operations */
6095aefad959SEric W. Biederman static int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
60961da177e4SLinus Torvalds {
60971da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
60982bf49690SThomas Liu 	struct common_audit_data ad;
6099275bb41eSDavid Howells 	u32 sid = current_sid();
61001da177e4SLinus Torvalds 	int rc;
61011da177e4SLinus Torvalds 
6102ecd5f82eSCasey Schaufler 	isec = selinux_ipc(sma);
6103ecd5f82eSCasey Schaufler 	ipc_init_security(isec, SECCLASS_SEM);
61041da177e4SLinus Torvalds 
610550c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
6106aefad959SEric W. Biederman 	ad.u.ipc_id = sma->key;
61071da177e4SLinus Torvalds 
61086b6bc620SStephen Smalley 	rc = avc_has_perm(&selinux_state,
61096b6bc620SStephen Smalley 			  sid, isec->sid, SECCLASS_SEM,
61101da177e4SLinus Torvalds 			  SEM__CREATE, &ad);
61111da177e4SLinus Torvalds 	return rc;
61121da177e4SLinus Torvalds }
61131da177e4SLinus Torvalds 
6114aefad959SEric W. Biederman static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
61151da177e4SLinus Torvalds {
61161da177e4SLinus Torvalds 	struct ipc_security_struct *isec;
61172bf49690SThomas Liu 	struct common_audit_data ad;
6118275bb41eSDavid Howells 	u32 sid = current_sid();
61191da177e4SLinus Torvalds 
61207c653828SCasey Schaufler 	isec = selinux_ipc(sma);
61211da177e4SLinus Torvalds 
612250c205f5SEric Paris 	ad.type = LSM_AUDIT_DATA_IPC;
6123aefad959SEric W. Biederman 	ad.u.ipc_id = sma->key;
61241da177e4SLinus Torvalds 
61256b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
61266b6bc620SStephen Smalley 			    sid, isec->sid, SECCLASS_SEM,
61271da177e4SLinus Torvalds 			    SEM__ASSOCIATE, &ad);
61281da177e4SLinus Torvalds }
61291da177e4SLinus Torvalds 
61301da177e4SLinus Torvalds /* Note, at this point, sma is locked down */
6131aefad959SEric W. Biederman static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
61321da177e4SLinus Torvalds {
61331da177e4SLinus Torvalds 	int err;
61341da177e4SLinus Torvalds 	u32 perms;
61351da177e4SLinus Torvalds 
61361da177e4SLinus Torvalds 	switch (cmd) {
61371da177e4SLinus Torvalds 	case IPC_INFO:
61381da177e4SLinus Torvalds 	case SEM_INFO:
61391da177e4SLinus Torvalds 		/* No specific object, just general system-wide information. */
61406b6bc620SStephen Smalley 		return avc_has_perm(&selinux_state,
61416b6bc620SStephen Smalley 				    current_sid(), SECINITSID_KERNEL,
6142be0554c9SStephen Smalley 				    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
61431da177e4SLinus Torvalds 	case GETPID:
61441da177e4SLinus Torvalds 	case GETNCNT:
61451da177e4SLinus Torvalds 	case GETZCNT:
61461da177e4SLinus Torvalds 		perms = SEM__GETATTR;
61471da177e4SLinus Torvalds 		break;
61481da177e4SLinus Torvalds 	case GETVAL:
61491da177e4SLinus Torvalds 	case GETALL:
61501da177e4SLinus Torvalds 		perms = SEM__READ;
61511da177e4SLinus Torvalds 		break;
61521da177e4SLinus Torvalds 	case SETVAL:
61531da177e4SLinus Torvalds 	case SETALL:
61541da177e4SLinus Torvalds 		perms = SEM__WRITE;
61551da177e4SLinus Torvalds 		break;
61561da177e4SLinus Torvalds 	case IPC_RMID:
61571da177e4SLinus Torvalds 		perms = SEM__DESTROY;
61581da177e4SLinus Torvalds 		break;
61591da177e4SLinus Torvalds 	case IPC_SET:
61601da177e4SLinus Torvalds 		perms = SEM__SETATTR;
61611da177e4SLinus Torvalds 		break;
61621da177e4SLinus Torvalds 	case IPC_STAT:
61631da177e4SLinus Torvalds 	case SEM_STAT:
6164a280d6dcSDavidlohr Bueso 	case SEM_STAT_ANY:
61651da177e4SLinus Torvalds 		perms = SEM__GETATTR | SEM__ASSOCIATE;
61661da177e4SLinus Torvalds 		break;
61671da177e4SLinus Torvalds 	default:
61681da177e4SLinus Torvalds 		return 0;
61691da177e4SLinus Torvalds 	}
61701da177e4SLinus Torvalds 
6171aefad959SEric W. Biederman 	err = ipc_has_perm(sma, perms);
61721da177e4SLinus Torvalds 	return err;
61731da177e4SLinus Torvalds }
61741da177e4SLinus Torvalds 
6175aefad959SEric W. Biederman static int selinux_sem_semop(struct kern_ipc_perm *sma,
61761da177e4SLinus Torvalds 			     struct sembuf *sops, unsigned nsops, int alter)
61771da177e4SLinus Torvalds {
61781da177e4SLinus Torvalds 	u32 perms;
61791da177e4SLinus Torvalds 
61801da177e4SLinus Torvalds 	if (alter)
61811da177e4SLinus Torvalds 		perms = SEM__READ | SEM__WRITE;
61821da177e4SLinus Torvalds 	else
61831da177e4SLinus Torvalds 		perms = SEM__READ;
61841da177e4SLinus Torvalds 
6185aefad959SEric W. Biederman 	return ipc_has_perm(sma, perms);
61861da177e4SLinus Torvalds }
61871da177e4SLinus Torvalds 
61881da177e4SLinus Torvalds static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
61891da177e4SLinus Torvalds {
61901da177e4SLinus Torvalds 	u32 av = 0;
61911da177e4SLinus Torvalds 
61921da177e4SLinus Torvalds 	av = 0;
61931da177e4SLinus Torvalds 	if (flag & S_IRUGO)
61941da177e4SLinus Torvalds 		av |= IPC__UNIX_READ;
61951da177e4SLinus Torvalds 	if (flag & S_IWUGO)
61961da177e4SLinus Torvalds 		av |= IPC__UNIX_WRITE;
61971da177e4SLinus Torvalds 
61981da177e4SLinus Torvalds 	if (av == 0)
61991da177e4SLinus Torvalds 		return 0;
62001da177e4SLinus Torvalds 
62016af963f1SStephen Smalley 	return ipc_has_perm(ipcp, av);
62021da177e4SLinus Torvalds }
62031da177e4SLinus Torvalds 
6204713a04aeSAhmed S. Darwish static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
6205713a04aeSAhmed S. Darwish {
62067c653828SCasey Schaufler 	struct ipc_security_struct *isec = selinux_ipc(ipcp);
6207713a04aeSAhmed S. Darwish 	*secid = isec->sid;
6208713a04aeSAhmed S. Darwish }
6209713a04aeSAhmed S. Darwish 
62101da177e4SLinus Torvalds static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
62111da177e4SLinus Torvalds {
62121da177e4SLinus Torvalds 	if (inode)
62131da177e4SLinus Torvalds 		inode_doinit_with_dentry(inode, dentry);
62141da177e4SLinus Torvalds }
62151da177e4SLinus Torvalds 
62161da177e4SLinus Torvalds static int selinux_getprocattr(struct task_struct *p,
621704ff9708SAl Viro 			       char *name, char **value)
62181da177e4SLinus Torvalds {
6219275bb41eSDavid Howells 	const struct task_security_struct *__tsec;
62208c8570fbSDustin Kirkland 	u32 sid;
62211da177e4SLinus Torvalds 	int error;
622204ff9708SAl Viro 	unsigned len;
62231da177e4SLinus Torvalds 
6224275bb41eSDavid Howells 	rcu_read_lock();
62250c6cfa62SCasey Schaufler 	__tsec = selinux_cred(__task_cred(p));
62261da177e4SLinus Torvalds 
6227be0554c9SStephen Smalley 	if (current != p) {
62286b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62296b6bc620SStephen Smalley 				     current_sid(), __tsec->sid,
6230be0554c9SStephen Smalley 				     SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
6231be0554c9SStephen Smalley 		if (error)
6232be0554c9SStephen Smalley 			goto bad;
6233be0554c9SStephen Smalley 	}
6234be0554c9SStephen Smalley 
62351da177e4SLinus Torvalds 	if (!strcmp(name, "current"))
6236275bb41eSDavid Howells 		sid = __tsec->sid;
62371da177e4SLinus Torvalds 	else if (!strcmp(name, "prev"))
6238275bb41eSDavid Howells 		sid = __tsec->osid;
62391da177e4SLinus Torvalds 	else if (!strcmp(name, "exec"))
6240275bb41eSDavid Howells 		sid = __tsec->exec_sid;
62411da177e4SLinus Torvalds 	else if (!strcmp(name, "fscreate"))
6242275bb41eSDavid Howells 		sid = __tsec->create_sid;
62434eb582cfSMichael LeMay 	else if (!strcmp(name, "keycreate"))
6244275bb41eSDavid Howells 		sid = __tsec->keycreate_sid;
624542c3e03eSEric Paris 	else if (!strcmp(name, "sockcreate"))
6246275bb41eSDavid Howells 		sid = __tsec->sockcreate_sid;
6247be0554c9SStephen Smalley 	else {
6248be0554c9SStephen Smalley 		error = -EINVAL;
6249be0554c9SStephen Smalley 		goto bad;
6250be0554c9SStephen Smalley 	}
6251275bb41eSDavid Howells 	rcu_read_unlock();
62521da177e4SLinus Torvalds 
62531da177e4SLinus Torvalds 	if (!sid)
62541da177e4SLinus Torvalds 		return 0;
62551da177e4SLinus Torvalds 
6256aa8e712cSStephen Smalley 	error = security_sid_to_context(&selinux_state, sid, value, &len);
625704ff9708SAl Viro 	if (error)
625804ff9708SAl Viro 		return error;
625904ff9708SAl Viro 	return len;
6260275bb41eSDavid Howells 
6261be0554c9SStephen Smalley bad:
6262275bb41eSDavid Howells 	rcu_read_unlock();
6263be0554c9SStephen Smalley 	return error;
62641da177e4SLinus Torvalds }
62651da177e4SLinus Torvalds 
6266b21507e2SStephen Smalley static int selinux_setprocattr(const char *name, void *value, size_t size)
62671da177e4SLinus Torvalds {
62681da177e4SLinus Torvalds 	struct task_security_struct *tsec;
6269d84f4f99SDavid Howells 	struct cred *new;
6270be0554c9SStephen Smalley 	u32 mysid = current_sid(), sid = 0, ptsid;
62711da177e4SLinus Torvalds 	int error;
62721da177e4SLinus Torvalds 	char *str = value;
62731da177e4SLinus Torvalds 
62741da177e4SLinus Torvalds 	/*
62751da177e4SLinus Torvalds 	 * Basic control over ability to set these attributes at all.
62761da177e4SLinus Torvalds 	 */
62771da177e4SLinus Torvalds 	if (!strcmp(name, "exec"))
62786b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62796b6bc620SStephen Smalley 				     mysid, mysid, SECCLASS_PROCESS,
6280be0554c9SStephen Smalley 				     PROCESS__SETEXEC, NULL);
62811da177e4SLinus Torvalds 	else if (!strcmp(name, "fscreate"))
62826b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62836b6bc620SStephen Smalley 				     mysid, mysid, SECCLASS_PROCESS,
6284be0554c9SStephen Smalley 				     PROCESS__SETFSCREATE, NULL);
62854eb582cfSMichael LeMay 	else if (!strcmp(name, "keycreate"))
62866b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62876b6bc620SStephen Smalley 				     mysid, mysid, SECCLASS_PROCESS,
6288be0554c9SStephen Smalley 				     PROCESS__SETKEYCREATE, NULL);
628942c3e03eSEric Paris 	else if (!strcmp(name, "sockcreate"))
62906b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62916b6bc620SStephen Smalley 				     mysid, mysid, SECCLASS_PROCESS,
6292be0554c9SStephen Smalley 				     PROCESS__SETSOCKCREATE, NULL);
62931da177e4SLinus Torvalds 	else if (!strcmp(name, "current"))
62946b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
62956b6bc620SStephen Smalley 				     mysid, mysid, SECCLASS_PROCESS,
6296be0554c9SStephen Smalley 				     PROCESS__SETCURRENT, NULL);
62971da177e4SLinus Torvalds 	else
62981da177e4SLinus Torvalds 		error = -EINVAL;
62991da177e4SLinus Torvalds 	if (error)
63001da177e4SLinus Torvalds 		return error;
63011da177e4SLinus Torvalds 
63021da177e4SLinus Torvalds 	/* Obtain a SID for the context, if one was specified. */
6303a050a570SStephen Smalley 	if (size && str[0] && str[0] != '\n') {
63041da177e4SLinus Torvalds 		if (str[size-1] == '\n') {
63051da177e4SLinus Torvalds 			str[size-1] = 0;
63061da177e4SLinus Torvalds 			size--;
63071da177e4SLinus Torvalds 		}
6308aa8e712cSStephen Smalley 		error = security_context_to_sid(&selinux_state, value, size,
6309aa8e712cSStephen Smalley 						&sid, GFP_KERNEL);
631012b29f34SStephen Smalley 		if (error == -EINVAL && !strcmp(name, "fscreate")) {
6311db59000aSStephen Smalley 			if (!has_cap_mac_admin(true)) {
6312d6ea83ecSEric Paris 				struct audit_buffer *ab;
6313d6ea83ecSEric Paris 				size_t audit_size;
6314d6ea83ecSEric Paris 
6315d6ea83ecSEric Paris 				/* We strip a nul only if it is at the end, otherwise the
6316d6ea83ecSEric Paris 				 * context contains a nul and we should audit that */
6317d6ea83ecSEric Paris 				if (str[size - 1] == '\0')
6318d6ea83ecSEric Paris 					audit_size = size - 1;
6319d6ea83ecSEric Paris 				else
6320d6ea83ecSEric Paris 					audit_size = size;
6321cdfb6b34SRichard Guy Briggs 				ab = audit_log_start(audit_context(),
6322cdfb6b34SRichard Guy Briggs 						     GFP_ATOMIC,
6323cdfb6b34SRichard Guy Briggs 						     AUDIT_SELINUX_ERR);
6324d6ea83ecSEric Paris 				audit_log_format(ab, "op=fscreate invalid_context=");
6325d6ea83ecSEric Paris 				audit_log_n_untrustedstring(ab, value, audit_size);
6326d6ea83ecSEric Paris 				audit_log_end(ab);
6327d6ea83ecSEric Paris 
632812b29f34SStephen Smalley 				return error;
6329d6ea83ecSEric Paris 			}
6330aa8e712cSStephen Smalley 			error = security_context_to_sid_force(
6331aa8e712cSStephen Smalley 						      &selinux_state,
6332aa8e712cSStephen Smalley 						      value, size, &sid);
633312b29f34SStephen Smalley 		}
63341da177e4SLinus Torvalds 		if (error)
63351da177e4SLinus Torvalds 			return error;
63361da177e4SLinus Torvalds 	}
63371da177e4SLinus Torvalds 
6338d84f4f99SDavid Howells 	new = prepare_creds();
6339d84f4f99SDavid Howells 	if (!new)
6340d84f4f99SDavid Howells 		return -ENOMEM;
6341d84f4f99SDavid Howells 
63421da177e4SLinus Torvalds 	/* Permission checking based on the specified context is
63431da177e4SLinus Torvalds 	   performed during the actual operation (execve,
63441da177e4SLinus Torvalds 	   open/mkdir/...), when we know the full context of the
6345d84f4f99SDavid Howells 	   operation.  See selinux_bprm_set_creds for the execve
63461da177e4SLinus Torvalds 	   checks and may_create for the file creation checks. The
63471da177e4SLinus Torvalds 	   operation will then fail if the context is not permitted. */
63480c6cfa62SCasey Schaufler 	tsec = selinux_cred(new);
6349d84f4f99SDavid Howells 	if (!strcmp(name, "exec")) {
63501da177e4SLinus Torvalds 		tsec->exec_sid = sid;
6351d84f4f99SDavid Howells 	} else if (!strcmp(name, "fscreate")) {
63521da177e4SLinus Torvalds 		tsec->create_sid = sid;
6353d84f4f99SDavid Howells 	} else if (!strcmp(name, "keycreate")) {
6354464c258aSOndrej Mosnacek 		if (sid) {
6355464c258aSOndrej Mosnacek 			error = avc_has_perm(&selinux_state, mysid, sid,
6356464c258aSOndrej Mosnacek 					     SECCLASS_KEY, KEY__CREATE, NULL);
63574eb582cfSMichael LeMay 			if (error)
6358d84f4f99SDavid Howells 				goto abort_change;
6359464c258aSOndrej Mosnacek 		}
63604eb582cfSMichael LeMay 		tsec->keycreate_sid = sid;
6361d84f4f99SDavid Howells 	} else if (!strcmp(name, "sockcreate")) {
636242c3e03eSEric Paris 		tsec->sockcreate_sid = sid;
6363d84f4f99SDavid Howells 	} else if (!strcmp(name, "current")) {
6364d84f4f99SDavid Howells 		error = -EINVAL;
63651da177e4SLinus Torvalds 		if (sid == 0)
6366d84f4f99SDavid Howells 			goto abort_change;
6367d9250deaSKaiGai Kohei 
6368d84f4f99SDavid Howells 		/* Only allow single threaded processes to change context */
6369d84f4f99SDavid Howells 		error = -EPERM;
63705bb459bbSOleg Nesterov 		if (!current_is_single_threaded()) {
6371aa8e712cSStephen Smalley 			error = security_bounded_transition(&selinux_state,
6372aa8e712cSStephen Smalley 							    tsec->sid, sid);
6373d84f4f99SDavid Howells 			if (error)
6374d84f4f99SDavid Howells 				goto abort_change;
63751da177e4SLinus Torvalds 		}
63761da177e4SLinus Torvalds 
63771da177e4SLinus Torvalds 		/* Check permissions for the transition. */
63786b6bc620SStephen Smalley 		error = avc_has_perm(&selinux_state,
63796b6bc620SStephen Smalley 				     tsec->sid, sid, SECCLASS_PROCESS,
63801da177e4SLinus Torvalds 				     PROCESS__DYNTRANSITION, NULL);
63811da177e4SLinus Torvalds 		if (error)
6382d84f4f99SDavid Howells 			goto abort_change;
63831da177e4SLinus Torvalds 
63841da177e4SLinus Torvalds 		/* Check for ptracing, and update the task SID if ok.
63851da177e4SLinus Torvalds 		   Otherwise, leave SID unchanged and fail. */
6386be0554c9SStephen Smalley 		ptsid = ptrace_parent_sid();
63870c6181cbSPaul Moore 		if (ptsid != 0) {
63886b6bc620SStephen Smalley 			error = avc_has_perm(&selinux_state,
63896b6bc620SStephen Smalley 					     ptsid, sid, SECCLASS_PROCESS,
6390d84f4f99SDavid Howells 					     PROCESS__PTRACE, NULL);
6391d84f4f99SDavid Howells 			if (error)
6392d84f4f99SDavid Howells 				goto abort_change;
6393d84f4f99SDavid Howells 		}
6394d84f4f99SDavid Howells 
6395d84f4f99SDavid Howells 		tsec->sid = sid;
6396d84f4f99SDavid Howells 	} else {
6397d84f4f99SDavid Howells 		error = -EINVAL;
6398d84f4f99SDavid Howells 		goto abort_change;
6399d84f4f99SDavid Howells 	}
6400d84f4f99SDavid Howells 
6401d84f4f99SDavid Howells 	commit_creds(new);
64021da177e4SLinus Torvalds 	return size;
6403d84f4f99SDavid Howells 
6404d84f4f99SDavid Howells abort_change:
6405d84f4f99SDavid Howells 	abort_creds(new);
6406d84f4f99SDavid Howells 	return error;
64071da177e4SLinus Torvalds }
64081da177e4SLinus Torvalds 
6409746df9b5SDavid Quigley static int selinux_ismaclabel(const char *name)
6410746df9b5SDavid Quigley {
6411746df9b5SDavid Quigley 	return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
6412746df9b5SDavid Quigley }
6413746df9b5SDavid Quigley 
6414dc49c1f9SCatherine Zhang static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
6415dc49c1f9SCatherine Zhang {
6416aa8e712cSStephen Smalley 	return security_sid_to_context(&selinux_state, secid,
6417aa8e712cSStephen Smalley 				       secdata, seclen);
6418dc49c1f9SCatherine Zhang }
6419dc49c1f9SCatherine Zhang 
64207bf570dcSDavid Howells static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
642163cb3449SDavid Howells {
6422aa8e712cSStephen Smalley 	return security_context_to_sid(&selinux_state, secdata, seclen,
6423aa8e712cSStephen Smalley 				       secid, GFP_KERNEL);
642463cb3449SDavid Howells }
642563cb3449SDavid Howells 
6426dc49c1f9SCatherine Zhang static void selinux_release_secctx(char *secdata, u32 seclen)
6427dc49c1f9SCatherine Zhang {
6428dc49c1f9SCatherine Zhang 	kfree(secdata);
6429dc49c1f9SCatherine Zhang }
6430dc49c1f9SCatherine Zhang 
64316f3be9f5SAndreas Gruenbacher static void selinux_inode_invalidate_secctx(struct inode *inode)
64326f3be9f5SAndreas Gruenbacher {
643380788c22SCasey Schaufler 	struct inode_security_struct *isec = selinux_inode(inode);
64346f3be9f5SAndreas Gruenbacher 
64359287aed2SAndreas Gruenbacher 	spin_lock(&isec->lock);
64366f3be9f5SAndreas Gruenbacher 	isec->initialized = LABEL_INVALID;
64379287aed2SAndreas Gruenbacher 	spin_unlock(&isec->lock);
64386f3be9f5SAndreas Gruenbacher }
64396f3be9f5SAndreas Gruenbacher 
64401ee65e37SDavid P. Quigley /*
64411ee65e37SDavid P. Quigley  *	called with inode->i_mutex locked
64421ee65e37SDavid P. Quigley  */
64431ee65e37SDavid P. Quigley static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
64441ee65e37SDavid P. Quigley {
644553e0c2aaSOndrej Mosnacek 	int rc = selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX,
644653e0c2aaSOndrej Mosnacek 					   ctx, ctxlen, 0);
644753e0c2aaSOndrej Mosnacek 	/* Do not return error when suppressing label (SBLABEL_MNT not set). */
644853e0c2aaSOndrej Mosnacek 	return rc == -EOPNOTSUPP ? 0 : rc;
64491ee65e37SDavid P. Quigley }
64501ee65e37SDavid P. Quigley 
64511ee65e37SDavid P. Quigley /*
64521ee65e37SDavid P. Quigley  *	called with inode->i_mutex locked
64531ee65e37SDavid P. Quigley  */
64541ee65e37SDavid P. Quigley static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
64551ee65e37SDavid P. Quigley {
64561ee65e37SDavid P. Quigley 	return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
64571ee65e37SDavid P. Quigley }
64581ee65e37SDavid P. Quigley 
64591ee65e37SDavid P. Quigley static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
64601ee65e37SDavid P. Quigley {
64611ee65e37SDavid P. Quigley 	int len = 0;
64621ee65e37SDavid P. Quigley 	len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
64631ee65e37SDavid P. Quigley 						ctx, true);
64641ee65e37SDavid P. Quigley 	if (len < 0)
64651ee65e37SDavid P. Quigley 		return len;
64661ee65e37SDavid P. Quigley 	*ctxlen = len;
64671ee65e37SDavid P. Quigley 	return 0;
64681ee65e37SDavid P. Quigley }
6469d720024eSMichael LeMay #ifdef CONFIG_KEYS
6470d720024eSMichael LeMay 
6471d84f4f99SDavid Howells static int selinux_key_alloc(struct key *k, const struct cred *cred,
64727e047ef5SDavid Howells 			     unsigned long flags)
6473d720024eSMichael LeMay {
6474d84f4f99SDavid Howells 	const struct task_security_struct *tsec;
6475d720024eSMichael LeMay 	struct key_security_struct *ksec;
6476d720024eSMichael LeMay 
6477d720024eSMichael LeMay 	ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
6478d720024eSMichael LeMay 	if (!ksec)
6479d720024eSMichael LeMay 		return -ENOMEM;
6480d720024eSMichael LeMay 
64810c6cfa62SCasey Schaufler 	tsec = selinux_cred(cred);
6482d84f4f99SDavid Howells 	if (tsec->keycreate_sid)
6483d84f4f99SDavid Howells 		ksec->sid = tsec->keycreate_sid;
64844eb582cfSMichael LeMay 	else
6485d84f4f99SDavid Howells 		ksec->sid = tsec->sid;
6486d720024eSMichael LeMay 
6487275bb41eSDavid Howells 	k->security = ksec;
6488d720024eSMichael LeMay 	return 0;
6489d720024eSMichael LeMay }
6490d720024eSMichael LeMay 
6491d720024eSMichael LeMay static void selinux_key_free(struct key *k)
6492d720024eSMichael LeMay {
6493d720024eSMichael LeMay 	struct key_security_struct *ksec = k->security;
6494d720024eSMichael LeMay 
6495d720024eSMichael LeMay 	k->security = NULL;
6496d720024eSMichael LeMay 	kfree(ksec);
6497d720024eSMichael LeMay }
6498d720024eSMichael LeMay 
6499d720024eSMichael LeMay static int selinux_key_permission(key_ref_t key_ref,
6500d84f4f99SDavid Howells 				  const struct cred *cred,
6501f5895943SDavid Howells 				  unsigned perm)
6502d720024eSMichael LeMay {
6503d720024eSMichael LeMay 	struct key *key;
6504d720024eSMichael LeMay 	struct key_security_struct *ksec;
6505275bb41eSDavid Howells 	u32 sid;
6506d720024eSMichael LeMay 
6507d720024eSMichael LeMay 	/* if no specific permissions are requested, we skip the
6508d720024eSMichael LeMay 	   permission check. No serious, additional covert channels
6509d720024eSMichael LeMay 	   appear to be created. */
6510d720024eSMichael LeMay 	if (perm == 0)
6511d720024eSMichael LeMay 		return 0;
6512d720024eSMichael LeMay 
6513d84f4f99SDavid Howells 	sid = cred_sid(cred);
6514275bb41eSDavid Howells 
6515275bb41eSDavid Howells 	key = key_ref_to_ptr(key_ref);
6516275bb41eSDavid Howells 	ksec = key->security;
6517275bb41eSDavid Howells 
65186b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
6519*028db3e2SLinus Torvalds 			    sid, ksec->sid, SECCLASS_KEY, perm, NULL);
6520d720024eSMichael LeMay }
6521d720024eSMichael LeMay 
652270a5bb72SDavid Howells static int selinux_key_getsecurity(struct key *key, char **_buffer)
652370a5bb72SDavid Howells {
652470a5bb72SDavid Howells 	struct key_security_struct *ksec = key->security;
652570a5bb72SDavid Howells 	char *context = NULL;
652670a5bb72SDavid Howells 	unsigned len;
652770a5bb72SDavid Howells 	int rc;
652870a5bb72SDavid Howells 
6529aa8e712cSStephen Smalley 	rc = security_sid_to_context(&selinux_state, ksec->sid,
6530aa8e712cSStephen Smalley 				     &context, &len);
653170a5bb72SDavid Howells 	if (!rc)
653270a5bb72SDavid Howells 		rc = len;
653370a5bb72SDavid Howells 	*_buffer = context;
653470a5bb72SDavid Howells 	return rc;
653570a5bb72SDavid Howells }
65363a976fa6SDaniel Jurgens #endif
653770a5bb72SDavid Howells 
65383a976fa6SDaniel Jurgens #ifdef CONFIG_SECURITY_INFINIBAND
6539cfc4d882SDaniel Jurgens static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val)
6540cfc4d882SDaniel Jurgens {
6541cfc4d882SDaniel Jurgens 	struct common_audit_data ad;
6542cfc4d882SDaniel Jurgens 	int err;
6543cfc4d882SDaniel Jurgens 	u32 sid = 0;
6544cfc4d882SDaniel Jurgens 	struct ib_security_struct *sec = ib_sec;
6545cfc4d882SDaniel Jurgens 	struct lsm_ibpkey_audit ibpkey;
6546cfc4d882SDaniel Jurgens 
6547409dcf31SDaniel Jurgens 	err = sel_ib_pkey_sid(subnet_prefix, pkey_val, &sid);
6548cfc4d882SDaniel Jurgens 	if (err)
6549cfc4d882SDaniel Jurgens 		return err;
6550cfc4d882SDaniel Jurgens 
6551cfc4d882SDaniel Jurgens 	ad.type = LSM_AUDIT_DATA_IBPKEY;
6552cfc4d882SDaniel Jurgens 	ibpkey.subnet_prefix = subnet_prefix;
6553cfc4d882SDaniel Jurgens 	ibpkey.pkey = pkey_val;
6554cfc4d882SDaniel Jurgens 	ad.u.ibpkey = &ibpkey;
65556b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
65566b6bc620SStephen Smalley 			    sec->sid, sid,
6557cfc4d882SDaniel Jurgens 			    SECCLASS_INFINIBAND_PKEY,
6558cfc4d882SDaniel Jurgens 			    INFINIBAND_PKEY__ACCESS, &ad);
6559cfc4d882SDaniel Jurgens }
6560cfc4d882SDaniel Jurgens 
6561ab861dfcSDaniel Jurgens static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
6562ab861dfcSDaniel Jurgens 					    u8 port_num)
6563ab861dfcSDaniel Jurgens {
6564ab861dfcSDaniel Jurgens 	struct common_audit_data ad;
6565ab861dfcSDaniel Jurgens 	int err;
6566ab861dfcSDaniel Jurgens 	u32 sid = 0;
6567ab861dfcSDaniel Jurgens 	struct ib_security_struct *sec = ib_sec;
6568ab861dfcSDaniel Jurgens 	struct lsm_ibendport_audit ibendport;
6569ab861dfcSDaniel Jurgens 
6570aa8e712cSStephen Smalley 	err = security_ib_endport_sid(&selinux_state, dev_name, port_num,
6571aa8e712cSStephen Smalley 				      &sid);
6572ab861dfcSDaniel Jurgens 
6573ab861dfcSDaniel Jurgens 	if (err)
6574ab861dfcSDaniel Jurgens 		return err;
6575ab861dfcSDaniel Jurgens 
6576ab861dfcSDaniel Jurgens 	ad.type = LSM_AUDIT_DATA_IBENDPORT;
6577ab861dfcSDaniel Jurgens 	strncpy(ibendport.dev_name, dev_name, sizeof(ibendport.dev_name));
6578ab861dfcSDaniel Jurgens 	ibendport.port = port_num;
6579ab861dfcSDaniel Jurgens 	ad.u.ibendport = &ibendport;
65806b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
65816b6bc620SStephen Smalley 			    sec->sid, sid,
6582ab861dfcSDaniel Jurgens 			    SECCLASS_INFINIBAND_ENDPORT,
6583ab861dfcSDaniel Jurgens 			    INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
6584ab861dfcSDaniel Jurgens }
6585ab861dfcSDaniel Jurgens 
65863a976fa6SDaniel Jurgens static int selinux_ib_alloc_security(void **ib_sec)
65873a976fa6SDaniel Jurgens {
65883a976fa6SDaniel Jurgens 	struct ib_security_struct *sec;
65893a976fa6SDaniel Jurgens 
65903a976fa6SDaniel Jurgens 	sec = kzalloc(sizeof(*sec), GFP_KERNEL);
65913a976fa6SDaniel Jurgens 	if (!sec)
65923a976fa6SDaniel Jurgens 		return -ENOMEM;
65933a976fa6SDaniel Jurgens 	sec->sid = current_sid();
65943a976fa6SDaniel Jurgens 
65953a976fa6SDaniel Jurgens 	*ib_sec = sec;
65963a976fa6SDaniel Jurgens 	return 0;
65973a976fa6SDaniel Jurgens }
65983a976fa6SDaniel Jurgens 
65993a976fa6SDaniel Jurgens static void selinux_ib_free_security(void *ib_sec)
66003a976fa6SDaniel Jurgens {
66013a976fa6SDaniel Jurgens 	kfree(ib_sec);
66023a976fa6SDaniel Jurgens }
6603d720024eSMichael LeMay #endif
6604d720024eSMichael LeMay 
6605ec27c356SChenbo Feng #ifdef CONFIG_BPF_SYSCALL
6606ec27c356SChenbo Feng static int selinux_bpf(int cmd, union bpf_attr *attr,
6607ec27c356SChenbo Feng 				     unsigned int size)
6608ec27c356SChenbo Feng {
6609ec27c356SChenbo Feng 	u32 sid = current_sid();
6610ec27c356SChenbo Feng 	int ret;
6611ec27c356SChenbo Feng 
6612ec27c356SChenbo Feng 	switch (cmd) {
6613ec27c356SChenbo Feng 	case BPF_MAP_CREATE:
66146b6bc620SStephen Smalley 		ret = avc_has_perm(&selinux_state,
66156b6bc620SStephen Smalley 				   sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
6616ec27c356SChenbo Feng 				   NULL);
6617ec27c356SChenbo Feng 		break;
6618ec27c356SChenbo Feng 	case BPF_PROG_LOAD:
66196b6bc620SStephen Smalley 		ret = avc_has_perm(&selinux_state,
66206b6bc620SStephen Smalley 				   sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
6621ec27c356SChenbo Feng 				   NULL);
6622ec27c356SChenbo Feng 		break;
6623ec27c356SChenbo Feng 	default:
6624ec27c356SChenbo Feng 		ret = 0;
6625ec27c356SChenbo Feng 		break;
6626ec27c356SChenbo Feng 	}
6627ec27c356SChenbo Feng 
6628ec27c356SChenbo Feng 	return ret;
6629ec27c356SChenbo Feng }
6630ec27c356SChenbo Feng 
6631ec27c356SChenbo Feng static u32 bpf_map_fmode_to_av(fmode_t fmode)
6632ec27c356SChenbo Feng {
6633ec27c356SChenbo Feng 	u32 av = 0;
6634ec27c356SChenbo Feng 
6635ec27c356SChenbo Feng 	if (fmode & FMODE_READ)
6636ec27c356SChenbo Feng 		av |= BPF__MAP_READ;
6637ec27c356SChenbo Feng 	if (fmode & FMODE_WRITE)
6638ec27c356SChenbo Feng 		av |= BPF__MAP_WRITE;
6639ec27c356SChenbo Feng 	return av;
6640ec27c356SChenbo Feng }
6641ec27c356SChenbo Feng 
6642f66e448cSChenbo Feng /* This function will check the file pass through unix socket or binder to see
6643f66e448cSChenbo Feng  * if it is a bpf related object. And apply correspinding checks on the bpf
6644f66e448cSChenbo Feng  * object based on the type. The bpf maps and programs, not like other files and
6645f66e448cSChenbo Feng  * socket, are using a shared anonymous inode inside the kernel as their inode.
6646f66e448cSChenbo Feng  * So checking that inode cannot identify if the process have privilege to
6647f66e448cSChenbo Feng  * access the bpf object and that's why we have to add this additional check in
6648f66e448cSChenbo Feng  * selinux_file_receive and selinux_binder_transfer_files.
6649f66e448cSChenbo Feng  */
6650f66e448cSChenbo Feng static int bpf_fd_pass(struct file *file, u32 sid)
6651f66e448cSChenbo Feng {
6652f66e448cSChenbo Feng 	struct bpf_security_struct *bpfsec;
6653f66e448cSChenbo Feng 	struct bpf_prog *prog;
6654f66e448cSChenbo Feng 	struct bpf_map *map;
6655f66e448cSChenbo Feng 	int ret;
6656f66e448cSChenbo Feng 
6657f66e448cSChenbo Feng 	if (file->f_op == &bpf_map_fops) {
6658f66e448cSChenbo Feng 		map = file->private_data;
6659f66e448cSChenbo Feng 		bpfsec = map->security;
66606b6bc620SStephen Smalley 		ret = avc_has_perm(&selinux_state,
66616b6bc620SStephen Smalley 				   sid, bpfsec->sid, SECCLASS_BPF,
6662f66e448cSChenbo Feng 				   bpf_map_fmode_to_av(file->f_mode), NULL);
6663f66e448cSChenbo Feng 		if (ret)
6664f66e448cSChenbo Feng 			return ret;
6665f66e448cSChenbo Feng 	} else if (file->f_op == &bpf_prog_fops) {
6666f66e448cSChenbo Feng 		prog = file->private_data;
6667f66e448cSChenbo Feng 		bpfsec = prog->aux->security;
66686b6bc620SStephen Smalley 		ret = avc_has_perm(&selinux_state,
66696b6bc620SStephen Smalley 				   sid, bpfsec->sid, SECCLASS_BPF,
6670f66e448cSChenbo Feng 				   BPF__PROG_RUN, NULL);
6671f66e448cSChenbo Feng 		if (ret)
6672f66e448cSChenbo Feng 			return ret;
6673f66e448cSChenbo Feng 	}
6674f66e448cSChenbo Feng 	return 0;
6675f66e448cSChenbo Feng }
6676f66e448cSChenbo Feng 
6677ec27c356SChenbo Feng static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
6678ec27c356SChenbo Feng {
6679ec27c356SChenbo Feng 	u32 sid = current_sid();
6680ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec;
6681ec27c356SChenbo Feng 
6682ec27c356SChenbo Feng 	bpfsec = map->security;
66836b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
66846b6bc620SStephen Smalley 			    sid, bpfsec->sid, SECCLASS_BPF,
6685ec27c356SChenbo Feng 			    bpf_map_fmode_to_av(fmode), NULL);
6686ec27c356SChenbo Feng }
6687ec27c356SChenbo Feng 
6688ec27c356SChenbo Feng static int selinux_bpf_prog(struct bpf_prog *prog)
6689ec27c356SChenbo Feng {
6690ec27c356SChenbo Feng 	u32 sid = current_sid();
6691ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec;
6692ec27c356SChenbo Feng 
6693ec27c356SChenbo Feng 	bpfsec = prog->aux->security;
66946b6bc620SStephen Smalley 	return avc_has_perm(&selinux_state,
66956b6bc620SStephen Smalley 			    sid, bpfsec->sid, SECCLASS_BPF,
6696ec27c356SChenbo Feng 			    BPF__PROG_RUN, NULL);
6697ec27c356SChenbo Feng }
6698ec27c356SChenbo Feng 
6699ec27c356SChenbo Feng static int selinux_bpf_map_alloc(struct bpf_map *map)
6700ec27c356SChenbo Feng {
6701ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec;
6702ec27c356SChenbo Feng 
6703ec27c356SChenbo Feng 	bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
6704ec27c356SChenbo Feng 	if (!bpfsec)
6705ec27c356SChenbo Feng 		return -ENOMEM;
6706ec27c356SChenbo Feng 
6707ec27c356SChenbo Feng 	bpfsec->sid = current_sid();
6708ec27c356SChenbo Feng 	map->security = bpfsec;
6709ec27c356SChenbo Feng 
6710ec27c356SChenbo Feng 	return 0;
6711ec27c356SChenbo Feng }
6712ec27c356SChenbo Feng 
6713ec27c356SChenbo Feng static void selinux_bpf_map_free(struct bpf_map *map)
6714ec27c356SChenbo Feng {
6715ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec = map->security;
6716ec27c356SChenbo Feng 
6717ec27c356SChenbo Feng 	map->security = NULL;
6718ec27c356SChenbo Feng 	kfree(bpfsec);
6719ec27c356SChenbo Feng }
6720ec27c356SChenbo Feng 
6721ec27c356SChenbo Feng static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
6722ec27c356SChenbo Feng {
6723ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec;
6724ec27c356SChenbo Feng 
6725ec27c356SChenbo Feng 	bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
6726ec27c356SChenbo Feng 	if (!bpfsec)
6727ec27c356SChenbo Feng 		return -ENOMEM;
6728ec27c356SChenbo Feng 
6729ec27c356SChenbo Feng 	bpfsec->sid = current_sid();
6730ec27c356SChenbo Feng 	aux->security = bpfsec;
6731ec27c356SChenbo Feng 
6732ec27c356SChenbo Feng 	return 0;
6733ec27c356SChenbo Feng }
6734ec27c356SChenbo Feng 
6735ec27c356SChenbo Feng static void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
6736ec27c356SChenbo Feng {
6737ec27c356SChenbo Feng 	struct bpf_security_struct *bpfsec = aux->security;
6738ec27c356SChenbo Feng 
6739ec27c356SChenbo Feng 	aux->security = NULL;
6740ec27c356SChenbo Feng 	kfree(bpfsec);
6741ec27c356SChenbo Feng }
6742ec27c356SChenbo Feng #endif
6743ec27c356SChenbo Feng 
6744bbd3662aSCasey Schaufler struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
6745bbd3662aSCasey Schaufler 	.lbs_cred = sizeof(struct task_security_struct),
674633bf60caSCasey Schaufler 	.lbs_file = sizeof(struct file_security_struct),
6747afb1cbe3SCasey Schaufler 	.lbs_inode = sizeof(struct inode_security_struct),
6748ecd5f82eSCasey Schaufler 	.lbs_ipc = sizeof(struct ipc_security_struct),
6749ecd5f82eSCasey Schaufler 	.lbs_msg_msg = sizeof(struct msg_security_struct),
6750bbd3662aSCasey Schaufler };
6751bbd3662aSCasey Schaufler 
6752ca97d939SJames Morris static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = {
6753e20b043aSCasey Schaufler 	LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
6754e20b043aSCasey Schaufler 	LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
6755e20b043aSCasey Schaufler 	LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
6756e20b043aSCasey Schaufler 	LSM_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file),
6757076c54c5SAhmed S. Darwish 
6758e20b043aSCasey Schaufler 	LSM_HOOK_INIT(ptrace_access_check, selinux_ptrace_access_check),
6759e20b043aSCasey Schaufler 	LSM_HOOK_INIT(ptrace_traceme, selinux_ptrace_traceme),
6760e20b043aSCasey Schaufler 	LSM_HOOK_INIT(capget, selinux_capget),
6761e20b043aSCasey Schaufler 	LSM_HOOK_INIT(capset, selinux_capset),
6762e20b043aSCasey Schaufler 	LSM_HOOK_INIT(capable, selinux_capable),
6763e20b043aSCasey Schaufler 	LSM_HOOK_INIT(quotactl, selinux_quotactl),
6764e20b043aSCasey Schaufler 	LSM_HOOK_INIT(quota_on, selinux_quota_on),
6765e20b043aSCasey Schaufler 	LSM_HOOK_INIT(syslog, selinux_syslog),
6766e20b043aSCasey Schaufler 	LSM_HOOK_INIT(vm_enough_memory, selinux_vm_enough_memory),
676779af7307SStephen Smalley 
6768e20b043aSCasey Schaufler 	LSM_HOOK_INIT(netlink_send, selinux_netlink_send),
67691da177e4SLinus Torvalds 
6770e20b043aSCasey Schaufler 	LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds),
6771e20b043aSCasey Schaufler 	LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
6772e20b043aSCasey Schaufler 	LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
67731da177e4SLinus Torvalds 
67740b52075eSAl Viro 	LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
6775442155c1SDavid Howells 	LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param),
6776442155c1SDavid Howells 
6777e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
6778e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security),
67795b400239SAl Viro 	LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
6780204cc0ccSAl Viro 	LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
6781e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
6782e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
6783e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
6784e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs),
6785e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_mount, selinux_mount),
6786e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_umount, selinux_umount),
6787e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts),
6788e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts),
6789757cbe59SAl Viro 	LSM_HOOK_INIT(sb_add_mnt_opt, selinux_add_mnt_opt),
67901da177e4SLinus Torvalds 
6791e20b043aSCasey Schaufler 	LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security),
6792a518b0a5SVivek Goyal 	LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as),
6793e0007529SEric Paris 
6794e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
6795e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security),
6796e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security),
6797e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_create, selinux_inode_create),
6798e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_link, selinux_inode_link),
6799e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink),
6800e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_symlink, selinux_inode_symlink),
6801e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_mkdir, selinux_inode_mkdir),
6802e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_rmdir, selinux_inode_rmdir),
6803e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_mknod, selinux_inode_mknod),
6804e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_rename, selinux_inode_rename),
6805e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_readlink, selinux_inode_readlink),
6806e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_follow_link, selinux_inode_follow_link),
6807e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_permission, selinux_inode_permission),
6808e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr),
6809e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr),
6810e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr),
6811e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr),
6812e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
6813e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr),
6814e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr),
6815e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
6816e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
6817e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
6818e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
681956909eb3SVivek Goyal 	LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
682019472b69SVivek Goyal 	LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
68211da177e4SLinus Torvalds 
6822ec882da5SOndrej Mosnacek 	LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security),
6823ec882da5SOndrej Mosnacek 
6824e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_permission, selinux_file_permission),
6825e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
6826e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
6827e20b043aSCasey Schaufler 	LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
6828e20b043aSCasey Schaufler 	LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
6829e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
6830e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_lock, selinux_file_lock),
6831e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_fcntl, selinux_file_fcntl),
6832e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_set_fowner, selinux_file_set_fowner),
6833e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_send_sigiotask, selinux_file_send_sigiotask),
6834e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_receive, selinux_file_receive),
68351da177e4SLinus Torvalds 
6836e20b043aSCasey Schaufler 	LSM_HOOK_INIT(file_open, selinux_file_open),
68371da177e4SLinus Torvalds 
6838a79be238STetsuo Handa 	LSM_HOOK_INIT(task_alloc, selinux_task_alloc),
6839e20b043aSCasey Schaufler 	LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
6840e20b043aSCasey Schaufler 	LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
68413ec30113SMatthew Garrett 	LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
6842e20b043aSCasey Schaufler 	LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
6843e20b043aSCasey Schaufler 	LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
6844e20b043aSCasey Schaufler 	LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
6845c77b8cdfSMimi Zohar 	LSM_HOOK_INIT(kernel_load_data, selinux_kernel_load_data),
684661d612eaSJeff Vander Stoep 	LSM_HOOK_INIT(kernel_read_file, selinux_kernel_read_file),
6847e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
6848e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
6849e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
6850e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_getsecid, selinux_task_getsecid),
6851e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
6852e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
6853e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
6854791ec491SStephen Smalley 	LSM_HOOK_INIT(task_prlimit, selinux_task_prlimit),
6855e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_setrlimit, selinux_task_setrlimit),
6856e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_setscheduler, selinux_task_setscheduler),
6857e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler),
6858e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_movememory, selinux_task_movememory),
6859e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_kill, selinux_task_kill),
6860e20b043aSCasey Schaufler 	LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode),
6861788e7dd4SYuichi Nakamura 
6862e20b043aSCasey Schaufler 	LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
6863e20b043aSCasey Schaufler 	LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
68641da177e4SLinus Torvalds 
6865e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security),
68661da177e4SLinus Torvalds 
6867e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_alloc_security,
6868e20b043aSCasey Schaufler 			selinux_msg_queue_alloc_security),
6869e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
6870e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
6871e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd),
6872e20b043aSCasey Schaufler 	LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv),
68731da177e4SLinus Torvalds 
6874e20b043aSCasey Schaufler 	LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
6875e20b043aSCasey Schaufler 	LSM_HOOK_INIT(shm_associate, selinux_shm_associate),
6876e20b043aSCasey Schaufler 	LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl),
6877e20b043aSCasey Schaufler 	LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat),
68781da177e4SLinus Torvalds 
6879e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
6880e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sem_associate, selinux_sem_associate),
6881e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl),
6882e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sem_semop, selinux_sem_semop),
68831da177e4SLinus Torvalds 
6884e20b043aSCasey Schaufler 	LSM_HOOK_INIT(d_instantiate, selinux_d_instantiate),
68851da177e4SLinus Torvalds 
6886e20b043aSCasey Schaufler 	LSM_HOOK_INIT(getprocattr, selinux_getprocattr),
6887e20b043aSCasey Schaufler 	LSM_HOOK_INIT(setprocattr, selinux_setprocattr),
68881da177e4SLinus Torvalds 
6889e20b043aSCasey Schaufler 	LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
6890e20b043aSCasey Schaufler 	LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
6891e20b043aSCasey Schaufler 	LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
6892e20b043aSCasey Schaufler 	LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
68936f3be9f5SAndreas Gruenbacher 	LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
6894e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
6895e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
6896e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
68971da177e4SLinus Torvalds 
6898e20b043aSCasey Schaufler 	LSM_HOOK_INIT(unix_stream_connect, selinux_socket_unix_stream_connect),
6899e20b043aSCasey Schaufler 	LSM_HOOK_INIT(unix_may_send, selinux_socket_unix_may_send),
6900dc49c1f9SCatherine Zhang 
6901e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_create, selinux_socket_create),
6902e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_post_create, selinux_socket_post_create),
69030b811db2SDavid Herrmann 	LSM_HOOK_INIT(socket_socketpair, selinux_socket_socketpair),
6904e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_bind, selinux_socket_bind),
6905e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_connect, selinux_socket_connect),
6906e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_listen, selinux_socket_listen),
6907e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_accept, selinux_socket_accept),
6908e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_sendmsg, selinux_socket_sendmsg),
6909e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_recvmsg, selinux_socket_recvmsg),
6910e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_getsockname, selinux_socket_getsockname),
6911e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_getpeername, selinux_socket_getpeername),
6912e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt),
6913e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt),
6914e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_shutdown, selinux_socket_shutdown),
6915e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb),
6916e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_getpeersec_stream,
6917e20b043aSCasey Schaufler 			selinux_socket_getpeersec_stream),
6918e20b043aSCasey Schaufler 	LSM_HOOK_INIT(socket_getpeersec_dgram, selinux_socket_getpeersec_dgram),
6919e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
6920e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sk_free_security, selinux_sk_free_security),
6921e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security),
6922e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid),
6923e20b043aSCasey Schaufler 	LSM_HOOK_INIT(sock_graft, selinux_sock_graft),
6924d452930fSRichard Haines 	LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request),
6925d452930fSRichard Haines 	LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
6926d452930fSRichard Haines 	LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
6927e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
6928e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
6929e20b043aSCasey Schaufler 	LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
6930e20b043aSCasey Schaufler 	LSM_HOOK_INIT(secmark_relabel_packet, selinux_secmark_relabel_packet),
6931e20b043aSCasey Schaufler 	LSM_HOOK_INIT(secmark_refcount_inc, selinux_secmark_refcount_inc),
6932e20b043aSCasey Schaufler 	LSM_HOOK_INIT(secmark_refcount_dec, selinux_secmark_refcount_dec),
6933e20b043aSCasey Schaufler 	LSM_HOOK_INIT(req_classify_flow, selinux_req_classify_flow),
6934e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),
6935e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_free_security, selinux_tun_dev_free_security),
6936e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_create, selinux_tun_dev_create),
6937e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue),
6938e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach),
6939e20b043aSCasey Schaufler 	LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open),
69403a976fa6SDaniel Jurgens #ifdef CONFIG_SECURITY_INFINIBAND
6941cfc4d882SDaniel Jurgens 	LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access),
6942ab861dfcSDaniel Jurgens 	LSM_HOOK_INIT(ib_endport_manage_subnet,
6943ab861dfcSDaniel Jurgens 		      selinux_ib_endport_manage_subnet),
69443a976fa6SDaniel Jurgens 	LSM_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security),
69453a976fa6SDaniel Jurgens 	LSM_HOOK_INIT(ib_free_security, selinux_ib_free_security),
69463a976fa6SDaniel Jurgens #endif
6947d28d1e08STrent Jaeger #ifdef CONFIG_SECURITY_NETWORK_XFRM
6948e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc),
6949e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone),
6950e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_policy_free_security, selinux_xfrm_policy_free),
6951e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_policy_delete_security, selinux_xfrm_policy_delete),
6952e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_state_alloc, selinux_xfrm_state_alloc),
6953e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_state_alloc_acquire,
6954e20b043aSCasey Schaufler 			selinux_xfrm_state_alloc_acquire),
6955e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_state_free_security, selinux_xfrm_state_free),
6956e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_state_delete_security, selinux_xfrm_state_delete),
6957e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_policy_lookup, selinux_xfrm_policy_lookup),
6958e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_state_pol_flow_match,
6959e20b043aSCasey Schaufler 			selinux_xfrm_state_pol_flow_match),
6960e20b043aSCasey Schaufler 	LSM_HOOK_INIT(xfrm_decode_session, selinux_xfrm_decode_session),
69611da177e4SLinus Torvalds #endif
6962d720024eSMichael LeMay 
6963d720024eSMichael LeMay #ifdef CONFIG_KEYS
6964e20b043aSCasey Schaufler 	LSM_HOOK_INIT(key_alloc, selinux_key_alloc),
6965e20b043aSCasey Schaufler 	LSM_HOOK_INIT(key_free, selinux_key_free),
6966e20b043aSCasey Schaufler 	LSM_HOOK_INIT(key_permission, selinux_key_permission),
6967e20b043aSCasey Schaufler 	LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
6968d720024eSMichael LeMay #endif
69699d57a7f9SAhmed S. Darwish 
69709d57a7f9SAhmed S. Darwish #ifdef CONFIG_AUDIT
6971e20b043aSCasey Schaufler 	LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init),
6972e20b043aSCasey Schaufler 	LSM_HOOK_INIT(audit_rule_known, selinux_audit_rule_known),
6973e20b043aSCasey Schaufler 	LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
6974e20b043aSCasey Schaufler 	LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
69759d57a7f9SAhmed S. Darwish #endif
6976ec27c356SChenbo Feng 
6977ec27c356SChenbo Feng #ifdef CONFIG_BPF_SYSCALL
6978ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf, selinux_bpf),
6979ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
6980ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
6981ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
6982ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
6983ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
6984ec27c356SChenbo Feng 	LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
6985ec27c356SChenbo Feng #endif
69861da177e4SLinus Torvalds };
69871da177e4SLinus Torvalds 
69881da177e4SLinus Torvalds static __init int selinux_init(void)
69891da177e4SLinus Torvalds {
6990c103a91eSpeter enderborg 	pr_info("SELinux:  Initializing.\n");
69911da177e4SLinus Torvalds 
6992aa8e712cSStephen Smalley 	memset(&selinux_state, 0, sizeof(selinux_state));
6993e5a5ca96SPaul Moore 	enforcing_set(&selinux_state, selinux_enforcing_boot);
6994aa8e712cSStephen Smalley 	selinux_state.checkreqprot = selinux_checkreqprot_boot;
6995aa8e712cSStephen Smalley 	selinux_ss_init(&selinux_state.ss);
69966b6bc620SStephen Smalley 	selinux_avc_init(&selinux_state.avc);
6997aa8e712cSStephen Smalley 
69981da177e4SLinus Torvalds 	/* Set the security state for the initial task. */
6999d84f4f99SDavid Howells 	cred_init_security();
70001da177e4SLinus Torvalds 
7001fcaaade1SStephen Smalley 	default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
7002fcaaade1SStephen Smalley 
70031da177e4SLinus Torvalds 	avc_init();
70041da177e4SLinus Torvalds 
7005aa8e712cSStephen Smalley 	avtab_cache_init();
7006aa8e712cSStephen Smalley 
7007aa8e712cSStephen Smalley 	ebitmap_cache_init();
7008aa8e712cSStephen Smalley 
7009aa8e712cSStephen Smalley 	hashtab_cache_init();
7010aa8e712cSStephen Smalley 
7011d69dece5SCasey Schaufler 	security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
70121da177e4SLinus Torvalds 
7013615e51fdSPaul Moore 	if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
7014615e51fdSPaul Moore 		panic("SELinux: Unable to register AVC netcache callback\n");
7015615e51fdSPaul Moore 
70168f408ab6SDaniel Jurgens 	if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET))
70178f408ab6SDaniel Jurgens 		panic("SELinux: Unable to register AVC LSM notifier callback\n");
70188f408ab6SDaniel Jurgens 
7019aa8e712cSStephen Smalley 	if (selinux_enforcing_boot)
7020c103a91eSpeter enderborg 		pr_debug("SELinux:  Starting in enforcing mode\n");
7021828dfe1dSEric Paris 	else
7022c103a91eSpeter enderborg 		pr_debug("SELinux:  Starting in permissive mode\n");
7023d720024eSMichael LeMay 
7024442155c1SDavid Howells 	fs_validate_description(&selinux_fs_parameters);
7025442155c1SDavid Howells 
70261da177e4SLinus Torvalds 	return 0;
70271da177e4SLinus Torvalds }
70281da177e4SLinus Torvalds 
7029e8c26255SAl Viro static void delayed_superblock_init(struct super_block *sb, void *unused)
7030e8c26255SAl Viro {
7031204cc0ccSAl Viro 	selinux_set_mnt_opts(sb, NULL, 0, NULL);
7032e8c26255SAl Viro }
7033e8c26255SAl Viro 
70341da177e4SLinus Torvalds void selinux_complete_init(void)
70351da177e4SLinus Torvalds {
7036c103a91eSpeter enderborg 	pr_debug("SELinux:  Completing initialization.\n");
70371da177e4SLinus Torvalds 
70381da177e4SLinus Torvalds 	/* Set up any superblocks initialized prior to the policy load. */
7039c103a91eSpeter enderborg 	pr_debug("SELinux:  Setting up existing superblocks.\n");
7040e8c26255SAl Viro 	iterate_supers(delayed_superblock_init, NULL);
70411da177e4SLinus Torvalds }
70421da177e4SLinus Torvalds 
70431da177e4SLinus Torvalds /* SELinux requires early initialization in order to label
70441da177e4SLinus Torvalds    all processes and objects when they are created. */
70453d6e5f6dSKees Cook DEFINE_LSM(selinux) = {
704607aed2f2SKees Cook 	.name = "selinux",
704714bd99c8SKees Cook 	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
7048c5459b82SKees Cook 	.enabled = &selinux_enabled,
7049bbd3662aSCasey Schaufler 	.blobs = &selinux_blob_sizes,
70503d6e5f6dSKees Cook 	.init = selinux_init,
70513d6e5f6dSKees Cook };
70521da177e4SLinus Torvalds 
7053c2b507fdSStephen Smalley #if defined(CONFIG_NETFILTER)
70541da177e4SLinus Torvalds 
7055591bb278SFlorian Westphal static const struct nf_hook_ops selinux_nf_ops[] = {
7056effad8dfSPaul Moore 	{
7057effad8dfSPaul Moore 		.hook =		selinux_ipv4_postroute,
70582597a834SAlban Crequy 		.pf =		NFPROTO_IPV4,
70596e23ae2aSPatrick McHardy 		.hooknum =	NF_INET_POST_ROUTING,
70601da177e4SLinus Torvalds 		.priority =	NF_IP_PRI_SELINUX_LAST,
7061effad8dfSPaul Moore 	},
7062effad8dfSPaul Moore 	{
7063effad8dfSPaul Moore 		.hook =		selinux_ipv4_forward,
70642597a834SAlban Crequy 		.pf =		NFPROTO_IPV4,
7065effad8dfSPaul Moore 		.hooknum =	NF_INET_FORWARD,
7066effad8dfSPaul Moore 		.priority =	NF_IP_PRI_SELINUX_FIRST,
7067948bf85cSPaul Moore 	},
7068948bf85cSPaul Moore 	{
7069948bf85cSPaul Moore 		.hook =		selinux_ipv4_output,
70702597a834SAlban Crequy 		.pf =		NFPROTO_IPV4,
7071948bf85cSPaul Moore 		.hooknum =	NF_INET_LOCAL_OUT,
7072948bf85cSPaul Moore 		.priority =	NF_IP_PRI_SELINUX_FIRST,
707325db6beaSJiri Pirko 	},
70741a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6)
7075effad8dfSPaul Moore 	{
7076effad8dfSPaul Moore 		.hook =		selinux_ipv6_postroute,
70772597a834SAlban Crequy 		.pf =		NFPROTO_IPV6,
70786e23ae2aSPatrick McHardy 		.hooknum =	NF_INET_POST_ROUTING,
70791da177e4SLinus Torvalds 		.priority =	NF_IP6_PRI_SELINUX_LAST,
7080effad8dfSPaul Moore 	},
7081effad8dfSPaul Moore 	{
7082effad8dfSPaul Moore 		.hook =		selinux_ipv6_forward,
70832597a834SAlban Crequy 		.pf =		NFPROTO_IPV6,
7084effad8dfSPaul Moore 		.hooknum =	NF_INET_FORWARD,
7085effad8dfSPaul Moore 		.priority =	NF_IP6_PRI_SELINUX_FIRST,
708625db6beaSJiri Pirko 	},
70872917f57bSHuw Davies 	{
70882917f57bSHuw Davies 		.hook =		selinux_ipv6_output,
70892917f57bSHuw Davies 		.pf =		NFPROTO_IPV6,
70902917f57bSHuw Davies 		.hooknum =	NF_INET_LOCAL_OUT,
70912917f57bSHuw Davies 		.priority =	NF_IP6_PRI_SELINUX_FIRST,
70922917f57bSHuw Davies 	},
70931da177e4SLinus Torvalds #endif	/* IPV6 */
709425db6beaSJiri Pirko };
70951da177e4SLinus Torvalds 
70968e71bf75SFlorian Westphal static int __net_init selinux_nf_register(struct net *net)
70978e71bf75SFlorian Westphal {
70988e71bf75SFlorian Westphal 	return nf_register_net_hooks(net, selinux_nf_ops,
70998e71bf75SFlorian Westphal 				     ARRAY_SIZE(selinux_nf_ops));
71008e71bf75SFlorian Westphal }
71018e71bf75SFlorian Westphal 
71028e71bf75SFlorian Westphal static void __net_exit selinux_nf_unregister(struct net *net)
71038e71bf75SFlorian Westphal {
71048e71bf75SFlorian Westphal 	nf_unregister_net_hooks(net, selinux_nf_ops,
71058e71bf75SFlorian Westphal 				ARRAY_SIZE(selinux_nf_ops));
71068e71bf75SFlorian Westphal }
71078e71bf75SFlorian Westphal 
71088e71bf75SFlorian Westphal static struct pernet_operations selinux_net_ops = {
71098e71bf75SFlorian Westphal 	.init = selinux_nf_register,
71108e71bf75SFlorian Westphal 	.exit = selinux_nf_unregister,
71118e71bf75SFlorian Westphal };
71128e71bf75SFlorian Westphal 
71131da177e4SLinus Torvalds static int __init selinux_nf_ip_init(void)
71141da177e4SLinus Torvalds {
711525db6beaSJiri Pirko 	int err;
71161da177e4SLinus Torvalds 
71171da177e4SLinus Torvalds 	if (!selinux_enabled)
711825db6beaSJiri Pirko 		return 0;
71191da177e4SLinus Torvalds 
7120c103a91eSpeter enderborg 	pr_debug("SELinux:  Registering netfilter hooks\n");
71211da177e4SLinus Torvalds 
71228e71bf75SFlorian Westphal 	err = register_pernet_subsys(&selinux_net_ops);
71231da177e4SLinus Torvalds 	if (err)
71248e71bf75SFlorian Westphal 		panic("SELinux: register_pernet_subsys: error %d\n", err);
71251da177e4SLinus Torvalds 
712625db6beaSJiri Pirko 	return 0;
71271da177e4SLinus Torvalds }
71281da177e4SLinus Torvalds __initcall(selinux_nf_ip_init);
71291da177e4SLinus Torvalds 
71301da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE
71311da177e4SLinus Torvalds static void selinux_nf_ip_exit(void)
71321da177e4SLinus Torvalds {
7133c103a91eSpeter enderborg 	pr_debug("SELinux:  Unregistering netfilter hooks\n");
71341da177e4SLinus Torvalds 
71358e71bf75SFlorian Westphal 	unregister_pernet_subsys(&selinux_net_ops);
71361da177e4SLinus Torvalds }
71371da177e4SLinus Torvalds #endif
71381da177e4SLinus Torvalds 
7139c2b507fdSStephen Smalley #else /* CONFIG_NETFILTER */
71401da177e4SLinus Torvalds 
71411da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE
71421da177e4SLinus Torvalds #define selinux_nf_ip_exit()
71431da177e4SLinus Torvalds #endif
71441da177e4SLinus Torvalds 
7145c2b507fdSStephen Smalley #endif /* CONFIG_NETFILTER */
71461da177e4SLinus Torvalds 
71471da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE
7148aa8e712cSStephen Smalley int selinux_disable(struct selinux_state *state)
71491da177e4SLinus Torvalds {
7150aa8e712cSStephen Smalley 	if (state->initialized) {
71511da177e4SLinus Torvalds 		/* Not permitted after initial policy load. */
71521da177e4SLinus Torvalds 		return -EINVAL;
71531da177e4SLinus Torvalds 	}
71541da177e4SLinus Torvalds 
7155aa8e712cSStephen Smalley 	if (state->disabled) {
71561da177e4SLinus Torvalds 		/* Only do this once. */
71571da177e4SLinus Torvalds 		return -EINVAL;
71581da177e4SLinus Torvalds 	}
71591da177e4SLinus Torvalds 
7160aa8e712cSStephen Smalley 	state->disabled = 1;
7161aa8e712cSStephen Smalley 
7162c103a91eSpeter enderborg 	pr_info("SELinux:  Disabled at runtime.\n");
71631da177e4SLinus Torvalds 
716430d55280SStephen Smalley 	selinux_enabled = 0;
71651da177e4SLinus Torvalds 
7166b1d9e6b0SCasey Schaufler 	security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks));
71671da177e4SLinus Torvalds 
7168af8ff049SEric Paris 	/* Try to destroy the avc node cache */
7169af8ff049SEric Paris 	avc_disable();
7170af8ff049SEric Paris 
71711da177e4SLinus Torvalds 	/* Unregister netfilter hooks. */
71721da177e4SLinus Torvalds 	selinux_nf_ip_exit();
71731da177e4SLinus Torvalds 
71741da177e4SLinus Torvalds 	/* Unregister selinuxfs. */
71751da177e4SLinus Torvalds 	exit_sel_fs();
71761da177e4SLinus Torvalds 
71771da177e4SLinus Torvalds 	return 0;
71781da177e4SLinus Torvalds }
71791da177e4SLinus Torvalds #endif
7180