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 * 61da177e4SLinus Torvalds * Authors: Stephen Smalley, <sds@epoch.ncsc.mil> 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> 16effad8dfSPaul Moore * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P. 17effad8dfSPaul Moore * Paul Moore <paul.moore@hp.com> 18788e7dd4SYuichi Nakamura * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. 19788e7dd4SYuichi Nakamura * Yuichi Nakamura <ynakam@hitachisoft.jp> 201da177e4SLinus Torvalds * 211da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 221da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2, 231da177e4SLinus Torvalds * as published by the Free Software Foundation. 241da177e4SLinus Torvalds */ 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #include <linux/init.h> 271da177e4SLinus Torvalds #include <linux/kernel.h> 280d094efeSRoland McGrath #include <linux/tracehook.h> 291da177e4SLinus Torvalds #include <linux/errno.h> 301da177e4SLinus Torvalds #include <linux/sched.h> 311da177e4SLinus Torvalds #include <linux/security.h> 321da177e4SLinus Torvalds #include <linux/xattr.h> 331da177e4SLinus Torvalds #include <linux/capability.h> 341da177e4SLinus Torvalds #include <linux/unistd.h> 351da177e4SLinus Torvalds #include <linux/mm.h> 361da177e4SLinus Torvalds #include <linux/mman.h> 371da177e4SLinus Torvalds #include <linux/slab.h> 381da177e4SLinus Torvalds #include <linux/pagemap.h> 391da177e4SLinus Torvalds #include <linux/swap.h> 401da177e4SLinus Torvalds #include <linux/spinlock.h> 411da177e4SLinus Torvalds #include <linux/syscalls.h> 421da177e4SLinus Torvalds #include <linux/file.h> 439f3acc31SAl Viro #include <linux/fdtable.h> 441da177e4SLinus Torvalds #include <linux/namei.h> 451da177e4SLinus Torvalds #include <linux/mount.h> 461da177e4SLinus Torvalds #include <linux/proc_fs.h> 471da177e4SLinus Torvalds #include <linux/netfilter_ipv4.h> 481da177e4SLinus Torvalds #include <linux/netfilter_ipv6.h> 491da177e4SLinus Torvalds #include <linux/tty.h> 501da177e4SLinus Torvalds #include <net/icmp.h> 51227b60f5SStephen Hemminger #include <net/ip.h> /* for local_port_range[] */ 521da177e4SLinus Torvalds #include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ 53220deb96SPaul Moore #include <net/net_namespace.h> 54d621d35eSPaul Moore #include <net/netlabel.h> 55f5269710SEric Paris #include <linux/uaccess.h> 561da177e4SLinus Torvalds #include <asm/ioctls.h> 57d621d35eSPaul Moore #include <asm/atomic.h> 581da177e4SLinus Torvalds #include <linux/bitops.h> 591da177e4SLinus Torvalds #include <linux/interrupt.h> 601da177e4SLinus Torvalds #include <linux/netdevice.h> /* for network interface checks */ 611da177e4SLinus Torvalds #include <linux/netlink.h> 621da177e4SLinus Torvalds #include <linux/tcp.h> 631da177e4SLinus Torvalds #include <linux/udp.h> 642ee92d46SJames Morris #include <linux/dccp.h> 651da177e4SLinus Torvalds #include <linux/quota.h> 661da177e4SLinus Torvalds #include <linux/un.h> /* for Unix socket types */ 671da177e4SLinus Torvalds #include <net/af_unix.h> /* for Unix socket types */ 681da177e4SLinus Torvalds #include <linux/parser.h> 691da177e4SLinus Torvalds #include <linux/nfs_mount.h> 701da177e4SLinus Torvalds #include <net/ipv6.h> 711da177e4SLinus Torvalds #include <linux/hugetlb.h> 721da177e4SLinus Torvalds #include <linux/personality.h> 731da177e4SLinus Torvalds #include <linux/sysctl.h> 741da177e4SLinus Torvalds #include <linux/audit.h> 756931dfc9SEric Paris #include <linux/string.h> 76877ce7c1SCatherine Zhang #include <linux/selinux.h> 7723970741SEric Paris #include <linux/mutex.h> 78f06febc9SFrank Mayhar #include <linux/posix-timers.h> 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds #include "avc.h" 811da177e4SLinus Torvalds #include "objsec.h" 821da177e4SLinus Torvalds #include "netif.h" 83224dfbd8SPaul Moore #include "netnode.h" 843e112172SPaul Moore #include "netport.h" 85d28d1e08STrent Jaeger #include "xfrm.h" 86c60475bfSPaul Moore #include "netlabel.h" 879d57a7f9SAhmed S. Darwish #include "audit.h" 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds #define XATTR_SELINUX_SUFFIX "selinux" 901da177e4SLinus Torvalds #define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX 911da177e4SLinus Torvalds 92c9180a57SEric Paris #define NUM_SEL_MNT_OPTS 4 93c9180a57SEric Paris 941da177e4SLinus Torvalds extern unsigned int policydb_loaded_version; 951da177e4SLinus Torvalds extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm); 964e5ab4cbSJames Morris extern int selinux_compat_net; 9720510f2fSJames Morris extern struct security_operations *security_ops; 981da177e4SLinus Torvalds 99d621d35eSPaul Moore /* SECMARK reference count */ 100d621d35eSPaul Moore atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); 101d621d35eSPaul Moore 1021da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DEVELOP 103828dfe1dSEric Paris int selinux_enforcing; 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds static int __init enforcing_setup(char *str) 1061da177e4SLinus Torvalds { 107f5269710SEric Paris unsigned long enforcing; 108f5269710SEric Paris if (!strict_strtoul(str, 0, &enforcing)) 109f5269710SEric Paris selinux_enforcing = enforcing ? 1 : 0; 1101da177e4SLinus Torvalds return 1; 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds __setup("enforcing=", enforcing_setup); 1131da177e4SLinus Torvalds #endif 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM 1161da177e4SLinus Torvalds int selinux_enabled = CONFIG_SECURITY_SELINUX_BOOTPARAM_VALUE; 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds static int __init selinux_enabled_setup(char *str) 1191da177e4SLinus Torvalds { 120f5269710SEric Paris unsigned long enabled; 121f5269710SEric Paris if (!strict_strtoul(str, 0, &enabled)) 122f5269710SEric Paris selinux_enabled = enabled ? 1 : 0; 1231da177e4SLinus Torvalds return 1; 1241da177e4SLinus Torvalds } 1251da177e4SLinus Torvalds __setup("selinux=", selinux_enabled_setup); 12630d55280SStephen Smalley #else 12730d55280SStephen Smalley int selinux_enabled = 1; 1281da177e4SLinus Torvalds #endif 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds 1316f0f0fd4SJames Morris /* 1326f0f0fd4SJames Morris * Minimal support for a secondary security module, 1336f0f0fd4SJames Morris * just to allow the use of the capability module. 1346f0f0fd4SJames Morris */ 135828dfe1dSEric Paris static struct security_operations *secondary_ops; 1361da177e4SLinus Torvalds 1371da177e4SLinus Torvalds /* Lists of inode and superblock security structures initialized 1381da177e4SLinus Torvalds before the policy was loaded. */ 1391da177e4SLinus Torvalds static LIST_HEAD(superblock_security_head); 1401da177e4SLinus Torvalds static DEFINE_SPINLOCK(sb_security_lock); 1411da177e4SLinus Torvalds 142e18b890bSChristoph Lameter static struct kmem_cache *sel_inode_cache; 1437cae7e26SJames Morris 144d621d35eSPaul Moore /** 145d621d35eSPaul Moore * selinux_secmark_enabled - Check to see if SECMARK is currently enabled 146d621d35eSPaul Moore * 147d621d35eSPaul Moore * Description: 148d621d35eSPaul Moore * This function checks the SECMARK reference counter to see if any SECMARK 149d621d35eSPaul Moore * targets are currently configured, if the reference counter is greater than 150d621d35eSPaul Moore * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is 151d621d35eSPaul Moore * enabled, false (0) if SECMARK is disabled. 152d621d35eSPaul Moore * 153d621d35eSPaul Moore */ 154d621d35eSPaul Moore static int selinux_secmark_enabled(void) 155d621d35eSPaul Moore { 156d621d35eSPaul Moore return (atomic_read(&selinux_secmark_refcount) > 0); 157d621d35eSPaul Moore } 158d621d35eSPaul Moore 1591da177e4SLinus Torvalds /* Allocate and free functions for each kind of security blob. */ 1601da177e4SLinus Torvalds 161f1752eecSDavid Howells static int cred_alloc_security(struct cred *cred) 1621da177e4SLinus Torvalds { 1631da177e4SLinus Torvalds struct task_security_struct *tsec; 1641da177e4SLinus Torvalds 16589d155efSJames Morris tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL); 1661da177e4SLinus Torvalds if (!tsec) 1671da177e4SLinus Torvalds return -ENOMEM; 1681da177e4SLinus Torvalds 1690356357cSRoland McGrath tsec->osid = tsec->sid = SECINITSID_UNLABELED; 170f1752eecSDavid Howells cred->security = tsec; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds return 0; 1731da177e4SLinus Torvalds } 1741da177e4SLinus Torvalds 175*275bb41eSDavid Howells /* 176*275bb41eSDavid Howells * get the security ID of a task 177*275bb41eSDavid Howells */ 178*275bb41eSDavid Howells static inline u32 task_sid(const struct task_struct *task) 179*275bb41eSDavid Howells { 180*275bb41eSDavid Howells const struct task_security_struct *tsec; 181*275bb41eSDavid Howells u32 sid; 182*275bb41eSDavid Howells 183*275bb41eSDavid Howells rcu_read_lock(); 184*275bb41eSDavid Howells tsec = __task_cred(task)->security; 185*275bb41eSDavid Howells sid = tsec->sid; 186*275bb41eSDavid Howells rcu_read_unlock(); 187*275bb41eSDavid Howells return sid; 188*275bb41eSDavid Howells } 189*275bb41eSDavid Howells 190*275bb41eSDavid Howells /* 191*275bb41eSDavid Howells * get the security ID of the current task 192*275bb41eSDavid Howells */ 193*275bb41eSDavid Howells static inline u32 current_sid(void) 194*275bb41eSDavid Howells { 195*275bb41eSDavid Howells const struct task_security_struct *tsec = current_cred()->security; 196*275bb41eSDavid Howells 197*275bb41eSDavid Howells return tsec->sid; 198*275bb41eSDavid Howells } 199*275bb41eSDavid Howells 2001da177e4SLinus Torvalds static int inode_alloc_security(struct inode *inode) 2011da177e4SLinus Torvalds { 2021da177e4SLinus Torvalds struct inode_security_struct *isec; 203*275bb41eSDavid Howells u32 sid = current_sid(); 2041da177e4SLinus Torvalds 205a02fe132SJosef Bacik isec = kmem_cache_zalloc(sel_inode_cache, GFP_NOFS); 2061da177e4SLinus Torvalds if (!isec) 2071da177e4SLinus Torvalds return -ENOMEM; 2081da177e4SLinus Torvalds 20923970741SEric Paris mutex_init(&isec->lock); 2101da177e4SLinus Torvalds INIT_LIST_HEAD(&isec->list); 2111da177e4SLinus Torvalds isec->inode = inode; 2121da177e4SLinus Torvalds isec->sid = SECINITSID_UNLABELED; 2131da177e4SLinus Torvalds isec->sclass = SECCLASS_FILE; 214*275bb41eSDavid Howells isec->task_sid = sid; 2151da177e4SLinus Torvalds inode->i_security = isec; 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds return 0; 2181da177e4SLinus Torvalds } 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds static void inode_free_security(struct inode *inode) 2211da177e4SLinus Torvalds { 2221da177e4SLinus Torvalds struct inode_security_struct *isec = inode->i_security; 2231da177e4SLinus Torvalds struct superblock_security_struct *sbsec = inode->i_sb->s_security; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds spin_lock(&sbsec->isec_lock); 2261da177e4SLinus Torvalds if (!list_empty(&isec->list)) 2271da177e4SLinus Torvalds list_del_init(&isec->list); 2281da177e4SLinus Torvalds spin_unlock(&sbsec->isec_lock); 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds inode->i_security = NULL; 2317cae7e26SJames Morris kmem_cache_free(sel_inode_cache, isec); 2321da177e4SLinus Torvalds } 2331da177e4SLinus Torvalds 2341da177e4SLinus Torvalds static int file_alloc_security(struct file *file) 2351da177e4SLinus Torvalds { 2361da177e4SLinus Torvalds struct file_security_struct *fsec; 237*275bb41eSDavid Howells u32 sid = current_sid(); 2381da177e4SLinus Torvalds 23926d2a4beSStephen Smalley fsec = kzalloc(sizeof(struct file_security_struct), GFP_KERNEL); 2401da177e4SLinus Torvalds if (!fsec) 2411da177e4SLinus Torvalds return -ENOMEM; 2421da177e4SLinus Torvalds 243*275bb41eSDavid Howells fsec->sid = sid; 244*275bb41eSDavid Howells fsec->fown_sid = sid; 2451da177e4SLinus Torvalds file->f_security = fsec; 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds return 0; 2481da177e4SLinus Torvalds } 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds static void file_free_security(struct file *file) 2511da177e4SLinus Torvalds { 2521da177e4SLinus Torvalds struct file_security_struct *fsec = file->f_security; 2531da177e4SLinus Torvalds file->f_security = NULL; 2541da177e4SLinus Torvalds kfree(fsec); 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds 2571da177e4SLinus Torvalds static int superblock_alloc_security(struct super_block *sb) 2581da177e4SLinus Torvalds { 2591da177e4SLinus Torvalds struct superblock_security_struct *sbsec; 2601da177e4SLinus Torvalds 26189d155efSJames Morris sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL); 2621da177e4SLinus Torvalds if (!sbsec) 2631da177e4SLinus Torvalds return -ENOMEM; 2641da177e4SLinus Torvalds 265bc7e982bSEric Paris mutex_init(&sbsec->lock); 2661da177e4SLinus Torvalds INIT_LIST_HEAD(&sbsec->list); 2671da177e4SLinus Torvalds INIT_LIST_HEAD(&sbsec->isec_head); 2681da177e4SLinus Torvalds spin_lock_init(&sbsec->isec_lock); 2691da177e4SLinus Torvalds sbsec->sb = sb; 2701da177e4SLinus Torvalds sbsec->sid = SECINITSID_UNLABELED; 2711da177e4SLinus Torvalds sbsec->def_sid = SECINITSID_FILE; 272c312feb2SEric Paris sbsec->mntpoint_sid = SECINITSID_UNLABELED; 2731da177e4SLinus Torvalds sb->s_security = sbsec; 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds return 0; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds static void superblock_free_security(struct super_block *sb) 2791da177e4SLinus Torvalds { 2801da177e4SLinus Torvalds struct superblock_security_struct *sbsec = sb->s_security; 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds spin_lock(&sb_security_lock); 2831da177e4SLinus Torvalds if (!list_empty(&sbsec->list)) 2841da177e4SLinus Torvalds list_del_init(&sbsec->list); 2851da177e4SLinus Torvalds spin_unlock(&sb_security_lock); 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds sb->s_security = NULL; 2881da177e4SLinus Torvalds kfree(sbsec); 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 2917d877f3bSAl Viro static int sk_alloc_security(struct sock *sk, int family, gfp_t priority) 2921da177e4SLinus Torvalds { 2931da177e4SLinus Torvalds struct sk_security_struct *ssec; 2941da177e4SLinus Torvalds 29589d155efSJames Morris ssec = kzalloc(sizeof(*ssec), priority); 2961da177e4SLinus Torvalds if (!ssec) 2971da177e4SLinus Torvalds return -ENOMEM; 2981da177e4SLinus Torvalds 2991da177e4SLinus Torvalds ssec->peer_sid = SECINITSID_UNLABELED; 300892c141eSVenkat Yekkirala ssec->sid = SECINITSID_UNLABELED; 3011da177e4SLinus Torvalds sk->sk_security = ssec; 3021da177e4SLinus Torvalds 303f74af6e8SPaul Moore selinux_netlbl_sk_security_reset(ssec, family); 30499f59ed0SPaul Moore 3051da177e4SLinus Torvalds return 0; 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds static void sk_free_security(struct sock *sk) 3091da177e4SLinus Torvalds { 3101da177e4SLinus Torvalds struct sk_security_struct *ssec = sk->sk_security; 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds sk->sk_security = NULL; 3136c5b3fc0SPaul Moore selinux_netlbl_sk_security_free(ssec); 3141da177e4SLinus Torvalds kfree(ssec); 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds /* The security server must be initialized before 3181da177e4SLinus Torvalds any labeling or access decisions can be provided. */ 3191da177e4SLinus Torvalds extern int ss_initialized; 3201da177e4SLinus Torvalds 3211da177e4SLinus Torvalds /* The file system's label must be initialized prior to use. */ 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds static char *labeling_behaviors[6] = { 3241da177e4SLinus Torvalds "uses xattr", 3251da177e4SLinus Torvalds "uses transition SIDs", 3261da177e4SLinus Torvalds "uses task SIDs", 3271da177e4SLinus Torvalds "uses genfs_contexts", 3281da177e4SLinus Torvalds "not configured for labeling", 3291da177e4SLinus Torvalds "uses mountpoint labeling", 3301da177e4SLinus Torvalds }; 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry); 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds static inline int inode_doinit(struct inode *inode) 3351da177e4SLinus Torvalds { 3361da177e4SLinus Torvalds return inode_doinit_with_dentry(inode, NULL); 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds 3391da177e4SLinus Torvalds enum { 34031e87930SEric Paris Opt_error = -1, 3411da177e4SLinus Torvalds Opt_context = 1, 3421da177e4SLinus Torvalds Opt_fscontext = 2, 343c9180a57SEric Paris Opt_defcontext = 3, 344c9180a57SEric Paris Opt_rootcontext = 4, 3451da177e4SLinus Torvalds }; 3461da177e4SLinus Torvalds 347a447c093SSteven Whitehouse static const match_table_t tokens = { 348832cbd9aSEric Paris {Opt_context, CONTEXT_STR "%s"}, 349832cbd9aSEric Paris {Opt_fscontext, FSCONTEXT_STR "%s"}, 350832cbd9aSEric Paris {Opt_defcontext, DEFCONTEXT_STR "%s"}, 351832cbd9aSEric Paris {Opt_rootcontext, ROOTCONTEXT_STR "%s"}, 35231e87930SEric Paris {Opt_error, NULL}, 3531da177e4SLinus Torvalds }; 3541da177e4SLinus Torvalds 3551da177e4SLinus Torvalds #define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" 3561da177e4SLinus Torvalds 357c312feb2SEric Paris static int may_context_mount_sb_relabel(u32 sid, 358c312feb2SEric Paris struct superblock_security_struct *sbsec, 359*275bb41eSDavid Howells const struct cred *cred) 360c312feb2SEric Paris { 361*275bb41eSDavid Howells const struct task_security_struct *tsec = cred->security; 362c312feb2SEric Paris int rc; 363c312feb2SEric Paris 364c312feb2SEric Paris rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, 365c312feb2SEric Paris FILESYSTEM__RELABELFROM, NULL); 366c312feb2SEric Paris if (rc) 367c312feb2SEric Paris return rc; 368c312feb2SEric Paris 369c312feb2SEric Paris rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM, 370c312feb2SEric Paris FILESYSTEM__RELABELTO, NULL); 371c312feb2SEric Paris return rc; 372c312feb2SEric Paris } 373c312feb2SEric Paris 3740808925eSEric Paris static int may_context_mount_inode_relabel(u32 sid, 3750808925eSEric Paris struct superblock_security_struct *sbsec, 376*275bb41eSDavid Howells const struct cred *cred) 3770808925eSEric Paris { 378*275bb41eSDavid Howells const struct task_security_struct *tsec = cred->security; 3790808925eSEric Paris int rc; 3800808925eSEric Paris rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, 3810808925eSEric Paris FILESYSTEM__RELABELFROM, NULL); 3820808925eSEric Paris if (rc) 3830808925eSEric Paris return rc; 3840808925eSEric Paris 3850808925eSEric Paris rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, 3860808925eSEric Paris FILESYSTEM__ASSOCIATE, NULL); 3870808925eSEric Paris return rc; 3880808925eSEric Paris } 3890808925eSEric Paris 390c9180a57SEric Paris static int sb_finish_set_opts(struct super_block *sb) 3911da177e4SLinus Torvalds { 3921da177e4SLinus Torvalds struct superblock_security_struct *sbsec = sb->s_security; 3931da177e4SLinus Torvalds struct dentry *root = sb->s_root; 394c9180a57SEric Paris struct inode *root_inode = root->d_inode; 3951da177e4SLinus Torvalds int rc = 0; 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds if (sbsec->behavior == SECURITY_FS_USE_XATTR) { 3981da177e4SLinus Torvalds /* Make sure that the xattr handler exists and that no 3991da177e4SLinus Torvalds error other than -ENODATA is returned by getxattr on 4001da177e4SLinus Torvalds the root directory. -ENODATA is ok, as this may be 4011da177e4SLinus Torvalds the first boot of the SELinux kernel before we have 4021da177e4SLinus Torvalds assigned xattr values to the filesystem. */ 403c9180a57SEric Paris if (!root_inode->i_op->getxattr) { 4041da177e4SLinus Torvalds printk(KERN_WARNING "SELinux: (dev %s, type %s) has no " 4051da177e4SLinus Torvalds "xattr support\n", sb->s_id, sb->s_type->name); 4061da177e4SLinus Torvalds rc = -EOPNOTSUPP; 4071da177e4SLinus Torvalds goto out; 4081da177e4SLinus Torvalds } 409c9180a57SEric Paris rc = root_inode->i_op->getxattr(root, XATTR_NAME_SELINUX, NULL, 0); 4101da177e4SLinus Torvalds if (rc < 0 && rc != -ENODATA) { 4111da177e4SLinus Torvalds if (rc == -EOPNOTSUPP) 4121da177e4SLinus Torvalds printk(KERN_WARNING "SELinux: (dev %s, type " 4131da177e4SLinus Torvalds "%s) has no security xattr handler\n", 4141da177e4SLinus Torvalds sb->s_id, sb->s_type->name); 4151da177e4SLinus Torvalds else 4161da177e4SLinus Torvalds printk(KERN_WARNING "SELinux: (dev %s, type " 4171da177e4SLinus Torvalds "%s) getxattr errno %d\n", sb->s_id, 4181da177e4SLinus Torvalds sb->s_type->name, -rc); 4191da177e4SLinus Torvalds goto out; 4201da177e4SLinus Torvalds } 4211da177e4SLinus Torvalds } 4221da177e4SLinus Torvalds 4231da177e4SLinus Torvalds sbsec->initialized = 1; 4241da177e4SLinus Torvalds 425c9180a57SEric Paris if (sbsec->behavior > ARRAY_SIZE(labeling_behaviors)) 426fadcdb45SEric Paris printk(KERN_ERR "SELinux: initialized (dev %s, type %s), unknown behavior\n", 4271da177e4SLinus Torvalds sb->s_id, sb->s_type->name); 428c9180a57SEric Paris else 429fadcdb45SEric Paris printk(KERN_DEBUG "SELinux: initialized (dev %s, type %s), %s\n", 4301da177e4SLinus Torvalds sb->s_id, sb->s_type->name, 4311da177e4SLinus Torvalds labeling_behaviors[sbsec->behavior-1]); 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds /* Initialize the root inode. */ 434c9180a57SEric Paris rc = inode_doinit_with_dentry(root_inode, root); 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds /* Initialize any other inodes associated with the superblock, e.g. 4371da177e4SLinus Torvalds inodes created prior to initial policy load or inodes created 4381da177e4SLinus Torvalds during get_sb by a pseudo filesystem that directly 4391da177e4SLinus Torvalds populates itself. */ 4401da177e4SLinus Torvalds spin_lock(&sbsec->isec_lock); 4411da177e4SLinus Torvalds next_inode: 4421da177e4SLinus Torvalds if (!list_empty(&sbsec->isec_head)) { 4431da177e4SLinus Torvalds struct inode_security_struct *isec = 4441da177e4SLinus Torvalds list_entry(sbsec->isec_head.next, 4451da177e4SLinus Torvalds struct inode_security_struct, list); 4461da177e4SLinus Torvalds struct inode *inode = isec->inode; 4471da177e4SLinus Torvalds spin_unlock(&sbsec->isec_lock); 4481da177e4SLinus Torvalds inode = igrab(inode); 4491da177e4SLinus Torvalds if (inode) { 4501da177e4SLinus Torvalds if (!IS_PRIVATE(inode)) 4511da177e4SLinus Torvalds inode_doinit(inode); 4521da177e4SLinus Torvalds iput(inode); 4531da177e4SLinus Torvalds } 4541da177e4SLinus Torvalds spin_lock(&sbsec->isec_lock); 4551da177e4SLinus Torvalds list_del_init(&isec->list); 4561da177e4SLinus Torvalds goto next_inode; 4571da177e4SLinus Torvalds } 4581da177e4SLinus Torvalds spin_unlock(&sbsec->isec_lock); 4591da177e4SLinus Torvalds out: 460c9180a57SEric Paris return rc; 461c9180a57SEric Paris } 462c9180a57SEric Paris 463c9180a57SEric Paris /* 464c9180a57SEric Paris * This function should allow an FS to ask what it's mount security 465c9180a57SEric Paris * options were so it can use those later for submounts, displaying 466c9180a57SEric Paris * mount options, or whatever. 467c9180a57SEric Paris */ 468c9180a57SEric Paris static int selinux_get_mnt_opts(const struct super_block *sb, 469e0007529SEric Paris struct security_mnt_opts *opts) 470c9180a57SEric Paris { 471c9180a57SEric Paris int rc = 0, i; 472c9180a57SEric Paris struct superblock_security_struct *sbsec = sb->s_security; 473c9180a57SEric Paris char *context = NULL; 474c9180a57SEric Paris u32 len; 475c9180a57SEric Paris char tmp; 476c9180a57SEric Paris 477e0007529SEric Paris security_init_mnt_opts(opts); 478c9180a57SEric Paris 479c9180a57SEric Paris if (!sbsec->initialized) 480c9180a57SEric Paris return -EINVAL; 481c9180a57SEric Paris 482c9180a57SEric Paris if (!ss_initialized) 483c9180a57SEric Paris return -EINVAL; 484c9180a57SEric Paris 485c9180a57SEric Paris /* 486c9180a57SEric Paris * if we ever use sbsec flags for anything other than tracking mount 487c9180a57SEric Paris * settings this is going to need a mask 488c9180a57SEric Paris */ 489c9180a57SEric Paris tmp = sbsec->flags; 490c9180a57SEric Paris /* count the number of mount options for this sb */ 491c9180a57SEric Paris for (i = 0; i < 8; i++) { 492c9180a57SEric Paris if (tmp & 0x01) 493e0007529SEric Paris opts->num_mnt_opts++; 494c9180a57SEric Paris tmp >>= 1; 495c9180a57SEric Paris } 496c9180a57SEric Paris 497e0007529SEric Paris opts->mnt_opts = kcalloc(opts->num_mnt_opts, sizeof(char *), GFP_ATOMIC); 498e0007529SEric Paris if (!opts->mnt_opts) { 499c9180a57SEric Paris rc = -ENOMEM; 500c9180a57SEric Paris goto out_free; 501c9180a57SEric Paris } 502c9180a57SEric Paris 503e0007529SEric Paris opts->mnt_opts_flags = kcalloc(opts->num_mnt_opts, sizeof(int), GFP_ATOMIC); 504e0007529SEric Paris if (!opts->mnt_opts_flags) { 505c9180a57SEric Paris rc = -ENOMEM; 506c9180a57SEric Paris goto out_free; 507c9180a57SEric Paris } 508c9180a57SEric Paris 509c9180a57SEric Paris i = 0; 510c9180a57SEric Paris if (sbsec->flags & FSCONTEXT_MNT) { 511c9180a57SEric Paris rc = security_sid_to_context(sbsec->sid, &context, &len); 512c9180a57SEric Paris if (rc) 513c9180a57SEric Paris goto out_free; 514e0007529SEric Paris opts->mnt_opts[i] = context; 515e0007529SEric Paris opts->mnt_opts_flags[i++] = FSCONTEXT_MNT; 516c9180a57SEric Paris } 517c9180a57SEric Paris if (sbsec->flags & CONTEXT_MNT) { 518c9180a57SEric Paris rc = security_sid_to_context(sbsec->mntpoint_sid, &context, &len); 519c9180a57SEric Paris if (rc) 520c9180a57SEric Paris goto out_free; 521e0007529SEric Paris opts->mnt_opts[i] = context; 522e0007529SEric Paris opts->mnt_opts_flags[i++] = CONTEXT_MNT; 523c9180a57SEric Paris } 524c9180a57SEric Paris if (sbsec->flags & DEFCONTEXT_MNT) { 525c9180a57SEric Paris rc = security_sid_to_context(sbsec->def_sid, &context, &len); 526c9180a57SEric Paris if (rc) 527c9180a57SEric Paris goto out_free; 528e0007529SEric Paris opts->mnt_opts[i] = context; 529e0007529SEric Paris opts->mnt_opts_flags[i++] = DEFCONTEXT_MNT; 530c9180a57SEric Paris } 531c9180a57SEric Paris if (sbsec->flags & ROOTCONTEXT_MNT) { 532c9180a57SEric Paris struct inode *root = sbsec->sb->s_root->d_inode; 533c9180a57SEric Paris struct inode_security_struct *isec = root->i_security; 534c9180a57SEric Paris 535c9180a57SEric Paris rc = security_sid_to_context(isec->sid, &context, &len); 536c9180a57SEric Paris if (rc) 537c9180a57SEric Paris goto out_free; 538e0007529SEric Paris opts->mnt_opts[i] = context; 539e0007529SEric Paris opts->mnt_opts_flags[i++] = ROOTCONTEXT_MNT; 540c9180a57SEric Paris } 541c9180a57SEric Paris 542e0007529SEric Paris BUG_ON(i != opts->num_mnt_opts); 543c9180a57SEric Paris 544c9180a57SEric Paris return 0; 545c9180a57SEric Paris 546c9180a57SEric Paris out_free: 547e0007529SEric Paris security_free_mnt_opts(opts); 548c9180a57SEric Paris return rc; 549c9180a57SEric Paris } 550c9180a57SEric Paris 551c9180a57SEric Paris static int bad_option(struct superblock_security_struct *sbsec, char flag, 552c9180a57SEric Paris u32 old_sid, u32 new_sid) 553c9180a57SEric Paris { 554c9180a57SEric Paris /* check if the old mount command had the same options */ 555c9180a57SEric Paris if (sbsec->initialized) 556c9180a57SEric Paris if (!(sbsec->flags & flag) || 557c9180a57SEric Paris (old_sid != new_sid)) 558c9180a57SEric Paris return 1; 559c9180a57SEric Paris 560c9180a57SEric Paris /* check if we were passed the same options twice, 561c9180a57SEric Paris * aka someone passed context=a,context=b 562c9180a57SEric Paris */ 563c9180a57SEric Paris if (!sbsec->initialized) 564c9180a57SEric Paris if (sbsec->flags & flag) 565c9180a57SEric Paris return 1; 566c9180a57SEric Paris return 0; 567c9180a57SEric Paris } 568e0007529SEric Paris 569c9180a57SEric Paris /* 570c9180a57SEric Paris * Allow filesystems with binary mount data to explicitly set mount point 571c9180a57SEric Paris * labeling information. 572c9180a57SEric Paris */ 573e0007529SEric Paris static int selinux_set_mnt_opts(struct super_block *sb, 574e0007529SEric Paris struct security_mnt_opts *opts) 575c9180a57SEric Paris { 576*275bb41eSDavid Howells const struct cred *cred = current_cred(); 577c9180a57SEric Paris int rc = 0, i; 578c9180a57SEric Paris struct superblock_security_struct *sbsec = sb->s_security; 579c9180a57SEric Paris const char *name = sb->s_type->name; 580089be43eSJames Morris struct inode *inode = sbsec->sb->s_root->d_inode; 581089be43eSJames Morris struct inode_security_struct *root_isec = inode->i_security; 582c9180a57SEric Paris u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; 583c9180a57SEric Paris u32 defcontext_sid = 0; 584e0007529SEric Paris char **mount_options = opts->mnt_opts; 585e0007529SEric Paris int *flags = opts->mnt_opts_flags; 586e0007529SEric Paris int num_opts = opts->num_mnt_opts; 587c9180a57SEric Paris 588c9180a57SEric Paris mutex_lock(&sbsec->lock); 589c9180a57SEric Paris 590c9180a57SEric Paris if (!ss_initialized) { 591c9180a57SEric Paris if (!num_opts) { 592c9180a57SEric Paris /* Defer initialization until selinux_complete_init, 593c9180a57SEric Paris after the initial policy is loaded and the security 594c9180a57SEric Paris server is ready to handle calls. */ 595c9180a57SEric Paris spin_lock(&sb_security_lock); 596c9180a57SEric Paris if (list_empty(&sbsec->list)) 597c9180a57SEric Paris list_add(&sbsec->list, &superblock_security_head); 598c9180a57SEric Paris spin_unlock(&sb_security_lock); 599c9180a57SEric Paris goto out; 600c9180a57SEric Paris } 601c9180a57SEric Paris rc = -EINVAL; 602744ba35eSEric Paris printk(KERN_WARNING "SELinux: Unable to set superblock options " 603744ba35eSEric Paris "before the security server is initialized\n"); 604c9180a57SEric Paris goto out; 605c9180a57SEric Paris } 606c9180a57SEric Paris 607c9180a57SEric Paris /* 608e0007529SEric Paris * Binary mount data FS will come through this function twice. Once 609e0007529SEric Paris * from an explicit call and once from the generic calls from the vfs. 610e0007529SEric Paris * Since the generic VFS calls will not contain any security mount data 611e0007529SEric Paris * we need to skip the double mount verification. 612e0007529SEric Paris * 613e0007529SEric Paris * This does open a hole in which we will not notice if the first 614e0007529SEric Paris * mount using this sb set explict options and a second mount using 615e0007529SEric Paris * this sb does not set any security options. (The first options 616e0007529SEric Paris * will be used for both mounts) 617e0007529SEric Paris */ 618e0007529SEric Paris if (sbsec->initialized && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) 619e0007529SEric Paris && (num_opts == 0)) 620e0007529SEric Paris goto out; 621e0007529SEric Paris 622e0007529SEric Paris /* 623c9180a57SEric Paris * parse the mount options, check if they are valid sids. 624c9180a57SEric Paris * also check if someone is trying to mount the same sb more 625c9180a57SEric Paris * than once with different security options. 626c9180a57SEric Paris */ 627c9180a57SEric Paris for (i = 0; i < num_opts; i++) { 628c9180a57SEric Paris u32 sid; 629c9180a57SEric Paris rc = security_context_to_sid(mount_options[i], 630c9180a57SEric Paris strlen(mount_options[i]), &sid); 631c9180a57SEric Paris if (rc) { 632c9180a57SEric Paris printk(KERN_WARNING "SELinux: security_context_to_sid" 633c9180a57SEric Paris "(%s) failed for (dev %s, type %s) errno=%d\n", 634c9180a57SEric Paris mount_options[i], sb->s_id, name, rc); 635c9180a57SEric Paris goto out; 636c9180a57SEric Paris } 637c9180a57SEric Paris switch (flags[i]) { 638c9180a57SEric Paris case FSCONTEXT_MNT: 639c9180a57SEric Paris fscontext_sid = sid; 640c9180a57SEric Paris 641c9180a57SEric Paris if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, 642c9180a57SEric Paris fscontext_sid)) 643c9180a57SEric Paris goto out_double_mount; 644c9180a57SEric Paris 645c9180a57SEric Paris sbsec->flags |= FSCONTEXT_MNT; 646c9180a57SEric Paris break; 647c9180a57SEric Paris case CONTEXT_MNT: 648c9180a57SEric Paris context_sid = sid; 649c9180a57SEric Paris 650c9180a57SEric Paris if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, 651c9180a57SEric Paris context_sid)) 652c9180a57SEric Paris goto out_double_mount; 653c9180a57SEric Paris 654c9180a57SEric Paris sbsec->flags |= CONTEXT_MNT; 655c9180a57SEric Paris break; 656c9180a57SEric Paris case ROOTCONTEXT_MNT: 657c9180a57SEric Paris rootcontext_sid = sid; 658c9180a57SEric Paris 659c9180a57SEric Paris if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, 660c9180a57SEric Paris rootcontext_sid)) 661c9180a57SEric Paris goto out_double_mount; 662c9180a57SEric Paris 663c9180a57SEric Paris sbsec->flags |= ROOTCONTEXT_MNT; 664c9180a57SEric Paris 665c9180a57SEric Paris break; 666c9180a57SEric Paris case DEFCONTEXT_MNT: 667c9180a57SEric Paris defcontext_sid = sid; 668c9180a57SEric Paris 669c9180a57SEric Paris if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, 670c9180a57SEric Paris defcontext_sid)) 671c9180a57SEric Paris goto out_double_mount; 672c9180a57SEric Paris 673c9180a57SEric Paris sbsec->flags |= DEFCONTEXT_MNT; 674c9180a57SEric Paris 675c9180a57SEric Paris break; 676c9180a57SEric Paris default: 677c9180a57SEric Paris rc = -EINVAL; 678c9180a57SEric Paris goto out; 679c9180a57SEric Paris } 680c9180a57SEric Paris } 681c9180a57SEric Paris 682c9180a57SEric Paris if (sbsec->initialized) { 683c9180a57SEric Paris /* previously mounted with options, but not on this attempt? */ 684c9180a57SEric Paris if (sbsec->flags && !num_opts) 685c9180a57SEric Paris goto out_double_mount; 686c9180a57SEric Paris rc = 0; 687c9180a57SEric Paris goto out; 688c9180a57SEric Paris } 689c9180a57SEric Paris 690089be43eSJames Morris if (strcmp(sb->s_type->name, "proc") == 0) 691c9180a57SEric Paris sbsec->proc = 1; 692c9180a57SEric Paris 693c9180a57SEric Paris /* Determine the labeling behavior to use for this filesystem type. */ 694089be43eSJames Morris rc = security_fs_use(sb->s_type->name, &sbsec->behavior, &sbsec->sid); 695c9180a57SEric Paris if (rc) { 696c9180a57SEric Paris printk(KERN_WARNING "%s: security_fs_use(%s) returned %d\n", 697089be43eSJames Morris __func__, sb->s_type->name, rc); 698c9180a57SEric Paris goto out; 699c9180a57SEric Paris } 700c9180a57SEric Paris 701c9180a57SEric Paris /* sets the context of the superblock for the fs being mounted. */ 702c9180a57SEric Paris if (fscontext_sid) { 703*275bb41eSDavid Howells rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred); 704c9180a57SEric Paris if (rc) 705c9180a57SEric Paris goto out; 706c9180a57SEric Paris 707c9180a57SEric Paris sbsec->sid = fscontext_sid; 708c9180a57SEric Paris } 709c9180a57SEric Paris 710c9180a57SEric Paris /* 711c9180a57SEric Paris * Switch to using mount point labeling behavior. 712c9180a57SEric Paris * sets the label used on all file below the mountpoint, and will set 713c9180a57SEric Paris * the superblock context if not already set. 714c9180a57SEric Paris */ 715c9180a57SEric Paris if (context_sid) { 716c9180a57SEric Paris if (!fscontext_sid) { 717*275bb41eSDavid Howells rc = may_context_mount_sb_relabel(context_sid, sbsec, 718*275bb41eSDavid Howells cred); 719c9180a57SEric Paris if (rc) 720c9180a57SEric Paris goto out; 721c9180a57SEric Paris sbsec->sid = context_sid; 722c9180a57SEric Paris } else { 723*275bb41eSDavid Howells rc = may_context_mount_inode_relabel(context_sid, sbsec, 724*275bb41eSDavid Howells cred); 725c9180a57SEric Paris if (rc) 726c9180a57SEric Paris goto out; 727c9180a57SEric Paris } 728c9180a57SEric Paris if (!rootcontext_sid) 729c9180a57SEric Paris rootcontext_sid = context_sid; 730c9180a57SEric Paris 731c9180a57SEric Paris sbsec->mntpoint_sid = context_sid; 732c9180a57SEric Paris sbsec->behavior = SECURITY_FS_USE_MNTPOINT; 733c9180a57SEric Paris } 734c9180a57SEric Paris 735c9180a57SEric Paris if (rootcontext_sid) { 736*275bb41eSDavid Howells rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, 737*275bb41eSDavid Howells cred); 738c9180a57SEric Paris if (rc) 739c9180a57SEric Paris goto out; 740c9180a57SEric Paris 741c9180a57SEric Paris root_isec->sid = rootcontext_sid; 742c9180a57SEric Paris root_isec->initialized = 1; 743c9180a57SEric Paris } 744c9180a57SEric Paris 745c9180a57SEric Paris if (defcontext_sid) { 746c9180a57SEric Paris if (sbsec->behavior != SECURITY_FS_USE_XATTR) { 747c9180a57SEric Paris rc = -EINVAL; 748c9180a57SEric Paris printk(KERN_WARNING "SELinux: defcontext option is " 749c9180a57SEric Paris "invalid for this filesystem type\n"); 750c9180a57SEric Paris goto out; 751c9180a57SEric Paris } 752c9180a57SEric Paris 753c9180a57SEric Paris if (defcontext_sid != sbsec->def_sid) { 754c9180a57SEric Paris rc = may_context_mount_inode_relabel(defcontext_sid, 755*275bb41eSDavid Howells sbsec, cred); 756c9180a57SEric Paris if (rc) 757c9180a57SEric Paris goto out; 758c9180a57SEric Paris } 759c9180a57SEric Paris 760c9180a57SEric Paris sbsec->def_sid = defcontext_sid; 761c9180a57SEric Paris } 762c9180a57SEric Paris 763c9180a57SEric Paris rc = sb_finish_set_opts(sb); 764c9180a57SEric Paris out: 765bc7e982bSEric Paris mutex_unlock(&sbsec->lock); 7661da177e4SLinus Torvalds return rc; 767c9180a57SEric Paris out_double_mount: 768c9180a57SEric Paris rc = -EINVAL; 769c9180a57SEric Paris printk(KERN_WARNING "SELinux: mount invalid. Same superblock, different " 770c9180a57SEric Paris "security settings for (dev %s, type %s)\n", sb->s_id, name); 771c9180a57SEric Paris goto out; 772c9180a57SEric Paris } 773c9180a57SEric Paris 774c9180a57SEric Paris static void selinux_sb_clone_mnt_opts(const struct super_block *oldsb, 775c9180a57SEric Paris struct super_block *newsb) 776c9180a57SEric Paris { 777c9180a57SEric Paris const struct superblock_security_struct *oldsbsec = oldsb->s_security; 778c9180a57SEric Paris struct superblock_security_struct *newsbsec = newsb->s_security; 779c9180a57SEric Paris 780c9180a57SEric Paris int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT); 781c9180a57SEric Paris int set_context = (oldsbsec->flags & CONTEXT_MNT); 782c9180a57SEric Paris int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT); 783c9180a57SEric Paris 7840f5e6420SEric Paris /* 7850f5e6420SEric Paris * if the parent was able to be mounted it clearly had no special lsm 7860f5e6420SEric Paris * mount options. thus we can safely put this sb on the list and deal 7870f5e6420SEric Paris * with it later 7880f5e6420SEric Paris */ 7890f5e6420SEric Paris if (!ss_initialized) { 7900f5e6420SEric Paris spin_lock(&sb_security_lock); 7910f5e6420SEric Paris if (list_empty(&newsbsec->list)) 7920f5e6420SEric Paris list_add(&newsbsec->list, &superblock_security_head); 7930f5e6420SEric Paris spin_unlock(&sb_security_lock); 7940f5e6420SEric Paris return; 7950f5e6420SEric Paris } 796c9180a57SEric Paris 797c9180a57SEric Paris /* how can we clone if the old one wasn't set up?? */ 798c9180a57SEric Paris BUG_ON(!oldsbsec->initialized); 799c9180a57SEric Paris 8005a552617SEric Paris /* if fs is reusing a sb, just let its options stand... */ 8015a552617SEric Paris if (newsbsec->initialized) 8025a552617SEric Paris return; 8035a552617SEric Paris 804c9180a57SEric Paris mutex_lock(&newsbsec->lock); 805c9180a57SEric Paris 806c9180a57SEric Paris newsbsec->flags = oldsbsec->flags; 807c9180a57SEric Paris 808c9180a57SEric Paris newsbsec->sid = oldsbsec->sid; 809c9180a57SEric Paris newsbsec->def_sid = oldsbsec->def_sid; 810c9180a57SEric Paris newsbsec->behavior = oldsbsec->behavior; 811c9180a57SEric Paris 812c9180a57SEric Paris if (set_context) { 813c9180a57SEric Paris u32 sid = oldsbsec->mntpoint_sid; 814c9180a57SEric Paris 815c9180a57SEric Paris if (!set_fscontext) 816c9180a57SEric Paris newsbsec->sid = sid; 817c9180a57SEric Paris if (!set_rootcontext) { 818c9180a57SEric Paris struct inode *newinode = newsb->s_root->d_inode; 819c9180a57SEric Paris struct inode_security_struct *newisec = newinode->i_security; 820c9180a57SEric Paris newisec->sid = sid; 821c9180a57SEric Paris } 822c9180a57SEric Paris newsbsec->mntpoint_sid = sid; 823c9180a57SEric Paris } 824c9180a57SEric Paris if (set_rootcontext) { 825c9180a57SEric Paris const struct inode *oldinode = oldsb->s_root->d_inode; 826c9180a57SEric Paris const struct inode_security_struct *oldisec = oldinode->i_security; 827c9180a57SEric Paris struct inode *newinode = newsb->s_root->d_inode; 828c9180a57SEric Paris struct inode_security_struct *newisec = newinode->i_security; 829c9180a57SEric Paris 830c9180a57SEric Paris newisec->sid = oldisec->sid; 831c9180a57SEric Paris } 832c9180a57SEric Paris 833c9180a57SEric Paris sb_finish_set_opts(newsb); 834c9180a57SEric Paris mutex_unlock(&newsbsec->lock); 835c9180a57SEric Paris } 836c9180a57SEric Paris 8372e1479d9SAdrian Bunk static int selinux_parse_opts_str(char *options, 8382e1479d9SAdrian Bunk struct security_mnt_opts *opts) 839c9180a57SEric Paris { 840e0007529SEric Paris char *p; 841c9180a57SEric Paris char *context = NULL, *defcontext = NULL; 842c9180a57SEric Paris char *fscontext = NULL, *rootcontext = NULL; 843e0007529SEric Paris int rc, num_mnt_opts = 0; 844c9180a57SEric Paris 845e0007529SEric Paris opts->num_mnt_opts = 0; 846c9180a57SEric Paris 847c9180a57SEric Paris /* Standard string-based options. */ 848c9180a57SEric Paris while ((p = strsep(&options, "|")) != NULL) { 849c9180a57SEric Paris int token; 850c9180a57SEric Paris substring_t args[MAX_OPT_ARGS]; 851c9180a57SEric Paris 852c9180a57SEric Paris if (!*p) 853c9180a57SEric Paris continue; 854c9180a57SEric Paris 855c9180a57SEric Paris token = match_token(p, tokens, args); 856c9180a57SEric Paris 857c9180a57SEric Paris switch (token) { 858c9180a57SEric Paris case Opt_context: 859c9180a57SEric Paris if (context || defcontext) { 860c9180a57SEric Paris rc = -EINVAL; 861c9180a57SEric Paris printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); 862c9180a57SEric Paris goto out_err; 863c9180a57SEric Paris } 864c9180a57SEric Paris context = match_strdup(&args[0]); 865c9180a57SEric Paris if (!context) { 866c9180a57SEric Paris rc = -ENOMEM; 867c9180a57SEric Paris goto out_err; 868c9180a57SEric Paris } 869c9180a57SEric Paris break; 870c9180a57SEric Paris 871c9180a57SEric Paris case Opt_fscontext: 872c9180a57SEric Paris if (fscontext) { 873c9180a57SEric Paris rc = -EINVAL; 874c9180a57SEric Paris printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); 875c9180a57SEric Paris goto out_err; 876c9180a57SEric Paris } 877c9180a57SEric Paris fscontext = match_strdup(&args[0]); 878c9180a57SEric Paris if (!fscontext) { 879c9180a57SEric Paris rc = -ENOMEM; 880c9180a57SEric Paris goto out_err; 881c9180a57SEric Paris } 882c9180a57SEric Paris break; 883c9180a57SEric Paris 884c9180a57SEric Paris case Opt_rootcontext: 885c9180a57SEric Paris if (rootcontext) { 886c9180a57SEric Paris rc = -EINVAL; 887c9180a57SEric Paris printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); 888c9180a57SEric Paris goto out_err; 889c9180a57SEric Paris } 890c9180a57SEric Paris rootcontext = match_strdup(&args[0]); 891c9180a57SEric Paris if (!rootcontext) { 892c9180a57SEric Paris rc = -ENOMEM; 893c9180a57SEric Paris goto out_err; 894c9180a57SEric Paris } 895c9180a57SEric Paris break; 896c9180a57SEric Paris 897c9180a57SEric Paris case Opt_defcontext: 898c9180a57SEric Paris if (context || defcontext) { 899c9180a57SEric Paris rc = -EINVAL; 900c9180a57SEric Paris printk(KERN_WARNING SEL_MOUNT_FAIL_MSG); 901c9180a57SEric Paris goto out_err; 902c9180a57SEric Paris } 903c9180a57SEric Paris defcontext = match_strdup(&args[0]); 904c9180a57SEric Paris if (!defcontext) { 905c9180a57SEric Paris rc = -ENOMEM; 906c9180a57SEric Paris goto out_err; 907c9180a57SEric Paris } 908c9180a57SEric Paris break; 909c9180a57SEric Paris 910c9180a57SEric Paris default: 911c9180a57SEric Paris rc = -EINVAL; 912c9180a57SEric Paris printk(KERN_WARNING "SELinux: unknown mount option\n"); 913c9180a57SEric Paris goto out_err; 914c9180a57SEric Paris 915c9180a57SEric Paris } 916c9180a57SEric Paris } 917c9180a57SEric Paris 918e0007529SEric Paris rc = -ENOMEM; 919e0007529SEric Paris opts->mnt_opts = kcalloc(NUM_SEL_MNT_OPTS, sizeof(char *), GFP_ATOMIC); 920e0007529SEric Paris if (!opts->mnt_opts) 921e0007529SEric Paris goto out_err; 922e0007529SEric Paris 923e0007529SEric Paris opts->mnt_opts_flags = kcalloc(NUM_SEL_MNT_OPTS, sizeof(int), GFP_ATOMIC); 924e0007529SEric Paris if (!opts->mnt_opts_flags) { 925e0007529SEric Paris kfree(opts->mnt_opts); 926e0007529SEric Paris goto out_err; 927c9180a57SEric Paris } 928c9180a57SEric Paris 929e0007529SEric Paris if (fscontext) { 930e0007529SEric Paris opts->mnt_opts[num_mnt_opts] = fscontext; 931e0007529SEric Paris opts->mnt_opts_flags[num_mnt_opts++] = FSCONTEXT_MNT; 932e0007529SEric Paris } 933e0007529SEric Paris if (context) { 934e0007529SEric Paris opts->mnt_opts[num_mnt_opts] = context; 935e0007529SEric Paris opts->mnt_opts_flags[num_mnt_opts++] = CONTEXT_MNT; 936e0007529SEric Paris } 937e0007529SEric Paris if (rootcontext) { 938e0007529SEric Paris opts->mnt_opts[num_mnt_opts] = rootcontext; 939e0007529SEric Paris opts->mnt_opts_flags[num_mnt_opts++] = ROOTCONTEXT_MNT; 940e0007529SEric Paris } 941e0007529SEric Paris if (defcontext) { 942e0007529SEric Paris opts->mnt_opts[num_mnt_opts] = defcontext; 943e0007529SEric Paris opts->mnt_opts_flags[num_mnt_opts++] = DEFCONTEXT_MNT; 944e0007529SEric Paris } 945e0007529SEric Paris 946e0007529SEric Paris opts->num_mnt_opts = num_mnt_opts; 947e0007529SEric Paris return 0; 948e0007529SEric Paris 949c9180a57SEric Paris out_err: 950c9180a57SEric Paris kfree(context); 951c9180a57SEric Paris kfree(defcontext); 952c9180a57SEric Paris kfree(fscontext); 953c9180a57SEric Paris kfree(rootcontext); 954c9180a57SEric Paris return rc; 9551da177e4SLinus Torvalds } 956e0007529SEric Paris /* 957e0007529SEric Paris * string mount options parsing and call set the sbsec 958e0007529SEric Paris */ 959e0007529SEric Paris static int superblock_doinit(struct super_block *sb, void *data) 960e0007529SEric Paris { 961e0007529SEric Paris int rc = 0; 962e0007529SEric Paris char *options = data; 963e0007529SEric Paris struct security_mnt_opts opts; 964e0007529SEric Paris 965e0007529SEric Paris security_init_mnt_opts(&opts); 966e0007529SEric Paris 967e0007529SEric Paris if (!data) 968e0007529SEric Paris goto out; 969e0007529SEric Paris 970e0007529SEric Paris BUG_ON(sb->s_type->fs_flags & FS_BINARY_MOUNTDATA); 971e0007529SEric Paris 972e0007529SEric Paris rc = selinux_parse_opts_str(options, &opts); 973e0007529SEric Paris if (rc) 974e0007529SEric Paris goto out_err; 975e0007529SEric Paris 976e0007529SEric Paris out: 977e0007529SEric Paris rc = selinux_set_mnt_opts(sb, &opts); 978e0007529SEric Paris 979e0007529SEric Paris out_err: 980e0007529SEric Paris security_free_mnt_opts(&opts); 981e0007529SEric Paris return rc; 982e0007529SEric Paris } 9831da177e4SLinus Torvalds 9843583a711SAdrian Bunk static void selinux_write_opts(struct seq_file *m, 9853583a711SAdrian Bunk struct security_mnt_opts *opts) 9862069f457SEric Paris { 9872069f457SEric Paris int i; 9882069f457SEric Paris char *prefix; 9892069f457SEric Paris 9902069f457SEric Paris for (i = 0; i < opts->num_mnt_opts; i++) { 9912069f457SEric Paris char *has_comma = strchr(opts->mnt_opts[i], ','); 9922069f457SEric Paris 9932069f457SEric Paris switch (opts->mnt_opts_flags[i]) { 9942069f457SEric Paris case CONTEXT_MNT: 9952069f457SEric Paris prefix = CONTEXT_STR; 9962069f457SEric Paris break; 9972069f457SEric Paris case FSCONTEXT_MNT: 9982069f457SEric Paris prefix = FSCONTEXT_STR; 9992069f457SEric Paris break; 10002069f457SEric Paris case ROOTCONTEXT_MNT: 10012069f457SEric Paris prefix = ROOTCONTEXT_STR; 10022069f457SEric Paris break; 10032069f457SEric Paris case DEFCONTEXT_MNT: 10042069f457SEric Paris prefix = DEFCONTEXT_STR; 10052069f457SEric Paris break; 10062069f457SEric Paris default: 10072069f457SEric Paris BUG(); 10082069f457SEric Paris }; 10092069f457SEric Paris /* we need a comma before each option */ 10102069f457SEric Paris seq_putc(m, ','); 10112069f457SEric Paris seq_puts(m, prefix); 10122069f457SEric Paris if (has_comma) 10132069f457SEric Paris seq_putc(m, '\"'); 10142069f457SEric Paris seq_puts(m, opts->mnt_opts[i]); 10152069f457SEric Paris if (has_comma) 10162069f457SEric Paris seq_putc(m, '\"'); 10172069f457SEric Paris } 10182069f457SEric Paris } 10192069f457SEric Paris 10202069f457SEric Paris static int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) 10212069f457SEric Paris { 10222069f457SEric Paris struct security_mnt_opts opts; 10232069f457SEric Paris int rc; 10242069f457SEric Paris 10252069f457SEric Paris rc = selinux_get_mnt_opts(sb, &opts); 1026383795c2SEric Paris if (rc) { 1027383795c2SEric Paris /* before policy load we may get EINVAL, don't show anything */ 1028383795c2SEric Paris if (rc == -EINVAL) 1029383795c2SEric Paris rc = 0; 10302069f457SEric Paris return rc; 1031383795c2SEric Paris } 10322069f457SEric Paris 10332069f457SEric Paris selinux_write_opts(m, &opts); 10342069f457SEric Paris 10352069f457SEric Paris security_free_mnt_opts(&opts); 10362069f457SEric Paris 10372069f457SEric Paris return rc; 10382069f457SEric Paris } 10392069f457SEric Paris 10401da177e4SLinus Torvalds static inline u16 inode_mode_to_security_class(umode_t mode) 10411da177e4SLinus Torvalds { 10421da177e4SLinus Torvalds switch (mode & S_IFMT) { 10431da177e4SLinus Torvalds case S_IFSOCK: 10441da177e4SLinus Torvalds return SECCLASS_SOCK_FILE; 10451da177e4SLinus Torvalds case S_IFLNK: 10461da177e4SLinus Torvalds return SECCLASS_LNK_FILE; 10471da177e4SLinus Torvalds case S_IFREG: 10481da177e4SLinus Torvalds return SECCLASS_FILE; 10491da177e4SLinus Torvalds case S_IFBLK: 10501da177e4SLinus Torvalds return SECCLASS_BLK_FILE; 10511da177e4SLinus Torvalds case S_IFDIR: 10521da177e4SLinus Torvalds return SECCLASS_DIR; 10531da177e4SLinus Torvalds case S_IFCHR: 10541da177e4SLinus Torvalds return SECCLASS_CHR_FILE; 10551da177e4SLinus Torvalds case S_IFIFO: 10561da177e4SLinus Torvalds return SECCLASS_FIFO_FILE; 10571da177e4SLinus Torvalds 10581da177e4SLinus Torvalds } 10591da177e4SLinus Torvalds 10601da177e4SLinus Torvalds return SECCLASS_FILE; 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds 106313402580SJames Morris static inline int default_protocol_stream(int protocol) 106413402580SJames Morris { 106513402580SJames Morris return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP); 106613402580SJames Morris } 106713402580SJames Morris 106813402580SJames Morris static inline int default_protocol_dgram(int protocol) 106913402580SJames Morris { 107013402580SJames Morris return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP); 107113402580SJames Morris } 107213402580SJames Morris 10731da177e4SLinus Torvalds static inline u16 socket_type_to_security_class(int family, int type, int protocol) 10741da177e4SLinus Torvalds { 10751da177e4SLinus Torvalds switch (family) { 10761da177e4SLinus Torvalds case PF_UNIX: 10771da177e4SLinus Torvalds switch (type) { 10781da177e4SLinus Torvalds case SOCK_STREAM: 10791da177e4SLinus Torvalds case SOCK_SEQPACKET: 10801da177e4SLinus Torvalds return SECCLASS_UNIX_STREAM_SOCKET; 10811da177e4SLinus Torvalds case SOCK_DGRAM: 10821da177e4SLinus Torvalds return SECCLASS_UNIX_DGRAM_SOCKET; 10831da177e4SLinus Torvalds } 10841da177e4SLinus Torvalds break; 10851da177e4SLinus Torvalds case PF_INET: 10861da177e4SLinus Torvalds case PF_INET6: 10871da177e4SLinus Torvalds switch (type) { 10881da177e4SLinus Torvalds case SOCK_STREAM: 108913402580SJames Morris if (default_protocol_stream(protocol)) 10901da177e4SLinus Torvalds return SECCLASS_TCP_SOCKET; 109113402580SJames Morris else 109213402580SJames Morris return SECCLASS_RAWIP_SOCKET; 10931da177e4SLinus Torvalds case SOCK_DGRAM: 109413402580SJames Morris if (default_protocol_dgram(protocol)) 10951da177e4SLinus Torvalds return SECCLASS_UDP_SOCKET; 109613402580SJames Morris else 109713402580SJames Morris return SECCLASS_RAWIP_SOCKET; 10982ee92d46SJames Morris case SOCK_DCCP: 10992ee92d46SJames Morris return SECCLASS_DCCP_SOCKET; 110013402580SJames Morris default: 11011da177e4SLinus Torvalds return SECCLASS_RAWIP_SOCKET; 11021da177e4SLinus Torvalds } 11031da177e4SLinus Torvalds break; 11041da177e4SLinus Torvalds case PF_NETLINK: 11051da177e4SLinus Torvalds switch (protocol) { 11061da177e4SLinus Torvalds case NETLINK_ROUTE: 11071da177e4SLinus Torvalds return SECCLASS_NETLINK_ROUTE_SOCKET; 11081da177e4SLinus Torvalds case NETLINK_FIREWALL: 11091da177e4SLinus Torvalds return SECCLASS_NETLINK_FIREWALL_SOCKET; 1110216efaaaSJames Morris case NETLINK_INET_DIAG: 11111da177e4SLinus Torvalds return SECCLASS_NETLINK_TCPDIAG_SOCKET; 11121da177e4SLinus Torvalds case NETLINK_NFLOG: 11131da177e4SLinus Torvalds return SECCLASS_NETLINK_NFLOG_SOCKET; 11141da177e4SLinus Torvalds case NETLINK_XFRM: 11151da177e4SLinus Torvalds return SECCLASS_NETLINK_XFRM_SOCKET; 11161da177e4SLinus Torvalds case NETLINK_SELINUX: 11171da177e4SLinus Torvalds return SECCLASS_NETLINK_SELINUX_SOCKET; 11181da177e4SLinus Torvalds case NETLINK_AUDIT: 11191da177e4SLinus Torvalds return SECCLASS_NETLINK_AUDIT_SOCKET; 11201da177e4SLinus Torvalds case NETLINK_IP6_FW: 11211da177e4SLinus Torvalds return SECCLASS_NETLINK_IP6FW_SOCKET; 11221da177e4SLinus Torvalds case NETLINK_DNRTMSG: 11231da177e4SLinus Torvalds return SECCLASS_NETLINK_DNRT_SOCKET; 11240c9b7942SJames Morris case NETLINK_KOBJECT_UEVENT: 11250c9b7942SJames Morris return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET; 11261da177e4SLinus Torvalds default: 11271da177e4SLinus Torvalds return SECCLASS_NETLINK_SOCKET; 11281da177e4SLinus Torvalds } 11291da177e4SLinus Torvalds case PF_PACKET: 11301da177e4SLinus Torvalds return SECCLASS_PACKET_SOCKET; 11311da177e4SLinus Torvalds case PF_KEY: 11321da177e4SLinus Torvalds return SECCLASS_KEY_SOCKET; 11333e3ff15eSChristopher J. PeBenito case PF_APPLETALK: 11343e3ff15eSChristopher J. PeBenito return SECCLASS_APPLETALK_SOCKET; 11351da177e4SLinus Torvalds } 11361da177e4SLinus Torvalds 11371da177e4SLinus Torvalds return SECCLASS_SOCKET; 11381da177e4SLinus Torvalds } 11391da177e4SLinus Torvalds 11401da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 11411da177e4SLinus Torvalds static int selinux_proc_get_sid(struct proc_dir_entry *de, 11421da177e4SLinus Torvalds u16 tclass, 11431da177e4SLinus Torvalds u32 *sid) 11441da177e4SLinus Torvalds { 11451da177e4SLinus Torvalds int buflen, rc; 11461da177e4SLinus Torvalds char *buffer, *path, *end; 11471da177e4SLinus Torvalds 11481da177e4SLinus Torvalds buffer = (char *)__get_free_page(GFP_KERNEL); 11491da177e4SLinus Torvalds if (!buffer) 11501da177e4SLinus Torvalds return -ENOMEM; 11511da177e4SLinus Torvalds 11521da177e4SLinus Torvalds buflen = PAGE_SIZE; 11531da177e4SLinus Torvalds end = buffer+buflen; 11541da177e4SLinus Torvalds *--end = '\0'; 11551da177e4SLinus Torvalds buflen--; 11561da177e4SLinus Torvalds path = end-1; 11571da177e4SLinus Torvalds *path = '/'; 11581da177e4SLinus Torvalds while (de && de != de->parent) { 11591da177e4SLinus Torvalds buflen -= de->namelen + 1; 11601da177e4SLinus Torvalds if (buflen < 0) 11611da177e4SLinus Torvalds break; 11621da177e4SLinus Torvalds end -= de->namelen; 11631da177e4SLinus Torvalds memcpy(end, de->name, de->namelen); 11641da177e4SLinus Torvalds *--end = '/'; 11651da177e4SLinus Torvalds path = end; 11661da177e4SLinus Torvalds de = de->parent; 11671da177e4SLinus Torvalds } 11681da177e4SLinus Torvalds rc = security_genfs_sid("proc", path, tclass, sid); 11691da177e4SLinus Torvalds free_page((unsigned long)buffer); 11701da177e4SLinus Torvalds return rc; 11711da177e4SLinus Torvalds } 11721da177e4SLinus Torvalds #else 11731da177e4SLinus Torvalds static int selinux_proc_get_sid(struct proc_dir_entry *de, 11741da177e4SLinus Torvalds u16 tclass, 11751da177e4SLinus Torvalds u32 *sid) 11761da177e4SLinus Torvalds { 11771da177e4SLinus Torvalds return -EINVAL; 11781da177e4SLinus Torvalds } 11791da177e4SLinus Torvalds #endif 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds /* The inode's security attributes must be initialized before first use. */ 11821da177e4SLinus Torvalds static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) 11831da177e4SLinus Torvalds { 11841da177e4SLinus Torvalds struct superblock_security_struct *sbsec = NULL; 11851da177e4SLinus Torvalds struct inode_security_struct *isec = inode->i_security; 11861da177e4SLinus Torvalds u32 sid; 11871da177e4SLinus Torvalds struct dentry *dentry; 11881da177e4SLinus Torvalds #define INITCONTEXTLEN 255 11891da177e4SLinus Torvalds char *context = NULL; 11901da177e4SLinus Torvalds unsigned len = 0; 11911da177e4SLinus Torvalds int rc = 0; 11921da177e4SLinus Torvalds 11931da177e4SLinus Torvalds if (isec->initialized) 11941da177e4SLinus Torvalds goto out; 11951da177e4SLinus Torvalds 119623970741SEric Paris mutex_lock(&isec->lock); 11971da177e4SLinus Torvalds if (isec->initialized) 119823970741SEric Paris goto out_unlock; 11991da177e4SLinus Torvalds 12001da177e4SLinus Torvalds sbsec = inode->i_sb->s_security; 12011da177e4SLinus Torvalds if (!sbsec->initialized) { 12021da177e4SLinus Torvalds /* Defer initialization until selinux_complete_init, 12031da177e4SLinus Torvalds after the initial policy is loaded and the security 12041da177e4SLinus Torvalds server is ready to handle calls. */ 12051da177e4SLinus Torvalds spin_lock(&sbsec->isec_lock); 12061da177e4SLinus Torvalds if (list_empty(&isec->list)) 12071da177e4SLinus Torvalds list_add(&isec->list, &sbsec->isec_head); 12081da177e4SLinus Torvalds spin_unlock(&sbsec->isec_lock); 120923970741SEric Paris goto out_unlock; 12101da177e4SLinus Torvalds } 12111da177e4SLinus Torvalds 12121da177e4SLinus Torvalds switch (sbsec->behavior) { 12131da177e4SLinus Torvalds case SECURITY_FS_USE_XATTR: 12141da177e4SLinus Torvalds if (!inode->i_op->getxattr) { 12151da177e4SLinus Torvalds isec->sid = sbsec->def_sid; 12161da177e4SLinus Torvalds break; 12171da177e4SLinus Torvalds } 12181da177e4SLinus Torvalds 12191da177e4SLinus Torvalds /* Need a dentry, since the xattr API requires one. 12201da177e4SLinus Torvalds Life would be simpler if we could just pass the inode. */ 12211da177e4SLinus Torvalds if (opt_dentry) { 12221da177e4SLinus Torvalds /* Called from d_instantiate or d_splice_alias. */ 12231da177e4SLinus Torvalds dentry = dget(opt_dentry); 12241da177e4SLinus Torvalds } else { 12251da177e4SLinus Torvalds /* Called from selinux_complete_init, try to find a dentry. */ 12261da177e4SLinus Torvalds dentry = d_find_alias(inode); 12271da177e4SLinus Torvalds } 12281da177e4SLinus Torvalds if (!dentry) { 1229744ba35eSEric Paris printk(KERN_WARNING "SELinux: %s: no dentry for dev=%s " 1230dd6f953aSHarvey Harrison "ino=%ld\n", __func__, inode->i_sb->s_id, 12311da177e4SLinus Torvalds inode->i_ino); 123223970741SEric Paris goto out_unlock; 12331da177e4SLinus Torvalds } 12341da177e4SLinus Torvalds 12351da177e4SLinus Torvalds len = INITCONTEXTLEN; 1236869ab514SStephen Smalley context = kmalloc(len, GFP_NOFS); 12371da177e4SLinus Torvalds if (!context) { 12381da177e4SLinus Torvalds rc = -ENOMEM; 12391da177e4SLinus Torvalds dput(dentry); 124023970741SEric Paris goto out_unlock; 12411da177e4SLinus Torvalds } 12421da177e4SLinus Torvalds rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, 12431da177e4SLinus Torvalds context, len); 12441da177e4SLinus Torvalds if (rc == -ERANGE) { 12451da177e4SLinus Torvalds /* Need a larger buffer. Query for the right size. */ 12461da177e4SLinus Torvalds rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX, 12471da177e4SLinus Torvalds NULL, 0); 12481da177e4SLinus Torvalds if (rc < 0) { 12491da177e4SLinus Torvalds dput(dentry); 125023970741SEric Paris goto out_unlock; 12511da177e4SLinus Torvalds } 12521da177e4SLinus Torvalds kfree(context); 12531da177e4SLinus Torvalds len = rc; 1254869ab514SStephen Smalley context = kmalloc(len, GFP_NOFS); 12551da177e4SLinus Torvalds if (!context) { 12561da177e4SLinus Torvalds rc = -ENOMEM; 12571da177e4SLinus Torvalds dput(dentry); 125823970741SEric Paris goto out_unlock; 12591da177e4SLinus Torvalds } 12601da177e4SLinus Torvalds rc = inode->i_op->getxattr(dentry, 12611da177e4SLinus Torvalds XATTR_NAME_SELINUX, 12621da177e4SLinus Torvalds context, len); 12631da177e4SLinus Torvalds } 12641da177e4SLinus Torvalds dput(dentry); 12651da177e4SLinus Torvalds if (rc < 0) { 12661da177e4SLinus Torvalds if (rc != -ENODATA) { 1267744ba35eSEric Paris printk(KERN_WARNING "SELinux: %s: getxattr returned " 1268dd6f953aSHarvey Harrison "%d for dev=%s ino=%ld\n", __func__, 12691da177e4SLinus Torvalds -rc, inode->i_sb->s_id, inode->i_ino); 12701da177e4SLinus Torvalds kfree(context); 127123970741SEric Paris goto out_unlock; 12721da177e4SLinus Torvalds } 12731da177e4SLinus Torvalds /* Map ENODATA to the default file SID */ 12741da177e4SLinus Torvalds sid = sbsec->def_sid; 12751da177e4SLinus Torvalds rc = 0; 12761da177e4SLinus Torvalds } else { 1277f5c1d5b2SJames Morris rc = security_context_to_sid_default(context, rc, &sid, 1278869ab514SStephen Smalley sbsec->def_sid, 1279869ab514SStephen Smalley GFP_NOFS); 12801da177e4SLinus Torvalds if (rc) { 1281744ba35eSEric Paris printk(KERN_WARNING "SELinux: %s: context_to_sid(%s) " 12821da177e4SLinus Torvalds "returned %d for dev=%s ino=%ld\n", 1283dd6f953aSHarvey Harrison __func__, context, -rc, 12841da177e4SLinus Torvalds inode->i_sb->s_id, inode->i_ino); 12851da177e4SLinus Torvalds kfree(context); 12861da177e4SLinus Torvalds /* Leave with the unlabeled SID */ 12871da177e4SLinus Torvalds rc = 0; 12881da177e4SLinus Torvalds break; 12891da177e4SLinus Torvalds } 12901da177e4SLinus Torvalds } 12911da177e4SLinus Torvalds kfree(context); 12921da177e4SLinus Torvalds isec->sid = sid; 12931da177e4SLinus Torvalds break; 12941da177e4SLinus Torvalds case SECURITY_FS_USE_TASK: 12951da177e4SLinus Torvalds isec->sid = isec->task_sid; 12961da177e4SLinus Torvalds break; 12971da177e4SLinus Torvalds case SECURITY_FS_USE_TRANS: 12981da177e4SLinus Torvalds /* Default to the fs SID. */ 12991da177e4SLinus Torvalds isec->sid = sbsec->sid; 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds /* Try to obtain a transition SID. */ 13021da177e4SLinus Torvalds isec->sclass = inode_mode_to_security_class(inode->i_mode); 13031da177e4SLinus Torvalds rc = security_transition_sid(isec->task_sid, 13041da177e4SLinus Torvalds sbsec->sid, 13051da177e4SLinus Torvalds isec->sclass, 13061da177e4SLinus Torvalds &sid); 13071da177e4SLinus Torvalds if (rc) 130823970741SEric Paris goto out_unlock; 13091da177e4SLinus Torvalds isec->sid = sid; 13101da177e4SLinus Torvalds break; 1311c312feb2SEric Paris case SECURITY_FS_USE_MNTPOINT: 1312c312feb2SEric Paris isec->sid = sbsec->mntpoint_sid; 1313c312feb2SEric Paris break; 13141da177e4SLinus Torvalds default: 1315c312feb2SEric Paris /* Default to the fs superblock SID. */ 13161da177e4SLinus Torvalds isec->sid = sbsec->sid; 13171da177e4SLinus Torvalds 1318ea6b184fSStephen Smalley if (sbsec->proc && !S_ISLNK(inode->i_mode)) { 13191da177e4SLinus Torvalds struct proc_inode *proci = PROC_I(inode); 13201da177e4SLinus Torvalds if (proci->pde) { 13211da177e4SLinus Torvalds isec->sclass = inode_mode_to_security_class(inode->i_mode); 13221da177e4SLinus Torvalds rc = selinux_proc_get_sid(proci->pde, 13231da177e4SLinus Torvalds isec->sclass, 13241da177e4SLinus Torvalds &sid); 13251da177e4SLinus Torvalds if (rc) 132623970741SEric Paris goto out_unlock; 13271da177e4SLinus Torvalds isec->sid = sid; 13281da177e4SLinus Torvalds } 13291da177e4SLinus Torvalds } 13301da177e4SLinus Torvalds break; 13311da177e4SLinus Torvalds } 13321da177e4SLinus Torvalds 13331da177e4SLinus Torvalds isec->initialized = 1; 13341da177e4SLinus Torvalds 133523970741SEric Paris out_unlock: 133623970741SEric Paris mutex_unlock(&isec->lock); 13371da177e4SLinus Torvalds out: 13381da177e4SLinus Torvalds if (isec->sclass == SECCLASS_FILE) 13391da177e4SLinus Torvalds isec->sclass = inode_mode_to_security_class(inode->i_mode); 13401da177e4SLinus Torvalds return rc; 13411da177e4SLinus Torvalds } 13421da177e4SLinus Torvalds 13431da177e4SLinus Torvalds /* Convert a Linux signal to an access vector. */ 13441da177e4SLinus Torvalds static inline u32 signal_to_av(int sig) 13451da177e4SLinus Torvalds { 13461da177e4SLinus Torvalds u32 perm = 0; 13471da177e4SLinus Torvalds 13481da177e4SLinus Torvalds switch (sig) { 13491da177e4SLinus Torvalds case SIGCHLD: 13501da177e4SLinus Torvalds /* Commonly granted from child to parent. */ 13511da177e4SLinus Torvalds perm = PROCESS__SIGCHLD; 13521da177e4SLinus Torvalds break; 13531da177e4SLinus Torvalds case SIGKILL: 13541da177e4SLinus Torvalds /* Cannot be caught or ignored */ 13551da177e4SLinus Torvalds perm = PROCESS__SIGKILL; 13561da177e4SLinus Torvalds break; 13571da177e4SLinus Torvalds case SIGSTOP: 13581da177e4SLinus Torvalds /* Cannot be caught or ignored */ 13591da177e4SLinus Torvalds perm = PROCESS__SIGSTOP; 13601da177e4SLinus Torvalds break; 13611da177e4SLinus Torvalds default: 13621da177e4SLinus Torvalds /* All other signals. */ 13631da177e4SLinus Torvalds perm = PROCESS__SIGNAL; 13641da177e4SLinus Torvalds break; 13651da177e4SLinus Torvalds } 13661da177e4SLinus Torvalds 13671da177e4SLinus Torvalds return perm; 13681da177e4SLinus Torvalds } 13691da177e4SLinus Torvalds 1370*275bb41eSDavid Howells /* 1371*275bb41eSDavid Howells * Check permission betweeen a pair of tasks, e.g. signal checks, 1372*275bb41eSDavid Howells * fork check, ptrace check, etc. 1373*275bb41eSDavid Howells * tsk1 is the actor and tsk2 is the target 1374*275bb41eSDavid Howells */ 1375*275bb41eSDavid Howells static int task_has_perm(const struct task_struct *tsk1, 1376*275bb41eSDavid Howells const struct task_struct *tsk2, 13771da177e4SLinus Torvalds u32 perms) 13781da177e4SLinus Torvalds { 1379*275bb41eSDavid Howells const struct task_security_struct *__tsec1, *__tsec2; 1380*275bb41eSDavid Howells u32 sid1, sid2; 13811da177e4SLinus Torvalds 1382*275bb41eSDavid Howells rcu_read_lock(); 1383*275bb41eSDavid Howells __tsec1 = __task_cred(tsk1)->security; sid1 = __tsec1->sid; 1384*275bb41eSDavid Howells __tsec2 = __task_cred(tsk2)->security; sid2 = __tsec2->sid; 1385*275bb41eSDavid Howells rcu_read_unlock(); 1386*275bb41eSDavid Howells return avc_has_perm(sid1, sid2, SECCLASS_PROCESS, perms, NULL); 13871da177e4SLinus Torvalds } 13881da177e4SLinus Torvalds 1389b68e418cSStephen Smalley #if CAP_LAST_CAP > 63 1390b68e418cSStephen Smalley #error Fix SELinux to handle capabilities > 63. 1391b68e418cSStephen Smalley #endif 1392b68e418cSStephen Smalley 13931da177e4SLinus Torvalds /* Check whether a task is allowed to use a capability. */ 13941da177e4SLinus Torvalds static int task_has_capability(struct task_struct *tsk, 139506112163SEric Paris int cap, int audit) 13961da177e4SLinus Torvalds { 13971da177e4SLinus Torvalds struct avc_audit_data ad; 139806112163SEric Paris struct av_decision avd; 1399b68e418cSStephen Smalley u16 sclass; 1400*275bb41eSDavid Howells u32 sid = task_sid(tsk); 1401b68e418cSStephen Smalley u32 av = CAP_TO_MASK(cap); 140206112163SEric Paris int rc; 14031da177e4SLinus Torvalds 14041da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, CAP); 14051da177e4SLinus Torvalds ad.tsk = tsk; 14061da177e4SLinus Torvalds ad.u.cap = cap; 14071da177e4SLinus Torvalds 1408b68e418cSStephen Smalley switch (CAP_TO_INDEX(cap)) { 1409b68e418cSStephen Smalley case 0: 1410b68e418cSStephen Smalley sclass = SECCLASS_CAPABILITY; 1411b68e418cSStephen Smalley break; 1412b68e418cSStephen Smalley case 1: 1413b68e418cSStephen Smalley sclass = SECCLASS_CAPABILITY2; 1414b68e418cSStephen Smalley break; 1415b68e418cSStephen Smalley default: 1416b68e418cSStephen Smalley printk(KERN_ERR 1417b68e418cSStephen Smalley "SELinux: out of range capability %d\n", cap); 1418b68e418cSStephen Smalley BUG(); 1419b68e418cSStephen Smalley } 142006112163SEric Paris 1421*275bb41eSDavid Howells rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd); 142206112163SEric Paris if (audit == SECURITY_CAP_AUDIT) 1423*275bb41eSDavid Howells avc_audit(sid, sid, sclass, av, &avd, rc, &ad); 142406112163SEric Paris return rc; 14251da177e4SLinus Torvalds } 14261da177e4SLinus Torvalds 14271da177e4SLinus Torvalds /* Check whether a task is allowed to use a system operation. */ 14281da177e4SLinus Torvalds static int task_has_system(struct task_struct *tsk, 14291da177e4SLinus Torvalds u32 perms) 14301da177e4SLinus Torvalds { 1431*275bb41eSDavid Howells u32 sid = task_sid(tsk); 14321da177e4SLinus Torvalds 1433*275bb41eSDavid Howells return avc_has_perm(sid, SECINITSID_KERNEL, 14341da177e4SLinus Torvalds SECCLASS_SYSTEM, perms, NULL); 14351da177e4SLinus Torvalds } 14361da177e4SLinus Torvalds 14371da177e4SLinus Torvalds /* Check whether a task has a particular permission to an inode. 14381da177e4SLinus Torvalds The 'adp' parameter is optional and allows other audit 14391da177e4SLinus Torvalds data to be passed (e.g. the dentry). */ 14401da177e4SLinus Torvalds static int inode_has_perm(struct task_struct *tsk, 14411da177e4SLinus Torvalds struct inode *inode, 14421da177e4SLinus Torvalds u32 perms, 14431da177e4SLinus Torvalds struct avc_audit_data *adp) 14441da177e4SLinus Torvalds { 14451da177e4SLinus Torvalds struct inode_security_struct *isec; 14461da177e4SLinus Torvalds struct avc_audit_data ad; 1447*275bb41eSDavid Howells u32 sid; 14481da177e4SLinus Torvalds 1449bbaca6c2SStephen Smalley if (unlikely(IS_PRIVATE(inode))) 1450bbaca6c2SStephen Smalley return 0; 1451bbaca6c2SStephen Smalley 1452*275bb41eSDavid Howells sid = task_sid(tsk); 14531da177e4SLinus Torvalds isec = inode->i_security; 14541da177e4SLinus Torvalds 14551da177e4SLinus Torvalds if (!adp) { 14561da177e4SLinus Torvalds adp = &ad; 14571da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 14581da177e4SLinus Torvalds ad.u.fs.inode = inode; 14591da177e4SLinus Torvalds } 14601da177e4SLinus Torvalds 1461*275bb41eSDavid Howells return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp); 14621da177e4SLinus Torvalds } 14631da177e4SLinus Torvalds 14641da177e4SLinus Torvalds /* Same as inode_has_perm, but pass explicit audit data containing 14651da177e4SLinus Torvalds the dentry to help the auditing code to more easily generate the 14661da177e4SLinus Torvalds pathname if needed. */ 14671da177e4SLinus Torvalds static inline int dentry_has_perm(struct task_struct *tsk, 14681da177e4SLinus Torvalds struct vfsmount *mnt, 14691da177e4SLinus Torvalds struct dentry *dentry, 14701da177e4SLinus Torvalds u32 av) 14711da177e4SLinus Torvalds { 14721da177e4SLinus Torvalds struct inode *inode = dentry->d_inode; 14731da177e4SLinus Torvalds struct avc_audit_data ad; 14741da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 147544707fdfSJan Blunck ad.u.fs.path.mnt = mnt; 147644707fdfSJan Blunck ad.u.fs.path.dentry = dentry; 14771da177e4SLinus Torvalds return inode_has_perm(tsk, inode, av, &ad); 14781da177e4SLinus Torvalds } 14791da177e4SLinus Torvalds 14801da177e4SLinus Torvalds /* Check whether a task can use an open file descriptor to 14811da177e4SLinus Torvalds access an inode in a given way. Check access to the 14821da177e4SLinus Torvalds descriptor itself, and then use dentry_has_perm to 14831da177e4SLinus Torvalds check a particular permission to the file. 14841da177e4SLinus Torvalds Access to the descriptor is implicitly granted if it 14851da177e4SLinus Torvalds has the same SID as the process. If av is zero, then 14861da177e4SLinus Torvalds access to the file is not checked, e.g. for cases 14871da177e4SLinus Torvalds where only the descriptor is affected like seek. */ 1488858119e1SArjan van de Ven static int file_has_perm(struct task_struct *tsk, 14891da177e4SLinus Torvalds struct file *file, 14901da177e4SLinus Torvalds u32 av) 14911da177e4SLinus Torvalds { 14921da177e4SLinus Torvalds struct file_security_struct *fsec = file->f_security; 149344707fdfSJan Blunck struct inode *inode = file->f_path.dentry->d_inode; 14941da177e4SLinus Torvalds struct avc_audit_data ad; 1495*275bb41eSDavid Howells u32 sid = task_sid(tsk); 14961da177e4SLinus Torvalds int rc; 14971da177e4SLinus Torvalds 14981da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 149944707fdfSJan Blunck ad.u.fs.path = file->f_path; 15001da177e4SLinus Torvalds 1501*275bb41eSDavid Howells if (sid != fsec->sid) { 1502*275bb41eSDavid Howells rc = avc_has_perm(sid, fsec->sid, 15031da177e4SLinus Torvalds SECCLASS_FD, 15041da177e4SLinus Torvalds FD__USE, 15051da177e4SLinus Torvalds &ad); 15061da177e4SLinus Torvalds if (rc) 15071da177e4SLinus Torvalds return rc; 15081da177e4SLinus Torvalds } 15091da177e4SLinus Torvalds 15101da177e4SLinus Torvalds /* av is zero if only checking access to the descriptor. */ 15111da177e4SLinus Torvalds if (av) 15121da177e4SLinus Torvalds return inode_has_perm(tsk, inode, av, &ad); 15131da177e4SLinus Torvalds 15141da177e4SLinus Torvalds return 0; 15151da177e4SLinus Torvalds } 15161da177e4SLinus Torvalds 15171da177e4SLinus Torvalds /* Check whether a task can create a file. */ 15181da177e4SLinus Torvalds static int may_create(struct inode *dir, 15191da177e4SLinus Torvalds struct dentry *dentry, 15201da177e4SLinus Torvalds u16 tclass) 15211da177e4SLinus Torvalds { 1522*275bb41eSDavid Howells const struct cred *cred = current_cred(); 1523*275bb41eSDavid Howells const struct task_security_struct *tsec = cred->security; 15241da177e4SLinus Torvalds struct inode_security_struct *dsec; 15251da177e4SLinus Torvalds struct superblock_security_struct *sbsec; 1526*275bb41eSDavid Howells u32 sid, newsid; 15271da177e4SLinus Torvalds struct avc_audit_data ad; 15281da177e4SLinus Torvalds int rc; 15291da177e4SLinus Torvalds 15301da177e4SLinus Torvalds dsec = dir->i_security; 15311da177e4SLinus Torvalds sbsec = dir->i_sb->s_security; 15321da177e4SLinus Torvalds 1533*275bb41eSDavid Howells sid = tsec->sid; 1534*275bb41eSDavid Howells newsid = tsec->create_sid; 1535*275bb41eSDavid Howells 15361da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 153744707fdfSJan Blunck ad.u.fs.path.dentry = dentry; 15381da177e4SLinus Torvalds 1539*275bb41eSDavid Howells rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, 15401da177e4SLinus Torvalds DIR__ADD_NAME | DIR__SEARCH, 15411da177e4SLinus Torvalds &ad); 15421da177e4SLinus Torvalds if (rc) 15431da177e4SLinus Torvalds return rc; 15441da177e4SLinus Torvalds 1545*275bb41eSDavid Howells if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) { 1546*275bb41eSDavid Howells rc = security_transition_sid(sid, dsec->sid, tclass, &newsid); 15471da177e4SLinus Torvalds if (rc) 15481da177e4SLinus Torvalds return rc; 15491da177e4SLinus Torvalds } 15501da177e4SLinus Torvalds 1551*275bb41eSDavid Howells rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); 15521da177e4SLinus Torvalds if (rc) 15531da177e4SLinus Torvalds return rc; 15541da177e4SLinus Torvalds 15551da177e4SLinus Torvalds return avc_has_perm(newsid, sbsec->sid, 15561da177e4SLinus Torvalds SECCLASS_FILESYSTEM, 15571da177e4SLinus Torvalds FILESYSTEM__ASSOCIATE, &ad); 15581da177e4SLinus Torvalds } 15591da177e4SLinus Torvalds 15604eb582cfSMichael LeMay /* Check whether a task can create a key. */ 15614eb582cfSMichael LeMay static int may_create_key(u32 ksid, 15624eb582cfSMichael LeMay struct task_struct *ctx) 15634eb582cfSMichael LeMay { 1564*275bb41eSDavid Howells u32 sid = task_sid(ctx); 15654eb582cfSMichael LeMay 1566*275bb41eSDavid Howells return avc_has_perm(sid, ksid, SECCLASS_KEY, KEY__CREATE, NULL); 15674eb582cfSMichael LeMay } 15684eb582cfSMichael LeMay 15691da177e4SLinus Torvalds #define MAY_LINK 0 15701da177e4SLinus Torvalds #define MAY_UNLINK 1 15711da177e4SLinus Torvalds #define MAY_RMDIR 2 15721da177e4SLinus Torvalds 15731da177e4SLinus Torvalds /* Check whether a task can link, unlink, or rmdir a file/directory. */ 15741da177e4SLinus Torvalds static int may_link(struct inode *dir, 15751da177e4SLinus Torvalds struct dentry *dentry, 15761da177e4SLinus Torvalds int kind) 15771da177e4SLinus Torvalds 15781da177e4SLinus Torvalds { 15791da177e4SLinus Torvalds struct inode_security_struct *dsec, *isec; 15801da177e4SLinus Torvalds struct avc_audit_data ad; 1581*275bb41eSDavid Howells u32 sid = current_sid(); 15821da177e4SLinus Torvalds u32 av; 15831da177e4SLinus Torvalds int rc; 15841da177e4SLinus Torvalds 15851da177e4SLinus Torvalds dsec = dir->i_security; 15861da177e4SLinus Torvalds isec = dentry->d_inode->i_security; 15871da177e4SLinus Torvalds 15881da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 158944707fdfSJan Blunck ad.u.fs.path.dentry = dentry; 15901da177e4SLinus Torvalds 15911da177e4SLinus Torvalds av = DIR__SEARCH; 15921da177e4SLinus Torvalds av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); 1593*275bb41eSDavid Howells rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad); 15941da177e4SLinus Torvalds if (rc) 15951da177e4SLinus Torvalds return rc; 15961da177e4SLinus Torvalds 15971da177e4SLinus Torvalds switch (kind) { 15981da177e4SLinus Torvalds case MAY_LINK: 15991da177e4SLinus Torvalds av = FILE__LINK; 16001da177e4SLinus Torvalds break; 16011da177e4SLinus Torvalds case MAY_UNLINK: 16021da177e4SLinus Torvalds av = FILE__UNLINK; 16031da177e4SLinus Torvalds break; 16041da177e4SLinus Torvalds case MAY_RMDIR: 16051da177e4SLinus Torvalds av = DIR__RMDIR; 16061da177e4SLinus Torvalds break; 16071da177e4SLinus Torvalds default: 1608744ba35eSEric Paris printk(KERN_WARNING "SELinux: %s: unrecognized kind %d\n", 1609744ba35eSEric Paris __func__, kind); 16101da177e4SLinus Torvalds return 0; 16111da177e4SLinus Torvalds } 16121da177e4SLinus Torvalds 1613*275bb41eSDavid Howells rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad); 16141da177e4SLinus Torvalds return rc; 16151da177e4SLinus Torvalds } 16161da177e4SLinus Torvalds 16171da177e4SLinus Torvalds static inline int may_rename(struct inode *old_dir, 16181da177e4SLinus Torvalds struct dentry *old_dentry, 16191da177e4SLinus Torvalds struct inode *new_dir, 16201da177e4SLinus Torvalds struct dentry *new_dentry) 16211da177e4SLinus Torvalds { 16221da177e4SLinus Torvalds struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; 16231da177e4SLinus Torvalds struct avc_audit_data ad; 1624*275bb41eSDavid Howells u32 sid = current_sid(); 16251da177e4SLinus Torvalds u32 av; 16261da177e4SLinus Torvalds int old_is_dir, new_is_dir; 16271da177e4SLinus Torvalds int rc; 16281da177e4SLinus Torvalds 16291da177e4SLinus Torvalds old_dsec = old_dir->i_security; 16301da177e4SLinus Torvalds old_isec = old_dentry->d_inode->i_security; 16311da177e4SLinus Torvalds old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); 16321da177e4SLinus Torvalds new_dsec = new_dir->i_security; 16331da177e4SLinus Torvalds 16341da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 16351da177e4SLinus Torvalds 163644707fdfSJan Blunck ad.u.fs.path.dentry = old_dentry; 1637*275bb41eSDavid Howells rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, 16381da177e4SLinus Torvalds DIR__REMOVE_NAME | DIR__SEARCH, &ad); 16391da177e4SLinus Torvalds if (rc) 16401da177e4SLinus Torvalds return rc; 1641*275bb41eSDavid Howells rc = avc_has_perm(sid, old_isec->sid, 16421da177e4SLinus Torvalds old_isec->sclass, FILE__RENAME, &ad); 16431da177e4SLinus Torvalds if (rc) 16441da177e4SLinus Torvalds return rc; 16451da177e4SLinus Torvalds if (old_is_dir && new_dir != old_dir) { 1646*275bb41eSDavid Howells rc = avc_has_perm(sid, old_isec->sid, 16471da177e4SLinus Torvalds old_isec->sclass, DIR__REPARENT, &ad); 16481da177e4SLinus Torvalds if (rc) 16491da177e4SLinus Torvalds return rc; 16501da177e4SLinus Torvalds } 16511da177e4SLinus Torvalds 165244707fdfSJan Blunck ad.u.fs.path.dentry = new_dentry; 16531da177e4SLinus Torvalds av = DIR__ADD_NAME | DIR__SEARCH; 16541da177e4SLinus Torvalds if (new_dentry->d_inode) 16551da177e4SLinus Torvalds av |= DIR__REMOVE_NAME; 1656*275bb41eSDavid Howells rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad); 16571da177e4SLinus Torvalds if (rc) 16581da177e4SLinus Torvalds return rc; 16591da177e4SLinus Torvalds if (new_dentry->d_inode) { 16601da177e4SLinus Torvalds new_isec = new_dentry->d_inode->i_security; 16611da177e4SLinus Torvalds new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode); 1662*275bb41eSDavid Howells rc = avc_has_perm(sid, new_isec->sid, 16631da177e4SLinus Torvalds new_isec->sclass, 16641da177e4SLinus Torvalds (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); 16651da177e4SLinus Torvalds if (rc) 16661da177e4SLinus Torvalds return rc; 16671da177e4SLinus Torvalds } 16681da177e4SLinus Torvalds 16691da177e4SLinus Torvalds return 0; 16701da177e4SLinus Torvalds } 16711da177e4SLinus Torvalds 16721da177e4SLinus Torvalds /* Check whether a task can perform a filesystem operation. */ 16731da177e4SLinus Torvalds static int superblock_has_perm(struct task_struct *tsk, 16741da177e4SLinus Torvalds struct super_block *sb, 16751da177e4SLinus Torvalds u32 perms, 16761da177e4SLinus Torvalds struct avc_audit_data *ad) 16771da177e4SLinus Torvalds { 16781da177e4SLinus Torvalds struct superblock_security_struct *sbsec; 1679*275bb41eSDavid Howells u32 sid = task_sid(tsk); 16801da177e4SLinus Torvalds 16811da177e4SLinus Torvalds sbsec = sb->s_security; 1682*275bb41eSDavid Howells return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad); 16831da177e4SLinus Torvalds } 16841da177e4SLinus Torvalds 16851da177e4SLinus Torvalds /* Convert a Linux mode and permission mask to an access vector. */ 16861da177e4SLinus Torvalds static inline u32 file_mask_to_av(int mode, int mask) 16871da177e4SLinus Torvalds { 16881da177e4SLinus Torvalds u32 av = 0; 16891da177e4SLinus Torvalds 16901da177e4SLinus Torvalds if ((mode & S_IFMT) != S_IFDIR) { 16911da177e4SLinus Torvalds if (mask & MAY_EXEC) 16921da177e4SLinus Torvalds av |= FILE__EXECUTE; 16931da177e4SLinus Torvalds if (mask & MAY_READ) 16941da177e4SLinus Torvalds av |= FILE__READ; 16951da177e4SLinus Torvalds 16961da177e4SLinus Torvalds if (mask & MAY_APPEND) 16971da177e4SLinus Torvalds av |= FILE__APPEND; 16981da177e4SLinus Torvalds else if (mask & MAY_WRITE) 16991da177e4SLinus Torvalds av |= FILE__WRITE; 17001da177e4SLinus Torvalds 17011da177e4SLinus Torvalds } else { 17021da177e4SLinus Torvalds if (mask & MAY_EXEC) 17031da177e4SLinus Torvalds av |= DIR__SEARCH; 17041da177e4SLinus Torvalds if (mask & MAY_WRITE) 17051da177e4SLinus Torvalds av |= DIR__WRITE; 17061da177e4SLinus Torvalds if (mask & MAY_READ) 17071da177e4SLinus Torvalds av |= DIR__READ; 17081da177e4SLinus Torvalds } 17091da177e4SLinus Torvalds 17101da177e4SLinus Torvalds return av; 17111da177e4SLinus Torvalds } 17121da177e4SLinus Torvalds 17131da177e4SLinus Torvalds /* Convert a Linux file to an access vector. */ 17141da177e4SLinus Torvalds static inline u32 file_to_av(struct file *file) 17151da177e4SLinus Torvalds { 17161da177e4SLinus Torvalds u32 av = 0; 17171da177e4SLinus Torvalds 17181da177e4SLinus Torvalds if (file->f_mode & FMODE_READ) 17191da177e4SLinus Torvalds av |= FILE__READ; 17201da177e4SLinus Torvalds if (file->f_mode & FMODE_WRITE) { 17211da177e4SLinus Torvalds if (file->f_flags & O_APPEND) 17221da177e4SLinus Torvalds av |= FILE__APPEND; 17231da177e4SLinus Torvalds else 17241da177e4SLinus Torvalds av |= FILE__WRITE; 17251da177e4SLinus Torvalds } 17260794c66dSStephen Smalley if (!av) { 17270794c66dSStephen Smalley /* 17280794c66dSStephen Smalley * Special file opened with flags 3 for ioctl-only use. 17290794c66dSStephen Smalley */ 17300794c66dSStephen Smalley av = FILE__IOCTL; 17310794c66dSStephen Smalley } 17321da177e4SLinus Torvalds 17331da177e4SLinus Torvalds return av; 17341da177e4SLinus Torvalds } 17351da177e4SLinus Torvalds 17368b6a5a37SEric Paris /* 17378b6a5a37SEric Paris * Convert a file to an access vector and include the correct open 17388b6a5a37SEric Paris * open permission. 17398b6a5a37SEric Paris */ 17408b6a5a37SEric Paris static inline u32 open_file_to_av(struct file *file) 17418b6a5a37SEric Paris { 17428b6a5a37SEric Paris u32 av = file_to_av(file); 17438b6a5a37SEric Paris 17448b6a5a37SEric Paris if (selinux_policycap_openperm) { 17458b6a5a37SEric Paris mode_t mode = file->f_path.dentry->d_inode->i_mode; 17468b6a5a37SEric Paris /* 17478b6a5a37SEric Paris * lnk files and socks do not really have an 'open' 17488b6a5a37SEric Paris */ 17498b6a5a37SEric Paris if (S_ISREG(mode)) 17508b6a5a37SEric Paris av |= FILE__OPEN; 17518b6a5a37SEric Paris else if (S_ISCHR(mode)) 17528b6a5a37SEric Paris av |= CHR_FILE__OPEN; 17538b6a5a37SEric Paris else if (S_ISBLK(mode)) 17548b6a5a37SEric Paris av |= BLK_FILE__OPEN; 17558b6a5a37SEric Paris else if (S_ISFIFO(mode)) 17568b6a5a37SEric Paris av |= FIFO_FILE__OPEN; 17578b6a5a37SEric Paris else if (S_ISDIR(mode)) 17588b6a5a37SEric Paris av |= DIR__OPEN; 17598b6a5a37SEric Paris else 17608b6a5a37SEric Paris printk(KERN_ERR "SELinux: WARNING: inside %s with " 17618b6a5a37SEric Paris "unknown mode:%o\n", __func__, mode); 17628b6a5a37SEric Paris } 17638b6a5a37SEric Paris return av; 17648b6a5a37SEric Paris } 17658b6a5a37SEric Paris 17661da177e4SLinus Torvalds /* Hook functions begin here. */ 17671da177e4SLinus Torvalds 17685cd9c58fSDavid Howells static int selinux_ptrace_may_access(struct task_struct *child, 1769006ebb40SStephen Smalley unsigned int mode) 17701da177e4SLinus Torvalds { 17711da177e4SLinus Torvalds int rc; 17721da177e4SLinus Torvalds 17735cd9c58fSDavid Howells rc = secondary_ops->ptrace_may_access(child, mode); 17741da177e4SLinus Torvalds if (rc) 17751da177e4SLinus Torvalds return rc; 17761da177e4SLinus Torvalds 1777006ebb40SStephen Smalley if (mode == PTRACE_MODE_READ) { 1778*275bb41eSDavid Howells u32 sid = current_sid(); 1779*275bb41eSDavid Howells u32 csid = task_sid(child); 1780*275bb41eSDavid Howells return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ, NULL); 1781006ebb40SStephen Smalley } 1782006ebb40SStephen Smalley 17835cd9c58fSDavid Howells return task_has_perm(current, child, PROCESS__PTRACE); 17845cd9c58fSDavid Howells } 17855cd9c58fSDavid Howells 17865cd9c58fSDavid Howells static int selinux_ptrace_traceme(struct task_struct *parent) 17875cd9c58fSDavid Howells { 17885cd9c58fSDavid Howells int rc; 17895cd9c58fSDavid Howells 17905cd9c58fSDavid Howells rc = secondary_ops->ptrace_traceme(parent); 17915cd9c58fSDavid Howells if (rc) 17925cd9c58fSDavid Howells return rc; 17935cd9c58fSDavid Howells 17945cd9c58fSDavid Howells return task_has_perm(parent, current, PROCESS__PTRACE); 17951da177e4SLinus Torvalds } 17961da177e4SLinus Torvalds 17971da177e4SLinus Torvalds static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, 17981da177e4SLinus Torvalds kernel_cap_t *inheritable, kernel_cap_t *permitted) 17991da177e4SLinus Torvalds { 18001da177e4SLinus Torvalds int error; 18011da177e4SLinus Torvalds 18021da177e4SLinus Torvalds error = task_has_perm(current, target, PROCESS__GETCAP); 18031da177e4SLinus Torvalds if (error) 18041da177e4SLinus Torvalds return error; 18051da177e4SLinus Torvalds 18061da177e4SLinus Torvalds return secondary_ops->capget(target, effective, inheritable, permitted); 18071da177e4SLinus Torvalds } 18081da177e4SLinus Torvalds 180915a2460eSDavid Howells static int selinux_capset_check(const kernel_cap_t *effective, 181015a2460eSDavid Howells const kernel_cap_t *inheritable, 181115a2460eSDavid Howells const kernel_cap_t *permitted) 18121da177e4SLinus Torvalds { 18131da177e4SLinus Torvalds int error; 18141da177e4SLinus Torvalds 18151cdcbec1SDavid Howells error = secondary_ops->capset_check(effective, inheritable, permitted); 18161da177e4SLinus Torvalds if (error) 18171da177e4SLinus Torvalds return error; 18181da177e4SLinus Torvalds 18191cdcbec1SDavid Howells return task_has_perm(current, current, PROCESS__SETCAP); 18201da177e4SLinus Torvalds } 18211da177e4SLinus Torvalds 182215a2460eSDavid Howells static void selinux_capset_set(const kernel_cap_t *effective, 182315a2460eSDavid Howells const kernel_cap_t *inheritable, 182415a2460eSDavid Howells const kernel_cap_t *permitted) 18251da177e4SLinus Torvalds { 18261cdcbec1SDavid Howells secondary_ops->capset_set(effective, inheritable, permitted); 18271da177e4SLinus Torvalds } 18281da177e4SLinus Torvalds 182906112163SEric Paris static int selinux_capable(struct task_struct *tsk, int cap, int audit) 18301da177e4SLinus Torvalds { 18311da177e4SLinus Torvalds int rc; 18321da177e4SLinus Torvalds 183306112163SEric Paris rc = secondary_ops->capable(tsk, cap, audit); 18341da177e4SLinus Torvalds if (rc) 18351da177e4SLinus Torvalds return rc; 18361da177e4SLinus Torvalds 183706112163SEric Paris return task_has_capability(tsk, cap, audit); 18381da177e4SLinus Torvalds } 18391da177e4SLinus Torvalds 18403fbfa981SEric W. Biederman static int selinux_sysctl_get_sid(ctl_table *table, u16 tclass, u32 *sid) 18413fbfa981SEric W. Biederman { 18423fbfa981SEric W. Biederman int buflen, rc; 18433fbfa981SEric W. Biederman char *buffer, *path, *end; 18443fbfa981SEric W. Biederman 18453fbfa981SEric W. Biederman rc = -ENOMEM; 18463fbfa981SEric W. Biederman buffer = (char *)__get_free_page(GFP_KERNEL); 18473fbfa981SEric W. Biederman if (!buffer) 18483fbfa981SEric W. Biederman goto out; 18493fbfa981SEric W. Biederman 18503fbfa981SEric W. Biederman buflen = PAGE_SIZE; 18513fbfa981SEric W. Biederman end = buffer+buflen; 18523fbfa981SEric W. Biederman *--end = '\0'; 18533fbfa981SEric W. Biederman buflen--; 18543fbfa981SEric W. Biederman path = end-1; 18553fbfa981SEric W. Biederman *path = '/'; 18563fbfa981SEric W. Biederman while (table) { 18573fbfa981SEric W. Biederman const char *name = table->procname; 18583fbfa981SEric W. Biederman size_t namelen = strlen(name); 18593fbfa981SEric W. Biederman buflen -= namelen + 1; 18603fbfa981SEric W. Biederman if (buflen < 0) 18613fbfa981SEric W. Biederman goto out_free; 18623fbfa981SEric W. Biederman end -= namelen; 18633fbfa981SEric W. Biederman memcpy(end, name, namelen); 18643fbfa981SEric W. Biederman *--end = '/'; 18653fbfa981SEric W. Biederman path = end; 18663fbfa981SEric W. Biederman table = table->parent; 18673fbfa981SEric W. Biederman } 1868b599fdfdSEric W. Biederman buflen -= 4; 1869b599fdfdSEric W. Biederman if (buflen < 0) 1870b599fdfdSEric W. Biederman goto out_free; 1871b599fdfdSEric W. Biederman end -= 4; 1872b599fdfdSEric W. Biederman memcpy(end, "/sys", 4); 1873b599fdfdSEric W. Biederman path = end; 18743fbfa981SEric W. Biederman rc = security_genfs_sid("proc", path, tclass, sid); 18753fbfa981SEric W. Biederman out_free: 18763fbfa981SEric W. Biederman free_page((unsigned long)buffer); 18773fbfa981SEric W. Biederman out: 18783fbfa981SEric W. Biederman return rc; 18793fbfa981SEric W. Biederman } 18803fbfa981SEric W. Biederman 18811da177e4SLinus Torvalds static int selinux_sysctl(ctl_table *table, int op) 18821da177e4SLinus Torvalds { 18831da177e4SLinus Torvalds int error = 0; 18841da177e4SLinus Torvalds u32 av; 1885*275bb41eSDavid Howells u32 tsid, sid; 18861da177e4SLinus Torvalds int rc; 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds rc = secondary_ops->sysctl(table, op); 18891da177e4SLinus Torvalds if (rc) 18901da177e4SLinus Torvalds return rc; 18911da177e4SLinus Torvalds 1892*275bb41eSDavid Howells sid = current_sid(); 18931da177e4SLinus Torvalds 18943fbfa981SEric W. Biederman rc = selinux_sysctl_get_sid(table, (op == 0001) ? 18951da177e4SLinus Torvalds SECCLASS_DIR : SECCLASS_FILE, &tsid); 18961da177e4SLinus Torvalds if (rc) { 18971da177e4SLinus Torvalds /* Default to the well-defined sysctl SID. */ 18981da177e4SLinus Torvalds tsid = SECINITSID_SYSCTL; 18991da177e4SLinus Torvalds } 19001da177e4SLinus Torvalds 19011da177e4SLinus Torvalds /* The op values are "defined" in sysctl.c, thereby creating 19021da177e4SLinus Torvalds * a bad coupling between this module and sysctl.c */ 19031da177e4SLinus Torvalds if (op == 001) { 1904*275bb41eSDavid Howells error = avc_has_perm(sid, tsid, 19051da177e4SLinus Torvalds SECCLASS_DIR, DIR__SEARCH, NULL); 19061da177e4SLinus Torvalds } else { 19071da177e4SLinus Torvalds av = 0; 19081da177e4SLinus Torvalds if (op & 004) 19091da177e4SLinus Torvalds av |= FILE__READ; 19101da177e4SLinus Torvalds if (op & 002) 19111da177e4SLinus Torvalds av |= FILE__WRITE; 19121da177e4SLinus Torvalds if (av) 1913*275bb41eSDavid Howells error = avc_has_perm(sid, tsid, 19141da177e4SLinus Torvalds SECCLASS_FILE, av, NULL); 19151da177e4SLinus Torvalds } 19161da177e4SLinus Torvalds 19171da177e4SLinus Torvalds return error; 19181da177e4SLinus Torvalds } 19191da177e4SLinus Torvalds 19201da177e4SLinus Torvalds static int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) 19211da177e4SLinus Torvalds { 19221da177e4SLinus Torvalds int rc = 0; 19231da177e4SLinus Torvalds 19241da177e4SLinus Torvalds if (!sb) 19251da177e4SLinus Torvalds return 0; 19261da177e4SLinus Torvalds 19271da177e4SLinus Torvalds switch (cmds) { 19281da177e4SLinus Torvalds case Q_SYNC: 19291da177e4SLinus Torvalds case Q_QUOTAON: 19301da177e4SLinus Torvalds case Q_QUOTAOFF: 19311da177e4SLinus Torvalds case Q_SETINFO: 19321da177e4SLinus Torvalds case Q_SETQUOTA: 1933828dfe1dSEric Paris rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAMOD, 1934828dfe1dSEric Paris NULL); 19351da177e4SLinus Torvalds break; 19361da177e4SLinus Torvalds case Q_GETFMT: 19371da177e4SLinus Torvalds case Q_GETINFO: 19381da177e4SLinus Torvalds case Q_GETQUOTA: 1939828dfe1dSEric Paris rc = superblock_has_perm(current, sb, FILESYSTEM__QUOTAGET, 1940828dfe1dSEric Paris NULL); 19411da177e4SLinus Torvalds break; 19421da177e4SLinus Torvalds default: 19431da177e4SLinus Torvalds rc = 0; /* let the kernel handle invalid cmds */ 19441da177e4SLinus Torvalds break; 19451da177e4SLinus Torvalds } 19461da177e4SLinus Torvalds return rc; 19471da177e4SLinus Torvalds } 19481da177e4SLinus Torvalds 19491da177e4SLinus Torvalds static int selinux_quota_on(struct dentry *dentry) 19501da177e4SLinus Torvalds { 19511da177e4SLinus Torvalds return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON); 19521da177e4SLinus Torvalds } 19531da177e4SLinus Torvalds 19541da177e4SLinus Torvalds static int selinux_syslog(int type) 19551da177e4SLinus Torvalds { 19561da177e4SLinus Torvalds int rc; 19571da177e4SLinus Torvalds 19581da177e4SLinus Torvalds rc = secondary_ops->syslog(type); 19591da177e4SLinus Torvalds if (rc) 19601da177e4SLinus Torvalds return rc; 19611da177e4SLinus Torvalds 19621da177e4SLinus Torvalds switch (type) { 19631da177e4SLinus Torvalds case 3: /* Read last kernel messages */ 19641da177e4SLinus Torvalds case 10: /* Return size of the log buffer */ 19651da177e4SLinus Torvalds rc = task_has_system(current, SYSTEM__SYSLOG_READ); 19661da177e4SLinus Torvalds break; 19671da177e4SLinus Torvalds case 6: /* Disable logging to console */ 19681da177e4SLinus Torvalds case 7: /* Enable logging to console */ 19691da177e4SLinus Torvalds case 8: /* Set level of messages printed to console */ 19701da177e4SLinus Torvalds rc = task_has_system(current, SYSTEM__SYSLOG_CONSOLE); 19711da177e4SLinus Torvalds break; 19721da177e4SLinus Torvalds case 0: /* Close log */ 19731da177e4SLinus Torvalds case 1: /* Open log */ 19741da177e4SLinus Torvalds case 2: /* Read from log */ 19751da177e4SLinus Torvalds case 4: /* Read/clear last kernel messages */ 19761da177e4SLinus Torvalds case 5: /* Clear ring buffer */ 19771da177e4SLinus Torvalds default: 19781da177e4SLinus Torvalds rc = task_has_system(current, SYSTEM__SYSLOG_MOD); 19791da177e4SLinus Torvalds break; 19801da177e4SLinus Torvalds } 19811da177e4SLinus Torvalds return rc; 19821da177e4SLinus Torvalds } 19831da177e4SLinus Torvalds 19841da177e4SLinus Torvalds /* 19851da177e4SLinus Torvalds * Check that a process has enough memory to allocate a new virtual 19861da177e4SLinus Torvalds * mapping. 0 means there is enough memory for the allocation to 19871da177e4SLinus Torvalds * succeed and -ENOMEM implies there is not. 19881da177e4SLinus Torvalds * 19891da177e4SLinus Torvalds * Note that secondary_ops->capable and task_has_perm_noaudit return 0 19901da177e4SLinus Torvalds * if the capability is granted, but __vm_enough_memory requires 1 if 19911da177e4SLinus Torvalds * the capability is granted. 19921da177e4SLinus Torvalds * 19931da177e4SLinus Torvalds * Do not audit the selinux permission check, as this is applied to all 19941da177e4SLinus Torvalds * processes that allocate mappings. 19951da177e4SLinus Torvalds */ 199634b4e4aaSAlan Cox static int selinux_vm_enough_memory(struct mm_struct *mm, long pages) 19971da177e4SLinus Torvalds { 19981da177e4SLinus Torvalds int rc, cap_sys_admin = 0; 19991da177e4SLinus Torvalds 200006674679SEric Paris rc = selinux_capable(current, CAP_SYS_ADMIN, SECURITY_CAP_NOAUDIT); 20011da177e4SLinus Torvalds if (rc == 0) 20021da177e4SLinus Torvalds cap_sys_admin = 1; 20031da177e4SLinus Torvalds 200434b4e4aaSAlan Cox return __vm_enough_memory(mm, pages, cap_sys_admin); 20051da177e4SLinus Torvalds } 20061da177e4SLinus Torvalds 20071da177e4SLinus Torvalds /* binprm security operations */ 20081da177e4SLinus Torvalds 20091da177e4SLinus Torvalds static int selinux_bprm_alloc_security(struct linux_binprm *bprm) 20101da177e4SLinus Torvalds { 20111da177e4SLinus Torvalds struct bprm_security_struct *bsec; 20121da177e4SLinus Torvalds 201389d155efSJames Morris bsec = kzalloc(sizeof(struct bprm_security_struct), GFP_KERNEL); 20141da177e4SLinus Torvalds if (!bsec) 20151da177e4SLinus Torvalds return -ENOMEM; 20161da177e4SLinus Torvalds 20171da177e4SLinus Torvalds bsec->sid = SECINITSID_UNLABELED; 20181da177e4SLinus Torvalds bsec->set = 0; 20191da177e4SLinus Torvalds 20201da177e4SLinus Torvalds bprm->security = bsec; 20211da177e4SLinus Torvalds return 0; 20221da177e4SLinus Torvalds } 20231da177e4SLinus Torvalds 20241da177e4SLinus Torvalds static int selinux_bprm_set_security(struct linux_binprm *bprm) 20251da177e4SLinus Torvalds { 20261da177e4SLinus Torvalds struct task_security_struct *tsec; 20273d5ff529SJosef Sipek struct inode *inode = bprm->file->f_path.dentry->d_inode; 20281da177e4SLinus Torvalds struct inode_security_struct *isec; 20291da177e4SLinus Torvalds struct bprm_security_struct *bsec; 20301da177e4SLinus Torvalds u32 newsid; 20311da177e4SLinus Torvalds struct avc_audit_data ad; 20321da177e4SLinus Torvalds int rc; 20331da177e4SLinus Torvalds 20341da177e4SLinus Torvalds rc = secondary_ops->bprm_set_security(bprm); 20351da177e4SLinus Torvalds if (rc) 20361da177e4SLinus Torvalds return rc; 20371da177e4SLinus Torvalds 20381da177e4SLinus Torvalds bsec = bprm->security; 20391da177e4SLinus Torvalds 20401da177e4SLinus Torvalds if (bsec->set) 20411da177e4SLinus Torvalds return 0; 20421da177e4SLinus Torvalds 2043*275bb41eSDavid Howells tsec = current_security(); 20441da177e4SLinus Torvalds isec = inode->i_security; 20451da177e4SLinus Torvalds 20461da177e4SLinus Torvalds /* Default to the current task SID. */ 20471da177e4SLinus Torvalds bsec->sid = tsec->sid; 20481da177e4SLinus Torvalds 204928eba5bfSMichael LeMay /* Reset fs, key, and sock SIDs on execve. */ 20501da177e4SLinus Torvalds tsec->create_sid = 0; 205128eba5bfSMichael LeMay tsec->keycreate_sid = 0; 205242c3e03eSEric Paris tsec->sockcreate_sid = 0; 20531da177e4SLinus Torvalds 20541da177e4SLinus Torvalds if (tsec->exec_sid) { 20551da177e4SLinus Torvalds newsid = tsec->exec_sid; 20561da177e4SLinus Torvalds /* Reset exec SID on execve. */ 20571da177e4SLinus Torvalds tsec->exec_sid = 0; 20581da177e4SLinus Torvalds } else { 20591da177e4SLinus Torvalds /* Check for a default transition on this program. */ 20601da177e4SLinus Torvalds rc = security_transition_sid(tsec->sid, isec->sid, 20611da177e4SLinus Torvalds SECCLASS_PROCESS, &newsid); 20621da177e4SLinus Torvalds if (rc) 20631da177e4SLinus Torvalds return rc; 20641da177e4SLinus Torvalds } 20651da177e4SLinus Torvalds 20661da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 206744707fdfSJan Blunck ad.u.fs.path = bprm->file->f_path; 20681da177e4SLinus Torvalds 20693d5ff529SJosef Sipek if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) 20701da177e4SLinus Torvalds newsid = tsec->sid; 20711da177e4SLinus Torvalds 20721da177e4SLinus Torvalds if (tsec->sid == newsid) { 20731da177e4SLinus Torvalds rc = avc_has_perm(tsec->sid, isec->sid, 20741da177e4SLinus Torvalds SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); 20751da177e4SLinus Torvalds if (rc) 20761da177e4SLinus Torvalds return rc; 20771da177e4SLinus Torvalds } else { 20781da177e4SLinus Torvalds /* Check permissions for the transition. */ 20791da177e4SLinus Torvalds rc = avc_has_perm(tsec->sid, newsid, 20801da177e4SLinus Torvalds SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); 20811da177e4SLinus Torvalds if (rc) 20821da177e4SLinus Torvalds return rc; 20831da177e4SLinus Torvalds 20841da177e4SLinus Torvalds rc = avc_has_perm(newsid, isec->sid, 20851da177e4SLinus Torvalds SECCLASS_FILE, FILE__ENTRYPOINT, &ad); 20861da177e4SLinus Torvalds if (rc) 20871da177e4SLinus Torvalds return rc; 20881da177e4SLinus Torvalds 20891da177e4SLinus Torvalds /* Clear any possibly unsafe personality bits on exec: */ 20901da177e4SLinus Torvalds current->personality &= ~PER_CLEAR_ON_SETID; 20911da177e4SLinus Torvalds 20921da177e4SLinus Torvalds /* Set the security field to the new SID. */ 20931da177e4SLinus Torvalds bsec->sid = newsid; 20941da177e4SLinus Torvalds } 20951da177e4SLinus Torvalds 20961da177e4SLinus Torvalds bsec->set = 1; 20971da177e4SLinus Torvalds return 0; 20981da177e4SLinus Torvalds } 20991da177e4SLinus Torvalds 21001da177e4SLinus Torvalds static int selinux_bprm_check_security(struct linux_binprm *bprm) 21011da177e4SLinus Torvalds { 21021da177e4SLinus Torvalds return secondary_ops->bprm_check_security(bprm); 21031da177e4SLinus Torvalds } 21041da177e4SLinus Torvalds 21051da177e4SLinus Torvalds 21061da177e4SLinus Torvalds static int selinux_bprm_secureexec(struct linux_binprm *bprm) 21071da177e4SLinus Torvalds { 2108*275bb41eSDavid Howells const struct cred *cred = current_cred(); 2109*275bb41eSDavid Howells const struct task_security_struct *tsec = cred->security; 2110*275bb41eSDavid Howells u32 sid, osid; 21111da177e4SLinus Torvalds int atsecure = 0; 21121da177e4SLinus Torvalds 2113*275bb41eSDavid Howells sid = tsec->sid; 2114*275bb41eSDavid Howells osid = tsec->osid; 2115*275bb41eSDavid Howells 2116*275bb41eSDavid Howells if (osid != sid) { 21171da177e4SLinus Torvalds /* Enable secure mode for SIDs transitions unless 21181da177e4SLinus Torvalds the noatsecure permission is granted between 21191da177e4SLinus Torvalds the two SIDs, i.e. ahp returns 0. */ 2120*275bb41eSDavid Howells atsecure = avc_has_perm(osid, sid, 21211da177e4SLinus Torvalds SECCLASS_PROCESS, 21221da177e4SLinus Torvalds PROCESS__NOATSECURE, NULL); 21231da177e4SLinus Torvalds } 21241da177e4SLinus Torvalds 21251da177e4SLinus Torvalds return (atsecure || secondary_ops->bprm_secureexec(bprm)); 21261da177e4SLinus Torvalds } 21271da177e4SLinus Torvalds 21281da177e4SLinus Torvalds static void selinux_bprm_free_security(struct linux_binprm *bprm) 21291da177e4SLinus Torvalds { 21309a5f04bfSJesper Juhl kfree(bprm->security); 21311da177e4SLinus Torvalds bprm->security = NULL; 21321da177e4SLinus Torvalds } 21331da177e4SLinus Torvalds 21341da177e4SLinus Torvalds extern struct vfsmount *selinuxfs_mount; 21351da177e4SLinus Torvalds extern struct dentry *selinux_null; 21361da177e4SLinus Torvalds 21371da177e4SLinus Torvalds /* Derived from fs/exec.c:flush_old_files. */ 21381da177e4SLinus Torvalds static inline void flush_unauthorized_files(struct files_struct *files) 21391da177e4SLinus Torvalds { 21401da177e4SLinus Torvalds struct avc_audit_data ad; 21411da177e4SLinus Torvalds struct file *file, *devnull = NULL; 2142b20c8122SStephen Smalley struct tty_struct *tty; 2143badf1662SDipankar Sarma struct fdtable *fdt; 21441da177e4SLinus Torvalds long j = -1; 214524ec839cSPeter Zijlstra int drop_tty = 0; 21461da177e4SLinus Torvalds 214724ec839cSPeter Zijlstra tty = get_current_tty(); 21481da177e4SLinus Torvalds if (tty) { 21491da177e4SLinus Torvalds file_list_lock(); 215037dd0bd0SEric Paris if (!list_empty(&tty->tty_files)) { 215137dd0bd0SEric Paris struct inode *inode; 215237dd0bd0SEric Paris 21531da177e4SLinus Torvalds /* Revalidate access to controlling tty. 21541da177e4SLinus Torvalds Use inode_has_perm on the tty inode directly rather 21551da177e4SLinus Torvalds than using file_has_perm, as this particular open 21561da177e4SLinus Torvalds file may belong to another process and we are only 21571da177e4SLinus Torvalds interested in the inode-based check here. */ 215837dd0bd0SEric Paris file = list_first_entry(&tty->tty_files, struct file, f_u.fu_list); 215937dd0bd0SEric Paris inode = file->f_path.dentry->d_inode; 21601da177e4SLinus Torvalds if (inode_has_perm(current, inode, 21611da177e4SLinus Torvalds FILE__READ | FILE__WRITE, NULL)) { 216224ec839cSPeter Zijlstra drop_tty = 1; 21631da177e4SLinus Torvalds } 21641da177e4SLinus Torvalds } 21651da177e4SLinus Torvalds file_list_unlock(); 2166452a00d2SAlan Cox tty_kref_put(tty); 21671da177e4SLinus Torvalds } 216898a27ba4SEric W. Biederman /* Reset controlling tty. */ 216998a27ba4SEric W. Biederman if (drop_tty) 217098a27ba4SEric W. Biederman no_tty(); 21711da177e4SLinus Torvalds 21721da177e4SLinus Torvalds /* Revalidate access to inherited open files. */ 21731da177e4SLinus Torvalds 21741da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 21751da177e4SLinus Torvalds 21761da177e4SLinus Torvalds spin_lock(&files->file_lock); 21771da177e4SLinus Torvalds for (;;) { 21781da177e4SLinus Torvalds unsigned long set, i; 21791da177e4SLinus Torvalds int fd; 21801da177e4SLinus Torvalds 21811da177e4SLinus Torvalds j++; 21821da177e4SLinus Torvalds i = j * __NFDBITS; 2183badf1662SDipankar Sarma fdt = files_fdtable(files); 2184bbea9f69SVadim Lobanov if (i >= fdt->max_fds) 21851da177e4SLinus Torvalds break; 2186badf1662SDipankar Sarma set = fdt->open_fds->fds_bits[j]; 21871da177e4SLinus Torvalds if (!set) 21881da177e4SLinus Torvalds continue; 21891da177e4SLinus Torvalds spin_unlock(&files->file_lock); 21901da177e4SLinus Torvalds for ( ; set ; i++, set >>= 1) { 21911da177e4SLinus Torvalds if (set & 1) { 21921da177e4SLinus Torvalds file = fget(i); 21931da177e4SLinus Torvalds if (!file) 21941da177e4SLinus Torvalds continue; 21951da177e4SLinus Torvalds if (file_has_perm(current, 21961da177e4SLinus Torvalds file, 21971da177e4SLinus Torvalds file_to_av(file))) { 21981da177e4SLinus Torvalds sys_close(i); 21991da177e4SLinus Torvalds fd = get_unused_fd(); 22001da177e4SLinus Torvalds if (fd != i) { 22011da177e4SLinus Torvalds if (fd >= 0) 22021da177e4SLinus Torvalds put_unused_fd(fd); 22031da177e4SLinus Torvalds fput(file); 22041da177e4SLinus Torvalds continue; 22051da177e4SLinus Torvalds } 22061da177e4SLinus Torvalds if (devnull) { 2207095975daSNick Piggin get_file(devnull); 22081da177e4SLinus Torvalds } else { 22091da177e4SLinus Torvalds devnull = dentry_open(dget(selinux_null), mntget(selinuxfs_mount), O_RDWR); 2210fc5d81e6SAkinobu Mita if (IS_ERR(devnull)) { 2211fc5d81e6SAkinobu Mita devnull = NULL; 22121da177e4SLinus Torvalds put_unused_fd(fd); 22131da177e4SLinus Torvalds fput(file); 22141da177e4SLinus Torvalds continue; 22151da177e4SLinus Torvalds } 22161da177e4SLinus Torvalds } 22171da177e4SLinus Torvalds fd_install(fd, devnull); 22181da177e4SLinus Torvalds } 22191da177e4SLinus Torvalds fput(file); 22201da177e4SLinus Torvalds } 22211da177e4SLinus Torvalds } 22221da177e4SLinus Torvalds spin_lock(&files->file_lock); 22231da177e4SLinus Torvalds 22241da177e4SLinus Torvalds } 22251da177e4SLinus Torvalds spin_unlock(&files->file_lock); 22261da177e4SLinus Torvalds } 22271da177e4SLinus Torvalds 22281da177e4SLinus Torvalds static void selinux_bprm_apply_creds(struct linux_binprm *bprm, int unsafe) 22291da177e4SLinus Torvalds { 22301da177e4SLinus Torvalds struct task_security_struct *tsec; 22311da177e4SLinus Torvalds struct bprm_security_struct *bsec; 22321da177e4SLinus Torvalds u32 sid; 22331da177e4SLinus Torvalds int rc; 22341da177e4SLinus Torvalds 22351da177e4SLinus Torvalds secondary_ops->bprm_apply_creds(bprm, unsafe); 22361da177e4SLinus Torvalds 2237*275bb41eSDavid Howells tsec = current_security(); 22381da177e4SLinus Torvalds 22391da177e4SLinus Torvalds bsec = bprm->security; 22401da177e4SLinus Torvalds sid = bsec->sid; 22411da177e4SLinus Torvalds 22421da177e4SLinus Torvalds tsec->osid = tsec->sid; 22431da177e4SLinus Torvalds bsec->unsafe = 0; 22441da177e4SLinus Torvalds if (tsec->sid != sid) { 22451da177e4SLinus Torvalds /* Check for shared state. If not ok, leave SID 22461da177e4SLinus Torvalds unchanged and kill. */ 22471da177e4SLinus Torvalds if (unsafe & LSM_UNSAFE_SHARE) { 22481da177e4SLinus Torvalds rc = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, 22491da177e4SLinus Torvalds PROCESS__SHARE, NULL); 22501da177e4SLinus Torvalds if (rc) { 22511da177e4SLinus Torvalds bsec->unsafe = 1; 22521da177e4SLinus Torvalds return; 22531da177e4SLinus Torvalds } 22541da177e4SLinus Torvalds } 22551da177e4SLinus Torvalds 22561da177e4SLinus Torvalds /* Check for ptracing, and update the task SID if ok. 22571da177e4SLinus Torvalds Otherwise, leave SID unchanged and kill. */ 22581da177e4SLinus Torvalds if (unsafe & (LSM_UNSAFE_PTRACE | LSM_UNSAFE_PTRACE_CAP)) { 22590356357cSRoland McGrath struct task_struct *tracer; 22600356357cSRoland McGrath struct task_security_struct *sec; 22610356357cSRoland McGrath u32 ptsid = 0; 22620356357cSRoland McGrath 22630356357cSRoland McGrath rcu_read_lock(); 22640d094efeSRoland McGrath tracer = tracehook_tracer_task(current); 22650356357cSRoland McGrath if (likely(tracer != NULL)) { 2266*275bb41eSDavid Howells sec = __task_cred(tracer)->security; 22670356357cSRoland McGrath ptsid = sec->sid; 22680356357cSRoland McGrath } 22690356357cSRoland McGrath rcu_read_unlock(); 22700356357cSRoland McGrath 22710356357cSRoland McGrath if (ptsid != 0) { 22720356357cSRoland McGrath rc = avc_has_perm(ptsid, sid, SECCLASS_PROCESS, 22730356357cSRoland McGrath PROCESS__PTRACE, NULL); 22741da177e4SLinus Torvalds if (rc) { 22751da177e4SLinus Torvalds bsec->unsafe = 1; 22761da177e4SLinus Torvalds return; 22771da177e4SLinus Torvalds } 22781da177e4SLinus Torvalds } 22790356357cSRoland McGrath } 22801da177e4SLinus Torvalds tsec->sid = sid; 22811da177e4SLinus Torvalds } 22821da177e4SLinus Torvalds } 22831da177e4SLinus Torvalds 22841da177e4SLinus Torvalds /* 22851da177e4SLinus Torvalds * called after apply_creds without the task lock held 22861da177e4SLinus Torvalds */ 22871da177e4SLinus Torvalds static void selinux_bprm_post_apply_creds(struct linux_binprm *bprm) 22881da177e4SLinus Torvalds { 22891da177e4SLinus Torvalds struct task_security_struct *tsec; 22901da177e4SLinus Torvalds struct rlimit *rlim, *initrlim; 22911da177e4SLinus Torvalds struct itimerval itimer; 22921da177e4SLinus Torvalds struct bprm_security_struct *bsec; 229341d9f9c5SEric Paris struct sighand_struct *psig; 22941da177e4SLinus Torvalds int rc, i; 229541d9f9c5SEric Paris unsigned long flags; 22961da177e4SLinus Torvalds 2297*275bb41eSDavid Howells tsec = current_security(); 22981da177e4SLinus Torvalds bsec = bprm->security; 22991da177e4SLinus Torvalds 23001da177e4SLinus Torvalds if (bsec->unsafe) { 23011da177e4SLinus Torvalds force_sig_specific(SIGKILL, current); 23021da177e4SLinus Torvalds return; 23031da177e4SLinus Torvalds } 23041da177e4SLinus Torvalds if (tsec->osid == tsec->sid) 23051da177e4SLinus Torvalds return; 23061da177e4SLinus Torvalds 23071da177e4SLinus Torvalds /* Close files for which the new task SID is not authorized. */ 23081da177e4SLinus Torvalds flush_unauthorized_files(current->files); 23091da177e4SLinus Torvalds 23101da177e4SLinus Torvalds /* Check whether the new SID can inherit signal state 23111da177e4SLinus Torvalds from the old SID. If not, clear itimers to avoid 23121da177e4SLinus Torvalds subsequent signal generation and flush and unblock 23131da177e4SLinus Torvalds signals. This must occur _after_ the task SID has 23141da177e4SLinus Torvalds been updated so that any kill done after the flush 23151da177e4SLinus Torvalds will be checked against the new SID. */ 23161da177e4SLinus Torvalds rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, 23171da177e4SLinus Torvalds PROCESS__SIGINH, NULL); 23181da177e4SLinus Torvalds if (rc) { 23191da177e4SLinus Torvalds memset(&itimer, 0, sizeof itimer); 23201da177e4SLinus Torvalds for (i = 0; i < 3; i++) 23211da177e4SLinus Torvalds do_setitimer(i, &itimer, NULL); 23221da177e4SLinus Torvalds flush_signals(current); 23231da177e4SLinus Torvalds spin_lock_irq(¤t->sighand->siglock); 23241da177e4SLinus Torvalds flush_signal_handlers(current, 1); 23251da177e4SLinus Torvalds sigemptyset(¤t->blocked); 23261da177e4SLinus Torvalds recalc_sigpending(); 23271da177e4SLinus Torvalds spin_unlock_irq(¤t->sighand->siglock); 23281da177e4SLinus Torvalds } 23291da177e4SLinus Torvalds 23304ac212adSStephen Smalley /* Always clear parent death signal on SID transitions. */ 23314ac212adSStephen Smalley current->pdeath_signal = 0; 23324ac212adSStephen Smalley 23331da177e4SLinus Torvalds /* Check whether the new SID can inherit resource limits 23341da177e4SLinus Torvalds from the old SID. If not, reset all soft limits to 23351da177e4SLinus Torvalds the lower of the current task's hard limit and the init 23361da177e4SLinus Torvalds task's soft limit. Note that the setting of hard limits 23371da177e4SLinus Torvalds (even to lower them) can be controlled by the setrlimit 23381da177e4SLinus Torvalds check. The inclusion of the init task's soft limit into 23391da177e4SLinus Torvalds the computation is to avoid resetting soft limits higher 23401da177e4SLinus Torvalds than the default soft limit for cases where the default 23411da177e4SLinus Torvalds is lower than the hard limit, e.g. RLIMIT_CORE or 23421da177e4SLinus Torvalds RLIMIT_STACK.*/ 23431da177e4SLinus Torvalds rc = avc_has_perm(tsec->osid, tsec->sid, SECCLASS_PROCESS, 23441da177e4SLinus Torvalds PROCESS__RLIMITINH, NULL); 23451da177e4SLinus Torvalds if (rc) { 23461da177e4SLinus Torvalds for (i = 0; i < RLIM_NLIMITS; i++) { 23471da177e4SLinus Torvalds rlim = current->signal->rlim + i; 23481da177e4SLinus Torvalds initrlim = init_task.signal->rlim+i; 23491da177e4SLinus Torvalds rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur); 23501da177e4SLinus Torvalds } 2351f06febc9SFrank Mayhar update_rlimit_cpu(rlim->rlim_cur); 23521da177e4SLinus Torvalds } 23531da177e4SLinus Torvalds 23541da177e4SLinus Torvalds /* Wake up the parent if it is waiting so that it can 23551da177e4SLinus Torvalds recheck wait permission to the new task SID. */ 235641d9f9c5SEric Paris read_lock_irq(&tasklist_lock); 235741d9f9c5SEric Paris psig = current->parent->sighand; 235841d9f9c5SEric Paris spin_lock_irqsave(&psig->siglock, flags); 23591da177e4SLinus Torvalds wake_up_interruptible(¤t->parent->signal->wait_chldexit); 236041d9f9c5SEric Paris spin_unlock_irqrestore(&psig->siglock, flags); 236141d9f9c5SEric Paris read_unlock_irq(&tasklist_lock); 23621da177e4SLinus Torvalds } 23631da177e4SLinus Torvalds 23641da177e4SLinus Torvalds /* superblock security operations */ 23651da177e4SLinus Torvalds 23661da177e4SLinus Torvalds static int selinux_sb_alloc_security(struct super_block *sb) 23671da177e4SLinus Torvalds { 23681da177e4SLinus Torvalds return superblock_alloc_security(sb); 23691da177e4SLinus Torvalds } 23701da177e4SLinus Torvalds 23711da177e4SLinus Torvalds static void selinux_sb_free_security(struct super_block *sb) 23721da177e4SLinus Torvalds { 23731da177e4SLinus Torvalds superblock_free_security(sb); 23741da177e4SLinus Torvalds } 23751da177e4SLinus Torvalds 23761da177e4SLinus Torvalds static inline int match_prefix(char *prefix, int plen, char *option, int olen) 23771da177e4SLinus Torvalds { 23781da177e4SLinus Torvalds if (plen > olen) 23791da177e4SLinus Torvalds return 0; 23801da177e4SLinus Torvalds 23811da177e4SLinus Torvalds return !memcmp(prefix, option, plen); 23821da177e4SLinus Torvalds } 23831da177e4SLinus Torvalds 23841da177e4SLinus Torvalds static inline int selinux_option(char *option, int len) 23851da177e4SLinus Torvalds { 2386832cbd9aSEric Paris return (match_prefix(CONTEXT_STR, sizeof(CONTEXT_STR)-1, option, len) || 2387832cbd9aSEric Paris match_prefix(FSCONTEXT_STR, sizeof(FSCONTEXT_STR)-1, option, len) || 2388832cbd9aSEric Paris match_prefix(DEFCONTEXT_STR, sizeof(DEFCONTEXT_STR)-1, option, len) || 2389832cbd9aSEric Paris match_prefix(ROOTCONTEXT_STR, sizeof(ROOTCONTEXT_STR)-1, option, len)); 23901da177e4SLinus Torvalds } 23911da177e4SLinus Torvalds 23921da177e4SLinus Torvalds static inline void take_option(char **to, char *from, int *first, int len) 23931da177e4SLinus Torvalds { 23941da177e4SLinus Torvalds if (!*first) { 23951da177e4SLinus Torvalds **to = ','; 23961da177e4SLinus Torvalds *to += 1; 23973528a953SCory Olmo } else 23981da177e4SLinus Torvalds *first = 0; 23991da177e4SLinus Torvalds memcpy(*to, from, len); 24001da177e4SLinus Torvalds *to += len; 24011da177e4SLinus Torvalds } 24021da177e4SLinus Torvalds 24033528a953SCory Olmo static inline void take_selinux_option(char **to, char *from, int *first, 24043528a953SCory Olmo int len) 24053528a953SCory Olmo { 24063528a953SCory Olmo int current_size = 0; 24073528a953SCory Olmo 24083528a953SCory Olmo if (!*first) { 24093528a953SCory Olmo **to = '|'; 24103528a953SCory Olmo *to += 1; 2411828dfe1dSEric Paris } else 24123528a953SCory Olmo *first = 0; 24133528a953SCory Olmo 24143528a953SCory Olmo while (current_size < len) { 24153528a953SCory Olmo if (*from != '"') { 24163528a953SCory Olmo **to = *from; 24173528a953SCory Olmo *to += 1; 24183528a953SCory Olmo } 24193528a953SCory Olmo from += 1; 24203528a953SCory Olmo current_size += 1; 24213528a953SCory Olmo } 24223528a953SCory Olmo } 24233528a953SCory Olmo 2424e0007529SEric Paris static int selinux_sb_copy_data(char *orig, char *copy) 24251da177e4SLinus Torvalds { 24261da177e4SLinus Torvalds int fnosec, fsec, rc = 0; 24271da177e4SLinus Torvalds char *in_save, *in_curr, *in_end; 24281da177e4SLinus Torvalds char *sec_curr, *nosec_save, *nosec; 24293528a953SCory Olmo int open_quote = 0; 24301da177e4SLinus Torvalds 24311da177e4SLinus Torvalds in_curr = orig; 24321da177e4SLinus Torvalds sec_curr = copy; 24331da177e4SLinus Torvalds 24341da177e4SLinus Torvalds nosec = (char *)get_zeroed_page(GFP_KERNEL); 24351da177e4SLinus Torvalds if (!nosec) { 24361da177e4SLinus Torvalds rc = -ENOMEM; 24371da177e4SLinus Torvalds goto out; 24381da177e4SLinus Torvalds } 24391da177e4SLinus Torvalds 24401da177e4SLinus Torvalds nosec_save = nosec; 24411da177e4SLinus Torvalds fnosec = fsec = 1; 24421da177e4SLinus Torvalds in_save = in_end = orig; 24431da177e4SLinus Torvalds 24441da177e4SLinus Torvalds do { 24453528a953SCory Olmo if (*in_end == '"') 24463528a953SCory Olmo open_quote = !open_quote; 24473528a953SCory Olmo if ((*in_end == ',' && open_quote == 0) || 24483528a953SCory Olmo *in_end == '\0') { 24491da177e4SLinus Torvalds int len = in_end - in_curr; 24501da177e4SLinus Torvalds 24511da177e4SLinus Torvalds if (selinux_option(in_curr, len)) 24523528a953SCory Olmo take_selinux_option(&sec_curr, in_curr, &fsec, len); 24531da177e4SLinus Torvalds else 24541da177e4SLinus Torvalds take_option(&nosec, in_curr, &fnosec, len); 24551da177e4SLinus Torvalds 24561da177e4SLinus Torvalds in_curr = in_end + 1; 24571da177e4SLinus Torvalds } 24581da177e4SLinus Torvalds } while (*in_end++); 24591da177e4SLinus Torvalds 24606931dfc9SEric Paris strcpy(in_save, nosec_save); 2461da3caa20SGerald Schaefer free_page((unsigned long)nosec_save); 24621da177e4SLinus Torvalds out: 24631da177e4SLinus Torvalds return rc; 24641da177e4SLinus Torvalds } 24651da177e4SLinus Torvalds 24661da177e4SLinus Torvalds static int selinux_sb_kern_mount(struct super_block *sb, void *data) 24671da177e4SLinus Torvalds { 24681da177e4SLinus Torvalds struct avc_audit_data ad; 24691da177e4SLinus Torvalds int rc; 24701da177e4SLinus Torvalds 24711da177e4SLinus Torvalds rc = superblock_doinit(sb, data); 24721da177e4SLinus Torvalds if (rc) 24731da177e4SLinus Torvalds return rc; 24741da177e4SLinus Torvalds 24751da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 247644707fdfSJan Blunck ad.u.fs.path.dentry = sb->s_root; 24771da177e4SLinus Torvalds return superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad); 24781da177e4SLinus Torvalds } 24791da177e4SLinus Torvalds 2480726c3342SDavid Howells static int selinux_sb_statfs(struct dentry *dentry) 24811da177e4SLinus Torvalds { 24821da177e4SLinus Torvalds struct avc_audit_data ad; 24831da177e4SLinus Torvalds 24841da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 248544707fdfSJan Blunck ad.u.fs.path.dentry = dentry->d_sb->s_root; 2486726c3342SDavid Howells return superblock_has_perm(current, dentry->d_sb, FILESYSTEM__GETATTR, &ad); 24871da177e4SLinus Torvalds } 24881da177e4SLinus Torvalds 24891da177e4SLinus Torvalds static int selinux_mount(char *dev_name, 2490b5266eb4SAl Viro struct path *path, 24911da177e4SLinus Torvalds char *type, 24921da177e4SLinus Torvalds unsigned long flags, 24931da177e4SLinus Torvalds void *data) 24941da177e4SLinus Torvalds { 24951da177e4SLinus Torvalds int rc; 24961da177e4SLinus Torvalds 2497b5266eb4SAl Viro rc = secondary_ops->sb_mount(dev_name, path, type, flags, data); 24981da177e4SLinus Torvalds if (rc) 24991da177e4SLinus Torvalds return rc; 25001da177e4SLinus Torvalds 25011da177e4SLinus Torvalds if (flags & MS_REMOUNT) 2502b5266eb4SAl Viro return superblock_has_perm(current, path->mnt->mnt_sb, 25031da177e4SLinus Torvalds FILESYSTEM__REMOUNT, NULL); 25041da177e4SLinus Torvalds else 2505b5266eb4SAl Viro return dentry_has_perm(current, path->mnt, path->dentry, 25061da177e4SLinus Torvalds FILE__MOUNTON); 25071da177e4SLinus Torvalds } 25081da177e4SLinus Torvalds 25091da177e4SLinus Torvalds static int selinux_umount(struct vfsmount *mnt, int flags) 25101da177e4SLinus Torvalds { 25111da177e4SLinus Torvalds int rc; 25121da177e4SLinus Torvalds 25131da177e4SLinus Torvalds rc = secondary_ops->sb_umount(mnt, flags); 25141da177e4SLinus Torvalds if (rc) 25151da177e4SLinus Torvalds return rc; 25161da177e4SLinus Torvalds 25171da177e4SLinus Torvalds return superblock_has_perm(current, mnt->mnt_sb, 25181da177e4SLinus Torvalds FILESYSTEM__UNMOUNT, NULL); 25191da177e4SLinus Torvalds } 25201da177e4SLinus Torvalds 25211da177e4SLinus Torvalds /* inode security operations */ 25221da177e4SLinus Torvalds 25231da177e4SLinus Torvalds static int selinux_inode_alloc_security(struct inode *inode) 25241da177e4SLinus Torvalds { 25251da177e4SLinus Torvalds return inode_alloc_security(inode); 25261da177e4SLinus Torvalds } 25271da177e4SLinus Torvalds 25281da177e4SLinus Torvalds static void selinux_inode_free_security(struct inode *inode) 25291da177e4SLinus Torvalds { 25301da177e4SLinus Torvalds inode_free_security(inode); 25311da177e4SLinus Torvalds } 25321da177e4SLinus Torvalds 25335e41ff9eSStephen Smalley static int selinux_inode_init_security(struct inode *inode, struct inode *dir, 25345e41ff9eSStephen Smalley char **name, void **value, 25355e41ff9eSStephen Smalley size_t *len) 25365e41ff9eSStephen Smalley { 2537*275bb41eSDavid Howells const struct cred *cred = current_cred(); 2538*275bb41eSDavid Howells const struct task_security_struct *tsec = cred->security; 25395e41ff9eSStephen Smalley struct inode_security_struct *dsec; 25405e41ff9eSStephen Smalley struct superblock_security_struct *sbsec; 2541*275bb41eSDavid Howells u32 sid, newsid, clen; 25425e41ff9eSStephen Smalley int rc; 2543570bc1c2SStephen Smalley char *namep = NULL, *context; 25445e41ff9eSStephen Smalley 25455e41ff9eSStephen Smalley dsec = dir->i_security; 25465e41ff9eSStephen Smalley sbsec = dir->i_sb->s_security; 25475e41ff9eSStephen Smalley 2548*275bb41eSDavid Howells sid = tsec->sid; 25495e41ff9eSStephen Smalley newsid = tsec->create_sid; 2550*275bb41eSDavid Howells 2551*275bb41eSDavid Howells if (!newsid || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) { 2552*275bb41eSDavid Howells rc = security_transition_sid(sid, dsec->sid, 25535e41ff9eSStephen Smalley inode_mode_to_security_class(inode->i_mode), 25545e41ff9eSStephen Smalley &newsid); 25555e41ff9eSStephen Smalley if (rc) { 25565e41ff9eSStephen Smalley printk(KERN_WARNING "%s: " 25575e41ff9eSStephen Smalley "security_transition_sid failed, rc=%d (dev=%s " 25585e41ff9eSStephen Smalley "ino=%ld)\n", 2559dd6f953aSHarvey Harrison __func__, 25605e41ff9eSStephen Smalley -rc, inode->i_sb->s_id, inode->i_ino); 25615e41ff9eSStephen Smalley return rc; 25625e41ff9eSStephen Smalley } 25635e41ff9eSStephen Smalley } 25645e41ff9eSStephen Smalley 2565296fddf7SEric Paris /* Possibly defer initialization to selinux_complete_init. */ 2566296fddf7SEric Paris if (sbsec->initialized) { 2567296fddf7SEric Paris struct inode_security_struct *isec = inode->i_security; 2568296fddf7SEric Paris isec->sclass = inode_mode_to_security_class(inode->i_mode); 2569296fddf7SEric Paris isec->sid = newsid; 2570296fddf7SEric Paris isec->initialized = 1; 2571296fddf7SEric Paris } 25725e41ff9eSStephen Smalley 25738aad3875SStephen Smalley if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT) 257425a74f3bSStephen Smalley return -EOPNOTSUPP; 257525a74f3bSStephen Smalley 2576570bc1c2SStephen Smalley if (name) { 2577a02fe132SJosef Bacik namep = kstrdup(XATTR_SELINUX_SUFFIX, GFP_NOFS); 25785e41ff9eSStephen Smalley if (!namep) 25795e41ff9eSStephen Smalley return -ENOMEM; 25805e41ff9eSStephen Smalley *name = namep; 2581570bc1c2SStephen Smalley } 25825e41ff9eSStephen Smalley 2583570bc1c2SStephen Smalley if (value && len) { 258412b29f34SStephen Smalley rc = security_sid_to_context_force(newsid, &context, &clen); 25855e41ff9eSStephen Smalley if (rc) { 25865e41ff9eSStephen Smalley kfree(namep); 25875e41ff9eSStephen Smalley return rc; 25885e41ff9eSStephen Smalley } 25895e41ff9eSStephen Smalley *value = context; 2590570bc1c2SStephen Smalley *len = clen; 2591570bc1c2SStephen Smalley } 25925e41ff9eSStephen Smalley 25935e41ff9eSStephen Smalley return 0; 25945e41ff9eSStephen Smalley } 25955e41ff9eSStephen Smalley 25961da177e4SLinus Torvalds static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask) 25971da177e4SLinus Torvalds { 25981da177e4SLinus Torvalds return may_create(dir, dentry, SECCLASS_FILE); 25991da177e4SLinus Torvalds } 26001da177e4SLinus Torvalds 26011da177e4SLinus Torvalds static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) 26021da177e4SLinus Torvalds { 26031da177e4SLinus Torvalds int rc; 26041da177e4SLinus Torvalds 26051da177e4SLinus Torvalds rc = secondary_ops->inode_link(old_dentry, dir, new_dentry); 26061da177e4SLinus Torvalds if (rc) 26071da177e4SLinus Torvalds return rc; 26081da177e4SLinus Torvalds return may_link(dir, old_dentry, MAY_LINK); 26091da177e4SLinus Torvalds } 26101da177e4SLinus Torvalds 26111da177e4SLinus Torvalds static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry) 26121da177e4SLinus Torvalds { 26131da177e4SLinus Torvalds int rc; 26141da177e4SLinus Torvalds 26151da177e4SLinus Torvalds rc = secondary_ops->inode_unlink(dir, dentry); 26161da177e4SLinus Torvalds if (rc) 26171da177e4SLinus Torvalds return rc; 26181da177e4SLinus Torvalds return may_link(dir, dentry, MAY_UNLINK); 26191da177e4SLinus Torvalds } 26201da177e4SLinus Torvalds 26211da177e4SLinus Torvalds static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name) 26221da177e4SLinus Torvalds { 26231da177e4SLinus Torvalds return may_create(dir, dentry, SECCLASS_LNK_FILE); 26241da177e4SLinus Torvalds } 26251da177e4SLinus Torvalds 26261da177e4SLinus Torvalds static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask) 26271da177e4SLinus Torvalds { 26281da177e4SLinus Torvalds return may_create(dir, dentry, SECCLASS_DIR); 26291da177e4SLinus Torvalds } 26301da177e4SLinus Torvalds 26311da177e4SLinus Torvalds static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry) 26321da177e4SLinus Torvalds { 26331da177e4SLinus Torvalds return may_link(dir, dentry, MAY_RMDIR); 26341da177e4SLinus Torvalds } 26351da177e4SLinus Torvalds 26361da177e4SLinus Torvalds static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) 26371da177e4SLinus Torvalds { 26381da177e4SLinus Torvalds int rc; 26391da177e4SLinus Torvalds 26401da177e4SLinus Torvalds rc = secondary_ops->inode_mknod(dir, dentry, mode, dev); 26411da177e4SLinus Torvalds if (rc) 26421da177e4SLinus Torvalds return rc; 26431da177e4SLinus Torvalds 26441da177e4SLinus Torvalds return may_create(dir, dentry, inode_mode_to_security_class(mode)); 26451da177e4SLinus Torvalds } 26461da177e4SLinus Torvalds 26471da177e4SLinus Torvalds static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry, 26481da177e4SLinus Torvalds struct inode *new_inode, struct dentry *new_dentry) 26491da177e4SLinus Torvalds { 26501da177e4SLinus Torvalds return may_rename(old_inode, old_dentry, new_inode, new_dentry); 26511da177e4SLinus Torvalds } 26521da177e4SLinus Torvalds 26531da177e4SLinus Torvalds static int selinux_inode_readlink(struct dentry *dentry) 26541da177e4SLinus Torvalds { 26551da177e4SLinus Torvalds return dentry_has_perm(current, NULL, dentry, FILE__READ); 26561da177e4SLinus Torvalds } 26571da177e4SLinus Torvalds 26581da177e4SLinus Torvalds static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata) 26591da177e4SLinus Torvalds { 26601da177e4SLinus Torvalds int rc; 26611da177e4SLinus Torvalds 26621da177e4SLinus Torvalds rc = secondary_ops->inode_follow_link(dentry, nameidata); 26631da177e4SLinus Torvalds if (rc) 26641da177e4SLinus Torvalds return rc; 26651da177e4SLinus Torvalds return dentry_has_perm(current, NULL, dentry, FILE__READ); 26661da177e4SLinus Torvalds } 26671da177e4SLinus Torvalds 2668b77b0646SAl Viro static int selinux_inode_permission(struct inode *inode, int mask) 26691da177e4SLinus Torvalds { 26701da177e4SLinus Torvalds int rc; 26711da177e4SLinus Torvalds 2672b77b0646SAl Viro rc = secondary_ops->inode_permission(inode, mask); 26731da177e4SLinus Torvalds if (rc) 26741da177e4SLinus Torvalds return rc; 26751da177e4SLinus Torvalds 26761da177e4SLinus Torvalds if (!mask) { 26771da177e4SLinus Torvalds /* No permission to check. Existence test. */ 26781da177e4SLinus Torvalds return 0; 26791da177e4SLinus Torvalds } 26801da177e4SLinus Torvalds 26811da177e4SLinus Torvalds return inode_has_perm(current, inode, 26828b6a5a37SEric Paris file_mask_to_av(inode->i_mode, mask), NULL); 26831da177e4SLinus Torvalds } 26841da177e4SLinus Torvalds 26851da177e4SLinus Torvalds static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) 26861da177e4SLinus Torvalds { 26871da177e4SLinus Torvalds int rc; 26881da177e4SLinus Torvalds 26891da177e4SLinus Torvalds rc = secondary_ops->inode_setattr(dentry, iattr); 26901da177e4SLinus Torvalds if (rc) 26911da177e4SLinus Torvalds return rc; 26921da177e4SLinus Torvalds 26931da177e4SLinus Torvalds if (iattr->ia_valid & ATTR_FORCE) 26941da177e4SLinus Torvalds return 0; 26951da177e4SLinus Torvalds 26961da177e4SLinus Torvalds if (iattr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | 26971da177e4SLinus Torvalds ATTR_ATIME_SET | ATTR_MTIME_SET)) 26981da177e4SLinus Torvalds return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); 26991da177e4SLinus Torvalds 27001da177e4SLinus Torvalds return dentry_has_perm(current, NULL, dentry, FILE__WRITE); 27011da177e4SLinus Torvalds } 27021da177e4SLinus Torvalds 27031da177e4SLinus Torvalds static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) 27041da177e4SLinus Torvalds { 27051da177e4SLinus Torvalds return dentry_has_perm(current, mnt, dentry, FILE__GETATTR); 27061da177e4SLinus Torvalds } 27071da177e4SLinus Torvalds 27088f0cfa52SDavid Howells static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) 2709b5376771SSerge E. Hallyn { 2710b5376771SSerge E. Hallyn if (!strncmp(name, XATTR_SECURITY_PREFIX, 2711b5376771SSerge E. Hallyn sizeof XATTR_SECURITY_PREFIX - 1)) { 2712b5376771SSerge E. Hallyn if (!strcmp(name, XATTR_NAME_CAPS)) { 2713b5376771SSerge E. Hallyn if (!capable(CAP_SETFCAP)) 2714b5376771SSerge E. Hallyn return -EPERM; 2715b5376771SSerge E. Hallyn } else if (!capable(CAP_SYS_ADMIN)) { 2716b5376771SSerge E. Hallyn /* A different attribute in the security namespace. 2717b5376771SSerge E. Hallyn Restrict to administrator. */ 2718b5376771SSerge E. Hallyn return -EPERM; 2719b5376771SSerge E. Hallyn } 2720b5376771SSerge E. Hallyn } 2721b5376771SSerge E. Hallyn 2722b5376771SSerge E. Hallyn /* Not an attribute we recognize, so just check the 2723b5376771SSerge E. Hallyn ordinary setattr permission. */ 2724b5376771SSerge E. Hallyn return dentry_has_perm(current, NULL, dentry, FILE__SETATTR); 2725b5376771SSerge E. Hallyn } 2726b5376771SSerge E. Hallyn 27278f0cfa52SDavid Howells static int selinux_inode_setxattr(struct dentry *dentry, const char *name, 27288f0cfa52SDavid Howells const void *value, size_t size, int flags) 27291da177e4SLinus Torvalds { 27301da177e4SLinus Torvalds struct inode *inode = dentry->d_inode; 27311da177e4SLinus Torvalds struct inode_security_struct *isec = inode->i_security; 27321da177e4SLinus Torvalds struct superblock_security_struct *sbsec; 27331da177e4SLinus Torvalds struct avc_audit_data ad; 2734*275bb41eSDavid Howells u32 newsid, sid = current_sid(); 27351da177e4SLinus Torvalds int rc = 0; 27361da177e4SLinus Torvalds 2737b5376771SSerge E. Hallyn if (strcmp(name, XATTR_NAME_SELINUX)) 2738b5376771SSerge E. Hallyn return selinux_inode_setotherxattr(dentry, name); 27391da177e4SLinus Torvalds 27401da177e4SLinus Torvalds sbsec = inode->i_sb->s_security; 27411da177e4SLinus Torvalds if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT) 27421da177e4SLinus Torvalds return -EOPNOTSUPP; 27431da177e4SLinus Torvalds 27443bd858abSSatyam Sharma if (!is_owner_or_cap(inode)) 27451da177e4SLinus Torvalds return -EPERM; 27461da177e4SLinus Torvalds 27471da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, FS); 274844707fdfSJan Blunck ad.u.fs.path.dentry = dentry; 27491da177e4SLinus Torvalds 2750*275bb41eSDavid Howells rc = avc_has_perm(sid, isec->sid, isec->sclass, 27511da177e4SLinus Torvalds FILE__RELABELFROM, &ad); 27521da177e4SLinus Torvalds if (rc) 27531da177e4SLinus Torvalds return rc; 27541da177e4SLinus Torvalds 27551da177e4SLinus Torvalds rc = security_context_to_sid(value, size, &newsid); 275612b29f34SStephen Smalley if (rc == -EINVAL) { 275712b29f34SStephen Smalley if (!capable(CAP_MAC_ADMIN)) 275812b29f34SStephen Smalley return rc; 275912b29f34SStephen Smalley rc = security_context_to_sid_force(value, size, &newsid); 276012b29f34SStephen Smalley } 27611da177e4SLinus Torvalds if (rc) 27621da177e4SLinus Torvalds return rc; 27631da177e4SLinus Torvalds 2764*275bb41eSDavid Howells rc = avc_has_perm(sid, newsid, isec->sclass, 27651da177e4SLinus Torvalds FILE__RELABELTO, &ad); 27661da177e4SLinus Torvalds if (rc) 27671da177e4SLinus Torvalds return rc; 27681da177e4SLinus Torvalds 2769*275bb41eSDavid Howells rc = security_validate_transition(isec->sid, newsid, sid, 27701da177e4SLinus Torvalds isec->sclass); 27711da177e4SLinus Torvalds if (rc) 27721da177e4SLinus Torvalds return rc; 27731da177e4SLinus Torvalds 27741da177e4SLinus Torvalds return avc_has_perm(newsid, 27751da177e4SLinus Torvalds sbsec->sid, 27761da177e4SLinus Torvalds SECCLASS_FILESYSTEM, 27771da177e4SLinus Torvalds FILESYSTEM__ASSOCIATE, 27781da177e4SLinus Torvalds &ad); 27791da177e4SLinus Torvalds } 27801da177e4SLinus Torvalds 27818f0cfa52SDavid Howells static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, 27828f0cfa52SDavid Howells const void *value, size_t size, 27838f0cfa52SDavid Howells int flags) 27841da177e4SLinus Torvalds { 27851da177e4SLinus Torvalds struct inode *inode = dentry->d_inode; 27861da177e4SLinus Torvalds struct inode_security_struct *isec = inode->i_security; 27871da177e4SLinus Torvalds u32 newsid; 27881da177e4SLinus Torvalds int rc; 27891da177e4SLinus Torvalds 27901da177e4SLinus Torvalds if (strcmp(name, XATTR_NAME_SELINUX)) { 27911da177e4SLinus Torvalds /* Not an attribute we recognize, so nothing to do. */ 27921da177e4SLinus Torvalds return; 27931da177e4SLinus Torvalds } 27941da177e4SLinus Torvalds 279512b29f34SStephen Smalley rc = security_context_to_sid_force(value, size, &newsid); 27961da177e4SLinus Torvalds if (rc) { 279712b29f34SStephen Smalley printk(KERN_ERR "SELinux: unable to map context to SID" 279812b29f34SStephen Smalley "for (%s, %lu), rc=%d\n", 279912b29f34SStephen Smalley inode->i_sb->s_id, inode->i_ino, -rc); 28001da177e4SLinus Torvalds return; 28011da177e4SLinus Torvalds } 28021da177e4SLinus Torvalds 28031da177e4SLinus Torvalds isec->sid = newsid; 28041da177e4SLinus Torvalds return; 28051da177e4SLinus Torvalds } 28061da177e4SLinus Torvalds 28078f0cfa52SDavid Howells static int selinux_inode_getxattr(struct dentry *dentry, const char *name) 28081da177e4SLinus Torvalds { 28091da177e4SLinus Torvalds return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); 28101da177e4SLinus Torvalds } 28111da177e4SLinus Torvalds 28121da177e4SLinus Torvalds static int selinux_inode_listxattr(struct dentry *dentry) 28131da177e4SLinus Torvalds { 28141da177e4SLinus Torvalds return dentry_has_perm(current, NULL, dentry, FILE__GETATTR); 28151da177e4SLinus Torvalds } 28161da177e4SLinus Torvalds 28178f0cfa52SDavid Howells static int selinux_inode_removexattr(struct dentry *dentry, const char *name) 28181da177e4SLinus Torvalds { 2819b5376771SSerge E. Hallyn if (strcmp(name, XATTR_NAME_SELINUX)) 2820b5376771SSerge E. Hallyn return selinux_inode_setotherxattr(dentry, name); 28211da177e4SLinus Torvalds 28221da177e4SLinus Torvalds /* No one is allowed to remove a SELinux security label. 28231da177e4SLinus Torvalds You can change the label, but all data must be labeled. */ 28241da177e4SLinus Torvalds return -EACCES; 28251da177e4SLinus Torvalds } 28261da177e4SLinus Torvalds 2827d381d8a9SJames Morris /* 2828abc69bb6SStephen Smalley * Copy the inode security context value to the user. 2829d381d8a9SJames Morris * 2830d381d8a9SJames Morris * Permission check is handled by selinux_inode_getxattr hook. 2831d381d8a9SJames Morris */ 283242492594SDavid P. Quigley static int selinux_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc) 28331da177e4SLinus Torvalds { 283442492594SDavid P. Quigley u32 size; 283542492594SDavid P. Quigley int error; 283642492594SDavid P. Quigley char *context = NULL; 28371da177e4SLinus Torvalds struct inode_security_struct *isec = inode->i_security; 28381da177e4SLinus Torvalds 28398c8570fbSDustin Kirkland if (strcmp(name, XATTR_SELINUX_SUFFIX)) 28408c8570fbSDustin Kirkland return -EOPNOTSUPP; 28411da177e4SLinus Torvalds 2842abc69bb6SStephen Smalley /* 2843abc69bb6SStephen Smalley * If the caller has CAP_MAC_ADMIN, then get the raw context 2844abc69bb6SStephen Smalley * value even if it is not defined by current policy; otherwise, 2845abc69bb6SStephen Smalley * use the in-core value under current policy. 2846abc69bb6SStephen Smalley * Use the non-auditing forms of the permission checks since 2847abc69bb6SStephen Smalley * getxattr may be called by unprivileged processes commonly 2848abc69bb6SStephen Smalley * and lack of permission just means that we fall back to the 2849abc69bb6SStephen Smalley * in-core context value, not a denial. 2850abc69bb6SStephen Smalley */ 285106674679SEric Paris error = selinux_capable(current, CAP_MAC_ADMIN, SECURITY_CAP_NOAUDIT); 2852abc69bb6SStephen Smalley if (!error) 2853abc69bb6SStephen Smalley error = security_sid_to_context_force(isec->sid, &context, 2854abc69bb6SStephen Smalley &size); 2855abc69bb6SStephen Smalley else 285642492594SDavid P. Quigley error = security_sid_to_context(isec->sid, &context, &size); 285742492594SDavid P. Quigley if (error) 285842492594SDavid P. Quigley return error; 285942492594SDavid P. Quigley error = size; 286042492594SDavid P. Quigley if (alloc) { 286142492594SDavid P. Quigley *buffer = context; 286242492594SDavid P. Quigley goto out_nofree; 286342492594SDavid P. Quigley } 286442492594SDavid P. Quigley kfree(context); 286542492594SDavid P. Quigley out_nofree: 286642492594SDavid P. Quigley return error; 28671da177e4SLinus Torvalds } 28681da177e4SLinus Torvalds 28691da177e4SLinus Torvalds static int selinux_inode_setsecurity(struct inode *inode, const char *name, 28701da177e4SLinus Torvalds const void *value, size_t size, int flags) 28711da177e4SLinus Torvalds { 28721da177e4SLinus Torvalds struct inode_security_struct *isec = inode->i_security; 28731da177e4SLinus Torvalds u32 newsid; 28741da177e4SLinus Torvalds int rc; 28751da177e4SLinus Torvalds 28761da177e4SLinus Torvalds if (strcmp(name, XATTR_SELINUX_SUFFIX)) 28771da177e4SLinus Torvalds return -EOPNOTSUPP; 28781da177e4SLinus Torvalds 28791da177e4SLinus Torvalds if (!value || !size) 28801da177e4SLinus Torvalds return -EACCES; 28811da177e4SLinus Torvalds 28821da177e4SLinus Torvalds rc = security_context_to_sid((void *)value, size, &newsid); 28831da177e4SLinus Torvalds if (rc) 28841da177e4SLinus Torvalds return rc; 28851da177e4SLinus Torvalds 28861da177e4SLinus Torvalds isec->sid = newsid; 28871da177e4SLinus Torvalds return 0; 28881da177e4SLinus Torvalds } 28891da177e4SLinus Torvalds 28901da177e4SLinus Torvalds static int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size) 28911da177e4SLinus Torvalds { 28921da177e4SLinus Torvalds const int len = sizeof(XATTR_NAME_SELINUX); 28931da177e4SLinus Torvalds if (buffer && len <= buffer_size) 28941da177e4SLinus Torvalds memcpy(buffer, XATTR_NAME_SELINUX, len); 28951da177e4SLinus Torvalds return len; 28961da177e4SLinus Torvalds } 28971da177e4SLinus Torvalds 2898b5376771SSerge E. Hallyn static int selinux_inode_need_killpriv(struct dentry *dentry) 2899b5376771SSerge E. Hallyn { 2900b5376771SSerge E. Hallyn return secondary_ops->inode_need_killpriv(dentry); 2901b5376771SSerge E. Hallyn } 2902b5376771SSerge E. Hallyn 2903b5376771SSerge E. Hallyn static int selinux_inode_killpriv(struct dentry *dentry) 2904b5376771SSerge E. Hallyn { 2905b5376771SSerge E. Hallyn return secondary_ops->inode_killpriv(dentry); 2906b5376771SSerge E. Hallyn } 2907b5376771SSerge E. Hallyn 2908713a04aeSAhmed S. Darwish static void selinux_inode_getsecid(const struct inode *inode, u32 *secid) 2909713a04aeSAhmed S. Darwish { 2910713a04aeSAhmed S. Darwish struct inode_security_struct *isec = inode->i_security; 2911713a04aeSAhmed S. Darwish *secid = isec->sid; 2912713a04aeSAhmed S. Darwish } 2913713a04aeSAhmed S. Darwish 29141da177e4SLinus Torvalds /* file security operations */ 29151da177e4SLinus Torvalds 2916788e7dd4SYuichi Nakamura static int selinux_revalidate_file_permission(struct file *file, int mask) 29171da177e4SLinus Torvalds { 29187420ed23SVenkat Yekkirala int rc; 29193d5ff529SJosef Sipek struct inode *inode = file->f_path.dentry->d_inode; 29201da177e4SLinus Torvalds 29211da177e4SLinus Torvalds if (!mask) { 29221da177e4SLinus Torvalds /* No permission to check. Existence test. */ 29231da177e4SLinus Torvalds return 0; 29241da177e4SLinus Torvalds } 29251da177e4SLinus Torvalds 29261da177e4SLinus Torvalds /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */ 29271da177e4SLinus Torvalds if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) 29281da177e4SLinus Torvalds mask |= MAY_APPEND; 29291da177e4SLinus Torvalds 29307420ed23SVenkat Yekkirala rc = file_has_perm(current, file, 29311da177e4SLinus Torvalds file_mask_to_av(inode->i_mode, mask)); 29327420ed23SVenkat Yekkirala if (rc) 29337420ed23SVenkat Yekkirala return rc; 29347420ed23SVenkat Yekkirala 29357420ed23SVenkat Yekkirala return selinux_netlbl_inode_permission(inode, mask); 29361da177e4SLinus Torvalds } 29371da177e4SLinus Torvalds 2938788e7dd4SYuichi Nakamura static int selinux_file_permission(struct file *file, int mask) 2939788e7dd4SYuichi Nakamura { 2940788e7dd4SYuichi Nakamura struct inode *inode = file->f_path.dentry->d_inode; 2941788e7dd4SYuichi Nakamura struct file_security_struct *fsec = file->f_security; 2942788e7dd4SYuichi Nakamura struct inode_security_struct *isec = inode->i_security; 2943*275bb41eSDavid Howells u32 sid = current_sid(); 2944788e7dd4SYuichi Nakamura 2945788e7dd4SYuichi Nakamura if (!mask) { 2946788e7dd4SYuichi Nakamura /* No permission to check. Existence test. */ 2947788e7dd4SYuichi Nakamura return 0; 2948788e7dd4SYuichi Nakamura } 2949788e7dd4SYuichi Nakamura 2950*275bb41eSDavid Howells if (sid == fsec->sid && fsec->isid == isec->sid 2951788e7dd4SYuichi Nakamura && fsec->pseqno == avc_policy_seqno()) 2952788e7dd4SYuichi Nakamura return selinux_netlbl_inode_permission(inode, mask); 2953788e7dd4SYuichi Nakamura 2954788e7dd4SYuichi Nakamura return selinux_revalidate_file_permission(file, mask); 2955788e7dd4SYuichi Nakamura } 2956788e7dd4SYuichi Nakamura 29571da177e4SLinus Torvalds static int selinux_file_alloc_security(struct file *file) 29581da177e4SLinus Torvalds { 29591da177e4SLinus Torvalds return file_alloc_security(file); 29601da177e4SLinus Torvalds } 29611da177e4SLinus Torvalds 29621da177e4SLinus Torvalds static void selinux_file_free_security(struct file *file) 29631da177e4SLinus Torvalds { 29641da177e4SLinus Torvalds file_free_security(file); 29651da177e4SLinus Torvalds } 29661da177e4SLinus Torvalds 29671da177e4SLinus Torvalds static int selinux_file_ioctl(struct file *file, unsigned int cmd, 29681da177e4SLinus Torvalds unsigned long arg) 29691da177e4SLinus Torvalds { 2970242631c4SStephen Smalley u32 av = 0; 29711da177e4SLinus Torvalds 2972242631c4SStephen Smalley if (_IOC_DIR(cmd) & _IOC_WRITE) 2973242631c4SStephen Smalley av |= FILE__WRITE; 2974242631c4SStephen Smalley if (_IOC_DIR(cmd) & _IOC_READ) 2975242631c4SStephen Smalley av |= FILE__READ; 2976242631c4SStephen Smalley if (!av) 2977242631c4SStephen Smalley av = FILE__IOCTL; 29781da177e4SLinus Torvalds 2979242631c4SStephen Smalley return file_has_perm(current, file, av); 29801da177e4SLinus Torvalds } 29811da177e4SLinus Torvalds 29821da177e4SLinus Torvalds static int file_map_prot_check(struct file *file, unsigned long prot, int shared) 29831da177e4SLinus Torvalds { 29841da177e4SLinus Torvalds #ifndef CONFIG_PPC32 29851da177e4SLinus Torvalds if ((prot & PROT_EXEC) && (!file || (!shared && (prot & PROT_WRITE)))) { 29861da177e4SLinus Torvalds /* 29871da177e4SLinus Torvalds * We are making executable an anonymous mapping or a 29881da177e4SLinus Torvalds * private file mapping that will also be writable. 29891da177e4SLinus Torvalds * This has an additional check. 29901da177e4SLinus Torvalds */ 29911da177e4SLinus Torvalds int rc = task_has_perm(current, current, PROCESS__EXECMEM); 29921da177e4SLinus Torvalds if (rc) 29931da177e4SLinus Torvalds return rc; 29941da177e4SLinus Torvalds } 29951da177e4SLinus Torvalds #endif 29961da177e4SLinus Torvalds 29971da177e4SLinus Torvalds if (file) { 29981da177e4SLinus Torvalds /* read access is always possible with a mapping */ 29991da177e4SLinus Torvalds u32 av = FILE__READ; 30001da177e4SLinus Torvalds 30011da177e4SLinus Torvalds /* write access only matters if the mapping is shared */ 30021da177e4SLinus Torvalds if (shared && (prot & PROT_WRITE)) 30031da177e4SLinus Torvalds av |= FILE__WRITE; 30041da177e4SLinus Torvalds 30051da177e4SLinus Torvalds if (prot & PROT_EXEC) 30061da177e4SLinus Torvalds av |= FILE__EXECUTE; 30071da177e4SLinus Torvalds 30081da177e4SLinus Torvalds return file_has_perm(current, file, av); 30091da177e4SLinus Torvalds } 30101da177e4SLinus Torvalds return 0; 30111da177e4SLinus Torvalds } 30121da177e4SLinus Torvalds 30131da177e4SLinus Torvalds static int selinux_file_mmap(struct file *file, unsigned long reqprot, 3014ed032189SEric Paris unsigned long prot, unsigned long flags, 3015ed032189SEric Paris unsigned long addr, unsigned long addr_only) 30161da177e4SLinus Torvalds { 3017ed032189SEric Paris int rc = 0; 3018*275bb41eSDavid Howells u32 sid = current_sid(); 30191da177e4SLinus Torvalds 3020ed032189SEric Paris if (addr < mmap_min_addr) 3021ed032189SEric Paris rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT, 3022ed032189SEric Paris MEMPROTECT__MMAP_ZERO, NULL); 3023ed032189SEric Paris if (rc || addr_only) 30241da177e4SLinus Torvalds return rc; 30251da177e4SLinus Torvalds 30261da177e4SLinus Torvalds if (selinux_checkreqprot) 30271da177e4SLinus Torvalds prot = reqprot; 30281da177e4SLinus Torvalds 30291da177e4SLinus Torvalds return file_map_prot_check(file, prot, 30301da177e4SLinus Torvalds (flags & MAP_TYPE) == MAP_SHARED); 30311da177e4SLinus Torvalds } 30321da177e4SLinus Torvalds 30331da177e4SLinus Torvalds static int selinux_file_mprotect(struct vm_area_struct *vma, 30341da177e4SLinus Torvalds unsigned long reqprot, 30351da177e4SLinus Torvalds unsigned long prot) 30361da177e4SLinus Torvalds { 30371da177e4SLinus Torvalds int rc; 30381da177e4SLinus Torvalds 30391da177e4SLinus Torvalds rc = secondary_ops->file_mprotect(vma, reqprot, prot); 30401da177e4SLinus Torvalds if (rc) 30411da177e4SLinus Torvalds return rc; 30421da177e4SLinus Torvalds 30431da177e4SLinus Torvalds if (selinux_checkreqprot) 30441da177e4SLinus Torvalds prot = reqprot; 30451da177e4SLinus Torvalds 30461da177e4SLinus Torvalds #ifndef CONFIG_PPC32 3047db4c9641SStephen Smalley if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { 3048db4c9641SStephen Smalley rc = 0; 3049db4c9641SStephen Smalley if (vma->vm_start >= vma->vm_mm->start_brk && 3050db4c9641SStephen Smalley vma->vm_end <= vma->vm_mm->brk) { 3051db4c9641SStephen Smalley rc = task_has_perm(current, current, 3052db4c9641SStephen Smalley PROCESS__EXECHEAP); 3053db4c9641SStephen Smalley } else if (!vma->vm_file && 30546b992197SLorenzo Hernandez García-Hierro vma->vm_start <= vma->vm_mm->start_stack && 30556b992197SLorenzo Hernandez García-Hierro vma->vm_end >= vma->vm_mm->start_stack) { 30566b992197SLorenzo Hernandez García-Hierro rc = task_has_perm(current, current, PROCESS__EXECSTACK); 3057db4c9641SStephen Smalley } else if (vma->vm_file && vma->anon_vma) { 3058db4c9641SStephen Smalley /* 3059db4c9641SStephen Smalley * We are making executable a file mapping that has 3060db4c9641SStephen Smalley * had some COW done. Since pages might have been 3061db4c9641SStephen Smalley * written, check ability to execute the possibly 3062db4c9641SStephen Smalley * modified content. This typically should only 3063db4c9641SStephen Smalley * occur for text relocations. 3064db4c9641SStephen Smalley */ 3065db4c9641SStephen Smalley rc = file_has_perm(current, vma->vm_file, 3066db4c9641SStephen Smalley FILE__EXECMOD); 3067db4c9641SStephen Smalley } 30686b992197SLorenzo Hernandez García-Hierro if (rc) 30696b992197SLorenzo Hernandez García-Hierro return rc; 30706b992197SLorenzo Hernandez García-Hierro } 30711da177e4SLinus Torvalds #endif 30721da177e4SLinus Torvalds 30731da177e4SLinus Torvalds return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); 30741da177e4SLinus Torvalds } 30751da177e4SLinus Torvalds 30761da177e4SLinus Torvalds static int selinux_file_lock(struct file *file, unsigned int cmd) 30771da177e4SLinus Torvalds { 30781da177e4SLinus Torvalds return file_has_perm(current, file, FILE__LOCK); 30791da177e4SLinus Torvalds } 30801da177e4SLinus Torvalds 30811da177e4SLinus Torvalds static int selinux_file_fcntl(struct file *file, unsigned int cmd, 30821da177e4SLinus Torvalds unsigned long arg) 30831da177e4SLinus Torvalds { 30841da177e4SLinus Torvalds int err = 0; 30851da177e4SLinus Torvalds 30861da177e4SLinus Torvalds switch (cmd) { 30871da177e4SLinus Torvalds case F_SETFL: 30883d5ff529SJosef Sipek if (!file->f_path.dentry || !file->f_path.dentry->d_inode) { 30891da177e4SLinus Torvalds err = -EINVAL; 30901da177e4SLinus Torvalds break; 30911da177e4SLinus Torvalds } 30921da177e4SLinus Torvalds 30931da177e4SLinus Torvalds if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) { 30941da177e4SLinus Torvalds err = file_has_perm(current, file, FILE__WRITE); 30951da177e4SLinus Torvalds break; 30961da177e4SLinus Torvalds } 30971da177e4SLinus Torvalds /* fall through */ 30981da177e4SLinus Torvalds case F_SETOWN: 30991da177e4SLinus Torvalds case F_SETSIG: 31001da177e4SLinus Torvalds case F_GETFL: 31011da177e4SLinus Torvalds case F_GETOWN: 31021da177e4SLinus Torvalds case F_GETSIG: 31031da177e4SLinus Torvalds /* Just check FD__USE permission */ 31041da177e4SLinus Torvalds err = file_has_perm(current, file, 0); 31051da177e4SLinus Torvalds break; 31061da177e4SLinus Torvalds case F_GETLK: 31071da177e4SLinus Torvalds case F_SETLK: 31081da177e4SLinus Torvalds case F_SETLKW: 31091da177e4SLinus Torvalds #if BITS_PER_LONG == 32 31101da177e4SLinus Torvalds case F_GETLK64: 31111da177e4SLinus Torvalds case F_SETLK64: 31121da177e4SLinus Torvalds case F_SETLKW64: 31131da177e4SLinus Torvalds #endif 31143d5ff529SJosef Sipek if (!file->f_path.dentry || !file->f_path.dentry->d_inode) { 31151da177e4SLinus Torvalds err = -EINVAL; 31161da177e4SLinus Torvalds break; 31171da177e4SLinus Torvalds } 31181da177e4SLinus Torvalds err = file_has_perm(current, file, FILE__LOCK); 31191da177e4SLinus Torvalds break; 31201da177e4SLinus Torvalds } 31211da177e4SLinus Torvalds 31221da177e4SLinus Torvalds return err; 31231da177e4SLinus Torvalds } 31241da177e4SLinus Torvalds 31251da177e4SLinus Torvalds static int selinux_file_set_fowner(struct file *file) 31261da177e4SLinus Torvalds { 31271da177e4SLinus Torvalds struct file_security_struct *fsec; 31281da177e4SLinus Torvalds 31291da177e4SLinus Torvalds fsec = file->f_security; 3130*275bb41eSDavid Howells fsec->fown_sid = current_sid(); 31311da177e4SLinus Torvalds 31321da177e4SLinus Torvalds return 0; 31331da177e4SLinus Torvalds } 31341da177e4SLinus Torvalds 31351da177e4SLinus Torvalds static int selinux_file_send_sigiotask(struct task_struct *tsk, 31361da177e4SLinus Torvalds struct fown_struct *fown, int signum) 31371da177e4SLinus Torvalds { 31381da177e4SLinus Torvalds struct file *file; 3139*275bb41eSDavid Howells u32 sid = current_sid(); 31401da177e4SLinus Torvalds u32 perm; 31411da177e4SLinus Torvalds struct file_security_struct *fsec; 31421da177e4SLinus Torvalds 31431da177e4SLinus Torvalds /* struct fown_struct is never outside the context of a struct file */ 3144b385a144SRobert P. J. Day file = container_of(fown, struct file, f_owner); 31451da177e4SLinus Torvalds 31461da177e4SLinus Torvalds fsec = file->f_security; 31471da177e4SLinus Torvalds 31481da177e4SLinus Torvalds if (!signum) 31491da177e4SLinus Torvalds perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */ 31501da177e4SLinus Torvalds else 31511da177e4SLinus Torvalds perm = signal_to_av(signum); 31521da177e4SLinus Torvalds 3153*275bb41eSDavid Howells return avc_has_perm(fsec->fown_sid, sid, 31541da177e4SLinus Torvalds SECCLASS_PROCESS, perm, NULL); 31551da177e4SLinus Torvalds } 31561da177e4SLinus Torvalds 31571da177e4SLinus Torvalds static int selinux_file_receive(struct file *file) 31581da177e4SLinus Torvalds { 31591da177e4SLinus Torvalds return file_has_perm(current, file, file_to_av(file)); 31601da177e4SLinus Torvalds } 31611da177e4SLinus Torvalds 3162788e7dd4SYuichi Nakamura static int selinux_dentry_open(struct file *file) 3163788e7dd4SYuichi Nakamura { 3164788e7dd4SYuichi Nakamura struct file_security_struct *fsec; 3165788e7dd4SYuichi Nakamura struct inode *inode; 3166788e7dd4SYuichi Nakamura struct inode_security_struct *isec; 3167788e7dd4SYuichi Nakamura inode = file->f_path.dentry->d_inode; 3168788e7dd4SYuichi Nakamura fsec = file->f_security; 3169788e7dd4SYuichi Nakamura isec = inode->i_security; 3170788e7dd4SYuichi Nakamura /* 3171788e7dd4SYuichi Nakamura * Save inode label and policy sequence number 3172788e7dd4SYuichi Nakamura * at open-time so that selinux_file_permission 3173788e7dd4SYuichi Nakamura * can determine whether revalidation is necessary. 3174788e7dd4SYuichi Nakamura * Task label is already saved in the file security 3175788e7dd4SYuichi Nakamura * struct as its SID. 3176788e7dd4SYuichi Nakamura */ 3177788e7dd4SYuichi Nakamura fsec->isid = isec->sid; 3178788e7dd4SYuichi Nakamura fsec->pseqno = avc_policy_seqno(); 3179788e7dd4SYuichi Nakamura /* 3180788e7dd4SYuichi Nakamura * Since the inode label or policy seqno may have changed 3181788e7dd4SYuichi Nakamura * between the selinux_inode_permission check and the saving 3182788e7dd4SYuichi Nakamura * of state above, recheck that access is still permitted. 3183788e7dd4SYuichi Nakamura * Otherwise, access might never be revalidated against the 3184788e7dd4SYuichi Nakamura * new inode label or new policy. 3185788e7dd4SYuichi Nakamura * This check is not redundant - do not remove. 3186788e7dd4SYuichi Nakamura */ 31878b6a5a37SEric Paris return inode_has_perm(current, inode, open_file_to_av(file), NULL); 3188788e7dd4SYuichi Nakamura } 3189788e7dd4SYuichi Nakamura 31901da177e4SLinus Torvalds /* task security operations */ 31911da177e4SLinus Torvalds 31921da177e4SLinus Torvalds static int selinux_task_create(unsigned long clone_flags) 31931da177e4SLinus Torvalds { 31941da177e4SLinus Torvalds int rc; 31951da177e4SLinus Torvalds 31961da177e4SLinus Torvalds rc = secondary_ops->task_create(clone_flags); 31971da177e4SLinus Torvalds if (rc) 31981da177e4SLinus Torvalds return rc; 31991da177e4SLinus Torvalds 32001da177e4SLinus Torvalds return task_has_perm(current, current, PROCESS__FORK); 32011da177e4SLinus Torvalds } 32021da177e4SLinus Torvalds 3203f1752eecSDavid Howells static int selinux_cred_alloc_security(struct cred *cred) 32041da177e4SLinus Torvalds { 32051da177e4SLinus Torvalds struct task_security_struct *tsec1, *tsec2; 32061da177e4SLinus Torvalds int rc; 32071da177e4SLinus Torvalds 3208*275bb41eSDavid Howells tsec1 = current_security(); 32091da177e4SLinus Torvalds 3210f1752eecSDavid Howells rc = cred_alloc_security(cred); 32111da177e4SLinus Torvalds if (rc) 32121da177e4SLinus Torvalds return rc; 3213f1752eecSDavid Howells tsec2 = cred->security; 32141da177e4SLinus Torvalds 32151da177e4SLinus Torvalds tsec2->osid = tsec1->osid; 32161da177e4SLinus Torvalds tsec2->sid = tsec1->sid; 32171da177e4SLinus Torvalds 321828eba5bfSMichael LeMay /* Retain the exec, fs, key, and sock SIDs across fork */ 32191da177e4SLinus Torvalds tsec2->exec_sid = tsec1->exec_sid; 32201da177e4SLinus Torvalds tsec2->create_sid = tsec1->create_sid; 322128eba5bfSMichael LeMay tsec2->keycreate_sid = tsec1->keycreate_sid; 322242c3e03eSEric Paris tsec2->sockcreate_sid = tsec1->sockcreate_sid; 32231da177e4SLinus Torvalds 32241da177e4SLinus Torvalds return 0; 32251da177e4SLinus Torvalds } 32261da177e4SLinus Torvalds 3227f1752eecSDavid Howells /* 3228f1752eecSDavid Howells * detach and free the LSM part of a set of credentials 3229f1752eecSDavid Howells */ 3230f1752eecSDavid Howells static void selinux_cred_free(struct cred *cred) 32311da177e4SLinus Torvalds { 3232f1752eecSDavid Howells struct task_security_struct *tsec = cred->security; 3233f1752eecSDavid Howells cred->security = NULL; 3234f1752eecSDavid Howells kfree(tsec); 32351da177e4SLinus Torvalds } 32361da177e4SLinus Torvalds 32371da177e4SLinus Torvalds static int selinux_task_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) 32381da177e4SLinus Torvalds { 32391da177e4SLinus Torvalds /* Since setuid only affects the current process, and 32401da177e4SLinus Torvalds since the SELinux controls are not based on the Linux 32411da177e4SLinus Torvalds identity attributes, SELinux does not need to control 32421da177e4SLinus Torvalds this operation. However, SELinux does control the use 32431da177e4SLinus Torvalds of the CAP_SETUID and CAP_SETGID capabilities using the 32441da177e4SLinus Torvalds capable hook. */ 32451da177e4SLinus Torvalds return 0; 32461da177e4SLinus Torvalds } 32471da177e4SLinus Torvalds 32481da177e4SLinus Torvalds static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags) 32491da177e4SLinus Torvalds { 32501da177e4SLinus Torvalds return secondary_ops->task_post_setuid(id0, id1, id2, flags); 32511da177e4SLinus Torvalds } 32521da177e4SLinus Torvalds 32531da177e4SLinus Torvalds static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags) 32541da177e4SLinus Torvalds { 32551da177e4SLinus Torvalds /* See the comment for setuid above. */ 32561da177e4SLinus Torvalds return 0; 32571da177e4SLinus Torvalds } 32581da177e4SLinus Torvalds 32591da177e4SLinus Torvalds static int selinux_task_setpgid(struct task_struct *p, pid_t pgid) 32601da177e4SLinus Torvalds { 32611da177e4SLinus Torvalds return task_has_perm(current, p, PROCESS__SETPGID); 32621da177e4SLinus Torvalds } 32631da177e4SLinus Torvalds 32641da177e4SLinus Torvalds static int selinux_task_getpgid(struct task_struct *p) 32651da177e4SLinus Torvalds { 32661da177e4SLinus Torvalds return task_has_perm(current, p, PROCESS__GETPGID); 32671da177e4SLinus Torvalds } 32681da177e4SLinus Torvalds 32691da177e4SLinus Torvalds static int selinux_task_getsid(struct task_struct *p) 32701da177e4SLinus Torvalds { 32711da177e4SLinus Torvalds return task_has_perm(current, p, PROCESS__GETSESSION); 32721da177e4SLinus Torvalds } 32731da177e4SLinus Torvalds 3274f9008e4cSDavid Quigley static void selinux_task_getsecid(struct task_struct *p, u32 *secid) 3275f9008e4cSDavid Quigley { 3276*275bb41eSDavid Howells *secid = task_sid(p); 3277f9008e4cSDavid Quigley } 3278f9008e4cSDavid Quigley 32791da177e4SLinus Torvalds static int selinux_task_setgroups(struct group_info *group_info) 32801da177e4SLinus Torvalds { 32811da177e4SLinus Torvalds /* See the comment for setuid above. */ 32821da177e4SLinus Torvalds return 0; 32831da177e4SLinus Torvalds } 32841da177e4SLinus Torvalds 32851da177e4SLinus Torvalds static int selinux_task_setnice(struct task_struct *p, int nice) 32861da177e4SLinus Torvalds { 32871da177e4SLinus Torvalds int rc; 32881da177e4SLinus Torvalds 32891da177e4SLinus Torvalds rc = secondary_ops->task_setnice(p, nice); 32901da177e4SLinus Torvalds if (rc) 32911da177e4SLinus Torvalds return rc; 32921da177e4SLinus Torvalds 32931da177e4SLinus Torvalds return task_has_perm(current, p, PROCESS__SETSCHED); 32941da177e4SLinus Torvalds } 32951da177e4SLinus Torvalds 329603e68060SJames Morris static int selinux_task_setioprio(struct task_struct *p, int ioprio) 329703e68060SJames Morris { 3298b5376771SSerge E. Hallyn int rc; 3299b5376771SSerge E. Hallyn 3300b5376771SSerge E. Hallyn rc = secondary_ops->task_setioprio(p, ioprio); 3301b5376771SSerge E. Hallyn if (rc) 3302b5376771SSerge E. Hallyn return rc; 3303b5376771SSerge E. Hallyn 330403e68060SJames Morris return task_has_perm(current, p, PROCESS__SETSCHED); 330503e68060SJames Morris } 330603e68060SJames Morris 3307a1836a42SDavid Quigley static int selinux_task_getioprio(struct task_struct *p) 3308a1836a42SDavid Quigley { 3309a1836a42SDavid Quigley return task_has_perm(current, p, PROCESS__GETSCHED); 3310a1836a42SDavid Quigley } 3311a1836a42SDavid Quigley 33121da177e4SLinus Torvalds static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim) 33131da177e4SLinus Torvalds { 33141da177e4SLinus Torvalds struct rlimit *old_rlim = current->signal->rlim + resource; 33151da177e4SLinus Torvalds int rc; 33161da177e4SLinus Torvalds 33171da177e4SLinus Torvalds rc = secondary_ops->task_setrlimit(resource, new_rlim); 33181da177e4SLinus Torvalds if (rc) 33191da177e4SLinus Torvalds return rc; 33201da177e4SLinus Torvalds 33211da177e4SLinus Torvalds /* Control the ability to change the hard limit (whether 33221da177e4SLinus Torvalds lowering or raising it), so that the hard limit can 33231da177e4SLinus Torvalds later be used as a safe reset point for the soft limit 33241da177e4SLinus Torvalds upon context transitions. See selinux_bprm_apply_creds. */ 33251da177e4SLinus Torvalds if (old_rlim->rlim_max != new_rlim->rlim_max) 33261da177e4SLinus Torvalds return task_has_perm(current, current, PROCESS__SETRLIMIT); 33271da177e4SLinus Torvalds 33281da177e4SLinus Torvalds return 0; 33291da177e4SLinus Torvalds } 33301da177e4SLinus Torvalds 33311da177e4SLinus Torvalds static int selinux_task_setscheduler(struct task_struct *p, int policy, struct sched_param *lp) 33321da177e4SLinus Torvalds { 3333b5376771SSerge E. Hallyn int rc; 3334b5376771SSerge E. Hallyn 3335b5376771SSerge E. Hallyn rc = secondary_ops->task_setscheduler(p, policy, lp); 3336b5376771SSerge E. Hallyn if (rc) 3337b5376771SSerge E. Hallyn return rc; 3338b5376771SSerge E. Hallyn 33391da177e4SLinus Torvalds return task_has_perm(current, p, PROCESS__SETSCHED); 33401da177e4SLinus Torvalds } 33411da177e4SLinus Torvalds 33421da177e4SLinus Torvalds static int selinux_task_getscheduler(struct task_struct *p) 33431da177e4SLinus Torvalds { 33441da177e4SLinus Torvalds return task_has_perm(current, p, PROCESS__GETSCHED); 33451da177e4SLinus Torvalds } 33461da177e4SLinus Torvalds 334735601547SDavid Quigley static int selinux_task_movememory(struct task_struct *p) 334835601547SDavid Quigley { 334935601547SDavid Quigley return task_has_perm(current, p, PROCESS__SETSCHED); 335035601547SDavid Quigley } 335135601547SDavid Quigley 3352f9008e4cSDavid Quigley static int selinux_task_kill(struct task_struct *p, struct siginfo *info, 3353f9008e4cSDavid Quigley int sig, u32 secid) 33541da177e4SLinus Torvalds { 33551da177e4SLinus Torvalds u32 perm; 33561da177e4SLinus Torvalds int rc; 33571da177e4SLinus Torvalds 3358f9008e4cSDavid Quigley rc = secondary_ops->task_kill(p, info, sig, secid); 33591da177e4SLinus Torvalds if (rc) 33601da177e4SLinus Torvalds return rc; 33611da177e4SLinus Torvalds 33621da177e4SLinus Torvalds if (!sig) 33631da177e4SLinus Torvalds perm = PROCESS__SIGNULL; /* null signal; existence test */ 33641da177e4SLinus Torvalds else 33651da177e4SLinus Torvalds perm = signal_to_av(sig); 3366f9008e4cSDavid Quigley if (secid) 3367*275bb41eSDavid Howells rc = avc_has_perm(secid, task_sid(p), 3368*275bb41eSDavid Howells SECCLASS_PROCESS, perm, NULL); 3369f9008e4cSDavid Quigley else 3370f9008e4cSDavid Quigley rc = task_has_perm(current, p, perm); 3371f9008e4cSDavid Quigley return rc; 33721da177e4SLinus Torvalds } 33731da177e4SLinus Torvalds 33741da177e4SLinus Torvalds static int selinux_task_prctl(int option, 33751da177e4SLinus Torvalds unsigned long arg2, 33761da177e4SLinus Torvalds unsigned long arg3, 33771da177e4SLinus Torvalds unsigned long arg4, 33783898b1b4SAndrew G. Morgan unsigned long arg5, 33793898b1b4SAndrew G. Morgan long *rc_p) 33801da177e4SLinus Torvalds { 33811da177e4SLinus Torvalds /* The current prctl operations do not appear to require 33821da177e4SLinus Torvalds any SELinux controls since they merely observe or modify 33831da177e4SLinus Torvalds the state of the current process. */ 33843898b1b4SAndrew G. Morgan return secondary_ops->task_prctl(option, arg2, arg3, arg4, arg5, rc_p); 33851da177e4SLinus Torvalds } 33861da177e4SLinus Torvalds 33871da177e4SLinus Torvalds static int selinux_task_wait(struct task_struct *p) 33881da177e4SLinus Torvalds { 33898a535140SEric Paris return task_has_perm(p, current, PROCESS__SIGCHLD); 33901da177e4SLinus Torvalds } 33911da177e4SLinus Torvalds 33921da177e4SLinus Torvalds static void selinux_task_reparent_to_init(struct task_struct *p) 33931da177e4SLinus Torvalds { 33941da177e4SLinus Torvalds struct task_security_struct *tsec; 33951da177e4SLinus Torvalds 33961da177e4SLinus Torvalds secondary_ops->task_reparent_to_init(p); 33971da177e4SLinus Torvalds 3398b6dff3ecSDavid Howells tsec = p->cred->security; 33991da177e4SLinus Torvalds tsec->osid = tsec->sid; 34001da177e4SLinus Torvalds tsec->sid = SECINITSID_KERNEL; 34011da177e4SLinus Torvalds return; 34021da177e4SLinus Torvalds } 34031da177e4SLinus Torvalds 34041da177e4SLinus Torvalds static void selinux_task_to_inode(struct task_struct *p, 34051da177e4SLinus Torvalds struct inode *inode) 34061da177e4SLinus Torvalds { 34071da177e4SLinus Torvalds struct inode_security_struct *isec = inode->i_security; 3408*275bb41eSDavid Howells u32 sid = task_sid(p); 34091da177e4SLinus Torvalds 3410*275bb41eSDavid Howells isec->sid = sid; 34111da177e4SLinus Torvalds isec->initialized = 1; 34121da177e4SLinus Torvalds } 34131da177e4SLinus Torvalds 34141da177e4SLinus Torvalds /* Returns error only if unable to parse addresses */ 341567f83cbfSVenkat Yekkirala static int selinux_parse_skb_ipv4(struct sk_buff *skb, 341667f83cbfSVenkat Yekkirala struct avc_audit_data *ad, u8 *proto) 34171da177e4SLinus Torvalds { 34181da177e4SLinus Torvalds int offset, ihlen, ret = -EINVAL; 34191da177e4SLinus Torvalds struct iphdr _iph, *ih; 34201da177e4SLinus Torvalds 3421bbe735e4SArnaldo Carvalho de Melo offset = skb_network_offset(skb); 34221da177e4SLinus Torvalds ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); 34231da177e4SLinus Torvalds if (ih == NULL) 34241da177e4SLinus Torvalds goto out; 34251da177e4SLinus Torvalds 34261da177e4SLinus Torvalds ihlen = ih->ihl * 4; 34271da177e4SLinus Torvalds if (ihlen < sizeof(_iph)) 34281da177e4SLinus Torvalds goto out; 34291da177e4SLinus Torvalds 34301da177e4SLinus Torvalds ad->u.net.v4info.saddr = ih->saddr; 34311da177e4SLinus Torvalds ad->u.net.v4info.daddr = ih->daddr; 34321da177e4SLinus Torvalds ret = 0; 34331da177e4SLinus Torvalds 343467f83cbfSVenkat Yekkirala if (proto) 343567f83cbfSVenkat Yekkirala *proto = ih->protocol; 343667f83cbfSVenkat Yekkirala 34371da177e4SLinus Torvalds switch (ih->protocol) { 34381da177e4SLinus Torvalds case IPPROTO_TCP: { 34391da177e4SLinus Torvalds struct tcphdr _tcph, *th; 34401da177e4SLinus Torvalds 34411da177e4SLinus Torvalds if (ntohs(ih->frag_off) & IP_OFFSET) 34421da177e4SLinus Torvalds break; 34431da177e4SLinus Torvalds 34441da177e4SLinus Torvalds offset += ihlen; 34451da177e4SLinus Torvalds th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); 34461da177e4SLinus Torvalds if (th == NULL) 34471da177e4SLinus Torvalds break; 34481da177e4SLinus Torvalds 34491da177e4SLinus Torvalds ad->u.net.sport = th->source; 34501da177e4SLinus Torvalds ad->u.net.dport = th->dest; 34511da177e4SLinus Torvalds break; 34521da177e4SLinus Torvalds } 34531da177e4SLinus Torvalds 34541da177e4SLinus Torvalds case IPPROTO_UDP: { 34551da177e4SLinus Torvalds struct udphdr _udph, *uh; 34561da177e4SLinus Torvalds 34571da177e4SLinus Torvalds if (ntohs(ih->frag_off) & IP_OFFSET) 34581da177e4SLinus Torvalds break; 34591da177e4SLinus Torvalds 34601da177e4SLinus Torvalds offset += ihlen; 34611da177e4SLinus Torvalds uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); 34621da177e4SLinus Torvalds if (uh == NULL) 34631da177e4SLinus Torvalds break; 34641da177e4SLinus Torvalds 34651da177e4SLinus Torvalds ad->u.net.sport = uh->source; 34661da177e4SLinus Torvalds ad->u.net.dport = uh->dest; 34671da177e4SLinus Torvalds break; 34681da177e4SLinus Torvalds } 34691da177e4SLinus Torvalds 34702ee92d46SJames Morris case IPPROTO_DCCP: { 34712ee92d46SJames Morris struct dccp_hdr _dccph, *dh; 34722ee92d46SJames Morris 34732ee92d46SJames Morris if (ntohs(ih->frag_off) & IP_OFFSET) 34742ee92d46SJames Morris break; 34752ee92d46SJames Morris 34762ee92d46SJames Morris offset += ihlen; 34772ee92d46SJames Morris dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); 34782ee92d46SJames Morris if (dh == NULL) 34792ee92d46SJames Morris break; 34802ee92d46SJames Morris 34812ee92d46SJames Morris ad->u.net.sport = dh->dccph_sport; 34822ee92d46SJames Morris ad->u.net.dport = dh->dccph_dport; 34832ee92d46SJames Morris break; 34842ee92d46SJames Morris } 34852ee92d46SJames Morris 34861da177e4SLinus Torvalds default: 34871da177e4SLinus Torvalds break; 34881da177e4SLinus Torvalds } 34891da177e4SLinus Torvalds out: 34901da177e4SLinus Torvalds return ret; 34911da177e4SLinus Torvalds } 34921da177e4SLinus Torvalds 34931da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 34941da177e4SLinus Torvalds 34951da177e4SLinus Torvalds /* Returns error only if unable to parse addresses */ 349667f83cbfSVenkat Yekkirala static int selinux_parse_skb_ipv6(struct sk_buff *skb, 349767f83cbfSVenkat Yekkirala struct avc_audit_data *ad, u8 *proto) 34981da177e4SLinus Torvalds { 34991da177e4SLinus Torvalds u8 nexthdr; 35001da177e4SLinus Torvalds int ret = -EINVAL, offset; 35011da177e4SLinus Torvalds struct ipv6hdr _ipv6h, *ip6; 35021da177e4SLinus Torvalds 3503bbe735e4SArnaldo Carvalho de Melo offset = skb_network_offset(skb); 35041da177e4SLinus Torvalds ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h); 35051da177e4SLinus Torvalds if (ip6 == NULL) 35061da177e4SLinus Torvalds goto out; 35071da177e4SLinus Torvalds 35081da177e4SLinus Torvalds ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr); 35091da177e4SLinus Torvalds ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr); 35101da177e4SLinus Torvalds ret = 0; 35111da177e4SLinus Torvalds 35121da177e4SLinus Torvalds nexthdr = ip6->nexthdr; 35131da177e4SLinus Torvalds offset += sizeof(_ipv6h); 35140d3d077cSHerbert Xu offset = ipv6_skip_exthdr(skb, offset, &nexthdr); 35151da177e4SLinus Torvalds if (offset < 0) 35161da177e4SLinus Torvalds goto out; 35171da177e4SLinus Torvalds 351867f83cbfSVenkat Yekkirala if (proto) 351967f83cbfSVenkat Yekkirala *proto = nexthdr; 352067f83cbfSVenkat Yekkirala 35211da177e4SLinus Torvalds switch (nexthdr) { 35221da177e4SLinus Torvalds case IPPROTO_TCP: { 35231da177e4SLinus Torvalds struct tcphdr _tcph, *th; 35241da177e4SLinus Torvalds 35251da177e4SLinus Torvalds th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); 35261da177e4SLinus Torvalds if (th == NULL) 35271da177e4SLinus Torvalds break; 35281da177e4SLinus Torvalds 35291da177e4SLinus Torvalds ad->u.net.sport = th->source; 35301da177e4SLinus Torvalds ad->u.net.dport = th->dest; 35311da177e4SLinus Torvalds break; 35321da177e4SLinus Torvalds } 35331da177e4SLinus Torvalds 35341da177e4SLinus Torvalds case IPPROTO_UDP: { 35351da177e4SLinus Torvalds struct udphdr _udph, *uh; 35361da177e4SLinus Torvalds 35371da177e4SLinus Torvalds uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); 35381da177e4SLinus Torvalds if (uh == NULL) 35391da177e4SLinus Torvalds break; 35401da177e4SLinus Torvalds 35411da177e4SLinus Torvalds ad->u.net.sport = uh->source; 35421da177e4SLinus Torvalds ad->u.net.dport = uh->dest; 35431da177e4SLinus Torvalds break; 35441da177e4SLinus Torvalds } 35451da177e4SLinus Torvalds 35462ee92d46SJames Morris case IPPROTO_DCCP: { 35472ee92d46SJames Morris struct dccp_hdr _dccph, *dh; 35482ee92d46SJames Morris 35492ee92d46SJames Morris dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); 35502ee92d46SJames Morris if (dh == NULL) 35512ee92d46SJames Morris break; 35522ee92d46SJames Morris 35532ee92d46SJames Morris ad->u.net.sport = dh->dccph_sport; 35542ee92d46SJames Morris ad->u.net.dport = dh->dccph_dport; 35552ee92d46SJames Morris break; 35562ee92d46SJames Morris } 35572ee92d46SJames Morris 35581da177e4SLinus Torvalds /* includes fragments */ 35591da177e4SLinus Torvalds default: 35601da177e4SLinus Torvalds break; 35611da177e4SLinus Torvalds } 35621da177e4SLinus Torvalds out: 35631da177e4SLinus Torvalds return ret; 35641da177e4SLinus Torvalds } 35651da177e4SLinus Torvalds 35661da177e4SLinus Torvalds #endif /* IPV6 */ 35671da177e4SLinus Torvalds 35681da177e4SLinus Torvalds static int selinux_parse_skb(struct sk_buff *skb, struct avc_audit_data *ad, 3569cf9481e2SDavid Howells char **_addrp, int src, u8 *proto) 35701da177e4SLinus Torvalds { 3571cf9481e2SDavid Howells char *addrp; 3572cf9481e2SDavid Howells int ret; 35731da177e4SLinus Torvalds 35741da177e4SLinus Torvalds switch (ad->u.net.family) { 35751da177e4SLinus Torvalds case PF_INET: 357667f83cbfSVenkat Yekkirala ret = selinux_parse_skb_ipv4(skb, ad, proto); 3577cf9481e2SDavid Howells if (ret) 3578cf9481e2SDavid Howells goto parse_error; 3579cf9481e2SDavid Howells addrp = (char *)(src ? &ad->u.net.v4info.saddr : 35801da177e4SLinus Torvalds &ad->u.net.v4info.daddr); 3581cf9481e2SDavid Howells goto okay; 35821da177e4SLinus Torvalds 35831da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 35841da177e4SLinus Torvalds case PF_INET6: 358567f83cbfSVenkat Yekkirala ret = selinux_parse_skb_ipv6(skb, ad, proto); 3586cf9481e2SDavid Howells if (ret) 3587cf9481e2SDavid Howells goto parse_error; 3588cf9481e2SDavid Howells addrp = (char *)(src ? &ad->u.net.v6info.saddr : 35891da177e4SLinus Torvalds &ad->u.net.v6info.daddr); 3590cf9481e2SDavid Howells goto okay; 35911da177e4SLinus Torvalds #endif /* IPV6 */ 35921da177e4SLinus Torvalds default: 3593cf9481e2SDavid Howells addrp = NULL; 3594cf9481e2SDavid Howells goto okay; 35951da177e4SLinus Torvalds } 35961da177e4SLinus Torvalds 3597cf9481e2SDavid Howells parse_error: 359871f1cb05SPaul Moore printk(KERN_WARNING 359971f1cb05SPaul Moore "SELinux: failure in selinux_parse_skb()," 360071f1cb05SPaul Moore " unable to parse packet\n"); 36011da177e4SLinus Torvalds return ret; 3602cf9481e2SDavid Howells 3603cf9481e2SDavid Howells okay: 3604cf9481e2SDavid Howells if (_addrp) 3605cf9481e2SDavid Howells *_addrp = addrp; 3606cf9481e2SDavid Howells return 0; 36071da177e4SLinus Torvalds } 36081da177e4SLinus Torvalds 36094f6a993fSPaul Moore /** 3610220deb96SPaul Moore * selinux_skb_peerlbl_sid - Determine the peer label of a packet 36114f6a993fSPaul Moore * @skb: the packet 361275e22910SPaul Moore * @family: protocol family 3613220deb96SPaul Moore * @sid: the packet's peer label SID 36144f6a993fSPaul Moore * 36154f6a993fSPaul Moore * Description: 3616220deb96SPaul Moore * Check the various different forms of network peer labeling and determine 3617220deb96SPaul Moore * the peer label/SID for the packet; most of the magic actually occurs in 3618220deb96SPaul Moore * the security server function security_net_peersid_cmp(). The function 3619220deb96SPaul Moore * returns zero if the value in @sid is valid (although it may be SECSID_NULL) 3620220deb96SPaul Moore * or -EACCES if @sid is invalid due to inconsistencies with the different 3621220deb96SPaul Moore * peer labels. 36224f6a993fSPaul Moore * 36234f6a993fSPaul Moore */ 3624220deb96SPaul Moore static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) 36254f6a993fSPaul Moore { 362671f1cb05SPaul Moore int err; 36274f6a993fSPaul Moore u32 xfrm_sid; 36284f6a993fSPaul Moore u32 nlbl_sid; 3629220deb96SPaul Moore u32 nlbl_type; 36304f6a993fSPaul Moore 36314f6a993fSPaul Moore selinux_skb_xfrm_sid(skb, &xfrm_sid); 36325dbe1eb0SPaul Moore selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid); 3633220deb96SPaul Moore 363471f1cb05SPaul Moore err = security_net_peersid_resolve(nlbl_sid, nlbl_type, xfrm_sid, sid); 363571f1cb05SPaul Moore if (unlikely(err)) { 363671f1cb05SPaul Moore printk(KERN_WARNING 363771f1cb05SPaul Moore "SELinux: failure in selinux_skb_peerlbl_sid()," 363871f1cb05SPaul Moore " unable to determine packet's peer label\n"); 3639220deb96SPaul Moore return -EACCES; 364071f1cb05SPaul Moore } 3641220deb96SPaul Moore 3642220deb96SPaul Moore return 0; 36434f6a993fSPaul Moore } 36444f6a993fSPaul Moore 36451da177e4SLinus Torvalds /* socket security operations */ 36461da177e4SLinus Torvalds static int socket_has_perm(struct task_struct *task, struct socket *sock, 36471da177e4SLinus Torvalds u32 perms) 36481da177e4SLinus Torvalds { 36491da177e4SLinus Torvalds struct inode_security_struct *isec; 36501da177e4SLinus Torvalds struct avc_audit_data ad; 3651*275bb41eSDavid Howells u32 sid; 36521da177e4SLinus Torvalds int err = 0; 36531da177e4SLinus Torvalds 36541da177e4SLinus Torvalds isec = SOCK_INODE(sock)->i_security; 36551da177e4SLinus Torvalds 36561da177e4SLinus Torvalds if (isec->sid == SECINITSID_KERNEL) 36571da177e4SLinus Torvalds goto out; 3658*275bb41eSDavid Howells sid = task_sid(task); 36591da177e4SLinus Torvalds 36601da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, NET); 36611da177e4SLinus Torvalds ad.u.net.sk = sock->sk; 3662*275bb41eSDavid Howells err = avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); 36631da177e4SLinus Torvalds 36641da177e4SLinus Torvalds out: 36651da177e4SLinus Torvalds return err; 36661da177e4SLinus Torvalds } 36671da177e4SLinus Torvalds 36681da177e4SLinus Torvalds static int selinux_socket_create(int family, int type, 36691da177e4SLinus Torvalds int protocol, int kern) 36701da177e4SLinus Torvalds { 3671*275bb41eSDavid Howells const struct cred *cred = current_cred(); 3672*275bb41eSDavid Howells const struct task_security_struct *tsec = cred->security; 3673*275bb41eSDavid Howells u32 sid, newsid; 3674*275bb41eSDavid Howells u16 secclass; 36751da177e4SLinus Torvalds int err = 0; 36761da177e4SLinus Torvalds 36771da177e4SLinus Torvalds if (kern) 36781da177e4SLinus Torvalds goto out; 36791da177e4SLinus Torvalds 3680*275bb41eSDavid Howells sid = tsec->sid; 3681*275bb41eSDavid Howells newsid = tsec->sockcreate_sid ?: sid; 3682*275bb41eSDavid Howells 3683*275bb41eSDavid Howells secclass = socket_type_to_security_class(family, type, protocol); 3684*275bb41eSDavid Howells err = avc_has_perm(sid, newsid, secclass, SOCKET__CREATE, NULL); 36851da177e4SLinus Torvalds 36861da177e4SLinus Torvalds out: 36871da177e4SLinus Torvalds return err; 36881da177e4SLinus Torvalds } 36891da177e4SLinus Torvalds 36907420ed23SVenkat Yekkirala static int selinux_socket_post_create(struct socket *sock, int family, 36911da177e4SLinus Torvalds int type, int protocol, int kern) 36921da177e4SLinus Torvalds { 3693*275bb41eSDavid Howells const struct cred *cred = current_cred(); 3694*275bb41eSDavid Howells const struct task_security_struct *tsec = cred->security; 36951da177e4SLinus Torvalds struct inode_security_struct *isec; 3696892c141eSVenkat Yekkirala struct sk_security_struct *sksec; 3697*275bb41eSDavid Howells u32 sid, newsid; 3698*275bb41eSDavid Howells int err = 0; 3699*275bb41eSDavid Howells 3700*275bb41eSDavid Howells sid = tsec->sid; 3701*275bb41eSDavid Howells newsid = tsec->sockcreate_sid; 37021da177e4SLinus Torvalds 37031da177e4SLinus Torvalds isec = SOCK_INODE(sock)->i_security; 37041da177e4SLinus Torvalds 3705*275bb41eSDavid Howells if (kern) 3706*275bb41eSDavid Howells isec->sid = SECINITSID_KERNEL; 3707*275bb41eSDavid Howells else if (newsid) 3708*275bb41eSDavid Howells isec->sid = newsid; 3709*275bb41eSDavid Howells else 3710*275bb41eSDavid Howells isec->sid = sid; 3711*275bb41eSDavid Howells 37121da177e4SLinus Torvalds isec->sclass = socket_type_to_security_class(family, type, protocol); 37131da177e4SLinus Torvalds isec->initialized = 1; 37141da177e4SLinus Torvalds 3715892c141eSVenkat Yekkirala if (sock->sk) { 3716892c141eSVenkat Yekkirala sksec = sock->sk->sk_security; 3717892c141eSVenkat Yekkirala sksec->sid = isec->sid; 3718220deb96SPaul Moore sksec->sclass = isec->sclass; 37199f2ad665SPaul Moore err = selinux_netlbl_socket_post_create(sock); 3720892c141eSVenkat Yekkirala } 3721892c141eSVenkat Yekkirala 37227420ed23SVenkat Yekkirala return err; 37231da177e4SLinus Torvalds } 37241da177e4SLinus Torvalds 37251da177e4SLinus Torvalds /* Range of port numbers used to automatically bind. 37261da177e4SLinus Torvalds Need to determine whether we should perform a name_bind 37271da177e4SLinus Torvalds permission check between the socket and the port number. */ 37281da177e4SLinus Torvalds 37291da177e4SLinus Torvalds static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) 37301da177e4SLinus Torvalds { 37311da177e4SLinus Torvalds u16 family; 37321da177e4SLinus Torvalds int err; 37331da177e4SLinus Torvalds 37341da177e4SLinus Torvalds err = socket_has_perm(current, sock, SOCKET__BIND); 37351da177e4SLinus Torvalds if (err) 37361da177e4SLinus Torvalds goto out; 37371da177e4SLinus Torvalds 37381da177e4SLinus Torvalds /* 37391da177e4SLinus Torvalds * If PF_INET or PF_INET6, check name_bind permission for the port. 374013402580SJames Morris * Multiple address binding for SCTP is not supported yet: we just 374113402580SJames Morris * check the first address now. 37421da177e4SLinus Torvalds */ 37431da177e4SLinus Torvalds family = sock->sk->sk_family; 37441da177e4SLinus Torvalds if (family == PF_INET || family == PF_INET6) { 37451da177e4SLinus Torvalds char *addrp; 37461da177e4SLinus Torvalds struct inode_security_struct *isec; 37471da177e4SLinus Torvalds struct avc_audit_data ad; 37481da177e4SLinus Torvalds struct sockaddr_in *addr4 = NULL; 37491da177e4SLinus Torvalds struct sockaddr_in6 *addr6 = NULL; 37501da177e4SLinus Torvalds unsigned short snum; 37511da177e4SLinus Torvalds struct sock *sk = sock->sk; 3752e399f982SJames Morris u32 sid, node_perm; 37531da177e4SLinus Torvalds 37541da177e4SLinus Torvalds isec = SOCK_INODE(sock)->i_security; 37551da177e4SLinus Torvalds 37561da177e4SLinus Torvalds if (family == PF_INET) { 37571da177e4SLinus Torvalds addr4 = (struct sockaddr_in *)address; 37581da177e4SLinus Torvalds snum = ntohs(addr4->sin_port); 37591da177e4SLinus Torvalds addrp = (char *)&addr4->sin_addr.s_addr; 37601da177e4SLinus Torvalds } else { 37611da177e4SLinus Torvalds addr6 = (struct sockaddr_in6 *)address; 37621da177e4SLinus Torvalds snum = ntohs(addr6->sin6_port); 37631da177e4SLinus Torvalds addrp = (char *)&addr6->sin6_addr.s6_addr; 37641da177e4SLinus Torvalds } 37651da177e4SLinus Torvalds 3766227b60f5SStephen Hemminger if (snum) { 3767227b60f5SStephen Hemminger int low, high; 3768227b60f5SStephen Hemminger 3769227b60f5SStephen Hemminger inet_get_local_port_range(&low, &high); 3770227b60f5SStephen Hemminger 3771227b60f5SStephen Hemminger if (snum < max(PROT_SOCK, low) || snum > high) { 37723e112172SPaul Moore err = sel_netport_sid(sk->sk_protocol, 37733e112172SPaul Moore snum, &sid); 37741da177e4SLinus Torvalds if (err) 37751da177e4SLinus Torvalds goto out; 37761da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, NET); 37771da177e4SLinus Torvalds ad.u.net.sport = htons(snum); 37781da177e4SLinus Torvalds ad.u.net.family = family; 37791da177e4SLinus Torvalds err = avc_has_perm(isec->sid, sid, 37801da177e4SLinus Torvalds isec->sclass, 37811da177e4SLinus Torvalds SOCKET__NAME_BIND, &ad); 37821da177e4SLinus Torvalds if (err) 37831da177e4SLinus Torvalds goto out; 37841da177e4SLinus Torvalds } 3785227b60f5SStephen Hemminger } 37861da177e4SLinus Torvalds 378713402580SJames Morris switch (isec->sclass) { 378813402580SJames Morris case SECCLASS_TCP_SOCKET: 37891da177e4SLinus Torvalds node_perm = TCP_SOCKET__NODE_BIND; 37901da177e4SLinus Torvalds break; 37911da177e4SLinus Torvalds 379213402580SJames Morris case SECCLASS_UDP_SOCKET: 37931da177e4SLinus Torvalds node_perm = UDP_SOCKET__NODE_BIND; 37941da177e4SLinus Torvalds break; 37951da177e4SLinus Torvalds 37962ee92d46SJames Morris case SECCLASS_DCCP_SOCKET: 37972ee92d46SJames Morris node_perm = DCCP_SOCKET__NODE_BIND; 37982ee92d46SJames Morris break; 37992ee92d46SJames Morris 38001da177e4SLinus Torvalds default: 38011da177e4SLinus Torvalds node_perm = RAWIP_SOCKET__NODE_BIND; 38021da177e4SLinus Torvalds break; 38031da177e4SLinus Torvalds } 38041da177e4SLinus Torvalds 3805224dfbd8SPaul Moore err = sel_netnode_sid(addrp, family, &sid); 38061da177e4SLinus Torvalds if (err) 38071da177e4SLinus Torvalds goto out; 38081da177e4SLinus Torvalds 38091da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, NET); 38101da177e4SLinus Torvalds ad.u.net.sport = htons(snum); 38111da177e4SLinus Torvalds ad.u.net.family = family; 38121da177e4SLinus Torvalds 38131da177e4SLinus Torvalds if (family == PF_INET) 38141da177e4SLinus Torvalds ad.u.net.v4info.saddr = addr4->sin_addr.s_addr; 38151da177e4SLinus Torvalds else 38161da177e4SLinus Torvalds ipv6_addr_copy(&ad.u.net.v6info.saddr, &addr6->sin6_addr); 38171da177e4SLinus Torvalds 38181da177e4SLinus Torvalds err = avc_has_perm(isec->sid, sid, 38191da177e4SLinus Torvalds isec->sclass, node_perm, &ad); 38201da177e4SLinus Torvalds if (err) 38211da177e4SLinus Torvalds goto out; 38221da177e4SLinus Torvalds } 38231da177e4SLinus Torvalds out: 38241da177e4SLinus Torvalds return err; 38251da177e4SLinus Torvalds } 38261da177e4SLinus Torvalds 38271da177e4SLinus Torvalds static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen) 38281da177e4SLinus Torvalds { 3829014ab19aSPaul Moore struct sock *sk = sock->sk; 38301da177e4SLinus Torvalds struct inode_security_struct *isec; 38311da177e4SLinus Torvalds int err; 38321da177e4SLinus Torvalds 38331da177e4SLinus Torvalds err = socket_has_perm(current, sock, SOCKET__CONNECT); 38341da177e4SLinus Torvalds if (err) 38351da177e4SLinus Torvalds return err; 38361da177e4SLinus Torvalds 38371da177e4SLinus Torvalds /* 38382ee92d46SJames Morris * If a TCP or DCCP socket, check name_connect permission for the port. 38391da177e4SLinus Torvalds */ 38401da177e4SLinus Torvalds isec = SOCK_INODE(sock)->i_security; 38412ee92d46SJames Morris if (isec->sclass == SECCLASS_TCP_SOCKET || 38422ee92d46SJames Morris isec->sclass == SECCLASS_DCCP_SOCKET) { 38431da177e4SLinus Torvalds struct avc_audit_data ad; 38441da177e4SLinus Torvalds struct sockaddr_in *addr4 = NULL; 38451da177e4SLinus Torvalds struct sockaddr_in6 *addr6 = NULL; 38461da177e4SLinus Torvalds unsigned short snum; 38472ee92d46SJames Morris u32 sid, perm; 38481da177e4SLinus Torvalds 38491da177e4SLinus Torvalds if (sk->sk_family == PF_INET) { 38501da177e4SLinus Torvalds addr4 = (struct sockaddr_in *)address; 3851911656f8SStephen Smalley if (addrlen < sizeof(struct sockaddr_in)) 38521da177e4SLinus Torvalds return -EINVAL; 38531da177e4SLinus Torvalds snum = ntohs(addr4->sin_port); 38541da177e4SLinus Torvalds } else { 38551da177e4SLinus Torvalds addr6 = (struct sockaddr_in6 *)address; 3856911656f8SStephen Smalley if (addrlen < SIN6_LEN_RFC2133) 38571da177e4SLinus Torvalds return -EINVAL; 38581da177e4SLinus Torvalds snum = ntohs(addr6->sin6_port); 38591da177e4SLinus Torvalds } 38601da177e4SLinus Torvalds 38613e112172SPaul Moore err = sel_netport_sid(sk->sk_protocol, snum, &sid); 38621da177e4SLinus Torvalds if (err) 38631da177e4SLinus Torvalds goto out; 38641da177e4SLinus Torvalds 38652ee92d46SJames Morris perm = (isec->sclass == SECCLASS_TCP_SOCKET) ? 38662ee92d46SJames Morris TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; 38672ee92d46SJames Morris 38681da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, NET); 38691da177e4SLinus Torvalds ad.u.net.dport = htons(snum); 38701da177e4SLinus Torvalds ad.u.net.family = sk->sk_family; 38712ee92d46SJames Morris err = avc_has_perm(isec->sid, sid, isec->sclass, perm, &ad); 38721da177e4SLinus Torvalds if (err) 38731da177e4SLinus Torvalds goto out; 38741da177e4SLinus Torvalds } 38751da177e4SLinus Torvalds 3876014ab19aSPaul Moore err = selinux_netlbl_socket_connect(sk, address); 3877014ab19aSPaul Moore 38781da177e4SLinus Torvalds out: 38791da177e4SLinus Torvalds return err; 38801da177e4SLinus Torvalds } 38811da177e4SLinus Torvalds 38821da177e4SLinus Torvalds static int selinux_socket_listen(struct socket *sock, int backlog) 38831da177e4SLinus Torvalds { 38841da177e4SLinus Torvalds return socket_has_perm(current, sock, SOCKET__LISTEN); 38851da177e4SLinus Torvalds } 38861da177e4SLinus Torvalds 38871da177e4SLinus Torvalds static int selinux_socket_accept(struct socket *sock, struct socket *newsock) 38881da177e4SLinus Torvalds { 38891da177e4SLinus Torvalds int err; 38901da177e4SLinus Torvalds struct inode_security_struct *isec; 38911da177e4SLinus Torvalds struct inode_security_struct *newisec; 38921da177e4SLinus Torvalds 38931da177e4SLinus Torvalds err = socket_has_perm(current, sock, SOCKET__ACCEPT); 38941da177e4SLinus Torvalds if (err) 38951da177e4SLinus Torvalds return err; 38961da177e4SLinus Torvalds 38971da177e4SLinus Torvalds newisec = SOCK_INODE(newsock)->i_security; 38981da177e4SLinus Torvalds 38991da177e4SLinus Torvalds isec = SOCK_INODE(sock)->i_security; 39001da177e4SLinus Torvalds newisec->sclass = isec->sclass; 39011da177e4SLinus Torvalds newisec->sid = isec->sid; 39021da177e4SLinus Torvalds newisec->initialized = 1; 39031da177e4SLinus Torvalds 39041da177e4SLinus Torvalds return 0; 39051da177e4SLinus Torvalds } 39061da177e4SLinus Torvalds 39071da177e4SLinus Torvalds static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, 39081da177e4SLinus Torvalds int size) 39091da177e4SLinus Torvalds { 39107420ed23SVenkat Yekkirala int rc; 39117420ed23SVenkat Yekkirala 39127420ed23SVenkat Yekkirala rc = socket_has_perm(current, sock, SOCKET__WRITE); 39137420ed23SVenkat Yekkirala if (rc) 39147420ed23SVenkat Yekkirala return rc; 39157420ed23SVenkat Yekkirala 39167420ed23SVenkat Yekkirala return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE); 39171da177e4SLinus Torvalds } 39181da177e4SLinus Torvalds 39191da177e4SLinus Torvalds static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, 39201da177e4SLinus Torvalds int size, int flags) 39211da177e4SLinus Torvalds { 39221da177e4SLinus Torvalds return socket_has_perm(current, sock, SOCKET__READ); 39231da177e4SLinus Torvalds } 39241da177e4SLinus Torvalds 39251da177e4SLinus Torvalds static int selinux_socket_getsockname(struct socket *sock) 39261da177e4SLinus Torvalds { 39271da177e4SLinus Torvalds return socket_has_perm(current, sock, SOCKET__GETATTR); 39281da177e4SLinus Torvalds } 39291da177e4SLinus Torvalds 39301da177e4SLinus Torvalds static int selinux_socket_getpeername(struct socket *sock) 39311da177e4SLinus Torvalds { 39321da177e4SLinus Torvalds return socket_has_perm(current, sock, SOCKET__GETATTR); 39331da177e4SLinus Torvalds } 39341da177e4SLinus Torvalds 39351da177e4SLinus Torvalds static int selinux_socket_setsockopt(struct socket *sock, int level, int optname) 39361da177e4SLinus Torvalds { 3937f8687afeSPaul Moore int err; 3938f8687afeSPaul Moore 3939f8687afeSPaul Moore err = socket_has_perm(current, sock, SOCKET__SETOPT); 3940f8687afeSPaul Moore if (err) 3941f8687afeSPaul Moore return err; 3942f8687afeSPaul Moore 3943f8687afeSPaul Moore return selinux_netlbl_socket_setsockopt(sock, level, optname); 39441da177e4SLinus Torvalds } 39451da177e4SLinus Torvalds 39461da177e4SLinus Torvalds static int selinux_socket_getsockopt(struct socket *sock, int level, 39471da177e4SLinus Torvalds int optname) 39481da177e4SLinus Torvalds { 39491da177e4SLinus Torvalds return socket_has_perm(current, sock, SOCKET__GETOPT); 39501da177e4SLinus Torvalds } 39511da177e4SLinus Torvalds 39521da177e4SLinus Torvalds static int selinux_socket_shutdown(struct socket *sock, int how) 39531da177e4SLinus Torvalds { 39541da177e4SLinus Torvalds return socket_has_perm(current, sock, SOCKET__SHUTDOWN); 39551da177e4SLinus Torvalds } 39561da177e4SLinus Torvalds 39571da177e4SLinus Torvalds static int selinux_socket_unix_stream_connect(struct socket *sock, 39581da177e4SLinus Torvalds struct socket *other, 39591da177e4SLinus Torvalds struct sock *newsk) 39601da177e4SLinus Torvalds { 39611da177e4SLinus Torvalds struct sk_security_struct *ssec; 39621da177e4SLinus Torvalds struct inode_security_struct *isec; 39631da177e4SLinus Torvalds struct inode_security_struct *other_isec; 39641da177e4SLinus Torvalds struct avc_audit_data ad; 39651da177e4SLinus Torvalds int err; 39661da177e4SLinus Torvalds 39671da177e4SLinus Torvalds err = secondary_ops->unix_stream_connect(sock, other, newsk); 39681da177e4SLinus Torvalds if (err) 39691da177e4SLinus Torvalds return err; 39701da177e4SLinus Torvalds 39711da177e4SLinus Torvalds isec = SOCK_INODE(sock)->i_security; 39721da177e4SLinus Torvalds other_isec = SOCK_INODE(other)->i_security; 39731da177e4SLinus Torvalds 39741da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, NET); 39751da177e4SLinus Torvalds ad.u.net.sk = other->sk; 39761da177e4SLinus Torvalds 39771da177e4SLinus Torvalds err = avc_has_perm(isec->sid, other_isec->sid, 39781da177e4SLinus Torvalds isec->sclass, 39791da177e4SLinus Torvalds UNIX_STREAM_SOCKET__CONNECTTO, &ad); 39801da177e4SLinus Torvalds if (err) 39811da177e4SLinus Torvalds return err; 39821da177e4SLinus Torvalds 39831da177e4SLinus Torvalds /* connecting socket */ 39841da177e4SLinus Torvalds ssec = sock->sk->sk_security; 39851da177e4SLinus Torvalds ssec->peer_sid = other_isec->sid; 39861da177e4SLinus Torvalds 39871da177e4SLinus Torvalds /* server child socket */ 39881da177e4SLinus Torvalds ssec = newsk->sk_security; 39891da177e4SLinus Torvalds ssec->peer_sid = isec->sid; 39904237c75cSVenkat Yekkirala err = security_sid_mls_copy(other_isec->sid, ssec->peer_sid, &ssec->sid); 39911da177e4SLinus Torvalds 39924237c75cSVenkat Yekkirala return err; 39931da177e4SLinus Torvalds } 39941da177e4SLinus Torvalds 39951da177e4SLinus Torvalds static int selinux_socket_unix_may_send(struct socket *sock, 39961da177e4SLinus Torvalds struct socket *other) 39971da177e4SLinus Torvalds { 39981da177e4SLinus Torvalds struct inode_security_struct *isec; 39991da177e4SLinus Torvalds struct inode_security_struct *other_isec; 40001da177e4SLinus Torvalds struct avc_audit_data ad; 40011da177e4SLinus Torvalds int err; 40021da177e4SLinus Torvalds 40031da177e4SLinus Torvalds isec = SOCK_INODE(sock)->i_security; 40041da177e4SLinus Torvalds other_isec = SOCK_INODE(other)->i_security; 40051da177e4SLinus Torvalds 40061da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, NET); 40071da177e4SLinus Torvalds ad.u.net.sk = other->sk; 40081da177e4SLinus Torvalds 40091da177e4SLinus Torvalds err = avc_has_perm(isec->sid, other_isec->sid, 40101da177e4SLinus Torvalds isec->sclass, SOCKET__SENDTO, &ad); 40111da177e4SLinus Torvalds if (err) 40121da177e4SLinus Torvalds return err; 40131da177e4SLinus Torvalds 40141da177e4SLinus Torvalds return 0; 40151da177e4SLinus Torvalds } 40161da177e4SLinus Torvalds 4017effad8dfSPaul Moore static int selinux_inet_sys_rcv_skb(int ifindex, char *addrp, u16 family, 4018effad8dfSPaul Moore u32 peer_sid, 4019effad8dfSPaul Moore struct avc_audit_data *ad) 4020effad8dfSPaul Moore { 4021effad8dfSPaul Moore int err; 4022effad8dfSPaul Moore u32 if_sid; 4023effad8dfSPaul Moore u32 node_sid; 4024effad8dfSPaul Moore 4025effad8dfSPaul Moore err = sel_netif_sid(ifindex, &if_sid); 4026effad8dfSPaul Moore if (err) 4027effad8dfSPaul Moore return err; 4028effad8dfSPaul Moore err = avc_has_perm(peer_sid, if_sid, 4029effad8dfSPaul Moore SECCLASS_NETIF, NETIF__INGRESS, ad); 4030effad8dfSPaul Moore if (err) 4031effad8dfSPaul Moore return err; 4032effad8dfSPaul Moore 4033effad8dfSPaul Moore err = sel_netnode_sid(addrp, family, &node_sid); 4034effad8dfSPaul Moore if (err) 4035effad8dfSPaul Moore return err; 4036effad8dfSPaul Moore return avc_has_perm(peer_sid, node_sid, 4037effad8dfSPaul Moore SECCLASS_NODE, NODE__RECVFROM, ad); 4038effad8dfSPaul Moore } 4039effad8dfSPaul Moore 4040220deb96SPaul Moore static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk, 4041220deb96SPaul Moore struct sk_buff *skb, 4042224dfbd8SPaul Moore struct avc_audit_data *ad, 4043220deb96SPaul Moore u16 family, 4044220deb96SPaul Moore char *addrp) 40451da177e4SLinus Torvalds { 4046220deb96SPaul Moore int err; 4047220deb96SPaul Moore struct sk_security_struct *sksec = sk->sk_security; 4048220deb96SPaul Moore u16 sk_class; 4049220deb96SPaul Moore u32 netif_perm, node_perm, recv_perm; 4050220deb96SPaul Moore u32 port_sid, node_sid, if_sid, sk_sid; 40514237c75cSVenkat Yekkirala 4052220deb96SPaul Moore sk_sid = sksec->sid; 4053220deb96SPaul Moore sk_class = sksec->sclass; 40541da177e4SLinus Torvalds 4055220deb96SPaul Moore switch (sk_class) { 40561da177e4SLinus Torvalds case SECCLASS_UDP_SOCKET: 40571da177e4SLinus Torvalds netif_perm = NETIF__UDP_RECV; 40581da177e4SLinus Torvalds node_perm = NODE__UDP_RECV; 40591da177e4SLinus Torvalds recv_perm = UDP_SOCKET__RECV_MSG; 40601da177e4SLinus Torvalds break; 40611da177e4SLinus Torvalds case SECCLASS_TCP_SOCKET: 40621da177e4SLinus Torvalds netif_perm = NETIF__TCP_RECV; 40631da177e4SLinus Torvalds node_perm = NODE__TCP_RECV; 40641da177e4SLinus Torvalds recv_perm = TCP_SOCKET__RECV_MSG; 40651da177e4SLinus Torvalds break; 40662ee92d46SJames Morris case SECCLASS_DCCP_SOCKET: 40672ee92d46SJames Morris netif_perm = NETIF__DCCP_RECV; 40682ee92d46SJames Morris node_perm = NODE__DCCP_RECV; 40692ee92d46SJames Morris recv_perm = DCCP_SOCKET__RECV_MSG; 40702ee92d46SJames Morris break; 40711da177e4SLinus Torvalds default: 40721da177e4SLinus Torvalds netif_perm = NETIF__RAWIP_RECV; 40731da177e4SLinus Torvalds node_perm = NODE__RAWIP_RECV; 4074220deb96SPaul Moore recv_perm = 0; 40751da177e4SLinus Torvalds break; 40761da177e4SLinus Torvalds } 40771da177e4SLinus Torvalds 4078220deb96SPaul Moore err = sel_netif_sid(skb->iif, &if_sid); 40791da177e4SLinus Torvalds if (err) 4080220deb96SPaul Moore return err; 4081220deb96SPaul Moore err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); 4082220deb96SPaul Moore if (err) 4083220deb96SPaul Moore return err; 40841da177e4SLinus Torvalds 4085224dfbd8SPaul Moore err = sel_netnode_sid(addrp, family, &node_sid); 40861da177e4SLinus Torvalds if (err) 4087220deb96SPaul Moore return err; 4088220deb96SPaul Moore err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); 40891da177e4SLinus Torvalds if (err) 4090220deb96SPaul Moore return err; 40911da177e4SLinus Torvalds 4092220deb96SPaul Moore if (!recv_perm) 4093220deb96SPaul Moore return 0; 40943e112172SPaul Moore err = sel_netport_sid(sk->sk_protocol, 40953e112172SPaul Moore ntohs(ad->u.net.sport), &port_sid); 409671f1cb05SPaul Moore if (unlikely(err)) { 409771f1cb05SPaul Moore printk(KERN_WARNING 409871f1cb05SPaul Moore "SELinux: failure in" 409971f1cb05SPaul Moore " selinux_sock_rcv_skb_iptables_compat()," 410071f1cb05SPaul Moore " network port label not found\n"); 4101220deb96SPaul Moore return err; 410271f1cb05SPaul Moore } 4103220deb96SPaul Moore return avc_has_perm(sk_sid, port_sid, sk_class, recv_perm, ad); 41041da177e4SLinus Torvalds } 4105d28d1e08STrent Jaeger 4106220deb96SPaul Moore static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, 4107d8395c87SPaul Moore u16 family) 4108220deb96SPaul Moore { 4109220deb96SPaul Moore int err; 4110220deb96SPaul Moore struct sk_security_struct *sksec = sk->sk_security; 4111220deb96SPaul Moore u32 peer_sid; 4112220deb96SPaul Moore u32 sk_sid = sksec->sid; 4113d8395c87SPaul Moore struct avc_audit_data ad; 4114d8395c87SPaul Moore char *addrp; 4115d8395c87SPaul Moore 4116d8395c87SPaul Moore AVC_AUDIT_DATA_INIT(&ad, NET); 4117d8395c87SPaul Moore ad.u.net.netif = skb->iif; 4118d8395c87SPaul Moore ad.u.net.family = family; 4119d8395c87SPaul Moore err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); 4120d8395c87SPaul Moore if (err) 4121d8395c87SPaul Moore return err; 4122220deb96SPaul Moore 4123220deb96SPaul Moore if (selinux_compat_net) 4124d8395c87SPaul Moore err = selinux_sock_rcv_skb_iptables_compat(sk, skb, &ad, 4125220deb96SPaul Moore family, addrp); 4126220deb96SPaul Moore else 4127220deb96SPaul Moore err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, 4128d8395c87SPaul Moore PACKET__RECV, &ad); 4129220deb96SPaul Moore if (err) 4130220deb96SPaul Moore return err; 4131220deb96SPaul Moore 4132220deb96SPaul Moore if (selinux_policycap_netpeer) { 4133220deb96SPaul Moore err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); 4134220deb96SPaul Moore if (err) 4135220deb96SPaul Moore return err; 4136220deb96SPaul Moore err = avc_has_perm(sk_sid, peer_sid, 4137d8395c87SPaul Moore SECCLASS_PEER, PEER__RECV, &ad); 4138dfaebe98SPaul Moore if (err) 4139dfaebe98SPaul Moore selinux_netlbl_err(skb, err, 0); 4140220deb96SPaul Moore } else { 4141d8395c87SPaul Moore err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); 4142220deb96SPaul Moore if (err) 4143220deb96SPaul Moore return err; 4144d8395c87SPaul Moore err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); 4145220deb96SPaul Moore } 4146220deb96SPaul Moore 41474e5ab4cbSJames Morris return err; 41484e5ab4cbSJames Morris } 4149d28d1e08STrent Jaeger 41504e5ab4cbSJames Morris static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 41514e5ab4cbSJames Morris { 4152220deb96SPaul Moore int err; 41534237c75cSVenkat Yekkirala struct sk_security_struct *sksec = sk->sk_security; 4154220deb96SPaul Moore u16 family = sk->sk_family; 4155220deb96SPaul Moore u32 sk_sid = sksec->sid; 4156220deb96SPaul Moore struct avc_audit_data ad; 4157220deb96SPaul Moore char *addrp; 4158d8395c87SPaul Moore u8 secmark_active; 4159d8395c87SPaul Moore u8 peerlbl_active; 41604e5ab4cbSJames Morris 41614e5ab4cbSJames Morris if (family != PF_INET && family != PF_INET6) 4162220deb96SPaul Moore return 0; 41634e5ab4cbSJames Morris 41644e5ab4cbSJames Morris /* Handle mapped IPv4 packets arriving via IPv6 sockets */ 416587fcd70dSAl Viro if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 41664e5ab4cbSJames Morris family = PF_INET; 41674e5ab4cbSJames Morris 4168d8395c87SPaul Moore /* If any sort of compatibility mode is enabled then handoff processing 4169d8395c87SPaul Moore * to the selinux_sock_rcv_skb_compat() function to deal with the 4170d8395c87SPaul Moore * special handling. We do this in an attempt to keep this function 4171d8395c87SPaul Moore * as fast and as clean as possible. */ 4172d8395c87SPaul Moore if (selinux_compat_net || !selinux_policycap_netpeer) 4173d8395c87SPaul Moore return selinux_sock_rcv_skb_compat(sk, skb, family); 4174d8395c87SPaul Moore 4175d8395c87SPaul Moore secmark_active = selinux_secmark_enabled(); 4176d8395c87SPaul Moore peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); 4177d8395c87SPaul Moore if (!secmark_active && !peerlbl_active) 4178d8395c87SPaul Moore return 0; 4179d8395c87SPaul Moore 41804e5ab4cbSJames Morris AVC_AUDIT_DATA_INIT(&ad, NET); 4181da5645a2SPaul Moore ad.u.net.netif = skb->iif; 41824e5ab4cbSJames Morris ad.u.net.family = family; 4183224dfbd8SPaul Moore err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); 41844e5ab4cbSJames Morris if (err) 4185220deb96SPaul Moore return err; 41864e5ab4cbSJames Morris 4187d8395c87SPaul Moore if (peerlbl_active) { 4188d621d35eSPaul Moore u32 peer_sid; 4189220deb96SPaul Moore 4190220deb96SPaul Moore err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); 4191220deb96SPaul Moore if (err) 4192220deb96SPaul Moore return err; 4193effad8dfSPaul Moore err = selinux_inet_sys_rcv_skb(skb->iif, addrp, family, 4194effad8dfSPaul Moore peer_sid, &ad); 4195dfaebe98SPaul Moore if (err) { 4196dfaebe98SPaul Moore selinux_netlbl_err(skb, err, 0); 4197effad8dfSPaul Moore return err; 4198dfaebe98SPaul Moore } 4199d621d35eSPaul Moore err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, 4200d621d35eSPaul Moore PEER__RECV, &ad); 4201dfaebe98SPaul Moore if (err) 4202dfaebe98SPaul Moore selinux_netlbl_err(skb, err, 0); 4203d621d35eSPaul Moore } 4204d621d35eSPaul Moore 4205d8395c87SPaul Moore if (secmark_active) { 4206effad8dfSPaul Moore err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, 4207effad8dfSPaul Moore PACKET__RECV, &ad); 4208effad8dfSPaul Moore if (err) 4209effad8dfSPaul Moore return err; 4210effad8dfSPaul Moore } 4211effad8dfSPaul Moore 4212d621d35eSPaul Moore return err; 42131da177e4SLinus Torvalds } 42141da177e4SLinus Torvalds 42152c7946a7SCatherine Zhang static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, 42161da177e4SLinus Torvalds int __user *optlen, unsigned len) 42171da177e4SLinus Torvalds { 42181da177e4SLinus Torvalds int err = 0; 42191da177e4SLinus Torvalds char *scontext; 42201da177e4SLinus Torvalds u32 scontext_len; 42211da177e4SLinus Torvalds struct sk_security_struct *ssec; 42221da177e4SLinus Torvalds struct inode_security_struct *isec; 42233de4bab5SPaul Moore u32 peer_sid = SECSID_NULL; 42241da177e4SLinus Torvalds 42251da177e4SLinus Torvalds isec = SOCK_INODE(sock)->i_security; 42262c7946a7SCatherine Zhang 42273de4bab5SPaul Moore if (isec->sclass == SECCLASS_UNIX_STREAM_SOCKET || 42283de4bab5SPaul Moore isec->sclass == SECCLASS_TCP_SOCKET) { 42296b877699SVenkat Yekkirala ssec = sock->sk->sk_security; 42306b877699SVenkat Yekkirala peer_sid = ssec->peer_sid; 42316b877699SVenkat Yekkirala } 42322c7946a7SCatherine Zhang if (peer_sid == SECSID_NULL) { 42332c7946a7SCatherine Zhang err = -ENOPROTOOPT; 42342c7946a7SCatherine Zhang goto out; 42352c7946a7SCatherine Zhang } 42361da177e4SLinus Torvalds 42372c7946a7SCatherine Zhang err = security_sid_to_context(peer_sid, &scontext, &scontext_len); 42381da177e4SLinus Torvalds 42391da177e4SLinus Torvalds if (err) 42401da177e4SLinus Torvalds goto out; 42411da177e4SLinus Torvalds 42421da177e4SLinus Torvalds if (scontext_len > len) { 42431da177e4SLinus Torvalds err = -ERANGE; 42441da177e4SLinus Torvalds goto out_len; 42451da177e4SLinus Torvalds } 42461da177e4SLinus Torvalds 42471da177e4SLinus Torvalds if (copy_to_user(optval, scontext, scontext_len)) 42481da177e4SLinus Torvalds err = -EFAULT; 42491da177e4SLinus Torvalds 42501da177e4SLinus Torvalds out_len: 42511da177e4SLinus Torvalds if (put_user(scontext_len, optlen)) 42521da177e4SLinus Torvalds err = -EFAULT; 42531da177e4SLinus Torvalds 42541da177e4SLinus Torvalds kfree(scontext); 42551da177e4SLinus Torvalds out: 42561da177e4SLinus Torvalds return err; 42571da177e4SLinus Torvalds } 42581da177e4SLinus Torvalds 4259dc49c1f9SCatherine Zhang static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) 42602c7946a7SCatherine Zhang { 4261dc49c1f9SCatherine Zhang u32 peer_secid = SECSID_NULL; 426275e22910SPaul Moore u16 family; 4263877ce7c1SCatherine Zhang 4264aa862900SPaul Moore if (skb && skb->protocol == htons(ETH_P_IP)) 4265aa862900SPaul Moore family = PF_INET; 4266aa862900SPaul Moore else if (skb && skb->protocol == htons(ETH_P_IPV6)) 4267aa862900SPaul Moore family = PF_INET6; 4268aa862900SPaul Moore else if (sock) 426975e22910SPaul Moore family = sock->sk->sk_family; 427075e22910SPaul Moore else 427175e22910SPaul Moore goto out; 427275e22910SPaul Moore 427375e22910SPaul Moore if (sock && family == PF_UNIX) 4274713a04aeSAhmed S. Darwish selinux_inode_getsecid(SOCK_INODE(sock), &peer_secid); 42753de4bab5SPaul Moore else if (skb) 4276220deb96SPaul Moore selinux_skb_peerlbl_sid(skb, family, &peer_secid); 42772c7946a7SCatherine Zhang 427875e22910SPaul Moore out: 4279dc49c1f9SCatherine Zhang *secid = peer_secid; 428075e22910SPaul Moore if (peer_secid == SECSID_NULL) 428175e22910SPaul Moore return -EINVAL; 428275e22910SPaul Moore return 0; 42832c7946a7SCatherine Zhang } 42842c7946a7SCatherine Zhang 42857d877f3bSAl Viro static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) 42861da177e4SLinus Torvalds { 42871da177e4SLinus Torvalds return sk_alloc_security(sk, family, priority); 42881da177e4SLinus Torvalds } 42891da177e4SLinus Torvalds 42901da177e4SLinus Torvalds static void selinux_sk_free_security(struct sock *sk) 42911da177e4SLinus Torvalds { 42921da177e4SLinus Torvalds sk_free_security(sk); 42931da177e4SLinus Torvalds } 42941da177e4SLinus Torvalds 4295892c141eSVenkat Yekkirala static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) 4296892c141eSVenkat Yekkirala { 4297892c141eSVenkat Yekkirala struct sk_security_struct *ssec = sk->sk_security; 4298892c141eSVenkat Yekkirala struct sk_security_struct *newssec = newsk->sk_security; 4299892c141eSVenkat Yekkirala 4300892c141eSVenkat Yekkirala newssec->sid = ssec->sid; 4301892c141eSVenkat Yekkirala newssec->peer_sid = ssec->peer_sid; 4302220deb96SPaul Moore newssec->sclass = ssec->sclass; 430399f59ed0SPaul Moore 4304f74af6e8SPaul Moore selinux_netlbl_sk_security_reset(newssec, newsk->sk_family); 4305892c141eSVenkat Yekkirala } 4306892c141eSVenkat Yekkirala 4307beb8d13bSVenkat Yekkirala static void selinux_sk_getsecid(struct sock *sk, u32 *secid) 4308d28d1e08STrent Jaeger { 4309d28d1e08STrent Jaeger if (!sk) 4310beb8d13bSVenkat Yekkirala *secid = SECINITSID_ANY_SOCKET; 4311892c141eSVenkat Yekkirala else { 4312892c141eSVenkat Yekkirala struct sk_security_struct *sksec = sk->sk_security; 4313d28d1e08STrent Jaeger 4314beb8d13bSVenkat Yekkirala *secid = sksec->sid; 4315892c141eSVenkat Yekkirala } 4316d28d1e08STrent Jaeger } 4317d28d1e08STrent Jaeger 43189a673e56SAdrian Bunk static void selinux_sock_graft(struct sock *sk, struct socket *parent) 43194237c75cSVenkat Yekkirala { 43204237c75cSVenkat Yekkirala struct inode_security_struct *isec = SOCK_INODE(parent)->i_security; 43214237c75cSVenkat Yekkirala struct sk_security_struct *sksec = sk->sk_security; 43224237c75cSVenkat Yekkirala 43232148ccc4SDavid Woodhouse if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || 43242148ccc4SDavid Woodhouse sk->sk_family == PF_UNIX) 43254237c75cSVenkat Yekkirala isec->sid = sksec->sid; 4326220deb96SPaul Moore sksec->sclass = isec->sclass; 43274237c75cSVenkat Yekkirala } 43284237c75cSVenkat Yekkirala 43299a673e56SAdrian Bunk static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, 43304237c75cSVenkat Yekkirala struct request_sock *req) 43314237c75cSVenkat Yekkirala { 43324237c75cSVenkat Yekkirala struct sk_security_struct *sksec = sk->sk_security; 43334237c75cSVenkat Yekkirala int err; 4334aa862900SPaul Moore u16 family = sk->sk_family; 43357420ed23SVenkat Yekkirala u32 newsid; 43364237c75cSVenkat Yekkirala u32 peersid; 43374237c75cSVenkat Yekkirala 4338aa862900SPaul Moore /* handle mapped IPv4 packets arriving via IPv6 sockets */ 4339aa862900SPaul Moore if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 4340aa862900SPaul Moore family = PF_INET; 4341aa862900SPaul Moore 4342aa862900SPaul Moore err = selinux_skb_peerlbl_sid(skb, family, &peersid); 4343220deb96SPaul Moore if (err) 4344220deb96SPaul Moore return err; 4345a51c64f1SVenkat Yekkirala if (peersid == SECSID_NULL) { 4346a51c64f1SVenkat Yekkirala req->secid = sksec->sid; 43473de4bab5SPaul Moore req->peer_secid = SECSID_NULL; 4348a51c64f1SVenkat Yekkirala return 0; 4349a51c64f1SVenkat Yekkirala } 4350a51c64f1SVenkat Yekkirala 43514237c75cSVenkat Yekkirala err = security_sid_mls_copy(sksec->sid, peersid, &newsid); 43524237c75cSVenkat Yekkirala if (err) 43534237c75cSVenkat Yekkirala return err; 43544237c75cSVenkat Yekkirala 43554237c75cSVenkat Yekkirala req->secid = newsid; 43566b877699SVenkat Yekkirala req->peer_secid = peersid; 43574237c75cSVenkat Yekkirala return 0; 43584237c75cSVenkat Yekkirala } 43594237c75cSVenkat Yekkirala 43609a673e56SAdrian Bunk static void selinux_inet_csk_clone(struct sock *newsk, 43619a673e56SAdrian Bunk const struct request_sock *req) 43624237c75cSVenkat Yekkirala { 43634237c75cSVenkat Yekkirala struct sk_security_struct *newsksec = newsk->sk_security; 43644237c75cSVenkat Yekkirala 43654237c75cSVenkat Yekkirala newsksec->sid = req->secid; 43666b877699SVenkat Yekkirala newsksec->peer_sid = req->peer_secid; 43674237c75cSVenkat Yekkirala /* NOTE: Ideally, we should also get the isec->sid for the 43684237c75cSVenkat Yekkirala new socket in sync, but we don't have the isec available yet. 43694237c75cSVenkat Yekkirala So we will wait until sock_graft to do it, by which 43704237c75cSVenkat Yekkirala time it will have been created and available. */ 437199f59ed0SPaul Moore 43729f2ad665SPaul Moore /* We don't need to take any sort of lock here as we are the only 43739f2ad665SPaul Moore * thread with access to newsksec */ 43749f2ad665SPaul Moore selinux_netlbl_sk_security_reset(newsksec, req->rsk_ops->family); 43754237c75cSVenkat Yekkirala } 43764237c75cSVenkat Yekkirala 4377014ab19aSPaul Moore static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) 43786b877699SVenkat Yekkirala { 4379aa862900SPaul Moore u16 family = sk->sk_family; 43806b877699SVenkat Yekkirala struct sk_security_struct *sksec = sk->sk_security; 43816b877699SVenkat Yekkirala 4382aa862900SPaul Moore /* handle mapped IPv4 packets arriving via IPv6 sockets */ 4383aa862900SPaul Moore if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 4384aa862900SPaul Moore family = PF_INET; 4385aa862900SPaul Moore 4386aa862900SPaul Moore selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); 4387014ab19aSPaul Moore 4388014ab19aSPaul Moore selinux_netlbl_inet_conn_established(sk, family); 43896b877699SVenkat Yekkirala } 43906b877699SVenkat Yekkirala 43919a673e56SAdrian Bunk static void selinux_req_classify_flow(const struct request_sock *req, 43929a673e56SAdrian Bunk struct flowi *fl) 43934237c75cSVenkat Yekkirala { 43944237c75cSVenkat Yekkirala fl->secid = req->secid; 43954237c75cSVenkat Yekkirala } 43964237c75cSVenkat Yekkirala 43971da177e4SLinus Torvalds static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb) 43981da177e4SLinus Torvalds { 43991da177e4SLinus Torvalds int err = 0; 44001da177e4SLinus Torvalds u32 perm; 44011da177e4SLinus Torvalds struct nlmsghdr *nlh; 44021da177e4SLinus Torvalds struct socket *sock = sk->sk_socket; 44031da177e4SLinus Torvalds struct inode_security_struct *isec = SOCK_INODE(sock)->i_security; 44041da177e4SLinus Torvalds 44051da177e4SLinus Torvalds if (skb->len < NLMSG_SPACE(0)) { 44061da177e4SLinus Torvalds err = -EINVAL; 44071da177e4SLinus Torvalds goto out; 44081da177e4SLinus Torvalds } 4409b529ccf2SArnaldo Carvalho de Melo nlh = nlmsg_hdr(skb); 44101da177e4SLinus Torvalds 44111da177e4SLinus Torvalds err = selinux_nlmsg_lookup(isec->sclass, nlh->nlmsg_type, &perm); 44121da177e4SLinus Torvalds if (err) { 44131da177e4SLinus Torvalds if (err == -EINVAL) { 44149ad9ad38SDavid Woodhouse audit_log(current->audit_context, GFP_KERNEL, AUDIT_SELINUX_ERR, 44151da177e4SLinus Torvalds "SELinux: unrecognized netlink message" 44161da177e4SLinus Torvalds " type=%hu for sclass=%hu\n", 44171da177e4SLinus Torvalds nlh->nlmsg_type, isec->sclass); 441839c9aedeSEric Paris if (!selinux_enforcing || security_get_allow_unknown()) 44191da177e4SLinus Torvalds err = 0; 44201da177e4SLinus Torvalds } 44211da177e4SLinus Torvalds 44221da177e4SLinus Torvalds /* Ignore */ 44231da177e4SLinus Torvalds if (err == -ENOENT) 44241da177e4SLinus Torvalds err = 0; 44251da177e4SLinus Torvalds goto out; 44261da177e4SLinus Torvalds } 44271da177e4SLinus Torvalds 44281da177e4SLinus Torvalds err = socket_has_perm(current, sock, perm); 44291da177e4SLinus Torvalds out: 44301da177e4SLinus Torvalds return err; 44311da177e4SLinus Torvalds } 44321da177e4SLinus Torvalds 44331da177e4SLinus Torvalds #ifdef CONFIG_NETFILTER 44341da177e4SLinus Torvalds 4435effad8dfSPaul Moore static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, 4436effad8dfSPaul Moore u16 family) 44371da177e4SLinus Torvalds { 4438dfaebe98SPaul Moore int err; 4439effad8dfSPaul Moore char *addrp; 4440effad8dfSPaul Moore u32 peer_sid; 4441effad8dfSPaul Moore struct avc_audit_data ad; 4442effad8dfSPaul Moore u8 secmark_active; 4443948bf85cSPaul Moore u8 netlbl_active; 4444effad8dfSPaul Moore u8 peerlbl_active; 44454237c75cSVenkat Yekkirala 4446effad8dfSPaul Moore if (!selinux_policycap_netpeer) 4447effad8dfSPaul Moore return NF_ACCEPT; 44484237c75cSVenkat Yekkirala 4449effad8dfSPaul Moore secmark_active = selinux_secmark_enabled(); 4450948bf85cSPaul Moore netlbl_active = netlbl_enabled(); 4451948bf85cSPaul Moore peerlbl_active = netlbl_active || selinux_xfrm_enabled(); 4452effad8dfSPaul Moore if (!secmark_active && !peerlbl_active) 4453effad8dfSPaul Moore return NF_ACCEPT; 44544237c75cSVenkat Yekkirala 4455d8395c87SPaul Moore if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) 4456d8395c87SPaul Moore return NF_DROP; 4457d8395c87SPaul Moore 4458effad8dfSPaul Moore AVC_AUDIT_DATA_INIT(&ad, NET); 4459effad8dfSPaul Moore ad.u.net.netif = ifindex; 4460effad8dfSPaul Moore ad.u.net.family = family; 4461effad8dfSPaul Moore if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) 4462effad8dfSPaul Moore return NF_DROP; 44631da177e4SLinus Torvalds 4464dfaebe98SPaul Moore if (peerlbl_active) { 4465dfaebe98SPaul Moore err = selinux_inet_sys_rcv_skb(ifindex, addrp, family, 4466dfaebe98SPaul Moore peer_sid, &ad); 4467dfaebe98SPaul Moore if (err) { 4468dfaebe98SPaul Moore selinux_netlbl_err(skb, err, 1); 4469effad8dfSPaul Moore return NF_DROP; 4470dfaebe98SPaul Moore } 4471dfaebe98SPaul Moore } 4472effad8dfSPaul Moore 4473effad8dfSPaul Moore if (secmark_active) 4474effad8dfSPaul Moore if (avc_has_perm(peer_sid, skb->secmark, 4475effad8dfSPaul Moore SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) 4476effad8dfSPaul Moore return NF_DROP; 4477effad8dfSPaul Moore 4478948bf85cSPaul Moore if (netlbl_active) 4479948bf85cSPaul Moore /* we do this in the FORWARD path and not the POST_ROUTING 4480948bf85cSPaul Moore * path because we want to make sure we apply the necessary 4481948bf85cSPaul Moore * labeling before IPsec is applied so we can leverage AH 4482948bf85cSPaul Moore * protection */ 4483948bf85cSPaul Moore if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) 4484948bf85cSPaul Moore return NF_DROP; 4485948bf85cSPaul Moore 4486effad8dfSPaul Moore return NF_ACCEPT; 4487effad8dfSPaul Moore } 4488effad8dfSPaul Moore 4489effad8dfSPaul Moore static unsigned int selinux_ipv4_forward(unsigned int hooknum, 4490effad8dfSPaul Moore struct sk_buff *skb, 4491effad8dfSPaul Moore const struct net_device *in, 4492effad8dfSPaul Moore const struct net_device *out, 4493effad8dfSPaul Moore int (*okfn)(struct sk_buff *)) 4494effad8dfSPaul Moore { 4495effad8dfSPaul Moore return selinux_ip_forward(skb, in->ifindex, PF_INET); 4496effad8dfSPaul Moore } 4497effad8dfSPaul Moore 4498effad8dfSPaul Moore #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 4499effad8dfSPaul Moore static unsigned int selinux_ipv6_forward(unsigned int hooknum, 4500effad8dfSPaul Moore struct sk_buff *skb, 4501effad8dfSPaul Moore const struct net_device *in, 4502effad8dfSPaul Moore const struct net_device *out, 4503effad8dfSPaul Moore int (*okfn)(struct sk_buff *)) 4504effad8dfSPaul Moore { 4505effad8dfSPaul Moore return selinux_ip_forward(skb, in->ifindex, PF_INET6); 4506effad8dfSPaul Moore } 4507effad8dfSPaul Moore #endif /* IPV6 */ 4508effad8dfSPaul Moore 4509948bf85cSPaul Moore static unsigned int selinux_ip_output(struct sk_buff *skb, 4510948bf85cSPaul Moore u16 family) 4511948bf85cSPaul Moore { 4512948bf85cSPaul Moore u32 sid; 4513948bf85cSPaul Moore 4514948bf85cSPaul Moore if (!netlbl_enabled()) 4515948bf85cSPaul Moore return NF_ACCEPT; 4516948bf85cSPaul Moore 4517948bf85cSPaul Moore /* we do this in the LOCAL_OUT path and not the POST_ROUTING path 4518948bf85cSPaul Moore * because we want to make sure we apply the necessary labeling 4519948bf85cSPaul Moore * before IPsec is applied so we can leverage AH protection */ 4520948bf85cSPaul Moore if (skb->sk) { 4521948bf85cSPaul Moore struct sk_security_struct *sksec = skb->sk->sk_security; 4522948bf85cSPaul Moore sid = sksec->sid; 4523948bf85cSPaul Moore } else 4524948bf85cSPaul Moore sid = SECINITSID_KERNEL; 4525948bf85cSPaul Moore if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0) 4526948bf85cSPaul Moore return NF_DROP; 4527948bf85cSPaul Moore 4528948bf85cSPaul Moore return NF_ACCEPT; 4529948bf85cSPaul Moore } 4530948bf85cSPaul Moore 4531948bf85cSPaul Moore static unsigned int selinux_ipv4_output(unsigned int hooknum, 4532948bf85cSPaul Moore struct sk_buff *skb, 4533948bf85cSPaul Moore const struct net_device *in, 4534948bf85cSPaul Moore const struct net_device *out, 4535948bf85cSPaul Moore int (*okfn)(struct sk_buff *)) 4536948bf85cSPaul Moore { 4537948bf85cSPaul Moore return selinux_ip_output(skb, PF_INET); 4538948bf85cSPaul Moore } 4539948bf85cSPaul Moore 4540effad8dfSPaul Moore static int selinux_ip_postroute_iptables_compat(struct sock *sk, 4541effad8dfSPaul Moore int ifindex, 4542effad8dfSPaul Moore struct avc_audit_data *ad, 4543effad8dfSPaul Moore u16 family, char *addrp) 4544effad8dfSPaul Moore { 4545effad8dfSPaul Moore int err; 4546effad8dfSPaul Moore struct sk_security_struct *sksec = sk->sk_security; 4547effad8dfSPaul Moore u16 sk_class; 4548effad8dfSPaul Moore u32 netif_perm, node_perm, send_perm; 4549effad8dfSPaul Moore u32 port_sid, node_sid, if_sid, sk_sid; 4550effad8dfSPaul Moore 4551effad8dfSPaul Moore sk_sid = sksec->sid; 4552effad8dfSPaul Moore sk_class = sksec->sclass; 4553effad8dfSPaul Moore 4554effad8dfSPaul Moore switch (sk_class) { 45551da177e4SLinus Torvalds case SECCLASS_UDP_SOCKET: 45561da177e4SLinus Torvalds netif_perm = NETIF__UDP_SEND; 45571da177e4SLinus Torvalds node_perm = NODE__UDP_SEND; 45581da177e4SLinus Torvalds send_perm = UDP_SOCKET__SEND_MSG; 45591da177e4SLinus Torvalds break; 45601da177e4SLinus Torvalds case SECCLASS_TCP_SOCKET: 45611da177e4SLinus Torvalds netif_perm = NETIF__TCP_SEND; 45621da177e4SLinus Torvalds node_perm = NODE__TCP_SEND; 45631da177e4SLinus Torvalds send_perm = TCP_SOCKET__SEND_MSG; 45641da177e4SLinus Torvalds break; 45652ee92d46SJames Morris case SECCLASS_DCCP_SOCKET: 45662ee92d46SJames Morris netif_perm = NETIF__DCCP_SEND; 45672ee92d46SJames Morris node_perm = NODE__DCCP_SEND; 45682ee92d46SJames Morris send_perm = DCCP_SOCKET__SEND_MSG; 45692ee92d46SJames Morris break; 45701da177e4SLinus Torvalds default: 45711da177e4SLinus Torvalds netif_perm = NETIF__RAWIP_SEND; 45721da177e4SLinus Torvalds node_perm = NODE__RAWIP_SEND; 4573effad8dfSPaul Moore send_perm = 0; 45741da177e4SLinus Torvalds break; 45751da177e4SLinus Torvalds } 45761da177e4SLinus Torvalds 4577effad8dfSPaul Moore err = sel_netif_sid(ifindex, &if_sid); 45784e5ab4cbSJames Morris if (err) 4579effad8dfSPaul Moore return err; 4580effad8dfSPaul Moore err = avc_has_perm(sk_sid, if_sid, SECCLASS_NETIF, netif_perm, ad); 4581effad8dfSPaul Moore return err; 45821da177e4SLinus Torvalds 4583224dfbd8SPaul Moore err = sel_netnode_sid(addrp, family, &node_sid); 45844e5ab4cbSJames Morris if (err) 4585effad8dfSPaul Moore return err; 4586effad8dfSPaul Moore err = avc_has_perm(sk_sid, node_sid, SECCLASS_NODE, node_perm, ad); 45874e5ab4cbSJames Morris if (err) 4588effad8dfSPaul Moore return err; 45891da177e4SLinus Torvalds 4590effad8dfSPaul Moore if (send_perm != 0) 4591effad8dfSPaul Moore return 0; 45921da177e4SLinus Torvalds 45933e112172SPaul Moore err = sel_netport_sid(sk->sk_protocol, 45943e112172SPaul Moore ntohs(ad->u.net.dport), &port_sid); 459571f1cb05SPaul Moore if (unlikely(err)) { 459671f1cb05SPaul Moore printk(KERN_WARNING 459771f1cb05SPaul Moore "SELinux: failure in" 459871f1cb05SPaul Moore " selinux_ip_postroute_iptables_compat()," 459971f1cb05SPaul Moore " network port label not found\n"); 46004e5ab4cbSJames Morris return err; 460171f1cb05SPaul Moore } 4602effad8dfSPaul Moore return avc_has_perm(sk_sid, port_sid, sk_class, send_perm, ad); 46031da177e4SLinus Torvalds } 46041da177e4SLinus Torvalds 4605effad8dfSPaul Moore static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, 4606effad8dfSPaul Moore int ifindex, 4607d8395c87SPaul Moore u16 family) 46084e5ab4cbSJames Morris { 4609effad8dfSPaul Moore struct sock *sk = skb->sk; 46104237c75cSVenkat Yekkirala struct sk_security_struct *sksec; 4611d8395c87SPaul Moore struct avc_audit_data ad; 4612d8395c87SPaul Moore char *addrp; 4613d8395c87SPaul Moore u8 proto; 46144e5ab4cbSJames Morris 4615effad8dfSPaul Moore if (sk == NULL) 4616effad8dfSPaul Moore return NF_ACCEPT; 46174237c75cSVenkat Yekkirala sksec = sk->sk_security; 46184e5ab4cbSJames Morris 4619d8395c87SPaul Moore AVC_AUDIT_DATA_INIT(&ad, NET); 4620d8395c87SPaul Moore ad.u.net.netif = ifindex; 4621d8395c87SPaul Moore ad.u.net.family = family; 4622d8395c87SPaul Moore if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) 4623d8395c87SPaul Moore return NF_DROP; 4624d8395c87SPaul Moore 4625effad8dfSPaul Moore if (selinux_compat_net) { 4626effad8dfSPaul Moore if (selinux_ip_postroute_iptables_compat(skb->sk, ifindex, 4627d8395c87SPaul Moore &ad, family, addrp)) 4628effad8dfSPaul Moore return NF_DROP; 4629effad8dfSPaul Moore } else { 4630effad8dfSPaul Moore if (avc_has_perm(sksec->sid, skb->secmark, 4631d8395c87SPaul Moore SECCLASS_PACKET, PACKET__SEND, &ad)) 4632effad8dfSPaul Moore return NF_DROP; 46331da177e4SLinus Torvalds } 46341da177e4SLinus Torvalds 4635effad8dfSPaul Moore if (selinux_policycap_netpeer) 4636d8395c87SPaul Moore if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) 4637effad8dfSPaul Moore return NF_DROP; 4638effad8dfSPaul Moore 4639effad8dfSPaul Moore return NF_ACCEPT; 4640effad8dfSPaul Moore } 4641effad8dfSPaul Moore 4642effad8dfSPaul Moore static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, 4643effad8dfSPaul Moore u16 family) 4644effad8dfSPaul Moore { 4645effad8dfSPaul Moore u32 secmark_perm; 4646effad8dfSPaul Moore u32 peer_sid; 4647effad8dfSPaul Moore struct sock *sk; 4648effad8dfSPaul Moore struct avc_audit_data ad; 4649effad8dfSPaul Moore char *addrp; 4650effad8dfSPaul Moore u8 secmark_active; 4651effad8dfSPaul Moore u8 peerlbl_active; 4652effad8dfSPaul Moore 4653effad8dfSPaul Moore /* If any sort of compatibility mode is enabled then handoff processing 4654effad8dfSPaul Moore * to the selinux_ip_postroute_compat() function to deal with the 4655effad8dfSPaul Moore * special handling. We do this in an attempt to keep this function 4656effad8dfSPaul Moore * as fast and as clean as possible. */ 4657effad8dfSPaul Moore if (selinux_compat_net || !selinux_policycap_netpeer) 4658d8395c87SPaul Moore return selinux_ip_postroute_compat(skb, ifindex, family); 4659effad8dfSPaul Moore 4660effad8dfSPaul Moore /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec 4661effad8dfSPaul Moore * packet transformation so allow the packet to pass without any checks 4662effad8dfSPaul Moore * since we'll have another chance to perform access control checks 4663effad8dfSPaul Moore * when the packet is on it's final way out. 4664effad8dfSPaul Moore * NOTE: there appear to be some IPv6 multicast cases where skb->dst 4665effad8dfSPaul Moore * is NULL, in this case go ahead and apply access control. */ 4666effad8dfSPaul Moore if (skb->dst != NULL && skb->dst->xfrm != NULL) 4667effad8dfSPaul Moore return NF_ACCEPT; 4668effad8dfSPaul Moore 4669effad8dfSPaul Moore secmark_active = selinux_secmark_enabled(); 4670effad8dfSPaul Moore peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); 4671effad8dfSPaul Moore if (!secmark_active && !peerlbl_active) 4672effad8dfSPaul Moore return NF_ACCEPT; 4673effad8dfSPaul Moore 4674d8395c87SPaul Moore /* if the packet is being forwarded then get the peer label from the 4675d8395c87SPaul Moore * packet itself; otherwise check to see if it is from a local 4676d8395c87SPaul Moore * application or the kernel, if from an application get the peer label 4677d8395c87SPaul Moore * from the sending socket, otherwise use the kernel's sid */ 4678effad8dfSPaul Moore sk = skb->sk; 4679d8395c87SPaul Moore if (sk == NULL) { 4680d8395c87SPaul Moore switch (family) { 4681d8395c87SPaul Moore case PF_INET: 4682d8395c87SPaul Moore if (IPCB(skb)->flags & IPSKB_FORWARDED) 4683d8395c87SPaul Moore secmark_perm = PACKET__FORWARD_OUT; 4684d8395c87SPaul Moore else 4685d8395c87SPaul Moore secmark_perm = PACKET__SEND; 4686d8395c87SPaul Moore break; 4687d8395c87SPaul Moore case PF_INET6: 4688d8395c87SPaul Moore if (IP6CB(skb)->flags & IP6SKB_FORWARDED) 4689d8395c87SPaul Moore secmark_perm = PACKET__FORWARD_OUT; 4690d8395c87SPaul Moore else 4691d8395c87SPaul Moore secmark_perm = PACKET__SEND; 4692d8395c87SPaul Moore break; 4693d8395c87SPaul Moore default: 4694d8395c87SPaul Moore return NF_DROP; 4695d8395c87SPaul Moore } 4696d8395c87SPaul Moore if (secmark_perm == PACKET__FORWARD_OUT) { 4697d8395c87SPaul Moore if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) 4698d8395c87SPaul Moore return NF_DROP; 4699d8395c87SPaul Moore } else 4700d8395c87SPaul Moore peer_sid = SECINITSID_KERNEL; 4701d8395c87SPaul Moore } else { 4702effad8dfSPaul Moore struct sk_security_struct *sksec = sk->sk_security; 4703effad8dfSPaul Moore peer_sid = sksec->sid; 4704effad8dfSPaul Moore secmark_perm = PACKET__SEND; 4705effad8dfSPaul Moore } 4706effad8dfSPaul Moore 4707d8395c87SPaul Moore AVC_AUDIT_DATA_INIT(&ad, NET); 4708d8395c87SPaul Moore ad.u.net.netif = ifindex; 4709d8395c87SPaul Moore ad.u.net.family = family; 4710d8395c87SPaul Moore if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) 4711d8395c87SPaul Moore return NF_DROP; 4712d8395c87SPaul Moore 4713effad8dfSPaul Moore if (secmark_active) 4714effad8dfSPaul Moore if (avc_has_perm(peer_sid, skb->secmark, 4715effad8dfSPaul Moore SECCLASS_PACKET, secmark_perm, &ad)) 4716effad8dfSPaul Moore return NF_DROP; 4717effad8dfSPaul Moore 4718effad8dfSPaul Moore if (peerlbl_active) { 4719effad8dfSPaul Moore u32 if_sid; 4720effad8dfSPaul Moore u32 node_sid; 4721effad8dfSPaul Moore 4722effad8dfSPaul Moore if (sel_netif_sid(ifindex, &if_sid)) 4723effad8dfSPaul Moore return NF_DROP; 4724effad8dfSPaul Moore if (avc_has_perm(peer_sid, if_sid, 4725effad8dfSPaul Moore SECCLASS_NETIF, NETIF__EGRESS, &ad)) 4726effad8dfSPaul Moore return NF_DROP; 4727effad8dfSPaul Moore 4728effad8dfSPaul Moore if (sel_netnode_sid(addrp, family, &node_sid)) 4729effad8dfSPaul Moore return NF_DROP; 4730effad8dfSPaul Moore if (avc_has_perm(peer_sid, node_sid, 4731effad8dfSPaul Moore SECCLASS_NODE, NODE__SENDTO, &ad)) 4732effad8dfSPaul Moore return NF_DROP; 4733effad8dfSPaul Moore } 4734effad8dfSPaul Moore 4735effad8dfSPaul Moore return NF_ACCEPT; 4736effad8dfSPaul Moore } 4737effad8dfSPaul Moore 4738effad8dfSPaul Moore static unsigned int selinux_ipv4_postroute(unsigned int hooknum, 4739a224be76SDavid S. Miller struct sk_buff *skb, 47401da177e4SLinus Torvalds const struct net_device *in, 47411da177e4SLinus Torvalds const struct net_device *out, 47421da177e4SLinus Torvalds int (*okfn)(struct sk_buff *)) 47431da177e4SLinus Torvalds { 4744effad8dfSPaul Moore return selinux_ip_postroute(skb, out->ifindex, PF_INET); 47451da177e4SLinus Torvalds } 47461da177e4SLinus Torvalds 47471da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 4748effad8dfSPaul Moore static unsigned int selinux_ipv6_postroute(unsigned int hooknum, 4749a224be76SDavid S. Miller struct sk_buff *skb, 47501da177e4SLinus Torvalds const struct net_device *in, 47511da177e4SLinus Torvalds const struct net_device *out, 47521da177e4SLinus Torvalds int (*okfn)(struct sk_buff *)) 47531da177e4SLinus Torvalds { 4754effad8dfSPaul Moore return selinux_ip_postroute(skb, out->ifindex, PF_INET6); 47551da177e4SLinus Torvalds } 47561da177e4SLinus Torvalds #endif /* IPV6 */ 47571da177e4SLinus Torvalds 47581da177e4SLinus Torvalds #endif /* CONFIG_NETFILTER */ 47591da177e4SLinus Torvalds 47601da177e4SLinus Torvalds static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) 47611da177e4SLinus Torvalds { 47621da177e4SLinus Torvalds int err; 47631da177e4SLinus Torvalds 47641da177e4SLinus Torvalds err = secondary_ops->netlink_send(sk, skb); 47651da177e4SLinus Torvalds if (err) 47661da177e4SLinus Torvalds return err; 47671da177e4SLinus Torvalds 47681da177e4SLinus Torvalds if (policydb_loaded_version >= POLICYDB_VERSION_NLCLASS) 47691da177e4SLinus Torvalds err = selinux_nlmsg_perm(sk, skb); 47701da177e4SLinus Torvalds 47711da177e4SLinus Torvalds return err; 47721da177e4SLinus Torvalds } 47731da177e4SLinus Torvalds 4774c7bdb545SDarrel Goeddel static int selinux_netlink_recv(struct sk_buff *skb, int capability) 47751da177e4SLinus Torvalds { 4776c7bdb545SDarrel Goeddel int err; 4777c7bdb545SDarrel Goeddel struct avc_audit_data ad; 4778c7bdb545SDarrel Goeddel 4779c7bdb545SDarrel Goeddel err = secondary_ops->netlink_recv(skb, capability); 4780c7bdb545SDarrel Goeddel if (err) 4781c7bdb545SDarrel Goeddel return err; 4782c7bdb545SDarrel Goeddel 4783c7bdb545SDarrel Goeddel AVC_AUDIT_DATA_INIT(&ad, CAP); 4784c7bdb545SDarrel Goeddel ad.u.cap = capability; 4785c7bdb545SDarrel Goeddel 4786c7bdb545SDarrel Goeddel return avc_has_perm(NETLINK_CB(skb).sid, NETLINK_CB(skb).sid, 4787c7bdb545SDarrel Goeddel SECCLASS_CAPABILITY, CAP_TO_MASK(capability), &ad); 47881da177e4SLinus Torvalds } 47891da177e4SLinus Torvalds 47901da177e4SLinus Torvalds static int ipc_alloc_security(struct task_struct *task, 47911da177e4SLinus Torvalds struct kern_ipc_perm *perm, 47921da177e4SLinus Torvalds u16 sclass) 47931da177e4SLinus Torvalds { 47941da177e4SLinus Torvalds struct ipc_security_struct *isec; 4795*275bb41eSDavid Howells u32 sid; 47961da177e4SLinus Torvalds 479789d155efSJames Morris isec = kzalloc(sizeof(struct ipc_security_struct), GFP_KERNEL); 47981da177e4SLinus Torvalds if (!isec) 47991da177e4SLinus Torvalds return -ENOMEM; 48001da177e4SLinus Torvalds 4801*275bb41eSDavid Howells sid = task_sid(task); 48021da177e4SLinus Torvalds isec->sclass = sclass; 4803*275bb41eSDavid Howells isec->sid = sid; 48041da177e4SLinus Torvalds perm->security = isec; 48051da177e4SLinus Torvalds 48061da177e4SLinus Torvalds return 0; 48071da177e4SLinus Torvalds } 48081da177e4SLinus Torvalds 48091da177e4SLinus Torvalds static void ipc_free_security(struct kern_ipc_perm *perm) 48101da177e4SLinus Torvalds { 48111da177e4SLinus Torvalds struct ipc_security_struct *isec = perm->security; 48121da177e4SLinus Torvalds perm->security = NULL; 48131da177e4SLinus Torvalds kfree(isec); 48141da177e4SLinus Torvalds } 48151da177e4SLinus Torvalds 48161da177e4SLinus Torvalds static int msg_msg_alloc_security(struct msg_msg *msg) 48171da177e4SLinus Torvalds { 48181da177e4SLinus Torvalds struct msg_security_struct *msec; 48191da177e4SLinus Torvalds 482089d155efSJames Morris msec = kzalloc(sizeof(struct msg_security_struct), GFP_KERNEL); 48211da177e4SLinus Torvalds if (!msec) 48221da177e4SLinus Torvalds return -ENOMEM; 48231da177e4SLinus Torvalds 48241da177e4SLinus Torvalds msec->sid = SECINITSID_UNLABELED; 48251da177e4SLinus Torvalds msg->security = msec; 48261da177e4SLinus Torvalds 48271da177e4SLinus Torvalds return 0; 48281da177e4SLinus Torvalds } 48291da177e4SLinus Torvalds 48301da177e4SLinus Torvalds static void msg_msg_free_security(struct msg_msg *msg) 48311da177e4SLinus Torvalds { 48321da177e4SLinus Torvalds struct msg_security_struct *msec = msg->security; 48331da177e4SLinus Torvalds 48341da177e4SLinus Torvalds msg->security = NULL; 48351da177e4SLinus Torvalds kfree(msec); 48361da177e4SLinus Torvalds } 48371da177e4SLinus Torvalds 48381da177e4SLinus Torvalds static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, 48396af963f1SStephen Smalley u32 perms) 48401da177e4SLinus Torvalds { 48411da177e4SLinus Torvalds struct ipc_security_struct *isec; 48421da177e4SLinus Torvalds struct avc_audit_data ad; 4843*275bb41eSDavid Howells u32 sid = current_sid(); 48441da177e4SLinus Torvalds 48451da177e4SLinus Torvalds isec = ipc_perms->security; 48461da177e4SLinus Torvalds 48471da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, IPC); 48481da177e4SLinus Torvalds ad.u.ipc_id = ipc_perms->key; 48491da177e4SLinus Torvalds 4850*275bb41eSDavid Howells return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); 48511da177e4SLinus Torvalds } 48521da177e4SLinus Torvalds 48531da177e4SLinus Torvalds static int selinux_msg_msg_alloc_security(struct msg_msg *msg) 48541da177e4SLinus Torvalds { 48551da177e4SLinus Torvalds return msg_msg_alloc_security(msg); 48561da177e4SLinus Torvalds } 48571da177e4SLinus Torvalds 48581da177e4SLinus Torvalds static void selinux_msg_msg_free_security(struct msg_msg *msg) 48591da177e4SLinus Torvalds { 48601da177e4SLinus Torvalds msg_msg_free_security(msg); 48611da177e4SLinus Torvalds } 48621da177e4SLinus Torvalds 48631da177e4SLinus Torvalds /* message queue security operations */ 48641da177e4SLinus Torvalds static int selinux_msg_queue_alloc_security(struct msg_queue *msq) 48651da177e4SLinus Torvalds { 48661da177e4SLinus Torvalds struct ipc_security_struct *isec; 48671da177e4SLinus Torvalds struct avc_audit_data ad; 4868*275bb41eSDavid Howells u32 sid = current_sid(); 48691da177e4SLinus Torvalds int rc; 48701da177e4SLinus Torvalds 48711da177e4SLinus Torvalds rc = ipc_alloc_security(current, &msq->q_perm, SECCLASS_MSGQ); 48721da177e4SLinus Torvalds if (rc) 48731da177e4SLinus Torvalds return rc; 48741da177e4SLinus Torvalds 48751da177e4SLinus Torvalds isec = msq->q_perm.security; 48761da177e4SLinus Torvalds 48771da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, IPC); 48781da177e4SLinus Torvalds ad.u.ipc_id = msq->q_perm.key; 48791da177e4SLinus Torvalds 4880*275bb41eSDavid Howells rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, 48811da177e4SLinus Torvalds MSGQ__CREATE, &ad); 48821da177e4SLinus Torvalds if (rc) { 48831da177e4SLinus Torvalds ipc_free_security(&msq->q_perm); 48841da177e4SLinus Torvalds return rc; 48851da177e4SLinus Torvalds } 48861da177e4SLinus Torvalds return 0; 48871da177e4SLinus Torvalds } 48881da177e4SLinus Torvalds 48891da177e4SLinus Torvalds static void selinux_msg_queue_free_security(struct msg_queue *msq) 48901da177e4SLinus Torvalds { 48911da177e4SLinus Torvalds ipc_free_security(&msq->q_perm); 48921da177e4SLinus Torvalds } 48931da177e4SLinus Torvalds 48941da177e4SLinus Torvalds static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) 48951da177e4SLinus Torvalds { 48961da177e4SLinus Torvalds struct ipc_security_struct *isec; 48971da177e4SLinus Torvalds struct avc_audit_data ad; 4898*275bb41eSDavid Howells u32 sid = current_sid(); 48991da177e4SLinus Torvalds 49001da177e4SLinus Torvalds isec = msq->q_perm.security; 49011da177e4SLinus Torvalds 49021da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, IPC); 49031da177e4SLinus Torvalds ad.u.ipc_id = msq->q_perm.key; 49041da177e4SLinus Torvalds 4905*275bb41eSDavid Howells return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, 49061da177e4SLinus Torvalds MSGQ__ASSOCIATE, &ad); 49071da177e4SLinus Torvalds } 49081da177e4SLinus Torvalds 49091da177e4SLinus Torvalds static int selinux_msg_queue_msgctl(struct msg_queue *msq, int cmd) 49101da177e4SLinus Torvalds { 49111da177e4SLinus Torvalds int err; 49121da177e4SLinus Torvalds int perms; 49131da177e4SLinus Torvalds 49141da177e4SLinus Torvalds switch (cmd) { 49151da177e4SLinus Torvalds case IPC_INFO: 49161da177e4SLinus Torvalds case MSG_INFO: 49171da177e4SLinus Torvalds /* No specific object, just general system-wide information. */ 49181da177e4SLinus Torvalds return task_has_system(current, SYSTEM__IPC_INFO); 49191da177e4SLinus Torvalds case IPC_STAT: 49201da177e4SLinus Torvalds case MSG_STAT: 49211da177e4SLinus Torvalds perms = MSGQ__GETATTR | MSGQ__ASSOCIATE; 49221da177e4SLinus Torvalds break; 49231da177e4SLinus Torvalds case IPC_SET: 49241da177e4SLinus Torvalds perms = MSGQ__SETATTR; 49251da177e4SLinus Torvalds break; 49261da177e4SLinus Torvalds case IPC_RMID: 49271da177e4SLinus Torvalds perms = MSGQ__DESTROY; 49281da177e4SLinus Torvalds break; 49291da177e4SLinus Torvalds default: 49301da177e4SLinus Torvalds return 0; 49311da177e4SLinus Torvalds } 49321da177e4SLinus Torvalds 49336af963f1SStephen Smalley err = ipc_has_perm(&msq->q_perm, perms); 49341da177e4SLinus Torvalds return err; 49351da177e4SLinus Torvalds } 49361da177e4SLinus Torvalds 49371da177e4SLinus Torvalds static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, int msqflg) 49381da177e4SLinus Torvalds { 49391da177e4SLinus Torvalds struct ipc_security_struct *isec; 49401da177e4SLinus Torvalds struct msg_security_struct *msec; 49411da177e4SLinus Torvalds struct avc_audit_data ad; 4942*275bb41eSDavid Howells u32 sid = current_sid(); 49431da177e4SLinus Torvalds int rc; 49441da177e4SLinus Torvalds 49451da177e4SLinus Torvalds isec = msq->q_perm.security; 49461da177e4SLinus Torvalds msec = msg->security; 49471da177e4SLinus Torvalds 49481da177e4SLinus Torvalds /* 49491da177e4SLinus Torvalds * First time through, need to assign label to the message 49501da177e4SLinus Torvalds */ 49511da177e4SLinus Torvalds if (msec->sid == SECINITSID_UNLABELED) { 49521da177e4SLinus Torvalds /* 49531da177e4SLinus Torvalds * Compute new sid based on current process and 49541da177e4SLinus Torvalds * message queue this message will be stored in 49551da177e4SLinus Torvalds */ 4956*275bb41eSDavid Howells rc = security_transition_sid(sid, isec->sid, SECCLASS_MSG, 49571da177e4SLinus Torvalds &msec->sid); 49581da177e4SLinus Torvalds if (rc) 49591da177e4SLinus Torvalds return rc; 49601da177e4SLinus Torvalds } 49611da177e4SLinus Torvalds 49621da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, IPC); 49631da177e4SLinus Torvalds ad.u.ipc_id = msq->q_perm.key; 49641da177e4SLinus Torvalds 49651da177e4SLinus Torvalds /* Can this process write to the queue? */ 4966*275bb41eSDavid Howells rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, 49671da177e4SLinus Torvalds MSGQ__WRITE, &ad); 49681da177e4SLinus Torvalds if (!rc) 49691da177e4SLinus Torvalds /* Can this process send the message */ 4970*275bb41eSDavid Howells rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG, 4971*275bb41eSDavid Howells MSG__SEND, &ad); 49721da177e4SLinus Torvalds if (!rc) 49731da177e4SLinus Torvalds /* Can the message be put in the queue? */ 4974*275bb41eSDavid Howells rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ, 4975*275bb41eSDavid Howells MSGQ__ENQUEUE, &ad); 49761da177e4SLinus Torvalds 49771da177e4SLinus Torvalds return rc; 49781da177e4SLinus Torvalds } 49791da177e4SLinus Torvalds 49801da177e4SLinus Torvalds static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, 49811da177e4SLinus Torvalds struct task_struct *target, 49821da177e4SLinus Torvalds long type, int mode) 49831da177e4SLinus Torvalds { 49841da177e4SLinus Torvalds struct ipc_security_struct *isec; 49851da177e4SLinus Torvalds struct msg_security_struct *msec; 49861da177e4SLinus Torvalds struct avc_audit_data ad; 4987*275bb41eSDavid Howells u32 sid = task_sid(target); 49881da177e4SLinus Torvalds int rc; 49891da177e4SLinus Torvalds 49901da177e4SLinus Torvalds isec = msq->q_perm.security; 49911da177e4SLinus Torvalds msec = msg->security; 49921da177e4SLinus Torvalds 49931da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, IPC); 49941da177e4SLinus Torvalds ad.u.ipc_id = msq->q_perm.key; 49951da177e4SLinus Torvalds 4996*275bb41eSDavid Howells rc = avc_has_perm(sid, isec->sid, 49971da177e4SLinus Torvalds SECCLASS_MSGQ, MSGQ__READ, &ad); 49981da177e4SLinus Torvalds if (!rc) 4999*275bb41eSDavid Howells rc = avc_has_perm(sid, msec->sid, 50001da177e4SLinus Torvalds SECCLASS_MSG, MSG__RECEIVE, &ad); 50011da177e4SLinus Torvalds return rc; 50021da177e4SLinus Torvalds } 50031da177e4SLinus Torvalds 50041da177e4SLinus Torvalds /* Shared Memory security operations */ 50051da177e4SLinus Torvalds static int selinux_shm_alloc_security(struct shmid_kernel *shp) 50061da177e4SLinus Torvalds { 50071da177e4SLinus Torvalds struct ipc_security_struct *isec; 50081da177e4SLinus Torvalds struct avc_audit_data ad; 5009*275bb41eSDavid Howells u32 sid = current_sid(); 50101da177e4SLinus Torvalds int rc; 50111da177e4SLinus Torvalds 50121da177e4SLinus Torvalds rc = ipc_alloc_security(current, &shp->shm_perm, SECCLASS_SHM); 50131da177e4SLinus Torvalds if (rc) 50141da177e4SLinus Torvalds return rc; 50151da177e4SLinus Torvalds 50161da177e4SLinus Torvalds isec = shp->shm_perm.security; 50171da177e4SLinus Torvalds 50181da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, IPC); 50191da177e4SLinus Torvalds ad.u.ipc_id = shp->shm_perm.key; 50201da177e4SLinus Torvalds 5021*275bb41eSDavid Howells rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, 50221da177e4SLinus Torvalds SHM__CREATE, &ad); 50231da177e4SLinus Torvalds if (rc) { 50241da177e4SLinus Torvalds ipc_free_security(&shp->shm_perm); 50251da177e4SLinus Torvalds return rc; 50261da177e4SLinus Torvalds } 50271da177e4SLinus Torvalds return 0; 50281da177e4SLinus Torvalds } 50291da177e4SLinus Torvalds 50301da177e4SLinus Torvalds static void selinux_shm_free_security(struct shmid_kernel *shp) 50311da177e4SLinus Torvalds { 50321da177e4SLinus Torvalds ipc_free_security(&shp->shm_perm); 50331da177e4SLinus Torvalds } 50341da177e4SLinus Torvalds 50351da177e4SLinus Torvalds static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) 50361da177e4SLinus Torvalds { 50371da177e4SLinus Torvalds struct ipc_security_struct *isec; 50381da177e4SLinus Torvalds struct avc_audit_data ad; 5039*275bb41eSDavid Howells u32 sid = current_sid(); 50401da177e4SLinus Torvalds 50411da177e4SLinus Torvalds isec = shp->shm_perm.security; 50421da177e4SLinus Torvalds 50431da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, IPC); 50441da177e4SLinus Torvalds ad.u.ipc_id = shp->shm_perm.key; 50451da177e4SLinus Torvalds 5046*275bb41eSDavid Howells return avc_has_perm(sid, isec->sid, SECCLASS_SHM, 50471da177e4SLinus Torvalds SHM__ASSOCIATE, &ad); 50481da177e4SLinus Torvalds } 50491da177e4SLinus Torvalds 50501da177e4SLinus Torvalds /* Note, at this point, shp is locked down */ 50511da177e4SLinus Torvalds static int selinux_shm_shmctl(struct shmid_kernel *shp, int cmd) 50521da177e4SLinus Torvalds { 50531da177e4SLinus Torvalds int perms; 50541da177e4SLinus Torvalds int err; 50551da177e4SLinus Torvalds 50561da177e4SLinus Torvalds switch (cmd) { 50571da177e4SLinus Torvalds case IPC_INFO: 50581da177e4SLinus Torvalds case SHM_INFO: 50591da177e4SLinus Torvalds /* No specific object, just general system-wide information. */ 50601da177e4SLinus Torvalds return task_has_system(current, SYSTEM__IPC_INFO); 50611da177e4SLinus Torvalds case IPC_STAT: 50621da177e4SLinus Torvalds case SHM_STAT: 50631da177e4SLinus Torvalds perms = SHM__GETATTR | SHM__ASSOCIATE; 50641da177e4SLinus Torvalds break; 50651da177e4SLinus Torvalds case IPC_SET: 50661da177e4SLinus Torvalds perms = SHM__SETATTR; 50671da177e4SLinus Torvalds break; 50681da177e4SLinus Torvalds case SHM_LOCK: 50691da177e4SLinus Torvalds case SHM_UNLOCK: 50701da177e4SLinus Torvalds perms = SHM__LOCK; 50711da177e4SLinus Torvalds break; 50721da177e4SLinus Torvalds case IPC_RMID: 50731da177e4SLinus Torvalds perms = SHM__DESTROY; 50741da177e4SLinus Torvalds break; 50751da177e4SLinus Torvalds default: 50761da177e4SLinus Torvalds return 0; 50771da177e4SLinus Torvalds } 50781da177e4SLinus Torvalds 50796af963f1SStephen Smalley err = ipc_has_perm(&shp->shm_perm, perms); 50801da177e4SLinus Torvalds return err; 50811da177e4SLinus Torvalds } 50821da177e4SLinus Torvalds 50831da177e4SLinus Torvalds static int selinux_shm_shmat(struct shmid_kernel *shp, 50841da177e4SLinus Torvalds char __user *shmaddr, int shmflg) 50851da177e4SLinus Torvalds { 50861da177e4SLinus Torvalds u32 perms; 50871da177e4SLinus Torvalds int rc; 50881da177e4SLinus Torvalds 50891da177e4SLinus Torvalds rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg); 50901da177e4SLinus Torvalds if (rc) 50911da177e4SLinus Torvalds return rc; 50921da177e4SLinus Torvalds 50931da177e4SLinus Torvalds if (shmflg & SHM_RDONLY) 50941da177e4SLinus Torvalds perms = SHM__READ; 50951da177e4SLinus Torvalds else 50961da177e4SLinus Torvalds perms = SHM__READ | SHM__WRITE; 50971da177e4SLinus Torvalds 50986af963f1SStephen Smalley return ipc_has_perm(&shp->shm_perm, perms); 50991da177e4SLinus Torvalds } 51001da177e4SLinus Torvalds 51011da177e4SLinus Torvalds /* Semaphore security operations */ 51021da177e4SLinus Torvalds static int selinux_sem_alloc_security(struct sem_array *sma) 51031da177e4SLinus Torvalds { 51041da177e4SLinus Torvalds struct ipc_security_struct *isec; 51051da177e4SLinus Torvalds struct avc_audit_data ad; 5106*275bb41eSDavid Howells u32 sid = current_sid(); 51071da177e4SLinus Torvalds int rc; 51081da177e4SLinus Torvalds 51091da177e4SLinus Torvalds rc = ipc_alloc_security(current, &sma->sem_perm, SECCLASS_SEM); 51101da177e4SLinus Torvalds if (rc) 51111da177e4SLinus Torvalds return rc; 51121da177e4SLinus Torvalds 51131da177e4SLinus Torvalds isec = sma->sem_perm.security; 51141da177e4SLinus Torvalds 51151da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, IPC); 51161da177e4SLinus Torvalds ad.u.ipc_id = sma->sem_perm.key; 51171da177e4SLinus Torvalds 5118*275bb41eSDavid Howells rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, 51191da177e4SLinus Torvalds SEM__CREATE, &ad); 51201da177e4SLinus Torvalds if (rc) { 51211da177e4SLinus Torvalds ipc_free_security(&sma->sem_perm); 51221da177e4SLinus Torvalds return rc; 51231da177e4SLinus Torvalds } 51241da177e4SLinus Torvalds return 0; 51251da177e4SLinus Torvalds } 51261da177e4SLinus Torvalds 51271da177e4SLinus Torvalds static void selinux_sem_free_security(struct sem_array *sma) 51281da177e4SLinus Torvalds { 51291da177e4SLinus Torvalds ipc_free_security(&sma->sem_perm); 51301da177e4SLinus Torvalds } 51311da177e4SLinus Torvalds 51321da177e4SLinus Torvalds static int selinux_sem_associate(struct sem_array *sma, int semflg) 51331da177e4SLinus Torvalds { 51341da177e4SLinus Torvalds struct ipc_security_struct *isec; 51351da177e4SLinus Torvalds struct avc_audit_data ad; 5136*275bb41eSDavid Howells u32 sid = current_sid(); 51371da177e4SLinus Torvalds 51381da177e4SLinus Torvalds isec = sma->sem_perm.security; 51391da177e4SLinus Torvalds 51401da177e4SLinus Torvalds AVC_AUDIT_DATA_INIT(&ad, IPC); 51411da177e4SLinus Torvalds ad.u.ipc_id = sma->sem_perm.key; 51421da177e4SLinus Torvalds 5143*275bb41eSDavid Howells return avc_has_perm(sid, isec->sid, SECCLASS_SEM, 51441da177e4SLinus Torvalds SEM__ASSOCIATE, &ad); 51451da177e4SLinus Torvalds } 51461da177e4SLinus Torvalds 51471da177e4SLinus Torvalds /* Note, at this point, sma is locked down */ 51481da177e4SLinus Torvalds static int selinux_sem_semctl(struct sem_array *sma, int cmd) 51491da177e4SLinus Torvalds { 51501da177e4SLinus Torvalds int err; 51511da177e4SLinus Torvalds u32 perms; 51521da177e4SLinus Torvalds 51531da177e4SLinus Torvalds switch (cmd) { 51541da177e4SLinus Torvalds case IPC_INFO: 51551da177e4SLinus Torvalds case SEM_INFO: 51561da177e4SLinus Torvalds /* No specific object, just general system-wide information. */ 51571da177e4SLinus Torvalds return task_has_system(current, SYSTEM__IPC_INFO); 51581da177e4SLinus Torvalds case GETPID: 51591da177e4SLinus Torvalds case GETNCNT: 51601da177e4SLinus Torvalds case GETZCNT: 51611da177e4SLinus Torvalds perms = SEM__GETATTR; 51621da177e4SLinus Torvalds break; 51631da177e4SLinus Torvalds case GETVAL: 51641da177e4SLinus Torvalds case GETALL: 51651da177e4SLinus Torvalds perms = SEM__READ; 51661da177e4SLinus Torvalds break; 51671da177e4SLinus Torvalds case SETVAL: 51681da177e4SLinus Torvalds case SETALL: 51691da177e4SLinus Torvalds perms = SEM__WRITE; 51701da177e4SLinus Torvalds break; 51711da177e4SLinus Torvalds case IPC_RMID: 51721da177e4SLinus Torvalds perms = SEM__DESTROY; 51731da177e4SLinus Torvalds break; 51741da177e4SLinus Torvalds case IPC_SET: 51751da177e4SLinus Torvalds perms = SEM__SETATTR; 51761da177e4SLinus Torvalds break; 51771da177e4SLinus Torvalds case IPC_STAT: 51781da177e4SLinus Torvalds case SEM_STAT: 51791da177e4SLinus Torvalds perms = SEM__GETATTR | SEM__ASSOCIATE; 51801da177e4SLinus Torvalds break; 51811da177e4SLinus Torvalds default: 51821da177e4SLinus Torvalds return 0; 51831da177e4SLinus Torvalds } 51841da177e4SLinus Torvalds 51856af963f1SStephen Smalley err = ipc_has_perm(&sma->sem_perm, perms); 51861da177e4SLinus Torvalds return err; 51871da177e4SLinus Torvalds } 51881da177e4SLinus Torvalds 51891da177e4SLinus Torvalds static int selinux_sem_semop(struct sem_array *sma, 51901da177e4SLinus Torvalds struct sembuf *sops, unsigned nsops, int alter) 51911da177e4SLinus Torvalds { 51921da177e4SLinus Torvalds u32 perms; 51931da177e4SLinus Torvalds 51941da177e4SLinus Torvalds if (alter) 51951da177e4SLinus Torvalds perms = SEM__READ | SEM__WRITE; 51961da177e4SLinus Torvalds else 51971da177e4SLinus Torvalds perms = SEM__READ; 51981da177e4SLinus Torvalds 51996af963f1SStephen Smalley return ipc_has_perm(&sma->sem_perm, perms); 52001da177e4SLinus Torvalds } 52011da177e4SLinus Torvalds 52021da177e4SLinus Torvalds static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) 52031da177e4SLinus Torvalds { 52041da177e4SLinus Torvalds u32 av = 0; 52051da177e4SLinus Torvalds 52061da177e4SLinus Torvalds av = 0; 52071da177e4SLinus Torvalds if (flag & S_IRUGO) 52081da177e4SLinus Torvalds av |= IPC__UNIX_READ; 52091da177e4SLinus Torvalds if (flag & S_IWUGO) 52101da177e4SLinus Torvalds av |= IPC__UNIX_WRITE; 52111da177e4SLinus Torvalds 52121da177e4SLinus Torvalds if (av == 0) 52131da177e4SLinus Torvalds return 0; 52141da177e4SLinus Torvalds 52156af963f1SStephen Smalley return ipc_has_perm(ipcp, av); 52161da177e4SLinus Torvalds } 52171da177e4SLinus Torvalds 5218713a04aeSAhmed S. Darwish static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) 5219713a04aeSAhmed S. Darwish { 5220713a04aeSAhmed S. Darwish struct ipc_security_struct *isec = ipcp->security; 5221713a04aeSAhmed S. Darwish *secid = isec->sid; 5222713a04aeSAhmed S. Darwish } 5223713a04aeSAhmed S. Darwish 52241da177e4SLinus Torvalds static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode) 52251da177e4SLinus Torvalds { 52261da177e4SLinus Torvalds if (inode) 52271da177e4SLinus Torvalds inode_doinit_with_dentry(inode, dentry); 52281da177e4SLinus Torvalds } 52291da177e4SLinus Torvalds 52301da177e4SLinus Torvalds static int selinux_getprocattr(struct task_struct *p, 523104ff9708SAl Viro char *name, char **value) 52321da177e4SLinus Torvalds { 5233*275bb41eSDavid Howells const struct task_security_struct *__tsec; 52348c8570fbSDustin Kirkland u32 sid; 52351da177e4SLinus Torvalds int error; 523604ff9708SAl Viro unsigned len; 52371da177e4SLinus Torvalds 52381da177e4SLinus Torvalds if (current != p) { 52391da177e4SLinus Torvalds error = task_has_perm(current, p, PROCESS__GETATTR); 52401da177e4SLinus Torvalds if (error) 52411da177e4SLinus Torvalds return error; 52421da177e4SLinus Torvalds } 52431da177e4SLinus Torvalds 5244*275bb41eSDavid Howells rcu_read_lock(); 5245*275bb41eSDavid Howells __tsec = __task_cred(p)->security; 52461da177e4SLinus Torvalds 52471da177e4SLinus Torvalds if (!strcmp(name, "current")) 5248*275bb41eSDavid Howells sid = __tsec->sid; 52491da177e4SLinus Torvalds else if (!strcmp(name, "prev")) 5250*275bb41eSDavid Howells sid = __tsec->osid; 52511da177e4SLinus Torvalds else if (!strcmp(name, "exec")) 5252*275bb41eSDavid Howells sid = __tsec->exec_sid; 52531da177e4SLinus Torvalds else if (!strcmp(name, "fscreate")) 5254*275bb41eSDavid Howells sid = __tsec->create_sid; 52554eb582cfSMichael LeMay else if (!strcmp(name, "keycreate")) 5256*275bb41eSDavid Howells sid = __tsec->keycreate_sid; 525742c3e03eSEric Paris else if (!strcmp(name, "sockcreate")) 5258*275bb41eSDavid Howells sid = __tsec->sockcreate_sid; 52591da177e4SLinus Torvalds else 5260*275bb41eSDavid Howells goto invalid; 5261*275bb41eSDavid Howells rcu_read_unlock(); 52621da177e4SLinus Torvalds 52631da177e4SLinus Torvalds if (!sid) 52641da177e4SLinus Torvalds return 0; 52651da177e4SLinus Torvalds 526604ff9708SAl Viro error = security_sid_to_context(sid, value, &len); 526704ff9708SAl Viro if (error) 526804ff9708SAl Viro return error; 526904ff9708SAl Viro return len; 5270*275bb41eSDavid Howells 5271*275bb41eSDavid Howells invalid: 5272*275bb41eSDavid Howells rcu_read_unlock(); 5273*275bb41eSDavid Howells return -EINVAL; 52741da177e4SLinus Torvalds } 52751da177e4SLinus Torvalds 52761da177e4SLinus Torvalds static int selinux_setprocattr(struct task_struct *p, 52771da177e4SLinus Torvalds char *name, void *value, size_t size) 52781da177e4SLinus Torvalds { 52791da177e4SLinus Torvalds struct task_security_struct *tsec; 52800356357cSRoland McGrath struct task_struct *tracer; 52811da177e4SLinus Torvalds u32 sid = 0; 52821da177e4SLinus Torvalds int error; 52831da177e4SLinus Torvalds char *str = value; 52841da177e4SLinus Torvalds 52851da177e4SLinus Torvalds if (current != p) { 52861da177e4SLinus Torvalds /* SELinux only allows a process to change its own 52871da177e4SLinus Torvalds security attributes. */ 52881da177e4SLinus Torvalds return -EACCES; 52891da177e4SLinus Torvalds } 52901da177e4SLinus Torvalds 52911da177e4SLinus Torvalds /* 52921da177e4SLinus Torvalds * Basic control over ability to set these attributes at all. 52931da177e4SLinus Torvalds * current == p, but we'll pass them separately in case the 52941da177e4SLinus Torvalds * above restriction is ever removed. 52951da177e4SLinus Torvalds */ 52961da177e4SLinus Torvalds if (!strcmp(name, "exec")) 52971da177e4SLinus Torvalds error = task_has_perm(current, p, PROCESS__SETEXEC); 52981da177e4SLinus Torvalds else if (!strcmp(name, "fscreate")) 52991da177e4SLinus Torvalds error = task_has_perm(current, p, PROCESS__SETFSCREATE); 53004eb582cfSMichael LeMay else if (!strcmp(name, "keycreate")) 53014eb582cfSMichael LeMay error = task_has_perm(current, p, PROCESS__SETKEYCREATE); 530242c3e03eSEric Paris else if (!strcmp(name, "sockcreate")) 530342c3e03eSEric Paris error = task_has_perm(current, p, PROCESS__SETSOCKCREATE); 53041da177e4SLinus Torvalds else if (!strcmp(name, "current")) 53051da177e4SLinus Torvalds error = task_has_perm(current, p, PROCESS__SETCURRENT); 53061da177e4SLinus Torvalds else 53071da177e4SLinus Torvalds error = -EINVAL; 53081da177e4SLinus Torvalds if (error) 53091da177e4SLinus Torvalds return error; 53101da177e4SLinus Torvalds 53111da177e4SLinus Torvalds /* Obtain a SID for the context, if one was specified. */ 53121da177e4SLinus Torvalds if (size && str[1] && str[1] != '\n') { 53131da177e4SLinus Torvalds if (str[size-1] == '\n') { 53141da177e4SLinus Torvalds str[size-1] = 0; 53151da177e4SLinus Torvalds size--; 53161da177e4SLinus Torvalds } 53171da177e4SLinus Torvalds error = security_context_to_sid(value, size, &sid); 531812b29f34SStephen Smalley if (error == -EINVAL && !strcmp(name, "fscreate")) { 531912b29f34SStephen Smalley if (!capable(CAP_MAC_ADMIN)) 532012b29f34SStephen Smalley return error; 532112b29f34SStephen Smalley error = security_context_to_sid_force(value, size, 532212b29f34SStephen Smalley &sid); 532312b29f34SStephen Smalley } 53241da177e4SLinus Torvalds if (error) 53251da177e4SLinus Torvalds return error; 53261da177e4SLinus Torvalds } 53271da177e4SLinus Torvalds 53281da177e4SLinus Torvalds /* Permission checking based on the specified context is 53291da177e4SLinus Torvalds performed during the actual operation (execve, 53301da177e4SLinus Torvalds open/mkdir/...), when we know the full context of the 53311da177e4SLinus Torvalds operation. See selinux_bprm_set_security for the execve 53321da177e4SLinus Torvalds checks and may_create for the file creation checks. The 53331da177e4SLinus Torvalds operation will then fail if the context is not permitted. */ 5334b6dff3ecSDavid Howells tsec = p->cred->security; 53351da177e4SLinus Torvalds if (!strcmp(name, "exec")) 53361da177e4SLinus Torvalds tsec->exec_sid = sid; 53371da177e4SLinus Torvalds else if (!strcmp(name, "fscreate")) 53381da177e4SLinus Torvalds tsec->create_sid = sid; 53394eb582cfSMichael LeMay else if (!strcmp(name, "keycreate")) { 53404eb582cfSMichael LeMay error = may_create_key(sid, p); 53414eb582cfSMichael LeMay if (error) 53424eb582cfSMichael LeMay return error; 53434eb582cfSMichael LeMay tsec->keycreate_sid = sid; 534442c3e03eSEric Paris } else if (!strcmp(name, "sockcreate")) 534542c3e03eSEric Paris tsec->sockcreate_sid = sid; 534642c3e03eSEric Paris else if (!strcmp(name, "current")) { 53471da177e4SLinus Torvalds struct av_decision avd; 53481da177e4SLinus Torvalds 53491da177e4SLinus Torvalds if (sid == 0) 53501da177e4SLinus Torvalds return -EINVAL; 5351d9250deaSKaiGai Kohei /* 5352d9250deaSKaiGai Kohei * SELinux allows to change context in the following case only. 5353d9250deaSKaiGai Kohei * - Single threaded processes. 5354d9250deaSKaiGai Kohei * - Multi threaded processes intend to change its context into 5355d9250deaSKaiGai Kohei * more restricted domain (defined by TYPEBOUNDS statement). 5356d9250deaSKaiGai Kohei */ 53571da177e4SLinus Torvalds if (atomic_read(&p->mm->mm_users) != 1) { 53581da177e4SLinus Torvalds struct task_struct *g, *t; 53591da177e4SLinus Torvalds struct mm_struct *mm = p->mm; 53601da177e4SLinus Torvalds read_lock(&tasklist_lock); 53612baf06dfSJames Morris do_each_thread(g, t) { 53621da177e4SLinus Torvalds if (t->mm == mm && t != p) { 53631da177e4SLinus Torvalds read_unlock(&tasklist_lock); 5364d9250deaSKaiGai Kohei error = security_bounded_transition(tsec->sid, sid); 5365d9250deaSKaiGai Kohei if (!error) 5366d9250deaSKaiGai Kohei goto boundary_ok; 5367d9250deaSKaiGai Kohei 5368d9250deaSKaiGai Kohei return error; 53691da177e4SLinus Torvalds } 53702baf06dfSJames Morris } while_each_thread(g, t); 53711da177e4SLinus Torvalds read_unlock(&tasklist_lock); 53721da177e4SLinus Torvalds } 5373d9250deaSKaiGai Kohei boundary_ok: 53741da177e4SLinus Torvalds 53751da177e4SLinus Torvalds /* Check permissions for the transition. */ 53761da177e4SLinus Torvalds error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS, 53771da177e4SLinus Torvalds PROCESS__DYNTRANSITION, NULL); 53781da177e4SLinus Torvalds if (error) 53791da177e4SLinus Torvalds return error; 53801da177e4SLinus Torvalds 53811da177e4SLinus Torvalds /* Check for ptracing, and update the task SID if ok. 53821da177e4SLinus Torvalds Otherwise, leave SID unchanged and fail. */ 53831da177e4SLinus Torvalds task_lock(p); 53840356357cSRoland McGrath rcu_read_lock(); 53850d094efeSRoland McGrath tracer = tracehook_tracer_task(p); 53860356357cSRoland McGrath if (tracer != NULL) { 5387*275bb41eSDavid Howells u32 ptsid = task_sid(tracer); 53880356357cSRoland McGrath rcu_read_unlock(); 53890356357cSRoland McGrath error = avc_has_perm_noaudit(ptsid, sid, 53901da177e4SLinus Torvalds SECCLASS_PROCESS, 53912c3c05dbSStephen Smalley PROCESS__PTRACE, 0, &avd); 53921da177e4SLinus Torvalds if (!error) 53931da177e4SLinus Torvalds tsec->sid = sid; 53941da177e4SLinus Torvalds task_unlock(p); 53950356357cSRoland McGrath avc_audit(ptsid, sid, SECCLASS_PROCESS, 53961da177e4SLinus Torvalds PROCESS__PTRACE, &avd, error, NULL); 53971da177e4SLinus Torvalds if (error) 53981da177e4SLinus Torvalds return error; 53991da177e4SLinus Torvalds } else { 54000356357cSRoland McGrath rcu_read_unlock(); 54011da177e4SLinus Torvalds tsec->sid = sid; 54021da177e4SLinus Torvalds task_unlock(p); 54031da177e4SLinus Torvalds } 5404828dfe1dSEric Paris } else 54051da177e4SLinus Torvalds return -EINVAL; 54061da177e4SLinus Torvalds 54071da177e4SLinus Torvalds return size; 54081da177e4SLinus Torvalds } 54091da177e4SLinus Torvalds 5410dc49c1f9SCatherine Zhang static int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) 5411dc49c1f9SCatherine Zhang { 5412dc49c1f9SCatherine Zhang return security_sid_to_context(secid, secdata, seclen); 5413dc49c1f9SCatherine Zhang } 5414dc49c1f9SCatherine Zhang 54157bf570dcSDavid Howells static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) 541663cb3449SDavid Howells { 541763cb3449SDavid Howells return security_context_to_sid(secdata, seclen, secid); 541863cb3449SDavid Howells } 541963cb3449SDavid Howells 5420dc49c1f9SCatherine Zhang static void selinux_release_secctx(char *secdata, u32 seclen) 5421dc49c1f9SCatherine Zhang { 5422dc49c1f9SCatherine Zhang kfree(secdata); 5423dc49c1f9SCatherine Zhang } 5424dc49c1f9SCatherine Zhang 5425d720024eSMichael LeMay #ifdef CONFIG_KEYS 5426d720024eSMichael LeMay 54277e047ef5SDavid Howells static int selinux_key_alloc(struct key *k, struct task_struct *tsk, 54287e047ef5SDavid Howells unsigned long flags) 5429d720024eSMichael LeMay { 5430*275bb41eSDavid Howells const struct task_security_struct *__tsec; 5431d720024eSMichael LeMay struct key_security_struct *ksec; 5432d720024eSMichael LeMay 5433d720024eSMichael LeMay ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL); 5434d720024eSMichael LeMay if (!ksec) 5435d720024eSMichael LeMay return -ENOMEM; 5436d720024eSMichael LeMay 5437*275bb41eSDavid Howells rcu_read_lock(); 5438*275bb41eSDavid Howells __tsec = __task_cred(tsk)->security; 5439*275bb41eSDavid Howells if (__tsec->keycreate_sid) 5440*275bb41eSDavid Howells ksec->sid = __tsec->keycreate_sid; 54414eb582cfSMichael LeMay else 5442*275bb41eSDavid Howells ksec->sid = __tsec->sid; 5443*275bb41eSDavid Howells rcu_read_unlock(); 5444d720024eSMichael LeMay 5445*275bb41eSDavid Howells k->security = ksec; 5446d720024eSMichael LeMay return 0; 5447d720024eSMichael LeMay } 5448d720024eSMichael LeMay 5449d720024eSMichael LeMay static void selinux_key_free(struct key *k) 5450d720024eSMichael LeMay { 5451d720024eSMichael LeMay struct key_security_struct *ksec = k->security; 5452d720024eSMichael LeMay 5453d720024eSMichael LeMay k->security = NULL; 5454d720024eSMichael LeMay kfree(ksec); 5455d720024eSMichael LeMay } 5456d720024eSMichael LeMay 5457d720024eSMichael LeMay static int selinux_key_permission(key_ref_t key_ref, 5458d720024eSMichael LeMay struct task_struct *ctx, 5459d720024eSMichael LeMay key_perm_t perm) 5460d720024eSMichael LeMay { 5461d720024eSMichael LeMay struct key *key; 5462d720024eSMichael LeMay struct key_security_struct *ksec; 5463*275bb41eSDavid Howells u32 sid; 5464d720024eSMichael LeMay 5465d720024eSMichael LeMay /* if no specific permissions are requested, we skip the 5466d720024eSMichael LeMay permission check. No serious, additional covert channels 5467d720024eSMichael LeMay appear to be created. */ 5468d720024eSMichael LeMay if (perm == 0) 5469d720024eSMichael LeMay return 0; 5470d720024eSMichael LeMay 5471*275bb41eSDavid Howells sid = task_sid(ctx); 5472*275bb41eSDavid Howells 5473*275bb41eSDavid Howells key = key_ref_to_ptr(key_ref); 5474*275bb41eSDavid Howells ksec = key->security; 5475*275bb41eSDavid Howells 5476*275bb41eSDavid Howells return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL); 5477d720024eSMichael LeMay } 5478d720024eSMichael LeMay 547970a5bb72SDavid Howells static int selinux_key_getsecurity(struct key *key, char **_buffer) 548070a5bb72SDavid Howells { 548170a5bb72SDavid Howells struct key_security_struct *ksec = key->security; 548270a5bb72SDavid Howells char *context = NULL; 548370a5bb72SDavid Howells unsigned len; 548470a5bb72SDavid Howells int rc; 548570a5bb72SDavid Howells 548670a5bb72SDavid Howells rc = security_sid_to_context(ksec->sid, &context, &len); 548770a5bb72SDavid Howells if (!rc) 548870a5bb72SDavid Howells rc = len; 548970a5bb72SDavid Howells *_buffer = context; 549070a5bb72SDavid Howells return rc; 549170a5bb72SDavid Howells } 549270a5bb72SDavid Howells 5493d720024eSMichael LeMay #endif 5494d720024eSMichael LeMay 54951da177e4SLinus Torvalds static struct security_operations selinux_ops = { 5496076c54c5SAhmed S. Darwish .name = "selinux", 5497076c54c5SAhmed S. Darwish 54985cd9c58fSDavid Howells .ptrace_may_access = selinux_ptrace_may_access, 54995cd9c58fSDavid Howells .ptrace_traceme = selinux_ptrace_traceme, 55001da177e4SLinus Torvalds .capget = selinux_capget, 55011da177e4SLinus Torvalds .capset_check = selinux_capset_check, 55021da177e4SLinus Torvalds .capset_set = selinux_capset_set, 55031da177e4SLinus Torvalds .sysctl = selinux_sysctl, 55041da177e4SLinus Torvalds .capable = selinux_capable, 55051da177e4SLinus Torvalds .quotactl = selinux_quotactl, 55061da177e4SLinus Torvalds .quota_on = selinux_quota_on, 55071da177e4SLinus Torvalds .syslog = selinux_syslog, 55081da177e4SLinus Torvalds .vm_enough_memory = selinux_vm_enough_memory, 55091da177e4SLinus Torvalds 55101da177e4SLinus Torvalds .netlink_send = selinux_netlink_send, 55111da177e4SLinus Torvalds .netlink_recv = selinux_netlink_recv, 55121da177e4SLinus Torvalds 55131da177e4SLinus Torvalds .bprm_alloc_security = selinux_bprm_alloc_security, 55141da177e4SLinus Torvalds .bprm_free_security = selinux_bprm_free_security, 55151da177e4SLinus Torvalds .bprm_apply_creds = selinux_bprm_apply_creds, 55161da177e4SLinus Torvalds .bprm_post_apply_creds = selinux_bprm_post_apply_creds, 55171da177e4SLinus Torvalds .bprm_set_security = selinux_bprm_set_security, 55181da177e4SLinus Torvalds .bprm_check_security = selinux_bprm_check_security, 55191da177e4SLinus Torvalds .bprm_secureexec = selinux_bprm_secureexec, 55201da177e4SLinus Torvalds 55211da177e4SLinus Torvalds .sb_alloc_security = selinux_sb_alloc_security, 55221da177e4SLinus Torvalds .sb_free_security = selinux_sb_free_security, 55231da177e4SLinus Torvalds .sb_copy_data = selinux_sb_copy_data, 55241da177e4SLinus Torvalds .sb_kern_mount = selinux_sb_kern_mount, 55252069f457SEric Paris .sb_show_options = selinux_sb_show_options, 55261da177e4SLinus Torvalds .sb_statfs = selinux_sb_statfs, 55271da177e4SLinus Torvalds .sb_mount = selinux_mount, 55281da177e4SLinus Torvalds .sb_umount = selinux_umount, 5529c9180a57SEric Paris .sb_set_mnt_opts = selinux_set_mnt_opts, 5530c9180a57SEric Paris .sb_clone_mnt_opts = selinux_sb_clone_mnt_opts, 5531e0007529SEric Paris .sb_parse_opts_str = selinux_parse_opts_str, 5532e0007529SEric Paris 55331da177e4SLinus Torvalds 55341da177e4SLinus Torvalds .inode_alloc_security = selinux_inode_alloc_security, 55351da177e4SLinus Torvalds .inode_free_security = selinux_inode_free_security, 55365e41ff9eSStephen Smalley .inode_init_security = selinux_inode_init_security, 55371da177e4SLinus Torvalds .inode_create = selinux_inode_create, 55381da177e4SLinus Torvalds .inode_link = selinux_inode_link, 55391da177e4SLinus Torvalds .inode_unlink = selinux_inode_unlink, 55401da177e4SLinus Torvalds .inode_symlink = selinux_inode_symlink, 55411da177e4SLinus Torvalds .inode_mkdir = selinux_inode_mkdir, 55421da177e4SLinus Torvalds .inode_rmdir = selinux_inode_rmdir, 55431da177e4SLinus Torvalds .inode_mknod = selinux_inode_mknod, 55441da177e4SLinus Torvalds .inode_rename = selinux_inode_rename, 55451da177e4SLinus Torvalds .inode_readlink = selinux_inode_readlink, 55461da177e4SLinus Torvalds .inode_follow_link = selinux_inode_follow_link, 55471da177e4SLinus Torvalds .inode_permission = selinux_inode_permission, 55481da177e4SLinus Torvalds .inode_setattr = selinux_inode_setattr, 55491da177e4SLinus Torvalds .inode_getattr = selinux_inode_getattr, 55501da177e4SLinus Torvalds .inode_setxattr = selinux_inode_setxattr, 55511da177e4SLinus Torvalds .inode_post_setxattr = selinux_inode_post_setxattr, 55521da177e4SLinus Torvalds .inode_getxattr = selinux_inode_getxattr, 55531da177e4SLinus Torvalds .inode_listxattr = selinux_inode_listxattr, 55541da177e4SLinus Torvalds .inode_removexattr = selinux_inode_removexattr, 55551da177e4SLinus Torvalds .inode_getsecurity = selinux_inode_getsecurity, 55561da177e4SLinus Torvalds .inode_setsecurity = selinux_inode_setsecurity, 55571da177e4SLinus Torvalds .inode_listsecurity = selinux_inode_listsecurity, 5558b5376771SSerge E. Hallyn .inode_need_killpriv = selinux_inode_need_killpriv, 5559b5376771SSerge E. Hallyn .inode_killpriv = selinux_inode_killpriv, 5560713a04aeSAhmed S. Darwish .inode_getsecid = selinux_inode_getsecid, 55611da177e4SLinus Torvalds 55621da177e4SLinus Torvalds .file_permission = selinux_file_permission, 55631da177e4SLinus Torvalds .file_alloc_security = selinux_file_alloc_security, 55641da177e4SLinus Torvalds .file_free_security = selinux_file_free_security, 55651da177e4SLinus Torvalds .file_ioctl = selinux_file_ioctl, 55661da177e4SLinus Torvalds .file_mmap = selinux_file_mmap, 55671da177e4SLinus Torvalds .file_mprotect = selinux_file_mprotect, 55681da177e4SLinus Torvalds .file_lock = selinux_file_lock, 55691da177e4SLinus Torvalds .file_fcntl = selinux_file_fcntl, 55701da177e4SLinus Torvalds .file_set_fowner = selinux_file_set_fowner, 55711da177e4SLinus Torvalds .file_send_sigiotask = selinux_file_send_sigiotask, 55721da177e4SLinus Torvalds .file_receive = selinux_file_receive, 55731da177e4SLinus Torvalds 5574788e7dd4SYuichi Nakamura .dentry_open = selinux_dentry_open, 5575788e7dd4SYuichi Nakamura 55761da177e4SLinus Torvalds .task_create = selinux_task_create, 5577f1752eecSDavid Howells .cred_alloc_security = selinux_cred_alloc_security, 5578f1752eecSDavid Howells .cred_free = selinux_cred_free, 55791da177e4SLinus Torvalds .task_setuid = selinux_task_setuid, 55801da177e4SLinus Torvalds .task_post_setuid = selinux_task_post_setuid, 55811da177e4SLinus Torvalds .task_setgid = selinux_task_setgid, 55821da177e4SLinus Torvalds .task_setpgid = selinux_task_setpgid, 55831da177e4SLinus Torvalds .task_getpgid = selinux_task_getpgid, 55841da177e4SLinus Torvalds .task_getsid = selinux_task_getsid, 5585f9008e4cSDavid Quigley .task_getsecid = selinux_task_getsecid, 55861da177e4SLinus Torvalds .task_setgroups = selinux_task_setgroups, 55871da177e4SLinus Torvalds .task_setnice = selinux_task_setnice, 558803e68060SJames Morris .task_setioprio = selinux_task_setioprio, 5589a1836a42SDavid Quigley .task_getioprio = selinux_task_getioprio, 55901da177e4SLinus Torvalds .task_setrlimit = selinux_task_setrlimit, 55911da177e4SLinus Torvalds .task_setscheduler = selinux_task_setscheduler, 55921da177e4SLinus Torvalds .task_getscheduler = selinux_task_getscheduler, 559335601547SDavid Quigley .task_movememory = selinux_task_movememory, 55941da177e4SLinus Torvalds .task_kill = selinux_task_kill, 55951da177e4SLinus Torvalds .task_wait = selinux_task_wait, 55961da177e4SLinus Torvalds .task_prctl = selinux_task_prctl, 55971da177e4SLinus Torvalds .task_reparent_to_init = selinux_task_reparent_to_init, 55981da177e4SLinus Torvalds .task_to_inode = selinux_task_to_inode, 55991da177e4SLinus Torvalds 56001da177e4SLinus Torvalds .ipc_permission = selinux_ipc_permission, 5601713a04aeSAhmed S. Darwish .ipc_getsecid = selinux_ipc_getsecid, 56021da177e4SLinus Torvalds 56031da177e4SLinus Torvalds .msg_msg_alloc_security = selinux_msg_msg_alloc_security, 56041da177e4SLinus Torvalds .msg_msg_free_security = selinux_msg_msg_free_security, 56051da177e4SLinus Torvalds 56061da177e4SLinus Torvalds .msg_queue_alloc_security = selinux_msg_queue_alloc_security, 56071da177e4SLinus Torvalds .msg_queue_free_security = selinux_msg_queue_free_security, 56081da177e4SLinus Torvalds .msg_queue_associate = selinux_msg_queue_associate, 56091da177e4SLinus Torvalds .msg_queue_msgctl = selinux_msg_queue_msgctl, 56101da177e4SLinus Torvalds .msg_queue_msgsnd = selinux_msg_queue_msgsnd, 56111da177e4SLinus Torvalds .msg_queue_msgrcv = selinux_msg_queue_msgrcv, 56121da177e4SLinus Torvalds 56131da177e4SLinus Torvalds .shm_alloc_security = selinux_shm_alloc_security, 56141da177e4SLinus Torvalds .shm_free_security = selinux_shm_free_security, 56151da177e4SLinus Torvalds .shm_associate = selinux_shm_associate, 56161da177e4SLinus Torvalds .shm_shmctl = selinux_shm_shmctl, 56171da177e4SLinus Torvalds .shm_shmat = selinux_shm_shmat, 56181da177e4SLinus Torvalds 56191da177e4SLinus Torvalds .sem_alloc_security = selinux_sem_alloc_security, 56201da177e4SLinus Torvalds .sem_free_security = selinux_sem_free_security, 56211da177e4SLinus Torvalds .sem_associate = selinux_sem_associate, 56221da177e4SLinus Torvalds .sem_semctl = selinux_sem_semctl, 56231da177e4SLinus Torvalds .sem_semop = selinux_sem_semop, 56241da177e4SLinus Torvalds 56251da177e4SLinus Torvalds .d_instantiate = selinux_d_instantiate, 56261da177e4SLinus Torvalds 56271da177e4SLinus Torvalds .getprocattr = selinux_getprocattr, 56281da177e4SLinus Torvalds .setprocattr = selinux_setprocattr, 56291da177e4SLinus Torvalds 5630dc49c1f9SCatherine Zhang .secid_to_secctx = selinux_secid_to_secctx, 563163cb3449SDavid Howells .secctx_to_secid = selinux_secctx_to_secid, 5632dc49c1f9SCatherine Zhang .release_secctx = selinux_release_secctx, 5633dc49c1f9SCatherine Zhang 56341da177e4SLinus Torvalds .unix_stream_connect = selinux_socket_unix_stream_connect, 56351da177e4SLinus Torvalds .unix_may_send = selinux_socket_unix_may_send, 56361da177e4SLinus Torvalds 56371da177e4SLinus Torvalds .socket_create = selinux_socket_create, 56381da177e4SLinus Torvalds .socket_post_create = selinux_socket_post_create, 56391da177e4SLinus Torvalds .socket_bind = selinux_socket_bind, 56401da177e4SLinus Torvalds .socket_connect = selinux_socket_connect, 56411da177e4SLinus Torvalds .socket_listen = selinux_socket_listen, 56421da177e4SLinus Torvalds .socket_accept = selinux_socket_accept, 56431da177e4SLinus Torvalds .socket_sendmsg = selinux_socket_sendmsg, 56441da177e4SLinus Torvalds .socket_recvmsg = selinux_socket_recvmsg, 56451da177e4SLinus Torvalds .socket_getsockname = selinux_socket_getsockname, 56461da177e4SLinus Torvalds .socket_getpeername = selinux_socket_getpeername, 56471da177e4SLinus Torvalds .socket_getsockopt = selinux_socket_getsockopt, 56481da177e4SLinus Torvalds .socket_setsockopt = selinux_socket_setsockopt, 56491da177e4SLinus Torvalds .socket_shutdown = selinux_socket_shutdown, 56501da177e4SLinus Torvalds .socket_sock_rcv_skb = selinux_socket_sock_rcv_skb, 56512c7946a7SCatherine Zhang .socket_getpeersec_stream = selinux_socket_getpeersec_stream, 56522c7946a7SCatherine Zhang .socket_getpeersec_dgram = selinux_socket_getpeersec_dgram, 56531da177e4SLinus Torvalds .sk_alloc_security = selinux_sk_alloc_security, 56541da177e4SLinus Torvalds .sk_free_security = selinux_sk_free_security, 5655892c141eSVenkat Yekkirala .sk_clone_security = selinux_sk_clone_security, 5656beb8d13bSVenkat Yekkirala .sk_getsecid = selinux_sk_getsecid, 56574237c75cSVenkat Yekkirala .sock_graft = selinux_sock_graft, 56584237c75cSVenkat Yekkirala .inet_conn_request = selinux_inet_conn_request, 56594237c75cSVenkat Yekkirala .inet_csk_clone = selinux_inet_csk_clone, 56606b877699SVenkat Yekkirala .inet_conn_established = selinux_inet_conn_established, 56614237c75cSVenkat Yekkirala .req_classify_flow = selinux_req_classify_flow, 5662d28d1e08STrent Jaeger 5663d28d1e08STrent Jaeger #ifdef CONFIG_SECURITY_NETWORK_XFRM 5664d28d1e08STrent Jaeger .xfrm_policy_alloc_security = selinux_xfrm_policy_alloc, 5665d28d1e08STrent Jaeger .xfrm_policy_clone_security = selinux_xfrm_policy_clone, 5666d28d1e08STrent Jaeger .xfrm_policy_free_security = selinux_xfrm_policy_free, 5667c8c05a8eSCatherine Zhang .xfrm_policy_delete_security = selinux_xfrm_policy_delete, 5668d28d1e08STrent Jaeger .xfrm_state_alloc_security = selinux_xfrm_state_alloc, 5669d28d1e08STrent Jaeger .xfrm_state_free_security = selinux_xfrm_state_free, 5670c8c05a8eSCatherine Zhang .xfrm_state_delete_security = selinux_xfrm_state_delete, 5671d28d1e08STrent Jaeger .xfrm_policy_lookup = selinux_xfrm_policy_lookup, 5672e0d1caa7SVenkat Yekkirala .xfrm_state_pol_flow_match = selinux_xfrm_state_pol_flow_match, 5673e0d1caa7SVenkat Yekkirala .xfrm_decode_session = selinux_xfrm_decode_session, 56741da177e4SLinus Torvalds #endif 5675d720024eSMichael LeMay 5676d720024eSMichael LeMay #ifdef CONFIG_KEYS 5677d720024eSMichael LeMay .key_alloc = selinux_key_alloc, 5678d720024eSMichael LeMay .key_free = selinux_key_free, 5679d720024eSMichael LeMay .key_permission = selinux_key_permission, 568070a5bb72SDavid Howells .key_getsecurity = selinux_key_getsecurity, 5681d720024eSMichael LeMay #endif 56829d57a7f9SAhmed S. Darwish 56839d57a7f9SAhmed S. Darwish #ifdef CONFIG_AUDIT 56849d57a7f9SAhmed S. Darwish .audit_rule_init = selinux_audit_rule_init, 56859d57a7f9SAhmed S. Darwish .audit_rule_known = selinux_audit_rule_known, 56869d57a7f9SAhmed S. Darwish .audit_rule_match = selinux_audit_rule_match, 56879d57a7f9SAhmed S. Darwish .audit_rule_free = selinux_audit_rule_free, 56889d57a7f9SAhmed S. Darwish #endif 56891da177e4SLinus Torvalds }; 56901da177e4SLinus Torvalds 56911da177e4SLinus Torvalds static __init int selinux_init(void) 56921da177e4SLinus Torvalds { 56931da177e4SLinus Torvalds struct task_security_struct *tsec; 56941da177e4SLinus Torvalds 5695076c54c5SAhmed S. Darwish if (!security_module_enable(&selinux_ops)) { 5696076c54c5SAhmed S. Darwish selinux_enabled = 0; 5697076c54c5SAhmed S. Darwish return 0; 5698076c54c5SAhmed S. Darwish } 5699076c54c5SAhmed S. Darwish 57001da177e4SLinus Torvalds if (!selinux_enabled) { 57011da177e4SLinus Torvalds printk(KERN_INFO "SELinux: Disabled at boot.\n"); 57021da177e4SLinus Torvalds return 0; 57031da177e4SLinus Torvalds } 57041da177e4SLinus Torvalds 57051da177e4SLinus Torvalds printk(KERN_INFO "SELinux: Initializing.\n"); 57061da177e4SLinus Torvalds 57071da177e4SLinus Torvalds /* Set the security state for the initial task. */ 5708f1752eecSDavid Howells if (cred_alloc_security(current->cred)) 57091da177e4SLinus Torvalds panic("SELinux: Failed to initialize initial task.\n"); 5710b6dff3ecSDavid Howells tsec = current->cred->security; 57111da177e4SLinus Torvalds tsec->osid = tsec->sid = SECINITSID_KERNEL; 57121da177e4SLinus Torvalds 57137cae7e26SJames Morris sel_inode_cache = kmem_cache_create("selinux_inode_security", 57147cae7e26SJames Morris sizeof(struct inode_security_struct), 571520c2df83SPaul Mundt 0, SLAB_PANIC, NULL); 57161da177e4SLinus Torvalds avc_init(); 57171da177e4SLinus Torvalds 57186f0f0fd4SJames Morris secondary_ops = security_ops; 57191da177e4SLinus Torvalds if (!secondary_ops) 57201da177e4SLinus Torvalds panic("SELinux: No initial security operations\n"); 57211da177e4SLinus Torvalds if (register_security(&selinux_ops)) 57221da177e4SLinus Torvalds panic("SELinux: Unable to register with kernel.\n"); 57231da177e4SLinus Torvalds 5724828dfe1dSEric Paris if (selinux_enforcing) 5725fadcdb45SEric Paris printk(KERN_DEBUG "SELinux: Starting in enforcing mode\n"); 5726828dfe1dSEric Paris else 5727fadcdb45SEric Paris printk(KERN_DEBUG "SELinux: Starting in permissive mode\n"); 5728d720024eSMichael LeMay 57291da177e4SLinus Torvalds return 0; 57301da177e4SLinus Torvalds } 57311da177e4SLinus Torvalds 57321da177e4SLinus Torvalds void selinux_complete_init(void) 57331da177e4SLinus Torvalds { 5734fadcdb45SEric Paris printk(KERN_DEBUG "SELinux: Completing initialization.\n"); 57351da177e4SLinus Torvalds 57361da177e4SLinus Torvalds /* Set up any superblocks initialized prior to the policy load. */ 5737fadcdb45SEric Paris printk(KERN_DEBUG "SELinux: Setting up existing superblocks.\n"); 5738ba0c19edSStephen Smalley spin_lock(&sb_lock); 57391da177e4SLinus Torvalds spin_lock(&sb_security_lock); 57401da177e4SLinus Torvalds next_sb: 57411da177e4SLinus Torvalds if (!list_empty(&superblock_security_head)) { 57421da177e4SLinus Torvalds struct superblock_security_struct *sbsec = 57431da177e4SLinus Torvalds list_entry(superblock_security_head.next, 57441da177e4SLinus Torvalds struct superblock_security_struct, 57451da177e4SLinus Torvalds list); 57461da177e4SLinus Torvalds struct super_block *sb = sbsec->sb; 57471da177e4SLinus Torvalds sb->s_count++; 57481da177e4SLinus Torvalds spin_unlock(&sb_security_lock); 5749ba0c19edSStephen Smalley spin_unlock(&sb_lock); 57501da177e4SLinus Torvalds down_read(&sb->s_umount); 57511da177e4SLinus Torvalds if (sb->s_root) 57521da177e4SLinus Torvalds superblock_doinit(sb, NULL); 57531da177e4SLinus Torvalds drop_super(sb); 5754ba0c19edSStephen Smalley spin_lock(&sb_lock); 57551da177e4SLinus Torvalds spin_lock(&sb_security_lock); 57561da177e4SLinus Torvalds list_del_init(&sbsec->list); 57571da177e4SLinus Torvalds goto next_sb; 57581da177e4SLinus Torvalds } 57591da177e4SLinus Torvalds spin_unlock(&sb_security_lock); 5760ba0c19edSStephen Smalley spin_unlock(&sb_lock); 57611da177e4SLinus Torvalds } 57621da177e4SLinus Torvalds 57631da177e4SLinus Torvalds /* SELinux requires early initialization in order to label 57641da177e4SLinus Torvalds all processes and objects when they are created. */ 57651da177e4SLinus Torvalds security_initcall(selinux_init); 57661da177e4SLinus Torvalds 5767c2b507fdSStephen Smalley #if defined(CONFIG_NETFILTER) 57681da177e4SLinus Torvalds 5769effad8dfSPaul Moore static struct nf_hook_ops selinux_ipv4_ops[] = { 5770effad8dfSPaul Moore { 5771effad8dfSPaul Moore .hook = selinux_ipv4_postroute, 57721da177e4SLinus Torvalds .owner = THIS_MODULE, 57731da177e4SLinus Torvalds .pf = PF_INET, 57746e23ae2aSPatrick McHardy .hooknum = NF_INET_POST_ROUTING, 57751da177e4SLinus Torvalds .priority = NF_IP_PRI_SELINUX_LAST, 5776effad8dfSPaul Moore }, 5777effad8dfSPaul Moore { 5778effad8dfSPaul Moore .hook = selinux_ipv4_forward, 5779effad8dfSPaul Moore .owner = THIS_MODULE, 5780effad8dfSPaul Moore .pf = PF_INET, 5781effad8dfSPaul Moore .hooknum = NF_INET_FORWARD, 5782effad8dfSPaul Moore .priority = NF_IP_PRI_SELINUX_FIRST, 5783948bf85cSPaul Moore }, 5784948bf85cSPaul Moore { 5785948bf85cSPaul Moore .hook = selinux_ipv4_output, 5786948bf85cSPaul Moore .owner = THIS_MODULE, 5787948bf85cSPaul Moore .pf = PF_INET, 5788948bf85cSPaul Moore .hooknum = NF_INET_LOCAL_OUT, 5789948bf85cSPaul Moore .priority = NF_IP_PRI_SELINUX_FIRST, 5790effad8dfSPaul Moore } 57911da177e4SLinus Torvalds }; 57921da177e4SLinus Torvalds 57931da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 57941da177e4SLinus Torvalds 5795effad8dfSPaul Moore static struct nf_hook_ops selinux_ipv6_ops[] = { 5796effad8dfSPaul Moore { 5797effad8dfSPaul Moore .hook = selinux_ipv6_postroute, 57981da177e4SLinus Torvalds .owner = THIS_MODULE, 57991da177e4SLinus Torvalds .pf = PF_INET6, 58006e23ae2aSPatrick McHardy .hooknum = NF_INET_POST_ROUTING, 58011da177e4SLinus Torvalds .priority = NF_IP6_PRI_SELINUX_LAST, 5802effad8dfSPaul Moore }, 5803effad8dfSPaul Moore { 5804effad8dfSPaul Moore .hook = selinux_ipv6_forward, 5805effad8dfSPaul Moore .owner = THIS_MODULE, 5806effad8dfSPaul Moore .pf = PF_INET6, 5807effad8dfSPaul Moore .hooknum = NF_INET_FORWARD, 5808effad8dfSPaul Moore .priority = NF_IP6_PRI_SELINUX_FIRST, 5809effad8dfSPaul Moore } 58101da177e4SLinus Torvalds }; 58111da177e4SLinus Torvalds 58121da177e4SLinus Torvalds #endif /* IPV6 */ 58131da177e4SLinus Torvalds 58141da177e4SLinus Torvalds static int __init selinux_nf_ip_init(void) 58151da177e4SLinus Torvalds { 58161da177e4SLinus Torvalds int err = 0; 58171da177e4SLinus Torvalds 58181da177e4SLinus Torvalds if (!selinux_enabled) 58191da177e4SLinus Torvalds goto out; 58201da177e4SLinus Torvalds 5821fadcdb45SEric Paris printk(KERN_DEBUG "SELinux: Registering netfilter hooks\n"); 58221da177e4SLinus Torvalds 58236c5a9d2eSAlexey Dobriyan err = nf_register_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops)); 58241da177e4SLinus Torvalds if (err) 58256c5a9d2eSAlexey Dobriyan panic("SELinux: nf_register_hooks for IPv4: error %d\n", err); 58261da177e4SLinus Torvalds 58271da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 58286c5a9d2eSAlexey Dobriyan err = nf_register_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops)); 58291da177e4SLinus Torvalds if (err) 58306c5a9d2eSAlexey Dobriyan panic("SELinux: nf_register_hooks for IPv6: error %d\n", err); 58311da177e4SLinus Torvalds #endif /* IPV6 */ 5832d28d1e08STrent Jaeger 58331da177e4SLinus Torvalds out: 58341da177e4SLinus Torvalds return err; 58351da177e4SLinus Torvalds } 58361da177e4SLinus Torvalds 58371da177e4SLinus Torvalds __initcall(selinux_nf_ip_init); 58381da177e4SLinus Torvalds 58391da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE 58401da177e4SLinus Torvalds static void selinux_nf_ip_exit(void) 58411da177e4SLinus Torvalds { 5842fadcdb45SEric Paris printk(KERN_DEBUG "SELinux: Unregistering netfilter hooks\n"); 58431da177e4SLinus Torvalds 58446c5a9d2eSAlexey Dobriyan nf_unregister_hooks(selinux_ipv4_ops, ARRAY_SIZE(selinux_ipv4_ops)); 58451da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 58466c5a9d2eSAlexey Dobriyan nf_unregister_hooks(selinux_ipv6_ops, ARRAY_SIZE(selinux_ipv6_ops)); 58471da177e4SLinus Torvalds #endif /* IPV6 */ 58481da177e4SLinus Torvalds } 58491da177e4SLinus Torvalds #endif 58501da177e4SLinus Torvalds 5851c2b507fdSStephen Smalley #else /* CONFIG_NETFILTER */ 58521da177e4SLinus Torvalds 58531da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE 58541da177e4SLinus Torvalds #define selinux_nf_ip_exit() 58551da177e4SLinus Torvalds #endif 58561da177e4SLinus Torvalds 5857c2b507fdSStephen Smalley #endif /* CONFIG_NETFILTER */ 58581da177e4SLinus Torvalds 58591da177e4SLinus Torvalds #ifdef CONFIG_SECURITY_SELINUX_DISABLE 5860828dfe1dSEric Paris static int selinux_disabled; 5861828dfe1dSEric Paris 58621da177e4SLinus Torvalds int selinux_disable(void) 58631da177e4SLinus Torvalds { 58641da177e4SLinus Torvalds extern void exit_sel_fs(void); 58651da177e4SLinus Torvalds 58661da177e4SLinus Torvalds if (ss_initialized) { 58671da177e4SLinus Torvalds /* Not permitted after initial policy load. */ 58681da177e4SLinus Torvalds return -EINVAL; 58691da177e4SLinus Torvalds } 58701da177e4SLinus Torvalds 58711da177e4SLinus Torvalds if (selinux_disabled) { 58721da177e4SLinus Torvalds /* Only do this once. */ 58731da177e4SLinus Torvalds return -EINVAL; 58741da177e4SLinus Torvalds } 58751da177e4SLinus Torvalds 58761da177e4SLinus Torvalds printk(KERN_INFO "SELinux: Disabled at runtime.\n"); 58771da177e4SLinus Torvalds 58781da177e4SLinus Torvalds selinux_disabled = 1; 587930d55280SStephen Smalley selinux_enabled = 0; 58801da177e4SLinus Torvalds 58811da177e4SLinus Torvalds /* Reset security_ops to the secondary module, dummy or capability. */ 58821da177e4SLinus Torvalds security_ops = secondary_ops; 58831da177e4SLinus Torvalds 58841da177e4SLinus Torvalds /* Unregister netfilter hooks. */ 58851da177e4SLinus Torvalds selinux_nf_ip_exit(); 58861da177e4SLinus Torvalds 58871da177e4SLinus Torvalds /* Unregister selinuxfs. */ 58881da177e4SLinus Torvalds exit_sel_fs(); 58891da177e4SLinus Torvalds 58901da177e4SLinus Torvalds return 0; 58911da177e4SLinus Torvalds } 58921da177e4SLinus Torvalds #endif 5893