Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
0da939b0
Commit
0da939b0
authored
Oct 11, 2008
by
James Morris
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://git.infradead.org/users/pcmoore/lblnet-2.6_next
into next
parents
4bdec11f
d91d4079
Changes
22
Show whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
2732 additions
and
972 deletions
+2732
-972
include/net/cipso_ipv4.h
include/net/cipso_ipv4.h
+41
-14
include/net/netlabel.h
include/net/netlabel.h
+33
-18
net/ipv4/cipso_ipv4.c
net/ipv4/cipso_ipv4.c
+461
-195
net/ipv4/ip_options.c
net/ipv4/ip_options.c
+1
-1
net/netlabel/Makefile
net/netlabel/Makefile
+2
-1
net/netlabel/netlabel_addrlist.c
net/netlabel/netlabel_addrlist.c
+388
-0
net/netlabel/netlabel_addrlist.h
net/netlabel/netlabel_addrlist.h
+189
-0
net/netlabel/netlabel_cipso_v4.c
net/netlabel/netlabel_cipso_v4.c
+94
-42
net/netlabel/netlabel_cipso_v4.h
net/netlabel/netlabel_cipso_v4.h
+6
-4
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_domainhash.c
+304
-89
net/netlabel/netlabel_domainhash.h
net/netlabel/netlabel_domainhash.h
+38
-2
net/netlabel/netlabel_kapi.c
net/netlabel/netlabel_kapi.c
+192
-80
net/netlabel/netlabel_mgmt.c
net/netlabel/netlabel_mgmt.c
+304
-106
net/netlabel/netlabel_mgmt.h
net/netlabel/netlabel_mgmt.h
+54
-5
net/netlabel/netlabel_unlabeled.c
net/netlabel/netlabel_unlabeled.c
+153
-303
security/selinux/hooks.c
security/selinux/hooks.c
+169
-60
security/selinux/include/netlabel.h
security/selinux/include/netlabel.h
+41
-3
security/selinux/include/objsec.h
security/selinux/include/objsec.h
+6
-3
security/selinux/netlabel.c
security/selinux/netlabel.c
+239
-41
security/selinux/ss/services.c
security/selinux/ss/services.c
+10
-3
security/smack/smack_lsm.c
security/smack/smack_lsm.c
+4
-1
security/smack/smackfs.c
security/smack/smackfs.c
+3
-1
No files found.
include/net/cipso_ipv4.h
View file @
0da939b0
...
...
@@ -40,11 +40,12 @@
#include <linux/net.h>
#include <linux/skbuff.h>
#include <net/netlabel.h>
#include <asm/atomic.h>
/* known doi values */
#define CIPSO_V4_DOI_UNKNOWN 0x00000000
/* tag types */
/*
standard
tag types */
#define CIPSO_V4_TAG_INVALID 0
#define CIPSO_V4_TAG_RBITMAP 1
#define CIPSO_V4_TAG_ENUM 2
...
...
@@ -52,10 +53,14 @@
#define CIPSO_V4_TAG_PBITMAP 6
#define CIPSO_V4_TAG_FREEFORM 7
/* non-standard tag types (tags > 127) */
#define CIPSO_V4_TAG_LOCAL 128
/* doi mapping types */
#define CIPSO_V4_MAP_UNKNOWN 0
#define CIPSO_V4_MAP_
STD
1
#define CIPSO_V4_MAP_
TRANS
1
#define CIPSO_V4_MAP_PASS 2
#define CIPSO_V4_MAP_LOCAL 3
/* limits */
#define CIPSO_V4_MAX_REM_LVLS 255
...
...
@@ -79,10 +84,9 @@ struct cipso_v4_doi {
}
map
;
u8
tags
[
CIPSO_V4_TAG_MAXCNT
];
u32
valid
;
atomic_t
refcount
;
struct
list_head
list
;
struct
rcu_head
rcu
;
struct
list_head
dom_list
;
};
/* Standard CIPSO mapping table */
...
...
@@ -128,25 +132,26 @@ extern int cipso_v4_rbm_strictvalid;
#ifdef CONFIG_NETLABEL
int
cipso_v4_doi_add
(
struct
cipso_v4_doi
*
doi_def
);
int
cipso_v4_doi_remove
(
u32
doi
,
struct
netlbl_audit
*
audit_info
,
void
(
*
callback
)
(
struct
rcu_head
*
head
));
void
cipso_v4_doi_free
(
struct
cipso_v4_doi
*
doi_def
);
int
cipso_v4_doi_remove
(
u32
doi
,
struct
netlbl_audit
*
audit_info
);
struct
cipso_v4_doi
*
cipso_v4_doi_getdef
(
u32
doi
);
void
cipso_v4_doi_putdef
(
struct
cipso_v4_doi
*
doi_def
);
int
cipso_v4_doi_walk
(
u32
*
skip_cnt
,
int
(
*
callback
)
(
struct
cipso_v4_doi
*
doi_def
,
void
*
arg
),
void
*
cb_arg
);
int
cipso_v4_doi_domhsh_add
(
struct
cipso_v4_doi
*
doi_def
,
const
char
*
domain
);
int
cipso_v4_doi_domhsh_remove
(
struct
cipso_v4_doi
*
doi_def
,
const
char
*
domain
);
#else
static
inline
int
cipso_v4_doi_add
(
struct
cipso_v4_doi
*
doi_def
)
{
return
-
ENOSYS
;
}
static
inline
void
cipso_v4_doi_free
(
struct
cipso_v4_doi
*
doi_def
)
{
return
;
}
static
inline
int
cipso_v4_doi_remove
(
u32
doi
,
struct
netlbl_audit
*
audit_info
,
void
(
*
callback
)
(
struct
rcu_head
*
head
))
struct
netlbl_audit
*
audit_info
)
{
return
0
;
}
...
...
@@ -206,10 +211,15 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway);
int
cipso_v4_sock_setattr
(
struct
sock
*
sk
,
const
struct
cipso_v4_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
);
void
cipso_v4_sock_delattr
(
struct
sock
*
sk
);
int
cipso_v4_sock_getattr
(
struct
sock
*
sk
,
struct
netlbl_lsm_secattr
*
secattr
);
int
cipso_v4_skbuff_setattr
(
struct
sk_buff
*
skb
,
const
struct
cipso_v4_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
);
int
cipso_v4_skbuff_delattr
(
struct
sk_buff
*
skb
);
int
cipso_v4_skbuff_getattr
(
const
struct
sk_buff
*
skb
,
struct
netlbl_lsm_secattr
*
secattr
);
int
cipso_v4_validate
(
unsigned
char
**
option
);
int
cipso_v4_validate
(
const
struct
sk_buff
*
skb
,
unsigned
char
**
option
);
#else
static
inline
void
cipso_v4_error
(
struct
sk_buff
*
skb
,
int
error
,
...
...
@@ -225,19 +235,36 @@ static inline int cipso_v4_sock_setattr(struct sock *sk,
return
-
ENOSYS
;
}
static
inline
void
cipso_v4_sock_delattr
(
struct
sock
*
sk
)
{
}
static
inline
int
cipso_v4_sock_getattr
(
struct
sock
*
sk
,
struct
netlbl_lsm_secattr
*
secattr
)
{
return
-
ENOSYS
;
}
static
inline
int
cipso_v4_skbuff_setattr
(
struct
sk_buff
*
skb
,
const
struct
cipso_v4_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
return
-
ENOSYS
;
}
static
inline
int
cipso_v4_skbuff_delattr
(
struct
sk_buff
*
skb
)
{
return
-
ENOSYS
;
}
static
inline
int
cipso_v4_skbuff_getattr
(
const
struct
sk_buff
*
skb
,
struct
netlbl_lsm_secattr
*
secattr
)
{
return
-
ENOSYS
;
}
static
inline
int
cipso_v4_validate
(
unsigned
char
**
option
)
static
inline
int
cipso_v4_validate
(
const
struct
sk_buff
*
skb
,
unsigned
char
**
option
)
{
return
-
ENOSYS
;
}
...
...
include/net/netlabel.h
View file @
0da939b0
...
...
@@ -9,7 +9,7 @@
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -72,8 +72,10 @@ struct cipso_v4_doi;
/* NetLabel NETLINK protocol version
* 1: initial version
* 2: added static labels for unlabeled connections
* 3: network selectors added to the NetLabel/LSM domain mapping and the
* CIPSO_V4_MAP_LOCAL CIPSO mapping was added
*/
#define NETLBL_PROTO_VERSION
2
#define NETLBL_PROTO_VERSION
3
/* NetLabel NETLINK types/families */
#define NETLBL_NLTYPE_NONE 0
...
...
@@ -87,6 +89,8 @@ struct cipso_v4_doi;
#define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6"
#define NETLBL_NLTYPE_UNLABELED 5
#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL"
#define NETLBL_NLTYPE_ADDRSELECT 6
#define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL"
/*
* NetLabel - Kernel API for accessing the network packet label mappings.
...
...
@@ -200,7 +204,7 @@ struct netlbl_lsm_secattr {
u32
type
;
char
*
domain
;
struct
netlbl_lsm_cache
*
cache
;
union
{
struct
{
struct
{
struct
netlbl_lsm_secattr_catmap
*
cat
;
u32
lvl
;
...
...
@@ -352,12 +356,9 @@ static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
int
netlbl_cfg_map_del
(
const
char
*
domain
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_cfg_unlbl_add_map
(
const
char
*
domain
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_cfg_cipsov4_add
(
struct
cipso_v4_doi
*
doi_def
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_cfg_cipsov4_add_map
(
struct
cipso_v4_doi
*
doi_def
,
const
char
*
domain
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_cfg_cipsov4_del
(
u32
doi
,
struct
netlbl_audit
*
audit_info
);
/*
* LSM security attribute operations
...
...
@@ -380,12 +381,19 @@ int netlbl_secattr_catmap_setrng(struct netlbl_lsm_secattr_catmap *catmap,
int
netlbl_enabled
(
void
);
int
netlbl_sock_setattr
(
struct
sock
*
sk
,
const
struct
netlbl_lsm_secattr
*
secattr
);
void
netlbl_sock_delattr
(
struct
sock
*
sk
);
int
netlbl_sock_getattr
(
struct
sock
*
sk
,
struct
netlbl_lsm_secattr
*
secattr
);
int
netlbl_conn_setattr
(
struct
sock
*
sk
,
struct
sockaddr
*
addr
,
const
struct
netlbl_lsm_secattr
*
secattr
);
int
netlbl_skbuff_setattr
(
struct
sk_buff
*
skb
,
u16
family
,
const
struct
netlbl_lsm_secattr
*
secattr
);
int
netlbl_skbuff_getattr
(
const
struct
sk_buff
*
skb
,
u16
family
,
struct
netlbl_lsm_secattr
*
secattr
);
void
netlbl_skbuff_err
(
struct
sk_buff
*
skb
,
int
error
);
void
netlbl_skbuff_err
(
struct
sk_buff
*
skb
,
int
error
,
int
gateway
);
/*
* LSM label mapping cache operations
...
...
@@ -404,22 +412,12 @@ static inline int netlbl_cfg_unlbl_add_map(const char *domain,
{
return
-
ENOSYS
;
}
static
inline
int
netlbl_cfg_cipsov4_add
(
struct
cipso_v4_doi
*
doi_def
,
struct
netlbl_audit
*
audit_info
)
{
return
-
ENOSYS
;
}
static
inline
int
netlbl_cfg_cipsov4_add_map
(
struct
cipso_v4_doi
*
doi_def
,
const
char
*
domain
,
struct
netlbl_audit
*
audit_info
)
{
return
-
ENOSYS
;
}
static
inline
int
netlbl_cfg_cipsov4_del
(
u32
doi
,
struct
netlbl_audit
*
audit_info
)
{
return
-
ENOSYS
;
}
static
inline
int
netlbl_secattr_catmap_walk
(
struct
netlbl_lsm_secattr_catmap
*
catmap
,
u32
offset
)
...
...
@@ -456,18 +454,35 @@ static inline int netlbl_sock_setattr(struct sock *sk,
{
return
-
ENOSYS
;
}
static
inline
void
netlbl_sock_delattr
(
struct
sock
*
sk
)
{
}
static
inline
int
netlbl_sock_getattr
(
struct
sock
*
sk
,
struct
netlbl_lsm_secattr
*
secattr
)
{
return
-
ENOSYS
;
}
static
inline
int
netlbl_conn_setattr
(
struct
sock
*
sk
,
struct
sockaddr
*
addr
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
return
-
ENOSYS
;
}
static
inline
int
netlbl_skbuff_setattr
(
struct
sk_buff
*
skb
,
u16
family
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
return
-
ENOSYS
;
}
static
inline
int
netlbl_skbuff_getattr
(
const
struct
sk_buff
*
skb
,
u16
family
,
struct
netlbl_lsm_secattr
*
secattr
)
{
return
-
ENOSYS
;
}
static
inline
void
netlbl_skbuff_err
(
struct
sk_buff
*
skb
,
int
error
)
static
inline
void
netlbl_skbuff_err
(
struct
sk_buff
*
skb
,
int
error
,
int
gateway
)
{
return
;
}
...
...
net/ipv4/cipso_ipv4.c
View file @
0da939b0
...
...
@@ -13,7 +13,7 @@
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -47,17 +47,7 @@
#include <asm/bug.h>
#include <asm/unaligned.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
...
...
@@ -119,6 +109,19 @@ int cipso_v4_rbm_strictvalid = 1;
* be omitted. */
#define CIPSO_V4_TAG_RNG_CAT_MAX 8
/* Base length of the local tag (non-standard tag).
* Tag definition (may change between kernel versions)
*
* 0 8 16 24 32
* +----------+----------+----------+----------+
* | 10000000 | 00000110 | 32-bit secid value |
* +----------+----------+----------+----------+
* | in (host byte order)|
* +----------+----------+
*
*/
#define CIPSO_V4_TAG_LOC_BLEN 6
/*
* Helper Functions
*/
...
...
@@ -193,25 +196,6 @@ static void cipso_v4_bitmap_setbit(unsigned char *bitmap,
bitmap
[
byte_spot
]
&=
~
bitmask
;
}
/**
* cipso_v4_doi_domhsh_free - Frees a domain list entry
* @entry: the entry's RCU field
*
* Description:
* This function is designed to be used as a callback to the call_rcu()
* function so that the memory allocated to a domain list entry can be released
* safely.
*
*/
static
void
cipso_v4_doi_domhsh_free
(
struct
rcu_head
*
entry
)
{
struct
cipso_v4_domhsh_entry
*
ptr
;
ptr
=
container_of
(
entry
,
struct
cipso_v4_domhsh_entry
,
rcu
);
kfree
(
ptr
->
domain
);
kfree
(
ptr
);
}
/**
* cipso_v4_cache_entry_free - Frees a cache entry
* @entry: the entry to free
...
...
@@ -457,7 +441,7 @@ static struct cipso_v4_doi *cipso_v4_doi_search(u32 doi)
struct
cipso_v4_doi
*
iter
;
list_for_each_entry_rcu
(
iter
,
&
cipso_v4_doi_list
,
list
)
if
(
iter
->
doi
==
doi
&&
iter
->
valid
)
if
(
iter
->
doi
==
doi
&&
atomic_read
(
&
iter
->
refcount
)
)
return
iter
;
return
NULL
;
}
...
...
@@ -496,14 +480,17 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
if
(
doi_def
->
type
!=
CIPSO_V4_MAP_PASS
)
return
-
EINVAL
;
break
;
case
CIPSO_V4_TAG_LOCAL
:
if
(
doi_def
->
type
!=
CIPSO_V4_MAP_LOCAL
)
return
-
EINVAL
;
break
;
default:
return
-
EINVAL
;
}
}
doi_def
->
valid
=
1
;
atomic_set
(
&
doi_def
->
refcount
,
1
)
;
INIT_RCU_HEAD
(
&
doi_def
->
rcu
);
INIT_LIST_HEAD
(
&
doi_def
->
dom_list
);
spin_lock
(
&
cipso_v4_doi_list_lock
);
if
(
cipso_v4_doi_search
(
doi_def
->
doi
)
!=
NULL
)
...
...
@@ -518,60 +505,130 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
return
-
EEXIST
;
}
/**
* cipso_v4_doi_free - Frees a DOI definition
* @entry: the entry's RCU field
*
* Description:
* This function frees all of the memory associated with a DOI definition.
*
*/
void
cipso_v4_doi_free
(
struct
cipso_v4_doi
*
doi_def
)
{
if
(
doi_def
==
NULL
)
return
;
switch
(
doi_def
->
type
)
{
case
CIPSO_V4_MAP_TRANS
:
kfree
(
doi_def
->
map
.
std
->
lvl
.
cipso
);
kfree
(
doi_def
->
map
.
std
->
lvl
.
local
);
kfree
(
doi_def
->
map
.
std
->
cat
.
cipso
);
kfree
(
doi_def
->
map
.
std
->
cat
.
local
);
break
;
}
kfree
(
doi_def
);
}
/**
* cipso_v4_doi_free_rcu - Frees a DOI definition via the RCU pointer
* @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
cipso_v4_doi_free_rcu
(
struct
rcu_head
*
entry
)
{
struct
cipso_v4_doi
*
doi_def
;
doi_def
=
container_of
(
entry
,
struct
cipso_v4_doi
,
rcu
);
cipso_v4_doi_free
(
doi_def
);
}
/**
* cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
* @doi: the DOI value
* @audit_secid: the LSM secid to use in the audit message
* @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.
* Removes a DOI definition from the CIPSO engine. 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
(
u32
doi
,
struct
netlbl_audit
*
audit_info
,
void
(
*
callback
)
(
struct
rcu_head
*
head
))
int
cipso_v4_doi_remove
(
u32
doi
,
struct
netlbl_audit
*
audit_info
)
{
struct
cipso_v4_doi
*
doi_def
;
struct
cipso_v4_domhsh_entry
*
dom_iter
;
spin_lock
(
&
cipso_v4_doi_list_lock
);
doi_def
=
cipso_v4_doi_search
(
doi
);
if
(
doi_def
!=
NULL
)
{
doi_def
->
valid
=
0
;
list_del_rcu
(
&
doi_def
->
list
);
if
(
doi_def
==
NULL
)
{
spin_unlock
(
&
cipso_v4_doi_list_lock
);
rcu_read_lock
();
list_for_each_entry_rcu
(
dom_iter
,
&
doi_def
->
dom_list
,
list
)
if
(
dom_iter
->
valid
)
netlbl_cfg_map_del
(
dom_iter
->
domain
,
audit_info
);
rcu_read_unlock
();
cipso_v4_cache_invalidate
();
call_rcu
(
&
doi_def
->
rcu
,
callback
);
return
0
;
return
-
ENOENT
;
}
if
(
!
atomic_dec_and_test
(
&
doi_def
->
refcount
))
{
spin_unlock
(
&
cipso_v4_doi_list_lock
);
return
-
EBUSY
;
}
list_del_rcu
(
&
doi_def
->
list
);
spin_unlock
(
&
cipso_v4_doi_list_lock
);
return
-
ENOENT
;
cipso_v4_cache_invalidate
();
call_rcu
(
&
doi_def
->
rcu
,
cipso_v4_doi_free_rcu
);
return
0
;
}
/**
* cipso_v4_doi_getdef - Returns a
pointer
to a valid DOI definition
* cipso_v4_doi_getdef - Returns a
reference
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.
* rcu_read_lock() is held while accessing the returned definition and the DOI
* definition reference count is decremented when the caller is done.
*
*/
struct
cipso_v4_doi
*
cipso_v4_doi_getdef
(
u32
doi
)
{
return
cipso_v4_doi_search
(
doi
);
struct
cipso_v4_doi
*
doi_def
;
rcu_read_lock
();
doi_def
=
cipso_v4_doi_search
(
doi
);
if
(
doi_def
==
NULL
)
goto
doi_getdef_return
;
if
(
!
atomic_inc_not_zero
(
&
doi_def
->
refcount
))
doi_def
=
NULL
;
doi_getdef_return:
rcu_read_unlock
();
return
doi_def
;
}
/**
* cipso_v4_doi_putdef - Releases a reference for the given DOI definition
* @doi_def: the DOI definition
*
* Description:
* Releases a DOI definition reference obtained from cipso_v4_doi_getdef().
*
*/
void
cipso_v4_doi_putdef
(
struct
cipso_v4_doi
*
doi_def
)
{
if
(
doi_def
==
NULL
)
return
;
if
(
!
atomic_dec_and_test
(
&
doi_def
->
refcount
))
return
;
spin_lock
(
&
cipso_v4_doi_list_lock
);
list_del_rcu
(
&
doi_def
->
list
);
spin_unlock
(
&
cipso_v4_doi_list_lock
);
cipso_v4_cache_invalidate
();
call_rcu
(
&
doi_def
->
rcu
,
cipso_v4_doi_free_rcu
);
}
/**
...
...
@@ -597,7 +654,7 @@ int cipso_v4_doi_walk(u32 *skip_cnt,
rcu_read_lock
();
list_for_each_entry_rcu
(
iter_doi
,
&
cipso_v4_doi_list
,
list
)
if
(
iter_doi
->
valid
)
{
if
(
atomic_read
(
&
iter_doi
->
refcount
)
>
0
)
{
if
(
doi_cnt
++
<
*
skip_cnt
)
continue
;
ret_val
=
callback
(
iter_doi
,
cb_arg
);
...
...
@@ -613,85 +670,6 @@ int cipso_v4_doi_walk(u32 *skip_cnt,
return
ret_val
;
}
/**
* 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 DOI specified by @doi_def, this function
* should only be called by external functions (i.e. NetLabel). This function
* does allocate memory. Returns zero on success, negative values on failure.
*
*/
int
cipso_v4_doi_domhsh_add
(
struct
cipso_v4_doi
*
doi_def
,
const
char
*
domain
)
{
struct
cipso_v4_domhsh_entry
*
iter
;
struct
cipso_v4_domhsh_entry
*
new_dom
;
new_dom
=
kzalloc
(
sizeof
(
*
new_dom
),
GFP_KERNEL
);
if
(
new_dom
==
NULL
)
return
-
ENOMEM
;
if
(
domain
)
{
new_dom
->
domain
=
kstrdup
(
domain
,
GFP_KERNEL
);
if
(
new_dom
->
domain
==
NULL
)
{
kfree
(
new_dom
);
return
-
ENOMEM
;
}
}
new_dom
->
valid
=
1
;
INIT_RCU_HEAD
(
&
new_dom
->
rcu
);
spin_lock
(
&
cipso_v4_doi_list_lock
);
list_for_each_entry
(
iter
,
&
doi_def
->
dom_list
,
list
)
if
(
iter
->
valid
&&
((
domain
!=
NULL
&&
iter
->
domain
!=
NULL
&&
strcmp
(
iter
->
domain
,
domain
)
==
0
)
||
(
domain
==
NULL
&&
iter
->
domain
==
NULL
)))
{
spin_unlock
(
&
cipso_v4_doi_list_lock
);
kfree
(
new_dom
->
domain
);
kfree
(
new_dom
);
return
-
EEXIST
;
}
list_add_tail_rcu
(
&
new_dom
->
list
,
&
doi_def
->
dom_list
);
spin_unlock
(
&
cipso_v4_doi_list_lock
);
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
;
spin_lock
(
&
cipso_v4_doi_list_lock
);
list_for_each_entry
(
iter
,
&
doi_def
->
dom_list
,
list
)
if
(
iter
->
valid
&&
((
domain
!=
NULL
&&
iter
->
domain
!=
NULL
&&
strcmp
(
iter
->
domain
,
domain
)
==
0
)
||
(
domain
==
NULL
&&
iter
->
domain
==
NULL
)))
{
iter
->
valid
=
0
;
list_del_rcu
(
&
iter
->
list
);
spin_unlock
(
&
cipso_v4_doi_list_lock
);
call_rcu
(
&
iter
->
rcu
,
cipso_v4_doi_domhsh_free
);
return
0
;
}
spin_unlock
(
&
cipso_v4_doi_list_lock
);
return
-
ENOENT
;
}
/*
* Label Mapping Functions
*/
...
...
@@ -712,7 +690,7 @@ static int cipso_v4_map_lvl_valid(const struct cipso_v4_doi *doi_def, u8 level)
switch
(
doi_def
->
type
)
{
case
CIPSO_V4_MAP_PASS
:
return
0
;
case
CIPSO_V4_MAP_
STD
:
case
CIPSO_V4_MAP_
TRANS
:
if
(
doi_def
->
map
.
std
->
lvl
.
cipso
[
level
]
<
CIPSO_V4_INV_LVL
)
return
0
;
break
;
...
...
@@ -741,7 +719,7 @@ static int cipso_v4_map_lvl_hton(const struct cipso_v4_doi *doi_def,
case
CIPSO_V4_MAP_PASS
:
*
net_lvl
=
host_lvl
;
return
0
;
case
CIPSO_V4_MAP_
STD
:
case
CIPSO_V4_MAP_
TRANS
:
if
(
host_lvl
<
doi_def
->
map
.
std
->
lvl
.
local_size
&&
doi_def
->
map
.
std
->
lvl
.
local
[
host_lvl
]
<
CIPSO_V4_INV_LVL
)
{
*
net_lvl
=
doi_def
->
map
.
std
->
lvl
.
local
[
host_lvl
];
...
...
@@ -775,7 +753,7 @@ static int cipso_v4_map_lvl_ntoh(const struct cipso_v4_doi *doi_def,
case
CIPSO_V4_MAP_PASS
:
*
host_lvl
=
net_lvl
;
return
0
;
case
CIPSO_V4_MAP_
STD
:
case
CIPSO_V4_MAP_
TRANS
:
map_tbl
=
doi_def
->
map
.
std
;
if
(
net_lvl
<
map_tbl
->
lvl
.
cipso_size
&&
map_tbl
->
lvl
.
cipso
[
net_lvl
]
<
CIPSO_V4_INV_LVL
)
{
...
...
@@ -812,7 +790,7 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
switch
(
doi_def
->
type
)
{
case
CIPSO_V4_MAP_PASS
:
return
0
;
case
CIPSO_V4_MAP_
STD
:
case
CIPSO_V4_MAP_
TRANS
:
cipso_cat_size
=
doi_def
->
map
.
std
->
cat
.
cipso_size
;
cipso_array
=
doi_def
->
map
.
std
->
cat
.
cipso
;
for
(;;)
{
...
...
@@ -860,7 +838,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
u32
host_cat_size
=
0
;
u32
*
host_cat_array
=
NULL
;
if
(
doi_def
->
type
==
CIPSO_V4_MAP_
STD
)
{
if
(
doi_def
->
type
==
CIPSO_V4_MAP_
TRANS
)
{
host_cat_size
=
doi_def
->
map
.
std
->
cat
.
local_size
;
host_cat_array
=
doi_def
->
map
.
std
->
cat
.
local
;
}
...
...
@@ -875,7 +853,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
case
CIPSO_V4_MAP_PASS
:
net_spot
=
host_spot
;
break
;
case
CIPSO_V4_MAP_
STD
:
case
CIPSO_V4_MAP_
TRANS
:
if
(
host_spot
>=
host_cat_size
)
return
-
EPERM
;
net_spot
=
host_cat_array
[
host_spot
];
...
...
@@ -921,7 +899,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
u32
net_cat_size
=
0
;
u32
*
net_cat_array
=
NULL
;
if
(
doi_def
->
type
==
CIPSO_V4_MAP_
STD
)
{
if
(
doi_def
->
type
==
CIPSO_V4_MAP_
TRANS
)
{
net_cat_size
=
doi_def
->
map
.
std
->
cat
.
cipso_size
;
net_cat_array
=
doi_def
->
map
.
std
->
cat
.
cipso
;
}
...
...
@@ -941,7 +919,7 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
case
CIPSO_V4_MAP_PASS
:
host_spot
=
net_spot
;
break
;
case
CIPSO_V4_MAP_
STD
:
case
CIPSO_V4_MAP_
TRANS
:
if
(
net_spot
>=
net_cat_size
)
return
-
EPERM
;
host_spot
=
net_cat_array
[
net_spot
];
...
...
@@ -1277,7 +1255,7 @@ static int cipso_v4_gentag_rbm(const struct cipso_v4_doi *doi_def,
}
else
tag_len
=
4
;
buffer
[
0
]
=
0x01
;
buffer
[
0
]
=
CIPSO_V4_TAG_RBITMAP
;
buffer
[
1
]
=
tag_len
;
buffer
[
3
]
=
level
;
...
...
@@ -1373,7 +1351,7 @@ static int cipso_v4_gentag_enum(const struct cipso_v4_doi *doi_def,
}
else
tag_len
=
4
;
buffer
[
0
]
=
0x02
;
buffer
[
0
]
=
CIPSO_V4_TAG_ENUM
;
buffer
[
1
]
=
tag_len
;
buffer
[
3
]
=
level
;
...
...
@@ -1469,7 +1447,7 @@ static int cipso_v4_gentag_rng(const struct cipso_v4_doi *doi_def,
}
else
tag_len
=
4
;
buffer
[
0
]
=
0x05
;
buffer
[
0
]
=
CIPSO_V4_TAG_RANGE
;
buffer
[
1
]
=
tag_len
;
buffer
[
3
]
=
level
;
...
...
@@ -1522,6 +1500,54 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
return
0
;
}
/**
* cipso_v4_gentag_loc - Generate a CIPSO local tag (non-standard)
* @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 local tag. Returns the size of the tag
* on success, negative values on failure.
*
*/
static
int
cipso_v4_gentag_loc
(
const
struct
cipso_v4_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
,
unsigned
char
*
buffer
,
u32
buffer_len
)
{
if
(
!
(
secattr
->
flags
&
NETLBL_SECATTR_SECID
))
return
-
EPERM
;
buffer
[
0
]
=
CIPSO_V4_TAG_LOCAL
;
buffer
[
1
]
=
CIPSO_V4_TAG_LOC_BLEN
;
*
(
u32
*
)
&
buffer
[
2
]
=
secattr
->
attr
.
secid
;
return
CIPSO_V4_TAG_LOC_BLEN
;
}
/**
* cipso_v4_parsetag_loc - Parse a CIPSO local tag
* @doi_def: the DOI definition
* @tag: the CIPSO tag
* @secattr: the security attributes
*
* Description:
* Parse a CIPSO local tag and return the security attributes in @secattr.
* Return zero on success, negatives values on failure.
*
*/
static
int
cipso_v4_parsetag_loc
(
const
struct
cipso_v4_doi
*
doi_def
,
const
unsigned
char
*
tag
,
struct
netlbl_lsm_secattr
*
secattr
)
{
secattr
->
attr
.
secid
=
*
(
u32
*
)
&
tag
[
2
];
secattr
->
flags
|=
NETLBL_SECATTR_SECID
;
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
...
...
@@ -1541,7 +1567,7 @@ static int cipso_v4_parsetag_rng(const struct cipso_v4_doi *doi_def,
* that is unrecognized."
*
*/
int
cipso_v4_validate
(
unsigned
char
**
option
)
int
cipso_v4_validate
(
const
struct
sk_buff
*
skb
,
unsigned
char
**
option
)
{
unsigned
char
*
opt
=
*
option
;
unsigned
char
*
tag
;
...
...
@@ -1566,7 +1592,7 @@ int cipso_v4_validate(unsigned char **option)
goto
validate_return_locked
;
}
opt_iter
=
6
;
opt_iter
=
CIPSO_V4_HDR_LEN
;
tag
=
opt
+
opt_iter
;
while
(
opt_iter
<
opt_len
)
{
for
(
tag_iter
=
0
;
doi_def
->
tags
[
tag_iter
]
!=
tag
[
0
];)
...
...
@@ -1584,7 +1610,7 @@ int cipso_v4_validate(unsigned char **option)
switch
(
tag
[
0
])
{
case
CIPSO_V4_TAG_RBITMAP
:
if
(
tag_len
<
4
)
{
if
(
tag_len
<
CIPSO_V4_TAG_RBM_BLEN
)
{
err_offset
=
opt_iter
+
1
;
goto
validate_return_locked
;
}
...
...
@@ -1602,7 +1628,7 @@ int cipso_v4_validate(unsigned char **option)
err_offset
=
opt_iter
+
3
;
goto
validate_return_locked
;
}
if
(
tag_len
>
4
&&
if
(
tag_len
>
CIPSO_V4_TAG_RBM_BLEN
&&
cipso_v4_map_cat_rbm_valid
(
doi_def
,
&
tag
[
4
],
tag_len
-
4
)
<
0
)
{
...
...
@@ -1612,7 +1638,7 @@ int cipso_v4_validate(unsigned char **option)
}
break
;
case
CIPSO_V4_TAG_ENUM
:
if
(
tag_len
<
4
)
{
if
(
tag_len
<
CIPSO_V4_TAG_ENUM_BLEN
)
{
err_offset
=
opt_iter
+
1
;
goto
validate_return_locked
;
}
...
...
@@ -1622,7 +1648,7 @@ int cipso_v4_validate(unsigned char **option)
err_offset
=
opt_iter
+
3
;
goto
validate_return_locked
;
}
if
(
tag_len
>
4
&&
if
(
tag_len
>
CIPSO_V4_TAG_ENUM_BLEN
&&
cipso_v4_map_cat_enum_valid
(
doi_def
,
&
tag
[
4
],
tag_len
-
4
)
<
0
)
{
...
...
@@ -1631,7 +1657,7 @@ int cipso_v4_validate(unsigned char **option)
}
break
;
case
CIPSO_V4_TAG_RANGE
:
if
(
tag_len
<
4
)
{
if
(
tag_len
<
CIPSO_V4_TAG_RNG_BLEN
)
{
err_offset
=
opt_iter
+
1
;
goto
validate_return_locked
;
}
...
...
@@ -1641,7 +1667,7 @@ int cipso_v4_validate(unsigned char **option)
err_offset
=
opt_iter
+
3
;
goto
validate_return_locked
;
}
if
(
tag_len
>
4
&&
if
(
tag_len
>
CIPSO_V4_TAG_RNG_BLEN
&&
cipso_v4_map_cat_rng_valid
(
doi_def
,
&
tag
[
4
],
tag_len
-
4
)
<
0
)
{
...
...
@@ -1649,6 +1675,19 @@ int cipso_v4_validate(unsigned char **option)
goto
validate_return_locked
;
}
break
;
case
CIPSO_V4_TAG_LOCAL
:
/* This is a non-standard tag that we only allow for
* local connections, so if the incoming interface is
* not the loopback device drop the packet. */
if
(
!
(
skb
->
dev
->
flags
&
IFF_LOOPBACK
))
{
err_offset
=
opt_iter
;
goto
validate_return_locked
;
}
if
(
tag_len
!=
CIPSO_V4_TAG_LOC_BLEN
)
{
err_offset
=
opt_iter
+
1
;
goto
validate_return_locked
;
}
break
;
default:
err_offset
=
opt_iter
;
goto
validate_return_locked
;
...
...
@@ -1704,48 +1743,27 @@ void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway)
}
/**
* cipso_v4_sock_setattr - Add a CIPSO option to a socket
* @sk: the socket
* cipso_v4_genopt - Generate a CIPSO option
* @buf: the option buffer
* @buf_len: the size of opt_buf
* @doi_def: the CIPSO DOI to use
* @secattr: the s
pecific security attributes of the socket
* @secattr: the s
ecurity attributes
*
* Description:
* Set the CIPSO option on the given socket using the DOI definition and
* security attributes passed to the function. This function requires
* exclusive access to @sk, which means it either needs to be in the
* process of being created or locked. Returns zero on success and negative
* values on failure.
* Generate a CIPSO option using the DOI definition and security attributes
* passed to the function. Returns the length of the option on success and
* negative values on failure.
*
*/
int
cipso_v4_sock_setattr
(
struct
sock
*
sk
,
static
int
cipso_v4_genopt
(
unsigned
char
*
buf
,
u32
buf_len
,
const
struct
cipso_v4_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
=
-
EPERM
;
int
ret_val
;
u32
iter
;
unsigned
char
*
buf
;
u32
buf_len
=
0
;
u32
opt_len
;
struct
ip_options
*
opt
=
NULL
;
struct
inet_sock
*
sk_inet
;
struct
inet_connection_sock
*
sk_conn
;
/* In the case of sock_create_lite(), the sock->sk field is not
* defined yet but it is not a problem as the only users of these
* "lite" PF_INET sockets are functions which do an accept() call
* afterwards so we will label the socket as part of the accept(). */
if
(
sk
==
NULL
)
return
0
;
/* We allocate the maximum CIPSO option size here so we are probably
* being a little wasteful, but it makes our life _much_ easier later
* on and after all we are only talking about 40 bytes. */
buf_len
=
CIPSO_V4_OPT_LEN_MAX
;
buf
=
kmalloc
(
buf_len
,
GFP_ATOMIC
);
if
(
buf
==
NULL
)
{
ret_val
=
-
ENOMEM
;
goto
socket_setattr_failure
;
}
if
(
buf_len
<=
CIPSO_V4_HDR_LEN
)
return
-
ENOSPC
;
/* XXX - This code assumes only one tag per CIPSO option which isn't
* really a good assumption to make but since we only support the MAC
...
...
@@ -1772,9 +1790,14 @@ int cipso_v4_sock_setattr(struct sock *sk,
&
buf
[
CIPSO_V4_HDR_LEN
],
buf_len
-
CIPSO_V4_HDR_LEN
);
break
;
case
CIPSO_V4_TAG_LOCAL
:
ret_val
=
cipso_v4_gentag_loc
(
doi_def
,
secattr
,
&
buf
[
CIPSO_V4_HDR_LEN
],
buf_len
-
CIPSO_V4_HDR_LEN
);
break
;
default:
ret_val
=
-
EPERM
;
goto
socket_setattr_failure
;
return
-
EPERM
;
}
iter
++
;
...
...
@@ -1782,9 +1805,58 @@ int cipso_v4_sock_setattr(struct sock *sk,
iter
<
CIPSO_V4_TAG_MAXCNT
&&
doi_def
->
tags
[
iter
]
!=
CIPSO_V4_TAG_INVALID
);
if
(
ret_val
<
0
)
goto
socket_setattr_failure
;
return
ret_val
;
cipso_v4_gentag_hdr
(
doi_def
,
buf
,
ret_val
);
buf_len
=
CIPSO_V4_HDR_LEN
+
ret_val
;
return
CIPSO_V4_HDR_LEN
+
ret_val
;
}
/**
* cipso_v4_sock_setattr - Add a CIPSO option to a socket
* @sk: 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. This function requires
* exclusive access to @sk, which means it either needs to be in the
* process of being created or locked. Returns zero on success and negative
* values on failure.
*
*/
int
cipso_v4_sock_setattr
(
struct
sock
*
sk
,
const
struct
cipso_v4_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
=
-
EPERM
;
unsigned
char
*
buf
=
NULL
;
u32
buf_len
;
u32
opt_len
;
struct
ip_options
*
opt
=
NULL
;
struct
inet_sock
*
sk_inet
;
struct
inet_connection_sock
*
sk_conn
;
/* In the case of sock_create_lite(), the sock->sk field is not
* defined yet but it is not a problem as the only users of these
* "lite" PF_INET sockets are functions which do an accept() call
* afterwards so we will label the socket as part of the accept(). */
if
(
sk
==
NULL
)
return
0
;
/* We allocate the maximum CIPSO option size here so we are probably
* being a little wasteful, but it makes our life _much_ easier later
* on and after all we are only talking about 40 bytes. */
buf_len
=
CIPSO_V4_OPT_LEN_MAX
;
buf
=
kmalloc
(
buf_len
,
GFP_ATOMIC
);
if
(
buf
==
NULL
)
{
ret_val
=
-
ENOMEM
;
goto
socket_setattr_failure
;
}
ret_val
=
cipso_v4_genopt
(
buf
,
buf_len
,
doi_def
,
secattr
);
if
(
ret_val
<
0
)
goto
socket_setattr_failure
;
buf_len
=
ret_val
;
/* We can't use ip_options_get() directly because it makes a call to
* ip_options_get_alloc() which allocates memory with GFP_KERNEL and
...
...
@@ -1821,6 +1893,80 @@ int cipso_v4_sock_setattr(struct sock *sk,
return
ret_val
;
}
/**
* cipso_v4_sock_delattr - Delete the CIPSO option from a socket
* @sk: the socket
*
* Description:
* Removes the CIPSO option from a socket, if present.
*
*/
void
cipso_v4_sock_delattr
(
struct
sock
*
sk
)
{
u8
hdr_delta
;
struct
ip_options
*
opt
;
struct
inet_sock
*
sk_inet
;
sk_inet
=
inet_sk
(
sk
);
opt
=
sk_inet
->
opt
;
if
(
opt
==
NULL
||
opt
->
cipso
==
0
)
return
;
if
(
opt
->
srr
||
opt
->
rr
||
opt
->
ts
||
opt
->
router_alert
)
{
u8
cipso_len
;
u8
cipso_off
;
unsigned
char
*
cipso_ptr
;
int
iter
;
int
optlen_new
;
cipso_off
=
opt
->
cipso
-
sizeof
(
struct
iphdr
);
cipso_ptr
=
&
opt
->
__data
[
cipso_off
];
cipso_len
=
cipso_ptr
[
1
];
if
(
opt
->
srr
>
opt
->
cipso
)
opt
->
srr
-=
cipso_len
;
if
(
opt
->
rr
>
opt
->
cipso
)
opt
->
rr
-=
cipso_len
;
if
(
opt
->
ts
>
opt
->
cipso
)
opt
->
ts
-=
cipso_len
;
if
(
opt
->
router_alert
>
opt
->
cipso
)
opt
->
router_alert
-=
cipso_len
;
opt
->
cipso
=
0
;
memmove
(
cipso_ptr
,
cipso_ptr
+
cipso_len
,
opt
->
optlen
-
cipso_off
-
cipso_len
);
/* determining the new total option length is tricky because of
* the padding necessary, the only thing i can think to do at
* this point is walk the options one-by-one, skipping the
* padding at the end to determine the actual option size and
* from there we can determine the new total option length */
iter
=
0
;
optlen_new
=
0
;
while
(
iter
<
opt
->
optlen
)
if
(
opt
->
__data
[
iter
]
!=
IPOPT_NOP
)
{
iter
+=
opt
->
__data
[
iter
+
1
];
optlen_new
=
iter
;
}
else
iter
++
;
hdr_delta
=
opt
->
optlen
;
opt
->
optlen
=
(
optlen_new
+
3
)
&
~
3
;
hdr_delta
-=
opt
->
optlen
;
}
else
{
/* only the cipso option was present on the socket so we can
* remove the entire option struct */
sk_inet
->
opt
=
NULL
;
hdr_delta
=
opt
->
optlen
;
kfree
(
opt
);
}
if
(
sk_inet
->
is_icsk
&&
hdr_delta
>
0
)
{
struct
inet_connection_sock
*
sk_conn
=
inet_csk
(
sk
);
sk_conn
->
icsk_ext_hdr_len
-=
hdr_delta
;
sk_conn
->
icsk_sync_mss
(
sk
,
sk_conn
->
icsk_pmtu_cookie
);
}
}
/**
* cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
* @cipso: the CIPSO v4 option
...
...
@@ -1859,6 +2005,9 @@ static int cipso_v4_getattr(const unsigned char *cipso,
case
CIPSO_V4_TAG_RANGE
:
ret_val
=
cipso_v4_parsetag_rng
(
doi_def
,
&
cipso
[
6
],
secattr
);
break
;
case
CIPSO_V4_TAG_LOCAL
:
ret_val
=
cipso_v4_parsetag_loc
(
doi_def
,
&
cipso
[
6
],
secattr
);
break
;
}
if
(
ret_val
==
0
)
secattr
->
type
=
NETLBL_NLTYPE_CIPSOV4
;
...
...
@@ -1892,6 +2041,123 @@ int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
secattr
);
}
/**
* cipso_v4_skbuff_setattr - Set the CIPSO option on a packet
* @skb: the packet
* @secattr: the security attributes
*
* Description:
* Set the CIPSO option on the given packet based on the security attributes.
* Returns a pointer to the IP header on success and NULL on failure.
*
*/
int
cipso_v4_skbuff_setattr
(
struct
sk_buff
*
skb
,
const
struct
cipso_v4_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
;
struct
iphdr
*
iph
;
struct
ip_options
*
opt
=
&
IPCB
(
skb
)
->
opt
;
unsigned
char
buf
[
CIPSO_V4_OPT_LEN_MAX
];
u32
buf_len
=
CIPSO_V4_OPT_LEN_MAX
;
u32
opt_len
;
int
len_delta
;
buf_len
=
cipso_v4_genopt
(
buf
,
buf_len
,
doi_def
,
secattr
);
if
(
buf_len
<
0
)
return
buf_len
;
opt_len
=
(
buf_len
+
3
)
&
~
3
;
/* we overwrite any existing options to ensure that we have enough
* room for the CIPSO option, the reason is that we _need_ to guarantee
* that the security label is applied to the packet - we do the same
* thing when using the socket options and it hasn't caused a problem,
* if we need to we can always revisit this choice later */
len_delta
=
opt_len
-
opt
->
optlen
;
/* if we don't ensure enough headroom we could panic on the skb_push()
* call below so make sure we have enough, we are also "mangling" the
* packet so we should probably do a copy-on-write call anyway */
ret_val
=
skb_cow
(
skb
,
skb_headroom
(
skb
)
+
len_delta
);
if
(
ret_val
<
0
)
return
ret_val
;
if
(
len_delta
>
0
)
{
/* we assume that the header + opt->optlen have already been
* "pushed" in ip_options_build() or similar */
iph
=
ip_hdr
(
skb
);
skb_push
(
skb
,
len_delta
);
memmove
((
char
*
)
iph
-
len_delta
,
iph
,
iph
->
ihl
<<
2
);
skb_reset_network_header
(
skb
);
iph
=
ip_hdr
(
skb
);
}
else
if
(
len_delta
<
0
)
{
iph
=
ip_hdr
(
skb
);
memset
(
iph
+
1
,
IPOPT_NOP
,
opt
->
optlen
);
}
else
iph
=
ip_hdr
(
skb
);
if
(
opt
->
optlen
>
0
)
memset
(
opt
,
0
,
sizeof
(
*
opt
));
opt
->
optlen
=
opt_len
;
opt
->
cipso
=
sizeof
(
struct
iphdr
);
opt
->
is_changed
=
1
;
/* we have to do the following because we are being called from a
* netfilter hook which means the packet already has had the header
* fields populated and the checksum calculated - yes this means we
* are doing more work than needed but we do it to keep the core
* stack clean and tidy */
memcpy
(
iph
+
1
,
buf
,
buf_len
);
if
(
opt_len
>
buf_len
)
memset
((
char
*
)(
iph
+
1
)
+
buf_len
,
0
,
opt_len
-
buf_len
);
if
(
len_delta
!=
0
)
{
iph
->
ihl
=
5
+
(
opt_len
>>
2
);
iph
->
tot_len
=
htons
(
skb
->
len
);
}
ip_send_check
(
iph
);
return
0
;
}
/**
* cipso_v4_skbuff_delattr - Delete any CIPSO options from a packet
* @skb: the packet
*
* Description:
* Removes any and all CIPSO options from the given packet. Returns zero on
* success, negative values on failure.
*
*/
int
cipso_v4_skbuff_delattr
(
struct
sk_buff
*
skb
)
{
int
ret_val
;
struct
iphdr
*
iph
;
struct
ip_options
*
opt
=
&
IPCB
(
skb
)
->
opt
;
unsigned
char
*
cipso_ptr
;
if
(
opt
->
cipso
==
0
)
return
0
;
/* since we are changing the packet we should make a copy */
ret_val
=
skb_cow
(
skb
,
skb_headroom
(
skb
));
if
(
ret_val
<
0
)
return
ret_val
;
/* the easiest thing to do is just replace the cipso option with noop
* options since we don't change the size of the packet, although we
* still need to recalculate the checksum */
iph
=
ip_hdr
(
skb
);
cipso_ptr
=
(
unsigned
char
*
)
iph
+
opt
->
cipso
;
memset
(
cipso_ptr
,
IPOPT_NOOP
,
cipso_ptr
[
1
]);
opt
->
cipso
=
0
;
opt
->
is_changed
=
1
;
ip_send_check
(
iph
);
return
0
;
}
/**
* cipso_v4_skbuff_getattr - Get the security attributes from the CIPSO option
* @skb: the packet
...
...
net/ipv4/ip_options.c
View file @
0da939b0
...
...
@@ -438,7 +438,7 @@ int ip_options_compile(struct net *net,
goto
error
;
}
opt
->
cipso
=
optptr
-
iph
;
if
(
cipso_v4_validate
(
&
optptr
))
{
if
(
cipso_v4_validate
(
skb
,
&
optptr
))
{
pp_ptr
=
optptr
;
goto
error
;
}
...
...
net/netlabel/Makefile
View file @
0da939b0
...
...
@@ -5,7 +5,8 @@
#
# base objects
obj-y
:=
netlabel_user.o netlabel_kapi.o netlabel_domainhash.o
obj-y
:=
netlabel_user.o netlabel_kapi.o
obj-y
+=
netlabel_domainhash.o netlabel_addrlist.o
# management objects
obj-y
+=
netlabel_mgmt.o
...
...
net/netlabel/netlabel_addrlist.c
0 → 100644
View file @
0da939b0
/*
* NetLabel Network Address Lists
*
* This file contains network address list functions used to manage ordered
* lists of network addresses for use by the NetLabel subsystem. The NetLabel
* system manages static and dynamic label mappings for network protocols such
* as CIPSO and RIPSO.
*
* Author: Paul Moore <paul.moore@hp.com>
*
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, 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/in.h>
#include <linux/in6.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <linux/audit.h>
#include "netlabel_addrlist.h"
/*
* Address List Functions
*/
/**
* netlbl_af4list_search - Search for a matching IPv4 address entry
* @addr: IPv4 address
* @head: the list head
*
* Description:
* Searches the IPv4 address list given by @head. If a matching address entry
* is found it is returned, otherwise NULL is returned. The caller is
* responsible for calling the rcu_read_[un]lock() functions.
*
*/
struct
netlbl_af4list
*
netlbl_af4list_search
(
__be32
addr
,
struct
list_head
*
head
)
{
struct
netlbl_af4list
*
iter
;
list_for_each_entry_rcu
(
iter
,
head
,
list
)
if
(
iter
->
valid
&&
(
addr
&
iter
->
mask
)
==
iter
->
addr
)
return
iter
;
return
NULL
;
}
/**
* netlbl_af4list_search_exact - Search for an exact IPv4 address entry
* @addr: IPv4 address
* @mask: IPv4 address mask
* @head: the list head
*
* Description:
* Searches the IPv4 address list given by @head. If an exact match if found
* it is returned, otherwise NULL is returned. The caller is responsible for
* calling the rcu_read_[un]lock() functions.
*
*/
struct
netlbl_af4list
*
netlbl_af4list_search_exact
(
__be32
addr
,
__be32
mask
,
struct
list_head
*
head
)
{
struct
netlbl_af4list
*
iter
;
list_for_each_entry_rcu
(
iter
,
head
,
list
)
if
(
iter
->
valid
&&
iter
->
addr
==
addr
&&
iter
->
mask
==
mask
)
return
iter
;
return
NULL
;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
* netlbl_af6list_search - Search for a matching IPv6 address entry
* @addr: IPv6 address
* @head: the list head
*
* Description:
* Searches the IPv6 address list given by @head. If a matching address entry
* is found it is returned, otherwise NULL is returned. The caller is
* responsible for calling the rcu_read_[un]lock() functions.
*
*/
struct
netlbl_af6list
*
netlbl_af6list_search
(
const
struct
in6_addr
*
addr
,
struct
list_head
*
head
)
{
struct
netlbl_af6list
*
iter
;
list_for_each_entry_rcu
(
iter
,
head
,
list
)
if
(
iter
->
valid
&&
ipv6_masked_addr_cmp
(
&
iter
->
addr
,
&
iter
->
mask
,
addr
)
==
0
)
return
iter
;
return
NULL
;
}
/**
* netlbl_af6list_search_exact - Search for an exact IPv6 address entry
* @addr: IPv6 address
* @mask: IPv6 address mask
* @head: the list head
*
* Description:
* Searches the IPv6 address list given by @head. If an exact match if found
* it is returned, otherwise NULL is returned. The caller is responsible for
* calling the rcu_read_[un]lock() functions.
*
*/
struct
netlbl_af6list
*
netlbl_af6list_search_exact
(
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
struct
list_head
*
head
)
{
struct
netlbl_af6list
*
iter
;
list_for_each_entry_rcu
(
iter
,
head
,
list
)
if
(
iter
->
valid
&&
ipv6_addr_equal
(
&
iter
->
addr
,
addr
)
&&
ipv6_addr_equal
(
&
iter
->
mask
,
mask
))
return
iter
;
return
NULL
;
}
#endif
/* IPv6 */
/**
* netlbl_af4list_add - Add a new IPv4 address entry to a list
* @entry: address entry
* @head: the list head
*
* Description:
* Add a new address entry to the list pointed to by @head. On success zero is
* returned, otherwise a negative value is returned. The caller is responsible
* for calling the necessary locking functions.
*
*/
int
netlbl_af4list_add
(
struct
netlbl_af4list
*
entry
,
struct
list_head
*
head
)
{
struct
netlbl_af4list
*
iter
;
iter
=
netlbl_af4list_search
(
entry
->
addr
,
head
);
if
(
iter
!=
NULL
&&
iter
->
addr
==
entry
->
addr
&&
iter
->
mask
==
entry
->
mask
)
return
-
EEXIST
;
/* in order to speed up address searches through the list (the common
* case) we need to keep the list in order based on the size of the
* address mask such that the entry with the widest mask (smallest
* numerical value) appears first in the list */
list_for_each_entry_rcu
(
iter
,
head
,
list
)
if
(
iter
->
valid
&&
ntohl
(
entry
->
mask
)
>
ntohl
(
iter
->
mask
))
{
__list_add_rcu
(
&
entry
->
list
,
iter
->
list
.
prev
,
&
iter
->
list
);
return
0
;
}
list_add_tail_rcu
(
&
entry
->
list
,
head
);
return
0
;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
* netlbl_af6list_add - Add a new IPv6 address entry to a list
* @entry: address entry
* @head: the list head
*
* Description:
* Add a new address entry to the list pointed to by @head. On success zero is
* returned, otherwise a negative value is returned. The caller is responsible
* for calling the necessary locking functions.
*
*/
int
netlbl_af6list_add
(
struct
netlbl_af6list
*
entry
,
struct
list_head
*
head
)
{
struct
netlbl_af6list
*
iter
;
iter
=
netlbl_af6list_search
(
&
entry
->
addr
,
head
);
if
(
iter
!=
NULL
&&
ipv6_addr_equal
(
&
iter
->
addr
,
&
entry
->
addr
)
&&
ipv6_addr_equal
(
&
iter
->
mask
,
&
entry
->
mask
))
return
-
EEXIST
;
/* in order to speed up address searches through the list (the common
* case) we need to keep the list in order based on the size of the
* address mask such that the entry with the widest mask (smallest
* numerical value) appears first in the list */
list_for_each_entry_rcu
(
iter
,
head
,
list
)
if
(
iter
->
valid
&&
ipv6_addr_cmp
(
&
entry
->
mask
,
&
iter
->
mask
)
>
0
)
{
__list_add_rcu
(
&
entry
->
list
,
iter
->
list
.
prev
,
&
iter
->
list
);
return
0
;
}
list_add_tail_rcu
(
&
entry
->
list
,
head
);
return
0
;
}
#endif
/* IPv6 */
/**
* netlbl_af4list_remove_entry - Remove an IPv4 address entry
* @entry: address entry
*
* Description:
* Remove the specified IP address entry. The caller is responsible for
* calling the necessary locking functions.
*
*/
void
netlbl_af4list_remove_entry
(
struct
netlbl_af4list
*
entry
)
{
entry
->
valid
=
0
;
list_del_rcu
(
&
entry
->
list
);
}
/**
* netlbl_af4list_remove - Remove an IPv4 address entry
* @addr: IP address
* @mask: IP address mask
* @head: the list head
*
* Description:
* Remove an IP address entry from the list pointed to by @head. Returns the
* entry on success, NULL on failure. The caller is responsible for calling
* the necessary locking functions.
*
*/
struct
netlbl_af4list
*
netlbl_af4list_remove
(
__be32
addr
,
__be32
mask
,
struct
list_head
*
head
)
{
struct
netlbl_af4list
*
entry
;
entry
=
netlbl_af4list_search
(
addr
,
head
);
if
(
entry
!=
NULL
&&
entry
->
addr
==
addr
&&
entry
->
mask
==
mask
)
{
netlbl_af4list_remove_entry
(
entry
);
return
entry
;
}
return
NULL
;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
* netlbl_af6list_remove_entry - Remove an IPv6 address entry
* @entry: address entry
*
* Description:
* Remove the specified IP address entry. The caller is responsible for
* calling the necessary locking functions.
*
*/
void
netlbl_af6list_remove_entry
(
struct
netlbl_af6list
*
entry
)
{
entry
->
valid
=
0
;
list_del_rcu
(
&
entry
->
list
);
}
/**
* netlbl_af6list_remove - Remove an IPv6 address entry
* @addr: IP address
* @mask: IP address mask
* @head: the list head
*
* Description:
* Remove an IP address entry from the list pointed to by @head. Returns the
* entry on success, NULL on failure. The caller is responsible for calling
* the necessary locking functions.
*
*/
struct
netlbl_af6list
*
netlbl_af6list_remove
(
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
struct
list_head
*
head
)
{
struct
netlbl_af6list
*
entry
;
entry
=
netlbl_af6list_search
(
addr
,
head
);
if
(
entry
!=
NULL
&&
ipv6_addr_equal
(
&
entry
->
addr
,
addr
)
&&
ipv6_addr_equal
(
&
entry
->
mask
,
mask
))
{
netlbl_af6list_remove_entry
(
entry
);
return
entry
;
}
return
NULL
;
}
#endif
/* IPv6 */
/*
* Audit Helper Functions
*/
/**
* netlbl_af4list_audit_addr - Audit an IPv4 address
* @audit_buf: audit buffer
* @src: true if source address, false if destination
* @dev: network interface
* @addr: IP address
* @mask: IP address mask
*
* Description:
* Write the IPv4 address and address mask, if necessary, to @audit_buf.
*
*/
void
netlbl_af4list_audit_addr
(
struct
audit_buffer
*
audit_buf
,
int
src
,
const
char
*
dev
,
__be32
addr
,
__be32
mask
)
{
u32
mask_val
=
ntohl
(
mask
);
char
*
dir
=
(
src
?
"src"
:
"dst"
);
if
(
dev
!=
NULL
)
audit_log_format
(
audit_buf
,
" netif=%s"
,
dev
);
audit_log_format
(
audit_buf
,
" %s="
NIPQUAD_FMT
,
dir
,
NIPQUAD
(
addr
));
if
(
mask_val
!=
0xffffffff
)
{
u32
mask_len
=
0
;
while
(
mask_val
>
0
)
{
mask_val
<<=
1
;
mask_len
++
;
}
audit_log_format
(
audit_buf
,
" %s_prefixlen=%d"
,
dir
,
mask_len
);
}
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
* netlbl_af6list_audit_addr - Audit an IPv6 address
* @audit_buf: audit buffer
* @src: true if source address, false if destination
* @dev: network interface
* @addr: IP address
* @mask: IP address mask
*
* Description:
* Write the IPv6 address and address mask, if necessary, to @audit_buf.
*
*/
void
netlbl_af6list_audit_addr
(
struct
audit_buffer
*
audit_buf
,
int
src
,
const
char
*
dev
,
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
)
{
char
*
dir
=
(
src
?
"src"
:
"dst"
);
if
(
dev
!=
NULL
)
audit_log_format
(
audit_buf
,
" netif=%s"
,
dev
);
audit_log_format
(
audit_buf
,
" %s="
NIP6_FMT
,
dir
,
NIP6
(
*
addr
));
if
(
ntohl
(
mask
->
s6_addr32
[
3
])
!=
0xffffffff
)
{
u32
mask_len
=
0
;
u32
mask_val
;
int
iter
=
-
1
;
while
(
ntohl
(
mask
->
s6_addr32
[
++
iter
])
==
0xffffffff
)
mask_len
+=
32
;
mask_val
=
ntohl
(
mask
->
s6_addr32
[
iter
]);
while
(
mask_val
>
0
)
{
mask_val
<<=
1
;
mask_len
++
;
}
audit_log_format
(
audit_buf
,
" %s_prefixlen=%d"
,
dir
,
mask_len
);
}
}
#endif
/* IPv6 */
net/netlabel/netlabel_addrlist.h
0 → 100644
View file @
0da939b0
/*
* NetLabel Network Address Lists
*
* This file contains network address list functions used to manage ordered
* lists of network addresses for use by the NetLabel subsystem. The NetLabel
* system manages static and dynamic label mappings for network protocols such
* as CIPSO and RIPSO.
*
* Author: Paul Moore <paul.moore@hp.com>
*
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef _NETLABEL_ADDRLIST_H
#define _NETLABEL_ADDRLIST_H
#include <linux/types.h>
#include <linux/rcupdate.h>
#include <linux/list.h>
#include <linux/in6.h>
#include <linux/audit.h>
/**
* struct netlbl_af4list - NetLabel IPv4 address list
* @addr: IPv4 address
* @mask: IPv4 address mask
* @valid: valid flag
* @list: list structure, used internally
*/
struct
netlbl_af4list
{
__be32
addr
;
__be32
mask
;
u32
valid
;
struct
list_head
list
;
};
/**
* struct netlbl_af6list - NetLabel IPv6 address list
* @addr: IPv6 address
* @mask: IPv6 address mask
* @valid: valid flag
* @list: list structure, used internally
*/
struct
netlbl_af6list
{
struct
in6_addr
addr
;
struct
in6_addr
mask
;
u32
valid
;
struct
list_head
list
;
};
#define __af4list_entry(ptr) container_of(ptr, struct netlbl_af4list, list)
static
inline
struct
netlbl_af4list
*
__af4list_valid
(
struct
list_head
*
s
,
struct
list_head
*
h
)
{
struct
list_head
*
i
=
s
;
struct
netlbl_af4list
*
n
=
__af4list_entry
(
s
);
while
(
i
!=
h
&&
!
n
->
valid
)
{
i
=
i
->
next
;
n
=
__af4list_entry
(
i
);
}
return
n
;
}
static
inline
struct
netlbl_af4list
*
__af4list_valid_rcu
(
struct
list_head
*
s
,
struct
list_head
*
h
)
{
struct
list_head
*
i
=
s
;
struct
netlbl_af4list
*
n
=
__af4list_entry
(
s
);
while
(
i
!=
h
&&
!
n
->
valid
)
{
i
=
rcu_dereference
(
i
->
next
);
n
=
__af4list_entry
(
i
);
}
return
n
;
}
#define netlbl_af4list_foreach(iter, head) \
for (iter = __af4list_valid((head)->next, head); \
prefetch(iter->list.next), &iter->list != (head); \
iter = __af4list_valid(iter->list.next, head))
#define netlbl_af4list_foreach_rcu(iter, head) \
for (iter = __af4list_valid_rcu((head)->next, head); \
prefetch(iter->list.next), &iter->list != (head); \
iter = __af4list_valid_rcu(iter->list.next, head))
#define netlbl_af4list_foreach_safe(iter, tmp, head) \
for (iter = __af4list_valid((head)->next, head), \
tmp = __af4list_valid(iter->list.next, head); \
&iter->list != (head); \
iter = tmp, tmp = __af4list_valid(iter->list.next, head))
int
netlbl_af4list_add
(
struct
netlbl_af4list
*
entry
,
struct
list_head
*
head
);
struct
netlbl_af4list
*
netlbl_af4list_remove
(
__be32
addr
,
__be32
mask
,
struct
list_head
*
head
);
void
netlbl_af4list_remove_entry
(
struct
netlbl_af4list
*
entry
);
struct
netlbl_af4list
*
netlbl_af4list_search
(
__be32
addr
,
struct
list_head
*
head
);
struct
netlbl_af4list
*
netlbl_af4list_search_exact
(
__be32
addr
,
__be32
mask
,
struct
list_head
*
head
);
void
netlbl_af4list_audit_addr
(
struct
audit_buffer
*
audit_buf
,
int
src
,
const
char
*
dev
,
__be32
addr
,
__be32
mask
);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#define __af6list_entry(ptr) container_of(ptr, struct netlbl_af6list, list)
static
inline
struct
netlbl_af6list
*
__af6list_valid
(
struct
list_head
*
s
,
struct
list_head
*
h
)
{
struct
list_head
*
i
=
s
;
struct
netlbl_af6list
*
n
=
__af6list_entry
(
s
);
while
(
i
!=
h
&&
!
n
->
valid
)
{
i
=
i
->
next
;
n
=
__af6list_entry
(
i
);
}
return
n
;
}
static
inline
struct
netlbl_af6list
*
__af6list_valid_rcu
(
struct
list_head
*
s
,
struct
list_head
*
h
)
{
struct
list_head
*
i
=
s
;
struct
netlbl_af6list
*
n
=
__af6list_entry
(
s
);
while
(
i
!=
h
&&
!
n
->
valid
)
{
i
=
rcu_dereference
(
i
->
next
);
n
=
__af6list_entry
(
i
);
}
return
n
;
}
#define netlbl_af6list_foreach(iter, head) \
for (iter = __af6list_valid((head)->next, head); \
prefetch(iter->list.next), &iter->list != (head); \
iter = __af6list_valid(iter->list.next, head))
#define netlbl_af6list_foreach_rcu(iter, head) \
for (iter = __af6list_valid_rcu((head)->next, head); \
prefetch(iter->list.next), &iter->list != (head); \
iter = __af6list_valid_rcu(iter->list.next, head))
#define netlbl_af6list_foreach_safe(iter, tmp, head) \
for (iter = __af6list_valid((head)->next, head), \
tmp = __af6list_valid(iter->list.next, head); \
&iter->list != (head); \
iter = tmp, tmp = __af6list_valid(iter->list.next, head))
int
netlbl_af6list_add
(
struct
netlbl_af6list
*
entry
,
struct
list_head
*
head
);
struct
netlbl_af6list
*
netlbl_af6list_remove
(
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
struct
list_head
*
head
);
void
netlbl_af6list_remove_entry
(
struct
netlbl_af6list
*
entry
);
struct
netlbl_af6list
*
netlbl_af6list_search
(
const
struct
in6_addr
*
addr
,
struct
list_head
*
head
);
struct
netlbl_af6list
*
netlbl_af6list_search_exact
(
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
struct
list_head
*
head
);
void
netlbl_af6list_audit_addr
(
struct
audit_buffer
*
audit_buf
,
int
src
,
const
char
*
dev
,
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
);
#endif
/* IPV6 */
#endif
net/netlabel/netlabel_cipso_v4.c
View file @
0da939b0
...
...
@@ -43,6 +43,7 @@
#include "netlabel_user.h"
#include "netlabel_cipso_v4.h"
#include "netlabel_mgmt.h"
#include "netlabel_domainhash.h"
/* Argument struct for cipso_v4_doi_walk() */
struct
netlbl_cipsov4_doiwalk_arg
{
...
...
@@ -51,6 +52,12 @@ struct netlbl_cipsov4_doiwalk_arg {
u32
seq
;
};
/* Argument struct for netlbl_domhsh_walk() */
struct
netlbl_domhsh_walk_arg
{
struct
netlbl_audit
*
audit_info
;
u32
doi
;
};
/* NetLabel Generic NETLINK CIPSOv4 family */
static
struct
genl_family
netlbl_cipsov4_gnl_family
=
{
.
id
=
GENL_ID_GENERATE
,
...
...
@@ -80,32 +87,6 @@ static const struct nla_policy netlbl_cipsov4_genl_policy[NLBL_CIPSOV4_A_MAX + 1
* Helper Functions
*/
/**
* netlbl_cipsov4_doi_free - Frees a CIPSO V4 DOI definition
* @entry: the entry's RCU field
*
* Description:
* This function is designed to be used as a callback to the call_rcu()
* function so that the memory allocated to the DOI definition can be released
* safely.
*
*/
void
netlbl_cipsov4_doi_free
(
struct
rcu_head
*
entry
)
{
struct
cipso_v4_doi
*
ptr
;
ptr
=
container_of
(
entry
,
struct
cipso_v4_doi
,
rcu
);
switch
(
ptr
->
type
)
{
case
CIPSO_V4_MAP_STD
:
kfree
(
ptr
->
map
.
std
->
lvl
.
cipso
);
kfree
(
ptr
->
map
.
std
->
lvl
.
local
);
kfree
(
ptr
->
map
.
std
->
cat
.
cipso
);
kfree
(
ptr
->
map
.
std
->
cat
.
local
);
break
;
}
kfree
(
ptr
);
}
/**
* netlbl_cipsov4_add_common - Parse the common sections of a ADD message
* @info: the Generic NETLINK info block
...
...
@@ -151,9 +132,9 @@ static int netlbl_cipsov4_add_common(struct genl_info *info,
* @info: the Generic NETLINK info block
*
* Description:
* Create a new CIPSO_V4_MAP_
STD DOI definition based on the given ADD message
*
and add it to the CIPSO V4 engine. Return zero on success and non-zero on
* error.
* Create a new CIPSO_V4_MAP_
TRANS DOI definition based on the given ADD
*
message and add it to the CIPSO V4 engine. Return zero on success and
*
non-zero on
error.
*
*/
static
int
netlbl_cipsov4_add_std
(
struct
genl_info
*
info
)
...
...
@@ -183,7 +164,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
ret_val
=
-
ENOMEM
;
goto
add_std_failure
;
}
doi_def
->
type
=
CIPSO_V4_MAP_
STD
;
doi_def
->
type
=
CIPSO_V4_MAP_
TRANS
;
ret_val
=
netlbl_cipsov4_add_common
(
info
,
doi_def
);
if
(
ret_val
!=
0
)
...
...
@@ -342,7 +323,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
add_std_failure:
if
(
doi_def
)
netlbl_cipsov4_doi_free
(
&
doi_def
->
rcu
);
cipso_v4_doi_free
(
doi_def
);
return
ret_val
;
}
...
...
@@ -379,7 +360,44 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
return
0
;
add_pass_failure:
netlbl_cipsov4_doi_free
(
&
doi_def
->
rcu
);
cipso_v4_doi_free
(
doi_def
);
return
ret_val
;
}
/**
* netlbl_cipsov4_add_local - Adds a CIPSO V4 DOI definition
* @info: the Generic NETLINK info block
*
* Description:
* Create a new CIPSO_V4_MAP_LOCAL DOI definition based on the given ADD
* message and add it to the CIPSO V4 engine. Return zero on success and
* non-zero on error.
*
*/
static
int
netlbl_cipsov4_add_local
(
struct
genl_info
*
info
)
{
int
ret_val
;
struct
cipso_v4_doi
*
doi_def
=
NULL
;
if
(
!
info
->
attrs
[
NLBL_CIPSOV4_A_TAGLST
])
return
-
EINVAL
;
doi_def
=
kmalloc
(
sizeof
(
*
doi_def
),
GFP_KERNEL
);
if
(
doi_def
==
NULL
)
return
-
ENOMEM
;
doi_def
->
type
=
CIPSO_V4_MAP_LOCAL
;
ret_val
=
netlbl_cipsov4_add_common
(
info
,
doi_def
);
if
(
ret_val
!=
0
)
goto
add_local_failure
;
ret_val
=
cipso_v4_doi_add
(
doi_def
);
if
(
ret_val
!=
0
)
goto
add_local_failure
;
return
0
;
add_local_failure:
cipso_v4_doi_free
(
doi_def
);
return
ret_val
;
}
...
...
@@ -412,14 +430,18 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
type
=
nla_get_u32
(
info
->
attrs
[
NLBL_CIPSOV4_A_MTYPE
]);
switch
(
type
)
{
case
CIPSO_V4_MAP_
STD
:
type_str
=
"
std
"
;
case
CIPSO_V4_MAP_
TRANS
:
type_str
=
"
trans
"
;
ret_val
=
netlbl_cipsov4_add_std
(
info
);
break
;
case
CIPSO_V4_MAP_PASS
:
type_str
=
"pass"
;
ret_val
=
netlbl_cipsov4_add_pass
(
info
);
break
;
case
CIPSO_V4_MAP_LOCAL
:
type_str
=
"local"
;
ret_val
=
netlbl_cipsov4_add_local
(
info
);
break
;
}
if
(
ret_val
==
0
)
atomic_inc
(
&
netlabel_mgmt_protocount
);
...
...
@@ -491,7 +513,7 @@ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
doi_def
=
cipso_v4_doi_getdef
(
doi
);
if
(
doi_def
==
NULL
)
{
ret_val
=
-
EINVAL
;
goto
list_failure
;
goto
list_failure
_lock
;
}
ret_val
=
nla_put_u32
(
ans_skb
,
NLBL_CIPSOV4_A_MTYPE
,
doi_def
->
type
);
...
...
@@ -516,7 +538,7 @@ static int netlbl_cipsov4_list(struct sk_buff *skb, struct genl_info *info)
nla_nest_end
(
ans_skb
,
nla_a
);
switch
(
doi_def
->
type
)
{
case
CIPSO_V4_MAP_
STD
:
case
CIPSO_V4_MAP_
TRANS
:
nla_a
=
nla_nest_start
(
ans_skb
,
NLBL_CIPSOV4_A_MLSLVLLST
);
if
(
nla_a
==
NULL
)
{
ret_val
=
-
ENOMEM
;
...
...
@@ -655,7 +677,7 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
struct
netlink_callback
*
cb
)
{
struct
netlbl_cipsov4_doiwalk_arg
cb_arg
;
int
doi_skip
=
cb
->
args
[
0
];
u32
doi_skip
=
cb
->
args
[
0
];
cb_arg
.
nl_cb
=
cb
;
cb_arg
.
skb
=
skb
;
...
...
@@ -667,6 +689,29 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
return
skb
->
len
;
}
/**
* netlbl_cipsov4_remove_cb - netlbl_cipsov4_remove() callback for REMOVE
* @entry: LSM domain mapping entry
* @arg: the netlbl_domhsh_walk_arg structure
*
* Description:
* This function is intended for use by netlbl_cipsov4_remove() as the callback
* for the netlbl_domhsh_walk() function; it removes LSM domain map entries
* which are associated with the CIPSO DOI specified in @arg. Returns zero on
* success, negative values on failure.
*
*/
static
int
netlbl_cipsov4_remove_cb
(
struct
netlbl_dom_map
*
entry
,
void
*
arg
)
{
struct
netlbl_domhsh_walk_arg
*
cb_arg
=
arg
;
if
(
entry
->
type
==
NETLBL_NLTYPE_CIPSOV4
&&
entry
->
type_def
.
cipsov4
->
doi
==
cb_arg
->
doi
)
return
netlbl_domhsh_remove_entry
(
entry
,
cb_arg
->
audit_info
);
return
0
;
}
/**
* netlbl_cipsov4_remove - Handle a REMOVE message
* @skb: the NETLINK buffer
...
...
@@ -681,8 +726,11 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
{
int
ret_val
=
-
EINVAL
;
u32
doi
=
0
;
struct
netlbl_domhsh_walk_arg
cb_arg
;
struct
audit_buffer
*
audit_buf
;
struct
netlbl_audit
audit_info
;
u32
skip_bkt
=
0
;
u32
skip_chain
=
0
;
if
(
!
info
->
attrs
[
NLBL_CIPSOV4_A_DOI
])
return
-
EINVAL
;
...
...
@@ -690,11 +738,15 @@ static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
doi
=
nla_get_u32
(
info
->
attrs
[
NLBL_CIPSOV4_A_DOI
]);
netlbl_netlink_auditinfo
(
skb
,
&
audit_info
);
ret_val
=
cipso_v4_doi_remove
(
doi
,
&
audit_info
,
netlbl_cipsov4_doi_free
);
cb_arg
.
doi
=
doi
;
cb_arg
.
audit_info
=
&
audit_info
;
ret_val
=
netlbl_domhsh_walk
(
&
skip_bkt
,
&
skip_chain
,
netlbl_cipsov4_remove_cb
,
&
cb_arg
);
if
(
ret_val
==
0
||
ret_val
==
-
ENOENT
)
{
ret_val
=
cipso_v4_doi_remove
(
doi
,
&
audit_info
);
if
(
ret_val
==
0
)
atomic_dec
(
&
netlabel_mgmt_protocount
);
}
audit_buf
=
netlbl_audit_start_common
(
AUDIT_MAC_CIPSOV4_DEL
,
&
audit_info
);
...
...
net/netlabel/netlabel_cipso_v4.h
View file @
0da939b0
...
...
@@ -45,12 +45,13 @@
* NLBL_CIPSOV4_A_MTYPE
* NLBL_CIPSOV4_A_TAGLST
*
* If using CIPSO_V4_MAP_
STD
the following attributes are required:
* If using CIPSO_V4_MAP_
TRANS
the following attributes are required:
*
* NLBL_CIPSOV4_A_MLSLVLLST
* NLBL_CIPSOV4_A_MLSCATLST
*
* If using CIPSO_V4_MAP_PASS no additional attributes are required.
* If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
* are required.
*
* o REMOVE:
* Sent by an application to remove a specific DOI mapping table from the
...
...
@@ -76,12 +77,13 @@
* NLBL_CIPSOV4_A_MTYPE
* NLBL_CIPSOV4_A_TAGLST
*
* If using CIPSO_V4_MAP_
STD
the following attributes are required:
* If using CIPSO_V4_MAP_
TRANS
the following attributes are required:
*
* NLBL_CIPSOV4_A_MLSLVLLST
* NLBL_CIPSOV4_A_MLSCATLST
*
* If using CIPSO_V4_MAP_PASS no additional attributes are required.
* If using CIPSO_V4_MAP_PASS or CIPSO_V4_MAP_LOCAL no additional attributes
* are required.
*
* o LISTALL:
* This message is sent by an application to list the valid DOIs on the
...
...
net/netlabel/netlabel_domainhash.c
View file @
0da939b0
...
...
@@ -11,7 +11,7 @@
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -40,6 +40,7 @@
#include <asm/bug.h>
#include "netlabel_mgmt.h"
#include "netlabel_addrlist.h"
#include "netlabel_domainhash.h"
#include "netlabel_user.h"
...
...
@@ -72,8 +73,28 @@ static struct netlbl_dom_map *netlbl_domhsh_def = NULL;
static
void
netlbl_domhsh_free_entry
(
struct
rcu_head
*
entry
)
{
struct
netlbl_dom_map
*
ptr
;
struct
netlbl_af4list
*
iter4
;
struct
netlbl_af4list
*
tmp4
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct
netlbl_af6list
*
iter6
;
struct
netlbl_af6list
*
tmp6
;
#endif
/* IPv6 */
ptr
=
container_of
(
entry
,
struct
netlbl_dom_map
,
rcu
);
if
(
ptr
->
type
==
NETLBL_NLTYPE_ADDRSELECT
)
{
netlbl_af4list_foreach_safe
(
iter4
,
tmp4
,
&
ptr
->
type_def
.
addrsel
->
list4
)
{
netlbl_af4list_remove_entry
(
iter4
);
kfree
(
netlbl_domhsh_addr4_entry
(
iter4
));
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
netlbl_af6list_foreach_safe
(
iter6
,
tmp6
,
&
ptr
->
type_def
.
addrsel
->
list6
)
{
netlbl_af6list_remove_entry
(
iter6
);
kfree
(
netlbl_domhsh_addr6_entry
(
iter6
));
}
#endif
/* IPv6 */
}
kfree
(
ptr
->
domain
);
kfree
(
ptr
);
}
...
...
@@ -115,13 +136,13 @@ static u32 netlbl_domhsh_hash(const char *key)
static
struct
netlbl_dom_map
*
netlbl_domhsh_search
(
const
char
*
domain
)
{
u32
bkt
;
struct
list_head
*
bkt_list
;
struct
netlbl_dom_map
*
iter
;
if
(
domain
!=
NULL
)
{
bkt
=
netlbl_domhsh_hash
(
domain
);
list_for_each_entry_rcu
(
iter
,
&
rcu_dereference
(
netlbl_domhsh
)
->
tbl
[
bkt
],
list
)
bkt_list
=
&
rcu_dereference
(
netlbl_domhsh
)
->
tbl
[
bkt
];
list_for_each_entry_rcu
(
iter
,
bkt_list
,
list
)
if
(
iter
->
valid
&&
strcmp
(
iter
->
domain
,
domain
)
==
0
)
return
iter
;
}
...
...
@@ -156,6 +177,69 @@ static struct netlbl_dom_map *netlbl_domhsh_search_def(const char *domain)
return
entry
;
}
/**
* netlbl_domhsh_audit_add - Generate an audit entry for an add event
* @entry: the entry being added
* @addr4: the IPv4 address information
* @addr6: the IPv6 address information
* @result: the result code
* @audit_info: NetLabel audit information
*
* Description:
* Generate an audit record for adding a new NetLabel/LSM mapping entry with
* the given information. Caller is responsibile for holding the necessary
* locks.
*
*/
static
void
netlbl_domhsh_audit_add
(
struct
netlbl_dom_map
*
entry
,
struct
netlbl_af4list
*
addr4
,
struct
netlbl_af6list
*
addr6
,
int
result
,
struct
netlbl_audit
*
audit_info
)
{
struct
audit_buffer
*
audit_buf
;
struct
cipso_v4_doi
*
cipsov4
=
NULL
;
u32
type
;
audit_buf
=
netlbl_audit_start_common
(
AUDIT_MAC_MAP_ADD
,
audit_info
);
if
(
audit_buf
!=
NULL
)
{
audit_log_format
(
audit_buf
,
" nlbl_domain=%s"
,
entry
->
domain
?
entry
->
domain
:
"(default)"
);
if
(
addr4
!=
NULL
)
{
struct
netlbl_domaddr4_map
*
map4
;
map4
=
netlbl_domhsh_addr4_entry
(
addr4
);
type
=
map4
->
type
;
cipsov4
=
map4
->
type_def
.
cipsov4
;
netlbl_af4list_audit_addr
(
audit_buf
,
0
,
NULL
,
addr4
->
addr
,
addr4
->
mask
);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
}
else
if
(
addr6
!=
NULL
)
{
struct
netlbl_domaddr6_map
*
map6
;
map6
=
netlbl_domhsh_addr6_entry
(
addr6
);
type
=
map6
->
type
;
netlbl_af6list_audit_addr
(
audit_buf
,
0
,
NULL
,
&
addr6
->
addr
,
&
addr6
->
mask
);
#endif
/* IPv6 */
}
else
{
type
=
entry
->
type
;
cipsov4
=
entry
->
type_def
.
cipsov4
;
}
switch
(
type
)
{
case
NETLBL_NLTYPE_UNLABELED
:
audit_log_format
(
audit_buf
,
" nlbl_protocol=unlbl"
);
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
BUG_ON
(
cipsov4
==
NULL
);
audit_log_format
(
audit_buf
,
" nlbl_protocol=cipsov4 cipso_doi=%u"
,
cipsov4
->
doi
);
break
;
}
audit_log_format
(
audit_buf
,
" res=%u"
,
result
==
0
?
1
:
0
);
audit_log_end
(
audit_buf
);
}
}
/*
* Domain Hash Table Functions
*/
...
...
@@ -213,74 +297,106 @@ int __init netlbl_domhsh_init(u32 size)
int
netlbl_domhsh_add
(
struct
netlbl_dom_map
*
entry
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
;
u32
bkt
;
struct
audit_buffer
*
audit_buf
;
int
ret_val
=
0
;
struct
netlbl_dom_map
*
entry_old
;
struct
netlbl_af4list
*
iter4
;
struct
netlbl_af4list
*
tmp4
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct
netlbl_af6list
*
iter6
;
struct
netlbl_af6list
*
tmp6
;
#endif
/* IPv6 */
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_UNLABELED
:
ret_val
=
0
;
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
cipso_v4_doi_domhsh_add
(
entry
->
type_def
.
cipsov4
,
entry
->
domain
);
break
;
default:
return
-
EINVAL
;
}
if
(
ret_val
!=
0
)
return
ret_val
;
rcu_read_lock
();
spin_lock
(
&
netlbl_domhsh_lock
);
if
(
entry
->
domain
!=
NULL
)
entry_old
=
netlbl_domhsh_search
(
entry
->
domain
);
else
entry_old
=
netlbl_domhsh_search_def
(
entry
->
domain
);
if
(
entry_old
==
NULL
)
{
entry
->
valid
=
1
;
INIT_RCU_HEAD
(
&
entry
->
rcu
);
rcu_read_lock
();
spin_lock
(
&
netlbl_domhsh_lock
);
if
(
entry
->
domain
!=
NULL
)
{
bkt
=
netlbl_domhsh_hash
(
entry
->
domain
);
if
(
netlbl_domhsh_search
(
entry
->
domain
)
==
NULL
)
u32
bkt
=
netlbl_domhsh_hash
(
entry
->
domain
);
list_add_tail_rcu
(
&
entry
->
list
,
&
rcu_dereference
(
netlbl_domhsh
)
->
tbl
[
bkt
]);
else
ret_val
=
-
EEXIST
;
}
else
{
INIT_LIST_HEAD
(
&
entry
->
list
);
if
(
rcu_dereference
(
netlbl_domhsh_def
)
==
NULL
)
rcu_assign_pointer
(
netlbl_domhsh_def
,
entry
);
else
ret_val
=
-
EEXIST
;
}
spin_unlock
(
&
netlbl_domhsh_lock
);
audit_buf
=
netlbl_audit_start_common
(
AUDIT_MAC_MAP_ADD
,
audit_info
);
if
(
audit_buf
!=
NULL
)
{
audit_log_format
(
audit_buf
,
" nlbl_domain=%s"
,
entry
->
domain
?
entry
->
domain
:
"(default)"
);
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_UNLABELED
:
audit_log_format
(
audit_buf
,
" nlbl_protocol=unlbl"
);
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
audit_log_format
(
audit_buf
,
" nlbl_protocol=cipsov4 cipso_doi=%u"
,
entry
->
type_def
.
cipsov4
->
doi
);
break
;
if
(
entry
->
type
==
NETLBL_NLTYPE_ADDRSELECT
)
{
netlbl_af4list_foreach_rcu
(
iter4
,
&
entry
->
type_def
.
addrsel
->
list4
)
netlbl_domhsh_audit_add
(
entry
,
iter4
,
NULL
,
ret_val
,
audit_info
);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
netlbl_af6list_foreach_rcu
(
iter6
,
&
entry
->
type_def
.
addrsel
->
list6
)
netlbl_domhsh_audit_add
(
entry
,
NULL
,
iter6
,
ret_val
,
audit_info
);
#endif
/* IPv6 */
}
else
netlbl_domhsh_audit_add
(
entry
,
NULL
,
NULL
,
ret_val
,
audit_info
);
}
else
if
(
entry_old
->
type
==
NETLBL_NLTYPE_ADDRSELECT
&&
entry
->
type
==
NETLBL_NLTYPE_ADDRSELECT
)
{
struct
list_head
*
old_list4
;
struct
list_head
*
old_list6
;
old_list4
=
&
entry_old
->
type_def
.
addrsel
->
list4
;
old_list6
=
&
entry_old
->
type_def
.
addrsel
->
list6
;
/* we only allow the addition of address selectors if all of
* the selectors do not exist in the existing domain map */
netlbl_af4list_foreach_rcu
(
iter4
,
&
entry
->
type_def
.
addrsel
->
list4
)
if
(
netlbl_af4list_search_exact
(
iter4
->
addr
,
iter4
->
mask
,
old_list4
))
{
ret_val
=
-
EEXIST
;
goto
add_return
;
}
audit_log_format
(
audit_buf
,
" res=%u"
,
ret_val
==
0
?
1
:
0
);
audit_log_end
(
audit_buf
);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
netlbl_af6list_foreach_rcu
(
iter6
,
&
entry
->
type_def
.
addrsel
->
list6
)
if
(
netlbl_af6list_search_exact
(
&
iter6
->
addr
,
&
iter6
->
mask
,
old_list6
))
{
ret_val
=
-
EEXIST
;
goto
add_return
;
}
rcu_read_unlock
();
if
(
ret_val
!=
0
)
{
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_CIPSOV4
:
if
(
cipso_v4_doi_domhsh_remove
(
entry
->
type_def
.
cipsov4
,
entry
->
domain
)
!=
0
)
BUG
();
break
;
#endif
/* IPv6 */
netlbl_af4list_foreach_safe
(
iter4
,
tmp4
,
&
entry
->
type_def
.
addrsel
->
list4
)
{
netlbl_af4list_remove_entry
(
iter4
);
iter4
->
valid
=
1
;
ret_val
=
netlbl_af4list_add
(
iter4
,
old_list4
);
netlbl_domhsh_audit_add
(
entry_old
,
iter4
,
NULL
,
ret_val
,
audit_info
);
if
(
ret_val
!=
0
)
goto
add_return
;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
netlbl_af6list_foreach_safe
(
iter6
,
tmp6
,
&
entry
->
type_def
.
addrsel
->
list6
)
{
netlbl_af6list_remove_entry
(
iter6
);
iter6
->
valid
=
1
;
ret_val
=
netlbl_af6list_add
(
iter6
,
old_list6
);
netlbl_domhsh_audit_add
(
entry_old
,
NULL
,
iter6
,
ret_val
,
audit_info
);
if
(
ret_val
!=
0
)
goto
add_return
;
}
#endif
/* IPv6 */
}
else
ret_val
=
-
EINVAL
;
add_return:
spin_unlock
(
&
netlbl_domhsh_lock
);
rcu_read_unlock
();
return
ret_val
;
}
...
...
@@ -302,35 +418,26 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
}
/**
* netlbl_domhsh_remove
- Removes an entry from the domain hash
table
* @
domain: the domain
to remove
* netlbl_domhsh_remove
_entry - Removes a given entry from the domain
table
* @
entry: the entry
to remove
* @audit_info: NetLabel audit information
*
* Description:
* Removes an entry from the domain hash table and handles any updates to the
* lower level protocol handler (i.e. CIPSO). Returns zero on success,
* negative on failure.
* lower level protocol handler (i.e. CIPSO). Caller is responsible for
* ensuring that the RCU read lock is held. Returns zero on success, negative
* on failure.
*
*/
int
netlbl_domhsh_remove
(
const
char
*
domain
,
struct
netlbl_audit
*
audit_info
)
int
netlbl_domhsh_remove_entry
(
struct
netlbl_dom_map
*
entry
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
=
-
ENOENT
;
struct
netlbl_dom_map
*
entry
;
int
ret_val
=
0
;
struct
audit_buffer
*
audit_buf
;
rcu_read_lock
();
if
(
domain
)
entry
=
netlbl_domhsh_search
(
domain
);
else
entry
=
netlbl_domhsh_search_def
(
domain
);
if
(
entry
==
NULL
)
goto
remove_return
;
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_CIPSOV4
:
cipso_v4_doi_domhsh_remove
(
entry
->
type_def
.
cipsov4
,
entry
->
domain
);
break
;
}
return
-
ENOENT
;
spin_lock
(
&
netlbl_domhsh_lock
);
if
(
entry
->
valid
)
{
entry
->
valid
=
0
;
...
...
@@ -338,8 +445,8 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
list_del_rcu
(
&
entry
->
list
);
else
rcu_assign_pointer
(
netlbl_domhsh_def
,
NULL
);
ret_val
=
0
;
}
}
else
ret_val
=
-
ENOENT
;
spin_unlock
(
&
netlbl_domhsh_lock
);
audit_buf
=
netlbl_audit_start_common
(
AUDIT_MAC_MAP_DEL
,
audit_info
);
...
...
@@ -351,10 +458,54 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
audit_log_end
(
audit_buf
);
}
remove_return:
rcu_read_unlock
();
if
(
ret_val
==
0
)
if
(
ret_val
==
0
)
{
struct
netlbl_af4list
*
iter4
;
struct
netlbl_domaddr4_map
*
map4
;
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_ADDRSELECT
:
netlbl_af4list_foreach_rcu
(
iter4
,
&
entry
->
type_def
.
addrsel
->
list4
)
{
map4
=
netlbl_domhsh_addr4_entry
(
iter4
);
cipso_v4_doi_putdef
(
map4
->
type_def
.
cipsov4
);
}
/* no need to check the IPv6 list since we currently
* support only unlabeled protocols for IPv6 */
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
cipso_v4_doi_putdef
(
entry
->
type_def
.
cipsov4
);
break
;
}
call_rcu
(
&
entry
->
rcu
,
netlbl_domhsh_free_entry
);
}
return
ret_val
;
}
/**
* netlbl_domhsh_remove - Removes an entry from the domain hash table
* @domain: the domain to remove
* @audit_info: NetLabel audit information
*
* Description:
* Removes an entry from the domain hash table and handles any updates to the
* lower level protocol handler (i.e. CIPSO). Returns zero on success,
* negative on failure.
*
*/
int
netlbl_domhsh_remove
(
const
char
*
domain
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
;
struct
netlbl_dom_map
*
entry
;
rcu_read_lock
();
if
(
domain
)
entry
=
netlbl_domhsh_search
(
domain
);
else
entry
=
netlbl_domhsh_search_def
(
domain
);
ret_val
=
netlbl_domhsh_remove_entry
(
entry
,
audit_info
);
rcu_read_unlock
();
return
ret_val
;
}
...
...
@@ -388,6 +539,70 @@ struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain)
return
netlbl_domhsh_search_def
(
domain
);
}
/**
* netlbl_domhsh_getentry_af4 - Get an entry from the domain hash table
* @domain: the domain name to search for
* @addr: the IP address to search for
*
* Description:
* Look through the domain hash table searching for an entry to match @domain
* and @addr, return a pointer to a copy of the entry or NULL. The caller is
* responsible for ensuring that rcu_read_[un]lock() is called.
*
*/
struct
netlbl_domaddr4_map
*
netlbl_domhsh_getentry_af4
(
const
char
*
domain
,
__be32
addr
)
{
struct
netlbl_dom_map
*
dom_iter
;
struct
netlbl_af4list
*
addr_iter
;
dom_iter
=
netlbl_domhsh_search_def
(
domain
);
if
(
dom_iter
==
NULL
)
return
NULL
;
if
(
dom_iter
->
type
!=
NETLBL_NLTYPE_ADDRSELECT
)
return
NULL
;
addr_iter
=
netlbl_af4list_search
(
addr
,
&
dom_iter
->
type_def
.
addrsel
->
list4
);
if
(
addr_iter
==
NULL
)
return
NULL
;
return
netlbl_domhsh_addr4_entry
(
addr_iter
);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
* netlbl_domhsh_getentry_af6 - Get an entry from the domain hash table
* @domain: the domain name to search for
* @addr: the IP address to search for
*
* Description:
* Look through the domain hash table searching for an entry to match @domain
* and @addr, return a pointer to a copy of the entry or NULL. The caller is
* responsible for ensuring that rcu_read_[un]lock() is called.
*
*/
struct
netlbl_domaddr6_map
*
netlbl_domhsh_getentry_af6
(
const
char
*
domain
,
const
struct
in6_addr
*
addr
)
{
struct
netlbl_dom_map
*
dom_iter
;
struct
netlbl_af6list
*
addr_iter
;
dom_iter
=
netlbl_domhsh_search_def
(
domain
);
if
(
dom_iter
==
NULL
)
return
NULL
;
if
(
dom_iter
->
type
!=
NETLBL_NLTYPE_ADDRSELECT
)
return
NULL
;
addr_iter
=
netlbl_af6list_search
(
addr
,
&
dom_iter
->
type_def
.
addrsel
->
list6
);
if
(
addr_iter
==
NULL
)
return
NULL
;
return
netlbl_domhsh_addr6_entry
(
addr_iter
);
}
#endif
/* IPv6 */
/**
* netlbl_domhsh_walk - Iterate through the domain mapping hash table
* @skip_bkt: the number of buckets to skip at the start
...
...
@@ -410,6 +625,7 @@ int netlbl_domhsh_walk(u32 *skip_bkt,
{
int
ret_val
=
-
ENOENT
;
u32
iter_bkt
;
struct
list_head
*
iter_list
;
struct
netlbl_dom_map
*
iter_entry
;
u32
chain_cnt
=
0
;
...
...
@@ -417,9 +633,8 @@ int netlbl_domhsh_walk(u32 *skip_bkt,
for
(
iter_bkt
=
*
skip_bkt
;
iter_bkt
<
rcu_dereference
(
netlbl_domhsh
)
->
size
;
iter_bkt
++
,
chain_cnt
=
0
)
{
list_for_each_entry_rcu
(
iter_entry
,
&
rcu_dereference
(
netlbl_domhsh
)
->
tbl
[
iter_bkt
],
list
)
iter_list
=
&
rcu_dereference
(
netlbl_domhsh
)
->
tbl
[
iter_bkt
];
list_for_each_entry_rcu
(
iter_entry
,
iter_list
,
list
)
if
(
iter_entry
->
valid
)
{
if
(
chain_cnt
++
<
*
skip_chain
)
continue
;
...
...
net/netlabel/netlabel_domainhash.h
View file @
0da939b0
...
...
@@ -11,7 +11,7 @@
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -36,16 +36,43 @@
#include <linux/rcupdate.h>
#include <linux/list.h>
#include "netlabel_addrlist.h"
/* Domain hash table size */
/* XXX - currently this number is an uneducated guess */
#define NETLBL_DOMHSH_BITSIZE 7
/* Domain mapping definition struct */
/* Domain mapping definition structures */
#define netlbl_domhsh_addr4_entry(iter) \
container_of(iter, struct netlbl_domaddr4_map, list)
struct
netlbl_domaddr4_map
{
u32
type
;
union
{
struct
cipso_v4_doi
*
cipsov4
;
}
type_def
;
struct
netlbl_af4list
list
;
};
#define netlbl_domhsh_addr6_entry(iter) \
container_of(iter, struct netlbl_domaddr6_map, list)
struct
netlbl_domaddr6_map
{
u32
type
;
/* NOTE: no 'type_def' union needed at present since we don't currently
* support any IPv6 labeling protocols */
struct
netlbl_af6list
list
;
};
struct
netlbl_domaddr_map
{
struct
list_head
list4
;
struct
list_head
list6
;
};
struct
netlbl_dom_map
{
char
*
domain
;
u32
type
;
union
{
struct
cipso_v4_doi
*
cipsov4
;
struct
netlbl_domaddr_map
*
addrsel
;
}
type_def
;
u32
valid
;
...
...
@@ -61,12 +88,21 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
struct
netlbl_audit
*
audit_info
);
int
netlbl_domhsh_add_default
(
struct
netlbl_dom_map
*
entry
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_domhsh_remove_entry
(
struct
netlbl_dom_map
*
entry
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_domhsh_remove
(
const
char
*
domain
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_domhsh_remove_default
(
struct
netlbl_audit
*
audit_info
);
struct
netlbl_dom_map
*
netlbl_domhsh_getentry
(
const
char
*
domain
);
struct
netlbl_domaddr4_map
*
netlbl_domhsh_getentry_af4
(
const
char
*
domain
,
__be32
addr
);
int
netlbl_domhsh_walk
(
u32
*
skip_bkt
,
u32
*
skip_chain
,
int
(
*
callback
)
(
struct
netlbl_dom_map
*
entry
,
void
*
arg
),
void
*
cb_arg
);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct
netlbl_domaddr6_map
*
netlbl_domhsh_getentry_af6
(
const
char
*
domain
,
const
struct
in6_addr
*
addr
);
#endif
/* IPv6 */
#endif
net/netlabel/netlabel_kapi.c
View file @
0da939b0
...
...
@@ -10,7 +10,7 @@
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -82,7 +82,7 @@ int netlbl_cfg_unlbl_add_map(const char *domain,
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_ATOMIC
);
if
(
entry
==
NULL
)
goto
cfg_unlbl_add_map_failure
;
return
-
ENOMEM
;
if
(
domain
!=
NULL
)
{
entry
->
domain
=
kstrdup
(
domain
,
GFP_ATOMIC
);
if
(
entry
->
domain
==
NULL
)
...
...
@@ -103,49 +103,6 @@ int netlbl_cfg_unlbl_add_map(const char *domain,
return
ret_val
;
}
/**
* netlbl_cfg_cipsov4_add - Add a new CIPSOv4 DOI definition
* @doi_def: the DOI definition
* @audit_info: NetLabel audit information
*
* Description:
* Add a new CIPSOv4 DOI definition to the NetLabel subsystem. Returns zero on
* success, negative values on failure.
*
*/
int
netlbl_cfg_cipsov4_add
(
struct
cipso_v4_doi
*
doi_def
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
;
const
char
*
type_str
;
struct
audit_buffer
*
audit_buf
;
ret_val
=
cipso_v4_doi_add
(
doi_def
);
audit_buf
=
netlbl_audit_start_common
(
AUDIT_MAC_CIPSOV4_ADD
,
audit_info
);
if
(
audit_buf
!=
NULL
)
{
switch
(
doi_def
->
type
)
{
case
CIPSO_V4_MAP_STD
:
type_str
=
"std"
;
break
;
case
CIPSO_V4_MAP_PASS
:
type_str
=
"pass"
;
break
;
default:
type_str
=
"(unknown)"
;
}
audit_log_format
(
audit_buf
,
" cipso_doi=%u cipso_type=%s res=%u"
,
doi_def
->
doi
,
type_str
,
ret_val
==
0
?
1
:
0
);
audit_log_end
(
audit_buf
);
}
return
ret_val
;
}
/**
* netlbl_cfg_cipsov4_add_map - Add a new CIPSOv4 DOI definition and mapping
* @doi_def: the DOI definition
...
...
@@ -164,58 +121,71 @@ int netlbl_cfg_cipsov4_add_map(struct cipso_v4_doi *doi_def,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
=
-
ENOMEM
;
u32
doi
;
u32
doi_type
;
struct
netlbl_dom_map
*
entry
;
const
char
*
type_str
;
struct
audit_buffer
*
audit_buf
;
doi
=
doi_def
->
doi
;
doi_type
=
doi_def
->
type
;
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_ATOMIC
);
if
(
entry
==
NULL
)
goto
cfg_cipsov4_add_map_failure
;
return
-
ENOMEM
;
if
(
domain
!=
NULL
)
{
entry
->
domain
=
kstrdup
(
domain
,
GFP_ATOMIC
);
if
(
entry
->
domain
==
NULL
)
goto
cfg_cipsov4_add_map_failure
;
}
entry
->
type
=
NETLBL_NLTYPE_CIPSOV4
;
entry
->
type_def
.
cipsov4
=
doi_def
;
/* Grab a RCU read lock here so nothing happens to the doi_def variable
* between adding it to the CIPSOv4 protocol engine and adding a
* domain mapping for it. */
rcu_read_lock
();
ret_val
=
netlbl_cfg_cipsov4_add
(
doi_def
,
audit_info
);
ret_val
=
cipso_v4_doi_add
(
doi_def
);
if
(
ret_val
!=
0
)
goto
cfg_cipsov4_add_map_failure_unlock
;
goto
cfg_cipsov4_add_map_failure_remove_doi
;
entry
->
type
=
NETLBL_NLTYPE_CIPSOV4
;
entry
->
type_def
.
cipsov4
=
cipso_v4_doi_getdef
(
doi
);
if
(
entry
->
type_def
.
cipsov4
==
NULL
)
{
ret_val
=
-
ENOENT
;
goto
cfg_cipsov4_add_map_failure_remove_doi
;
}
ret_val
=
netlbl_domhsh_add
(
entry
,
audit_info
);
if
(
ret_val
!=
0
)
goto
cfg_cipsov4_add_map_failure_remove_doi
;
rcu_read_unlock
();
goto
cfg_cipsov4_add_map_failure_release_doi
;
return
0
;
cfg_cipsov4_add_map_return:
audit_buf
=
netlbl_audit_start_common
(
AUDIT_MAC_CIPSOV4_ADD
,
audit_info
);
if
(
audit_buf
!=
NULL
)
{
switch
(
doi_type
)
{
case
CIPSO_V4_MAP_TRANS
:
type_str
=
"trans"
;
break
;
case
CIPSO_V4_MAP_PASS
:
type_str
=
"pass"
;
break
;
case
CIPSO_V4_MAP_LOCAL
:
type_str
=
"local"
;
break
;
default:
type_str
=
"(unknown)"
;
}
audit_log_format
(
audit_buf
,
" cipso_doi=%u cipso_type=%s res=%u"
,
doi
,
type_str
,
ret_val
==
0
?
1
:
0
);
audit_log_end
(
audit_buf
);
}
return
ret_val
;
cfg_cipsov4_add_map_failure_release_doi:
cipso_v4_doi_putdef
(
doi_def
);
cfg_cipsov4_add_map_failure_remove_doi:
cipso_v4_doi_remove
(
doi_def
->
doi
,
audit_info
,
netlbl_cipsov4_doi_free
);
cfg_cipsov4_add_map_failure_unlock:
rcu_read_unlock
();
cipso_v4_doi_remove
(
doi
,
audit_info
);
cfg_cipsov4_add_map_failure:
if
(
entry
!=
NULL
)
kfree
(
entry
->
domain
);
kfree
(
entry
);
return
ret_val
;
}
/**
* netlbl_cfg_cipsov4_del - Removean existing CIPSOv4 DOI definition
* @doi: the CIPSO DOI value
* @audit_info: NetLabel audit information
*
* Description:
* Removes an existing CIPSOv4 DOI definition from the NetLabel subsystem.
* Returns zero on success, negative values on failure.
*
*/
int
netlbl_cfg_cipsov4_del
(
u32
doi
,
struct
netlbl_audit
*
audit_info
)
{
return
cipso_v4_doi_remove
(
doi
,
audit_info
,
netlbl_cipsov4_doi_free
);
goto
cfg_cipsov4_add_map_return
;
}
/*
...
...
@@ -452,7 +422,9 @@ int netlbl_enabled(void)
* Attach the correct label to the given socket using the security attributes
* specified in @secattr. This function requires exclusive access to @sk,
* which means it either needs to be in the process of being created or locked.
* Returns zero on success, negative values on failure.
* Returns zero on success, -EDESTADDRREQ if the domain is configured to use
* network address selectors (can't blindly label the socket), and negative
* values on all other failures.
*
*/
int
netlbl_sock_setattr
(
struct
sock
*
sk
,
...
...
@@ -466,6 +438,9 @@ int netlbl_sock_setattr(struct sock *sk,
if
(
dom_entry
==
NULL
)
goto
socket_setattr_return
;
switch
(
dom_entry
->
type
)
{
case
NETLBL_NLTYPE_ADDRSELECT
:
ret_val
=
-
EDESTADDRREQ
;
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
cipso_v4_sock_setattr
(
sk
,
dom_entry
->
type_def
.
cipsov4
,
...
...
@@ -483,6 +458,20 @@ int netlbl_sock_setattr(struct sock *sk,
return
ret_val
;
}
/**
* netlbl_sock_delattr - Delete all the NetLabel labels on a socket
* @sk: the socket
*
* Description:
* Remove all the NetLabel labeling from @sk. The caller is responsible for
* ensuring that @sk is locked.
*
*/
void
netlbl_sock_delattr
(
struct
sock
*
sk
)
{
cipso_v4_sock_delattr
(
sk
);
}
/**
* netlbl_sock_getattr - Determine the security attributes of a sock
* @sk: the sock
...
...
@@ -500,6 +489,128 @@ int netlbl_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr)
return
cipso_v4_sock_getattr
(
sk
,
secattr
);
}
/**
* netlbl_conn_setattr - Label a connected socket using the correct protocol
* @sk: the socket to label
* @addr: the destination address
* @secattr: the security attributes
*
* Description:
* Attach the correct label to the given connected socket using the security
* attributes specified in @secattr. The caller is responsible for ensuring
* that @sk is locked. Returns zero on success, negative values on failure.
*
*/
int
netlbl_conn_setattr
(
struct
sock
*
sk
,
struct
sockaddr
*
addr
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
;
struct
sockaddr_in
*
addr4
;
struct
netlbl_domaddr4_map
*
af4_entry
;
rcu_read_lock
();
switch
(
addr
->
sa_family
)
{
case
AF_INET
:
addr4
=
(
struct
sockaddr_in
*
)
addr
;
af4_entry
=
netlbl_domhsh_getentry_af4
(
secattr
->
domain
,
addr4
->
sin_addr
.
s_addr
);
if
(
af4_entry
==
NULL
)
{
ret_val
=
-
ENOENT
;
goto
conn_setattr_return
;
}
switch
(
af4_entry
->
type
)
{
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
cipso_v4_sock_setattr
(
sk
,
af4_entry
->
type_def
.
cipsov4
,
secattr
);
break
;
case
NETLBL_NLTYPE_UNLABELED
:
/* just delete the protocols we support for right now
* but we could remove other protocols if needed */
cipso_v4_sock_delattr
(
sk
);
ret_val
=
0
;
break
;
default:
ret_val
=
-
ENOENT
;
}
break
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case
AF_INET6
:
/* since we don't support any IPv6 labeling protocols right
* now we can optimize everything away until we do */
ret_val
=
0
;
break
;
#endif
/* IPv6 */
default:
ret_val
=
0
;
}
conn_setattr_return:
rcu_read_unlock
();
return
ret_val
;
}
/**
* netlbl_skbuff_setattr - Label a packet using the correct protocol
* @skb: the packet
* @family: protocol family
* @secattr: the security attributes
*
* Description:
* Attach the correct label to the given packet using the security attributes
* specified in @secattr. Returns zero on success, negative values on failure.
*
*/
int
netlbl_skbuff_setattr
(
struct
sk_buff
*
skb
,
u16
family
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
;
struct
iphdr
*
hdr4
;
struct
netlbl_domaddr4_map
*
af4_entry
;
rcu_read_lock
();
switch
(
family
)
{
case
AF_INET
:
hdr4
=
ip_hdr
(
skb
);
af4_entry
=
netlbl_domhsh_getentry_af4
(
secattr
->
domain
,
hdr4
->
daddr
);
if
(
af4_entry
==
NULL
)
{
ret_val
=
-
ENOENT
;
goto
skbuff_setattr_return
;
}
switch
(
af4_entry
->
type
)
{
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
cipso_v4_skbuff_setattr
(
skb
,
af4_entry
->
type_def
.
cipsov4
,
secattr
);
break
;
case
NETLBL_NLTYPE_UNLABELED
:
/* just delete the protocols we support for right now
* but we could remove other protocols if needed */
ret_val
=
cipso_v4_skbuff_delattr
(
skb
);
break
;
default:
ret_val
=
-
ENOENT
;
}
break
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case
AF_INET6
:
/* since we don't support any IPv6 labeling protocols right
* now we can optimize everything away until we do */
ret_val
=
0
;
break
;
#endif
/* IPv6 */
default:
ret_val
=
0
;
}
skbuff_setattr_return:
rcu_read_unlock
();
return
ret_val
;
}
/**
* netlbl_skbuff_getattr - Determine the security attributes of a packet
* @skb: the packet
...
...
@@ -528,6 +639,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
* netlbl_skbuff_err - Handle a LSM error on a sk_buff
* @skb: the packet
* @error: the error code
* @gateway: true if host is acting as a gateway, false otherwise
*
* Description:
* Deal with a LSM problem when handling the packet in @skb, typically this is
...
...
@@ -535,10 +647,10 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
* according to the packet's labeling protocol.
*
*/
void
netlbl_skbuff_err
(
struct
sk_buff
*
skb
,
int
error
)
void
netlbl_skbuff_err
(
struct
sk_buff
*
skb
,
int
error
,
int
gateway
)
{
if
(
CIPSO_V4_OPTEXIST
(
skb
))
cipso_v4_error
(
skb
,
error
,
0
);
cipso_v4_error
(
skb
,
error
,
gateway
);
}
/**
...
...
net/netlabel/netlabel_mgmt.c
View file @
0da939b0
...
...
@@ -10,7 +10,7 @@
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -32,9 +32,13 @@
#include <linux/socket.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <net/genetlink.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
#include <asm/atomic.h>
...
...
@@ -71,85 +75,336 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
};
/*
*
NetLabel Command Handler
s
*
Helper Function
s
*/
/**
* netlbl_mgmt_add - Handle an ADD message
* @skb: the NETLINK buffer
* @info: the Generic NETLINK info block
* @audit_info: NetLabel audit information
*
* Description:
*
Process a user generated ADD message and add the domains from the message
*
to the hash table. See netlabel.h for a description of the message format.
* Returns zero on success, negative values on failure.
*
Helper function for the ADD and ADDDEF messages to add the domain mappings
*
from the message to the hash table. See netlabel.h for a description of the
*
message format.
Returns zero on success, negative values on failure.
*
*/
static
int
netlbl_mgmt_add
(
struct
sk_buff
*
skb
,
struct
genl_info
*
info
)
static
int
netlbl_mgmt_add_common
(
struct
genl_info
*
info
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
=
-
EINVAL
;
struct
netlbl_dom_map
*
entry
=
NULL
;
size_t
tmp_size
;
struct
netlbl_domaddr_map
*
addrmap
=
NULL
;
struct
cipso_v4_doi
*
cipsov4
=
NULL
;
u32
tmp_val
;
struct
netlbl_audit
audit_info
;
if
(
!
info
->
attrs
[
NLBL_MGMT_A_DOMAIN
]
||
!
info
->
attrs
[
NLBL_MGMT_A_PROTOCOL
])
goto
add_failure
;
netlbl_netlink_auditinfo
(
skb
,
&
audit_info
);
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_KERNEL
);
if
(
entry
==
NULL
)
{
ret_val
=
-
ENOMEM
;
goto
add_failure
;
}
tmp_size
=
nla_len
(
info
->
attrs
[
NLBL_MGMT_A_DOMAIN
]);
entry
->
type
=
nla_get_u32
(
info
->
attrs
[
NLBL_MGMT_A_PROTOCOL
]);
if
(
info
->
attrs
[
NLBL_MGMT_A_DOMAIN
])
{
size_t
tmp_size
=
nla_len
(
info
->
attrs
[
NLBL_MGMT_A_DOMAIN
]);
entry
->
domain
=
kmalloc
(
tmp_size
,
GFP_KERNEL
);
if
(
entry
->
domain
==
NULL
)
{
ret_val
=
-
ENOMEM
;
goto
add_failure
;
}
entry
->
type
=
nla_get_u32
(
info
->
attrs
[
NLBL_MGMT_A_PROTOCOL
]);
nla_strlcpy
(
entry
->
domain
,
info
->
attrs
[
NLBL_MGMT_A_DOMAIN
],
tmp_size
);
nla_strlcpy
(
entry
->
domain
,
info
->
attrs
[
NLBL_MGMT_A_DOMAIN
],
tmp_size
);
}
/* NOTE: internally we allow/use a entry->type value of
* NETLBL_NLTYPE_ADDRSELECT but we don't currently allow users
* to pass that as a protocol value because we need to know the
* "real" protocol */
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_UNLABELED
:
ret_val
=
netlbl_domhsh_add
(
entry
,
&
audit_info
);
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
if
(
!
info
->
attrs
[
NLBL_MGMT_A_CV4DOI
])
goto
add_failure
;
tmp_val
=
nla_get_u32
(
info
->
attrs
[
NLBL_MGMT_A_CV4DOI
]);
/* We should be holding a rcu_read_lock() here while we hold
* the result but since the entry will always be deleted when
* the CIPSO DOI is deleted we aren't going to keep the
* lock. */
rcu_read_lock
();
entry
->
type_def
.
cipsov4
=
cipso_v4_doi_getdef
(
tmp_val
);
if
(
entry
->
type_def
.
cipsov4
==
NULL
)
{
rcu_read_unlock
();
cipsov4
=
cipso_v4_doi_getdef
(
tmp_val
);
if
(
cipsov4
==
NULL
)
goto
add_failure
;
}
ret_val
=
netlbl_domhsh_add
(
entry
,
&
audit_info
);
rcu_read_unlock
();
entry
->
type_def
.
cipsov4
=
cipsov4
;
break
;
default:
goto
add_failure
;
}
if
(
info
->
attrs
[
NLBL_MGMT_A_IPV4ADDR
])
{
struct
in_addr
*
addr
;
struct
in_addr
*
mask
;
struct
netlbl_domaddr4_map
*
map
;
addrmap
=
kzalloc
(
sizeof
(
*
addrmap
),
GFP_KERNEL
);
if
(
addrmap
==
NULL
)
{
ret_val
=
-
ENOMEM
;
goto
add_failure
;
}
INIT_LIST_HEAD
(
&
addrmap
->
list4
);
INIT_LIST_HEAD
(
&
addrmap
->
list6
);
if
(
nla_len
(
info
->
attrs
[
NLBL_MGMT_A_IPV4ADDR
])
!=
sizeof
(
struct
in_addr
))
{
ret_val
=
-
EINVAL
;
goto
add_failure
;
}
if
(
nla_len
(
info
->
attrs
[
NLBL_MGMT_A_IPV4MASK
])
!=
sizeof
(
struct
in_addr
))
{
ret_val
=
-
EINVAL
;
goto
add_failure
;
}
addr
=
nla_data
(
info
->
attrs
[
NLBL_MGMT_A_IPV4ADDR
]);
mask
=
nla_data
(
info
->
attrs
[
NLBL_MGMT_A_IPV4MASK
]);
map
=
kzalloc
(
sizeof
(
*
map
),
GFP_KERNEL
);
if
(
map
==
NULL
)
{
ret_val
=
-
ENOMEM
;
goto
add_failure
;
}
map
->
list
.
addr
=
addr
->
s_addr
&
mask
->
s_addr
;
map
->
list
.
mask
=
mask
->
s_addr
;
map
->
list
.
valid
=
1
;
map
->
type
=
entry
->
type
;
if
(
cipsov4
)
map
->
type_def
.
cipsov4
=
cipsov4
;
ret_val
=
netlbl_af4list_add
(
&
map
->
list
,
&
addrmap
->
list4
);
if
(
ret_val
!=
0
)
{
kfree
(
map
);
goto
add_failure
;
}
entry
->
type
=
NETLBL_NLTYPE_ADDRSELECT
;
entry
->
type_def
.
addrsel
=
addrmap
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
}
else
if
(
info
->
attrs
[
NLBL_MGMT_A_IPV6ADDR
])
{
struct
in6_addr
*
addr
;
struct
in6_addr
*
mask
;
struct
netlbl_domaddr6_map
*
map
;
addrmap
=
kzalloc
(
sizeof
(
*
addrmap
),
GFP_KERNEL
);
if
(
addrmap
==
NULL
)
{
ret_val
=
-
ENOMEM
;
goto
add_failure
;
}
INIT_LIST_HEAD
(
&
addrmap
->
list4
);
INIT_LIST_HEAD
(
&
addrmap
->
list6
);
if
(
nla_len
(
info
->
attrs
[
NLBL_MGMT_A_IPV6ADDR
])
!=
sizeof
(
struct
in6_addr
))
{
ret_val
=
-
EINVAL
;
goto
add_failure
;
}
if
(
nla_len
(
info
->
attrs
[
NLBL_MGMT_A_IPV6MASK
])
!=
sizeof
(
struct
in6_addr
))
{
ret_val
=
-
EINVAL
;
goto
add_failure
;
}
addr
=
nla_data
(
info
->
attrs
[
NLBL_MGMT_A_IPV6ADDR
]);
mask
=
nla_data
(
info
->
attrs
[
NLBL_MGMT_A_IPV6MASK
]);
map
=
kzalloc
(
sizeof
(
*
map
),
GFP_KERNEL
);
if
(
map
==
NULL
)
{
ret_val
=
-
ENOMEM
;
goto
add_failure
;
}
ipv6_addr_copy
(
&
map
->
list
.
addr
,
addr
);
map
->
list
.
addr
.
s6_addr32
[
0
]
&=
mask
->
s6_addr32
[
0
];
map
->
list
.
addr
.
s6_addr32
[
1
]
&=
mask
->
s6_addr32
[
1
];
map
->
list
.
addr
.
s6_addr32
[
2
]
&=
mask
->
s6_addr32
[
2
];
map
->
list
.
addr
.
s6_addr32
[
3
]
&=
mask
->
s6_addr32
[
3
];
ipv6_addr_copy
(
&
map
->
list
.
mask
,
mask
);
map
->
list
.
valid
=
1
;
map
->
type
=
entry
->
type
;
ret_val
=
netlbl_af6list_add
(
&
map
->
list
,
&
addrmap
->
list6
);
if
(
ret_val
!=
0
)
{
kfree
(
map
);
goto
add_failure
;
}
entry
->
type
=
NETLBL_NLTYPE_ADDRSELECT
;
entry
->
type_def
.
addrsel
=
addrmap
;
#endif
/* IPv6 */
}
ret_val
=
netlbl_domhsh_add
(
entry
,
audit_info
);
if
(
ret_val
!=
0
)
goto
add_failure
;
return
0
;
add_failure:
if
(
cipsov4
)
cipso_v4_doi_putdef
(
cipsov4
);
if
(
entry
)
kfree
(
entry
->
domain
);
kfree
(
addrmap
);
kfree
(
entry
);
return
ret_val
;
}
/**
* netlbl_mgmt_listentry - List a NetLabel/LSM domain map entry
* @skb: the NETLINK buffer
* @entry: the map entry
*
* Description:
* This function is a helper function used by the LISTALL and LISTDEF command
* handlers. The caller is responsibile for ensuring that the RCU read lock
* is held. Returns zero on success, negative values on failure.
*
*/
static
int
netlbl_mgmt_listentry
(
struct
sk_buff
*
skb
,
struct
netlbl_dom_map
*
entry
)
{
int
ret_val
;
struct
nlattr
*
nla_a
;
struct
nlattr
*
nla_b
;
struct
netlbl_af4list
*
iter4
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct
netlbl_af6list
*
iter6
;
#endif
if
(
entry
->
domain
!=
NULL
)
{
ret_val
=
nla_put_string
(
skb
,
NLBL_MGMT_A_DOMAIN
,
entry
->
domain
);
if
(
ret_val
!=
0
)
return
ret_val
;
}
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_ADDRSELECT
:
nla_a
=
nla_nest_start
(
skb
,
NLBL_MGMT_A_SELECTORLIST
);
if
(
nla_a
==
NULL
)
return
-
ENOMEM
;
netlbl_af4list_foreach_rcu
(
iter4
,
&
entry
->
type_def
.
addrsel
->
list4
)
{
struct
netlbl_domaddr4_map
*
map4
;
struct
in_addr
addr_struct
;
nla_b
=
nla_nest_start
(
skb
,
NLBL_MGMT_A_ADDRSELECTOR
);
if
(
nla_b
==
NULL
)
return
-
ENOMEM
;
addr_struct
.
s_addr
=
iter4
->
addr
;
ret_val
=
nla_put
(
skb
,
NLBL_MGMT_A_IPV4ADDR
,
sizeof
(
struct
in_addr
),
&
addr_struct
);
if
(
ret_val
!=
0
)
return
ret_val
;
addr_struct
.
s_addr
=
iter4
->
mask
;
ret_val
=
nla_put
(
skb
,
NLBL_MGMT_A_IPV4MASK
,
sizeof
(
struct
in_addr
),
&
addr_struct
);
if
(
ret_val
!=
0
)
return
ret_val
;
map4
=
netlbl_domhsh_addr4_entry
(
iter4
);
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_PROTOCOL
,
map4
->
type
);
if
(
ret_val
!=
0
)
return
ret_val
;
switch
(
map4
->
type
)
{
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_CV4DOI
,
map4
->
type_def
.
cipsov4
->
doi
);
if
(
ret_val
!=
0
)
return
ret_val
;
break
;
}
nla_nest_end
(
skb
,
nla_b
);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
netlbl_af6list_foreach_rcu
(
iter6
,
&
entry
->
type_def
.
addrsel
->
list6
)
{
struct
netlbl_domaddr6_map
*
map6
;
nla_b
=
nla_nest_start
(
skb
,
NLBL_MGMT_A_ADDRSELECTOR
);
if
(
nla_b
==
NULL
)
return
-
ENOMEM
;
ret_val
=
nla_put
(
skb
,
NLBL_MGMT_A_IPV6ADDR
,
sizeof
(
struct
in6_addr
),
&
iter6
->
addr
);
if
(
ret_val
!=
0
)
return
ret_val
;
ret_val
=
nla_put
(
skb
,
NLBL_MGMT_A_IPV6MASK
,
sizeof
(
struct
in6_addr
),
&
iter6
->
mask
);
if
(
ret_val
!=
0
)
return
ret_val
;
map6
=
netlbl_domhsh_addr6_entry
(
iter6
);
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_PROTOCOL
,
map6
->
type
);
if
(
ret_val
!=
0
)
return
ret_val
;
nla_nest_end
(
skb
,
nla_b
);
}
#endif
/* IPv6 */
nla_nest_end
(
skb
,
nla_a
);
break
;
case
NETLBL_NLTYPE_UNLABELED
:
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_PROTOCOL
,
entry
->
type
);
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_PROTOCOL
,
entry
->
type
);
if
(
ret_val
!=
0
)
return
ret_val
;
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_CV4DOI
,
entry
->
type_def
.
cipsov4
->
doi
);
break
;
}
return
ret_val
;
}
/*
* NetLabel Command Handlers
*/
/**
* netlbl_mgmt_add - Handle an ADD message
* @skb: the NETLINK buffer
* @info: the Generic NETLINK info block
*
* Description:
* Process a user generated ADD message and add the domains from the message
* to the hash table. See netlabel.h for a description of the message format.
* Returns zero on success, negative values on failure.
*
*/
static
int
netlbl_mgmt_add
(
struct
sk_buff
*
skb
,
struct
genl_info
*
info
)
{
struct
netlbl_audit
audit_info
;
if
((
!
info
->
attrs
[
NLBL_MGMT_A_DOMAIN
])
||
(
!
info
->
attrs
[
NLBL_MGMT_A_PROTOCOL
])
||
(
info
->
attrs
[
NLBL_MGMT_A_IPV4ADDR
]
&&
info
->
attrs
[
NLBL_MGMT_A_IPV6ADDR
])
||
(
info
->
attrs
[
NLBL_MGMT_A_IPV4MASK
]
&&
info
->
attrs
[
NLBL_MGMT_A_IPV6MASK
])
||
((
info
->
attrs
[
NLBL_MGMT_A_IPV4ADDR
]
!=
NULL
)
^
(
info
->
attrs
[
NLBL_MGMT_A_IPV4MASK
]
!=
NULL
))
||
((
info
->
attrs
[
NLBL_MGMT_A_IPV6ADDR
]
!=
NULL
)
^
(
info
->
attrs
[
NLBL_MGMT_A_IPV6MASK
]
!=
NULL
)))
return
-
EINVAL
;
netlbl_netlink_auditinfo
(
skb
,
&
audit_info
);
return
netlbl_mgmt_add_common
(
info
,
&
audit_info
);
}
/**
* netlbl_mgmt_remove - Handle a REMOVE message
* @skb: the NETLINK buffer
...
...
@@ -198,23 +453,9 @@ static int netlbl_mgmt_listall_cb(struct netlbl_dom_map *entry, void *arg)
if
(
data
==
NULL
)
goto
listall_cb_failure
;
ret_val
=
nla_put_string
(
cb_arg
->
skb
,
NLBL_MGMT_A_DOMAIN
,
entry
->
domain
);
if
(
ret_val
!=
0
)
goto
listall_cb_failure
;
ret_val
=
nla_put_u32
(
cb_arg
->
skb
,
NLBL_MGMT_A_PROTOCOL
,
entry
->
type
);
if
(
ret_val
!=
0
)
goto
listall_cb_failure
;
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
nla_put_u32
(
cb_arg
->
skb
,
NLBL_MGMT_A_CV4DOI
,
entry
->
type_def
.
cipsov4
->
doi
);
ret_val
=
netlbl_mgmt_listentry
(
cb_arg
->
skb
,
entry
);
if
(
ret_val
!=
0
)
goto
listall_cb_failure
;
break
;
}
cb_arg
->
seq
++
;
return
genlmsg_end
(
cb_arg
->
skb
,
data
);
...
...
@@ -268,56 +509,22 @@ static int netlbl_mgmt_listall(struct sk_buff *skb,
*/
static
int
netlbl_mgmt_adddef
(
struct
sk_buff
*
skb
,
struct
genl_info
*
info
)
{
int
ret_val
=
-
EINVAL
;
struct
netlbl_dom_map
*
entry
=
NULL
;
u32
tmp_val
;
struct
netlbl_audit
audit_info
;
if
(
!
info
->
attrs
[
NLBL_MGMT_A_PROTOCOL
])
goto
adddef_failure
;
if
((
!
info
->
attrs
[
NLBL_MGMT_A_PROTOCOL
])
||
(
info
->
attrs
[
NLBL_MGMT_A_IPV4ADDR
]
&&
info
->
attrs
[
NLBL_MGMT_A_IPV6ADDR
])
||
(
info
->
attrs
[
NLBL_MGMT_A_IPV4MASK
]
&&
info
->
attrs
[
NLBL_MGMT_A_IPV6MASK
])
||
((
info
->
attrs
[
NLBL_MGMT_A_IPV4ADDR
]
!=
NULL
)
^
(
info
->
attrs
[
NLBL_MGMT_A_IPV4MASK
]
!=
NULL
))
||
((
info
->
attrs
[
NLBL_MGMT_A_IPV6ADDR
]
!=
NULL
)
^
(
info
->
attrs
[
NLBL_MGMT_A_IPV6MASK
]
!=
NULL
)))
return
-
EINVAL
;
netlbl_netlink_auditinfo
(
skb
,
&
audit_info
);
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_KERNEL
);
if
(
entry
==
NULL
)
{
ret_val
=
-
ENOMEM
;
goto
adddef_failure
;
}
entry
->
type
=
nla_get_u32
(
info
->
attrs
[
NLBL_MGMT_A_PROTOCOL
]);
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_UNLABELED
:
ret_val
=
netlbl_domhsh_add_default
(
entry
,
&
audit_info
);
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
if
(
!
info
->
attrs
[
NLBL_MGMT_A_CV4DOI
])
goto
adddef_failure
;
tmp_val
=
nla_get_u32
(
info
->
attrs
[
NLBL_MGMT_A_CV4DOI
]);
/* We should be holding a rcu_read_lock() here while we hold
* the result but since the entry will always be deleted when
* the CIPSO DOI is deleted we aren't going to keep the
* lock. */
rcu_read_lock
();
entry
->
type_def
.
cipsov4
=
cipso_v4_doi_getdef
(
tmp_val
);
if
(
entry
->
type_def
.
cipsov4
==
NULL
)
{
rcu_read_unlock
();
goto
adddef_failure
;
}
ret_val
=
netlbl_domhsh_add_default
(
entry
,
&
audit_info
);
rcu_read_unlock
();
break
;
default:
goto
adddef_failure
;
}
if
(
ret_val
!=
0
)
goto
adddef_failure
;
return
0
;
adddef_failure:
kfree
(
entry
);
return
ret_val
;
return
netlbl_mgmt_add_common
(
info
,
&
audit_info
);
}
/**
...
...
@@ -371,19 +578,10 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
ret_val
=
-
ENOENT
;
goto
listdef_failure_lock
;
}
ret_val
=
nla_put_u32
(
ans_skb
,
NLBL_MGMT_A_PROTOCOL
,
entry
->
type
);
if
(
ret_val
!=
0
)
goto
listdef_failure_lock
;
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
nla_put_u32
(
ans_skb
,
NLBL_MGMT_A_CV4DOI
,
entry
->
type_def
.
cipsov4
->
doi
);
if
(
ret_val
!=
0
)
goto
listdef_failure_lock
;
break
;
}
ret_val
=
netlbl_mgmt_listentry
(
ans_skb
,
entry
);
rcu_read_unlock
();
if
(
ret_val
!=
0
)
goto
listdef_failure
;
genlmsg_end
(
ans_skb
,
data
);
return
genlmsg_reply
(
ans_skb
,
info
);
...
...
net/netlabel/netlabel_mgmt.h
View file @
0da939b0
...
...
@@ -45,6 +45,16 @@
* NLBL_MGMT_A_DOMAIN
* NLBL_MGMT_A_PROTOCOL
*
* If IPv4 is specified the following attributes are required:
*
* NLBL_MGMT_A_IPV4ADDR
* NLBL_MGMT_A_IPV4MASK
*
* If IPv6 is specified the following attributes are required:
*
* NLBL_MGMT_A_IPV6ADDR
* NLBL_MGMT_A_IPV6MASK
*
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
*
* NLBL_MGMT_A_CV4DOI
...
...
@@ -68,13 +78,24 @@
* Required attributes:
*
* NLBL_MGMT_A_DOMAIN
*
* If the IP address selectors are not used the following attribute is
* required:
*
* NLBL_MGMT_A_PROTOCOL
*
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
* If the IP address selectors are used then the following attritbute is
* required:
*
* NLBL_MGMT_A_SELECTORLIST
*
* If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
* attributes are required:
*
* NLBL_MGMT_A_CV4DOI
*
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
* If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
* attributes are required.
*
* o ADDDEF:
* Sent by an application to set the default domain mapping for the NetLabel
...
...
@@ -100,15 +121,23 @@
* application there is no payload. On success the kernel should send a
* response using the following format.
*
* Required attributes:
* If the IP address selectors are not used the following attribute is
* required:
*
* NLBL_MGMT_A_PROTOCOL
*
* If using NETLBL_NLTYPE_CIPSOV4 the following attributes are required:
* If the IP address selectors are used then the following attritbute is
* required:
*
* NLBL_MGMT_A_SELECTORLIST
*
* If the mapping is using the NETLBL_NLTYPE_CIPSOV4 type then the following
* attributes are required:
*
* NLBL_MGMT_A_CV4DOI
*
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
* If the mapping is using the NETLBL_NLTYPE_UNLABELED type no other
* attributes are required.
*
* o PROTOCOLS:
* Sent by an application to request a list of configured NetLabel protocols
...
...
@@ -162,6 +191,26 @@ enum {
NLBL_MGMT_A_CV4DOI
,
/* (NLA_U32)
* the CIPSOv4 DOI value */
NLBL_MGMT_A_IPV6ADDR
,
/* (NLA_BINARY, struct in6_addr)
* an IPv6 address */
NLBL_MGMT_A_IPV6MASK
,
/* (NLA_BINARY, struct in6_addr)
* an IPv6 address mask */
NLBL_MGMT_A_IPV4ADDR
,
/* (NLA_BINARY, struct in_addr)
* an IPv4 address */
NLBL_MGMT_A_IPV4MASK
,
/* (NLA_BINARY, struct in_addr)
* and IPv4 address mask */
NLBL_MGMT_A_ADDRSELECTOR
,
/* (NLA_NESTED)
* an IP address selector, must contain an address, mask, and protocol
* attribute plus any protocol specific attributes */
NLBL_MGMT_A_SELECTORLIST
,
/* (NLA_NESTED)
* the selector list, there must be at least one
* NLBL_MGMT_A_ADDRSELECTOR attribute */
__NLBL_MGMT_A_MAX
,
};
#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
...
...
net/netlabel/netlabel_unlabeled.c
View file @
0da939b0
...
...
@@ -10,7 +10,7 @@
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 200
7
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - 200
8
*
* 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
...
...
@@ -54,6 +54,7 @@
#include <asm/atomic.h>
#include "netlabel_user.h"
#include "netlabel_addrlist.h"
#include "netlabel_domainhash.h"
#include "netlabel_unlabeled.h"
#include "netlabel_mgmt.h"
...
...
@@ -76,22 +77,20 @@ struct netlbl_unlhsh_tbl {
struct
list_head
*
tbl
;
u32
size
;
};
#define netlbl_unlhsh_addr4_entry(iter) \
container_of(iter, struct netlbl_unlhsh_addr4, list)
struct
netlbl_unlhsh_addr4
{
__be32
addr
;
__be32
mask
;
u32
secid
;
u32
valid
;
struct
list_head
list
;
struct
netlbl_af4list
list
;
struct
rcu_head
rcu
;
};
#define netlbl_unlhsh_addr6_entry(iter) \
container_of(iter, struct netlbl_unlhsh_addr6, list)
struct
netlbl_unlhsh_addr6
{
struct
in6_addr
addr
;
struct
in6_addr
mask
;
u32
secid
;
u32
valid
;
struct
list_head
list
;
struct
netlbl_af6list
list
;
struct
rcu_head
rcu
;
};
struct
netlbl_unlhsh_iface
{
...
...
@@ -146,76 +145,6 @@ static const struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1
[
NLBL_UNLABEL_A_SECCTX
]
=
{
.
type
=
NLA_BINARY
}
};
/*
* Audit Helper Functions
*/
/**
* netlbl_unlabel_audit_addr4 - Audit an IPv4 address
* @audit_buf: audit buffer
* @dev: network interface
* @addr: IP address
* @mask: IP address mask
*
* Description:
* Write the IPv4 address and address mask, if necessary, to @audit_buf.
*
*/
static
void
netlbl_unlabel_audit_addr4
(
struct
audit_buffer
*
audit_buf
,
const
char
*
dev
,
__be32
addr
,
__be32
mask
)
{
u32
mask_val
=
ntohl
(
mask
);
if
(
dev
!=
NULL
)
audit_log_format
(
audit_buf
,
" netif=%s"
,
dev
);
audit_log_format
(
audit_buf
,
" src="
NIPQUAD_FMT
,
NIPQUAD
(
addr
));
if
(
mask_val
!=
0xffffffff
)
{
u32
mask_len
=
0
;
while
(
mask_val
>
0
)
{
mask_val
<<=
1
;
mask_len
++
;
}
audit_log_format
(
audit_buf
,
" src_prefixlen=%d"
,
mask_len
);
}
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
* netlbl_unlabel_audit_addr6 - Audit an IPv6 address
* @audit_buf: audit buffer
* @dev: network interface
* @addr: IP address
* @mask: IP address mask
*
* Description:
* Write the IPv6 address and address mask, if necessary, to @audit_buf.
*
*/
static
void
netlbl_unlabel_audit_addr6
(
struct
audit_buffer
*
audit_buf
,
const
char
*
dev
,
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
)
{
if
(
dev
!=
NULL
)
audit_log_format
(
audit_buf
,
" netif=%s"
,
dev
);
audit_log_format
(
audit_buf
,
" src="
NIP6_FMT
,
NIP6
(
*
addr
));
if
(
ntohl
(
mask
->
s6_addr32
[
3
])
!=
0xffffffff
)
{
u32
mask_len
=
0
;
u32
mask_val
;
int
iter
=
-
1
;
while
(
ntohl
(
mask
->
s6_addr32
[
++
iter
])
==
0xffffffff
)
mask_len
+=
32
;
mask_val
=
ntohl
(
mask
->
s6_addr32
[
iter
]);
while
(
mask_val
>
0
)
{
mask_val
<<=
1
;
mask_len
++
;
}
audit_log_format
(
audit_buf
,
" src_prefixlen=%d"
,
mask_len
);
}
}
#endif
/* IPv6 */
/*
* Unlabeled Connection Hash Table Functions
*/
...
...
@@ -274,26 +203,28 @@ static void netlbl_unlhsh_free_addr6(struct rcu_head *entry)
static
void
netlbl_unlhsh_free_iface
(
struct
rcu_head
*
entry
)
{
struct
netlbl_unlhsh_iface
*
iface
;
struct
netlbl_unlhsh_addr4
*
iter4
;
struct
netlbl_unlhsh_addr4
*
tmp4
;
struct
netlbl_unlhsh_addr6
*
iter6
;
struct
netlbl_unlhsh_addr6
*
tmp6
;
struct
netlbl_af4list
*
iter4
;
struct
netlbl_af4list
*
tmp4
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct
netlbl_af6list
*
iter6
;
struct
netlbl_af6list
*
tmp6
;
#endif
/* IPv6 */
iface
=
container_of
(
entry
,
struct
netlbl_unlhsh_iface
,
rcu
);
/* no need for locks here since we are the only one with access to this
* structure */
list_for_each_entry_safe
(
iter4
,
tmp4
,
&
iface
->
addr4_list
,
list
)
if
(
iter4
->
valid
)
{
list_del_rcu
(
&
iter4
->
list
);
kfree
(
iter4
);
netlbl_af4list_foreach_safe
(
iter4
,
tmp4
,
&
iface
->
addr4_list
)
{
netlbl_af4list_remove_entry
(
iter4
);
kfree
(
netlbl_unlhsh_addr4_entry
(
iter4
));
}
list_for_each_entry_safe
(
iter6
,
tmp6
,
&
iface
->
addr6_list
,
list
)
if
(
iter6
->
valid
)
{
list_del_rcu
(
&
iter6
->
list
);
kfree
(
iter6
);
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE
)
netlbl_af6list_foreach_safe
(
iter6
,
tmp6
,
&
iface
->
addr6_list
)
{
netlbl_af6list_remove_entry
(
iter6
);
kfree
(
netlbl_unlhsh_addr6_entry
(
iter6
)
);
}
#endif
/* IPv6 */
kfree
(
iface
);
}
...
...
@@ -315,59 +246,6 @@ static u32 netlbl_unlhsh_hash(int ifindex)
return
ifindex
&
(
rcu_dereference
(
netlbl_unlhsh
)
->
size
-
1
);
}
/**
* netlbl_unlhsh_search_addr4 - Search for a matching IPv4 address entry
* @addr: IPv4 address
* @iface: the network interface entry
*
* Description:
* Searches the IPv4 address list of the network interface specified by @iface.
* If a matching address entry is found it is returned, otherwise NULL is
* returned. The caller is responsible for calling the rcu_read_[un]lock()
* functions.
*
*/
static
struct
netlbl_unlhsh_addr4
*
netlbl_unlhsh_search_addr4
(
__be32
addr
,
const
struct
netlbl_unlhsh_iface
*
iface
)
{
struct
netlbl_unlhsh_addr4
*
iter
;
list_for_each_entry_rcu
(
iter
,
&
iface
->
addr4_list
,
list
)
if
(
iter
->
valid
&&
(
addr
&
iter
->
mask
)
==
iter
->
addr
)
return
iter
;
return
NULL
;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
/**
* netlbl_unlhsh_search_addr6 - Search for a matching IPv6 address entry
* @addr: IPv6 address
* @iface: the network interface entry
*
* Description:
* Searches the IPv6 address list of the network interface specified by @iface.
* If a matching address entry is found it is returned, otherwise NULL is
* returned. The caller is responsible for calling the rcu_read_[un]lock()
* functions.
*
*/
static
struct
netlbl_unlhsh_addr6
*
netlbl_unlhsh_search_addr6
(
const
struct
in6_addr
*
addr
,
const
struct
netlbl_unlhsh_iface
*
iface
)
{
struct
netlbl_unlhsh_addr6
*
iter
;
list_for_each_entry_rcu
(
iter
,
&
iface
->
addr6_list
,
list
)
if
(
iter
->
valid
&&
ipv6_masked_addr_cmp
(
&
iter
->
addr
,
&
iter
->
mask
,
addr
)
==
0
)
return
iter
;
return
NULL
;
}
#endif
/* IPv6 */
/**
* netlbl_unlhsh_search_iface - Search for a matching interface entry
* @ifindex: the network interface
...
...
@@ -381,12 +259,12 @@ static struct netlbl_unlhsh_addr6 *netlbl_unlhsh_search_addr6(
static
struct
netlbl_unlhsh_iface
*
netlbl_unlhsh_search_iface
(
int
ifindex
)
{
u32
bkt
;
struct
list_head
*
bkt_list
;
struct
netlbl_unlhsh_iface
*
iter
;
bkt
=
netlbl_unlhsh_hash
(
ifindex
);
list_for_each_entry_rcu
(
iter
,
&
rcu_dereference
(
netlbl_unlhsh
)
->
tbl
[
bkt
],
list
)
bkt_list
=
&
rcu_dereference
(
netlbl_unlhsh
)
->
tbl
[
bkt
];
list_for_each_entry_rcu
(
iter
,
bkt_list
,
list
)
if
(
iter
->
valid
&&
iter
->
ifindex
==
ifindex
)
return
iter
;
...
...
@@ -439,43 +317,26 @@ static int netlbl_unlhsh_add_addr4(struct netlbl_unlhsh_iface *iface,
const
struct
in_addr
*
mask
,
u32
secid
)
{
int
ret_val
;
struct
netlbl_unlhsh_addr4
*
entry
;
struct
netlbl_unlhsh_addr4
*
iter
;
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_ATOMIC
);
if
(
entry
==
NULL
)
return
-
ENOMEM
;
entry
->
addr
=
addr
->
s_addr
&
mask
->
s_addr
;
entry
->
mask
=
mask
->
s_addr
;
entry
->
secid
=
secid
;
entry
->
valid
=
1
;
entry
->
list
.
addr
=
addr
->
s_addr
&
mask
->
s_addr
;
entry
->
list
.
mask
=
mask
->
s_addr
;
entry
->
list
.
valid
=
1
;
INIT_RCU_HEAD
(
&
entry
->
rcu
);
entry
->
secid
=
secid
;
spin_lock
(
&
netlbl_unlhsh_lock
);
iter
=
netlbl_unlhsh_search_addr4
(
entry
->
addr
,
iface
);
if
(
iter
!=
NULL
&&
iter
->
addr
==
addr
->
s_addr
&&
iter
->
mask
==
mask
->
s_addr
)
{
ret_val
=
netlbl_af4list_add
(
&
entry
->
list
,
&
iface
->
addr4_list
);
spin_unlock
(
&
netlbl_unlhsh_lock
);
if
(
ret_val
!=
0
)
kfree
(
entry
);
return
-
EEXIST
;
}
/* in order to speed up address searches through the list (the common
* case) we need to keep the list in order based on the size of the
* address mask such that the entry with the widest mask (smallest
* numerical value) appears first in the list */
list_for_each_entry_rcu
(
iter
,
&
iface
->
addr4_list
,
list
)
if
(
iter
->
valid
&&
ntohl
(
entry
->
mask
)
>
ntohl
(
iter
->
mask
))
{
__list_add_rcu
(
&
entry
->
list
,
iter
->
list
.
prev
,
&
iter
->
list
);
spin_unlock
(
&
netlbl_unlhsh_lock
);
return
0
;
}
list_add_tail_rcu
(
&
entry
->
list
,
&
iface
->
addr4_list
);
spin_unlock
(
&
netlbl_unlhsh_lock
);
return
0
;
return
ret_val
;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
...
...
@@ -498,47 +359,29 @@ static int netlbl_unlhsh_add_addr6(struct netlbl_unlhsh_iface *iface,
const
struct
in6_addr
*
mask
,
u32
secid
)
{
int
ret_val
;
struct
netlbl_unlhsh_addr6
*
entry
;
struct
netlbl_unlhsh_addr6
*
iter
;
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_ATOMIC
);
if
(
entry
==
NULL
)
return
-
ENOMEM
;
ipv6_addr_copy
(
&
entry
->
addr
,
addr
);
entry
->
addr
.
s6_addr32
[
0
]
&=
mask
->
s6_addr32
[
0
];
entry
->
addr
.
s6_addr32
[
1
]
&=
mask
->
s6_addr32
[
1
];
entry
->
addr
.
s6_addr32
[
2
]
&=
mask
->
s6_addr32
[
2
];
entry
->
addr
.
s6_addr32
[
3
]
&=
mask
->
s6_addr32
[
3
];
ipv6_addr_copy
(
&
entry
->
mask
,
mask
);
entry
->
secid
=
secid
;
entry
->
valid
=
1
;
ipv6_addr_copy
(
&
entry
->
list
.
addr
,
addr
);
entry
->
list
.
addr
.
s6_addr32
[
0
]
&=
mask
->
s6_addr32
[
0
];
entry
->
list
.
addr
.
s6_addr32
[
1
]
&=
mask
->
s6_addr32
[
1
];
entry
->
list
.
addr
.
s6_addr32
[
2
]
&=
mask
->
s6_addr32
[
2
];
entry
->
list
.
addr
.
s6_addr32
[
3
]
&=
mask
->
s6_addr32
[
3
];
ipv6_addr_copy
(
&
entry
->
list
.
mask
,
mask
);
entry
->
list
.
valid
=
1
;
INIT_RCU_HEAD
(
&
entry
->
rcu
);
entry
->
secid
=
secid
;
spin_lock
(
&
netlbl_unlhsh_lock
);
iter
=
netlbl_unlhsh_search_addr6
(
&
entry
->
addr
,
iface
);
if
(
iter
!=
NULL
&&
(
ipv6_addr_equal
(
&
iter
->
addr
,
addr
)
&&
ipv6_addr_equal
(
&
iter
->
mask
,
mask
)))
{
ret_val
=
netlbl_af6list_add
(
&
entry
->
list
,
&
iface
->
addr6_list
);
spin_unlock
(
&
netlbl_unlhsh_lock
);
if
(
ret_val
!=
0
)
kfree
(
entry
);
return
-
EEXIST
;
}
/* in order to speed up address searches through the list (the common
* case) we need to keep the list in order based on the size of the
* address mask such that the entry with the widest mask (smallest
* numerical value) appears first in the list */
list_for_each_entry_rcu
(
iter
,
&
iface
->
addr6_list
,
list
)
if
(
iter
->
valid
&&
ipv6_addr_cmp
(
&
entry
->
mask
,
&
iter
->
mask
)
>
0
)
{
__list_add_rcu
(
&
entry
->
list
,
iter
->
list
.
prev
,
&
iter
->
list
);
spin_unlock
(
&
netlbl_unlhsh_lock
);
return
0
;
}
list_add_tail_rcu
(
&
entry
->
list
,
&
iface
->
addr6_list
);
spin_unlock
(
&
netlbl_unlhsh_lock
);
return
0
;
}
#endif
/* IPv6 */
...
...
@@ -658,7 +501,7 @@ static int netlbl_unlhsh_add(struct net *net,
mask4
=
(
struct
in_addr
*
)
mask
;
ret_val
=
netlbl_unlhsh_add_addr4
(
iface
,
addr4
,
mask4
,
secid
);
if
(
audit_buf
!=
NULL
)
netlbl_
unlabel_audit_addr4
(
audit_buf
,
netlbl_
af4list_audit_addr
(
audit_buf
,
1
,
dev_name
,
addr4
->
s_addr
,
mask4
->
s_addr
);
...
...
@@ -672,7 +515,7 @@ static int netlbl_unlhsh_add(struct net *net,
mask6
=
(
struct
in6_addr
*
)
mask
;
ret_val
=
netlbl_unlhsh_add_addr6
(
iface
,
addr6
,
mask6
,
secid
);
if
(
audit_buf
!=
NULL
)
netlbl_
unlabel_audit_addr6
(
audit_buf
,
netlbl_
af6list_audit_addr
(
audit_buf
,
1
,
dev_name
,
addr6
,
mask6
);
break
;
...
...
@@ -719,33 +562,32 @@ static int netlbl_unlhsh_remove_addr4(struct net *net,
const
struct
in_addr
*
mask
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
=
-
ENOENT
;
int
ret_val
=
0
;
struct
netlbl_af4list
*
list_entry
;
struct
netlbl_unlhsh_addr4
*
entry
;
struct
audit_buffer
*
audit_buf
=
NULL
;
struct
audit_buffer
*
audit_buf
;
struct
net_device
*
dev
;
char
*
secctx
=
NULL
;
char
*
secctx
;
u32
secctx_len
;
spin_lock
(
&
netlbl_unlhsh_lock
);
entry
=
netlbl_unlhsh_search_addr4
(
addr
->
s_addr
,
iface
);
if
(
entry
!=
NULL
&&
entry
->
addr
==
addr
->
s_addr
&&
entry
->
mask
==
mask
->
s_addr
)
{
entry
->
valid
=
0
;
list_del_rcu
(
&
entry
->
list
);
ret_val
=
0
;
}
list_entry
=
netlbl_af4list_remove
(
addr
->
s_addr
,
mask
->
s_addr
,
&
iface
->
addr4_list
);
spin_unlock
(
&
netlbl_unlhsh_lock
);
if
(
list_entry
==
NULL
)
ret_val
=
-
ENOENT
;
entry
=
netlbl_unlhsh_addr4_entry
(
list_entry
);
audit_buf
=
netlbl_audit_start_common
(
AUDIT_MAC_UNLBL_STCDEL
,
audit_info
);
if
(
audit_buf
!=
NULL
)
{
dev
=
dev_get_by_index
(
net
,
iface
->
ifindex
);
netlbl_
unlabel_audit_addr4
(
audit_buf
,
netlbl_
af4list_audit_addr
(
audit_buf
,
1
,
(
dev
!=
NULL
?
dev
->
name
:
NULL
),
entry
->
addr
,
entry
->
mask
);
addr
->
s_addr
,
mask
->
s_addr
);
if
(
dev
!=
NULL
)
dev_put
(
dev
);
if
(
security_secid_to_secctx
(
entry
->
secid
,
if
(
entry
&&
security_secid_to_secctx
(
entry
->
secid
,
&
secctx
,
&
secctx_len
)
==
0
)
{
audit_log_format
(
audit_buf
,
" sec_obj=%s"
,
secctx
);
...
...
@@ -781,34 +623,31 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
const
struct
in6_addr
*
mask
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
=
-
ENOENT
;
int
ret_val
=
0
;
struct
netlbl_af6list
*
list_entry
;
struct
netlbl_unlhsh_addr6
*
entry
;
struct
audit_buffer
*
audit_buf
=
NULL
;
struct
audit_buffer
*
audit_buf
;
struct
net_device
*
dev
;
char
*
secctx
=
NULL
;
char
*
secctx
;
u32
secctx_len
;
spin_lock
(
&
netlbl_unlhsh_lock
);
entry
=
netlbl_unlhsh_search_addr6
(
addr
,
iface
);
if
(
entry
!=
NULL
&&
(
ipv6_addr_equal
(
&
entry
->
addr
,
addr
)
&&
ipv6_addr_equal
(
&
entry
->
mask
,
mask
)))
{
entry
->
valid
=
0
;
list_del_rcu
(
&
entry
->
list
);
ret_val
=
0
;
}
list_entry
=
netlbl_af6list_remove
(
addr
,
mask
,
&
iface
->
addr6_list
);
spin_unlock
(
&
netlbl_unlhsh_lock
);
if
(
list_entry
==
NULL
)
ret_val
=
-
ENOENT
;
entry
=
netlbl_unlhsh_addr6_entry
(
list_entry
);
audit_buf
=
netlbl_audit_start_common
(
AUDIT_MAC_UNLBL_STCDEL
,
audit_info
);
if
(
audit_buf
!=
NULL
)
{
dev
=
dev_get_by_index
(
net
,
iface
->
ifindex
);
netlbl_
unlabel_audit_addr6
(
audit_buf
,
netlbl_
af6list_audit_addr
(
audit_buf
,
1
,
(
dev
!=
NULL
?
dev
->
name
:
NULL
),
addr
,
mask
);
if
(
dev
!=
NULL
)
dev_put
(
dev
);
if
(
security_secid_to_secctx
(
entry
->
secid
,
if
(
entry
&&
security_secid_to_secctx
(
entry
->
secid
,
&
secctx
,
&
secctx_len
)
==
0
)
{
audit_log_format
(
audit_buf
,
" sec_obj=%s"
,
secctx
);
...
...
@@ -836,16 +675,18 @@ static int netlbl_unlhsh_remove_addr6(struct net *net,
*/
static
void
netlbl_unlhsh_condremove_iface
(
struct
netlbl_unlhsh_iface
*
iface
)
{
struct
netlbl_unlhsh_addr4
*
iter4
;
struct
netlbl_unlhsh_addr6
*
iter6
;
struct
netlbl_af4list
*
iter4
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct
netlbl_af6list
*
iter6
;
#endif
/* IPv6 */
spin_lock
(
&
netlbl_unlhsh_lock
);
list_for_each_entry_rcu
(
iter4
,
&
iface
->
addr4_list
,
list
)
if
(
iter4
->
valid
)
netlbl_af4list_foreach_rcu
(
iter4
,
&
iface
->
addr4_list
)
goto
unlhsh_condremove_failure
;
list_for_each_entry_rcu
(
iter6
,
&
iface
->
addr6_list
,
list
)
if
(
iter6
->
valid
)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE
)
netlbl_af6list_foreach_rcu
(
iter6
,
&
iface
->
addr6_list
)
goto
unlhsh_condremove_failure
;
#endif
/* IPv6 */
iface
->
valid
=
0
;
if
(
iface
->
ifindex
>
0
)
list_del_rcu
(
&
iface
->
list
);
...
...
@@ -1349,7 +1190,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
if
(
addr4
)
{
struct
in_addr
addr_struct
;
addr_struct
.
s_addr
=
addr4
->
addr
;
addr_struct
.
s_addr
=
addr4
->
list
.
addr
;
ret_val
=
nla_put
(
cb_arg
->
skb
,
NLBL_UNLABEL_A_IPV4ADDR
,
sizeof
(
struct
in_addr
),
...
...
@@ -1357,7 +1198,7 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
if
(
ret_val
!=
0
)
goto
list_cb_failure
;
addr_struct
.
s_addr
=
addr4
->
mask
;
addr_struct
.
s_addr
=
addr4
->
list
.
mask
;
ret_val
=
nla_put
(
cb_arg
->
skb
,
NLBL_UNLABEL_A_IPV4MASK
,
sizeof
(
struct
in_addr
),
...
...
@@ -1370,14 +1211,14 @@ static int netlbl_unlabel_staticlist_gen(u32 cmd,
ret_val
=
nla_put
(
cb_arg
->
skb
,
NLBL_UNLABEL_A_IPV6ADDR
,
sizeof
(
struct
in6_addr
),
&
addr6
->
addr
);
&
addr6
->
list
.
addr
);
if
(
ret_val
!=
0
)
goto
list_cb_failure
;
ret_val
=
nla_put
(
cb_arg
->
skb
,
NLBL_UNLABEL_A_IPV6MASK
,
sizeof
(
struct
in6_addr
),
&
addr6
->
mask
);
&
addr6
->
list
.
mask
);
if
(
ret_val
!=
0
)
goto
list_cb_failure
;
...
...
@@ -1425,8 +1266,11 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
u32
iter_bkt
;
u32
iter_chain
=
0
,
iter_addr4
=
0
,
iter_addr6
=
0
;
struct
netlbl_unlhsh_iface
*
iface
;
struct
netlbl_unlhsh_addr4
*
addr4
;
struct
netlbl_unlhsh_addr6
*
addr6
;
struct
list_head
*
iter_list
;
struct
netlbl_af4list
*
addr4
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
struct
netlbl_af6list
*
addr6
;
#endif
cb_arg
.
nl_cb
=
cb
;
cb_arg
.
skb
=
skb
;
...
...
@@ -1436,21 +1280,19 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
for
(
iter_bkt
=
skip_bkt
;
iter_bkt
<
rcu_dereference
(
netlbl_unlhsh
)
->
size
;
iter_bkt
++
,
iter_chain
=
0
,
iter_addr4
=
0
,
iter_addr6
=
0
)
{
list_for_each_entry_rcu
(
iface
,
&
rcu_dereference
(
netlbl_unlhsh
)
->
tbl
[
iter_bkt
],
list
)
{
iter_list
=
&
rcu_dereference
(
netlbl_unlhsh
)
->
tbl
[
iter_bkt
];
list_for_each_entry_rcu
(
iface
,
iter_list
,
list
)
{
if
(
!
iface
->
valid
||
iter_chain
++
<
skip_chain
)
continue
;
list_for_each_entry_rcu
(
addr4
,
&
iface
->
addr4_list
,
list
)
{
if
(
!
addr4
->
valid
||
iter_addr4
++
<
skip_addr4
)
netlbl_af4list_foreach_rcu
(
addr4
,
&
iface
->
addr4_list
)
{
if
(
iter_addr4
++
<
skip_addr4
)
continue
;
if
(
netlbl_unlabel_staticlist_gen
(
NLBL_UNLABEL_C_STATICLIST
,
iface
,
addr4
,
netlbl_unlhsh_addr4_entry
(
addr4
)
,
NULL
,
&
cb_arg
)
<
0
)
{
iter_addr4
--
;
...
...
@@ -1458,22 +1300,23 @@ static int netlbl_unlabel_staticlist(struct sk_buff *skb,
goto
unlabel_staticlist_return
;
}
}
list_for_each_entry_rcu
(
addr6
,
&
iface
->
addr6_list
,
list
)
{
if
(
!
addr6
->
valid
||
iter_addr6
++
<
skip_addr6
)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
netlbl_af6list_foreach_rcu
(
addr6
,
&
iface
->
addr6_
list
)
{
if
(
iter_addr6
++
<
skip_addr6
)
continue
;
if
(
netlbl_unlabel_staticlist_gen
(
NLBL_UNLABEL_C_STATICLIST
,
iface
,
NULL
,
addr6
,
netlbl_unlhsh_addr6_entry
(
addr6
)
,
&
cb_arg
)
<
0
)
{
iter_addr6
--
;
iter_chain
--
;
goto
unlabel_staticlist_return
;
}
}
#endif
/* IPv6 */
}
}
...
...
@@ -1504,9 +1347,12 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
struct
netlbl_unlhsh_iface
*
iface
;
u32
skip_addr4
=
cb
->
args
[
0
];
u32
skip_addr6
=
cb
->
args
[
1
];
u32
iter_addr4
=
0
,
iter_addr6
=
0
;
struct
netlbl_unlhsh_addr4
*
addr4
;
struct
netlbl_unlhsh_addr6
*
addr6
;
u32
iter_addr4
=
0
;
struct
netlbl_af4list
*
addr4
;
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
u32
iter_addr6
=
0
;
struct
netlbl_af6list
*
addr6
;
#endif
cb_arg
.
nl_cb
=
cb
;
cb_arg
.
skb
=
skb
;
...
...
@@ -1517,30 +1363,32 @@ static int netlbl_unlabel_staticlistdef(struct sk_buff *skb,
if
(
iface
==
NULL
||
!
iface
->
valid
)
goto
unlabel_staticlistdef_return
;
list_for_each_entry_rcu
(
addr4
,
&
iface
->
addr4_list
,
list
)
{
if
(
!
addr4
->
valid
||
iter_addr4
++
<
skip_addr4
)
netlbl_af4list_foreach_rcu
(
addr4
,
&
iface
->
addr4_
list
)
{
if
(
iter_addr4
++
<
skip_addr4
)
continue
;
if
(
netlbl_unlabel_staticlist_gen
(
NLBL_UNLABEL_C_STATICLISTDEF
,
iface
,
addr4
,
netlbl_unlhsh_addr4_entry
(
addr4
)
,
NULL
,
&
cb_arg
)
<
0
)
{
iter_addr4
--
;
goto
unlabel_staticlistdef_return
;
}
}
list_for_each_entry_rcu
(
addr6
,
&
iface
->
addr6_list
,
list
)
{
if
(
!
addr6
->
valid
||
iter_addr6
++
<
skip_addr6
)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
netlbl_af6list_foreach_rcu
(
addr6
,
&
iface
->
addr6_list
)
{
if
(
iter_addr6
++
<
skip_addr6
)
continue
;
if
(
netlbl_unlabel_staticlist_gen
(
NLBL_UNLABEL_C_STATICLISTDEF
,
iface
,
NULL
,
addr6
,
netlbl_unlhsh_addr6_entry
(
addr6
)
,
&
cb_arg
)
<
0
)
{
iter_addr6
--
;
goto
unlabel_staticlistdef_return
;
}
}
#endif
/* IPv6 */
unlabel_staticlistdef_return:
rcu_read_unlock
();
...
...
@@ -1718,25 +1566,27 @@ int netlbl_unlabel_getattr(const struct sk_buff *skb,
switch
(
family
)
{
case
PF_INET
:
{
struct
iphdr
*
hdr4
;
struct
netlbl_
unlhsh_addr4
*
addr4
;
struct
netlbl_
af4list
*
addr4
;
hdr4
=
ip_hdr
(
skb
);
addr4
=
netlbl_unlhsh_search_addr4
(
hdr4
->
saddr
,
iface
);
addr4
=
netlbl_af4list_search
(
hdr4
->
saddr
,
&
iface
->
addr4_list
);
if
(
addr4
==
NULL
)
goto
unlabel_getattr_nolabel
;
secattr
->
attr
.
secid
=
addr4
->
secid
;
secattr
->
attr
.
secid
=
netlbl_unlhsh_addr4_entry
(
addr4
)
->
secid
;
break
;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
case
PF_INET6
:
{
struct
ipv6hdr
*
hdr6
;
struct
netlbl_
unlhsh_addr6
*
addr6
;
struct
netlbl_
af6list
*
addr6
;
hdr6
=
ipv6_hdr
(
skb
);
addr6
=
netlbl_unlhsh_search_addr6
(
&
hdr6
->
saddr
,
iface
);
addr6
=
netlbl_af6list_search
(
&
hdr6
->
saddr
,
&
iface
->
addr6_list
);
if
(
addr6
==
NULL
)
goto
unlabel_getattr_nolabel
;
secattr
->
attr
.
secid
=
addr6
->
secid
;
secattr
->
attr
.
secid
=
netlbl_unlhsh_addr6_entry
(
addr6
)
->
secid
;
break
;
}
#endif
/* IPv6 */
...
...
security/selinux/hooks.c
View file @
0da939b0
...
...
@@ -291,6 +291,7 @@ static void sk_free_security(struct sock *sk)
struct
sk_security_struct
*
ssec
=
sk
->
sk_security
;
sk
->
sk_security
=
NULL
;
selinux_netlbl_sk_security_free
(
ssec
);
kfree
(
ssec
);
}
...
...
@@ -3801,6 +3802,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in
static
int
selinux_socket_connect
(
struct
socket
*
sock
,
struct
sockaddr
*
address
,
int
addrlen
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
inode_security_struct
*
isec
;
int
err
;
...
...
@@ -3814,7 +3816,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
isec
=
SOCK_INODE
(
sock
)
->
i_security
;
if
(
isec
->
sclass
==
SECCLASS_TCP_SOCKET
||
isec
->
sclass
==
SECCLASS_DCCP_SOCKET
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
avc_audit_data
ad
;
struct
sockaddr_in
*
addr4
=
NULL
;
struct
sockaddr_in6
*
addr6
=
NULL
;
...
...
@@ -3848,6 +3849,8 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address,
goto
out
;
}
err
=
selinux_netlbl_socket_connect
(
sk
,
address
);
out:
return
err
;
}
...
...
@@ -4077,20 +4080,28 @@ static int selinux_sock_rcv_skb_iptables_compat(struct sock *sk,
}
static
int
selinux_sock_rcv_skb_compat
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
,
struct
avc_audit_data
*
ad
,
u16
family
,
char
*
addrp
)
u16
family
)
{
int
err
;
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
u32
peer_sid
;
u32
sk_sid
=
sksec
->
sid
;
struct
avc_audit_data
ad
;
char
*
addrp
;
AVC_AUDIT_DATA_INIT
(
&
ad
,
NET
);
ad
.
u
.
net
.
netif
=
skb
->
iif
;
ad
.
u
.
net
.
family
=
family
;
err
=
selinux_parse_skb
(
skb
,
&
ad
,
&
addrp
,
1
,
NULL
);
if
(
err
)
return
err
;
if
(
selinux_compat_net
)
err
=
selinux_sock_rcv_skb_iptables_compat
(
sk
,
skb
,
ad
,
err
=
selinux_sock_rcv_skb_iptables_compat
(
sk
,
skb
,
&
ad
,
family
,
addrp
);
else
err
=
avc_has_perm
(
sk_sid
,
skb
->
secmark
,
SECCLASS_PACKET
,
PACKET__RECV
,
ad
);
PACKET__RECV
,
&
ad
);
if
(
err
)
return
err
;
...
...
@@ -4099,12 +4110,14 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb,
if
(
err
)
return
err
;
err
=
avc_has_perm
(
sk_sid
,
peer_sid
,
SECCLASS_PEER
,
PEER__RECV
,
ad
);
SECCLASS_PEER
,
PEER__RECV
,
&
ad
);
if
(
err
)
selinux_netlbl_err
(
skb
,
err
,
0
);
}
else
{
err
=
selinux_netlbl_sock_rcv_skb
(
sksec
,
skb
,
family
,
ad
);
err
=
selinux_netlbl_sock_rcv_skb
(
sksec
,
skb
,
family
,
&
ad
);
if
(
err
)
return
err
;
err
=
selinux_xfrm_sock_rcv_skb
(
sksec
->
sid
,
skb
,
ad
);
err
=
selinux_xfrm_sock_rcv_skb
(
sksec
->
sid
,
skb
,
&
ad
);
}
return
err
;
...
...
@@ -4118,6 +4131,8 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
u32
sk_sid
=
sksec
->
sid
;
struct
avc_audit_data
ad
;
char
*
addrp
;
u8
secmark_active
;
u8
peerlbl_active
;
if
(
family
!=
PF_INET
&&
family
!=
PF_INET6
)
return
0
;
...
...
@@ -4126,6 +4141,18 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
if
(
family
==
PF_INET6
&&
skb
->
protocol
==
htons
(
ETH_P_IP
))
family
=
PF_INET
;
/* If any sort of compatibility mode is enabled then handoff processing
* to the selinux_sock_rcv_skb_compat() function to deal with the
* special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */
if
(
selinux_compat_net
||
!
selinux_policycap_netpeer
)
return
selinux_sock_rcv_skb_compat
(
sk
,
skb
,
family
);
secmark_active
=
selinux_secmark_enabled
();
peerlbl_active
=
netlbl_enabled
()
||
selinux_xfrm_enabled
();
if
(
!
secmark_active
&&
!
peerlbl_active
)
return
0
;
AVC_AUDIT_DATA_INIT
(
&
ad
,
NET
);
ad
.
u
.
net
.
netif
=
skb
->
iif
;
ad
.
u
.
net
.
family
=
family
;
...
...
@@ -4133,15 +4160,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
if
(
err
)
return
err
;
/* If any sort of compatibility mode is enabled then handoff processing
* to the selinux_sock_rcv_skb_compat() function to deal with the
* special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */
if
(
selinux_compat_net
||
!
selinux_policycap_netpeer
)
return
selinux_sock_rcv_skb_compat
(
sk
,
skb
,
&
ad
,
family
,
addrp
);
if
(
netlbl_enabled
()
||
selinux_xfrm_enabled
())
{
if
(
peerlbl_active
)
{
u32
peer_sid
;
err
=
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
peer_sid
);
...
...
@@ -4149,13 +4168,17 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
return
err
;
err
=
selinux_inet_sys_rcv_skb
(
skb
->
iif
,
addrp
,
family
,
peer_sid
,
&
ad
);
if
(
err
)
if
(
err
)
{
selinux_netlbl_err
(
skb
,
err
,
0
);
return
err
;
}
err
=
avc_has_perm
(
sk_sid
,
peer_sid
,
SECCLASS_PEER
,
PEER__RECV
,
&
ad
);
if
(
err
)
selinux_netlbl_err
(
skb
,
err
,
0
);
}
if
(
se
linux_secmark_enabled
()
)
{
if
(
se
cmark_active
)
{
err
=
avc_has_perm
(
sk_sid
,
skb
->
secmark
,
SECCLASS_PACKET
,
PACKET__RECV
,
&
ad
);
if
(
err
)
...
...
@@ -4214,10 +4237,12 @@ static int selinux_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *
u32
peer_secid
=
SECSID_NULL
;
u16
family
;
if
(
sock
)
if
(
skb
&&
skb
->
protocol
==
htons
(
ETH_P_IP
))
family
=
PF_INET
;
else
if
(
skb
&&
skb
->
protocol
==
htons
(
ETH_P_IPV6
))
family
=
PF_INET6
;
else
if
(
sock
)
family
=
sock
->
sk
->
sk_family
;
else
if
(
skb
&&
skb
->
sk
)
family
=
skb
->
sk
->
sk_family
;
else
goto
out
;
...
...
@@ -4275,8 +4300,6 @@ static void selinux_sock_graft(struct sock *sk, struct socket *parent)
sk
->
sk_family
==
PF_UNIX
)
isec
->
sid
=
sksec
->
sid
;
sksec
->
sclass
=
isec
->
sclass
;
selinux_netlbl_sock_graft
(
sk
,
parent
);
}
static
int
selinux_inet_conn_request
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
,
...
...
@@ -4284,10 +4307,15 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
{
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
int
err
;
u16
family
=
sk
->
sk_family
;
u32
newsid
;
u32
peersid
;
err
=
selinux_skb_peerlbl_sid
(
skb
,
sk
->
sk_family
,
&
peersid
);
/* handle mapped IPv4 packets arriving via IPv6 sockets */
if
(
family
==
PF_INET6
&&
skb
->
protocol
==
htons
(
ETH_P_IP
))
family
=
PF_INET
;
err
=
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
peersid
);
if
(
err
)
return
err
;
if
(
peersid
==
SECSID_NULL
)
{
...
...
@@ -4322,12 +4350,18 @@ static void selinux_inet_csk_clone(struct sock *newsk,
selinux_netlbl_sk_security_reset
(
newsksec
,
req
->
rsk_ops
->
family
);
}
static
void
selinux_inet_conn_established
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
static
void
selinux_inet_conn_established
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
u16
family
=
sk
->
sk_family
;
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
selinux_skb_peerlbl_sid
(
skb
,
sk
->
sk_family
,
&
sksec
->
peer_sid
);
/* handle mapped IPv4 packets arriving via IPv6 sockets */
if
(
family
==
PF_INET6
&&
skb
->
protocol
==
htons
(
ETH_P_IP
))
family
=
PF_INET
;
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
sksec
->
peer_sid
);
selinux_netlbl_inet_conn_established
(
sk
,
family
);
}
static
void
selinux_req_classify_flow
(
const
struct
request_sock
*
req
,
...
...
@@ -4377,39 +4411,54 @@ static int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
static
unsigned
int
selinux_ip_forward
(
struct
sk_buff
*
skb
,
int
ifindex
,
u16
family
)
{
int
err
;
char
*
addrp
;
u32
peer_sid
;
struct
avc_audit_data
ad
;
u8
secmark_active
;
u8
netlbl_active
;
u8
peerlbl_active
;
if
(
!
selinux_policycap_netpeer
)
return
NF_ACCEPT
;
secmark_active
=
selinux_secmark_enabled
();
peerlbl_active
=
netlbl_enabled
()
||
selinux_xfrm_enabled
();
netlbl_active
=
netlbl_enabled
();
peerlbl_active
=
netlbl_active
||
selinux_xfrm_enabled
();
if
(
!
secmark_active
&&
!
peerlbl_active
)
return
NF_ACCEPT
;
if
(
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
peer_sid
)
!=
0
)
return
NF_DROP
;
AVC_AUDIT_DATA_INIT
(
&
ad
,
NET
);
ad
.
u
.
net
.
netif
=
ifindex
;
ad
.
u
.
net
.
family
=
family
;
if
(
selinux_parse_skb
(
skb
,
&
ad
,
&
addrp
,
1
,
NULL
)
!=
0
)
return
NF_DROP
;
if
(
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
peer_sid
)
!=
0
)
return
NF_DROP
;
if
(
peerlbl_active
)
if
(
selinux_inet_sys_rcv_skb
(
ifindex
,
addrp
,
family
,
peer_sid
,
&
ad
)
!=
0
)
if
(
peerlbl_active
)
{
err
=
selinux_inet_sys_rcv_skb
(
ifindex
,
addrp
,
family
,
peer_sid
,
&
ad
);
if
(
err
)
{
selinux_netlbl_err
(
skb
,
err
,
1
);
return
NF_DROP
;
}
}
if
(
secmark_active
)
if
(
avc_has_perm
(
peer_sid
,
skb
->
secmark
,
SECCLASS_PACKET
,
PACKET__FORWARD_IN
,
&
ad
))
return
NF_DROP
;
if
(
netlbl_active
)
/* we do this in the FORWARD path and not the POST_ROUTING
* path because we want to make sure we apply the necessary
* labeling before IPsec is applied so we can leverage AH
* protection */
if
(
selinux_netlbl_skbuff_setsid
(
skb
,
family
,
peer_sid
)
!=
0
)
return
NF_DROP
;
return
NF_ACCEPT
;
}
...
...
@@ -4433,6 +4482,37 @@ static unsigned int selinux_ipv6_forward(unsigned int hooknum,
}
#endif
/* IPV6 */
static
unsigned
int
selinux_ip_output
(
struct
sk_buff
*
skb
,
u16
family
)
{
u32
sid
;
if
(
!
netlbl_enabled
())
return
NF_ACCEPT
;
/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
* because we want to make sure we apply the necessary labeling
* before IPsec is applied so we can leverage AH protection */
if
(
skb
->
sk
)
{
struct
sk_security_struct
*
sksec
=
skb
->
sk
->
sk_security
;
sid
=
sksec
->
sid
;
}
else
sid
=
SECINITSID_KERNEL
;
if
(
selinux_netlbl_skbuff_setsid
(
skb
,
family
,
sid
)
!=
0
)
return
NF_DROP
;
return
NF_ACCEPT
;
}
static
unsigned
int
selinux_ipv4_output
(
unsigned
int
hooknum
,
struct
sk_buff
*
skb
,
const
struct
net_device
*
in
,
const
struct
net_device
*
out
,
int
(
*
okfn
)(
struct
sk_buff
*
))
{
return
selinux_ip_output
(
skb
,
PF_INET
);
}
static
int
selinux_ip_postroute_iptables_compat
(
struct
sock
*
sk
,
int
ifindex
,
struct
avc_audit_data
*
ad
,
...
...
@@ -4500,30 +4580,36 @@ static int selinux_ip_postroute_iptables_compat(struct sock *sk,
static
unsigned
int
selinux_ip_postroute_compat
(
struct
sk_buff
*
skb
,
int
ifindex
,
struct
avc_audit_data
*
ad
,
u16
family
,
char
*
addrp
,
u8
proto
)
u16
family
)
{
struct
sock
*
sk
=
skb
->
sk
;
struct
sk_security_struct
*
sksec
;
struct
avc_audit_data
ad
;
char
*
addrp
;
u8
proto
;
if
(
sk
==
NULL
)
return
NF_ACCEPT
;
sksec
=
sk
->
sk_security
;
AVC_AUDIT_DATA_INIT
(
&
ad
,
NET
);
ad
.
u
.
net
.
netif
=
ifindex
;
ad
.
u
.
net
.
family
=
family
;
if
(
selinux_parse_skb
(
skb
,
&
ad
,
&
addrp
,
0
,
&
proto
))
return
NF_DROP
;
if
(
selinux_compat_net
)
{
if
(
selinux_ip_postroute_iptables_compat
(
skb
->
sk
,
ifindex
,
ad
,
family
,
addrp
))
&
ad
,
family
,
addrp
))
return
NF_DROP
;
}
else
{
if
(
avc_has_perm
(
sksec
->
sid
,
skb
->
secmark
,
SECCLASS_PACKET
,
PACKET__SEND
,
ad
))
SECCLASS_PACKET
,
PACKET__SEND
,
&
ad
))
return
NF_DROP
;
}
if
(
selinux_policycap_netpeer
)
if
(
selinux_xfrm_postroute_last
(
sksec
->
sid
,
skb
,
ad
,
proto
))
if
(
selinux_xfrm_postroute_last
(
sksec
->
sid
,
skb
,
&
ad
,
proto
))
return
NF_DROP
;
return
NF_ACCEPT
;
...
...
@@ -4537,23 +4623,15 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
struct
sock
*
sk
;
struct
avc_audit_data
ad
;
char
*
addrp
;
u8
proto
;
u8
secmark_active
;
u8
peerlbl_active
;
AVC_AUDIT_DATA_INIT
(
&
ad
,
NET
);
ad
.
u
.
net
.
netif
=
ifindex
;
ad
.
u
.
net
.
family
=
family
;
if
(
selinux_parse_skb
(
skb
,
&
ad
,
&
addrp
,
0
,
&
proto
))
return
NF_DROP
;
/* If any sort of compatibility mode is enabled then handoff processing
* to the selinux_ip_postroute_compat() function to deal with the
* special handling. We do this in an attempt to keep this function
* as fast and as clean as possible. */
if
(
selinux_compat_net
||
!
selinux_policycap_netpeer
)
return
selinux_ip_postroute_compat
(
skb
,
ifindex
,
&
ad
,
family
,
addrp
,
proto
);
return
selinux_ip_postroute_compat
(
skb
,
ifindex
,
family
);
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
* packet transformation so allow the packet to pass without any checks
...
...
@@ -4569,21 +4647,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
if
(
!
secmark_active
&&
!
peerlbl_active
)
return
NF_ACCEPT
;
/* if the packet is
locally generated (skb->sk != NULL) then use
the
*
socket's label as the peer label, otherwise the packet is being
*
forwarded through this system and we need to fetch
the peer label
*
directly from the packet
*/
/* if the packet is
being forwarded then get the peer label from
the
*
packet itself; otherwise check to see if it is from a local
*
application or the kernel, if from an application get
the peer label
*
from the sending socket, otherwise use the kernel's sid
*/
sk
=
skb
->
sk
;
if
(
sk
)
{
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
peer_sid
=
sksec
->
sid
;
if
(
sk
==
NULL
)
{
switch
(
family
)
{
case
PF_INET
:
if
(
IPCB
(
skb
)
->
flags
&
IPSKB_FORWARDED
)
secmark_perm
=
PACKET__FORWARD_OUT
;
else
secmark_perm
=
PACKET__SEND
;
}
else
{
break
;
case
PF_INET6
:
if
(
IP6CB
(
skb
)
->
flags
&
IP6SKB_FORWARDED
)
secmark_perm
=
PACKET__FORWARD_OUT
;
else
secmark_perm
=
PACKET__SEND
;
break
;
default:
return
NF_DROP
;
}
if
(
secmark_perm
==
PACKET__FORWARD_OUT
)
{
if
(
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
peer_sid
))
return
NF_DROP
;
secmark_perm
=
PACKET__FORWARD_OUT
;
}
else
peer_sid
=
SECINITSID_KERNEL
;
}
else
{
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
peer_sid
=
sksec
->
sid
;
secmark_perm
=
PACKET__SEND
;
}
AVC_AUDIT_DATA_INIT
(
&
ad
,
NET
);
ad
.
u
.
net
.
netif
=
ifindex
;
ad
.
u
.
net
.
family
=
family
;
if
(
selinux_parse_skb
(
skb
,
&
ad
,
&
addrp
,
0
,
NULL
))
return
NF_DROP
;
if
(
secmark_active
)
if
(
avc_has_perm
(
peer_sid
,
skb
->
secmark
,
SECCLASS_PACKET
,
secmark_perm
,
&
ad
))
...
...
@@ -5657,6 +5759,13 @@ static struct nf_hook_ops selinux_ipv4_ops[] = {
.
pf
=
PF_INET
,
.
hooknum
=
NF_INET_FORWARD
,
.
priority
=
NF_IP_PRI_SELINUX_FIRST
,
},
{
.
hook
=
selinux_ipv4_output
,
.
owner
=
THIS_MODULE
,
.
pf
=
PF_INET
,
.
hooknum
=
NF_INET_LOCAL_OUT
,
.
priority
=
NF_IP_PRI_SELINUX_FIRST
,
}
};
...
...
security/selinux/include/netlabel.h
View file @
0da939b0
...
...
@@ -39,6 +39,9 @@
#ifdef CONFIG_NETLABEL
void
selinux_netlbl_cache_invalidate
(
void
);
void
selinux_netlbl_err
(
struct
sk_buff
*
skb
,
int
error
,
int
gateway
);
void
selinux_netlbl_sk_security_free
(
struct
sk_security_struct
*
ssec
);
void
selinux_netlbl_sk_security_reset
(
struct
sk_security_struct
*
ssec
,
int
family
);
...
...
@@ -46,8 +49,11 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
u16
family
,
u32
*
type
,
u32
*
sid
);
int
selinux_netlbl_skbuff_setsid
(
struct
sk_buff
*
skb
,
u16
family
,
u32
sid
);
void
selinux_netlbl_
sock_graft
(
struct
sock
*
sk
,
struct
socket
*
sock
);
void
selinux_netlbl_
inet_conn_established
(
struct
sock
*
sk
,
u16
family
);
int
selinux_netlbl_socket_post_create
(
struct
socket
*
sock
);
int
selinux_netlbl_inode_permission
(
struct
inode
*
inode
,
int
mask
);
int
selinux_netlbl_sock_rcv_skb
(
struct
sk_security_struct
*
sksec
,
...
...
@@ -57,12 +63,27 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
int
selinux_netlbl_socket_setsockopt
(
struct
socket
*
sock
,
int
level
,
int
optname
);
int
selinux_netlbl_socket_connect
(
struct
sock
*
sk
,
struct
sockaddr
*
addr
);
#else
static
inline
void
selinux_netlbl_cache_invalidate
(
void
)
{
return
;
}
static
inline
void
selinux_netlbl_err
(
struct
sk_buff
*
skb
,
int
error
,
int
gateway
)
{
return
;
}
static
inline
void
selinux_netlbl_sk_security_free
(
struct
sk_security_struct
*
ssec
)
{
return
;
}
static
inline
void
selinux_netlbl_sk_security_reset
(
struct
sk_security_struct
*
ssec
,
int
family
)
...
...
@@ -79,9 +100,21 @@ static inline int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
*
sid
=
SECSID_NULL
;
return
0
;
}
static
inline
int
selinux_netlbl_skbuff_setsid
(
struct
sk_buff
*
skb
,
u16
family
,
u32
sid
)
{
return
0
;
}
static
inline
void
selinux_netlbl_sock_graft
(
struct
sock
*
sk
,
struct
socket
*
sock
)
static
inline
int
selinux_netlbl_conn_setsid
(
struct
sock
*
sk
,
struct
sockaddr
*
addr
)
{
return
0
;
}
static
inline
void
selinux_netlbl_inet_conn_established
(
struct
sock
*
sk
,
u16
family
)
{
return
;
}
...
...
@@ -107,6 +140,11 @@ static inline int selinux_netlbl_socket_setsockopt(struct socket *sock,
{
return
0
;
}
static
inline
int
selinux_netlbl_socket_connect
(
struct
sock
*
sk
,
struct
sockaddr
*
addr
)
{
return
0
;
}
#endif
/* CONFIG_NETLABEL */
#endif
security/selinux/include/objsec.h
View file @
0da939b0
...
...
@@ -109,16 +109,19 @@ struct netport_security_struct {
};
struct
sk_security_struct
{
u32
sid
;
/* SID of this object */
u32
peer_sid
;
/* SID of peer */
u16
sclass
;
/* sock security class */
#ifdef CONFIG_NETLABEL
enum
{
/* NetLabel state */
NLBL_UNSET
=
0
,
NLBL_REQUIRE
,
NLBL_LABELED
,
NLBL_REQSKB
,
NLBL_CONNLABELED
,
}
nlbl_state
;
struct
netlbl_lsm_secattr
*
nlbl_secattr
;
/* NetLabel sec attributes */
#endif
u32
sid
;
/* SID of this object */
u32
peer_sid
;
/* SID of peer */
u16
sclass
;
/* sock security class */
};
struct
key_security_struct
{
...
...
security/selinux/netlabel.c
View file @
0da939b0
...
...
@@ -9,7 +9,7 @@
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2007
* (c) Copyright Hewlett-Packard Development Company, L.P., 2007
, 2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -29,8 +29,12 @@
#include <linux/spinlock.h>
#include <linux/rcupdate.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/sock.h>
#include <net/netlabel.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include "objsec.h"
#include "security.h"
...
...
@@ -63,33 +67,70 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
return
rc
;
}
/**
* selinux_netlbl_sock_genattr - Generate the NetLabel socket secattr
* @sk: the socket
*
* Description:
* Generate the NetLabel security attributes for a socket, making full use of
* the socket's attribute cache. Returns a pointer to the security attributes
* on success, NULL on failure.
*
*/
static
struct
netlbl_lsm_secattr
*
selinux_netlbl_sock_genattr
(
struct
sock
*
sk
)
{
int
rc
;
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
struct
netlbl_lsm_secattr
*
secattr
;
if
(
sksec
->
nlbl_secattr
!=
NULL
)
return
sksec
->
nlbl_secattr
;
secattr
=
netlbl_secattr_alloc
(
GFP_ATOMIC
);
if
(
secattr
==
NULL
)
return
NULL
;
rc
=
security_netlbl_sid_to_secattr
(
sksec
->
sid
,
secattr
);
if
(
rc
!=
0
)
{
netlbl_secattr_free
(
secattr
);
return
NULL
;
}
sksec
->
nlbl_secattr
=
secattr
;
return
secattr
;
}
/**
* selinux_netlbl_sock_setsid - Label a socket using the NetLabel mechanism
* @sk: the socket to label
* @sid: the SID to use
*
* Description:
* Attempt to label a socket using the NetLabel mechanism
using the given
*
SID. Returns zero values
on success, negative values on failure.
* Attempt to label a socket using the NetLabel mechanism
. Returns zero values
* on success, negative values on failure.
*
*/
static
int
selinux_netlbl_sock_setsid
(
struct
sock
*
sk
,
u32
sid
)
static
int
selinux_netlbl_sock_setsid
(
struct
sock
*
sk
)
{
int
rc
;
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
struct
netlbl_lsm_secattr
secattr
;
struct
netlbl_lsm_secattr
*
secattr
;
netlbl_secattr_init
(
&
secattr
);
if
(
sksec
->
nlbl_state
!=
NLBL_REQUIRE
)
return
0
;
rc
=
security_netlbl_sid_to_secattr
(
sid
,
&
secattr
);
if
(
rc
!=
0
)
goto
sock_setsid_return
;
rc
=
netlbl_sock_setattr
(
sk
,
&
secattr
);
if
(
rc
==
0
)
secattr
=
selinux_netlbl_sock_genattr
(
sk
);
if
(
secattr
==
NULL
)
return
-
ENOMEM
;
rc
=
netlbl_sock_setattr
(
sk
,
secattr
);
switch
(
rc
)
{
case
0
:
sksec
->
nlbl_state
=
NLBL_LABELED
;
break
;
case
-
EDESTADDRREQ
:
sksec
->
nlbl_state
=
NLBL_REQSKB
;
rc
=
0
;
break
;
}
sock_setsid_return:
netlbl_secattr_destroy
(
&
secattr
);
return
rc
;
}
...
...
@@ -105,6 +146,38 @@ void selinux_netlbl_cache_invalidate(void)
netlbl_cache_invalidate
();
}
/**
* selinux_netlbl_err - Handle a NetLabel packet error
* @skb: the packet
* @error: the error code
* @gateway: true if host is acting as a gateway, false otherwise
*
* Description:
* When a packet is dropped due to a call to avc_has_perm() pass the error
* code to the NetLabel subsystem so any protocol specific processing can be
* done. This is safe to call even if you are unsure if NetLabel labeling is
* present on the packet, NetLabel is smart enough to only act when it should.
*
*/
void
selinux_netlbl_err
(
struct
sk_buff
*
skb
,
int
error
,
int
gateway
)
{
netlbl_skbuff_err
(
skb
,
error
,
gateway
);
}
/**
* selinux_netlbl_sk_security_free - Free the NetLabel fields
* @sssec: the sk_security_struct
*
* Description:
* Free all of the memory in the NetLabel fields of a sk_security_struct.
*
*/
void
selinux_netlbl_sk_security_free
(
struct
sk_security_struct
*
ssec
)
{
if
(
ssec
->
nlbl_secattr
!=
NULL
)
netlbl_secattr_free
(
ssec
->
nlbl_secattr
);
}
/**
* selinux_netlbl_sk_security_reset - Reset the NetLabel fields
* @ssec: the sk_security_struct
...
...
@@ -163,35 +236,118 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
}
/**
* selinux_netlbl_sock_graft - Netlabel the new socket
* selinux_netlbl_skbuff_setsid - Set the NetLabel on a packet given a sid
* @skb: the packet
* @family: protocol family
* @sid: the SID
*
* Description
* Call the NetLabel mechanism to set the label of a packet using @sid.
* Returns zero on auccess, negative values on failure.
*
*/
int
selinux_netlbl_skbuff_setsid
(
struct
sk_buff
*
skb
,
u16
family
,
u32
sid
)
{
int
rc
;
struct
netlbl_lsm_secattr
secattr_storage
;
struct
netlbl_lsm_secattr
*
secattr
=
NULL
;
struct
sock
*
sk
;
/* if this is a locally generated packet check to see if it is already
* being labeled by it's parent socket, if it is just exit */
sk
=
skb
->
sk
;
if
(
sk
!=
NULL
)
{
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
if
(
sksec
->
nlbl_state
!=
NLBL_REQSKB
)
return
0
;
secattr
=
sksec
->
nlbl_secattr
;
}
if
(
secattr
==
NULL
)
{
secattr
=
&
secattr_storage
;
netlbl_secattr_init
(
secattr
);
rc
=
security_netlbl_sid_to_secattr
(
sid
,
secattr
);
if
(
rc
!=
0
)
goto
skbuff_setsid_return
;
}
rc
=
netlbl_skbuff_setattr
(
skb
,
family
,
secattr
);
skbuff_setsid_return:
if
(
secattr
==
&
secattr_storage
)
netlbl_secattr_destroy
(
secattr
);
return
rc
;
}
/**
* selinux_netlbl_inet_conn_established - Netlabel the newly accepted connection
* @sk: the new connection
* @sock: the new socket
*
* Description:
*
The connection represented by @sk is being grafted onto @sock so set the
*
socket's NetLabel to match the SID of @sk
.
*
A new connection has been established on @sk so make sure it is labeled
*
correctly with the NetLabel susbsystem
.
*
*/
void
selinux_netlbl_
sock_graft
(
struct
sock
*
sk
,
struct
socket
*
sock
)
void
selinux_netlbl_
inet_conn_established
(
struct
sock
*
sk
,
u16
family
)
{
int
rc
;
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
struct
netlbl_lsm_secattr
secattr
;
u32
nlbl_peer_sid
;
struct
netlbl_lsm_secattr
*
secattr
;
struct
inet_sock
*
sk_inet
=
inet_sk
(
sk
);
struct
sockaddr_in
addr
;
if
(
sksec
->
nlbl_state
!=
NLBL_REQUIRE
)
return
;
netlbl_secattr_init
(
&
secattr
);
if
(
netlbl_sock_getattr
(
sk
,
&
secattr
)
==
0
&&
secattr
.
flags
!=
NETLBL_SECATTR_NONE
&&
security_netlbl_secattr_to_sid
(
&
secattr
,
&
nlbl_peer_sid
)
==
0
)
sksec
->
peer_sid
=
nlbl_peer_sid
;
netlbl_secattr_destroy
(
&
secattr
);
secattr
=
selinux_netlbl_sock_genattr
(
sk
);
if
(
secattr
==
NULL
)
return
;
/* Try to set the NetLabel on the socket to save time later, if we fail
* here we will pick up the pieces in later calls to
* selinux_netlbl_inode_permission(). */
selinux_netlbl_sock_setsid
(
sk
,
sksec
->
sid
);
rc
=
netlbl_sock_setattr
(
sk
,
secattr
);
switch
(
rc
)
{
case
0
:
sksec
->
nlbl_state
=
NLBL_LABELED
;
break
;
case
-
EDESTADDRREQ
:
/* no PF_INET6 support yet because we don't support any IPv6
* labeling protocols */
if
(
family
!=
PF_INET
)
{
sksec
->
nlbl_state
=
NLBL_UNSET
;
return
;
}
addr
.
sin_family
=
family
;
addr
.
sin_addr
.
s_addr
=
sk_inet
->
daddr
;
if
(
netlbl_conn_setattr
(
sk
,
(
struct
sockaddr
*
)
&
addr
,
secattr
)
!=
0
)
{
/* we failed to label the connected socket (could be
* for a variety of reasons, the actual "why" isn't
* important here) so we have to go to our backup plan,
* labeling the packets individually in the netfilter
* local output hook. this is okay but we need to
* adjust the MSS of the connection to take into
* account any labeling overhead, since we don't know
* the exact overhead at this point we'll use the worst
* case value which is 40 bytes for IPv4 */
struct
inet_connection_sock
*
sk_conn
=
inet_csk
(
sk
);
sk_conn
->
icsk_ext_hdr_len
+=
40
-
(
sk_inet
->
opt
?
sk_inet
->
opt
->
optlen
:
0
);
sk_conn
->
icsk_sync_mss
(
sk
,
sk_conn
->
icsk_pmtu_cookie
);
sksec
->
nlbl_state
=
NLBL_REQSKB
;
}
else
sksec
->
nlbl_state
=
NLBL_CONNLABELED
;
break
;
default:
/* note that we are failing to label the socket which could be
* a bad thing since it means traffic could leave the system
* without the desired labeling, however, all is not lost as
* we have a check in selinux_netlbl_inode_permission() to
* pick up the pieces that we might drop here because we can't
* return an error code */
break
;
}
}
/**
...
...
@@ -205,13 +361,7 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
*/
int
selinux_netlbl_socket_post_create
(
struct
socket
*
sock
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
if
(
sksec
->
nlbl_state
!=
NLBL_REQUIRE
)
return
0
;
return
selinux_netlbl_sock_setsid
(
sk
,
sksec
->
sid
);
return
selinux_netlbl_sock_setsid
(
sock
->
sk
);
}
/**
...
...
@@ -246,7 +396,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
local_bh_disable
();
bh_lock_sock_nested
(
sk
);
if
(
likely
(
sksec
->
nlbl_state
==
NLBL_REQUIRE
))
rc
=
selinux_netlbl_sock_setsid
(
sk
,
sksec
->
sid
);
rc
=
selinux_netlbl_sock_setsid
(
sk
);
else
rc
=
0
;
bh_unlock_sock
(
sk
);
...
...
@@ -307,7 +457,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
return
0
;
if
(
nlbl_sid
!=
SECINITSID_UNLABELED
)
netlbl_skbuff_err
(
skb
,
rc
);
netlbl_skbuff_err
(
skb
,
rc
,
0
);
return
rc
;
}
...
...
@@ -334,7 +484,8 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
struct
netlbl_lsm_secattr
secattr
;
if
(
level
==
IPPROTO_IP
&&
optname
==
IP_OPTIONS
&&
sksec
->
nlbl_state
==
NLBL_LABELED
)
{
(
sksec
->
nlbl_state
==
NLBL_LABELED
||
sksec
->
nlbl_state
==
NLBL_CONNLABELED
))
{
netlbl_secattr_init
(
&
secattr
);
lock_sock
(
sk
);
rc
=
netlbl_sock_getattr
(
sk
,
&
secattr
);
...
...
@@ -346,3 +497,50 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
return
rc
;
}
/**
* selinux_netlbl_socket_connect - Label a client-side socket on connect
* @sk: the socket to label
* @addr: the destination address
*
* Description:
* Attempt to label a connected socket with NetLabel using the given address.
* Returns zero values on success, negative values on failure.
*
*/
int
selinux_netlbl_socket_connect
(
struct
sock
*
sk
,
struct
sockaddr
*
addr
)
{
int
rc
;
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
struct
netlbl_lsm_secattr
*
secattr
;
if
(
sksec
->
nlbl_state
!=
NLBL_REQSKB
&&
sksec
->
nlbl_state
!=
NLBL_CONNLABELED
)
return
0
;
local_bh_disable
();
bh_lock_sock_nested
(
sk
);
/* connected sockets are allowed to disconnect when the address family
* is set to AF_UNSPEC, if that is what is happening we want to reset
* the socket */
if
(
addr
->
sa_family
==
AF_UNSPEC
)
{
netlbl_sock_delattr
(
sk
);
sksec
->
nlbl_state
=
NLBL_REQSKB
;
rc
=
0
;
goto
socket_connect_return
;
}
secattr
=
selinux_netlbl_sock_genattr
(
sk
);
if
(
secattr
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
socket_connect_return
;
}
rc
=
netlbl_conn_setattr
(
sk
,
addr
,
secattr
);
if
(
rc
==
0
)
sksec
->
nlbl_state
=
NLBL_CONNLABELED
;
socket_connect_return:
bh_unlock_sock
(
sk
);
local_bh_enable
();
return
rc
;
}
security/selinux/ss/services.c
View file @
0da939b0
...
...
@@ -2955,7 +2955,7 @@ int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
*/
int
security_netlbl_sid_to_secattr
(
u32
sid
,
struct
netlbl_lsm_secattr
*
secattr
)
{
int
rc
=
-
ENOENT
;
int
rc
;
struct
context
*
ctx
;
if
(
!
ss_initialized
)
...
...
@@ -2963,11 +2963,18 @@ int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
read_lock
(
&
policy_rwlock
);
ctx
=
sidtab_search
(
&
sidtab
,
sid
);
if
(
ctx
==
NULL
)
if
(
ctx
==
NULL
)
{
rc
=
-
ENOENT
;
goto
netlbl_sid_to_secattr_failure
;
}
secattr
->
domain
=
kstrdup
(
policydb
.
p_type_val_to_name
[
ctx
->
type
-
1
],
GFP_ATOMIC
);
secattr
->
flags
|=
NETLBL_SECATTR_DOMAIN_CPY
;
if
(
secattr
->
domain
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
netlbl_sid_to_secattr_failure
;
}
secattr
->
attr
.
secid
=
sid
;
secattr
->
flags
|=
NETLBL_SECATTR_DOMAIN_CPY
|
NETLBL_SECATTR_SECID
;
mls_export_netlbl_lvl
(
ctx
,
secattr
);
rc
=
mls_export_netlbl_cat
(
ctx
,
secattr
);
if
(
rc
!=
0
)
...
...
security/smack/smack_lsm.c
View file @
0da939b0
...
...
@@ -2179,7 +2179,10 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
* This is the simplist possible security model
* for networking.
*/
return
smk_access
(
smack
,
ssp
->
smk_in
,
MAY_WRITE
);
rc
=
smk_access
(
smack
,
ssp
->
smk_in
,
MAY_WRITE
);
if
(
rc
!=
0
)
netlbl_skbuff_err
(
skb
,
rc
,
0
);
return
rc
;
}
/**
...
...
security/smack/smackfs.c
View file @
0da939b0
...
...
@@ -354,9 +354,11 @@ static void smk_cipso_doi(void)
doip
->
tags
[
rc
]
=
CIPSO_V4_TAG_INVALID
;
rc
=
netlbl_cfg_cipsov4_add_map
(
doip
,
NULL
,
&
audit_info
);
if
(
rc
!=
0
)
if
(
rc
!=
0
)
{
printk
(
KERN_WARNING
"%s:%d add rc = %d
\n
"
,
__func__
,
__LINE__
,
rc
);
kfree
(
doip
);
}
}
/**
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment