Creation of Cybook 2416 (actually Gen4) repository
This commit is contained in:
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.
|
||||
16
net/netlabel/Makefile
Normal file
16
net/netlabel/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# Makefile for the NetLabel subsystem.
|
||||
#
|
||||
# Feb 9, 2006, Paul Moore <paul.moore@hp.com>
|
||||
#
|
||||
|
||||
# base objects
|
||||
obj-y := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o
|
||||
|
||||
# management objects
|
||||
obj-y += netlabel_mgmt.o
|
||||
|
||||
# protocol modules
|
||||
obj-y += netlabel_unlabeled.o
|
||||
obj-y += netlabel_cipso_v4.o
|
||||
|
||||
785
net/netlabel/netlabel_cipso_v4.c
Normal file
785
net/netlabel/netlabel_cipso_v4.c
Normal file
@@ -0,0 +1,785 @@
|
||||
/*
|
||||
* 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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/audit.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
|
||||
#include "netlabel_user.h"
|
||||
#include "netlabel_cipso_v4.h"
|
||||
|
||||
/* Argument struct for cipso_v4_doi_walk() */
|
||||
struct netlbl_cipsov4_doiwalk_arg {
|
||||
struct netlink_callback *nl_cb;
|
||||
struct sk_buff *skb;
|
||||
u32 seq;
|
||||
};
|
||||
|
||||
/* 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 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_doi_free - Frees a CIPSO V4 DOI definition
|
||||
* @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 the DOI definition can be released
|
||||
* safely.
|
||||
*
|
||||
*/
|
||||
static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
|
||||
{
|
||||
struct cipso_v4_doi *ptr;
|
||||
|
||||
ptr = container_of(entry, struct cipso_v4_doi, rcu);
|
||||
switch (ptr->type) {
|
||||
case CIPSO_V4_MAP_STD:
|
||||
kfree(ptr->map.std->lvl.cipso);
|
||||
kfree(ptr->map.std->lvl.local);
|
||||
kfree(ptr->map.std->cat.cipso);
|
||||
kfree(ptr->map.std->cat.local);
|
||||
break;
|
||||
}
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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->nla_type == 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
|
||||
*
|
||||
* Description:
|
||||
* Create a new CIPSO_V4_MAP_STD 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)
|
||||
{
|
||||
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_STD;
|
||||
|
||||
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_a->nla_type == 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_b->nla_type) {
|
||||
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_a->nla_type == 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_a->nla_type == 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_b->nla_type) {
|
||||
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_a->nla_type == 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);
|
||||
if (ret_val != 0)
|
||||
goto add_std_failure;
|
||||
return 0;
|
||||
|
||||
add_std_failure:
|
||||
if (doi_def)
|
||||
netlbl_cipsov4_doi_free(&doi_def->rcu);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
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);
|
||||
if (ret_val != 0)
|
||||
goto add_pass_failure;
|
||||
return 0;
|
||||
|
||||
add_pass_failure:
|
||||
netlbl_cipsov4_doi_free(&doi_def->rcu);
|
||||
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;
|
||||
u32 type;
|
||||
u32 doi;
|
||||
const char *type_str = "(unknown)";
|
||||
struct audit_buffer *audit_buf;
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
|
||||
!info->attrs[NLBL_CIPSOV4_A_MTYPE])
|
||||
return -EINVAL;
|
||||
|
||||
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
|
||||
switch (type) {
|
||||
case CIPSO_V4_MAP_STD:
|
||||
type_str = "std";
|
||||
ret_val = netlbl_cipsov4_add_std(info);
|
||||
break;
|
||||
case CIPSO_V4_MAP_PASS:
|
||||
type_str = "pass";
|
||||
ret_val = netlbl_cipsov4_add_pass(info);
|
||||
break;
|
||||
}
|
||||
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
|
||||
&audit_info);
|
||||
if (audit_buf != NULL) {
|
||||
audit_log_format(audit_buf,
|
||||
" cipso_doi=%u cipso_type=%s res=%u",
|
||||
doi,
|
||||
type_str,
|
||||
ret_val == 0 ? 1 : 0);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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_STD:
|
||||
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);
|
||||
|
||||
ret_val = genlmsg_reply(ans_skb, info);
|
||||
if (ret_val != 0)
|
||||
goto list_failure;
|
||||
|
||||
return 0;
|
||||
|
||||
list_retry:
|
||||
/* XXX - this limit is a guesstimate */
|
||||
if (nlsze_mult < 4) {
|
||||
rcu_read_unlock();
|
||||
kfree_skb(ans_skb);
|
||||
nlsze_mult++;
|
||||
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).pid,
|
||||
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;
|
||||
int 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 - 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;
|
||||
u32 doi = 0;
|
||||
struct audit_buffer *audit_buf;
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
if (!info->attrs[NLBL_CIPSOV4_A_DOI])
|
||||
return -EINVAL;
|
||||
|
||||
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
ret_val = cipso_v4_doi_remove(doi,
|
||||
&audit_info,
|
||||
netlbl_cipsov4_doi_free);
|
||||
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
|
||||
&audit_info);
|
||||
if (audit_buf != NULL) {
|
||||
audit_log_format(audit_buf,
|
||||
" cipso_doi=%u res=%u",
|
||||
doi,
|
||||
ret_val == 0 ? 1 : 0);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* NetLabel Generic NETLINK Command Definitions
|
||||
*/
|
||||
|
||||
static struct genl_ops netlbl_cipsov4_genl_c_add = {
|
||||
.cmd = NLBL_CIPSOV4_C_ADD,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_cipsov4_genl_policy,
|
||||
.doit = netlbl_cipsov4_add,
|
||||
.dumpit = NULL,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_cipsov4_genl_c_remove = {
|
||||
.cmd = NLBL_CIPSOV4_C_REMOVE,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_cipsov4_genl_policy,
|
||||
.doit = netlbl_cipsov4_remove,
|
||||
.dumpit = NULL,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_cipsov4_genl_c_list = {
|
||||
.cmd = NLBL_CIPSOV4_C_LIST,
|
||||
.flags = 0,
|
||||
.policy = netlbl_cipsov4_genl_policy,
|
||||
.doit = netlbl_cipsov4_list,
|
||||
.dumpit = NULL,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_cipsov4_genl_c_listall = {
|
||||
.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 netlbl_cipsov4_genl_init(void)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
ret_val = genl_register_family(&netlbl_cipsov4_gnl_family);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
|
||||
&netlbl_cipsov4_genl_c_add);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
|
||||
&netlbl_cipsov4_genl_c_remove);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
|
||||
&netlbl_cipsov4_genl_c_list);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = genl_register_ops(&netlbl_cipsov4_gnl_family,
|
||||
&netlbl_cipsov4_genl_c_listall);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
166
net/netlabel/netlabel_cipso_v4.h
Normal file
166
net/netlabel/netlabel_cipso_v4.h
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#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_STD the following attributes are required:
|
||||
*
|
||||
* NLBL_CIPSOV4_A_MLSLVLLST
|
||||
* NLBL_CIPSOV4_A_MLSCATLST
|
||||
*
|
||||
* If using CIPSO_V4_MAP_PASS 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_STD the following attributes are required:
|
||||
*
|
||||
* NLBL_CIPSOV4_A_MLSLVLLST
|
||||
* NLBL_CIPSOV4_A_MLSCATLST
|
||||
*
|
||||
* If using CIPSO_V4_MAP_PASS 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,
|
||||
};
|
||||
#define NLBL_CIPSOV4_C_MAX (__NLBL_CIPSOV4_C_MAX - 1)
|
||||
|
||||
/* 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);
|
||||
|
||||
#endif
|
||||
444
net/netlabel/netlabel_domainhash.c
Normal file
444
net/netlabel/netlabel_domainhash.c
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* 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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/audit.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
#include "netlabel_mgmt.h"
|
||||
#include "netlabel_domainhash.h"
|
||||
#include "netlabel_user.h"
|
||||
|
||||
struct netlbl_domhsh_tbl {
|
||||
struct list_head *tbl;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
/* Domain hash table */
|
||||
/* XXX - updates should be so rare that having one spinlock for the entire
|
||||
* hash table should be okay */
|
||||
static DEFINE_SPINLOCK(netlbl_domhsh_lock);
|
||||
static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
|
||||
|
||||
/* Default domain mapping */
|
||||
static DEFINE_SPINLOCK(netlbl_domhsh_def_lock);
|
||||
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;
|
||||
|
||||
ptr = container_of(entry, struct netlbl_dom_map, rcu);
|
||||
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 responsibile for
|
||||
* calling the rcu_read_[un]lock() functions.
|
||||
*
|
||||
*/
|
||||
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 & (rcu_dereference(netlbl_domhsh)->size - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_domhsh_search - 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 found, otherwise NULL is returned. If @def is non-zero and a
|
||||
* match is not found in the domain hash table the default mapping is returned
|
||||
* if it exists. The caller is responsibile for the rcu hash table locks
|
||||
* (i.e. the caller much call rcu_read_[un]lock()).
|
||||
*
|
||||
*/
|
||||
static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain, u32 def)
|
||||
{
|
||||
u32 bkt;
|
||||
struct netlbl_dom_map *iter;
|
||||
|
||||
if (domain != NULL) {
|
||||
bkt = netlbl_domhsh_hash(domain);
|
||||
list_for_each_entry_rcu(iter, &netlbl_domhsh->tbl[bkt], list)
|
||||
if (iter->valid && strcmp(iter->domain, domain) == 0)
|
||||
return iter;
|
||||
}
|
||||
|
||||
if (def != 0) {
|
||||
iter = rcu_dereference(netlbl_domhsh_def);
|
||||
if (iter != NULL && iter->valid)
|
||||
return iter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 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]);
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
rcu_read_unlock();
|
||||
|
||||
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;
|
||||
u32 bkt;
|
||||
struct audit_buffer *audit_buf;
|
||||
|
||||
switch (entry->type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
ret_val = 0;
|
||||
break;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4,
|
||||
entry->domain);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
entry->valid = 1;
|
||||
INIT_RCU_HEAD(&entry->rcu);
|
||||
|
||||
ret_val = 0;
|
||||
rcu_read_lock();
|
||||
if (entry->domain != NULL) {
|
||||
bkt = netlbl_domhsh_hash(entry->domain);
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
if (netlbl_domhsh_search(entry->domain, 0) == NULL)
|
||||
list_add_tail_rcu(&entry->list,
|
||||
&netlbl_domhsh->tbl[bkt]);
|
||||
else
|
||||
ret_val = -EEXIST;
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
} else if (entry->domain == NULL) {
|
||||
INIT_LIST_HEAD(&entry->list);
|
||||
spin_lock(&netlbl_domhsh_def_lock);
|
||||
if (rcu_dereference(netlbl_domhsh_def) == NULL)
|
||||
rcu_assign_pointer(netlbl_domhsh_def, entry);
|
||||
else
|
||||
ret_val = -EEXIST;
|
||||
spin_unlock(&netlbl_domhsh_def_lock);
|
||||
} else
|
||||
ret_val = -EINVAL;
|
||||
|
||||
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)");
|
||||
switch (entry->type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
audit_log_format(audit_buf, " nlbl_protocol=unlbl");
|
||||
break;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
audit_log_format(audit_buf,
|
||||
" nlbl_protocol=cipsov4 cipso_doi=%u",
|
||||
entry->type_def.cipsov4->doi);
|
||||
break;
|
||||
}
|
||||
audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ret_val != 0) {
|
||||
switch (entry->type) {
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
|
||||
entry->domain) != 0)
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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 - 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 = -ENOENT;
|
||||
struct netlbl_dom_map *entry;
|
||||
struct audit_buffer *audit_buf;
|
||||
|
||||
rcu_read_lock();
|
||||
if (domain != NULL)
|
||||
entry = netlbl_domhsh_search(domain, 0);
|
||||
else
|
||||
entry = netlbl_domhsh_search(domain, 1);
|
||||
if (entry == NULL)
|
||||
goto remove_return;
|
||||
switch (entry->type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
break;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
ret_val = cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
|
||||
entry->domain);
|
||||
if (ret_val != 0)
|
||||
goto remove_return;
|
||||
break;
|
||||
}
|
||||
ret_val = 0;
|
||||
if (entry != rcu_dereference(netlbl_domhsh_def)) {
|
||||
spin_lock(&netlbl_domhsh_lock);
|
||||
if (entry->valid) {
|
||||
entry->valid = 0;
|
||||
list_del_rcu(&entry->list);
|
||||
} else
|
||||
ret_val = -ENOENT;
|
||||
spin_unlock(&netlbl_domhsh_lock);
|
||||
} else {
|
||||
spin_lock(&netlbl_domhsh_def_lock);
|
||||
if (entry->valid) {
|
||||
entry->valid = 0;
|
||||
rcu_assign_pointer(netlbl_domhsh_def, NULL);
|
||||
} else
|
||||
ret_val = -ENOENT;
|
||||
spin_unlock(&netlbl_domhsh_def_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)
|
||||
call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
|
||||
|
||||
remove_return:
|
||||
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 responsibile
|
||||
* for ensuring that rcu_read_[un]lock() is called.
|
||||
*
|
||||
*/
|
||||
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
|
||||
{
|
||||
return netlbl_domhsh_search(domain, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 succcess, 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 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) {
|
||||
list_for_each_entry_rcu(iter_entry,
|
||||
&netlbl_domhsh->tbl[iter_bkt],
|
||||
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;
|
||||
}
|
||||
71
net/netlabel/netlabel_domainhash.h
Normal file
71
net/netlabel/netlabel_domainhash.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETLABEL_DOMAINHASH_H
|
||||
#define _NETLABEL_DOMAINHASH_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
/* Domain hash table size */
|
||||
/* XXX - currently this number is an uneducated guess */
|
||||
#define NETLBL_DOMHSH_BITSIZE 7
|
||||
|
||||
/* Domain mapping definition struct */
|
||||
struct netlbl_dom_map {
|
||||
char *domain;
|
||||
u32 type;
|
||||
union {
|
||||
struct cipso_v4_doi *cipsov4;
|
||||
} type_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_default(struct netlbl_audit *audit_info);
|
||||
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
|
||||
int netlbl_domhsh_walk(u32 *skip_bkt,
|
||||
u32 *skip_chain,
|
||||
int (*callback) (struct netlbl_dom_map *entry, void *arg),
|
||||
void *cb_arg);
|
||||
|
||||
#endif
|
||||
456
net/netlabel/netlabel_kapi.c
Normal file
456
net/netlabel/netlabel_kapi.c
Normal file
@@ -0,0 +1,456 @@
|
||||
/*
|
||||
* NetLabel Kernel API
|
||||
*
|
||||
* This file defines the kernel API 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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
#include "netlabel_domainhash.h"
|
||||
#include "netlabel_unlabeled.h"
|
||||
#include "netlabel_user.h"
|
||||
|
||||
/*
|
||||
* Security Attribute Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_secattr_catmap_walk - Walk a LSM secattr catmap looking for a bit
|
||||
* @catmap: the category bitmap
|
||||
* @offset: the offset to start searching at, in bits
|
||||
*
|
||||
* Description:
|
||||
* This function walks a LSM secattr category bitmap starting at @offset and
|
||||
* returns the spot of the first set bit or -ENOENT if no bits are set.
|
||||
*
|
||||
*/
|
||||
int netlbl_secattr_catmap_walk(struct netlbl_lsm_secattr_catmap *catmap,
|
||||
u32 offset)
|
||||
{
|
||||
struct netlbl_lsm_secattr_catmap *iter = catmap;
|
||||
u32 node_idx;
|
||||
u32 node_bit;
|
||||
NETLBL_CATMAP_MAPTYPE bitmap;
|
||||
|
||||
if (offset > iter->startbit) {
|
||||
while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
|
||||
iter = iter->next;
|
||||
if (iter == NULL)
|
||||
return -ENOENT;
|
||||
}
|
||||
node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
|
||||
node_bit = offset - iter->startbit -
|
||||
(NETLBL_CATMAP_MAPSIZE * node_idx);
|
||||
} else {
|
||||
node_idx = 0;
|
||||
node_bit = 0;
|
||||
}
|
||||
bitmap = iter->bitmap[node_idx] >> node_bit;
|
||||
|
||||
for (;;) {
|
||||
if (bitmap != 0) {
|
||||
while ((bitmap & NETLBL_CATMAP_BIT) == 0) {
|
||||
bitmap >>= 1;
|
||||
node_bit++;
|
||||
}
|
||||
return iter->startbit +
|
||||
(NETLBL_CATMAP_MAPSIZE * node_idx) + node_bit;
|
||||
}
|
||||
if (++node_idx >= NETLBL_CATMAP_MAPCNT) {
|
||||
if (iter->next != NULL) {
|
||||
iter = iter->next;
|
||||
node_idx = 0;
|
||||
} else
|
||||
return -ENOENT;
|
||||
}
|
||||
bitmap = iter->bitmap[node_idx];
|
||||
node_bit = 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_secattr_catmap_walk_rng - Find the end of a string of set bits
|
||||
* @catmap: the category bitmap
|
||||
* @offset: the offset to start searching at, in bits
|
||||
*
|
||||
* Description:
|
||||
* This function walks a LSM secattr category bitmap starting at @offset and
|
||||
* returns the spot of the first cleared bit or -ENOENT if the offset is past
|
||||
* the end of the bitmap.
|
||||
*
|
||||
*/
|
||||
int netlbl_secattr_catmap_walk_rng(struct netlbl_lsm_secattr_catmap *catmap,
|
||||
u32 offset)
|
||||
{
|
||||
struct netlbl_lsm_secattr_catmap *iter = catmap;
|
||||
u32 node_idx;
|
||||
u32 node_bit;
|
||||
NETLBL_CATMAP_MAPTYPE bitmask;
|
||||
NETLBL_CATMAP_MAPTYPE bitmap;
|
||||
|
||||
if (offset > iter->startbit) {
|
||||
while (offset >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
|
||||
iter = iter->next;
|
||||
if (iter == NULL)
|
||||
return -ENOENT;
|
||||
}
|
||||
node_idx = (offset - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
|
||||
node_bit = offset - iter->startbit -
|
||||
(NETLBL_CATMAP_MAPSIZE * node_idx);
|
||||
} else {
|
||||
node_idx = 0;
|
||||
node_bit = 0;
|
||||
}
|
||||
bitmask = NETLBL_CATMAP_BIT << node_bit;
|
||||
|
||||
for (;;) {
|
||||
bitmap = iter->bitmap[node_idx];
|
||||
while (bitmask != 0 && (bitmap & bitmask) != 0) {
|
||||
bitmask <<= 1;
|
||||
node_bit++;
|
||||
}
|
||||
|
||||
if (bitmask != 0)
|
||||
return iter->startbit +
|
||||
(NETLBL_CATMAP_MAPSIZE * node_idx) +
|
||||
node_bit - 1;
|
||||
else if (++node_idx >= NETLBL_CATMAP_MAPCNT) {
|
||||
if (iter->next == NULL)
|
||||
return iter->startbit + NETLBL_CATMAP_SIZE - 1;
|
||||
iter = iter->next;
|
||||
node_idx = 0;
|
||||
}
|
||||
bitmask = NETLBL_CATMAP_BIT;
|
||||
node_bit = 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_secattr_catmap_setbit - Set a bit in a LSM secattr catmap
|
||||
* @catmap: the category bitmap
|
||||
* @bit: the bit to set
|
||||
* @flags: memory allocation flags
|
||||
*
|
||||
* Description:
|
||||
* Set the bit specified by @bit in @catmap. Returns zero on success,
|
||||
* negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_secattr_catmap_setbit(struct netlbl_lsm_secattr_catmap *catmap,
|
||||
u32 bit,
|
||||
gfp_t flags)
|
||||
{
|
||||
struct netlbl_lsm_secattr_catmap *iter = catmap;
|
||||
u32 node_bit;
|
||||
u32 node_idx;
|
||||
|
||||
while (iter->next != NULL &&
|
||||
bit >= (iter->startbit + NETLBL_CATMAP_SIZE))
|
||||
iter = iter->next;
|
||||
if (bit >= (iter->startbit + NETLBL_CATMAP_SIZE)) {
|
||||
iter->next = netlbl_secattr_catmap_alloc(flags);
|
||||
if (iter->next == NULL)
|
||||
return -ENOMEM;
|
||||
iter = iter->next;
|
||||
iter->startbit = bit & ~(NETLBL_CATMAP_SIZE - 1);
|
||||
}
|
||||
|
||||
/* gcc always rounds to zero when doing integer division */
|
||||
node_idx = (bit - iter->startbit) / NETLBL_CATMAP_MAPSIZE;
|
||||
node_bit = bit - iter->startbit - (NETLBL_CATMAP_MAPSIZE * node_idx);
|
||||
iter->bitmap[node_idx] |= NETLBL_CATMAP_BIT << node_bit;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_secattr_catmap_setrng - Set a range of bits in a LSM secattr catmap
|
||||
* @catmap: the category bitmap
|
||||
* @start: the starting bit
|
||||
* @end: the last bit in the string
|
||||
* @flags: memory allocation flags
|
||||
*
|
||||
* Description:
|
||||
* Set a range of bits, starting at @start and ending with @end. Returns zero
|
||||
* on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
|
||||
u32 start,
|
||||
u32 end,
|
||||
gfp_t flags)
|
||||
{
|
||||
int ret_val = 0;
|
||||
struct netlbl_lsm_secattr_catmap *iter = catmap;
|
||||
u32 iter_max_spot;
|
||||
u32 spot;
|
||||
|
||||
/* XXX - This could probably be made a bit faster by combining writes
|
||||
* to the catmap instead of setting a single bit each time, but for
|
||||
* right now skipping to the start of the range in the catmap should
|
||||
* be a nice improvement over calling the individual setbit function
|
||||
* repeatedly from a loop. */
|
||||
|
||||
while (iter->next != NULL &&
|
||||
start >= (iter->startbit + NETLBL_CATMAP_SIZE))
|
||||
iter = iter->next;
|
||||
iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
|
||||
|
||||
for (spot = start; spot <= end && ret_val == 0; spot++) {
|
||||
if (spot >= iter_max_spot && iter->next != NULL) {
|
||||
iter = iter->next;
|
||||
iter_max_spot = iter->startbit + NETLBL_CATMAP_SIZE;
|
||||
}
|
||||
ret_val = netlbl_secattr_catmap_setbit(iter, spot, GFP_ATOMIC);
|
||||
}
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/*
|
||||
* LSM Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_socket_setattr - Label a socket using the correct protocol
|
||||
* @sock: the socket to label
|
||||
* @secattr: the security attributes
|
||||
*
|
||||
* Description:
|
||||
* Attach the correct label to the given socket using the security attributes
|
||||
* specified in @secattr. This function requires exclusive access to
|
||||
* @sock->sk, which means it either needs to be in the process of being
|
||||
* created or locked via lock_sock(sock->sk). Returns zero on success,
|
||||
* negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_socket_setattr(const struct socket *sock,
|
||||
const struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
int ret_val = -ENOENT;
|
||||
struct netlbl_dom_map *dom_entry;
|
||||
|
||||
if ((secattr->flags & NETLBL_SECATTR_DOMAIN) == 0)
|
||||
return -ENOENT;
|
||||
|
||||
rcu_read_lock();
|
||||
dom_entry = netlbl_domhsh_getentry(secattr->domain);
|
||||
if (dom_entry == NULL)
|
||||
goto socket_setattr_return;
|
||||
switch (dom_entry->type) {
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
ret_val = cipso_v4_socket_setattr(sock,
|
||||
dom_entry->type_def.cipsov4,
|
||||
secattr);
|
||||
break;
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
ret_val = 0;
|
||||
break;
|
||||
default:
|
||||
ret_val = -ENOENT;
|
||||
}
|
||||
|
||||
socket_setattr_return:
|
||||
rcu_read_unlock();
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_sock_getattr - Determine the security attributes of a sock
|
||||
* @sk: the sock
|
||||
* @secattr: the security attributes
|
||||
*
|
||||
* Description:
|
||||
* Examines the given sock to see any NetLabel style labeling has been
|
||||
* applied to the sock, if so it parses the socket label and returns the
|
||||
* security attributes in @secattr. Returns zero on success, negative values
|
||||
* on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
ret_val = cipso_v4_sock_getattr(sk, secattr);
|
||||
if (ret_val == 0)
|
||||
return 0;
|
||||
|
||||
return netlbl_unlabel_getattr(secattr);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_socket_getattr - Determine the security attributes of a socket
|
||||
* @sock: the socket
|
||||
* @secattr: the security attributes
|
||||
*
|
||||
* Description:
|
||||
* Examines the given socket to see any NetLabel style labeling has been
|
||||
* applied to the socket, if so it parses the socket label and returns the
|
||||
* security attributes in @secattr. Returns zero on success, negative values
|
||||
* on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_socket_getattr(const struct socket *sock,
|
||||
struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
ret_val = cipso_v4_socket_getattr(sock, secattr);
|
||||
if (ret_val == 0)
|
||||
return 0;
|
||||
|
||||
return netlbl_unlabel_getattr(secattr);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_skbuff_getattr - Determine the security attributes of a packet
|
||||
* @skb: the packet
|
||||
* @secattr: the security attributes
|
||||
*
|
||||
* Description:
|
||||
* Examines the given packet to see if a recognized form of packet labeling
|
||||
* is present, if so it parses the packet label and returns the security
|
||||
* attributes in @secattr. Returns zero on success, negative values on
|
||||
* failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_skbuff_getattr(const struct sk_buff *skb,
|
||||
struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
if (CIPSO_V4_OPTEXIST(skb) &&
|
||||
cipso_v4_skbuff_getattr(skb, secattr) == 0)
|
||||
return 0;
|
||||
|
||||
return netlbl_unlabel_getattr(secattr);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_skbuff_err - Handle a LSM error on a sk_buff
|
||||
* @skb: the packet
|
||||
* @error: the error code
|
||||
*
|
||||
* Description:
|
||||
* Deal with a LSM problem when handling the packet in @skb, typically this is
|
||||
* a permission denied problem (-EACCES). The correct action is determined
|
||||
* according to the packet's labeling protocol.
|
||||
*
|
||||
*/
|
||||
void netlbl_skbuff_err(struct sk_buff *skb, int error)
|
||||
{
|
||||
if (CIPSO_V4_OPTEXIST(skb))
|
||||
cipso_v4_error(skb, error, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches
|
||||
*
|
||||
* Description:
|
||||
* For all of the NetLabel protocols that support some form of label mapping
|
||||
* cache, invalidate the cache. Returns zero on success, negative values on
|
||||
* error.
|
||||
*
|
||||
*/
|
||||
void netlbl_cache_invalidate(void)
|
||||
{
|
||||
cipso_v4_cache_invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_cache_add - Add an entry to a NetLabel protocol cache
|
||||
* @skb: the packet
|
||||
* @secattr: the packet's security attributes
|
||||
*
|
||||
* Description:
|
||||
* Add the LSM security attributes for the given packet to the underlying
|
||||
* NetLabel protocol's label mapping cache. Returns zero on success, negative
|
||||
* values on error.
|
||||
*
|
||||
*/
|
||||
int netlbl_cache_add(const struct sk_buff *skb,
|
||||
const struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
if ((secattr->flags & NETLBL_SECATTR_CACHE) == 0)
|
||||
return -ENOMSG;
|
||||
|
||||
if (CIPSO_V4_OPTEXIST(skb))
|
||||
return cipso_v4_cache_add(skb, secattr);
|
||||
|
||||
return -ENOMSG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_init - Initialize NetLabel
|
||||
*
|
||||
* Description:
|
||||
* Perform the required NetLabel initialization before first use.
|
||||
*
|
||||
*/
|
||||
static int __init netlbl_init(void)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
printk(KERN_INFO "NetLabel: Initializing\n");
|
||||
printk(KERN_INFO "NetLabel: domain hash size = %u\n",
|
||||
(1 << NETLBL_DOMHSH_BITSIZE));
|
||||
printk(KERN_INFO "NetLabel: protocols ="
|
||||
" UNLABELED"
|
||||
" CIPSOv4"
|
||||
"\n");
|
||||
|
||||
ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE);
|
||||
if (ret_val != 0)
|
||||
goto init_failure;
|
||||
|
||||
ret_val = netlbl_netlink_init();
|
||||
if (ret_val != 0)
|
||||
goto init_failure;
|
||||
|
||||
ret_val = netlbl_unlabel_defconf();
|
||||
if (ret_val != 0)
|
||||
goto init_failure;
|
||||
printk(KERN_INFO "NetLabel: unlabeled traffic allowed by default\n");
|
||||
|
||||
return 0;
|
||||
|
||||
init_failure:
|
||||
panic("NetLabel: failed to initialize properly (%d)\n", ret_val);
|
||||
}
|
||||
|
||||
subsys_initcall(netlbl_init);
|
||||
634
net/netlabel/netlabel_mgmt.c
Normal file
634
net/netlabel/netlabel_mgmt.c
Normal file
@@ -0,0 +1,634 @@
|
||||
/*
|
||||
* 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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <net/netlabel.h>
|
||||
#include <net/cipso_ipv4.h>
|
||||
|
||||
#include "netlabel_domainhash.h"
|
||||
#include "netlabel_user.h"
|
||||
#include "netlabel_mgmt.h"
|
||||
|
||||
/* 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 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 },
|
||||
};
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
struct netlbl_dom_map *entry = NULL;
|
||||
size_t tmp_size;
|
||||
u32 tmp_val;
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
|
||||
!info->attrs[NLBL_MGMT_A_PROTOCOL])
|
||||
goto add_failure;
|
||||
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (entry == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto add_failure;
|
||||
}
|
||||
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;
|
||||
}
|
||||
entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
|
||||
nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
|
||||
|
||||
switch (entry->type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
ret_val = netlbl_domhsh_add(entry, &audit_info);
|
||||
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]);
|
||||
/* We should be holding a rcu_read_lock() here while we hold
|
||||
* the result but since the entry will always be deleted when
|
||||
* the CIPSO DOI is deleted we aren't going to keep the
|
||||
* lock. */
|
||||
rcu_read_lock();
|
||||
entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
|
||||
if (entry->type_def.cipsov4 == NULL) {
|
||||
rcu_read_unlock();
|
||||
goto add_failure;
|
||||
}
|
||||
ret_val = netlbl_domhsh_add(entry, &audit_info);
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
default:
|
||||
goto add_failure;
|
||||
}
|
||||
if (ret_val != 0)
|
||||
goto add_failure;
|
||||
|
||||
return 0;
|
||||
|
||||
add_failure:
|
||||
if (entry)
|
||||
kfree(entry->domain);
|
||||
kfree(entry);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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).pid,
|
||||
cb_arg->seq, &netlbl_mgmt_gnl_family,
|
||||
NLM_F_MULTI, NLBL_MGMT_C_LISTALL);
|
||||
if (data == NULL)
|
||||
goto listall_cb_failure;
|
||||
|
||||
ret_val = nla_put_string(cb_arg->skb,
|
||||
NLBL_MGMT_A_DOMAIN,
|
||||
entry->domain);
|
||||
if (ret_val != 0)
|
||||
goto listall_cb_failure;
|
||||
ret_val = nla_put_u32(cb_arg->skb, NLBL_MGMT_A_PROTOCOL, entry->type);
|
||||
if (ret_val != 0)
|
||||
goto listall_cb_failure;
|
||||
switch (entry->type) {
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
ret_val = nla_put_u32(cb_arg->skb,
|
||||
NLBL_MGMT_A_CV4DOI,
|
||||
entry->type_def.cipsov4->doi);
|
||||
if (ret_val != 0)
|
||||
goto listall_cb_failure;
|
||||
break;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
struct netlbl_dom_map *entry = NULL;
|
||||
u32 tmp_val;
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
|
||||
goto adddef_failure;
|
||||
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (entry == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto adddef_failure;
|
||||
}
|
||||
entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
|
||||
|
||||
switch (entry->type) {
|
||||
case NETLBL_NLTYPE_UNLABELED:
|
||||
ret_val = netlbl_domhsh_add_default(entry, &audit_info);
|
||||
break;
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
|
||||
goto adddef_failure;
|
||||
|
||||
tmp_val = nla_get_u32(info->attrs[NLBL_MGMT_A_CV4DOI]);
|
||||
/* We should be holding a rcu_read_lock() here while we hold
|
||||
* the result but since the entry will always be deleted when
|
||||
* the CIPSO DOI is deleted we aren't going to keep the
|
||||
* lock. */
|
||||
rcu_read_lock();
|
||||
entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
|
||||
if (entry->type_def.cipsov4 == NULL) {
|
||||
rcu_read_unlock();
|
||||
goto adddef_failure;
|
||||
}
|
||||
ret_val = netlbl_domhsh_add_default(entry, &audit_info);
|
||||
rcu_read_unlock();
|
||||
break;
|
||||
default:
|
||||
goto adddef_failure;
|
||||
}
|
||||
if (ret_val != 0)
|
||||
goto adddef_failure;
|
||||
|
||||
return 0;
|
||||
|
||||
adddef_failure:
|
||||
kfree(entry);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = nla_put_u32(ans_skb, NLBL_MGMT_A_PROTOCOL, entry->type);
|
||||
if (ret_val != 0)
|
||||
goto listdef_failure_lock;
|
||||
switch (entry->type) {
|
||||
case NETLBL_NLTYPE_CIPSOV4:
|
||||
ret_val = nla_put_u32(ans_skb,
|
||||
NLBL_MGMT_A_CV4DOI,
|
||||
entry->type_def.cipsov4->doi);
|
||||
if (ret_val != 0)
|
||||
goto listdef_failure_lock;
|
||||
break;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
genlmsg_end(ans_skb, data);
|
||||
|
||||
ret_val = genlmsg_reply(ans_skb, info);
|
||||
if (ret_val != 0)
|
||||
goto listdef_failure;
|
||||
return 0;
|
||||
|
||||
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
|
||||
* @seq: the NETLINK sequence number
|
||||
* @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).pid, 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);
|
||||
|
||||
ret_val = genlmsg_reply(ans_skb, info);
|
||||
if (ret_val != 0)
|
||||
goto version_failure;
|
||||
return 0;
|
||||
|
||||
version_failure:
|
||||
kfree_skb(ans_skb);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NetLabel Generic NETLINK Command Definitions
|
||||
*/
|
||||
|
||||
static struct genl_ops netlbl_mgmt_genl_c_add = {
|
||||
.cmd = NLBL_MGMT_C_ADD,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_add,
|
||||
.dumpit = NULL,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_mgmt_genl_c_remove = {
|
||||
.cmd = NLBL_MGMT_C_REMOVE,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_remove,
|
||||
.dumpit = NULL,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_mgmt_genl_c_listall = {
|
||||
.cmd = NLBL_MGMT_C_LISTALL,
|
||||
.flags = 0,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = NULL,
|
||||
.dumpit = netlbl_mgmt_listall,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_mgmt_genl_c_adddef = {
|
||||
.cmd = NLBL_MGMT_C_ADDDEF,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_adddef,
|
||||
.dumpit = NULL,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_mgmt_genl_c_removedef = {
|
||||
.cmd = NLBL_MGMT_C_REMOVEDEF,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_removedef,
|
||||
.dumpit = NULL,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_mgmt_genl_c_listdef = {
|
||||
.cmd = NLBL_MGMT_C_LISTDEF,
|
||||
.flags = 0,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = netlbl_mgmt_listdef,
|
||||
.dumpit = NULL,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_mgmt_genl_c_protocols = {
|
||||
.cmd = NLBL_MGMT_C_PROTOCOLS,
|
||||
.flags = 0,
|
||||
.policy = netlbl_mgmt_genl_policy,
|
||||
.doit = NULL,
|
||||
.dumpit = netlbl_mgmt_protocols,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_mgmt_genl_c_version = {
|
||||
.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 netlbl_mgmt_genl_init(void)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
ret_val = genl_register_family(&netlbl_mgmt_gnl_family);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
|
||||
&netlbl_mgmt_genl_c_add);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
|
||||
&netlbl_mgmt_genl_c_remove);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
|
||||
&netlbl_mgmt_genl_c_listall);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
|
||||
&netlbl_mgmt_genl_c_adddef);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
|
||||
&netlbl_mgmt_genl_c_removedef);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
|
||||
&netlbl_mgmt_genl_c_listdef);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
|
||||
&netlbl_mgmt_genl_c_protocols);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
|
||||
&netlbl_mgmt_genl_c_version);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
171
net/netlabel/netlabel_mgmt.h
Normal file
171
net/netlabel/netlabel_mgmt.h
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* 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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETLABEL_MGMT_H
|
||||
#define _NETLABEL_MGMT_H
|
||||
|
||||
#include <net/netlabel.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 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
|
||||
* 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 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.
|
||||
*
|
||||
* 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 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,
|
||||
};
|
||||
#define NLBL_MGMT_C_MAX (__NLBL_MGMT_C_MAX - 1)
|
||||
|
||||
/* 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_MAX,
|
||||
};
|
||||
#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
|
||||
|
||||
/* NetLabel protocol functions */
|
||||
int netlbl_mgmt_genl_init(void);
|
||||
|
||||
#endif
|
||||
294
net/netlabel/netlabel_unlabeled.c
Normal file
294
net/netlabel/netlabel_unlabeled.c
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* 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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/audit.h>
|
||||
#include <net/sock.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include <net/netlabel.h>
|
||||
#include <asm/bug.h>
|
||||
|
||||
#include "netlabel_user.h"
|
||||
#include "netlabel_domainhash.h"
|
||||
#include "netlabel_unlabeled.h"
|
||||
|
||||
/* Accept unlabeled packets flag */
|
||||
static DEFINE_SPINLOCK(netlabel_unlabel_acceptflg_lock);
|
||||
static u8 netlabel_unlabel_acceptflg = 0;
|
||||
|
||||
/* NetLabel Generic NETLINK CIPSOv4 family */
|
||||
static struct genl_family netlbl_unlabel_gnl_family = {
|
||||
.id = GENL_ID_GENERATE,
|
||||
.hdrsize = 0,
|
||||
.name = NETLBL_NLTYPE_UNLABELED_NAME,
|
||||
.version = NETLBL_PROTO_VERSION,
|
||||
.maxattr = NLBL_UNLABEL_A_MAX,
|
||||
};
|
||||
|
||||
/* NetLabel Netlink attribute policy */
|
||||
static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
|
||||
[NLBL_UNLABEL_A_ACPTFLG] = { .type = NLA_U8 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Helper Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag
|
||||
* @value: desired value
|
||||
* @audit_info: NetLabel audit information
|
||||
*
|
||||
* Description:
|
||||
* Set the value of the unlabeled accept flag to @value.
|
||||
*
|
||||
*/
|
||||
static void netlbl_unlabel_acceptflg_set(u8 value,
|
||||
struct netlbl_audit *audit_info)
|
||||
{
|
||||
struct audit_buffer *audit_buf;
|
||||
u8 old_val;
|
||||
|
||||
rcu_read_lock();
|
||||
old_val = netlabel_unlabel_acceptflg;
|
||||
spin_lock(&netlabel_unlabel_acceptflg_lock);
|
||||
netlabel_unlabel_acceptflg = value;
|
||||
spin_unlock(&netlabel_unlabel_acceptflg_lock);
|
||||
rcu_read_unlock();
|
||||
|
||||
audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW,
|
||||
audit_info);
|
||||
if (audit_buf != NULL) {
|
||||
audit_log_format(audit_buf,
|
||||
" unlbl_accept=%u old=%u", value, old_val);
|
||||
audit_log_end(audit_buf);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* NetLabel Command Handlers
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_unlabel_accept - Handle an ACCEPT message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated ACCEPT message and set the accept flag accordingly.
|
||||
* Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
u8 value;
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
|
||||
value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
|
||||
if (value == 1 || value == 0) {
|
||||
netlbl_netlink_auditinfo(skb, &audit_info);
|
||||
netlbl_unlabel_acceptflg_set(value, &audit_info);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_unlabel_list - Handle a LIST message
|
||||
* @skb: the NETLINK buffer
|
||||
* @info: the Generic NETLINK info block
|
||||
*
|
||||
* Description:
|
||||
* Process a user generated LIST message and respond with the current status.
|
||||
* Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int ret_val = -EINVAL;
|
||||
struct sk_buff *ans_skb;
|
||||
void *data;
|
||||
|
||||
ans_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (ans_skb == NULL)
|
||||
goto list_failure;
|
||||
data = genlmsg_put_reply(ans_skb, info, &netlbl_unlabel_gnl_family,
|
||||
0, NLBL_UNLABEL_C_LIST);
|
||||
if (data == NULL) {
|
||||
ret_val = -ENOMEM;
|
||||
goto list_failure;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
ret_val = nla_put_u8(ans_skb,
|
||||
NLBL_UNLABEL_A_ACPTFLG,
|
||||
netlabel_unlabel_acceptflg);
|
||||
rcu_read_unlock();
|
||||
if (ret_val != 0)
|
||||
goto list_failure;
|
||||
|
||||
genlmsg_end(ans_skb, data);
|
||||
|
||||
ret_val = genlmsg_reply(ans_skb, info);
|
||||
if (ret_val != 0)
|
||||
goto list_failure;
|
||||
return 0;
|
||||
|
||||
list_failure:
|
||||
kfree_skb(ans_skb);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NetLabel Generic NETLINK Command Definitions
|
||||
*/
|
||||
|
||||
static struct genl_ops netlbl_unlabel_genl_c_accept = {
|
||||
.cmd = NLBL_UNLABEL_C_ACCEPT,
|
||||
.flags = GENL_ADMIN_PERM,
|
||||
.policy = netlbl_unlabel_genl_policy,
|
||||
.doit = netlbl_unlabel_accept,
|
||||
.dumpit = NULL,
|
||||
};
|
||||
|
||||
static struct genl_ops netlbl_unlabel_genl_c_list = {
|
||||
.cmd = NLBL_UNLABEL_C_LIST,
|
||||
.flags = 0,
|
||||
.policy = netlbl_unlabel_genl_policy,
|
||||
.doit = netlbl_unlabel_list,
|
||||
.dumpit = NULL,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* NetLabel Generic NETLINK Protocol Functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_unlabel_genl_init - Register the Unlabeled NetLabel component
|
||||
*
|
||||
* Description:
|
||||
* Register the unlabeled packet NetLabel component with the Generic NETLINK
|
||||
* mechanism. Returns zero on success, negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_unlabel_genl_init(void)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
ret_val = genl_register_family(&netlbl_unlabel_gnl_family);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
|
||||
&netlbl_unlabel_genl_c_accept);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
ret_val = genl_register_ops(&netlbl_unlabel_gnl_family,
|
||||
&netlbl_unlabel_genl_c_list);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NetLabel KAPI Hooks
|
||||
*/
|
||||
|
||||
/**
|
||||
* netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
|
||||
* @secattr: the security attributes
|
||||
*
|
||||
* Description:
|
||||
* Determine the security attributes, if any, for an unlabled packet and return
|
||||
* them in @secattr. Returns zero on success and negative values on failure.
|
||||
*
|
||||
*/
|
||||
int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr)
|
||||
{
|
||||
int ret_val;
|
||||
|
||||
rcu_read_lock();
|
||||
if (netlabel_unlabel_acceptflg == 1) {
|
||||
netlbl_secattr_init(secattr);
|
||||
ret_val = 0;
|
||||
} else
|
||||
ret_val = -ENOMSG;
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
/**
|
||||
* netlbl_unlabel_defconf - Set the default config to allow unlabeled packets
|
||||
*
|
||||
* Description:
|
||||
* Set the default NetLabel configuration to allow incoming unlabeled packets
|
||||
* and to send unlabeled network traffic by default.
|
||||
*
|
||||
*/
|
||||
int netlbl_unlabel_defconf(void)
|
||||
{
|
||||
int ret_val;
|
||||
struct netlbl_dom_map *entry;
|
||||
struct netlbl_audit audit_info;
|
||||
|
||||
/* Only the kernel is allowed to call this function and the only time
|
||||
* it is called is at bootup before the audit subsystem is reporting
|
||||
* messages so don't worry to much about these values. */
|
||||
security_task_getsecid(current, &audit_info.secid);
|
||||
audit_info.loginuid = 0;
|
||||
|
||||
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (entry == NULL)
|
||||
return -ENOMEM;
|
||||
entry->type = NETLBL_NLTYPE_UNLABELED;
|
||||
ret_val = netlbl_domhsh_add_default(entry, &audit_info);
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
netlbl_unlabel_acceptflg_set(1, &audit_info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
89
net/netlabel/netlabel_unlabeled.h
Normal file
89
net/netlabel/netlabel_unlabeled.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NETLABEL_UNLABELED_H
|
||||
#define _NETLABEL_UNLABELED_H
|
||||
|
||||
#include <net/netlabel.h>
|
||||
|
||||
/*
|
||||
* The following NetLabel payloads are supported by the Unlabeled subsystem.
|
||||
*
|
||||
* 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_MAX,
|
||||
};
|
||||
#define NLBL_UNLABEL_C_MAX (__NLBL_UNLABEL_C_MAX - 1)
|
||||
|
||||
/* 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_MAX,
|
||||
};
|
||||
#define NLBL_UNLABEL_A_MAX (__NLBL_UNLABEL_A_MAX - 1)
|
||||
|
||||
/* NetLabel protocol functions */
|
||||
int netlbl_unlabel_genl_init(void);
|
||||
|
||||
/* Process Unlabeled incoming network packets */
|
||||
int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr);
|
||||
|
||||
/* Set the default configuration to allow Unlabeled packets */
|
||||
int netlbl_unlabel_defconf(void);
|
||||
|
||||
#endif
|
||||
124
net/netlabel/netlabel_user.c
Normal file
124
net/netlabel/netlabel_user.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#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 <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"
|
||||
|
||||
/* do not do any auditing if audit_enabled == 0, see kernel/audit.c for
|
||||
* details */
|
||||
extern int audit_enabled;
|
||||
|
||||
/*
|
||||
* 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 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;
|
||||
|
||||
ret_val = netlbl_unlabel_genl_init();
|
||||
if (ret_val != 0)
|
||||
return ret_val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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_context *audit_ctx = current->audit_context;
|
||||
struct audit_buffer *audit_buf;
|
||||
char *secctx;
|
||||
u32 secctx_len;
|
||||
|
||||
if (audit_enabled == 0)
|
||||
return NULL;
|
||||
|
||||
audit_buf = audit_log_start(audit_ctx, GFP_ATOMIC, type);
|
||||
if (audit_buf == NULL)
|
||||
return NULL;
|
||||
|
||||
audit_log_format(audit_buf, "netlabel: auid=%u", audit_info->loginuid);
|
||||
|
||||
if (audit_info->secid != 0 &&
|
||||
security_secid_to_secctx(audit_info->secid,
|
||||
&secctx,
|
||||
&secctx_len) == 0)
|
||||
audit_log_format(audit_buf, " subj=%s", secctx);
|
||||
|
||||
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.moore@hp.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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#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)
|
||||
{
|
||||
audit_info->secid = NETLINK_CB(skb).sid;
|
||||
audit_info->loginuid = NETLINK_CB(skb).loginuid;
|
||||
}
|
||||
|
||||
/* 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
|
||||
Reference in New Issue
Block a user