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 4361da177e4SLinus Torvalds static inline int inode_doinit(struct inode *inode) 4371da177e4SLinus Torvalds { 4381da177e4SLinus Torvalds return inode_doinit_with_dentry(inode, NULL); 4391da177e4SLinus Torvalds } 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds enum { 44231e87930SEric Paris Opt_error = -1, 4431da177e4SLinus Torvalds Opt_context = 1, 4441da177e4SLinus Torvalds Opt_fscontext = 2, 445c9180a57SEric Paris Opt_defcontext = 3, 446c9180a57SEric Paris Opt_rootcontext = 4, 44711689d47SDavid P. Quigley Opt_labelsupport = 5, 448d355987fSEric Paris Opt_nextmntopt = 6, 4491da177e4SLinus Torvalds }; 4501da177e4SLinus Torvalds 451d355987fSEric Paris #define NUM_SEL_MNT_OPTS (Opt_nextmntopt - 1) 452d355987fSEric Paris 453a447c093SSteven Whitehouse static const match_table_t tokens = { 454832cbd9aSEric Paris {Opt_context, CONTEXT_STR "%s"}, 455832cbd9aSEric Paris {Opt_fscontext, FSCONTEXT_STR "%s"}, 456832cbd9aSEric Paris {Opt_defcontext, DEFCONTEXT_STR "%s"}, 457832cbd9aSEric Paris {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, 45811689d47SDavid P. Quigley {Opt_labelsupport, LABELSUPP_STR}, 45931e87930SEric Paris {Opt_error, NULL}, 4601da177e4SLinus Torvalds }; 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" 4631da177e4SLinus Torvalds 464c312feb2SEric Paris static int may_context_mount_sb_relabel(u32 sid, 465c312feb2SEric Paris struct superblock_security_struct *sbsec, 466275bb41eSDavid Howells const struct cred *cred) 467c312feb2SEric Paris { 468275bb41eSDavid Howells const struct task_security_struct *tsec = cred->security; 469c312feb2SEric Paris int rc; 470c312feb2SEric Paris 4716b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 4726b6bc620SStephen Smalley tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, 473c312feb2SEric Paris FILESYSTEM__RELABELFROM, NULL); 474c312feb2SEric Paris if (rc) 475c312feb2SEric Paris return rc; 476c312feb2SEric Paris 4776b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 4786b6bc620SStephen Smalley tsec->sid, sid, SECCLASS_FILESYSTEM, 479c312feb2SEric Paris FILESYSTEM__RELABELTO, NULL); 480c312feb2SEric Paris return rc; 481c312feb2SEric Paris } 482c312feb2SEric Paris 4830808925eSEric Paris static int may_context_mount_inode_relabel(u32 sid, 4840808925eSEric Paris struct superblock_security_struct *sbsec, 485275bb41eSDavid Howells const struct cred *cred) 4860808925eSEric Paris { 487275bb41eSDavid Howells const struct task_security_struct *tsec = cred->security; 4880808925eSEric Paris int rc; 4896b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 4906b6bc620SStephen Smalley tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, 4910808925eSEric Paris FILESYSTEM__RELABELFROM, NULL); 4920808925eSEric Paris if (rc) 4930808925eSEric Paris return rc; 4940808925eSEric Paris 4956b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 4966b6bc620SStephen Smalley sid, sbsec->sid, SECCLASS_FILESYSTEM, 4970808925eSEric Paris FILESYSTEM__ASSOCIATE, NULL); 4980808925eSEric Paris return rc; 4990808925eSEric Paris } 5000808925eSEric Paris 501b43e725dSEric Paris static int selinux_is_sblabel_mnt(struct super_block *sb) 502b43e725dSEric Paris { 503b43e725dSEric Paris struct superblock_security_struct *sbsec = sb->s_security; 504b43e725dSEric Paris 505d5f3a5f6SMark Salyzyn return sbsec->behavior == SECURITY_FS_USE_XATTR || 506b43e725dSEric Paris sbsec->behavior == SECURITY_FS_USE_TRANS || 507d5f3a5f6SMark Salyzyn sbsec->behavior == SECURITY_FS_USE_TASK || 5089fc2b4b4SJ. Bruce Fields sbsec->behavior == SECURITY_FS_USE_NATIVE || 509d5f3a5f6SMark Salyzyn /* Special handling. Genfs but also in-core setxattr handler */ 510d5f3a5f6SMark Salyzyn !strcmp(sb->s_type->name, "sysfs") || 511d5f3a5f6SMark Salyzyn !strcmp(sb->s_type->name, "pstore") || 512d5f3a5f6SMark Salyzyn !strcmp(sb->s_type->name, "debugfs") || 513a2c7c6fbSYongqin Liu !strcmp(sb->s_type->name, "tracefs") || 5142651225bSStephen Smalley !strcmp(sb->s_type->name, "rootfs") || 515aa8e712cSStephen Smalley (selinux_policycap_cgroupseclabel() && 5162651225bSStephen Smalley (!strcmp(sb->s_type->name, "cgroup") || 5172651225bSStephen Smalley !strcmp(sb->s_type->name, "cgroup2"))); 518b43e725dSEric Paris } 519b43e725dSEric Paris 520c9180a57SEric Paris static int sb_finish_set_opts(struct super_block *sb) 5211da177e4SLinus Torvalds { 5221da177e4SLinus Torvalds struct superblock_security_struct *sbsec = sb->s_security; 5231da177e4SLinus Torvalds struct dentry *root = sb->s_root; 524c6f493d6SDavid Howells struct inode *root_inode = d_backing_inode(root); 5251da177e4SLinus Torvalds int rc = 0; 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds if (sbsec->behavior == SECURITY_FS_USE_XATTR) { 5281da177e4SLinus Torvalds /* Make sure that the xattr handler exists and that no 5291da177e4SLinus Torvalds error other than -ENODATA is returned by getxattr on 5301da177e4SLinus Torvalds the root directory. -ENODATA is ok, as this may be 5311da177e4SLinus Torvalds the first boot of the SELinux kernel before we have 5321da177e4SLinus Torvalds assigned xattr values to the filesystem. */ 5335d6c3191SAndreas Gruenbacher if (!(root_inode->i_opflags & IOP_XATTR)) { 534c103a91eSpeter enderborg pr_warn("SELinux: (dev %s, type %s) has no " 53529b1deb2SLinus Torvalds "xattr support\n", sb->s_id, sb->s_type->name); 5361da177e4SLinus Torvalds rc = -EOPNOTSUPP; 5371da177e4SLinus Torvalds goto out; 5381da177e4SLinus Torvalds } 5395d6c3191SAndreas Gruenbacher 5405d6c3191SAndreas Gruenbacher rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0); 5411da177e4SLinus Torvalds if (rc < 0 && rc != -ENODATA) { 5421da177e4SLinus Torvalds if (rc == -EOPNOTSUPP) 543c103a91eSpeter enderborg pr_warn("SELinux: (dev %s, type " 54429b1deb2SLinus Torvalds "%s) has no security xattr handler\n", 54529b1deb2SLinus Torvalds sb->s_id, sb->s_type->name); 5461da177e4SLinus Torvalds else 547c103a91eSpeter enderborg pr_warn("SELinux: (dev %s, type " 54829b1deb2SLinus Torvalds "%s) getxattr errno %d\n", sb->s_id, 54929b1deb2SLinus Torvalds sb->s_type->name, -rc); 5501da177e4SLinus Torvalds goto out; 5511da177e4SLinus Torvalds } 5521da177e4SLinus Torvalds } 5531da177e4SLinus Torvalds 554eadcabc6SEric Paris sbsec->flags |= SE_SBINITIALIZED; 5550b4d3452SScott Mayhew 5560b4d3452SScott Mayhew /* 5570b4d3452SScott Mayhew * Explicitly set or clear SBLABEL_MNT. It's not sufficient to simply 5580b4d3452SScott Mayhew * leave the flag untouched because sb_clone_mnt_opts might be handing 5590b4d3452SScott Mayhew * us a superblock that needs the flag to be cleared. 5600b4d3452SScott Mayhew */ 561b43e725dSEric Paris if (selinux_is_sblabel_mnt(sb)) 56212f348b9SEric Paris sbsec->flags |= SBLABEL_MNT; 5630b4d3452SScott Mayhew else 5640b4d3452SScott Mayhew sbsec->flags &= ~SBLABEL_MNT; 565ddd29ec6SDavid P. Quigley 5661da177e4SLinus Torvalds /* Initialize the root inode. */ 567c9180a57SEric Paris rc = inode_doinit_with_dentry(root_inode, root); 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds /* Initialize any other inodes associated with the superblock, e.g. 5701da177e4SLinus Torvalds inodes created prior to initial policy load or inodes created 5711da177e4SLinus Torvalds during get_sb by a pseudo filesystem that directly 5721da177e4SLinus Torvalds populates itself. */ 5731da177e4SLinus Torvalds spin_lock(&sbsec->isec_lock); 574*8d64124aSAl Viro while (!list_empty(&sbsec->isec_head)) { 5751da177e4SLinus Torvalds struct inode_security_struct *isec = 576*8d64124aSAl Viro list_first_entry(&sbsec->isec_head, 5771da177e4SLinus Torvalds struct inode_security_struct, list); 5781da177e4SLinus Torvalds struct inode *inode = isec->inode; 579923190d3SStephen Smalley list_del_init(&isec->list); 5801da177e4SLinus Torvalds spin_unlock(&sbsec->isec_lock); 5811da177e4SLinus Torvalds inode = igrab(inode); 5821da177e4SLinus Torvalds if (inode) { 5831da177e4SLinus Torvalds if (!IS_PRIVATE(inode)) 5841da177e4SLinus Torvalds inode_doinit(inode); 5851da177e4SLinus Torvalds iput(inode); 5861da177e4SLinus Torvalds } 5871da177e4SLinus Torvalds spin_lock(&sbsec->isec_lock); 5881da177e4SLinus Torvalds } 5891da177e4SLinus Torvalds spin_unlock(&sbsec->isec_lock); 5901da177e4SLinus Torvalds out: 591c9180a57SEric Paris return rc; 592c9180a57SEric Paris } 593c9180a57SEric Paris 594c9180a57SEric Paris /* 595c9180a57SEric Paris * This function should allow an FS to ask what it's mount security 596c9180a57SEric Paris * options were so it can use those later for submounts, displaying 597c9180a57SEric Paris * mount options, or whatever. 598c9180a57SEric Paris */ 599c9180a57SEric Paris static int selinux_get_mnt_opts(const struct super_block *sb, 600e0007529SEric Paris struct security_mnt_opts *opts) 601c9180a57SEric Paris { 602c9180a57SEric Paris int rc = 0, i; 603c9180a57SEric Paris struct superblock_security_struct *sbsec = sb->s_security; 604c9180a57SEric Paris char *context = NULL; 605c9180a57SEric Paris u32 len; 606c9180a57SEric Paris char tmp; 607c9180a57SEric Paris 608e0007529SEric Paris security_init_mnt_opts(opts); 609c9180a57SEric Paris 6100d90a7ecSDavid P. Quigley if (!(sbsec->flags & SE_SBINITIALIZED)) 611c9180a57SEric Paris return -EINVAL; 612c9180a57SEric Paris 613aa8e712cSStephen Smalley if (!selinux_state.initialized) 614c9180a57SEric Paris return -EINVAL; 615c9180a57SEric Paris 616af8e50ccSEric Paris /* make sure we always check enough bits to cover the mask */ 617af8e50ccSEric Paris BUILD_BUG_ON(SE_MNTMASK >= (1 << NUM_SEL_MNT_OPTS)); 618af8e50ccSEric Paris 6190d90a7ecSDavid P. Quigley tmp = sbsec->flags & SE_MNTMASK; 620c9180a57SEric Paris /* count the number of mount options for this sb */ 621af8e50ccSEric Paris for (i = 0; i < NUM_SEL_MNT_OPTS; i++) { 622c9180a57SEric Paris if (tmp & 0x01) 623e0007529SEric Paris opts->num_mnt_opts++; 624c9180a57SEric Paris tmp >>= 1; 625c9180a57SEric Paris } 62611689d47SDavid P. Quigley /* Check if the Label support flag is set */ 6270b4bdb35SEric Paris if (sbsec->flags & SBLABEL_MNT) 62811689d47SDavid P. Quigley opts->num_mnt_opts++; 629c9180a57SEric Paris 630e0007529SEric Paris opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC); 631e0007529SEric Paris if (!opts->mnt_opts) { 632c9180a57SEric Paris rc = -ENOMEM; 633c9180a57SEric Paris goto out_free; 634c9180a57SEric Paris } 635c9180a57SEric Paris 636e0007529SEric Paris opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC); 637e0007529SEric Paris if (!opts->mnt_opts_flags) { 638c9180a57SEric Paris rc = -ENOMEM; 639c9180a57SEric Paris goto out_free; 640c9180a57SEric Paris } 641c9180a57SEric Paris 642c9180a57SEric Paris i = 0; 643c9180a57SEric Paris if (sbsec->flags & FSCONTEXT_MNT) { 644aa8e712cSStephen Smalley rc = security_sid_to_context(&selinux_state, sbsec->sid, 645aa8e712cSStephen Smalley &context, &len); 646c9180a57SEric Paris if (rc) 647c9180a57SEric Paris goto out_free; 648e0007529SEric Paris opts->mnt_opts[i] = context; 649e0007529SEric Paris opts->mnt_opts_flags[i++] = FSCONTEXT_MNT; 650c9180a57SEric Paris } 651c9180a57SEric Paris if (sbsec->flags & CONTEXT_MNT) { 652aa8e712cSStephen Smalley rc = security_sid_to_context(&selinux_state, 653aa8e712cSStephen Smalley sbsec->mntpoint_sid, 654aa8e712cSStephen Smalley &context, &len); 655c9180a57SEric Paris if (rc) 656c9180a57SEric Paris goto out_free; 657e0007529SEric Paris opts->mnt_opts[i] = context; 658e0007529SEric Paris opts->mnt_opts_flags[i++] = CONTEXT_MNT; 659c9180a57SEric Paris } 660c9180a57SEric Paris if (sbsec->flags & DEFCONTEXT_MNT) { 661aa8e712cSStephen Smalley rc = security_sid_to_context(&selinux_state, sbsec->def_sid, 662aa8e712cSStephen Smalley &context, &len); 663c9180a57SEric Paris if (rc) 664c9180a57SEric Paris goto out_free; 665e0007529SEric Paris opts->mnt_opts[i] = context; 666e0007529SEric Paris opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT; 667c9180a57SEric Paris } 668c9180a57SEric Paris if (sbsec->flags & ROOTCONTEXT_MNT) { 66983da53c5SAndreas Gruenbacher struct dentry *root = sbsec->sb->s_root; 67083da53c5SAndreas Gruenbacher struct inode_security_struct *isec = backing_inode_security(root); 671c9180a57SEric Paris 672aa8e712cSStephen Smalley rc = security_sid_to_context(&selinux_state, isec->sid, 673aa8e712cSStephen Smalley &context, &len); 674c9180a57SEric Paris if (rc) 675c9180a57SEric Paris goto out_free; 676e0007529SEric Paris opts->mnt_opts[i] = context; 677e0007529SEric Paris opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT; 678c9180a57SEric Paris } 67912f348b9SEric Paris if (sbsec->flags & SBLABEL_MNT) { 68011689d47SDavid P. Quigley opts->mnt_opts[i] = NULL; 68112f348b9SEric Paris opts->mnt_opts_flags[i++] = SBLABEL_MNT; 68211689d47SDavid P. Quigley } 683c9180a57SEric Paris 684e0007529SEric Paris BUG_ON(i != opts->num_mnt_opts); 685c9180a57SEric Paris 686c9180a57SEric Paris return 0; 687c9180a57SEric Paris 688c9180a57SEric Paris out_free: 689e0007529SEric Paris security_free_mnt_opts(opts); 690c9180a57SEric Paris return rc; 691c9180a57SEric Paris } 692c9180a57SEric Paris 693c9180a57SEric Paris static int bad_option(struct superblock_security_struct *sbsec, char flag, 694c9180a57SEric Paris u32 old_sid, u32 new_sid) 695c9180a57SEric Paris { 6960d90a7ecSDavid P. Quigley char mnt_flags = sbsec->flags & SE_MNTMASK; 6970d90a7ecSDavid P. Quigley 698c9180a57SEric Paris /* check if the old mount command had the same options */ 6990d90a7ecSDavid P. Quigley if (sbsec->flags & SE_SBINITIALIZED) 700c9180a57SEric Paris if (!(sbsec->flags & flag) || 701c9180a57SEric Paris (old_sid != new_sid)) 702c9180a57SEric Paris return 1; 703c9180a57SEric Paris 704c9180a57SEric Paris /* check if we were passed the same options twice, 705c9180a57SEric Paris * aka someone passed context=a,context=b 706c9180a57SEric Paris */ 7070d90a7ecSDavid P. Quigley if (!(sbsec->flags & SE_SBINITIALIZED)) 7080d90a7ecSDavid P. Quigley if (mnt_flags & flag) 709c9180a57SEric Paris return 1; 710c9180a57SEric Paris return 0; 711c9180a57SEric Paris } 712e0007529SEric Paris 713c9180a57SEric Paris /* 714c9180a57SEric Paris * Allow filesystems with binary mount data to explicitly set mount point 715c9180a57SEric Paris * labeling information. 716c9180a57SEric Paris */ 717e0007529SEric Paris static int selinux_set_mnt_opts(struct super_block *sb, 718649f6e77SDavid Quigley struct security_mnt_opts *opts, 719649f6e77SDavid Quigley unsigned long kern_flags, 720649f6e77SDavid Quigley unsigned long *set_kern_flags) 721c9180a57SEric Paris { 722275bb41eSDavid Howells const struct cred *cred = current_cred(); 723c9180a57SEric Paris int rc = 0, i; 724c9180a57SEric Paris struct superblock_security_struct *sbsec = sb->s_security; 72529b1deb2SLinus Torvalds const char *name = sb->s_type->name; 72683da53c5SAndreas Gruenbacher struct dentry *root = sbsec->sb->s_root; 7272c97165bSPaul Moore struct inode_security_struct *root_isec; 728c9180a57SEric Paris u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; 729c9180a57SEric Paris u32 defcontext_sid = 0; 730e0007529SEric Paris char **mount_options = opts->mnt_opts; 731e0007529SEric Paris int *flags = opts->mnt_opts_flags; 732e0007529SEric Paris int num_opts = opts->num_mnt_opts; 733c9180a57SEric Paris 734c9180a57SEric Paris mutex_lock(&sbsec->lock); 735c9180a57SEric Paris 736aa8e712cSStephen Smalley if (!selinux_state.initialized) { 737c9180a57SEric Paris if (!num_opts) { 738c9180a57SEric Paris /* Defer initialization until selinux_complete_init, 739c9180a57SEric Paris after the initial policy is loaded and the security 740c9180a57SEric Paris server is ready to handle calls. */ 741c9180a57SEric Paris goto out; 742c9180a57SEric Paris } 743c9180a57SEric Paris rc = -EINVAL; 744c103a91eSpeter enderborg pr_warn("SELinux: Unable to set superblock options " 745744ba35eSEric Paris "before the security server is initialized\n"); 746c9180a57SEric Paris goto out; 747c9180a57SEric Paris } 748649f6e77SDavid Quigley if (kern_flags && !set_kern_flags) { 749649f6e77SDavid Quigley /* Specifying internal flags without providing a place to 750649f6e77SDavid Quigley * place the results is not allowed */ 751649f6e77SDavid Quigley rc = -EINVAL; 752649f6e77SDavid Quigley goto out; 753649f6e77SDavid Quigley } 754c9180a57SEric Paris 755c9180a57SEric Paris /* 756e0007529SEric Paris * Binary mount data FS will come through this function twice. Once 757e0007529SEric Paris * from an explicit call and once from the generic calls from the vfs. 758e0007529SEric Paris * Since the generic VFS calls will not contain any security mount data 759e0007529SEric Paris * we need to skip the double mount verification. 760e0007529SEric Paris * 761e0007529SEric Paris * This does open a hole in which we will not notice if the first 762e0007529SEric Paris * mount using this sb set explict options and a second mount using 763e0007529SEric Paris * this sb does not set any security options. (The first options 764e0007529SEric Paris * will be used for both mounts) 765e0007529SEric Paris */ 7660d90a7ecSDavid P. Quigley if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) 767e0007529SEric Paris && (num_opts == 0)) 768e0007529SEric Paris goto out; 769e0007529SEric Paris 7702c97165bSPaul Moore root_isec = backing_inode_security_novalidate(root); 7712c97165bSPaul Moore 772e0007529SEric Paris /* 773c9180a57SEric Paris * parse the mount options, check if they are valid sids. 774c9180a57SEric Paris * also check if someone is trying to mount the same sb more 775c9180a57SEric Paris * than once with different security options. 776c9180a57SEric Paris */ 777c9180a57SEric Paris for (i = 0; i < num_opts; i++) { 778c9180a57SEric Paris u32 sid; 77911689d47SDavid P. Quigley 78012f348b9SEric Paris if (flags[i] == SBLABEL_MNT) 78111689d47SDavid P. Quigley continue; 782aa8e712cSStephen Smalley rc = security_context_str_to_sid(&selinux_state, 783aa8e712cSStephen Smalley mount_options[i], &sid, 784aa8e712cSStephen Smalley GFP_KERNEL); 785c9180a57SEric Paris if (rc) { 786c103a91eSpeter enderborg pr_warn("SELinux: security_context_str_to_sid" 78729b1deb2SLinus Torvalds "(%s) failed for (dev %s, type %s) errno=%d\n", 78829b1deb2SLinus Torvalds mount_options[i], sb->s_id, name, rc); 789c9180a57SEric Paris goto out; 790c9180a57SEric Paris } 791c9180a57SEric Paris switch (flags[i]) { 792c9180a57SEric Paris case FSCONTEXT_MNT: 793c9180a57SEric Paris fscontext_sid = sid; 794c9180a57SEric Paris 795c9180a57SEric Paris if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, 796c9180a57SEric Paris fscontext_sid)) 797c9180a57SEric Paris goto out_double_mount; 798c9180a57SEric Paris 799c9180a57SEric Paris sbsec->flags |= FSCONTEXT_MNT; 800c9180a57SEric Paris break; 801c9180a57SEric Paris case CONTEXT_MNT: 802c9180a57SEric Paris context_sid = sid; 803c9180a57SEric Paris 804c9180a57SEric Paris if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, 805c9180a57SEric Paris context_sid)) 806c9180a57SEric Paris goto out_double_mount; 807c9180a57SEric Paris 808c9180a57SEric Paris sbsec->flags |= CONTEXT_MNT; 809c9180a57SEric Paris break; 810c9180a57SEric Paris case ROOTCONTEXT_MNT: 811c9180a57SEric Paris rootcontext_sid = sid; 812c9180a57SEric Paris 813c9180a57SEric Paris if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, 814c9180a57SEric Paris rootcontext_sid)) 815c9180a57SEric Paris goto out_double_mount; 816c9180a57SEric Paris 817c9180a57SEric Paris sbsec->flags |= ROOTCONTEXT_MNT; 818c9180a57SEric Paris 819c9180a57SEric Paris break; 820c9180a57SEric Paris case DEFCONTEXT_MNT: 821c9180a57SEric Paris defcontext_sid = sid; 822c9180a57SEric Paris 823c9180a57SEric Paris if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, 824c9180a57SEric Paris defcontext_sid)) 825c9180a57SEric Paris goto out_double_mount; 826c9180a57SEric Paris 827c9180a57SEric Paris sbsec->flags |= DEFCONTEXT_MNT; 828c9180a57SEric Paris 829c9180a57SEric Paris break; 830c9180a57SEric Paris default: 831c9180a57SEric Paris rc = -EINVAL; 832c9180a57SEric Paris goto out; 833c9180a57SEric Paris } 834c9180a57SEric Paris } 835c9180a57SEric Paris 8360d90a7ecSDavid P. Quigley if (sbsec->flags & SE_SBINITIALIZED) { 837c9180a57SEric Paris /* previously mounted with options, but not on this attempt? */ 8380d90a7ecSDavid P. Quigley if ((sbsec->flags & SE_MNTMASK) && !num_opts) 839c9180a57SEric Paris goto out_double_mount; 840c9180a57SEric Paris rc = 0; 841c9180a57SEric Paris goto out; 842c9180a57SEric Paris } 843c9180a57SEric Paris 844089be43eSJames Morris if (strcmp(sb->s_type->name, "proc") == 0) 845134509d5SStephen Smalley sbsec->flags |= SE_SBPROC | SE_SBGENFS; 846134509d5SStephen Smalley 8478e014720SStephen Smalley if (!strcmp(sb->s_type->name, "debugfs") || 8486a391183SJeff Vander Stoep !strcmp(sb->s_type->name, "tracefs") || 8498e014720SStephen Smalley !strcmp(sb->s_type->name, "sysfs") || 850901ef845SAntonio Murdaca !strcmp(sb->s_type->name, "pstore") || 851901ef845SAntonio Murdaca !strcmp(sb->s_type->name, "cgroup") || 852901ef845SAntonio Murdaca !strcmp(sb->s_type->name, "cgroup2")) 853134509d5SStephen Smalley sbsec->flags |= SE_SBGENFS; 854c9180a57SEric Paris 855eb9ae686SDavid Quigley if (!sbsec->behavior) { 856eb9ae686SDavid Quigley /* 857eb9ae686SDavid Quigley * Determine the labeling behavior to use for this 858eb9ae686SDavid Quigley * filesystem type. 859eb9ae686SDavid Quigley */ 860aa8e712cSStephen Smalley rc = security_fs_use(&selinux_state, sb); 861c9180a57SEric Paris if (rc) { 862c103a91eSpeter enderborg pr_warn("%s: security_fs_use(%s) returned %d\n", 863089be43eSJames Morris __func__, sb->s_type->name, rc); 864c9180a57SEric Paris goto out; 865c9180a57SEric Paris } 866eb9ae686SDavid Quigley } 867aad82892SSeth Forshee 868aad82892SSeth Forshee /* 86901593d32SStephen Smalley * If this is a user namespace mount and the filesystem type is not 87001593d32SStephen Smalley * explicitly whitelisted, then no contexts are allowed on the command 87101593d32SStephen Smalley * line and security labels must be ignored. 872aad82892SSeth Forshee */ 87301593d32SStephen Smalley if (sb->s_user_ns != &init_user_ns && 87401593d32SStephen Smalley strcmp(sb->s_type->name, "tmpfs") && 87501593d32SStephen Smalley strcmp(sb->s_type->name, "ramfs") && 87601593d32SStephen Smalley strcmp(sb->s_type->name, "devpts")) { 877aad82892SSeth Forshee if (context_sid || fscontext_sid || rootcontext_sid || 878aad82892SSeth Forshee defcontext_sid) { 879aad82892SSeth Forshee rc = -EACCES; 880aad82892SSeth Forshee goto out; 881aad82892SSeth Forshee } 882aad82892SSeth Forshee if (sbsec->behavior == SECURITY_FS_USE_XATTR) { 883aad82892SSeth Forshee sbsec->behavior = SECURITY_FS_USE_MNTPOINT; 884aa8e712cSStephen Smalley rc = security_transition_sid(&selinux_state, 885aa8e712cSStephen Smalley current_sid(), 886aa8e712cSStephen Smalley current_sid(), 887aad82892SSeth Forshee SECCLASS_FILE, NULL, 888aad82892SSeth Forshee &sbsec->mntpoint_sid); 889aad82892SSeth Forshee if (rc) 890aad82892SSeth Forshee goto out; 891aad82892SSeth Forshee } 892aad82892SSeth Forshee goto out_set_opts; 893aad82892SSeth Forshee } 894aad82892SSeth Forshee 895c9180a57SEric Paris /* sets the context of the superblock for the fs being mounted. */ 896c9180a57SEric Paris if (fscontext_sid) { 897275bb41eSDavid Howells rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred); 898c9180a57SEric Paris if (rc) 899c9180a57SEric Paris goto out; 900c9180a57SEric Paris 901c9180a57SEric Paris sbsec->sid = fscontext_sid; 902c9180a57SEric Paris } 903c9180a57SEric Paris 904c9180a57SEric Paris /* 905c9180a57SEric Paris * Switch to using mount point labeling behavior. 906c9180a57SEric Paris * sets the label used on all file below the mountpoint, and will set 907c9180a57SEric Paris * the superblock context if not already set. 908c9180a57SEric Paris */ 909eb9ae686SDavid Quigley if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) { 910eb9ae686SDavid Quigley sbsec->behavior = SECURITY_FS_USE_NATIVE; 911eb9ae686SDavid Quigley *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; 912eb9ae686SDavid Quigley } 913eb9ae686SDavid Quigley 914c9180a57SEric Paris if (context_sid) { 915c9180a57SEric Paris if (!fscontext_sid) { 916275bb41eSDavid Howells rc = may_context_mount_sb_relabel(context_sid, sbsec, 917275bb41eSDavid Howells cred); 918c9180a57SEric Paris if (rc) 919c9180a57SEric Paris goto out; 920c9180a57SEric Paris sbsec->sid = context_sid; 921c9180a57SEric Paris } else { 922275bb41eSDavid Howells rc = may_context_mount_inode_relabel(context_sid, sbsec, 923275bb41eSDavid Howells cred); 924c9180a57SEric Paris if (rc) 925c9180a57SEric Paris goto out; 926c9180a57SEric Paris } 927c9180a57SEric Paris if (!rootcontext_sid) 928c9180a57SEric Paris rootcontext_sid = context_sid; 929c9180a57SEric Paris 930c9180a57SEric Paris sbsec->mntpoint_sid = context_sid; 931c9180a57SEric Paris sbsec->behavior = SECURITY_FS_USE_MNTPOINT; 932c9180a57SEric Paris } 933c9180a57SEric Paris 934c9180a57SEric Paris if (rootcontext_sid) { 935275bb41eSDavid Howells rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, 936275bb41eSDavid Howells cred); 937c9180a57SEric Paris if (rc) 938c9180a57SEric Paris goto out; 939c9180a57SEric Paris 940c9180a57SEric Paris root_isec->sid = rootcontext_sid; 9416f3be9f5SAndreas Gruenbacher root_isec->initialized = LABEL_INITIALIZED; 942c9180a57SEric Paris } 943c9180a57SEric Paris 944c9180a57SEric Paris if (defcontext_sid) { 945eb9ae686SDavid Quigley if (sbsec->behavior != SECURITY_FS_USE_XATTR && 946eb9ae686SDavid Quigley sbsec->behavior != SECURITY_FS_USE_NATIVE) { 947c9180a57SEric Paris rc = -EINVAL; 948c103a91eSpeter enderborg pr_warn("SELinux: defcontext option is " 949c9180a57SEric Paris "invalid for this filesystem type\n"); 950c9180a57SEric Paris goto out; 951c9180a57SEric Paris } 952c9180a57SEric Paris 953c9180a57SEric Paris if (defcontext_sid != sbsec->def_sid) { 954c9180a57SEric Paris rc = may_context_mount_inode_relabel(defcontext_sid, 955275bb41eSDavid Howells sbsec, cred); 956c9180a57SEric Paris if (rc) 957c9180a57SEric Paris goto out; 958c9180a57SEric Paris } 959c9180a57SEric Paris 960c9180a57SEric Paris sbsec->def_sid = defcontext_sid; 961c9180a57SEric Paris } 962c9180a57SEric Paris 963aad82892SSeth Forshee out_set_opts: 964c9180a57SEric Paris rc = sb_finish_set_opts(sb); 965c9180a57SEric Paris out: 966bc7e982bSEric Paris mutex_unlock(&sbsec->lock); 9671da177e4SLinus Torvalds return rc; 968c9180a57SEric Paris out_double_mount: 969c9180a57SEric Paris rc = -EINVAL; 970c103a91eSpeter enderborg pr_warn("SELinux: mount invalid. Same superblock, different " 97129b1deb2SLinus Torvalds "security settings for (dev %s, type %s)\n", sb->s_id, name); 972c9180a57SEric Paris goto out; 973c9180a57SEric Paris } 974c9180a57SEric Paris 975094f7b69SJeff Layton static int selinux_cmp_sb_context(const struct super_block *oldsb, 976094f7b69SJeff Layton const struct super_block *newsb) 977094f7b69SJeff Layton { 978094f7b69SJeff Layton struct superblock_security_struct *old = oldsb->s_security; 979094f7b69SJeff Layton struct superblock_security_struct *new = newsb->s_security; 980094f7b69SJeff Layton char oldflags = old->flags & SE_MNTMASK; 981094f7b69SJeff Layton char newflags = new->flags & SE_MNTMASK; 982094f7b69SJeff Layton 983094f7b69SJeff Layton if (oldflags != newflags) 984094f7b69SJeff Layton goto mismatch; 985094f7b69SJeff Layton if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid) 986094f7b69SJeff Layton goto mismatch; 987094f7b69SJeff Layton if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid) 988094f7b69SJeff Layton goto mismatch; 989094f7b69SJeff Layton if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid) 990094f7b69SJeff Layton goto mismatch; 991094f7b69SJeff Layton if (oldflags & ROOTCONTEXT_MNT) { 99283da53c5SAndreas Gruenbacher struct inode_security_struct *oldroot = backing_inode_security(oldsb->s_root); 99383da53c5SAndreas Gruenbacher struct inode_security_struct *newroot = backing_inode_security(newsb->s_root); 994094f7b69SJeff Layton if (oldroot->sid != newroot->sid) 995094f7b69SJeff Layton goto mismatch; 996094f7b69SJeff Layton } 997094f7b69SJeff Layton return 0; 998094f7b69SJeff Layton mismatch: 999c103a91eSpeter enderborg pr_warn("SELinux: mount invalid. Same superblock, " 1000094f7b69SJeff Layton "different security settings for (dev %s, " 1001094f7b69SJeff Layton "type %s)\n", newsb->s_id, newsb->s_type->name); 1002094f7b69SJeff Layton return -EBUSY; 1003094f7b69SJeff Layton } 1004094f7b69SJeff Layton 1005094f7b69SJeff Layton static int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, 10060b4d3452SScott Mayhew struct super_block *newsb, 10070b4d3452SScott Mayhew unsigned long kern_flags, 10080b4d3452SScott Mayhew unsigned long *set_kern_flags) 1009c9180a57SEric Paris { 10100b4d3452SScott Mayhew int rc = 0; 1011c9180a57SEric Paris const struct superblock_security_struct *oldsbsec = oldsb->s_security; 1012c9180a57SEric Paris struct superblock_security_struct *newsbsec = newsb->s_security; 1013c9180a57SEric Paris 1014c9180a57SEric Paris int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT); 1015c9180a57SEric Paris int set_context = (oldsbsec->flags & CONTEXT_MNT); 1016c9180a57SEric Paris int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT); 1017c9180a57SEric Paris 10180f5e6420SEric Paris /* 10190f5e6420SEric Paris * if the parent was able to be mounted it clearly had no special lsm 1020e8c26255SAl Viro * mount options. thus we can safely deal with this superblock later 10210f5e6420SEric Paris */ 1022aa8e712cSStephen Smalley if (!selinux_state.initialized) 1023094f7b69SJeff Layton return 0; 1024c9180a57SEric Paris 10250b4d3452SScott Mayhew /* 10260b4d3452SScott Mayhew * Specifying internal flags without providing a place to 10270b4d3452SScott Mayhew * place the results is not allowed. 10280b4d3452SScott Mayhew */ 10290b4d3452SScott Mayhew if (kern_flags && !set_kern_flags) 10300b4d3452SScott Mayhew return -EINVAL; 10310b4d3452SScott Mayhew 1032c9180a57SEric Paris /* how can we clone if the old one wasn't set up?? */ 10330d90a7ecSDavid P. Quigley BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); 1034c9180a57SEric Paris 1035094f7b69SJeff Layton /* if fs is reusing a sb, make sure that the contexts match */ 10360d90a7ecSDavid P. Quigley if (newsbsec->flags & SE_SBINITIALIZED) 1037094f7b69SJeff Layton return selinux_cmp_sb_context(oldsb, newsb); 10385a552617SEric Paris 1039c9180a57SEric Paris mutex_lock(&newsbsec->lock); 1040c9180a57SEric Paris 1041c9180a57SEric Paris newsbsec->flags = oldsbsec->flags; 1042c9180a57SEric Paris 1043c9180a57SEric Paris newsbsec->sid = oldsbsec->sid; 1044c9180a57SEric Paris newsbsec->def_sid = oldsbsec->def_sid; 1045c9180a57SEric Paris newsbsec->behavior = oldsbsec->behavior; 1046c9180a57SEric Paris 10470b4d3452SScott Mayhew if (newsbsec->behavior == SECURITY_FS_USE_NATIVE && 10480b4d3452SScott Mayhew !(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) { 1049aa8e712cSStephen Smalley rc = security_fs_use(&selinux_state, newsb); 10500b4d3452SScott Mayhew if (rc) 10510b4d3452SScott Mayhew goto out; 10520b4d3452SScott Mayhew } 10530b4d3452SScott Mayhew 10540b4d3452SScott Mayhew if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !set_context) { 10550b4d3452SScott Mayhew newsbsec->behavior = SECURITY_FS_USE_NATIVE; 10560b4d3452SScott Mayhew *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; 10570b4d3452SScott Mayhew } 10580b4d3452SScott Mayhew 1059c9180a57SEric Paris if (set_context) { 1060c9180a57SEric Paris u32 sid = oldsbsec->mntpoint_sid; 1061c9180a57SEric Paris 1062c9180a57SEric Paris if (!set_fscontext) 1063c9180a57SEric Paris newsbsec->sid = sid; 1064c9180a57SEric Paris if (!set_rootcontext) { 106583da53c5SAndreas Gruenbacher struct inode_security_struct *newisec = backing_inode_security(newsb->s_root); 1066c9180a57SEric Paris newisec->sid = sid; 1067c9180a57SEric Paris } 1068c9180a57SEric Paris newsbsec->mntpoint_sid = sid; 1069c9180a57SEric Paris } 1070c9180a57SEric Paris if (set_rootcontext) { 107183da53c5SAndreas Gruenbacher const struct inode_security_struct *oldisec = backing_inode_security(oldsb->s_root); 107283da53c5SAndreas Gruenbacher struct inode_security_struct *newisec = backing_inode_security(newsb->s_root); 1073c9180a57SEric Paris 1074c9180a57SEric Paris newisec->sid = oldisec->sid; 1075c9180a57SEric Paris } 1076c9180a57SEric Paris 1077c9180a57SEric Paris sb_finish_set_opts(newsb); 10780b4d3452SScott Mayhew out: 1079c9180a57SEric Paris mutex_unlock(&newsbsec->lock); 10800b4d3452SScott Mayhew return rc; 1081c9180a57SEric Paris } 1082c9180a57SEric Paris 10832e1479d9SAdrian Bunk static int selinux_parse_opts_str(char *options, 10842e1479d9SAdrian Bunk struct security_mnt_opts *opts) 1085c9180a57SEric Paris { 1086e0007529SEric Paris char *p; 1087c9180a57SEric Paris char *context = NULL, *defcontext = NULL; 1088c9180a57SEric Paris char *fscontext = NULL, *rootcontext = NULL; 1089e0007529SEric Paris int rc, num_mnt_opts = 0; 1090c9180a57SEric Paris 1091e0007529SEric Paris opts->num_mnt_opts = 0; 1092c9180a57SEric Paris 1093c9180a57SEric Paris /* Standard string-based options. */ 1094c9180a57SEric Paris while ((p = strsep(&options, "|")) != NULL) { 1095c9180a57SEric Paris int token; 1096c9180a57SEric Paris substring_t args[MAX_OPT_ARGS]; 1097c9180a57SEric Paris 1098c9180a57SEric Paris if (!*p) 1099c9180a57SEric Paris continue; 1100c9180a57SEric Paris 1101c9180a57SEric Paris token = match_token(p, tokens, args); 1102c9180a57SEric Paris 1103c9180a57SEric Paris switch (token) { 1104c9180a57SEric Paris case Opt_context: 1105c9180a57SEric Paris if (context || defcontext) { 1106c9180a57SEric Paris rc = -EINVAL; 1107c103a91eSpeter enderborg pr_warn(SEL_MOUNT_FAIL_MSG); 1108c9180a57SEric Paris goto out_err; 1109c9180a57SEric Paris } 1110c9180a57SEric Paris context = match_strdup(&args[0]); 1111c9180a57SEric Paris if (!context) { 1112c9180a57SEric Paris rc = -ENOMEM; 1113c9180a57SEric Paris goto out_err; 1114c9180a57SEric Paris } 1115c9180a57SEric Paris break; 1116c9180a57SEric Paris 1117c9180a57SEric Paris case Opt_fscontext: 1118c9180a57SEric Paris if (fscontext) { 1119c9180a57SEric Paris rc = -EINVAL; 1120c103a91eSpeter enderborg pr_warn(SEL_MOUNT_FAIL_MSG); 1121c9180a57SEric Paris goto out_err; 1122c9180a57SEric Paris } 1123c9180a57SEric Paris fscontext = match_strdup(&args[0]); 1124c9180a57SEric Paris if (!fscontext) { 1125c9180a57SEric Paris rc = -ENOMEM; 1126c9180a57SEric Paris goto out_err; 1127c9180a57SEric Paris } 1128c9180a57SEric Paris break; 1129c9180a57SEric Paris 1130c9180a57SEric Paris case Opt_rootcontext: 1131c9180a57SEric Paris if (rootcontext) { 1132c9180a57SEric Paris rc = -EINVAL; 1133c103a91eSpeter enderborg pr_warn(SEL_MOUNT_FAIL_MSG); 1134c9180a57SEric Paris goto out_err; 1135c9180a57SEric Paris } 1136c9180a57SEric Paris rootcontext = match_strdup(&args[0]); 1137c9180a57SEric Paris if (!rootcontext) { 1138c9180a57SEric Paris rc = -ENOMEM; 1139c9180a57SEric Paris goto out_err; 1140c9180a57SEric Paris } 1141c9180a57SEric Paris break; 1142c9180a57SEric Paris 1143c9180a57SEric Paris case Opt_defcontext: 1144c9180a57SEric Paris if (context || defcontext) { 1145c9180a57SEric Paris rc = -EINVAL; 1146c103a91eSpeter enderborg pr_warn(SEL_MOUNT_FAIL_MSG); 1147c9180a57SEric Paris goto out_err; 1148c9180a57SEric Paris } 1149c9180a57SEric Paris defcontext = match_strdup(&args[0]); 1150c9180a57SEric Paris if (!defcontext) { 1151c9180a57SEric Paris rc = -ENOMEM; 1152c9180a57SEric Paris goto out_err; 1153c9180a57SEric Paris } 1154c9180a57SEric Paris break; 115511689d47SDavid P. Quigley case Opt_labelsupport: 115611689d47SDavid P. Quigley break; 1157c9180a57SEric Paris default: 1158c9180a57SEric Paris rc = -EINVAL; 1159c103a91eSpeter enderborg pr_warn("SELinux: unknown mount option\n"); 1160c9180a57SEric Paris goto out_err; 1161c9180a57SEric Paris 1162c9180a57SEric Paris } 1163c9180a57SEric Paris } 1164c9180a57SEric Paris 1165e0007529SEric Paris rc = -ENOMEM; 11668931c3bdSTetsuo Handa opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_KERNEL); 1167e0007529SEric Paris if (!opts->mnt_opts) 1168e0007529SEric Paris goto out_err; 1169e0007529SEric Paris 11708931c3bdSTetsuo Handa opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), 11718931c3bdSTetsuo Handa GFP_KERNEL); 1172023f108dSPaul Moore if (!opts->mnt_opts_flags) 1173e0007529SEric Paris goto out_err; 1174c9180a57SEric Paris 1175e0007529SEric Paris if (fscontext) { 1176e0007529SEric Paris opts->mnt_opts[num_mnt_opts] = fscontext; 1177e0007529SEric Paris opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT; 1178e0007529SEric Paris } 1179e0007529SEric Paris if (context) { 1180e0007529SEric Paris opts->mnt_opts[num_mnt_opts] = context; 1181e0007529SEric Paris opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT; 1182e0007529SEric Paris } 1183e0007529SEric Paris if (rootcontext) { 1184e0007529SEric Paris opts->mnt_opts[num_mnt_opts] = rootcontext; 1185e0007529SEric Paris opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT; 1186e0007529SEric Paris } 1187e0007529SEric Paris if (defcontext) { 1188e0007529SEric Paris opts->mnt_opts[num_mnt_opts] = defcontext; 1189e0007529SEric Paris opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT; 1190e0007529SEric Paris } 1191e0007529SEric Paris 1192e0007529SEric Paris opts->num_mnt_opts = num_mnt_opts; 1193e0007529SEric Paris return 0; 1194e0007529SEric Paris 1195c9180a57SEric Paris out_err: 1196023f108dSPaul Moore security_free_mnt_opts(opts); 1197c9180a57SEric Paris kfree(context); 1198c9180a57SEric Paris kfree(defcontext); 1199c9180a57SEric Paris kfree(fscontext); 1200c9180a57SEric Paris kfree(rootcontext); 1201c9180a57SEric Paris return rc; 12021da177e4SLinus Torvalds } 12031da177e4SLinus Torvalds 12043583a711SAdrian Bunk static void selinux_write_opts(struct seq_file *m, 12053583a711SAdrian Bunk struct security_mnt_opts *opts) 12062069f457SEric Paris { 12072069f457SEric Paris int i; 12082069f457SEric Paris char *prefix; 12092069f457SEric Paris 12102069f457SEric Paris for (i = 0; i < opts->num_mnt_opts; i++) { 121111689d47SDavid P. Quigley char *has_comma; 121211689d47SDavid P. Quigley 121311689d47SDavid P. Quigley if (opts->mnt_opts[i]) 121411689d47SDavid P. Quigley has_comma = strchr(opts->mnt_opts[i], ','); 121511689d47SDavid P. Quigley else 121611689d47SDavid P. Quigley has_comma = NULL; 12172069f457SEric Paris 12182069f457SEric Paris switch (opts->mnt_opts_flags[i]) { 12192069f457SEric Paris case CONTEXT_MNT: 12202069f457SEric Paris prefix = CONTEXT_STR; 12212069f457SEric Paris break; 12222069f457SEric Paris case FSCONTEXT_MNT: 12232069f457SEric Paris prefix = FSCONTEXT_STR; 12242069f457SEric Paris break; 12252069f457SEric Paris case ROOTCONTEXT_MNT: 12262069f457SEric Paris prefix = ROOTCONTEXT_STR; 12272069f457SEric Paris break; 12282069f457SEric Paris case DEFCONTEXT_MNT: 12292069f457SEric Paris prefix = DEFCONTEXT_STR; 12302069f457SEric Paris break; 123112f348b9SEric Paris case SBLABEL_MNT: 123211689d47SDavid P. Quigley seq_putc(m, ','); 123311689d47SDavid P. Quigley seq_puts(m, LABELSUPP_STR); 123411689d47SDavid P. Quigley continue; 12352069f457SEric Paris default: 12362069f457SEric Paris BUG(); 1237a35c6c83SEric Paris return; 12382069f457SEric Paris }; 12392069f457SEric Paris /* we need a comma before each option */ 12402069f457SEric Paris seq_putc(m, ','); 12412069f457SEric Paris seq_puts(m, prefix); 12422069f457SEric Paris if (has_comma) 12432069f457SEric Paris seq_putc(m, '\"'); 1244a068acf2SKees Cook seq_escape(m, opts->mnt_opts[i], "\"\n\\"); 12452069f457SEric Paris if (has_comma) 12462069f457SEric Paris seq_putc(m, '\"'); 12472069f457SEric Paris } 12482069f457SEric Paris } 12492069f457SEric Paris 12502069f457SEric Paris static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) 12512069f457SEric Paris { 12522069f457SEric Paris struct security_mnt_opts opts; 12532069f457SEric Paris int rc; 12542069f457SEric Paris 12552069f457SEric Paris rc = selinux_get_mnt_opts(sb, &opts); 1256383795c2SEric Paris if (rc) { 1257383795c2SEric Paris /* before policy load we may get EINVAL, don't show anything */ 1258383795c2SEric Paris if (rc == -EINVAL) 1259383795c2SEric Paris rc = 0; 12602069f457SEric Paris return rc; 1261383795c2SEric Paris } 12622069f457SEric Paris 12632069f457SEric Paris selinux_write_opts(m, &opts); 12642069f457SEric Paris 12652069f457SEric Paris security_free_mnt_opts(&opts); 12662069f457SEric Paris 12672069f457SEric Paris return rc; 12682069f457SEric Paris } 12692069f457SEric Paris 12701da177e4SLinus Torvalds static inline u16 inode_mode_to_security_class(umode_t mode) 12711da177e4SLinus Torvalds { 12721da177e4SLinus Torvalds switch (mode & S_IFMT) { 12731da177e4SLinus Torvalds case S_IFSOCK: 12741da177e4SLinus Torvalds return SECCLASS_SOCK_FILE; 12751da177e4SLinus Torvalds case S_IFLNK: 12761da177e4SLinus Torvalds return SECCLASS_LNK_FILE; 12771da177e4SLinus Torvalds case S_IFREG: 12781da177e4SLinus Torvalds return SECCLASS_FILE; 12791da177e4SLinus Torvalds case S_IFBLK: 12801da177e4SLinus Torvalds return SECCLASS_BLK_FILE; 12811da177e4SLinus Torvalds case S_IFDIR: 12821da177e4SLinus Torvalds return SECCLASS_DIR; 12831da177e4SLinus Torvalds case S_IFCHR: 12841da177e4SLinus Torvalds return SECCLASS_CHR_FILE; 12851da177e4SLinus Torvalds case S_IFIFO: 12861da177e4SLinus Torvalds return SECCLASS_FIFO_FILE; 12871da177e4SLinus Torvalds 12881da177e4SLinus Torvalds } 12891da177e4SLinus Torvalds 12901da177e4SLinus Torvalds return SECCLASS_FILE; 12911da177e4SLinus Torvalds } 12921da177e4SLinus Torvalds 129313402580SJames Morris static inline int default_protocol_stream(int protocol) 129413402580SJames Morris { 129513402580SJames Morris return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP); 129613402580SJames Morris } 129713402580SJames Morris 129813402580SJames Morris static inline int default_protocol_dgram(int protocol) 129913402580SJames Morris { 130013402580SJames Morris return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP); 130113402580SJames Morris } 130213402580SJames Morris 13031da177e4SLinus Torvalds static inline u16 socket_type_to_security_class(int family, int type, int protocol) 13041da177e4SLinus Torvalds { 1305aa8e712cSStephen Smalley int extsockclass = selinux_policycap_extsockclass(); 1306da69a530SStephen Smalley 13071da177e4SLinus Torvalds switch (family) { 13081da177e4SLinus Torvalds case PF_UNIX: 13091da177e4SLinus Torvalds switch (type) { 13101da177e4SLinus Torvalds case SOCK_STREAM: 13111da177e4SLinus Torvalds case SOCK_SEQPACKET: 13121da177e4SLinus Torvalds return SECCLASS_UNIX_STREAM_SOCKET; 13131da177e4SLinus Torvalds case SOCK_DGRAM: 13142a764b52SLuis Ressel case SOCK_RAW: 13151da177e4SLinus Torvalds return SECCLASS_UNIX_DGRAM_SOCKET; 13161da177e4SLinus Torvalds } 13171da177e4SLinus Torvalds break; 13181da177e4SLinus Torvalds case PF_INET: 13191da177e4SLinus Torvalds case PF_INET6: 13201da177e4SLinus Torvalds switch (type) { 13211da177e4SLinus Torvalds case SOCK_STREAM: 1322da69a530SStephen Smalley case SOCK_SEQPACKET: 132313402580SJames Morris if (default_protocol_stream(protocol)) 13241da177e4SLinus Torvalds return SECCLASS_TCP_SOCKET; 1325da69a530SStephen Smalley else if (extsockclass && protocol == IPPROTO_SCTP) 1326da69a530SStephen Smalley return SECCLASS_SCTP_SOCKET; 132713402580SJames Morris else 132813402580SJames Morris return SECCLASS_RAWIP_SOCKET; 13291da177e4SLinus Torvalds case SOCK_DGRAM: 133013402580SJames Morris if (default_protocol_dgram(protocol)) 13311da177e4SLinus Torvalds return SECCLASS_UDP_SOCKET; 1332ef37979aSStephen Smalley else if (extsockclass && (protocol == IPPROTO_ICMP || 1333ef37979aSStephen Smalley protocol == IPPROTO_ICMPV6)) 1334da69a530SStephen Smalley return SECCLASS_ICMP_SOCKET; 133513402580SJames Morris else 133613402580SJames Morris return SECCLASS_RAWIP_SOCKET; 13372ee92d46SJames Morris case SOCK_DCCP: 13382ee92d46SJames Morris return SECCLASS_DCCP_SOCKET; 133913402580SJames Morris default: 13401da177e4SLinus Torvalds return SECCLASS_RAWIP_SOCKET; 13411da177e4SLinus Torvalds } 13421da177e4SLinus Torvalds break; 13431da177e4SLinus Torvalds case PF_NETLINK: 13441da177e4SLinus Torvalds switch (protocol) { 13451da177e4SLinus Torvalds case NETLINK_ROUTE: 13461da177e4SLinus Torvalds return SECCLASS_NETLINK_ROUTE_SOCKET; 13477f1fb60cSPavel Emelyanov case NETLINK_SOCK_DIAG: 13481da177e4SLinus Torvalds return SECCLASS_NETLINK_TCPDIAG_SOCKET; 13491da177e4SLinus Torvalds case NETLINK_NFLOG: 13501da177e4SLinus Torvalds return SECCLASS_NETLINK_NFLOG_SOCKET; 13511da177e4SLinus Torvalds case NETLINK_XFRM: 13521da177e4SLinus Torvalds return SECCLASS_NETLINK_XFRM_SOCKET; 13531da177e4SLinus Torvalds case NETLINK_SELINUX: 13541da177e4SLinus Torvalds return SECCLASS_NETLINK_SELINUX_SOCKET; 13556c6d2e9bSStephen Smalley case NETLINK_ISCSI: 13566c6d2e9bSStephen Smalley return SECCLASS_NETLINK_ISCSI_SOCKET; 13571da177e4SLinus Torvalds case NETLINK_AUDIT: 13581da177e4SLinus Torvalds return SECCLASS_NETLINK_AUDIT_SOCKET; 13596c6d2e9bSStephen Smalley case NETLINK_FIB_LOOKUP: 13606c6d2e9bSStephen Smalley return SECCLASS_NETLINK_FIB_LOOKUP_SOCKET; 13616c6d2e9bSStephen Smalley case NETLINK_CONNECTOR: 13626c6d2e9bSStephen Smalley return SECCLASS_NETLINK_CONNECTOR_SOCKET; 13636c6d2e9bSStephen Smalley case NETLINK_NETFILTER: 13646c6d2e9bSStephen Smalley return SECCLASS_NETLINK_NETFILTER_SOCKET; 13651da177e4SLinus Torvalds case NETLINK_DNRTMSG: 13661da177e4SLinus Torvalds return SECCLASS_NETLINK_DNRT_SOCKET; 13670c9b7942SJames Morris case NETLINK_KOBJECT_UEVENT: 13680c9b7942SJames Morris return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET; 13696c6d2e9bSStephen Smalley case NETLINK_GENERIC: 13706c6d2e9bSStephen Smalley return SECCLASS_NETLINK_GENERIC_SOCKET; 13716c6d2e9bSStephen Smalley case NETLINK_SCSITRANSPORT: 13726c6d2e9bSStephen Smalley return SECCLASS_NETLINK_SCSITRANSPORT_SOCKET; 13736c6d2e9bSStephen Smalley case NETLINK_RDMA: 13746c6d2e9bSStephen Smalley return SECCLASS_NETLINK_RDMA_SOCKET; 13756c6d2e9bSStephen Smalley case NETLINK_CRYPTO: 13766c6d2e9bSStephen Smalley return SECCLASS_NETLINK_CRYPTO_SOCKET; 13771da177e4SLinus Torvalds default: 13781da177e4SLinus Torvalds return SECCLASS_NETLINK_SOCKET; 13791da177e4SLinus Torvalds } 13801da177e4SLinus Torvalds case PF_PACKET: 13811da177e4SLinus Torvalds return SECCLASS_PACKET_SOCKET; 13821da177e4SLinus Torvalds case PF_KEY: 13831da177e4SLinus Torvalds return SECCLASS_KEY_SOCKET; 13843e3ff15eSChristopher J. PeBenito case PF_APPLETALK: 13853e3ff15eSChristopher J. PeBenito return SECCLASS_APPLETALK_SOCKET; 13861da177e4SLinus Torvalds } 13871da177e4SLinus Torvalds 1388da69a530SStephen Smalley if (extsockclass) { 1389da69a530SStephen Smalley switch (family) { 1390da69a530SStephen Smalley case PF_AX25: 1391da69a530SStephen Smalley return SECCLASS_AX25_SOCKET; 1392da69a530SStephen Smalley case PF_IPX: 1393da69a530SStephen Smalley return SECCLASS_IPX_SOCKET; 1394da69a530SStephen Smalley case PF_NETROM: 1395da69a530SStephen Smalley return SECCLASS_NETROM_SOCKET; 1396da69a530SStephen Smalley case PF_ATMPVC: 1397da69a530SStephen Smalley return SECCLASS_ATMPVC_SOCKET; 1398da69a530SStephen Smalley case PF_X25: 1399da69a530SStephen Smalley return SECCLASS_X25_SOCKET; 1400da69a530SStephen Smalley case PF_ROSE: 1401da69a530SStephen Smalley return SECCLASS_ROSE_SOCKET; 1402da69a530SStephen Smalley case PF_DECnet: 1403da69a530SStephen Smalley return SECCLASS_DECNET_SOCKET; 1404da69a530SStephen Smalley case PF_ATMSVC: 1405da69a530SStephen Smalley return SECCLASS_ATMSVC_SOCKET; 1406da69a530SStephen Smalley case PF_RDS: 1407da69a530SStephen Smalley return SECCLASS_RDS_SOCKET; 1408da69a530SStephen Smalley case PF_IRDA: 1409da69a530SStephen Smalley return SECCLASS_IRDA_SOCKET; 1410da69a530SStephen Smalley case PF_PPPOX: 1411da69a530SStephen Smalley return SECCLASS_PPPOX_SOCKET; 1412da69a530SStephen Smalley case PF_LLC: 1413da69a530SStephen Smalley return SECCLASS_LLC_SOCKET; 1414da69a530SStephen Smalley case PF_CAN: 1415da69a530SStephen Smalley return SECCLASS_CAN_SOCKET; 1416da69a530SStephen Smalley case PF_TIPC: 1417da69a530SStephen Smalley return SECCLASS_TIPC_SOCKET; 1418da69a530SStephen Smalley case PF_BLUETOOTH: 1419da69a530SStephen Smalley return SECCLASS_BLUETOOTH_SOCKET; 1420da69a530SStephen Smalley case PF_IUCV: 1421da69a530SStephen Smalley return SECCLASS_IUCV_SOCKET; 1422da69a530SStephen Smalley case PF_RXRPC: 1423da69a530SStephen Smalley return SECCLASS_RXRPC_SOCKET; 1424da69a530SStephen Smalley case PF_ISDN: 1425da69a530SStephen Smalley return SECCLASS_ISDN_SOCKET; 1426da69a530SStephen Smalley case PF_PHONET: 1427da69a530SStephen Smalley return SECCLASS_PHONET_SOCKET; 1428da69a530SStephen Smalley case PF_IEEE802154: 1429da69a530SStephen Smalley return SECCLASS_IEEE802154_SOCKET; 1430da69a530SStephen Smalley case PF_CAIF: 1431da69a530SStephen Smalley return SECCLASS_CAIF_SOCKET; 1432da69a530SStephen Smalley case PF_ALG: 1433da69a530SStephen Smalley return SECCLASS_ALG_SOCKET; 1434da69a530SStephen Smalley case PF_NFC: 1435da69a530SStephen Smalley return SECCLASS_NFC_SOCKET; 1436da69a530SStephen Smalley case PF_VSOCK: 1437da69a530SStephen Smalley return SECCLASS_VSOCK_SOCKET; 1438da69a530SStephen Smalley case PF_KCM: 1439da69a530SStephen Smalley return SECCLASS_KCM_SOCKET; 1440da69a530SStephen Smalley case PF_QIPCRTR: 1441da69a530SStephen Smalley return SECCLASS_QIPCRTR_SOCKET; 14423051bf36SLinus Torvalds case PF_SMC: 14433051bf36SLinus Torvalds return SECCLASS_SMC_SOCKET; 144468e8b849SBjörn Töpel case PF_XDP: 144568e8b849SBjörn Töpel return SECCLASS_XDP_SOCKET; 144668e8b849SBjörn Töpel #if PF_MAX > 45 1447da69a530SStephen Smalley #error New address family defined, please update this function. 1448da69a530SStephen Smalley #endif 1449da69a530SStephen Smalley } 1450da69a530SStephen Smalley } 1451da69a530SStephen Smalley 14521da177e4SLinus Torvalds return SECCLASS_SOCKET; 14531da177e4SLinus Torvalds } 14541da177e4SLinus Torvalds 1455134509d5SStephen Smalley static int selinux_genfs_get_sid(struct dentry *dentry, 14561da177e4SLinus Torvalds u16 tclass, 1457134509d5SStephen Smalley u16 flags, 14581da177e4SLinus Torvalds u32 *sid) 14591da177e4SLinus Torvalds { 14608e6c9693SLucian Adrian Grijincu int rc; 1461fc64005cSAl Viro struct super_block *sb = dentry->d_sb; 14628e6c9693SLucian Adrian Grijincu char *buffer, *path; 14631da177e4SLinus Torvalds 14641da177e4SLinus Torvalds buffer = (char *)__get_free_page(GFP_KERNEL); 14651da177e4SLinus Torvalds if (!buffer) 14661da177e4SLinus Torvalds return -ENOMEM; 14671da177e4SLinus Torvalds 14688e6c9693SLucian Adrian Grijincu path = dentry_path_raw(dentry, buffer, PAGE_SIZE); 14698e6c9693SLucian Adrian Grijincu if (IS_ERR(path)) 14708e6c9693SLucian Adrian Grijincu rc = PTR_ERR(path); 14718e6c9693SLucian Adrian Grijincu else { 1472134509d5SStephen Smalley if (flags & SE_SBPROC) { 14738e6c9693SLucian Adrian Grijincu /* each process gets a /proc/PID/ entry. Strip off the 14748e6c9693SLucian Adrian Grijincu * PID part to get a valid selinux labeling. 14758e6c9693SLucian Adrian Grijincu * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ 14768e6c9693SLucian Adrian Grijincu while (path[1] >= '0' && path[1] <= '9') { 14778e6c9693SLucian Adrian Grijincu path[1] = '/'; 14788e6c9693SLucian Adrian Grijincu path++; 14791da177e4SLinus Torvalds } 1480134509d5SStephen Smalley } 1481aa8e712cSStephen Smalley rc = security_genfs_sid(&selinux_state, sb->s_type->name, 1482aa8e712cSStephen Smalley path, tclass, sid); 14837bb185edSStephen Smalley if (rc == -ENOENT) { 14847bb185edSStephen Smalley /* No match in policy, mark as unlabeled. */ 14857bb185edSStephen Smalley *sid = SECINITSID_UNLABELED; 14867bb185edSStephen Smalley rc = 0; 14877bb185edSStephen Smalley } 14888e6c9693SLucian Adrian Grijincu } 14891da177e4SLinus Torvalds free_page((unsigned long)buffer); 14901da177e4SLinus Torvalds return rc; 14911da177e4SLinus Torvalds } 14921da177e4SLinus Torvalds 14931da177e4SLinus Torvalds /* The inode's security attributes must be initialized before first use. */ 14941da177e4SLinus Torvalds static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) 14951da177e4SLinus Torvalds { 14961da177e4SLinus Torvalds struct superblock_security_struct *sbsec = NULL; 14971da177e4SLinus Torvalds struct inode_security_struct *isec = inode->i_security; 14989287aed2SAndreas Gruenbacher u32 task_sid, sid = 0; 14999287aed2SAndreas Gruenbacher u16 sclass; 15001da177e4SLinus Torvalds struct dentry *dentry; 15011da177e4SLinus Torvalds #define INITCONTEXTLEN 255 15021da177e4SLinus Torvalds char *context = NULL; 15031da177e4SLinus Torvalds unsigned len = 0; 15041da177e4SLinus Torvalds int rc = 0; 15051da177e4SLinus Torvalds 15066f3be9f5SAndreas Gruenbacher if (isec->initialized == LABEL_INITIALIZED) 150713457d07SAndreas Gruenbacher return 0; 15081da177e4SLinus Torvalds 15099287aed2SAndreas Gruenbacher spin_lock(&isec->lock); 15106f3be9f5SAndreas Gruenbacher if (isec->initialized == LABEL_INITIALIZED) 151123970741SEric Paris goto out_unlock; 15121da177e4SLinus Torvalds 151313457d07SAndreas Gruenbacher if (isec->sclass == SECCLASS_FILE) 151413457d07SAndreas Gruenbacher isec->sclass = inode_mode_to_security_class(inode->i_mode); 151513457d07SAndreas Gruenbacher 15161da177e4SLinus Torvalds sbsec = inode->i_sb->s_security; 15170d90a7ecSDavid P. Quigley if (!(sbsec->flags & SE_SBINITIALIZED)) { 15181da177e4SLinus Torvalds /* Defer initialization until selinux_complete_init, 15191da177e4SLinus Torvalds after the initial policy is loaded and the security 15201da177e4SLinus Torvalds server is ready to handle calls. */ 15211da177e4SLinus Torvalds spin_lock(&sbsec->isec_lock); 15221da177e4SLinus Torvalds if (list_empty(&isec->list)) 15231da177e4SLinus Torvalds list_add(&isec->list, &sbsec->isec_head); 15241da177e4SLinus Torvalds spin_unlock(&sbsec->isec_lock); 152523970741SEric Paris goto out_unlock; 15261da177e4SLinus Torvalds } 15271da177e4SLinus Torvalds 15289287aed2SAndreas Gruenbacher sclass = isec->sclass; 15299287aed2SAndreas Gruenbacher task_sid = isec->task_sid; 15309287aed2SAndreas Gruenbacher sid = isec->sid; 15319287aed2SAndreas Gruenbacher isec->initialized = LABEL_PENDING; 15329287aed2SAndreas Gruenbacher spin_unlock(&isec->lock); 15339287aed2SAndreas Gruenbacher 15341da177e4SLinus Torvalds switch (sbsec->behavior) { 1535eb9ae686SDavid Quigley case SECURITY_FS_USE_NATIVE: 1536eb9ae686SDavid Quigley break; 15371da177e4SLinus Torvalds case SECURITY_FS_USE_XATTR: 15385d6c3191SAndreas Gruenbacher if (!(inode->i_opflags & IOP_XATTR)) { 15399287aed2SAndreas Gruenbacher sid = sbsec->def_sid; 15401da177e4SLinus Torvalds break; 15411da177e4SLinus Torvalds } 15421da177e4SLinus Torvalds /* Need a dentry, since the xattr API requires one. 15431da177e4SLinus Torvalds Life would be simpler if we could just pass the inode. */ 15441da177e4SLinus Torvalds if (opt_dentry) { 15451da177e4SLinus Torvalds /* Called from d_instantiate or d_splice_alias. */ 15461da177e4SLinus Torvalds dentry = dget(opt_dentry); 15471da177e4SLinus Torvalds } else { 1548b127125dSAl Viro /* 1549b127125dSAl Viro * Called from selinux_complete_init, try to find a dentry. 1550b127125dSAl Viro * Some filesystems really want a connected one, so try 1551b127125dSAl Viro * that first. We could split SECURITY_FS_USE_XATTR in 1552b127125dSAl Viro * two, depending upon that... 1553b127125dSAl Viro */ 15541da177e4SLinus Torvalds dentry = d_find_alias(inode); 1555b127125dSAl Viro if (!dentry) 1556b127125dSAl Viro dentry = d_find_any_alias(inode); 15571da177e4SLinus Torvalds } 15581da177e4SLinus Torvalds if (!dentry) { 1559df7f54c0SEric Paris /* 1560df7f54c0SEric Paris * this is can be hit on boot when a file is accessed 1561df7f54c0SEric Paris * before the policy is loaded. When we load policy we 1562df7f54c0SEric Paris * may find inodes that have no dentry on the 1563df7f54c0SEric Paris * sbsec->isec_head list. No reason to complain as these 1564df7f54c0SEric Paris * will get fixed up the next time we go through 1565df7f54c0SEric Paris * inode_doinit with a dentry, before these inodes could 1566df7f54c0SEric Paris * be used again by userspace. 1567df7f54c0SEric Paris */ 15689287aed2SAndreas Gruenbacher goto out; 15691da177e4SLinus Torvalds } 15701da177e4SLinus Torvalds 15711da177e4SLinus Torvalds len = INITCONTEXTLEN; 15724cb912f1SEric Paris context = kmalloc(len+1, GFP_NOFS); 15731da177e4SLinus Torvalds if (!context) { 15741da177e4SLinus Torvalds rc = -ENOMEM; 15751da177e4SLinus Torvalds dput(dentry); 15769287aed2SAndreas Gruenbacher goto out; 15771da177e4SLinus Torvalds } 15784cb912f1SEric Paris context[len] = '\0'; 15795d6c3191SAndreas Gruenbacher rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len); 15801da177e4SLinus Torvalds if (rc == -ERANGE) { 1581314dabb8SJames Morris kfree(context); 1582314dabb8SJames Morris 15831da177e4SLinus Torvalds /* Need a larger buffer. Query for the right size. */ 15845d6c3191SAndreas Gruenbacher rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0); 15851da177e4SLinus Torvalds if (rc < 0) { 15861da177e4SLinus Torvalds dput(dentry); 15879287aed2SAndreas Gruenbacher goto out; 15881da177e4SLinus Torvalds } 15891da177e4SLinus Torvalds len = rc; 15904cb912f1SEric Paris context = kmalloc(len+1, GFP_NOFS); 15911da177e4SLinus Torvalds if (!context) { 15921da177e4SLinus Torvalds rc = -ENOMEM; 15931da177e4SLinus Torvalds dput(dentry); 15949287aed2SAndreas Gruenbacher goto out; 15951da177e4SLinus Torvalds } 15964cb912f1SEric Paris context[len] = '\0'; 15975d6c3191SAndreas Gruenbacher rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len); 15981da177e4SLinus Torvalds } 15991da177e4SLinus Torvalds dput(dentry); 16001da177e4SLinus Torvalds if (rc < 0) { 16011da177e4SLinus Torvalds if (rc != -ENODATA) { 1602c103a91eSpeter enderborg pr_warn("SELinux: %s: getxattr returned " 1603dd6f953aSHarvey Harrison "%d for dev=%s ino=%ld\n", __func__, 16041da177e4SLinus Torvalds -rc, inode->i_sb->s_id, inode->i_ino); 16051da177e4SLinus Torvalds kfree(context); 16069287aed2SAndreas Gruenbacher goto out; 16071da177e4SLinus Torvalds } 16081da177e4SLinus Torvalds /* Map ENODATA to the default file SID */ 16091da177e4SLinus Torvalds sid = sbsec->def_sid; 16101da177e4SLinus Torvalds rc = 0; 16111da177e4SLinus Torvalds } else { 1612aa8e712cSStephen Smalley rc = security_context_to_sid_default(&selinux_state, 1613aa8e712cSStephen Smalley context, rc, &sid, 1614869ab514SStephen Smalley sbsec->def_sid, 1615869ab514SStephen Smalley GFP_NOFS); 16161da177e4SLinus Torvalds if (rc) { 16174ba0a8adSEric Paris char *dev = inode->i_sb->s_id; 16184ba0a8adSEric Paris unsigned long ino = inode->i_ino; 16194ba0a8adSEric Paris 16204ba0a8adSEric Paris if (rc == -EINVAL) { 16214ba0a8adSEric Paris if (printk_ratelimit()) 1622c103a91eSpeter enderborg pr_notice("SELinux: inode=%lu on dev=%s was found to have an invalid " 16234ba0a8adSEric Paris "context=%s. This indicates you may need to relabel the inode or the " 16244ba0a8adSEric Paris "filesystem in question.\n", ino, dev, context); 16254ba0a8adSEric Paris } else { 1626c103a91eSpeter enderborg pr_warn("SELinux: %s: context_to_sid(%s) " 16271da177e4SLinus Torvalds "returned %d for dev=%s ino=%ld\n", 16284ba0a8adSEric Paris __func__, context, -rc, dev, ino); 16294ba0a8adSEric Paris } 16301da177e4SLinus Torvalds kfree(context); 16311da177e4SLinus Torvalds /* Leave with the unlabeled SID */ 16321da177e4SLinus Torvalds rc = 0; 16331da177e4SLinus Torvalds break; 16341da177e4SLinus Torvalds } 16351da177e4SLinus Torvalds } 16361da177e4SLinus Torvalds kfree(context); 16371da177e4SLinus Torvalds break; 16381da177e4SLinus Torvalds case SECURITY_FS_USE_TASK: 16399287aed2SAndreas Gruenbacher sid = task_sid; 16401da177e4SLinus Torvalds break; 16411da177e4SLinus Torvalds case SECURITY_FS_USE_TRANS: 16421da177e4SLinus Torvalds /* Default to the fs SID. */ 16439287aed2SAndreas Gruenbacher sid = sbsec->sid; 16441da177e4SLinus Torvalds 16451da177e4SLinus Torvalds /* Try to obtain a transition SID. */ 1646aa8e712cSStephen Smalley rc = security_transition_sid(&selinux_state, task_sid, sid, 1647aa8e712cSStephen Smalley sclass, NULL, &sid); 16481da177e4SLinus Torvalds if (rc) 16499287aed2SAndreas Gruenbacher goto out; 16501da177e4SLinus Torvalds break; 1651c312feb2SEric Paris case SECURITY_FS_USE_MNTPOINT: 16529287aed2SAndreas Gruenbacher sid = sbsec->mntpoint_sid; 1653c312feb2SEric Paris break; 16541da177e4SLinus Torvalds default: 1655c312feb2SEric Paris /* Default to the fs superblock SID. */ 16569287aed2SAndreas Gruenbacher sid = sbsec->sid; 16571da177e4SLinus Torvalds 1658134509d5SStephen Smalley if ((sbsec->flags & SE_SBGENFS) && !S_ISLNK(inode->i_mode)) { 1659f64410ecSPaul Moore /* We must have a dentry to determine the label on 1660f64410ecSPaul Moore * procfs inodes */ 1661b127125dSAl Viro if (opt_dentry) { 1662f64410ecSPaul Moore /* Called from d_instantiate or 1663f64410ecSPaul Moore * d_splice_alias. */ 1664f64410ecSPaul Moore dentry = dget(opt_dentry); 1665b127125dSAl Viro } else { 1666f64410ecSPaul Moore /* Called from selinux_complete_init, try to 1667b127125dSAl Viro * find a dentry. Some filesystems really want 1668b127125dSAl Viro * a connected one, so try that first. 1669b127125dSAl Viro */ 1670f64410ecSPaul Moore dentry = d_find_alias(inode); 1671b127125dSAl Viro if (!dentry) 1672b127125dSAl Viro dentry = d_find_any_alias(inode); 1673b127125dSAl Viro } 1674f64410ecSPaul Moore /* 1675f64410ecSPaul Moore * This can be hit on boot when a file is accessed 1676f64410ecSPaul Moore * before the policy is loaded. When we load policy we 1677f64410ecSPaul Moore * may find inodes that have no dentry on the 1678f64410ecSPaul Moore * sbsec->isec_head list. No reason to complain as 1679f64410ecSPaul Moore * these will get fixed up the next time we go through 1680f64410ecSPaul Moore * inode_doinit() with a dentry, before these inodes 1681f64410ecSPaul Moore * could be used again by userspace. 1682f64410ecSPaul Moore */ 1683f64410ecSPaul Moore if (!dentry) 16849287aed2SAndreas Gruenbacher goto out; 16859287aed2SAndreas Gruenbacher rc = selinux_genfs_get_sid(dentry, sclass, 1686134509d5SStephen Smalley sbsec->flags, &sid); 1687f64410ecSPaul Moore dput(dentry); 16881da177e4SLinus Torvalds if (rc) 16899287aed2SAndreas Gruenbacher goto out; 16901da177e4SLinus Torvalds } 16911da177e4SLinus Torvalds break; 16921da177e4SLinus Torvalds } 16931da177e4SLinus Torvalds 16949287aed2SAndreas Gruenbacher out: 16959287aed2SAndreas Gruenbacher spin_lock(&isec->lock); 16969287aed2SAndreas Gruenbacher if (isec->initialized == LABEL_PENDING) { 16979287aed2SAndreas Gruenbacher if (!sid || rc) { 16989287aed2SAndreas Gruenbacher isec->initialized = LABEL_INVALID; 16999287aed2SAndreas Gruenbacher goto out_unlock; 17009287aed2SAndreas Gruenbacher } 17019287aed2SAndreas Gruenbacher 17026f3be9f5SAndreas Gruenbacher isec->initialized = LABEL_INITIALIZED; 17039287aed2SAndreas Gruenbacher isec->sid = sid; 17049287aed2SAndreas Gruenbacher } 17051da177e4SLinus Torvalds 170623970741SEric Paris out_unlock: 17079287aed2SAndreas Gruenbacher spin_unlock(&isec->lock); 17081da177e4SLinus Torvalds return rc; 17091da177e4SLinus Torvalds } 17101da177e4SLinus Torvalds 17111da177e4SLinus Torvalds /* Convert a Linux signal to an access vector. */ 17121da177e4SLinus Torvalds static inline u32 signal_to_av(int sig) 17131da177e4SLinus Torvalds { 17141da177e4SLinus Torvalds u32 perm = 0; 17151da177e4SLinus Torvalds 17161da177e4SLinus Torvalds switch (sig) { 17171da177e4SLinus Torvalds case SIGCHLD: 17181da177e4SLinus Torvalds /* Commonly granted from child to parent. */ 17191da177e4SLinus Torvalds perm = PROCESS__SIGCHLD; 17201da177e4SLinus Torvalds break; 17211da177e4SLinus Torvalds case SIGKILL: 17221da177e4SLinus Torvalds /* Cannot be caught or ignored */ 17231da177e4SLinus Torvalds perm = PROCESS__SIGKILL; 17241da177e4SLinus Torvalds break; 17251da177e4SLinus Torvalds case SIGSTOP: 17261da177e4SLinus Torvalds /* Cannot be caught or ignored */ 17271da177e4SLinus Torvalds perm = PROCESS__SIGSTOP; 17281da177e4SLinus Torvalds break; 17291da177e4SLinus Torvalds default: 17301da177e4SLinus Torvalds /* All other signals. */ 17311da177e4SLinus Torvalds perm = PROCESS__SIGNAL; 17321da177e4SLinus Torvalds break; 17331da177e4SLinus Torvalds } 17341da177e4SLinus Torvalds 17351da177e4SLinus Torvalds return perm; 17361da177e4SLinus Torvalds } 17371da177e4SLinus Torvalds 1738b68e418cSStephen Smalley #if CAP_LAST_CAP > 63 1739b68e418cSStephen Smalley #error Fix SELinux to handle capabilities > 63. 1740b68e418cSStephen Smalley #endif 1741b68e418cSStephen Smalley 17421da177e4SLinus Torvalds /* Check whether a task is allowed to use a capability. */ 17436a9de491SEric Paris static int cred_has_capability(const struct cred *cred, 17448e4ff6f2SStephen Smalley int cap, int audit, bool initns) 17451da177e4SLinus Torvalds { 17462bf49690SThomas Liu struct common_audit_data ad; 174706112163SEric Paris struct av_decision avd; 1748b68e418cSStephen Smalley u16 sclass; 17493699c53cSDavid Howells u32 sid = cred_sid(cred); 1750b68e418cSStephen Smalley u32 av = CAP_TO_MASK(cap); 175106112163SEric Paris int rc; 17521da177e4SLinus Torvalds 175350c205f5SEric Paris ad.type = LSM_AUDIT_DATA_CAP; 17541da177e4SLinus Torvalds ad.u.cap = cap; 17551da177e4SLinus Torvalds 1756b68e418cSStephen Smalley switch (CAP_TO_INDEX(cap)) { 1757b68e418cSStephen Smalley case 0: 17588e4ff6f2SStephen Smalley sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS; 1759b68e418cSStephen Smalley break; 1760b68e418cSStephen Smalley case 1: 17618e4ff6f2SStephen Smalley sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS; 1762b68e418cSStephen Smalley break; 1763b68e418cSStephen Smalley default: 1764c103a91eSpeter enderborg pr_err("SELinux: out of range capability %d\n", cap); 1765b68e418cSStephen Smalley BUG(); 1766a35c6c83SEric Paris return -EINVAL; 1767b68e418cSStephen Smalley } 176806112163SEric Paris 17696b6bc620SStephen Smalley rc = avc_has_perm_noaudit(&selinux_state, 17706b6bc620SStephen Smalley sid, sid, sclass, av, 0, &avd); 17719ade0cf4SEric Paris if (audit == SECURITY_CAP_AUDIT) { 17726b6bc620SStephen Smalley int rc2 = avc_audit(&selinux_state, 17736b6bc620SStephen Smalley sid, sid, sclass, av, &avd, rc, &ad, 0); 17749ade0cf4SEric Paris if (rc2) 17759ade0cf4SEric Paris return rc2; 17769ade0cf4SEric Paris } 177706112163SEric Paris return rc; 17781da177e4SLinus Torvalds } 17791da177e4SLinus Torvalds 17801da177e4SLinus Torvalds /* Check whether a task has a particular permission to an inode. 17811da177e4SLinus Torvalds The 'adp' parameter is optional and allows other audit 17821da177e4SLinus Torvalds data to be passed (e.g. the dentry). */ 178388e67f3bSDavid Howells static int inode_has_perm(const struct cred *cred, 17841da177e4SLinus Torvalds struct inode *inode, 17851da177e4SLinus Torvalds u32 perms, 178619e49834SLinus Torvalds struct common_audit_data *adp) 17871da177e4SLinus Torvalds { 17881da177e4SLinus Torvalds struct inode_security_struct *isec; 1789275bb41eSDavid Howells u32 sid; 17901da177e4SLinus Torvalds 1791e0e81739SDavid Howells validate_creds(cred); 1792e0e81739SDavid Howells 1793bbaca6c2SStephen Smalley if (unlikely(IS_PRIVATE(inode))) 1794bbaca6c2SStephen Smalley return 0; 1795bbaca6c2SStephen Smalley 179688e67f3bSDavid Howells sid = cred_sid(cred); 17971da177e4SLinus Torvalds isec = inode->i_security; 17981da177e4SLinus Torvalds 17996b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 18006b6bc620SStephen Smalley sid, isec->sid, isec->sclass, perms, adp); 18011da177e4SLinus Torvalds } 18021da177e4SLinus Torvalds 18031da177e4SLinus Torvalds /* Same as inode_has_perm, but pass explicit audit data containing 18041da177e4SLinus Torvalds the dentry to help the auditing code to more easily generate the 18051da177e4SLinus Torvalds pathname if needed. */ 180688e67f3bSDavid Howells static inline int dentry_has_perm(const struct cred *cred, 18071da177e4SLinus Torvalds struct dentry *dentry, 18081da177e4SLinus Torvalds u32 av) 18091da177e4SLinus Torvalds { 1810c6f493d6SDavid Howells struct inode *inode = d_backing_inode(dentry); 18112bf49690SThomas Liu struct common_audit_data ad; 181288e67f3bSDavid Howells 181350c205f5SEric Paris ad.type = LSM_AUDIT_DATA_DENTRY; 18142875fa00SEric Paris ad.u.dentry = dentry; 18155d226df4SAndreas Gruenbacher __inode_security_revalidate(inode, dentry, true); 181619e49834SLinus Torvalds return inode_has_perm(cred, inode, av, &ad); 18172875fa00SEric Paris } 18182875fa00SEric Paris 18192875fa00SEric Paris /* Same as inode_has_perm, but pass explicit audit data containing 18202875fa00SEric Paris the path to help the auditing code to more easily generate the 18212875fa00SEric Paris pathname if needed. */ 18222875fa00SEric Paris static inline int path_has_perm(const struct cred *cred, 18233f7036a0SAl Viro const struct path *path, 18242875fa00SEric Paris u32 av) 18252875fa00SEric Paris { 1826c6f493d6SDavid Howells struct inode *inode = d_backing_inode(path->dentry); 18272875fa00SEric Paris struct common_audit_data ad; 18282875fa00SEric Paris 182950c205f5SEric Paris ad.type = LSM_AUDIT_DATA_PATH; 18302875fa00SEric Paris ad.u.path = *path; 18315d226df4SAndreas Gruenbacher __inode_security_revalidate(inode, path->dentry, true); 183219e49834SLinus Torvalds return inode_has_perm(cred, inode, av, &ad); 18331da177e4SLinus Torvalds } 18341da177e4SLinus Torvalds 183513f8e981SDavid Howells /* Same as path_has_perm, but uses the inode from the file struct. */ 183613f8e981SDavid Howells static inline int file_path_has_perm(const struct cred *cred, 183713f8e981SDavid Howells struct file *file, 183813f8e981SDavid Howells u32 av) 183913f8e981SDavid Howells { 184013f8e981SDavid Howells struct common_audit_data ad; 184113f8e981SDavid Howells 184243af5de7SVivek Goyal ad.type = LSM_AUDIT_DATA_FILE; 184343af5de7SVivek Goyal ad.u.file = file; 184419e49834SLinus Torvalds return inode_has_perm(cred, file_inode(file), av, &ad); 184513f8e981SDavid Howells } 184613f8e981SDavid Howells 1847f66e448cSChenbo Feng #ifdef CONFIG_BPF_SYSCALL 1848f66e448cSChenbo Feng static int bpf_fd_pass(struct file *file, u32 sid); 1849f66e448cSChenbo Feng #endif 1850f66e448cSChenbo Feng 18511da177e4SLinus Torvalds /* Check whether a task can use an open file descriptor to 18521da177e4SLinus Torvalds access an inode in a given way. Check access to the 18531da177e4SLinus Torvalds descriptor itself, and then use dentry_has_perm to 18541da177e4SLinus Torvalds check a particular permission to the file. 18551da177e4SLinus Torvalds Access to the descriptor is implicitly granted if it 18561da177e4SLinus Torvalds has the same SID as the process. If av is zero, then 18571da177e4SLinus Torvalds access to the file is not checked, e.g. for cases 18581da177e4SLinus Torvalds where only the descriptor is affected like seek. */ 185988e67f3bSDavid Howells static int file_has_perm(const struct cred *cred, 18601da177e4SLinus Torvalds struct file *file, 18611da177e4SLinus Torvalds u32 av) 18621da177e4SLinus Torvalds { 18631da177e4SLinus Torvalds struct file_security_struct *fsec = file->f_security; 1864496ad9aaSAl Viro struct inode *inode = file_inode(file); 18652bf49690SThomas Liu struct common_audit_data ad; 186688e67f3bSDavid Howells u32 sid = cred_sid(cred); 18671da177e4SLinus Torvalds int rc; 18681da177e4SLinus Torvalds 186943af5de7SVivek Goyal ad.type = LSM_AUDIT_DATA_FILE; 187043af5de7SVivek Goyal ad.u.file = file; 18711da177e4SLinus Torvalds 1872275bb41eSDavid Howells if (sid != fsec->sid) { 18736b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 18746b6bc620SStephen Smalley sid, fsec->sid, 18751da177e4SLinus Torvalds SECCLASS_FD, 18761da177e4SLinus Torvalds FD__USE, 18771da177e4SLinus Torvalds &ad); 18781da177e4SLinus Torvalds if (rc) 187988e67f3bSDavid Howells goto out; 18801da177e4SLinus Torvalds } 18811da177e4SLinus Torvalds 1882f66e448cSChenbo Feng #ifdef CONFIG_BPF_SYSCALL 1883f66e448cSChenbo Feng rc = bpf_fd_pass(file, cred_sid(cred)); 1884f66e448cSChenbo Feng if (rc) 1885f66e448cSChenbo Feng return rc; 1886f66e448cSChenbo Feng #endif 1887f66e448cSChenbo Feng 18881da177e4SLinus Torvalds /* av is zero if only checking access to the descriptor. */ 188988e67f3bSDavid Howells rc = 0; 18901da177e4SLinus Torvalds if (av) 189119e49834SLinus Torvalds rc = inode_has_perm(cred, inode, av, &ad); 18921da177e4SLinus Torvalds 189388e67f3bSDavid Howells out: 189488e67f3bSDavid Howells return rc; 18951da177e4SLinus Torvalds } 18961da177e4SLinus Torvalds 1897c3c188b2SDavid Howells /* 1898c3c188b2SDavid Howells * Determine the label for an inode that might be unioned. 1899c3c188b2SDavid Howells */ 1900c957f6dfSVivek Goyal static int 1901c957f6dfSVivek Goyal selinux_determine_inode_label(const struct task_security_struct *tsec, 1902c957f6dfSVivek Goyal struct inode *dir, 1903c957f6dfSVivek Goyal const struct qstr *name, u16 tclass, 1904c3c188b2SDavid Howells u32 *_new_isid) 1905c3c188b2SDavid Howells { 1906c3c188b2SDavid Howells const struct superblock_security_struct *sbsec = dir->i_sb->s_security; 1907c3c188b2SDavid Howells 1908c3c188b2SDavid Howells if ((sbsec->flags & SE_SBINITIALIZED) && 1909c3c188b2SDavid Howells (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) { 1910c3c188b2SDavid Howells *_new_isid = sbsec->mntpoint_sid; 1911c3c188b2SDavid Howells } else if ((sbsec->flags & SBLABEL_MNT) && 1912c3c188b2SDavid Howells tsec->create_sid) { 1913c3c188b2SDavid Howells *_new_isid = tsec->create_sid; 1914c3c188b2SDavid Howells } else { 191520cdef8dSPaul Moore const struct inode_security_struct *dsec = inode_security(dir); 1916aa8e712cSStephen Smalley return security_transition_sid(&selinux_state, tsec->sid, 1917aa8e712cSStephen Smalley dsec->sid, tclass, 1918c3c188b2SDavid Howells name, _new_isid); 1919c3c188b2SDavid Howells } 1920c3c188b2SDavid Howells 1921c3c188b2SDavid Howells return 0; 1922c3c188b2SDavid Howells } 1923c3c188b2SDavid Howells 19241da177e4SLinus Torvalds /* Check whether a task can create a file. */ 19251da177e4SLinus Torvalds static int may_create(struct inode *dir, 19261da177e4SLinus Torvalds struct dentry *dentry, 19271da177e4SLinus Torvalds u16 tclass) 19281da177e4SLinus Torvalds { 19295fb49870SPaul Moore const struct task_security_struct *tsec = current_security(); 19301da177e4SLinus Torvalds struct inode_security_struct *dsec; 19311da177e4SLinus Torvalds struct superblock_security_struct *sbsec; 1932275bb41eSDavid Howells u32 sid, newsid; 19332bf49690SThomas Liu struct common_audit_data ad; 19341da177e4SLinus Torvalds int rc; 19351da177e4SLinus Torvalds 193683da53c5SAndreas Gruenbacher dsec = inode_security(dir); 19371da177e4SLinus Torvalds sbsec = dir->i_sb->s_security; 19381da177e4SLinus Torvalds 1939275bb41eSDavid Howells sid = tsec->sid; 1940275bb41eSDavid Howells 194150c205f5SEric Paris ad.type = LSM_AUDIT_DATA_DENTRY; 1942a269434dSEric Paris ad.u.dentry = dentry; 19431da177e4SLinus Torvalds 19446b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 19456b6bc620SStephen Smalley sid, dsec->sid, SECCLASS_DIR, 19461da177e4SLinus Torvalds DIR__ADD_NAME | DIR__SEARCH, 19471da177e4SLinus Torvalds &ad); 19481da177e4SLinus Torvalds if (rc) 19491da177e4SLinus Torvalds return rc; 19501da177e4SLinus Torvalds 1951c957f6dfSVivek Goyal rc = selinux_determine_inode_label(current_security(), dir, 1952c957f6dfSVivek Goyal &dentry->d_name, tclass, &newsid); 19531da177e4SLinus Torvalds if (rc) 19541da177e4SLinus Torvalds return rc; 19551da177e4SLinus Torvalds 19566b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 19576b6bc620SStephen Smalley sid, newsid, tclass, FILE__CREATE, &ad); 19581da177e4SLinus Torvalds if (rc) 19591da177e4SLinus Torvalds return rc; 19601da177e4SLinus Torvalds 19616b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 19626b6bc620SStephen Smalley newsid, sbsec->sid, 19631da177e4SLinus Torvalds SECCLASS_FILESYSTEM, 19641da177e4SLinus Torvalds FILESYSTEM__ASSOCIATE, &ad); 19651da177e4SLinus Torvalds } 19661da177e4SLinus Torvalds 19671da177e4SLinus Torvalds #define MAY_LINK 0 19681da177e4SLinus Torvalds #define MAY_UNLINK 1 19691da177e4SLinus Torvalds #define MAY_RMDIR 2 19701da177e4SLinus Torvalds 19711da177e4SLinus Torvalds /* Check whether a task can link, unlink, or rmdir a file/directory. */ 19721da177e4SLinus Torvalds static int may_link(struct inode *dir, 19731da177e4SLinus Torvalds struct dentry *dentry, 19741da177e4SLinus Torvalds int kind) 19751da177e4SLinus Torvalds 19761da177e4SLinus Torvalds { 19771da177e4SLinus Torvalds struct inode_security_struct *dsec, *isec; 19782bf49690SThomas Liu struct common_audit_data ad; 1979275bb41eSDavid Howells u32 sid = current_sid(); 19801da177e4SLinus Torvalds u32 av; 19811da177e4SLinus Torvalds int rc; 19821da177e4SLinus Torvalds 198383da53c5SAndreas Gruenbacher dsec = inode_security(dir); 198483da53c5SAndreas Gruenbacher isec = backing_inode_security(dentry); 19851da177e4SLinus Torvalds 198650c205f5SEric Paris ad.type = LSM_AUDIT_DATA_DENTRY; 1987a269434dSEric Paris ad.u.dentry = dentry; 19881da177e4SLinus Torvalds 19891da177e4SLinus Torvalds av = DIR__SEARCH; 19901da177e4SLinus Torvalds av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); 19916b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 19926b6bc620SStephen Smalley sid, dsec->sid, SECCLASS_DIR, av, &ad); 19931da177e4SLinus Torvalds if (rc) 19941da177e4SLinus Torvalds return rc; 19951da177e4SLinus Torvalds 19961da177e4SLinus Torvalds switch (kind) { 19971da177e4SLinus Torvalds case MAY_LINK: 19981da177e4SLinus Torvalds av = FILE__LINK; 19991da177e4SLinus Torvalds break; 20001da177e4SLinus Torvalds case MAY_UNLINK: 20011da177e4SLinus Torvalds av = FILE__UNLINK; 20021da177e4SLinus Torvalds break; 20031da177e4SLinus Torvalds case MAY_RMDIR: 20041da177e4SLinus Torvalds av = DIR__RMDIR; 20051da177e4SLinus Torvalds break; 20061da177e4SLinus Torvalds default: 2007c103a91eSpeter enderborg pr_warn("SELinux: %s: unrecognized kind %d\n", 2008744ba35eSEric Paris __func__, kind); 20091da177e4SLinus Torvalds return 0; 20101da177e4SLinus Torvalds } 20111da177e4SLinus Torvalds 20126b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 20136b6bc620SStephen Smalley sid, isec->sid, isec->sclass, av, &ad); 20141da177e4SLinus Torvalds return rc; 20151da177e4SLinus Torvalds } 20161da177e4SLinus Torvalds 20171da177e4SLinus Torvalds static inline int may_rename(struct inode *old_dir, 20181da177e4SLinus Torvalds struct dentry *old_dentry, 20191da177e4SLinus Torvalds struct inode *new_dir, 20201da177e4SLinus Torvalds struct dentry *new_dentry) 20211da177e4SLinus Torvalds { 20221da177e4SLinus Torvalds struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; 20232bf49690SThomas Liu struct common_audit_data ad; 2024275bb41eSDavid Howells u32 sid = current_sid(); 20251da177e4SLinus Torvalds u32 av; 20261da177e4SLinus Torvalds int old_is_dir, new_is_dir; 20271da177e4SLinus Torvalds int rc; 20281da177e4SLinus Torvalds 202983da53c5SAndreas Gruenbacher old_dsec = inode_security(old_dir); 203083da53c5SAndreas Gruenbacher old_isec = backing_inode_security(old_dentry); 2031e36cb0b8SDavid Howells old_is_dir = d_is_dir(old_dentry); 203283da53c5SAndreas Gruenbacher new_dsec = inode_security(new_dir); 20331da177e4SLinus Torvalds 203450c205f5SEric Paris ad.type = LSM_AUDIT_DATA_DENTRY; 20351da177e4SLinus Torvalds 2036a269434dSEric Paris ad.u.dentry = old_dentry; 20376b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 20386b6bc620SStephen Smalley sid, old_dsec->sid, SECCLASS_DIR, 20391da177e4SLinus Torvalds DIR__REMOVE_NAME | DIR__SEARCH, &ad); 20401da177e4SLinus Torvalds if (rc) 20411da177e4SLinus Torvalds return rc; 20426b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 20436b6bc620SStephen Smalley sid, old_isec->sid, 20441da177e4SLinus Torvalds old_isec->sclass, FILE__RENAME, &ad); 20451da177e4SLinus Torvalds if (rc) 20461da177e4SLinus Torvalds return rc; 20471da177e4SLinus Torvalds if (old_is_dir && new_dir != old_dir) { 20486b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 20496b6bc620SStephen Smalley sid, old_isec->sid, 20501da177e4SLinus Torvalds old_isec->sclass, DIR__REPARENT, &ad); 20511da177e4SLinus Torvalds if (rc) 20521da177e4SLinus Torvalds return rc; 20531da177e4SLinus Torvalds } 20541da177e4SLinus Torvalds 2055a269434dSEric Paris ad.u.dentry = new_dentry; 20561da177e4SLinus Torvalds av = DIR__ADD_NAME | DIR__SEARCH; 20572c616d4dSDavid Howells if (d_is_positive(new_dentry)) 20581da177e4SLinus Torvalds av |= DIR__REMOVE_NAME; 20596b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 20606b6bc620SStephen Smalley sid, new_dsec->sid, SECCLASS_DIR, av, &ad); 20611da177e4SLinus Torvalds if (rc) 20621da177e4SLinus Torvalds return rc; 20632c616d4dSDavid Howells if (d_is_positive(new_dentry)) { 206483da53c5SAndreas Gruenbacher new_isec = backing_inode_security(new_dentry); 2065e36cb0b8SDavid Howells new_is_dir = d_is_dir(new_dentry); 20666b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 20676b6bc620SStephen Smalley sid, new_isec->sid, 20681da177e4SLinus Torvalds new_isec->sclass, 20691da177e4SLinus Torvalds (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); 20701da177e4SLinus Torvalds if (rc) 20711da177e4SLinus Torvalds return rc; 20721da177e4SLinus Torvalds } 20731da177e4SLinus Torvalds 20741da177e4SLinus Torvalds return 0; 20751da177e4SLinus Torvalds } 20761da177e4SLinus Torvalds 20771da177e4SLinus Torvalds /* Check whether a task can perform a filesystem operation. */ 207888e67f3bSDavid Howells static int superblock_has_perm(const struct cred *cred, 20791da177e4SLinus Torvalds struct super_block *sb, 20801da177e4SLinus Torvalds u32 perms, 20812bf49690SThomas Liu struct common_audit_data *ad) 20821da177e4SLinus Torvalds { 20831da177e4SLinus Torvalds struct superblock_security_struct *sbsec; 208488e67f3bSDavid Howells u32 sid = cred_sid(cred); 20851da177e4SLinus Torvalds 20861da177e4SLinus Torvalds sbsec = sb->s_security; 20876b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 20886b6bc620SStephen Smalley sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad); 20891da177e4SLinus Torvalds } 20901da177e4SLinus Torvalds 20911da177e4SLinus Torvalds /* Convert a Linux mode and permission mask to an access vector. */ 20921da177e4SLinus Torvalds static inline u32 file_mask_to_av(int mode, int mask) 20931da177e4SLinus Torvalds { 20941da177e4SLinus Torvalds u32 av = 0; 20951da177e4SLinus Torvalds 2096dba19c60SAl Viro if (!S_ISDIR(mode)) { 20971da177e4SLinus Torvalds if (mask & MAY_EXEC) 20981da177e4SLinus Torvalds av |= FILE__EXECUTE; 20991da177e4SLinus Torvalds if (mask & MAY_READ) 21001da177e4SLinus Torvalds av |= FILE__READ; 21011da177e4SLinus Torvalds 21021da177e4SLinus Torvalds if (mask & MAY_APPEND) 21031da177e4SLinus Torvalds av |= FILE__APPEND; 21041da177e4SLinus Torvalds else if (mask & MAY_WRITE) 21051da177e4SLinus Torvalds av |= FILE__WRITE; 21061da177e4SLinus Torvalds 21071da177e4SLinus Torvalds } else { 21081da177e4SLinus Torvalds if (mask & MAY_EXEC) 21091da177e4SLinus Torvalds av |= DIR__SEARCH; 21101da177e4SLinus Torvalds if (mask & MAY_WRITE) 21111da177e4SLinus Torvalds av |= DIR__WRITE; 21121da177e4SLinus Torvalds if (mask & MAY_READ) 21131da177e4SLinus Torvalds av |= DIR__READ; 21141da177e4SLinus Torvalds } 21151da177e4SLinus Torvalds 21161da177e4SLinus Torvalds return av; 21171da177e4SLinus Torvalds } 21181da177e4SLinus Torvalds 21191da177e4SLinus Torvalds /* Convert a Linux file to an access vector. */ 21201da177e4SLinus Torvalds static inline u32 file_to_av(struct file *file) 21211da177e4SLinus Torvalds { 21221da177e4SLinus Torvalds u32 av = 0; 21231da177e4SLinus Torvalds 21241da177e4SLinus Torvalds if (file->f_mode & FMODE_READ) 21251da177e4SLinus Torvalds av |= FILE__READ; 21261da177e4SLinus Torvalds if (file->f_mode & FMODE_WRITE) { 21271da177e4SLinus Torvalds if (file->f_flags & O_APPEND) 21281da177e4SLinus Torvalds av |= FILE__APPEND; 21291da177e4SLinus Torvalds else 21301da177e4SLinus Torvalds av |= FILE__WRITE; 21311da177e4SLinus Torvalds } 21320794c66dSStephen Smalley if (!av) { 21330794c66dSStephen Smalley /* 21340794c66dSStephen Smalley * Special file opened with flags 3 for ioctl-only use. 21350794c66dSStephen Smalley */ 21360794c66dSStephen Smalley av = FILE__IOCTL; 21370794c66dSStephen Smalley } 21381da177e4SLinus Torvalds 21391da177e4SLinus Torvalds return av; 21401da177e4SLinus Torvalds } 21411da177e4SLinus Torvalds 21428b6a5a37SEric Paris /* 21438b6a5a37SEric Paris * Convert a file to an access vector and include the correct open 21448b6a5a37SEric Paris * open permission. 21458b6a5a37SEric Paris */ 21468b6a5a37SEric Paris static inline u32 open_file_to_av(struct file *file) 21478b6a5a37SEric Paris { 21488b6a5a37SEric Paris u32 av = file_to_av(file); 2149ccb54478SStephen Smalley struct inode *inode = file_inode(file); 21508b6a5a37SEric Paris 2151aa8e712cSStephen Smalley if (selinux_policycap_openperm() && 2152aa8e712cSStephen Smalley inode->i_sb->s_magic != SOCKFS_MAGIC) 21538b6a5a37SEric Paris av |= FILE__OPEN; 215449b7b8deSEric Paris 21558b6a5a37SEric Paris return av; 21568b6a5a37SEric Paris } 21578b6a5a37SEric Paris 21581da177e4SLinus Torvalds /* Hook functions begin here. */ 21591da177e4SLinus Torvalds 216079af7307SStephen Smalley static int selinux_binder_set_context_mgr(struct task_struct *mgr) 216179af7307SStephen Smalley { 216279af7307SStephen Smalley u32 mysid = current_sid(); 216379af7307SStephen Smalley u32 mgrsid = task_sid(mgr); 216479af7307SStephen Smalley 21656b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 21666b6bc620SStephen Smalley mysid, mgrsid, SECCLASS_BINDER, 216779af7307SStephen Smalley BINDER__SET_CONTEXT_MGR, NULL); 216879af7307SStephen Smalley } 216979af7307SStephen Smalley 217079af7307SStephen Smalley static int selinux_binder_transaction(struct task_struct *from, 217179af7307SStephen Smalley struct task_struct *to) 217279af7307SStephen Smalley { 217379af7307SStephen Smalley u32 mysid = current_sid(); 217479af7307SStephen Smalley u32 fromsid = task_sid(from); 217579af7307SStephen Smalley u32 tosid = task_sid(to); 217679af7307SStephen Smalley int rc; 217779af7307SStephen Smalley 217879af7307SStephen Smalley if (mysid != fromsid) { 21796b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 21806b6bc620SStephen Smalley mysid, fromsid, SECCLASS_BINDER, 218179af7307SStephen Smalley BINDER__IMPERSONATE, NULL); 218279af7307SStephen Smalley if (rc) 218379af7307SStephen Smalley return rc; 218479af7307SStephen Smalley } 218579af7307SStephen Smalley 21866b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 21876b6bc620SStephen Smalley fromsid, tosid, SECCLASS_BINDER, BINDER__CALL, 218879af7307SStephen Smalley NULL); 218979af7307SStephen Smalley } 219079af7307SStephen Smalley 219179af7307SStephen Smalley static int selinux_binder_transfer_binder(struct task_struct *from, 219279af7307SStephen Smalley struct task_struct *to) 219379af7307SStephen Smalley { 219479af7307SStephen Smalley u32 fromsid = task_sid(from); 219579af7307SStephen Smalley u32 tosid = task_sid(to); 219679af7307SStephen Smalley 21976b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 21986b6bc620SStephen Smalley fromsid, tosid, SECCLASS_BINDER, BINDER__TRANSFER, 219979af7307SStephen Smalley NULL); 220079af7307SStephen Smalley } 220179af7307SStephen Smalley 220279af7307SStephen Smalley static int selinux_binder_transfer_file(struct task_struct *from, 220379af7307SStephen Smalley struct task_struct *to, 220479af7307SStephen Smalley struct file *file) 220579af7307SStephen Smalley { 220679af7307SStephen Smalley u32 sid = task_sid(to); 220779af7307SStephen Smalley struct file_security_struct *fsec = file->f_security; 220883da53c5SAndreas Gruenbacher struct dentry *dentry = file->f_path.dentry; 220920cdef8dSPaul Moore struct inode_security_struct *isec; 221079af7307SStephen Smalley struct common_audit_data ad; 221179af7307SStephen Smalley int rc; 221279af7307SStephen Smalley 221379af7307SStephen Smalley ad.type = LSM_AUDIT_DATA_PATH; 221479af7307SStephen Smalley ad.u.path = file->f_path; 221579af7307SStephen Smalley 221679af7307SStephen Smalley if (sid != fsec->sid) { 22176b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 22186b6bc620SStephen Smalley sid, fsec->sid, 221979af7307SStephen Smalley SECCLASS_FD, 222079af7307SStephen Smalley FD__USE, 222179af7307SStephen Smalley &ad); 222279af7307SStephen Smalley if (rc) 222379af7307SStephen Smalley return rc; 222479af7307SStephen Smalley } 222579af7307SStephen Smalley 2226f66e448cSChenbo Feng #ifdef CONFIG_BPF_SYSCALL 2227f66e448cSChenbo Feng rc = bpf_fd_pass(file, sid); 2228f66e448cSChenbo Feng if (rc) 2229f66e448cSChenbo Feng return rc; 2230f66e448cSChenbo Feng #endif 2231f66e448cSChenbo Feng 223283da53c5SAndreas Gruenbacher if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) 223379af7307SStephen Smalley return 0; 223479af7307SStephen Smalley 223520cdef8dSPaul Moore isec = backing_inode_security(dentry); 22366b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 22376b6bc620SStephen Smalley sid, isec->sid, isec->sclass, file_to_av(file), 223879af7307SStephen Smalley &ad); 223979af7307SStephen Smalley } 224079af7307SStephen Smalley 22419e48858fSIngo Molnar static int selinux_ptrace_access_check(struct task_struct *child, 2242006ebb40SStephen Smalley unsigned int mode) 22431da177e4SLinus Torvalds { 2244275bb41eSDavid Howells u32 sid = current_sid(); 2245275bb41eSDavid Howells u32 csid = task_sid(child); 2246006ebb40SStephen Smalley 2247be0554c9SStephen Smalley if (mode & PTRACE_MODE_READ) 22486b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 22496b6bc620SStephen Smalley sid, csid, SECCLASS_FILE, FILE__READ, NULL); 2250be0554c9SStephen Smalley 22516b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 22526b6bc620SStephen Smalley sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); 22535cd9c58fSDavid Howells } 22545cd9c58fSDavid Howells 22555cd9c58fSDavid Howells static int selinux_ptrace_traceme(struct task_struct *parent) 22565cd9c58fSDavid Howells { 22576b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 22586b6bc620SStephen Smalley task_sid(parent), current_sid(), SECCLASS_PROCESS, 2259be0554c9SStephen Smalley PROCESS__PTRACE, NULL); 22601da177e4SLinus Torvalds } 22611da177e4SLinus Torvalds 22621da177e4SLinus Torvalds static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, 22631da177e4SLinus Torvalds kernel_cap_t *inheritable, kernel_cap_t *permitted) 22641da177e4SLinus Torvalds { 22656b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 22666b6bc620SStephen Smalley current_sid(), task_sid(target), SECCLASS_PROCESS, 2267be0554c9SStephen Smalley PROCESS__GETCAP, NULL); 22681da177e4SLinus Torvalds } 22691da177e4SLinus Torvalds 2270d84f4f99SDavid Howells static int selinux_capset(struct cred *new, const struct cred *old, 2271d84f4f99SDavid Howells const kernel_cap_t *effective, 227215a2460eSDavid Howells const kernel_cap_t *inheritable, 227315a2460eSDavid Howells const kernel_cap_t *permitted) 22741da177e4SLinus Torvalds { 22756b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 22766b6bc620SStephen Smalley cred_sid(old), cred_sid(new), SECCLASS_PROCESS, 2277be0554c9SStephen Smalley PROCESS__SETCAP, NULL); 22781da177e4SLinus Torvalds } 22791da177e4SLinus Torvalds 22805626d3e8SJames Morris /* 22815626d3e8SJames Morris * (This comment used to live with the selinux_task_setuid hook, 22825626d3e8SJames Morris * which was removed). 22835626d3e8SJames Morris * 22845626d3e8SJames Morris * Since setuid only affects the current process, and since the SELinux 22855626d3e8SJames Morris * controls are not based on the Linux identity attributes, SELinux does not 22865626d3e8SJames Morris * need to control this operation. However, SELinux does control the use of 22875626d3e8SJames Morris * the CAP_SETUID and CAP_SETGID capabilities using the capable hook. 22885626d3e8SJames Morris */ 22895626d3e8SJames Morris 22906a9de491SEric Paris static int selinux_capable(const struct cred *cred, struct user_namespace *ns, 22916a9de491SEric Paris int cap, int audit) 22921da177e4SLinus Torvalds { 22938e4ff6f2SStephen Smalley return cred_has_capability(cred, cap, audit, ns == &init_user_ns); 22941da177e4SLinus Torvalds } 22951da177e4SLinus Torvalds 22961da177e4SLinus Torvalds static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) 22971da177e4SLinus Torvalds { 229888e67f3bSDavid Howells const struct cred *cred = current_cred(); 22991da177e4SLinus Torvalds int rc = 0; 23001da177e4SLinus Torvalds 23011da177e4SLinus Torvalds if (!sb) 23021da177e4SLinus Torvalds return 0; 23031da177e4SLinus Torvalds 23041da177e4SLinus Torvalds switch (cmds) { 23051da177e4SLinus Torvalds case Q_SYNC: 23061da177e4SLinus Torvalds case Q_QUOTAON: 23071da177e4SLinus Torvalds case Q_QUOTAOFF: 23081da177e4SLinus Torvalds case Q_SETINFO: 23091da177e4SLinus Torvalds case Q_SETQUOTA: 231088e67f3bSDavid Howells rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL); 23111da177e4SLinus Torvalds break; 23121da177e4SLinus Torvalds case Q_GETFMT: 23131da177e4SLinus Torvalds case Q_GETINFO: 23141da177e4SLinus Torvalds case Q_GETQUOTA: 231588e67f3bSDavid Howells rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL); 23161da177e4SLinus Torvalds break; 23171da177e4SLinus Torvalds default: 23181da177e4SLinus Torvalds rc = 0; /* let the kernel handle invalid cmds */ 23191da177e4SLinus Torvalds break; 23201da177e4SLinus Torvalds } 23211da177e4SLinus Torvalds return rc; 23221da177e4SLinus Torvalds } 23231da177e4SLinus Torvalds 23241da177e4SLinus Torvalds static int selinux_quota_on(struct dentry *dentry) 23251da177e4SLinus Torvalds { 232688e67f3bSDavid Howells const struct cred *cred = current_cred(); 232788e67f3bSDavid Howells 23282875fa00SEric Paris return dentry_has_perm(cred, dentry, FILE__QUOTAON); 23291da177e4SLinus Torvalds } 23301da177e4SLinus Torvalds 233112b3052cSEric Paris static int selinux_syslog(int type) 23321da177e4SLinus Torvalds { 23331da177e4SLinus Torvalds switch (type) { 2334d78ca3cdSKees Cook case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ 2335d78ca3cdSKees Cook case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ 23366b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 23376b6bc620SStephen Smalley current_sid(), SECINITSID_KERNEL, 2338be0554c9SStephen Smalley SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL); 2339d78ca3cdSKees Cook case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ 2340d78ca3cdSKees Cook case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ 2341d78ca3cdSKees Cook /* Set level of messages printed to console */ 2342d78ca3cdSKees Cook case SYSLOG_ACTION_CONSOLE_LEVEL: 23436b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 23446b6bc620SStephen Smalley current_sid(), SECINITSID_KERNEL, 2345be0554c9SStephen Smalley SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, 2346be0554c9SStephen Smalley NULL); 23471da177e4SLinus Torvalds } 2348be0554c9SStephen Smalley /* All other syslog types */ 23496b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 23506b6bc620SStephen Smalley current_sid(), SECINITSID_KERNEL, 2351be0554c9SStephen Smalley SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL); 23521da177e4SLinus Torvalds } 23531da177e4SLinus Torvalds 23541da177e4SLinus Torvalds /* 23551da177e4SLinus Torvalds * Check that a process has enough memory to allocate a new virtual 23561da177e4SLinus Torvalds * mapping. 0 means there is enough memory for the allocation to 23571da177e4SLinus Torvalds * succeed and -ENOMEM implies there is not. 23581da177e4SLinus Torvalds * 23591da177e4SLinus Torvalds * Do not audit the selinux permission check, as this is applied to all 23601da177e4SLinus Torvalds * processes that allocate mappings. 23611da177e4SLinus Torvalds */ 236234b4e4aaSAlan Cox static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) 23631da177e4SLinus Torvalds { 23641da177e4SLinus Torvalds int rc, cap_sys_admin = 0; 23651da177e4SLinus Torvalds 2366b1d9e6b0SCasey Schaufler rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN, 23678e4ff6f2SStephen Smalley SECURITY_CAP_NOAUDIT, true); 23681da177e4SLinus Torvalds if (rc == 0) 23691da177e4SLinus Torvalds cap_sys_admin = 1; 23701da177e4SLinus Torvalds 2371b1d9e6b0SCasey Schaufler return cap_sys_admin; 23721da177e4SLinus Torvalds } 23731da177e4SLinus Torvalds 23741da177e4SLinus Torvalds /* binprm security operations */ 23751da177e4SLinus Torvalds 2376be0554c9SStephen Smalley static u32 ptrace_parent_sid(void) 23770c6181cbSPaul Moore { 23780c6181cbSPaul Moore u32 sid = 0; 23790c6181cbSPaul Moore struct task_struct *tracer; 23800c6181cbSPaul Moore 23810c6181cbSPaul Moore rcu_read_lock(); 2382be0554c9SStephen Smalley tracer = ptrace_parent(current); 23830c6181cbSPaul Moore if (tracer) 23840c6181cbSPaul Moore sid = task_sid(tracer); 23850c6181cbSPaul Moore rcu_read_unlock(); 23860c6181cbSPaul Moore 23870c6181cbSPaul Moore return sid; 23880c6181cbSPaul Moore } 23890c6181cbSPaul Moore 23907b0d0b40SStephen Smalley static int check_nnp_nosuid(const struct linux_binprm *bprm, 23917b0d0b40SStephen Smalley const struct task_security_struct *old_tsec, 23927b0d0b40SStephen Smalley const struct task_security_struct *new_tsec) 23937b0d0b40SStephen Smalley { 23947b0d0b40SStephen Smalley int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS); 2395380cf5baSAndy Lutomirski int nosuid = !mnt_may_suid(bprm->file->f_path.mnt); 23967b0d0b40SStephen Smalley int rc; 2397af63f419SStephen Smalley u32 av; 23987b0d0b40SStephen Smalley 23997b0d0b40SStephen Smalley if (!nnp && !nosuid) 24007b0d0b40SStephen Smalley return 0; /* neither NNP nor nosuid */ 24017b0d0b40SStephen Smalley 24027b0d0b40SStephen Smalley if (new_tsec->sid == old_tsec->sid) 24037b0d0b40SStephen Smalley return 0; /* No change in credentials */ 24047b0d0b40SStephen Smalley 24057b0d0b40SStephen Smalley /* 2406af63f419SStephen Smalley * If the policy enables the nnp_nosuid_transition policy capability, 2407af63f419SStephen Smalley * then we permit transitions under NNP or nosuid if the 2408af63f419SStephen Smalley * policy allows the corresponding permission between 2409af63f419SStephen Smalley * the old and new contexts. 2410af63f419SStephen Smalley */ 2411aa8e712cSStephen Smalley if (selinux_policycap_nnp_nosuid_transition()) { 2412af63f419SStephen Smalley av = 0; 2413af63f419SStephen Smalley if (nnp) 2414af63f419SStephen Smalley av |= PROCESS2__NNP_TRANSITION; 2415af63f419SStephen Smalley if (nosuid) 2416af63f419SStephen Smalley av |= PROCESS2__NOSUID_TRANSITION; 24176b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 24186b6bc620SStephen Smalley old_tsec->sid, new_tsec->sid, 2419af63f419SStephen Smalley SECCLASS_PROCESS2, av, NULL); 2420af63f419SStephen Smalley if (!rc) 2421af63f419SStephen Smalley return 0; 2422af63f419SStephen Smalley } 2423af63f419SStephen Smalley 2424af63f419SStephen Smalley /* 2425af63f419SStephen Smalley * We also permit NNP or nosuid transitions to bounded SIDs, 2426af63f419SStephen Smalley * i.e. SIDs that are guaranteed to only be allowed a subset 2427af63f419SStephen Smalley * of the permissions of the current SID. 24287b0d0b40SStephen Smalley */ 2429aa8e712cSStephen Smalley rc = security_bounded_transition(&selinux_state, old_tsec->sid, 2430aa8e712cSStephen Smalley new_tsec->sid); 2431af63f419SStephen Smalley if (!rc) 2432af63f419SStephen Smalley return 0; 2433af63f419SStephen Smalley 24347b0d0b40SStephen Smalley /* 24357b0d0b40SStephen Smalley * On failure, preserve the errno values for NNP vs nosuid. 24367b0d0b40SStephen Smalley * NNP: Operation not permitted for caller. 24377b0d0b40SStephen Smalley * nosuid: Permission denied to file. 24387b0d0b40SStephen Smalley */ 24397b0d0b40SStephen Smalley if (nnp) 24407b0d0b40SStephen Smalley return -EPERM; 24417b0d0b40SStephen Smalley return -EACCES; 24427b0d0b40SStephen Smalley } 24437b0d0b40SStephen Smalley 2444a6f76f23SDavid Howells static int selinux_bprm_set_creds(struct linux_binprm *bprm) 24451da177e4SLinus Torvalds { 2446a6f76f23SDavid Howells const struct task_security_struct *old_tsec; 2447a6f76f23SDavid Howells struct task_security_struct *new_tsec; 24481da177e4SLinus Torvalds struct inode_security_struct *isec; 24492bf49690SThomas Liu struct common_audit_data ad; 2450496ad9aaSAl Viro struct inode *inode = file_inode(bprm->file); 24511da177e4SLinus Torvalds int rc; 24521da177e4SLinus Torvalds 2453a6f76f23SDavid Howells /* SELinux context only depends on initial program or script and not 2454a6f76f23SDavid Howells * the script interpreter */ 2455ddb4a144SKees Cook if (bprm->called_set_creds) 24561da177e4SLinus Torvalds return 0; 24571da177e4SLinus Torvalds 2458a6f76f23SDavid Howells old_tsec = current_security(); 2459a6f76f23SDavid Howells new_tsec = bprm->cred->security; 246083da53c5SAndreas Gruenbacher isec = inode_security(inode); 24611da177e4SLinus Torvalds 24621da177e4SLinus Torvalds /* Default to the current task SID. */ 2463a6f76f23SDavid Howells new_tsec->sid = old_tsec->sid; 2464a6f76f23SDavid Howells new_tsec->osid = old_tsec->sid; 24651da177e4SLinus Torvalds 246628eba5bfSMichael LeMay /* Reset fs, key, and sock SIDs on execve. */ 2467a6f76f23SDavid Howells new_tsec->create_sid = 0; 2468a6f76f23SDavid Howells new_tsec->keycreate_sid = 0; 2469a6f76f23SDavid Howells new_tsec->sockcreate_sid = 0; 24701da177e4SLinus Torvalds 2471a6f76f23SDavid Howells if (old_tsec->exec_sid) { 2472a6f76f23SDavid Howells new_tsec->sid = old_tsec->exec_sid; 24731da177e4SLinus Torvalds /* Reset exec SID on execve. */ 2474a6f76f23SDavid Howells new_tsec->exec_sid = 0; 2475259e5e6cSAndy Lutomirski 24767b0d0b40SStephen Smalley /* Fail on NNP or nosuid if not an allowed transition. */ 24777b0d0b40SStephen Smalley rc = check_nnp_nosuid(bprm, old_tsec, new_tsec); 24787b0d0b40SStephen Smalley if (rc) 24797b0d0b40SStephen Smalley return rc; 24801da177e4SLinus Torvalds } else { 24811da177e4SLinus Torvalds /* Check for a default transition on this program. */ 2482aa8e712cSStephen Smalley rc = security_transition_sid(&selinux_state, old_tsec->sid, 2483aa8e712cSStephen Smalley isec->sid, SECCLASS_PROCESS, NULL, 2484652bb9b0SEric Paris &new_tsec->sid); 24851da177e4SLinus Torvalds if (rc) 24861da177e4SLinus Torvalds return rc; 24877b0d0b40SStephen Smalley 24887b0d0b40SStephen Smalley /* 24897b0d0b40SStephen Smalley * Fallback to old SID on NNP or nosuid if not an allowed 24907b0d0b40SStephen Smalley * transition. 24917b0d0b40SStephen Smalley */ 24927b0d0b40SStephen Smalley rc = check_nnp_nosuid(bprm, old_tsec, new_tsec); 24937b0d0b40SStephen Smalley if (rc) 24947b0d0b40SStephen Smalley new_tsec->sid = old_tsec->sid; 24951da177e4SLinus Torvalds } 24961da177e4SLinus Torvalds 249743af5de7SVivek Goyal ad.type = LSM_AUDIT_DATA_FILE; 249843af5de7SVivek Goyal ad.u.file = bprm->file; 24991da177e4SLinus Torvalds 2500a6f76f23SDavid Howells if (new_tsec->sid == old_tsec->sid) { 25016b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 25026b6bc620SStephen Smalley old_tsec->sid, isec->sid, 25031da177e4SLinus Torvalds SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); 25041da177e4SLinus Torvalds if (rc) 25051da177e4SLinus Torvalds return rc; 25061da177e4SLinus Torvalds } else { 25071da177e4SLinus Torvalds /* Check permissions for the transition. */ 25086b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 25096b6bc620SStephen Smalley old_tsec->sid, new_tsec->sid, 25101da177e4SLinus Torvalds SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); 25111da177e4SLinus Torvalds if (rc) 25121da177e4SLinus Torvalds return rc; 25131da177e4SLinus Torvalds 25146b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 25156b6bc620SStephen Smalley new_tsec->sid, isec->sid, 25161da177e4SLinus Torvalds SECCLASS_FILE, FILE__ENTRYPOINT, &ad); 25171da177e4SLinus Torvalds if (rc) 25181da177e4SLinus Torvalds return rc; 25191da177e4SLinus Torvalds 2520a6f76f23SDavid Howells /* Check for shared state */ 2521a6f76f23SDavid Howells if (bprm->unsafe & LSM_UNSAFE_SHARE) { 25226b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 25236b6bc620SStephen Smalley old_tsec->sid, new_tsec->sid, 2524a6f76f23SDavid Howells SECCLASS_PROCESS, PROCESS__SHARE, 2525a6f76f23SDavid Howells NULL); 2526a6f76f23SDavid Howells if (rc) 2527a6f76f23SDavid Howells return -EPERM; 25281da177e4SLinus Torvalds } 25291da177e4SLinus Torvalds 2530a6f76f23SDavid Howells /* Make sure that anyone attempting to ptrace over a task that 2531a6f76f23SDavid Howells * changes its SID has the appropriate permit */ 25329227dd2aSEric W. Biederman if (bprm->unsafe & LSM_UNSAFE_PTRACE) { 2533be0554c9SStephen Smalley u32 ptsid = ptrace_parent_sid(); 2534a6f76f23SDavid Howells if (ptsid != 0) { 25356b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 25366b6bc620SStephen Smalley ptsid, new_tsec->sid, 2537a6f76f23SDavid Howells SECCLASS_PROCESS, 2538a6f76f23SDavid Howells PROCESS__PTRACE, NULL); 2539a6f76f23SDavid Howells if (rc) 2540a6f76f23SDavid Howells return -EPERM; 2541a6f76f23SDavid Howells } 2542a6f76f23SDavid Howells } 2543a6f76f23SDavid Howells 2544a6f76f23SDavid Howells /* Clear any possibly unsafe personality bits on exec: */ 2545a6f76f23SDavid Howells bprm->per_clear |= PER_CLEAR_ON_SETID; 2546a6f76f23SDavid Howells 25471da177e4SLinus Torvalds /* Enable secure mode for SIDs transitions unless 25481da177e4SLinus Torvalds the noatsecure permission is granted between 25491da177e4SLinus Torvalds the two SIDs, i.e. ahp returns 0. */ 25506b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 25516b6bc620SStephen Smalley old_tsec->sid, new_tsec->sid, 255262874c3aSKees Cook SECCLASS_PROCESS, PROCESS__NOATSECURE, 255362874c3aSKees Cook NULL); 255462874c3aSKees Cook bprm->secureexec |= !!rc; 25551da177e4SLinus Torvalds } 25561da177e4SLinus Torvalds 255762874c3aSKees Cook return 0; 25581da177e4SLinus Torvalds } 25591da177e4SLinus Torvalds 2560c3c073f8SAl Viro static int match_file(const void *p, struct file *file, unsigned fd) 2561c3c073f8SAl Viro { 2562c3c073f8SAl Viro return file_has_perm(p, file, file_to_av(file)) ? fd + 1 : 0; 2563c3c073f8SAl Viro } 2564c3c073f8SAl Viro 25651da177e4SLinus Torvalds /* Derived from fs/exec.c:flush_old_files. */ 2566745ca247SDavid Howells static inline void flush_unauthorized_files(const struct cred *cred, 2567745ca247SDavid Howells struct files_struct *files) 25681da177e4SLinus Torvalds { 25691da177e4SLinus Torvalds struct file *file, *devnull = NULL; 2570b20c8122SStephen Smalley struct tty_struct *tty; 257124ec839cSPeter Zijlstra int drop_tty = 0; 2572c3c073f8SAl Viro unsigned n; 25731da177e4SLinus Torvalds 257424ec839cSPeter Zijlstra tty = get_current_tty(); 25751da177e4SLinus Torvalds if (tty) { 25764a510969SPeter Hurley spin_lock(&tty->files_lock); 257737dd0bd0SEric Paris if (!list_empty(&tty->tty_files)) { 2578d996b62aSNick Piggin struct tty_file_private *file_priv; 257937dd0bd0SEric Paris 25801da177e4SLinus Torvalds /* Revalidate access to controlling tty. 258113f8e981SDavid Howells Use file_path_has_perm on the tty path directly 258213f8e981SDavid Howells rather than using file_has_perm, as this particular 258313f8e981SDavid Howells open file may belong to another process and we are 258413f8e981SDavid Howells only interested in the inode-based check here. */ 2585d996b62aSNick Piggin file_priv = list_first_entry(&tty->tty_files, 2586d996b62aSNick Piggin struct tty_file_private, list); 2587d996b62aSNick Piggin file = file_priv->file; 258813f8e981SDavid Howells if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE)) 258924ec839cSPeter Zijlstra drop_tty = 1; 25901da177e4SLinus Torvalds } 25914a510969SPeter Hurley spin_unlock(&tty->files_lock); 2592452a00d2SAlan Cox tty_kref_put(tty); 25931da177e4SLinus Torvalds } 259498a27ba4SEric W. Biederman /* Reset controlling tty. */ 259598a27ba4SEric W. Biederman if (drop_tty) 259698a27ba4SEric W. Biederman no_tty(); 25971da177e4SLinus Torvalds 25981da177e4SLinus Torvalds /* Revalidate access to inherited open files. */ 2599c3c073f8SAl Viro n = iterate_fd(files, 0, match_file, cred); 2600c3c073f8SAl Viro if (!n) /* none found? */ 2601c3c073f8SAl Viro return; 26021da177e4SLinus Torvalds 2603c3c073f8SAl Viro devnull = dentry_open(&selinux_null, O_RDWR, cred); 260445525b26SAl Viro if (IS_ERR(devnull)) 260545525b26SAl Viro devnull = NULL; 2606c3c073f8SAl Viro /* replace all the matching ones with this */ 2607c3c073f8SAl Viro do { 260845525b26SAl Viro replace_fd(n - 1, devnull, 0); 2609c3c073f8SAl Viro } while ((n = iterate_fd(files, n, match_file, cred)) != 0); 261045525b26SAl Viro if (devnull) 2611c3c073f8SAl Viro fput(devnull); 26121da177e4SLinus Torvalds } 26131da177e4SLinus Torvalds 26141da177e4SLinus Torvalds /* 2615a6f76f23SDavid Howells * Prepare a process for imminent new credential changes due to exec 26161da177e4SLinus Torvalds */ 2617a6f76f23SDavid Howells static void selinux_bprm_committing_creds(struct linux_binprm *bprm) 26181da177e4SLinus Torvalds { 2619a6f76f23SDavid Howells struct task_security_struct *new_tsec; 26201da177e4SLinus Torvalds struct rlimit *rlim, *initrlim; 26211da177e4SLinus Torvalds int rc, i; 26221da177e4SLinus Torvalds 2623a6f76f23SDavid Howells new_tsec = bprm->cred->security; 2624a6f76f23SDavid Howells if (new_tsec->sid == new_tsec->osid) 26251da177e4SLinus Torvalds return; 26261da177e4SLinus Torvalds 26271da177e4SLinus Torvalds /* Close files for which the new task SID is not authorized. */ 2628a6f76f23SDavid Howells flush_unauthorized_files(bprm->cred, current->files); 26291da177e4SLinus Torvalds 2630a6f76f23SDavid Howells /* Always clear parent death signal on SID transitions. */ 2631a6f76f23SDavid Howells current->pdeath_signal = 0; 2632a6f76f23SDavid Howells 2633a6f76f23SDavid Howells /* Check whether the new SID can inherit resource limits from the old 2634a6f76f23SDavid Howells * SID. If not, reset all soft limits to the lower of the current 2635a6f76f23SDavid Howells * task's hard limit and the init task's soft limit. 2636a6f76f23SDavid Howells * 2637a6f76f23SDavid Howells * Note that the setting of hard limits (even to lower them) can be 2638a6f76f23SDavid Howells * controlled by the setrlimit check. The inclusion of the init task's 2639a6f76f23SDavid Howells * soft limit into the computation is to avoid resetting soft limits 2640a6f76f23SDavid Howells * higher than the default soft limit for cases where the default is 2641a6f76f23SDavid Howells * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK. 2642a6f76f23SDavid Howells */ 26436b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 26446b6bc620SStephen Smalley new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS, 2645a6f76f23SDavid Howells PROCESS__RLIMITINH, NULL); 2646a6f76f23SDavid Howells if (rc) { 2647eb2d55a3SOleg Nesterov /* protect against do_prlimit() */ 2648eb2d55a3SOleg Nesterov task_lock(current); 2649a6f76f23SDavid Howells for (i = 0; i < RLIM_NLIMITS; i++) { 2650a6f76f23SDavid Howells rlim = current->signal->rlim + i; 2651a6f76f23SDavid Howells initrlim = init_task.signal->rlim + i; 2652a6f76f23SDavid Howells rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur); 2653a6f76f23SDavid Howells } 2654eb2d55a3SOleg Nesterov task_unlock(current); 2655baa73d9eSNicolas Pitre if (IS_ENABLED(CONFIG_POSIX_TIMERS)) 2656eb2d55a3SOleg Nesterov update_rlimit_cpu(current, rlimit(RLIMIT_CPU)); 2657a6f76f23SDavid Howells } 2658a6f76f23SDavid Howells } 2659a6f76f23SDavid Howells 2660a6f76f23SDavid Howells /* 2661a6f76f23SDavid Howells * Clean up the process immediately after the installation of new credentials 2662a6f76f23SDavid Howells * due to exec 2663a6f76f23SDavid Howells */ 2664a6f76f23SDavid Howells static void selinux_bprm_committed_creds(struct linux_binprm *bprm) 2665a6f76f23SDavid Howells { 2666a6f76f23SDavid Howells const struct task_security_struct *tsec = current_security(); 2667a6f76f23SDavid Howells struct itimerval itimer; 2668a6f76f23SDavid Howells u32 osid, sid; 2669a6f76f23SDavid Howells int rc, i; 2670a6f76f23SDavid Howells 2671a6f76f23SDavid Howells osid = tsec->osid; 2672a6f76f23SDavid Howells sid = tsec->sid; 2673a6f76f23SDavid Howells 2674a6f76f23SDavid Howells if (sid == osid) 2675a6f76f23SDavid Howells return; 2676a6f76f23SDavid Howells 2677a6f76f23SDavid Howells /* Check whether the new SID can inherit signal state from the old SID. 2678a6f76f23SDavid Howells * If not, clear itimers to avoid subsequent signal generation and 2679a6f76f23SDavid Howells * flush and unblock signals. 2680a6f76f23SDavid Howells * 2681a6f76f23SDavid Howells * This must occur _after_ the task SID has been updated so that any 2682a6f76f23SDavid Howells * kill done after the flush will be checked against the new SID. 2683a6f76f23SDavid Howells */ 26846b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 26856b6bc620SStephen Smalley osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL); 26861da177e4SLinus Torvalds if (rc) { 2687baa73d9eSNicolas Pitre if (IS_ENABLED(CONFIG_POSIX_TIMERS)) { 26881da177e4SLinus Torvalds memset(&itimer, 0, sizeof itimer); 26891da177e4SLinus Torvalds for (i = 0; i < 3; i++) 26901da177e4SLinus Torvalds do_setitimer(i, &itimer, NULL); 2691baa73d9eSNicolas Pitre } 26921da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 26939e7c8f8cSOleg Nesterov if (!fatal_signal_pending(current)) { 26949e7c8f8cSOleg Nesterov flush_sigqueue(¤t->pending); 26959e7c8f8cSOleg Nesterov flush_sigqueue(¤t->signal->shared_pending); 26961da177e4SLinus Torvalds flush_signal_handlers(current, 1); 26971da177e4SLinus Torvalds sigemptyset(¤t->blocked); 26989e7c8f8cSOleg Nesterov recalc_sigpending(); 26993bcac026SDavid Howells } 27001da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 27011da177e4SLinus Torvalds } 27021da177e4SLinus Torvalds 2703a6f76f23SDavid Howells /* Wake up the parent if it is waiting so that it can recheck 2704a6f76f23SDavid Howells * wait permission to the new task SID. */ 2705ecd6de3cSOleg Nesterov read_lock(&tasklist_lock); 27060b7570e7SOleg Nesterov __wake_up_parent(current, current->real_parent); 2707ecd6de3cSOleg Nesterov read_unlock(&tasklist_lock); 27081da177e4SLinus Torvalds } 27091da177e4SLinus Torvalds 27101da177e4SLinus Torvalds /* superblock security operations */ 27111da177e4SLinus Torvalds 27121da177e4SLinus Torvalds static int selinux_sb_alloc_security(struct super_block *sb) 27131da177e4SLinus Torvalds { 27141da177e4SLinus Torvalds return superblock_alloc_security(sb); 27151da177e4SLinus Torvalds } 27161da177e4SLinus Torvalds 27171da177e4SLinus Torvalds static void selinux_sb_free_security(struct super_block *sb) 27181da177e4SLinus Torvalds { 27191da177e4SLinus Torvalds superblock_free_security(sb); 27201da177e4SLinus Torvalds } 27211da177e4SLinus Torvalds 27221da177e4SLinus Torvalds static inline int match_prefix(char *prefix, int plen, char *option, int olen) 27231da177e4SLinus Torvalds { 27241da177e4SLinus Torvalds if (plen > olen) 27251da177e4SLinus Torvalds return 0; 27261da177e4SLinus Torvalds 27271da177e4SLinus Torvalds return !memcmp(prefix, option, plen); 27281da177e4SLinus Torvalds } 27291da177e4SLinus Torvalds 27301da177e4SLinus Torvalds static inline int selinux_option(char *option, int len) 27311da177e4SLinus Torvalds { 2732832cbd9aSEric Paris return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) || 2733832cbd9aSEric Paris match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) || 2734832cbd9aSEric Paris match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) || 273511689d47SDavid P. Quigley match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len) || 273611689d47SDavid P. Quigley match_prefix(LABELSUPP_STR, sizeof(LABELSUPP_STR)-1, option, len)); 27371da177e4SLinus Torvalds } 27381da177e4SLinus Torvalds 27391da177e4SLinus Torvalds static inline void take_option(char **to, char *from, int *first, int len) 27401da177e4SLinus Torvalds { 27411da177e4SLinus Torvalds if (!*first) { 27421da177e4SLinus Torvalds **to = ','; 27431da177e4SLinus Torvalds *to += 1; 27443528a953SCory Olmo } else 27451da177e4SLinus Torvalds *first = 0; 27461da177e4SLinus Torvalds memcpy(*to, from, len); 27471da177e4SLinus Torvalds *to += len; 27481da177e4SLinus Torvalds } 27491da177e4SLinus Torvalds 27503528a953SCory Olmo static inline void take_selinux_option(char **to, char *from, int *first, 27513528a953SCory Olmo int len) 27523528a953SCory Olmo { 27533528a953SCory Olmo int current_size = 0; 27543528a953SCory Olmo 27553528a953SCory Olmo if (!*first) { 27563528a953SCory Olmo **to = '|'; 27573528a953SCory Olmo *to += 1; 2758828dfe1dSEric Paris } else 27593528a953SCory Olmo *first = 0; 27603528a953SCory Olmo 27613528a953SCory Olmo while (current_size < len) { 27623528a953SCory Olmo if (*from != '"') { 27633528a953SCory Olmo **to = *from; 27643528a953SCory Olmo *to += 1; 27653528a953SCory Olmo } 27663528a953SCory Olmo from += 1; 27673528a953SCory Olmo current_size += 1; 27683528a953SCory Olmo } 27693528a953SCory Olmo } 27703528a953SCory Olmo 2771e0007529SEric Paris static int selinux_sb_copy_data(char *orig, char *copy) 27721da177e4SLinus Torvalds { 27731da177e4SLinus Torvalds int fnosec, fsec, rc = 0; 27741da177e4SLinus Torvalds char *in_save, *in_curr, *in_end; 27751da177e4SLinus Torvalds char *sec_curr, *nosec_save, *nosec; 27763528a953SCory Olmo int open_quote = 0; 27771da177e4SLinus Torvalds 27781da177e4SLinus Torvalds in_curr = orig; 27791da177e4SLinus Torvalds sec_curr = copy; 27801da177e4SLinus Torvalds 27811da177e4SLinus Torvalds nosec = (char *)get_zeroed_page(GFP_KERNEL); 27821da177e4SLinus Torvalds if (!nosec) { 27831da177e4SLinus Torvalds rc = -ENOMEM; 27841da177e4SLinus Torvalds goto out; 27851da177e4SLinus Torvalds } 27861da177e4SLinus Torvalds 27871da177e4SLinus Torvalds nosec_save = nosec; 27881da177e4SLinus Torvalds fnosec = fsec = 1; 27891da177e4SLinus Torvalds in_save = in_end = orig; 27901da177e4SLinus Torvalds 27911da177e4SLinus Torvalds do { 27923528a953SCory Olmo if (*in_end == '"') 27933528a953SCory Olmo open_quote = !open_quote; 27943528a953SCory Olmo if ((*in_end == ',' && open_quote == 0) || 27953528a953SCory Olmo *in_end == '\0') { 27961da177e4SLinus Torvalds int len = in_end - in_curr; 27971da177e4SLinus Torvalds 27981da177e4SLinus Torvalds if (selinux_option(in_curr, len)) 27993528a953SCory Olmo take_selinux_option(&sec_curr, in_curr, &fsec, len); 28001da177e4SLinus Torvalds else 28011da177e4SLinus Torvalds take_option(&nosec, in_curr, &fnosec, len); 28021da177e4SLinus Torvalds 28031da177e4SLinus Torvalds in_curr = in_end + 1; 28041da177e4SLinus Torvalds } 28051da177e4SLinus Torvalds } while (*in_end++); 28061da177e4SLinus Torvalds 28076931dfc9SEric Paris strcpy(in_save, nosec_save); 2808da3caa20SGerald Schaefer free_page((unsigned long)nosec_save); 28091da177e4SLinus Torvalds out: 28101da177e4SLinus Torvalds return rc; 28111da177e4SLinus Torvalds } 28121da177e4SLinus Torvalds 2813c039bc3cSAl Viro static int selinux_sb_remount(struct super_block *sb, 2814c039bc3cSAl Viro struct security_mnt_opts *opts) 2815026eb167SEric Paris { 2816c039bc3cSAl Viro int i, *flags; 2817c039bc3cSAl Viro char **mount_options; 2818026eb167SEric Paris struct superblock_security_struct *sbsec = sb->s_security; 2819026eb167SEric Paris 2820026eb167SEric Paris if (!(sbsec->flags & SE_SBINITIALIZED)) 2821026eb167SEric Paris return 0; 2822026eb167SEric Paris 2823c039bc3cSAl Viro mount_options = opts->mnt_opts; 2824c039bc3cSAl Viro flags = opts->mnt_opts_flags; 2825026eb167SEric Paris 2826c039bc3cSAl Viro for (i = 0; i < opts->num_mnt_opts; i++) { 2827026eb167SEric Paris u32 sid; 2828c039bc3cSAl Viro int rc; 2829026eb167SEric Paris 283012f348b9SEric Paris if (flags[i] == SBLABEL_MNT) 2831026eb167SEric Paris continue; 2832aa8e712cSStephen Smalley rc = security_context_str_to_sid(&selinux_state, 2833aa8e712cSStephen Smalley mount_options[i], &sid, 2834aa8e712cSStephen Smalley GFP_KERNEL); 2835026eb167SEric Paris if (rc) { 2836c103a91eSpeter enderborg pr_warn("SELinux: security_context_str_to_sid" 283729b1deb2SLinus Torvalds "(%s) failed for (dev %s, type %s) errno=%d\n", 283829b1deb2SLinus Torvalds mount_options[i], sb->s_id, sb->s_type->name, rc); 2839c039bc3cSAl Viro return rc; 2840026eb167SEric Paris } 2841026eb167SEric Paris switch (flags[i]) { 2842026eb167SEric Paris case FSCONTEXT_MNT: 2843026eb167SEric Paris if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) 2844026eb167SEric Paris goto out_bad_option; 2845026eb167SEric Paris break; 2846026eb167SEric Paris case CONTEXT_MNT: 2847026eb167SEric Paris if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) 2848026eb167SEric Paris goto out_bad_option; 2849026eb167SEric Paris break; 2850026eb167SEric Paris case ROOTCONTEXT_MNT: { 2851026eb167SEric Paris struct inode_security_struct *root_isec; 285283da53c5SAndreas Gruenbacher root_isec = backing_inode_security(sb->s_root); 2853026eb167SEric Paris 2854026eb167SEric Paris if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) 2855026eb167SEric Paris goto out_bad_option; 2856026eb167SEric Paris break; 2857026eb167SEric Paris } 2858026eb167SEric Paris case DEFCONTEXT_MNT: 2859026eb167SEric Paris if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) 2860026eb167SEric Paris goto out_bad_option; 2861026eb167SEric Paris break; 2862026eb167SEric Paris default: 2863c039bc3cSAl Viro return -EINVAL; 2864026eb167SEric Paris } 2865026eb167SEric Paris } 2866c039bc3cSAl Viro return 0; 2867026eb167SEric Paris 2868026eb167SEric Paris out_bad_option: 2869c103a91eSpeter enderborg pr_warn("SELinux: unable to change security options " 287029b1deb2SLinus Torvalds "during remount (dev %s, type=%s)\n", sb->s_id, 287129b1deb2SLinus Torvalds sb->s_type->name); 2872c039bc3cSAl Viro return -EINVAL; 2873026eb167SEric Paris } 2874026eb167SEric Paris 2875a10d7c22SAl Viro static int selinux_sb_kern_mount(struct super_block *sb) 28761da177e4SLinus Torvalds { 287788e67f3bSDavid Howells const struct cred *cred = current_cred(); 28782bf49690SThomas Liu struct common_audit_data ad; 287974192246SJames Morris 288050c205f5SEric Paris ad.type = LSM_AUDIT_DATA_DENTRY; 2881a269434dSEric Paris ad.u.dentry = sb->s_root; 288288e67f3bSDavid Howells return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); 28831da177e4SLinus Torvalds } 28841da177e4SLinus Torvalds 2885726c3342SDavid Howells static int selinux_sb_statfs(struct dentry *dentry) 28861da177e4SLinus Torvalds { 288788e67f3bSDavid Howells const struct cred *cred = current_cred(); 28882bf49690SThomas Liu struct common_audit_data ad; 28891da177e4SLinus Torvalds 289050c205f5SEric Paris ad.type = LSM_AUDIT_DATA_DENTRY; 2891a269434dSEric Paris ad.u.dentry = dentry->d_sb->s_root; 289288e67f3bSDavid Howells return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); 28931da177e4SLinus Torvalds } 28941da177e4SLinus Torvalds 2895808d4e3cSAl Viro static int selinux_mount(const char *dev_name, 28968a04c43bSAl Viro const struct path *path, 2897808d4e3cSAl Viro const char *type, 28981da177e4SLinus Torvalds unsigned long flags, 28991da177e4SLinus Torvalds void *data) 29001da177e4SLinus Torvalds { 290188e67f3bSDavid Howells const struct cred *cred = current_cred(); 29021da177e4SLinus Torvalds 29031da177e4SLinus Torvalds if (flags & MS_REMOUNT) 2904d8c9584eSAl Viro return superblock_has_perm(cred, path->dentry->d_sb, 29051da177e4SLinus Torvalds FILESYSTEM__REMOUNT, NULL); 29061da177e4SLinus Torvalds else 29072875fa00SEric Paris return path_has_perm(cred, path, FILE__MOUNTON); 29081da177e4SLinus Torvalds } 29091da177e4SLinus Torvalds 29101da177e4SLinus Torvalds static int selinux_umount(struct vfsmount *mnt, int flags) 29111da177e4SLinus Torvalds { 291288e67f3bSDavid Howells const struct cred *cred = current_cred(); 29131da177e4SLinus Torvalds 291488e67f3bSDavid Howells return superblock_has_perm(cred, mnt->mnt_sb, 29151da177e4SLinus Torvalds FILESYSTEM__UNMOUNT, NULL); 29161da177e4SLinus Torvalds } 29171da177e4SLinus Torvalds 29181da177e4SLinus Torvalds /* inode security operations */ 29191da177e4SLinus Torvalds 29201da177e4SLinus Torvalds static int selinux_inode_alloc_security(struct inode *inode) 29211da177e4SLinus Torvalds { 29221da177e4SLinus Torvalds return inode_alloc_security(inode); 29231da177e4SLinus Torvalds } 29241da177e4SLinus Torvalds 29251da177e4SLinus Torvalds static void selinux_inode_free_security(struct inode *inode) 29261da177e4SLinus Torvalds { 29271da177e4SLinus Torvalds inode_free_security(inode); 29281da177e4SLinus Torvalds } 29291da177e4SLinus Torvalds 2930d47be3dfSDavid Quigley static int selinux_dentry_init_security(struct dentry *dentry, int mode, 29314f3ccd76SAl Viro const struct qstr *name, void **ctx, 2932d47be3dfSDavid Quigley u32 *ctxlen) 2933d47be3dfSDavid Quigley { 2934d47be3dfSDavid Quigley u32 newsid; 2935d47be3dfSDavid Quigley int rc; 2936d47be3dfSDavid Quigley 2937c957f6dfSVivek Goyal rc = selinux_determine_inode_label(current_security(), 2938c957f6dfSVivek Goyal d_inode(dentry->d_parent), name, 2939d47be3dfSDavid Quigley inode_mode_to_security_class(mode), 2940d47be3dfSDavid Quigley &newsid); 2941c3c188b2SDavid Howells if (rc) 2942d47be3dfSDavid Quigley return rc; 2943d47be3dfSDavid Quigley 2944aa8e712cSStephen Smalley return security_sid_to_context(&selinux_state, newsid, (char **)ctx, 2945aa8e712cSStephen Smalley ctxlen); 2946d47be3dfSDavid Quigley } 2947d47be3dfSDavid Quigley 2948a518b0a5SVivek Goyal static int selinux_dentry_create_files_as(struct dentry *dentry, int mode, 2949a518b0a5SVivek Goyal struct qstr *name, 2950a518b0a5SVivek Goyal const struct cred *old, 2951a518b0a5SVivek Goyal struct cred *new) 2952a518b0a5SVivek Goyal { 2953a518b0a5SVivek Goyal u32 newsid; 2954a518b0a5SVivek Goyal int rc; 2955a518b0a5SVivek Goyal struct task_security_struct *tsec; 2956a518b0a5SVivek Goyal 2957a518b0a5SVivek Goyal rc = selinux_determine_inode_label(old->security, 2958a518b0a5SVivek Goyal d_inode(dentry->d_parent), name, 2959a518b0a5SVivek Goyal inode_mode_to_security_class(mode), 2960a518b0a5SVivek Goyal &newsid); 2961a518b0a5SVivek Goyal if (rc) 2962a518b0a5SVivek Goyal return rc; 2963a518b0a5SVivek Goyal 2964a518b0a5SVivek Goyal tsec = new->security; 2965a518b0a5SVivek Goyal tsec->create_sid = newsid; 2966a518b0a5SVivek Goyal return 0; 2967a518b0a5SVivek Goyal } 2968a518b0a5SVivek Goyal 29695e41ff9eSStephen Smalley static int selinux_inode_init_security(struct inode *inode, struct inode *dir, 29709548906bSTetsuo Handa const struct qstr *qstr, 29719548906bSTetsuo Handa const char **name, 29722a7dba39SEric Paris void **value, size_t *len) 29735e41ff9eSStephen Smalley { 29745fb49870SPaul Moore const struct task_security_struct *tsec = current_security(); 29755e41ff9eSStephen Smalley struct superblock_security_struct *sbsec; 2976c0d4f464SCorentin LABBE u32 newsid, clen; 29775e41ff9eSStephen Smalley int rc; 29789548906bSTetsuo Handa char *context; 29795e41ff9eSStephen Smalley 29805e41ff9eSStephen Smalley sbsec = dir->i_sb->s_security; 29815e41ff9eSStephen Smalley 29825e41ff9eSStephen Smalley newsid = tsec->create_sid; 2983275bb41eSDavid Howells 2984c957f6dfSVivek Goyal rc = selinux_determine_inode_label(current_security(), 2985c3c188b2SDavid Howells dir, qstr, 29865e41ff9eSStephen Smalley inode_mode_to_security_class(inode->i_mode), 2987c3c188b2SDavid Howells &newsid); 2988c3c188b2SDavid Howells if (rc) 29895e41ff9eSStephen Smalley return rc; 29905e41ff9eSStephen Smalley 2991296fddf7SEric Paris /* Possibly defer initialization to selinux_complete_init. */ 29920d90a7ecSDavid P. Quigley if (sbsec->flags & SE_SBINITIALIZED) { 2993296fddf7SEric Paris struct inode_security_struct *isec = inode->i_security; 2994296fddf7SEric Paris isec->sclass = inode_mode_to_security_class(inode->i_mode); 2995296fddf7SEric Paris isec->sid = newsid; 29966f3be9f5SAndreas Gruenbacher isec->initialized = LABEL_INITIALIZED; 2997296fddf7SEric Paris } 29985e41ff9eSStephen Smalley 2999aa8e712cSStephen Smalley if (!selinux_state.initialized || !(sbsec->flags & SBLABEL_MNT)) 300025a74f3bSStephen Smalley return -EOPNOTSUPP; 300125a74f3bSStephen Smalley 30029548906bSTetsuo Handa if (name) 30039548906bSTetsuo Handa *name = XATTR_SELINUX_SUFFIX; 30045e41ff9eSStephen Smalley 3005570bc1c2SStephen Smalley if (value && len) { 3006aa8e712cSStephen Smalley rc = security_sid_to_context_force(&selinux_state, newsid, 3007aa8e712cSStephen Smalley &context, &clen); 30089548906bSTetsuo Handa if (rc) 30095e41ff9eSStephen Smalley return rc; 30105e41ff9eSStephen Smalley *value = context; 3011570bc1c2SStephen Smalley *len = clen; 3012570bc1c2SStephen Smalley } 30135e41ff9eSStephen Smalley 30145e41ff9eSStephen Smalley return 0; 30155e41ff9eSStephen Smalley } 30165e41ff9eSStephen Smalley 30174acdaf27SAl Viro static int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode) 30181da177e4SLinus Torvalds { 30191da177e4SLinus Torvalds return may_create(dir, dentry, SECCLASS_FILE); 30201da177e4SLinus Torvalds } 30211da177e4SLinus Torvalds 30221da177e4SLinus Torvalds static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) 30231da177e4SLinus Torvalds { 30241da177e4SLinus Torvalds return may_link(dir, old_dentry, MAY_LINK); 30251da177e4SLinus Torvalds } 30261da177e4SLinus Torvalds 30271da177e4SLinus Torvalds static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry) 30281da177e4SLinus Torvalds { 30291da177e4SLinus Torvalds return may_link(dir, dentry, MAY_UNLINK); 30301da177e4SLinus Torvalds } 30311da177e4SLinus Torvalds 30321da177e4SLinus Torvalds static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name) 30331da177e4SLinus Torvalds { 30341da177e4SLinus Torvalds return may_create(dir, dentry, SECCLASS_LNK_FILE); 30351da177e4SLinus Torvalds } 30361da177e4SLinus Torvalds 303718bb1db3SAl Viro static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask) 30381da177e4SLinus Torvalds { 30391da177e4SLinus Torvalds return may_create(dir, dentry, SECCLASS_DIR); 30401da177e4SLinus Torvalds } 30411da177e4SLinus Torvalds 30421da177e4SLinus Torvalds static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry) 30431da177e4SLinus Torvalds { 30441da177e4SLinus Torvalds return may_link(dir, dentry, MAY_RMDIR); 30451da177e4SLinus Torvalds } 30461da177e4SLinus Torvalds 30471a67aafbSAl Viro static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) 30481da177e4SLinus Torvalds { 30491da177e4SLinus Torvalds return may_create(dir, dentry, inode_mode_to_security_class(mode)); 30501da177e4SLinus Torvalds } 30511da177e4SLinus Torvalds 30521da177e4SLinus Torvalds static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry, 30531da177e4SLinus Torvalds struct inode *new_inode, struct dentry *new_dentry) 30541da177e4SLinus Torvalds { 30551da177e4SLinus Torvalds return may_rename(old_inode, old_dentry, new_inode, new_dentry); 30561da177e4SLinus Torvalds } 30571da177e4SLinus Torvalds 30581da177e4SLinus Torvalds static int selinux_inode_readlink(struct dentry *dentry) 30591da177e4SLinus Torvalds { 306088e67f3bSDavid Howells const struct cred *cred = current_cred(); 306188e67f3bSDavid Howells 30622875fa00SEric Paris return dentry_has_perm(cred, dentry, FILE__READ); 30631da177e4SLinus Torvalds } 30641da177e4SLinus Torvalds 3065bda0be7aSNeilBrown static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, 3066bda0be7aSNeilBrown bool rcu) 30671da177e4SLinus Torvalds { 306888e67f3bSDavid Howells const struct cred *cred = current_cred(); 3069bda0be7aSNeilBrown struct common_audit_data ad; 3070bda0be7aSNeilBrown struct inode_security_struct *isec; 3071bda0be7aSNeilBrown u32 sid; 30721da177e4SLinus Torvalds 3073bda0be7aSNeilBrown validate_creds(cred); 3074bda0be7aSNeilBrown 3075bda0be7aSNeilBrown ad.type = LSM_AUDIT_DATA_DENTRY; 3076bda0be7aSNeilBrown ad.u.dentry = dentry; 3077bda0be7aSNeilBrown sid = cred_sid(cred); 30785d226df4SAndreas Gruenbacher isec = inode_security_rcu(inode, rcu); 30795d226df4SAndreas Gruenbacher if (IS_ERR(isec)) 30805d226df4SAndreas Gruenbacher return PTR_ERR(isec); 3081bda0be7aSNeilBrown 30826b6bc620SStephen Smalley return avc_has_perm_flags(&selinux_state, 30836b6bc620SStephen Smalley sid, isec->sid, isec->sclass, FILE__READ, &ad, 3084bda0be7aSNeilBrown rcu ? MAY_NOT_BLOCK : 0); 30851da177e4SLinus Torvalds } 30861da177e4SLinus Torvalds 3087d4cf970dSEric Paris static noinline int audit_inode_permission(struct inode *inode, 3088d4cf970dSEric Paris u32 perms, u32 audited, u32 denied, 3089626b9740SStephen Smalley int result, 3090d4cf970dSEric Paris unsigned flags) 3091d4cf970dSEric Paris { 3092d4cf970dSEric Paris struct common_audit_data ad; 3093d4cf970dSEric Paris struct inode_security_struct *isec = inode->i_security; 3094d4cf970dSEric Paris int rc; 3095d4cf970dSEric Paris 309650c205f5SEric Paris ad.type = LSM_AUDIT_DATA_INODE; 3097d4cf970dSEric Paris ad.u.inode = inode; 3098d4cf970dSEric Paris 30996b6bc620SStephen Smalley rc = slow_avc_audit(&selinux_state, 31006b6bc620SStephen Smalley current_sid(), isec->sid, isec->sclass, perms, 3101626b9740SStephen Smalley audited, denied, result, &ad, flags); 3102d4cf970dSEric Paris if (rc) 3103d4cf970dSEric Paris return rc; 3104d4cf970dSEric Paris return 0; 3105d4cf970dSEric Paris } 3106d4cf970dSEric Paris 3107e74f71ebSAl Viro static int selinux_inode_permission(struct inode *inode, int mask) 31081da177e4SLinus Torvalds { 310988e67f3bSDavid Howells const struct cred *cred = current_cred(); 3110b782e0a6SEric Paris u32 perms; 3111b782e0a6SEric Paris bool from_access; 3112cf1dd1daSAl Viro unsigned flags = mask & MAY_NOT_BLOCK; 31132e334057SEric Paris struct inode_security_struct *isec; 31142e334057SEric Paris u32 sid; 31152e334057SEric Paris struct av_decision avd; 31162e334057SEric Paris int rc, rc2; 31172e334057SEric Paris u32 audited, denied; 31181da177e4SLinus Torvalds 3119b782e0a6SEric Paris from_access = mask & MAY_ACCESS; 3120d09ca739SEric Paris mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); 3121d09ca739SEric Paris 31221da177e4SLinus Torvalds /* No permission to check. Existence test. */ 3123b782e0a6SEric Paris if (!mask) 31241da177e4SLinus Torvalds return 0; 31251da177e4SLinus Torvalds 31262e334057SEric Paris validate_creds(cred); 3127b782e0a6SEric Paris 31282e334057SEric Paris if (unlikely(IS_PRIVATE(inode))) 31292e334057SEric Paris return 0; 3130b782e0a6SEric Paris 3131b782e0a6SEric Paris perms = file_mask_to_av(inode->i_mode, mask); 3132b782e0a6SEric Paris 31332e334057SEric Paris sid = cred_sid(cred); 31345d226df4SAndreas Gruenbacher isec = inode_security_rcu(inode, flags & MAY_NOT_BLOCK); 31355d226df4SAndreas Gruenbacher if (IS_ERR(isec)) 31365d226df4SAndreas Gruenbacher return PTR_ERR(isec); 31372e334057SEric Paris 31386b6bc620SStephen Smalley rc = avc_has_perm_noaudit(&selinux_state, 31396b6bc620SStephen Smalley sid, isec->sid, isec->sclass, perms, 0, &avd); 31402e334057SEric Paris audited = avc_audit_required(perms, &avd, rc, 31412e334057SEric Paris from_access ? FILE__AUDIT_ACCESS : 0, 31422e334057SEric Paris &denied); 31432e334057SEric Paris if (likely(!audited)) 31442e334057SEric Paris return rc; 31452e334057SEric Paris 3146626b9740SStephen Smalley rc2 = audit_inode_permission(inode, perms, audited, denied, rc, flags); 31472e334057SEric Paris if (rc2) 31482e334057SEric Paris return rc2; 31492e334057SEric Paris return rc; 31501da177e4SLinus Torvalds } 31511da177e4SLinus Torvalds 31521da177e4SLinus Torvalds static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) 31531da177e4SLinus Torvalds { 315488e67f3bSDavid Howells const struct cred *cred = current_cred(); 3155ccb54478SStephen Smalley struct inode *inode = d_backing_inode(dentry); 3156bc6a6008SAmerigo Wang unsigned int ia_valid = iattr->ia_valid; 315795dbf739SEric Paris __u32 av = FILE__WRITE; 31581da177e4SLinus Torvalds 3159bc6a6008SAmerigo Wang /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ 3160bc6a6008SAmerigo Wang if (ia_valid & ATTR_FORCE) { 3161bc6a6008SAmerigo Wang ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE | 3162bc6a6008SAmerigo Wang ATTR_FORCE); 3163bc6a6008SAmerigo Wang if (!ia_valid) 31641da177e4SLinus Torvalds return 0; 3165bc6a6008SAmerigo Wang } 31661da177e4SLinus Torvalds 3167bc6a6008SAmerigo Wang if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | 3168bc6a6008SAmerigo Wang ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) 31692875fa00SEric Paris return dentry_has_perm(cred, dentry, FILE__SETATTR); 31701da177e4SLinus Torvalds 3171aa8e712cSStephen Smalley if (selinux_policycap_openperm() && 3172ccb54478SStephen Smalley inode->i_sb->s_magic != SOCKFS_MAGIC && 3173ccb54478SStephen Smalley (ia_valid & ATTR_SIZE) && 3174ccb54478SStephen Smalley !(ia_valid & ATTR_FILE)) 317595dbf739SEric Paris av |= FILE__OPEN; 317695dbf739SEric Paris 317795dbf739SEric Paris return dentry_has_perm(cred, dentry, av); 31781da177e4SLinus Torvalds } 31791da177e4SLinus Torvalds 31803f7036a0SAl Viro static int selinux_inode_getattr(const struct path *path) 31811da177e4SLinus Torvalds { 31823f7036a0SAl Viro return path_has_perm(current_cred(), path, FILE__GETATTR); 31831da177e4SLinus Torvalds } 31841da177e4SLinus Torvalds 3185db59000aSStephen Smalley static bool has_cap_mac_admin(bool audit) 3186db59000aSStephen Smalley { 3187db59000aSStephen Smalley const struct cred *cred = current_cred(); 3188db59000aSStephen Smalley int cap_audit = audit ? SECURITY_CAP_AUDIT : SECURITY_CAP_NOAUDIT; 3189db59000aSStephen Smalley 3190db59000aSStephen Smalley if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, cap_audit)) 3191db59000aSStephen Smalley return false; 3192db59000aSStephen Smalley if (cred_has_capability(cred, CAP_MAC_ADMIN, cap_audit, true)) 3193db59000aSStephen Smalley return false; 3194db59000aSStephen Smalley return true; 3195db59000aSStephen Smalley } 3196db59000aSStephen Smalley 31978f0cfa52SDavid Howells static int selinux_inode_setxattr(struct dentry *dentry, const char *name, 31988f0cfa52SDavid Howells const void *value, size_t size, int flags) 31991da177e4SLinus Torvalds { 3200c6f493d6SDavid Howells struct inode *inode = d_backing_inode(dentry); 320120cdef8dSPaul Moore struct inode_security_struct *isec; 32021da177e4SLinus Torvalds struct superblock_security_struct *sbsec; 32032bf49690SThomas Liu struct common_audit_data ad; 3204275bb41eSDavid Howells u32 newsid, sid = current_sid(); 32051da177e4SLinus Torvalds int rc = 0; 32061da177e4SLinus Torvalds 32076b240306SEric W. Biederman if (strcmp(name, XATTR_NAME_SELINUX)) { 32086b240306SEric W. Biederman rc = cap_inode_setxattr(dentry, name, value, size, flags); 32096b240306SEric W. Biederman if (rc) 32106b240306SEric W. Biederman return rc; 32116b240306SEric W. Biederman 32126b240306SEric W. Biederman /* Not an attribute we recognize, so just check the 32136b240306SEric W. Biederman ordinary setattr permission. */ 32146b240306SEric W. Biederman return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); 32156b240306SEric W. Biederman } 32161da177e4SLinus Torvalds 32171da177e4SLinus Torvalds sbsec = inode->i_sb->s_security; 321812f348b9SEric Paris if (!(sbsec->flags & SBLABEL_MNT)) 32191da177e4SLinus Torvalds return -EOPNOTSUPP; 32201da177e4SLinus Torvalds 32212e149670SSerge E. Hallyn if (!inode_owner_or_capable(inode)) 32221da177e4SLinus Torvalds return -EPERM; 32231da177e4SLinus Torvalds 322450c205f5SEric Paris ad.type = LSM_AUDIT_DATA_DENTRY; 3225a269434dSEric Paris ad.u.dentry = dentry; 32261da177e4SLinus Torvalds 322720cdef8dSPaul Moore isec = backing_inode_security(dentry); 32286b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 32296b6bc620SStephen Smalley sid, isec->sid, isec->sclass, 32301da177e4SLinus Torvalds FILE__RELABELFROM, &ad); 32311da177e4SLinus Torvalds if (rc) 32321da177e4SLinus Torvalds return rc; 32331da177e4SLinus Torvalds 3234aa8e712cSStephen Smalley rc = security_context_to_sid(&selinux_state, value, size, &newsid, 3235aa8e712cSStephen Smalley GFP_KERNEL); 323612b29f34SStephen Smalley if (rc == -EINVAL) { 3237db59000aSStephen Smalley if (!has_cap_mac_admin(true)) { 3238d6ea83ecSEric Paris struct audit_buffer *ab; 3239d6ea83ecSEric Paris size_t audit_size; 3240d6ea83ecSEric Paris 3241d6ea83ecSEric Paris /* We strip a nul only if it is at the end, otherwise the 3242d6ea83ecSEric Paris * context contains a nul and we should audit that */ 3243e3fea3f7SAl Viro if (value) { 3244add24372SColin Ian King const char *str = value; 3245add24372SColin Ian King 3246d6ea83ecSEric Paris if (str[size - 1] == '\0') 3247d6ea83ecSEric Paris audit_size = size - 1; 3248d6ea83ecSEric Paris else 3249d6ea83ecSEric Paris audit_size = size; 3250e3fea3f7SAl Viro } else { 3251e3fea3f7SAl Viro audit_size = 0; 3252e3fea3f7SAl Viro } 3253cdfb6b34SRichard Guy Briggs ab = audit_log_start(audit_context(), 3254cdfb6b34SRichard Guy Briggs GFP_ATOMIC, AUDIT_SELINUX_ERR); 3255d6ea83ecSEric Paris audit_log_format(ab, "op=setxattr invalid_context="); 3256d6ea83ecSEric Paris audit_log_n_untrustedstring(ab, value, audit_size); 3257d6ea83ecSEric Paris audit_log_end(ab); 3258d6ea83ecSEric Paris 325912b29f34SStephen Smalley return rc; 3260d6ea83ecSEric Paris } 3261aa8e712cSStephen Smalley rc = security_context_to_sid_force(&selinux_state, value, 3262aa8e712cSStephen Smalley size, &newsid); 326312b29f34SStephen Smalley } 32641da177e4SLinus Torvalds if (rc) 32651da177e4SLinus Torvalds return rc; 32661da177e4SLinus Torvalds 32676b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 32686b6bc620SStephen Smalley sid, newsid, isec->sclass, 32691da177e4SLinus Torvalds FILE__RELABELTO, &ad); 32701da177e4SLinus Torvalds if (rc) 32711da177e4SLinus Torvalds return rc; 32721da177e4SLinus Torvalds 3273aa8e712cSStephen Smalley rc = security_validate_transition(&selinux_state, isec->sid, newsid, 3274aa8e712cSStephen Smalley sid, isec->sclass); 32751da177e4SLinus Torvalds if (rc) 32761da177e4SLinus Torvalds return rc; 32771da177e4SLinus Torvalds 32786b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 32796b6bc620SStephen Smalley newsid, 32801da177e4SLinus Torvalds sbsec->sid, 32811da177e4SLinus Torvalds SECCLASS_FILESYSTEM, 32821da177e4SLinus Torvalds FILESYSTEM__ASSOCIATE, 32831da177e4SLinus Torvalds &ad); 32841da177e4SLinus Torvalds } 32851da177e4SLinus Torvalds 32868f0cfa52SDavid Howells static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, 32878f0cfa52SDavid Howells const void *value, size_t size, 32888f0cfa52SDavid Howells int flags) 32891da177e4SLinus Torvalds { 3290c6f493d6SDavid Howells struct inode *inode = d_backing_inode(dentry); 329120cdef8dSPaul Moore struct inode_security_struct *isec; 32921da177e4SLinus Torvalds u32 newsid; 32931da177e4SLinus Torvalds int rc; 32941da177e4SLinus Torvalds 32951da177e4SLinus Torvalds if (strcmp(name, XATTR_NAME_SELINUX)) { 32961da177e4SLinus Torvalds /* Not an attribute we recognize, so nothing to do. */ 32971da177e4SLinus Torvalds return; 32981da177e4SLinus Torvalds } 32991da177e4SLinus Torvalds 3300aa8e712cSStephen Smalley rc = security_context_to_sid_force(&selinux_state, value, size, 3301aa8e712cSStephen Smalley &newsid); 33021da177e4SLinus Torvalds if (rc) { 3303c103a91eSpeter enderborg pr_err("SELinux: unable to map context to SID" 330412b29f34SStephen Smalley "for (%s, %lu), rc=%d\n", 330512b29f34SStephen Smalley inode->i_sb->s_id, inode->i_ino, -rc); 33061da177e4SLinus Torvalds return; 33071da177e4SLinus Torvalds } 33081da177e4SLinus Torvalds 330920cdef8dSPaul Moore isec = backing_inode_security(dentry); 33109287aed2SAndreas Gruenbacher spin_lock(&isec->lock); 3311aa9c2669SDavid Quigley isec->sclass = inode_mode_to_security_class(inode->i_mode); 33121da177e4SLinus Torvalds isec->sid = newsid; 33136f3be9f5SAndreas Gruenbacher isec->initialized = LABEL_INITIALIZED; 33149287aed2SAndreas Gruenbacher spin_unlock(&isec->lock); 3315aa9c2669SDavid Quigley 33161da177e4SLinus Torvalds return; 33171da177e4SLinus Torvalds } 33181da177e4SLinus Torvalds 33198f0cfa52SDavid Howells static int selinux_inode_getxattr(struct dentry *dentry, const char *name) 33201da177e4SLinus Torvalds { 332188e67f3bSDavid Howells const struct cred *cred = current_cred(); 332288e67f3bSDavid Howells 33232875fa00SEric Paris return dentry_has_perm(cred, dentry, FILE__GETATTR); 33241da177e4SLinus Torvalds } 33251da177e4SLinus Torvalds 33261da177e4SLinus Torvalds static int selinux_inode_listxattr(struct dentry *dentry) 33271da177e4SLinus Torvalds { 332888e67f3bSDavid Howells const struct cred *cred = current_cred(); 332988e67f3bSDavid Howells 33302875fa00SEric Paris return dentry_has_perm(cred, dentry, FILE__GETATTR); 33311da177e4SLinus Torvalds } 33321da177e4SLinus Torvalds 33338f0cfa52SDavid Howells static int selinux_inode_removexattr(struct dentry *dentry, const char *name) 33341da177e4SLinus Torvalds { 33356b240306SEric W. Biederman if (strcmp(name, XATTR_NAME_SELINUX)) { 33366b240306SEric W. Biederman int rc = cap_inode_removexattr(dentry, name); 33376b240306SEric W. Biederman if (rc) 33386b240306SEric W. Biederman return rc; 33396b240306SEric W. Biederman 33406b240306SEric W. Biederman /* Not an attribute we recognize, so just check the 33416b240306SEric W. Biederman ordinary setattr permission. */ 33426b240306SEric W. Biederman return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); 33436b240306SEric W. Biederman } 33441da177e4SLinus Torvalds 33451da177e4SLinus Torvalds /* No one is allowed to remove a SELinux security label. 33461da177e4SLinus Torvalds You can change the label, but all data must be labeled. */ 33471da177e4SLinus Torvalds return -EACCES; 33481da177e4SLinus Torvalds } 33491da177e4SLinus Torvalds 3350d381d8a9SJames Morris /* 3351abc69bb6SStephen Smalley * Copy the inode security context value to the user. 3352d381d8a9SJames Morris * 3353d381d8a9SJames Morris * Permission check is handled by selinux_inode_getxattr hook. 3354d381d8a9SJames Morris */ 3355ea861dfdSAndreas Gruenbacher static int selinux_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc) 33561da177e4SLinus Torvalds { 335742492594SDavid P. Quigley u32 size; 335842492594SDavid P. Quigley int error; 335942492594SDavid P. Quigley char *context = NULL; 336020cdef8dSPaul Moore struct inode_security_struct *isec; 33611da177e4SLinus Torvalds 33628c8570fbSDustin Kirkland if (strcmp(name, XATTR_SELINUX_SUFFIX)) 33638c8570fbSDustin Kirkland return -EOPNOTSUPP; 33641da177e4SLinus Torvalds 3365abc69bb6SStephen Smalley /* 3366abc69bb6SStephen Smalley * If the caller has CAP_MAC_ADMIN, then get the raw context 3367abc69bb6SStephen Smalley * value even if it is not defined by current policy; otherwise, 3368abc69bb6SStephen Smalley * use the in-core value under current policy. 3369abc69bb6SStephen Smalley * Use the non-auditing forms of the permission checks since 3370abc69bb6SStephen Smalley * getxattr may be called by unprivileged processes commonly 3371abc69bb6SStephen Smalley * and lack of permission just means that we fall back to the 3372abc69bb6SStephen Smalley * in-core context value, not a denial. 3373abc69bb6SStephen Smalley */ 337420cdef8dSPaul Moore isec = inode_security(inode); 3375db59000aSStephen Smalley if (has_cap_mac_admin(false)) 3376aa8e712cSStephen Smalley error = security_sid_to_context_force(&selinux_state, 3377aa8e712cSStephen Smalley isec->sid, &context, 3378abc69bb6SStephen Smalley &size); 3379abc69bb6SStephen Smalley else 3380aa8e712cSStephen Smalley error = security_sid_to_context(&selinux_state, isec->sid, 3381aa8e712cSStephen Smalley &context, &size); 338242492594SDavid P. Quigley if (error) 338342492594SDavid P. Quigley return error; 338442492594SDavid P. Quigley error = size; 338542492594SDavid P. Quigley if (alloc) { 338642492594SDavid P. Quigley *buffer = context; 338742492594SDavid P. Quigley goto out_nofree; 338842492594SDavid P. Quigley } 338942492594SDavid P. Quigley kfree(context); 339042492594SDavid P. Quigley out_nofree: 339142492594SDavid P. Quigley return error; 33921da177e4SLinus Torvalds } 33931da177e4SLinus Torvalds 33941da177e4SLinus Torvalds static int selinux_inode_setsecurity(struct inode *inode, const char *name, 33951da177e4SLinus Torvalds const void *value, size_t size, int flags) 33961da177e4SLinus Torvalds { 33972c97165bSPaul Moore struct inode_security_struct *isec = inode_security_novalidate(inode); 33981da177e4SLinus Torvalds u32 newsid; 33991da177e4SLinus Torvalds int rc; 34001da177e4SLinus Torvalds 34011da177e4SLinus Torvalds if (strcmp(name, XATTR_SELINUX_SUFFIX)) 34021da177e4SLinus Torvalds return -EOPNOTSUPP; 34031da177e4SLinus Torvalds 34041da177e4SLinus Torvalds if (!value || !size) 34051da177e4SLinus Torvalds return -EACCES; 34061da177e4SLinus Torvalds 3407aa8e712cSStephen Smalley rc = security_context_to_sid(&selinux_state, value, size, &newsid, 3408aa8e712cSStephen Smalley GFP_KERNEL); 34091da177e4SLinus Torvalds if (rc) 34101da177e4SLinus Torvalds return rc; 34111da177e4SLinus Torvalds 34129287aed2SAndreas Gruenbacher spin_lock(&isec->lock); 3413aa9c2669SDavid Quigley isec->sclass = inode_mode_to_security_class(inode->i_mode); 34141da177e4SLinus Torvalds isec->sid = newsid; 34156f3be9f5SAndreas Gruenbacher isec->initialized = LABEL_INITIALIZED; 34169287aed2SAndreas Gruenbacher spin_unlock(&isec->lock); 34171da177e4SLinus Torvalds return 0; 34181da177e4SLinus Torvalds } 34191da177e4SLinus Torvalds 34201da177e4SLinus Torvalds static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size) 34211da177e4SLinus Torvalds { 34221da177e4SLinus Torvalds const int len = sizeof(XATTR_NAME_SELINUX); 34231da177e4SLinus Torvalds if (buffer && len <= buffer_size) 34241da177e4SLinus Torvalds memcpy(buffer, XATTR_NAME_SELINUX, len); 34251da177e4SLinus Torvalds return len; 34261da177e4SLinus Torvalds } 34271da177e4SLinus Torvalds 3428d6335d77SAndreas Gruenbacher static void selinux_inode_getsecid(struct inode *inode, u32 *secid) 3429713a04aeSAhmed S. Darwish { 3430e817c2f3SAndreas Gruenbacher struct inode_security_struct *isec = inode_security_novalidate(inode); 3431713a04aeSAhmed S. Darwish *secid = isec->sid; 3432713a04aeSAhmed S. Darwish } 3433713a04aeSAhmed S. Darwish 343456909eb3SVivek Goyal static int selinux_inode_copy_up(struct dentry *src, struct cred **new) 343556909eb3SVivek Goyal { 343656909eb3SVivek Goyal u32 sid; 343756909eb3SVivek Goyal struct task_security_struct *tsec; 343856909eb3SVivek Goyal struct cred *new_creds = *new; 343956909eb3SVivek Goyal 344056909eb3SVivek Goyal if (new_creds == NULL) { 344156909eb3SVivek Goyal new_creds = prepare_creds(); 344256909eb3SVivek Goyal if (!new_creds) 344356909eb3SVivek Goyal return -ENOMEM; 344456909eb3SVivek Goyal } 344556909eb3SVivek Goyal 344656909eb3SVivek Goyal tsec = new_creds->security; 344756909eb3SVivek Goyal /* Get label from overlay inode and set it in create_sid */ 344856909eb3SVivek Goyal selinux_inode_getsecid(d_inode(src), &sid); 344956909eb3SVivek Goyal tsec->create_sid = sid; 345056909eb3SVivek Goyal *new = new_creds; 345156909eb3SVivek Goyal return 0; 345256909eb3SVivek Goyal } 345356909eb3SVivek Goyal 345419472b69SVivek Goyal static int selinux_inode_copy_up_xattr(const char *name) 345519472b69SVivek Goyal { 345619472b69SVivek Goyal /* The copy_up hook above sets the initial context on an inode, but we 345719472b69SVivek Goyal * don't then want to overwrite it by blindly copying all the lower 345819472b69SVivek Goyal * xattrs up. Instead, we have to filter out SELinux-related xattrs. 345919472b69SVivek Goyal */ 346019472b69SVivek Goyal if (strcmp(name, XATTR_NAME_SELINUX) == 0) 346119472b69SVivek Goyal return 1; /* Discard */ 346219472b69SVivek Goyal /* 346319472b69SVivek Goyal * Any other attribute apart from SELINUX is not claimed, supported 346419472b69SVivek Goyal * by selinux. 346519472b69SVivek Goyal */ 346619472b69SVivek Goyal return -EOPNOTSUPP; 346719472b69SVivek Goyal } 346819472b69SVivek Goyal 34691da177e4SLinus Torvalds /* file security operations */ 34701da177e4SLinus Torvalds 3471788e7dd4SYuichi Nakamura static int selinux_revalidate_file_permission(struct file *file, int mask) 34721da177e4SLinus Torvalds { 347388e67f3bSDavid Howells const struct cred *cred = current_cred(); 3474496ad9aaSAl Viro struct inode *inode = file_inode(file); 34751da177e4SLinus Torvalds 34761da177e4SLinus Torvalds /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */ 34771da177e4SLinus Torvalds if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) 34781da177e4SLinus Torvalds mask |= MAY_APPEND; 34791da177e4SLinus Torvalds 3480389fb800SPaul Moore return file_has_perm(cred, file, 34811da177e4SLinus Torvalds file_mask_to_av(inode->i_mode, mask)); 34821da177e4SLinus Torvalds } 34831da177e4SLinus Torvalds 3484788e7dd4SYuichi Nakamura static int selinux_file_permission(struct file *file, int mask) 3485788e7dd4SYuichi Nakamura { 3486496ad9aaSAl Viro struct inode *inode = file_inode(file); 348720dda18bSStephen Smalley struct file_security_struct *fsec = file->f_security; 3488b197367eSAndreas Gruenbacher struct inode_security_struct *isec; 348920dda18bSStephen Smalley u32 sid = current_sid(); 349020dda18bSStephen Smalley 3491389fb800SPaul Moore if (!mask) 3492788e7dd4SYuichi Nakamura /* No permission to check. Existence test. */ 3493788e7dd4SYuichi Nakamura return 0; 3494788e7dd4SYuichi Nakamura 3495b197367eSAndreas Gruenbacher isec = inode_security(inode); 349620dda18bSStephen Smalley if (sid == fsec->sid && fsec->isid == isec->sid && 34976b6bc620SStephen Smalley fsec->pseqno == avc_policy_seqno(&selinux_state)) 349883d49856SEric Paris /* No change since file_open check. */ 349920dda18bSStephen Smalley return 0; 350020dda18bSStephen Smalley 3501788e7dd4SYuichi Nakamura return selinux_revalidate_file_permission(file, mask); 3502788e7dd4SYuichi Nakamura } 3503788e7dd4SYuichi Nakamura 35041da177e4SLinus Torvalds static int selinux_file_alloc_security(struct file *file) 35051da177e4SLinus Torvalds { 35061da177e4SLinus Torvalds return file_alloc_security(file); 35071da177e4SLinus Torvalds } 35081da177e4SLinus Torvalds 35091da177e4SLinus Torvalds static void selinux_file_free_security(struct file *file) 35101da177e4SLinus Torvalds { 35111da177e4SLinus Torvalds file_free_security(file); 35121da177e4SLinus Torvalds } 35131da177e4SLinus Torvalds 3514fa1aa143SJeff Vander Stoep /* 3515fa1aa143SJeff Vander Stoep * Check whether a task has the ioctl permission and cmd 3516fa1aa143SJeff Vander Stoep * operation to an inode. 3517fa1aa143SJeff Vander Stoep */ 35181d2a168aSGeliang Tang static int ioctl_has_perm(const struct cred *cred, struct file *file, 3519fa1aa143SJeff Vander Stoep u32 requested, u16 cmd) 3520fa1aa143SJeff Vander Stoep { 3521fa1aa143SJeff Vander Stoep struct common_audit_data ad; 3522fa1aa143SJeff Vander Stoep struct file_security_struct *fsec = file->f_security; 3523fa1aa143SJeff Vander Stoep struct inode *inode = file_inode(file); 352420cdef8dSPaul Moore struct inode_security_struct *isec; 3525fa1aa143SJeff Vander Stoep struct lsm_ioctlop_audit ioctl; 3526fa1aa143SJeff Vander Stoep u32 ssid = cred_sid(cred); 3527fa1aa143SJeff Vander Stoep int rc; 3528fa1aa143SJeff Vander Stoep u8 driver = cmd >> 8; 3529fa1aa143SJeff Vander Stoep u8 xperm = cmd & 0xff; 3530fa1aa143SJeff Vander Stoep 3531fa1aa143SJeff Vander Stoep ad.type = LSM_AUDIT_DATA_IOCTL_OP; 3532fa1aa143SJeff Vander Stoep ad.u.op = &ioctl; 3533fa1aa143SJeff Vander Stoep ad.u.op->cmd = cmd; 3534fa1aa143SJeff Vander Stoep ad.u.op->path = file->f_path; 3535fa1aa143SJeff Vander Stoep 3536fa1aa143SJeff Vander Stoep if (ssid != fsec->sid) { 35376b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 35386b6bc620SStephen Smalley ssid, fsec->sid, 3539fa1aa143SJeff Vander Stoep SECCLASS_FD, 3540fa1aa143SJeff Vander Stoep FD__USE, 3541fa1aa143SJeff Vander Stoep &ad); 3542fa1aa143SJeff Vander Stoep if (rc) 3543fa1aa143SJeff Vander Stoep goto out; 3544fa1aa143SJeff Vander Stoep } 3545fa1aa143SJeff Vander Stoep 3546fa1aa143SJeff Vander Stoep if (unlikely(IS_PRIVATE(inode))) 3547fa1aa143SJeff Vander Stoep return 0; 3548fa1aa143SJeff Vander Stoep 354920cdef8dSPaul Moore isec = inode_security(inode); 35506b6bc620SStephen Smalley rc = avc_has_extended_perms(&selinux_state, 35516b6bc620SStephen Smalley ssid, isec->sid, isec->sclass, 3552fa1aa143SJeff Vander Stoep requested, driver, xperm, &ad); 3553fa1aa143SJeff Vander Stoep out: 3554fa1aa143SJeff Vander Stoep return rc; 3555fa1aa143SJeff Vander Stoep } 3556fa1aa143SJeff Vander Stoep 35571da177e4SLinus Torvalds static int selinux_file_ioctl(struct file *file, unsigned int cmd, 35581da177e4SLinus Torvalds unsigned long arg) 35591da177e4SLinus Torvalds { 356088e67f3bSDavid Howells const struct cred *cred = current_cred(); 35610b24dcb7SEric Paris int error = 0; 35621da177e4SLinus Torvalds 35630b24dcb7SEric Paris switch (cmd) { 35640b24dcb7SEric Paris case FIONREAD: 35650b24dcb7SEric Paris /* fall through */ 35660b24dcb7SEric Paris case FIBMAP: 35670b24dcb7SEric Paris /* fall through */ 35680b24dcb7SEric Paris case FIGETBSZ: 35690b24dcb7SEric Paris /* fall through */ 35702f99c369SAl Viro case FS_IOC_GETFLAGS: 35710b24dcb7SEric Paris /* fall through */ 35722f99c369SAl Viro case FS_IOC_GETVERSION: 35730b24dcb7SEric Paris error = file_has_perm(cred, file, FILE__GETATTR); 35740b24dcb7SEric Paris break; 35751da177e4SLinus Torvalds 35762f99c369SAl Viro case FS_IOC_SETFLAGS: 35770b24dcb7SEric Paris /* fall through */ 35782f99c369SAl Viro case FS_IOC_SETVERSION: 35790b24dcb7SEric Paris error = file_has_perm(cred, file, FILE__SETATTR); 35800b24dcb7SEric Paris break; 35810b24dcb7SEric Paris 35820b24dcb7SEric Paris /* sys_ioctl() checks */ 35830b24dcb7SEric Paris case FIONBIO: 35840b24dcb7SEric Paris /* fall through */ 35850b24dcb7SEric Paris case FIOASYNC: 35860b24dcb7SEric Paris error = file_has_perm(cred, file, 0); 35870b24dcb7SEric Paris break; 35880b24dcb7SEric Paris 35890b24dcb7SEric Paris case KDSKBENT: 35900b24dcb7SEric Paris case KDSKBSENT: 35916a9de491SEric Paris error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, 35928e4ff6f2SStephen Smalley SECURITY_CAP_AUDIT, true); 35930b24dcb7SEric Paris break; 35940b24dcb7SEric Paris 35950b24dcb7SEric Paris /* default case assumes that the command will go 35960b24dcb7SEric Paris * to the file's ioctl() function. 35970b24dcb7SEric Paris */ 35980b24dcb7SEric Paris default: 3599fa1aa143SJeff Vander Stoep error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); 36000b24dcb7SEric Paris } 36010b24dcb7SEric Paris return error; 36021da177e4SLinus Torvalds } 36031da177e4SLinus Torvalds 3604fcaaade1SStephen Smalley static int default_noexec; 3605fcaaade1SStephen Smalley 36061da177e4SLinus Torvalds static int file_map_prot_check(struct file *file, unsigned long prot, int shared) 36071da177e4SLinus Torvalds { 360888e67f3bSDavid Howells const struct cred *cred = current_cred(); 3609be0554c9SStephen Smalley u32 sid = cred_sid(cred); 3610d84f4f99SDavid Howells int rc = 0; 361188e67f3bSDavid Howells 3612fcaaade1SStephen Smalley if (default_noexec && 3613892e8cacSStephen Smalley (prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) || 3614892e8cacSStephen Smalley (!shared && (prot & PROT_WRITE)))) { 36151da177e4SLinus Torvalds /* 36161da177e4SLinus Torvalds * We are making executable an anonymous mapping or a 36171da177e4SLinus Torvalds * private file mapping that will also be writable. 36181da177e4SLinus Torvalds * This has an additional check. 36191da177e4SLinus Torvalds */ 36206b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 36216b6bc620SStephen Smalley sid, sid, SECCLASS_PROCESS, 3622be0554c9SStephen Smalley PROCESS__EXECMEM, NULL); 36231da177e4SLinus Torvalds if (rc) 3624d84f4f99SDavid Howells goto error; 36251da177e4SLinus Torvalds } 36261da177e4SLinus Torvalds 36271da177e4SLinus Torvalds if (file) { 36281da177e4SLinus Torvalds /* read access is always possible with a mapping */ 36291da177e4SLinus Torvalds u32 av = FILE__READ; 36301da177e4SLinus Torvalds 36311da177e4SLinus Torvalds /* write access only matters if the mapping is shared */ 36321da177e4SLinus Torvalds if (shared && (prot & PROT_WRITE)) 36331da177e4SLinus Torvalds av |= FILE__WRITE; 36341da177e4SLinus Torvalds 36351da177e4SLinus Torvalds if (prot & PROT_EXEC) 36361da177e4SLinus Torvalds av |= FILE__EXECUTE; 36371da177e4SLinus Torvalds 363888e67f3bSDavid Howells return file_has_perm(cred, file, av); 36391da177e4SLinus Torvalds } 3640d84f4f99SDavid Howells 3641d84f4f99SDavid Howells error: 3642d84f4f99SDavid Howells return rc; 36431da177e4SLinus Torvalds } 36441da177e4SLinus Torvalds 3645e5467859SAl Viro static int selinux_mmap_addr(unsigned long addr) 36461da177e4SLinus Torvalds { 3647b1d9e6b0SCasey Schaufler int rc = 0; 364898883bfdSPaul Moore 364998883bfdSPaul Moore if (addr < CONFIG_LSM_MMAP_MIN_ADDR) { 365098883bfdSPaul Moore u32 sid = current_sid(); 36516b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 36526b6bc620SStephen Smalley sid, sid, SECCLASS_MEMPROTECT, 365398883bfdSPaul Moore MEMPROTECT__MMAP_ZERO, NULL); 365498883bfdSPaul Moore } 365598883bfdSPaul Moore 365698883bfdSPaul Moore return rc; 3657e5467859SAl Viro } 36581da177e4SLinus Torvalds 3659e5467859SAl Viro static int selinux_mmap_file(struct file *file, unsigned long reqprot, 3660e5467859SAl Viro unsigned long prot, unsigned long flags) 3661e5467859SAl Viro { 36623ba4bf5fSStephen Smalley struct common_audit_data ad; 36633ba4bf5fSStephen Smalley int rc; 36643ba4bf5fSStephen Smalley 36653ba4bf5fSStephen Smalley if (file) { 36663ba4bf5fSStephen Smalley ad.type = LSM_AUDIT_DATA_FILE; 36673ba4bf5fSStephen Smalley ad.u.file = file; 36683ba4bf5fSStephen Smalley rc = inode_has_perm(current_cred(), file_inode(file), 36693ba4bf5fSStephen Smalley FILE__MAP, &ad); 36703ba4bf5fSStephen Smalley if (rc) 36713ba4bf5fSStephen Smalley return rc; 36723ba4bf5fSStephen Smalley } 36733ba4bf5fSStephen Smalley 3674aa8e712cSStephen Smalley if (selinux_state.checkreqprot) 36751da177e4SLinus Torvalds prot = reqprot; 36761da177e4SLinus Torvalds 36771da177e4SLinus Torvalds return file_map_prot_check(file, prot, 36781da177e4SLinus Torvalds (flags & MAP_TYPE) == MAP_SHARED); 36791da177e4SLinus Torvalds } 36801da177e4SLinus Torvalds 36811da177e4SLinus Torvalds static int selinux_file_mprotect(struct vm_area_struct *vma, 36821da177e4SLinus Torvalds unsigned long reqprot, 36831da177e4SLinus Torvalds unsigned long prot) 36841da177e4SLinus Torvalds { 368588e67f3bSDavid Howells const struct cred *cred = current_cred(); 3686be0554c9SStephen Smalley u32 sid = cred_sid(cred); 36871da177e4SLinus Torvalds 3688aa8e712cSStephen Smalley if (selinux_state.checkreqprot) 36891da177e4SLinus Torvalds prot = reqprot; 36901da177e4SLinus Torvalds 3691fcaaade1SStephen Smalley if (default_noexec && 3692fcaaade1SStephen Smalley (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { 3693d541bbeeSJames Morris int rc = 0; 3694db4c9641SStephen Smalley if (vma->vm_start >= vma->vm_mm->start_brk && 3695db4c9641SStephen Smalley vma->vm_end <= vma->vm_mm->brk) { 36966b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 36976b6bc620SStephen Smalley sid, sid, SECCLASS_PROCESS, 3698be0554c9SStephen Smalley PROCESS__EXECHEAP, NULL); 3699db4c9641SStephen Smalley } else if (!vma->vm_file && 3700c2316dbfSStephen Smalley ((vma->vm_start <= vma->vm_mm->start_stack && 3701c2316dbfSStephen Smalley vma->vm_end >= vma->vm_mm->start_stack) || 3702d17af505SAndy Lutomirski vma_is_stack_for_current(vma))) { 37036b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 37046b6bc620SStephen Smalley sid, sid, SECCLASS_PROCESS, 3705be0554c9SStephen Smalley PROCESS__EXECSTACK, NULL); 3706db4c9641SStephen Smalley } else if (vma->vm_file && vma->anon_vma) { 3707db4c9641SStephen Smalley /* 3708db4c9641SStephen Smalley * We are making executable a file mapping that has 3709db4c9641SStephen Smalley * had some COW done. Since pages might have been 3710db4c9641SStephen Smalley * written, check ability to execute the possibly 3711db4c9641SStephen Smalley * modified content. This typically should only 3712db4c9641SStephen Smalley * occur for text relocations. 3713db4c9641SStephen Smalley */ 3714d84f4f99SDavid Howells rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD); 3715db4c9641SStephen Smalley } 37166b992197SLorenzo Hernandez García-Hierro if (rc) 37176b992197SLorenzo Hernandez García-Hierro return rc; 37186b992197SLorenzo Hernandez García-Hierro } 37191da177e4SLinus Torvalds 37201da177e4SLinus Torvalds return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); 37211da177e4SLinus Torvalds } 37221da177e4SLinus Torvalds 37231da177e4SLinus Torvalds static int selinux_file_lock(struct file *file, unsigned int cmd) 37241da177e4SLinus Torvalds { 372588e67f3bSDavid Howells const struct cred *cred = current_cred(); 372688e67f3bSDavid Howells 372788e67f3bSDavid Howells return file_has_perm(cred, file, FILE__LOCK); 37281da177e4SLinus Torvalds } 37291da177e4SLinus Torvalds 37301da177e4SLinus Torvalds static int selinux_file_fcntl(struct file *file, unsigned int cmd, 37311da177e4SLinus Torvalds unsigned long arg) 37321da177e4SLinus Torvalds { 373388e67f3bSDavid Howells const struct cred *cred = current_cred(); 37341da177e4SLinus Torvalds int err = 0; 37351da177e4SLinus Torvalds 37361da177e4SLinus Torvalds switch (cmd) { 37371da177e4SLinus Torvalds case F_SETFL: 37381da177e4SLinus Torvalds if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) { 373988e67f3bSDavid Howells err = file_has_perm(cred, file, FILE__WRITE); 37401da177e4SLinus Torvalds break; 37411da177e4SLinus Torvalds } 37421da177e4SLinus Torvalds /* fall through */ 37431da177e4SLinus Torvalds case F_SETOWN: 37441da177e4SLinus Torvalds case F_SETSIG: 37451da177e4SLinus Torvalds case F_GETFL: 37461da177e4SLinus Torvalds case F_GETOWN: 37471da177e4SLinus Torvalds case F_GETSIG: 37481d151c33SCyrill Gorcunov case F_GETOWNER_UIDS: 37491da177e4SLinus Torvalds /* Just check FD__USE permission */ 375088e67f3bSDavid Howells err = file_has_perm(cred, file, 0); 37511da177e4SLinus Torvalds break; 37521da177e4SLinus Torvalds case F_GETLK: 37531da177e4SLinus Torvalds case F_SETLK: 37541da177e4SLinus Torvalds case F_SETLKW: 37550d3f7a2dSJeff Layton case F_OFD_GETLK: 37560d3f7a2dSJeff Layton case F_OFD_SETLK: 37570d3f7a2dSJeff Layton case F_OFD_SETLKW: 37581da177e4SLinus Torvalds #if BITS_PER_LONG == 32 37591da177e4SLinus Torvalds case F_GETLK64: 37601da177e4SLinus Torvalds case F_SETLK64: 37611da177e4SLinus Torvalds case F_SETLKW64: 37621da177e4SLinus Torvalds #endif 376388e67f3bSDavid Howells err = file_has_perm(cred, file, FILE__LOCK); 37641da177e4SLinus Torvalds break; 37651da177e4SLinus Torvalds } 37661da177e4SLinus Torvalds 37671da177e4SLinus Torvalds return err; 37681da177e4SLinus Torvalds } 37691da177e4SLinus Torvalds 3770e0b93eddSJeff Layton static void selinux_file_set_fowner(struct file *file) 37711da177e4SLinus Torvalds { 37721da177e4SLinus Torvalds struct file_security_struct *fsec; 37731da177e4SLinus Torvalds 37741da177e4SLinus Torvalds fsec = file->f_security; 3775275bb41eSDavid Howells fsec->fown_sid = current_sid(); 37761da177e4SLinus Torvalds } 37771da177e4SLinus Torvalds 37781da177e4SLinus Torvalds static int selinux_file_send_sigiotask(struct task_struct *tsk, 37791da177e4SLinus Torvalds struct fown_struct *fown, int signum) 37801da177e4SLinus Torvalds { 37811da177e4SLinus Torvalds struct file *file; 378265c90bcaSStephen Smalley u32 sid = task_sid(tsk); 37831da177e4SLinus Torvalds u32 perm; 37841da177e4SLinus Torvalds struct file_security_struct *fsec; 37851da177e4SLinus Torvalds 37861da177e4SLinus Torvalds /* struct fown_struct is never outside the context of a struct file */ 3787b385a144SRobert P. J. Day file = container_of(fown, struct file, f_owner); 37881da177e4SLinus Torvalds 37891da177e4SLinus Torvalds fsec = file->f_security; 37901da177e4SLinus Torvalds 37911da177e4SLinus Torvalds if (!signum) 37921da177e4SLinus Torvalds perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */ 37931da177e4SLinus Torvalds else 37941da177e4SLinus Torvalds perm = signal_to_av(signum); 37951da177e4SLinus Torvalds 37966b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 37976b6bc620SStephen Smalley fsec->fown_sid, sid, 37981da177e4SLinus Torvalds SECCLASS_PROCESS, perm, NULL); 37991da177e4SLinus Torvalds } 38001da177e4SLinus Torvalds 38011da177e4SLinus Torvalds static int selinux_file_receive(struct file *file) 38021da177e4SLinus Torvalds { 380388e67f3bSDavid Howells const struct cred *cred = current_cred(); 380488e67f3bSDavid Howells 380588e67f3bSDavid Howells return file_has_perm(cred, file, file_to_av(file)); 38061da177e4SLinus Torvalds } 38071da177e4SLinus Torvalds 380894817692SAl Viro static int selinux_file_open(struct file *file) 3809788e7dd4SYuichi Nakamura { 3810788e7dd4SYuichi Nakamura struct file_security_struct *fsec; 3811788e7dd4SYuichi Nakamura struct inode_security_struct *isec; 3812d84f4f99SDavid Howells 3813788e7dd4SYuichi Nakamura fsec = file->f_security; 381483da53c5SAndreas Gruenbacher isec = inode_security(file_inode(file)); 3815788e7dd4SYuichi Nakamura /* 3816788e7dd4SYuichi Nakamura * Save inode label and policy sequence number 3817788e7dd4SYuichi Nakamura * at open-time so that selinux_file_permission 3818788e7dd4SYuichi Nakamura * can determine whether revalidation is necessary. 3819788e7dd4SYuichi Nakamura * Task label is already saved in the file security 3820788e7dd4SYuichi Nakamura * struct as its SID. 3821788e7dd4SYuichi Nakamura */ 3822788e7dd4SYuichi Nakamura fsec->isid = isec->sid; 38236b6bc620SStephen Smalley fsec->pseqno = avc_policy_seqno(&selinux_state); 3824788e7dd4SYuichi Nakamura /* 3825788e7dd4SYuichi Nakamura * Since the inode label or policy seqno may have changed 3826788e7dd4SYuichi Nakamura * between the selinux_inode_permission check and the saving 3827788e7dd4SYuichi Nakamura * of state above, recheck that access is still permitted. 3828788e7dd4SYuichi Nakamura * Otherwise, access might never be revalidated against the 3829788e7dd4SYuichi Nakamura * new inode label or new policy. 3830788e7dd4SYuichi Nakamura * This check is not redundant - do not remove. 3831788e7dd4SYuichi Nakamura */ 383294817692SAl Viro return file_path_has_perm(file->f_cred, file, open_file_to_av(file)); 3833788e7dd4SYuichi Nakamura } 3834788e7dd4SYuichi Nakamura 38351da177e4SLinus Torvalds /* task security operations */ 38361da177e4SLinus Torvalds 3837a79be238STetsuo Handa static int selinux_task_alloc(struct task_struct *task, 3838a79be238STetsuo Handa unsigned long clone_flags) 38391da177e4SLinus Torvalds { 3840be0554c9SStephen Smalley u32 sid = current_sid(); 3841be0554c9SStephen Smalley 38426b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 38436b6bc620SStephen Smalley sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL); 38441da177e4SLinus Torvalds } 38451da177e4SLinus Torvalds 3846f1752eecSDavid Howells /* 3847ee18d64cSDavid Howells * allocate the SELinux part of blank credentials 3848ee18d64cSDavid Howells */ 3849ee18d64cSDavid Howells static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp) 3850ee18d64cSDavid Howells { 3851ee18d64cSDavid Howells struct task_security_struct *tsec; 3852ee18d64cSDavid Howells 3853ee18d64cSDavid Howells tsec = kzalloc(sizeof(struct task_security_struct), gfp); 3854ee18d64cSDavid Howells if (!tsec) 3855ee18d64cSDavid Howells return -ENOMEM; 3856ee18d64cSDavid Howells 3857ee18d64cSDavid Howells cred->security = tsec; 3858ee18d64cSDavid Howells return 0; 3859ee18d64cSDavid Howells } 3860ee18d64cSDavid Howells 3861ee18d64cSDavid Howells /* 3862f1752eecSDavid Howells * detach and free the LSM part of a set of credentials 3863f1752eecSDavid Howells */ 3864f1752eecSDavid Howells static void selinux_cred_free(struct cred *cred) 38651da177e4SLinus Torvalds { 3866f1752eecSDavid Howells struct task_security_struct *tsec = cred->security; 3867e0e81739SDavid Howells 38682edeaa34STetsuo Handa /* 38692edeaa34STetsuo Handa * cred->security == NULL if security_cred_alloc_blank() or 38702edeaa34STetsuo Handa * security_prepare_creds() returned an error. 38712edeaa34STetsuo Handa */ 38722edeaa34STetsuo Handa BUG_ON(cred->security && (unsigned long) cred->security < PAGE_SIZE); 3873e0e81739SDavid Howells cred->security = (void *) 0x7UL; 3874f1752eecSDavid Howells kfree(tsec); 38751da177e4SLinus Torvalds } 38761da177e4SLinus Torvalds 3877d84f4f99SDavid Howells /* 3878d84f4f99SDavid Howells * prepare a new set of credentials for modification 3879d84f4f99SDavid Howells */ 3880d84f4f99SDavid Howells static int selinux_cred_prepare(struct cred *new, const struct cred *old, 3881d84f4f99SDavid Howells gfp_t gfp) 3882d84f4f99SDavid Howells { 3883d84f4f99SDavid Howells const struct task_security_struct *old_tsec; 3884d84f4f99SDavid Howells struct task_security_struct *tsec; 3885d84f4f99SDavid Howells 3886d84f4f99SDavid Howells old_tsec = old->security; 3887d84f4f99SDavid Howells 3888d84f4f99SDavid Howells tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp); 3889d84f4f99SDavid Howells if (!tsec) 3890d84f4f99SDavid Howells return -ENOMEM; 3891d84f4f99SDavid Howells 3892d84f4f99SDavid Howells new->security = tsec; 3893d84f4f99SDavid Howells return 0; 3894d84f4f99SDavid Howells } 3895d84f4f99SDavid Howells 3896d84f4f99SDavid Howells /* 3897ee18d64cSDavid Howells * transfer the SELinux data to a blank set of creds 3898ee18d64cSDavid Howells */ 3899ee18d64cSDavid Howells static void selinux_cred_transfer(struct cred *new, const struct cred *old) 3900ee18d64cSDavid Howells { 3901ee18d64cSDavid Howells const struct task_security_struct *old_tsec = old->security; 3902ee18d64cSDavid Howells struct task_security_struct *tsec = new->security; 3903ee18d64cSDavid Howells 3904ee18d64cSDavid Howells *tsec = *old_tsec; 3905ee18d64cSDavid Howells } 3906ee18d64cSDavid Howells 39073ec30113SMatthew Garrett static void selinux_cred_getsecid(const struct cred *c, u32 *secid) 39083ec30113SMatthew Garrett { 39093ec30113SMatthew Garrett *secid = cred_sid(c); 39103ec30113SMatthew Garrett } 39113ec30113SMatthew Garrett 3912ee18d64cSDavid Howells /* 39133a3b7ce9SDavid Howells * set the security data for a kernel service 39143a3b7ce9SDavid Howells * - all the creation contexts are set to unlabelled 39153a3b7ce9SDavid Howells */ 39163a3b7ce9SDavid Howells static int selinux_kernel_act_as(struct cred *new, u32 secid) 39173a3b7ce9SDavid Howells { 39183a3b7ce9SDavid Howells struct task_security_struct *tsec = new->security; 39193a3b7ce9SDavid Howells u32 sid = current_sid(); 39203a3b7ce9SDavid Howells int ret; 39213a3b7ce9SDavid Howells 39226b6bc620SStephen Smalley ret = avc_has_perm(&selinux_state, 39236b6bc620SStephen Smalley sid, secid, 39243a3b7ce9SDavid Howells SECCLASS_KERNEL_SERVICE, 39253a3b7ce9SDavid Howells KERNEL_SERVICE__USE_AS_OVERRIDE, 39263a3b7ce9SDavid Howells NULL); 39273a3b7ce9SDavid Howells if (ret == 0) { 39283a3b7ce9SDavid Howells tsec->sid = secid; 39293a3b7ce9SDavid Howells tsec->create_sid = 0; 39303a3b7ce9SDavid Howells tsec->keycreate_sid = 0; 39313a3b7ce9SDavid Howells tsec->sockcreate_sid = 0; 39323a3b7ce9SDavid Howells } 39333a3b7ce9SDavid Howells return ret; 39343a3b7ce9SDavid Howells } 39353a3b7ce9SDavid Howells 39363a3b7ce9SDavid Howells /* 39373a3b7ce9SDavid Howells * set the file creation context in a security record to the same as the 39383a3b7ce9SDavid Howells * objective context of the specified inode 39393a3b7ce9SDavid Howells */ 39403a3b7ce9SDavid Howells static int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) 39413a3b7ce9SDavid Howells { 394283da53c5SAndreas Gruenbacher struct inode_security_struct *isec = inode_security(inode); 39433a3b7ce9SDavid Howells struct task_security_struct *tsec = new->security; 39443a3b7ce9SDavid Howells u32 sid = current_sid(); 39453a3b7ce9SDavid Howells int ret; 39463a3b7ce9SDavid Howells 39476b6bc620SStephen Smalley ret = avc_has_perm(&selinux_state, 39486b6bc620SStephen Smalley sid, isec->sid, 39493a3b7ce9SDavid Howells SECCLASS_KERNEL_SERVICE, 39503a3b7ce9SDavid Howells KERNEL_SERVICE__CREATE_FILES_AS, 39513a3b7ce9SDavid Howells NULL); 39523a3b7ce9SDavid Howells 39533a3b7ce9SDavid Howells if (ret == 0) 39543a3b7ce9SDavid Howells tsec->create_sid = isec->sid; 3955ef57471aSDavid Howells return ret; 39563a3b7ce9SDavid Howells } 39573a3b7ce9SDavid Howells 3958dd8dbf2eSEric Paris static int selinux_kernel_module_request(char *kmod_name) 395925354c4fSEric Paris { 3960dd8dbf2eSEric Paris struct common_audit_data ad; 3961dd8dbf2eSEric Paris 396250c205f5SEric Paris ad.type = LSM_AUDIT_DATA_KMOD; 3963dd8dbf2eSEric Paris ad.u.kmod_name = kmod_name; 3964dd8dbf2eSEric Paris 39656b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 39666b6bc620SStephen Smalley current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, 3967dd8dbf2eSEric Paris SYSTEM__MODULE_REQUEST, &ad); 396825354c4fSEric Paris } 396925354c4fSEric Paris 397061d612eaSJeff Vander Stoep static int selinux_kernel_module_from_file(struct file *file) 397161d612eaSJeff Vander Stoep { 397261d612eaSJeff Vander Stoep struct common_audit_data ad; 397361d612eaSJeff Vander Stoep struct inode_security_struct *isec; 397461d612eaSJeff Vander Stoep struct file_security_struct *fsec; 397561d612eaSJeff Vander Stoep u32 sid = current_sid(); 397661d612eaSJeff Vander Stoep int rc; 397761d612eaSJeff Vander Stoep 397861d612eaSJeff Vander Stoep /* init_module */ 397961d612eaSJeff Vander Stoep if (file == NULL) 39806b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 39816b6bc620SStephen Smalley sid, sid, SECCLASS_SYSTEM, 398261d612eaSJeff Vander Stoep SYSTEM__MODULE_LOAD, NULL); 398361d612eaSJeff Vander Stoep 398461d612eaSJeff Vander Stoep /* finit_module */ 398520cdef8dSPaul Moore 398643af5de7SVivek Goyal ad.type = LSM_AUDIT_DATA_FILE; 398743af5de7SVivek Goyal ad.u.file = file; 398861d612eaSJeff Vander Stoep 398961d612eaSJeff Vander Stoep fsec = file->f_security; 399061d612eaSJeff Vander Stoep if (sid != fsec->sid) { 39916b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 39926b6bc620SStephen Smalley sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); 399361d612eaSJeff Vander Stoep if (rc) 399461d612eaSJeff Vander Stoep return rc; 399561d612eaSJeff Vander Stoep } 399661d612eaSJeff Vander Stoep 399720cdef8dSPaul Moore isec = inode_security(file_inode(file)); 39986b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 39996b6bc620SStephen Smalley sid, isec->sid, SECCLASS_SYSTEM, 400061d612eaSJeff Vander Stoep SYSTEM__MODULE_LOAD, &ad); 400161d612eaSJeff Vander Stoep } 400261d612eaSJeff Vander Stoep 400361d612eaSJeff Vander Stoep static int selinux_kernel_read_file(struct file *file, 400461d612eaSJeff Vander Stoep enum kernel_read_file_id id) 400561d612eaSJeff Vander Stoep { 400661d612eaSJeff Vander Stoep int rc = 0; 400761d612eaSJeff Vander Stoep 400861d612eaSJeff Vander Stoep switch (id) { 400961d612eaSJeff Vander Stoep case READING_MODULE: 401061d612eaSJeff Vander Stoep rc = selinux_kernel_module_from_file(file); 401161d612eaSJeff Vander Stoep break; 401261d612eaSJeff Vander Stoep default: 401361d612eaSJeff Vander Stoep break; 401461d612eaSJeff Vander Stoep } 401561d612eaSJeff Vander Stoep 401661d612eaSJeff Vander Stoep return rc; 401761d612eaSJeff Vander Stoep } 401861d612eaSJeff Vander Stoep 4019c77b8cdfSMimi Zohar static int selinux_kernel_load_data(enum kernel_load_data_id id) 4020c77b8cdfSMimi Zohar { 4021c77b8cdfSMimi Zohar int rc = 0; 4022c77b8cdfSMimi Zohar 4023c77b8cdfSMimi Zohar switch (id) { 4024c77b8cdfSMimi Zohar case LOADING_MODULE: 4025c77b8cdfSMimi Zohar rc = selinux_kernel_module_from_file(NULL); 4026c77b8cdfSMimi Zohar default: 4027c77b8cdfSMimi Zohar break; 4028c77b8cdfSMimi Zohar } 4029c77b8cdfSMimi Zohar 4030c77b8cdfSMimi Zohar return rc; 4031c77b8cdfSMimi Zohar } 4032c77b8cdfSMimi Zohar 40331da177e4SLinus Torvalds static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) 40341da177e4SLinus Torvalds { 40356b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 40366b6bc620SStephen Smalley current_sid(), task_sid(p), SECCLASS_PROCESS, 4037be0554c9SStephen Smalley PROCESS__SETPGID, NULL); 40381da177e4SLinus Torvalds } 40391da177e4SLinus Torvalds 40401da177e4SLinus Torvalds static int selinux_task_getpgid(struct task_struct *p) 40411da177e4SLinus Torvalds { 40426b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 40436b6bc620SStephen Smalley current_sid(), task_sid(p), SECCLASS_PROCESS, 4044be0554c9SStephen Smalley PROCESS__GETPGID, NULL); 40451da177e4SLinus Torvalds } 40461da177e4SLinus Torvalds 40471da177e4SLinus Torvalds static int selinux_task_getsid(struct task_struct *p) 40481da177e4SLinus Torvalds { 40496b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 40506b6bc620SStephen Smalley current_sid(), task_sid(p), SECCLASS_PROCESS, 4051be0554c9SStephen Smalley PROCESS__GETSESSION, NULL); 40521da177e4SLinus Torvalds } 40531da177e4SLinus Torvalds 4054f9008e4cSDavid Quigley static void selinux_task_getsecid(struct task_struct *p, u32 *secid) 4055f9008e4cSDavid Quigley { 4056275bb41eSDavid Howells *secid = task_sid(p); 4057f9008e4cSDavid Quigley } 4058f9008e4cSDavid Quigley 40591da177e4SLinus Torvalds static int selinux_task_setnice(struct task_struct *p, int nice) 40601da177e4SLinus Torvalds { 40616b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 40626b6bc620SStephen Smalley current_sid(), task_sid(p), SECCLASS_PROCESS, 4063be0554c9SStephen Smalley PROCESS__SETSCHED, NULL); 40641da177e4SLinus Torvalds } 40651da177e4SLinus Torvalds 406603e68060SJames Morris static int selinux_task_setioprio(struct task_struct *p, int ioprio) 406703e68060SJames Morris { 40686b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 40696b6bc620SStephen Smalley current_sid(), task_sid(p), SECCLASS_PROCESS, 4070be0554c9SStephen Smalley PROCESS__SETSCHED, NULL); 407103e68060SJames Morris } 407203e68060SJames Morris 4073a1836a42SDavid Quigley static int selinux_task_getioprio(struct task_struct *p) 4074a1836a42SDavid Quigley { 40756b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 40766b6bc620SStephen Smalley current_sid(), task_sid(p), SECCLASS_PROCESS, 4077be0554c9SStephen Smalley PROCESS__GETSCHED, NULL); 4078a1836a42SDavid Quigley } 4079a1836a42SDavid Quigley 40804298555dSCorentin LABBE static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred, 4081791ec491SStephen Smalley unsigned int flags) 4082791ec491SStephen Smalley { 4083791ec491SStephen Smalley u32 av = 0; 4084791ec491SStephen Smalley 408584e6885eSStephen Smalley if (!flags) 408684e6885eSStephen Smalley return 0; 4087791ec491SStephen Smalley if (flags & LSM_PRLIMIT_WRITE) 4088791ec491SStephen Smalley av |= PROCESS__SETRLIMIT; 4089791ec491SStephen Smalley if (flags & LSM_PRLIMIT_READ) 4090791ec491SStephen Smalley av |= PROCESS__GETRLIMIT; 40916b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 40926b6bc620SStephen Smalley cred_sid(cred), cred_sid(tcred), 4093791ec491SStephen Smalley SECCLASS_PROCESS, av, NULL); 4094791ec491SStephen Smalley } 4095791ec491SStephen Smalley 40968fd00b4dSJiri Slaby static int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, 40978fd00b4dSJiri Slaby struct rlimit *new_rlim) 40981da177e4SLinus Torvalds { 40998fd00b4dSJiri Slaby struct rlimit *old_rlim = p->signal->rlim + resource; 41001da177e4SLinus Torvalds 41011da177e4SLinus Torvalds /* Control the ability to change the hard limit (whether 41021da177e4SLinus Torvalds lowering or raising it), so that the hard limit can 41031da177e4SLinus Torvalds later be used as a safe reset point for the soft limit 4104d84f4f99SDavid Howells upon context transitions. See selinux_bprm_committing_creds. */ 41051da177e4SLinus Torvalds if (old_rlim->rlim_max != new_rlim->rlim_max) 41066b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 41076b6bc620SStephen Smalley current_sid(), task_sid(p), 4108be0554c9SStephen Smalley SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL); 41091da177e4SLinus Torvalds 41101da177e4SLinus Torvalds return 0; 41111da177e4SLinus Torvalds } 41121da177e4SLinus Torvalds 4113b0ae1981SKOSAKI Motohiro static int selinux_task_setscheduler(struct task_struct *p) 41141da177e4SLinus Torvalds { 41156b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 41166b6bc620SStephen Smalley current_sid(), task_sid(p), SECCLASS_PROCESS, 4117be0554c9SStephen Smalley PROCESS__SETSCHED, NULL); 41181da177e4SLinus Torvalds } 41191da177e4SLinus Torvalds 41201da177e4SLinus Torvalds static int selinux_task_getscheduler(struct task_struct *p) 41211da177e4SLinus Torvalds { 41226b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 41236b6bc620SStephen Smalley current_sid(), task_sid(p), SECCLASS_PROCESS, 4124be0554c9SStephen Smalley PROCESS__GETSCHED, NULL); 41251da177e4SLinus Torvalds } 41261da177e4SLinus Torvalds 412735601547SDavid Quigley static int selinux_task_movememory(struct task_struct *p) 412835601547SDavid Quigley { 41296b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 41306b6bc620SStephen Smalley current_sid(), task_sid(p), SECCLASS_PROCESS, 4131be0554c9SStephen Smalley PROCESS__SETSCHED, NULL); 413235601547SDavid Quigley } 413335601547SDavid Quigley 4134ae7795bcSEric W. Biederman static int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info, 41356b4f3d01SStephen Smalley int sig, const struct cred *cred) 41361da177e4SLinus Torvalds { 41376b4f3d01SStephen Smalley u32 secid; 41381da177e4SLinus Torvalds u32 perm; 41391da177e4SLinus Torvalds 41401da177e4SLinus Torvalds if (!sig) 41411da177e4SLinus Torvalds perm = PROCESS__SIGNULL; /* null signal; existence test */ 41421da177e4SLinus Torvalds else 41431da177e4SLinus Torvalds perm = signal_to_av(sig); 41446b4f3d01SStephen Smalley if (!cred) 4145be0554c9SStephen Smalley secid = current_sid(); 41466b4f3d01SStephen Smalley else 41476b4f3d01SStephen Smalley secid = cred_sid(cred); 41486b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 41496b6bc620SStephen Smalley secid, task_sid(p), SECCLASS_PROCESS, perm, NULL); 41501da177e4SLinus Torvalds } 41511da177e4SLinus Torvalds 41521da177e4SLinus Torvalds static void selinux_task_to_inode(struct task_struct *p, 41531da177e4SLinus Torvalds struct inode *inode) 41541da177e4SLinus Torvalds { 41551da177e4SLinus Torvalds struct inode_security_struct *isec = inode->i_security; 4156275bb41eSDavid Howells u32 sid = task_sid(p); 41571da177e4SLinus Torvalds 41589287aed2SAndreas Gruenbacher spin_lock(&isec->lock); 4159db978da8SAndreas Gruenbacher isec->sclass = inode_mode_to_security_class(inode->i_mode); 4160275bb41eSDavid Howells isec->sid = sid; 41616f3be9f5SAndreas Gruenbacher isec->initialized = LABEL_INITIALIZED; 41629287aed2SAndreas Gruenbacher spin_unlock(&isec->lock); 41631da177e4SLinus Torvalds } 41641da177e4SLinus Torvalds 41651da177e4SLinus Torvalds /* Returns error only if unable to parse addresses */ 416667f83cbfSVenkat Yekkirala static int selinux_parse_skb_ipv4(struct sk_buff *skb, 41672bf49690SThomas Liu struct common_audit_data *ad, u8 *proto) 41681da177e4SLinus Torvalds { 41691da177e4SLinus Torvalds int offset, ihlen, ret = -EINVAL; 41701da177e4SLinus Torvalds struct iphdr _iph, *ih; 41711da177e4SLinus Torvalds 4172bbe735e4SArnaldo Carvalho de Melo offset = skb_network_offset(skb); 41731da177e4SLinus Torvalds ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); 41741da177e4SLinus Torvalds if (ih == NULL) 41751da177e4SLinus Torvalds goto out; 41761da177e4SLinus Torvalds 41771da177e4SLinus Torvalds ihlen = ih->ihl * 4; 41781da177e4SLinus Torvalds if (ihlen < sizeof(_iph)) 41791da177e4SLinus Torvalds goto out; 41801da177e4SLinus Torvalds 418148c62af6SEric Paris ad->u.net->v4info.saddr = ih->saddr; 418248c62af6SEric Paris ad->u.net->v4info.daddr = ih->daddr; 41831da177e4SLinus Torvalds ret = 0; 41841da177e4SLinus Torvalds 418567f83cbfSVenkat Yekkirala if (proto) 418667f83cbfSVenkat Yekkirala *proto = ih->protocol; 418767f83cbfSVenkat Yekkirala 41881da177e4SLinus Torvalds switch (ih->protocol) { 41891da177e4SLinus Torvalds case IPPROTO_TCP: { 41901da177e4SLinus Torvalds struct tcphdr _tcph, *th; 41911da177e4SLinus Torvalds 41921da177e4SLinus Torvalds if (ntohs(ih->frag_off) & IP_OFFSET) 41931da177e4SLinus Torvalds break; 41941da177e4SLinus Torvalds 41951da177e4SLinus Torvalds offset += ihlen; 41961da177e4SLinus Torvalds th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); 41971da177e4SLinus Torvalds if (th == NULL) 41981da177e4SLinus Torvalds break; 41991da177e4SLinus Torvalds 420048c62af6SEric Paris ad->u.net->sport = th->source; 420148c62af6SEric Paris ad->u.net->dport = th->dest; 42021da177e4SLinus Torvalds break; 42031da177e4SLinus Torvalds } 42041da177e4SLinus Torvalds 42051da177e4SLinus Torvalds case IPPROTO_UDP: { 42061da177e4SLinus Torvalds struct udphdr _udph, *uh; 42071da177e4SLinus Torvalds 42081da177e4SLinus Torvalds if (ntohs(ih->frag_off) & IP_OFFSET) 42091da177e4SLinus Torvalds break; 42101da177e4SLinus Torvalds 42111da177e4SLinus Torvalds offset += ihlen; 42121da177e4SLinus Torvalds uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); 42131da177e4SLinus Torvalds if (uh == NULL) 42141da177e4SLinus Torvalds break; 42151da177e4SLinus Torvalds 421648c62af6SEric Paris ad->u.net->sport = uh->source; 421748c62af6SEric Paris ad->u.net->dport = uh->dest; 42181da177e4SLinus Torvalds break; 42191da177e4SLinus Torvalds } 42201da177e4SLinus Torvalds 42212ee92d46SJames Morris case IPPROTO_DCCP: { 42222ee92d46SJames Morris struct dccp_hdr _dccph, *dh; 42232ee92d46SJames Morris 42242ee92d46SJames Morris if (ntohs(ih->frag_off) & IP_OFFSET) 42252ee92d46SJames Morris break; 42262ee92d46SJames Morris 42272ee92d46SJames Morris offset += ihlen; 42282ee92d46SJames Morris dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); 42292ee92d46SJames Morris if (dh == NULL) 42302ee92d46SJames Morris break; 42312ee92d46SJames Morris 423248c62af6SEric Paris ad->u.net->sport = dh->dccph_sport; 423348c62af6SEric Paris ad->u.net->dport = dh->dccph_dport; 42342ee92d46SJames Morris break; 42352ee92d46SJames Morris } 42362ee92d46SJames Morris 4237d452930fSRichard Haines #if IS_ENABLED(CONFIG_IP_SCTP) 4238d452930fSRichard Haines case IPPROTO_SCTP: { 4239d452930fSRichard Haines struct sctphdr _sctph, *sh; 4240d452930fSRichard Haines 4241d452930fSRichard Haines if (ntohs(ih->frag_off) & IP_OFFSET) 4242d452930fSRichard Haines break; 4243d452930fSRichard Haines 4244d452930fSRichard Haines offset += ihlen; 4245d452930fSRichard Haines sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph); 4246d452930fSRichard Haines if (sh == NULL) 4247d452930fSRichard Haines break; 4248d452930fSRichard Haines 4249d452930fSRichard Haines ad->u.net->sport = sh->source; 4250d452930fSRichard Haines ad->u.net->dport = sh->dest; 4251d452930fSRichard Haines break; 4252d452930fSRichard Haines } 4253d452930fSRichard Haines #endif 42541da177e4SLinus Torvalds default: 42551da177e4SLinus Torvalds break; 42561da177e4SLinus Torvalds } 42571da177e4SLinus Torvalds out: 42581da177e4SLinus Torvalds return ret; 42591da177e4SLinus Torvalds } 42601da177e4SLinus Torvalds 42611a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6) 42621da177e4SLinus Torvalds 42631da177e4SLinus Torvalds /* Returns error only if unable to parse addresses */ 426467f83cbfSVenkat Yekkirala static int selinux_parse_skb_ipv6(struct sk_buff *skb, 42652bf49690SThomas Liu struct common_audit_data *ad, u8 *proto) 42661da177e4SLinus Torvalds { 42671da177e4SLinus Torvalds u8 nexthdr; 42681da177e4SLinus Torvalds int ret = -EINVAL, offset; 42691da177e4SLinus Torvalds struct ipv6hdr _ipv6h, *ip6; 427075f2811cSJesse Gross __be16 frag_off; 42711da177e4SLinus Torvalds 4272bbe735e4SArnaldo Carvalho de Melo offset = skb_network_offset(skb); 42731da177e4SLinus Torvalds ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h); 42741da177e4SLinus Torvalds if (ip6 == NULL) 42751da177e4SLinus Torvalds goto out; 42761da177e4SLinus Torvalds 427748c62af6SEric Paris ad->u.net->v6info.saddr = ip6->saddr; 427848c62af6SEric Paris ad->u.net->v6info.daddr = ip6->daddr; 42791da177e4SLinus Torvalds ret = 0; 42801da177e4SLinus Torvalds 42811da177e4SLinus Torvalds nexthdr = ip6->nexthdr; 42821da177e4SLinus Torvalds offset += sizeof(_ipv6h); 428375f2811cSJesse Gross offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off); 42841da177e4SLinus Torvalds if (offset < 0) 42851da177e4SLinus Torvalds goto out; 42861da177e4SLinus Torvalds 428767f83cbfSVenkat Yekkirala if (proto) 428867f83cbfSVenkat Yekkirala *proto = nexthdr; 428967f83cbfSVenkat Yekkirala 42901da177e4SLinus Torvalds switch (nexthdr) { 42911da177e4SLinus Torvalds case IPPROTO_TCP: { 42921da177e4SLinus Torvalds struct tcphdr _tcph, *th; 42931da177e4SLinus Torvalds 42941da177e4SLinus Torvalds th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); 42951da177e4SLinus Torvalds if (th == NULL) 42961da177e4SLinus Torvalds break; 42971da177e4SLinus Torvalds 429848c62af6SEric Paris ad->u.net->sport = th->source; 429948c62af6SEric Paris ad->u.net->dport = th->dest; 43001da177e4SLinus Torvalds break; 43011da177e4SLinus Torvalds } 43021da177e4SLinus Torvalds 43031da177e4SLinus Torvalds case IPPROTO_UDP: { 43041da177e4SLinus Torvalds struct udphdr _udph, *uh; 43051da177e4SLinus Torvalds 43061da177e4SLinus Torvalds uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); 43071da177e4SLinus Torvalds if (uh == NULL) 43081da177e4SLinus Torvalds break; 43091da177e4SLinus Torvalds 431048c62af6SEric Paris ad->u.net->sport = uh->source; 431148c62af6SEric Paris ad->u.net->dport = uh->dest; 43121da177e4SLinus Torvalds break; 43131da177e4SLinus Torvalds } 43141da177e4SLinus Torvalds 43152ee92d46SJames Morris case IPPROTO_DCCP: { 43162ee92d46SJames Morris struct dccp_hdr _dccph, *dh; 43172ee92d46SJames Morris 43182ee92d46SJames Morris dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); 43192ee92d46SJames Morris if (dh == NULL) 43202ee92d46SJames Morris break; 43212ee92d46SJames Morris 432248c62af6SEric Paris ad->u.net->sport = dh->dccph_sport; 432348c62af6SEric Paris ad->u.net->dport = dh->dccph_dport; 43242ee92d46SJames Morris break; 43252ee92d46SJames Morris } 43262ee92d46SJames Morris 4327d452930fSRichard Haines #if IS_ENABLED(CONFIG_IP_SCTP) 4328d452930fSRichard Haines case IPPROTO_SCTP: { 4329d452930fSRichard Haines struct sctphdr _sctph, *sh; 4330d452930fSRichard Haines 4331d452930fSRichard Haines sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph); 4332d452930fSRichard Haines if (sh == NULL) 4333d452930fSRichard Haines break; 4334d452930fSRichard Haines 4335d452930fSRichard Haines ad->u.net->sport = sh->source; 4336d452930fSRichard Haines ad->u.net->dport = sh->dest; 4337d452930fSRichard Haines break; 4338d452930fSRichard Haines } 4339d452930fSRichard Haines #endif 43401da177e4SLinus Torvalds /* includes fragments */ 43411da177e4SLinus Torvalds default: 43421da177e4SLinus Torvalds break; 43431da177e4SLinus Torvalds } 43441da177e4SLinus Torvalds out: 43451da177e4SLinus Torvalds return ret; 43461da177e4SLinus Torvalds } 43471da177e4SLinus Torvalds 43481da177e4SLinus Torvalds #endif /* IPV6 */ 43491da177e4SLinus Torvalds 43502bf49690SThomas Liu static int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad, 4351cf9481e2SDavid Howells char **_addrp, int src, u8 *proto) 43521da177e4SLinus Torvalds { 4353cf9481e2SDavid Howells char *addrp; 4354cf9481e2SDavid Howells int ret; 43551da177e4SLinus Torvalds 435648c62af6SEric Paris switch (ad->u.net->family) { 43571da177e4SLinus Torvalds case PF_INET: 435867f83cbfSVenkat Yekkirala ret = selinux_parse_skb_ipv4(skb, ad, proto); 4359cf9481e2SDavid Howells if (ret) 4360cf9481e2SDavid Howells goto parse_error; 436148c62af6SEric Paris addrp = (char *)(src ? &ad->u.net->v4info.saddr : 436248c62af6SEric Paris &ad->u.net->v4info.daddr); 4363cf9481e2SDavid Howells goto okay; 43641da177e4SLinus Torvalds 43651a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6) 43661da177e4SLinus Torvalds case PF_INET6: 436767f83cbfSVenkat Yekkirala ret = selinux_parse_skb_ipv6(skb, ad, proto); 4368cf9481e2SDavid Howells if (ret) 4369cf9481e2SDavid Howells goto parse_error; 437048c62af6SEric Paris addrp = (char *)(src ? &ad->u.net->v6info.saddr : 437148c62af6SEric Paris &ad->u.net->v6info.daddr); 4372cf9481e2SDavid Howells goto okay; 43731da177e4SLinus Torvalds #endif /* IPV6 */ 43741da177e4SLinus Torvalds default: 4375cf9481e2SDavid Howells addrp = NULL; 4376cf9481e2SDavid Howells goto okay; 43771da177e4SLinus Torvalds } 43781da177e4SLinus Torvalds 4379cf9481e2SDavid Howells parse_error: 4380c103a91eSpeter enderborg pr_warn( 438171f1cb05SPaul Moore "SELinux: failure in selinux_parse_skb()," 438271f1cb05SPaul Moore " unable to parse packet\n"); 43831da177e4SLinus Torvalds return ret; 4384cf9481e2SDavid Howells 4385cf9481e2SDavid Howells okay: 4386cf9481e2SDavid Howells if (_addrp) 4387cf9481e2SDavid Howells *_addrp = addrp; 4388cf9481e2SDavid Howells return 0; 43891da177e4SLinus Torvalds } 43901da177e4SLinus Torvalds 43914f6a993fSPaul Moore /** 4392220deb96SPaul Moore * selinux_skb_peerlbl_sid - Determine the peer label of a packet 43934f6a993fSPaul Moore * @skb: the packet 439475e22910SPaul Moore * @family: protocol family 4395220deb96SPaul Moore * @sid: the packet's peer label SID 43964f6a993fSPaul Moore * 43974f6a993fSPaul Moore * Description: 4398220deb96SPaul Moore * Check the various different forms of network peer labeling and determine 4399220deb96SPaul Moore * the peer label/SID for the packet; most of the magic actually occurs in 4400220deb96SPaul Moore * the security server function security_net_peersid_cmp(). The function 4401220deb96SPaul Moore * returns zero if the value in @sid is valid (although it may be SECSID_NULL) 4402220deb96SPaul Moore * or -EACCES if @sid is invalid due to inconsistencies with the different 4403220deb96SPaul Moore * peer labels. 44044f6a993fSPaul Moore * 44054f6a993fSPaul Moore */ 4406220deb96SPaul Moore static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) 44074f6a993fSPaul Moore { 440871f1cb05SPaul Moore int err; 44094f6a993fSPaul Moore u32 xfrm_sid; 44104f6a993fSPaul Moore u32 nlbl_sid; 4411220deb96SPaul Moore u32 nlbl_type; 44124f6a993fSPaul Moore 4413817eff71SPaul Moore err = selinux_xfrm_skb_sid(skb, &xfrm_sid); 4414bed4d7efSPaul Moore if (unlikely(err)) 4415bed4d7efSPaul Moore return -EACCES; 4416bed4d7efSPaul Moore err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid); 4417bed4d7efSPaul Moore if (unlikely(err)) 4418bed4d7efSPaul Moore return -EACCES; 4419220deb96SPaul Moore 4420aa8e712cSStephen Smalley err = security_net_peersid_resolve(&selinux_state, nlbl_sid, 4421aa8e712cSStephen Smalley nlbl_type, xfrm_sid, sid); 442271f1cb05SPaul Moore if (unlikely(err)) { 4423c103a91eSpeter enderborg pr_warn( 442471f1cb05SPaul Moore "SELinux: failure in selinux_skb_peerlbl_sid()," 442571f1cb05SPaul Moore " unable to determine packet's peer label\n"); 4426220deb96SPaul Moore return -EACCES; 442771f1cb05SPaul Moore } 4428220deb96SPaul Moore 4429220deb96SPaul Moore return 0; 44304f6a993fSPaul Moore } 44314f6a993fSPaul Moore 4432446b8024SPaul Moore /** 4433446b8024SPaul Moore * selinux_conn_sid - Determine the child socket label for a connection 4434446b8024SPaul Moore * @sk_sid: the parent socket's SID 4435446b8024SPaul Moore * @skb_sid: the packet's SID 4436446b8024SPaul Moore * @conn_sid: the resulting connection SID 4437446b8024SPaul Moore * 4438446b8024SPaul Moore * If @skb_sid is valid then the user:role:type information from @sk_sid is 4439446b8024SPaul Moore * combined with the MLS information from @skb_sid in order to create 4440446b8024SPaul Moore * @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy 4441446b8024SPaul Moore * of @sk_sid. Returns zero on success, negative values on failure. 4442446b8024SPaul Moore * 4443446b8024SPaul Moore */ 4444446b8024SPaul Moore static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid) 4445446b8024SPaul Moore { 4446446b8024SPaul Moore int err = 0; 4447446b8024SPaul Moore 4448446b8024SPaul Moore if (skb_sid != SECSID_NULL) 4449aa8e712cSStephen Smalley err = security_sid_mls_copy(&selinux_state, sk_sid, skb_sid, 4450aa8e712cSStephen Smalley conn_sid); 4451446b8024SPaul Moore else 4452446b8024SPaul Moore *conn_sid = sk_sid; 4453446b8024SPaul Moore 4454446b8024SPaul Moore return err; 4455446b8024SPaul Moore } 4456446b8024SPaul Moore 44571da177e4SLinus Torvalds /* socket security operations */ 4458d4f2d978SPaul Moore 44592ad18bdfSHarry Ciao static int socket_sockcreate_sid(const struct task_security_struct *tsec, 44602ad18bdfSHarry Ciao u16 secclass, u32 *socksid) 4461d4f2d978SPaul Moore { 44622ad18bdfSHarry Ciao if (tsec->sockcreate_sid > SECSID_NULL) { 44632ad18bdfSHarry Ciao *socksid = tsec->sockcreate_sid; 44642ad18bdfSHarry Ciao return 0; 44652ad18bdfSHarry Ciao } 44662ad18bdfSHarry Ciao 4467aa8e712cSStephen Smalley return security_transition_sid(&selinux_state, tsec->sid, tsec->sid, 4468aa8e712cSStephen Smalley secclass, NULL, socksid); 4469d4f2d978SPaul Moore } 4470d4f2d978SPaul Moore 4471be0554c9SStephen Smalley static int sock_has_perm(struct sock *sk, u32 perms) 44721da177e4SLinus Torvalds { 4473253bfae6SPaul Moore struct sk_security_struct *sksec = sk->sk_security; 44742bf49690SThomas Liu struct common_audit_data ad; 447548c62af6SEric Paris struct lsm_network_audit net = {0,}; 44761da177e4SLinus Torvalds 4477253bfae6SPaul Moore if (sksec->sid == SECINITSID_KERNEL) 4478253bfae6SPaul Moore return 0; 44791da177e4SLinus Torvalds 448050c205f5SEric Paris ad.type = LSM_AUDIT_DATA_NET; 448148c62af6SEric Paris ad.u.net = &net; 448248c62af6SEric Paris ad.u.net->sk = sk; 44831da177e4SLinus Torvalds 44846b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 44856b6bc620SStephen Smalley current_sid(), sksec->sid, sksec->sclass, perms, 4486be0554c9SStephen Smalley &ad); 44871da177e4SLinus Torvalds } 44881da177e4SLinus Torvalds 44891da177e4SLinus Torvalds static int selinux_socket_create(int family, int type, 44901da177e4SLinus Torvalds int protocol, int kern) 44911da177e4SLinus Torvalds { 44925fb49870SPaul Moore const struct task_security_struct *tsec = current_security(); 4493d4f2d978SPaul Moore u32 newsid; 4494275bb41eSDavid Howells u16 secclass; 44952ad18bdfSHarry Ciao int rc; 44961da177e4SLinus Torvalds 44971da177e4SLinus Torvalds if (kern) 4498d4f2d978SPaul Moore return 0; 44991da177e4SLinus Torvalds 4500275bb41eSDavid Howells secclass = socket_type_to_security_class(family, type, protocol); 45012ad18bdfSHarry Ciao rc = socket_sockcreate_sid(tsec, secclass, &newsid); 45022ad18bdfSHarry Ciao if (rc) 45032ad18bdfSHarry Ciao return rc; 45042ad18bdfSHarry Ciao 45056b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 45066b6bc620SStephen Smalley tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); 45071da177e4SLinus Torvalds } 45081da177e4SLinus Torvalds 45097420ed23SVenkat Yekkirala static int selinux_socket_post_create(struct socket *sock, int family, 45101da177e4SLinus Torvalds int type, int protocol, int kern) 45111da177e4SLinus Torvalds { 45125fb49870SPaul Moore const struct task_security_struct *tsec = current_security(); 45135d226df4SAndreas Gruenbacher struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock)); 4514892c141eSVenkat Yekkirala struct sk_security_struct *sksec; 45159287aed2SAndreas Gruenbacher u16 sclass = socket_type_to_security_class(family, type, protocol); 45169287aed2SAndreas Gruenbacher u32 sid = SECINITSID_KERNEL; 4517275bb41eSDavid Howells int err = 0; 4518275bb41eSDavid Howells 45199287aed2SAndreas Gruenbacher if (!kern) { 45209287aed2SAndreas Gruenbacher err = socket_sockcreate_sid(tsec, sclass, &sid); 45212ad18bdfSHarry Ciao if (err) 45222ad18bdfSHarry Ciao return err; 45232ad18bdfSHarry Ciao } 4524275bb41eSDavid Howells 45259287aed2SAndreas Gruenbacher isec->sclass = sclass; 45269287aed2SAndreas Gruenbacher isec->sid = sid; 45276f3be9f5SAndreas Gruenbacher isec->initialized = LABEL_INITIALIZED; 45281da177e4SLinus Torvalds 4529892c141eSVenkat Yekkirala if (sock->sk) { 4530892c141eSVenkat Yekkirala sksec = sock->sk->sk_security; 45319287aed2SAndreas Gruenbacher sksec->sclass = sclass; 45329287aed2SAndreas Gruenbacher sksec->sid = sid; 4533d452930fSRichard Haines /* Allows detection of the first association on this socket */ 4534d452930fSRichard Haines if (sksec->sclass == SECCLASS_SCTP_SOCKET) 4535d452930fSRichard Haines sksec->sctp_assoc_state = SCTP_ASSOC_UNSET; 4536d452930fSRichard Haines 4537389fb800SPaul Moore err = selinux_netlbl_socket_post_create(sock->sk, family); 4538892c141eSVenkat Yekkirala } 4539892c141eSVenkat Yekkirala 45407420ed23SVenkat Yekkirala return err; 45411da177e4SLinus Torvalds } 45421da177e4SLinus Torvalds 45430b811db2SDavid Herrmann static int selinux_socket_socketpair(struct socket *socka, 45440b811db2SDavid Herrmann struct socket *sockb) 45450b811db2SDavid Herrmann { 45460b811db2SDavid Herrmann struct sk_security_struct *sksec_a = socka->sk->sk_security; 45470b811db2SDavid Herrmann struct sk_security_struct *sksec_b = sockb->sk->sk_security; 45480b811db2SDavid Herrmann 45490b811db2SDavid Herrmann sksec_a->peer_sid = sksec_b->sid; 45500b811db2SDavid Herrmann sksec_b->peer_sid = sksec_a->sid; 45510b811db2SDavid Herrmann 45520b811db2SDavid Herrmann return 0; 45530b811db2SDavid Herrmann } 45540b811db2SDavid Herrmann 45551da177e4SLinus Torvalds /* Range of port numbers used to automatically bind. 45561da177e4SLinus Torvalds Need to determine whether we should perform a name_bind 45571da177e4SLinus Torvalds permission check between the socket and the port number. */ 45581da177e4SLinus Torvalds 45591da177e4SLinus Torvalds static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) 45601da177e4SLinus Torvalds { 4561253bfae6SPaul Moore struct sock *sk = sock->sk; 45620f8db8ccSAlexey Kodanev struct sk_security_struct *sksec = sk->sk_security; 45631da177e4SLinus Torvalds u16 family; 45641da177e4SLinus Torvalds int err; 45651da177e4SLinus Torvalds 4566be0554c9SStephen Smalley err = sock_has_perm(sk, SOCKET__BIND); 45671da177e4SLinus Torvalds if (err) 45681da177e4SLinus Torvalds goto out; 45691da177e4SLinus Torvalds 4570d452930fSRichard Haines /* If PF_INET or PF_INET6, check name_bind permission for the port. */ 4571253bfae6SPaul Moore family = sk->sk_family; 45721da177e4SLinus Torvalds if (family == PF_INET || family == PF_INET6) { 45731da177e4SLinus Torvalds char *addrp; 45742bf49690SThomas Liu struct common_audit_data ad; 457548c62af6SEric Paris struct lsm_network_audit net = {0,}; 45761da177e4SLinus Torvalds struct sockaddr_in *addr4 = NULL; 45771da177e4SLinus Torvalds struct sockaddr_in6 *addr6 = NULL; 45780f8db8ccSAlexey Kodanev u16 family_sa = address->sa_family; 45791da177e4SLinus Torvalds unsigned short snum; 4580e399f982SJames Morris u32 sid, node_perm; 45811da177e4SLinus Torvalds 4582d452930fSRichard Haines /* 4583d452930fSRichard Haines * sctp_bindx(3) calls via selinux_sctp_bind_connect() 4584d452930fSRichard Haines * that validates multiple binding addresses. Because of this 4585d452930fSRichard Haines * need to check address->sa_family as it is possible to have 4586d452930fSRichard Haines * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. 4587d452930fSRichard Haines */ 45880f8db8ccSAlexey Kodanev switch (family_sa) { 45890f8db8ccSAlexey Kodanev case AF_UNSPEC: 459068741a8aSRichard Haines case AF_INET: 459168741a8aSRichard Haines if (addrlen < sizeof(struct sockaddr_in)) 459268741a8aSRichard Haines return -EINVAL; 45931da177e4SLinus Torvalds addr4 = (struct sockaddr_in *)address; 45940f8db8ccSAlexey Kodanev if (family_sa == AF_UNSPEC) { 45950f8db8ccSAlexey Kodanev /* see __inet_bind(), we only want to allow 45960f8db8ccSAlexey Kodanev * AF_UNSPEC if the address is INADDR_ANY 45970f8db8ccSAlexey Kodanev */ 45980f8db8ccSAlexey Kodanev if (addr4->sin_addr.s_addr != htonl(INADDR_ANY)) 45990f8db8ccSAlexey Kodanev goto err_af; 46000f8db8ccSAlexey Kodanev family_sa = AF_INET; 46010f8db8ccSAlexey Kodanev } 46021da177e4SLinus Torvalds snum = ntohs(addr4->sin_port); 46031da177e4SLinus Torvalds addrp = (char *)&addr4->sin_addr.s_addr; 460468741a8aSRichard Haines break; 460568741a8aSRichard Haines case AF_INET6: 460668741a8aSRichard Haines if (addrlen < SIN6_LEN_RFC2133) 460768741a8aSRichard Haines return -EINVAL; 46081da177e4SLinus Torvalds addr6 = (struct sockaddr_in6 *)address; 46091da177e4SLinus Torvalds snum = ntohs(addr6->sin6_port); 46101da177e4SLinus Torvalds addrp = (char *)&addr6->sin6_addr.s6_addr; 461168741a8aSRichard Haines break; 461268741a8aSRichard Haines default: 46130f8db8ccSAlexey Kodanev goto err_af; 46141da177e4SLinus Torvalds } 46151da177e4SLinus Torvalds 461688b7d370SAlexey Kodanev ad.type = LSM_AUDIT_DATA_NET; 461788b7d370SAlexey Kodanev ad.u.net = &net; 461888b7d370SAlexey Kodanev ad.u.net->sport = htons(snum); 461988b7d370SAlexey Kodanev ad.u.net->family = family_sa; 462088b7d370SAlexey Kodanev 4621227b60f5SStephen Hemminger if (snum) { 4622227b60f5SStephen Hemminger int low, high; 4623227b60f5SStephen Hemminger 46240bbf87d8SEric W. Biederman inet_get_local_port_range(sock_net(sk), &low, &high); 4625227b60f5SStephen Hemminger 46264548b683SKrister Johansen if (snum < max(inet_prot_sock(sock_net(sk)), low) || 46274548b683SKrister Johansen snum > high) { 46283e112172SPaul Moore err = sel_netport_sid(sk->sk_protocol, 46293e112172SPaul Moore snum, &sid); 46301da177e4SLinus Torvalds if (err) 46311da177e4SLinus Torvalds goto out; 46326b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 46336b6bc620SStephen Smalley sksec->sid, sid, 4634253bfae6SPaul Moore sksec->sclass, 46351da177e4SLinus Torvalds SOCKET__NAME_BIND, &ad); 46361da177e4SLinus Torvalds if (err) 46371da177e4SLinus Torvalds goto out; 46381da177e4SLinus Torvalds } 4639227b60f5SStephen Hemminger } 46401da177e4SLinus Torvalds 4641253bfae6SPaul Moore switch (sksec->sclass) { 464213402580SJames Morris case SECCLASS_TCP_SOCKET: 46431da177e4SLinus Torvalds node_perm = TCP_SOCKET__NODE_BIND; 46441da177e4SLinus Torvalds break; 46451da177e4SLinus Torvalds 464613402580SJames Morris case SECCLASS_UDP_SOCKET: 46471da177e4SLinus Torvalds node_perm = UDP_SOCKET__NODE_BIND; 46481da177e4SLinus Torvalds break; 46491da177e4SLinus Torvalds 46502ee92d46SJames Morris case SECCLASS_DCCP_SOCKET: 46512ee92d46SJames Morris node_perm = DCCP_SOCKET__NODE_BIND; 46522ee92d46SJames Morris break; 46532ee92d46SJames Morris 4654d452930fSRichard Haines case SECCLASS_SCTP_SOCKET: 4655d452930fSRichard Haines node_perm = SCTP_SOCKET__NODE_BIND; 4656d452930fSRichard Haines break; 4657d452930fSRichard Haines 46581da177e4SLinus Torvalds default: 46591da177e4SLinus Torvalds node_perm = RAWIP_SOCKET__NODE_BIND; 46601da177e4SLinus Torvalds break; 46611da177e4SLinus Torvalds } 46621da177e4SLinus Torvalds 466388b7d370SAlexey Kodanev err = sel_netnode_sid(addrp, family_sa, &sid); 46641da177e4SLinus Torvalds if (err) 46651da177e4SLinus Torvalds goto out; 46661da177e4SLinus Torvalds 46670f8db8ccSAlexey Kodanev if (family_sa == AF_INET) 466848c62af6SEric Paris ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; 46691da177e4SLinus Torvalds else 467048c62af6SEric Paris ad.u.net->v6info.saddr = addr6->sin6_addr; 46711da177e4SLinus Torvalds 46726b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 46736b6bc620SStephen Smalley sksec->sid, sid, 4674253bfae6SPaul Moore sksec->sclass, node_perm, &ad); 46751da177e4SLinus Torvalds if (err) 46761da177e4SLinus Torvalds goto out; 46771da177e4SLinus Torvalds } 46781da177e4SLinus Torvalds out: 46791da177e4SLinus Torvalds return err; 46800f8db8ccSAlexey Kodanev err_af: 46810f8db8ccSAlexey Kodanev /* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */ 46820f8db8ccSAlexey Kodanev if (sksec->sclass == SECCLASS_SCTP_SOCKET) 46830f8db8ccSAlexey Kodanev return -EINVAL; 46840f8db8ccSAlexey Kodanev return -EAFNOSUPPORT; 46851da177e4SLinus Torvalds } 46861da177e4SLinus Torvalds 4687d452930fSRichard Haines /* This supports connect(2) and SCTP connect services such as sctp_connectx(3) 46885fb94e9cSMauro Carvalho Chehab * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.rst 4689d452930fSRichard Haines */ 4690d452930fSRichard Haines static int selinux_socket_connect_helper(struct socket *sock, 4691d452930fSRichard Haines struct sockaddr *address, int addrlen) 46921da177e4SLinus Torvalds { 4693014ab19aSPaul Moore struct sock *sk = sock->sk; 4694253bfae6SPaul Moore struct sk_security_struct *sksec = sk->sk_security; 46951da177e4SLinus Torvalds int err; 46961da177e4SLinus Torvalds 4697be0554c9SStephen Smalley err = sock_has_perm(sk, SOCKET__CONNECT); 46981da177e4SLinus Torvalds if (err) 46991da177e4SLinus Torvalds return err; 47001da177e4SLinus Torvalds 47011da177e4SLinus Torvalds /* 4702d452930fSRichard Haines * If a TCP, DCCP or SCTP socket, check name_connect permission 4703d452930fSRichard Haines * for the port. 47041da177e4SLinus Torvalds */ 4705253bfae6SPaul Moore if (sksec->sclass == SECCLASS_TCP_SOCKET || 4706d452930fSRichard Haines sksec->sclass == SECCLASS_DCCP_SOCKET || 4707d452930fSRichard Haines sksec->sclass == SECCLASS_SCTP_SOCKET) { 47082bf49690SThomas Liu struct common_audit_data ad; 470948c62af6SEric Paris struct lsm_network_audit net = {0,}; 47101da177e4SLinus Torvalds struct sockaddr_in *addr4 = NULL; 47111da177e4SLinus Torvalds struct sockaddr_in6 *addr6 = NULL; 47121da177e4SLinus Torvalds unsigned short snum; 47132ee92d46SJames Morris u32 sid, perm; 47141da177e4SLinus Torvalds 4715d452930fSRichard Haines /* sctp_connectx(3) calls via selinux_sctp_bind_connect() 4716d452930fSRichard Haines * that validates multiple connect addresses. Because of this 4717d452930fSRichard Haines * need to check address->sa_family as it is possible to have 4718d452930fSRichard Haines * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. 4719d452930fSRichard Haines */ 472068741a8aSRichard Haines switch (address->sa_family) { 472168741a8aSRichard Haines case AF_INET: 47221da177e4SLinus Torvalds addr4 = (struct sockaddr_in *)address; 4723911656f8SStephen Smalley if (addrlen < sizeof(struct sockaddr_in)) 47241da177e4SLinus Torvalds return -EINVAL; 47251da177e4SLinus Torvalds snum = ntohs(addr4->sin_port); 472668741a8aSRichard Haines break; 472768741a8aSRichard Haines case AF_INET6: 47281da177e4SLinus Torvalds addr6 = (struct sockaddr_in6 *)address; 4729911656f8SStephen Smalley if (addrlen < SIN6_LEN_RFC2133) 47301da177e4SLinus Torvalds return -EINVAL; 47311da177e4SLinus Torvalds snum = ntohs(addr6->sin6_port); 473268741a8aSRichard Haines break; 473368741a8aSRichard Haines default: 473468741a8aSRichard Haines /* Note that SCTP services expect -EINVAL, whereas 473568741a8aSRichard Haines * others expect -EAFNOSUPPORT. 473668741a8aSRichard Haines */ 473768741a8aSRichard Haines if (sksec->sclass == SECCLASS_SCTP_SOCKET) 473868741a8aSRichard Haines return -EINVAL; 473968741a8aSRichard Haines else 474068741a8aSRichard Haines return -EAFNOSUPPORT; 47411da177e4SLinus Torvalds } 47421da177e4SLinus Torvalds 47433e112172SPaul Moore err = sel_netport_sid(sk->sk_protocol, snum, &sid); 47441da177e4SLinus Torvalds if (err) 4745d452930fSRichard Haines return err; 47461da177e4SLinus Torvalds 4747d452930fSRichard Haines switch (sksec->sclass) { 4748d452930fSRichard Haines case SECCLASS_TCP_SOCKET: 4749d452930fSRichard Haines perm = TCP_SOCKET__NAME_CONNECT; 4750d452930fSRichard Haines break; 4751d452930fSRichard Haines case SECCLASS_DCCP_SOCKET: 4752d452930fSRichard Haines perm = DCCP_SOCKET__NAME_CONNECT; 4753d452930fSRichard Haines break; 4754d452930fSRichard Haines case SECCLASS_SCTP_SOCKET: 4755d452930fSRichard Haines perm = SCTP_SOCKET__NAME_CONNECT; 4756d452930fSRichard Haines break; 4757d452930fSRichard Haines } 47582ee92d46SJames Morris 475950c205f5SEric Paris ad.type = LSM_AUDIT_DATA_NET; 476048c62af6SEric Paris ad.u.net = &net; 476148c62af6SEric Paris ad.u.net->dport = htons(snum); 476288b7d370SAlexey Kodanev ad.u.net->family = address->sa_family; 47636b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 47646b6bc620SStephen Smalley sksec->sid, sid, sksec->sclass, perm, &ad); 47651da177e4SLinus Torvalds if (err) 4766d452930fSRichard Haines return err; 47671da177e4SLinus Torvalds } 47681da177e4SLinus Torvalds 4769d452930fSRichard Haines return 0; 4770d452930fSRichard Haines } 4771014ab19aSPaul Moore 4772d452930fSRichard Haines /* Supports connect(2), see comments in selinux_socket_connect_helper() */ 4773d452930fSRichard Haines static int selinux_socket_connect(struct socket *sock, 4774d452930fSRichard Haines struct sockaddr *address, int addrlen) 4775d452930fSRichard Haines { 4776d452930fSRichard Haines int err; 4777d452930fSRichard Haines struct sock *sk = sock->sk; 4778d452930fSRichard Haines 4779d452930fSRichard Haines err = selinux_socket_connect_helper(sock, address, addrlen); 4780d452930fSRichard Haines if (err) 47811da177e4SLinus Torvalds return err; 4782d452930fSRichard Haines 4783d452930fSRichard Haines return selinux_netlbl_socket_connect(sk, address); 47841da177e4SLinus Torvalds } 47851da177e4SLinus Torvalds 47861da177e4SLinus Torvalds static int selinux_socket_listen(struct socket *sock, int backlog) 47871da177e4SLinus Torvalds { 4788be0554c9SStephen Smalley return sock_has_perm(sock->sk, SOCKET__LISTEN); 47891da177e4SLinus Torvalds } 47901da177e4SLinus Torvalds 47911da177e4SLinus Torvalds static int selinux_socket_accept(struct socket *sock, struct socket *newsock) 47921da177e4SLinus Torvalds { 47931da177e4SLinus Torvalds int err; 47941da177e4SLinus Torvalds struct inode_security_struct *isec; 47951da177e4SLinus Torvalds struct inode_security_struct *newisec; 47969287aed2SAndreas Gruenbacher u16 sclass; 47979287aed2SAndreas Gruenbacher u32 sid; 47981da177e4SLinus Torvalds 4799be0554c9SStephen Smalley err = sock_has_perm(sock->sk, SOCKET__ACCEPT); 48001da177e4SLinus Torvalds if (err) 48011da177e4SLinus Torvalds return err; 48021da177e4SLinus Torvalds 48035d226df4SAndreas Gruenbacher isec = inode_security_novalidate(SOCK_INODE(sock)); 48049287aed2SAndreas Gruenbacher spin_lock(&isec->lock); 48059287aed2SAndreas Gruenbacher sclass = isec->sclass; 48069287aed2SAndreas Gruenbacher sid = isec->sid; 48079287aed2SAndreas Gruenbacher spin_unlock(&isec->lock); 48089287aed2SAndreas Gruenbacher 48099287aed2SAndreas Gruenbacher newisec = inode_security_novalidate(SOCK_INODE(newsock)); 48109287aed2SAndreas Gruenbacher newisec->sclass = sclass; 48119287aed2SAndreas Gruenbacher newisec->sid = sid; 48126f3be9f5SAndreas Gruenbacher newisec->initialized = LABEL_INITIALIZED; 48131da177e4SLinus Torvalds 48141da177e4SLinus Torvalds return 0; 48151da177e4SLinus Torvalds } 48161da177e4SLinus Torvalds 48171da177e4SLinus Torvalds static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, 48181da177e4SLinus Torvalds int size) 48191da177e4SLinus Torvalds { 4820be0554c9SStephen Smalley return sock_has_perm(sock->sk, SOCKET__WRITE); 48211da177e4SLinus Torvalds } 48221da177e4SLinus Torvalds 48231da177e4SLinus Torvalds static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, 48241da177e4SLinus Torvalds int size, int flags) 48251da177e4SLinus Torvalds { 4826be0554c9SStephen Smalley return sock_has_perm(sock->sk, SOCKET__READ); 48271da177e4SLinus Torvalds } 48281da177e4SLinus Torvalds 48291da177e4SLinus Torvalds static int selinux_socket_getsockname(struct socket *sock) 48301da177e4SLinus Torvalds { 4831be0554c9SStephen Smalley return sock_has_perm(sock->sk, SOCKET__GETATTR); 48321da177e4SLinus Torvalds } 48331da177e4SLinus Torvalds 48341da177e4SLinus Torvalds static int selinux_socket_getpeername(struct socket *sock) 48351da177e4SLinus Torvalds { 4836be0554c9SStephen Smalley return sock_has_perm(sock->sk, SOCKET__GETATTR); 48371da177e4SLinus Torvalds } 48381da177e4SLinus Torvalds 48391da177e4SLinus Torvalds static int selinux_socket_setsockopt(struct socket *sock, int level, int optname) 48401da177e4SLinus Torvalds { 4841f8687afeSPaul Moore int err; 4842f8687afeSPaul Moore 4843be0554c9SStephen Smalley err = sock_has_perm(sock->sk, SOCKET__SETOPT); 4844f8687afeSPaul Moore if (err) 4845f8687afeSPaul Moore return err; 4846f8687afeSPaul Moore 4847f8687afeSPaul Moore return selinux_netlbl_socket_setsockopt(sock, level, optname); 48481da177e4SLinus Torvalds } 48491da177e4SLinus Torvalds 48501da177e4SLinus Torvalds static int selinux_socket_getsockopt(struct socket *sock, int level, 48511da177e4SLinus Torvalds int optname) 48521da177e4SLinus Torvalds { 4853be0554c9SStephen Smalley return sock_has_perm(sock->sk, SOCKET__GETOPT); 48541da177e4SLinus Torvalds } 48551da177e4SLinus Torvalds 48561da177e4SLinus Torvalds static int selinux_socket_shutdown(struct socket *sock, int how) 48571da177e4SLinus Torvalds { 4858be0554c9SStephen Smalley return sock_has_perm(sock->sk, SOCKET__SHUTDOWN); 48591da177e4SLinus Torvalds } 48601da177e4SLinus Torvalds 48613610cda5SDavid S. Miller static int selinux_socket_unix_stream_connect(struct sock *sock, 48623610cda5SDavid S. Miller struct sock *other, 48631da177e4SLinus Torvalds struct sock *newsk) 48641da177e4SLinus Torvalds { 48653610cda5SDavid S. Miller struct sk_security_struct *sksec_sock = sock->sk_security; 48663610cda5SDavid S. Miller struct sk_security_struct *sksec_other = other->sk_security; 48674d1e2451SPaul Moore struct sk_security_struct *sksec_new = newsk->sk_security; 48682bf49690SThomas Liu struct common_audit_data ad; 486948c62af6SEric Paris struct lsm_network_audit net = {0,}; 48701da177e4SLinus Torvalds int err; 48711da177e4SLinus Torvalds 487250c205f5SEric Paris ad.type = LSM_AUDIT_DATA_NET; 487348c62af6SEric Paris ad.u.net = &net; 487448c62af6SEric Paris ad.u.net->sk = other; 48751da177e4SLinus Torvalds 48766b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 48776b6bc620SStephen Smalley sksec_sock->sid, sksec_other->sid, 48784d1e2451SPaul Moore sksec_other->sclass, 48791da177e4SLinus Torvalds UNIX_STREAM_SOCKET__CONNECTTO, &ad); 48801da177e4SLinus Torvalds if (err) 48811da177e4SLinus Torvalds return err; 48821da177e4SLinus Torvalds 48831da177e4SLinus Torvalds /* server child socket */ 48844d1e2451SPaul Moore sksec_new->peer_sid = sksec_sock->sid; 4885aa8e712cSStephen Smalley err = security_sid_mls_copy(&selinux_state, sksec_other->sid, 4886aa8e712cSStephen Smalley sksec_sock->sid, &sksec_new->sid); 48874d1e2451SPaul Moore if (err) 48884237c75cSVenkat Yekkirala return err; 48894d1e2451SPaul Moore 48904d1e2451SPaul Moore /* connecting socket */ 48914d1e2451SPaul Moore sksec_sock->peer_sid = sksec_new->sid; 48924d1e2451SPaul Moore 48934d1e2451SPaul Moore return 0; 48941da177e4SLinus Torvalds } 48951da177e4SLinus Torvalds 48961da177e4SLinus Torvalds static int selinux_socket_unix_may_send(struct socket *sock, 48971da177e4SLinus Torvalds struct socket *other) 48981da177e4SLinus Torvalds { 4899253bfae6SPaul Moore struct sk_security_struct *ssec = sock->sk->sk_security; 4900253bfae6SPaul Moore struct sk_security_struct *osec = other->sk->sk_security; 49012bf49690SThomas Liu struct common_audit_data ad; 490248c62af6SEric Paris struct lsm_network_audit net = {0,}; 49031da177e4SLinus Torvalds 490450c205f5SEric Paris ad.type = LSM_AUDIT_DATA_NET; 490548c62af6SEric Paris ad.u.net = &net; 490648c62af6SEric Paris ad.u.net->sk = other->sk; 49071da177e4SLinus Torvalds 49086b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 49096b6bc620SStephen Smalley ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO, 4910253bfae6SPaul Moore &ad); 49111da177e4SLinus Torvalds } 49121da177e4SLinus Torvalds 4913cbe0d6e8SPaul Moore static int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex, 4914cbe0d6e8SPaul Moore char *addrp, u16 family, u32 peer_sid, 49152bf49690SThomas Liu struct common_audit_data *ad) 4916effad8dfSPaul Moore { 4917effad8dfSPaul Moore int err; 4918effad8dfSPaul Moore u32 if_sid; 4919effad8dfSPaul Moore u32 node_sid; 4920effad8dfSPaul Moore 4921cbe0d6e8SPaul Moore err = sel_netif_sid(ns, ifindex, &if_sid); 4922effad8dfSPaul Moore if (err) 4923effad8dfSPaul Moore return err; 49246b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 49256b6bc620SStephen Smalley peer_sid, if_sid, 4926effad8dfSPaul Moore SECCLASS_NETIF, NETIF__INGRESS, ad); 4927effad8dfSPaul Moore if (err) 4928effad8dfSPaul Moore return err; 4929effad8dfSPaul Moore 4930effad8dfSPaul Moore err = sel_netnode_sid(addrp, family, &node_sid); 4931effad8dfSPaul Moore if (err) 4932effad8dfSPaul Moore return err; 49336b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 49346b6bc620SStephen Smalley peer_sid, node_sid, 4935effad8dfSPaul Moore SECCLASS_NODE, NODE__RECVFROM, ad); 4936effad8dfSPaul Moore } 4937effad8dfSPaul Moore 4938220deb96SPaul Moore static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, 4939d8395c87SPaul Moore u16 family) 4940220deb96SPaul Moore { 4941277d342fSPaul Moore int err = 0; 4942220deb96SPaul Moore struct sk_security_struct *sksec = sk->sk_security; 4943220deb96SPaul Moore u32 sk_sid = sksec->sid; 49442bf49690SThomas Liu struct common_audit_data ad; 494548c62af6SEric Paris struct lsm_network_audit net = {0,}; 4946d8395c87SPaul Moore char *addrp; 4947d8395c87SPaul Moore 494850c205f5SEric Paris ad.type = LSM_AUDIT_DATA_NET; 494948c62af6SEric Paris ad.u.net = &net; 495048c62af6SEric Paris ad.u.net->netif = skb->skb_iif; 495148c62af6SEric Paris ad.u.net->family = family; 4952d8395c87SPaul Moore err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); 4953d8395c87SPaul Moore if (err) 4954d8395c87SPaul Moore return err; 4955220deb96SPaul Moore 495658bfbb51SPaul Moore if (selinux_secmark_enabled()) { 49576b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 49586b6bc620SStephen Smalley sk_sid, skb->secmark, SECCLASS_PACKET, 4959d8395c87SPaul Moore PACKET__RECV, &ad); 4960220deb96SPaul Moore if (err) 4961220deb96SPaul Moore return err; 496258bfbb51SPaul Moore } 4963220deb96SPaul Moore 4964d8395c87SPaul Moore err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); 4965220deb96SPaul Moore if (err) 4966220deb96SPaul Moore return err; 4967d8395c87SPaul Moore err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); 4968220deb96SPaul Moore 49694e5ab4cbSJames Morris return err; 49704e5ab4cbSJames Morris } 4971d28d1e08STrent Jaeger 49724e5ab4cbSJames Morris static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 49734e5ab4cbSJames Morris { 4974220deb96SPaul Moore int err; 49754237c75cSVenkat Yekkirala struct sk_security_struct *sksec = sk->sk_security; 4976220deb96SPaul Moore u16 family = sk->sk_family; 4977220deb96SPaul Moore u32 sk_sid = sksec->sid; 49782bf49690SThomas Liu struct common_audit_data ad; 497948c62af6SEric Paris struct lsm_network_audit net = {0,}; 4980220deb96SPaul Moore char *addrp; 4981d8395c87SPaul Moore u8 secmark_active; 4982d8395c87SPaul Moore u8 peerlbl_active; 49834e5ab4cbSJames Morris 49844e5ab4cbSJames Morris if (family != PF_INET && family != PF_INET6) 4985220deb96SPaul Moore return 0; 49864e5ab4cbSJames Morris 49874e5ab4cbSJames Morris /* Handle mapped IPv4 packets arriving via IPv6 sockets */ 498887fcd70dSAl Viro if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 49894e5ab4cbSJames Morris family = PF_INET; 49904e5ab4cbSJames Morris 4991d8395c87SPaul Moore /* If any sort of compatibility mode is enabled then handoff processing 4992d8395c87SPaul Moore * to the selinux_sock_rcv_skb_compat() function to deal with the 4993d8395c87SPaul Moore * special handling. We do this in an attempt to keep this function 4994d8395c87SPaul Moore * as fast and as clean as possible. */ 4995aa8e712cSStephen Smalley if (!selinux_policycap_netpeer()) 4996d8395c87SPaul Moore return selinux_sock_rcv_skb_compat(sk, skb, family); 4997d8395c87SPaul Moore 4998d8395c87SPaul Moore secmark_active = selinux_secmark_enabled(); 49992be4d74fSChris PeBenito peerlbl_active = selinux_peerlbl_enabled(); 5000d8395c87SPaul Moore if (!secmark_active && !peerlbl_active) 5001d8395c87SPaul Moore return 0; 5002d8395c87SPaul Moore 500350c205f5SEric Paris ad.type = LSM_AUDIT_DATA_NET; 500448c62af6SEric Paris ad.u.net = &net; 500548c62af6SEric Paris ad.u.net->netif = skb->skb_iif; 500648c62af6SEric Paris ad.u.net->family = family; 5007224dfbd8SPaul Moore err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); 50084e5ab4cbSJames Morris if (err) 5009220deb96SPaul Moore return err; 50104e5ab4cbSJames Morris 5011d8395c87SPaul Moore if (peerlbl_active) { 5012d621d35eSPaul Moore u32 peer_sid; 5013220deb96SPaul Moore 5014220deb96SPaul Moore err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); 5015220deb96SPaul Moore if (err) 5016220deb96SPaul Moore return err; 5017cbe0d6e8SPaul Moore err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif, 5018cbe0d6e8SPaul Moore addrp, family, peer_sid, &ad); 5019dfaebe98SPaul Moore if (err) { 5020a04e71f6SHuw Davies selinux_netlbl_err(skb, family, err, 0); 5021effad8dfSPaul Moore return err; 5022dfaebe98SPaul Moore } 50236b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 50246b6bc620SStephen Smalley sk_sid, peer_sid, SECCLASS_PEER, 5025d621d35eSPaul Moore PEER__RECV, &ad); 502646d01d63SChad Hanson if (err) { 5027a04e71f6SHuw Davies selinux_netlbl_err(skb, family, err, 0); 502846d01d63SChad Hanson return err; 502946d01d63SChad Hanson } 5030d621d35eSPaul Moore } 5031d621d35eSPaul Moore 5032d8395c87SPaul Moore if (secmark_active) { 50336b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 50346b6bc620SStephen Smalley sk_sid, skb->secmark, SECCLASS_PACKET, 5035effad8dfSPaul Moore PACKET__RECV, &ad); 5036effad8dfSPaul Moore if (err) 5037effad8dfSPaul Moore return err; 5038effad8dfSPaul Moore } 5039effad8dfSPaul Moore 5040d621d35eSPaul Moore return err; 50411da177e4SLinus Torvalds } 50421da177e4SLinus Torvalds 50432c7946a7SCatherine Zhang static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, 50441da177e4SLinus Torvalds int __user *optlen, unsigned len) 50451da177e4SLinus Torvalds { 50461da177e4SLinus Torvalds int err = 0; 50471da177e4SLinus Torvalds char *scontext; 50481da177e4SLinus Torvalds u32 scontext_len; 5049253bfae6SPaul Moore struct sk_security_struct *sksec = sock->sk->sk_security; 50503de4bab5SPaul Moore u32 peer_sid = SECSID_NULL; 50511da177e4SLinus Torvalds 5052253bfae6SPaul Moore if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET || 5053d452930fSRichard Haines sksec->sclass == SECCLASS_TCP_SOCKET || 5054d452930fSRichard Haines sksec->sclass == SECCLASS_SCTP_SOCKET) 5055dd3e7836SEric Paris peer_sid = sksec->peer_sid; 5056253bfae6SPaul Moore if (peer_sid == SECSID_NULL) 5057253bfae6SPaul Moore return -ENOPROTOOPT; 50581da177e4SLinus Torvalds 5059aa8e712cSStephen Smalley err = security_sid_to_context(&selinux_state, peer_sid, &scontext, 5060aa8e712cSStephen Smalley &scontext_len); 50611da177e4SLinus Torvalds if (err) 5062253bfae6SPaul Moore return err; 50631da177e4SLinus Torvalds 50641da177e4SLinus Torvalds if (scontext_len > len) { 50651da177e4SLinus Torvalds err = -ERANGE; 50661da177e4SLinus Torvalds goto out_len; 50671da177e4SLinus Torvalds } 50681da177e4SLinus Torvalds 50691da177e4SLinus Torvalds if (copy_to_user(optval, scontext, scontext_len)) 50701da177e4SLinus Torvalds err = -EFAULT; 50711da177e4SLinus Torvalds 50721da177e4SLinus Torvalds out_len: 50731da177e4SLinus Torvalds if (put_user(scontext_len, optlen)) 50741da177e4SLinus Torvalds err = -EFAULT; 50751da177e4SLinus Torvalds kfree(scontext); 50761da177e4SLinus Torvalds return err; 50771da177e4SLinus Torvalds } 50781da177e4SLinus Torvalds 5079dc49c1f9SCatherine Zhang static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) 50802c7946a7SCatherine Zhang { 5081dc49c1f9SCatherine Zhang u32 peer_secid = SECSID_NULL; 508275e22910SPaul Moore u16 family; 5083899134f2SPaul Moore struct inode_security_struct *isec; 5084877ce7c1SCatherine Zhang 5085aa862900SPaul Moore if (skb && skb->protocol == htons(ETH_P_IP)) 5086aa862900SPaul Moore family = PF_INET; 5087aa862900SPaul Moore else if (skb && skb->protocol == htons(ETH_P_IPV6)) 5088aa862900SPaul Moore family = PF_INET6; 5089aa862900SPaul Moore else if (sock) 509075e22910SPaul Moore family = sock->sk->sk_family; 509175e22910SPaul Moore else 509275e22910SPaul Moore goto out; 509375e22910SPaul Moore 5094899134f2SPaul Moore if (sock && family == PF_UNIX) { 5095899134f2SPaul Moore isec = inode_security_novalidate(SOCK_INODE(sock)); 5096899134f2SPaul Moore peer_secid = isec->sid; 5097899134f2SPaul Moore } else if (skb) 5098220deb96SPaul Moore selinux_skb_peerlbl_sid(skb, family, &peer_secid); 50992c7946a7SCatherine Zhang 510075e22910SPaul Moore out: 5101dc49c1f9SCatherine Zhang *secid = peer_secid; 510275e22910SPaul Moore if (peer_secid == SECSID_NULL) 510375e22910SPaul Moore return -EINVAL; 510475e22910SPaul Moore return 0; 51052c7946a7SCatherine Zhang } 51062c7946a7SCatherine Zhang 51077d877f3bSAl Viro static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) 51081da177e4SLinus Torvalds { 510984914b7eSPaul Moore struct sk_security_struct *sksec; 511084914b7eSPaul Moore 511184914b7eSPaul Moore sksec = kzalloc(sizeof(*sksec), priority); 511284914b7eSPaul Moore if (!sksec) 511384914b7eSPaul Moore return -ENOMEM; 511484914b7eSPaul Moore 511584914b7eSPaul Moore sksec->peer_sid = SECINITSID_UNLABELED; 511684914b7eSPaul Moore sksec->sid = SECINITSID_UNLABELED; 51175dee25d0SStephen Smalley sksec->sclass = SECCLASS_SOCKET; 511884914b7eSPaul Moore selinux_netlbl_sk_security_reset(sksec); 511984914b7eSPaul Moore sk->sk_security = sksec; 512084914b7eSPaul Moore 512184914b7eSPaul Moore return 0; 51221da177e4SLinus Torvalds } 51231da177e4SLinus Torvalds 51241da177e4SLinus Torvalds static void selinux_sk_free_security(struct sock *sk) 51251da177e4SLinus Torvalds { 512684914b7eSPaul Moore struct sk_security_struct *sksec = sk->sk_security; 512784914b7eSPaul Moore 512884914b7eSPaul Moore sk->sk_security = NULL; 512984914b7eSPaul Moore selinux_netlbl_sk_security_free(sksec); 513084914b7eSPaul Moore kfree(sksec); 51311da177e4SLinus Torvalds } 51321da177e4SLinus Torvalds 5133892c141eSVenkat Yekkirala static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) 5134892c141eSVenkat Yekkirala { 5135dd3e7836SEric Paris struct sk_security_struct *sksec = sk->sk_security; 5136dd3e7836SEric Paris struct sk_security_struct *newsksec = newsk->sk_security; 5137892c141eSVenkat Yekkirala 5138dd3e7836SEric Paris newsksec->sid = sksec->sid; 5139dd3e7836SEric Paris newsksec->peer_sid = sksec->peer_sid; 5140dd3e7836SEric Paris newsksec->sclass = sksec->sclass; 514199f59ed0SPaul Moore 5142dd3e7836SEric Paris selinux_netlbl_sk_security_reset(newsksec); 5143892c141eSVenkat Yekkirala } 5144892c141eSVenkat Yekkirala 5145beb8d13bSVenkat Yekkirala static void selinux_sk_getsecid(struct sock *sk, u32 *secid) 5146d28d1e08STrent Jaeger { 5147d28d1e08STrent Jaeger if (!sk) 5148beb8d13bSVenkat Yekkirala *secid = SECINITSID_ANY_SOCKET; 5149892c141eSVenkat Yekkirala else { 5150892c141eSVenkat Yekkirala struct sk_security_struct *sksec = sk->sk_security; 5151d28d1e08STrent Jaeger 5152beb8d13bSVenkat Yekkirala *secid = sksec->sid; 5153892c141eSVenkat Yekkirala } 5154d28d1e08STrent Jaeger } 5155d28d1e08STrent Jaeger 51569a673e56SAdrian Bunk static void selinux_sock_graft(struct sock *sk, struct socket *parent) 51574237c75cSVenkat Yekkirala { 51585d226df4SAndreas Gruenbacher struct inode_security_struct *isec = 51595d226df4SAndreas Gruenbacher inode_security_novalidate(SOCK_INODE(parent)); 51604237c75cSVenkat Yekkirala struct sk_security_struct *sksec = sk->sk_security; 51614237c75cSVenkat Yekkirala 51622873ead7SPaul Moore if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || 51632873ead7SPaul Moore sk->sk_family == PF_UNIX) 51644237c75cSVenkat Yekkirala isec->sid = sksec->sid; 5165220deb96SPaul Moore sksec->sclass = isec->sclass; 51664237c75cSVenkat Yekkirala } 51674237c75cSVenkat Yekkirala 5168d452930fSRichard Haines /* Called whenever SCTP receives an INIT chunk. This happens when an incoming 5169d452930fSRichard Haines * connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association 5170d452930fSRichard Haines * already present). 5171d452930fSRichard Haines */ 5172d452930fSRichard Haines static int selinux_sctp_assoc_request(struct sctp_endpoint *ep, 5173d452930fSRichard Haines struct sk_buff *skb) 5174d452930fSRichard Haines { 5175d452930fSRichard Haines struct sk_security_struct *sksec = ep->base.sk->sk_security; 5176d452930fSRichard Haines struct common_audit_data ad; 5177d452930fSRichard Haines struct lsm_network_audit net = {0,}; 5178d452930fSRichard Haines u8 peerlbl_active; 5179d452930fSRichard Haines u32 peer_sid = SECINITSID_UNLABELED; 5180d452930fSRichard Haines u32 conn_sid; 5181d452930fSRichard Haines int err = 0; 5182d452930fSRichard Haines 5183aa8e712cSStephen Smalley if (!selinux_policycap_extsockclass()) 5184d452930fSRichard Haines return 0; 5185d452930fSRichard Haines 5186d452930fSRichard Haines peerlbl_active = selinux_peerlbl_enabled(); 5187d452930fSRichard Haines 5188d452930fSRichard Haines if (peerlbl_active) { 5189d452930fSRichard Haines /* This will return peer_sid = SECSID_NULL if there are 5190d452930fSRichard Haines * no peer labels, see security_net_peersid_resolve(). 5191d452930fSRichard Haines */ 5192d452930fSRichard Haines err = selinux_skb_peerlbl_sid(skb, ep->base.sk->sk_family, 5193d452930fSRichard Haines &peer_sid); 5194d452930fSRichard Haines if (err) 5195d452930fSRichard Haines return err; 5196d452930fSRichard Haines 5197d452930fSRichard Haines if (peer_sid == SECSID_NULL) 5198d452930fSRichard Haines peer_sid = SECINITSID_UNLABELED; 5199d452930fSRichard Haines } 5200d452930fSRichard Haines 5201d452930fSRichard Haines if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) { 5202d452930fSRichard Haines sksec->sctp_assoc_state = SCTP_ASSOC_SET; 5203d452930fSRichard Haines 5204d452930fSRichard Haines /* Here as first association on socket. As the peer SID 5205d452930fSRichard Haines * was allowed by peer recv (and the netif/node checks), 5206d452930fSRichard Haines * then it is approved by policy and used as the primary 5207d452930fSRichard Haines * peer SID for getpeercon(3). 5208d452930fSRichard Haines */ 5209d452930fSRichard Haines sksec->peer_sid = peer_sid; 5210d452930fSRichard Haines } else if (sksec->peer_sid != peer_sid) { 5211d452930fSRichard Haines /* Other association peer SIDs are checked to enforce 5212d452930fSRichard Haines * consistency among the peer SIDs. 5213d452930fSRichard Haines */ 5214d452930fSRichard Haines ad.type = LSM_AUDIT_DATA_NET; 5215d452930fSRichard Haines ad.u.net = &net; 5216d452930fSRichard Haines ad.u.net->sk = ep->base.sk; 52176b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 52186b6bc620SStephen Smalley sksec->peer_sid, peer_sid, sksec->sclass, 5219d452930fSRichard Haines SCTP_SOCKET__ASSOCIATION, &ad); 5220d452930fSRichard Haines if (err) 5221d452930fSRichard Haines return err; 5222d452930fSRichard Haines } 5223d452930fSRichard Haines 5224d452930fSRichard Haines /* Compute the MLS component for the connection and store 5225d452930fSRichard Haines * the information in ep. This will be used by SCTP TCP type 5226d452930fSRichard Haines * sockets and peeled off connections as they cause a new 5227d452930fSRichard Haines * socket to be generated. selinux_sctp_sk_clone() will then 5228d452930fSRichard Haines * plug this into the new socket. 5229d452930fSRichard Haines */ 5230d452930fSRichard Haines err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid); 5231d452930fSRichard Haines if (err) 5232d452930fSRichard Haines return err; 5233d452930fSRichard Haines 5234d452930fSRichard Haines ep->secid = conn_sid; 5235d452930fSRichard Haines ep->peer_secid = peer_sid; 5236d452930fSRichard Haines 5237d452930fSRichard Haines /* Set any NetLabel labels including CIPSO/CALIPSO options. */ 5238d452930fSRichard Haines return selinux_netlbl_sctp_assoc_request(ep, skb); 5239d452930fSRichard Haines } 5240d452930fSRichard Haines 5241d452930fSRichard Haines /* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting 5242d452930fSRichard Haines * based on their @optname. 5243d452930fSRichard Haines */ 5244d452930fSRichard Haines static int selinux_sctp_bind_connect(struct sock *sk, int optname, 5245d452930fSRichard Haines struct sockaddr *address, 5246d452930fSRichard Haines int addrlen) 5247d452930fSRichard Haines { 5248d452930fSRichard Haines int len, err = 0, walk_size = 0; 5249d452930fSRichard Haines void *addr_buf; 5250d452930fSRichard Haines struct sockaddr *addr; 5251d452930fSRichard Haines struct socket *sock; 5252d452930fSRichard Haines 5253aa8e712cSStephen Smalley if (!selinux_policycap_extsockclass()) 5254d452930fSRichard Haines return 0; 5255d452930fSRichard Haines 5256d452930fSRichard Haines /* Process one or more addresses that may be IPv4 or IPv6 */ 5257d452930fSRichard Haines sock = sk->sk_socket; 5258d452930fSRichard Haines addr_buf = address; 5259d452930fSRichard Haines 5260d452930fSRichard Haines while (walk_size < addrlen) { 5261d452930fSRichard Haines addr = addr_buf; 5262d452930fSRichard Haines switch (addr->sa_family) { 52634152dc91SAlexey Kodanev case AF_UNSPEC: 5264d452930fSRichard Haines case AF_INET: 5265d452930fSRichard Haines len = sizeof(struct sockaddr_in); 5266d452930fSRichard Haines break; 5267d452930fSRichard Haines case AF_INET6: 5268d452930fSRichard Haines len = sizeof(struct sockaddr_in6); 5269d452930fSRichard Haines break; 5270d452930fSRichard Haines default: 52714152dc91SAlexey Kodanev return -EINVAL; 5272d452930fSRichard Haines } 5273d452930fSRichard Haines 5274d452930fSRichard Haines err = -EINVAL; 5275d452930fSRichard Haines switch (optname) { 5276d452930fSRichard Haines /* Bind checks */ 5277d452930fSRichard Haines case SCTP_PRIMARY_ADDR: 5278d452930fSRichard Haines case SCTP_SET_PEER_PRIMARY_ADDR: 5279d452930fSRichard Haines case SCTP_SOCKOPT_BINDX_ADD: 5280d452930fSRichard Haines err = selinux_socket_bind(sock, addr, len); 5281d452930fSRichard Haines break; 5282d452930fSRichard Haines /* Connect checks */ 5283d452930fSRichard Haines case SCTP_SOCKOPT_CONNECTX: 5284d452930fSRichard Haines case SCTP_PARAM_SET_PRIMARY: 5285d452930fSRichard Haines case SCTP_PARAM_ADD_IP: 5286d452930fSRichard Haines case SCTP_SENDMSG_CONNECT: 5287d452930fSRichard Haines err = selinux_socket_connect_helper(sock, addr, len); 5288d452930fSRichard Haines if (err) 5289d452930fSRichard Haines return err; 5290d452930fSRichard Haines 5291d452930fSRichard Haines /* As selinux_sctp_bind_connect() is called by the 5292d452930fSRichard Haines * SCTP protocol layer, the socket is already locked, 5293d452930fSRichard Haines * therefore selinux_netlbl_socket_connect_locked() is 5294d452930fSRichard Haines * is called here. The situations handled are: 5295d452930fSRichard Haines * sctp_connectx(3), sctp_sendmsg(3), sendmsg(2), 5296d452930fSRichard Haines * whenever a new IP address is added or when a new 5297d452930fSRichard Haines * primary address is selected. 5298d452930fSRichard Haines * Note that an SCTP connect(2) call happens before 5299d452930fSRichard Haines * the SCTP protocol layer and is handled via 5300d452930fSRichard Haines * selinux_socket_connect(). 5301d452930fSRichard Haines */ 5302d452930fSRichard Haines err = selinux_netlbl_socket_connect_locked(sk, addr); 5303d452930fSRichard Haines break; 5304d452930fSRichard Haines } 5305d452930fSRichard Haines 5306d452930fSRichard Haines if (err) 5307d452930fSRichard Haines return err; 5308d452930fSRichard Haines 5309d452930fSRichard Haines addr_buf += len; 5310d452930fSRichard Haines walk_size += len; 5311d452930fSRichard Haines } 5312d452930fSRichard Haines 5313d452930fSRichard Haines return 0; 5314d452930fSRichard Haines } 5315d452930fSRichard Haines 5316d452930fSRichard Haines /* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */ 5317d452930fSRichard Haines static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk, 5318d452930fSRichard Haines struct sock *newsk) 5319d452930fSRichard Haines { 5320d452930fSRichard Haines struct sk_security_struct *sksec = sk->sk_security; 5321d452930fSRichard Haines struct sk_security_struct *newsksec = newsk->sk_security; 5322d452930fSRichard Haines 5323d452930fSRichard Haines /* If policy does not support SECCLASS_SCTP_SOCKET then call 5324d452930fSRichard Haines * the non-sctp clone version. 5325d452930fSRichard Haines */ 5326aa8e712cSStephen Smalley if (!selinux_policycap_extsockclass()) 5327d452930fSRichard Haines return selinux_sk_clone_security(sk, newsk); 5328d452930fSRichard Haines 5329d452930fSRichard Haines newsksec->sid = ep->secid; 5330d452930fSRichard Haines newsksec->peer_sid = ep->peer_secid; 5331d452930fSRichard Haines newsksec->sclass = sksec->sclass; 5332d452930fSRichard Haines selinux_netlbl_sctp_sk_clone(sk, newsk); 5333d452930fSRichard Haines } 5334d452930fSRichard Haines 53359a673e56SAdrian Bunk static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, 53364237c75cSVenkat Yekkirala struct request_sock *req) 53374237c75cSVenkat Yekkirala { 53384237c75cSVenkat Yekkirala struct sk_security_struct *sksec = sk->sk_security; 53394237c75cSVenkat Yekkirala int err; 53400b1f24e6SPaul Moore u16 family = req->rsk_ops->family; 5341446b8024SPaul Moore u32 connsid; 53424237c75cSVenkat Yekkirala u32 peersid; 53434237c75cSVenkat Yekkirala 5344aa862900SPaul Moore err = selinux_skb_peerlbl_sid(skb, family, &peersid); 5345220deb96SPaul Moore if (err) 5346220deb96SPaul Moore return err; 5347446b8024SPaul Moore err = selinux_conn_sid(sksec->sid, peersid, &connsid); 53484237c75cSVenkat Yekkirala if (err) 53494237c75cSVenkat Yekkirala return err; 5350446b8024SPaul Moore req->secid = connsid; 53516b877699SVenkat Yekkirala req->peer_secid = peersid; 5352389fb800SPaul Moore 5353389fb800SPaul Moore return selinux_netlbl_inet_conn_request(req, family); 53544237c75cSVenkat Yekkirala } 53554237c75cSVenkat Yekkirala 53569a673e56SAdrian Bunk static void selinux_inet_csk_clone(struct sock *newsk, 53579a673e56SAdrian Bunk const struct request_sock *req) 53584237c75cSVenkat Yekkirala { 53594237c75cSVenkat Yekkirala struct sk_security_struct *newsksec = newsk->sk_security; 53604237c75cSVenkat Yekkirala 53614237c75cSVenkat Yekkirala newsksec->sid = req->secid; 53626b877699SVenkat Yekkirala newsksec->peer_sid = req->peer_secid; 53634237c75cSVenkat Yekkirala /* NOTE: Ideally, we should also get the isec->sid for the 53644237c75cSVenkat Yekkirala new socket in sync, but we don't have the isec available yet. 53654237c75cSVenkat Yekkirala So we will wait until sock_graft to do it, by which 53664237c75cSVenkat Yekkirala time it will have been created and available. */ 536799f59ed0SPaul Moore 53689f2ad665SPaul Moore /* We don't need to take any sort of lock here as we are the only 53699f2ad665SPaul Moore * thread with access to newsksec */ 5370389fb800SPaul Moore selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family); 53714237c75cSVenkat Yekkirala } 53724237c75cSVenkat Yekkirala 5373014ab19aSPaul Moore static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) 53746b877699SVenkat Yekkirala { 5375aa862900SPaul Moore u16 family = sk->sk_family; 53766b877699SVenkat Yekkirala struct sk_security_struct *sksec = sk->sk_security; 53776b877699SVenkat Yekkirala 5378aa862900SPaul Moore /* handle mapped IPv4 packets arriving via IPv6 sockets */ 5379aa862900SPaul Moore if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 5380aa862900SPaul Moore family = PF_INET; 5381aa862900SPaul Moore 5382aa862900SPaul Moore selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); 53836b877699SVenkat Yekkirala } 53846b877699SVenkat Yekkirala 53852606fd1fSEric Paris static int selinux_secmark_relabel_packet(u32 sid) 53862606fd1fSEric Paris { 53872606fd1fSEric Paris const struct task_security_struct *__tsec; 53882606fd1fSEric Paris u32 tsid; 53892606fd1fSEric Paris 53902606fd1fSEric Paris __tsec = current_security(); 53912606fd1fSEric Paris tsid = __tsec->sid; 53922606fd1fSEric Paris 53936b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 53946b6bc620SStephen Smalley tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, 53956b6bc620SStephen Smalley NULL); 53962606fd1fSEric Paris } 53972606fd1fSEric Paris 53982606fd1fSEric Paris static void selinux_secmark_refcount_inc(void) 53992606fd1fSEric Paris { 54002606fd1fSEric Paris atomic_inc(&selinux_secmark_refcount); 54012606fd1fSEric Paris } 54022606fd1fSEric Paris 54032606fd1fSEric Paris static void selinux_secmark_refcount_dec(void) 54042606fd1fSEric Paris { 54052606fd1fSEric Paris atomic_dec(&selinux_secmark_refcount); 54062606fd1fSEric Paris } 54072606fd1fSEric Paris 54089a673e56SAdrian Bunk static void selinux_req_classify_flow(const struct request_sock *req, 54099a673e56SAdrian Bunk struct flowi *fl) 54104237c75cSVenkat Yekkirala { 54111d28f42cSDavid S. Miller fl->flowi_secid = req->secid; 54124237c75cSVenkat Yekkirala } 54134237c75cSVenkat Yekkirala 54145dbbaf2dSPaul Moore static int selinux_tun_dev_alloc_security(void **security) 54155dbbaf2dSPaul Moore { 54165dbbaf2dSPaul Moore struct tun_security_struct *tunsec; 54175dbbaf2dSPaul Moore 54185dbbaf2dSPaul Moore tunsec = kzalloc(sizeof(*tunsec), GFP_KERNEL); 54195dbbaf2dSPaul Moore if (!tunsec) 54205dbbaf2dSPaul Moore return -ENOMEM; 54215dbbaf2dSPaul Moore tunsec->sid = current_sid(); 54225dbbaf2dSPaul Moore 54235dbbaf2dSPaul Moore *security = tunsec; 54245dbbaf2dSPaul Moore return 0; 54255dbbaf2dSPaul Moore } 54265dbbaf2dSPaul Moore 54275dbbaf2dSPaul Moore static void selinux_tun_dev_free_security(void *security) 54285dbbaf2dSPaul Moore { 54295dbbaf2dSPaul Moore kfree(security); 54305dbbaf2dSPaul Moore } 54315dbbaf2dSPaul Moore 5432ed6d76e4SPaul Moore static int selinux_tun_dev_create(void) 5433ed6d76e4SPaul Moore { 5434ed6d76e4SPaul Moore u32 sid = current_sid(); 5435ed6d76e4SPaul Moore 5436ed6d76e4SPaul Moore /* we aren't taking into account the "sockcreate" SID since the socket 5437ed6d76e4SPaul Moore * that is being created here is not a socket in the traditional sense, 5438ed6d76e4SPaul Moore * instead it is a private sock, accessible only to the kernel, and 5439ed6d76e4SPaul Moore * representing a wide range of network traffic spanning multiple 5440ed6d76e4SPaul Moore * connections unlike traditional sockets - check the TUN driver to 5441ed6d76e4SPaul Moore * get a better understanding of why this socket is special */ 5442ed6d76e4SPaul Moore 54436b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 54446b6bc620SStephen Smalley sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE, 5445ed6d76e4SPaul Moore NULL); 5446ed6d76e4SPaul Moore } 5447ed6d76e4SPaul Moore 54485dbbaf2dSPaul Moore static int selinux_tun_dev_attach_queue(void *security) 5449ed6d76e4SPaul Moore { 54505dbbaf2dSPaul Moore struct tun_security_struct *tunsec = security; 54515dbbaf2dSPaul Moore 54526b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 54536b6bc620SStephen Smalley current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET, 54545dbbaf2dSPaul Moore TUN_SOCKET__ATTACH_QUEUE, NULL); 54555dbbaf2dSPaul Moore } 54565dbbaf2dSPaul Moore 54575dbbaf2dSPaul Moore static int selinux_tun_dev_attach(struct sock *sk, void *security) 54585dbbaf2dSPaul Moore { 54595dbbaf2dSPaul Moore struct tun_security_struct *tunsec = security; 5460ed6d76e4SPaul Moore struct sk_security_struct *sksec = sk->sk_security; 5461ed6d76e4SPaul Moore 5462ed6d76e4SPaul Moore /* we don't currently perform any NetLabel based labeling here and it 5463ed6d76e4SPaul Moore * isn't clear that we would want to do so anyway; while we could apply 5464ed6d76e4SPaul Moore * labeling without the support of the TUN user the resulting labeled 5465ed6d76e4SPaul Moore * traffic from the other end of the connection would almost certainly 5466ed6d76e4SPaul Moore * cause confusion to the TUN user that had no idea network labeling 5467ed6d76e4SPaul Moore * protocols were being used */ 5468ed6d76e4SPaul Moore 54695dbbaf2dSPaul Moore sksec->sid = tunsec->sid; 5470ed6d76e4SPaul Moore sksec->sclass = SECCLASS_TUN_SOCKET; 54715dbbaf2dSPaul Moore 54725dbbaf2dSPaul Moore return 0; 5473ed6d76e4SPaul Moore } 5474ed6d76e4SPaul Moore 54755dbbaf2dSPaul Moore static int selinux_tun_dev_open(void *security) 5476ed6d76e4SPaul Moore { 54775dbbaf2dSPaul Moore struct tun_security_struct *tunsec = security; 5478ed6d76e4SPaul Moore u32 sid = current_sid(); 5479ed6d76e4SPaul Moore int err; 5480ed6d76e4SPaul Moore 54816b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 54826b6bc620SStephen Smalley sid, tunsec->sid, SECCLASS_TUN_SOCKET, 5483ed6d76e4SPaul Moore TUN_SOCKET__RELABELFROM, NULL); 5484ed6d76e4SPaul Moore if (err) 5485ed6d76e4SPaul Moore return err; 54866b6bc620SStephen Smalley err = avc_has_perm(&selinux_state, 54876b6bc620SStephen Smalley sid, sid, SECCLASS_TUN_SOCKET, 5488ed6d76e4SPaul Moore TUN_SOCKET__RELABELTO, NULL); 5489ed6d76e4SPaul Moore if (err) 5490ed6d76e4SPaul Moore return err; 54915dbbaf2dSPaul Moore tunsec->sid = sid; 5492ed6d76e4SPaul Moore 5493ed6d76e4SPaul Moore return 0; 5494ed6d76e4SPaul Moore } 5495ed6d76e4SPaul Moore 54961da177e4SLinus Torvalds static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) 54971da177e4SLinus Torvalds { 54981da177e4SLinus Torvalds int err = 0; 54991da177e4SLinus Torvalds u32 perm; 55001da177e4SLinus Torvalds struct nlmsghdr *nlh; 5501253bfae6SPaul Moore struct sk_security_struct *sksec = sk->sk_security; 55021da177e4SLinus Torvalds 550377954983SHong zhi guo if (skb->len < NLMSG_HDRLEN) { 55041da177e4SLinus Torvalds err = -EINVAL; 55051da177e4SLinus Torvalds goto out; 55061da177e4SLinus Torvalds } 5507b529ccf2SArnaldo Carvalho de Melo nlh = nlmsg_hdr(skb); 55081da177e4SLinus Torvalds 5509253bfae6SPaul Moore err = selinux_nlmsg_lookup(sksec->sclass, nlh->nlmsg_type, &perm); 55101da177e4SLinus Torvalds if (err) { 55111da177e4SLinus Torvalds if (err == -EINVAL) { 551276319946SVladis Dronov pr_warn_ratelimited("SELinux: unrecognized netlink" 551376319946SVladis Dronov " message: protocol=%hu nlmsg_type=%hu sclass=%s" 551476319946SVladis Dronov " pig=%d comm=%s\n", 5515cded3fffSMarek Milkovic sk->sk_protocol, nlh->nlmsg_type, 551676319946SVladis Dronov secclass_map[sksec->sclass - 1].name, 551776319946SVladis Dronov task_pid_nr(current), current->comm); 5518e5a5ca96SPaul Moore if (!enforcing_enabled(&selinux_state) || 5519aa8e712cSStephen Smalley security_get_allow_unknown(&selinux_state)) 55201da177e4SLinus Torvalds err = 0; 55211da177e4SLinus Torvalds } 55221da177e4SLinus Torvalds 55231da177e4SLinus Torvalds /* Ignore */ 55241da177e4SLinus Torvalds if (err == -ENOENT) 55251da177e4SLinus Torvalds err = 0; 55261da177e4SLinus Torvalds goto out; 55271da177e4SLinus Torvalds } 55281da177e4SLinus Torvalds 5529be0554c9SStephen Smalley err = sock_has_perm(sk, perm); 55301da177e4SLinus Torvalds out: 55311da177e4SLinus Torvalds return err; 55321da177e4SLinus Torvalds } 55331da177e4SLinus Torvalds 55341da177e4SLinus Torvalds #ifdef CONFIG_NETFILTER 55351da177e4SLinus Torvalds 5536cbe0d6e8SPaul Moore static unsigned int selinux_ip_forward(struct sk_buff *skb, 5537cbe0d6e8SPaul Moore const struct net_device *indev, 5538effad8dfSPaul Moore u16 family) 55391da177e4SLinus Torvalds { 5540dfaebe98SPaul Moore int err; 5541effad8dfSPaul Moore char *addrp; 5542effad8dfSPaul Moore u32 peer_sid; 55432bf49690SThomas Liu struct common_audit_data ad; 554448c62af6SEric Paris struct lsm_network_audit net = {0,}; 5545effad8dfSPaul Moore u8 secmark_active; 5546948bf85cSPaul Moore u8 netlbl_active; 5547effad8dfSPaul Moore u8 peerlbl_active; 55484237c75cSVenkat Yekkirala 5549aa8e712cSStephen Smalley if (!selinux_policycap_netpeer()) 5550effad8dfSPaul Moore return NF_ACCEPT; 55514237c75cSVenkat Yekkirala 5552effad8dfSPaul Moore secmark_active = selinux_secmark_enabled(); 5553948bf85cSPaul Moore netlbl_active = netlbl_enabled(); 55542be4d74fSChris PeBenito peerlbl_active = selinux_peerlbl_enabled(); 5555effad8dfSPaul Moore if (!secmark_active && !peerlbl_active) 5556effad8dfSPaul Moore return NF_ACCEPT; 55574237c75cSVenkat Yekkirala 5558d8395c87SPaul Moore if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) 5559d8395c87SPaul Moore return NF_DROP; 5560d8395c87SPaul Moore 556150c205f5SEric Paris ad.type = LSM_AUDIT_DATA_NET; 556248c62af6SEric Paris ad.u.net = &net; 5563cbe0d6e8SPaul Moore ad.u.net->netif = indev->ifindex; 556448c62af6SEric Paris ad.u.net->family = family; 5565effad8dfSPaul Moore if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) 5566effad8dfSPaul Moore return NF_DROP; 55671da177e4SLinus Torvalds 5568dfaebe98SPaul Moore if (peerlbl_active) { 5569cbe0d6e8SPaul Moore err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex, 5570cbe0d6e8SPaul Moore addrp, family, peer_sid, &ad); 5571dfaebe98SPaul Moore if (err) { 5572a04e71f6SHuw Davies selinux_netlbl_err(skb, family, err, 1); 5573effad8dfSPaul Moore return NF_DROP; 5574dfaebe98SPaul Moore } 5575dfaebe98SPaul Moore } 5576effad8dfSPaul Moore 5577effad8dfSPaul Moore if (secmark_active) 55786b6bc620SStephen Smalley if (avc_has_perm(&selinux_state, 55796b6bc620SStephen Smalley peer_sid, skb->secmark, 5580effad8dfSPaul Moore SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) 5581effad8dfSPaul Moore return NF_DROP; 5582effad8dfSPaul Moore 5583948bf85cSPaul Moore if (netlbl_active) 5584948bf85cSPaul Moore /* we do this in the FORWARD path and not the POST_ROUTING 5585948bf85cSPaul Moore * path because we want to make sure we apply the necessary 5586948bf85cSPaul Moore * labeling before IPsec is applied so we can leverage AH 5587948bf85cSPaul Moore * protection */ 5588948bf85cSPaul Moore if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) 5589948bf85cSPaul Moore return NF_DROP; 5590948bf85cSPaul Moore 5591effad8dfSPaul Moore return NF_ACCEPT; 5592effad8dfSPaul Moore } 5593effad8dfSPaul Moore 559406198b34SEric W. Biederman static unsigned int selinux_ipv4_forward(void *priv, 5595effad8dfSPaul Moore struct sk_buff *skb, 5596238e54c9SDavid S. Miller const struct nf_hook_state *state) 5597effad8dfSPaul Moore { 5598238e54c9SDavid S. Miller return selinux_ip_forward(skb, state->in, PF_INET); 5599effad8dfSPaul Moore } 5600effad8dfSPaul Moore 56011a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6) 560206198b34SEric W. Biederman static unsigned int selinux_ipv6_forward(void *priv, 5603effad8dfSPaul Moore struct sk_buff *skb, 5604238e54c9SDavid S. Miller const struct nf_hook_state *state) 5605effad8dfSPaul Moore { 5606238e54c9SDavid S. Miller return selinux_ip_forward(skb, state->in, PF_INET6); 5607effad8dfSPaul Moore } 5608effad8dfSPaul Moore #endif /* IPV6 */ 5609effad8dfSPaul Moore 5610948bf85cSPaul Moore static unsigned int selinux_ip_output(struct sk_buff *skb, 5611948bf85cSPaul Moore u16 family) 5612948bf85cSPaul Moore { 561347180068SPaul Moore struct sock *sk; 5614948bf85cSPaul Moore u32 sid; 5615948bf85cSPaul Moore 5616948bf85cSPaul Moore if (!netlbl_enabled()) 5617948bf85cSPaul Moore return NF_ACCEPT; 5618948bf85cSPaul Moore 5619948bf85cSPaul Moore /* we do this in the LOCAL_OUT path and not the POST_ROUTING path 5620948bf85cSPaul Moore * because we want to make sure we apply the necessary labeling 5621948bf85cSPaul Moore * before IPsec is applied so we can leverage AH protection */ 562247180068SPaul Moore sk = skb->sk; 562347180068SPaul Moore if (sk) { 562447180068SPaul Moore struct sk_security_struct *sksec; 562547180068SPaul Moore 5626e446f9dfSEric Dumazet if (sk_listener(sk)) 562747180068SPaul Moore /* if the socket is the listening state then this 562847180068SPaul Moore * packet is a SYN-ACK packet which means it needs to 562947180068SPaul Moore * be labeled based on the connection/request_sock and 563047180068SPaul Moore * not the parent socket. unfortunately, we can't 563147180068SPaul Moore * lookup the request_sock yet as it isn't queued on 563247180068SPaul Moore * the parent socket until after the SYN-ACK is sent. 563347180068SPaul Moore * the "solution" is to simply pass the packet as-is 563447180068SPaul Moore * as any IP option based labeling should be copied 563547180068SPaul Moore * from the initial connection request (in the IP 563647180068SPaul Moore * layer). it is far from ideal, but until we get a 563747180068SPaul Moore * security label in the packet itself this is the 563847180068SPaul Moore * best we can do. */ 563947180068SPaul Moore return NF_ACCEPT; 564047180068SPaul Moore 564147180068SPaul Moore /* standard practice, label using the parent socket */ 564247180068SPaul Moore sksec = sk->sk_security; 5643948bf85cSPaul Moore sid = sksec->sid; 5644948bf85cSPaul Moore } else 5645948bf85cSPaul Moore sid = SECINITSID_KERNEL; 5646948bf85cSPaul Moore if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0) 5647948bf85cSPaul Moore return NF_DROP; 5648948bf85cSPaul Moore 5649948bf85cSPaul Moore return NF_ACCEPT; 5650948bf85cSPaul Moore } 5651948bf85cSPaul Moore 565206198b34SEric W. Biederman static unsigned int selinux_ipv4_output(void *priv, 5653948bf85cSPaul Moore struct sk_buff *skb, 5654238e54c9SDavid S. Miller const struct nf_hook_state *state) 5655948bf85cSPaul Moore { 5656948bf85cSPaul Moore return selinux_ip_output(skb, PF_INET); 5657948bf85cSPaul Moore } 5658948bf85cSPaul Moore 56591a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6) 56602917f57bSHuw Davies static unsigned int selinux_ipv6_output(void *priv, 56612917f57bSHuw Davies struct sk_buff *skb, 56622917f57bSHuw Davies const struct nf_hook_state *state) 56632917f57bSHuw Davies { 56642917f57bSHuw Davies return selinux_ip_output(skb, PF_INET6); 56652917f57bSHuw Davies } 56662917f57bSHuw Davies #endif /* IPV6 */ 56672917f57bSHuw Davies 5668effad8dfSPaul Moore static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, 5669effad8dfSPaul Moore int ifindex, 5670d8395c87SPaul Moore u16 family) 56714e5ab4cbSJames Morris { 567254abc686SEric Dumazet struct sock *sk = skb_to_full_sk(skb); 56734237c75cSVenkat Yekkirala struct sk_security_struct *sksec; 56742bf49690SThomas Liu struct common_audit_data ad; 567548c62af6SEric Paris struct lsm_network_audit net = {0,}; 5676d8395c87SPaul Moore char *addrp; 5677d8395c87SPaul Moore u8 proto; 56784e5ab4cbSJames Morris 5679effad8dfSPaul Moore if (sk == NULL) 5680effad8dfSPaul Moore return NF_ACCEPT; 56814237c75cSVenkat Yekkirala sksec = sk->sk_security; 56824e5ab4cbSJames Morris 568350c205f5SEric Paris ad.type = LSM_AUDIT_DATA_NET; 568448c62af6SEric Paris ad.u.net = &net; 568548c62af6SEric Paris ad.u.net->netif = ifindex; 568648c62af6SEric Paris ad.u.net->family = family; 5687d8395c87SPaul Moore if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) 5688d8395c87SPaul Moore return NF_DROP; 5689d8395c87SPaul Moore 569058bfbb51SPaul Moore if (selinux_secmark_enabled()) 56916b6bc620SStephen Smalley if (avc_has_perm(&selinux_state, 56926b6bc620SStephen Smalley sksec->sid, skb->secmark, 5693d8395c87SPaul Moore SECCLASS_PACKET, PACKET__SEND, &ad)) 56942fe66ec2SEric Paris return NF_DROP_ERR(-ECONNREFUSED); 56951da177e4SLinus Torvalds 5696d8395c87SPaul Moore if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) 56972fe66ec2SEric Paris return NF_DROP_ERR(-ECONNREFUSED); 5698effad8dfSPaul Moore 5699effad8dfSPaul Moore return NF_ACCEPT; 5700effad8dfSPaul Moore } 5701effad8dfSPaul Moore 5702cbe0d6e8SPaul Moore static unsigned int selinux_ip_postroute(struct sk_buff *skb, 5703cbe0d6e8SPaul Moore const struct net_device *outdev, 5704effad8dfSPaul Moore u16 family) 5705effad8dfSPaul Moore { 5706effad8dfSPaul Moore u32 secmark_perm; 5707effad8dfSPaul Moore u32 peer_sid; 5708cbe0d6e8SPaul Moore int ifindex = outdev->ifindex; 5709effad8dfSPaul Moore struct sock *sk; 57102bf49690SThomas Liu struct common_audit_data ad; 571148c62af6SEric Paris struct lsm_network_audit net = {0,}; 5712effad8dfSPaul Moore char *addrp; 5713effad8dfSPaul Moore u8 secmark_active; 5714effad8dfSPaul Moore u8 peerlbl_active; 5715effad8dfSPaul Moore 5716effad8dfSPaul Moore /* If any sort of compatibility mode is enabled then handoff processing 5717effad8dfSPaul Moore * to the selinux_ip_postroute_compat() function to deal with the 5718effad8dfSPaul Moore * special handling. We do this in an attempt to keep this function 5719effad8dfSPaul Moore * as fast and as clean as possible. */ 5720aa8e712cSStephen Smalley if (!selinux_policycap_netpeer()) 5721d8395c87SPaul Moore return selinux_ip_postroute_compat(skb, ifindex, family); 5722c0828e50SPaul Moore 5723effad8dfSPaul Moore secmark_active = selinux_secmark_enabled(); 57242be4d74fSChris PeBenito peerlbl_active = selinux_peerlbl_enabled(); 5725effad8dfSPaul Moore if (!secmark_active && !peerlbl_active) 5726effad8dfSPaul Moore return NF_ACCEPT; 5727effad8dfSPaul Moore 572854abc686SEric Dumazet sk = skb_to_full_sk(skb); 5729c0828e50SPaul Moore 5730effad8dfSPaul Moore #ifdef CONFIG_XFRM 5731effad8dfSPaul Moore /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec 5732effad8dfSPaul Moore * packet transformation so allow the packet to pass without any checks 5733effad8dfSPaul Moore * since we'll have another chance to perform access control checks 5734effad8dfSPaul Moore * when the packet is on it's final way out. 5735effad8dfSPaul Moore * NOTE: there appear to be some IPv6 multicast cases where skb->dst 5736c0828e50SPaul Moore * is NULL, in this case go ahead and apply access control. 5737c0828e50SPaul Moore * NOTE: if this is a local socket (skb->sk != NULL) that is in the 5738c0828e50SPaul Moore * TCP listening state we cannot wait until the XFRM processing 5739c0828e50SPaul Moore * is done as we will miss out on the SA label if we do; 5740c0828e50SPaul Moore * unfortunately, this means more work, but it is only once per 5741c0828e50SPaul Moore * connection. */ 5742c0828e50SPaul Moore if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL && 5743e446f9dfSEric Dumazet !(sk && sk_listener(sk))) 5744effad8dfSPaul Moore return NF_ACCEPT; 5745effad8dfSPaul Moore #endif 5746effad8dfSPaul Moore 5747d8395c87SPaul Moore if (sk == NULL) { 5748446b8024SPaul Moore /* Without an associated socket the packet is either coming 5749446b8024SPaul Moore * from the kernel or it is being forwarded; check the packet 5750446b8024SPaul Moore * to determine which and if the packet is being forwarded 5751446b8024SPaul Moore * query the packet directly to determine the security label. */ 57524a7ab3dcSSteffen Klassert if (skb->skb_iif) { 5753d8395c87SPaul Moore secmark_perm = PACKET__FORWARD_OUT; 5754d8395c87SPaul Moore if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) 575504f6d70fSEric Paris return NF_DROP; 57564a7ab3dcSSteffen Klassert } else { 57574a7ab3dcSSteffen Klassert secmark_perm = PACKET__SEND; 5758d8395c87SPaul Moore peer_sid = SECINITSID_KERNEL; 57594a7ab3dcSSteffen Klassert } 5760e446f9dfSEric Dumazet } else if (sk_listener(sk)) { 5761446b8024SPaul Moore /* Locally generated packet but the associated socket is in the 5762446b8024SPaul Moore * listening state which means this is a SYN-ACK packet. In 5763446b8024SPaul Moore * this particular case the correct security label is assigned 5764446b8024SPaul Moore * to the connection/request_sock but unfortunately we can't 5765446b8024SPaul Moore * query the request_sock as it isn't queued on the parent 5766446b8024SPaul Moore * socket until after the SYN-ACK packet is sent; the only 5767446b8024SPaul Moore * viable choice is to regenerate the label like we do in 5768446b8024SPaul Moore * selinux_inet_conn_request(). See also selinux_ip_output() 5769446b8024SPaul Moore * for similar problems. */ 5770446b8024SPaul Moore u32 skb_sid; 5771e446f9dfSEric Dumazet struct sk_security_struct *sksec; 5772e446f9dfSEric Dumazet 5773e446f9dfSEric Dumazet sksec = sk->sk_security; 5774446b8024SPaul Moore if (selinux_skb_peerlbl_sid(skb, family, &skb_sid)) 5775446b8024SPaul Moore return NF_DROP; 5776c0828e50SPaul Moore /* At this point, if the returned skb peerlbl is SECSID_NULL 5777c0828e50SPaul Moore * and the packet has been through at least one XFRM 5778c0828e50SPaul Moore * transformation then we must be dealing with the "final" 5779c0828e50SPaul Moore * form of labeled IPsec packet; since we've already applied 5780c0828e50SPaul Moore * all of our access controls on this packet we can safely 5781c0828e50SPaul Moore * pass the packet. */ 5782c0828e50SPaul Moore if (skb_sid == SECSID_NULL) { 5783c0828e50SPaul Moore switch (family) { 5784c0828e50SPaul Moore case PF_INET: 5785c0828e50SPaul Moore if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) 5786c0828e50SPaul Moore return NF_ACCEPT; 5787c0828e50SPaul Moore break; 5788c0828e50SPaul Moore case PF_INET6: 5789c0828e50SPaul Moore if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) 5790c0828e50SPaul Moore return NF_ACCEPT; 5791a7a91a19SPaul Moore break; 5792c0828e50SPaul Moore default: 5793c0828e50SPaul Moore return NF_DROP_ERR(-ECONNREFUSED); 5794c0828e50SPaul Moore } 5795c0828e50SPaul Moore } 5796446b8024SPaul Moore if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid)) 5797446b8024SPaul Moore return NF_DROP; 5798446b8024SPaul Moore secmark_perm = PACKET__SEND; 5799d8395c87SPaul Moore } else { 5800446b8024SPaul Moore /* Locally generated packet, fetch the security label from the 5801446b8024SPaul Moore * associated socket. */ 5802effad8dfSPaul Moore struct sk_security_struct *sksec = sk->sk_security; 5803effad8dfSPaul Moore peer_sid = sksec->sid; 5804effad8dfSPaul Moore secmark_perm = PACKET__SEND; 5805effad8dfSPaul Moore } 5806effad8dfSPaul Moore 580750c205f5SEric Paris ad.type = LSM_AUDIT_DATA_NET; 580848c62af6SEric Paris ad.u.net = &net; 580948c62af6SEric Paris ad.u.net->netif = ifindex; 581048c62af6SEric Paris ad.u.net->family = family; 5811d8395c87SPaul Moore if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) 581204f6d70fSEric Paris return NF_DROP; 5813d8395c87SPaul Moore 5814effad8dfSPaul Moore if (secmark_active) 58156b6bc620SStephen Smalley if (avc_has_perm(&selinux_state, 58166b6bc620SStephen Smalley peer_sid, skb->secmark, 5817effad8dfSPaul Moore SECCLASS_PACKET, secmark_perm, &ad)) 58181f1aaf82SEric Paris return NF_DROP_ERR(-ECONNREFUSED); 5819effad8dfSPaul Moore 5820effad8dfSPaul Moore if (peerlbl_active) { 5821effad8dfSPaul Moore u32 if_sid; 5822effad8dfSPaul Moore u32 node_sid; 5823effad8dfSPaul Moore 5824cbe0d6e8SPaul Moore if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid)) 582504f6d70fSEric Paris return NF_DROP; 58266b6bc620SStephen Smalley if (avc_has_perm(&selinux_state, 58276b6bc620SStephen Smalley peer_sid, if_sid, 5828effad8dfSPaul Moore SECCLASS_NETIF, NETIF__EGRESS, &ad)) 58291f1aaf82SEric Paris return NF_DROP_ERR(-ECONNREFUSED); 5830effad8dfSPaul Moore 5831effad8dfSPaul Moore if (sel_netnode_sid(addrp, family, &node_sid)) 583204f6d70fSEric Paris return NF_DROP; 58336b6bc620SStephen Smalley if (avc_has_perm(&selinux_state, 58346b6bc620SStephen Smalley peer_sid, node_sid, 5835effad8dfSPaul Moore SECCLASS_NODE, NODE__SENDTO, &ad)) 58361f1aaf82SEric Paris return NF_DROP_ERR(-ECONNREFUSED); 5837effad8dfSPaul Moore } 5838effad8dfSPaul Moore 5839effad8dfSPaul Moore return NF_ACCEPT; 5840effad8dfSPaul Moore } 5841effad8dfSPaul Moore 584206198b34SEric W. Biederman static unsigned int selinux_ipv4_postroute(void *priv, 5843a224be76SDavid S. Miller struct sk_buff *skb, 5844238e54c9SDavid S. Miller const struct nf_hook_state *state) 58451da177e4SLinus Torvalds { 5846238e54c9SDavid S. Miller return selinux_ip_postroute(skb, state->out, PF_INET); 58471da177e4SLinus Torvalds } 58481da177e4SLinus Torvalds 58491a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6) 585006198b34SEric W. Biederman static unsigned int selinux_ipv6_postroute(void *priv, 5851a224be76SDavid S. Miller struct sk_buff *skb, 5852238e54c9SDavid S. Miller const struct nf_hook_state *state) 58531da177e4SLinus Torvalds { 5854238e54c9SDavid S. Miller return selinux_ip_postroute(skb, state->out, PF_INET6); 58551da177e4SLinus Torvalds } 58561da177e4SLinus Torvalds #endif /* IPV6 */ 58571da177e4SLinus Torvalds 58581da177e4SLinus Torvalds #endif /* CONFIG_NETFILTER */ 58591da177e4SLinus Torvalds 58601da177e4SLinus Torvalds static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) 58611da177e4SLinus Torvalds { 5862941fc5b2SStephen Smalley return selinux_nlmsg_perm(sk, skb); 58631da177e4SLinus Torvalds } 58641da177e4SLinus Torvalds 5865be0554c9SStephen Smalley static int ipc_alloc_security(struct kern_ipc_perm *perm, 58661da177e4SLinus Torvalds u16 sclass) 58671da177e4SLinus Torvalds { 58681da177e4SLinus Torvalds struct ipc_security_struct *isec; 58691da177e4SLinus Torvalds 587089d155efSJames Morris isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL); 58711da177e4SLinus Torvalds if (!isec) 58721da177e4SLinus Torvalds return -ENOMEM; 58731da177e4SLinus Torvalds 58741da177e4SLinus Torvalds isec->sclass = sclass; 5875be0554c9SStephen Smalley isec->sid = current_sid(); 58761da177e4SLinus Torvalds perm->security = isec; 58771da177e4SLinus Torvalds 58781da177e4SLinus Torvalds return 0; 58791da177e4SLinus Torvalds } 58801da177e4SLinus Torvalds 58811da177e4SLinus Torvalds static void ipc_free_security(struct kern_ipc_perm *perm) 58821da177e4SLinus Torvalds { 58831da177e4SLinus Torvalds struct ipc_security_struct *isec = perm->security; 58841da177e4SLinus Torvalds perm->security = NULL; 58851da177e4SLinus Torvalds kfree(isec); 58861da177e4SLinus Torvalds } 58871da177e4SLinus Torvalds 58881da177e4SLinus Torvalds static int msg_msg_alloc_security(struct msg_msg *msg) 58891da177e4SLinus Torvalds { 58901da177e4SLinus Torvalds struct msg_security_struct *msec; 58911da177e4SLinus Torvalds 589289d155efSJames Morris msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL); 58931da177e4SLinus Torvalds if (!msec) 58941da177e4SLinus Torvalds return -ENOMEM; 58951da177e4SLinus Torvalds 58961da177e4SLinus Torvalds msec->sid = SECINITSID_UNLABELED; 58971da177e4SLinus Torvalds msg->security = msec; 58981da177e4SLinus Torvalds 58991da177e4SLinus Torvalds return 0; 59001da177e4SLinus Torvalds } 59011da177e4SLinus Torvalds 59021da177e4SLinus Torvalds static void msg_msg_free_security(struct msg_msg *msg) 59031da177e4SLinus Torvalds { 59041da177e4SLinus Torvalds struct msg_security_struct *msec = msg->security; 59051da177e4SLinus Torvalds 59061da177e4SLinus Torvalds msg->security = NULL; 59071da177e4SLinus Torvalds kfree(msec); 59081da177e4SLinus Torvalds } 59091da177e4SLinus Torvalds 59101da177e4SLinus Torvalds static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, 59116af963f1SStephen Smalley u32 perms) 59121da177e4SLinus Torvalds { 59131da177e4SLinus Torvalds struct ipc_security_struct *isec; 59142bf49690SThomas Liu struct common_audit_data ad; 5915275bb41eSDavid Howells u32 sid = current_sid(); 59161da177e4SLinus Torvalds 59171da177e4SLinus Torvalds isec = ipc_perms->security; 59181da177e4SLinus Torvalds 591950c205f5SEric Paris ad.type = LSM_AUDIT_DATA_IPC; 59201da177e4SLinus Torvalds ad.u.ipc_id = ipc_perms->key; 59211da177e4SLinus Torvalds 59226b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 59236b6bc620SStephen Smalley sid, isec->sid, isec->sclass, perms, &ad); 59241da177e4SLinus Torvalds } 59251da177e4SLinus Torvalds 59261da177e4SLinus Torvalds static int selinux_msg_msg_alloc_security(struct msg_msg *msg) 59271da177e4SLinus Torvalds { 59281da177e4SLinus Torvalds return msg_msg_alloc_security(msg); 59291da177e4SLinus Torvalds } 59301da177e4SLinus Torvalds 59311da177e4SLinus Torvalds static void selinux_msg_msg_free_security(struct msg_msg *msg) 59321da177e4SLinus Torvalds { 59331da177e4SLinus Torvalds msg_msg_free_security(msg); 59341da177e4SLinus Torvalds } 59351da177e4SLinus Torvalds 59361da177e4SLinus Torvalds /* message queue security operations */ 5937d8c6e854SEric W. Biederman static int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq) 59381da177e4SLinus Torvalds { 59391da177e4SLinus Torvalds struct ipc_security_struct *isec; 59402bf49690SThomas Liu struct common_audit_data ad; 5941275bb41eSDavid Howells u32 sid = current_sid(); 59421da177e4SLinus Torvalds int rc; 59431da177e4SLinus Torvalds 5944d8c6e854SEric W. Biederman rc = ipc_alloc_security(msq, SECCLASS_MSGQ); 59451da177e4SLinus Torvalds if (rc) 59461da177e4SLinus Torvalds return rc; 59471da177e4SLinus Torvalds 5948d8c6e854SEric W. Biederman isec = msq->security; 59491da177e4SLinus Torvalds 595050c205f5SEric Paris ad.type = LSM_AUDIT_DATA_IPC; 5951d8c6e854SEric W. Biederman ad.u.ipc_id = msq->key; 59521da177e4SLinus Torvalds 59536b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 59546b6bc620SStephen Smalley sid, isec->sid, SECCLASS_MSGQ, 59551da177e4SLinus Torvalds MSGQ__CREATE, &ad); 59561da177e4SLinus Torvalds if (rc) { 5957d8c6e854SEric W. Biederman ipc_free_security(msq); 59581da177e4SLinus Torvalds return rc; 59591da177e4SLinus Torvalds } 59601da177e4SLinus Torvalds return 0; 59611da177e4SLinus Torvalds } 59621da177e4SLinus Torvalds 5963d8c6e854SEric W. Biederman static void selinux_msg_queue_free_security(struct kern_ipc_perm *msq) 59641da177e4SLinus Torvalds { 5965d8c6e854SEric W. Biederman ipc_free_security(msq); 59661da177e4SLinus Torvalds } 59671da177e4SLinus Torvalds 5968d8c6e854SEric W. Biederman static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) 59691da177e4SLinus Torvalds { 59701da177e4SLinus Torvalds struct ipc_security_struct *isec; 59712bf49690SThomas Liu struct common_audit_data ad; 5972275bb41eSDavid Howells u32 sid = current_sid(); 59731da177e4SLinus Torvalds 5974d8c6e854SEric W. Biederman isec = msq->security; 59751da177e4SLinus Torvalds 597650c205f5SEric Paris ad.type = LSM_AUDIT_DATA_IPC; 5977d8c6e854SEric W. Biederman ad.u.ipc_id = msq->key; 59781da177e4SLinus Torvalds 59796b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 59806b6bc620SStephen Smalley sid, isec->sid, SECCLASS_MSGQ, 59811da177e4SLinus Torvalds MSGQ__ASSOCIATE, &ad); 59821da177e4SLinus Torvalds } 59831da177e4SLinus Torvalds 5984d8c6e854SEric W. Biederman static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd) 59851da177e4SLinus Torvalds { 59861da177e4SLinus Torvalds int err; 59871da177e4SLinus Torvalds int perms; 59881da177e4SLinus Torvalds 59891da177e4SLinus Torvalds switch (cmd) { 59901da177e4SLinus Torvalds case IPC_INFO: 59911da177e4SLinus Torvalds case MSG_INFO: 59921da177e4SLinus Torvalds /* No specific object, just general system-wide information. */ 59936b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 59946b6bc620SStephen Smalley current_sid(), SECINITSID_KERNEL, 5995be0554c9SStephen Smalley SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); 59961da177e4SLinus Torvalds case IPC_STAT: 59971da177e4SLinus Torvalds case MSG_STAT: 599823c8cec8SDavidlohr Bueso case MSG_STAT_ANY: 59991da177e4SLinus Torvalds perms = MSGQ__GETATTR | MSGQ__ASSOCIATE; 60001da177e4SLinus Torvalds break; 60011da177e4SLinus Torvalds case IPC_SET: 60021da177e4SLinus Torvalds perms = MSGQ__SETATTR; 60031da177e4SLinus Torvalds break; 60041da177e4SLinus Torvalds case IPC_RMID: 60051da177e4SLinus Torvalds perms = MSGQ__DESTROY; 60061da177e4SLinus Torvalds break; 60071da177e4SLinus Torvalds default: 60081da177e4SLinus Torvalds return 0; 60091da177e4SLinus Torvalds } 60101da177e4SLinus Torvalds 6011d8c6e854SEric W. Biederman err = ipc_has_perm(msq, perms); 60121da177e4SLinus Torvalds return err; 60131da177e4SLinus Torvalds } 60141da177e4SLinus Torvalds 6015d8c6e854SEric W. Biederman static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg) 60161da177e4SLinus Torvalds { 60171da177e4SLinus Torvalds struct ipc_security_struct *isec; 60181da177e4SLinus Torvalds struct msg_security_struct *msec; 60192bf49690SThomas Liu struct common_audit_data ad; 6020275bb41eSDavid Howells u32 sid = current_sid(); 60211da177e4SLinus Torvalds int rc; 60221da177e4SLinus Torvalds 6023d8c6e854SEric W. Biederman isec = msq->security; 60241da177e4SLinus Torvalds msec = msg->security; 60251da177e4SLinus Torvalds 60261da177e4SLinus Torvalds /* 60271da177e4SLinus Torvalds * First time through, need to assign label to the message 60281da177e4SLinus Torvalds */ 60291da177e4SLinus Torvalds if (msec->sid == SECINITSID_UNLABELED) { 60301da177e4SLinus Torvalds /* 60311da177e4SLinus Torvalds * Compute new sid based on current process and 60321da177e4SLinus Torvalds * message queue this message will be stored in 60331da177e4SLinus Torvalds */ 6034aa8e712cSStephen Smalley rc = security_transition_sid(&selinux_state, sid, isec->sid, 6035aa8e712cSStephen Smalley SECCLASS_MSG, NULL, &msec->sid); 60361da177e4SLinus Torvalds if (rc) 60371da177e4SLinus Torvalds return rc; 60381da177e4SLinus Torvalds } 60391da177e4SLinus Torvalds 604050c205f5SEric Paris ad.type = LSM_AUDIT_DATA_IPC; 6041d8c6e854SEric W. Biederman ad.u.ipc_id = msq->key; 60421da177e4SLinus Torvalds 60431da177e4SLinus Torvalds /* Can this process write to the queue? */ 60446b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 60456b6bc620SStephen Smalley sid, isec->sid, SECCLASS_MSGQ, 60461da177e4SLinus Torvalds MSGQ__WRITE, &ad); 60471da177e4SLinus Torvalds if (!rc) 60481da177e4SLinus Torvalds /* Can this process send the message */ 60496b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 60506b6bc620SStephen Smalley sid, msec->sid, SECCLASS_MSG, 6051275bb41eSDavid Howells MSG__SEND, &ad); 60521da177e4SLinus Torvalds if (!rc) 60531da177e4SLinus Torvalds /* Can the message be put in the queue? */ 60546b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 60556b6bc620SStephen Smalley msec->sid, isec->sid, SECCLASS_MSGQ, 6056275bb41eSDavid Howells MSGQ__ENQUEUE, &ad); 60571da177e4SLinus Torvalds 60581da177e4SLinus Torvalds return rc; 60591da177e4SLinus Torvalds } 60601da177e4SLinus Torvalds 6061d8c6e854SEric W. Biederman static int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg, 60621da177e4SLinus Torvalds struct task_struct *target, 60631da177e4SLinus Torvalds long type, int mode) 60641da177e4SLinus Torvalds { 60651da177e4SLinus Torvalds struct ipc_security_struct *isec; 60661da177e4SLinus Torvalds struct msg_security_struct *msec; 60672bf49690SThomas Liu struct common_audit_data ad; 6068275bb41eSDavid Howells u32 sid = task_sid(target); 60691da177e4SLinus Torvalds int rc; 60701da177e4SLinus Torvalds 6071d8c6e854SEric W. Biederman isec = msq->security; 60721da177e4SLinus Torvalds msec = msg->security; 60731da177e4SLinus Torvalds 607450c205f5SEric Paris ad.type = LSM_AUDIT_DATA_IPC; 6075d8c6e854SEric W. Biederman ad.u.ipc_id = msq->key; 60761da177e4SLinus Torvalds 60776b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 60786b6bc620SStephen Smalley sid, isec->sid, 60791da177e4SLinus Torvalds SECCLASS_MSGQ, MSGQ__READ, &ad); 60801da177e4SLinus Torvalds if (!rc) 60816b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 60826b6bc620SStephen Smalley sid, msec->sid, 60831da177e4SLinus Torvalds SECCLASS_MSG, MSG__RECEIVE, &ad); 60841da177e4SLinus Torvalds return rc; 60851da177e4SLinus Torvalds } 60861da177e4SLinus Torvalds 60871da177e4SLinus Torvalds /* Shared Memory security operations */ 60887191adffSEric W. Biederman static int selinux_shm_alloc_security(struct kern_ipc_perm *shp) 60891da177e4SLinus Torvalds { 60901da177e4SLinus Torvalds struct ipc_security_struct *isec; 60912bf49690SThomas Liu struct common_audit_data ad; 6092275bb41eSDavid Howells u32 sid = current_sid(); 60931da177e4SLinus Torvalds int rc; 60941da177e4SLinus Torvalds 60957191adffSEric W. Biederman rc = ipc_alloc_security(shp, SECCLASS_SHM); 60961da177e4SLinus Torvalds if (rc) 60971da177e4SLinus Torvalds return rc; 60981da177e4SLinus Torvalds 60997191adffSEric W. Biederman isec = shp->security; 61001da177e4SLinus Torvalds 610150c205f5SEric Paris ad.type = LSM_AUDIT_DATA_IPC; 61027191adffSEric W. Biederman ad.u.ipc_id = shp->key; 61031da177e4SLinus Torvalds 61046b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 61056b6bc620SStephen Smalley sid, isec->sid, SECCLASS_SHM, 61061da177e4SLinus Torvalds SHM__CREATE, &ad); 61071da177e4SLinus Torvalds if (rc) { 61087191adffSEric W. Biederman ipc_free_security(shp); 61091da177e4SLinus Torvalds return rc; 61101da177e4SLinus Torvalds } 61111da177e4SLinus Torvalds return 0; 61121da177e4SLinus Torvalds } 61131da177e4SLinus Torvalds 61147191adffSEric W. Biederman static void selinux_shm_free_security(struct kern_ipc_perm *shp) 61151da177e4SLinus Torvalds { 61167191adffSEric W. Biederman ipc_free_security(shp); 61171da177e4SLinus Torvalds } 61181da177e4SLinus Torvalds 61197191adffSEric W. Biederman static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg) 61201da177e4SLinus Torvalds { 61211da177e4SLinus Torvalds struct ipc_security_struct *isec; 61222bf49690SThomas Liu struct common_audit_data ad; 6123275bb41eSDavid Howells u32 sid = current_sid(); 61241da177e4SLinus Torvalds 61257191adffSEric W. Biederman isec = shp->security; 61261da177e4SLinus Torvalds 612750c205f5SEric Paris ad.type = LSM_AUDIT_DATA_IPC; 61287191adffSEric W. Biederman ad.u.ipc_id = shp->key; 61291da177e4SLinus Torvalds 61306b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 61316b6bc620SStephen Smalley sid, isec->sid, SECCLASS_SHM, 61321da177e4SLinus Torvalds SHM__ASSOCIATE, &ad); 61331da177e4SLinus Torvalds } 61341da177e4SLinus Torvalds 61351da177e4SLinus Torvalds /* Note, at this point, shp is locked down */ 61367191adffSEric W. Biederman static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd) 61371da177e4SLinus Torvalds { 61381da177e4SLinus Torvalds int perms; 61391da177e4SLinus Torvalds int err; 61401da177e4SLinus Torvalds 61411da177e4SLinus Torvalds switch (cmd) { 61421da177e4SLinus Torvalds case IPC_INFO: 61431da177e4SLinus Torvalds case SHM_INFO: 61441da177e4SLinus Torvalds /* No specific object, just general system-wide information. */ 61456b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 61466b6bc620SStephen Smalley current_sid(), SECINITSID_KERNEL, 6147be0554c9SStephen Smalley SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); 61481da177e4SLinus Torvalds case IPC_STAT: 61491da177e4SLinus Torvalds case SHM_STAT: 6150c21a6970SDavidlohr Bueso case SHM_STAT_ANY: 61511da177e4SLinus Torvalds perms = SHM__GETATTR | SHM__ASSOCIATE; 61521da177e4SLinus Torvalds break; 61531da177e4SLinus Torvalds case IPC_SET: 61541da177e4SLinus Torvalds perms = SHM__SETATTR; 61551da177e4SLinus Torvalds break; 61561da177e4SLinus Torvalds case SHM_LOCK: 61571da177e4SLinus Torvalds case SHM_UNLOCK: 61581da177e4SLinus Torvalds perms = SHM__LOCK; 61591da177e4SLinus Torvalds break; 61601da177e4SLinus Torvalds case IPC_RMID: 61611da177e4SLinus Torvalds perms = SHM__DESTROY; 61621da177e4SLinus Torvalds break; 61631da177e4SLinus Torvalds default: 61641da177e4SLinus Torvalds return 0; 61651da177e4SLinus Torvalds } 61661da177e4SLinus Torvalds 61677191adffSEric W. Biederman err = ipc_has_perm(shp, perms); 61681da177e4SLinus Torvalds return err; 61691da177e4SLinus Torvalds } 61701da177e4SLinus Torvalds 61717191adffSEric W. Biederman static int selinux_shm_shmat(struct kern_ipc_perm *shp, 61721da177e4SLinus Torvalds char __user *shmaddr, int shmflg) 61731da177e4SLinus Torvalds { 61741da177e4SLinus Torvalds u32 perms; 61751da177e4SLinus Torvalds 61761da177e4SLinus Torvalds if (shmflg & SHM_RDONLY) 61771da177e4SLinus Torvalds perms = SHM__READ; 61781da177e4SLinus Torvalds else 61791da177e4SLinus Torvalds perms = SHM__READ | SHM__WRITE; 61801da177e4SLinus Torvalds 61817191adffSEric W. Biederman return ipc_has_perm(shp, perms); 61821da177e4SLinus Torvalds } 61831da177e4SLinus Torvalds 61841da177e4SLinus Torvalds /* Semaphore security operations */ 6185aefad959SEric W. Biederman static int selinux_sem_alloc_security(struct kern_ipc_perm *sma) 61861da177e4SLinus Torvalds { 61871da177e4SLinus Torvalds struct ipc_security_struct *isec; 61882bf49690SThomas Liu struct common_audit_data ad; 6189275bb41eSDavid Howells u32 sid = current_sid(); 61901da177e4SLinus Torvalds int rc; 61911da177e4SLinus Torvalds 6192aefad959SEric W. Biederman rc = ipc_alloc_security(sma, SECCLASS_SEM); 61931da177e4SLinus Torvalds if (rc) 61941da177e4SLinus Torvalds return rc; 61951da177e4SLinus Torvalds 6196aefad959SEric W. Biederman isec = sma->security; 61971da177e4SLinus Torvalds 619850c205f5SEric Paris ad.type = LSM_AUDIT_DATA_IPC; 6199aefad959SEric W. Biederman ad.u.ipc_id = sma->key; 62001da177e4SLinus Torvalds 62016b6bc620SStephen Smalley rc = avc_has_perm(&selinux_state, 62026b6bc620SStephen Smalley sid, isec->sid, SECCLASS_SEM, 62031da177e4SLinus Torvalds SEM__CREATE, &ad); 62041da177e4SLinus Torvalds if (rc) { 6205aefad959SEric W. Biederman ipc_free_security(sma); 62061da177e4SLinus Torvalds return rc; 62071da177e4SLinus Torvalds } 62081da177e4SLinus Torvalds return 0; 62091da177e4SLinus Torvalds } 62101da177e4SLinus Torvalds 6211aefad959SEric W. Biederman static void selinux_sem_free_security(struct kern_ipc_perm *sma) 62121da177e4SLinus Torvalds { 6213aefad959SEric W. Biederman ipc_free_security(sma); 62141da177e4SLinus Torvalds } 62151da177e4SLinus Torvalds 6216aefad959SEric W. Biederman static int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg) 62171da177e4SLinus Torvalds { 62181da177e4SLinus Torvalds struct ipc_security_struct *isec; 62192bf49690SThomas Liu struct common_audit_data ad; 6220275bb41eSDavid Howells u32 sid = current_sid(); 62211da177e4SLinus Torvalds 6222aefad959SEric W. Biederman isec = sma->security; 62231da177e4SLinus Torvalds 622450c205f5SEric Paris ad.type = LSM_AUDIT_DATA_IPC; 6225aefad959SEric W. Biederman ad.u.ipc_id = sma->key; 62261da177e4SLinus Torvalds 62276b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 62286b6bc620SStephen Smalley sid, isec->sid, SECCLASS_SEM, 62291da177e4SLinus Torvalds SEM__ASSOCIATE, &ad); 62301da177e4SLinus Torvalds } 62311da177e4SLinus Torvalds 62321da177e4SLinus Torvalds /* Note, at this point, sma is locked down */ 6233aefad959SEric W. Biederman static int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd) 62341da177e4SLinus Torvalds { 62351da177e4SLinus Torvalds int err; 62361da177e4SLinus Torvalds u32 perms; 62371da177e4SLinus Torvalds 62381da177e4SLinus Torvalds switch (cmd) { 62391da177e4SLinus Torvalds case IPC_INFO: 62401da177e4SLinus Torvalds case SEM_INFO: 62411da177e4SLinus Torvalds /* No specific object, just general system-wide information. */ 62426b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 62436b6bc620SStephen Smalley current_sid(), SECINITSID_KERNEL, 6244be0554c9SStephen Smalley SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); 62451da177e4SLinus Torvalds case GETPID: 62461da177e4SLinus Torvalds case GETNCNT: 62471da177e4SLinus Torvalds case GETZCNT: 62481da177e4SLinus Torvalds perms = SEM__GETATTR; 62491da177e4SLinus Torvalds break; 62501da177e4SLinus Torvalds case GETVAL: 62511da177e4SLinus Torvalds case GETALL: 62521da177e4SLinus Torvalds perms = SEM__READ; 62531da177e4SLinus Torvalds break; 62541da177e4SLinus Torvalds case SETVAL: 62551da177e4SLinus Torvalds case SETALL: 62561da177e4SLinus Torvalds perms = SEM__WRITE; 62571da177e4SLinus Torvalds break; 62581da177e4SLinus Torvalds case IPC_RMID: 62591da177e4SLinus Torvalds perms = SEM__DESTROY; 62601da177e4SLinus Torvalds break; 62611da177e4SLinus Torvalds case IPC_SET: 62621da177e4SLinus Torvalds perms = SEM__SETATTR; 62631da177e4SLinus Torvalds break; 62641da177e4SLinus Torvalds case IPC_STAT: 62651da177e4SLinus Torvalds case SEM_STAT: 6266a280d6dcSDavidlohr Bueso case SEM_STAT_ANY: 62671da177e4SLinus Torvalds perms = SEM__GETATTR | SEM__ASSOCIATE; 62681da177e4SLinus Torvalds break; 62691da177e4SLinus Torvalds default: 62701da177e4SLinus Torvalds return 0; 62711da177e4SLinus Torvalds } 62721da177e4SLinus Torvalds 6273aefad959SEric W. Biederman err = ipc_has_perm(sma, perms); 62741da177e4SLinus Torvalds return err; 62751da177e4SLinus Torvalds } 62761da177e4SLinus Torvalds 6277aefad959SEric W. Biederman static int selinux_sem_semop(struct kern_ipc_perm *sma, 62781da177e4SLinus Torvalds struct sembuf *sops, unsigned nsops, int alter) 62791da177e4SLinus Torvalds { 62801da177e4SLinus Torvalds u32 perms; 62811da177e4SLinus Torvalds 62821da177e4SLinus Torvalds if (alter) 62831da177e4SLinus Torvalds perms = SEM__READ | SEM__WRITE; 62841da177e4SLinus Torvalds else 62851da177e4SLinus Torvalds perms = SEM__READ; 62861da177e4SLinus Torvalds 6287aefad959SEric W. Biederman return ipc_has_perm(sma, perms); 62881da177e4SLinus Torvalds } 62891da177e4SLinus Torvalds 62901da177e4SLinus Torvalds static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) 62911da177e4SLinus Torvalds { 62921da177e4SLinus Torvalds u32 av = 0; 62931da177e4SLinus Torvalds 62941da177e4SLinus Torvalds av = 0; 62951da177e4SLinus Torvalds if (flag & S_IRUGO) 62961da177e4SLinus Torvalds av |= IPC__UNIX_READ; 62971da177e4SLinus Torvalds if (flag & S_IWUGO) 62981da177e4SLinus Torvalds av |= IPC__UNIX_WRITE; 62991da177e4SLinus Torvalds 63001da177e4SLinus Torvalds if (av == 0) 63011da177e4SLinus Torvalds return 0; 63021da177e4SLinus Torvalds 63036af963f1SStephen Smalley return ipc_has_perm(ipcp, av); 63041da177e4SLinus Torvalds } 63051da177e4SLinus Torvalds 6306713a04aeSAhmed S. Darwish static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) 6307713a04aeSAhmed S. Darwish { 6308713a04aeSAhmed S. Darwish struct ipc_security_struct *isec = ipcp->security; 6309713a04aeSAhmed S. Darwish *secid = isec->sid; 6310713a04aeSAhmed S. Darwish } 6311713a04aeSAhmed S. Darwish 63121da177e4SLinus Torvalds static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode) 63131da177e4SLinus Torvalds { 63141da177e4SLinus Torvalds if (inode) 63151da177e4SLinus Torvalds inode_doinit_with_dentry(inode, dentry); 63161da177e4SLinus Torvalds } 63171da177e4SLinus Torvalds 63181da177e4SLinus Torvalds static int selinux_getprocattr(struct task_struct *p, 631904ff9708SAl Viro char *name, char **value) 63201da177e4SLinus Torvalds { 6321275bb41eSDavid Howells const struct task_security_struct *__tsec; 63228c8570fbSDustin Kirkland u32 sid; 63231da177e4SLinus Torvalds int error; 632404ff9708SAl Viro unsigned len; 63251da177e4SLinus Torvalds 6326275bb41eSDavid Howells rcu_read_lock(); 6327275bb41eSDavid Howells __tsec = __task_cred(p)->security; 63281da177e4SLinus Torvalds 6329be0554c9SStephen Smalley if (current != p) { 63306b6bc620SStephen Smalley error = avc_has_perm(&selinux_state, 63316b6bc620SStephen Smalley current_sid(), __tsec->sid, 6332be0554c9SStephen Smalley SECCLASS_PROCESS, PROCESS__GETATTR, NULL); 6333be0554c9SStephen Smalley if (error) 6334be0554c9SStephen Smalley goto bad; 6335be0554c9SStephen Smalley } 6336be0554c9SStephen Smalley 63371da177e4SLinus Torvalds if (!strcmp(name, "current")) 6338275bb41eSDavid Howells sid = __tsec->sid; 63391da177e4SLinus Torvalds else if (!strcmp(name, "prev")) 6340275bb41eSDavid Howells sid = __tsec->osid; 63411da177e4SLinus Torvalds else if (!strcmp(name, "exec")) 6342275bb41eSDavid Howells sid = __tsec->exec_sid; 63431da177e4SLinus Torvalds else if (!strcmp(name, "fscreate")) 6344275bb41eSDavid Howells sid = __tsec->create_sid; 63454eb582cfSMichael LeMay else if (!strcmp(name, "keycreate")) 6346275bb41eSDavid Howells sid = __tsec->keycreate_sid; 634742c3e03eSEric Paris else if (!strcmp(name, "sockcreate")) 6348275bb41eSDavid Howells sid = __tsec->sockcreate_sid; 6349be0554c9SStephen Smalley else { 6350be0554c9SStephen Smalley error = -EINVAL; 6351be0554c9SStephen Smalley goto bad; 6352be0554c9SStephen Smalley } 6353275bb41eSDavid Howells rcu_read_unlock(); 63541da177e4SLinus Torvalds 63551da177e4SLinus Torvalds if (!sid) 63561da177e4SLinus Torvalds return 0; 63571da177e4SLinus Torvalds 6358aa8e712cSStephen Smalley error = security_sid_to_context(&selinux_state, sid, value, &len); 635904ff9708SAl Viro if (error) 636004ff9708SAl Viro return error; 636104ff9708SAl Viro return len; 6362275bb41eSDavid Howells 6363be0554c9SStephen Smalley bad: 6364275bb41eSDavid Howells rcu_read_unlock(); 6365be0554c9SStephen Smalley return error; 63661da177e4SLinus Torvalds } 63671da177e4SLinus Torvalds 6368b21507e2SStephen Smalley static int selinux_setprocattr(const char *name, void *value, size_t size) 63691da177e4SLinus Torvalds { 63701da177e4SLinus Torvalds struct task_security_struct *tsec; 6371d84f4f99SDavid Howells struct cred *new; 6372be0554c9SStephen Smalley u32 mysid = current_sid(), sid = 0, ptsid; 63731da177e4SLinus Torvalds int error; 63741da177e4SLinus Torvalds char *str = value; 63751da177e4SLinus Torvalds 63761da177e4SLinus Torvalds /* 63771da177e4SLinus Torvalds * Basic control over ability to set these attributes at all. 63781da177e4SLinus Torvalds */ 63791da177e4SLinus Torvalds if (!strcmp(name, "exec")) 63806b6bc620SStephen Smalley error = avc_has_perm(&selinux_state, 63816b6bc620SStephen Smalley mysid, mysid, SECCLASS_PROCESS, 6382be0554c9SStephen Smalley PROCESS__SETEXEC, NULL); 63831da177e4SLinus Torvalds else if (!strcmp(name, "fscreate")) 63846b6bc620SStephen Smalley error = avc_has_perm(&selinux_state, 63856b6bc620SStephen Smalley mysid, mysid, SECCLASS_PROCESS, 6386be0554c9SStephen Smalley PROCESS__SETFSCREATE, NULL); 63874eb582cfSMichael LeMay else if (!strcmp(name, "keycreate")) 63886b6bc620SStephen Smalley error = avc_has_perm(&selinux_state, 63896b6bc620SStephen Smalley mysid, mysid, SECCLASS_PROCESS, 6390be0554c9SStephen Smalley PROCESS__SETKEYCREATE, NULL); 639142c3e03eSEric Paris else if (!strcmp(name, "sockcreate")) 63926b6bc620SStephen Smalley error = avc_has_perm(&selinux_state, 63936b6bc620SStephen Smalley mysid, mysid, SECCLASS_PROCESS, 6394be0554c9SStephen Smalley PROCESS__SETSOCKCREATE, NULL); 63951da177e4SLinus Torvalds else if (!strcmp(name, "current")) 63966b6bc620SStephen Smalley error = avc_has_perm(&selinux_state, 63976b6bc620SStephen Smalley mysid, mysid, SECCLASS_PROCESS, 6398be0554c9SStephen Smalley PROCESS__SETCURRENT, NULL); 63991da177e4SLinus Torvalds else 64001da177e4SLinus Torvalds error = -EINVAL; 64011da177e4SLinus Torvalds if (error) 64021da177e4SLinus Torvalds return error; 64031da177e4SLinus Torvalds 64041da177e4SLinus Torvalds /* Obtain a SID for the context, if one was specified. */ 6405a050a570SStephen Smalley if (size && str[0] && str[0] != '\n') { 64061da177e4SLinus Torvalds if (str[size-1] == '\n') { 64071da177e4SLinus Torvalds str[size-1] = 0; 64081da177e4SLinus Torvalds size--; 64091da177e4SLinus Torvalds } 6410aa8e712cSStephen Smalley error = security_context_to_sid(&selinux_state, value, size, 6411aa8e712cSStephen Smalley &sid, GFP_KERNEL); 641212b29f34SStephen Smalley if (error == -EINVAL && !strcmp(name, "fscreate")) { 6413db59000aSStephen Smalley if (!has_cap_mac_admin(true)) { 6414d6ea83ecSEric Paris struct audit_buffer *ab; 6415d6ea83ecSEric Paris size_t audit_size; 6416d6ea83ecSEric Paris 6417d6ea83ecSEric Paris /* We strip a nul only if it is at the end, otherwise the 6418d6ea83ecSEric Paris * context contains a nul and we should audit that */ 6419d6ea83ecSEric Paris if (str[size - 1] == '\0') 6420d6ea83ecSEric Paris audit_size = size - 1; 6421d6ea83ecSEric Paris else 6422d6ea83ecSEric Paris audit_size = size; 6423cdfb6b34SRichard Guy Briggs ab = audit_log_start(audit_context(), 6424cdfb6b34SRichard Guy Briggs GFP_ATOMIC, 6425cdfb6b34SRichard Guy Briggs AUDIT_SELINUX_ERR); 6426d6ea83ecSEric Paris audit_log_format(ab, "op=fscreate invalid_context="); 6427d6ea83ecSEric Paris audit_log_n_untrustedstring(ab, value, audit_size); 6428d6ea83ecSEric Paris audit_log_end(ab); 6429d6ea83ecSEric Paris 643012b29f34SStephen Smalley return error; 6431d6ea83ecSEric Paris } 6432aa8e712cSStephen Smalley error = security_context_to_sid_force( 6433aa8e712cSStephen Smalley &selinux_state, 6434aa8e712cSStephen Smalley value, size, &sid); 643512b29f34SStephen Smalley } 64361da177e4SLinus Torvalds if (error) 64371da177e4SLinus Torvalds return error; 64381da177e4SLinus Torvalds } 64391da177e4SLinus Torvalds 6440d84f4f99SDavid Howells new = prepare_creds(); 6441d84f4f99SDavid Howells if (!new) 6442d84f4f99SDavid Howells return -ENOMEM; 6443d84f4f99SDavid Howells 64441da177e4SLinus Torvalds /* Permission checking based on the specified context is 64451da177e4SLinus Torvalds performed during the actual operation (execve, 64461da177e4SLinus Torvalds open/mkdir/...), when we know the full context of the 6447d84f4f99SDavid Howells operation. See selinux_bprm_set_creds for the execve 64481da177e4SLinus Torvalds checks and may_create for the file creation checks. The 64491da177e4SLinus Torvalds operation will then fail if the context is not permitted. */ 6450d84f4f99SDavid Howells tsec = new->security; 6451d84f4f99SDavid Howells if (!strcmp(name, "exec")) { 64521da177e4SLinus Torvalds tsec->exec_sid = sid; 6453d84f4f99SDavid Howells } else if (!strcmp(name, "fscreate")) { 64541da177e4SLinus Torvalds tsec->create_sid = sid; 6455d84f4f99SDavid Howells } else if (!strcmp(name, "keycreate")) { 64566b6bc620SStephen Smalley error = avc_has_perm(&selinux_state, 64576b6bc620SStephen Smalley mysid, sid, SECCLASS_KEY, KEY__CREATE, 6458be0554c9SStephen Smalley NULL); 64594eb582cfSMichael LeMay if (error) 6460d84f4f99SDavid Howells goto abort_change; 64614eb582cfSMichael LeMay tsec->keycreate_sid = sid; 6462d84f4f99SDavid Howells } else if (!strcmp(name, "sockcreate")) { 646342c3e03eSEric Paris tsec->sockcreate_sid = sid; 6464d84f4f99SDavid Howells } else if (!strcmp(name, "current")) { 6465d84f4f99SDavid Howells error = -EINVAL; 64661da177e4SLinus Torvalds if (sid == 0) 6467d84f4f99SDavid Howells goto abort_change; 6468d9250deaSKaiGai Kohei 6469d84f4f99SDavid Howells /* Only allow single threaded processes to change context */ 6470d84f4f99SDavid Howells error = -EPERM; 64715bb459bbSOleg Nesterov if (!current_is_single_threaded()) { 6472aa8e712cSStephen Smalley error = security_bounded_transition(&selinux_state, 6473aa8e712cSStephen Smalley tsec->sid, sid); 6474d84f4f99SDavid Howells if (error) 6475d84f4f99SDavid Howells goto abort_change; 64761da177e4SLinus Torvalds } 64771da177e4SLinus Torvalds 64781da177e4SLinus Torvalds /* Check permissions for the transition. */ 64796b6bc620SStephen Smalley error = avc_has_perm(&selinux_state, 64806b6bc620SStephen Smalley tsec->sid, sid, SECCLASS_PROCESS, 64811da177e4SLinus Torvalds PROCESS__DYNTRANSITION, NULL); 64821da177e4SLinus Torvalds if (error) 6483d84f4f99SDavid Howells goto abort_change; 64841da177e4SLinus Torvalds 64851da177e4SLinus Torvalds /* Check for ptracing, and update the task SID if ok. 64861da177e4SLinus Torvalds Otherwise, leave SID unchanged and fail. */ 6487be0554c9SStephen Smalley ptsid = ptrace_parent_sid(); 64880c6181cbSPaul Moore if (ptsid != 0) { 64896b6bc620SStephen Smalley error = avc_has_perm(&selinux_state, 64906b6bc620SStephen Smalley ptsid, sid, SECCLASS_PROCESS, 6491d84f4f99SDavid Howells PROCESS__PTRACE, NULL); 6492d84f4f99SDavid Howells if (error) 6493d84f4f99SDavid Howells goto abort_change; 6494d84f4f99SDavid Howells } 6495d84f4f99SDavid Howells 6496d84f4f99SDavid Howells tsec->sid = sid; 6497d84f4f99SDavid Howells } else { 6498d84f4f99SDavid Howells error = -EINVAL; 6499d84f4f99SDavid Howells goto abort_change; 6500d84f4f99SDavid Howells } 6501d84f4f99SDavid Howells 6502d84f4f99SDavid Howells commit_creds(new); 65031da177e4SLinus Torvalds return size; 6504d84f4f99SDavid Howells 6505d84f4f99SDavid Howells abort_change: 6506d84f4f99SDavid Howells abort_creds(new); 6507d84f4f99SDavid Howells return error; 65081da177e4SLinus Torvalds } 65091da177e4SLinus Torvalds 6510746df9b5SDavid Quigley static int selinux_ismaclabel(const char *name) 6511746df9b5SDavid Quigley { 6512746df9b5SDavid Quigley return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0); 6513746df9b5SDavid Quigley } 6514746df9b5SDavid Quigley 6515dc49c1f9SCatherine Zhang static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) 6516dc49c1f9SCatherine Zhang { 6517aa8e712cSStephen Smalley return security_sid_to_context(&selinux_state, secid, 6518aa8e712cSStephen Smalley secdata, seclen); 6519dc49c1f9SCatherine Zhang } 6520dc49c1f9SCatherine Zhang 65217bf570dcSDavid Howells static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) 652263cb3449SDavid Howells { 6523aa8e712cSStephen Smalley return security_context_to_sid(&selinux_state, secdata, seclen, 6524aa8e712cSStephen Smalley secid, GFP_KERNEL); 652563cb3449SDavid Howells } 652663cb3449SDavid Howells 6527dc49c1f9SCatherine Zhang static void selinux_release_secctx(char *secdata, u32 seclen) 6528dc49c1f9SCatherine Zhang { 6529dc49c1f9SCatherine Zhang kfree(secdata); 6530dc49c1f9SCatherine Zhang } 6531dc49c1f9SCatherine Zhang 65326f3be9f5SAndreas Gruenbacher static void selinux_inode_invalidate_secctx(struct inode *inode) 65336f3be9f5SAndreas Gruenbacher { 65346f3be9f5SAndreas Gruenbacher struct inode_security_struct *isec = inode->i_security; 65356f3be9f5SAndreas Gruenbacher 65369287aed2SAndreas Gruenbacher spin_lock(&isec->lock); 65376f3be9f5SAndreas Gruenbacher isec->initialized = LABEL_INVALID; 65389287aed2SAndreas Gruenbacher spin_unlock(&isec->lock); 65396f3be9f5SAndreas Gruenbacher } 65406f3be9f5SAndreas Gruenbacher 65411ee65e37SDavid P. Quigley /* 65421ee65e37SDavid P. Quigley * called with inode->i_mutex locked 65431ee65e37SDavid P. Quigley */ 65441ee65e37SDavid P. Quigley static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) 65451ee65e37SDavid P. Quigley { 65461ee65e37SDavid P. Quigley return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0); 65471ee65e37SDavid P. Quigley } 65481ee65e37SDavid P. Quigley 65491ee65e37SDavid P. Quigley /* 65501ee65e37SDavid P. Quigley * called with inode->i_mutex locked 65511ee65e37SDavid P. Quigley */ 65521ee65e37SDavid P. Quigley static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) 65531ee65e37SDavid P. Quigley { 65541ee65e37SDavid P. Quigley return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0); 65551ee65e37SDavid P. Quigley } 65561ee65e37SDavid P. Quigley 65571ee65e37SDavid P. Quigley static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) 65581ee65e37SDavid P. Quigley { 65591ee65e37SDavid P. Quigley int len = 0; 65601ee65e37SDavid P. Quigley len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX, 65611ee65e37SDavid P. Quigley ctx, true); 65621ee65e37SDavid P. Quigley if (len < 0) 65631ee65e37SDavid P. Quigley return len; 65641ee65e37SDavid P. Quigley *ctxlen = len; 65651ee65e37SDavid P. Quigley return 0; 65661ee65e37SDavid P. Quigley } 6567d720024eSMichael LeMay #ifdef CONFIG_KEYS 6568d720024eSMichael LeMay 6569d84f4f99SDavid Howells static int selinux_key_alloc(struct key *k, const struct cred *cred, 65707e047ef5SDavid Howells unsigned long flags) 6571d720024eSMichael LeMay { 6572d84f4f99SDavid Howells const struct task_security_struct *tsec; 6573d720024eSMichael LeMay struct key_security_struct *ksec; 6574d720024eSMichael LeMay 6575d720024eSMichael LeMay ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL); 6576d720024eSMichael LeMay if (!ksec) 6577d720024eSMichael LeMay return -ENOMEM; 6578d720024eSMichael LeMay 6579d84f4f99SDavid Howells tsec = cred->security; 6580d84f4f99SDavid Howells if (tsec->keycreate_sid) 6581d84f4f99SDavid Howells ksec->sid = tsec->keycreate_sid; 65824eb582cfSMichael LeMay else 6583d84f4f99SDavid Howells ksec->sid = tsec->sid; 6584d720024eSMichael LeMay 6585275bb41eSDavid Howells k->security = ksec; 6586d720024eSMichael LeMay return 0; 6587d720024eSMichael LeMay } 6588d720024eSMichael LeMay 6589d720024eSMichael LeMay static void selinux_key_free(struct key *k) 6590d720024eSMichael LeMay { 6591d720024eSMichael LeMay struct key_security_struct *ksec = k->security; 6592d720024eSMichael LeMay 6593d720024eSMichael LeMay k->security = NULL; 6594d720024eSMichael LeMay kfree(ksec); 6595d720024eSMichael LeMay } 6596d720024eSMichael LeMay 6597d720024eSMichael LeMay static int selinux_key_permission(key_ref_t key_ref, 6598d84f4f99SDavid Howells const struct cred *cred, 6599f5895943SDavid Howells unsigned perm) 6600d720024eSMichael LeMay { 6601d720024eSMichael LeMay struct key *key; 6602d720024eSMichael LeMay struct key_security_struct *ksec; 6603275bb41eSDavid Howells u32 sid; 6604d720024eSMichael LeMay 6605d720024eSMichael LeMay /* if no specific permissions are requested, we skip the 6606d720024eSMichael LeMay permission check. No serious, additional covert channels 6607d720024eSMichael LeMay appear to be created. */ 6608d720024eSMichael LeMay if (perm == 0) 6609d720024eSMichael LeMay return 0; 6610d720024eSMichael LeMay 6611d84f4f99SDavid Howells sid = cred_sid(cred); 6612275bb41eSDavid Howells 6613275bb41eSDavid Howells key = key_ref_to_ptr(key_ref); 6614275bb41eSDavid Howells ksec = key->security; 6615275bb41eSDavid Howells 66166b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 66176b6bc620SStephen Smalley sid, ksec->sid, SECCLASS_KEY, perm, NULL); 6618d720024eSMichael LeMay } 6619d720024eSMichael LeMay 662070a5bb72SDavid Howells static int selinux_key_getsecurity(struct key *key, char **_buffer) 662170a5bb72SDavid Howells { 662270a5bb72SDavid Howells struct key_security_struct *ksec = key->security; 662370a5bb72SDavid Howells char *context = NULL; 662470a5bb72SDavid Howells unsigned len; 662570a5bb72SDavid Howells int rc; 662670a5bb72SDavid Howells 6627aa8e712cSStephen Smalley rc = security_sid_to_context(&selinux_state, ksec->sid, 6628aa8e712cSStephen Smalley &context, &len); 662970a5bb72SDavid Howells if (!rc) 663070a5bb72SDavid Howells rc = len; 663170a5bb72SDavid Howells *_buffer = context; 663270a5bb72SDavid Howells return rc; 663370a5bb72SDavid Howells } 66343a976fa6SDaniel Jurgens #endif 663570a5bb72SDavid Howells 66363a976fa6SDaniel Jurgens #ifdef CONFIG_SECURITY_INFINIBAND 6637cfc4d882SDaniel Jurgens static int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val) 6638cfc4d882SDaniel Jurgens { 6639cfc4d882SDaniel Jurgens struct common_audit_data ad; 6640cfc4d882SDaniel Jurgens int err; 6641cfc4d882SDaniel Jurgens u32 sid = 0; 6642cfc4d882SDaniel Jurgens struct ib_security_struct *sec = ib_sec; 6643cfc4d882SDaniel Jurgens struct lsm_ibpkey_audit ibpkey; 6644cfc4d882SDaniel Jurgens 6645409dcf31SDaniel Jurgens err = sel_ib_pkey_sid(subnet_prefix, pkey_val, &sid); 6646cfc4d882SDaniel Jurgens if (err) 6647cfc4d882SDaniel Jurgens return err; 6648cfc4d882SDaniel Jurgens 6649cfc4d882SDaniel Jurgens ad.type = LSM_AUDIT_DATA_IBPKEY; 6650cfc4d882SDaniel Jurgens ibpkey.subnet_prefix = subnet_prefix; 6651cfc4d882SDaniel Jurgens ibpkey.pkey = pkey_val; 6652cfc4d882SDaniel Jurgens ad.u.ibpkey = &ibpkey; 66536b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 66546b6bc620SStephen Smalley sec->sid, sid, 6655cfc4d882SDaniel Jurgens SECCLASS_INFINIBAND_PKEY, 6656cfc4d882SDaniel Jurgens INFINIBAND_PKEY__ACCESS, &ad); 6657cfc4d882SDaniel Jurgens } 6658cfc4d882SDaniel Jurgens 6659ab861dfcSDaniel Jurgens static int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name, 6660ab861dfcSDaniel Jurgens u8 port_num) 6661ab861dfcSDaniel Jurgens { 6662ab861dfcSDaniel Jurgens struct common_audit_data ad; 6663ab861dfcSDaniel Jurgens int err; 6664ab861dfcSDaniel Jurgens u32 sid = 0; 6665ab861dfcSDaniel Jurgens struct ib_security_struct *sec = ib_sec; 6666ab861dfcSDaniel Jurgens struct lsm_ibendport_audit ibendport; 6667ab861dfcSDaniel Jurgens 6668aa8e712cSStephen Smalley err = security_ib_endport_sid(&selinux_state, dev_name, port_num, 6669aa8e712cSStephen Smalley &sid); 6670ab861dfcSDaniel Jurgens 6671ab861dfcSDaniel Jurgens if (err) 6672ab861dfcSDaniel Jurgens return err; 6673ab861dfcSDaniel Jurgens 6674ab861dfcSDaniel Jurgens ad.type = LSM_AUDIT_DATA_IBENDPORT; 6675ab861dfcSDaniel Jurgens strncpy(ibendport.dev_name, dev_name, sizeof(ibendport.dev_name)); 6676ab861dfcSDaniel Jurgens ibendport.port = port_num; 6677ab861dfcSDaniel Jurgens ad.u.ibendport = &ibendport; 66786b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 66796b6bc620SStephen Smalley sec->sid, sid, 6680ab861dfcSDaniel Jurgens SECCLASS_INFINIBAND_ENDPORT, 6681ab861dfcSDaniel Jurgens INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad); 6682ab861dfcSDaniel Jurgens } 6683ab861dfcSDaniel Jurgens 66843a976fa6SDaniel Jurgens static int selinux_ib_alloc_security(void **ib_sec) 66853a976fa6SDaniel Jurgens { 66863a976fa6SDaniel Jurgens struct ib_security_struct *sec; 66873a976fa6SDaniel Jurgens 66883a976fa6SDaniel Jurgens sec = kzalloc(sizeof(*sec), GFP_KERNEL); 66893a976fa6SDaniel Jurgens if (!sec) 66903a976fa6SDaniel Jurgens return -ENOMEM; 66913a976fa6SDaniel Jurgens sec->sid = current_sid(); 66923a976fa6SDaniel Jurgens 66933a976fa6SDaniel Jurgens *ib_sec = sec; 66943a976fa6SDaniel Jurgens return 0; 66953a976fa6SDaniel Jurgens } 66963a976fa6SDaniel Jurgens 66973a976fa6SDaniel Jurgens static void selinux_ib_free_security(void *ib_sec) 66983a976fa6SDaniel Jurgens { 66993a976fa6SDaniel Jurgens kfree(ib_sec); 67003a976fa6SDaniel Jurgens } 6701d720024eSMichael LeMay #endif 6702d720024eSMichael LeMay 6703ec27c356SChenbo Feng #ifdef CONFIG_BPF_SYSCALL 6704ec27c356SChenbo Feng static int selinux_bpf(int cmd, union bpf_attr *attr, 6705ec27c356SChenbo Feng unsigned int size) 6706ec27c356SChenbo Feng { 6707ec27c356SChenbo Feng u32 sid = current_sid(); 6708ec27c356SChenbo Feng int ret; 6709ec27c356SChenbo Feng 6710ec27c356SChenbo Feng switch (cmd) { 6711ec27c356SChenbo Feng case BPF_MAP_CREATE: 67126b6bc620SStephen Smalley ret = avc_has_perm(&selinux_state, 67136b6bc620SStephen Smalley sid, sid, SECCLASS_BPF, BPF__MAP_CREATE, 6714ec27c356SChenbo Feng NULL); 6715ec27c356SChenbo Feng break; 6716ec27c356SChenbo Feng case BPF_PROG_LOAD: 67176b6bc620SStephen Smalley ret = avc_has_perm(&selinux_state, 67186b6bc620SStephen Smalley sid, sid, SECCLASS_BPF, BPF__PROG_LOAD, 6719ec27c356SChenbo Feng NULL); 6720ec27c356SChenbo Feng break; 6721ec27c356SChenbo Feng default: 6722ec27c356SChenbo Feng ret = 0; 6723ec27c356SChenbo Feng break; 6724ec27c356SChenbo Feng } 6725ec27c356SChenbo Feng 6726ec27c356SChenbo Feng return ret; 6727ec27c356SChenbo Feng } 6728ec27c356SChenbo Feng 6729ec27c356SChenbo Feng static u32 bpf_map_fmode_to_av(fmode_t fmode) 6730ec27c356SChenbo Feng { 6731ec27c356SChenbo Feng u32 av = 0; 6732ec27c356SChenbo Feng 6733ec27c356SChenbo Feng if (fmode & FMODE_READ) 6734ec27c356SChenbo Feng av |= BPF__MAP_READ; 6735ec27c356SChenbo Feng if (fmode & FMODE_WRITE) 6736ec27c356SChenbo Feng av |= BPF__MAP_WRITE; 6737ec27c356SChenbo Feng return av; 6738ec27c356SChenbo Feng } 6739ec27c356SChenbo Feng 6740f66e448cSChenbo Feng /* This function will check the file pass through unix socket or binder to see 6741f66e448cSChenbo Feng * if it is a bpf related object. And apply correspinding checks on the bpf 6742f66e448cSChenbo Feng * object based on the type. The bpf maps and programs, not like other files and 6743f66e448cSChenbo Feng * socket, are using a shared anonymous inode inside the kernel as their inode. 6744f66e448cSChenbo Feng * So checking that inode cannot identify if the process have privilege to 6745f66e448cSChenbo Feng * access the bpf object and that's why we have to add this additional check in 6746f66e448cSChenbo Feng * selinux_file_receive and selinux_binder_transfer_files. 6747f66e448cSChenbo Feng */ 6748f66e448cSChenbo Feng static int bpf_fd_pass(struct file *file, u32 sid) 6749f66e448cSChenbo Feng { 6750f66e448cSChenbo Feng struct bpf_security_struct *bpfsec; 6751f66e448cSChenbo Feng struct bpf_prog *prog; 6752f66e448cSChenbo Feng struct bpf_map *map; 6753f66e448cSChenbo Feng int ret; 6754f66e448cSChenbo Feng 6755f66e448cSChenbo Feng if (file->f_op == &bpf_map_fops) { 6756f66e448cSChenbo Feng map = file->private_data; 6757f66e448cSChenbo Feng bpfsec = map->security; 67586b6bc620SStephen Smalley ret = avc_has_perm(&selinux_state, 67596b6bc620SStephen Smalley sid, bpfsec->sid, SECCLASS_BPF, 6760f66e448cSChenbo Feng bpf_map_fmode_to_av(file->f_mode), NULL); 6761f66e448cSChenbo Feng if (ret) 6762f66e448cSChenbo Feng return ret; 6763f66e448cSChenbo Feng } else if (file->f_op == &bpf_prog_fops) { 6764f66e448cSChenbo Feng prog = file->private_data; 6765f66e448cSChenbo Feng bpfsec = prog->aux->security; 67666b6bc620SStephen Smalley ret = avc_has_perm(&selinux_state, 67676b6bc620SStephen Smalley sid, bpfsec->sid, SECCLASS_BPF, 6768f66e448cSChenbo Feng BPF__PROG_RUN, NULL); 6769f66e448cSChenbo Feng if (ret) 6770f66e448cSChenbo Feng return ret; 6771f66e448cSChenbo Feng } 6772f66e448cSChenbo Feng return 0; 6773f66e448cSChenbo Feng } 6774f66e448cSChenbo Feng 6775ec27c356SChenbo Feng static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode) 6776ec27c356SChenbo Feng { 6777ec27c356SChenbo Feng u32 sid = current_sid(); 6778ec27c356SChenbo Feng struct bpf_security_struct *bpfsec; 6779ec27c356SChenbo Feng 6780ec27c356SChenbo Feng bpfsec = map->security; 67816b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 67826b6bc620SStephen Smalley sid, bpfsec->sid, SECCLASS_BPF, 6783ec27c356SChenbo Feng bpf_map_fmode_to_av(fmode), NULL); 6784ec27c356SChenbo Feng } 6785ec27c356SChenbo Feng 6786ec27c356SChenbo Feng static int selinux_bpf_prog(struct bpf_prog *prog) 6787ec27c356SChenbo Feng { 6788ec27c356SChenbo Feng u32 sid = current_sid(); 6789ec27c356SChenbo Feng struct bpf_security_struct *bpfsec; 6790ec27c356SChenbo Feng 6791ec27c356SChenbo Feng bpfsec = prog->aux->security; 67926b6bc620SStephen Smalley return avc_has_perm(&selinux_state, 67936b6bc620SStephen Smalley sid, bpfsec->sid, SECCLASS_BPF, 6794ec27c356SChenbo Feng BPF__PROG_RUN, NULL); 6795ec27c356SChenbo Feng } 6796ec27c356SChenbo Feng 6797ec27c356SChenbo Feng static int selinux_bpf_map_alloc(struct bpf_map *map) 6798ec27c356SChenbo Feng { 6799ec27c356SChenbo Feng struct bpf_security_struct *bpfsec; 6800ec27c356SChenbo Feng 6801ec27c356SChenbo Feng bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); 6802ec27c356SChenbo Feng if (!bpfsec) 6803ec27c356SChenbo Feng return -ENOMEM; 6804ec27c356SChenbo Feng 6805ec27c356SChenbo Feng bpfsec->sid = current_sid(); 6806ec27c356SChenbo Feng map->security = bpfsec; 6807ec27c356SChenbo Feng 6808ec27c356SChenbo Feng return 0; 6809ec27c356SChenbo Feng } 6810ec27c356SChenbo Feng 6811ec27c356SChenbo Feng static void selinux_bpf_map_free(struct bpf_map *map) 6812ec27c356SChenbo Feng { 6813ec27c356SChenbo Feng struct bpf_security_struct *bpfsec = map->security; 6814ec27c356SChenbo Feng 6815ec27c356SChenbo Feng map->security = NULL; 6816ec27c356SChenbo Feng kfree(bpfsec); 6817ec27c356SChenbo Feng } 6818ec27c356SChenbo Feng 6819ec27c356SChenbo Feng static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux) 6820ec27c356SChenbo Feng { 6821ec27c356SChenbo Feng struct bpf_security_struct *bpfsec; 6822ec27c356SChenbo Feng 6823ec27c356SChenbo Feng bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); 6824ec27c356SChenbo Feng if (!bpfsec) 6825ec27c356SChenbo Feng return -ENOMEM; 6826ec27c356SChenbo Feng 6827ec27c356SChenbo Feng bpfsec->sid = current_sid(); 6828ec27c356SChenbo Feng aux->security = bpfsec; 6829ec27c356SChenbo Feng 6830ec27c356SChenbo Feng return 0; 6831ec27c356SChenbo Feng } 6832ec27c356SChenbo Feng 6833ec27c356SChenbo Feng static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) 6834ec27c356SChenbo Feng { 6835ec27c356SChenbo Feng struct bpf_security_struct *bpfsec = aux->security; 6836ec27c356SChenbo Feng 6837ec27c356SChenbo Feng aux->security = NULL; 6838ec27c356SChenbo Feng kfree(bpfsec); 6839ec27c356SChenbo Feng } 6840ec27c356SChenbo Feng #endif 6841ec27c356SChenbo Feng 6842ca97d939SJames Morris static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { 6843e20b043aSCasey Schaufler LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), 6844e20b043aSCasey Schaufler LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), 6845e20b043aSCasey Schaufler LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder), 6846e20b043aSCasey Schaufler LSM_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file), 6847076c54c5SAhmed S. Darwish 6848e20b043aSCasey Schaufler LSM_HOOK_INIT(ptrace_access_check, selinux_ptrace_access_check), 6849e20b043aSCasey Schaufler LSM_HOOK_INIT(ptrace_traceme, selinux_ptrace_traceme), 6850e20b043aSCasey Schaufler LSM_HOOK_INIT(capget, selinux_capget), 6851e20b043aSCasey Schaufler LSM_HOOK_INIT(capset, selinux_capset), 6852e20b043aSCasey Schaufler LSM_HOOK_INIT(capable, selinux_capable), 6853e20b043aSCasey Schaufler LSM_HOOK_INIT(quotactl, selinux_quotactl), 6854e20b043aSCasey Schaufler LSM_HOOK_INIT(quota_on, selinux_quota_on), 6855e20b043aSCasey Schaufler LSM_HOOK_INIT(syslog, selinux_syslog), 6856e20b043aSCasey Schaufler LSM_HOOK_INIT(vm_enough_memory, selinux_vm_enough_memory), 685779af7307SStephen Smalley 6858e20b043aSCasey Schaufler LSM_HOOK_INIT(netlink_send, selinux_netlink_send), 68591da177e4SLinus Torvalds 6860e20b043aSCasey Schaufler LSM_HOOK_INIT(bprm_set_creds, selinux_bprm_set_creds), 6861e20b043aSCasey Schaufler LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds), 6862e20b043aSCasey Schaufler LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds), 68631da177e4SLinus Torvalds 6864e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), 6865e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security), 6866e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_copy_data, selinux_sb_copy_data), 6867e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_remount, selinux_sb_remount), 6868e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount), 6869e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options), 6870e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs), 6871e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_mount, selinux_mount), 6872e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_umount, selinux_umount), 6873e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts), 6874e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts), 6875e20b043aSCasey Schaufler LSM_HOOK_INIT(sb_parse_opts_str, selinux_parse_opts_str), 68761da177e4SLinus Torvalds 6877e20b043aSCasey Schaufler LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security), 6878a518b0a5SVivek Goyal LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as), 6879e0007529SEric Paris 6880e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security), 6881e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security), 6882e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security), 6883e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_create, selinux_inode_create), 6884e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_link, selinux_inode_link), 6885e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink), 6886e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_symlink, selinux_inode_symlink), 6887e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_mkdir, selinux_inode_mkdir), 6888e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_rmdir, selinux_inode_rmdir), 6889e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_mknod, selinux_inode_mknod), 6890e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_rename, selinux_inode_rename), 6891e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_readlink, selinux_inode_readlink), 6892e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_follow_link, selinux_inode_follow_link), 6893e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_permission, selinux_inode_permission), 6894e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr), 6895e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr), 6896e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr), 6897e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr), 6898e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr), 6899e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr), 6900e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr), 6901e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity), 6902e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity), 6903e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity), 6904e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid), 690556909eb3SVivek Goyal LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), 690619472b69SVivek Goyal LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), 69071da177e4SLinus Torvalds 6908e20b043aSCasey Schaufler LSM_HOOK_INIT(file_permission, selinux_file_permission), 6909e20b043aSCasey Schaufler LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), 6910e20b043aSCasey Schaufler LSM_HOOK_INIT(file_free_security, selinux_file_free_security), 6911e20b043aSCasey Schaufler LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), 6912e20b043aSCasey Schaufler LSM_HOOK_INIT(mmap_file, selinux_mmap_file), 6913e20b043aSCasey Schaufler LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr), 6914e20b043aSCasey Schaufler LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect), 6915e20b043aSCasey Schaufler LSM_HOOK_INIT(file_lock, selinux_file_lock), 6916e20b043aSCasey Schaufler LSM_HOOK_INIT(file_fcntl, selinux_file_fcntl), 6917e20b043aSCasey Schaufler LSM_HOOK_INIT(file_set_fowner, selinux_file_set_fowner), 6918e20b043aSCasey Schaufler LSM_HOOK_INIT(file_send_sigiotask, selinux_file_send_sigiotask), 6919e20b043aSCasey Schaufler LSM_HOOK_INIT(file_receive, selinux_file_receive), 69201da177e4SLinus Torvalds 6921e20b043aSCasey Schaufler LSM_HOOK_INIT(file_open, selinux_file_open), 69221da177e4SLinus Torvalds 6923a79be238STetsuo Handa LSM_HOOK_INIT(task_alloc, selinux_task_alloc), 6924e20b043aSCasey Schaufler LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank), 6925e20b043aSCasey Schaufler LSM_HOOK_INIT(cred_free, selinux_cred_free), 6926e20b043aSCasey Schaufler LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare), 6927e20b043aSCasey Schaufler LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer), 69283ec30113SMatthew Garrett LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid), 6929e20b043aSCasey Schaufler LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as), 6930e20b043aSCasey Schaufler LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as), 6931e20b043aSCasey Schaufler LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request), 6932c77b8cdfSMimi Zohar LSM_HOOK_INIT(kernel_load_data, selinux_kernel_load_data), 693361d612eaSJeff Vander Stoep LSM_HOOK_INIT(kernel_read_file, selinux_kernel_read_file), 6934e20b043aSCasey Schaufler LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid), 6935e20b043aSCasey Schaufler LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid), 6936e20b043aSCasey Schaufler LSM_HOOK_INIT(task_getsid, selinux_task_getsid), 6937e20b043aSCasey Schaufler LSM_HOOK_INIT(task_getsecid, selinux_task_getsecid), 6938e20b043aSCasey Schaufler LSM_HOOK_INIT(task_setnice, selinux_task_setnice), 6939e20b043aSCasey Schaufler LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio), 6940e20b043aSCasey Schaufler LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio), 6941791ec491SStephen Smalley LSM_HOOK_INIT(task_prlimit, selinux_task_prlimit), 6942e20b043aSCasey Schaufler LSM_HOOK_INIT(task_setrlimit, selinux_task_setrlimit), 6943e20b043aSCasey Schaufler LSM_HOOK_INIT(task_setscheduler, selinux_task_setscheduler), 6944e20b043aSCasey Schaufler LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler), 6945e20b043aSCasey Schaufler LSM_HOOK_INIT(task_movememory, selinux_task_movememory), 6946e20b043aSCasey Schaufler LSM_HOOK_INIT(task_kill, selinux_task_kill), 6947e20b043aSCasey Schaufler LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode), 6948788e7dd4SYuichi Nakamura 6949e20b043aSCasey Schaufler LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission), 6950e20b043aSCasey Schaufler LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid), 69511da177e4SLinus Torvalds 6952e20b043aSCasey Schaufler LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security), 6953e20b043aSCasey Schaufler LSM_HOOK_INIT(msg_msg_free_security, selinux_msg_msg_free_security), 69541da177e4SLinus Torvalds 6955e20b043aSCasey Schaufler LSM_HOOK_INIT(msg_queue_alloc_security, 6956e20b043aSCasey Schaufler selinux_msg_queue_alloc_security), 6957e20b043aSCasey Schaufler LSM_HOOK_INIT(msg_queue_free_security, selinux_msg_queue_free_security), 6958e20b043aSCasey Schaufler LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate), 6959e20b043aSCasey Schaufler LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl), 6960e20b043aSCasey Schaufler LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd), 6961e20b043aSCasey Schaufler LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv), 69621da177e4SLinus Torvalds 6963e20b043aSCasey Schaufler LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security), 6964e20b043aSCasey Schaufler LSM_HOOK_INIT(shm_free_security, selinux_shm_free_security), 6965e20b043aSCasey Schaufler LSM_HOOK_INIT(shm_associate, selinux_shm_associate), 6966e20b043aSCasey Schaufler LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl), 6967e20b043aSCasey Schaufler LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat), 69681da177e4SLinus Torvalds 6969e20b043aSCasey Schaufler LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security), 6970e20b043aSCasey Schaufler LSM_HOOK_INIT(sem_free_security, selinux_sem_free_security), 6971e20b043aSCasey Schaufler LSM_HOOK_INIT(sem_associate, selinux_sem_associate), 6972e20b043aSCasey Schaufler LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl), 6973e20b043aSCasey Schaufler LSM_HOOK_INIT(sem_semop, selinux_sem_semop), 69741da177e4SLinus Torvalds 6975e20b043aSCasey Schaufler LSM_HOOK_INIT(d_instantiate, selinux_d_instantiate), 69761da177e4SLinus Torvalds 6977e20b043aSCasey Schaufler LSM_HOOK_INIT(getprocattr, selinux_getprocattr), 6978e20b043aSCasey Schaufler LSM_HOOK_INIT(setprocattr, selinux_setprocattr), 69791da177e4SLinus Torvalds 6980e20b043aSCasey Schaufler LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel), 6981e20b043aSCasey Schaufler LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx), 6982e20b043aSCasey Schaufler LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid), 6983e20b043aSCasey Schaufler LSM_HOOK_INIT(release_secctx, selinux_release_secctx), 69846f3be9f5SAndreas Gruenbacher LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx), 6985e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx), 6986e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx), 6987e20b043aSCasey Schaufler LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx), 69881da177e4SLinus Torvalds 6989e20b043aSCasey Schaufler LSM_HOOK_INIT(unix_stream_connect, selinux_socket_unix_stream_connect), 6990e20b043aSCasey Schaufler LSM_HOOK_INIT(unix_may_send, selinux_socket_unix_may_send), 6991dc49c1f9SCatherine Zhang 6992e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_create, selinux_socket_create), 6993e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_post_create, selinux_socket_post_create), 69940b811db2SDavid Herrmann LSM_HOOK_INIT(socket_socketpair, selinux_socket_socketpair), 6995e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_bind, selinux_socket_bind), 6996e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_connect, selinux_socket_connect), 6997e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_listen, selinux_socket_listen), 6998e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_accept, selinux_socket_accept), 6999e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_sendmsg, selinux_socket_sendmsg), 7000e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_recvmsg, selinux_socket_recvmsg), 7001e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_getsockname, selinux_socket_getsockname), 7002e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_getpeername, selinux_socket_getpeername), 7003e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt), 7004e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt), 7005e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_shutdown, selinux_socket_shutdown), 7006e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb), 7007e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_getpeersec_stream, 7008e20b043aSCasey Schaufler selinux_socket_getpeersec_stream), 7009e20b043aSCasey Schaufler LSM_HOOK_INIT(socket_getpeersec_dgram, selinux_socket_getpeersec_dgram), 7010e20b043aSCasey Schaufler LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security), 7011e20b043aSCasey Schaufler LSM_HOOK_INIT(sk_free_security, selinux_sk_free_security), 7012e20b043aSCasey Schaufler LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security), 7013e20b043aSCasey Schaufler LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid), 7014e20b043aSCasey Schaufler LSM_HOOK_INIT(sock_graft, selinux_sock_graft), 7015d452930fSRichard Haines LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request), 7016d452930fSRichard Haines LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone), 7017d452930fSRichard Haines LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect), 7018e20b043aSCasey Schaufler LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request), 7019e20b043aSCasey Schaufler LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone), 7020e20b043aSCasey Schaufler LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established), 7021e20b043aSCasey Schaufler LSM_HOOK_INIT(secmark_relabel_packet, selinux_secmark_relabel_packet), 7022e20b043aSCasey Schaufler LSM_HOOK_INIT(secmark_refcount_inc, selinux_secmark_refcount_inc), 7023e20b043aSCasey Schaufler LSM_HOOK_INIT(secmark_refcount_dec, selinux_secmark_refcount_dec), 7024e20b043aSCasey Schaufler LSM_HOOK_INIT(req_classify_flow, selinux_req_classify_flow), 7025e20b043aSCasey Schaufler LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security), 7026e20b043aSCasey Schaufler LSM_HOOK_INIT(tun_dev_free_security, selinux_tun_dev_free_security), 7027e20b043aSCasey Schaufler LSM_HOOK_INIT(tun_dev_create, selinux_tun_dev_create), 7028e20b043aSCasey Schaufler LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue), 7029e20b043aSCasey Schaufler LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach), 7030e20b043aSCasey Schaufler LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open), 70313a976fa6SDaniel Jurgens #ifdef CONFIG_SECURITY_INFINIBAND 7032cfc4d882SDaniel Jurgens LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access), 7033ab861dfcSDaniel Jurgens LSM_HOOK_INIT(ib_endport_manage_subnet, 7034ab861dfcSDaniel Jurgens selinux_ib_endport_manage_subnet), 70353a976fa6SDaniel Jurgens LSM_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security), 70363a976fa6SDaniel Jurgens LSM_HOOK_INIT(ib_free_security, selinux_ib_free_security), 70373a976fa6SDaniel Jurgens #endif 7038d28d1e08STrent Jaeger #ifdef CONFIG_SECURITY_NETWORK_XFRM 7039e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc), 7040e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone), 7041e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_policy_free_security, selinux_xfrm_policy_free), 7042e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_policy_delete_security, selinux_xfrm_policy_delete), 7043e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_state_alloc, selinux_xfrm_state_alloc), 7044e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_state_alloc_acquire, 7045e20b043aSCasey Schaufler selinux_xfrm_state_alloc_acquire), 7046e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_state_free_security, selinux_xfrm_state_free), 7047e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_state_delete_security, selinux_xfrm_state_delete), 7048e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_policy_lookup, selinux_xfrm_policy_lookup), 7049e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_state_pol_flow_match, 7050e20b043aSCasey Schaufler selinux_xfrm_state_pol_flow_match), 7051e20b043aSCasey Schaufler LSM_HOOK_INIT(xfrm_decode_session, selinux_xfrm_decode_session), 70521da177e4SLinus Torvalds #endif 7053d720024eSMichael LeMay 7054d720024eSMichael LeMay #ifdef CONFIG_KEYS 7055e20b043aSCasey Schaufler LSM_HOOK_INIT(key_alloc, selinux_key_alloc), 7056e20b043aSCasey Schaufler LSM_HOOK_INIT(key_free, selinux_key_free), 7057e20b043aSCasey Schaufler LSM_HOOK_INIT(key_permission, selinux_key_permission), 7058e20b043aSCasey Schaufler LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity), 7059d720024eSMichael LeMay #endif 70609d57a7f9SAhmed S. Darwish 70619d57a7f9SAhmed S. Darwish #ifdef CONFIG_AUDIT 7062e20b043aSCasey Schaufler LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init), 7063e20b043aSCasey Schaufler LSM_HOOK_INIT(audit_rule_known, selinux_audit_rule_known), 7064e20b043aSCasey Schaufler LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match), 7065e20b043aSCasey Schaufler LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free), 70669d57a7f9SAhmed S. Darwish #endif 7067ec27c356SChenbo Feng 7068ec27c356SChenbo Feng #ifdef CONFIG_BPF_SYSCALL 7069ec27c356SChenbo Feng LSM_HOOK_INIT(bpf, selinux_bpf), 7070ec27c356SChenbo Feng LSM_HOOK_INIT(bpf_map, selinux_bpf_map), 7071ec27c356SChenbo Feng LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), 7072ec27c356SChenbo Feng LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc), 7073ec27c356SChenbo Feng LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc), 7074ec27c356SChenbo Feng LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), 7075ec27c356SChenbo Feng LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free), 7076ec27c356SChenbo Feng #endif 70771da177e4SLinus Torvalds }; 70781da177e4SLinus Torvalds 70791da177e4SLinus Torvalds static __init int selinux_init(void) 70801da177e4SLinus Torvalds { 7081b1d9e6b0SCasey Schaufler if (!security_module_enable("selinux")) { 7082076c54c5SAhmed S. Darwish selinux_enabled = 0; 7083076c54c5SAhmed S. Darwish return 0; 7084076c54c5SAhmed S. Darwish } 7085076c54c5SAhmed S. Darwish 70861da177e4SLinus Torvalds if (!selinux_enabled) { 7087c103a91eSpeter enderborg pr_info("SELinux: Disabled at boot.\n"); 70881da177e4SLinus Torvalds return 0; 70891da177e4SLinus Torvalds } 70901da177e4SLinus Torvalds 7091c103a91eSpeter enderborg pr_info("SELinux: Initializing.\n"); 70921da177e4SLinus Torvalds 7093aa8e712cSStephen Smalley memset(&selinux_state, 0, sizeof(selinux_state)); 7094e5a5ca96SPaul Moore enforcing_set(&selinux_state, selinux_enforcing_boot); 7095aa8e712cSStephen Smalley selinux_state.checkreqprot = selinux_checkreqprot_boot; 7096aa8e712cSStephen Smalley selinux_ss_init(&selinux_state.ss); 70976b6bc620SStephen Smalley selinux_avc_init(&selinux_state.avc); 7098aa8e712cSStephen Smalley 70991da177e4SLinus Torvalds /* Set the security state for the initial task. */ 7100d84f4f99SDavid Howells cred_init_security(); 71011da177e4SLinus Torvalds 7102fcaaade1SStephen Smalley default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC); 7103fcaaade1SStephen Smalley 71047cae7e26SJames Morris sel_inode_cache = kmem_cache_create("selinux_inode_security", 71057cae7e26SJames Morris sizeof(struct inode_security_struct), 710620c2df83SPaul Mundt 0, SLAB_PANIC, NULL); 710763205654SSangwoo file_security_cache = kmem_cache_create("selinux_file_security", 710863205654SSangwoo sizeof(struct file_security_struct), 710963205654SSangwoo 0, SLAB_PANIC, NULL); 71101da177e4SLinus Torvalds avc_init(); 71111da177e4SLinus Torvalds 7112aa8e712cSStephen Smalley avtab_cache_init(); 7113aa8e712cSStephen Smalley 7114aa8e712cSStephen Smalley ebitmap_cache_init(); 7115aa8e712cSStephen Smalley 7116aa8e712cSStephen Smalley hashtab_cache_init(); 7117aa8e712cSStephen Smalley 7118d69dece5SCasey Schaufler security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); 71191da177e4SLinus Torvalds 7120615e51fdSPaul Moore if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) 7121615e51fdSPaul Moore panic("SELinux: Unable to register AVC netcache callback\n"); 7122615e51fdSPaul Moore 71238f408ab6SDaniel Jurgens if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET)) 71248f408ab6SDaniel Jurgens panic("SELinux: Unable to register AVC LSM notifier callback\n"); 71258f408ab6SDaniel Jurgens 7126aa8e712cSStephen Smalley if (selinux_enforcing_boot) 7127c103a91eSpeter enderborg pr_debug("SELinux: Starting in enforcing mode\n"); 7128828dfe1dSEric Paris else 7129c103a91eSpeter enderborg pr_debug("SELinux: Starting in permissive mode\n"); 7130d720024eSMichael LeMay 71311da177e4SLinus Torvalds return 0; 71321da177e4SLinus Torvalds } 71331da177e4SLinus Torvalds 7134e8c26255SAl Viro static void delayed_superblock_init(struct super_block *sb, void *unused) 7135e8c26255SAl Viro { 713617f3b556SAl Viro struct security_mnt_opts opts; 713717f3b556SAl Viro 713817f3b556SAl Viro security_init_mnt_opts(&opts); 713917f3b556SAl Viro selinux_set_mnt_opts(sb, &opts, 0, NULL); 714017f3b556SAl Viro security_free_mnt_opts(&opts); 7141e8c26255SAl Viro } 7142e8c26255SAl Viro 71431da177e4SLinus Torvalds void selinux_complete_init(void) 71441da177e4SLinus Torvalds { 7145c103a91eSpeter enderborg pr_debug("SELinux: Completing initialization.\n"); 71461da177e4SLinus Torvalds 71471da177e4SLinus Torvalds /* Set up any superblocks initialized prior to the policy load. */ 7148c103a91eSpeter enderborg pr_debug("SELinux: Setting up existing superblocks.\n"); 7149e8c26255SAl Viro iterate_supers(delayed_superblock_init, NULL); 71501da177e4SLinus Torvalds } 71511da177e4SLinus Torvalds 71521da177e4SLinus Torvalds /* SELinux requires early initialization in order to label 71531da177e4SLinus Torvalds all processes and objects when they are created. */ 71543d6e5f6dSKees Cook DEFINE_LSM(selinux) = { 715507aed2f2SKees Cook .name = "selinux", 71563d6e5f6dSKees Cook .init = selinux_init, 71573d6e5f6dSKees Cook }; 71581da177e4SLinus Torvalds 7159c2b507fdSStephen Smalley #if defined(CONFIG_NETFILTER) 71601da177e4SLinus Torvalds 7161591bb278SFlorian Westphal static const struct nf_hook_ops selinux_nf_ops[] = { 7162effad8dfSPaul Moore { 7163effad8dfSPaul Moore .hook = selinux_ipv4_postroute, 71642597a834SAlban Crequy .pf = NFPROTO_IPV4, 71656e23ae2aSPatrick McHardy .hooknum = NF_INET_POST_ROUTING, 71661da177e4SLinus Torvalds .priority = NF_IP_PRI_SELINUX_LAST, 7167effad8dfSPaul Moore }, 7168effad8dfSPaul Moore { 7169effad8dfSPaul Moore .hook = selinux_ipv4_forward, 71702597a834SAlban Crequy .pf = NFPROTO_IPV4, 7171effad8dfSPaul Moore .hooknum = NF_INET_FORWARD, 7172effad8dfSPaul Moore .priority = NF_IP_PRI_SELINUX_FIRST, 7173948bf85cSPaul Moore }, 7174948bf85cSPaul Moore { 7175948bf85cSPaul Moore .hook = selinux_ipv4_output, 71762597a834SAlban Crequy .pf = NFPROTO_IPV4, 7177948bf85cSPaul Moore .hooknum = NF_INET_LOCAL_OUT, 7178948bf85cSPaul Moore .priority = NF_IP_PRI_SELINUX_FIRST, 717925db6beaSJiri Pirko }, 71801a93a6eaSJavier Martinez Canillas #if IS_ENABLED(CONFIG_IPV6) 7181effad8dfSPaul Moore { 7182effad8dfSPaul Moore .hook = selinux_ipv6_postroute, 71832597a834SAlban Crequy .pf = NFPROTO_IPV6, 71846e23ae2aSPatrick McHardy .hooknum = NF_INET_POST_ROUTING, 71851da177e4SLinus Torvalds .priority = NF_IP6_PRI_SELINUX_LAST, 7186effad8dfSPaul Moore }, 7187effad8dfSPaul Moore { 7188effad8dfSPaul Moore .hook = selinux_ipv6_forward, 71892597a834SAlban Crequy .pf = NFPROTO_IPV6, 7190effad8dfSPaul Moore .hooknum = NF_INET_FORWARD, 7191effad8dfSPaul Moore .priority = NF_IP6_PRI_SELINUX_FIRST, 719225db6beaSJiri Pirko }, 71932917f57bSHuw Davies { 71942917f57bSHuw Davies .hook = selinux_ipv6_output, 71952917f57bSHuw Davies .pf = NFPROTO_IPV6, 71962917f57bSHuw Davies .hooknum = NF_INET_LOCAL_OUT, 71972917f57bSHuw Davies .priority = NF_IP6_PRI_SELINUX_FIRST, 71982917f57bSHuw Davies }, 71991da177e4SLinus Torvalds #endif /* IPV6 */ 720025db6beaSJiri Pirko }; 72011da177e4SLinus Torvalds 72028e71bf75SFlorian Westphal static int __net_init selinux_nf_register(struct net *net) 72038e71bf75SFlorian Westphal { 72048e71bf75SFlorian Westphal return nf_register_net_hooks(net, selinux_nf_ops, 72058e71bf75SFlorian Westphal ARRAY_SIZE(selinux_nf_ops)); 72068e71bf75SFlorian Westphal } 72078e71bf75SFlorian Westphal 72088e71bf75SFlorian Westphal static void __net_exit selinux_nf_unregister(struct net *net) 72098e71bf75SFlorian Westphal { 72108e71bf75SFlorian Westphal nf_unregister_net_hooks(net, selinux_nf_ops, 72118e71bf75SFlorian Westphal ARRAY_SIZE(selinux_nf_ops)); 72128e71bf75SFlorian Westphal } 72138e71bf75SFlorian Westphal 72148e71bf75SFlorian Westphal static struct pernet_operations selinux_net_ops = { 72158e71bf75SFlorian Westphal .init = selinux_nf_register, 72168e71bf75SFlorian Westphal .exit = selinux_nf_unregister, 72178e71bf75SFlorian Westphal }; 72188e71bf75SFlorian Westphal 72191da177e4SLinus Torvalds static int __init selinux_nf_ip_init(void) 72201da177e4SLinus Torvalds { 722125db6beaSJiri Pirko int err; 72221da177e4SLinus Torvalds 72231da177e4SLinus Torvalds if (!selinux_enabled) 722425db6beaSJiri Pirko return 0; 72251da177e4SLinus Torvalds 7226c103a91eSpeter enderborg pr_debug("SELinux: Registering netfilter hooks\n"); 72271da177e4SLinus Torvalds 72288e71bf75SFlorian Westphal err = register_pernet_subsys(&selinux_net_ops); 72291da177e4SLinus Torvalds if (err) 72308e71bf75SFlorian Westphal panic("SELinux: register_pernet_subsys: error %d\n", err); 72311da177e4SLinus Torvalds 723225db6beaSJiri Pirko return 0; 72331da177e4SLinus Torvalds } 72341da177e4SLinus Torvalds __initcall(selinux_nf_ip_init); 72351da177e4SLinus Torvalds 72361da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE 72371da177e4SLinus Torvalds static void selinux_nf_ip_exit(void) 72381da177e4SLinus Torvalds { 7239c103a91eSpeter enderborg pr_debug("SELinux: Unregistering netfilter hooks\n"); 72401da177e4SLinus Torvalds 72418e71bf75SFlorian Westphal unregister_pernet_subsys(&selinux_net_ops); 72421da177e4SLinus Torvalds } 72431da177e4SLinus Torvalds #endif 72441da177e4SLinus Torvalds 7245c2b507fdSStephen Smalley #else /* CONFIG_NETFILTER */ 72461da177e4SLinus Torvalds 72471da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE 72481da177e4SLinus Torvalds #define selinux_nf_ip_exit() 72491da177e4SLinus Torvalds #endif 72501da177e4SLinus Torvalds 7251c2b507fdSStephen Smalley #endif /* CONFIG_NETFILTER */ 72521da177e4SLinus Torvalds 72531da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE 7254aa8e712cSStephen Smalley int selinux_disable(struct selinux_state *state) 72551da177e4SLinus Torvalds { 7256aa8e712cSStephen Smalley if (state->initialized) { 72571da177e4SLinus Torvalds /* Not permitted after initial policy load. */ 72581da177e4SLinus Torvalds return -EINVAL; 72591da177e4SLinus Torvalds } 72601da177e4SLinus Torvalds 7261aa8e712cSStephen Smalley if (state->disabled) { 72621da177e4SLinus Torvalds /* Only do this once. */ 72631da177e4SLinus Torvalds return -EINVAL; 72641da177e4SLinus Torvalds } 72651da177e4SLinus Torvalds 7266aa8e712cSStephen Smalley state->disabled = 1; 7267aa8e712cSStephen Smalley 7268c103a91eSpeter enderborg pr_info("SELinux: Disabled at runtime.\n"); 72691da177e4SLinus Torvalds 727030d55280SStephen Smalley selinux_enabled = 0; 72711da177e4SLinus Torvalds 7272b1d9e6b0SCasey Schaufler security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks)); 72731da177e4SLinus Torvalds 7274af8ff049SEric Paris /* Try to destroy the avc node cache */ 7275af8ff049SEric Paris avc_disable(); 7276af8ff049SEric Paris 72771da177e4SLinus Torvalds /* Unregister netfilter hooks. */ 72781da177e4SLinus Torvalds selinux_nf_ip_exit(); 72791da177e4SLinus Torvalds 72801da177e4SLinus Torvalds /* Unregister selinuxfs. */ 72811da177e4SLinus Torvalds exit_sel_fs(); 72821da177e4SLinus Torvalds 72831da177e4SLinus Torvalds return 0; 72841da177e4SLinus Torvalds } 72851da177e4SLinus Torvalds #endif 7286