Commit 7e472020 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [NetLabel]: update docs with website information
  [NetLabel]: rework the Netlink attribute handling (part 2)
  [NetLabel]: rework the Netlink attribute handling (part 1)
  [Netlink]: add nla_validate_nested()
  [NETLINK]: add nla_for_each_nested() to the interface list
  [NetLabel]: change the SELinux permissions
  [NetLabel]: make the CIPSOv4 cache spinlocks bottom half safe
  [NetLabel]: correct improper handling of non-NetLabel peer contexts
  [TCP]: make cubic the default
  [TCP]: default congestion control menu
  [ATM] he: Fix __init/__devinit conflict
  [NETFILTER]: Add dscp,DSCP headers to header-y
  [DCCP]: Introduce dccp_probe
  [DCCP]: Use constants for CCIDs
  [DCCP]: Introduce constants for CCID numbers
  [DCCP]: Allow default/fallback service code.
parents 7b29122f 4cc67735
DCCP protocol
============
Last updated: 10 November 2005
Contents
========
......@@ -42,8 +41,11 @@ Socket options
DCCP_SOCKOPT_PACKET_SIZE is used for CCID3 to set default packet size for
calculations.
DCCP_SOCKOPT_SERVICE sets the service. This is compulsory as per the
specification. If you don't set it you will get EPROTO.
DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
the socket will fall back to 0 (which means that no meaningful service code
is present). Connecting sockets set at most one service option; for
listening sockets, multiple service codes can be specified.
Notes
=====
......
......@@ -2031,6 +2031,13 @@ L: netfilter@lists.netfilter.org
L: netfilter-devel@lists.netfilter.org
S: Supported
NETLABEL
P: Paul Moore
M: paul.moore@hp.com
W: http://netlabel.sf.net
L: netdev@vger.kernel.org
S: Supported
NETROM NETWORK LAYER
P: Ralf Baechle
M: ralf@linux-mips.org
......
......@@ -454,7 +454,7 @@ rate_to_atmf(unsigned rate) /* cps to atm forum format */
return (NONZERO | (exp << 9) | (rate & 0x1ff));
}
static void __init
static void __devinit
he_init_rx_lbfp0(struct he_dev *he_dev)
{
unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
......@@ -485,7 +485,7 @@ he_init_rx_lbfp0(struct he_dev *he_dev)
he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C);
}
static void __init
static void __devinit
he_init_rx_lbfp1(struct he_dev *he_dev)
{
unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
......@@ -516,7 +516,7 @@ he_init_rx_lbfp1(struct he_dev *he_dev)
he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C);
}
static void __init
static void __devinit
he_init_tx_lbfp(struct he_dev *he_dev)
{
unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
......@@ -546,7 +546,7 @@ he_init_tx_lbfp(struct he_dev *he_dev)
he_writel(he_dev, lbufd_index - 1, TLBF_T);
}
static int __init
static int __devinit
he_init_tpdrq(struct he_dev *he_dev)
{
he_dev->tpdrq_base = pci_alloc_consistent(he_dev->pci_dev,
......@@ -568,7 +568,7 @@ he_init_tpdrq(struct he_dev *he_dev)
return 0;
}
static void __init
static void __devinit
he_init_cs_block(struct he_dev *he_dev)
{
unsigned clock, rate, delta;
......@@ -664,7 +664,7 @@ he_init_cs_block(struct he_dev *he_dev)
}
static int __init
static int __devinit
he_init_cs_block_rcm(struct he_dev *he_dev)
{
unsigned (*rategrid)[16][16];
......@@ -785,7 +785,7 @@ he_init_cs_block_rcm(struct he_dev *he_dev)
return 0;
}
static int __init
static int __devinit
he_init_group(struct he_dev *he_dev, int group)
{
int i;
......@@ -955,7 +955,7 @@ he_init_group(struct he_dev *he_dev, int group)
return 0;
}
static int __init
static int __devinit
he_init_irq(struct he_dev *he_dev)
{
int i;
......
......@@ -169,6 +169,12 @@ enum {
DCCPO_MAX_CCID_SPECIFIC = 255,
};
/* DCCP CCIDS */
enum {
DCCPC_CCID2 = 2,
DCCPC_CCID3 = 3,
};
/* DCCP features */
enum {
DCCPF_RESERVED = 0,
......@@ -320,7 +326,7 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb)
/* initial values for each feature */
#define DCCPF_INITIAL_SEQUENCE_WINDOW 100
#define DCCPF_INITIAL_ACK_RATIO 2
#define DCCPF_INITIAL_CCID 2
#define DCCPF_INITIAL_CCID DCCPC_CCID2
#define DCCPF_INITIAL_SEND_ACK_VECTOR 1
/* FIXME: for now we're default to 1 but it should really be 0 */
#define DCCPF_INITIAL_SEND_NDP_COUNT 1
......@@ -404,6 +410,7 @@ struct dccp_service_list {
};
#define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1)
#define DCCP_SERVICE_CODE_IS_ABSENT 0
static inline int dccp_list_has_service(const struct dccp_service_list *sl,
const __be32 service)
......@@ -484,11 +491,6 @@ static inline struct dccp_minisock *dccp_msk(const struct sock *sk)
return (struct dccp_minisock *)&dccp_sk(sk)->dccps_minisock;
}
static inline int dccp_service_not_initialized(const struct sock *sk)
{
return dccp_sk(sk)->dccps_service == DCCP_SERVICE_INVALID_VALUE;
}
static inline const char *dccp_role(const struct sock *sk)
{
switch (dccp_sk(sk)->dccps_role) {
......
......@@ -10,6 +10,8 @@ header-y += xt_connmark.h
header-y += xt_CONNMARK.h
header-y += xt_conntrack.h
header-y += xt_dccp.h
header-y += xt_dscp.h
header-y += xt_DSCP.h
header-y += xt_esp.h
header-y += xt_helper.h
header-y += xt_length.h
......
......@@ -130,8 +130,9 @@ extern int cipso_v4_rbm_strictvalid;
int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head));
struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
struct sk_buff *cipso_v4_doi_dump_all(size_t headroom);
struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom);
int cipso_v4_doi_walk(u32 *skip_cnt,
int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
void *cb_arg);
int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain);
int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
const char *domain);
......@@ -152,14 +153,11 @@ static inline struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
return NULL;
}
static inline struct sk_buff *cipso_v4_doi_dump_all(size_t headroom)
static inline int cipso_v4_doi_walk(u32 *skip_cnt,
int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
void *cb_arg)
{
return NULL;
}
static inline struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom)
{
return NULL;
return 0;
}
static inline int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def,
......@@ -205,6 +203,7 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
int cipso_v4_socket_setattr(const struct socket *sock,
const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr);
int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr);
int cipso_v4_socket_getattr(const struct socket *sock,
struct netlbl_lsm_secattr *secattr);
int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
......@@ -225,6 +224,12 @@ static inline int cipso_v4_socket_setattr(const struct socket *sock,
return -ENOSYS;
}
static inline int cipso_v4_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
static inline int cipso_v4_socket_getattr(const struct socket *sock,
struct netlbl_lsm_secattr *secattr)
{
......
......@@ -57,9 +57,8 @@
* The payload is dependent on the subsystem specified in the
* 'nlmsghdr->nlmsg_type' and should be defined below, supporting functions
* should be defined in the corresponding net/netlabel/netlabel_<subsys>.h|c
* file. All of the fields in the NetLabel payload are NETLINK attributes, the
* length of each field is the length of the NETLINK attribute payload, see
* include/net/netlink.h for more information on NETLINK attributes.
* file. All of the fields in the NetLabel payload are NETLINK attributes, see
* the include/net/netlink.h file for more information on NETLINK attributes.
*
*/
......@@ -82,50 +81,6 @@
#define NETLBL_NLTYPE_UNLABELED 5
#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL"
/* NetLabel return codes */
#define NETLBL_E_OK 0
/*
* Helper functions
*/
#define NETLBL_LEN_U8 nla_total_size(sizeof(u8))
#define NETLBL_LEN_U16 nla_total_size(sizeof(u16))
#define NETLBL_LEN_U32 nla_total_size(sizeof(u32))
/**
* netlbl_netlink_alloc_skb - Allocate a NETLINK message buffer
* @head: the amount of headroom in bytes
* @body: the desired size (minus headroom) in bytes
* @gfp_flags: the alloc flags to pass to alloc_skb()
*
* Description:
* Allocate a NETLINK message buffer based on the sizes given in @head and
* @body. If @head is greater than zero skb_reserve() is called to reserve
* @head bytes at the start of the buffer. Returns a valid sk_buff pointer on
* success, NULL on failure.
*
*/
static inline struct sk_buff *netlbl_netlink_alloc_skb(size_t head,
size_t body,
gfp_t gfp_flags)
{
struct sk_buff *skb;
skb = alloc_skb(NLMSG_ALIGN(head + body), gfp_flags);
if (skb == NULL)
return NULL;
if (head > 0) {
skb_reserve(skb, head);
if (skb_tailroom(skb) < body) {
kfree_skb(skb);
return NULL;
}
}
return skb;
}
/*
* NetLabel - Kernel API for accessing the network packet label mappings.
*
......@@ -238,6 +193,8 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr,
#ifdef CONFIG_NETLABEL
int netlbl_socket_setattr(const struct socket *sock,
const struct netlbl_lsm_secattr *secattr);
int netlbl_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr);
int netlbl_socket_getattr(const struct socket *sock,
struct netlbl_lsm_secattr *secattr);
int netlbl_skbuff_getattr(const struct sk_buff *skb,
......@@ -250,6 +207,12 @@ static inline int netlbl_socket_setattr(const struct socket *sock,
return -ENOSYS;
}
static inline int netlbl_sock_getattr(struct sock *sk,
struct netlbl_lsm_secattr *secattr)
{
return -ENOSYS;
}
static inline int netlbl_socket_getattr(const struct socket *sock,
struct netlbl_lsm_secattr *secattr)
{
......
......@@ -146,11 +146,13 @@
* nla_ok(nla, remaining) does nla fit into remaining bytes?
* nla_next(nla, remaining) get next netlink attribute
* nla_validate() validate a stream of attributes
* nla_validate_nested() validate a stream of nested attributes
* nla_find() find attribute in stream of attributes
* nla_find_nested() find attribute in nested attributes
* nla_parse() parse and validate stream of attrs
* nla_parse_nested() parse nested attribuets
* nla_for_each_attr() loop over all attributes
* nla_for_each_nested() loop over the nested attributes
*=========================================================================
*/
......@@ -949,6 +951,24 @@ static inline int nla_nest_cancel(struct sk_buff *skb, struct nlattr *start)
return nlmsg_trim(skb, start);
}
/**
* nla_validate_nested - Validate a stream of nested attributes
* @start: container attribute
* @maxtype: maximum attribute type to be expected
* @policy: validation policy
*
* Validates all attributes in the nested attribute stream against the
* specified policy. Attributes with a type exceeding maxtype will be
* ignored. See documenation of struct nla_policy for more details.
*
* Returns 0 on success or a negative error code.
*/
static inline int nla_validate_nested(struct nlattr *start, int maxtype,
struct nla_policy *policy)
{
return nla_validate(nla_data(start), nla_len(start), maxtype, policy);
}
/**
* nla_for_each_attr - iterate over a stream of attributes
* @pos: loop counter, set to current attribute
......
......@@ -40,6 +40,22 @@ config IP_DCCP_DEBUG
Just say N.
config NET_DCCPPROBE
tristate "DCCP connection probing"
depends on PROC_FS && KPROBES
---help---
This module allows for capturing the changes to DCCP connection
state in response to incoming packets. It is used for debugging
DCCP congestion avoidance modules. If you don't understand
what was just said, you don't need it: say N.
Documentation on how to use the packet generator can be found
at http://linux-net.osdl.org/index.php/DccpProbe
To compile this code as a module, choose M here: the
module will be called dccp_probe.
endmenu
endmenu
......@@ -11,9 +11,11 @@ dccp_ipv4-y := ipv4.o
dccp-$(CONFIG_IP_DCCP_ACKVEC) += ackvec.o
obj-$(CONFIG_INET_DCCP_DIAG) += dccp_diag.o
obj-$(CONFIG_NET_DCCPPROBE) += dccp_probe.o
dccp-$(CONFIG_SYSCTL) += sysctl.o
dccp_diag-y := diag.o
dccp_probe-y := probe.o
obj-y += ccids/
......@@ -808,7 +808,7 @@ static void ccid2_hc_rx_packet_recv(struct sock *sk, struct sk_buff *skb)
}
static struct ccid_operations ccid2 = {
.ccid_id = 2,
.ccid_id = DCCPC_CCID2,
.ccid_name = "ccid2",
.ccid_owner = THIS_MODULE,
.ccid_hc_tx_obj_size = sizeof(struct ccid2_hc_tx_sock),
......
......@@ -1240,7 +1240,7 @@ static int ccid3_hc_tx_getsockopt(struct sock *sk, const int optname, int len,
}
static struct ccid_operations ccid3 = {
.ccid_id = 3,
.ccid_id = DCCPC_CCID3,
.ccid_name = "ccid3",
.ccid_owner = THIS_MODULE,
.ccid_hc_tx_obj_size = sizeof(struct ccid3_hc_tx_sock),
......
......@@ -56,9 +56,6 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
dp->dccps_role = DCCP_ROLE_CLIENT;
if (dccp_service_not_initialized(sk))
return -EPROTO;
if (addr_len < sizeof(struct sockaddr_in))
return -EINVAL;
......
/*
* dccp_probe - Observe the DCCP flow with kprobes.
*
* The idea for this came from Werner Almesberger's umlsim
* Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
*
* Modified for DCCP from Stephen Hemminger's code
* Copyright (C) 2006, Ian McDonald <ian.mcdonald@jandi.co.nz>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/kprobes.h>
#include <linux/socket.h>
#include <linux/dccp.h>
#include <linux/proc_fs.h>
#include <linux/module.h>
#include <linux/kfifo.h>
#include <linux/vmalloc.h>
#include "dccp.h"
#include "ccid.h"
#include "ccids/ccid3.h"
static int port;
static int bufsize = 64 * 1024;
static const char procname[] = "dccpprobe";
struct {
struct kfifo *fifo;
spinlock_t lock;
wait_queue_head_t wait;
struct timeval tstart;
} dccpw;
static void printl(const char *fmt, ...)
{
va_list args;
int len;
struct timeval now;
char tbuf[256];
va_start(args, fmt);
do_gettimeofday(&now);
now.tv_sec -= dccpw.tstart.tv_sec;
now.tv_usec -= dccpw.tstart.tv_usec;
if (now.tv_usec < 0) {
--now.tv_sec;
now.tv_usec += 1000000;
}
len = sprintf(tbuf, "%lu.%06lu ",
(unsigned long) now.tv_sec,
(unsigned long) now.tv_usec);
len += vscnprintf(tbuf+len, sizeof(tbuf)-len, fmt, args);
va_end(args);
kfifo_put(dccpw.fifo, tbuf, len);
wake_up(&dccpw.wait);
}
static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk,
struct msghdr *msg, size_t size)
{
const struct dccp_minisock *dmsk = dccp_msk(sk);
const struct inet_sock *inet = inet_sk(sk);
const struct ccid3_hc_tx_sock *hctx;
if (dmsk->dccpms_tx_ccid == DCCPC_CCID3)
hctx = ccid3_hc_tx_sk(sk);
else
hctx = NULL;
if (port == 0 || ntohs(inet->dport) == port ||
ntohs(inet->sport) == port) {
if (hctx)
printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %d %d %d %d\n",
NIPQUAD(inet->saddr), ntohs(inet->sport),
NIPQUAD(inet->daddr), ntohs(inet->dport), size,
hctx->ccid3hctx_s, hctx->ccid3hctx_rtt,
hctx->ccid3hctx_p, hctx->ccid3hctx_t_ipi);
else
printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d\n",
NIPQUAD(inet->saddr), ntohs(inet->sport),
NIPQUAD(inet->daddr), ntohs(inet->dport), size);
}
jprobe_return();
return 0;
}
static struct jprobe dccp_send_probe = {
.kp = { .addr = (kprobe_opcode_t *)&dccp_sendmsg, },
.entry = (kprobe_opcode_t *)&jdccp_sendmsg,
};
static int dccpprobe_open(struct inode *inode, struct file *file)
{
kfifo_reset(dccpw.fifo);
do_gettimeofday(&dccpw.tstart);
return 0;
}
static ssize_t dccpprobe_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
int error = 0, cnt = 0;
unsigned char *tbuf;
if (!buf || len < 0)
return -EINVAL;
if (len == 0)
return 0;
tbuf = vmalloc(len);
if (!tbuf)
return -ENOMEM;
error = wait_event_interruptible(dccpw.wait,
__kfifo_len(dccpw.fifo) != 0);
if (error)
goto out_free;
cnt = kfifo_get(dccpw.fifo, tbuf, len);
error = copy_to_user(buf, tbuf, cnt);
out_free:
vfree(tbuf);
return error ? error : cnt;
}
static struct file_operations dccpprobe_fops = {
.owner = THIS_MODULE,
.open = dccpprobe_open,
.read = dccpprobe_read,
};
static __init int dccpprobe_init(void)
{
int ret = -ENOMEM;
init_waitqueue_head(&dccpw.wait);
spin_lock_init(&dccpw.lock);
dccpw.fifo = kfifo_alloc(bufsize, GFP_KERNEL, &dccpw.lock);
if (!proc_net_fops_create(procname, S_IRUSR, &dccpprobe_fops))
goto err0;
ret = register_jprobe(&dccp_send_probe);
if (ret)
goto err1;
pr_info("DCCP watch registered (port=%d)\n", port);
return 0;
err1:
proc_net_remove(procname);
err0:
kfifo_free(dccpw.fifo);
return ret;
}
module_init(dccpprobe_init);
static __exit void dccpprobe_exit(void)
{
kfifo_free(dccpw.fifo);
proc_net_remove(procname);
unregister_jprobe(&dccp_send_probe);
}
module_exit(dccpprobe_exit);
MODULE_PARM_DESC(port, "Port to match (0=all)");
module_param(port, int, 0);
MODULE_PARM_DESC(bufsize, "Log buffer size (default 64k)");
module_param(bufsize, int, 0);
MODULE_AUTHOR("Ian McDonald <ian.mcdonald@jandi.co.nz>");
MODULE_DESCRIPTION("DCCP snooper");
MODULE_LICENSE("GPL");
......@@ -217,7 +217,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
icsk->icsk_sync_mss = dccp_sync_mss;
dp->dccps_mss_cache = 536;
dp->dccps_role = DCCP_ROLE_UNDEFINED;
dp->dccps_service = DCCP_SERVICE_INVALID_VALUE;
dp->dccps_service = DCCP_SERVICE_CODE_IS_ABSENT;
dp->dccps_l_ack_ratio = dp->dccps_r_ack_ratio = 1;
return 0;
......@@ -267,12 +267,6 @@ static inline int dccp_listen_start(struct sock *sk)
struct dccp_sock *dp = dccp_sk(sk);
dp->dccps_role = DCCP_ROLE_LISTEN;
/*
* Apps need to use setsockopt(DCCP_SOCKOPT_SERVICE)
* before calling listen()
*/
if (dccp_service_not_initialized(sk))
return -EPROTO;
return inet_csk_listen_start(sk, TCP_SYNQ_HSIZE);
}
......@@ -540,9 +534,6 @@ static int dccp_getsockopt_service(struct sock *sk, int len,
int err = -ENOENT, slen = 0, total_len = sizeof(u32);
lock_sock(sk);
if (dccp_service_not_initialized(sk))
goto out;
if ((sl = dp->dccps_service_list) != NULL) {
slen = sl->dccpsl_nr * sizeof(u32);
total_len += slen;
......
......@@ -448,24 +448,22 @@ config INET_TCP_DIAG
depends on INET_DIAG
def_tristate INET_DIAG
config TCP_CONG_ADVANCED
menuconfig TCP_CONG_ADVANCED
bool "TCP: advanced congestion control"
---help---
Support for selection of various TCP congestion control
modules.
Nearly all users can safely say no here, and a safe default
selection will be made (BIC-TCP with new Reno as a fallback).
selection will be made (CUBIC with new Reno as a fallback).
If unsure, say N.
# TCP Reno is builtin (required as fallback)
menu "TCP congestion control"
depends on TCP_CONG_ADVANCED
if TCP_CONG_ADVANCED
config TCP_CONG_BIC
tristate "Binary Increase Congestion (BIC) control"
default y
default m
---help---
BIC-TCP is a sender-side only change that ensures a linear RTT
fairness under large windows while offering both scalability and
......@@ -479,7 +477,7 @@ config TCP_CONG_BIC
config TCP_CONG_CUBIC
tristate "CUBIC TCP"
default m
default y
---help---
This is version 2.0 of BIC-TCP which uses a cubic growth function
among other techniques.
......@@ -574,12 +572,49 @@ config TCP_CONG_VENO
loss packets.
See http://www.ntu.edu.sg/home5/ZHOU0022/papers/CPFu03a.pdf
endmenu
choice
prompt "Default TCP congestion control"
default DEFAULT_CUBIC
help
Select the TCP congestion control that will be used by default
for all connections.
config TCP_CONG_BIC
config DEFAULT_BIC
bool "Bic" if TCP_CONG_BIC=y
config DEFAULT_CUBIC
bool "Cubic" if TCP_CONG_CUBIC=y
config DEFAULT_HTCP
bool "Htcp" if TCP_CONG_HTCP=y
config DEFAULT_VEGAS
bool "Vegas" if TCP_CONG_VEGAS=y
config DEFAULT_WESTWOOD
bool "Westwood" if TCP_CONG_WESTWOOD=y
config DEFAULT_RENO
bool "Reno"
endchoice
endif
config TCP_CONG_CUBIC
tristate
depends on !TCP_CONG_ADVANCED
default y
config DEFAULT_TCP_CONG
string
default "bic" if DEFAULT_BIC
default "cubic" if DEFAULT_CUBIC
default "htcp" if DEFAULT_HTCP
default "vegas" if DEFAULT_VEGAS
default "westwood" if DEFAULT_WESTWOOD
default "reno" if DEFAULT_RENO
default "cubic"
source "net/ipv4/ipvs/Kconfig"
......@@ -259,7 +259,7 @@ void cipso_v4_cache_invalidate(void)
u32 iter;
for (iter = 0; iter < CIPSO_V4_CACHE_BUCKETS; iter++) {
spin_lock(&cipso_v4_cache[iter].lock);
spin_lock_bh(&cipso_v4_cache[iter].lock);
list_for_each_entry_safe(entry,
tmp_entry,
&cipso_v4_cache[iter].list, list) {
......@@ -267,7 +267,7 @@ void cipso_v4_cache_invalidate(void)
cipso_v4_cache_entry_free(entry);
}
cipso_v4_cache[iter].size = 0;
spin_unlock(&cipso_v4_cache[iter].lock);
spin_unlock_bh(&cipso_v4_cache[iter].lock);
}
return;
......@@ -309,7 +309,7 @@ static int cipso_v4_cache_check(const unsigned char *key,
hash = cipso_v4_map_cache_hash(key, key_len);
bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
spin_lock(&cipso_v4_cache[bkt].lock);
spin_lock_bh(&cipso_v4_cache[bkt].lock);
list_for_each_entry(entry, &cipso_v4_cache[bkt].list, list) {
if (entry->hash == hash &&
entry->key_len == key_len &&
......@@ -318,7 +318,7 @@ static int cipso_v4_cache_check(const unsigned char *key,
secattr->cache.free = entry->lsm_data.free;
secattr->cache.data = entry->lsm_data.data;
if (prev_entry == NULL) {
spin_unlock(&cipso_v4_cache[bkt].lock);
spin_unlock_bh(&cipso_v4_cache[bkt].lock);
return 0;
}
......@@ -333,12 +333,12 @@ static int cipso_v4_cache_check(const unsigned char *key,
&prev_entry->list);
}
spin_unlock(&cipso_v4_cache[bkt].lock);
spin_unlock_bh(&cipso_v4_cache[bkt].lock);
return 0;
}
prev_entry = entry;
}
spin_unlock(&cipso_v4_cache[bkt].lock);
spin_unlock_bh(&cipso_v4_cache[bkt].lock);
return -ENOENT;
}
......@@ -387,7 +387,7 @@ int cipso_v4_cache_add(const struct sk_buff *skb,
entry->lsm_data.data = secattr->cache.data;
bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
spin_lock(&cipso_v4_cache[bkt].lock);
spin_lock_bh(&cipso_v4_cache[bkt].lock);
if (cipso_v4_cache[bkt].size < cipso_v4_cache_bucketsize) {
list_add(&entry->list, &cipso_v4_cache[bkt].list);
cipso_v4_cache[bkt].size += 1;
......@@ -398,7 +398,7 @@ int cipso_v4_cache_add(const struct sk_buff *skb,
list_add(&entry->list, &cipso_v4_cache[bkt].list);
cipso_v4_cache_entry_free(old_entry);
}
spin_unlock(&cipso_v4_cache[bkt].lock);
spin_unlock_bh(&cipso_v4_cache[bkt].lock);
return 0;
......@@ -530,197 +530,42 @@ struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi)
}
/**
* cipso_v4_doi_dump_all - Dump all the CIPSO DOI definitions into a sk_buff
* @headroom: the amount of headroom to allocate for the sk_buff
* cipso_v4_doi_walk - Iterate through the DOI definitions
* @skip_cnt: skip past this number of DOI definitions, updated
* @callback: callback for each DOI definition
* @cb_arg: argument for the callback function
*
* Description:
* Dump a list of all the configured DOI values into a sk_buff. The returned
* sk_buff has room at the front of the sk_buff for @headroom bytes. See
* net/netlabel/netlabel_cipso_v4.h for the LISTALL message format. This
* function may fail if another process is changing the DOI list at the same
* time. Returns a pointer to a sk_buff on success, NULL on error.
* Iterate over the DOI definition list, skipping the first @skip_cnt entries.
* For each entry call @callback, if @callback returns a negative value stop
* 'walking' through the list and return. Updates the value in @skip_cnt upon
* return. Returns zero on success, negative values on failure.
*
*/
struct sk_buff *cipso_v4_doi_dump_all(size_t headroom)
int cipso_v4_doi_walk(u32 *skip_cnt,
int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
void *cb_arg)
{
struct sk_buff *skb = NULL;
struct cipso_v4_doi *iter;
int ret_val = -ENOENT;
u32 doi_cnt = 0;
ssize_t buf_len;
struct cipso_v4_doi *iter_doi;
buf_len = NETLBL_LEN_U32;
rcu_read_lock();
list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
if (iter->valid) {
doi_cnt += 1;
buf_len += 2 * NETLBL_LEN_U32;
}
skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC);
if (skb == NULL)
goto doi_dump_all_failure;
if (nla_put_u32(skb, NLA_U32, doi_cnt) != 0)
goto doi_dump_all_failure;
buf_len -= NETLBL_LEN_U32;
list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
if (iter->valid) {
if (buf_len < 2 * NETLBL_LEN_U32)
goto doi_dump_all_failure;
if (nla_put_u32(skb, NLA_U32, iter->doi) != 0)
goto doi_dump_all_failure;
if (nla_put_u32(skb, NLA_U32, iter->type) != 0)
goto doi_dump_all_failure;
buf_len -= 2 * NETLBL_LEN_U32;
}
rcu_read_unlock();
return skb;
doi_dump_all_failure:
rcu_read_unlock();
kfree(skb);
return NULL;
}
/**
* cipso_v4_doi_dump - Dump a CIPSO DOI definition into a sk_buff
* @doi: the DOI value
* @headroom: the amount of headroom to allocate for the sk_buff
*
* Description:
* Lookup the DOI definition matching @doi and dump it's contents into a
* sk_buff. The returned sk_buff has room at the front of the sk_buff for
* @headroom bytes. See net/netlabel/netlabel_cipso_v4.h for the LIST message
* format. This function may fail if another process is changing the DOI list
* at the same time. Returns a pointer to a sk_buff on success, NULL on error.
*
*/
struct sk_buff *cipso_v4_doi_dump(u32 doi, size_t headroom)
{
struct sk_buff *skb = NULL;
struct cipso_v4_doi *iter;
u32 tag_cnt = 0;
u32 lvl_cnt = 0;
u32 cat_cnt = 0;
ssize_t buf_len;
ssize_t tmp;
rcu_read_lock();
iter = cipso_v4_doi_getdef(doi);
if (iter == NULL)
goto doi_dump_failure;
buf_len = NETLBL_LEN_U32;
switch (iter->type) {
case CIPSO_V4_MAP_PASS:
buf_len += NETLBL_LEN_U32;
while(tag_cnt < CIPSO_V4_TAG_MAXCNT &&
iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) {
tag_cnt += 1;
buf_len += NETLBL_LEN_U8;
}
break;
case CIPSO_V4_MAP_STD:
buf_len += 3 * NETLBL_LEN_U32;
while (tag_cnt < CIPSO_V4_TAG_MAXCNT &&
iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) {
tag_cnt += 1;
buf_len += NETLBL_LEN_U8;
}
for (tmp = 0; tmp < iter->map.std->lvl.local_size; tmp++)
if (iter->map.std->lvl.local[tmp] !=
CIPSO_V4_INV_LVL) {
lvl_cnt += 1;
buf_len += NETLBL_LEN_U32 + NETLBL_LEN_U8;
}
for (tmp = 0; tmp < iter->map.std->cat.local_size; tmp++)
if (iter->map.std->cat.local[tmp] !=
CIPSO_V4_INV_CAT) {
cat_cnt += 1;
buf_len += NETLBL_LEN_U32 + NETLBL_LEN_U16;
list_for_each_entry_rcu(iter_doi, &cipso_v4_doi_list, list)
if (iter_doi->valid) {
if (doi_cnt++ < *skip_cnt)
continue;
ret_val = callback(iter_doi, cb_arg);
if (ret_val < 0) {
doi_cnt--;
goto doi_walk_return;
}
break;
}
skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC);
if (skb == NULL)
goto doi_dump_failure;
if (nla_put_u32(skb, NLA_U32, iter->type) != 0)
goto doi_dump_failure;
buf_len -= NETLBL_LEN_U32;
if (iter != cipso_v4_doi_getdef(doi))
goto doi_dump_failure;
switch (iter->type) {
case CIPSO_V4_MAP_PASS:
if (nla_put_u32(skb, NLA_U32, tag_cnt) != 0)
goto doi_dump_failure;
buf_len -= NETLBL_LEN_U32;
for (tmp = 0;
tmp < CIPSO_V4_TAG_MAXCNT &&
iter->tags[tmp] != CIPSO_V4_TAG_INVALID;
tmp++) {
if (buf_len < NETLBL_LEN_U8)
goto doi_dump_failure;
if (nla_put_u8(skb, NLA_U8, iter->tags[tmp]) != 0)
goto doi_dump_failure;
buf_len -= NETLBL_LEN_U8;
}
break;
case CIPSO_V4_MAP_STD:
if (nla_put_u32(skb, NLA_U32, tag_cnt) != 0)
goto doi_dump_failure;
if (nla_put_u32(skb, NLA_U32, lvl_cnt) != 0)
goto doi_dump_failure;
if (nla_put_u32(skb, NLA_U32, cat_cnt) != 0)
goto doi_dump_failure;
buf_len -= 3 * NETLBL_LEN_U32;
for (tmp = 0;
tmp < CIPSO_V4_TAG_MAXCNT &&
iter->tags[tmp] != CIPSO_V4_TAG_INVALID;
tmp++) {
if (buf_len < NETLBL_LEN_U8)
goto doi_dump_failure;
if (nla_put_u8(skb, NLA_U8, iter->tags[tmp]) != 0)
goto doi_dump_failure;
buf_len -= NETLBL_LEN_U8;
}
for (tmp = 0; tmp < iter->map.std->lvl.local_size; tmp++)
if (iter->map.std->lvl.local[tmp] !=
CIPSO_V4_INV_LVL) {
if (buf_len < NETLBL_LEN_U32 + NETLBL_LEN_U8)
goto doi_dump_failure;
if (nla_put_u32(skb, NLA_U32, tmp) != 0)
goto doi_dump_failure;
if (nla_put_u8(skb,
NLA_U8,
iter->map.std->lvl.local[tmp]) != 0)
goto doi_dump_failure;
buf_len -= NETLBL_LEN_U32 + NETLBL_LEN_U8;
}
for (tmp = 0; tmp < iter->map.std->cat.local_size; tmp++)
if (iter->map.std->cat.local[tmp] !=
CIPSO_V4_INV_CAT) {
if (buf_len < NETLBL_LEN_U32 + NETLBL_LEN_U16)
goto doi_dump_failure;
if (nla_put_u32(skb, NLA_U32, tmp) != 0)
goto doi_dump_failure;
if (nla_put_u16(skb,
NLA_U16,
iter->map.std->cat.local[tmp]) != 0)
goto doi_dump_failure;
buf_len -= NETLBL_LEN_U32 + NETLBL_LEN_U16;
}
break;
}
rcu_read_unlock();
return skb;
doi_dump_failure:
doi_walk_return:
rcu_read_unlock();
kfree(skb);
return NULL;
*skip_cnt = doi_cnt;
return ret_val;
}
/**
......@@ -1486,43 +1331,40 @@ int cipso_v4_socket_setattr(const struct socket *sock,
}
/**
* cipso_v4_socket_getattr - Get the security attributes from a socket
* @sock: the socket
* cipso_v4_sock_getattr - Get the security attributes from a sock
* @sk: the sock
* @secattr: the security attributes
*
* Description:
* Query @sock to see if there is a CIPSO option attached to the socket and if
* there is return the CIPSO security attributes in @secattr. Returns zero on
* success and negative values on failure.
* Query @sk to see if there is a CIPSO option attached to the sock and if
* there is return the CIPSO security attributes in @secattr. This function
* requires that @sk be locked, or privately held, but it does not do any
* locking itself. Returns zero on success and negative values on failure.
*
*/
int cipso_v4_socket_getattr(const struct socket *sock,
struct netlbl_lsm_secattr *secattr)
int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
{
int ret_val = -ENOMSG;
struct sock *sk;
struct inet_sock *sk_inet;
unsigned char *cipso_ptr;
u32 doi;
struct cipso_v4_doi *doi_def;
sk = sock->sk;
lock_sock(sk);
sk_inet = inet_sk(sk);
if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0)
goto socket_getattr_return;
return -ENOMSG;
cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso -
sizeof(struct iphdr);
ret_val = cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr);
if (ret_val == 0)
goto socket_getattr_return;
return ret_val;
doi = ntohl(*(u32 *)&cipso_ptr[2]);
rcu_read_lock();
doi_def = cipso_v4_doi_getdef(doi);
if (doi_def == NULL) {
rcu_read_unlock();
goto socket_getattr_return;
return -ENOMSG;
}
switch (cipso_ptr[6]) {
case CIPSO_V4_TAG_RBITMAP:
......@@ -1533,8 +1375,29 @@ int cipso_v4_socket_getattr(const struct socket *sock,
}
rcu_read_unlock();
socket_getattr_return:
release_sock(sk);
return ret_val;
}
/**
* cipso_v4_socket_getattr - Get the security attributes from a socket
* @sock: the socket
* @secattr: the security attributes
*
* Description:
* Query @sock to see if there is a CIPSO option attached to the socket and if
* there is return the CIPSO security attributes in @secattr. Returns zero on
* success and negative values on failure.
*
*/
int cipso_v4_socket_getattr(const struct socket *sock,
struct netlbl_lsm_secattr *secattr)
{
int ret_val;
lock_sock(sock->sk);
ret_val = cipso_v4_sock_getattr(sock->sk, secattr);
release_sock(sock->sk);
return ret_val;
}
......
......@@ -129,6 +129,12 @@ static int sysctl_tcp_congestion_control(ctl_table *table, int __user *name,
return ret;
}
static int __init tcp_congestion_default(void)
{
return tcp_set_default_congestion_control(CONFIG_DEFAULT_TCP_CONG);
}
late_initcall(tcp_congestion_default);
ctl_table ipv4_table[] = {
{
......
......@@ -48,7 +48,7 @@ int tcp_register_congestion_control(struct tcp_congestion_ops *ca)
printk(KERN_NOTICE "TCP %s already registered\n", ca->name);
ret = -EEXIST;
} else {
list_add_rcu(&ca->list, &tcp_cong_list);
list_add_tail_rcu(&ca->list, &tcp_cong_list);
printk(KERN_INFO "TCP %s registered\n", ca->name);
}
spin_unlock(&tcp_cong_list_lock);
......
......@@ -9,6 +9,9 @@ config NETLABEL
---help---
NetLabel provides support for explicit network packet labeling
protocols such as CIPSO and RIPSO. For more information see
Documentation/netlabel.
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.
......@@ -41,15 +41,37 @@
#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 = 0,
.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
......@@ -81,6 +103,41 @@ static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
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);
}
if (iter < CIPSO_V4_TAG_MAXCNT)
doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
return 0;
}
/*
* NetLabel Command Handlers
......@@ -88,9 +145,7 @@ static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
/**
* netlbl_cipsov4_add_std - Adds a CIPSO V4 DOI definition
* @doi: the DOI value
* @msg: the ADD message data
* @msg_size: the size of the ADD message buffer
* @info: the Generic NETLINK info block
*
* Description:
* Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
......@@ -98,29 +153,28 @@ static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
* error.
*
*/
static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
static int netlbl_cipsov4_add_std(struct genl_info *info)
{
int ret_val = -EINVAL;
int msg_len = msg_size;
u32 num_tags;
u32 num_lvls;
u32 num_cats;
struct cipso_v4_doi *doi_def = NULL;
u32 iter;
u32 tmp_val_a;
u32 tmp_val_b;
struct nlattr *nla_a;
struct nlattr *nla_b;
int nla_a_rem;
int nla_b_rem;
if (msg_len < NETLBL_LEN_U32)
goto add_std_failure;
num_tags = netlbl_getinc_u32(&msg, &msg_len);
if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
goto add_std_failure;
if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
!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) {
ret_val = -ENOMEM;
goto add_std_failure;
}
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;
......@@ -128,28 +182,32 @@ static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
}
doi_def->type = CIPSO_V4_MAP_STD;
for (iter = 0; iter < num_tags; iter++) {
if (msg_len < NETLBL_LEN_U8)
goto add_std_failure;
doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len);
switch (doi_def->tags[iter]) {
case CIPSO_V4_TAG_RBITMAP:
break;
default:
goto add_std_failure;
}
}
if (iter < CIPSO_V4_TAG_MAXCNT)
doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
if (msg_len < 6 * NETLBL_LEN_U32)
ret_val = netlbl_cipsov4_add_common(info, doi_def);
if (ret_val != 0)
goto add_std_failure;
num_lvls = netlbl_getinc_u32(&msg, &msg_len);
if (num_lvls == 0)
goto add_std_failure;
doi_def->map.std->lvl.local_size = netlbl_getinc_u32(&msg, &msg_len);
if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS)
nla_for_each_nested(nla_a,
info->attrs[NLBL_CIPSOV4_A_MLSLVLLST],
nla_a_rem)
if (nla_a->nla_type == NLBL_CIPSOV4_A_MLSLVL) {
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) >=
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) >=
doi_def->map.std->lvl.cipso_size)
doi_def->map.std->lvl.cipso_size =
nla_get_u32(nla_b) + 1;
break;
}
}
if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS ||
doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS)
goto add_std_failure;
doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
sizeof(u32),
......@@ -158,9 +216,6 @@ static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
ret_val = -ENOMEM;
goto add_std_failure;
}
doi_def->map.std->lvl.cipso_size = netlbl_getinc_u8(&msg, &msg_len);
if (doi_def->map.std->lvl.cipso_size > CIPSO_V4_MAX_REM_LVLS)
goto add_std_failure;
doi_def->map.std->lvl.cipso = kcalloc(doi_def->map.std->lvl.cipso_size,
sizeof(u32),
GFP_KERNEL);
......@@ -168,68 +223,101 @@ static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
ret_val = -ENOMEM;
goto add_std_failure;
}
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;
if (nla_validate_nested(nla_a,
NLBL_CIPSOV4_A_MAX,
netlbl_cipsov4_genl_policy) != 0)
goto add_std_failure;
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);
}
num_cats = netlbl_getinc_u32(&msg, &msg_len);
doi_def->map.std->cat.local_size = netlbl_getinc_u32(&msg, &msg_len);
if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS)
goto add_std_failure;
doi_def->map.std->cat.local = kcalloc(doi_def->map.std->cat.local_size,
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) >=
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) >=
doi_def->map.std->cat.cipso_size)
doi_def->map.std->cat.cipso_size =
nla_get_u32(nla_b) + 1;
break;
}
}
if (doi_def->map.std->cat.local_size > CIPSO_V4_MAX_LOC_CATS ||
doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS)
goto add_std_failure;
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_size = netlbl_getinc_u16(&msg, &msg_len);
if (doi_def->map.std->cat.cipso_size > CIPSO_V4_MAX_REM_CATS)
goto add_std_failure;
doi_def->map.std->cat.cipso = kcalloc(doi_def->map.std->cat.cipso_size,
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;
}
if (msg_len <
num_lvls * (NETLBL_LEN_U32 + NETLBL_LEN_U8) +
num_cats * (NETLBL_LEN_U32 + NETLBL_LEN_U16))
goto add_std_failure;
for (iter = 0; iter < doi_def->map.std->lvl.cipso_size; iter++)
doi_def->map.std->lvl.cipso[iter] = CIPSO_V4_INV_LVL;
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->cat.cipso_size; iter++)
doi_def->map.std->cat.cipso[iter] = CIPSO_V4_INV_CAT;
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 < num_lvls; iter++) {
tmp_val_a = netlbl_getinc_u32(&msg, &msg_len);
tmp_val_b = netlbl_getinc_u8(&msg, &msg_len);
if (tmp_val_a >= doi_def->map.std->lvl.local_size ||
tmp_val_b >= doi_def->map.std->lvl.cipso_size)
goto add_std_failure;
doi_def->map.std->lvl.cipso[tmp_val_b] = tmp_val_a;
doi_def->map.std->lvl.local[tmp_val_a] = tmp_val_b;
}
for (iter = 0; iter < num_cats; iter++) {
tmp_val_a = netlbl_getinc_u32(&msg, &msg_len);
tmp_val_b = netlbl_getinc_u16(&msg, &msg_len);
if (tmp_val_a >= doi_def->map.std->cat.local_size ||
tmp_val_b >= doi_def->map.std->cat.cipso_size)
if (doi_def->map.std->cat.cipso == NULL) {
ret_val = -ENOMEM;
goto add_std_failure;
doi_def->map.std->cat.cipso[tmp_val_b] = tmp_val_a;
doi_def->map.std->cat.local[tmp_val_a] = tmp_val_b;
}
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);
}
}
doi_def->doi = doi;
ret_val = cipso_v4_doi_add(doi_def);
if (ret_val != 0)
goto add_std_failure;
......@@ -243,9 +331,7 @@ static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
/**
* netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
* @doi: the DOI value
* @msg: the ADD message data
* @msg_size: the size of the ADD message buffer
* @info: the Generic NETLINK info block
*
* Description:
* Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
......@@ -253,52 +339,31 @@ static int netlbl_cipsov4_add_std(u32 doi, struct nlattr *msg, size_t msg_size)
* error.
*
*/
static int netlbl_cipsov4_add_pass(u32 doi,
struct nlattr *msg,
size_t msg_size)
static int netlbl_cipsov4_add_pass(struct genl_info *info)
{
int ret_val = -EINVAL;
int msg_len = msg_size;
u32 num_tags;
int ret_val;
struct cipso_v4_doi *doi_def = NULL;
u32 iter;
if (msg_len < NETLBL_LEN_U32)
goto add_pass_failure;
num_tags = netlbl_getinc_u32(&msg, &msg_len);
if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
goto add_pass_failure;
if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
!info->attrs[NLBL_CIPSOV4_A_TAGLST])
return -EINVAL;
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
if (doi_def == NULL) {
ret_val = -ENOMEM;
goto add_pass_failure;
}
if (doi_def == NULL)
return -ENOMEM;
doi_def->type = CIPSO_V4_MAP_PASS;
for (iter = 0; iter < num_tags; iter++) {
if (msg_len < NETLBL_LEN_U8)
goto add_pass_failure;
doi_def->tags[iter] = netlbl_getinc_u8(&msg, &msg_len);
switch (doi_def->tags[iter]) {
case CIPSO_V4_TAG_RBITMAP:
break;
default:
goto add_pass_failure;
}
}
if (iter < CIPSO_V4_TAG_MAXCNT)
doi_def->tags[iter] = CIPSO_V4_TAG_INVALID;
ret_val = netlbl_cipsov4_add_common(info, doi_def);
if (ret_val != 0)
goto add_pass_failure;
doi_def->doi = doi;
ret_val = cipso_v4_doi_add(doi_def);
if (ret_val != 0)
goto add_pass_failure;
return 0;
add_pass_failure:
if (doi_def)
netlbl_cipsov4_doi_free(&doi_def->rcu);
netlbl_cipsov4_doi_free(&doi_def->rcu);
return ret_val;
}
......@@ -316,34 +381,21 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -EINVAL;
u32 doi;
u32 map_type;
int msg_len = netlbl_netlink_payload_len(skb);
struct nlattr *msg = netlbl_netlink_payload_data(skb);
ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
if (ret_val != 0)
goto add_return;
if (msg_len < 2 * NETLBL_LEN_U32)
goto add_return;
if (!info->attrs[NLBL_CIPSOV4_A_MTYPE])
return -EINVAL;
doi = netlbl_getinc_u32(&msg, &msg_len);
map_type = netlbl_getinc_u32(&msg, &msg_len);
map_type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
switch (map_type) {
case CIPSO_V4_MAP_STD:
ret_val = netlbl_cipsov4_add_std(doi, msg, msg_len);
ret_val = netlbl_cipsov4_add_std(info);
break;
case CIPSO_V4_MAP_PASS:
ret_val = netlbl_cipsov4_add_pass(doi, msg, msg_len);
ret_val = netlbl_cipsov4_add_pass(info);
break;
}
add_return:
netlbl_netlink_send_ack(info,
netlbl_cipsov4_gnl_family.id,
NLBL_CIPSOV4_C_ACK,
-ret_val);
return ret_val;
}
......@@ -353,84 +405,239 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
* @info: the Generic NETLINK info block
*
* Description:
* Process a user generated LIST message and respond accordingly. Returns
* zero on success and negative values on error.
* 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 = -EINVAL;
int ret_val;
struct sk_buff *ans_skb = NULL;
u32 nlsze_mult = 1;
void *data;
u32 doi;
struct nlattr *msg = netlbl_netlink_payload_data(skb);
struct sk_buff *ans_skb;
struct nlattr *nla_a;
struct nlattr *nla_b;
struct cipso_v4_doi *doi_def;
u32 iter;
if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32)
if (!info->attrs[NLBL_CIPSOV4_A_DOI]) {
ret_val = -EINVAL;
goto list_failure;
}
doi = nla_get_u32(msg);
ans_skb = cipso_v4_doi_dump(doi, NLMSG_SPACE(GENL_HDRLEN));
list_start:
ans_skb = nlmsg_new(NLMSG_GOODSIZE * nlsze_mult, GFP_KERNEL);
if (ans_skb == NULL) {
ret_val = -ENOMEM;
goto list_failure;
}
netlbl_netlink_hdr_push(ans_skb,
info->snd_pid,
0,
netlbl_cipsov4_gnl_family.id,
NLBL_CIPSOV4_C_LIST);
data = netlbl_netlink_hdr_put(ans_skb,
info->snd_pid,
info->snd_seq,
netlbl_cipsov4_gnl_family.id,
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();
ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
genlmsg_end(ans_skb, data);
ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
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:
netlbl_netlink_send_ack(info,
netlbl_cipsov4_gnl_family.id,
NLBL_CIPSOV4_C_ACK,
-ret_val);
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 = netlbl_netlink_hdr_put(cb_arg->skb,
NETLINK_CB(cb_arg->nl_cb->skb).pid,
cb_arg->seq,
netlbl_cipsov4_gnl_family.id,
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
* @info: the Generic NETLINK info block
* @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 genl_info *info)
static int netlbl_cipsov4_listall(struct sk_buff *skb,
struct netlink_callback *cb)
{
int ret_val = -EINVAL;
struct sk_buff *ans_skb;
struct netlbl_cipsov4_doiwalk_arg cb_arg;
int doi_skip = cb->args[0];
ans_skb = cipso_v4_doi_dump_all(NLMSG_SPACE(GENL_HDRLEN));
if (ans_skb == NULL) {
ret_val = -ENOMEM;
goto listall_failure;
}
netlbl_netlink_hdr_push(ans_skb,
info->snd_pid,
0,
netlbl_cipsov4_gnl_family.id,
NLBL_CIPSOV4_C_LISTALL);
cb_arg.nl_cb = cb;
cb_arg.skb = skb;
cb_arg.seq = cb->nlh->nlmsg_seq;
ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
if (ret_val != 0)
goto listall_failure;
return 0;
cipso_v4_doi_walk(&doi_skip, netlbl_cipsov4_listall_cb, &cb_arg);
listall_failure:
netlbl_netlink_send_ack(info,
netlbl_cipsov4_gnl_family.id,
NLBL_CIPSOV4_C_ACK,
-ret_val);
return ret_val;
cb->args[0] = doi_skip;
return skb->len;
}
/**
......@@ -445,27 +652,14 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb, struct genl_info *info)
*/
static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
{
int ret_val;
int ret_val = -EINVAL;
u32 doi;
struct nlattr *msg = netlbl_netlink_payload_data(skb);
ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
if (ret_val != 0)
goto remove_return;
if (netlbl_netlink_payload_len(skb) != NETLBL_LEN_U32) {
ret_val = -EINVAL;
goto remove_return;
if (info->attrs[NLBL_CIPSOV4_A_DOI]) {
doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free);
}
doi = nla_get_u32(msg);
ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free);
remove_return:
netlbl_netlink_send_ack(info,
netlbl_cipsov4_gnl_family.id,
NLBL_CIPSOV4_C_ACK,
-ret_val);
return ret_val;
}
......@@ -475,14 +669,16 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
static struct genl_ops netlbl_cipsov4_genl_c_add = {
.cmd = NLBL_CIPSOV4_C_ADD,
.flags = 0,
.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 = 0,
.flags = GENL_ADMIN_PERM,
.policy = netlbl_cipsov4_genl_policy,
.doit = netlbl_cipsov4_remove,
.dumpit = NULL,
};
......@@ -490,6 +686,7 @@ static struct genl_ops netlbl_cipsov4_genl_c_remove = {
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,
};
......@@ -497,8 +694,9 @@ static struct genl_ops netlbl_cipsov4_genl_c_list = {
static struct genl_ops netlbl_cipsov4_genl_c_listall = {
.cmd = NLBL_CIPSOV4_C_LISTALL,
.flags = 0,
.doit = netlbl_cipsov4_listall,
.dumpit = NULL,
.policy = netlbl_cipsov4_genl_policy,
.doit = NULL,
.dumpit = netlbl_cipsov4_listall,
};
/*
......
......@@ -34,175 +34,71 @@
#include <net/netlabel.h>
/*
* The following NetLabel payloads are supported by the CIPSO subsystem, all
* of which are preceeded by the nlmsghdr struct.
* The following NetLabel payloads are supported by the CIPSO subsystem.
*
* o ACK:
* Sent by the kernel in response to an applications message, applications
* should never send this message.
* o ADD:
* Sent by an application to add a new DOI mapping table.
*
* +----------------------+-----------------------+
* | seq number (32 bits) | return code (32 bits) |
* +----------------------+-----------------------+
* Required attributes:
*
* seq number: the sequence number of the original message, taken from the
* nlmsghdr structure
* return code: return value, based on errno values
* NLBL_CIPSOV4_A_DOI
* NLBL_CIPSOV4_A_MTYPE
* NLBL_CIPSOV4_A_TAGLST
*
* o ADD:
* Sent by an application to add a new DOI mapping table, after completion
* of the task the kernel should ACK this message.
*
* +---------------+--------------------+---------------------+
* | DOI (32 bits) | map type (32 bits) | tag count (32 bits) | ...
* +---------------+--------------------+---------------------+
*
* +-----------------+
* | tag #X (8 bits) | ... repeated
* +-----------------+
*
* +-------------- ---- --- -- -
* | mapping data
* +-------------- ---- --- -- -
*
* DOI: the DOI value
* map type: the mapping table type (defined in the cipso_ipv4.h header
* as CIPSO_V4_MAP_*)
* tag count: the number of tags, must be greater than zero
* tag: the CIPSO tag for the DOI, tags listed first are given
* higher priorirty when sending packets
* mapping data: specific to the map type (see below)
*
* CIPSO_V4_MAP_STD
*
* +------------------+-----------------------+----------------------+
* | levels (32 bits) | max l level (32 bits) | max r level (8 bits) | ...
* +------------------+-----------------------+----------------------+
*
* +----------------------+---------------------+---------------------+
* | categories (32 bits) | max l cat (32 bits) | max r cat (16 bits) | ...
* +----------------------+---------------------+---------------------+
*
* +--------------------------+-------------------------+
* | local level #X (32 bits) | CIPSO level #X (8 bits) | ... repeated
* +--------------------------+-------------------------+
*
* +-----------------------------+-----------------------------+
* | local category #X (32 bits) | CIPSO category #X (16 bits) | ... repeated
* +-----------------------------+-----------------------------+
*
* levels: the number of level mappings
* max l level: the highest local level
* max r level: the highest remote/CIPSO level
* categories: the number of category mappings
* max l cat: the highest local category
* max r cat: the highest remote/CIPSO category
* local level: the local part of a level mapping
* CIPSO level: the remote/CIPSO part of a level mapping
* local category: the local part of a category mapping
* CIPSO category: the remote/CIPSO part of a category mapping
*
* CIPSO_V4_MAP_PASS
*
* No mapping data is needed for this map type.
* 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. The kernel should ACK this message.
* CIPSO V4 system.
*
* +---------------+
* | DOI (32 bits) |
* +---------------+
* Required attributes:
*
* DOI: the DOI value
* NLBL_CIPSOV4_A_DOI
*
* o LIST:
* Sent by an application to list the details of a DOI definition. The
* kernel should send an ACK on error or a response as indicated below. The
* application generated message format is shown below.
* Sent by an application to list the details of a DOI definition. On
* success the kernel should send a response using the following format.
*
* +---------------+
* | DOI (32 bits) |
* +---------------+
* Required attributes:
*
* DOI: the DOI value
* NLBL_CIPSOV4_A_DOI
*
* The valid response message format depends on the type of the DOI mapping,
* the known formats are shown below.
*
* +--------------------+
* | map type (32 bits) | ...
* +--------------------+
*
* map type: the DOI mapping table type (defined in the cipso_ipv4.h
* header as CIPSO_V4_MAP_*)
*
* (map type == CIPSO_V4_MAP_STD)
*
* +----------------+------------------+----------------------+
* | tags (32 bits) | levels (32 bits) | categories (32 bits) | ...
* +----------------+------------------+----------------------+
* the defined formats are shown below.
*
* +-----------------+
* | tag #X (8 bits) | ... repeated
* +-----------------+
* Required attributes:
*
* +--------------------------+-------------------------+
* | local level #X (32 bits) | CIPSO level #X (8 bits) | ... repeated
* +--------------------------+-------------------------+
* NLBL_CIPSOV4_A_MTYPE
* NLBL_CIPSOV4_A_TAGLST
*
* +-----------------------------+-----------------------------+
* | local category #X (32 bits) | CIPSO category #X (16 bits) | ... repeated
* +-----------------------------+-----------------------------+
* If using CIPSO_V4_MAP_STD the following attributes are required:
*
* tags: the number of CIPSO tag types
* levels: the number of level mappings
* categories: the number of category mappings
* tag: the tag number, tags listed first are given higher
* priority when sending packets
* local level: the local part of a level mapping
* CIPSO level: the remote/CIPSO part of a level mapping
* local category: the local part of a category mapping
* CIPSO category: the remote/CIPSO part of a category mapping
* NLBL_CIPSOV4_A_MLSLVLLST
* NLBL_CIPSOV4_A_MLSCATLST
*
* (map type == CIPSO_V4_MAP_PASS)
*
* +----------------+
* | tags (32 bits) | ...
* +----------------+
*
* +-----------------+
* | tag #X (8 bits) | ... repeated
* +-----------------+
*
* tags: the number of CIPSO tag types
* tag: the tag number, tags listed first are given higher
* priority when sending packets
* 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. There is no payload and the kernel should respond with an ACK
* or the following message.
*
* +---------------------+------------------+-----------------------+
* | DOI count (32 bits) | DOI #X (32 bits) | map type #X (32 bits) |
* +---------------------+------------------+-----------------------+
* 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.
*
* +-----------------------+
* | map type #X (32 bits) | ...
* +-----------------------+
* Required attributes:
*
* DOI count: the number of DOIs
* DOI: the DOI value
* map type: the DOI mapping table type (defined in the cipso_ipv4.h
* header as CIPSO_V4_MAP_*)
* NLBL_CIPSOV4_A_DOI
* NLBL_CIPSOV4_A_MTYPE
*
*/
/* NetLabel CIPSOv4 commands */
enum {
NLBL_CIPSOV4_C_UNSPEC,
NLBL_CIPSOV4_C_ACK,
NLBL_CIPSOV4_C_ADD,
NLBL_CIPSOV4_C_REMOVE,
NLBL_CIPSOV4_C_LIST,
......@@ -211,6 +107,59 @@ enum {
};
#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);
......
......@@ -354,160 +354,51 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
}
/**
* netlbl_domhsh_dump - Dump the domain hash table into a sk_buff
* 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:
* Dump the domain hash table into a buffer suitable for returning to an
* application in response to a NetLabel management DOMAIN message. This
* function may fail if another process is growing the hash table at the same
* time. The returned sk_buff has room at the front of the sk_buff for
* @headroom bytes. See netlabel.h for the DOMAIN message format. Returns a
* pointer to a sk_buff on success, NULL on error.
* 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.
*
*/
struct sk_buff *netlbl_domhsh_dump(size_t headroom)
int netlbl_domhsh_walk(u32 *skip_bkt,
u32 *skip_chain,
int (*callback) (struct netlbl_dom_map *entry, void *arg),
void *cb_arg)
{
struct sk_buff *skb = NULL;
ssize_t buf_len;
u32 bkt_iter;
u32 dom_cnt = 0;
struct netlbl_domhsh_tbl *hsh_tbl;
struct netlbl_dom_map *list_iter;
ssize_t tmp_len;
int ret_val = -ENOENT;
u32 iter_bkt;
struct netlbl_dom_map *iter_entry;
u32 chain_cnt = 0;
buf_len = NETLBL_LEN_U32;
rcu_read_lock();
hsh_tbl = rcu_dereference(netlbl_domhsh);
for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++)
list_for_each_entry_rcu(list_iter,
&hsh_tbl->tbl[bkt_iter], list) {
buf_len += NETLBL_LEN_U32 +
nla_total_size(strlen(list_iter->domain) + 1);
switch (list_iter->type) {
case NETLBL_NLTYPE_UNLABELED:
break;
case NETLBL_NLTYPE_CIPSOV4:
buf_len += 2 * NETLBL_LEN_U32;
break;
}
dom_cnt++;
}
skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC);
if (skb == NULL)
goto dump_failure;
if (nla_put_u32(skb, NLA_U32, dom_cnt) != 0)
goto dump_failure;
buf_len -= NETLBL_LEN_U32;
hsh_tbl = rcu_dereference(netlbl_domhsh);
for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++)
list_for_each_entry_rcu(list_iter,
&hsh_tbl->tbl[bkt_iter], list) {
tmp_len = nla_total_size(strlen(list_iter->domain) +
1);
if (buf_len < NETLBL_LEN_U32 + tmp_len)
goto dump_failure;
if (nla_put_string(skb,
NLA_STRING,
list_iter->domain) != 0)
goto dump_failure;
if (nla_put_u32(skb, NLA_U32, list_iter->type) != 0)
goto dump_failure;
buf_len -= NETLBL_LEN_U32 + tmp_len;
switch (list_iter->type) {
case NETLBL_NLTYPE_UNLABELED:
break;
case NETLBL_NLTYPE_CIPSOV4:
if (buf_len < 2 * NETLBL_LEN_U32)
goto dump_failure;
if (nla_put_u32(skb,
NLA_U32,
list_iter->type_def.cipsov4->type) != 0)
goto dump_failure;
if (nla_put_u32(skb,
NLA_U32,
list_iter->type_def.cipsov4->doi) != 0)
goto dump_failure;
buf_len -= 2 * NETLBL_LEN_U32;
break;
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;
}
}
}
rcu_read_unlock();
return skb;
dump_failure:
rcu_read_unlock();
kfree_skb(skb);
return NULL;
}
/**
* netlbl_domhsh_dump_default - Dump the default domain mapping into a sk_buff
*
* Description:
* Dump the default domain mapping into a buffer suitable for returning to an
* application in response to a NetLabel management DEFDOMAIN message. This
* function may fail if another process is changing the default domain mapping
* at the same time. The returned sk_buff has room at the front of the
* skb_buff for @headroom bytes. See netlabel.h for the DEFDOMAIN message
* format. Returns a pointer to a sk_buff on success, NULL on error.
*
*/
struct sk_buff *netlbl_domhsh_dump_default(size_t headroom)
{
struct sk_buff *skb;
ssize_t buf_len;
struct netlbl_dom_map *entry;
buf_len = NETLBL_LEN_U32;
rcu_read_lock();
entry = rcu_dereference(netlbl_domhsh_def);
if (entry != NULL)
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
break;
case NETLBL_NLTYPE_CIPSOV4:
buf_len += 2 * NETLBL_LEN_U32;
break;
}
skb = netlbl_netlink_alloc_skb(headroom, buf_len, GFP_ATOMIC);
if (skb == NULL)
goto dump_default_failure;
if (entry != rcu_dereference(netlbl_domhsh_def))
goto dump_default_failure;
if (entry != NULL) {
if (nla_put_u32(skb, NLA_U32, entry->type) != 0)
goto dump_default_failure;
buf_len -= NETLBL_LEN_U32;
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
break;
case NETLBL_NLTYPE_CIPSOV4:
if (buf_len < 2 * NETLBL_LEN_U32)
goto dump_default_failure;
if (nla_put_u32(skb,
NLA_U32,
entry->type_def.cipsov4->type) != 0)
goto dump_default_failure;
if (nla_put_u32(skb,
NLA_U32,
entry->type_def.cipsov4->doi) != 0)
goto dump_default_failure;
buf_len -= 2 * NETLBL_LEN_U32;
break;
}
} else
nla_put_u32(skb, NLA_U32, NETLBL_NLTYPE_NONE);
rcu_read_unlock();
return skb;
}
dump_default_failure:
walk_return:
rcu_read_unlock();
kfree_skb(skb);
return NULL;
*skip_bkt = iter_bkt;
*skip_chain = chain_cnt;
return ret_val;
}
......@@ -61,7 +61,9 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry);
int netlbl_domhsh_add_default(struct netlbl_dom_map *entry);
int netlbl_domhsh_remove_default(void);
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
struct sk_buff *netlbl_domhsh_dump(size_t headroom);
struct sk_buff *netlbl_domhsh_dump_default(size_t headroom);
int netlbl_domhsh_walk(u32 *skip_bkt,
u32 *skip_chain,
int (*callback) (struct netlbl_dom_map *entry, void *arg),
void *cb_arg);
#endif
......@@ -84,6 +84,29 @@ int netlbl_socket_setattr(const struct socket *sock,
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
......
......@@ -42,15 +42,29 @@
#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 = 0,
.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
......@@ -70,97 +84,62 @@ static struct genl_family netlbl_mgmt_gnl_family = {
static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -EINVAL;
struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb);
int msg_len = netlbl_netlink_payload_len(skb);
u32 count;
struct netlbl_dom_map *entry = NULL;
u32 iter;
size_t tmp_size;
u32 tmp_val;
int tmp_size;
ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
if (ret_val != 0)
if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
!info->attrs[NLBL_MGMT_A_PROTOCOL])
goto add_failure;
if (msg_len < NETLBL_LEN_U32)
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;
count = netlbl_getinc_u32(&msg_ptr, &msg_len);
}
entry->type = nla_get_u32(info->attrs[NLBL_MGMT_A_PROTOCOL]);
nla_strlcpy(entry->domain, info->attrs[NLBL_MGMT_A_DOMAIN], tmp_size);
for (iter = 0; iter < count && msg_len > 0; iter++, entry = NULL) {
if (msg_len <= 0) {
ret_val = -EINVAL;
goto add_failure;
}
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (entry == NULL) {
ret_val = -ENOMEM;
goto add_failure;
}
tmp_size = nla_len(msg_ptr);
if (tmp_size <= 0 || tmp_size > msg_len) {
ret_val = -EINVAL;
goto add_failure;
}
entry->domain = kmalloc(tmp_size, GFP_KERNEL);
if (entry->domain == NULL) {
ret_val = -ENOMEM;
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
ret_val = netlbl_domhsh_add(entry);
break;
case NETLBL_NLTYPE_CIPSOV4:
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
goto add_failure;
}
nla_strlcpy(entry->domain, msg_ptr, tmp_size);
entry->domain[tmp_size - 1] = '\0';
msg_ptr = nla_next(msg_ptr, &msg_len);
if (msg_len < NETLBL_LEN_U32) {
ret_val = -EINVAL;
goto add_failure;
}
tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len);
entry->type = tmp_val;
switch (tmp_val) {
case NETLBL_NLTYPE_UNLABELED:
ret_val = netlbl_domhsh_add(entry);
break;
case NETLBL_NLTYPE_CIPSOV4:
if (msg_len < NETLBL_LEN_U32) {
ret_val = -EINVAL;
goto add_failure;
}
tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len);
/* 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();
ret_val = -EINVAL;
goto add_failure;
}
ret_val = netlbl_domhsh_add(entry);
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();
break;
default:
ret_val = -EINVAL;
}
if (ret_val != 0)
goto add_failure;
}
ret_val = netlbl_domhsh_add(entry);
rcu_read_unlock();
break;
default:
goto add_failure;
}
if (ret_val != 0)
goto add_failure;
netlbl_netlink_send_ack(info,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_ACK,
NETLBL_E_OK);
return 0;
add_failure:
if (entry)
kfree(entry->domain);
kfree(entry);
netlbl_netlink_send_ack(info,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_ACK,
-ret_val);
return ret_val;
}
......@@ -176,87 +155,98 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
*/
static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -EINVAL;
struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb);
int msg_len = netlbl_netlink_payload_len(skb);
u32 count;
u32 iter;
int tmp_size;
unsigned char *domain;
ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
if (ret_val != 0)
goto remove_return;
char *domain;
if (msg_len < NETLBL_LEN_U32)
goto remove_return;
count = netlbl_getinc_u32(&msg_ptr, &msg_len);
if (!info->attrs[NLBL_MGMT_A_DOMAIN])
return -EINVAL;
for (iter = 0; iter < count && msg_len > 0; iter++) {
if (msg_len <= 0) {
ret_val = -EINVAL;
goto remove_return;
}
tmp_size = nla_len(msg_ptr);
domain = nla_data(msg_ptr);
if (tmp_size <= 0 || tmp_size > msg_len ||
domain[tmp_size - 1] != '\0') {
ret_val = -EINVAL;
goto remove_return;
}
ret_val = netlbl_domhsh_remove(domain);
domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
return netlbl_domhsh_remove(domain);
}
/**
* 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 = netlbl_netlink_hdr_put(cb_arg->skb,
NETLINK_CB(cb_arg->nl_cb->skb).pid,
cb_arg->seq,
netlbl_mgmt_gnl_family.id,
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 remove_return;
msg_ptr = nla_next(msg_ptr, &msg_len);
goto listall_cb_failure;
break;
}
ret_val = 0;
cb_arg->seq++;
return genlmsg_end(cb_arg->skb, data);
remove_return:
netlbl_netlink_send_ack(info,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_ACK,
-ret_val);
listall_cb_failure:
genlmsg_cancel(cb_arg->skb, data);
return ret_val;
}
/**
* netlbl_mgmt_list - Handle a LIST message
* netlbl_mgmt_listall - Handle a LISTALL message
* @skb: the NETLINK buffer
* @info: the Generic NETLINK info block
* @cb: the NETLINK callback
*
* Description:
* Process a user generated LIST message and dumps the domain hash table in a
* form suitable for use in a kernel generated LIST message. Returns zero on
* success, negative values on failure.
* 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_list(struct sk_buff *skb, struct genl_info *info)
static int netlbl_mgmt_listall(struct sk_buff *skb,
struct netlink_callback *cb)
{
int ret_val = -ENOMEM;
struct sk_buff *ans_skb;
ans_skb = netlbl_domhsh_dump(NLMSG_SPACE(GENL_HDRLEN));
if (ans_skb == NULL)
goto list_failure;
netlbl_netlink_hdr_push(ans_skb,
info->snd_pid,
0,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_LIST);
ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
if (ret_val != 0)
goto list_failure;
return 0;
list_failure:
netlbl_netlink_send_ack(info,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_ACK,
-ret_val);
return ret_val;
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;
}
/**
......@@ -272,68 +262,51 @@ static int netlbl_mgmt_list(struct sk_buff *skb, struct genl_info *info)
static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -EINVAL;
struct nlattr *msg_ptr = netlbl_netlink_payload_data(skb);
int msg_len = netlbl_netlink_payload_len(skb);
struct netlbl_dom_map *entry = NULL;
u32 tmp_val;
ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
if (ret_val != 0)
goto adddef_failure;
if (msg_len < NETLBL_LEN_U32)
if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
goto adddef_failure;
tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len);
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]);
entry->type = tmp_val;
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
ret_val = netlbl_domhsh_add_default(entry);
break;
case NETLBL_NLTYPE_CIPSOV4:
if (msg_len < NETLBL_LEN_U32) {
ret_val = -EINVAL;
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
goto adddef_failure;
}
tmp_val = netlbl_getinc_u32(&msg_ptr, &msg_len);
/* 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 are going
* to skip the lock. */
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();
ret_val = -EINVAL;
goto adddef_failure;
}
ret_val = netlbl_domhsh_add_default(entry);
rcu_read_unlock();
break;
default:
ret_val = -EINVAL;
goto adddef_failure;
}
if (ret_val != 0)
goto adddef_failure;
netlbl_netlink_send_ack(info,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_ACK,
NETLBL_E_OK);
return 0;
adddef_failure:
kfree(entry);
netlbl_netlink_send_ack(info,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_ACK,
-ret_val);
return ret_val;
}
......@@ -349,20 +322,7 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
*/
static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
{
int ret_val;
ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
if (ret_val != 0)
goto removedef_return;
ret_val = netlbl_domhsh_remove_default();
removedef_return:
netlbl_netlink_send_ack(info,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_ACK,
-ret_val);
return ret_val;
return netlbl_domhsh_remove_default();
}
/**
......@@ -379,87 +339,130 @@ static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -ENOMEM;
struct sk_buff *ans_skb;
struct sk_buff *ans_skb = NULL;
void *data;
struct netlbl_dom_map *entry;
ans_skb = netlbl_domhsh_dump_default(NLMSG_SPACE(GENL_HDRLEN));
ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (ans_skb == NULL)
return -ENOMEM;
data = netlbl_netlink_hdr_put(ans_skb,
info->snd_pid,
info->snd_seq,
netlbl_mgmt_gnl_family.id,
0,
NLBL_MGMT_C_LISTDEF);
if (data == NULL)
goto listdef_failure;
netlbl_netlink_hdr_push(ans_skb,
info->snd_pid,
0,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_LISTDEF);
ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
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;
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_unicast(ans_skb, info->snd_pid);
if (ret_val != 0)
goto listdef_failure;
return 0;
listdef_failure_lock:
rcu_read_unlock();
listdef_failure:
netlbl_netlink_send_ack(info,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_ACK,
-ret_val);
kfree_skb(ans_skb);
return ret_val;
}
/**
* netlbl_mgmt_modules - Handle a MODULES message
* @skb: the NETLINK buffer
* @info: the Generic NETLINK info block
* 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:
* Process a user generated MODULES message and respond accordingly.
* 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_modules(struct sk_buff *skb, struct genl_info *info)
static int netlbl_mgmt_protocols_cb(struct sk_buff *skb,
struct netlink_callback *cb,
u32 protocol)
{
int ret_val = -ENOMEM;
size_t data_size;
u32 mod_count;
struct sk_buff *ans_skb = NULL;
/* unlabeled + cipsov4 */
mod_count = 2;
data_size = GENL_HDRLEN + NETLBL_LEN_U32 + mod_count * NETLBL_LEN_U32;
ans_skb = netlbl_netlink_alloc_skb(0, data_size, GFP_KERNEL);
if (ans_skb == NULL)
goto modules_failure;
if (netlbl_netlink_hdr_put(ans_skb,
info->snd_pid,
0,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_MODULES) == NULL)
goto modules_failure;
ret_val = nla_put_u32(ans_skb, NLA_U32, mod_count);
if (ret_val != 0)
goto modules_failure;
ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_NLTYPE_UNLABELED);
void *data;
data = netlbl_netlink_hdr_put(skb,
NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq,
netlbl_mgmt_gnl_family.id,
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 modules_failure;
ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_NLTYPE_CIPSOV4);
if (ret_val != 0)
goto modules_failure;
ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
if (ret_val != 0)
goto modules_failure;
goto protocols_cb_failure;
return 0;
return genlmsg_end(skb, data);
modules_failure:
kfree_skb(ans_skb);
netlbl_netlink_send_ack(info,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_ACK,
-ret_val);
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
......@@ -474,35 +477,35 @@ 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 = netlbl_netlink_alloc_skb(0,
GENL_HDRLEN + NETLBL_LEN_U32,
GFP_KERNEL);
ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (ans_skb == NULL)
goto version_failure;
if (netlbl_netlink_hdr_put(ans_skb,
info->snd_pid,
0,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_VERSION) == NULL)
return -ENOMEM;
data = netlbl_netlink_hdr_put(ans_skb,
info->snd_pid,
info->snd_seq,
netlbl_mgmt_gnl_family.id,
0,
NLBL_MGMT_C_VERSION);
if (data == NULL)
goto version_failure;
ret_val = nla_put_u32(ans_skb, NLA_U32, NETLBL_PROTO_VERSION);
ret_val = nla_put_u32(ans_skb,
NLBL_MGMT_A_VERSION,
NETLBL_PROTO_VERSION);
if (ret_val != 0)
goto version_failure;
ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
genlmsg_end(ans_skb, data);
ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
if (ret_val != 0)
goto version_failure;
return 0;
version_failure:
kfree_skb(ans_skb);
netlbl_netlink_send_ack(info,
netlbl_mgmt_gnl_family.id,
NLBL_MGMT_C_ACK,
-ret_val);
return ret_val;
}
......@@ -513,35 +516,40 @@ static int netlbl_mgmt_version(struct sk_buff *skb, struct genl_info *info)
static struct genl_ops netlbl_mgmt_genl_c_add = {
.cmd = NLBL_MGMT_C_ADD,
.flags = 0,
.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 = 0,
.flags = GENL_ADMIN_PERM,
.policy = netlbl_mgmt_genl_policy,
.doit = netlbl_mgmt_remove,
.dumpit = NULL,
};
static struct genl_ops netlbl_mgmt_genl_c_list = {
.cmd = NLBL_MGMT_C_LIST,
static struct genl_ops netlbl_mgmt_genl_c_listall = {
.cmd = NLBL_MGMT_C_LISTALL,
.flags = 0,
.doit = netlbl_mgmt_list,
.dumpit = NULL,
.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 = 0,
.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 = 0,
.flags = GENL_ADMIN_PERM,
.policy = netlbl_mgmt_genl_policy,
.doit = netlbl_mgmt_removedef,
.dumpit = NULL,
};
......@@ -549,20 +557,23 @@ static struct genl_ops netlbl_mgmt_genl_c_removedef = {
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_modules = {
.cmd = NLBL_MGMT_C_MODULES,
static struct genl_ops netlbl_mgmt_genl_c_protocols = {
.cmd = NLBL_MGMT_C_PROTOCOLS,
.flags = 0,
.doit = netlbl_mgmt_modules,
.dumpit = NULL,
.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,
};
......@@ -596,7 +607,7 @@ int netlbl_mgmt_genl_init(void)
if (ret_val != 0)
return ret_val;
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
&netlbl_mgmt_genl_c_list);
&netlbl_mgmt_genl_c_listall);
if (ret_val != 0)
return ret_val;
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
......@@ -612,7 +623,7 @@ int netlbl_mgmt_genl_init(void)
if (ret_val != 0)
return ret_val;
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
&netlbl_mgmt_genl_c_modules);
&netlbl_mgmt_genl_c_protocols);
if (ret_val != 0)
return ret_val;
ret_val = genl_register_ops(&netlbl_mgmt_gnl_family,
......
......@@ -34,212 +34,137 @@
#include <net/netlabel.h>
/*
* The following NetLabel payloads are supported by the management interface,
* all of which are preceeded by the nlmsghdr struct.
*
* o ACK:
* Sent by the kernel in response to an applications message, applications
* should never send this message.
*
* +----------------------+-----------------------+
* | seq number (32 bits) | return code (32 bits) |
* +----------------------+-----------------------+
*
* seq number: the sequence number of the original message, taken from the
* nlmsghdr structure
* return code: return value, based on errno values
* 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.
* The kernel should respond with an ACK.
*
* +-------------------+
* | domains (32 bits) | ...
* +-------------------+
*
* domains: the number of domains in the message
*
* +--------------------------+-------------------------+
* | domain string (variable) | protocol type (32 bits) | ...
* +--------------------------+-------------------------+
*
* +-------------- ---- --- -- -
* | mapping data ... repeated
* +-------------- ---- --- -- -
* Required attributes:
*
* domain string: the domain string, NULL terminated
* protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
* mapping data: specific to the map type (see below)
* NLBL_MGMT_A_DOMAIN
* NLBL_MGMT_A_PROTOCOL
*
* NETLBL_NLTYPE_UNLABELED
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
*
* No mapping data for this protocol type.
* NLBL_MGMT_A_CV4DOI
*
* NETLBL_NLTYPE_CIPSOV4
*
* +---------------+
* | doi (32 bits) |
* +---------------+
*
* doi: the CIPSO DOI value
* 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. The kernel should ACK this message.
*
* +-------------------+
* | domains (32 bits) | ...
* +-------------------+
* system.
*
* domains: the number of domains in the message
* Required attributes:
*
* +--------------------------+
* | domain string (variable) | ...
* +--------------------------+
* NLBL_MGMT_A_DOMAIN
*
* domain string: the domain string, NULL terminated
*
* o LIST:
* o LISTALL:
* 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 either with a LIST message on success or an ACK message on
* failure.
*
* +-------------------+
* | domains (32 bits) | ...
* +-------------------+
*
* domains: the number of domains in the message
* 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.
*
* +--------------------------+
* | domain string (variable) | ...
* +--------------------------+
* Required attributes:
*
* +-------------------------+-------------- ---- --- -- -
* | protocol type (32 bits) | mapping data ... repeated
* +-------------------------+-------------- ---- --- -- -
* NLBL_MGMT_A_DOMAIN
* NLBL_MGMT_A_PROTOCOL
*
* domain string: the domain string, NULL terminated
* protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
* mapping data: specific to the map type (see below)
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
*
* NETLBL_NLTYPE_UNLABELED
* NLBL_MGMT_A_CV4DOI
*
* No mapping data for this protocol type.
*
* NETLBL_NLTYPE_CIPSOV4
*
* +----------------+---------------+
* | type (32 bits) | doi (32 bits) |
* +----------------+---------------+
*
* type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
* as CIPSO_V4_MAP_*)
* doi: the CIPSO DOI value
* 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. The kernel should respond with an ACK.
* system.
*
* +-------------------------+-------------- ---- --- -- -
* | protocol type (32 bits) | mapping data ... repeated
* +-------------------------+-------------- ---- --- -- -
* Required attributes:
*
* protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
* mapping data: specific to the map type (see below)
* NLBL_MGMT_A_PROTOCOL
*
* NETLBL_NLTYPE_UNLABELED
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
*
* No mapping data for this protocol type.
* NLBL_MGMT_A_CV4DOI
*
* NETLBL_NLTYPE_CIPSOV4
*
* +---------------+
* | doi (32 bits) |
* +---------------+
*
* doi: the CIPSO DOI value
* 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. The kernel should ACK this message.
* 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. The kernel should respond to a
* LISTDEF message either with a LISTDEF message on success or an ACK message
* on failure.
*
* +-------------------------+-------------- ---- --- -- -
* | protocol type (32 bits) | mapping data ... repeated
* +-------------------------+-------------- ---- --- -- -
* application there is no payload. On success the kernel should send a
* response using the following format.
*
* protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
* mapping data: specific to the map type (see below)
* Required attributes:
*
* NETLBL_NLTYPE_UNLABELED
* NLBL_MGMT_A_PROTOCOL
*
* No mapping data for this protocol type.
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
*
* NETLBL_NLTYPE_CIPSOV4
* NLBL_MGMT_A_CV4DOI
*
* +----------------+---------------+
* | type (32 bits) | doi (32 bits) |
* +----------------+---------------+
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
*
* type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
* as CIPSO_V4_MAP_*)
* doi: the CIPSO DOI value
* 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.
*
* o MODULES:
* Sent by an application to request a list of configured NetLabel modules
* in the kernel. When sent by an application there is no payload.
* Required attributes:
*
* +-------------------+
* | modules (32 bits) | ...
* +-------------------+
*
* modules: the number of modules in the message, if this is an application
* generated message and the value is zero then return a list of
* the configured modules
*
* +------------------+
* | module (32 bits) | ... repeated
* +------------------+
*
* module: the module number as defined by NETLBL_NLTYPE_*
* NLBL_MGMT_A_PROTOCOL
*
* o VERSION:
* Sent by an application to request the NetLabel version string. When sent
* by an application there is no payload. This message type is also used by
* the kernel to respond to an VERSION request.
* 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.
*
* +-------------------+
* | version (32 bits) |
* +-------------------+
* Required attributes:
*
* version: the protocol version number
* NLBL_MGMT_A_VERSION
*
*/
/* NetLabel Management commands */
enum {
NLBL_MGMT_C_UNSPEC,
NLBL_MGMT_C_ACK,
NLBL_MGMT_C_ADD,
NLBL_MGMT_C_REMOVE,
NLBL_MGMT_C_LIST,
NLBL_MGMT_C_LISTALL,
NLBL_MGMT_C_ADDDEF,
NLBL_MGMT_C_REMOVEDEF,
NLBL_MGMT_C_LISTDEF,
NLBL_MGMT_C_MODULES,
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);
......
......@@ -55,9 +55,13 @@ static struct genl_family netlbl_unlabel_gnl_family = {
.hdrsize = 0,
.name = NETLBL_NLTYPE_UNLABELED_NAME,
.version = NETLBL_PROTO_VERSION,
.maxattr = 0,
.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 },
};
/*
* NetLabel Command Handlers
......@@ -75,31 +79,18 @@ static struct genl_family netlbl_unlabel_gnl_family = {
*/
static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
{
int ret_val;
struct nlattr *data = netlbl_netlink_payload_data(skb);
u32 value;
ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
if (ret_val != 0)
return ret_val;
int ret_val = -EINVAL;
u8 value;
if (netlbl_netlink_payload_len(skb) == NETLBL_LEN_U32) {
value = nla_get_u32(data);
if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
if (value == 1 || value == 0) {
atomic_set(&netlabel_unlabel_accept_flg, value);
netlbl_netlink_send_ack(info,
netlbl_unlabel_gnl_family.id,
NLBL_UNLABEL_C_ACK,
NETLBL_E_OK);
return 0;
ret_val = 0;
}
}
netlbl_netlink_send_ack(info,
netlbl_unlabel_gnl_family.id,
NLBL_UNLABEL_C_ACK,
EINVAL);
return -EINVAL;
return ret_val;
}
/**
......@@ -114,39 +105,39 @@ static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
*/
static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -ENOMEM;
int ret_val = -EINVAL;
struct sk_buff *ans_skb;
void *data;
ans_skb = netlbl_netlink_alloc_skb(0,
GENL_HDRLEN + NETLBL_LEN_U32,
GFP_KERNEL);
ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
if (ans_skb == NULL)
goto list_failure;
if (netlbl_netlink_hdr_put(ans_skb,
info->snd_pid,
0,
netlbl_unlabel_gnl_family.id,
NLBL_UNLABEL_C_LIST) == NULL)
data = netlbl_netlink_hdr_put(ans_skb,
info->snd_pid,
info->snd_seq,
netlbl_unlabel_gnl_family.id,
0,
NLBL_UNLABEL_C_LIST);
if (data == NULL) {
ret_val = -ENOMEM;
goto list_failure;
}
ret_val = nla_put_u32(ans_skb,
NLA_U32,
atomic_read(&netlabel_unlabel_accept_flg));
ret_val = nla_put_u8(ans_skb,
NLBL_UNLABEL_A_ACPTFLG,
atomic_read(&netlabel_unlabel_accept_flg));
if (ret_val != 0)
goto list_failure;
ret_val = netlbl_netlink_snd(ans_skb, info->snd_pid);
genlmsg_end(ans_skb, data);
ret_val = genlmsg_unicast(ans_skb, info->snd_pid);
if (ret_val != 0)
goto list_failure;
return 0;
list_failure:
netlbl_netlink_send_ack(info,
netlbl_unlabel_gnl_family.id,
NLBL_UNLABEL_C_ACK,
-ret_val);
kfree(ans_skb);
return ret_val;
}
......@@ -157,7 +148,8 @@ static int netlbl_unlabel_list(struct sk_buff *skb, struct genl_info *info)
static struct genl_ops netlbl_unlabel_genl_c_accept = {
.cmd = NLBL_UNLABEL_C_ACCEPT,
.flags = 0,
.flags = GENL_ADMIN_PERM,
.policy = netlbl_unlabel_genl_policy,
.doit = netlbl_unlabel_accept,
.dumpit = NULL,
};
......@@ -165,6 +157,7 @@ static struct genl_ops netlbl_unlabel_genl_c_accept = {
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,
};
......@@ -218,10 +211,8 @@ int netlbl_unlabel_genl_init(void)
*/
int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr)
{
if (atomic_read(&netlabel_unlabel_accept_flg) == 1) {
memset(secattr, 0, sizeof(*secattr));
return 0;
}
if (atomic_read(&netlabel_unlabel_accept_flg) == 1)
return netlbl_secattr_init(secattr);
return -ENOMSG;
}
......
......@@ -36,56 +36,47 @@
/*
* The following NetLabel payloads are supported by the Unlabeled subsystem.
*
* o ACK:
* Sent by the kernel in response to an applications message, applications
* should never send this message.
*
* +----------------------+-----------------------+
* | seq number (32 bits) | return code (32 bits) |
* +----------------------+-----------------------+
*
* seq number: the sequence number of the original message, taken from the
* nlmsghdr structure
* return code: return value, based on errno values
*
* 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.
*
* +-----------------+
* | allow (32 bits) |
* +-----------------+
* Required attributes:
*
* allow: if true (1) then allow the packets to pass, if false (0) then
* reject the packets
* 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 either with a LIST message on success or an ACK message on
* failure.
* message with a LIST message on success.
*
* +-----------------------+
* | accept flag (32 bits) |
* +-----------------------+
* Required attributes:
*
* accept flag: if true (1) then unlabeled packets are allowed to pass,
* if false (0) then unlabeled packets are rejected
* NLBL_UNLABEL_A_ACPTFLG
*
*/
/* NetLabel Unlabeled commands */
enum {
NLBL_UNLABEL_C_UNSPEC,
NLBL_UNLABEL_C_ACK,
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);
......
......@@ -74,85 +74,3 @@ int netlbl_netlink_init(void)
return 0;
}
/*
* NetLabel Common Protocol Functions
*/
/**
* netlbl_netlink_send_ack - Send an ACK message
* @info: the generic NETLINK information
* @genl_family: the generic NETLINK family ID value
* @ack_cmd: the generic NETLINK family ACK command value
* @ret_code: return code to use
*
* Description:
* This function sends an ACK message to the sender of the NETLINK message
* specified by @info.
*
*/
void netlbl_netlink_send_ack(const struct genl_info *info,
u32 genl_family,
u8 ack_cmd,
u32 ret_code)
{
size_t data_size;
struct sk_buff *skb;
data_size = GENL_HDRLEN + 2 * NETLBL_LEN_U32;
skb = netlbl_netlink_alloc_skb(0, data_size, GFP_KERNEL);
if (skb == NULL)
return;
if (netlbl_netlink_hdr_put(skb,
info->snd_pid,
0,
genl_family,
ack_cmd) == NULL)
goto send_ack_failure;
if (nla_put_u32(skb, NLA_U32, info->snd_seq) != 0)
goto send_ack_failure;
if (nla_put_u32(skb, NLA_U32, ret_code) != 0)
goto send_ack_failure;
netlbl_netlink_snd(skb, info->snd_pid);
return;
send_ack_failure:
kfree_skb(skb);
}
/*
* NETLINK I/O Functions
*/
/**
* netlbl_netlink_snd - Send a NetLabel message
* @skb: NetLabel message
* @pid: destination PID
*
* Description:
* Sends a unicast NetLabel message over the NETLINK socket.
*
*/
int netlbl_netlink_snd(struct sk_buff *skb, u32 pid)
{
return genlmsg_unicast(skb, pid);
}
/**
* netlbl_netlink_snd - Send a NetLabel message
* @skb: NetLabel message
* @pid: sending PID
* @group: multicast group id
*
* Description:
* Sends a multicast NetLabel message over the NETLINK socket to all members
* of @group except @pid.
*
*/
int netlbl_netlink_snd_multicast(struct sk_buff *skb, u32 pid, u32 group)
{
return genlmsg_multicast(skb, pid, group, GFP_KERNEL);
}
......@@ -40,72 +40,6 @@
/* NetLabel NETLINK helper functions */
/**
* netlbl_netlink_cap_check - Check the NETLINK msg capabilities
* @skb: the NETLINK buffer
* @req_cap: the required capability
*
* Description:
* Check the NETLINK buffer's capabilities against the required capabilities.
* Returns zero on success, negative values on failure.
*
*/
static inline int netlbl_netlink_cap_check(const struct sk_buff *skb,
kernel_cap_t req_cap)
{
if (cap_raised(NETLINK_CB(skb).eff_cap, req_cap))
return 0;
return -EPERM;
}
/**
* netlbl_getinc_u8 - Read a u8 value from a nlattr stream and move on
* @nla: the attribute
* @rem_len: remaining length
*
* Description:
* Return a u8 value pointed to by @nla and advance it to the next attribute.
*
*/
static inline u8 netlbl_getinc_u8(struct nlattr **nla, int *rem_len)
{
u8 val = nla_get_u8(*nla);
*nla = nla_next(*nla, rem_len);
return val;
}
/**
* netlbl_getinc_u16 - Read a u16 value from a nlattr stream and move on
* @nla: the attribute
* @rem_len: remaining length
*
* Description:
* Return a u16 value pointed to by @nla and advance it to the next attribute.
*
*/
static inline u16 netlbl_getinc_u16(struct nlattr **nla, int *rem_len)
{
u16 val = nla_get_u16(*nla);
*nla = nla_next(*nla, rem_len);
return val;
}
/**
* netlbl_getinc_u32 - Read a u32 value from a nlattr stream and move on
* @nla: the attribute
* @rem_len: remaining length
*
* Description:
* Return a u32 value pointed to by @nla and advance it to the next attribute.
*
*/
static inline u32 netlbl_getinc_u32(struct nlattr **nla, int *rem_len)
{
u32 val = nla_get_u32(*nla);
*nla = nla_next(*nla, rem_len);
return val;
}
/**
* netlbl_netlink_hdr_put - Write the NETLINK buffers into a sk_buff
* @skb: the packet
......@@ -124,6 +58,7 @@ static inline void *netlbl_netlink_hdr_put(struct sk_buff *skb,
u32 pid,
u32 seq,
int type,
int flags,
u8 cmd)
{
return genlmsg_put(skb,
......@@ -131,85 +66,13 @@ static inline void *netlbl_netlink_hdr_put(struct sk_buff *skb,
seq,
type,
0,
0,
flags,
cmd,
NETLBL_PROTO_VERSION);
}
/**
* netlbl_netlink_hdr_push - Write the NETLINK buffers into a sk_buff
* @skb: the packet
* @pid: the PID of the receipient
* @seq: the sequence number
* @type: the generic NETLINK message family type
* @cmd: command
*
* Description:
* Write both a NETLINK nlmsghdr structure and a Generic NETLINK genlmsghdr
* struct to the packet.
*
*/
static inline void netlbl_netlink_hdr_push(struct sk_buff *skb,
u32 pid,
u32 seq,
int type,
u8 cmd)
{
struct nlmsghdr *nlh;
struct genlmsghdr *hdr;
nlh = (struct nlmsghdr *)skb_push(skb, NLMSG_SPACE(GENL_HDRLEN));
nlh->nlmsg_type = type;
nlh->nlmsg_len = skb->len;
nlh->nlmsg_flags = 0;
nlh->nlmsg_pid = pid;
nlh->nlmsg_seq = seq;
hdr = nlmsg_data(nlh);
hdr->cmd = cmd;
hdr->version = NETLBL_PROTO_VERSION;
hdr->reserved = 0;
}
/**
* netlbl_netlink_payload_len - Return the length of the payload
* @skb: the NETLINK buffer
*
* Description:
* This function returns the length of the NetLabel payload.
*
*/
static inline u32 netlbl_netlink_payload_len(const struct sk_buff *skb)
{
return nlmsg_len((struct nlmsghdr *)skb->data) - GENL_HDRLEN;
}
/**
* netlbl_netlink_payload_data - Returns a pointer to the start of the payload
* @skb: the NETLINK buffer
*
* Description:
* This function returns a pointer to the start of the NetLabel payload.
*
*/
static inline void *netlbl_netlink_payload_data(const struct sk_buff *skb)
{
return (unsigned char *)nlmsg_data((struct nlmsghdr *)skb->data) +
GENL_HDRLEN;
}
/* NetLabel common protocol functions */
void netlbl_netlink_send_ack(const struct genl_info *info,
u32 genl_family,
u8 ack_cmd,
u32 ret_code);
/* NetLabel NETLINK I/O functions */
int netlbl_netlink_init(void);
int netlbl_netlink_snd(struct sk_buff *skb, u32 pid);
int netlbl_netlink_snd_multicast(struct sk_buff *skb, u32 pid, u32 group);
#endif
......@@ -2502,14 +2502,24 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
{
struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
struct sk_security_struct *sksec = sk->sk_security;
struct netlbl_lsm_secattr secattr;
u32 nlbl_peer_sid;
sksec->sclass = isec->sclass;
if (sk->sk_family != PF_INET)
return;
netlbl_secattr_init(&secattr);
if (netlbl_sock_getattr(sk, &secattr) == 0 &&
selinux_netlbl_secattr_to_sid(NULL,
&secattr,
sksec->sid,
&nlbl_peer_sid) == 0)
sksec->peer_sid = nlbl_peer_sid;
netlbl_secattr_destroy(&secattr, 0);
sksec->nlbl_state = NLBL_REQUIRE;
sksec->peer_sid = sksec->sid;
/* Try to set the NetLabel on the socket to save time later, if we fail
* here we will pick up the pieces in later calls to
......@@ -2601,7 +2611,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
u32 netlbl_sid;
u32 recv_perm;
rc = selinux_netlbl_skbuff_getsid(skb, sksec->sid, &netlbl_sid);
rc = selinux_netlbl_skbuff_getsid(skb, SECINITSID_NETMSG, &netlbl_sid);
if (rc != 0)
return rc;
......@@ -2610,13 +2620,13 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
switch (sksec->sclass) {
case SECCLASS_UDP_SOCKET:
recv_perm = UDP_SOCKET__RECV_MSG;
recv_perm = UDP_SOCKET__RECVFROM;
break;
case SECCLASS_TCP_SOCKET:
recv_perm = TCP_SOCKET__RECV_MSG;
recv_perm = TCP_SOCKET__RECVFROM;
break;
default:
recv_perm = RAWIP_SOCKET__RECV_MSG;
recv_perm = RAWIP_SOCKET__RECVFROM;
}
rc = avc_has_perm(sksec->sid,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment