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