[PATCH 02/58] LSM: Infrastructure management of the sock security

Kees Cook keescook at chromium.org
Sat Jun 1 15:17:47 UTC 2019


On Fri, May 31, 2019 at 04:09:24PM -0700, Casey Schaufler wrote:
> Move management of the sock->sk_security blob out
> of the individual security modules and into the security
> infrastructure. Instead of allocating the blobs from within
> the modules the modules tell the infrastructure how much
> space is required, and the space is allocated there.
> 
> Signed-off-by: Casey Schaufler <casey at schaufler-ca.com>

Reviewed-by: Kees Cook <keescook at chromium.org>

-Kees

> ---
>  include/linux/lsm_hooks.h         |  1 +
>  security/apparmor/include/net.h   |  6 ++-
>  security/apparmor/lsm.c           | 38 ++++-----------
>  security/security.c               | 36 +++++++++++++-
>  security/selinux/hooks.c          | 78 +++++++++++++++----------------
>  security/selinux/include/objsec.h |  5 ++
>  security/selinux/netlabel.c       | 23 ++++-----
>  security/smack/smack.h            |  5 ++
>  security/smack/smack_lsm.c        | 64 ++++++++++++-------------
>  security/smack/smack_netfilter.c  |  8 ++--
>  10 files changed, 144 insertions(+), 120 deletions(-)
> 
> diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h
> index f9222a04968d..b353482ea348 100644
> --- a/include/linux/lsm_hooks.h
> +++ b/include/linux/lsm_hooks.h
> @@ -2047,6 +2047,7 @@ struct lsm_blob_sizes {
>  	int	lbs_cred;
>  	int	lbs_file;
>  	int	lbs_inode;
> +	int	lbs_sock;
>  	int	lbs_superblock;
>  	int	lbs_ipc;
>  	int	lbs_msg_msg;
> diff --git a/security/apparmor/include/net.h b/security/apparmor/include/net.h
> index 7334ac966d01..adac04e3b3cc 100644
> --- a/security/apparmor/include/net.h
> +++ b/security/apparmor/include/net.h
> @@ -55,7 +55,11 @@ struct aa_sk_ctx {
>  	struct aa_label *peer;
>  };
>  
> -#define SK_CTX(X) ((X)->sk_security)
> +static inline struct aa_sk_ctx *aa_sock(const struct sock *sk)
> +{
> +	return sk->sk_security + apparmor_blob_sizes.lbs_sock;
> +}
> +
>  #define SOCK_ctx(X) SOCK_INODE(X)->i_security
>  #define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P)				  \
>  	struct lsm_network_audit NAME ## _net = { .sk = (SK),		  \
> diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
> index 49d664ddff44..2716e7731279 100644
> --- a/security/apparmor/lsm.c
> +++ b/security/apparmor/lsm.c
> @@ -757,33 +757,15 @@ static int apparmor_task_kill(struct task_struct *target, struct kernel_siginfo
>  	return error;
>  }
>  
> -/**
> - * apparmor_sk_alloc_security - allocate and attach the sk_security field
> - */
> -static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags)
> -{
> -	struct aa_sk_ctx *ctx;
> -
> -	ctx = kzalloc(sizeof(*ctx), flags);
> -	if (!ctx)
> -		return -ENOMEM;
> -
> -	SK_CTX(sk) = ctx;
> -
> -	return 0;
> -}
> -
>  /**
>   * apparmor_sk_free_security - free the sk_security field
>   */
>  static void apparmor_sk_free_security(struct sock *sk)
>  {
> -	struct aa_sk_ctx *ctx = SK_CTX(sk);
> +	struct aa_sk_ctx *ctx = aa_sock(sk);
>  
> -	SK_CTX(sk) = NULL;
>  	aa_put_label(ctx->label);
>  	aa_put_label(ctx->peer);
> -	kfree(ctx);
>  }
>  
>  /**
> @@ -792,8 +774,8 @@ static void apparmor_sk_free_security(struct sock *sk)
>  static void apparmor_sk_clone_security(const struct sock *sk,
>  				       struct sock *newsk)
>  {
> -	struct aa_sk_ctx *ctx = SK_CTX(sk);
> -	struct aa_sk_ctx *new = SK_CTX(newsk);
> +	struct aa_sk_ctx *ctx = aa_sock(sk);
> +	struct aa_sk_ctx *new = aa_sock(newsk);
>  
>  	new->label = aa_get_label(ctx->label);
>  	new->peer = aa_get_label(ctx->peer);
> @@ -844,7 +826,7 @@ static int apparmor_socket_post_create(struct socket *sock, int family,
>  		label = aa_get_current_label();
>  
>  	if (sock->sk) {
> -		struct aa_sk_ctx *ctx = SK_CTX(sock->sk);
> +		struct aa_sk_ctx *ctx = aa_sock(sock->sk);
>  
>  		aa_put_label(ctx->label);
>  		ctx->label = aa_get_label(label);
> @@ -1029,7 +1011,7 @@ static int apparmor_socket_shutdown(struct socket *sock, int how)
>   */
>  static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
>  {
> -	struct aa_sk_ctx *ctx = SK_CTX(sk);
> +	struct aa_sk_ctx *ctx = aa_sock(sk);
>  
>  	if (!skb->secmark)
>  		return 0;
> @@ -1042,7 +1024,7 @@ static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
>  
>  static struct aa_label *sk_peer_label(struct sock *sk)
>  {
> -	struct aa_sk_ctx *ctx = SK_CTX(sk);
> +	struct aa_sk_ctx *ctx = aa_sock(sk);
>  
>  	if (ctx->peer)
>  		return ctx->peer;
> @@ -1126,7 +1108,7 @@ static int apparmor_socket_getpeersec_dgram(struct socket *sock,
>   */
>  static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
>  {
> -	struct aa_sk_ctx *ctx = SK_CTX(sk);
> +	struct aa_sk_ctx *ctx = aa_sock(sk);
>  
>  	if (!ctx->label)
>  		ctx->label = aa_get_current_label();
> @@ -1136,7 +1118,7 @@ static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
>  static int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
>  				      struct request_sock *req)
>  {
> -	struct aa_sk_ctx *ctx = SK_CTX(sk);
> +	struct aa_sk_ctx *ctx = aa_sock(sk);
>  
>  	if (!skb->secmark)
>  		return 0;
> @@ -1153,6 +1135,7 @@ struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = {
>  	.lbs_cred = sizeof(struct aa_task_ctx *),
>  	.lbs_file = sizeof(struct aa_file_ctx),
>  	.lbs_task = sizeof(struct aa_task_ctx),
> +	.lbs_sock = sizeof(struct aa_sk_ctx),
>  };
>  
>  static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
> @@ -1189,7 +1172,6 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
>  	LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
>  	LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
>  
> -	LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security),
>  	LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security),
>  	LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),
>  
> @@ -1581,7 +1563,7 @@ static unsigned int apparmor_ip_postroute(void *priv,
>  	if (sk == NULL)
>  		return NF_ACCEPT;
>  
> -	ctx = SK_CTX(sk);
> +	ctx = aa_sock(sk);
>  	if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND,
>  				    skb->secmark, sk))
>  		return NF_ACCEPT;
> diff --git a/security/security.c b/security/security.c
> index 550988a0f024..e32b7180282e 100644
> --- a/security/security.c
> +++ b/security/security.c
> @@ -32,6 +32,7 @@
>  #include <linux/string.h>
>  #include <linux/msg.h>
>  #include <net/flow.h>
> +#include <net/sock.h>
>  
>  #define MAX_LSM_EVM_XATTR	2
>  
> @@ -172,6 +173,7 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
>  	lsm_set_blob_size(&needed->lbs_inode, &blob_sizes.lbs_inode);
>  	lsm_set_blob_size(&needed->lbs_ipc, &blob_sizes.lbs_ipc);
>  	lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
> +	lsm_set_blob_size(&needed->lbs_sock, &blob_sizes.lbs_sock);
>  	lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
>  	lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
>  }
> @@ -306,6 +308,7 @@ static void __init ordered_lsm_init(void)
>  	init_debug("inode blob size      = %d\n", blob_sizes.lbs_inode);
>  	init_debug("ipc blob size        = %d\n", blob_sizes.lbs_ipc);
>  	init_debug("msg_msg blob size    = %d\n", blob_sizes.lbs_msg_msg);
> +	init_debug("sock blob size       = %d\n", blob_sizes.lbs_sock);
>  	init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
>  	init_debug("task blob size       = %d\n", blob_sizes.lbs_task);
>  
> @@ -605,6 +608,28 @@ static void __init lsm_early_task(struct task_struct *task)
>  		panic("%s: Early task alloc failed.\n", __func__);
>  }
>  
> +/**
> + * lsm_sock_alloc - allocate a composite sock blob
> + * @sock: the sock that needs a blob
> + * @priority: allocation mode
> + *
> + * Allocate the sock blob for all the modules
> + *
> + * Returns 0, or -ENOMEM if memory can't be allocated.
> + */
> +int lsm_sock_alloc(struct sock *sock, gfp_t priority)
> +{
> +	if (blob_sizes.lbs_sock == 0) {
> +		sock->sk_security = NULL;
> +		return 0;
> +	}
> +
> +	sock->sk_security = kzalloc(blob_sizes.lbs_sock, priority);
> +	if (sock->sk_security == NULL)
> +		return -ENOMEM;
> +	return 0;
> +}
> +
>  /**
>   * lsm_superblock_alloc - allocate a composite superblock blob
>   * @sb: the superblock that needs a blob
> @@ -2048,12 +2073,21 @@ EXPORT_SYMBOL(security_socket_getpeersec_dgram);
>  
>  int security_sk_alloc(struct sock *sk, int family, gfp_t priority)
>  {
> -	return call_int_hook(sk_alloc_security, 0, sk, family, priority);
> +	int rc = lsm_sock_alloc(sk, priority);
> +
> +	if (unlikely(rc))
> +		return rc;
> +	rc = call_int_hook(sk_alloc_security, 0, sk, family, priority);
> +	if (unlikely(rc))
> +		security_sk_free(sk);
> +	return rc;
>  }
>  
>  void security_sk_free(struct sock *sk)
>  {
>  	call_void_hook(sk_free_security, sk);
> +	kfree(sk->sk_security);
> +	sk->sk_security = NULL;
>  }
>  
>  void security_sk_clone(const struct sock *sk, struct sock *newsk)
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index 7478d8eda00a..f38a6f484613 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -4319,7 +4319,7 @@ static int socket_sockcreate_sid(const struct task_security_struct *tsec,
>  
>  static int sock_has_perm(struct sock *sk, u32 perms)
>  {
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	struct common_audit_data ad;
>  	struct lsm_network_audit net = {0,};
>  
> @@ -4376,7 +4376,7 @@ static int selinux_socket_post_create(struct socket *sock, int family,
>  	isec->initialized = LABEL_INITIALIZED;
>  
>  	if (sock->sk) {
> -		sksec = sock->sk->sk_security;
> +		sksec = selinux_sock(sock->sk);
>  		sksec->sclass = sclass;
>  		sksec->sid = sid;
>  		/* Allows detection of the first association on this socket */
> @@ -4392,8 +4392,8 @@ static int selinux_socket_post_create(struct socket *sock, int family,
>  static int selinux_socket_socketpair(struct socket *socka,
>  				     struct socket *sockb)
>  {
> -	struct sk_security_struct *sksec_a = socka->sk->sk_security;
> -	struct sk_security_struct *sksec_b = sockb->sk->sk_security;
> +	struct sk_security_struct *sksec_a = selinux_sock(socka->sk);
> +	struct sk_security_struct *sksec_b = selinux_sock(sockb->sk);
>  
>  	sksec_a->peer_sid = sksec_b->sid;
>  	sksec_b->peer_sid = sksec_a->sid;
> @@ -4408,7 +4408,7 @@ static int selinux_socket_socketpair(struct socket *socka,
>  static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen)
>  {
>  	struct sock *sk = sock->sk;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	u16 family;
>  	int err;
>  
> @@ -4540,7 +4540,7 @@ static int selinux_socket_connect_helper(struct socket *sock,
>  					 struct sockaddr *address, int addrlen)
>  {
>  	struct sock *sk = sock->sk;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	int err;
>  
>  	err = sock_has_perm(sk, SOCKET__CONNECT);
> @@ -4711,9 +4711,9 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
>  					      struct sock *other,
>  					      struct sock *newsk)
>  {
> -	struct sk_security_struct *sksec_sock = sock->sk_security;
> -	struct sk_security_struct *sksec_other = other->sk_security;
> -	struct sk_security_struct *sksec_new = newsk->sk_security;
> +	struct sk_security_struct *sksec_sock = selinux_sock(sock);
> +	struct sk_security_struct *sksec_other = selinux_sock(other);
> +	struct sk_security_struct *sksec_new = selinux_sock(newsk);
>  	struct common_audit_data ad;
>  	struct lsm_network_audit net = {0,};
>  	int err;
> @@ -4745,8 +4745,8 @@ static int selinux_socket_unix_stream_connect(struct sock *sock,
>  static int selinux_socket_unix_may_send(struct socket *sock,
>  					struct socket *other)
>  {
> -	struct sk_security_struct *ssec = sock->sk->sk_security;
> -	struct sk_security_struct *osec = other->sk->sk_security;
> +	struct sk_security_struct *ssec = selinux_sock(sock->sk);
> +	struct sk_security_struct *osec = selinux_sock(other->sk);
>  	struct common_audit_data ad;
>  	struct lsm_network_audit net = {0,};
>  
> @@ -4788,7 +4788,7 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
>  				       u16 family)
>  {
>  	int err = 0;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	u32 sk_sid = sksec->sid;
>  	struct common_audit_data ad;
>  	struct lsm_network_audit net = {0,};
> @@ -4821,7 +4821,7 @@ 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;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	u16 family = sk->sk_family;
>  	u32 sk_sid = sksec->sid;
>  	struct common_audit_data ad;
> @@ -4889,13 +4889,15 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
>  	return err;
>  }
>  
> -static int selinux_socket_getpeersec_stream(struct socket *sock, char __user *optval,
> -					    int __user *optlen, unsigned len)
> +static int selinux_socket_getpeersec_stream(struct socket *sock,
> +					    __user char *optval,
> +					    __user int *optlen,
> +					    unsigned int len)
>  {
>  	int err = 0;
>  	char *scontext;
>  	u32 scontext_len;
> -	struct sk_security_struct *sksec = sock->sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sock->sk);
>  	u32 peer_sid = SECSID_NULL;
>  
>  	if (sksec->sclass == SECCLASS_UNIX_STREAM_SOCKET ||
> @@ -4955,34 +4957,27 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
>  
>  static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority)
>  {
> -	struct sk_security_struct *sksec;
> -
> -	sksec = kzalloc(sizeof(*sksec), priority);
> -	if (!sksec)
> -		return -ENOMEM;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  
>  	sksec->peer_sid = SECINITSID_UNLABELED;
>  	sksec->sid = SECINITSID_UNLABELED;
>  	sksec->sclass = SECCLASS_SOCKET;
>  	selinux_netlbl_sk_security_reset(sksec);
> -	sk->sk_security = sksec;
>  
>  	return 0;
>  }
>  
>  static void selinux_sk_free_security(struct sock *sk)
>  {
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  
> -	sk->sk_security = NULL;
>  	selinux_netlbl_sk_security_free(sksec);
> -	kfree(sksec);
>  }
>  
>  static void selinux_sk_clone_security(const struct sock *sk, struct sock *newsk)
>  {
> -	struct sk_security_struct *sksec = sk->sk_security;
> -	struct sk_security_struct *newsksec = newsk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
> +	struct sk_security_struct *newsksec = selinux_sock(newsk);
>  
>  	newsksec->sid = sksec->sid;
>  	newsksec->peer_sid = sksec->peer_sid;
> @@ -4996,7 +4991,7 @@ static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
>  	if (!sk)
>  		*secid = SECINITSID_ANY_SOCKET;
>  	else {
> -		struct sk_security_struct *sksec = sk->sk_security;
> +		struct sk_security_struct *sksec = selinux_sock(sk);
>  
>  		*secid = sksec->sid;
>  	}
> @@ -5006,7 +5001,7 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
>  {
>  	struct inode_security_struct *isec =
>  		inode_security_novalidate(SOCK_INODE(parent));
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  
>  	if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
>  	    sk->sk_family == PF_UNIX)
> @@ -5021,7 +5016,7 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
>  static int selinux_sctp_assoc_request(struct sctp_endpoint *ep,
>  				      struct sk_buff *skb)
>  {
> -	struct sk_security_struct *sksec = ep->base.sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(ep->base.sk);
>  	struct common_audit_data ad;
>  	struct lsm_network_audit net = {0,};
>  	u8 peerlbl_active;
> @@ -5172,8 +5167,8 @@ static int selinux_sctp_bind_connect(struct sock *sk, int optname,
>  static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
>  				  struct sock *newsk)
>  {
> -	struct sk_security_struct *sksec = sk->sk_security;
> -	struct sk_security_struct *newsksec = newsk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
> +	struct sk_security_struct *newsksec = selinux_sock(newsk);
>  
>  	/* If policy does not support SECCLASS_SCTP_SOCKET then call
>  	 * the non-sctp clone version.
> @@ -5190,7 +5185,7 @@ static void selinux_sctp_sk_clone(struct sctp_endpoint *ep, struct sock *sk,
>  static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
>  				     struct request_sock *req)
>  {
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	int err;
>  	u16 family = req->rsk_ops->family;
>  	u32 connsid;
> @@ -5211,7 +5206,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
>  static void selinux_inet_csk_clone(struct sock *newsk,
>  				   const struct request_sock *req)
>  {
> -	struct sk_security_struct *newsksec = newsk->sk_security;
> +	struct sk_security_struct *newsksec = selinux_sock(newsk);
>  
>  	newsksec->sid = req->secid;
>  	newsksec->peer_sid = req->peer_secid;
> @@ -5228,7 +5223,7 @@ static void selinux_inet_csk_clone(struct sock *newsk,
>  static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
>  {
>  	u16 family = sk->sk_family;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  
>  	/* handle mapped IPv4 packets arriving via IPv6 sockets */
>  	if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
> @@ -5312,7 +5307,7 @@ static int selinux_tun_dev_attach_queue(void *security)
>  static int selinux_tun_dev_attach(struct sock *sk, void *security)
>  {
>  	struct tun_security_struct *tunsec = security;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  
>  	/* we don't currently perform any NetLabel based labeling here and it
>  	 * isn't clear that we would want to do so anyway; while we could apply
> @@ -5353,7 +5348,7 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
>  	int err = 0;
>  	u32 perm;
>  	struct nlmsghdr *nlh;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  
>  	if (skb->len < NLMSG_HDRLEN) {
>  		err = -EINVAL;
> @@ -5494,7 +5489,7 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
>  			return NF_ACCEPT;
>  
>  		/* standard practice, label using the parent socket */
> -		sksec = sk->sk_security;
> +		sksec = selinux_sock(sk);
>  		sid = sksec->sid;
>  	} else
>  		sid = SECINITSID_KERNEL;
> @@ -5533,7 +5528,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb,
>  
>  	if (sk == NULL)
>  		return NF_ACCEPT;
> -	sksec = sk->sk_security;
> +	sksec = selinux_sock(sk);
>  
>  	ad.type = LSM_AUDIT_DATA_NET;
>  	ad.u.net = &net;
> @@ -5625,7 +5620,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
>  		u32 skb_sid;
>  		struct sk_security_struct *sksec;
>  
> -		sksec = sk->sk_security;
> +		sksec = selinux_sock(sk);
>  		if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
>  			return NF_DROP;
>  		/* At this point, if the returned skb peerlbl is SECSID_NULL
> @@ -5654,7 +5649,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb,
>  	} else {
>  		/* Locally generated packet, fetch the security label from the
>  		 * associated socket. */
> -		struct sk_security_struct *sksec = sk->sk_security;
> +		struct sk_security_struct *sksec = selinux_sock(sk);
>  		peer_sid = sksec->sid;
>  		secmark_perm = PACKET__SEND;
>  	}
> @@ -6633,6 +6628,7 @@ struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = {
>  	.lbs_inode = sizeof(struct inode_security_struct),
>  	.lbs_ipc = sizeof(struct ipc_security_struct),
>  	.lbs_msg_msg = sizeof(struct msg_security_struct),
> +	.lbs_sock = sizeof(struct sk_security_struct),
>  	.lbs_superblock = sizeof(struct superblock_security_struct),
>  };
>  
> diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
> index d08d7e5d2f93..29f02b8f8f31 100644
> --- a/security/selinux/include/objsec.h
> +++ b/security/selinux/include/objsec.h
> @@ -194,4 +194,9 @@ static inline struct superblock_security_struct *selinux_superblock(
>  	return superblock->s_security + selinux_blob_sizes.lbs_superblock;
>  }
>  
> +static inline struct sk_security_struct *selinux_sock(const struct sock *sock)
> +{
> +	return sock->sk_security + selinux_blob_sizes.lbs_sock;
> +}
> +
>  #endif /* _SELINUX_OBJSEC_H_ */
> diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
> index 186e727b737b..c40914a157b7 100644
> --- a/security/selinux/netlabel.c
> +++ b/security/selinux/netlabel.c
> @@ -31,6 +31,7 @@
>  #include <linux/gfp.h>
>  #include <linux/ip.h>
>  #include <linux/ipv6.h>
> +#include <linux/lsm_hooks.h>
>  #include <net/sock.h>
>  #include <net/netlabel.h>
>  #include <net/ip.h>
> @@ -81,7 +82,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
>  static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
>  {
>  	int rc;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	struct netlbl_lsm_secattr *secattr;
>  
>  	if (sksec->nlbl_secattr != NULL)
> @@ -114,7 +115,7 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
>  							const struct sock *sk,
>  							u32 sid)
>  {
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
>  
>  	if (secattr == NULL)
> @@ -249,7 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
>  	 * being labeled by it's parent socket, if it is just exit */
>  	sk = skb_to_full_sk(skb);
>  	if (sk != NULL) {
> -		struct sk_security_struct *sksec = sk->sk_security;
> +		struct sk_security_struct *sksec = selinux_sock(sk);
>  
>  		if (sksec->nlbl_state != NLBL_REQSKB)
>  			return 0;
> @@ -287,7 +288,7 @@ int selinux_netlbl_sctp_assoc_request(struct sctp_endpoint *ep,
>  {
>  	int rc;
>  	struct netlbl_lsm_secattr secattr;
> -	struct sk_security_struct *sksec = ep->base.sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(ep->base.sk);
>  	struct sockaddr *addr;
>  	struct sockaddr_in addr4;
>  #if IS_ENABLED(CONFIG_IPV6)
> @@ -370,7 +371,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
>   */
>  void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
>  {
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  
>  	if (family == PF_INET)
>  		sksec->nlbl_state = NLBL_LABELED;
> @@ -388,8 +389,8 @@ void selinux_netlbl_inet_csk_clone(struct sock *sk, u16 family)
>   */
>  void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
>  {
> -	struct sk_security_struct *sksec = sk->sk_security;
> -	struct sk_security_struct *newsksec = newsk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
> +	struct sk_security_struct *newsksec = selinux_sock(newsk);
>  
>  	newsksec->nlbl_state = sksec->nlbl_state;
>  }
> @@ -407,7 +408,7 @@ void selinux_netlbl_sctp_sk_clone(struct sock *sk, struct sock *newsk)
>  int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
>  {
>  	int rc;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	struct netlbl_lsm_secattr *secattr;
>  
>  	if (family != PF_INET && family != PF_INET6)
> @@ -522,7 +523,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
>  {
>  	int rc = 0;
>  	struct sock *sk = sock->sk;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	struct netlbl_lsm_secattr secattr;
>  
>  	if (selinux_netlbl_option(level, optname) &&
> @@ -560,7 +561,7 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
>  						struct sockaddr *addr)
>  {
>  	int rc;
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  	struct netlbl_lsm_secattr *secattr;
>  
>  	/* connected sockets are allowed to disconnect when the address family
> @@ -599,7 +600,7 @@ static int selinux_netlbl_socket_connect_helper(struct sock *sk,
>  int selinux_netlbl_socket_connect_locked(struct sock *sk,
>  					 struct sockaddr *addr)
>  {
> -	struct sk_security_struct *sksec = sk->sk_security;
> +	struct sk_security_struct *sksec = selinux_sock(sk);
>  
>  	if (sksec->nlbl_state != NLBL_REQSKB &&
>  	    sksec->nlbl_state != NLBL_CONNLABELED)
> diff --git a/security/smack/smack.h b/security/smack/smack.h
> index caecbcba9942..4ac4bf3310d7 100644
> --- a/security/smack/smack.h
> +++ b/security/smack/smack.h
> @@ -375,6 +375,11 @@ static inline struct smack_known **smack_ipc(const struct kern_ipc_perm *ipc)
>  	return ipc->security + smack_blob_sizes.lbs_ipc;
>  }
>  
> +static inline struct socket_smack *smack_sock(const struct sock *sock)
> +{
> +	return sock->sk_security + smack_blob_sizes.lbs_sock;
> +}
> +
>  static inline struct superblock_smack *smack_superblock(
>  					const struct super_block *superblock)
>  {
> diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
> index 807eff2ccce9..fd69e1bd841b 100644
> --- a/security/smack/smack_lsm.c
> +++ b/security/smack/smack_lsm.c
> @@ -1439,7 +1439,7 @@ static int smack_inode_getsecurity(struct inode *inode,
>  		if (sock == NULL || sock->sk == NULL)
>  			return -EOPNOTSUPP;
>  
> -		ssp = sock->sk->sk_security;
> +		ssp = smack_sock(sock->sk);
>  
>  		if (strcmp(name, XATTR_SMACK_IPIN) == 0)
>  			isp = ssp->smk_in;
> @@ -1821,7 +1821,7 @@ static int smack_file_receive(struct file *file)
>  
>  	if (inode->i_sb->s_magic == SOCKFS_MAGIC) {
>  		sock = SOCKET_I(inode);
> -		ssp = sock->sk->sk_security;
> +		ssp = smack_sock(sock->sk);
>  		tsp = smack_cred(current_cred());
>  		/*
>  		 * If the receiving process can't write to the
> @@ -2231,11 +2231,7 @@ static void smack_task_to_inode(struct task_struct *p, struct inode *inode)
>  static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
>  {
>  	struct smack_known *skp = smk_of_current();
> -	struct socket_smack *ssp;
> -
> -	ssp = kzalloc(sizeof(struct socket_smack), gfp_flags);
> -	if (ssp == NULL)
> -		return -ENOMEM;
> +	struct socket_smack *ssp = smack_sock(sk);
>  
>  	/*
>  	 * Sockets created by kernel threads receive web label.
> @@ -2249,11 +2245,10 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
>  	}
>  	ssp->smk_packet = NULL;
>  
> -	sk->sk_security = ssp;
> -
>  	return 0;
>  }
>  
> +#ifdef SMACK_IPV6_PORT_LABELING
>  /**
>   * smack_sk_free_security - Free a socket blob
>   * @sk: the socket
> @@ -2262,7 +2257,6 @@ static int smack_sk_alloc_security(struct sock *sk, int family, gfp_t gfp_flags)
>   */
>  static void smack_sk_free_security(struct sock *sk)
>  {
> -#ifdef SMACK_IPV6_PORT_LABELING
>  	struct smk_port_label *spp;
>  
>  	if (sk->sk_family == PF_INET6) {
> @@ -2275,9 +2269,8 @@ static void smack_sk_free_security(struct sock *sk)
>  		}
>  		rcu_read_unlock();
>  	}
> -#endif
> -	kfree(sk->sk_security);
>  }
> +#endif
>  
>  /**
>  * smack_ipv4host_label - check host based restrictions
> @@ -2395,7 +2388,7 @@ static struct smack_known *smack_ipv6host_label(struct sockaddr_in6 *sip)
>  static int smack_netlabel(struct sock *sk, int labeled)
>  {
>  	struct smack_known *skp;
> -	struct socket_smack *ssp = sk->sk_security;
> +	struct socket_smack *ssp = smack_sock(sk);
>  	int rc = 0;
>  
>  	/*
> @@ -2440,7 +2433,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap)
>  	int rc;
>  	int sk_lbl;
>  	struct smack_known *hkp;
> -	struct socket_smack *ssp = sk->sk_security;
> +	struct socket_smack *ssp = smack_sock(sk);
>  	struct smk_audit_info ad;
>  
>  	rcu_read_lock();
> @@ -2516,7 +2509,7 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address)
>  {
>  	struct sock *sk = sock->sk;
>  	struct sockaddr_in6 *addr6;
> -	struct socket_smack *ssp = sock->sk->sk_security;
> +	struct socket_smack *ssp = smack_sock(sock->sk);
>  	struct smk_port_label *spp;
>  	unsigned short port = 0;
>  
> @@ -2603,7 +2596,7 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address,
>  				int act)
>  {
>  	struct smk_port_label *spp;
> -	struct socket_smack *ssp = sk->sk_security;
> +	struct socket_smack *ssp = smack_sock(sk);
>  	struct smack_known *skp = NULL;
>  	unsigned short port;
>  	struct smack_known *object;
> @@ -2697,7 +2690,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name,
>  	if (sock == NULL || sock->sk == NULL)
>  		return -EOPNOTSUPP;
>  
> -	ssp = sock->sk->sk_security;
> +	ssp = smack_sock(sock->sk);
>  
>  	if (strcmp(name, XATTR_SMACK_IPIN) == 0)
>  		ssp->smk_in = skp;
> @@ -2745,7 +2738,7 @@ static int smack_socket_post_create(struct socket *sock, int family,
>  	 * Sockets created by kernel threads receive web label.
>  	 */
>  	if (unlikely(current->flags & PF_KTHREAD)) {
> -		ssp = sock->sk->sk_security;
> +		ssp = smack_sock(sock->sk);
>  		ssp->smk_in = &smack_known_web;
>  		ssp->smk_out = &smack_known_web;
>  	}
> @@ -2770,8 +2763,8 @@ static int smack_socket_post_create(struct socket *sock, int family,
>  static int smack_socket_socketpair(struct socket *socka,
>  		                   struct socket *sockb)
>  {
> -	struct socket_smack *asp = socka->sk->sk_security;
> -	struct socket_smack *bsp = sockb->sk->sk_security;
> +	struct socket_smack *asp = smack_sock(socka->sk);
> +	struct socket_smack *bsp = smack_sock(sockb->sk);
>  
>  	asp->smk_packet = bsp->smk_out;
>  	bsp->smk_packet = asp->smk_out;
> @@ -2825,7 +2818,7 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap,
>  		return 0;
>  
>  #ifdef SMACK_IPV6_SECMARK_LABELING
> -	ssp = sock->sk->sk_security;
> +	ssp = smack_sock(sock->sk);
>  #endif
>  
>  	switch (sock->sk->sk_family) {
> @@ -3566,9 +3559,9 @@ static int smack_unix_stream_connect(struct sock *sock,
>  {
>  	struct smack_known *skp;
>  	struct smack_known *okp;
> -	struct socket_smack *ssp = sock->sk_security;
> -	struct socket_smack *osp = other->sk_security;
> -	struct socket_smack *nsp = newsk->sk_security;
> +	struct socket_smack *ssp = smack_sock(sock);
> +	struct socket_smack *osp = smack_sock(other);
> +	struct socket_smack *nsp = smack_sock(newsk);
>  	struct smk_audit_info ad;
>  	int rc = 0;
>  #ifdef CONFIG_AUDIT
> @@ -3614,8 +3607,8 @@ static int smack_unix_stream_connect(struct sock *sock,
>   */
>  static int smack_unix_may_send(struct socket *sock, struct socket *other)
>  {
> -	struct socket_smack *ssp = sock->sk->sk_security;
> -	struct socket_smack *osp = other->sk->sk_security;
> +	struct socket_smack *ssp = smack_sock(sock->sk);
> +	struct socket_smack *osp = smack_sock(other->sk);
>  	struct smk_audit_info ad;
>  	int rc;
>  
> @@ -3652,7 +3645,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg,
>  	struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name;
>  #endif
>  #ifdef SMACK_IPV6_SECMARK_LABELING
> -	struct socket_smack *ssp = sock->sk->sk_security;
> +	struct socket_smack *ssp = smack_sock(sock->sk);
>  	struct smack_known *rsp;
>  #endif
>  	int rc = 0;
> @@ -3817,7 +3810,7 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip)
>  static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
>  {
>  	struct netlbl_lsm_secattr secattr;
> -	struct socket_smack *ssp = sk->sk_security;
> +	struct socket_smack *ssp = smack_sock(sk);
>  	struct smack_known *skp = NULL;
>  	int rc = 0;
>  	struct smk_audit_info ad;
> @@ -3934,7 +3927,7 @@ static int smack_socket_getpeersec_stream(struct socket *sock,
>  	int slen = 1;
>  	int rc = 0;
>  
> -	ssp = sock->sk->sk_security;
> +	ssp = smack_sock(sock->sk);
>  	if (ssp->smk_packet != NULL) {
>  		rcp = ssp->smk_packet->smk_known;
>  		slen = strlen(rcp) + 1;
> @@ -3984,7 +3977,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
>  
>  	switch (family) {
>  	case PF_UNIX:
> -		ssp = sock->sk->sk_security;
> +		ssp = smack_sock(sock->sk);
>  		s = ssp->smk_out->smk_secid;
>  		break;
>  	case PF_INET:
> @@ -3997,7 +3990,7 @@ static int smack_socket_getpeersec_dgram(struct socket *sock,
>  		 * Translate what netlabel gave us.
>  		 */
>  		if (sock != NULL && sock->sk != NULL)
> -			ssp = sock->sk->sk_security;
> +			ssp = smack_sock(sock->sk);
>  		netlbl_secattr_init(&secattr);
>  		rc = netlbl_skbuff_getattr(skb, family, &secattr);
>  		if (rc == 0) {
> @@ -4035,7 +4028,7 @@ static void smack_sock_graft(struct sock *sk, struct socket *parent)
>  	    (sk->sk_family != PF_INET && sk->sk_family != PF_INET6))
>  		return;
>  
> -	ssp = sk->sk_security;
> +	ssp = smack_sock(sk);
>  	ssp->smk_in = skp;
>  	ssp->smk_out = skp;
>  	/* cssp->smk_packet is already set in smack_inet_csk_clone() */
> @@ -4055,7 +4048,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
>  {
>  	u16 family = sk->sk_family;
>  	struct smack_known *skp;
> -	struct socket_smack *ssp = sk->sk_security;
> +	struct socket_smack *ssp = smack_sock(sk);
>  	struct netlbl_lsm_secattr secattr;
>  	struct sockaddr_in addr;
>  	struct iphdr *hdr;
> @@ -4154,7 +4147,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb,
>  static void smack_inet_csk_clone(struct sock *sk,
>  				 const struct request_sock *req)
>  {
> -	struct socket_smack *ssp = sk->sk_security;
> +	struct socket_smack *ssp = smack_sock(sk);
>  	struct smack_known *skp;
>  
>  	if (req->peer_secid != 0) {
> @@ -4558,6 +4551,7 @@ struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = {
>  	.lbs_inode = sizeof(struct inode_smack),
>  	.lbs_ipc = sizeof(struct smack_known *),
>  	.lbs_msg_msg = sizeof(struct smack_known *),
> +	.lbs_sock = sizeof(struct socket_smack),
>  	.lbs_superblock = sizeof(struct superblock_smack),
>  };
>  
> @@ -4667,7 +4661,9 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = {
>  	LSM_HOOK_INIT(socket_getpeersec_stream, smack_socket_getpeersec_stream),
>  	LSM_HOOK_INIT(socket_getpeersec_dgram, smack_socket_getpeersec_dgram),
>  	LSM_HOOK_INIT(sk_alloc_security, smack_sk_alloc_security),
> +#ifdef SMACK_IPV6_PORT_LABELING
>  	LSM_HOOK_INIT(sk_free_security, smack_sk_free_security),
> +#endif
>  	LSM_HOOK_INIT(sock_graft, smack_sock_graft),
>  	LSM_HOOK_INIT(inet_conn_request, smack_inet_conn_request),
>  	LSM_HOOK_INIT(inet_csk_clone, smack_inet_csk_clone),
> diff --git a/security/smack/smack_netfilter.c b/security/smack/smack_netfilter.c
> index e36d17835d4f..701a1cc1bdcc 100644
> --- a/security/smack/smack_netfilter.c
> +++ b/security/smack/smack_netfilter.c
> @@ -31,8 +31,8 @@ static unsigned int smack_ipv6_output(void *priv,
>  	struct socket_smack *ssp;
>  	struct smack_known *skp;
>  
> -	if (sk && sk->sk_security) {
> -		ssp = sk->sk_security;
> +	if (sk && smack_sock(sk)) {
> +		ssp = smack_sock(sk);
>  		skp = ssp->smk_out;
>  		skb->secmark = skp->smk_secid;
>  	}
> @@ -49,8 +49,8 @@ static unsigned int smack_ipv4_output(void *priv,
>  	struct socket_smack *ssp;
>  	struct smack_known *skp;
>  
> -	if (sk && sk->sk_security) {
> -		ssp = sk->sk_security;
> +	if (sk && smack_sock(sk)) {
> +		ssp = smack_sock(sk);
>  		skp = ssp->smk_out;
>  		skb->secmark = skp->smk_secid;
>  	}
> -- 
> 2.19.1
> 

-- 
Kees Cook



More information about the Linux-security-module-archive mailing list