diff options
Diffstat (limited to 'security/selinux/netlabel.c')
| -rw-r--r-- | security/selinux/netlabel.c | 115 | 
1 files changed, 79 insertions, 36 deletions
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c index b22b7dafa0e..f58701a7b72 100644 --- a/security/selinux/netlabel.c +++ b/security/selinux/netlabel.c @@ -68,6 +68,38 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,  }  /** + * selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr + * @sk: the socket + * + * Description: + * Generate the NetLabel security attributes for a socket, making full use of + * the socket's attribute cache.  Returns a pointer to the security attributes + * on success, NULL on failure. + * + */ +static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk) +{ +	int rc; +	struct sk_security_struct *sksec = sk->sk_security; +	struct netlbl_lsm_secattr *secattr; + +	if (sksec->nlbl_secattr != NULL) +		return sksec->nlbl_secattr; + +	secattr = netlbl_secattr_alloc(GFP_ATOMIC); +	if (secattr == NULL) +		return NULL; +	rc = security_netlbl_sid_to_secattr(sksec->sid, secattr); +	if (rc != 0) { +		netlbl_secattr_free(secattr); +		return NULL; +	} +	sksec->nlbl_secattr = secattr; + +	return secattr; +} + +/**   * selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism   * @sk: the socket to label   * @@ -80,17 +112,15 @@ static int selinux_netlbl_sock_setsid(struct sock *sk)  {  	int rc;  	struct sk_security_struct *sksec = sk->sk_security; -	struct netlbl_lsm_secattr secattr; +	struct netlbl_lsm_secattr *secattr;  	if (sksec->nlbl_state != NLBL_REQUIRE)  		return 0; -	netlbl_secattr_init(&secattr); - -	rc = security_netlbl_sid_to_secattr(sksec->sid, &secattr); -	if (rc != 0) -		goto sock_setsid_return; -	rc = netlbl_sock_setattr(sk, &secattr); +	secattr = selinux_netlbl_sock_genattr(sk); +	if (secattr == NULL) +		return -ENOMEM; +	rc = netlbl_sock_setattr(sk, secattr);  	switch (rc) {  	case 0:  		sksec->nlbl_state = NLBL_LABELED; @@ -101,8 +131,6 @@ static int selinux_netlbl_sock_setsid(struct sock *sk)  		break;  	} -sock_setsid_return: -	netlbl_secattr_destroy(&secattr);  	return rc;  } @@ -137,6 +165,20 @@ void selinux_netlbl_err(struct sk_buff *skb, int error, int gateway)  }  /** + * selinux_netlbl_sk_security_free - Free the NetLabel fields + * @sssec: the sk_security_struct + * + * Description: + * Free all of the memory in the NetLabel fields of a sk_security_struct. + * + */ +void selinux_netlbl_sk_security_free(struct sk_security_struct *ssec) +{ +	if (ssec->nlbl_secattr != NULL) +		netlbl_secattr_free(ssec->nlbl_secattr); +} + +/**   * selinux_netlbl_sk_security_reset - Reset the NetLabel fields   * @ssec: the sk_security_struct   * @family: the socket family @@ -209,7 +251,8 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,  				 u32 sid)  {  	int rc; -	struct netlbl_lsm_secattr secattr; +	struct netlbl_lsm_secattr secattr_storage; +	struct netlbl_lsm_secattr *secattr = NULL;  	struct sock *sk;  	/* if this is a locally generated packet check to see if it is already @@ -219,16 +262,21 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,  		struct sk_security_struct *sksec = sk->sk_security;  		if (sksec->nlbl_state != NLBL_REQSKB)  			return 0; +		secattr = sksec->nlbl_secattr; +	} +	if (secattr == NULL) { +		secattr = &secattr_storage; +		netlbl_secattr_init(secattr); +		rc = security_netlbl_sid_to_secattr(sid, secattr); +		if (rc != 0) +			goto skbuff_setsid_return;  	} -	netlbl_secattr_init(&secattr); -	rc = security_netlbl_sid_to_secattr(sid, &secattr); -	if (rc != 0) -		goto skbuff_setsid_return; -	rc = netlbl_skbuff_setattr(skb, family, &secattr); +	rc = netlbl_skbuff_setattr(skb, family, secattr);  skbuff_setsid_return: -	netlbl_secattr_destroy(&secattr); +	if (secattr == &secattr_storage) +		netlbl_secattr_destroy(secattr);  	return rc;  } @@ -245,18 +293,18 @@ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)  {  	int rc;  	struct sk_security_struct *sksec = sk->sk_security; -	struct netlbl_lsm_secattr secattr; +	struct netlbl_lsm_secattr *secattr;  	struct inet_sock *sk_inet = inet_sk(sk);  	struct sockaddr_in addr;  	if (sksec->nlbl_state != NLBL_REQUIRE)  		return; -	netlbl_secattr_init(&secattr); -	if (security_netlbl_sid_to_secattr(sksec->sid, &secattr) != 0) -		goto inet_conn_established_return; +	secattr = selinux_netlbl_sock_genattr(sk); +	if (secattr == NULL) +		return; -	rc = netlbl_sock_setattr(sk, &secattr); +	rc = netlbl_sock_setattr(sk, secattr);  	switch (rc) {  	case 0:  		sksec->nlbl_state = NLBL_LABELED; @@ -266,13 +314,13 @@ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)  		 * labeling protocols */  		if (family != PF_INET) {  			sksec->nlbl_state = NLBL_UNSET; -			goto inet_conn_established_return; +			return;  		}  		addr.sin_family = family;  		addr.sin_addr.s_addr = sk_inet->daddr;  		if (netlbl_conn_setattr(sk, (struct sockaddr *)&addr, -					&secattr) != 0) { +					secattr) != 0) {  			/* we failed to label the connected socket (could be  			 * for a variety of reasons, the actual "why" isn't  			 * important here) so we have to go to our backup plan, @@ -300,10 +348,6 @@ void selinux_netlbl_inet_conn_established(struct sock *sk, u16 family)  		 * return an error code */  		break;  	} - -inet_conn_established_return: -	netlbl_secattr_destroy(&secattr); -	return;  }  /** @@ -468,13 +512,12 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)  {  	int rc;  	struct sk_security_struct *sksec = sk->sk_security; -	struct netlbl_lsm_secattr secattr; +	struct netlbl_lsm_secattr *secattr;  	if (sksec->nlbl_state != NLBL_REQSKB &&  	    sksec->nlbl_state != NLBL_CONNLABELED)  		return 0; -	netlbl_secattr_init(&secattr);  	local_bh_disable();  	bh_lock_sock_nested(sk); @@ -487,17 +530,17 @@ int selinux_netlbl_socket_connect(struct sock *sk, struct sockaddr *addr)  		rc = 0;  		goto socket_connect_return;  	} -	rc = security_netlbl_sid_to_secattr(sksec->sid, &secattr); -	if (rc != 0) +	secattr = selinux_netlbl_sock_genattr(sk); +	if (secattr == NULL) { +		rc = -ENOMEM;  		goto socket_connect_return; -	rc = netlbl_conn_setattr(sk, addr, &secattr); -	if (rc != 0) -		goto socket_connect_return; -	sksec->nlbl_state = NLBL_CONNLABELED; +	} +	rc = netlbl_conn_setattr(sk, addr, secattr); +	if (rc == 0) +		sksec->nlbl_state = NLBL_CONNLABELED;  socket_connect_return:  	bh_unlock_sock(sk);  	local_bh_enable(); -	netlbl_secattr_destroy(&secattr);  	return rc;  }  |