162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  Security-Enhanced Linux (SELinux) security module
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  This file contains the SELinux hook function implementations.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *  Authors:  Stephen Smalley, <stephen.smalley.work@gmail.com>
862306a36Sopenharmony_ci *	      Chris Vance, <cvance@nai.com>
962306a36Sopenharmony_ci *	      Wayne Salamon, <wsalamon@nai.com>
1062306a36Sopenharmony_ci *	      James Morris <jmorris@redhat.com>
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *  Copyright (C) 2001,2002 Networks Associates Technology, Inc.
1362306a36Sopenharmony_ci *  Copyright (C) 2003-2008 Red Hat, Inc., James Morris <jmorris@redhat.com>
1462306a36Sopenharmony_ci *					   Eric Paris <eparis@redhat.com>
1562306a36Sopenharmony_ci *  Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
1662306a36Sopenharmony_ci *			    <dgoeddel@trustedcs.com>
1762306a36Sopenharmony_ci *  Copyright (C) 2006, 2007, 2009 Hewlett-Packard Development Company, L.P.
1862306a36Sopenharmony_ci *	Paul Moore <paul@paul-moore.com>
1962306a36Sopenharmony_ci *  Copyright (C) 2007 Hitachi Software Engineering Co., Ltd.
2062306a36Sopenharmony_ci *		       Yuichi Nakamura <ynakam@hitachisoft.jp>
2162306a36Sopenharmony_ci *  Copyright (C) 2016 Mellanox Technologies
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#include <linux/init.h>
2562306a36Sopenharmony_ci#include <linux/kd.h>
2662306a36Sopenharmony_ci#include <linux/kernel.h>
2762306a36Sopenharmony_ci#include <linux/kernel_read_file.h>
2862306a36Sopenharmony_ci#include <linux/errno.h>
2962306a36Sopenharmony_ci#include <linux/sched/signal.h>
3062306a36Sopenharmony_ci#include <linux/sched/task.h>
3162306a36Sopenharmony_ci#include <linux/lsm_hooks.h>
3262306a36Sopenharmony_ci#include <linux/xattr.h>
3362306a36Sopenharmony_ci#include <linux/capability.h>
3462306a36Sopenharmony_ci#include <linux/unistd.h>
3562306a36Sopenharmony_ci#include <linux/mm.h>
3662306a36Sopenharmony_ci#include <linux/mman.h>
3762306a36Sopenharmony_ci#include <linux/slab.h>
3862306a36Sopenharmony_ci#include <linux/pagemap.h>
3962306a36Sopenharmony_ci#include <linux/proc_fs.h>
4062306a36Sopenharmony_ci#include <linux/swap.h>
4162306a36Sopenharmony_ci#include <linux/spinlock.h>
4262306a36Sopenharmony_ci#include <linux/syscalls.h>
4362306a36Sopenharmony_ci#include <linux/dcache.h>
4462306a36Sopenharmony_ci#include <linux/file.h>
4562306a36Sopenharmony_ci#include <linux/fdtable.h>
4662306a36Sopenharmony_ci#include <linux/namei.h>
4762306a36Sopenharmony_ci#include <linux/mount.h>
4862306a36Sopenharmony_ci#include <linux/fs_context.h>
4962306a36Sopenharmony_ci#include <linux/fs_parser.h>
5062306a36Sopenharmony_ci#include <linux/netfilter_ipv4.h>
5162306a36Sopenharmony_ci#include <linux/netfilter_ipv6.h>
5262306a36Sopenharmony_ci#include <linux/tty.h>
5362306a36Sopenharmony_ci#include <net/icmp.h>
5462306a36Sopenharmony_ci#include <net/ip.h>		/* for local_port_range[] */
5562306a36Sopenharmony_ci#include <net/tcp.h>		/* struct or_callable used in sock_rcv_skb */
5662306a36Sopenharmony_ci#include <net/inet_connection_sock.h>
5762306a36Sopenharmony_ci#include <net/net_namespace.h>
5862306a36Sopenharmony_ci#include <net/netlabel.h>
5962306a36Sopenharmony_ci#include <linux/uaccess.h>
6062306a36Sopenharmony_ci#include <asm/ioctls.h>
6162306a36Sopenharmony_ci#include <linux/atomic.h>
6262306a36Sopenharmony_ci#include <linux/bitops.h>
6362306a36Sopenharmony_ci#include <linux/interrupt.h>
6462306a36Sopenharmony_ci#include <linux/netdevice.h>	/* for network interface checks */
6562306a36Sopenharmony_ci#include <net/netlink.h>
6662306a36Sopenharmony_ci#include <linux/tcp.h>
6762306a36Sopenharmony_ci#include <linux/udp.h>
6862306a36Sopenharmony_ci#include <linux/dccp.h>
6962306a36Sopenharmony_ci#include <linux/sctp.h>
7062306a36Sopenharmony_ci#include <net/sctp/structs.h>
7162306a36Sopenharmony_ci#include <linux/quota.h>
7262306a36Sopenharmony_ci#include <linux/un.h>		/* for Unix socket types */
7362306a36Sopenharmony_ci#include <net/af_unix.h>	/* for Unix socket types */
7462306a36Sopenharmony_ci#include <linux/parser.h>
7562306a36Sopenharmony_ci#include <linux/nfs_mount.h>
7662306a36Sopenharmony_ci#include <net/ipv6.h>
7762306a36Sopenharmony_ci#include <linux/hugetlb.h>
7862306a36Sopenharmony_ci#include <linux/personality.h>
7962306a36Sopenharmony_ci#include <linux/audit.h>
8062306a36Sopenharmony_ci#include <linux/string.h>
8162306a36Sopenharmony_ci#include <linux/mutex.h>
8262306a36Sopenharmony_ci#include <linux/posix-timers.h>
8362306a36Sopenharmony_ci#include <linux/syslog.h>
8462306a36Sopenharmony_ci#include <linux/user_namespace.h>
8562306a36Sopenharmony_ci#include <linux/export.h>
8662306a36Sopenharmony_ci#include <linux/msg.h>
8762306a36Sopenharmony_ci#include <linux/shm.h>
8862306a36Sopenharmony_ci#include <linux/bpf.h>
8962306a36Sopenharmony_ci#include <linux/kernfs.h>
9062306a36Sopenharmony_ci#include <linux/stringhash.h>	/* for hashlen_string() */
9162306a36Sopenharmony_ci#include <uapi/linux/mount.h>
9262306a36Sopenharmony_ci#include <linux/fsnotify.h>
9362306a36Sopenharmony_ci#include <linux/fanotify.h>
9462306a36Sopenharmony_ci#include <linux/io_uring.h>
9562306a36Sopenharmony_ci#include <linux/hck/lite_hck_ced.h>
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci#include "avc.h"
9862306a36Sopenharmony_ci#include "objsec.h"
9962306a36Sopenharmony_ci#include "netif.h"
10062306a36Sopenharmony_ci#include "netnode.h"
10162306a36Sopenharmony_ci#include "netport.h"
10262306a36Sopenharmony_ci#include "ibpkey.h"
10362306a36Sopenharmony_ci#include "xfrm.h"
10462306a36Sopenharmony_ci#include "netlabel.h"
10562306a36Sopenharmony_ci#include "audit.h"
10662306a36Sopenharmony_ci#include "avc_ss.h"
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci#define SELINUX_INODE_INIT_XATTRS 1
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistruct selinux_state selinux_state;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci/* SECMARK reference count */
11362306a36Sopenharmony_cistatic atomic_t selinux_secmark_refcount = ATOMIC_INIT(0);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
11662306a36Sopenharmony_cistatic int selinux_enforcing_boot __initdata;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic int __init enforcing_setup(char *str)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	unsigned long enforcing;
12162306a36Sopenharmony_ci	if (!kstrtoul(str, 0, &enforcing))
12262306a36Sopenharmony_ci		selinux_enforcing_boot = enforcing ? 1 : 0;
12362306a36Sopenharmony_ci	return 1;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ci__setup("enforcing=", enforcing_setup);
12662306a36Sopenharmony_ci#else
12762306a36Sopenharmony_ci#define selinux_enforcing_boot 1
12862306a36Sopenharmony_ci#endif
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ciint selinux_enabled_boot __initdata = 1;
13162306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_SELINUX_BOOTPARAM
13262306a36Sopenharmony_cistatic int __init selinux_enabled_setup(char *str)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	unsigned long enabled;
13562306a36Sopenharmony_ci	if (!kstrtoul(str, 0, &enabled))
13662306a36Sopenharmony_ci		selinux_enabled_boot = enabled ? 1 : 0;
13762306a36Sopenharmony_ci	return 1;
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci__setup("selinux=", selinux_enabled_setup);
14062306a36Sopenharmony_ci#endif
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic int __init checkreqprot_setup(char *str)
14362306a36Sopenharmony_ci{
14462306a36Sopenharmony_ci	unsigned long checkreqprot;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	if (!kstrtoul(str, 0, &checkreqprot)) {
14762306a36Sopenharmony_ci		if (checkreqprot)
14862306a36Sopenharmony_ci			pr_err("SELinux: checkreqprot set to 1 via kernel parameter.  This is no longer supported.\n");
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci	return 1;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci__setup("checkreqprot=", checkreqprot_setup);
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/**
15562306a36Sopenharmony_ci * selinux_secmark_enabled - Check to see if SECMARK is currently enabled
15662306a36Sopenharmony_ci *
15762306a36Sopenharmony_ci * Description:
15862306a36Sopenharmony_ci * This function checks the SECMARK reference counter to see if any SECMARK
15962306a36Sopenharmony_ci * targets are currently configured, if the reference counter is greater than
16062306a36Sopenharmony_ci * zero SECMARK is considered to be enabled.  Returns true (1) if SECMARK is
16162306a36Sopenharmony_ci * enabled, false (0) if SECMARK is disabled.  If the always_check_network
16262306a36Sopenharmony_ci * policy capability is enabled, SECMARK is always considered enabled.
16362306a36Sopenharmony_ci *
16462306a36Sopenharmony_ci */
16562306a36Sopenharmony_cistatic int selinux_secmark_enabled(void)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	return (selinux_policycap_alwaysnetwork() ||
16862306a36Sopenharmony_ci		atomic_read(&selinux_secmark_refcount));
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci/**
17262306a36Sopenharmony_ci * selinux_peerlbl_enabled - Check to see if peer labeling is currently enabled
17362306a36Sopenharmony_ci *
17462306a36Sopenharmony_ci * Description:
17562306a36Sopenharmony_ci * This function checks if NetLabel or labeled IPSEC is enabled.  Returns true
17662306a36Sopenharmony_ci * (1) if any are enabled or false (0) if neither are enabled.  If the
17762306a36Sopenharmony_ci * always_check_network policy capability is enabled, peer labeling
17862306a36Sopenharmony_ci * is always considered enabled.
17962306a36Sopenharmony_ci *
18062306a36Sopenharmony_ci */
18162306a36Sopenharmony_cistatic int selinux_peerlbl_enabled(void)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	return (selinux_policycap_alwaysnetwork() ||
18462306a36Sopenharmony_ci		netlbl_enabled() || selinux_xfrm_enabled());
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic int selinux_netcache_avc_callback(u32 event)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	if (event == AVC_CALLBACK_RESET) {
19062306a36Sopenharmony_ci		sel_netif_flush();
19162306a36Sopenharmony_ci		sel_netnode_flush();
19262306a36Sopenharmony_ci		sel_netport_flush();
19362306a36Sopenharmony_ci		synchronize_net();
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci	return 0;
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic int selinux_lsm_notifier_avc_callback(u32 event)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	if (event == AVC_CALLBACK_RESET) {
20162306a36Sopenharmony_ci		sel_ib_pkey_flush();
20262306a36Sopenharmony_ci		call_blocking_lsm_notifier(LSM_POLICY_CHANGE, NULL);
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return 0;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci/*
20962306a36Sopenharmony_ci * initialise the security for the init task
21062306a36Sopenharmony_ci */
21162306a36Sopenharmony_cistatic void cred_init_security(void)
21262306a36Sopenharmony_ci{
21362306a36Sopenharmony_ci	struct task_security_struct *tsec;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	tsec = selinux_cred(unrcu_pointer(current->real_cred));
21662306a36Sopenharmony_ci	tsec->osid = tsec->sid = SECINITSID_KERNEL;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci/*
22062306a36Sopenharmony_ci * get the security ID of a set of credentials
22162306a36Sopenharmony_ci */
22262306a36Sopenharmony_cistatic inline u32 cred_sid(const struct cred *cred)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	const struct task_security_struct *tsec;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	tsec = selinux_cred(cred);
22762306a36Sopenharmony_ci	return tsec->sid;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic void __ad_net_init(struct common_audit_data *ad,
23162306a36Sopenharmony_ci			  struct lsm_network_audit *net,
23262306a36Sopenharmony_ci			  int ifindex, struct sock *sk, u16 family)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	ad->type = LSM_AUDIT_DATA_NET;
23562306a36Sopenharmony_ci	ad->u.net = net;
23662306a36Sopenharmony_ci	net->netif = ifindex;
23762306a36Sopenharmony_ci	net->sk = sk;
23862306a36Sopenharmony_ci	net->family = family;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_cistatic void ad_net_init_from_sk(struct common_audit_data *ad,
24262306a36Sopenharmony_ci				struct lsm_network_audit *net,
24362306a36Sopenharmony_ci				struct sock *sk)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	__ad_net_init(ad, net, 0, sk, 0);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void ad_net_init_from_iif(struct common_audit_data *ad,
24962306a36Sopenharmony_ci				 struct lsm_network_audit *net,
25062306a36Sopenharmony_ci				 int ifindex, u16 family)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	__ad_net_init(ad, net, ifindex, NULL, family);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/*
25662306a36Sopenharmony_ci * get the objective security ID of a task
25762306a36Sopenharmony_ci */
25862306a36Sopenharmony_cistatic inline u32 task_sid_obj(const struct task_struct *task)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	u32 sid;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	rcu_read_lock();
26362306a36Sopenharmony_ci	sid = cred_sid(__task_cred(task));
26462306a36Sopenharmony_ci	rcu_read_unlock();
26562306a36Sopenharmony_ci	return sid;
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/*
27162306a36Sopenharmony_ci * Try reloading inode security labels that have been marked as invalid.  The
27262306a36Sopenharmony_ci * @may_sleep parameter indicates when sleeping and thus reloading labels is
27362306a36Sopenharmony_ci * allowed; when set to false, returns -ECHILD when the label is
27462306a36Sopenharmony_ci * invalid.  The @dentry parameter should be set to a dentry of the inode.
27562306a36Sopenharmony_ci */
27662306a36Sopenharmony_cistatic int __inode_security_revalidate(struct inode *inode,
27762306a36Sopenharmony_ci				       struct dentry *dentry,
27862306a36Sopenharmony_ci				       bool may_sleep)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	struct inode_security_struct *isec = selinux_inode(inode);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	might_sleep_if(may_sleep);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (selinux_initialized() &&
28562306a36Sopenharmony_ci	    isec->initialized != LABEL_INITIALIZED) {
28662306a36Sopenharmony_ci		if (!may_sleep)
28762306a36Sopenharmony_ci			return -ECHILD;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		/*
29062306a36Sopenharmony_ci		 * Try reloading the inode security label.  This will fail if
29162306a36Sopenharmony_ci		 * @opt_dentry is NULL and no dentry for this inode can be
29262306a36Sopenharmony_ci		 * found; in that case, continue using the old label.
29362306a36Sopenharmony_ci		 */
29462306a36Sopenharmony_ci		inode_doinit_with_dentry(inode, dentry);
29562306a36Sopenharmony_ci	}
29662306a36Sopenharmony_ci	return 0;
29762306a36Sopenharmony_ci}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic struct inode_security_struct *inode_security_novalidate(struct inode *inode)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	return selinux_inode(inode);
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic struct inode_security_struct *inode_security_rcu(struct inode *inode, bool rcu)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	int error;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	error = __inode_security_revalidate(inode, NULL, !rcu);
30962306a36Sopenharmony_ci	if (error)
31062306a36Sopenharmony_ci		return ERR_PTR(error);
31162306a36Sopenharmony_ci	return selinux_inode(inode);
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/*
31562306a36Sopenharmony_ci * Get the security label of an inode.
31662306a36Sopenharmony_ci */
31762306a36Sopenharmony_cistatic struct inode_security_struct *inode_security(struct inode *inode)
31862306a36Sopenharmony_ci{
31962306a36Sopenharmony_ci	__inode_security_revalidate(inode, NULL, true);
32062306a36Sopenharmony_ci	return selinux_inode(inode);
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic struct inode_security_struct *backing_inode_security_novalidate(struct dentry *dentry)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct inode *inode = d_backing_inode(dentry);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	return selinux_inode(inode);
32862306a36Sopenharmony_ci}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci/*
33162306a36Sopenharmony_ci * Get the security label of a dentry's backing inode.
33262306a36Sopenharmony_ci */
33362306a36Sopenharmony_cistatic struct inode_security_struct *backing_inode_security(struct dentry *dentry)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	struct inode *inode = d_backing_inode(dentry);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	__inode_security_revalidate(inode, dentry, true);
33862306a36Sopenharmony_ci	return selinux_inode(inode);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_cistatic void inode_free_security(struct inode *inode)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct inode_security_struct *isec = selinux_inode(inode);
34462306a36Sopenharmony_ci	struct superblock_security_struct *sbsec;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (!isec)
34762306a36Sopenharmony_ci		return;
34862306a36Sopenharmony_ci	sbsec = selinux_superblock(inode->i_sb);
34962306a36Sopenharmony_ci	/*
35062306a36Sopenharmony_ci	 * As not all inode security structures are in a list, we check for
35162306a36Sopenharmony_ci	 * empty list outside of the lock to make sure that we won't waste
35262306a36Sopenharmony_ci	 * time taking a lock doing nothing.
35362306a36Sopenharmony_ci	 *
35462306a36Sopenharmony_ci	 * The list_del_init() function can be safely called more than once.
35562306a36Sopenharmony_ci	 * It should not be possible for this function to be called with
35662306a36Sopenharmony_ci	 * concurrent list_add(), but for better safety against future changes
35762306a36Sopenharmony_ci	 * in the code, we use list_empty_careful() here.
35862306a36Sopenharmony_ci	 */
35962306a36Sopenharmony_ci	if (!list_empty_careful(&isec->list)) {
36062306a36Sopenharmony_ci		spin_lock(&sbsec->isec_lock);
36162306a36Sopenharmony_ci		list_del_init(&isec->list);
36262306a36Sopenharmony_ci		spin_unlock(&sbsec->isec_lock);
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistruct selinux_mnt_opts {
36762306a36Sopenharmony_ci	u32 fscontext_sid;
36862306a36Sopenharmony_ci	u32 context_sid;
36962306a36Sopenharmony_ci	u32 rootcontext_sid;
37062306a36Sopenharmony_ci	u32 defcontext_sid;
37162306a36Sopenharmony_ci};
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic void selinux_free_mnt_opts(void *mnt_opts)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	kfree(mnt_opts);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cienum {
37962306a36Sopenharmony_ci	Opt_error = -1,
38062306a36Sopenharmony_ci	Opt_context = 0,
38162306a36Sopenharmony_ci	Opt_defcontext = 1,
38262306a36Sopenharmony_ci	Opt_fscontext = 2,
38362306a36Sopenharmony_ci	Opt_rootcontext = 3,
38462306a36Sopenharmony_ci	Opt_seclabel = 4,
38562306a36Sopenharmony_ci};
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci#define A(s, has_arg) {#s, sizeof(#s) - 1, Opt_##s, has_arg}
38862306a36Sopenharmony_cistatic const struct {
38962306a36Sopenharmony_ci	const char *name;
39062306a36Sopenharmony_ci	int len;
39162306a36Sopenharmony_ci	int opt;
39262306a36Sopenharmony_ci	bool has_arg;
39362306a36Sopenharmony_ci} tokens[] = {
39462306a36Sopenharmony_ci	A(context, true),
39562306a36Sopenharmony_ci	A(fscontext, true),
39662306a36Sopenharmony_ci	A(defcontext, true),
39762306a36Sopenharmony_ci	A(rootcontext, true),
39862306a36Sopenharmony_ci	A(seclabel, false),
39962306a36Sopenharmony_ci};
40062306a36Sopenharmony_ci#undef A
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic int match_opt_prefix(char *s, int l, char **arg)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	int i;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tokens); i++) {
40762306a36Sopenharmony_ci		size_t len = tokens[i].len;
40862306a36Sopenharmony_ci		if (len > l || memcmp(s, tokens[i].name, len))
40962306a36Sopenharmony_ci			continue;
41062306a36Sopenharmony_ci		if (tokens[i].has_arg) {
41162306a36Sopenharmony_ci			if (len == l || s[len] != '=')
41262306a36Sopenharmony_ci				continue;
41362306a36Sopenharmony_ci			*arg = s + len + 1;
41462306a36Sopenharmony_ci		} else if (len != l)
41562306a36Sopenharmony_ci			continue;
41662306a36Sopenharmony_ci		return tokens[i].opt;
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci	return Opt_error;
41962306a36Sopenharmony_ci}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci#define SEL_MOUNT_FAIL_MSG "SELinux:  duplicate or incompatible mount options\n"
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_cistatic int may_context_mount_sb_relabel(u32 sid,
42462306a36Sopenharmony_ci			struct superblock_security_struct *sbsec,
42562306a36Sopenharmony_ci			const struct cred *cred)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	const struct task_security_struct *tsec = selinux_cred(cred);
42862306a36Sopenharmony_ci	int rc;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
43162306a36Sopenharmony_ci			  FILESYSTEM__RELABELFROM, NULL);
43262306a36Sopenharmony_ci	if (rc)
43362306a36Sopenharmony_ci		return rc;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	rc = avc_has_perm(tsec->sid, sid, SECCLASS_FILESYSTEM,
43662306a36Sopenharmony_ci			  FILESYSTEM__RELABELTO, NULL);
43762306a36Sopenharmony_ci	return rc;
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_cistatic int may_context_mount_inode_relabel(u32 sid,
44162306a36Sopenharmony_ci			struct superblock_security_struct *sbsec,
44262306a36Sopenharmony_ci			const struct cred *cred)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	const struct task_security_struct *tsec = selinux_cred(cred);
44562306a36Sopenharmony_ci	int rc;
44662306a36Sopenharmony_ci	rc = avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
44762306a36Sopenharmony_ci			  FILESYSTEM__RELABELFROM, NULL);
44862306a36Sopenharmony_ci	if (rc)
44962306a36Sopenharmony_ci		return rc;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	rc = avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM,
45262306a36Sopenharmony_ci			  FILESYSTEM__ASSOCIATE, NULL);
45362306a36Sopenharmony_ci	return rc;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic int selinux_is_genfs_special_handling(struct super_block *sb)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	/* Special handling. Genfs but also in-core setxattr handler */
45962306a36Sopenharmony_ci	return	!strcmp(sb->s_type->name, "sysfs") ||
46062306a36Sopenharmony_ci		!strcmp(sb->s_type->name, "pstore") ||
46162306a36Sopenharmony_ci		!strcmp(sb->s_type->name, "debugfs") ||
46262306a36Sopenharmony_ci		!strcmp(sb->s_type->name, "tracefs") ||
46362306a36Sopenharmony_ci		!strcmp(sb->s_type->name, "rootfs") ||
46462306a36Sopenharmony_ci		(selinux_policycap_cgroupseclabel() &&
46562306a36Sopenharmony_ci		 (!strcmp(sb->s_type->name, "cgroup") ||
46662306a36Sopenharmony_ci		  !strcmp(sb->s_type->name, "cgroup2")));
46762306a36Sopenharmony_ci}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_cistatic int selinux_is_sblabel_mnt(struct super_block *sb)
47062306a36Sopenharmony_ci{
47162306a36Sopenharmony_ci	struct superblock_security_struct *sbsec = selinux_superblock(sb);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	/*
47462306a36Sopenharmony_ci	 * IMPORTANT: Double-check logic in this function when adding a new
47562306a36Sopenharmony_ci	 * SECURITY_FS_USE_* definition!
47662306a36Sopenharmony_ci	 */
47762306a36Sopenharmony_ci	BUILD_BUG_ON(SECURITY_FS_USE_MAX != 7);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	switch (sbsec->behavior) {
48062306a36Sopenharmony_ci	case SECURITY_FS_USE_XATTR:
48162306a36Sopenharmony_ci	case SECURITY_FS_USE_TRANS:
48262306a36Sopenharmony_ci	case SECURITY_FS_USE_TASK:
48362306a36Sopenharmony_ci	case SECURITY_FS_USE_NATIVE:
48462306a36Sopenharmony_ci		return 1;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	case SECURITY_FS_USE_GENFS:
48762306a36Sopenharmony_ci		return selinux_is_genfs_special_handling(sb);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	/* Never allow relabeling on context mounts */
49062306a36Sopenharmony_ci	case SECURITY_FS_USE_MNTPOINT:
49162306a36Sopenharmony_ci	case SECURITY_FS_USE_NONE:
49262306a36Sopenharmony_ci	default:
49362306a36Sopenharmony_ci		return 0;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci}
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_cistatic int sb_check_xattr_support(struct super_block *sb)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	struct superblock_security_struct *sbsec = selinux_superblock(sb);
50062306a36Sopenharmony_ci	struct dentry *root = sb->s_root;
50162306a36Sopenharmony_ci	struct inode *root_inode = d_backing_inode(root);
50262306a36Sopenharmony_ci	u32 sid;
50362306a36Sopenharmony_ci	int rc;
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci	/*
50662306a36Sopenharmony_ci	 * Make sure that the xattr handler exists and that no
50762306a36Sopenharmony_ci	 * error other than -ENODATA is returned by getxattr on
50862306a36Sopenharmony_ci	 * the root directory.  -ENODATA is ok, as this may be
50962306a36Sopenharmony_ci	 * the first boot of the SELinux kernel before we have
51062306a36Sopenharmony_ci	 * assigned xattr values to the filesystem.
51162306a36Sopenharmony_ci	 */
51262306a36Sopenharmony_ci	if (!(root_inode->i_opflags & IOP_XATTR)) {
51362306a36Sopenharmony_ci		pr_warn("SELinux: (dev %s, type %s) has no xattr support\n",
51462306a36Sopenharmony_ci			sb->s_id, sb->s_type->name);
51562306a36Sopenharmony_ci		goto fallback;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
51962306a36Sopenharmony_ci	if (rc < 0 && rc != -ENODATA) {
52062306a36Sopenharmony_ci		if (rc == -EOPNOTSUPP) {
52162306a36Sopenharmony_ci			pr_warn("SELinux: (dev %s, type %s) has no security xattr handler\n",
52262306a36Sopenharmony_ci				sb->s_id, sb->s_type->name);
52362306a36Sopenharmony_ci			goto fallback;
52462306a36Sopenharmony_ci		} else {
52562306a36Sopenharmony_ci			pr_warn("SELinux: (dev %s, type %s) getxattr errno %d\n",
52662306a36Sopenharmony_ci				sb->s_id, sb->s_type->name, -rc);
52762306a36Sopenharmony_ci			return rc;
52862306a36Sopenharmony_ci		}
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci	return 0;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cifallback:
53362306a36Sopenharmony_ci	/* No xattr support - try to fallback to genfs if possible. */
53462306a36Sopenharmony_ci	rc = security_genfs_sid(sb->s_type->name, "/",
53562306a36Sopenharmony_ci				SECCLASS_DIR, &sid);
53662306a36Sopenharmony_ci	if (rc)
53762306a36Sopenharmony_ci		return -EOPNOTSUPP;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	pr_warn("SELinux: (dev %s, type %s) falling back to genfs\n",
54062306a36Sopenharmony_ci		sb->s_id, sb->s_type->name);
54162306a36Sopenharmony_ci	sbsec->behavior = SECURITY_FS_USE_GENFS;
54262306a36Sopenharmony_ci	sbsec->sid = sid;
54362306a36Sopenharmony_ci	return 0;
54462306a36Sopenharmony_ci}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_cistatic int sb_finish_set_opts(struct super_block *sb)
54762306a36Sopenharmony_ci{
54862306a36Sopenharmony_ci	struct superblock_security_struct *sbsec = selinux_superblock(sb);
54962306a36Sopenharmony_ci	struct dentry *root = sb->s_root;
55062306a36Sopenharmony_ci	struct inode *root_inode = d_backing_inode(root);
55162306a36Sopenharmony_ci	int rc = 0;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
55462306a36Sopenharmony_ci		rc = sb_check_xattr_support(sb);
55562306a36Sopenharmony_ci		if (rc)
55662306a36Sopenharmony_ci			return rc;
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	sbsec->flags |= SE_SBINITIALIZED;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	/*
56262306a36Sopenharmony_ci	 * Explicitly set or clear SBLABEL_MNT.  It's not sufficient to simply
56362306a36Sopenharmony_ci	 * leave the flag untouched because sb_clone_mnt_opts might be handing
56462306a36Sopenharmony_ci	 * us a superblock that needs the flag to be cleared.
56562306a36Sopenharmony_ci	 */
56662306a36Sopenharmony_ci	if (selinux_is_sblabel_mnt(sb))
56762306a36Sopenharmony_ci		sbsec->flags |= SBLABEL_MNT;
56862306a36Sopenharmony_ci	else
56962306a36Sopenharmony_ci		sbsec->flags &= ~SBLABEL_MNT;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	/* Initialize the root inode. */
57262306a36Sopenharmony_ci	rc = inode_doinit_with_dentry(root_inode, root);
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/* Initialize any other inodes associated with the superblock, e.g.
57562306a36Sopenharmony_ci	   inodes created prior to initial policy load or inodes created
57662306a36Sopenharmony_ci	   during get_sb by a pseudo filesystem that directly
57762306a36Sopenharmony_ci	   populates itself. */
57862306a36Sopenharmony_ci	spin_lock(&sbsec->isec_lock);
57962306a36Sopenharmony_ci	while (!list_empty(&sbsec->isec_head)) {
58062306a36Sopenharmony_ci		struct inode_security_struct *isec =
58162306a36Sopenharmony_ci				list_first_entry(&sbsec->isec_head,
58262306a36Sopenharmony_ci					   struct inode_security_struct, list);
58362306a36Sopenharmony_ci		struct inode *inode = isec->inode;
58462306a36Sopenharmony_ci		list_del_init(&isec->list);
58562306a36Sopenharmony_ci		spin_unlock(&sbsec->isec_lock);
58662306a36Sopenharmony_ci		inode = igrab(inode);
58762306a36Sopenharmony_ci		if (inode) {
58862306a36Sopenharmony_ci			if (!IS_PRIVATE(inode))
58962306a36Sopenharmony_ci				inode_doinit_with_dentry(inode, NULL);
59062306a36Sopenharmony_ci			iput(inode);
59162306a36Sopenharmony_ci		}
59262306a36Sopenharmony_ci		spin_lock(&sbsec->isec_lock);
59362306a36Sopenharmony_ci	}
59462306a36Sopenharmony_ci	spin_unlock(&sbsec->isec_lock);
59562306a36Sopenharmony_ci	return rc;
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic int bad_option(struct superblock_security_struct *sbsec, char flag,
59962306a36Sopenharmony_ci		      u32 old_sid, u32 new_sid)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	char mnt_flags = sbsec->flags & SE_MNTMASK;
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/* check if the old mount command had the same options */
60462306a36Sopenharmony_ci	if (sbsec->flags & SE_SBINITIALIZED)
60562306a36Sopenharmony_ci		if (!(sbsec->flags & flag) ||
60662306a36Sopenharmony_ci		    (old_sid != new_sid))
60762306a36Sopenharmony_ci			return 1;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	/* check if we were passed the same options twice,
61062306a36Sopenharmony_ci	 * aka someone passed context=a,context=b
61162306a36Sopenharmony_ci	 */
61262306a36Sopenharmony_ci	if (!(sbsec->flags & SE_SBINITIALIZED))
61362306a36Sopenharmony_ci		if (mnt_flags & flag)
61462306a36Sopenharmony_ci			return 1;
61562306a36Sopenharmony_ci	return 0;
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci/*
61962306a36Sopenharmony_ci * Allow filesystems with binary mount data to explicitly set mount point
62062306a36Sopenharmony_ci * labeling information.
62162306a36Sopenharmony_ci */
62262306a36Sopenharmony_cistatic int selinux_set_mnt_opts(struct super_block *sb,
62362306a36Sopenharmony_ci				void *mnt_opts,
62462306a36Sopenharmony_ci				unsigned long kern_flags,
62562306a36Sopenharmony_ci				unsigned long *set_kern_flags)
62662306a36Sopenharmony_ci{
62762306a36Sopenharmony_ci	const struct cred *cred = current_cred();
62862306a36Sopenharmony_ci	struct superblock_security_struct *sbsec = selinux_superblock(sb);
62962306a36Sopenharmony_ci	struct dentry *root = sb->s_root;
63062306a36Sopenharmony_ci	struct selinux_mnt_opts *opts = mnt_opts;
63162306a36Sopenharmony_ci	struct inode_security_struct *root_isec;
63262306a36Sopenharmony_ci	u32 fscontext_sid = 0, context_sid = 0, rootcontext_sid = 0;
63362306a36Sopenharmony_ci	u32 defcontext_sid = 0;
63462306a36Sopenharmony_ci	int rc = 0;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	/*
63762306a36Sopenharmony_ci	 * Specifying internal flags without providing a place to
63862306a36Sopenharmony_ci	 * place the results is not allowed
63962306a36Sopenharmony_ci	 */
64062306a36Sopenharmony_ci	if (kern_flags && !set_kern_flags)
64162306a36Sopenharmony_ci		return -EINVAL;
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	mutex_lock(&sbsec->lock);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (!selinux_initialized()) {
64662306a36Sopenharmony_ci		if (!opts) {
64762306a36Sopenharmony_ci			/* Defer initialization until selinux_complete_init,
64862306a36Sopenharmony_ci			   after the initial policy is loaded and the security
64962306a36Sopenharmony_ci			   server is ready to handle calls. */
65062306a36Sopenharmony_ci			if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
65162306a36Sopenharmony_ci				sbsec->flags |= SE_SBNATIVE;
65262306a36Sopenharmony_ci				*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
65362306a36Sopenharmony_ci			}
65462306a36Sopenharmony_ci			goto out;
65562306a36Sopenharmony_ci		}
65662306a36Sopenharmony_ci		rc = -EINVAL;
65762306a36Sopenharmony_ci		pr_warn("SELinux: Unable to set superblock options "
65862306a36Sopenharmony_ci			"before the security server is initialized\n");
65962306a36Sopenharmony_ci		goto out;
66062306a36Sopenharmony_ci	}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	/*
66362306a36Sopenharmony_ci	 * Binary mount data FS will come through this function twice.  Once
66462306a36Sopenharmony_ci	 * from an explicit call and once from the generic calls from the vfs.
66562306a36Sopenharmony_ci	 * Since the generic VFS calls will not contain any security mount data
66662306a36Sopenharmony_ci	 * we need to skip the double mount verification.
66762306a36Sopenharmony_ci	 *
66862306a36Sopenharmony_ci	 * This does open a hole in which we will not notice if the first
66962306a36Sopenharmony_ci	 * mount using this sb set explicit options and a second mount using
67062306a36Sopenharmony_ci	 * this sb does not set any security options.  (The first options
67162306a36Sopenharmony_ci	 * will be used for both mounts)
67262306a36Sopenharmony_ci	 */
67362306a36Sopenharmony_ci	if ((sbsec->flags & SE_SBINITIALIZED) && (sb->s_type->fs_flags & FS_BINARY_MOUNTDATA)
67462306a36Sopenharmony_ci	    && !opts)
67562306a36Sopenharmony_ci		goto out;
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	root_isec = backing_inode_security_novalidate(root);
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	/*
68062306a36Sopenharmony_ci	 * parse the mount options, check if they are valid sids.
68162306a36Sopenharmony_ci	 * also check if someone is trying to mount the same sb more
68262306a36Sopenharmony_ci	 * than once with different security options.
68362306a36Sopenharmony_ci	 */
68462306a36Sopenharmony_ci	if (opts) {
68562306a36Sopenharmony_ci		if (opts->fscontext_sid) {
68662306a36Sopenharmony_ci			fscontext_sid = opts->fscontext_sid;
68762306a36Sopenharmony_ci			if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
68862306a36Sopenharmony_ci					fscontext_sid))
68962306a36Sopenharmony_ci				goto out_double_mount;
69062306a36Sopenharmony_ci			sbsec->flags |= FSCONTEXT_MNT;
69162306a36Sopenharmony_ci		}
69262306a36Sopenharmony_ci		if (opts->context_sid) {
69362306a36Sopenharmony_ci			context_sid = opts->context_sid;
69462306a36Sopenharmony_ci			if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
69562306a36Sopenharmony_ci					context_sid))
69662306a36Sopenharmony_ci				goto out_double_mount;
69762306a36Sopenharmony_ci			sbsec->flags |= CONTEXT_MNT;
69862306a36Sopenharmony_ci		}
69962306a36Sopenharmony_ci		if (opts->rootcontext_sid) {
70062306a36Sopenharmony_ci			rootcontext_sid = opts->rootcontext_sid;
70162306a36Sopenharmony_ci			if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
70262306a36Sopenharmony_ci					rootcontext_sid))
70362306a36Sopenharmony_ci				goto out_double_mount;
70462306a36Sopenharmony_ci			sbsec->flags |= ROOTCONTEXT_MNT;
70562306a36Sopenharmony_ci		}
70662306a36Sopenharmony_ci		if (opts->defcontext_sid) {
70762306a36Sopenharmony_ci			defcontext_sid = opts->defcontext_sid;
70862306a36Sopenharmony_ci			if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
70962306a36Sopenharmony_ci					defcontext_sid))
71062306a36Sopenharmony_ci				goto out_double_mount;
71162306a36Sopenharmony_ci			sbsec->flags |= DEFCONTEXT_MNT;
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (sbsec->flags & SE_SBINITIALIZED) {
71662306a36Sopenharmony_ci		/* previously mounted with options, but not on this attempt? */
71762306a36Sopenharmony_ci		if ((sbsec->flags & SE_MNTMASK) && !opts)
71862306a36Sopenharmony_ci			goto out_double_mount;
71962306a36Sopenharmony_ci		rc = 0;
72062306a36Sopenharmony_ci		goto out;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	if (strcmp(sb->s_type->name, "proc") == 0)
72462306a36Sopenharmony_ci		sbsec->flags |= SE_SBPROC | SE_SBGENFS;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	if (!strcmp(sb->s_type->name, "debugfs") ||
72762306a36Sopenharmony_ci	    !strcmp(sb->s_type->name, "tracefs") ||
72862306a36Sopenharmony_ci	    !strcmp(sb->s_type->name, "binder") ||
72962306a36Sopenharmony_ci	    !strcmp(sb->s_type->name, "bpf") ||
73062306a36Sopenharmony_ci	    !strcmp(sb->s_type->name, "pstore") ||
73162306a36Sopenharmony_ci	    !strcmp(sb->s_type->name, "securityfs"))
73262306a36Sopenharmony_ci		sbsec->flags |= SE_SBGENFS;
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	if (!strcmp(sb->s_type->name, "sysfs") ||
73562306a36Sopenharmony_ci	    !strcmp(sb->s_type->name, "cgroup") ||
73662306a36Sopenharmony_ci	    !strcmp(sb->s_type->name, "cgroup2"))
73762306a36Sopenharmony_ci		sbsec->flags |= SE_SBGENFS | SE_SBGENFS_XATTR;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	if (!sbsec->behavior) {
74062306a36Sopenharmony_ci		/*
74162306a36Sopenharmony_ci		 * Determine the labeling behavior to use for this
74262306a36Sopenharmony_ci		 * filesystem type.
74362306a36Sopenharmony_ci		 */
74462306a36Sopenharmony_ci		rc = security_fs_use(sb);
74562306a36Sopenharmony_ci		if (rc) {
74662306a36Sopenharmony_ci			pr_warn("%s: security_fs_use(%s) returned %d\n",
74762306a36Sopenharmony_ci					__func__, sb->s_type->name, rc);
74862306a36Sopenharmony_ci			goto out;
74962306a36Sopenharmony_ci		}
75062306a36Sopenharmony_ci	}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci	/*
75362306a36Sopenharmony_ci	 * If this is a user namespace mount and the filesystem type is not
75462306a36Sopenharmony_ci	 * explicitly whitelisted, then no contexts are allowed on the command
75562306a36Sopenharmony_ci	 * line and security labels must be ignored.
75662306a36Sopenharmony_ci	 */
75762306a36Sopenharmony_ci	if (sb->s_user_ns != &init_user_ns &&
75862306a36Sopenharmony_ci	    strcmp(sb->s_type->name, "tmpfs") &&
75962306a36Sopenharmony_ci	    strcmp(sb->s_type->name, "ramfs") &&
76062306a36Sopenharmony_ci	    strcmp(sb->s_type->name, "devpts") &&
76162306a36Sopenharmony_ci	    strcmp(sb->s_type->name, "overlay")) {
76262306a36Sopenharmony_ci		if (context_sid || fscontext_sid || rootcontext_sid ||
76362306a36Sopenharmony_ci		    defcontext_sid) {
76462306a36Sopenharmony_ci			rc = -EACCES;
76562306a36Sopenharmony_ci			goto out;
76662306a36Sopenharmony_ci		}
76762306a36Sopenharmony_ci		if (sbsec->behavior == SECURITY_FS_USE_XATTR) {
76862306a36Sopenharmony_ci			sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
76962306a36Sopenharmony_ci			rc = security_transition_sid(current_sid(),
77062306a36Sopenharmony_ci						     current_sid(),
77162306a36Sopenharmony_ci						     SECCLASS_FILE, NULL,
77262306a36Sopenharmony_ci						     &sbsec->mntpoint_sid);
77362306a36Sopenharmony_ci			if (rc)
77462306a36Sopenharmony_ci				goto out;
77562306a36Sopenharmony_ci		}
77662306a36Sopenharmony_ci		goto out_set_opts;
77762306a36Sopenharmony_ci	}
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	/* sets the context of the superblock for the fs being mounted. */
78062306a36Sopenharmony_ci	if (fscontext_sid) {
78162306a36Sopenharmony_ci		rc = may_context_mount_sb_relabel(fscontext_sid, sbsec, cred);
78262306a36Sopenharmony_ci		if (rc)
78362306a36Sopenharmony_ci			goto out;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci		sbsec->sid = fscontext_sid;
78662306a36Sopenharmony_ci	}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	/*
78962306a36Sopenharmony_ci	 * Switch to using mount point labeling behavior.
79062306a36Sopenharmony_ci	 * sets the label used on all file below the mountpoint, and will set
79162306a36Sopenharmony_ci	 * the superblock context if not already set.
79262306a36Sopenharmony_ci	 */
79362306a36Sopenharmony_ci	if (sbsec->flags & SE_SBNATIVE) {
79462306a36Sopenharmony_ci		/*
79562306a36Sopenharmony_ci		 * This means we are initializing a superblock that has been
79662306a36Sopenharmony_ci		 * mounted before the SELinux was initialized and the
79762306a36Sopenharmony_ci		 * filesystem requested native labeling. We had already
79862306a36Sopenharmony_ci		 * returned SECURITY_LSM_NATIVE_LABELS in *set_kern_flags
79962306a36Sopenharmony_ci		 * in the original mount attempt, so now we just need to set
80062306a36Sopenharmony_ci		 * the SECURITY_FS_USE_NATIVE behavior.
80162306a36Sopenharmony_ci		 */
80262306a36Sopenharmony_ci		sbsec->behavior = SECURITY_FS_USE_NATIVE;
80362306a36Sopenharmony_ci	} else if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !context_sid) {
80462306a36Sopenharmony_ci		sbsec->behavior = SECURITY_FS_USE_NATIVE;
80562306a36Sopenharmony_ci		*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (context_sid) {
80962306a36Sopenharmony_ci		if (!fscontext_sid) {
81062306a36Sopenharmony_ci			rc = may_context_mount_sb_relabel(context_sid, sbsec,
81162306a36Sopenharmony_ci							  cred);
81262306a36Sopenharmony_ci			if (rc)
81362306a36Sopenharmony_ci				goto out;
81462306a36Sopenharmony_ci			sbsec->sid = context_sid;
81562306a36Sopenharmony_ci		} else {
81662306a36Sopenharmony_ci			rc = may_context_mount_inode_relabel(context_sid, sbsec,
81762306a36Sopenharmony_ci							     cred);
81862306a36Sopenharmony_ci			if (rc)
81962306a36Sopenharmony_ci				goto out;
82062306a36Sopenharmony_ci		}
82162306a36Sopenharmony_ci		if (!rootcontext_sid)
82262306a36Sopenharmony_ci			rootcontext_sid = context_sid;
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		sbsec->mntpoint_sid = context_sid;
82562306a36Sopenharmony_ci		sbsec->behavior = SECURITY_FS_USE_MNTPOINT;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	if (rootcontext_sid) {
82962306a36Sopenharmony_ci		rc = may_context_mount_inode_relabel(rootcontext_sid, sbsec,
83062306a36Sopenharmony_ci						     cred);
83162306a36Sopenharmony_ci		if (rc)
83262306a36Sopenharmony_ci			goto out;
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci		root_isec->sid = rootcontext_sid;
83562306a36Sopenharmony_ci		root_isec->initialized = LABEL_INITIALIZED;
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	if (defcontext_sid) {
83962306a36Sopenharmony_ci		if (sbsec->behavior != SECURITY_FS_USE_XATTR &&
84062306a36Sopenharmony_ci			sbsec->behavior != SECURITY_FS_USE_NATIVE) {
84162306a36Sopenharmony_ci			rc = -EINVAL;
84262306a36Sopenharmony_ci			pr_warn("SELinux: defcontext option is "
84362306a36Sopenharmony_ci			       "invalid for this filesystem type\n");
84462306a36Sopenharmony_ci			goto out;
84562306a36Sopenharmony_ci		}
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci		if (defcontext_sid != sbsec->def_sid) {
84862306a36Sopenharmony_ci			rc = may_context_mount_inode_relabel(defcontext_sid,
84962306a36Sopenharmony_ci							     sbsec, cred);
85062306a36Sopenharmony_ci			if (rc)
85162306a36Sopenharmony_ci				goto out;
85262306a36Sopenharmony_ci		}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci		sbsec->def_sid = defcontext_sid;
85562306a36Sopenharmony_ci	}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ciout_set_opts:
85862306a36Sopenharmony_ci	rc = sb_finish_set_opts(sb);
85962306a36Sopenharmony_ciout:
86062306a36Sopenharmony_ci	mutex_unlock(&sbsec->lock);
86162306a36Sopenharmony_ci	return rc;
86262306a36Sopenharmony_ciout_double_mount:
86362306a36Sopenharmony_ci	rc = -EINVAL;
86462306a36Sopenharmony_ci	pr_warn("SELinux: mount invalid.  Same superblock, different "
86562306a36Sopenharmony_ci	       "security settings for (dev %s, type %s)\n", sb->s_id,
86662306a36Sopenharmony_ci	       sb->s_type->name);
86762306a36Sopenharmony_ci	goto out;
86862306a36Sopenharmony_ci}
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic int selinux_cmp_sb_context(const struct super_block *oldsb,
87162306a36Sopenharmony_ci				    const struct super_block *newsb)
87262306a36Sopenharmony_ci{
87362306a36Sopenharmony_ci	struct superblock_security_struct *old = selinux_superblock(oldsb);
87462306a36Sopenharmony_ci	struct superblock_security_struct *new = selinux_superblock(newsb);
87562306a36Sopenharmony_ci	char oldflags = old->flags & SE_MNTMASK;
87662306a36Sopenharmony_ci	char newflags = new->flags & SE_MNTMASK;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	if (oldflags != newflags)
87962306a36Sopenharmony_ci		goto mismatch;
88062306a36Sopenharmony_ci	if ((oldflags & FSCONTEXT_MNT) && old->sid != new->sid)
88162306a36Sopenharmony_ci		goto mismatch;
88262306a36Sopenharmony_ci	if ((oldflags & CONTEXT_MNT) && old->mntpoint_sid != new->mntpoint_sid)
88362306a36Sopenharmony_ci		goto mismatch;
88462306a36Sopenharmony_ci	if ((oldflags & DEFCONTEXT_MNT) && old->def_sid != new->def_sid)
88562306a36Sopenharmony_ci		goto mismatch;
88662306a36Sopenharmony_ci	if (oldflags & ROOTCONTEXT_MNT) {
88762306a36Sopenharmony_ci		struct inode_security_struct *oldroot = backing_inode_security(oldsb->s_root);
88862306a36Sopenharmony_ci		struct inode_security_struct *newroot = backing_inode_security(newsb->s_root);
88962306a36Sopenharmony_ci		if (oldroot->sid != newroot->sid)
89062306a36Sopenharmony_ci			goto mismatch;
89162306a36Sopenharmony_ci	}
89262306a36Sopenharmony_ci	return 0;
89362306a36Sopenharmony_cimismatch:
89462306a36Sopenharmony_ci	pr_warn("SELinux: mount invalid.  Same superblock, "
89562306a36Sopenharmony_ci			    "different security settings for (dev %s, "
89662306a36Sopenharmony_ci			    "type %s)\n", newsb->s_id, newsb->s_type->name);
89762306a36Sopenharmony_ci	return -EBUSY;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic int selinux_sb_clone_mnt_opts(const struct super_block *oldsb,
90162306a36Sopenharmony_ci					struct super_block *newsb,
90262306a36Sopenharmony_ci					unsigned long kern_flags,
90362306a36Sopenharmony_ci					unsigned long *set_kern_flags)
90462306a36Sopenharmony_ci{
90562306a36Sopenharmony_ci	int rc = 0;
90662306a36Sopenharmony_ci	const struct superblock_security_struct *oldsbsec =
90762306a36Sopenharmony_ci						selinux_superblock(oldsb);
90862306a36Sopenharmony_ci	struct superblock_security_struct *newsbsec = selinux_superblock(newsb);
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci	int set_fscontext =	(oldsbsec->flags & FSCONTEXT_MNT);
91162306a36Sopenharmony_ci	int set_context =	(oldsbsec->flags & CONTEXT_MNT);
91262306a36Sopenharmony_ci	int set_rootcontext =	(oldsbsec->flags & ROOTCONTEXT_MNT);
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	/*
91562306a36Sopenharmony_ci	 * Specifying internal flags without providing a place to
91662306a36Sopenharmony_ci	 * place the results is not allowed.
91762306a36Sopenharmony_ci	 */
91862306a36Sopenharmony_ci	if (kern_flags && !set_kern_flags)
91962306a36Sopenharmony_ci		return -EINVAL;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	mutex_lock(&newsbsec->lock);
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	/*
92462306a36Sopenharmony_ci	 * if the parent was able to be mounted it clearly had no special lsm
92562306a36Sopenharmony_ci	 * mount options.  thus we can safely deal with this superblock later
92662306a36Sopenharmony_ci	 */
92762306a36Sopenharmony_ci	if (!selinux_initialized()) {
92862306a36Sopenharmony_ci		if (kern_flags & SECURITY_LSM_NATIVE_LABELS) {
92962306a36Sopenharmony_ci			newsbsec->flags |= SE_SBNATIVE;
93062306a36Sopenharmony_ci			*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
93162306a36Sopenharmony_ci		}
93262306a36Sopenharmony_ci		goto out;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* how can we clone if the old one wasn't set up?? */
93662306a36Sopenharmony_ci	BUG_ON(!(oldsbsec->flags & SE_SBINITIALIZED));
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	/* if fs is reusing a sb, make sure that the contexts match */
93962306a36Sopenharmony_ci	if (newsbsec->flags & SE_SBINITIALIZED) {
94062306a36Sopenharmony_ci		mutex_unlock(&newsbsec->lock);
94162306a36Sopenharmony_ci		if ((kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context)
94262306a36Sopenharmony_ci			*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
94362306a36Sopenharmony_ci		return selinux_cmp_sb_context(oldsb, newsb);
94462306a36Sopenharmony_ci	}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	newsbsec->flags = oldsbsec->flags;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	newsbsec->sid = oldsbsec->sid;
94962306a36Sopenharmony_ci	newsbsec->def_sid = oldsbsec->def_sid;
95062306a36Sopenharmony_ci	newsbsec->behavior = oldsbsec->behavior;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	if (newsbsec->behavior == SECURITY_FS_USE_NATIVE &&
95362306a36Sopenharmony_ci		!(kern_flags & SECURITY_LSM_NATIVE_LABELS) && !set_context) {
95462306a36Sopenharmony_ci		rc = security_fs_use(newsb);
95562306a36Sopenharmony_ci		if (rc)
95662306a36Sopenharmony_ci			goto out;
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	if (kern_flags & SECURITY_LSM_NATIVE_LABELS && !set_context) {
96062306a36Sopenharmony_ci		newsbsec->behavior = SECURITY_FS_USE_NATIVE;
96162306a36Sopenharmony_ci		*set_kern_flags |= SECURITY_LSM_NATIVE_LABELS;
96262306a36Sopenharmony_ci	}
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	if (set_context) {
96562306a36Sopenharmony_ci		u32 sid = oldsbsec->mntpoint_sid;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci		if (!set_fscontext)
96862306a36Sopenharmony_ci			newsbsec->sid = sid;
96962306a36Sopenharmony_ci		if (!set_rootcontext) {
97062306a36Sopenharmony_ci			struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
97162306a36Sopenharmony_ci			newisec->sid = sid;
97262306a36Sopenharmony_ci		}
97362306a36Sopenharmony_ci		newsbsec->mntpoint_sid = sid;
97462306a36Sopenharmony_ci	}
97562306a36Sopenharmony_ci	if (set_rootcontext) {
97662306a36Sopenharmony_ci		const struct inode_security_struct *oldisec = backing_inode_security(oldsb->s_root);
97762306a36Sopenharmony_ci		struct inode_security_struct *newisec = backing_inode_security(newsb->s_root);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci		newisec->sid = oldisec->sid;
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	sb_finish_set_opts(newsb);
98362306a36Sopenharmony_ciout:
98462306a36Sopenharmony_ci	mutex_unlock(&newsbsec->lock);
98562306a36Sopenharmony_ci	return rc;
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci/*
98962306a36Sopenharmony_ci * NOTE: the caller is responsible for freeing the memory even if on error.
99062306a36Sopenharmony_ci */
99162306a36Sopenharmony_cistatic int selinux_add_opt(int token, const char *s, void **mnt_opts)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	struct selinux_mnt_opts *opts = *mnt_opts;
99462306a36Sopenharmony_ci	u32 *dst_sid;
99562306a36Sopenharmony_ci	int rc;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	if (token == Opt_seclabel)
99862306a36Sopenharmony_ci		/* eaten and completely ignored */
99962306a36Sopenharmony_ci		return 0;
100062306a36Sopenharmony_ci	if (!s)
100162306a36Sopenharmony_ci		return -EINVAL;
100262306a36Sopenharmony_ci
100362306a36Sopenharmony_ci	if (!selinux_initialized()) {
100462306a36Sopenharmony_ci		pr_warn("SELinux: Unable to set superblock options before the security server is initialized\n");
100562306a36Sopenharmony_ci		return -EINVAL;
100662306a36Sopenharmony_ci	}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	if (!opts) {
100962306a36Sopenharmony_ci		opts = kzalloc(sizeof(*opts), GFP_KERNEL);
101062306a36Sopenharmony_ci		if (!opts)
101162306a36Sopenharmony_ci			return -ENOMEM;
101262306a36Sopenharmony_ci		*mnt_opts = opts;
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	switch (token) {
101662306a36Sopenharmony_ci	case Opt_context:
101762306a36Sopenharmony_ci		if (opts->context_sid || opts->defcontext_sid)
101862306a36Sopenharmony_ci			goto err;
101962306a36Sopenharmony_ci		dst_sid = &opts->context_sid;
102062306a36Sopenharmony_ci		break;
102162306a36Sopenharmony_ci	case Opt_fscontext:
102262306a36Sopenharmony_ci		if (opts->fscontext_sid)
102362306a36Sopenharmony_ci			goto err;
102462306a36Sopenharmony_ci		dst_sid = &opts->fscontext_sid;
102562306a36Sopenharmony_ci		break;
102662306a36Sopenharmony_ci	case Opt_rootcontext:
102762306a36Sopenharmony_ci		if (opts->rootcontext_sid)
102862306a36Sopenharmony_ci			goto err;
102962306a36Sopenharmony_ci		dst_sid = &opts->rootcontext_sid;
103062306a36Sopenharmony_ci		break;
103162306a36Sopenharmony_ci	case Opt_defcontext:
103262306a36Sopenharmony_ci		if (opts->context_sid || opts->defcontext_sid)
103362306a36Sopenharmony_ci			goto err;
103462306a36Sopenharmony_ci		dst_sid = &opts->defcontext_sid;
103562306a36Sopenharmony_ci		break;
103662306a36Sopenharmony_ci	default:
103762306a36Sopenharmony_ci		WARN_ON(1);
103862306a36Sopenharmony_ci		return -EINVAL;
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci	rc = security_context_str_to_sid(s, dst_sid, GFP_KERNEL);
104162306a36Sopenharmony_ci	if (rc)
104262306a36Sopenharmony_ci		pr_warn("SELinux: security_context_str_to_sid (%s) failed with errno=%d\n",
104362306a36Sopenharmony_ci			s, rc);
104462306a36Sopenharmony_ci	return rc;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cierr:
104762306a36Sopenharmony_ci	pr_warn(SEL_MOUNT_FAIL_MSG);
104862306a36Sopenharmony_ci	return -EINVAL;
104962306a36Sopenharmony_ci}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_cistatic int show_sid(struct seq_file *m, u32 sid)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	char *context = NULL;
105462306a36Sopenharmony_ci	u32 len;
105562306a36Sopenharmony_ci	int rc;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	rc = security_sid_to_context(sid, &context, &len);
105862306a36Sopenharmony_ci	if (!rc) {
105962306a36Sopenharmony_ci		bool has_comma = strchr(context, ',');
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci		seq_putc(m, '=');
106262306a36Sopenharmony_ci		if (has_comma)
106362306a36Sopenharmony_ci			seq_putc(m, '\"');
106462306a36Sopenharmony_ci		seq_escape(m, context, "\"\n\\");
106562306a36Sopenharmony_ci		if (has_comma)
106662306a36Sopenharmony_ci			seq_putc(m, '\"');
106762306a36Sopenharmony_ci	}
106862306a36Sopenharmony_ci	kfree(context);
106962306a36Sopenharmony_ci	return rc;
107062306a36Sopenharmony_ci}
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_cistatic int selinux_sb_show_options(struct seq_file *m, struct super_block *sb)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	struct superblock_security_struct *sbsec = selinux_superblock(sb);
107562306a36Sopenharmony_ci	int rc;
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci	if (!(sbsec->flags & SE_SBINITIALIZED))
107862306a36Sopenharmony_ci		return 0;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	if (!selinux_initialized())
108162306a36Sopenharmony_ci		return 0;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	if (sbsec->flags & FSCONTEXT_MNT) {
108462306a36Sopenharmony_ci		seq_putc(m, ',');
108562306a36Sopenharmony_ci		seq_puts(m, FSCONTEXT_STR);
108662306a36Sopenharmony_ci		rc = show_sid(m, sbsec->sid);
108762306a36Sopenharmony_ci		if (rc)
108862306a36Sopenharmony_ci			return rc;
108962306a36Sopenharmony_ci	}
109062306a36Sopenharmony_ci	if (sbsec->flags & CONTEXT_MNT) {
109162306a36Sopenharmony_ci		seq_putc(m, ',');
109262306a36Sopenharmony_ci		seq_puts(m, CONTEXT_STR);
109362306a36Sopenharmony_ci		rc = show_sid(m, sbsec->mntpoint_sid);
109462306a36Sopenharmony_ci		if (rc)
109562306a36Sopenharmony_ci			return rc;
109662306a36Sopenharmony_ci	}
109762306a36Sopenharmony_ci	if (sbsec->flags & DEFCONTEXT_MNT) {
109862306a36Sopenharmony_ci		seq_putc(m, ',');
109962306a36Sopenharmony_ci		seq_puts(m, DEFCONTEXT_STR);
110062306a36Sopenharmony_ci		rc = show_sid(m, sbsec->def_sid);
110162306a36Sopenharmony_ci		if (rc)
110262306a36Sopenharmony_ci			return rc;
110362306a36Sopenharmony_ci	}
110462306a36Sopenharmony_ci	if (sbsec->flags & ROOTCONTEXT_MNT) {
110562306a36Sopenharmony_ci		struct dentry *root = sb->s_root;
110662306a36Sopenharmony_ci		struct inode_security_struct *isec = backing_inode_security(root);
110762306a36Sopenharmony_ci		seq_putc(m, ',');
110862306a36Sopenharmony_ci		seq_puts(m, ROOTCONTEXT_STR);
110962306a36Sopenharmony_ci		rc = show_sid(m, isec->sid);
111062306a36Sopenharmony_ci		if (rc)
111162306a36Sopenharmony_ci			return rc;
111262306a36Sopenharmony_ci	}
111362306a36Sopenharmony_ci	if (sbsec->flags & SBLABEL_MNT) {
111462306a36Sopenharmony_ci		seq_putc(m, ',');
111562306a36Sopenharmony_ci		seq_puts(m, SECLABEL_STR);
111662306a36Sopenharmony_ci	}
111762306a36Sopenharmony_ci	return 0;
111862306a36Sopenharmony_ci}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_cistatic inline u16 inode_mode_to_security_class(umode_t mode)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	switch (mode & S_IFMT) {
112362306a36Sopenharmony_ci	case S_IFSOCK:
112462306a36Sopenharmony_ci		return SECCLASS_SOCK_FILE;
112562306a36Sopenharmony_ci	case S_IFLNK:
112662306a36Sopenharmony_ci		return SECCLASS_LNK_FILE;
112762306a36Sopenharmony_ci	case S_IFREG:
112862306a36Sopenharmony_ci		return SECCLASS_FILE;
112962306a36Sopenharmony_ci	case S_IFBLK:
113062306a36Sopenharmony_ci		return SECCLASS_BLK_FILE;
113162306a36Sopenharmony_ci	case S_IFDIR:
113262306a36Sopenharmony_ci		return SECCLASS_DIR;
113362306a36Sopenharmony_ci	case S_IFCHR:
113462306a36Sopenharmony_ci		return SECCLASS_CHR_FILE;
113562306a36Sopenharmony_ci	case S_IFIFO:
113662306a36Sopenharmony_ci		return SECCLASS_FIFO_FILE;
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	}
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	return SECCLASS_FILE;
114162306a36Sopenharmony_ci}
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_cistatic inline int default_protocol_stream(int protocol)
114462306a36Sopenharmony_ci{
114562306a36Sopenharmony_ci	return (protocol == IPPROTO_IP || protocol == IPPROTO_TCP ||
114662306a36Sopenharmony_ci		protocol == IPPROTO_MPTCP);
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_cistatic inline int default_protocol_dgram(int protocol)
115062306a36Sopenharmony_ci{
115162306a36Sopenharmony_ci	return (protocol == IPPROTO_IP || protocol == IPPROTO_UDP);
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_cistatic inline u16 socket_type_to_security_class(int family, int type, int protocol)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	bool extsockclass = selinux_policycap_extsockclass();
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	switch (family) {
115962306a36Sopenharmony_ci	case PF_UNIX:
116062306a36Sopenharmony_ci		switch (type) {
116162306a36Sopenharmony_ci		case SOCK_STREAM:
116262306a36Sopenharmony_ci		case SOCK_SEQPACKET:
116362306a36Sopenharmony_ci			return SECCLASS_UNIX_STREAM_SOCKET;
116462306a36Sopenharmony_ci		case SOCK_DGRAM:
116562306a36Sopenharmony_ci		case SOCK_RAW:
116662306a36Sopenharmony_ci			return SECCLASS_UNIX_DGRAM_SOCKET;
116762306a36Sopenharmony_ci		}
116862306a36Sopenharmony_ci		break;
116962306a36Sopenharmony_ci	case PF_INET:
117062306a36Sopenharmony_ci	case PF_INET6:
117162306a36Sopenharmony_ci		switch (type) {
117262306a36Sopenharmony_ci		case SOCK_STREAM:
117362306a36Sopenharmony_ci		case SOCK_SEQPACKET:
117462306a36Sopenharmony_ci			if (default_protocol_stream(protocol))
117562306a36Sopenharmony_ci				return SECCLASS_TCP_SOCKET;
117662306a36Sopenharmony_ci			else if (extsockclass && protocol == IPPROTO_SCTP)
117762306a36Sopenharmony_ci				return SECCLASS_SCTP_SOCKET;
117862306a36Sopenharmony_ci			else
117962306a36Sopenharmony_ci				return SECCLASS_RAWIP_SOCKET;
118062306a36Sopenharmony_ci		case SOCK_DGRAM:
118162306a36Sopenharmony_ci			if (default_protocol_dgram(protocol))
118262306a36Sopenharmony_ci				return SECCLASS_UDP_SOCKET;
118362306a36Sopenharmony_ci			else if (extsockclass && (protocol == IPPROTO_ICMP ||
118462306a36Sopenharmony_ci						  protocol == IPPROTO_ICMPV6))
118562306a36Sopenharmony_ci				return SECCLASS_ICMP_SOCKET;
118662306a36Sopenharmony_ci			else
118762306a36Sopenharmony_ci				return SECCLASS_RAWIP_SOCKET;
118862306a36Sopenharmony_ci		case SOCK_DCCP:
118962306a36Sopenharmony_ci			return SECCLASS_DCCP_SOCKET;
119062306a36Sopenharmony_ci		default:
119162306a36Sopenharmony_ci			return SECCLASS_RAWIP_SOCKET;
119262306a36Sopenharmony_ci		}
119362306a36Sopenharmony_ci		break;
119462306a36Sopenharmony_ci	case PF_NETLINK:
119562306a36Sopenharmony_ci		switch (protocol) {
119662306a36Sopenharmony_ci		case NETLINK_ROUTE:
119762306a36Sopenharmony_ci			return SECCLASS_NETLINK_ROUTE_SOCKET;
119862306a36Sopenharmony_ci		case NETLINK_SOCK_DIAG:
119962306a36Sopenharmony_ci			return SECCLASS_NETLINK_TCPDIAG_SOCKET;
120062306a36Sopenharmony_ci		case NETLINK_NFLOG:
120162306a36Sopenharmony_ci			return SECCLASS_NETLINK_NFLOG_SOCKET;
120262306a36Sopenharmony_ci		case NETLINK_XFRM:
120362306a36Sopenharmony_ci			return SECCLASS_NETLINK_XFRM_SOCKET;
120462306a36Sopenharmony_ci		case NETLINK_SELINUX:
120562306a36Sopenharmony_ci			return SECCLASS_NETLINK_SELINUX_SOCKET;
120662306a36Sopenharmony_ci		case NETLINK_ISCSI:
120762306a36Sopenharmony_ci			return SECCLASS_NETLINK_ISCSI_SOCKET;
120862306a36Sopenharmony_ci		case NETLINK_AUDIT:
120962306a36Sopenharmony_ci			return SECCLASS_NETLINK_AUDIT_SOCKET;
121062306a36Sopenharmony_ci		case NETLINK_FIB_LOOKUP:
121162306a36Sopenharmony_ci			return SECCLASS_NETLINK_FIB_LOOKUP_SOCKET;
121262306a36Sopenharmony_ci		case NETLINK_CONNECTOR:
121362306a36Sopenharmony_ci			return SECCLASS_NETLINK_CONNECTOR_SOCKET;
121462306a36Sopenharmony_ci		case NETLINK_NETFILTER:
121562306a36Sopenharmony_ci			return SECCLASS_NETLINK_NETFILTER_SOCKET;
121662306a36Sopenharmony_ci		case NETLINK_DNRTMSG:
121762306a36Sopenharmony_ci			return SECCLASS_NETLINK_DNRT_SOCKET;
121862306a36Sopenharmony_ci		case NETLINK_KOBJECT_UEVENT:
121962306a36Sopenharmony_ci			return SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET;
122062306a36Sopenharmony_ci		case NETLINK_GENERIC:
122162306a36Sopenharmony_ci			return SECCLASS_NETLINK_GENERIC_SOCKET;
122262306a36Sopenharmony_ci		case NETLINK_SCSITRANSPORT:
122362306a36Sopenharmony_ci			return SECCLASS_NETLINK_SCSITRANSPORT_SOCKET;
122462306a36Sopenharmony_ci		case NETLINK_RDMA:
122562306a36Sopenharmony_ci			return SECCLASS_NETLINK_RDMA_SOCKET;
122662306a36Sopenharmony_ci		case NETLINK_CRYPTO:
122762306a36Sopenharmony_ci			return SECCLASS_NETLINK_CRYPTO_SOCKET;
122862306a36Sopenharmony_ci		default:
122962306a36Sopenharmony_ci			return SECCLASS_NETLINK_SOCKET;
123062306a36Sopenharmony_ci		}
123162306a36Sopenharmony_ci	case PF_PACKET:
123262306a36Sopenharmony_ci		return SECCLASS_PACKET_SOCKET;
123362306a36Sopenharmony_ci	case PF_KEY:
123462306a36Sopenharmony_ci		return SECCLASS_KEY_SOCKET;
123562306a36Sopenharmony_ci	case PF_APPLETALK:
123662306a36Sopenharmony_ci		return SECCLASS_APPLETALK_SOCKET;
123762306a36Sopenharmony_ci	}
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	if (extsockclass) {
124062306a36Sopenharmony_ci		switch (family) {
124162306a36Sopenharmony_ci		case PF_AX25:
124262306a36Sopenharmony_ci			return SECCLASS_AX25_SOCKET;
124362306a36Sopenharmony_ci		case PF_IPX:
124462306a36Sopenharmony_ci			return SECCLASS_IPX_SOCKET;
124562306a36Sopenharmony_ci		case PF_NETROM:
124662306a36Sopenharmony_ci			return SECCLASS_NETROM_SOCKET;
124762306a36Sopenharmony_ci		case PF_ATMPVC:
124862306a36Sopenharmony_ci			return SECCLASS_ATMPVC_SOCKET;
124962306a36Sopenharmony_ci		case PF_X25:
125062306a36Sopenharmony_ci			return SECCLASS_X25_SOCKET;
125162306a36Sopenharmony_ci		case PF_ROSE:
125262306a36Sopenharmony_ci			return SECCLASS_ROSE_SOCKET;
125362306a36Sopenharmony_ci		case PF_DECnet:
125462306a36Sopenharmony_ci			return SECCLASS_DECNET_SOCKET;
125562306a36Sopenharmony_ci		case PF_ATMSVC:
125662306a36Sopenharmony_ci			return SECCLASS_ATMSVC_SOCKET;
125762306a36Sopenharmony_ci		case PF_RDS:
125862306a36Sopenharmony_ci			return SECCLASS_RDS_SOCKET;
125962306a36Sopenharmony_ci		case PF_IRDA:
126062306a36Sopenharmony_ci			return SECCLASS_IRDA_SOCKET;
126162306a36Sopenharmony_ci		case PF_PPPOX:
126262306a36Sopenharmony_ci			return SECCLASS_PPPOX_SOCKET;
126362306a36Sopenharmony_ci		case PF_LLC:
126462306a36Sopenharmony_ci			return SECCLASS_LLC_SOCKET;
126562306a36Sopenharmony_ci		case PF_CAN:
126662306a36Sopenharmony_ci			return SECCLASS_CAN_SOCKET;
126762306a36Sopenharmony_ci		case PF_TIPC:
126862306a36Sopenharmony_ci			return SECCLASS_TIPC_SOCKET;
126962306a36Sopenharmony_ci		case PF_BLUETOOTH:
127062306a36Sopenharmony_ci			return SECCLASS_BLUETOOTH_SOCKET;
127162306a36Sopenharmony_ci		case PF_IUCV:
127262306a36Sopenharmony_ci			return SECCLASS_IUCV_SOCKET;
127362306a36Sopenharmony_ci		case PF_RXRPC:
127462306a36Sopenharmony_ci			return SECCLASS_RXRPC_SOCKET;
127562306a36Sopenharmony_ci		case PF_ISDN:
127662306a36Sopenharmony_ci			return SECCLASS_ISDN_SOCKET;
127762306a36Sopenharmony_ci		case PF_PHONET:
127862306a36Sopenharmony_ci			return SECCLASS_PHONET_SOCKET;
127962306a36Sopenharmony_ci		case PF_IEEE802154:
128062306a36Sopenharmony_ci			return SECCLASS_IEEE802154_SOCKET;
128162306a36Sopenharmony_ci		case PF_CAIF:
128262306a36Sopenharmony_ci			return SECCLASS_CAIF_SOCKET;
128362306a36Sopenharmony_ci		case PF_ALG:
128462306a36Sopenharmony_ci			return SECCLASS_ALG_SOCKET;
128562306a36Sopenharmony_ci		case PF_NFC:
128662306a36Sopenharmony_ci			return SECCLASS_NFC_SOCKET;
128762306a36Sopenharmony_ci		case PF_VSOCK:
128862306a36Sopenharmony_ci			return SECCLASS_VSOCK_SOCKET;
128962306a36Sopenharmony_ci		case PF_KCM:
129062306a36Sopenharmony_ci			return SECCLASS_KCM_SOCKET;
129162306a36Sopenharmony_ci		case PF_QIPCRTR:
129262306a36Sopenharmony_ci			return SECCLASS_QIPCRTR_SOCKET;
129362306a36Sopenharmony_ci		case PF_SMC:
129462306a36Sopenharmony_ci			return SECCLASS_SMC_SOCKET;
129562306a36Sopenharmony_ci		case PF_XDP:
129662306a36Sopenharmony_ci			return SECCLASS_XDP_SOCKET;
129762306a36Sopenharmony_ci		case PF_MCTP:
129862306a36Sopenharmony_ci			return SECCLASS_MCTP_SOCKET;
129962306a36Sopenharmony_ci#if PF_MAX > 46
130062306a36Sopenharmony_ci#error New address family defined, please update this function.
130162306a36Sopenharmony_ci#endif
130262306a36Sopenharmony_ci		}
130362306a36Sopenharmony_ci	}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	return SECCLASS_SOCKET;
130662306a36Sopenharmony_ci}
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_cistatic int selinux_genfs_get_sid(struct dentry *dentry,
130962306a36Sopenharmony_ci				 u16 tclass,
131062306a36Sopenharmony_ci				 u16 flags,
131162306a36Sopenharmony_ci				 u32 *sid)
131262306a36Sopenharmony_ci{
131362306a36Sopenharmony_ci	int rc;
131462306a36Sopenharmony_ci	struct super_block *sb = dentry->d_sb;
131562306a36Sopenharmony_ci	char *buffer, *path;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	buffer = (char *)__get_free_page(GFP_KERNEL);
131862306a36Sopenharmony_ci	if (!buffer)
131962306a36Sopenharmony_ci		return -ENOMEM;
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_ci	path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
132262306a36Sopenharmony_ci	if (IS_ERR(path))
132362306a36Sopenharmony_ci		rc = PTR_ERR(path);
132462306a36Sopenharmony_ci	else {
132562306a36Sopenharmony_ci		if (flags & SE_SBPROC) {
132662306a36Sopenharmony_ci			/* each process gets a /proc/PID/ entry. Strip off the
132762306a36Sopenharmony_ci			 * PID part to get a valid selinux labeling.
132862306a36Sopenharmony_ci			 * e.g. /proc/1/net/rpc/nfs -> /net/rpc/nfs */
132962306a36Sopenharmony_ci			while (path[1] >= '0' && path[1] <= '9') {
133062306a36Sopenharmony_ci				path[1] = '/';
133162306a36Sopenharmony_ci				path++;
133262306a36Sopenharmony_ci			}
133362306a36Sopenharmony_ci		}
133462306a36Sopenharmony_ci		rc = security_genfs_sid(sb->s_type->name,
133562306a36Sopenharmony_ci					path, tclass, sid);
133662306a36Sopenharmony_ci		if (rc == -ENOENT) {
133762306a36Sopenharmony_ci			/* No match in policy, mark as unlabeled. */
133862306a36Sopenharmony_ci			*sid = SECINITSID_UNLABELED;
133962306a36Sopenharmony_ci			rc = 0;
134062306a36Sopenharmony_ci		}
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci	free_page((unsigned long)buffer);
134362306a36Sopenharmony_ci	return rc;
134462306a36Sopenharmony_ci}
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_cistatic int inode_doinit_use_xattr(struct inode *inode, struct dentry *dentry,
134762306a36Sopenharmony_ci				  u32 def_sid, u32 *sid)
134862306a36Sopenharmony_ci{
134962306a36Sopenharmony_ci#define INITCONTEXTLEN 255
135062306a36Sopenharmony_ci	char *context;
135162306a36Sopenharmony_ci	unsigned int len;
135262306a36Sopenharmony_ci	int rc;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	len = INITCONTEXTLEN;
135562306a36Sopenharmony_ci	context = kmalloc(len + 1, GFP_NOFS);
135662306a36Sopenharmony_ci	if (!context)
135762306a36Sopenharmony_ci		return -ENOMEM;
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci	context[len] = '\0';
136062306a36Sopenharmony_ci	rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
136162306a36Sopenharmony_ci	if (rc == -ERANGE) {
136262306a36Sopenharmony_ci		kfree(context);
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci		/* Need a larger buffer.  Query for the right size. */
136562306a36Sopenharmony_ci		rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0);
136662306a36Sopenharmony_ci		if (rc < 0)
136762306a36Sopenharmony_ci			return rc;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci		len = rc;
137062306a36Sopenharmony_ci		context = kmalloc(len + 1, GFP_NOFS);
137162306a36Sopenharmony_ci		if (!context)
137262306a36Sopenharmony_ci			return -ENOMEM;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci		context[len] = '\0';
137562306a36Sopenharmony_ci		rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX,
137662306a36Sopenharmony_ci				    context, len);
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci	if (rc < 0) {
137962306a36Sopenharmony_ci		kfree(context);
138062306a36Sopenharmony_ci		if (rc != -ENODATA) {
138162306a36Sopenharmony_ci			pr_warn("SELinux: %s:  getxattr returned %d for dev=%s ino=%ld\n",
138262306a36Sopenharmony_ci				__func__, -rc, inode->i_sb->s_id, inode->i_ino);
138362306a36Sopenharmony_ci			return rc;
138462306a36Sopenharmony_ci		}
138562306a36Sopenharmony_ci		*sid = def_sid;
138662306a36Sopenharmony_ci		return 0;
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	rc = security_context_to_sid_default(context, rc, sid,
139062306a36Sopenharmony_ci					     def_sid, GFP_NOFS);
139162306a36Sopenharmony_ci	if (rc) {
139262306a36Sopenharmony_ci		char *dev = inode->i_sb->s_id;
139362306a36Sopenharmony_ci		unsigned long ino = inode->i_ino;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci		if (rc == -EINVAL) {
139662306a36Sopenharmony_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",
139762306a36Sopenharmony_ci					      ino, dev, context);
139862306a36Sopenharmony_ci		} else {
139962306a36Sopenharmony_ci			pr_warn("SELinux: %s:  context_to_sid(%s) returned %d for dev=%s ino=%ld\n",
140062306a36Sopenharmony_ci				__func__, context, -rc, dev, ino);
140162306a36Sopenharmony_ci		}
140262306a36Sopenharmony_ci	}
140362306a36Sopenharmony_ci	kfree(context);
140462306a36Sopenharmony_ci	return 0;
140562306a36Sopenharmony_ci}
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci/* The inode's security attributes must be initialized before first use. */
140862306a36Sopenharmony_cistatic int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
140962306a36Sopenharmony_ci{
141062306a36Sopenharmony_ci	struct superblock_security_struct *sbsec = NULL;
141162306a36Sopenharmony_ci	struct inode_security_struct *isec = selinux_inode(inode);
141262306a36Sopenharmony_ci	u32 task_sid, sid = 0;
141362306a36Sopenharmony_ci	u16 sclass;
141462306a36Sopenharmony_ci	struct dentry *dentry;
141562306a36Sopenharmony_ci	int rc = 0;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	if (isec->initialized == LABEL_INITIALIZED)
141862306a36Sopenharmony_ci		return 0;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	spin_lock(&isec->lock);
142162306a36Sopenharmony_ci	if (isec->initialized == LABEL_INITIALIZED)
142262306a36Sopenharmony_ci		goto out_unlock;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	if (isec->sclass == SECCLASS_FILE)
142562306a36Sopenharmony_ci		isec->sclass = inode_mode_to_security_class(inode->i_mode);
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	sbsec = selinux_superblock(inode->i_sb);
142862306a36Sopenharmony_ci	if (!(sbsec->flags & SE_SBINITIALIZED)) {
142962306a36Sopenharmony_ci		/* Defer initialization until selinux_complete_init,
143062306a36Sopenharmony_ci		   after the initial policy is loaded and the security
143162306a36Sopenharmony_ci		   server is ready to handle calls. */
143262306a36Sopenharmony_ci		spin_lock(&sbsec->isec_lock);
143362306a36Sopenharmony_ci		if (list_empty(&isec->list))
143462306a36Sopenharmony_ci			list_add(&isec->list, &sbsec->isec_head);
143562306a36Sopenharmony_ci		spin_unlock(&sbsec->isec_lock);
143662306a36Sopenharmony_ci		goto out_unlock;
143762306a36Sopenharmony_ci	}
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	sclass = isec->sclass;
144062306a36Sopenharmony_ci	task_sid = isec->task_sid;
144162306a36Sopenharmony_ci	sid = isec->sid;
144262306a36Sopenharmony_ci	isec->initialized = LABEL_PENDING;
144362306a36Sopenharmony_ci	spin_unlock(&isec->lock);
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	switch (sbsec->behavior) {
144662306a36Sopenharmony_ci	/*
144762306a36Sopenharmony_ci	 * In case of SECURITY_FS_USE_NATIVE we need to re-fetch the labels
144862306a36Sopenharmony_ci	 * via xattr when called from delayed_superblock_init().
144962306a36Sopenharmony_ci	 */
145062306a36Sopenharmony_ci	case SECURITY_FS_USE_NATIVE:
145162306a36Sopenharmony_ci	case SECURITY_FS_USE_XATTR:
145262306a36Sopenharmony_ci		if (!(inode->i_opflags & IOP_XATTR)) {
145362306a36Sopenharmony_ci			sid = sbsec->def_sid;
145462306a36Sopenharmony_ci			break;
145562306a36Sopenharmony_ci		}
145662306a36Sopenharmony_ci		/* Need a dentry, since the xattr API requires one.
145762306a36Sopenharmony_ci		   Life would be simpler if we could just pass the inode. */
145862306a36Sopenharmony_ci		if (opt_dentry) {
145962306a36Sopenharmony_ci			/* Called from d_instantiate or d_splice_alias. */
146062306a36Sopenharmony_ci			dentry = dget(opt_dentry);
146162306a36Sopenharmony_ci		} else {
146262306a36Sopenharmony_ci			/*
146362306a36Sopenharmony_ci			 * Called from selinux_complete_init, try to find a dentry.
146462306a36Sopenharmony_ci			 * Some filesystems really want a connected one, so try
146562306a36Sopenharmony_ci			 * that first.  We could split SECURITY_FS_USE_XATTR in
146662306a36Sopenharmony_ci			 * two, depending upon that...
146762306a36Sopenharmony_ci			 */
146862306a36Sopenharmony_ci			dentry = d_find_alias(inode);
146962306a36Sopenharmony_ci			if (!dentry)
147062306a36Sopenharmony_ci				dentry = d_find_any_alias(inode);
147162306a36Sopenharmony_ci		}
147262306a36Sopenharmony_ci		if (!dentry) {
147362306a36Sopenharmony_ci			/*
147462306a36Sopenharmony_ci			 * this is can be hit on boot when a file is accessed
147562306a36Sopenharmony_ci			 * before the policy is loaded.  When we load policy we
147662306a36Sopenharmony_ci			 * may find inodes that have no dentry on the
147762306a36Sopenharmony_ci			 * sbsec->isec_head list.  No reason to complain as these
147862306a36Sopenharmony_ci			 * will get fixed up the next time we go through
147962306a36Sopenharmony_ci			 * inode_doinit with a dentry, before these inodes could
148062306a36Sopenharmony_ci			 * be used again by userspace.
148162306a36Sopenharmony_ci			 */
148262306a36Sopenharmony_ci			goto out_invalid;
148362306a36Sopenharmony_ci		}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci		rc = inode_doinit_use_xattr(inode, dentry, sbsec->def_sid,
148662306a36Sopenharmony_ci					    &sid);
148762306a36Sopenharmony_ci		dput(dentry);
148862306a36Sopenharmony_ci		if (rc)
148962306a36Sopenharmony_ci			goto out;
149062306a36Sopenharmony_ci		break;
149162306a36Sopenharmony_ci	case SECURITY_FS_USE_TASK:
149262306a36Sopenharmony_ci		sid = task_sid;
149362306a36Sopenharmony_ci		break;
149462306a36Sopenharmony_ci	case SECURITY_FS_USE_TRANS:
149562306a36Sopenharmony_ci		/* Default to the fs SID. */
149662306a36Sopenharmony_ci		sid = sbsec->sid;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci		/* Try to obtain a transition SID. */
149962306a36Sopenharmony_ci		rc = security_transition_sid(task_sid, sid,
150062306a36Sopenharmony_ci					     sclass, NULL, &sid);
150162306a36Sopenharmony_ci		if (rc)
150262306a36Sopenharmony_ci			goto out;
150362306a36Sopenharmony_ci		break;
150462306a36Sopenharmony_ci	case SECURITY_FS_USE_MNTPOINT:
150562306a36Sopenharmony_ci		sid = sbsec->mntpoint_sid;
150662306a36Sopenharmony_ci		break;
150762306a36Sopenharmony_ci	default:
150862306a36Sopenharmony_ci		/* Default to the fs superblock SID. */
150962306a36Sopenharmony_ci		sid = sbsec->sid;
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci		if ((sbsec->flags & SE_SBGENFS) &&
151262306a36Sopenharmony_ci		     (!S_ISLNK(inode->i_mode) ||
151362306a36Sopenharmony_ci		      selinux_policycap_genfs_seclabel_symlinks())) {
151462306a36Sopenharmony_ci			/* We must have a dentry to determine the label on
151562306a36Sopenharmony_ci			 * procfs inodes */
151662306a36Sopenharmony_ci			if (opt_dentry) {
151762306a36Sopenharmony_ci				/* Called from d_instantiate or
151862306a36Sopenharmony_ci				 * d_splice_alias. */
151962306a36Sopenharmony_ci				dentry = dget(opt_dentry);
152062306a36Sopenharmony_ci			} else {
152162306a36Sopenharmony_ci				/* Called from selinux_complete_init, try to
152262306a36Sopenharmony_ci				 * find a dentry.  Some filesystems really want
152362306a36Sopenharmony_ci				 * a connected one, so try that first.
152462306a36Sopenharmony_ci				 */
152562306a36Sopenharmony_ci				dentry = d_find_alias(inode);
152662306a36Sopenharmony_ci				if (!dentry)
152762306a36Sopenharmony_ci					dentry = d_find_any_alias(inode);
152862306a36Sopenharmony_ci			}
152962306a36Sopenharmony_ci			/*
153062306a36Sopenharmony_ci			 * This can be hit on boot when a file is accessed
153162306a36Sopenharmony_ci			 * before the policy is loaded.  When we load policy we
153262306a36Sopenharmony_ci			 * may find inodes that have no dentry on the
153362306a36Sopenharmony_ci			 * sbsec->isec_head list.  No reason to complain as
153462306a36Sopenharmony_ci			 * these will get fixed up the next time we go through
153562306a36Sopenharmony_ci			 * inode_doinit() with a dentry, before these inodes
153662306a36Sopenharmony_ci			 * could be used again by userspace.
153762306a36Sopenharmony_ci			 */
153862306a36Sopenharmony_ci			if (!dentry)
153962306a36Sopenharmony_ci				goto out_invalid;
154062306a36Sopenharmony_ci			rc = selinux_genfs_get_sid(dentry, sclass,
154162306a36Sopenharmony_ci						   sbsec->flags, &sid);
154262306a36Sopenharmony_ci			if (rc) {
154362306a36Sopenharmony_ci				dput(dentry);
154462306a36Sopenharmony_ci				goto out;
154562306a36Sopenharmony_ci			}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci			if ((sbsec->flags & SE_SBGENFS_XATTR) &&
154862306a36Sopenharmony_ci			    (inode->i_opflags & IOP_XATTR)) {
154962306a36Sopenharmony_ci				rc = inode_doinit_use_xattr(inode, dentry,
155062306a36Sopenharmony_ci							    sid, &sid);
155162306a36Sopenharmony_ci				if (rc) {
155262306a36Sopenharmony_ci					dput(dentry);
155362306a36Sopenharmony_ci					goto out;
155462306a36Sopenharmony_ci				}
155562306a36Sopenharmony_ci			}
155662306a36Sopenharmony_ci			dput(dentry);
155762306a36Sopenharmony_ci		}
155862306a36Sopenharmony_ci		break;
155962306a36Sopenharmony_ci	}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ciout:
156262306a36Sopenharmony_ci	spin_lock(&isec->lock);
156362306a36Sopenharmony_ci	if (isec->initialized == LABEL_PENDING) {
156462306a36Sopenharmony_ci		if (rc) {
156562306a36Sopenharmony_ci			isec->initialized = LABEL_INVALID;
156662306a36Sopenharmony_ci			goto out_unlock;
156762306a36Sopenharmony_ci		}
156862306a36Sopenharmony_ci		isec->initialized = LABEL_INITIALIZED;
156962306a36Sopenharmony_ci		isec->sid = sid;
157062306a36Sopenharmony_ci	}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ciout_unlock:
157362306a36Sopenharmony_ci	spin_unlock(&isec->lock);
157462306a36Sopenharmony_ci	return rc;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ciout_invalid:
157762306a36Sopenharmony_ci	spin_lock(&isec->lock);
157862306a36Sopenharmony_ci	if (isec->initialized == LABEL_PENDING) {
157962306a36Sopenharmony_ci		isec->initialized = LABEL_INVALID;
158062306a36Sopenharmony_ci		isec->sid = sid;
158162306a36Sopenharmony_ci	}
158262306a36Sopenharmony_ci	spin_unlock(&isec->lock);
158362306a36Sopenharmony_ci	return 0;
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci/* Convert a Linux signal to an access vector. */
158762306a36Sopenharmony_cistatic inline u32 signal_to_av(int sig)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	u32 perm = 0;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	switch (sig) {
159262306a36Sopenharmony_ci	case SIGCHLD:
159362306a36Sopenharmony_ci		/* Commonly granted from child to parent. */
159462306a36Sopenharmony_ci		perm = PROCESS__SIGCHLD;
159562306a36Sopenharmony_ci		break;
159662306a36Sopenharmony_ci	case SIGKILL:
159762306a36Sopenharmony_ci		/* Cannot be caught or ignored */
159862306a36Sopenharmony_ci		perm = PROCESS__SIGKILL;
159962306a36Sopenharmony_ci		break;
160062306a36Sopenharmony_ci	case SIGSTOP:
160162306a36Sopenharmony_ci		/* Cannot be caught or ignored */
160262306a36Sopenharmony_ci		perm = PROCESS__SIGSTOP;
160362306a36Sopenharmony_ci		break;
160462306a36Sopenharmony_ci	default:
160562306a36Sopenharmony_ci		/* All other signals. */
160662306a36Sopenharmony_ci		perm = PROCESS__SIGNAL;
160762306a36Sopenharmony_ci		break;
160862306a36Sopenharmony_ci	}
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci	return perm;
161162306a36Sopenharmony_ci}
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci#if CAP_LAST_CAP > 63
161462306a36Sopenharmony_ci#error Fix SELinux to handle capabilities > 63.
161562306a36Sopenharmony_ci#endif
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci/* Check whether a task is allowed to use a capability. */
161862306a36Sopenharmony_cistatic int cred_has_capability(const struct cred *cred,
161962306a36Sopenharmony_ci			       int cap, unsigned int opts, bool initns)
162062306a36Sopenharmony_ci{
162162306a36Sopenharmony_ci	struct common_audit_data ad;
162262306a36Sopenharmony_ci	struct av_decision avd;
162362306a36Sopenharmony_ci	u16 sclass;
162462306a36Sopenharmony_ci	u32 sid = cred_sid(cred);
162562306a36Sopenharmony_ci	u32 av = CAP_TO_MASK(cap);
162662306a36Sopenharmony_ci	int rc;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_CAP;
162962306a36Sopenharmony_ci	ad.u.cap = cap;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	switch (CAP_TO_INDEX(cap)) {
163262306a36Sopenharmony_ci	case 0:
163362306a36Sopenharmony_ci		sclass = initns ? SECCLASS_CAPABILITY : SECCLASS_CAP_USERNS;
163462306a36Sopenharmony_ci		break;
163562306a36Sopenharmony_ci	case 1:
163662306a36Sopenharmony_ci		sclass = initns ? SECCLASS_CAPABILITY2 : SECCLASS_CAP2_USERNS;
163762306a36Sopenharmony_ci		break;
163862306a36Sopenharmony_ci	default:
163962306a36Sopenharmony_ci		pr_err("SELinux:  out of range capability %d\n", cap);
164062306a36Sopenharmony_ci		BUG();
164162306a36Sopenharmony_ci		return -EINVAL;
164262306a36Sopenharmony_ci	}
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci	rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
164562306a36Sopenharmony_ci	if (!(opts & CAP_OPT_NOAUDIT)) {
164662306a36Sopenharmony_ci		int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
164762306a36Sopenharmony_ci		if (rc2)
164862306a36Sopenharmony_ci			return rc2;
164962306a36Sopenharmony_ci	}
165062306a36Sopenharmony_ci	return rc;
165162306a36Sopenharmony_ci}
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci/* Check whether a task has a particular permission to an inode.
165462306a36Sopenharmony_ci   The 'adp' parameter is optional and allows other audit
165562306a36Sopenharmony_ci   data to be passed (e.g. the dentry). */
165662306a36Sopenharmony_cistatic int inode_has_perm(const struct cred *cred,
165762306a36Sopenharmony_ci			  struct inode *inode,
165862306a36Sopenharmony_ci			  u32 perms,
165962306a36Sopenharmony_ci			  struct common_audit_data *adp)
166062306a36Sopenharmony_ci{
166162306a36Sopenharmony_ci	struct inode_security_struct *isec;
166262306a36Sopenharmony_ci	u32 sid;
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	if (unlikely(IS_PRIVATE(inode)))
166562306a36Sopenharmony_ci		return 0;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	sid = cred_sid(cred);
166862306a36Sopenharmony_ci	isec = selinux_inode(inode);
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, isec->sclass, perms, adp);
167162306a36Sopenharmony_ci}
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci/* Same as inode_has_perm, but pass explicit audit data containing
167462306a36Sopenharmony_ci   the dentry to help the auditing code to more easily generate the
167562306a36Sopenharmony_ci   pathname if needed. */
167662306a36Sopenharmony_cistatic inline int dentry_has_perm(const struct cred *cred,
167762306a36Sopenharmony_ci				  struct dentry *dentry,
167862306a36Sopenharmony_ci				  u32 av)
167962306a36Sopenharmony_ci{
168062306a36Sopenharmony_ci	struct inode *inode = d_backing_inode(dentry);
168162306a36Sopenharmony_ci	struct common_audit_data ad;
168262306a36Sopenharmony_ci
168362306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_DENTRY;
168462306a36Sopenharmony_ci	ad.u.dentry = dentry;
168562306a36Sopenharmony_ci	__inode_security_revalidate(inode, dentry, true);
168662306a36Sopenharmony_ci	return inode_has_perm(cred, inode, av, &ad);
168762306a36Sopenharmony_ci}
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci/* Same as inode_has_perm, but pass explicit audit data containing
169062306a36Sopenharmony_ci   the path to help the auditing code to more easily generate the
169162306a36Sopenharmony_ci   pathname if needed. */
169262306a36Sopenharmony_cistatic inline int path_has_perm(const struct cred *cred,
169362306a36Sopenharmony_ci				const struct path *path,
169462306a36Sopenharmony_ci				u32 av)
169562306a36Sopenharmony_ci{
169662306a36Sopenharmony_ci	struct inode *inode = d_backing_inode(path->dentry);
169762306a36Sopenharmony_ci	struct common_audit_data ad;
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_PATH;
170062306a36Sopenharmony_ci	ad.u.path = *path;
170162306a36Sopenharmony_ci	__inode_security_revalidate(inode, path->dentry, true);
170262306a36Sopenharmony_ci	return inode_has_perm(cred, inode, av, &ad);
170362306a36Sopenharmony_ci}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci/* Same as path_has_perm, but uses the inode from the file struct. */
170662306a36Sopenharmony_cistatic inline int file_path_has_perm(const struct cred *cred,
170762306a36Sopenharmony_ci				     struct file *file,
170862306a36Sopenharmony_ci				     u32 av)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	struct common_audit_data ad;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_FILE;
171362306a36Sopenharmony_ci	ad.u.file = file;
171462306a36Sopenharmony_ci	return inode_has_perm(cred, file_inode(file), av, &ad);
171562306a36Sopenharmony_ci}
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL
171862306a36Sopenharmony_cistatic int bpf_fd_pass(const struct file *file, u32 sid);
171962306a36Sopenharmony_ci#endif
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci/* Check whether a task can use an open file descriptor to
172262306a36Sopenharmony_ci   access an inode in a given way.  Check access to the
172362306a36Sopenharmony_ci   descriptor itself, and then use dentry_has_perm to
172462306a36Sopenharmony_ci   check a particular permission to the file.
172562306a36Sopenharmony_ci   Access to the descriptor is implicitly granted if it
172662306a36Sopenharmony_ci   has the same SID as the process.  If av is zero, then
172762306a36Sopenharmony_ci   access to the file is not checked, e.g. for cases
172862306a36Sopenharmony_ci   where only the descriptor is affected like seek. */
172962306a36Sopenharmony_cistatic int file_has_perm(const struct cred *cred,
173062306a36Sopenharmony_ci			 struct file *file,
173162306a36Sopenharmony_ci			 u32 av)
173262306a36Sopenharmony_ci{
173362306a36Sopenharmony_ci	struct file_security_struct *fsec = selinux_file(file);
173462306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
173562306a36Sopenharmony_ci	struct common_audit_data ad;
173662306a36Sopenharmony_ci	u32 sid = cred_sid(cred);
173762306a36Sopenharmony_ci	int rc;
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_FILE;
174062306a36Sopenharmony_ci	ad.u.file = file;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	if (sid != fsec->sid) {
174362306a36Sopenharmony_ci		rc = avc_has_perm(sid, fsec->sid,
174462306a36Sopenharmony_ci				  SECCLASS_FD,
174562306a36Sopenharmony_ci				  FD__USE,
174662306a36Sopenharmony_ci				  &ad);
174762306a36Sopenharmony_ci		if (rc)
174862306a36Sopenharmony_ci			goto out;
174962306a36Sopenharmony_ci	}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL
175262306a36Sopenharmony_ci	rc = bpf_fd_pass(file, cred_sid(cred));
175362306a36Sopenharmony_ci	if (rc)
175462306a36Sopenharmony_ci		return rc;
175562306a36Sopenharmony_ci#endif
175662306a36Sopenharmony_ci
175762306a36Sopenharmony_ci	/* av is zero if only checking access to the descriptor. */
175862306a36Sopenharmony_ci	rc = 0;
175962306a36Sopenharmony_ci	if (av)
176062306a36Sopenharmony_ci		rc = inode_has_perm(cred, inode, av, &ad);
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ciout:
176362306a36Sopenharmony_ci	return rc;
176462306a36Sopenharmony_ci}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci/*
176762306a36Sopenharmony_ci * Determine the label for an inode that might be unioned.
176862306a36Sopenharmony_ci */
176962306a36Sopenharmony_cistatic int
177062306a36Sopenharmony_ciselinux_determine_inode_label(const struct task_security_struct *tsec,
177162306a36Sopenharmony_ci				 struct inode *dir,
177262306a36Sopenharmony_ci				 const struct qstr *name, u16 tclass,
177362306a36Sopenharmony_ci				 u32 *_new_isid)
177462306a36Sopenharmony_ci{
177562306a36Sopenharmony_ci	const struct superblock_security_struct *sbsec =
177662306a36Sopenharmony_ci						selinux_superblock(dir->i_sb);
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	if ((sbsec->flags & SE_SBINITIALIZED) &&
177962306a36Sopenharmony_ci	    (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) {
178062306a36Sopenharmony_ci		*_new_isid = sbsec->mntpoint_sid;
178162306a36Sopenharmony_ci	} else if ((sbsec->flags & SBLABEL_MNT) &&
178262306a36Sopenharmony_ci		   tsec->create_sid) {
178362306a36Sopenharmony_ci		*_new_isid = tsec->create_sid;
178462306a36Sopenharmony_ci	} else {
178562306a36Sopenharmony_ci		const struct inode_security_struct *dsec = inode_security(dir);
178662306a36Sopenharmony_ci		return security_transition_sid(tsec->sid,
178762306a36Sopenharmony_ci					       dsec->sid, tclass,
178862306a36Sopenharmony_ci					       name, _new_isid);
178962306a36Sopenharmony_ci	}
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	return 0;
179262306a36Sopenharmony_ci}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci/* Check whether a task can create a file. */
179562306a36Sopenharmony_cistatic int may_create(struct inode *dir,
179662306a36Sopenharmony_ci		      struct dentry *dentry,
179762306a36Sopenharmony_ci		      u16 tclass)
179862306a36Sopenharmony_ci{
179962306a36Sopenharmony_ci	const struct task_security_struct *tsec = selinux_cred(current_cred());
180062306a36Sopenharmony_ci	struct inode_security_struct *dsec;
180162306a36Sopenharmony_ci	struct superblock_security_struct *sbsec;
180262306a36Sopenharmony_ci	u32 sid, newsid;
180362306a36Sopenharmony_ci	struct common_audit_data ad;
180462306a36Sopenharmony_ci	int rc;
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	dsec = inode_security(dir);
180762306a36Sopenharmony_ci	sbsec = selinux_superblock(dir->i_sb);
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci	sid = tsec->sid;
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_DENTRY;
181262306a36Sopenharmony_ci	ad.u.dentry = dentry;
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR,
181562306a36Sopenharmony_ci			  DIR__ADD_NAME | DIR__SEARCH,
181662306a36Sopenharmony_ci			  &ad);
181762306a36Sopenharmony_ci	if (rc)
181862306a36Sopenharmony_ci		return rc;
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	rc = selinux_determine_inode_label(tsec, dir, &dentry->d_name, tclass,
182162306a36Sopenharmony_ci					   &newsid);
182262306a36Sopenharmony_ci	if (rc)
182362306a36Sopenharmony_ci		return rc;
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci	rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad);
182662306a36Sopenharmony_ci	if (rc)
182762306a36Sopenharmony_ci		return rc;
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	return avc_has_perm(newsid, sbsec->sid,
183062306a36Sopenharmony_ci			    SECCLASS_FILESYSTEM,
183162306a36Sopenharmony_ci			    FILESYSTEM__ASSOCIATE, &ad);
183262306a36Sopenharmony_ci}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci#define MAY_LINK	0
183562306a36Sopenharmony_ci#define MAY_UNLINK	1
183662306a36Sopenharmony_ci#define MAY_RMDIR	2
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci/* Check whether a task can link, unlink, or rmdir a file/directory. */
183962306a36Sopenharmony_cistatic int may_link(struct inode *dir,
184062306a36Sopenharmony_ci		    struct dentry *dentry,
184162306a36Sopenharmony_ci		    int kind)
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci{
184462306a36Sopenharmony_ci	struct inode_security_struct *dsec, *isec;
184562306a36Sopenharmony_ci	struct common_audit_data ad;
184662306a36Sopenharmony_ci	u32 sid = current_sid();
184762306a36Sopenharmony_ci	u32 av;
184862306a36Sopenharmony_ci	int rc;
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_ci	dsec = inode_security(dir);
185162306a36Sopenharmony_ci	isec = backing_inode_security(dentry);
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_DENTRY;
185462306a36Sopenharmony_ci	ad.u.dentry = dentry;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	av = DIR__SEARCH;
185762306a36Sopenharmony_ci	av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
185862306a36Sopenharmony_ci	rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, av, &ad);
185962306a36Sopenharmony_ci	if (rc)
186062306a36Sopenharmony_ci		return rc;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	switch (kind) {
186362306a36Sopenharmony_ci	case MAY_LINK:
186462306a36Sopenharmony_ci		av = FILE__LINK;
186562306a36Sopenharmony_ci		break;
186662306a36Sopenharmony_ci	case MAY_UNLINK:
186762306a36Sopenharmony_ci		av = FILE__UNLINK;
186862306a36Sopenharmony_ci		break;
186962306a36Sopenharmony_ci	case MAY_RMDIR:
187062306a36Sopenharmony_ci		av = DIR__RMDIR;
187162306a36Sopenharmony_ci		break;
187262306a36Sopenharmony_ci	default:
187362306a36Sopenharmony_ci		pr_warn("SELinux: %s:  unrecognized kind %d\n",
187462306a36Sopenharmony_ci			__func__, kind);
187562306a36Sopenharmony_ci		return 0;
187662306a36Sopenharmony_ci	}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	rc = avc_has_perm(sid, isec->sid, isec->sclass, av, &ad);
187962306a36Sopenharmony_ci	return rc;
188062306a36Sopenharmony_ci}
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_cistatic inline int may_rename(struct inode *old_dir,
188362306a36Sopenharmony_ci			     struct dentry *old_dentry,
188462306a36Sopenharmony_ci			     struct inode *new_dir,
188562306a36Sopenharmony_ci			     struct dentry *new_dentry)
188662306a36Sopenharmony_ci{
188762306a36Sopenharmony_ci	struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
188862306a36Sopenharmony_ci	struct common_audit_data ad;
188962306a36Sopenharmony_ci	u32 sid = current_sid();
189062306a36Sopenharmony_ci	u32 av;
189162306a36Sopenharmony_ci	int old_is_dir, new_is_dir;
189262306a36Sopenharmony_ci	int rc;
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	old_dsec = inode_security(old_dir);
189562306a36Sopenharmony_ci	old_isec = backing_inode_security(old_dentry);
189662306a36Sopenharmony_ci	old_is_dir = d_is_dir(old_dentry);
189762306a36Sopenharmony_ci	new_dsec = inode_security(new_dir);
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_DENTRY;
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ci	ad.u.dentry = old_dentry;
190262306a36Sopenharmony_ci	rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR,
190362306a36Sopenharmony_ci			  DIR__REMOVE_NAME | DIR__SEARCH, &ad);
190462306a36Sopenharmony_ci	if (rc)
190562306a36Sopenharmony_ci		return rc;
190662306a36Sopenharmony_ci	rc = avc_has_perm(sid, old_isec->sid,
190762306a36Sopenharmony_ci			  old_isec->sclass, FILE__RENAME, &ad);
190862306a36Sopenharmony_ci	if (rc)
190962306a36Sopenharmony_ci		return rc;
191062306a36Sopenharmony_ci	if (old_is_dir && new_dir != old_dir) {
191162306a36Sopenharmony_ci		rc = avc_has_perm(sid, old_isec->sid,
191262306a36Sopenharmony_ci				  old_isec->sclass, DIR__REPARENT, &ad);
191362306a36Sopenharmony_ci		if (rc)
191462306a36Sopenharmony_ci			return rc;
191562306a36Sopenharmony_ci	}
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	ad.u.dentry = new_dentry;
191862306a36Sopenharmony_ci	av = DIR__ADD_NAME | DIR__SEARCH;
191962306a36Sopenharmony_ci	if (d_is_positive(new_dentry))
192062306a36Sopenharmony_ci		av |= DIR__REMOVE_NAME;
192162306a36Sopenharmony_ci	rc = avc_has_perm(sid, new_dsec->sid, SECCLASS_DIR, av, &ad);
192262306a36Sopenharmony_ci	if (rc)
192362306a36Sopenharmony_ci		return rc;
192462306a36Sopenharmony_ci	if (d_is_positive(new_dentry)) {
192562306a36Sopenharmony_ci		new_isec = backing_inode_security(new_dentry);
192662306a36Sopenharmony_ci		new_is_dir = d_is_dir(new_dentry);
192762306a36Sopenharmony_ci		rc = avc_has_perm(sid, new_isec->sid,
192862306a36Sopenharmony_ci				  new_isec->sclass,
192962306a36Sopenharmony_ci				  (new_is_dir ? DIR__RMDIR : FILE__UNLINK), &ad);
193062306a36Sopenharmony_ci		if (rc)
193162306a36Sopenharmony_ci			return rc;
193262306a36Sopenharmony_ci	}
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	return 0;
193562306a36Sopenharmony_ci}
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci/* Check whether a task can perform a filesystem operation. */
193862306a36Sopenharmony_cistatic int superblock_has_perm(const struct cred *cred,
193962306a36Sopenharmony_ci			       struct super_block *sb,
194062306a36Sopenharmony_ci			       u32 perms,
194162306a36Sopenharmony_ci			       struct common_audit_data *ad)
194262306a36Sopenharmony_ci{
194362306a36Sopenharmony_ci	struct superblock_security_struct *sbsec;
194462306a36Sopenharmony_ci	u32 sid = cred_sid(cred);
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	sbsec = selinux_superblock(sb);
194762306a36Sopenharmony_ci	return avc_has_perm(sid, sbsec->sid, SECCLASS_FILESYSTEM, perms, ad);
194862306a36Sopenharmony_ci}
194962306a36Sopenharmony_ci
195062306a36Sopenharmony_ci/* Convert a Linux mode and permission mask to an access vector. */
195162306a36Sopenharmony_cistatic inline u32 file_mask_to_av(int mode, int mask)
195262306a36Sopenharmony_ci{
195362306a36Sopenharmony_ci	u32 av = 0;
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	if (!S_ISDIR(mode)) {
195662306a36Sopenharmony_ci		if (mask & MAY_EXEC)
195762306a36Sopenharmony_ci			av |= FILE__EXECUTE;
195862306a36Sopenharmony_ci		if (mask & MAY_READ)
195962306a36Sopenharmony_ci			av |= FILE__READ;
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci		if (mask & MAY_APPEND)
196262306a36Sopenharmony_ci			av |= FILE__APPEND;
196362306a36Sopenharmony_ci		else if (mask & MAY_WRITE)
196462306a36Sopenharmony_ci			av |= FILE__WRITE;
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci	} else {
196762306a36Sopenharmony_ci		if (mask & MAY_EXEC)
196862306a36Sopenharmony_ci			av |= DIR__SEARCH;
196962306a36Sopenharmony_ci		if (mask & MAY_WRITE)
197062306a36Sopenharmony_ci			av |= DIR__WRITE;
197162306a36Sopenharmony_ci		if (mask & MAY_READ)
197262306a36Sopenharmony_ci			av |= DIR__READ;
197362306a36Sopenharmony_ci	}
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	return av;
197662306a36Sopenharmony_ci}
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci/* Convert a Linux file to an access vector. */
197962306a36Sopenharmony_cistatic inline u32 file_to_av(const struct file *file)
198062306a36Sopenharmony_ci{
198162306a36Sopenharmony_ci	u32 av = 0;
198262306a36Sopenharmony_ci
198362306a36Sopenharmony_ci	if (file->f_mode & FMODE_READ)
198462306a36Sopenharmony_ci		av |= FILE__READ;
198562306a36Sopenharmony_ci	if (file->f_mode & FMODE_WRITE) {
198662306a36Sopenharmony_ci		if (file->f_flags & O_APPEND)
198762306a36Sopenharmony_ci			av |= FILE__APPEND;
198862306a36Sopenharmony_ci		else
198962306a36Sopenharmony_ci			av |= FILE__WRITE;
199062306a36Sopenharmony_ci	}
199162306a36Sopenharmony_ci	if (!av) {
199262306a36Sopenharmony_ci		/*
199362306a36Sopenharmony_ci		 * Special file opened with flags 3 for ioctl-only use.
199462306a36Sopenharmony_ci		 */
199562306a36Sopenharmony_ci		av = FILE__IOCTL;
199662306a36Sopenharmony_ci	}
199762306a36Sopenharmony_ci
199862306a36Sopenharmony_ci	return av;
199962306a36Sopenharmony_ci}
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci/*
200262306a36Sopenharmony_ci * Convert a file to an access vector and include the correct
200362306a36Sopenharmony_ci * open permission.
200462306a36Sopenharmony_ci */
200562306a36Sopenharmony_cistatic inline u32 open_file_to_av(struct file *file)
200662306a36Sopenharmony_ci{
200762306a36Sopenharmony_ci	u32 av = file_to_av(file);
200862306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
200962306a36Sopenharmony_ci
201062306a36Sopenharmony_ci	if (selinux_policycap_openperm() &&
201162306a36Sopenharmony_ci	    inode->i_sb->s_magic != SOCKFS_MAGIC)
201262306a36Sopenharmony_ci		av |= FILE__OPEN;
201362306a36Sopenharmony_ci
201462306a36Sopenharmony_ci	return av;
201562306a36Sopenharmony_ci}
201662306a36Sopenharmony_ci
201762306a36Sopenharmony_ci/* Hook functions begin here. */
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_cistatic int selinux_binder_set_context_mgr(const struct cred *mgr)
202062306a36Sopenharmony_ci{
202162306a36Sopenharmony_ci	return avc_has_perm(current_sid(), cred_sid(mgr), SECCLASS_BINDER,
202262306a36Sopenharmony_ci			    BINDER__SET_CONTEXT_MGR, NULL);
202362306a36Sopenharmony_ci}
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_cistatic int selinux_binder_transaction(const struct cred *from,
202662306a36Sopenharmony_ci				      const struct cred *to)
202762306a36Sopenharmony_ci{
202862306a36Sopenharmony_ci	u32 mysid = current_sid();
202962306a36Sopenharmony_ci	u32 fromsid = cred_sid(from);
203062306a36Sopenharmony_ci	u32 tosid = cred_sid(to);
203162306a36Sopenharmony_ci	int rc;
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	if (mysid != fromsid) {
203462306a36Sopenharmony_ci		rc = avc_has_perm(mysid, fromsid, SECCLASS_BINDER,
203562306a36Sopenharmony_ci				  BINDER__IMPERSONATE, NULL);
203662306a36Sopenharmony_ci		if (rc)
203762306a36Sopenharmony_ci			return rc;
203862306a36Sopenharmony_ci	}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	return avc_has_perm(fromsid, tosid,
204162306a36Sopenharmony_ci			    SECCLASS_BINDER, BINDER__CALL, NULL);
204262306a36Sopenharmony_ci}
204362306a36Sopenharmony_ci
204462306a36Sopenharmony_cistatic int selinux_binder_transfer_binder(const struct cred *from,
204562306a36Sopenharmony_ci					  const struct cred *to)
204662306a36Sopenharmony_ci{
204762306a36Sopenharmony_ci	return avc_has_perm(cred_sid(from), cred_sid(to),
204862306a36Sopenharmony_ci			    SECCLASS_BINDER, BINDER__TRANSFER,
204962306a36Sopenharmony_ci			    NULL);
205062306a36Sopenharmony_ci}
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_cistatic int selinux_binder_transfer_file(const struct cred *from,
205362306a36Sopenharmony_ci					const struct cred *to,
205462306a36Sopenharmony_ci					const struct file *file)
205562306a36Sopenharmony_ci{
205662306a36Sopenharmony_ci	u32 sid = cred_sid(to);
205762306a36Sopenharmony_ci	struct file_security_struct *fsec = selinux_file(file);
205862306a36Sopenharmony_ci	struct dentry *dentry = file->f_path.dentry;
205962306a36Sopenharmony_ci	struct inode_security_struct *isec;
206062306a36Sopenharmony_ci	struct common_audit_data ad;
206162306a36Sopenharmony_ci	int rc;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_PATH;
206462306a36Sopenharmony_ci	ad.u.path = file->f_path;
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	if (sid != fsec->sid) {
206762306a36Sopenharmony_ci		rc = avc_has_perm(sid, fsec->sid,
206862306a36Sopenharmony_ci				  SECCLASS_FD,
206962306a36Sopenharmony_ci				  FD__USE,
207062306a36Sopenharmony_ci				  &ad);
207162306a36Sopenharmony_ci		if (rc)
207262306a36Sopenharmony_ci			return rc;
207362306a36Sopenharmony_ci	}
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL
207662306a36Sopenharmony_ci	rc = bpf_fd_pass(file, sid);
207762306a36Sopenharmony_ci	if (rc)
207862306a36Sopenharmony_ci		return rc;
207962306a36Sopenharmony_ci#endif
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci	if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
208262306a36Sopenharmony_ci		return 0;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	isec = backing_inode_security(dentry);
208562306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, isec->sclass, file_to_av(file),
208662306a36Sopenharmony_ci			    &ad);
208762306a36Sopenharmony_ci}
208862306a36Sopenharmony_ci
208962306a36Sopenharmony_cistatic int selinux_ptrace_access_check(struct task_struct *child,
209062306a36Sopenharmony_ci				       unsigned int mode)
209162306a36Sopenharmony_ci{
209262306a36Sopenharmony_ci	u32 sid = current_sid();
209362306a36Sopenharmony_ci	u32 csid = task_sid_obj(child);
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	if (mode & PTRACE_MODE_READ)
209662306a36Sopenharmony_ci		return avc_has_perm(sid, csid, SECCLASS_FILE, FILE__READ,
209762306a36Sopenharmony_ci				NULL);
209862306a36Sopenharmony_ci
209962306a36Sopenharmony_ci	return avc_has_perm(sid, csid, SECCLASS_PROCESS, PROCESS__PTRACE,
210062306a36Sopenharmony_ci			NULL);
210162306a36Sopenharmony_ci}
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_cistatic int selinux_ptrace_traceme(struct task_struct *parent)
210462306a36Sopenharmony_ci{
210562306a36Sopenharmony_ci	return avc_has_perm(task_sid_obj(parent), task_sid_obj(current),
210662306a36Sopenharmony_ci			    SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_cistatic int selinux_capget(const struct task_struct *target, kernel_cap_t *effective,
211062306a36Sopenharmony_ci			  kernel_cap_t *inheritable, kernel_cap_t *permitted)
211162306a36Sopenharmony_ci{
211262306a36Sopenharmony_ci	return avc_has_perm(current_sid(), task_sid_obj(target),
211362306a36Sopenharmony_ci			SECCLASS_PROCESS, PROCESS__GETCAP, NULL);
211462306a36Sopenharmony_ci}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_cistatic int selinux_capset(struct cred *new, const struct cred *old,
211762306a36Sopenharmony_ci			  const kernel_cap_t *effective,
211862306a36Sopenharmony_ci			  const kernel_cap_t *inheritable,
211962306a36Sopenharmony_ci			  const kernel_cap_t *permitted)
212062306a36Sopenharmony_ci{
212162306a36Sopenharmony_ci	return avc_has_perm(cred_sid(old), cred_sid(new), SECCLASS_PROCESS,
212262306a36Sopenharmony_ci			    PROCESS__SETCAP, NULL);
212362306a36Sopenharmony_ci}
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci/*
212662306a36Sopenharmony_ci * (This comment used to live with the selinux_task_setuid hook,
212762306a36Sopenharmony_ci * which was removed).
212862306a36Sopenharmony_ci *
212962306a36Sopenharmony_ci * Since setuid only affects the current process, and since the SELinux
213062306a36Sopenharmony_ci * controls are not based on the Linux identity attributes, SELinux does not
213162306a36Sopenharmony_ci * need to control this operation.  However, SELinux does control the use of
213262306a36Sopenharmony_ci * the CAP_SETUID and CAP_SETGID capabilities using the capable hook.
213362306a36Sopenharmony_ci */
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_cistatic int selinux_capable(const struct cred *cred, struct user_namespace *ns,
213662306a36Sopenharmony_ci			   int cap, unsigned int opts)
213762306a36Sopenharmony_ci{
213862306a36Sopenharmony_ci	return cred_has_capability(cred, cap, opts, ns == &init_user_ns);
213962306a36Sopenharmony_ci}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_cistatic int selinux_quotactl(int cmds, int type, int id, struct super_block *sb)
214262306a36Sopenharmony_ci{
214362306a36Sopenharmony_ci	const struct cred *cred = current_cred();
214462306a36Sopenharmony_ci	int rc = 0;
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	if (!sb)
214762306a36Sopenharmony_ci		return 0;
214862306a36Sopenharmony_ci
214962306a36Sopenharmony_ci	switch (cmds) {
215062306a36Sopenharmony_ci	case Q_SYNC:
215162306a36Sopenharmony_ci	case Q_QUOTAON:
215262306a36Sopenharmony_ci	case Q_QUOTAOFF:
215362306a36Sopenharmony_ci	case Q_SETINFO:
215462306a36Sopenharmony_ci	case Q_SETQUOTA:
215562306a36Sopenharmony_ci	case Q_XQUOTAOFF:
215662306a36Sopenharmony_ci	case Q_XQUOTAON:
215762306a36Sopenharmony_ci	case Q_XSETQLIM:
215862306a36Sopenharmony_ci		rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAMOD, NULL);
215962306a36Sopenharmony_ci		break;
216062306a36Sopenharmony_ci	case Q_GETFMT:
216162306a36Sopenharmony_ci	case Q_GETINFO:
216262306a36Sopenharmony_ci	case Q_GETQUOTA:
216362306a36Sopenharmony_ci	case Q_XGETQUOTA:
216462306a36Sopenharmony_ci	case Q_XGETQSTAT:
216562306a36Sopenharmony_ci	case Q_XGETQSTATV:
216662306a36Sopenharmony_ci	case Q_XGETNEXTQUOTA:
216762306a36Sopenharmony_ci		rc = superblock_has_perm(cred, sb, FILESYSTEM__QUOTAGET, NULL);
216862306a36Sopenharmony_ci		break;
216962306a36Sopenharmony_ci	default:
217062306a36Sopenharmony_ci		rc = 0;  /* let the kernel handle invalid cmds */
217162306a36Sopenharmony_ci		break;
217262306a36Sopenharmony_ci	}
217362306a36Sopenharmony_ci	return rc;
217462306a36Sopenharmony_ci}
217562306a36Sopenharmony_ci
217662306a36Sopenharmony_cistatic int selinux_quota_on(struct dentry *dentry)
217762306a36Sopenharmony_ci{
217862306a36Sopenharmony_ci	const struct cred *cred = current_cred();
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	return dentry_has_perm(cred, dentry, FILE__QUOTAON);
218162306a36Sopenharmony_ci}
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_cistatic int selinux_syslog(int type)
218462306a36Sopenharmony_ci{
218562306a36Sopenharmony_ci	switch (type) {
218662306a36Sopenharmony_ci	case SYSLOG_ACTION_READ_ALL:	/* Read last kernel messages */
218762306a36Sopenharmony_ci	case SYSLOG_ACTION_SIZE_BUFFER:	/* Return size of the log buffer */
218862306a36Sopenharmony_ci		return avc_has_perm(current_sid(), SECINITSID_KERNEL,
218962306a36Sopenharmony_ci				    SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, NULL);
219062306a36Sopenharmony_ci	case SYSLOG_ACTION_CONSOLE_OFF:	/* Disable logging to console */
219162306a36Sopenharmony_ci	case SYSLOG_ACTION_CONSOLE_ON:	/* Enable logging to console */
219262306a36Sopenharmony_ci	/* Set level of messages printed to console */
219362306a36Sopenharmony_ci	case SYSLOG_ACTION_CONSOLE_LEVEL:
219462306a36Sopenharmony_ci		return avc_has_perm(current_sid(), SECINITSID_KERNEL,
219562306a36Sopenharmony_ci				    SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE,
219662306a36Sopenharmony_ci				    NULL);
219762306a36Sopenharmony_ci	}
219862306a36Sopenharmony_ci	/* All other syslog types */
219962306a36Sopenharmony_ci	return avc_has_perm(current_sid(), SECINITSID_KERNEL,
220062306a36Sopenharmony_ci			    SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, NULL);
220162306a36Sopenharmony_ci}
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci/*
220462306a36Sopenharmony_ci * Check that a process has enough memory to allocate a new virtual
220562306a36Sopenharmony_ci * mapping. 0 means there is enough memory for the allocation to
220662306a36Sopenharmony_ci * succeed and -ENOMEM implies there is not.
220762306a36Sopenharmony_ci *
220862306a36Sopenharmony_ci * Do not audit the selinux permission check, as this is applied to all
220962306a36Sopenharmony_ci * processes that allocate mappings.
221062306a36Sopenharmony_ci */
221162306a36Sopenharmony_cistatic int selinux_vm_enough_memory(struct mm_struct *mm, long pages)
221262306a36Sopenharmony_ci{
221362306a36Sopenharmony_ci	int rc, cap_sys_admin = 0;
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci	rc = cred_has_capability(current_cred(), CAP_SYS_ADMIN,
221662306a36Sopenharmony_ci				 CAP_OPT_NOAUDIT, true);
221762306a36Sopenharmony_ci	if (rc == 0)
221862306a36Sopenharmony_ci		cap_sys_admin = 1;
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci	return cap_sys_admin;
222162306a36Sopenharmony_ci}
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci/* binprm security operations */
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_cistatic u32 ptrace_parent_sid(void)
222662306a36Sopenharmony_ci{
222762306a36Sopenharmony_ci	u32 sid = 0;
222862306a36Sopenharmony_ci	struct task_struct *tracer;
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	rcu_read_lock();
223162306a36Sopenharmony_ci	tracer = ptrace_parent(current);
223262306a36Sopenharmony_ci	if (tracer)
223362306a36Sopenharmony_ci		sid = task_sid_obj(tracer);
223462306a36Sopenharmony_ci	rcu_read_unlock();
223562306a36Sopenharmony_ci
223662306a36Sopenharmony_ci	return sid;
223762306a36Sopenharmony_ci}
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_cistatic int check_nnp_nosuid(const struct linux_binprm *bprm,
224062306a36Sopenharmony_ci			    const struct task_security_struct *old_tsec,
224162306a36Sopenharmony_ci			    const struct task_security_struct *new_tsec)
224262306a36Sopenharmony_ci{
224362306a36Sopenharmony_ci	int nnp = (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS);
224462306a36Sopenharmony_ci	int nosuid = !mnt_may_suid(bprm->file->f_path.mnt);
224562306a36Sopenharmony_ci	int rc;
224662306a36Sopenharmony_ci	u32 av;
224762306a36Sopenharmony_ci
224862306a36Sopenharmony_ci	if (!nnp && !nosuid)
224962306a36Sopenharmony_ci		return 0; /* neither NNP nor nosuid */
225062306a36Sopenharmony_ci
225162306a36Sopenharmony_ci	if (new_tsec->sid == old_tsec->sid)
225262306a36Sopenharmony_ci		return 0; /* No change in credentials */
225362306a36Sopenharmony_ci
225462306a36Sopenharmony_ci	/*
225562306a36Sopenharmony_ci	 * If the policy enables the nnp_nosuid_transition policy capability,
225662306a36Sopenharmony_ci	 * then we permit transitions under NNP or nosuid if the
225762306a36Sopenharmony_ci	 * policy allows the corresponding permission between
225862306a36Sopenharmony_ci	 * the old and new contexts.
225962306a36Sopenharmony_ci	 */
226062306a36Sopenharmony_ci	if (selinux_policycap_nnp_nosuid_transition()) {
226162306a36Sopenharmony_ci		av = 0;
226262306a36Sopenharmony_ci		if (nnp)
226362306a36Sopenharmony_ci			av |= PROCESS2__NNP_TRANSITION;
226462306a36Sopenharmony_ci		if (nosuid)
226562306a36Sopenharmony_ci			av |= PROCESS2__NOSUID_TRANSITION;
226662306a36Sopenharmony_ci		rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
226762306a36Sopenharmony_ci				  SECCLASS_PROCESS2, av, NULL);
226862306a36Sopenharmony_ci		if (!rc)
226962306a36Sopenharmony_ci			return 0;
227062306a36Sopenharmony_ci	}
227162306a36Sopenharmony_ci
227262306a36Sopenharmony_ci	/*
227362306a36Sopenharmony_ci	 * We also permit NNP or nosuid transitions to bounded SIDs,
227462306a36Sopenharmony_ci	 * i.e. SIDs that are guaranteed to only be allowed a subset
227562306a36Sopenharmony_ci	 * of the permissions of the current SID.
227662306a36Sopenharmony_ci	 */
227762306a36Sopenharmony_ci	rc = security_bounded_transition(old_tsec->sid,
227862306a36Sopenharmony_ci					 new_tsec->sid);
227962306a36Sopenharmony_ci	if (!rc)
228062306a36Sopenharmony_ci		return 0;
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_ci	/*
228362306a36Sopenharmony_ci	 * On failure, preserve the errno values for NNP vs nosuid.
228462306a36Sopenharmony_ci	 * NNP:  Operation not permitted for caller.
228562306a36Sopenharmony_ci	 * nosuid:  Permission denied to file.
228662306a36Sopenharmony_ci	 */
228762306a36Sopenharmony_ci	if (nnp)
228862306a36Sopenharmony_ci		return -EPERM;
228962306a36Sopenharmony_ci	return -EACCES;
229062306a36Sopenharmony_ci}
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_cistatic int selinux_bprm_creds_for_exec(struct linux_binprm *bprm)
229362306a36Sopenharmony_ci{
229462306a36Sopenharmony_ci	const struct task_security_struct *old_tsec;
229562306a36Sopenharmony_ci	struct task_security_struct *new_tsec;
229662306a36Sopenharmony_ci	struct inode_security_struct *isec;
229762306a36Sopenharmony_ci	struct common_audit_data ad;
229862306a36Sopenharmony_ci	struct inode *inode = file_inode(bprm->file);
229962306a36Sopenharmony_ci	int rc;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci	/* SELinux context only depends on initial program or script and not
230262306a36Sopenharmony_ci	 * the script interpreter */
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	old_tsec = selinux_cred(current_cred());
230562306a36Sopenharmony_ci	new_tsec = selinux_cred(bprm->cred);
230662306a36Sopenharmony_ci	isec = inode_security(inode);
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci	/* Default to the current task SID. */
230962306a36Sopenharmony_ci	new_tsec->sid = old_tsec->sid;
231062306a36Sopenharmony_ci	new_tsec->osid = old_tsec->sid;
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	/* Reset fs, key, and sock SIDs on execve. */
231362306a36Sopenharmony_ci	new_tsec->create_sid = 0;
231462306a36Sopenharmony_ci	new_tsec->keycreate_sid = 0;
231562306a36Sopenharmony_ci	new_tsec->sockcreate_sid = 0;
231662306a36Sopenharmony_ci
231762306a36Sopenharmony_ci	if (old_tsec->exec_sid) {
231862306a36Sopenharmony_ci		new_tsec->sid = old_tsec->exec_sid;
231962306a36Sopenharmony_ci		/* Reset exec SID on execve. */
232062306a36Sopenharmony_ci		new_tsec->exec_sid = 0;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci		/* Fail on NNP or nosuid if not an allowed transition. */
232362306a36Sopenharmony_ci		rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
232462306a36Sopenharmony_ci		if (rc)
232562306a36Sopenharmony_ci			return rc;
232662306a36Sopenharmony_ci	} else {
232762306a36Sopenharmony_ci		/* Check for a default transition on this program. */
232862306a36Sopenharmony_ci		rc = security_transition_sid(old_tsec->sid,
232962306a36Sopenharmony_ci					     isec->sid, SECCLASS_PROCESS, NULL,
233062306a36Sopenharmony_ci					     &new_tsec->sid);
233162306a36Sopenharmony_ci		if (rc)
233262306a36Sopenharmony_ci			return rc;
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci		/*
233562306a36Sopenharmony_ci		 * Fallback to old SID on NNP or nosuid if not an allowed
233662306a36Sopenharmony_ci		 * transition.
233762306a36Sopenharmony_ci		 */
233862306a36Sopenharmony_ci		rc = check_nnp_nosuid(bprm, old_tsec, new_tsec);
233962306a36Sopenharmony_ci		if (rc)
234062306a36Sopenharmony_ci			new_tsec->sid = old_tsec->sid;
234162306a36Sopenharmony_ci	}
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_FILE;
234462306a36Sopenharmony_ci	ad.u.file = bprm->file;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	if (new_tsec->sid == old_tsec->sid) {
234762306a36Sopenharmony_ci		rc = avc_has_perm(old_tsec->sid, isec->sid,
234862306a36Sopenharmony_ci				  SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, &ad);
234962306a36Sopenharmony_ci		if (rc)
235062306a36Sopenharmony_ci			return rc;
235162306a36Sopenharmony_ci	} else {
235262306a36Sopenharmony_ci		/* Check permissions for the transition. */
235362306a36Sopenharmony_ci		rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
235462306a36Sopenharmony_ci				  SECCLASS_PROCESS, PROCESS__TRANSITION, &ad);
235562306a36Sopenharmony_ci		if (rc)
235662306a36Sopenharmony_ci			return rc;
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci		rc = avc_has_perm(new_tsec->sid, isec->sid,
235962306a36Sopenharmony_ci				  SECCLASS_FILE, FILE__ENTRYPOINT, &ad);
236062306a36Sopenharmony_ci		if (rc)
236162306a36Sopenharmony_ci			return rc;
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci		/* Check for shared state */
236462306a36Sopenharmony_ci		if (bprm->unsafe & LSM_UNSAFE_SHARE) {
236562306a36Sopenharmony_ci			rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
236662306a36Sopenharmony_ci					  SECCLASS_PROCESS, PROCESS__SHARE,
236762306a36Sopenharmony_ci					  NULL);
236862306a36Sopenharmony_ci			if (rc)
236962306a36Sopenharmony_ci				return -EPERM;
237062306a36Sopenharmony_ci		}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci		/* Make sure that anyone attempting to ptrace over a task that
237362306a36Sopenharmony_ci		 * changes its SID has the appropriate permit */
237462306a36Sopenharmony_ci		if (bprm->unsafe & LSM_UNSAFE_PTRACE) {
237562306a36Sopenharmony_ci			u32 ptsid = ptrace_parent_sid();
237662306a36Sopenharmony_ci			if (ptsid != 0) {
237762306a36Sopenharmony_ci				rc = avc_has_perm(ptsid, new_tsec->sid,
237862306a36Sopenharmony_ci						  SECCLASS_PROCESS,
237962306a36Sopenharmony_ci						  PROCESS__PTRACE, NULL);
238062306a36Sopenharmony_ci				if (rc)
238162306a36Sopenharmony_ci					return -EPERM;
238262306a36Sopenharmony_ci			}
238362306a36Sopenharmony_ci		}
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_ci		/* Clear any possibly unsafe personality bits on exec: */
238662306a36Sopenharmony_ci		bprm->per_clear |= PER_CLEAR_ON_SETID;
238762306a36Sopenharmony_ci
238862306a36Sopenharmony_ci		/* Enable secure mode for SIDs transitions unless
238962306a36Sopenharmony_ci		   the noatsecure permission is granted between
239062306a36Sopenharmony_ci		   the two SIDs, i.e. ahp returns 0. */
239162306a36Sopenharmony_ci		rc = avc_has_perm(old_tsec->sid, new_tsec->sid,
239262306a36Sopenharmony_ci				  SECCLASS_PROCESS, PROCESS__NOATSECURE,
239362306a36Sopenharmony_ci				  NULL);
239462306a36Sopenharmony_ci		bprm->secureexec |= !!rc;
239562306a36Sopenharmony_ci	}
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci	return 0;
239862306a36Sopenharmony_ci}
239962306a36Sopenharmony_ci
240062306a36Sopenharmony_cistatic int match_file(const void *p, struct file *file, unsigned fd)
240162306a36Sopenharmony_ci{
240262306a36Sopenharmony_ci	return file_has_perm(p, file, file_to_av(file)) ? fd + 1 : 0;
240362306a36Sopenharmony_ci}
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci/* Derived from fs/exec.c:flush_old_files. */
240662306a36Sopenharmony_cistatic inline void flush_unauthorized_files(const struct cred *cred,
240762306a36Sopenharmony_ci					    struct files_struct *files)
240862306a36Sopenharmony_ci{
240962306a36Sopenharmony_ci	struct file *file, *devnull = NULL;
241062306a36Sopenharmony_ci	struct tty_struct *tty;
241162306a36Sopenharmony_ci	int drop_tty = 0;
241262306a36Sopenharmony_ci	unsigned n;
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	tty = get_current_tty();
241562306a36Sopenharmony_ci	if (tty) {
241662306a36Sopenharmony_ci		spin_lock(&tty->files_lock);
241762306a36Sopenharmony_ci		if (!list_empty(&tty->tty_files)) {
241862306a36Sopenharmony_ci			struct tty_file_private *file_priv;
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci			/* Revalidate access to controlling tty.
242162306a36Sopenharmony_ci			   Use file_path_has_perm on the tty path directly
242262306a36Sopenharmony_ci			   rather than using file_has_perm, as this particular
242362306a36Sopenharmony_ci			   open file may belong to another process and we are
242462306a36Sopenharmony_ci			   only interested in the inode-based check here. */
242562306a36Sopenharmony_ci			file_priv = list_first_entry(&tty->tty_files,
242662306a36Sopenharmony_ci						struct tty_file_private, list);
242762306a36Sopenharmony_ci			file = file_priv->file;
242862306a36Sopenharmony_ci			if (file_path_has_perm(cred, file, FILE__READ | FILE__WRITE))
242962306a36Sopenharmony_ci				drop_tty = 1;
243062306a36Sopenharmony_ci		}
243162306a36Sopenharmony_ci		spin_unlock(&tty->files_lock);
243262306a36Sopenharmony_ci		tty_kref_put(tty);
243362306a36Sopenharmony_ci	}
243462306a36Sopenharmony_ci	/* Reset controlling tty. */
243562306a36Sopenharmony_ci	if (drop_tty)
243662306a36Sopenharmony_ci		no_tty();
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	/* Revalidate access to inherited open files. */
243962306a36Sopenharmony_ci	n = iterate_fd(files, 0, match_file, cred);
244062306a36Sopenharmony_ci	if (!n) /* none found? */
244162306a36Sopenharmony_ci		return;
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	devnull = dentry_open(&selinux_null, O_RDWR, cred);
244462306a36Sopenharmony_ci	if (IS_ERR(devnull))
244562306a36Sopenharmony_ci		devnull = NULL;
244662306a36Sopenharmony_ci	/* replace all the matching ones with this */
244762306a36Sopenharmony_ci	do {
244862306a36Sopenharmony_ci		replace_fd(n - 1, devnull, 0);
244962306a36Sopenharmony_ci	} while ((n = iterate_fd(files, n, match_file, cred)) != 0);
245062306a36Sopenharmony_ci	if (devnull)
245162306a36Sopenharmony_ci		fput(devnull);
245262306a36Sopenharmony_ci}
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci/*
245562306a36Sopenharmony_ci * Prepare a process for imminent new credential changes due to exec
245662306a36Sopenharmony_ci */
245762306a36Sopenharmony_cistatic void selinux_bprm_committing_creds(struct linux_binprm *bprm)
245862306a36Sopenharmony_ci{
245962306a36Sopenharmony_ci	struct task_security_struct *new_tsec;
246062306a36Sopenharmony_ci	struct rlimit *rlim, *initrlim;
246162306a36Sopenharmony_ci	int rc, i;
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ci	new_tsec = selinux_cred(bprm->cred);
246462306a36Sopenharmony_ci	if (new_tsec->sid == new_tsec->osid)
246562306a36Sopenharmony_ci		return;
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	/* Close files for which the new task SID is not authorized. */
246862306a36Sopenharmony_ci	flush_unauthorized_files(bprm->cred, current->files);
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	/* Always clear parent death signal on SID transitions. */
247162306a36Sopenharmony_ci	current->pdeath_signal = 0;
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	/* Check whether the new SID can inherit resource limits from the old
247462306a36Sopenharmony_ci	 * SID.  If not, reset all soft limits to the lower of the current
247562306a36Sopenharmony_ci	 * task's hard limit and the init task's soft limit.
247662306a36Sopenharmony_ci	 *
247762306a36Sopenharmony_ci	 * Note that the setting of hard limits (even to lower them) can be
247862306a36Sopenharmony_ci	 * controlled by the setrlimit check.  The inclusion of the init task's
247962306a36Sopenharmony_ci	 * soft limit into the computation is to avoid resetting soft limits
248062306a36Sopenharmony_ci	 * higher than the default soft limit for cases where the default is
248162306a36Sopenharmony_ci	 * lower than the hard limit, e.g. RLIMIT_CORE or RLIMIT_STACK.
248262306a36Sopenharmony_ci	 */
248362306a36Sopenharmony_ci	rc = avc_has_perm(new_tsec->osid, new_tsec->sid, SECCLASS_PROCESS,
248462306a36Sopenharmony_ci			  PROCESS__RLIMITINH, NULL);
248562306a36Sopenharmony_ci	if (rc) {
248662306a36Sopenharmony_ci		/* protect against do_prlimit() */
248762306a36Sopenharmony_ci		task_lock(current);
248862306a36Sopenharmony_ci		for (i = 0; i < RLIM_NLIMITS; i++) {
248962306a36Sopenharmony_ci			rlim = current->signal->rlim + i;
249062306a36Sopenharmony_ci			initrlim = init_task.signal->rlim + i;
249162306a36Sopenharmony_ci			rlim->rlim_cur = min(rlim->rlim_max, initrlim->rlim_cur);
249262306a36Sopenharmony_ci		}
249362306a36Sopenharmony_ci		task_unlock(current);
249462306a36Sopenharmony_ci		if (IS_ENABLED(CONFIG_POSIX_TIMERS))
249562306a36Sopenharmony_ci			update_rlimit_cpu(current, rlimit(RLIMIT_CPU));
249662306a36Sopenharmony_ci	}
249762306a36Sopenharmony_ci}
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci/*
250062306a36Sopenharmony_ci * Clean up the process immediately after the installation of new credentials
250162306a36Sopenharmony_ci * due to exec
250262306a36Sopenharmony_ci */
250362306a36Sopenharmony_cistatic void selinux_bprm_committed_creds(struct linux_binprm *bprm)
250462306a36Sopenharmony_ci{
250562306a36Sopenharmony_ci	const struct task_security_struct *tsec = selinux_cred(current_cred());
250662306a36Sopenharmony_ci	u32 osid, sid;
250762306a36Sopenharmony_ci	int rc;
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	osid = tsec->osid;
251062306a36Sopenharmony_ci	sid = tsec->sid;
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	if (sid == osid)
251362306a36Sopenharmony_ci		return;
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci	/* Check whether the new SID can inherit signal state from the old SID.
251662306a36Sopenharmony_ci	 * If not, clear itimers to avoid subsequent signal generation and
251762306a36Sopenharmony_ci	 * flush and unblock signals.
251862306a36Sopenharmony_ci	 *
251962306a36Sopenharmony_ci	 * This must occur _after_ the task SID has been updated so that any
252062306a36Sopenharmony_ci	 * kill done after the flush will be checked against the new SID.
252162306a36Sopenharmony_ci	 */
252262306a36Sopenharmony_ci	rc = avc_has_perm(osid, sid, SECCLASS_PROCESS, PROCESS__SIGINH, NULL);
252362306a36Sopenharmony_ci	if (rc) {
252462306a36Sopenharmony_ci		clear_itimer();
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci		spin_lock_irq(&unrcu_pointer(current->sighand)->siglock);
252762306a36Sopenharmony_ci		if (!fatal_signal_pending(current)) {
252862306a36Sopenharmony_ci			flush_sigqueue(&current->pending);
252962306a36Sopenharmony_ci			flush_sigqueue(&current->signal->shared_pending);
253062306a36Sopenharmony_ci			flush_signal_handlers(current, 1);
253162306a36Sopenharmony_ci			sigemptyset(&current->blocked);
253262306a36Sopenharmony_ci			recalc_sigpending();
253362306a36Sopenharmony_ci		}
253462306a36Sopenharmony_ci		spin_unlock_irq(&unrcu_pointer(current->sighand)->siglock);
253562306a36Sopenharmony_ci	}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_ci	/* Wake up the parent if it is waiting so that it can recheck
253862306a36Sopenharmony_ci	 * wait permission to the new task SID. */
253962306a36Sopenharmony_ci	read_lock(&tasklist_lock);
254062306a36Sopenharmony_ci	__wake_up_parent(current, unrcu_pointer(current->real_parent));
254162306a36Sopenharmony_ci	read_unlock(&tasklist_lock);
254262306a36Sopenharmony_ci}
254362306a36Sopenharmony_ci
254462306a36Sopenharmony_ci/* superblock security operations */
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_cistatic int selinux_sb_alloc_security(struct super_block *sb)
254762306a36Sopenharmony_ci{
254862306a36Sopenharmony_ci	struct superblock_security_struct *sbsec = selinux_superblock(sb);
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_ci	mutex_init(&sbsec->lock);
255162306a36Sopenharmony_ci	INIT_LIST_HEAD(&sbsec->isec_head);
255262306a36Sopenharmony_ci	spin_lock_init(&sbsec->isec_lock);
255362306a36Sopenharmony_ci	sbsec->sid = SECINITSID_UNLABELED;
255462306a36Sopenharmony_ci	sbsec->def_sid = SECINITSID_FILE;
255562306a36Sopenharmony_ci	sbsec->mntpoint_sid = SECINITSID_UNLABELED;
255662306a36Sopenharmony_ci
255762306a36Sopenharmony_ci	return 0;
255862306a36Sopenharmony_ci}
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_cistatic inline int opt_len(const char *s)
256162306a36Sopenharmony_ci{
256262306a36Sopenharmony_ci	bool open_quote = false;
256362306a36Sopenharmony_ci	int len;
256462306a36Sopenharmony_ci	char c;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	for (len = 0; (c = s[len]) != '\0'; len++) {
256762306a36Sopenharmony_ci		if (c == '"')
256862306a36Sopenharmony_ci			open_quote = !open_quote;
256962306a36Sopenharmony_ci		if (c == ',' && !open_quote)
257062306a36Sopenharmony_ci			break;
257162306a36Sopenharmony_ci	}
257262306a36Sopenharmony_ci	return len;
257362306a36Sopenharmony_ci}
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_cistatic int selinux_sb_eat_lsm_opts(char *options, void **mnt_opts)
257662306a36Sopenharmony_ci{
257762306a36Sopenharmony_ci	char *from = options;
257862306a36Sopenharmony_ci	char *to = options;
257962306a36Sopenharmony_ci	bool first = true;
258062306a36Sopenharmony_ci	int rc;
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	while (1) {
258362306a36Sopenharmony_ci		int len = opt_len(from);
258462306a36Sopenharmony_ci		int token;
258562306a36Sopenharmony_ci		char *arg = NULL;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci		token = match_opt_prefix(from, len, &arg);
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci		if (token != Opt_error) {
259062306a36Sopenharmony_ci			char *p, *q;
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci			/* strip quotes */
259362306a36Sopenharmony_ci			if (arg) {
259462306a36Sopenharmony_ci				for (p = q = arg; p < from + len; p++) {
259562306a36Sopenharmony_ci					char c = *p;
259662306a36Sopenharmony_ci					if (c != '"')
259762306a36Sopenharmony_ci						*q++ = c;
259862306a36Sopenharmony_ci				}
259962306a36Sopenharmony_ci				arg = kmemdup_nul(arg, q - arg, GFP_KERNEL);
260062306a36Sopenharmony_ci				if (!arg) {
260162306a36Sopenharmony_ci					rc = -ENOMEM;
260262306a36Sopenharmony_ci					goto free_opt;
260362306a36Sopenharmony_ci				}
260462306a36Sopenharmony_ci			}
260562306a36Sopenharmony_ci			rc = selinux_add_opt(token, arg, mnt_opts);
260662306a36Sopenharmony_ci			kfree(arg);
260762306a36Sopenharmony_ci			arg = NULL;
260862306a36Sopenharmony_ci			if (unlikely(rc)) {
260962306a36Sopenharmony_ci				goto free_opt;
261062306a36Sopenharmony_ci			}
261162306a36Sopenharmony_ci		} else {
261262306a36Sopenharmony_ci			if (!first) {	// copy with preceding comma
261362306a36Sopenharmony_ci				from--;
261462306a36Sopenharmony_ci				len++;
261562306a36Sopenharmony_ci			}
261662306a36Sopenharmony_ci			if (to != from)
261762306a36Sopenharmony_ci				memmove(to, from, len);
261862306a36Sopenharmony_ci			to += len;
261962306a36Sopenharmony_ci			first = false;
262062306a36Sopenharmony_ci		}
262162306a36Sopenharmony_ci		if (!from[len])
262262306a36Sopenharmony_ci			break;
262362306a36Sopenharmony_ci		from += len + 1;
262462306a36Sopenharmony_ci	}
262562306a36Sopenharmony_ci	*to = '\0';
262662306a36Sopenharmony_ci	return 0;
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_cifree_opt:
262962306a36Sopenharmony_ci	if (*mnt_opts) {
263062306a36Sopenharmony_ci		selinux_free_mnt_opts(*mnt_opts);
263162306a36Sopenharmony_ci		*mnt_opts = NULL;
263262306a36Sopenharmony_ci	}
263362306a36Sopenharmony_ci	return rc;
263462306a36Sopenharmony_ci}
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_cistatic int selinux_sb_mnt_opts_compat(struct super_block *sb, void *mnt_opts)
263762306a36Sopenharmony_ci{
263862306a36Sopenharmony_ci	struct selinux_mnt_opts *opts = mnt_opts;
263962306a36Sopenharmony_ci	struct superblock_security_struct *sbsec = selinux_superblock(sb);
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_ci	/*
264262306a36Sopenharmony_ci	 * Superblock not initialized (i.e. no options) - reject if any
264362306a36Sopenharmony_ci	 * options specified, otherwise accept.
264462306a36Sopenharmony_ci	 */
264562306a36Sopenharmony_ci	if (!(sbsec->flags & SE_SBINITIALIZED))
264662306a36Sopenharmony_ci		return opts ? 1 : 0;
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	/*
264962306a36Sopenharmony_ci	 * Superblock initialized and no options specified - reject if
265062306a36Sopenharmony_ci	 * superblock has any options set, otherwise accept.
265162306a36Sopenharmony_ci	 */
265262306a36Sopenharmony_ci	if (!opts)
265362306a36Sopenharmony_ci		return (sbsec->flags & SE_MNTMASK) ? 1 : 0;
265462306a36Sopenharmony_ci
265562306a36Sopenharmony_ci	if (opts->fscontext_sid) {
265662306a36Sopenharmony_ci		if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
265762306a36Sopenharmony_ci			       opts->fscontext_sid))
265862306a36Sopenharmony_ci			return 1;
265962306a36Sopenharmony_ci	}
266062306a36Sopenharmony_ci	if (opts->context_sid) {
266162306a36Sopenharmony_ci		if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
266262306a36Sopenharmony_ci			       opts->context_sid))
266362306a36Sopenharmony_ci			return 1;
266462306a36Sopenharmony_ci	}
266562306a36Sopenharmony_ci	if (opts->rootcontext_sid) {
266662306a36Sopenharmony_ci		struct inode_security_struct *root_isec;
266762306a36Sopenharmony_ci
266862306a36Sopenharmony_ci		root_isec = backing_inode_security(sb->s_root);
266962306a36Sopenharmony_ci		if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
267062306a36Sopenharmony_ci			       opts->rootcontext_sid))
267162306a36Sopenharmony_ci			return 1;
267262306a36Sopenharmony_ci	}
267362306a36Sopenharmony_ci	if (opts->defcontext_sid) {
267462306a36Sopenharmony_ci		if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
267562306a36Sopenharmony_ci			       opts->defcontext_sid))
267662306a36Sopenharmony_ci			return 1;
267762306a36Sopenharmony_ci	}
267862306a36Sopenharmony_ci	return 0;
267962306a36Sopenharmony_ci}
268062306a36Sopenharmony_ci
268162306a36Sopenharmony_cistatic int selinux_sb_remount(struct super_block *sb, void *mnt_opts)
268262306a36Sopenharmony_ci{
268362306a36Sopenharmony_ci	struct selinux_mnt_opts *opts = mnt_opts;
268462306a36Sopenharmony_ci	struct superblock_security_struct *sbsec = selinux_superblock(sb);
268562306a36Sopenharmony_ci
268662306a36Sopenharmony_ci	if (!(sbsec->flags & SE_SBINITIALIZED))
268762306a36Sopenharmony_ci		return 0;
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_ci	if (!opts)
269062306a36Sopenharmony_ci		return 0;
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	if (opts->fscontext_sid) {
269362306a36Sopenharmony_ci		if (bad_option(sbsec, FSCONTEXT_MNT, sbsec->sid,
269462306a36Sopenharmony_ci			       opts->fscontext_sid))
269562306a36Sopenharmony_ci			goto out_bad_option;
269662306a36Sopenharmony_ci	}
269762306a36Sopenharmony_ci	if (opts->context_sid) {
269862306a36Sopenharmony_ci		if (bad_option(sbsec, CONTEXT_MNT, sbsec->mntpoint_sid,
269962306a36Sopenharmony_ci			       opts->context_sid))
270062306a36Sopenharmony_ci			goto out_bad_option;
270162306a36Sopenharmony_ci	}
270262306a36Sopenharmony_ci	if (opts->rootcontext_sid) {
270362306a36Sopenharmony_ci		struct inode_security_struct *root_isec;
270462306a36Sopenharmony_ci		root_isec = backing_inode_security(sb->s_root);
270562306a36Sopenharmony_ci		if (bad_option(sbsec, ROOTCONTEXT_MNT, root_isec->sid,
270662306a36Sopenharmony_ci			       opts->rootcontext_sid))
270762306a36Sopenharmony_ci			goto out_bad_option;
270862306a36Sopenharmony_ci	}
270962306a36Sopenharmony_ci	if (opts->defcontext_sid) {
271062306a36Sopenharmony_ci		if (bad_option(sbsec, DEFCONTEXT_MNT, sbsec->def_sid,
271162306a36Sopenharmony_ci			       opts->defcontext_sid))
271262306a36Sopenharmony_ci			goto out_bad_option;
271362306a36Sopenharmony_ci	}
271462306a36Sopenharmony_ci	return 0;
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ciout_bad_option:
271762306a36Sopenharmony_ci	pr_warn("SELinux: unable to change security options "
271862306a36Sopenharmony_ci	       "during remount (dev %s, type=%s)\n", sb->s_id,
271962306a36Sopenharmony_ci	       sb->s_type->name);
272062306a36Sopenharmony_ci	return -EINVAL;
272162306a36Sopenharmony_ci}
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_cistatic int selinux_sb_kern_mount(struct super_block *sb)
272462306a36Sopenharmony_ci{
272562306a36Sopenharmony_ci	const struct cred *cred = current_cred();
272662306a36Sopenharmony_ci	struct common_audit_data ad;
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_DENTRY;
272962306a36Sopenharmony_ci	ad.u.dentry = sb->s_root;
273062306a36Sopenharmony_ci	return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad);
273162306a36Sopenharmony_ci}
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_cistatic int selinux_sb_statfs(struct dentry *dentry)
273462306a36Sopenharmony_ci{
273562306a36Sopenharmony_ci	const struct cred *cred = current_cred();
273662306a36Sopenharmony_ci	struct common_audit_data ad;
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_DENTRY;
273962306a36Sopenharmony_ci	ad.u.dentry = dentry->d_sb->s_root;
274062306a36Sopenharmony_ci	return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad);
274162306a36Sopenharmony_ci}
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_cistatic int selinux_mount(const char *dev_name,
274462306a36Sopenharmony_ci			 const struct path *path,
274562306a36Sopenharmony_ci			 const char *type,
274662306a36Sopenharmony_ci			 unsigned long flags,
274762306a36Sopenharmony_ci			 void *data)
274862306a36Sopenharmony_ci{
274962306a36Sopenharmony_ci	const struct cred *cred = current_cred();
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	if (flags & MS_REMOUNT)
275262306a36Sopenharmony_ci		return superblock_has_perm(cred, path->dentry->d_sb,
275362306a36Sopenharmony_ci					   FILESYSTEM__REMOUNT, NULL);
275462306a36Sopenharmony_ci	else
275562306a36Sopenharmony_ci		return path_has_perm(cred, path, FILE__MOUNTON);
275662306a36Sopenharmony_ci}
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_cistatic int selinux_move_mount(const struct path *from_path,
275962306a36Sopenharmony_ci			      const struct path *to_path)
276062306a36Sopenharmony_ci{
276162306a36Sopenharmony_ci	const struct cred *cred = current_cred();
276262306a36Sopenharmony_ci
276362306a36Sopenharmony_ci	return path_has_perm(cred, to_path, FILE__MOUNTON);
276462306a36Sopenharmony_ci}
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_cistatic int selinux_umount(struct vfsmount *mnt, int flags)
276762306a36Sopenharmony_ci{
276862306a36Sopenharmony_ci	const struct cred *cred = current_cred();
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	return superblock_has_perm(cred, mnt->mnt_sb,
277162306a36Sopenharmony_ci				   FILESYSTEM__UNMOUNT, NULL);
277262306a36Sopenharmony_ci}
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_cistatic int selinux_fs_context_submount(struct fs_context *fc,
277562306a36Sopenharmony_ci				   struct super_block *reference)
277662306a36Sopenharmony_ci{
277762306a36Sopenharmony_ci	const struct superblock_security_struct *sbsec = selinux_superblock(reference);
277862306a36Sopenharmony_ci	struct selinux_mnt_opts *opts;
277962306a36Sopenharmony_ci
278062306a36Sopenharmony_ci	/*
278162306a36Sopenharmony_ci	 * Ensure that fc->security remains NULL when no options are set
278262306a36Sopenharmony_ci	 * as expected by selinux_set_mnt_opts().
278362306a36Sopenharmony_ci	 */
278462306a36Sopenharmony_ci	if (!(sbsec->flags & (FSCONTEXT_MNT|CONTEXT_MNT|DEFCONTEXT_MNT)))
278562306a36Sopenharmony_ci		return 0;
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	opts = kzalloc(sizeof(*opts), GFP_KERNEL);
278862306a36Sopenharmony_ci	if (!opts)
278962306a36Sopenharmony_ci		return -ENOMEM;
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci	if (sbsec->flags & FSCONTEXT_MNT)
279262306a36Sopenharmony_ci		opts->fscontext_sid = sbsec->sid;
279362306a36Sopenharmony_ci	if (sbsec->flags & CONTEXT_MNT)
279462306a36Sopenharmony_ci		opts->context_sid = sbsec->mntpoint_sid;
279562306a36Sopenharmony_ci	if (sbsec->flags & DEFCONTEXT_MNT)
279662306a36Sopenharmony_ci		opts->defcontext_sid = sbsec->def_sid;
279762306a36Sopenharmony_ci	fc->security = opts;
279862306a36Sopenharmony_ci	return 0;
279962306a36Sopenharmony_ci}
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_cistatic int selinux_fs_context_dup(struct fs_context *fc,
280262306a36Sopenharmony_ci				  struct fs_context *src_fc)
280362306a36Sopenharmony_ci{
280462306a36Sopenharmony_ci	const struct selinux_mnt_opts *src = src_fc->security;
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci	if (!src)
280762306a36Sopenharmony_ci		return 0;
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	fc->security = kmemdup(src, sizeof(*src), GFP_KERNEL);
281062306a36Sopenharmony_ci	return fc->security ? 0 : -ENOMEM;
281162306a36Sopenharmony_ci}
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_cistatic const struct fs_parameter_spec selinux_fs_parameters[] = {
281462306a36Sopenharmony_ci	fsparam_string(CONTEXT_STR,	Opt_context),
281562306a36Sopenharmony_ci	fsparam_string(DEFCONTEXT_STR,	Opt_defcontext),
281662306a36Sopenharmony_ci	fsparam_string(FSCONTEXT_STR,	Opt_fscontext),
281762306a36Sopenharmony_ci	fsparam_string(ROOTCONTEXT_STR,	Opt_rootcontext),
281862306a36Sopenharmony_ci	fsparam_flag  (SECLABEL_STR,	Opt_seclabel),
281962306a36Sopenharmony_ci	{}
282062306a36Sopenharmony_ci};
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_cistatic int selinux_fs_context_parse_param(struct fs_context *fc,
282362306a36Sopenharmony_ci					  struct fs_parameter *param)
282462306a36Sopenharmony_ci{
282562306a36Sopenharmony_ci	struct fs_parse_result result;
282662306a36Sopenharmony_ci	int opt;
282762306a36Sopenharmony_ci
282862306a36Sopenharmony_ci	opt = fs_parse(fc, selinux_fs_parameters, param, &result);
282962306a36Sopenharmony_ci	if (opt < 0)
283062306a36Sopenharmony_ci		return opt;
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci	return selinux_add_opt(opt, param->string, &fc->security);
283362306a36Sopenharmony_ci}
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci/* inode security operations */
283662306a36Sopenharmony_ci
283762306a36Sopenharmony_cistatic int selinux_inode_alloc_security(struct inode *inode)
283862306a36Sopenharmony_ci{
283962306a36Sopenharmony_ci	struct inode_security_struct *isec = selinux_inode(inode);
284062306a36Sopenharmony_ci	u32 sid = current_sid();
284162306a36Sopenharmony_ci
284262306a36Sopenharmony_ci	spin_lock_init(&isec->lock);
284362306a36Sopenharmony_ci	INIT_LIST_HEAD(&isec->list);
284462306a36Sopenharmony_ci	isec->inode = inode;
284562306a36Sopenharmony_ci	isec->sid = SECINITSID_UNLABELED;
284662306a36Sopenharmony_ci	isec->sclass = SECCLASS_FILE;
284762306a36Sopenharmony_ci	isec->task_sid = sid;
284862306a36Sopenharmony_ci	isec->initialized = LABEL_INVALID;
284962306a36Sopenharmony_ci
285062306a36Sopenharmony_ci	return 0;
285162306a36Sopenharmony_ci}
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_cistatic void selinux_inode_free_security(struct inode *inode)
285462306a36Sopenharmony_ci{
285562306a36Sopenharmony_ci	inode_free_security(inode);
285662306a36Sopenharmony_ci}
285762306a36Sopenharmony_ci
285862306a36Sopenharmony_cistatic int selinux_dentry_init_security(struct dentry *dentry, int mode,
285962306a36Sopenharmony_ci					const struct qstr *name,
286062306a36Sopenharmony_ci					const char **xattr_name, void **ctx,
286162306a36Sopenharmony_ci					u32 *ctxlen)
286262306a36Sopenharmony_ci{
286362306a36Sopenharmony_ci	u32 newsid;
286462306a36Sopenharmony_ci	int rc;
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci	rc = selinux_determine_inode_label(selinux_cred(current_cred()),
286762306a36Sopenharmony_ci					   d_inode(dentry->d_parent), name,
286862306a36Sopenharmony_ci					   inode_mode_to_security_class(mode),
286962306a36Sopenharmony_ci					   &newsid);
287062306a36Sopenharmony_ci	if (rc)
287162306a36Sopenharmony_ci		return rc;
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	if (xattr_name)
287462306a36Sopenharmony_ci		*xattr_name = XATTR_NAME_SELINUX;
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci	return security_sid_to_context(newsid, (char **)ctx,
287762306a36Sopenharmony_ci				       ctxlen);
287862306a36Sopenharmony_ci}
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_cistatic int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
288162306a36Sopenharmony_ci					  struct qstr *name,
288262306a36Sopenharmony_ci					  const struct cred *old,
288362306a36Sopenharmony_ci					  struct cred *new)
288462306a36Sopenharmony_ci{
288562306a36Sopenharmony_ci	u32 newsid;
288662306a36Sopenharmony_ci	int rc;
288762306a36Sopenharmony_ci	struct task_security_struct *tsec;
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	rc = selinux_determine_inode_label(selinux_cred(old),
289062306a36Sopenharmony_ci					   d_inode(dentry->d_parent), name,
289162306a36Sopenharmony_ci					   inode_mode_to_security_class(mode),
289262306a36Sopenharmony_ci					   &newsid);
289362306a36Sopenharmony_ci	if (rc)
289462306a36Sopenharmony_ci		return rc;
289562306a36Sopenharmony_ci
289662306a36Sopenharmony_ci	tsec = selinux_cred(new);
289762306a36Sopenharmony_ci	tsec->create_sid = newsid;
289862306a36Sopenharmony_ci	return 0;
289962306a36Sopenharmony_ci}
290062306a36Sopenharmony_ci
290162306a36Sopenharmony_cistatic int selinux_inode_init_security(struct inode *inode, struct inode *dir,
290262306a36Sopenharmony_ci				       const struct qstr *qstr,
290362306a36Sopenharmony_ci				       struct xattr *xattrs, int *xattr_count)
290462306a36Sopenharmony_ci{
290562306a36Sopenharmony_ci	const struct task_security_struct *tsec = selinux_cred(current_cred());
290662306a36Sopenharmony_ci	struct superblock_security_struct *sbsec;
290762306a36Sopenharmony_ci	struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
290862306a36Sopenharmony_ci	u32 newsid, clen;
290962306a36Sopenharmony_ci	int rc;
291062306a36Sopenharmony_ci	char *context;
291162306a36Sopenharmony_ci
291262306a36Sopenharmony_ci	sbsec = selinux_superblock(dir->i_sb);
291362306a36Sopenharmony_ci
291462306a36Sopenharmony_ci	newsid = tsec->create_sid;
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci	rc = selinux_determine_inode_label(tsec, dir, qstr,
291762306a36Sopenharmony_ci		inode_mode_to_security_class(inode->i_mode),
291862306a36Sopenharmony_ci		&newsid);
291962306a36Sopenharmony_ci	if (rc)
292062306a36Sopenharmony_ci		return rc;
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_ci	/* Possibly defer initialization to selinux_complete_init. */
292362306a36Sopenharmony_ci	if (sbsec->flags & SE_SBINITIALIZED) {
292462306a36Sopenharmony_ci		struct inode_security_struct *isec = selinux_inode(inode);
292562306a36Sopenharmony_ci		isec->sclass = inode_mode_to_security_class(inode->i_mode);
292662306a36Sopenharmony_ci		isec->sid = newsid;
292762306a36Sopenharmony_ci		isec->initialized = LABEL_INITIALIZED;
292862306a36Sopenharmony_ci	}
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci	if (!selinux_initialized() ||
293162306a36Sopenharmony_ci	    !(sbsec->flags & SBLABEL_MNT))
293262306a36Sopenharmony_ci		return -EOPNOTSUPP;
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	if (xattr) {
293562306a36Sopenharmony_ci		rc = security_sid_to_context_force(newsid,
293662306a36Sopenharmony_ci						   &context, &clen);
293762306a36Sopenharmony_ci		if (rc)
293862306a36Sopenharmony_ci			return rc;
293962306a36Sopenharmony_ci		xattr->value = context;
294062306a36Sopenharmony_ci		xattr->value_len = clen;
294162306a36Sopenharmony_ci		xattr->name = XATTR_SELINUX_SUFFIX;
294262306a36Sopenharmony_ci	}
294362306a36Sopenharmony_ci
294462306a36Sopenharmony_ci	return 0;
294562306a36Sopenharmony_ci}
294662306a36Sopenharmony_ci
294762306a36Sopenharmony_cistatic int selinux_inode_init_security_anon(struct inode *inode,
294862306a36Sopenharmony_ci					    const struct qstr *name,
294962306a36Sopenharmony_ci					    const struct inode *context_inode)
295062306a36Sopenharmony_ci{
295162306a36Sopenharmony_ci	const struct task_security_struct *tsec = selinux_cred(current_cred());
295262306a36Sopenharmony_ci	struct common_audit_data ad;
295362306a36Sopenharmony_ci	struct inode_security_struct *isec;
295462306a36Sopenharmony_ci	int rc;
295562306a36Sopenharmony_ci
295662306a36Sopenharmony_ci	if (unlikely(!selinux_initialized()))
295762306a36Sopenharmony_ci		return 0;
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci	isec = selinux_inode(inode);
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	/*
296262306a36Sopenharmony_ci	 * We only get here once per ephemeral inode.  The inode has
296362306a36Sopenharmony_ci	 * been initialized via inode_alloc_security but is otherwise
296462306a36Sopenharmony_ci	 * untouched.
296562306a36Sopenharmony_ci	 */
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci	if (context_inode) {
296862306a36Sopenharmony_ci		struct inode_security_struct *context_isec =
296962306a36Sopenharmony_ci			selinux_inode(context_inode);
297062306a36Sopenharmony_ci		if (context_isec->initialized != LABEL_INITIALIZED) {
297162306a36Sopenharmony_ci			pr_err("SELinux:  context_inode is not initialized\n");
297262306a36Sopenharmony_ci			return -EACCES;
297362306a36Sopenharmony_ci		}
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_ci		isec->sclass = context_isec->sclass;
297662306a36Sopenharmony_ci		isec->sid = context_isec->sid;
297762306a36Sopenharmony_ci	} else {
297862306a36Sopenharmony_ci		isec->sclass = SECCLASS_ANON_INODE;
297962306a36Sopenharmony_ci		rc = security_transition_sid(
298062306a36Sopenharmony_ci			tsec->sid, tsec->sid,
298162306a36Sopenharmony_ci			isec->sclass, name, &isec->sid);
298262306a36Sopenharmony_ci		if (rc)
298362306a36Sopenharmony_ci			return rc;
298462306a36Sopenharmony_ci	}
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci	isec->initialized = LABEL_INITIALIZED;
298762306a36Sopenharmony_ci	/*
298862306a36Sopenharmony_ci	 * Now that we've initialized security, check whether we're
298962306a36Sopenharmony_ci	 * allowed to actually create this type of anonymous inode.
299062306a36Sopenharmony_ci	 */
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_ANONINODE;
299362306a36Sopenharmony_ci	ad.u.anonclass = name ? (const char *)name->name : "?";
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci	return avc_has_perm(tsec->sid,
299662306a36Sopenharmony_ci			    isec->sid,
299762306a36Sopenharmony_ci			    isec->sclass,
299862306a36Sopenharmony_ci			    FILE__CREATE,
299962306a36Sopenharmony_ci			    &ad);
300062306a36Sopenharmony_ci}
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_cistatic int selinux_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode)
300362306a36Sopenharmony_ci{
300462306a36Sopenharmony_ci	return may_create(dir, dentry, SECCLASS_FILE);
300562306a36Sopenharmony_ci}
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_cistatic int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
300862306a36Sopenharmony_ci{
300962306a36Sopenharmony_ci	return may_link(dir, old_dentry, MAY_LINK);
301062306a36Sopenharmony_ci}
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_cistatic int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
301362306a36Sopenharmony_ci{
301462306a36Sopenharmony_ci	return may_link(dir, dentry, MAY_UNLINK);
301562306a36Sopenharmony_ci}
301662306a36Sopenharmony_ci
301762306a36Sopenharmony_cistatic int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
301862306a36Sopenharmony_ci{
301962306a36Sopenharmony_ci	return may_create(dir, dentry, SECCLASS_LNK_FILE);
302062306a36Sopenharmony_ci}
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_cistatic int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mask)
302362306a36Sopenharmony_ci{
302462306a36Sopenharmony_ci	return may_create(dir, dentry, SECCLASS_DIR);
302562306a36Sopenharmony_ci}
302662306a36Sopenharmony_ci
302762306a36Sopenharmony_cistatic int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
302862306a36Sopenharmony_ci{
302962306a36Sopenharmony_ci	return may_link(dir, dentry, MAY_RMDIR);
303062306a36Sopenharmony_ci}
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_cistatic int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
303362306a36Sopenharmony_ci{
303462306a36Sopenharmony_ci	return may_create(dir, dentry, inode_mode_to_security_class(mode));
303562306a36Sopenharmony_ci}
303662306a36Sopenharmony_ci
303762306a36Sopenharmony_cistatic int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry,
303862306a36Sopenharmony_ci				struct inode *new_inode, struct dentry *new_dentry)
303962306a36Sopenharmony_ci{
304062306a36Sopenharmony_ci	return may_rename(old_inode, old_dentry, new_inode, new_dentry);
304162306a36Sopenharmony_ci}
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_cistatic int selinux_inode_readlink(struct dentry *dentry)
304462306a36Sopenharmony_ci{
304562306a36Sopenharmony_ci	const struct cred *cred = current_cred();
304662306a36Sopenharmony_ci
304762306a36Sopenharmony_ci	return dentry_has_perm(cred, dentry, FILE__READ);
304862306a36Sopenharmony_ci}
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_cistatic int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
305162306a36Sopenharmony_ci				     bool rcu)
305262306a36Sopenharmony_ci{
305362306a36Sopenharmony_ci	const struct cred *cred = current_cred();
305462306a36Sopenharmony_ci	struct common_audit_data ad;
305562306a36Sopenharmony_ci	struct inode_security_struct *isec;
305662306a36Sopenharmony_ci	u32 sid;
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_DENTRY;
305962306a36Sopenharmony_ci	ad.u.dentry = dentry;
306062306a36Sopenharmony_ci	sid = cred_sid(cred);
306162306a36Sopenharmony_ci	isec = inode_security_rcu(inode, rcu);
306262306a36Sopenharmony_ci	if (IS_ERR(isec))
306362306a36Sopenharmony_ci		return PTR_ERR(isec);
306462306a36Sopenharmony_ci
306562306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, isec->sclass, FILE__READ, &ad);
306662306a36Sopenharmony_ci}
306762306a36Sopenharmony_ci
306862306a36Sopenharmony_cistatic noinline int audit_inode_permission(struct inode *inode,
306962306a36Sopenharmony_ci					   u32 perms, u32 audited, u32 denied,
307062306a36Sopenharmony_ci					   int result)
307162306a36Sopenharmony_ci{
307262306a36Sopenharmony_ci	struct common_audit_data ad;
307362306a36Sopenharmony_ci	struct inode_security_struct *isec = selinux_inode(inode);
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_INODE;
307662306a36Sopenharmony_ci	ad.u.inode = inode;
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci	return slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms,
307962306a36Sopenharmony_ci			    audited, denied, result, &ad);
308062306a36Sopenharmony_ci}
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_cistatic int selinux_inode_permission(struct inode *inode, int mask)
308362306a36Sopenharmony_ci{
308462306a36Sopenharmony_ci	const struct cred *cred = current_cred();
308562306a36Sopenharmony_ci	u32 perms;
308662306a36Sopenharmony_ci	bool from_access;
308762306a36Sopenharmony_ci	bool no_block = mask & MAY_NOT_BLOCK;
308862306a36Sopenharmony_ci	struct inode_security_struct *isec;
308962306a36Sopenharmony_ci	u32 sid;
309062306a36Sopenharmony_ci	struct av_decision avd;
309162306a36Sopenharmony_ci	int rc, rc2;
309262306a36Sopenharmony_ci	u32 audited, denied;
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	from_access = mask & MAY_ACCESS;
309562306a36Sopenharmony_ci	mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND);
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_ci	/* No permission to check.  Existence test. */
309862306a36Sopenharmony_ci	if (!mask)
309962306a36Sopenharmony_ci		return 0;
310062306a36Sopenharmony_ci
310162306a36Sopenharmony_ci	if (unlikely(IS_PRIVATE(inode)))
310262306a36Sopenharmony_ci		return 0;
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci	perms = file_mask_to_av(inode->i_mode, mask);
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci	sid = cred_sid(cred);
310762306a36Sopenharmony_ci	isec = inode_security_rcu(inode, no_block);
310862306a36Sopenharmony_ci	if (IS_ERR(isec))
310962306a36Sopenharmony_ci		return PTR_ERR(isec);
311062306a36Sopenharmony_ci
311162306a36Sopenharmony_ci	rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0,
311262306a36Sopenharmony_ci				  &avd);
311362306a36Sopenharmony_ci	audited = avc_audit_required(perms, &avd, rc,
311462306a36Sopenharmony_ci				     from_access ? FILE__AUDIT_ACCESS : 0,
311562306a36Sopenharmony_ci				     &denied);
311662306a36Sopenharmony_ci	if (likely(!audited))
311762306a36Sopenharmony_ci		return rc;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	rc2 = audit_inode_permission(inode, perms, audited, denied, rc);
312062306a36Sopenharmony_ci	if (rc2)
312162306a36Sopenharmony_ci		return rc2;
312262306a36Sopenharmony_ci	return rc;
312362306a36Sopenharmony_ci}
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_cistatic int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
312662306a36Sopenharmony_ci{
312762306a36Sopenharmony_ci	const struct cred *cred = current_cred();
312862306a36Sopenharmony_ci	struct inode *inode = d_backing_inode(dentry);
312962306a36Sopenharmony_ci	unsigned int ia_valid = iattr->ia_valid;
313062306a36Sopenharmony_ci	__u32 av = FILE__WRITE;
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci	/* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */
313362306a36Sopenharmony_ci	if (ia_valid & ATTR_FORCE) {
313462306a36Sopenharmony_ci		ia_valid &= ~(ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_MODE |
313562306a36Sopenharmony_ci			      ATTR_FORCE);
313662306a36Sopenharmony_ci		if (!ia_valid)
313762306a36Sopenharmony_ci			return 0;
313862306a36Sopenharmony_ci	}
313962306a36Sopenharmony_ci
314062306a36Sopenharmony_ci	if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID |
314162306a36Sopenharmony_ci			ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET))
314262306a36Sopenharmony_ci		return dentry_has_perm(cred, dentry, FILE__SETATTR);
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ci	if (selinux_policycap_openperm() &&
314562306a36Sopenharmony_ci	    inode->i_sb->s_magic != SOCKFS_MAGIC &&
314662306a36Sopenharmony_ci	    (ia_valid & ATTR_SIZE) &&
314762306a36Sopenharmony_ci	    !(ia_valid & ATTR_FILE))
314862306a36Sopenharmony_ci		av |= FILE__OPEN;
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_ci	return dentry_has_perm(cred, dentry, av);
315162306a36Sopenharmony_ci}
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_cistatic int selinux_inode_getattr(const struct path *path)
315462306a36Sopenharmony_ci{
315562306a36Sopenharmony_ci	return path_has_perm(current_cred(), path, FILE__GETATTR);
315662306a36Sopenharmony_ci}
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_cistatic bool has_cap_mac_admin(bool audit)
315962306a36Sopenharmony_ci{
316062306a36Sopenharmony_ci	const struct cred *cred = current_cred();
316162306a36Sopenharmony_ci	unsigned int opts = audit ? CAP_OPT_NONE : CAP_OPT_NOAUDIT;
316262306a36Sopenharmony_ci
316362306a36Sopenharmony_ci	if (cap_capable(cred, &init_user_ns, CAP_MAC_ADMIN, opts))
316462306a36Sopenharmony_ci		return false;
316562306a36Sopenharmony_ci	if (cred_has_capability(cred, CAP_MAC_ADMIN, opts, true))
316662306a36Sopenharmony_ci		return false;
316762306a36Sopenharmony_ci	return true;
316862306a36Sopenharmony_ci}
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_cistatic int selinux_inode_setxattr(struct mnt_idmap *idmap,
317162306a36Sopenharmony_ci				  struct dentry *dentry, const char *name,
317262306a36Sopenharmony_ci				  const void *value, size_t size, int flags)
317362306a36Sopenharmony_ci{
317462306a36Sopenharmony_ci	struct inode *inode = d_backing_inode(dentry);
317562306a36Sopenharmony_ci	struct inode_security_struct *isec;
317662306a36Sopenharmony_ci	struct superblock_security_struct *sbsec;
317762306a36Sopenharmony_ci	struct common_audit_data ad;
317862306a36Sopenharmony_ci	u32 newsid, sid = current_sid();
317962306a36Sopenharmony_ci	int rc = 0;
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci	if (strcmp(name, XATTR_NAME_SELINUX)) {
318262306a36Sopenharmony_ci		rc = cap_inode_setxattr(dentry, name, value, size, flags);
318362306a36Sopenharmony_ci		if (rc)
318462306a36Sopenharmony_ci			return rc;
318562306a36Sopenharmony_ci
318662306a36Sopenharmony_ci		/* Not an attribute we recognize, so just check the
318762306a36Sopenharmony_ci		   ordinary setattr permission. */
318862306a36Sopenharmony_ci		return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
318962306a36Sopenharmony_ci	}
319062306a36Sopenharmony_ci
319162306a36Sopenharmony_ci	if (!selinux_initialized())
319262306a36Sopenharmony_ci		return (inode_owner_or_capable(idmap, inode) ? 0 : -EPERM);
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci	sbsec = selinux_superblock(inode->i_sb);
319562306a36Sopenharmony_ci	if (!(sbsec->flags & SBLABEL_MNT))
319662306a36Sopenharmony_ci		return -EOPNOTSUPP;
319762306a36Sopenharmony_ci
319862306a36Sopenharmony_ci	if (!inode_owner_or_capable(idmap, inode))
319962306a36Sopenharmony_ci		return -EPERM;
320062306a36Sopenharmony_ci
320162306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_DENTRY;
320262306a36Sopenharmony_ci	ad.u.dentry = dentry;
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci	isec = backing_inode_security(dentry);
320562306a36Sopenharmony_ci	rc = avc_has_perm(sid, isec->sid, isec->sclass,
320662306a36Sopenharmony_ci			  FILE__RELABELFROM, &ad);
320762306a36Sopenharmony_ci	if (rc)
320862306a36Sopenharmony_ci		return rc;
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	rc = security_context_to_sid(value, size, &newsid,
321162306a36Sopenharmony_ci				     GFP_KERNEL);
321262306a36Sopenharmony_ci	if (rc == -EINVAL) {
321362306a36Sopenharmony_ci		if (!has_cap_mac_admin(true)) {
321462306a36Sopenharmony_ci			struct audit_buffer *ab;
321562306a36Sopenharmony_ci			size_t audit_size;
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci			/* We strip a nul only if it is at the end, otherwise the
321862306a36Sopenharmony_ci			 * context contains a nul and we should audit that */
321962306a36Sopenharmony_ci			if (value) {
322062306a36Sopenharmony_ci				const char *str = value;
322162306a36Sopenharmony_ci
322262306a36Sopenharmony_ci				if (str[size - 1] == '\0')
322362306a36Sopenharmony_ci					audit_size = size - 1;
322462306a36Sopenharmony_ci				else
322562306a36Sopenharmony_ci					audit_size = size;
322662306a36Sopenharmony_ci			} else {
322762306a36Sopenharmony_ci				audit_size = 0;
322862306a36Sopenharmony_ci			}
322962306a36Sopenharmony_ci			ab = audit_log_start(audit_context(),
323062306a36Sopenharmony_ci					     GFP_ATOMIC, AUDIT_SELINUX_ERR);
323162306a36Sopenharmony_ci			if (!ab)
323262306a36Sopenharmony_ci				return rc;
323362306a36Sopenharmony_ci			audit_log_format(ab, "op=setxattr invalid_context=");
323462306a36Sopenharmony_ci			audit_log_n_untrustedstring(ab, value, audit_size);
323562306a36Sopenharmony_ci			audit_log_end(ab);
323662306a36Sopenharmony_ci
323762306a36Sopenharmony_ci			return rc;
323862306a36Sopenharmony_ci		}
323962306a36Sopenharmony_ci		rc = security_context_to_sid_force(value,
324062306a36Sopenharmony_ci						   size, &newsid);
324162306a36Sopenharmony_ci	}
324262306a36Sopenharmony_ci	if (rc)
324362306a36Sopenharmony_ci		return rc;
324462306a36Sopenharmony_ci
324562306a36Sopenharmony_ci	rc = avc_has_perm(sid, newsid, isec->sclass,
324662306a36Sopenharmony_ci			  FILE__RELABELTO, &ad);
324762306a36Sopenharmony_ci	if (rc)
324862306a36Sopenharmony_ci		return rc;
324962306a36Sopenharmony_ci
325062306a36Sopenharmony_ci	rc = security_validate_transition(isec->sid, newsid,
325162306a36Sopenharmony_ci					  sid, isec->sclass);
325262306a36Sopenharmony_ci	if (rc)
325362306a36Sopenharmony_ci		return rc;
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	return avc_has_perm(newsid,
325662306a36Sopenharmony_ci			    sbsec->sid,
325762306a36Sopenharmony_ci			    SECCLASS_FILESYSTEM,
325862306a36Sopenharmony_ci			    FILESYSTEM__ASSOCIATE,
325962306a36Sopenharmony_ci			    &ad);
326062306a36Sopenharmony_ci}
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_cistatic int selinux_inode_set_acl(struct mnt_idmap *idmap,
326362306a36Sopenharmony_ci				 struct dentry *dentry, const char *acl_name,
326462306a36Sopenharmony_ci				 struct posix_acl *kacl)
326562306a36Sopenharmony_ci{
326662306a36Sopenharmony_ci	return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
326762306a36Sopenharmony_ci}
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_cistatic int selinux_inode_get_acl(struct mnt_idmap *idmap,
327062306a36Sopenharmony_ci				 struct dentry *dentry, const char *acl_name)
327162306a36Sopenharmony_ci{
327262306a36Sopenharmony_ci	return dentry_has_perm(current_cred(), dentry, FILE__GETATTR);
327362306a36Sopenharmony_ci}
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_cistatic int selinux_inode_remove_acl(struct mnt_idmap *idmap,
327662306a36Sopenharmony_ci				    struct dentry *dentry, const char *acl_name)
327762306a36Sopenharmony_ci{
327862306a36Sopenharmony_ci	return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
327962306a36Sopenharmony_ci}
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_cistatic void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
328262306a36Sopenharmony_ci					const void *value, size_t size,
328362306a36Sopenharmony_ci					int flags)
328462306a36Sopenharmony_ci{
328562306a36Sopenharmony_ci	struct inode *inode = d_backing_inode(dentry);
328662306a36Sopenharmony_ci	struct inode_security_struct *isec;
328762306a36Sopenharmony_ci	u32 newsid;
328862306a36Sopenharmony_ci	int rc;
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci	if (strcmp(name, XATTR_NAME_SELINUX)) {
329162306a36Sopenharmony_ci		/* Not an attribute we recognize, so nothing to do. */
329262306a36Sopenharmony_ci		return;
329362306a36Sopenharmony_ci	}
329462306a36Sopenharmony_ci
329562306a36Sopenharmony_ci	if (!selinux_initialized()) {
329662306a36Sopenharmony_ci		/* If we haven't even been initialized, then we can't validate
329762306a36Sopenharmony_ci		 * against a policy, so leave the label as invalid. It may
329862306a36Sopenharmony_ci		 * resolve to a valid label on the next revalidation try if
329962306a36Sopenharmony_ci		 * we've since initialized.
330062306a36Sopenharmony_ci		 */
330162306a36Sopenharmony_ci		return;
330262306a36Sopenharmony_ci	}
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_ci	rc = security_context_to_sid_force(value, size,
330562306a36Sopenharmony_ci					   &newsid);
330662306a36Sopenharmony_ci	if (rc) {
330762306a36Sopenharmony_ci		pr_err("SELinux:  unable to map context to SID"
330862306a36Sopenharmony_ci		       "for (%s, %lu), rc=%d\n",
330962306a36Sopenharmony_ci		       inode->i_sb->s_id, inode->i_ino, -rc);
331062306a36Sopenharmony_ci		return;
331162306a36Sopenharmony_ci	}
331262306a36Sopenharmony_ci
331362306a36Sopenharmony_ci	isec = backing_inode_security(dentry);
331462306a36Sopenharmony_ci	spin_lock(&isec->lock);
331562306a36Sopenharmony_ci	isec->sclass = inode_mode_to_security_class(inode->i_mode);
331662306a36Sopenharmony_ci	isec->sid = newsid;
331762306a36Sopenharmony_ci	isec->initialized = LABEL_INITIALIZED;
331862306a36Sopenharmony_ci	spin_unlock(&isec->lock);
331962306a36Sopenharmony_ci}
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_cistatic int selinux_inode_getxattr(struct dentry *dentry, const char *name)
332262306a36Sopenharmony_ci{
332362306a36Sopenharmony_ci	const struct cred *cred = current_cred();
332462306a36Sopenharmony_ci
332562306a36Sopenharmony_ci	return dentry_has_perm(cred, dentry, FILE__GETATTR);
332662306a36Sopenharmony_ci}
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_cistatic int selinux_inode_listxattr(struct dentry *dentry)
332962306a36Sopenharmony_ci{
333062306a36Sopenharmony_ci	const struct cred *cred = current_cred();
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci	return dentry_has_perm(cred, dentry, FILE__GETATTR);
333362306a36Sopenharmony_ci}
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_cistatic int selinux_inode_removexattr(struct mnt_idmap *idmap,
333662306a36Sopenharmony_ci				     struct dentry *dentry, const char *name)
333762306a36Sopenharmony_ci{
333862306a36Sopenharmony_ci	if (strcmp(name, XATTR_NAME_SELINUX)) {
333962306a36Sopenharmony_ci		int rc = cap_inode_removexattr(idmap, dentry, name);
334062306a36Sopenharmony_ci		if (rc)
334162306a36Sopenharmony_ci			return rc;
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_ci		/* Not an attribute we recognize, so just check the
334462306a36Sopenharmony_ci		   ordinary setattr permission. */
334562306a36Sopenharmony_ci		return dentry_has_perm(current_cred(), dentry, FILE__SETATTR);
334662306a36Sopenharmony_ci	}
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci	if (!selinux_initialized())
334962306a36Sopenharmony_ci		return 0;
335062306a36Sopenharmony_ci
335162306a36Sopenharmony_ci	/* No one is allowed to remove a SELinux security label.
335262306a36Sopenharmony_ci	   You can change the label, but all data must be labeled. */
335362306a36Sopenharmony_ci	return -EACCES;
335462306a36Sopenharmony_ci}
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_cistatic int selinux_path_notify(const struct path *path, u64 mask,
335762306a36Sopenharmony_ci						unsigned int obj_type)
335862306a36Sopenharmony_ci{
335962306a36Sopenharmony_ci	int ret;
336062306a36Sopenharmony_ci	u32 perm;
336162306a36Sopenharmony_ci
336262306a36Sopenharmony_ci	struct common_audit_data ad;
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_PATH;
336562306a36Sopenharmony_ci	ad.u.path = *path;
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci	/*
336862306a36Sopenharmony_ci	 * Set permission needed based on the type of mark being set.
336962306a36Sopenharmony_ci	 * Performs an additional check for sb watches.
337062306a36Sopenharmony_ci	 */
337162306a36Sopenharmony_ci	switch (obj_type) {
337262306a36Sopenharmony_ci	case FSNOTIFY_OBJ_TYPE_VFSMOUNT:
337362306a36Sopenharmony_ci		perm = FILE__WATCH_MOUNT;
337462306a36Sopenharmony_ci		break;
337562306a36Sopenharmony_ci	case FSNOTIFY_OBJ_TYPE_SB:
337662306a36Sopenharmony_ci		perm = FILE__WATCH_SB;
337762306a36Sopenharmony_ci		ret = superblock_has_perm(current_cred(), path->dentry->d_sb,
337862306a36Sopenharmony_ci						FILESYSTEM__WATCH, &ad);
337962306a36Sopenharmony_ci		if (ret)
338062306a36Sopenharmony_ci			return ret;
338162306a36Sopenharmony_ci		break;
338262306a36Sopenharmony_ci	case FSNOTIFY_OBJ_TYPE_INODE:
338362306a36Sopenharmony_ci		perm = FILE__WATCH;
338462306a36Sopenharmony_ci		break;
338562306a36Sopenharmony_ci	default:
338662306a36Sopenharmony_ci		return -EINVAL;
338762306a36Sopenharmony_ci	}
338862306a36Sopenharmony_ci
338962306a36Sopenharmony_ci	/* blocking watches require the file:watch_with_perm permission */
339062306a36Sopenharmony_ci	if (mask & (ALL_FSNOTIFY_PERM_EVENTS))
339162306a36Sopenharmony_ci		perm |= FILE__WATCH_WITH_PERM;
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	/* watches on read-like events need the file:watch_reads permission */
339462306a36Sopenharmony_ci	if (mask & (FS_ACCESS | FS_ACCESS_PERM | FS_CLOSE_NOWRITE))
339562306a36Sopenharmony_ci		perm |= FILE__WATCH_READS;
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci	return path_has_perm(current_cred(), path, perm);
339862306a36Sopenharmony_ci}
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci/*
340162306a36Sopenharmony_ci * Copy the inode security context value to the user.
340262306a36Sopenharmony_ci *
340362306a36Sopenharmony_ci * Permission check is handled by selinux_inode_getxattr hook.
340462306a36Sopenharmony_ci */
340562306a36Sopenharmony_cistatic int selinux_inode_getsecurity(struct mnt_idmap *idmap,
340662306a36Sopenharmony_ci				     struct inode *inode, const char *name,
340762306a36Sopenharmony_ci				     void **buffer, bool alloc)
340862306a36Sopenharmony_ci{
340962306a36Sopenharmony_ci	u32 size;
341062306a36Sopenharmony_ci	int error;
341162306a36Sopenharmony_ci	char *context = NULL;
341262306a36Sopenharmony_ci	struct inode_security_struct *isec;
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_ci	/*
341562306a36Sopenharmony_ci	 * If we're not initialized yet, then we can't validate contexts, so
341662306a36Sopenharmony_ci	 * just let vfs_getxattr fall back to using the on-disk xattr.
341762306a36Sopenharmony_ci	 */
341862306a36Sopenharmony_ci	if (!selinux_initialized() ||
341962306a36Sopenharmony_ci	    strcmp(name, XATTR_SELINUX_SUFFIX))
342062306a36Sopenharmony_ci		return -EOPNOTSUPP;
342162306a36Sopenharmony_ci
342262306a36Sopenharmony_ci	/*
342362306a36Sopenharmony_ci	 * If the caller has CAP_MAC_ADMIN, then get the raw context
342462306a36Sopenharmony_ci	 * value even if it is not defined by current policy; otherwise,
342562306a36Sopenharmony_ci	 * use the in-core value under current policy.
342662306a36Sopenharmony_ci	 * Use the non-auditing forms of the permission checks since
342762306a36Sopenharmony_ci	 * getxattr may be called by unprivileged processes commonly
342862306a36Sopenharmony_ci	 * and lack of permission just means that we fall back to the
342962306a36Sopenharmony_ci	 * in-core context value, not a denial.
343062306a36Sopenharmony_ci	 */
343162306a36Sopenharmony_ci	isec = inode_security(inode);
343262306a36Sopenharmony_ci	if (has_cap_mac_admin(false))
343362306a36Sopenharmony_ci		error = security_sid_to_context_force(isec->sid, &context,
343462306a36Sopenharmony_ci						      &size);
343562306a36Sopenharmony_ci	else
343662306a36Sopenharmony_ci		error = security_sid_to_context(isec->sid,
343762306a36Sopenharmony_ci						&context, &size);
343862306a36Sopenharmony_ci	if (error)
343962306a36Sopenharmony_ci		return error;
344062306a36Sopenharmony_ci	error = size;
344162306a36Sopenharmony_ci	if (alloc) {
344262306a36Sopenharmony_ci		*buffer = context;
344362306a36Sopenharmony_ci		goto out_nofree;
344462306a36Sopenharmony_ci	}
344562306a36Sopenharmony_ci	kfree(context);
344662306a36Sopenharmony_ciout_nofree:
344762306a36Sopenharmony_ci	return error;
344862306a36Sopenharmony_ci}
344962306a36Sopenharmony_ci
345062306a36Sopenharmony_cistatic int selinux_inode_setsecurity(struct inode *inode, const char *name,
345162306a36Sopenharmony_ci				     const void *value, size_t size, int flags)
345262306a36Sopenharmony_ci{
345362306a36Sopenharmony_ci	struct inode_security_struct *isec = inode_security_novalidate(inode);
345462306a36Sopenharmony_ci	struct superblock_security_struct *sbsec;
345562306a36Sopenharmony_ci	u32 newsid;
345662306a36Sopenharmony_ci	int rc;
345762306a36Sopenharmony_ci
345862306a36Sopenharmony_ci	if (strcmp(name, XATTR_SELINUX_SUFFIX))
345962306a36Sopenharmony_ci		return -EOPNOTSUPP;
346062306a36Sopenharmony_ci
346162306a36Sopenharmony_ci	sbsec = selinux_superblock(inode->i_sb);
346262306a36Sopenharmony_ci	if (!(sbsec->flags & SBLABEL_MNT))
346362306a36Sopenharmony_ci		return -EOPNOTSUPP;
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_ci	if (!value || !size)
346662306a36Sopenharmony_ci		return -EACCES;
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	rc = security_context_to_sid(value, size, &newsid,
346962306a36Sopenharmony_ci				     GFP_KERNEL);
347062306a36Sopenharmony_ci	if (rc)
347162306a36Sopenharmony_ci		return rc;
347262306a36Sopenharmony_ci
347362306a36Sopenharmony_ci	spin_lock(&isec->lock);
347462306a36Sopenharmony_ci	isec->sclass = inode_mode_to_security_class(inode->i_mode);
347562306a36Sopenharmony_ci	isec->sid = newsid;
347662306a36Sopenharmony_ci	isec->initialized = LABEL_INITIALIZED;
347762306a36Sopenharmony_ci	spin_unlock(&isec->lock);
347862306a36Sopenharmony_ci	return 0;
347962306a36Sopenharmony_ci}
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_cistatic int selinux_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
348262306a36Sopenharmony_ci{
348362306a36Sopenharmony_ci	const int len = sizeof(XATTR_NAME_SELINUX);
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ci	if (!selinux_initialized())
348662306a36Sopenharmony_ci		return 0;
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_ci	if (buffer && len <= buffer_size)
348962306a36Sopenharmony_ci		memcpy(buffer, XATTR_NAME_SELINUX, len);
349062306a36Sopenharmony_ci	return len;
349162306a36Sopenharmony_ci}
349262306a36Sopenharmony_ci
349362306a36Sopenharmony_cistatic void selinux_inode_getsecid(struct inode *inode, u32 *secid)
349462306a36Sopenharmony_ci{
349562306a36Sopenharmony_ci	struct inode_security_struct *isec = inode_security_novalidate(inode);
349662306a36Sopenharmony_ci	*secid = isec->sid;
349762306a36Sopenharmony_ci}
349862306a36Sopenharmony_ci
349962306a36Sopenharmony_cistatic int selinux_inode_copy_up(struct dentry *src, struct cred **new)
350062306a36Sopenharmony_ci{
350162306a36Sopenharmony_ci	u32 sid;
350262306a36Sopenharmony_ci	struct task_security_struct *tsec;
350362306a36Sopenharmony_ci	struct cred *new_creds = *new;
350462306a36Sopenharmony_ci
350562306a36Sopenharmony_ci	if (new_creds == NULL) {
350662306a36Sopenharmony_ci		new_creds = prepare_creds();
350762306a36Sopenharmony_ci		if (!new_creds)
350862306a36Sopenharmony_ci			return -ENOMEM;
350962306a36Sopenharmony_ci	}
351062306a36Sopenharmony_ci
351162306a36Sopenharmony_ci	tsec = selinux_cred(new_creds);
351262306a36Sopenharmony_ci	/* Get label from overlay inode and set it in create_sid */
351362306a36Sopenharmony_ci	selinux_inode_getsecid(d_inode(src), &sid);
351462306a36Sopenharmony_ci	tsec->create_sid = sid;
351562306a36Sopenharmony_ci	*new = new_creds;
351662306a36Sopenharmony_ci	return 0;
351762306a36Sopenharmony_ci}
351862306a36Sopenharmony_ci
351962306a36Sopenharmony_cistatic int selinux_inode_copy_up_xattr(const char *name)
352062306a36Sopenharmony_ci{
352162306a36Sopenharmony_ci	/* The copy_up hook above sets the initial context on an inode, but we
352262306a36Sopenharmony_ci	 * don't then want to overwrite it by blindly copying all the lower
352362306a36Sopenharmony_ci	 * xattrs up.  Instead, we have to filter out SELinux-related xattrs.
352462306a36Sopenharmony_ci	 */
352562306a36Sopenharmony_ci	if (strcmp(name, XATTR_NAME_SELINUX) == 0)
352662306a36Sopenharmony_ci		return 1; /* Discard */
352762306a36Sopenharmony_ci	/*
352862306a36Sopenharmony_ci	 * Any other attribute apart from SELINUX is not claimed, supported
352962306a36Sopenharmony_ci	 * by selinux.
353062306a36Sopenharmony_ci	 */
353162306a36Sopenharmony_ci	return -EOPNOTSUPP;
353262306a36Sopenharmony_ci}
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci/* kernfs node operations */
353562306a36Sopenharmony_ci
353662306a36Sopenharmony_cistatic int selinux_kernfs_init_security(struct kernfs_node *kn_dir,
353762306a36Sopenharmony_ci					struct kernfs_node *kn)
353862306a36Sopenharmony_ci{
353962306a36Sopenharmony_ci	const struct task_security_struct *tsec = selinux_cred(current_cred());
354062306a36Sopenharmony_ci	u32 parent_sid, newsid, clen;
354162306a36Sopenharmony_ci	int rc;
354262306a36Sopenharmony_ci	char *context;
354362306a36Sopenharmony_ci
354462306a36Sopenharmony_ci	rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, NULL, 0);
354562306a36Sopenharmony_ci	if (rc == -ENODATA)
354662306a36Sopenharmony_ci		return 0;
354762306a36Sopenharmony_ci	else if (rc < 0)
354862306a36Sopenharmony_ci		return rc;
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ci	clen = (u32)rc;
355162306a36Sopenharmony_ci	context = kmalloc(clen, GFP_KERNEL);
355262306a36Sopenharmony_ci	if (!context)
355362306a36Sopenharmony_ci		return -ENOMEM;
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci	rc = kernfs_xattr_get(kn_dir, XATTR_NAME_SELINUX, context, clen);
355662306a36Sopenharmony_ci	if (rc < 0) {
355762306a36Sopenharmony_ci		kfree(context);
355862306a36Sopenharmony_ci		return rc;
355962306a36Sopenharmony_ci	}
356062306a36Sopenharmony_ci
356162306a36Sopenharmony_ci	rc = security_context_to_sid(context, clen, &parent_sid,
356262306a36Sopenharmony_ci				     GFP_KERNEL);
356362306a36Sopenharmony_ci	kfree(context);
356462306a36Sopenharmony_ci	if (rc)
356562306a36Sopenharmony_ci		return rc;
356662306a36Sopenharmony_ci
356762306a36Sopenharmony_ci	if (tsec->create_sid) {
356862306a36Sopenharmony_ci		newsid = tsec->create_sid;
356962306a36Sopenharmony_ci	} else {
357062306a36Sopenharmony_ci		u16 secclass = inode_mode_to_security_class(kn->mode);
357162306a36Sopenharmony_ci		struct qstr q;
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci		q.name = kn->name;
357462306a36Sopenharmony_ci		q.hash_len = hashlen_string(kn_dir, kn->name);
357562306a36Sopenharmony_ci
357662306a36Sopenharmony_ci		rc = security_transition_sid(tsec->sid,
357762306a36Sopenharmony_ci					     parent_sid, secclass, &q,
357862306a36Sopenharmony_ci					     &newsid);
357962306a36Sopenharmony_ci		if (rc)
358062306a36Sopenharmony_ci			return rc;
358162306a36Sopenharmony_ci	}
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci	rc = security_sid_to_context_force(newsid,
358462306a36Sopenharmony_ci					   &context, &clen);
358562306a36Sopenharmony_ci	if (rc)
358662306a36Sopenharmony_ci		return rc;
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci	rc = kernfs_xattr_set(kn, XATTR_NAME_SELINUX, context, clen,
358962306a36Sopenharmony_ci			      XATTR_CREATE);
359062306a36Sopenharmony_ci	kfree(context);
359162306a36Sopenharmony_ci	return rc;
359262306a36Sopenharmony_ci}
359362306a36Sopenharmony_ci
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_ci/* file security operations */
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_cistatic int selinux_revalidate_file_permission(struct file *file, int mask)
359862306a36Sopenharmony_ci{
359962306a36Sopenharmony_ci	const struct cred *cred = current_cred();
360062306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci	/* file_mask_to_av won't add FILE__WRITE if MAY_APPEND is set */
360362306a36Sopenharmony_ci	if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
360462306a36Sopenharmony_ci		mask |= MAY_APPEND;
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci	return file_has_perm(cred, file,
360762306a36Sopenharmony_ci			     file_mask_to_av(inode->i_mode, mask));
360862306a36Sopenharmony_ci}
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_cistatic int selinux_file_permission(struct file *file, int mask)
361162306a36Sopenharmony_ci{
361262306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
361362306a36Sopenharmony_ci	struct file_security_struct *fsec = selinux_file(file);
361462306a36Sopenharmony_ci	struct inode_security_struct *isec;
361562306a36Sopenharmony_ci	u32 sid = current_sid();
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci	if (!mask)
361862306a36Sopenharmony_ci		/* No permission to check.  Existence test. */
361962306a36Sopenharmony_ci		return 0;
362062306a36Sopenharmony_ci
362162306a36Sopenharmony_ci	isec = inode_security(inode);
362262306a36Sopenharmony_ci	if (sid == fsec->sid && fsec->isid == isec->sid &&
362362306a36Sopenharmony_ci	    fsec->pseqno == avc_policy_seqno())
362462306a36Sopenharmony_ci		/* No change since file_open check. */
362562306a36Sopenharmony_ci		return 0;
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci	return selinux_revalidate_file_permission(file, mask);
362862306a36Sopenharmony_ci}
362962306a36Sopenharmony_ci
363062306a36Sopenharmony_cistatic int selinux_file_alloc_security(struct file *file)
363162306a36Sopenharmony_ci{
363262306a36Sopenharmony_ci	struct file_security_struct *fsec = selinux_file(file);
363362306a36Sopenharmony_ci	u32 sid = current_sid();
363462306a36Sopenharmony_ci
363562306a36Sopenharmony_ci	fsec->sid = sid;
363662306a36Sopenharmony_ci	fsec->fown_sid = sid;
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci	return 0;
363962306a36Sopenharmony_ci}
364062306a36Sopenharmony_ci
364162306a36Sopenharmony_ci/*
364262306a36Sopenharmony_ci * Check whether a task has the ioctl permission and cmd
364362306a36Sopenharmony_ci * operation to an inode.
364462306a36Sopenharmony_ci */
364562306a36Sopenharmony_cistatic int ioctl_has_perm(const struct cred *cred, struct file *file,
364662306a36Sopenharmony_ci		u32 requested, u16 cmd)
364762306a36Sopenharmony_ci{
364862306a36Sopenharmony_ci	struct common_audit_data ad;
364962306a36Sopenharmony_ci	struct file_security_struct *fsec = selinux_file(file);
365062306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
365162306a36Sopenharmony_ci	struct inode_security_struct *isec;
365262306a36Sopenharmony_ci	struct lsm_ioctlop_audit ioctl;
365362306a36Sopenharmony_ci	u32 ssid = cred_sid(cred);
365462306a36Sopenharmony_ci	int rc;
365562306a36Sopenharmony_ci	u8 driver = cmd >> 8;
365662306a36Sopenharmony_ci	u8 xperm = cmd & 0xff;
365762306a36Sopenharmony_ci
365862306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IOCTL_OP;
365962306a36Sopenharmony_ci	ad.u.op = &ioctl;
366062306a36Sopenharmony_ci	ad.u.op->cmd = cmd;
366162306a36Sopenharmony_ci	ad.u.op->path = file->f_path;
366262306a36Sopenharmony_ci
366362306a36Sopenharmony_ci	if (ssid != fsec->sid) {
366462306a36Sopenharmony_ci		rc = avc_has_perm(ssid, fsec->sid,
366562306a36Sopenharmony_ci				SECCLASS_FD,
366662306a36Sopenharmony_ci				FD__USE,
366762306a36Sopenharmony_ci				&ad);
366862306a36Sopenharmony_ci		if (rc)
366962306a36Sopenharmony_ci			goto out;
367062306a36Sopenharmony_ci	}
367162306a36Sopenharmony_ci
367262306a36Sopenharmony_ci	if (unlikely(IS_PRIVATE(inode)))
367362306a36Sopenharmony_ci		return 0;
367462306a36Sopenharmony_ci
367562306a36Sopenharmony_ci	isec = inode_security(inode);
367662306a36Sopenharmony_ci	rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass,
367762306a36Sopenharmony_ci				    requested, driver, xperm, &ad);
367862306a36Sopenharmony_ciout:
367962306a36Sopenharmony_ci	return rc;
368062306a36Sopenharmony_ci}
368162306a36Sopenharmony_ci
368262306a36Sopenharmony_cistatic int selinux_file_ioctl(struct file *file, unsigned int cmd,
368362306a36Sopenharmony_ci			      unsigned long arg)
368462306a36Sopenharmony_ci{
368562306a36Sopenharmony_ci	const struct cred *cred = current_cred();
368662306a36Sopenharmony_ci	int error = 0;
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci	switch (cmd) {
368962306a36Sopenharmony_ci	case FIONREAD:
369062306a36Sopenharmony_ci	case FIBMAP:
369162306a36Sopenharmony_ci	case FIGETBSZ:
369262306a36Sopenharmony_ci	case FS_IOC_GETFLAGS:
369362306a36Sopenharmony_ci	case FS_IOC_GETVERSION:
369462306a36Sopenharmony_ci		error = file_has_perm(cred, file, FILE__GETATTR);
369562306a36Sopenharmony_ci		break;
369662306a36Sopenharmony_ci
369762306a36Sopenharmony_ci	case FS_IOC_SETFLAGS:
369862306a36Sopenharmony_ci	case FS_IOC_SETVERSION:
369962306a36Sopenharmony_ci		error = file_has_perm(cred, file, FILE__SETATTR);
370062306a36Sopenharmony_ci		break;
370162306a36Sopenharmony_ci
370262306a36Sopenharmony_ci	/* sys_ioctl() checks */
370362306a36Sopenharmony_ci	case FIONBIO:
370462306a36Sopenharmony_ci	case FIOASYNC:
370562306a36Sopenharmony_ci		error = file_has_perm(cred, file, 0);
370662306a36Sopenharmony_ci		break;
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci	case KDSKBENT:
370962306a36Sopenharmony_ci	case KDSKBSENT:
371062306a36Sopenharmony_ci		error = cred_has_capability(cred, CAP_SYS_TTY_CONFIG,
371162306a36Sopenharmony_ci					    CAP_OPT_NONE, true);
371262306a36Sopenharmony_ci		break;
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci	case FIOCLEX:
371562306a36Sopenharmony_ci	case FIONCLEX:
371662306a36Sopenharmony_ci		if (!selinux_policycap_ioctl_skip_cloexec())
371762306a36Sopenharmony_ci			error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
371862306a36Sopenharmony_ci		break;
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci	/* default case assumes that the command will go
372162306a36Sopenharmony_ci	 * to the file's ioctl() function.
372262306a36Sopenharmony_ci	 */
372362306a36Sopenharmony_ci	default:
372462306a36Sopenharmony_ci		error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd);
372562306a36Sopenharmony_ci	}
372662306a36Sopenharmony_ci	return error;
372762306a36Sopenharmony_ci}
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_cistatic int selinux_file_ioctl_compat(struct file *file, unsigned int cmd,
373062306a36Sopenharmony_ci			      unsigned long arg)
373162306a36Sopenharmony_ci{
373262306a36Sopenharmony_ci	/*
373362306a36Sopenharmony_ci	 * If we are in a 64-bit kernel running 32-bit userspace, we need to
373462306a36Sopenharmony_ci	 * make sure we don't compare 32-bit flags to 64-bit flags.
373562306a36Sopenharmony_ci	 */
373662306a36Sopenharmony_ci	switch (cmd) {
373762306a36Sopenharmony_ci	case FS_IOC32_GETFLAGS:
373862306a36Sopenharmony_ci		cmd = FS_IOC_GETFLAGS;
373962306a36Sopenharmony_ci		break;
374062306a36Sopenharmony_ci	case FS_IOC32_SETFLAGS:
374162306a36Sopenharmony_ci		cmd = FS_IOC_SETFLAGS;
374262306a36Sopenharmony_ci		break;
374362306a36Sopenharmony_ci	case FS_IOC32_GETVERSION:
374462306a36Sopenharmony_ci		cmd = FS_IOC_GETVERSION;
374562306a36Sopenharmony_ci		break;
374662306a36Sopenharmony_ci	case FS_IOC32_SETVERSION:
374762306a36Sopenharmony_ci		cmd = FS_IOC_SETVERSION;
374862306a36Sopenharmony_ci		break;
374962306a36Sopenharmony_ci	default:
375062306a36Sopenharmony_ci		break;
375162306a36Sopenharmony_ci	}
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci	return selinux_file_ioctl(file, cmd, arg);
375462306a36Sopenharmony_ci}
375562306a36Sopenharmony_ci
375662306a36Sopenharmony_cistatic int default_noexec __ro_after_init;
375762306a36Sopenharmony_ci
375862306a36Sopenharmony_cistatic int file_map_prot_check(struct file *file, unsigned long prot, int shared)
375962306a36Sopenharmony_ci{
376062306a36Sopenharmony_ci	const struct cred *cred = current_cred();
376162306a36Sopenharmony_ci	u32 sid = cred_sid(cred);
376262306a36Sopenharmony_ci	int rc = 0;
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci	if (default_noexec &&
376562306a36Sopenharmony_ci	    (prot & PROT_EXEC) && (!file || IS_PRIVATE(file_inode(file)) ||
376662306a36Sopenharmony_ci				   (!shared && (prot & PROT_WRITE)))) {
376762306a36Sopenharmony_ci		/*
376862306a36Sopenharmony_ci		 * We are making executable an anonymous mapping or a
376962306a36Sopenharmony_ci		 * private file mapping that will also be writable.
377062306a36Sopenharmony_ci		 * This has an additional check.
377162306a36Sopenharmony_ci		 */
377262306a36Sopenharmony_ci		rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
377362306a36Sopenharmony_ci				  PROCESS__EXECMEM, NULL);
377462306a36Sopenharmony_ci		if (rc)
377562306a36Sopenharmony_ci			goto error;
377662306a36Sopenharmony_ci	}
377762306a36Sopenharmony_ci
377862306a36Sopenharmony_ci	if (file) {
377962306a36Sopenharmony_ci		/* read access is always possible with a mapping */
378062306a36Sopenharmony_ci		u32 av = FILE__READ;
378162306a36Sopenharmony_ci
378262306a36Sopenharmony_ci		/* write access only matters if the mapping is shared */
378362306a36Sopenharmony_ci		if (shared && (prot & PROT_WRITE))
378462306a36Sopenharmony_ci			av |= FILE__WRITE;
378562306a36Sopenharmony_ci
378662306a36Sopenharmony_ci		if (prot & PROT_EXEC)
378762306a36Sopenharmony_ci			av |= FILE__EXECUTE;
378862306a36Sopenharmony_ci
378962306a36Sopenharmony_ci		return file_has_perm(cred, file, av);
379062306a36Sopenharmony_ci	}
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_cierror:
379362306a36Sopenharmony_ci	return rc;
379462306a36Sopenharmony_ci}
379562306a36Sopenharmony_ci
379662306a36Sopenharmony_cistatic int selinux_mmap_addr(unsigned long addr)
379762306a36Sopenharmony_ci{
379862306a36Sopenharmony_ci	int rc = 0;
379962306a36Sopenharmony_ci
380062306a36Sopenharmony_ci	if (addr < CONFIG_LSM_MMAP_MIN_ADDR) {
380162306a36Sopenharmony_ci		u32 sid = current_sid();
380262306a36Sopenharmony_ci		rc = avc_has_perm(sid, sid, SECCLASS_MEMPROTECT,
380362306a36Sopenharmony_ci				  MEMPROTECT__MMAP_ZERO, NULL);
380462306a36Sopenharmony_ci	}
380562306a36Sopenharmony_ci
380662306a36Sopenharmony_ci	return rc;
380762306a36Sopenharmony_ci}
380862306a36Sopenharmony_ci
380962306a36Sopenharmony_cistatic int selinux_mmap_file(struct file *file,
381062306a36Sopenharmony_ci			     unsigned long reqprot __always_unused,
381162306a36Sopenharmony_ci			     unsigned long prot, unsigned long flags)
381262306a36Sopenharmony_ci{
381362306a36Sopenharmony_ci	struct common_audit_data ad;
381462306a36Sopenharmony_ci	int rc;
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_ci	if (file) {
381762306a36Sopenharmony_ci		ad.type = LSM_AUDIT_DATA_FILE;
381862306a36Sopenharmony_ci		ad.u.file = file;
381962306a36Sopenharmony_ci		rc = inode_has_perm(current_cred(), file_inode(file),
382062306a36Sopenharmony_ci				    FILE__MAP, &ad);
382162306a36Sopenharmony_ci		if (rc)
382262306a36Sopenharmony_ci			return rc;
382362306a36Sopenharmony_ci	}
382462306a36Sopenharmony_ci
382562306a36Sopenharmony_ci	return file_map_prot_check(file, prot,
382662306a36Sopenharmony_ci				   (flags & MAP_TYPE) == MAP_SHARED);
382762306a36Sopenharmony_ci}
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_cistatic int selinux_file_mprotect(struct vm_area_struct *vma,
383062306a36Sopenharmony_ci				 unsigned long reqprot __always_unused,
383162306a36Sopenharmony_ci				 unsigned long prot)
383262306a36Sopenharmony_ci{
383362306a36Sopenharmony_ci	const struct cred *cred = current_cred();
383462306a36Sopenharmony_ci	u32 sid = cred_sid(cred);
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_ci	if (default_noexec &&
383762306a36Sopenharmony_ci	    (prot & PROT_EXEC) && !(vma->vm_flags & VM_EXEC)) {
383862306a36Sopenharmony_ci		int rc = 0;
383962306a36Sopenharmony_ci		if (vma_is_initial_heap(vma)) {
384062306a36Sopenharmony_ci			rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
384162306a36Sopenharmony_ci					  PROCESS__EXECHEAP, NULL);
384262306a36Sopenharmony_ci		} else if (!vma->vm_file && (vma_is_initial_stack(vma) ||
384362306a36Sopenharmony_ci			    vma_is_stack_for_current(vma))) {
384462306a36Sopenharmony_ci			rc = avc_has_perm(sid, sid, SECCLASS_PROCESS,
384562306a36Sopenharmony_ci					  PROCESS__EXECSTACK, NULL);
384662306a36Sopenharmony_ci		} else if (vma->vm_file && vma->anon_vma) {
384762306a36Sopenharmony_ci			/*
384862306a36Sopenharmony_ci			 * We are making executable a file mapping that has
384962306a36Sopenharmony_ci			 * had some COW done. Since pages might have been
385062306a36Sopenharmony_ci			 * written, check ability to execute the possibly
385162306a36Sopenharmony_ci			 * modified content.  This typically should only
385262306a36Sopenharmony_ci			 * occur for text relocations.
385362306a36Sopenharmony_ci			 */
385462306a36Sopenharmony_ci			rc = file_has_perm(cred, vma->vm_file, FILE__EXECMOD);
385562306a36Sopenharmony_ci		}
385662306a36Sopenharmony_ci		if (rc)
385762306a36Sopenharmony_ci			return rc;
385862306a36Sopenharmony_ci	}
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci	return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
386162306a36Sopenharmony_ci}
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_cistatic int selinux_file_lock(struct file *file, unsigned int cmd)
386462306a36Sopenharmony_ci{
386562306a36Sopenharmony_ci	const struct cred *cred = current_cred();
386662306a36Sopenharmony_ci
386762306a36Sopenharmony_ci	return file_has_perm(cred, file, FILE__LOCK);
386862306a36Sopenharmony_ci}
386962306a36Sopenharmony_ci
387062306a36Sopenharmony_cistatic int selinux_file_fcntl(struct file *file, unsigned int cmd,
387162306a36Sopenharmony_ci			      unsigned long arg)
387262306a36Sopenharmony_ci{
387362306a36Sopenharmony_ci	const struct cred *cred = current_cred();
387462306a36Sopenharmony_ci	int err = 0;
387562306a36Sopenharmony_ci
387662306a36Sopenharmony_ci	switch (cmd) {
387762306a36Sopenharmony_ci	case F_SETFL:
387862306a36Sopenharmony_ci		if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
387962306a36Sopenharmony_ci			err = file_has_perm(cred, file, FILE__WRITE);
388062306a36Sopenharmony_ci			break;
388162306a36Sopenharmony_ci		}
388262306a36Sopenharmony_ci		fallthrough;
388362306a36Sopenharmony_ci	case F_SETOWN:
388462306a36Sopenharmony_ci	case F_SETSIG:
388562306a36Sopenharmony_ci	case F_GETFL:
388662306a36Sopenharmony_ci	case F_GETOWN:
388762306a36Sopenharmony_ci	case F_GETSIG:
388862306a36Sopenharmony_ci	case F_GETOWNER_UIDS:
388962306a36Sopenharmony_ci		/* Just check FD__USE permission */
389062306a36Sopenharmony_ci		err = file_has_perm(cred, file, 0);
389162306a36Sopenharmony_ci		break;
389262306a36Sopenharmony_ci	case F_GETLK:
389362306a36Sopenharmony_ci	case F_SETLK:
389462306a36Sopenharmony_ci	case F_SETLKW:
389562306a36Sopenharmony_ci	case F_OFD_GETLK:
389662306a36Sopenharmony_ci	case F_OFD_SETLK:
389762306a36Sopenharmony_ci	case F_OFD_SETLKW:
389862306a36Sopenharmony_ci#if BITS_PER_LONG == 32
389962306a36Sopenharmony_ci	case F_GETLK64:
390062306a36Sopenharmony_ci	case F_SETLK64:
390162306a36Sopenharmony_ci	case F_SETLKW64:
390262306a36Sopenharmony_ci#endif
390362306a36Sopenharmony_ci		err = file_has_perm(cred, file, FILE__LOCK);
390462306a36Sopenharmony_ci		break;
390562306a36Sopenharmony_ci	}
390662306a36Sopenharmony_ci
390762306a36Sopenharmony_ci	return err;
390862306a36Sopenharmony_ci}
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_cistatic void selinux_file_set_fowner(struct file *file)
391162306a36Sopenharmony_ci{
391262306a36Sopenharmony_ci	struct file_security_struct *fsec;
391362306a36Sopenharmony_ci
391462306a36Sopenharmony_ci	fsec = selinux_file(file);
391562306a36Sopenharmony_ci	fsec->fown_sid = current_sid();
391662306a36Sopenharmony_ci}
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_cistatic int selinux_file_send_sigiotask(struct task_struct *tsk,
391962306a36Sopenharmony_ci				       struct fown_struct *fown, int signum)
392062306a36Sopenharmony_ci{
392162306a36Sopenharmony_ci	struct file *file;
392262306a36Sopenharmony_ci	u32 sid = task_sid_obj(tsk);
392362306a36Sopenharmony_ci	u32 perm;
392462306a36Sopenharmony_ci	struct file_security_struct *fsec;
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci	/* struct fown_struct is never outside the context of a struct file */
392762306a36Sopenharmony_ci	file = container_of(fown, struct file, f_owner);
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_ci	fsec = selinux_file(file);
393062306a36Sopenharmony_ci
393162306a36Sopenharmony_ci	if (!signum)
393262306a36Sopenharmony_ci		perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
393362306a36Sopenharmony_ci	else
393462306a36Sopenharmony_ci		perm = signal_to_av(signum);
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	return avc_has_perm(fsec->fown_sid, sid,
393762306a36Sopenharmony_ci			    SECCLASS_PROCESS, perm, NULL);
393862306a36Sopenharmony_ci}
393962306a36Sopenharmony_ci
394062306a36Sopenharmony_cistatic int selinux_file_receive(struct file *file)
394162306a36Sopenharmony_ci{
394262306a36Sopenharmony_ci	const struct cred *cred = current_cred();
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	return file_has_perm(cred, file, file_to_av(file));
394562306a36Sopenharmony_ci}
394662306a36Sopenharmony_ci
394762306a36Sopenharmony_cistatic int selinux_file_open(struct file *file)
394862306a36Sopenharmony_ci{
394962306a36Sopenharmony_ci	struct file_security_struct *fsec;
395062306a36Sopenharmony_ci	struct inode_security_struct *isec;
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_ci	fsec = selinux_file(file);
395362306a36Sopenharmony_ci	isec = inode_security(file_inode(file));
395462306a36Sopenharmony_ci	/*
395562306a36Sopenharmony_ci	 * Save inode label and policy sequence number
395662306a36Sopenharmony_ci	 * at open-time so that selinux_file_permission
395762306a36Sopenharmony_ci	 * can determine whether revalidation is necessary.
395862306a36Sopenharmony_ci	 * Task label is already saved in the file security
395962306a36Sopenharmony_ci	 * struct as its SID.
396062306a36Sopenharmony_ci	 */
396162306a36Sopenharmony_ci	fsec->isid = isec->sid;
396262306a36Sopenharmony_ci	fsec->pseqno = avc_policy_seqno();
396362306a36Sopenharmony_ci	/*
396462306a36Sopenharmony_ci	 * Since the inode label or policy seqno may have changed
396562306a36Sopenharmony_ci	 * between the selinux_inode_permission check and the saving
396662306a36Sopenharmony_ci	 * of state above, recheck that access is still permitted.
396762306a36Sopenharmony_ci	 * Otherwise, access might never be revalidated against the
396862306a36Sopenharmony_ci	 * new inode label or new policy.
396962306a36Sopenharmony_ci	 * This check is not redundant - do not remove.
397062306a36Sopenharmony_ci	 */
397162306a36Sopenharmony_ci	return file_path_has_perm(file->f_cred, file, open_file_to_av(file));
397262306a36Sopenharmony_ci}
397362306a36Sopenharmony_ci
397462306a36Sopenharmony_ci/* task security operations */
397562306a36Sopenharmony_ci
397662306a36Sopenharmony_cistatic int selinux_task_alloc(struct task_struct *task,
397762306a36Sopenharmony_ci			      unsigned long clone_flags)
397862306a36Sopenharmony_ci{
397962306a36Sopenharmony_ci	u32 sid = current_sid();
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_ci	return avc_has_perm(sid, sid, SECCLASS_PROCESS, PROCESS__FORK, NULL);
398262306a36Sopenharmony_ci}
398362306a36Sopenharmony_ci
398462306a36Sopenharmony_ci/*
398562306a36Sopenharmony_ci * prepare a new set of credentials for modification
398662306a36Sopenharmony_ci */
398762306a36Sopenharmony_cistatic int selinux_cred_prepare(struct cred *new, const struct cred *old,
398862306a36Sopenharmony_ci				gfp_t gfp)
398962306a36Sopenharmony_ci{
399062306a36Sopenharmony_ci	const struct task_security_struct *old_tsec = selinux_cred(old);
399162306a36Sopenharmony_ci	struct task_security_struct *tsec = selinux_cred(new);
399262306a36Sopenharmony_ci
399362306a36Sopenharmony_ci	*tsec = *old_tsec;
399462306a36Sopenharmony_ci	return 0;
399562306a36Sopenharmony_ci}
399662306a36Sopenharmony_ci
399762306a36Sopenharmony_ci/*
399862306a36Sopenharmony_ci * transfer the SELinux data to a blank set of creds
399962306a36Sopenharmony_ci */
400062306a36Sopenharmony_cistatic void selinux_cred_transfer(struct cred *new, const struct cred *old)
400162306a36Sopenharmony_ci{
400262306a36Sopenharmony_ci	const struct task_security_struct *old_tsec = selinux_cred(old);
400362306a36Sopenharmony_ci	struct task_security_struct *tsec = selinux_cred(new);
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_ci	*tsec = *old_tsec;
400662306a36Sopenharmony_ci}
400762306a36Sopenharmony_ci
400862306a36Sopenharmony_cistatic void selinux_cred_getsecid(const struct cred *c, u32 *secid)
400962306a36Sopenharmony_ci{
401062306a36Sopenharmony_ci	*secid = cred_sid(c);
401162306a36Sopenharmony_ci}
401262306a36Sopenharmony_ci
401362306a36Sopenharmony_ci/*
401462306a36Sopenharmony_ci * set the security data for a kernel service
401562306a36Sopenharmony_ci * - all the creation contexts are set to unlabelled
401662306a36Sopenharmony_ci */
401762306a36Sopenharmony_cistatic int selinux_kernel_act_as(struct cred *new, u32 secid)
401862306a36Sopenharmony_ci{
401962306a36Sopenharmony_ci	struct task_security_struct *tsec = selinux_cred(new);
402062306a36Sopenharmony_ci	u32 sid = current_sid();
402162306a36Sopenharmony_ci	int ret;
402262306a36Sopenharmony_ci
402362306a36Sopenharmony_ci	ret = avc_has_perm(sid, secid,
402462306a36Sopenharmony_ci			   SECCLASS_KERNEL_SERVICE,
402562306a36Sopenharmony_ci			   KERNEL_SERVICE__USE_AS_OVERRIDE,
402662306a36Sopenharmony_ci			   NULL);
402762306a36Sopenharmony_ci	if (ret == 0) {
402862306a36Sopenharmony_ci		tsec->sid = secid;
402962306a36Sopenharmony_ci		tsec->create_sid = 0;
403062306a36Sopenharmony_ci		tsec->keycreate_sid = 0;
403162306a36Sopenharmony_ci		tsec->sockcreate_sid = 0;
403262306a36Sopenharmony_ci	}
403362306a36Sopenharmony_ci	return ret;
403462306a36Sopenharmony_ci}
403562306a36Sopenharmony_ci
403662306a36Sopenharmony_ci/*
403762306a36Sopenharmony_ci * set the file creation context in a security record to the same as the
403862306a36Sopenharmony_ci * objective context of the specified inode
403962306a36Sopenharmony_ci */
404062306a36Sopenharmony_cistatic int selinux_kernel_create_files_as(struct cred *new, struct inode *inode)
404162306a36Sopenharmony_ci{
404262306a36Sopenharmony_ci	struct inode_security_struct *isec = inode_security(inode);
404362306a36Sopenharmony_ci	struct task_security_struct *tsec = selinux_cred(new);
404462306a36Sopenharmony_ci	u32 sid = current_sid();
404562306a36Sopenharmony_ci	int ret;
404662306a36Sopenharmony_ci
404762306a36Sopenharmony_ci	ret = avc_has_perm(sid, isec->sid,
404862306a36Sopenharmony_ci			   SECCLASS_KERNEL_SERVICE,
404962306a36Sopenharmony_ci			   KERNEL_SERVICE__CREATE_FILES_AS,
405062306a36Sopenharmony_ci			   NULL);
405162306a36Sopenharmony_ci
405262306a36Sopenharmony_ci	if (ret == 0)
405362306a36Sopenharmony_ci		tsec->create_sid = isec->sid;
405462306a36Sopenharmony_ci	return ret;
405562306a36Sopenharmony_ci}
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_cistatic int selinux_kernel_module_request(char *kmod_name)
405862306a36Sopenharmony_ci{
405962306a36Sopenharmony_ci	struct common_audit_data ad;
406062306a36Sopenharmony_ci
406162306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_KMOD;
406262306a36Sopenharmony_ci	ad.u.kmod_name = kmod_name;
406362306a36Sopenharmony_ci
406462306a36Sopenharmony_ci	return avc_has_perm(current_sid(), SECINITSID_KERNEL, SECCLASS_SYSTEM,
406562306a36Sopenharmony_ci			    SYSTEM__MODULE_REQUEST, &ad);
406662306a36Sopenharmony_ci}
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_cistatic int selinux_kernel_module_from_file(struct file *file)
406962306a36Sopenharmony_ci{
407062306a36Sopenharmony_ci	struct common_audit_data ad;
407162306a36Sopenharmony_ci	struct inode_security_struct *isec;
407262306a36Sopenharmony_ci	struct file_security_struct *fsec;
407362306a36Sopenharmony_ci	u32 sid = current_sid();
407462306a36Sopenharmony_ci	int rc;
407562306a36Sopenharmony_ci
407662306a36Sopenharmony_ci	/* init_module */
407762306a36Sopenharmony_ci	if (file == NULL)
407862306a36Sopenharmony_ci		return avc_has_perm(sid, sid, SECCLASS_SYSTEM,
407962306a36Sopenharmony_ci					SYSTEM__MODULE_LOAD, NULL);
408062306a36Sopenharmony_ci
408162306a36Sopenharmony_ci	/* finit_module */
408262306a36Sopenharmony_ci
408362306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_FILE;
408462306a36Sopenharmony_ci	ad.u.file = file;
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_ci	fsec = selinux_file(file);
408762306a36Sopenharmony_ci	if (sid != fsec->sid) {
408862306a36Sopenharmony_ci		rc = avc_has_perm(sid, fsec->sid, SECCLASS_FD, FD__USE, &ad);
408962306a36Sopenharmony_ci		if (rc)
409062306a36Sopenharmony_ci			return rc;
409162306a36Sopenharmony_ci	}
409262306a36Sopenharmony_ci
409362306a36Sopenharmony_ci	isec = inode_security(file_inode(file));
409462306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, SECCLASS_SYSTEM,
409562306a36Sopenharmony_ci				SYSTEM__MODULE_LOAD, &ad);
409662306a36Sopenharmony_ci}
409762306a36Sopenharmony_ci
409862306a36Sopenharmony_cistatic int selinux_kernel_read_file(struct file *file,
409962306a36Sopenharmony_ci				    enum kernel_read_file_id id,
410062306a36Sopenharmony_ci				    bool contents)
410162306a36Sopenharmony_ci{
410262306a36Sopenharmony_ci	int rc = 0;
410362306a36Sopenharmony_ci
410462306a36Sopenharmony_ci	switch (id) {
410562306a36Sopenharmony_ci	case READING_MODULE:
410662306a36Sopenharmony_ci		rc = selinux_kernel_module_from_file(contents ? file : NULL);
410762306a36Sopenharmony_ci		break;
410862306a36Sopenharmony_ci	default:
410962306a36Sopenharmony_ci		break;
411062306a36Sopenharmony_ci	}
411162306a36Sopenharmony_ci
411262306a36Sopenharmony_ci	return rc;
411362306a36Sopenharmony_ci}
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_cistatic int selinux_kernel_load_data(enum kernel_load_data_id id, bool contents)
411662306a36Sopenharmony_ci{
411762306a36Sopenharmony_ci	int rc = 0;
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci	switch (id) {
412062306a36Sopenharmony_ci	case LOADING_MODULE:
412162306a36Sopenharmony_ci		rc = selinux_kernel_module_from_file(NULL);
412262306a36Sopenharmony_ci		break;
412362306a36Sopenharmony_ci	default:
412462306a36Sopenharmony_ci		break;
412562306a36Sopenharmony_ci	}
412662306a36Sopenharmony_ci
412762306a36Sopenharmony_ci	return rc;
412862306a36Sopenharmony_ci}
412962306a36Sopenharmony_ci
413062306a36Sopenharmony_cistatic int selinux_task_setpgid(struct task_struct *p, pid_t pgid)
413162306a36Sopenharmony_ci{
413262306a36Sopenharmony_ci	return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
413362306a36Sopenharmony_ci			    PROCESS__SETPGID, NULL);
413462306a36Sopenharmony_ci}
413562306a36Sopenharmony_ci
413662306a36Sopenharmony_cistatic int selinux_task_getpgid(struct task_struct *p)
413762306a36Sopenharmony_ci{
413862306a36Sopenharmony_ci	return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
413962306a36Sopenharmony_ci			    PROCESS__GETPGID, NULL);
414062306a36Sopenharmony_ci}
414162306a36Sopenharmony_ci
414262306a36Sopenharmony_cistatic int selinux_task_getsid(struct task_struct *p)
414362306a36Sopenharmony_ci{
414462306a36Sopenharmony_ci	return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
414562306a36Sopenharmony_ci			    PROCESS__GETSESSION, NULL);
414662306a36Sopenharmony_ci}
414762306a36Sopenharmony_ci
414862306a36Sopenharmony_cistatic void selinux_current_getsecid_subj(u32 *secid)
414962306a36Sopenharmony_ci{
415062306a36Sopenharmony_ci	*secid = current_sid();
415162306a36Sopenharmony_ci}
415262306a36Sopenharmony_ci
415362306a36Sopenharmony_cistatic void selinux_task_getsecid_obj(struct task_struct *p, u32 *secid)
415462306a36Sopenharmony_ci{
415562306a36Sopenharmony_ci	*secid = task_sid_obj(p);
415662306a36Sopenharmony_ci}
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_cistatic int selinux_task_setnice(struct task_struct *p, int nice)
415962306a36Sopenharmony_ci{
416062306a36Sopenharmony_ci	return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
416162306a36Sopenharmony_ci			    PROCESS__SETSCHED, NULL);
416262306a36Sopenharmony_ci}
416362306a36Sopenharmony_ci
416462306a36Sopenharmony_cistatic int selinux_task_setioprio(struct task_struct *p, int ioprio)
416562306a36Sopenharmony_ci{
416662306a36Sopenharmony_ci	return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
416762306a36Sopenharmony_ci			    PROCESS__SETSCHED, NULL);
416862306a36Sopenharmony_ci}
416962306a36Sopenharmony_ci
417062306a36Sopenharmony_cistatic int selinux_task_getioprio(struct task_struct *p)
417162306a36Sopenharmony_ci{
417262306a36Sopenharmony_ci	return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
417362306a36Sopenharmony_ci			    PROCESS__GETSCHED, NULL);
417462306a36Sopenharmony_ci}
417562306a36Sopenharmony_ci
417662306a36Sopenharmony_cistatic int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred,
417762306a36Sopenharmony_ci				unsigned int flags)
417862306a36Sopenharmony_ci{
417962306a36Sopenharmony_ci	u32 av = 0;
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci	if (!flags)
418262306a36Sopenharmony_ci		return 0;
418362306a36Sopenharmony_ci	if (flags & LSM_PRLIMIT_WRITE)
418462306a36Sopenharmony_ci		av |= PROCESS__SETRLIMIT;
418562306a36Sopenharmony_ci	if (flags & LSM_PRLIMIT_READ)
418662306a36Sopenharmony_ci		av |= PROCESS__GETRLIMIT;
418762306a36Sopenharmony_ci	return avc_has_perm(cred_sid(cred), cred_sid(tcred),
418862306a36Sopenharmony_ci			    SECCLASS_PROCESS, av, NULL);
418962306a36Sopenharmony_ci}
419062306a36Sopenharmony_ci
419162306a36Sopenharmony_cistatic int selinux_task_setrlimit(struct task_struct *p, unsigned int resource,
419262306a36Sopenharmony_ci		struct rlimit *new_rlim)
419362306a36Sopenharmony_ci{
419462306a36Sopenharmony_ci	struct rlimit *old_rlim = p->signal->rlim + resource;
419562306a36Sopenharmony_ci
419662306a36Sopenharmony_ci	/* Control the ability to change the hard limit (whether
419762306a36Sopenharmony_ci	   lowering or raising it), so that the hard limit can
419862306a36Sopenharmony_ci	   later be used as a safe reset point for the soft limit
419962306a36Sopenharmony_ci	   upon context transitions.  See selinux_bprm_committing_creds. */
420062306a36Sopenharmony_ci	if (old_rlim->rlim_max != new_rlim->rlim_max)
420162306a36Sopenharmony_ci		return avc_has_perm(current_sid(), task_sid_obj(p),
420262306a36Sopenharmony_ci				    SECCLASS_PROCESS, PROCESS__SETRLIMIT, NULL);
420362306a36Sopenharmony_ci
420462306a36Sopenharmony_ci	return 0;
420562306a36Sopenharmony_ci}
420662306a36Sopenharmony_ci
420762306a36Sopenharmony_cistatic int selinux_task_setscheduler(struct task_struct *p)
420862306a36Sopenharmony_ci{
420962306a36Sopenharmony_ci	return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
421062306a36Sopenharmony_ci			    PROCESS__SETSCHED, NULL);
421162306a36Sopenharmony_ci}
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_cistatic int selinux_task_getscheduler(struct task_struct *p)
421462306a36Sopenharmony_ci{
421562306a36Sopenharmony_ci	return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
421662306a36Sopenharmony_ci			    PROCESS__GETSCHED, NULL);
421762306a36Sopenharmony_ci}
421862306a36Sopenharmony_ci
421962306a36Sopenharmony_cistatic int selinux_task_movememory(struct task_struct *p)
422062306a36Sopenharmony_ci{
422162306a36Sopenharmony_ci	return avc_has_perm(current_sid(), task_sid_obj(p), SECCLASS_PROCESS,
422262306a36Sopenharmony_ci			    PROCESS__SETSCHED, NULL);
422362306a36Sopenharmony_ci}
422462306a36Sopenharmony_ci
422562306a36Sopenharmony_cistatic int selinux_task_kill(struct task_struct *p, struct kernel_siginfo *info,
422662306a36Sopenharmony_ci				int sig, const struct cred *cred)
422762306a36Sopenharmony_ci{
422862306a36Sopenharmony_ci	u32 secid;
422962306a36Sopenharmony_ci	u32 perm;
423062306a36Sopenharmony_ci
423162306a36Sopenharmony_ci	if (!sig)
423262306a36Sopenharmony_ci		perm = PROCESS__SIGNULL; /* null signal; existence test */
423362306a36Sopenharmony_ci	else
423462306a36Sopenharmony_ci		perm = signal_to_av(sig);
423562306a36Sopenharmony_ci	if (!cred)
423662306a36Sopenharmony_ci		secid = current_sid();
423762306a36Sopenharmony_ci	else
423862306a36Sopenharmony_ci		secid = cred_sid(cred);
423962306a36Sopenharmony_ci	return avc_has_perm(secid, task_sid_obj(p), SECCLASS_PROCESS, perm, NULL);
424062306a36Sopenharmony_ci}
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_cistatic void selinux_task_to_inode(struct task_struct *p,
424362306a36Sopenharmony_ci				  struct inode *inode)
424462306a36Sopenharmony_ci{
424562306a36Sopenharmony_ci	struct inode_security_struct *isec = selinux_inode(inode);
424662306a36Sopenharmony_ci	u32 sid = task_sid_obj(p);
424762306a36Sopenharmony_ci
424862306a36Sopenharmony_ci	spin_lock(&isec->lock);
424962306a36Sopenharmony_ci	isec->sclass = inode_mode_to_security_class(inode->i_mode);
425062306a36Sopenharmony_ci	isec->sid = sid;
425162306a36Sopenharmony_ci	isec->initialized = LABEL_INITIALIZED;
425262306a36Sopenharmony_ci	spin_unlock(&isec->lock);
425362306a36Sopenharmony_ci}
425462306a36Sopenharmony_ci
425562306a36Sopenharmony_cistatic int selinux_userns_create(const struct cred *cred)
425662306a36Sopenharmony_ci{
425762306a36Sopenharmony_ci	u32 sid = current_sid();
425862306a36Sopenharmony_ci
425962306a36Sopenharmony_ci	return avc_has_perm(sid, sid, SECCLASS_USER_NAMESPACE,
426062306a36Sopenharmony_ci			USER_NAMESPACE__CREATE, NULL);
426162306a36Sopenharmony_ci}
426262306a36Sopenharmony_ci
426362306a36Sopenharmony_ci/* Returns error only if unable to parse addresses */
426462306a36Sopenharmony_cistatic int selinux_parse_skb_ipv4(struct sk_buff *skb,
426562306a36Sopenharmony_ci			struct common_audit_data *ad, u8 *proto)
426662306a36Sopenharmony_ci{
426762306a36Sopenharmony_ci	int offset, ihlen, ret = -EINVAL;
426862306a36Sopenharmony_ci	struct iphdr _iph, *ih;
426962306a36Sopenharmony_ci
427062306a36Sopenharmony_ci	offset = skb_network_offset(skb);
427162306a36Sopenharmony_ci	ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
427262306a36Sopenharmony_ci	if (ih == NULL)
427362306a36Sopenharmony_ci		goto out;
427462306a36Sopenharmony_ci
427562306a36Sopenharmony_ci	ihlen = ih->ihl * 4;
427662306a36Sopenharmony_ci	if (ihlen < sizeof(_iph))
427762306a36Sopenharmony_ci		goto out;
427862306a36Sopenharmony_ci
427962306a36Sopenharmony_ci	ad->u.net->v4info.saddr = ih->saddr;
428062306a36Sopenharmony_ci	ad->u.net->v4info.daddr = ih->daddr;
428162306a36Sopenharmony_ci	ret = 0;
428262306a36Sopenharmony_ci
428362306a36Sopenharmony_ci	if (proto)
428462306a36Sopenharmony_ci		*proto = ih->protocol;
428562306a36Sopenharmony_ci
428662306a36Sopenharmony_ci	switch (ih->protocol) {
428762306a36Sopenharmony_ci	case IPPROTO_TCP: {
428862306a36Sopenharmony_ci		struct tcphdr _tcph, *th;
428962306a36Sopenharmony_ci
429062306a36Sopenharmony_ci		if (ntohs(ih->frag_off) & IP_OFFSET)
429162306a36Sopenharmony_ci			break;
429262306a36Sopenharmony_ci
429362306a36Sopenharmony_ci		offset += ihlen;
429462306a36Sopenharmony_ci		th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
429562306a36Sopenharmony_ci		if (th == NULL)
429662306a36Sopenharmony_ci			break;
429762306a36Sopenharmony_ci
429862306a36Sopenharmony_ci		ad->u.net->sport = th->source;
429962306a36Sopenharmony_ci		ad->u.net->dport = th->dest;
430062306a36Sopenharmony_ci		break;
430162306a36Sopenharmony_ci	}
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_ci	case IPPROTO_UDP: {
430462306a36Sopenharmony_ci		struct udphdr _udph, *uh;
430562306a36Sopenharmony_ci
430662306a36Sopenharmony_ci		if (ntohs(ih->frag_off) & IP_OFFSET)
430762306a36Sopenharmony_ci			break;
430862306a36Sopenharmony_ci
430962306a36Sopenharmony_ci		offset += ihlen;
431062306a36Sopenharmony_ci		uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
431162306a36Sopenharmony_ci		if (uh == NULL)
431262306a36Sopenharmony_ci			break;
431362306a36Sopenharmony_ci
431462306a36Sopenharmony_ci		ad->u.net->sport = uh->source;
431562306a36Sopenharmony_ci		ad->u.net->dport = uh->dest;
431662306a36Sopenharmony_ci		break;
431762306a36Sopenharmony_ci	}
431862306a36Sopenharmony_ci
431962306a36Sopenharmony_ci	case IPPROTO_DCCP: {
432062306a36Sopenharmony_ci		struct dccp_hdr _dccph, *dh;
432162306a36Sopenharmony_ci
432262306a36Sopenharmony_ci		if (ntohs(ih->frag_off) & IP_OFFSET)
432362306a36Sopenharmony_ci			break;
432462306a36Sopenharmony_ci
432562306a36Sopenharmony_ci		offset += ihlen;
432662306a36Sopenharmony_ci		dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
432762306a36Sopenharmony_ci		if (dh == NULL)
432862306a36Sopenharmony_ci			break;
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_ci		ad->u.net->sport = dh->dccph_sport;
433162306a36Sopenharmony_ci		ad->u.net->dport = dh->dccph_dport;
433262306a36Sopenharmony_ci		break;
433362306a36Sopenharmony_ci	}
433462306a36Sopenharmony_ci
433562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IP_SCTP)
433662306a36Sopenharmony_ci	case IPPROTO_SCTP: {
433762306a36Sopenharmony_ci		struct sctphdr _sctph, *sh;
433862306a36Sopenharmony_ci
433962306a36Sopenharmony_ci		if (ntohs(ih->frag_off) & IP_OFFSET)
434062306a36Sopenharmony_ci			break;
434162306a36Sopenharmony_ci
434262306a36Sopenharmony_ci		offset += ihlen;
434362306a36Sopenharmony_ci		sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
434462306a36Sopenharmony_ci		if (sh == NULL)
434562306a36Sopenharmony_ci			break;
434662306a36Sopenharmony_ci
434762306a36Sopenharmony_ci		ad->u.net->sport = sh->source;
434862306a36Sopenharmony_ci		ad->u.net->dport = sh->dest;
434962306a36Sopenharmony_ci		break;
435062306a36Sopenharmony_ci	}
435162306a36Sopenharmony_ci#endif
435262306a36Sopenharmony_ci	default:
435362306a36Sopenharmony_ci		break;
435462306a36Sopenharmony_ci	}
435562306a36Sopenharmony_ciout:
435662306a36Sopenharmony_ci	return ret;
435762306a36Sopenharmony_ci}
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
436062306a36Sopenharmony_ci
436162306a36Sopenharmony_ci/* Returns error only if unable to parse addresses */
436262306a36Sopenharmony_cistatic int selinux_parse_skb_ipv6(struct sk_buff *skb,
436362306a36Sopenharmony_ci			struct common_audit_data *ad, u8 *proto)
436462306a36Sopenharmony_ci{
436562306a36Sopenharmony_ci	u8 nexthdr;
436662306a36Sopenharmony_ci	int ret = -EINVAL, offset;
436762306a36Sopenharmony_ci	struct ipv6hdr _ipv6h, *ip6;
436862306a36Sopenharmony_ci	__be16 frag_off;
436962306a36Sopenharmony_ci
437062306a36Sopenharmony_ci	offset = skb_network_offset(skb);
437162306a36Sopenharmony_ci	ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
437262306a36Sopenharmony_ci	if (ip6 == NULL)
437362306a36Sopenharmony_ci		goto out;
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci	ad->u.net->v6info.saddr = ip6->saddr;
437662306a36Sopenharmony_ci	ad->u.net->v6info.daddr = ip6->daddr;
437762306a36Sopenharmony_ci	ret = 0;
437862306a36Sopenharmony_ci
437962306a36Sopenharmony_ci	nexthdr = ip6->nexthdr;
438062306a36Sopenharmony_ci	offset += sizeof(_ipv6h);
438162306a36Sopenharmony_ci	offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off);
438262306a36Sopenharmony_ci	if (offset < 0)
438362306a36Sopenharmony_ci		goto out;
438462306a36Sopenharmony_ci
438562306a36Sopenharmony_ci	if (proto)
438662306a36Sopenharmony_ci		*proto = nexthdr;
438762306a36Sopenharmony_ci
438862306a36Sopenharmony_ci	switch (nexthdr) {
438962306a36Sopenharmony_ci	case IPPROTO_TCP: {
439062306a36Sopenharmony_ci		struct tcphdr _tcph, *th;
439162306a36Sopenharmony_ci
439262306a36Sopenharmony_ci		th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
439362306a36Sopenharmony_ci		if (th == NULL)
439462306a36Sopenharmony_ci			break;
439562306a36Sopenharmony_ci
439662306a36Sopenharmony_ci		ad->u.net->sport = th->source;
439762306a36Sopenharmony_ci		ad->u.net->dport = th->dest;
439862306a36Sopenharmony_ci		break;
439962306a36Sopenharmony_ci	}
440062306a36Sopenharmony_ci
440162306a36Sopenharmony_ci	case IPPROTO_UDP: {
440262306a36Sopenharmony_ci		struct udphdr _udph, *uh;
440362306a36Sopenharmony_ci
440462306a36Sopenharmony_ci		uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
440562306a36Sopenharmony_ci		if (uh == NULL)
440662306a36Sopenharmony_ci			break;
440762306a36Sopenharmony_ci
440862306a36Sopenharmony_ci		ad->u.net->sport = uh->source;
440962306a36Sopenharmony_ci		ad->u.net->dport = uh->dest;
441062306a36Sopenharmony_ci		break;
441162306a36Sopenharmony_ci	}
441262306a36Sopenharmony_ci
441362306a36Sopenharmony_ci	case IPPROTO_DCCP: {
441462306a36Sopenharmony_ci		struct dccp_hdr _dccph, *dh;
441562306a36Sopenharmony_ci
441662306a36Sopenharmony_ci		dh = skb_header_pointer(skb, offset, sizeof(_dccph), &_dccph);
441762306a36Sopenharmony_ci		if (dh == NULL)
441862306a36Sopenharmony_ci			break;
441962306a36Sopenharmony_ci
442062306a36Sopenharmony_ci		ad->u.net->sport = dh->dccph_sport;
442162306a36Sopenharmony_ci		ad->u.net->dport = dh->dccph_dport;
442262306a36Sopenharmony_ci		break;
442362306a36Sopenharmony_ci	}
442462306a36Sopenharmony_ci
442562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IP_SCTP)
442662306a36Sopenharmony_ci	case IPPROTO_SCTP: {
442762306a36Sopenharmony_ci		struct sctphdr _sctph, *sh;
442862306a36Sopenharmony_ci
442962306a36Sopenharmony_ci		sh = skb_header_pointer(skb, offset, sizeof(_sctph), &_sctph);
443062306a36Sopenharmony_ci		if (sh == NULL)
443162306a36Sopenharmony_ci			break;
443262306a36Sopenharmony_ci
443362306a36Sopenharmony_ci		ad->u.net->sport = sh->source;
443462306a36Sopenharmony_ci		ad->u.net->dport = sh->dest;
443562306a36Sopenharmony_ci		break;
443662306a36Sopenharmony_ci	}
443762306a36Sopenharmony_ci#endif
443862306a36Sopenharmony_ci	/* includes fragments */
443962306a36Sopenharmony_ci	default:
444062306a36Sopenharmony_ci		break;
444162306a36Sopenharmony_ci	}
444262306a36Sopenharmony_ciout:
444362306a36Sopenharmony_ci	return ret;
444462306a36Sopenharmony_ci}
444562306a36Sopenharmony_ci
444662306a36Sopenharmony_ci#endif /* IPV6 */
444762306a36Sopenharmony_ci
444862306a36Sopenharmony_cistatic int selinux_parse_skb(struct sk_buff *skb, struct common_audit_data *ad,
444962306a36Sopenharmony_ci			     char **_addrp, int src, u8 *proto)
445062306a36Sopenharmony_ci{
445162306a36Sopenharmony_ci	char *addrp;
445262306a36Sopenharmony_ci	int ret;
445362306a36Sopenharmony_ci
445462306a36Sopenharmony_ci	switch (ad->u.net->family) {
445562306a36Sopenharmony_ci	case PF_INET:
445662306a36Sopenharmony_ci		ret = selinux_parse_skb_ipv4(skb, ad, proto);
445762306a36Sopenharmony_ci		if (ret)
445862306a36Sopenharmony_ci			goto parse_error;
445962306a36Sopenharmony_ci		addrp = (char *)(src ? &ad->u.net->v4info.saddr :
446062306a36Sopenharmony_ci				       &ad->u.net->v4info.daddr);
446162306a36Sopenharmony_ci		goto okay;
446262306a36Sopenharmony_ci
446362306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
446462306a36Sopenharmony_ci	case PF_INET6:
446562306a36Sopenharmony_ci		ret = selinux_parse_skb_ipv6(skb, ad, proto);
446662306a36Sopenharmony_ci		if (ret)
446762306a36Sopenharmony_ci			goto parse_error;
446862306a36Sopenharmony_ci		addrp = (char *)(src ? &ad->u.net->v6info.saddr :
446962306a36Sopenharmony_ci				       &ad->u.net->v6info.daddr);
447062306a36Sopenharmony_ci		goto okay;
447162306a36Sopenharmony_ci#endif	/* IPV6 */
447262306a36Sopenharmony_ci	default:
447362306a36Sopenharmony_ci		addrp = NULL;
447462306a36Sopenharmony_ci		goto okay;
447562306a36Sopenharmony_ci	}
447662306a36Sopenharmony_ci
447762306a36Sopenharmony_ciparse_error:
447862306a36Sopenharmony_ci	pr_warn(
447962306a36Sopenharmony_ci	       "SELinux: failure in selinux_parse_skb(),"
448062306a36Sopenharmony_ci	       " unable to parse packet\n");
448162306a36Sopenharmony_ci	return ret;
448262306a36Sopenharmony_ci
448362306a36Sopenharmony_ciokay:
448462306a36Sopenharmony_ci	if (_addrp)
448562306a36Sopenharmony_ci		*_addrp = addrp;
448662306a36Sopenharmony_ci	return 0;
448762306a36Sopenharmony_ci}
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci/**
449062306a36Sopenharmony_ci * selinux_skb_peerlbl_sid - Determine the peer label of a packet
449162306a36Sopenharmony_ci * @skb: the packet
449262306a36Sopenharmony_ci * @family: protocol family
449362306a36Sopenharmony_ci * @sid: the packet's peer label SID
449462306a36Sopenharmony_ci *
449562306a36Sopenharmony_ci * Description:
449662306a36Sopenharmony_ci * Check the various different forms of network peer labeling and determine
449762306a36Sopenharmony_ci * the peer label/SID for the packet; most of the magic actually occurs in
449862306a36Sopenharmony_ci * the security server function security_net_peersid_cmp().  The function
449962306a36Sopenharmony_ci * returns zero if the value in @sid is valid (although it may be SECSID_NULL)
450062306a36Sopenharmony_ci * or -EACCES if @sid is invalid due to inconsistencies with the different
450162306a36Sopenharmony_ci * peer labels.
450262306a36Sopenharmony_ci *
450362306a36Sopenharmony_ci */
450462306a36Sopenharmony_cistatic int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
450562306a36Sopenharmony_ci{
450662306a36Sopenharmony_ci	int err;
450762306a36Sopenharmony_ci	u32 xfrm_sid;
450862306a36Sopenharmony_ci	u32 nlbl_sid;
450962306a36Sopenharmony_ci	u32 nlbl_type;
451062306a36Sopenharmony_ci
451162306a36Sopenharmony_ci	err = selinux_xfrm_skb_sid(skb, &xfrm_sid);
451262306a36Sopenharmony_ci	if (unlikely(err))
451362306a36Sopenharmony_ci		return -EACCES;
451462306a36Sopenharmony_ci	err = selinux_netlbl_skbuff_getsid(skb, family, &nlbl_type, &nlbl_sid);
451562306a36Sopenharmony_ci	if (unlikely(err))
451662306a36Sopenharmony_ci		return -EACCES;
451762306a36Sopenharmony_ci
451862306a36Sopenharmony_ci	err = security_net_peersid_resolve(nlbl_sid,
451962306a36Sopenharmony_ci					   nlbl_type, xfrm_sid, sid);
452062306a36Sopenharmony_ci	if (unlikely(err)) {
452162306a36Sopenharmony_ci		pr_warn(
452262306a36Sopenharmony_ci		       "SELinux: failure in selinux_skb_peerlbl_sid(),"
452362306a36Sopenharmony_ci		       " unable to determine packet's peer label\n");
452462306a36Sopenharmony_ci		return -EACCES;
452562306a36Sopenharmony_ci	}
452662306a36Sopenharmony_ci
452762306a36Sopenharmony_ci	return 0;
452862306a36Sopenharmony_ci}
452962306a36Sopenharmony_ci
453062306a36Sopenharmony_ci/**
453162306a36Sopenharmony_ci * selinux_conn_sid - Determine the child socket label for a connection
453262306a36Sopenharmony_ci * @sk_sid: the parent socket's SID
453362306a36Sopenharmony_ci * @skb_sid: the packet's SID
453462306a36Sopenharmony_ci * @conn_sid: the resulting connection SID
453562306a36Sopenharmony_ci *
453662306a36Sopenharmony_ci * If @skb_sid is valid then the user:role:type information from @sk_sid is
453762306a36Sopenharmony_ci * combined with the MLS information from @skb_sid in order to create
453862306a36Sopenharmony_ci * @conn_sid.  If @skb_sid is not valid then @conn_sid is simply a copy
453962306a36Sopenharmony_ci * of @sk_sid.  Returns zero on success, negative values on failure.
454062306a36Sopenharmony_ci *
454162306a36Sopenharmony_ci */
454262306a36Sopenharmony_cistatic int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
454362306a36Sopenharmony_ci{
454462306a36Sopenharmony_ci	int err = 0;
454562306a36Sopenharmony_ci
454662306a36Sopenharmony_ci	if (skb_sid != SECSID_NULL)
454762306a36Sopenharmony_ci		err = security_sid_mls_copy(sk_sid, skb_sid,
454862306a36Sopenharmony_ci					    conn_sid);
454962306a36Sopenharmony_ci	else
455062306a36Sopenharmony_ci		*conn_sid = sk_sid;
455162306a36Sopenharmony_ci
455262306a36Sopenharmony_ci	return err;
455362306a36Sopenharmony_ci}
455462306a36Sopenharmony_ci
455562306a36Sopenharmony_ci/* socket security operations */
455662306a36Sopenharmony_ci
455762306a36Sopenharmony_cistatic int socket_sockcreate_sid(const struct task_security_struct *tsec,
455862306a36Sopenharmony_ci				 u16 secclass, u32 *socksid)
455962306a36Sopenharmony_ci{
456062306a36Sopenharmony_ci	if (tsec->sockcreate_sid > SECSID_NULL) {
456162306a36Sopenharmony_ci		*socksid = tsec->sockcreate_sid;
456262306a36Sopenharmony_ci		return 0;
456362306a36Sopenharmony_ci	}
456462306a36Sopenharmony_ci
456562306a36Sopenharmony_ci	return security_transition_sid(tsec->sid, tsec->sid,
456662306a36Sopenharmony_ci				       secclass, NULL, socksid);
456762306a36Sopenharmony_ci}
456862306a36Sopenharmony_ci
456962306a36Sopenharmony_cistatic int sock_has_perm(struct sock *sk, u32 perms)
457062306a36Sopenharmony_ci{
457162306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
457262306a36Sopenharmony_ci	struct common_audit_data ad;
457362306a36Sopenharmony_ci	struct lsm_network_audit net;
457462306a36Sopenharmony_ci
457562306a36Sopenharmony_ci	if (sksec->sid == SECINITSID_KERNEL)
457662306a36Sopenharmony_ci		return 0;
457762306a36Sopenharmony_ci
457862306a36Sopenharmony_ci	ad_net_init_from_sk(&ad, &net, sk);
457962306a36Sopenharmony_ci
458062306a36Sopenharmony_ci	return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms,
458162306a36Sopenharmony_ci			    &ad);
458262306a36Sopenharmony_ci}
458362306a36Sopenharmony_ci
458462306a36Sopenharmony_cistatic int selinux_socket_create(int family, int type,
458562306a36Sopenharmony_ci				 int protocol, int kern)
458662306a36Sopenharmony_ci{
458762306a36Sopenharmony_ci	const struct task_security_struct *tsec = selinux_cred(current_cred());
458862306a36Sopenharmony_ci	u32 newsid;
458962306a36Sopenharmony_ci	u16 secclass;
459062306a36Sopenharmony_ci	int rc;
459162306a36Sopenharmony_ci
459262306a36Sopenharmony_ci	if (kern)
459362306a36Sopenharmony_ci		return 0;
459462306a36Sopenharmony_ci
459562306a36Sopenharmony_ci	secclass = socket_type_to_security_class(family, type, protocol);
459662306a36Sopenharmony_ci	rc = socket_sockcreate_sid(tsec, secclass, &newsid);
459762306a36Sopenharmony_ci	if (rc)
459862306a36Sopenharmony_ci		return rc;
459962306a36Sopenharmony_ci
460062306a36Sopenharmony_ci	return avc_has_perm(tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
460162306a36Sopenharmony_ci}
460262306a36Sopenharmony_ci
460362306a36Sopenharmony_cistatic int selinux_socket_post_create(struct socket *sock, int family,
460462306a36Sopenharmony_ci				      int type, int protocol, int kern)
460562306a36Sopenharmony_ci{
460662306a36Sopenharmony_ci	const struct task_security_struct *tsec = selinux_cred(current_cred());
460762306a36Sopenharmony_ci	struct inode_security_struct *isec = inode_security_novalidate(SOCK_INODE(sock));
460862306a36Sopenharmony_ci	struct sk_security_struct *sksec;
460962306a36Sopenharmony_ci	u16 sclass = socket_type_to_security_class(family, type, protocol);
461062306a36Sopenharmony_ci	u32 sid = SECINITSID_KERNEL;
461162306a36Sopenharmony_ci	int err = 0;
461262306a36Sopenharmony_ci
461362306a36Sopenharmony_ci	if (!kern) {
461462306a36Sopenharmony_ci		err = socket_sockcreate_sid(tsec, sclass, &sid);
461562306a36Sopenharmony_ci		if (err)
461662306a36Sopenharmony_ci			return err;
461762306a36Sopenharmony_ci	}
461862306a36Sopenharmony_ci
461962306a36Sopenharmony_ci	isec->sclass = sclass;
462062306a36Sopenharmony_ci	isec->sid = sid;
462162306a36Sopenharmony_ci	isec->initialized = LABEL_INITIALIZED;
462262306a36Sopenharmony_ci
462362306a36Sopenharmony_ci	if (sock->sk) {
462462306a36Sopenharmony_ci		sksec = sock->sk->sk_security;
462562306a36Sopenharmony_ci		sksec->sclass = sclass;
462662306a36Sopenharmony_ci		sksec->sid = sid;
462762306a36Sopenharmony_ci		/* Allows detection of the first association on this socket */
462862306a36Sopenharmony_ci		if (sksec->sclass == SECCLASS_SCTP_SOCKET)
462962306a36Sopenharmony_ci			sksec->sctp_assoc_state = SCTP_ASSOC_UNSET;
463062306a36Sopenharmony_ci
463162306a36Sopenharmony_ci		err = selinux_netlbl_socket_post_create(sock->sk, family);
463262306a36Sopenharmony_ci	}
463362306a36Sopenharmony_ci
463462306a36Sopenharmony_ci	return err;
463562306a36Sopenharmony_ci}
463662306a36Sopenharmony_ci
463762306a36Sopenharmony_cistatic int selinux_socket_socketpair(struct socket *socka,
463862306a36Sopenharmony_ci				     struct socket *sockb)
463962306a36Sopenharmony_ci{
464062306a36Sopenharmony_ci	struct sk_security_struct *sksec_a = socka->sk->sk_security;
464162306a36Sopenharmony_ci	struct sk_security_struct *sksec_b = sockb->sk->sk_security;
464262306a36Sopenharmony_ci
464362306a36Sopenharmony_ci	sksec_a->peer_sid = sksec_b->sid;
464462306a36Sopenharmony_ci	sksec_b->peer_sid = sksec_a->sid;
464562306a36Sopenharmony_ci
464662306a36Sopenharmony_ci	return 0;
464762306a36Sopenharmony_ci}
464862306a36Sopenharmony_ci
464962306a36Sopenharmony_ci/* Range of port numbers used to automatically bind.
465062306a36Sopenharmony_ci   Need to determine whether we should perform a name_bind
465162306a36Sopenharmony_ci   permission check between the socket and the port number. */
465262306a36Sopenharmony_ci
465362306a36Sopenharmony_cistatic int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
465462306a36Sopenharmony_ci{
465562306a36Sopenharmony_ci	struct sock *sk = sock->sk;
465662306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
465762306a36Sopenharmony_ci	u16 family;
465862306a36Sopenharmony_ci	int err;
465962306a36Sopenharmony_ci
466062306a36Sopenharmony_ci	err = sock_has_perm(sk, SOCKET__BIND);
466162306a36Sopenharmony_ci	if (err)
466262306a36Sopenharmony_ci		goto out;
466362306a36Sopenharmony_ci
466462306a36Sopenharmony_ci	/* If PF_INET or PF_INET6, check name_bind permission for the port. */
466562306a36Sopenharmony_ci	family = sk->sk_family;
466662306a36Sopenharmony_ci	if (family == PF_INET || family == PF_INET6) {
466762306a36Sopenharmony_ci		char *addrp;
466862306a36Sopenharmony_ci		struct common_audit_data ad;
466962306a36Sopenharmony_ci		struct lsm_network_audit net = {0,};
467062306a36Sopenharmony_ci		struct sockaddr_in *addr4 = NULL;
467162306a36Sopenharmony_ci		struct sockaddr_in6 *addr6 = NULL;
467262306a36Sopenharmony_ci		u16 family_sa;
467362306a36Sopenharmony_ci		unsigned short snum;
467462306a36Sopenharmony_ci		u32 sid, node_perm;
467562306a36Sopenharmony_ci
467662306a36Sopenharmony_ci		/*
467762306a36Sopenharmony_ci		 * sctp_bindx(3) calls via selinux_sctp_bind_connect()
467862306a36Sopenharmony_ci		 * that validates multiple binding addresses. Because of this
467962306a36Sopenharmony_ci		 * need to check address->sa_family as it is possible to have
468062306a36Sopenharmony_ci		 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
468162306a36Sopenharmony_ci		 */
468262306a36Sopenharmony_ci		if (addrlen < offsetofend(struct sockaddr, sa_family))
468362306a36Sopenharmony_ci			return -EINVAL;
468462306a36Sopenharmony_ci		family_sa = address->sa_family;
468562306a36Sopenharmony_ci		switch (family_sa) {
468662306a36Sopenharmony_ci		case AF_UNSPEC:
468762306a36Sopenharmony_ci		case AF_INET:
468862306a36Sopenharmony_ci			if (addrlen < sizeof(struct sockaddr_in))
468962306a36Sopenharmony_ci				return -EINVAL;
469062306a36Sopenharmony_ci			addr4 = (struct sockaddr_in *)address;
469162306a36Sopenharmony_ci			if (family_sa == AF_UNSPEC) {
469262306a36Sopenharmony_ci				if (family == PF_INET6) {
469362306a36Sopenharmony_ci					/* Length check from inet6_bind_sk() */
469462306a36Sopenharmony_ci					if (addrlen < SIN6_LEN_RFC2133)
469562306a36Sopenharmony_ci						return -EINVAL;
469662306a36Sopenharmony_ci					/* Family check from __inet6_bind() */
469762306a36Sopenharmony_ci					goto err_af;
469862306a36Sopenharmony_ci				}
469962306a36Sopenharmony_ci				/* see __inet_bind(), we only want to allow
470062306a36Sopenharmony_ci				 * AF_UNSPEC if the address is INADDR_ANY
470162306a36Sopenharmony_ci				 */
470262306a36Sopenharmony_ci				if (addr4->sin_addr.s_addr != htonl(INADDR_ANY))
470362306a36Sopenharmony_ci					goto err_af;
470462306a36Sopenharmony_ci				family_sa = AF_INET;
470562306a36Sopenharmony_ci			}
470662306a36Sopenharmony_ci			snum = ntohs(addr4->sin_port);
470762306a36Sopenharmony_ci			addrp = (char *)&addr4->sin_addr.s_addr;
470862306a36Sopenharmony_ci			break;
470962306a36Sopenharmony_ci		case AF_INET6:
471062306a36Sopenharmony_ci			if (addrlen < SIN6_LEN_RFC2133)
471162306a36Sopenharmony_ci				return -EINVAL;
471262306a36Sopenharmony_ci			addr6 = (struct sockaddr_in6 *)address;
471362306a36Sopenharmony_ci			snum = ntohs(addr6->sin6_port);
471462306a36Sopenharmony_ci			addrp = (char *)&addr6->sin6_addr.s6_addr;
471562306a36Sopenharmony_ci			break;
471662306a36Sopenharmony_ci		default:
471762306a36Sopenharmony_ci			goto err_af;
471862306a36Sopenharmony_ci		}
471962306a36Sopenharmony_ci
472062306a36Sopenharmony_ci		ad.type = LSM_AUDIT_DATA_NET;
472162306a36Sopenharmony_ci		ad.u.net = &net;
472262306a36Sopenharmony_ci		ad.u.net->sport = htons(snum);
472362306a36Sopenharmony_ci		ad.u.net->family = family_sa;
472462306a36Sopenharmony_ci
472562306a36Sopenharmony_ci		if (snum) {
472662306a36Sopenharmony_ci			int low, high;
472762306a36Sopenharmony_ci
472862306a36Sopenharmony_ci			inet_get_local_port_range(sock_net(sk), &low, &high);
472962306a36Sopenharmony_ci
473062306a36Sopenharmony_ci			if (inet_port_requires_bind_service(sock_net(sk), snum) ||
473162306a36Sopenharmony_ci			    snum < low || snum > high) {
473262306a36Sopenharmony_ci				err = sel_netport_sid(sk->sk_protocol,
473362306a36Sopenharmony_ci						      snum, &sid);
473462306a36Sopenharmony_ci				if (err)
473562306a36Sopenharmony_ci					goto out;
473662306a36Sopenharmony_ci				err = avc_has_perm(sksec->sid, sid,
473762306a36Sopenharmony_ci						   sksec->sclass,
473862306a36Sopenharmony_ci						   SOCKET__NAME_BIND, &ad);
473962306a36Sopenharmony_ci				if (err)
474062306a36Sopenharmony_ci					goto out;
474162306a36Sopenharmony_ci			}
474262306a36Sopenharmony_ci		}
474362306a36Sopenharmony_ci
474462306a36Sopenharmony_ci		switch (sksec->sclass) {
474562306a36Sopenharmony_ci		case SECCLASS_TCP_SOCKET:
474662306a36Sopenharmony_ci			node_perm = TCP_SOCKET__NODE_BIND;
474762306a36Sopenharmony_ci			break;
474862306a36Sopenharmony_ci
474962306a36Sopenharmony_ci		case SECCLASS_UDP_SOCKET:
475062306a36Sopenharmony_ci			node_perm = UDP_SOCKET__NODE_BIND;
475162306a36Sopenharmony_ci			break;
475262306a36Sopenharmony_ci
475362306a36Sopenharmony_ci		case SECCLASS_DCCP_SOCKET:
475462306a36Sopenharmony_ci			node_perm = DCCP_SOCKET__NODE_BIND;
475562306a36Sopenharmony_ci			break;
475662306a36Sopenharmony_ci
475762306a36Sopenharmony_ci		case SECCLASS_SCTP_SOCKET:
475862306a36Sopenharmony_ci			node_perm = SCTP_SOCKET__NODE_BIND;
475962306a36Sopenharmony_ci			break;
476062306a36Sopenharmony_ci
476162306a36Sopenharmony_ci		default:
476262306a36Sopenharmony_ci			node_perm = RAWIP_SOCKET__NODE_BIND;
476362306a36Sopenharmony_ci			break;
476462306a36Sopenharmony_ci		}
476562306a36Sopenharmony_ci
476662306a36Sopenharmony_ci		err = sel_netnode_sid(addrp, family_sa, &sid);
476762306a36Sopenharmony_ci		if (err)
476862306a36Sopenharmony_ci			goto out;
476962306a36Sopenharmony_ci
477062306a36Sopenharmony_ci		if (family_sa == AF_INET)
477162306a36Sopenharmony_ci			ad.u.net->v4info.saddr = addr4->sin_addr.s_addr;
477262306a36Sopenharmony_ci		else
477362306a36Sopenharmony_ci			ad.u.net->v6info.saddr = addr6->sin6_addr;
477462306a36Sopenharmony_ci
477562306a36Sopenharmony_ci		err = avc_has_perm(sksec->sid, sid,
477662306a36Sopenharmony_ci				   sksec->sclass, node_perm, &ad);
477762306a36Sopenharmony_ci		if (err)
477862306a36Sopenharmony_ci			goto out;
477962306a36Sopenharmony_ci	}
478062306a36Sopenharmony_ciout:
478162306a36Sopenharmony_ci	return err;
478262306a36Sopenharmony_cierr_af:
478362306a36Sopenharmony_ci	/* Note that SCTP services expect -EINVAL, others -EAFNOSUPPORT. */
478462306a36Sopenharmony_ci	if (sksec->sclass == SECCLASS_SCTP_SOCKET)
478562306a36Sopenharmony_ci		return -EINVAL;
478662306a36Sopenharmony_ci	return -EAFNOSUPPORT;
478762306a36Sopenharmony_ci}
478862306a36Sopenharmony_ci
478962306a36Sopenharmony_ci/* This supports connect(2) and SCTP connect services such as sctp_connectx(3)
479062306a36Sopenharmony_ci * and sctp_sendmsg(3) as described in Documentation/security/SCTP.rst
479162306a36Sopenharmony_ci */
479262306a36Sopenharmony_cistatic int selinux_socket_connect_helper(struct socket *sock,
479362306a36Sopenharmony_ci					 struct sockaddr *address, int addrlen)
479462306a36Sopenharmony_ci{
479562306a36Sopenharmony_ci	struct sock *sk = sock->sk;
479662306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
479762306a36Sopenharmony_ci	int err;
479862306a36Sopenharmony_ci
479962306a36Sopenharmony_ci	err = sock_has_perm(sk, SOCKET__CONNECT);
480062306a36Sopenharmony_ci	if (err)
480162306a36Sopenharmony_ci		return err;
480262306a36Sopenharmony_ci	if (addrlen < offsetofend(struct sockaddr, sa_family))
480362306a36Sopenharmony_ci		return -EINVAL;
480462306a36Sopenharmony_ci
480562306a36Sopenharmony_ci	/* connect(AF_UNSPEC) has special handling, as it is a documented
480662306a36Sopenharmony_ci	 * way to disconnect the socket
480762306a36Sopenharmony_ci	 */
480862306a36Sopenharmony_ci	if (address->sa_family == AF_UNSPEC)
480962306a36Sopenharmony_ci		return 0;
481062306a36Sopenharmony_ci
481162306a36Sopenharmony_ci	/*
481262306a36Sopenharmony_ci	 * If a TCP, DCCP or SCTP socket, check name_connect permission
481362306a36Sopenharmony_ci	 * for the port.
481462306a36Sopenharmony_ci	 */
481562306a36Sopenharmony_ci	if (sksec->sclass == SECCLASS_TCP_SOCKET ||
481662306a36Sopenharmony_ci	    sksec->sclass == SECCLASS_DCCP_SOCKET ||
481762306a36Sopenharmony_ci	    sksec->sclass == SECCLASS_SCTP_SOCKET) {
481862306a36Sopenharmony_ci		struct common_audit_data ad;
481962306a36Sopenharmony_ci		struct lsm_network_audit net = {0,};
482062306a36Sopenharmony_ci		struct sockaddr_in *addr4 = NULL;
482162306a36Sopenharmony_ci		struct sockaddr_in6 *addr6 = NULL;
482262306a36Sopenharmony_ci		unsigned short snum;
482362306a36Sopenharmony_ci		u32 sid, perm;
482462306a36Sopenharmony_ci
482562306a36Sopenharmony_ci		/* sctp_connectx(3) calls via selinux_sctp_bind_connect()
482662306a36Sopenharmony_ci		 * that validates multiple connect addresses. Because of this
482762306a36Sopenharmony_ci		 * need to check address->sa_family as it is possible to have
482862306a36Sopenharmony_ci		 * sk->sk_family = PF_INET6 with addr->sa_family = AF_INET.
482962306a36Sopenharmony_ci		 */
483062306a36Sopenharmony_ci		switch (address->sa_family) {
483162306a36Sopenharmony_ci		case AF_INET:
483262306a36Sopenharmony_ci			addr4 = (struct sockaddr_in *)address;
483362306a36Sopenharmony_ci			if (addrlen < sizeof(struct sockaddr_in))
483462306a36Sopenharmony_ci				return -EINVAL;
483562306a36Sopenharmony_ci			snum = ntohs(addr4->sin_port);
483662306a36Sopenharmony_ci			break;
483762306a36Sopenharmony_ci		case AF_INET6:
483862306a36Sopenharmony_ci			addr6 = (struct sockaddr_in6 *)address;
483962306a36Sopenharmony_ci			if (addrlen < SIN6_LEN_RFC2133)
484062306a36Sopenharmony_ci				return -EINVAL;
484162306a36Sopenharmony_ci			snum = ntohs(addr6->sin6_port);
484262306a36Sopenharmony_ci			break;
484362306a36Sopenharmony_ci		default:
484462306a36Sopenharmony_ci			/* Note that SCTP services expect -EINVAL, whereas
484562306a36Sopenharmony_ci			 * others expect -EAFNOSUPPORT.
484662306a36Sopenharmony_ci			 */
484762306a36Sopenharmony_ci			if (sksec->sclass == SECCLASS_SCTP_SOCKET)
484862306a36Sopenharmony_ci				return -EINVAL;
484962306a36Sopenharmony_ci			else
485062306a36Sopenharmony_ci				return -EAFNOSUPPORT;
485162306a36Sopenharmony_ci		}
485262306a36Sopenharmony_ci
485362306a36Sopenharmony_ci		err = sel_netport_sid(sk->sk_protocol, snum, &sid);
485462306a36Sopenharmony_ci		if (err)
485562306a36Sopenharmony_ci			return err;
485662306a36Sopenharmony_ci
485762306a36Sopenharmony_ci		switch (sksec->sclass) {
485862306a36Sopenharmony_ci		case SECCLASS_TCP_SOCKET:
485962306a36Sopenharmony_ci			perm = TCP_SOCKET__NAME_CONNECT;
486062306a36Sopenharmony_ci			break;
486162306a36Sopenharmony_ci		case SECCLASS_DCCP_SOCKET:
486262306a36Sopenharmony_ci			perm = DCCP_SOCKET__NAME_CONNECT;
486362306a36Sopenharmony_ci			break;
486462306a36Sopenharmony_ci		case SECCLASS_SCTP_SOCKET:
486562306a36Sopenharmony_ci			perm = SCTP_SOCKET__NAME_CONNECT;
486662306a36Sopenharmony_ci			break;
486762306a36Sopenharmony_ci		}
486862306a36Sopenharmony_ci
486962306a36Sopenharmony_ci		ad.type = LSM_AUDIT_DATA_NET;
487062306a36Sopenharmony_ci		ad.u.net = &net;
487162306a36Sopenharmony_ci		ad.u.net->dport = htons(snum);
487262306a36Sopenharmony_ci		ad.u.net->family = address->sa_family;
487362306a36Sopenharmony_ci		err = avc_has_perm(sksec->sid, sid, sksec->sclass, perm, &ad);
487462306a36Sopenharmony_ci		if (err)
487562306a36Sopenharmony_ci			return err;
487662306a36Sopenharmony_ci	}
487762306a36Sopenharmony_ci
487862306a36Sopenharmony_ci	return 0;
487962306a36Sopenharmony_ci}
488062306a36Sopenharmony_ci
488162306a36Sopenharmony_ci/* Supports connect(2), see comments in selinux_socket_connect_helper() */
488262306a36Sopenharmony_cistatic int selinux_socket_connect(struct socket *sock,
488362306a36Sopenharmony_ci				  struct sockaddr *address, int addrlen)
488462306a36Sopenharmony_ci{
488562306a36Sopenharmony_ci	int err;
488662306a36Sopenharmony_ci	struct sock *sk = sock->sk;
488762306a36Sopenharmony_ci
488862306a36Sopenharmony_ci	err = selinux_socket_connect_helper(sock, address, addrlen);
488962306a36Sopenharmony_ci	if (err)
489062306a36Sopenharmony_ci		return err;
489162306a36Sopenharmony_ci
489262306a36Sopenharmony_ci	return selinux_netlbl_socket_connect(sk, address);
489362306a36Sopenharmony_ci}
489462306a36Sopenharmony_ci
489562306a36Sopenharmony_cistatic int selinux_socket_listen(struct socket *sock, int backlog)
489662306a36Sopenharmony_ci{
489762306a36Sopenharmony_ci	return sock_has_perm(sock->sk, SOCKET__LISTEN);
489862306a36Sopenharmony_ci}
489962306a36Sopenharmony_ci
490062306a36Sopenharmony_cistatic int selinux_socket_accept(struct socket *sock, struct socket *newsock)
490162306a36Sopenharmony_ci{
490262306a36Sopenharmony_ci	int err;
490362306a36Sopenharmony_ci	struct inode_security_struct *isec;
490462306a36Sopenharmony_ci	struct inode_security_struct *newisec;
490562306a36Sopenharmony_ci	u16 sclass;
490662306a36Sopenharmony_ci	u32 sid;
490762306a36Sopenharmony_ci
490862306a36Sopenharmony_ci	err = sock_has_perm(sock->sk, SOCKET__ACCEPT);
490962306a36Sopenharmony_ci	if (err)
491062306a36Sopenharmony_ci		return err;
491162306a36Sopenharmony_ci
491262306a36Sopenharmony_ci	isec = inode_security_novalidate(SOCK_INODE(sock));
491362306a36Sopenharmony_ci	spin_lock(&isec->lock);
491462306a36Sopenharmony_ci	sclass = isec->sclass;
491562306a36Sopenharmony_ci	sid = isec->sid;
491662306a36Sopenharmony_ci	spin_unlock(&isec->lock);
491762306a36Sopenharmony_ci
491862306a36Sopenharmony_ci	newisec = inode_security_novalidate(SOCK_INODE(newsock));
491962306a36Sopenharmony_ci	newisec->sclass = sclass;
492062306a36Sopenharmony_ci	newisec->sid = sid;
492162306a36Sopenharmony_ci	newisec->initialized = LABEL_INITIALIZED;
492262306a36Sopenharmony_ci
492362306a36Sopenharmony_ci	return 0;
492462306a36Sopenharmony_ci}
492562306a36Sopenharmony_ci
492662306a36Sopenharmony_cistatic int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
492762306a36Sopenharmony_ci				  int size)
492862306a36Sopenharmony_ci{
492962306a36Sopenharmony_ci	return sock_has_perm(sock->sk, SOCKET__WRITE);
493062306a36Sopenharmony_ci}
493162306a36Sopenharmony_ci
493262306a36Sopenharmony_cistatic int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
493362306a36Sopenharmony_ci				  int size, int flags)
493462306a36Sopenharmony_ci{
493562306a36Sopenharmony_ci	return sock_has_perm(sock->sk, SOCKET__READ);
493662306a36Sopenharmony_ci}
493762306a36Sopenharmony_ci
493862306a36Sopenharmony_cistatic int selinux_socket_getsockname(struct socket *sock)
493962306a36Sopenharmony_ci{
494062306a36Sopenharmony_ci	return sock_has_perm(sock->sk, SOCKET__GETATTR);
494162306a36Sopenharmony_ci}
494262306a36Sopenharmony_ci
494362306a36Sopenharmony_cistatic int selinux_socket_getpeername(struct socket *sock)
494462306a36Sopenharmony_ci{
494562306a36Sopenharmony_ci	return sock_has_perm(sock->sk, SOCKET__GETATTR);
494662306a36Sopenharmony_ci}
494762306a36Sopenharmony_ci
494862306a36Sopenharmony_cistatic int selinux_socket_setsockopt(struct socket *sock, int level, int optname)
494962306a36Sopenharmony_ci{
495062306a36Sopenharmony_ci	int err;
495162306a36Sopenharmony_ci
495262306a36Sopenharmony_ci	err = sock_has_perm(sock->sk, SOCKET__SETOPT);
495362306a36Sopenharmony_ci	if (err)
495462306a36Sopenharmony_ci		return err;
495562306a36Sopenharmony_ci
495662306a36Sopenharmony_ci	return selinux_netlbl_socket_setsockopt(sock, level, optname);
495762306a36Sopenharmony_ci}
495862306a36Sopenharmony_ci
495962306a36Sopenharmony_cistatic int selinux_socket_getsockopt(struct socket *sock, int level,
496062306a36Sopenharmony_ci				     int optname)
496162306a36Sopenharmony_ci{
496262306a36Sopenharmony_ci	return sock_has_perm(sock->sk, SOCKET__GETOPT);
496362306a36Sopenharmony_ci}
496462306a36Sopenharmony_ci
496562306a36Sopenharmony_cistatic int selinux_socket_shutdown(struct socket *sock, int how)
496662306a36Sopenharmony_ci{
496762306a36Sopenharmony_ci	return sock_has_perm(sock->sk, SOCKET__SHUTDOWN);
496862306a36Sopenharmony_ci}
496962306a36Sopenharmony_ci
497062306a36Sopenharmony_cistatic int selinux_socket_unix_stream_connect(struct sock *sock,
497162306a36Sopenharmony_ci					      struct sock *other,
497262306a36Sopenharmony_ci					      struct sock *newsk)
497362306a36Sopenharmony_ci{
497462306a36Sopenharmony_ci	struct sk_security_struct *sksec_sock = sock->sk_security;
497562306a36Sopenharmony_ci	struct sk_security_struct *sksec_other = other->sk_security;
497662306a36Sopenharmony_ci	struct sk_security_struct *sksec_new = newsk->sk_security;
497762306a36Sopenharmony_ci	struct common_audit_data ad;
497862306a36Sopenharmony_ci	struct lsm_network_audit net;
497962306a36Sopenharmony_ci	int err;
498062306a36Sopenharmony_ci
498162306a36Sopenharmony_ci	ad_net_init_from_sk(&ad, &net, other);
498262306a36Sopenharmony_ci
498362306a36Sopenharmony_ci	err = avc_has_perm(sksec_sock->sid, sksec_other->sid,
498462306a36Sopenharmony_ci			   sksec_other->sclass,
498562306a36Sopenharmony_ci			   UNIX_STREAM_SOCKET__CONNECTTO, &ad);
498662306a36Sopenharmony_ci	if (err)
498762306a36Sopenharmony_ci		return err;
498862306a36Sopenharmony_ci
498962306a36Sopenharmony_ci	/* server child socket */
499062306a36Sopenharmony_ci	sksec_new->peer_sid = sksec_sock->sid;
499162306a36Sopenharmony_ci	err = security_sid_mls_copy(sksec_other->sid,
499262306a36Sopenharmony_ci				    sksec_sock->sid, &sksec_new->sid);
499362306a36Sopenharmony_ci	if (err)
499462306a36Sopenharmony_ci		return err;
499562306a36Sopenharmony_ci
499662306a36Sopenharmony_ci	/* connecting socket */
499762306a36Sopenharmony_ci	sksec_sock->peer_sid = sksec_new->sid;
499862306a36Sopenharmony_ci
499962306a36Sopenharmony_ci	return 0;
500062306a36Sopenharmony_ci}
500162306a36Sopenharmony_ci
500262306a36Sopenharmony_cistatic int selinux_socket_unix_may_send(struct socket *sock,
500362306a36Sopenharmony_ci					struct socket *other)
500462306a36Sopenharmony_ci{
500562306a36Sopenharmony_ci	struct sk_security_struct *ssec = sock->sk->sk_security;
500662306a36Sopenharmony_ci	struct sk_security_struct *osec = other->sk->sk_security;
500762306a36Sopenharmony_ci	struct common_audit_data ad;
500862306a36Sopenharmony_ci	struct lsm_network_audit net;
500962306a36Sopenharmony_ci
501062306a36Sopenharmony_ci	ad_net_init_from_sk(&ad, &net, other->sk);
501162306a36Sopenharmony_ci
501262306a36Sopenharmony_ci	return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,
501362306a36Sopenharmony_ci			    &ad);
501462306a36Sopenharmony_ci}
501562306a36Sopenharmony_ci
501662306a36Sopenharmony_cistatic int selinux_inet_sys_rcv_skb(struct net *ns, int ifindex,
501762306a36Sopenharmony_ci				    char *addrp, u16 family, u32 peer_sid,
501862306a36Sopenharmony_ci				    struct common_audit_data *ad)
501962306a36Sopenharmony_ci{
502062306a36Sopenharmony_ci	int err;
502162306a36Sopenharmony_ci	u32 if_sid;
502262306a36Sopenharmony_ci	u32 node_sid;
502362306a36Sopenharmony_ci
502462306a36Sopenharmony_ci	err = sel_netif_sid(ns, ifindex, &if_sid);
502562306a36Sopenharmony_ci	if (err)
502662306a36Sopenharmony_ci		return err;
502762306a36Sopenharmony_ci	err = avc_has_perm(peer_sid, if_sid,
502862306a36Sopenharmony_ci			   SECCLASS_NETIF, NETIF__INGRESS, ad);
502962306a36Sopenharmony_ci	if (err)
503062306a36Sopenharmony_ci		return err;
503162306a36Sopenharmony_ci
503262306a36Sopenharmony_ci	err = sel_netnode_sid(addrp, family, &node_sid);
503362306a36Sopenharmony_ci	if (err)
503462306a36Sopenharmony_ci		return err;
503562306a36Sopenharmony_ci	return avc_has_perm(peer_sid, node_sid,
503662306a36Sopenharmony_ci			    SECCLASS_NODE, NODE__RECVFROM, ad);
503762306a36Sopenharmony_ci}
503862306a36Sopenharmony_ci
503962306a36Sopenharmony_cistatic int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
504062306a36Sopenharmony_ci				       u16 family)
504162306a36Sopenharmony_ci{
504262306a36Sopenharmony_ci	int err = 0;
504362306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
504462306a36Sopenharmony_ci	u32 sk_sid = sksec->sid;
504562306a36Sopenharmony_ci	struct common_audit_data ad;
504662306a36Sopenharmony_ci	struct lsm_network_audit net;
504762306a36Sopenharmony_ci	char *addrp;
504862306a36Sopenharmony_ci
504962306a36Sopenharmony_ci	ad_net_init_from_iif(&ad, &net, skb->skb_iif, family);
505062306a36Sopenharmony_ci	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
505162306a36Sopenharmony_ci	if (err)
505262306a36Sopenharmony_ci		return err;
505362306a36Sopenharmony_ci
505462306a36Sopenharmony_ci	if (selinux_secmark_enabled()) {
505562306a36Sopenharmony_ci		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
505662306a36Sopenharmony_ci				   PACKET__RECV, &ad);
505762306a36Sopenharmony_ci		if (err)
505862306a36Sopenharmony_ci			return err;
505962306a36Sopenharmony_ci	}
506062306a36Sopenharmony_ci
506162306a36Sopenharmony_ci	err = selinux_netlbl_sock_rcv_skb(sksec, skb, family, &ad);
506262306a36Sopenharmony_ci	if (err)
506362306a36Sopenharmony_ci		return err;
506462306a36Sopenharmony_ci	err = selinux_xfrm_sock_rcv_skb(sksec->sid, skb, &ad);
506562306a36Sopenharmony_ci
506662306a36Sopenharmony_ci	return err;
506762306a36Sopenharmony_ci}
506862306a36Sopenharmony_ci
506962306a36Sopenharmony_cistatic int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
507062306a36Sopenharmony_ci{
507162306a36Sopenharmony_ci	int err, peerlbl_active, secmark_active;
507262306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
507362306a36Sopenharmony_ci	u16 family = sk->sk_family;
507462306a36Sopenharmony_ci	u32 sk_sid = sksec->sid;
507562306a36Sopenharmony_ci	struct common_audit_data ad;
507662306a36Sopenharmony_ci	struct lsm_network_audit net;
507762306a36Sopenharmony_ci	char *addrp;
507862306a36Sopenharmony_ci
507962306a36Sopenharmony_ci	if (family != PF_INET && family != PF_INET6)
508062306a36Sopenharmony_ci		return 0;
508162306a36Sopenharmony_ci
508262306a36Sopenharmony_ci	/* Handle mapped IPv4 packets arriving via IPv6 sockets */
508362306a36Sopenharmony_ci	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
508462306a36Sopenharmony_ci		family = PF_INET;
508562306a36Sopenharmony_ci
508662306a36Sopenharmony_ci	/* If any sort of compatibility mode is enabled then handoff processing
508762306a36Sopenharmony_ci	 * to the selinux_sock_rcv_skb_compat() function to deal with the
508862306a36Sopenharmony_ci	 * special handling.  We do this in an attempt to keep this function
508962306a36Sopenharmony_ci	 * as fast and as clean as possible. */
509062306a36Sopenharmony_ci	if (!selinux_policycap_netpeer())
509162306a36Sopenharmony_ci		return selinux_sock_rcv_skb_compat(sk, skb, family);
509262306a36Sopenharmony_ci
509362306a36Sopenharmony_ci	secmark_active = selinux_secmark_enabled();
509462306a36Sopenharmony_ci	peerlbl_active = selinux_peerlbl_enabled();
509562306a36Sopenharmony_ci	if (!secmark_active && !peerlbl_active)
509662306a36Sopenharmony_ci		return 0;
509762306a36Sopenharmony_ci
509862306a36Sopenharmony_ci	ad_net_init_from_iif(&ad, &net, skb->skb_iif, family);
509962306a36Sopenharmony_ci	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);
510062306a36Sopenharmony_ci	if (err)
510162306a36Sopenharmony_ci		return err;
510262306a36Sopenharmony_ci
510362306a36Sopenharmony_ci	if (peerlbl_active) {
510462306a36Sopenharmony_ci		u32 peer_sid;
510562306a36Sopenharmony_ci
510662306a36Sopenharmony_ci		err = selinux_skb_peerlbl_sid(skb, family, &peer_sid);
510762306a36Sopenharmony_ci		if (err)
510862306a36Sopenharmony_ci			return err;
510962306a36Sopenharmony_ci		err = selinux_inet_sys_rcv_skb(sock_net(sk), skb->skb_iif,
511062306a36Sopenharmony_ci					       addrp, family, peer_sid, &ad);
511162306a36Sopenharmony_ci		if (err) {
511262306a36Sopenharmony_ci			selinux_netlbl_err(skb, family, err, 0);
511362306a36Sopenharmony_ci			return err;
511462306a36Sopenharmony_ci		}
511562306a36Sopenharmony_ci		err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER,
511662306a36Sopenharmony_ci				   PEER__RECV, &ad);
511762306a36Sopenharmony_ci		if (err) {
511862306a36Sopenharmony_ci			selinux_netlbl_err(skb, family, err, 0);
511962306a36Sopenharmony_ci			return err;
512062306a36Sopenharmony_ci		}
512162306a36Sopenharmony_ci	}
512262306a36Sopenharmony_ci
512362306a36Sopenharmony_ci	if (secmark_active) {
512462306a36Sopenharmony_ci		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET,
512562306a36Sopenharmony_ci				   PACKET__RECV, &ad);
512662306a36Sopenharmony_ci		if (err)
512762306a36Sopenharmony_ci			return err;
512862306a36Sopenharmony_ci	}
512962306a36Sopenharmony_ci
513062306a36Sopenharmony_ci	return err;
513162306a36Sopenharmony_ci}
513262306a36Sopenharmony_ci
513362306a36Sopenharmony_cistatic int selinux_socket_getpeersec_stream(struct socket *sock,
513462306a36Sopenharmony_ci					    sockptr_t optval, sockptr_t optlen,
513562306a36Sopenharmony_ci					    unsigned int len)
513662306a36Sopenharmony_ci{
513762306a36Sopenharmony_ci	int err = 0;
513862306a36Sopenharmony_ci	char *scontext = NULL;
513962306a36Sopenharmony_ci	u32 scontext_len;
514062306a36Sopenharmony_ci	struct sk_security_struct *sksec = sock->sk->sk_security;
514162306a36Sopenharmony_ci	u32 peer_sid = SECSID_NULL;
514262306a36Sopenharmony_ci
514362306a36Sopenharmony_ci	if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
514462306a36Sopenharmony_ci	    sksec->sclass == SECCLASS_TCP_SOCKET ||
514562306a36Sopenharmony_ci	    sksec->sclass == SECCLASS_SCTP_SOCKET)
514662306a36Sopenharmony_ci		peer_sid = sksec->peer_sid;
514762306a36Sopenharmony_ci	if (peer_sid == SECSID_NULL)
514862306a36Sopenharmony_ci		return -ENOPROTOOPT;
514962306a36Sopenharmony_ci
515062306a36Sopenharmony_ci	err = security_sid_to_context(peer_sid, &scontext,
515162306a36Sopenharmony_ci				      &scontext_len);
515262306a36Sopenharmony_ci	if (err)
515362306a36Sopenharmony_ci		return err;
515462306a36Sopenharmony_ci	if (scontext_len > len) {
515562306a36Sopenharmony_ci		err = -ERANGE;
515662306a36Sopenharmony_ci		goto out_len;
515762306a36Sopenharmony_ci	}
515862306a36Sopenharmony_ci
515962306a36Sopenharmony_ci	if (copy_to_sockptr(optval, scontext, scontext_len))
516062306a36Sopenharmony_ci		err = -EFAULT;
516162306a36Sopenharmony_ciout_len:
516262306a36Sopenharmony_ci	if (copy_to_sockptr(optlen, &scontext_len, sizeof(scontext_len)))
516362306a36Sopenharmony_ci		err = -EFAULT;
516462306a36Sopenharmony_ci	kfree(scontext);
516562306a36Sopenharmony_ci	return err;
516662306a36Sopenharmony_ci}
516762306a36Sopenharmony_ci
516862306a36Sopenharmony_cistatic int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid)
516962306a36Sopenharmony_ci{
517062306a36Sopenharmony_ci	u32 peer_secid = SECSID_NULL;
517162306a36Sopenharmony_ci	u16 family;
517262306a36Sopenharmony_ci	struct inode_security_struct *isec;
517362306a36Sopenharmony_ci
517462306a36Sopenharmony_ci	if (skb && skb->protocol == htons(ETH_P_IP))
517562306a36Sopenharmony_ci		family = PF_INET;
517662306a36Sopenharmony_ci	else if (skb && skb->protocol == htons(ETH_P_IPV6))
517762306a36Sopenharmony_ci		family = PF_INET6;
517862306a36Sopenharmony_ci	else if (sock)
517962306a36Sopenharmony_ci		family = sock->sk->sk_family;
518062306a36Sopenharmony_ci	else
518162306a36Sopenharmony_ci		goto out;
518262306a36Sopenharmony_ci
518362306a36Sopenharmony_ci	if (sock && family == PF_UNIX) {
518462306a36Sopenharmony_ci		isec = inode_security_novalidate(SOCK_INODE(sock));
518562306a36Sopenharmony_ci		peer_secid = isec->sid;
518662306a36Sopenharmony_ci	} else if (skb)
518762306a36Sopenharmony_ci		selinux_skb_peerlbl_sid(skb, family, &peer_secid);
518862306a36Sopenharmony_ci
518962306a36Sopenharmony_ciout:
519062306a36Sopenharmony_ci	*secid = peer_secid;
519162306a36Sopenharmony_ci	if (peer_secid == SECSID_NULL)
519262306a36Sopenharmony_ci		return -EINVAL;
519362306a36Sopenharmony_ci	return 0;
519462306a36Sopenharmony_ci}
519562306a36Sopenharmony_ci
519662306a36Sopenharmony_cistatic int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
519762306a36Sopenharmony_ci{
519862306a36Sopenharmony_ci	struct sk_security_struct *sksec;
519962306a36Sopenharmony_ci
520062306a36Sopenharmony_ci	sksec = kzalloc(sizeof(*sksec), priority);
520162306a36Sopenharmony_ci	if (!sksec)
520262306a36Sopenharmony_ci		return -ENOMEM;
520362306a36Sopenharmony_ci
520462306a36Sopenharmony_ci	sksec->peer_sid = SECINITSID_UNLABELED;
520562306a36Sopenharmony_ci	sksec->sid = SECINITSID_UNLABELED;
520662306a36Sopenharmony_ci	sksec->sclass = SECCLASS_SOCKET;
520762306a36Sopenharmony_ci	selinux_netlbl_sk_security_reset(sksec);
520862306a36Sopenharmony_ci	sk->sk_security = sksec;
520962306a36Sopenharmony_ci
521062306a36Sopenharmony_ci	return 0;
521162306a36Sopenharmony_ci}
521262306a36Sopenharmony_ci
521362306a36Sopenharmony_cistatic void selinux_sk_free_security(struct sock *sk)
521462306a36Sopenharmony_ci{
521562306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
521662306a36Sopenharmony_ci
521762306a36Sopenharmony_ci	sk->sk_security = NULL;
521862306a36Sopenharmony_ci	selinux_netlbl_sk_security_free(sksec);
521962306a36Sopenharmony_ci	kfree(sksec);
522062306a36Sopenharmony_ci}
522162306a36Sopenharmony_ci
522262306a36Sopenharmony_cistatic void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
522362306a36Sopenharmony_ci{
522462306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
522562306a36Sopenharmony_ci	struct sk_security_struct *newsksec = newsk->sk_security;
522662306a36Sopenharmony_ci
522762306a36Sopenharmony_ci	newsksec->sid = sksec->sid;
522862306a36Sopenharmony_ci	newsksec->peer_sid = sksec->peer_sid;
522962306a36Sopenharmony_ci	newsksec->sclass = sksec->sclass;
523062306a36Sopenharmony_ci
523162306a36Sopenharmony_ci	selinux_netlbl_sk_security_reset(newsksec);
523262306a36Sopenharmony_ci}
523362306a36Sopenharmony_ci
523462306a36Sopenharmony_cistatic void selinux_sk_getsecid(const struct sock *sk, u32 *secid)
523562306a36Sopenharmony_ci{
523662306a36Sopenharmony_ci	if (!sk)
523762306a36Sopenharmony_ci		*secid = SECINITSID_ANY_SOCKET;
523862306a36Sopenharmony_ci	else {
523962306a36Sopenharmony_ci		const struct sk_security_struct *sksec = sk->sk_security;
524062306a36Sopenharmony_ci
524162306a36Sopenharmony_ci		*secid = sksec->sid;
524262306a36Sopenharmony_ci	}
524362306a36Sopenharmony_ci}
524462306a36Sopenharmony_ci
524562306a36Sopenharmony_cistatic void selinux_sock_graft(struct sock *sk, struct socket *parent)
524662306a36Sopenharmony_ci{
524762306a36Sopenharmony_ci	struct inode_security_struct *isec =
524862306a36Sopenharmony_ci		inode_security_novalidate(SOCK_INODE(parent));
524962306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
525062306a36Sopenharmony_ci
525162306a36Sopenharmony_ci	if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
525262306a36Sopenharmony_ci	    sk->sk_family == PF_UNIX)
525362306a36Sopenharmony_ci		isec->sid = sksec->sid;
525462306a36Sopenharmony_ci	sksec->sclass = isec->sclass;
525562306a36Sopenharmony_ci}
525662306a36Sopenharmony_ci
525762306a36Sopenharmony_ci/*
525862306a36Sopenharmony_ci * Determines peer_secid for the asoc and updates socket's peer label
525962306a36Sopenharmony_ci * if it's the first association on the socket.
526062306a36Sopenharmony_ci */
526162306a36Sopenharmony_cistatic int selinux_sctp_process_new_assoc(struct sctp_association *asoc,
526262306a36Sopenharmony_ci					  struct sk_buff *skb)
526362306a36Sopenharmony_ci{
526462306a36Sopenharmony_ci	struct sock *sk = asoc->base.sk;
526562306a36Sopenharmony_ci	u16 family = sk->sk_family;
526662306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
526762306a36Sopenharmony_ci	struct common_audit_data ad;
526862306a36Sopenharmony_ci	struct lsm_network_audit net;
526962306a36Sopenharmony_ci	int err;
527062306a36Sopenharmony_ci
527162306a36Sopenharmony_ci	/* handle mapped IPv4 packets arriving via IPv6 sockets */
527262306a36Sopenharmony_ci	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
527362306a36Sopenharmony_ci		family = PF_INET;
527462306a36Sopenharmony_ci
527562306a36Sopenharmony_ci	if (selinux_peerlbl_enabled()) {
527662306a36Sopenharmony_ci		asoc->peer_secid = SECSID_NULL;
527762306a36Sopenharmony_ci
527862306a36Sopenharmony_ci		/* This will return peer_sid = SECSID_NULL if there are
527962306a36Sopenharmony_ci		 * no peer labels, see security_net_peersid_resolve().
528062306a36Sopenharmony_ci		 */
528162306a36Sopenharmony_ci		err = selinux_skb_peerlbl_sid(skb, family, &asoc->peer_secid);
528262306a36Sopenharmony_ci		if (err)
528362306a36Sopenharmony_ci			return err;
528462306a36Sopenharmony_ci
528562306a36Sopenharmony_ci		if (asoc->peer_secid == SECSID_NULL)
528662306a36Sopenharmony_ci			asoc->peer_secid = SECINITSID_UNLABELED;
528762306a36Sopenharmony_ci	} else {
528862306a36Sopenharmony_ci		asoc->peer_secid = SECINITSID_UNLABELED;
528962306a36Sopenharmony_ci	}
529062306a36Sopenharmony_ci
529162306a36Sopenharmony_ci	if (sksec->sctp_assoc_state == SCTP_ASSOC_UNSET) {
529262306a36Sopenharmony_ci		sksec->sctp_assoc_state = SCTP_ASSOC_SET;
529362306a36Sopenharmony_ci
529462306a36Sopenharmony_ci		/* Here as first association on socket. As the peer SID
529562306a36Sopenharmony_ci		 * was allowed by peer recv (and the netif/node checks),
529662306a36Sopenharmony_ci		 * then it is approved by policy and used as the primary
529762306a36Sopenharmony_ci		 * peer SID for getpeercon(3).
529862306a36Sopenharmony_ci		 */
529962306a36Sopenharmony_ci		sksec->peer_sid = asoc->peer_secid;
530062306a36Sopenharmony_ci	} else if (sksec->peer_sid != asoc->peer_secid) {
530162306a36Sopenharmony_ci		/* Other association peer SIDs are checked to enforce
530262306a36Sopenharmony_ci		 * consistency among the peer SIDs.
530362306a36Sopenharmony_ci		 */
530462306a36Sopenharmony_ci		ad_net_init_from_sk(&ad, &net, asoc->base.sk);
530562306a36Sopenharmony_ci		err = avc_has_perm(sksec->peer_sid, asoc->peer_secid,
530662306a36Sopenharmony_ci				   sksec->sclass, SCTP_SOCKET__ASSOCIATION,
530762306a36Sopenharmony_ci				   &ad);
530862306a36Sopenharmony_ci		if (err)
530962306a36Sopenharmony_ci			return err;
531062306a36Sopenharmony_ci	}
531162306a36Sopenharmony_ci	return 0;
531262306a36Sopenharmony_ci}
531362306a36Sopenharmony_ci
531462306a36Sopenharmony_ci/* Called whenever SCTP receives an INIT or COOKIE ECHO chunk. This
531562306a36Sopenharmony_ci * happens on an incoming connect(2), sctp_connectx(3) or
531662306a36Sopenharmony_ci * sctp_sendmsg(3) (with no association already present).
531762306a36Sopenharmony_ci */
531862306a36Sopenharmony_cistatic int selinux_sctp_assoc_request(struct sctp_association *asoc,
531962306a36Sopenharmony_ci				      struct sk_buff *skb)
532062306a36Sopenharmony_ci{
532162306a36Sopenharmony_ci	struct sk_security_struct *sksec = asoc->base.sk->sk_security;
532262306a36Sopenharmony_ci	u32 conn_sid;
532362306a36Sopenharmony_ci	int err;
532462306a36Sopenharmony_ci
532562306a36Sopenharmony_ci	if (!selinux_policycap_extsockclass())
532662306a36Sopenharmony_ci		return 0;
532762306a36Sopenharmony_ci
532862306a36Sopenharmony_ci	err = selinux_sctp_process_new_assoc(asoc, skb);
532962306a36Sopenharmony_ci	if (err)
533062306a36Sopenharmony_ci		return err;
533162306a36Sopenharmony_ci
533262306a36Sopenharmony_ci	/* Compute the MLS component for the connection and store
533362306a36Sopenharmony_ci	 * the information in asoc. This will be used by SCTP TCP type
533462306a36Sopenharmony_ci	 * sockets and peeled off connections as they cause a new
533562306a36Sopenharmony_ci	 * socket to be generated. selinux_sctp_sk_clone() will then
533662306a36Sopenharmony_ci	 * plug this into the new socket.
533762306a36Sopenharmony_ci	 */
533862306a36Sopenharmony_ci	err = selinux_conn_sid(sksec->sid, asoc->peer_secid, &conn_sid);
533962306a36Sopenharmony_ci	if (err)
534062306a36Sopenharmony_ci		return err;
534162306a36Sopenharmony_ci
534262306a36Sopenharmony_ci	asoc->secid = conn_sid;
534362306a36Sopenharmony_ci
534462306a36Sopenharmony_ci	/* Set any NetLabel labels including CIPSO/CALIPSO options. */
534562306a36Sopenharmony_ci	return selinux_netlbl_sctp_assoc_request(asoc, skb);
534662306a36Sopenharmony_ci}
534762306a36Sopenharmony_ci
534862306a36Sopenharmony_ci/* Called when SCTP receives a COOKIE ACK chunk as the final
534962306a36Sopenharmony_ci * response to an association request (initited by us).
535062306a36Sopenharmony_ci */
535162306a36Sopenharmony_cistatic int selinux_sctp_assoc_established(struct sctp_association *asoc,
535262306a36Sopenharmony_ci					  struct sk_buff *skb)
535362306a36Sopenharmony_ci{
535462306a36Sopenharmony_ci	struct sk_security_struct *sksec = asoc->base.sk->sk_security;
535562306a36Sopenharmony_ci
535662306a36Sopenharmony_ci	if (!selinux_policycap_extsockclass())
535762306a36Sopenharmony_ci		return 0;
535862306a36Sopenharmony_ci
535962306a36Sopenharmony_ci	/* Inherit secid from the parent socket - this will be picked up
536062306a36Sopenharmony_ci	 * by selinux_sctp_sk_clone() if the association gets peeled off
536162306a36Sopenharmony_ci	 * into a new socket.
536262306a36Sopenharmony_ci	 */
536362306a36Sopenharmony_ci	asoc->secid = sksec->sid;
536462306a36Sopenharmony_ci
536562306a36Sopenharmony_ci	return selinux_sctp_process_new_assoc(asoc, skb);
536662306a36Sopenharmony_ci}
536762306a36Sopenharmony_ci
536862306a36Sopenharmony_ci/* Check if sctp IPv4/IPv6 addresses are valid for binding or connecting
536962306a36Sopenharmony_ci * based on their @optname.
537062306a36Sopenharmony_ci */
537162306a36Sopenharmony_cistatic int selinux_sctp_bind_connect(struct sock *sk, int optname,
537262306a36Sopenharmony_ci				     struct sockaddr *address,
537362306a36Sopenharmony_ci				     int addrlen)
537462306a36Sopenharmony_ci{
537562306a36Sopenharmony_ci	int len, err = 0, walk_size = 0;
537662306a36Sopenharmony_ci	void *addr_buf;
537762306a36Sopenharmony_ci	struct sockaddr *addr;
537862306a36Sopenharmony_ci	struct socket *sock;
537962306a36Sopenharmony_ci
538062306a36Sopenharmony_ci	if (!selinux_policycap_extsockclass())
538162306a36Sopenharmony_ci		return 0;
538262306a36Sopenharmony_ci
538362306a36Sopenharmony_ci	/* Process one or more addresses that may be IPv4 or IPv6 */
538462306a36Sopenharmony_ci	sock = sk->sk_socket;
538562306a36Sopenharmony_ci	addr_buf = address;
538662306a36Sopenharmony_ci
538762306a36Sopenharmony_ci	while (walk_size < addrlen) {
538862306a36Sopenharmony_ci		if (walk_size + sizeof(sa_family_t) > addrlen)
538962306a36Sopenharmony_ci			return -EINVAL;
539062306a36Sopenharmony_ci
539162306a36Sopenharmony_ci		addr = addr_buf;
539262306a36Sopenharmony_ci		switch (addr->sa_family) {
539362306a36Sopenharmony_ci		case AF_UNSPEC:
539462306a36Sopenharmony_ci		case AF_INET:
539562306a36Sopenharmony_ci			len = sizeof(struct sockaddr_in);
539662306a36Sopenharmony_ci			break;
539762306a36Sopenharmony_ci		case AF_INET6:
539862306a36Sopenharmony_ci			len = sizeof(struct sockaddr_in6);
539962306a36Sopenharmony_ci			break;
540062306a36Sopenharmony_ci		default:
540162306a36Sopenharmony_ci			return -EINVAL;
540262306a36Sopenharmony_ci		}
540362306a36Sopenharmony_ci
540462306a36Sopenharmony_ci		if (walk_size + len > addrlen)
540562306a36Sopenharmony_ci			return -EINVAL;
540662306a36Sopenharmony_ci
540762306a36Sopenharmony_ci		err = -EINVAL;
540862306a36Sopenharmony_ci		switch (optname) {
540962306a36Sopenharmony_ci		/* Bind checks */
541062306a36Sopenharmony_ci		case SCTP_PRIMARY_ADDR:
541162306a36Sopenharmony_ci		case SCTP_SET_PEER_PRIMARY_ADDR:
541262306a36Sopenharmony_ci		case SCTP_SOCKOPT_BINDX_ADD:
541362306a36Sopenharmony_ci			err = selinux_socket_bind(sock, addr, len);
541462306a36Sopenharmony_ci			break;
541562306a36Sopenharmony_ci		/* Connect checks */
541662306a36Sopenharmony_ci		case SCTP_SOCKOPT_CONNECTX:
541762306a36Sopenharmony_ci		case SCTP_PARAM_SET_PRIMARY:
541862306a36Sopenharmony_ci		case SCTP_PARAM_ADD_IP:
541962306a36Sopenharmony_ci		case SCTP_SENDMSG_CONNECT:
542062306a36Sopenharmony_ci			err = selinux_socket_connect_helper(sock, addr, len);
542162306a36Sopenharmony_ci			if (err)
542262306a36Sopenharmony_ci				return err;
542362306a36Sopenharmony_ci
542462306a36Sopenharmony_ci			/* As selinux_sctp_bind_connect() is called by the
542562306a36Sopenharmony_ci			 * SCTP protocol layer, the socket is already locked,
542662306a36Sopenharmony_ci			 * therefore selinux_netlbl_socket_connect_locked()
542762306a36Sopenharmony_ci			 * is called here. The situations handled are:
542862306a36Sopenharmony_ci			 * sctp_connectx(3), sctp_sendmsg(3), sendmsg(2),
542962306a36Sopenharmony_ci			 * whenever a new IP address is added or when a new
543062306a36Sopenharmony_ci			 * primary address is selected.
543162306a36Sopenharmony_ci			 * Note that an SCTP connect(2) call happens before
543262306a36Sopenharmony_ci			 * the SCTP protocol layer and is handled via
543362306a36Sopenharmony_ci			 * selinux_socket_connect().
543462306a36Sopenharmony_ci			 */
543562306a36Sopenharmony_ci			err = selinux_netlbl_socket_connect_locked(sk, addr);
543662306a36Sopenharmony_ci			break;
543762306a36Sopenharmony_ci		}
543862306a36Sopenharmony_ci
543962306a36Sopenharmony_ci		if (err)
544062306a36Sopenharmony_ci			return err;
544162306a36Sopenharmony_ci
544262306a36Sopenharmony_ci		addr_buf += len;
544362306a36Sopenharmony_ci		walk_size += len;
544462306a36Sopenharmony_ci	}
544562306a36Sopenharmony_ci
544662306a36Sopenharmony_ci	return 0;
544762306a36Sopenharmony_ci}
544862306a36Sopenharmony_ci
544962306a36Sopenharmony_ci/* Called whenever a new socket is created by accept(2) or sctp_peeloff(3). */
545062306a36Sopenharmony_cistatic void selinux_sctp_sk_clone(struct sctp_association *asoc, struct sock *sk,
545162306a36Sopenharmony_ci				  struct sock *newsk)
545262306a36Sopenharmony_ci{
545362306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
545462306a36Sopenharmony_ci	struct sk_security_struct *newsksec = newsk->sk_security;
545562306a36Sopenharmony_ci
545662306a36Sopenharmony_ci	/* If policy does not support SECCLASS_SCTP_SOCKET then call
545762306a36Sopenharmony_ci	 * the non-sctp clone version.
545862306a36Sopenharmony_ci	 */
545962306a36Sopenharmony_ci	if (!selinux_policycap_extsockclass())
546062306a36Sopenharmony_ci		return selinux_sk_clone_security(sk, newsk);
546162306a36Sopenharmony_ci
546262306a36Sopenharmony_ci	newsksec->sid = asoc->secid;
546362306a36Sopenharmony_ci	newsksec->peer_sid = asoc->peer_secid;
546462306a36Sopenharmony_ci	newsksec->sclass = sksec->sclass;
546562306a36Sopenharmony_ci	selinux_netlbl_sctp_sk_clone(sk, newsk);
546662306a36Sopenharmony_ci}
546762306a36Sopenharmony_ci
546862306a36Sopenharmony_cistatic int selinux_mptcp_add_subflow(struct sock *sk, struct sock *ssk)
546962306a36Sopenharmony_ci{
547062306a36Sopenharmony_ci	struct sk_security_struct *ssksec = ssk->sk_security;
547162306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
547262306a36Sopenharmony_ci
547362306a36Sopenharmony_ci	ssksec->sclass = sksec->sclass;
547462306a36Sopenharmony_ci	ssksec->sid = sksec->sid;
547562306a36Sopenharmony_ci
547662306a36Sopenharmony_ci	/* replace the existing subflow label deleting the existing one
547762306a36Sopenharmony_ci	 * and re-recreating a new label using the updated context
547862306a36Sopenharmony_ci	 */
547962306a36Sopenharmony_ci	selinux_netlbl_sk_security_free(ssksec);
548062306a36Sopenharmony_ci	return selinux_netlbl_socket_post_create(ssk, ssk->sk_family);
548162306a36Sopenharmony_ci}
548262306a36Sopenharmony_ci
548362306a36Sopenharmony_cistatic int selinux_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
548462306a36Sopenharmony_ci				     struct request_sock *req)
548562306a36Sopenharmony_ci{
548662306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
548762306a36Sopenharmony_ci	int err;
548862306a36Sopenharmony_ci	u16 family = req->rsk_ops->family;
548962306a36Sopenharmony_ci	u32 connsid;
549062306a36Sopenharmony_ci	u32 peersid;
549162306a36Sopenharmony_ci
549262306a36Sopenharmony_ci	err = selinux_skb_peerlbl_sid(skb, family, &peersid);
549362306a36Sopenharmony_ci	if (err)
549462306a36Sopenharmony_ci		return err;
549562306a36Sopenharmony_ci	err = selinux_conn_sid(sksec->sid, peersid, &connsid);
549662306a36Sopenharmony_ci	if (err)
549762306a36Sopenharmony_ci		return err;
549862306a36Sopenharmony_ci	req->secid = connsid;
549962306a36Sopenharmony_ci	req->peer_secid = peersid;
550062306a36Sopenharmony_ci
550162306a36Sopenharmony_ci	return selinux_netlbl_inet_conn_request(req, family);
550262306a36Sopenharmony_ci}
550362306a36Sopenharmony_ci
550462306a36Sopenharmony_cistatic void selinux_inet_csk_clone(struct sock *newsk,
550562306a36Sopenharmony_ci				   const struct request_sock *req)
550662306a36Sopenharmony_ci{
550762306a36Sopenharmony_ci	struct sk_security_struct *newsksec = newsk->sk_security;
550862306a36Sopenharmony_ci
550962306a36Sopenharmony_ci	newsksec->sid = req->secid;
551062306a36Sopenharmony_ci	newsksec->peer_sid = req->peer_secid;
551162306a36Sopenharmony_ci	/* NOTE: Ideally, we should also get the isec->sid for the
551262306a36Sopenharmony_ci	   new socket in sync, but we don't have the isec available yet.
551362306a36Sopenharmony_ci	   So we will wait until sock_graft to do it, by which
551462306a36Sopenharmony_ci	   time it will have been created and available. */
551562306a36Sopenharmony_ci
551662306a36Sopenharmony_ci	/* We don't need to take any sort of lock here as we are the only
551762306a36Sopenharmony_ci	 * thread with access to newsksec */
551862306a36Sopenharmony_ci	selinux_netlbl_inet_csk_clone(newsk, req->rsk_ops->family);
551962306a36Sopenharmony_ci}
552062306a36Sopenharmony_ci
552162306a36Sopenharmony_cistatic void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
552262306a36Sopenharmony_ci{
552362306a36Sopenharmony_ci	u16 family = sk->sk_family;
552462306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
552562306a36Sopenharmony_ci
552662306a36Sopenharmony_ci	/* handle mapped IPv4 packets arriving via IPv6 sockets */
552762306a36Sopenharmony_ci	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
552862306a36Sopenharmony_ci		family = PF_INET;
552962306a36Sopenharmony_ci
553062306a36Sopenharmony_ci	selinux_skb_peerlbl_sid(skb, family, &sksec->peer_sid);
553162306a36Sopenharmony_ci}
553262306a36Sopenharmony_ci
553362306a36Sopenharmony_cistatic int selinux_secmark_relabel_packet(u32 sid)
553462306a36Sopenharmony_ci{
553562306a36Sopenharmony_ci	const struct task_security_struct *tsec;
553662306a36Sopenharmony_ci	u32 tsid;
553762306a36Sopenharmony_ci
553862306a36Sopenharmony_ci	tsec = selinux_cred(current_cred());
553962306a36Sopenharmony_ci	tsid = tsec->sid;
554062306a36Sopenharmony_ci
554162306a36Sopenharmony_ci	return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
554262306a36Sopenharmony_ci			    NULL);
554362306a36Sopenharmony_ci}
554462306a36Sopenharmony_ci
554562306a36Sopenharmony_cistatic void selinux_secmark_refcount_inc(void)
554662306a36Sopenharmony_ci{
554762306a36Sopenharmony_ci	atomic_inc(&selinux_secmark_refcount);
554862306a36Sopenharmony_ci}
554962306a36Sopenharmony_ci
555062306a36Sopenharmony_cistatic void selinux_secmark_refcount_dec(void)
555162306a36Sopenharmony_ci{
555262306a36Sopenharmony_ci	atomic_dec(&selinux_secmark_refcount);
555362306a36Sopenharmony_ci}
555462306a36Sopenharmony_ci
555562306a36Sopenharmony_cistatic void selinux_req_classify_flow(const struct request_sock *req,
555662306a36Sopenharmony_ci				      struct flowi_common *flic)
555762306a36Sopenharmony_ci{
555862306a36Sopenharmony_ci	flic->flowic_secid = req->secid;
555962306a36Sopenharmony_ci}
556062306a36Sopenharmony_ci
556162306a36Sopenharmony_cistatic int selinux_tun_dev_alloc_security(void **security)
556262306a36Sopenharmony_ci{
556362306a36Sopenharmony_ci	struct tun_security_struct *tunsec;
556462306a36Sopenharmony_ci
556562306a36Sopenharmony_ci	tunsec = kzalloc(sizeof(*tunsec), GFP_KERNEL);
556662306a36Sopenharmony_ci	if (!tunsec)
556762306a36Sopenharmony_ci		return -ENOMEM;
556862306a36Sopenharmony_ci	tunsec->sid = current_sid();
556962306a36Sopenharmony_ci
557062306a36Sopenharmony_ci	*security = tunsec;
557162306a36Sopenharmony_ci	return 0;
557262306a36Sopenharmony_ci}
557362306a36Sopenharmony_ci
557462306a36Sopenharmony_cistatic void selinux_tun_dev_free_security(void *security)
557562306a36Sopenharmony_ci{
557662306a36Sopenharmony_ci	kfree(security);
557762306a36Sopenharmony_ci}
557862306a36Sopenharmony_ci
557962306a36Sopenharmony_cistatic int selinux_tun_dev_create(void)
558062306a36Sopenharmony_ci{
558162306a36Sopenharmony_ci	u32 sid = current_sid();
558262306a36Sopenharmony_ci
558362306a36Sopenharmony_ci	/* we aren't taking into account the "sockcreate" SID since the socket
558462306a36Sopenharmony_ci	 * that is being created here is not a socket in the traditional sense,
558562306a36Sopenharmony_ci	 * instead it is a private sock, accessible only to the kernel, and
558662306a36Sopenharmony_ci	 * representing a wide range of network traffic spanning multiple
558762306a36Sopenharmony_ci	 * connections unlike traditional sockets - check the TUN driver to
558862306a36Sopenharmony_ci	 * get a better understanding of why this socket is special */
558962306a36Sopenharmony_ci
559062306a36Sopenharmony_ci	return avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET, TUN_SOCKET__CREATE,
559162306a36Sopenharmony_ci			    NULL);
559262306a36Sopenharmony_ci}
559362306a36Sopenharmony_ci
559462306a36Sopenharmony_cistatic int selinux_tun_dev_attach_queue(void *security)
559562306a36Sopenharmony_ci{
559662306a36Sopenharmony_ci	struct tun_security_struct *tunsec = security;
559762306a36Sopenharmony_ci
559862306a36Sopenharmony_ci	return avc_has_perm(current_sid(), tunsec->sid, SECCLASS_TUN_SOCKET,
559962306a36Sopenharmony_ci			    TUN_SOCKET__ATTACH_QUEUE, NULL);
560062306a36Sopenharmony_ci}
560162306a36Sopenharmony_ci
560262306a36Sopenharmony_cistatic int selinux_tun_dev_attach(struct sock *sk, void *security)
560362306a36Sopenharmony_ci{
560462306a36Sopenharmony_ci	struct tun_security_struct *tunsec = security;
560562306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
560662306a36Sopenharmony_ci
560762306a36Sopenharmony_ci	/* we don't currently perform any NetLabel based labeling here and it
560862306a36Sopenharmony_ci	 * isn't clear that we would want to do so anyway; while we could apply
560962306a36Sopenharmony_ci	 * labeling without the support of the TUN user the resulting labeled
561062306a36Sopenharmony_ci	 * traffic from the other end of the connection would almost certainly
561162306a36Sopenharmony_ci	 * cause confusion to the TUN user that had no idea network labeling
561262306a36Sopenharmony_ci	 * protocols were being used */
561362306a36Sopenharmony_ci
561462306a36Sopenharmony_ci	sksec->sid = tunsec->sid;
561562306a36Sopenharmony_ci	sksec->sclass = SECCLASS_TUN_SOCKET;
561662306a36Sopenharmony_ci
561762306a36Sopenharmony_ci	return 0;
561862306a36Sopenharmony_ci}
561962306a36Sopenharmony_ci
562062306a36Sopenharmony_cistatic int selinux_tun_dev_open(void *security)
562162306a36Sopenharmony_ci{
562262306a36Sopenharmony_ci	struct tun_security_struct *tunsec = security;
562362306a36Sopenharmony_ci	u32 sid = current_sid();
562462306a36Sopenharmony_ci	int err;
562562306a36Sopenharmony_ci
562662306a36Sopenharmony_ci	err = avc_has_perm(sid, tunsec->sid, SECCLASS_TUN_SOCKET,
562762306a36Sopenharmony_ci			   TUN_SOCKET__RELABELFROM, NULL);
562862306a36Sopenharmony_ci	if (err)
562962306a36Sopenharmony_ci		return err;
563062306a36Sopenharmony_ci	err = avc_has_perm(sid, sid, SECCLASS_TUN_SOCKET,
563162306a36Sopenharmony_ci			   TUN_SOCKET__RELABELTO, NULL);
563262306a36Sopenharmony_ci	if (err)
563362306a36Sopenharmony_ci		return err;
563462306a36Sopenharmony_ci	tunsec->sid = sid;
563562306a36Sopenharmony_ci
563662306a36Sopenharmony_ci	return 0;
563762306a36Sopenharmony_ci}
563862306a36Sopenharmony_ci
563962306a36Sopenharmony_ci#ifdef CONFIG_NETFILTER
564062306a36Sopenharmony_ci
564162306a36Sopenharmony_cistatic unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,
564262306a36Sopenharmony_ci				       const struct nf_hook_state *state)
564362306a36Sopenharmony_ci{
564462306a36Sopenharmony_ci	int ifindex;
564562306a36Sopenharmony_ci	u16 family;
564662306a36Sopenharmony_ci	char *addrp;
564762306a36Sopenharmony_ci	u32 peer_sid;
564862306a36Sopenharmony_ci	struct common_audit_data ad;
564962306a36Sopenharmony_ci	struct lsm_network_audit net;
565062306a36Sopenharmony_ci	int secmark_active, peerlbl_active;
565162306a36Sopenharmony_ci
565262306a36Sopenharmony_ci	if (!selinux_policycap_netpeer())
565362306a36Sopenharmony_ci		return NF_ACCEPT;
565462306a36Sopenharmony_ci
565562306a36Sopenharmony_ci	secmark_active = selinux_secmark_enabled();
565662306a36Sopenharmony_ci	peerlbl_active = selinux_peerlbl_enabled();
565762306a36Sopenharmony_ci	if (!secmark_active && !peerlbl_active)
565862306a36Sopenharmony_ci		return NF_ACCEPT;
565962306a36Sopenharmony_ci
566062306a36Sopenharmony_ci	family = state->pf;
566162306a36Sopenharmony_ci	if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0)
566262306a36Sopenharmony_ci		return NF_DROP;
566362306a36Sopenharmony_ci
566462306a36Sopenharmony_ci	ifindex = state->in->ifindex;
566562306a36Sopenharmony_ci	ad_net_init_from_iif(&ad, &net, ifindex, family);
566662306a36Sopenharmony_ci	if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)
566762306a36Sopenharmony_ci		return NF_DROP;
566862306a36Sopenharmony_ci
566962306a36Sopenharmony_ci	if (peerlbl_active) {
567062306a36Sopenharmony_ci		int err;
567162306a36Sopenharmony_ci
567262306a36Sopenharmony_ci		err = selinux_inet_sys_rcv_skb(state->net, ifindex,
567362306a36Sopenharmony_ci					       addrp, family, peer_sid, &ad);
567462306a36Sopenharmony_ci		if (err) {
567562306a36Sopenharmony_ci			selinux_netlbl_err(skb, family, err, 1);
567662306a36Sopenharmony_ci			return NF_DROP;
567762306a36Sopenharmony_ci		}
567862306a36Sopenharmony_ci	}
567962306a36Sopenharmony_ci
568062306a36Sopenharmony_ci	if (secmark_active)
568162306a36Sopenharmony_ci		if (avc_has_perm(peer_sid, skb->secmark,
568262306a36Sopenharmony_ci				 SECCLASS_PACKET, PACKET__FORWARD_IN, &ad))
568362306a36Sopenharmony_ci			return NF_DROP;
568462306a36Sopenharmony_ci
568562306a36Sopenharmony_ci	if (netlbl_enabled())
568662306a36Sopenharmony_ci		/* we do this in the FORWARD path and not the POST_ROUTING
568762306a36Sopenharmony_ci		 * path because we want to make sure we apply the necessary
568862306a36Sopenharmony_ci		 * labeling before IPsec is applied so we can leverage AH
568962306a36Sopenharmony_ci		 * protection */
569062306a36Sopenharmony_ci		if (selinux_netlbl_skbuff_setsid(skb, family, peer_sid) != 0)
569162306a36Sopenharmony_ci			return NF_DROP;
569262306a36Sopenharmony_ci
569362306a36Sopenharmony_ci	return NF_ACCEPT;
569462306a36Sopenharmony_ci}
569562306a36Sopenharmony_ci
569662306a36Sopenharmony_cistatic unsigned int selinux_ip_output(void *priv, struct sk_buff *skb,
569762306a36Sopenharmony_ci				      const struct nf_hook_state *state)
569862306a36Sopenharmony_ci{
569962306a36Sopenharmony_ci	struct sock *sk;
570062306a36Sopenharmony_ci	u32 sid;
570162306a36Sopenharmony_ci
570262306a36Sopenharmony_ci	if (!netlbl_enabled())
570362306a36Sopenharmony_ci		return NF_ACCEPT;
570462306a36Sopenharmony_ci
570562306a36Sopenharmony_ci	/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
570662306a36Sopenharmony_ci	 * because we want to make sure we apply the necessary labeling
570762306a36Sopenharmony_ci	 * before IPsec is applied so we can leverage AH protection */
570862306a36Sopenharmony_ci	sk = skb->sk;
570962306a36Sopenharmony_ci	if (sk) {
571062306a36Sopenharmony_ci		struct sk_security_struct *sksec;
571162306a36Sopenharmony_ci
571262306a36Sopenharmony_ci		if (sk_listener(sk))
571362306a36Sopenharmony_ci			/* if the socket is the listening state then this
571462306a36Sopenharmony_ci			 * packet is a SYN-ACK packet which means it needs to
571562306a36Sopenharmony_ci			 * be labeled based on the connection/request_sock and
571662306a36Sopenharmony_ci			 * not the parent socket.  unfortunately, we can't
571762306a36Sopenharmony_ci			 * lookup the request_sock yet as it isn't queued on
571862306a36Sopenharmony_ci			 * the parent socket until after the SYN-ACK is sent.
571962306a36Sopenharmony_ci			 * the "solution" is to simply pass the packet as-is
572062306a36Sopenharmony_ci			 * as any IP option based labeling should be copied
572162306a36Sopenharmony_ci			 * from the initial connection request (in the IP
572262306a36Sopenharmony_ci			 * layer).  it is far from ideal, but until we get a
572362306a36Sopenharmony_ci			 * security label in the packet itself this is the
572462306a36Sopenharmony_ci			 * best we can do. */
572562306a36Sopenharmony_ci			return NF_ACCEPT;
572662306a36Sopenharmony_ci
572762306a36Sopenharmony_ci		/* standard practice, label using the parent socket */
572862306a36Sopenharmony_ci		sksec = sk->sk_security;
572962306a36Sopenharmony_ci		sid = sksec->sid;
573062306a36Sopenharmony_ci	} else
573162306a36Sopenharmony_ci		sid = SECINITSID_KERNEL;
573262306a36Sopenharmony_ci	if (selinux_netlbl_skbuff_setsid(skb, state->pf, sid) != 0)
573362306a36Sopenharmony_ci		return NF_DROP;
573462306a36Sopenharmony_ci
573562306a36Sopenharmony_ci	return NF_ACCEPT;
573662306a36Sopenharmony_ci}
573762306a36Sopenharmony_ci
573862306a36Sopenharmony_ci
573962306a36Sopenharmony_cistatic unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
574062306a36Sopenharmony_ci					const struct nf_hook_state *state)
574162306a36Sopenharmony_ci{
574262306a36Sopenharmony_ci	struct sock *sk;
574362306a36Sopenharmony_ci	struct sk_security_struct *sksec;
574462306a36Sopenharmony_ci	struct common_audit_data ad;
574562306a36Sopenharmony_ci	struct lsm_network_audit net;
574662306a36Sopenharmony_ci	u8 proto = 0;
574762306a36Sopenharmony_ci
574862306a36Sopenharmony_ci	sk = skb_to_full_sk(skb);
574962306a36Sopenharmony_ci	if (sk == NULL)
575062306a36Sopenharmony_ci		return NF_ACCEPT;
575162306a36Sopenharmony_ci	sksec = sk->sk_security;
575262306a36Sopenharmony_ci
575362306a36Sopenharmony_ci	ad_net_init_from_iif(&ad, &net, state->out->ifindex, state->pf);
575462306a36Sopenharmony_ci	if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))
575562306a36Sopenharmony_ci		return NF_DROP;
575662306a36Sopenharmony_ci
575762306a36Sopenharmony_ci	if (selinux_secmark_enabled())
575862306a36Sopenharmony_ci		if (avc_has_perm(sksec->sid, skb->secmark,
575962306a36Sopenharmony_ci				 SECCLASS_PACKET, PACKET__SEND, &ad))
576062306a36Sopenharmony_ci			return NF_DROP_ERR(-ECONNREFUSED);
576162306a36Sopenharmony_ci
576262306a36Sopenharmony_ci	if (selinux_xfrm_postroute_last(sksec->sid, skb, &ad, proto))
576362306a36Sopenharmony_ci		return NF_DROP_ERR(-ECONNREFUSED);
576462306a36Sopenharmony_ci
576562306a36Sopenharmony_ci	return NF_ACCEPT;
576662306a36Sopenharmony_ci}
576762306a36Sopenharmony_ci
576862306a36Sopenharmony_cistatic unsigned int selinux_ip_postroute(void *priv,
576962306a36Sopenharmony_ci					 struct sk_buff *skb,
577062306a36Sopenharmony_ci					 const struct nf_hook_state *state)
577162306a36Sopenharmony_ci{
577262306a36Sopenharmony_ci	u16 family;
577362306a36Sopenharmony_ci	u32 secmark_perm;
577462306a36Sopenharmony_ci	u32 peer_sid;
577562306a36Sopenharmony_ci	int ifindex;
577662306a36Sopenharmony_ci	struct sock *sk;
577762306a36Sopenharmony_ci	struct common_audit_data ad;
577862306a36Sopenharmony_ci	struct lsm_network_audit net;
577962306a36Sopenharmony_ci	char *addrp;
578062306a36Sopenharmony_ci	int secmark_active, peerlbl_active;
578162306a36Sopenharmony_ci
578262306a36Sopenharmony_ci	/* If any sort of compatibility mode is enabled then handoff processing
578362306a36Sopenharmony_ci	 * to the selinux_ip_postroute_compat() function to deal with the
578462306a36Sopenharmony_ci	 * special handling.  We do this in an attempt to keep this function
578562306a36Sopenharmony_ci	 * as fast and as clean as possible. */
578662306a36Sopenharmony_ci	if (!selinux_policycap_netpeer())
578762306a36Sopenharmony_ci		return selinux_ip_postroute_compat(skb, state);
578862306a36Sopenharmony_ci
578962306a36Sopenharmony_ci	secmark_active = selinux_secmark_enabled();
579062306a36Sopenharmony_ci	peerlbl_active = selinux_peerlbl_enabled();
579162306a36Sopenharmony_ci	if (!secmark_active && !peerlbl_active)
579262306a36Sopenharmony_ci		return NF_ACCEPT;
579362306a36Sopenharmony_ci
579462306a36Sopenharmony_ci	sk = skb_to_full_sk(skb);
579562306a36Sopenharmony_ci
579662306a36Sopenharmony_ci#ifdef CONFIG_XFRM
579762306a36Sopenharmony_ci	/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
579862306a36Sopenharmony_ci	 * packet transformation so allow the packet to pass without any checks
579962306a36Sopenharmony_ci	 * since we'll have another chance to perform access control checks
580062306a36Sopenharmony_ci	 * when the packet is on it's final way out.
580162306a36Sopenharmony_ci	 * NOTE: there appear to be some IPv6 multicast cases where skb->dst
580262306a36Sopenharmony_ci	 *       is NULL, in this case go ahead and apply access control.
580362306a36Sopenharmony_ci	 * NOTE: if this is a local socket (skb->sk != NULL) that is in the
580462306a36Sopenharmony_ci	 *       TCP listening state we cannot wait until the XFRM processing
580562306a36Sopenharmony_ci	 *       is done as we will miss out on the SA label if we do;
580662306a36Sopenharmony_ci	 *       unfortunately, this means more work, but it is only once per
580762306a36Sopenharmony_ci	 *       connection. */
580862306a36Sopenharmony_ci	if (skb_dst(skb) != NULL && skb_dst(skb)->xfrm != NULL &&
580962306a36Sopenharmony_ci	    !(sk && sk_listener(sk)))
581062306a36Sopenharmony_ci		return NF_ACCEPT;
581162306a36Sopenharmony_ci#endif
581262306a36Sopenharmony_ci
581362306a36Sopenharmony_ci	family = state->pf;
581462306a36Sopenharmony_ci	if (sk == NULL) {
581562306a36Sopenharmony_ci		/* Without an associated socket the packet is either coming
581662306a36Sopenharmony_ci		 * from the kernel or it is being forwarded; check the packet
581762306a36Sopenharmony_ci		 * to determine which and if the packet is being forwarded
581862306a36Sopenharmony_ci		 * query the packet directly to determine the security label. */
581962306a36Sopenharmony_ci		if (skb->skb_iif) {
582062306a36Sopenharmony_ci			secmark_perm = PACKET__FORWARD_OUT;
582162306a36Sopenharmony_ci			if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
582262306a36Sopenharmony_ci				return NF_DROP;
582362306a36Sopenharmony_ci		} else {
582462306a36Sopenharmony_ci			secmark_perm = PACKET__SEND;
582562306a36Sopenharmony_ci			peer_sid = SECINITSID_KERNEL;
582662306a36Sopenharmony_ci		}
582762306a36Sopenharmony_ci	} else if (sk_listener(sk)) {
582862306a36Sopenharmony_ci		/* Locally generated packet but the associated socket is in the
582962306a36Sopenharmony_ci		 * listening state which means this is a SYN-ACK packet.  In
583062306a36Sopenharmony_ci		 * this particular case the correct security label is assigned
583162306a36Sopenharmony_ci		 * to the connection/request_sock but unfortunately we can't
583262306a36Sopenharmony_ci		 * query the request_sock as it isn't queued on the parent
583362306a36Sopenharmony_ci		 * socket until after the SYN-ACK packet is sent; the only
583462306a36Sopenharmony_ci		 * viable choice is to regenerate the label like we do in
583562306a36Sopenharmony_ci		 * selinux_inet_conn_request().  See also selinux_ip_output()
583662306a36Sopenharmony_ci		 * for similar problems. */
583762306a36Sopenharmony_ci		u32 skb_sid;
583862306a36Sopenharmony_ci		struct sk_security_struct *sksec;
583962306a36Sopenharmony_ci
584062306a36Sopenharmony_ci		sksec = sk->sk_security;
584162306a36Sopenharmony_ci		if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
584262306a36Sopenharmony_ci			return NF_DROP;
584362306a36Sopenharmony_ci		/* At this point, if the returned skb peerlbl is SECSID_NULL
584462306a36Sopenharmony_ci		 * and the packet has been through at least one XFRM
584562306a36Sopenharmony_ci		 * transformation then we must be dealing with the "final"
584662306a36Sopenharmony_ci		 * form of labeled IPsec packet; since we've already applied
584762306a36Sopenharmony_ci		 * all of our access controls on this packet we can safely
584862306a36Sopenharmony_ci		 * pass the packet. */
584962306a36Sopenharmony_ci		if (skb_sid == SECSID_NULL) {
585062306a36Sopenharmony_ci			switch (family) {
585162306a36Sopenharmony_ci			case PF_INET:
585262306a36Sopenharmony_ci				if (IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED)
585362306a36Sopenharmony_ci					return NF_ACCEPT;
585462306a36Sopenharmony_ci				break;
585562306a36Sopenharmony_ci			case PF_INET6:
585662306a36Sopenharmony_ci				if (IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED)
585762306a36Sopenharmony_ci					return NF_ACCEPT;
585862306a36Sopenharmony_ci				break;
585962306a36Sopenharmony_ci			default:
586062306a36Sopenharmony_ci				return NF_DROP_ERR(-ECONNREFUSED);
586162306a36Sopenharmony_ci			}
586262306a36Sopenharmony_ci		}
586362306a36Sopenharmony_ci		if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid))
586462306a36Sopenharmony_ci			return NF_DROP;
586562306a36Sopenharmony_ci		secmark_perm = PACKET__SEND;
586662306a36Sopenharmony_ci	} else {
586762306a36Sopenharmony_ci		/* Locally generated packet, fetch the security label from the
586862306a36Sopenharmony_ci		 * associated socket. */
586962306a36Sopenharmony_ci		struct sk_security_struct *sksec = sk->sk_security;
587062306a36Sopenharmony_ci		peer_sid = sksec->sid;
587162306a36Sopenharmony_ci		secmark_perm = PACKET__SEND;
587262306a36Sopenharmony_ci	}
587362306a36Sopenharmony_ci
587462306a36Sopenharmony_ci	ifindex = state->out->ifindex;
587562306a36Sopenharmony_ci	ad_net_init_from_iif(&ad, &net, ifindex, family);
587662306a36Sopenharmony_ci	if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))
587762306a36Sopenharmony_ci		return NF_DROP;
587862306a36Sopenharmony_ci
587962306a36Sopenharmony_ci	if (secmark_active)
588062306a36Sopenharmony_ci		if (avc_has_perm(peer_sid, skb->secmark,
588162306a36Sopenharmony_ci				 SECCLASS_PACKET, secmark_perm, &ad))
588262306a36Sopenharmony_ci			return NF_DROP_ERR(-ECONNREFUSED);
588362306a36Sopenharmony_ci
588462306a36Sopenharmony_ci	if (peerlbl_active) {
588562306a36Sopenharmony_ci		u32 if_sid;
588662306a36Sopenharmony_ci		u32 node_sid;
588762306a36Sopenharmony_ci
588862306a36Sopenharmony_ci		if (sel_netif_sid(state->net, ifindex, &if_sid))
588962306a36Sopenharmony_ci			return NF_DROP;
589062306a36Sopenharmony_ci		if (avc_has_perm(peer_sid, if_sid,
589162306a36Sopenharmony_ci				 SECCLASS_NETIF, NETIF__EGRESS, &ad))
589262306a36Sopenharmony_ci			return NF_DROP_ERR(-ECONNREFUSED);
589362306a36Sopenharmony_ci
589462306a36Sopenharmony_ci		if (sel_netnode_sid(addrp, family, &node_sid))
589562306a36Sopenharmony_ci			return NF_DROP;
589662306a36Sopenharmony_ci		if (avc_has_perm(peer_sid, node_sid,
589762306a36Sopenharmony_ci				 SECCLASS_NODE, NODE__SENDTO, &ad))
589862306a36Sopenharmony_ci			return NF_DROP_ERR(-ECONNREFUSED);
589962306a36Sopenharmony_ci	}
590062306a36Sopenharmony_ci
590162306a36Sopenharmony_ci	return NF_ACCEPT;
590262306a36Sopenharmony_ci}
590362306a36Sopenharmony_ci#endif	/* CONFIG_NETFILTER */
590462306a36Sopenharmony_ci
590562306a36Sopenharmony_cistatic int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
590662306a36Sopenharmony_ci{
590762306a36Sopenharmony_ci	int rc = 0;
590862306a36Sopenharmony_ci	unsigned int msg_len;
590962306a36Sopenharmony_ci	unsigned int data_len = skb->len;
591062306a36Sopenharmony_ci	unsigned char *data = skb->data;
591162306a36Sopenharmony_ci	struct nlmsghdr *nlh;
591262306a36Sopenharmony_ci	struct sk_security_struct *sksec = sk->sk_security;
591362306a36Sopenharmony_ci	u16 sclass = sksec->sclass;
591462306a36Sopenharmony_ci	u32 perm;
591562306a36Sopenharmony_ci
591662306a36Sopenharmony_ci	while (data_len >= nlmsg_total_size(0)) {
591762306a36Sopenharmony_ci		nlh = (struct nlmsghdr *)data;
591862306a36Sopenharmony_ci
591962306a36Sopenharmony_ci		/* NOTE: the nlmsg_len field isn't reliably set by some netlink
592062306a36Sopenharmony_ci		 *       users which means we can't reject skb's with bogus
592162306a36Sopenharmony_ci		 *       length fields; our solution is to follow what
592262306a36Sopenharmony_ci		 *       netlink_rcv_skb() does and simply skip processing at
592362306a36Sopenharmony_ci		 *       messages with length fields that are clearly junk
592462306a36Sopenharmony_ci		 */
592562306a36Sopenharmony_ci		if (nlh->nlmsg_len < NLMSG_HDRLEN || nlh->nlmsg_len > data_len)
592662306a36Sopenharmony_ci			return 0;
592762306a36Sopenharmony_ci
592862306a36Sopenharmony_ci		rc = selinux_nlmsg_lookup(sclass, nlh->nlmsg_type, &perm);
592962306a36Sopenharmony_ci		if (rc == 0) {
593062306a36Sopenharmony_ci			rc = sock_has_perm(sk, perm);
593162306a36Sopenharmony_ci			if (rc)
593262306a36Sopenharmony_ci				return rc;
593362306a36Sopenharmony_ci		} else if (rc == -EINVAL) {
593462306a36Sopenharmony_ci			/* -EINVAL is a missing msg/perm mapping */
593562306a36Sopenharmony_ci			pr_warn_ratelimited("SELinux: unrecognized netlink"
593662306a36Sopenharmony_ci				" message: protocol=%hu nlmsg_type=%hu sclass=%s"
593762306a36Sopenharmony_ci				" pid=%d comm=%s\n",
593862306a36Sopenharmony_ci				sk->sk_protocol, nlh->nlmsg_type,
593962306a36Sopenharmony_ci				secclass_map[sclass - 1].name,
594062306a36Sopenharmony_ci				task_pid_nr(current), current->comm);
594162306a36Sopenharmony_ci			if (enforcing_enabled() &&
594262306a36Sopenharmony_ci			    !security_get_allow_unknown())
594362306a36Sopenharmony_ci				return rc;
594462306a36Sopenharmony_ci			rc = 0;
594562306a36Sopenharmony_ci		} else if (rc == -ENOENT) {
594662306a36Sopenharmony_ci			/* -ENOENT is a missing socket/class mapping, ignore */
594762306a36Sopenharmony_ci			rc = 0;
594862306a36Sopenharmony_ci		} else {
594962306a36Sopenharmony_ci			return rc;
595062306a36Sopenharmony_ci		}
595162306a36Sopenharmony_ci
595262306a36Sopenharmony_ci		/* move to the next message after applying netlink padding */
595362306a36Sopenharmony_ci		msg_len = NLMSG_ALIGN(nlh->nlmsg_len);
595462306a36Sopenharmony_ci		if (msg_len >= data_len)
595562306a36Sopenharmony_ci			return 0;
595662306a36Sopenharmony_ci		data_len -= msg_len;
595762306a36Sopenharmony_ci		data += msg_len;
595862306a36Sopenharmony_ci	}
595962306a36Sopenharmony_ci
596062306a36Sopenharmony_ci	return rc;
596162306a36Sopenharmony_ci}
596262306a36Sopenharmony_ci
596362306a36Sopenharmony_cistatic void ipc_init_security(struct ipc_security_struct *isec, u16 sclass)
596462306a36Sopenharmony_ci{
596562306a36Sopenharmony_ci	isec->sclass = sclass;
596662306a36Sopenharmony_ci	isec->sid = current_sid();
596762306a36Sopenharmony_ci}
596862306a36Sopenharmony_ci
596962306a36Sopenharmony_cistatic int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
597062306a36Sopenharmony_ci			u32 perms)
597162306a36Sopenharmony_ci{
597262306a36Sopenharmony_ci	struct ipc_security_struct *isec;
597362306a36Sopenharmony_ci	struct common_audit_data ad;
597462306a36Sopenharmony_ci	u32 sid = current_sid();
597562306a36Sopenharmony_ci
597662306a36Sopenharmony_ci	isec = selinux_ipc(ipc_perms);
597762306a36Sopenharmony_ci
597862306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IPC;
597962306a36Sopenharmony_ci	ad.u.ipc_id = ipc_perms->key;
598062306a36Sopenharmony_ci
598162306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad);
598262306a36Sopenharmony_ci}
598362306a36Sopenharmony_ci
598462306a36Sopenharmony_cistatic int selinux_msg_msg_alloc_security(struct msg_msg *msg)
598562306a36Sopenharmony_ci{
598662306a36Sopenharmony_ci	struct msg_security_struct *msec;
598762306a36Sopenharmony_ci
598862306a36Sopenharmony_ci	msec = selinux_msg_msg(msg);
598962306a36Sopenharmony_ci	msec->sid = SECINITSID_UNLABELED;
599062306a36Sopenharmony_ci
599162306a36Sopenharmony_ci	return 0;
599262306a36Sopenharmony_ci}
599362306a36Sopenharmony_ci
599462306a36Sopenharmony_ci/* message queue security operations */
599562306a36Sopenharmony_cistatic int selinux_msg_queue_alloc_security(struct kern_ipc_perm *msq)
599662306a36Sopenharmony_ci{
599762306a36Sopenharmony_ci	struct ipc_security_struct *isec;
599862306a36Sopenharmony_ci	struct common_audit_data ad;
599962306a36Sopenharmony_ci	u32 sid = current_sid();
600062306a36Sopenharmony_ci
600162306a36Sopenharmony_ci	isec = selinux_ipc(msq);
600262306a36Sopenharmony_ci	ipc_init_security(isec, SECCLASS_MSGQ);
600362306a36Sopenharmony_ci
600462306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IPC;
600562306a36Sopenharmony_ci	ad.u.ipc_id = msq->key;
600662306a36Sopenharmony_ci
600762306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
600862306a36Sopenharmony_ci			    MSGQ__CREATE, &ad);
600962306a36Sopenharmony_ci}
601062306a36Sopenharmony_ci
601162306a36Sopenharmony_cistatic int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)
601262306a36Sopenharmony_ci{
601362306a36Sopenharmony_ci	struct ipc_security_struct *isec;
601462306a36Sopenharmony_ci	struct common_audit_data ad;
601562306a36Sopenharmony_ci	u32 sid = current_sid();
601662306a36Sopenharmony_ci
601762306a36Sopenharmony_ci	isec = selinux_ipc(msq);
601862306a36Sopenharmony_ci
601962306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IPC;
602062306a36Sopenharmony_ci	ad.u.ipc_id = msq->key;
602162306a36Sopenharmony_ci
602262306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
602362306a36Sopenharmony_ci			    MSGQ__ASSOCIATE, &ad);
602462306a36Sopenharmony_ci}
602562306a36Sopenharmony_ci
602662306a36Sopenharmony_cistatic int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)
602762306a36Sopenharmony_ci{
602862306a36Sopenharmony_ci	u32 perms;
602962306a36Sopenharmony_ci
603062306a36Sopenharmony_ci	switch (cmd) {
603162306a36Sopenharmony_ci	case IPC_INFO:
603262306a36Sopenharmony_ci	case MSG_INFO:
603362306a36Sopenharmony_ci		/* No specific object, just general system-wide information. */
603462306a36Sopenharmony_ci		return avc_has_perm(current_sid(), SECINITSID_KERNEL,
603562306a36Sopenharmony_ci				    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
603662306a36Sopenharmony_ci	case IPC_STAT:
603762306a36Sopenharmony_ci	case MSG_STAT:
603862306a36Sopenharmony_ci	case MSG_STAT_ANY:
603962306a36Sopenharmony_ci		perms = MSGQ__GETATTR | MSGQ__ASSOCIATE;
604062306a36Sopenharmony_ci		break;
604162306a36Sopenharmony_ci	case IPC_SET:
604262306a36Sopenharmony_ci		perms = MSGQ__SETATTR;
604362306a36Sopenharmony_ci		break;
604462306a36Sopenharmony_ci	case IPC_RMID:
604562306a36Sopenharmony_ci		perms = MSGQ__DESTROY;
604662306a36Sopenharmony_ci		break;
604762306a36Sopenharmony_ci	default:
604862306a36Sopenharmony_ci		return 0;
604962306a36Sopenharmony_ci	}
605062306a36Sopenharmony_ci
605162306a36Sopenharmony_ci	return ipc_has_perm(msq, perms);
605262306a36Sopenharmony_ci}
605362306a36Sopenharmony_ci
605462306a36Sopenharmony_cistatic int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg)
605562306a36Sopenharmony_ci{
605662306a36Sopenharmony_ci	struct ipc_security_struct *isec;
605762306a36Sopenharmony_ci	struct msg_security_struct *msec;
605862306a36Sopenharmony_ci	struct common_audit_data ad;
605962306a36Sopenharmony_ci	u32 sid = current_sid();
606062306a36Sopenharmony_ci	int rc;
606162306a36Sopenharmony_ci
606262306a36Sopenharmony_ci	isec = selinux_ipc(msq);
606362306a36Sopenharmony_ci	msec = selinux_msg_msg(msg);
606462306a36Sopenharmony_ci
606562306a36Sopenharmony_ci	/*
606662306a36Sopenharmony_ci	 * First time through, need to assign label to the message
606762306a36Sopenharmony_ci	 */
606862306a36Sopenharmony_ci	if (msec->sid == SECINITSID_UNLABELED) {
606962306a36Sopenharmony_ci		/*
607062306a36Sopenharmony_ci		 * Compute new sid based on current process and
607162306a36Sopenharmony_ci		 * message queue this message will be stored in
607262306a36Sopenharmony_ci		 */
607362306a36Sopenharmony_ci		rc = security_transition_sid(sid, isec->sid,
607462306a36Sopenharmony_ci					     SECCLASS_MSG, NULL, &msec->sid);
607562306a36Sopenharmony_ci		if (rc)
607662306a36Sopenharmony_ci			return rc;
607762306a36Sopenharmony_ci	}
607862306a36Sopenharmony_ci
607962306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IPC;
608062306a36Sopenharmony_ci	ad.u.ipc_id = msq->key;
608162306a36Sopenharmony_ci
608262306a36Sopenharmony_ci	/* Can this process write to the queue? */
608362306a36Sopenharmony_ci	rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ,
608462306a36Sopenharmony_ci			  MSGQ__WRITE, &ad);
608562306a36Sopenharmony_ci	if (!rc)
608662306a36Sopenharmony_ci		/* Can this process send the message */
608762306a36Sopenharmony_ci		rc = avc_has_perm(sid, msec->sid, SECCLASS_MSG,
608862306a36Sopenharmony_ci				  MSG__SEND, &ad);
608962306a36Sopenharmony_ci	if (!rc)
609062306a36Sopenharmony_ci		/* Can the message be put in the queue? */
609162306a36Sopenharmony_ci		rc = avc_has_perm(msec->sid, isec->sid, SECCLASS_MSGQ,
609262306a36Sopenharmony_ci				  MSGQ__ENQUEUE, &ad);
609362306a36Sopenharmony_ci
609462306a36Sopenharmony_ci	return rc;
609562306a36Sopenharmony_ci}
609662306a36Sopenharmony_ci
609762306a36Sopenharmony_cistatic int selinux_msg_queue_msgrcv(struct kern_ipc_perm *msq, struct msg_msg *msg,
609862306a36Sopenharmony_ci				    struct task_struct *target,
609962306a36Sopenharmony_ci				    long type, int mode)
610062306a36Sopenharmony_ci{
610162306a36Sopenharmony_ci	struct ipc_security_struct *isec;
610262306a36Sopenharmony_ci	struct msg_security_struct *msec;
610362306a36Sopenharmony_ci	struct common_audit_data ad;
610462306a36Sopenharmony_ci	u32 sid = task_sid_obj(target);
610562306a36Sopenharmony_ci	int rc;
610662306a36Sopenharmony_ci
610762306a36Sopenharmony_ci	isec = selinux_ipc(msq);
610862306a36Sopenharmony_ci	msec = selinux_msg_msg(msg);
610962306a36Sopenharmony_ci
611062306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IPC;
611162306a36Sopenharmony_ci	ad.u.ipc_id = msq->key;
611262306a36Sopenharmony_ci
611362306a36Sopenharmony_ci	rc = avc_has_perm(sid, isec->sid,
611462306a36Sopenharmony_ci			  SECCLASS_MSGQ, MSGQ__READ, &ad);
611562306a36Sopenharmony_ci	if (!rc)
611662306a36Sopenharmony_ci		rc = avc_has_perm(sid, msec->sid,
611762306a36Sopenharmony_ci				  SECCLASS_MSG, MSG__RECEIVE, &ad);
611862306a36Sopenharmony_ci	return rc;
611962306a36Sopenharmony_ci}
612062306a36Sopenharmony_ci
612162306a36Sopenharmony_ci/* Shared Memory security operations */
612262306a36Sopenharmony_cistatic int selinux_shm_alloc_security(struct kern_ipc_perm *shp)
612362306a36Sopenharmony_ci{
612462306a36Sopenharmony_ci	struct ipc_security_struct *isec;
612562306a36Sopenharmony_ci	struct common_audit_data ad;
612662306a36Sopenharmony_ci	u32 sid = current_sid();
612762306a36Sopenharmony_ci
612862306a36Sopenharmony_ci	isec = selinux_ipc(shp);
612962306a36Sopenharmony_ci	ipc_init_security(isec, SECCLASS_SHM);
613062306a36Sopenharmony_ci
613162306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IPC;
613262306a36Sopenharmony_ci	ad.u.ipc_id = shp->key;
613362306a36Sopenharmony_ci
613462306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
613562306a36Sopenharmony_ci			    SHM__CREATE, &ad);
613662306a36Sopenharmony_ci}
613762306a36Sopenharmony_ci
613862306a36Sopenharmony_cistatic int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)
613962306a36Sopenharmony_ci{
614062306a36Sopenharmony_ci	struct ipc_security_struct *isec;
614162306a36Sopenharmony_ci	struct common_audit_data ad;
614262306a36Sopenharmony_ci	u32 sid = current_sid();
614362306a36Sopenharmony_ci
614462306a36Sopenharmony_ci	isec = selinux_ipc(shp);
614562306a36Sopenharmony_ci
614662306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IPC;
614762306a36Sopenharmony_ci	ad.u.ipc_id = shp->key;
614862306a36Sopenharmony_ci
614962306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, SECCLASS_SHM,
615062306a36Sopenharmony_ci			    SHM__ASSOCIATE, &ad);
615162306a36Sopenharmony_ci}
615262306a36Sopenharmony_ci
615362306a36Sopenharmony_ci/* Note, at this point, shp is locked down */
615462306a36Sopenharmony_cistatic int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)
615562306a36Sopenharmony_ci{
615662306a36Sopenharmony_ci	u32 perms;
615762306a36Sopenharmony_ci
615862306a36Sopenharmony_ci	switch (cmd) {
615962306a36Sopenharmony_ci	case IPC_INFO:
616062306a36Sopenharmony_ci	case SHM_INFO:
616162306a36Sopenharmony_ci		/* No specific object, just general system-wide information. */
616262306a36Sopenharmony_ci		return avc_has_perm(current_sid(), SECINITSID_KERNEL,
616362306a36Sopenharmony_ci				    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
616462306a36Sopenharmony_ci	case IPC_STAT:
616562306a36Sopenharmony_ci	case SHM_STAT:
616662306a36Sopenharmony_ci	case SHM_STAT_ANY:
616762306a36Sopenharmony_ci		perms = SHM__GETATTR | SHM__ASSOCIATE;
616862306a36Sopenharmony_ci		break;
616962306a36Sopenharmony_ci	case IPC_SET:
617062306a36Sopenharmony_ci		perms = SHM__SETATTR;
617162306a36Sopenharmony_ci		break;
617262306a36Sopenharmony_ci	case SHM_LOCK:
617362306a36Sopenharmony_ci	case SHM_UNLOCK:
617462306a36Sopenharmony_ci		perms = SHM__LOCK;
617562306a36Sopenharmony_ci		break;
617662306a36Sopenharmony_ci	case IPC_RMID:
617762306a36Sopenharmony_ci		perms = SHM__DESTROY;
617862306a36Sopenharmony_ci		break;
617962306a36Sopenharmony_ci	default:
618062306a36Sopenharmony_ci		return 0;
618162306a36Sopenharmony_ci	}
618262306a36Sopenharmony_ci
618362306a36Sopenharmony_ci	return ipc_has_perm(shp, perms);
618462306a36Sopenharmony_ci}
618562306a36Sopenharmony_ci
618662306a36Sopenharmony_cistatic int selinux_shm_shmat(struct kern_ipc_perm *shp,
618762306a36Sopenharmony_ci			     char __user *shmaddr, int shmflg)
618862306a36Sopenharmony_ci{
618962306a36Sopenharmony_ci	u32 perms;
619062306a36Sopenharmony_ci
619162306a36Sopenharmony_ci	if (shmflg & SHM_RDONLY)
619262306a36Sopenharmony_ci		perms = SHM__READ;
619362306a36Sopenharmony_ci	else
619462306a36Sopenharmony_ci		perms = SHM__READ | SHM__WRITE;
619562306a36Sopenharmony_ci
619662306a36Sopenharmony_ci	return ipc_has_perm(shp, perms);
619762306a36Sopenharmony_ci}
619862306a36Sopenharmony_ci
619962306a36Sopenharmony_ci/* Semaphore security operations */
620062306a36Sopenharmony_cistatic int selinux_sem_alloc_security(struct kern_ipc_perm *sma)
620162306a36Sopenharmony_ci{
620262306a36Sopenharmony_ci	struct ipc_security_struct *isec;
620362306a36Sopenharmony_ci	struct common_audit_data ad;
620462306a36Sopenharmony_ci	u32 sid = current_sid();
620562306a36Sopenharmony_ci
620662306a36Sopenharmony_ci	isec = selinux_ipc(sma);
620762306a36Sopenharmony_ci	ipc_init_security(isec, SECCLASS_SEM);
620862306a36Sopenharmony_ci
620962306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IPC;
621062306a36Sopenharmony_ci	ad.u.ipc_id = sma->key;
621162306a36Sopenharmony_ci
621262306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
621362306a36Sopenharmony_ci			    SEM__CREATE, &ad);
621462306a36Sopenharmony_ci}
621562306a36Sopenharmony_ci
621662306a36Sopenharmony_cistatic int selinux_sem_associate(struct kern_ipc_perm *sma, int semflg)
621762306a36Sopenharmony_ci{
621862306a36Sopenharmony_ci	struct ipc_security_struct *isec;
621962306a36Sopenharmony_ci	struct common_audit_data ad;
622062306a36Sopenharmony_ci	u32 sid = current_sid();
622162306a36Sopenharmony_ci
622262306a36Sopenharmony_ci	isec = selinux_ipc(sma);
622362306a36Sopenharmony_ci
622462306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IPC;
622562306a36Sopenharmony_ci	ad.u.ipc_id = sma->key;
622662306a36Sopenharmony_ci
622762306a36Sopenharmony_ci	return avc_has_perm(sid, isec->sid, SECCLASS_SEM,
622862306a36Sopenharmony_ci			    SEM__ASSOCIATE, &ad);
622962306a36Sopenharmony_ci}
623062306a36Sopenharmony_ci
623162306a36Sopenharmony_ci/* Note, at this point, sma is locked down */
623262306a36Sopenharmony_cistatic int selinux_sem_semctl(struct kern_ipc_perm *sma, int cmd)
623362306a36Sopenharmony_ci{
623462306a36Sopenharmony_ci	int err;
623562306a36Sopenharmony_ci	u32 perms;
623662306a36Sopenharmony_ci
623762306a36Sopenharmony_ci	switch (cmd) {
623862306a36Sopenharmony_ci	case IPC_INFO:
623962306a36Sopenharmony_ci	case SEM_INFO:
624062306a36Sopenharmony_ci		/* No specific object, just general system-wide information. */
624162306a36Sopenharmony_ci		return avc_has_perm(current_sid(), SECINITSID_KERNEL,
624262306a36Sopenharmony_ci				    SECCLASS_SYSTEM, SYSTEM__IPC_INFO, NULL);
624362306a36Sopenharmony_ci	case GETPID:
624462306a36Sopenharmony_ci	case GETNCNT:
624562306a36Sopenharmony_ci	case GETZCNT:
624662306a36Sopenharmony_ci		perms = SEM__GETATTR;
624762306a36Sopenharmony_ci		break;
624862306a36Sopenharmony_ci	case GETVAL:
624962306a36Sopenharmony_ci	case GETALL:
625062306a36Sopenharmony_ci		perms = SEM__READ;
625162306a36Sopenharmony_ci		break;
625262306a36Sopenharmony_ci	case SETVAL:
625362306a36Sopenharmony_ci	case SETALL:
625462306a36Sopenharmony_ci		perms = SEM__WRITE;
625562306a36Sopenharmony_ci		break;
625662306a36Sopenharmony_ci	case IPC_RMID:
625762306a36Sopenharmony_ci		perms = SEM__DESTROY;
625862306a36Sopenharmony_ci		break;
625962306a36Sopenharmony_ci	case IPC_SET:
626062306a36Sopenharmony_ci		perms = SEM__SETATTR;
626162306a36Sopenharmony_ci		break;
626262306a36Sopenharmony_ci	case IPC_STAT:
626362306a36Sopenharmony_ci	case SEM_STAT:
626462306a36Sopenharmony_ci	case SEM_STAT_ANY:
626562306a36Sopenharmony_ci		perms = SEM__GETATTR | SEM__ASSOCIATE;
626662306a36Sopenharmony_ci		break;
626762306a36Sopenharmony_ci	default:
626862306a36Sopenharmony_ci		return 0;
626962306a36Sopenharmony_ci	}
627062306a36Sopenharmony_ci
627162306a36Sopenharmony_ci	err = ipc_has_perm(sma, perms);
627262306a36Sopenharmony_ci	return err;
627362306a36Sopenharmony_ci}
627462306a36Sopenharmony_ci
627562306a36Sopenharmony_cistatic int selinux_sem_semop(struct kern_ipc_perm *sma,
627662306a36Sopenharmony_ci			     struct sembuf *sops, unsigned nsops, int alter)
627762306a36Sopenharmony_ci{
627862306a36Sopenharmony_ci	u32 perms;
627962306a36Sopenharmony_ci
628062306a36Sopenharmony_ci	if (alter)
628162306a36Sopenharmony_ci		perms = SEM__READ | SEM__WRITE;
628262306a36Sopenharmony_ci	else
628362306a36Sopenharmony_ci		perms = SEM__READ;
628462306a36Sopenharmony_ci
628562306a36Sopenharmony_ci	return ipc_has_perm(sma, perms);
628662306a36Sopenharmony_ci}
628762306a36Sopenharmony_ci
628862306a36Sopenharmony_cistatic int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
628962306a36Sopenharmony_ci{
629062306a36Sopenharmony_ci	u32 av = 0;
629162306a36Sopenharmony_ci
629262306a36Sopenharmony_ci	av = 0;
629362306a36Sopenharmony_ci	if (flag & S_IRUGO)
629462306a36Sopenharmony_ci		av |= IPC__UNIX_READ;
629562306a36Sopenharmony_ci	if (flag & S_IWUGO)
629662306a36Sopenharmony_ci		av |= IPC__UNIX_WRITE;
629762306a36Sopenharmony_ci
629862306a36Sopenharmony_ci	if (av == 0)
629962306a36Sopenharmony_ci		return 0;
630062306a36Sopenharmony_ci
630162306a36Sopenharmony_ci	return ipc_has_perm(ipcp, av);
630262306a36Sopenharmony_ci}
630362306a36Sopenharmony_ci
630462306a36Sopenharmony_cistatic void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
630562306a36Sopenharmony_ci{
630662306a36Sopenharmony_ci	struct ipc_security_struct *isec = selinux_ipc(ipcp);
630762306a36Sopenharmony_ci	*secid = isec->sid;
630862306a36Sopenharmony_ci}
630962306a36Sopenharmony_ci
631062306a36Sopenharmony_cistatic void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
631162306a36Sopenharmony_ci{
631262306a36Sopenharmony_ci	if (inode)
631362306a36Sopenharmony_ci		inode_doinit_with_dentry(inode, dentry);
631462306a36Sopenharmony_ci}
631562306a36Sopenharmony_ci
631662306a36Sopenharmony_cistatic int selinux_getprocattr(struct task_struct *p,
631762306a36Sopenharmony_ci			       const char *name, char **value)
631862306a36Sopenharmony_ci{
631962306a36Sopenharmony_ci	const struct task_security_struct *__tsec;
632062306a36Sopenharmony_ci	u32 sid;
632162306a36Sopenharmony_ci	int error;
632262306a36Sopenharmony_ci	unsigned len;
632362306a36Sopenharmony_ci
632462306a36Sopenharmony_ci	rcu_read_lock();
632562306a36Sopenharmony_ci	__tsec = selinux_cred(__task_cred(p));
632662306a36Sopenharmony_ci
632762306a36Sopenharmony_ci	if (current != p) {
632862306a36Sopenharmony_ci		error = avc_has_perm(current_sid(), __tsec->sid,
632962306a36Sopenharmony_ci				     SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
633062306a36Sopenharmony_ci		if (error)
633162306a36Sopenharmony_ci			goto bad;
633262306a36Sopenharmony_ci	}
633362306a36Sopenharmony_ci
633462306a36Sopenharmony_ci	if (!strcmp(name, "current"))
633562306a36Sopenharmony_ci		sid = __tsec->sid;
633662306a36Sopenharmony_ci	else if (!strcmp(name, "prev"))
633762306a36Sopenharmony_ci		sid = __tsec->osid;
633862306a36Sopenharmony_ci	else if (!strcmp(name, "exec"))
633962306a36Sopenharmony_ci		sid = __tsec->exec_sid;
634062306a36Sopenharmony_ci	else if (!strcmp(name, "fscreate"))
634162306a36Sopenharmony_ci		sid = __tsec->create_sid;
634262306a36Sopenharmony_ci	else if (!strcmp(name, "keycreate"))
634362306a36Sopenharmony_ci		sid = __tsec->keycreate_sid;
634462306a36Sopenharmony_ci	else if (!strcmp(name, "sockcreate"))
634562306a36Sopenharmony_ci		sid = __tsec->sockcreate_sid;
634662306a36Sopenharmony_ci	else {
634762306a36Sopenharmony_ci		error = -EINVAL;
634862306a36Sopenharmony_ci		goto bad;
634962306a36Sopenharmony_ci	}
635062306a36Sopenharmony_ci	rcu_read_unlock();
635162306a36Sopenharmony_ci
635262306a36Sopenharmony_ci	if (!sid)
635362306a36Sopenharmony_ci		return 0;
635462306a36Sopenharmony_ci
635562306a36Sopenharmony_ci	error = security_sid_to_context(sid, value, &len);
635662306a36Sopenharmony_ci	if (error)
635762306a36Sopenharmony_ci		return error;
635862306a36Sopenharmony_ci	return len;
635962306a36Sopenharmony_ci
636062306a36Sopenharmony_cibad:
636162306a36Sopenharmony_ci	rcu_read_unlock();
636262306a36Sopenharmony_ci	return error;
636362306a36Sopenharmony_ci}
636462306a36Sopenharmony_ci
636562306a36Sopenharmony_cistatic int selinux_setprocattr(const char *name, void *value, size_t size)
636662306a36Sopenharmony_ci{
636762306a36Sopenharmony_ci	struct task_security_struct *tsec;
636862306a36Sopenharmony_ci	struct cred *new;
636962306a36Sopenharmony_ci	u32 mysid = current_sid(), sid = 0, ptsid;
637062306a36Sopenharmony_ci	int error;
637162306a36Sopenharmony_ci	char *str = value;
637262306a36Sopenharmony_ci
637362306a36Sopenharmony_ci	/*
637462306a36Sopenharmony_ci	 * Basic control over ability to set these attributes at all.
637562306a36Sopenharmony_ci	 */
637662306a36Sopenharmony_ci	if (!strcmp(name, "exec"))
637762306a36Sopenharmony_ci		error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
637862306a36Sopenharmony_ci				     PROCESS__SETEXEC, NULL);
637962306a36Sopenharmony_ci	else if (!strcmp(name, "fscreate"))
638062306a36Sopenharmony_ci		error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
638162306a36Sopenharmony_ci				     PROCESS__SETFSCREATE, NULL);
638262306a36Sopenharmony_ci	else if (!strcmp(name, "keycreate"))
638362306a36Sopenharmony_ci		error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
638462306a36Sopenharmony_ci				     PROCESS__SETKEYCREATE, NULL);
638562306a36Sopenharmony_ci	else if (!strcmp(name, "sockcreate"))
638662306a36Sopenharmony_ci		error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
638762306a36Sopenharmony_ci				     PROCESS__SETSOCKCREATE, NULL);
638862306a36Sopenharmony_ci	else if (!strcmp(name, "current"))
638962306a36Sopenharmony_ci		error = avc_has_perm(mysid, mysid, SECCLASS_PROCESS,
639062306a36Sopenharmony_ci				     PROCESS__SETCURRENT, NULL);
639162306a36Sopenharmony_ci	else
639262306a36Sopenharmony_ci		error = -EINVAL;
639362306a36Sopenharmony_ci	if (error)
639462306a36Sopenharmony_ci		return error;
639562306a36Sopenharmony_ci
639662306a36Sopenharmony_ci	/* Obtain a SID for the context, if one was specified. */
639762306a36Sopenharmony_ci	if (size && str[0] && str[0] != '\n') {
639862306a36Sopenharmony_ci		if (str[size-1] == '\n') {
639962306a36Sopenharmony_ci			str[size-1] = 0;
640062306a36Sopenharmony_ci			size--;
640162306a36Sopenharmony_ci		}
640262306a36Sopenharmony_ci		error = security_context_to_sid(value, size,
640362306a36Sopenharmony_ci						&sid, GFP_KERNEL);
640462306a36Sopenharmony_ci		if (error == -EINVAL && !strcmp(name, "fscreate")) {
640562306a36Sopenharmony_ci			if (!has_cap_mac_admin(true)) {
640662306a36Sopenharmony_ci				struct audit_buffer *ab;
640762306a36Sopenharmony_ci				size_t audit_size;
640862306a36Sopenharmony_ci
640962306a36Sopenharmony_ci				/* We strip a nul only if it is at the end, otherwise the
641062306a36Sopenharmony_ci				 * context contains a nul and we should audit that */
641162306a36Sopenharmony_ci				if (str[size - 1] == '\0')
641262306a36Sopenharmony_ci					audit_size = size - 1;
641362306a36Sopenharmony_ci				else
641462306a36Sopenharmony_ci					audit_size = size;
641562306a36Sopenharmony_ci				ab = audit_log_start(audit_context(),
641662306a36Sopenharmony_ci						     GFP_ATOMIC,
641762306a36Sopenharmony_ci						     AUDIT_SELINUX_ERR);
641862306a36Sopenharmony_ci				if (!ab)
641962306a36Sopenharmony_ci					return error;
642062306a36Sopenharmony_ci				audit_log_format(ab, "op=fscreate invalid_context=");
642162306a36Sopenharmony_ci				audit_log_n_untrustedstring(ab, value, audit_size);
642262306a36Sopenharmony_ci				audit_log_end(ab);
642362306a36Sopenharmony_ci
642462306a36Sopenharmony_ci				return error;
642562306a36Sopenharmony_ci			}
642662306a36Sopenharmony_ci			error = security_context_to_sid_force(value, size,
642762306a36Sopenharmony_ci							&sid);
642862306a36Sopenharmony_ci		}
642962306a36Sopenharmony_ci		if (error)
643062306a36Sopenharmony_ci			return error;
643162306a36Sopenharmony_ci	}
643262306a36Sopenharmony_ci
643362306a36Sopenharmony_ci	new = prepare_creds();
643462306a36Sopenharmony_ci	if (!new)
643562306a36Sopenharmony_ci		return -ENOMEM;
643662306a36Sopenharmony_ci
643762306a36Sopenharmony_ci	/* Permission checking based on the specified context is
643862306a36Sopenharmony_ci	   performed during the actual operation (execve,
643962306a36Sopenharmony_ci	   open/mkdir/...), when we know the full context of the
644062306a36Sopenharmony_ci	   operation.  See selinux_bprm_creds_for_exec for the execve
644162306a36Sopenharmony_ci	   checks and may_create for the file creation checks. The
644262306a36Sopenharmony_ci	   operation will then fail if the context is not permitted. */
644362306a36Sopenharmony_ci	tsec = selinux_cred(new);
644462306a36Sopenharmony_ci	if (!strcmp(name, "exec")) {
644562306a36Sopenharmony_ci		tsec->exec_sid = sid;
644662306a36Sopenharmony_ci	} else if (!strcmp(name, "fscreate")) {
644762306a36Sopenharmony_ci		tsec->create_sid = sid;
644862306a36Sopenharmony_ci	} else if (!strcmp(name, "keycreate")) {
644962306a36Sopenharmony_ci		if (sid) {
645062306a36Sopenharmony_ci			error = avc_has_perm(mysid, sid,
645162306a36Sopenharmony_ci					     SECCLASS_KEY, KEY__CREATE, NULL);
645262306a36Sopenharmony_ci			if (error)
645362306a36Sopenharmony_ci				goto abort_change;
645462306a36Sopenharmony_ci		}
645562306a36Sopenharmony_ci		tsec->keycreate_sid = sid;
645662306a36Sopenharmony_ci	} else if (!strcmp(name, "sockcreate")) {
645762306a36Sopenharmony_ci		tsec->sockcreate_sid = sid;
645862306a36Sopenharmony_ci	} else if (!strcmp(name, "current")) {
645962306a36Sopenharmony_ci		error = -EINVAL;
646062306a36Sopenharmony_ci		if (sid == 0)
646162306a36Sopenharmony_ci			goto abort_change;
646262306a36Sopenharmony_ci
646362306a36Sopenharmony_ci		/* Only allow single threaded processes to change context */
646462306a36Sopenharmony_ci		if (!current_is_single_threaded()) {
646562306a36Sopenharmony_ci			error = security_bounded_transition(tsec->sid, sid);
646662306a36Sopenharmony_ci			if (error)
646762306a36Sopenharmony_ci				goto abort_change;
646862306a36Sopenharmony_ci		}
646962306a36Sopenharmony_ci
647062306a36Sopenharmony_ci		/* Check permissions for the transition. */
647162306a36Sopenharmony_ci		error = avc_has_perm(tsec->sid, sid, SECCLASS_PROCESS,
647262306a36Sopenharmony_ci				     PROCESS__DYNTRANSITION, NULL);
647362306a36Sopenharmony_ci		if (error)
647462306a36Sopenharmony_ci			goto abort_change;
647562306a36Sopenharmony_ci
647662306a36Sopenharmony_ci		/* Check for ptracing, and update the task SID if ok.
647762306a36Sopenharmony_ci		   Otherwise, leave SID unchanged and fail. */
647862306a36Sopenharmony_ci		ptsid = ptrace_parent_sid();
647962306a36Sopenharmony_ci		if (ptsid != 0) {
648062306a36Sopenharmony_ci			error = avc_has_perm(ptsid, sid, SECCLASS_PROCESS,
648162306a36Sopenharmony_ci					     PROCESS__PTRACE, NULL);
648262306a36Sopenharmony_ci			if (error)
648362306a36Sopenharmony_ci				goto abort_change;
648462306a36Sopenharmony_ci		}
648562306a36Sopenharmony_ci
648662306a36Sopenharmony_ci		tsec->sid = sid;
648762306a36Sopenharmony_ci	} else {
648862306a36Sopenharmony_ci		error = -EINVAL;
648962306a36Sopenharmony_ci		goto abort_change;
649062306a36Sopenharmony_ci	}
649162306a36Sopenharmony_ci
649262306a36Sopenharmony_ci	commit_creds(new);
649362306a36Sopenharmony_ci	CALL_HCK_LITE_HOOK(ced_setattr_insert_lhck, current);
649462306a36Sopenharmony_ci	return size;
649562306a36Sopenharmony_ci
649662306a36Sopenharmony_ciabort_change:
649762306a36Sopenharmony_ci	abort_creds(new);
649862306a36Sopenharmony_ci	return error;
649962306a36Sopenharmony_ci}
650062306a36Sopenharmony_ci
650162306a36Sopenharmony_cistatic int selinux_ismaclabel(const char *name)
650262306a36Sopenharmony_ci{
650362306a36Sopenharmony_ci	return (strcmp(name, XATTR_SELINUX_SUFFIX) == 0);
650462306a36Sopenharmony_ci}
650562306a36Sopenharmony_ci
650662306a36Sopenharmony_cistatic int selinux_secid_to_secctx(u32 secid, char **secdata, u32 *seclen)
650762306a36Sopenharmony_ci{
650862306a36Sopenharmony_ci	return security_sid_to_context(secid,
650962306a36Sopenharmony_ci				       secdata, seclen);
651062306a36Sopenharmony_ci}
651162306a36Sopenharmony_ci
651262306a36Sopenharmony_cistatic int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
651362306a36Sopenharmony_ci{
651462306a36Sopenharmony_ci	return security_context_to_sid(secdata, seclen,
651562306a36Sopenharmony_ci				       secid, GFP_KERNEL);
651662306a36Sopenharmony_ci}
651762306a36Sopenharmony_ci
651862306a36Sopenharmony_cistatic void selinux_release_secctx(char *secdata, u32 seclen)
651962306a36Sopenharmony_ci{
652062306a36Sopenharmony_ci	kfree(secdata);
652162306a36Sopenharmony_ci}
652262306a36Sopenharmony_ci
652362306a36Sopenharmony_cistatic void selinux_inode_invalidate_secctx(struct inode *inode)
652462306a36Sopenharmony_ci{
652562306a36Sopenharmony_ci	struct inode_security_struct *isec = selinux_inode(inode);
652662306a36Sopenharmony_ci
652762306a36Sopenharmony_ci	spin_lock(&isec->lock);
652862306a36Sopenharmony_ci	isec->initialized = LABEL_INVALID;
652962306a36Sopenharmony_ci	spin_unlock(&isec->lock);
653062306a36Sopenharmony_ci}
653162306a36Sopenharmony_ci
653262306a36Sopenharmony_ci/*
653362306a36Sopenharmony_ci *	called with inode->i_mutex locked
653462306a36Sopenharmony_ci */
653562306a36Sopenharmony_cistatic int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
653662306a36Sopenharmony_ci{
653762306a36Sopenharmony_ci	int rc = selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX,
653862306a36Sopenharmony_ci					   ctx, ctxlen, 0);
653962306a36Sopenharmony_ci	/* Do not return error when suppressing label (SBLABEL_MNT not set). */
654062306a36Sopenharmony_ci	return rc == -EOPNOTSUPP ? 0 : rc;
654162306a36Sopenharmony_ci}
654262306a36Sopenharmony_ci
654362306a36Sopenharmony_ci/*
654462306a36Sopenharmony_ci *	called with inode->i_mutex locked
654562306a36Sopenharmony_ci */
654662306a36Sopenharmony_cistatic int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
654762306a36Sopenharmony_ci{
654862306a36Sopenharmony_ci	return __vfs_setxattr_noperm(&nop_mnt_idmap, dentry, XATTR_NAME_SELINUX,
654962306a36Sopenharmony_ci				     ctx, ctxlen, 0);
655062306a36Sopenharmony_ci}
655162306a36Sopenharmony_ci
655262306a36Sopenharmony_cistatic int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
655362306a36Sopenharmony_ci{
655462306a36Sopenharmony_ci	int len = 0;
655562306a36Sopenharmony_ci	len = selinux_inode_getsecurity(&nop_mnt_idmap, inode,
655662306a36Sopenharmony_ci					XATTR_SELINUX_SUFFIX, ctx, true);
655762306a36Sopenharmony_ci	if (len < 0)
655862306a36Sopenharmony_ci		return len;
655962306a36Sopenharmony_ci	*ctxlen = len;
656062306a36Sopenharmony_ci	return 0;
656162306a36Sopenharmony_ci}
656262306a36Sopenharmony_ci#ifdef CONFIG_KEYS
656362306a36Sopenharmony_ci
656462306a36Sopenharmony_cistatic int selinux_key_alloc(struct key *k, const struct cred *cred,
656562306a36Sopenharmony_ci			     unsigned long flags)
656662306a36Sopenharmony_ci{
656762306a36Sopenharmony_ci	const struct task_security_struct *tsec;
656862306a36Sopenharmony_ci	struct key_security_struct *ksec;
656962306a36Sopenharmony_ci
657062306a36Sopenharmony_ci	ksec = kzalloc(sizeof(struct key_security_struct), GFP_KERNEL);
657162306a36Sopenharmony_ci	if (!ksec)
657262306a36Sopenharmony_ci		return -ENOMEM;
657362306a36Sopenharmony_ci
657462306a36Sopenharmony_ci	tsec = selinux_cred(cred);
657562306a36Sopenharmony_ci	if (tsec->keycreate_sid)
657662306a36Sopenharmony_ci		ksec->sid = tsec->keycreate_sid;
657762306a36Sopenharmony_ci	else
657862306a36Sopenharmony_ci		ksec->sid = tsec->sid;
657962306a36Sopenharmony_ci
658062306a36Sopenharmony_ci	k->security = ksec;
658162306a36Sopenharmony_ci	return 0;
658262306a36Sopenharmony_ci}
658362306a36Sopenharmony_ci
658462306a36Sopenharmony_cistatic void selinux_key_free(struct key *k)
658562306a36Sopenharmony_ci{
658662306a36Sopenharmony_ci	struct key_security_struct *ksec = k->security;
658762306a36Sopenharmony_ci
658862306a36Sopenharmony_ci	k->security = NULL;
658962306a36Sopenharmony_ci	kfree(ksec);
659062306a36Sopenharmony_ci}
659162306a36Sopenharmony_ci
659262306a36Sopenharmony_cistatic int selinux_key_permission(key_ref_t key_ref,
659362306a36Sopenharmony_ci				  const struct cred *cred,
659462306a36Sopenharmony_ci				  enum key_need_perm need_perm)
659562306a36Sopenharmony_ci{
659662306a36Sopenharmony_ci	struct key *key;
659762306a36Sopenharmony_ci	struct key_security_struct *ksec;
659862306a36Sopenharmony_ci	u32 perm, sid;
659962306a36Sopenharmony_ci
660062306a36Sopenharmony_ci	switch (need_perm) {
660162306a36Sopenharmony_ci	case KEY_NEED_VIEW:
660262306a36Sopenharmony_ci		perm = KEY__VIEW;
660362306a36Sopenharmony_ci		break;
660462306a36Sopenharmony_ci	case KEY_NEED_READ:
660562306a36Sopenharmony_ci		perm = KEY__READ;
660662306a36Sopenharmony_ci		break;
660762306a36Sopenharmony_ci	case KEY_NEED_WRITE:
660862306a36Sopenharmony_ci		perm = KEY__WRITE;
660962306a36Sopenharmony_ci		break;
661062306a36Sopenharmony_ci	case KEY_NEED_SEARCH:
661162306a36Sopenharmony_ci		perm = KEY__SEARCH;
661262306a36Sopenharmony_ci		break;
661362306a36Sopenharmony_ci	case KEY_NEED_LINK:
661462306a36Sopenharmony_ci		perm = KEY__LINK;
661562306a36Sopenharmony_ci		break;
661662306a36Sopenharmony_ci	case KEY_NEED_SETATTR:
661762306a36Sopenharmony_ci		perm = KEY__SETATTR;
661862306a36Sopenharmony_ci		break;
661962306a36Sopenharmony_ci	case KEY_NEED_UNLINK:
662062306a36Sopenharmony_ci	case KEY_SYSADMIN_OVERRIDE:
662162306a36Sopenharmony_ci	case KEY_AUTHTOKEN_OVERRIDE:
662262306a36Sopenharmony_ci	case KEY_DEFER_PERM_CHECK:
662362306a36Sopenharmony_ci		return 0;
662462306a36Sopenharmony_ci	default:
662562306a36Sopenharmony_ci		WARN_ON(1);
662662306a36Sopenharmony_ci		return -EPERM;
662762306a36Sopenharmony_ci
662862306a36Sopenharmony_ci	}
662962306a36Sopenharmony_ci
663062306a36Sopenharmony_ci	sid = cred_sid(cred);
663162306a36Sopenharmony_ci	key = key_ref_to_ptr(key_ref);
663262306a36Sopenharmony_ci	ksec = key->security;
663362306a36Sopenharmony_ci
663462306a36Sopenharmony_ci	return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, perm, NULL);
663562306a36Sopenharmony_ci}
663662306a36Sopenharmony_ci
663762306a36Sopenharmony_cistatic int selinux_key_getsecurity(struct key *key, char **_buffer)
663862306a36Sopenharmony_ci{
663962306a36Sopenharmony_ci	struct key_security_struct *ksec = key->security;
664062306a36Sopenharmony_ci	char *context = NULL;
664162306a36Sopenharmony_ci	unsigned len;
664262306a36Sopenharmony_ci	int rc;
664362306a36Sopenharmony_ci
664462306a36Sopenharmony_ci	rc = security_sid_to_context(ksec->sid,
664562306a36Sopenharmony_ci				     &context, &len);
664662306a36Sopenharmony_ci	if (!rc)
664762306a36Sopenharmony_ci		rc = len;
664862306a36Sopenharmony_ci	*_buffer = context;
664962306a36Sopenharmony_ci	return rc;
665062306a36Sopenharmony_ci}
665162306a36Sopenharmony_ci
665262306a36Sopenharmony_ci#ifdef CONFIG_KEY_NOTIFICATIONS
665362306a36Sopenharmony_cistatic int selinux_watch_key(struct key *key)
665462306a36Sopenharmony_ci{
665562306a36Sopenharmony_ci	struct key_security_struct *ksec = key->security;
665662306a36Sopenharmony_ci	u32 sid = current_sid();
665762306a36Sopenharmony_ci
665862306a36Sopenharmony_ci	return avc_has_perm(sid, ksec->sid, SECCLASS_KEY, KEY__VIEW, NULL);
665962306a36Sopenharmony_ci}
666062306a36Sopenharmony_ci#endif
666162306a36Sopenharmony_ci#endif
666262306a36Sopenharmony_ci
666362306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_INFINIBAND
666462306a36Sopenharmony_cistatic int selinux_ib_pkey_access(void *ib_sec, u64 subnet_prefix, u16 pkey_val)
666562306a36Sopenharmony_ci{
666662306a36Sopenharmony_ci	struct common_audit_data ad;
666762306a36Sopenharmony_ci	int err;
666862306a36Sopenharmony_ci	u32 sid = 0;
666962306a36Sopenharmony_ci	struct ib_security_struct *sec = ib_sec;
667062306a36Sopenharmony_ci	struct lsm_ibpkey_audit ibpkey;
667162306a36Sopenharmony_ci
667262306a36Sopenharmony_ci	err = sel_ib_pkey_sid(subnet_prefix, pkey_val, &sid);
667362306a36Sopenharmony_ci	if (err)
667462306a36Sopenharmony_ci		return err;
667562306a36Sopenharmony_ci
667662306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IBPKEY;
667762306a36Sopenharmony_ci	ibpkey.subnet_prefix = subnet_prefix;
667862306a36Sopenharmony_ci	ibpkey.pkey = pkey_val;
667962306a36Sopenharmony_ci	ad.u.ibpkey = &ibpkey;
668062306a36Sopenharmony_ci	return avc_has_perm(sec->sid, sid,
668162306a36Sopenharmony_ci			    SECCLASS_INFINIBAND_PKEY,
668262306a36Sopenharmony_ci			    INFINIBAND_PKEY__ACCESS, &ad);
668362306a36Sopenharmony_ci}
668462306a36Sopenharmony_ci
668562306a36Sopenharmony_cistatic int selinux_ib_endport_manage_subnet(void *ib_sec, const char *dev_name,
668662306a36Sopenharmony_ci					    u8 port_num)
668762306a36Sopenharmony_ci{
668862306a36Sopenharmony_ci	struct common_audit_data ad;
668962306a36Sopenharmony_ci	int err;
669062306a36Sopenharmony_ci	u32 sid = 0;
669162306a36Sopenharmony_ci	struct ib_security_struct *sec = ib_sec;
669262306a36Sopenharmony_ci	struct lsm_ibendport_audit ibendport;
669362306a36Sopenharmony_ci
669462306a36Sopenharmony_ci	err = security_ib_endport_sid(dev_name, port_num,
669562306a36Sopenharmony_ci				      &sid);
669662306a36Sopenharmony_ci
669762306a36Sopenharmony_ci	if (err)
669862306a36Sopenharmony_ci		return err;
669962306a36Sopenharmony_ci
670062306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_IBENDPORT;
670162306a36Sopenharmony_ci	ibendport.dev_name = dev_name;
670262306a36Sopenharmony_ci	ibendport.port = port_num;
670362306a36Sopenharmony_ci	ad.u.ibendport = &ibendport;
670462306a36Sopenharmony_ci	return avc_has_perm(sec->sid, sid,
670562306a36Sopenharmony_ci			    SECCLASS_INFINIBAND_ENDPORT,
670662306a36Sopenharmony_ci			    INFINIBAND_ENDPORT__MANAGE_SUBNET, &ad);
670762306a36Sopenharmony_ci}
670862306a36Sopenharmony_ci
670962306a36Sopenharmony_cistatic int selinux_ib_alloc_security(void **ib_sec)
671062306a36Sopenharmony_ci{
671162306a36Sopenharmony_ci	struct ib_security_struct *sec;
671262306a36Sopenharmony_ci
671362306a36Sopenharmony_ci	sec = kzalloc(sizeof(*sec), GFP_KERNEL);
671462306a36Sopenharmony_ci	if (!sec)
671562306a36Sopenharmony_ci		return -ENOMEM;
671662306a36Sopenharmony_ci	sec->sid = current_sid();
671762306a36Sopenharmony_ci
671862306a36Sopenharmony_ci	*ib_sec = sec;
671962306a36Sopenharmony_ci	return 0;
672062306a36Sopenharmony_ci}
672162306a36Sopenharmony_ci
672262306a36Sopenharmony_cistatic void selinux_ib_free_security(void *ib_sec)
672362306a36Sopenharmony_ci{
672462306a36Sopenharmony_ci	kfree(ib_sec);
672562306a36Sopenharmony_ci}
672662306a36Sopenharmony_ci#endif
672762306a36Sopenharmony_ci
672862306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL
672962306a36Sopenharmony_cistatic int selinux_bpf(int cmd, union bpf_attr *attr,
673062306a36Sopenharmony_ci				     unsigned int size)
673162306a36Sopenharmony_ci{
673262306a36Sopenharmony_ci	u32 sid = current_sid();
673362306a36Sopenharmony_ci	int ret;
673462306a36Sopenharmony_ci
673562306a36Sopenharmony_ci	switch (cmd) {
673662306a36Sopenharmony_ci	case BPF_MAP_CREATE:
673762306a36Sopenharmony_ci		ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE,
673862306a36Sopenharmony_ci				   NULL);
673962306a36Sopenharmony_ci		break;
674062306a36Sopenharmony_ci	case BPF_PROG_LOAD:
674162306a36Sopenharmony_ci		ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD,
674262306a36Sopenharmony_ci				   NULL);
674362306a36Sopenharmony_ci		break;
674462306a36Sopenharmony_ci	default:
674562306a36Sopenharmony_ci		ret = 0;
674662306a36Sopenharmony_ci		break;
674762306a36Sopenharmony_ci	}
674862306a36Sopenharmony_ci
674962306a36Sopenharmony_ci	return ret;
675062306a36Sopenharmony_ci}
675162306a36Sopenharmony_ci
675262306a36Sopenharmony_cistatic u32 bpf_map_fmode_to_av(fmode_t fmode)
675362306a36Sopenharmony_ci{
675462306a36Sopenharmony_ci	u32 av = 0;
675562306a36Sopenharmony_ci
675662306a36Sopenharmony_ci	if (fmode & FMODE_READ)
675762306a36Sopenharmony_ci		av |= BPF__MAP_READ;
675862306a36Sopenharmony_ci	if (fmode & FMODE_WRITE)
675962306a36Sopenharmony_ci		av |= BPF__MAP_WRITE;
676062306a36Sopenharmony_ci	return av;
676162306a36Sopenharmony_ci}
676262306a36Sopenharmony_ci
676362306a36Sopenharmony_ci/* This function will check the file pass through unix socket or binder to see
676462306a36Sopenharmony_ci * if it is a bpf related object. And apply corresponding checks on the bpf
676562306a36Sopenharmony_ci * object based on the type. The bpf maps and programs, not like other files and
676662306a36Sopenharmony_ci * socket, are using a shared anonymous inode inside the kernel as their inode.
676762306a36Sopenharmony_ci * So checking that inode cannot identify if the process have privilege to
676862306a36Sopenharmony_ci * access the bpf object and that's why we have to add this additional check in
676962306a36Sopenharmony_ci * selinux_file_receive and selinux_binder_transfer_files.
677062306a36Sopenharmony_ci */
677162306a36Sopenharmony_cistatic int bpf_fd_pass(const struct file *file, u32 sid)
677262306a36Sopenharmony_ci{
677362306a36Sopenharmony_ci	struct bpf_security_struct *bpfsec;
677462306a36Sopenharmony_ci	struct bpf_prog *prog;
677562306a36Sopenharmony_ci	struct bpf_map *map;
677662306a36Sopenharmony_ci	int ret;
677762306a36Sopenharmony_ci
677862306a36Sopenharmony_ci	if (file->f_op == &bpf_map_fops) {
677962306a36Sopenharmony_ci		map = file->private_data;
678062306a36Sopenharmony_ci		bpfsec = map->security;
678162306a36Sopenharmony_ci		ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
678262306a36Sopenharmony_ci				   bpf_map_fmode_to_av(file->f_mode), NULL);
678362306a36Sopenharmony_ci		if (ret)
678462306a36Sopenharmony_ci			return ret;
678562306a36Sopenharmony_ci	} else if (file->f_op == &bpf_prog_fops) {
678662306a36Sopenharmony_ci		prog = file->private_data;
678762306a36Sopenharmony_ci		bpfsec = prog->aux->security;
678862306a36Sopenharmony_ci		ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
678962306a36Sopenharmony_ci				   BPF__PROG_RUN, NULL);
679062306a36Sopenharmony_ci		if (ret)
679162306a36Sopenharmony_ci			return ret;
679262306a36Sopenharmony_ci	}
679362306a36Sopenharmony_ci	return 0;
679462306a36Sopenharmony_ci}
679562306a36Sopenharmony_ci
679662306a36Sopenharmony_cistatic int selinux_bpf_map(struct bpf_map *map, fmode_t fmode)
679762306a36Sopenharmony_ci{
679862306a36Sopenharmony_ci	u32 sid = current_sid();
679962306a36Sopenharmony_ci	struct bpf_security_struct *bpfsec;
680062306a36Sopenharmony_ci
680162306a36Sopenharmony_ci	bpfsec = map->security;
680262306a36Sopenharmony_ci	return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
680362306a36Sopenharmony_ci			    bpf_map_fmode_to_av(fmode), NULL);
680462306a36Sopenharmony_ci}
680562306a36Sopenharmony_ci
680662306a36Sopenharmony_cistatic int selinux_bpf_prog(struct bpf_prog *prog)
680762306a36Sopenharmony_ci{
680862306a36Sopenharmony_ci	u32 sid = current_sid();
680962306a36Sopenharmony_ci	struct bpf_security_struct *bpfsec;
681062306a36Sopenharmony_ci
681162306a36Sopenharmony_ci	bpfsec = prog->aux->security;
681262306a36Sopenharmony_ci	return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF,
681362306a36Sopenharmony_ci			    BPF__PROG_RUN, NULL);
681462306a36Sopenharmony_ci}
681562306a36Sopenharmony_ci
681662306a36Sopenharmony_cistatic int selinux_bpf_map_alloc(struct bpf_map *map)
681762306a36Sopenharmony_ci{
681862306a36Sopenharmony_ci	struct bpf_security_struct *bpfsec;
681962306a36Sopenharmony_ci
682062306a36Sopenharmony_ci	bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
682162306a36Sopenharmony_ci	if (!bpfsec)
682262306a36Sopenharmony_ci		return -ENOMEM;
682362306a36Sopenharmony_ci
682462306a36Sopenharmony_ci	bpfsec->sid = current_sid();
682562306a36Sopenharmony_ci	map->security = bpfsec;
682662306a36Sopenharmony_ci
682762306a36Sopenharmony_ci	return 0;
682862306a36Sopenharmony_ci}
682962306a36Sopenharmony_ci
683062306a36Sopenharmony_cistatic void selinux_bpf_map_free(struct bpf_map *map)
683162306a36Sopenharmony_ci{
683262306a36Sopenharmony_ci	struct bpf_security_struct *bpfsec = map->security;
683362306a36Sopenharmony_ci
683462306a36Sopenharmony_ci	map->security = NULL;
683562306a36Sopenharmony_ci	kfree(bpfsec);
683662306a36Sopenharmony_ci}
683762306a36Sopenharmony_ci
683862306a36Sopenharmony_cistatic int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux)
683962306a36Sopenharmony_ci{
684062306a36Sopenharmony_ci	struct bpf_security_struct *bpfsec;
684162306a36Sopenharmony_ci
684262306a36Sopenharmony_ci	bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL);
684362306a36Sopenharmony_ci	if (!bpfsec)
684462306a36Sopenharmony_ci		return -ENOMEM;
684562306a36Sopenharmony_ci
684662306a36Sopenharmony_ci	bpfsec->sid = current_sid();
684762306a36Sopenharmony_ci	aux->security = bpfsec;
684862306a36Sopenharmony_ci
684962306a36Sopenharmony_ci	return 0;
685062306a36Sopenharmony_ci}
685162306a36Sopenharmony_ci
685262306a36Sopenharmony_cistatic void selinux_bpf_prog_free(struct bpf_prog_aux *aux)
685362306a36Sopenharmony_ci{
685462306a36Sopenharmony_ci	struct bpf_security_struct *bpfsec = aux->security;
685562306a36Sopenharmony_ci
685662306a36Sopenharmony_ci	aux->security = NULL;
685762306a36Sopenharmony_ci	kfree(bpfsec);
685862306a36Sopenharmony_ci}
685962306a36Sopenharmony_ci#endif
686062306a36Sopenharmony_ci
686162306a36Sopenharmony_cistruct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
686262306a36Sopenharmony_ci	.lbs_cred = sizeof(struct task_security_struct),
686362306a36Sopenharmony_ci	.lbs_file = sizeof(struct file_security_struct),
686462306a36Sopenharmony_ci	.lbs_inode = sizeof(struct inode_security_struct),
686562306a36Sopenharmony_ci	.lbs_ipc = sizeof(struct ipc_security_struct),
686662306a36Sopenharmony_ci	.lbs_msg_msg = sizeof(struct msg_security_struct),
686762306a36Sopenharmony_ci	.lbs_superblock = sizeof(struct superblock_security_struct),
686862306a36Sopenharmony_ci	.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
686962306a36Sopenharmony_ci};
687062306a36Sopenharmony_ci
687162306a36Sopenharmony_ci#ifdef CONFIG_PERF_EVENTS
687262306a36Sopenharmony_cistatic int selinux_perf_event_open(struct perf_event_attr *attr, int type)
687362306a36Sopenharmony_ci{
687462306a36Sopenharmony_ci	u32 requested, sid = current_sid();
687562306a36Sopenharmony_ci
687662306a36Sopenharmony_ci	if (type == PERF_SECURITY_OPEN)
687762306a36Sopenharmony_ci		requested = PERF_EVENT__OPEN;
687862306a36Sopenharmony_ci	else if (type == PERF_SECURITY_CPU)
687962306a36Sopenharmony_ci		requested = PERF_EVENT__CPU;
688062306a36Sopenharmony_ci	else if (type == PERF_SECURITY_KERNEL)
688162306a36Sopenharmony_ci		requested = PERF_EVENT__KERNEL;
688262306a36Sopenharmony_ci	else if (type == PERF_SECURITY_TRACEPOINT)
688362306a36Sopenharmony_ci		requested = PERF_EVENT__TRACEPOINT;
688462306a36Sopenharmony_ci	else
688562306a36Sopenharmony_ci		return -EINVAL;
688662306a36Sopenharmony_ci
688762306a36Sopenharmony_ci	return avc_has_perm(sid, sid, SECCLASS_PERF_EVENT,
688862306a36Sopenharmony_ci			    requested, NULL);
688962306a36Sopenharmony_ci}
689062306a36Sopenharmony_ci
689162306a36Sopenharmony_cistatic int selinux_perf_event_alloc(struct perf_event *event)
689262306a36Sopenharmony_ci{
689362306a36Sopenharmony_ci	struct perf_event_security_struct *perfsec;
689462306a36Sopenharmony_ci
689562306a36Sopenharmony_ci	perfsec = kzalloc(sizeof(*perfsec), GFP_KERNEL);
689662306a36Sopenharmony_ci	if (!perfsec)
689762306a36Sopenharmony_ci		return -ENOMEM;
689862306a36Sopenharmony_ci
689962306a36Sopenharmony_ci	perfsec->sid = current_sid();
690062306a36Sopenharmony_ci	event->security = perfsec;
690162306a36Sopenharmony_ci
690262306a36Sopenharmony_ci	return 0;
690362306a36Sopenharmony_ci}
690462306a36Sopenharmony_ci
690562306a36Sopenharmony_cistatic void selinux_perf_event_free(struct perf_event *event)
690662306a36Sopenharmony_ci{
690762306a36Sopenharmony_ci	struct perf_event_security_struct *perfsec = event->security;
690862306a36Sopenharmony_ci
690962306a36Sopenharmony_ci	event->security = NULL;
691062306a36Sopenharmony_ci	kfree(perfsec);
691162306a36Sopenharmony_ci}
691262306a36Sopenharmony_ci
691362306a36Sopenharmony_cistatic int selinux_perf_event_read(struct perf_event *event)
691462306a36Sopenharmony_ci{
691562306a36Sopenharmony_ci	struct perf_event_security_struct *perfsec = event->security;
691662306a36Sopenharmony_ci	u32 sid = current_sid();
691762306a36Sopenharmony_ci
691862306a36Sopenharmony_ci	return avc_has_perm(sid, perfsec->sid,
691962306a36Sopenharmony_ci			    SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL);
692062306a36Sopenharmony_ci}
692162306a36Sopenharmony_ci
692262306a36Sopenharmony_cistatic int selinux_perf_event_write(struct perf_event *event)
692362306a36Sopenharmony_ci{
692462306a36Sopenharmony_ci	struct perf_event_security_struct *perfsec = event->security;
692562306a36Sopenharmony_ci	u32 sid = current_sid();
692662306a36Sopenharmony_ci
692762306a36Sopenharmony_ci	return avc_has_perm(sid, perfsec->sid,
692862306a36Sopenharmony_ci			    SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL);
692962306a36Sopenharmony_ci}
693062306a36Sopenharmony_ci#endif
693162306a36Sopenharmony_ci
693262306a36Sopenharmony_ci#ifdef CONFIG_IO_URING
693362306a36Sopenharmony_ci/**
693462306a36Sopenharmony_ci * selinux_uring_override_creds - check the requested cred override
693562306a36Sopenharmony_ci * @new: the target creds
693662306a36Sopenharmony_ci *
693762306a36Sopenharmony_ci * Check to see if the current task is allowed to override it's credentials
693862306a36Sopenharmony_ci * to service an io_uring operation.
693962306a36Sopenharmony_ci */
694062306a36Sopenharmony_cistatic int selinux_uring_override_creds(const struct cred *new)
694162306a36Sopenharmony_ci{
694262306a36Sopenharmony_ci	return avc_has_perm(current_sid(), cred_sid(new),
694362306a36Sopenharmony_ci			    SECCLASS_IO_URING, IO_URING__OVERRIDE_CREDS, NULL);
694462306a36Sopenharmony_ci}
694562306a36Sopenharmony_ci
694662306a36Sopenharmony_ci/**
694762306a36Sopenharmony_ci * selinux_uring_sqpoll - check if a io_uring polling thread can be created
694862306a36Sopenharmony_ci *
694962306a36Sopenharmony_ci * Check to see if the current task is allowed to create a new io_uring
695062306a36Sopenharmony_ci * kernel polling thread.
695162306a36Sopenharmony_ci */
695262306a36Sopenharmony_cistatic int selinux_uring_sqpoll(void)
695362306a36Sopenharmony_ci{
695462306a36Sopenharmony_ci	u32 sid = current_sid();
695562306a36Sopenharmony_ci
695662306a36Sopenharmony_ci	return avc_has_perm(sid, sid,
695762306a36Sopenharmony_ci			    SECCLASS_IO_URING, IO_URING__SQPOLL, NULL);
695862306a36Sopenharmony_ci}
695962306a36Sopenharmony_ci
696062306a36Sopenharmony_ci/**
696162306a36Sopenharmony_ci * selinux_uring_cmd - check if IORING_OP_URING_CMD is allowed
696262306a36Sopenharmony_ci * @ioucmd: the io_uring command structure
696362306a36Sopenharmony_ci *
696462306a36Sopenharmony_ci * Check to see if the current domain is allowed to execute an
696562306a36Sopenharmony_ci * IORING_OP_URING_CMD against the device/file specified in @ioucmd.
696662306a36Sopenharmony_ci *
696762306a36Sopenharmony_ci */
696862306a36Sopenharmony_cistatic int selinux_uring_cmd(struct io_uring_cmd *ioucmd)
696962306a36Sopenharmony_ci{
697062306a36Sopenharmony_ci	struct file *file = ioucmd->file;
697162306a36Sopenharmony_ci	struct inode *inode = file_inode(file);
697262306a36Sopenharmony_ci	struct inode_security_struct *isec = selinux_inode(inode);
697362306a36Sopenharmony_ci	struct common_audit_data ad;
697462306a36Sopenharmony_ci
697562306a36Sopenharmony_ci	ad.type = LSM_AUDIT_DATA_FILE;
697662306a36Sopenharmony_ci	ad.u.file = file;
697762306a36Sopenharmony_ci
697862306a36Sopenharmony_ci	return avc_has_perm(current_sid(), isec->sid,
697962306a36Sopenharmony_ci			    SECCLASS_IO_URING, IO_URING__CMD, &ad);
698062306a36Sopenharmony_ci}
698162306a36Sopenharmony_ci#endif /* CONFIG_IO_URING */
698262306a36Sopenharmony_ci
698362306a36Sopenharmony_ci/*
698462306a36Sopenharmony_ci * IMPORTANT NOTE: When adding new hooks, please be careful to keep this order:
698562306a36Sopenharmony_ci * 1. any hooks that don't belong to (2.) or (3.) below,
698662306a36Sopenharmony_ci * 2. hooks that both access structures allocated by other hooks, and allocate
698762306a36Sopenharmony_ci *    structures that can be later accessed by other hooks (mostly "cloning"
698862306a36Sopenharmony_ci *    hooks),
698962306a36Sopenharmony_ci * 3. hooks that only allocate structures that can be later accessed by other
699062306a36Sopenharmony_ci *    hooks ("allocating" hooks).
699162306a36Sopenharmony_ci *
699262306a36Sopenharmony_ci * Please follow block comment delimiters in the list to keep this order.
699362306a36Sopenharmony_ci */
699462306a36Sopenharmony_cistatic struct security_hook_list selinux_hooks[] __ro_after_init = {
699562306a36Sopenharmony_ci	LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr),
699662306a36Sopenharmony_ci	LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction),
699762306a36Sopenharmony_ci	LSM_HOOK_INIT(binder_transfer_binder, selinux_binder_transfer_binder),
699862306a36Sopenharmony_ci	LSM_HOOK_INIT(binder_transfer_file, selinux_binder_transfer_file),
699962306a36Sopenharmony_ci
700062306a36Sopenharmony_ci	LSM_HOOK_INIT(ptrace_access_check, selinux_ptrace_access_check),
700162306a36Sopenharmony_ci	LSM_HOOK_INIT(ptrace_traceme, selinux_ptrace_traceme),
700262306a36Sopenharmony_ci	LSM_HOOK_INIT(capget, selinux_capget),
700362306a36Sopenharmony_ci	LSM_HOOK_INIT(capset, selinux_capset),
700462306a36Sopenharmony_ci	LSM_HOOK_INIT(capable, selinux_capable),
700562306a36Sopenharmony_ci	LSM_HOOK_INIT(quotactl, selinux_quotactl),
700662306a36Sopenharmony_ci	LSM_HOOK_INIT(quota_on, selinux_quota_on),
700762306a36Sopenharmony_ci	LSM_HOOK_INIT(syslog, selinux_syslog),
700862306a36Sopenharmony_ci	LSM_HOOK_INIT(vm_enough_memory, selinux_vm_enough_memory),
700962306a36Sopenharmony_ci
701062306a36Sopenharmony_ci	LSM_HOOK_INIT(netlink_send, selinux_netlink_send),
701162306a36Sopenharmony_ci
701262306a36Sopenharmony_ci	LSM_HOOK_INIT(bprm_creds_for_exec, selinux_bprm_creds_for_exec),
701362306a36Sopenharmony_ci	LSM_HOOK_INIT(bprm_committing_creds, selinux_bprm_committing_creds),
701462306a36Sopenharmony_ci	LSM_HOOK_INIT(bprm_committed_creds, selinux_bprm_committed_creds),
701562306a36Sopenharmony_ci
701662306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_free_mnt_opts, selinux_free_mnt_opts),
701762306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_mnt_opts_compat, selinux_sb_mnt_opts_compat),
701862306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_remount, selinux_sb_remount),
701962306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_kern_mount, selinux_sb_kern_mount),
702062306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_show_options, selinux_sb_show_options),
702162306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_statfs, selinux_sb_statfs),
702262306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_mount, selinux_mount),
702362306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_umount, selinux_umount),
702462306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_set_mnt_opts, selinux_set_mnt_opts),
702562306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_clone_mnt_opts, selinux_sb_clone_mnt_opts),
702662306a36Sopenharmony_ci
702762306a36Sopenharmony_ci	LSM_HOOK_INIT(move_mount, selinux_move_mount),
702862306a36Sopenharmony_ci
702962306a36Sopenharmony_ci	LSM_HOOK_INIT(dentry_init_security, selinux_dentry_init_security),
703062306a36Sopenharmony_ci	LSM_HOOK_INIT(dentry_create_files_as, selinux_dentry_create_files_as),
703162306a36Sopenharmony_ci
703262306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_free_security, selinux_inode_free_security),
703362306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_init_security, selinux_inode_init_security),
703462306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_init_security_anon, selinux_inode_init_security_anon),
703562306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_create, selinux_inode_create),
703662306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_link, selinux_inode_link),
703762306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_unlink, selinux_inode_unlink),
703862306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_symlink, selinux_inode_symlink),
703962306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_mkdir, selinux_inode_mkdir),
704062306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_rmdir, selinux_inode_rmdir),
704162306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_mknod, selinux_inode_mknod),
704262306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_rename, selinux_inode_rename),
704362306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_readlink, selinux_inode_readlink),
704462306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_follow_link, selinux_inode_follow_link),
704562306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_permission, selinux_inode_permission),
704662306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_setattr, selinux_inode_setattr),
704762306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_getattr, selinux_inode_getattr),
704862306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_setxattr, selinux_inode_setxattr),
704962306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_post_setxattr, selinux_inode_post_setxattr),
705062306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_getxattr, selinux_inode_getxattr),
705162306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_listxattr, selinux_inode_listxattr),
705262306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_removexattr, selinux_inode_removexattr),
705362306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_set_acl, selinux_inode_set_acl),
705462306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_get_acl, selinux_inode_get_acl),
705562306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_remove_acl, selinux_inode_remove_acl),
705662306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_getsecurity, selinux_inode_getsecurity),
705762306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_setsecurity, selinux_inode_setsecurity),
705862306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_listsecurity, selinux_inode_listsecurity),
705962306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_getsecid, selinux_inode_getsecid),
706062306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_copy_up, selinux_inode_copy_up),
706162306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_copy_up_xattr, selinux_inode_copy_up_xattr),
706262306a36Sopenharmony_ci	LSM_HOOK_INIT(path_notify, selinux_path_notify),
706362306a36Sopenharmony_ci
706462306a36Sopenharmony_ci	LSM_HOOK_INIT(kernfs_init_security, selinux_kernfs_init_security),
706562306a36Sopenharmony_ci
706662306a36Sopenharmony_ci	LSM_HOOK_INIT(file_permission, selinux_file_permission),
706762306a36Sopenharmony_ci	LSM_HOOK_INIT(file_alloc_security, selinux_file_alloc_security),
706862306a36Sopenharmony_ci	LSM_HOOK_INIT(file_ioctl, selinux_file_ioctl),
706962306a36Sopenharmony_ci	LSM_HOOK_INIT(file_ioctl_compat, selinux_file_ioctl_compat),
707062306a36Sopenharmony_ci	LSM_HOOK_INIT(mmap_file, selinux_mmap_file),
707162306a36Sopenharmony_ci	LSM_HOOK_INIT(mmap_addr, selinux_mmap_addr),
707262306a36Sopenharmony_ci	LSM_HOOK_INIT(file_mprotect, selinux_file_mprotect),
707362306a36Sopenharmony_ci	LSM_HOOK_INIT(file_lock, selinux_file_lock),
707462306a36Sopenharmony_ci	LSM_HOOK_INIT(file_fcntl, selinux_file_fcntl),
707562306a36Sopenharmony_ci	LSM_HOOK_INIT(file_set_fowner, selinux_file_set_fowner),
707662306a36Sopenharmony_ci	LSM_HOOK_INIT(file_send_sigiotask, selinux_file_send_sigiotask),
707762306a36Sopenharmony_ci	LSM_HOOK_INIT(file_receive, selinux_file_receive),
707862306a36Sopenharmony_ci
707962306a36Sopenharmony_ci	LSM_HOOK_INIT(file_open, selinux_file_open),
708062306a36Sopenharmony_ci
708162306a36Sopenharmony_ci	LSM_HOOK_INIT(task_alloc, selinux_task_alloc),
708262306a36Sopenharmony_ci	LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare),
708362306a36Sopenharmony_ci	LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer),
708462306a36Sopenharmony_ci	LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid),
708562306a36Sopenharmony_ci	LSM_HOOK_INIT(kernel_act_as, selinux_kernel_act_as),
708662306a36Sopenharmony_ci	LSM_HOOK_INIT(kernel_create_files_as, selinux_kernel_create_files_as),
708762306a36Sopenharmony_ci	LSM_HOOK_INIT(kernel_module_request, selinux_kernel_module_request),
708862306a36Sopenharmony_ci	LSM_HOOK_INIT(kernel_load_data, selinux_kernel_load_data),
708962306a36Sopenharmony_ci	LSM_HOOK_INIT(kernel_read_file, selinux_kernel_read_file),
709062306a36Sopenharmony_ci	LSM_HOOK_INIT(task_setpgid, selinux_task_setpgid),
709162306a36Sopenharmony_ci	LSM_HOOK_INIT(task_getpgid, selinux_task_getpgid),
709262306a36Sopenharmony_ci	LSM_HOOK_INIT(task_getsid, selinux_task_getsid),
709362306a36Sopenharmony_ci	LSM_HOOK_INIT(current_getsecid_subj, selinux_current_getsecid_subj),
709462306a36Sopenharmony_ci	LSM_HOOK_INIT(task_getsecid_obj, selinux_task_getsecid_obj),
709562306a36Sopenharmony_ci	LSM_HOOK_INIT(task_setnice, selinux_task_setnice),
709662306a36Sopenharmony_ci	LSM_HOOK_INIT(task_setioprio, selinux_task_setioprio),
709762306a36Sopenharmony_ci	LSM_HOOK_INIT(task_getioprio, selinux_task_getioprio),
709862306a36Sopenharmony_ci	LSM_HOOK_INIT(task_prlimit, selinux_task_prlimit),
709962306a36Sopenharmony_ci	LSM_HOOK_INIT(task_setrlimit, selinux_task_setrlimit),
710062306a36Sopenharmony_ci	LSM_HOOK_INIT(task_setscheduler, selinux_task_setscheduler),
710162306a36Sopenharmony_ci	LSM_HOOK_INIT(task_getscheduler, selinux_task_getscheduler),
710262306a36Sopenharmony_ci	LSM_HOOK_INIT(task_movememory, selinux_task_movememory),
710362306a36Sopenharmony_ci	LSM_HOOK_INIT(task_kill, selinux_task_kill),
710462306a36Sopenharmony_ci	LSM_HOOK_INIT(task_to_inode, selinux_task_to_inode),
710562306a36Sopenharmony_ci	LSM_HOOK_INIT(userns_create, selinux_userns_create),
710662306a36Sopenharmony_ci
710762306a36Sopenharmony_ci	LSM_HOOK_INIT(ipc_permission, selinux_ipc_permission),
710862306a36Sopenharmony_ci	LSM_HOOK_INIT(ipc_getsecid, selinux_ipc_getsecid),
710962306a36Sopenharmony_ci
711062306a36Sopenharmony_ci	LSM_HOOK_INIT(msg_queue_associate, selinux_msg_queue_associate),
711162306a36Sopenharmony_ci	LSM_HOOK_INIT(msg_queue_msgctl, selinux_msg_queue_msgctl),
711262306a36Sopenharmony_ci	LSM_HOOK_INIT(msg_queue_msgsnd, selinux_msg_queue_msgsnd),
711362306a36Sopenharmony_ci	LSM_HOOK_INIT(msg_queue_msgrcv, selinux_msg_queue_msgrcv),
711462306a36Sopenharmony_ci
711562306a36Sopenharmony_ci	LSM_HOOK_INIT(shm_associate, selinux_shm_associate),
711662306a36Sopenharmony_ci	LSM_HOOK_INIT(shm_shmctl, selinux_shm_shmctl),
711762306a36Sopenharmony_ci	LSM_HOOK_INIT(shm_shmat, selinux_shm_shmat),
711862306a36Sopenharmony_ci
711962306a36Sopenharmony_ci	LSM_HOOK_INIT(sem_associate, selinux_sem_associate),
712062306a36Sopenharmony_ci	LSM_HOOK_INIT(sem_semctl, selinux_sem_semctl),
712162306a36Sopenharmony_ci	LSM_HOOK_INIT(sem_semop, selinux_sem_semop),
712262306a36Sopenharmony_ci
712362306a36Sopenharmony_ci	LSM_HOOK_INIT(d_instantiate, selinux_d_instantiate),
712462306a36Sopenharmony_ci
712562306a36Sopenharmony_ci	LSM_HOOK_INIT(getprocattr, selinux_getprocattr),
712662306a36Sopenharmony_ci	LSM_HOOK_INIT(setprocattr, selinux_setprocattr),
712762306a36Sopenharmony_ci
712862306a36Sopenharmony_ci	LSM_HOOK_INIT(ismaclabel, selinux_ismaclabel),
712962306a36Sopenharmony_ci	LSM_HOOK_INIT(secctx_to_secid, selinux_secctx_to_secid),
713062306a36Sopenharmony_ci	LSM_HOOK_INIT(release_secctx, selinux_release_secctx),
713162306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_invalidate_secctx, selinux_inode_invalidate_secctx),
713262306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_notifysecctx, selinux_inode_notifysecctx),
713362306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_setsecctx, selinux_inode_setsecctx),
713462306a36Sopenharmony_ci
713562306a36Sopenharmony_ci	LSM_HOOK_INIT(unix_stream_connect, selinux_socket_unix_stream_connect),
713662306a36Sopenharmony_ci	LSM_HOOK_INIT(unix_may_send, selinux_socket_unix_may_send),
713762306a36Sopenharmony_ci
713862306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_create, selinux_socket_create),
713962306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_post_create, selinux_socket_post_create),
714062306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_socketpair, selinux_socket_socketpair),
714162306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_bind, selinux_socket_bind),
714262306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_connect, selinux_socket_connect),
714362306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_listen, selinux_socket_listen),
714462306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_accept, selinux_socket_accept),
714562306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_sendmsg, selinux_socket_sendmsg),
714662306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_recvmsg, selinux_socket_recvmsg),
714762306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_getsockname, selinux_socket_getsockname),
714862306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_getpeername, selinux_socket_getpeername),
714962306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_getsockopt, selinux_socket_getsockopt),
715062306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_setsockopt, selinux_socket_setsockopt),
715162306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_shutdown, selinux_socket_shutdown),
715262306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_sock_rcv_skb, selinux_socket_sock_rcv_skb),
715362306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_getpeersec_stream,
715462306a36Sopenharmony_ci			selinux_socket_getpeersec_stream),
715562306a36Sopenharmony_ci	LSM_HOOK_INIT(socket_getpeersec_dgram, selinux_socket_getpeersec_dgram),
715662306a36Sopenharmony_ci	LSM_HOOK_INIT(sk_free_security, selinux_sk_free_security),
715762306a36Sopenharmony_ci	LSM_HOOK_INIT(sk_clone_security, selinux_sk_clone_security),
715862306a36Sopenharmony_ci	LSM_HOOK_INIT(sk_getsecid, selinux_sk_getsecid),
715962306a36Sopenharmony_ci	LSM_HOOK_INIT(sock_graft, selinux_sock_graft),
716062306a36Sopenharmony_ci	LSM_HOOK_INIT(sctp_assoc_request, selinux_sctp_assoc_request),
716162306a36Sopenharmony_ci	LSM_HOOK_INIT(sctp_sk_clone, selinux_sctp_sk_clone),
716262306a36Sopenharmony_ci	LSM_HOOK_INIT(sctp_bind_connect, selinux_sctp_bind_connect),
716362306a36Sopenharmony_ci	LSM_HOOK_INIT(sctp_assoc_established, selinux_sctp_assoc_established),
716462306a36Sopenharmony_ci	LSM_HOOK_INIT(mptcp_add_subflow, selinux_mptcp_add_subflow),
716562306a36Sopenharmony_ci	LSM_HOOK_INIT(inet_conn_request, selinux_inet_conn_request),
716662306a36Sopenharmony_ci	LSM_HOOK_INIT(inet_csk_clone, selinux_inet_csk_clone),
716762306a36Sopenharmony_ci	LSM_HOOK_INIT(inet_conn_established, selinux_inet_conn_established),
716862306a36Sopenharmony_ci	LSM_HOOK_INIT(secmark_relabel_packet, selinux_secmark_relabel_packet),
716962306a36Sopenharmony_ci	LSM_HOOK_INIT(secmark_refcount_inc, selinux_secmark_refcount_inc),
717062306a36Sopenharmony_ci	LSM_HOOK_INIT(secmark_refcount_dec, selinux_secmark_refcount_dec),
717162306a36Sopenharmony_ci	LSM_HOOK_INIT(req_classify_flow, selinux_req_classify_flow),
717262306a36Sopenharmony_ci	LSM_HOOK_INIT(tun_dev_free_security, selinux_tun_dev_free_security),
717362306a36Sopenharmony_ci	LSM_HOOK_INIT(tun_dev_create, selinux_tun_dev_create),
717462306a36Sopenharmony_ci	LSM_HOOK_INIT(tun_dev_attach_queue, selinux_tun_dev_attach_queue),
717562306a36Sopenharmony_ci	LSM_HOOK_INIT(tun_dev_attach, selinux_tun_dev_attach),
717662306a36Sopenharmony_ci	LSM_HOOK_INIT(tun_dev_open, selinux_tun_dev_open),
717762306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_INFINIBAND
717862306a36Sopenharmony_ci	LSM_HOOK_INIT(ib_pkey_access, selinux_ib_pkey_access),
717962306a36Sopenharmony_ci	LSM_HOOK_INIT(ib_endport_manage_subnet,
718062306a36Sopenharmony_ci		      selinux_ib_endport_manage_subnet),
718162306a36Sopenharmony_ci	LSM_HOOK_INIT(ib_free_security, selinux_ib_free_security),
718262306a36Sopenharmony_ci#endif
718362306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK_XFRM
718462306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_policy_free_security, selinux_xfrm_policy_free),
718562306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_policy_delete_security, selinux_xfrm_policy_delete),
718662306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_state_free_security, selinux_xfrm_state_free),
718762306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_state_delete_security, selinux_xfrm_state_delete),
718862306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_policy_lookup, selinux_xfrm_policy_lookup),
718962306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_state_pol_flow_match,
719062306a36Sopenharmony_ci			selinux_xfrm_state_pol_flow_match),
719162306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_decode_session, selinux_xfrm_decode_session),
719262306a36Sopenharmony_ci#endif
719362306a36Sopenharmony_ci
719462306a36Sopenharmony_ci#ifdef CONFIG_KEYS
719562306a36Sopenharmony_ci	LSM_HOOK_INIT(key_free, selinux_key_free),
719662306a36Sopenharmony_ci	LSM_HOOK_INIT(key_permission, selinux_key_permission),
719762306a36Sopenharmony_ci	LSM_HOOK_INIT(key_getsecurity, selinux_key_getsecurity),
719862306a36Sopenharmony_ci#ifdef CONFIG_KEY_NOTIFICATIONS
719962306a36Sopenharmony_ci	LSM_HOOK_INIT(watch_key, selinux_watch_key),
720062306a36Sopenharmony_ci#endif
720162306a36Sopenharmony_ci#endif
720262306a36Sopenharmony_ci
720362306a36Sopenharmony_ci#ifdef CONFIG_AUDIT
720462306a36Sopenharmony_ci	LSM_HOOK_INIT(audit_rule_known, selinux_audit_rule_known),
720562306a36Sopenharmony_ci	LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match),
720662306a36Sopenharmony_ci	LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free),
720762306a36Sopenharmony_ci#endif
720862306a36Sopenharmony_ci
720962306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL
721062306a36Sopenharmony_ci	LSM_HOOK_INIT(bpf, selinux_bpf),
721162306a36Sopenharmony_ci	LSM_HOOK_INIT(bpf_map, selinux_bpf_map),
721262306a36Sopenharmony_ci	LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog),
721362306a36Sopenharmony_ci	LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free),
721462306a36Sopenharmony_ci	LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free),
721562306a36Sopenharmony_ci#endif
721662306a36Sopenharmony_ci
721762306a36Sopenharmony_ci#ifdef CONFIG_PERF_EVENTS
721862306a36Sopenharmony_ci	LSM_HOOK_INIT(perf_event_open, selinux_perf_event_open),
721962306a36Sopenharmony_ci	LSM_HOOK_INIT(perf_event_free, selinux_perf_event_free),
722062306a36Sopenharmony_ci	LSM_HOOK_INIT(perf_event_read, selinux_perf_event_read),
722162306a36Sopenharmony_ci	LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write),
722262306a36Sopenharmony_ci#endif
722362306a36Sopenharmony_ci
722462306a36Sopenharmony_ci#ifdef CONFIG_IO_URING
722562306a36Sopenharmony_ci	LSM_HOOK_INIT(uring_override_creds, selinux_uring_override_creds),
722662306a36Sopenharmony_ci	LSM_HOOK_INIT(uring_sqpoll, selinux_uring_sqpoll),
722762306a36Sopenharmony_ci	LSM_HOOK_INIT(uring_cmd, selinux_uring_cmd),
722862306a36Sopenharmony_ci#endif
722962306a36Sopenharmony_ci
723062306a36Sopenharmony_ci	/*
723162306a36Sopenharmony_ci	 * PUT "CLONING" (ACCESSING + ALLOCATING) HOOKS HERE
723262306a36Sopenharmony_ci	 */
723362306a36Sopenharmony_ci	LSM_HOOK_INIT(fs_context_submount, selinux_fs_context_submount),
723462306a36Sopenharmony_ci	LSM_HOOK_INIT(fs_context_dup, selinux_fs_context_dup),
723562306a36Sopenharmony_ci	LSM_HOOK_INIT(fs_context_parse_param, selinux_fs_context_parse_param),
723662306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_eat_lsm_opts, selinux_sb_eat_lsm_opts),
723762306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK_XFRM
723862306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_policy_clone_security, selinux_xfrm_policy_clone),
723962306a36Sopenharmony_ci#endif
724062306a36Sopenharmony_ci
724162306a36Sopenharmony_ci	/*
724262306a36Sopenharmony_ci	 * PUT "ALLOCATING" HOOKS HERE
724362306a36Sopenharmony_ci	 */
724462306a36Sopenharmony_ci	LSM_HOOK_INIT(msg_msg_alloc_security, selinux_msg_msg_alloc_security),
724562306a36Sopenharmony_ci	LSM_HOOK_INIT(msg_queue_alloc_security,
724662306a36Sopenharmony_ci		      selinux_msg_queue_alloc_security),
724762306a36Sopenharmony_ci	LSM_HOOK_INIT(shm_alloc_security, selinux_shm_alloc_security),
724862306a36Sopenharmony_ci	LSM_HOOK_INIT(sb_alloc_security, selinux_sb_alloc_security),
724962306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_alloc_security, selinux_inode_alloc_security),
725062306a36Sopenharmony_ci	LSM_HOOK_INIT(sem_alloc_security, selinux_sem_alloc_security),
725162306a36Sopenharmony_ci	LSM_HOOK_INIT(secid_to_secctx, selinux_secid_to_secctx),
725262306a36Sopenharmony_ci	LSM_HOOK_INIT(inode_getsecctx, selinux_inode_getsecctx),
725362306a36Sopenharmony_ci	LSM_HOOK_INIT(sk_alloc_security, selinux_sk_alloc_security),
725462306a36Sopenharmony_ci	LSM_HOOK_INIT(tun_dev_alloc_security, selinux_tun_dev_alloc_security),
725562306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_INFINIBAND
725662306a36Sopenharmony_ci	LSM_HOOK_INIT(ib_alloc_security, selinux_ib_alloc_security),
725762306a36Sopenharmony_ci#endif
725862306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_NETWORK_XFRM
725962306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_policy_alloc_security, selinux_xfrm_policy_alloc),
726062306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_state_alloc, selinux_xfrm_state_alloc),
726162306a36Sopenharmony_ci	LSM_HOOK_INIT(xfrm_state_alloc_acquire,
726262306a36Sopenharmony_ci		      selinux_xfrm_state_alloc_acquire),
726362306a36Sopenharmony_ci#endif
726462306a36Sopenharmony_ci#ifdef CONFIG_KEYS
726562306a36Sopenharmony_ci	LSM_HOOK_INIT(key_alloc, selinux_key_alloc),
726662306a36Sopenharmony_ci#endif
726762306a36Sopenharmony_ci#ifdef CONFIG_AUDIT
726862306a36Sopenharmony_ci	LSM_HOOK_INIT(audit_rule_init, selinux_audit_rule_init),
726962306a36Sopenharmony_ci#endif
727062306a36Sopenharmony_ci#ifdef CONFIG_BPF_SYSCALL
727162306a36Sopenharmony_ci	LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc),
727262306a36Sopenharmony_ci	LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc),
727362306a36Sopenharmony_ci#endif
727462306a36Sopenharmony_ci#ifdef CONFIG_PERF_EVENTS
727562306a36Sopenharmony_ci	LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc),
727662306a36Sopenharmony_ci#endif
727762306a36Sopenharmony_ci};
727862306a36Sopenharmony_ci
727962306a36Sopenharmony_cistatic __init int selinux_init(void)
728062306a36Sopenharmony_ci{
728162306a36Sopenharmony_ci	pr_info("SELinux:  Initializing.\n");
728262306a36Sopenharmony_ci
728362306a36Sopenharmony_ci	memset(&selinux_state, 0, sizeof(selinux_state));
728462306a36Sopenharmony_ci	enforcing_set(selinux_enforcing_boot);
728562306a36Sopenharmony_ci	selinux_avc_init();
728662306a36Sopenharmony_ci	mutex_init(&selinux_state.status_lock);
728762306a36Sopenharmony_ci	mutex_init(&selinux_state.policy_mutex);
728862306a36Sopenharmony_ci
728962306a36Sopenharmony_ci	/* Set the security state for the initial task. */
729062306a36Sopenharmony_ci	cred_init_security();
729162306a36Sopenharmony_ci
729262306a36Sopenharmony_ci	default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC);
729362306a36Sopenharmony_ci	if (!default_noexec)
729462306a36Sopenharmony_ci		pr_notice("SELinux:  virtual memory is executable by default\n");
729562306a36Sopenharmony_ci
729662306a36Sopenharmony_ci	avc_init();
729762306a36Sopenharmony_ci
729862306a36Sopenharmony_ci	avtab_cache_init();
729962306a36Sopenharmony_ci
730062306a36Sopenharmony_ci	ebitmap_cache_init();
730162306a36Sopenharmony_ci
730262306a36Sopenharmony_ci	hashtab_cache_init();
730362306a36Sopenharmony_ci
730462306a36Sopenharmony_ci	security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks), "selinux");
730562306a36Sopenharmony_ci
730662306a36Sopenharmony_ci	if (avc_add_callback(selinux_netcache_avc_callback, AVC_CALLBACK_RESET))
730762306a36Sopenharmony_ci		panic("SELinux: Unable to register AVC netcache callback\n");
730862306a36Sopenharmony_ci
730962306a36Sopenharmony_ci	if (avc_add_callback(selinux_lsm_notifier_avc_callback, AVC_CALLBACK_RESET))
731062306a36Sopenharmony_ci		panic("SELinux: Unable to register AVC LSM notifier callback\n");
731162306a36Sopenharmony_ci
731262306a36Sopenharmony_ci	if (selinux_enforcing_boot)
731362306a36Sopenharmony_ci		pr_debug("SELinux:  Starting in enforcing mode\n");
731462306a36Sopenharmony_ci	else
731562306a36Sopenharmony_ci		pr_debug("SELinux:  Starting in permissive mode\n");
731662306a36Sopenharmony_ci
731762306a36Sopenharmony_ci	fs_validate_description("selinux", selinux_fs_parameters);
731862306a36Sopenharmony_ci
731962306a36Sopenharmony_ci	return 0;
732062306a36Sopenharmony_ci}
732162306a36Sopenharmony_ci
732262306a36Sopenharmony_cistatic void delayed_superblock_init(struct super_block *sb, void *unused)
732362306a36Sopenharmony_ci{
732462306a36Sopenharmony_ci	selinux_set_mnt_opts(sb, NULL, 0, NULL);
732562306a36Sopenharmony_ci}
732662306a36Sopenharmony_ci
732762306a36Sopenharmony_civoid selinux_complete_init(void)
732862306a36Sopenharmony_ci{
732962306a36Sopenharmony_ci	pr_debug("SELinux:  Completing initialization.\n");
733062306a36Sopenharmony_ci
733162306a36Sopenharmony_ci	/* Set up any superblocks initialized prior to the policy load. */
733262306a36Sopenharmony_ci	pr_debug("SELinux:  Setting up existing superblocks.\n");
733362306a36Sopenharmony_ci	iterate_supers(delayed_superblock_init, NULL);
733462306a36Sopenharmony_ci}
733562306a36Sopenharmony_ci
733662306a36Sopenharmony_ci/* SELinux requires early initialization in order to label
733762306a36Sopenharmony_ci   all processes and objects when they are created. */
733862306a36Sopenharmony_ciDEFINE_LSM(selinux) = {
733962306a36Sopenharmony_ci	.name = "selinux",
734062306a36Sopenharmony_ci	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
734162306a36Sopenharmony_ci	.enabled = &selinux_enabled_boot,
734262306a36Sopenharmony_ci	.blobs = &selinux_blob_sizes,
734362306a36Sopenharmony_ci	.init = selinux_init,
734462306a36Sopenharmony_ci};
734562306a36Sopenharmony_ci
734662306a36Sopenharmony_ci#if defined(CONFIG_NETFILTER)
734762306a36Sopenharmony_cistatic const struct nf_hook_ops selinux_nf_ops[] = {
734862306a36Sopenharmony_ci	{
734962306a36Sopenharmony_ci		.hook =		selinux_ip_postroute,
735062306a36Sopenharmony_ci		.pf =		NFPROTO_IPV4,
735162306a36Sopenharmony_ci		.hooknum =	NF_INET_POST_ROUTING,
735262306a36Sopenharmony_ci		.priority =	NF_IP_PRI_SELINUX_LAST,
735362306a36Sopenharmony_ci	},
735462306a36Sopenharmony_ci	{
735562306a36Sopenharmony_ci		.hook =		selinux_ip_forward,
735662306a36Sopenharmony_ci		.pf =		NFPROTO_IPV4,
735762306a36Sopenharmony_ci		.hooknum =	NF_INET_FORWARD,
735862306a36Sopenharmony_ci		.priority =	NF_IP_PRI_SELINUX_FIRST,
735962306a36Sopenharmony_ci	},
736062306a36Sopenharmony_ci	{
736162306a36Sopenharmony_ci		.hook =		selinux_ip_output,
736262306a36Sopenharmony_ci		.pf =		NFPROTO_IPV4,
736362306a36Sopenharmony_ci		.hooknum =	NF_INET_LOCAL_OUT,
736462306a36Sopenharmony_ci		.priority =	NF_IP_PRI_SELINUX_FIRST,
736562306a36Sopenharmony_ci	},
736662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
736762306a36Sopenharmony_ci	{
736862306a36Sopenharmony_ci		.hook =		selinux_ip_postroute,
736962306a36Sopenharmony_ci		.pf =		NFPROTO_IPV6,
737062306a36Sopenharmony_ci		.hooknum =	NF_INET_POST_ROUTING,
737162306a36Sopenharmony_ci		.priority =	NF_IP6_PRI_SELINUX_LAST,
737262306a36Sopenharmony_ci	},
737362306a36Sopenharmony_ci	{
737462306a36Sopenharmony_ci		.hook =		selinux_ip_forward,
737562306a36Sopenharmony_ci		.pf =		NFPROTO_IPV6,
737662306a36Sopenharmony_ci		.hooknum =	NF_INET_FORWARD,
737762306a36Sopenharmony_ci		.priority =	NF_IP6_PRI_SELINUX_FIRST,
737862306a36Sopenharmony_ci	},
737962306a36Sopenharmony_ci	{
738062306a36Sopenharmony_ci		.hook =		selinux_ip_output,
738162306a36Sopenharmony_ci		.pf =		NFPROTO_IPV6,
738262306a36Sopenharmony_ci		.hooknum =	NF_INET_LOCAL_OUT,
738362306a36Sopenharmony_ci		.priority =	NF_IP6_PRI_SELINUX_FIRST,
738462306a36Sopenharmony_ci	},
738562306a36Sopenharmony_ci#endif	/* IPV6 */
738662306a36Sopenharmony_ci};
738762306a36Sopenharmony_ci
738862306a36Sopenharmony_cistatic int __net_init selinux_nf_register(struct net *net)
738962306a36Sopenharmony_ci{
739062306a36Sopenharmony_ci	return nf_register_net_hooks(net, selinux_nf_ops,
739162306a36Sopenharmony_ci				     ARRAY_SIZE(selinux_nf_ops));
739262306a36Sopenharmony_ci}
739362306a36Sopenharmony_ci
739462306a36Sopenharmony_cistatic void __net_exit selinux_nf_unregister(struct net *net)
739562306a36Sopenharmony_ci{
739662306a36Sopenharmony_ci	nf_unregister_net_hooks(net, selinux_nf_ops,
739762306a36Sopenharmony_ci				ARRAY_SIZE(selinux_nf_ops));
739862306a36Sopenharmony_ci}
739962306a36Sopenharmony_ci
740062306a36Sopenharmony_cistatic struct pernet_operations selinux_net_ops = {
740162306a36Sopenharmony_ci	.init = selinux_nf_register,
740262306a36Sopenharmony_ci	.exit = selinux_nf_unregister,
740362306a36Sopenharmony_ci};
740462306a36Sopenharmony_ci
740562306a36Sopenharmony_cistatic int __init selinux_nf_ip_init(void)
740662306a36Sopenharmony_ci{
740762306a36Sopenharmony_ci	int err;
740862306a36Sopenharmony_ci
740962306a36Sopenharmony_ci	if (!selinux_enabled_boot)
741062306a36Sopenharmony_ci		return 0;
741162306a36Sopenharmony_ci
741262306a36Sopenharmony_ci	pr_debug("SELinux:  Registering netfilter hooks\n");
741362306a36Sopenharmony_ci
741462306a36Sopenharmony_ci	err = register_pernet_subsys(&selinux_net_ops);
741562306a36Sopenharmony_ci	if (err)
741662306a36Sopenharmony_ci		panic("SELinux: register_pernet_subsys: error %d\n", err);
741762306a36Sopenharmony_ci
741862306a36Sopenharmony_ci	return 0;
741962306a36Sopenharmony_ci}
742062306a36Sopenharmony_ci__initcall(selinux_nf_ip_init);
742162306a36Sopenharmony_ci#endif /* CONFIG_NETFILTER */
7422