[RFC PATCH v8 17/18] NetLabel: Add auditing to the static labeling mechanism

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

 include/linux/audit.h             |    2 
 net/netlabel/netlabel_unlabeled.c |  207 ++++++++++++++++++++++++++++++++++---
 2 files changed, 195 insertions(+), 14 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index c687816..bdd6f5d 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -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
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index d289ff4..cdeb6d9 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -148,6 +148,74 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1
 };
 
 /*
+ * 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
  */
 
@@ -524,6 +592,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
@@ -535,12 +604,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))
@@ -567,13 +642,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:
@@ -584,14 +674,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.
@@ -599,12 +701,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);
@@ -616,6 +724,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;
@@ -624,9 +751,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.
@@ -634,12 +763,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);
@@ -652,6 +787,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;
@@ -702,6 +856,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.
@@ -712,7 +867,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;
@@ -739,11 +895,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:
@@ -969,6 +1129,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
@@ -982,6 +1143,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;
@@ -994,7 +1157,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);
 }
 
 /**
@@ -1016,6 +1180,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
@@ -1028,6 +1193,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;
@@ -1038,7 +1205,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);
 }
 
 /**
@@ -1060,6 +1229,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. */
@@ -1070,12 +1240,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);
 }
 
 /**
@@ -1096,6 +1270,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. */
@@ -1105,11 +1280,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);
 }
 
 


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to majordomo@xxxxxxxxxxxxx with
the words "unsubscribe selinux" without quotes as the message.

[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux