18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * NSA Security-Enhanced Linux (SELinux) security module 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This file contains the SELinux hook function implementations. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Stephen Smalley, <sds@tycho.nsa.gov> 88c2ecf20Sopenharmony_ci * Chris Vance, <cvance@nai.com> 98c2ecf20Sopenharmony_ci * Wayne Salamon, <wsalamon@nai.com> 108c2ecf20Sopenharmony_ci * James Morris <jmorris@redhat.com> 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Copyright (C) 2001,2002 Networks Associates Technology, Inc. 138c2ecf20Sopenharmony_ci * Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com> 148c2ecf20Sopenharmony_ci * Eric Paris <eparis@redhat.com> 158c2ecf20Sopenharmony_ci * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. 168c2ecf20Sopenharmony_ci * <dgoeddel@trustedcs.com> 178c2ecf20Sopenharmony_ci * Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P. 188c2ecf20Sopenharmony_ci * Paul Moore <paul@paul-moore.com> 198c2ecf20Sopenharmony_ci * Copyright (C) 2007 Hitachi Software Engineering Co., Ltd. 208c2ecf20Sopenharmony_ci * Yuichi Nakamura <ynakam@hitachisoft.jp> 218c2ecf20Sopenharmony_ci * Copyright (C) 2016 Mellanox Technologies 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <linux/init.h> 258c2ecf20Sopenharmony_ci#include <linux/kd.h> 268c2ecf20Sopenharmony_ci#include <linux/kernel.h> 278c2ecf20Sopenharmony_ci#include <linux/kernel_read_file.h> 288c2ecf20Sopenharmony_ci#include <linux/tracehook.h> 298c2ecf20Sopenharmony_ci#include <linux/errno.h> 308c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 318c2ecf20Sopenharmony_ci#include <linux/sched/task.h> 328c2ecf20Sopenharmony_ci#include <linux/lsm_hooks.h> 338c2ecf20Sopenharmony_ci#include <linux/xattr.h> 348c2ecf20Sopenharmony_ci#include <linux/capability.h> 358c2ecf20Sopenharmony_ci#include <linux/unistd.h> 368c2ecf20Sopenharmony_ci#include <linux/mm.h> 378c2ecf20Sopenharmony_ci#include <linux/mman.h> 388c2ecf20Sopenharmony_ci#include <linux/slab.h> 398c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 408c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 418c2ecf20Sopenharmony_ci#include <linux/swap.h> 428c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 438c2ecf20Sopenharmony_ci#include <linux/syscalls.h> 448c2ecf20Sopenharmony_ci#include <linux/dcache.h> 458c2ecf20Sopenharmony_ci#include <linux/file.h> 468c2ecf20Sopenharmony_ci#include <linux/fdtable.h> 478c2ecf20Sopenharmony_ci#include <linux/namei.h> 488c2ecf20Sopenharmony_ci#include <linux/mount.h> 498c2ecf20Sopenharmony_ci#include <linux/fs_context.h> 508c2ecf20Sopenharmony_ci#include <linux/fs_parser.h> 518c2ecf20Sopenharmony_ci#include <linux/netfilter_ipv4.h> 528c2ecf20Sopenharmony_ci#include <linux/netfilter_ipv6.h> 538c2ecf20Sopenharmony_ci#include <linux/tty.h> 548c2ecf20Sopenharmony_ci#include <net/icmp.h> 558c2ecf20Sopenharmony_ci#include <net/ip.h> /* for local_port_range[] */ 568c2ecf20Sopenharmony_ci#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */ 578c2ecf20Sopenharmony_ci#include <net/inet_connection_sock.h> 588c2ecf20Sopenharmony_ci#include <net/net_namespace.h> 598c2ecf20Sopenharmony_ci#include <net/netlabel.h> 608c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 618c2ecf20Sopenharmony_ci#include <asm/ioctls.h> 628c2ecf20Sopenharmony_ci#include <linux/atomic.h> 638c2ecf20Sopenharmony_ci#include <linux/bitops.h> 648c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 658c2ecf20Sopenharmony_ci#include <linux/netdevice.h> /* for network interface checks */ 668c2ecf20Sopenharmony_ci#include <net/netlink.h> 678c2ecf20Sopenharmony_ci#include <linux/tcp.h> 688c2ecf20Sopenharmony_ci#include <linux/udp.h> 698c2ecf20Sopenharmony_ci#include <linux/dccp.h> 708c2ecf20Sopenharmony_ci#include <linux/sctp.h> 718c2ecf20Sopenharmony_ci#include <net/sctp/structs.h> 728c2ecf20Sopenharmony_ci#include <linux/quota.h> 738c2ecf20Sopenharmony_ci#include <linux/un.h> /* for Unix socket types */ 748c2ecf20Sopenharmony_ci#include <net/af_unix.h> /* for Unix socket types */ 758c2ecf20Sopenharmony_ci#include <linux/parser.h> 768c2ecf20Sopenharmony_ci#include <linux/nfs_mount.h> 778c2ecf20Sopenharmony_ci#include <net/ipv6.h> 788c2ecf20Sopenharmony_ci#include <linux/hugetlb.h> 798c2ecf20Sopenharmony_ci#include <linux/personality.h> 808c2ecf20Sopenharmony_ci#include <linux/audit.h> 818c2ecf20Sopenharmony_ci#include <linux/string.h> 828c2ecf20Sopenharmony_ci#include <linux/mutex.h> 838c2ecf20Sopenharmony_ci#include <linux/posix-timers.h> 848c2ecf20Sopenharmony_ci#include <linux/syslog.h> 858c2ecf20Sopenharmony_ci#include <linux/user_namespace.h> 868c2ecf20Sopenharmony_ci#include <linux/export.h> 878c2ecf20Sopenharmony_ci#include <linux/msg.h> 888c2ecf20Sopenharmony_ci#include <linux/shm.h> 898c2ecf20Sopenharmony_ci#include <linux/bpf.h> 908c2ecf20Sopenharmony_ci#include <linux/kernfs.h> 918c2ecf20Sopenharmony_ci#include <linux/stringhash.h> /* for hashlen_string() */ 928c2ecf20Sopenharmony_ci#include <uapi/linux/mount.h> 938c2ecf20Sopenharmony_ci#include <linux/fsnotify.h> 948c2ecf20Sopenharmony_ci#include <linux/fanotify.h> 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#include <linux/hck/lite_hck_ced.h> 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#include "avc.h" 998c2ecf20Sopenharmony_ci#include "objsec.h" 1008c2ecf20Sopenharmony_ci#include "netif.h" 1018c2ecf20Sopenharmony_ci#include "netnode.h" 1028c2ecf20Sopenharmony_ci#include "netport.h" 1038c2ecf20Sopenharmony_ci#include "ibpkey.h" 1048c2ecf20Sopenharmony_ci#include "xfrm.h" 1058c2ecf20Sopenharmony_ci#include "netlabel.h" 1068c2ecf20Sopenharmony_ci#include "audit.h" 1078c2ecf20Sopenharmony_ci#include "avc_ss.h" 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistruct selinux_state selinux_state; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* SECMARK reference count */ 1128c2ecf20Sopenharmony_cistatic atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SELINUX_DEVELOP 1158c2ecf20Sopenharmony_cistatic int selinux_enforcing_boot __initdata; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int __init enforcing_setup(char *str) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci unsigned long enforcing; 1208c2ecf20Sopenharmony_ci if (!kstrtoul(str, 0, &enforcing)) 1218c2ecf20Sopenharmony_ci selinux_enforcing_boot = enforcing ? 1 : 0; 1228c2ecf20Sopenharmony_ci return 1; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci__setup("enforcing=", enforcing_setup); 1258c2ecf20Sopenharmony_ci#else 1268c2ecf20Sopenharmony_ci#define selinux_enforcing_boot 1 1278c2ecf20Sopenharmony_ci#endif 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ciint selinux_enabled_boot __initdata = 1; 1308c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM 1318c2ecf20Sopenharmony_cistatic int __init selinux_enabled_setup(char *str) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci unsigned long enabled; 1348c2ecf20Sopenharmony_ci if (!kstrtoul(str, 0, &enabled)) 1358c2ecf20Sopenharmony_ci selinux_enabled_boot = enabled ? 1 : 0; 1368c2ecf20Sopenharmony_ci return 1; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci__setup("selinux=", selinux_enabled_setup); 1398c2ecf20Sopenharmony_ci#endif 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic unsigned int selinux_checkreqprot_boot = 1428c2ecf20Sopenharmony_ci CONFIG_SECURITY_SELINUX_CHECKREQPROT_VALUE; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int __init checkreqprot_setup(char *str) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci unsigned long checkreqprot; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (!kstrtoul(str, 0, &checkreqprot)) { 1498c2ecf20Sopenharmony_ci selinux_checkreqprot_boot = checkreqprot ? 1 : 0; 1508c2ecf20Sopenharmony_ci if (checkreqprot) 1518c2ecf20Sopenharmony_ci pr_warn("SELinux: checkreqprot set to 1 via kernel parameter. This is deprecated and will be rejected in a future kernel release.\n"); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci return 1; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci__setup("checkreqprot=", checkreqprot_setup); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci/** 1588c2ecf20Sopenharmony_ci * selinux_secmark_enabled - Check to see if SECMARK is currently enabled 1598c2ecf20Sopenharmony_ci * 1608c2ecf20Sopenharmony_ci * Description: 1618c2ecf20Sopenharmony_ci * This function checks the SECMARK reference counter to see if any SECMARK 1628c2ecf20Sopenharmony_ci * targets are currently configured, if the reference counter is greater than 1638c2ecf20Sopenharmony_ci * zero SECMARK is considered to be enabled. Returns true (1) if SECMARK is 1648c2ecf20Sopenharmony_ci * enabled, false (0) if SECMARK is disabled. If the always_check_network 1658c2ecf20Sopenharmony_ci * policy capability is enabled, SECMARK is always considered enabled. 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_cistatic int selinux_secmark_enabled(void) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci return (selinux_policycap_alwaysnetwork() || 1718c2ecf20Sopenharmony_ci atomic_read(&selinux_secmark_refcount)); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci/** 1758c2ecf20Sopenharmony_ci * selinux_peerlbl_enabled - Check to see if peer labeling is currently enabled 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * Description: 1788c2ecf20Sopenharmony_ci * This function checks if NetLabel or labeled IPSEC is enabled. Returns true 1798c2ecf20Sopenharmony_ci * (1) if any are enabled or false (0) if neither are enabled. If the 1808c2ecf20Sopenharmony_ci * always_check_network policy capability is enabled, peer labeling 1818c2ecf20Sopenharmony_ci * is always considered enabled. 1828c2ecf20Sopenharmony_ci * 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistatic int selinux_peerlbl_enabled(void) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci return (selinux_policycap_alwaysnetwork() || 1878c2ecf20Sopenharmony_ci netlbl_enabled() || selinux_xfrm_enabled()); 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_cistatic int selinux_netcache_avc_callback(u32 event) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci if (event == AVC_CALLBACK_RESET) { 1938c2ecf20Sopenharmony_ci sel_netif_flush(); 1948c2ecf20Sopenharmony_ci sel_netnode_flush(); 1958c2ecf20Sopenharmony_ci sel_netport_flush(); 1968c2ecf20Sopenharmony_ci synchronize_net(); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int selinux_lsm_notifier_avc_callback(u32 event) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci if (event == AVC_CALLBACK_RESET) { 2048c2ecf20Sopenharmony_ci sel_ib_pkey_flush(); 2058c2ecf20Sopenharmony_ci call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL); 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* 2128c2ecf20Sopenharmony_ci * initialise the security for the init task 2138c2ecf20Sopenharmony_ci */ 2148c2ecf20Sopenharmony_cistatic void cred_init_security(void) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci struct cred *cred = (struct cred *) current->real_cred; 2178c2ecf20Sopenharmony_ci struct task_security_struct *tsec; 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci tsec = selinux_cred(cred); 2208c2ecf20Sopenharmony_ci tsec->osid = tsec->sid = SECINITSID_KERNEL; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci/* 2248c2ecf20Sopenharmony_ci * get the security ID of a set of credentials 2258c2ecf20Sopenharmony_ci */ 2268c2ecf20Sopenharmony_cistatic inline u32 cred_sid(const struct cred *cred) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci const struct task_security_struct *tsec; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci tsec = selinux_cred(cred); 2318c2ecf20Sopenharmony_ci return tsec->sid; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* 2358c2ecf20Sopenharmony_ci * get the objective security ID of a task 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_cistatic inline u32 task_sid(const struct task_struct *task) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci u32 sid; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci rcu_read_lock(); 2428c2ecf20Sopenharmony_ci sid = cred_sid(__task_cred(task)); 2438c2ecf20Sopenharmony_ci rcu_read_unlock(); 2448c2ecf20Sopenharmony_ci return sid; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci/* 2508c2ecf20Sopenharmony_ci * Try reloading inode security labels that have been marked as invalid. The 2518c2ecf20Sopenharmony_ci * @may_sleep parameter indicates when sleeping and thus reloading labels is 2528c2ecf20Sopenharmony_ci * allowed; when set to false, returns -ECHILD when the label is 2538c2ecf20Sopenharmony_ci * invalid. The @dentry parameter should be set to a dentry of the inode. 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_cistatic int __inode_security_revalidate(struct inode *inode, 2568c2ecf20Sopenharmony_ci struct dentry *dentry, 2578c2ecf20Sopenharmony_ci bool may_sleep) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci struct inode_security_struct *isec = selinux_inode(inode); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci might_sleep_if(may_sleep); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (selinux_initialized(&selinux_state) && 2648c2ecf20Sopenharmony_ci isec->initialized != LABEL_INITIALIZED) { 2658c2ecf20Sopenharmony_ci if (!may_sleep) 2668c2ecf20Sopenharmony_ci return -ECHILD; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* 2698c2ecf20Sopenharmony_ci * Try reloading the inode security label. This will fail if 2708c2ecf20Sopenharmony_ci * @opt_dentry is NULL and no dentry for this inode can be 2718c2ecf20Sopenharmony_ci * found; in that case, continue using the old label. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci inode_doinit_with_dentry(inode, dentry); 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic struct inode_security_struct *inode_security_novalidate(struct inode *inode) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci return selinux_inode(inode); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci int error; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci error = __inode_security_revalidate(inode, NULL, !rcu); 2888c2ecf20Sopenharmony_ci if (error) 2898c2ecf20Sopenharmony_ci return ERR_PTR(error); 2908c2ecf20Sopenharmony_ci return selinux_inode(inode); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci/* 2948c2ecf20Sopenharmony_ci * Get the security label of an inode. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_cistatic struct inode_security_struct *inode_security(struct inode *inode) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci __inode_security_revalidate(inode, NULL, true); 2998c2ecf20Sopenharmony_ci return selinux_inode(inode); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return selinux_inode(inode); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* 3108c2ecf20Sopenharmony_ci * Get the security label of a dentry's backing inode. 3118c2ecf20Sopenharmony_ci */ 3128c2ecf20Sopenharmony_cistatic struct inode_security_struct *backing_inode_security(struct dentry *dentry) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci __inode_security_revalidate(inode, dentry, true); 3178c2ecf20Sopenharmony_ci return selinux_inode(inode); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void inode_free_security(struct inode *inode) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct inode_security_struct *isec = selinux_inode(inode); 3238c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci if (!isec) 3268c2ecf20Sopenharmony_ci return; 3278c2ecf20Sopenharmony_ci sbsec = inode->i_sb->s_security; 3288c2ecf20Sopenharmony_ci /* 3298c2ecf20Sopenharmony_ci * As not all inode security structures are in a list, we check for 3308c2ecf20Sopenharmony_ci * empty list outside of the lock to make sure that we won't waste 3318c2ecf20Sopenharmony_ci * time taking a lock doing nothing. 3328c2ecf20Sopenharmony_ci * 3338c2ecf20Sopenharmony_ci * The list_del_init() function can be safely called more than once. 3348c2ecf20Sopenharmony_ci * It should not be possible for this function to be called with 3358c2ecf20Sopenharmony_ci * concurrent list_add(), but for better safety against future changes 3368c2ecf20Sopenharmony_ci * in the code, we use list_empty_careful() here. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci if (!list_empty_careful(&isec->list)) { 3398c2ecf20Sopenharmony_ci spin_lock(&sbsec->isec_lock); 3408c2ecf20Sopenharmony_ci list_del_init(&isec->list); 3418c2ecf20Sopenharmony_ci spin_unlock(&sbsec->isec_lock); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic void superblock_free_security(struct super_block *sb) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec = sb->s_security; 3488c2ecf20Sopenharmony_ci sb->s_security = NULL; 3498c2ecf20Sopenharmony_ci kfree(sbsec); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistruct selinux_mnt_opts { 3538c2ecf20Sopenharmony_ci const char *fscontext, *context, *rootcontext, *defcontext; 3548c2ecf20Sopenharmony_ci}; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic void selinux_free_mnt_opts(void *mnt_opts) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct selinux_mnt_opts *opts = mnt_opts; 3598c2ecf20Sopenharmony_ci kfree(opts->fscontext); 3608c2ecf20Sopenharmony_ci kfree(opts->context); 3618c2ecf20Sopenharmony_ci kfree(opts->rootcontext); 3628c2ecf20Sopenharmony_ci kfree(opts->defcontext); 3638c2ecf20Sopenharmony_ci kfree(opts); 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cienum { 3678c2ecf20Sopenharmony_ci Opt_error = -1, 3688c2ecf20Sopenharmony_ci Opt_context = 0, 3698c2ecf20Sopenharmony_ci Opt_defcontext = 1, 3708c2ecf20Sopenharmony_ci Opt_fscontext = 2, 3718c2ecf20Sopenharmony_ci Opt_rootcontext = 3, 3728c2ecf20Sopenharmony_ci Opt_seclabel = 4, 3738c2ecf20Sopenharmony_ci}; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci#define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg} 3768c2ecf20Sopenharmony_cistatic struct { 3778c2ecf20Sopenharmony_ci const char *name; 3788c2ecf20Sopenharmony_ci int len; 3798c2ecf20Sopenharmony_ci int opt; 3808c2ecf20Sopenharmony_ci bool has_arg; 3818c2ecf20Sopenharmony_ci} tokens[] = { 3828c2ecf20Sopenharmony_ci A(context, true), 3838c2ecf20Sopenharmony_ci A(fscontext, true), 3848c2ecf20Sopenharmony_ci A(defcontext, true), 3858c2ecf20Sopenharmony_ci A(rootcontext, true), 3868c2ecf20Sopenharmony_ci A(seclabel, false), 3878c2ecf20Sopenharmony_ci}; 3888c2ecf20Sopenharmony_ci#undef A 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int match_opt_prefix(char *s, int l, char **arg) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci int i; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tokens); i++) { 3958c2ecf20Sopenharmony_ci size_t len = tokens[i].len; 3968c2ecf20Sopenharmony_ci if (len > l || memcmp(s, tokens[i].name, len)) 3978c2ecf20Sopenharmony_ci continue; 3988c2ecf20Sopenharmony_ci if (tokens[i].has_arg) { 3998c2ecf20Sopenharmony_ci if (len == l || s[len] != '=') 4008c2ecf20Sopenharmony_ci continue; 4018c2ecf20Sopenharmony_ci *arg = s + len + 1; 4028c2ecf20Sopenharmony_ci } else if (len != l) 4038c2ecf20Sopenharmony_ci continue; 4048c2ecf20Sopenharmony_ci return tokens[i].opt; 4058c2ecf20Sopenharmony_ci } 4068c2ecf20Sopenharmony_ci return Opt_error; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci#define SEL_MOUNT_FAIL_MSG "SELinux: duplicate or incompatible mount options\n" 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_cistatic int may_context_mount_sb_relabel(u32 sid, 4128c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec, 4138c2ecf20Sopenharmony_ci const struct cred *cred) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci const struct task_security_struct *tsec = selinux_cred(cred); 4168c2ecf20Sopenharmony_ci int rc; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 4198c2ecf20Sopenharmony_ci tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, 4208c2ecf20Sopenharmony_ci FILESYSTEM__RELABELFROM, NULL); 4218c2ecf20Sopenharmony_ci if (rc) 4228c2ecf20Sopenharmony_ci return rc; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 4258c2ecf20Sopenharmony_ci tsec->sid, sid, SECCLASS_FILESYSTEM, 4268c2ecf20Sopenharmony_ci FILESYSTEM__RELABELTO, NULL); 4278c2ecf20Sopenharmony_ci return rc; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int may_context_mount_inode_relabel(u32 sid, 4318c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec, 4328c2ecf20Sopenharmony_ci const struct cred *cred) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci const struct task_security_struct *tsec = selinux_cred(cred); 4358c2ecf20Sopenharmony_ci int rc; 4368c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 4378c2ecf20Sopenharmony_ci tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, 4388c2ecf20Sopenharmony_ci FILESYSTEM__RELABELFROM, NULL); 4398c2ecf20Sopenharmony_ci if (rc) 4408c2ecf20Sopenharmony_ci return rc; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 4438c2ecf20Sopenharmony_ci sid, sbsec->sid, SECCLASS_FILESYSTEM, 4448c2ecf20Sopenharmony_ci FILESYSTEM__ASSOCIATE, NULL); 4458c2ecf20Sopenharmony_ci return rc; 4468c2ecf20Sopenharmony_ci} 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_cistatic int selinux_is_genfs_special_handling(struct super_block *sb) 4498c2ecf20Sopenharmony_ci{ 4508c2ecf20Sopenharmony_ci /* Special handling. Genfs but also in-core setxattr handler */ 4518c2ecf20Sopenharmony_ci return !strcmp(sb->s_type->name, "sysfs") || 4528c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "pstore") || 4538c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "debugfs") || 4548c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "tracefs") || 4558c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "rootfs") || 4568c2ecf20Sopenharmony_ci (selinux_policycap_cgroupseclabel() && 4578c2ecf20Sopenharmony_ci (!strcmp(sb->s_type->name, "cgroup") || 4588c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "cgroup2"))); 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic int selinux_is_sblabel_mnt(struct super_block *sb) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec = sb->s_security; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* 4668c2ecf20Sopenharmony_ci * IMPORTANT: Double-check logic in this function when adding a new 4678c2ecf20Sopenharmony_ci * SECURITY_FS_USE_* definition! 4688c2ecf20Sopenharmony_ci */ 4698c2ecf20Sopenharmony_ci BUILD_BUG_ON(SECURITY_FS_USE_MAX != 7); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci switch (sbsec->behavior) { 4728c2ecf20Sopenharmony_ci case SECURITY_FS_USE_XATTR: 4738c2ecf20Sopenharmony_ci case SECURITY_FS_USE_TRANS: 4748c2ecf20Sopenharmony_ci case SECURITY_FS_USE_TASK: 4758c2ecf20Sopenharmony_ci case SECURITY_FS_USE_NATIVE: 4768c2ecf20Sopenharmony_ci return 1; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci case SECURITY_FS_USE_GENFS: 4798c2ecf20Sopenharmony_ci return selinux_is_genfs_special_handling(sb); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci /* Never allow relabeling on context mounts */ 4828c2ecf20Sopenharmony_ci case SECURITY_FS_USE_MNTPOINT: 4838c2ecf20Sopenharmony_ci case SECURITY_FS_USE_NONE: 4848c2ecf20Sopenharmony_ci default: 4858c2ecf20Sopenharmony_ci return 0; 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic int sb_finish_set_opts(struct super_block *sb) 4908c2ecf20Sopenharmony_ci{ 4918c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec = sb->s_security; 4928c2ecf20Sopenharmony_ci struct dentry *root = sb->s_root; 4938c2ecf20Sopenharmony_ci struct inode *root_inode = d_backing_inode(root); 4948c2ecf20Sopenharmony_ci int rc = 0; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (sbsec->behavior == SECURITY_FS_USE_XATTR) { 4978c2ecf20Sopenharmony_ci /* Make sure that the xattr handler exists and that no 4988c2ecf20Sopenharmony_ci error other than -ENODATA is returned by getxattr on 4998c2ecf20Sopenharmony_ci the root directory. -ENODATA is ok, as this may be 5008c2ecf20Sopenharmony_ci the first boot of the SELinux kernel before we have 5018c2ecf20Sopenharmony_ci assigned xattr values to the filesystem. */ 5028c2ecf20Sopenharmony_ci if (!(root_inode->i_opflags & IOP_XATTR)) { 5038c2ecf20Sopenharmony_ci pr_warn("SELinux: (dev %s, type %s) has no " 5048c2ecf20Sopenharmony_ci "xattr support\n", sb->s_id, sb->s_type->name); 5058c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 5068c2ecf20Sopenharmony_ci goto out; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0); 5108c2ecf20Sopenharmony_ci if (rc < 0 && rc != -ENODATA) { 5118c2ecf20Sopenharmony_ci if (rc == -EOPNOTSUPP) 5128c2ecf20Sopenharmony_ci pr_warn("SELinux: (dev %s, type " 5138c2ecf20Sopenharmony_ci "%s) has no security xattr handler\n", 5148c2ecf20Sopenharmony_ci sb->s_id, sb->s_type->name); 5158c2ecf20Sopenharmony_ci else 5168c2ecf20Sopenharmony_ci pr_warn("SELinux: (dev %s, type " 5178c2ecf20Sopenharmony_ci "%s) getxattr errno %d\n", sb->s_id, 5188c2ecf20Sopenharmony_ci sb->s_type->name, -rc); 5198c2ecf20Sopenharmony_ci goto out; 5208c2ecf20Sopenharmony_ci } 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci sbsec->flags |= SE_SBINITIALIZED; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* 5268c2ecf20Sopenharmony_ci * Explicitly set or clear SBLABEL_MNT. It's not sufficient to simply 5278c2ecf20Sopenharmony_ci * leave the flag untouched because sb_clone_mnt_opts might be handing 5288c2ecf20Sopenharmony_ci * us a superblock that needs the flag to be cleared. 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_ci if (selinux_is_sblabel_mnt(sb)) 5318c2ecf20Sopenharmony_ci sbsec->flags |= SBLABEL_MNT; 5328c2ecf20Sopenharmony_ci else 5338c2ecf20Sopenharmony_ci sbsec->flags &= ~SBLABEL_MNT; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci /* Initialize the root inode. */ 5368c2ecf20Sopenharmony_ci rc = inode_doinit_with_dentry(root_inode, root); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* Initialize any other inodes associated with the superblock, e.g. 5398c2ecf20Sopenharmony_ci inodes created prior to initial policy load or inodes created 5408c2ecf20Sopenharmony_ci during get_sb by a pseudo filesystem that directly 5418c2ecf20Sopenharmony_ci populates itself. */ 5428c2ecf20Sopenharmony_ci spin_lock(&sbsec->isec_lock); 5438c2ecf20Sopenharmony_ci while (!list_empty(&sbsec->isec_head)) { 5448c2ecf20Sopenharmony_ci struct inode_security_struct *isec = 5458c2ecf20Sopenharmony_ci list_first_entry(&sbsec->isec_head, 5468c2ecf20Sopenharmony_ci struct inode_security_struct, list); 5478c2ecf20Sopenharmony_ci struct inode *inode = isec->inode; 5488c2ecf20Sopenharmony_ci list_del_init(&isec->list); 5498c2ecf20Sopenharmony_ci spin_unlock(&sbsec->isec_lock); 5508c2ecf20Sopenharmony_ci inode = igrab(inode); 5518c2ecf20Sopenharmony_ci if (inode) { 5528c2ecf20Sopenharmony_ci if (!IS_PRIVATE(inode)) 5538c2ecf20Sopenharmony_ci inode_doinit_with_dentry(inode, NULL); 5548c2ecf20Sopenharmony_ci iput(inode); 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci spin_lock(&sbsec->isec_lock); 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci spin_unlock(&sbsec->isec_lock); 5598c2ecf20Sopenharmony_ciout: 5608c2ecf20Sopenharmony_ci return rc; 5618c2ecf20Sopenharmony_ci} 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_cistatic int bad_option(struct superblock_security_struct *sbsec, char flag, 5648c2ecf20Sopenharmony_ci u32 old_sid, u32 new_sid) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci char mnt_flags = sbsec->flags & SE_MNTMASK; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* check if the old mount command had the same options */ 5698c2ecf20Sopenharmony_ci if (sbsec->flags & SE_SBINITIALIZED) 5708c2ecf20Sopenharmony_ci if (!(sbsec->flags & flag) || 5718c2ecf20Sopenharmony_ci (old_sid != new_sid)) 5728c2ecf20Sopenharmony_ci return 1; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* check if we were passed the same options twice, 5758c2ecf20Sopenharmony_ci * aka someone passed context=a,context=b 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_ci if (!(sbsec->flags & SE_SBINITIALIZED)) 5788c2ecf20Sopenharmony_ci if (mnt_flags & flag) 5798c2ecf20Sopenharmony_ci return 1; 5808c2ecf20Sopenharmony_ci return 0; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int parse_sid(struct super_block *sb, const char *s, u32 *sid) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci int rc = security_context_str_to_sid(&selinux_state, s, 5868c2ecf20Sopenharmony_ci sid, GFP_KERNEL); 5878c2ecf20Sopenharmony_ci if (rc) 5888c2ecf20Sopenharmony_ci pr_warn("SELinux: security_context_str_to_sid" 5898c2ecf20Sopenharmony_ci "(%s) failed for (dev %s, type %s) errno=%d\n", 5908c2ecf20Sopenharmony_ci s, sb->s_id, sb->s_type->name, rc); 5918c2ecf20Sopenharmony_ci return rc; 5928c2ecf20Sopenharmony_ci} 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci/* 5958c2ecf20Sopenharmony_ci * Allow filesystems with binary mount data to explicitly set mount point 5968c2ecf20Sopenharmony_ci * labeling information. 5978c2ecf20Sopenharmony_ci */ 5988c2ecf20Sopenharmony_cistatic int selinux_set_mnt_opts(struct super_block *sb, 5998c2ecf20Sopenharmony_ci void *mnt_opts, 6008c2ecf20Sopenharmony_ci unsigned long kern_flags, 6018c2ecf20Sopenharmony_ci unsigned long *set_kern_flags) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 6048c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec = sb->s_security; 6058c2ecf20Sopenharmony_ci struct dentry *root = sbsec->sb->s_root; 6068c2ecf20Sopenharmony_ci struct selinux_mnt_opts *opts = mnt_opts; 6078c2ecf20Sopenharmony_ci struct inode_security_struct *root_isec; 6088c2ecf20Sopenharmony_ci u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0; 6098c2ecf20Sopenharmony_ci u32 defcontext_sid = 0; 6108c2ecf20Sopenharmony_ci int rc = 0; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci mutex_lock(&sbsec->lock); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci if (!selinux_initialized(&selinux_state)) { 6158c2ecf20Sopenharmony_ci if (!opts) { 6168c2ecf20Sopenharmony_ci /* Defer initialization until selinux_complete_init, 6178c2ecf20Sopenharmony_ci after the initial policy is loaded and the security 6188c2ecf20Sopenharmony_ci server is ready to handle calls. */ 6198c2ecf20Sopenharmony_ci goto out; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci rc = -EINVAL; 6228c2ecf20Sopenharmony_ci pr_warn("SELinux: Unable to set superblock options " 6238c2ecf20Sopenharmony_ci "before the security server is initialized\n"); 6248c2ecf20Sopenharmony_ci goto out; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci if (kern_flags && !set_kern_flags) { 6278c2ecf20Sopenharmony_ci /* Specifying internal flags without providing a place to 6288c2ecf20Sopenharmony_ci * place the results is not allowed */ 6298c2ecf20Sopenharmony_ci rc = -EINVAL; 6308c2ecf20Sopenharmony_ci goto out; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* 6348c2ecf20Sopenharmony_ci * Binary mount data FS will come through this function twice. Once 6358c2ecf20Sopenharmony_ci * from an explicit call and once from the generic calls from the vfs. 6368c2ecf20Sopenharmony_ci * Since the generic VFS calls will not contain any security mount data 6378c2ecf20Sopenharmony_ci * we need to skip the double mount verification. 6388c2ecf20Sopenharmony_ci * 6398c2ecf20Sopenharmony_ci * This does open a hole in which we will not notice if the first 6408c2ecf20Sopenharmony_ci * mount using this sb set explict options and a second mount using 6418c2ecf20Sopenharmony_ci * this sb does not set any security options. (The first options 6428c2ecf20Sopenharmony_ci * will be used for both mounts) 6438c2ecf20Sopenharmony_ci */ 6448c2ecf20Sopenharmony_ci if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA) 6458c2ecf20Sopenharmony_ci && !opts) 6468c2ecf20Sopenharmony_ci goto out; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci root_isec = backing_inode_security_novalidate(root); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* 6518c2ecf20Sopenharmony_ci * parse the mount options, check if they are valid sids. 6528c2ecf20Sopenharmony_ci * also check if someone is trying to mount the same sb more 6538c2ecf20Sopenharmony_ci * than once with different security options. 6548c2ecf20Sopenharmony_ci */ 6558c2ecf20Sopenharmony_ci if (opts) { 6568c2ecf20Sopenharmony_ci if (opts->fscontext) { 6578c2ecf20Sopenharmony_ci rc = parse_sid(sb, opts->fscontext, &fscontext_sid); 6588c2ecf20Sopenharmony_ci if (rc) 6598c2ecf20Sopenharmony_ci goto out; 6608c2ecf20Sopenharmony_ci if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, 6618c2ecf20Sopenharmony_ci fscontext_sid)) 6628c2ecf20Sopenharmony_ci goto out_double_mount; 6638c2ecf20Sopenharmony_ci sbsec->flags |= FSCONTEXT_MNT; 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci if (opts->context) { 6668c2ecf20Sopenharmony_ci rc = parse_sid(sb, opts->context, &context_sid); 6678c2ecf20Sopenharmony_ci if (rc) 6688c2ecf20Sopenharmony_ci goto out; 6698c2ecf20Sopenharmony_ci if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, 6708c2ecf20Sopenharmony_ci context_sid)) 6718c2ecf20Sopenharmony_ci goto out_double_mount; 6728c2ecf20Sopenharmony_ci sbsec->flags |= CONTEXT_MNT; 6738c2ecf20Sopenharmony_ci } 6748c2ecf20Sopenharmony_ci if (opts->rootcontext) { 6758c2ecf20Sopenharmony_ci rc = parse_sid(sb, opts->rootcontext, &rootcontext_sid); 6768c2ecf20Sopenharmony_ci if (rc) 6778c2ecf20Sopenharmony_ci goto out; 6788c2ecf20Sopenharmony_ci if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, 6798c2ecf20Sopenharmony_ci rootcontext_sid)) 6808c2ecf20Sopenharmony_ci goto out_double_mount; 6818c2ecf20Sopenharmony_ci sbsec->flags |= ROOTCONTEXT_MNT; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci if (opts->defcontext) { 6848c2ecf20Sopenharmony_ci rc = parse_sid(sb, opts->defcontext, &defcontext_sid); 6858c2ecf20Sopenharmony_ci if (rc) 6868c2ecf20Sopenharmony_ci goto out; 6878c2ecf20Sopenharmony_ci if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, 6888c2ecf20Sopenharmony_ci defcontext_sid)) 6898c2ecf20Sopenharmony_ci goto out_double_mount; 6908c2ecf20Sopenharmony_ci sbsec->flags |= DEFCONTEXT_MNT; 6918c2ecf20Sopenharmony_ci } 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (sbsec->flags & SE_SBINITIALIZED) { 6958c2ecf20Sopenharmony_ci /* previously mounted with options, but not on this attempt? */ 6968c2ecf20Sopenharmony_ci if ((sbsec->flags & SE_MNTMASK) && !opts) 6978c2ecf20Sopenharmony_ci goto out_double_mount; 6988c2ecf20Sopenharmony_ci rc = 0; 6998c2ecf20Sopenharmony_ci goto out; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci if (strcmp(sb->s_type->name, "proc") == 0) 7038c2ecf20Sopenharmony_ci sbsec->flags |= SE_SBPROC | SE_SBGENFS; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci if (!strcmp(sb->s_type->name, "debugfs") || 7068c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "tracefs") || 7078c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "binder") || 7088c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "bpf") || 7098c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "pstore")) 7108c2ecf20Sopenharmony_ci sbsec->flags |= SE_SBGENFS; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci if (!strcmp(sb->s_type->name, "sysfs") || 7138c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "cgroup") || 7148c2ecf20Sopenharmony_ci !strcmp(sb->s_type->name, "cgroup2")) 7158c2ecf20Sopenharmony_ci sbsec->flags |= SE_SBGENFS | SE_SBGENFS_XATTR; 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (!sbsec->behavior) { 7188c2ecf20Sopenharmony_ci /* 7198c2ecf20Sopenharmony_ci * Determine the labeling behavior to use for this 7208c2ecf20Sopenharmony_ci * filesystem type. 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci rc = security_fs_use(&selinux_state, sb); 7238c2ecf20Sopenharmony_ci if (rc) { 7248c2ecf20Sopenharmony_ci pr_warn("%s: security_fs_use(%s) returned %d\n", 7258c2ecf20Sopenharmony_ci __func__, sb->s_type->name, rc); 7268c2ecf20Sopenharmony_ci goto out; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci } 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci /* 7318c2ecf20Sopenharmony_ci * If this is a user namespace mount and the filesystem type is not 7328c2ecf20Sopenharmony_ci * explicitly whitelisted, then no contexts are allowed on the command 7338c2ecf20Sopenharmony_ci * line and security labels must be ignored. 7348c2ecf20Sopenharmony_ci */ 7358c2ecf20Sopenharmony_ci if (sb->s_user_ns != &init_user_ns && 7368c2ecf20Sopenharmony_ci strcmp(sb->s_type->name, "tmpfs") && 7378c2ecf20Sopenharmony_ci strcmp(sb->s_type->name, "ramfs") && 7388c2ecf20Sopenharmony_ci strcmp(sb->s_type->name, "devpts")) { 7398c2ecf20Sopenharmony_ci if (context_sid || fscontext_sid || rootcontext_sid || 7408c2ecf20Sopenharmony_ci defcontext_sid) { 7418c2ecf20Sopenharmony_ci rc = -EACCES; 7428c2ecf20Sopenharmony_ci goto out; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci if (sbsec->behavior == SECURITY_FS_USE_XATTR) { 7458c2ecf20Sopenharmony_ci sbsec->behavior = SECURITY_FS_USE_MNTPOINT; 7468c2ecf20Sopenharmony_ci rc = security_transition_sid(&selinux_state, 7478c2ecf20Sopenharmony_ci current_sid(), 7488c2ecf20Sopenharmony_ci current_sid(), 7498c2ecf20Sopenharmony_ci SECCLASS_FILE, NULL, 7508c2ecf20Sopenharmony_ci &sbsec->mntpoint_sid); 7518c2ecf20Sopenharmony_ci if (rc) 7528c2ecf20Sopenharmony_ci goto out; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci goto out_set_opts; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* sets the context of the superblock for the fs being mounted. */ 7588c2ecf20Sopenharmony_ci if (fscontext_sid) { 7598c2ecf20Sopenharmony_ci rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred); 7608c2ecf20Sopenharmony_ci if (rc) 7618c2ecf20Sopenharmony_ci goto out; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci sbsec->sid = fscontext_sid; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci /* 7678c2ecf20Sopenharmony_ci * Switch to using mount point labeling behavior. 7688c2ecf20Sopenharmony_ci * sets the label used on all file below the mountpoint, and will set 7698c2ecf20Sopenharmony_ci * the superblock context if not already set. 7708c2ecf20Sopenharmony_ci */ 7718c2ecf20Sopenharmony_ci if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) { 7728c2ecf20Sopenharmony_ci sbsec->behavior = SECURITY_FS_USE_NATIVE; 7738c2ecf20Sopenharmony_ci *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci if (context_sid) { 7778c2ecf20Sopenharmony_ci if (!fscontext_sid) { 7788c2ecf20Sopenharmony_ci rc = may_context_mount_sb_relabel(context_sid, sbsec, 7798c2ecf20Sopenharmony_ci cred); 7808c2ecf20Sopenharmony_ci if (rc) 7818c2ecf20Sopenharmony_ci goto out; 7828c2ecf20Sopenharmony_ci sbsec->sid = context_sid; 7838c2ecf20Sopenharmony_ci } else { 7848c2ecf20Sopenharmony_ci rc = may_context_mount_inode_relabel(context_sid, sbsec, 7858c2ecf20Sopenharmony_ci cred); 7868c2ecf20Sopenharmony_ci if (rc) 7878c2ecf20Sopenharmony_ci goto out; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci if (!rootcontext_sid) 7908c2ecf20Sopenharmony_ci rootcontext_sid = context_sid; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci sbsec->mntpoint_sid = context_sid; 7938c2ecf20Sopenharmony_ci sbsec->behavior = SECURITY_FS_USE_MNTPOINT; 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (rootcontext_sid) { 7978c2ecf20Sopenharmony_ci rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec, 7988c2ecf20Sopenharmony_ci cred); 7998c2ecf20Sopenharmony_ci if (rc) 8008c2ecf20Sopenharmony_ci goto out; 8018c2ecf20Sopenharmony_ci 8028c2ecf20Sopenharmony_ci root_isec->sid = rootcontext_sid; 8038c2ecf20Sopenharmony_ci root_isec->initialized = LABEL_INITIALIZED; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (defcontext_sid) { 8078c2ecf20Sopenharmony_ci if (sbsec->behavior != SECURITY_FS_USE_XATTR && 8088c2ecf20Sopenharmony_ci sbsec->behavior != SECURITY_FS_USE_NATIVE) { 8098c2ecf20Sopenharmony_ci rc = -EINVAL; 8108c2ecf20Sopenharmony_ci pr_warn("SELinux: defcontext option is " 8118c2ecf20Sopenharmony_ci "invalid for this filesystem type\n"); 8128c2ecf20Sopenharmony_ci goto out; 8138c2ecf20Sopenharmony_ci } 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci if (defcontext_sid != sbsec->def_sid) { 8168c2ecf20Sopenharmony_ci rc = may_context_mount_inode_relabel(defcontext_sid, 8178c2ecf20Sopenharmony_ci sbsec, cred); 8188c2ecf20Sopenharmony_ci if (rc) 8198c2ecf20Sopenharmony_ci goto out; 8208c2ecf20Sopenharmony_ci } 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci sbsec->def_sid = defcontext_sid; 8238c2ecf20Sopenharmony_ci } 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ciout_set_opts: 8268c2ecf20Sopenharmony_ci rc = sb_finish_set_opts(sb); 8278c2ecf20Sopenharmony_ciout: 8288c2ecf20Sopenharmony_ci mutex_unlock(&sbsec->lock); 8298c2ecf20Sopenharmony_ci return rc; 8308c2ecf20Sopenharmony_ciout_double_mount: 8318c2ecf20Sopenharmony_ci rc = -EINVAL; 8328c2ecf20Sopenharmony_ci pr_warn("SELinux: mount invalid. Same superblock, different " 8338c2ecf20Sopenharmony_ci "security settings for (dev %s, type %s)\n", sb->s_id, 8348c2ecf20Sopenharmony_ci sb->s_type->name); 8358c2ecf20Sopenharmony_ci goto out; 8368c2ecf20Sopenharmony_ci} 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_cistatic int selinux_cmp_sb_context(const struct super_block *oldsb, 8398c2ecf20Sopenharmony_ci const struct super_block *newsb) 8408c2ecf20Sopenharmony_ci{ 8418c2ecf20Sopenharmony_ci struct superblock_security_struct *old = oldsb->s_security; 8428c2ecf20Sopenharmony_ci struct superblock_security_struct *new = newsb->s_security; 8438c2ecf20Sopenharmony_ci char oldflags = old->flags & SE_MNTMASK; 8448c2ecf20Sopenharmony_ci char newflags = new->flags & SE_MNTMASK; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci if (oldflags != newflags) 8478c2ecf20Sopenharmony_ci goto mismatch; 8488c2ecf20Sopenharmony_ci if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid) 8498c2ecf20Sopenharmony_ci goto mismatch; 8508c2ecf20Sopenharmony_ci if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid) 8518c2ecf20Sopenharmony_ci goto mismatch; 8528c2ecf20Sopenharmony_ci if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid) 8538c2ecf20Sopenharmony_ci goto mismatch; 8548c2ecf20Sopenharmony_ci if (oldflags & ROOTCONTEXT_MNT) { 8558c2ecf20Sopenharmony_ci struct inode_security_struct *oldroot = backing_inode_security(oldsb->s_root); 8568c2ecf20Sopenharmony_ci struct inode_security_struct *newroot = backing_inode_security(newsb->s_root); 8578c2ecf20Sopenharmony_ci if (oldroot->sid != newroot->sid) 8588c2ecf20Sopenharmony_ci goto mismatch; 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci return 0; 8618c2ecf20Sopenharmony_cimismatch: 8628c2ecf20Sopenharmony_ci pr_warn("SELinux: mount invalid. Same superblock, " 8638c2ecf20Sopenharmony_ci "different security settings for (dev %s, " 8648c2ecf20Sopenharmony_ci "type %s)\n", newsb->s_id, newsb->s_type->name); 8658c2ecf20Sopenharmony_ci return -EBUSY; 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic int selinux_sb_clone_mnt_opts(const struct super_block *oldsb, 8698c2ecf20Sopenharmony_ci struct super_block *newsb, 8708c2ecf20Sopenharmony_ci unsigned long kern_flags, 8718c2ecf20Sopenharmony_ci unsigned long *set_kern_flags) 8728c2ecf20Sopenharmony_ci{ 8738c2ecf20Sopenharmony_ci int rc = 0; 8748c2ecf20Sopenharmony_ci const struct superblock_security_struct *oldsbsec = oldsb->s_security; 8758c2ecf20Sopenharmony_ci struct superblock_security_struct *newsbsec = newsb->s_security; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci int set_fscontext = (oldsbsec->flags & FSCONTEXT_MNT); 8788c2ecf20Sopenharmony_ci int set_context = (oldsbsec->flags & CONTEXT_MNT); 8798c2ecf20Sopenharmony_ci int set_rootcontext = (oldsbsec->flags & ROOTCONTEXT_MNT); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* 8828c2ecf20Sopenharmony_ci * if the parent was able to be mounted it clearly had no special lsm 8838c2ecf20Sopenharmony_ci * mount options. thus we can safely deal with this superblock later 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_ci if (!selinux_initialized(&selinux_state)) 8868c2ecf20Sopenharmony_ci return 0; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* 8898c2ecf20Sopenharmony_ci * Specifying internal flags without providing a place to 8908c2ecf20Sopenharmony_ci * place the results is not allowed. 8918c2ecf20Sopenharmony_ci */ 8928c2ecf20Sopenharmony_ci if (kern_flags && !set_kern_flags) 8938c2ecf20Sopenharmony_ci return -EINVAL; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* how can we clone if the old one wasn't set up?? */ 8968c2ecf20Sopenharmony_ci BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED)); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci /* if fs is reusing a sb, make sure that the contexts match */ 8998c2ecf20Sopenharmony_ci if (newsbsec->flags & SE_SBINITIALIZED) { 9008c2ecf20Sopenharmony_ci if ((kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) 9018c2ecf20Sopenharmony_ci *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; 9028c2ecf20Sopenharmony_ci return selinux_cmp_sb_context(oldsb, newsb); 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci mutex_lock(&newsbsec->lock); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci newsbsec->flags = oldsbsec->flags; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci newsbsec->sid = oldsbsec->sid; 9108c2ecf20Sopenharmony_ci newsbsec->def_sid = oldsbsec->def_sid; 9118c2ecf20Sopenharmony_ci newsbsec->behavior = oldsbsec->behavior; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci if (newsbsec->behavior == SECURITY_FS_USE_NATIVE && 9148c2ecf20Sopenharmony_ci !(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) { 9158c2ecf20Sopenharmony_ci rc = security_fs_use(&selinux_state, newsb); 9168c2ecf20Sopenharmony_ci if (rc) 9178c2ecf20Sopenharmony_ci goto out; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !set_context) { 9218c2ecf20Sopenharmony_ci newsbsec->behavior = SECURITY_FS_USE_NATIVE; 9228c2ecf20Sopenharmony_ci *set_kern_flags |= SECURITY_LSM_NATIVE_LABELS; 9238c2ecf20Sopenharmony_ci } 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci if (set_context) { 9268c2ecf20Sopenharmony_ci u32 sid = oldsbsec->mntpoint_sid; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci if (!set_fscontext) 9298c2ecf20Sopenharmony_ci newsbsec->sid = sid; 9308c2ecf20Sopenharmony_ci if (!set_rootcontext) { 9318c2ecf20Sopenharmony_ci struct inode_security_struct *newisec = backing_inode_security(newsb->s_root); 9328c2ecf20Sopenharmony_ci newisec->sid = sid; 9338c2ecf20Sopenharmony_ci } 9348c2ecf20Sopenharmony_ci newsbsec->mntpoint_sid = sid; 9358c2ecf20Sopenharmony_ci } 9368c2ecf20Sopenharmony_ci if (set_rootcontext) { 9378c2ecf20Sopenharmony_ci const struct inode_security_struct *oldisec = backing_inode_security(oldsb->s_root); 9388c2ecf20Sopenharmony_ci struct inode_security_struct *newisec = backing_inode_security(newsb->s_root); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci newisec->sid = oldisec->sid; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci sb_finish_set_opts(newsb); 9448c2ecf20Sopenharmony_ciout: 9458c2ecf20Sopenharmony_ci mutex_unlock(&newsbsec->lock); 9468c2ecf20Sopenharmony_ci return rc; 9478c2ecf20Sopenharmony_ci} 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic int selinux_add_opt(int token, const char *s, void **mnt_opts) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci struct selinux_mnt_opts *opts = *mnt_opts; 9528c2ecf20Sopenharmony_ci bool is_alloc_opts = false; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (token == Opt_seclabel) /* eaten and completely ignored */ 9558c2ecf20Sopenharmony_ci return 0; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci if (!s) 9588c2ecf20Sopenharmony_ci return -ENOMEM; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (!opts) { 9618c2ecf20Sopenharmony_ci opts = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL); 9628c2ecf20Sopenharmony_ci if (!opts) 9638c2ecf20Sopenharmony_ci return -ENOMEM; 9648c2ecf20Sopenharmony_ci *mnt_opts = opts; 9658c2ecf20Sopenharmony_ci is_alloc_opts = true; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci switch (token) { 9698c2ecf20Sopenharmony_ci case Opt_context: 9708c2ecf20Sopenharmony_ci if (opts->context || opts->defcontext) 9718c2ecf20Sopenharmony_ci goto Einval; 9728c2ecf20Sopenharmony_ci opts->context = s; 9738c2ecf20Sopenharmony_ci break; 9748c2ecf20Sopenharmony_ci case Opt_fscontext: 9758c2ecf20Sopenharmony_ci if (opts->fscontext) 9768c2ecf20Sopenharmony_ci goto Einval; 9778c2ecf20Sopenharmony_ci opts->fscontext = s; 9788c2ecf20Sopenharmony_ci break; 9798c2ecf20Sopenharmony_ci case Opt_rootcontext: 9808c2ecf20Sopenharmony_ci if (opts->rootcontext) 9818c2ecf20Sopenharmony_ci goto Einval; 9828c2ecf20Sopenharmony_ci opts->rootcontext = s; 9838c2ecf20Sopenharmony_ci break; 9848c2ecf20Sopenharmony_ci case Opt_defcontext: 9858c2ecf20Sopenharmony_ci if (opts->context || opts->defcontext) 9868c2ecf20Sopenharmony_ci goto Einval; 9878c2ecf20Sopenharmony_ci opts->defcontext = s; 9888c2ecf20Sopenharmony_ci break; 9898c2ecf20Sopenharmony_ci } 9908c2ecf20Sopenharmony_ci return 0; 9918c2ecf20Sopenharmony_ciEinval: 9928c2ecf20Sopenharmony_ci if (is_alloc_opts) { 9938c2ecf20Sopenharmony_ci kfree(opts); 9948c2ecf20Sopenharmony_ci *mnt_opts = NULL; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci pr_warn(SEL_MOUNT_FAIL_MSG); 9978c2ecf20Sopenharmony_ci return -EINVAL; 9988c2ecf20Sopenharmony_ci} 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_cistatic int selinux_add_mnt_opt(const char *option, const char *val, int len, 10018c2ecf20Sopenharmony_ci void **mnt_opts) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci int token = Opt_error; 10048c2ecf20Sopenharmony_ci int rc, i; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(tokens); i++) { 10078c2ecf20Sopenharmony_ci if (strcmp(option, tokens[i].name) == 0) { 10088c2ecf20Sopenharmony_ci token = tokens[i].opt; 10098c2ecf20Sopenharmony_ci break; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci } 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (token == Opt_error) 10148c2ecf20Sopenharmony_ci return -EINVAL; 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci if (token != Opt_seclabel) { 10178c2ecf20Sopenharmony_ci val = kmemdup_nul(val, len, GFP_KERNEL); 10188c2ecf20Sopenharmony_ci if (!val) { 10198c2ecf20Sopenharmony_ci rc = -ENOMEM; 10208c2ecf20Sopenharmony_ci goto free_opt; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci } 10238c2ecf20Sopenharmony_ci rc = selinux_add_opt(token, val, mnt_opts); 10248c2ecf20Sopenharmony_ci if (unlikely(rc)) { 10258c2ecf20Sopenharmony_ci kfree(val); 10268c2ecf20Sopenharmony_ci goto free_opt; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci return rc; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cifree_opt: 10318c2ecf20Sopenharmony_ci if (*mnt_opts) { 10328c2ecf20Sopenharmony_ci selinux_free_mnt_opts(*mnt_opts); 10338c2ecf20Sopenharmony_ci *mnt_opts = NULL; 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci return rc; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic int show_sid(struct seq_file *m, u32 sid) 10398c2ecf20Sopenharmony_ci{ 10408c2ecf20Sopenharmony_ci char *context = NULL; 10418c2ecf20Sopenharmony_ci u32 len; 10428c2ecf20Sopenharmony_ci int rc; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci rc = security_sid_to_context(&selinux_state, sid, 10458c2ecf20Sopenharmony_ci &context, &len); 10468c2ecf20Sopenharmony_ci if (!rc) { 10478c2ecf20Sopenharmony_ci bool has_comma = context && strchr(context, ','); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci seq_putc(m, '='); 10508c2ecf20Sopenharmony_ci if (has_comma) 10518c2ecf20Sopenharmony_ci seq_putc(m, '\"'); 10528c2ecf20Sopenharmony_ci seq_escape(m, context, "\"\n\\"); 10538c2ecf20Sopenharmony_ci if (has_comma) 10548c2ecf20Sopenharmony_ci seq_putc(m, '\"'); 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci kfree(context); 10578c2ecf20Sopenharmony_ci return rc; 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic int selinux_sb_show_options(struct seq_file *m, struct super_block *sb) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec = sb->s_security; 10638c2ecf20Sopenharmony_ci int rc; 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci if (!(sbsec->flags & SE_SBINITIALIZED)) 10668c2ecf20Sopenharmony_ci return 0; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (!selinux_initialized(&selinux_state)) 10698c2ecf20Sopenharmony_ci return 0; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (sbsec->flags & FSCONTEXT_MNT) { 10728c2ecf20Sopenharmony_ci seq_putc(m, ','); 10738c2ecf20Sopenharmony_ci seq_puts(m, FSCONTEXT_STR); 10748c2ecf20Sopenharmony_ci rc = show_sid(m, sbsec->sid); 10758c2ecf20Sopenharmony_ci if (rc) 10768c2ecf20Sopenharmony_ci return rc; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci if (sbsec->flags & CONTEXT_MNT) { 10798c2ecf20Sopenharmony_ci seq_putc(m, ','); 10808c2ecf20Sopenharmony_ci seq_puts(m, CONTEXT_STR); 10818c2ecf20Sopenharmony_ci rc = show_sid(m, sbsec->mntpoint_sid); 10828c2ecf20Sopenharmony_ci if (rc) 10838c2ecf20Sopenharmony_ci return rc; 10848c2ecf20Sopenharmony_ci } 10858c2ecf20Sopenharmony_ci if (sbsec->flags & DEFCONTEXT_MNT) { 10868c2ecf20Sopenharmony_ci seq_putc(m, ','); 10878c2ecf20Sopenharmony_ci seq_puts(m, DEFCONTEXT_STR); 10888c2ecf20Sopenharmony_ci rc = show_sid(m, sbsec->def_sid); 10898c2ecf20Sopenharmony_ci if (rc) 10908c2ecf20Sopenharmony_ci return rc; 10918c2ecf20Sopenharmony_ci } 10928c2ecf20Sopenharmony_ci if (sbsec->flags & ROOTCONTEXT_MNT) { 10938c2ecf20Sopenharmony_ci struct dentry *root = sbsec->sb->s_root; 10948c2ecf20Sopenharmony_ci struct inode_security_struct *isec = backing_inode_security(root); 10958c2ecf20Sopenharmony_ci seq_putc(m, ','); 10968c2ecf20Sopenharmony_ci seq_puts(m, ROOTCONTEXT_STR); 10978c2ecf20Sopenharmony_ci rc = show_sid(m, isec->sid); 10988c2ecf20Sopenharmony_ci if (rc) 10998c2ecf20Sopenharmony_ci return rc; 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci if (sbsec->flags & SBLABEL_MNT) { 11028c2ecf20Sopenharmony_ci seq_putc(m, ','); 11038c2ecf20Sopenharmony_ci seq_puts(m, SECLABEL_STR); 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci return 0; 11068c2ecf20Sopenharmony_ci} 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_cistatic inline u16 inode_mode_to_security_class(umode_t mode) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci switch (mode & S_IFMT) { 11118c2ecf20Sopenharmony_ci case S_IFSOCK: 11128c2ecf20Sopenharmony_ci return SECCLASS_SOCK_FILE; 11138c2ecf20Sopenharmony_ci case S_IFLNK: 11148c2ecf20Sopenharmony_ci return SECCLASS_LNK_FILE; 11158c2ecf20Sopenharmony_ci case S_IFREG: 11168c2ecf20Sopenharmony_ci return SECCLASS_FILE; 11178c2ecf20Sopenharmony_ci case S_IFBLK: 11188c2ecf20Sopenharmony_ci return SECCLASS_BLK_FILE; 11198c2ecf20Sopenharmony_ci case S_IFDIR: 11208c2ecf20Sopenharmony_ci return SECCLASS_DIR; 11218c2ecf20Sopenharmony_ci case S_IFCHR: 11228c2ecf20Sopenharmony_ci return SECCLASS_CHR_FILE; 11238c2ecf20Sopenharmony_ci case S_IFIFO: 11248c2ecf20Sopenharmony_ci return SECCLASS_FIFO_FILE; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci return SECCLASS_FILE; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic inline int default_protocol_stream(int protocol) 11328c2ecf20Sopenharmony_ci{ 11338c2ecf20Sopenharmony_ci return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP); 11348c2ecf20Sopenharmony_ci} 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_cistatic inline int default_protocol_dgram(int protocol) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP); 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic inline u16 socket_type_to_security_class(int family, int type, int protocol) 11428c2ecf20Sopenharmony_ci{ 11438c2ecf20Sopenharmony_ci int extsockclass = selinux_policycap_extsockclass(); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci switch (family) { 11468c2ecf20Sopenharmony_ci case PF_UNIX: 11478c2ecf20Sopenharmony_ci switch (type) { 11488c2ecf20Sopenharmony_ci case SOCK_STREAM: 11498c2ecf20Sopenharmony_ci case SOCK_SEQPACKET: 11508c2ecf20Sopenharmony_ci return SECCLASS_UNIX_STREAM_SOCKET; 11518c2ecf20Sopenharmony_ci case SOCK_DGRAM: 11528c2ecf20Sopenharmony_ci case SOCK_RAW: 11538c2ecf20Sopenharmony_ci return SECCLASS_UNIX_DGRAM_SOCKET; 11548c2ecf20Sopenharmony_ci } 11558c2ecf20Sopenharmony_ci break; 11568c2ecf20Sopenharmony_ci case PF_INET: 11578c2ecf20Sopenharmony_ci case PF_INET6: 11588c2ecf20Sopenharmony_ci switch (type) { 11598c2ecf20Sopenharmony_ci case SOCK_STREAM: 11608c2ecf20Sopenharmony_ci case SOCK_SEQPACKET: 11618c2ecf20Sopenharmony_ci if (default_protocol_stream(protocol)) 11628c2ecf20Sopenharmony_ci return SECCLASS_TCP_SOCKET; 11638c2ecf20Sopenharmony_ci else if (extsockclass && protocol == IPPROTO_SCTP) 11648c2ecf20Sopenharmony_ci return SECCLASS_SCTP_SOCKET; 11658c2ecf20Sopenharmony_ci else 11668c2ecf20Sopenharmony_ci return SECCLASS_RAWIP_SOCKET; 11678c2ecf20Sopenharmony_ci case SOCK_DGRAM: 11688c2ecf20Sopenharmony_ci if (default_protocol_dgram(protocol)) 11698c2ecf20Sopenharmony_ci return SECCLASS_UDP_SOCKET; 11708c2ecf20Sopenharmony_ci else if (extsockclass && (protocol == IPPROTO_ICMP || 11718c2ecf20Sopenharmony_ci protocol == IPPROTO_ICMPV6)) 11728c2ecf20Sopenharmony_ci return SECCLASS_ICMP_SOCKET; 11738c2ecf20Sopenharmony_ci else 11748c2ecf20Sopenharmony_ci return SECCLASS_RAWIP_SOCKET; 11758c2ecf20Sopenharmony_ci case SOCK_DCCP: 11768c2ecf20Sopenharmony_ci return SECCLASS_DCCP_SOCKET; 11778c2ecf20Sopenharmony_ci default: 11788c2ecf20Sopenharmony_ci return SECCLASS_RAWIP_SOCKET; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci break; 11818c2ecf20Sopenharmony_ci case PF_NETLINK: 11828c2ecf20Sopenharmony_ci switch (protocol) { 11838c2ecf20Sopenharmony_ci case NETLINK_ROUTE: 11848c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_ROUTE_SOCKET; 11858c2ecf20Sopenharmony_ci case NETLINK_SOCK_DIAG: 11868c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_TCPDIAG_SOCKET; 11878c2ecf20Sopenharmony_ci case NETLINK_NFLOG: 11888c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_NFLOG_SOCKET; 11898c2ecf20Sopenharmony_ci case NETLINK_XFRM: 11908c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_XFRM_SOCKET; 11918c2ecf20Sopenharmony_ci case NETLINK_SELINUX: 11928c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_SELINUX_SOCKET; 11938c2ecf20Sopenharmony_ci case NETLINK_ISCSI: 11948c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_ISCSI_SOCKET; 11958c2ecf20Sopenharmony_ci case NETLINK_AUDIT: 11968c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_AUDIT_SOCKET; 11978c2ecf20Sopenharmony_ci case NETLINK_FIB_LOOKUP: 11988c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_FIB_LOOKUP_SOCKET; 11998c2ecf20Sopenharmony_ci case NETLINK_CONNECTOR: 12008c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_CONNECTOR_SOCKET; 12018c2ecf20Sopenharmony_ci case NETLINK_NETFILTER: 12028c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_NETFILTER_SOCKET; 12038c2ecf20Sopenharmony_ci case NETLINK_DNRTMSG: 12048c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_DNRT_SOCKET; 12058c2ecf20Sopenharmony_ci case NETLINK_KOBJECT_UEVENT: 12068c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET; 12078c2ecf20Sopenharmony_ci case NETLINK_GENERIC: 12088c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_GENERIC_SOCKET; 12098c2ecf20Sopenharmony_ci case NETLINK_SCSITRANSPORT: 12108c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_SCSITRANSPORT_SOCKET; 12118c2ecf20Sopenharmony_ci case NETLINK_RDMA: 12128c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_RDMA_SOCKET; 12138c2ecf20Sopenharmony_ci case NETLINK_CRYPTO: 12148c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_CRYPTO_SOCKET; 12158c2ecf20Sopenharmony_ci default: 12168c2ecf20Sopenharmony_ci return SECCLASS_NETLINK_SOCKET; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci case PF_PACKET: 12198c2ecf20Sopenharmony_ci return SECCLASS_PACKET_SOCKET; 12208c2ecf20Sopenharmony_ci case PF_KEY: 12218c2ecf20Sopenharmony_ci return SECCLASS_KEY_SOCKET; 12228c2ecf20Sopenharmony_ci case PF_APPLETALK: 12238c2ecf20Sopenharmony_ci return SECCLASS_APPLETALK_SOCKET; 12248c2ecf20Sopenharmony_ci } 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci if (extsockclass) { 12278c2ecf20Sopenharmony_ci switch (family) { 12288c2ecf20Sopenharmony_ci case PF_AX25: 12298c2ecf20Sopenharmony_ci return SECCLASS_AX25_SOCKET; 12308c2ecf20Sopenharmony_ci case PF_IPX: 12318c2ecf20Sopenharmony_ci return SECCLASS_IPX_SOCKET; 12328c2ecf20Sopenharmony_ci case PF_NETROM: 12338c2ecf20Sopenharmony_ci return SECCLASS_NETROM_SOCKET; 12348c2ecf20Sopenharmony_ci case PF_ATMPVC: 12358c2ecf20Sopenharmony_ci return SECCLASS_ATMPVC_SOCKET; 12368c2ecf20Sopenharmony_ci case PF_X25: 12378c2ecf20Sopenharmony_ci return SECCLASS_X25_SOCKET; 12388c2ecf20Sopenharmony_ci case PF_ROSE: 12398c2ecf20Sopenharmony_ci return SECCLASS_ROSE_SOCKET; 12408c2ecf20Sopenharmony_ci case PF_DECnet: 12418c2ecf20Sopenharmony_ci return SECCLASS_DECNET_SOCKET; 12428c2ecf20Sopenharmony_ci case PF_ATMSVC: 12438c2ecf20Sopenharmony_ci return SECCLASS_ATMSVC_SOCKET; 12448c2ecf20Sopenharmony_ci case PF_RDS: 12458c2ecf20Sopenharmony_ci return SECCLASS_RDS_SOCKET; 12468c2ecf20Sopenharmony_ci case PF_IRDA: 12478c2ecf20Sopenharmony_ci return SECCLASS_IRDA_SOCKET; 12488c2ecf20Sopenharmony_ci case PF_PPPOX: 12498c2ecf20Sopenharmony_ci return SECCLASS_PPPOX_SOCKET; 12508c2ecf20Sopenharmony_ci case PF_LLC: 12518c2ecf20Sopenharmony_ci return SECCLASS_LLC_SOCKET; 12528c2ecf20Sopenharmony_ci case PF_CAN: 12538c2ecf20Sopenharmony_ci return SECCLASS_CAN_SOCKET; 12548c2ecf20Sopenharmony_ci case PF_TIPC: 12558c2ecf20Sopenharmony_ci return SECCLASS_TIPC_SOCKET; 12568c2ecf20Sopenharmony_ci case PF_BLUETOOTH: 12578c2ecf20Sopenharmony_ci return SECCLASS_BLUETOOTH_SOCKET; 12588c2ecf20Sopenharmony_ci case PF_IUCV: 12598c2ecf20Sopenharmony_ci return SECCLASS_IUCV_SOCKET; 12608c2ecf20Sopenharmony_ci case PF_RXRPC: 12618c2ecf20Sopenharmony_ci return SECCLASS_RXRPC_SOCKET; 12628c2ecf20Sopenharmony_ci case PF_ISDN: 12638c2ecf20Sopenharmony_ci return SECCLASS_ISDN_SOCKET; 12648c2ecf20Sopenharmony_ci case PF_PHONET: 12658c2ecf20Sopenharmony_ci return SECCLASS_PHONET_SOCKET; 12668c2ecf20Sopenharmony_ci case PF_IEEE802154: 12678c2ecf20Sopenharmony_ci return SECCLASS_IEEE802154_SOCKET; 12688c2ecf20Sopenharmony_ci case PF_CAIF: 12698c2ecf20Sopenharmony_ci return SECCLASS_CAIF_SOCKET; 12708c2ecf20Sopenharmony_ci case PF_ALG: 12718c2ecf20Sopenharmony_ci return SECCLASS_ALG_SOCKET; 12728c2ecf20Sopenharmony_ci case PF_NFC: 12738c2ecf20Sopenharmony_ci return SECCLASS_NFC_SOCKET; 12748c2ecf20Sopenharmony_ci case PF_VSOCK: 12758c2ecf20Sopenharmony_ci return SECCLASS_VSOCK_SOCKET; 12768c2ecf20Sopenharmony_ci case PF_KCM: 12778c2ecf20Sopenharmony_ci return SECCLASS_KCM_SOCKET; 12788c2ecf20Sopenharmony_ci case PF_QIPCRTR: 12798c2ecf20Sopenharmony_ci return SECCLASS_QIPCRTR_SOCKET; 12808c2ecf20Sopenharmony_ci case PF_SMC: 12818c2ecf20Sopenharmony_ci return SECCLASS_SMC_SOCKET; 12828c2ecf20Sopenharmony_ci case PF_XDP: 12838c2ecf20Sopenharmony_ci return SECCLASS_XDP_SOCKET; 12848c2ecf20Sopenharmony_ci#if PF_MAX > 46 12858c2ecf20Sopenharmony_ci#error New address family defined, please update this function. 12868c2ecf20Sopenharmony_ci#endif 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci return SECCLASS_SOCKET; 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cistatic int selinux_genfs_get_sid(struct dentry *dentry, 12948c2ecf20Sopenharmony_ci u16 tclass, 12958c2ecf20Sopenharmony_ci u16 flags, 12968c2ecf20Sopenharmony_ci u32 *sid) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci int rc; 12998c2ecf20Sopenharmony_ci struct super_block *sb = dentry->d_sb; 13008c2ecf20Sopenharmony_ci char *buffer, *path; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci buffer = (char *)__get_free_page(GFP_KERNEL); 13038c2ecf20Sopenharmony_ci if (!buffer) 13048c2ecf20Sopenharmony_ci return -ENOMEM; 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci path = dentry_path_raw(dentry, buffer, PAGE_SIZE); 13078c2ecf20Sopenharmony_ci if (IS_ERR(path)) 13088c2ecf20Sopenharmony_ci rc = PTR_ERR(path); 13098c2ecf20Sopenharmony_ci else { 13108c2ecf20Sopenharmony_ci if (flags & SE_SBPROC) { 13118c2ecf20Sopenharmony_ci /* each process gets a /proc/PID/ entry. Strip off the 13128c2ecf20Sopenharmony_ci * PID part to get a valid selinux labeling. 13138c2ecf20Sopenharmony_ci * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */ 13148c2ecf20Sopenharmony_ci while (path[1] >= '0' && path[1] <= '9') { 13158c2ecf20Sopenharmony_ci path[1] = '/'; 13168c2ecf20Sopenharmony_ci path++; 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci } 13198c2ecf20Sopenharmony_ci rc = security_genfs_sid(&selinux_state, sb->s_type->name, 13208c2ecf20Sopenharmony_ci path, tclass, sid); 13218c2ecf20Sopenharmony_ci if (rc == -ENOENT) { 13228c2ecf20Sopenharmony_ci /* No match in policy, mark as unlabeled. */ 13238c2ecf20Sopenharmony_ci *sid = SECINITSID_UNLABELED; 13248c2ecf20Sopenharmony_ci rc = 0; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci } 13278c2ecf20Sopenharmony_ci free_page((unsigned long)buffer); 13288c2ecf20Sopenharmony_ci return rc; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry, 13328c2ecf20Sopenharmony_ci u32 def_sid, u32 *sid) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci#define INITCONTEXTLEN 255 13358c2ecf20Sopenharmony_ci char *context; 13368c2ecf20Sopenharmony_ci unsigned int len; 13378c2ecf20Sopenharmony_ci int rc; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci len = INITCONTEXTLEN; 13408c2ecf20Sopenharmony_ci context = kmalloc(len + 1, GFP_NOFS); 13418c2ecf20Sopenharmony_ci if (!context) 13428c2ecf20Sopenharmony_ci return -ENOMEM; 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci context[len] = '\0'; 13458c2ecf20Sopenharmony_ci rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len); 13468c2ecf20Sopenharmony_ci if (rc == -ERANGE) { 13478c2ecf20Sopenharmony_ci kfree(context); 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci /* Need a larger buffer. Query for the right size. */ 13508c2ecf20Sopenharmony_ci rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0); 13518c2ecf20Sopenharmony_ci if (rc < 0) 13528c2ecf20Sopenharmony_ci return rc; 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci len = rc; 13558c2ecf20Sopenharmony_ci context = kmalloc(len + 1, GFP_NOFS); 13568c2ecf20Sopenharmony_ci if (!context) 13578c2ecf20Sopenharmony_ci return -ENOMEM; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci context[len] = '\0'; 13608c2ecf20Sopenharmony_ci rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, 13618c2ecf20Sopenharmony_ci context, len); 13628c2ecf20Sopenharmony_ci } 13638c2ecf20Sopenharmony_ci if (rc < 0) { 13648c2ecf20Sopenharmony_ci kfree(context); 13658c2ecf20Sopenharmony_ci if (rc != -ENODATA) { 13668c2ecf20Sopenharmony_ci pr_warn("SELinux: %s: getxattr returned %d for dev=%s ino=%ld\n", 13678c2ecf20Sopenharmony_ci __func__, -rc, inode->i_sb->s_id, inode->i_ino); 13688c2ecf20Sopenharmony_ci return rc; 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ci *sid = def_sid; 13718c2ecf20Sopenharmony_ci return 0; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci rc = security_context_to_sid_default(&selinux_state, context, rc, sid, 13758c2ecf20Sopenharmony_ci def_sid, GFP_NOFS); 13768c2ecf20Sopenharmony_ci if (rc) { 13778c2ecf20Sopenharmony_ci char *dev = inode->i_sb->s_id; 13788c2ecf20Sopenharmony_ci unsigned long ino = inode->i_ino; 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci if (rc == -EINVAL) { 13818c2ecf20Sopenharmony_ci pr_notice_ratelimited("SELinux: inode=%lu on dev=%s was found to have an invalid context=%s. This indicates you may need to relabel the inode or the filesystem in question.\n", 13828c2ecf20Sopenharmony_ci ino, dev, context); 13838c2ecf20Sopenharmony_ci } else { 13848c2ecf20Sopenharmony_ci pr_warn("SELinux: %s: context_to_sid(%s) returned %d for dev=%s ino=%ld\n", 13858c2ecf20Sopenharmony_ci __func__, context, -rc, dev, ino); 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci } 13888c2ecf20Sopenharmony_ci kfree(context); 13898c2ecf20Sopenharmony_ci return 0; 13908c2ecf20Sopenharmony_ci} 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci/* The inode's security attributes must be initialized before first use. */ 13938c2ecf20Sopenharmony_cistatic int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry) 13948c2ecf20Sopenharmony_ci{ 13958c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec = NULL; 13968c2ecf20Sopenharmony_ci struct inode_security_struct *isec = selinux_inode(inode); 13978c2ecf20Sopenharmony_ci u32 task_sid, sid = 0; 13988c2ecf20Sopenharmony_ci u16 sclass; 13998c2ecf20Sopenharmony_ci struct dentry *dentry; 14008c2ecf20Sopenharmony_ci int rc = 0; 14018c2ecf20Sopenharmony_ci 14028c2ecf20Sopenharmony_ci if (isec->initialized == LABEL_INITIALIZED) 14038c2ecf20Sopenharmony_ci return 0; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci spin_lock(&isec->lock); 14068c2ecf20Sopenharmony_ci if (isec->initialized == LABEL_INITIALIZED) 14078c2ecf20Sopenharmony_ci goto out_unlock; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (isec->sclass == SECCLASS_FILE) 14108c2ecf20Sopenharmony_ci isec->sclass = inode_mode_to_security_class(inode->i_mode); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci sbsec = inode->i_sb->s_security; 14138c2ecf20Sopenharmony_ci if (!(sbsec->flags & SE_SBINITIALIZED)) { 14148c2ecf20Sopenharmony_ci /* Defer initialization until selinux_complete_init, 14158c2ecf20Sopenharmony_ci after the initial policy is loaded and the security 14168c2ecf20Sopenharmony_ci server is ready to handle calls. */ 14178c2ecf20Sopenharmony_ci spin_lock(&sbsec->isec_lock); 14188c2ecf20Sopenharmony_ci if (list_empty(&isec->list)) 14198c2ecf20Sopenharmony_ci list_add(&isec->list, &sbsec->isec_head); 14208c2ecf20Sopenharmony_ci spin_unlock(&sbsec->isec_lock); 14218c2ecf20Sopenharmony_ci goto out_unlock; 14228c2ecf20Sopenharmony_ci } 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci sclass = isec->sclass; 14258c2ecf20Sopenharmony_ci task_sid = isec->task_sid; 14268c2ecf20Sopenharmony_ci sid = isec->sid; 14278c2ecf20Sopenharmony_ci isec->initialized = LABEL_PENDING; 14288c2ecf20Sopenharmony_ci spin_unlock(&isec->lock); 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci switch (sbsec->behavior) { 14318c2ecf20Sopenharmony_ci case SECURITY_FS_USE_NATIVE: 14328c2ecf20Sopenharmony_ci break; 14338c2ecf20Sopenharmony_ci case SECURITY_FS_USE_XATTR: 14348c2ecf20Sopenharmony_ci if (!(inode->i_opflags & IOP_XATTR)) { 14358c2ecf20Sopenharmony_ci sid = sbsec->def_sid; 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci /* Need a dentry, since the xattr API requires one. 14398c2ecf20Sopenharmony_ci Life would be simpler if we could just pass the inode. */ 14408c2ecf20Sopenharmony_ci if (opt_dentry) { 14418c2ecf20Sopenharmony_ci /* Called from d_instantiate or d_splice_alias. */ 14428c2ecf20Sopenharmony_ci dentry = dget(opt_dentry); 14438c2ecf20Sopenharmony_ci } else { 14448c2ecf20Sopenharmony_ci /* 14458c2ecf20Sopenharmony_ci * Called from selinux_complete_init, try to find a dentry. 14468c2ecf20Sopenharmony_ci * Some filesystems really want a connected one, so try 14478c2ecf20Sopenharmony_ci * that first. We could split SECURITY_FS_USE_XATTR in 14488c2ecf20Sopenharmony_ci * two, depending upon that... 14498c2ecf20Sopenharmony_ci */ 14508c2ecf20Sopenharmony_ci dentry = d_find_alias(inode); 14518c2ecf20Sopenharmony_ci if (!dentry) 14528c2ecf20Sopenharmony_ci dentry = d_find_any_alias(inode); 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci if (!dentry) { 14558c2ecf20Sopenharmony_ci /* 14568c2ecf20Sopenharmony_ci * this is can be hit on boot when a file is accessed 14578c2ecf20Sopenharmony_ci * before the policy is loaded. When we load policy we 14588c2ecf20Sopenharmony_ci * may find inodes that have no dentry on the 14598c2ecf20Sopenharmony_ci * sbsec->isec_head list. No reason to complain as these 14608c2ecf20Sopenharmony_ci * will get fixed up the next time we go through 14618c2ecf20Sopenharmony_ci * inode_doinit with a dentry, before these inodes could 14628c2ecf20Sopenharmony_ci * be used again by userspace. 14638c2ecf20Sopenharmony_ci */ 14648c2ecf20Sopenharmony_ci goto out_invalid; 14658c2ecf20Sopenharmony_ci } 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid, 14688c2ecf20Sopenharmony_ci &sid); 14698c2ecf20Sopenharmony_ci dput(dentry); 14708c2ecf20Sopenharmony_ci if (rc) 14718c2ecf20Sopenharmony_ci goto out; 14728c2ecf20Sopenharmony_ci break; 14738c2ecf20Sopenharmony_ci case SECURITY_FS_USE_TASK: 14748c2ecf20Sopenharmony_ci sid = task_sid; 14758c2ecf20Sopenharmony_ci break; 14768c2ecf20Sopenharmony_ci case SECURITY_FS_USE_TRANS: 14778c2ecf20Sopenharmony_ci /* Default to the fs SID. */ 14788c2ecf20Sopenharmony_ci sid = sbsec->sid; 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci /* Try to obtain a transition SID. */ 14818c2ecf20Sopenharmony_ci rc = security_transition_sid(&selinux_state, task_sid, sid, 14828c2ecf20Sopenharmony_ci sclass, NULL, &sid); 14838c2ecf20Sopenharmony_ci if (rc) 14848c2ecf20Sopenharmony_ci goto out; 14858c2ecf20Sopenharmony_ci break; 14868c2ecf20Sopenharmony_ci case SECURITY_FS_USE_MNTPOINT: 14878c2ecf20Sopenharmony_ci sid = sbsec->mntpoint_sid; 14888c2ecf20Sopenharmony_ci break; 14898c2ecf20Sopenharmony_ci default: 14908c2ecf20Sopenharmony_ci /* Default to the fs superblock SID. */ 14918c2ecf20Sopenharmony_ci sid = sbsec->sid; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci if ((sbsec->flags & SE_SBGENFS) && 14948c2ecf20Sopenharmony_ci (!S_ISLNK(inode->i_mode) || 14958c2ecf20Sopenharmony_ci selinux_policycap_genfs_seclabel_symlinks())) { 14968c2ecf20Sopenharmony_ci /* We must have a dentry to determine the label on 14978c2ecf20Sopenharmony_ci * procfs inodes */ 14988c2ecf20Sopenharmony_ci if (opt_dentry) { 14998c2ecf20Sopenharmony_ci /* Called from d_instantiate or 15008c2ecf20Sopenharmony_ci * d_splice_alias. */ 15018c2ecf20Sopenharmony_ci dentry = dget(opt_dentry); 15028c2ecf20Sopenharmony_ci } else { 15038c2ecf20Sopenharmony_ci /* Called from selinux_complete_init, try to 15048c2ecf20Sopenharmony_ci * find a dentry. Some filesystems really want 15058c2ecf20Sopenharmony_ci * a connected one, so try that first. 15068c2ecf20Sopenharmony_ci */ 15078c2ecf20Sopenharmony_ci dentry = d_find_alias(inode); 15088c2ecf20Sopenharmony_ci if (!dentry) 15098c2ecf20Sopenharmony_ci dentry = d_find_any_alias(inode); 15108c2ecf20Sopenharmony_ci } 15118c2ecf20Sopenharmony_ci /* 15128c2ecf20Sopenharmony_ci * This can be hit on boot when a file is accessed 15138c2ecf20Sopenharmony_ci * before the policy is loaded. When we load policy we 15148c2ecf20Sopenharmony_ci * may find inodes that have no dentry on the 15158c2ecf20Sopenharmony_ci * sbsec->isec_head list. No reason to complain as 15168c2ecf20Sopenharmony_ci * these will get fixed up the next time we go through 15178c2ecf20Sopenharmony_ci * inode_doinit() with a dentry, before these inodes 15188c2ecf20Sopenharmony_ci * could be used again by userspace. 15198c2ecf20Sopenharmony_ci */ 15208c2ecf20Sopenharmony_ci if (!dentry) 15218c2ecf20Sopenharmony_ci goto out_invalid; 15228c2ecf20Sopenharmony_ci rc = selinux_genfs_get_sid(dentry, sclass, 15238c2ecf20Sopenharmony_ci sbsec->flags, &sid); 15248c2ecf20Sopenharmony_ci if (rc) { 15258c2ecf20Sopenharmony_ci dput(dentry); 15268c2ecf20Sopenharmony_ci goto out; 15278c2ecf20Sopenharmony_ci } 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci if ((sbsec->flags & SE_SBGENFS_XATTR) && 15308c2ecf20Sopenharmony_ci (inode->i_opflags & IOP_XATTR)) { 15318c2ecf20Sopenharmony_ci rc = inode_doinit_use_xattr(inode, dentry, 15328c2ecf20Sopenharmony_ci sid, &sid); 15338c2ecf20Sopenharmony_ci if (rc) { 15348c2ecf20Sopenharmony_ci dput(dentry); 15358c2ecf20Sopenharmony_ci goto out; 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci dput(dentry); 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci break; 15418c2ecf20Sopenharmony_ci } 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ciout: 15448c2ecf20Sopenharmony_ci spin_lock(&isec->lock); 15458c2ecf20Sopenharmony_ci if (isec->initialized == LABEL_PENDING) { 15468c2ecf20Sopenharmony_ci if (rc) { 15478c2ecf20Sopenharmony_ci isec->initialized = LABEL_INVALID; 15488c2ecf20Sopenharmony_ci goto out_unlock; 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci isec->initialized = LABEL_INITIALIZED; 15518c2ecf20Sopenharmony_ci isec->sid = sid; 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ciout_unlock: 15558c2ecf20Sopenharmony_ci spin_unlock(&isec->lock); 15568c2ecf20Sopenharmony_ci return rc; 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_ciout_invalid: 15598c2ecf20Sopenharmony_ci spin_lock(&isec->lock); 15608c2ecf20Sopenharmony_ci if (isec->initialized == LABEL_PENDING) { 15618c2ecf20Sopenharmony_ci isec->initialized = LABEL_INVALID; 15628c2ecf20Sopenharmony_ci isec->sid = sid; 15638c2ecf20Sopenharmony_ci } 15648c2ecf20Sopenharmony_ci spin_unlock(&isec->lock); 15658c2ecf20Sopenharmony_ci return 0; 15668c2ecf20Sopenharmony_ci} 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci/* Convert a Linux signal to an access vector. */ 15698c2ecf20Sopenharmony_cistatic inline u32 signal_to_av(int sig) 15708c2ecf20Sopenharmony_ci{ 15718c2ecf20Sopenharmony_ci u32 perm = 0; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci switch (sig) { 15748c2ecf20Sopenharmony_ci case SIGCHLD: 15758c2ecf20Sopenharmony_ci /* Commonly granted from child to parent. */ 15768c2ecf20Sopenharmony_ci perm = PROCESS__SIGCHLD; 15778c2ecf20Sopenharmony_ci break; 15788c2ecf20Sopenharmony_ci case SIGKILL: 15798c2ecf20Sopenharmony_ci /* Cannot be caught or ignored */ 15808c2ecf20Sopenharmony_ci perm = PROCESS__SIGKILL; 15818c2ecf20Sopenharmony_ci break; 15828c2ecf20Sopenharmony_ci case SIGSTOP: 15838c2ecf20Sopenharmony_ci /* Cannot be caught or ignored */ 15848c2ecf20Sopenharmony_ci perm = PROCESS__SIGSTOP; 15858c2ecf20Sopenharmony_ci break; 15868c2ecf20Sopenharmony_ci default: 15878c2ecf20Sopenharmony_ci /* All other signals. */ 15888c2ecf20Sopenharmony_ci perm = PROCESS__SIGNAL; 15898c2ecf20Sopenharmony_ci break; 15908c2ecf20Sopenharmony_ci } 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci return perm; 15938c2ecf20Sopenharmony_ci} 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci#if CAP_LAST_CAP > 63 15968c2ecf20Sopenharmony_ci#error Fix SELinux to handle capabilities > 63. 15978c2ecf20Sopenharmony_ci#endif 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci/* Check whether a task is allowed to use a capability. */ 16008c2ecf20Sopenharmony_cistatic int cred_has_capability(const struct cred *cred, 16018c2ecf20Sopenharmony_ci int cap, unsigned int opts, bool initns) 16028c2ecf20Sopenharmony_ci{ 16038c2ecf20Sopenharmony_ci struct common_audit_data ad; 16048c2ecf20Sopenharmony_ci struct av_decision avd; 16058c2ecf20Sopenharmony_ci u16 sclass; 16068c2ecf20Sopenharmony_ci u32 sid = cred_sid(cred); 16078c2ecf20Sopenharmony_ci u32 av = CAP_TO_MASK(cap); 16088c2ecf20Sopenharmony_ci int rc; 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_CAP; 16118c2ecf20Sopenharmony_ci ad.u.cap = cap; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci switch (CAP_TO_INDEX(cap)) { 16148c2ecf20Sopenharmony_ci case 0: 16158c2ecf20Sopenharmony_ci sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS; 16168c2ecf20Sopenharmony_ci break; 16178c2ecf20Sopenharmony_ci case 1: 16188c2ecf20Sopenharmony_ci sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS; 16198c2ecf20Sopenharmony_ci break; 16208c2ecf20Sopenharmony_ci default: 16218c2ecf20Sopenharmony_ci pr_err("SELinux: out of range capability %d\n", cap); 16228c2ecf20Sopenharmony_ci BUG(); 16238c2ecf20Sopenharmony_ci return -EINVAL; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci rc = avc_has_perm_noaudit(&selinux_state, 16278c2ecf20Sopenharmony_ci sid, sid, sclass, av, 0, &avd); 16288c2ecf20Sopenharmony_ci if (!(opts & CAP_OPT_NOAUDIT)) { 16298c2ecf20Sopenharmony_ci int rc2 = avc_audit(&selinux_state, 16308c2ecf20Sopenharmony_ci sid, sid, sclass, av, &avd, rc, &ad, 0); 16318c2ecf20Sopenharmony_ci if (rc2) 16328c2ecf20Sopenharmony_ci return rc2; 16338c2ecf20Sopenharmony_ci } 16348c2ecf20Sopenharmony_ci return rc; 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci/* Check whether a task has a particular permission to an inode. 16388c2ecf20Sopenharmony_ci The 'adp' parameter is optional and allows other audit 16398c2ecf20Sopenharmony_ci data to be passed (e.g. the dentry). */ 16408c2ecf20Sopenharmony_cistatic int inode_has_perm(const struct cred *cred, 16418c2ecf20Sopenharmony_ci struct inode *inode, 16428c2ecf20Sopenharmony_ci u32 perms, 16438c2ecf20Sopenharmony_ci struct common_audit_data *adp) 16448c2ecf20Sopenharmony_ci{ 16458c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 16468c2ecf20Sopenharmony_ci u32 sid; 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci validate_creds(cred); 16498c2ecf20Sopenharmony_ci 16508c2ecf20Sopenharmony_ci if (unlikely(IS_PRIVATE(inode))) 16518c2ecf20Sopenharmony_ci return 0; 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci sid = cred_sid(cred); 16548c2ecf20Sopenharmony_ci isec = selinux_inode(inode); 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 16578c2ecf20Sopenharmony_ci sid, isec->sid, isec->sclass, perms, adp); 16588c2ecf20Sopenharmony_ci} 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci/* Same as inode_has_perm, but pass explicit audit data containing 16618c2ecf20Sopenharmony_ci the dentry to help the auditing code to more easily generate the 16628c2ecf20Sopenharmony_ci pathname if needed. */ 16638c2ecf20Sopenharmony_cistatic inline int dentry_has_perm(const struct cred *cred, 16648c2ecf20Sopenharmony_ci struct dentry *dentry, 16658c2ecf20Sopenharmony_ci u32 av) 16668c2ecf20Sopenharmony_ci{ 16678c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 16688c2ecf20Sopenharmony_ci struct common_audit_data ad; 16698c2ecf20Sopenharmony_ci 16708c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_DENTRY; 16718c2ecf20Sopenharmony_ci ad.u.dentry = dentry; 16728c2ecf20Sopenharmony_ci __inode_security_revalidate(inode, dentry, true); 16738c2ecf20Sopenharmony_ci return inode_has_perm(cred, inode, av, &ad); 16748c2ecf20Sopenharmony_ci} 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci/* Same as inode_has_perm, but pass explicit audit data containing 16778c2ecf20Sopenharmony_ci the path to help the auditing code to more easily generate the 16788c2ecf20Sopenharmony_ci pathname if needed. */ 16798c2ecf20Sopenharmony_cistatic inline int path_has_perm(const struct cred *cred, 16808c2ecf20Sopenharmony_ci const struct path *path, 16818c2ecf20Sopenharmony_ci u32 av) 16828c2ecf20Sopenharmony_ci{ 16838c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(path->dentry); 16848c2ecf20Sopenharmony_ci struct common_audit_data ad; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_PATH; 16878c2ecf20Sopenharmony_ci ad.u.path = *path; 16888c2ecf20Sopenharmony_ci __inode_security_revalidate(inode, path->dentry, true); 16898c2ecf20Sopenharmony_ci return inode_has_perm(cred, inode, av, &ad); 16908c2ecf20Sopenharmony_ci} 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci/* Same as path_has_perm, but uses the inode from the file struct. */ 16938c2ecf20Sopenharmony_cistatic inline int file_path_has_perm(const struct cred *cred, 16948c2ecf20Sopenharmony_ci struct file *file, 16958c2ecf20Sopenharmony_ci u32 av) 16968c2ecf20Sopenharmony_ci{ 16978c2ecf20Sopenharmony_ci struct common_audit_data ad; 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_FILE; 17008c2ecf20Sopenharmony_ci ad.u.file = file; 17018c2ecf20Sopenharmony_ci return inode_has_perm(cred, file_inode(file), av, &ad); 17028c2ecf20Sopenharmony_ci} 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 17058c2ecf20Sopenharmony_cistatic int bpf_fd_pass(struct file *file, u32 sid); 17068c2ecf20Sopenharmony_ci#endif 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci/* Check whether a task can use an open file descriptor to 17098c2ecf20Sopenharmony_ci access an inode in a given way. Check access to the 17108c2ecf20Sopenharmony_ci descriptor itself, and then use dentry_has_perm to 17118c2ecf20Sopenharmony_ci check a particular permission to the file. 17128c2ecf20Sopenharmony_ci Access to the descriptor is implicitly granted if it 17138c2ecf20Sopenharmony_ci has the same SID as the process. If av is zero, then 17148c2ecf20Sopenharmony_ci access to the file is not checked, e.g. for cases 17158c2ecf20Sopenharmony_ci where only the descriptor is affected like seek. */ 17168c2ecf20Sopenharmony_cistatic int file_has_perm(const struct cred *cred, 17178c2ecf20Sopenharmony_ci struct file *file, 17188c2ecf20Sopenharmony_ci u32 av) 17198c2ecf20Sopenharmony_ci{ 17208c2ecf20Sopenharmony_ci struct file_security_struct *fsec = selinux_file(file); 17218c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 17228c2ecf20Sopenharmony_ci struct common_audit_data ad; 17238c2ecf20Sopenharmony_ci u32 sid = cred_sid(cred); 17248c2ecf20Sopenharmony_ci int rc; 17258c2ecf20Sopenharmony_ci 17268c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_FILE; 17278c2ecf20Sopenharmony_ci ad.u.file = file; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci if (sid != fsec->sid) { 17308c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 17318c2ecf20Sopenharmony_ci sid, fsec->sid, 17328c2ecf20Sopenharmony_ci SECCLASS_FD, 17338c2ecf20Sopenharmony_ci FD__USE, 17348c2ecf20Sopenharmony_ci &ad); 17358c2ecf20Sopenharmony_ci if (rc) 17368c2ecf20Sopenharmony_ci goto out; 17378c2ecf20Sopenharmony_ci } 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 17408c2ecf20Sopenharmony_ci rc = bpf_fd_pass(file, cred_sid(cred)); 17418c2ecf20Sopenharmony_ci if (rc) 17428c2ecf20Sopenharmony_ci return rc; 17438c2ecf20Sopenharmony_ci#endif 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci /* av is zero if only checking access to the descriptor. */ 17468c2ecf20Sopenharmony_ci rc = 0; 17478c2ecf20Sopenharmony_ci if (av) 17488c2ecf20Sopenharmony_ci rc = inode_has_perm(cred, inode, av, &ad); 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ciout: 17518c2ecf20Sopenharmony_ci return rc; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci/* 17558c2ecf20Sopenharmony_ci * Determine the label for an inode that might be unioned. 17568c2ecf20Sopenharmony_ci */ 17578c2ecf20Sopenharmony_cistatic int 17588c2ecf20Sopenharmony_ciselinux_determine_inode_label(const struct task_security_struct *tsec, 17598c2ecf20Sopenharmony_ci struct inode *dir, 17608c2ecf20Sopenharmony_ci const struct qstr *name, u16 tclass, 17618c2ecf20Sopenharmony_ci u32 *_new_isid) 17628c2ecf20Sopenharmony_ci{ 17638c2ecf20Sopenharmony_ci const struct superblock_security_struct *sbsec = dir->i_sb->s_security; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if ((sbsec->flags & SE_SBINITIALIZED) && 17668c2ecf20Sopenharmony_ci (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) { 17678c2ecf20Sopenharmony_ci *_new_isid = sbsec->mntpoint_sid; 17688c2ecf20Sopenharmony_ci } else if ((sbsec->flags & SBLABEL_MNT) && 17698c2ecf20Sopenharmony_ci tsec->create_sid) { 17708c2ecf20Sopenharmony_ci *_new_isid = tsec->create_sid; 17718c2ecf20Sopenharmony_ci } else { 17728c2ecf20Sopenharmony_ci const struct inode_security_struct *dsec = inode_security(dir); 17738c2ecf20Sopenharmony_ci return security_transition_sid(&selinux_state, tsec->sid, 17748c2ecf20Sopenharmony_ci dsec->sid, tclass, 17758c2ecf20Sopenharmony_ci name, _new_isid); 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci return 0; 17798c2ecf20Sopenharmony_ci} 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci/* Check whether a task can create a file. */ 17828c2ecf20Sopenharmony_cistatic int may_create(struct inode *dir, 17838c2ecf20Sopenharmony_ci struct dentry *dentry, 17848c2ecf20Sopenharmony_ci u16 tclass) 17858c2ecf20Sopenharmony_ci{ 17868c2ecf20Sopenharmony_ci const struct task_security_struct *tsec = selinux_cred(current_cred()); 17878c2ecf20Sopenharmony_ci struct inode_security_struct *dsec; 17888c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec; 17898c2ecf20Sopenharmony_ci u32 sid, newsid; 17908c2ecf20Sopenharmony_ci struct common_audit_data ad; 17918c2ecf20Sopenharmony_ci int rc; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci dsec = inode_security(dir); 17948c2ecf20Sopenharmony_ci sbsec = dir->i_sb->s_security; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci sid = tsec->sid; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_DENTRY; 17998c2ecf20Sopenharmony_ci ad.u.dentry = dentry; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 18028c2ecf20Sopenharmony_ci sid, dsec->sid, SECCLASS_DIR, 18038c2ecf20Sopenharmony_ci DIR__ADD_NAME | DIR__SEARCH, 18048c2ecf20Sopenharmony_ci &ad); 18058c2ecf20Sopenharmony_ci if (rc) 18068c2ecf20Sopenharmony_ci return rc; 18078c2ecf20Sopenharmony_ci 18088c2ecf20Sopenharmony_ci rc = selinux_determine_inode_label(tsec, dir, &dentry->d_name, tclass, 18098c2ecf20Sopenharmony_ci &newsid); 18108c2ecf20Sopenharmony_ci if (rc) 18118c2ecf20Sopenharmony_ci return rc; 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 18148c2ecf20Sopenharmony_ci sid, newsid, tclass, FILE__CREATE, &ad); 18158c2ecf20Sopenharmony_ci if (rc) 18168c2ecf20Sopenharmony_ci return rc; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 18198c2ecf20Sopenharmony_ci newsid, sbsec->sid, 18208c2ecf20Sopenharmony_ci SECCLASS_FILESYSTEM, 18218c2ecf20Sopenharmony_ci FILESYSTEM__ASSOCIATE, &ad); 18228c2ecf20Sopenharmony_ci} 18238c2ecf20Sopenharmony_ci 18248c2ecf20Sopenharmony_ci#define MAY_LINK 0 18258c2ecf20Sopenharmony_ci#define MAY_UNLINK 1 18268c2ecf20Sopenharmony_ci#define MAY_RMDIR 2 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci/* Check whether a task can link, unlink, or rmdir a file/directory. */ 18298c2ecf20Sopenharmony_cistatic int may_link(struct inode *dir, 18308c2ecf20Sopenharmony_ci struct dentry *dentry, 18318c2ecf20Sopenharmony_ci int kind) 18328c2ecf20Sopenharmony_ci 18338c2ecf20Sopenharmony_ci{ 18348c2ecf20Sopenharmony_ci struct inode_security_struct *dsec, *isec; 18358c2ecf20Sopenharmony_ci struct common_audit_data ad; 18368c2ecf20Sopenharmony_ci u32 sid = current_sid(); 18378c2ecf20Sopenharmony_ci u32 av; 18388c2ecf20Sopenharmony_ci int rc; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci dsec = inode_security(dir); 18418c2ecf20Sopenharmony_ci isec = backing_inode_security(dentry); 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_DENTRY; 18448c2ecf20Sopenharmony_ci ad.u.dentry = dentry; 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_ci av = DIR__SEARCH; 18478c2ecf20Sopenharmony_ci av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); 18488c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 18498c2ecf20Sopenharmony_ci sid, dsec->sid, SECCLASS_DIR, av, &ad); 18508c2ecf20Sopenharmony_ci if (rc) 18518c2ecf20Sopenharmony_ci return rc; 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci switch (kind) { 18548c2ecf20Sopenharmony_ci case MAY_LINK: 18558c2ecf20Sopenharmony_ci av = FILE__LINK; 18568c2ecf20Sopenharmony_ci break; 18578c2ecf20Sopenharmony_ci case MAY_UNLINK: 18588c2ecf20Sopenharmony_ci av = FILE__UNLINK; 18598c2ecf20Sopenharmony_ci break; 18608c2ecf20Sopenharmony_ci case MAY_RMDIR: 18618c2ecf20Sopenharmony_ci av = DIR__RMDIR; 18628c2ecf20Sopenharmony_ci break; 18638c2ecf20Sopenharmony_ci default: 18648c2ecf20Sopenharmony_ci pr_warn("SELinux: %s: unrecognized kind %d\n", 18658c2ecf20Sopenharmony_ci __func__, kind); 18668c2ecf20Sopenharmony_ci return 0; 18678c2ecf20Sopenharmony_ci } 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 18708c2ecf20Sopenharmony_ci sid, isec->sid, isec->sclass, av, &ad); 18718c2ecf20Sopenharmony_ci return rc; 18728c2ecf20Sopenharmony_ci} 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_cistatic inline int may_rename(struct inode *old_dir, 18758c2ecf20Sopenharmony_ci struct dentry *old_dentry, 18768c2ecf20Sopenharmony_ci struct inode *new_dir, 18778c2ecf20Sopenharmony_ci struct dentry *new_dentry) 18788c2ecf20Sopenharmony_ci{ 18798c2ecf20Sopenharmony_ci struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; 18808c2ecf20Sopenharmony_ci struct common_audit_data ad; 18818c2ecf20Sopenharmony_ci u32 sid = current_sid(); 18828c2ecf20Sopenharmony_ci u32 av; 18838c2ecf20Sopenharmony_ci int old_is_dir, new_is_dir; 18848c2ecf20Sopenharmony_ci int rc; 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_ci old_dsec = inode_security(old_dir); 18878c2ecf20Sopenharmony_ci old_isec = backing_inode_security(old_dentry); 18888c2ecf20Sopenharmony_ci old_is_dir = d_is_dir(old_dentry); 18898c2ecf20Sopenharmony_ci new_dsec = inode_security(new_dir); 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_DENTRY; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci ad.u.dentry = old_dentry; 18948c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 18958c2ecf20Sopenharmony_ci sid, old_dsec->sid, SECCLASS_DIR, 18968c2ecf20Sopenharmony_ci DIR__REMOVE_NAME | DIR__SEARCH, &ad); 18978c2ecf20Sopenharmony_ci if (rc) 18988c2ecf20Sopenharmony_ci return rc; 18998c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 19008c2ecf20Sopenharmony_ci sid, old_isec->sid, 19018c2ecf20Sopenharmony_ci old_isec->sclass, FILE__RENAME, &ad); 19028c2ecf20Sopenharmony_ci if (rc) 19038c2ecf20Sopenharmony_ci return rc; 19048c2ecf20Sopenharmony_ci if (old_is_dir && new_dir != old_dir) { 19058c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 19068c2ecf20Sopenharmony_ci sid, old_isec->sid, 19078c2ecf20Sopenharmony_ci old_isec->sclass, DIR__REPARENT, &ad); 19088c2ecf20Sopenharmony_ci if (rc) 19098c2ecf20Sopenharmony_ci return rc; 19108c2ecf20Sopenharmony_ci } 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci ad.u.dentry = new_dentry; 19138c2ecf20Sopenharmony_ci av = DIR__ADD_NAME | DIR__SEARCH; 19148c2ecf20Sopenharmony_ci if (d_is_positive(new_dentry)) 19158c2ecf20Sopenharmony_ci av |= DIR__REMOVE_NAME; 19168c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 19178c2ecf20Sopenharmony_ci sid, new_dsec->sid, SECCLASS_DIR, av, &ad); 19188c2ecf20Sopenharmony_ci if (rc) 19198c2ecf20Sopenharmony_ci return rc; 19208c2ecf20Sopenharmony_ci if (d_is_positive(new_dentry)) { 19218c2ecf20Sopenharmony_ci new_isec = backing_inode_security(new_dentry); 19228c2ecf20Sopenharmony_ci new_is_dir = d_is_dir(new_dentry); 19238c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 19248c2ecf20Sopenharmony_ci sid, new_isec->sid, 19258c2ecf20Sopenharmony_ci new_isec->sclass, 19268c2ecf20Sopenharmony_ci (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad); 19278c2ecf20Sopenharmony_ci if (rc) 19288c2ecf20Sopenharmony_ci return rc; 19298c2ecf20Sopenharmony_ci } 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci return 0; 19328c2ecf20Sopenharmony_ci} 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ci/* Check whether a task can perform a filesystem operation. */ 19358c2ecf20Sopenharmony_cistatic int superblock_has_perm(const struct cred *cred, 19368c2ecf20Sopenharmony_ci struct super_block *sb, 19378c2ecf20Sopenharmony_ci u32 perms, 19388c2ecf20Sopenharmony_ci struct common_audit_data *ad) 19398c2ecf20Sopenharmony_ci{ 19408c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec; 19418c2ecf20Sopenharmony_ci u32 sid = cred_sid(cred); 19428c2ecf20Sopenharmony_ci 19438c2ecf20Sopenharmony_ci sbsec = sb->s_security; 19448c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 19458c2ecf20Sopenharmony_ci sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad); 19468c2ecf20Sopenharmony_ci} 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci/* Convert a Linux mode and permission mask to an access vector. */ 19498c2ecf20Sopenharmony_cistatic inline u32 file_mask_to_av(int mode, int mask) 19508c2ecf20Sopenharmony_ci{ 19518c2ecf20Sopenharmony_ci u32 av = 0; 19528c2ecf20Sopenharmony_ci 19538c2ecf20Sopenharmony_ci if (!S_ISDIR(mode)) { 19548c2ecf20Sopenharmony_ci if (mask & MAY_EXEC) 19558c2ecf20Sopenharmony_ci av |= FILE__EXECUTE; 19568c2ecf20Sopenharmony_ci if (mask & MAY_READ) 19578c2ecf20Sopenharmony_ci av |= FILE__READ; 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci if (mask & MAY_APPEND) 19608c2ecf20Sopenharmony_ci av |= FILE__APPEND; 19618c2ecf20Sopenharmony_ci else if (mask & MAY_WRITE) 19628c2ecf20Sopenharmony_ci av |= FILE__WRITE; 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci } else { 19658c2ecf20Sopenharmony_ci if (mask & MAY_EXEC) 19668c2ecf20Sopenharmony_ci av |= DIR__SEARCH; 19678c2ecf20Sopenharmony_ci if (mask & MAY_WRITE) 19688c2ecf20Sopenharmony_ci av |= DIR__WRITE; 19698c2ecf20Sopenharmony_ci if (mask & MAY_READ) 19708c2ecf20Sopenharmony_ci av |= DIR__READ; 19718c2ecf20Sopenharmony_ci } 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_ci return av; 19748c2ecf20Sopenharmony_ci} 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci/* Convert a Linux file to an access vector. */ 19778c2ecf20Sopenharmony_cistatic inline u32 file_to_av(struct file *file) 19788c2ecf20Sopenharmony_ci{ 19798c2ecf20Sopenharmony_ci u32 av = 0; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci if (file->f_mode & FMODE_READ) 19828c2ecf20Sopenharmony_ci av |= FILE__READ; 19838c2ecf20Sopenharmony_ci if (file->f_mode & FMODE_WRITE) { 19848c2ecf20Sopenharmony_ci if (file->f_flags & O_APPEND) 19858c2ecf20Sopenharmony_ci av |= FILE__APPEND; 19868c2ecf20Sopenharmony_ci else 19878c2ecf20Sopenharmony_ci av |= FILE__WRITE; 19888c2ecf20Sopenharmony_ci } 19898c2ecf20Sopenharmony_ci if (!av) { 19908c2ecf20Sopenharmony_ci /* 19918c2ecf20Sopenharmony_ci * Special file opened with flags 3 for ioctl-only use. 19928c2ecf20Sopenharmony_ci */ 19938c2ecf20Sopenharmony_ci av = FILE__IOCTL; 19948c2ecf20Sopenharmony_ci } 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci return av; 19978c2ecf20Sopenharmony_ci} 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci/* 20008c2ecf20Sopenharmony_ci * Convert a file to an access vector and include the correct 20018c2ecf20Sopenharmony_ci * open permission. 20028c2ecf20Sopenharmony_ci */ 20038c2ecf20Sopenharmony_cistatic inline u32 open_file_to_av(struct file *file) 20048c2ecf20Sopenharmony_ci{ 20058c2ecf20Sopenharmony_ci u32 av = file_to_av(file); 20068c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci if (selinux_policycap_openperm() && 20098c2ecf20Sopenharmony_ci inode->i_sb->s_magic != SOCKFS_MAGIC) 20108c2ecf20Sopenharmony_ci av |= FILE__OPEN; 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci return av; 20138c2ecf20Sopenharmony_ci} 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci/* Hook functions begin here. */ 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_cistatic int selinux_binder_set_context_mgr(const struct cred *mgr) 20188c2ecf20Sopenharmony_ci{ 20198c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 20208c2ecf20Sopenharmony_ci current_sid(), cred_sid(mgr), SECCLASS_BINDER, 20218c2ecf20Sopenharmony_ci BINDER__SET_CONTEXT_MGR, NULL); 20228c2ecf20Sopenharmony_ci} 20238c2ecf20Sopenharmony_ci 20248c2ecf20Sopenharmony_cistatic int selinux_binder_transaction(const struct cred *from, 20258c2ecf20Sopenharmony_ci const struct cred *to) 20268c2ecf20Sopenharmony_ci{ 20278c2ecf20Sopenharmony_ci u32 mysid = current_sid(); 20288c2ecf20Sopenharmony_ci u32 fromsid = cred_sid(from); 20298c2ecf20Sopenharmony_ci u32 tosid = cred_sid(to); 20308c2ecf20Sopenharmony_ci int rc; 20318c2ecf20Sopenharmony_ci 20328c2ecf20Sopenharmony_ci if (mysid != fromsid) { 20338c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 20348c2ecf20Sopenharmony_ci mysid, fromsid, SECCLASS_BINDER, 20358c2ecf20Sopenharmony_ci BINDER__IMPERSONATE, NULL); 20368c2ecf20Sopenharmony_ci if (rc) 20378c2ecf20Sopenharmony_ci return rc; 20388c2ecf20Sopenharmony_ci } 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, fromsid, tosid, 20418c2ecf20Sopenharmony_ci SECCLASS_BINDER, BINDER__CALL, NULL); 20428c2ecf20Sopenharmony_ci} 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_cistatic int selinux_binder_transfer_binder(const struct cred *from, 20458c2ecf20Sopenharmony_ci const struct cred *to) 20468c2ecf20Sopenharmony_ci{ 20478c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 20488c2ecf20Sopenharmony_ci cred_sid(from), cred_sid(to), 20498c2ecf20Sopenharmony_ci SECCLASS_BINDER, BINDER__TRANSFER, 20508c2ecf20Sopenharmony_ci NULL); 20518c2ecf20Sopenharmony_ci} 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_cistatic int selinux_binder_transfer_file(const struct cred *from, 20548c2ecf20Sopenharmony_ci const struct cred *to, 20558c2ecf20Sopenharmony_ci struct file *file) 20568c2ecf20Sopenharmony_ci{ 20578c2ecf20Sopenharmony_ci u32 sid = cred_sid(to); 20588c2ecf20Sopenharmony_ci struct file_security_struct *fsec = selinux_file(file); 20598c2ecf20Sopenharmony_ci struct dentry *dentry = file->f_path.dentry; 20608c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 20618c2ecf20Sopenharmony_ci struct common_audit_data ad; 20628c2ecf20Sopenharmony_ci int rc; 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_PATH; 20658c2ecf20Sopenharmony_ci ad.u.path = file->f_path; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci if (sid != fsec->sid) { 20688c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 20698c2ecf20Sopenharmony_ci sid, fsec->sid, 20708c2ecf20Sopenharmony_ci SECCLASS_FD, 20718c2ecf20Sopenharmony_ci FD__USE, 20728c2ecf20Sopenharmony_ci &ad); 20738c2ecf20Sopenharmony_ci if (rc) 20748c2ecf20Sopenharmony_ci return rc; 20758c2ecf20Sopenharmony_ci } 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 20788c2ecf20Sopenharmony_ci rc = bpf_fd_pass(file, sid); 20798c2ecf20Sopenharmony_ci if (rc) 20808c2ecf20Sopenharmony_ci return rc; 20818c2ecf20Sopenharmony_ci#endif 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) 20848c2ecf20Sopenharmony_ci return 0; 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci isec = backing_inode_security(dentry); 20878c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 20888c2ecf20Sopenharmony_ci sid, isec->sid, isec->sclass, file_to_av(file), 20898c2ecf20Sopenharmony_ci &ad); 20908c2ecf20Sopenharmony_ci} 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_cistatic int selinux_ptrace_access_check(struct task_struct *child, 20938c2ecf20Sopenharmony_ci unsigned int mode) 20948c2ecf20Sopenharmony_ci{ 20958c2ecf20Sopenharmony_ci u32 sid = current_sid(); 20968c2ecf20Sopenharmony_ci u32 csid = task_sid(child); 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci if (mode & PTRACE_MODE_READ) 20998c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 21008c2ecf20Sopenharmony_ci sid, csid, SECCLASS_FILE, FILE__READ, NULL); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 21038c2ecf20Sopenharmony_ci sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE, NULL); 21048c2ecf20Sopenharmony_ci} 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_cistatic int selinux_ptrace_traceme(struct task_struct *parent) 21078c2ecf20Sopenharmony_ci{ 21088c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 21098c2ecf20Sopenharmony_ci task_sid(parent), current_sid(), SECCLASS_PROCESS, 21108c2ecf20Sopenharmony_ci PROCESS__PTRACE, NULL); 21118c2ecf20Sopenharmony_ci} 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_cistatic int selinux_capget(struct task_struct *target, kernel_cap_t *effective, 21148c2ecf20Sopenharmony_ci kernel_cap_t *inheritable, kernel_cap_t *permitted) 21158c2ecf20Sopenharmony_ci{ 21168c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 21178c2ecf20Sopenharmony_ci current_sid(), task_sid(target), SECCLASS_PROCESS, 21188c2ecf20Sopenharmony_ci PROCESS__GETCAP, NULL); 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_cistatic int selinux_capset(struct cred *new, const struct cred *old, 21228c2ecf20Sopenharmony_ci const kernel_cap_t *effective, 21238c2ecf20Sopenharmony_ci const kernel_cap_t *inheritable, 21248c2ecf20Sopenharmony_ci const kernel_cap_t *permitted) 21258c2ecf20Sopenharmony_ci{ 21268c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 21278c2ecf20Sopenharmony_ci cred_sid(old), cred_sid(new), SECCLASS_PROCESS, 21288c2ecf20Sopenharmony_ci PROCESS__SETCAP, NULL); 21298c2ecf20Sopenharmony_ci} 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci/* 21328c2ecf20Sopenharmony_ci * (This comment used to live with the selinux_task_setuid hook, 21338c2ecf20Sopenharmony_ci * which was removed). 21348c2ecf20Sopenharmony_ci * 21358c2ecf20Sopenharmony_ci * Since setuid only affects the current process, and since the SELinux 21368c2ecf20Sopenharmony_ci * controls are not based on the Linux identity attributes, SELinux does not 21378c2ecf20Sopenharmony_ci * need to control this operation. However, SELinux does control the use of 21388c2ecf20Sopenharmony_ci * the CAP_SETUID and CAP_SETGID capabilities using the capable hook. 21398c2ecf20Sopenharmony_ci */ 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_cistatic int selinux_capable(const struct cred *cred, struct user_namespace *ns, 21428c2ecf20Sopenharmony_ci int cap, unsigned int opts) 21438c2ecf20Sopenharmony_ci{ 21448c2ecf20Sopenharmony_ci return cred_has_capability(cred, cap, opts, ns == &init_user_ns); 21458c2ecf20Sopenharmony_ci} 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_cistatic int selinux_quotactl(int cmds, int type, int id, struct super_block *sb) 21488c2ecf20Sopenharmony_ci{ 21498c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 21508c2ecf20Sopenharmony_ci int rc = 0; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci if (!sb) 21538c2ecf20Sopenharmony_ci return 0; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci switch (cmds) { 21568c2ecf20Sopenharmony_ci case Q_SYNC: 21578c2ecf20Sopenharmony_ci case Q_QUOTAON: 21588c2ecf20Sopenharmony_ci case Q_QUOTAOFF: 21598c2ecf20Sopenharmony_ci case Q_SETINFO: 21608c2ecf20Sopenharmony_ci case Q_SETQUOTA: 21618c2ecf20Sopenharmony_ci case Q_XQUOTAOFF: 21628c2ecf20Sopenharmony_ci case Q_XQUOTAON: 21638c2ecf20Sopenharmony_ci case Q_XSETQLIM: 21648c2ecf20Sopenharmony_ci rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL); 21658c2ecf20Sopenharmony_ci break; 21668c2ecf20Sopenharmony_ci case Q_GETFMT: 21678c2ecf20Sopenharmony_ci case Q_GETINFO: 21688c2ecf20Sopenharmony_ci case Q_GETQUOTA: 21698c2ecf20Sopenharmony_ci case Q_XGETQUOTA: 21708c2ecf20Sopenharmony_ci case Q_XGETQSTAT: 21718c2ecf20Sopenharmony_ci case Q_XGETQSTATV: 21728c2ecf20Sopenharmony_ci case Q_XGETNEXTQUOTA: 21738c2ecf20Sopenharmony_ci rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL); 21748c2ecf20Sopenharmony_ci break; 21758c2ecf20Sopenharmony_ci default: 21768c2ecf20Sopenharmony_ci rc = 0; /* let the kernel handle invalid cmds */ 21778c2ecf20Sopenharmony_ci break; 21788c2ecf20Sopenharmony_ci } 21798c2ecf20Sopenharmony_ci return rc; 21808c2ecf20Sopenharmony_ci} 21818c2ecf20Sopenharmony_ci 21828c2ecf20Sopenharmony_cistatic int selinux_quota_on(struct dentry *dentry) 21838c2ecf20Sopenharmony_ci{ 21848c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci return dentry_has_perm(cred, dentry, FILE__QUOTAON); 21878c2ecf20Sopenharmony_ci} 21888c2ecf20Sopenharmony_ci 21898c2ecf20Sopenharmony_cistatic int selinux_syslog(int type) 21908c2ecf20Sopenharmony_ci{ 21918c2ecf20Sopenharmony_ci switch (type) { 21928c2ecf20Sopenharmony_ci case SYSLOG_ACTION_READ_ALL: /* Read last kernel messages */ 21938c2ecf20Sopenharmony_ci case SYSLOG_ACTION_SIZE_BUFFER: /* Return size of the log buffer */ 21948c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 21958c2ecf20Sopenharmony_ci current_sid(), SECINITSID_KERNEL, 21968c2ecf20Sopenharmony_ci SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL); 21978c2ecf20Sopenharmony_ci case SYSLOG_ACTION_CONSOLE_OFF: /* Disable logging to console */ 21988c2ecf20Sopenharmony_ci case SYSLOG_ACTION_CONSOLE_ON: /* Enable logging to console */ 21998c2ecf20Sopenharmony_ci /* Set level of messages printed to console */ 22008c2ecf20Sopenharmony_ci case SYSLOG_ACTION_CONSOLE_LEVEL: 22018c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 22028c2ecf20Sopenharmony_ci current_sid(), SECINITSID_KERNEL, 22038c2ecf20Sopenharmony_ci SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, 22048c2ecf20Sopenharmony_ci NULL); 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci /* All other syslog types */ 22078c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 22088c2ecf20Sopenharmony_ci current_sid(), SECINITSID_KERNEL, 22098c2ecf20Sopenharmony_ci SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL); 22108c2ecf20Sopenharmony_ci} 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_ci/* 22138c2ecf20Sopenharmony_ci * Check that a process has enough memory to allocate a new virtual 22148c2ecf20Sopenharmony_ci * mapping. 0 means there is enough memory for the allocation to 22158c2ecf20Sopenharmony_ci * succeed and -ENOMEM implies there is not. 22168c2ecf20Sopenharmony_ci * 22178c2ecf20Sopenharmony_ci * Do not audit the selinux permission check, as this is applied to all 22188c2ecf20Sopenharmony_ci * processes that allocate mappings. 22198c2ecf20Sopenharmony_ci */ 22208c2ecf20Sopenharmony_cistatic int selinux_vm_enough_memory(struct mm_struct *mm, long pages) 22218c2ecf20Sopenharmony_ci{ 22228c2ecf20Sopenharmony_ci int rc, cap_sys_admin = 0; 22238c2ecf20Sopenharmony_ci 22248c2ecf20Sopenharmony_ci rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN, 22258c2ecf20Sopenharmony_ci CAP_OPT_NOAUDIT, true); 22268c2ecf20Sopenharmony_ci if (rc == 0) 22278c2ecf20Sopenharmony_ci cap_sys_admin = 1; 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci return cap_sys_admin; 22308c2ecf20Sopenharmony_ci} 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci/* binprm security operations */ 22338c2ecf20Sopenharmony_ci 22348c2ecf20Sopenharmony_cistatic u32 ptrace_parent_sid(void) 22358c2ecf20Sopenharmony_ci{ 22368c2ecf20Sopenharmony_ci u32 sid = 0; 22378c2ecf20Sopenharmony_ci struct task_struct *tracer; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci rcu_read_lock(); 22408c2ecf20Sopenharmony_ci tracer = ptrace_parent(current); 22418c2ecf20Sopenharmony_ci if (tracer) 22428c2ecf20Sopenharmony_ci sid = task_sid(tracer); 22438c2ecf20Sopenharmony_ci rcu_read_unlock(); 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci return sid; 22468c2ecf20Sopenharmony_ci} 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_cistatic int check_nnp_nosuid(const struct linux_binprm *bprm, 22498c2ecf20Sopenharmony_ci const struct task_security_struct *old_tsec, 22508c2ecf20Sopenharmony_ci const struct task_security_struct *new_tsec) 22518c2ecf20Sopenharmony_ci{ 22528c2ecf20Sopenharmony_ci int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS); 22538c2ecf20Sopenharmony_ci int nosuid = !mnt_may_suid(bprm->file->f_path.mnt); 22548c2ecf20Sopenharmony_ci int rc; 22558c2ecf20Sopenharmony_ci u32 av; 22568c2ecf20Sopenharmony_ci 22578c2ecf20Sopenharmony_ci if (!nnp && !nosuid) 22588c2ecf20Sopenharmony_ci return 0; /* neither NNP nor nosuid */ 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci if (new_tsec->sid == old_tsec->sid) 22618c2ecf20Sopenharmony_ci return 0; /* No change in credentials */ 22628c2ecf20Sopenharmony_ci 22638c2ecf20Sopenharmony_ci /* 22648c2ecf20Sopenharmony_ci * If the policy enables the nnp_nosuid_transition policy capability, 22658c2ecf20Sopenharmony_ci * then we permit transitions under NNP or nosuid if the 22668c2ecf20Sopenharmony_ci * policy allows the corresponding permission between 22678c2ecf20Sopenharmony_ci * the old and new contexts. 22688c2ecf20Sopenharmony_ci */ 22698c2ecf20Sopenharmony_ci if (selinux_policycap_nnp_nosuid_transition()) { 22708c2ecf20Sopenharmony_ci av = 0; 22718c2ecf20Sopenharmony_ci if (nnp) 22728c2ecf20Sopenharmony_ci av |= PROCESS2__NNP_TRANSITION; 22738c2ecf20Sopenharmony_ci if (nosuid) 22748c2ecf20Sopenharmony_ci av |= PROCESS2__NOSUID_TRANSITION; 22758c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 22768c2ecf20Sopenharmony_ci old_tsec->sid, new_tsec->sid, 22778c2ecf20Sopenharmony_ci SECCLASS_PROCESS2, av, NULL); 22788c2ecf20Sopenharmony_ci if (!rc) 22798c2ecf20Sopenharmony_ci return 0; 22808c2ecf20Sopenharmony_ci } 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci /* 22838c2ecf20Sopenharmony_ci * We also permit NNP or nosuid transitions to bounded SIDs, 22848c2ecf20Sopenharmony_ci * i.e. SIDs that are guaranteed to only be allowed a subset 22858c2ecf20Sopenharmony_ci * of the permissions of the current SID. 22868c2ecf20Sopenharmony_ci */ 22878c2ecf20Sopenharmony_ci rc = security_bounded_transition(&selinux_state, old_tsec->sid, 22888c2ecf20Sopenharmony_ci new_tsec->sid); 22898c2ecf20Sopenharmony_ci if (!rc) 22908c2ecf20Sopenharmony_ci return 0; 22918c2ecf20Sopenharmony_ci 22928c2ecf20Sopenharmony_ci /* 22938c2ecf20Sopenharmony_ci * On failure, preserve the errno values for NNP vs nosuid. 22948c2ecf20Sopenharmony_ci * NNP: Operation not permitted for caller. 22958c2ecf20Sopenharmony_ci * nosuid: Permission denied to file. 22968c2ecf20Sopenharmony_ci */ 22978c2ecf20Sopenharmony_ci if (nnp) 22988c2ecf20Sopenharmony_ci return -EPERM; 22998c2ecf20Sopenharmony_ci return -EACCES; 23008c2ecf20Sopenharmony_ci} 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_cistatic int selinux_bprm_creds_for_exec(struct linux_binprm *bprm) 23038c2ecf20Sopenharmony_ci{ 23048c2ecf20Sopenharmony_ci const struct task_security_struct *old_tsec; 23058c2ecf20Sopenharmony_ci struct task_security_struct *new_tsec; 23068c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 23078c2ecf20Sopenharmony_ci struct common_audit_data ad; 23088c2ecf20Sopenharmony_ci struct inode *inode = file_inode(bprm->file); 23098c2ecf20Sopenharmony_ci int rc; 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci /* SELinux context only depends on initial program or script and not 23128c2ecf20Sopenharmony_ci * the script interpreter */ 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci old_tsec = selinux_cred(current_cred()); 23158c2ecf20Sopenharmony_ci new_tsec = selinux_cred(bprm->cred); 23168c2ecf20Sopenharmony_ci isec = inode_security(inode); 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci /* Default to the current task SID. */ 23198c2ecf20Sopenharmony_ci new_tsec->sid = old_tsec->sid; 23208c2ecf20Sopenharmony_ci new_tsec->osid = old_tsec->sid; 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci /* Reset fs, key, and sock SIDs on execve. */ 23238c2ecf20Sopenharmony_ci new_tsec->create_sid = 0; 23248c2ecf20Sopenharmony_ci new_tsec->keycreate_sid = 0; 23258c2ecf20Sopenharmony_ci new_tsec->sockcreate_sid = 0; 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci if (old_tsec->exec_sid) { 23288c2ecf20Sopenharmony_ci new_tsec->sid = old_tsec->exec_sid; 23298c2ecf20Sopenharmony_ci /* Reset exec SID on execve. */ 23308c2ecf20Sopenharmony_ci new_tsec->exec_sid = 0; 23318c2ecf20Sopenharmony_ci 23328c2ecf20Sopenharmony_ci /* Fail on NNP or nosuid if not an allowed transition. */ 23338c2ecf20Sopenharmony_ci rc = check_nnp_nosuid(bprm, old_tsec, new_tsec); 23348c2ecf20Sopenharmony_ci if (rc) 23358c2ecf20Sopenharmony_ci return rc; 23368c2ecf20Sopenharmony_ci } else { 23378c2ecf20Sopenharmony_ci /* Check for a default transition on this program. */ 23388c2ecf20Sopenharmony_ci rc = security_transition_sid(&selinux_state, old_tsec->sid, 23398c2ecf20Sopenharmony_ci isec->sid, SECCLASS_PROCESS, NULL, 23408c2ecf20Sopenharmony_ci &new_tsec->sid); 23418c2ecf20Sopenharmony_ci if (rc) 23428c2ecf20Sopenharmony_ci return rc; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci /* 23458c2ecf20Sopenharmony_ci * Fallback to old SID on NNP or nosuid if not an allowed 23468c2ecf20Sopenharmony_ci * transition. 23478c2ecf20Sopenharmony_ci */ 23488c2ecf20Sopenharmony_ci rc = check_nnp_nosuid(bprm, old_tsec, new_tsec); 23498c2ecf20Sopenharmony_ci if (rc) 23508c2ecf20Sopenharmony_ci new_tsec->sid = old_tsec->sid; 23518c2ecf20Sopenharmony_ci } 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_FILE; 23548c2ecf20Sopenharmony_ci ad.u.file = bprm->file; 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci if (new_tsec->sid == old_tsec->sid) { 23578c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 23588c2ecf20Sopenharmony_ci old_tsec->sid, isec->sid, 23598c2ecf20Sopenharmony_ci SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad); 23608c2ecf20Sopenharmony_ci if (rc) 23618c2ecf20Sopenharmony_ci return rc; 23628c2ecf20Sopenharmony_ci } else { 23638c2ecf20Sopenharmony_ci /* Check permissions for the transition. */ 23648c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 23658c2ecf20Sopenharmony_ci old_tsec->sid, new_tsec->sid, 23668c2ecf20Sopenharmony_ci SECCLASS_PROCESS, PROCESS__TRANSITION, &ad); 23678c2ecf20Sopenharmony_ci if (rc) 23688c2ecf20Sopenharmony_ci return rc; 23698c2ecf20Sopenharmony_ci 23708c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 23718c2ecf20Sopenharmony_ci new_tsec->sid, isec->sid, 23728c2ecf20Sopenharmony_ci SECCLASS_FILE, FILE__ENTRYPOINT, &ad); 23738c2ecf20Sopenharmony_ci if (rc) 23748c2ecf20Sopenharmony_ci return rc; 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci /* Check for shared state */ 23778c2ecf20Sopenharmony_ci if (bprm->unsafe & LSM_UNSAFE_SHARE) { 23788c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 23798c2ecf20Sopenharmony_ci old_tsec->sid, new_tsec->sid, 23808c2ecf20Sopenharmony_ci SECCLASS_PROCESS, PROCESS__SHARE, 23818c2ecf20Sopenharmony_ci NULL); 23828c2ecf20Sopenharmony_ci if (rc) 23838c2ecf20Sopenharmony_ci return -EPERM; 23848c2ecf20Sopenharmony_ci } 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci /* Make sure that anyone attempting to ptrace over a task that 23878c2ecf20Sopenharmony_ci * changes its SID has the appropriate permit */ 23888c2ecf20Sopenharmony_ci if (bprm->unsafe & LSM_UNSAFE_PTRACE) { 23898c2ecf20Sopenharmony_ci u32 ptsid = ptrace_parent_sid(); 23908c2ecf20Sopenharmony_ci if (ptsid != 0) { 23918c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 23928c2ecf20Sopenharmony_ci ptsid, new_tsec->sid, 23938c2ecf20Sopenharmony_ci SECCLASS_PROCESS, 23948c2ecf20Sopenharmony_ci PROCESS__PTRACE, NULL); 23958c2ecf20Sopenharmony_ci if (rc) 23968c2ecf20Sopenharmony_ci return -EPERM; 23978c2ecf20Sopenharmony_ci } 23988c2ecf20Sopenharmony_ci } 23998c2ecf20Sopenharmony_ci 24008c2ecf20Sopenharmony_ci /* Clear any possibly unsafe personality bits on exec: */ 24018c2ecf20Sopenharmony_ci bprm->per_clear |= PER_CLEAR_ON_SETID; 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_ci /* Enable secure mode for SIDs transitions unless 24048c2ecf20Sopenharmony_ci the noatsecure permission is granted between 24058c2ecf20Sopenharmony_ci the two SIDs, i.e. ahp returns 0. */ 24068c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 24078c2ecf20Sopenharmony_ci old_tsec->sid, new_tsec->sid, 24088c2ecf20Sopenharmony_ci SECCLASS_PROCESS, PROCESS__NOATSECURE, 24098c2ecf20Sopenharmony_ci NULL); 24108c2ecf20Sopenharmony_ci bprm->secureexec |= !!rc; 24118c2ecf20Sopenharmony_ci } 24128c2ecf20Sopenharmony_ci 24138c2ecf20Sopenharmony_ci return 0; 24148c2ecf20Sopenharmony_ci} 24158c2ecf20Sopenharmony_ci 24168c2ecf20Sopenharmony_cistatic int match_file(const void *p, struct file *file, unsigned fd) 24178c2ecf20Sopenharmony_ci{ 24188c2ecf20Sopenharmony_ci return file_has_perm(p, file, file_to_av(file)) ? fd + 1 : 0; 24198c2ecf20Sopenharmony_ci} 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci/* Derived from fs/exec.c:flush_old_files. */ 24228c2ecf20Sopenharmony_cistatic inline void flush_unauthorized_files(const struct cred *cred, 24238c2ecf20Sopenharmony_ci struct files_struct *files) 24248c2ecf20Sopenharmony_ci{ 24258c2ecf20Sopenharmony_ci struct file *file, *devnull = NULL; 24268c2ecf20Sopenharmony_ci struct tty_struct *tty; 24278c2ecf20Sopenharmony_ci int drop_tty = 0; 24288c2ecf20Sopenharmony_ci unsigned n; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci tty = get_current_tty(); 24318c2ecf20Sopenharmony_ci if (tty) { 24328c2ecf20Sopenharmony_ci spin_lock(&tty->files_lock); 24338c2ecf20Sopenharmony_ci if (!list_empty(&tty->tty_files)) { 24348c2ecf20Sopenharmony_ci struct tty_file_private *file_priv; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci /* Revalidate access to controlling tty. 24378c2ecf20Sopenharmony_ci Use file_path_has_perm on the tty path directly 24388c2ecf20Sopenharmony_ci rather than using file_has_perm, as this particular 24398c2ecf20Sopenharmony_ci open file may belong to another process and we are 24408c2ecf20Sopenharmony_ci only interested in the inode-based check here. */ 24418c2ecf20Sopenharmony_ci file_priv = list_first_entry(&tty->tty_files, 24428c2ecf20Sopenharmony_ci struct tty_file_private, list); 24438c2ecf20Sopenharmony_ci file = file_priv->file; 24448c2ecf20Sopenharmony_ci if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE)) 24458c2ecf20Sopenharmony_ci drop_tty = 1; 24468c2ecf20Sopenharmony_ci } 24478c2ecf20Sopenharmony_ci spin_unlock(&tty->files_lock); 24488c2ecf20Sopenharmony_ci tty_kref_put(tty); 24498c2ecf20Sopenharmony_ci } 24508c2ecf20Sopenharmony_ci /* Reset controlling tty. */ 24518c2ecf20Sopenharmony_ci if (drop_tty) 24528c2ecf20Sopenharmony_ci no_tty(); 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci /* Revalidate access to inherited open files. */ 24558c2ecf20Sopenharmony_ci n = iterate_fd(files, 0, match_file, cred); 24568c2ecf20Sopenharmony_ci if (!n) /* none found? */ 24578c2ecf20Sopenharmony_ci return; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci devnull = dentry_open(&selinux_null, O_RDWR, cred); 24608c2ecf20Sopenharmony_ci if (IS_ERR(devnull)) 24618c2ecf20Sopenharmony_ci devnull = NULL; 24628c2ecf20Sopenharmony_ci /* replace all the matching ones with this */ 24638c2ecf20Sopenharmony_ci do { 24648c2ecf20Sopenharmony_ci replace_fd(n - 1, devnull, 0); 24658c2ecf20Sopenharmony_ci } while ((n = iterate_fd(files, n, match_file, cred)) != 0); 24668c2ecf20Sopenharmony_ci if (devnull) 24678c2ecf20Sopenharmony_ci fput(devnull); 24688c2ecf20Sopenharmony_ci} 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci/* 24718c2ecf20Sopenharmony_ci * Prepare a process for imminent new credential changes due to exec 24728c2ecf20Sopenharmony_ci */ 24738c2ecf20Sopenharmony_cistatic void selinux_bprm_committing_creds(struct linux_binprm *bprm) 24748c2ecf20Sopenharmony_ci{ 24758c2ecf20Sopenharmony_ci struct task_security_struct *new_tsec; 24768c2ecf20Sopenharmony_ci struct rlimit *rlim, *initrlim; 24778c2ecf20Sopenharmony_ci int rc, i; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci new_tsec = selinux_cred(bprm->cred); 24808c2ecf20Sopenharmony_ci if (new_tsec->sid == new_tsec->osid) 24818c2ecf20Sopenharmony_ci return; 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci /* Close files for which the new task SID is not authorized. */ 24848c2ecf20Sopenharmony_ci flush_unauthorized_files(bprm->cred, current->files); 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci /* Always clear parent death signal on SID transitions. */ 24878c2ecf20Sopenharmony_ci current->pdeath_signal = 0; 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci /* Check whether the new SID can inherit resource limits from the old 24908c2ecf20Sopenharmony_ci * SID. If not, reset all soft limits to the lower of the current 24918c2ecf20Sopenharmony_ci * task's hard limit and the init task's soft limit. 24928c2ecf20Sopenharmony_ci * 24938c2ecf20Sopenharmony_ci * Note that the setting of hard limits (even to lower them) can be 24948c2ecf20Sopenharmony_ci * controlled by the setrlimit check. The inclusion of the init task's 24958c2ecf20Sopenharmony_ci * soft limit into the computation is to avoid resetting soft limits 24968c2ecf20Sopenharmony_ci * higher than the default soft limit for cases where the default is 24978c2ecf20Sopenharmony_ci * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK. 24988c2ecf20Sopenharmony_ci */ 24998c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 25008c2ecf20Sopenharmony_ci new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS, 25018c2ecf20Sopenharmony_ci PROCESS__RLIMITINH, NULL); 25028c2ecf20Sopenharmony_ci if (rc) { 25038c2ecf20Sopenharmony_ci /* protect against do_prlimit() */ 25048c2ecf20Sopenharmony_ci task_lock(current); 25058c2ecf20Sopenharmony_ci for (i = 0; i < RLIM_NLIMITS; i++) { 25068c2ecf20Sopenharmony_ci rlim = current->signal->rlim + i; 25078c2ecf20Sopenharmony_ci initrlim = init_task.signal->rlim + i; 25088c2ecf20Sopenharmony_ci rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur); 25098c2ecf20Sopenharmony_ci } 25108c2ecf20Sopenharmony_ci task_unlock(current); 25118c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_POSIX_TIMERS)) 25128c2ecf20Sopenharmony_ci update_rlimit_cpu(current, rlimit(RLIMIT_CPU)); 25138c2ecf20Sopenharmony_ci } 25148c2ecf20Sopenharmony_ci} 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci/* 25178c2ecf20Sopenharmony_ci * Clean up the process immediately after the installation of new credentials 25188c2ecf20Sopenharmony_ci * due to exec 25198c2ecf20Sopenharmony_ci */ 25208c2ecf20Sopenharmony_cistatic void selinux_bprm_committed_creds(struct linux_binprm *bprm) 25218c2ecf20Sopenharmony_ci{ 25228c2ecf20Sopenharmony_ci const struct task_security_struct *tsec = selinux_cred(current_cred()); 25238c2ecf20Sopenharmony_ci u32 osid, sid; 25248c2ecf20Sopenharmony_ci int rc; 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ci osid = tsec->osid; 25278c2ecf20Sopenharmony_ci sid = tsec->sid; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci if (sid == osid) 25308c2ecf20Sopenharmony_ci return; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci /* Check whether the new SID can inherit signal state from the old SID. 25338c2ecf20Sopenharmony_ci * If not, clear itimers to avoid subsequent signal generation and 25348c2ecf20Sopenharmony_ci * flush and unblock signals. 25358c2ecf20Sopenharmony_ci * 25368c2ecf20Sopenharmony_ci * This must occur _after_ the task SID has been updated so that any 25378c2ecf20Sopenharmony_ci * kill done after the flush will be checked against the new SID. 25388c2ecf20Sopenharmony_ci */ 25398c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 25408c2ecf20Sopenharmony_ci osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL); 25418c2ecf20Sopenharmony_ci if (rc) { 25428c2ecf20Sopenharmony_ci clear_itimer(); 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci spin_lock_irq(¤t->sighand->siglock); 25458c2ecf20Sopenharmony_ci if (!fatal_signal_pending(current)) { 25468c2ecf20Sopenharmony_ci flush_sigqueue(¤t->pending); 25478c2ecf20Sopenharmony_ci flush_sigqueue(¤t->signal->shared_pending); 25488c2ecf20Sopenharmony_ci flush_signal_handlers(current, 1); 25498c2ecf20Sopenharmony_ci sigemptyset(¤t->blocked); 25508c2ecf20Sopenharmony_ci recalc_sigpending(); 25518c2ecf20Sopenharmony_ci } 25528c2ecf20Sopenharmony_ci spin_unlock_irq(¤t->sighand->siglock); 25538c2ecf20Sopenharmony_ci } 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci /* Wake up the parent if it is waiting so that it can recheck 25568c2ecf20Sopenharmony_ci * wait permission to the new task SID. */ 25578c2ecf20Sopenharmony_ci read_lock(&tasklist_lock); 25588c2ecf20Sopenharmony_ci __wake_up_parent(current, current->real_parent); 25598c2ecf20Sopenharmony_ci read_unlock(&tasklist_lock); 25608c2ecf20Sopenharmony_ci} 25618c2ecf20Sopenharmony_ci 25628c2ecf20Sopenharmony_ci/* superblock security operations */ 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_cistatic int selinux_sb_alloc_security(struct super_block *sb) 25658c2ecf20Sopenharmony_ci{ 25668c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci sbsec = kzalloc(sizeof(struct superblock_security_struct), GFP_KERNEL); 25698c2ecf20Sopenharmony_ci if (!sbsec) 25708c2ecf20Sopenharmony_ci return -ENOMEM; 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci mutex_init(&sbsec->lock); 25738c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sbsec->isec_head); 25748c2ecf20Sopenharmony_ci spin_lock_init(&sbsec->isec_lock); 25758c2ecf20Sopenharmony_ci sbsec->sb = sb; 25768c2ecf20Sopenharmony_ci sbsec->sid = SECINITSID_UNLABELED; 25778c2ecf20Sopenharmony_ci sbsec->def_sid = SECINITSID_FILE; 25788c2ecf20Sopenharmony_ci sbsec->mntpoint_sid = SECINITSID_UNLABELED; 25798c2ecf20Sopenharmony_ci sb->s_security = sbsec; 25808c2ecf20Sopenharmony_ci 25818c2ecf20Sopenharmony_ci return 0; 25828c2ecf20Sopenharmony_ci} 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_cistatic void selinux_sb_free_security(struct super_block *sb) 25858c2ecf20Sopenharmony_ci{ 25868c2ecf20Sopenharmony_ci superblock_free_security(sb); 25878c2ecf20Sopenharmony_ci} 25888c2ecf20Sopenharmony_ci 25898c2ecf20Sopenharmony_cistatic inline int opt_len(const char *s) 25908c2ecf20Sopenharmony_ci{ 25918c2ecf20Sopenharmony_ci bool open_quote = false; 25928c2ecf20Sopenharmony_ci int len; 25938c2ecf20Sopenharmony_ci char c; 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci for (len = 0; (c = s[len]) != '\0'; len++) { 25968c2ecf20Sopenharmony_ci if (c == '"') 25978c2ecf20Sopenharmony_ci open_quote = !open_quote; 25988c2ecf20Sopenharmony_ci if (c == ',' && !open_quote) 25998c2ecf20Sopenharmony_ci break; 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci return len; 26028c2ecf20Sopenharmony_ci} 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_cistatic int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts) 26058c2ecf20Sopenharmony_ci{ 26068c2ecf20Sopenharmony_ci char *from = options; 26078c2ecf20Sopenharmony_ci char *to = options; 26088c2ecf20Sopenharmony_ci bool first = true; 26098c2ecf20Sopenharmony_ci int rc; 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci while (1) { 26128c2ecf20Sopenharmony_ci int len = opt_len(from); 26138c2ecf20Sopenharmony_ci int token; 26148c2ecf20Sopenharmony_ci char *arg = NULL; 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci token = match_opt_prefix(from, len, &arg); 26178c2ecf20Sopenharmony_ci 26188c2ecf20Sopenharmony_ci if (token != Opt_error) { 26198c2ecf20Sopenharmony_ci char *p, *q; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci /* strip quotes */ 26228c2ecf20Sopenharmony_ci if (arg) { 26238c2ecf20Sopenharmony_ci for (p = q = arg; p < from + len; p++) { 26248c2ecf20Sopenharmony_ci char c = *p; 26258c2ecf20Sopenharmony_ci if (c != '"') 26268c2ecf20Sopenharmony_ci *q++ = c; 26278c2ecf20Sopenharmony_ci } 26288c2ecf20Sopenharmony_ci arg = kmemdup_nul(arg, q - arg, GFP_KERNEL); 26298c2ecf20Sopenharmony_ci if (!arg) { 26308c2ecf20Sopenharmony_ci rc = -ENOMEM; 26318c2ecf20Sopenharmony_ci goto free_opt; 26328c2ecf20Sopenharmony_ci } 26338c2ecf20Sopenharmony_ci } 26348c2ecf20Sopenharmony_ci rc = selinux_add_opt(token, arg, mnt_opts); 26358c2ecf20Sopenharmony_ci if (unlikely(rc)) { 26368c2ecf20Sopenharmony_ci kfree(arg); 26378c2ecf20Sopenharmony_ci goto free_opt; 26388c2ecf20Sopenharmony_ci } 26398c2ecf20Sopenharmony_ci } else { 26408c2ecf20Sopenharmony_ci if (!first) { // copy with preceding comma 26418c2ecf20Sopenharmony_ci from--; 26428c2ecf20Sopenharmony_ci len++; 26438c2ecf20Sopenharmony_ci } 26448c2ecf20Sopenharmony_ci if (to != from) 26458c2ecf20Sopenharmony_ci memmove(to, from, len); 26468c2ecf20Sopenharmony_ci to += len; 26478c2ecf20Sopenharmony_ci first = false; 26488c2ecf20Sopenharmony_ci } 26498c2ecf20Sopenharmony_ci if (!from[len]) 26508c2ecf20Sopenharmony_ci break; 26518c2ecf20Sopenharmony_ci from += len + 1; 26528c2ecf20Sopenharmony_ci } 26538c2ecf20Sopenharmony_ci *to = '\0'; 26548c2ecf20Sopenharmony_ci return 0; 26558c2ecf20Sopenharmony_ci 26568c2ecf20Sopenharmony_cifree_opt: 26578c2ecf20Sopenharmony_ci if (*mnt_opts) { 26588c2ecf20Sopenharmony_ci selinux_free_mnt_opts(*mnt_opts); 26598c2ecf20Sopenharmony_ci *mnt_opts = NULL; 26608c2ecf20Sopenharmony_ci } 26618c2ecf20Sopenharmony_ci return rc; 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_cistatic int selinux_sb_remount(struct super_block *sb, void *mnt_opts) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci struct selinux_mnt_opts *opts = mnt_opts; 26678c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec = sb->s_security; 26688c2ecf20Sopenharmony_ci u32 sid; 26698c2ecf20Sopenharmony_ci int rc; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci if (!(sbsec->flags & SE_SBINITIALIZED)) 26728c2ecf20Sopenharmony_ci return 0; 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci if (!opts) 26758c2ecf20Sopenharmony_ci return 0; 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci if (opts->fscontext) { 26788c2ecf20Sopenharmony_ci rc = parse_sid(sb, opts->fscontext, &sid); 26798c2ecf20Sopenharmony_ci if (rc) 26808c2ecf20Sopenharmony_ci return rc; 26818c2ecf20Sopenharmony_ci if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid, sid)) 26828c2ecf20Sopenharmony_ci goto out_bad_option; 26838c2ecf20Sopenharmony_ci } 26848c2ecf20Sopenharmony_ci if (opts->context) { 26858c2ecf20Sopenharmony_ci rc = parse_sid(sb, opts->context, &sid); 26868c2ecf20Sopenharmony_ci if (rc) 26878c2ecf20Sopenharmony_ci return rc; 26888c2ecf20Sopenharmony_ci if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid, sid)) 26898c2ecf20Sopenharmony_ci goto out_bad_option; 26908c2ecf20Sopenharmony_ci } 26918c2ecf20Sopenharmony_ci if (opts->rootcontext) { 26928c2ecf20Sopenharmony_ci struct inode_security_struct *root_isec; 26938c2ecf20Sopenharmony_ci root_isec = backing_inode_security(sb->s_root); 26948c2ecf20Sopenharmony_ci rc = parse_sid(sb, opts->rootcontext, &sid); 26958c2ecf20Sopenharmony_ci if (rc) 26968c2ecf20Sopenharmony_ci return rc; 26978c2ecf20Sopenharmony_ci if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid, sid)) 26988c2ecf20Sopenharmony_ci goto out_bad_option; 26998c2ecf20Sopenharmony_ci } 27008c2ecf20Sopenharmony_ci if (opts->defcontext) { 27018c2ecf20Sopenharmony_ci rc = parse_sid(sb, opts->defcontext, &sid); 27028c2ecf20Sopenharmony_ci if (rc) 27038c2ecf20Sopenharmony_ci return rc; 27048c2ecf20Sopenharmony_ci if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid, sid)) 27058c2ecf20Sopenharmony_ci goto out_bad_option; 27068c2ecf20Sopenharmony_ci } 27078c2ecf20Sopenharmony_ci return 0; 27088c2ecf20Sopenharmony_ci 27098c2ecf20Sopenharmony_ciout_bad_option: 27108c2ecf20Sopenharmony_ci pr_warn("SELinux: unable to change security options " 27118c2ecf20Sopenharmony_ci "during remount (dev %s, type=%s)\n", sb->s_id, 27128c2ecf20Sopenharmony_ci sb->s_type->name); 27138c2ecf20Sopenharmony_ci return -EINVAL; 27148c2ecf20Sopenharmony_ci} 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_cistatic int selinux_sb_kern_mount(struct super_block *sb) 27178c2ecf20Sopenharmony_ci{ 27188c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 27198c2ecf20Sopenharmony_ci struct common_audit_data ad; 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_DENTRY; 27228c2ecf20Sopenharmony_ci ad.u.dentry = sb->s_root; 27238c2ecf20Sopenharmony_ci return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); 27248c2ecf20Sopenharmony_ci} 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_cistatic int selinux_sb_statfs(struct dentry *dentry) 27278c2ecf20Sopenharmony_ci{ 27288c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 27298c2ecf20Sopenharmony_ci struct common_audit_data ad; 27308c2ecf20Sopenharmony_ci 27318c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_DENTRY; 27328c2ecf20Sopenharmony_ci ad.u.dentry = dentry->d_sb->s_root; 27338c2ecf20Sopenharmony_ci return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); 27348c2ecf20Sopenharmony_ci} 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_cistatic int selinux_mount(const char *dev_name, 27378c2ecf20Sopenharmony_ci const struct path *path, 27388c2ecf20Sopenharmony_ci const char *type, 27398c2ecf20Sopenharmony_ci unsigned long flags, 27408c2ecf20Sopenharmony_ci void *data) 27418c2ecf20Sopenharmony_ci{ 27428c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci if (flags & MS_REMOUNT) 27458c2ecf20Sopenharmony_ci return superblock_has_perm(cred, path->dentry->d_sb, 27468c2ecf20Sopenharmony_ci FILESYSTEM__REMOUNT, NULL); 27478c2ecf20Sopenharmony_ci else 27488c2ecf20Sopenharmony_ci return path_has_perm(cred, path, FILE__MOUNTON); 27498c2ecf20Sopenharmony_ci} 27508c2ecf20Sopenharmony_ci 27518c2ecf20Sopenharmony_cistatic int selinux_move_mount(const struct path *from_path, 27528c2ecf20Sopenharmony_ci const struct path *to_path) 27538c2ecf20Sopenharmony_ci{ 27548c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci return path_has_perm(cred, to_path, FILE__MOUNTON); 27578c2ecf20Sopenharmony_ci} 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_cistatic int selinux_umount(struct vfsmount *mnt, int flags) 27608c2ecf20Sopenharmony_ci{ 27618c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci return superblock_has_perm(cred, mnt->mnt_sb, 27648c2ecf20Sopenharmony_ci FILESYSTEM__UNMOUNT, NULL); 27658c2ecf20Sopenharmony_ci} 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_cistatic int selinux_fs_context_dup(struct fs_context *fc, 27688c2ecf20Sopenharmony_ci struct fs_context *src_fc) 27698c2ecf20Sopenharmony_ci{ 27708c2ecf20Sopenharmony_ci const struct selinux_mnt_opts *src = src_fc->security; 27718c2ecf20Sopenharmony_ci struct selinux_mnt_opts *opts; 27728c2ecf20Sopenharmony_ci 27738c2ecf20Sopenharmony_ci if (!src) 27748c2ecf20Sopenharmony_ci return 0; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci fc->security = kzalloc(sizeof(struct selinux_mnt_opts), GFP_KERNEL); 27778c2ecf20Sopenharmony_ci if (!fc->security) 27788c2ecf20Sopenharmony_ci return -ENOMEM; 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_ci opts = fc->security; 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci if (src->fscontext) { 27838c2ecf20Sopenharmony_ci opts->fscontext = kstrdup(src->fscontext, GFP_KERNEL); 27848c2ecf20Sopenharmony_ci if (!opts->fscontext) 27858c2ecf20Sopenharmony_ci return -ENOMEM; 27868c2ecf20Sopenharmony_ci } 27878c2ecf20Sopenharmony_ci if (src->context) { 27888c2ecf20Sopenharmony_ci opts->context = kstrdup(src->context, GFP_KERNEL); 27898c2ecf20Sopenharmony_ci if (!opts->context) 27908c2ecf20Sopenharmony_ci return -ENOMEM; 27918c2ecf20Sopenharmony_ci } 27928c2ecf20Sopenharmony_ci if (src->rootcontext) { 27938c2ecf20Sopenharmony_ci opts->rootcontext = kstrdup(src->rootcontext, GFP_KERNEL); 27948c2ecf20Sopenharmony_ci if (!opts->rootcontext) 27958c2ecf20Sopenharmony_ci return -ENOMEM; 27968c2ecf20Sopenharmony_ci } 27978c2ecf20Sopenharmony_ci if (src->defcontext) { 27988c2ecf20Sopenharmony_ci opts->defcontext = kstrdup(src->defcontext, GFP_KERNEL); 27998c2ecf20Sopenharmony_ci if (!opts->defcontext) 28008c2ecf20Sopenharmony_ci return -ENOMEM; 28018c2ecf20Sopenharmony_ci } 28028c2ecf20Sopenharmony_ci return 0; 28038c2ecf20Sopenharmony_ci} 28048c2ecf20Sopenharmony_ci 28058c2ecf20Sopenharmony_cistatic const struct fs_parameter_spec selinux_fs_parameters[] = { 28068c2ecf20Sopenharmony_ci fsparam_string(CONTEXT_STR, Opt_context), 28078c2ecf20Sopenharmony_ci fsparam_string(DEFCONTEXT_STR, Opt_defcontext), 28088c2ecf20Sopenharmony_ci fsparam_string(FSCONTEXT_STR, Opt_fscontext), 28098c2ecf20Sopenharmony_ci fsparam_string(ROOTCONTEXT_STR, Opt_rootcontext), 28108c2ecf20Sopenharmony_ci fsparam_flag (SECLABEL_STR, Opt_seclabel), 28118c2ecf20Sopenharmony_ci {} 28128c2ecf20Sopenharmony_ci}; 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_cistatic int selinux_fs_context_parse_param(struct fs_context *fc, 28158c2ecf20Sopenharmony_ci struct fs_parameter *param) 28168c2ecf20Sopenharmony_ci{ 28178c2ecf20Sopenharmony_ci struct fs_parse_result result; 28188c2ecf20Sopenharmony_ci int opt, rc; 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci opt = fs_parse(fc, selinux_fs_parameters, param, &result); 28218c2ecf20Sopenharmony_ci if (opt < 0) 28228c2ecf20Sopenharmony_ci return opt; 28238c2ecf20Sopenharmony_ci 28248c2ecf20Sopenharmony_ci rc = selinux_add_opt(opt, param->string, &fc->security); 28258c2ecf20Sopenharmony_ci if (!rc) 28268c2ecf20Sopenharmony_ci param->string = NULL; 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci return rc; 28298c2ecf20Sopenharmony_ci} 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci/* inode security operations */ 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_cistatic int selinux_inode_alloc_security(struct inode *inode) 28348c2ecf20Sopenharmony_ci{ 28358c2ecf20Sopenharmony_ci struct inode_security_struct *isec = selinux_inode(inode); 28368c2ecf20Sopenharmony_ci u32 sid = current_sid(); 28378c2ecf20Sopenharmony_ci 28388c2ecf20Sopenharmony_ci spin_lock_init(&isec->lock); 28398c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&isec->list); 28408c2ecf20Sopenharmony_ci isec->inode = inode; 28418c2ecf20Sopenharmony_ci isec->sid = SECINITSID_UNLABELED; 28428c2ecf20Sopenharmony_ci isec->sclass = SECCLASS_FILE; 28438c2ecf20Sopenharmony_ci isec->task_sid = sid; 28448c2ecf20Sopenharmony_ci isec->initialized = LABEL_INVALID; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci return 0; 28478c2ecf20Sopenharmony_ci} 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_cistatic void selinux_inode_free_security(struct inode *inode) 28508c2ecf20Sopenharmony_ci{ 28518c2ecf20Sopenharmony_ci inode_free_security(inode); 28528c2ecf20Sopenharmony_ci} 28538c2ecf20Sopenharmony_ci 28548c2ecf20Sopenharmony_cistatic int selinux_dentry_init_security(struct dentry *dentry, int mode, 28558c2ecf20Sopenharmony_ci const struct qstr *name, void **ctx, 28568c2ecf20Sopenharmony_ci u32 *ctxlen) 28578c2ecf20Sopenharmony_ci{ 28588c2ecf20Sopenharmony_ci u32 newsid; 28598c2ecf20Sopenharmony_ci int rc; 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci rc = selinux_determine_inode_label(selinux_cred(current_cred()), 28628c2ecf20Sopenharmony_ci d_inode(dentry->d_parent), name, 28638c2ecf20Sopenharmony_ci inode_mode_to_security_class(mode), 28648c2ecf20Sopenharmony_ci &newsid); 28658c2ecf20Sopenharmony_ci if (rc) 28668c2ecf20Sopenharmony_ci return rc; 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_ci return security_sid_to_context(&selinux_state, newsid, (char **)ctx, 28698c2ecf20Sopenharmony_ci ctxlen); 28708c2ecf20Sopenharmony_ci} 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_cistatic int selinux_dentry_create_files_as(struct dentry *dentry, int mode, 28738c2ecf20Sopenharmony_ci struct qstr *name, 28748c2ecf20Sopenharmony_ci const struct cred *old, 28758c2ecf20Sopenharmony_ci struct cred *new) 28768c2ecf20Sopenharmony_ci{ 28778c2ecf20Sopenharmony_ci u32 newsid; 28788c2ecf20Sopenharmony_ci int rc; 28798c2ecf20Sopenharmony_ci struct task_security_struct *tsec; 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci rc = selinux_determine_inode_label(selinux_cred(old), 28828c2ecf20Sopenharmony_ci d_inode(dentry->d_parent), name, 28838c2ecf20Sopenharmony_ci inode_mode_to_security_class(mode), 28848c2ecf20Sopenharmony_ci &newsid); 28858c2ecf20Sopenharmony_ci if (rc) 28868c2ecf20Sopenharmony_ci return rc; 28878c2ecf20Sopenharmony_ci 28888c2ecf20Sopenharmony_ci tsec = selinux_cred(new); 28898c2ecf20Sopenharmony_ci tsec->create_sid = newsid; 28908c2ecf20Sopenharmony_ci return 0; 28918c2ecf20Sopenharmony_ci} 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_cistatic int selinux_inode_init_security(struct inode *inode, struct inode *dir, 28948c2ecf20Sopenharmony_ci const struct qstr *qstr, 28958c2ecf20Sopenharmony_ci const char **name, 28968c2ecf20Sopenharmony_ci void **value, size_t *len) 28978c2ecf20Sopenharmony_ci{ 28988c2ecf20Sopenharmony_ci const struct task_security_struct *tsec = selinux_cred(current_cred()); 28998c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec; 29008c2ecf20Sopenharmony_ci u32 newsid, clen; 29018c2ecf20Sopenharmony_ci int rc; 29028c2ecf20Sopenharmony_ci char *context; 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci sbsec = dir->i_sb->s_security; 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci newsid = tsec->create_sid; 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci rc = selinux_determine_inode_label(tsec, dir, qstr, 29098c2ecf20Sopenharmony_ci inode_mode_to_security_class(inode->i_mode), 29108c2ecf20Sopenharmony_ci &newsid); 29118c2ecf20Sopenharmony_ci if (rc) 29128c2ecf20Sopenharmony_ci return rc; 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_ci /* Possibly defer initialization to selinux_complete_init. */ 29158c2ecf20Sopenharmony_ci if (sbsec->flags & SE_SBINITIALIZED) { 29168c2ecf20Sopenharmony_ci struct inode_security_struct *isec = selinux_inode(inode); 29178c2ecf20Sopenharmony_ci isec->sclass = inode_mode_to_security_class(inode->i_mode); 29188c2ecf20Sopenharmony_ci isec->sid = newsid; 29198c2ecf20Sopenharmony_ci isec->initialized = LABEL_INITIALIZED; 29208c2ecf20Sopenharmony_ci } 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci if (!selinux_initialized(&selinux_state) || 29238c2ecf20Sopenharmony_ci !(sbsec->flags & SBLABEL_MNT)) 29248c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci if (name) 29278c2ecf20Sopenharmony_ci *name = XATTR_SELINUX_SUFFIX; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci if (value && len) { 29308c2ecf20Sopenharmony_ci rc = security_sid_to_context_force(&selinux_state, newsid, 29318c2ecf20Sopenharmony_ci &context, &clen); 29328c2ecf20Sopenharmony_ci if (rc) 29338c2ecf20Sopenharmony_ci return rc; 29348c2ecf20Sopenharmony_ci *value = context; 29358c2ecf20Sopenharmony_ci *len = clen; 29368c2ecf20Sopenharmony_ci } 29378c2ecf20Sopenharmony_ci 29388c2ecf20Sopenharmony_ci return 0; 29398c2ecf20Sopenharmony_ci} 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_cistatic int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode) 29428c2ecf20Sopenharmony_ci{ 29438c2ecf20Sopenharmony_ci return may_create(dir, dentry, SECCLASS_FILE); 29448c2ecf20Sopenharmony_ci} 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_cistatic int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) 29478c2ecf20Sopenharmony_ci{ 29488c2ecf20Sopenharmony_ci return may_link(dir, old_dentry, MAY_LINK); 29498c2ecf20Sopenharmony_ci} 29508c2ecf20Sopenharmony_ci 29518c2ecf20Sopenharmony_cistatic int selinux_inode_unlink(struct inode *dir, struct dentry *dentry) 29528c2ecf20Sopenharmony_ci{ 29538c2ecf20Sopenharmony_ci return may_link(dir, dentry, MAY_UNLINK); 29548c2ecf20Sopenharmony_ci} 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_cistatic int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name) 29578c2ecf20Sopenharmony_ci{ 29588c2ecf20Sopenharmony_ci return may_create(dir, dentry, SECCLASS_LNK_FILE); 29598c2ecf20Sopenharmony_ci} 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_cistatic int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask) 29628c2ecf20Sopenharmony_ci{ 29638c2ecf20Sopenharmony_ci return may_create(dir, dentry, SECCLASS_DIR); 29648c2ecf20Sopenharmony_ci} 29658c2ecf20Sopenharmony_ci 29668c2ecf20Sopenharmony_cistatic int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry) 29678c2ecf20Sopenharmony_ci{ 29688c2ecf20Sopenharmony_ci return may_link(dir, dentry, MAY_RMDIR); 29698c2ecf20Sopenharmony_ci} 29708c2ecf20Sopenharmony_ci 29718c2ecf20Sopenharmony_cistatic int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) 29728c2ecf20Sopenharmony_ci{ 29738c2ecf20Sopenharmony_ci return may_create(dir, dentry, inode_mode_to_security_class(mode)); 29748c2ecf20Sopenharmony_ci} 29758c2ecf20Sopenharmony_ci 29768c2ecf20Sopenharmony_cistatic int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry, 29778c2ecf20Sopenharmony_ci struct inode *new_inode, struct dentry *new_dentry) 29788c2ecf20Sopenharmony_ci{ 29798c2ecf20Sopenharmony_ci return may_rename(old_inode, old_dentry, new_inode, new_dentry); 29808c2ecf20Sopenharmony_ci} 29818c2ecf20Sopenharmony_ci 29828c2ecf20Sopenharmony_cistatic int selinux_inode_readlink(struct dentry *dentry) 29838c2ecf20Sopenharmony_ci{ 29848c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci return dentry_has_perm(cred, dentry, FILE__READ); 29878c2ecf20Sopenharmony_ci} 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_cistatic int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, 29908c2ecf20Sopenharmony_ci bool rcu) 29918c2ecf20Sopenharmony_ci{ 29928c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 29938c2ecf20Sopenharmony_ci struct common_audit_data ad; 29948c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 29958c2ecf20Sopenharmony_ci u32 sid; 29968c2ecf20Sopenharmony_ci 29978c2ecf20Sopenharmony_ci validate_creds(cred); 29988c2ecf20Sopenharmony_ci 29998c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_DENTRY; 30008c2ecf20Sopenharmony_ci ad.u.dentry = dentry; 30018c2ecf20Sopenharmony_ci sid = cred_sid(cred); 30028c2ecf20Sopenharmony_ci isec = inode_security_rcu(inode, rcu); 30038c2ecf20Sopenharmony_ci if (IS_ERR(isec)) 30048c2ecf20Sopenharmony_ci return PTR_ERR(isec); 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci return avc_has_perm_flags(&selinux_state, 30078c2ecf20Sopenharmony_ci sid, isec->sid, isec->sclass, FILE__READ, &ad, 30088c2ecf20Sopenharmony_ci rcu ? MAY_NOT_BLOCK : 0); 30098c2ecf20Sopenharmony_ci} 30108c2ecf20Sopenharmony_ci 30118c2ecf20Sopenharmony_cistatic noinline int audit_inode_permission(struct inode *inode, 30128c2ecf20Sopenharmony_ci u32 perms, u32 audited, u32 denied, 30138c2ecf20Sopenharmony_ci int result) 30148c2ecf20Sopenharmony_ci{ 30158c2ecf20Sopenharmony_ci struct common_audit_data ad; 30168c2ecf20Sopenharmony_ci struct inode_security_struct *isec = selinux_inode(inode); 30178c2ecf20Sopenharmony_ci int rc; 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_INODE; 30208c2ecf20Sopenharmony_ci ad.u.inode = inode; 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci rc = slow_avc_audit(&selinux_state, 30238c2ecf20Sopenharmony_ci current_sid(), isec->sid, isec->sclass, perms, 30248c2ecf20Sopenharmony_ci audited, denied, result, &ad); 30258c2ecf20Sopenharmony_ci if (rc) 30268c2ecf20Sopenharmony_ci return rc; 30278c2ecf20Sopenharmony_ci return 0; 30288c2ecf20Sopenharmony_ci} 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_cistatic int selinux_inode_permission(struct inode *inode, int mask) 30318c2ecf20Sopenharmony_ci{ 30328c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 30338c2ecf20Sopenharmony_ci u32 perms; 30348c2ecf20Sopenharmony_ci bool from_access; 30358c2ecf20Sopenharmony_ci bool no_block = mask & MAY_NOT_BLOCK; 30368c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 30378c2ecf20Sopenharmony_ci u32 sid; 30388c2ecf20Sopenharmony_ci struct av_decision avd; 30398c2ecf20Sopenharmony_ci int rc, rc2; 30408c2ecf20Sopenharmony_ci u32 audited, denied; 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci from_access = mask & MAY_ACCESS; 30438c2ecf20Sopenharmony_ci mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci /* No permission to check. Existence test. */ 30468c2ecf20Sopenharmony_ci if (!mask) 30478c2ecf20Sopenharmony_ci return 0; 30488c2ecf20Sopenharmony_ci 30498c2ecf20Sopenharmony_ci validate_creds(cred); 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci if (unlikely(IS_PRIVATE(inode))) 30528c2ecf20Sopenharmony_ci return 0; 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci perms = file_mask_to_av(inode->i_mode, mask); 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci sid = cred_sid(cred); 30578c2ecf20Sopenharmony_ci isec = inode_security_rcu(inode, no_block); 30588c2ecf20Sopenharmony_ci if (IS_ERR(isec)) 30598c2ecf20Sopenharmony_ci return PTR_ERR(isec); 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci rc = avc_has_perm_noaudit(&selinux_state, 30628c2ecf20Sopenharmony_ci sid, isec->sid, isec->sclass, perms, 30638c2ecf20Sopenharmony_ci no_block ? AVC_NONBLOCKING : 0, 30648c2ecf20Sopenharmony_ci &avd); 30658c2ecf20Sopenharmony_ci audited = avc_audit_required(perms, &avd, rc, 30668c2ecf20Sopenharmony_ci from_access ? FILE__AUDIT_ACCESS : 0, 30678c2ecf20Sopenharmony_ci &denied); 30688c2ecf20Sopenharmony_ci if (likely(!audited)) 30698c2ecf20Sopenharmony_ci return rc; 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci /* fall back to ref-walk if we have to generate audit */ 30728c2ecf20Sopenharmony_ci if (no_block) 30738c2ecf20Sopenharmony_ci return -ECHILD; 30748c2ecf20Sopenharmony_ci 30758c2ecf20Sopenharmony_ci rc2 = audit_inode_permission(inode, perms, audited, denied, rc); 30768c2ecf20Sopenharmony_ci if (rc2) 30778c2ecf20Sopenharmony_ci return rc2; 30788c2ecf20Sopenharmony_ci return rc; 30798c2ecf20Sopenharmony_ci} 30808c2ecf20Sopenharmony_ci 30818c2ecf20Sopenharmony_cistatic int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) 30828c2ecf20Sopenharmony_ci{ 30838c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 30848c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 30858c2ecf20Sopenharmony_ci unsigned int ia_valid = iattr->ia_valid; 30868c2ecf20Sopenharmony_ci __u32 av = FILE__WRITE; 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ 30898c2ecf20Sopenharmony_ci if (ia_valid & ATTR_FORCE) { 30908c2ecf20Sopenharmony_ci ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE | 30918c2ecf20Sopenharmony_ci ATTR_FORCE); 30928c2ecf20Sopenharmony_ci if (!ia_valid) 30938c2ecf20Sopenharmony_ci return 0; 30948c2ecf20Sopenharmony_ci } 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | 30978c2ecf20Sopenharmony_ci ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) 30988c2ecf20Sopenharmony_ci return dentry_has_perm(cred, dentry, FILE__SETATTR); 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci if (selinux_policycap_openperm() && 31018c2ecf20Sopenharmony_ci inode->i_sb->s_magic != SOCKFS_MAGIC && 31028c2ecf20Sopenharmony_ci (ia_valid & ATTR_SIZE) && 31038c2ecf20Sopenharmony_ci !(ia_valid & ATTR_FILE)) 31048c2ecf20Sopenharmony_ci av |= FILE__OPEN; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci return dentry_has_perm(cred, dentry, av); 31078c2ecf20Sopenharmony_ci} 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_cistatic int selinux_inode_getattr(const struct path *path) 31108c2ecf20Sopenharmony_ci{ 31118c2ecf20Sopenharmony_ci return path_has_perm(current_cred(), path, FILE__GETATTR); 31128c2ecf20Sopenharmony_ci} 31138c2ecf20Sopenharmony_ci 31148c2ecf20Sopenharmony_cistatic bool has_cap_mac_admin(bool audit) 31158c2ecf20Sopenharmony_ci{ 31168c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 31178c2ecf20Sopenharmony_ci unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT; 31188c2ecf20Sopenharmony_ci 31198c2ecf20Sopenharmony_ci if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts)) 31208c2ecf20Sopenharmony_ci return false; 31218c2ecf20Sopenharmony_ci if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true)) 31228c2ecf20Sopenharmony_ci return false; 31238c2ecf20Sopenharmony_ci return true; 31248c2ecf20Sopenharmony_ci} 31258c2ecf20Sopenharmony_ci 31268c2ecf20Sopenharmony_cistatic int selinux_inode_setxattr(struct dentry *dentry, const char *name, 31278c2ecf20Sopenharmony_ci const void *value, size_t size, int flags) 31288c2ecf20Sopenharmony_ci{ 31298c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 31308c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 31318c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec; 31328c2ecf20Sopenharmony_ci struct common_audit_data ad; 31338c2ecf20Sopenharmony_ci u32 newsid, sid = current_sid(); 31348c2ecf20Sopenharmony_ci int rc = 0; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_NAME_SELINUX)) { 31378c2ecf20Sopenharmony_ci rc = cap_inode_setxattr(dentry, name, value, size, flags); 31388c2ecf20Sopenharmony_ci if (rc) 31398c2ecf20Sopenharmony_ci return rc; 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci /* Not an attribute we recognize, so just check the 31428c2ecf20Sopenharmony_ci ordinary setattr permission. */ 31438c2ecf20Sopenharmony_ci return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); 31448c2ecf20Sopenharmony_ci } 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci if (!selinux_initialized(&selinux_state)) 31478c2ecf20Sopenharmony_ci return (inode_owner_or_capable(inode) ? 0 : -EPERM); 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci sbsec = inode->i_sb->s_security; 31508c2ecf20Sopenharmony_ci if (!(sbsec->flags & SBLABEL_MNT)) 31518c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci if (!inode_owner_or_capable(inode)) 31548c2ecf20Sopenharmony_ci return -EPERM; 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_DENTRY; 31578c2ecf20Sopenharmony_ci ad.u.dentry = dentry; 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci isec = backing_inode_security(dentry); 31608c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 31618c2ecf20Sopenharmony_ci sid, isec->sid, isec->sclass, 31628c2ecf20Sopenharmony_ci FILE__RELABELFROM, &ad); 31638c2ecf20Sopenharmony_ci if (rc) 31648c2ecf20Sopenharmony_ci return rc; 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci rc = security_context_to_sid(&selinux_state, value, size, &newsid, 31678c2ecf20Sopenharmony_ci GFP_KERNEL); 31688c2ecf20Sopenharmony_ci if (rc == -EINVAL) { 31698c2ecf20Sopenharmony_ci if (!has_cap_mac_admin(true)) { 31708c2ecf20Sopenharmony_ci struct audit_buffer *ab; 31718c2ecf20Sopenharmony_ci size_t audit_size; 31728c2ecf20Sopenharmony_ci 31738c2ecf20Sopenharmony_ci /* We strip a nul only if it is at the end, otherwise the 31748c2ecf20Sopenharmony_ci * context contains a nul and we should audit that */ 31758c2ecf20Sopenharmony_ci if (value) { 31768c2ecf20Sopenharmony_ci const char *str = value; 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_ci if (str[size - 1] == '\0') 31798c2ecf20Sopenharmony_ci audit_size = size - 1; 31808c2ecf20Sopenharmony_ci else 31818c2ecf20Sopenharmony_ci audit_size = size; 31828c2ecf20Sopenharmony_ci } else { 31838c2ecf20Sopenharmony_ci audit_size = 0; 31848c2ecf20Sopenharmony_ci } 31858c2ecf20Sopenharmony_ci ab = audit_log_start(audit_context(), 31868c2ecf20Sopenharmony_ci GFP_ATOMIC, AUDIT_SELINUX_ERR); 31878c2ecf20Sopenharmony_ci audit_log_format(ab, "op=setxattr invalid_context="); 31888c2ecf20Sopenharmony_ci audit_log_n_untrustedstring(ab, value, audit_size); 31898c2ecf20Sopenharmony_ci audit_log_end(ab); 31908c2ecf20Sopenharmony_ci 31918c2ecf20Sopenharmony_ci return rc; 31928c2ecf20Sopenharmony_ci } 31938c2ecf20Sopenharmony_ci rc = security_context_to_sid_force(&selinux_state, value, 31948c2ecf20Sopenharmony_ci size, &newsid); 31958c2ecf20Sopenharmony_ci } 31968c2ecf20Sopenharmony_ci if (rc) 31978c2ecf20Sopenharmony_ci return rc; 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 32008c2ecf20Sopenharmony_ci sid, newsid, isec->sclass, 32018c2ecf20Sopenharmony_ci FILE__RELABELTO, &ad); 32028c2ecf20Sopenharmony_ci if (rc) 32038c2ecf20Sopenharmony_ci return rc; 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci rc = security_validate_transition(&selinux_state, isec->sid, newsid, 32068c2ecf20Sopenharmony_ci sid, isec->sclass); 32078c2ecf20Sopenharmony_ci if (rc) 32088c2ecf20Sopenharmony_ci return rc; 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 32118c2ecf20Sopenharmony_ci newsid, 32128c2ecf20Sopenharmony_ci sbsec->sid, 32138c2ecf20Sopenharmony_ci SECCLASS_FILESYSTEM, 32148c2ecf20Sopenharmony_ci FILESYSTEM__ASSOCIATE, 32158c2ecf20Sopenharmony_ci &ad); 32168c2ecf20Sopenharmony_ci} 32178c2ecf20Sopenharmony_ci 32188c2ecf20Sopenharmony_cistatic void selinux_inode_post_setxattr(struct dentry *dentry, const char *name, 32198c2ecf20Sopenharmony_ci const void *value, size_t size, 32208c2ecf20Sopenharmony_ci int flags) 32218c2ecf20Sopenharmony_ci{ 32228c2ecf20Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 32238c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 32248c2ecf20Sopenharmony_ci u32 newsid; 32258c2ecf20Sopenharmony_ci int rc; 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_NAME_SELINUX)) { 32288c2ecf20Sopenharmony_ci /* Not an attribute we recognize, so nothing to do. */ 32298c2ecf20Sopenharmony_ci return; 32308c2ecf20Sopenharmony_ci } 32318c2ecf20Sopenharmony_ci 32328c2ecf20Sopenharmony_ci if (!selinux_initialized(&selinux_state)) { 32338c2ecf20Sopenharmony_ci /* If we haven't even been initialized, then we can't validate 32348c2ecf20Sopenharmony_ci * against a policy, so leave the label as invalid. It may 32358c2ecf20Sopenharmony_ci * resolve to a valid label on the next revalidation try if 32368c2ecf20Sopenharmony_ci * we've since initialized. 32378c2ecf20Sopenharmony_ci */ 32388c2ecf20Sopenharmony_ci return; 32398c2ecf20Sopenharmony_ci } 32408c2ecf20Sopenharmony_ci 32418c2ecf20Sopenharmony_ci rc = security_context_to_sid_force(&selinux_state, value, size, 32428c2ecf20Sopenharmony_ci &newsid); 32438c2ecf20Sopenharmony_ci if (rc) { 32448c2ecf20Sopenharmony_ci pr_err("SELinux: unable to map context to SID" 32458c2ecf20Sopenharmony_ci "for (%s, %lu), rc=%d\n", 32468c2ecf20Sopenharmony_ci inode->i_sb->s_id, inode->i_ino, -rc); 32478c2ecf20Sopenharmony_ci return; 32488c2ecf20Sopenharmony_ci } 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ci isec = backing_inode_security(dentry); 32518c2ecf20Sopenharmony_ci spin_lock(&isec->lock); 32528c2ecf20Sopenharmony_ci isec->sclass = inode_mode_to_security_class(inode->i_mode); 32538c2ecf20Sopenharmony_ci isec->sid = newsid; 32548c2ecf20Sopenharmony_ci isec->initialized = LABEL_INITIALIZED; 32558c2ecf20Sopenharmony_ci spin_unlock(&isec->lock); 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci return; 32588c2ecf20Sopenharmony_ci} 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_cistatic int selinux_inode_getxattr(struct dentry *dentry, const char *name) 32618c2ecf20Sopenharmony_ci{ 32628c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci return dentry_has_perm(cred, dentry, FILE__GETATTR); 32658c2ecf20Sopenharmony_ci} 32668c2ecf20Sopenharmony_ci 32678c2ecf20Sopenharmony_cistatic int selinux_inode_listxattr(struct dentry *dentry) 32688c2ecf20Sopenharmony_ci{ 32698c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ci return dentry_has_perm(cred, dentry, FILE__GETATTR); 32728c2ecf20Sopenharmony_ci} 32738c2ecf20Sopenharmony_ci 32748c2ecf20Sopenharmony_cistatic int selinux_inode_removexattr(struct dentry *dentry, const char *name) 32758c2ecf20Sopenharmony_ci{ 32768c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_NAME_SELINUX)) { 32778c2ecf20Sopenharmony_ci int rc = cap_inode_removexattr(dentry, name); 32788c2ecf20Sopenharmony_ci if (rc) 32798c2ecf20Sopenharmony_ci return rc; 32808c2ecf20Sopenharmony_ci 32818c2ecf20Sopenharmony_ci /* Not an attribute we recognize, so just check the 32828c2ecf20Sopenharmony_ci ordinary setattr permission. */ 32838c2ecf20Sopenharmony_ci return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); 32848c2ecf20Sopenharmony_ci } 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci if (!selinux_initialized(&selinux_state)) 32878c2ecf20Sopenharmony_ci return 0; 32888c2ecf20Sopenharmony_ci 32898c2ecf20Sopenharmony_ci /* No one is allowed to remove a SELinux security label. 32908c2ecf20Sopenharmony_ci You can change the label, but all data must be labeled. */ 32918c2ecf20Sopenharmony_ci return -EACCES; 32928c2ecf20Sopenharmony_ci} 32938c2ecf20Sopenharmony_ci 32948c2ecf20Sopenharmony_cistatic int selinux_path_notify(const struct path *path, u64 mask, 32958c2ecf20Sopenharmony_ci unsigned int obj_type) 32968c2ecf20Sopenharmony_ci{ 32978c2ecf20Sopenharmony_ci int ret; 32988c2ecf20Sopenharmony_ci u32 perm; 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_ci struct common_audit_data ad; 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_PATH; 33038c2ecf20Sopenharmony_ci ad.u.path = *path; 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci /* 33068c2ecf20Sopenharmony_ci * Set permission needed based on the type of mark being set. 33078c2ecf20Sopenharmony_ci * Performs an additional check for sb watches. 33088c2ecf20Sopenharmony_ci */ 33098c2ecf20Sopenharmony_ci switch (obj_type) { 33108c2ecf20Sopenharmony_ci case FSNOTIFY_OBJ_TYPE_VFSMOUNT: 33118c2ecf20Sopenharmony_ci perm = FILE__WATCH_MOUNT; 33128c2ecf20Sopenharmony_ci break; 33138c2ecf20Sopenharmony_ci case FSNOTIFY_OBJ_TYPE_SB: 33148c2ecf20Sopenharmony_ci perm = FILE__WATCH_SB; 33158c2ecf20Sopenharmony_ci ret = superblock_has_perm(current_cred(), path->dentry->d_sb, 33168c2ecf20Sopenharmony_ci FILESYSTEM__WATCH, &ad); 33178c2ecf20Sopenharmony_ci if (ret) 33188c2ecf20Sopenharmony_ci return ret; 33198c2ecf20Sopenharmony_ci break; 33208c2ecf20Sopenharmony_ci case FSNOTIFY_OBJ_TYPE_INODE: 33218c2ecf20Sopenharmony_ci perm = FILE__WATCH; 33228c2ecf20Sopenharmony_ci break; 33238c2ecf20Sopenharmony_ci default: 33248c2ecf20Sopenharmony_ci return -EINVAL; 33258c2ecf20Sopenharmony_ci } 33268c2ecf20Sopenharmony_ci 33278c2ecf20Sopenharmony_ci /* blocking watches require the file:watch_with_perm permission */ 33288c2ecf20Sopenharmony_ci if (mask & (ALL_FSNOTIFY_PERM_EVENTS)) 33298c2ecf20Sopenharmony_ci perm |= FILE__WATCH_WITH_PERM; 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci /* watches on read-like events need the file:watch_reads permission */ 33328c2ecf20Sopenharmony_ci if (mask & (FS_ACCESS | FS_ACCESS_PERM | FS_CLOSE_NOWRITE)) 33338c2ecf20Sopenharmony_ci perm |= FILE__WATCH_READS; 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci return path_has_perm(current_cred(), path, perm); 33368c2ecf20Sopenharmony_ci} 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ci/* 33398c2ecf20Sopenharmony_ci * Copy the inode security context value to the user. 33408c2ecf20Sopenharmony_ci * 33418c2ecf20Sopenharmony_ci * Permission check is handled by selinux_inode_getxattr hook. 33428c2ecf20Sopenharmony_ci */ 33438c2ecf20Sopenharmony_cistatic int selinux_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc) 33448c2ecf20Sopenharmony_ci{ 33458c2ecf20Sopenharmony_ci u32 size; 33468c2ecf20Sopenharmony_ci int error; 33478c2ecf20Sopenharmony_ci char *context = NULL; 33488c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 33498c2ecf20Sopenharmony_ci 33508c2ecf20Sopenharmony_ci /* 33518c2ecf20Sopenharmony_ci * If we're not initialized yet, then we can't validate contexts, so 33528c2ecf20Sopenharmony_ci * just let vfs_getxattr fall back to using the on-disk xattr. 33538c2ecf20Sopenharmony_ci */ 33548c2ecf20Sopenharmony_ci if (!selinux_initialized(&selinux_state) || 33558c2ecf20Sopenharmony_ci strcmp(name, XATTR_SELINUX_SUFFIX)) 33568c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 33578c2ecf20Sopenharmony_ci 33588c2ecf20Sopenharmony_ci /* 33598c2ecf20Sopenharmony_ci * If the caller has CAP_MAC_ADMIN, then get the raw context 33608c2ecf20Sopenharmony_ci * value even if it is not defined by current policy; otherwise, 33618c2ecf20Sopenharmony_ci * use the in-core value under current policy. 33628c2ecf20Sopenharmony_ci * Use the non-auditing forms of the permission checks since 33638c2ecf20Sopenharmony_ci * getxattr may be called by unprivileged processes commonly 33648c2ecf20Sopenharmony_ci * and lack of permission just means that we fall back to the 33658c2ecf20Sopenharmony_ci * in-core context value, not a denial. 33668c2ecf20Sopenharmony_ci */ 33678c2ecf20Sopenharmony_ci isec = inode_security(inode); 33688c2ecf20Sopenharmony_ci if (has_cap_mac_admin(false)) 33698c2ecf20Sopenharmony_ci error = security_sid_to_context_force(&selinux_state, 33708c2ecf20Sopenharmony_ci isec->sid, &context, 33718c2ecf20Sopenharmony_ci &size); 33728c2ecf20Sopenharmony_ci else 33738c2ecf20Sopenharmony_ci error = security_sid_to_context(&selinux_state, isec->sid, 33748c2ecf20Sopenharmony_ci &context, &size); 33758c2ecf20Sopenharmony_ci if (error) 33768c2ecf20Sopenharmony_ci return error; 33778c2ecf20Sopenharmony_ci error = size; 33788c2ecf20Sopenharmony_ci if (alloc) { 33798c2ecf20Sopenharmony_ci *buffer = context; 33808c2ecf20Sopenharmony_ci goto out_nofree; 33818c2ecf20Sopenharmony_ci } 33828c2ecf20Sopenharmony_ci kfree(context); 33838c2ecf20Sopenharmony_ciout_nofree: 33848c2ecf20Sopenharmony_ci return error; 33858c2ecf20Sopenharmony_ci} 33868c2ecf20Sopenharmony_ci 33878c2ecf20Sopenharmony_cistatic int selinux_inode_setsecurity(struct inode *inode, const char *name, 33888c2ecf20Sopenharmony_ci const void *value, size_t size, int flags) 33898c2ecf20Sopenharmony_ci{ 33908c2ecf20Sopenharmony_ci struct inode_security_struct *isec = inode_security_novalidate(inode); 33918c2ecf20Sopenharmony_ci struct superblock_security_struct *sbsec = inode->i_sb->s_security; 33928c2ecf20Sopenharmony_ci u32 newsid; 33938c2ecf20Sopenharmony_ci int rc; 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_SELINUX_SUFFIX)) 33968c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci if (!(sbsec->flags & SBLABEL_MNT)) 33998c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 34008c2ecf20Sopenharmony_ci 34018c2ecf20Sopenharmony_ci if (!value || !size) 34028c2ecf20Sopenharmony_ci return -EACCES; 34038c2ecf20Sopenharmony_ci 34048c2ecf20Sopenharmony_ci rc = security_context_to_sid(&selinux_state, value, size, &newsid, 34058c2ecf20Sopenharmony_ci GFP_KERNEL); 34068c2ecf20Sopenharmony_ci if (rc) 34078c2ecf20Sopenharmony_ci return rc; 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci spin_lock(&isec->lock); 34108c2ecf20Sopenharmony_ci isec->sclass = inode_mode_to_security_class(inode->i_mode); 34118c2ecf20Sopenharmony_ci isec->sid = newsid; 34128c2ecf20Sopenharmony_ci isec->initialized = LABEL_INITIALIZED; 34138c2ecf20Sopenharmony_ci spin_unlock(&isec->lock); 34148c2ecf20Sopenharmony_ci return 0; 34158c2ecf20Sopenharmony_ci} 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_cistatic int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size) 34188c2ecf20Sopenharmony_ci{ 34198c2ecf20Sopenharmony_ci const int len = sizeof(XATTR_NAME_SELINUX); 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci if (!selinux_initialized(&selinux_state)) 34228c2ecf20Sopenharmony_ci return 0; 34238c2ecf20Sopenharmony_ci 34248c2ecf20Sopenharmony_ci if (buffer && len <= buffer_size) 34258c2ecf20Sopenharmony_ci memcpy(buffer, XATTR_NAME_SELINUX, len); 34268c2ecf20Sopenharmony_ci return len; 34278c2ecf20Sopenharmony_ci} 34288c2ecf20Sopenharmony_ci 34298c2ecf20Sopenharmony_cistatic void selinux_inode_getsecid(struct inode *inode, u32 *secid) 34308c2ecf20Sopenharmony_ci{ 34318c2ecf20Sopenharmony_ci struct inode_security_struct *isec = inode_security_novalidate(inode); 34328c2ecf20Sopenharmony_ci *secid = isec->sid; 34338c2ecf20Sopenharmony_ci} 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_cistatic int selinux_inode_copy_up(struct dentry *src, struct cred **new) 34368c2ecf20Sopenharmony_ci{ 34378c2ecf20Sopenharmony_ci u32 sid; 34388c2ecf20Sopenharmony_ci struct task_security_struct *tsec; 34398c2ecf20Sopenharmony_ci struct cred *new_creds = *new; 34408c2ecf20Sopenharmony_ci 34418c2ecf20Sopenharmony_ci if (new_creds == NULL) { 34428c2ecf20Sopenharmony_ci new_creds = prepare_creds(); 34438c2ecf20Sopenharmony_ci if (!new_creds) 34448c2ecf20Sopenharmony_ci return -ENOMEM; 34458c2ecf20Sopenharmony_ci } 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci tsec = selinux_cred(new_creds); 34488c2ecf20Sopenharmony_ci /* Get label from overlay inode and set it in create_sid */ 34498c2ecf20Sopenharmony_ci selinux_inode_getsecid(d_inode(src), &sid); 34508c2ecf20Sopenharmony_ci tsec->create_sid = sid; 34518c2ecf20Sopenharmony_ci *new = new_creds; 34528c2ecf20Sopenharmony_ci return 0; 34538c2ecf20Sopenharmony_ci} 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_cistatic int selinux_inode_copy_up_xattr(const char *name) 34568c2ecf20Sopenharmony_ci{ 34578c2ecf20Sopenharmony_ci /* The copy_up hook above sets the initial context on an inode, but we 34588c2ecf20Sopenharmony_ci * don't then want to overwrite it by blindly copying all the lower 34598c2ecf20Sopenharmony_ci * xattrs up. Instead, we have to filter out SELinux-related xattrs. 34608c2ecf20Sopenharmony_ci */ 34618c2ecf20Sopenharmony_ci if (strcmp(name, XATTR_NAME_SELINUX) == 0) 34628c2ecf20Sopenharmony_ci return 1; /* Discard */ 34638c2ecf20Sopenharmony_ci /* 34648c2ecf20Sopenharmony_ci * Any other attribute apart from SELINUX is not claimed, supported 34658c2ecf20Sopenharmony_ci * by selinux. 34668c2ecf20Sopenharmony_ci */ 34678c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 34688c2ecf20Sopenharmony_ci} 34698c2ecf20Sopenharmony_ci 34708c2ecf20Sopenharmony_ci/* kernfs node operations */ 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_cistatic int selinux_kernfs_init_security(struct kernfs_node *kn_dir, 34738c2ecf20Sopenharmony_ci struct kernfs_node *kn) 34748c2ecf20Sopenharmony_ci{ 34758c2ecf20Sopenharmony_ci const struct task_security_struct *tsec = selinux_cred(current_cred()); 34768c2ecf20Sopenharmony_ci u32 parent_sid, newsid, clen; 34778c2ecf20Sopenharmony_ci int rc; 34788c2ecf20Sopenharmony_ci char *context; 34798c2ecf20Sopenharmony_ci 34808c2ecf20Sopenharmony_ci rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, NULL, 0); 34818c2ecf20Sopenharmony_ci if (rc == -ENODATA) 34828c2ecf20Sopenharmony_ci return 0; 34838c2ecf20Sopenharmony_ci else if (rc < 0) 34848c2ecf20Sopenharmony_ci return rc; 34858c2ecf20Sopenharmony_ci 34868c2ecf20Sopenharmony_ci clen = (u32)rc; 34878c2ecf20Sopenharmony_ci context = kmalloc(clen, GFP_KERNEL); 34888c2ecf20Sopenharmony_ci if (!context) 34898c2ecf20Sopenharmony_ci return -ENOMEM; 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, context, clen); 34928c2ecf20Sopenharmony_ci if (rc < 0) { 34938c2ecf20Sopenharmony_ci kfree(context); 34948c2ecf20Sopenharmony_ci return rc; 34958c2ecf20Sopenharmony_ci } 34968c2ecf20Sopenharmony_ci 34978c2ecf20Sopenharmony_ci rc = security_context_to_sid(&selinux_state, context, clen, &parent_sid, 34988c2ecf20Sopenharmony_ci GFP_KERNEL); 34998c2ecf20Sopenharmony_ci kfree(context); 35008c2ecf20Sopenharmony_ci if (rc) 35018c2ecf20Sopenharmony_ci return rc; 35028c2ecf20Sopenharmony_ci 35038c2ecf20Sopenharmony_ci if (tsec->create_sid) { 35048c2ecf20Sopenharmony_ci newsid = tsec->create_sid; 35058c2ecf20Sopenharmony_ci } else { 35068c2ecf20Sopenharmony_ci u16 secclass = inode_mode_to_security_class(kn->mode); 35078c2ecf20Sopenharmony_ci struct qstr q; 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci q.name = kn->name; 35108c2ecf20Sopenharmony_ci q.hash_len = hashlen_string(kn_dir, kn->name); 35118c2ecf20Sopenharmony_ci 35128c2ecf20Sopenharmony_ci rc = security_transition_sid(&selinux_state, tsec->sid, 35138c2ecf20Sopenharmony_ci parent_sid, secclass, &q, 35148c2ecf20Sopenharmony_ci &newsid); 35158c2ecf20Sopenharmony_ci if (rc) 35168c2ecf20Sopenharmony_ci return rc; 35178c2ecf20Sopenharmony_ci } 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_ci rc = security_sid_to_context_force(&selinux_state, newsid, 35208c2ecf20Sopenharmony_ci &context, &clen); 35218c2ecf20Sopenharmony_ci if (rc) 35228c2ecf20Sopenharmony_ci return rc; 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci rc = kernfs_xattr_set(kn, XATTR_NAME_SELINUX, context, clen, 35258c2ecf20Sopenharmony_ci XATTR_CREATE); 35268c2ecf20Sopenharmony_ci kfree(context); 35278c2ecf20Sopenharmony_ci return rc; 35288c2ecf20Sopenharmony_ci} 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci/* file security operations */ 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_cistatic int selinux_revalidate_file_permission(struct file *file, int mask) 35348c2ecf20Sopenharmony_ci{ 35358c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 35368c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 35378c2ecf20Sopenharmony_ci 35388c2ecf20Sopenharmony_ci /* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */ 35398c2ecf20Sopenharmony_ci if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE)) 35408c2ecf20Sopenharmony_ci mask |= MAY_APPEND; 35418c2ecf20Sopenharmony_ci 35428c2ecf20Sopenharmony_ci return file_has_perm(cred, file, 35438c2ecf20Sopenharmony_ci file_mask_to_av(inode->i_mode, mask)); 35448c2ecf20Sopenharmony_ci} 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_cistatic int selinux_file_permission(struct file *file, int mask) 35478c2ecf20Sopenharmony_ci{ 35488c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 35498c2ecf20Sopenharmony_ci struct file_security_struct *fsec = selinux_file(file); 35508c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 35518c2ecf20Sopenharmony_ci u32 sid = current_sid(); 35528c2ecf20Sopenharmony_ci 35538c2ecf20Sopenharmony_ci if (!mask) 35548c2ecf20Sopenharmony_ci /* No permission to check. Existence test. */ 35558c2ecf20Sopenharmony_ci return 0; 35568c2ecf20Sopenharmony_ci 35578c2ecf20Sopenharmony_ci isec = inode_security(inode); 35588c2ecf20Sopenharmony_ci if (sid == fsec->sid && fsec->isid == isec->sid && 35598c2ecf20Sopenharmony_ci fsec->pseqno == avc_policy_seqno(&selinux_state)) 35608c2ecf20Sopenharmony_ci /* No change since file_open check. */ 35618c2ecf20Sopenharmony_ci return 0; 35628c2ecf20Sopenharmony_ci 35638c2ecf20Sopenharmony_ci return selinux_revalidate_file_permission(file, mask); 35648c2ecf20Sopenharmony_ci} 35658c2ecf20Sopenharmony_ci 35668c2ecf20Sopenharmony_cistatic int selinux_file_alloc_security(struct file *file) 35678c2ecf20Sopenharmony_ci{ 35688c2ecf20Sopenharmony_ci struct file_security_struct *fsec = selinux_file(file); 35698c2ecf20Sopenharmony_ci u32 sid = current_sid(); 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci fsec->sid = sid; 35728c2ecf20Sopenharmony_ci fsec->fown_sid = sid; 35738c2ecf20Sopenharmony_ci 35748c2ecf20Sopenharmony_ci return 0; 35758c2ecf20Sopenharmony_ci} 35768c2ecf20Sopenharmony_ci 35778c2ecf20Sopenharmony_ci/* 35788c2ecf20Sopenharmony_ci * Check whether a task has the ioctl permission and cmd 35798c2ecf20Sopenharmony_ci * operation to an inode. 35808c2ecf20Sopenharmony_ci */ 35818c2ecf20Sopenharmony_cistatic int ioctl_has_perm(const struct cred *cred, struct file *file, 35828c2ecf20Sopenharmony_ci u32 requested, u16 cmd) 35838c2ecf20Sopenharmony_ci{ 35848c2ecf20Sopenharmony_ci struct common_audit_data ad; 35858c2ecf20Sopenharmony_ci struct file_security_struct *fsec = selinux_file(file); 35868c2ecf20Sopenharmony_ci struct inode *inode = file_inode(file); 35878c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 35888c2ecf20Sopenharmony_ci struct lsm_ioctlop_audit ioctl; 35898c2ecf20Sopenharmony_ci u32 ssid = cred_sid(cred); 35908c2ecf20Sopenharmony_ci int rc; 35918c2ecf20Sopenharmony_ci u8 driver = cmd >> 8; 35928c2ecf20Sopenharmony_ci u8 xperm = cmd & 0xff; 35938c2ecf20Sopenharmony_ci 35948c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IOCTL_OP; 35958c2ecf20Sopenharmony_ci ad.u.op = &ioctl; 35968c2ecf20Sopenharmony_ci ad.u.op->cmd = cmd; 35978c2ecf20Sopenharmony_ci ad.u.op->path = file->f_path; 35988c2ecf20Sopenharmony_ci 35998c2ecf20Sopenharmony_ci if (ssid != fsec->sid) { 36008c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 36018c2ecf20Sopenharmony_ci ssid, fsec->sid, 36028c2ecf20Sopenharmony_ci SECCLASS_FD, 36038c2ecf20Sopenharmony_ci FD__USE, 36048c2ecf20Sopenharmony_ci &ad); 36058c2ecf20Sopenharmony_ci if (rc) 36068c2ecf20Sopenharmony_ci goto out; 36078c2ecf20Sopenharmony_ci } 36088c2ecf20Sopenharmony_ci 36098c2ecf20Sopenharmony_ci if (unlikely(IS_PRIVATE(inode))) 36108c2ecf20Sopenharmony_ci return 0; 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci isec = inode_security(inode); 36138c2ecf20Sopenharmony_ci rc = avc_has_extended_perms(&selinux_state, 36148c2ecf20Sopenharmony_ci ssid, isec->sid, isec->sclass, 36158c2ecf20Sopenharmony_ci requested, driver, xperm, &ad); 36168c2ecf20Sopenharmony_ciout: 36178c2ecf20Sopenharmony_ci return rc; 36188c2ecf20Sopenharmony_ci} 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_cistatic int selinux_file_ioctl(struct file *file, unsigned int cmd, 36218c2ecf20Sopenharmony_ci unsigned long arg) 36228c2ecf20Sopenharmony_ci{ 36238c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 36248c2ecf20Sopenharmony_ci int error = 0; 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_ci switch (cmd) { 36278c2ecf20Sopenharmony_ci case FIONREAD: 36288c2ecf20Sopenharmony_ci case FIBMAP: 36298c2ecf20Sopenharmony_ci case FIGETBSZ: 36308c2ecf20Sopenharmony_ci case FS_IOC_GETFLAGS: 36318c2ecf20Sopenharmony_ci case FS_IOC_GETVERSION: 36328c2ecf20Sopenharmony_ci error = file_has_perm(cred, file, FILE__GETATTR); 36338c2ecf20Sopenharmony_ci break; 36348c2ecf20Sopenharmony_ci 36358c2ecf20Sopenharmony_ci case FS_IOC_SETFLAGS: 36368c2ecf20Sopenharmony_ci case FS_IOC_SETVERSION: 36378c2ecf20Sopenharmony_ci error = file_has_perm(cred, file, FILE__SETATTR); 36388c2ecf20Sopenharmony_ci break; 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_ci /* sys_ioctl() checks */ 36418c2ecf20Sopenharmony_ci case FIONBIO: 36428c2ecf20Sopenharmony_ci case FIOASYNC: 36438c2ecf20Sopenharmony_ci error = file_has_perm(cred, file, 0); 36448c2ecf20Sopenharmony_ci break; 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ci case KDSKBENT: 36478c2ecf20Sopenharmony_ci case KDSKBSENT: 36488c2ecf20Sopenharmony_ci error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG, 36498c2ecf20Sopenharmony_ci CAP_OPT_NONE, true); 36508c2ecf20Sopenharmony_ci break; 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci case FIOCLEX: 36538c2ecf20Sopenharmony_ci case FIONCLEX: 36548c2ecf20Sopenharmony_ci if (!selinux_policycap_ioctl_skip_cloexec()) 36558c2ecf20Sopenharmony_ci error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); 36568c2ecf20Sopenharmony_ci break; 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci /* default case assumes that the command will go 36598c2ecf20Sopenharmony_ci * to the file's ioctl() function. 36608c2ecf20Sopenharmony_ci */ 36618c2ecf20Sopenharmony_ci default: 36628c2ecf20Sopenharmony_ci error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); 36638c2ecf20Sopenharmony_ci } 36648c2ecf20Sopenharmony_ci return error; 36658c2ecf20Sopenharmony_ci} 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_cistatic int selinux_file_ioctl_compat(struct file *file, unsigned int cmd, 36688c2ecf20Sopenharmony_ci unsigned long arg) 36698c2ecf20Sopenharmony_ci{ 36708c2ecf20Sopenharmony_ci /* 36718c2ecf20Sopenharmony_ci * If we are in a 64-bit kernel running 32-bit userspace, we need to 36728c2ecf20Sopenharmony_ci * make sure we don't compare 32-bit flags to 64-bit flags. 36738c2ecf20Sopenharmony_ci */ 36748c2ecf20Sopenharmony_ci switch (cmd) { 36758c2ecf20Sopenharmony_ci case FS_IOC32_GETFLAGS: 36768c2ecf20Sopenharmony_ci cmd = FS_IOC_GETFLAGS; 36778c2ecf20Sopenharmony_ci break; 36788c2ecf20Sopenharmony_ci case FS_IOC32_SETFLAGS: 36798c2ecf20Sopenharmony_ci cmd = FS_IOC_SETFLAGS; 36808c2ecf20Sopenharmony_ci break; 36818c2ecf20Sopenharmony_ci case FS_IOC32_GETVERSION: 36828c2ecf20Sopenharmony_ci cmd = FS_IOC_GETVERSION; 36838c2ecf20Sopenharmony_ci break; 36848c2ecf20Sopenharmony_ci case FS_IOC32_SETVERSION: 36858c2ecf20Sopenharmony_ci cmd = FS_IOC_SETVERSION; 36868c2ecf20Sopenharmony_ci break; 36878c2ecf20Sopenharmony_ci default: 36888c2ecf20Sopenharmony_ci break; 36898c2ecf20Sopenharmony_ci } 36908c2ecf20Sopenharmony_ci 36918c2ecf20Sopenharmony_ci return selinux_file_ioctl(file, cmd, arg); 36928c2ecf20Sopenharmony_ci} 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_cistatic int default_noexec __ro_after_init; 36958c2ecf20Sopenharmony_ci 36968c2ecf20Sopenharmony_cistatic int file_map_prot_check(struct file *file, unsigned long prot, int shared) 36978c2ecf20Sopenharmony_ci{ 36988c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 36998c2ecf20Sopenharmony_ci u32 sid = cred_sid(cred); 37008c2ecf20Sopenharmony_ci int rc = 0; 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci if (default_noexec && 37038c2ecf20Sopenharmony_ci (prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) || 37048c2ecf20Sopenharmony_ci (!shared && (prot & PROT_WRITE)))) { 37058c2ecf20Sopenharmony_ci /* 37068c2ecf20Sopenharmony_ci * We are making executable an anonymous mapping or a 37078c2ecf20Sopenharmony_ci * private file mapping that will also be writable. 37088c2ecf20Sopenharmony_ci * This has an additional check. 37098c2ecf20Sopenharmony_ci */ 37108c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 37118c2ecf20Sopenharmony_ci sid, sid, SECCLASS_PROCESS, 37128c2ecf20Sopenharmony_ci PROCESS__EXECMEM, NULL); 37138c2ecf20Sopenharmony_ci if (rc) 37148c2ecf20Sopenharmony_ci goto error; 37158c2ecf20Sopenharmony_ci } 37168c2ecf20Sopenharmony_ci 37178c2ecf20Sopenharmony_ci if (file) { 37188c2ecf20Sopenharmony_ci /* read access is always possible with a mapping */ 37198c2ecf20Sopenharmony_ci u32 av = FILE__READ; 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci /* write access only matters if the mapping is shared */ 37228c2ecf20Sopenharmony_ci if (shared && (prot & PROT_WRITE)) 37238c2ecf20Sopenharmony_ci av |= FILE__WRITE; 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci if (prot & PROT_EXEC) 37268c2ecf20Sopenharmony_ci av |= FILE__EXECUTE; 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_ci return file_has_perm(cred, file, av); 37298c2ecf20Sopenharmony_ci } 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_cierror: 37328c2ecf20Sopenharmony_ci return rc; 37338c2ecf20Sopenharmony_ci} 37348c2ecf20Sopenharmony_ci 37358c2ecf20Sopenharmony_cistatic int selinux_mmap_addr(unsigned long addr) 37368c2ecf20Sopenharmony_ci{ 37378c2ecf20Sopenharmony_ci int rc = 0; 37388c2ecf20Sopenharmony_ci 37398c2ecf20Sopenharmony_ci if (addr < CONFIG_LSM_MMAP_MIN_ADDR) { 37408c2ecf20Sopenharmony_ci u32 sid = current_sid(); 37418c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 37428c2ecf20Sopenharmony_ci sid, sid, SECCLASS_MEMPROTECT, 37438c2ecf20Sopenharmony_ci MEMPROTECT__MMAP_ZERO, NULL); 37448c2ecf20Sopenharmony_ci } 37458c2ecf20Sopenharmony_ci 37468c2ecf20Sopenharmony_ci return rc; 37478c2ecf20Sopenharmony_ci} 37488c2ecf20Sopenharmony_ci 37498c2ecf20Sopenharmony_cistatic int selinux_mmap_file(struct file *file, unsigned long reqprot, 37508c2ecf20Sopenharmony_ci unsigned long prot, unsigned long flags) 37518c2ecf20Sopenharmony_ci{ 37528c2ecf20Sopenharmony_ci struct common_audit_data ad; 37538c2ecf20Sopenharmony_ci int rc; 37548c2ecf20Sopenharmony_ci 37558c2ecf20Sopenharmony_ci if (file) { 37568c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_FILE; 37578c2ecf20Sopenharmony_ci ad.u.file = file; 37588c2ecf20Sopenharmony_ci rc = inode_has_perm(current_cred(), file_inode(file), 37598c2ecf20Sopenharmony_ci FILE__MAP, &ad); 37608c2ecf20Sopenharmony_ci if (rc) 37618c2ecf20Sopenharmony_ci return rc; 37628c2ecf20Sopenharmony_ci } 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci if (checkreqprot_get(&selinux_state)) 37658c2ecf20Sopenharmony_ci prot = reqprot; 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci return file_map_prot_check(file, prot, 37688c2ecf20Sopenharmony_ci (flags & MAP_TYPE) == MAP_SHARED); 37698c2ecf20Sopenharmony_ci} 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_cistatic int selinux_file_mprotect(struct vm_area_struct *vma, 37728c2ecf20Sopenharmony_ci unsigned long reqprot, 37738c2ecf20Sopenharmony_ci unsigned long prot) 37748c2ecf20Sopenharmony_ci{ 37758c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 37768c2ecf20Sopenharmony_ci u32 sid = cred_sid(cred); 37778c2ecf20Sopenharmony_ci 37788c2ecf20Sopenharmony_ci if (checkreqprot_get(&selinux_state)) 37798c2ecf20Sopenharmony_ci prot = reqprot; 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ci if (default_noexec && 37828c2ecf20Sopenharmony_ci (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) { 37838c2ecf20Sopenharmony_ci int rc = 0; 37848c2ecf20Sopenharmony_ci if (vma->vm_start >= vma->vm_mm->start_brk && 37858c2ecf20Sopenharmony_ci vma->vm_end <= vma->vm_mm->brk) { 37868c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 37878c2ecf20Sopenharmony_ci sid, sid, SECCLASS_PROCESS, 37888c2ecf20Sopenharmony_ci PROCESS__EXECHEAP, NULL); 37898c2ecf20Sopenharmony_ci } else if (!vma->vm_file && 37908c2ecf20Sopenharmony_ci ((vma->vm_start <= vma->vm_mm->start_stack && 37918c2ecf20Sopenharmony_ci vma->vm_end >= vma->vm_mm->start_stack) || 37928c2ecf20Sopenharmony_ci vma_is_stack_for_current(vma))) { 37938c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 37948c2ecf20Sopenharmony_ci sid, sid, SECCLASS_PROCESS, 37958c2ecf20Sopenharmony_ci PROCESS__EXECSTACK, NULL); 37968c2ecf20Sopenharmony_ci } else if (vma->vm_file && vma->anon_vma) { 37978c2ecf20Sopenharmony_ci /* 37988c2ecf20Sopenharmony_ci * We are making executable a file mapping that has 37998c2ecf20Sopenharmony_ci * had some COW done. Since pages might have been 38008c2ecf20Sopenharmony_ci * written, check ability to execute the possibly 38018c2ecf20Sopenharmony_ci * modified content. This typically should only 38028c2ecf20Sopenharmony_ci * occur for text relocations. 38038c2ecf20Sopenharmony_ci */ 38048c2ecf20Sopenharmony_ci rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD); 38058c2ecf20Sopenharmony_ci } 38068c2ecf20Sopenharmony_ci if (rc) 38078c2ecf20Sopenharmony_ci return rc; 38088c2ecf20Sopenharmony_ci } 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED); 38118c2ecf20Sopenharmony_ci} 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_cistatic int selinux_file_lock(struct file *file, unsigned int cmd) 38148c2ecf20Sopenharmony_ci{ 38158c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_ci return file_has_perm(cred, file, FILE__LOCK); 38188c2ecf20Sopenharmony_ci} 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_cistatic int selinux_file_fcntl(struct file *file, unsigned int cmd, 38218c2ecf20Sopenharmony_ci unsigned long arg) 38228c2ecf20Sopenharmony_ci{ 38238c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 38248c2ecf20Sopenharmony_ci int err = 0; 38258c2ecf20Sopenharmony_ci 38268c2ecf20Sopenharmony_ci switch (cmd) { 38278c2ecf20Sopenharmony_ci case F_SETFL: 38288c2ecf20Sopenharmony_ci if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) { 38298c2ecf20Sopenharmony_ci err = file_has_perm(cred, file, FILE__WRITE); 38308c2ecf20Sopenharmony_ci break; 38318c2ecf20Sopenharmony_ci } 38328c2ecf20Sopenharmony_ci fallthrough; 38338c2ecf20Sopenharmony_ci case F_SETOWN: 38348c2ecf20Sopenharmony_ci case F_SETSIG: 38358c2ecf20Sopenharmony_ci case F_GETFL: 38368c2ecf20Sopenharmony_ci case F_GETOWN: 38378c2ecf20Sopenharmony_ci case F_GETSIG: 38388c2ecf20Sopenharmony_ci case F_GETOWNER_UIDS: 38398c2ecf20Sopenharmony_ci /* Just check FD__USE permission */ 38408c2ecf20Sopenharmony_ci err = file_has_perm(cred, file, 0); 38418c2ecf20Sopenharmony_ci break; 38428c2ecf20Sopenharmony_ci case F_GETLK: 38438c2ecf20Sopenharmony_ci case F_SETLK: 38448c2ecf20Sopenharmony_ci case F_SETLKW: 38458c2ecf20Sopenharmony_ci case F_OFD_GETLK: 38468c2ecf20Sopenharmony_ci case F_OFD_SETLK: 38478c2ecf20Sopenharmony_ci case F_OFD_SETLKW: 38488c2ecf20Sopenharmony_ci#if BITS_PER_LONG == 32 38498c2ecf20Sopenharmony_ci case F_GETLK64: 38508c2ecf20Sopenharmony_ci case F_SETLK64: 38518c2ecf20Sopenharmony_ci case F_SETLKW64: 38528c2ecf20Sopenharmony_ci#endif 38538c2ecf20Sopenharmony_ci err = file_has_perm(cred, file, FILE__LOCK); 38548c2ecf20Sopenharmony_ci break; 38558c2ecf20Sopenharmony_ci } 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_ci return err; 38588c2ecf20Sopenharmony_ci} 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_cistatic void selinux_file_set_fowner(struct file *file) 38618c2ecf20Sopenharmony_ci{ 38628c2ecf20Sopenharmony_ci struct file_security_struct *fsec; 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ci fsec = selinux_file(file); 38658c2ecf20Sopenharmony_ci fsec->fown_sid = current_sid(); 38668c2ecf20Sopenharmony_ci} 38678c2ecf20Sopenharmony_ci 38688c2ecf20Sopenharmony_cistatic int selinux_file_send_sigiotask(struct task_struct *tsk, 38698c2ecf20Sopenharmony_ci struct fown_struct *fown, int signum) 38708c2ecf20Sopenharmony_ci{ 38718c2ecf20Sopenharmony_ci struct file *file; 38728c2ecf20Sopenharmony_ci u32 sid = task_sid(tsk); 38738c2ecf20Sopenharmony_ci u32 perm; 38748c2ecf20Sopenharmony_ci struct file_security_struct *fsec; 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci /* struct fown_struct is never outside the context of a struct file */ 38778c2ecf20Sopenharmony_ci file = container_of(fown, struct file, f_owner); 38788c2ecf20Sopenharmony_ci 38798c2ecf20Sopenharmony_ci fsec = selinux_file(file); 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci if (!signum) 38828c2ecf20Sopenharmony_ci perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */ 38838c2ecf20Sopenharmony_ci else 38848c2ecf20Sopenharmony_ci perm = signal_to_av(signum); 38858c2ecf20Sopenharmony_ci 38868c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 38878c2ecf20Sopenharmony_ci fsec->fown_sid, sid, 38888c2ecf20Sopenharmony_ci SECCLASS_PROCESS, perm, NULL); 38898c2ecf20Sopenharmony_ci} 38908c2ecf20Sopenharmony_ci 38918c2ecf20Sopenharmony_cistatic int selinux_file_receive(struct file *file) 38928c2ecf20Sopenharmony_ci{ 38938c2ecf20Sopenharmony_ci const struct cred *cred = current_cred(); 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci return file_has_perm(cred, file, file_to_av(file)); 38968c2ecf20Sopenharmony_ci} 38978c2ecf20Sopenharmony_ci 38988c2ecf20Sopenharmony_cistatic int selinux_file_open(struct file *file) 38998c2ecf20Sopenharmony_ci{ 39008c2ecf20Sopenharmony_ci struct file_security_struct *fsec; 39018c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_ci fsec = selinux_file(file); 39048c2ecf20Sopenharmony_ci isec = inode_security(file_inode(file)); 39058c2ecf20Sopenharmony_ci /* 39068c2ecf20Sopenharmony_ci * Save inode label and policy sequence number 39078c2ecf20Sopenharmony_ci * at open-time so that selinux_file_permission 39088c2ecf20Sopenharmony_ci * can determine whether revalidation is necessary. 39098c2ecf20Sopenharmony_ci * Task label is already saved in the file security 39108c2ecf20Sopenharmony_ci * struct as its SID. 39118c2ecf20Sopenharmony_ci */ 39128c2ecf20Sopenharmony_ci fsec->isid = isec->sid; 39138c2ecf20Sopenharmony_ci fsec->pseqno = avc_policy_seqno(&selinux_state); 39148c2ecf20Sopenharmony_ci /* 39158c2ecf20Sopenharmony_ci * Since the inode label or policy seqno may have changed 39168c2ecf20Sopenharmony_ci * between the selinux_inode_permission check and the saving 39178c2ecf20Sopenharmony_ci * of state above, recheck that access is still permitted. 39188c2ecf20Sopenharmony_ci * Otherwise, access might never be revalidated against the 39198c2ecf20Sopenharmony_ci * new inode label or new policy. 39208c2ecf20Sopenharmony_ci * This check is not redundant - do not remove. 39218c2ecf20Sopenharmony_ci */ 39228c2ecf20Sopenharmony_ci return file_path_has_perm(file->f_cred, file, open_file_to_av(file)); 39238c2ecf20Sopenharmony_ci} 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ci/* task security operations */ 39268c2ecf20Sopenharmony_ci 39278c2ecf20Sopenharmony_cistatic int selinux_task_alloc(struct task_struct *task, 39288c2ecf20Sopenharmony_ci unsigned long clone_flags) 39298c2ecf20Sopenharmony_ci{ 39308c2ecf20Sopenharmony_ci u32 sid = current_sid(); 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 39338c2ecf20Sopenharmony_ci sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL); 39348c2ecf20Sopenharmony_ci} 39358c2ecf20Sopenharmony_ci 39368c2ecf20Sopenharmony_ci/* 39378c2ecf20Sopenharmony_ci * prepare a new set of credentials for modification 39388c2ecf20Sopenharmony_ci */ 39398c2ecf20Sopenharmony_cistatic int selinux_cred_prepare(struct cred *new, const struct cred *old, 39408c2ecf20Sopenharmony_ci gfp_t gfp) 39418c2ecf20Sopenharmony_ci{ 39428c2ecf20Sopenharmony_ci const struct task_security_struct *old_tsec = selinux_cred(old); 39438c2ecf20Sopenharmony_ci struct task_security_struct *tsec = selinux_cred(new); 39448c2ecf20Sopenharmony_ci 39458c2ecf20Sopenharmony_ci *tsec = *old_tsec; 39468c2ecf20Sopenharmony_ci return 0; 39478c2ecf20Sopenharmony_ci} 39488c2ecf20Sopenharmony_ci 39498c2ecf20Sopenharmony_ci/* 39508c2ecf20Sopenharmony_ci * transfer the SELinux data to a blank set of creds 39518c2ecf20Sopenharmony_ci */ 39528c2ecf20Sopenharmony_cistatic void selinux_cred_transfer(struct cred *new, const struct cred *old) 39538c2ecf20Sopenharmony_ci{ 39548c2ecf20Sopenharmony_ci const struct task_security_struct *old_tsec = selinux_cred(old); 39558c2ecf20Sopenharmony_ci struct task_security_struct *tsec = selinux_cred(new); 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_ci *tsec = *old_tsec; 39588c2ecf20Sopenharmony_ci} 39598c2ecf20Sopenharmony_ci 39608c2ecf20Sopenharmony_cistatic void selinux_cred_getsecid(const struct cred *c, u32 *secid) 39618c2ecf20Sopenharmony_ci{ 39628c2ecf20Sopenharmony_ci *secid = cred_sid(c); 39638c2ecf20Sopenharmony_ci} 39648c2ecf20Sopenharmony_ci 39658c2ecf20Sopenharmony_ci/* 39668c2ecf20Sopenharmony_ci * set the security data for a kernel service 39678c2ecf20Sopenharmony_ci * - all the creation contexts are set to unlabelled 39688c2ecf20Sopenharmony_ci */ 39698c2ecf20Sopenharmony_cistatic int selinux_kernel_act_as(struct cred *new, u32 secid) 39708c2ecf20Sopenharmony_ci{ 39718c2ecf20Sopenharmony_ci struct task_security_struct *tsec = selinux_cred(new); 39728c2ecf20Sopenharmony_ci u32 sid = current_sid(); 39738c2ecf20Sopenharmony_ci int ret; 39748c2ecf20Sopenharmony_ci 39758c2ecf20Sopenharmony_ci ret = avc_has_perm(&selinux_state, 39768c2ecf20Sopenharmony_ci sid, secid, 39778c2ecf20Sopenharmony_ci SECCLASS_KERNEL_SERVICE, 39788c2ecf20Sopenharmony_ci KERNEL_SERVICE__USE_AS_OVERRIDE, 39798c2ecf20Sopenharmony_ci NULL); 39808c2ecf20Sopenharmony_ci if (ret == 0) { 39818c2ecf20Sopenharmony_ci tsec->sid = secid; 39828c2ecf20Sopenharmony_ci tsec->create_sid = 0; 39838c2ecf20Sopenharmony_ci tsec->keycreate_sid = 0; 39848c2ecf20Sopenharmony_ci tsec->sockcreate_sid = 0; 39858c2ecf20Sopenharmony_ci } 39868c2ecf20Sopenharmony_ci return ret; 39878c2ecf20Sopenharmony_ci} 39888c2ecf20Sopenharmony_ci 39898c2ecf20Sopenharmony_ci/* 39908c2ecf20Sopenharmony_ci * set the file creation context in a security record to the same as the 39918c2ecf20Sopenharmony_ci * objective context of the specified inode 39928c2ecf20Sopenharmony_ci */ 39938c2ecf20Sopenharmony_cistatic int selinux_kernel_create_files_as(struct cred *new, struct inode *inode) 39948c2ecf20Sopenharmony_ci{ 39958c2ecf20Sopenharmony_ci struct inode_security_struct *isec = inode_security(inode); 39968c2ecf20Sopenharmony_ci struct task_security_struct *tsec = selinux_cred(new); 39978c2ecf20Sopenharmony_ci u32 sid = current_sid(); 39988c2ecf20Sopenharmony_ci int ret; 39998c2ecf20Sopenharmony_ci 40008c2ecf20Sopenharmony_ci ret = avc_has_perm(&selinux_state, 40018c2ecf20Sopenharmony_ci sid, isec->sid, 40028c2ecf20Sopenharmony_ci SECCLASS_KERNEL_SERVICE, 40038c2ecf20Sopenharmony_ci KERNEL_SERVICE__CREATE_FILES_AS, 40048c2ecf20Sopenharmony_ci NULL); 40058c2ecf20Sopenharmony_ci 40068c2ecf20Sopenharmony_ci if (ret == 0) 40078c2ecf20Sopenharmony_ci tsec->create_sid = isec->sid; 40088c2ecf20Sopenharmony_ci return ret; 40098c2ecf20Sopenharmony_ci} 40108c2ecf20Sopenharmony_ci 40118c2ecf20Sopenharmony_cistatic int selinux_kernel_module_request(char *kmod_name) 40128c2ecf20Sopenharmony_ci{ 40138c2ecf20Sopenharmony_ci struct common_audit_data ad; 40148c2ecf20Sopenharmony_ci 40158c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_KMOD; 40168c2ecf20Sopenharmony_ci ad.u.kmod_name = kmod_name; 40178c2ecf20Sopenharmony_ci 40188c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 40198c2ecf20Sopenharmony_ci current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM, 40208c2ecf20Sopenharmony_ci SYSTEM__MODULE_REQUEST, &ad); 40218c2ecf20Sopenharmony_ci} 40228c2ecf20Sopenharmony_ci 40238c2ecf20Sopenharmony_cistatic int selinux_kernel_module_from_file(struct file *file) 40248c2ecf20Sopenharmony_ci{ 40258c2ecf20Sopenharmony_ci struct common_audit_data ad; 40268c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 40278c2ecf20Sopenharmony_ci struct file_security_struct *fsec; 40288c2ecf20Sopenharmony_ci u32 sid = current_sid(); 40298c2ecf20Sopenharmony_ci int rc; 40308c2ecf20Sopenharmony_ci 40318c2ecf20Sopenharmony_ci /* init_module */ 40328c2ecf20Sopenharmony_ci if (file == NULL) 40338c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 40348c2ecf20Sopenharmony_ci sid, sid, SECCLASS_SYSTEM, 40358c2ecf20Sopenharmony_ci SYSTEM__MODULE_LOAD, NULL); 40368c2ecf20Sopenharmony_ci 40378c2ecf20Sopenharmony_ci /* finit_module */ 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_FILE; 40408c2ecf20Sopenharmony_ci ad.u.file = file; 40418c2ecf20Sopenharmony_ci 40428c2ecf20Sopenharmony_ci fsec = selinux_file(file); 40438c2ecf20Sopenharmony_ci if (sid != fsec->sid) { 40448c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 40458c2ecf20Sopenharmony_ci sid, fsec->sid, SECCLASS_FD, FD__USE, &ad); 40468c2ecf20Sopenharmony_ci if (rc) 40478c2ecf20Sopenharmony_ci return rc; 40488c2ecf20Sopenharmony_ci } 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_ci isec = inode_security(file_inode(file)); 40518c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 40528c2ecf20Sopenharmony_ci sid, isec->sid, SECCLASS_SYSTEM, 40538c2ecf20Sopenharmony_ci SYSTEM__MODULE_LOAD, &ad); 40548c2ecf20Sopenharmony_ci} 40558c2ecf20Sopenharmony_ci 40568c2ecf20Sopenharmony_cistatic int selinux_kernel_read_file(struct file *file, 40578c2ecf20Sopenharmony_ci enum kernel_read_file_id id, 40588c2ecf20Sopenharmony_ci bool contents) 40598c2ecf20Sopenharmony_ci{ 40608c2ecf20Sopenharmony_ci int rc = 0; 40618c2ecf20Sopenharmony_ci 40628c2ecf20Sopenharmony_ci switch (id) { 40638c2ecf20Sopenharmony_ci case READING_MODULE: 40648c2ecf20Sopenharmony_ci rc = selinux_kernel_module_from_file(contents ? file : NULL); 40658c2ecf20Sopenharmony_ci break; 40668c2ecf20Sopenharmony_ci default: 40678c2ecf20Sopenharmony_ci break; 40688c2ecf20Sopenharmony_ci } 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci return rc; 40718c2ecf20Sopenharmony_ci} 40728c2ecf20Sopenharmony_ci 40738c2ecf20Sopenharmony_cistatic int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents) 40748c2ecf20Sopenharmony_ci{ 40758c2ecf20Sopenharmony_ci int rc = 0; 40768c2ecf20Sopenharmony_ci 40778c2ecf20Sopenharmony_ci switch (id) { 40788c2ecf20Sopenharmony_ci case LOADING_MODULE: 40798c2ecf20Sopenharmony_ci rc = selinux_kernel_module_from_file(NULL); 40808c2ecf20Sopenharmony_ci default: 40818c2ecf20Sopenharmony_ci break; 40828c2ecf20Sopenharmony_ci } 40838c2ecf20Sopenharmony_ci 40848c2ecf20Sopenharmony_ci return rc; 40858c2ecf20Sopenharmony_ci} 40868c2ecf20Sopenharmony_ci 40878c2ecf20Sopenharmony_cistatic int selinux_task_setpgid(struct task_struct *p, pid_t pgid) 40888c2ecf20Sopenharmony_ci{ 40898c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 40908c2ecf20Sopenharmony_ci current_sid(), task_sid(p), SECCLASS_PROCESS, 40918c2ecf20Sopenharmony_ci PROCESS__SETPGID, NULL); 40928c2ecf20Sopenharmony_ci} 40938c2ecf20Sopenharmony_ci 40948c2ecf20Sopenharmony_cistatic int selinux_task_getpgid(struct task_struct *p) 40958c2ecf20Sopenharmony_ci{ 40968c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 40978c2ecf20Sopenharmony_ci current_sid(), task_sid(p), SECCLASS_PROCESS, 40988c2ecf20Sopenharmony_ci PROCESS__GETPGID, NULL); 40998c2ecf20Sopenharmony_ci} 41008c2ecf20Sopenharmony_ci 41018c2ecf20Sopenharmony_cistatic int selinux_task_getsid(struct task_struct *p) 41028c2ecf20Sopenharmony_ci{ 41038c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 41048c2ecf20Sopenharmony_ci current_sid(), task_sid(p), SECCLASS_PROCESS, 41058c2ecf20Sopenharmony_ci PROCESS__GETSESSION, NULL); 41068c2ecf20Sopenharmony_ci} 41078c2ecf20Sopenharmony_ci 41088c2ecf20Sopenharmony_cistatic void selinux_task_getsecid(struct task_struct *p, u32 *secid) 41098c2ecf20Sopenharmony_ci{ 41108c2ecf20Sopenharmony_ci *secid = task_sid(p); 41118c2ecf20Sopenharmony_ci} 41128c2ecf20Sopenharmony_ci 41138c2ecf20Sopenharmony_cistatic int selinux_task_setnice(struct task_struct *p, int nice) 41148c2ecf20Sopenharmony_ci{ 41158c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 41168c2ecf20Sopenharmony_ci current_sid(), task_sid(p), SECCLASS_PROCESS, 41178c2ecf20Sopenharmony_ci PROCESS__SETSCHED, NULL); 41188c2ecf20Sopenharmony_ci} 41198c2ecf20Sopenharmony_ci 41208c2ecf20Sopenharmony_cistatic int selinux_task_setioprio(struct task_struct *p, int ioprio) 41218c2ecf20Sopenharmony_ci{ 41228c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 41238c2ecf20Sopenharmony_ci current_sid(), task_sid(p), SECCLASS_PROCESS, 41248c2ecf20Sopenharmony_ci PROCESS__SETSCHED, NULL); 41258c2ecf20Sopenharmony_ci} 41268c2ecf20Sopenharmony_ci 41278c2ecf20Sopenharmony_cistatic int selinux_task_getioprio(struct task_struct *p) 41288c2ecf20Sopenharmony_ci{ 41298c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 41308c2ecf20Sopenharmony_ci current_sid(), task_sid(p), SECCLASS_PROCESS, 41318c2ecf20Sopenharmony_ci PROCESS__GETSCHED, NULL); 41328c2ecf20Sopenharmony_ci} 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_cistatic int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred, 41358c2ecf20Sopenharmony_ci unsigned int flags) 41368c2ecf20Sopenharmony_ci{ 41378c2ecf20Sopenharmony_ci u32 av = 0; 41388c2ecf20Sopenharmony_ci 41398c2ecf20Sopenharmony_ci if (!flags) 41408c2ecf20Sopenharmony_ci return 0; 41418c2ecf20Sopenharmony_ci if (flags & LSM_PRLIMIT_WRITE) 41428c2ecf20Sopenharmony_ci av |= PROCESS__SETRLIMIT; 41438c2ecf20Sopenharmony_ci if (flags & LSM_PRLIMIT_READ) 41448c2ecf20Sopenharmony_ci av |= PROCESS__GETRLIMIT; 41458c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 41468c2ecf20Sopenharmony_ci cred_sid(cred), cred_sid(tcred), 41478c2ecf20Sopenharmony_ci SECCLASS_PROCESS, av, NULL); 41488c2ecf20Sopenharmony_ci} 41498c2ecf20Sopenharmony_ci 41508c2ecf20Sopenharmony_cistatic int selinux_task_setrlimit(struct task_struct *p, unsigned int resource, 41518c2ecf20Sopenharmony_ci struct rlimit *new_rlim) 41528c2ecf20Sopenharmony_ci{ 41538c2ecf20Sopenharmony_ci struct rlimit *old_rlim = p->signal->rlim + resource; 41548c2ecf20Sopenharmony_ci 41558c2ecf20Sopenharmony_ci /* Control the ability to change the hard limit (whether 41568c2ecf20Sopenharmony_ci lowering or raising it), so that the hard limit can 41578c2ecf20Sopenharmony_ci later be used as a safe reset point for the soft limit 41588c2ecf20Sopenharmony_ci upon context transitions. See selinux_bprm_committing_creds. */ 41598c2ecf20Sopenharmony_ci if (old_rlim->rlim_max != new_rlim->rlim_max) 41608c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 41618c2ecf20Sopenharmony_ci current_sid(), task_sid(p), 41628c2ecf20Sopenharmony_ci SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL); 41638c2ecf20Sopenharmony_ci 41648c2ecf20Sopenharmony_ci return 0; 41658c2ecf20Sopenharmony_ci} 41668c2ecf20Sopenharmony_ci 41678c2ecf20Sopenharmony_cistatic int selinux_task_setscheduler(struct task_struct *p) 41688c2ecf20Sopenharmony_ci{ 41698c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 41708c2ecf20Sopenharmony_ci current_sid(), task_sid(p), SECCLASS_PROCESS, 41718c2ecf20Sopenharmony_ci PROCESS__SETSCHED, NULL); 41728c2ecf20Sopenharmony_ci} 41738c2ecf20Sopenharmony_ci 41748c2ecf20Sopenharmony_cistatic int selinux_task_getscheduler(struct task_struct *p) 41758c2ecf20Sopenharmony_ci{ 41768c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 41778c2ecf20Sopenharmony_ci current_sid(), task_sid(p), SECCLASS_PROCESS, 41788c2ecf20Sopenharmony_ci PROCESS__GETSCHED, NULL); 41798c2ecf20Sopenharmony_ci} 41808c2ecf20Sopenharmony_ci 41818c2ecf20Sopenharmony_cistatic int selinux_task_movememory(struct task_struct *p) 41828c2ecf20Sopenharmony_ci{ 41838c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 41848c2ecf20Sopenharmony_ci current_sid(), task_sid(p), SECCLASS_PROCESS, 41858c2ecf20Sopenharmony_ci PROCESS__SETSCHED, NULL); 41868c2ecf20Sopenharmony_ci} 41878c2ecf20Sopenharmony_ci 41888c2ecf20Sopenharmony_cistatic int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info, 41898c2ecf20Sopenharmony_ci int sig, const struct cred *cred) 41908c2ecf20Sopenharmony_ci{ 41918c2ecf20Sopenharmony_ci u32 secid; 41928c2ecf20Sopenharmony_ci u32 perm; 41938c2ecf20Sopenharmony_ci 41948c2ecf20Sopenharmony_ci if (!sig) 41958c2ecf20Sopenharmony_ci perm = PROCESS__SIGNULL; /* null signal; existence test */ 41968c2ecf20Sopenharmony_ci else 41978c2ecf20Sopenharmony_ci perm = signal_to_av(sig); 41988c2ecf20Sopenharmony_ci if (!cred) 41998c2ecf20Sopenharmony_ci secid = current_sid(); 42008c2ecf20Sopenharmony_ci else 42018c2ecf20Sopenharmony_ci secid = cred_sid(cred); 42028c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 42038c2ecf20Sopenharmony_ci secid, task_sid(p), SECCLASS_PROCESS, perm, NULL); 42048c2ecf20Sopenharmony_ci} 42058c2ecf20Sopenharmony_ci 42068c2ecf20Sopenharmony_cistatic void selinux_task_to_inode(struct task_struct *p, 42078c2ecf20Sopenharmony_ci struct inode *inode) 42088c2ecf20Sopenharmony_ci{ 42098c2ecf20Sopenharmony_ci struct inode_security_struct *isec = selinux_inode(inode); 42108c2ecf20Sopenharmony_ci u32 sid = task_sid(p); 42118c2ecf20Sopenharmony_ci 42128c2ecf20Sopenharmony_ci spin_lock(&isec->lock); 42138c2ecf20Sopenharmony_ci isec->sclass = inode_mode_to_security_class(inode->i_mode); 42148c2ecf20Sopenharmony_ci isec->sid = sid; 42158c2ecf20Sopenharmony_ci isec->initialized = LABEL_INITIALIZED; 42168c2ecf20Sopenharmony_ci spin_unlock(&isec->lock); 42178c2ecf20Sopenharmony_ci} 42188c2ecf20Sopenharmony_ci 42198c2ecf20Sopenharmony_ci/* Returns error only if unable to parse addresses */ 42208c2ecf20Sopenharmony_cistatic int selinux_parse_skb_ipv4(struct sk_buff *skb, 42218c2ecf20Sopenharmony_ci struct common_audit_data *ad, u8 *proto) 42228c2ecf20Sopenharmony_ci{ 42238c2ecf20Sopenharmony_ci int offset, ihlen, ret = -EINVAL; 42248c2ecf20Sopenharmony_ci struct iphdr _iph, *ih; 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci offset = skb_network_offset(skb); 42278c2ecf20Sopenharmony_ci ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph); 42288c2ecf20Sopenharmony_ci if (ih == NULL) 42298c2ecf20Sopenharmony_ci goto out; 42308c2ecf20Sopenharmony_ci 42318c2ecf20Sopenharmony_ci ihlen = ih->ihl * 4; 42328c2ecf20Sopenharmony_ci if (ihlen < sizeof(_iph)) 42338c2ecf20Sopenharmony_ci goto out; 42348c2ecf20Sopenharmony_ci 42358c2ecf20Sopenharmony_ci ad->u.net->v4info.saddr = ih->saddr; 42368c2ecf20Sopenharmony_ci ad->u.net->v4info.daddr = ih->daddr; 42378c2ecf20Sopenharmony_ci ret = 0; 42388c2ecf20Sopenharmony_ci 42398c2ecf20Sopenharmony_ci if (proto) 42408c2ecf20Sopenharmony_ci *proto = ih->protocol; 42418c2ecf20Sopenharmony_ci 42428c2ecf20Sopenharmony_ci switch (ih->protocol) { 42438c2ecf20Sopenharmony_ci case IPPROTO_TCP: { 42448c2ecf20Sopenharmony_ci struct tcphdr _tcph, *th; 42458c2ecf20Sopenharmony_ci 42468c2ecf20Sopenharmony_ci if (ntohs(ih->frag_off) & IP_OFFSET) 42478c2ecf20Sopenharmony_ci break; 42488c2ecf20Sopenharmony_ci 42498c2ecf20Sopenharmony_ci offset += ihlen; 42508c2ecf20Sopenharmony_ci th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); 42518c2ecf20Sopenharmony_ci if (th == NULL) 42528c2ecf20Sopenharmony_ci break; 42538c2ecf20Sopenharmony_ci 42548c2ecf20Sopenharmony_ci ad->u.net->sport = th->source; 42558c2ecf20Sopenharmony_ci ad->u.net->dport = th->dest; 42568c2ecf20Sopenharmony_ci break; 42578c2ecf20Sopenharmony_ci } 42588c2ecf20Sopenharmony_ci 42598c2ecf20Sopenharmony_ci case IPPROTO_UDP: { 42608c2ecf20Sopenharmony_ci struct udphdr _udph, *uh; 42618c2ecf20Sopenharmony_ci 42628c2ecf20Sopenharmony_ci if (ntohs(ih->frag_off) & IP_OFFSET) 42638c2ecf20Sopenharmony_ci break; 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci offset += ihlen; 42668c2ecf20Sopenharmony_ci uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); 42678c2ecf20Sopenharmony_ci if (uh == NULL) 42688c2ecf20Sopenharmony_ci break; 42698c2ecf20Sopenharmony_ci 42708c2ecf20Sopenharmony_ci ad->u.net->sport = uh->source; 42718c2ecf20Sopenharmony_ci ad->u.net->dport = uh->dest; 42728c2ecf20Sopenharmony_ci break; 42738c2ecf20Sopenharmony_ci } 42748c2ecf20Sopenharmony_ci 42758c2ecf20Sopenharmony_ci case IPPROTO_DCCP: { 42768c2ecf20Sopenharmony_ci struct dccp_hdr _dccph, *dh; 42778c2ecf20Sopenharmony_ci 42788c2ecf20Sopenharmony_ci if (ntohs(ih->frag_off) & IP_OFFSET) 42798c2ecf20Sopenharmony_ci break; 42808c2ecf20Sopenharmony_ci 42818c2ecf20Sopenharmony_ci offset += ihlen; 42828c2ecf20Sopenharmony_ci dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); 42838c2ecf20Sopenharmony_ci if (dh == NULL) 42848c2ecf20Sopenharmony_ci break; 42858c2ecf20Sopenharmony_ci 42868c2ecf20Sopenharmony_ci ad->u.net->sport = dh->dccph_sport; 42878c2ecf20Sopenharmony_ci ad->u.net->dport = dh->dccph_dport; 42888c2ecf20Sopenharmony_ci break; 42898c2ecf20Sopenharmony_ci } 42908c2ecf20Sopenharmony_ci 42918c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IP_SCTP) 42928c2ecf20Sopenharmony_ci case IPPROTO_SCTP: { 42938c2ecf20Sopenharmony_ci struct sctphdr _sctph, *sh; 42948c2ecf20Sopenharmony_ci 42958c2ecf20Sopenharmony_ci if (ntohs(ih->frag_off) & IP_OFFSET) 42968c2ecf20Sopenharmony_ci break; 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_ci offset += ihlen; 42998c2ecf20Sopenharmony_ci sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph); 43008c2ecf20Sopenharmony_ci if (sh == NULL) 43018c2ecf20Sopenharmony_ci break; 43028c2ecf20Sopenharmony_ci 43038c2ecf20Sopenharmony_ci ad->u.net->sport = sh->source; 43048c2ecf20Sopenharmony_ci ad->u.net->dport = sh->dest; 43058c2ecf20Sopenharmony_ci break; 43068c2ecf20Sopenharmony_ci } 43078c2ecf20Sopenharmony_ci#endif 43088c2ecf20Sopenharmony_ci default: 43098c2ecf20Sopenharmony_ci break; 43108c2ecf20Sopenharmony_ci } 43118c2ecf20Sopenharmony_ciout: 43128c2ecf20Sopenharmony_ci return ret; 43138c2ecf20Sopenharmony_ci} 43148c2ecf20Sopenharmony_ci 43158c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 43168c2ecf20Sopenharmony_ci 43178c2ecf20Sopenharmony_ci/* Returns error only if unable to parse addresses */ 43188c2ecf20Sopenharmony_cistatic int selinux_parse_skb_ipv6(struct sk_buff *skb, 43198c2ecf20Sopenharmony_ci struct common_audit_data *ad, u8 *proto) 43208c2ecf20Sopenharmony_ci{ 43218c2ecf20Sopenharmony_ci u8 nexthdr; 43228c2ecf20Sopenharmony_ci int ret = -EINVAL, offset; 43238c2ecf20Sopenharmony_ci struct ipv6hdr _ipv6h, *ip6; 43248c2ecf20Sopenharmony_ci __be16 frag_off; 43258c2ecf20Sopenharmony_ci 43268c2ecf20Sopenharmony_ci offset = skb_network_offset(skb); 43278c2ecf20Sopenharmony_ci ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h); 43288c2ecf20Sopenharmony_ci if (ip6 == NULL) 43298c2ecf20Sopenharmony_ci goto out; 43308c2ecf20Sopenharmony_ci 43318c2ecf20Sopenharmony_ci ad->u.net->v6info.saddr = ip6->saddr; 43328c2ecf20Sopenharmony_ci ad->u.net->v6info.daddr = ip6->daddr; 43338c2ecf20Sopenharmony_ci ret = 0; 43348c2ecf20Sopenharmony_ci 43358c2ecf20Sopenharmony_ci nexthdr = ip6->nexthdr; 43368c2ecf20Sopenharmony_ci offset += sizeof(_ipv6h); 43378c2ecf20Sopenharmony_ci offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off); 43388c2ecf20Sopenharmony_ci if (offset < 0) 43398c2ecf20Sopenharmony_ci goto out; 43408c2ecf20Sopenharmony_ci 43418c2ecf20Sopenharmony_ci if (proto) 43428c2ecf20Sopenharmony_ci *proto = nexthdr; 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_ci switch (nexthdr) { 43458c2ecf20Sopenharmony_ci case IPPROTO_TCP: { 43468c2ecf20Sopenharmony_ci struct tcphdr _tcph, *th; 43478c2ecf20Sopenharmony_ci 43488c2ecf20Sopenharmony_ci th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph); 43498c2ecf20Sopenharmony_ci if (th == NULL) 43508c2ecf20Sopenharmony_ci break; 43518c2ecf20Sopenharmony_ci 43528c2ecf20Sopenharmony_ci ad->u.net->sport = th->source; 43538c2ecf20Sopenharmony_ci ad->u.net->dport = th->dest; 43548c2ecf20Sopenharmony_ci break; 43558c2ecf20Sopenharmony_ci } 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci case IPPROTO_UDP: { 43588c2ecf20Sopenharmony_ci struct udphdr _udph, *uh; 43598c2ecf20Sopenharmony_ci 43608c2ecf20Sopenharmony_ci uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph); 43618c2ecf20Sopenharmony_ci if (uh == NULL) 43628c2ecf20Sopenharmony_ci break; 43638c2ecf20Sopenharmony_ci 43648c2ecf20Sopenharmony_ci ad->u.net->sport = uh->source; 43658c2ecf20Sopenharmony_ci ad->u.net->dport = uh->dest; 43668c2ecf20Sopenharmony_ci break; 43678c2ecf20Sopenharmony_ci } 43688c2ecf20Sopenharmony_ci 43698c2ecf20Sopenharmony_ci case IPPROTO_DCCP: { 43708c2ecf20Sopenharmony_ci struct dccp_hdr _dccph, *dh; 43718c2ecf20Sopenharmony_ci 43728c2ecf20Sopenharmony_ci dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph); 43738c2ecf20Sopenharmony_ci if (dh == NULL) 43748c2ecf20Sopenharmony_ci break; 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_ci ad->u.net->sport = dh->dccph_sport; 43778c2ecf20Sopenharmony_ci ad->u.net->dport = dh->dccph_dport; 43788c2ecf20Sopenharmony_ci break; 43798c2ecf20Sopenharmony_ci } 43808c2ecf20Sopenharmony_ci 43818c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IP_SCTP) 43828c2ecf20Sopenharmony_ci case IPPROTO_SCTP: { 43838c2ecf20Sopenharmony_ci struct sctphdr _sctph, *sh; 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ci sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph); 43868c2ecf20Sopenharmony_ci if (sh == NULL) 43878c2ecf20Sopenharmony_ci break; 43888c2ecf20Sopenharmony_ci 43898c2ecf20Sopenharmony_ci ad->u.net->sport = sh->source; 43908c2ecf20Sopenharmony_ci ad->u.net->dport = sh->dest; 43918c2ecf20Sopenharmony_ci break; 43928c2ecf20Sopenharmony_ci } 43938c2ecf20Sopenharmony_ci#endif 43948c2ecf20Sopenharmony_ci /* includes fragments */ 43958c2ecf20Sopenharmony_ci default: 43968c2ecf20Sopenharmony_ci break; 43978c2ecf20Sopenharmony_ci } 43988c2ecf20Sopenharmony_ciout: 43998c2ecf20Sopenharmony_ci return ret; 44008c2ecf20Sopenharmony_ci} 44018c2ecf20Sopenharmony_ci 44028c2ecf20Sopenharmony_ci#endif /* IPV6 */ 44038c2ecf20Sopenharmony_ci 44048c2ecf20Sopenharmony_cistatic int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad, 44058c2ecf20Sopenharmony_ci char **_addrp, int src, u8 *proto) 44068c2ecf20Sopenharmony_ci{ 44078c2ecf20Sopenharmony_ci char *addrp; 44088c2ecf20Sopenharmony_ci int ret; 44098c2ecf20Sopenharmony_ci 44108c2ecf20Sopenharmony_ci switch (ad->u.net->family) { 44118c2ecf20Sopenharmony_ci case PF_INET: 44128c2ecf20Sopenharmony_ci ret = selinux_parse_skb_ipv4(skb, ad, proto); 44138c2ecf20Sopenharmony_ci if (ret) 44148c2ecf20Sopenharmony_ci goto parse_error; 44158c2ecf20Sopenharmony_ci addrp = (char *)(src ? &ad->u.net->v4info.saddr : 44168c2ecf20Sopenharmony_ci &ad->u.net->v4info.daddr); 44178c2ecf20Sopenharmony_ci goto okay; 44188c2ecf20Sopenharmony_ci 44198c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 44208c2ecf20Sopenharmony_ci case PF_INET6: 44218c2ecf20Sopenharmony_ci ret = selinux_parse_skb_ipv6(skb, ad, proto); 44228c2ecf20Sopenharmony_ci if (ret) 44238c2ecf20Sopenharmony_ci goto parse_error; 44248c2ecf20Sopenharmony_ci addrp = (char *)(src ? &ad->u.net->v6info.saddr : 44258c2ecf20Sopenharmony_ci &ad->u.net->v6info.daddr); 44268c2ecf20Sopenharmony_ci goto okay; 44278c2ecf20Sopenharmony_ci#endif /* IPV6 */ 44288c2ecf20Sopenharmony_ci default: 44298c2ecf20Sopenharmony_ci addrp = NULL; 44308c2ecf20Sopenharmony_ci goto okay; 44318c2ecf20Sopenharmony_ci } 44328c2ecf20Sopenharmony_ci 44338c2ecf20Sopenharmony_ciparse_error: 44348c2ecf20Sopenharmony_ci pr_warn( 44358c2ecf20Sopenharmony_ci "SELinux: failure in selinux_parse_skb()," 44368c2ecf20Sopenharmony_ci " unable to parse packet\n"); 44378c2ecf20Sopenharmony_ci return ret; 44388c2ecf20Sopenharmony_ci 44398c2ecf20Sopenharmony_ciokay: 44408c2ecf20Sopenharmony_ci if (_addrp) 44418c2ecf20Sopenharmony_ci *_addrp = addrp; 44428c2ecf20Sopenharmony_ci return 0; 44438c2ecf20Sopenharmony_ci} 44448c2ecf20Sopenharmony_ci 44458c2ecf20Sopenharmony_ci/** 44468c2ecf20Sopenharmony_ci * selinux_skb_peerlbl_sid - Determine the peer label of a packet 44478c2ecf20Sopenharmony_ci * @skb: the packet 44488c2ecf20Sopenharmony_ci * @family: protocol family 44498c2ecf20Sopenharmony_ci * @sid: the packet's peer label SID 44508c2ecf20Sopenharmony_ci * 44518c2ecf20Sopenharmony_ci * Description: 44528c2ecf20Sopenharmony_ci * Check the various different forms of network peer labeling and determine 44538c2ecf20Sopenharmony_ci * the peer label/SID for the packet; most of the magic actually occurs in 44548c2ecf20Sopenharmony_ci * the security server function security_net_peersid_cmp(). The function 44558c2ecf20Sopenharmony_ci * returns zero if the value in @sid is valid (although it may be SECSID_NULL) 44568c2ecf20Sopenharmony_ci * or -EACCES if @sid is invalid due to inconsistencies with the different 44578c2ecf20Sopenharmony_ci * peer labels. 44588c2ecf20Sopenharmony_ci * 44598c2ecf20Sopenharmony_ci */ 44608c2ecf20Sopenharmony_cistatic int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid) 44618c2ecf20Sopenharmony_ci{ 44628c2ecf20Sopenharmony_ci int err; 44638c2ecf20Sopenharmony_ci u32 xfrm_sid; 44648c2ecf20Sopenharmony_ci u32 nlbl_sid; 44658c2ecf20Sopenharmony_ci u32 nlbl_type; 44668c2ecf20Sopenharmony_ci 44678c2ecf20Sopenharmony_ci err = selinux_xfrm_skb_sid(skb, &xfrm_sid); 44688c2ecf20Sopenharmony_ci if (unlikely(err)) 44698c2ecf20Sopenharmony_ci return -EACCES; 44708c2ecf20Sopenharmony_ci err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid); 44718c2ecf20Sopenharmony_ci if (unlikely(err)) 44728c2ecf20Sopenharmony_ci return -EACCES; 44738c2ecf20Sopenharmony_ci 44748c2ecf20Sopenharmony_ci err = security_net_peersid_resolve(&selinux_state, nlbl_sid, 44758c2ecf20Sopenharmony_ci nlbl_type, xfrm_sid, sid); 44768c2ecf20Sopenharmony_ci if (unlikely(err)) { 44778c2ecf20Sopenharmony_ci pr_warn( 44788c2ecf20Sopenharmony_ci "SELinux: failure in selinux_skb_peerlbl_sid()," 44798c2ecf20Sopenharmony_ci " unable to determine packet's peer label\n"); 44808c2ecf20Sopenharmony_ci return -EACCES; 44818c2ecf20Sopenharmony_ci } 44828c2ecf20Sopenharmony_ci 44838c2ecf20Sopenharmony_ci return 0; 44848c2ecf20Sopenharmony_ci} 44858c2ecf20Sopenharmony_ci 44868c2ecf20Sopenharmony_ci/** 44878c2ecf20Sopenharmony_ci * selinux_conn_sid - Determine the child socket label for a connection 44888c2ecf20Sopenharmony_ci * @sk_sid: the parent socket's SID 44898c2ecf20Sopenharmony_ci * @skb_sid: the packet's SID 44908c2ecf20Sopenharmony_ci * @conn_sid: the resulting connection SID 44918c2ecf20Sopenharmony_ci * 44928c2ecf20Sopenharmony_ci * If @skb_sid is valid then the user:role:type information from @sk_sid is 44938c2ecf20Sopenharmony_ci * combined with the MLS information from @skb_sid in order to create 44948c2ecf20Sopenharmony_ci * @conn_sid. If @skb_sid is not valid then @conn_sid is simply a copy 44958c2ecf20Sopenharmony_ci * of @sk_sid. Returns zero on success, negative values on failure. 44968c2ecf20Sopenharmony_ci * 44978c2ecf20Sopenharmony_ci */ 44988c2ecf20Sopenharmony_cistatic int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid) 44998c2ecf20Sopenharmony_ci{ 45008c2ecf20Sopenharmony_ci int err = 0; 45018c2ecf20Sopenharmony_ci 45028c2ecf20Sopenharmony_ci if (skb_sid != SECSID_NULL) 45038c2ecf20Sopenharmony_ci err = security_sid_mls_copy(&selinux_state, sk_sid, skb_sid, 45048c2ecf20Sopenharmony_ci conn_sid); 45058c2ecf20Sopenharmony_ci else 45068c2ecf20Sopenharmony_ci *conn_sid = sk_sid; 45078c2ecf20Sopenharmony_ci 45088c2ecf20Sopenharmony_ci return err; 45098c2ecf20Sopenharmony_ci} 45108c2ecf20Sopenharmony_ci 45118c2ecf20Sopenharmony_ci/* socket security operations */ 45128c2ecf20Sopenharmony_ci 45138c2ecf20Sopenharmony_cistatic int socket_sockcreate_sid(const struct task_security_struct *tsec, 45148c2ecf20Sopenharmony_ci u16 secclass, u32 *socksid) 45158c2ecf20Sopenharmony_ci{ 45168c2ecf20Sopenharmony_ci if (tsec->sockcreate_sid > SECSID_NULL) { 45178c2ecf20Sopenharmony_ci *socksid = tsec->sockcreate_sid; 45188c2ecf20Sopenharmony_ci return 0; 45198c2ecf20Sopenharmony_ci } 45208c2ecf20Sopenharmony_ci 45218c2ecf20Sopenharmony_ci return security_transition_sid(&selinux_state, tsec->sid, tsec->sid, 45228c2ecf20Sopenharmony_ci secclass, NULL, socksid); 45238c2ecf20Sopenharmony_ci} 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_cistatic int sock_has_perm(struct sock *sk, u32 perms) 45268c2ecf20Sopenharmony_ci{ 45278c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 45288c2ecf20Sopenharmony_ci struct common_audit_data ad; 45298c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 45308c2ecf20Sopenharmony_ci 45318c2ecf20Sopenharmony_ci if (sksec->sid == SECINITSID_KERNEL) 45328c2ecf20Sopenharmony_ci return 0; 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 45358c2ecf20Sopenharmony_ci ad.u.net = &net; 45368c2ecf20Sopenharmony_ci ad.u.net->sk = sk; 45378c2ecf20Sopenharmony_ci 45388c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 45398c2ecf20Sopenharmony_ci current_sid(), sksec->sid, sksec->sclass, perms, 45408c2ecf20Sopenharmony_ci &ad); 45418c2ecf20Sopenharmony_ci} 45428c2ecf20Sopenharmony_ci 45438c2ecf20Sopenharmony_cistatic int selinux_socket_create(int family, int type, 45448c2ecf20Sopenharmony_ci int protocol, int kern) 45458c2ecf20Sopenharmony_ci{ 45468c2ecf20Sopenharmony_ci const struct task_security_struct *tsec = selinux_cred(current_cred()); 45478c2ecf20Sopenharmony_ci u32 newsid; 45488c2ecf20Sopenharmony_ci u16 secclass; 45498c2ecf20Sopenharmony_ci int rc; 45508c2ecf20Sopenharmony_ci 45518c2ecf20Sopenharmony_ci if (kern) 45528c2ecf20Sopenharmony_ci return 0; 45538c2ecf20Sopenharmony_ci 45548c2ecf20Sopenharmony_ci secclass = socket_type_to_security_class(family, type, protocol); 45558c2ecf20Sopenharmony_ci rc = socket_sockcreate_sid(tsec, secclass, &newsid); 45568c2ecf20Sopenharmony_ci if (rc) 45578c2ecf20Sopenharmony_ci return rc; 45588c2ecf20Sopenharmony_ci 45598c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 45608c2ecf20Sopenharmony_ci tsec->sid, newsid, secclass, SOCKET__CREATE, NULL); 45618c2ecf20Sopenharmony_ci} 45628c2ecf20Sopenharmony_ci 45638c2ecf20Sopenharmony_cistatic int selinux_socket_post_create(struct socket *sock, int family, 45648c2ecf20Sopenharmony_ci int type, int protocol, int kern) 45658c2ecf20Sopenharmony_ci{ 45668c2ecf20Sopenharmony_ci const struct task_security_struct *tsec = selinux_cred(current_cred()); 45678c2ecf20Sopenharmony_ci struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock)); 45688c2ecf20Sopenharmony_ci struct sk_security_struct *sksec; 45698c2ecf20Sopenharmony_ci u16 sclass = socket_type_to_security_class(family, type, protocol); 45708c2ecf20Sopenharmony_ci u32 sid = SECINITSID_KERNEL; 45718c2ecf20Sopenharmony_ci int err = 0; 45728c2ecf20Sopenharmony_ci 45738c2ecf20Sopenharmony_ci if (!kern) { 45748c2ecf20Sopenharmony_ci err = socket_sockcreate_sid(tsec, sclass, &sid); 45758c2ecf20Sopenharmony_ci if (err) 45768c2ecf20Sopenharmony_ci return err; 45778c2ecf20Sopenharmony_ci } 45788c2ecf20Sopenharmony_ci 45798c2ecf20Sopenharmony_ci isec->sclass = sclass; 45808c2ecf20Sopenharmony_ci isec->sid = sid; 45818c2ecf20Sopenharmony_ci isec->initialized = LABEL_INITIALIZED; 45828c2ecf20Sopenharmony_ci 45838c2ecf20Sopenharmony_ci if (sock->sk) { 45848c2ecf20Sopenharmony_ci sksec = sock->sk->sk_security; 45858c2ecf20Sopenharmony_ci sksec->sclass = sclass; 45868c2ecf20Sopenharmony_ci sksec->sid = sid; 45878c2ecf20Sopenharmony_ci /* Allows detection of the first association on this socket */ 45888c2ecf20Sopenharmony_ci if (sksec->sclass == SECCLASS_SCTP_SOCKET) 45898c2ecf20Sopenharmony_ci sksec->sctp_assoc_state = SCTP_ASSOC_UNSET; 45908c2ecf20Sopenharmony_ci 45918c2ecf20Sopenharmony_ci err = selinux_netlbl_socket_post_create(sock->sk, family); 45928c2ecf20Sopenharmony_ci } 45938c2ecf20Sopenharmony_ci 45948c2ecf20Sopenharmony_ci return err; 45958c2ecf20Sopenharmony_ci} 45968c2ecf20Sopenharmony_ci 45978c2ecf20Sopenharmony_cistatic int selinux_socket_socketpair(struct socket *socka, 45988c2ecf20Sopenharmony_ci struct socket *sockb) 45998c2ecf20Sopenharmony_ci{ 46008c2ecf20Sopenharmony_ci struct sk_security_struct *sksec_a = socka->sk->sk_security; 46018c2ecf20Sopenharmony_ci struct sk_security_struct *sksec_b = sockb->sk->sk_security; 46028c2ecf20Sopenharmony_ci 46038c2ecf20Sopenharmony_ci sksec_a->peer_sid = sksec_b->sid; 46048c2ecf20Sopenharmony_ci sksec_b->peer_sid = sksec_a->sid; 46058c2ecf20Sopenharmony_ci 46068c2ecf20Sopenharmony_ci return 0; 46078c2ecf20Sopenharmony_ci} 46088c2ecf20Sopenharmony_ci 46098c2ecf20Sopenharmony_ci/* Range of port numbers used to automatically bind. 46108c2ecf20Sopenharmony_ci Need to determine whether we should perform a name_bind 46118c2ecf20Sopenharmony_ci permission check between the socket and the port number. */ 46128c2ecf20Sopenharmony_ci 46138c2ecf20Sopenharmony_cistatic int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) 46148c2ecf20Sopenharmony_ci{ 46158c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 46168c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 46178c2ecf20Sopenharmony_ci u16 family; 46188c2ecf20Sopenharmony_ci int err; 46198c2ecf20Sopenharmony_ci 46208c2ecf20Sopenharmony_ci err = sock_has_perm(sk, SOCKET__BIND); 46218c2ecf20Sopenharmony_ci if (err) 46228c2ecf20Sopenharmony_ci goto out; 46238c2ecf20Sopenharmony_ci 46248c2ecf20Sopenharmony_ci /* If PF_INET or PF_INET6, check name_bind permission for the port. */ 46258c2ecf20Sopenharmony_ci family = sk->sk_family; 46268c2ecf20Sopenharmony_ci if (family == PF_INET || family == PF_INET6) { 46278c2ecf20Sopenharmony_ci char *addrp; 46288c2ecf20Sopenharmony_ci struct common_audit_data ad; 46298c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 46308c2ecf20Sopenharmony_ci struct sockaddr_in *addr4 = NULL; 46318c2ecf20Sopenharmony_ci struct sockaddr_in6 *addr6 = NULL; 46328c2ecf20Sopenharmony_ci u16 family_sa; 46338c2ecf20Sopenharmony_ci unsigned short snum; 46348c2ecf20Sopenharmony_ci u32 sid, node_perm; 46358c2ecf20Sopenharmony_ci 46368c2ecf20Sopenharmony_ci /* 46378c2ecf20Sopenharmony_ci * sctp_bindx(3) calls via selinux_sctp_bind_connect() 46388c2ecf20Sopenharmony_ci * that validates multiple binding addresses. Because of this 46398c2ecf20Sopenharmony_ci * need to check address->sa_family as it is possible to have 46408c2ecf20Sopenharmony_ci * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. 46418c2ecf20Sopenharmony_ci */ 46428c2ecf20Sopenharmony_ci if (addrlen < offsetofend(struct sockaddr, sa_family)) 46438c2ecf20Sopenharmony_ci return -EINVAL; 46448c2ecf20Sopenharmony_ci family_sa = address->sa_family; 46458c2ecf20Sopenharmony_ci switch (family_sa) { 46468c2ecf20Sopenharmony_ci case AF_UNSPEC: 46478c2ecf20Sopenharmony_ci case AF_INET: 46488c2ecf20Sopenharmony_ci if (addrlen < sizeof(struct sockaddr_in)) 46498c2ecf20Sopenharmony_ci return -EINVAL; 46508c2ecf20Sopenharmony_ci addr4 = (struct sockaddr_in *)address; 46518c2ecf20Sopenharmony_ci if (family_sa == AF_UNSPEC) { 46528c2ecf20Sopenharmony_ci if (family == PF_INET6) { 46538c2ecf20Sopenharmony_ci /* Length check from inet6_bind_sk() */ 46548c2ecf20Sopenharmony_ci if (addrlen < SIN6_LEN_RFC2133) 46558c2ecf20Sopenharmony_ci return -EINVAL; 46568c2ecf20Sopenharmony_ci /* Family check from __inet6_bind() */ 46578c2ecf20Sopenharmony_ci goto err_af; 46588c2ecf20Sopenharmony_ci } 46598c2ecf20Sopenharmony_ci /* see __inet_bind(), we only want to allow 46608c2ecf20Sopenharmony_ci * AF_UNSPEC if the address is INADDR_ANY 46618c2ecf20Sopenharmony_ci */ 46628c2ecf20Sopenharmony_ci if (addr4->sin_addr.s_addr != htonl(INADDR_ANY)) 46638c2ecf20Sopenharmony_ci goto err_af; 46648c2ecf20Sopenharmony_ci family_sa = AF_INET; 46658c2ecf20Sopenharmony_ci } 46668c2ecf20Sopenharmony_ci snum = ntohs(addr4->sin_port); 46678c2ecf20Sopenharmony_ci addrp = (char *)&addr4->sin_addr.s_addr; 46688c2ecf20Sopenharmony_ci break; 46698c2ecf20Sopenharmony_ci case AF_INET6: 46708c2ecf20Sopenharmony_ci if (addrlen < SIN6_LEN_RFC2133) 46718c2ecf20Sopenharmony_ci return -EINVAL; 46728c2ecf20Sopenharmony_ci addr6 = (struct sockaddr_in6 *)address; 46738c2ecf20Sopenharmony_ci snum = ntohs(addr6->sin6_port); 46748c2ecf20Sopenharmony_ci addrp = (char *)&addr6->sin6_addr.s6_addr; 46758c2ecf20Sopenharmony_ci break; 46768c2ecf20Sopenharmony_ci default: 46778c2ecf20Sopenharmony_ci goto err_af; 46788c2ecf20Sopenharmony_ci } 46798c2ecf20Sopenharmony_ci 46808c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 46818c2ecf20Sopenharmony_ci ad.u.net = &net; 46828c2ecf20Sopenharmony_ci ad.u.net->sport = htons(snum); 46838c2ecf20Sopenharmony_ci ad.u.net->family = family_sa; 46848c2ecf20Sopenharmony_ci 46858c2ecf20Sopenharmony_ci if (snum) { 46868c2ecf20Sopenharmony_ci int low, high; 46878c2ecf20Sopenharmony_ci 46888c2ecf20Sopenharmony_ci inet_get_local_port_range(sock_net(sk), &low, &high); 46898c2ecf20Sopenharmony_ci 46908c2ecf20Sopenharmony_ci if (inet_port_requires_bind_service(sock_net(sk), snum) || 46918c2ecf20Sopenharmony_ci snum < low || snum > high) { 46928c2ecf20Sopenharmony_ci err = sel_netport_sid(sk->sk_protocol, 46938c2ecf20Sopenharmony_ci snum, &sid); 46948c2ecf20Sopenharmony_ci if (err) 46958c2ecf20Sopenharmony_ci goto out; 46968c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 46978c2ecf20Sopenharmony_ci sksec->sid, sid, 46988c2ecf20Sopenharmony_ci sksec->sclass, 46998c2ecf20Sopenharmony_ci SOCKET__NAME_BIND, &ad); 47008c2ecf20Sopenharmony_ci if (err) 47018c2ecf20Sopenharmony_ci goto out; 47028c2ecf20Sopenharmony_ci } 47038c2ecf20Sopenharmony_ci } 47048c2ecf20Sopenharmony_ci 47058c2ecf20Sopenharmony_ci switch (sksec->sclass) { 47068c2ecf20Sopenharmony_ci case SECCLASS_TCP_SOCKET: 47078c2ecf20Sopenharmony_ci node_perm = TCP_SOCKET__NODE_BIND; 47088c2ecf20Sopenharmony_ci break; 47098c2ecf20Sopenharmony_ci 47108c2ecf20Sopenharmony_ci case SECCLASS_UDP_SOCKET: 47118c2ecf20Sopenharmony_ci node_perm = UDP_SOCKET__NODE_BIND; 47128c2ecf20Sopenharmony_ci break; 47138c2ecf20Sopenharmony_ci 47148c2ecf20Sopenharmony_ci case SECCLASS_DCCP_SOCKET: 47158c2ecf20Sopenharmony_ci node_perm = DCCP_SOCKET__NODE_BIND; 47168c2ecf20Sopenharmony_ci break; 47178c2ecf20Sopenharmony_ci 47188c2ecf20Sopenharmony_ci case SECCLASS_SCTP_SOCKET: 47198c2ecf20Sopenharmony_ci node_perm = SCTP_SOCKET__NODE_BIND; 47208c2ecf20Sopenharmony_ci break; 47218c2ecf20Sopenharmony_ci 47228c2ecf20Sopenharmony_ci default: 47238c2ecf20Sopenharmony_ci node_perm = RAWIP_SOCKET__NODE_BIND; 47248c2ecf20Sopenharmony_ci break; 47258c2ecf20Sopenharmony_ci } 47268c2ecf20Sopenharmony_ci 47278c2ecf20Sopenharmony_ci err = sel_netnode_sid(addrp, family_sa, &sid); 47288c2ecf20Sopenharmony_ci if (err) 47298c2ecf20Sopenharmony_ci goto out; 47308c2ecf20Sopenharmony_ci 47318c2ecf20Sopenharmony_ci if (family_sa == AF_INET) 47328c2ecf20Sopenharmony_ci ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; 47338c2ecf20Sopenharmony_ci else 47348c2ecf20Sopenharmony_ci ad.u.net->v6info.saddr = addr6->sin6_addr; 47358c2ecf20Sopenharmony_ci 47368c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 47378c2ecf20Sopenharmony_ci sksec->sid, sid, 47388c2ecf20Sopenharmony_ci sksec->sclass, node_perm, &ad); 47398c2ecf20Sopenharmony_ci if (err) 47408c2ecf20Sopenharmony_ci goto out; 47418c2ecf20Sopenharmony_ci } 47428c2ecf20Sopenharmony_ciout: 47438c2ecf20Sopenharmony_ci return err; 47448c2ecf20Sopenharmony_cierr_af: 47458c2ecf20Sopenharmony_ci /* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */ 47468c2ecf20Sopenharmony_ci if (sksec->sclass == SECCLASS_SCTP_SOCKET) 47478c2ecf20Sopenharmony_ci return -EINVAL; 47488c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 47498c2ecf20Sopenharmony_ci} 47508c2ecf20Sopenharmony_ci 47518c2ecf20Sopenharmony_ci/* This supports connect(2) and SCTP connect services such as sctp_connectx(3) 47528c2ecf20Sopenharmony_ci * and sctp_sendmsg(3) as described in Documentation/security/SCTP.rst 47538c2ecf20Sopenharmony_ci */ 47548c2ecf20Sopenharmony_cistatic int selinux_socket_connect_helper(struct socket *sock, 47558c2ecf20Sopenharmony_ci struct sockaddr *address, int addrlen) 47568c2ecf20Sopenharmony_ci{ 47578c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 47588c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 47598c2ecf20Sopenharmony_ci int err; 47608c2ecf20Sopenharmony_ci 47618c2ecf20Sopenharmony_ci err = sock_has_perm(sk, SOCKET__CONNECT); 47628c2ecf20Sopenharmony_ci if (err) 47638c2ecf20Sopenharmony_ci return err; 47648c2ecf20Sopenharmony_ci if (addrlen < offsetofend(struct sockaddr, sa_family)) 47658c2ecf20Sopenharmony_ci return -EINVAL; 47668c2ecf20Sopenharmony_ci 47678c2ecf20Sopenharmony_ci /* connect(AF_UNSPEC) has special handling, as it is a documented 47688c2ecf20Sopenharmony_ci * way to disconnect the socket 47698c2ecf20Sopenharmony_ci */ 47708c2ecf20Sopenharmony_ci if (address->sa_family == AF_UNSPEC) 47718c2ecf20Sopenharmony_ci return 0; 47728c2ecf20Sopenharmony_ci 47738c2ecf20Sopenharmony_ci /* 47748c2ecf20Sopenharmony_ci * If a TCP, DCCP or SCTP socket, check name_connect permission 47758c2ecf20Sopenharmony_ci * for the port. 47768c2ecf20Sopenharmony_ci */ 47778c2ecf20Sopenharmony_ci if (sksec->sclass == SECCLASS_TCP_SOCKET || 47788c2ecf20Sopenharmony_ci sksec->sclass == SECCLASS_DCCP_SOCKET || 47798c2ecf20Sopenharmony_ci sksec->sclass == SECCLASS_SCTP_SOCKET) { 47808c2ecf20Sopenharmony_ci struct common_audit_data ad; 47818c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 47828c2ecf20Sopenharmony_ci struct sockaddr_in *addr4 = NULL; 47838c2ecf20Sopenharmony_ci struct sockaddr_in6 *addr6 = NULL; 47848c2ecf20Sopenharmony_ci unsigned short snum; 47858c2ecf20Sopenharmony_ci u32 sid, perm; 47868c2ecf20Sopenharmony_ci 47878c2ecf20Sopenharmony_ci /* sctp_connectx(3) calls via selinux_sctp_bind_connect() 47888c2ecf20Sopenharmony_ci * that validates multiple connect addresses. Because of this 47898c2ecf20Sopenharmony_ci * need to check address->sa_family as it is possible to have 47908c2ecf20Sopenharmony_ci * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET. 47918c2ecf20Sopenharmony_ci */ 47928c2ecf20Sopenharmony_ci switch (address->sa_family) { 47938c2ecf20Sopenharmony_ci case AF_INET: 47948c2ecf20Sopenharmony_ci addr4 = (struct sockaddr_in *)address; 47958c2ecf20Sopenharmony_ci if (addrlen < sizeof(struct sockaddr_in)) 47968c2ecf20Sopenharmony_ci return -EINVAL; 47978c2ecf20Sopenharmony_ci snum = ntohs(addr4->sin_port); 47988c2ecf20Sopenharmony_ci break; 47998c2ecf20Sopenharmony_ci case AF_INET6: 48008c2ecf20Sopenharmony_ci addr6 = (struct sockaddr_in6 *)address; 48018c2ecf20Sopenharmony_ci if (addrlen < SIN6_LEN_RFC2133) 48028c2ecf20Sopenharmony_ci return -EINVAL; 48038c2ecf20Sopenharmony_ci snum = ntohs(addr6->sin6_port); 48048c2ecf20Sopenharmony_ci break; 48058c2ecf20Sopenharmony_ci default: 48068c2ecf20Sopenharmony_ci /* Note that SCTP services expect -EINVAL, whereas 48078c2ecf20Sopenharmony_ci * others expect -EAFNOSUPPORT. 48088c2ecf20Sopenharmony_ci */ 48098c2ecf20Sopenharmony_ci if (sksec->sclass == SECCLASS_SCTP_SOCKET) 48108c2ecf20Sopenharmony_ci return -EINVAL; 48118c2ecf20Sopenharmony_ci else 48128c2ecf20Sopenharmony_ci return -EAFNOSUPPORT; 48138c2ecf20Sopenharmony_ci } 48148c2ecf20Sopenharmony_ci 48158c2ecf20Sopenharmony_ci err = sel_netport_sid(sk->sk_protocol, snum, &sid); 48168c2ecf20Sopenharmony_ci if (err) 48178c2ecf20Sopenharmony_ci return err; 48188c2ecf20Sopenharmony_ci 48198c2ecf20Sopenharmony_ci switch (sksec->sclass) { 48208c2ecf20Sopenharmony_ci case SECCLASS_TCP_SOCKET: 48218c2ecf20Sopenharmony_ci perm = TCP_SOCKET__NAME_CONNECT; 48228c2ecf20Sopenharmony_ci break; 48238c2ecf20Sopenharmony_ci case SECCLASS_DCCP_SOCKET: 48248c2ecf20Sopenharmony_ci perm = DCCP_SOCKET__NAME_CONNECT; 48258c2ecf20Sopenharmony_ci break; 48268c2ecf20Sopenharmony_ci case SECCLASS_SCTP_SOCKET: 48278c2ecf20Sopenharmony_ci perm = SCTP_SOCKET__NAME_CONNECT; 48288c2ecf20Sopenharmony_ci break; 48298c2ecf20Sopenharmony_ci } 48308c2ecf20Sopenharmony_ci 48318c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 48328c2ecf20Sopenharmony_ci ad.u.net = &net; 48338c2ecf20Sopenharmony_ci ad.u.net->dport = htons(snum); 48348c2ecf20Sopenharmony_ci ad.u.net->family = address->sa_family; 48358c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 48368c2ecf20Sopenharmony_ci sksec->sid, sid, sksec->sclass, perm, &ad); 48378c2ecf20Sopenharmony_ci if (err) 48388c2ecf20Sopenharmony_ci return err; 48398c2ecf20Sopenharmony_ci } 48408c2ecf20Sopenharmony_ci 48418c2ecf20Sopenharmony_ci return 0; 48428c2ecf20Sopenharmony_ci} 48438c2ecf20Sopenharmony_ci 48448c2ecf20Sopenharmony_ci/* Supports connect(2), see comments in selinux_socket_connect_helper() */ 48458c2ecf20Sopenharmony_cistatic int selinux_socket_connect(struct socket *sock, 48468c2ecf20Sopenharmony_ci struct sockaddr *address, int addrlen) 48478c2ecf20Sopenharmony_ci{ 48488c2ecf20Sopenharmony_ci int err; 48498c2ecf20Sopenharmony_ci struct sock *sk = sock->sk; 48508c2ecf20Sopenharmony_ci 48518c2ecf20Sopenharmony_ci err = selinux_socket_connect_helper(sock, address, addrlen); 48528c2ecf20Sopenharmony_ci if (err) 48538c2ecf20Sopenharmony_ci return err; 48548c2ecf20Sopenharmony_ci 48558c2ecf20Sopenharmony_ci return selinux_netlbl_socket_connect(sk, address); 48568c2ecf20Sopenharmony_ci} 48578c2ecf20Sopenharmony_ci 48588c2ecf20Sopenharmony_cistatic int selinux_socket_listen(struct socket *sock, int backlog) 48598c2ecf20Sopenharmony_ci{ 48608c2ecf20Sopenharmony_ci return sock_has_perm(sock->sk, SOCKET__LISTEN); 48618c2ecf20Sopenharmony_ci} 48628c2ecf20Sopenharmony_ci 48638c2ecf20Sopenharmony_cistatic int selinux_socket_accept(struct socket *sock, struct socket *newsock) 48648c2ecf20Sopenharmony_ci{ 48658c2ecf20Sopenharmony_ci int err; 48668c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 48678c2ecf20Sopenharmony_ci struct inode_security_struct *newisec; 48688c2ecf20Sopenharmony_ci u16 sclass; 48698c2ecf20Sopenharmony_ci u32 sid; 48708c2ecf20Sopenharmony_ci 48718c2ecf20Sopenharmony_ci err = sock_has_perm(sock->sk, SOCKET__ACCEPT); 48728c2ecf20Sopenharmony_ci if (err) 48738c2ecf20Sopenharmony_ci return err; 48748c2ecf20Sopenharmony_ci 48758c2ecf20Sopenharmony_ci isec = inode_security_novalidate(SOCK_INODE(sock)); 48768c2ecf20Sopenharmony_ci spin_lock(&isec->lock); 48778c2ecf20Sopenharmony_ci sclass = isec->sclass; 48788c2ecf20Sopenharmony_ci sid = isec->sid; 48798c2ecf20Sopenharmony_ci spin_unlock(&isec->lock); 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci newisec = inode_security_novalidate(SOCK_INODE(newsock)); 48828c2ecf20Sopenharmony_ci newisec->sclass = sclass; 48838c2ecf20Sopenharmony_ci newisec->sid = sid; 48848c2ecf20Sopenharmony_ci newisec->initialized = LABEL_INITIALIZED; 48858c2ecf20Sopenharmony_ci 48868c2ecf20Sopenharmony_ci return 0; 48878c2ecf20Sopenharmony_ci} 48888c2ecf20Sopenharmony_ci 48898c2ecf20Sopenharmony_cistatic int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg, 48908c2ecf20Sopenharmony_ci int size) 48918c2ecf20Sopenharmony_ci{ 48928c2ecf20Sopenharmony_ci return sock_has_perm(sock->sk, SOCKET__WRITE); 48938c2ecf20Sopenharmony_ci} 48948c2ecf20Sopenharmony_ci 48958c2ecf20Sopenharmony_cistatic int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg, 48968c2ecf20Sopenharmony_ci int size, int flags) 48978c2ecf20Sopenharmony_ci{ 48988c2ecf20Sopenharmony_ci return sock_has_perm(sock->sk, SOCKET__READ); 48998c2ecf20Sopenharmony_ci} 49008c2ecf20Sopenharmony_ci 49018c2ecf20Sopenharmony_cistatic int selinux_socket_getsockname(struct socket *sock) 49028c2ecf20Sopenharmony_ci{ 49038c2ecf20Sopenharmony_ci return sock_has_perm(sock->sk, SOCKET__GETATTR); 49048c2ecf20Sopenharmony_ci} 49058c2ecf20Sopenharmony_ci 49068c2ecf20Sopenharmony_cistatic int selinux_socket_getpeername(struct socket *sock) 49078c2ecf20Sopenharmony_ci{ 49088c2ecf20Sopenharmony_ci return sock_has_perm(sock->sk, SOCKET__GETATTR); 49098c2ecf20Sopenharmony_ci} 49108c2ecf20Sopenharmony_ci 49118c2ecf20Sopenharmony_cistatic int selinux_socket_setsockopt(struct socket *sock, int level, int optname) 49128c2ecf20Sopenharmony_ci{ 49138c2ecf20Sopenharmony_ci int err; 49148c2ecf20Sopenharmony_ci 49158c2ecf20Sopenharmony_ci err = sock_has_perm(sock->sk, SOCKET__SETOPT); 49168c2ecf20Sopenharmony_ci if (err) 49178c2ecf20Sopenharmony_ci return err; 49188c2ecf20Sopenharmony_ci 49198c2ecf20Sopenharmony_ci return selinux_netlbl_socket_setsockopt(sock, level, optname); 49208c2ecf20Sopenharmony_ci} 49218c2ecf20Sopenharmony_ci 49228c2ecf20Sopenharmony_cistatic int selinux_socket_getsockopt(struct socket *sock, int level, 49238c2ecf20Sopenharmony_ci int optname) 49248c2ecf20Sopenharmony_ci{ 49258c2ecf20Sopenharmony_ci return sock_has_perm(sock->sk, SOCKET__GETOPT); 49268c2ecf20Sopenharmony_ci} 49278c2ecf20Sopenharmony_ci 49288c2ecf20Sopenharmony_cistatic int selinux_socket_shutdown(struct socket *sock, int how) 49298c2ecf20Sopenharmony_ci{ 49308c2ecf20Sopenharmony_ci return sock_has_perm(sock->sk, SOCKET__SHUTDOWN); 49318c2ecf20Sopenharmony_ci} 49328c2ecf20Sopenharmony_ci 49338c2ecf20Sopenharmony_cistatic int selinux_socket_unix_stream_connect(struct sock *sock, 49348c2ecf20Sopenharmony_ci struct sock *other, 49358c2ecf20Sopenharmony_ci struct sock *newsk) 49368c2ecf20Sopenharmony_ci{ 49378c2ecf20Sopenharmony_ci struct sk_security_struct *sksec_sock = sock->sk_security; 49388c2ecf20Sopenharmony_ci struct sk_security_struct *sksec_other = other->sk_security; 49398c2ecf20Sopenharmony_ci struct sk_security_struct *sksec_new = newsk->sk_security; 49408c2ecf20Sopenharmony_ci struct common_audit_data ad; 49418c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 49428c2ecf20Sopenharmony_ci int err; 49438c2ecf20Sopenharmony_ci 49448c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 49458c2ecf20Sopenharmony_ci ad.u.net = &net; 49468c2ecf20Sopenharmony_ci ad.u.net->sk = other; 49478c2ecf20Sopenharmony_ci 49488c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 49498c2ecf20Sopenharmony_ci sksec_sock->sid, sksec_other->sid, 49508c2ecf20Sopenharmony_ci sksec_other->sclass, 49518c2ecf20Sopenharmony_ci UNIX_STREAM_SOCKET__CONNECTTO, &ad); 49528c2ecf20Sopenharmony_ci if (err) 49538c2ecf20Sopenharmony_ci return err; 49548c2ecf20Sopenharmony_ci 49558c2ecf20Sopenharmony_ci /* server child socket */ 49568c2ecf20Sopenharmony_ci sksec_new->peer_sid = sksec_sock->sid; 49578c2ecf20Sopenharmony_ci err = security_sid_mls_copy(&selinux_state, sksec_other->sid, 49588c2ecf20Sopenharmony_ci sksec_sock->sid, &sksec_new->sid); 49598c2ecf20Sopenharmony_ci if (err) 49608c2ecf20Sopenharmony_ci return err; 49618c2ecf20Sopenharmony_ci 49628c2ecf20Sopenharmony_ci /* connecting socket */ 49638c2ecf20Sopenharmony_ci sksec_sock->peer_sid = sksec_new->sid; 49648c2ecf20Sopenharmony_ci 49658c2ecf20Sopenharmony_ci return 0; 49668c2ecf20Sopenharmony_ci} 49678c2ecf20Sopenharmony_ci 49688c2ecf20Sopenharmony_cistatic int selinux_socket_unix_may_send(struct socket *sock, 49698c2ecf20Sopenharmony_ci struct socket *other) 49708c2ecf20Sopenharmony_ci{ 49718c2ecf20Sopenharmony_ci struct sk_security_struct *ssec = sock->sk->sk_security; 49728c2ecf20Sopenharmony_ci struct sk_security_struct *osec = other->sk->sk_security; 49738c2ecf20Sopenharmony_ci struct common_audit_data ad; 49748c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 49758c2ecf20Sopenharmony_ci 49768c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 49778c2ecf20Sopenharmony_ci ad.u.net = &net; 49788c2ecf20Sopenharmony_ci ad.u.net->sk = other->sk; 49798c2ecf20Sopenharmony_ci 49808c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 49818c2ecf20Sopenharmony_ci ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO, 49828c2ecf20Sopenharmony_ci &ad); 49838c2ecf20Sopenharmony_ci} 49848c2ecf20Sopenharmony_ci 49858c2ecf20Sopenharmony_cistatic int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex, 49868c2ecf20Sopenharmony_ci char *addrp, u16 family, u32 peer_sid, 49878c2ecf20Sopenharmony_ci struct common_audit_data *ad) 49888c2ecf20Sopenharmony_ci{ 49898c2ecf20Sopenharmony_ci int err; 49908c2ecf20Sopenharmony_ci u32 if_sid; 49918c2ecf20Sopenharmony_ci u32 node_sid; 49928c2ecf20Sopenharmony_ci 49938c2ecf20Sopenharmony_ci err = sel_netif_sid(ns, ifindex, &if_sid); 49948c2ecf20Sopenharmony_ci if (err) 49958c2ecf20Sopenharmony_ci return err; 49968c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 49978c2ecf20Sopenharmony_ci peer_sid, if_sid, 49988c2ecf20Sopenharmony_ci SECCLASS_NETIF, NETIF__INGRESS, ad); 49998c2ecf20Sopenharmony_ci if (err) 50008c2ecf20Sopenharmony_ci return err; 50018c2ecf20Sopenharmony_ci 50028c2ecf20Sopenharmony_ci err = sel_netnode_sid(addrp, family, &node_sid); 50038c2ecf20Sopenharmony_ci if (err) 50048c2ecf20Sopenharmony_ci return err; 50058c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 50068c2ecf20Sopenharmony_ci peer_sid, node_sid, 50078c2ecf20Sopenharmony_ci SECCLASS_NODE, NODE__RECVFROM, ad); 50088c2ecf20Sopenharmony_ci} 50098c2ecf20Sopenharmony_ci 50108c2ecf20Sopenharmony_cistatic int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, 50118c2ecf20Sopenharmony_ci u16 family) 50128c2ecf20Sopenharmony_ci{ 50138c2ecf20Sopenharmony_ci int err = 0; 50148c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 50158c2ecf20Sopenharmony_ci u32 sk_sid = sksec->sid; 50168c2ecf20Sopenharmony_ci struct common_audit_data ad; 50178c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 50188c2ecf20Sopenharmony_ci char *addrp; 50198c2ecf20Sopenharmony_ci 50208c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 50218c2ecf20Sopenharmony_ci ad.u.net = &net; 50228c2ecf20Sopenharmony_ci ad.u.net->netif = skb->skb_iif; 50238c2ecf20Sopenharmony_ci ad.u.net->family = family; 50248c2ecf20Sopenharmony_ci err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); 50258c2ecf20Sopenharmony_ci if (err) 50268c2ecf20Sopenharmony_ci return err; 50278c2ecf20Sopenharmony_ci 50288c2ecf20Sopenharmony_ci if (selinux_secmark_enabled()) { 50298c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 50308c2ecf20Sopenharmony_ci sk_sid, skb->secmark, SECCLASS_PACKET, 50318c2ecf20Sopenharmony_ci PACKET__RECV, &ad); 50328c2ecf20Sopenharmony_ci if (err) 50338c2ecf20Sopenharmony_ci return err; 50348c2ecf20Sopenharmony_ci } 50358c2ecf20Sopenharmony_ci 50368c2ecf20Sopenharmony_ci err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad); 50378c2ecf20Sopenharmony_ci if (err) 50388c2ecf20Sopenharmony_ci return err; 50398c2ecf20Sopenharmony_ci err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad); 50408c2ecf20Sopenharmony_ci 50418c2ecf20Sopenharmony_ci return err; 50428c2ecf20Sopenharmony_ci} 50438c2ecf20Sopenharmony_ci 50448c2ecf20Sopenharmony_cistatic int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 50458c2ecf20Sopenharmony_ci{ 50468c2ecf20Sopenharmony_ci int err; 50478c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 50488c2ecf20Sopenharmony_ci u16 family = sk->sk_family; 50498c2ecf20Sopenharmony_ci u32 sk_sid = sksec->sid; 50508c2ecf20Sopenharmony_ci struct common_audit_data ad; 50518c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 50528c2ecf20Sopenharmony_ci char *addrp; 50538c2ecf20Sopenharmony_ci u8 secmark_active; 50548c2ecf20Sopenharmony_ci u8 peerlbl_active; 50558c2ecf20Sopenharmony_ci 50568c2ecf20Sopenharmony_ci if (family != PF_INET && family != PF_INET6) 50578c2ecf20Sopenharmony_ci return 0; 50588c2ecf20Sopenharmony_ci 50598c2ecf20Sopenharmony_ci /* Handle mapped IPv4 packets arriving via IPv6 sockets */ 50608c2ecf20Sopenharmony_ci if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 50618c2ecf20Sopenharmony_ci family = PF_INET; 50628c2ecf20Sopenharmony_ci 50638c2ecf20Sopenharmony_ci /* If any sort of compatibility mode is enabled then handoff processing 50648c2ecf20Sopenharmony_ci * to the selinux_sock_rcv_skb_compat() function to deal with the 50658c2ecf20Sopenharmony_ci * special handling. We do this in an attempt to keep this function 50668c2ecf20Sopenharmony_ci * as fast and as clean as possible. */ 50678c2ecf20Sopenharmony_ci if (!selinux_policycap_netpeer()) 50688c2ecf20Sopenharmony_ci return selinux_sock_rcv_skb_compat(sk, skb, family); 50698c2ecf20Sopenharmony_ci 50708c2ecf20Sopenharmony_ci secmark_active = selinux_secmark_enabled(); 50718c2ecf20Sopenharmony_ci peerlbl_active = selinux_peerlbl_enabled(); 50728c2ecf20Sopenharmony_ci if (!secmark_active && !peerlbl_active) 50738c2ecf20Sopenharmony_ci return 0; 50748c2ecf20Sopenharmony_ci 50758c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 50768c2ecf20Sopenharmony_ci ad.u.net = &net; 50778c2ecf20Sopenharmony_ci ad.u.net->netif = skb->skb_iif; 50788c2ecf20Sopenharmony_ci ad.u.net->family = family; 50798c2ecf20Sopenharmony_ci err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL); 50808c2ecf20Sopenharmony_ci if (err) 50818c2ecf20Sopenharmony_ci return err; 50828c2ecf20Sopenharmony_ci 50838c2ecf20Sopenharmony_ci if (peerlbl_active) { 50848c2ecf20Sopenharmony_ci u32 peer_sid; 50858c2ecf20Sopenharmony_ci 50868c2ecf20Sopenharmony_ci err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); 50878c2ecf20Sopenharmony_ci if (err) 50888c2ecf20Sopenharmony_ci return err; 50898c2ecf20Sopenharmony_ci err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif, 50908c2ecf20Sopenharmony_ci addrp, family, peer_sid, &ad); 50918c2ecf20Sopenharmony_ci if (err) { 50928c2ecf20Sopenharmony_ci selinux_netlbl_err(skb, family, err, 0); 50938c2ecf20Sopenharmony_ci return err; 50948c2ecf20Sopenharmony_ci } 50958c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 50968c2ecf20Sopenharmony_ci sk_sid, peer_sid, SECCLASS_PEER, 50978c2ecf20Sopenharmony_ci PEER__RECV, &ad); 50988c2ecf20Sopenharmony_ci if (err) { 50998c2ecf20Sopenharmony_ci selinux_netlbl_err(skb, family, err, 0); 51008c2ecf20Sopenharmony_ci return err; 51018c2ecf20Sopenharmony_ci } 51028c2ecf20Sopenharmony_ci } 51038c2ecf20Sopenharmony_ci 51048c2ecf20Sopenharmony_ci if (secmark_active) { 51058c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 51068c2ecf20Sopenharmony_ci sk_sid, skb->secmark, SECCLASS_PACKET, 51078c2ecf20Sopenharmony_ci PACKET__RECV, &ad); 51088c2ecf20Sopenharmony_ci if (err) 51098c2ecf20Sopenharmony_ci return err; 51108c2ecf20Sopenharmony_ci } 51118c2ecf20Sopenharmony_ci 51128c2ecf20Sopenharmony_ci return err; 51138c2ecf20Sopenharmony_ci} 51148c2ecf20Sopenharmony_ci 51158c2ecf20Sopenharmony_cistatic int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, 51168c2ecf20Sopenharmony_ci int __user *optlen, unsigned len) 51178c2ecf20Sopenharmony_ci{ 51188c2ecf20Sopenharmony_ci int err = 0; 51198c2ecf20Sopenharmony_ci char *scontext; 51208c2ecf20Sopenharmony_ci u32 scontext_len; 51218c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sock->sk->sk_security; 51228c2ecf20Sopenharmony_ci u32 peer_sid = SECSID_NULL; 51238c2ecf20Sopenharmony_ci 51248c2ecf20Sopenharmony_ci if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET || 51258c2ecf20Sopenharmony_ci sksec->sclass == SECCLASS_TCP_SOCKET || 51268c2ecf20Sopenharmony_ci sksec->sclass == SECCLASS_SCTP_SOCKET) 51278c2ecf20Sopenharmony_ci peer_sid = sksec->peer_sid; 51288c2ecf20Sopenharmony_ci if (peer_sid == SECSID_NULL) 51298c2ecf20Sopenharmony_ci return -ENOPROTOOPT; 51308c2ecf20Sopenharmony_ci 51318c2ecf20Sopenharmony_ci err = security_sid_to_context(&selinux_state, peer_sid, &scontext, 51328c2ecf20Sopenharmony_ci &scontext_len); 51338c2ecf20Sopenharmony_ci if (err) 51348c2ecf20Sopenharmony_ci return err; 51358c2ecf20Sopenharmony_ci 51368c2ecf20Sopenharmony_ci if (scontext_len > len) { 51378c2ecf20Sopenharmony_ci err = -ERANGE; 51388c2ecf20Sopenharmony_ci goto out_len; 51398c2ecf20Sopenharmony_ci } 51408c2ecf20Sopenharmony_ci 51418c2ecf20Sopenharmony_ci if (copy_to_user(optval, scontext, scontext_len)) 51428c2ecf20Sopenharmony_ci err = -EFAULT; 51438c2ecf20Sopenharmony_ci 51448c2ecf20Sopenharmony_ciout_len: 51458c2ecf20Sopenharmony_ci if (put_user(scontext_len, optlen)) 51468c2ecf20Sopenharmony_ci err = -EFAULT; 51478c2ecf20Sopenharmony_ci kfree(scontext); 51488c2ecf20Sopenharmony_ci return err; 51498c2ecf20Sopenharmony_ci} 51508c2ecf20Sopenharmony_ci 51518c2ecf20Sopenharmony_cistatic int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) 51528c2ecf20Sopenharmony_ci{ 51538c2ecf20Sopenharmony_ci u32 peer_secid = SECSID_NULL; 51548c2ecf20Sopenharmony_ci u16 family; 51558c2ecf20Sopenharmony_ci struct inode_security_struct *isec; 51568c2ecf20Sopenharmony_ci 51578c2ecf20Sopenharmony_ci if (skb && skb->protocol == htons(ETH_P_IP)) 51588c2ecf20Sopenharmony_ci family = PF_INET; 51598c2ecf20Sopenharmony_ci else if (skb && skb->protocol == htons(ETH_P_IPV6)) 51608c2ecf20Sopenharmony_ci family = PF_INET6; 51618c2ecf20Sopenharmony_ci else if (sock) 51628c2ecf20Sopenharmony_ci family = sock->sk->sk_family; 51638c2ecf20Sopenharmony_ci else 51648c2ecf20Sopenharmony_ci goto out; 51658c2ecf20Sopenharmony_ci 51668c2ecf20Sopenharmony_ci if (sock && family == PF_UNIX) { 51678c2ecf20Sopenharmony_ci isec = inode_security_novalidate(SOCK_INODE(sock)); 51688c2ecf20Sopenharmony_ci peer_secid = isec->sid; 51698c2ecf20Sopenharmony_ci } else if (skb) 51708c2ecf20Sopenharmony_ci selinux_skb_peerlbl_sid(skb, family, &peer_secid); 51718c2ecf20Sopenharmony_ci 51728c2ecf20Sopenharmony_ciout: 51738c2ecf20Sopenharmony_ci *secid = peer_secid; 51748c2ecf20Sopenharmony_ci if (peer_secid == SECSID_NULL) 51758c2ecf20Sopenharmony_ci return -EINVAL; 51768c2ecf20Sopenharmony_ci return 0; 51778c2ecf20Sopenharmony_ci} 51788c2ecf20Sopenharmony_ci 51798c2ecf20Sopenharmony_cistatic int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority) 51808c2ecf20Sopenharmony_ci{ 51818c2ecf20Sopenharmony_ci struct sk_security_struct *sksec; 51828c2ecf20Sopenharmony_ci 51838c2ecf20Sopenharmony_ci sksec = kzalloc(sizeof(*sksec), priority); 51848c2ecf20Sopenharmony_ci if (!sksec) 51858c2ecf20Sopenharmony_ci return -ENOMEM; 51868c2ecf20Sopenharmony_ci 51878c2ecf20Sopenharmony_ci sksec->peer_sid = SECINITSID_UNLABELED; 51888c2ecf20Sopenharmony_ci sksec->sid = SECINITSID_UNLABELED; 51898c2ecf20Sopenharmony_ci sksec->sclass = SECCLASS_SOCKET; 51908c2ecf20Sopenharmony_ci selinux_netlbl_sk_security_reset(sksec); 51918c2ecf20Sopenharmony_ci sk->sk_security = sksec; 51928c2ecf20Sopenharmony_ci 51938c2ecf20Sopenharmony_ci return 0; 51948c2ecf20Sopenharmony_ci} 51958c2ecf20Sopenharmony_ci 51968c2ecf20Sopenharmony_cistatic void selinux_sk_free_security(struct sock *sk) 51978c2ecf20Sopenharmony_ci{ 51988c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 51998c2ecf20Sopenharmony_ci 52008c2ecf20Sopenharmony_ci sk->sk_security = NULL; 52018c2ecf20Sopenharmony_ci selinux_netlbl_sk_security_free(sksec); 52028c2ecf20Sopenharmony_ci kfree(sksec); 52038c2ecf20Sopenharmony_ci} 52048c2ecf20Sopenharmony_ci 52058c2ecf20Sopenharmony_cistatic void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk) 52068c2ecf20Sopenharmony_ci{ 52078c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 52088c2ecf20Sopenharmony_ci struct sk_security_struct *newsksec = newsk->sk_security; 52098c2ecf20Sopenharmony_ci 52108c2ecf20Sopenharmony_ci newsksec->sid = sksec->sid; 52118c2ecf20Sopenharmony_ci newsksec->peer_sid = sksec->peer_sid; 52128c2ecf20Sopenharmony_ci newsksec->sclass = sksec->sclass; 52138c2ecf20Sopenharmony_ci 52148c2ecf20Sopenharmony_ci selinux_netlbl_sk_security_reset(newsksec); 52158c2ecf20Sopenharmony_ci} 52168c2ecf20Sopenharmony_ci 52178c2ecf20Sopenharmony_cistatic void selinux_sk_getsecid(struct sock *sk, u32 *secid) 52188c2ecf20Sopenharmony_ci{ 52198c2ecf20Sopenharmony_ci if (!sk) 52208c2ecf20Sopenharmony_ci *secid = SECINITSID_ANY_SOCKET; 52218c2ecf20Sopenharmony_ci else { 52228c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 52238c2ecf20Sopenharmony_ci 52248c2ecf20Sopenharmony_ci *secid = sksec->sid; 52258c2ecf20Sopenharmony_ci } 52268c2ecf20Sopenharmony_ci} 52278c2ecf20Sopenharmony_ci 52288c2ecf20Sopenharmony_cistatic void selinux_sock_graft(struct sock *sk, struct socket *parent) 52298c2ecf20Sopenharmony_ci{ 52308c2ecf20Sopenharmony_ci struct inode_security_struct *isec = 52318c2ecf20Sopenharmony_ci inode_security_novalidate(SOCK_INODE(parent)); 52328c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 52338c2ecf20Sopenharmony_ci 52348c2ecf20Sopenharmony_ci if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 || 52358c2ecf20Sopenharmony_ci sk->sk_family == PF_UNIX) 52368c2ecf20Sopenharmony_ci isec->sid = sksec->sid; 52378c2ecf20Sopenharmony_ci sksec->sclass = isec->sclass; 52388c2ecf20Sopenharmony_ci} 52398c2ecf20Sopenharmony_ci 52408c2ecf20Sopenharmony_ci/* Called whenever SCTP receives an INIT chunk. This happens when an incoming 52418c2ecf20Sopenharmony_ci * connect(2), sctp_connectx(3) or sctp_sendmsg(3) (with no association 52428c2ecf20Sopenharmony_ci * already present). 52438c2ecf20Sopenharmony_ci */ 52448c2ecf20Sopenharmony_cistatic int selinux_sctp_assoc_request(struct sctp_endpoint *ep, 52458c2ecf20Sopenharmony_ci struct sk_buff *skb) 52468c2ecf20Sopenharmony_ci{ 52478c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = ep->base.sk->sk_security; 52488c2ecf20Sopenharmony_ci struct common_audit_data ad; 52498c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 52508c2ecf20Sopenharmony_ci u8 peerlbl_active; 52518c2ecf20Sopenharmony_ci u32 peer_sid = SECINITSID_UNLABELED; 52528c2ecf20Sopenharmony_ci u32 conn_sid; 52538c2ecf20Sopenharmony_ci int err = 0; 52548c2ecf20Sopenharmony_ci 52558c2ecf20Sopenharmony_ci if (!selinux_policycap_extsockclass()) 52568c2ecf20Sopenharmony_ci return 0; 52578c2ecf20Sopenharmony_ci 52588c2ecf20Sopenharmony_ci peerlbl_active = selinux_peerlbl_enabled(); 52598c2ecf20Sopenharmony_ci 52608c2ecf20Sopenharmony_ci if (peerlbl_active) { 52618c2ecf20Sopenharmony_ci /* This will return peer_sid = SECSID_NULL if there are 52628c2ecf20Sopenharmony_ci * no peer labels, see security_net_peersid_resolve(). 52638c2ecf20Sopenharmony_ci */ 52648c2ecf20Sopenharmony_ci err = selinux_skb_peerlbl_sid(skb, ep->base.sk->sk_family, 52658c2ecf20Sopenharmony_ci &peer_sid); 52668c2ecf20Sopenharmony_ci if (err) 52678c2ecf20Sopenharmony_ci return err; 52688c2ecf20Sopenharmony_ci 52698c2ecf20Sopenharmony_ci if (peer_sid == SECSID_NULL) 52708c2ecf20Sopenharmony_ci peer_sid = SECINITSID_UNLABELED; 52718c2ecf20Sopenharmony_ci } 52728c2ecf20Sopenharmony_ci 52738c2ecf20Sopenharmony_ci if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) { 52748c2ecf20Sopenharmony_ci sksec->sctp_assoc_state = SCTP_ASSOC_SET; 52758c2ecf20Sopenharmony_ci 52768c2ecf20Sopenharmony_ci /* Here as first association on socket. As the peer SID 52778c2ecf20Sopenharmony_ci * was allowed by peer recv (and the netif/node checks), 52788c2ecf20Sopenharmony_ci * then it is approved by policy and used as the primary 52798c2ecf20Sopenharmony_ci * peer SID for getpeercon(3). 52808c2ecf20Sopenharmony_ci */ 52818c2ecf20Sopenharmony_ci sksec->peer_sid = peer_sid; 52828c2ecf20Sopenharmony_ci } else if (sksec->peer_sid != peer_sid) { 52838c2ecf20Sopenharmony_ci /* Other association peer SIDs are checked to enforce 52848c2ecf20Sopenharmony_ci * consistency among the peer SIDs. 52858c2ecf20Sopenharmony_ci */ 52868c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 52878c2ecf20Sopenharmony_ci ad.u.net = &net; 52888c2ecf20Sopenharmony_ci ad.u.net->sk = ep->base.sk; 52898c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 52908c2ecf20Sopenharmony_ci sksec->peer_sid, peer_sid, sksec->sclass, 52918c2ecf20Sopenharmony_ci SCTP_SOCKET__ASSOCIATION, &ad); 52928c2ecf20Sopenharmony_ci if (err) 52938c2ecf20Sopenharmony_ci return err; 52948c2ecf20Sopenharmony_ci } 52958c2ecf20Sopenharmony_ci 52968c2ecf20Sopenharmony_ci /* Compute the MLS component for the connection and store 52978c2ecf20Sopenharmony_ci * the information in ep. This will be used by SCTP TCP type 52988c2ecf20Sopenharmony_ci * sockets and peeled off connections as they cause a new 52998c2ecf20Sopenharmony_ci * socket to be generated. selinux_sctp_sk_clone() will then 53008c2ecf20Sopenharmony_ci * plug this into the new socket. 53018c2ecf20Sopenharmony_ci */ 53028c2ecf20Sopenharmony_ci err = selinux_conn_sid(sksec->sid, peer_sid, &conn_sid); 53038c2ecf20Sopenharmony_ci if (err) 53048c2ecf20Sopenharmony_ci return err; 53058c2ecf20Sopenharmony_ci 53068c2ecf20Sopenharmony_ci ep->secid = conn_sid; 53078c2ecf20Sopenharmony_ci ep->peer_secid = peer_sid; 53088c2ecf20Sopenharmony_ci 53098c2ecf20Sopenharmony_ci /* Set any NetLabel labels including CIPSO/CALIPSO options. */ 53108c2ecf20Sopenharmony_ci return selinux_netlbl_sctp_assoc_request(ep, skb); 53118c2ecf20Sopenharmony_ci} 53128c2ecf20Sopenharmony_ci 53138c2ecf20Sopenharmony_ci/* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting 53148c2ecf20Sopenharmony_ci * based on their @optname. 53158c2ecf20Sopenharmony_ci */ 53168c2ecf20Sopenharmony_cistatic int selinux_sctp_bind_connect(struct sock *sk, int optname, 53178c2ecf20Sopenharmony_ci struct sockaddr *address, 53188c2ecf20Sopenharmony_ci int addrlen) 53198c2ecf20Sopenharmony_ci{ 53208c2ecf20Sopenharmony_ci int len, err = 0, walk_size = 0; 53218c2ecf20Sopenharmony_ci void *addr_buf; 53228c2ecf20Sopenharmony_ci struct sockaddr *addr; 53238c2ecf20Sopenharmony_ci struct socket *sock; 53248c2ecf20Sopenharmony_ci 53258c2ecf20Sopenharmony_ci if (!selinux_policycap_extsockclass()) 53268c2ecf20Sopenharmony_ci return 0; 53278c2ecf20Sopenharmony_ci 53288c2ecf20Sopenharmony_ci /* Process one or more addresses that may be IPv4 or IPv6 */ 53298c2ecf20Sopenharmony_ci sock = sk->sk_socket; 53308c2ecf20Sopenharmony_ci addr_buf = address; 53318c2ecf20Sopenharmony_ci 53328c2ecf20Sopenharmony_ci while (walk_size < addrlen) { 53338c2ecf20Sopenharmony_ci if (walk_size + sizeof(sa_family_t) > addrlen) 53348c2ecf20Sopenharmony_ci return -EINVAL; 53358c2ecf20Sopenharmony_ci 53368c2ecf20Sopenharmony_ci addr = addr_buf; 53378c2ecf20Sopenharmony_ci switch (addr->sa_family) { 53388c2ecf20Sopenharmony_ci case AF_UNSPEC: 53398c2ecf20Sopenharmony_ci case AF_INET: 53408c2ecf20Sopenharmony_ci len = sizeof(struct sockaddr_in); 53418c2ecf20Sopenharmony_ci break; 53428c2ecf20Sopenharmony_ci case AF_INET6: 53438c2ecf20Sopenharmony_ci len = sizeof(struct sockaddr_in6); 53448c2ecf20Sopenharmony_ci break; 53458c2ecf20Sopenharmony_ci default: 53468c2ecf20Sopenharmony_ci return -EINVAL; 53478c2ecf20Sopenharmony_ci } 53488c2ecf20Sopenharmony_ci 53498c2ecf20Sopenharmony_ci if (walk_size + len > addrlen) 53508c2ecf20Sopenharmony_ci return -EINVAL; 53518c2ecf20Sopenharmony_ci 53528c2ecf20Sopenharmony_ci err = -EINVAL; 53538c2ecf20Sopenharmony_ci switch (optname) { 53548c2ecf20Sopenharmony_ci /* Bind checks */ 53558c2ecf20Sopenharmony_ci case SCTP_PRIMARY_ADDR: 53568c2ecf20Sopenharmony_ci case SCTP_SET_PEER_PRIMARY_ADDR: 53578c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_BINDX_ADD: 53588c2ecf20Sopenharmony_ci err = selinux_socket_bind(sock, addr, len); 53598c2ecf20Sopenharmony_ci break; 53608c2ecf20Sopenharmony_ci /* Connect checks */ 53618c2ecf20Sopenharmony_ci case SCTP_SOCKOPT_CONNECTX: 53628c2ecf20Sopenharmony_ci case SCTP_PARAM_SET_PRIMARY: 53638c2ecf20Sopenharmony_ci case SCTP_PARAM_ADD_IP: 53648c2ecf20Sopenharmony_ci case SCTP_SENDMSG_CONNECT: 53658c2ecf20Sopenharmony_ci err = selinux_socket_connect_helper(sock, addr, len); 53668c2ecf20Sopenharmony_ci if (err) 53678c2ecf20Sopenharmony_ci return err; 53688c2ecf20Sopenharmony_ci 53698c2ecf20Sopenharmony_ci /* As selinux_sctp_bind_connect() is called by the 53708c2ecf20Sopenharmony_ci * SCTP protocol layer, the socket is already locked, 53718c2ecf20Sopenharmony_ci * therefore selinux_netlbl_socket_connect_locked() 53728c2ecf20Sopenharmony_ci * is called here. The situations handled are: 53738c2ecf20Sopenharmony_ci * sctp_connectx(3), sctp_sendmsg(3), sendmsg(2), 53748c2ecf20Sopenharmony_ci * whenever a new IP address is added or when a new 53758c2ecf20Sopenharmony_ci * primary address is selected. 53768c2ecf20Sopenharmony_ci * Note that an SCTP connect(2) call happens before 53778c2ecf20Sopenharmony_ci * the SCTP protocol layer and is handled via 53788c2ecf20Sopenharmony_ci * selinux_socket_connect(). 53798c2ecf20Sopenharmony_ci */ 53808c2ecf20Sopenharmony_ci err = selinux_netlbl_socket_connect_locked(sk, addr); 53818c2ecf20Sopenharmony_ci break; 53828c2ecf20Sopenharmony_ci } 53838c2ecf20Sopenharmony_ci 53848c2ecf20Sopenharmony_ci if (err) 53858c2ecf20Sopenharmony_ci return err; 53868c2ecf20Sopenharmony_ci 53878c2ecf20Sopenharmony_ci addr_buf += len; 53888c2ecf20Sopenharmony_ci walk_size += len; 53898c2ecf20Sopenharmony_ci } 53908c2ecf20Sopenharmony_ci 53918c2ecf20Sopenharmony_ci return 0; 53928c2ecf20Sopenharmony_ci} 53938c2ecf20Sopenharmony_ci 53948c2ecf20Sopenharmony_ci/* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */ 53958c2ecf20Sopenharmony_cistatic void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk, 53968c2ecf20Sopenharmony_ci struct sock *newsk) 53978c2ecf20Sopenharmony_ci{ 53988c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 53998c2ecf20Sopenharmony_ci struct sk_security_struct *newsksec = newsk->sk_security; 54008c2ecf20Sopenharmony_ci 54018c2ecf20Sopenharmony_ci /* If policy does not support SECCLASS_SCTP_SOCKET then call 54028c2ecf20Sopenharmony_ci * the non-sctp clone version. 54038c2ecf20Sopenharmony_ci */ 54048c2ecf20Sopenharmony_ci if (!selinux_policycap_extsockclass()) 54058c2ecf20Sopenharmony_ci return selinux_sk_clone_security(sk, newsk); 54068c2ecf20Sopenharmony_ci 54078c2ecf20Sopenharmony_ci newsksec->sid = ep->secid; 54088c2ecf20Sopenharmony_ci newsksec->peer_sid = ep->peer_secid; 54098c2ecf20Sopenharmony_ci newsksec->sclass = sksec->sclass; 54108c2ecf20Sopenharmony_ci selinux_netlbl_sctp_sk_clone(sk, newsk); 54118c2ecf20Sopenharmony_ci} 54128c2ecf20Sopenharmony_ci 54138c2ecf20Sopenharmony_cistatic int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb, 54148c2ecf20Sopenharmony_ci struct request_sock *req) 54158c2ecf20Sopenharmony_ci{ 54168c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 54178c2ecf20Sopenharmony_ci int err; 54188c2ecf20Sopenharmony_ci u16 family = req->rsk_ops->family; 54198c2ecf20Sopenharmony_ci u32 connsid; 54208c2ecf20Sopenharmony_ci u32 peersid; 54218c2ecf20Sopenharmony_ci 54228c2ecf20Sopenharmony_ci err = selinux_skb_peerlbl_sid(skb, family, &peersid); 54238c2ecf20Sopenharmony_ci if (err) 54248c2ecf20Sopenharmony_ci return err; 54258c2ecf20Sopenharmony_ci err = selinux_conn_sid(sksec->sid, peersid, &connsid); 54268c2ecf20Sopenharmony_ci if (err) 54278c2ecf20Sopenharmony_ci return err; 54288c2ecf20Sopenharmony_ci req->secid = connsid; 54298c2ecf20Sopenharmony_ci req->peer_secid = peersid; 54308c2ecf20Sopenharmony_ci 54318c2ecf20Sopenharmony_ci return selinux_netlbl_inet_conn_request(req, family); 54328c2ecf20Sopenharmony_ci} 54338c2ecf20Sopenharmony_ci 54348c2ecf20Sopenharmony_cistatic void selinux_inet_csk_clone(struct sock *newsk, 54358c2ecf20Sopenharmony_ci const struct request_sock *req) 54368c2ecf20Sopenharmony_ci{ 54378c2ecf20Sopenharmony_ci struct sk_security_struct *newsksec = newsk->sk_security; 54388c2ecf20Sopenharmony_ci 54398c2ecf20Sopenharmony_ci newsksec->sid = req->secid; 54408c2ecf20Sopenharmony_ci newsksec->peer_sid = req->peer_secid; 54418c2ecf20Sopenharmony_ci /* NOTE: Ideally, we should also get the isec->sid for the 54428c2ecf20Sopenharmony_ci new socket in sync, but we don't have the isec available yet. 54438c2ecf20Sopenharmony_ci So we will wait until sock_graft to do it, by which 54448c2ecf20Sopenharmony_ci time it will have been created and available. */ 54458c2ecf20Sopenharmony_ci 54468c2ecf20Sopenharmony_ci /* We don't need to take any sort of lock here as we are the only 54478c2ecf20Sopenharmony_ci * thread with access to newsksec */ 54488c2ecf20Sopenharmony_ci selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family); 54498c2ecf20Sopenharmony_ci} 54508c2ecf20Sopenharmony_ci 54518c2ecf20Sopenharmony_cistatic void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb) 54528c2ecf20Sopenharmony_ci{ 54538c2ecf20Sopenharmony_ci u16 family = sk->sk_family; 54548c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 54558c2ecf20Sopenharmony_ci 54568c2ecf20Sopenharmony_ci /* handle mapped IPv4 packets arriving via IPv6 sockets */ 54578c2ecf20Sopenharmony_ci if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP)) 54588c2ecf20Sopenharmony_ci family = PF_INET; 54598c2ecf20Sopenharmony_ci 54608c2ecf20Sopenharmony_ci selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid); 54618c2ecf20Sopenharmony_ci} 54628c2ecf20Sopenharmony_ci 54638c2ecf20Sopenharmony_cistatic int selinux_secmark_relabel_packet(u32 sid) 54648c2ecf20Sopenharmony_ci{ 54658c2ecf20Sopenharmony_ci const struct task_security_struct *__tsec; 54668c2ecf20Sopenharmony_ci u32 tsid; 54678c2ecf20Sopenharmony_ci 54688c2ecf20Sopenharmony_ci __tsec = selinux_cred(current_cred()); 54698c2ecf20Sopenharmony_ci tsid = __tsec->sid; 54708c2ecf20Sopenharmony_ci 54718c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 54728c2ecf20Sopenharmony_ci tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO, 54738c2ecf20Sopenharmony_ci NULL); 54748c2ecf20Sopenharmony_ci} 54758c2ecf20Sopenharmony_ci 54768c2ecf20Sopenharmony_cistatic void selinux_secmark_refcount_inc(void) 54778c2ecf20Sopenharmony_ci{ 54788c2ecf20Sopenharmony_ci atomic_inc(&selinux_secmark_refcount); 54798c2ecf20Sopenharmony_ci} 54808c2ecf20Sopenharmony_ci 54818c2ecf20Sopenharmony_cistatic void selinux_secmark_refcount_dec(void) 54828c2ecf20Sopenharmony_ci{ 54838c2ecf20Sopenharmony_ci atomic_dec(&selinux_secmark_refcount); 54848c2ecf20Sopenharmony_ci} 54858c2ecf20Sopenharmony_ci 54868c2ecf20Sopenharmony_cistatic void selinux_req_classify_flow(const struct request_sock *req, 54878c2ecf20Sopenharmony_ci struct flowi_common *flic) 54888c2ecf20Sopenharmony_ci{ 54898c2ecf20Sopenharmony_ci flic->flowic_secid = req->secid; 54908c2ecf20Sopenharmony_ci} 54918c2ecf20Sopenharmony_ci 54928c2ecf20Sopenharmony_cistatic int selinux_tun_dev_alloc_security(void **security) 54938c2ecf20Sopenharmony_ci{ 54948c2ecf20Sopenharmony_ci struct tun_security_struct *tunsec; 54958c2ecf20Sopenharmony_ci 54968c2ecf20Sopenharmony_ci tunsec = kzalloc(sizeof(*tunsec), GFP_KERNEL); 54978c2ecf20Sopenharmony_ci if (!tunsec) 54988c2ecf20Sopenharmony_ci return -ENOMEM; 54998c2ecf20Sopenharmony_ci tunsec->sid = current_sid(); 55008c2ecf20Sopenharmony_ci 55018c2ecf20Sopenharmony_ci *security = tunsec; 55028c2ecf20Sopenharmony_ci return 0; 55038c2ecf20Sopenharmony_ci} 55048c2ecf20Sopenharmony_ci 55058c2ecf20Sopenharmony_cistatic void selinux_tun_dev_free_security(void *security) 55068c2ecf20Sopenharmony_ci{ 55078c2ecf20Sopenharmony_ci kfree(security); 55088c2ecf20Sopenharmony_ci} 55098c2ecf20Sopenharmony_ci 55108c2ecf20Sopenharmony_cistatic int selinux_tun_dev_create(void) 55118c2ecf20Sopenharmony_ci{ 55128c2ecf20Sopenharmony_ci u32 sid = current_sid(); 55138c2ecf20Sopenharmony_ci 55148c2ecf20Sopenharmony_ci /* we aren't taking into account the "sockcreate" SID since the socket 55158c2ecf20Sopenharmony_ci * that is being created here is not a socket in the traditional sense, 55168c2ecf20Sopenharmony_ci * instead it is a private sock, accessible only to the kernel, and 55178c2ecf20Sopenharmony_ci * representing a wide range of network traffic spanning multiple 55188c2ecf20Sopenharmony_ci * connections unlike traditional sockets - check the TUN driver to 55198c2ecf20Sopenharmony_ci * get a better understanding of why this socket is special */ 55208c2ecf20Sopenharmony_ci 55218c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 55228c2ecf20Sopenharmony_ci sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE, 55238c2ecf20Sopenharmony_ci NULL); 55248c2ecf20Sopenharmony_ci} 55258c2ecf20Sopenharmony_ci 55268c2ecf20Sopenharmony_cistatic int selinux_tun_dev_attach_queue(void *security) 55278c2ecf20Sopenharmony_ci{ 55288c2ecf20Sopenharmony_ci struct tun_security_struct *tunsec = security; 55298c2ecf20Sopenharmony_ci 55308c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 55318c2ecf20Sopenharmony_ci current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET, 55328c2ecf20Sopenharmony_ci TUN_SOCKET__ATTACH_QUEUE, NULL); 55338c2ecf20Sopenharmony_ci} 55348c2ecf20Sopenharmony_ci 55358c2ecf20Sopenharmony_cistatic int selinux_tun_dev_attach(struct sock *sk, void *security) 55368c2ecf20Sopenharmony_ci{ 55378c2ecf20Sopenharmony_ci struct tun_security_struct *tunsec = security; 55388c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 55398c2ecf20Sopenharmony_ci 55408c2ecf20Sopenharmony_ci /* we don't currently perform any NetLabel based labeling here and it 55418c2ecf20Sopenharmony_ci * isn't clear that we would want to do so anyway; while we could apply 55428c2ecf20Sopenharmony_ci * labeling without the support of the TUN user the resulting labeled 55438c2ecf20Sopenharmony_ci * traffic from the other end of the connection would almost certainly 55448c2ecf20Sopenharmony_ci * cause confusion to the TUN user that had no idea network labeling 55458c2ecf20Sopenharmony_ci * protocols were being used */ 55468c2ecf20Sopenharmony_ci 55478c2ecf20Sopenharmony_ci sksec->sid = tunsec->sid; 55488c2ecf20Sopenharmony_ci sksec->sclass = SECCLASS_TUN_SOCKET; 55498c2ecf20Sopenharmony_ci 55508c2ecf20Sopenharmony_ci return 0; 55518c2ecf20Sopenharmony_ci} 55528c2ecf20Sopenharmony_ci 55538c2ecf20Sopenharmony_cistatic int selinux_tun_dev_open(void *security) 55548c2ecf20Sopenharmony_ci{ 55558c2ecf20Sopenharmony_ci struct tun_security_struct *tunsec = security; 55568c2ecf20Sopenharmony_ci u32 sid = current_sid(); 55578c2ecf20Sopenharmony_ci int err; 55588c2ecf20Sopenharmony_ci 55598c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 55608c2ecf20Sopenharmony_ci sid, tunsec->sid, SECCLASS_TUN_SOCKET, 55618c2ecf20Sopenharmony_ci TUN_SOCKET__RELABELFROM, NULL); 55628c2ecf20Sopenharmony_ci if (err) 55638c2ecf20Sopenharmony_ci return err; 55648c2ecf20Sopenharmony_ci err = avc_has_perm(&selinux_state, 55658c2ecf20Sopenharmony_ci sid, sid, SECCLASS_TUN_SOCKET, 55668c2ecf20Sopenharmony_ci TUN_SOCKET__RELABELTO, NULL); 55678c2ecf20Sopenharmony_ci if (err) 55688c2ecf20Sopenharmony_ci return err; 55698c2ecf20Sopenharmony_ci tunsec->sid = sid; 55708c2ecf20Sopenharmony_ci 55718c2ecf20Sopenharmony_ci return 0; 55728c2ecf20Sopenharmony_ci} 55738c2ecf20Sopenharmony_ci 55748c2ecf20Sopenharmony_ci#ifdef CONFIG_NETFILTER 55758c2ecf20Sopenharmony_ci 55768c2ecf20Sopenharmony_cistatic unsigned int selinux_ip_forward(struct sk_buff *skb, 55778c2ecf20Sopenharmony_ci const struct net_device *indev, 55788c2ecf20Sopenharmony_ci u16 family) 55798c2ecf20Sopenharmony_ci{ 55808c2ecf20Sopenharmony_ci int err; 55818c2ecf20Sopenharmony_ci char *addrp; 55828c2ecf20Sopenharmony_ci u32 peer_sid; 55838c2ecf20Sopenharmony_ci struct common_audit_data ad; 55848c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 55858c2ecf20Sopenharmony_ci u8 secmark_active; 55868c2ecf20Sopenharmony_ci u8 netlbl_active; 55878c2ecf20Sopenharmony_ci u8 peerlbl_active; 55888c2ecf20Sopenharmony_ci 55898c2ecf20Sopenharmony_ci if (!selinux_policycap_netpeer()) 55908c2ecf20Sopenharmony_ci return NF_ACCEPT; 55918c2ecf20Sopenharmony_ci 55928c2ecf20Sopenharmony_ci secmark_active = selinux_secmark_enabled(); 55938c2ecf20Sopenharmony_ci netlbl_active = netlbl_enabled(); 55948c2ecf20Sopenharmony_ci peerlbl_active = selinux_peerlbl_enabled(); 55958c2ecf20Sopenharmony_ci if (!secmark_active && !peerlbl_active) 55968c2ecf20Sopenharmony_ci return NF_ACCEPT; 55978c2ecf20Sopenharmony_ci 55988c2ecf20Sopenharmony_ci if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) 55998c2ecf20Sopenharmony_ci return NF_DROP; 56008c2ecf20Sopenharmony_ci 56018c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 56028c2ecf20Sopenharmony_ci ad.u.net = &net; 56038c2ecf20Sopenharmony_ci ad.u.net->netif = indev->ifindex; 56048c2ecf20Sopenharmony_ci ad.u.net->family = family; 56058c2ecf20Sopenharmony_ci if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0) 56068c2ecf20Sopenharmony_ci return NF_DROP; 56078c2ecf20Sopenharmony_ci 56088c2ecf20Sopenharmony_ci if (peerlbl_active) { 56098c2ecf20Sopenharmony_ci err = selinux_inet_sys_rcv_skb(dev_net(indev), indev->ifindex, 56108c2ecf20Sopenharmony_ci addrp, family, peer_sid, &ad); 56118c2ecf20Sopenharmony_ci if (err) { 56128c2ecf20Sopenharmony_ci selinux_netlbl_err(skb, family, err, 1); 56138c2ecf20Sopenharmony_ci return NF_DROP; 56148c2ecf20Sopenharmony_ci } 56158c2ecf20Sopenharmony_ci } 56168c2ecf20Sopenharmony_ci 56178c2ecf20Sopenharmony_ci if (secmark_active) 56188c2ecf20Sopenharmony_ci if (avc_has_perm(&selinux_state, 56198c2ecf20Sopenharmony_ci peer_sid, skb->secmark, 56208c2ecf20Sopenharmony_ci SECCLASS_PACKET, PACKET__FORWARD_IN, &ad)) 56218c2ecf20Sopenharmony_ci return NF_DROP; 56228c2ecf20Sopenharmony_ci 56238c2ecf20Sopenharmony_ci if (netlbl_active) 56248c2ecf20Sopenharmony_ci /* we do this in the FORWARD path and not the POST_ROUTING 56258c2ecf20Sopenharmony_ci * path because we want to make sure we apply the necessary 56268c2ecf20Sopenharmony_ci * labeling before IPsec is applied so we can leverage AH 56278c2ecf20Sopenharmony_ci * protection */ 56288c2ecf20Sopenharmony_ci if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0) 56298c2ecf20Sopenharmony_ci return NF_DROP; 56308c2ecf20Sopenharmony_ci 56318c2ecf20Sopenharmony_ci return NF_ACCEPT; 56328c2ecf20Sopenharmony_ci} 56338c2ecf20Sopenharmony_ci 56348c2ecf20Sopenharmony_cistatic unsigned int selinux_ipv4_forward(void *priv, 56358c2ecf20Sopenharmony_ci struct sk_buff *skb, 56368c2ecf20Sopenharmony_ci const struct nf_hook_state *state) 56378c2ecf20Sopenharmony_ci{ 56388c2ecf20Sopenharmony_ci return selinux_ip_forward(skb, state->in, PF_INET); 56398c2ecf20Sopenharmony_ci} 56408c2ecf20Sopenharmony_ci 56418c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 56428c2ecf20Sopenharmony_cistatic unsigned int selinux_ipv6_forward(void *priv, 56438c2ecf20Sopenharmony_ci struct sk_buff *skb, 56448c2ecf20Sopenharmony_ci const struct nf_hook_state *state) 56458c2ecf20Sopenharmony_ci{ 56468c2ecf20Sopenharmony_ci return selinux_ip_forward(skb, state->in, PF_INET6); 56478c2ecf20Sopenharmony_ci} 56488c2ecf20Sopenharmony_ci#endif /* IPV6 */ 56498c2ecf20Sopenharmony_ci 56508c2ecf20Sopenharmony_cistatic unsigned int selinux_ip_output(struct sk_buff *skb, 56518c2ecf20Sopenharmony_ci u16 family) 56528c2ecf20Sopenharmony_ci{ 56538c2ecf20Sopenharmony_ci struct sock *sk; 56548c2ecf20Sopenharmony_ci u32 sid; 56558c2ecf20Sopenharmony_ci 56568c2ecf20Sopenharmony_ci if (!netlbl_enabled()) 56578c2ecf20Sopenharmony_ci return NF_ACCEPT; 56588c2ecf20Sopenharmony_ci 56598c2ecf20Sopenharmony_ci /* we do this in the LOCAL_OUT path and not the POST_ROUTING path 56608c2ecf20Sopenharmony_ci * because we want to make sure we apply the necessary labeling 56618c2ecf20Sopenharmony_ci * before IPsec is applied so we can leverage AH protection */ 56628c2ecf20Sopenharmony_ci sk = skb->sk; 56638c2ecf20Sopenharmony_ci if (sk) { 56648c2ecf20Sopenharmony_ci struct sk_security_struct *sksec; 56658c2ecf20Sopenharmony_ci 56668c2ecf20Sopenharmony_ci if (sk_listener(sk)) 56678c2ecf20Sopenharmony_ci /* if the socket is the listening state then this 56688c2ecf20Sopenharmony_ci * packet is a SYN-ACK packet which means it needs to 56698c2ecf20Sopenharmony_ci * be labeled based on the connection/request_sock and 56708c2ecf20Sopenharmony_ci * not the parent socket. unfortunately, we can't 56718c2ecf20Sopenharmony_ci * lookup the request_sock yet as it isn't queued on 56728c2ecf20Sopenharmony_ci * the parent socket until after the SYN-ACK is sent. 56738c2ecf20Sopenharmony_ci * the "solution" is to simply pass the packet as-is 56748c2ecf20Sopenharmony_ci * as any IP option based labeling should be copied 56758c2ecf20Sopenharmony_ci * from the initial connection request (in the IP 56768c2ecf20Sopenharmony_ci * layer). it is far from ideal, but until we get a 56778c2ecf20Sopenharmony_ci * security label in the packet itself this is the 56788c2ecf20Sopenharmony_ci * best we can do. */ 56798c2ecf20Sopenharmony_ci return NF_ACCEPT; 56808c2ecf20Sopenharmony_ci 56818c2ecf20Sopenharmony_ci /* standard practice, label using the parent socket */ 56828c2ecf20Sopenharmony_ci sksec = sk->sk_security; 56838c2ecf20Sopenharmony_ci sid = sksec->sid; 56848c2ecf20Sopenharmony_ci } else 56858c2ecf20Sopenharmony_ci sid = SECINITSID_KERNEL; 56868c2ecf20Sopenharmony_ci if (selinux_netlbl_skbuff_setsid(skb, family, sid) != 0) 56878c2ecf20Sopenharmony_ci return NF_DROP; 56888c2ecf20Sopenharmony_ci 56898c2ecf20Sopenharmony_ci return NF_ACCEPT; 56908c2ecf20Sopenharmony_ci} 56918c2ecf20Sopenharmony_ci 56928c2ecf20Sopenharmony_cistatic unsigned int selinux_ipv4_output(void *priv, 56938c2ecf20Sopenharmony_ci struct sk_buff *skb, 56948c2ecf20Sopenharmony_ci const struct nf_hook_state *state) 56958c2ecf20Sopenharmony_ci{ 56968c2ecf20Sopenharmony_ci return selinux_ip_output(skb, PF_INET); 56978c2ecf20Sopenharmony_ci} 56988c2ecf20Sopenharmony_ci 56998c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 57008c2ecf20Sopenharmony_cistatic unsigned int selinux_ipv6_output(void *priv, 57018c2ecf20Sopenharmony_ci struct sk_buff *skb, 57028c2ecf20Sopenharmony_ci const struct nf_hook_state *state) 57038c2ecf20Sopenharmony_ci{ 57048c2ecf20Sopenharmony_ci return selinux_ip_output(skb, PF_INET6); 57058c2ecf20Sopenharmony_ci} 57068c2ecf20Sopenharmony_ci#endif /* IPV6 */ 57078c2ecf20Sopenharmony_ci 57088c2ecf20Sopenharmony_cistatic unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, 57098c2ecf20Sopenharmony_ci int ifindex, 57108c2ecf20Sopenharmony_ci u16 family) 57118c2ecf20Sopenharmony_ci{ 57128c2ecf20Sopenharmony_ci struct sock *sk = skb_to_full_sk(skb); 57138c2ecf20Sopenharmony_ci struct sk_security_struct *sksec; 57148c2ecf20Sopenharmony_ci struct common_audit_data ad; 57158c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 57168c2ecf20Sopenharmony_ci char *addrp; 57178c2ecf20Sopenharmony_ci u8 proto = 0; 57188c2ecf20Sopenharmony_ci 57198c2ecf20Sopenharmony_ci if (sk == NULL) 57208c2ecf20Sopenharmony_ci return NF_ACCEPT; 57218c2ecf20Sopenharmony_ci sksec = sk->sk_security; 57228c2ecf20Sopenharmony_ci 57238c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 57248c2ecf20Sopenharmony_ci ad.u.net = &net; 57258c2ecf20Sopenharmony_ci ad.u.net->netif = ifindex; 57268c2ecf20Sopenharmony_ci ad.u.net->family = family; 57278c2ecf20Sopenharmony_ci if (selinux_parse_skb(skb, &ad, &addrp, 0, &proto)) 57288c2ecf20Sopenharmony_ci return NF_DROP; 57298c2ecf20Sopenharmony_ci 57308c2ecf20Sopenharmony_ci if (selinux_secmark_enabled()) 57318c2ecf20Sopenharmony_ci if (avc_has_perm(&selinux_state, 57328c2ecf20Sopenharmony_ci sksec->sid, skb->secmark, 57338c2ecf20Sopenharmony_ci SECCLASS_PACKET, PACKET__SEND, &ad)) 57348c2ecf20Sopenharmony_ci return NF_DROP_ERR(-ECONNREFUSED); 57358c2ecf20Sopenharmony_ci 57368c2ecf20Sopenharmony_ci if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto)) 57378c2ecf20Sopenharmony_ci return NF_DROP_ERR(-ECONNREFUSED); 57388c2ecf20Sopenharmony_ci 57398c2ecf20Sopenharmony_ci return NF_ACCEPT; 57408c2ecf20Sopenharmony_ci} 57418c2ecf20Sopenharmony_ci 57428c2ecf20Sopenharmony_cistatic unsigned int selinux_ip_postroute(struct sk_buff *skb, 57438c2ecf20Sopenharmony_ci const struct net_device *outdev, 57448c2ecf20Sopenharmony_ci u16 family) 57458c2ecf20Sopenharmony_ci{ 57468c2ecf20Sopenharmony_ci u32 secmark_perm; 57478c2ecf20Sopenharmony_ci u32 peer_sid; 57488c2ecf20Sopenharmony_ci int ifindex = outdev->ifindex; 57498c2ecf20Sopenharmony_ci struct sock *sk; 57508c2ecf20Sopenharmony_ci struct common_audit_data ad; 57518c2ecf20Sopenharmony_ci struct lsm_network_audit net = {0,}; 57528c2ecf20Sopenharmony_ci char *addrp; 57538c2ecf20Sopenharmony_ci u8 secmark_active; 57548c2ecf20Sopenharmony_ci u8 peerlbl_active; 57558c2ecf20Sopenharmony_ci 57568c2ecf20Sopenharmony_ci /* If any sort of compatibility mode is enabled then handoff processing 57578c2ecf20Sopenharmony_ci * to the selinux_ip_postroute_compat() function to deal with the 57588c2ecf20Sopenharmony_ci * special handling. We do this in an attempt to keep this function 57598c2ecf20Sopenharmony_ci * as fast and as clean as possible. */ 57608c2ecf20Sopenharmony_ci if (!selinux_policycap_netpeer()) 57618c2ecf20Sopenharmony_ci return selinux_ip_postroute_compat(skb, ifindex, family); 57628c2ecf20Sopenharmony_ci 57638c2ecf20Sopenharmony_ci secmark_active = selinux_secmark_enabled(); 57648c2ecf20Sopenharmony_ci peerlbl_active = selinux_peerlbl_enabled(); 57658c2ecf20Sopenharmony_ci if (!secmark_active && !peerlbl_active) 57668c2ecf20Sopenharmony_ci return NF_ACCEPT; 57678c2ecf20Sopenharmony_ci 57688c2ecf20Sopenharmony_ci sk = skb_to_full_sk(skb); 57698c2ecf20Sopenharmony_ci 57708c2ecf20Sopenharmony_ci#ifdef CONFIG_XFRM 57718c2ecf20Sopenharmony_ci /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec 57728c2ecf20Sopenharmony_ci * packet transformation so allow the packet to pass without any checks 57738c2ecf20Sopenharmony_ci * since we'll have another chance to perform access control checks 57748c2ecf20Sopenharmony_ci * when the packet is on it's final way out. 57758c2ecf20Sopenharmony_ci * NOTE: there appear to be some IPv6 multicast cases where skb->dst 57768c2ecf20Sopenharmony_ci * is NULL, in this case go ahead and apply access control. 57778c2ecf20Sopenharmony_ci * NOTE: if this is a local socket (skb->sk != NULL) that is in the 57788c2ecf20Sopenharmony_ci * TCP listening state we cannot wait until the XFRM processing 57798c2ecf20Sopenharmony_ci * is done as we will miss out on the SA label if we do; 57808c2ecf20Sopenharmony_ci * unfortunately, this means more work, but it is only once per 57818c2ecf20Sopenharmony_ci * connection. */ 57828c2ecf20Sopenharmony_ci if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL && 57838c2ecf20Sopenharmony_ci !(sk && sk_listener(sk))) 57848c2ecf20Sopenharmony_ci return NF_ACCEPT; 57858c2ecf20Sopenharmony_ci#endif 57868c2ecf20Sopenharmony_ci 57878c2ecf20Sopenharmony_ci if (sk == NULL) { 57888c2ecf20Sopenharmony_ci /* Without an associated socket the packet is either coming 57898c2ecf20Sopenharmony_ci * from the kernel or it is being forwarded; check the packet 57908c2ecf20Sopenharmony_ci * to determine which and if the packet is being forwarded 57918c2ecf20Sopenharmony_ci * query the packet directly to determine the security label. */ 57928c2ecf20Sopenharmony_ci if (skb->skb_iif) { 57938c2ecf20Sopenharmony_ci secmark_perm = PACKET__FORWARD_OUT; 57948c2ecf20Sopenharmony_ci if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) 57958c2ecf20Sopenharmony_ci return NF_DROP; 57968c2ecf20Sopenharmony_ci } else { 57978c2ecf20Sopenharmony_ci secmark_perm = PACKET__SEND; 57988c2ecf20Sopenharmony_ci peer_sid = SECINITSID_KERNEL; 57998c2ecf20Sopenharmony_ci } 58008c2ecf20Sopenharmony_ci } else if (sk_listener(sk)) { 58018c2ecf20Sopenharmony_ci /* Locally generated packet but the associated socket is in the 58028c2ecf20Sopenharmony_ci * listening state which means this is a SYN-ACK packet. In 58038c2ecf20Sopenharmony_ci * this particular case the correct security label is assigned 58048c2ecf20Sopenharmony_ci * to the connection/request_sock but unfortunately we can't 58058c2ecf20Sopenharmony_ci * query the request_sock as it isn't queued on the parent 58068c2ecf20Sopenharmony_ci * socket until after the SYN-ACK packet is sent; the only 58078c2ecf20Sopenharmony_ci * viable choice is to regenerate the label like we do in 58088c2ecf20Sopenharmony_ci * selinux_inet_conn_request(). See also selinux_ip_output() 58098c2ecf20Sopenharmony_ci * for similar problems. */ 58108c2ecf20Sopenharmony_ci u32 skb_sid; 58118c2ecf20Sopenharmony_ci struct sk_security_struct *sksec; 58128c2ecf20Sopenharmony_ci 58138c2ecf20Sopenharmony_ci sksec = sk->sk_security; 58148c2ecf20Sopenharmony_ci if (selinux_skb_peerlbl_sid(skb, family, &skb_sid)) 58158c2ecf20Sopenharmony_ci return NF_DROP; 58168c2ecf20Sopenharmony_ci /* At this point, if the returned skb peerlbl is SECSID_NULL 58178c2ecf20Sopenharmony_ci * and the packet has been through at least one XFRM 58188c2ecf20Sopenharmony_ci * transformation then we must be dealing with the "final" 58198c2ecf20Sopenharmony_ci * form of labeled IPsec packet; since we've already applied 58208c2ecf20Sopenharmony_ci * all of our access controls on this packet we can safely 58218c2ecf20Sopenharmony_ci * pass the packet. */ 58228c2ecf20Sopenharmony_ci if (skb_sid == SECSID_NULL) { 58238c2ecf20Sopenharmony_ci switch (family) { 58248c2ecf20Sopenharmony_ci case PF_INET: 58258c2ecf20Sopenharmony_ci if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) 58268c2ecf20Sopenharmony_ci return NF_ACCEPT; 58278c2ecf20Sopenharmony_ci break; 58288c2ecf20Sopenharmony_ci case PF_INET6: 58298c2ecf20Sopenharmony_ci if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) 58308c2ecf20Sopenharmony_ci return NF_ACCEPT; 58318c2ecf20Sopenharmony_ci break; 58328c2ecf20Sopenharmony_ci default: 58338c2ecf20Sopenharmony_ci return NF_DROP_ERR(-ECONNREFUSED); 58348c2ecf20Sopenharmony_ci } 58358c2ecf20Sopenharmony_ci } 58368c2ecf20Sopenharmony_ci if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid)) 58378c2ecf20Sopenharmony_ci return NF_DROP; 58388c2ecf20Sopenharmony_ci secmark_perm = PACKET__SEND; 58398c2ecf20Sopenharmony_ci } else { 58408c2ecf20Sopenharmony_ci /* Locally generated packet, fetch the security label from the 58418c2ecf20Sopenharmony_ci * associated socket. */ 58428c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 58438c2ecf20Sopenharmony_ci peer_sid = sksec->sid; 58448c2ecf20Sopenharmony_ci secmark_perm = PACKET__SEND; 58458c2ecf20Sopenharmony_ci } 58468c2ecf20Sopenharmony_ci 58478c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_NET; 58488c2ecf20Sopenharmony_ci ad.u.net = &net; 58498c2ecf20Sopenharmony_ci ad.u.net->netif = ifindex; 58508c2ecf20Sopenharmony_ci ad.u.net->family = family; 58518c2ecf20Sopenharmony_ci if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL)) 58528c2ecf20Sopenharmony_ci return NF_DROP; 58538c2ecf20Sopenharmony_ci 58548c2ecf20Sopenharmony_ci if (secmark_active) 58558c2ecf20Sopenharmony_ci if (avc_has_perm(&selinux_state, 58568c2ecf20Sopenharmony_ci peer_sid, skb->secmark, 58578c2ecf20Sopenharmony_ci SECCLASS_PACKET, secmark_perm, &ad)) 58588c2ecf20Sopenharmony_ci return NF_DROP_ERR(-ECONNREFUSED); 58598c2ecf20Sopenharmony_ci 58608c2ecf20Sopenharmony_ci if (peerlbl_active) { 58618c2ecf20Sopenharmony_ci u32 if_sid; 58628c2ecf20Sopenharmony_ci u32 node_sid; 58638c2ecf20Sopenharmony_ci 58648c2ecf20Sopenharmony_ci if (sel_netif_sid(dev_net(outdev), ifindex, &if_sid)) 58658c2ecf20Sopenharmony_ci return NF_DROP; 58668c2ecf20Sopenharmony_ci if (avc_has_perm(&selinux_state, 58678c2ecf20Sopenharmony_ci peer_sid, if_sid, 58688c2ecf20Sopenharmony_ci SECCLASS_NETIF, NETIF__EGRESS, &ad)) 58698c2ecf20Sopenharmony_ci return NF_DROP_ERR(-ECONNREFUSED); 58708c2ecf20Sopenharmony_ci 58718c2ecf20Sopenharmony_ci if (sel_netnode_sid(addrp, family, &node_sid)) 58728c2ecf20Sopenharmony_ci return NF_DROP; 58738c2ecf20Sopenharmony_ci if (avc_has_perm(&selinux_state, 58748c2ecf20Sopenharmony_ci peer_sid, node_sid, 58758c2ecf20Sopenharmony_ci SECCLASS_NODE, NODE__SENDTO, &ad)) 58768c2ecf20Sopenharmony_ci return NF_DROP_ERR(-ECONNREFUSED); 58778c2ecf20Sopenharmony_ci } 58788c2ecf20Sopenharmony_ci 58798c2ecf20Sopenharmony_ci return NF_ACCEPT; 58808c2ecf20Sopenharmony_ci} 58818c2ecf20Sopenharmony_ci 58828c2ecf20Sopenharmony_cistatic unsigned int selinux_ipv4_postroute(void *priv, 58838c2ecf20Sopenharmony_ci struct sk_buff *skb, 58848c2ecf20Sopenharmony_ci const struct nf_hook_state *state) 58858c2ecf20Sopenharmony_ci{ 58868c2ecf20Sopenharmony_ci return selinux_ip_postroute(skb, state->out, PF_INET); 58878c2ecf20Sopenharmony_ci} 58888c2ecf20Sopenharmony_ci 58898c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 58908c2ecf20Sopenharmony_cistatic unsigned int selinux_ipv6_postroute(void *priv, 58918c2ecf20Sopenharmony_ci struct sk_buff *skb, 58928c2ecf20Sopenharmony_ci const struct nf_hook_state *state) 58938c2ecf20Sopenharmony_ci{ 58948c2ecf20Sopenharmony_ci return selinux_ip_postroute(skb, state->out, PF_INET6); 58958c2ecf20Sopenharmony_ci} 58968c2ecf20Sopenharmony_ci#endif /* IPV6 */ 58978c2ecf20Sopenharmony_ci 58988c2ecf20Sopenharmony_ci#endif /* CONFIG_NETFILTER */ 58998c2ecf20Sopenharmony_ci 59008c2ecf20Sopenharmony_cistatic int selinux_netlink_send(struct sock *sk, struct sk_buff *skb) 59018c2ecf20Sopenharmony_ci{ 59028c2ecf20Sopenharmony_ci int rc = 0; 59038c2ecf20Sopenharmony_ci unsigned int msg_len; 59048c2ecf20Sopenharmony_ci unsigned int data_len = skb->len; 59058c2ecf20Sopenharmony_ci unsigned char *data = skb->data; 59068c2ecf20Sopenharmony_ci struct nlmsghdr *nlh; 59078c2ecf20Sopenharmony_ci struct sk_security_struct *sksec = sk->sk_security; 59088c2ecf20Sopenharmony_ci u16 sclass = sksec->sclass; 59098c2ecf20Sopenharmony_ci u32 perm; 59108c2ecf20Sopenharmony_ci 59118c2ecf20Sopenharmony_ci while (data_len >= nlmsg_total_size(0)) { 59128c2ecf20Sopenharmony_ci nlh = (struct nlmsghdr *)data; 59138c2ecf20Sopenharmony_ci 59148c2ecf20Sopenharmony_ci /* NOTE: the nlmsg_len field isn't reliably set by some netlink 59158c2ecf20Sopenharmony_ci * users which means we can't reject skb's with bogus 59168c2ecf20Sopenharmony_ci * length fields; our solution is to follow what 59178c2ecf20Sopenharmony_ci * netlink_rcv_skb() does and simply skip processing at 59188c2ecf20Sopenharmony_ci * messages with length fields that are clearly junk 59198c2ecf20Sopenharmony_ci */ 59208c2ecf20Sopenharmony_ci if (nlh->nlmsg_len < NLMSG_HDRLEN || nlh->nlmsg_len > data_len) 59218c2ecf20Sopenharmony_ci return 0; 59228c2ecf20Sopenharmony_ci 59238c2ecf20Sopenharmony_ci rc = selinux_nlmsg_lookup(sclass, nlh->nlmsg_type, &perm); 59248c2ecf20Sopenharmony_ci if (rc == 0) { 59258c2ecf20Sopenharmony_ci rc = sock_has_perm(sk, perm); 59268c2ecf20Sopenharmony_ci if (rc) 59278c2ecf20Sopenharmony_ci return rc; 59288c2ecf20Sopenharmony_ci } else if (rc == -EINVAL) { 59298c2ecf20Sopenharmony_ci /* -EINVAL is a missing msg/perm mapping */ 59308c2ecf20Sopenharmony_ci pr_warn_ratelimited("SELinux: unrecognized netlink" 59318c2ecf20Sopenharmony_ci " message: protocol=%hu nlmsg_type=%hu sclass=%s" 59328c2ecf20Sopenharmony_ci " pid=%d comm=%s\n", 59338c2ecf20Sopenharmony_ci sk->sk_protocol, nlh->nlmsg_type, 59348c2ecf20Sopenharmony_ci secclass_map[sclass - 1].name, 59358c2ecf20Sopenharmony_ci task_pid_nr(current), current->comm); 59368c2ecf20Sopenharmony_ci if (enforcing_enabled(&selinux_state) && 59378c2ecf20Sopenharmony_ci !security_get_allow_unknown(&selinux_state)) 59388c2ecf20Sopenharmony_ci return rc; 59398c2ecf20Sopenharmony_ci rc = 0; 59408c2ecf20Sopenharmony_ci } else if (rc == -ENOENT) { 59418c2ecf20Sopenharmony_ci /* -ENOENT is a missing socket/class mapping, ignore */ 59428c2ecf20Sopenharmony_ci rc = 0; 59438c2ecf20Sopenharmony_ci } else { 59448c2ecf20Sopenharmony_ci return rc; 59458c2ecf20Sopenharmony_ci } 59468c2ecf20Sopenharmony_ci 59478c2ecf20Sopenharmony_ci /* move to the next message after applying netlink padding */ 59488c2ecf20Sopenharmony_ci msg_len = NLMSG_ALIGN(nlh->nlmsg_len); 59498c2ecf20Sopenharmony_ci if (msg_len >= data_len) 59508c2ecf20Sopenharmony_ci return 0; 59518c2ecf20Sopenharmony_ci data_len -= msg_len; 59528c2ecf20Sopenharmony_ci data += msg_len; 59538c2ecf20Sopenharmony_ci } 59548c2ecf20Sopenharmony_ci 59558c2ecf20Sopenharmony_ci return rc; 59568c2ecf20Sopenharmony_ci} 59578c2ecf20Sopenharmony_ci 59588c2ecf20Sopenharmony_cistatic void ipc_init_security(struct ipc_security_struct *isec, u16 sclass) 59598c2ecf20Sopenharmony_ci{ 59608c2ecf20Sopenharmony_ci isec->sclass = sclass; 59618c2ecf20Sopenharmony_ci isec->sid = current_sid(); 59628c2ecf20Sopenharmony_ci} 59638c2ecf20Sopenharmony_ci 59648c2ecf20Sopenharmony_cistatic int ipc_has_perm(struct kern_ipc_perm *ipc_perms, 59658c2ecf20Sopenharmony_ci u32 perms) 59668c2ecf20Sopenharmony_ci{ 59678c2ecf20Sopenharmony_ci struct ipc_security_struct *isec; 59688c2ecf20Sopenharmony_ci struct common_audit_data ad; 59698c2ecf20Sopenharmony_ci u32 sid = current_sid(); 59708c2ecf20Sopenharmony_ci 59718c2ecf20Sopenharmony_ci isec = selinux_ipc(ipc_perms); 59728c2ecf20Sopenharmony_ci 59738c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IPC; 59748c2ecf20Sopenharmony_ci ad.u.ipc_id = ipc_perms->key; 59758c2ecf20Sopenharmony_ci 59768c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 59778c2ecf20Sopenharmony_ci sid, isec->sid, isec->sclass, perms, &ad); 59788c2ecf20Sopenharmony_ci} 59798c2ecf20Sopenharmony_ci 59808c2ecf20Sopenharmony_cistatic int selinux_msg_msg_alloc_security(struct msg_msg *msg) 59818c2ecf20Sopenharmony_ci{ 59828c2ecf20Sopenharmony_ci struct msg_security_struct *msec; 59838c2ecf20Sopenharmony_ci 59848c2ecf20Sopenharmony_ci msec = selinux_msg_msg(msg); 59858c2ecf20Sopenharmony_ci msec->sid = SECINITSID_UNLABELED; 59868c2ecf20Sopenharmony_ci 59878c2ecf20Sopenharmony_ci return 0; 59888c2ecf20Sopenharmony_ci} 59898c2ecf20Sopenharmony_ci 59908c2ecf20Sopenharmony_ci/* message queue security operations */ 59918c2ecf20Sopenharmony_cistatic int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq) 59928c2ecf20Sopenharmony_ci{ 59938c2ecf20Sopenharmony_ci struct ipc_security_struct *isec; 59948c2ecf20Sopenharmony_ci struct common_audit_data ad; 59958c2ecf20Sopenharmony_ci u32 sid = current_sid(); 59968c2ecf20Sopenharmony_ci int rc; 59978c2ecf20Sopenharmony_ci 59988c2ecf20Sopenharmony_ci isec = selinux_ipc(msq); 59998c2ecf20Sopenharmony_ci ipc_init_security(isec, SECCLASS_MSGQ); 60008c2ecf20Sopenharmony_ci 60018c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IPC; 60028c2ecf20Sopenharmony_ci ad.u.ipc_id = msq->key; 60038c2ecf20Sopenharmony_ci 60048c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 60058c2ecf20Sopenharmony_ci sid, isec->sid, SECCLASS_MSGQ, 60068c2ecf20Sopenharmony_ci MSGQ__CREATE, &ad); 60078c2ecf20Sopenharmony_ci return rc; 60088c2ecf20Sopenharmony_ci} 60098c2ecf20Sopenharmony_ci 60108c2ecf20Sopenharmony_cistatic int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg) 60118c2ecf20Sopenharmony_ci{ 60128c2ecf20Sopenharmony_ci struct ipc_security_struct *isec; 60138c2ecf20Sopenharmony_ci struct common_audit_data ad; 60148c2ecf20Sopenharmony_ci u32 sid = current_sid(); 60158c2ecf20Sopenharmony_ci 60168c2ecf20Sopenharmony_ci isec = selinux_ipc(msq); 60178c2ecf20Sopenharmony_ci 60188c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IPC; 60198c2ecf20Sopenharmony_ci ad.u.ipc_id = msq->key; 60208c2ecf20Sopenharmony_ci 60218c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 60228c2ecf20Sopenharmony_ci sid, isec->sid, SECCLASS_MSGQ, 60238c2ecf20Sopenharmony_ci MSGQ__ASSOCIATE, &ad); 60248c2ecf20Sopenharmony_ci} 60258c2ecf20Sopenharmony_ci 60268c2ecf20Sopenharmony_cistatic int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd) 60278c2ecf20Sopenharmony_ci{ 60288c2ecf20Sopenharmony_ci int err; 60298c2ecf20Sopenharmony_ci int perms; 60308c2ecf20Sopenharmony_ci 60318c2ecf20Sopenharmony_ci switch (cmd) { 60328c2ecf20Sopenharmony_ci case IPC_INFO: 60338c2ecf20Sopenharmony_ci case MSG_INFO: 60348c2ecf20Sopenharmony_ci /* No specific object, just general system-wide information. */ 60358c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 60368c2ecf20Sopenharmony_ci current_sid(), SECINITSID_KERNEL, 60378c2ecf20Sopenharmony_ci SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); 60388c2ecf20Sopenharmony_ci case IPC_STAT: 60398c2ecf20Sopenharmony_ci case MSG_STAT: 60408c2ecf20Sopenharmony_ci case MSG_STAT_ANY: 60418c2ecf20Sopenharmony_ci perms = MSGQ__GETATTR | MSGQ__ASSOCIATE; 60428c2ecf20Sopenharmony_ci break; 60438c2ecf20Sopenharmony_ci case IPC_SET: 60448c2ecf20Sopenharmony_ci perms = MSGQ__SETATTR; 60458c2ecf20Sopenharmony_ci break; 60468c2ecf20Sopenharmony_ci case IPC_RMID: 60478c2ecf20Sopenharmony_ci perms = MSGQ__DESTROY; 60488c2ecf20Sopenharmony_ci break; 60498c2ecf20Sopenharmony_ci default: 60508c2ecf20Sopenharmony_ci return 0; 60518c2ecf20Sopenharmony_ci } 60528c2ecf20Sopenharmony_ci 60538c2ecf20Sopenharmony_ci err = ipc_has_perm(msq, perms); 60548c2ecf20Sopenharmony_ci return err; 60558c2ecf20Sopenharmony_ci} 60568c2ecf20Sopenharmony_ci 60578c2ecf20Sopenharmony_cistatic int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg) 60588c2ecf20Sopenharmony_ci{ 60598c2ecf20Sopenharmony_ci struct ipc_security_struct *isec; 60608c2ecf20Sopenharmony_ci struct msg_security_struct *msec; 60618c2ecf20Sopenharmony_ci struct common_audit_data ad; 60628c2ecf20Sopenharmony_ci u32 sid = current_sid(); 60638c2ecf20Sopenharmony_ci int rc; 60648c2ecf20Sopenharmony_ci 60658c2ecf20Sopenharmony_ci isec = selinux_ipc(msq); 60668c2ecf20Sopenharmony_ci msec = selinux_msg_msg(msg); 60678c2ecf20Sopenharmony_ci 60688c2ecf20Sopenharmony_ci /* 60698c2ecf20Sopenharmony_ci * First time through, need to assign label to the message 60708c2ecf20Sopenharmony_ci */ 60718c2ecf20Sopenharmony_ci if (msec->sid == SECINITSID_UNLABELED) { 60728c2ecf20Sopenharmony_ci /* 60738c2ecf20Sopenharmony_ci * Compute new sid based on current process and 60748c2ecf20Sopenharmony_ci * message queue this message will be stored in 60758c2ecf20Sopenharmony_ci */ 60768c2ecf20Sopenharmony_ci rc = security_transition_sid(&selinux_state, sid, isec->sid, 60778c2ecf20Sopenharmony_ci SECCLASS_MSG, NULL, &msec->sid); 60788c2ecf20Sopenharmony_ci if (rc) 60798c2ecf20Sopenharmony_ci return rc; 60808c2ecf20Sopenharmony_ci } 60818c2ecf20Sopenharmony_ci 60828c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IPC; 60838c2ecf20Sopenharmony_ci ad.u.ipc_id = msq->key; 60848c2ecf20Sopenharmony_ci 60858c2ecf20Sopenharmony_ci /* Can this process write to the queue? */ 60868c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 60878c2ecf20Sopenharmony_ci sid, isec->sid, SECCLASS_MSGQ, 60888c2ecf20Sopenharmony_ci MSGQ__WRITE, &ad); 60898c2ecf20Sopenharmony_ci if (!rc) 60908c2ecf20Sopenharmony_ci /* Can this process send the message */ 60918c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 60928c2ecf20Sopenharmony_ci sid, msec->sid, SECCLASS_MSG, 60938c2ecf20Sopenharmony_ci MSG__SEND, &ad); 60948c2ecf20Sopenharmony_ci if (!rc) 60958c2ecf20Sopenharmony_ci /* Can the message be put in the queue? */ 60968c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 60978c2ecf20Sopenharmony_ci msec->sid, isec->sid, SECCLASS_MSGQ, 60988c2ecf20Sopenharmony_ci MSGQ__ENQUEUE, &ad); 60998c2ecf20Sopenharmony_ci 61008c2ecf20Sopenharmony_ci return rc; 61018c2ecf20Sopenharmony_ci} 61028c2ecf20Sopenharmony_ci 61038c2ecf20Sopenharmony_cistatic int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg, 61048c2ecf20Sopenharmony_ci struct task_struct *target, 61058c2ecf20Sopenharmony_ci long type, int mode) 61068c2ecf20Sopenharmony_ci{ 61078c2ecf20Sopenharmony_ci struct ipc_security_struct *isec; 61088c2ecf20Sopenharmony_ci struct msg_security_struct *msec; 61098c2ecf20Sopenharmony_ci struct common_audit_data ad; 61108c2ecf20Sopenharmony_ci u32 sid = task_sid(target); 61118c2ecf20Sopenharmony_ci int rc; 61128c2ecf20Sopenharmony_ci 61138c2ecf20Sopenharmony_ci isec = selinux_ipc(msq); 61148c2ecf20Sopenharmony_ci msec = selinux_msg_msg(msg); 61158c2ecf20Sopenharmony_ci 61168c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IPC; 61178c2ecf20Sopenharmony_ci ad.u.ipc_id = msq->key; 61188c2ecf20Sopenharmony_ci 61198c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 61208c2ecf20Sopenharmony_ci sid, isec->sid, 61218c2ecf20Sopenharmony_ci SECCLASS_MSGQ, MSGQ__READ, &ad); 61228c2ecf20Sopenharmony_ci if (!rc) 61238c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 61248c2ecf20Sopenharmony_ci sid, msec->sid, 61258c2ecf20Sopenharmony_ci SECCLASS_MSG, MSG__RECEIVE, &ad); 61268c2ecf20Sopenharmony_ci return rc; 61278c2ecf20Sopenharmony_ci} 61288c2ecf20Sopenharmony_ci 61298c2ecf20Sopenharmony_ci/* Shared Memory security operations */ 61308c2ecf20Sopenharmony_cistatic int selinux_shm_alloc_security(struct kern_ipc_perm *shp) 61318c2ecf20Sopenharmony_ci{ 61328c2ecf20Sopenharmony_ci struct ipc_security_struct *isec; 61338c2ecf20Sopenharmony_ci struct common_audit_data ad; 61348c2ecf20Sopenharmony_ci u32 sid = current_sid(); 61358c2ecf20Sopenharmony_ci int rc; 61368c2ecf20Sopenharmony_ci 61378c2ecf20Sopenharmony_ci isec = selinux_ipc(shp); 61388c2ecf20Sopenharmony_ci ipc_init_security(isec, SECCLASS_SHM); 61398c2ecf20Sopenharmony_ci 61408c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IPC; 61418c2ecf20Sopenharmony_ci ad.u.ipc_id = shp->key; 61428c2ecf20Sopenharmony_ci 61438c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 61448c2ecf20Sopenharmony_ci sid, isec->sid, SECCLASS_SHM, 61458c2ecf20Sopenharmony_ci SHM__CREATE, &ad); 61468c2ecf20Sopenharmony_ci return rc; 61478c2ecf20Sopenharmony_ci} 61488c2ecf20Sopenharmony_ci 61498c2ecf20Sopenharmony_cistatic int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg) 61508c2ecf20Sopenharmony_ci{ 61518c2ecf20Sopenharmony_ci struct ipc_security_struct *isec; 61528c2ecf20Sopenharmony_ci struct common_audit_data ad; 61538c2ecf20Sopenharmony_ci u32 sid = current_sid(); 61548c2ecf20Sopenharmony_ci 61558c2ecf20Sopenharmony_ci isec = selinux_ipc(shp); 61568c2ecf20Sopenharmony_ci 61578c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IPC; 61588c2ecf20Sopenharmony_ci ad.u.ipc_id = shp->key; 61598c2ecf20Sopenharmony_ci 61608c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 61618c2ecf20Sopenharmony_ci sid, isec->sid, SECCLASS_SHM, 61628c2ecf20Sopenharmony_ci SHM__ASSOCIATE, &ad); 61638c2ecf20Sopenharmony_ci} 61648c2ecf20Sopenharmony_ci 61658c2ecf20Sopenharmony_ci/* Note, at this point, shp is locked down */ 61668c2ecf20Sopenharmony_cistatic int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd) 61678c2ecf20Sopenharmony_ci{ 61688c2ecf20Sopenharmony_ci int perms; 61698c2ecf20Sopenharmony_ci int err; 61708c2ecf20Sopenharmony_ci 61718c2ecf20Sopenharmony_ci switch (cmd) { 61728c2ecf20Sopenharmony_ci case IPC_INFO: 61738c2ecf20Sopenharmony_ci case SHM_INFO: 61748c2ecf20Sopenharmony_ci /* No specific object, just general system-wide information. */ 61758c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 61768c2ecf20Sopenharmony_ci current_sid(), SECINITSID_KERNEL, 61778c2ecf20Sopenharmony_ci SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); 61788c2ecf20Sopenharmony_ci case IPC_STAT: 61798c2ecf20Sopenharmony_ci case SHM_STAT: 61808c2ecf20Sopenharmony_ci case SHM_STAT_ANY: 61818c2ecf20Sopenharmony_ci perms = SHM__GETATTR | SHM__ASSOCIATE; 61828c2ecf20Sopenharmony_ci break; 61838c2ecf20Sopenharmony_ci case IPC_SET: 61848c2ecf20Sopenharmony_ci perms = SHM__SETATTR; 61858c2ecf20Sopenharmony_ci break; 61868c2ecf20Sopenharmony_ci case SHM_LOCK: 61878c2ecf20Sopenharmony_ci case SHM_UNLOCK: 61888c2ecf20Sopenharmony_ci perms = SHM__LOCK; 61898c2ecf20Sopenharmony_ci break; 61908c2ecf20Sopenharmony_ci case IPC_RMID: 61918c2ecf20Sopenharmony_ci perms = SHM__DESTROY; 61928c2ecf20Sopenharmony_ci break; 61938c2ecf20Sopenharmony_ci default: 61948c2ecf20Sopenharmony_ci return 0; 61958c2ecf20Sopenharmony_ci } 61968c2ecf20Sopenharmony_ci 61978c2ecf20Sopenharmony_ci err = ipc_has_perm(shp, perms); 61988c2ecf20Sopenharmony_ci return err; 61998c2ecf20Sopenharmony_ci} 62008c2ecf20Sopenharmony_ci 62018c2ecf20Sopenharmony_cistatic int selinux_shm_shmat(struct kern_ipc_perm *shp, 62028c2ecf20Sopenharmony_ci char __user *shmaddr, int shmflg) 62038c2ecf20Sopenharmony_ci{ 62048c2ecf20Sopenharmony_ci u32 perms; 62058c2ecf20Sopenharmony_ci 62068c2ecf20Sopenharmony_ci if (shmflg & SHM_RDONLY) 62078c2ecf20Sopenharmony_ci perms = SHM__READ; 62088c2ecf20Sopenharmony_ci else 62098c2ecf20Sopenharmony_ci perms = SHM__READ | SHM__WRITE; 62108c2ecf20Sopenharmony_ci 62118c2ecf20Sopenharmony_ci return ipc_has_perm(shp, perms); 62128c2ecf20Sopenharmony_ci} 62138c2ecf20Sopenharmony_ci 62148c2ecf20Sopenharmony_ci/* Semaphore security operations */ 62158c2ecf20Sopenharmony_cistatic int selinux_sem_alloc_security(struct kern_ipc_perm *sma) 62168c2ecf20Sopenharmony_ci{ 62178c2ecf20Sopenharmony_ci struct ipc_security_struct *isec; 62188c2ecf20Sopenharmony_ci struct common_audit_data ad; 62198c2ecf20Sopenharmony_ci u32 sid = current_sid(); 62208c2ecf20Sopenharmony_ci int rc; 62218c2ecf20Sopenharmony_ci 62228c2ecf20Sopenharmony_ci isec = selinux_ipc(sma); 62238c2ecf20Sopenharmony_ci ipc_init_security(isec, SECCLASS_SEM); 62248c2ecf20Sopenharmony_ci 62258c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IPC; 62268c2ecf20Sopenharmony_ci ad.u.ipc_id = sma->key; 62278c2ecf20Sopenharmony_ci 62288c2ecf20Sopenharmony_ci rc = avc_has_perm(&selinux_state, 62298c2ecf20Sopenharmony_ci sid, isec->sid, SECCLASS_SEM, 62308c2ecf20Sopenharmony_ci SEM__CREATE, &ad); 62318c2ecf20Sopenharmony_ci return rc; 62328c2ecf20Sopenharmony_ci} 62338c2ecf20Sopenharmony_ci 62348c2ecf20Sopenharmony_cistatic int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg) 62358c2ecf20Sopenharmony_ci{ 62368c2ecf20Sopenharmony_ci struct ipc_security_struct *isec; 62378c2ecf20Sopenharmony_ci struct common_audit_data ad; 62388c2ecf20Sopenharmony_ci u32 sid = current_sid(); 62398c2ecf20Sopenharmony_ci 62408c2ecf20Sopenharmony_ci isec = selinux_ipc(sma); 62418c2ecf20Sopenharmony_ci 62428c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IPC; 62438c2ecf20Sopenharmony_ci ad.u.ipc_id = sma->key; 62448c2ecf20Sopenharmony_ci 62458c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 62468c2ecf20Sopenharmony_ci sid, isec->sid, SECCLASS_SEM, 62478c2ecf20Sopenharmony_ci SEM__ASSOCIATE, &ad); 62488c2ecf20Sopenharmony_ci} 62498c2ecf20Sopenharmony_ci 62508c2ecf20Sopenharmony_ci/* Note, at this point, sma is locked down */ 62518c2ecf20Sopenharmony_cistatic int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd) 62528c2ecf20Sopenharmony_ci{ 62538c2ecf20Sopenharmony_ci int err; 62548c2ecf20Sopenharmony_ci u32 perms; 62558c2ecf20Sopenharmony_ci 62568c2ecf20Sopenharmony_ci switch (cmd) { 62578c2ecf20Sopenharmony_ci case IPC_INFO: 62588c2ecf20Sopenharmony_ci case SEM_INFO: 62598c2ecf20Sopenharmony_ci /* No specific object, just general system-wide information. */ 62608c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 62618c2ecf20Sopenharmony_ci current_sid(), SECINITSID_KERNEL, 62628c2ecf20Sopenharmony_ci SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL); 62638c2ecf20Sopenharmony_ci case GETPID: 62648c2ecf20Sopenharmony_ci case GETNCNT: 62658c2ecf20Sopenharmony_ci case GETZCNT: 62668c2ecf20Sopenharmony_ci perms = SEM__GETATTR; 62678c2ecf20Sopenharmony_ci break; 62688c2ecf20Sopenharmony_ci case GETVAL: 62698c2ecf20Sopenharmony_ci case GETALL: 62708c2ecf20Sopenharmony_ci perms = SEM__READ; 62718c2ecf20Sopenharmony_ci break; 62728c2ecf20Sopenharmony_ci case SETVAL: 62738c2ecf20Sopenharmony_ci case SETALL: 62748c2ecf20Sopenharmony_ci perms = SEM__WRITE; 62758c2ecf20Sopenharmony_ci break; 62768c2ecf20Sopenharmony_ci case IPC_RMID: 62778c2ecf20Sopenharmony_ci perms = SEM__DESTROY; 62788c2ecf20Sopenharmony_ci break; 62798c2ecf20Sopenharmony_ci case IPC_SET: 62808c2ecf20Sopenharmony_ci perms = SEM__SETATTR; 62818c2ecf20Sopenharmony_ci break; 62828c2ecf20Sopenharmony_ci case IPC_STAT: 62838c2ecf20Sopenharmony_ci case SEM_STAT: 62848c2ecf20Sopenharmony_ci case SEM_STAT_ANY: 62858c2ecf20Sopenharmony_ci perms = SEM__GETATTR | SEM__ASSOCIATE; 62868c2ecf20Sopenharmony_ci break; 62878c2ecf20Sopenharmony_ci default: 62888c2ecf20Sopenharmony_ci return 0; 62898c2ecf20Sopenharmony_ci } 62908c2ecf20Sopenharmony_ci 62918c2ecf20Sopenharmony_ci err = ipc_has_perm(sma, perms); 62928c2ecf20Sopenharmony_ci return err; 62938c2ecf20Sopenharmony_ci} 62948c2ecf20Sopenharmony_ci 62958c2ecf20Sopenharmony_cistatic int selinux_sem_semop(struct kern_ipc_perm *sma, 62968c2ecf20Sopenharmony_ci struct sembuf *sops, unsigned nsops, int alter) 62978c2ecf20Sopenharmony_ci{ 62988c2ecf20Sopenharmony_ci u32 perms; 62998c2ecf20Sopenharmony_ci 63008c2ecf20Sopenharmony_ci if (alter) 63018c2ecf20Sopenharmony_ci perms = SEM__READ | SEM__WRITE; 63028c2ecf20Sopenharmony_ci else 63038c2ecf20Sopenharmony_ci perms = SEM__READ; 63048c2ecf20Sopenharmony_ci 63058c2ecf20Sopenharmony_ci return ipc_has_perm(sma, perms); 63068c2ecf20Sopenharmony_ci} 63078c2ecf20Sopenharmony_ci 63088c2ecf20Sopenharmony_cistatic int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag) 63098c2ecf20Sopenharmony_ci{ 63108c2ecf20Sopenharmony_ci u32 av = 0; 63118c2ecf20Sopenharmony_ci 63128c2ecf20Sopenharmony_ci av = 0; 63138c2ecf20Sopenharmony_ci if (flag & S_IRUGO) 63148c2ecf20Sopenharmony_ci av |= IPC__UNIX_READ; 63158c2ecf20Sopenharmony_ci if (flag & S_IWUGO) 63168c2ecf20Sopenharmony_ci av |= IPC__UNIX_WRITE; 63178c2ecf20Sopenharmony_ci 63188c2ecf20Sopenharmony_ci if (av == 0) 63198c2ecf20Sopenharmony_ci return 0; 63208c2ecf20Sopenharmony_ci 63218c2ecf20Sopenharmony_ci return ipc_has_perm(ipcp, av); 63228c2ecf20Sopenharmony_ci} 63238c2ecf20Sopenharmony_ci 63248c2ecf20Sopenharmony_cistatic void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) 63258c2ecf20Sopenharmony_ci{ 63268c2ecf20Sopenharmony_ci struct ipc_security_struct *isec = selinux_ipc(ipcp); 63278c2ecf20Sopenharmony_ci *secid = isec->sid; 63288c2ecf20Sopenharmony_ci} 63298c2ecf20Sopenharmony_ci 63308c2ecf20Sopenharmony_cistatic void selinux_d_instantiate(struct dentry *dentry, struct inode *inode) 63318c2ecf20Sopenharmony_ci{ 63328c2ecf20Sopenharmony_ci if (inode) 63338c2ecf20Sopenharmony_ci inode_doinit_with_dentry(inode, dentry); 63348c2ecf20Sopenharmony_ci} 63358c2ecf20Sopenharmony_ci 63368c2ecf20Sopenharmony_cistatic int selinux_getprocattr(struct task_struct *p, 63378c2ecf20Sopenharmony_ci char *name, char **value) 63388c2ecf20Sopenharmony_ci{ 63398c2ecf20Sopenharmony_ci const struct task_security_struct *__tsec; 63408c2ecf20Sopenharmony_ci u32 sid; 63418c2ecf20Sopenharmony_ci int error; 63428c2ecf20Sopenharmony_ci unsigned len; 63438c2ecf20Sopenharmony_ci 63448c2ecf20Sopenharmony_ci rcu_read_lock(); 63458c2ecf20Sopenharmony_ci __tsec = selinux_cred(__task_cred(p)); 63468c2ecf20Sopenharmony_ci 63478c2ecf20Sopenharmony_ci if (current != p) { 63488c2ecf20Sopenharmony_ci error = avc_has_perm(&selinux_state, 63498c2ecf20Sopenharmony_ci current_sid(), __tsec->sid, 63508c2ecf20Sopenharmony_ci SECCLASS_PROCESS, PROCESS__GETATTR, NULL); 63518c2ecf20Sopenharmony_ci if (error) 63528c2ecf20Sopenharmony_ci goto bad; 63538c2ecf20Sopenharmony_ci } 63548c2ecf20Sopenharmony_ci 63558c2ecf20Sopenharmony_ci if (!strcmp(name, "current")) 63568c2ecf20Sopenharmony_ci sid = __tsec->sid; 63578c2ecf20Sopenharmony_ci else if (!strcmp(name, "prev")) 63588c2ecf20Sopenharmony_ci sid = __tsec->osid; 63598c2ecf20Sopenharmony_ci else if (!strcmp(name, "exec")) 63608c2ecf20Sopenharmony_ci sid = __tsec->exec_sid; 63618c2ecf20Sopenharmony_ci else if (!strcmp(name, "fscreate")) 63628c2ecf20Sopenharmony_ci sid = __tsec->create_sid; 63638c2ecf20Sopenharmony_ci else if (!strcmp(name, "keycreate")) 63648c2ecf20Sopenharmony_ci sid = __tsec->keycreate_sid; 63658c2ecf20Sopenharmony_ci else if (!strcmp(name, "sockcreate")) 63668c2ecf20Sopenharmony_ci sid = __tsec->sockcreate_sid; 63678c2ecf20Sopenharmony_ci else { 63688c2ecf20Sopenharmony_ci error = -EINVAL; 63698c2ecf20Sopenharmony_ci goto bad; 63708c2ecf20Sopenharmony_ci } 63718c2ecf20Sopenharmony_ci rcu_read_unlock(); 63728c2ecf20Sopenharmony_ci 63738c2ecf20Sopenharmony_ci if (!sid) 63748c2ecf20Sopenharmony_ci return 0; 63758c2ecf20Sopenharmony_ci 63768c2ecf20Sopenharmony_ci error = security_sid_to_context(&selinux_state, sid, value, &len); 63778c2ecf20Sopenharmony_ci if (error) 63788c2ecf20Sopenharmony_ci return error; 63798c2ecf20Sopenharmony_ci return len; 63808c2ecf20Sopenharmony_ci 63818c2ecf20Sopenharmony_cibad: 63828c2ecf20Sopenharmony_ci rcu_read_unlock(); 63838c2ecf20Sopenharmony_ci return error; 63848c2ecf20Sopenharmony_ci} 63858c2ecf20Sopenharmony_ci 63868c2ecf20Sopenharmony_cistatic int selinux_setprocattr(const char *name, void *value, size_t size) 63878c2ecf20Sopenharmony_ci{ 63888c2ecf20Sopenharmony_ci struct task_security_struct *tsec; 63898c2ecf20Sopenharmony_ci struct cred *new; 63908c2ecf20Sopenharmony_ci u32 mysid = current_sid(), sid = 0, ptsid; 63918c2ecf20Sopenharmony_ci int error; 63928c2ecf20Sopenharmony_ci char *str = value; 63938c2ecf20Sopenharmony_ci 63948c2ecf20Sopenharmony_ci /* 63958c2ecf20Sopenharmony_ci * Basic control over ability to set these attributes at all. 63968c2ecf20Sopenharmony_ci */ 63978c2ecf20Sopenharmony_ci if (!strcmp(name, "exec")) 63988c2ecf20Sopenharmony_ci error = avc_has_perm(&selinux_state, 63998c2ecf20Sopenharmony_ci mysid, mysid, SECCLASS_PROCESS, 64008c2ecf20Sopenharmony_ci PROCESS__SETEXEC, NULL); 64018c2ecf20Sopenharmony_ci else if (!strcmp(name, "fscreate")) 64028c2ecf20Sopenharmony_ci error = avc_has_perm(&selinux_state, 64038c2ecf20Sopenharmony_ci mysid, mysid, SECCLASS_PROCESS, 64048c2ecf20Sopenharmony_ci PROCESS__SETFSCREATE, NULL); 64058c2ecf20Sopenharmony_ci else if (!strcmp(name, "keycreate")) 64068c2ecf20Sopenharmony_ci error = avc_has_perm(&selinux_state, 64078c2ecf20Sopenharmony_ci mysid, mysid, SECCLASS_PROCESS, 64088c2ecf20Sopenharmony_ci PROCESS__SETKEYCREATE, NULL); 64098c2ecf20Sopenharmony_ci else if (!strcmp(name, "sockcreate")) 64108c2ecf20Sopenharmony_ci error = avc_has_perm(&selinux_state, 64118c2ecf20Sopenharmony_ci mysid, mysid, SECCLASS_PROCESS, 64128c2ecf20Sopenharmony_ci PROCESS__SETSOCKCREATE, NULL); 64138c2ecf20Sopenharmony_ci else if (!strcmp(name, "current")) 64148c2ecf20Sopenharmony_ci error = avc_has_perm(&selinux_state, 64158c2ecf20Sopenharmony_ci mysid, mysid, SECCLASS_PROCESS, 64168c2ecf20Sopenharmony_ci PROCESS__SETCURRENT, NULL); 64178c2ecf20Sopenharmony_ci else 64188c2ecf20Sopenharmony_ci error = -EINVAL; 64198c2ecf20Sopenharmony_ci if (error) 64208c2ecf20Sopenharmony_ci return error; 64218c2ecf20Sopenharmony_ci 64228c2ecf20Sopenharmony_ci /* Obtain a SID for the context, if one was specified. */ 64238c2ecf20Sopenharmony_ci if (size && str[0] && str[0] != '\n') { 64248c2ecf20Sopenharmony_ci if (str[size-1] == '\n') { 64258c2ecf20Sopenharmony_ci str[size-1] = 0; 64268c2ecf20Sopenharmony_ci size--; 64278c2ecf20Sopenharmony_ci } 64288c2ecf20Sopenharmony_ci error = security_context_to_sid(&selinux_state, value, size, 64298c2ecf20Sopenharmony_ci &sid, GFP_KERNEL); 64308c2ecf20Sopenharmony_ci if (error == -EINVAL && !strcmp(name, "fscreate")) { 64318c2ecf20Sopenharmony_ci if (!has_cap_mac_admin(true)) { 64328c2ecf20Sopenharmony_ci struct audit_buffer *ab; 64338c2ecf20Sopenharmony_ci size_t audit_size; 64348c2ecf20Sopenharmony_ci 64358c2ecf20Sopenharmony_ci /* We strip a nul only if it is at the end, otherwise the 64368c2ecf20Sopenharmony_ci * context contains a nul and we should audit that */ 64378c2ecf20Sopenharmony_ci if (str[size - 1] == '\0') 64388c2ecf20Sopenharmony_ci audit_size = size - 1; 64398c2ecf20Sopenharmony_ci else 64408c2ecf20Sopenharmony_ci audit_size = size; 64418c2ecf20Sopenharmony_ci ab = audit_log_start(audit_context(), 64428c2ecf20Sopenharmony_ci GFP_ATOMIC, 64438c2ecf20Sopenharmony_ci AUDIT_SELINUX_ERR); 64448c2ecf20Sopenharmony_ci audit_log_format(ab, "op=fscreate invalid_context="); 64458c2ecf20Sopenharmony_ci audit_log_n_untrustedstring(ab, value, audit_size); 64468c2ecf20Sopenharmony_ci audit_log_end(ab); 64478c2ecf20Sopenharmony_ci 64488c2ecf20Sopenharmony_ci return error; 64498c2ecf20Sopenharmony_ci } 64508c2ecf20Sopenharmony_ci error = security_context_to_sid_force( 64518c2ecf20Sopenharmony_ci &selinux_state, 64528c2ecf20Sopenharmony_ci value, size, &sid); 64538c2ecf20Sopenharmony_ci } 64548c2ecf20Sopenharmony_ci if (error) 64558c2ecf20Sopenharmony_ci return error; 64568c2ecf20Sopenharmony_ci } 64578c2ecf20Sopenharmony_ci 64588c2ecf20Sopenharmony_ci new = prepare_creds(); 64598c2ecf20Sopenharmony_ci if (!new) 64608c2ecf20Sopenharmony_ci return -ENOMEM; 64618c2ecf20Sopenharmony_ci 64628c2ecf20Sopenharmony_ci /* Permission checking based on the specified context is 64638c2ecf20Sopenharmony_ci performed during the actual operation (execve, 64648c2ecf20Sopenharmony_ci open/mkdir/...), when we know the full context of the 64658c2ecf20Sopenharmony_ci operation. See selinux_bprm_creds_for_exec for the execve 64668c2ecf20Sopenharmony_ci checks and may_create for the file creation checks. The 64678c2ecf20Sopenharmony_ci operation will then fail if the context is not permitted. */ 64688c2ecf20Sopenharmony_ci tsec = selinux_cred(new); 64698c2ecf20Sopenharmony_ci if (!strcmp(name, "exec")) { 64708c2ecf20Sopenharmony_ci tsec->exec_sid = sid; 64718c2ecf20Sopenharmony_ci } else if (!strcmp(name, "fscreate")) { 64728c2ecf20Sopenharmony_ci tsec->create_sid = sid; 64738c2ecf20Sopenharmony_ci } else if (!strcmp(name, "keycreate")) { 64748c2ecf20Sopenharmony_ci if (sid) { 64758c2ecf20Sopenharmony_ci error = avc_has_perm(&selinux_state, mysid, sid, 64768c2ecf20Sopenharmony_ci SECCLASS_KEY, KEY__CREATE, NULL); 64778c2ecf20Sopenharmony_ci if (error) 64788c2ecf20Sopenharmony_ci goto abort_change; 64798c2ecf20Sopenharmony_ci } 64808c2ecf20Sopenharmony_ci tsec->keycreate_sid = sid; 64818c2ecf20Sopenharmony_ci } else if (!strcmp(name, "sockcreate")) { 64828c2ecf20Sopenharmony_ci tsec->sockcreate_sid = sid; 64838c2ecf20Sopenharmony_ci } else if (!strcmp(name, "current")) { 64848c2ecf20Sopenharmony_ci error = -EINVAL; 64858c2ecf20Sopenharmony_ci if (sid == 0) 64868c2ecf20Sopenharmony_ci goto abort_change; 64878c2ecf20Sopenharmony_ci 64888c2ecf20Sopenharmony_ci /* Only allow single threaded processes to change context */ 64898c2ecf20Sopenharmony_ci error = -EPERM; 64908c2ecf20Sopenharmony_ci if (!current_is_single_threaded()) { 64918c2ecf20Sopenharmony_ci error = security_bounded_transition(&selinux_state, 64928c2ecf20Sopenharmony_ci tsec->sid, sid); 64938c2ecf20Sopenharmony_ci if (error) 64948c2ecf20Sopenharmony_ci goto abort_change; 64958c2ecf20Sopenharmony_ci } 64968c2ecf20Sopenharmony_ci 64978c2ecf20Sopenharmony_ci /* Check permissions for the transition. */ 64988c2ecf20Sopenharmony_ci error = avc_has_perm(&selinux_state, 64998c2ecf20Sopenharmony_ci tsec->sid, sid, SECCLASS_PROCESS, 65008c2ecf20Sopenharmony_ci PROCESS__DYNTRANSITION, NULL); 65018c2ecf20Sopenharmony_ci if (error) 65028c2ecf20Sopenharmony_ci goto abort_change; 65038c2ecf20Sopenharmony_ci 65048c2ecf20Sopenharmony_ci /* Check for ptracing, and update the task SID if ok. 65058c2ecf20Sopenharmony_ci Otherwise, leave SID unchanged and fail. */ 65068c2ecf20Sopenharmony_ci ptsid = ptrace_parent_sid(); 65078c2ecf20Sopenharmony_ci if (ptsid != 0) { 65088c2ecf20Sopenharmony_ci error = avc_has_perm(&selinux_state, 65098c2ecf20Sopenharmony_ci ptsid, sid, SECCLASS_PROCESS, 65108c2ecf20Sopenharmony_ci PROCESS__PTRACE, NULL); 65118c2ecf20Sopenharmony_ci if (error) 65128c2ecf20Sopenharmony_ci goto abort_change; 65138c2ecf20Sopenharmony_ci } 65148c2ecf20Sopenharmony_ci 65158c2ecf20Sopenharmony_ci tsec->sid = sid; 65168c2ecf20Sopenharmony_ci } else { 65178c2ecf20Sopenharmony_ci error = -EINVAL; 65188c2ecf20Sopenharmony_ci goto abort_change; 65198c2ecf20Sopenharmony_ci } 65208c2ecf20Sopenharmony_ci 65218c2ecf20Sopenharmony_ci commit_creds(new); 65228c2ecf20Sopenharmony_ci CALL_HCK_LITE_HOOK(ced_setattr_insert_lhck, current); 65238c2ecf20Sopenharmony_ci return size; 65248c2ecf20Sopenharmony_ci 65258c2ecf20Sopenharmony_ciabort_change: 65268c2ecf20Sopenharmony_ci abort_creds(new); 65278c2ecf20Sopenharmony_ci return error; 65288c2ecf20Sopenharmony_ci} 65298c2ecf20Sopenharmony_ci 65308c2ecf20Sopenharmony_cistatic int selinux_ismaclabel(const char *name) 65318c2ecf20Sopenharmony_ci{ 65328c2ecf20Sopenharmony_ci return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0); 65338c2ecf20Sopenharmony_ci} 65348c2ecf20Sopenharmony_ci 65358c2ecf20Sopenharmony_cistatic int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) 65368c2ecf20Sopenharmony_ci{ 65378c2ecf20Sopenharmony_ci return security_sid_to_context(&selinux_state, secid, 65388c2ecf20Sopenharmony_ci secdata, seclen); 65398c2ecf20Sopenharmony_ci} 65408c2ecf20Sopenharmony_ci 65418c2ecf20Sopenharmony_cistatic int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid) 65428c2ecf20Sopenharmony_ci{ 65438c2ecf20Sopenharmony_ci return security_context_to_sid(&selinux_state, secdata, seclen, 65448c2ecf20Sopenharmony_ci secid, GFP_KERNEL); 65458c2ecf20Sopenharmony_ci} 65468c2ecf20Sopenharmony_ci 65478c2ecf20Sopenharmony_cistatic void selinux_release_secctx(char *secdata, u32 seclen) 65488c2ecf20Sopenharmony_ci{ 65498c2ecf20Sopenharmony_ci kfree(secdata); 65508c2ecf20Sopenharmony_ci} 65518c2ecf20Sopenharmony_ci 65528c2ecf20Sopenharmony_cistatic void selinux_inode_invalidate_secctx(struct inode *inode) 65538c2ecf20Sopenharmony_ci{ 65548c2ecf20Sopenharmony_ci struct inode_security_struct *isec = selinux_inode(inode); 65558c2ecf20Sopenharmony_ci 65568c2ecf20Sopenharmony_ci spin_lock(&isec->lock); 65578c2ecf20Sopenharmony_ci isec->initialized = LABEL_INVALID; 65588c2ecf20Sopenharmony_ci spin_unlock(&isec->lock); 65598c2ecf20Sopenharmony_ci} 65608c2ecf20Sopenharmony_ci 65618c2ecf20Sopenharmony_ci/* 65628c2ecf20Sopenharmony_ci * called with inode->i_mutex locked 65638c2ecf20Sopenharmony_ci */ 65648c2ecf20Sopenharmony_cistatic int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) 65658c2ecf20Sopenharmony_ci{ 65668c2ecf20Sopenharmony_ci int rc = selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, 65678c2ecf20Sopenharmony_ci ctx, ctxlen, 0); 65688c2ecf20Sopenharmony_ci /* Do not return error when suppressing label (SBLABEL_MNT not set). */ 65698c2ecf20Sopenharmony_ci return rc == -EOPNOTSUPP ? 0 : rc; 65708c2ecf20Sopenharmony_ci} 65718c2ecf20Sopenharmony_ci 65728c2ecf20Sopenharmony_ci/* 65738c2ecf20Sopenharmony_ci * called with inode->i_mutex locked 65748c2ecf20Sopenharmony_ci */ 65758c2ecf20Sopenharmony_cistatic int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) 65768c2ecf20Sopenharmony_ci{ 65778c2ecf20Sopenharmony_ci return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0); 65788c2ecf20Sopenharmony_ci} 65798c2ecf20Sopenharmony_ci 65808c2ecf20Sopenharmony_cistatic int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) 65818c2ecf20Sopenharmony_ci{ 65828c2ecf20Sopenharmony_ci int len = 0; 65838c2ecf20Sopenharmony_ci len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX, 65848c2ecf20Sopenharmony_ci ctx, true); 65858c2ecf20Sopenharmony_ci if (len < 0) 65868c2ecf20Sopenharmony_ci return len; 65878c2ecf20Sopenharmony_ci *ctxlen = len; 65888c2ecf20Sopenharmony_ci return 0; 65898c2ecf20Sopenharmony_ci} 65908c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 65918c2ecf20Sopenharmony_ci 65928c2ecf20Sopenharmony_cistatic int selinux_key_alloc(struct key *k, const struct cred *cred, 65938c2ecf20Sopenharmony_ci unsigned long flags) 65948c2ecf20Sopenharmony_ci{ 65958c2ecf20Sopenharmony_ci const struct task_security_struct *tsec; 65968c2ecf20Sopenharmony_ci struct key_security_struct *ksec; 65978c2ecf20Sopenharmony_ci 65988c2ecf20Sopenharmony_ci ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL); 65998c2ecf20Sopenharmony_ci if (!ksec) 66008c2ecf20Sopenharmony_ci return -ENOMEM; 66018c2ecf20Sopenharmony_ci 66028c2ecf20Sopenharmony_ci tsec = selinux_cred(cred); 66038c2ecf20Sopenharmony_ci if (tsec->keycreate_sid) 66048c2ecf20Sopenharmony_ci ksec->sid = tsec->keycreate_sid; 66058c2ecf20Sopenharmony_ci else 66068c2ecf20Sopenharmony_ci ksec->sid = tsec->sid; 66078c2ecf20Sopenharmony_ci 66088c2ecf20Sopenharmony_ci k->security = ksec; 66098c2ecf20Sopenharmony_ci return 0; 66108c2ecf20Sopenharmony_ci} 66118c2ecf20Sopenharmony_ci 66128c2ecf20Sopenharmony_cistatic void selinux_key_free(struct key *k) 66138c2ecf20Sopenharmony_ci{ 66148c2ecf20Sopenharmony_ci struct key_security_struct *ksec = k->security; 66158c2ecf20Sopenharmony_ci 66168c2ecf20Sopenharmony_ci k->security = NULL; 66178c2ecf20Sopenharmony_ci kfree(ksec); 66188c2ecf20Sopenharmony_ci} 66198c2ecf20Sopenharmony_ci 66208c2ecf20Sopenharmony_cistatic int selinux_key_permission(key_ref_t key_ref, 66218c2ecf20Sopenharmony_ci const struct cred *cred, 66228c2ecf20Sopenharmony_ci enum key_need_perm need_perm) 66238c2ecf20Sopenharmony_ci{ 66248c2ecf20Sopenharmony_ci struct key *key; 66258c2ecf20Sopenharmony_ci struct key_security_struct *ksec; 66268c2ecf20Sopenharmony_ci u32 perm, sid; 66278c2ecf20Sopenharmony_ci 66288c2ecf20Sopenharmony_ci switch (need_perm) { 66298c2ecf20Sopenharmony_ci case KEY_NEED_VIEW: 66308c2ecf20Sopenharmony_ci perm = KEY__VIEW; 66318c2ecf20Sopenharmony_ci break; 66328c2ecf20Sopenharmony_ci case KEY_NEED_READ: 66338c2ecf20Sopenharmony_ci perm = KEY__READ; 66348c2ecf20Sopenharmony_ci break; 66358c2ecf20Sopenharmony_ci case KEY_NEED_WRITE: 66368c2ecf20Sopenharmony_ci perm = KEY__WRITE; 66378c2ecf20Sopenharmony_ci break; 66388c2ecf20Sopenharmony_ci case KEY_NEED_SEARCH: 66398c2ecf20Sopenharmony_ci perm = KEY__SEARCH; 66408c2ecf20Sopenharmony_ci break; 66418c2ecf20Sopenharmony_ci case KEY_NEED_LINK: 66428c2ecf20Sopenharmony_ci perm = KEY__LINK; 66438c2ecf20Sopenharmony_ci break; 66448c2ecf20Sopenharmony_ci case KEY_NEED_SETATTR: 66458c2ecf20Sopenharmony_ci perm = KEY__SETATTR; 66468c2ecf20Sopenharmony_ci break; 66478c2ecf20Sopenharmony_ci case KEY_NEED_UNLINK: 66488c2ecf20Sopenharmony_ci case KEY_SYSADMIN_OVERRIDE: 66498c2ecf20Sopenharmony_ci case KEY_AUTHTOKEN_OVERRIDE: 66508c2ecf20Sopenharmony_ci case KEY_DEFER_PERM_CHECK: 66518c2ecf20Sopenharmony_ci return 0; 66528c2ecf20Sopenharmony_ci default: 66538c2ecf20Sopenharmony_ci WARN_ON(1); 66548c2ecf20Sopenharmony_ci return -EPERM; 66558c2ecf20Sopenharmony_ci 66568c2ecf20Sopenharmony_ci } 66578c2ecf20Sopenharmony_ci 66588c2ecf20Sopenharmony_ci sid = cred_sid(cred); 66598c2ecf20Sopenharmony_ci key = key_ref_to_ptr(key_ref); 66608c2ecf20Sopenharmony_ci ksec = key->security; 66618c2ecf20Sopenharmony_ci 66628c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 66638c2ecf20Sopenharmony_ci sid, ksec->sid, SECCLASS_KEY, perm, NULL); 66648c2ecf20Sopenharmony_ci} 66658c2ecf20Sopenharmony_ci 66668c2ecf20Sopenharmony_cistatic int selinux_key_getsecurity(struct key *key, char **_buffer) 66678c2ecf20Sopenharmony_ci{ 66688c2ecf20Sopenharmony_ci struct key_security_struct *ksec = key->security; 66698c2ecf20Sopenharmony_ci char *context = NULL; 66708c2ecf20Sopenharmony_ci unsigned len; 66718c2ecf20Sopenharmony_ci int rc; 66728c2ecf20Sopenharmony_ci 66738c2ecf20Sopenharmony_ci rc = security_sid_to_context(&selinux_state, ksec->sid, 66748c2ecf20Sopenharmony_ci &context, &len); 66758c2ecf20Sopenharmony_ci if (!rc) 66768c2ecf20Sopenharmony_ci rc = len; 66778c2ecf20Sopenharmony_ci *_buffer = context; 66788c2ecf20Sopenharmony_ci return rc; 66798c2ecf20Sopenharmony_ci} 66808c2ecf20Sopenharmony_ci 66818c2ecf20Sopenharmony_ci#ifdef CONFIG_KEY_NOTIFICATIONS 66828c2ecf20Sopenharmony_cistatic int selinux_watch_key(struct key *key) 66838c2ecf20Sopenharmony_ci{ 66848c2ecf20Sopenharmony_ci struct key_security_struct *ksec = key->security; 66858c2ecf20Sopenharmony_ci u32 sid = current_sid(); 66868c2ecf20Sopenharmony_ci 66878c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 66888c2ecf20Sopenharmony_ci sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL); 66898c2ecf20Sopenharmony_ci} 66908c2ecf20Sopenharmony_ci#endif 66918c2ecf20Sopenharmony_ci#endif 66928c2ecf20Sopenharmony_ci 66938c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_INFINIBAND 66948c2ecf20Sopenharmony_cistatic int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val) 66958c2ecf20Sopenharmony_ci{ 66968c2ecf20Sopenharmony_ci struct common_audit_data ad; 66978c2ecf20Sopenharmony_ci int err; 66988c2ecf20Sopenharmony_ci u32 sid = 0; 66998c2ecf20Sopenharmony_ci struct ib_security_struct *sec = ib_sec; 67008c2ecf20Sopenharmony_ci struct lsm_ibpkey_audit ibpkey; 67018c2ecf20Sopenharmony_ci 67028c2ecf20Sopenharmony_ci err = sel_ib_pkey_sid(subnet_prefix, pkey_val, &sid); 67038c2ecf20Sopenharmony_ci if (err) 67048c2ecf20Sopenharmony_ci return err; 67058c2ecf20Sopenharmony_ci 67068c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IBPKEY; 67078c2ecf20Sopenharmony_ci ibpkey.subnet_prefix = subnet_prefix; 67088c2ecf20Sopenharmony_ci ibpkey.pkey = pkey_val; 67098c2ecf20Sopenharmony_ci ad.u.ibpkey = &ibpkey; 67108c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 67118c2ecf20Sopenharmony_ci sec->sid, sid, 67128c2ecf20Sopenharmony_ci SECCLASS_INFINIBAND_PKEY, 67138c2ecf20Sopenharmony_ci INFINIBAND_PKEY__ACCESS, &ad); 67148c2ecf20Sopenharmony_ci} 67158c2ecf20Sopenharmony_ci 67168c2ecf20Sopenharmony_cistatic int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name, 67178c2ecf20Sopenharmony_ci u8 port_num) 67188c2ecf20Sopenharmony_ci{ 67198c2ecf20Sopenharmony_ci struct common_audit_data ad; 67208c2ecf20Sopenharmony_ci int err; 67218c2ecf20Sopenharmony_ci u32 sid = 0; 67228c2ecf20Sopenharmony_ci struct ib_security_struct *sec = ib_sec; 67238c2ecf20Sopenharmony_ci struct lsm_ibendport_audit ibendport; 67248c2ecf20Sopenharmony_ci 67258c2ecf20Sopenharmony_ci err = security_ib_endport_sid(&selinux_state, dev_name, port_num, 67268c2ecf20Sopenharmony_ci &sid); 67278c2ecf20Sopenharmony_ci 67288c2ecf20Sopenharmony_ci if (err) 67298c2ecf20Sopenharmony_ci return err; 67308c2ecf20Sopenharmony_ci 67318c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_IBENDPORT; 67328c2ecf20Sopenharmony_ci strncpy(ibendport.dev_name, dev_name, sizeof(ibendport.dev_name)); 67338c2ecf20Sopenharmony_ci ibendport.port = port_num; 67348c2ecf20Sopenharmony_ci ad.u.ibendport = &ibendport; 67358c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 67368c2ecf20Sopenharmony_ci sec->sid, sid, 67378c2ecf20Sopenharmony_ci SECCLASS_INFINIBAND_ENDPORT, 67388c2ecf20Sopenharmony_ci INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad); 67398c2ecf20Sopenharmony_ci} 67408c2ecf20Sopenharmony_ci 67418c2ecf20Sopenharmony_cistatic int selinux_ib_alloc_security(void **ib_sec) 67428c2ecf20Sopenharmony_ci{ 67438c2ecf20Sopenharmony_ci struct ib_security_struct *sec; 67448c2ecf20Sopenharmony_ci 67458c2ecf20Sopenharmony_ci sec = kzalloc(sizeof(*sec), GFP_KERNEL); 67468c2ecf20Sopenharmony_ci if (!sec) 67478c2ecf20Sopenharmony_ci return -ENOMEM; 67488c2ecf20Sopenharmony_ci sec->sid = current_sid(); 67498c2ecf20Sopenharmony_ci 67508c2ecf20Sopenharmony_ci *ib_sec = sec; 67518c2ecf20Sopenharmony_ci return 0; 67528c2ecf20Sopenharmony_ci} 67538c2ecf20Sopenharmony_ci 67548c2ecf20Sopenharmony_cistatic void selinux_ib_free_security(void *ib_sec) 67558c2ecf20Sopenharmony_ci{ 67568c2ecf20Sopenharmony_ci kfree(ib_sec); 67578c2ecf20Sopenharmony_ci} 67588c2ecf20Sopenharmony_ci#endif 67598c2ecf20Sopenharmony_ci 67608c2ecf20Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 67618c2ecf20Sopenharmony_cistatic int selinux_bpf(int cmd, union bpf_attr *attr, 67628c2ecf20Sopenharmony_ci unsigned int size) 67638c2ecf20Sopenharmony_ci{ 67648c2ecf20Sopenharmony_ci u32 sid = current_sid(); 67658c2ecf20Sopenharmony_ci int ret; 67668c2ecf20Sopenharmony_ci 67678c2ecf20Sopenharmony_ci switch (cmd) { 67688c2ecf20Sopenharmony_ci case BPF_MAP_CREATE: 67698c2ecf20Sopenharmony_ci ret = avc_has_perm(&selinux_state, 67708c2ecf20Sopenharmony_ci sid, sid, SECCLASS_BPF, BPF__MAP_CREATE, 67718c2ecf20Sopenharmony_ci NULL); 67728c2ecf20Sopenharmony_ci break; 67738c2ecf20Sopenharmony_ci case BPF_PROG_LOAD: 67748c2ecf20Sopenharmony_ci ret = avc_has_perm(&selinux_state, 67758c2ecf20Sopenharmony_ci sid, sid, SECCLASS_BPF, BPF__PROG_LOAD, 67768c2ecf20Sopenharmony_ci NULL); 67778c2ecf20Sopenharmony_ci break; 67788c2ecf20Sopenharmony_ci default: 67798c2ecf20Sopenharmony_ci ret = 0; 67808c2ecf20Sopenharmony_ci break; 67818c2ecf20Sopenharmony_ci } 67828c2ecf20Sopenharmony_ci 67838c2ecf20Sopenharmony_ci return ret; 67848c2ecf20Sopenharmony_ci} 67858c2ecf20Sopenharmony_ci 67868c2ecf20Sopenharmony_cistatic u32 bpf_map_fmode_to_av(fmode_t fmode) 67878c2ecf20Sopenharmony_ci{ 67888c2ecf20Sopenharmony_ci u32 av = 0; 67898c2ecf20Sopenharmony_ci 67908c2ecf20Sopenharmony_ci if (fmode & FMODE_READ) 67918c2ecf20Sopenharmony_ci av |= BPF__MAP_READ; 67928c2ecf20Sopenharmony_ci if (fmode & FMODE_WRITE) 67938c2ecf20Sopenharmony_ci av |= BPF__MAP_WRITE; 67948c2ecf20Sopenharmony_ci return av; 67958c2ecf20Sopenharmony_ci} 67968c2ecf20Sopenharmony_ci 67978c2ecf20Sopenharmony_ci/* This function will check the file pass through unix socket or binder to see 67988c2ecf20Sopenharmony_ci * if it is a bpf related object. And apply correspinding checks on the bpf 67998c2ecf20Sopenharmony_ci * object based on the type. The bpf maps and programs, not like other files and 68008c2ecf20Sopenharmony_ci * socket, are using a shared anonymous inode inside the kernel as their inode. 68018c2ecf20Sopenharmony_ci * So checking that inode cannot identify if the process have privilege to 68028c2ecf20Sopenharmony_ci * access the bpf object and that's why we have to add this additional check in 68038c2ecf20Sopenharmony_ci * selinux_file_receive and selinux_binder_transfer_files. 68048c2ecf20Sopenharmony_ci */ 68058c2ecf20Sopenharmony_cistatic int bpf_fd_pass(struct file *file, u32 sid) 68068c2ecf20Sopenharmony_ci{ 68078c2ecf20Sopenharmony_ci struct bpf_security_struct *bpfsec; 68088c2ecf20Sopenharmony_ci struct bpf_prog *prog; 68098c2ecf20Sopenharmony_ci struct bpf_map *map; 68108c2ecf20Sopenharmony_ci int ret; 68118c2ecf20Sopenharmony_ci 68128c2ecf20Sopenharmony_ci if (file->f_op == &bpf_map_fops) { 68138c2ecf20Sopenharmony_ci map = file->private_data; 68148c2ecf20Sopenharmony_ci bpfsec = map->security; 68158c2ecf20Sopenharmony_ci ret = avc_has_perm(&selinux_state, 68168c2ecf20Sopenharmony_ci sid, bpfsec->sid, SECCLASS_BPF, 68178c2ecf20Sopenharmony_ci bpf_map_fmode_to_av(file->f_mode), NULL); 68188c2ecf20Sopenharmony_ci if (ret) 68198c2ecf20Sopenharmony_ci return ret; 68208c2ecf20Sopenharmony_ci } else if (file->f_op == &bpf_prog_fops) { 68218c2ecf20Sopenharmony_ci prog = file->private_data; 68228c2ecf20Sopenharmony_ci bpfsec = prog->aux->security; 68238c2ecf20Sopenharmony_ci ret = avc_has_perm(&selinux_state, 68248c2ecf20Sopenharmony_ci sid, bpfsec->sid, SECCLASS_BPF, 68258c2ecf20Sopenharmony_ci BPF__PROG_RUN, NULL); 68268c2ecf20Sopenharmony_ci if (ret) 68278c2ecf20Sopenharmony_ci return ret; 68288c2ecf20Sopenharmony_ci } 68298c2ecf20Sopenharmony_ci return 0; 68308c2ecf20Sopenharmony_ci} 68318c2ecf20Sopenharmony_ci 68328c2ecf20Sopenharmony_cistatic int selinux_bpf_map(struct bpf_map *map, fmode_t fmode) 68338c2ecf20Sopenharmony_ci{ 68348c2ecf20Sopenharmony_ci u32 sid = current_sid(); 68358c2ecf20Sopenharmony_ci struct bpf_security_struct *bpfsec; 68368c2ecf20Sopenharmony_ci 68378c2ecf20Sopenharmony_ci bpfsec = map->security; 68388c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 68398c2ecf20Sopenharmony_ci sid, bpfsec->sid, SECCLASS_BPF, 68408c2ecf20Sopenharmony_ci bpf_map_fmode_to_av(fmode), NULL); 68418c2ecf20Sopenharmony_ci} 68428c2ecf20Sopenharmony_ci 68438c2ecf20Sopenharmony_cistatic int selinux_bpf_prog(struct bpf_prog *prog) 68448c2ecf20Sopenharmony_ci{ 68458c2ecf20Sopenharmony_ci u32 sid = current_sid(); 68468c2ecf20Sopenharmony_ci struct bpf_security_struct *bpfsec; 68478c2ecf20Sopenharmony_ci 68488c2ecf20Sopenharmony_ci bpfsec = prog->aux->security; 68498c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 68508c2ecf20Sopenharmony_ci sid, bpfsec->sid, SECCLASS_BPF, 68518c2ecf20Sopenharmony_ci BPF__PROG_RUN, NULL); 68528c2ecf20Sopenharmony_ci} 68538c2ecf20Sopenharmony_ci 68548c2ecf20Sopenharmony_cistatic int selinux_bpf_map_alloc(struct bpf_map *map) 68558c2ecf20Sopenharmony_ci{ 68568c2ecf20Sopenharmony_ci struct bpf_security_struct *bpfsec; 68578c2ecf20Sopenharmony_ci 68588c2ecf20Sopenharmony_ci bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); 68598c2ecf20Sopenharmony_ci if (!bpfsec) 68608c2ecf20Sopenharmony_ci return -ENOMEM; 68618c2ecf20Sopenharmony_ci 68628c2ecf20Sopenharmony_ci bpfsec->sid = current_sid(); 68638c2ecf20Sopenharmony_ci map->security = bpfsec; 68648c2ecf20Sopenharmony_ci 68658c2ecf20Sopenharmony_ci return 0; 68668c2ecf20Sopenharmony_ci} 68678c2ecf20Sopenharmony_ci 68688c2ecf20Sopenharmony_cistatic void selinux_bpf_map_free(struct bpf_map *map) 68698c2ecf20Sopenharmony_ci{ 68708c2ecf20Sopenharmony_ci struct bpf_security_struct *bpfsec = map->security; 68718c2ecf20Sopenharmony_ci 68728c2ecf20Sopenharmony_ci map->security = NULL; 68738c2ecf20Sopenharmony_ci kfree(bpfsec); 68748c2ecf20Sopenharmony_ci} 68758c2ecf20Sopenharmony_ci 68768c2ecf20Sopenharmony_cistatic int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux) 68778c2ecf20Sopenharmony_ci{ 68788c2ecf20Sopenharmony_ci struct bpf_security_struct *bpfsec; 68798c2ecf20Sopenharmony_ci 68808c2ecf20Sopenharmony_ci bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); 68818c2ecf20Sopenharmony_ci if (!bpfsec) 68828c2ecf20Sopenharmony_ci return -ENOMEM; 68838c2ecf20Sopenharmony_ci 68848c2ecf20Sopenharmony_ci bpfsec->sid = current_sid(); 68858c2ecf20Sopenharmony_ci aux->security = bpfsec; 68868c2ecf20Sopenharmony_ci 68878c2ecf20Sopenharmony_ci return 0; 68888c2ecf20Sopenharmony_ci} 68898c2ecf20Sopenharmony_ci 68908c2ecf20Sopenharmony_cistatic void selinux_bpf_prog_free(struct bpf_prog_aux *aux) 68918c2ecf20Sopenharmony_ci{ 68928c2ecf20Sopenharmony_ci struct bpf_security_struct *bpfsec = aux->security; 68938c2ecf20Sopenharmony_ci 68948c2ecf20Sopenharmony_ci aux->security = NULL; 68958c2ecf20Sopenharmony_ci kfree(bpfsec); 68968c2ecf20Sopenharmony_ci} 68978c2ecf20Sopenharmony_ci#endif 68988c2ecf20Sopenharmony_ci 68998c2ecf20Sopenharmony_cistatic int selinux_lockdown(enum lockdown_reason what) 69008c2ecf20Sopenharmony_ci{ 69018c2ecf20Sopenharmony_ci struct common_audit_data ad; 69028c2ecf20Sopenharmony_ci u32 sid = current_sid(); 69038c2ecf20Sopenharmony_ci int invalid_reason = (what <= LOCKDOWN_NONE) || 69048c2ecf20Sopenharmony_ci (what == LOCKDOWN_INTEGRITY_MAX) || 69058c2ecf20Sopenharmony_ci (what >= LOCKDOWN_CONFIDENTIALITY_MAX); 69068c2ecf20Sopenharmony_ci 69078c2ecf20Sopenharmony_ci if (WARN(invalid_reason, "Invalid lockdown reason")) { 69088c2ecf20Sopenharmony_ci audit_log(audit_context(), 69098c2ecf20Sopenharmony_ci GFP_ATOMIC, AUDIT_SELINUX_ERR, 69108c2ecf20Sopenharmony_ci "lockdown_reason=invalid"); 69118c2ecf20Sopenharmony_ci return -EINVAL; 69128c2ecf20Sopenharmony_ci } 69138c2ecf20Sopenharmony_ci 69148c2ecf20Sopenharmony_ci ad.type = LSM_AUDIT_DATA_LOCKDOWN; 69158c2ecf20Sopenharmony_ci ad.u.reason = what; 69168c2ecf20Sopenharmony_ci 69178c2ecf20Sopenharmony_ci if (what <= LOCKDOWN_INTEGRITY_MAX) 69188c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 69198c2ecf20Sopenharmony_ci sid, sid, SECCLASS_LOCKDOWN, 69208c2ecf20Sopenharmony_ci LOCKDOWN__INTEGRITY, &ad); 69218c2ecf20Sopenharmony_ci else 69228c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, 69238c2ecf20Sopenharmony_ci sid, sid, SECCLASS_LOCKDOWN, 69248c2ecf20Sopenharmony_ci LOCKDOWN__CONFIDENTIALITY, &ad); 69258c2ecf20Sopenharmony_ci} 69268c2ecf20Sopenharmony_ci 69278c2ecf20Sopenharmony_cistruct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = { 69288c2ecf20Sopenharmony_ci .lbs_cred = sizeof(struct task_security_struct), 69298c2ecf20Sopenharmony_ci .lbs_file = sizeof(struct file_security_struct), 69308c2ecf20Sopenharmony_ci .lbs_inode = sizeof(struct inode_security_struct), 69318c2ecf20Sopenharmony_ci .lbs_ipc = sizeof(struct ipc_security_struct), 69328c2ecf20Sopenharmony_ci .lbs_msg_msg = sizeof(struct msg_security_struct), 69338c2ecf20Sopenharmony_ci}; 69348c2ecf20Sopenharmony_ci 69358c2ecf20Sopenharmony_ci#ifdef CONFIG_PERF_EVENTS 69368c2ecf20Sopenharmony_cistatic int selinux_perf_event_open(struct perf_event_attr *attr, int type) 69378c2ecf20Sopenharmony_ci{ 69388c2ecf20Sopenharmony_ci u32 requested, sid = current_sid(); 69398c2ecf20Sopenharmony_ci 69408c2ecf20Sopenharmony_ci if (type == PERF_SECURITY_OPEN) 69418c2ecf20Sopenharmony_ci requested = PERF_EVENT__OPEN; 69428c2ecf20Sopenharmony_ci else if (type == PERF_SECURITY_CPU) 69438c2ecf20Sopenharmony_ci requested = PERF_EVENT__CPU; 69448c2ecf20Sopenharmony_ci else if (type == PERF_SECURITY_KERNEL) 69458c2ecf20Sopenharmony_ci requested = PERF_EVENT__KERNEL; 69468c2ecf20Sopenharmony_ci else if (type == PERF_SECURITY_TRACEPOINT) 69478c2ecf20Sopenharmony_ci requested = PERF_EVENT__TRACEPOINT; 69488c2ecf20Sopenharmony_ci else 69498c2ecf20Sopenharmony_ci return -EINVAL; 69508c2ecf20Sopenharmony_ci 69518c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, sid, sid, SECCLASS_PERF_EVENT, 69528c2ecf20Sopenharmony_ci requested, NULL); 69538c2ecf20Sopenharmony_ci} 69548c2ecf20Sopenharmony_ci 69558c2ecf20Sopenharmony_cistatic int selinux_perf_event_alloc(struct perf_event *event) 69568c2ecf20Sopenharmony_ci{ 69578c2ecf20Sopenharmony_ci struct perf_event_security_struct *perfsec; 69588c2ecf20Sopenharmony_ci 69598c2ecf20Sopenharmony_ci perfsec = kzalloc(sizeof(*perfsec), GFP_KERNEL); 69608c2ecf20Sopenharmony_ci if (!perfsec) 69618c2ecf20Sopenharmony_ci return -ENOMEM; 69628c2ecf20Sopenharmony_ci 69638c2ecf20Sopenharmony_ci perfsec->sid = current_sid(); 69648c2ecf20Sopenharmony_ci event->security = perfsec; 69658c2ecf20Sopenharmony_ci 69668c2ecf20Sopenharmony_ci return 0; 69678c2ecf20Sopenharmony_ci} 69688c2ecf20Sopenharmony_ci 69698c2ecf20Sopenharmony_cistatic void selinux_perf_event_free(struct perf_event *event) 69708c2ecf20Sopenharmony_ci{ 69718c2ecf20Sopenharmony_ci struct perf_event_security_struct *perfsec = event->security; 69728c2ecf20Sopenharmony_ci 69738c2ecf20Sopenharmony_ci event->security = NULL; 69748c2ecf20Sopenharmony_ci kfree(perfsec); 69758c2ecf20Sopenharmony_ci} 69768c2ecf20Sopenharmony_ci 69778c2ecf20Sopenharmony_cistatic int selinux_perf_event_read(struct perf_event *event) 69788c2ecf20Sopenharmony_ci{ 69798c2ecf20Sopenharmony_ci struct perf_event_security_struct *perfsec = event->security; 69808c2ecf20Sopenharmony_ci u32 sid = current_sid(); 69818c2ecf20Sopenharmony_ci 69828c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, sid, perfsec->sid, 69838c2ecf20Sopenharmony_ci SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL); 69848c2ecf20Sopenharmony_ci} 69858c2ecf20Sopenharmony_ci 69868c2ecf20Sopenharmony_cistatic int selinux_perf_event_write(struct perf_event *event) 69878c2ecf20Sopenharmony_ci{ 69888c2ecf20Sopenharmony_ci struct perf_event_security_struct *perfsec = event->security; 69898c2ecf20Sopenharmony_ci u32 sid = current_sid(); 69908c2ecf20Sopenharmony_ci 69918c2ecf20Sopenharmony_ci return avc_has_perm(&selinux_state, sid, perfsec->sid, 69928c2ecf20Sopenharmony_ci SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL); 69938c2ecf20Sopenharmony_ci} 69948c2ecf20Sopenharmony_ci#endif 69958c2ecf20Sopenharmony_ci 69968c2ecf20Sopenharmony_ci/* 69978c2ecf20Sopenharmony_ci * IMPORTANT NOTE: When adding new hooks, please be careful to keep this order: 69988c2ecf20Sopenharmony_ci * 1. any hooks that don't belong to (2.) or (3.) below, 69998c2ecf20Sopenharmony_ci * 2. hooks that both access structures allocated by other hooks, and allocate 70008c2ecf20Sopenharmony_ci * structures that can be later accessed by other hooks (mostly "cloning" 70018c2ecf20Sopenharmony_ci * hooks), 70028c2ecf20Sopenharmony_ci * 3. hooks that only allocate structures that can be later accessed by other 70038c2ecf20Sopenharmony_ci * hooks ("allocating" hooks). 70048c2ecf20Sopenharmony_ci * 70058c2ecf20Sopenharmony_ci * Please follow block comment delimiters in the list to keep this order. 70068c2ecf20Sopenharmony_ci * 70078c2ecf20Sopenharmony_ci * This ordering is needed for SELinux runtime disable to work at least somewhat 70088c2ecf20Sopenharmony_ci * safely. Breaking the ordering rules above might lead to NULL pointer derefs 70098c2ecf20Sopenharmony_ci * when disabling SELinux at runtime. 70108c2ecf20Sopenharmony_ci */ 70118c2ecf20Sopenharmony_cistatic struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { 70128c2ecf20Sopenharmony_ci LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), 70138c2ecf20Sopenharmony_ci LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), 70148c2ecf20Sopenharmony_ci LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder), 70158c2ecf20Sopenharmony_ci LSM_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file), 70168c2ecf20Sopenharmony_ci 70178c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ptrace_access_check, selinux_ptrace_access_check), 70188c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ptrace_traceme, selinux_ptrace_traceme), 70198c2ecf20Sopenharmony_ci LSM_HOOK_INIT(capget, selinux_capget), 70208c2ecf20Sopenharmony_ci LSM_HOOK_INIT(capset, selinux_capset), 70218c2ecf20Sopenharmony_ci LSM_HOOK_INIT(capable, selinux_capable), 70228c2ecf20Sopenharmony_ci LSM_HOOK_INIT(quotactl, selinux_quotactl), 70238c2ecf20Sopenharmony_ci LSM_HOOK_INIT(quota_on, selinux_quota_on), 70248c2ecf20Sopenharmony_ci LSM_HOOK_INIT(syslog, selinux_syslog), 70258c2ecf20Sopenharmony_ci LSM_HOOK_INIT(vm_enough_memory, selinux_vm_enough_memory), 70268c2ecf20Sopenharmony_ci 70278c2ecf20Sopenharmony_ci LSM_HOOK_INIT(netlink_send, selinux_netlink_send), 70288c2ecf20Sopenharmony_ci 70298c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bprm_creds_for_exec, selinux_bprm_creds_for_exec), 70308c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds), 70318c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds), 70328c2ecf20Sopenharmony_ci 70338c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_free_security, selinux_sb_free_security), 70348c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts), 70358c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_remount, selinux_sb_remount), 70368c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount), 70378c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options), 70388c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs), 70398c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_mount, selinux_mount), 70408c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_umount, selinux_umount), 70418c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts), 70428c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts), 70438c2ecf20Sopenharmony_ci 70448c2ecf20Sopenharmony_ci LSM_HOOK_INIT(move_mount, selinux_move_mount), 70458c2ecf20Sopenharmony_ci 70468c2ecf20Sopenharmony_ci LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security), 70478c2ecf20Sopenharmony_ci LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as), 70488c2ecf20Sopenharmony_ci 70498c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security), 70508c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security), 70518c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_create, selinux_inode_create), 70528c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_link, selinux_inode_link), 70538c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink), 70548c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_symlink, selinux_inode_symlink), 70558c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_mkdir, selinux_inode_mkdir), 70568c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_rmdir, selinux_inode_rmdir), 70578c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_mknod, selinux_inode_mknod), 70588c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_rename, selinux_inode_rename), 70598c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_readlink, selinux_inode_readlink), 70608c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_follow_link, selinux_inode_follow_link), 70618c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_permission, selinux_inode_permission), 70628c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr), 70638c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr), 70648c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr), 70658c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr), 70668c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr), 70678c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr), 70688c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr), 70698c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity), 70708c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity), 70718c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity), 70728c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid), 70738c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up), 70748c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr), 70758c2ecf20Sopenharmony_ci LSM_HOOK_INIT(path_notify, selinux_path_notify), 70768c2ecf20Sopenharmony_ci 70778c2ecf20Sopenharmony_ci LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security), 70788c2ecf20Sopenharmony_ci 70798c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_permission, selinux_file_permission), 70808c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security), 70818c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl), 70828c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat), 70838c2ecf20Sopenharmony_ci LSM_HOOK_INIT(mmap_file, selinux_mmap_file), 70848c2ecf20Sopenharmony_ci LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr), 70858c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect), 70868c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_lock, selinux_file_lock), 70878c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_fcntl, selinux_file_fcntl), 70888c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_set_fowner, selinux_file_set_fowner), 70898c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_send_sigiotask, selinux_file_send_sigiotask), 70908c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_receive, selinux_file_receive), 70918c2ecf20Sopenharmony_ci 70928c2ecf20Sopenharmony_ci LSM_HOOK_INIT(file_open, selinux_file_open), 70938c2ecf20Sopenharmony_ci 70948c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_alloc, selinux_task_alloc), 70958c2ecf20Sopenharmony_ci LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare), 70968c2ecf20Sopenharmony_ci LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer), 70978c2ecf20Sopenharmony_ci LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid), 70988c2ecf20Sopenharmony_ci LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as), 70998c2ecf20Sopenharmony_ci LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as), 71008c2ecf20Sopenharmony_ci LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request), 71018c2ecf20Sopenharmony_ci LSM_HOOK_INIT(kernel_load_data, selinux_kernel_load_data), 71028c2ecf20Sopenharmony_ci LSM_HOOK_INIT(kernel_read_file, selinux_kernel_read_file), 71038c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid), 71048c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid), 71058c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_getsid, selinux_task_getsid), 71068c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_getsecid, selinux_task_getsecid), 71078c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_setnice, selinux_task_setnice), 71088c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio), 71098c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio), 71108c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_prlimit, selinux_task_prlimit), 71118c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_setrlimit, selinux_task_setrlimit), 71128c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_setscheduler, selinux_task_setscheduler), 71138c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler), 71148c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_movememory, selinux_task_movememory), 71158c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_kill, selinux_task_kill), 71168c2ecf20Sopenharmony_ci LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode), 71178c2ecf20Sopenharmony_ci 71188c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission), 71198c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid), 71208c2ecf20Sopenharmony_ci 71218c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate), 71228c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl), 71238c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd), 71248c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv), 71258c2ecf20Sopenharmony_ci 71268c2ecf20Sopenharmony_ci LSM_HOOK_INIT(shm_associate, selinux_shm_associate), 71278c2ecf20Sopenharmony_ci LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl), 71288c2ecf20Sopenharmony_ci LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat), 71298c2ecf20Sopenharmony_ci 71308c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sem_associate, selinux_sem_associate), 71318c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl), 71328c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sem_semop, selinux_sem_semop), 71338c2ecf20Sopenharmony_ci 71348c2ecf20Sopenharmony_ci LSM_HOOK_INIT(d_instantiate, selinux_d_instantiate), 71358c2ecf20Sopenharmony_ci 71368c2ecf20Sopenharmony_ci LSM_HOOK_INIT(getprocattr, selinux_getprocattr), 71378c2ecf20Sopenharmony_ci LSM_HOOK_INIT(setprocattr, selinux_setprocattr), 71388c2ecf20Sopenharmony_ci 71398c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel), 71408c2ecf20Sopenharmony_ci LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid), 71418c2ecf20Sopenharmony_ci LSM_HOOK_INIT(release_secctx, selinux_release_secctx), 71428c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx), 71438c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx), 71448c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx), 71458c2ecf20Sopenharmony_ci 71468c2ecf20Sopenharmony_ci LSM_HOOK_INIT(unix_stream_connect, selinux_socket_unix_stream_connect), 71478c2ecf20Sopenharmony_ci LSM_HOOK_INIT(unix_may_send, selinux_socket_unix_may_send), 71488c2ecf20Sopenharmony_ci 71498c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_create, selinux_socket_create), 71508c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_post_create, selinux_socket_post_create), 71518c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_socketpair, selinux_socket_socketpair), 71528c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_bind, selinux_socket_bind), 71538c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_connect, selinux_socket_connect), 71548c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_listen, selinux_socket_listen), 71558c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_accept, selinux_socket_accept), 71568c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_sendmsg, selinux_socket_sendmsg), 71578c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_recvmsg, selinux_socket_recvmsg), 71588c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_getsockname, selinux_socket_getsockname), 71598c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_getpeername, selinux_socket_getpeername), 71608c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt), 71618c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt), 71628c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_shutdown, selinux_socket_shutdown), 71638c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb), 71648c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_getpeersec_stream, 71658c2ecf20Sopenharmony_ci selinux_socket_getpeersec_stream), 71668c2ecf20Sopenharmony_ci LSM_HOOK_INIT(socket_getpeersec_dgram, selinux_socket_getpeersec_dgram), 71678c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sk_free_security, selinux_sk_free_security), 71688c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security), 71698c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid), 71708c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sock_graft, selinux_sock_graft), 71718c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request), 71728c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone), 71738c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect), 71748c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request), 71758c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone), 71768c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established), 71778c2ecf20Sopenharmony_ci LSM_HOOK_INIT(secmark_relabel_packet, selinux_secmark_relabel_packet), 71788c2ecf20Sopenharmony_ci LSM_HOOK_INIT(secmark_refcount_inc, selinux_secmark_refcount_inc), 71798c2ecf20Sopenharmony_ci LSM_HOOK_INIT(secmark_refcount_dec, selinux_secmark_refcount_dec), 71808c2ecf20Sopenharmony_ci LSM_HOOK_INIT(req_classify_flow, selinux_req_classify_flow), 71818c2ecf20Sopenharmony_ci LSM_HOOK_INIT(tun_dev_free_security, selinux_tun_dev_free_security), 71828c2ecf20Sopenharmony_ci LSM_HOOK_INIT(tun_dev_create, selinux_tun_dev_create), 71838c2ecf20Sopenharmony_ci LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue), 71848c2ecf20Sopenharmony_ci LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach), 71858c2ecf20Sopenharmony_ci LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open), 71868c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_INFINIBAND 71878c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access), 71888c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ib_endport_manage_subnet, 71898c2ecf20Sopenharmony_ci selinux_ib_endport_manage_subnet), 71908c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ib_free_security, selinux_ib_free_security), 71918c2ecf20Sopenharmony_ci#endif 71928c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK_XFRM 71938c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_policy_free_security, selinux_xfrm_policy_free), 71948c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_policy_delete_security, selinux_xfrm_policy_delete), 71958c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_state_free_security, selinux_xfrm_state_free), 71968c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_state_delete_security, selinux_xfrm_state_delete), 71978c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_policy_lookup, selinux_xfrm_policy_lookup), 71988c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_state_pol_flow_match, 71998c2ecf20Sopenharmony_ci selinux_xfrm_state_pol_flow_match), 72008c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_decode_session, selinux_xfrm_decode_session), 72018c2ecf20Sopenharmony_ci#endif 72028c2ecf20Sopenharmony_ci 72038c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 72048c2ecf20Sopenharmony_ci LSM_HOOK_INIT(key_free, selinux_key_free), 72058c2ecf20Sopenharmony_ci LSM_HOOK_INIT(key_permission, selinux_key_permission), 72068c2ecf20Sopenharmony_ci LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity), 72078c2ecf20Sopenharmony_ci#ifdef CONFIG_KEY_NOTIFICATIONS 72088c2ecf20Sopenharmony_ci LSM_HOOK_INIT(watch_key, selinux_watch_key), 72098c2ecf20Sopenharmony_ci#endif 72108c2ecf20Sopenharmony_ci#endif 72118c2ecf20Sopenharmony_ci 72128c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 72138c2ecf20Sopenharmony_ci LSM_HOOK_INIT(audit_rule_known, selinux_audit_rule_known), 72148c2ecf20Sopenharmony_ci LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match), 72158c2ecf20Sopenharmony_ci LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free), 72168c2ecf20Sopenharmony_ci#endif 72178c2ecf20Sopenharmony_ci 72188c2ecf20Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 72198c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bpf, selinux_bpf), 72208c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bpf_map, selinux_bpf_map), 72218c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), 72228c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), 72238c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free), 72248c2ecf20Sopenharmony_ci#endif 72258c2ecf20Sopenharmony_ci 72268c2ecf20Sopenharmony_ci#ifdef CONFIG_PERF_EVENTS 72278c2ecf20Sopenharmony_ci LSM_HOOK_INIT(perf_event_open, selinux_perf_event_open), 72288c2ecf20Sopenharmony_ci LSM_HOOK_INIT(perf_event_free, selinux_perf_event_free), 72298c2ecf20Sopenharmony_ci LSM_HOOK_INIT(perf_event_read, selinux_perf_event_read), 72308c2ecf20Sopenharmony_ci LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write), 72318c2ecf20Sopenharmony_ci#endif 72328c2ecf20Sopenharmony_ci 72338c2ecf20Sopenharmony_ci LSM_HOOK_INIT(locked_down, selinux_lockdown), 72348c2ecf20Sopenharmony_ci 72358c2ecf20Sopenharmony_ci /* 72368c2ecf20Sopenharmony_ci * PUT "CLONING" (ACCESSING + ALLOCATING) HOOKS HERE 72378c2ecf20Sopenharmony_ci */ 72388c2ecf20Sopenharmony_ci LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup), 72398c2ecf20Sopenharmony_ci LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param), 72408c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts), 72418c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_add_mnt_opt, selinux_add_mnt_opt), 72428c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK_XFRM 72438c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone), 72448c2ecf20Sopenharmony_ci#endif 72458c2ecf20Sopenharmony_ci 72468c2ecf20Sopenharmony_ci /* 72478c2ecf20Sopenharmony_ci * PUT "ALLOCATING" HOOKS HERE 72488c2ecf20Sopenharmony_ci */ 72498c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security), 72508c2ecf20Sopenharmony_ci LSM_HOOK_INIT(msg_queue_alloc_security, 72518c2ecf20Sopenharmony_ci selinux_msg_queue_alloc_security), 72528c2ecf20Sopenharmony_ci LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security), 72538c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security), 72548c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security), 72558c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security), 72568c2ecf20Sopenharmony_ci LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx), 72578c2ecf20Sopenharmony_ci LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx), 72588c2ecf20Sopenharmony_ci LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security), 72598c2ecf20Sopenharmony_ci LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security), 72608c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_INFINIBAND 72618c2ecf20Sopenharmony_ci LSM_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security), 72628c2ecf20Sopenharmony_ci#endif 72638c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK_XFRM 72648c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc), 72658c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_state_alloc, selinux_xfrm_state_alloc), 72668c2ecf20Sopenharmony_ci LSM_HOOK_INIT(xfrm_state_alloc_acquire, 72678c2ecf20Sopenharmony_ci selinux_xfrm_state_alloc_acquire), 72688c2ecf20Sopenharmony_ci#endif 72698c2ecf20Sopenharmony_ci#ifdef CONFIG_KEYS 72708c2ecf20Sopenharmony_ci LSM_HOOK_INIT(key_alloc, selinux_key_alloc), 72718c2ecf20Sopenharmony_ci#endif 72728c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT 72738c2ecf20Sopenharmony_ci LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init), 72748c2ecf20Sopenharmony_ci#endif 72758c2ecf20Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL 72768c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc), 72778c2ecf20Sopenharmony_ci LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc), 72788c2ecf20Sopenharmony_ci#endif 72798c2ecf20Sopenharmony_ci#ifdef CONFIG_PERF_EVENTS 72808c2ecf20Sopenharmony_ci LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc), 72818c2ecf20Sopenharmony_ci#endif 72828c2ecf20Sopenharmony_ci}; 72838c2ecf20Sopenharmony_ci 72848c2ecf20Sopenharmony_cistatic __init int selinux_init(void) 72858c2ecf20Sopenharmony_ci{ 72868c2ecf20Sopenharmony_ci pr_info("SELinux: Initializing.\n"); 72878c2ecf20Sopenharmony_ci 72888c2ecf20Sopenharmony_ci memset(&selinux_state, 0, sizeof(selinux_state)); 72898c2ecf20Sopenharmony_ci enforcing_set(&selinux_state, selinux_enforcing_boot); 72908c2ecf20Sopenharmony_ci checkreqprot_set(&selinux_state, selinux_checkreqprot_boot); 72918c2ecf20Sopenharmony_ci selinux_avc_init(&selinux_state.avc); 72928c2ecf20Sopenharmony_ci mutex_init(&selinux_state.status_lock); 72938c2ecf20Sopenharmony_ci mutex_init(&selinux_state.policy_mutex); 72948c2ecf20Sopenharmony_ci 72958c2ecf20Sopenharmony_ci /* Set the security state for the initial task. */ 72968c2ecf20Sopenharmony_ci cred_init_security(); 72978c2ecf20Sopenharmony_ci 72988c2ecf20Sopenharmony_ci default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC); 72998c2ecf20Sopenharmony_ci 73008c2ecf20Sopenharmony_ci avc_init(); 73018c2ecf20Sopenharmony_ci 73028c2ecf20Sopenharmony_ci avtab_cache_init(); 73038c2ecf20Sopenharmony_ci 73048c2ecf20Sopenharmony_ci ebitmap_cache_init(); 73058c2ecf20Sopenharmony_ci 73068c2ecf20Sopenharmony_ci hashtab_cache_init(); 73078c2ecf20Sopenharmony_ci 73088c2ecf20Sopenharmony_ci security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux"); 73098c2ecf20Sopenharmony_ci 73108c2ecf20Sopenharmony_ci if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET)) 73118c2ecf20Sopenharmony_ci panic("SELinux: Unable to register AVC netcache callback\n"); 73128c2ecf20Sopenharmony_ci 73138c2ecf20Sopenharmony_ci if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET)) 73148c2ecf20Sopenharmony_ci panic("SELinux: Unable to register AVC LSM notifier callback\n"); 73158c2ecf20Sopenharmony_ci 73168c2ecf20Sopenharmony_ci if (selinux_enforcing_boot) 73178c2ecf20Sopenharmony_ci pr_debug("SELinux: Starting in enforcing mode\n"); 73188c2ecf20Sopenharmony_ci else 73198c2ecf20Sopenharmony_ci pr_debug("SELinux: Starting in permissive mode\n"); 73208c2ecf20Sopenharmony_ci 73218c2ecf20Sopenharmony_ci fs_validate_description("selinux", selinux_fs_parameters); 73228c2ecf20Sopenharmony_ci 73238c2ecf20Sopenharmony_ci return 0; 73248c2ecf20Sopenharmony_ci} 73258c2ecf20Sopenharmony_ci 73268c2ecf20Sopenharmony_cistatic void delayed_superblock_init(struct super_block *sb, void *unused) 73278c2ecf20Sopenharmony_ci{ 73288c2ecf20Sopenharmony_ci selinux_set_mnt_opts(sb, NULL, 0, NULL); 73298c2ecf20Sopenharmony_ci} 73308c2ecf20Sopenharmony_ci 73318c2ecf20Sopenharmony_civoid selinux_complete_init(void) 73328c2ecf20Sopenharmony_ci{ 73338c2ecf20Sopenharmony_ci pr_debug("SELinux: Completing initialization.\n"); 73348c2ecf20Sopenharmony_ci 73358c2ecf20Sopenharmony_ci /* Set up any superblocks initialized prior to the policy load. */ 73368c2ecf20Sopenharmony_ci pr_debug("SELinux: Setting up existing superblocks.\n"); 73378c2ecf20Sopenharmony_ci iterate_supers(delayed_superblock_init, NULL); 73388c2ecf20Sopenharmony_ci} 73398c2ecf20Sopenharmony_ci 73408c2ecf20Sopenharmony_ci/* SELinux requires early initialization in order to label 73418c2ecf20Sopenharmony_ci all processes and objects when they are created. */ 73428c2ecf20Sopenharmony_ciDEFINE_LSM(selinux) = { 73438c2ecf20Sopenharmony_ci .name = "selinux", 73448c2ecf20Sopenharmony_ci .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, 73458c2ecf20Sopenharmony_ci .enabled = &selinux_enabled_boot, 73468c2ecf20Sopenharmony_ci .blobs = &selinux_blob_sizes, 73478c2ecf20Sopenharmony_ci .init = selinux_init, 73488c2ecf20Sopenharmony_ci}; 73498c2ecf20Sopenharmony_ci 73508c2ecf20Sopenharmony_ci#if defined(CONFIG_NETFILTER) 73518c2ecf20Sopenharmony_ci 73528c2ecf20Sopenharmony_cistatic const struct nf_hook_ops selinux_nf_ops[] = { 73538c2ecf20Sopenharmony_ci { 73548c2ecf20Sopenharmony_ci .hook = selinux_ipv4_postroute, 73558c2ecf20Sopenharmony_ci .pf = NFPROTO_IPV4, 73568c2ecf20Sopenharmony_ci .hooknum = NF_INET_POST_ROUTING, 73578c2ecf20Sopenharmony_ci .priority = NF_IP_PRI_SELINUX_LAST, 73588c2ecf20Sopenharmony_ci }, 73598c2ecf20Sopenharmony_ci { 73608c2ecf20Sopenharmony_ci .hook = selinux_ipv4_forward, 73618c2ecf20Sopenharmony_ci .pf = NFPROTO_IPV4, 73628c2ecf20Sopenharmony_ci .hooknum = NF_INET_FORWARD, 73638c2ecf20Sopenharmony_ci .priority = NF_IP_PRI_SELINUX_FIRST, 73648c2ecf20Sopenharmony_ci }, 73658c2ecf20Sopenharmony_ci { 73668c2ecf20Sopenharmony_ci .hook = selinux_ipv4_output, 73678c2ecf20Sopenharmony_ci .pf = NFPROTO_IPV4, 73688c2ecf20Sopenharmony_ci .hooknum = NF_INET_LOCAL_OUT, 73698c2ecf20Sopenharmony_ci .priority = NF_IP_PRI_SELINUX_FIRST, 73708c2ecf20Sopenharmony_ci }, 73718c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 73728c2ecf20Sopenharmony_ci { 73738c2ecf20Sopenharmony_ci .hook = selinux_ipv6_postroute, 73748c2ecf20Sopenharmony_ci .pf = NFPROTO_IPV6, 73758c2ecf20Sopenharmony_ci .hooknum = NF_INET_POST_ROUTING, 73768c2ecf20Sopenharmony_ci .priority = NF_IP6_PRI_SELINUX_LAST, 73778c2ecf20Sopenharmony_ci }, 73788c2ecf20Sopenharmony_ci { 73798c2ecf20Sopenharmony_ci .hook = selinux_ipv6_forward, 73808c2ecf20Sopenharmony_ci .pf = NFPROTO_IPV6, 73818c2ecf20Sopenharmony_ci .hooknum = NF_INET_FORWARD, 73828c2ecf20Sopenharmony_ci .priority = NF_IP6_PRI_SELINUX_FIRST, 73838c2ecf20Sopenharmony_ci }, 73848c2ecf20Sopenharmony_ci { 73858c2ecf20Sopenharmony_ci .hook = selinux_ipv6_output, 73868c2ecf20Sopenharmony_ci .pf = NFPROTO_IPV6, 73878c2ecf20Sopenharmony_ci .hooknum = NF_INET_LOCAL_OUT, 73888c2ecf20Sopenharmony_ci .priority = NF_IP6_PRI_SELINUX_FIRST, 73898c2ecf20Sopenharmony_ci }, 73908c2ecf20Sopenharmony_ci#endif /* IPV6 */ 73918c2ecf20Sopenharmony_ci}; 73928c2ecf20Sopenharmony_ci 73938c2ecf20Sopenharmony_cistatic int __net_init selinux_nf_register(struct net *net) 73948c2ecf20Sopenharmony_ci{ 73958c2ecf20Sopenharmony_ci return nf_register_net_hooks(net, selinux_nf_ops, 73968c2ecf20Sopenharmony_ci ARRAY_SIZE(selinux_nf_ops)); 73978c2ecf20Sopenharmony_ci} 73988c2ecf20Sopenharmony_ci 73998c2ecf20Sopenharmony_cistatic void __net_exit selinux_nf_unregister(struct net *net) 74008c2ecf20Sopenharmony_ci{ 74018c2ecf20Sopenharmony_ci nf_unregister_net_hooks(net, selinux_nf_ops, 74028c2ecf20Sopenharmony_ci ARRAY_SIZE(selinux_nf_ops)); 74038c2ecf20Sopenharmony_ci} 74048c2ecf20Sopenharmony_ci 74058c2ecf20Sopenharmony_cistatic struct pernet_operations selinux_net_ops = { 74068c2ecf20Sopenharmony_ci .init = selinux_nf_register, 74078c2ecf20Sopenharmony_ci .exit = selinux_nf_unregister, 74088c2ecf20Sopenharmony_ci}; 74098c2ecf20Sopenharmony_ci 74108c2ecf20Sopenharmony_cistatic int __init selinux_nf_ip_init(void) 74118c2ecf20Sopenharmony_ci{ 74128c2ecf20Sopenharmony_ci int err; 74138c2ecf20Sopenharmony_ci 74148c2ecf20Sopenharmony_ci if (!selinux_enabled_boot) 74158c2ecf20Sopenharmony_ci return 0; 74168c2ecf20Sopenharmony_ci 74178c2ecf20Sopenharmony_ci pr_debug("SELinux: Registering netfilter hooks\n"); 74188c2ecf20Sopenharmony_ci 74198c2ecf20Sopenharmony_ci err = register_pernet_subsys(&selinux_net_ops); 74208c2ecf20Sopenharmony_ci if (err) 74218c2ecf20Sopenharmony_ci panic("SELinux: register_pernet_subsys: error %d\n", err); 74228c2ecf20Sopenharmony_ci 74238c2ecf20Sopenharmony_ci return 0; 74248c2ecf20Sopenharmony_ci} 74258c2ecf20Sopenharmony_ci__initcall(selinux_nf_ip_init); 74268c2ecf20Sopenharmony_ci 74278c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SELINUX_DISABLE 74288c2ecf20Sopenharmony_cistatic void selinux_nf_ip_exit(void) 74298c2ecf20Sopenharmony_ci{ 74308c2ecf20Sopenharmony_ci pr_debug("SELinux: Unregistering netfilter hooks\n"); 74318c2ecf20Sopenharmony_ci 74328c2ecf20Sopenharmony_ci unregister_pernet_subsys(&selinux_net_ops); 74338c2ecf20Sopenharmony_ci} 74348c2ecf20Sopenharmony_ci#endif 74358c2ecf20Sopenharmony_ci 74368c2ecf20Sopenharmony_ci#else /* CONFIG_NETFILTER */ 74378c2ecf20Sopenharmony_ci 74388c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SELINUX_DISABLE 74398c2ecf20Sopenharmony_ci#define selinux_nf_ip_exit() 74408c2ecf20Sopenharmony_ci#endif 74418c2ecf20Sopenharmony_ci 74428c2ecf20Sopenharmony_ci#endif /* CONFIG_NETFILTER */ 74438c2ecf20Sopenharmony_ci 74448c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_SELINUX_DISABLE 74458c2ecf20Sopenharmony_ciint selinux_disable(struct selinux_state *state) 74468c2ecf20Sopenharmony_ci{ 74478c2ecf20Sopenharmony_ci if (selinux_initialized(state)) { 74488c2ecf20Sopenharmony_ci /* Not permitted after initial policy load. */ 74498c2ecf20Sopenharmony_ci return -EINVAL; 74508c2ecf20Sopenharmony_ci } 74518c2ecf20Sopenharmony_ci 74528c2ecf20Sopenharmony_ci if (selinux_disabled(state)) { 74538c2ecf20Sopenharmony_ci /* Only do this once. */ 74548c2ecf20Sopenharmony_ci return -EINVAL; 74558c2ecf20Sopenharmony_ci } 74568c2ecf20Sopenharmony_ci 74578c2ecf20Sopenharmony_ci selinux_mark_disabled(state); 74588c2ecf20Sopenharmony_ci 74598c2ecf20Sopenharmony_ci pr_info("SELinux: Disabled at runtime.\n"); 74608c2ecf20Sopenharmony_ci 74618c2ecf20Sopenharmony_ci /* 74628c2ecf20Sopenharmony_ci * Unregister netfilter hooks. 74638c2ecf20Sopenharmony_ci * Must be done before security_delete_hooks() to avoid breaking 74648c2ecf20Sopenharmony_ci * runtime disable. 74658c2ecf20Sopenharmony_ci */ 74668c2ecf20Sopenharmony_ci selinux_nf_ip_exit(); 74678c2ecf20Sopenharmony_ci 74688c2ecf20Sopenharmony_ci security_delete_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks)); 74698c2ecf20Sopenharmony_ci 74708c2ecf20Sopenharmony_ci /* Try to destroy the avc node cache */ 74718c2ecf20Sopenharmony_ci avc_disable(); 74728c2ecf20Sopenharmony_ci 74738c2ecf20Sopenharmony_ci /* Unregister selinuxfs. */ 74748c2ecf20Sopenharmony_ci exit_sel_fs(); 74758c2ecf20Sopenharmony_ci 74768c2ecf20Sopenharmony_ci return 0; 74778c2ecf20Sopenharmony_ci} 74788c2ecf20Sopenharmony_ci#endif 7479