Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 13541b3a authored by Paul Moore's avatar Paul Moore Committed by James Morris
Browse files

NetLabel: Add auditing to the static labeling mechanism



This patch adds auditing support to the NetLabel static labeling mechanism.

Signed-off-by: default avatarPaul Moore <paul.moore@hp.com>
Signed-off-by: default avatarJames Morris <jmorris@namei.org>
parent 8cc44579
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -115,6 +115,8 @@
#define AUDIT_MAC_IPSEC_ADDSPD	1413	/* Not used */
#define AUDIT_MAC_IPSEC_DELSPD	1414	/* Not used */
#define AUDIT_MAC_IPSEC_EVENT	1415	/* Audit an IPSec event */
#define AUDIT_MAC_UNLBL_STCADD	1416	/* NetLabel: add a static label */
#define AUDIT_MAC_UNLBL_STCDEL	1417	/* NetLabel: del a static label */

#define AUDIT_FIRST_KERN_ANOM_MSG   1700
#define AUDIT_LAST_KERN_ANOM_MSG    1799
+193 −14
Original line number Diff line number Diff line
@@ -146,6 +146,74 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1
	[NLBL_UNLABEL_A_SECCTX] = { .type = NLA_BINARY }
};

/*
 * Audit Helper Functions
 */

/**
 * netlbl_unlabel_audit_addr4 - Audit an IPv4 address
 * @audit_buf: audit buffer
 * @dev: network interface
 * @addr: IP address
 * @mask: IP address mask
 *
 * Description:
 * Write the IPv4 address and address mask, if necessary, to @audit_buf.
 *
 */
static void netlbl_unlabel_audit_addr4(struct audit_buffer *audit_buf,
				     const char *dev,
				     __be32 addr, __be32 mask)
{
	u32 mask_val = ntohl(mask);

	if (dev != NULL)
		audit_log_format(audit_buf, " netif=%s", dev);
	audit_log_format(audit_buf, " src=" NIPQUAD_FMT, NIPQUAD(addr));
	if (mask_val != 0xffffffff) {
		u32 mask_len = 0;
		while (mask_val > 0) {
			mask_val <<= 1;
			mask_len++;
		}
		audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
	}
}

/**
 * netlbl_unlabel_audit_addr6 - Audit an IPv6 address
 * @audit_buf: audit buffer
 * @dev: network interface
 * @addr: IP address
 * @mask: IP address mask
 *
 * Description:
 * Write the IPv6 address and address mask, if necessary, to @audit_buf.
 *
 */
static void netlbl_unlabel_audit_addr6(struct audit_buffer *audit_buf,
				     const char *dev,
				     const struct in6_addr *addr,
				     const struct in6_addr *mask)
{
	if (dev != NULL)
		audit_log_format(audit_buf, " netif=%s", dev);
	audit_log_format(audit_buf, " src=" NIP6_FMT, NIP6(*addr));
	if (ntohl(mask->s6_addr32[3]) != 0xffffffff) {
		u32 mask_len = 0;
		u32 mask_val;
		int iter = -1;
		while (ntohl(mask->s6_addr32[++iter]) == 0xffffffff)
			mask_len += 32;
		mask_val = ntohl(mask->s6_addr32[iter]);
		while (mask_val > 0) {
			mask_val <<= 1;
			mask_len++;
		}
		audit_log_format(audit_buf, " src_prefixlen=%d", mask_len);
	}
}

/*
 * Unlabeled Connection Hash Table Functions
 */
@@ -530,6 +598,7 @@ add_iface_failure:
 * @mask: address mask in network byte order
 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
 * @secid: LSM secid value for the entry
 * @audit_info: NetLabel audit information
 *
 * Description:
 * Adds a new entry to the unlabeled connection hash table.  Returns zero on
@@ -541,12 +610,18 @@ static int netlbl_unlhsh_add(struct net *net,
			     const void *addr,
			     const void *mask,
			     u32 addr_len,
			     u32 secid)
			     u32 secid,
			     struct netlbl_audit *audit_info)
{
	int ret_val;
	int ifindex;
	struct net_device *dev;
	struct netlbl_unlhsh_iface *iface;
	struct in_addr *addr4, *mask4;
	struct in6_addr *addr6, *mask6;
	struct audit_buffer *audit_buf = NULL;
	char *secctx = NULL;
	u32 secctx_len;

	if (addr_len != sizeof(struct in_addr) &&
	    addr_len != sizeof(struct in6_addr))
@@ -573,13 +648,28 @@ static int netlbl_unlhsh_add(struct net *net,
			goto unlhsh_add_return;
		}
	}
	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCADD,
					      audit_info);
	switch (addr_len) {
	case sizeof(struct in_addr):
		ret_val = netlbl_unlhsh_add_addr4(iface, addr, mask, secid);
		addr4 = (struct in_addr *)addr;
		mask4 = (struct in_addr *)mask;
		ret_val = netlbl_unlhsh_add_addr4(iface, addr4, mask4, secid);
		if (audit_buf != NULL)
			netlbl_unlabel_audit_addr4(audit_buf,
						   dev_name,
						   addr4->s_addr,
						   mask4->s_addr);
		break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	case sizeof(struct in6_addr):
		ret_val = netlbl_unlhsh_add_addr6(iface, addr, mask, secid);
		addr6 = (struct in6_addr *)addr;
		mask6 = (struct in6_addr *)mask;
		ret_val = netlbl_unlhsh_add_addr6(iface, addr6, mask6, secid);
		if (audit_buf != NULL)
			netlbl_unlabel_audit_addr6(audit_buf,
						   dev_name,
						   addr6, mask6);
		break;
#endif /* IPv6 */
	default:
@@ -590,14 +680,26 @@ static int netlbl_unlhsh_add(struct net *net,

unlhsh_add_return:
	rcu_read_unlock();
	if (audit_buf != NULL) {
		if (security_secid_to_secctx(secid,
					     &secctx,
					     &secctx_len) == 0) {
			audit_log_format(audit_buf, " sec_obj=%s", secctx);
			security_release_secctx(secctx, secctx_len);
		}
		audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
		audit_log_end(audit_buf);
	}
	return ret_val;
}

/**
 * netlbl_unlhsh_remove_addr4 - Remove an IPv4 address entry
 * @net: network namespace
 * @iface: interface entry
 * @addr: IP address
 * @mask: IP address mask
 * @audit_info: NetLabel audit information
 *
 * Description:
 * Remove an IP address entry from the unlabeled connection hash table.
@@ -605,12 +707,18 @@ unlhsh_add_return:
 * responsible for calling the rcu_read_[un]lock() functions.
 *
 */
static int netlbl_unlhsh_remove_addr4(struct netlbl_unlhsh_iface *iface,
static int netlbl_unlhsh_remove_addr4(struct net *net,
				      struct netlbl_unlhsh_iface *iface,
				      const struct in_addr *addr,
				      const struct in_addr *mask)
				      const struct in_addr *mask,
				      struct netlbl_audit *audit_info)
{
	int ret_val = -ENOENT;
	struct netlbl_unlhsh_addr4 *entry;
	struct audit_buffer *audit_buf = NULL;
	struct net_device *dev;
	char *secctx = NULL;
	u32 secctx_len;

	spin_lock(&netlbl_unlhsh_lock);
	entry = netlbl_unlhsh_search_addr4(addr->s_addr, iface);
@@ -622,6 +730,25 @@ static int netlbl_unlhsh_remove_addr4(struct netlbl_unlhsh_iface *iface,
	}
	spin_unlock(&netlbl_unlhsh_lock);

	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
					      audit_info);
	if (audit_buf != NULL) {
		dev = dev_get_by_index(net, iface->ifindex);
		netlbl_unlabel_audit_addr4(audit_buf,
					   (dev != NULL ? dev->name : NULL),
					   entry->addr, entry->mask);
		if (dev != NULL)
			dev_put(dev);
		if (security_secid_to_secctx(entry->secid,
					     &secctx,
					     &secctx_len) == 0) {
			audit_log_format(audit_buf, " sec_obj=%s", secctx);
			security_release_secctx(secctx, secctx_len);
		}
		audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
		audit_log_end(audit_buf);
	}

	if (ret_val == 0)
		call_rcu(&entry->rcu, netlbl_unlhsh_free_addr4);
	return ret_val;
@@ -630,9 +757,11 @@ static int netlbl_unlhsh_remove_addr4(struct netlbl_unlhsh_iface *iface,
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
 * netlbl_unlhsh_remove_addr6 - Remove an IPv6 address entry
 * @net: network namespace
 * @iface: interface entry
 * @addr: IP address
 * @mask: IP address mask
 * @audit_info: NetLabel audit information
 *
 * Description:
 * Remove an IP address entry from the unlabeled connection hash table.
@@ -640,12 +769,18 @@ static int netlbl_unlhsh_remove_addr4(struct netlbl_unlhsh_iface *iface,
 * responsible for calling the rcu_read_[un]lock() functions.
 *
 */
static int netlbl_unlhsh_remove_addr6(struct netlbl_unlhsh_iface *iface,
static int netlbl_unlhsh_remove_addr6(struct net *net,
				      struct netlbl_unlhsh_iface *iface,
				      const struct in6_addr *addr,
				      const struct in6_addr *mask)
				      const struct in6_addr *mask,
				      struct netlbl_audit *audit_info)
{
	int ret_val = -ENOENT;
	struct netlbl_unlhsh_addr6 *entry;
	struct audit_buffer *audit_buf = NULL;
	struct net_device *dev;
	char *secctx = NULL;
	u32 secctx_len;

	spin_lock(&netlbl_unlhsh_lock);
	entry = netlbl_unlhsh_search_addr6(addr, iface);
@@ -658,6 +793,25 @@ static int netlbl_unlhsh_remove_addr6(struct netlbl_unlhsh_iface *iface,
	}
	spin_unlock(&netlbl_unlhsh_lock);

	audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_STCDEL,
					      audit_info);
	if (audit_buf != NULL) {
		dev = dev_get_by_index(net, iface->ifindex);
		netlbl_unlabel_audit_addr6(audit_buf,
					   (dev != NULL ? dev->name : NULL),
					   addr, mask);
		if (dev != NULL)
			dev_put(dev);
		if (security_secid_to_secctx(entry->secid,
					     &secctx,
					     &secctx_len) == 0) {
			audit_log_format(audit_buf, " sec_obj=%s", secctx);
			security_release_secctx(secctx, secctx_len);
		}
		audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
		audit_log_end(audit_buf);
	}

	if (ret_val == 0)
		call_rcu(&entry->rcu, netlbl_unlhsh_free_addr6);
	return ret_val;
@@ -708,6 +862,7 @@ unlhsh_condremove_failure:
 * @addr: IP address in network byte order
 * @mask: address mask in network byte order
 * @addr_len: length of address/mask (4 for IPv4, 16 for IPv6)
 * @audit_info: NetLabel audit information
 *
 * Description:
 * Removes and existing entry from the unlabeled connection hash table.
@@ -718,7 +873,8 @@ static int netlbl_unlhsh_remove(struct net *net,
				const char *dev_name,
				const void *addr,
				const void *mask,
				u32 addr_len)
				u32 addr_len,
				struct netlbl_audit *audit_info)
{
	int ret_val;
	struct net_device *dev;
@@ -745,11 +901,15 @@ static int netlbl_unlhsh_remove(struct net *net,
	}
	switch (addr_len) {
	case sizeof(struct in_addr):
		ret_val = netlbl_unlhsh_remove_addr4(iface, addr, mask);
		ret_val = netlbl_unlhsh_remove_addr4(net,
						     iface, addr, mask,
						     audit_info);
		break;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
	case sizeof(struct in6_addr):
		ret_val = netlbl_unlhsh_remove_addr6(iface, addr, mask);
		ret_val = netlbl_unlhsh_remove_addr6(net,
						     iface, addr, mask,
						     audit_info);
		break;
#endif /* IPv6 */
	default:
@@ -972,6 +1132,7 @@ static int netlbl_unlabel_staticadd(struct sk_buff *skb,
	void *mask;
	u32 addr_len;
	u32 secid;
	struct netlbl_audit audit_info;

	/* Don't allow users to add both IPv4 and IPv6 addresses for a
	 * single entry.  However, allow users to create two entries, one each
@@ -985,6 +1146,8 @@ static int netlbl_unlabel_staticadd(struct sk_buff *skb,
	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
		return -EINVAL;

	netlbl_netlink_auditinfo(skb, &audit_info);

	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
	if (ret_val != 0)
		return ret_val;
@@ -997,7 +1160,8 @@ static int netlbl_unlabel_staticadd(struct sk_buff *skb,
		return ret_val;

	return netlbl_unlhsh_add(&init_net,
				 dev_name, addr, mask, addr_len, secid);
				 dev_name, addr, mask, addr_len, secid,
				 &audit_info);
}

/**
@@ -1019,6 +1183,7 @@ static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
	void *mask;
	u32 addr_len;
	u32 secid;
	struct netlbl_audit audit_info;

	/* Don't allow users to add both IPv4 and IPv6 addresses for a
	 * single entry.  However, allow users to create two entries, one each
@@ -1031,6 +1196,8 @@ static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
		return -EINVAL;

	netlbl_netlink_auditinfo(skb, &audit_info);

	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
	if (ret_val != 0)
		return ret_val;
@@ -1041,7 +1208,9 @@ static int netlbl_unlabel_staticadddef(struct sk_buff *skb,
	if (ret_val != 0)
		return ret_val;

	return netlbl_unlhsh_add(&init_net, NULL, addr, mask, addr_len, secid);
	return netlbl_unlhsh_add(&init_net,
				 NULL, addr, mask, addr_len, secid,
				 &audit_info);
}

/**
@@ -1063,6 +1232,7 @@ static int netlbl_unlabel_staticremove(struct sk_buff *skb,
	void *addr;
	void *mask;
	u32 addr_len;
	struct netlbl_audit audit_info;

	/* See the note in netlbl_unlabel_staticadd() about not allowing both
	 * IPv4 and IPv6 in the same entry. */
@@ -1073,12 +1243,16 @@ static int netlbl_unlabel_staticremove(struct sk_buff *skb,
	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
		return -EINVAL;

	netlbl_netlink_auditinfo(skb, &audit_info);

	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
	if (ret_val != 0)
		return ret_val;
	dev_name = nla_data(info->attrs[NLBL_UNLABEL_A_IFACE]);

	return netlbl_unlhsh_remove(&init_net, dev_name, addr, mask, addr_len);
	return netlbl_unlhsh_remove(&init_net,
				    dev_name, addr, mask, addr_len,
				    &audit_info);
}

/**
@@ -1099,6 +1273,7 @@ static int netlbl_unlabel_staticremovedef(struct sk_buff *skb,
	void *addr;
	void *mask;
	u32 addr_len;
	struct netlbl_audit audit_info;

	/* See the note in netlbl_unlabel_staticadd() about not allowing both
	 * IPv4 and IPv6 in the same entry. */
@@ -1108,11 +1283,15 @@ static int netlbl_unlabel_staticremovedef(struct sk_buff *skb,
	       !info->attrs[NLBL_UNLABEL_A_IPV6MASK])))
		return -EINVAL;

	netlbl_netlink_auditinfo(skb, &audit_info);

	ret_val = netlbl_unlabel_addrinfo_get(info, &addr, &mask, &addr_len);
	if (ret_val != 0)
		return ret_val;

	return netlbl_unlhsh_remove(&init_net, NULL, addr, mask, addr_len);
	return netlbl_unlhsh_remove(&init_net,
				    NULL, addr, mask, addr_len,
				    &audit_info);
}