return rc;
}
+/**
+ * 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
{
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;
break;
}
-sock_setsid_return:
- netlbl_secattr_destroy(&secattr);
return rc;
}
netlbl_skbuff_err(skb, error, 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
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
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;
}
{
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;
* 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,
* return an error code */
break;
}
-
-inet_conn_established_return:
- netlbl_secattr_destroy(&secattr);
- return;
}
/**
{
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);
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;
}