Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
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
Hide 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 @@ doi_add_failure:
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 @@ doi_walk_return:
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
,
const
struct
cipso_v4_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
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 @@ socket_setattr_failure:
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 @@ list_start:
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 @@ list_start:
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
);
if
(
ret_val
==
0
)
atomic_dec
(
&
netlabel_mgmt_protocount
);
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
;
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_UNLABELED
:
ret_val
=
0
;
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
cipso_v4_doi_domhsh_add
(
entry
->
type_def
.
cipsov4
,
entry
->
domain
);
break
;
default:
return
-
EINVAL
;
}
if
(
ret_val
!=
0
)
return
ret_val
;
entry
->
valid
=
1
;
INIT_RCU_HEAD
(
&
entry
->
rcu
);
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 */
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
)
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
);
if
(
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
)
}
else
{
INIT_LIST_HEAD
(
&
entry
->
list
);
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
;
}
audit_log_format
(
audit_buf
,
" res=%u"
,
ret_val
==
0
?
1
:
0
);
audit_log_end
(
audit_buf
);
}
rcu_read_unlock
();
if
(
ret_val
!=
0
)
{
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_CIPSOV4
:
if
(
cipso_v4_doi_domhsh_remove
(
entry
->
type_def
.
cipsov4
,
entry
->
domain
)
!=
0
)
BUG
();
break
;
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
;
}
#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
;
}
#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 @@ cfg_unlbl_add_map_failure:
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 @@ socket_setattr_return:
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
->
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
);
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
;
}
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
);
ret_val
=
netlbl_mgmt_listentry
(
cb_arg
->
skb
,
entry
);
if
(
ret_val
!=
0
)
goto
listall_cb_failure
;
ret_val
=
nla_put_u32
(
cb_arg
->
skb
,
NLBL_MGMT_A_PROTOCOL
,
entry
->
type
);
if
(
ret_val
!=
0
)
goto
listall_cb_failure
;
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
nla_put_u32
(
cb_arg
->
skb
,
NLBL_MGMT_A_CV4DOI
,
entry
->
type_def
.
cipsov4
->
doi
);
if
(
ret_val
!=
0
)
goto
listall_cb_failure
;
break
;
}
cb_arg
->
seq
++
;
return
genlmsg_end
(
cb_arg
->
skb
,
data
);
...
...
@@ -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
);
}
list_for_each_entry_safe
(
iter6
,
tmp6
,
&
iface
->
addr6_list
,
list
)
if
(
iter6
->
valid
)
{
list_del_rcu
(
&
iter6
->
list
);
kfree
(
iter6
);
}
netlbl_af4list_foreach_safe
(
iter4
,
tmp4
,
&
iface
->
addr4_list
)
{
netlbl_af4list_remove_entry
(
iter4
);
kfree
(
netlbl_unlhsh_addr4_entry
(
iter4
)
);
}
#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
)
{
spin_unlock
(
&
netlbl_unlhsh_lock
);
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
);
ret_val
=
netlbl_af4list_add
(
&
entry
->
list
,
&
iface
->
addr4_list
);
spin_unlock
(
&
netlbl_unlhsh_lock
);
return
0
;
if
(
ret_val
!=
0
)
kfree
(
entry
);
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
)))
{
spin_unlock
(
&
netlbl_unlhsh_lock
);
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
);
ret_val
=
netlbl_af6list_add
(
&
entry
->
list
,
&
iface
->
addr6_list
);
spin_unlock
(
&
netlbl_unlhsh_lock
);
if
(
ret_val
!=
0
)
kfree
(
entry
);
return
0
;
}
#endif
/* IPv6 */
...
...
@@ -658,10 +501,10 @@ 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
,
dev_name
,
addr4
->
s_addr
,
mask4
->
s_addr
);
netlbl_
af4list_audit_addr
(
audit_buf
,
1
,
dev_name
,
addr4
->
s_addr
,
mask4
->
s_addr
);
break
;
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
...
...
@@ -672,9 +515,9 @@ 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
,
dev_name
,
addr6
,
mask6
);
netlbl_
af6list_audit_addr
(
audit_buf
,
1
,
dev_name
,
addr6
,
mask6
);
break
;
}
#endif
/* IPv6 */
...
...
@@ -719,35 +562,34 @@ 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
,
(
dev
!=
NULL
?
dev
->
name
:
NULL
),
entry
->
addr
,
entry
->
mask
);
netlbl_
af4list_audit_addr
(
audit_buf
,
1
,
(
dev
!=
NULL
?
dev
->
name
:
NULL
),
addr
->
s_addr
,
mask
->
s_addr
);
if
(
dev
!=
NULL
)
dev_put
(
dev
);
if
(
security_secid_to_secctx
(
entry
->
secid
,
&
secctx
,
&
secctx_len
)
==
0
)
{
if
(
entry
&&
security_secid_to_secctx
(
entry
->
secid
,
&
secctx
,
&
secctx_len
)
==
0
)
{
audit_log_format
(
audit_buf
,
" sec_obj=%s"
,
secctx
);
security_release_secctx
(
secctx
,
secctx_len
);
}
...
...
@@ -781,36 +623,33 @@ 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
,
(
dev
!=
NULL
?
dev
->
name
:
NULL
),
addr
,
mask
);
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
,
&
secctx
,
&
secctx_len
)
==
0
)
{
if
(
entry
&&
security_secid_to_secctx
(
entry
->
secid
,
&
secctx
,
&
secctx_len
)
==
0
)
{
audit_log_format
(
audit_buf
,
" sec_obj=%s"
,
secctx
);
security_release_secctx
(
secctx
,
secctx_len
);
}
...
...
@@ -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
)
goto
unlhsh_condremove_failure
;
list_for_each_entry_rcu
(
iter6
,
&
iface
->
addr6_list
,
list
)
if
(
iter6
->
valid
)
goto
unlhsh_condremove_failure
;
netlbl_af4list_foreach_rcu
(
iter4
,
&
iface
->
addr4_
list
)
goto
unlhsh_condremove_failure
;
#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,44 +1280,43 @@ 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
,
NULL
,
&
cb_arg
)
<
0
)
{
NLBL_UNLABEL_C_STATICLIST
,
iface
,
netlbl_unlhsh_addr4_entry
(
addr4
)
,
NULL
,
&
cb_arg
)
<
0
)
{
iter_addr4
--
;
iter_chain
--
;
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
,
&
cb_arg
)
<
0
)
{
NLBL_UNLABEL_C_STATICLIST
,
iface
,
NULL
,
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
,
NULL
,
&
cb_arg
)
<
0
)
{
iface
,
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
,
&
cb_arg
)
<
0
)
{
iface
,
NULL
,
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 @@ out:
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 @@ out:
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
)
{
if
(
sk
==
NULL
)
{
switch
(
family
)
{
case
PF_INET
:
if
(
IPCB
(
skb
)
->
flags
&
IPSKB_FORWARDED
)
secmark_perm
=
PACKET__FORWARD_OUT
;
else
secmark_perm
=
PACKET__SEND
;
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
;
}
else
peer_sid
=
SECINITSID_KERNEL
;
}
else
{
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
peer_sid
=
sksec
->
sid
;
secmark_perm
=
PACKET__SEND
;
}
else
{
if
(
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
peer_sid
))
return
NF_DROP
;
secmark_perm
=
PACKET__FORWARD_OUT
;
}
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 @@ netlbl_secattr_to_sid_return_cleanup:
*/
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