Commit 99a6740f authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'Smack-for-5.10' of git://github.com/cschaufler/smack-next

Pull smack updates from Casey Schaufler:
 "Two minor fixes and one performance enhancement to Smack. The
  performance improvement is significant and the new code is more like
  its counterpart in SELinux.

   - Two kernel test robot suggested clean-ups.

   - Teach Smack to use the IPv4 netlabel cache. This results in a
     12-14% improvement on TCP benchmarks"

* tag 'Smack-for-5.10' of git://github.com/cschaufler/smack-next:
  Smack: Remove unnecessary variable initialization
  Smack: Fix build when NETWORK_SECMARK is not set
  Smack: Use the netlabel cache
  Smack: Set socket labels only once
  Smack: Consolidate uses of secmark into a function
parents b274279a edd61537
Loading
Loading
Loading
Loading
+6 −13
Original line number Diff line number Diff line
@@ -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
@@ -196,19 +201,6 @@ enum {
#define SMACK_DELETE_OPTION	"-DELETE"
#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.
 */
@@ -305,6 +297,7 @@ struct smack_known *smk_find_entry(const char *);
bool smack_privileged(int cap);
bool smack_privileged_cred(int cap, const struct cred *cred);
void smk_destroy_label_list(struct list_head *list);
int smack_populate_secattr(struct smack_known *skp);

/*
 * Shared data.
+37 −18
Original line number Diff line number Diff line
@@ -510,6 +510,42 @@ int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap,
	return 0;
}

/**
 * smack_populate_secattr - fill in the smack_known netlabel information
 * @skp: pointer to the structure to fill
 *
 * Populate the netlabel secattr structure for a Smack label.
 *
 * Returns 0 unless creating the category mapping fails
 */
int smack_populate_secattr(struct smack_known *skp)
{
	int slen;

	skp->smk_netlabel.attr.secid = skp->smk_secid;
	skp->smk_netlabel.domain = skp->smk_known;
	skp->smk_netlabel.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
	if (skp->smk_netlabel.cache != NULL) {
		skp->smk_netlabel.flags |= NETLBL_SECATTR_CACHE;
		skp->smk_netlabel.cache->free = NULL;
		skp->smk_netlabel.cache->data = skp;
	}
	skp->smk_netlabel.flags |= NETLBL_SECATTR_SECID |
				   NETLBL_SECATTR_MLS_LVL |
				   NETLBL_SECATTR_DOMAIN;
	/*
	 * If direct labeling works use it.
	 * Otherwise use mapped labeling.
	 */
	slen = strlen(skp->smk_known);
	if (slen < SMK_CIPSOLEN)
		return smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
				      &skp->smk_netlabel, slen);

	return smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
			      &skp->smk_netlabel, sizeof(skp->smk_secid));
}

/**
 * smk_import_entry - import a label, return the list entry
 * @string: a text string that might be a Smack label
@@ -523,7 +559,6 @@ struct smack_known *smk_import_entry(const char *string, int len)
{
	struct smack_known *skp;
	char *smack;
	int slen;
	int rc;

	smack = smk_parse_smack(string, len);
@@ -544,21 +579,8 @@ struct smack_known *smk_import_entry(const char *string, int len)

	skp->smk_known = smack;
	skp->smk_secid = smack_next_secid++;
	skp->smk_netlabel.domain = skp->smk_known;
	skp->smk_netlabel.flags =
		NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
	/*
	 * If direct labeling works use it.
	 * Otherwise use mapped labeling.
	 */
	slen = strlen(smack);
	if (slen < SMK_CIPSOLEN)
		rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
			       &skp->smk_netlabel, slen);
	else
		rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid,
			       &skp->smk_netlabel, sizeof(skp->smk_secid));

	rc = smack_populate_secattr(skp);
	if (rc >= 0) {
		INIT_LIST_HEAD(&skp->smk_rules);
		mutex_init(&skp->smk_rules_lock);
@@ -569,9 +591,6 @@ struct smack_known *smk_import_entry(const char *string, int len)
		smk_insert_entry(skp);
		goto unlockout;
	}
	/*
	 * smk_netlbl_mls failed.
	 */
	kfree(skp);
	skp = ERR_PTR(rc);
freeout:
+148 −104
Original line number Diff line number Diff line
@@ -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);
	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:
@@ -3700,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.
@@ -3747,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
@@ -3810,6 +3832,62 @@ 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.
 */
#ifdef CONFIG_NETWORK_SECMARK
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);
}
#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
 * @sk: socket data came in on
 * @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,
					     struct sk_buff *skb)
{
	struct netlbl_lsm_secattr secattr;
	struct socket_smack *ssp = NULL;
	struct smack_known *skp = NULL;
	int rc;

	netlbl_secattr_init(&secattr);

	if (sk)
		ssp = sk->sk_security;

	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);

	return skp;
}

/**
 * smack_socket_sock_rcv_skb - Smack packet delivery access check
 * @sk: socket
@@ -3819,7 +3897,6 @@ 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 smack_known *skp = NULL;
	int rc = 0;
@@ -3838,33 +3915,18 @@ 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);
			goto access_check;
		}
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */
		/*
		 * 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_from_skb(skb);
		if (skp == NULL) {
			skp = smack_from_netlbl(sk, family, skb);
			if (skp == NULL)
				skp = smack_net_ambient;
		}

		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 +3952,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))
		skp = smack_from_skb(skb);
		if (skp == NULL) {
			if (smk_ipv6_localhost(&sadd))
				break;
		else
			skp = smack_ipv6host_label(&sadd);
			if (skp == NULL)
				skp = smack_net_ambient;
		if (skb == NULL)
			break;
		}
#ifdef CONFIG_AUDIT
		smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net);
		ad.a.u.net->family = family;
@@ -3971,12 +4031,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))
@@ -3995,27 +4054,25 @@ 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.
		 */
		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
		s = skb->secmark;
		skp = smack_from_skb(skb);
		if (skp)
			s = skp->smk_secid;
#endif
		break;
	}
@@ -4063,7 +4120,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;
@@ -4087,29 +4143,17 @@ 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);
		goto access_check;
	}
#endif /* CONFIG_SECURITY_SMACK_NETFILTER */

	netlbl_secattr_init(&secattr);
	rc = netlbl_skbuff_getattr(skb, family, &secattr);
	if (rc == 0)
		skp = smack_from_secattr(&secattr, ssp);
	else
	skp = smack_from_skb(skb);
	if (skp == NULL) {
		skp = smack_from_netlbl(sk, family, skb);
		if (skp == NULL)
			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);
+9 −14
Original line number Diff line number Diff line
@@ -922,6 +922,10 @@ static ssize_t smk_set_cipso(struct file *file, const char __user *buf,
		skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat;
		skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl;
		rc = count;
		/*
		 * This mapping may have been cached, so clear the cache.
		 */
		netlbl_cache_invalidate();
	}

out:
@@ -2950,15 +2954,6 @@ static struct file_system_type smk_fs_type = {

static struct vfsmount *smackfs_mount;

static int __init smk_preset_netlabel(struct smack_known *skp)
{
	skp->smk_netlabel.domain = skp->smk_known;
	skp->smk_netlabel.flags =
		NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL;
	return smk_netlbl_mls(smack_cipso_direct, skp->smk_known,
				&skp->smk_netlabel, strlen(skp->smk_known));
}

/**
 * init_smk_fs - get the smackfs superblock
 *
@@ -2997,19 +2992,19 @@ static int __init init_smk_fs(void)
	smk_cipso_doi();
	smk_unlbl_ambient(NULL);

	rc = smk_preset_netlabel(&smack_known_floor);
	rc = smack_populate_secattr(&smack_known_floor);
	if (err == 0 && rc < 0)
		err = rc;
	rc = smk_preset_netlabel(&smack_known_hat);
	rc = smack_populate_secattr(&smack_known_hat);
	if (err == 0 && rc < 0)
		err = rc;
	rc = smk_preset_netlabel(&smack_known_huh);
	rc = smack_populate_secattr(&smack_known_huh);
	if (err == 0 && rc < 0)
		err = rc;
	rc = smk_preset_netlabel(&smack_known_star);
	rc = smack_populate_secattr(&smack_known_star);
	if (err == 0 && rc < 0)
		err = rc;
	rc = smk_preset_netlabel(&smack_known_web);
	rc = smack_populate_secattr(&smack_known_web);
	if (err == 0 && rc < 0)
		err = rc;