diff options
Diffstat (limited to 'security/smack')
-rw-r--r-- | security/smack/smack.h | 18 | ||||
-rw-r--r-- | security/smack/smack_lsm.c | 169 |
2 files changed, 98 insertions, 89 deletions
diff --git a/security/smack/smack.h b/security/smack/smack.h index e9e817d09785..c5d745a3ada8 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -100,7 +100,12 @@ struct socket_smack { struct smack_known *smk_out; /* outbound label */ struct smack_known *smk_in; /* inbound label */ struct smack_known *smk_packet; /* TCP peer label */ + int smk_state; /* netlabel socket states */ }; +#define SMK_NETLBL_UNSET 0 +#define SMK_NETLBL_UNLABELED 1 +#define SMK_NETLBL_LABELED 2 +#define SMK_NETLBL_REQSKB 3 /* * Inode smack data @@ -197,19 +202,6 @@ enum { #define SMACK_CIPSO_OPTION "-CIPSO" /* - * How communications on this socket are treated. - * Usually it's determined by the underlying netlabel code - * but there are certain cases, including single label hosts - * and potentially single label interfaces for which the - * treatment can not be known in advance. - * - * The possibility of additional labeling schemes being - * introduced in the future exists as well. - */ -#define SMACK_UNLABELED_SOCKET 0 -#define SMACK_CIPSO_SOCKET 1 - -/* * CIPSO defaults. */ #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 3402ac4aa28e..7a79ddb39e94 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -2383,38 +2383,31 @@ static struct smack_known *smack_ipv6host_label(struct sockaddr_in6 *sip) } /** - * smack_netlabel - Set the secattr on a socket + * smack_netlbl_add - Set the secattr on a socket * @sk: the socket - * @labeled: socket label scheme * - * Convert the outbound smack value (smk_out) to a - * secattr and attach it to the socket. + * Attach the outbound smack value (smk_out) to the socket. * * Returns 0 on success or an error code */ -static int smack_netlabel(struct sock *sk, int labeled) +static int smack_netlbl_add(struct sock *sk) { - struct smack_known *skp; struct socket_smack *ssp = sk->sk_security; - int rc = 0; + struct smack_known *skp = ssp->smk_out; + int rc; - /* - * Usually the netlabel code will handle changing the - * packet labeling based on the label. - * The case of a single label host is different, because - * a single label host should never get a labeled packet - * even though the label is usually associated with a packet - * label. - */ local_bh_disable(); bh_lock_sock_nested(sk); - if (ssp->smk_out == smack_net_ambient || - labeled == SMACK_UNLABELED_SOCKET) - netlbl_sock_delattr(sk); - else { - skp = ssp->smk_out; - rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); + rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); + switch (rc) { + case 0: + ssp->smk_state = SMK_NETLBL_LABELED; + break; + case -EDESTADDRREQ: + ssp->smk_state = SMK_NETLBL_REQSKB; + rc = 0; + break; } bh_unlock_sock(sk); @@ -2424,7 +2417,31 @@ static int smack_netlabel(struct sock *sk, int labeled) } /** - * smack_netlbel_send - Set the secattr on a socket and perform access checks + * smack_netlbl_delete - Remove the secattr from a socket + * @sk: the socket + * + * Remove the outbound smack value from a socket + */ +static void smack_netlbl_delete(struct sock *sk) +{ + struct socket_smack *ssp = sk->sk_security; + + /* + * Take the label off the socket if one is set. + */ + if (ssp->smk_state != SMK_NETLBL_LABELED) + return; + + local_bh_disable(); + bh_lock_sock_nested(sk); + netlbl_sock_delattr(sk); + bh_unlock_sock(sk); + local_bh_enable(); + ssp->smk_state = SMK_NETLBL_UNLABELED; +} + +/** + * smk_ipv4_check - Perform IPv4 host access checks * @sk: the socket * @sap: the destination address * @@ -2434,11 +2451,10 @@ static int smack_netlabel(struct sock *sk, int labeled) * Returns 0 on success or an error code. * */ -static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) +static int smk_ipv4_check(struct sock *sk, struct sockaddr_in *sap) { struct smack_known *skp; - int rc; - int sk_lbl; + int rc = 0; struct smack_known *hkp; struct socket_smack *ssp = sk->sk_security; struct smk_audit_info ad; @@ -2454,19 +2470,18 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) ad.a.u.net->dport = sap->sin_port; ad.a.u.net->v4info.daddr = sap->sin_addr.s_addr; #endif - sk_lbl = SMACK_UNLABELED_SOCKET; skp = ssp->smk_out; rc = smk_access(skp, hkp, MAY_WRITE, &ad); rc = smk_bu_note("IPv4 host check", skp, hkp, MAY_WRITE, rc); - } else { - sk_lbl = SMACK_CIPSO_SOCKET; - rc = 0; + /* + * Clear the socket netlabel if it's set. + */ + if (!rc) + smack_netlbl_delete(sk); } rcu_read_unlock(); - if (rc != 0) - return rc; - return smack_netlabel(sk, sk_lbl); + return rc; } /** @@ -2703,7 +2718,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, else if (strcmp(name, XATTR_SMACK_IPOUT) == 0) { ssp->smk_out = skp; if (sock->sk->sk_family == PF_INET) { - rc = smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); + rc = smack_netlbl_add(sock->sk); if (rc != 0) printk(KERN_WARNING "Smack: \"%s\" netlbl error %d.\n", @@ -2754,7 +2769,7 @@ static int smack_socket_post_create(struct socket *sock, int family, /* * Set the outbound netlbl. */ - return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); + return smack_netlbl_add(sock->sk); } /** @@ -2845,7 +2860,7 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, } if (sap->sa_family != AF_INET || addrlen < sizeof(struct sockaddr_in)) return 0; - rc = smack_netlabel_send(sock->sk, (struct sockaddr_in *)sap); + rc = smk_ipv4_check(sock->sk, (struct sockaddr_in *)sap); return rc; } @@ -3663,7 +3678,7 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, if (msg->msg_namelen < sizeof(struct sockaddr_in) || sip->sin_family != AF_INET) return -EINVAL; - rc = smack_netlabel_send(sock->sk, sip); + rc = smk_ipv4_check(sock->sk, sip); break; #if IS_ENABLED(CONFIG_IPV6) case AF_INET6: @@ -3825,6 +3840,33 @@ static struct smack_known *smack_from_skb(struct sk_buff *skb) } /** + * smack_from_netlbl - Smack data from the IP options in an skb + * @sk: socket data came in on + * @family: address family + * @skb: packet + * + * Returns smack_known of the IP options or NULL if that won't work. + */ +static struct smack_known *smack_from_netlbl(struct sock *sk, u16 family, + struct sk_buff *skb) +{ + struct netlbl_lsm_secattr secattr; + struct socket_smack *ssp = NULL; + struct smack_known *skp = NULL; + + netlbl_secattr_init(&secattr); + + if (sk) + ssp = sk->sk_security; + if (netlbl_skbuff_getattr(skb, family, &secattr) == 0) + skp = smack_from_secattr(&secattr, ssp); + + netlbl_secattr_destroy(&secattr); + + return skp; +} + +/** * smack_socket_sock_rcv_skb - Smack packet delivery access check * @sk: socket * @skb: packet @@ -3833,7 +3875,6 @@ static struct smack_known *smack_from_skb(struct sk_buff *skb) */ 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 smack_known *skp = NULL; int rc = 0; @@ -3858,22 +3899,11 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) * The secmark is assumed to reflect policy better. */ skp = smack_from_skb(skb); - if (skp) - goto access_check; - /* - * Translate what netlabel gave us. - */ - netlbl_secattr_init(&secattr); - - rc = netlbl_skbuff_getattr(skb, family, &secattr); - if (rc == 0) - skp = smack_from_secattr(&secattr, ssp); - else - skp = smack_net_ambient; - - netlbl_secattr_destroy(&secattr); - -access_check: + if (skp == NULL) { + skp = smack_from_netlbl(sk, family, skb); + if (skp == NULL) + skp = smack_net_ambient; + } #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); @@ -3979,12 +4009,11 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) { - struct netlbl_lsm_secattr secattr; struct socket_smack *ssp = NULL; struct smack_known *skp; + struct sock *sk = NULL; int family = PF_UNSPEC; u32 s = 0; /* 0 is the invalid secid */ - int rc; if (skb != NULL) { if (skb->protocol == htons(ETH_P_IP)) @@ -4011,15 +4040,11 @@ 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; - netlbl_secattr_init(&secattr); - rc = netlbl_skbuff_getattr(skb, family, &secattr); - if (rc == 0) { - skp = smack_from_secattr(&secattr, ssp); + if (sock != NULL) + sk = sock->sk; + skp = smack_from_netlbl(sk, family, skb); + if (skp != NULL) s = skp->smk_secid; - } - netlbl_secattr_destroy(&secattr); break; case PF_INET6: #ifdef SMACK_IPV6_SECMARK_LABELING @@ -4073,7 +4098,6 @@ 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 netlbl_lsm_secattr secattr; struct sockaddr_in addr; struct iphdr *hdr; struct smack_known *hskp; @@ -4103,18 +4127,11 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, * The secmark is assumed to reflect policy better. */ skp = smack_from_skb(skb); - if (skp) - goto access_check; - - netlbl_secattr_init(&secattr); - rc = netlbl_skbuff_getattr(skb, family, &secattr); - if (rc == 0) - skp = smack_from_secattr(&secattr, ssp); - else - skp = &smack_known_huh; - netlbl_secattr_destroy(&secattr); - -access_check: + if (skp == NULL) { + skp = smack_from_netlbl(sk, family, skb); + if (skp == NULL) + skp = &smack_known_huh; + } #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); |