* [RFC 2/8] NetLabel: core network changes
From: paul.moore @ 2006-06-22 22:49 UTC (permalink / raw)
To: netdev; +Cc: davem
In-Reply-To: <20060622224910.885573000@flek.zko.hp.com>
[-- Attachment #1: netlabel-net_core-2.6.17 --]
[-- Type: text/plain, Size: 25376 bytes --]
Changes to the core network stack to support the NetLabel subsystem. This
includes changes to support the NetLabel NETLINK communication mechanism,
changes to the IPv4 option handling to support CIPSO labels, and a new NetLabel
hook in inet_accept() to handle NetLabel attributes across an accept().
---
include/linux/ip.h | 1
include/linux/netlink.h | 1
include/net/cipso_ipv4.h | 251 ++++++++++++++++++++++++
include/net/inet_sock.h | 2
include/net/netlabel.h | 487 +++++++++++++++++++++++++++++++++++++++++++++++
net/ipv4/Makefile | 1
net/ipv4/af_inet.c | 3
net/ipv4/ah4.c | 2
net/ipv4/ip_options.c | 19 +
9 files changed, 765 insertions(+), 2 deletions(-)
Index: linux-2.6.17.i686-quilt/include/linux/ip.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/include/linux/ip.h
+++ linux-2.6.17.i686-quilt/include/linux/ip.h
@@ -57,6 +57,7 @@
#define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY)
#define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY)
#define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT)
+#define IPOPT_CIPSO (6 |IPOPT_CONTROL|IPOPT_COPY)
#define IPOPT_RR (7 |IPOPT_CONTROL)
#define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY)
#define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY)
Index: linux-2.6.17.i686-quilt/include/linux/netlink.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/include/linux/netlink.h
+++ linux-2.6.17.i686-quilt/include/linux/netlink.h
@@ -21,6 +21,7 @@
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
#define NETLINK_GENERIC 16
+#define NETLINK_NETLABEL 17 /* Network packet labeling */
#define MAX_LINKS 32
Index: linux-2.6.17.i686-quilt/include/net/cipso_ipv4.h
===================================================================
--- /dev/null
+++ linux-2.6.17.i686-quilt/include/net/cipso_ipv4.h
@@ -0,0 +1,251 @@
+/*
+ * CIPSO - Commercial IP Security Option
+ *
+ * This is an implementation of the CIPSO 2.2 protocol as specified in
+ * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
+ * FIPS-188, copies of both documents can be found in the Documentation
+ * directory. While CIPSO never became a full IETF RFC standard many vendors
+ * have chosen to adopt the protocol and over the years it has become a
+ * de-facto standard for labeled networking.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _CIPSO_IPV4_H
+#define _CIPSO_IPV4_H
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <net/netlabel.h>
+
+/* known doi values */
+#define CIPSO_V4_DOI_UNKNOWN 0x00000000
+
+/* tag types */
+#define CIPSO_V4_TAG_INVALID 0
+#define CIPSO_V4_TAG_RBITMAP 1
+#define CIPSO_V4_TAG_ENUM 2
+#define CIPSO_V4_TAG_RANGE 5
+#define CIPSO_V4_TAG_PBITMAP 6
+#define CIPSO_V4_TAG_FREEFORM 7
+
+/* doi mapping types */
+#define CIPSO_V4_MAP_UNKNOWN 0
+#define CIPSO_V4_MAP_STD 1
+#define CIPSO_V4_MAP_PASS 2
+
+/* limits */
+#define CIPSO_V4_MAX_REM_LVLS 256
+#define CIPSO_V4_INV_LVL 0x80000000
+#define CIPSO_V4_MAX_LOC_LVLS (CIPSO_V4_INV_LVL - 1)
+#define CIPSO_V4_MAX_REM_CATS 65536
+#define CIPSO_V4_INV_CAT 0x80000000
+#define CIPSO_V4_MAX_LOC_CATS (CIPSO_V4_INV_CAT - 1)
+
+/*
+ * CIPSO DOI definitions
+ */
+
+/* DOI definition struct */
+#define CIPSO_V4_TAG_MAXCNT 5
+struct cipso_v4_doi {
+ u32 doi;
+ u32 type;
+ union {
+ struct cipso_v4_std_map_tbl *std;
+ } map;
+ u8 tags[CIPSO_V4_TAG_MAXCNT];
+
+ u32 valid;
+ struct list_head list;
+ struct rcu_head rcu;
+ struct list_head dom_list;
+};
+
+/* Standard CIPSO mapping table */
+/* NOTE: the highest order bit (i.e. 0x80000000) is an 'invalid' flag, if the
+ * bit is set then consider that value as unspecified, meaning the
+ * mapping for that particular level/category is invalid */
+struct cipso_v4_std_map_tbl {
+ struct {
+ u32 *cipso;
+ u32 *local;
+ u32 cipso_size;
+ u32 local_size;
+ } lvl;
+ struct {
+ u32 *cipso;
+ u32 *local;
+ u32 cipso_size;
+ u32 local_size;
+ } cat;
+};
+
+/*
+ * Helper Functions
+ */
+
+#define CIPSO_V4_OPTEXIST(x) (IPCB(x)->opt.cipso != 0)
+#define CIPSO_V4_OPTPTR(x) ((x)->nh.raw + IPCB(x)->opt.cipso)
+
+/*
+ * DOI List Functions
+ */
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
+int cipso_v4_doi_remove(const u32 doi,
+ void (*callback) (struct rcu_head * head));
+struct cipso_v4_doi *cipso_v4_doi_getdef(const u32 doi);
+struct sk_buff *cipso_v4_doi_dump(const u32 doi, const u32 headroom);
+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);
+#else
+static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
+{
+ return -ENOSYS;
+}
+
+static inline int cipso_v4_doi_remove(const u32 doi,
+ void (*callback) (struct rcu_head * head))
+{
+ return 0;
+}
+
+static inline struct cipso_v4_doi *cipso_v4_doi_getdef(const u32 doi)
+{
+ return NULL;
+}
+
+static inline struct sk_buff *cipso_v4_doi_dump(const u32 doi,
+ const u32 headroom)
+{
+ return NULL;
+}
+
+static inline int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def,
+ const char *domain)
+{
+ return -ENOSYS;
+}
+
+static inline int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
+ const char *domain)
+{
+ return 0;
+}
+#endif /* CONFIG_NETLABEL_CIPSOV4 */
+
+/*
+ * Label Mapping Cache Functions
+ */
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+void cipso_v4_cache_invalidate(void);
+int cipso_v4_cache_add(const struct sk_buff *skb,
+ const struct netlbl_lsm_secattr *secattr);
+#else
+static inline void cipso_v4_cache_invalidate(void)
+{
+ return;
+}
+
+static inline int cipso_v4_cache_add(const struct sk_buff *skb,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ return 0;
+}
+#endif /* CONFIG_NETLABEL_CIPSOV4 */
+
+/*
+ * Protocol Handling Functions
+ */
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+int cipso_v4_error(struct sk_buff *skb,
+ const int error,
+ const u32 gateway);
+int cipso_v4_socket_setopt(struct socket *sock,
+ unsigned char *opt,
+ u32 opt_len);
+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_socket_getopt(const struct socket *sock,
+ unsigned char **opt,
+ u32 *opt_len);
+int cipso_v4_socket_getattr(const struct socket *sock,
+ struct netlbl_lsm_secattr *secattr);
+int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
+ struct netlbl_lsm_secattr *secattr);
+int cipso_v4_validate(unsigned char **option);
+#else
+static inline int cipso_v4_error(struct sk_buff *skb,
+ const int error,
+ const u32 gateway)
+{
+ return 0;
+}
+
+static inline int cipso_v4_socket_setopt(struct socket *sock,
+ unsigned char *opt,
+ u32 opt_len)
+{
+ return -ENOSYS;
+}
+
+static inline int cipso_v4_socket_setattr(const struct socket *sock,
+ const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ return -ENOSYS;
+}
+
+static inline int cipso_v4_socket_getopt(const struct socket *sock,
+ unsigned char **opt,
+ u32 *opt_len)
+{
+ return -ENOSYS;
+}
+
+static inline int cipso_v4_socket_getattr(const struct socket *sock,
+ struct netlbl_lsm_secattr *secattr)
+{
+ return -ENOSYS;
+}
+
+static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
+ struct netlbl_lsm_secattr *secattr)
+{
+ return -ENOSYS;
+}
+
+static inline int cipso_v4_validate(unsigned char **option)
+{
+ return -ENOSYS;
+}
+#endif /* CONFIG_NETLABEL_CIPSOV4 */
+
+#endif /* _CIPSO_IPV4_H */
Index: linux-2.6.17.i686-quilt/include/net/inet_sock.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/include/net/inet_sock.h
+++ linux-2.6.17.i686-quilt/include/net/inet_sock.h
@@ -52,7 +52,7 @@ struct ip_options {
ts_needtime:1,
ts_needaddr:1;
unsigned char router_alert;
- unsigned char __pad1;
+ unsigned char cipso;
unsigned char __pad2;
unsigned char __data[0];
};
Index: linux-2.6.17.i686-quilt/include/net/netlabel.h
===================================================================
--- /dev/null
+++ linux-2.6.17.i686-quilt/include/net/netlabel.h
@@ -0,0 +1,487 @@
+/*
+ * NetLabel System
+ *
+ * The NetLabel system manages static and dynamic label mappings for network
+ * protocols such as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_H
+#define _NETLABEL_H
+
+#include <linux/types.h>
+#include <linux/skbuff.h>
+#include <net/netlink.h>
+
+/*
+ * NetLabel - A management interface for maintaining network packet label
+ * mapping tables for explicit packet labling protocols.
+ *
+ * Network protocols such as CIPSO and RIPSO require a label translation layer
+ * to convert the label on the packet into something meaningful on the host
+ * machine. In the current Linux implementation these mapping tables live
+ * inside the kernel; NetLabel provides a mechanism for user space applications
+ * to manage these mapping tables.
+ *
+ * NetLabel makes use of NETLINK as a transport layer to send messages between
+ * kernel and user space. The general format of a NetLabel message is shown
+ * below:
+ *
+ * +----------+------------------+--------- --- -- -
+ * | nlmsghdr | subsystem header | payload
+ * +----------+------------------+--------- --- -- -
+ *
+ * The 'nlmsghdr' struct should be dealt with like any other NETLINK 'nlmsghdr'
+ * struct. The subsystem header structure 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.
+ *
+ */
+
+/*
+ * NetLabel NETLINK protocol
+ */
+
+#define NETLBL_PROTO_VERSION 1
+
+/* NetLabel NETLINK groups */
+#define NETLBL_NLGRP_NONE 0x00000000
+#define NETLBL_NLGRP_MAX 0x00000000
+
+/* NetLabel NETLINK types */
+#define NETLBL_NLTYPE_NONE 0
+#define NETLBL_NLTYPE_MGMT 1
+#define NETLBL_NLTYPE_RIPSO 2
+#define NETLBL_NLTYPE_CIPSOV4 3
+#define NETLBL_NLTYPE_CIPSOV6 4
+#define NETLBL_NLTYPE_UNLABELED 5
+
+/* NetLabel return codes */
+#define NETLBL_E_OK 0
+
+/*
+ * Helper functions
+ */
+
+/**
+ * netlbl_put_u8 - Write a u8 value into a buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer.
+ *
+ */
+static inline void netlbl_put_u8(unsigned char *buffer, const u8 val)
+{
+ *(u8 *)buffer = val;
+}
+
+/**
+ * netlbl_put_u32 - Write a u32 value into a buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer.
+ *
+ */
+static inline void netlbl_put_u32(unsigned char *buffer, const u32 val)
+{
+ *(u32 *)buffer = val;
+}
+
+/**
+ * netlbl_put_str - Write a string into a buffer
+ * @buffer: the buffer
+ * @val: the string
+ *
+ * Description:
+ * Write the string specified in @val into the buffer specified by @buffer.
+ *
+ */
+static inline void netlbl_put_str(unsigned char *buffer, const char *val)
+{
+ strcpy((char *)buffer, val);
+}
+
+/**
+ * netlbl_put_hdr - Write a NETLINK header into a buffer
+ * @buffer: the buffer
+ * @msg_type: the NETLINK message type
+ * @msg_len: the NETLINK message length
+ * @msg_flags: the NETLINK message flags
+ * @msg_pid: the NETLINK message PID
+ * @msg_seq: the NETLINK message sequence number
+ *
+ * Description:
+ * Use the given values to write a NETLINK header into the given buffer.
+ *
+ */
+static inline void netlbl_put_hdr(unsigned char *buffer,
+ const u32 msg_type,
+ const u16 msg_len,
+ const u16 msg_flags,
+ const u32 msg_pid,
+ const u32 msg_seq)
+{
+ struct nlmsghdr *hdr = (struct nlmsghdr *)buffer;
+ hdr->nlmsg_len = msg_len;
+ hdr->nlmsg_type = msg_type;
+ hdr->nlmsg_flags = msg_flags;
+ hdr->nlmsg_seq = msg_seq;
+ hdr->nlmsg_pid = msg_pid;
+}
+
+/**
+ * netlbl_put_u8 - Write a u8 value into a buffer and increment the buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer
+ * and advance the buffer pointer past the newly written value.
+ *
+ */
+static inline void netlbl_putinc_u8(unsigned char **buffer, const u8 val)
+{
+ netlbl_put_u8(*buffer, val);
+ *buffer += sizeof(u8);
+}
+
+/**
+ * netlbl_put_u32 - Write a u32 value into a buffer and increment the buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the value specified in @val into the buffer specified by @buffer
+ * and advance the buffer pointer past the newly written value.
+ *
+ */
+static inline void netlbl_putinc_u32(unsigned char **buffer, const u32 val)
+{
+ netlbl_put_u32(*buffer, val);
+ *buffer += sizeof(u32);
+}
+
+/**
+ * netlbl_put_u8 - Write a string into a buffer and increment the buffer
+ * @buffer: the buffer
+ * @val: the value
+ *
+ * Description:
+ * Write the string specified in @val into the buffer specified by @buffer
+ * and advance the buffer pointer past the newly written value.
+ *
+ */
+static inline void netlbl_putinc_str(unsigned char **buffer, const char *val)
+{
+ netlbl_put_str(*buffer, val);
+ *buffer += strlen(val) + 1;
+}
+
+/**
+ * netlbl_put_hdr - Write a NETLINK header into a buffer and increment the ptr
+ * @buffer: the buffer
+ * @msg_type: the NETLINK message type
+ * @msg_len: the NETLINK message length
+ * @msg_flags: the NETLINK message flags
+ * @msg_pid: the NETLINK message PID
+ * @msg_seq: the NETLINK message sequence number
+ *
+ * Description:
+ * Use the given values to write a NETLINK header into the given buffer and
+ * then increment the buffer pointer past the header.
+ *
+ */
+static inline void netlbl_putinc_hdr(unsigned char **buffer,
+ const u32 msg_type,
+ const u16 msg_len,
+ const u16 msg_flags,
+ const u32 msg_pid,
+ const u32 msg_seq)
+{
+ netlbl_put_hdr(*buffer,
+ msg_type,
+ msg_len,
+ msg_flags,
+ msg_pid,
+ msg_seq);
+ *buffer += NLMSG_HDRLEN;
+}
+
+/**
+ * netlbl_get_u8 - Read a u8 value from a buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u8 value pointed to by @buffer.
+ *
+ */
+static inline u8 netlbl_get_u8(const unsigned char *buffer)
+{
+ return *(u8 *)buffer;
+}
+
+/**
+ * netlbl_get_u32 - Read a u32 value from a buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u8 value pointed to by @buffer.
+ *
+ */
+static inline u32 netlbl_get_u32(const unsigned char *buffer)
+{
+ return *(u32 *)buffer;
+}
+
+/**
+ * netlbl_getinc_u8 - Read a u8 value from a buffer and increment the buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u8 value pointed to by @buffer and increment the buffer pointer
+ * past the value.
+ *
+ */
+static inline u8 netlbl_getinc_u8(unsigned char **buffer)
+{
+ u8 val = netlbl_get_u8(*buffer);
+ *buffer += sizeof(u8);
+ return val;
+}
+
+/**
+ * netlbl_getinc_u32 - Read a u32 value from a buffer and increment the buffer
+ * @buffer: the buffer
+ *
+ * Description:
+ * Return a u32 value pointed to by @buffer and increment the buffer pointer
+ * past the value.
+ *
+ */
+static inline u32 netlbl_getinc_u32(unsigned char **buffer)
+{
+ u32 val = netlbl_get_u32(*buffer);
+ *buffer += sizeof(u32);
+ return val;
+}
+
+/*
+ * NetLabel - Kernel API for accessing the network packet label mappings.
+ *
+ * The following functions are provided for use by other kernel modules,
+ * specifically kernel LSM modules, to provide a consistent, transparent API
+ * for dealing with explicit packet labeling protocols such as CIPSO and
+ * RIPSO. The functions defined here are implemented in the
+ * net/netlabel/netlabel_kapi.c file.
+ *
+ */
+
+/* Domain mapping definition struct */
+struct netlbl_dom_map;
+
+/* Domain mapping operations */
+int netlbl_domhsh_remove(const char *domain);
+
+/* LSM security attributes */
+struct netlbl_lsm_cache {
+ void (*free) (const void *data);
+ void *data;
+};
+struct netlbl_lsm_secattr {
+ char *domain;
+
+ u32 mls_lvl;
+ unsigned char *mls_cat;
+ u32 mls_cat_len;
+
+ struct netlbl_lsm_cache cache;
+
+ u32 set_domain:1,
+ set_mls_lvl:1,
+ set_mls_cat:1,
+ set_cache:1,
+ __unused:28;
+};
+
+/*
+ * LSM security attribute operations
+ */
+
+/**
+ * netlbl_secattr_alloc - Allocate and initialize a netlbl_lsm_secattr struct
+ * @flags: the memory allocation flags
+ *
+ * Description:
+ * Allocate and initialize a netlbl_lsm_secattr struct. Returns a valid
+ * pointer on success, or NULL on failure.
+ *
+ */
+static inline struct netlbl_lsm_secattr *netlbl_secattr_alloc(const int flags)
+{
+ return kzalloc(sizeof(struct netlbl_lsm_secattr), flags);
+}
+
+/**
+ * netlbl_secattr_free - Frees a netlbl_lsm_secattr struct
+ * @secattr: the struct to free
+ *
+ * Description:
+ * Frees @secattr including all of the internal buffers.
+ *
+ */
+static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
+{
+ BUG_ON(secattr == NULL);
+ if (secattr->set_domain)
+ kfree(secattr->domain);
+ if (secattr->set_mls_cat)
+ kfree(secattr->mls_cat);
+ if (secattr->set_cache && secattr->cache.free)
+ secattr->cache.free(secattr->cache.data);
+ kfree(secattr);
+}
+
+/**
+ * netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct
+ * @secattr: the struct to initialize
+ *
+ * Description:
+ * Initialize an already allocated netlbl_lsm_secattr struct. Returns zero on
+ * success, negative values on error.
+ *
+ */
+static inline int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
+{
+ BUG_ON(secattr == NULL);
+ memset(secattr, 0, sizeof(*secattr));
+ return 0;
+}
+
+/**
+ * netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct
+ * @secattr: the struct to clear
+ *
+ * Description:
+ * Destroys the @secattr struct, including freeing all of the internal buffers.
+ * On return the struct is suitable for reuse.
+ *
+ */
+static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
+{
+ BUG_ON(secattr == NULL);
+ if (secattr->set_domain)
+ kfree(secattr->domain);
+ if (secattr->set_mls_cat)
+ kfree(secattr->mls_cat);
+ if (secattr->set_cache && secattr->cache.free)
+ secattr->cache.free(secattr->cache.data);
+ memset(secattr, 0, sizeof(*secattr));
+}
+
+/*
+ * LSM protocol operations
+ */
+
+#ifdef CONFIG_NETLABEL
+int netlbl_socket_setattr(const struct socket *sock,
+ const struct netlbl_lsm_secattr *secattr);
+int netlbl_socket_peekattr(const struct socket *sock,
+ 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,
+ struct netlbl_lsm_secattr *secattr);
+int netlbl_skbuff_err(struct sk_buff *skb, int error);
+#else
+static inline int netlbl_socket_setattr(const struct socket *sock,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ return -ENOSYS;
+}
+
+static inline int netlbl_socket_peekattr(const struct socket *sock,
+ struct netlbl_lsm_secattr *secattr)
+{
+ return -ENOSYS;
+}
+
+static inline int netlbl_socket_getattr(const struct socket *sock,
+ struct netlbl_lsm_secattr *secattr)
+{
+ return -ENOSYS;
+}
+
+static inline int netlbl_skbuff_getattr(const struct sk_buff *skb,
+ struct netlbl_lsm_secattr *secattr)
+{
+ return -ENOSYS;
+}
+
+static inline int netlbl_skbuff_err(struct sk_buff *skb, int error)
+{
+ return 0;
+}
+#endif /* CONFIG_NETLABEL */
+
+/*
+ * LSM label mapping cache operations
+ */
+
+#ifdef CONFIG_NETLABEL
+void netlbl_cache_invalidate(void);
+int netlbl_cache_add(const struct sk_buff *skb,
+ const struct netlbl_lsm_secattr *secattr);
+#else
+static inline void netlbl_cache_invalidate(void)
+{
+ return;
+}
+
+static inline int netlbl_cache_add(const struct sk_buff *skb,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ return 0;
+}
+#endif /* CONFIG_NETLABEL */
+
+/*
+ * Network stack operations
+ */
+
+#ifdef CONFIG_NETLABEL
+void netlbl_socket_inet_accept(struct socket *sock, struct socket *newsock);
+#else
+static inline void netlbl_socket_inet_accept(struct socket *sock,
+ struct socket *newsock)
+{
+ return;
+}
+#endif /* CONFIG_NETLABEL */
+
+#endif /* _NETLABEL_H */
Index: linux-2.6.17.i686-quilt/net/ipv4/Makefile
===================================================================
--- linux-2.6.17.i686-quilt.orig/net/ipv4/Makefile
+++ linux-2.6.17.i686-quilt/net/ipv4/Makefile
@@ -42,6 +42,7 @@ obj-$(CONFIG_TCP_CONG_HYBLA) += tcp_hybl
obj-$(CONFIG_TCP_CONG_HTCP) += tcp_htcp.o
obj-$(CONFIG_TCP_CONG_VEGAS) += tcp_vegas.o
obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o
+obj-$(CONFIG_NETLABEL_CIPSOV4) += cipso_ipv4.o
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
xfrm4_output.o
Index: linux-2.6.17.i686-quilt/net/ipv4/af_inet.c
===================================================================
--- linux-2.6.17.i686-quilt.orig/net/ipv4/af_inet.c
+++ linux-2.6.17.i686-quilt/net/ipv4/af_inet.c
@@ -114,6 +114,7 @@
#ifdef CONFIG_IP_MROUTE
#include <linux/mroute.h>
#endif
+#include <net/netlabel.h>
DEFINE_SNMP_STAT(struct linux_mib, net_statistics) __read_mostly;
@@ -616,6 +617,8 @@ int inet_accept(struct socket *sock, str
sock_graft(sk2, newsock);
+ netlbl_socket_inet_accept(sock, newsock);
+
newsock->state = SS_CONNECTED;
err = 0;
release_sock(sk2);
Index: linux-2.6.17.i686-quilt/net/ipv4/ah4.c
===================================================================
--- linux-2.6.17.i686-quilt.orig/net/ipv4/ah4.c
+++ linux-2.6.17.i686-quilt/net/ipv4/ah4.c
@@ -35,7 +35,7 @@ static int ip_clear_mutable_options(stru
switch (*optptr) {
case IPOPT_SEC:
case 0x85: /* Some "Extended Security" crap. */
- case 0x86: /* Another "Commercial Security" crap. */
+ case IPOPT_CIPSO:
case IPOPT_RA:
case 0x80|21: /* RFC1770 */
break;
Index: linux-2.6.17.i686-quilt/net/ipv4/ip_options.c
===================================================================
--- linux-2.6.17.i686-quilt.orig/net/ipv4/ip_options.c
+++ linux-2.6.17.i686-quilt/net/ipv4/ip_options.c
@@ -24,6 +24,7 @@
#include <net/ip.h>
#include <net/icmp.h>
#include <net/route.h>
+#include <net/cipso_ipv4.h>
/*
* Write options to IP header, record destination address to
@@ -194,6 +195,13 @@ int ip_options_echo(struct ip_options *
dopt->is_strictroute = sopt->is_strictroute;
}
}
+ if (sopt->cipso) {
+ optlen = sptr[sopt->cipso+1];
+ dopt->cipso = dopt->optlen+sizeof(struct iphdr);
+ memcpy(dptr, sptr+sopt->cipso, optlen);
+ dptr += optlen;
+ dopt->optlen += optlen;
+ }
while (dopt->optlen & 3) {
*dptr++ = IPOPT_END;
dopt->optlen++;
@@ -435,6 +443,17 @@ int ip_options_compile(struct ip_options
if (optptr[2] == 0 && optptr[3] == 0)
opt->router_alert = optptr - iph;
break;
+ case IPOPT_CIPSO:
+ if (opt->cipso) {
+ pp_ptr = optptr;
+ goto error;
+ }
+ opt->cipso = optptr - iph;
+ if (cipso_v4_validate(&optptr)) {
+ pp_ptr = optptr;
+ goto error;
+ }
+ break;
case IPOPT_SEC:
case IPOPT_SID:
default:
--
paul moore
linux security @ hp
^ permalink raw reply
* [RFC 5/8] NetLabel: SELinux support
From: paul.moore @ 2006-06-22 22:49 UTC (permalink / raw)
To: netdev; +Cc: davem
In-Reply-To: <20060622224910.885573000@flek.zko.hp.com>
[-- Attachment #1: netlabel-selinux-2.6.17 --]
[-- Type: text/plain, Size: 49211 bytes --]
Add NetLabel support to the SELinux LSM and modify the socket_post_create() LSM
hook to return an error code. The most significant part of this patch is the
addition of NetLabel hooks into the following SELinux LSM hooks:
* selinux_file_permission()
* selinux_socket_sendmsg()
* selinux_socket_post_create()
* selinux_socket_post_accept() [NEW]
* selinux_socket_sock_rcv_skb()
* selinux_socket_getpeersec_stream()
* selinux_socket_getpeersec_dgram()
The basic reasoning behind this patch is that outgoing packets are "NetLabel'd"
by labeling their socket and the NetLabel security attributes are checked via
the additional hook in selinux_socket_sock_rcv_skb(). NetLabel itself is only
a labeling mechanism, similar to filesystem extended attributes, it is up to
the SELinux enforcement mechanism to perform the actual access checks.
In addition to the changes outlined above this patch also includes some changes
to the extended bitmap (ebitmap) and multi-level security (mls) code to import
and export SELinux TE/MLS attributes into and out of NetLabel.
---
include/linux/security.h | 25 -
net/socket.c | 13
security/dummy.c | 6
security/selinux/hooks.c | 59 ++
security/selinux/include/av_inherit.h | 1
security/selinux/include/av_perm_to_string.h | 1
security/selinux/include/av_permissions.h | 1
security/selinux/include/flask.h | 1
security/selinux/include/objsec.h | 11
security/selinux/include/security.h | 2
security/selinux/include/selinux_netlabel.h | 94 ++++
security/selinux/nlmsgtab.c | 15
security/selinux/ss/Makefile | 1
security/selinux/ss/ebitmap.c | 155 +++++++
security/selinux/ss/ebitmap.h | 6
security/selinux/ss/mls.c | 160 +++++++
security/selinux/ss/mls.h | 25 +
security/selinux/ss/selinux_netlabel.c | 574 +++++++++++++++++++++++++++
security/selinux/ss/services.c | 12
security/selinux/ss/services.h | 2
20 files changed, 1134 insertions(+), 30 deletions(-)
Index: linux-2.6.17.i686-quilt/include/linux/security.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/include/linux/security.h
+++ linux-2.6.17.i686-quilt/include/linux/security.h
@@ -1267,8 +1267,8 @@ struct security_operations {
int (*unix_may_send) (struct socket * sock, struct socket * other);
int (*socket_create) (int family, int type, int protocol, int kern);
- void (*socket_post_create) (struct socket * sock, int family,
- int type, int protocol, int kern);
+ int (*socket_post_create) (struct socket * sock, int family,
+ int type, int protocol, int kern);
int (*socket_bind) (struct socket * sock,
struct sockaddr * address, int addrlen);
int (*socket_connect) (struct socket * sock,
@@ -2677,13 +2677,13 @@ static inline int security_socket_create
return security_ops->socket_create(family, type, protocol, kern);
}
-static inline void security_socket_post_create(struct socket * sock,
- int family,
- int type,
- int protocol, int kern)
+static inline int security_socket_post_create(struct socket * sock,
+ int family,
+ int type,
+ int protocol, int kern)
{
- security_ops->socket_post_create(sock, family, type,
- protocol, kern);
+ return security_ops->socket_post_create(sock, family, type,
+ protocol, kern);
}
static inline int security_socket_bind(struct socket * sock,
@@ -2809,11 +2809,12 @@ static inline int security_socket_create
return 0;
}
-static inline void security_socket_post_create(struct socket * sock,
- int family,
- int type,
- int protocol, int kern)
+static inline int security_socket_post_create(struct socket * sock,
+ int family,
+ int type,
+ int protocol, int kern)
{
+ return 0;
}
static inline int security_socket_bind(struct socket * sock,
Index: linux-2.6.17.i686-quilt/net/socket.c
===================================================================
--- linux-2.6.17.i686-quilt.orig/net/socket.c
+++ linux-2.6.17.i686-quilt/net/socket.c
@@ -976,11 +976,18 @@ int sock_create_lite(int family, int typ
goto out;
}
- security_socket_post_create(sock, family, type, protocol, 1);
sock->type = type;
+ err = security_socket_post_create(sock, family, type, protocol, 1);
+ if (err)
+ goto out_release;
+
out:
*res = sock;
return err;
+out_release:
+ sock_release(sock);
+ sock = NULL;
+ goto out;
}
/* No kernel lock held - perfect */
@@ -1218,7 +1225,9 @@ static int __sock_create(int family, int
*/
module_put(net_families[family]->owner);
*res = sock;
- security_socket_post_create(sock, family, type, protocol, kern);
+ err = security_socket_post_create(sock, family, type, protocol, kern);
+ if (err)
+ goto out_release;
out:
net_family_read_unlock();
Index: linux-2.6.17.i686-quilt/security/dummy.c
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/dummy.c
+++ linux-2.6.17.i686-quilt/security/dummy.c
@@ -692,10 +692,10 @@ static int dummy_socket_create (int fami
return 0;
}
-static void dummy_socket_post_create (struct socket *sock, int family, int type,
- int protocol, int kern)
+static int dummy_socket_post_create (struct socket *sock, int family, int type,
+ int protocol, int kern)
{
- return;
+ return 0;
}
static int dummy_socket_bind (struct socket *sock, struct sockaddr *address,
Index: linux-2.6.17.i686-quilt/security/selinux/hooks.c
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/hooks.c
+++ linux-2.6.17.i686-quilt/security/selinux/hooks.c
@@ -12,6 +12,8 @@
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
* Copyright (C) 2004-2005 Trusted Computer Solutions, Inc.
* <dgoeddel@trustedcs.com>
+ * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
+ * Paul Moore, <paul.moore@hp.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
@@ -74,6 +76,7 @@
#include "objsec.h"
#include "netif.h"
#include "xfrm.h"
+#include "selinux_netlabel.h"
#define XATTR_SELINUX_SUFFIX "selinux"
#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX
@@ -2293,6 +2296,7 @@ static int selinux_inode_listsecurity(st
static int selinux_file_permission(struct file *file, int mask)
{
+ int rc;
struct inode *inode = file->f_dentry->d_inode;
if (!mask) {
@@ -2304,8 +2308,12 @@ static int selinux_file_permission(struc
if ((file->f_flags & O_APPEND) && (mask & MAY_WRITE))
mask |= MAY_APPEND;
- return file_has_perm(current, file,
- file_mask_to_av(inode->i_mode, mask));
+ rc = file_has_perm(current, file,
+ file_mask_to_av(inode->i_mode, mask));
+ if (rc)
+ return rc;
+
+ return selinux_netlbl_inode_permission(inode, mask);
}
static int selinux_file_alloc_security(struct file *file)
@@ -2922,8 +2930,8 @@ out:
return err;
}
-static void selinux_socket_post_create(struct socket *sock, int family,
- int type, int protocol, int kern)
+static int selinux_socket_post_create(struct socket *sock, int family,
+ int type, int protocol, int kern)
{
struct inode_security_struct *isec;
struct task_security_struct *tsec;
@@ -2935,7 +2943,7 @@ static void selinux_socket_post_create(s
isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
isec->initialized = 1;
- return;
+ return selinux_netlbl_socket_create(sock, family, isec->sid);
}
/* Range of port numbers used to automatically bind.
@@ -3113,10 +3121,24 @@ static int selinux_socket_accept(struct
return 0;
}
+#ifdef CONFIG_NETLABEL
+static void selinux_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
+{
+ selinux_netlbl_socket_accept(sock, newsock);
+}
+#endif /* CONFIG_NETLABEL */
+
static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
int size)
{
- return socket_has_perm(current, sock, SOCKET__WRITE);
+ int rc;
+
+ rc = socket_has_perm(current, sock, SOCKET__WRITE);
+ if (rc)
+ return rc;
+
+ return selinux_netlbl_inode_permission(SOCK_INODE(sock), MAY_WRITE);
}
static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
@@ -3306,10 +3328,15 @@ static int selinux_socket_sock_rcv_skb(s
err = avc_has_perm(sock_sid, port_sid,
sock_class, recv_perm, &ad);
+ if (err)
+ goto out;
}
- if (!err)
- err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
+ err = selinux_netlbl_sock_rcv_skb(sock_class, sock_sid, skb, &ad);
+ if (err)
+ goto out;
+
+ err = selinux_xfrm_sock_rcv_skb(sock_sid, skb);
out:
return err;
@@ -3333,8 +3360,9 @@ static int selinux_socket_getpeersec_str
peer_sid = ssec->peer_sid;
}
else if (isec->sclass == SECCLASS_TCP_SOCKET) {
- peer_sid = selinux_socket_getpeer_stream(sock->sk);
-
+ err = selinux_netlbl_socket_getpeersec_stream(sock, &peer_sid);
+ if (err || peer_sid == SECSID_NULL)
+ peer_sid = selinux_socket_getpeer_stream(sock->sk);
if (peer_sid == SECSID_NULL) {
err = -ENOPROTOOPT;
goto out;
@@ -3369,8 +3397,12 @@ out:
static int selinux_socket_getpeersec_dgram(struct sk_buff *skb, char **secdata, u32 *seclen)
{
- int err = 0;
- u32 peer_sid = selinux_socket_getpeer_dgram(skb);
+ int err;
+ u32 peer_sid;
+
+ err = selinux_netlbl_socket_getpeersec_dgram(skb, &peer_sid);
+ if (err || peer_sid == SECSID_NULL)
+ peer_sid = selinux_socket_getpeer_dgram(skb);
if (peer_sid == SECSID_NULL)
return -EINVAL;
@@ -4353,6 +4385,9 @@ static struct security_operations selinu
.socket_connect = selinux_socket_connect,
.socket_listen = selinux_socket_listen,
.socket_accept = selinux_socket_accept,
+#ifdef CONFIG_NETLABEL
+ .socket_post_accept = selinux_socket_post_accept,
+#endif
.socket_sendmsg = selinux_socket_sendmsg,
.socket_recvmsg = selinux_socket_recvmsg,
.socket_getsockname = selinux_socket_getsockname,
Index: linux-2.6.17.i686-quilt/security/selinux/include/av_inherit.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/include/av_inherit.h
+++ linux-2.6.17.i686-quilt/security/selinux/include/av_inherit.h
@@ -29,3 +29,4 @@
S_(SECCLASS_NETLINK_IP6FW_SOCKET, socket, 0x00400000UL)
S_(SECCLASS_NETLINK_DNRT_SOCKET, socket, 0x00400000UL)
S_(SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET, socket, 0x00400000UL)
+ S_(SECCLASS_NETLINK_NETLABEL_SOCKET, socket, 0x00400000UL)
Index: linux-2.6.17.i686-quilt/security/selinux/include/av_perm_to_string.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/include/av_perm_to_string.h
+++ linux-2.6.17.i686-quilt/security/selinux/include/av_perm_to_string.h
@@ -239,3 +239,4 @@
S_(SECCLASS_ASSOCIATION, ASSOCIATION__SENDTO, "sendto")
S_(SECCLASS_ASSOCIATION, ASSOCIATION__RECVFROM, "recvfrom")
S_(SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, "setcontext")
+ S_(SECCLASS_NETLINK_NETLABEL_SOCKET, NETLINK_NETLABEL_SOCKET__NLMSG_WRITE, "nlmsg_write")
Index: linux-2.6.17.i686-quilt/security/selinux/include/av_permissions.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/include/av_permissions.h
+++ linux-2.6.17.i686-quilt/security/selinux/include/av_permissions.h
@@ -933,3 +933,4 @@
#define NETLINK_KOBJECT_UEVENT_SOCKET__SEND_MSG 0x00100000UL
#define NETLINK_KOBJECT_UEVENT_SOCKET__NAME_BIND 0x00200000UL
+#define NETLINK_NETLABEL_SOCKET__NLMSG_WRITE 0x00000001UL
Index: linux-2.6.17.i686-quilt/security/selinux/include/flask.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/include/flask.h
+++ linux-2.6.17.i686-quilt/security/selinux/include/flask.h
@@ -60,6 +60,7 @@
#define SECCLASS_NSCD 53
#define SECCLASS_ASSOCIATION 54
#define SECCLASS_NETLINK_KOBJECT_UEVENT_SOCKET 55
+#define SECCLASS_NETLINK_NETLABEL_SOCKET 56
/*
* Security identifier indices for initial entities
Index: linux-2.6.17.i686-quilt/security/selinux/include/objsec.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/include/objsec.h
+++ linux-2.6.17.i686-quilt/security/selinux/include/objsec.h
@@ -35,6 +35,14 @@ struct task_security_struct {
u32 ptrace_sid; /* SID of ptrace parent */
};
+struct netlbl_security_struct {
+ u32 netlbl_sid; /* SID used to set the NetLabel */
+ u32 peer_sid; /* SID of the connected peer */
+ u32 req_netlbl:1, /* socket requires a NetLabel label */
+ labeled:1, /* socket is labeled with NetLabel */
+ __unused:30;
+};
+
struct inode_security_struct {
struct inode *inode; /* back pointer to inode object */
struct list_head list; /* list of inode_security_struct */
@@ -44,6 +52,9 @@ struct inode_security_struct {
unsigned char initialized; /* initialization flag */
struct semaphore sem;
unsigned char inherit; /* inherit SID from parent entry */
+#ifdef CONFIG_NETLABEL
+ struct netlbl_security_struct netlbl;
+#endif
};
struct file_security_struct {
Index: linux-2.6.17.i686-quilt/security/selinux/include/security.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/include/security.h
+++ linux-2.6.17.i686-quilt/security/selinux/include/security.h
@@ -8,6 +8,8 @@
#ifndef _SELINUX_SECURITY_H_
#define _SELINUX_SECURITY_H_
+#include <linux/skbuff.h>
+
#include "flask.h"
#define SECSID_NULL 0x00000000 /* unspecified SID */
Index: linux-2.6.17.i686-quilt/security/selinux/include/selinux_netlabel.h
===================================================================
--- /dev/null
+++ linux-2.6.17.i686-quilt/security/selinux/include/selinux_netlabel.h
@@ -0,0 +1,94 @@
+/*
+ * SELinux interface to the NetLabel subsystem
+ *
+ * Author : Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _SELINUX_NETLABEL_H_
+#define _SELINUX_NETLABEL_H_
+
+#ifdef CONFIG_NETLABEL
+void selinux_netlbl_cache_invalidate(void);
+
+int selinux_netlbl_inode_permission(struct inode *inode, int mask);
+
+int selinux_netlbl_socket_create(struct socket *sock,
+ const int sock_family,
+ u32 sid);
+void selinux_netlbl_socket_accept(struct socket *sock, struct socket *newsock);
+int selinux_netlbl_sock_rcv_skb(const u16 sock_class,
+ const u32 sock_sid,
+ struct sk_buff *skb,
+ struct avc_audit_data *ad);
+int selinux_netlbl_socket_getpeersec_stream(struct socket *sock,
+ u32 *peer_sid);
+int selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb, u32 *peer_sid);
+#else
+static inline void selinux_netlbl_cache_invalidate(void)
+{
+ return;
+}
+
+static inline int selinux_netlbl_inode_permission(struct inode *inode,
+ int mask)
+{
+ return 0;
+}
+
+static inline int selinux_netlbl_socket_create(struct socket *sock,
+ const int sock_family,
+ u32 sid)
+{
+ return 0;
+}
+
+static inline void selinux_netlbl_socket_accept(struct socket *sock,
+ struct socket *newsock)
+{
+ return;
+}
+
+static inline int selinux_netlbl_sock_rcv_skb(const u16 sock_class,
+ const u32 sock_sid,
+ struct sk_buff *skb,
+ struct avc_audit_data *ad)
+{
+ return 0;
+}
+
+static inline int selinux_netlbl_socket_getpeersec_stream(struct socket *sock,
+ u32 *peer_sid)
+{
+ *peer_sid = SECSID_NULL;
+ return 0;
+}
+
+static inline int selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb,
+ u32 *peer_sid)
+{
+ *peer_sid = SECSID_NULL;
+ return 0;
+}
+#endif /* CONFIG_NETLABEL */
+
+#endif
Index: linux-2.6.17.i686-quilt/security/selinux/nlmsgtab.c
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/nlmsgtab.c
+++ linux-2.6.17.i686-quilt/security/selinux/nlmsgtab.c
@@ -19,6 +19,7 @@
#include <linux/inet_diag.h>
#include <linux/xfrm.h>
#include <linux/audit.h>
+#include <net/netlabel.h>
#include "flask.h"
#include "av_permissions.h"
@@ -116,6 +117,15 @@ static struct nlmsg_perm nlmsg_audit_per
{ AUDIT_WATCH_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
};
+static struct nlmsg_perm nlmsg_netlabel_perms[] =
+{
+ { NETLBL_NLTYPE_NONE, NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+ { NETLBL_NLTYPE_MGMT, NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+ { NETLBL_NLTYPE_RIPSO, NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+ { NETLBL_NLTYPE_CIPSOV4, NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+ { NETLBL_NLTYPE_CIPSOV6, NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+ { NETLBL_NLTYPE_UNLABELED, NETLINK_NETLABEL_SOCKET__NLMSG_WRITE },
+};
static int nlmsg_perm(u16 nlmsg_type, u32 *perm, struct nlmsg_perm *tab, size_t tabsize)
{
@@ -169,6 +179,11 @@ int selinux_nlmsg_lookup(u16 sclass, u16
}
break;
+ case SECCLASS_NETLINK_NETLABEL_SOCKET:
+ err = nlmsg_perm(nlmsg_type, perm, nlmsg_netlabel_perms,
+ sizeof(nlmsg_netlabel_perms));
+ break;
+
/* No messaging from userspace, or class unknown/unhandled */
default:
err = -ENOENT;
Index: linux-2.6.17.i686-quilt/security/selinux/ss/Makefile
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/ss/Makefile
+++ linux-2.6.17.i686-quilt/security/selinux/ss/Makefile
@@ -7,3 +7,4 @@ obj-y := ss.o
ss-y := ebitmap.o hashtab.o symtab.o sidtab.o avtab.o policydb.o services.o conditional.o mls.o
+obj-$(CONFIG_NETLABEL) += selinux_netlabel.o
Index: linux-2.6.17.i686-quilt/security/selinux/ss/ebitmap.c
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/ss/ebitmap.c
+++ linux-2.6.17.i686-quilt/security/selinux/ss/ebitmap.c
@@ -3,6 +3,14 @@
*
* Author : Stephen Smalley, <sds@epoch.ncsc.mil>
*/
+/*
+ * Updated: Hewlett-Packard <paul.moore@hp.com>
+ *
+ * Added ebitmap_export() and ebitmap_import()
+ *
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ */
+
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/errno.h>
@@ -59,6 +67,153 @@ int ebitmap_cpy(struct ebitmap *dst, str
return 0;
}
+/**
+ * ebitmap_export - Export an ebitmap to a unsigned char bitmap string
+ * @src: the ebitmap to export
+ * @dst: the resulting bitmap string
+ * @dst_len: length of dst in bytes
+ *
+ * Description:
+ * Allocate a buffer at least src->highbit bits long and export the extensible
+ * bitmap into the buffer. The bitmap string will be in little endian format,
+ * i.e. LSB first. The value returned in dst_len may not the true size of the
+ * buffer as the length of the buffer is rounded up to a multiple of MAPTYPE.
+ * The caller must free the buffer when finished. Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int ebitmap_export(const struct ebitmap *src,
+ unsigned char **dst,
+ u32 *dst_len)
+{
+ u32 bitmap_len;
+ unsigned char *bitmap;
+ struct ebitmap_node *iter_node;
+ MAPTYPE node_val;
+ u32 bitmap_byte;
+ unsigned char bitmask;
+
+ if (src == NULL || dst == NULL || dst_len == NULL)
+ return -EINVAL;
+
+ *dst = NULL;
+ *dst_len = 0;
+
+ bitmap_len = src->highbit / 8;
+ if (src->highbit % 8 > 0)
+ bitmap_len += 1;
+ if (bitmap_len == 0)
+ return -EINVAL;
+
+ bitmap = kzalloc(bitmap_len + sizeof(MAPTYPE) -
+ (bitmap_len % sizeof(MAPTYPE)),
+ GFP_ATOMIC);
+ if (bitmap == NULL)
+ return -ENOMEM;
+
+ /* PM - there _has_ to be a faster way to do this, work on this more */
+ iter_node = src->node;
+ do {
+ bitmap_byte = iter_node->startbit / 8;
+ bitmask = 0x80;
+ node_val = iter_node->map;
+ do {
+ if (bitmask == 0) {
+ bitmap_byte++;
+ bitmask = 0x80;
+ }
+ if (node_val & (MAPTYPE)0x01)
+ bitmap[bitmap_byte] |= bitmask;
+ node_val >>= 1;
+ bitmask >>= 1;
+ } while (node_val > 0);
+ iter_node = iter_node->next;
+ } while (iter_node);
+
+ *dst = bitmap;
+ *dst_len = bitmap_len;
+ return 0;
+}
+
+/**
+ * ebitmap_import - Import an unsigned char bitmap string into an ebitmap
+ * @src: the bitmap string
+ * @src_len: the bitmap length in bytes
+ * @dst: the empty ebitmap
+ *
+ * Description:
+ * This function takes a little endian bitmap string in src and imports it into
+ * the ebitmap pointed to by dst. Returns zero on success, negative values on
+ * failure.
+ *
+ */
+int ebitmap_import(const unsigned char *src,
+ const u32 src_len,
+ struct ebitmap *dst)
+{
+ u32 src_off = 0;
+ struct ebitmap_node *node_new;
+ struct ebitmap_node *node_last = NULL;
+ u32 src_rem = src_len;
+ MAPTYPE tmp_val;
+ u32 iter;
+ u32 iter_bit;
+ unsigned char src_byte;
+
+ if (src == NULL || dst == NULL || src_len == 0)
+ return -EINVAL;
+
+ do {
+ node_new = kzalloc(sizeof(*node_new), GFP_ATOMIC);
+ if (node_new == NULL) {
+ ebitmap_destroy(dst);
+ return -ENOMEM;
+ }
+
+ /* PM - there _has_ to be a faster way to do this,
+ work on this more */
+ if (src_rem >= sizeof(MAPTYPE))
+ iter = sizeof(MAPTYPE);
+ else
+ iter = src_rem;
+ tmp_val = 0;
+ while (iter > 0) {
+ src_byte = src[src_off + --iter];
+ if (src_byte > 0)
+ for (iter_bit = 0; iter_bit < 8; iter_bit++) {
+ tmp_val <<= 1;
+ tmp_val |= src_byte & 0x01;
+ src_byte >>= 1;
+ }
+ else
+ tmp_val <<= 8;
+ }
+ node_new->map = tmp_val;
+ node_new->startbit = src_off * 8;
+
+ if (node_last != NULL)
+ node_last->next = node_new;
+ else
+ dst->node = node_new;
+ node_last = node_new;
+
+ if (src_rem >= sizeof(MAPTYPE)) {
+ src_off += sizeof(MAPTYPE);
+ src_rem -= sizeof(MAPTYPE);
+ } else
+ src_off += src_rem;
+ } while (src_off < src_len);
+
+ tmp_val = node_last->map;
+ dst->highbit = node_last->startbit;
+ while (tmp_val >= 1) {
+ dst->highbit += 1;
+ tmp_val >>= 1;
+ }
+
+ return 0;
+}
+
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)
{
struct ebitmap_node *n1, *n2;
Index: linux-2.6.17.i686-quilt/security/selinux/ss/ebitmap.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/ss/ebitmap.h
+++ linux-2.6.17.i686-quilt/security/selinux/ss/ebitmap.h
@@ -69,6 +69,12 @@ static inline int ebitmap_node_get_bit(s
int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src);
+int ebitmap_export(const struct ebitmap *src,
+ unsigned char **dst,
+ u32 *dst_len);
+int ebitmap_import(const unsigned char *src,
+ const u32 src_len,
+ struct ebitmap *dst);
int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2);
int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);
int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);
Index: linux-2.6.17.i686-quilt/security/selinux/ss/mls.c
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/ss/mls.c
+++ linux-2.6.17.i686-quilt/security/selinux/ss/mls.c
@@ -10,6 +10,13 @@
*
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
*/
+/*
+ * Updated: Hewlett-Packard <paul.moore@hp.com>
+ *
+ * Added support to import/export the MLS label
+ *
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ */
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -585,3 +592,156 @@ int mls_compute_sid(struct context *scon
return -EINVAL;
}
+/**
+ * mls_export_lvl - Export the MLS sensitivity levels
+ * @context: the security context
+ * @lvl_low: the low sensitivity level
+ * @lvl_high: the high sensitivity level
+ *
+ * Description:
+ * Given the security context copy the low MLS sensitivity level into lvl_low
+ * and the high sensitivity level in lvl_high. The MLS levels are only
+ * exported if the pointers are not NULL, if they are NULL then that level is
+ * not exported. Returns zero on success, negative values on failure.
+ *
+ */
+int mls_export_lvl(const struct context *context, u32 *lvl_low, u32 *lvl_high)
+{
+ if (!selinux_mls_enabled)
+ return 0;
+
+ if (lvl_low != NULL)
+ *lvl_low = context->range.level[0].sens - 1;
+ if (lvl_high != NULL)
+ *lvl_high = context->range.level[1].sens - 1;
+
+ return 0;
+}
+
+/**
+ * mls_import_lvl - Import the MLS sensitivity levels
+ * @context: the security context
+ * @lvl_low: the low sensitivity level
+ * @lvl_high: the high sensitivity level
+ *
+ * Description:
+ * Given the security context and the two sensitivty levels, set the MLS levels
+ * in the context according the two given as parameters. Returns zero on
+ * success, negative values on failure.
+ *
+ */
+int mls_import_lvl(struct context *context,
+ const u32 lvl_low,
+ const u32 lvl_high)
+{
+ if (!selinux_mls_enabled)
+ return 0;
+
+ context->range.level[0].sens = lvl_low + 1;
+ context->range.level[1].sens = lvl_high + 1;
+
+ return 0;
+}
+
+/**
+ * mls_export_cat - Export the MLS categories
+ * @context: the security context
+ * @cat_low: the low category
+ * @cat_low_len: length of the cat_low bitmap in bytes
+ * @cat_high: the high category
+ * @cat_high_len: length of the cat_high bitmap in bytes
+ *
+ * Description:
+ * Given the security context export the low MLS category bitmap into cat_low
+ * and the high category bitmap into cat_high. The MLS categories are only
+ * exported if the pointers are not NULL, if they are NULL then that level is
+ * not exported. The caller is responsibile for freeing the memory when
+ * finished. Returns zero on success, negative values on failure.
+ *
+ */
+int mls_export_cat(const struct context *context,
+ unsigned char **cat_low,
+ u32 *cat_low_len,
+ unsigned char **cat_high,
+ u32 *cat_high_len)
+{
+ int ret_val = -EPERM;
+
+ if (!selinux_mls_enabled)
+ return 0;
+
+ if (cat_low != NULL && cat_low_len != NULL) {
+ ret_val = ebitmap_export(&context->range.level[0].cat,
+ cat_low,
+ cat_low_len);
+ if (ret_val != 0)
+ goto export_cat_failure;
+ }
+ if (cat_high != NULL && cat_high_len != NULL) {
+ ret_val = ebitmap_export(&context->range.level[1].cat,
+ cat_high,
+ cat_high_len);
+ if (ret_val != 0)
+ goto export_cat_failure;
+ }
+
+ return 0;
+
+export_cat_failure:
+ if (cat_low != NULL && *cat_low != NULL)
+ kfree(*cat_low);
+ if (cat_high != NULL && *cat_high != NULL)
+ kfree(*cat_high);
+ return ret_val;
+}
+
+/**
+ * mls_import_cat - Import the MLS categories
+ * @context: the security context
+ * @cat_low: the low category
+ * @cat_low_len: length of the cat_low bitmap in bytes
+ * @cat_high: the high category
+ * @cat_high_len: length of the cat_high bitmap in bytes
+ *
+ * Description:
+ * Given the security context and the two category bitmap strings import the
+ * categories into the security context. The MLS categories are only imported
+ * if the pointers are not NULL, if they are NULL they are skipped. Returns
+ * zero on success, negative values on failure.
+ *
+ */
+int mls_import_cat(struct context *context,
+ const unsigned char *cat_low,
+ const u32 cat_low_len,
+ const unsigned char *cat_high,
+ const u32 cat_high_len)
+{
+ int ret_val = -EPERM;
+
+ if (!selinux_mls_enabled)
+ return 0;
+
+ if (cat_low != NULL && cat_low_len > 0) {
+ ret_val = ebitmap_import(cat_low,
+ cat_low_len,
+ &context->range.level[0].cat);
+ if (ret_val != 0)
+ goto import_cat_failure;
+ }
+ if (cat_high != NULL && cat_high_len > 0) {
+ ret_val = ebitmap_import(cat_high,
+ cat_high_len,
+ &context->range.level[1].cat);
+ if (ret_val != 0)
+ goto import_cat_failure;
+ }
+
+ return 0;
+
+import_cat_failure:
+ if (cat_low)
+ ebitmap_destroy(&context->range.level[0].cat);
+ if (cat_high)
+ ebitmap_destroy(&context->range.level[1].cat);
+ return ret_val;
+}
Index: linux-2.6.17.i686-quilt/security/selinux/ss/mls.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/ss/mls.h
+++ linux-2.6.17.i686-quilt/security/selinux/ss/mls.h
@@ -10,6 +10,13 @@
*
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
*/
+/*
+ * Updated: Hewlett-Packard <paul.moore@hp.com>
+ *
+ * Added support to import/export the MLS label
+ *
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ */
#ifndef _SS_MLS_H_
#define _SS_MLS_H_
@@ -42,5 +49,23 @@ int mls_compute_sid(struct context *scon
int mls_setup_user_range(struct context *fromcon, struct user_datum *user,
struct context *usercon);
+int mls_export_lvl(const struct context *context,
+ u32 *lvl_low,
+ u32 *lvl_high);
+int mls_import_lvl(struct context *context,
+ const u32 lvl_low,
+ const u32 lvl_high);
+
+int mls_export_cat(const struct context *context,
+ unsigned char **cat_low,
+ u32 *cat_low_len,
+ unsigned char **cat_high,
+ u32 *cat_high_len);
+int mls_import_cat(struct context *context,
+ const unsigned char *cat_low,
+ const u32 cat_low_len,
+ const unsigned char *cat_high,
+ const u32 cat_high_len);
+
#endif /* _SS_MLS_H */
Index: linux-2.6.17.i686-quilt/security/selinux/ss/selinux_netlabel.c
===================================================================
--- /dev/null
+++ linux-2.6.17.i686-quilt/security/selinux/ss/selinux_netlabel.c
@@ -0,0 +1,574 @@
+/*
+ * SELinux interface to the NetLabel subsystem
+ *
+ * Author : Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/audit.h>
+#include <net/sock.h>
+#include <net/netlabel.h>
+
+#include "avc.h"
+#include "context.h"
+#include "sidtab.h"
+#include "services.h"
+#include "mls.h"
+#include "objsec.h"
+
+/*
+ * This is the structure we store inside the NetLabel cache block.
+ */
+#define NETLBL_CACHE(x) ((struct netlbl_cache *)(x))
+#define NETLBL_CACHE_T_NONE 0
+#define NETLBL_CACHE_T_SID 1
+#define NETLBL_CACHE_T_MLSLBL 2
+struct netlbl_cache {
+ u32 type;
+ union {
+ u32 sid;
+ struct mls_level mls_label;
+ } data;
+};
+
+/**
+ * selinux_netlbl_cache_free - Free the NetLabel cached data
+ * @data: the data to free
+ *
+ * Description:
+ * This function is intended to be used as the free() callback inside the
+ * netlbl_lsm_cache structure.
+ *
+ */
+static void selinux_netlbl_cache_free(const void *data)
+{
+ struct netlbl_cache *cache = NETLBL_CACHE(data);
+ switch (cache->type) {
+ case NETLBL_CACHE_T_MLSLBL:
+ ebitmap_destroy(&cache->data.mls_label.cat);
+ break;
+ }
+ kfree(data);
+}
+
+/**
+ * selinux_netlbl_cache_add - Add an entry to the NetLabel cache
+ * @skb: the packet
+ * @ctx: the SELinux context
+ *
+ * Description:
+ * Attempt to cache the context in @ctx, which was derived from the packet in
+ * @skb, in the NetLabel subsystem cache.
+ *
+ */
+static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx)
+{
+ struct netlbl_cache *cache = NULL;
+ struct netlbl_lsm_secattr secattr;
+
+ netlbl_secattr_init(&secattr);
+
+ cache = kzalloc(sizeof(*cache), GFP_ATOMIC);
+ if (cache == NULL)
+ goto netlbl_cache_add_return;
+ secattr.cache.free = selinux_netlbl_cache_free;
+ secattr.cache.data = (void *)cache;
+ secattr.set_cache = 1;
+
+ if (ebitmap_cpy(&cache->data.mls_label.cat,
+ &ctx->range.level[0].cat) != 0)
+ goto netlbl_cache_add_return;
+ cache->data.mls_label.sens = ctx->range.level[0].sens;
+ cache->type = NETLBL_CACHE_T_MLSLBL;
+
+ if (netlbl_cache_add(skb, &secattr) != 0)
+ goto netlbl_cache_add_return;
+ secattr.set_cache = 0;
+
+netlbl_cache_add_return:
+ netlbl_secattr_destroy(&secattr);
+}
+
+/**
+ * selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
+ *
+ * Description:
+ * Invalidate the NetLabel security attribute mapping cache.
+ *
+ */
+void selinux_netlbl_cache_invalidate(void)
+{
+ netlbl_cache_invalidate();
+}
+
+/**
+ * selinux_netlbl_domain_export - Exports the type of a given context
+ * @context: the security context
+ * @scontext: the resulting type string
+ * @scontext_len: the length of scontext including the NULL byte
+ *
+ * Description:
+ * Allocate a buffer for the type name specified in context and copy the type
+ * name into the buffer. The caller must free the buffer when finished.
+ * Returns zero on success, negative values on failure.
+ *
+ */
+static int selinux_netlbl_domain_export(const struct context *context,
+ char **scontext,
+ u32 *scontext_len)
+{
+ char *str;
+ u32 str_len;
+
+ *scontext = NULL;
+ if (scontext_len != NULL)
+ *scontext_len = 0;
+ str_len = strlen(policydb.p_type_val_to_name[context->type - 1]) + 1;
+ str = kmalloc(str_len, GFP_ATOMIC);
+ if (str == NULL)
+ return -ENOMEM;
+ strcpy(str, policydb.p_type_val_to_name[context->type - 1]);
+
+ *scontext = str;
+ if (scontext_len != NULL)
+ *scontext_len = str_len;
+ return 0;
+}
+
+/**
+ * selinux_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
+ * @skb: the network packet
+ * @secattr: the NetLabel packet security attributes
+ * @base_sid: the SELinux SID to use as a context for MLS only attributes
+ * @sid: the SELinux SID
+ *
+ * Description:
+ * Convert the given NetLabel packet security attributes in @secattr into a
+ * SELinux SID. If the @secattr field does not contain a full SELinux
+ * SID/context then use the context in @base_sid as the foundation. If @skb
+ * is not NULL attempt to cache as much data as possibile. Returns zero on
+ * success, negative values on failure.
+ *
+ */
+static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb,
+ struct netlbl_lsm_secattr *secattr,
+ const u32 base_sid,
+ u32 *sid)
+{
+ int ret_val = -EIDRM;
+ struct context *ctx;
+ struct context ctx_new;
+ struct netlbl_cache *cache;
+ u32 ctx_new_destroy = 0;
+
+ if (secattr->set_cache) {
+ cache = NETLBL_CACHE(secattr->cache.data);
+ switch (cache->type) {
+ case NETLBL_CACHE_T_SID:
+ *sid = cache->data.sid;
+ break;
+ case NETLBL_CACHE_T_MLSLBL:
+ ctx = sidtab_search(&sidtab, base_sid);
+ if (ctx == NULL)
+ goto netlbl_secattr_to_sid_failure;
+ ret_val = context_cpy(&ctx_new, ctx);
+ if (ret_val != 0)
+ goto netlbl_secattr_to_sid_failure;
+ ctx_new_destroy = 1;
+ mls_context_destroy(&ctx_new);
+
+ ctx_new.range.level[0].sens =
+ cache->data.mls_label.sens;
+ ret_val = ebitmap_cpy(&ctx_new.range.level[0].cat,
+ &cache->data.mls_label.cat);
+ if (ret_val != 0)
+ goto netlbl_secattr_to_sid_failure;
+ ctx_new.range.level[1].sens =
+ cache->data.mls_label.sens;
+ ret_val = ebitmap_cpy(&ctx_new.range.level[1].cat,
+ &cache->data.mls_label.cat);
+ if (ret_val != 0)
+ goto netlbl_secattr_to_sid_failure;
+
+ ret_val = sidtab_context_to_sid(&sidtab,
+ &ctx_new,
+ sid);
+ break;
+ default:
+ goto netlbl_secattr_to_sid_failure;
+ }
+ } else if (secattr->set_mls_lvl) {
+ ctx = sidtab_search(&sidtab, base_sid);
+ if (ctx == NULL)
+ goto netlbl_secattr_to_sid_failure;
+ ret_val = context_cpy(&ctx_new, ctx);
+ if (ret_val != 0)
+ goto netlbl_secattr_to_sid_failure;
+ ctx_new_destroy = 1;
+ mls_context_destroy(&ctx_new);
+
+ if (mls_import_lvl(&ctx_new,
+ secattr->mls_lvl,
+ secattr->mls_lvl) != 0)
+ goto netlbl_secattr_to_sid_failure;
+ if (secattr->set_mls_cat) {
+ if (mls_import_cat(&ctx_new,
+ secattr->mls_cat,
+ secattr->mls_cat_len,
+ secattr->mls_cat,
+ secattr->mls_cat_len) != 0)
+ goto netlbl_secattr_to_sid_failure;
+ }
+
+ ret_val = mls_context_isvalid(&policydb, &ctx_new);
+ if (ret_val != 1)
+ goto netlbl_secattr_to_sid_failure;
+
+ if (skb != NULL)
+ selinux_netlbl_cache_add(skb, &ctx_new);
+
+ ret_val = sidtab_context_to_sid(&sidtab, &ctx_new, sid);
+ } else
+ *sid = SECINITSID_UNLABELED;
+
+ ret_val = 0;
+
+netlbl_secattr_to_sid_failure:
+ if (ctx_new_destroy)
+ context_destroy(&ctx_new);
+ return ret_val;
+}
+
+/**
+ * selinux_netlbl_skbuff_getsid - Get the sid of a packet using NetLabel
+ * @skb: the packet
+ * @base_sid: the SELinux SID to use as a context for MLS only attributes
+ * @sid: the SID
+ *
+ * Description:
+ * Call the NetLabel mechanism to get the security attributes of the given
+ * packet and use those attributes to determine the correct context/SID to
+ * assign to the packet. Returns zero on success, negative values on failure.
+ *
+ */
+static int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
+ const u32 base_sid,
+ u32 *sid)
+{
+ int ret_val;
+ struct netlbl_lsm_secattr secattr;
+
+ netlbl_secattr_init(&secattr);
+ ret_val = netlbl_skbuff_getattr(skb, &secattr);
+ if (ret_val == 0)
+ ret_val = selinux_netlbl_secattr_to_sid(skb,
+ &secattr,
+ base_sid,
+ sid);
+
+ secattr.set_cache = 0;
+ netlbl_secattr_destroy(&secattr);
+
+ return ret_val;
+}
+
+/**
+ * selinux_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
+ * @sock: the socket to label
+ * @sock_family: the socket family
+ * @sid: the SID to use
+ *
+ * Description:
+ * Attempt to label a socket using the NetLabel mechanism using the given
+ * SID. Returns zero values on success, negative values on failure.
+ *
+ */
+static int selinux_netlbl_socket_setsid(struct socket *sock,
+ const int sock_family,
+ u32 sid)
+{
+ int ret_val;
+ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+ struct netlbl_lsm_secattr secattr;
+ struct context *ctx;
+
+ ctx = sidtab_search(&sidtab, sid);
+ if (ctx != NULL) {
+ netlbl_secattr_init(&secattr);
+
+ if (selinux_netlbl_domain_export(ctx,
+ &secattr.domain,
+ NULL) == 0)
+ secattr.set_domain = 1;
+ if (mls_export_lvl(ctx, &secattr.mls_lvl, NULL) == 0)
+ secattr.set_mls_lvl = 1;
+ if (mls_export_cat(ctx,
+ &secattr.mls_cat,
+ &secattr.mls_cat_len,
+ NULL,
+ NULL) == 0)
+ secattr.set_mls_cat = 1;
+
+ ret_val = netlbl_socket_setattr(sock, &secattr);
+ if (ret_val == 0) {
+ isec->netlbl.netlbl_sid = sid;
+ isec->netlbl.labeled = 1;
+ }
+
+ netlbl_secattr_destroy(&secattr);
+ } else
+ ret_val = -ENOENT;
+
+ return ret_val;
+}
+
+/**
+ * selinux_netlbl_socket_peeksid - Get the SID of the first queued packet
+ * @sock: the socket to query
+ * @sid: the packet's SID
+ *
+ * Description:
+ * Examine the first incoming packet in the socket's queue and determine the
+ * packet's SELinux SID. Return zero on success, negative values on failure.
+ *
+ */
+static int selinux_netlbl_socket_peeksid(struct socket *sock, u32 *sid)
+{
+ int ret_val;
+ struct netlbl_lsm_secattr secattr;
+ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+
+ netlbl_secattr_init(&secattr);
+ ret_val = netlbl_socket_peekattr(sock, &secattr);
+ if (ret_val == 0)
+ ret_val = selinux_netlbl_secattr_to_sid(NULL,
+ &secattr,
+ isec->sid,
+ sid);
+
+ secattr.set_cache = 0;
+ netlbl_secattr_destroy(&secattr);
+
+ return ret_val;
+}
+
+/**
+ * selinux_netlbl_socket_create - Label a socket using the NetLabel mechanism
+ * @sock: the socket to label
+ * @sock_family: the socket family
+ * @sid: the SID to use
+ *
+ * Description:
+ * Attempt to label a socket using the NetLabel mechanism using the given
+ * SID. Returns zero values on success, negative values on failure.
+ *
+ */
+int selinux_netlbl_socket_create(struct socket *sock,
+ const int sock_family,
+ u32 sid)
+{
+ struct inode_security_struct *isec;
+
+ if (!ss_initialized || sock_family != PF_INET)
+ return 0;
+
+ isec = SOCK_INODE(sock)->i_security;
+ isec->netlbl.req_netlbl = 1;
+
+ /* PM - should we audit failures, or at the very least do a printk()
+ so users are not left wondering? */
+ return selinux_netlbl_socket_setsid(sock, sock_family, sid);
+}
+
+/**
+ * selinux_netlbl_socket_accept - Handle the labeling of an accept()ed socket
+ * @sock: the original socket
+ * @newsock: the new accept()ed socket
+ *
+ * Description:
+ * Attempt to label a socket using the NetLabel mechanism based on the packets
+ * in the queue and the original socket's SID.
+ *
+ */
+void selinux_netlbl_socket_accept(struct socket *sock, struct socket *newsock)
+{
+ int ret_val;
+ struct inode_security_struct *newisec;
+ struct netlbl_lsm_secattr secattr;
+
+ if (!ss_initialized ||
+ newsock->sk == NULL || newsock->sk->sk_family != PF_INET)
+ return;
+
+ newisec = SOCK_INODE(newsock)->i_security;
+ newisec->netlbl.req_netlbl = 1;
+
+ netlbl_secattr_init(&secattr);
+ ret_val = netlbl_socket_getattr(newsock, &secattr);
+ if (ret_val == 0)
+ ret_val = selinux_netlbl_secattr_to_sid(NULL,
+ &secattr,
+ newisec->sid,
+ &newisec->netlbl.peer_sid);
+ if (ret_val != 0)
+ newisec->netlbl.peer_sid = SECSID_NULL;
+ secattr.set_cache = 0;
+ netlbl_secattr_destroy(&secattr);
+}
+
+/**
+ * selinux_netlbl_file_permission - Very the file/socket is NetLabel labeled
+ * @inode: the file descriptor's inode
+ * @mask: the permission mask
+ *
+ * Description:
+ * Looks at a file's inode and if it is marked as a socket protected by
+ * NetLabel then verify that the socket has been labeled, if not try to label
+ * the socket now with the task's SID. Returns zero on success, negative
+ * values on failure.
+ *
+ */
+int selinux_netlbl_inode_permission(struct inode *inode, int mask)
+{
+ int ret_val = 0;
+ struct inode_security_struct *isec = inode->i_security;
+ struct task_security_struct *tsec;
+ struct netlbl_security_struct *netlbl_sec = &isec->netlbl;
+ struct socket *sock;
+
+ if (netlbl_sec->req_netlbl && (mask & (MAY_WRITE | MAY_APPEND))) {
+ tsec = current->security;
+ if (netlbl_sec->labeled == 0) {
+ sock = SOCKET_I(inode);
+ ret_val = selinux_netlbl_socket_setsid(sock,
+ sock->sk->sk_family,
+ tsec->sid);
+ } else if (netlbl_sec->netlbl_sid != tsec->sid &&
+ netlbl_sec->netlbl_sid != SECINITSID_KERNEL)
+ ret_val = -EACCES;
+ }
+
+ return ret_val;
+}
+
+/**
+ * selinux_netlbl_sock_rcv_skb - Do an inbound access check using NetLabel
+ * @sock_class: the socket class
+ * @sock_sid: the socket's SID
+ * @skb: the incoming packet
+ * @ad: the audit data
+ *
+ * Description:
+ * Fetch the NetLabel security attributes from @skb and perform an access check
+ * against the receiving socket. Returns zero on success, negative values on
+ * error.
+ *
+ */
+int selinux_netlbl_sock_rcv_skb(const u16 sock_class,
+ const u32 sock_sid,
+ struct sk_buff *skb,
+ struct avc_audit_data *ad)
+{
+ int ret_val;
+ u32 netlbl_sid;
+ u32 recv_perm;
+
+ ret_val = selinux_netlbl_skbuff_getsid(skb, sock_sid, &netlbl_sid);
+ if (ret_val)
+ goto netlbl_sock_rcv_skb;
+
+ /* PM - at some point we want to do an unlabeled check here too but
+ we need a way to enable/disable NetLabel checks at runtime first,
+ see RH BZ #195238 for more details */
+ if (netlbl_sid != SECINITSID_UNLABELED) {
+ switch (sock_class) {
+ case SECCLASS_UDP_SOCKET:
+ recv_perm = UDP_SOCKET__RECV_MSG;
+ break;
+ case SECCLASS_TCP_SOCKET:
+ recv_perm = TCP_SOCKET__RECV_MSG;
+ break;
+ default:
+ recv_perm = RAWIP_SOCKET__RECV_MSG;
+ break;
+ }
+
+ ret_val = avc_has_perm(sock_sid,
+ netlbl_sid,
+ sock_class,
+ recv_perm,
+ ad);
+ if (ret_val)
+ netlbl_skbuff_err(skb, ret_val);
+ }
+
+netlbl_sock_rcv_skb:
+ return ret_val;
+}
+
+/**
+ * selinux_netlbl_socket_peersid - Return the peer SID of a connected socket
+ * @sock: the socket
+ * @peer_sid: the peer SID
+ *
+ * Description:
+ * Examine @sock to find the connected peer's SID, if that is not possibile
+ * check the socket's receive queue and take the SID from the incoming
+ * packets. Returns zero on success, negative values on error.
+ *
+ */
+int selinux_netlbl_socket_getpeersec_stream(struct socket *sock, u32 *peer_sid)
+{
+ int ret_val = 0;
+ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+
+ if (isec->netlbl.peer_sid == 0)
+ ret_val = selinux_netlbl_socket_peeksid(sock, peer_sid);
+ else
+ *peer_sid = isec->netlbl.peer_sid;
+
+ return ret_val;
+}
+
+/**
+ * selinux_netlbl_socket_getpeersec_dgram - Return the SID of a NetLabel packet
+ * @skb: the packet
+ * @peer_sid: the packet's SID
+ *
+ * Description:
+ * Examine @skb to find the SID assigned to it by NetLabel. Returns zero on
+ * success, negative values on error.
+ *
+ */
+int selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb, u32 *peer_sid)
+{
+ struct inode_security_struct *isec;
+
+ if (skb->sk == NULL || skb->sk->sk_socket == NULL)
+ return -ENOPROTOOPT;
+
+ isec = SOCK_INODE(skb->sk->sk_socket)->i_security;
+
+ return selinux_netlbl_skbuff_getsid(skb, isec->sid, peer_sid);
+}
Index: linux-2.6.17.i686-quilt/security/selinux/ss/services.c
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/ss/services.c
+++ linux-2.6.17.i686-quilt/security/selinux/ss/services.c
@@ -13,6 +13,11 @@
*
* Added conditional policy language extensions
*
+ * Updated: Hewlett-Packard <paul.moore@hp.com>
+ *
+ * Added support for NetLabel
+ *
+ * Copyright (C) 2006 Hewlett-Packard Development Company, L.P.
* Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
* Copyright (C) 2003 - 2004 Tresys Technology, LLC
* Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
@@ -29,6 +34,7 @@
#include <linux/sched.h>
#include <linux/audit.h>
#include <linux/mutex.h>
+#include <net/sock.h>
#include "flask.h"
#include "avc.h"
@@ -40,6 +46,8 @@
#include "services.h"
#include "conditional.h"
#include "mls.h"
+#include "objsec.h"
+#include "selinux_netlabel.h"
extern void selnl_notify_policyload(u32 seqno);
unsigned int policydb_loaded_version;
@@ -54,7 +62,7 @@ static DEFINE_MUTEX(load_mutex);
#define LOAD_LOCK mutex_lock(&load_mutex)
#define LOAD_UNLOCK mutex_unlock(&load_mutex)
-static struct sidtab sidtab;
+struct sidtab sidtab;
struct policydb policydb;
int ss_initialized = 0;
@@ -1241,6 +1249,7 @@ int security_load_policy(void *data, siz
selinux_complete_init();
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
+ selinux_netlbl_cache_invalidate();
return 0;
}
@@ -1295,6 +1304,7 @@ int security_load_policy(void *data, siz
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
+ selinux_netlbl_cache_invalidate();
return 0;
Index: linux-2.6.17.i686-quilt/security/selinux/ss/services.h
===================================================================
--- linux-2.6.17.i686-quilt.orig/security/selinux/ss/services.h
+++ linux-2.6.17.i686-quilt/security/selinux/ss/services.h
@@ -9,7 +9,9 @@
#include "policydb.h"
#include "sidtab.h"
+extern struct sidtab sidtab;
extern struct policydb policydb;
+extern int ss_initialized;
#endif /* _SS_SERVICES_H_ */
--
paul moore
linux security @ hp
^ permalink raw reply
* [RFC 3/8] NetLabel: CIPSOv4 engine
From: paul.moore @ 2006-06-22 22:49 UTC (permalink / raw)
To: netdev; +Cc: davem
In-Reply-To: <20060622224910.885573000@flek.zko.hp.com>
[-- Attachment #1: netlabel-net_cipsov4-2.6.17 --]
[-- Type: text/plain, Size: 50050 bytes --]
Add support for the Commercial IP Security Option (CIPSO) to the IPv4 network
stack. CIPSO has become a de-facto standard for trusted/labeled networking
amongst existing Trusted Operating Systems such as Trusted Solaris, HP-UX CMW,
etc. This implementation is designed to be used with the NetLabel subsystem
to provide explicit packet labeling to LSM developers.
The CIPSO/IPv4 packet labeling works by the LSM calling a NetLabel API function
which attaches a CIPSO label (IPv4 option) to a given socket; this in turn
attaches the CIPSO label to every packet leaving the socket without any extra
processing on the outbound side. On the inbound side the individual packet's
sk_buff is examined through a call to a NetLabel API function to determine if a
CIPSO/IPv4 label is present and if so the security attributes of the CIPSO
label are returned to the caller of the NetLabel API function.
---
net/ipv4/cipso_ipv4.c | 1755 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 1755 insertions(+)
Index: linux-2.6.17.i686-quilt/net/ipv4/cipso_ipv4.c
===================================================================
--- /dev/null
+++ linux-2.6.17.i686-quilt/net/ipv4/cipso_ipv4.c
@@ -0,0 +1,1755 @@
+/*
+ * CIPSO - Commercial IP Security Option
+ *
+ * This is an implementation of the CIPSO 2.2 protocol as specified in
+ * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
+ * FIPS-188, copies of both documents can be found in the Documentation
+ * directory. While CIPSO never became a full IETF RFC standard many vendors
+ * have chosen to adopt the protocol and over the years it has become a
+ * de-facto standard for labeled networking.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/jhash.h>
+#include <net/ip.h>
+#include <net/icmp.h>
+#include <net/tcp.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include <asm/bug.h>
+
+struct cipso_v4_domhsh_entry {
+ char *domain;
+ u32 valid;
+ struct list_head list;
+ struct rcu_head rcu;
+};
+
+/* List of available DOI definitions */
+/* XXX - Updates should be minimal so having a single lock for the
+ cipso_v4_doi_list and the cipso_v4_doi_list->dom_list should be
+ okay. */
+/* XXX - This currently assumes a minimal number of different DOIs in use,
+ if in practice there are a lot of different DOIs this list should
+ probably be turned into a hash table or something similar so we
+ can do quick lookups. */
+DEFINE_SPINLOCK(cipso_v4_doi_list_lock);
+static struct list_head cipso_v4_doi_list = LIST_HEAD_INIT(cipso_v4_doi_list);
+
+/* Label mapping cache */
+#define CIPSO_V4_CACHE_BUCKETBITS 7
+#define CIPSO_V4_CACHE_BUCKETS (1 << CIPSO_V4_CACHE_BUCKETBITS)
+#define CIPSO_V4_CACHE_BUCKETSIZE 10
+#define CIPSO_V4_CACHE_REORDERLIMIT 10
+/* PM - the number of cache buckets should probably be a compile time option */
+struct cipso_v4_map_cache_bkt {
+ spinlock_t lock;
+ u32 size;
+ struct list_head list;
+};
+struct cipso_v4_map_cache_entry {
+ u32 hash;
+ unsigned char *key;
+ u32 key_len;
+
+ struct netlbl_lsm_cache lsm_data;
+
+ u32 activity;
+ struct list_head list;
+};
+static u32 cipso_v4_cache_size = 0;
+static struct cipso_v4_map_cache_bkt *cipso_v4_cache = NULL;
+#define CIPSO_V4_CACHE_ENABLED (cipso_v4_cache_size > 0)
+
+/*
+ * Helper Functions
+ */
+
+/**
+ * cipso_v4_bitmap_walk - Walk a bitmap looking for a bit
+ * @bitmap: the bitmap
+ * @bitmap_len: length in bits
+ * @offset: starting offset
+ * @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
+ *
+ * Description:
+ * Starting at @offset, walk the bitmap from left to right until either the
+ * desired bit is found or we reach the end. Return the bit offset, -1 if
+ * not found, or -2 if error.
+ */
+static int cipso_v4_bitmap_walk(const unsigned char *bitmap,
+ const u32 bitmap_len,
+ const u32 offset,
+ const u8 state)
+{
+ u32 bit_spot;
+ u32 byte_offset;
+ unsigned char bitmask;
+ unsigned char byte;
+
+ /* gcc always rounds to zero when doing integer division */
+ byte_offset = offset / 8;
+ byte = bitmap[byte_offset];
+ bit_spot = offset;
+ bitmask = 0x80 >> offset % 8;
+
+ /* XXX - probably should use include/asm/bitops.h if we can */
+ while (bit_spot < bitmap_len) {
+ if ((state && (byte & bitmask) == bitmask) ||
+ (state == 0 && (byte & bitmask) == 0))
+ return bit_spot;
+
+ bit_spot++;
+ bitmask >>= 1;
+ if (bitmask == 0) {
+ byte = bitmap[++byte_offset];
+ bitmask = 0x80;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ * cipso_v4_bitmap_setbit - Sets a single bit in a bitmap
+ * @bitmap: the bitmap
+ * @bit: the bit
+ * @state: if non-zero, set the bit (1) else clear the bit (0)
+ *
+ * Description:
+ * Set a single bit in the bitmask. Returns zero on success, negative values
+ * on error.
+ */
+static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
+ const u32 bit,
+ const u8 state)
+{
+ u32 byte_spot;
+ u8 bitmask;
+
+ /* gcc always rounds to zero when doing integer division */
+ byte_spot = bit / 8;
+ bitmask = 0x80 >> bit % 8;
+ if (state)
+ bitmap[byte_spot] |= bitmask;
+ else
+ bitmap[byte_spot] &= ~bitmask;
+}
+
+/**
+ * cipso_v4_doi_domhsh_free - Frees a domain list entry
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to a domain list entry can be released
+ * safely.
+ *
+ */
+static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
+{
+ struct cipso_v4_domhsh_entry *ptr;
+
+ ptr = container_of(entry, struct cipso_v4_domhsh_entry, rcu);
+ if (ptr->domain)
+ kfree(ptr->domain);
+ kfree(ptr);
+}
+
+/**
+ * cipso_v4_cache_entry_free - Frees a cache entry
+ * @entry: the entry to free
+ *
+ * Description:
+ * This function frees the memory associated with a cache entry.
+ *
+ */
+static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry)
+{
+ if (entry->lsm_data.free)
+ entry->lsm_data.free(entry->lsm_data.data);
+ if (entry->key)
+ kfree(entry->key);
+ kfree(entry);
+}
+
+/**
+ * cipso_v4_map_cache_hash - Hashing function for the CIPSO cache
+ * @key: the hash key
+ * @key_len: the length of the key in bytes
+ *
+ * Description:
+ * The CIPSO tag hashing function. Returns a 32-bit hash value.
+ *
+ */
+static u32 cipso_v4_map_cache_hash(const unsigned char *key, const u32 key_len)
+{
+ /* PM - not sure if this is a good hash for this particular use but
+ it's probably better than what I had here before */
+ return jhash(key, key_len, 0);
+}
+
+/*
+ * Label Mapping Cache Functions
+ */
+
+/**
+ * cipso_v4_cache_init - Initialize the CIPSO cache
+ * @bkt_size: the number of cache buckets
+ *
+ * Description:
+ * Initializes the CIPSO label mapping cache, this function should be called
+ * before any of the other functions defined in this file. Returns zero on
+ * success, negative values on error.
+ *
+ */
+static int cipso_v4_cache_init(const u32 bkt_size)
+{
+ struct cipso_v4_map_cache_bkt *cache;
+ u32 iter;
+
+ if (bkt_size == 0)
+ return -EINVAL;
+
+ cache = kcalloc(bkt_size,
+ sizeof(struct cipso_v4_map_cache_bkt), GFP_KERNEL);
+ if (cache == NULL)
+ return -ENOMEM;
+
+ for (iter = 0; iter < bkt_size; iter++) {
+ cache[iter].lock = SPIN_LOCK_UNLOCKED;
+ cache[iter].size = 0;
+ INIT_LIST_HEAD(&cache[iter].list);
+ }
+ cipso_v4_cache = cache;
+ cipso_v4_cache_size = bkt_size;
+
+ return 0;
+}
+
+/**
+ * cipso_v4_cache_destroy - Destroy the CIPSO cache
+ *
+ * Description:
+ * Clears the CIPSO cache and frees all the memory. This function does not
+ * hold any locks and should only be called when the module is being unloaded.
+ *
+ */
+static int cipso_v4_cache_destroy(void)
+{
+ struct cipso_v4_map_cache_bkt *cache;
+ struct cipso_v4_map_cache_entry *entry;
+ u32 cache_size;
+ u32 iter;
+
+ cache = cipso_v4_cache;
+ cache_size = cipso_v4_cache_size;
+ cipso_v4_cache_size = 0;
+ cipso_v4_cache = NULL;
+
+ for (iter = 0; iter < cache_size; iter++)
+ list_for_each_entry(entry, &cache[iter].list, list) {
+ list_del(&entry->list);
+ cipso_v4_cache_entry_free(entry);
+ }
+
+ return 0;
+}
+
+/**
+ * cipso_v4_cache_invalidate - Invalidates the current CIPSO cache
+ *
+ * Description:
+ * Invalidates and frees any entries in the CIPSO cache. Returns zero on
+ * success and negative values on failure.
+ *
+ */
+void cipso_v4_cache_invalidate(void)
+{
+ struct cipso_v4_map_cache_entry *entry, *tmp_entry;
+ u32 iter;
+
+ if (!CIPSO_V4_CACHE_ENABLED)
+ return;
+
+ for (iter = 0; iter < cipso_v4_cache_size; iter++) {
+ spin_lock(&cipso_v4_cache[iter].lock);
+ list_for_each_entry_safe(entry,
+ tmp_entry,
+ &cipso_v4_cache[iter].list, list) {
+ list_del(&entry->list);
+ cipso_v4_cache_entry_free(entry);
+ }
+ cipso_v4_cache[iter].size = 0;
+ spin_unlock(&cipso_v4_cache[iter].lock);
+ }
+
+ return;
+}
+
+/**
+ * cipso_v4_cache_check - Check the CIPSO cache for a label mapping
+ * @key: the buffer to check
+ * @key_len: buffer length in bytes
+ * @secattr: the security attribute struct to use
+ *
+ * Description:
+ * This function checks the cache to see if a label mapping already exists for
+ * the given key. If there is a match then the cache is adjusted and the
+ * @secattr struct is populated with the correct LSM security attributes. The
+ * cache is adjusted in the following manner if the entry is not already the
+ * first in the cache bucket:
+ *
+ * 1. The cache entry's activity counter is incremented
+ * 2. The previous (higher ranking) entry's activity counter is decremented
+ * 3. If the difference between the two activity counters is geater than
+ * CIPSO_V4_CACHE_REORDERLIMIT the two entries are swapped
+ *
+ * Returns zero on success, -ENOENT for a cache miss, and other negative values
+ * on error.
+ *
+ */
+static int cipso_v4_cache_check(const unsigned char *key,
+ const u32 key_len,
+ struct netlbl_lsm_secattr *secattr)
+{
+ u32 bkt;
+ struct cipso_v4_map_cache_entry *entry;
+ struct cipso_v4_map_cache_entry *prev_entry = NULL;
+ u32 hash;
+
+ if (!CIPSO_V4_CACHE_ENABLED)
+ return -ENOENT;
+
+ hash = cipso_v4_map_cache_hash(key, key_len);
+ bkt = hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
+ spin_lock(&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 &&
+ memcmp(entry->key, key, key_len) == 0) {
+ entry->activity += 1;
+
+ if (prev_entry != NULL) {
+ if (prev_entry->activity > 0)
+ prev_entry->activity -= 1;
+
+ if (entry->activity > prev_entry->activity &&
+ entry->activity - prev_entry->activity >
+ CIPSO_V4_CACHE_REORDERLIMIT) {
+ __list_del(entry->list.prev,
+ entry->list.next);
+ __list_add(&entry->list,
+ prev_entry->list.prev,
+ &prev_entry->list);
+ }
+ }
+
+ secattr->cache.free = entry->lsm_data.free;
+ secattr->cache.data = entry->lsm_data.data;
+ spin_unlock(&cipso_v4_cache[bkt].lock);
+
+ secattr->set_cache = 1;
+ return 0;
+ }
+ prev_entry = entry;
+ }
+ spin_unlock(&cipso_v4_cache[bkt].lock);
+
+ return -ENOENT;
+}
+
+/**
+ * cipso_v4_cache_add - Add an entry to the CIPSO cache
+ * @skb: the packet
+ * @secattr: the packet's security attributes
+ *
+ * Description:
+ * Add a new entry into the CIPSO label mapping cache. Add the new entry to
+ * head of the cache bucket's list, if the cache bucket is out of room remove
+ * the last entry in the list first. It is important to note that there is
+ * currently no checking for duplicate keys. Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int cipso_v4_cache_add(const struct sk_buff *skb,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val = -EPERM;
+ u32 bkt;
+ struct cipso_v4_map_cache_entry *entry = NULL;
+ struct cipso_v4_map_cache_entry *old_entry = NULL;
+ unsigned char *cipso_ptr;
+ u32 cipso_ptr_len;
+
+ if (!CIPSO_V4_CACHE_ENABLED)
+ return 0;
+
+ cipso_ptr = CIPSO_V4_OPTPTR(skb);
+ cipso_ptr_len = cipso_ptr[1];
+
+ entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
+ if (entry == NULL)
+ return -ENOMEM;
+ entry->key = kmalloc(cipso_ptr_len, GFP_ATOMIC);
+ if (entry->key == NULL) {
+ ret_val = -ENOMEM;
+ goto cache_add_failure;
+ }
+ memcpy(entry->key, cipso_ptr, cipso_ptr_len);
+ entry->key_len = cipso_ptr_len;
+ entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
+ entry->lsm_data.free = secattr->cache.free;
+ entry->lsm_data.data = secattr->cache.data;
+
+ bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
+ spin_lock(&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;
+ } else {
+ old_entry = list_entry(cipso_v4_cache[bkt].list.prev,
+ struct cipso_v4_map_cache_entry, list);
+ list_del(&old_entry->list);
+ list_add(&entry->list, &cipso_v4_cache[bkt].list);
+ cipso_v4_cache_entry_free(old_entry);
+ }
+ spin_unlock(&cipso_v4_cache[bkt].lock);
+
+ return 0;
+
+cache_add_failure:
+ if (entry)
+ cipso_v4_cache_entry_free(entry);
+ return ret_val;
+}
+
+/*
+ * DOI List Functions
+ */
+
+/**
+ * cipso_v4_doi_search - Searches for a DOI definition
+ * @doi: the DOI to search for
+ *
+ * Description:
+ * Search the DOI definition list for a DOI definition with a DOI value that
+ * matches @doi. The caller is responsibile for calling rcu_read_[un]lock().
+ * Returns a pointer to the DOI definition on success and NULL on failure.
+ */
+static struct cipso_v4_doi *cipso_v4_doi_search(const u32 doi)
+{
+ struct cipso_v4_doi *iter;
+
+ list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
+ if (iter->doi == doi && iter->valid)
+ return iter;
+ return NULL;
+}
+
+/**
+ * cipso_v4_doi_add - Add a new DOI to the CIPSO protocol engine
+ * @doi_def: the DOI structure
+ *
+ * Description:
+ * The caller defines a new DOI for use by the CIPSO engine and calls this
+ * function to add it to the list of acceptable domains. The caller must
+ * ensure that the mapping table specified in @doi_def->map meets all of the
+ * requirements of the mapping type (see cipso_ipv4.h for details). Returns
+ * zero on success and non-zero on failure.
+ *
+ */
+int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
+{
+ if (doi_def == NULL || doi_def->doi == CIPSO_V4_DOI_UNKNOWN)
+ return -EINVAL;
+
+ doi_def->valid = 1;
+ INIT_RCU_HEAD(&doi_def->rcu);
+ INIT_LIST_HEAD(&doi_def->dom_list);
+
+ rcu_read_lock();
+ if (cipso_v4_doi_search(doi_def->doi) != NULL) {
+ rcu_read_unlock();
+ return -EEXIST;
+ }
+ spin_lock(&cipso_v4_doi_list_lock);
+ list_add_tail_rcu(&doi_def->list, &cipso_v4_doi_list);
+ spin_unlock(&cipso_v4_doi_list_lock);
+ rcu_read_unlock();
+
+ return 0;
+}
+
+/**
+ * cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
+ * @doi: the DOI value
+ * @callback: the DOI cleanup/free callback
+ *
+ * Description:
+ * Removes a DOI definition from the CIPSO engine, @callback is called to
+ * free any memory. The NetLabel routines will be called to release their own
+ * LSM domain mappings as well as our own domain list. Returns zero on
+ * success and negative values on failure.
+ *
+ */
+int cipso_v4_doi_remove(const u32 doi,
+ void (*callback) (struct rcu_head * head))
+{
+ struct cipso_v4_doi *doi_def;
+ struct cipso_v4_domhsh_entry *dom_iter;
+
+ if (callback == NULL)
+ return -EINVAL;
+
+ rcu_read_lock();
+ doi_def = cipso_v4_doi_search(doi);
+ if (doi_def != NULL) {
+ spin_lock(&cipso_v4_doi_list_lock);
+ doi_def->valid = 0;
+ list_del_rcu(&doi_def->list);
+ spin_unlock(&cipso_v4_doi_list_lock);
+ list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
+ if (dom_iter->valid)
+ netlbl_domhsh_remove(dom_iter->domain);
+ rcu_read_unlock();
+ /* PM - should we invalidate the cache before we drop the
+ lock? */
+ cipso_v4_cache_invalidate();
+
+ call_rcu(&doi_def->rcu, callback);
+ return 0;
+ }
+ rcu_read_unlock();
+
+ return -ENOENT;
+}
+
+/**
+ * cipso_v4_doi_getdef - Returns a pointer to a valid DOI definition
+ * @doi: the DOI value
+ *
+ * Description:
+ * Searches for a valid DOI definition and if one is found it is returned to
+ * the caller. Otherwise NULL is returned. The caller must ensure that
+ * rcu_read_lock() is held while accessing the returned definition.
+ *
+ */
+struct cipso_v4_doi *cipso_v4_doi_getdef(const u32 doi)
+{
+ return cipso_v4_doi_search(doi);
+}
+
+/**
+ * cipso_v4_doi_dump - Dump the CIPSO DOI definitions into a sk_buff
+ * @doi: the DOI value
+ * @headroom: the amount of headroom to allocate for the sk_buff
+ *
+ * Description:
+ * If the @doi value is zero then dump a list of all the configured DOI values
+ * into a sk_buff. If the @doi value is non-zero, lookup the match DOI
+ * definition and dump it's contents into a sk_buff. The returned sk_buff has
+ * room at the front of the sk_buff for a nlmsghdr struct and a @headroom
+ * bytes. See 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(const u32 doi, const u32 headroom)
+{
+ struct sk_buff *skb;
+ unsigned char *buf;
+ struct cipso_v4_doi *iter;
+ u32 doi_cnt = 0;
+ u32 tag_cnt = 0;
+ u32 lvl_cnt = 0;
+ u32 cat_cnt = 0;
+ u32 buf_len;
+ u32 tmp_len;
+
+ /* XXX - In both cases, this is kinda ugly as we have to go through
+ the list once to determine how large of a buffer we need,
+ drop the locks, allocate the buffer, grab the locks, and
+ finally fill the buffer. The problem is that there is that
+ open window where the table could grow and we will end up
+ short on space. */
+
+ if (doi == 0) {
+ buf_len = 4;
+ rcu_read_lock();
+ list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
+ if (iter->valid) {
+ doi_cnt += 1;
+ buf_len += 8;
+ }
+ rcu_read_unlock();
+
+ skb = alloc_skb(NLMSG_SPACE(headroom + buf_len), GFP_KERNEL);
+ if (skb == NULL)
+ return NULL;
+ skb_reserve(skb, NLMSG_SPACE(headroom));
+ tmp_len = skb_tailroom(skb);
+ if (tmp_len < buf_len)
+ goto doi_dump_failure;
+ buf = skb_put(skb, buf_len);
+ buf_len -= 4;
+ netlbl_putinc_u32(&buf, doi_cnt);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(iter, &cipso_v4_doi_list, list)
+ if (iter->valid) {
+ if (buf_len < 8) {
+ rcu_read_unlock();
+ goto doi_dump_failure;
+ }
+ buf_len -= 8;
+ netlbl_putinc_u32(&buf, iter->doi);
+ netlbl_putinc_u32(&buf, iter->type);
+ }
+ rcu_read_unlock();
+ } else {
+ rcu_read_lock();
+ iter = cipso_v4_doi_getdef(doi);
+ if (iter == NULL) {
+ rcu_read_unlock();
+ return NULL;
+ }
+ buf_len = 4;
+ switch (iter->type) {
+ case CIPSO_V4_MAP_PASS:
+ buf_len += 4;
+ while (tag_cnt < CIPSO_V4_TAG_MAXCNT &&
+ iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) {
+ tag_cnt += 1;
+ buf_len += 1;
+ }
+ break;
+ case CIPSO_V4_MAP_STD:
+ buf_len += 12;
+ while (tag_cnt < CIPSO_V4_TAG_MAXCNT &&
+ iter->tags[tag_cnt] != CIPSO_V4_TAG_INVALID) {
+ tag_cnt += 1;
+ buf_len += 1;
+ }
+ tmp_len = 0;
+ while (tmp_len < iter->map.std->lvl.local_size)
+ if (iter->map.std->lvl.local[tmp_len++] !=
+ CIPSO_V4_INV_LVL) {
+ lvl_cnt += 1;
+ buf_len += 8;
+ }
+ tmp_len = 0;
+ while (tmp_len < iter->map.std->cat.local_size)
+ if (iter->map.std->cat.local[tmp_len++] !=
+ CIPSO_V4_INV_CAT) {
+ cat_cnt += 1;
+ buf_len += 8;
+ }
+ break;
+ default:
+ rcu_read_unlock();
+ return NULL;
+ }
+ rcu_read_unlock();
+
+ skb = alloc_skb(NLMSG_SPACE(sizeof(headroom) + buf_len),
+ GFP_KERNEL);
+ if (skb == NULL)
+ return NULL;
+ skb_reserve(skb, NLMSG_SPACE(headroom));
+ tmp_len = skb_tailroom(skb);
+ if (tmp_len < buf_len)
+ goto doi_dump_failure;
+ buf = skb_put(skb, buf_len);
+ buf_len -= 4;
+ netlbl_putinc_u32(&buf, iter->type);
+
+ rcu_read_lock();
+ if (iter != cipso_v4_doi_getdef(doi)) {
+ rcu_read_unlock();
+ goto doi_dump_failure;
+ }
+ switch (iter->type) {
+ case CIPSO_V4_MAP_PASS:
+ netlbl_putinc_u32(&buf, tag_cnt);
+ tmp_len = 0;
+ while (tmp_len < CIPSO_V4_TAG_MAXCNT &&
+ iter->tags[tmp_len] != CIPSO_V4_TAG_INVALID) {
+ if (buf_len < 1) {
+ rcu_read_unlock();
+ goto doi_dump_failure;
+ }
+ buf_len -= 1;
+ netlbl_putinc_u8(&buf, iter->tags[tmp_len++]);
+ }
+ break;
+ case CIPSO_V4_MAP_STD:
+ buf_len -= 12;
+ netlbl_putinc_u32(&buf, tag_cnt);
+ netlbl_putinc_u32(&buf, lvl_cnt);
+ netlbl_putinc_u32(&buf, cat_cnt);
+ tmp_len = 0;
+ while (tmp_len < CIPSO_V4_TAG_MAXCNT &&
+ iter->tags[tmp_len] != CIPSO_V4_TAG_INVALID) {
+ if (buf_len < 1) {
+ rcu_read_unlock();
+ goto doi_dump_failure;
+ }
+ buf_len -= 1;
+ netlbl_putinc_u8(&buf, iter->tags[tmp_len++]);
+ }
+ tmp_len = 0;
+ while (tmp_len < iter->map.std->lvl.local_size) {
+ if (iter->map.std->lvl.local[tmp_len] !=
+ CIPSO_V4_INV_LVL) {
+ if (buf_len < 8) {
+ rcu_read_unlock();
+ goto doi_dump_failure;
+ }
+ buf_len -= 8;
+ netlbl_putinc_u32(&buf, tmp_len);
+ netlbl_putinc_u32(&buf,
+ iter->map.std->lvl.
+ local[tmp_len]);
+ }
+ tmp_len += 1;
+ }
+ tmp_len = 0;
+ while (tmp_len < iter->map.std->cat.local_size) {
+ if (iter->map.std->cat.local[tmp_len] !=
+ CIPSO_V4_INV_CAT) {
+ if (buf_len < 8) {
+ rcu_read_unlock();
+ goto doi_dump_failure;
+ }
+ buf_len -= 8;
+ netlbl_putinc_u32(&buf, tmp_len);
+ netlbl_putinc_u32(&buf,
+ iter->map.std->cat.
+ local[tmp_len]);
+ }
+ tmp_len += 1;
+ }
+ break;
+ }
+ rcu_read_unlock();
+ }
+
+ return skb;
+
+doi_dump_failure:
+ kfree(skb);
+ return NULL;
+}
+
+/**
+ * cipso_v4_doi_domhsh_add - Adds a domain entry to a DOI definition
+ * @doi_def: the DOI definition
+ * @domain: the domain to add
+ *
+ * Description:
+ * Adds the @domain to the the DOI specified by @doi_def, this function
+ * should only be called by external functions (i.e. NetLabel). This function
+ * does allocate memory. Returns zero on success, negative values on failure.
+ *
+ */
+int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, const char *domain)
+{
+ struct cipso_v4_domhsh_entry *iter;
+ struct cipso_v4_domhsh_entry *new_dom;
+
+ new_dom = kzalloc(sizeof(*new_dom), GFP_KERNEL);
+ if (new_dom == NULL)
+ return -ENOMEM;
+ if (domain) {
+ new_dom->domain = kstrdup(domain, GFP_KERNEL);
+ if (new_dom->domain == NULL) {
+ kfree(new_dom);
+ return -ENOMEM;
+ }
+ }
+ new_dom->valid = 1;
+ INIT_RCU_HEAD(&new_dom->rcu);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
+ if (iter->valid &&
+ ((domain != NULL && iter->domain != NULL &&
+ strcmp(iter->domain, domain) == 0) ||
+ (domain == NULL && iter->domain == NULL))) {
+ rcu_read_unlock();
+ if (new_dom->domain != NULL)
+ kfree(new_dom->domain);
+ kfree(new_dom);
+ return -EEXIST;
+ }
+ spin_lock(&cipso_v4_doi_list_lock);
+ list_add_tail_rcu(&new_dom->list, &doi_def->dom_list);
+ spin_unlock(&cipso_v4_doi_list_lock);
+ rcu_read_unlock();
+
+ return 0;
+}
+
+/**
+ * cipso_v4_doi_domhsh_remove - Removes a domain entry from a DOI definition
+ * @doi_def: the DOI definition
+ * @domain: the domain to remove
+ *
+ * Description:
+ * Removes the @domain from the DOI specified by @doi_def, this function
+ * should only be called by external functions (i.e. NetLabel). Returns zero
+ * on success and negative values on error.
+ *
+ */
+int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def,
+ const char *domain)
+{
+ struct cipso_v4_domhsh_entry *iter;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
+ if (iter->valid &&
+ ((domain != NULL && iter->domain != NULL &&
+ strcmp(iter->domain, domain) == 0) ||
+ (domain == NULL && iter->domain == NULL))) {
+ spin_lock(&cipso_v4_doi_list_lock);
+ iter->valid = 0;
+ list_del_rcu(&iter->list);
+ spin_unlock(&cipso_v4_doi_list_lock);
+ rcu_read_unlock();
+
+ call_rcu(&iter->rcu, cipso_v4_doi_domhsh_free);
+ return 0;
+ }
+ rcu_read_unlock();
+
+ return -ENOENT;
+}
+
+/*
+ * Label Mapping Functions
+ */
+
+/**
+ * cipso_v4_map_lvl_valid - Checks to see if the given level is understood
+ * @doi_def: the DOI definition
+ * @level: the level to check
+ *
+ * Description:
+ * Checks the given level against the given DOI definition and returns a
+ * negative value if the level does not have a valid mapping and a zero value
+ * if the level is defined by the DOI.
+ *
+ */
+static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def,
+ const u8 level)
+{
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_PASS:
+ return 0;
+ case CIPSO_V4_MAP_STD:
+ if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
+ return 0;
+ break;
+ }
+
+ return -EFAULT;
+}
+
+/**
+ * cipso_v4_map_lvl_hton - Perform a level mapping from the host to the network
+ * @doi_def: the DOI definition
+ * @host_lvl: the host MLS level
+ * @net_lvl: the network/CIPSO MLS level
+ *
+ * Description:
+ * Perform a label mapping to translate a local MLS level to the correct
+ * CIPSO level using the given DOI definition. Returns zero on success,
+ * negative values otherwise.
+ *
+ */
+static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
+ const u32 host_lvl,
+ u32 *net_lvl)
+{
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_PASS:
+ *net_lvl = host_lvl;
+ return 0;
+ case CIPSO_V4_MAP_STD:
+ if (host_lvl < doi_def->map.std->lvl.local_size) {
+ *net_lvl = doi_def->map.std->lvl.local[host_lvl];
+ return 0;
+ }
+ break;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * cipso_v4_map_lvl_ntoh - Perform a level mapping from the network to the host
+ * @doi_def: the DOI definition
+ * @net_lvl: the network/CIPSO MLS level
+ * @host_lvl: the host MLS level
+ *
+ * Description:
+ * Perform a label mapping to translate a CIPSO level to the correct local MLS
+ * level using the given DOI definition. Returns zero on success, negative
+ * values otherwise.
+ *
+ */
+static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
+ const u32 net_lvl,
+ u32 *host_lvl)
+{
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_PASS:
+ *host_lvl = net_lvl;
+ return 0;
+ case CIPSO_V4_MAP_STD:
+ if (net_lvl < doi_def->map.std->lvl.cipso_size) {
+ *host_lvl = doi_def->map.std->lvl.cipso[net_lvl];
+ return 0;
+ }
+ break;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * cipso_v4_map_cat_rbm_valid - Checks to see if the category bitmap is valid
+ * @doi_def: the DOI definition
+ * @bitmap: category bitmap
+ * @bitmap_len: bitmap length in bytes
+ *
+ * Description:
+ * Checks the given category bitmap against the given DOI definition and
+ * returns a negative value if any of the categories in the bitmap do not have
+ * a valid mapping and a zero value if all of the categories are valid.
+ *
+ */
+static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
+ const unsigned char *bitmap,
+ const u32 bitmap_len)
+{
+ int cat = -1;
+ u32 bitmap_len_bits = bitmap_len * 8;
+ u32 cipso_cat_size = doi_def->map.std->cat.cipso_size;
+ u32 *cipso_array = doi_def->map.std->cat.cipso;
+
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_PASS:
+ return 0;
+ case CIPSO_V4_MAP_STD:
+ for (;;) {
+ cat = cipso_v4_bitmap_walk(bitmap,
+ bitmap_len_bits,
+ cat + 1,
+ 1);
+ if (cat < 0)
+ break;
+ if (cat >= cipso_cat_size ||
+ cipso_array[cat] >= CIPSO_V4_INV_CAT)
+ return -EFAULT;
+ }
+
+ if (cat == -1)
+ return 0;
+ break;
+ }
+
+ return -EFAULT;
+}
+
+/**
+ * cipso_v4_map_cat_rbm_hton - Perform a category mapping from host to network
+ * @doi_def: the DOI definition
+ * @host_cat: the category bitmap in host format
+ * @host_cat_len: the length of the host's category bitmap in bytes
+ * @net_cat: the zero'd out category bitmap in network/CIPSO format
+ * @net_cat_len: the length of the CIPSO bitmap in bytes
+ *
+ * Description:
+ * Perform a label mapping to translate a local MLS category bitmap to the
+ * correct CIPSO bitmap using the given DOI definition. Returns the minimum
+ * size in bytes of the network bitmap on success, negative values otherwise.
+ *
+ */
+static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
+ const unsigned char *host_cat,
+ const u32 host_cat_len,
+ unsigned char *net_cat,
+ const u32 net_cat_len)
+{
+ int host_spot = -1;
+ u32 net_spot;
+ u32 net_spot_max = 0;
+ u32 host_clen_bits = host_cat_len * 8;
+ u32 net_clen_bits = net_cat_len * 8;
+ u32 host_cat_size = doi_def->map.std->cat.local_size;
+ u32 *host_cat_array = doi_def->map.std->cat.local;
+
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_PASS:
+ net_spot_max = host_cat_len - 1;
+ while (net_spot_max > 0 && host_cat[net_spot_max] == 0)
+ net_spot_max--;
+ if (net_spot_max > net_cat_len)
+ return -EINVAL;
+ memcpy(net_cat, host_cat, net_spot_max);
+ return net_spot_max;
+ case CIPSO_V4_MAP_STD:
+ for (;;) {
+ host_spot = cipso_v4_bitmap_walk(host_cat,
+ host_clen_bits,
+ host_spot + 1,
+ 1);
+ if (host_spot < 0)
+ break;
+ if (host_spot >= host_cat_size)
+ return -EPERM;
+
+ net_spot = host_cat_array[host_spot];
+ if (net_spot >= net_clen_bits)
+ return -ENOSPC;
+ cipso_v4_bitmap_setbit(net_cat, net_spot, 1);
+
+ if (net_spot > net_spot_max)
+ net_spot_max = net_spot;
+ }
+
+ if (host_spot == -2)
+ return -EFAULT;
+
+ if (++net_spot_max % 8)
+ return net_spot_max / 8 + 1;
+ return net_spot_max / 8;
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * cipso_v4_map_cat_rbm_ntoh - Perform a category mapping from network to host
+ * @doi_def: the DOI definition
+ * @net_cat: the category bitmap in network/CIPSO format
+ * @net_cat_len: the length of the CIPSO bitmap in bytes
+ * @host_cat: the zero'd out category bitmap in host format
+ * @host_cat_len: the length of the host's category bitmap in bytes
+ *
+ * Description:
+ * Perform a label mapping to translate a CIPSO bitmap to the correct local
+ * MLS category bitmap using the given DOI definition. Returns the minimum
+ * size in bytes of the host bitmap on success, negative values otherwise.
+ *
+ */
+static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
+ const unsigned char *net_cat,
+ const u32 net_cat_len,
+ unsigned char *host_cat,
+ const u32 host_cat_len)
+{
+ u32 host_spot;
+ u32 host_spot_max = 0;
+ int net_spot = -1;
+ u32 net_clen_bits = net_cat_len * 8;
+ u32 host_clen_bits = host_cat_len * 8;
+ u32 net_cat_size = doi_def->map.std->cat.cipso_size;
+ u32 *net_cat_array = doi_def->map.std->cat.cipso;
+
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_PASS:
+ if (net_cat_len > host_cat_len)
+ return -EINVAL;
+ memcpy(host_cat, net_cat, net_cat_len);
+ return host_cat_len;
+ case CIPSO_V4_MAP_STD:
+ for (;;) {
+ net_spot = cipso_v4_bitmap_walk(net_cat,
+ net_clen_bits,
+ net_spot + 1,
+ 1);
+ if (net_spot < 0)
+ break;
+ if (net_spot >= net_cat_size)
+ return -EPERM;
+
+ host_spot = net_cat_array[net_spot];
+ if (host_spot >= host_clen_bits)
+ return -ENOSPC;
+ cipso_v4_bitmap_setbit(host_cat, host_spot, 1);
+
+ if (host_spot > host_spot_max)
+ host_spot_max = host_spot;
+ }
+
+ if (net_spot == -2)
+ return -EFAULT;
+
+ if (++host_spot_max % 8)
+ return host_spot_max / 8 + 1;
+ return host_spot_max / 8;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Protocol Handling Functions
+ */
+
+#define CIPSO_V4_HDR_LEN 6
+
+/**
+ * cipso_v4_gentag_hdr - Generate a CIPSO option header
+ * @doi_def: the DOI definition
+ * @len: the total tag length in bytes
+ * @buf: the CIPSO option buffer
+ *
+ * Description:
+ * Write a CIPSO header into the beginning of @buffer. Return zero on success,
+ * negative values on failure.
+ *
+ */
+static int cipso_v4_gentag_hdr(const struct cipso_v4_doi *doi_def,
+ const u32 len,
+ unsigned char *buf)
+{
+ if (CIPSO_V4_HDR_LEN + len > 40)
+ return -ENOSPC;
+
+ buf[0] = IPOPT_CIPSO;
+ buf[1] = CIPSO_V4_HDR_LEN + len;
+ *(u32 *)&buf[2] = htonl(doi_def->doi);
+
+ return 0;
+}
+
+#define CIPSO_V4_TAG1_CAT_LEN 30
+
+/**
+ * cipso_v4_gentag_rbm - Generate a CIPSO restricted bitmap tag (type #1)
+ * @doi_def: the DOI definition
+ * @secattr: the security attributes
+ * @buffer: the option buffer
+ * @buffer_len: length of buffer in bytes
+ *
+ * Description:
+ * Generate a CIPSO option using the restricted bitmap tag, tag type #1. The
+ * actual buffer length may be larger than the indicated size due to
+ * translation between host and network category bitmaps. Returns zero on
+ * success, negative values on failure.
+ *
+ */
+static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr,
+ unsigned char **buffer,
+ u32 *buffer_len)
+{
+ int ret_val = -EPERM;
+ unsigned char *buf = NULL;
+ u32 buf_len;
+ u32 level;
+
+ if (secattr->set_mls_cat) {
+ buf = kzalloc(CIPSO_V4_HDR_LEN + 4 + CIPSO_V4_TAG1_CAT_LEN,
+ GFP_ATOMIC);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ ret_val = cipso_v4_map_cat_rbm_hton(doi_def,
+ secattr->mls_cat,
+ secattr->mls_cat_len,
+ &buf[CIPSO_V4_HDR_LEN + 4],
+ CIPSO_V4_TAG1_CAT_LEN);
+ if (ret_val < 0)
+ goto gentag_failure;
+#if 0
+ /* PM - this should be a sysctl adjustable setting */
+ /* XXX - this will send packets using the "optimized" format
+ when possibile as specified in section 3.4.2.6 of the
+ CIPSO draft */
+ if (ret_val > 0 && ret_val < 10)
+ ret_val = 10;
+#endif
+ buf_len = 4 + ret_val;
+ } else {
+ buf = kzalloc(CIPSO_V4_HDR_LEN + 4, GFP_ATOMIC);
+ if (buf == NULL)
+ return -ENOMEM;
+ buf_len = 4;
+ }
+
+ ret_val = cipso_v4_map_lvl_hton(doi_def, secattr->mls_lvl, &level);
+ if (ret_val != 0)
+ goto gentag_failure;
+
+ ret_val = cipso_v4_gentag_hdr(doi_def, buf_len, buf);
+ if (ret_val != 0)
+ goto gentag_failure;
+
+ buf[CIPSO_V4_HDR_LEN] = 0x01;
+ buf[CIPSO_V4_HDR_LEN + 1] = buf_len;
+ buf[CIPSO_V4_HDR_LEN + 3] = level;
+
+ *buffer = buf;
+ *buffer_len = CIPSO_V4_HDR_LEN + buf_len;
+
+ return 0;
+
+gentag_failure:
+ if (buf)
+ kfree(buf);
+ return ret_val;
+}
+
+/**
+ * cipso_v4_parsetag_rbm - Parse a CIPSO restricted bitmap tag
+ * @doi_def: the DOI definition
+ * @tag: the CIPSO tag
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Parse a CIPSO restricted bitmap tag (tag type #1) and return the security
+ * attributes in @secattr. Return zero on success, negatives values on
+ * failure.
+ *
+ */
+static int cipso_v4_parsetag_rbm(const struct cipso_v4_doi *doi_def,
+ const unsigned char *tag,
+ struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val;
+ u8 tag_len = tag[1];
+ u32 level;
+
+ ret_val = cipso_v4_map_lvl_ntoh(doi_def, tag[3], &level);
+ if (ret_val != 0)
+ return ret_val;
+ secattr->mls_lvl = level;
+ secattr->set_mls_lvl = 1;
+
+ if (tag_len > 4) {
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_PASS:
+ secattr->mls_cat_len = tag_len - 4;
+ break;
+ case CIPSO_V4_MAP_STD:
+ secattr->mls_cat_len =
+ doi_def->map.std->cat.local_size;
+ break;
+ }
+ secattr->mls_cat = kzalloc(secattr->mls_cat_len, GFP_ATOMIC);
+ if (secattr->mls_cat == NULL)
+ return -ENOMEM;
+
+ ret_val = cipso_v4_map_cat_rbm_ntoh(doi_def,
+ &tag[4],
+ tag_len - 4,
+ secattr->mls_cat,
+ secattr->mls_cat_len);
+ if (ret_val < 0) {
+ kfree(secattr->mls_cat);
+ return ret_val;
+ }
+ secattr->mls_cat_len = ret_val;
+ secattr->set_mls_cat = 1;
+ }
+
+ return 0;
+}
+
+/**
+ * cipso_v4_validate - Validate a CIPSO option
+ * @option: the start of the option, on error it is set to point to the error
+ *
+ * Description:
+ * This routine is called to validate a CIPSO option, it checks all of the
+ * fields to ensure that they are at least valid, see the draft snippet below
+ * for details. If the option is valid then a zero value is returned and
+ * the value of @option is unchanged. If the option is invalid then a
+ * non-zero value is returned and @option is adjusted to point to the
+ * offending portion of the option. From the IETF draft ...
+ *
+ * "If any field within the CIPSO options, such as the DOI identifier, is not
+ * recognized the IP datagram is discarded and an ICMP 'parameter problem'
+ * (type 12) is generated and returned. The ICMP code field is set to 'bad
+ * parameter' (code 0) and the pointer is set to the start of the CIPSO field
+ * that is unrecognized."
+ *
+ */
+int cipso_v4_validate(unsigned char **option)
+{
+ unsigned char *opt = *option;
+ unsigned char *tag;
+ unsigned char opt_iter;
+ unsigned char err_offset = 0;
+ unsigned char locked = 0;
+ u8 opt_len;
+ u8 tag_len;
+ struct cipso_v4_doi *doi_def = NULL;
+ u32 tag_iter;
+
+ /* XXX: caller already checks for length values that are too large */
+ opt_len = opt[1];
+ if (opt_len < 8) {
+ err_offset = 1;
+ goto validate_return;
+ }
+
+ rcu_read_lock();
+ locked = 1;
+ doi_def = cipso_v4_doi_getdef(ntohl(*((u32 *)&opt[2])));
+ if (doi_def == NULL) {
+ err_offset = 2;
+ goto validate_return;
+ }
+
+ opt_iter = 6;
+ tag = opt + opt_iter;
+ while (opt_iter < opt_len) {
+ for (tag_iter = 0; doi_def->tags[tag_iter] != tag[0];)
+ if (doi_def->tags[tag_iter] == CIPSO_V4_TAG_INVALID ||
+ ++tag_iter == CIPSO_V4_TAG_MAXCNT) {
+ err_offset = opt_iter;
+ goto validate_return;
+ }
+
+ tag_len = tag[1];
+ if (tag_len > (opt_len - opt_iter)) {
+ err_offset = opt_iter + 1;
+ goto validate_return;
+ }
+
+ switch (tag[0]) {
+ case CIPSO_V4_TAG_RBITMAP:
+ if (tag_len < 4) {
+ err_offset = opt_iter + 1;
+ goto validate_return;
+ }
+#if 0
+ /* PM - i think we can skip this check safely */
+ if (tag[2] != 0) {
+ err_offset = opt_iter + 2;
+ goto validate_return;
+ }
+#endif
+ /* PM - how detailed a check do we need to make, are
+ these last two checks (level and category)
+ neccessary at this level? if we do drop these
+ checks we need to add a bit of code to the *_ntoh()
+ functions to check for invalid levels/cats. */
+ if (cipso_v4_map_lvl_valid(doi_def, tag[3]) < 0) {
+ err_offset = opt_iter + 3;
+ goto validate_return;
+ }
+ if (tag_len > 4 &&
+ cipso_v4_map_cat_rbm_valid(doi_def,
+ &tag[4],
+ tag_len - 4) < 0) {
+ err_offset = opt_iter + 4;
+ goto validate_return;
+ }
+ break;
+ case CIPSO_V4_TAG_ENUM:
+ case CIPSO_V4_TAG_RANGE:
+ case CIPSO_V4_TAG_PBITMAP:
+ case CIPSO_V4_TAG_FREEFORM:
+ default:
+ err_offset = opt_iter;
+ goto validate_return;
+ }
+
+ tag += tag_len;
+ opt_iter += tag_len;
+ }
+
+validate_return:
+ if (locked)
+ rcu_read_unlock();
+ *option = opt + err_offset;
+ return err_offset;
+}
+
+/**
+ * cipso_v4_error - Send the correct reponse for a bad packet
+ * @skb: the packet
+ * @error: the error code
+ * @gateway: CIPSO gateway flag
+ *
+ * Description:
+ * Based on the error code given in @error, send an ICMP error message back to
+ * the originating host. Returns zero on success, negative values on failure.
+ * From the IETF draft ...
+ *
+ * "If the contents of the CIPSO [option] are valid but the security label is
+ * outside of the configured host or port label range, the datagram is
+ * discarded and an ICMP 'destination unreachable' (type 3) is generated and
+ * returned. The code field of the ICMP is set to 'communication with
+ * destination network administratively prohibited' (code 9) or to
+ * 'communication with destination host administratively prohibited'
+ * (code 10). The value of the code is dependent on whether the originator
+ * of the ICMP message is acting as a CIPSO host or a CIPSO gateway. The
+ * recipient of the ICMP message MUST be able to handle either value. The
+ * same procedure is performed if a CIPSO [option] can not be added to an
+ * IP packet because it is too large to fit in the IP options area."
+ *
+ * "If the error is triggered by receipt of an ICMP message, the message is
+ * discarded and no response is permitted (consistent with general ICMP
+ * processing rules)."
+ *
+ */
+int cipso_v4_error(struct sk_buff *skb,
+ const int error,
+ const u32 gateway)
+{
+ switch (error) {
+ case -EACCES:
+ break;
+ default:
+ return 0;
+ }
+
+ if (skb->nh.iph->protocol == IPPROTO_ICMP)
+ return 0;
+
+ if (gateway)
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0);
+ else
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0);
+
+ return 0;
+}
+
+/**
+ * cipso_v4_socket_setopt - Set the CIPSO option string on a socket
+ * @sock: the socket
+ * @opt: the option string
+ * @opt_len: the option string length
+ *
+ * Description:
+ * Attempt to add the given CIPSO option string to the socket. The caller is
+ * responsibile for locking and releasing the socket. Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int cipso_v4_socket_setopt(struct socket *sock,
+ unsigned char *opt,
+ u32 opt_len)
+{
+ int ret_val;
+ struct ip_options *ip_opt = NULL;
+ struct sock *sk = sock->sk;
+ struct inet_sock *sk_inet;
+ struct inet_connection_sock *sk_conn;
+
+ ret_val = ip_options_get(&ip_opt, opt, opt_len);
+ if (ret_val != 0)
+ goto socket_setopt_return;
+ ip_opt->is_setbyuser = 0;
+ sk_inet = inet_sk(sk);
+ if (sk_inet->is_icsk) {
+ sk_conn = inet_csk(sk);
+ if (sk_inet->opt)
+ sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen;
+ sk_conn->icsk_ext_hdr_len += ip_opt->optlen;
+ sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+ }
+ ip_opt = xchg(&sk_inet->opt, ip_opt);
+
+ ret_val = 0;
+
+socket_setopt_return:
+ if (ip_opt)
+ kfree(opt);
+ return ret_val;
+}
+
+/**
+ * cipso_v4_socket_setattr - Add a CIPSO option to a socket
+ * @sock: the socket
+ * @doi_def: the CIPSO DOI to use
+ * @secattr: the specific security attributes of the socket
+ *
+ * Description:
+ * Set the CIPSO option on the given socket using the DOI definition and
+ * security attributes passed to the function. Returns zero on success and
+ * negative values on failure.
+ *
+ */
+int cipso_v4_socket_setattr(const struct socket *sock,
+ const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val = -EPERM;
+ u32 iter;
+ unsigned char *buf = NULL;
+ u32 buf_len = 0;
+ struct ip_options *opt = NULL;
+ struct sock *sk;
+ struct inet_sock *sk_inet;
+ struct inet_connection_sock *sk_conn;
+
+ /* In the case of sock_create_lite(), the sock->sk field is not
+ defined yet but it is not a problem as the only users of these
+ "lite" PF_INET sockets are functions which do an accept() call
+ afterwards so we will label the socket as part of the accept(). */
+ /* PM - test this, nfs/sunrpc is a "lite" socket user */
+ sk = sock->sk;
+ if (sk == NULL)
+ return 0;
+
+ /* XXX - this code assumes only one tag per CIPSO option which isnt
+ really a good assumption to make but since we only support the MAC
+ tags right now it is a safe assumption */
+ iter = 0;
+ do {
+ switch (doi_def->tags[iter]) {
+ case CIPSO_V4_TAG_RBITMAP:
+ ret_val = cipso_v4_gentag_rbm(doi_def,
+ secattr,
+ &buf,
+ &buf_len);
+ break;
+ case CIPSO_V4_TAG_ENUM:
+ case CIPSO_V4_TAG_RANGE:
+ case CIPSO_V4_TAG_PBITMAP:
+ case CIPSO_V4_TAG_FREEFORM:
+ default:
+ ret_val = -EPERM;
+ goto socket_setattr_failure;
+ }
+
+ iter++;
+ } while (ret_val != 0 &&
+ iter < CIPSO_V4_TAG_MAXCNT &&
+ doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
+ if (ret_val != 0)
+ goto socket_setattr_failure;
+
+ ret_val = ip_options_get(&opt, buf, buf_len);
+ if (ret_val != 0)
+ goto socket_setattr_failure;
+ opt->is_setbyuser = 0;
+
+ kfree(buf);
+ buf = NULL;
+
+ lock_sock(sk);
+ sk_inet = inet_sk(sk);
+ if (sk_inet->is_icsk) {
+ sk_conn = inet_csk(sk);
+ if (sk_inet->opt)
+ sk_conn->icsk_ext_hdr_len -= sk_inet->opt->optlen;
+ sk_conn->icsk_ext_hdr_len += opt->optlen;
+ sk_conn->icsk_sync_mss(sk, sk_conn->icsk_pmtu_cookie);
+ }
+ opt = xchg(&sk_inet->opt, opt);
+ release_sock(sk);
+ if (opt)
+ kfree(opt);
+
+ return 0;
+
+socket_setattr_failure:
+ if (buf)
+ kfree(buf);
+ if (opt)
+ kfree(opt);
+ return ret_val;
+}
+
+/**
+ * cipso_v4_socket_getopt - Get the CIPSO IP option string from the socket
+ * @sock: the socket
+ * @opt: the option string
+ * @opt_len: the option string length in bytes
+ *
+ * Description:
+ * If a CIPSO option is present in the socket's IP options then return a
+ * a pointer to the option string. The caller is responsibile for locking
+ * and releasing the socket. Returns zero on success, negative values on
+ * failure.
+ *
+ */
+int cipso_v4_socket_getopt(const struct socket *sock,
+ unsigned char **opt,
+ u32 *opt_len)
+{
+ struct ip_options *ip_opt = inet_sk(sock->sk)->opt;
+ unsigned char *cipso_ptr;
+
+ if (ip_opt == NULL || ip_opt->cipso == 0)
+ return -ENOMSG;
+ cipso_ptr = ip_opt->__data + ip_opt->cipso - sizeof(struct iphdr);
+
+ *opt = cipso_ptr;
+ *opt_len = cipso_ptr[1];
+
+ return 0;
+}
+
+/**
+ * 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 = -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;
+ 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;
+
+ 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;
+ }
+ /* XXX - this code assumes only one tag per CIPSO option, the draft is
+ a little unclear about supporting multiple tags per option
+ but this seems safe for now */
+ switch (cipso_ptr[6]) {
+ case CIPSO_V4_TAG_RBITMAP:
+ ret_val = cipso_v4_parsetag_rbm(doi_def,
+ &cipso_ptr[6],
+ secattr);
+ break;
+ }
+ rcu_read_unlock();
+
+socket_getattr_return:
+ release_sock(sk);
+ return ret_val;
+}
+
+/**
+ * cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
+ * @skb: the packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Parse the given packet's CIPSO option and return the security attributes.
+ * Returns zero on success and negative values on failure.
+ *
+ */
+int cipso_v4_skbuff_getattr(const struct sk_buff *skb,
+ struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val = -ENOMSG;
+ unsigned char *cipso_ptr;
+ u32 doi;
+ struct cipso_v4_doi *doi_def;
+
+ if (!CIPSO_V4_OPTEXIST(skb))
+ return -ENOMSG;
+ cipso_ptr = CIPSO_V4_OPTPTR(skb);
+ if (cipso_v4_cache_check(cipso_ptr, cipso_ptr[1], secattr) == 0)
+ return 0;
+
+ doi = ntohl(*(u32 *)&cipso_ptr[2]);
+ rcu_read_lock();
+ doi_def = cipso_v4_doi_getdef(doi);
+ if (doi_def == NULL)
+ goto skbuff_getattr_return;
+ /* XXX - this code assumes only one tag per CIPSO option which isnt
+ really a good assumption to make but since we only support the MAC
+ tags right now it is a safe assumption */
+ switch (cipso_ptr[6]) {
+ case CIPSO_V4_TAG_RBITMAP:
+ ret_val = cipso_v4_parsetag_rbm(doi_def,
+ &cipso_ptr[6],
+ secattr);
+ break;
+ }
+
+skbuff_getattr_return:
+ rcu_read_unlock();
+ return ret_val;
+}
+
+/*
+ * Setup Functions
+ */
+
+/**
+ * cipso_v4_init - Initialize the CIPSO module
+ *
+ * Description:
+ * Initialize the CIPSO module and prepare it for use. Returns zero on success
+ * and negative values on failure.
+ *
+ */
+static int __init cipso_v4_init(void)
+{
+ return cipso_v4_cache_init(CIPSO_V4_CACHE_BUCKETS);
+}
+
+/* PM - not sure there is any point to this now, delete this func? */
+/**
+ * cipso_v4_exit - Cleanup after the CIPSO module
+ *
+ * Description:
+ * Perform any necessary cleanup tasks before the CIPSO module goes away.
+ *
+ */
+static void __exit cipso_v4_exit(void)
+{
+ cipso_v4_cache_destroy();
+}
+
+subsys_initcall(cipso_v4_init);
+
--
paul moore
linux security @ hp
^ permalink raw reply
* [RFC 6/8] NetLabel: CIPSOv4 integration
From: paul.moore @ 2006-06-22 22:49 UTC (permalink / raw)
To: netdev; +Cc: davem
In-Reply-To: <20060622224910.885573000@flek.zko.hp.com>
[-- Attachment #1: netlabel-cipsov4 --]
[-- Type: text/plain, Size: 16562 bytes --]
Add CIPSO/IPv4 support and management to the NetLabel subsystem. These changes
integrate the CIPSO/IPv4 configuration into the existing NetLabel code and
enable the use of CIPSO/IPv4 within the overall NetLabel framework.
---
net/netlabel/netlabel_cipso_v4.c | 583 +++++++++++++++++++++++++++++++++++++++
1 files changed, 583 insertions(+)
Index: linux-2.6.17.i686-quilt/net/netlabel/netlabel_cipso_v4.c
===================================================================
--- /dev/null
+++ linux-2.6.17.i686-quilt/net/netlabel/netlabel_cipso_v4.c
@@ -0,0 +1,583 @@
+/*
+ * NetLabel CIPSO/IPv4 Support
+ *
+ * This file defines the CIPSO/IPv4 functions for the NetLabel system. The
+ * NetLabel system manages static and dynamic label mappings for network
+ * protocols such as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+
+#include "netlabel_user.h"
+#include "netlabel_cipso_v4.h"
+
+/*
+ * Local Prototypes
+ */
+
+static void netlbl_cipsov4_send_ack(const struct sk_buff *req_skb,
+ const u32 ret_code);
+
+/*
+ * Helper Functions
+ */
+
+/**
+ * netlbl_cipsov4_put_hdr - Write a CIPSO NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel CIPSOv4 opcode
+ * @doi: the CIPSO DOI value
+ *
+ * Description:
+ * Use the given values to write a NetLabel CIPSOv4 header into the given
+ * buffer.
+ *
+ */
+static void netlbl_cipsov4_put_hdr(unsigned char *buffer,
+ const u32 opcode,
+ const u32 doi)
+{
+ struct netlbl_cipsov4_msghdr *hdr =
+ (struct netlbl_cipsov4_msghdr *)buffer;
+ hdr->opcode = opcode;
+ hdr->doi = doi;
+}
+
+/**
+ * netlbl_cipsov4_putinc_hdr - Write a CIPSO NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel CIPSOv4 opcode
+ * @doi: the CIPSO DOI value
+ *
+ * Description:
+ * Use the given values to write a NetLabel CIPSOv4 header into the given
+ * buffer and increment the buffer pointer past the header.
+ *
+ */
+static void netlbl_cipsov4_putinc_hdr(unsigned char **buffer,
+ const u32 opcode,
+ const u32 doi)
+{
+ netlbl_cipsov4_put_hdr(*buffer, opcode, doi);
+ *buffer += sizeof(struct netlbl_cipsov4_msghdr);
+}
+
+/**
+ * netlbl_cipsov4_payload_len - Return the length of the payload
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns the length of the CIPSO V4 NetLabel payload.
+ *
+ */
+static u32 netlbl_cipsov4_payload_len(const struct sk_buff *skb)
+{
+ const struct nlmsghdr *nl_hdr = (struct nlmsghdr *)skb->data;
+
+ if (nlmsg_len(nl_hdr) <= sizeof(struct netlbl_cipsov4_msghdr))
+ return 0;
+ return nlmsg_len(nl_hdr) - sizeof(struct netlbl_cipsov4_msghdr);
+}
+
+/**
+ * netlbl_cipsov4_payload_data - Returns a pointer to the start of the data
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns a pointer to the start of the CIPSO V4 NetLabel
+ * payload.
+ *
+ */
+static unsigned char *netlbl_cipsov4_payload_data(const struct sk_buff *skb)
+{
+ return nlmsg_data((struct nlmsghdr *)skb->data) +
+ sizeof(struct netlbl_cipsov4_msghdr);
+}
+
+/**
+ * netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to the DOI definition can be released
+ * safely.
+ *
+ */
+static void netlbl_cipsov4_doi_free(struct rcu_head *entry)
+{
+ struct cipso_v4_doi *ptr;
+
+ ptr = container_of(entry, struct cipso_v4_doi, rcu);
+ switch (ptr->type) {
+ case CIPSO_V4_MAP_STD:
+ if (ptr->map.std->lvl.cipso_size > 0)
+ kfree(ptr->map.std->lvl.cipso);
+ if (ptr->map.std->lvl.local_size > 0)
+ kfree(ptr->map.std->lvl.local);
+ if (ptr->map.std->cat.cipso_size > 0)
+ kfree(ptr->map.std->cat.cipso);
+ if (ptr->map.std->cat.local_size > 0)
+ kfree(ptr->map.std->cat.local);
+ break;
+ }
+ kfree(ptr);
+}
+
+/*
+ * Label Mapping Functions
+ */
+
+/**
+ * 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
+ *
+ * Description:
+ * Create a new CIPSO_V4_MAP_STD DOI definition based on the given ADD message
+ * and add it to the CIPSO V4 engine. Return zero on success and non-zero on
+ * error.
+ *
+ */
+static int netlbl_cipsov4_add_std(const u32 doi,
+ const unsigned char *msg,
+ const u32 msg_size)
+{
+ int ret_val = -EPERM;
+ unsigned char *msg_ptr = (unsigned char *)msg;
+ u32 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;
+
+ if (msg_len < 4)
+ goto add_std_failure;
+ num_tags = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
+ goto add_std_failure;
+
+ doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
+ if (doi_def == NULL) {
+ ret_val = -ENOMEM;
+ goto add_std_failure;
+ }
+ doi_def->map.std = kzalloc(sizeof(*doi_def->map.std),
+ GFP_KERNEL);
+ if (doi_def->map.std == NULL) {
+ ret_val = -ENOMEM;
+ goto add_std_failure;
+ }
+ doi_def->type = CIPSO_V4_MAP_STD;
+
+ if (msg_len < num_tags)
+ goto add_std_failure;
+ msg_len -= num_tags;
+ for (iter = 0; iter < num_tags; iter++) {
+ doi_def->tags[iter] = netlbl_getinc_u8(&msg_ptr);
+ 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 < 24)
+ goto add_std_failure;
+
+ num_lvls = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ if (num_lvls == 0)
+ goto add_std_failure;
+ doi_def->map.std->lvl.local_size = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ if (doi_def->map.std->lvl.local_size > CIPSO_V4_MAX_LOC_LVLS)
+ goto add_std_failure;
+ doi_def->map.std->lvl.local = kcalloc(doi_def->map.std->lvl.local_size,
+ sizeof(u32), GFP_KERNEL);
+ if (doi_def->map.std->lvl.local == NULL) {
+ ret_val = -ENOMEM;
+ goto add_std_failure;
+ }
+ doi_def->map.std->lvl.cipso_size = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ 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);
+ if (doi_def->map.std->lvl.cipso == NULL) {
+ ret_val = -ENOMEM;
+ goto add_std_failure;
+ }
+
+ num_cats = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ doi_def->map.std->cat.local_size = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ 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,
+ 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_u32(&msg_ptr);
+ msg_len -= 4;
+ 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,
+ sizeof(u32), GFP_KERNEL);
+ if (doi_def->map.std->cat.cipso == NULL) {
+ ret_val = -ENOMEM;
+ goto add_std_failure;
+ }
+
+ if (msg_len < num_lvls * 8 + num_cats * 8)
+ goto add_std_failure;
+ msg_len -= num_lvls * 8 + num_cats * 8;
+
+ 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_ptr);
+ tmp_val_b = netlbl_getinc_u32(&msg_ptr);
+
+ 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_ptr);
+ tmp_val_b = netlbl_getinc_u32(&msg_ptr);
+
+ if (tmp_val_a >= doi_def->map.std->cat.local_size ||
+ tmp_val_b >= doi_def->map.std->cat.cipso_size)
+ 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;
+ }
+
+ doi_def->doi = doi;
+ ret_val = cipso_v4_doi_add(doi_def);
+ if (ret_val != 0)
+ goto add_std_failure;
+ return 0;
+
+add_std_failure:
+ if (doi_def)
+ netlbl_cipsov4_doi_free(&doi_def->rcu);
+ return ret_val;
+}
+
+/**
+ * netlbl_cipsov4_add_pass - Adds a CIPSO V4 DOI definition
+ * @doi: the DOI value
+ * @msg: the ADD message data
+ * @msg_size: the size of the ADD message buffer
+ *
+ * Description:
+ * Create a new CIPSO_V4_MAP_PASS DOI definition based on the given ADD message
+ * and add it to the CIPSO V4 engine. Return zero on success and non-zero on
+ * error.
+ *
+ */
+static int netlbl_cipsov4_add_pass(const u32 doi,
+ const unsigned char *msg,
+ const u32 msg_size)
+{
+ int ret_val = -EPERM;
+ unsigned char *msg_ptr = (unsigned char *)msg;
+ u32 msg_len = msg_size;
+ u32 num_tags;
+ struct cipso_v4_doi *doi_def = NULL;
+ u32 iter;
+
+ if (msg_len < 4)
+ goto add_pass_failure;
+ num_tags = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ if (num_tags == 0 || num_tags > CIPSO_V4_TAG_MAXCNT)
+ goto add_pass_failure;
+
+ doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
+ if (doi_def == NULL) {
+ ret_val = -ENOMEM;
+ goto add_pass_failure;
+ }
+ doi_def->type = CIPSO_V4_MAP_PASS;
+
+ if (msg_len < num_tags)
+ goto add_pass_failure;
+ msg_len -= num_tags;
+ for (iter = 0; iter < num_tags; iter++) {
+ doi_def->tags[iter] = netlbl_getinc_u8(&msg_ptr);
+ 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;
+
+ 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);
+ return ret_val;
+}
+
+/**
+ * netlbl_cipsov4_add - Handle an ADD message
+ * @req_skb: the NETLINK buffer
+ * @doi: the DOI
+ * @msg: the NetLabel CIPSO V4 message
+ *
+ * Description:
+ * Create a new DOI definition based on the given ADD message and add it to the
+ * CIPSO V4 engine.
+ *
+ */
+static void netlbl_cipsov4_add(const struct sk_buff *req_skb,
+ const u32 doi,
+ const unsigned char *msg)
+{
+ int ret_val = -EINVAL;
+ u32 map_type;
+ u32 msg_len = netlbl_cipsov4_payload_len(req_skb);
+
+ if (msg_len < 4) {
+ netlbl_cipsov4_send_ack(req_skb, EINVAL);
+ return;
+ }
+
+ map_type = netlbl_get_u32(msg);
+ switch (map_type) {
+ case CIPSO_V4_MAP_STD:
+ ret_val = netlbl_cipsov4_add_std(doi, msg + 4, msg_len - 4);
+ break;
+ case CIPSO_V4_MAP_PASS:
+ ret_val = netlbl_cipsov4_add_pass(doi, msg + 4, msg_len - 4);
+ break;
+ }
+ netlbl_cipsov4_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_cipsov4_list - Handle a LIST message
+ * @req_skb: the NETLINK buffer
+ * @doi: the DOI
+ * @msg: the NetLabel CIPSO V4 message
+ *
+ * Description:
+ * Process a user generated LIST message and respond accordingly.
+ *
+ */
+static void netlbl_cipsov4_list(const struct sk_buff *req_skb,
+ const u32 doi,
+ const unsigned char *msg)
+{
+ int ret_val = -ENOMEM;
+ struct sk_buff *skb;
+ unsigned char *buf_ptr;
+
+ skb = cipso_v4_doi_dump(doi, sizeof(struct netlbl_cipsov4_msghdr));
+ if (skb == NULL)
+ goto list_return;
+ buf_ptr = skb_push(skb,
+ NLMSG_SPACE(sizeof(struct netlbl_cipsov4_msghdr)));
+ if (buf_ptr == NULL) {
+ kfree(skb);
+ ret_val = -EAGAIN;
+ goto list_return;
+ }
+ netlbl_putinc_hdr(&buf_ptr,
+ NETLBL_NLTYPE_CIPSOV4,
+ skb->len,
+ 0,
+ NETLINK_CB(req_skb).pid,
+ 0);
+ netlbl_cipsov4_putinc_hdr(&buf_ptr, NL_CV4_LIST, 0);
+
+ ret_val = netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+
+list_return:
+ if (ret_val != 0)
+ netlbl_cipsov4_send_ack(skb, -ret_val);
+}
+
+/**
+ * netlbl_cipsov4_remove - Handle a REMOVE message
+ * @req_skb: the NETLINK buffer
+ * @doi: the DOI
+ * @msg: the NetLabel CIPSO V4 message
+ *
+ * Description:
+ * Process a user generated REMOVE message and respond accordingly.
+ *
+ */
+static void netlbl_cipsov4_remove(const struct sk_buff *req_skb,
+ const u32 doi,
+ const unsigned char *msg)
+{
+ int ret_val;
+
+ ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free);
+ netlbl_cipsov4_send_ack(req_skb, -ret_val);
+}
+
+/*
+ * NetLabel Protocol Handlers
+ */
+
+/**
+ * netlbl_cipsov4_send_ack - Send an ACK message
+ * @req_skb: the NETLINK buffer
+ * @ret_code: return code to use
+ *
+ * Description:
+ * This function sends an ACK message to the sender of the NETLINK message
+ * specified by @req_skb.
+ *
+ */
+static void netlbl_cipsov4_send_ack(const struct sk_buff *req_skb,
+ const u32 ret_code)
+{
+ size_t msg_size;
+ size_t data_size;
+ struct sk_buff *skb;
+ struct nlmsghdr *nl_ack_hdr;
+ unsigned char *data;
+
+ data_size = sizeof(struct netlbl_cipsov4_msghdr) + 8;
+ msg_size = NLMSG_SPACE(data_size);
+
+ skb = alloc_skb(msg_size, GFP_KERNEL);
+ if (skb == NULL)
+ return;
+
+ nl_ack_hdr = NLMSG_PUT(skb,
+ NETLINK_CB(req_skb).pid,
+ 0,
+ NETLBL_NLTYPE_CIPSOV4,
+ data_size);
+ nl_ack_hdr->nlmsg_len = msg_size;
+
+ data = NLMSG_DATA(nl_ack_hdr);
+ netlbl_cipsov4_putinc_hdr(&data, NL_CV4_ACK, 0);
+ netlbl_putinc_u32(&data,
+ ((struct nlmsghdr *)req_skb->data)->nlmsg_seq);
+ netlbl_putinc_u32(&data, ret_code);
+
+ netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+ return;
+
+nlmsg_failure:
+ kfree_skb(skb);
+}
+
+/**
+ * netlbl_cipsov4_rcv - Process incoming NetLabel packets
+ * @skb: the NETLINK buffer
+ * @msg: pointer to the start of the NetLabel data
+ *
+ * Description:
+ * This function is reponsibile for reading all of the incoming CIPSO V4
+ * NetLabel traffic and dispatching it to the correct CIPSO V4 functions.
+ *
+ */
+void netlbl_cipsov4_rcv(const struct sk_buff *skb, const unsigned char *msg)
+{
+ int ret_val;
+ struct netlbl_cipsov4_msghdr *nl_cv4_hdr;
+
+ if (nlmsg_len((struct nlmsghdr *)skb->data) <
+ sizeof(struct netlbl_cipsov4_msghdr)) {
+ netlbl_cipsov4_send_ack(skb, EINVAL);
+ return;
+ }
+
+ nl_cv4_hdr = (struct netlbl_cipsov4_msghdr *)msg;
+ switch (nl_cv4_hdr->opcode) {
+ case NL_CV4_ADD:
+ ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
+ if (ret_val != 0)
+ netlbl_cipsov4_send_ack(skb, ret_val);
+ netlbl_cipsov4_add(skb,
+ nl_cv4_hdr->doi,
+ netlbl_cipsov4_payload_data(skb));
+ break;
+ case NL_CV4_REMOVE:
+ ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
+ if (ret_val != 0)
+ netlbl_cipsov4_send_ack(skb, ret_val);
+ netlbl_cipsov4_remove(skb,
+ nl_cv4_hdr->doi,
+ netlbl_cipsov4_payload_data(skb));
+ break;
+ case NL_CV4_LIST:
+ netlbl_cipsov4_list(skb,
+ nl_cv4_hdr->doi,
+ netlbl_cipsov4_payload_data(skb));
+ break;
+ default:
+ netlbl_cipsov4_send_ack(skb, EINVAL);
+ return;
+ }
+}
--
paul moore
linux security @ hp
^ permalink raw reply
* [RFC 7/8] NetLabel: unlabeled packet handling
From: paul.moore @ 2006-06-22 22:49 UTC (permalink / raw)
To: netdev; +Cc: davem
In-Reply-To: <20060622224910.885573000@flek.zko.hp.com>
[-- Attachment #1: netlabel-unlabeled --]
[-- Type: text/plain, Size: 8156 bytes --]
Add unlabeled packet support to the NetLabel subsystem. NetLabel does not do
any processing on unlabled packets, but it must support passing unlabled
packets on both the inbound and outbound sides.
---
net/netlabel/netlabel_unlabeled.c | 287 ++++++++++++++++++++++++++++++++++++++
1 files changed, 287 insertions(+)
Index: linux-2.6.17.i686-quilt/net/netlabel/netlabel_unlabeled.c
===================================================================
--- /dev/null
+++ linux-2.6.17.i686-quilt/net/netlabel/netlabel_unlabeled.c
@@ -0,0 +1,287 @@
+/*
+ * NetLabel Unlabeled Support
+ *
+ * This file defines functions for dealing with unlabeled packets for the
+ * NetLabel system. The NetLabel system manages static and dynamic label
+ * mappings for network protocols such as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul.moore@hp.com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <asm/bug.h>
+
+#include "netlabel_user.h"
+#include "netlabel_domainhash.h"
+#include "netlabel_unlabeled.h"
+
+/* Accept unlabeled packets flag */
+static atomic_t netlabel_unlabel_accept_flg = ATOMIC_INIT(0);
+
+/*
+ * Local Prototypes
+ */
+
+static void netlbl_unlabel_send_ack(const struct sk_buff *req_skb,
+ const u32 ret_code);
+
+/*
+ * Helper Functions
+ */
+
+/**
+ * netlbl_unlabel_put_hdr - Write a Unlabeled NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Unlabeled opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Unlabeled header into the given
+ * buffer.
+ *
+ */
+static void netlbl_unlabel_put_hdr(unsigned char *buffer, const u32 opcode)
+{
+ ((struct netlbl_unlabel_msghdr *)buffer)->opcode = opcode;
+}
+
+/**
+ * netlbl_unlabel_putinc_hdr - Write a Unlabeled NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Unlabeled opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Unlabeled header into the given
+ * buffer and increment the buffer pointer past the header.
+ *
+ */
+static void netlbl_unlabel_putinc_hdr(unsigned char **buffer, const u32 opcode)
+{
+ netlbl_unlabel_put_hdr(*buffer, opcode);
+ *buffer += sizeof(struct netlbl_unlabel_msghdr);
+}
+
+/**
+ * netlbl_unlabel_payload_len - Return the length of the payload
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns the length of the NetLabel unlabeled payload.
+ *
+ */
+static u32 netlbl_unlabel_payload_len(const struct sk_buff *skb)
+{
+ const struct nlmsghdr *nl_hdr = (struct nlmsghdr *)skb->data;
+
+ if (nlmsg_len(nl_hdr) <= sizeof(struct netlbl_unlabel_msghdr))
+ return 0;
+ return nlmsg_len(nl_hdr) - sizeof(struct netlbl_unlabel_msghdr);
+}
+
+/**
+ * netlbl_unlabel_payload_data - Returns a pointer to the start of the data
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns a pointer to the start of the NetLabel unlabeled
+ * payload.
+ *
+ */
+static unsigned char *netlbl_unlabel_payload_data(const struct sk_buff *skb)
+{
+ return nlmsg_data((struct nlmsghdr *)skb->data)
+ + sizeof(struct netlbl_unlabel_msghdr);
+}
+
+/*
+ * Label Mapping Functions
+ */
+
+/**
+ * netlbl_unlabel_accept - Handle an ACCEPT message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated ACCEPT message and set the accept flag accordingly.
+ *
+ */
+static void netlbl_unlabel_accept(const struct sk_buff *req_skb,
+ const unsigned char *msg)
+{
+ u32 value;
+
+ if (netlbl_unlabel_payload_len(req_skb) == 4) {
+ value = netlbl_get_u32(msg);
+ if (value == 1 || value == 0) {
+ atomic_set(&netlabel_unlabel_accept_flg, value);
+ netlbl_unlabel_send_ack(req_skb, NETLBL_E_OK);
+ return;
+ }
+ }
+
+ netlbl_unlabel_send_ack(req_skb, EINVAL);
+ return;
+}
+
+/*
+ * NetLabel Protocol Handlers
+ */
+
+/**
+ * netlbl_unlabel_send_ack - Send an ACK message
+ * @req_skb: the NETLINK buffer
+ * @ret_code: return code to use
+ *
+ * Description:
+ * This function sends an ACK message to the sender of the NETLINK message
+ * specified by @req_skb.
+ *
+ */
+static void netlbl_unlabel_send_ack(const struct sk_buff *req_skb,
+ const u32 ret_code)
+{
+ size_t msg_size;
+ size_t data_size;
+ struct sk_buff *skb;
+ struct nlmsghdr *nl_ack_hdr;
+ unsigned char *data;
+
+ data_size = sizeof(struct netlbl_unlabel_msghdr) + 8;
+ msg_size = NLMSG_SPACE(data_size);
+
+ skb = alloc_skb(msg_size, GFP_KERNEL);
+ if (skb == NULL)
+ return;
+
+ nl_ack_hdr = NLMSG_PUT(skb,
+ NETLINK_CB(req_skb).pid,
+ 0,
+ NETLBL_NLTYPE_UNLABELED,
+ data_size);
+ nl_ack_hdr->nlmsg_len = msg_size;
+
+ data = NLMSG_DATA(nl_ack_hdr);
+ netlbl_unlabel_putinc_hdr(&data, NL_UNL_ACK);
+ netlbl_putinc_u32(&data,
+ ((struct nlmsghdr *)req_skb->data)->nlmsg_seq);
+ netlbl_putinc_u32(&data, ret_code);
+
+ netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+ return;
+
+nlmsg_failure:
+ kfree_skb(skb);
+}
+
+/**
+ * netlbl_unlabel_rcv - Process incoming NetLabel packets
+ * @skb: the NETLINK buffer
+ * @msg: pointer to the start of the NetLabel data
+ *
+ * Description:
+ * This function is reponsibile for reading all of the incoming Unlabeled
+ * NetLabel traffic and dispatching it to the correct Unlabeled functions.
+ *
+ */
+void netlbl_unlabel_rcv(const struct sk_buff *skb, const unsigned char *msg)
+{
+ int ret_val;
+
+ if (nlmsg_len((struct nlmsghdr *)skb->data) <
+ sizeof(struct netlbl_unlabel_msghdr)) {
+ netlbl_unlabel_send_ack(skb, EINVAL);
+ return;
+ }
+
+ switch (((struct netlbl_unlabel_msghdr *)msg)->opcode) {
+ case NL_UNL_ACCEPT:
+ ret_val = netlbl_netlink_cap_check(skb, CAP_NET_ADMIN);
+ if (ret_val != 0)
+ netlbl_unlabel_send_ack(skb, ret_val);
+ netlbl_unlabel_accept(skb, netlbl_unlabel_payload_data(skb));
+ break;
+ default:
+ netlbl_unlabel_send_ack(skb, EINVAL);
+ return;
+ }
+}
+
+/*
+ * NetLabel KAPI Hooks
+ */
+
+/**
+ * netlbl_unlabel_getattr - Get the security attributes for an unlabled packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Determine the security attributes, if any, for an unlabled packet and return
+ * them in @secattr. Returns zero on success and negative values on failure.
+ *
+ */
+int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr)
+{
+ BUG_ON(secattr == NULL);
+
+ if (atomic_read(&netlabel_unlabel_accept_flg) == 1) {
+ memset(secattr, 0, sizeof(*secattr));
+ return 0;
+ }
+
+ return -ENOMSG;
+}
+
+/**
+ * netlbl_unlabel_defconf - Set the default config to allow unlabeled packets
+ *
+ * Description:
+ * Set the default NetLabel configuration to allow incoming unlabeled packets
+ * and to send unlabeled network traffic by default.
+ *
+ */
+int netlbl_unlabel_defconf(void)
+{
+ int ret_val;
+ struct netlbl_dom_map *entry;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (entry == NULL)
+ return -ENOMEM;
+ entry->type = NETLBL_NLTYPE_UNLABELED;
+ ret_val = netlbl_domhsh_add_default(entry);
+ if (ret_val != 0)
+ return ret_val;
+
+ atomic_set(&netlabel_unlabel_accept_flg, 1);
+
+ return 0;
+}
--
paul moore
linux security @ hp
^ permalink raw reply
* [RFC 8/8] NetLabel: tie NetLabel into the Kconfig system
From: paul.moore @ 2006-06-22 22:49 UTC (permalink / raw)
To: netdev; +Cc: davem
In-Reply-To: <20060622224910.885573000@flek.zko.hp.com>
[-- Attachment #1: netlabel-net_kconfig-2.6.17 --]
[-- Type: text/plain, Size: 521 bytes --]
Modify the net/Kconfig file to enable selecting the NetLabel Kconfig options.
---
net/Kconfig | 2 ++
1 files changed, 2 insertions(+)
Index: linux-2.6.17.i686-quilt/net/Kconfig
===================================================================
--- linux-2.6.17.i686-quilt.orig/net/Kconfig
+++ linux-2.6.17.i686-quilt/net/Kconfig
@@ -228,6 +228,8 @@ source "net/tux/Kconfig"
config WIRELESS_EXT
bool
+source "net/netlabel/Kconfig"
+
endif # if NET
endmenu # Networking
--
paul moore
linux security @ hp
^ permalink raw reply
* Re: [PATCH 0/2][RFC] Network Event Notifier Mechanism
From: David Miller @ 2006-06-22 22:58 UTC (permalink / raw)
To: caitlinb; +Cc: hadi, swise, netdev
In-Reply-To: <54AD0F12E08D1541B826BE97C98F99F15F55E2@NT-SJCA-0751.brcm.ad.broadcom.com>
From: "Caitlin Bestler" <caitlinb@broadcom.com>
Date: Thu, 22 Jun 2006 15:11:27 -0700
> I don't have any strong opinion on the best mechanism
> for implementing these subscriptions, but having correct
> consistent networking behaviour depend on a user-mode
> relay strikes me as odd.
Never heard of a routing daemon? That all works in userspace.
Anyways, we can create normal notifiers for neighbour and route
events just like we have for network device stuff.
There should be netlink counterparts for that stuff too, which
are generated by the notifier calls or similar.
^ permalink raw reply
* Re: [PATCH] fix net-core kernel-doc
From: David Miller @ 2006-06-22 23:00 UTC (permalink / raw)
To: rdunlap; +Cc: netdev
In-Reply-To: <20060622151443.24dd8d9e.rdunlap@xenotime.net>
From: "Randy.Dunlap" <rdunlap@xenotime.net>
Date: Thu, 22 Jun 2006 15:14:43 -0700
> From: Randy Dunlap <rdunlap@xenotime.net>
>
> Warning(/var/linsrc/linux-2617-g4//include/linux/skbuff.h:304): No description found for parameter 'dma_cookie'
> Warning(/var/linsrc/linux-2617-g4//include/net/sock.h:1274): No description found for parameter 'copied_early'
> Warning(/var/linsrc/linux-2617-g4//net/core/dev.c:3309): No description found for parameter 'chan'
> Warning(/var/linsrc/linux-2617-g4//net/core/dev.c:3309): No description found for parameter 'event'
>
> Signed-off-by: Randy Dunlap <rdunlap@xenotime.net>
Applied, thanks a lot Randy.
^ permalink raw reply
* Pull request for 'upstream' branch
From: Francois Romieu @ 2006-06-22 23:20 UTC (permalink / raw)
To: jeff; +Cc: netdev, Roy Marples
Please pull from branch 'upstream' to get the change below:
git://electric-eye.fr.zoreil.com/home/romieu/linux-2.6.git
Patch applies to jeff#upstream, jeff#upstream-fixes and jeff#upstream-linus.
Shortlog
--------
Roy Marples:
via-velocity: the link is not correctly detected when the device starts
Patch
-----
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 2eb6b5f..09e05fe 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -248,6 +248,7 @@ static void velocity_free_rd_ring(struct
static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_info *);
static int velocity_soft_reset(struct velocity_info *vptr);
static void mii_init(struct velocity_info *vptr, u32 mii_status);
+static u32 velocity_get_link(struct net_device *dev);
static u32 velocity_get_opt_media_mode(struct velocity_info *vptr);
static void velocity_print_link_status(struct velocity_info *vptr);
static void safe_disable_mii_autopoll(struct mac_regs __iomem * regs);
@@ -798,6 +799,9 @@ #endif
if (ret < 0)
goto err_iounmap;
+ if (velocity_get_link(dev))
+ netif_carrier_off(dev);
+
velocity_print_info(vptr);
pci_set_drvdata(pdev, dev);
@@ -1653,8 +1657,10 @@ static void velocity_error(struct veloci
if (linked) {
vptr->mii_status &= ~VELOCITY_LINK_FAIL;
+ netif_carrier_on(vptr->dev);
} else {
vptr->mii_status |= VELOCITY_LINK_FAIL;
+ netif_carrier_off(vptr->dev);
}
velocity_print_link_status(vptr);
^ permalink raw reply related
* Re: New Qlogic qla3xxx NIC Driver v2.02.00k34 for upstream inclusion
From: Jeff Garzik @ 2006-06-22 23:22 UTC (permalink / raw)
To: Ron Mercer; +Cc: Andrew Morton, netdev, linux-driver, Francois Romieu
In-Reply-To: <0BB3E5E7462EEA4295BC02D49691DC0717688F@AVEXCH1.qlogic.org>
Ron Mercer wrote:
> ftp://ftp.qlogic.com/outgoing/linux/network/upstream/2.02.00k34/qla3xxxp
> atch1-v2.02.00-k34.txt
Your mailer breaks this into two lines, which is a pain.
Comments on this updated version:
1) [semi-major] Infinite loop in ql_sem_spinlock(), if hardware is
faulty or been unplugged.
2) Similarly, other rare hardware conditions could cause
ql_sem_spinlock() to wait for a very, very long time.
3) [minor] PCI_POSTING() macro seems a bit ugly to me. No good
suggestions on better paths... maybe at least make it a static inline,
to enable better type checking.
4) [minor] ql_wait_for_drvr_lock() should use ssleep() rather than msleep()
5) What is the point of using the hardware semaphore? Is a firmware
competing with the device driver somehow, and its activities require
synchronization with the OS driver?
6) [major] The locking model is wrong for the API. The very low level
functions ql_read_common_reg() and ql_write_common_reg() take a spinlock
inside their guts, which is quite expensive when you read the rest of
the code:
> + /* Clock in a zero, then do the start bit */
> + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,+ ISP_NVRAM_MASK | qdev->eeprom_cmd_data |
> + AUBURN_EEPROM_DO_1);
> + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,+ ISP_NVRAM_MASK | qdev->
> + eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
> + AUBURN_EEPROM_CLK_RISE);
> + ql_write_common_reg(qdev, &port_regs->CommonRegs.serialPortInterfaceReg,+ ISP_NVRAM_MASK | qdev->
> + eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
> + AUBURN_EEPROM_CLK_FALL);
The above quoted code just acquired and released the spinlock three
times, an operation that could have _obviously_ been reduced to a single
lock acquire + release. In fact, the situation is worse than it sounds,
because there were a bunch more ql_write_common_reg() calls in the
function I quoted from.
Thus, this locking is _too_ low-level, and it _prevents_ more
intelligent use of spinlocks, e.g.
spin_lock_foo()
write reg
write reg
read reg
spin_unlock_foo()
I would venture to say that this locking model is largely useless in
practice. A better locking scheme is not only far more optimal, it
would also be more _provable_ (such as with Ingo's lock validator).
7) Severe lack of comments.
8) [readability] ql_link_state_machine() suffers from overzealous
indentation, which was caused by the functions large size. At the very
least, I would suggest breaking out the "/* configure the MAC */"
sequence into a separate function.
9) [minor] "N/A" appears to be an inaccurate value for fw_version in
ql_get_drvinfo()
10) [semi-major] More over-locking. You take the TX spinlock for
_every_ TX, in ql_process_mac_tx_intr() [which only processes a single
TX completion] -> ql_free_txbuf().
11) General comment: Have you noticed that all hot path operations save
for ->hard_start_xmit() occur entirely inside adapter_lock ?
12) For new drivers, we see additional work and little value for
maintained #ifdef'd NAPI and non-NAPI code paths. Just pick the best
one (and justify that decision with sound technical rationale).
13) The tx_lock appears to offer no value outside of the normal locking.
14) Surely there is a better way to down the adapter than masking the
interrupts and resetting the adapter? If this is ever used in non-MSI
situations (common in Linux today), there is the possibility of
screaming interrupts, in shared-interrupt situations.
15) I wonder if SA_SHIRQ needs to be set, for MSI?
16) [minor] several other places where ssleep() could be used
17) the following tests in ql3xxx_remove() should be eliminated, as they
are impossible:
+ if (ndev == NULL)
+ if (qdev == NULL) {
18) [minor] standard practice is to print the driver name and version in
pci_driver::probe(), on the first call to that function. Your driver
acts differently from others, by printing it in ql3xxx_init_module()
^ permalink raw reply
* Re: [Bugme-new] [Bug 6735] New: network connection does not survive APM suspend and resume
From: Andrew Morton @ 2006-06-22 23:54 UTC (permalink / raw)
To: bugme-daemon@kernel-bugs.osdl.org; +Cc: Lee Revell, netdev, rob.dyck
In-Reply-To: <200606222339.k5MNdM7K007547@fire-2.osdl.org>
bugme-daemon@bugzilla.kernel.org wrote:
>
> http://bugzilla.kernel.org/show_bug.cgi?id=6735
>
> Summary: network connection does not survive APM suspend and
> resume
>
> ...
>
> Steps to reproduce:Push button to suspend ( APM ), push button again to resume,
> network connection is lost.
>
> Problem Description:The network connection will not survive suspend and resume.
> Works correctly on 2.6.16.1. "/etc/rc.d/init.d/network restart" will restore
> the network. I tried compiling with the file via-rhine.c from 2.6.16.1 but it
> still fails. No error messages.
This is a post-2.6.16 regression.
It's probably unrelated to the device driver itself.
Can anyone suggest where we should be looking?
Thanks.
^ permalink raw reply
* RE: [PATCH 01/06] MLSXFRM: Granular IPSec associations for use in MLS environments
From: James Morris @ 2006-06-22 23:53 UTC (permalink / raw)
To: Venkat Yekkirala; +Cc: netdev, selinux, David S. Miller, Stephen Smalley
In-Reply-To: <36282A1733C57546BE392885C06185920132419A@chaos.tcs.tcs-sec.com>
On Wed, 21 Jun 2006, Venkat Yekkirala wrote:
> > Can you clarify whether, with this patch, Linux will then have a
> > complete labeled network implementation in terms of both LSPP
> > compliance and common user requirements?
>
> I can't comment on the LSPP compliance issue since the specific/proprietary
> security target being used might really decide what's needed.
>
> As for common user requirements, at least as I understand them, I would
> look for the following in addition to this patch:
>
> - Auto-labelling of child sockets for TCP (I am planning on sending a
> separate
> patch out in the next few days).
> - Using the label from the incoming packet while sending timewait
> acknowledgements
> and other packets sent on behalf of kernel sockets.
I think we'd want to have these as part of this MLS enhancement patchset.
As-is, it's not functional in a production quality sense, in that, simple
common actions such as a user pressing ctrl-c in an ftp client can cause
TCP to break, because packets not owned any more by a process will be
labeled differently.
Features added to the upstream kernel need to be 'complete' in that they
provide some minimally functional set of features, and meet a clear user
requirement. This code seems to be only partially complete, and it's not
clear to me (and likely other network maintainers) what a complete
implementation should look like.
What we need is a design rationale, some kind of detailed discussion of
what the user requirements are and what the plan is for implementing
features to meet these requirements.
Then, we can trace patchsets back to the requirements and understand where
each patchset gets us in terms of orderly progression toward
specific goals.
> - sid prioritization among the current mix of secmark, ipsec, and the
> upcoming netlabel
> - Replacing secmark on output with an access check in postrouting.
This area in general, the interaction between local packet labeling and on
the wire labeling, needs some solid analysis and discussion on netdev, so
that the correct solution can be implemented.
It should not be an afterthought.
> - localhost traffic handling with regard to labelling.
Again, this is an important area, but currently seems like an
afterthought.
And what about userland APIs relating to MLS labeling? Does the kernel
currently provide everything you think you need in this respect?
What about polyinstantiated ports?
What about interaction with namespaces and containers?
> > > Outstanding items/issues: - Timewait acknowledgements and such are
> > > generated in the current/upstream implementation using a NULL socket
> > resulting in the
> > > any_socket sid (SYSTEM_HIGH) to be used. This problem is
> > not addressed
> > > by this patch set.
> >
> > This needs to be resolved, along with labeling for all kernel owned
> > socket/tw objects.
>
> Resolved these should be, but given the fact that this patch doesn't
> introduce this problem in the first place, and given the value it adds
> to the xfrm stuff, my hope would be for this patch to be treated
> separately. I am hoping for 2.6.18 if possible.
The problem is that not all of the packets are being labeled the way you
want them to be. It's a partial solution which I can't imagine being
useful to anyone in a practical scenario.
Upstream developers are not experts in MLS, yet need to be able to make
informed decisions on whether patches being submitted are appropriate:
better documentation is required.
The original SELinux submissions presented a significant shift in thinking
on security, but they were supported by extensive documentation including
the user requirement for MAC and detailed design rationale. This made it
possible for kernel maintainers to understand what was being submitted.
Similar is required for these MLS enhancements to networking, including
some broader thinking about general architectural directions (e.g. how
this fits in with namespaces, as mentioned above, and also possibly,
whether APIs and other components are suitable also for legacy MLS
labeling schemes, at least two of which are being worked on).
There's also the question of ongoing maintenance in the mainline kernel.
Unfortunately, there's been an increasing trend recently for companies to
drop code over the wall. For example, once they get it to some basic
level of completeness, and the initial patches are merged, their
developers are reassigned to other projects and the upstream maintainers
are left with code that's not yet up to Linux kernel quality and also
something they may not understand very well. So, we need to know whether
TCS or anyone else with expert knowledge of MLS will be helping months or
years down the track, once this code has been merged.
- James
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: [Bugme-new] [Bug 6735] New: network connection does not survive APM suspend and resume
From: Lee Revell @ 2006-06-22 23:55 UTC (permalink / raw)
To: Andrew Morton; +Cc: bugme-daemon@kernel-bugs.osdl.org, netdev, rob.dyck
In-Reply-To: <20060622165440.3807e92c.akpm@osdl.org>
How in the heck did I get on the CC list for this? ;-)
Lee
On Thu, 2006-06-22 at 16:54 -0700, Andrew Morton wrote:
> bugme-daemon@bugzilla.kernel.org wrote:
> >
> > http://bugzilla.kernel.org/show_bug.cgi?id=6735
> >
> > Summary: network connection does not survive APM suspend and
> > resume
> >
> > ...
> >
> > Steps to reproduce:Push button to suspend ( APM ), push button again to resume,
> > network connection is lost.
> >
> > Problem Description:The network connection will not survive suspend and resume.
> > Works correctly on 2.6.16.1. "/etc/rc.d/init.d/network restart" will restore
> > the network. I tried compiling with the file via-rhine.c from 2.6.16.1 but it
> > still fails. No error messages.
>
> This is a post-2.6.16 regression.
>
> It's probably unrelated to the device driver itself.
>
> Can anyone suggest where we should be looking?
>
> Thanks.
>
^ permalink raw reply
* Re: New Qlogic qla3xxx NIC Driver v2.02.00k34 for upstream inclusion
From: Roland Dreier @ 2006-06-23 0:05 UTC (permalink / raw)
To: Jeff Garzik
Cc: Ron Mercer, Andrew Morton, netdev, linux-driver, Francois Romieu
In-Reply-To: <449B2621.7080607@garzik.org>
> 15) I wonder if SA_SHIRQ needs to be set, for MSI?
Why would it? MSI vectors are always unique, aren't they?
- R.
^ permalink raw reply
* [PATCH 1/1] add b44 to maintainers
From: Gary Zambrano @ 2006-06-23 0:26 UTC (permalink / raw)
To: Jeff Garzik; +Cc: netdev
In-Reply-To: <1151021430.20563.10.camel@dhcp-10-7-81-7.broadcom.com>
Add b44 to the MAINTAINERS file.
Signed-off-by: Gary Zambrano <zambrano@broadcom.com>
diff --git a/MAINTAINERS b/MAINTAINERS
index 1421f74..a52e9c0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -568,6 +568,12 @@ L: linuxppc-dev@ozlabs.org
W: http://www.penguinppc.org/ppc64/
S: Supported
+BROADCOM B44 10/100 ETHERNET DRIVER
+P: Gary Zambrano
+M: zambrano@broadcom.com
+L: netdev@vger.kernel.org
+S: Supported
+
BROADCOM BNX2 GIGABIT ETHERNET DRIVER
P: Michael Chan
M: mchan@broadcom.com
^ permalink raw reply related
* Re: New Qlogic qla3xxx NIC Driver v2.02.00k31 for upstream inclusion
From: Philip Craig @ 2006-06-23 0:51 UTC (permalink / raw)
To: Ron Mercer; +Cc: Andrew Morton, jeff, linux-driver, netdev
In-Reply-To: <20060621215531.14812d7c.akpm@osdl.org>
On 06/22/2006 02:55 PM, Andrew Morton wrote:
> - Is there a better way of doing this?
>
> static void ql_swap_mac_addr(u8 * macAddress)
> {
> #ifdef __BIG_ENDIAN
> u8 temp;
> temp = macAddress[0];
> macAddress[0] = macAddress[1];
> macAddress[1] = temp;
> temp = macAddress[2];
> macAddress[2] = macAddress[3];
> macAddress[3] = temp;
> temp = macAddress[4];
> macAddress[4] = macAddress[5];
> macAddress[5] = temp;
> #endif
> }
Perhaps something like:
static void ql_swap_mac_addr(u8 * macAddress)
{
u16 *p = (u16 *)macAddress;
cpu_to_le16s(p);
cpu_to_le16s(p+1);
cpu_to_le16s(p+2);
}
You could use cpu_to_le16s for the version/numPorts conversion too.
^ permalink raw reply
* Re: [NET]: Prevent multiple qdisc runs
From: jamal @ 2006-06-23 0:52 UTC (permalink / raw)
To: Herbert Xu; +Cc: Robert Olsson, David S. Miller, netdev
In-Reply-To: <20060622224302.GA10136@gondor.apana.org.au>
On Fri, 2006-23-06 at 08:43 +1000, Herbert Xu wrote:
> Sure. However, I still don't see the point of transmitting in parallel
> even there. The reason is that there is no work being done here by the
> CPU between dequeueing the packet and obtaining the TX lock.
You make a reasonable argument.
I think I will need to run the experiment to gather facts. I will defer
this discussion until i run some tests or Robert beats me to it.
It does feel like the qdisc_is_running though is now a replacement
for the need for dev->txlock which existed to protect multi-cpus from
entering the device transmit path. Is that unintended side effect?
i.e why would dev->txlock be needed anymore in that path?
cheers,
jamal
^ permalink raw reply
* Re: [PATCH 0/2][RFC] Network Event Notifier Mechanism
From: jamal @ 2006-06-23 0:56 UTC (permalink / raw)
To: David Miller; +Cc: netdev, swise, caitlinb
In-Reply-To: <20060622.155805.35017169.davem@davemloft.net>
On Thu, 2006-22-06 at 15:58 -0700, David Miller wrote:
> Anyways, we can create normal notifiers for neighbour and route
> events just like we have for network device stuff.
>
> There should be netlink counterparts for that stuff too, which
> are generated by the notifier calls or similar.
Sounds reasonable - so someone deciding to do this from user space
would still be able to do so.
cheers,
jamal
PS:- I do think what they need is to hear route cache generation
as opposed to ARP+FIB updates; but lets wait and see how clever
the patches would look.
^ permalink raw reply
* [PATCH 0/2] myri10ge - drop 2 workarounds that have been fixed in the PCI core
From: Brice Goglin @ 2006-06-23 1:10 UTC (permalink / raw)
To: netdev
Hi,
The following 2 patches remove 2 workarounds that were in myri10ge until
the PCI core included a nice fix, which is the case now.
[PATCH] myri10ge - drop workaround for the missing AER ext cap on nVidia CK804
[PATCH] myri10ge - drop workaround pci_save_state() disabling MSI
Please apply.
Thanks,
Brice Goglin
^ permalink raw reply
* [PATCH 1/2] myri10ge - drop workaround for the missing AER ext cap on nVidia CK804
From: Brice Goglin @ 2006-06-23 1:11 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060623011043.GA18234@myri.com>
[PATCH] myri10ge - drop workaround for the missing AER ext cap on nVidia CK804
We don't need to hardcode the AER capability of the nVidia CK804 chipset
anymore since commit cf34a8e07f02c76f3f1232eecb681301a3d7b10b (PCI: nVidia
quirk to make AER PCI-E extended capability visible) now makes sure that
this cap will be available to pci_find_ext_capability().
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/myri10ge.c | 6 ------
1 file changed, 6 deletions(-)
Index: linux-mm/drivers/net/myri10ge/myri10ge.c
===================================================================
--- linux-mm.orig/drivers/net/myri10ge/myri10ge.c 2006-06-22 20:41:50.000000000 -0400
+++ linux-mm/drivers/net/myri10ge/myri10ge.c 2006-06-22 20:41:59.000000000 -0400
@@ -2251,12 +2251,6 @@
}
cap = pci_find_ext_capability(bridge, PCI_EXT_CAP_ID_ERR);
- /* nvidia ext cap is not always linked in ext cap chain */
- if (!cap
- && bridge->vendor == PCI_VENDOR_ID_NVIDIA
- && bridge->device == PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_PCIE)
- cap = 0x160;
-
if (!cap)
return;
^ permalink raw reply
* [PATCH 2/2] myri10ge - drop workaround pci_save_state() disabling MSI
From: Brice Goglin @ 2006-06-23 1:12 UTC (permalink / raw)
To: netdev
In-Reply-To: <20060623011043.GA18234@myri.com>
[PATCH] myri10ge - drop workaround pci_save_state() disabling MSI
We don't need to restore the state right after saving it for later recovery
since commit 99dc804d9bcc2c53f4c20c291bf4e185312a1a0c (PCI: disable msi mode
in pci_disable_device) now prevents pci_save_state() from disabling MSI.
Signed-off-by: Brice Goglin <brice@myri.com>
---
drivers/net/myri10ge/myri10ge.c | 2 --
1 file changed, 2 deletions(-)
Index: linux-mm/drivers/net/myri10ge/myri10ge.c
===================================================================
--- linux-mm.orig/drivers/net/myri10ge/myri10ge.c 2006-06-22 20:42:34.000000000 -0400
+++ linux-mm/drivers/net/myri10ge/myri10ge.c 2006-06-22 20:42:45.000000000 -0400
@@ -2726,8 +2726,6 @@
/* Save configuration space to be restored if the
* nic resets due to a parity error */
myri10ge_save_state(mgp);
- /* Restore state immediately since pci_save_msi_state disables MSI */
- myri10ge_restore_state(mgp);
/* Setup the watchdog timer */
setup_timer(&mgp->watchdog_timer, myri10ge_watchdog_timer,
^ permalink raw reply
* Re: New Qlogic qla3xxx NIC Driver v2.02.00k34 for upstream inclusion
From: Jeff Garzik @ 2006-06-23 1:20 UTC (permalink / raw)
To: Roland Dreier
Cc: Ron Mercer, Andrew Morton, netdev, linux-driver, Francois Romieu
In-Reply-To: <adapsh0losd.fsf@cisco.com>
Roland Dreier wrote:
> > 15) I wonder if SA_SHIRQ needs to be set, for MSI?
>
> Why would it? MSI vectors are always unique, aren't they?
Precisely what my question implies...
Jeff
^ permalink raw reply
* Re: Locking validator output on DCCP
From: Ian McDonald @ 2006-06-23 2:38 UTC (permalink / raw)
To: Arjan van de Ven
Cc: Herbert Xu, Arnaldo Carvalho de Melo, DCCP Mailing List, netdev,
Ingo Molnar
In-Reply-To: <5640c7e00606212151y213c0bfap5e02a77d9363ebb7@mail.gmail.com>
On 6/22/06, Ian McDonald <ian.mcdonald@jandi.co.nz> wrote:
> On 6/21/06, Arjan van de Ven <arjan@linux.intel.com> wrote:
> > On Wed, 2006-06-21 at 10:34 +1000, Herbert Xu wrote:
> > > > As I read this it is not a recursive lock as sk_clone is occurring
> > > > second and is actually creating a new socket so they are trying to
> > > > lock on different sockets.
> > > >
> > > > Can someone tell me whether I am correct in my thinking or not? If I
> > > > am then I will work out how to tell the lock validator not to worry
> > > > about it.
> > >
> > > I agree, this looks bogus. Ingo, could you please take a look?
> >
> > Fix is relatively easy:
> >
> >
> > sk_clone creates a new socket, and thus can never deadlock, and in fact
> > can be called with the original socket locked. This therefore is a
> > legitimate nesting case; mark it as such.
> >
> > Signed-off-by: Arjan van de Ven <arjan@linux.intel.com>
> >
> >
> > ---
> > net/core/sock.c | 2 +-
> > 1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > Index: linux-2.6.17-rc6-mm2/net/core/sock.c
> > ===================================================================
> > --- linux-2.6.17-rc6-mm2.orig/net/core/sock.c
> > +++ linux-2.6.17-rc6-mm2/net/core/sock.c
> > @@ -846,7 +846,7 @@ struct sock *sk_clone(const struct sock
> > /* SANITY */
> > sk_node_init(&newsk->sk_node);
> > sock_lock_init(newsk);
> > - bh_lock_sock(newsk);
> > + bh_lock_sock_nested(newsk);
> >
> > atomic_set(&newsk->sk_rmem_alloc, 0);
> > atomic_set(&newsk->sk_wmem_alloc, 0);
> >
> >
> When I do this it now shifts around. I'll investigate further
> (probably tomorrow).
>
> Now get
>
> Jun 22 14:20:48 localhost kernel: [ 1276.424531]
> =============================================
> Jun 22 14:20:48 localhost kernel: [ 1276.424541] [ INFO: possible
> recursive locking detected ]
> Jun 22 14:20:48 localhost kernel: [ 1276.424546]
> ---------------------------------------------
> Jun 22 14:20:48 localhost kernel: [ 1276.424553] idle/0 is trying to
> acquire lock:
> Jun 22 14:20:48 localhost kernel: [ 1276.424559]
> (&sk->sk_lock.slock#5/1){-+..}, at: [<c024594e>] sk_clone+0x5f/0x195
> Jun 22 14:20:48 localhost kernel: [ 1276.424585]
> Jun 22 14:20:48 localhost kernel: [ 1276.424587] but task is already
> holding lock:
> Jun 22 14:20:48 localhost kernel: [ 1276.424592]
> (&sk->sk_lock.slock#5/1){-+..}, at: [<c027cd87>]
> tcp_v4_rcv+0x42e/0x9b3
> Jun 22 14:20:48 localhost kernel: [ 1276.424616]
> Jun 22 14:20:48 localhost kernel: [ 1276.424618] other info that might
> help us debug this:
> Jun 22 14:20:48 localhost kernel: [ 1276.424624] 2 locks held by idle/0:
> Jun 22 14:20:48 localhost kernel: [ 1276.424628] #0:
> (&tp->rx_lock){-+..}, at: [<e0898915>] rtl8139_poll+0x42/0x41c
> [8139too]
> Jun 22 14:20:48 localhost kernel: [ 1276.424666] #1:
> (&sk->sk_lock.slock#5/1){-+..}, at: [<c027cd87>]
> tcp_v4_rcv+0x42e/0x9b3
> Jun 22 14:20:48 localhost kernel: [ 1276.424685]
> Jun 22 14:20:48 localhost kernel: [ 1276.424686] stack backtrace:
> Jun 22 14:20:48 localhost kernel: [ 1276.425002] [<c0103a2a>]
> show_trace_log_lvl+0x53/0xff
> Jun 22 14:20:48 localhost kernel: [ 1276.425038] [<c0104078>]
> show_trace+0x16/0x19
> Jun 22 14:20:48 localhost kernel: [ 1276.425068] [<c010411e>]
> dump_stack+0x1a/0x1f
> Jun 22 14:20:48 localhost kernel: [ 1276.425099] [<c012d6cb>]
> __lock_acquire+0x8e6/0x902
> Jun 22 14:20:48 localhost kernel: [ 1276.425311] [<c012d879>]
> lock_acquire+0x4e/0x66
> Jun 22 14:20:48 localhost kernel: [ 1276.425510] [<c02989e1>]
> _spin_lock_nested+0x26/0x36
> Jun 22 14:20:48 localhost kernel: [ 1276.425726] [<c024594e>]
> sk_clone+0x5f/0x195
> Jun 22 14:20:48 localhost kernel: [ 1276.427191] [<c026d10f>]
> inet_csk_clone+0xf/0x67
> Jun 22 14:20:48 localhost kernel: [ 1276.428879] [<c027d3d0>]
> tcp_create_openreq_child+0x15/0x32b
> Jun 22 14:20:48 localhost kernel: [ 1276.430598] [<c027b383>]
> tcp_v4_syn_recv_sock+0x47/0x29c
> Jun 22 14:20:48 localhost kernel: [ 1276.432313] [<e0fcf440>]
> tcp_v6_syn_recv_sock+0x37/0x534 [ipv6]
> Jun 22 14:20:48 localhost kernel: [ 1276.432482] [<c027d886>]
> tcp_check_req+0x1a0/0x2db
> Jun 22 14:20:48 localhost kernel: [ 1276.434198] [<c027aecc>]
> tcp_v4_do_rcv+0x9f/0x2fe
> Jun 22 14:20:48 localhost kernel: [ 1276.435911] [<c027d28b>]
> tcp_v4_rcv+0x932/0x9b3
> Jun 22 14:20:48 localhost kernel: [ 1276.437632] [<c0265980>]
> ip_local_deliver+0x159/0x1f1
> Jun 22 14:20:48 localhost kernel: [ 1276.439305] [<c02657fa>]
> ip_rcv+0x3e9/0x416
> Jun 22 14:20:48 localhost kernel: [ 1276.440977] [<c024bba4>]
> netif_receive_skb+0x287/0x317
> Jun 22 14:20:48 localhost kernel: [ 1276.442542] [<e0898b67>]
> rtl8139_poll+0x294/0x41c [8139too]
> Jun 22 14:20:48 localhost kernel: [ 1276.442590] [<c024d585>]
> net_rx_action+0x8b/0x17c
> Jun 22 14:20:48 localhost kernel: [ 1276.444160] [<c011adf6>]
> __do_softirq+0x54/0xb3
> Jun 22 14:20:48 localhost kernel: [ 1276.444335] [<c011ae84>]
> do_softirq+0x2f/0x47
> Jun 22 14:20:48 localhost kernel: [ 1276.444460] [<c011b0a5>]
> irq_exit+0x39/0x46
> Jun 22 14:20:48 localhost kernel: [ 1276.444585] [<c0104f73>] do_IRQ+0x77/0x84
> Jun 22 14:20:48 localhost kernel: [ 1276.444621] [<c0103561>]
> common_interrupt+0x25/0x2c
>
OK. This is in net/ipv4/tcp_ipv4.c tcp_v4_rcv with the
bh_lock_sock_nested which I presume is clashing with the nested of
skb_clone....
Can we not do two levels nested?
Is there extra documentation for the locking validation suite so that
I can stop asking stupid questions? If not I'll just read more of the
source code.
Ian
--
Ian McDonald
Web: http://wand.net.nz/~iam4
Blog: http://imcdnzl.blogspot.com
WAND Network Research Group
Department of Computer Science
University of Waikato
New Zealand
^ permalink raw reply
* Re: [PATCH 2.6.17] AT91RM9200 Ethernet #1: Link poll
From: Jeff Garzik @ 2006-06-23 2:56 UTC (permalink / raw)
To: Andrew Victor; +Cc: netdev
In-Reply-To: <1150797022.15581.329.camel@fuzzie.sanpeople.com>
Andrew Victor wrote:
> For Ethernet PHYs that don't have an IRQ pin or boards that don't
> connect the IRQ pin to the processor, we enable a timer to poll the
> PHY's link state.
>
> Patch originally supplied by Eric Benard and Roman Kolesnikov.
applied patches 1-4
^ permalink raw reply
* Re: [PATCH 1/6 resend] b44: fix manual speed/duplex/autoneg settings
From: Jeff Garzik @ 2006-06-23 3:16 UTC (permalink / raw)
To: Gary Zambrano; +Cc: netdev
In-Reply-To: <1150842855.21197.53.camel@dhcp-10-7-81-7.broadcom.com>
applied patches 1-6
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox