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(¤t->sighand->siglock); 25769e7c8f8cSOleg Nesterov if (!fatal_signal_pending(current)) { 25779e7c8f8cSOleg Nesterov flush_sigqueue(¤t->pending); 25789e7c8f8cSOleg Nesterov flush_sigqueue(¤t->signal->shared_pending); 25791da177e4SLinus Torvalds flush_signal_handlers(current, 1); 25801da177e4SLinus Torvalds sigemptyset(¤t->blocked); 25819e7c8f8cSOleg Nesterov recalc_sigpending(); 25823bcac026SDavid Howells } 25831da177e4SLinus Torvalds spin_unlock_irq(¤t->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