[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
*/
* @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
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))
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:
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.
* 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);
}
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;
#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.
* 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);
}
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;
* @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.
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;
}
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:
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
!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 ret_val;
return netlbl_unlhsh_add(&init_net,
- dev_name, addr, mask, addr_len, secid);
+ dev_name, addr, mask, addr_len, secid,
+ &audit_info);
}
/**
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
!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;
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);
}
/**
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. */
!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);
}
/**
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. */
!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);
}