diff options
Diffstat (limited to 'security/selinux/hooks.c')
| -rw-r--r-- | security/selinux/hooks.c | 149 | 
1 files changed, 72 insertions, 77 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 3363716ee80a..10350534de6d 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1,10 +1,10 @@  // SPDX-License-Identifier: GPL-2.0-only  /* - *  NSA Security-Enhanced Linux (SELinux) security module + *  Security-Enhanced Linux (SELinux) security module   *   *  This file contains the SELinux hook function implementations.   * - *  Authors:  Stephen Smalley, <[email protected]> + *  Authors:  Stephen Smalley, <[email protected]>   *	      Chris Vance, <[email protected]>   *	      Wayne Salamon, <[email protected]>   *	      James Morris <[email protected]> @@ -104,6 +104,8 @@  #include "audit.h"  #include "avc_ss.h" +#define SELINUX_INODE_INIT_XATTRS 1 +  struct selinux_state selinux_state;  /* SECMARK reference count */ @@ -224,6 +226,31 @@ static inline u32 cred_sid(const struct cred *cred)  	return tsec->sid;  } +static void __ad_net_init(struct common_audit_data *ad, +			  struct lsm_network_audit *net, +			  int ifindex, struct sock *sk, u16 family) +{ +	ad->type = LSM_AUDIT_DATA_NET; +	ad->u.net = net; +	net->netif = ifindex; +	net->sk = sk; +	net->family = family; +} + +static void ad_net_init_from_sk(struct common_audit_data *ad, +				struct lsm_network_audit *net, +				struct sock *sk) +{ +	__ad_net_init(ad, net, 0, sk, 0); +} + +static void ad_net_init_from_iif(struct common_audit_data *ad, +				 struct lsm_network_audit *net, +				 int ifindex, u16 family) +{ +	__ad_net_init(ad, net, ifindex, NULL, family); +} +  /*   * get the objective security ID of a task   */ @@ -1125,7 +1152,7 @@ static inline int default_protocol_dgram(int protocol)  static inline u16 socket_type_to_security_class(int family, int type, int protocol)  { -	int extsockclass = selinux_policycap_extsockclass(); +	bool extsockclass = selinux_policycap_extsockclass();  	switch (family) {  	case PF_UNIX: @@ -1689,7 +1716,7 @@ static inline int file_path_has_perm(const struct cred *cred,  }  #ifdef CONFIG_BPF_SYSCALL -static int bpf_fd_pass(struct file *file, u32 sid); +static int bpf_fd_pass(const struct file *file, u32 sid);  #endif  /* Check whether a task can use an open file descriptor to @@ -1950,7 +1977,7 @@ static inline u32 file_mask_to_av(int mode, int mask)  }  /* Convert a Linux file to an access vector. */ -static inline u32 file_to_av(struct file *file) +static inline u32 file_to_av(const struct file *file)  {  	u32 av = 0; @@ -2025,7 +2052,7 @@ static int selinux_binder_transfer_binder(const struct cred *from,  static int selinux_binder_transfer_file(const struct cred *from,  					const struct cred *to, -					struct file *file) +					const struct file *file)  {  	u32 sid = cred_sid(to);  	struct file_security_struct *fsec = selinux_file(file); @@ -2080,7 +2107,7 @@ static int selinux_ptrace_traceme(struct task_struct *parent)  			    SECCLASS_PROCESS, PROCESS__PTRACE, NULL);  } -static int selinux_capget(struct task_struct *target, kernel_cap_t *effective, +static int selinux_capget(const struct task_struct *target, kernel_cap_t *effective,  			  kernel_cap_t *inheritable, kernel_cap_t *permitted)  {  	return avc_has_perm(current_sid(), task_sid_obj(target), @@ -2868,11 +2895,11 @@ static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,  static int selinux_inode_init_security(struct inode *inode, struct inode *dir,  				       const struct qstr *qstr, -				       const char **name, -				       void **value, size_t *len) +				       struct xattr *xattrs, int *xattr_count)  {  	const struct task_security_struct *tsec = selinux_cred(current_cred());  	struct superblock_security_struct *sbsec; +	struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);  	u32 newsid, clen;  	int rc;  	char *context; @@ -2899,16 +2926,14 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,  	    !(sbsec->flags & SBLABEL_MNT))  		return -EOPNOTSUPP; -	if (name) -		*name = XATTR_SELINUX_SUFFIX; - -	if (value && len) { +	if (xattr) {  		rc = security_sid_to_context_force(newsid,  						   &context, &clen);  		if (rc)  			return rc; -		*value = context; -		*len = clen; +		xattr->value = context; +		xattr->value_len = clen; +		xattr->name = XATTR_SELINUX_SUFFIX;  	}  	return 0; @@ -2938,7 +2963,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,  		struct inode_security_struct *context_isec =  			selinux_inode(context_inode);  		if (context_isec->initialized != LABEL_INITIALIZED) { -			pr_err("SELinux:  context_inode is not initialized"); +			pr_err("SELinux:  context_inode is not initialized\n");  			return -EACCES;  		} @@ -4517,14 +4542,12 @@ static int sock_has_perm(struct sock *sk, u32 perms)  {  	struct sk_security_struct *sksec = sk->sk_security;  	struct common_audit_data ad; -	struct lsm_network_audit net = {0,}; +	struct lsm_network_audit net;  	if (sksec->sid == SECINITSID_KERNEL)  		return 0; -	ad.type = LSM_AUDIT_DATA_NET; -	ad.u.net = &net; -	ad.u.net->sk = sk; +	ad_net_init_from_sk(&ad, &net, sk);  	return avc_has_perm(current_sid(), sksec->sid, sksec->sclass, perms,  			    &ad); @@ -4917,12 +4940,10 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,  	struct sk_security_struct *sksec_other = other->sk_security;  	struct sk_security_struct *sksec_new = newsk->sk_security;  	struct common_audit_data ad; -	struct lsm_network_audit net = {0,}; +	struct lsm_network_audit net;  	int err; -	ad.type = LSM_AUDIT_DATA_NET; -	ad.u.net = &net; -	ad.u.net->sk = other; +	ad_net_init_from_sk(&ad, &net, other);  	err = avc_has_perm(sksec_sock->sid, sksec_other->sid,  			   sksec_other->sclass, @@ -4949,11 +4970,9 @@ static int selinux_socket_unix_may_send(struct socket *sock,  	struct sk_security_struct *ssec = sock->sk->sk_security;  	struct sk_security_struct *osec = other->sk->sk_security;  	struct common_audit_data ad; -	struct lsm_network_audit net = {0,}; +	struct lsm_network_audit net; -	ad.type = LSM_AUDIT_DATA_NET; -	ad.u.net = &net; -	ad.u.net->sk = other->sk; +	ad_net_init_from_sk(&ad, &net, other->sk);  	return avc_has_perm(ssec->sid, osec->sid, osec->sclass, SOCKET__SENDTO,  			    &ad); @@ -4989,13 +5008,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,  	struct sk_security_struct *sksec = sk->sk_security;  	u32 sk_sid = sksec->sid;  	struct common_audit_data ad; -	struct lsm_network_audit net = {0,}; +	struct lsm_network_audit net;  	char *addrp; -	ad.type = LSM_AUDIT_DATA_NET; -	ad.u.net = &net; -	ad.u.net->netif = skb->skb_iif; -	ad.u.net->family = family; +	ad_net_init_from_iif(&ad, &net, skb->skb_iif, family);  	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);  	if (err)  		return err; @@ -5017,15 +5033,13 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,  static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)  { -	int err; +	int err, peerlbl_active, secmark_active;  	struct sk_security_struct *sksec = sk->sk_security;  	u16 family = sk->sk_family;  	u32 sk_sid = sksec->sid;  	struct common_audit_data ad; -	struct lsm_network_audit net = {0,}; +	struct lsm_network_audit net;  	char *addrp; -	u8 secmark_active; -	u8 peerlbl_active;  	if (family != PF_INET && family != PF_INET6)  		return 0; @@ -5046,10 +5060,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)  	if (!secmark_active && !peerlbl_active)  		return 0; -	ad.type = LSM_AUDIT_DATA_NET; -	ad.u.net = &net; -	ad.u.net->netif = skb->skb_iif; -	ad.u.net->family = family; +	ad_net_init_from_iif(&ad, &net, skb->skb_iif, family);  	err = selinux_parse_skb(skb, &ad, &addrp, 1, NULL);  	if (err)  		return err; @@ -5219,7 +5230,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,  	u16 family = sk->sk_family;  	struct sk_security_struct *sksec = sk->sk_security;  	struct common_audit_data ad; -	struct lsm_network_audit net = {0,}; +	struct lsm_network_audit net;  	int err;  	/* handle mapped IPv4 packets arriving via IPv6 sockets */ @@ -5255,9 +5266,7 @@ static int selinux_sctp_process_new_assoc(struct sctp_association *asoc,  		/* Other association peer SIDs are checked to enforce  		 * consistency among the peer SIDs.  		 */ -		ad.type = LSM_AUDIT_DATA_NET; -		ad.u.net = &net; -		ad.u.net->sk = asoc->base.sk; +		ad_net_init_from_sk(&ad, &net, asoc->base.sk);  		err = avc_has_perm(sksec->peer_sid, asoc->peer_secid,  				   sksec->sclass, SCTP_SOCKET__ASSOCIATION,  				   &ad); @@ -5488,11 +5497,11 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)  static int selinux_secmark_relabel_packet(u32 sid)  { -	const struct task_security_struct *__tsec; +	const struct task_security_struct *tsec;  	u32 tsid; -	__tsec = selinux_cred(current_cred()); -	tsid = __tsec->sid; +	tsec = selinux_cred(current_cred()); +	tsid = tsec->sid;  	return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,  			    NULL); @@ -5602,7 +5611,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,  	char *addrp;  	u32 peer_sid;  	struct common_audit_data ad; -	struct lsm_network_audit net = {0,}; +	struct lsm_network_audit net;  	int secmark_active, peerlbl_active;  	if (!selinux_policycap_netpeer()) @@ -5618,10 +5627,7 @@ static unsigned int selinux_ip_forward(void *priv, struct sk_buff *skb,  		return NF_DROP;  	ifindex = state->in->ifindex; -	ad.type = LSM_AUDIT_DATA_NET; -	ad.u.net = &net; -	ad.u.net->netif = ifindex; -	ad.u.net->family = family; +	ad_net_init_from_iif(&ad, &net, ifindex, family);  	if (selinux_parse_skb(skb, &ad, &addrp, 1, NULL) != 0)  		return NF_DROP; @@ -5701,7 +5707,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,  	struct sock *sk;  	struct sk_security_struct *sksec;  	struct common_audit_data ad; -	struct lsm_network_audit net = {0,}; +	struct lsm_network_audit net;  	u8 proto = 0;  	sk = skb_to_full_sk(skb); @@ -5709,10 +5715,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,  		return NF_ACCEPT;  	sksec = sk->sk_security; -	ad.type = LSM_AUDIT_DATA_NET; -	ad.u.net = &net; -	ad.u.net->netif = state->out->ifindex; -	ad.u.net->family = state->pf; +	ad_net_init_from_iif(&ad, &net, state->out->ifindex, state->pf);  	if (selinux_parse_skb(skb, &ad, NULL, 0, &proto))  		return NF_DROP; @@ -5737,7 +5740,7 @@ static unsigned int selinux_ip_postroute(void *priv,  	int ifindex;  	struct sock *sk;  	struct common_audit_data ad; -	struct lsm_network_audit net = {0,}; +	struct lsm_network_audit net;  	char *addrp;  	int secmark_active, peerlbl_active; @@ -5834,10 +5837,7 @@ static unsigned int selinux_ip_postroute(void *priv,  	}  	ifindex = state->out->ifindex; -	ad.type = LSM_AUDIT_DATA_NET; -	ad.u.net = &net; -	ad.u.net->netif = ifindex; -	ad.u.net->family = family; +	ad_net_init_from_iif(&ad, &net, ifindex, family);  	if (selinux_parse_skb(skb, &ad, &addrp, 0, NULL))  		return NF_DROP; @@ -5990,8 +5990,7 @@ static int selinux_msg_queue_associate(struct kern_ipc_perm *msq, int msqflg)  static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)  { -	int err; -	int perms; +	u32 perms;  	switch (cmd) {  	case IPC_INFO: @@ -6014,8 +6013,7 @@ static int selinux_msg_queue_msgctl(struct kern_ipc_perm *msq, int cmd)  		return 0;  	} -	err = ipc_has_perm(msq, perms); -	return err; +	return ipc_has_perm(msq, perms);  }  static int selinux_msg_queue_msgsnd(struct kern_ipc_perm *msq, struct msg_msg *msg, int msqflg) @@ -6120,8 +6118,7 @@ static int selinux_shm_associate(struct kern_ipc_perm *shp, int shmflg)  /* Note, at this point, shp is locked down */  static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)  { -	int perms; -	int err; +	u32 perms;  	switch (cmd) {  	case IPC_INFO: @@ -6148,8 +6145,7 @@ static int selinux_shm_shmctl(struct kern_ipc_perm *shp, int cmd)  		return 0;  	} -	err = ipc_has_perm(shp, perms); -	return err; +	return ipc_has_perm(shp, perms);  }  static int selinux_shm_shmat(struct kern_ipc_perm *shp, @@ -6736,7 +6732,7 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)   * access the bpf object and that's why we have to add this additional check in   * selinux_file_receive and selinux_binder_transfer_files.   */ -static int bpf_fd_pass(struct file *file, u32 sid) +static int bpf_fd_pass(const struct file *file, u32 sid)  {  	struct bpf_security_struct *bpfsec;  	struct bpf_prog *prog; @@ -6833,6 +6829,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {  	.lbs_ipc = sizeof(struct ipc_security_struct),  	.lbs_msg_msg = sizeof(struct msg_security_struct),  	.lbs_superblock = sizeof(struct superblock_security_struct), +	.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,  };  #ifdef CONFIG_PERF_EVENTS @@ -6918,7 +6915,7 @@ static int selinux_uring_override_creds(const struct cred *new)   */  static int selinux_uring_sqpoll(void)  { -	int sid = current_sid(); +	u32 sid = current_sid();  	return avc_has_perm(sid, sid,  			    SECCLASS_IO_URING, IO_URING__SQPOLL, NULL); @@ -6957,10 +6954,6 @@ static int selinux_uring_cmd(struct io_uring_cmd *ioucmd)   *    hooks ("allocating" hooks).   *   * Please follow block comment delimiters in the list to keep this order. - * - * This ordering is needed for SELinux runtime disable to work at least somewhat - * safely. Breaking the ordering rules above might lead to NULL pointer derefs - * when disabling SELinux at runtime.   */  static struct security_hook_list selinux_hooks[] __ro_after_init = {  	LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), @@ -7260,6 +7253,8 @@ static __init int selinux_init(void)  	cred_init_security();  	default_noexec = !(VM_DATA_DEFAULT_FLAGS & VM_EXEC); +	if (!default_noexec) +		pr_notice("SELinux:  virtual memory is executable by default\n");  	avc_init();  |