Commit 63c41688 authored by Paul Moore's avatar Paul Moore

netlabel: Add network address selectors to the NetLabel/LSM domain mapping

This patch extends the NetLabel traffic labeling capabilities to individual
packets based not only on the LSM domain but the by the destination address
as well.  The changes here only affect the core NetLabel infrastructre,
changes to the NetLabel KAPI and individial protocol engines are also
required but are split out into a different patch to ease review.
Signed-off-by: default avatarPaul Moore <paul.moore@hp.com>
Reviewed-by: default avatarJames Morris <jmorris@namei.org>
parent 61e10682
......@@ -9,7 +9,7 @@
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -72,8 +72,9 @@ struct cipso_v4_doi;
/* NetLabel NETLINK protocol version
* 1: initial version
* 2: added static labels for unlabeled connections
* 3: network selectors added to the NetLabel/LSM domain mapping
*/
#define NETLBL_PROTO_VERSION 2
#define NETLBL_PROTO_VERSION 3
/* NetLabel NETLINK types/families */
#define NETLBL_NLTYPE_NONE 0
......@@ -87,6 +88,8 @@ struct cipso_v4_doi;
#define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6"
#define NETLBL_NLTYPE_UNLABELED 5
#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL"
#define NETLBL_NLTYPE_ADDRSELECT 6
#define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL"
/*
* NetLabel - Kernel API for accessing the network packet label mappings.
......
......@@ -39,6 +39,7 @@
#include <linux/ipv6.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <linux/audit.h>
#include "netlabel_addrlist.h"
......@@ -69,6 +70,32 @@ struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
return NULL;
}
/**
* netlbl_af4list_search_exact - Search for an exact IPv4 address entry
* @addr: IPv4 address
* @mask: IPv4 address mask
* @head: the list head
*
* Description:
* Searches the IPv4 address list given by @head. If an exact match if found
* it is returned, otherwise NULL is returned. The caller is responsible for
* calling the rcu_read_[un]lock() functions.
*
*/
struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
__be32 mask,
struct list_head *head)
{
struct netlbl_af4list *iter;
list_for_each_entry_rcu(iter, head, list)
if (iter->valid && iter->addr == addr && iter->mask == mask)
return iter;
return NULL;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
* netlbl_af6list_search - Search for a matching IPv6 address entry
......@@ -93,6 +120,33 @@ struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
return NULL;
}
/**
* netlbl_af6list_search_exact - Search for an exact IPv6 address entry
* @addr: IPv6 address
* @mask: IPv6 address mask
* @head: the list head
*
* Description:
* Searches the IPv6 address list given by @head. If an exact match if found
* it is returned, otherwise NULL is returned. The caller is responsible for
* calling the rcu_read_[un]lock() functions.
*
*/
struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
const struct in6_addr *mask,
struct list_head *head)
{
struct netlbl_af6list *iter;
list_for_each_entry_rcu(iter, head, list)
if (iter->valid &&
ipv6_addr_equal(&iter->addr, addr) &&
ipv6_addr_equal(&iter->mask, mask))
return iter;
return NULL;
}
#endif /* IPv6 */
/**
......@@ -256,3 +310,79 @@ struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
return NULL;
}
#endif /* IPv6 */
/*
* Audit Helper Functions
*/
/**
* netlbl_af4list_audit_addr - Audit an IPv4 address
* @audit_buf: audit buffer
* @src: true if source address, false if destination
* @dev: network interface
* @addr: IP address
* @mask: IP address mask
*
* Description:
* Write the IPv4 address and address mask, if necessary, to @audit_buf.
*
*/
void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
int src, const char *dev,
__be32 addr, __be32 mask)
{
u32 mask_val = ntohl(mask);
char *dir = (src ? "src" : "dst");
if (dev != NULL)
audit_log_format(audit_buf, " netif=%s", dev);
audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr));
if (mask_val != 0xffffffff) {
u32 mask_len = 0;
while (mask_val > 0) {
mask_val <<= 1;
mask_len++;
}
audit_log_format(audit_buf, " %s_prefixlen=%d", dir, mask_len);
}
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
* netlbl_af6list_audit_addr - Audit an IPv6 address
* @audit_buf: audit buffer
* @src: true if source address, false if destination
* @dev: network interface
* @addr: IP address
* @mask: IP address mask
*
* Description:
* Write the IPv6 address and address mask, if necessary, to @audit_buf.
*
*/
void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
int src,
const char *dev,
const struct in6_addr *addr,
const struct in6_addr *mask)
{
char *dir = (src ? "src" : "dst");
if (dev != NULL)
audit_log_format(audit_buf, " netif=%s", dev);
audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, 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, " %s_prefixlen=%d", dir, mask_len);
}
}
#endif /* IPv6 */
......@@ -36,6 +36,7 @@
#include <linux/rcupdate.h>
#include <linux/list.h>
#include <linux/in6.h>
#include <linux/audit.h>
/**
* struct netlbl_af4list - NetLabel IPv4 address list
......@@ -116,6 +117,12 @@ struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
void netlbl_af4list_remove_entry(struct netlbl_af4list *entry);
struct netlbl_af4list *netlbl_af4list_search(__be32 addr,
struct list_head *head);
struct netlbl_af4list *netlbl_af4list_search_exact(__be32 addr,
__be32 mask,
struct list_head *head);
void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
int src, const char *dev,
__be32 addr, __be32 mask);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
......@@ -169,6 +176,14 @@ struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
void netlbl_af6list_remove_entry(struct netlbl_af6list *entry);
struct netlbl_af6list *netlbl_af6list_search(const struct in6_addr *addr,
struct list_head *head);
struct netlbl_af6list *netlbl_af6list_search_exact(const struct in6_addr *addr,
const struct in6_addr *mask,
struct list_head *head);
void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf,
int src,
const char *dev,
const struct in6_addr *addr,
const struct in6_addr *mask);
#endif /* IPV6 */
#endif
This diff is collapsed.
......@@ -11,7 +11,7 @@
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -36,16 +36,43 @@
#include <linux/rcupdate.h>
#include <linux/list.h>
#include "netlabel_addrlist.h"
/* Domain hash table size */
/* XXX - currently this number is an uneducated guess */
#define NETLBL_DOMHSH_BITSIZE 7
/* Domain mapping definition struct */
/* Domain mapping definition structures */
#define netlbl_domhsh_addr4_entry(iter) \
container_of(iter, struct netlbl_domaddr4_map, list)
struct netlbl_domaddr4_map {
u32 type;
union {
struct cipso_v4_doi *cipsov4;
} type_def;
struct netlbl_af4list list;
};
#define netlbl_domhsh_addr6_entry(iter) \
container_of(iter, struct netlbl_domaddr6_map, list)
struct netlbl_domaddr6_map {
u32 type;
/* NOTE: no 'type_def' union needed at present since we don't currently
* support any IPv6 labeling protocols */
struct netlbl_af6list list;
};
struct netlbl_domaddr_map {
struct list_head list4;
struct list_head list6;
};
struct netlbl_dom_map {
char *domain;
u32 type;
union {
struct cipso_v4_doi *cipsov4;
struct netlbl_domaddr_map *addrsel;
} type_def;
u32 valid;
......@@ -66,9 +93,16 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
struct netlbl_domaddr4_map *netlbl_domhsh_getentry_af4(const char *domain,
__be32 addr);
int netlbl_domhsh_walk(u32 *skip_bkt,
u32 *skip_chain,
int (*callback) (struct netlbl_dom_map *entry, void *arg),
void *cb_arg);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct netlbl_domaddr6_map *netlbl_domhsh_getentry_af6(const char *domain,
const struct in6_addr *addr);
#endif /* IPv6 */
#endif
......@@ -419,7 +419,9 @@ int netlbl_enabled(void)
* Attach the correct label to the given socket using the security attributes
* specified in @secattr. This function requires exclusive access to @sk,
* which means it either needs to be in the process of being created or locked.
* Returns zero on success, negative values on failure.
* Returns zero on success, -EDESTADDRREQ if the domain is configured to use
* network address selectors (can't blindly label the socket), and negative
* values on all other failures.
*
*/
int netlbl_sock_setattr(struct sock *sk,
......@@ -433,6 +435,9 @@ int netlbl_sock_setattr(struct sock *sk,
if (dom_entry == NULL)
goto socket_setattr_return;
switch (dom_entry->type) {
case NETLBL_NLTYPE_ADDRSELECT:
ret_val = -EDESTADDRREQ;
break;
case NETLBL_NLTYPE_CIPSOV4:
ret_val = cipso_v4_sock_setattr(sk,
dom_entry->type_def.cipsov4,
......
This diff is collapsed.
......@@ -45,6 +45,16 @@
* NLBL_MGMT_A_DOMAIN
* NLBL_MGMT_A_PROTOCOL
*
* If IPv4 is specified the following attributes are required:
*
* NLBL_MGMT_A_IPV4ADDR
* NLBL_MGMT_A_IPV4MASK
*
* If IPv6 is specified the following attributes are required:
*
* NLBL_MGMT_A_IPV6ADDR
* NLBL_MGMT_A_IPV6MASK
*
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
*
* NLBL_MGMT_A_CV4DOI
......@@ -68,13 +78,24 @@
* Required attributes:
*
* NLBL_MGMT_A_DOMAIN
*
* If the IP address selectors are not used the following attribute is
* required:
*
* NLBL_MGMT_A_PROTOCOL
*
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
* If the IP address selectors are used then the following attritbute is
* required:
*
* NLBL_MGMT_A_SELECTORLIST
*
* If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
* attributes are required:
*
* NLBL_MGMT_A_CV4DOI
*
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
* If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
* attributes are required.
*
* o ADDDEF:
* Sent by an application to set the default domain mapping for the NetLabel
......@@ -100,15 +121,23 @@
* application there is no payload. On success the kernel should send a
* response using the following format.
*
* Required attributes:
* If the IP address selectors are not used the following attribute is
* required:
*
* NLBL_MGMT_A_PROTOCOL
*
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
* If the IP address selectors are used then the following attritbute is
* required:
*
* NLBL_MGMT_A_SELECTORLIST
*
* If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
* attributes are required:
*
* NLBL_MGMT_A_CV4DOI
*
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
* If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
* attributes are required.
*
* o PROTOCOLS:
* Sent by an application to request a list of configured NetLabel protocols
......@@ -162,6 +191,26 @@ enum {
NLBL_MGMT_A_CV4DOI,
/* (NLA_U32)
* the CIPSOv4 DOI value */
NLBL_MGMT_A_IPV6ADDR,
/* (NLA_BINARY, struct in6_addr)
* an IPv6 address */
NLBL_MGMT_A_IPV6MASK,
/* (NLA_BINARY, struct in6_addr)
* an IPv6 address mask */
NLBL_MGMT_A_IPV4ADDR,
/* (NLA_BINARY, struct in_addr)
* an IPv4 address */
NLBL_MGMT_A_IPV4MASK,
/* (NLA_BINARY, struct in_addr)
* and IPv4 address mask */
NLBL_MGMT_A_ADDRSELECTOR,
/* (NLA_NESTED)
* an IP address selector, must contain an address, mask, and protocol
* attribute plus any protocol specific attributes */
NLBL_MGMT_A_SELECTORLIST,
/* (NLA_NESTED)
* the selector list, there must be at least one
* NLBL_MGMT_A_ADDRSELECTOR attribute */
__NLBL_MGMT_A_MAX,
};
#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
......
......@@ -145,76 +145,6 @@ 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);
}
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
* 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);
}
}
#endif /* IPv6 */
/*
* Unlabeled Connection Hash Table Functions
*/
......@@ -571,10 +501,10 @@ static int netlbl_unlhsh_add(struct net *net,
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);
netlbl_af4list_audit_addr(audit_buf, 1,
dev_name,
addr4->s_addr,
mask4->s_addr);
break;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
......@@ -585,9 +515,9 @@ static int netlbl_unlhsh_add(struct net *net,
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);
netlbl_af6list_audit_addr(audit_buf, 1,
dev_name,
addr6, mask6);
break;
}
#endif /* IPv6 */
......@@ -652,9 +582,9 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
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),
addr->s_addr, mask->s_addr);
netlbl_af4list_audit_addr(audit_buf, 1,
(dev != NULL ? dev->name : NULL),
addr->s_addr, mask->s_addr);
if (dev != NULL)
dev_put(dev);
if (entry && security_secid_to_secctx(entry->secid,
......@@ -712,9 +642,9 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
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);
netlbl_af6list_audit_addr(audit_buf, 1,
(dev != NULL ? dev->name : NULL),
addr, mask);
if (dev != NULL)
dev_put(dev);
if (entry && security_secid_to_secctx(entry->secid,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment