[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]
[redhat-lspp] Updated NetLabel patch
- From: Paul Moore <paul moore hp com>
- To: redhat-lspp redhat com
- Cc: Steve Grubb <sgrubb redhat com>
- Subject: [redhat-lspp] Updated NetLabel patch
- Date: Tue, 13 Jun 2006 13:19:29 -0400
Attached is an updated NetLabel patch from June 13th (today) against the
lspp.35 sources. As before it has been quickly tested on x86, x86_64,
targeted/enforcing, and mls/permissive although not all hw/policy
combinations have been tested. If you wish to configure NetLabel to use
CIPSO please grab the June 13th release of netlabel_tools which can be
found here:
* http://free.linux.hp.com/~pmoore/projects/linux_cipso
The big changes since the last posting on June 6th are:
* Demonstrated interop between TSOL v 8 (big thanks to Ted)
* Relabeling of sockets on accept()
* The addition of the "pass through" CIPSO mapping
* Better NetLabel netlink error reporting to userspace
* Verified CIPSO option is recognized as immutable by AH
(not yet tested)
The patch stats:
CREDITS | 7
Documentation/00-INDEX | 2
Documentation/netlabel/00-INDEX | 10
Documentation/netlabel/cipso_ipv4.txt | 48
Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt | 791 ++++
Documentation/netlabel/introduction.txt | 44
Documentation/netlabel/lsm_interface.txt | 47
include/linux/ip.h | 1
include/linux/netlink.h | 1
include/net/cipso_ipv4.h | 159
include/net/inet_sock.h | 2
include/net/netlabel.h | 354 ++
net/Kconfig | 2
net/Makefile | 1
net/ipv4/Makefile | 1
net/ipv4/ah4.c | 2
net/ipv4/cipso_ipv4.c | 1749 ++++++
net/ipv4/ip_options.c | 19
net/netlabel/Kconfig | 47
net/netlabel/Makefile | 15
net/netlabel/netlabel_cipso_v4.c | 580 +++
net/netlabel/netlabel_cipso_v4.h | 201 +
net/netlabel/netlabel_domainhash.c | 629 +++
net/netlabel/netlabel_domainhash.h | 64
net/netlabel/netlabel_kapi.c | 420 ++
net/netlabel/netlabel_mgmt.c | 677 +++
net/netlabel/netlabel_mgmt.h | 248 +
net/netlabel/netlabel_unlabeled.c | 285 +
net/netlabel/netlabel_unlabeled.h | 83
net/netlabel/netlabel_user.c | 174
net/netlabel/netlabel_user.h | 42
security/selinux/hooks.c | 81
security/selinux/include/av_inherit.h | 1
security/selinux/include/av_perm_to_string.h | 2
security/selinux/include/av_permissions.h | 1
security/selinux/include/flask.h | 1
security/selinux/include/security.h | 9
security/selinux/nlmsgtab.c | 159
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/services.c | 415 ++
security/selinux/xfrm.c | 22
44 files changed, 7652 insertions(+), 90 deletions(-)
I'll be posting a more "reviewer friendly" patchset in a week or so once
this has been out for a few days and I have had a chance to work on the
patch a bit more (discussed on Monday's concall).
--
paul moore
linux security @ hp
diff -purN linux-2.6.16.i686/CREDITS linux-2.6.16.i686-netlabel_06132006/CREDITS
--- linux-2.6.16.i686/CREDITS 2006-06-13 10:47:07.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/CREDITS 2006-06-13 11:19:58.000000000 -0400
@@ -2383,6 +2383,13 @@ N: Thomas Molina
E: tmolina cablespeed com
D: bug fixes, documentation, minor hackery
+N: Paul Moore
+E: paul moore hp com
+D: NetLabel author
+S: Hewlett-Packard
+S: 110 Spit Brook Road
+S: Nashua, NH 03062
+
N: James Morris
E: jmorris namei org
W: http://namei.org/
diff -purN linux-2.6.16.i686/Documentation/00-INDEX linux-2.6.16.i686-netlabel_06132006/Documentation/00-INDEX
--- linux-2.6.16.i686/Documentation/00-INDEX 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/00-INDEX 2006-06-13 11:19:58.000000000 -0400
@@ -184,6 +184,8 @@ mtrr.txt
- how to use PPro Memory Type Range Registers to increase performance.
nbd.txt
- info on a TCP implementation of a network block device.
+netlabel/
+ - directory with information on the NetLabel subsystem.
networking/
- directory with info on various aspects of networking with Linux.
nfsroot.txt
diff -purN linux-2.6.16.i686/Documentation/netlabel/00-INDEX linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/00-INDEX
--- linux-2.6.16.i686/Documentation/netlabel/00-INDEX 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/00-INDEX 2006-06-13 11:19:58.000000000 -0400
@@ -0,0 +1,10 @@
+00-INDEX
+ - this file.
+cipso_ipv4.txt
+ - documentation on the IPv4 CIPSO protocol engine.
+draft-ietf-cipso-ipsecurity-01.txt
+ - IETF draft of the CIPSO protocol, dated 16 July 1992.
+introduction.txt
+ - NetLabel introduction, READ THIS FIRST.
+lsm_interface.txt
+ - documentation on the NetLabel kernel security module API.
diff -purN linux-2.6.16.i686/Documentation/netlabel/cipso_ipv4.txt linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/cipso_ipv4.txt
--- linux-2.6.16.i686/Documentation/netlabel/cipso_ipv4.txt 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/cipso_ipv4.txt 2006-06-13 11:19:58.000000000 -0400
@@ -0,0 +1,48 @@
+NetLabel CIPSO/IPv4 Protocol Engine
+==============================================================================
+Paul Moore, paul moore hp com
+
+May 17, 2006
+
+ * Overview
+
+The NetLabel CIPSO/IPv4 protocol engine is based on the IETF Commercial IP
+Security Option (CIPSO) draft from July 16, 1992. A copy of this draft can be
+found in this directory, consult '00-INDEX' for the filename. While the IETF
+draft never made it to an RFC standard it has become a de-facto standard for
+labeled networking and is used in many trusted operating systems.
+
+ * Outbound Packet Processing
+
+The CIPSO/IPv4 protocol engine applies the CIPSO IP option to packets by
+adding the CIPSO label to the socket. This causes all packets leaving the
+system through the socket to have the CIPSO IP option applied. The socket's
+CIPSO label can be changed at any point in time, however, it is recommended
+that it is set upon the socket's creation. The LSM can set the socket's CIPSO
+label by using the NetLabel security module API; if the NetLabel "domain" is
+configured to use CIPSO for packet labeling then a CIPSO IP option will be
+generated and attached to the socket.
+
+ * Inbound Packet Processing
+
+The CIPSO/IPv4 protocol engine validates every CIPSO IP option it finds at the
+IP layer without any special handling required by the LSM. However, in order
+to decode and translate the CIPSO label on the packet the LSM must use the
+NetLabel security module API to extract the security attributes of the packet.
+This is typically done at the socket layer using the 'socket_sock_rcv_skb()'
+LSM hook.
+
+ * Label Translation
+
+The CIPSO/IPv4 protocol engine contains a mechanism to translate CIPSO security
+attributes such as sensitivity level and category to values which are
+appropriate for the host. These mappings are defined as part of a CIPSO
+Domain Of Interpretation (DOI) definition and are configured through the
+NetLabel user space communication layer. Each DOI definition can have a
+different security attribute mapping table.
+
+ * Label Translation Cache
+
+The NetLabel system provides a framework for caching security attribute
+mappings from the network labels to the corresponding LSM identifiers. The
+CIPSO/IPv4 protocol engine supports this caching mechanism.
diff -purN linux-2.6.16.i686/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt
--- linux-2.6.16.i686/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/draft-ietf-cipso-ipsecurity-01.txt 2006-06-13 11:19:58.000000000 -0400
@@ -0,0 +1,791 @@
+IETF CIPSO Working Group
+16 July, 1992
+
+
+
+ COMMERCIAL IP SECURITY OPTION (CIPSO 2.2)
+
+
+
+1. Status
+
+This Internet Draft provides the high level specification for a Commercial
+IP Security Option (CIPSO). This draft reflects the version as approved by
+the CIPSO IETF Working Group. Distribution of this memo is unlimited.
+
+This document is an Internet Draft. Internet Drafts are working documents
+of the Internet Engineering Task Force (IETF), its Areas, and its Working
+Groups. Note that other groups may also distribute working documents as
+Internet Drafts.
+
+Internet Drafts are draft documents valid for a maximum of six months.
+Internet Drafts may be updated, replaced, or obsoleted by other documents
+at any time. It is not appropriate to use Internet Drafts as reference
+material or to cite them other than as a "working draft" or "work in
+progress."
+
+Please check the I-D abstract listing contained in each Internet Draft
+directory to learn the current status of this or any other Internet Draft.
+
+
+
+
+2. Background
+
+Currently the Internet Protocol includes two security options. One of
+these options is the DoD Basic Security Option (BSO) (Type 130) which allows
+IP datagrams to be labeled with security classifications. This option
+provides sixteen security classifications and a variable number of handling
+restrictions. To handle additional security information, such as security
+categories or compartments, another security option (Type 133) exists and
+is referred to as the DoD Extended Security Option (ESO). The values for
+the fixed fields within these two options are administered by the Defense
+Information Systems Agency (DISA).
+
+Computer vendors are now building commercial operating systems with
+mandatory access controls and multi-level security. These systems are
+no longer built specifically for a particular group in the defense or
+intelligence communities. They are generally available commercial systems
+for use in a variety of government and civil sector environments.
+
+The small number of ESO format codes can not support all the possible
+applications of a commercial security option. The BSO and ESO were
+designed to only support the United States DoD. CIPSO has been designed
+to support multiple security policies. This Internet Draft provides the
+format and procedures required to support a Mandatory Access Control
+security policy. Support for additional security policies shall be
+defined in future RFCs.
+
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 1]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+
+3. CIPSO Format
+
+Option type: 134 (Class 0, Number 6, Copy on Fragmentation)
+Option length: Variable
+
+This option permits security related information to be passed between
+systems within a single Domain of Interpretation (DOI). A DOI is a
+collection of systems which agree on the meaning of particular values
+in the security option. An authority that has been assigned a DOI
+identifier will define a mapping between appropriate CIPSO field values
+and their human readable equivalent. This authority will distribute that
+mapping to hosts within the authority's domain. These mappings may be
+sensitive, therefore a DOI authority is not required to make these
+mappings available to anyone other than the systems that are included in
+the DOI.
+
+This option MUST be copied on fragmentation. This option appears at most
+once in a datagram. All multi-octet fields in the option are defined to be
+transmitted in network byte order. The format of this option is as follows:
+
++----------+----------+------//------+-----------//---------+
+| 10000110 | LLLLLLLL | DDDDDDDDDDDD | TTTTTTTTTTTTTTTTTTTT |
++----------+----------+------//------+-----------//---------+
+
+ TYPE=134 OPTION DOMAIN OF TAGS
+ LENGTH INTERPRETATION
+
+
+ Figure 1. CIPSO Format
+
+
+3.1 Type
+
+This field is 1 octet in length. Its value is 134.
+
+
+3.2 Length
+
+This field is 1 octet in length. It is the total length of the option
+including the type and length fields. With the current IP header length
+restriction of 40 octets the value of this field MUST not exceed 40.
+
+
+3.3 Domain of Interpretation Identifier
+
+This field is an unsigned 32 bit integer. The value 0 is reserved and MUST
+not appear as the DOI identifier in any CIPSO option. Implementations
+should assume that the DOI identifier field is not aligned on any particular
+byte boundary.
+
+To conserve space in the protocol, security levels and categories are
+represented by numbers rather than their ASCII equivalent. This requires
+a mapping table within CIPSO hosts to map these numbers to their
+corresponding ASCII representations. Non-related groups of systems may
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 2]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+have their own unique mappings. For example, one group of systems may
+use the number 5 to represent Unclassified while another group may use the
+number 1 to represent that same security level. The DOI identifier is used
+to identify which mapping was used for the values within the option.
+
+
+3.4 Tag Types
+
+A common format for passing security related information is necessary
+for interoperability. CIPSO uses sets of "tags" to contain the security
+information relevant to the data in the IP packet. Each tag begins with
+a tag type identifier followed by the length of the tag and ends with the
+actual security information to be passed. All multi-octet fields in a tag
+are defined to be transmitted in network byte order. Like the DOI
+identifier field in the CIPSO header, implementations should assume that
+all tags, as well as fields within a tag, are not aligned on any particular
+octet boundary. The tag types defined in this document contain alignment
+bytes to assist alignment of some information, however alignment can not
+be guaranteed if CIPSO is not the first IP option.
+
+CIPSO tag types 0 through 127 are reserved for defining standard tag
+formats. Their definitions will be published in RFCs. Tag types whose
+identifiers are greater than 127 are defined by the DOI authority and may
+only be meaningful in certain Domains of Interpretation. For these tag
+types, implementations will require the DOI identifier as well as the tag
+number to determine the security policy and the format associated with the
+tag. Use of tag types above 127 are restricted to closed networks where
+interoperability with other networks will not be an issue. Implementations
+that support a tag type greater than 127 MUST support at least one DOI that
+requires only tag types 1 to 127.
+
+Tag type 0 is reserved. Tag types 1, 2, and 5 are defined in this
+Internet Draft. Types 3 and 4 are reserved for work in progress.
+The standard format for all current and future CIPSO tags is shown below:
+
++----------+----------+--------//--------+
+| TTTTTTTT | LLLLLLLL | IIIIIIIIIIIIIIII |
++----------+----------+--------//--------+
+ TAG TAG TAG
+ TYPE LENGTH INFORMATION
+
+ Figure 2: Standard Tag Format
+
+In the three tag types described in this document, the length and count
+restrictions are based on the current IP limitation of 40 octets for all
+IP options. If the IP header is later expanded, then the length and count
+restrictions specified in this document may increase to use the full area
+provided for IP options.
+
+
+3.4.1 Tag Type Classes
+
+Tag classes consist of tag types that have common processing requirements
+and support the same security policy. The three tags defined in this
+Internet Draft belong to the Mandatory Access Control (MAC) Sensitivity
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 3]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+class and support the MAC Sensitivity security policy.
+
+
+3.4.2 Tag Type 1
+
+This is referred to as the "bit-mapped" tag type. Tag type 1 is included
+in the MAC Sensitivity tag type class. The format of this tag type is as
+follows:
+
++----------+----------+----------+----------+--------//---------+
+| 00000001 | LLLLLLLL | 00000000 | LLLLLLLL | CCCCCCCCCCCCCCCCC |
++----------+----------+----------+----------+--------//---------+
+
+ TAG TAG ALIGNMENT SENSITIVITY BIT MAP OF
+ TYPE LENGTH OCTET LEVEL CATEGORIES
+
+ Figure 3. Tag Type 1 Format
+
+
+3.4.2.1 Tag Type
+
+This field is 1 octet in length and has a value of 1.
+
+
+3.4.2.2 Tag Length
+
+This field is 1 octet in length. It is the total length of the tag type
+including the type and length fields. With the current IP header length
+restriction of 40 bytes the value within this field is between 4 and 34.
+
+
+3.4.2.3 Alignment Octet
+
+This field is 1 octet in length and always has the value of 0. Its purpose
+is to align the category bitmap field on an even octet boundary. This will
+speed many implementations including router implementations.
+
+
+3.4.2.4 Sensitivity Level
+
+This field is 1 octet in length. Its value is from 0 to 255. The values
+are ordered with 0 being the minimum value and 255 representing the maximum
+value.
+
+
+3.4.2.5 Bit Map of Categories
+
+The length of this field is variable and ranges from 0 to 30 octets. This
+provides representation of categories 0 to 239. The ordering of the bits
+is left to right or MSB to LSB. For example category 0 is represented by
+the most significant bit of the first byte and category 15 is represented
+by the least significant bit of the second byte. Figure 4 graphically
+shows this ordering. Bit N is binary 1 if category N is part of the label
+for the datagram, and bit N is binary 0 if category N is not part of the
+label. Except for the optimized tag 1 format described in the next section,
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 4]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+minimal encoding SHOULD be used resulting in no trailing zero octets in the
+category bitmap.
+
+ octet 0 octet 1 octet 2 octet 3 octet 4 octet 5
+ XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX . . .
+bit 01234567 89111111 11112222 22222233 33333333 44444444
+number 012345 67890123 45678901 23456789 01234567
+
+ Figure 4. Ordering of Bits in Tag 1 Bit Map
+
+
+3.4.2.6 Optimized Tag 1 Format
+
+Routers work most efficiently when processing fixed length fields. To
+support these routers there is an optimized form of tag type 1. The format
+does not change. The only change is to the category bitmap which is set to
+a constant length of 10 octets. Trailing octets required to fill out the 10
+octets are zero filled. Ten octets, allowing for 80 categories, was chosen
+because it makes the total length of the CIPSO option 20 octets. If CIPSO
+is the only option then the option will be full word aligned and additional
+filler octets will not be required.
+
+
+3.4.3 Tag Type 2
+
+This is referred to as the "enumerated" tag type. It is used to describe
+large but sparsely populated sets of categories. Tag type 2 is in the MAC
+Sensitivity tag type class. The format of this tag type is as follows:
+
++----------+----------+----------+----------+-------------//-------------+
+| 00000010 | LLLLLLLL | 00000000 | LLLLLLLL | CCCCCCCCCCCCCCCCCCCCCCCCCC |
++----------+----------+----------+----------+-------------//-------------+
+
+ TAG TAG ALIGNMENT SENSITIVITY ENUMERATED
+ TYPE LENGTH OCTET LEVEL CATEGORIES
+
+ Figure 5. Tag Type 2 Format
+
+
+3.4.3.1 Tag Type
+
+This field is one octet in length and has a value of 2.
+
+
+3.4.3.2 Tag Length
+
+This field is 1 octet in length. It is the total length of the tag type
+including the type and length fields. With the current IP header length
+restriction of 40 bytes the value within this field is between 4 and 34.
+
+
+3.4.3.3 Alignment Octet
+
+This field is 1 octet in length and always has the value of 0. Its purpose
+is to align the category field on an even octet boundary. This will
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 5]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+speed many implementations including router implementations.
+
+
+3.4.3.4 Sensitivity Level
+
+This field is 1 octet in length. Its value is from 0 to 255. The values
+are ordered with 0 being the minimum value and 255 representing the
+maximum value.
+
+
+3.4.3.5 Enumerated Categories
+
+In this tag, categories are represented by their actual value rather than
+by their position within a bit field. The length of each category is 2
+octets. Up to 15 categories may be represented by this tag. Valid values
+for categories are 0 to 65534. Category 65535 is not a valid category
+value. The categories MUST be listed in ascending order within the tag.
+
+
+3.4.4 Tag Type 5
+
+This is referred to as the "range" tag type. It is used to represent
+labels where all categories in a range, or set of ranges, are included
+in the sensitivity label. Tag type 5 is in the MAC Sensitivity tag type
+class. The format of this tag type is as follows:
+
++----------+----------+----------+----------+------------//-------------+
+| 00000101 | LLLLLLLL | 00000000 | LLLLLLLL | Top/Bottom | Top/Bottom |
++----------+----------+----------+----------+------------//-------------+
+
+ TAG TAG ALIGNMENT SENSITIVITY CATEGORY RANGES
+ TYPE LENGTH OCTET LEVEL
+
+ Figure 6. Tag Type 5 Format
+
+
+3.4.4.1 Tag Type
+
+This field is one octet in length and has a value of 5.
+
+
+3.4.4.2 Tag Length
+
+This field is 1 octet in length. It is the total length of the tag type
+including the type and length fields. With the current IP header length
+restriction of 40 bytes the value within this field is between 4 and 34.
+
+
+3.4.4.3 Alignment Octet
+
+This field is 1 octet in length and always has the value of 0. Its purpose
+is to align the category range field on an even octet boundary. This will
+speed many implementations including router implementations.
+
+
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 6]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+3.4.4.4 Sensitivity Level
+
+This field is 1 octet in length. Its value is from 0 to 255. The values
+are ordered with 0 being the minimum value and 255 representing the maximum
+value.
+
+
+3.4.4.5 Category Ranges
+
+A category range is a 4 octet field comprised of the 2 octet index of the
+highest numbered category followed by the 2 octet index of the lowest
+numbered category. These range endpoints are inclusive within the range of
+categories. All categories within a range are included in the sensitivity
+label. This tag may contain a maximum of 7 category pairs. The bottom
+category endpoint for the last pair in the tag MAY be omitted and SHOULD be
+assumed to be 0. The ranges MUST be non-overlapping and be listed in
+descending order. Valid values for categories are 0 to 65534. Category
+65535 is not a valid category value.
+
+
+3.4.5 Minimum Requirements
+
+A CIPSO implementation MUST be capable of generating at least tag type 1 in
+the non-optimized form. In addition, a CIPSO implementation MUST be able
+to receive any valid tag type 1 even those using the optimized tag type 1
+format.
+
+
+4. Configuration Parameters
+
+The configuration parameters defined below are required for all CIPSO hosts,
+gateways, and routers that support multiple sensitivity labels. A CIPSO
+host is defined to be the origination or destination system for an IP
+datagram. A CIPSO gateway provides IP routing services between two or more
+IP networks and may be required to perform label translations between
+networks. A CIPSO gateway may be an enhanced CIPSO host or it may just
+provide gateway services with no end system CIPSO capabilities. A CIPSO
+router is a dedicated IP router that routes IP datagrams between two or more
+IP networks.
+
+An implementation of CIPSO on a host MUST have the capability to reject a
+datagram for reasons that the information contained can not be adequately
+protected by the receiving host or if acceptance may result in violation of
+the host or network security policy. In addition, a CIPSO gateway or router
+MUST be able to reject datagrams going to networks that can not provide
+adequate protection or may violate the network's security policy. To
+provide this capability the following minimal set of configuration
+parameters are required for CIPSO implementations:
+
+HOST_LABEL_MAX - This parameter contains the maximum sensitivity label that
+a CIPSO host is authorized to handle. All datagrams that have a label
+greater than this maximum MUST be rejected by the CIPSO host. This
+parameter does not apply to CIPSO gateways or routers. This parameter need
+not be defined explicitly as it can be implicitly derived from the
+PORT_LABEL_MAX parameters for the associated interfaces.
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 7]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+
+HOST_LABEL_MIN - This parameter contains the minimum sensitivity label that
+a CIPSO host is authorized to handle. All datagrams that have a label less
+than this minimum MUST be rejected by the CIPSO host. This parameter does
+not apply to CIPSO gateways or routers. This parameter need not be defined
+explicitly as it can be implicitly derived from the PORT_LABEL_MIN
+parameters for the associated interfaces.
+
+PORT_LABEL_MAX - This parameter contains the maximum sensitivity label for
+all datagrams that may exit a particular network interface port. All
+outgoing datagrams that have a label greater than this maximum MUST be
+rejected by the CIPSO system. The label within this parameter MUST be
+less than or equal to the label within the HOST_LABEL_MAX parameter. This
+parameter does not apply to CIPSO hosts that support only one network port.
+
+PORT_LABEL_MIN - This parameter contains the minimum sensitivity label for
+all datagrams that may exit a particular network interface port. All
+outgoing datagrams that have a label less than this minimum MUST be
+rejected by the CIPSO system. The label within this parameter MUST be
+greater than or equal to the label within the HOST_LABEL_MIN parameter.
+This parameter does not apply to CIPSO hosts that support only one network
+port.
+
+PORT_DOI - This parameter is used to assign a DOI identifier value to a
+particular network interface port. All CIPSO labels within datagrams
+going out this port MUST use the specified DOI identifier. All CIPSO
+hosts and gateways MUST support either this parameter, the NET_DOI
+parameter, or the HOST_DOI parameter.
+
+NET_DOI - This parameter is used to assign a DOI identifier value to a
+particular IP network address. All CIPSO labels within datagrams destined
+for the particular IP network MUST use the specified DOI identifier. All
+CIPSO hosts and gateways MUST support either this parameter, the PORT_DOI
+parameter, or the HOST_DOI parameter.
+
+HOST_DOI - This parameter is used to assign a DOI identifier value to a
+particular IP host address. All CIPSO labels within datagrams destined for
+the particular IP host will use the specified DOI identifier. All CIPSO
+hosts and gateways MUST support either this parameter, the PORT_DOI
+parameter, or the NET_DOI parameter.
+
+This list represents the minimal set of configuration parameters required
+to be compliant. Implementors are encouraged to add to this list to
+provide enhanced functionality and control. For example, many security
+policies may require both incoming and outgoing datagrams be checked against
+the port and host label ranges.
+
+
+4.1 Port Range Parameters
+
+The labels represented by the PORT_LABEL_MAX and PORT_LABEL_MIN parameters
+MAY be in CIPSO or local format. Some CIPSO systems, such as routers, may
+want to have the range parameters expressed in CIPSO format so that incoming
+labels do not have to be converted to a local format before being compared
+against the range. If multiple DOIs are supported by one of these CIPSO
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 8]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+systems then multiple port range parameters would be needed, one set for
+each DOI supported on a particular port.
+
+The port range will usually represent the total set of labels that may
+exist on the logical network accessed through the corresponding network
+interface. It may, however, represent a subset of these labels that are
+allowed to enter the CIPSO system.
+
+
+4.2 Single Label CIPSO Hosts
+
+CIPSO implementations that support only one label are not required to
+support the parameters described above. These limited implementations are
+only required to support a NET_LABEL parameter. This parameter contains
+the CIPSO label that may be inserted in datagrams that exit the host. In
+addition, the host MUST reject any incoming datagram that has a label which
+is not equivalent to the NET_LABEL parameter.
+
+
+5. Handling Procedures
+
+This section describes the processing requirements for incoming and
+outgoing IP datagrams. Just providing the correct CIPSO label format
+is not enough. Assumptions will be made by one system on how a
+receiving system will handle the CIPSO label. Wrong assumptions may
+lead to non-interoperability or even a security incident. The
+requirements described below represent the minimal set needed for
+interoperability and that provide users some level of confidence.
+Many other requirements could be added to increase user confidence,
+however at the risk of restricting creativity and limiting vendor
+participation.
+
+
+5.1 Input Procedures
+
+All datagrams received through a network port MUST have a security label
+associated with them, either contained in the datagram or assigned to the
+receiving port. Without this label the host, gateway, or router will not
+have the information it needs to make security decisions. This security
+label will be obtained from the CIPSO if the option is present in the
+datagram. See section 4.1.2 for handling procedures for unlabeled
+datagrams. This label will be compared against the PORT (if appropriate)
+and HOST configuration parameters defined in section 3.
+
+If any field within the CIPSO option, 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.
+
+If the contents of the CIPSO 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
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 9]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+"communication with destination host administratively prohibited"
+(code 10). The value of the code field used is dependent upon 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 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).
+
+
+5.1.1 Unrecognized tag types
+
+The default condition for any CIPSO implementation is that an
+unrecognized tag type MUST be treated as a "parameter problem" and
+handled as described in section 4.1. A CIPSO implementation MAY allow
+the system administrator to identify tag types that may safely be
+ignored. This capability is an allowable enhancement, not a
+requirement.
+
+
+5.1.2 Unlabeled Packets
+
+A network port may be configured to not require a CIPSO label for all
+incoming datagrams. For this configuration a CIPSO label must be
+assigned to that network port and associated with all unlabeled IP
+datagrams. This capability might be used for single level networks or
+networks that have CIPSO and non-CIPSO hosts and the non-CIPSO hosts
+all operate at the same label.
+
+If a CIPSO option is required and none is found, the datagram is
+discarded and an ICMP "parameter problem" (type 12) is generated and
+returned to the originator of the datagram. The code field of the ICMP
+is set to "option missing" (code 1) and the ICMP pointer is set to 134
+(the value of the option type for the missing CIPSO option).
+
+
+5.2 Output Procedures
+
+A CIPSO option MUST appear only once in a datagram. Only one tag type
+from the MAC Sensitivity class MAY be included in a CIPSO option. Given
+the current set of defined tag types, this means that CIPSO labels at
+first will contain only one tag.
+
+All datagrams leaving a CIPSO system MUST meet the following condition:
+
+ PORT_LABEL_MIN <= CIPSO label <= PORT_LABEL_MAX
+
+If this condition is not satisfied the datagram MUST be discarded.
+If the CIPSO system only supports one port, the HOST_LABEL_MIN and the
+HOST_LABEL_MAX parameters MAY be substituted for the PORT parameters in
+the above condition.
+
+The DOI identifier to be used for all outgoing datagrams is configured by
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 10]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+the administrator. If port level DOI identifier assignment is used, then
+the PORT_DOI configuration parameter MUST contain the DOI identifier to
+use. If network level DOI assignment is used, then the NET_DOI parameter
+MUST contain the DOI identifier to use. And if host level DOI assignment
+is employed, then the HOST_DOI parameter MUST contain the DOI identifier
+to use. A CIPSO implementation need only support one level of DOI
+assignment.
+
+
+5.3 DOI Processing Requirements
+
+A CIPSO implementation MUST support at least one DOI and SHOULD support
+multiple DOIs. System and network administrators are cautioned to
+ensure that at least one DOI is common within an IP network to allow for
+broadcasting of IP datagrams.
+
+CIPSO gateways MUST be capable of translating a CIPSO option from one
+DOI to another when forwarding datagrams between networks. For
+efficiency purposes this capability is only a desired feature for CIPSO
+routers.
+
+
+5.4 Label of ICMP Messages
+
+The CIPSO label to be used on all outgoing ICMP messages MUST be equivalent
+to the label of the datagram that caused the ICMP message. If the ICMP was
+generated due to a problem associated with the original CIPSO label then the
+following responses are allowed:
+
+ a. Use the CIPSO label of the original IP datagram
+ b. Drop the original datagram with no return message generated
+
+In most cases these options will have the same effect. If you can not
+interpret the label or if it is outside the label range of your host or
+interface then an ICMP message with the same label will probably not be
+able to exit the system.
+
+
+6. Assignment of DOI Identifier Numbers =
+
+Requests for assignment of a DOI identifier number should be addressed to
+the Internet Assigned Numbers Authority (IANA).
+
+
+7. Acknowledgements
+
+Much of the material in this RFC is based on (and copied from) work
+done by Gary Winiger of Sun Microsystems and published as Commercial
+IP Security Option at the INTEROP 89, Commercial IPSO Workshop.
+
+
+8. Author's Address
+
+To submit mail for distribution to members of the IETF CIPSO Working
+Group, send mail to: cipso wdl1 wdl loral com
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 11]
+
+
+
+CIPSO INTERNET DRAFT 16 July, 1992
+
+
+
+
+To be added to or deleted from this distribution, send mail to:
+cipso-request wdl1 wdl loral com
+
+
+9. References
+
+RFC 1038, "Draft Revised IP Security Option", M. St. Johns, IETF, January
+1988.
+
+RFC 1108, "U.S. Department of Defense Security Options
+for the Internet Protocol", Stephen Kent, IAB, 1 March, 1991.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Internet Draft, Expires 15 Jan 93 [PAGE 12]
+
+
+
diff -purN linux-2.6.16.i686/Documentation/netlabel/introduction.txt linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/introduction.txt
--- linux-2.6.16.i686/Documentation/netlabel/introduction.txt 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/introduction.txt 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,44 @@
+NetLabel Introduction
+==============================================================================
+Paul Moore, paul moore hp com
+
+May 17, 2006
+
+ * Overview
+
+NetLabel is a mechanism which can be used by kernel security modules to attach
+security attributes to outgoing network packets and read security attributes
+from incoming network packets. It is composed of three main components, the
+protocol engines, the communication layer, and the kernel security module API.
+
+ * Protocol Engines
+
+The protocol engines are responsible for both applying and retrieving the
+network packet's security attributes. If any translation between the network
+security attributes and those on the host are required then the protocol
+engine will handle those tasks as well. Other kernel subsystems should
+refrain from calling the protocol engines directly, instead they should use
+the NetLabel kernel security module API described below.
+
+Detailed information about each NetLabel protocol engine can be found in this
+directory, consult '00-INDEX' for filenames.
+
+ * Communication Layer
+
+The communication layer exists to allow NetLabel configuration and monitoring
+from user space. The NetLabel communication layer uses a message based
+protocol built on top of the NETLINK transport mechanism. The exact formatting
+of these NetLabel messages can be found in the the 'net/netlabel/' directory as
+comments in the header files.
+
+ * Security Module API
+
+The purpose of the NetLabel security module API is to provide a protocol
+independent interface to the underlying NetLabel protocol engines. In addition
+to protocol independence, the security module API is designed to be completely
+LSM independent which should allow multiple LSMs to leverage the same code
+base.
+
+Detailed information about the NetLabel security module API can be found in the
+'include/net/netlabel.h' header file as well as the 'lsm_interface.txt' file
+found in this directory.
diff -purN linux-2.6.16.i686/Documentation/netlabel/lsm_interface.txt linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/lsm_interface.txt
--- linux-2.6.16.i686/Documentation/netlabel/lsm_interface.txt 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/Documentation/netlabel/lsm_interface.txt 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,47 @@
+NetLabel Linux Security Module Interface
+==============================================================================
+Paul Moore, paul moore hp com
+
+May 17, 2006
+
+ * Overview
+
+NetLabel is a mechanism which can set and retrieve security attributes from
+network packets. It is intended to be used by LSM developers who want to make
+use of a common code base for several different packet labeling protocols.
+The NetLabel security module API is defined in 'include/net/netlabel.h' but a
+brief overview is given below.
+
+ * NetLabel Security Attributes
+
+Since NetLabel supports multiple different packet labeling protocols and LSMs
+it uses the concept of security attributes to refer to the packet's security
+labels. The NetLabel security attributes are defined by the
+'netlbl_lsm_secattr' structure in the NetLabel header file. Internally the
+NetLabel subsystem converts the security attributes to and from the correct
+low-level packet label depending on the NetLabel build time and run time
+configuration. It is up to the LSM developer to translate the NetLabel
+security attributes into whatever security identifiers are in use for their
+particular LSM.
+
+ * NetLabel LSM Protocol Operations
+
+These are the functions which allow the LSM developer to manipulate the labels
+on outgoing packets as well as read the labels on incoming packets. Functions
+exist to operate both on sockets as well as the sk_buffs directly. These high
+level functions are translated into low level protocol operations based on how
+the administrator has configured the NetLabel subsystem.
+
+ * NetLabel Label Mapping Cache Operations
+
+Depending on the exact configuration, translation between the network packet
+label and the internal LSM security identifier can be time consuming. The
+NetLabel label mapping cache is a caching mechanism which can be used to
+sidestep much of this overhead once a mapping has been established. Once the
+LSM has received a packet, used NetLabel to decode it's security attributes,
+and translated the security attributes into a LSM internal identifier the LSM
+can use the NetLabel caching functions to associate the LSM internal
+identifier with the network packet's label. This means that in the future
+when a incoming packet matches a cached value not only are the internal
+NetLabel translation mechanisms bypassed but the LSM translation mechanisms are
+bypassed as well which should result in a significant reduction in overhead.
diff -purN linux-2.6.16.i686/include/linux/ip.h linux-2.6.16.i686-netlabel_06132006/include/linux/ip.h
--- linux-2.6.16.i686/include/linux/ip.h 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/include/linux/ip.h 2006-06-13 11:19:59.000000000 -0400
@@ -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)
diff -purN linux-2.6.16.i686/include/linux/netlink.h linux-2.6.16.i686-netlabel_06132006/include/linux/netlink.h
--- linux-2.6.16.i686/include/linux/netlink.h 2006-06-13 10:46:57.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/include/linux/netlink.h 2006-06-13 11:19:59.000000000 -0400
@@ -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
diff -purN linux-2.6.16.i686/include/net/cipso_ipv4.h linux-2.6.16.i686-netlabel_06132006/include/net/cipso_ipv4.h
--- linux-2.6.16.i686/include/net/cipso_ipv4.h 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/include/net/cipso_ipv4.h 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,159 @@
+/*
+ * 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
+ */
+
+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);
+
+/*
+ * Label Mapping Cache Functions
+ */
+
+int cipso_v4_cache_invalidate(void);
+int cipso_v4_cache_add(const struct sk_buff *skb,
+ const struct netlbl_lsm_secattr *secattr);
+
+/*
+ * Protocol Handling Functions
+ */
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+int cipso_v4_validate(unsigned char **option);
+#else
+static inline int cipso_v4_validate(unsigned char **option)
+{
+ return *option;
+}
+#endif /* CONFIG_NETLABEL_CIPSOV4 */
+
+int cipso_v4_error(struct sk_buff *skb,
+ const int error,
+ const u32 gateway);
+int cipso_v4_socket_setattr(const struct socket *sock,
+ const struct cipso_v4_doi *doi_def,
+ const struct netlbl_lsm_secattr *secattr);
+int cipso_v4_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);
+
+#endif /* _CIPSO_IPV4_H */
diff -purN linux-2.6.16.i686/include/net/inet_sock.h linux-2.6.16.i686-netlabel_06132006/include/net/inet_sock.h
--- linux-2.6.16.i686/include/net/inet_sock.h 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/include/net/inet_sock.h 2006-06-13 11:19:59.000000000 -0400
@@ -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];
};
diff -purN linux-2.6.16.i686/include/net/netlabel.h linux-2.6.16.i686-netlabel_06132006/include/net/netlabel.h
--- linux-2.6.16.i686/include/net/netlabel.h 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/include/net/netlabel.h 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,354 @@
+/*
+ * 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 */
+struct netlbl_lsm_secattr *netlbl_secattr_alloc(const int flags);
+void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr);
+int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr);
+void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr);
+
+/* LSM protocol operations */
+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);
+
+/* LSM label mapping cache operations */
+int netlbl_cache_invalidate(void);
+int netlbl_cache_add(const struct sk_buff *skb,
+ const struct netlbl_lsm_secattr *secattr);
+
+#endif /* _NETLABEL_H */
diff -purN linux-2.6.16.i686/net/ipv4/ah4.c linux-2.6.16.i686-netlabel_06132006/net/ipv4/ah4.c
--- linux-2.6.16.i686/net/ipv4/ah4.c 2006-06-13 10:46:58.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/net/ipv4/ah4.c 2006-06-13 11:19:59.000000000 -0400
@@ -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;
diff -purN linux-2.6.16.i686/net/ipv4/cipso_ipv4.c linux-2.6.16.i686-netlabel_06132006/net/ipv4/cipso_ipv4.c
--- linux-2.6.16.i686/net/ipv4/cipso_ipv4.c 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/ipv4/cipso_ipv4.c 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,1749 @@
+/*
+ * 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 <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 inline int cipso_v4_bitmap_walk(const unsigned char *bitmap,
+ const u32 bitmap_len,
+ const u32 offset,
+ const u8 state)
+{
+ u32 byte_spot;
+ u32 byte_spot_rem;
+ unsigned char bitmask;
+
+ /* gcc always rounds to zero when doing integer division */
+ byte_spot = offset / 8;
+ byte_spot_rem = offset % 8;
+ bitmask = 0x80 >> byte_spot_rem;
+
+ /* XXX - probably should use include/asm/bitops.h if we can */
+ while ((byte_spot * 8 + byte_spot_rem) < bitmap_len) {
+ if ((state && (bitmap[byte_spot] & bitmask) == bitmask) ||
+ (state == 0 && (bitmap[byte_spot] & bitmask) == 0))
+ return byte_spot * 8 + byte_spot_rem;
+
+ if (++byte_spot_rem == 8) {
+ byte_spot++;
+ byte_spot_rem = 0;
+ bitmask = 0x80;
+ } else
+ bitmask = bitmask >> 1;
+ }
+
+ 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 inline int 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;
+
+ return 0;
+}
+
+/**
+ * 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 inline void cipso_v4_cache_entry_free(
+ struct cipso_v4_map_cache_entry *entry)
+{
+ BUG_ON(entry == NULL);
+
+ 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 inline u32 cipso_v4_map_cache_hash(const unsigned char *key,
+ const u32 key_len)
+{
+ unsigned char *p;
+ unsigned char *keyp = (char *)key;
+ u32 val = 0;
+
+ /* This is taken (with slight modification) from
+ security/selinux/ss/symtab.c:symhash(), we probably need to find
+ a better hash for dealing with bitmaps */
+
+ for (p = keyp; (p - keyp) < key_len; p++)
+ val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ (*p);
+ return val;
+}
+
+/*
+ * 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;
+
+ BUG_ON(cipso_v4_cache != NULL);
+
+ 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;
+
+ BUG_ON(cipso_v4_cache == NULL);
+
+ 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.
+ *
+ */
+int cipso_v4_cache_invalidate(void)
+{
+ struct cipso_v4_map_cache_entry *entry, *tmp_entry;
+ u32 iter;
+
+ if (!CIPSO_V4_CACHE_ENABLED)
+ return 0;
+
+ 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 0;
+}
+
+/**
+ * cipso_v4_cache_check - Check the CIPSO cache for a label mapping
+ * @skb: the packet
+ * @secattr: the security attribute struct to use
+ *
+ * Description:
+ * This function checks the cache to see if a label mapping already exists for
+ * the CIPSO tags in the packet. 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 struct sk_buff *skb,
+ struct netlbl_lsm_secattr *secattr)
+{
+ u32 bkt;
+ struct cipso_v4_map_cache_entry *entry;
+ struct cipso_v4_map_cache_entry *prev_entry = NULL;
+ unsigned char *cipso_ptr;
+ u32 cipso_ptr_len;
+ u32 hash;
+
+ if (!CIPSO_V4_CACHE_ENABLED)
+ return -ENOENT;
+
+ cipso_ptr = CIPSO_V4_OPTPTR(skb);
+ cipso_ptr_len = cipso_ptr[1];
+ hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_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 == cipso_ptr_len &&
+ memcmp(entry->key, cipso_ptr, cipso_ptr_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;
+
+ BUG_ON(skb == NULL || secattr == NULL);
+
+ if (!CIPSO_V4_CACHE_ENABLED)
+ return 0;
+
+ cipso_ptr = CIPSO_V4_OPTPTR(skb);
+ BUG_ON(cipso_ptr == NULL);
+ 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;
+ }
+
+ entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
+ memcpy(entry->key, cipso_ptr, cipso_ptr_len);
+ entry->key_len = 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);
+ }
+ spin_unlock(&cipso_v4_cache[bkt].lock);
+
+ if (old_entry)
+ cipso_v4_cache_entry_free(old_entry);
+
+ 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 (doi == CIPSO_V4_DOI_UNKNOWN || 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)
+{
+ struct cipso_v4_doi *doi_def;
+
+ if (doi == CIPSO_V4_DOI_UNKNOWN)
+ return NULL;
+
+ doi_def = cipso_v4_doi_search(doi);
+
+ return doi_def;
+}
+
+/**
+ * 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_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;
+ 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;
+ 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_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;
+ 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;
+ }
+ 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;
+
+ BUG_ON(doi_def == NULL);
+
+ new_dom = kmalloc(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;
+ }
+ } else
+ new_dom->domain = NULL;
+ 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 && 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;
+
+ BUG_ON(doi_def == NULL);
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(iter, &doi_def->dom_list, list)
+ if (iter->valid &&
+ ((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 inline int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def,
+ const u8 level)
+{
+ BUG_ON(doi_def == NULL);
+
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_STD:
+ if (doi_def->map.std->lvl.cipso[level] < CIPSO_V4_INV_LVL)
+ return 0;
+ break;
+ case CIPSO_V4_MAP_PASS:
+ 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 inline int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
+ const u32 host_lvl,
+ u32 *net_lvl)
+{
+ BUG_ON(doi_def == NULL || net_lvl == NULL);
+
+ switch (doi_def->type) {
+ 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;
+ case CIPSO_V4_MAP_PASS:
+ *net_lvl = 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 inline int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
+ const u32 net_lvl,
+ u32 *host_lvl)
+{
+ BUG_ON(doi_def == NULL || host_lvl == NULL);
+
+ switch (doi_def->type) {
+ 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;
+ case CIPSO_V4_MAP_PASS:
+ *host_lvl = 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 inline int cipso_v4_map_cat_rbm_valid(
+ const struct cipso_v4_doi *doi_def,
+ const unsigned char *bitmap,
+ const u32 bitmap_len)
+{
+ u32 offset = 0;
+ int cat;
+ u32 bitmap_len_bits = bitmap_len * 8;
+
+ BUG_ON(doi_def == NULL || bitmap_len_bits >= CIPSO_V4_MAX_REM_CATS);
+
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_STD:
+ do {
+ cat = cipso_v4_bitmap_walk(bitmap,
+ bitmap_len_bits,
+ offset,
+ 1);
+ if (cat >= 0 &&
+ doi_def->map.std->cat.cipso[cat] >=
+ CIPSO_V4_INV_CAT)
+ return -EFAULT;
+ offset = cat + 1;
+ } while (cat >= 0 && offset <= bitmap_len_bits);
+
+ if (cat == -1)
+ return 0;
+ break;
+ case CIPSO_V4_MAP_PASS:
+ 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 inline 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 ret_val;
+ int offset = 0;
+ int host_spot;
+ u32 net_spot;
+ u32 net_spot_max = 0;
+ u32 host_clen_bits = host_cat_len * 8;
+
+ BUG_ON(doi_def == NULL || host_cat == NULL || net_cat == NULL ||
+ host_cat_len == 0);
+
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_STD:
+ do {
+ host_spot = cipso_v4_bitmap_walk(host_cat,
+ host_clen_bits,
+ offset,
+ 1);
+ offset = host_spot + 1;
+ if (host_spot >= 0 &&
+ host_spot < doi_def->map.std->cat.local_size) {
+ net_spot =
+ doi_def->map.std->cat.local[host_spot];
+ if (net_spot / 8 >= net_cat_len)
+ return -ENOSPC;
+ ret_val = cipso_v4_bitmap_setbit(net_cat,
+ net_spot,
+ 1);
+ if (ret_val != 0)
+ return ret_val;
+ if (net_spot > net_spot_max)
+ net_spot_max = net_spot;
+ }
+ } while (host_spot >= 0 && offset <= host_clen_bits);
+
+ if (host_spot == -2)
+ return -EFAULT;
+
+ if (++net_spot_max % 8)
+ return net_spot_max / 8 + 1;
+ return net_spot_max / 8;
+ break;
+ 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;
+ break;
+ }
+
+ 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 inline 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)
+{
+ int ret_val;
+ u32 offset = 0;
+ u32 host_spot;
+ u32 host_spot_max = 0;
+ int net_spot;
+ u32 net_clen_bits = net_cat_len * 8;
+
+ BUG_ON(doi_def == NULL || host_cat == NULL || net_cat == NULL ||
+ net_cat_len == 0);
+
+ switch (doi_def->type) {
+ case CIPSO_V4_MAP_STD:
+ do {
+ net_spot = cipso_v4_bitmap_walk(net_cat,
+ net_clen_bits,
+ offset,
+ 1);
+ offset = net_spot + 1;
+ if (net_spot >= 0 &&
+ net_spot < doi_def->map.std->cat.cipso_size) {
+ host_spot =
+ doi_def->map.std->cat.cipso[net_spot];
+ if (host_spot / 8 >= host_cat_len)
+ return -ENOSPC;
+ ret_val = cipso_v4_bitmap_setbit(host_cat,
+ host_spot,
+ 1);
+ if (ret_val != 0)
+ return ret_val;
+ if (host_spot > host_spot_max)
+ host_spot_max = host_spot;
+ }
+ } while (net_spot >= 0 && offset <= net_clen_bits);
+
+ if (net_spot == -2)
+ return -EFAULT;
+
+ if (++host_spot_max % 8)
+ return host_spot_max / 8 + 1;
+ return host_spot_max / 8;
+ break;
+ 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;
+ break;
+ }
+
+ 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 inline 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 inline 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;
+ int cat_len = 0;
+ u32 level;
+
+ *buffer = NULL;
+ *buffer_len = 0;
+
+ buf_len = 4;
+ if (secattr->set_mls_cat)
+ buf_len += CIPSO_V4_TAG1_CAT_LEN;
+
+ buf = kzalloc(CIPSO_V4_HDR_LEN + buf_len, GFP_ATOMIC);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ if (secattr->set_mls_cat) {
+ cat_len = 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 (cat_len < 0) {
+ ret_val = cat_len;
+ goto gentag_failure;
+ }
+ /* PM - make this a sysctl adjustable value? */
+#if 0
+ /* XXX - this will send packets using the "optimized" format
+ when possibile as specified in section 3.4.2.6 of the
+ CIPSO draft */
+ if (cat_len > 0 && cat_len < 10)
+ cat_len = 10;
+#endif
+ }
+ buf_len = 4 + cat_len;
+
+ 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 + 0] = 0x01;
+ buf[CIPSO_V4_HDR_LEN + 1] = buf_len;
+ buf[CIPSO_V4_HDR_LEN + 3] = level;
+
+ *buffer = buf;
+ *buffer_len = CIPSO_V4_HDR_LEN + 4 + cat_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 inline 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_STD:
+ secattr->mls_cat_len =
+ doi_def->map.std->cat.local_size;
+ break;
+ case CIPSO_V4_MAP_PASS:
+ secattr->mls_cat_len = tag_len - 4;
+ 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 < 9) {
+ 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 (tag[2] != 0) {
+ err_offset = opt_iter + 2;
+ goto validate_return;
+ }
+ /* PM - how detailed a check do we need to make, are
+ these last two checks (level and category)
+ neccessary at this level? would our decoding
+ at the upper levels fail if we don't check the
+ values here? need input from interop testing */
+ 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)
+{
+ BUG_ON(skb == NULL);
+
+ 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_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;
+ struct ip_options *opt = NULL;
+ struct sock *sk;
+ struct inet_sock *sk_inet;
+ struct inet_connection_sock *sk_conn;
+
+ BUG_ON(sock == NULL || doi_def == NULL || secattr == NULL);
+
+ /* 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 is
+ technically against the IETF draft but since we only recognize
+ the MAC tags right now it's okay */
+ iter = 0;
+ do {
+ switch (doi_def->tags[iter]) {
+ case CIPSO_V4_TAG_RBITMAP:
+ 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 (buf == NULL &&
+ iter < CIPSO_V4_TAG_MAXCNT &&
+ doi_def->tags[iter] != CIPSO_V4_TAG_INVALID);
+
+ if (buf == NULL)
+ goto socket_setattr_failure;
+
+ ret_val = ip_options_get(&opt, buf, buf_len);
+ if (ret_val != 0)
+ goto socket_setattr_failure;
+#if 1
+ /* PM - ip_options_get() sets this, should we clear it? i say lets
+ try it as it just makes sense and i'm not sure anyone pays attention
+ to this flag anyway, if it causes problems we can always remove it */
+ opt->is_setbyuser = 0;
+#endif
+ 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_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;
+ struct sock *sk;
+ struct inet_sock *sk_inet;
+ unsigned char *cipso_ptr;
+ u32 doi;
+ struct cipso_v4_doi *doi_def;
+
+ BUG_ON(sock == NULL || secattr == NULL);
+
+ sk = sock->sk;
+ lock_sock(sk);
+ sk_inet = inet_sk(sk);
+ if (sk_inet->opt == NULL || sk_inet->opt->cipso == 0) {
+ release_sock(sk);
+ return -ENOMSG;
+ }
+ cipso_ptr = sk_inet->opt->__data + sk_inet->opt->cipso -
+ sizeof(struct iphdr);
+ doi = ntohl(*(u32 *) & cipso_ptr[2]);
+ rcu_read_lock();
+ doi_def = cipso_v4_doi_getdef(doi);
+ if (doi_def == NULL) {
+ rcu_read_unlock();
+ release_sock(sk);
+ return -ENOMSG;
+ }
+ /* 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;
+ default:
+ ret_val = -ENOMSG;
+ }
+ rcu_read_unlock();
+ 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;
+ unsigned char *cipso_ptr;
+ u32 doi;
+ struct cipso_v4_doi *doi_def;
+
+ BUG_ON(skb == NULL || secattr == NULL);
+
+ if (cipso_v4_cache_check(skb, secattr) == 0)
+ return 0;
+
+ cipso_ptr = CIPSO_V4_OPTPTR(skb);
+ doi = ntohl(*(u32 *) & cipso_ptr[2]);
+ rcu_read_lock();
+ doi_def = cipso_v4_doi_getdef(doi);
+ if (doi_def == NULL) {
+ rcu_read_unlock();
+ return -ENOMSG;
+ }
+ /* 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;
+ default:
+ ret_val = -ENOMSG;
+ }
+ 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);
+
diff -purN linux-2.6.16.i686/net/ipv4/ip_options.c linux-2.6.16.i686-netlabel_06132006/net/ipv4/ip_options.c
--- linux-2.6.16.i686/net/ipv4/ip_options.c 2006-06-13 10:46:58.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/net/ipv4/ip_options.c 2006-06-13 11:19:59.000000000 -0400
@@ -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:
diff -purN linux-2.6.16.i686/net/ipv4/Makefile linux-2.6.16.i686-netlabel_06132006/net/ipv4/Makefile
--- linux-2.6.16.i686/net/ipv4/Makefile 2006-06-13 10:46:58.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/net/ipv4/Makefile 2006-06-13 11:19:59.000000000 -0400
@@ -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
diff -purN linux-2.6.16.i686/net/Kconfig linux-2.6.16.i686-netlabel_06132006/net/Kconfig
--- linux-2.6.16.i686/net/Kconfig 2006-06-13 10:47:06.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/net/Kconfig 2006-06-13 11:19:59.000000000 -0400
@@ -228,6 +228,8 @@ source "net/tux/Kconfig"
config WIRELESS_EXT
bool
+source "net/netlabel/Kconfig"
+
endif # if NET
endmenu # Networking
diff -purN linux-2.6.16.i686/net/Makefile linux-2.6.16.i686-netlabel_06132006/net/Makefile
--- linux-2.6.16.i686/net/Makefile 2006-06-13 10:47:06.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/net/Makefile 2006-06-13 11:19:59.000000000 -0400
@@ -47,6 +47,7 @@ obj-$(CONFIG_IP_DCCP) += dccp/
obj-$(CONFIG_IP_SCTP) += sctp/
obj-$(CONFIG_IEEE80211) += ieee80211/
obj-$(CONFIG_TIPC) += tipc/
+obj-$(CONFIG_NETLABEL) += netlabel/
ifeq ($(CONFIG_NET),y)
obj-$(CONFIG_SYSCTL) += sysctl_net.o
diff -purN linux-2.6.16.i686/net/netlabel/Kconfig linux-2.6.16.i686-netlabel_06132006/net/netlabel/Kconfig
--- linux-2.6.16.i686/net/netlabel/Kconfig 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/Kconfig 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,47 @@
+#
+# NetLabel configuration
+#
+
+config NETLABEL
+ bool "NetLabel subsystem support"
+ depends on NET && SECURITY
+ default n
+ ---help---
+ NetLabel provides support for network packet labeling protocols. For
+ more information see Documentation/netlabel.
+
+ If you are unsure, say N.
+
+config NETLABEL_CIPSOV4
+ bool "CIPSO for IPv4"
+ depends on NETLABEL
+ default n
+ ---help---
+ The Commercial IP Security Option (CIPSO) is commonly used in
+ trusted multi-level security networks. This implementation is based
+ on the IETF draft draft-ietf-cipso-ipsecurity-01.txt and FIPS-188.
+
+ If you are unsure say N.
+
+config NETLABEL_UNLABELED
+ bool "Unlabeled packets"
+ depends on NETLABEL
+ default y
+ ---help---
+ This adds support for sending and receiving unlabeled packets through
+ the NetLabel system.
+
+ If you are unsure say Y.
+
+config NETLABEL_UNLABELED_DEFAULT
+ bool "Enable unlabeled traffic by default"
+ depends on NETLABEL_UNLABELED
+ default y
+ ---help---
+ Enabling this option allows unlabeled (i.e. normal) network traffic
+ on the system without any user configuration at bootup. Disabling
+ this option means the user must configure the NetLabel subsystem
+ before any type of network traffic can be sent or received on the
+ system.
+
+ If you are unsure say Y.
diff -purN linux-2.6.16.i686/net/netlabel/Makefile linux-2.6.16.i686-netlabel_06132006/net/netlabel/Makefile
--- linux-2.6.16.i686/net/netlabel/Makefile 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/Makefile 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,15 @@
+#
+# Makefile for the NetLabel subsystem.
+#
+# Feb 9, 2006, Paul Moore <paul moore hp com>
+#
+
+# base objects
+obj-y := netlabel_user.o netlabel_kapi.o netlabel_domainhash.o
+
+# management objects
+obj-y += netlabel_mgmt.o
+
+# protocol modules
+obj-$(CONFIG_NETLABEL_UNLABELED) += netlabel_unlabeled.o
+obj-$(CONFIG_NETLABEL_CIPSOV4) += netlabel_cipso_v4.o
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_cipso_v4.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_cipso_v4.c
--- linux-2.6.16.i686/net/netlabel/netlabel_cipso_v4.c 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_cipso_v4.c 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,580 @@
+/*
+ * 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"
+
+/* PM - for debugging only, remove before release */
+#define NETLBL_PRINT(msg) printk msg
+
+/*
+ * 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 inline 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 inline 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 inline 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 inline 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)
+{
+ 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:
+ netlbl_cipsov4_add(skb,
+ nl_cv4_hdr->doi,
+ netlbl_cipsov4_payload_data(skb));
+ break;
+ case NL_CV4_REMOVE:
+ 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;
+ }
+}
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_cipso_v4.h linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_cipso_v4.h
--- linux-2.6.16.i686/net/netlabel/netlabel_cipso_v4.h 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_cipso_v4.h 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,201 @@
+/*
+ * NetLabel CIPSO/IPv4 Support
+ *
+ * This file defines the CIPSO/IPv4 functions for the NetLabel system. The
+ * NetLabel system manages static and dynamic label mappings for network
+ * protocols such as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_CIPSO_V4
+#define _NETLABEL_CIPSO_V4
+
+#include <net/netlabel.h>
+
+/*
+ * The following NetLabel payloads are supported by the CIPSO subsystem, all
+ * of which are preceeded by the nlmsghdr struct.
+ *
+ * o ACK:
+ * Sent by the kernel in response to an applications message, applications
+ * should never send this message.
+ *
+ * +----------------------+-----------------------+
+ * | seq number (32 bits) | return code (32 bits) |
+ * +----------------------+-----------------------+
+ *
+ * seq number: the sequence number of the original message, taken from the
+ * nlmsghdr structure
+ * return code: return value, based on errno values
+ *
+ * o ADD:
+ * Sent by an application to add a new DOI mapping table, after completion
+ * of the task the kernel should ACK this message.
+ *
+ * +--------------------+---------------------+
+ * | map type (32 bits) | tag count (32 bits) | ...
+ * +--------------------+---------------------+
+ *
+ * +-----------------+
+ * | tag #X (8 bits) | ... repeated
+ * +-----------------+
+ *
+ * +-------------- ---- --- -- -
+ * | mapping data
+ * +-------------- ---- --- -- -
+ *
+ * map type: the mapping table type (defined in the cipso_ipv4.h header
+ * as CIPSO_V4_MAP_*)
+ * tag count: the number of tags, must be greater than zero
+ * tag: the CIPSO tag for the DOI, tags listed first are given
+ * higher priorirty when sending packets
+ * mapping data: specific to the map type (see below)
+ *
+ * CIPSO_V4_MAP_STD
+ *
+ * +------------------+-----------------------+-----------------------+
+ * | levels (32 bits) | max l level (32 bits) | max r level (32 bits) | ...
+ * +------------------+-----------------------+-----------------------+
+ *
+ * +----------------------+---------------------+---------------------+
+ * | categories (32 bits) | max l cat (32 bits) | max r cat (32 bits) | ...
+ * +----------------------+---------------------+---------------------+
+ *
+ * +--------------------------+--------------------------+
+ * | local level #X (32 bits) | CIPSO level #X (32 bits) | ... repeated
+ * +--------------------------+--------------------------+
+ *
+ * +-----------------------------+-----------------------------+
+ * | local category #X (32 bits) | CIPSO category #X (32 bits) | ... repeated
+ * +-----------------------------+-----------------------------+
+ *
+ * levels: the number of level mappings
+ * max l level: the highest local level
+ * max r level: the highest remote/CIPSO level
+ * categories: the number of category mappings
+ * max l cat: the highest local category
+ * max r cat: the highest remote/CIPSO category
+ * local level: the local part of a level mapping
+ * CIPSO level: the remote/CIPSO part of a level mapping
+ * local category: the local part of a category mapping
+ * CIPSO category: the remote/CIPSO part of a category mapping
+ *
+ * CIPSO_V4_MAP_PASS
+ *
+ * No mapping data is needed for this map type.
+ *
+ * o REMOVE:
+ * Sent by an application to remove a specific DOI mapping table from the
+ * CIPSO V4 system. This message does not contain a payload. The kernel
+ * should ACK this message.
+ *
+ * o LIST:
+ * This message can be sent either from an application or by the kernel in
+ * response to an application generated LIST message. When sent by an
+ * application there is no payload. If the application sets the DOI field
+ * to zero in the CIPSO V4 message header then the kernel should respond
+ * with a list of valid DOIs. If the application sets the DOI field equal to
+ * a non-zero value then the kernel should respond with the matching mapping
+ * table. In the case of an error the kernel should respond with an ACK
+ * message.
+ *
+ * DOI Listing (DOI == 0)
+ *
+ * +---------------------+------------------+-----------------------+
+ * | DOI count (32 bits) | DOI #X (32 bits) | map type #X (32 bits) | ...
+ * +---------------------+------------------+-----------------------+
+ *
+ * DOI count: the number of DOIs
+ * DOI: the DOI value
+ * map type: the DOI mapping table type (defined in the cipso_ipv4.h
+ * header as CIPSO_V4_MAP_*)
+ *
+ * DOI Mapping Table (DOI != 0)
+ *
+ * +--------------------+
+ * | map type (32 bits) | ...
+ * +--------------------+
+ *
+ * map type: the DOI mapping table type (defined in the cipso_ipv4.h
+ * header as CIPSO_V4_MAP_*)
+ *
+ * (map type == CIPSO_V4_MAP_STD)
+ *
+ * +----------------+------------------+----------------------+
+ * | tags (32 bits) | levels (32 bits) | categories (32 bits) | ...
+ * +----------------+------------------+----------------------+
+ *
+ * +-----------------+
+ * | tag #X (8 bits) | ... repeated
+ * +-----------------+
+ *
+ * +--------------------------+--------------------------+
+ * | local level #X (32 bits) | CIPSO level #X (32 bits) | ... repeated
+ * +--------------------------+--------------------------+
+ *
+ * +-----------------------------+-----------------------------+
+ * | local category #X (32 bits) | CIPSO category #X (32 bits) | ... repeated
+ * +-----------------------------+-----------------------------+
+ *
+ * tags: the number of CIPSO tag types
+ * levels: the number of level mappings
+ * categories: the number of category mappings
+ * tag: the tag number, tags listed first are given higher
+ * priority when sending packets
+ * local level: the local part of a level mapping
+ * CIPSO level: the remote/CIPSO part of a level mapping
+ * local category: the local part of a category mapping
+ * CIPSO category: the remote/CIPSO part of a category mapping
+ *
+ * (map type == CIPSO_V4_MAP_PASS)
+ *
+ * +----------------+
+ * | tags (32 bits) | ...
+ * +----------------+
+ *
+ * +-----------------+
+ * | tag #X (8 bits) | ... repeated
+ * +-----------------+
+ *
+ * tags: the number of CIPSO tag types
+ * tag: the tag number, tags listed first are given higher
+ * priority when sending packets
+ *
+ */
+
+/* CIPSO V4 message header */
+struct netlbl_cipsov4_msghdr {
+ enum { NL_CV4_NOOP,
+ NL_CV4_ACK,
+ NL_CV4_ADD,
+ NL_CV4_REMOVE,
+ NL_CV4_LIST
+ } opcode;
+ u32 doi;
+};
+
+/* Process CIPSO V4 NetLabel messages */
+void netlbl_cipsov4_rcv(const struct sk_buff *skb, const unsigned char *msg);
+
+#endif
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_domainhash.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_domainhash.c
--- linux-2.6.16.i686/net/netlabel/netlabel_domainhash.c 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_domainhash.c 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,629 @@
+/*
+ * NetLabel Domain Hash Table
+ *
+ * This file manages the domain hash table that NetLabel uses to determine
+ * which network labeling protocol to use for a given domain. The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include <asm/bug.h>
+
+#include "netlabel_mgmt.h"
+#include "netlabel_domainhash.h"
+
+struct netlbl_domhsh_tbl {
+ struct list_head *tbl;
+ u32 size;
+};
+
+/* Domain hash table */
+/* XXX - updates should be so rare that having one spinlock for the entire
+ hash table should be okay */
+DEFINE_SPINLOCK(netlbl_domhsh_lock);
+static struct netlbl_domhsh_tbl *netlbl_domhsh = NULL;
+
+/* Default domain mapping */
+DEFINE_SPINLOCK(netlbl_domhsh_def_lock);
+static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
+
+/*
+ * Domain Hash Table Helper Functions
+ */
+
+/**
+ * netlbl_domhsh_free_entry - Frees a domain hash table entry
+ * @entry: the entry's RCU field
+ *
+ * Description:
+ * This function is designed to be used as a callback to the call_rcu()
+ * function so that the memory allocated to a hash table entry can be released
+ * safely.
+ *
+ */
+static void netlbl_domhsh_free_entry(struct rcu_head *entry)
+{
+ struct netlbl_dom_map *ptr;
+
+ ptr = container_of(entry, struct netlbl_dom_map, rcu);
+ if (ptr->domain)
+ kfree(ptr->domain);
+ kfree(ptr);
+}
+
+/**
+ * netlbl_domhsh_hash - Hashing function for the domain hash table
+ * @domain: the domain name to hash
+ *
+ * Description:
+ * This is the hashing function for the domain hash table, it returns the
+ * correct bucket number for the domain. The caller is responsibile for
+ * calling the rcu_read_[un]lock() functions.
+ *
+ */
+static inline u32 netlbl_domhsh_hash(const char *domain)
+{
+ char *p;
+ char *keyp = (char *)domain;
+ u32 size;
+ u32 val = 0;
+
+ /* This is taken (with slight modification) from
+ security/selinux/ss/symtab.c:symhash() */
+
+ size = strlen(keyp);
+ for (p = keyp; (p - keyp) < size; p++)
+ val = (val << 4 | (val >> (8 * sizeof(u32) - 4))) ^ (*p);
+ return val & (rcu_dereference(netlbl_domhsh)->size - 1);
+}
+
+/**
+ * netlbl_domhsh_search - Search for a domain entry
+ * @domain: the domain
+ * @def: return default if no match is found
+ *
+ * Description:
+ * Searches the domain hash table and returns a pointer to the hash table
+ * entry if found, otherwise NULL is returned. If @def is non-zero and a
+ * match is not found in the domain hash table the default mapping is returned
+ * if it exists. The caller is responsibile for the rcu hash table locks
+ * (i.e. the caller much call rcu_read_[un]lock()).
+ *
+ */
+static inline struct netlbl_dom_map *netlbl_domhsh_search(const char *domain,
+ const u32 def)
+{
+ u32 bkt;
+ struct netlbl_dom_map *iter;
+
+ if (domain != NULL) {
+ bkt = netlbl_domhsh_hash(domain);
+ list_for_each_entry_rcu(iter, &netlbl_domhsh->tbl[bkt], list)
+ if (iter->valid && strcmp(iter->domain, domain) == 0)
+ return iter;
+ }
+
+ if (def != 0) {
+ iter = rcu_dereference(netlbl_domhsh_def);
+ if (iter != NULL && iter->valid)
+ return iter;
+ }
+
+ return NULL;
+}
+
+/*
+ * Domain Hash Table Functions
+ */
+
+/**
+ * netlbl_domhsh_init - Init for the domain hash
+ * @size: the number of bits to use for the hash buckets
+ *
+ * Description:
+ * Initializes the domain hash table, should be called only by
+ * netlbl_user_init() during module load. Returns zero on success, non-zero
+ * values on error.
+ *
+ */
+int __init netlbl_domhsh_init(const u32 size)
+{
+ u32 iter;
+ struct netlbl_domhsh_tbl *hsh_tbl;
+
+ if (size <= 0)
+ return -EINVAL;
+
+ hsh_tbl = kmalloc(sizeof(*hsh_tbl), GFP_KERNEL);
+ if (hsh_tbl == NULL)
+ return -ENOMEM;
+ hsh_tbl->size = 1 << size;
+ hsh_tbl->tbl = kcalloc(hsh_tbl->size,
+ sizeof(struct list_head),
+ GFP_KERNEL);
+ if (hsh_tbl->tbl == NULL) {
+ kfree(hsh_tbl);
+ return -ENOMEM;
+ }
+ for (iter = 0; iter < hsh_tbl->size; iter++)
+ INIT_LIST_HEAD(&hsh_tbl->tbl[iter]);
+
+ rcu_read_lock();
+ spin_lock(&netlbl_domhsh_lock);
+ rcu_assign_pointer(netlbl_domhsh, hsh_tbl);
+ spin_unlock(&netlbl_domhsh_lock);
+ rcu_read_unlock();
+
+ return 0;
+}
+
+/**
+ * netlbl_domhsh_exit - Cleanup for the domain hash
+ *
+ * Description:
+ * Clears and frees the domain hash table. No real serious effort is made
+ * towards locking but that shouldn't be an issue since we should only be
+ * called when the module is being unloaded. Returns zero on success, non-zero
+ * values on error.
+ *
+ */
+void netlbl_domhsh_exit(void)
+{
+ u32 iter_bkt;
+ struct netlbl_domhsh_tbl *hsh_tbl;
+ struct netlbl_dom_map *iter_list;
+
+ rcu_read_lock();
+ if (rcu_dereference(netlbl_domhsh) == NULL) {
+ rcu_read_unlock();
+ return;
+ }
+ iter_list = rcu_dereference(netlbl_domhsh_def);
+ spin_lock(&netlbl_domhsh_def_lock);
+ rcu_assign_pointer(netlbl_domhsh_def, NULL);
+ spin_unlock(&netlbl_domhsh_def_lock);
+ rcu_read_unlock();
+
+ if (iter_list) {
+ synchronize_rcu();
+ netlbl_domhsh_free_entry(&iter_list->rcu);
+ }
+
+ rcu_read_lock();
+ hsh_tbl = rcu_dereference(netlbl_domhsh);
+ spin_lock(&netlbl_domhsh_lock);
+ rcu_assign_pointer(netlbl_domhsh, NULL);
+ spin_unlock(&netlbl_domhsh_lock);
+ rcu_read_unlock();
+
+ synchronize_rcu();
+
+ /* PM - it probably doesn't matter, but do we need to use the rcu list
+ functions here since we are the only one who has access to the
+ list now? */
+ for (iter_bkt = 0; iter_bkt < hsh_tbl->size; iter_bkt++)
+ list_for_each_entry_rcu(iter_list,
+ &hsh_tbl->tbl[iter_bkt], list) {
+ iter_list->valid = 0;
+ list_del_rcu(&iter_list->list);
+ netlbl_domhsh_free_entry(&iter_list->rcu);
+ }
+ kfree(hsh_tbl->tbl);
+ kfree(hsh_tbl);
+
+ return;
+}
+
+/**
+ * netlbl_domhsh_add - Adds a entry to the domain hash table
+ * @entry: the entry to add
+ *
+ * Description:
+ * Adds a new entry to the domain hash table and handles any updates to the
+ * lower level protocol handler (i.e. CIPSO). Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_add(struct netlbl_dom_map *entry)
+{
+ int ret_val = -EPERM;
+ u32 bkt;
+
+ BUG_ON(entry == NULL);
+
+ switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ ret_val = 0;
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ ret_val = cipso_v4_doi_domhsh_add(entry->type_def.cipsov4,
+ entry->domain);
+ break;
+#endif
+ default:
+ BUG();
+ }
+ if (ret_val != 0)
+ return ret_val;
+
+ entry->valid = 1;
+ INIT_RCU_HEAD(&entry->rcu);
+
+ rcu_read_lock();
+ if (entry->domain != NULL &&
+ netlbl_domhsh_search(entry->domain, 0) == NULL) {
+ bkt = netlbl_domhsh_hash(entry->domain);
+ spin_lock(&netlbl_domhsh_lock);
+ list_add_tail_rcu(&entry->list, &netlbl_domhsh->tbl[bkt]);
+ spin_unlock(&netlbl_domhsh_lock);
+ } else if (entry->domain == NULL &&
+ rcu_dereference(netlbl_domhsh_def) == NULL) {
+ INIT_LIST_HEAD(&entry->list);
+ spin_lock(&netlbl_domhsh_def_lock);
+ rcu_assign_pointer(netlbl_domhsh_def, entry);
+ spin_unlock(&netlbl_domhsh_def_lock);
+ } else {
+ rcu_read_unlock();
+ switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
+ entry->domain) != 0)
+ BUG();
+ break;
+#endif
+ default:
+ BUG();
+ }
+ return -EPERM;
+ }
+ rcu_read_unlock();
+
+ return 0;
+}
+
+/**
+ * netlbl_domhsh_add_default - Adds the default entry to the domain hash table
+ * @entry: the entry to add
+ *
+ * Description:
+ * Adds a new default entry to the domain hash table and handles any updates
+ * to the lower level protocol handler (i.e. CIPSO). Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_add_default(struct netlbl_dom_map *entry)
+{
+ return netlbl_domhsh_add(entry);
+}
+
+/**
+ * netlbl_domhsh_remove - Removes an entry from the domain hash table
+ * @domain: the domain to remove
+ *
+ * Description:
+ * Removes an entry from the domain hash table and handles any updates to the
+ * lower level protocol handler (i.e. CIPSO). Returns zero on success,
+ * negative on failure.
+ *
+ */
+int netlbl_domhsh_remove(const char *domain)
+{
+ int ret_val = -EPERM;
+ struct netlbl_dom_map *entry;
+
+ rcu_read_lock();
+ if (domain != NULL)
+ entry = netlbl_domhsh_search(domain, 0);
+ else
+ entry = netlbl_domhsh_search(domain, 1);
+ if (entry == NULL)
+ goto remove_return;
+ switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ if (cipso_v4_doi_domhsh_remove(entry->type_def.cipsov4,
+ entry->domain) != 0)
+ goto remove_return;
+ break;
+#endif
+ default:
+ BUG();
+ }
+ if (entry != rcu_dereference(netlbl_domhsh_def)) {
+ spin_lock(&netlbl_domhsh_lock);
+ entry->valid = 0;
+ list_del_rcu(&entry->list);
+ spin_unlock(&netlbl_domhsh_lock);
+ } else {
+ spin_lock(&netlbl_domhsh_def_lock);
+ entry->valid = 0;
+ rcu_assign_pointer(netlbl_domhsh_def, NULL);
+ spin_unlock(&netlbl_domhsh_def_lock);
+ }
+ call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
+
+ ret_val = 0;
+
+remove_return:
+ rcu_read_unlock();
+ return ret_val;
+}
+
+/**
+ * netlbl_domhsh_remove_default - Removes the default entry from the table
+ *
+ * Description:
+ * Removes/resets the default entry for the domain hash table and handles any
+ * updates to the lower level protocol handler (i.e. CIPSO). Returns zero on
+ * success, non-zero on failure.
+ *
+ */
+int netlbl_domhsh_remove_default(void)
+{
+ return netlbl_domhsh_remove(NULL);
+}
+
+/**
+ * netlbl_domhsh_getentry - Get an entry from the domain hash table
+ * @domain: the domain name to search for
+ *
+ * Description:
+ * Look through the domain hash table searching for an entry to match @domain,
+ * return a pointer to a copy of the entry or NULL. The caller is responsibile
+ * for ensuring that rcu_read_[un]lock() is called.
+ *
+ */
+struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
+{
+ return netlbl_domhsh_search(domain, 1);
+}
+
+/**
+ * netlbl_domhsh_dump - Dump the domain hash table into a sk_buff
+ *
+ * Description:
+ * Dump the domain hash table into a buffer suitable for returning to an
+ * application in response to a NetLabel management DOMAIN message. This
+ * function may fail if another process is growing the hash table at the same
+ * time. The returned sk_buff has room at the front of the sk_buff for
+ * a nlmsghdr struct and a netlbl_mgmt_msghdr struct. See netlabel.h for the
+ * DOMAIN message format. Returns a pointer to a sk_buff on success, NULL on
+ * error.
+ *
+ */
+struct sk_buff *netlbl_domhsh_dump(void)
+{
+ struct sk_buff *skb;
+ unsigned char *buf;
+ u32 buf_len;
+ u32 bkt_iter;
+ u32 dom_cnt = 0;
+ struct netlbl_domhsh_tbl *hsh_tbl;
+ struct netlbl_dom_map *list_iter;
+ u32 tmp_len;
+
+ /* XXX - This is kinda ugly as we have to go through the table 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. */
+
+ buf_len = 4;
+ rcu_read_lock();
+ hsh_tbl = rcu_dereference(netlbl_domhsh);
+ for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++)
+ list_for_each_entry_rcu(list_iter,
+ &hsh_tbl->tbl[bkt_iter], list) {
+ buf_len += 9 + strlen(list_iter->domain);
+ switch (list_iter->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ buf_len += 8;
+ break;
+#endif
+ default:
+ rcu_read_unlock();
+ BUG();
+ }
+ dom_cnt++;
+ }
+ rcu_read_unlock();
+
+ skb = alloc_skb(NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr) +
+ buf_len), GFP_KERNEL);
+ if (skb == NULL)
+ return NULL;
+ skb_reserve(skb, NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+ tmp_len = skb_tailroom(skb);
+ if (tmp_len < buf_len)
+ goto dump_failure;
+ buf = skb_put(skb, buf_len);
+ buf_len -= 4;
+ netlbl_putinc_u32(&buf, dom_cnt);
+
+ rcu_read_lock();
+ hsh_tbl = rcu_dereference(netlbl_domhsh);
+ for (bkt_iter = 0; bkt_iter < hsh_tbl->size; bkt_iter++)
+ list_for_each_entry_rcu(list_iter,
+ &hsh_tbl->tbl[bkt_iter], list) {
+ tmp_len = strlen(list_iter->domain) + 1;
+ if (buf_len < tmp_len + 8) {
+ rcu_read_unlock();
+ goto dump_failure;
+ }
+ buf_len -= tmp_len + 8;
+ netlbl_putinc_u32(&buf, tmp_len);
+ netlbl_putinc_str(&buf, list_iter->domain);
+ netlbl_putinc_u32(&buf, list_iter->type);
+ switch (list_iter->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ if (buf_len < 8) {
+ rcu_read_unlock();
+ goto dump_failure;
+ }
+ buf_len -= 8;
+ netlbl_putinc_u32(&buf,
+ list_iter->type_def.cipsov4->type);
+ netlbl_putinc_u32(&buf,
+ list_iter->type_def.cipsov4->doi);
+ break;
+#endif
+ default:
+ rcu_read_unlock();
+ BUG();
+ }
+ }
+ rcu_read_unlock();
+
+ return skb;
+
+dump_failure:
+ kfree_skb(skb);
+ return NULL;
+}
+
+/**
+ * netlbl_domhsh_dump_default - Dump the default domain mapping into a sk_buff
+ *
+ * Description:
+ * Dump the default domain mapping into a buffer suitable for returning to an
+ * application in response to a NetLabel management DEFDOMAIN message. This
+ * function may fail if another process is changing the default domain mapping
+ * at the same time. The returned sk_buff has room at the front of the
+ * skb_buff for a nlmsghdr struct and a netlbl_mgmt_msghdr struct. See
+ * netlabel.h for the DEFDOMAIN message format. Returns a pointer to a
+ * sk_buff on success, NULL on error.
+ *
+ */
+struct sk_buff *netlbl_domhsh_dump_default(void)
+{
+ struct sk_buff *skb;
+ unsigned char *buf;
+ u32 buf_len;
+ u32 tmp_len;
+ struct netlbl_dom_map *entry;
+
+ /* XXX - This is kinda ugly as we have to go look at the default
+ mapping 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
+ default mapping could change on us, if that is the case we fail. */
+
+ buf_len = 4;
+ rcu_read_lock();
+ entry = rcu_dereference(netlbl_domhsh_def);
+ if (entry != NULL)
+ switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ buf_len += 8;
+ break;
+#endif
+ default:
+ BUG();
+ }
+ rcu_read_unlock();
+
+ skb = alloc_skb(NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr) +
+ buf_len), GFP_KERNEL);
+ if (skb == NULL)
+ return NULL;
+ skb_reserve(skb, NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+ tmp_len = skb_tailroom(skb);
+ if (tmp_len < buf_len)
+ goto dump_default_failure;
+ buf = skb_put(skb, buf_len);
+
+ rcu_read_lock();
+ if (entry != rcu_dereference(netlbl_domhsh_def)) {
+ rcu_read_unlock();
+ goto dump_default_failure;
+ }
+ buf_len -= 4;
+ if (entry != NULL) {
+ netlbl_putinc_u32(&buf, entry->type);
+ switch (entry->type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ if (buf_len < 8) {
+ rcu_read_unlock();
+ goto dump_default_failure;
+ }
+ buf_len -= 8;
+ netlbl_putinc_u32(&buf, entry->type_def.cipsov4->type);
+ netlbl_putinc_u32(&buf, entry->type_def.cipsov4->doi);
+ break;
+#endif
+ default:
+ rcu_read_unlock();
+ BUG();
+ }
+ } else
+ netlbl_putinc_u32(&buf, NETLBL_NLTYPE_NONE);
+ rcu_read_unlock();
+
+ return skb;
+
+dump_default_failure:
+ kfree_skb(skb);
+ return NULL;
+}
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_domainhash.h linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_domainhash.h
--- linux-2.6.16.i686/net/netlabel/netlabel_domainhash.h 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_domainhash.h 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,64 @@
+/*
+ * NetLabel Domain Hash Table
+ *
+ * This file manages the domain hash table that NetLabel uses to determine
+ * which network labeling protocol to use for a given domain. The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_DOMAINHASH_H
+#define _NETLABEL_DOMAINHASH_H
+
+/* Domain hash table size */
+/* XXX - currently this number is an uneducated guess */
+#define NETLBL_DOMHSH_BITSIZE 7
+
+/* Domain mapping definition struct */
+struct netlbl_dom_map {
+ char *domain;
+ u32 type;
+ union {
+ struct cipso_v4_doi *cipsov4;
+ } type_def;
+
+ u32 valid;
+ struct list_head list;
+ struct rcu_head rcu;
+};
+
+/* init/exit functions */
+int netlbl_domhsh_init(const u32 size) __init;
+void netlbl_domhsh_exit(void) __exit;
+
+/* Manipulate the domain hash table */
+int netlbl_domhsh_add(struct netlbl_dom_map *entry);
+int netlbl_domhsh_add_default(struct netlbl_dom_map *entry);
+int netlbl_domhsh_remove_default(void);
+struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
+struct sk_buff *netlbl_domhsh_dump(void);
+struct sk_buff *netlbl_domhsh_dump_default(void);
+
+#endif
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_kapi.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_kapi.c
--- linux-2.6.16.i686/net/netlabel/netlabel_kapi.c 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_kapi.c 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,420 @@
+/*
+ * NetLabel Kernel API
+ *
+ * This file defines the kernel API for the NetLabel system. The NetLabel
+ * system manages static and dynamic label mappings for network protocols such
+ * as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <net/ip.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+#include <asm/bug.h>
+
+#include "netlabel_domainhash.h"
+#include "netlabel_user.h"
+#include "netlabel_unlabeled.h"
+
+/*
+ * LSM Functions
+ */
+
+/**
+ * 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.
+ *
+ */
+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.
+ *
+ */
+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.
+ *
+ */
+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.
+ *
+ */
+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));
+}
+
+/**
+ * netlbl_socket_setattr - Label a socket using the correct protocol
+ * @sock: the socket to label
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Attach the correct label to the given socket using the security attributes
+ * specified in @secattr. Returns zero on success, negative values on failure.
+ *
+ */
+int netlbl_socket_setattr(const struct socket *sock,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val;
+ struct netlbl_dom_map *dom_entry;
+
+ /* PM - split these into individual BUGs so we can pinpoint problems
+ easier */
+ BUG_ON(sock == NULL);
+ BUG_ON(secattr == NULL);
+ BUG_ON(secattr->set_domain == 0);
+
+ rcu_read_lock();
+ dom_entry = netlbl_domhsh_getentry(secattr->domain);
+ if (dom_entry == NULL) {
+ rcu_read_unlock();
+ return -ENOENT;
+ }
+ switch (dom_entry->type) {
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ ret_val = cipso_v4_socket_setattr(sock,
+ dom_entry->type_def.cipsov4,
+ secattr);
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ ret_val = 0;
+ break;
+#endif
+ default:
+ ret_val = -ENOENT;
+ }
+ rcu_read_unlock();
+
+ return ret_val;
+}
+
+/**
+ * netlbl_socket_peekattr - Get the security attributes on a queued packet
+ * @sock: the socket
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Peek at the incoming packet queue of @sock and return the security
+ * attributes of the first packet in the queue. If there are no packets in
+ * the queue or no packets with security attributes return -ENOMSG. Otherwise
+ * return zero on success, negative values on failure.
+ *
+ */
+int netlbl_socket_peekattr(const struct socket *sock,
+ struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val = -ENOMSG;
+ struct sk_buff_head *sock_queue;
+ struct sk_buff *skb;
+ struct sk_buff *skb_tmp = NULL;
+
+ /* PM - split these into individual BUGs so we can pinpoint problems
+ easier */
+ BUG_ON(sock == NULL);
+ BUG_ON(sock->sk == NULL);
+ BUG_ON(sock->sk->sk_family != PF_INET);
+ BUG_ON(secattr == NULL);
+
+ sock_queue = &sock->sk->sk_receive_queue;
+ /* XXX - We could just take the lock here and do a skb_peek() but we
+ might end up holding the lock for a long time so grab the
+ lock, do a peek, and clone the result */
+ spin_lock(&sock_queue->lock);
+ skb = skb_peek(sock_queue);
+ if (skb != NULL)
+ skb_tmp = skb_clone(skb, GFP_ATOMIC);
+ spin_unlock(&sock_queue->lock);
+ if (skb_tmp != NULL) {
+ ret_val = netlbl_skbuff_getattr(skb_tmp, secattr);
+ kfree_skb(skb_tmp);
+ } else
+ ret_val = -ENOMEM;
+
+ return ret_val;
+}
+
+/**
+ * netlbl_socket_getattr - Determine the security attributes of a socket
+ * @sock: the socket
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Examines the given socket to see any NetLabel style labeling has been
+ * applied to the socket, if so it parses the socket label and returns the
+ * security attributes in @secattr. Returns zero on success, negative values
+ * on failure.
+ *
+ */
+int netlbl_socket_getattr(const struct socket *sock,
+ struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val;
+
+ /* PM - split these into individual BUGs so we can pinpoint problems
+ easier */
+ BUG_ON(sock == NULL);
+ BUG_ON(sock->sk == NULL);
+ BUG_ON(sock->sk->sk_family != PF_INET);
+ BUG_ON(secattr == NULL);
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ ret_val = cipso_v4_socket_getattr(sock, secattr);
+#endif
+
+#ifdef CONFIG_NETLABEL_UNLABELED
+ if (ret_val != 0)
+ ret_val = netlbl_unlabel_getattr(secattr);
+#endif
+
+ return ret_val;
+}
+
+/**
+ * netlbl_skbuff_getattr - Determine the security attributes of a packet
+ * @skb: the packet
+ * @secattr: the security attributes
+ *
+ * Description:
+ * Examines the given packet to see if a recognized form of packet labeling
+ * is present, if so it parses the packet label and returns the security
+ * attributes in @secattr. Returns zero on success, negative values on
+ * failure.
+ *
+ */
+int netlbl_skbuff_getattr(const struct sk_buff *skb,
+ struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val = -ENOMSG;
+
+ /* PM - split these into individual BUGs so we can pinpoint problems
+ easier */
+ BUG_ON(skb == NULL);
+ BUG_ON(secattr == NULL);
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ if (CIPSO_V4_OPTEXIST(skb)) {
+ ret_val = cipso_v4_skbuff_getattr(skb, secattr);
+ goto skbuff_read_return;
+ }
+#endif
+
+#ifdef CONFIG_NETLABEL_UNLABELED
+ ret_val = netlbl_unlabel_getattr(secattr);
+#endif
+
+skbuff_read_return:
+ return ret_val;
+}
+
+/**
+ * netlbl_skbuff_err - Handle a LSM error on a sk_buff
+ * @skb: the packet
+ * @error: the error code
+ *
+ * Description:
+ * Deal with a LSM problem when handling the packet in @skb, typically this is
+ * a permission denied problem (-EACCES). The correct action is determined
+ * according to the packet's labeling protocol. Returns zero on success,
+ * negative values on failure.
+ *
+ */
+int netlbl_skbuff_err(struct sk_buff *skb, int error)
+{
+ /* PM - split these into individual BUGs so we can pinpoint problems
+ easier */
+ BUG_ON(skb == NULL);
+ BUG_ON(error == 0);
+
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ if (CIPSO_V4_OPTEXIST(skb))
+ return cipso_v4_error(skb, error, 0);
+#endif
+
+ return -ENOMSG;
+}
+
+/**
+ * netlbl_cache_invalidate - Invalidate all of the NetLabel protocol caches
+ *
+ * Description:
+ * For all of the NetLabel protocols that support some form of label mapping
+ * cache, invalidate the cache. Returns zero on success, negative values on
+ * error.
+ *
+ */
+int netlbl_cache_invalidate(void)
+{
+ return cipso_v4_cache_invalidate();
+}
+
+/**
+ * netlbl_cache_add - Add an entry to a NetLabel protocol cache
+ * @skb: the packet
+ * @secattr: the packet's security attributes
+ *
+ * Description:
+ * Add the LSM security attributes for the given packet to the underlying
+ * NetLabel protocol's label mapping cache. Returns zero on success, negative
+ * values on error.
+ *
+ */
+int netlbl_cache_add(const struct sk_buff *skb,
+ const struct netlbl_lsm_secattr *secattr)
+{
+ int ret_val = -ENOMSG;
+
+ /* PM - split these into individual BUGs so we can pinpoint problems
+ easier */
+ BUG_ON(skb == NULL);
+ BUG_ON(secattr == NULL);
+
+ if (secattr->set_cache != 1)
+ return -ENOMSG;
+
+ if (CIPSO_V4_OPTEXIST(skb))
+ ret_val = cipso_v4_cache_add(skb, secattr);
+
+ return ret_val;
+}
+
+/*
+ * Setup Functions
+ */
+
+/**
+ * netlbl_init - Init for the NetLabel module
+ *
+ * Description:
+ * Perform the initialization of the NetLabel module before first use.
+ *
+ */
+static int __init netlbl_init(void)
+{
+ int ret_val = 0;
+
+ printk(KERN_INFO "NetLabel: Initializing\n");
+ printk(KERN_INFO "NetLabel: domain hash size = %u\n",
+ (1 << NETLBL_DOMHSH_BITSIZE));
+ printk(KERN_INFO "NetLabel: protocols ="
+#ifdef CONFIG_NETLABEL_UNLABELED
+ " UNLABELED"
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ " CIPSOv4"
+#endif
+ "\n");
+
+ ret_val = netlbl_domhsh_init(NETLBL_DOMHSH_BITSIZE);
+ if (ret_val != 0)
+ goto init_return;
+
+ ret_val = netlbl_netlink_init();
+ if (ret_val != 0)
+ goto init_return;
+
+#ifdef CONFIG_NETLABEL_UNLABELED_DEFAULT
+ ret_val = netlbl_unlabel_defconf();
+ if (ret_val != 0)
+ goto init_return;
+ printk(KERN_INFO "NetLabel: unlabeled traffic allowed by default\n");
+#endif
+
+init_return:
+ if (ret_val != 0) {
+ netlbl_netlink_exit();
+ netlbl_domhsh_exit();
+ }
+ return ret_val;
+}
+
+/* PM - not sure there is any point to this now, delete this func? */
+/**
+ * netlbl_exit - Cleanup for the NetLabel module
+ *
+ * Description:
+ * Perform any cleanup required before removing the NetLabel module.
+ *
+ */
+static void __exit netlbl_exit(void)
+{
+ netlbl_netlink_exit();
+ netlbl_domhsh_exit();
+}
+
+subsys_initcall(netlbl_init);
+
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_mgmt.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_mgmt.c
--- linux-2.6.16.i686/net/netlabel/netlabel_mgmt.c 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_mgmt.c 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,677 @@
+/*
+ * NetLabel Management Support
+ *
+ * This file defines the management functions for the NetLabel system. The
+ * NetLabel system manages static and dynamic label mappings for network
+ * protocols such as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <net/cipso_ipv4.h>
+
+#include "netlabel_domainhash.h"
+#include "netlabel_user.h"
+#include "netlabel_mgmt.h"
+
+/*
+ * Local Prototypes
+ */
+
+static void netlbl_mgmt_send_ack(const struct sk_buff *req_skb,
+ const u32 ret_code);
+
+/*
+ * Helper Functions
+ */
+
+/**
+ * netlbl_mgmt_put_hdr - Write a MGMT NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Management opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Management header into the given
+ * buffer.
+ *
+ */
+static inline void netlbl_mgmt_put_hdr(unsigned char *buffer, const u32 opcode)
+{
+ ((struct netlbl_mgmt_msghdr *)buffer)->opcode = opcode;
+}
+
+/**
+ * netlbl_mgmt_putinc_hdr - Write a MGMT NetLabel header into a buffer
+ * @buffer: the buffer
+ * @opcode: the NetLabel Management opcode
+ *
+ * Description:
+ * Use the given values to write a NetLabel Management header into the given
+ * buffer and increment the buffer pointer past the header.
+ *
+ */
+static inline void netlbl_mgmt_putinc_hdr(unsigned char **buffer,
+ const u32 opcode)
+{
+ netlbl_mgmt_put_hdr(*buffer, opcode);
+ *buffer += sizeof(struct netlbl_mgmt_msghdr);
+}
+
+/**
+ * netlbl_mgmt_payload_len - Return the length of the payload
+ * @skb: the NETLINK buffer
+ *
+ * Description:
+ * This function returns the length of the NetLabel management payload.
+ *
+ */
+static inline u32 netlbl_mgmt_payload_len(const struct sk_buff *skb)
+{
+ const struct nlmsghdr *nl_hdr = (struct nlmsghdr *)skb->data;
+
+ if (nlmsg_len(nl_hdr) <= sizeof(struct netlbl_mgmt_msghdr))
+ return 0;
+ return nlmsg_len(nl_hdr) - sizeof(struct netlbl_mgmt_msghdr);
+}
+
+/**
+ * netlbl_mgmt_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 management
+ * payload.
+ *
+ */
+static inline unsigned char *netlbl_mgmt_payload_data(
+ const struct sk_buff *skb)
+{
+ return nlmsg_data((struct nlmsghdr *)skb->data) +
+ sizeof(struct netlbl_mgmt_msghdr);
+}
+
+/*
+ * Label Mapping Functions
+ */
+
+/**
+ * netlbl_mgmt_add - Handle an ADD message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated ADD message and add the domains from the message
+ * to the hash table. See netlabel.h for a description of the message format.
+ *
+ */
+static void netlbl_mgmt_add(const struct sk_buff *req_skb,
+ const unsigned char *msg)
+{
+ int ret_val = -EINVAL;
+ unsigned char *msg_ptr = (unsigned char *)msg;
+ u32 msg_len = netlbl_mgmt_payload_len(req_skb);
+ u32 count;
+ struct netlbl_dom_map *entry = NULL;
+ u32 iter;
+ u32 tmp_val;
+ u32 rcu_locked = 0;
+
+ if (msg_len < 4)
+ goto add_failure;
+ count = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+
+ for (iter = 0; iter < count && msg_len > 0; iter++, entry = NULL) {
+ if (msg_len < 4)
+ goto add_failure;
+ tmp_val = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ if (tmp_val == 0)
+ goto add_failure;
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (entry == NULL) {
+ ret_val = -ENOMEM;
+ goto add_failure;
+ }
+
+ if (msg_len < tmp_val)
+ goto add_failure;
+ entry->domain = kmalloc(tmp_val, GFP_KERNEL);
+ if (entry->domain == NULL) {
+ ret_val = -ENOMEM;
+ goto add_failure;
+ }
+ strncpy(entry->domain, msg_ptr, tmp_val);
+ entry->domain[tmp_val - 1] = '\0';
+ msg_ptr += tmp_val;
+ msg_len -= tmp_val;
+
+ if (msg_len < 4)
+ goto add_failure;
+ tmp_val = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ entry->type = tmp_val;
+ switch (tmp_val) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ if (msg_len < 4)
+ goto add_failure;
+ tmp_val = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ /* XXX - we should be holding a rcu_read_lock() here
+ while we hold the result but since the entry
+ will always be deleted when the CIPSO DOI
+ is deleted we aren't going to keep the lock */
+ rcu_read_lock();
+ entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
+ if (entry->type_def.cipsov4 == NULL) {
+ rcu_read_unlock();
+ goto add_failure;
+ }
+ rcu_locked = 1;
+ break;
+#endif
+ default:
+ goto add_failure;
+ }
+
+ ret_val = netlbl_domhsh_add(entry);
+ if (rcu_locked) {
+ rcu_read_unlock();
+ rcu_locked = 0;
+ }
+ if (ret_val != 0)
+ goto add_failure;
+ }
+
+ netlbl_mgmt_send_ack(req_skb, NETLBL_E_OK);
+ return;
+
+add_failure:
+ if (entry) {
+ if (entry->domain)
+ kfree(entry->domain);
+ kfree(entry);
+ }
+ netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_remove - Handle a REMOVE message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated REMOVE message and remove the specified domain
+ * mappings.
+ *
+ */
+static void netlbl_mgmt_remove(const struct sk_buff *req_skb,
+ const unsigned char *msg)
+{
+ int ret_val = -EINVAL;
+ unsigned char *msg_ptr = (unsigned char *)msg;
+ u32 msg_len = netlbl_mgmt_payload_len(req_skb);
+ u32 count;
+ u32 iter;
+ u32 tmp_val;
+
+ if (msg_len < 4)
+ goto remove_return;
+ count = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+
+ for (iter = 0; iter < count && msg_len > 0; iter++) {
+ if (msg_len < 4)
+ goto remove_return;
+ tmp_val = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ if (tmp_val == 0 ||
+ msg_len < tmp_val || msg_ptr[tmp_val - 1] != '\0')
+ goto remove_return;
+ ret_val = netlbl_domhsh_remove(msg_ptr);
+ msg_ptr += tmp_val;
+ msg_len -= tmp_val;
+ if (ret_val != 0)
+ goto remove_return;
+ }
+
+ ret_val = 0;
+
+remove_return:
+ netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_list - Handle a LIST message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated LIST message and dumps the domain hash table in a
+ * form suitable for use in a kernel generated LIST message.
+ *
+ */
+static void netlbl_mgmt_list(const struct sk_buff *req_skb,
+ const unsigned char *msg)
+{
+ int ret_val = -ENOMEM;
+ struct sk_buff *skb;
+ unsigned char *buf_ptr;
+
+ skb = netlbl_domhsh_dump();
+ if (skb == NULL)
+ goto list_return;
+ buf_ptr = skb_push(skb,
+ NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+ if (buf_ptr == NULL) {
+ kfree_skb(skb);
+ ret_val = -EAGAIN;
+ goto list_return;
+ }
+ netlbl_putinc_hdr(&buf_ptr,
+ NETLBL_NLTYPE_MGMT,
+ skb->len,
+ 0,
+ NETLINK_CB(req_skb).pid,
+ 0);
+ netlbl_mgmt_putinc_hdr(&buf_ptr, NL_MGMT_LIST);
+
+ ret_val = netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+
+list_return:
+ if (ret_val != 0)
+ netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_adddef - Handle an ADDDEF message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated ADDDEF message and respond accordingly.
+ *
+ */
+static void netlbl_mgmt_adddef(const struct sk_buff *req_skb,
+ const unsigned char *msg)
+{
+ int ret_val = -EINVAL;
+ unsigned char *msg_ptr = (unsigned char *)msg;
+ u32 msg_len = netlbl_mgmt_payload_len(req_skb);
+ u32 type;
+ struct netlbl_dom_map *entry = NULL;
+ u32 tmp_val;
+ u32 rcu_locked = 0;
+
+ if (msg_len < 4)
+ goto adddef_failure;
+ type = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (entry == NULL) {
+ ret_val = -ENOMEM;
+ goto adddef_failure;
+ }
+ entry->type = type;
+
+ switch (type) {
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ if (msg_len < 4)
+ goto adddef_failure;
+ tmp_val = netlbl_getinc_u32(&msg_ptr);
+ msg_len -= 4;
+ /* XXX - we should be holding a rcu_read_lock here while we
+ hold the result but since the entry will always be
+ deleted when the CIPSO DOI is deleted we are going
+ to skip the lock */
+ rcu_read_lock();
+ entry->type_def.cipsov4 = cipso_v4_doi_getdef(tmp_val);
+ if (entry->type_def.cipsov4 == NULL) {
+ rcu_read_unlock();
+ goto adddef_failure;
+ }
+ rcu_locked = 1;
+ break;
+#endif
+ default:
+ ret_val = -EINVAL;
+ goto adddef_failure;
+ }
+
+ ret_val = netlbl_domhsh_add_default(entry);
+ if (rcu_locked) {
+ rcu_read_unlock();
+ rcu_locked = 0;
+ }
+ if (ret_val != 0)
+ goto adddef_failure;
+
+ netlbl_mgmt_send_ack(req_skb, NETLBL_E_OK);
+ return;
+
+adddef_failure:
+ if (entry)
+ kfree(entry);
+ netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_removedef - Handle a REMOVEDEF message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated REMOVEDEF message and remove the default domain
+ * mapping.
+ *
+ */
+static void netlbl_mgmt_removedef(const struct sk_buff *req_skb,
+ const unsigned char *msg)
+{
+ int ret_val;
+
+ ret_val = netlbl_domhsh_remove_default();
+ netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_listdef - Handle a LISTDEF message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated LISTDEF message and dumps the default domain
+ * mapping in a form suitable for use in a kernel generated LISTDEF message.
+ *
+ */
+static void netlbl_mgmt_listdef(const struct sk_buff *req_skb,
+ const unsigned char *msg)
+{
+ int ret_val = -ENOMEM;
+ struct sk_buff *skb;
+ unsigned char *buf_ptr;
+
+ skb = netlbl_domhsh_dump_default();
+ if (skb == NULL)
+ goto listdef_return;
+ buf_ptr = skb_push(skb,
+ NLMSG_SPACE(sizeof(struct netlbl_mgmt_msghdr)));
+ if (buf_ptr == NULL) {
+ kfree_skb(skb);
+ ret_val = -EAGAIN;
+ goto listdef_return;
+ }
+ netlbl_putinc_hdr(&buf_ptr,
+ NETLBL_NLTYPE_MGMT,
+ skb->len,
+ 0,
+ NETLINK_CB(req_skb).pid,
+ 0);
+ netlbl_mgmt_putinc_hdr(&buf_ptr, NL_MGMT_LISTDEF);
+
+ ret_val = netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+
+listdef_return:
+ if (ret_val != 0)
+ netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_modules - Handle a MODULES message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated MODULES message and respond accordingly.
+ *
+ */
+static void netlbl_mgmt_modules(const struct sk_buff *req_skb,
+ const unsigned char *msg)
+{
+ int ret_val = -EINVAL;
+ u32 mod_count = 0;
+ size_t msg_size;
+ size_t data_size;
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nl_mgmt_hdr;
+ unsigned char *data;
+
+ if (netlbl_mgmt_payload_len(req_skb) < 4)
+ goto nlmsg_failure;
+ mod_count = netlbl_get_u32(msg);
+ if (mod_count != 0)
+ goto nlmsg_failure;
+
+#ifdef CONFIG_NETLABEL_UNLABELED
+ mod_count += 1;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ mod_count += 1;
+#endif
+
+ data_size = sizeof(struct netlbl_mgmt_msghdr) + 4 + mod_count * 4;
+ msg_size = NLMSG_SPACE(data_size);
+
+ skb = alloc_skb(msg_size, GFP_KERNEL);
+ if (skb == NULL) {
+ ret_val = -ENOMEM;
+ goto nlmsg_failure;
+ }
+
+ nl_mgmt_hdr = NLMSG_PUT(skb,
+ NETLINK_CB(req_skb).pid,
+ 0,
+ NETLBL_NLTYPE_MGMT,
+ data_size);
+ nl_mgmt_hdr->nlmsg_len = msg_size;
+
+ data = NLMSG_DATA(nl_mgmt_hdr);
+ netlbl_mgmt_putinc_hdr(&data, NL_MGMT_MODULES);
+ netlbl_putinc_u32(&data, mod_count);
+#ifdef CONFIG_NETLABEL_UNLABELED
+ netlbl_putinc_u32(&data, NETLBL_NLTYPE_UNLABELED);
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ netlbl_putinc_u32(&data, NETLBL_NLTYPE_CIPSOV4);
+#endif
+
+ netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+ return;
+
+nlmsg_failure:
+ if (skb)
+ kfree_skb(skb);
+ netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/**
+ * netlbl_mgmt_version - Handle a VERSION message
+ * @req_skb: the NETLINK buffer
+ * @msg: the NetLabel management message
+ *
+ * Description:
+ * Process a user generated VERSION message and respond accordingly.
+ *
+ */
+static void netlbl_mgmt_version(const struct sk_buff *req_skb,
+ const unsigned char *msg)
+{
+ int ret_val = -EINVAL;
+ u32 str_len;
+ size_t msg_size;
+ size_t data_size;
+ struct sk_buff *skb = NULL;
+ struct nlmsghdr *nl_mgmt_hdr;
+ unsigned char *data;
+
+ if (netlbl_mgmt_payload_len(req_skb) < 4)
+ goto nlmsg_failure;
+ str_len = netlbl_get_u32(msg);
+ if (str_len != 0)
+ goto nlmsg_failure;
+
+ data_size = sizeof(struct netlbl_mgmt_msghdr) + 4;
+ msg_size = NLMSG_SPACE(data_size);
+
+ skb = alloc_skb(msg_size, GFP_KERNEL);
+ if (skb == NULL) {
+ ret_val = -ENOMEM;
+ goto nlmsg_failure;
+ }
+
+ nl_mgmt_hdr = NLMSG_PUT(skb,
+ NETLINK_CB(req_skb).pid,
+ 0,
+ NETLBL_NLTYPE_MGMT,
+ data_size);
+ nl_mgmt_hdr->nlmsg_len = msg_size;
+
+ data = NLMSG_DATA(nl_mgmt_hdr);
+ netlbl_mgmt_putinc_hdr(&data, NL_MGMT_VERSION);
+ netlbl_putinc_u32(&data, NETLBL_PROTO_VERSION);
+
+ netlbl_netlink_snd(skb, NETLINK_CB(req_skb).pid);
+ return;
+
+nlmsg_failure:
+ if (skb)
+ kfree_skb(skb);
+ netlbl_mgmt_send_ack(req_skb, -ret_val);
+}
+
+/*
+ * NetLabel Protocol Handlers
+ */
+
+/**
+ * netlbl_mgmt_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. Returns negative values on error.
+ *
+ */
+static void netlbl_mgmt_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_mgmt_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_MGMT,
+ data_size);
+ nl_ack_hdr->nlmsg_len = msg_size;
+
+ data = NLMSG_DATA(nl_ack_hdr);
+ netlbl_mgmt_putinc_hdr(&data, NL_MGMT_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_mgmt_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 NetLabel
+ * management traffic and dispatching it to the correct functions.
+ *
+ */
+void netlbl_mgmt_rcv(const struct sk_buff *skb, const unsigned char *msg)
+{
+ if (nlmsg_len((struct nlmsghdr *)skb->data) <
+ sizeof(struct netlbl_mgmt_msghdr)) {
+ netlbl_mgmt_send_ack(skb, EINVAL);
+ return;
+ }
+
+ switch (((struct netlbl_mgmt_msghdr *)msg)->opcode) {
+ case NL_MGMT_ADD:
+ netlbl_mgmt_add(skb, netlbl_mgmt_payload_data(skb));
+ break;
+ case NL_MGMT_REMOVE:
+ netlbl_mgmt_remove(skb, netlbl_mgmt_payload_data(skb));
+ break;
+ case NL_MGMT_LIST:
+ netlbl_mgmt_list(skb, netlbl_mgmt_payload_data(skb));
+ break;
+ case NL_MGMT_ADDDEF:
+ netlbl_mgmt_adddef(skb, netlbl_mgmt_payload_data(skb));
+ break;
+ case NL_MGMT_REMOVEDEF:
+ netlbl_mgmt_removedef(skb, netlbl_mgmt_payload_data(skb));
+ break;
+ case NL_MGMT_LISTDEF:
+ netlbl_mgmt_listdef(skb, netlbl_mgmt_payload_data(skb));
+ break;
+ case NL_MGMT_MODULES:
+ netlbl_mgmt_modules(skb, netlbl_mgmt_payload_data(skb));
+ break;
+ case NL_MGMT_VERSION:
+ netlbl_mgmt_version(skb, netlbl_mgmt_payload_data(skb));
+ break;
+ default:
+ netlbl_mgmt_send_ack(skb, EINVAL);
+ return;
+ }
+}
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_mgmt.h linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_mgmt.h
--- linux-2.6.16.i686/net/netlabel/netlabel_mgmt.h 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_mgmt.h 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,248 @@
+/*
+ * NetLabel Management Support
+ *
+ * This file defines the management functions for the NetLabel system. The
+ * NetLabel system manages static and dynamic label mappings for network
+ * protocols such as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_MGMT_H
+#define _NETLABEL_MGMT_H
+
+#include <net/netlabel.h>
+
+/*
+ * The following NetLabel payloads are supported by the management interface,
+ * all of which are preceeded by the nlmsghdr struct.
+ *
+ * o ACK:
+ * Sent by the kernel in response to an applications message, applications
+ * should never send this message.
+ *
+ * +----------------------+-----------------------+
+ * | seq number (32 bits) | return code (32 bits) |
+ * +----------------------+-----------------------+
+ *
+ * seq number: the sequence number of the original message, taken from the
+ * nlmsghdr structure
+ * return code: return value, based on errno values
+ *
+ * o ADD:
+ * Sent by an application to add a domain mapping to the NetLabel system.
+ * The kernel should respond with an ACK.
+ *
+ * +-------------------+
+ * | domains (32 bits) | ...
+ * +-------------------+
+ *
+ * domains: the number of domains in the message
+ *
+ * +-------------------------+--------------------------+
+ * | domain length (32 bits) | domain string (variable) | ...
+ * +-------------------------+--------------------------+
+ *
+ * +-------------------------+-------------- ---- --- -- -
+ * | protocol type (32 bits) | mapping data ... repeated
+ * +-------------------------+-------------- ---- --- -- -
+ *
+ * domain length: the length of the "domain string" in bytes
+ * domain string: the domain string, NULL terminated
+ * protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ * mapping data: specific to the map type (see below)
+ *
+ * NETLBL_NLTYPE_UNLABELED
+ *
+ * No mapping data for this protocol type.
+ *
+ * NETLBL_NLTYPE_CIPSOV4
+ *
+ * +---------------+
+ * | doi (32 bits) |
+ * +---------------+
+ *
+ * doi: the CIPSO DOI value
+ *
+ * o REMOVE:
+ * Sent by an application to remove a domain mapping from the NetLabel
+ * system. The kernel should ACK this message.
+ *
+ * +-------------------+
+ * | domains (32 bits) | ...
+ * +-------------------+
+ *
+ * domains: the number of domains in the message
+ *
+ * +-------------------------+--------------------------+
+ * | domain length (32 bits) | domain string (variable) | ...
+ * +-------------------------+--------------------------+
+ *
+ * domain length: the length of the "domain string" in bytes
+ * domain string: the domain string, NULL terminated
+ *
+ * o LIST:
+ * This message can be sent either from an application or by the kernel in
+ * response to an application generated LIST message. When sent by an
+ * application there is no payload. The kernel should respond to a LIST
+ * message either with a LIST message on success or an ACK message on
+ * failure.
+ *
+ * +-------------------+
+ * | domains (32 bits) | ...
+ * +-------------------+
+ *
+ * domains: the number of domains in the message
+ *
+ * +-------------------------+--------------------------+
+ * | domain length (32 bits) | domain string (variable) | ...
+ * +-------------------------+--------------------------+
+ *
+ * +-------------------------+-------------- ---- --- -- -
+ * | protocol type (32 bits) | mapping data ... repeated
+ * +-------------------------+-------------- ---- --- -- -
+ *
+ * domain length: the length of the "domain string" in bytes
+ * domain string: the domain string, NULL terminated
+ * protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ * mapping data: specific to the map type (see below)
+ *
+ * NETLBL_NLTYPE_UNLABELED
+ *
+ * No mapping data for this protocol type.
+ *
+ * NETLBL_NLTYPE_CIPSOV4
+ *
+ * +----------------+---------------+
+ * | type (32 bits) | doi (32 bits) |
+ * +----------------+---------------+
+ *
+ * type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
+ * as CIPSO_V4_MAP_*)
+ * doi: the CIPSO DOI value
+ *
+ * o ADDDEF:
+ * Sent by an application to set the default domain mapping for the NetLabel
+ * system. The kernel should respond with an ACK.
+ *
+ * +-------------------------+-------------- ---- --- -- -
+ * | protocol type (32 bits) | mapping data ... repeated
+ * +-------------------------+-------------- ---- --- -- -
+ *
+ * protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ * mapping data: specific to the map type (see below)
+ *
+ * NETLBL_NLTYPE_UNLABELED
+ *
+ * No mapping data for this protocol type.
+ *
+ * NETLBL_NLTYPE_CIPSOV4
+ *
+ * +---------------+
+ * | doi (32 bits) |
+ * +---------------+
+ *
+ * doi: the CIPSO DOI value
+ *
+ * o REMOVEDEF:
+ * Sent by an application to remove the default domain mapping from the
+ * NetLabel system, there is no payload. The kernel should ACK this message.
+ *
+ * o LISTDEF:
+ * This message can be sent either from an application or by the kernel in
+ * response to an application generated LISTDEF message. When sent by an
+ * application there is no payload. The kernel should respond to a
+ * LISTDEF message either with a LISTDEF message on success or an ACK message
+ * on failure.
+ *
+ * +-------------------------+-------------- ---- --- -- -
+ * | protocol type (32 bits) | mapping data ... repeated
+ * +-------------------------+-------------- ---- --- -- -
+ *
+ * protocol type: the protocol type (defined by NETLBL_NLTYPE_*)
+ * mapping data: specific to the map type (see below)
+ *
+ * NETLBL_NLTYPE_UNLABELED
+ *
+ * No mapping data for this protocol type.
+ *
+ * NETLBL_NLTYPE_CIPSOV4
+ *
+ * +----------------+---------------+
+ * | type (32 bits) | doi (32 bits) |
+ * +----------------+---------------+
+ *
+ * type: the CIPSO mapping table type (defined in the cipso_ipv4.h header
+ * as CIPSO_V4_MAP_*)
+ * doi: the CIPSO DOI value
+ *
+ * o MODULES:
+ * Sent by an application to request a list of configured NetLabel modules
+ * in the kernel. This message type is also used by the kernel to respond
+ * to an application's MODULES message.
+ *
+ * +-------------------+
+ * | modules (32 bits) | ...
+ * +-------------------+
+ *
+ * modules: the number of modules in the message, if this is an application
+ * generated message and the value is zero then return a list of
+ * the configured modules
+ *
+ * +------------------+
+ * | module (32 bits) | ... repeated
+ * +------------------+
+ *
+ * module: the module number as defined by NETLBL_NLTYPE_*
+ *
+ * o VERSION:
+ * Sent by an application to request the NetLabel version string. This
+ * message type is also used by the kernel to respond to an VERSION request.
+ *
+ * +-------------------+
+ * | version (32 bits) |
+ * +-------------------+
+ *
+ * version: the protocol version number
+ *
+ */
+
+/* MGMT message header */
+struct netlbl_mgmt_msghdr {
+ enum { NL_MGMT_NOOP,
+ NL_MGMT_ACK,
+ NL_MGMT_ADD,
+ NL_MGMT_REMOVE,
+ NL_MGMT_LIST,
+ NL_MGMT_ADDDEF,
+ NL_MGMT_REMOVEDEF,
+ NL_MGMT_LISTDEF,
+ NL_MGMT_MODULES,
+ NL_MGMT_VERSION
+ } opcode;
+};
+
+/* Process NetLabel management messages */
+void netlbl_mgmt_rcv(const struct sk_buff *skb, const unsigned char *msg);
+
+#endif
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_unlabeled.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_unlabeled.c
--- linux-2.6.16.i686/net/netlabel/netlabel_unlabeled.c 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_unlabeled.c 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,285 @@
+/*
+ * 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 inline 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 inline 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 inline 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 inline 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)
+{
+ 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:
+ 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;
+}
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_unlabeled.h linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_unlabeled.h
--- linux-2.6.16.i686/net/netlabel/netlabel_unlabeled.h 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_unlabeled.h 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,83 @@
+/*
+ * NetLabel Unlabeled Support
+ *
+ * This file defines functions for dealing with unlabeled packets for the
+ * NetLabel system. The NetLabel system manages static and dynamic label
+ * mappings for network protocols such as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_UNLABELED_H
+#define _NETLABEL_UNLABELED_H
+
+#include <net/netlabel.h>
+
+/*
+ * The following NetLabel payloads are supported by the Unlabeled subsystem,
+ * all of which are preceeded by the nlmsghdr struct.
+ *
+ * o ACK:
+ * Sent by the kernel in response to an applications message, applications
+ * should never send this message.
+ *
+ * +----------------------+-----------------------+
+ * | seq number (32 bits) | return code (32 bits) |
+ * +----------------------+-----------------------+
+ *
+ * seq number: the sequence number of the original message, taken from the
+ * nlmsghdr structure
+ * return code: return value, based on errno values
+ *
+ * o ACCEPT
+ * This message is sent from an application to specify if the kernel should
+ * allow unlabled packets to pass if they do not match any of the static
+ * mappings defined in the unlabeled module.
+ *
+ * +-----------------+
+ * | allow (32 bits) |
+ * +-----------------+
+ *
+ * allow: if true (1) then allow the packets to pass, if false (0) then
+ * reject the packets
+ *
+ */
+
+/* Unlabeled message header */
+struct netlbl_unlabel_msghdr {
+ enum { NL_UNL_NOOP,
+ NL_UNL_ACK,
+ NL_UNL_ACCEPT
+ } opcode;
+};
+
+/* Process Unlabeled NetLabel messages */
+void netlbl_unlabel_rcv(const struct sk_buff *skb, const unsigned char *msg);
+
+/* Process Unlabeled incoming network packets */
+int netlbl_unlabel_getattr(struct netlbl_lsm_secattr *secattr);
+
+/* Set the default configuration to allow Unlabeled packets */
+int netlbl_unlabel_defconf(void);
+
+#endif
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_user.c linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_user.c
--- linux-2.6.16.i686/net/netlabel/netlabel_user.c 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_user.c 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,174 @@
+/*
+ * NetLabel NETLINK Interface
+ *
+ * This file defines the NETLINK interface for the NetLabel system. The
+ * NetLabel system manages static and dynamic label mappings for network
+ * protocols such as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <net/netlabel.h>
+#include <asm/bug.h>
+
+#include "netlabel_mgmt.h"
+#include "netlabel_unlabeled.h"
+#include "netlabel_cipso_v4.h"
+#include "netlabel_user.h"
+
+/* NETLINK socket */
+/* PM - do we need a lock (or something) around this? */
+static struct sock *netlbl_nl = NULL;
+
+/*
+ * NetLabel Functions
+ */
+
+/**
+ * netlbl_netlink_rcv - Catch incoming NETLINK packets
+ * @sk: the NETLINK socket
+ * @len: absolutely no clue, socket queue length maybe?
+ *
+ * Description:
+ * Receives the NETLINK packet, inspects the packet to determine the correct
+ * NetLabel subsystem and hands the packet off to the correct handler.
+ *
+ */
+static void netlbl_netlink_rcv(struct sock *sk, const int len)
+{
+ struct sk_buff *skb;
+ struct nlmsghdr *nl_hdr;
+
+ /* PM - verify that this is really what we want */
+ if (!capable(CAP_NET_ADMIN))
+ return;
+
+ /* XXX - should this use netlink_run_queue() instead? */
+ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
+ nl_hdr = (struct nlmsghdr *)skb->data;
+ switch (nl_hdr->nlmsg_type) {
+ case NETLBL_NLTYPE_MGMT:
+ netlbl_mgmt_rcv(skb, nlmsg_data(nl_hdr));
+ break;
+#ifdef CONFIG_NETLABEL_UNLABELED
+ case NETLBL_NLTYPE_UNLABELED:
+ netlbl_unlabel_rcv(skb, nlmsg_data(nl_hdr));
+ break;
+#endif
+#ifdef CONFIG_NETLABEL_CIPSOV4
+ case NETLBL_NLTYPE_CIPSOV4:
+ netlbl_cipsov4_rcv(skb, nlmsg_data(nl_hdr));
+ break;
+#endif
+ }
+ nlmsg_free(skb);
+ }
+}
+
+/**
+ * netlbl_netlink_init - Initialize the netlink socket
+ *
+ * Description:
+ * Create the netlink socket and do any other setup required. Returns zero on
+ * success and non-zero on failure.
+ *
+ */
+int __init netlbl_netlink_init(void)
+{
+ /* XXX - it might be a good idea to spawn a thread here at startup to
+ handle the updates to the label mapping databases and have the
+ netlbl_netlink_rcv() function simply poke the thread but i am unsure
+ and this approach is much simpler so it wins for now */
+ netlbl_nl = netlink_kernel_create(NETLINK_NETLABEL,
+ NETLBL_NLGRP_MAX,
+ netlbl_netlink_rcv, THIS_MODULE);
+ if (netlbl_nl == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+/**
+ * netlbl_exit - Release the netlink socket
+ *
+ * Description:
+ * Close the netlink socket and do any other cleanup required.
+ *
+ */
+void netlbl_netlink_exit(void)
+{
+ /* XXX - if we do have a worker thread, see the above comment in
+ netlbl_netlink_init(), we should handle any cleanup here
+ before we go away */
+ if (netlbl_nl != NULL)
+ sock_release(netlbl_nl->sk_socket);
+}
+
+/*
+ * NETLINK I/O Functions
+ */
+
+/**
+ * netlbl_netlink_snd - Send a NetLabel message
+ * @skb: NetLabel message
+ * @pid: destination PID
+ *
+ * Description:
+ * Sends a unicast NetLabel message over the NETLINK socket.
+ *
+ */
+int netlbl_netlink_snd(struct sk_buff *skb, const u32 pid)
+{
+ /* PM - verify that this is really what we want */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ return nlmsg_unicast(netlbl_nl, skb, pid);
+}
+
+/**
+ * netlbl_netlink_snd - Send a NetLabel message
+ * @skb: NetLabel message
+ * @pid: sending PID
+ * @group: multicast group id
+ *
+ * Description:
+ * Sends a multicast NetLabel message over the NETLINK socket to all members
+ * of @group except @pid.
+ *
+ */
+int netlbl_netlink_snd_multicast(struct sk_buff *skb,
+ const u32 pid,
+ const u32 group)
+{
+ /* PM - verify that this is really what we want */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ return nlmsg_multicast(netlbl_nl, skb, pid, group);
+}
diff -purN linux-2.6.16.i686/net/netlabel/netlabel_user.h linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_user.h
--- linux-2.6.16.i686/net/netlabel/netlabel_user.h 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/net/netlabel/netlabel_user.h 2006-06-13 11:19:59.000000000 -0400
@@ -0,0 +1,42 @@
+/*
+ * NetLabel NETLINK Interface
+ *
+ * This file defines the NETLINK interface for the NetLabel system. The
+ * NetLabel system manages static and dynamic label mappings for network
+ * protocols such as CIPSO and RIPSO.
+ *
+ * Author: Paul Moore <paul moore hp com>
+ *
+ */
+
+/*
+ * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
+ * the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifndef _NETLABEL_USER_H
+#define _NETLABEL_USER_H
+
+/* NetLabel NETLINK I/O functions */
+int netlbl_netlink_init(void) __init;
+void netlbl_netlink_exit(void) __exit;
+int netlbl_netlink_snd(struct sk_buff *skb, const u32 pid);
+int netlbl_netlink_snd_multicast(struct sk_buff *skb,
+ const u32 pid,
+ const u32 group);
+
+#endif
diff -purN linux-2.6.16.i686/security/selinux/hooks.c linux-2.6.16.i686-netlabel_06132006/security/selinux/hooks.c
--- linux-2.6.16.i686/security/selinux/hooks.c 2006-06-13 10:47:10.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/hooks.c 2006-06-13 11:19:59.000000000 -0400
@@ -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,
@@ -69,6 +71,7 @@
#include <linux/sysctl.h>
#include <linux/audit.h>
#include <linux/string.h>
+#include <net/netlabel.h>
#include "avc.h"
#include "objsec.h"
@@ -2935,6 +2938,16 @@ static void selinux_socket_post_create(s
isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
isec->initialized = 1;
+#ifdef CONFIG_NETLABEL
+ if (family == PF_INET)
+ /* PM - this will throw errors unless netlabel is configured
+ so if you enable netlabel you must make sure you configure
+ it early in your init scripts (i.e. before you bring up
+ networking) ... or should we just drop the BUG_ON() and
+ audit the failure? */
+ BUG_ON(security_netlbl_socket_setsid(sock, isec->sid));
+#endif /* CONFIG_NETLABEL */
+
return;
}
@@ -3113,6 +3126,19 @@ static int selinux_socket_accept(struct
return 0;
}
+#ifdef CONFIG_NETLABEL
+static void selinux_socket_post_accept(struct socket *sock,
+ struct socket *newsock)
+{
+ if (newsock->sk != NULL && newsock->sk->sk_family == PF_INET)
+ /* PM - see my comments in the socket_post_create() hook, the
+ problem is not quite as bad here since you have already
+ created at least one pf_inet socket and gotten traffic on
+ it but the core question still remains: BUG() or audit? */
+ BUG_ON(security_netlbl_socket_accept(sock, newsock));
+}
+#endif /* CONFIG_NETLABEL */
+
static int selinux_socket_sendmsg(struct socket *sock, struct msghdr *msg,
int size)
{
@@ -3221,6 +3247,9 @@ static int selinux_socket_sock_rcv_skb(s
struct socket *sock;
struct net_device *dev;
struct avc_audit_data ad;
+#ifdef CONFIG_NETLABEL
+ u32 netlbl_sid;
+#endif
family = sk->sk_family;
if (family != PF_INET && family != PF_INET6)
@@ -3270,6 +3299,7 @@ static int selinux_socket_sock_rcv_skb(s
default:
netif_perm = NETIF__RAWIP_RECV;
node_perm = NODE__RAWIP_RECV;
+ recv_perm = RAWIP_SOCKET__RECV_MSG;
break;
}
@@ -3294,7 +3324,7 @@ static int selinux_socket_sock_rcv_skb(s
if (err)
goto out;
- if (recv_perm) {
+ if (recv_perm != 0 && recv_perm != RAWIP_SOCKET__RECV_MSG) {
u32 port_sid;
/* Fixme: make this more efficient */
@@ -3306,10 +3336,46 @@ 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_xfrm_sock_rcv_skb(sock_sid, skb);
+#ifdef CONFIG_NETLABEL
+ if (err == 0)
+ goto out;
+
+ err = security_netlbl_skbuff_getsid(skb, sock_sid, &netlbl_sid);
+ if (err)
+ goto out;
+
+ if (netlbl_sid == SECINITSID_UNLABELED)
+ /* PM - this may look strange (it is) but it is here to
+ preserve backward compatability */
+ err = avc_has_perm(sock_sid,
+ SECINITSID_UNLABELED,
+ SECCLASS_ASSOCIATION,
+ ASSOCIATION__RECVFROM,
+ NULL);
+ else
+ err = avc_has_perm(sock_sid,
+ netlbl_sid,
+ sock_class,
+ recv_perm,
+ &ad);
+
+ if (err)
+ netlbl_skbuff_err(skb, err);
+#else
+ if (err)
+ goto out;
+
+ err = avc_has_perm(sock_sid,
+ SECINITSID_UNLABELED,
+ SECCLASS_ASSOCIATION,
+ ASSOCIATION__RECVFROM,
+ NULL);
+#endif /* CONFIG_NETLABEL */
out:
return err;
@@ -3334,7 +3400,11 @@ static int selinux_socket_getpeersec_str
}
else if (isec->sclass == SECCLASS_TCP_SOCKET) {
peer_sid = selinux_socket_getpeer_stream(sock->sk);
-
+#ifdef CONFIG_NETLABEL
+ if (peer_sid == SECSID_NULL &&
+ security_netlbl_socket_peeksid(sock, &peer_sid) != 0)
+ peer_sid = SECSID_NULL;
+#endif
if (peer_sid == SECSID_NULL) {
err = -ENOPROTOOPT;
goto out;
@@ -4353,6 +4423,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,
diff -purN linux-2.6.16.i686/security/selinux/include/av_inherit.h linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_inherit.h
--- linux-2.6.16.i686/security/selinux/include/av_inherit.h 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_inherit.h 2006-06-13 11:19:59.000000000 -0400
@@ -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)
diff -purN linux-2.6.16.i686/security/selinux/include/av_permissions.h linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_permissions.h
--- linux-2.6.16.i686/security/selinux/include/av_permissions.h 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_permissions.h 2006-06-13 11:19:59.000000000 -0400
@@ -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
diff -purN linux-2.6.16.i686/security/selinux/include/av_perm_to_string.h linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_perm_to_string.h
--- linux-2.6.16.i686/security/selinux/include/av_perm_to_string.h 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/include/av_perm_to_string.h 2006-06-13 11:19:59.000000000 -0400
@@ -239,3 +239,5 @@
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")
+
diff -purN linux-2.6.16.i686/security/selinux/include/flask.h linux-2.6.16.i686-netlabel_06132006/security/selinux/include/flask.h
--- linux-2.6.16.i686/security/selinux/include/flask.h 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/include/flask.h 2006-06-13 11:20:00.000000000 -0400
@@ -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
diff -purN linux-2.6.16.i686/security/selinux/include/security.h linux-2.6.16.i686-netlabel_06132006/security/selinux/include/security.h
--- linux-2.6.16.i686/security/selinux/include/security.h 2006-06-13 10:46:59.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/include/security.h 2006-06-13 11:20:00.000000000 -0400
@@ -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 */
@@ -91,5 +93,12 @@ int security_fs_use(const char *fstype,
int security_genfs_sid(const char *fstype, char *name, u16 sclass,
u32 *sid);
+int security_netlbl_socket_peeksid(struct socket *sock, u32 *sid);
+int security_netlbl_skbuff_getsid(struct sk_buff *skb,
+ const u32 base_sid,
+ u32 *sid);
+int security_netlbl_socket_setsid(const struct socket *sock, const u32 sid);
+int security_netlbl_socket_accept(struct socket *sock, struct socket *newsock);
+
#endif /* _SELINUX_SECURITY_H_ */
diff -purN linux-2.6.16.i686/security/selinux/nlmsgtab.c linux-2.6.16.i686-netlabel_06132006/security/selinux/nlmsgtab.c
--- linux-2.6.16.i686/security/selinux/nlmsgtab.c 2006-06-13 10:47:09.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/nlmsgtab.c 2006-06-13 11:20:00.000000000 -0400
@@ -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"
@@ -31,92 +32,101 @@ struct nlmsg_perm
static struct nlmsg_perm nlmsg_route_perms[] =
{
- { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETLINK, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_SETLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_NEWADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETADDR, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETROUTE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETRULE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETQDISC, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_DELACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETACTION, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_NEWPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
- { RTM_GETPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_GETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
- { RTM_SETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_NEWLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETLINK, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_SETLINK, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_NEWADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELADDR, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETADDR, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELROUTE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETROUTE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETNEIGH, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETRULE, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELQDISC, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETQDISC, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETTCLASS, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETTFILTER, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_DELACTION, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETACTION, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_NEWPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
+ { RTM_GETPREFIX, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_GETMULTICAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_GETANYCAST, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_GETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_READ },
+ { RTM_SETNEIGHTBL, NETLINK_ROUTE_SOCKET__NLMSG_WRITE },
};
static struct nlmsg_perm nlmsg_firewall_perms[] =
{
- { IPQM_MODE, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
- { IPQM_VERDICT, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
+ { IPQM_MODE, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
+ { IPQM_VERDICT, NETLINK_FIREWALL_SOCKET__NLMSG_WRITE },
};
static struct nlmsg_perm nlmsg_tcpdiag_perms[] =
{
- { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
- { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
+ { TCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
+ { DCCPDIAG_GETSOCK, NETLINK_TCPDIAG_SOCKET__NLMSG_READ },
};
static struct nlmsg_perm nlmsg_xfrm_perms[] =
{
- { XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_GETSA, NETLINK_XFRM_SOCKET__NLMSG_READ },
- { XFRM_MSG_NEWPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_DELPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_GETPOLICY, NETLINK_XFRM_SOCKET__NLMSG_READ },
- { XFRM_MSG_ALLOCSPI, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_ACQUIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_EXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_UPDPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_UPDSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_POLEXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_FLUSHSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
- { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_NEWSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_DELSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_GETSA, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_NEWPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_DELPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_GETPOLICY, NETLINK_XFRM_SOCKET__NLMSG_READ },
+ { XFRM_MSG_ALLOCSPI, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_ACQUIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_EXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_UPDPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_UPDSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_POLEXPIRE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_FLUSHSA, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_FLUSHPOLICY, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_NEWAE, NETLINK_XFRM_SOCKET__NLMSG_WRITE },
+ { XFRM_MSG_GETAE, NETLINK_XFRM_SOCKET__NLMSG_READ },
};
static struct nlmsg_perm nlmsg_audit_perms[] =
{
- { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
- { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
- { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_LIST_RULES, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
- { AUDIT_ADD_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
- { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ },
- { AUDIT_WATCH_INS, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_WATCH_REM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
- { AUDIT_WATCH_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+ { AUDIT_GET, NETLINK_AUDIT_SOCKET__NLMSG_READ },
+ { AUDIT_SET, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_LIST, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+ { AUDIT_ADD, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_DEL, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_LIST_RULES, NETLINK_AUDIT_SOCKET__NLMSG_READPRIV },
+ { AUDIT_ADD_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_DEL_RULE, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_USER, NETLINK_AUDIT_SOCKET__NLMSG_RELAY },
+ { AUDIT_SIGNAL_INFO, NETLINK_AUDIT_SOCKET__NLMSG_READ },
+ { AUDIT_WATCH_INS, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { AUDIT_WATCH_REM, NETLINK_AUDIT_SOCKET__NLMSG_WRITE },
+ { 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)
{
int i, err = -EINVAL;
@@ -169,6 +179,19 @@ int selinux_nlmsg_lookup(u16 sclass, u16
}
break;
+ case SECCLASS_NETLINK_NETLABEL_SOCKET:
+ /* PM - This is really a poor fit right now as NetLabel uses
+ the nlmsg_type value to specify the "class" of NetLabel
+ message (i.e. management, cipso, etc.). One way to fix
+ this would be to refactor the NetLabel netlink API so
+ that it uses the nlmsg_type in a way that more closely
+ resembles the other netlink consumers, however, that is
+ going to require a non-trivial rework at this point so lets
+ just leave it as is right now unless somebody complains. */
+ 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;
diff -purN linux-2.6.16.i686/security/selinux/ss/ebitmap.c linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/ebitmap.c
--- linux-2.6.16.i686/security/selinux/ss/ebitmap.c 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/ebitmap.c 2006-06-13 11:20:00.000000000 -0400
@@ -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;
diff -purN linux-2.6.16.i686/security/selinux/ss/ebitmap.h linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/ebitmap.h
--- linux-2.6.16.i686/security/selinux/ss/ebitmap.h 2006-03-20 00:53:29.000000000 -0500
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/ebitmap.h 2006-06-13 11:20:00.000000000 -0400
@@ -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);
diff -purN linux-2.6.16.i686/security/selinux/ss/mls.c linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/mls.c
--- linux-2.6.16.i686/security/selinux/ss/mls.c 2006-06-13 10:46:59.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/mls.c 2006-06-13 11:20:00.000000000 -0400
@@ -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;
+}
diff -purN linux-2.6.16.i686/security/selinux/ss/mls.h linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/mls.h
--- linux-2.6.16.i686/security/selinux/ss/mls.h 2006-06-13 10:46:59.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/mls.h 2006-06-13 11:20:00.000000000 -0400
@@ -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 */
diff -purN linux-2.6.16.i686/security/selinux/ss/services.c linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/services.c
--- linux-2.6.16.i686/security/selinux/ss/services.c 2006-06-13 10:47:10.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/ss/services.c 2006-06-13 11:20:00.000000000 -0400
@@ -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,8 @@
#include <linux/sched.h>
#include <linux/audit.h>
#include <linux/mutex.h>
+#include <net/netlabel.h>
+#include <net/sock.h>
#include "flask.h"
#include "avc.h"
@@ -40,6 +47,7 @@
#include "services.h"
#include "conditional.h"
#include "mls.h"
+#include "objsec.h"
extern void selnl_notify_policyload(u32 seqno);
unsigned int policydb_loaded_version;
@@ -778,6 +786,40 @@ int security_context_to_sid_default(char
sid, def_sid);
}
+/**
+ * security_context_export_type - 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 security_context_export_type(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;
+}
+
static int compute_sid_handle_invalid_context(
struct context *scontext,
struct context *tcontext,
@@ -1241,6 +1283,9 @@ int security_load_policy(void *data, siz
selinux_complete_init();
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
+#ifdef CONFIG_NETLABEL
+ netlbl_cache_invalidate();
+#endif
return 0;
}
@@ -1295,6 +1340,9 @@ int security_load_policy(void *data, siz
avc_ss_reset(seqno);
selnl_notify_policyload(seqno);
+#ifdef CONFIG_NETLABEL
+ netlbl_cache_invalidate();
+#endif
return 0;
@@ -1817,6 +1865,373 @@ out:
return rc;
}
+#ifdef CONFIG_NETLABEL
+/*
+ * 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;
+};
+
+/**
+ * security_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 security_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);
+}
+
+/**
+ * security_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 inline void security_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_failure;
+
+ if (ebitmap_cpy(&cache->data.mls_label.cat,
+ &ctx->range.level[0].cat) != 0)
+ goto netlbl_cache_add_failure;
+ cache->data.mls_label.sens = ctx->range.level[0].sens;
+ cache->type = NETLBL_CACHE_T_MLSLBL;
+
+ netlbl_secattr_init(&secattr);
+ secattr.cache.free = security_netlbl_cache_free;
+ secattr.cache.data = (void *)cache;
+ secattr.set_cache = 1;
+
+ if (netlbl_cache_add(skb, &secattr) != 0)
+ goto netlbl_cache_add_failure;
+
+ return;
+
+netlbl_cache_add_failure:
+ netlbl_secattr_destroy(&secattr);
+ if (cache)
+ security_netlbl_cache_free(cache);
+}
+
+/**
+ * security_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 inline int security_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:
+ BUG();
+ }
+ } 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)
+ security_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;
+}
+
+/**
+ * security_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.
+ *
+ */
+int security_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;
+
+ if (!ss_initialized)
+ return 0;
+
+ netlbl_secattr_init(&secattr);
+
+ ret_val = netlbl_socket_peekattr(sock, &secattr);
+ if (ret_val == 0)
+ ret_val = security_netlbl_secattr_to_sid(NULL,
+ &secattr,
+ isec->sid,
+ sid);
+
+ secattr.set_cache = 0;
+ netlbl_secattr_destroy(&secattr);
+
+ return ret_val;
+}
+
+/**
+ * security_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.
+ *
+ */
+int security_netlbl_skbuff_getsid(struct sk_buff *skb,
+ const u32 base_sid,
+ u32 *sid)
+{
+ int ret_val;
+ struct netlbl_lsm_secattr secattr;
+
+ if (!ss_initialized)
+ return 0;
+
+ netlbl_secattr_init(&secattr);
+
+ ret_val = netlbl_skbuff_getattr(skb, &secattr);
+ if (ret_val == 0)
+ ret_val = security_netlbl_secattr_to_sid(skb,
+ &secattr,
+ base_sid,
+ sid);
+
+ secattr.set_cache = 0;
+ netlbl_secattr_destroy(&secattr);
+
+ return ret_val;
+}
+
+/**
+ * security_netlbl_socket_setsid - Label a socket using the NetLabel mechanism
+ * @sock: the socket to label
+ * @sid: the SID to use as the basis for the label
+ *
+ * Description:
+ * Attempt to label a socket using the NetLabel mechanism using the given
+ * SID. Returns zero values on success, negative values on failure.
+ *
+ */
+int security_netlbl_socket_setsid(const struct socket *sock, const u32 sid)
+{
+ int ret_val;
+ struct netlbl_lsm_secattr secattr;
+ struct context *ctx;
+
+ if (!ss_initialized)
+ return 0;
+
+ ctx = sidtab_search(&sidtab, sid);
+ if (ctx != NULL) {
+ netlbl_secattr_init(&secattr);
+
+ if (security_context_export_type(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);
+ netlbl_secattr_destroy(&secattr);
+ } else
+ ret_val = -ENOENT;
+
+ return ret_val;
+}
+
+/**
+ * security_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. Returns zero values on success,
+ * negative values on failure.
+ *
+ */
+int security_netlbl_socket_accept(struct socket *sock, struct socket *newsock)
+{
+ int ret_val;
+ struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+ struct netlbl_lsm_secattr secattr;
+ u32 newsock_sid;
+ u16 sock_class;
+ u32 relabelto_perm;
+
+ if (!ss_initialized)
+ return 0;
+ netlbl_secattr_init(&secattr);
+
+ ret_val = netlbl_socket_getattr(newsock, &secattr);
+ if (ret_val != 0)
+ goto netlbl_socket_accept_return;
+ ret_val = security_netlbl_secattr_to_sid(NULL,
+ &secattr,
+ isec->sid,
+ &newsock_sid);
+ if (ret_val != 0 || newsock_sid == SECINITSID_UNLABELED)
+ goto netlbl_socket_accept_return;
+
+ sock_class = isec->sclass;
+ switch (sock_class) {
+ case SECCLASS_UDP_SOCKET:
+ relabelto_perm = UDP_SOCKET__RELABELTO;
+ break;
+ case SECCLASS_TCP_SOCKET:
+ relabelto_perm = TCP_SOCKET__RELABELTO;
+ break;
+ default:
+ relabelto_perm = RAWIP_SOCKET__RELABELTO;
+ }
+
+ /* PM - should we have a "RELABELFROM" check too? */
+ /* PM - i suspect we should audit this socket relabel */
+ ret_val = avc_has_perm(isec->sid,
+ newsock_sid,
+ sock_class,
+ relabelto_perm,
+ NULL);
+ if (ret_val != 0)
+ goto netlbl_socket_accept_return;
+
+ isec = SOCK_INODE(newsock)->i_security;
+ isec->sid = newsock_sid;
+
+netlbl_socket_accept_return:
+ secattr.set_cache = 0;
+ netlbl_secattr_destroy(&secattr);
+
+ return security_netlbl_socket_setsid(newsock, isec->sid);
+}
+#endif /* CONFIG_NETLABEL */
+
struct selinux_audit_rule {
u32 au_seqno;
struct context au_ctxt;
diff -purN linux-2.6.16.i686/security/selinux/xfrm.c linux-2.6.16.i686-netlabel_06132006/security/selinux/xfrm.c
--- linux-2.6.16.i686/security/selinux/xfrm.c 2006-06-13 10:46:59.000000000 -0400
+++ linux-2.6.16.i686-netlabel_06132006/security/selinux/xfrm.c 2006-06-13 11:20:00.000000000 -0400
@@ -295,13 +295,13 @@ u32 selinux_socket_getpeer_dgram(struct
/*
* LSM hook that controls access to unlabelled packets. If
* a xfrm_state is authorizable (defined by macro) then it was
- * already authorized by the IPSec process. If not, then
- * we need to check for unlabelled access since this may not have
- * gone thru the IPSec process.
+ * already authorized by the IPsec process. Return zero when the
+ * packet has been approved by the IPsec process, negative values
+ * otherwise.
*/
int selinux_xfrm_sock_rcv_skb(u32 isec_sid, struct sk_buff *skb)
{
- int i, rc = 0;
+ int i;
struct sec_path *sp;
sp = skb->sp;
@@ -317,21 +317,11 @@ int selinux_xfrm_sock_rcv_skb(u32 isec_s
struct xfrm_state *x = sp->xvec[i];
if (x && selinux_authorizable_xfrm(x))
- goto accept;
+ return 0;
}
}
- /* check SELinux sock for unlabelled access */
- rc = avc_has_perm(isec_sid, SECINITSID_UNLABELED, SECCLASS_ASSOCIATION,
- ASSOCIATION__RECVFROM, NULL);
- if (rc)
- goto drop;
-
-accept:
- return 0;
-
-drop:
- return rc;
+ return -ENOMSG;
}
/*
[Date Prev][Date Next] [Thread Prev][Thread Next]
[Thread Index]
[Date Index]
[Author Index]