mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-08 01:08:03 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
17
net/netlabel/Kconfig
Normal file
17
net/netlabel/Kconfig
Normal file
|
@ -0,0 +1,17 @@
|
|||
#
|
||||
# NetLabel configuration
|
||||
#
|
||||
|
||||
config NETLABEL
|
||||
bool "NetLabel subsystem support"
|
||||
depends on SECURITY
|
||||
default n
|
||||
---help---
|
||||
NetLabel provides support for explicit network packet labeling
|
||||
protocols such as CIPSO and RIPSO. For more information see
|
||||
Documentation/netlabel as well as the NetLabel SourceForge project
|
||||
for configuration tools and additional documentation.
|
||||
|
||||
* http://netlabel.sf.net
|
||||
|
||||
If you are unsure, say N.
|
15
net/netlabel/Makefile
Normal file
15
net/netlabel/Makefile
Normal file
|
@ -0,0 +1,15 @@
|
|||
#
|
||||
# Makefile for the NetLabel subsystem.
|
||||
#
|
||||
|
||||
# base objects
|
||||
obj-y := netlabel_user.o netlabel_kapi.o
|
||||
obj-y += netlabel_domainhash.o netlabel_addrlist.o
|
||||
|
||||
# management objects
|
||||
obj-y += netlabel_mgmt.o
|
||||
|
||||
# protocol modules
|
||||
obj-y += netlabel_unlabeled.o
|
||||
obj-y += netlabel_cipso_v4.o
|
||||
|
383
net/netlabel/netlabel_addrlist.c
Normal file
383
net/netlabel/netlabel_addrlist.c
Normal file
|
@ -0,0 +1,383 @@
|
|||
/*
|
||||
* NetLabel Network Address Lists
|
||||
*
|
||||
* This file contains network address list functions used to manage ordered
|
||||
* lists of network addresses for use by the NetLabel subsystem. The NetLabel
|
||||
* system manages static and dynamic label mappings for network protocols such
|
||||
* as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (c) Copyright Hewlett-Packard Development Company, L.P., 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/ipv6.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
#include "netlabel_addrlist.h"
|
||||
|
||||
/*
|
||||
* Address List Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_af4list_search - Search for a matching IPv4 address entry
|
||||
* @addr: IPv4 address
|
||||
* @head: the list head
|
||||
*
|
||||
* Description:
|
||||
* Searches the IPv4 address list given by @head. If a matching address entry
|
||||
* is 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(__be32 addr,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct netlbl_af4list *iter;
|
||||
|
||||
list_for_each_entry_rcu(iter, head, list)
|
||||
if (iter->valid && (addr & iter->mask) == iter->addr)
|
||||
return iter;
|
||||
|
||||
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 IS_ENABLED(CONFIG_IPV6)
|
||||
/**
|
||||
* netlbl_af6list_search - Search for a matching IPv6 address entry
|
||||
* @addr: IPv6 address
|
||||
* @head: the list head
|
||||
*
|
||||
* Description:
|
||||
* Searches the IPv6 address list given by @head. If a matching address entry
|
||||
* is 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(const struct in6_addr *addr,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct netlbl_af6list *iter;
|
||||
|
||||
list_for_each_entry_rcu(iter, head, list)
|
||||
if (iter->valid &&
|
||||
ipv6_masked_addr_cmp(&iter->addr, &iter->mask, addr) == 0)
|
||||
return iter;
|
||||
|
||||
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 */
|
||||
|
||||
/**
|
||||
* netlbl_af4list_add - Add a new IPv4 address entry to a list
|
||||
* @entry: address entry
|
||||
* @head: the list head
|
||||
*
|
||||
* Description:
|
||||
* Add a new address entry to the list pointed to by @head. On success zero is
|
||||
* returned, otherwise a negative value is returned. The caller is responsible
|
||||
* for calling the necessary locking functions.
|
||||
*
|
||||
*/
|
||||
int netlbl_af4list_add(struct netlbl_af4list *entry, struct list_head *head)
|
||||
{
|
||||
struct netlbl_af4list *iter;
|
||||
|
||||
iter = netlbl_af4list_search(entry->addr, head);
|
||||
if (iter != NULL &&
|
||||
iter->addr == entry->addr && iter->mask == entry->mask)
|
||||
return -EEXIST;
|
||||
|
||||
/* in order to speed up address searches through the list (the common
|
||||
* case) we need to keep the list in order based on the size of the
|
||||
* address mask such that the entry with the widest mask (smallest
|
||||
* numerical value) appears first in the list */
|
||||
list_for_each_entry_rcu(iter, head, list)
|
||||
if (iter->valid &&
|
||||
ntohl(entry->mask) > ntohl(iter->mask)) {
|
||||
__list_add_rcu(&entry->list,
|
||||
iter->list.prev,
|
||||
&iter->list);
|
||||
return 0;
|
||||
}
|
||||
list_add_tail_rcu(&entry->list, head);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
/**
|
||||
* netlbl_af6list_add - Add a new IPv6 address entry to a list
|
||||
* @entry: address entry
|
||||
* @head: the list head
|
||||
*
|
||||
* Description:
|
||||
* Add a new address entry to the list pointed to by @head. On success zero is
|
||||
* returned, otherwise a negative value is returned. The caller is responsible
|
||||
* for calling the necessary locking functions.
|
||||
*
|
||||
*/
|
||||
int netlbl_af6list_add(struct netlbl_af6list *entry, struct list_head *head)
|
||||
{
|
||||
struct netlbl_af6list *iter;
|
||||
|
||||
iter = netlbl_af6list_search(&entry->addr, head);
|
||||
if (iter != NULL &&
|
||||
ipv6_addr_equal(&iter->addr, &entry->addr) &&
|
||||
ipv6_addr_equal(&iter->mask, &entry->mask))
|
||||
return -EEXIST;
|
||||
|
||||
/* in order to speed up address searches through the list (the common
|
||||
* case) we need to keep the list in order based on the size of the
|
||||
* address mask such that the entry with the widest mask (smallest
|
||||
* numerical value) appears first in the list */
|
||||
list_for_each_entry_rcu(iter, head, list)
|
||||
if (iter->valid &&
|
||||
ipv6_addr_cmp(&entry->mask, &iter->mask) > 0) {
|
||||
__list_add_rcu(&entry->list,
|
||||
iter->list.prev,
|
||||
&iter->list);
|
||||
return 0;
|
||||
}
|
||||
list_add_tail_rcu(&entry->list, head);
|
||||
return 0;
|
||||
}
|
||||
#endif /* IPv6 */
|
||||
|
||||
/**
|
||||
* netlbl_af4list_remove_entry - Remove an IPv4 address entry
|
||||
* @entry: address entry
|
||||
*
|
||||
* Description:
|
||||
* Remove the specified IP address entry. The caller is responsible for
|
||||
* calling the necessary locking functions.
|
||||
*
|
||||
*/
|
||||
void netlbl_af4list_remove_entry(struct netlbl_af4list *entry)
|
||||
{
|
||||
entry->valid = 0;
|
||||
list_del_rcu(&entry->list);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_af4list_remove - Remove an IPv4 address entry
|
||||
* @addr: IP address
|
||||
* @mask: IP address mask
|
||||
* @head: the list head
|
||||
*
|
||||
* Description:
|
||||
* Remove an IP address entry from the list pointed to by @head. Returns the
|
||||
* entry on success, NULL on failure. The caller is responsible for calling
|
||||
* the necessary locking functions.
|
||||
*
|
||||
*/
|
||||
struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct netlbl_af4list *entry;
|
||||
|
||||
entry = netlbl_af4list_search_exact(addr, mask, head);
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
netlbl_af4list_remove_entry(entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
/**
|
||||
* netlbl_af6list_remove_entry - Remove an IPv6 address entry
|
||||
* @entry: address entry
|
||||
*
|
||||
* Description:
|
||||
* Remove the specified IP address entry. The caller is responsible for
|
||||
* calling the necessary locking functions.
|
||||
*
|
||||
*/
|
||||
void netlbl_af6list_remove_entry(struct netlbl_af6list *entry)
|
||||
{
|
||||
entry->valid = 0;
|
||||
list_del_rcu(&entry->list);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_af6list_remove - Remove an IPv6 address entry
|
||||
* @addr: IP address
|
||||
* @mask: IP address mask
|
||||
* @head: the list head
|
||||
*
|
||||
* Description:
|
||||
* Remove an IP address entry from the list pointed to by @head. Returns the
|
||||
* entry on success, NULL on failure. The caller is responsible for calling
|
||||
* the necessary locking functions.
|
||||
*
|
||||
*/
|
||||
struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
|
||||
const struct in6_addr *mask,
|
||||
struct list_head *head)
|
||||
{
|
||||
struct netlbl_af6list *entry;
|
||||
|
||||
entry = netlbl_af6list_search_exact(addr, mask, head);
|
||||
if (entry == NULL)
|
||||
return NULL;
|
||||
netlbl_af6list_remove_entry(entry);
|
||||
return entry;
|
||||
}
|
||||
#endif /* IPv6 */
|
||||
|
||||
/*
|
||||
* Audit Helper Functions
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_AUDIT
|
||||
/**
|
||||
* 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=%pI4", dir, &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 IS_ENABLED(CONFIG_IPV6)
|
||||
/**
|
||||
* 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=%pI6", dir, 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 */
|
||||
#endif /* CONFIG_AUDIT */
|
208
net/netlabel/netlabel_addrlist.h
Normal file
208
net/netlabel/netlabel_addrlist.h
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* NetLabel Network Address Lists
|
||||
*
|
||||
* This file contains network address list functions used to manage ordered
|
||||
* lists of network addresses for use by the NetLabel subsystem. The NetLabel
|
||||
* system manages static and dynamic label mappings for network protocols such
|
||||
* as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (c) Copyright Hewlett-Packard Development Company, L.P., 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETLABEL_ADDRLIST_H
|
||||
#define _NETLABEL_ADDRLIST_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
/**
|
||||
* struct netlbl_af4list - NetLabel IPv4 address list
|
||||
* @addr: IPv4 address
|
||||
* @mask: IPv4 address mask
|
||||
* @valid: valid flag
|
||||
* @list: list structure, used internally
|
||||
*/
|
||||
struct netlbl_af4list {
|
||||
__be32 addr;
|
||||
__be32 mask;
|
||||
|
||||
u32 valid;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct netlbl_af6list - NetLabel IPv6 address list
|
||||
* @addr: IPv6 address
|
||||
* @mask: IPv6 address mask
|
||||
* @valid: valid flag
|
||||
* @list: list structure, used internally
|
||||
*/
|
||||
struct netlbl_af6list {
|
||||
struct in6_addr addr;
|
||||
struct in6_addr mask;
|
||||
|
||||
u32 valid;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define __af4list_entry(ptr) container_of(ptr, struct netlbl_af4list, list)
|
||||
|
||||
static inline struct netlbl_af4list *__af4list_valid(struct list_head *s,
|
||||
struct list_head *h)
|
||||
{
|
||||
struct list_head *i = s;
|
||||
struct netlbl_af4list *n = __af4list_entry(s);
|
||||
while (i != h && !n->valid) {
|
||||
i = i->next;
|
||||
n = __af4list_entry(i);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline struct netlbl_af4list *__af4list_valid_rcu(struct list_head *s,
|
||||
struct list_head *h)
|
||||
{
|
||||
struct list_head *i = s;
|
||||
struct netlbl_af4list *n = __af4list_entry(s);
|
||||
while (i != h && !n->valid) {
|
||||
i = rcu_dereference(i->next);
|
||||
n = __af4list_entry(i);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#define netlbl_af4list_foreach(iter, head) \
|
||||
for (iter = __af4list_valid((head)->next, head); \
|
||||
&iter->list != (head); \
|
||||
iter = __af4list_valid(iter->list.next, head))
|
||||
|
||||
#define netlbl_af4list_foreach_rcu(iter, head) \
|
||||
for (iter = __af4list_valid_rcu((head)->next, head); \
|
||||
&iter->list != (head); \
|
||||
iter = __af4list_valid_rcu(iter->list.next, head))
|
||||
|
||||
#define netlbl_af4list_foreach_safe(iter, tmp, head) \
|
||||
for (iter = __af4list_valid((head)->next, head), \
|
||||
tmp = __af4list_valid(iter->list.next, head); \
|
||||
&iter->list != (head); \
|
||||
iter = tmp, tmp = __af4list_valid(iter->list.next, head))
|
||||
|
||||
int netlbl_af4list_add(struct netlbl_af4list *entry,
|
||||
struct list_head *head);
|
||||
struct netlbl_af4list *netlbl_af4list_remove(__be32 addr, __be32 mask,
|
||||
struct list_head *head);
|
||||
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);
|
||||
|
||||
#ifdef CONFIG_AUDIT
|
||||
void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
|
||||
int src, const char *dev,
|
||||
__be32 addr, __be32 mask);
|
||||
#else
|
||||
static inline void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf,
|
||||
int src, const char *dev,
|
||||
__be32 addr, __be32 mask)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
|
||||
#define __af6list_entry(ptr) container_of(ptr, struct netlbl_af6list, list)
|
||||
|
||||
static inline struct netlbl_af6list *__af6list_valid(struct list_head *s,
|
||||
struct list_head *h)
|
||||
{
|
||||
struct list_head *i = s;
|
||||
struct netlbl_af6list *n = __af6list_entry(s);
|
||||
while (i != h && !n->valid) {
|
||||
i = i->next;
|
||||
n = __af6list_entry(i);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static inline struct netlbl_af6list *__af6list_valid_rcu(struct list_head *s,
|
||||
struct list_head *h)
|
||||
{
|
||||
struct list_head *i = s;
|
||||
struct netlbl_af6list *n = __af6list_entry(s);
|
||||
while (i != h && !n->valid) {
|
||||
i = rcu_dereference(i->next);
|
||||
n = __af6list_entry(i);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#define netlbl_af6list_foreach(iter, head) \
|
||||
for (iter = __af6list_valid((head)->next, head); \
|
||||
&iter->list != (head); \
|
||||
iter = __af6list_valid(iter->list.next, head))
|
||||
|
||||
#define netlbl_af6list_foreach_rcu(iter, head) \
|
||||
for (iter = __af6list_valid_rcu((head)->next, head); \
|
||||
&iter->list != (head); \
|
||||
iter = __af6list_valid_rcu(iter->list.next, head))
|
||||
|
||||
#define netlbl_af6list_foreach_safe(iter, tmp, head) \
|
||||
for (iter = __af6list_valid((head)->next, head), \
|
||||
tmp = __af6list_valid(iter->list.next, head); \
|
||||
&iter->list != (head); \
|
||||
iter = tmp, tmp = __af6list_valid(iter->list.next, head))
|
||||
|
||||
int netlbl_af6list_add(struct netlbl_af6list *entry,
|
||||
struct list_head *head);
|
||||
struct netlbl_af6list *netlbl_af6list_remove(const struct in6_addr *addr,
|
||||
const struct in6_addr *mask,
|
||||
struct list_head *head);
|
||||
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);
|
||||
|
||||
#ifdef CONFIG_AUDIT
|
||||
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);
|
||||
#else
|
||||
static inline 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
|
||||
#endif /* IPV6 */
|
||||
|
||||
#endif
|
786
net/netlabel/netlabel_cipso_v4.c
Normal file
786
net/netlabel/netlabel_cipso_v4.c
Normal file
|
@ -0,0 +1,786 @@
|
|||
/*
|
||||
* NetLabel CIPSO/IPv4 Support
|
||||
*
|
||||
* This file defines the CIPSO/IPv4 functions for the NetLabel system. The
|
||||
* NetLabel system manages static and dynamic label mappings for network
|
||||
* protocols such as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/audit.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include "netlabel_user.h"
|
||||
#include "netlabel_cipso_v4.h"
|
||||
#include "netlabel_mgmt.h"
|
||||
#include "netlabel_domainhash.h"
|
||||
|
||||
/* Argument struct for cipso_v4_doi_walk() */
|
||||
struct netlbl_cipsov4_doiwalk_arg {
|
||||
struct netlink_callback *nl_cb;
|
||||
struct sk_buff *skb;
|
||||
u32 seq;
|
||||
};
|
||||
|
||||
/* Argument struct for netlbl_domhsh_walk() */
|
||||
struct netlbl_domhsh_walk_arg {
|
||||
struct netlbl_audit *audit_info;
|
||||
u32 doi;
|
||||
};
|
||||
|
||||
/* NetLabel Generic NETLINK CIPSOv4 family */
|
||||
static struct genl_family netlbl_cipsov4_gnl_family = {
|
||||
.id = GENL_ID_GENERATE,
|
||||
.hdrsize = 0,
|
||||
.name = NETLBL_NLTYPE_CIPSOV4_NAME,
|
||||
.version = NETLBL_PROTO_VERSION,
|
||||
.maxattr = NLBL_CIPSOV4_A_MAX,
|
||||
};
|
||||
|
||||
/* NetLabel Netlink attribute policy */
|
||||
static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1] = {
|
||||
[NLBL_CIPSOV4_A_DOI] = { .type = NLA_U32 },
|
||||
[NLBL_CIPSOV4_A_MTYPE] = { .type = NLA_U32 },
|
||||
[NLBL_CIPSOV4_A_TAG] = { .type = NLA_U8 },
|
||||
[NLBL_CIPSOV4_A_TAGLST] = { .type = NLA_NESTED },
|
||||
[NLBL_CIPSOV4_A_MLSLVLLOC] = { .type = NLA_U32 },
|
||||
[NLBL_CIPSOV4_A_MLSLVLREM] = { .type = NLA_U32 },
|
||||
[NLBL_CIPSOV4_A_MLSLVL] = { .type = NLA_NESTED },
|
||||
[NLBL_CIPSOV4_A_MLSLVLLST] = { .type = NLA_NESTED },
|
||||
[NLBL_CIPSOV4_A_MLSCATLOC] = { .type = NLA_U32 },
|
||||
[NLBL_CIPSOV4_A_MLSCATREM] = { .type = NLA_U32 },
|
||||
[NLBL_CIPSOV4_A_MLSCAT] = { .type = NLA_NESTED },
|
||||
[NLBL_CIPSOV4_A_MLSCATLST] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_add_common - Parse the common sections of a ADD message
|
||||
* @info: the Generic NETLINK info block
|
||||
* @doi_def: the CIPSO V4 DOI definition
|
||||
*
|
||||
* Description:
|
||||
* Parse the common sections of a ADD message and fill in the related values
|
||||
* in @doi_def. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_add_common(struct genl_info *info,
|
||||
struct cipso_v4_doi *doi_def)
|
||||
{
|
||||
struct nlattr *nla;
|
||||
int nla_rem;
|
||||
u32 iter = 0;
|
||||
|
||||
doi_def->doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
|
||||
|
||||
if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_TAGLST],
|
||||
NLBL_CIPSOV4_A_MAX,
|
||||
netlbl_cipsov4_genl_policy) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
nla_for_each_nested(nla, info->attrs[NLBL_CIPSOV4_A_TAGLST], nla_rem)
|
||||
if (nla_type(nla) == NLBL_CIPSOV4_A_TAG) {
|
||||
if (iter >= CIPSO_V4_TAG_MAXCNT)
|
||||
return -EINVAL;
|
||||
doi_def->tags[iter++] = nla_get_u8(nla);
|
||||
}
|
||||
while (iter < CIPSO_V4_TAG_MAXCNT)
|
||||
doi_def->tags[iter++] = CIPSO_V4_TAG_INVALID;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NetLabel Command Handlers
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
|
||||
* @info: the Generic NETLINK info block
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Create a new CIPSO_V4_MAP_TRANS DOI definition based on the given ADD
|
||||
* message and add it to the CIPSO V4 engine. Return zero on success and
|
||||
* non-zero on error.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_add_std(struct genl_info *info,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
struct cipso_v4_doi *doi_def = NULL;
|
||||
struct nlattr *nla_a;
|
||||
struct nlattr *nla_b;
|
||||
int nla_a_rem;
|
||||
int nla_b_rem;
|
||||
u32 iter;
|
||||
|
||||
if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
|
||||
!info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
|
||||
return -EINVAL;
|
||||
|
||||
if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
|
||||
NLBL_CIPSOV4_A_MAX,
|
||||
netlbl_cipsov4_genl_policy) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
|
||||
if (doi_def == NULL)
|
||||
return -ENOMEM;
|
||||
doi_def->map.std = kzalloc(sizeof(*doi_def->map.std), GFP_KERNEL);
|
||||
if (doi_def->map.std == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_std_failure;
|
||||
}
|
||||
doi_def->type = CIPSO_V4_MAP_TRANS;
|
||||
|
||||
ret_val = netlbl_cipsov4_add_common(info, doi_def);
|
||||
if (ret_val != 0)
|
||||
goto add_std_failure;
|
||||
ret_val = -EINVAL;
|
||||
|
||||
nla_for_each_nested(nla_a,
|
||||
info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
|
||||
nla_a_rem)
|
||||
if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
|
||||
if (nla_validate_nested(nla_a,
|
||||
NLBL_CIPSOV4_A_MAX,
|
||||
netlbl_cipsov4_genl_policy) != 0)
|
||||
goto add_std_failure;
|
||||
nla_for_each_nested(nla_b, nla_a, nla_b_rem)
|
||||
switch (nla_type(nla_b)) {
|
||||
case NLBL_CIPSOV4_A_MLSLVLLOC:
|
||||
if (nla_get_u32(nla_b) >
|
||||
CIPSO_V4_MAX_LOC_LVLS)
|
||||
goto add_std_failure;
|
||||
if (nla_get_u32(nla_b) >=
|
||||
doi_def->map.std->lvl.local_size)
|
||||
doi_def->map.std->lvl.local_size =
|
||||
nla_get_u32(nla_b) + 1;
|
||||
break;
|
||||
case NLBL_CIPSOV4_A_MLSLVLREM:
|
||||
if (nla_get_u32(nla_b) >
|
||||
CIPSO_V4_MAX_REM_LVLS)
|
||||
goto add_std_failure;
|
||||
if (nla_get_u32(nla_b) >=
|
||||
doi_def->map.std->lvl.cipso_size)
|
||||
doi_def->map.std->lvl.cipso_size =
|
||||
nla_get_u32(nla_b) + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
|
||||
sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (doi_def->map.std->lvl.local == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_std_failure;
|
||||
}
|
||||
doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
|
||||
sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (doi_def->map.std->lvl.cipso == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_std_failure;
|
||||
}
|
||||
for (iter = 0; iter < doi_def->map.std->lvl.local_size; iter++)
|
||||
doi_def->map.std->lvl.local[iter] = CIPSO_V4_INV_LVL;
|
||||
for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
|
||||
doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
|
||||
nla_for_each_nested(nla_a,
|
||||
info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
|
||||
nla_a_rem)
|
||||
if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSLVL) {
|
||||
struct nlattr *lvl_loc;
|
||||
struct nlattr *lvl_rem;
|
||||
|
||||
lvl_loc = nla_find_nested(nla_a,
|
||||
NLBL_CIPSOV4_A_MLSLVLLOC);
|
||||
lvl_rem = nla_find_nested(nla_a,
|
||||
NLBL_CIPSOV4_A_MLSLVLREM);
|
||||
if (lvl_loc == NULL || lvl_rem == NULL)
|
||||
goto add_std_failure;
|
||||
doi_def->map.std->lvl.local[nla_get_u32(lvl_loc)] =
|
||||
nla_get_u32(lvl_rem);
|
||||
doi_def->map.std->lvl.cipso[nla_get_u32(lvl_rem)] =
|
||||
nla_get_u32(lvl_loc);
|
||||
}
|
||||
|
||||
if (info->attrs[NLBL_CIPSOV4_A_MLSCATLST]) {
|
||||
if (nla_validate_nested(info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
|
||||
NLBL_CIPSOV4_A_MAX,
|
||||
netlbl_cipsov4_genl_policy) != 0)
|
||||
goto add_std_failure;
|
||||
|
||||
nla_for_each_nested(nla_a,
|
||||
info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
|
||||
nla_a_rem)
|
||||
if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
|
||||
if (nla_validate_nested(nla_a,
|
||||
NLBL_CIPSOV4_A_MAX,
|
||||
netlbl_cipsov4_genl_policy) != 0)
|
||||
goto add_std_failure;
|
||||
nla_for_each_nested(nla_b, nla_a, nla_b_rem)
|
||||
switch (nla_type(nla_b)) {
|
||||
case NLBL_CIPSOV4_A_MLSCATLOC:
|
||||
if (nla_get_u32(nla_b) >
|
||||
CIPSO_V4_MAX_LOC_CATS)
|
||||
goto add_std_failure;
|
||||
if (nla_get_u32(nla_b) >=
|
||||
doi_def->map.std->cat.local_size)
|
||||
doi_def->map.std->cat.local_size =
|
||||
nla_get_u32(nla_b) + 1;
|
||||
break;
|
||||
case NLBL_CIPSOV4_A_MLSCATREM:
|
||||
if (nla_get_u32(nla_b) >
|
||||
CIPSO_V4_MAX_REM_CATS)
|
||||
goto add_std_failure;
|
||||
if (nla_get_u32(nla_b) >=
|
||||
doi_def->map.std->cat.cipso_size)
|
||||
doi_def->map.std->cat.cipso_size =
|
||||
nla_get_u32(nla_b) + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
doi_def->map.std->cat.local = kcalloc(
|
||||
doi_def->map.std->cat.local_size,
|
||||
sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (doi_def->map.std->cat.local == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_std_failure;
|
||||
}
|
||||
doi_def->map.std->cat.cipso = kcalloc(
|
||||
doi_def->map.std->cat.cipso_size,
|
||||
sizeof(u32),
|
||||
GFP_KERNEL);
|
||||
if (doi_def->map.std->cat.cipso == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_std_failure;
|
||||
}
|
||||
for (iter = 0; iter < doi_def->map.std->cat.local_size; iter++)
|
||||
doi_def->map.std->cat.local[iter] = CIPSO_V4_INV_CAT;
|
||||
for (iter = 0; iter < doi_def->map.std->cat.cipso_size; iter++)
|
||||
doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
|
||||
nla_for_each_nested(nla_a,
|
||||
info->attrs[NLBL_CIPSOV4_A_MLSCATLST],
|
||||
nla_a_rem)
|
||||
if (nla_type(nla_a) == NLBL_CIPSOV4_A_MLSCAT) {
|
||||
struct nlattr *cat_loc;
|
||||
struct nlattr *cat_rem;
|
||||
|
||||
cat_loc = nla_find_nested(nla_a,
|
||||
NLBL_CIPSOV4_A_MLSCATLOC);
|
||||
cat_rem = nla_find_nested(nla_a,
|
||||
NLBL_CIPSOV4_A_MLSCATREM);
|
||||
if (cat_loc == NULL || cat_rem == NULL)
|
||||
goto add_std_failure;
|
||||
doi_def->map.std->cat.local[
|
||||
nla_get_u32(cat_loc)] =
|
||||
nla_get_u32(cat_rem);
|
||||
doi_def->map.std->cat.cipso[
|
||||
nla_get_u32(cat_rem)] =
|
||||
nla_get_u32(cat_loc);
|
||||
}
|
||||
}
|
||||
|
||||
ret_val = cipso_v4_doi_add(doi_def, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto add_std_failure;
|
||||
return 0;
|
||||
|
||||
add_std_failure:
|
||||
if (doi_def)
|
||||
cipso_v4_doi_free(doi_def);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
|
||||
* @info: the Generic NETLINK info block
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
|
||||
* and add it to the CIPSO V4 engine. Return zero on success and non-zero on
|
||||
* error.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_add_pass(struct genl_info *info,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val;
|
||||
struct cipso_v4_doi *doi_def = NULL;
|
||||
|
||||
if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
|
||||
return -EINVAL;
|
||||
|
||||
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
|
||||
if (doi_def == NULL)
|
||||
return -ENOMEM;
|
||||
doi_def->type = CIPSO_V4_MAP_PASS;
|
||||
|
||||
ret_val = netlbl_cipsov4_add_common(info, doi_def);
|
||||
if (ret_val != 0)
|
||||
goto add_pass_failure;
|
||||
|
||||
ret_val = cipso_v4_doi_add(doi_def, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto add_pass_failure;
|
||||
return 0;
|
||||
|
||||
add_pass_failure:
|
||||
cipso_v4_doi_free(doi_def);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
|
||||
* @info: the Generic NETLINK info block
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
|
||||
* message and add it to the CIPSO V4 engine. Return zero on success and
|
||||
* non-zero on error.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_add_local(struct genl_info *info,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val;
|
||||
struct cipso_v4_doi *doi_def = NULL;
|
||||
|
||||
if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
|
||||
return -EINVAL;
|
||||
|
||||
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
|
||||
if (doi_def == NULL)
|
||||
return -ENOMEM;
|
||||
doi_def->type = CIPSO_V4_MAP_LOCAL;
|
||||
|
||||
ret_val = netlbl_cipsov4_add_common(info, doi_def);
|
||||
if (ret_val != 0)
|
||||
goto add_local_failure;
|
||||
|
||||
ret_val = cipso_v4_doi_add(doi_def, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto add_local_failure;
|
||||
return 0;
|
||||
|
||||
add_local_failure:
|
||||
cipso_v4_doi_free(doi_def);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_add - Handle an ADD message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Create a new DOI definition based on the given ADD message and add it to the
|
||||
* CIPSO V4 engine. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
|
||||
!info->attrs[NLBL_CIPSOV4_A_MTYPE])
|
||||
return -EINVAL;
|
||||
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
switch (nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE])) {
|
||||
case CIPSO_V4_MAP_TRANS:
|
||||
ret_val = netlbl_cipsov4_add_std(info, &audit_info);
|
||||
break;
|
||||
case CIPSO_V4_MAP_PASS:
|
||||
ret_val = netlbl_cipsov4_add_pass(info, &audit_info);
|
||||
break;
|
||||
case CIPSO_V4_MAP_LOCAL:
|
||||
ret_val = netlbl_cipsov4_add_local(info, &audit_info);
|
||||
break;
|
||||
}
|
||||
if (ret_val == 0)
|
||||
atomic_inc(&netlabel_mgmt_protocount);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_list - Handle a LIST message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated LIST message and respond accordingly. While the
|
||||
* response message generated by the kernel is straightforward, determining
|
||||
* before hand the size of the buffer to allocate is not (we have to generate
|
||||
* the message to know the size). In order to keep this function sane what we
|
||||
* do is allocate a buffer of NLMSG_GOODSIZE and try to fit the response in
|
||||
* that size, if we fail then we restart with a larger buffer and try again.
|
||||
* We continue in this manner until we hit a limit of failed attempts then we
|
||||
* give up and just send an error message. Returns zero on success and
|
||||
* negative values on error.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int ret_val;
|
||||
struct sk_buff *ans_skb = NULL;
|
||||
u32 nlsze_mult = 1;
|
||||
void *data;
|
||||
u32 doi;
|
||||
struct nlattr *nla_a;
|
||||
struct nlattr *nla_b;
|
||||
struct cipso_v4_doi *doi_def;
|
||||
u32 iter;
|
||||
|
||||
if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
|
||||
ret_val = -EINVAL;
|
||||
goto list_failure;
|
||||
}
|
||||
|
||||
list_start:
|
||||
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE * nlsze_mult, GFP_KERNEL);
|
||||
if (ans_skb == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto list_failure;
|
||||
}
|
||||
data = genlmsg_put_reply(ans_skb, info, &netlbl_cipsov4_gnl_family,
|
||||
0, NLBL_CIPSOV4_C_LIST);
|
||||
if (data == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto list_failure;
|
||||
}
|
||||
|
||||
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
|
||||
|
||||
rcu_read_lock();
|
||||
doi_def = cipso_v4_doi_getdef(doi);
|
||||
if (doi_def == NULL) {
|
||||
ret_val = -EINVAL;
|
||||
goto list_failure_lock;
|
||||
}
|
||||
|
||||
ret_val = nla_put_u32(ans_skb, NLBL_CIPSOV4_A_MTYPE, doi_def->type);
|
||||
if (ret_val != 0)
|
||||
goto list_failure_lock;
|
||||
|
||||
nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_TAGLST);
|
||||
if (nla_a == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto list_failure_lock;
|
||||
}
|
||||
for (iter = 0;
|
||||
iter < CIPSO_V4_TAG_MAXCNT &&
|
||||
doi_def->tags[iter] != CIPSO_V4_TAG_INVALID;
|
||||
iter++) {
|
||||
ret_val = nla_put_u8(ans_skb,
|
||||
NLBL_CIPSOV4_A_TAG,
|
||||
doi_def->tags[iter]);
|
||||
if (ret_val != 0)
|
||||
goto list_failure_lock;
|
||||
}
|
||||
nla_nest_end(ans_skb, nla_a);
|
||||
|
||||
switch (doi_def->type) {
|
||||
case CIPSO_V4_MAP_TRANS:
|
||||
nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVLLST);
|
||||
if (nla_a == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto list_failure_lock;
|
||||
}
|
||||
for (iter = 0;
|
||||
iter < doi_def->map.std->lvl.local_size;
|
||||
iter++) {
|
||||
if (doi_def->map.std->lvl.local[iter] ==
|
||||
CIPSO_V4_INV_LVL)
|
||||
continue;
|
||||
|
||||
nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSLVL);
|
||||
if (nla_b == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto list_retry;
|
||||
}
|
||||
ret_val = nla_put_u32(ans_skb,
|
||||
NLBL_CIPSOV4_A_MLSLVLLOC,
|
||||
iter);
|
||||
if (ret_val != 0)
|
||||
goto list_retry;
|
||||
ret_val = nla_put_u32(ans_skb,
|
||||
NLBL_CIPSOV4_A_MLSLVLREM,
|
||||
doi_def->map.std->lvl.local[iter]);
|
||||
if (ret_val != 0)
|
||||
goto list_retry;
|
||||
nla_nest_end(ans_skb, nla_b);
|
||||
}
|
||||
nla_nest_end(ans_skb, nla_a);
|
||||
|
||||
nla_a = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCATLST);
|
||||
if (nla_a == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto list_retry;
|
||||
}
|
||||
for (iter = 0;
|
||||
iter < doi_def->map.std->cat.local_size;
|
||||
iter++) {
|
||||
if (doi_def->map.std->cat.local[iter] ==
|
||||
CIPSO_V4_INV_CAT)
|
||||
continue;
|
||||
|
||||
nla_b = nla_nest_start(ans_skb, NLBL_CIPSOV4_A_MLSCAT);
|
||||
if (nla_b == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto list_retry;
|
||||
}
|
||||
ret_val = nla_put_u32(ans_skb,
|
||||
NLBL_CIPSOV4_A_MLSCATLOC,
|
||||
iter);
|
||||
if (ret_val != 0)
|
||||
goto list_retry;
|
||||
ret_val = nla_put_u32(ans_skb,
|
||||
NLBL_CIPSOV4_A_MLSCATREM,
|
||||
doi_def->map.std->cat.local[iter]);
|
||||
if (ret_val != 0)
|
||||
goto list_retry;
|
||||
nla_nest_end(ans_skb, nla_b);
|
||||
}
|
||||
nla_nest_end(ans_skb, nla_a);
|
||||
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
genlmsg_end(ans_skb, data);
|
||||
return genlmsg_reply(ans_skb, info);
|
||||
|
||||
list_retry:
|
||||
/* XXX - this limit is a guesstimate */
|
||||
if (nlsze_mult < 4) {
|
||||
rcu_read_unlock();
|
||||
kfree_skb(ans_skb);
|
||||
nlsze_mult *= 2;
|
||||
goto list_start;
|
||||
}
|
||||
list_failure_lock:
|
||||
rcu_read_unlock();
|
||||
list_failure:
|
||||
kfree_skb(ans_skb);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_listall_cb - cipso_v4_doi_walk() callback for LISTALL
|
||||
* @doi_def: the CIPSOv4 DOI definition
|
||||
* @arg: the netlbl_cipsov4_doiwalk_arg structure
|
||||
*
|
||||
* Description:
|
||||
* This function is designed to be used as a callback to the
|
||||
* cipso_v4_doi_walk() function for use in generating a response for a LISTALL
|
||||
* message. Returns the size of the message on success, negative values on
|
||||
* failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_listall_cb(struct cipso_v4_doi *doi_def, void *arg)
|
||||
{
|
||||
int ret_val = -ENOMEM;
|
||||
struct netlbl_cipsov4_doiwalk_arg *cb_arg = arg;
|
||||
void *data;
|
||||
|
||||
data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
|
||||
cb_arg->seq, &netlbl_cipsov4_gnl_family,
|
||||
NLM_F_MULTI, NLBL_CIPSOV4_C_LISTALL);
|
||||
if (data == NULL)
|
||||
goto listall_cb_failure;
|
||||
|
||||
ret_val = nla_put_u32(cb_arg->skb, NLBL_CIPSOV4_A_DOI, doi_def->doi);
|
||||
if (ret_val != 0)
|
||||
goto listall_cb_failure;
|
||||
ret_val = nla_put_u32(cb_arg->skb,
|
||||
NLBL_CIPSOV4_A_MTYPE,
|
||||
doi_def->type);
|
||||
if (ret_val != 0)
|
||||
goto listall_cb_failure;
|
||||
|
||||
return genlmsg_end(cb_arg->skb, data);
|
||||
|
||||
listall_cb_failure:
|
||||
genlmsg_cancel(cb_arg->skb, data);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_listall - Handle a LISTALL message
|
||||
* @skb: the NETLINK buffer
|
||||
* @cb: the NETLINK callback
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated LISTALL message and respond accordingly. Returns
|
||||
* zero on success and negative values on error.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_listall(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct netlbl_cipsov4_doiwalk_arg cb_arg;
|
||||
u32 doi_skip = cb->args[0];
|
||||
|
||||
cb_arg.nl_cb = cb;
|
||||
cb_arg.skb = skb;
|
||||
cb_arg.seq = cb->nlh->nlmsg_seq;
|
||||
|
||||
cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
|
||||
|
||||
cb->args[0] = doi_skip;
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
|
||||
* @entry: LSM domain mapping entry
|
||||
* @arg: the netlbl_domhsh_walk_arg structure
|
||||
*
|
||||
* Description:
|
||||
* This function is intended for use by netlbl_cipsov4_remove() as the callback
|
||||
* for the netlbl_domhsh_walk() function; it removes LSM domain map entries
|
||||
* which are associated with the CIPSO DOI specified in @arg. Returns zero on
|
||||
* success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_remove_cb(struct netlbl_dom_map *entry, void *arg)
|
||||
{
|
||||
struct netlbl_domhsh_walk_arg *cb_arg = arg;
|
||||
|
||||
if (entry->def.type == NETLBL_NLTYPE_CIPSOV4 &&
|
||||
entry->def.cipso->doi == cb_arg->doi)
|
||||
return netlbl_domhsh_remove_entry(entry, cb_arg->audit_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_remove - Handle a REMOVE message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated REMOVE message and respond accordingly. Returns
|
||||
* zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
struct netlbl_domhsh_walk_arg cb_arg;
|
||||
struct netlbl_audit audit_info;
|
||||
u32 skip_bkt = 0;
|
||||
u32 skip_chain = 0;
|
||||
|
||||
if (!info->attrs[NLBL_CIPSOV4_A_DOI])
|
||||
return -EINVAL;
|
||||
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
cb_arg.doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
|
||||
cb_arg.audit_info = &audit_info;
|
||||
ret_val = netlbl_domhsh_walk(&skip_bkt, &skip_chain,
|
||||
netlbl_cipsov4_remove_cb, &cb_arg);
|
||||
if (ret_val == 0 || ret_val == -ENOENT) {
|
||||
ret_val = cipso_v4_doi_remove(cb_arg.doi, &audit_info);
|
||||
if (ret_val == 0)
|
||||
atomic_dec(&netlabel_mgmt_protocount);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* NetLabel Generic NETLINK Command Definitions
|
||||
*/
|
||||
|
||||
static const struct genl_ops netlbl_cipsov4_ops[] = {
|
||||
{
|
||||
.cmd = NLBL_CIPSOV4_C_ADD,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_cipsov4_genl_policy,
|
||||
.doit = netlbl_cipsov4_add,
|
||||
.dumpit = NULL,
|
||||
},
|
||||
{
|
||||
.cmd = NLBL_CIPSOV4_C_REMOVE,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_cipsov4_genl_policy,
|
||||
.doit = netlbl_cipsov4_remove,
|
||||
.dumpit = NULL,
|
||||
},
|
||||
{
|
||||
.cmd = NLBL_CIPSOV4_C_LIST,
|
||||
.flags = 0,
|
||||
.policy = netlbl_cipsov4_genl_policy,
|
||||
.doit = netlbl_cipsov4_list,
|
||||
.dumpit = NULL,
|
||||
},
|
||||
{
|
||||
.cmd = NLBL_CIPSOV4_C_LISTALL,
|
||||
.flags = 0,
|
||||
.policy = netlbl_cipsov4_genl_policy,
|
||||
.doit = NULL,
|
||||
.dumpit = netlbl_cipsov4_listall,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* NetLabel Generic NETLINK Protocol Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_genl_init - Register the CIPSOv4 NetLabel component
|
||||
*
|
||||
* Description:
|
||||
* Register the CIPSOv4 packet NetLabel component with the Generic NETLINK
|
||||
* mechanism. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
int __init netlbl_cipsov4_genl_init(void)
|
||||
{
|
||||
return genl_register_family_with_ops(&netlbl_cipsov4_gnl_family,
|
||||
netlbl_cipsov4_ops);
|
||||
}
|
169
net/netlabel/netlabel_cipso_v4.h
Normal file
169
net/netlabel/netlabel_cipso_v4.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* NetLabel CIPSO/IPv4 Support
|
||||
*
|
||||
* This file defines the CIPSO/IPv4 functions for the NetLabel system. The
|
||||
* NetLabel system manages static and dynamic label mappings for network
|
||||
* protocols such as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETLABEL_CIPSO_V4
|
||||
#define _NETLABEL_CIPSO_V4
|
||||
|
||||
#include <net/netlabel.h>
|
||||
|
||||
/*
|
||||
* The following NetLabel payloads are supported by the CIPSO subsystem.
|
||||
*
|
||||
* o ADD:
|
||||
* Sent by an application to add a new DOI mapping table.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_CIPSOV4_A_DOI
|
||||
* NLBL_CIPSOV4_A_MTYPE
|
||||
* NLBL_CIPSOV4_A_TAGLST
|
||||
*
|
||||
* If using CIPSO_V4_MAP_TRANS the following attributes are required:
|
||||
*
|
||||
* NLBL_CIPSOV4_A_MLSLVLLST
|
||||
* NLBL_CIPSOV4_A_MLSCATLST
|
||||
*
|
||||
* If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
|
||||
* are required.
|
||||
*
|
||||
* o REMOVE:
|
||||
* Sent by an application to remove a specific DOI mapping table from the
|
||||
* CIPSO V4 system.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_CIPSOV4_A_DOI
|
||||
*
|
||||
* o LIST:
|
||||
* Sent by an application to list the details of a DOI definition. On
|
||||
* success the kernel should send a response using the following format.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_CIPSOV4_A_DOI
|
||||
*
|
||||
* The valid response message format depends on the type of the DOI mapping,
|
||||
* the defined formats are shown below.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_CIPSOV4_A_MTYPE
|
||||
* NLBL_CIPSOV4_A_TAGLST
|
||||
*
|
||||
* If using CIPSO_V4_MAP_TRANS the following attributes are required:
|
||||
*
|
||||
* NLBL_CIPSOV4_A_MLSLVLLST
|
||||
* NLBL_CIPSOV4_A_MLSCATLST
|
||||
*
|
||||
* If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
|
||||
* are required.
|
||||
*
|
||||
* o LISTALL:
|
||||
* This message is sent by an application to list the valid DOIs on the
|
||||
* system. When sent by an application there is no payload and the
|
||||
* NLM_F_DUMP flag should be set. The kernel should respond with a series of
|
||||
* the following messages.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_CIPSOV4_A_DOI
|
||||
* NLBL_CIPSOV4_A_MTYPE
|
||||
*
|
||||
*/
|
||||
|
||||
/* NetLabel CIPSOv4 commands */
|
||||
enum {
|
||||
NLBL_CIPSOV4_C_UNSPEC,
|
||||
NLBL_CIPSOV4_C_ADD,
|
||||
NLBL_CIPSOV4_C_REMOVE,
|
||||
NLBL_CIPSOV4_C_LIST,
|
||||
NLBL_CIPSOV4_C_LISTALL,
|
||||
__NLBL_CIPSOV4_C_MAX,
|
||||
};
|
||||
|
||||
/* NetLabel CIPSOv4 attributes */
|
||||
enum {
|
||||
NLBL_CIPSOV4_A_UNSPEC,
|
||||
NLBL_CIPSOV4_A_DOI,
|
||||
/* (NLA_U32)
|
||||
* the DOI value */
|
||||
NLBL_CIPSOV4_A_MTYPE,
|
||||
/* (NLA_U32)
|
||||
* the mapping table type (defined in the cipso_ipv4.h header as
|
||||
* CIPSO_V4_MAP_*) */
|
||||
NLBL_CIPSOV4_A_TAG,
|
||||
/* (NLA_U8)
|
||||
* a CIPSO tag type, meant to be used within a NLBL_CIPSOV4_A_TAGLST
|
||||
* attribute */
|
||||
NLBL_CIPSOV4_A_TAGLST,
|
||||
/* (NLA_NESTED)
|
||||
* the CIPSO tag list for the DOI, there must be at least one
|
||||
* NLBL_CIPSOV4_A_TAG attribute, tags listed first are given higher
|
||||
* priorirty when sending packets */
|
||||
NLBL_CIPSOV4_A_MLSLVLLOC,
|
||||
/* (NLA_U32)
|
||||
* the local MLS sensitivity level */
|
||||
NLBL_CIPSOV4_A_MLSLVLREM,
|
||||
/* (NLA_U32)
|
||||
* the remote MLS sensitivity level */
|
||||
NLBL_CIPSOV4_A_MLSLVL,
|
||||
/* (NLA_NESTED)
|
||||
* a MLS sensitivity level mapping, must contain only one attribute of
|
||||
* each of the following types: NLBL_CIPSOV4_A_MLSLVLLOC and
|
||||
* NLBL_CIPSOV4_A_MLSLVLREM */
|
||||
NLBL_CIPSOV4_A_MLSLVLLST,
|
||||
/* (NLA_NESTED)
|
||||
* the CIPSO level mappings, there must be at least one
|
||||
* NLBL_CIPSOV4_A_MLSLVL attribute */
|
||||
NLBL_CIPSOV4_A_MLSCATLOC,
|
||||
/* (NLA_U32)
|
||||
* the local MLS category */
|
||||
NLBL_CIPSOV4_A_MLSCATREM,
|
||||
/* (NLA_U32)
|
||||
* the remote MLS category */
|
||||
NLBL_CIPSOV4_A_MLSCAT,
|
||||
/* (NLA_NESTED)
|
||||
* a MLS category mapping, must contain only one attribute of each of
|
||||
* the following types: NLBL_CIPSOV4_A_MLSCATLOC and
|
||||
* NLBL_CIPSOV4_A_MLSCATREM */
|
||||
NLBL_CIPSOV4_A_MLSCATLST,
|
||||
/* (NLA_NESTED)
|
||||
* the CIPSO category mappings, there must be at least one
|
||||
* NLBL_CIPSOV4_A_MLSCAT attribute */
|
||||
__NLBL_CIPSOV4_A_MAX,
|
||||
};
|
||||
#define NLBL_CIPSOV4_A_MAX (__NLBL_CIPSOV4_A_MAX - 1)
|
||||
|
||||
/* NetLabel protocol functions */
|
||||
int netlbl_cipsov4_genl_init(void);
|
||||
|
||||
/* Free the memory associated with a CIPSOv4 DOI definition */
|
||||
void netlbl_cipsov4_doi_free(struct rcu_head *entry);
|
||||
|
||||
#endif
|
790
net/netlabel/netlabel_domainhash.c
Normal file
790
net/netlabel/netlabel_domainhash.c
Normal file
|
@ -0,0 +1,790 @@
|
|||
/*
|
||||
* NetLabel Domain Hash Table
|
||||
*
|
||||
* This file manages the domain hash table that NetLabel uses to determine
|
||||
* which network labeling protocol to use for a given domain. The NetLabel
|
||||
* system manages static and dynamic label mappings for network protocols such
|
||||
* as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/rculist.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/audit.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
#include "netlabel_mgmt.h"
|
||||
#include "netlabel_addrlist.h"
|
||||
#include "netlabel_domainhash.h"
|
||||
#include "netlabel_user.h"
|
||||
|
||||
struct netlbl_domhsh_tbl {
|
||||
struct list_head *tbl;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
/* Domain hash table */
|
||||
/* updates should be so rare that having one spinlock for the entire hash table
|
||||
* should be okay */
|
||||
static DEFINE_SPINLOCK(netlbl_domhsh_lock);
|
||||
#define netlbl_domhsh_rcu_deref(p) \
|
||||
rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
|
||||
static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
|
||||
static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
|
||||
|
||||
/*
|
||||
* Domain Hash Table Helper Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_free_entry - Frees a domain hash table entry
|
||||
* @entry: the entry's RCU field
|
||||
*
|
||||
* Description:
|
||||
* This function is designed to be used as a callback to the call_rcu()
|
||||
* function so that the memory allocated to a hash table entry can be released
|
||||
* safely.
|
||||
*
|
||||
*/
|
||||
static void netlbl_domhsh_free_entry(struct rcu_head *entry)
|
||||
{
|
||||
struct netlbl_dom_map *ptr;
|
||||
struct netlbl_af4list *iter4;
|
||||
struct netlbl_af4list *tmp4;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct netlbl_af6list *iter6;
|
||||
struct netlbl_af6list *tmp6;
|
||||
#endif /* IPv6 */
|
||||
|
||||
ptr = container_of(entry, struct netlbl_dom_map, rcu);
|
||||
if (ptr->def.type == NETLBL_NLTYPE_ADDRSELECT) {
|
||||
netlbl_af4list_foreach_safe(iter4, tmp4,
|
||||
&ptr->def.addrsel->list4) {
|
||||
netlbl_af4list_remove_entry(iter4);
|
||||
kfree(netlbl_domhsh_addr4_entry(iter4));
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
netlbl_af6list_foreach_safe(iter6, tmp6,
|
||||
&ptr->def.addrsel->list6) {
|
||||
netlbl_af6list_remove_entry(iter6);
|
||||
kfree(netlbl_domhsh_addr6_entry(iter6));
|
||||
}
|
||||
#endif /* IPv6 */
|
||||
}
|
||||
kfree(ptr->domain);
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_hash - Hashing function for the domain hash table
|
||||
* @domain: the domain name to hash
|
||||
*
|
||||
* Description:
|
||||
* This is the hashing function for the domain hash table, it returns the
|
||||
* correct bucket number for the domain. The caller is responsible for
|
||||
* ensuring that the hash table is protected with either a RCU read lock or the
|
||||
* hash table lock.
|
||||
*
|
||||
*/
|
||||
static u32 netlbl_domhsh_hash(const char *key)
|
||||
{
|
||||
u32 iter;
|
||||
u32 val;
|
||||
u32 len;
|
||||
|
||||
/* This is taken (with slight modification) from
|
||||
* security/selinux/ss/symtab.c:symhash() */
|
||||
|
||||
for (iter = 0, val = 0, len = strlen(key); iter < len; iter++)
|
||||
val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ key[iter];
|
||||
return val & (netlbl_domhsh_rcu_deref(netlbl_domhsh)->size - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_search - Search for a domain entry
|
||||
* @domain: the domain
|
||||
*
|
||||
* Description:
|
||||
* Searches the domain hash table and returns a pointer to the hash table
|
||||
* entry if found, otherwise NULL is returned. The caller is responsible for
|
||||
* ensuring that the hash table is protected with either a RCU read lock or the
|
||||
* hash table lock.
|
||||
*
|
||||
*/
|
||||
static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
|
||||
{
|
||||
u32 bkt;
|
||||
struct list_head *bkt_list;
|
||||
struct netlbl_dom_map *iter;
|
||||
|
||||
if (domain != NULL) {
|
||||
bkt = netlbl_domhsh_hash(domain);
|
||||
bkt_list = &netlbl_domhsh_rcu_deref(netlbl_domhsh)->tbl[bkt];
|
||||
list_for_each_entry_rcu(iter, bkt_list, list)
|
||||
if (iter->valid && strcmp(iter->domain, domain) == 0)
|
||||
return iter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_search_def - Search for a domain entry
|
||||
* @domain: the domain
|
||||
* @def: return default if no match is found
|
||||
*
|
||||
* Description:
|
||||
* Searches the domain hash table and returns a pointer to the hash table
|
||||
* entry if an exact match is found, if an exact match is not present in the
|
||||
* hash table then the default entry is returned if valid otherwise NULL is
|
||||
* returned. The caller is responsible ensuring that the hash table is
|
||||
* protected with either a RCU read lock or the hash table lock.
|
||||
*
|
||||
*/
|
||||
static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
|
||||
{
|
||||
struct netlbl_dom_map *entry;
|
||||
|
||||
entry = netlbl_domhsh_search(domain);
|
||||
if (entry == NULL) {
|
||||
entry = netlbl_domhsh_rcu_deref(netlbl_domhsh_def);
|
||||
if (entry != NULL && !entry->valid)
|
||||
entry = NULL;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_audit_add - Generate an audit entry for an add event
|
||||
* @entry: the entry being added
|
||||
* @addr4: the IPv4 address information
|
||||
* @addr6: the IPv6 address information
|
||||
* @result: the result code
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Generate an audit record for adding a new NetLabel/LSM mapping entry with
|
||||
* the given information. Caller is responsible for holding the necessary
|
||||
* locks.
|
||||
*
|
||||
*/
|
||||
static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
|
||||
struct netlbl_af4list *addr4,
|
||||
struct netlbl_af6list *addr6,
|
||||
int result,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
struct audit_buffer *audit_buf;
|
||||
struct cipso_v4_doi *cipsov4 = NULL;
|
||||
u32 type;
|
||||
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
|
||||
if (audit_buf != NULL) {
|
||||
audit_log_format(audit_buf, " nlbl_domain=%s",
|
||||
entry->domain ? entry->domain : "(default)");
|
||||
if (addr4 != NULL) {
|
||||
struct netlbl_domaddr4_map *map4;
|
||||
map4 = netlbl_domhsh_addr4_entry(addr4);
|
||||
type = map4->def.type;
|
||||
cipsov4 = map4->def.cipso;
|
||||
netlbl_af4list_audit_addr(audit_buf, 0, NULL,
|
||||
addr4->addr, addr4->mask);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else if (addr6 != NULL) {
|
||||
struct netlbl_domaddr6_map *map6;
|
||||
map6 = netlbl_domhsh_addr6_entry(addr6);
|
||||
type = map6->def.type;
|
||||
netlbl_af6list_audit_addr(audit_buf, 0, NULL,
|
||||
&addr6->addr, &addr6->mask);
|
||||
#endif /* IPv6 */
|
||||
} else {
|
||||
type = entry->def.type;
|
||||
cipsov4 = entry->def.cipso;
|
||||
}
|
||||
switch (type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
audit_log_format(audit_buf, " nlbl_protocol=unlbl");
|
||||
break;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
BUG_ON(cipsov4 == NULL);
|
||||
audit_log_format(audit_buf,
|
||||
" nlbl_protocol=cipsov4 cipso_doi=%u",
|
||||
cipsov4->doi);
|
||||
break;
|
||||
}
|
||||
audit_log_format(audit_buf, " res=%u", result == 0 ? 1 : 0);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_validate - Validate a new domain mapping entry
|
||||
* @entry: the entry to validate
|
||||
*
|
||||
* This function validates the new domain mapping entry to ensure that it is
|
||||
* a valid entry. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
|
||||
{
|
||||
struct netlbl_af4list *iter4;
|
||||
struct netlbl_domaddr4_map *map4;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct netlbl_af6list *iter6;
|
||||
struct netlbl_domaddr6_map *map6;
|
||||
#endif /* IPv6 */
|
||||
|
||||
if (entry == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
switch (entry->def.type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
if (entry->def.cipso != NULL || entry->def.addrsel != NULL)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
if (entry->def.cipso == NULL)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case NETLBL_NLTYPE_ADDRSELECT:
|
||||
netlbl_af4list_foreach(iter4, &entry->def.addrsel->list4) {
|
||||
map4 = netlbl_domhsh_addr4_entry(iter4);
|
||||
switch (map4->def.type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
if (map4->def.cipso != NULL)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
if (map4->def.cipso == NULL)
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
netlbl_af6list_foreach(iter6, &entry->def.addrsel->list6) {
|
||||
map6 = netlbl_domhsh_addr6_entry(iter6);
|
||||
switch (map6->def.type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
#endif /* IPv6 */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Domain Hash Table Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_init - Init for the domain hash
|
||||
* @size: the number of bits to use for the hash buckets
|
||||
*
|
||||
* Description:
|
||||
* Initializes the domain hash table, should be called only by
|
||||
* netlbl_user_init() during initialization. Returns zero on success, non-zero
|
||||
* values on error.
|
||||
*
|
||||
*/
|
||||
int __init netlbl_domhsh_init(u32 size)
|
||||
{
|
||||
u32 iter;
|
||||
struct netlbl_domhsh_tbl *hsh_tbl;
|
||||
|
||||
if (size == 0)
|
||||
return -EINVAL;
|
||||
|
||||
hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
|
||||
if (hsh_tbl == NULL)
|
||||
return -ENOMEM;
|
||||
hsh_tbl->size = 1 << size;
|
||||
hsh_tbl->tbl = kcalloc(hsh_tbl->size,
|
||||
sizeof(struct list_head),
|
||||
GFP_KERNEL);
|
||||
if (hsh_tbl->tbl == NULL) {
|
||||
kfree(hsh_tbl);
|
||||
return -ENOMEM;
|
||||
}
|
||||
for (iter = 0; iter < hsh_tbl->size; iter++)
|
||||
INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
|
||||
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_add - Adds a entry to the domain hash table
|
||||
* @entry: the entry to add
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Adds a new entry to the domain hash table and handles any updates to the
|
||||
* lower level protocol handler (i.e. CIPSO). Returns zero on success,
|
||||
* negative on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_domhsh_add(struct netlbl_dom_map *entry,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val = 0;
|
||||
struct netlbl_dom_map *entry_old;
|
||||
struct netlbl_af4list *iter4;
|
||||
struct netlbl_af4list *tmp4;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct netlbl_af6list *iter6;
|
||||
struct netlbl_af6list *tmp6;
|
||||
#endif /* IPv6 */
|
||||
|
||||
ret_val = netlbl_domhsh_validate(entry);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
/* XXX - we can remove this RCU read lock as the spinlock protects the
|
||||
* entire function, but before we do we need to fixup the
|
||||
* netlbl_af[4,6]list RCU functions to do "the right thing" with
|
||||
* respect to rcu_dereference() when only a spinlock is held. */
|
||||
rcu_read_lock();
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
if (entry->domain != NULL)
|
||||
entry_old = netlbl_domhsh_search(entry->domain);
|
||||
else
|
||||
entry_old = netlbl_domhsh_search_def(entry->domain);
|
||||
if (entry_old == NULL) {
|
||||
entry->valid = 1;
|
||||
|
||||
if (entry->domain != NULL) {
|
||||
u32 bkt = netlbl_domhsh_hash(entry->domain);
|
||||
list_add_tail_rcu(&entry->list,
|
||||
&rcu_dereference(netlbl_domhsh)->tbl[bkt]);
|
||||
} else {
|
||||
INIT_LIST_HEAD(&entry->list);
|
||||
rcu_assign_pointer(netlbl_domhsh_def, entry);
|
||||
}
|
||||
|
||||
if (entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
|
||||
netlbl_af4list_foreach_rcu(iter4,
|
||||
&entry->def.addrsel->list4)
|
||||
netlbl_domhsh_audit_add(entry, iter4, NULL,
|
||||
ret_val, audit_info);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
netlbl_af6list_foreach_rcu(iter6,
|
||||
&entry->def.addrsel->list6)
|
||||
netlbl_domhsh_audit_add(entry, NULL, iter6,
|
||||
ret_val, audit_info);
|
||||
#endif /* IPv6 */
|
||||
} else
|
||||
netlbl_domhsh_audit_add(entry, NULL, NULL,
|
||||
ret_val, audit_info);
|
||||
} else if (entry_old->def.type == NETLBL_NLTYPE_ADDRSELECT &&
|
||||
entry->def.type == NETLBL_NLTYPE_ADDRSELECT) {
|
||||
struct list_head *old_list4;
|
||||
struct list_head *old_list6;
|
||||
|
||||
old_list4 = &entry_old->def.addrsel->list4;
|
||||
old_list6 = &entry_old->def.addrsel->list6;
|
||||
|
||||
/* we only allow the addition of address selectors if all of
|
||||
* the selectors do not exist in the existing domain map */
|
||||
netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4)
|
||||
if (netlbl_af4list_search_exact(iter4->addr,
|
||||
iter4->mask,
|
||||
old_list4)) {
|
||||
ret_val = -EEXIST;
|
||||
goto add_return;
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6)
|
||||
if (netlbl_af6list_search_exact(&iter6->addr,
|
||||
&iter6->mask,
|
||||
old_list6)) {
|
||||
ret_val = -EEXIST;
|
||||
goto add_return;
|
||||
}
|
||||
#endif /* IPv6 */
|
||||
|
||||
netlbl_af4list_foreach_safe(iter4, tmp4,
|
||||
&entry->def.addrsel->list4) {
|
||||
netlbl_af4list_remove_entry(iter4);
|
||||
iter4->valid = 1;
|
||||
ret_val = netlbl_af4list_add(iter4, old_list4);
|
||||
netlbl_domhsh_audit_add(entry_old, iter4, NULL,
|
||||
ret_val, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto add_return;
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
netlbl_af6list_foreach_safe(iter6, tmp6,
|
||||
&entry->def.addrsel->list6) {
|
||||
netlbl_af6list_remove_entry(iter6);
|
||||
iter6->valid = 1;
|
||||
ret_val = netlbl_af6list_add(iter6, old_list6);
|
||||
netlbl_domhsh_audit_add(entry_old, NULL, iter6,
|
||||
ret_val, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto add_return;
|
||||
}
|
||||
#endif /* IPv6 */
|
||||
} else
|
||||
ret_val = -EINVAL;
|
||||
|
||||
add_return:
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
rcu_read_unlock();
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_add_default - Adds the default entry to the domain hash table
|
||||
* @entry: the entry to add
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Adds a new default entry to the domain hash table and handles any updates
|
||||
* to the lower level protocol handler (i.e. CIPSO). Returns zero on success,
|
||||
* negative on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
return netlbl_domhsh_add(entry, audit_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_remove_entry - Removes a given entry from the domain table
|
||||
* @entry: the entry to remove
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Removes an entry from the domain hash table and handles any updates to the
|
||||
* lower level protocol handler (i.e. CIPSO). Caller is responsible for
|
||||
* ensuring that the RCU read lock is held. Returns zero on success, negative
|
||||
* on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val = 0;
|
||||
struct audit_buffer *audit_buf;
|
||||
|
||||
if (entry == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
if (entry->valid) {
|
||||
entry->valid = 0;
|
||||
if (entry != rcu_dereference(netlbl_domhsh_def))
|
||||
list_del_rcu(&entry->list);
|
||||
else
|
||||
RCU_INIT_POINTER(netlbl_domhsh_def, NULL);
|
||||
} else
|
||||
ret_val = -ENOENT;
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
|
||||
if (audit_buf != NULL) {
|
||||
audit_log_format(audit_buf,
|
||||
" nlbl_domain=%s res=%u",
|
||||
entry->domain ? entry->domain : "(default)",
|
||||
ret_val == 0 ? 1 : 0);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
|
||||
if (ret_val == 0) {
|
||||
struct netlbl_af4list *iter4;
|
||||
struct netlbl_domaddr4_map *map4;
|
||||
|
||||
switch (entry->def.type) {
|
||||
case NETLBL_NLTYPE_ADDRSELECT:
|
||||
netlbl_af4list_foreach_rcu(iter4,
|
||||
&entry->def.addrsel->list4) {
|
||||
map4 = netlbl_domhsh_addr4_entry(iter4);
|
||||
cipso_v4_doi_putdef(map4->def.cipso);
|
||||
}
|
||||
/* no need to check the IPv6 list since we currently
|
||||
* support only unlabeled protocols for IPv6 */
|
||||
break;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
cipso_v4_doi_putdef(entry->def.cipso);
|
||||
break;
|
||||
}
|
||||
call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_remove_af4 - Removes an address selector entry
|
||||
* @domain: the domain
|
||||
* @addr: IPv4 address
|
||||
* @mask: IPv4 address mask
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Removes an individual address selector from a domain mapping and potentially
|
||||
* the entire mapping if it is empty. Returns zero on success, negative values
|
||||
* on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_domhsh_remove_af4(const char *domain,
|
||||
const struct in_addr *addr,
|
||||
const struct in_addr *mask,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
struct netlbl_dom_map *entry_map;
|
||||
struct netlbl_af4list *entry_addr;
|
||||
struct netlbl_af4list *iter4;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct netlbl_af6list *iter6;
|
||||
#endif /* IPv6 */
|
||||
struct netlbl_domaddr4_map *entry;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (domain)
|
||||
entry_map = netlbl_domhsh_search(domain);
|
||||
else
|
||||
entry_map = netlbl_domhsh_search_def(domain);
|
||||
if (entry_map == NULL ||
|
||||
entry_map->def.type != NETLBL_NLTYPE_ADDRSELECT)
|
||||
goto remove_af4_failure;
|
||||
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
entry_addr = netlbl_af4list_remove(addr->s_addr, mask->s_addr,
|
||||
&entry_map->def.addrsel->list4);
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
|
||||
if (entry_addr == NULL)
|
||||
goto remove_af4_failure;
|
||||
netlbl_af4list_foreach_rcu(iter4, &entry_map->def.addrsel->list4)
|
||||
goto remove_af4_single_addr;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
netlbl_af6list_foreach_rcu(iter6, &entry_map->def.addrsel->list6)
|
||||
goto remove_af4_single_addr;
|
||||
#endif /* IPv6 */
|
||||
/* the domain mapping is empty so remove it from the mapping table */
|
||||
netlbl_domhsh_remove_entry(entry_map, audit_info);
|
||||
|
||||
remove_af4_single_addr:
|
||||
rcu_read_unlock();
|
||||
/* yick, we can't use call_rcu here because we don't have a rcu head
|
||||
* pointer but hopefully this should be a rare case so the pause
|
||||
* shouldn't be a problem */
|
||||
synchronize_rcu();
|
||||
entry = netlbl_domhsh_addr4_entry(entry_addr);
|
||||
cipso_v4_doi_putdef(entry->def.cipso);
|
||||
kfree(entry);
|
||||
return 0;
|
||||
|
||||
remove_af4_failure:
|
||||
rcu_read_unlock();
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_remove - Removes an entry from the domain hash table
|
||||
* @domain: the domain to remove
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Removes an entry from the domain hash table and handles any updates to the
|
||||
* lower level protocol handler (i.e. CIPSO). Returns zero on success,
|
||||
* negative on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val;
|
||||
struct netlbl_dom_map *entry;
|
||||
|
||||
rcu_read_lock();
|
||||
if (domain)
|
||||
entry = netlbl_domhsh_search(domain);
|
||||
else
|
||||
entry = netlbl_domhsh_search_def(domain);
|
||||
ret_val = netlbl_domhsh_remove_entry(entry, audit_info);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_remove_default - Removes the default entry from the table
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Removes/resets the default entry for the domain hash table and handles any
|
||||
* updates to the lower level protocol handler (i.e. CIPSO). Returns zero on
|
||||
* success, non-zero on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
|
||||
{
|
||||
return netlbl_domhsh_remove(NULL, audit_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_getentry - Get an entry from the domain hash table
|
||||
* @domain: the domain name to search for
|
||||
*
|
||||
* Description:
|
||||
* Look through the domain hash table searching for an entry to match @domain,
|
||||
* return a pointer to a copy of the entry or NULL. The caller is responsible
|
||||
* for ensuring that rcu_read_[un]lock() is called.
|
||||
*
|
||||
*/
|
||||
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
|
||||
{
|
||||
return netlbl_domhsh_search_def(domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
|
||||
* @domain: the domain name to search for
|
||||
* @addr: the IP address to search for
|
||||
*
|
||||
* Description:
|
||||
* Look through the domain hash table searching for an entry to match @domain
|
||||
* and @addr, return a pointer to a copy of the entry or NULL. The caller is
|
||||
* responsible for ensuring that rcu_read_[un]lock() is called.
|
||||
*
|
||||
*/
|
||||
struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
|
||||
__be32 addr)
|
||||
{
|
||||
struct netlbl_dom_map *dom_iter;
|
||||
struct netlbl_af4list *addr_iter;
|
||||
|
||||
dom_iter = netlbl_domhsh_search_def(domain);
|
||||
if (dom_iter == NULL)
|
||||
return NULL;
|
||||
|
||||
if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
|
||||
return &dom_iter->def;
|
||||
addr_iter = netlbl_af4list_search(addr, &dom_iter->def.addrsel->list4);
|
||||
if (addr_iter == NULL)
|
||||
return NULL;
|
||||
return &(netlbl_domhsh_addr4_entry(addr_iter)->def);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
/**
|
||||
* netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
|
||||
* @domain: the domain name to search for
|
||||
* @addr: the IP address to search for
|
||||
*
|
||||
* Description:
|
||||
* Look through the domain hash table searching for an entry to match @domain
|
||||
* and @addr, return a pointer to a copy of the entry or NULL. The caller is
|
||||
* responsible for ensuring that rcu_read_[un]lock() is called.
|
||||
*
|
||||
*/
|
||||
struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
|
||||
const struct in6_addr *addr)
|
||||
{
|
||||
struct netlbl_dom_map *dom_iter;
|
||||
struct netlbl_af6list *addr_iter;
|
||||
|
||||
dom_iter = netlbl_domhsh_search_def(domain);
|
||||
if (dom_iter == NULL)
|
||||
return NULL;
|
||||
|
||||
if (dom_iter->def.type != NETLBL_NLTYPE_ADDRSELECT)
|
||||
return &dom_iter->def;
|
||||
addr_iter = netlbl_af6list_search(addr, &dom_iter->def.addrsel->list6);
|
||||
if (addr_iter == NULL)
|
||||
return NULL;
|
||||
return &(netlbl_domhsh_addr6_entry(addr_iter)->def);
|
||||
}
|
||||
#endif /* IPv6 */
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_walk - Iterate through the domain mapping hash table
|
||||
* @skip_bkt: the number of buckets to skip at the start
|
||||
* @skip_chain: the number of entries to skip in the first iterated bucket
|
||||
* @callback: callback for each entry
|
||||
* @cb_arg: argument for the callback function
|
||||
*
|
||||
* Description:
|
||||
* Interate over the domain mapping hash table, skipping the first @skip_bkt
|
||||
* buckets and @skip_chain entries. For each entry in the table call
|
||||
* @callback, if @callback returns a negative value stop 'walking' through the
|
||||
* table and return. Updates the values in @skip_bkt and @skip_chain on
|
||||
* return. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_domhsh_walk(u32 *skip_bkt,
|
||||
u32 *skip_chain,
|
||||
int (*callback) (struct netlbl_dom_map *entry, void *arg),
|
||||
void *cb_arg)
|
||||
{
|
||||
int ret_val = -ENOENT;
|
||||
u32 iter_bkt;
|
||||
struct list_head *iter_list;
|
||||
struct netlbl_dom_map *iter_entry;
|
||||
u32 chain_cnt = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
for (iter_bkt = *skip_bkt;
|
||||
iter_bkt < rcu_dereference(netlbl_domhsh)->size;
|
||||
iter_bkt++, chain_cnt = 0) {
|
||||
iter_list = &rcu_dereference(netlbl_domhsh)->tbl[iter_bkt];
|
||||
list_for_each_entry_rcu(iter_entry, iter_list, list)
|
||||
if (iter_entry->valid) {
|
||||
if (chain_cnt++ < *skip_chain)
|
||||
continue;
|
||||
ret_val = callback(iter_entry, cb_arg);
|
||||
if (ret_val < 0) {
|
||||
chain_cnt--;
|
||||
goto walk_return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
walk_return:
|
||||
rcu_read_unlock();
|
||||
*skip_bkt = iter_bkt;
|
||||
*skip_chain = chain_cnt;
|
||||
return ret_val;
|
||||
}
|
109
net/netlabel/netlabel_domainhash.h
Normal file
109
net/netlabel/netlabel_domainhash.h
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* NetLabel Domain Hash Table
|
||||
*
|
||||
* This file manages the domain hash table that NetLabel uses to determine
|
||||
* which network labeling protocol to use for a given domain. The NetLabel
|
||||
* system manages static and dynamic label mappings for network protocols such
|
||||
* as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETLABEL_DOMAINHASH_H
|
||||
#define _NETLABEL_DOMAINHASH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#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 structures */
|
||||
struct netlbl_domaddr_map {
|
||||
struct list_head list4;
|
||||
struct list_head list6;
|
||||
};
|
||||
struct netlbl_dommap_def {
|
||||
u32 type;
|
||||
union {
|
||||
struct netlbl_domaddr_map *addrsel;
|
||||
struct cipso_v4_doi *cipso;
|
||||
};
|
||||
};
|
||||
#define netlbl_domhsh_addr4_entry(iter) \
|
||||
container_of(iter, struct netlbl_domaddr4_map, list)
|
||||
struct netlbl_domaddr4_map {
|
||||
struct netlbl_dommap_def def;
|
||||
|
||||
struct netlbl_af4list list;
|
||||
};
|
||||
#define netlbl_domhsh_addr6_entry(iter) \
|
||||
container_of(iter, struct netlbl_domaddr6_map, list)
|
||||
struct netlbl_domaddr6_map {
|
||||
struct netlbl_dommap_def def;
|
||||
|
||||
struct netlbl_af6list list;
|
||||
};
|
||||
|
||||
struct netlbl_dom_map {
|
||||
char *domain;
|
||||
struct netlbl_dommap_def def;
|
||||
|
||||
u32 valid;
|
||||
struct list_head list;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
/* init function */
|
||||
int netlbl_domhsh_init(u32 size);
|
||||
|
||||
/* Manipulate the domain hash table */
|
||||
int netlbl_domhsh_add(struct netlbl_dom_map *entry,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_domhsh_remove_af4(const char *domain,
|
||||
const struct in_addr *addr,
|
||||
const struct in_addr *mask,
|
||||
struct netlbl_audit *audit_info);
|
||||
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_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
|
||||
__be32 addr);
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
|
||||
const struct in6_addr *addr);
|
||||
#endif /* IPv6 */
|
||||
|
||||
int netlbl_domhsh_walk(u32 *skip_bkt,
|
||||
u32 *skip_chain,
|
||||
int (*callback) (struct netlbl_dom_map *entry, void *arg),
|
||||
void *cb_arg);
|
||||
|
||||
#endif
|
1211
net/netlabel/netlabel_kapi.c
Normal file
1211
net/netlabel/netlabel_kapi.c
Normal file
File diff suppressed because it is too large
Load diff
782
net/netlabel/netlabel_mgmt.c
Normal file
782
net/netlabel/netlabel_mgmt.c
Normal file
|
@ -0,0 +1,782 @@
|
|||
/*
|
||||
* NetLabel Management Support
|
||||
*
|
||||
* This file defines the management functions for the NetLabel system. The
|
||||
* NetLabel system manages static and dynamic label mappings for network
|
||||
* protocols such as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/in.h>
|
||||
#include <linux/in6.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ipv6.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
#include "netlabel_domainhash.h"
|
||||
#include "netlabel_user.h"
|
||||
#include "netlabel_mgmt.h"
|
||||
|
||||
/* NetLabel configured protocol counter */
|
||||
atomic_t netlabel_mgmt_protocount = ATOMIC_INIT(0);
|
||||
|
||||
/* Argument struct for netlbl_domhsh_walk() */
|
||||
struct netlbl_domhsh_walk_arg {
|
||||
struct netlink_callback *nl_cb;
|
||||
struct sk_buff *skb;
|
||||
u32 seq;
|
||||
};
|
||||
|
||||
/* NetLabel Generic NETLINK CIPSOv4 family */
|
||||
static struct genl_family netlbl_mgmt_gnl_family = {
|
||||
.id = GENL_ID_GENERATE,
|
||||
.hdrsize = 0,
|
||||
.name = NETLBL_NLTYPE_MGMT_NAME,
|
||||
.version = NETLBL_PROTO_VERSION,
|
||||
.maxattr = NLBL_MGMT_A_MAX,
|
||||
};
|
||||
|
||||
/* NetLabel Netlink attribute policy */
|
||||
static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
|
||||
[NLBL_MGMT_A_DOMAIN] = { .type = NLA_NUL_STRING },
|
||||
[NLBL_MGMT_A_PROTOCOL] = { .type = NLA_U32 },
|
||||
[NLBL_MGMT_A_VERSION] = { .type = NLA_U32 },
|
||||
[NLBL_MGMT_A_CV4DOI] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_add - Handle an ADD message
|
||||
* @info: the Generic NETLINK info block
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Helper function for the ADD and ADDDEF messages to add the domain mappings
|
||||
* from the message to the hash table. See netlabel.h for a description of the
|
||||
* message format. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_add_common(struct genl_info *info,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
struct netlbl_dom_map *entry = NULL;
|
||||
struct netlbl_domaddr_map *addrmap = NULL;
|
||||
struct cipso_v4_doi *cipsov4 = NULL;
|
||||
u32 tmp_val;
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (entry == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_failure;
|
||||
}
|
||||
entry->def.type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
|
||||
if (info->attrs[NLBL_MGMT_A_DOMAIN]) {
|
||||
size_t tmp_size = nla_len(info->attrs[NLBL_MGMT_A_DOMAIN]);
|
||||
entry->domain = kmalloc(tmp_size, GFP_KERNEL);
|
||||
if (entry->domain == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_failure;
|
||||
}
|
||||
nla_strlcpy(entry->domain,
|
||||
info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
|
||||
}
|
||||
|
||||
/* NOTE: internally we allow/use a entry->def.type value of
|
||||
* NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
|
||||
* to pass that as a protocol value because we need to know the
|
||||
* "real" protocol */
|
||||
|
||||
switch (entry->def.type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
break;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
|
||||
goto add_failure;
|
||||
|
||||
tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
|
||||
cipsov4 = cipso_v4_doi_getdef(tmp_val);
|
||||
if (cipsov4 == NULL)
|
||||
goto add_failure;
|
||||
entry->def.cipso = cipsov4;
|
||||
break;
|
||||
default:
|
||||
goto add_failure;
|
||||
}
|
||||
|
||||
if (info->attrs[NLBL_MGMT_A_IPV4ADDR]) {
|
||||
struct in_addr *addr;
|
||||
struct in_addr *mask;
|
||||
struct netlbl_domaddr4_map *map;
|
||||
|
||||
addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
|
||||
if (addrmap == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_failure;
|
||||
}
|
||||
INIT_LIST_HEAD(&addrmap->list4);
|
||||
INIT_LIST_HEAD(&addrmap->list6);
|
||||
|
||||
if (nla_len(info->attrs[NLBL_MGMT_A_IPV4ADDR]) !=
|
||||
sizeof(struct in_addr)) {
|
||||
ret_val = -EINVAL;
|
||||
goto add_failure;
|
||||
}
|
||||
if (nla_len(info->attrs[NLBL_MGMT_A_IPV4MASK]) !=
|
||||
sizeof(struct in_addr)) {
|
||||
ret_val = -EINVAL;
|
||||
goto add_failure;
|
||||
}
|
||||
addr = nla_data(info->attrs[NLBL_MGMT_A_IPV4ADDR]);
|
||||
mask = nla_data(info->attrs[NLBL_MGMT_A_IPV4MASK]);
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (map == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_failure;
|
||||
}
|
||||
map->list.addr = addr->s_addr & mask->s_addr;
|
||||
map->list.mask = mask->s_addr;
|
||||
map->list.valid = 1;
|
||||
map->def.type = entry->def.type;
|
||||
if (cipsov4)
|
||||
map->def.cipso = cipsov4;
|
||||
|
||||
ret_val = netlbl_af4list_add(&map->list, &addrmap->list4);
|
||||
if (ret_val != 0) {
|
||||
kfree(map);
|
||||
goto add_failure;
|
||||
}
|
||||
|
||||
entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
|
||||
entry->def.addrsel = addrmap;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
} else if (info->attrs[NLBL_MGMT_A_IPV6ADDR]) {
|
||||
struct in6_addr *addr;
|
||||
struct in6_addr *mask;
|
||||
struct netlbl_domaddr6_map *map;
|
||||
|
||||
addrmap = kzalloc(sizeof(*addrmap), GFP_KERNEL);
|
||||
if (addrmap == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_failure;
|
||||
}
|
||||
INIT_LIST_HEAD(&addrmap->list4);
|
||||
INIT_LIST_HEAD(&addrmap->list6);
|
||||
|
||||
if (nla_len(info->attrs[NLBL_MGMT_A_IPV6ADDR]) !=
|
||||
sizeof(struct in6_addr)) {
|
||||
ret_val = -EINVAL;
|
||||
goto add_failure;
|
||||
}
|
||||
if (nla_len(info->attrs[NLBL_MGMT_A_IPV6MASK]) !=
|
||||
sizeof(struct in6_addr)) {
|
||||
ret_val = -EINVAL;
|
||||
goto add_failure;
|
||||
}
|
||||
addr = nla_data(info->attrs[NLBL_MGMT_A_IPV6ADDR]);
|
||||
mask = nla_data(info->attrs[NLBL_MGMT_A_IPV6MASK]);
|
||||
|
||||
map = kzalloc(sizeof(*map), GFP_KERNEL);
|
||||
if (map == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_failure;
|
||||
}
|
||||
map->list.addr = *addr;
|
||||
map->list.addr.s6_addr32[0] &= mask->s6_addr32[0];
|
||||
map->list.addr.s6_addr32[1] &= mask->s6_addr32[1];
|
||||
map->list.addr.s6_addr32[2] &= mask->s6_addr32[2];
|
||||
map->list.addr.s6_addr32[3] &= mask->s6_addr32[3];
|
||||
map->list.mask = *mask;
|
||||
map->list.valid = 1;
|
||||
map->def.type = entry->def.type;
|
||||
|
||||
ret_val = netlbl_af6list_add(&map->list, &addrmap->list6);
|
||||
if (ret_val != 0) {
|
||||
kfree(map);
|
||||
goto add_failure;
|
||||
}
|
||||
|
||||
entry->def.type = NETLBL_NLTYPE_ADDRSELECT;
|
||||
entry->def.addrsel = addrmap;
|
||||
#endif /* IPv6 */
|
||||
}
|
||||
|
||||
ret_val = netlbl_domhsh_add(entry, audit_info);
|
||||
if (ret_val != 0)
|
||||
goto add_failure;
|
||||
|
||||
return 0;
|
||||
|
||||
add_failure:
|
||||
if (cipsov4)
|
||||
cipso_v4_doi_putdef(cipsov4);
|
||||
if (entry)
|
||||
kfree(entry->domain);
|
||||
kfree(addrmap);
|
||||
kfree(entry);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
|
||||
* @skb: the NETLINK buffer
|
||||
* @entry: the map entry
|
||||
*
|
||||
* Description:
|
||||
* This function is a helper function used by the LISTALL and LISTDEF command
|
||||
* handlers. The caller is responsible for ensuring that the RCU read lock
|
||||
* is held. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_listentry(struct sk_buff *skb,
|
||||
struct netlbl_dom_map *entry)
|
||||
{
|
||||
int ret_val = 0;
|
||||
struct nlattr *nla_a;
|
||||
struct nlattr *nla_b;
|
||||
struct netlbl_af4list *iter4;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
struct netlbl_af6list *iter6;
|
||||
#endif
|
||||
|
||||
if (entry->domain != NULL) {
|
||||
ret_val = nla_put_string(skb,
|
||||
NLBL_MGMT_A_DOMAIN, entry->domain);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
switch (entry->def.type) {
|
||||
case NETLBL_NLTYPE_ADDRSELECT:
|
||||
nla_a = nla_nest_start(skb, NLBL_MGMT_A_SELECTORLIST);
|
||||
if (nla_a == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
netlbl_af4list_foreach_rcu(iter4, &entry->def.addrsel->list4) {
|
||||
struct netlbl_domaddr4_map *map4;
|
||||
struct in_addr addr_struct;
|
||||
|
||||
nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
|
||||
if (nla_b == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
addr_struct.s_addr = iter4->addr;
|
||||
ret_val = nla_put(skb, NLBL_MGMT_A_IPV4ADDR,
|
||||
sizeof(struct in_addr),
|
||||
&addr_struct);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
addr_struct.s_addr = iter4->mask;
|
||||
ret_val = nla_put(skb, NLBL_MGMT_A_IPV4MASK,
|
||||
sizeof(struct in_addr),
|
||||
&addr_struct);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
map4 = netlbl_domhsh_addr4_entry(iter4);
|
||||
ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
|
||||
map4->def.type);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
switch (map4->def.type) {
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
|
||||
map4->def.cipso->doi);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
break;
|
||||
}
|
||||
|
||||
nla_nest_end(skb, nla_b);
|
||||
}
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
netlbl_af6list_foreach_rcu(iter6, &entry->def.addrsel->list6) {
|
||||
struct netlbl_domaddr6_map *map6;
|
||||
|
||||
nla_b = nla_nest_start(skb, NLBL_MGMT_A_ADDRSELECTOR);
|
||||
if (nla_b == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret_val = nla_put(skb, NLBL_MGMT_A_IPV6ADDR,
|
||||
sizeof(struct in6_addr),
|
||||
&iter6->addr);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = nla_put(skb, NLBL_MGMT_A_IPV6MASK,
|
||||
sizeof(struct in6_addr),
|
||||
&iter6->mask);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
map6 = netlbl_domhsh_addr6_entry(iter6);
|
||||
ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL,
|
||||
map6->def.type);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
nla_nest_end(skb, nla_b);
|
||||
}
|
||||
#endif /* IPv6 */
|
||||
|
||||
nla_nest_end(skb, nla_a);
|
||||
break;
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type);
|
||||
break;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
ret_val = nla_put_u32(skb,NLBL_MGMT_A_PROTOCOL,entry->def.type);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = nla_put_u32(skb, NLBL_MGMT_A_CV4DOI,
|
||||
entry->def.cipso->doi);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* NetLabel Command Handlers
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_add - Handle an ADD message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated ADD message and add the domains from the message
|
||||
* to the hash table. See netlabel.h for a description of the message format.
|
||||
* Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
if ((!info->attrs[NLBL_MGMT_A_DOMAIN]) ||
|
||||
(!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
|
||||
(info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
|
||||
info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
|
||||
(info->attrs[NLBL_MGMT_A_IPV4MASK] &&
|
||||
info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
|
||||
((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
|
||||
(info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
|
||||
((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
|
||||
(info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
|
||||
return -EINVAL;
|
||||
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
return netlbl_mgmt_add_common(info, &audit_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_remove - Handle a REMOVE message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated REMOVE message and remove the specified domain
|
||||
* mappings. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
char *domain;
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
if (!info->attrs[NLBL_MGMT_A_DOMAIN])
|
||||
return -EINVAL;
|
||||
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
|
||||
return netlbl_domhsh_remove(domain, &audit_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_listall_cb - netlbl_domhsh_walk() callback for LISTALL
|
||||
* @entry: the domain mapping hash table entry
|
||||
* @arg: the netlbl_domhsh_walk_arg structure
|
||||
*
|
||||
* Description:
|
||||
* This function is designed to be used as a callback to the
|
||||
* netlbl_domhsh_walk() function for use in generating a response for a LISTALL
|
||||
* message. Returns the size of the message on success, negative values on
|
||||
* failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
|
||||
{
|
||||
int ret_val = -ENOMEM;
|
||||
struct netlbl_domhsh_walk_arg *cb_arg = arg;
|
||||
void *data;
|
||||
|
||||
data = genlmsg_put(cb_arg->skb, NETLINK_CB(cb_arg->nl_cb->skb).portid,
|
||||
cb_arg->seq, &netlbl_mgmt_gnl_family,
|
||||
NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
|
||||
if (data == NULL)
|
||||
goto listall_cb_failure;
|
||||
|
||||
ret_val = netlbl_mgmt_listentry(cb_arg->skb, entry);
|
||||
if (ret_val != 0)
|
||||
goto listall_cb_failure;
|
||||
|
||||
cb_arg->seq++;
|
||||
return genlmsg_end(cb_arg->skb, data);
|
||||
|
||||
listall_cb_failure:
|
||||
genlmsg_cancel(cb_arg->skb, data);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_listall - Handle a LISTALL message
|
||||
* @skb: the NETLINK buffer
|
||||
* @cb: the NETLINK callback
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated LISTALL message and dumps the domain hash table in
|
||||
* a form suitable for use in a kernel generated LISTALL message. Returns zero
|
||||
* on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_listall(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct netlbl_domhsh_walk_arg cb_arg;
|
||||
u32 skip_bkt = cb->args[0];
|
||||
u32 skip_chain = cb->args[1];
|
||||
|
||||
cb_arg.nl_cb = cb;
|
||||
cb_arg.skb = skb;
|
||||
cb_arg.seq = cb->nlh->nlmsg_seq;
|
||||
|
||||
netlbl_domhsh_walk(&skip_bkt,
|
||||
&skip_chain,
|
||||
netlbl_mgmt_listall_cb,
|
||||
&cb_arg);
|
||||
|
||||
cb->args[0] = skip_bkt;
|
||||
cb->args[1] = skip_chain;
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_adddef - Handle an ADDDEF message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated ADDDEF message and respond accordingly. Returns
|
||||
* zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
if ((!info->attrs[NLBL_MGMT_A_PROTOCOL]) ||
|
||||
(info->attrs[NLBL_MGMT_A_IPV4ADDR] &&
|
||||
info->attrs[NLBL_MGMT_A_IPV6ADDR]) ||
|
||||
(info->attrs[NLBL_MGMT_A_IPV4MASK] &&
|
||||
info->attrs[NLBL_MGMT_A_IPV6MASK]) ||
|
||||
((info->attrs[NLBL_MGMT_A_IPV4ADDR] != NULL) ^
|
||||
(info->attrs[NLBL_MGMT_A_IPV4MASK] != NULL)) ||
|
||||
((info->attrs[NLBL_MGMT_A_IPV6ADDR] != NULL) ^
|
||||
(info->attrs[NLBL_MGMT_A_IPV6MASK] != NULL)))
|
||||
return -EINVAL;
|
||||
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
return netlbl_mgmt_add_common(info, &audit_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_removedef - Handle a REMOVEDEF message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated REMOVEDEF message and remove the default domain
|
||||
* mapping. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
return netlbl_domhsh_remove_default(&audit_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_listdef - Handle a LISTDEF message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated LISTDEF message and dumps the default domain
|
||||
* mapping in a form suitable for use in a kernel generated LISTDEF message.
|
||||
* Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int ret_val = -ENOMEM;
|
||||
struct sk_buff *ans_skb = NULL;
|
||||
void *data;
|
||||
struct netlbl_dom_map *entry;
|
||||
|
||||
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (ans_skb == NULL)
|
||||
return -ENOMEM;
|
||||
data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
|
||||
0, NLBL_MGMT_C_LISTDEF);
|
||||
if (data == NULL)
|
||||
goto listdef_failure;
|
||||
|
||||
rcu_read_lock();
|
||||
entry = netlbl_domhsh_getentry(NULL);
|
||||
if (entry == NULL) {
|
||||
ret_val = -ENOENT;
|
||||
goto listdef_failure_lock;
|
||||
}
|
||||
ret_val = netlbl_mgmt_listentry(ans_skb, entry);
|
||||
rcu_read_unlock();
|
||||
if (ret_val != 0)
|
||||
goto listdef_failure;
|
||||
|
||||
genlmsg_end(ans_skb, data);
|
||||
return genlmsg_reply(ans_skb, info);
|
||||
|
||||
listdef_failure_lock:
|
||||
rcu_read_unlock();
|
||||
listdef_failure:
|
||||
kfree_skb(ans_skb);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response
|
||||
* @skb: the skb to write to
|
||||
* @cb: the NETLINK callback
|
||||
* @protocol: the NetLabel protocol to use in the message
|
||||
*
|
||||
* Description:
|
||||
* This function is to be used in conjunction with netlbl_mgmt_protocols() to
|
||||
* answer a application's PROTOCOLS message. Returns the size of the message
|
||||
* on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
u32 protocol)
|
||||
{
|
||||
int ret_val = -ENOMEM;
|
||||
void *data;
|
||||
|
||||
data = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
|
||||
&netlbl_mgmt_gnl_family, NLM_F_MULTI,
|
||||
NLBL_MGMT_C_PROTOCOLS);
|
||||
if (data == NULL)
|
||||
goto protocols_cb_failure;
|
||||
|
||||
ret_val = nla_put_u32(skb, NLBL_MGMT_A_PROTOCOL, protocol);
|
||||
if (ret_val != 0)
|
||||
goto protocols_cb_failure;
|
||||
|
||||
return genlmsg_end(skb, data);
|
||||
|
||||
protocols_cb_failure:
|
||||
genlmsg_cancel(skb, data);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_protocols - Handle a PROTOCOLS message
|
||||
* @skb: the NETLINK buffer
|
||||
* @cb: the NETLINK callback
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated PROTOCOLS message and respond accordingly.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_protocols(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
u32 protos_sent = cb->args[0];
|
||||
|
||||
if (protos_sent == 0) {
|
||||
if (netlbl_mgmt_protocols_cb(skb,
|
||||
cb,
|
||||
NETLBL_NLTYPE_UNLABELED) < 0)
|
||||
goto protocols_return;
|
||||
protos_sent++;
|
||||
}
|
||||
if (protos_sent == 1) {
|
||||
if (netlbl_mgmt_protocols_cb(skb,
|
||||
cb,
|
||||
NETLBL_NLTYPE_CIPSOV4) < 0)
|
||||
goto protocols_return;
|
||||
protos_sent++;
|
||||
}
|
||||
|
||||
protocols_return:
|
||||
cb->args[0] = protos_sent;
|
||||
return skb->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_version - Handle a VERSION message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated VERSION message and respond accordingly. Returns
|
||||
* zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int ret_val = -ENOMEM;
|
||||
struct sk_buff *ans_skb = NULL;
|
||||
void *data;
|
||||
|
||||
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (ans_skb == NULL)
|
||||
return -ENOMEM;
|
||||
data = genlmsg_put_reply(ans_skb, info, &netlbl_mgmt_gnl_family,
|
||||
0, NLBL_MGMT_C_VERSION);
|
||||
if (data == NULL)
|
||||
goto version_failure;
|
||||
|
||||
ret_val = nla_put_u32(ans_skb,
|
||||
NLBL_MGMT_A_VERSION,
|
||||
NETLBL_PROTO_VERSION);
|
||||
if (ret_val != 0)
|
||||
goto version_failure;
|
||||
|
||||
genlmsg_end(ans_skb, data);
|
||||
return genlmsg_reply(ans_skb, info);
|
||||
|
||||
version_failure:
|
||||
kfree_skb(ans_skb);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NetLabel Generic NETLINK Command Definitions
|
||||
*/
|
||||
|
||||
static const struct genl_ops netlbl_mgmt_genl_ops[] = {
|
||||
{
|
||||
.cmd = NLBL_MGMT_C_ADD,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_add,
|
||||
.dumpit = NULL,
|
||||
},
|
||||
{
|
||||
.cmd = NLBL_MGMT_C_REMOVE,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_remove,
|
||||
.dumpit = NULL,
|
||||
},
|
||||
{
|
||||
.cmd = NLBL_MGMT_C_LISTALL,
|
||||
.flags = 0,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = NULL,
|
||||
.dumpit = netlbl_mgmt_listall,
|
||||
},
|
||||
{
|
||||
.cmd = NLBL_MGMT_C_ADDDEF,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_adddef,
|
||||
.dumpit = NULL,
|
||||
},
|
||||
{
|
||||
.cmd = NLBL_MGMT_C_REMOVEDEF,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_removedef,
|
||||
.dumpit = NULL,
|
||||
},
|
||||
{
|
||||
.cmd = NLBL_MGMT_C_LISTDEF,
|
||||
.flags = 0,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_listdef,
|
||||
.dumpit = NULL,
|
||||
},
|
||||
{
|
||||
.cmd = NLBL_MGMT_C_PROTOCOLS,
|
||||
.flags = 0,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = NULL,
|
||||
.dumpit = netlbl_mgmt_protocols,
|
||||
},
|
||||
{
|
||||
.cmd = NLBL_MGMT_C_VERSION,
|
||||
.flags = 0,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_version,
|
||||
.dumpit = NULL,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* NetLabel Generic NETLINK Protocol Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_mgmt_genl_init - Register the NetLabel management component
|
||||
*
|
||||
* Description:
|
||||
* Register the NetLabel management component with the Generic NETLINK
|
||||
* mechanism. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
int __init netlbl_mgmt_genl_init(void)
|
||||
{
|
||||
return genl_register_family_with_ops(&netlbl_mgmt_gnl_family,
|
||||
netlbl_mgmt_genl_ops);
|
||||
}
|
222
net/netlabel/netlabel_mgmt.h
Normal file
222
net/netlabel/netlabel_mgmt.h
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* NetLabel Management Support
|
||||
*
|
||||
* This file defines the management functions for the NetLabel system. The
|
||||
* NetLabel system manages static and dynamic label mappings for network
|
||||
* protocols such as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETLABEL_MGMT_H
|
||||
#define _NETLABEL_MGMT_H
|
||||
|
||||
#include <net/netlabel.h>
|
||||
#include <linux/atomic.h>
|
||||
|
||||
/*
|
||||
* The following NetLabel payloads are supported by the management interface.
|
||||
*
|
||||
* o ADD:
|
||||
* Sent by an application to add a domain mapping to the NetLabel system.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
|
||||
*
|
||||
* o REMOVE:
|
||||
* Sent by an application to remove a domain mapping from the NetLabel
|
||||
* system.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_MGMT_A_DOMAIN
|
||||
*
|
||||
* o LISTALL:
|
||||
* This message can be sent either from an application or by the kernel in
|
||||
* response to an application generated LISTALL message. When sent by an
|
||||
* application there is no payload and the NLM_F_DUMP flag should be set.
|
||||
* The kernel should respond with a series of the following messages.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_MGMT_A_DOMAIN
|
||||
*
|
||||
* If the IP address selectors are not used the following attribute is
|
||||
* required:
|
||||
*
|
||||
* NLBL_MGMT_A_PROTOCOL
|
||||
*
|
||||
* 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 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
|
||||
* system.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_MGMT_A_PROTOCOL
|
||||
*
|
||||
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
|
||||
*
|
||||
* NLBL_MGMT_A_CV4DOI
|
||||
*
|
||||
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
|
||||
*
|
||||
* o REMOVEDEF:
|
||||
* Sent by an application to remove the default domain mapping from the
|
||||
* NetLabel system, there is no payload.
|
||||
*
|
||||
* o LISTDEF:
|
||||
* This message can be sent either from an application or by the kernel in
|
||||
* response to an application generated LISTDEF message. When sent by an
|
||||
* application there is no payload. On success the kernel should send a
|
||||
* response using the following format.
|
||||
*
|
||||
* If the IP address selectors are not used the following attribute is
|
||||
* required:
|
||||
*
|
||||
* NLBL_MGMT_A_PROTOCOL
|
||||
*
|
||||
* 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 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
|
||||
* in the kernel. When sent by an application there is no payload and the
|
||||
* NLM_F_DUMP flag should be set. The kernel should respond with a series of
|
||||
* the following messages.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_MGMT_A_PROTOCOL
|
||||
*
|
||||
* o VERSION:
|
||||
* Sent by an application to request the NetLabel version. When sent by an
|
||||
* application there is no payload. This message type is also used by the
|
||||
* kernel to respond to an VERSION request.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_MGMT_A_VERSION
|
||||
*
|
||||
*/
|
||||
|
||||
/* NetLabel Management commands */
|
||||
enum {
|
||||
NLBL_MGMT_C_UNSPEC,
|
||||
NLBL_MGMT_C_ADD,
|
||||
NLBL_MGMT_C_REMOVE,
|
||||
NLBL_MGMT_C_LISTALL,
|
||||
NLBL_MGMT_C_ADDDEF,
|
||||
NLBL_MGMT_C_REMOVEDEF,
|
||||
NLBL_MGMT_C_LISTDEF,
|
||||
NLBL_MGMT_C_PROTOCOLS,
|
||||
NLBL_MGMT_C_VERSION,
|
||||
__NLBL_MGMT_C_MAX,
|
||||
};
|
||||
|
||||
/* NetLabel Management attributes */
|
||||
enum {
|
||||
NLBL_MGMT_A_UNSPEC,
|
||||
NLBL_MGMT_A_DOMAIN,
|
||||
/* (NLA_NUL_STRING)
|
||||
* the NULL terminated LSM domain string */
|
||||
NLBL_MGMT_A_PROTOCOL,
|
||||
/* (NLA_U32)
|
||||
* the NetLabel protocol type (defined by NETLBL_NLTYPE_*) */
|
||||
NLBL_MGMT_A_VERSION,
|
||||
/* (NLA_U32)
|
||||
* the NetLabel protocol version number (defined by
|
||||
* NETLBL_PROTO_VERSION) */
|
||||
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)
|
||||
|
||||
/* NetLabel protocol functions */
|
||||
int netlbl_mgmt_genl_init(void);
|
||||
|
||||
/* NetLabel configured protocol reference counter */
|
||||
extern atomic_t netlabel_mgmt_protocount;
|
||||
|
||||
#endif
|
1551
net/netlabel/netlabel_unlabeled.c
Normal file
1551
net/netlabel/netlabel_unlabeled.c
Normal file
File diff suppressed because it is too large
Load diff
245
net/netlabel/netlabel_unlabeled.h
Normal file
245
net/netlabel/netlabel_unlabeled.h
Normal file
|
@ -0,0 +1,245 @@
|
|||
/*
|
||||
* NetLabel Unlabeled Support
|
||||
*
|
||||
* This file defines functions for dealing with unlabeled packets for the
|
||||
* NetLabel system. The NetLabel system manages static and dynamic label
|
||||
* mappings for network protocols such as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETLABEL_UNLABELED_H
|
||||
#define _NETLABEL_UNLABELED_H
|
||||
|
||||
#include <net/netlabel.h>
|
||||
|
||||
/*
|
||||
* The following NetLabel payloads are supported by the Unlabeled subsystem.
|
||||
*
|
||||
* o STATICADD
|
||||
* This message is sent from an application to add a new static label for
|
||||
* incoming unlabeled connections.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IFACE
|
||||
* NLBL_UNLABEL_A_SECCTX
|
||||
*
|
||||
* If IPv4 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV4ADDR
|
||||
* NLBL_UNLABEL_A_IPV4MASK
|
||||
*
|
||||
* If IPv6 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV6ADDR
|
||||
* NLBL_UNLABEL_A_IPV6MASK
|
||||
*
|
||||
* o STATICREMOVE
|
||||
* This message is sent from an application to remove an existing static
|
||||
* label for incoming unlabeled connections.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IFACE
|
||||
*
|
||||
* If IPv4 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV4ADDR
|
||||
* NLBL_UNLABEL_A_IPV4MASK
|
||||
*
|
||||
* If IPv6 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV6ADDR
|
||||
* NLBL_UNLABEL_A_IPV6MASK
|
||||
*
|
||||
* o STATICLIST
|
||||
* This message can be sent either from an application or by the kernel in
|
||||
* response to an application generated STATICLIST message. When sent by an
|
||||
* application there is no payload and the NLM_F_DUMP flag should be set.
|
||||
* The kernel should response with a series of the following messages.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IFACE
|
||||
* NLBL_UNLABEL_A_SECCTX
|
||||
*
|
||||
* If IPv4 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV4ADDR
|
||||
* NLBL_UNLABEL_A_IPV4MASK
|
||||
*
|
||||
* If IPv6 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV6ADDR
|
||||
* NLBL_UNLABEL_A_IPV6MASK
|
||||
*
|
||||
* o STATICADDDEF
|
||||
* This message is sent from an application to set the default static
|
||||
* label for incoming unlabeled connections.
|
||||
*
|
||||
* Required attribute:
|
||||
*
|
||||
* NLBL_UNLABEL_A_SECCTX
|
||||
*
|
||||
* If IPv4 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV4ADDR
|
||||
* NLBL_UNLABEL_A_IPV4MASK
|
||||
*
|
||||
* If IPv6 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV6ADDR
|
||||
* NLBL_UNLABEL_A_IPV6MASK
|
||||
*
|
||||
* o STATICREMOVEDEF
|
||||
* This message is sent from an application to remove the existing default
|
||||
* static label for incoming unlabeled connections.
|
||||
*
|
||||
* If IPv4 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV4ADDR
|
||||
* NLBL_UNLABEL_A_IPV4MASK
|
||||
*
|
||||
* If IPv6 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV6ADDR
|
||||
* NLBL_UNLABEL_A_IPV6MASK
|
||||
*
|
||||
* o STATICLISTDEF
|
||||
* This message can be sent either from an application or by the kernel in
|
||||
* response to an application generated STATICLISTDEF message. When sent by
|
||||
* an application there is no payload and the NLM_F_DUMP flag should be set.
|
||||
* The kernel should response with the following message.
|
||||
*
|
||||
* Required attribute:
|
||||
*
|
||||
* NLBL_UNLABEL_A_SECCTX
|
||||
*
|
||||
* If IPv4 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV4ADDR
|
||||
* NLBL_UNLABEL_A_IPV4MASK
|
||||
*
|
||||
* If IPv6 is specified the following attributes are required:
|
||||
*
|
||||
* NLBL_UNLABEL_A_IPV6ADDR
|
||||
* NLBL_UNLABEL_A_IPV6MASK
|
||||
*
|
||||
* o ACCEPT
|
||||
* This message is sent from an application to specify if the kernel should
|
||||
* allow unlabled packets to pass if they do not match any of the static
|
||||
* mappings defined in the unlabeled module.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_UNLABEL_A_ACPTFLG
|
||||
*
|
||||
* o LIST
|
||||
* This message can be sent either from an application or by the kernel in
|
||||
* response to an application generated LIST message. When sent by an
|
||||
* application there is no payload. The kernel should respond to a LIST
|
||||
* message with a LIST message on success.
|
||||
*
|
||||
* Required attributes:
|
||||
*
|
||||
* NLBL_UNLABEL_A_ACPTFLG
|
||||
*
|
||||
*/
|
||||
|
||||
/* NetLabel Unlabeled commands */
|
||||
enum {
|
||||
NLBL_UNLABEL_C_UNSPEC,
|
||||
NLBL_UNLABEL_C_ACCEPT,
|
||||
NLBL_UNLABEL_C_LIST,
|
||||
NLBL_UNLABEL_C_STATICADD,
|
||||
NLBL_UNLABEL_C_STATICREMOVE,
|
||||
NLBL_UNLABEL_C_STATICLIST,
|
||||
NLBL_UNLABEL_C_STATICADDDEF,
|
||||
NLBL_UNLABEL_C_STATICREMOVEDEF,
|
||||
NLBL_UNLABEL_C_STATICLISTDEF,
|
||||
__NLBL_UNLABEL_C_MAX,
|
||||
};
|
||||
|
||||
/* NetLabel Unlabeled attributes */
|
||||
enum {
|
||||
NLBL_UNLABEL_A_UNSPEC,
|
||||
NLBL_UNLABEL_A_ACPTFLG,
|
||||
/* (NLA_U8)
|
||||
* if true then unlabeled packets are allowed to pass, else unlabeled
|
||||
* packets are rejected */
|
||||
NLBL_UNLABEL_A_IPV6ADDR,
|
||||
/* (NLA_BINARY, struct in6_addr)
|
||||
* an IPv6 address */
|
||||
NLBL_UNLABEL_A_IPV6MASK,
|
||||
/* (NLA_BINARY, struct in6_addr)
|
||||
* an IPv6 address mask */
|
||||
NLBL_UNLABEL_A_IPV4ADDR,
|
||||
/* (NLA_BINARY, struct in_addr)
|
||||
* an IPv4 address */
|
||||
NLBL_UNLABEL_A_IPV4MASK,
|
||||
/* (NLA_BINARY, struct in_addr)
|
||||
* and IPv4 address mask */
|
||||
NLBL_UNLABEL_A_IFACE,
|
||||
/* (NLA_NULL_STRING)
|
||||
* network interface */
|
||||
NLBL_UNLABEL_A_SECCTX,
|
||||
/* (NLA_BINARY)
|
||||
* a LSM specific security context */
|
||||
__NLBL_UNLABEL_A_MAX,
|
||||
};
|
||||
#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1)
|
||||
|
||||
/* NetLabel protocol functions */
|
||||
int netlbl_unlabel_genl_init(void);
|
||||
|
||||
/* Unlabeled connection hash table size */
|
||||
/* XXX - currently this number is an uneducated guess */
|
||||
#define NETLBL_UNLHSH_BITSIZE 7
|
||||
|
||||
/* General Unlabeled init function */
|
||||
int netlbl_unlabel_init(u32 size);
|
||||
|
||||
/* Static/Fallback label management functions */
|
||||
int netlbl_unlhsh_add(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u32 addr_len,
|
||||
u32 secid,
|
||||
struct netlbl_audit *audit_info);
|
||||
int netlbl_unlhsh_remove(struct net *net,
|
||||
const char *dev_name,
|
||||
const void *addr,
|
||||
const void *mask,
|
||||
u32 addr_len,
|
||||
struct netlbl_audit *audit_info);
|
||||
|
||||
/* Process Unlabeled incoming network packets */
|
||||
int netlbl_unlabel_getattr(const struct sk_buff *skb,
|
||||
u16 family,
|
||||
struct netlbl_lsm_secattr *secattr);
|
||||
|
||||
/* Set the default configuration to allow Unlabeled packets */
|
||||
int netlbl_unlabel_defconf(void);
|
||||
|
||||
#endif
|
119
net/netlabel/netlabel_user.c
Normal file
119
net/netlabel/netlabel_user.c
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* NetLabel NETLINK Interface
|
||||
*
|
||||
* This file defines the NETLINK interface for the NetLabel system. The
|
||||
* NetLabel system manages static and dynamic label mappings for network
|
||||
* protocols such as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/audit.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
#include "netlabel_mgmt.h"
|
||||
#include "netlabel_unlabeled.h"
|
||||
#include "netlabel_cipso_v4.h"
|
||||
#include "netlabel_user.h"
|
||||
|
||||
/*
|
||||
* NetLabel NETLINK Setup Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_netlink_init - Initialize the NETLINK communication channel
|
||||
*
|
||||
* Description:
|
||||
* Call out to the NetLabel components so they can register their families and
|
||||
* commands with the Generic NETLINK mechanism. Returns zero on success and
|
||||
* non-zero on failure.
|
||||
*
|
||||
*/
|
||||
int __init netlbl_netlink_init(void)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
ret_val = netlbl_mgmt_genl_init();
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
ret_val = netlbl_cipsov4_genl_init();
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
return netlbl_unlabel_genl_init();
|
||||
}
|
||||
|
||||
/*
|
||||
* NetLabel Audit Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_audit_start_common - Start an audit message
|
||||
* @type: audit message type
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Start an audit message using the type specified in @type and fill the audit
|
||||
* message with some fields common to all NetLabel audit messages. Returns
|
||||
* a pointer to the audit buffer on success, NULL on failure.
|
||||
*
|
||||
*/
|
||||
struct audit_buffer *netlbl_audit_start_common(int type,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
struct audit_buffer *audit_buf;
|
||||
char *secctx;
|
||||
u32 secctx_len;
|
||||
|
||||
if (audit_enabled == 0)
|
||||
return NULL;
|
||||
|
||||
audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC, type);
|
||||
if (audit_buf == NULL)
|
||||
return NULL;
|
||||
|
||||
audit_log_format(audit_buf, "netlabel: auid=%u ses=%u",
|
||||
from_kuid(&init_user_ns, audit_info->loginuid),
|
||||
audit_info->sessionid);
|
||||
|
||||
if (audit_info->secid != 0 &&
|
||||
security_secid_to_secctx(audit_info->secid,
|
||||
&secctx,
|
||||
&secctx_len) == 0) {
|
||||
audit_log_format(audit_buf, " subj=%s", secctx);
|
||||
security_release_secctx(secctx, secctx_len);
|
||||
}
|
||||
|
||||
return audit_buf;
|
||||
}
|
65
net/netlabel/netlabel_user.h
Normal file
65
net/netlabel/netlabel_user.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* NetLabel NETLINK Interface
|
||||
*
|
||||
* This file defines the NETLINK interface for the NetLabel system. The
|
||||
* NetLabel system manages static and dynamic label mappings for network
|
||||
* protocols such as CIPSO and RIPSO.
|
||||
*
|
||||
* Author: Paul Moore <paul@paul-moore.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
|
||||
*
|
||||
* 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
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
|
||||
* the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETLABEL_USER_H
|
||||
#define _NETLABEL_USER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/audit.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlabel.h>
|
||||
|
||||
/* NetLabel NETLINK helper functions */
|
||||
|
||||
/**
|
||||
* netlbl_netlink_auditinfo - Fetch the audit information from a NETLINK msg
|
||||
* @skb: the packet
|
||||
* @audit_info: NetLabel audit information
|
||||
*/
|
||||
static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
security_task_getsecid(current, &audit_info->secid);
|
||||
audit_info->loginuid = audit_get_loginuid(current);
|
||||
audit_info->sessionid = audit_get_sessionid(current);
|
||||
}
|
||||
|
||||
/* NetLabel NETLINK I/O functions */
|
||||
|
||||
int netlbl_netlink_init(void);
|
||||
|
||||
/* NetLabel Audit Functions */
|
||||
|
||||
struct audit_buffer *netlbl_audit_start_common(int type,
|
||||
struct netlbl_audit *audit_info);
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue