From 36be81293dbe35aca487917c2d76941bf734d2ad Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Tue, 11 Aug 2020 17:39:41 -0700 Subject: Smack: Consolidate uses of secmark into a function Add a function smack_from_skb() that returns the Smack label identified by a network secmark. Replace the explicit uses of the secmark with this function. Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 61 +++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 28 deletions(-) (limited to 'security/smack/smack_lsm.c') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 8ffbf951b7ed..3402ac4aa28e 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3810,6 +3810,20 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip) } #endif /* CONFIG_IPV6 */ +/** + * smack_from_skb - Smack data from the secmark in an skb + * @skb: packet + * + * Returns smack_known of the secmark or NULL if that won't work. + */ +static struct smack_known *smack_from_skb(struct sk_buff *skb) +{ + if (skb == NULL || skb->secmark == 0) + return NULL; + + return smack_from_secid(skb->secmark); +} + /** * smack_socket_sock_rcv_skb - Smack packet delivery access check * @sk: socket @@ -3838,17 +3852,14 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) switch (family) { case PF_INET: -#ifdef CONFIG_SECURITY_SMACK_NETFILTER /* * If there is a secmark use it rather than the CIPSO label. * If there is no secmark fall back to CIPSO. * The secmark is assumed to reflect policy better. */ - if (skb && skb->secmark != 0) { - skp = smack_from_secid(skb->secmark); + skp = smack_from_skb(skb); + if (skp) goto access_check; - } -#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ /* * Translate what netlabel gave us. */ @@ -3862,9 +3873,8 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) netlbl_secattr_destroy(&secattr); -#ifdef CONFIG_SECURITY_SMACK_NETFILTER access_check: -#endif + #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); ad.a.u.net->family = family; @@ -3890,16 +3900,14 @@ access_check: proto != IPPROTO_TCP && proto != IPPROTO_DCCP) break; #ifdef SMACK_IPV6_SECMARK_LABELING - if (skb && skb->secmark != 0) - skp = smack_from_secid(skb->secmark); - else if (smk_ipv6_localhost(&sadd)) - break; - else + skp = smack_from_skb(skb); + if (skp == NULL) { + if (smk_ipv6_localhost(&sadd)) + break; skp = smack_ipv6host_label(&sadd); - if (skp == NULL) - skp = smack_net_ambient; - if (skb == NULL) - break; + if (skp == NULL) + skp = smack_net_ambient; + } #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); ad.a.u.net->family = family; @@ -3995,11 +4003,11 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, s = ssp->smk_out->smk_secid; break; case PF_INET: -#ifdef CONFIG_SECURITY_SMACK_NETFILTER - s = skb->secmark; - if (s != 0) + skp = smack_from_skb(skb); + if (skp) { + s = skp->smk_secid; break; -#endif + } /* * Translate what netlabel gave us. */ @@ -4015,7 +4023,9 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, break; case PF_INET6: #ifdef SMACK_IPV6_SECMARK_LABELING - s = skb->secmark; + skp = smack_from_skb(skb); + if (skp) + s = skp->smk_secid; #endif break; } @@ -4087,17 +4097,14 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, } #endif /* CONFIG_IPV6 */ -#ifdef CONFIG_SECURITY_SMACK_NETFILTER /* * If there is a secmark use it rather than the CIPSO label. * If there is no secmark fall back to CIPSO. * The secmark is assumed to reflect policy better. */ - if (skb && skb->secmark != 0) { - skp = smack_from_secid(skb->secmark); + skp = smack_from_skb(skb); + if (skp) goto access_check; - } -#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ netlbl_secattr_init(&secattr); rc = netlbl_skbuff_getattr(skb, family, &secattr); @@ -4107,9 +4114,7 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, skp = &smack_known_huh; netlbl_secattr_destroy(&secattr); -#ifdef CONFIG_SECURITY_SMACK_NETFILTER access_check: -#endif #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); -- cgit From a2af031885071604452f03cd4e0eafdbd8014767 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Tue, 11 Aug 2020 17:39:42 -0700 Subject: Smack: Set socket labels only once Refactor the IP send checks so that the netlabel value is set only when necessary, not on every send. Some functions get renamed as the changes made the old name misleading. Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 169 +++++++++++++++++++++++++-------------------- 1 file changed, 93 insertions(+), 76 deletions(-) (limited to 'security/smack/smack_lsm.c') 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: @@ -3824,6 +3839,33 @@ static struct smack_known *smack_from_skb(struct sk_buff *skb) return smack_from_secid(skb->secmark); } +/** + * 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 @@ -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); -- cgit From 322dd63c7f98315b5794653bc582d109841219ae Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Tue, 11 Aug 2020 17:39:43 -0700 Subject: Smack: Use the netlabel cache Utilize the Netlabel cache mechanism for incoming packet matching. Refactor the initialization of secattr structures, as it was being done in two places. Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'security/smack/smack_lsm.c') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 7a79ddb39e94..86db667ce319 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3715,6 +3715,18 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, int acat; int kcat; + /* + * Netlabel found it in the cache. + */ + if ((sap->flags & NETLBL_SECATTR_CACHE) != 0) + return (struct smack_known *)sap->cache->data; + + if ((sap->flags & NETLBL_SECATTR_SECID) != 0) + /* + * Looks like a fallback, which gives us a secid. + */ + return smack_from_secid(sap->attr.secid); + if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { /* * Looks like a CIPSO packet. @@ -3762,11 +3774,6 @@ static struct smack_known *smack_from_secattr(struct netlbl_lsm_secattr *sap, return &smack_known_web; return &smack_known_star; } - if ((sap->flags & NETLBL_SECATTR_SECID) != 0) - /* - * Looks like a fallback, which gives us a secid. - */ - return smack_from_secid(sap->attr.secid); /* * Without guidance regarding the smack value * for the packet fall back on the network @@ -3845,6 +3852,9 @@ static struct smack_known *smack_from_skb(struct sk_buff *skb) * @family: address family * @skb: packet * + * Find the Smack label in the IP options. If it hasn't been + * added to the netlabel cache, add it here. + * * 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, @@ -3853,13 +3863,18 @@ static struct smack_known *smack_from_netlbl(struct sock *sk, u16 family, struct netlbl_lsm_secattr secattr; struct socket_smack *ssp = NULL; struct smack_known *skp = NULL; + int rc = 0; netlbl_secattr_init(&secattr); if (sk) ssp = sk->sk_security; - if (netlbl_skbuff_getattr(skb, family, &secattr) == 0) + + if (netlbl_skbuff_getattr(skb, family, &secattr) == 0) { skp = smack_from_secattr(&secattr, ssp); + if (secattr.flags & NETLBL_SECATTR_CACHEABLE) + rc = netlbl_cache_add(skb, family, &skp->smk_netlabel); + } netlbl_secattr_destroy(&secattr); -- cgit From bf0afe673b999439b6a53c75727821795ccb27e2 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Tue, 22 Sep 2020 14:59:31 -0700 Subject: Smack: Fix build when NETWORK_SECMARK is not set Use proper conditional compilation for the secmark field in the network skb. Reported-by: kernel test robot Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'security/smack/smack_lsm.c') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 86db667ce319..aa60a9468734 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3838,6 +3838,7 @@ static int smk_skb_to_addr_ipv6(struct sk_buff *skb, struct sockaddr_in6 *sip) * * Returns smack_known of the secmark or NULL if that won't work. */ +#ifdef CONFIG_NETWORK_SECMARK static struct smack_known *smack_from_skb(struct sk_buff *skb) { if (skb == NULL || skb->secmark == 0) @@ -3845,6 +3846,12 @@ static struct smack_known *smack_from_skb(struct sk_buff *skb) return smack_from_secid(skb->secmark); } +#else +static inline struct smack_known *smack_from_skb(struct sk_buff *skb) +{ + return NULL; +} +#endif /** * smack_from_netlbl - Smack data from the IP options in an skb -- cgit From edd615371b668404d06699c04f5f90c4f438814a Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Mon, 5 Oct 2020 14:20:51 -0700 Subject: Smack: Remove unnecessary variable initialization The initialization of rc in smack_from_netlbl() is pointless. Reported-by: kernel test robot Signed-off-by: Casey Schaufler --- security/smack/smack_lsm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'security/smack/smack_lsm.c') diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index aa60a9468734..db2d455b80a8 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -3870,7 +3870,7 @@ static struct smack_known *smack_from_netlbl(struct sock *sk, u16 family, struct netlbl_lsm_secattr secattr; struct socket_smack *ssp = NULL; struct smack_known *skp = NULL; - int rc = 0; + int rc; netlbl_secattr_init(&secattr); -- cgit