diff options
Diffstat (limited to 'security')
| -rw-r--r-- | security/selinux/exports.c | 20 | ||||
| -rw-r--r-- | security/selinux/hooks.c | 46 | ||||
| -rw-r--r-- | security/selinux/include/xfrm.h | 12 | ||||
| -rw-r--r-- | security/selinux/xfrm.c | 18 | 
4 files changed, 83 insertions, 13 deletions
diff --git a/security/selinux/exports.c b/security/selinux/exports.c index b6f96943be1..87d2bb3ea35 100644 --- a/security/selinux/exports.c +++ b/security/selinux/exports.c @@ -17,10 +17,14 @@  #include <linux/selinux.h>  #include <linux/fs.h>  #include <linux/ipc.h> +#include <asm/atomic.h>  #include "security.h"  #include "objsec.h" +/* SECMARK reference count */ +extern atomic_t selinux_secmark_refcount; +  int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)  {  	if (selinux_enabled) @@ -74,7 +78,7 @@ int selinux_string_to_sid(char *str, u32 *sid)  }  EXPORT_SYMBOL_GPL(selinux_string_to_sid); -int selinux_relabel_packet_permission(u32 sid) +int selinux_secmark_relabel_packet_permission(u32 sid)  {  	if (selinux_enabled) {  		struct task_security_struct *tsec = current->security; @@ -84,4 +88,16 @@ int selinux_relabel_packet_permission(u32 sid)  	}  	return 0;  } -EXPORT_SYMBOL_GPL(selinux_relabel_packet_permission); +EXPORT_SYMBOL_GPL(selinux_secmark_relabel_packet_permission); + +void selinux_secmark_refcount_inc(void) +{ +	atomic_inc(&selinux_secmark_refcount); +} +EXPORT_SYMBOL_GPL(selinux_secmark_refcount_inc); + +void selinux_secmark_refcount_dec(void) +{ +	atomic_dec(&selinux_secmark_refcount); +} +EXPORT_SYMBOL_GPL(selinux_secmark_refcount_dec); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index bfe9a05db3a..6156241c877 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -51,8 +51,10 @@  #include <net/ip.h>		/* for local_port_range[] */  #include <net/tcp.h>		/* struct or_callable used in sock_rcv_skb */  #include <net/net_namespace.h> +#include <net/netlabel.h>  #include <asm/uaccess.h>  #include <asm/ioctls.h> +#include <asm/atomic.h>  #include <linux/bitops.h>  #include <linux/interrupt.h>  #include <linux/netdevice.h>	/* for network interface checks */ @@ -91,6 +93,9 @@ extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);  extern int selinux_compat_net;  extern struct security_operations *security_ops; +/* SECMARK reference count */ +atomic_t selinux_secmark_refcount = ATOMIC_INIT(0); +  #ifdef CONFIG_SECURITY_SELINUX_DEVELOP  int selinux_enforcing = 0; @@ -157,6 +162,21 @@ getsecurity_exit:  	return len;  } +/** + * selinux_secmark_enabled - Check to see if SECMARK is currently enabled + * + * Description: + * This function checks the SECMARK reference counter to see if any SECMARK + * targets are currently configured, if the reference counter is greater than + * zero SECMARK is considered to be enabled.  Returns true (1) if SECMARK is + * enabled, false (0) if SECMARK is disabled. + * + */ +static int selinux_secmark_enabled(void) +{ +	return (atomic_read(&selinux_secmark_refcount) > 0); +} +  /* Allocate and free functions for each kind of security blob. */  static int task_alloc_security(struct task_struct *task) @@ -3931,7 +3951,6 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)  	struct sk_security_struct *sksec = sk->sk_security;  	u16 family = sk->sk_family;  	u32 sk_sid = sksec->sid; -	u32 peer_sid;  	struct avc_audit_data ad;  	char *addrp; @@ -3957,15 +3976,24 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)  		return selinux_sock_rcv_skb_compat(sk, skb, &ad,  						   family, addrp); -	err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, -			   PACKET__RECV, &ad); -	if (err) -		return err; +	if (selinux_secmark_enabled()) { +		err = avc_has_perm(sk_sid, skb->secmark, SECCLASS_PACKET, +				   PACKET__RECV, &ad); +		if (err) +			return err; +	} -	err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); -	if (err) -		return err; -	return avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, PEER__RECV, &ad); +	if (netlbl_enabled() || selinux_xfrm_enabled()) { +		u32 peer_sid; + +		err = selinux_skb_peerlbl_sid(skb, family, &peer_sid); +		if (err) +			return err; +		err = avc_has_perm(sk_sid, peer_sid, SECCLASS_PEER, +				   PEER__RECV, &ad); +	} + +	return err;  }  static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval, diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h index 31929e39f5c..36b0510efa7 100644 --- a/security/selinux/include/xfrm.h +++ b/security/selinux/include/xfrm.h @@ -32,6 +32,13 @@ static inline struct inode_security_struct *get_sock_isec(struct sock *sk)  }  #ifdef CONFIG_SECURITY_NETWORK_XFRM +extern atomic_t selinux_xfrm_refcount; + +static inline int selinux_xfrm_enabled(void) +{ +	return (atomic_read(&selinux_xfrm_refcount) > 0); +} +  int selinux_xfrm_sock_rcv_skb(u32 sid, struct sk_buff *skb,  			struct avc_audit_data *ad);  int selinux_xfrm_postroute_last(u32 isec_sid, struct sk_buff *skb, @@ -43,6 +50,11 @@ static inline void selinux_xfrm_notify_policyload(void)  	atomic_inc(&flow_cache_genid);  }  #else +static inline int selinux_xfrm_enabled(void) +{ +	return 0; +} +  static inline int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb,  			struct avc_audit_data *ad)  { diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c index e0760396903..7e158205d08 100644 --- a/security/selinux/xfrm.c +++ b/security/selinux/xfrm.c @@ -46,11 +46,14 @@  #include <net/checksum.h>  #include <net/udp.h>  #include <asm/semaphore.h> +#include <asm/atomic.h>  #include "avc.h"  #include "objsec.h"  #include "xfrm.h" +/* Labeled XFRM instance counter */ +atomic_t selinux_xfrm_refcount = ATOMIC_INIT(0);  /*   * Returns true if an LSM/SELinux context @@ -293,6 +296,9 @@ int selinux_xfrm_policy_alloc(struct xfrm_policy *xp,  	BUG_ON(!uctx);  	err = selinux_xfrm_sec_ctx_alloc(&xp->security, uctx, 0); +	if (err == 0) +		atomic_inc(&selinux_xfrm_refcount); +  	return err;  } @@ -340,10 +346,13 @@ int selinux_xfrm_policy_delete(struct xfrm_policy *xp)  	struct xfrm_sec_ctx *ctx = xp->security;  	int rc = 0; -	if (ctx) +	if (ctx) {  		rc = avc_has_perm(tsec->sid, ctx->ctx_sid,  				  SECCLASS_ASSOCIATION,  				  ASSOCIATION__SETCONTEXT, NULL); +		if (rc == 0) +			atomic_dec(&selinux_xfrm_refcount); +	}  	return rc;  } @@ -360,6 +369,8 @@ int selinux_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *uct  	BUG_ON(!x);  	err = selinux_xfrm_sec_ctx_alloc(&x->security, uctx, secid); +	if (err == 0) +		atomic_inc(&selinux_xfrm_refcount);  	return err;  } @@ -382,10 +393,13 @@ int selinux_xfrm_state_delete(struct xfrm_state *x)  	struct xfrm_sec_ctx *ctx = x->security;  	int rc = 0; -	if (ctx) +	if (ctx) {  		rc = avc_has_perm(tsec->sid, ctx->ctx_sid,  				  SECCLASS_ASSOCIATION,  				  ASSOCIATION__SETCONTEXT, NULL); +		if (rc == 0) +			atomic_dec(&selinux_xfrm_refcount); +	}  	return rc;  }  |