Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
d011a4d8
Commit
d011a4d8
authored
Jul 07, 2016
by
James Morris
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'stable-4.8' of
git://git.infradead.org/users/pcmoore/selinux
into next
parents
544e1cea
3f09354a
Changes
36
Hide whitespace changes
Inline
Side-by-side
Showing
36 changed files
with
3511 additions
and
259 deletions
+3511
-259
include/net/calipso.h
include/net/calipso.h
+91
-0
include/net/inet_sock.h
include/net/inet_sock.h
+6
-1
include/net/ipv6.h
include/net/ipv6.h
+9
-1
include/net/netlabel.h
include/net/netlabel.h
+98
-3
include/uapi/linux/audit.h
include/uapi/linux/audit.h
+2
-0
include/uapi/linux/in6.h
include/uapi/linux/in6.h
+1
-0
net/dccp/ipv6.c
net/dccp/ipv6.c
+9
-3
net/ipv4/cipso_ipv4.c
net/ipv4/cipso_ipv4.c
+9
-79
net/ipv4/tcp_input.c
net/ipv4/tcp_input.c
+3
-0
net/ipv6/Makefile
net/ipv6/Makefile
+1
-0
net/ipv6/af_inet6.c
net/ipv6/af_inet6.c
+8
-1
net/ipv6/calipso.c
net/ipv6/calipso.c
+1473
-0
net/ipv6/exthdrs.c
net/ipv6/exthdrs.c
+76
-0
net/ipv6/exthdrs_core.c
net/ipv6/exthdrs_core.c
+1
-1
net/ipv6/ipv6_sockglue.c
net/ipv6/ipv6_sockglue.c
+0
-1
net/ipv6/sysctl_net_ipv6.c
net/ipv6/sysctl_net_ipv6.c
+19
-0
net/ipv6/tcp_ipv6.c
net/ipv6/tcp_ipv6.c
+9
-3
net/iucv/af_iucv.c
net/iucv/af_iucv.c
+4
-1
net/netlabel/Kconfig
net/netlabel/Kconfig
+1
-0
net/netlabel/Makefile
net/netlabel/Makefile
+1
-1
net/netlabel/netlabel_calipso.c
net/netlabel/netlabel_calipso.c
+740
-0
net/netlabel/netlabel_calipso.h
net/netlabel/netlabel_calipso.h
+151
-0
net/netlabel/netlabel_domainhash.c
net/netlabel/netlabel_domainhash.c
+244
-49
net/netlabel/netlabel_domainhash.h
net/netlabel/netlabel_domainhash.h
+14
-3
net/netlabel/netlabel_kapi.c
net/netlabel/netlabel_kapi.c
+358
-36
net/netlabel/netlabel_mgmt.c
net/netlabel/netlabel_mgmt.c
+80
-5
net/netlabel/netlabel_mgmt.h
net/netlabel/netlabel_mgmt.h
+22
-5
net/netlabel/netlabel_unlabeled.c
net/netlabel/netlabel_unlabeled.c
+3
-2
net/netlabel/netlabel_user.c
net/netlabel/netlabel_user.c
+5
-0
security/selinux/hooks.c
security/selinux/hooks.c
+18
-3
security/selinux/include/netlabel.h
security/selinux/include/netlabel.h
+3
-1
security/selinux/netlabel.c
security/selinux/netlabel.c
+27
-9
security/selinux/selinuxfs.c
security/selinux/selinuxfs.c
+1
-1
security/selinux/ss/ebitmap.c
security/selinux/ss/ebitmap.c
+1
-1
security/selinux/ss/services.c
security/selinux/ss/services.c
+22
-48
security/smack/smack_lsm.c
security/smack/smack_lsm.c
+1
-1
No files found.
include/net/calipso.h
0 → 100644
View file @
d011a4d8
/*
* CALIPSO - Common Architecture Label IPv6 Security Option
*
* This is an implementation of the CALIPSO protocol as specified in
* RFC 5570.
*
* Authors: Paul Moore <paul@paul-moore.com>
* Huw Davies <huw@codeweavers.com>
*
*/
/*
* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
*
* 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _CALIPSO_H
#define _CALIPSO_H
#include <linux/types.h>
#include <linux/rcupdate.h>
#include <linux/list.h>
#include <linux/net.h>
#include <linux/skbuff.h>
#include <net/netlabel.h>
#include <net/request_sock.h>
#include <linux/atomic.h>
#include <asm/unaligned.h>
/* known doi values */
#define CALIPSO_DOI_UNKNOWN 0x00000000
/* doi mapping types */
#define CALIPSO_MAP_UNKNOWN 0
#define CALIPSO_MAP_PASS 2
/*
* CALIPSO DOI definitions
*/
/* DOI definition struct */
struct
calipso_doi
{
u32
doi
;
u32
type
;
atomic_t
refcount
;
struct
list_head
list
;
struct
rcu_head
rcu
;
};
/*
* Sysctl Variables
*/
extern
int
calipso_cache_enabled
;
extern
int
calipso_cache_bucketsize
;
#ifdef CONFIG_NETLABEL
int
__init
calipso_init
(
void
);
void
calipso_exit
(
void
);
bool
calipso_validate
(
const
struct
sk_buff
*
skb
,
const
unsigned
char
*
option
);
#else
static
inline
int
__init
calipso_init
(
void
)
{
return
0
;
}
static
inline
void
calipso_exit
(
void
)
{
}
static
inline
bool
calipso_validate
(
const
struct
sk_buff
*
skb
,
const
unsigned
char
*
option
)
{
return
true
;
}
#endif
/* CONFIG_NETLABEL */
#endif
/* _CALIPSO_H */
include/net/inet_sock.h
View file @
d011a4d8
...
...
@@ -97,7 +97,12 @@ struct inet_request_sock {
u32
ir_mark
;
union
{
struct
ip_options_rcu
*
opt
;
struct
sk_buff
*
pktopts
;
#if IS_ENABLED(CONFIG_IPV6)
struct
{
struct
ipv6_txoptions
*
ipv6_opt
;
struct
sk_buff
*
pktopts
;
};
#endif
};
};
...
...
include/net/ipv6.h
View file @
d011a4d8
...
...
@@ -313,11 +313,19 @@ struct ipv6_txoptions *ipv6_renew_options(struct sock *sk,
int
newtype
,
struct
ipv6_opt_hdr
__user
*
newopt
,
int
newoptlen
);
struct
ipv6_txoptions
*
ipv6_renew_options_kern
(
struct
sock
*
sk
,
struct
ipv6_txoptions
*
opt
,
int
newtype
,
struct
ipv6_opt_hdr
*
newopt
,
int
newoptlen
);
struct
ipv6_txoptions
*
ipv6_fixup_options
(
struct
ipv6_txoptions
*
opt_space
,
struct
ipv6_txoptions
*
opt
);
bool
ipv6_opt_accepted
(
const
struct
sock
*
sk
,
const
struct
sk_buff
*
skb
,
const
struct
inet6_skb_parm
*
opt
);
struct
ipv6_txoptions
*
ipv6_update_options
(
struct
sock
*
sk
,
struct
ipv6_txoptions
*
opt
);
static
inline
bool
ipv6_accept_ra
(
struct
inet6_dev
*
idev
)
{
...
...
@@ -943,7 +951,7 @@ enum {
int
ipv6_find_hdr
(
const
struct
sk_buff
*
skb
,
unsigned
int
*
offset
,
int
target
,
unsigned
short
*
fragoff
,
int
*
fragflg
);
int
ipv6_find_tlv
(
struct
sk_buff
*
skb
,
int
offset
,
int
type
);
int
ipv6_find_tlv
(
const
struct
sk_buff
*
skb
,
int
offset
,
int
type
);
struct
in6_addr
*
fl6_update_dst
(
struct
flowi6
*
fl6
,
const
struct
ipv6_txoptions
*
opt
,
...
...
include/net/netlabel.h
View file @
d011a4d8
...
...
@@ -40,6 +40,7 @@
#include <linux/atomic.h>
struct
cipso_v4_doi
;
struct
calipso_doi
;
/*
* NetLabel - A management interface for maintaining network packet label
...
...
@@ -94,6 +95,8 @@ struct cipso_v4_doi;
#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL"
#define NETLBL_NLTYPE_ADDRSELECT 6
#define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL"
#define NETLBL_NLTYPE_CALIPSO 7
#define NETLBL_NLTYPE_CALIPSO_NAME "NLBL_CALIPSO"
/*
* NetLabel - Kernel API for accessing the network packet label mappings.
...
...
@@ -216,6 +219,63 @@ struct netlbl_lsm_secattr {
}
attr
;
};
/**
* struct netlbl_calipso_ops - NetLabel CALIPSO operations
* @doi_add: add a CALIPSO DOI
* @doi_free: free a CALIPSO DOI
* @doi_getdef: returns a reference to a DOI
* @doi_putdef: releases a reference of a DOI
* @doi_walk: enumerate the DOI list
* @sock_getattr: retrieve the socket's attr
* @sock_setattr: set the socket's attr
* @sock_delattr: remove the socket's attr
* @req_setattr: set the req socket's attr
* @req_delattr: remove the req socket's attr
* @opt_getattr: retrieve attr from memory block
* @skbuff_optptr: find option in packet
* @skbuff_setattr: set the skbuff's attr
* @skbuff_delattr: remove the skbuff's attr
* @cache_invalidate: invalidate cache
* @cache_add: add cache entry
*
* Description:
* This structure is filled out by the CALIPSO engine and passed
* to the NetLabel core via a call to netlbl_calipso_ops_register().
* It enables the CALIPSO engine (and hence IPv6) to be compiled
* as a module.
*/
struct
netlbl_calipso_ops
{
int
(
*
doi_add
)(
struct
calipso_doi
*
doi_def
,
struct
netlbl_audit
*
audit_info
);
void
(
*
doi_free
)(
struct
calipso_doi
*
doi_def
);
int
(
*
doi_remove
)(
u32
doi
,
struct
netlbl_audit
*
audit_info
);
struct
calipso_doi
*
(
*
doi_getdef
)(
u32
doi
);
void
(
*
doi_putdef
)(
struct
calipso_doi
*
doi_def
);
int
(
*
doi_walk
)(
u32
*
skip_cnt
,
int
(
*
callback
)(
struct
calipso_doi
*
doi_def
,
void
*
arg
),
void
*
cb_arg
);
int
(
*
sock_getattr
)(
struct
sock
*
sk
,
struct
netlbl_lsm_secattr
*
secattr
);
int
(
*
sock_setattr
)(
struct
sock
*
sk
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
);
void
(
*
sock_delattr
)(
struct
sock
*
sk
);
int
(
*
req_setattr
)(
struct
request_sock
*
req
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
);
void
(
*
req_delattr
)(
struct
request_sock
*
req
);
int
(
*
opt_getattr
)(
const
unsigned
char
*
calipso
,
struct
netlbl_lsm_secattr
*
secattr
);
unsigned
char
*
(
*
skbuff_optptr
)(
const
struct
sk_buff
*
skb
);
int
(
*
skbuff_setattr
)(
struct
sk_buff
*
skb
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
);
int
(
*
skbuff_delattr
)(
struct
sk_buff
*
skb
);
void
(
*
cache_invalidate
)(
void
);
int
(
*
cache_add
)(
const
unsigned
char
*
calipso_ptr
,
const
struct
netlbl_lsm_secattr
*
secattr
);
};
/*
* LSM security attribute operations (inline)
*/
...
...
@@ -385,6 +445,14 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
const
struct
in_addr
*
addr
,
const
struct
in_addr
*
mask
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_cfg_calipso_add
(
struct
calipso_doi
*
doi_def
,
struct
netlbl_audit
*
audit_info
);
void
netlbl_cfg_calipso_del
(
u32
doi
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_cfg_calipso_map_add
(
u32
doi
,
const
char
*
domain
,
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
struct
netlbl_audit
*
audit_info
);
/*
* LSM security attribute operations
*/
...
...
@@ -405,6 +473,12 @@ int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
unsigned
long
bitmap
,
gfp_t
flags
);
/* Bitmap functions
*/
int
netlbl_bitmap_walk
(
const
unsigned
char
*
bitmap
,
u32
bitmap_len
,
u32
offset
,
u8
state
);
void
netlbl_bitmap_setbit
(
unsigned
char
*
bitmap
,
u32
bit
,
u8
state
);
/*
* LSM protocol operations (NetLabel LSM/kernel API)
*/
...
...
@@ -427,13 +501,13 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
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
,
int
gateway
);
void
netlbl_skbuff_err
(
struct
sk_buff
*
skb
,
u16
family
,
int
error
,
int
gateway
);
/*
* LSM label mapping cache operations
*/
void
netlbl_cache_invalidate
(
void
);
int
netlbl_cache_add
(
const
struct
sk_buff
*
skb
,
int
netlbl_cache_add
(
const
struct
sk_buff
*
skb
,
u16
family
,
const
struct
netlbl_lsm_secattr
*
secattr
);
/*
...
...
@@ -495,6 +569,24 @@ static inline int netlbl_cfg_cipsov4_map_add(u32 doi,
{
return
-
ENOSYS
;
}
static
inline
int
netlbl_cfg_calipso_add
(
struct
calipso_doi
*
doi_def
,
struct
netlbl_audit
*
audit_info
)
{
return
-
ENOSYS
;
}
static
inline
void
netlbl_cfg_calipso_del
(
u32
doi
,
struct
netlbl_audit
*
audit_info
)
{
return
;
}
static
inline
int
netlbl_cfg_calipso_map_add
(
u32
doi
,
const
char
*
domain
,
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
struct
netlbl_audit
*
audit_info
)
{
return
-
ENOSYS
;
}
static
inline
int
netlbl_catmap_walk
(
struct
netlbl_lsm_catmap
*
catmap
,
u32
offset
)
{
...
...
@@ -586,7 +678,7 @@ static inline void netlbl_cache_invalidate(void)
{
return
;
}
static
inline
int
netlbl_cache_add
(
const
struct
sk_buff
*
skb
,
static
inline
int
netlbl_cache_add
(
const
struct
sk_buff
*
skb
,
u16
family
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
return
0
;
...
...
@@ -598,4 +690,7 @@ static inline struct audit_buffer *netlbl_audit_start(int type,
}
#endif
/* CONFIG_NETLABEL */
const
struct
netlbl_calipso_ops
*
netlbl_calipso_ops_register
(
const
struct
netlbl_calipso_ops
*
ops
);
#endif
/* _NETLABEL_H */
include/uapi/linux/audit.h
View file @
d011a4d8
...
...
@@ -130,6 +130,8 @@
#define AUDIT_MAC_IPSEC_EVENT 1415
/* Audit an IPSec event */
#define AUDIT_MAC_UNLBL_STCADD 1416
/* NetLabel: add a static label */
#define AUDIT_MAC_UNLBL_STCDEL 1417
/* NetLabel: del a static label */
#define AUDIT_MAC_CALIPSO_ADD 1418
/* NetLabel: add CALIPSO DOI entry */
#define AUDIT_MAC_CALIPSO_DEL 1419
/* NetLabel: del CALIPSO DOI entry */
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
...
...
include/uapi/linux/in6.h
View file @
d011a4d8
...
...
@@ -143,6 +143,7 @@ struct in6_flowlabel_req {
#define IPV6_TLV_PAD1 0
#define IPV6_TLV_PADN 1
#define IPV6_TLV_ROUTERALERT 5
#define IPV6_TLV_CALIPSO 7
/* RFC 5570 */
#define IPV6_TLV_JUMBO 194
#define IPV6_TLV_HAO 201
/* home address option */
...
...
net/dccp/ipv6.c
View file @
d011a4d8
...
...
@@ -216,14 +216,17 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
skb
=
dccp_make_response
(
sk
,
dst
,
req
);
if
(
skb
!=
NULL
)
{
struct
dccp_hdr
*
dh
=
dccp_hdr
(
skb
);
struct
ipv6_txoptions
*
opt
;
dh
->
dccph_checksum
=
dccp_v6_csum_finish
(
skb
,
&
ireq
->
ir_v6_loc_addr
,
&
ireq
->
ir_v6_rmt_addr
);
fl6
.
daddr
=
ireq
->
ir_v6_rmt_addr
;
rcu_read_lock
();
err
=
ip6_xmit
(
sk
,
skb
,
&
fl6
,
rcu_dereference
(
np
->
opt
),
np
->
tclass
);
opt
=
ireq
->
ipv6_opt
;
if
(
!
opt
)
opt
=
rcu_dereference
(
np
->
opt
);
err
=
ip6_xmit
(
sk
,
skb
,
&
fl6
,
opt
,
np
->
tclass
);
rcu_read_unlock
();
err
=
net_xmit_eval
(
err
);
}
...
...
@@ -236,6 +239,7 @@ static int dccp_v6_send_response(const struct sock *sk, struct request_sock *req
static
void
dccp_v6_reqsk_destructor
(
struct
request_sock
*
req
)
{
dccp_feat_list_purge
(
&
dccp_rsk
(
req
)
->
dreq_featneg
);
kfree
(
inet_rsk
(
req
)
->
ipv6_opt
);
kfree_skb
(
inet_rsk
(
req
)
->
pktopts
);
}
...
...
@@ -494,7 +498,9 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,
* Yes, keeping reference count would be much more clever, but we make
* one more one thing there: reattach optmem to newsk.
*/
opt
=
rcu_dereference
(
np
->
opt
);
opt
=
ireq
->
ipv6_opt
;
if
(
!
opt
)
opt
=
rcu_dereference
(
np
->
opt
);
if
(
opt
)
{
opt
=
ipv6_dup_options
(
newsk
,
opt
);
RCU_INIT_POINTER
(
newnp
->
opt
,
opt
);
...
...
net/ipv4/cipso_ipv4.c
View file @
d011a4d8
...
...
@@ -134,76 +134,6 @@ int cipso_v4_rbm_strictvalid = 1;
* Helper Functions
*/
/**
* cipso_v4_bitmap_walk - Walk a bitmap looking for a bit
* @bitmap: the bitmap
* @bitmap_len: length in bits
* @offset: starting offset
* @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
*
* Description:
* Starting at @offset, walk the bitmap from left to right until either the
* desired bit is found or we reach the end. Return the bit offset, -1 if
* not found, or -2 if error.
*/
static
int
cipso_v4_bitmap_walk
(
const
unsigned
char
*
bitmap
,
u32
bitmap_len
,
u32
offset
,
u8
state
)
{
u32
bit_spot
;
u32
byte_offset
;
unsigned
char
bitmask
;
unsigned
char
byte
;
/* gcc always rounds to zero when doing integer division */
byte_offset
=
offset
/
8
;
byte
=
bitmap
[
byte_offset
];
bit_spot
=
offset
;
bitmask
=
0x80
>>
(
offset
%
8
);
while
(
bit_spot
<
bitmap_len
)
{
if
((
state
&&
(
byte
&
bitmask
)
==
bitmask
)
||
(
state
==
0
&&
(
byte
&
bitmask
)
==
0
))
return
bit_spot
;
bit_spot
++
;
bitmask
>>=
1
;
if
(
bitmask
==
0
)
{
byte
=
bitmap
[
++
byte_offset
];
bitmask
=
0x80
;
}
}
return
-
1
;
}
/**
* cipso_v4_bitmap_setbit - Sets a single bit in a bitmap
* @bitmap: the bitmap
* @bit: the bit
* @state: if non-zero, set the bit (1) else clear the bit (0)
*
* Description:
* Set a single bit in the bitmask. Returns zero on success, negative values
* on error.
*/
static
void
cipso_v4_bitmap_setbit
(
unsigned
char
*
bitmap
,
u32
bit
,
u8
state
)
{
u32
byte_spot
;
u8
bitmask
;
/* gcc always rounds to zero when doing integer division */
byte_spot
=
bit
/
8
;
bitmask
=
0x80
>>
(
bit
%
8
);
if
(
state
)
bitmap
[
byte_spot
]
|=
bitmask
;
else
bitmap
[
byte_spot
]
&=
~
bitmask
;
}
/**
* cipso_v4_cache_entry_free - Frees a cache entry
* @entry: the entry to free
...
...
@@ -840,10 +770,10 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
cipso_cat_size
=
doi_def
->
map
.
std
->
cat
.
cipso_size
;
cipso_array
=
doi_def
->
map
.
std
->
cat
.
cipso
;
for
(;;)
{
cat
=
cipso_v4
_bitmap_walk
(
bitmap
,
bitmap_len_bits
,
cat
+
1
,
1
);
cat
=
netlbl
_bitmap_walk
(
bitmap
,
bitmap_len_bits
,
cat
+
1
,
1
);
if
(
cat
<
0
)
break
;
if
(
cat
>=
cipso_cat_size
||
...
...
@@ -909,7 +839,7 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
}
if
(
net_spot
>=
net_clen_bits
)
return
-
ENOSPC
;
cipso_v4
_bitmap_setbit
(
net_cat
,
net_spot
,
1
);
netlbl
_bitmap_setbit
(
net_cat
,
net_spot
,
1
);
if
(
net_spot
>
net_spot_max
)
net_spot_max
=
net_spot
;
...
...
@@ -951,10 +881,10 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
}
for
(;;)
{
net_spot
=
cipso_v4
_bitmap_walk
(
net_cat
,
net_clen_bits
,
net_spot
+
1
,
1
);
net_spot
=
netlbl
_bitmap_walk
(
net_cat
,
net_clen_bits
,
net_spot
+
1
,
1
);
if
(
net_spot
<
0
)
{
if
(
net_spot
==
-
2
)
return
-
EFAULT
;
...
...
net/ipv4/tcp_input.c
View file @
d011a4d8
...
...
@@ -6114,6 +6114,9 @@ struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops,
kmemcheck_annotate_bitfield
(
ireq
,
flags
);
ireq
->
opt
=
NULL
;
#if IS_ENABLED(CONFIG_IPV6)
ireq
->
pktopts
=
NULL
;
#endif
atomic64_set
(
&
ireq
->
ir_cookie
,
0
);
ireq
->
ireq_state
=
TCP_NEW_SYN_RECV
;
write_pnet
(
&
ireq
->
ireq_net
,
sock_net
(
sk_listener
));
...
...
net/ipv6/Makefile
View file @
d011a4d8
...
...
@@ -22,6 +22,7 @@ ipv6-$(CONFIG_NETFILTER) += netfilter.o
ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES)
+=
fib6_rules.o
ipv6-$(CONFIG_PROC_FS)
+=
proc.o
ipv6-$(CONFIG_SYN_COOKIES)
+=
syncookies.o
ipv6-$(CONFIG_NETLABEL)
+=
calipso.o
ipv6-objs
+=
$
(
ipv6-y
)
...
...
net/ipv6/af_inet6.c
View file @
d011a4d8
...
...
@@ -60,6 +60,7 @@
#ifdef CONFIG_IPV6_TUNNEL
#include <net/ip6_tunnel.h>
#endif
#include <net/calipso.h>
#include <asm/uaccess.h>
#include <linux/mroute6.h>
...
...
@@ -977,6 +978,10 @@ static int __init inet6_init(void)
if
(
err
)
goto
pingv6_fail
;
err
=
calipso_init
();
if
(
err
)
goto
calipso_fail
;
#ifdef CONFIG_SYSCTL
err
=
ipv6_sysctl_register
();
if
(
err
)
...
...
@@ -987,8 +992,10 @@ static int __init inet6_init(void)
#ifdef CONFIG_SYSCTL
sysctl_fail:
pingv6
_exit
();
calipso
_exit
();
#endif
calipso_fail:
pingv6_exit
();
pingv6_fail:
ipv6_packet_cleanup
();
ipv6_packet_fail:
...
...
net/ipv6/calipso.c
0 → 100644
View file @
d011a4d8
/*
* CALIPSO - Common Architecture Label IPv6 Security Option
*
* This is an implementation of the CALIPSO protocol as specified in
* RFC 5570.
*
* Authors: Paul Moore <paul.moore@hp.com>
* Huw Davies <huw@codeweavers.com>
*
*/
/* (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008
* (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
*
* 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <linux/init.h>
#include <linux/types.h>
#include <linux/rcupdate.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/jhash.h>
#include <linux/audit.h>
#include <linux/slab.h>
#include <net/ip.h>
#include <net/icmp.h>
#include <net/tcp.h>
#include <net/netlabel.h>
#include <net/calipso.h>
#include <linux/atomic.h>
#include <linux/bug.h>
#include <asm/unaligned.h>
#include <linux/crc-ccitt.h>
/* Maximium size of the calipso option including
* the two-byte TLV header.
*/
#define CALIPSO_OPT_LEN_MAX (2 + 252)
/* Size of the minimum calipso option including
* the two-byte TLV header.
*/
#define CALIPSO_HDR_LEN (2 + 8)
/* Maximium size of the calipso option including
* the two-byte TLV header and upto 3 bytes of
* leading pad and 7 bytes of trailing pad.
*/
#define CALIPSO_OPT_LEN_MAX_WITH_PAD (3 + CALIPSO_OPT_LEN_MAX + 7)
/* Maximium size of u32 aligned buffer required to hold calipso
* option. Max of 3 initial pad bytes starting from buffer + 3.
* i.e. the worst case is when the previous tlv finishes on 4n + 3.
*/
#define CALIPSO_MAX_BUFFER (6 + CALIPSO_OPT_LEN_MAX)
/* List of available DOI definitions */
static
DEFINE_SPINLOCK
(
calipso_doi_list_lock
);
static
LIST_HEAD
(
calipso_doi_list
);
/* Label mapping cache */
int
calipso_cache_enabled
=
1
;
int
calipso_cache_bucketsize
=
10
;
#define CALIPSO_CACHE_BUCKETBITS 7
#define CALIPSO_CACHE_BUCKETS BIT(CALIPSO_CACHE_BUCKETBITS)
#define CALIPSO_CACHE_REORDERLIMIT 10
struct
calipso_map_cache_bkt
{
spinlock_t
lock
;
u32
size
;
struct
list_head
list
;
};
struct
calipso_map_cache_entry
{
u32
hash
;
unsigned
char
*
key
;
size_t
key_len
;
struct
netlbl_lsm_cache
*
lsm_data
;
u32
activity
;
struct
list_head
list
;
};
static
struct
calipso_map_cache_bkt
*
calipso_cache
;
/* Label Mapping Cache Functions
*/
/**
* calipso_cache_entry_free - Frees a cache entry
* @entry: the entry to free
*
* Description:
* This function frees the memory associated with a cache entry including the
* LSM cache data if there are no longer any users, i.e. reference count == 0.
*
*/
static
void
calipso_cache_entry_free
(
struct
calipso_map_cache_entry
*
entry
)
{
if
(
entry
->
lsm_data
)
netlbl_secattr_cache_free
(
entry
->
lsm_data
);
kfree
(
entry
->
key
);
kfree
(
entry
);
}
/**
* calipso_map_cache_hash - Hashing function for the CALIPSO cache
* @key: the hash key
* @key_len: the length of the key in bytes
*
* Description:
* The CALIPSO tag hashing function. Returns a 32-bit hash value.
*
*/
static
u32
calipso_map_cache_hash
(
const
unsigned
char
*
key
,
u32
key_len
)
{
return
jhash
(
key
,
key_len
,
0
);
}
/**
* calipso_cache_init - Initialize the CALIPSO cache
*
* Description:
* Initializes the CALIPSO label mapping cache, this function should be called
* before any of the other functions defined in this file. Returns zero on
* success, negative values on error.
*
*/
static
int
__init
calipso_cache_init
(
void
)
{
u32
iter
;
calipso_cache
=
kcalloc
(
CALIPSO_CACHE_BUCKETS
,
sizeof
(
struct
calipso_map_cache_bkt
),
GFP_KERNEL
);
if
(
!
calipso_cache
)
return
-
ENOMEM
;
for
(
iter
=
0
;
iter
<
CALIPSO_CACHE_BUCKETS
;
iter
++
)
{
spin_lock_init
(
&
calipso_cache
[
iter
].
lock
);
calipso_cache
[
iter
].
size
=
0
;
INIT_LIST_HEAD
(
&
calipso_cache
[
iter
].
list
);
}
return
0
;
}
/**
* calipso_cache_invalidate - Invalidates the current CALIPSO cache
*
* Description:
* Invalidates and frees any entries in the CALIPSO cache. Returns zero on
* success and negative values on failure.
*
*/
static
void
calipso_cache_invalidate
(
void
)
{
struct
calipso_map_cache_entry
*
entry
,
*
tmp_entry
;
u32
iter
;
for
(
iter
=
0
;
iter
<
CALIPSO_CACHE_BUCKETS
;
iter
++
)
{
spin_lock_bh
(
&
calipso_cache
[
iter
].
lock
);
list_for_each_entry_safe
(
entry
,
tmp_entry
,
&
calipso_cache
[
iter
].
list
,
list
)
{
list_del
(
&
entry
->
list
);
calipso_cache_entry_free
(
entry
);
}
calipso_cache
[
iter
].
size
=
0
;
spin_unlock_bh
(
&
calipso_cache
[
iter
].
lock
);
}
}
/**
* calipso_cache_check - Check the CALIPSO cache for a label mapping
* @key: the buffer to check
* @key_len: buffer length in bytes
* @secattr: the security attribute struct to use
*
* Description:
* This function checks the cache to see if a label mapping already exists for
* the given key. If there is a match then the cache is adjusted and the
* @secattr struct is populated with the correct LSM security attributes. The
* cache is adjusted in the following manner if the entry is not already the
* first in the cache bucket:
*
* 1. The cache entry's activity counter is incremented
* 2. The previous (higher ranking) entry's activity counter is decremented
* 3. If the difference between the two activity counters is geater than
* CALIPSO_CACHE_REORDERLIMIT the two entries are swapped
*
* Returns zero on success, -ENOENT for a cache miss, and other negative values
* on error.
*
*/
static
int
calipso_cache_check
(
const
unsigned
char
*
key
,
u32
key_len
,
struct
netlbl_lsm_secattr
*
secattr
)
{
u32
bkt
;
struct
calipso_map_cache_entry
*
entry
;
struct
calipso_map_cache_entry
*
prev_entry
=
NULL
;
u32
hash
;
if
(
!
calipso_cache_enabled
)
return
-
ENOENT
;
hash
=
calipso_map_cache_hash
(
key
,
key_len
);
bkt
=
hash
&
(
CALIPSO_CACHE_BUCKETS
-
1
);
spin_lock_bh
(
&
calipso_cache
[
bkt
].
lock
);
list_for_each_entry
(
entry
,
&
calipso_cache
[
bkt
].
list
,
list
)
{
if
(
entry
->
hash
==
hash
&&
entry
->
key_len
==
key_len
&&
memcmp
(
entry
->
key
,
key
,
key_len
)
==
0
)
{
entry
->
activity
+=
1
;
atomic_inc
(
&
entry
->
lsm_data
->
refcount
);
secattr
->
cache
=
entry
->
lsm_data
;
secattr
->
flags
|=
NETLBL_SECATTR_CACHE
;
secattr
->
type
=
NETLBL_NLTYPE_CALIPSO
;
if
(
!
prev_entry
)
{
spin_unlock_bh
(
&
calipso_cache
[
bkt
].
lock
);
return
0
;
}
if
(
prev_entry
->
activity
>
0
)
prev_entry
->
activity
-=
1
;
if
(
entry
->
activity
>
prev_entry
->
activity
&&
entry
->
activity
-
prev_entry
->
activity
>
CALIPSO_CACHE_REORDERLIMIT
)
{
__list_del
(
entry
->
list
.
prev
,
entry
->
list
.
next
);
__list_add
(
&
entry
->
list
,
prev_entry
->
list
.
prev
,
&
prev_entry
->
list
);
}
spin_unlock_bh
(
&
calipso_cache
[
bkt
].
lock
);
return
0
;
}
prev_entry
=
entry
;
}
spin_unlock_bh
(
&
calipso_cache
[
bkt
].
lock
);
return
-
ENOENT
;
}
/**
* calipso_cache_add - Add an entry to the CALIPSO cache
* @calipso_ptr: the CALIPSO option
* @secattr: the packet's security attributes
*
* Description:
* Add a new entry into the CALIPSO label mapping cache. Add the new entry to
* head of the cache bucket's list, if the cache bucket is out of room remove
* the last entry in the list first. It is important to note that there is
* currently no checking for duplicate keys. Returns zero on success,
* negative values on failure. The key stored starts at calipso_ptr + 2,
* i.e. the type and length bytes are not stored, this corresponds to
* calipso_ptr[1] bytes of data.
*
*/
static
int
calipso_cache_add
(
const
unsigned
char
*
calipso_ptr
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
=
-
EPERM
;
u32
bkt
;
struct
calipso_map_cache_entry
*
entry
=
NULL
;
struct
calipso_map_cache_entry
*
old_entry
=
NULL
;
u32
calipso_ptr_len
;
if
(
!
calipso_cache_enabled
||
calipso_cache_bucketsize
<=
0
)
return
0
;
calipso_ptr_len
=
calipso_ptr
[
1
];
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_ATOMIC
);
if
(
!
entry
)
return
-
ENOMEM
;
entry
->
key
=
kmemdup
(
calipso_ptr
+
2
,
calipso_ptr_len
,
GFP_ATOMIC
);
if
(
!
entry
->
key
)
{
ret_val
=
-
ENOMEM
;
goto
cache_add_failure
;
}
entry
->
key_len
=
calipso_ptr_len
;
entry
->
hash
=
calipso_map_cache_hash
(
calipso_ptr
,
calipso_ptr_len
);
atomic_inc
(
&
secattr
->
cache
->
refcount
);
entry
->
lsm_data
=
secattr
->
cache
;
bkt
=
entry
->
hash
&
(
CALIPSO_CACHE_BUCKETS
-
1
);
spin_lock_bh
(
&
calipso_cache
[
bkt
].
lock
);
if
(
calipso_cache
[
bkt
].
size
<
calipso_cache_bucketsize
)
{
list_add
(
&
entry
->
list
,
&
calipso_cache
[
bkt
].
list
);
calipso_cache
[
bkt
].
size
+=
1
;
}
else
{
old_entry
=
list_entry
(
calipso_cache
[
bkt
].
list
.
prev
,
struct
calipso_map_cache_entry
,
list
);
list_del
(
&
old_entry
->
list
);
list_add
(
&
entry
->
list
,
&
calipso_cache
[
bkt
].
list
);
calipso_cache_entry_free
(
old_entry
);
}
spin_unlock_bh
(
&
calipso_cache
[
bkt
].
lock
);
return
0
;
cache_add_failure:
if
(
entry
)
calipso_cache_entry_free
(
entry
);
return
ret_val
;
}
/* DOI List Functions
*/
/**
* calipso_doi_search - Searches for a DOI definition
* @doi: the DOI to search for
*
* Description:
* Search the DOI definition list for a DOI definition with a DOI value that
* matches @doi. The caller is responsible for calling rcu_read_[un]lock().
* Returns a pointer to the DOI definition on success and NULL on failure.
*/
static
struct
calipso_doi
*
calipso_doi_search
(
u32
doi
)
{
struct
calipso_doi
*
iter
;
list_for_each_entry_rcu
(
iter
,
&
calipso_doi_list
,
list
)
if
(
iter
->
doi
==
doi
&&
atomic_read
(
&
iter
->
refcount
))
return
iter
;
return
NULL
;
}
/**
* calipso_doi_add - Add a new DOI to the CALIPSO protocol engine
* @doi_def: the DOI structure
* @audit_info: NetLabel audit information
*
* Description:
* The caller defines a new DOI for use by the CALIPSO engine and calls this
* function to add it to the list of acceptable domains. The caller must
* ensure that the mapping table specified in @doi_def->map meets all of the
* requirements of the mapping type (see calipso.h for details). Returns
* zero on success and non-zero on failure.
*
*/
static
int
calipso_doi_add
(
struct
calipso_doi
*
doi_def
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
=
-
EINVAL
;
u32
doi
;
u32
doi_type
;
struct
audit_buffer
*
audit_buf
;
doi
=
doi_def
->
doi
;
doi_type
=
doi_def
->
type
;
if
(
doi_def
->
doi
==
CALIPSO_DOI_UNKNOWN
)
goto
doi_add_return
;
atomic_set
(
&
doi_def
->
refcount
,
1
);
spin_lock
(
&
calipso_doi_list_lock
);
if
(
calipso_doi_search
(
doi_def
->
doi
))
{
spin_unlock
(
&
calipso_doi_list_lock
);
ret_val
=
-
EEXIST
;
goto
doi_add_return
;
}
list_add_tail_rcu
(
&
doi_def
->
list
,
&
calipso_doi_list
);
spin_unlock
(
&
calipso_doi_list_lock
);
ret_val
=
0
;
doi_add_return:
audit_buf
=
netlbl_audit_start
(
AUDIT_MAC_CALIPSO_ADD
,
audit_info
);
if
(
audit_buf
)
{
const
char
*
type_str
;
switch
(
doi_type
)
{
case
CALIPSO_MAP_PASS
:
type_str
=
"pass"
;
break
;
default:
type_str
=
"(unknown)"
;
}
audit_log_format
(
audit_buf
,
" calipso_doi=%u calipso_type=%s res=%u"
,
doi
,
type_str
,
ret_val
==
0
?
1
:
0
);
audit_log_end
(
audit_buf
);
}
return
ret_val
;
}
/**
* calipso_doi_free - Frees a DOI definition
* @doi_def: the DOI definition
*
* Description:
* This function frees all of the memory associated with a DOI definition.
*
*/
static
void
calipso_doi_free
(
struct
calipso_doi
*
doi_def
)
{
kfree
(
doi_def
);
}
/**
* calipso_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
calipso_doi_free_rcu
(
struct
rcu_head
*
entry
)
{
struct
calipso_doi
*
doi_def
;
doi_def
=
container_of
(
entry
,
struct
calipso_doi
,
rcu
);
calipso_doi_free
(
doi_def
);
}
/**
* calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine
* @doi: the DOI value
* @audit_secid: the LSM secid to use in the audit message
*
* Description:
* Removes a DOI definition from the CALIPSO 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.
*
*/
static
int
calipso_doi_remove
(
u32
doi
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
;
struct
calipso_doi
*
doi_def
;
struct
audit_buffer
*
audit_buf
;
spin_lock
(
&
calipso_doi_list_lock
);
doi_def
=
calipso_doi_search
(
doi
);
if
(
!
doi_def
)
{
spin_unlock
(
&
calipso_doi_list_lock
);
ret_val
=
-
ENOENT
;
goto
doi_remove_return
;
}
if
(
!
atomic_dec_and_test
(
&
doi_def
->
refcount
))
{
spin_unlock
(
&
calipso_doi_list_lock
);
ret_val
=
-
EBUSY
;
goto
doi_remove_return
;
}
list_del_rcu
(
&
doi_def
->
list
);
spin_unlock
(
&
calipso_doi_list_lock
);
call_rcu
(
&
doi_def
->
rcu
,
calipso_doi_free_rcu
);
ret_val
=
0
;
doi_remove_return:
audit_buf
=
netlbl_audit_start
(
AUDIT_MAC_CALIPSO_DEL
,
audit_info
);
if
(
audit_buf
)
{
audit_log_format
(
audit_buf
,
" calipso_doi=%u res=%u"
,
doi
,
ret_val
==
0
?
1
:
0
);
audit_log_end
(
audit_buf
);
}
return
ret_val
;
}
/**
* calipso_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
* calipso_doi_putdef() is called when the caller is done.
*
*/
static
struct
calipso_doi
*
calipso_doi_getdef
(
u32
doi
)
{
struct
calipso_doi
*
doi_def
;
rcu_read_lock
();
doi_def
=
calipso_doi_search
(
doi
);
if
(
!
doi_def
)
goto
doi_getdef_return
;
if
(
!
atomic_inc_not_zero
(
&
doi_def
->
refcount
))
doi_def
=
NULL
;
doi_getdef_return:
rcu_read_unlock
();
return
doi_def
;
}
/**
* calipso_doi_putdef - Releases a reference for the given DOI definition
* @doi_def: the DOI definition
*
* Description:
* Releases a DOI definition reference obtained from calipso_doi_getdef().
*
*/
static
void
calipso_doi_putdef
(
struct
calipso_doi
*
doi_def
)
{
if
(
!
doi_def
)
return
;
if
(
!
atomic_dec_and_test
(
&
doi_def
->
refcount
))
return
;
spin_lock
(
&
calipso_doi_list_lock
);
list_del_rcu
(
&
doi_def
->
list
);
spin_unlock
(
&
calipso_doi_list_lock
);
call_rcu
(
&
doi_def
->
rcu
,
calipso_doi_free_rcu
);
}
/**
* calipso_doi_walk - Iterate through the DOI definitions
* @skip_cnt: skip past this number of DOI definitions, updated
* @callback: callback for each DOI definition
* @cb_arg: argument for the callback function
*
* Description:
* Iterate over the DOI definition list, skipping the first @skip_cnt entries.
* For each entry call @callback, if @callback returns a negative value stop
* 'walking' through the list and return. Updates the value in @skip_cnt upon
* return. Returns zero on success, negative values on failure.
*
*/
static
int
calipso_doi_walk
(
u32
*
skip_cnt
,
int
(
*
callback
)(
struct
calipso_doi
*
doi_def
,
void
*
arg
),
void
*
cb_arg
)
{
int
ret_val
=
-
ENOENT
;
u32
doi_cnt
=
0
;
struct
calipso_doi
*
iter_doi
;
rcu_read_lock
();
list_for_each_entry_rcu
(
iter_doi
,
&
calipso_doi_list
,
list
)
if
(
atomic_read
(
&
iter_doi
->
refcount
)
>
0
)
{
if
(
doi_cnt
++
<
*
skip_cnt
)
continue
;
ret_val
=
callback
(
iter_doi
,
cb_arg
);
if
(
ret_val
<
0
)
{
doi_cnt
--
;
goto
doi_walk_return
;
}
}
doi_walk_return:
rcu_read_unlock
();
*
skip_cnt
=
doi_cnt
;
return
ret_val
;
}
/**
* calipso_validate - Validate a CALIPSO option
* @skb: the packet
* @option: the start of the option
*
* Description:
* This routine is called to validate a CALIPSO option.
* If the option is valid then %true is returned, otherwise
* %false is returned.
*
* The caller should have already checked that the length of the
* option (including the TLV header) is >= 10 and that the catmap
* length is consistent with the option length.
*
* We leave checks on the level and categories to the socket layer.
*/
bool
calipso_validate
(
const
struct
sk_buff
*
skb
,
const
unsigned
char
*
option
)
{
struct
calipso_doi
*
doi_def
;
bool
ret_val
;
u16
crc
,
len
=
option
[
1
]
+
2
;
static
const
u8
zero
[
2
];
/* The original CRC runs over the option including the TLV header
* with the CRC-16 field (at offset 8) zeroed out. */
crc
=
crc_ccitt
(
0xffff
,
option
,
8
);
crc
=
crc_ccitt
(
crc
,
zero
,
sizeof
(
zero
));
if
(
len
>
10
)
crc
=
crc_ccitt
(
crc
,
option
+
10
,
len
-
10
);
crc
=
~
crc
;
if
(
option
[
8
]
!=
(
crc
&
0xff
)
||
option
[
9
]
!=
((
crc
>>
8
)
&
0xff
))
return
false
;
rcu_read_lock
();
doi_def
=
calipso_doi_search
(
get_unaligned_be32
(
option
+
2
));
ret_val
=
!!
doi_def
;
rcu_read_unlock
();
return
ret_val
;
}
/**
* calipso_map_cat_hton - Perform a category mapping from host to network
* @doi_def: the DOI definition
* @secattr: the security attributes
* @net_cat: the zero'd out category bitmap in network/CALIPSO format
* @net_cat_len: the length of the CALIPSO bitmap in bytes
*
* Description:
* Perform a label mapping to translate a local MLS category bitmap to the
* correct CALIPSO bitmap using the given DOI definition. Returns the minimum
* size in bytes of the network bitmap on success, negative values otherwise.
*
*/
static
int
calipso_map_cat_hton
(
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
,
unsigned
char
*
net_cat
,
u32
net_cat_len
)
{
int
spot
=
-
1
;
u32
net_spot_max
=
0
;
u32
net_clen_bits
=
net_cat_len
*
8
;
for
(;;)
{
spot
=
netlbl_catmap_walk
(
secattr
->
attr
.
mls
.
cat
,
spot
+
1
);
if
(
spot
<
0
)
break
;
if
(
spot
>=
net_clen_bits
)
return
-
ENOSPC
;
netlbl_bitmap_setbit
(
net_cat
,
spot
,
1
);
if
(
spot
>
net_spot_max
)
net_spot_max
=
spot
;
}
return
(
net_spot_max
/
32
+
1
)
*
4
;
}
/**
* calipso_map_cat_ntoh - Perform a category mapping from network to host
* @doi_def: the DOI definition
* @net_cat: the category bitmap in network/CALIPSO format
* @net_cat_len: the length of the CALIPSO bitmap in bytes
* @secattr: the security attributes
*
* Description:
* Perform a label mapping to translate a CALIPSO bitmap to the correct local
* MLS category bitmap using the given DOI definition. Returns zero on
* success, negative values on failure.
*
*/
static
int
calipso_map_cat_ntoh
(
const
struct
calipso_doi
*
doi_def
,
const
unsigned
char
*
net_cat
,
u32
net_cat_len
,
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
;
int
spot
=
-
1
;
u32
net_clen_bits
=
net_cat_len
*
8
;
for
(;;)
{
spot
=
netlbl_bitmap_walk
(
net_cat
,
net_clen_bits
,
spot
+
1
,
1
);
if
(
spot
<
0
)
{
if
(
spot
==
-
2
)
return
-
EFAULT
;
return
0
;
}
ret_val
=
netlbl_catmap_setbit
(
&
secattr
->
attr
.
mls
.
cat
,
spot
,
GFP_ATOMIC
);
if
(
ret_val
!=
0
)
return
ret_val
;
}
return
-
EINVAL
;
}
/**
* calipso_pad_write - Writes pad bytes in TLV format
* @buf: the buffer
* @offset: offset from start of buffer to write padding
* @count: number of pad bytes to write
*
* Description:
* Write @count bytes of TLV padding into @buffer starting at offset @offset.
* @count should be less than 8 - see RFC 4942.
*
*/
static
int
calipso_pad_write
(
unsigned
char
*
buf
,
unsigned
int
offset
,
unsigned
int
count
)
{
if
(
WARN_ON_ONCE
(
count
>=
8
))
return
-
EINVAL
;
switch
(
count
)
{
case
0
:
break
;
case
1
:
buf
[
offset
]
=
IPV6_TLV_PAD1
;
break
;
default:
buf
[
offset
]
=
IPV6_TLV_PADN
;
buf
[
offset
+
1
]
=
count
-
2
;
if
(
count
>
2
)
memset
(
buf
+
offset
+
2
,
0
,
count
-
2
);
break
;
}
return
0
;
}
/**
* calipso_genopt - Generate a CALIPSO option
* @buf: the option buffer
* @start: offset from which to write
* @buf_len: the size of opt_buf
* @doi_def: the CALIPSO DOI to use
* @secattr: the security attributes
*
* Description:
* Generate a CALIPSO option using the DOI definition and security attributes
* passed to the function. This also generates upto three bytes of leading
* padding that ensures that the option is 4n + 2 aligned. It returns the
* number of bytes written (including any initial padding).
*/
static
int
calipso_genopt
(
unsigned
char
*
buf
,
u32
start
,
u32
buf_len
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
;
u32
len
,
pad
;
u16
crc
;
static
const
unsigned
char
padding
[
4
]
=
{
2
,
1
,
0
,
3
};
unsigned
char
*
calipso
;
/* CALIPSO has 4n + 2 alignment */
pad
=
padding
[
start
&
3
];
if
(
buf_len
<=
start
+
pad
+
CALIPSO_HDR_LEN
)
return
-
ENOSPC
;
if
((
secattr
->
flags
&
NETLBL_SECATTR_MLS_LVL
)
==
0
)
return
-
EPERM
;
len
=
CALIPSO_HDR_LEN
;
if
(
secattr
->
flags
&
NETLBL_SECATTR_MLS_CAT
)
{
ret_val
=
calipso_map_cat_hton
(
doi_def
,
secattr
,
buf
+
start
+
pad
+
len
,
buf_len
-
start
-
pad
-
len
);
if
(
ret_val
<
0
)
return
ret_val
;
len
+=
ret_val
;
}
calipso_pad_write
(
buf
,
start
,
pad
);
calipso
=
buf
+
start
+
pad
;
calipso
[
0
]
=
IPV6_TLV_CALIPSO
;
calipso
[
1
]
=
len
-
2
;
*
(
__be32
*
)(
calipso
+
2
)
=
htonl
(
doi_def
->
doi
);
calipso
[
6
]
=
(
len
-
CALIPSO_HDR_LEN
)
/
4
;
calipso
[
7
]
=
secattr
->
attr
.
mls
.
lvl
,
crc
=
~
crc_ccitt
(
0xffff
,
calipso
,
len
);
calipso
[
8
]
=
crc
&
0xff
;
calipso
[
9
]
=
(
crc
>>
8
)
&
0xff
;
return
pad
+
len
;
}
/* Hop-by-hop hdr helper functions
*/
/**
* calipso_opt_update - Replaces socket's hop options with a new set
* @sk: the socket
* @hop: new hop options
*
* Description:
* Replaces @sk's hop options with @hop. @hop may be NULL to leave
* the socket with no hop options.
*
*/
static
int
calipso_opt_update
(
struct
sock
*
sk
,
struct
ipv6_opt_hdr
*
hop
)
{
struct
ipv6_txoptions
*
old
=
txopt_get
(
inet6_sk
(
sk
)),
*
txopts
;
txopts
=
ipv6_renew_options_kern
(
sk
,
old
,
IPV6_HOPOPTS
,
hop
,
hop
?
ipv6_optlen
(
hop
)
:
0
);
txopt_put
(
old
);
if
(
IS_ERR
(
txopts
))
return
PTR_ERR
(
txopts
);
txopts
=
ipv6_update_options
(
sk
,
txopts
);
if
(
txopts
)
{
atomic_sub
(
txopts
->
tot_len
,
&
sk
->
sk_omem_alloc
);
txopt_put
(
txopts
);
}
return
0
;
}
/**
* calipso_tlv_len - Returns the length of the TLV
* @opt: the option header
* @offset: offset of the TLV within the header
*
* Description:
* Returns the length of the TLV option at offset @offset within
* the option header @opt. Checks that the entire TLV fits inside
* the option header, returns a negative value if this is not the case.
*/
static
int
calipso_tlv_len
(
struct
ipv6_opt_hdr
*
opt
,
unsigned
int
offset
)
{
unsigned
char
*
tlv
=
(
unsigned
char
*
)
opt
;
unsigned
int
opt_len
=
ipv6_optlen
(
opt
),
tlv_len
;
if
(
offset
<
sizeof
(
*
opt
)
||
offset
>=
opt_len
)
return
-
EINVAL
;
if
(
tlv
[
offset
]
==
IPV6_TLV_PAD1
)
return
1
;
if
(
offset
+
1
>=
opt_len
)
return
-
EINVAL
;
tlv_len
=
tlv
[
offset
+
1
]
+
2
;
if
(
offset
+
tlv_len
>
opt_len
)
return
-
EINVAL
;
return
tlv_len
;
}
/**
* calipso_opt_find - Finds the CALIPSO option in an IPv6 hop options header
* @hop: the hop options header
* @start: on return holds the offset of any leading padding
* @end: on return holds the offset of the first non-pad TLV after CALIPSO
*
* Description:
* Finds the space occupied by a CALIPSO option (including any leading and
* trailing padding).
*
* If a CALIPSO option exists set @start and @end to the
* offsets within @hop of the start of padding before the first
* CALIPSO option and the end of padding after the first CALIPSO
* option. In this case the function returns 0.
*
* In the absence of a CALIPSO option, @start and @end will be
* set to the start and end of any trailing padding in the header.
* This is useful when appending a new option, as the caller may want
* to overwrite some of this padding. In this case the function will
* return -ENOENT.
*/
static
int
calipso_opt_find
(
struct
ipv6_opt_hdr
*
hop
,
unsigned
int
*
start
,
unsigned
int
*
end
)
{
int
ret_val
=
-
ENOENT
,
tlv_len
;
unsigned
int
opt_len
,
offset
,
offset_s
=
0
,
offset_e
=
0
;
unsigned
char
*
opt
=
(
unsigned
char
*
)
hop
;
opt_len
=
ipv6_optlen
(
hop
);
offset
=
sizeof
(
*
hop
);
while
(
offset
<
opt_len
)
{
tlv_len
=
calipso_tlv_len
(
hop
,
offset
);
if
(
tlv_len
<
0
)
return
tlv_len
;
switch
(
opt
[
offset
])
{
case
IPV6_TLV_PAD1
:
case
IPV6_TLV_PADN
:
if
(
offset_e
)
offset_e
=
offset
;
break
;
case
IPV6_TLV_CALIPSO
:
ret_val
=
0
;
offset_e
=
offset
;
break
;
default:
if
(
offset_e
==
0
)
offset_s
=
offset
;
else
goto
out
;
}
offset
+=
tlv_len
;
}
out:
if
(
offset_s
)
*
start
=
offset_s
+
calipso_tlv_len
(
hop
,
offset_s
);
else
*
start
=
sizeof
(
*
hop
);
if
(
offset_e
)
*
end
=
offset_e
+
calipso_tlv_len
(
hop
,
offset_e
);
else
*
end
=
opt_len
;
return
ret_val
;
}
/**
* calipso_opt_insert - Inserts a CALIPSO option into an IPv6 hop opt hdr
* @hop: the original hop options header
* @doi_def: the CALIPSO DOI to use
* @secattr: the specific security attributes of the socket
*
* Description:
* Creates a new hop options header based on @hop with a
* CALIPSO option added to it. If @hop already contains a CALIPSO
* option this is overwritten, otherwise the new option is appended
* after any existing options. If @hop is NULL then the new header
* will contain just the CALIPSO option and any needed padding.
*
*/
static
struct
ipv6_opt_hdr
*
calipso_opt_insert
(
struct
ipv6_opt_hdr
*
hop
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
unsigned
int
start
,
end
,
buf_len
,
pad
,
hop_len
;
struct
ipv6_opt_hdr
*
new
;
int
ret_val
;
if
(
hop
)
{
hop_len
=
ipv6_optlen
(
hop
);
ret_val
=
calipso_opt_find
(
hop
,
&
start
,
&
end
);
if
(
ret_val
&&
ret_val
!=
-
ENOENT
)
return
ERR_PTR
(
ret_val
);
}
else
{
hop_len
=
0
;
start
=
sizeof
(
*
hop
);
end
=
0
;
}
buf_len
=
hop_len
+
start
-
end
+
CALIPSO_OPT_LEN_MAX_WITH_PAD
;
new
=
kzalloc
(
buf_len
,
GFP_ATOMIC
);
if
(
!
new
)
return
ERR_PTR
(
-
ENOMEM
);
if
(
start
>
sizeof
(
*
hop
))
memcpy
(
new
,
hop
,
start
);
ret_val
=
calipso_genopt
((
unsigned
char
*
)
new
,
start
,
buf_len
,
doi_def
,
secattr
);
if
(
ret_val
<
0
)
return
ERR_PTR
(
ret_val
);
buf_len
=
start
+
ret_val
;
/* At this point buf_len aligns to 4n, so (buf_len & 4) pads to 8n */
pad
=
((
buf_len
&
4
)
+
(
end
&
7
))
&
7
;
calipso_pad_write
((
unsigned
char
*
)
new
,
buf_len
,
pad
);
buf_len
+=
pad
;
if
(
end
!=
hop_len
)
{
memcpy
((
char
*
)
new
+
buf_len
,
(
char
*
)
hop
+
end
,
hop_len
-
end
);
buf_len
+=
hop_len
-
end
;
}
new
->
nexthdr
=
0
;
new
->
hdrlen
=
buf_len
/
8
-
1
;
return
new
;
}
/**
* calipso_opt_del - Removes the CALIPSO option from an option header
* @hop: the original header
* @new: the new header
*
* Description:
* Creates a new header based on @hop without any CALIPSO option. If @hop
* doesn't contain a CALIPSO option it returns -ENOENT. If @hop contains
* no other non-padding options, it returns zero with @new set to NULL.
* Otherwise it returns zero, creates a new header without the CALIPSO
* option (and removing as much padding as possible) and returns with
* @new set to that header.
*
*/
static
int
calipso_opt_del
(
struct
ipv6_opt_hdr
*
hop
,
struct
ipv6_opt_hdr
**
new
)
{
int
ret_val
;
unsigned
int
start
,
end
,
delta
,
pad
,
hop_len
;
ret_val
=
calipso_opt_find
(
hop
,
&
start
,
&
end
);
if
(
ret_val
)
return
ret_val
;
hop_len
=
ipv6_optlen
(
hop
);
if
(
start
==
sizeof
(
*
hop
)
&&
end
==
hop_len
)
{
/* There's no other option in the header so return NULL */
*
new
=
NULL
;
return
0
;
}
delta
=
(
end
-
start
)
&
~
7
;
*
new
=
kzalloc
(
hop_len
-
delta
,
GFP_ATOMIC
);
if
(
!*
new
)
return
-
ENOMEM
;
memcpy
(
*
new
,
hop
,
start
);
(
*
new
)
->
hdrlen
-=
delta
/
8
;
pad
=
(
end
-
start
)
&
7
;
calipso_pad_write
((
unsigned
char
*
)
*
new
,
start
,
pad
);
if
(
end
!=
hop_len
)
memcpy
((
char
*
)
*
new
+
start
+
pad
,
(
char
*
)
hop
+
end
,
hop_len
-
end
);
return
0
;
}
/**
* calipso_opt_getattr - Get the security attributes from a memory block
* @calipso: the CALIPSO option
* @secattr: the security attributes
*
* Description:
* Inspect @calipso and return the security attributes in @secattr.
* Returns zero on success and negative values on failure.
*
*/
static
int
calipso_opt_getattr
(
const
unsigned
char
*
calipso
,
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
=
-
ENOMSG
;
u32
doi
,
len
=
calipso
[
1
],
cat_len
=
calipso
[
6
]
*
4
;
struct
calipso_doi
*
doi_def
;
if
(
cat_len
+
8
>
len
)
return
-
EINVAL
;
if
(
calipso_cache_check
(
calipso
+
2
,
calipso
[
1
],
secattr
)
==
0
)
return
0
;
doi
=
get_unaligned_be32
(
calipso
+
2
);
rcu_read_lock
();
doi_def
=
calipso_doi_search
(
doi
);
if
(
!
doi_def
)
goto
getattr_return
;
secattr
->
attr
.
mls
.
lvl
=
calipso
[
7
];
secattr
->
flags
|=
NETLBL_SECATTR_MLS_LVL
;
if
(
cat_len
)
{
ret_val
=
calipso_map_cat_ntoh
(
doi_def
,
calipso
+
10
,
cat_len
,
secattr
);
if
(
ret_val
!=
0
)
{
netlbl_catmap_free
(
secattr
->
attr
.
mls
.
cat
);
goto
getattr_return
;
}
secattr
->
flags
|=
NETLBL_SECATTR_MLS_CAT
;
}
secattr
->
type
=
NETLBL_NLTYPE_CALIPSO
;
getattr_return:
rcu_read_unlock
();
return
ret_val
;
}
/* sock functions.
*/
/**
* calipso_sock_getattr - Get the security attributes from a sock
* @sk: the sock
* @secattr: the security attributes
*
* Description:
* Query @sk to see if there is a CALIPSO option attached to the sock and if
* there is return the CALIPSO security attributes in @secattr. This function
* requires that @sk be locked, or privately held, but it does not do any
* locking itself. Returns zero on success and negative values on failure.
*
*/
static
int
calipso_sock_getattr
(
struct
sock
*
sk
,
struct
netlbl_lsm_secattr
*
secattr
)
{
struct
ipv6_opt_hdr
*
hop
;
int
opt_len
,
len
,
ret_val
=
-
ENOMSG
,
offset
;
unsigned
char
*
opt
;
struct
ipv6_txoptions
*
txopts
=
txopt_get
(
inet6_sk
(
sk
));
if
(
!
txopts
||
!
txopts
->
hopopt
)
goto
done
;
hop
=
txopts
->
hopopt
;
opt
=
(
unsigned
char
*
)
hop
;
opt_len
=
ipv6_optlen
(
hop
);
offset
=
sizeof
(
*
hop
);
while
(
offset
<
opt_len
)
{
len
=
calipso_tlv_len
(
hop
,
offset
);
if
(
len
<
0
)
{
ret_val
=
len
;
goto
done
;
}
switch
(
opt
[
offset
])
{
case
IPV6_TLV_CALIPSO
:
if
(
len
<
CALIPSO_HDR_LEN
)
ret_val
=
-
EINVAL
;
else
ret_val
=
calipso_opt_getattr
(
&
opt
[
offset
],
secattr
);
goto
done
;
default:
offset
+=
len
;
break
;
}
}
done:
txopt_put
(
txopts
);
return
ret_val
;
}
/**
* calipso_sock_setattr - Add a CALIPSO option to a socket
* @sk: the socket
* @doi_def: the CALIPSO DOI to use
* @secattr: the specific security attributes of the socket
*
* Description:
* Set the CALIPSO 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.
*
*/
static
int
calipso_sock_setattr
(
struct
sock
*
sk
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
;
struct
ipv6_opt_hdr
*
old
,
*
new
;
struct
ipv6_txoptions
*
txopts
=
txopt_get
(
inet6_sk
(
sk
));
old
=
NULL
;
if
(
txopts
)
old
=
txopts
->
hopopt
;
new
=
calipso_opt_insert
(
old
,
doi_def
,
secattr
);
txopt_put
(
txopts
);
if
(
IS_ERR
(
new
))
return
PTR_ERR
(
new
);
ret_val
=
calipso_opt_update
(
sk
,
new
);
kfree
(
new
);
return
ret_val
;
}
/**
* calipso_sock_delattr - Delete the CALIPSO option from a socket
* @sk: the socket
*
* Description:
* Removes the CALIPSO option from a socket, if present.
*
*/
static
void
calipso_sock_delattr
(
struct
sock
*
sk
)
{
struct
ipv6_opt_hdr
*
new_hop
;
struct
ipv6_txoptions
*
txopts
=
txopt_get
(
inet6_sk
(
sk
));
if
(
!
txopts
||
!
txopts
->
hopopt
)
goto
done
;
if
(
calipso_opt_del
(
txopts
->
hopopt
,
&
new_hop
))
goto
done
;
calipso_opt_update
(
sk
,
new_hop
);
kfree
(
new_hop
);
done:
txopt_put
(
txopts
);
}
/* request sock functions.
*/
/**
* calipso_req_setattr - Add a CALIPSO option to a connection request socket
* @req: the connection request socket
* @doi_def: the CALIPSO DOI to use
* @secattr: the specific security attributes of the socket
*
* Description:
* Set the CALIPSO option on the given socket using the DOI definition and
* security attributes passed to the function. Returns zero on success and
* negative values on failure.
*
*/
static
int
calipso_req_setattr
(
struct
request_sock
*
req
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
struct
ipv6_txoptions
*
txopts
;
struct
inet_request_sock
*
req_inet
=
inet_rsk
(
req
);
struct
ipv6_opt_hdr
*
old
,
*
new
;
struct
sock
*
sk
=
sk_to_full_sk
(
req_to_sk
(
req
));
if
(
req_inet
->
ipv6_opt
&&
req_inet
->
ipv6_opt
->
hopopt
)
old
=
req_inet
->
ipv6_opt
->
hopopt
;
else
old
=
NULL
;
new
=
calipso_opt_insert
(
old
,
doi_def
,
secattr
);
if
(
IS_ERR
(
new
))
return
PTR_ERR
(
new
);
txopts
=
ipv6_renew_options_kern
(
sk
,
req_inet
->
ipv6_opt
,
IPV6_HOPOPTS
,
new
,
new
?
ipv6_optlen
(
new
)
:
0
);
kfree
(
new
);
if
(
IS_ERR
(
txopts
))
return
PTR_ERR
(
txopts
);
txopts
=
xchg
(
&
req_inet
->
ipv6_opt
,
txopts
);
if
(
txopts
)
{
atomic_sub
(
txopts
->
tot_len
,
&
sk
->
sk_omem_alloc
);
txopt_put
(
txopts
);
}
return
0
;
}
/**
* calipso_req_delattr - Delete the CALIPSO option from a request socket
* @reg: the request socket
*
* Description:
* Removes the CALIPSO option from a request socket, if present.
*
*/
static
void
calipso_req_delattr
(
struct
request_sock
*
req
)
{
struct
inet_request_sock
*
req_inet
=
inet_rsk
(
req
);
struct
ipv6_opt_hdr
*
new
;
struct
ipv6_txoptions
*
txopts
;
struct
sock
*
sk
=
sk_to_full_sk
(
req_to_sk
(
req
));
if
(
!
req_inet
->
ipv6_opt
||
!
req_inet
->
ipv6_opt
->
hopopt
)
return
;
if
(
calipso_opt_del
(
req_inet
->
ipv6_opt
->
hopopt
,
&
new
))
return
;
/* Nothing to do */
txopts
=
ipv6_renew_options_kern
(
sk
,
req_inet
->
ipv6_opt
,
IPV6_HOPOPTS
,
new
,
new
?
ipv6_optlen
(
new
)
:
0
);
if
(
!
IS_ERR
(
txopts
))
{
txopts
=
xchg
(
&
req_inet
->
ipv6_opt
,
txopts
);
if
(
txopts
)
{
atomic_sub
(
txopts
->
tot_len
,
&
sk
->
sk_omem_alloc
);
txopt_put
(
txopts
);
}
}
kfree
(
new
);
}
/* skbuff functions.
*/
/**
* calipso_skbuff_optptr - Find the CALIPSO option in the packet
* @skb: the packet
*
* Description:
* Parse the packet's IP header looking for a CALIPSO option. Returns a pointer
* to the start of the CALIPSO option on success, NULL if one if not found.
*
*/
static
unsigned
char
*
calipso_skbuff_optptr
(
const
struct
sk_buff
*
skb
)
{
const
struct
ipv6hdr
*
ip6_hdr
=
ipv6_hdr
(
skb
);
int
offset
;
if
(
ip6_hdr
->
nexthdr
!=
NEXTHDR_HOP
)
return
NULL
;
offset
=
ipv6_find_tlv
(
skb
,
sizeof
(
*
ip6_hdr
),
IPV6_TLV_CALIPSO
);
if
(
offset
>=
0
)
return
(
unsigned
char
*
)
ip6_hdr
+
offset
;
return
NULL
;
}
/**
* calipso_skbuff_setattr - Set the CALIPSO option on a packet
* @skb: the packet
* @doi_def: the CALIPSO DOI to use
* @secattr: the security attributes
*
* Description:
* Set the CALIPSO option on the given packet based on the security attributes.
* Returns a pointer to the IP header on success and NULL on failure.
*
*/
static
int
calipso_skbuff_setattr
(
struct
sk_buff
*
skb
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
;
struct
ipv6hdr
*
ip6_hdr
;
struct
ipv6_opt_hdr
*
hop
;
unsigned
char
buf
[
CALIPSO_MAX_BUFFER
];
int
len_delta
,
new_end
,
pad
;
unsigned
int
start
,
end
;
ip6_hdr
=
ipv6_hdr
(
skb
);
if
(
ip6_hdr
->
nexthdr
==
NEXTHDR_HOP
)
{
hop
=
(
struct
ipv6_opt_hdr
*
)(
ip6_hdr
+
1
);
ret_val
=
calipso_opt_find
(
hop
,
&
start
,
&
end
);
if
(
ret_val
&&
ret_val
!=
-
ENOENT
)
return
ret_val
;
}
else
{
start
=
0
;
end
=
0
;
}
memset
(
buf
,
0
,
sizeof
(
buf
));
ret_val
=
calipso_genopt
(
buf
,
start
&
3
,
sizeof
(
buf
),
doi_def
,
secattr
);
if
(
ret_val
<
0
)
return
ret_val
;
new_end
=
start
+
ret_val
;
/* At this point new_end aligns to 4n, so (new_end & 4) pads to 8n */
pad
=
((
new_end
&
4
)
+
(
end
&
7
))
&
7
;
len_delta
=
new_end
-
(
int
)
end
+
pad
;
ret_val
=
skb_cow
(
skb
,
skb_headroom
(
skb
)
+
len_delta
);
if
(
ret_val
<
0
)
return
ret_val
;
if
(
len_delta
)
{
if
(
len_delta
>
0
)
skb_push
(
skb
,
len_delta
);
else
skb_pull
(
skb
,
-
len_delta
);
memmove
((
char
*
)
ip6_hdr
-
len_delta
,
ip6_hdr
,
sizeof
(
*
ip6_hdr
)
+
start
);
skb_reset_network_header
(
skb
);
ip6_hdr
=
ipv6_hdr
(
skb
);
}
hop
=
(
struct
ipv6_opt_hdr
*
)(
ip6_hdr
+
1
);
if
(
start
==
0
)
{
struct
ipv6_opt_hdr
*
new_hop
=
(
struct
ipv6_opt_hdr
*
)
buf
;
new_hop
->
nexthdr
=
ip6_hdr
->
nexthdr
;
new_hop
->
hdrlen
=
len_delta
/
8
-
1
;
ip6_hdr
->
nexthdr
=
NEXTHDR_HOP
;
}
else
{
hop
->
hdrlen
+=
len_delta
/
8
;
}
memcpy
((
char
*
)
hop
+
start
,
buf
+
(
start
&
3
),
new_end
-
start
);
calipso_pad_write
((
unsigned
char
*
)
hop
,
new_end
,
pad
);
return
0
;
}
/**
* calipso_skbuff_delattr - Delete any CALIPSO options from a packet
* @skb: the packet
*
* Description:
* Removes any and all CALIPSO options from the given packet. Returns zero on
* success, negative values on failure.
*
*/
static
int
calipso_skbuff_delattr
(
struct
sk_buff
*
skb
)
{
int
ret_val
;
struct
ipv6hdr
*
ip6_hdr
;
struct
ipv6_opt_hdr
*
old_hop
;
u32
old_hop_len
,
start
=
0
,
end
=
0
,
delta
,
size
,
pad
;
if
(
!
calipso_skbuff_optptr
(
skb
))
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
;
ip6_hdr
=
ipv6_hdr
(
skb
);
old_hop
=
(
struct
ipv6_opt_hdr
*
)(
ip6_hdr
+
1
);
old_hop_len
=
ipv6_optlen
(
old_hop
);
ret_val
=
calipso_opt_find
(
old_hop
,
&
start
,
&
end
);
if
(
ret_val
)
return
ret_val
;
if
(
start
==
sizeof
(
*
old_hop
)
&&
end
==
old_hop_len
)
{
/* There's no other option in the header so we delete
* the whole thing. */
delta
=
old_hop_len
;
size
=
sizeof
(
*
ip6_hdr
);
ip6_hdr
->
nexthdr
=
old_hop
->
nexthdr
;
}
else
{
delta
=
(
end
-
start
)
&
~
7
;
if
(
delta
)
old_hop
->
hdrlen
-=
delta
/
8
;
pad
=
(
end
-
start
)
&
7
;
size
=
sizeof
(
*
ip6_hdr
)
+
start
+
pad
;
calipso_pad_write
((
unsigned
char
*
)
old_hop
,
start
,
pad
);
}
if
(
delta
)
{
skb_pull
(
skb
,
delta
);
memmove
((
char
*
)
ip6_hdr
+
delta
,
ip6_hdr
,
size
);
skb_reset_network_header
(
skb
);
}
return
0
;
}
static
const
struct
netlbl_calipso_ops
ops
=
{
.
doi_add
=
calipso_doi_add
,
.
doi_free
=
calipso_doi_free
,
.
doi_remove
=
calipso_doi_remove
,
.
doi_getdef
=
calipso_doi_getdef
,
.
doi_putdef
=
calipso_doi_putdef
,
.
doi_walk
=
calipso_doi_walk
,
.
sock_getattr
=
calipso_sock_getattr
,
.
sock_setattr
=
calipso_sock_setattr
,
.
sock_delattr
=
calipso_sock_delattr
,
.
req_setattr
=
calipso_req_setattr
,
.
req_delattr
=
calipso_req_delattr
,
.
opt_getattr
=
calipso_opt_getattr
,
.
skbuff_optptr
=
calipso_skbuff_optptr
,
.
skbuff_setattr
=
calipso_skbuff_setattr
,
.
skbuff_delattr
=
calipso_skbuff_delattr
,
.
cache_invalidate
=
calipso_cache_invalidate
,
.
cache_add
=
calipso_cache_add
};
/**
* calipso_init - Initialize the CALIPSO module
*
* Description:
* Initialize the CALIPSO module and prepare it for use. Returns zero on
* success and negative values on failure.
*
*/
int
__init
calipso_init
(
void
)
{
int
ret_val
;
ret_val
=
calipso_cache_init
();
if
(
!
ret_val
)
netlbl_calipso_ops_register
(
&
ops
);
return
ret_val
;
}
void
calipso_exit
(
void
)
{
netlbl_calipso_ops_register
(
NULL
);
calipso_cache_invalidate
();
kfree
(
calipso_cache
);
}
net/ipv6/exthdrs.c
View file @
d011a4d8
...
...
@@ -43,6 +43,7 @@
#include <net/ndisc.h>
#include <net/ip6_route.h>
#include <net/addrconf.h>
#include <net/calipso.h>
#if IS_ENABLED(CONFIG_IPV6_MIP6)
#include <net/xfrm.h>
#endif
...
...
@@ -603,6 +604,28 @@ static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
return
false
;
}
/* CALIPSO RFC 5570 */
static
bool
ipv6_hop_calipso
(
struct
sk_buff
*
skb
,
int
optoff
)
{
const
unsigned
char
*
nh
=
skb_network_header
(
skb
);
if
(
nh
[
optoff
+
1
]
<
8
)
goto
drop
;
if
(
nh
[
optoff
+
6
]
*
4
+
8
>
nh
[
optoff
+
1
])
goto
drop
;
if
(
!
calipso_validate
(
skb
,
nh
+
optoff
))
goto
drop
;
return
true
;
drop:
kfree_skb
(
skb
);
return
false
;
}
static
const
struct
tlvtype_proc
tlvprochopopt_lst
[]
=
{
{
.
type
=
IPV6_TLV_ROUTERALERT
,
...
...
@@ -612,6 +635,10 @@ static const struct tlvtype_proc tlvprochopopt_lst[] = {
.
type
=
IPV6_TLV_JUMBO
,
.
func
=
ipv6_hop_jumbo
,
},
{
.
type
=
IPV6_TLV_CALIPSO
,
.
func
=
ipv6_hop_calipso
,
},
{
-
1
,
}
};
...
...
@@ -758,6 +785,27 @@ static int ipv6_renew_option(void *ohdr,
return
0
;
}
/**
* ipv6_renew_options - replace a specific ext hdr with a new one.
*
* @sk: sock from which to allocate memory
* @opt: original options
* @newtype: option type to replace in @opt
* @newopt: new option of type @newtype to replace (user-mem)
* @newoptlen: length of @newopt
*
* Returns a new set of options which is a copy of @opt with the
* option type @newtype replaced with @newopt.
*
* @opt may be NULL, in which case a new set of options is returned
* containing just @newopt.
*
* @newopt may be NULL, in which case the specified option type is
* not copied into the new set of options.
*
* The new set of options is allocated from the socket option memory
* buffer of @sk.
*/
struct
ipv6_txoptions
*
ipv6_renew_options
(
struct
sock
*
sk
,
struct
ipv6_txoptions
*
opt
,
int
newtype
,
...
...
@@ -830,6 +878,34 @@ ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt,
return
ERR_PTR
(
err
);
}
/**
* ipv6_renew_options_kern - replace a specific ext hdr with a new one.
*
* @sk: sock from which to allocate memory
* @opt: original options
* @newtype: option type to replace in @opt
* @newopt: new option of type @newtype to replace (kernel-mem)
* @newoptlen: length of @newopt
*
* See ipv6_renew_options(). The difference is that @newopt is
* kernel memory, rather than user memory.
*/
struct
ipv6_txoptions
*
ipv6_renew_options_kern
(
struct
sock
*
sk
,
struct
ipv6_txoptions
*
opt
,
int
newtype
,
struct
ipv6_opt_hdr
*
newopt
,
int
newoptlen
)
{
struct
ipv6_txoptions
*
ret_val
;
const
mm_segment_t
old_fs
=
get_fs
();
set_fs
(
KERNEL_DS
);
ret_val
=
ipv6_renew_options
(
sk
,
opt
,
newtype
,
(
struct
ipv6_opt_hdr
__user
*
)
newopt
,
newoptlen
);
set_fs
(
old_fs
);
return
ret_val
;
}
struct
ipv6_txoptions
*
ipv6_fixup_options
(
struct
ipv6_txoptions
*
opt_space
,
struct
ipv6_txoptions
*
opt
)
{
...
...
net/ipv6/exthdrs_core.c
View file @
d011a4d8
...
...
@@ -112,7 +112,7 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp,
}
EXPORT_SYMBOL
(
ipv6_skip_exthdr
);
int
ipv6_find_tlv
(
struct
sk_buff
*
skb
,
int
offset
,
int
type
)
int
ipv6_find_tlv
(
const
struct
sk_buff
*
skb
,
int
offset
,
int
type
)
{
const
unsigned
char
*
nh
=
skb_network_header
(
skb
);
int
packet_len
=
skb_tail_pointer
(
skb
)
-
skb_network_header
(
skb
);
...
...
net/ipv6/ipv6_sockglue.c
View file @
d011a4d8
...
...
@@ -98,7 +98,6 @@ int ip6_ra_control(struct sock *sk, int sel)
return
0
;
}
static
struct
ipv6_txoptions
*
ipv6_update_options
(
struct
sock
*
sk
,
struct
ipv6_txoptions
*
opt
)
{
...
...
net/ipv6/sysctl_net_ipv6.c
View file @
d011a4d8
...
...
@@ -15,6 +15,9 @@
#include <net/ipv6.h>
#include <net/addrconf.h>
#include <net/inet_frag.h>
#ifdef CONFIG_NETLABEL
#include <net/calipso.h>
#endif
static
int
one
=
1
;
static
int
auto_flowlabels_min
;
...
...
@@ -106,6 +109,22 @@ static struct ctl_table ipv6_rotable[] = {
.
proc_handler
=
proc_dointvec_minmax
,
.
extra1
=
&
one
},
#ifdef CONFIG_NETLABEL
{
.
procname
=
"calipso_cache_enable"
,
.
data
=
&
calipso_cache_enabled
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
proc_dointvec
,
},
{
.
procname
=
"calipso_cache_bucket_size"
,
.
data
=
&
calipso_cache_bucketsize
,
.
maxlen
=
sizeof
(
int
),
.
mode
=
0644
,
.
proc_handler
=
proc_dointvec
,
},
#endif
/* CONFIG_NETLABEL */
{
}
};
...
...
net/ipv6/tcp_ipv6.c
View file @
d011a4d8
...
...
@@ -443,6 +443,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
{
struct
inet_request_sock
*
ireq
=
inet_rsk
(
req
);
struct
ipv6_pinfo
*
np
=
inet6_sk
(
sk
);
struct
ipv6_txoptions
*
opt
;
struct
flowi6
*
fl6
=
&
fl
->
u
.
ip6
;
struct
sk_buff
*
skb
;
int
err
=
-
ENOMEM
;
...
...
@@ -463,8 +464,10 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
fl6
->
flowlabel
=
ip6_flowlabel
(
ipv6_hdr
(
ireq
->
pktopts
));
rcu_read_lock
();
err
=
ip6_xmit
(
sk
,
skb
,
fl6
,
rcu_dereference
(
np
->
opt
),
np
->
tclass
);
opt
=
ireq
->
ipv6_opt
;
if
(
!
opt
)
opt
=
rcu_dereference
(
np
->
opt
);
err
=
ip6_xmit
(
sk
,
skb
,
fl6
,
opt
,
np
->
tclass
);
rcu_read_unlock
();
err
=
net_xmit_eval
(
err
);
}
...
...
@@ -476,6 +479,7 @@ static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst,
static
void
tcp_v6_reqsk_destructor
(
struct
request_sock
*
req
)
{
kfree
(
inet_rsk
(
req
)
->
ipv6_opt
);
kfree_skb
(
inet_rsk
(
req
)
->
pktopts
);
}
...
...
@@ -1109,7 +1113,9 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
but we make one more one thing there: reattach optmem
to newsk.
*/
opt
=
rcu_dereference
(
np
->
opt
);
opt
=
ireq
->
ipv6_opt
;
if
(
!
opt
)
opt
=
rcu_dereference
(
np
->
opt
);
if
(
opt
)
{
opt
=
ipv6_dup_options
(
newsk
,
opt
);
RCU_INIT_POINTER
(
newnp
->
opt
,
opt
);
...
...
net/iucv/af_iucv.c
View file @
d011a4d8
...
...
@@ -22,6 +22,7 @@
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/security.h>
#include <net/sock.h>
#include <asm/ebcdic.h>
#include <asm/cpcmd.h>
...
...
@@ -530,8 +531,10 @@ static void iucv_sock_close(struct sock *sk)
static
void
iucv_sock_init
(
struct
sock
*
sk
,
struct
sock
*
parent
)
{
if
(
parent
)
if
(
parent
)
{
sk
->
sk_type
=
parent
->
sk_type
;
security_sk_clone
(
parent
,
sk
);
}
}
static
struct
sock
*
iucv_sock_alloc
(
struct
socket
*
sock
,
int
proto
,
gfp_t
prio
,
int
kern
)
...
...
net/netlabel/Kconfig
View file @
d011a4d8
...
...
@@ -5,6 +5,7 @@
config NETLABEL
bool "NetLabel subsystem support"
depends on SECURITY
select CRC_CCITT if IPV6
default n
---help---
NetLabel provides support for explicit network packet labeling
...
...
net/netlabel/Makefile
View file @
d011a4d8
...
...
@@ -12,4 +12,4 @@ obj-y += netlabel_mgmt.o
# protocol modules
obj-y
+=
netlabel_unlabeled.o
obj-y
+=
netlabel_cipso_v4.o
obj-$(subst
m,y,
$(CONFIG_IPV6))
+=
netlabel_calipso.o
net/netlabel/netlabel_calipso.c
0 → 100644
View file @
d011a4d8
/*
* NetLabel CALIPSO/IPv6 Support
*
* This file defines the CALIPSO/IPv6 functions for the NetLabel system. The
* NetLabel system manages static and dynamic label mappings for network
* protocols such as CIPSO and CALIPSO.
*
* Authors: Paul Moore <paul@paul-moore.com>
* Huw Davies <huw@codeweavers.com>
*
*/
/* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
*
* 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, see <http://www.gnu.org/licenses/>.
*
*/
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/audit.h>
#include <linux/slab.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <net/genetlink.h>
#include <net/netlabel.h>
#include <net/calipso.h>
#include <linux/atomic.h>
#include "netlabel_user.h"
#include "netlabel_calipso.h"
#include "netlabel_mgmt.h"
#include "netlabel_domainhash.h"
/* Argument struct for calipso_doi_walk() */
struct
netlbl_calipso_doiwalk_arg
{
struct
netlink_callback
*
nl_cb
;
struct
sk_buff
*
skb
;
u32
seq
;
};
/* Argument struct for netlbl_domhsh_walk() */
struct
netlbl_domhsh_walk_arg
{
struct
netlbl_audit
*
audit_info
;
u32
doi
;
};
/* NetLabel Generic NETLINK CALIPSO family */
static
struct
genl_family
netlbl_calipso_gnl_family
=
{
.
id
=
GENL_ID_GENERATE
,
.
hdrsize
=
0
,
.
name
=
NETLBL_NLTYPE_CALIPSO_NAME
,
.
version
=
NETLBL_PROTO_VERSION
,
.
maxattr
=
NLBL_CALIPSO_A_MAX
,
};
/* NetLabel Netlink attribute policy */
static
const
struct
nla_policy
calipso_genl_policy
[
NLBL_CALIPSO_A_MAX
+
1
]
=
{
[
NLBL_CALIPSO_A_DOI
]
=
{
.
type
=
NLA_U32
},
[
NLBL_CALIPSO_A_MTYPE
]
=
{
.
type
=
NLA_U32
},
};
/* NetLabel Command Handlers
*/
/**
* netlbl_calipso_add_pass - Adds a CALIPSO pass DOI definition
* @info: the Generic NETLINK info block
* @audit_info: NetLabel audit information
*
* Description:
* Create a new CALIPSO_MAP_PASS DOI definition based on the given ADD message
* and add it to the CALIPSO engine. Return zero on success and non-zero on
* error.
*
*/
static
int
netlbl_calipso_add_pass
(
struct
genl_info
*
info
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
;
struct
calipso_doi
*
doi_def
=
NULL
;
doi_def
=
kmalloc
(
sizeof
(
*
doi_def
),
GFP_KERNEL
);
if
(
!
doi_def
)
return
-
ENOMEM
;
doi_def
->
type
=
CALIPSO_MAP_PASS
;
doi_def
->
doi
=
nla_get_u32
(
info
->
attrs
[
NLBL_CALIPSO_A_DOI
]);
ret_val
=
calipso_doi_add
(
doi_def
,
audit_info
);
if
(
ret_val
!=
0
)
calipso_doi_free
(
doi_def
);
return
ret_val
;
}
/**
* netlbl_calipso_add - Handle an ADD message
* @skb: the NETLINK buffer
* @info: the Generic NETLINK info block
*
* Description:
* Create a new DOI definition based on the given ADD message and add it to the
* CALIPSO engine. Returns zero on success, negative values on failure.
*
*/
static
int
netlbl_calipso_add
(
struct
sk_buff
*
skb
,
struct
genl_info
*
info
)
{
int
ret_val
=
-
EINVAL
;
struct
netlbl_audit
audit_info
;
if
(
!
info
->
attrs
[
NLBL_CALIPSO_A_DOI
]
||
!
info
->
attrs
[
NLBL_CALIPSO_A_MTYPE
])
return
-
EINVAL
;
netlbl_netlink_auditinfo
(
skb
,
&
audit_info
);
switch
(
nla_get_u32
(
info
->
attrs
[
NLBL_CALIPSO_A_MTYPE
]))
{
case
CALIPSO_MAP_PASS
:
ret_val
=
netlbl_calipso_add_pass
(
info
,
&
audit_info
);
break
;
}
if
(
ret_val
==
0
)
atomic_inc
(
&
netlabel_mgmt_protocount
);
return
ret_val
;
}
/**
* netlbl_calipso_list - Handle a LIST message
* @skb: the NETLINK buffer
* @info: the Generic NETLINK info block
*
* Description:
* Process a user generated LIST message and respond accordingly.
* Returns zero on success and negative values on error.
*
*/
static
int
netlbl_calipso_list
(
struct
sk_buff
*
skb
,
struct
genl_info
*
info
)
{
int
ret_val
;
struct
sk_buff
*
ans_skb
=
NULL
;
void
*
data
;
u32
doi
;
struct
calipso_doi
*
doi_def
;
if
(
!
info
->
attrs
[
NLBL_CALIPSO_A_DOI
])
{
ret_val
=
-
EINVAL
;
goto
list_failure
;
}
doi
=
nla_get_u32
(
info
->
attrs
[
NLBL_CALIPSO_A_DOI
]);
doi_def
=
calipso_doi_getdef
(
doi
);
if
(
!
doi_def
)
{
ret_val
=
-
EINVAL
;
goto
list_failure
;
}
ans_skb
=
nlmsg_new
(
NLMSG_DEFAULT_SIZE
,
GFP_KERNEL
);
if
(
!
ans_skb
)
{
ret_val
=
-
ENOMEM
;
goto
list_failure_put
;
}
data
=
genlmsg_put_reply
(
ans_skb
,
info
,
&
netlbl_calipso_gnl_family
,
0
,
NLBL_CALIPSO_C_LIST
);
if
(
!
data
)
{
ret_val
=
-
ENOMEM
;
goto
list_failure_put
;
}
ret_val
=
nla_put_u32
(
ans_skb
,
NLBL_CALIPSO_A_MTYPE
,
doi_def
->
type
);
if
(
ret_val
!=
0
)
goto
list_failure_put
;
calipso_doi_putdef
(
doi_def
);
genlmsg_end
(
ans_skb
,
data
);
return
genlmsg_reply
(
ans_skb
,
info
);
list_failure_put:
calipso_doi_putdef
(
doi_def
);
list_failure:
kfree_skb
(
ans_skb
);
return
ret_val
;
}
/**
* netlbl_calipso_listall_cb - calipso_doi_walk() callback for LISTALL
* @doi_def: the CALIPSO DOI definition
* @arg: the netlbl_calipso_doiwalk_arg structure
*
* Description:
* This function is designed to be used as a callback to the
* calipso_doi_walk() function for use in generating a response for a LISTALL
* message. Returns the size of the message on success, negative values on
* failure.
*
*/
static
int
netlbl_calipso_listall_cb
(
struct
calipso_doi
*
doi_def
,
void
*
arg
)
{
int
ret_val
=
-
ENOMEM
;
struct
netlbl_calipso_doiwalk_arg
*
cb_arg
=
arg
;
void
*
data
;
data
=
genlmsg_put
(
cb_arg
->
skb
,
NETLINK_CB
(
cb_arg
->
nl_cb
->
skb
).
portid
,
cb_arg
->
seq
,
&
netlbl_calipso_gnl_family
,
NLM_F_MULTI
,
NLBL_CALIPSO_C_LISTALL
);
if
(
!
data
)
goto
listall_cb_failure
;
ret_val
=
nla_put_u32
(
cb_arg
->
skb
,
NLBL_CALIPSO_A_DOI
,
doi_def
->
doi
);
if
(
ret_val
!=
0
)
goto
listall_cb_failure
;
ret_val
=
nla_put_u32
(
cb_arg
->
skb
,
NLBL_CALIPSO_A_MTYPE
,
doi_def
->
type
);
if
(
ret_val
!=
0
)
goto
listall_cb_failure
;
genlmsg_end
(
cb_arg
->
skb
,
data
);
return
0
;
listall_cb_failure:
genlmsg_cancel
(
cb_arg
->
skb
,
data
);
return
ret_val
;
}
/**
* netlbl_calipso_listall - Handle a LISTALL message
* @skb: the NETLINK buffer
* @cb: the NETLINK callback
*
* Description:
* Process a user generated LISTALL message and respond accordingly. Returns
* zero on success and negative values on error.
*
*/
static
int
netlbl_calipso_listall
(
struct
sk_buff
*
skb
,
struct
netlink_callback
*
cb
)
{
struct
netlbl_calipso_doiwalk_arg
cb_arg
;
u32
doi_skip
=
cb
->
args
[
0
];
cb_arg
.
nl_cb
=
cb
;
cb_arg
.
skb
=
skb
;
cb_arg
.
seq
=
cb
->
nlh
->
nlmsg_seq
;
calipso_doi_walk
(
&
doi_skip
,
netlbl_calipso_listall_cb
,
&
cb_arg
);
cb
->
args
[
0
]
=
doi_skip
;
return
skb
->
len
;
}
/**
* netlbl_calipso_remove_cb - netlbl_calipso_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_calipso_remove() as the callback
* for the netlbl_domhsh_walk() function; it removes LSM domain map entries
* which are associated with the CALIPSO DOI specified in @arg. Returns zero on
* success, negative values on failure.
*
*/
static
int
netlbl_calipso_remove_cb
(
struct
netlbl_dom_map
*
entry
,
void
*
arg
)
{
struct
netlbl_domhsh_walk_arg
*
cb_arg
=
arg
;
if
(
entry
->
def
.
type
==
NETLBL_NLTYPE_CALIPSO
&&
entry
->
def
.
calipso
->
doi
==
cb_arg
->
doi
)
return
netlbl_domhsh_remove_entry
(
entry
,
cb_arg
->
audit_info
);
return
0
;
}
/**
* netlbl_calipso_remove - Handle a REMOVE message
* @skb: the NETLINK buffer
* @info: the Generic NETLINK info block
*
* Description:
* Process a user generated REMOVE message and respond accordingly. Returns
* zero on success, negative values on failure.
*
*/
static
int
netlbl_calipso_remove
(
struct
sk_buff
*
skb
,
struct
genl_info
*
info
)
{
int
ret_val
=
-
EINVAL
;
struct
netlbl_domhsh_walk_arg
cb_arg
;
struct
netlbl_audit
audit_info
;
u32
skip_bkt
=
0
;
u32
skip_chain
=
0
;
if
(
!
info
->
attrs
[
NLBL_CALIPSO_A_DOI
])
return
-
EINVAL
;
netlbl_netlink_auditinfo
(
skb
,
&
audit_info
);
cb_arg
.
doi
=
nla_get_u32
(
info
->
attrs
[
NLBL_CALIPSO_A_DOI
]);
cb_arg
.
audit_info
=
&
audit_info
;
ret_val
=
netlbl_domhsh_walk
(
&
skip_bkt
,
&
skip_chain
,
netlbl_calipso_remove_cb
,
&
cb_arg
);
if
(
ret_val
==
0
||
ret_val
==
-
ENOENT
)
{
ret_val
=
calipso_doi_remove
(
cb_arg
.
doi
,
&
audit_info
);
if
(
ret_val
==
0
)
atomic_dec
(
&
netlabel_mgmt_protocount
);
}
return
ret_val
;
}
/* NetLabel Generic NETLINK Command Definitions
*/
static
const
struct
genl_ops
netlbl_calipso_ops
[]
=
{
{
.
cmd
=
NLBL_CALIPSO_C_ADD
,
.
flags
=
GENL_ADMIN_PERM
,
.
policy
=
calipso_genl_policy
,
.
doit
=
netlbl_calipso_add
,
.
dumpit
=
NULL
,
},
{
.
cmd
=
NLBL_CALIPSO_C_REMOVE
,
.
flags
=
GENL_ADMIN_PERM
,
.
policy
=
calipso_genl_policy
,
.
doit
=
netlbl_calipso_remove
,
.
dumpit
=
NULL
,
},
{
.
cmd
=
NLBL_CALIPSO_C_LIST
,
.
flags
=
0
,
.
policy
=
calipso_genl_policy
,
.
doit
=
netlbl_calipso_list
,
.
dumpit
=
NULL
,
},
{
.
cmd
=
NLBL_CALIPSO_C_LISTALL
,
.
flags
=
0
,
.
policy
=
calipso_genl_policy
,
.
doit
=
NULL
,
.
dumpit
=
netlbl_calipso_listall
,
},
};
/* NetLabel Generic NETLINK Protocol Functions
*/
/**
* netlbl_calipso_genl_init - Register the CALIPSO NetLabel component
*
* Description:
* Register the CALIPSO packet NetLabel component with the Generic NETLINK
* mechanism. Returns zero on success, negative values on failure.
*
*/
int
__init
netlbl_calipso_genl_init
(
void
)
{
return
genl_register_family_with_ops
(
&
netlbl_calipso_gnl_family
,
netlbl_calipso_ops
);
}
static
const
struct
netlbl_calipso_ops
*
calipso_ops
;
/**
* netlbl_calipso_ops_register - Register the CALIPSO operations
*
* Description:
* Register the CALIPSO packet engine operations.
*
*/
const
struct
netlbl_calipso_ops
*
netlbl_calipso_ops_register
(
const
struct
netlbl_calipso_ops
*
ops
)
{
return
xchg
(
&
calipso_ops
,
ops
);
}
EXPORT_SYMBOL
(
netlbl_calipso_ops_register
);
static
const
struct
netlbl_calipso_ops
*
netlbl_calipso_ops_get
(
void
)
{
return
ACCESS_ONCE
(
calipso_ops
);
}
/**
* calipso_doi_add - Add a new DOI to the CALIPSO protocol engine
* @doi_def: the DOI structure
* @audit_info: NetLabel audit information
*
* Description:
* The caller defines a new DOI for use by the CALIPSO engine and calls this
* function to add it to the list of acceptable domains. The caller must
* ensure that the mapping table specified in @doi_def->map meets all of the
* requirements of the mapping type (see calipso.h for details). Returns
* zero on success and non-zero on failure.
*
*/
int
calipso_doi_add
(
struct
calipso_doi
*
doi_def
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
=
-
ENOMSG
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
doi_add
(
doi_def
,
audit_info
);
return
ret_val
;
}
/**
* calipso_doi_free - Frees a DOI definition
* @doi_def: the DOI definition
*
* Description:
* This function frees all of the memory associated with a DOI definition.
*
*/
void
calipso_doi_free
(
struct
calipso_doi
*
doi_def
)
{
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ops
->
doi_free
(
doi_def
);
}
/**
* calipso_doi_remove - Remove an existing DOI from the CALIPSO protocol engine
* @doi: the DOI value
* @audit_secid: the LSM secid to use in the audit message
*
* Description:
* Removes a DOI definition from the CALIPSO 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
calipso_doi_remove
(
u32
doi
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
=
-
ENOMSG
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
doi_remove
(
doi
,
audit_info
);
return
ret_val
;
}
/**
* calipso_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
* calipso_doi_putdef() is called when the caller is done.
*
*/
struct
calipso_doi
*
calipso_doi_getdef
(
u32
doi
)
{
struct
calipso_doi
*
ret_val
=
NULL
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
doi_getdef
(
doi
);
return
ret_val
;
}
/**
* calipso_doi_putdef - Releases a reference for the given DOI definition
* @doi_def: the DOI definition
*
* Description:
* Releases a DOI definition reference obtained from calipso_doi_getdef().
*
*/
void
calipso_doi_putdef
(
struct
calipso_doi
*
doi_def
)
{
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ops
->
doi_putdef
(
doi_def
);
}
/**
* calipso_doi_walk - Iterate through the DOI definitions
* @skip_cnt: skip past this number of DOI definitions, updated
* @callback: callback for each DOI definition
* @cb_arg: argument for the callback function
*
* Description:
* Iterate over the DOI definition list, skipping the first @skip_cnt entries.
* For each entry call @callback, if @callback returns a negative value stop
* 'walking' through the list and return. Updates the value in @skip_cnt upon
* return. Returns zero on success, negative values on failure.
*
*/
int
calipso_doi_walk
(
u32
*
skip_cnt
,
int
(
*
callback
)(
struct
calipso_doi
*
doi_def
,
void
*
arg
),
void
*
cb_arg
)
{
int
ret_val
=
-
ENOMSG
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
doi_walk
(
skip_cnt
,
callback
,
cb_arg
);
return
ret_val
;
}
/**
* calipso_sock_getattr - Get the security attributes from a sock
* @sk: the sock
* @secattr: the security attributes
*
* Description:
* Query @sk to see if there is a CALIPSO option attached to the sock and if
* there is return the CALIPSO security attributes in @secattr. This function
* requires that @sk be locked, or privately held, but it does not do any
* locking itself. Returns zero on success and negative values on failure.
*
*/
int
calipso_sock_getattr
(
struct
sock
*
sk
,
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
=
-
ENOMSG
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
sock_getattr
(
sk
,
secattr
);
return
ret_val
;
}
/**
* calipso_sock_setattr - Add a CALIPSO option to a socket
* @sk: the socket
* @doi_def: the CALIPSO DOI to use
* @secattr: the specific security attributes of the socket
*
* Description:
* Set the CALIPSO 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
calipso_sock_setattr
(
struct
sock
*
sk
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
=
-
ENOMSG
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
sock_setattr
(
sk
,
doi_def
,
secattr
);
return
ret_val
;
}
/**
* calipso_sock_delattr - Delete the CALIPSO option from a socket
* @sk: the socket
*
* Description:
* Removes the CALIPSO option from a socket, if present.
*
*/
void
calipso_sock_delattr
(
struct
sock
*
sk
)
{
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ops
->
sock_delattr
(
sk
);
}
/**
* calipso_req_setattr - Add a CALIPSO option to a connection request socket
* @req: the connection request socket
* @doi_def: the CALIPSO DOI to use
* @secattr: the specific security attributes of the socket
*
* Description:
* Set the CALIPSO option on the given socket using the DOI definition and
* security attributes passed to the function. Returns zero on success and
* negative values on failure.
*
*/
int
calipso_req_setattr
(
struct
request_sock
*
req
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
=
-
ENOMSG
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
req_setattr
(
req
,
doi_def
,
secattr
);
return
ret_val
;
}
/**
* calipso_req_delattr - Delete the CALIPSO option from a request socket
* @reg: the request socket
*
* Description:
* Removes the CALIPSO option from a request socket, if present.
*
*/
void
calipso_req_delattr
(
struct
request_sock
*
req
)
{
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ops
->
req_delattr
(
req
);
}
/**
* calipso_optptr - Find the CALIPSO option in the packet
* @skb: the packet
*
* Description:
* Parse the packet's IP header looking for a CALIPSO option. Returns a pointer
* to the start of the CALIPSO option on success, NULL if one if not found.
*
*/
unsigned
char
*
calipso_optptr
(
const
struct
sk_buff
*
skb
)
{
unsigned
char
*
ret_val
=
NULL
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
skbuff_optptr
(
skb
);
return
ret_val
;
}
/**
* calipso_getattr - Get the security attributes from a memory block.
* @calipso: the CALIPSO option
* @secattr: the security attributes
*
* Description:
* Inspect @calipso and return the security attributes in @secattr.
* Returns zero on success and negative values on failure.
*
*/
int
calipso_getattr
(
const
unsigned
char
*
calipso
,
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
=
-
ENOMSG
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
opt_getattr
(
calipso
,
secattr
);
return
ret_val
;
}
/**
* calipso_skbuff_setattr - Set the CALIPSO option on a packet
* @skb: the packet
* @doi_def: the CALIPSO DOI to use
* @secattr: the security attributes
*
* Description:
* Set the CALIPSO option on the given packet based on the security attributes.
* Returns a pointer to the IP header on success and NULL on failure.
*
*/
int
calipso_skbuff_setattr
(
struct
sk_buff
*
skb
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
=
-
ENOMSG
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
skbuff_setattr
(
skb
,
doi_def
,
secattr
);
return
ret_val
;
}
/**
* calipso_skbuff_delattr - Delete any CALIPSO options from a packet
* @skb: the packet
*
* Description:
* Removes any and all CALIPSO options from the given packet. Returns zero on
* success, negative values on failure.
*
*/
int
calipso_skbuff_delattr
(
struct
sk_buff
*
skb
)
{
int
ret_val
=
-
ENOMSG
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
skbuff_delattr
(
skb
);
return
ret_val
;
}
/**
* calipso_cache_invalidate - Invalidates the current CALIPSO cache
*
* Description:
* Invalidates and frees any entries in the CALIPSO cache. Returns zero on
* success and negative values on failure.
*
*/
void
calipso_cache_invalidate
(
void
)
{
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ops
->
cache_invalidate
();
}
/**
* calipso_cache_add - Add an entry to the CALIPSO cache
* @calipso_ptr: the CALIPSO option
* @secattr: the packet's security attributes
*
* Description:
* Add a new entry into the CALIPSO label mapping cache.
* Returns zero on success, negative values on failure.
*
*/
int
calipso_cache_add
(
const
unsigned
char
*
calipso_ptr
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
int
ret_val
=
-
ENOMSG
;
const
struct
netlbl_calipso_ops
*
ops
=
netlbl_calipso_ops_get
();
if
(
ops
)
ret_val
=
ops
->
cache_add
(
calipso_ptr
,
secattr
);
return
ret_val
;
}
net/netlabel/netlabel_calipso.h
0 → 100644
View file @
d011a4d8
/*
* NetLabel CALIPSO Support
*
* This file defines the CALIPSO functions for the NetLabel system. The
* NetLabel system manages static and dynamic label mappings for network
* protocols such as CIPSO and RIPSO.
*
* Authors: Paul Moore <paul@paul-moore.com>
* Huw Davies <huw@codeweavers.com>
*
*/
/* (c) Copyright Hewlett-Packard Development Company, L.P., 2006
* (c) Copyright Huw Davies <huw@codeweavers.com>, 2015
*
* 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef _NETLABEL_CALIPSO
#define _NETLABEL_CALIPSO
#include <net/netlabel.h>
#include <net/calipso.h>
/* The following NetLabel payloads are supported by the CALIPSO subsystem.
*
* o ADD:
* Sent by an application to add a new DOI mapping table.
*
* Required attributes:
*
* NLBL_CALIPSO_A_DOI
* NLBL_CALIPSO_A_MTYPE
*
* If using CALIPSO_MAP_PASS no additional attributes are required.
*
* o REMOVE:
* Sent by an application to remove a specific DOI mapping table from the
* CALIPSO system.
*
* Required attributes:
*
* NLBL_CALIPSO_A_DOI
*
* o LIST:
* Sent by an application to list the details of a DOI definition. On
* success the kernel should send a response using the following format.
*
* Required attributes:
*
* NLBL_CALIPSO_A_DOI
*
* The valid response message format depends on the type of the DOI mapping,
* the defined formats are shown below.
*
* Required attributes:
*
* NLBL_CALIPSO_A_MTYPE
*
* If using CALIPSO_MAP_PASS no additional attributes are required.
*
* o LISTALL:
* This message is sent by an application to list the valid DOIs on the
* system. When sent by an application there is no payload and the
* NLM_F_DUMP flag should be set. The kernel should respond with a series of
* the following messages.
*
* Required attributes:
*
* NLBL_CALIPSO_A_DOI
* NLBL_CALIPSO_A_MTYPE
*
*/
/* NetLabel CALIPSO commands */
enum
{
NLBL_CALIPSO_C_UNSPEC
,
NLBL_CALIPSO_C_ADD
,
NLBL_CALIPSO_C_REMOVE
,
NLBL_CALIPSO_C_LIST
,
NLBL_CALIPSO_C_LISTALL
,
__NLBL_CALIPSO_C_MAX
,
};
/* NetLabel CALIPSO attributes */
enum
{
NLBL_CALIPSO_A_UNSPEC
,
NLBL_CALIPSO_A_DOI
,
/* (NLA_U32)
* the DOI value */
NLBL_CALIPSO_A_MTYPE
,
/* (NLA_U32)
* the mapping table type (defined in the calipso.h header as
* CALIPSO_MAP_*) */
__NLBL_CALIPSO_A_MAX
,
};
#define NLBL_CALIPSO_A_MAX (__NLBL_CALIPSO_A_MAX - 1)
/* NetLabel protocol functions */
#if IS_ENABLED(CONFIG_IPV6)
int
netlbl_calipso_genl_init
(
void
);
#else
static
inline
int
netlbl_calipso_genl_init
(
void
)
{
return
0
;
}
#endif
int
calipso_doi_add
(
struct
calipso_doi
*
doi_def
,
struct
netlbl_audit
*
audit_info
);
void
calipso_doi_free
(
struct
calipso_doi
*
doi_def
);
int
calipso_doi_remove
(
u32
doi
,
struct
netlbl_audit
*
audit_info
);
struct
calipso_doi
*
calipso_doi_getdef
(
u32
doi
);
void
calipso_doi_putdef
(
struct
calipso_doi
*
doi_def
);
int
calipso_doi_walk
(
u32
*
skip_cnt
,
int
(
*
callback
)(
struct
calipso_doi
*
doi_def
,
void
*
arg
),
void
*
cb_arg
);
int
calipso_sock_getattr
(
struct
sock
*
sk
,
struct
netlbl_lsm_secattr
*
secattr
);
int
calipso_sock_setattr
(
struct
sock
*
sk
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
);
void
calipso_sock_delattr
(
struct
sock
*
sk
);
int
calipso_req_setattr
(
struct
request_sock
*
req
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
);
void
calipso_req_delattr
(
struct
request_sock
*
req
);
unsigned
char
*
calipso_optptr
(
const
struct
sk_buff
*
skb
);
int
calipso_getattr
(
const
unsigned
char
*
calipso
,
struct
netlbl_lsm_secattr
*
secattr
);
int
calipso_skbuff_setattr
(
struct
sk_buff
*
skb
,
const
struct
calipso_doi
*
doi_def
,
const
struct
netlbl_lsm_secattr
*
secattr
);
int
calipso_skbuff_delattr
(
struct
sk_buff
*
skb
);
void
calipso_cache_invalidate
(
void
);
int
calipso_cache_add
(
const
unsigned
char
*
calipso_ptr
,
const
struct
netlbl_lsm_secattr
*
secattr
);
#endif
net/netlabel/netlabel_domainhash.c
View file @
d011a4d8
...
...
@@ -37,10 +37,12 @@
#include <linux/slab.h>
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
#include <net/calipso.h>
#include <asm/bug.h>
#include "netlabel_mgmt.h"
#include "netlabel_addrlist.h"
#include "netlabel_calipso.h"
#include "netlabel_domainhash.h"
#include "netlabel_user.h"
...
...
@@ -55,8 +57,9 @@ struct netlbl_domhsh_tbl {
static
DEFINE_SPINLOCK
(
netlbl_domhsh_lock
);
#define netlbl_domhsh_rcu_deref(p) \
rcu_dereference_check(p, lockdep_is_held(&netlbl_domhsh_lock))
static
struct
netlbl_domhsh_tbl
*
netlbl_domhsh
;
static
struct
netlbl_dom_map
*
netlbl_domhsh_def
;
static
struct
netlbl_domhsh_tbl
__rcu
*
netlbl_domhsh
;
static
struct
netlbl_dom_map
__rcu
*
netlbl_domhsh_def_ipv4
;
static
struct
netlbl_dom_map
__rcu
*
netlbl_domhsh_def_ipv6
;
/*
* Domain Hash Table Helper Functions
...
...
@@ -126,18 +129,26 @@ static u32 netlbl_domhsh_hash(const char *key)
return
val
&
(
netlbl_domhsh_rcu_deref
(
netlbl_domhsh
)
->
size
-
1
);
}
static
bool
netlbl_family_match
(
u16
f1
,
u16
f2
)
{
return
(
f1
==
f2
)
||
(
f1
==
AF_UNSPEC
)
||
(
f2
==
AF_UNSPEC
);
}
/**
* netlbl_domhsh_search - Search for a domain entry
* @domain: the domain
* @family: the address family
*
* Description:
* Searches the domain hash table and returns a pointer to the hash table
* entry if found, otherwise NULL is returned. The caller is responsible for
* entry if found, otherwise NULL is returned. @family may be %AF_UNSPEC
* which matches any address family entries. The caller is responsible for
* ensuring that the hash table is protected with either a RCU read lock or the
* hash table lock.
*
*/
static
struct
netlbl_dom_map
*
netlbl_domhsh_search
(
const
char
*
domain
)
static
struct
netlbl_dom_map
*
netlbl_domhsh_search
(
const
char
*
domain
,
u16
family
)
{
u32
bkt
;
struct
list_head
*
bkt_list
;
...
...
@@ -147,7 +158,9 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
bkt
=
netlbl_domhsh_hash
(
domain
);
bkt_list
=
&
netlbl_domhsh_rcu_deref
(
netlbl_domhsh
)
->
tbl
[
bkt
];
list_for_each_entry_rcu
(
iter
,
bkt_list
,
list
)
if
(
iter
->
valid
&&
strcmp
(
iter
->
domain
,
domain
)
==
0
)
if
(
iter
->
valid
&&
netlbl_family_match
(
iter
->
family
,
family
)
&&
strcmp
(
iter
->
domain
,
domain
)
==
0
)
return
iter
;
}
...
...
@@ -157,28 +170,37 @@ static struct netlbl_dom_map *netlbl_domhsh_search(const char *domain)
/**
* netlbl_domhsh_search_def - Search for a domain entry
* @domain: the domain
* @
def: return default if no match is found
* @
family: the address family
*
* Description:
* Searches the domain hash table and returns a pointer to the hash table
* entry if an exact match is found, if an exact match is not present in the
* hash table then the default entry is returned if valid otherwise NULL is
* returned. The caller is responsible ensuring that the hash table is
* returned. @family may be %AF_UNSPEC which matches any address family
* entries. The caller is responsible ensuring that the hash table is
* protected with either a RCU read lock or the hash table lock.
*
*/
static
struct
netlbl_dom_map
*
netlbl_domhsh_search_def
(
const
char
*
domain
)
static
struct
netlbl_dom_map
*
netlbl_domhsh_search_def
(
const
char
*
domain
,
u16
family
)
{
struct
netlbl_dom_map
*
entry
;
entry
=
netlbl_domhsh_search
(
domain
);
if
(
entry
==
NULL
)
{
entry
=
netlbl_domhsh_rcu_deref
(
netlbl_domhsh_def
);
if
(
entry
!=
NULL
&&
!
entry
->
valid
)
entry
=
NULL
;
entry
=
netlbl_domhsh_search
(
domain
,
family
);
if
(
entry
!=
NULL
)
return
entry
;
if
(
family
==
AF_INET
||
family
==
AF_UNSPEC
)
{
entry
=
netlbl_domhsh_rcu_deref
(
netlbl_domhsh_def_ipv4
);
if
(
entry
!=
NULL
&&
entry
->
valid
)
return
entry
;
}
if
(
family
==
AF_INET6
||
family
==
AF_UNSPEC
)
{
entry
=
netlbl_domhsh_rcu_deref
(
netlbl_domhsh_def_ipv6
);
if
(
entry
!=
NULL
&&
entry
->
valid
)
return
entry
;
}
return
entry
;
return
NULL
;
}
/**
...
...
@@ -203,6 +225,7 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
{
struct
audit_buffer
*
audit_buf
;
struct
cipso_v4_doi
*
cipsov4
=
NULL
;
struct
calipso_doi
*
calipso
=
NULL
;
u32
type
;
audit_buf
=
netlbl_audit_start_common
(
AUDIT_MAC_MAP_ADD
,
audit_info
);
...
...
@@ -221,12 +244,14 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
struct
netlbl_domaddr6_map
*
map6
;
map6
=
netlbl_domhsh_addr6_entry
(
addr6
);
type
=
map6
->
def
.
type
;
calipso
=
map6
->
def
.
calipso
;
netlbl_af6list_audit_addr
(
audit_buf
,
0
,
NULL
,
&
addr6
->
addr
,
&
addr6
->
mask
);
#endif
/* IPv6 */
}
else
{
type
=
entry
->
def
.
type
;
cipsov4
=
entry
->
def
.
cipso
;
calipso
=
entry
->
def
.
calipso
;
}
switch
(
type
)
{
case
NETLBL_NLTYPE_UNLABELED
:
...
...
@@ -238,6 +263,12 @@ static void netlbl_domhsh_audit_add(struct netlbl_dom_map *entry,
" nlbl_protocol=cipsov4 cipso_doi=%u"
,
cipsov4
->
doi
);
break
;
case
NETLBL_NLTYPE_CALIPSO
:
BUG_ON
(
calipso
==
NULL
);
audit_log_format
(
audit_buf
,
" nlbl_protocol=calipso calipso_doi=%u"
,
calipso
->
doi
);
break
;
}
audit_log_format
(
audit_buf
,
" res=%u"
,
result
==
0
?
1
:
0
);
audit_log_end
(
audit_buf
);
...
...
@@ -264,13 +295,25 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
if
(
entry
==
NULL
)
return
-
EINVAL
;
if
(
entry
->
family
!=
AF_INET
&&
entry
->
family
!=
AF_INET6
&&
(
entry
->
family
!=
AF_UNSPEC
||
entry
->
def
.
type
!=
NETLBL_NLTYPE_UNLABELED
))
return
-
EINVAL
;
switch
(
entry
->
def
.
type
)
{
case
NETLBL_NLTYPE_UNLABELED
:
if
(
entry
->
def
.
cipso
!=
NULL
||
entry
->
def
.
addrsel
!=
NULL
)
if
(
entry
->
def
.
cipso
!=
NULL
||
entry
->
def
.
calipso
!=
NULL
||
entry
->
def
.
addrsel
!=
NULL
)
return
-
EINVAL
;
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
if
(
entry
->
def
.
cipso
==
NULL
)
if
(
entry
->
family
!=
AF_INET
||
entry
->
def
.
cipso
==
NULL
)
return
-
EINVAL
;
break
;
case
NETLBL_NLTYPE_CALIPSO
:
if
(
entry
->
family
!=
AF_INET6
||
entry
->
def
.
calipso
==
NULL
)
return
-
EINVAL
;
break
;
case
NETLBL_NLTYPE_ADDRSELECT
:
...
...
@@ -294,6 +337,12 @@ static int netlbl_domhsh_validate(const struct netlbl_dom_map *entry)
map6
=
netlbl_domhsh_addr6_entry
(
iter6
);
switch
(
map6
->
def
.
type
)
{
case
NETLBL_NLTYPE_UNLABELED
:
if
(
map6
->
def
.
calipso
!=
NULL
)
return
-
EINVAL
;
break
;
case
NETLBL_NLTYPE_CALIPSO
:
if
(
map6
->
def
.
calipso
==
NULL
)
return
-
EINVAL
;
break
;
default:
return
-
EINVAL
;
...
...
@@ -358,15 +407,18 @@ int __init netlbl_domhsh_init(u32 size)
*
* Description:
* Adds a new entry to the domain hash table and handles any updates to the
* lower level protocol handler (i.e. CIPSO). Returns zero on success,
* negative on failure.
* lower level protocol handler (i.e. CIPSO). @entry->family may be set to
* %AF_UNSPEC which will add an entry that matches all address families. This
* is only useful for the unlabelled type and will only succeed if there is no
* existing entry for any address family with the same domain. Returns zero
* on success, negative on failure.
*
*/
int
netlbl_domhsh_add
(
struct
netlbl_dom_map
*
entry
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
=
0
;
struct
netlbl_dom_map
*
entry_old
;
struct
netlbl_dom_map
*
entry_old
,
*
entry_b
;
struct
netlbl_af4list
*
iter4
;
struct
netlbl_af4list
*
tmp4
;
#if IS_ENABLED(CONFIG_IPV6)
...
...
@@ -385,9 +437,10 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
rcu_read_lock
();
spin_lock
(
&
netlbl_domhsh_lock
);
if
(
entry
->
domain
!=
NULL
)
entry_old
=
netlbl_domhsh_search
(
entry
->
domain
);
entry_old
=
netlbl_domhsh_search
(
entry
->
domain
,
entry
->
family
);
else
entry_old
=
netlbl_domhsh_search_def
(
entry
->
domain
);
entry_old
=
netlbl_domhsh_search_def
(
entry
->
domain
,
entry
->
family
);
if
(
entry_old
==
NULL
)
{
entry
->
valid
=
1
;
...
...
@@ -397,7 +450,41 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry,
&
rcu_dereference
(
netlbl_domhsh
)
->
tbl
[
bkt
]);
}
else
{
INIT_LIST_HEAD
(
&
entry
->
list
);
rcu_assign_pointer
(
netlbl_domhsh_def
,
entry
);
switch
(
entry
->
family
)
{
case
AF_INET
:
rcu_assign_pointer
(
netlbl_domhsh_def_ipv4
,
entry
);
break
;
case
AF_INET6
:
rcu_assign_pointer
(
netlbl_domhsh_def_ipv6
,
entry
);
break
;
case
AF_UNSPEC
:
if
(
entry
->
def
.
type
!=
NETLBL_NLTYPE_UNLABELED
)
{
ret_val
=
-
EINVAL
;
goto
add_return
;
}
entry_b
=
kzalloc
(
sizeof
(
*
entry_b
),
GFP_ATOMIC
);
if
(
entry_b
==
NULL
)
{
ret_val
=
-
ENOMEM
;
goto
add_return
;
}
entry_b
->
family
=
AF_INET6
;
entry_b
->
def
.
type
=
NETLBL_NLTYPE_UNLABELED
;
entry_b
->
valid
=
1
;
entry
->
family
=
AF_INET
;
rcu_assign_pointer
(
netlbl_domhsh_def_ipv4
,
entry
);
rcu_assign_pointer
(
netlbl_domhsh_def_ipv6
,
entry_b
);
break
;
default:
/* Already checked in
* netlbl_domhsh_validate(). */
ret_val
=
-
EINVAL
;
goto
add_return
;
}
}
if
(
entry
->
def
.
type
==
NETLBL_NLTYPE_ADDRSELECT
)
{
...
...
@@ -513,10 +600,12 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
spin_lock
(
&
netlbl_domhsh_lock
);
if
(
entry
->
valid
)
{
entry
->
valid
=
0
;
if
(
entry
!=
rcu_dereference
(
netlbl_domhsh_def
))
list_del_rcu
(
&
entry
->
list
);
if
(
entry
==
rcu_dereference
(
netlbl_domhsh_def_ipv4
))
RCU_INIT_POINTER
(
netlbl_domhsh_def_ipv4
,
NULL
);
else
if
(
entry
==
rcu_dereference
(
netlbl_domhsh_def_ipv6
))
RCU_INIT_POINTER
(
netlbl_domhsh_def_ipv6
,
NULL
);
else
RCU_INIT_POINTER
(
netlbl_domhsh_def
,
NULL
);
list_del_rcu
(
&
entry
->
list
);
}
else
ret_val
=
-
ENOENT
;
spin_unlock
(
&
netlbl_domhsh_lock
);
...
...
@@ -533,6 +622,10 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
if
(
ret_val
==
0
)
{
struct
netlbl_af4list
*
iter4
;
struct
netlbl_domaddr4_map
*
map4
;
#if IS_ENABLED(CONFIG_IPV6)
struct
netlbl_af6list
*
iter6
;
struct
netlbl_domaddr6_map
*
map6
;
#endif
/* IPv6 */
switch
(
entry
->
def
.
type
)
{
case
NETLBL_NLTYPE_ADDRSELECT
:
...
...
@@ -541,12 +634,22 @@ int netlbl_domhsh_remove_entry(struct netlbl_dom_map *entry,
map4
=
netlbl_domhsh_addr4_entry
(
iter4
);
cipso_v4_doi_putdef
(
map4
->
def
.
cipso
);
}
/* no need to check the IPv6 list since we currently
* support only unlabeled protocols for IPv6 */
#if IS_ENABLED(CONFIG_IPV6)
netlbl_af6list_foreach_rcu
(
iter6
,
&
entry
->
def
.
addrsel
->
list6
)
{
map6
=
netlbl_domhsh_addr6_entry
(
iter6
);
calipso_doi_putdef
(
map6
->
def
.
calipso
);
}
#endif
/* IPv6 */
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
cipso_v4_doi_putdef
(
entry
->
def
.
cipso
);
break
;
#if IS_ENABLED(CONFIG_IPV6)
case
NETLBL_NLTYPE_CALIPSO
:
calipso_doi_putdef
(
entry
->
def
.
calipso
);
break
;
#endif
/* IPv6 */
}
call_rcu
(
&
entry
->
rcu
,
netlbl_domhsh_free_entry
);
}
...
...
@@ -583,9 +686,9 @@ int netlbl_domhsh_remove_af4(const char *domain,
rcu_read_lock
();
if
(
domain
)
entry_map
=
netlbl_domhsh_search
(
domain
);
entry_map
=
netlbl_domhsh_search
(
domain
,
AF_INET
);
else
entry_map
=
netlbl_domhsh_search_def
(
domain
);
entry_map
=
netlbl_domhsh_search_def
(
domain
,
AF_INET
);
if
(
entry_map
==
NULL
||
entry_map
->
def
.
type
!=
NETLBL_NLTYPE_ADDRSELECT
)
goto
remove_af4_failure
;
...
...
@@ -622,28 +725,114 @@ int netlbl_domhsh_remove_af4(const char *domain,
return
-
ENOENT
;
}
#if IS_ENABLED(CONFIG_IPV6)
/**
* netlbl_domhsh_remove_af6 - Removes an address selector entry
* @domain: the domain
* @addr: IPv6 address
* @mask: IPv6 address mask
* @audit_info: NetLabel audit information
*
* Description:
* Removes an individual address selector from a domain mapping and potentially
* the entire mapping if it is empty. Returns zero on success, negative values
* on failure.
*
*/
int
netlbl_domhsh_remove_af6
(
const
char
*
domain
,
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
struct
netlbl_audit
*
audit_info
)
{
struct
netlbl_dom_map
*
entry_map
;
struct
netlbl_af6list
*
entry_addr
;
struct
netlbl_af4list
*
iter4
;
struct
netlbl_af6list
*
iter6
;
struct
netlbl_domaddr6_map
*
entry
;
rcu_read_lock
();
if
(
domain
)
entry_map
=
netlbl_domhsh_search
(
domain
,
AF_INET6
);
else
entry_map
=
netlbl_domhsh_search_def
(
domain
,
AF_INET6
);
if
(
entry_map
==
NULL
||
entry_map
->
def
.
type
!=
NETLBL_NLTYPE_ADDRSELECT
)
goto
remove_af6_failure
;
spin_lock
(
&
netlbl_domhsh_lock
);
entry_addr
=
netlbl_af6list_remove
(
addr
,
mask
,
&
entry_map
->
def
.
addrsel
->
list6
);
spin_unlock
(
&
netlbl_domhsh_lock
);
if
(
entry_addr
==
NULL
)
goto
remove_af6_failure
;
netlbl_af4list_foreach_rcu
(
iter4
,
&
entry_map
->
def
.
addrsel
->
list4
)
goto
remove_af6_single_addr
;
netlbl_af6list_foreach_rcu
(
iter6
,
&
entry_map
->
def
.
addrsel
->
list6
)
goto
remove_af6_single_addr
;
/* the domain mapping is empty so remove it from the mapping table */
netlbl_domhsh_remove_entry
(
entry_map
,
audit_info
);
remove_af6_single_addr:
rcu_read_unlock
();
/* yick, we can't use call_rcu here because we don't have a rcu head
* pointer but hopefully this should be a rare case so the pause
* shouldn't be a problem */
synchronize_rcu
();
entry
=
netlbl_domhsh_addr6_entry
(
entry_addr
);
calipso_doi_putdef
(
entry
->
def
.
calipso
);
kfree
(
entry
);
return
0
;
remove_af6_failure:
rcu_read_unlock
();
return
-
ENOENT
;
}
#endif
/* IPv6 */
/**
* netlbl_domhsh_remove - Removes an entry from the domain hash table
* @domain: the domain to remove
* @family: address family
* @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). @family may be %AF_UNSPEC which
* removes all address family entries. Returns zero on success, negative on
* failure.
*
*/
int
netlbl_domhsh_remove
(
const
char
*
domain
,
struct
netlbl_audit
*
audit_info
)
int
netlbl_domhsh_remove
(
const
char
*
domain
,
u16
family
,
struct
netlbl_audit
*
audit_info
)
{
int
ret_val
;
int
ret_val
=
-
EINVAL
;
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
);
if
(
family
==
AF_INET
||
family
==
AF_UNSPEC
)
{
if
(
domain
)
entry
=
netlbl_domhsh_search
(
domain
,
AF_INET
);
else
entry
=
netlbl_domhsh_search_def
(
domain
,
AF_INET
);
ret_val
=
netlbl_domhsh_remove_entry
(
entry
,
audit_info
);
if
(
ret_val
&&
ret_val
!=
-
ENOENT
)
goto
done
;
}
if
(
family
==
AF_INET6
||
family
==
AF_UNSPEC
)
{
int
ret_val2
;
if
(
domain
)
entry
=
netlbl_domhsh_search
(
domain
,
AF_INET6
);
else
entry
=
netlbl_domhsh_search_def
(
domain
,
AF_INET6
);
ret_val2
=
netlbl_domhsh_remove_entry
(
entry
,
audit_info
);
if
(
ret_val2
!=
-
ENOENT
)
ret_val
=
ret_val2
;
}
done:
rcu_read_unlock
();
return
ret_val
;
...
...
@@ -651,32 +840,38 @@ int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
/**
* netlbl_domhsh_remove_default - Removes the default entry from the table
* @family: address family
* @audit_info: NetLabel audit information
*
* Description:
* Removes/resets the default entry for the domain hash table and handles any
* updates to the lower level protocol handler (i.e. CIPSO). Returns zero on
* success, non-zero on failure.
* Removes/resets the default entry corresponding to @family from the domain
* hash table and handles any updates to the lower level protocol handler
* (i.e. CIPSO). @family may be %AF_UNSPEC which removes all address family
* entries. Returns zero on success, negative on failure.
*
*/
int
netlbl_domhsh_remove_default
(
struct
netlbl_audit
*
audit_info
)
int
netlbl_domhsh_remove_default
(
u16
family
,
struct
netlbl_audit
*
audit_info
)
{
return
netlbl_domhsh_remove
(
NULL
,
audit_info
);
return
netlbl_domhsh_remove
(
NULL
,
family
,
audit_info
);
}
/**
* netlbl_domhsh_getentry - Get an entry from the domain hash table
* @domain: the domain name to search for
* @family: address family
*
* Description:
* Look through the domain hash table searching for an entry to match @domain,
* return a pointer to a copy of the entry or NULL. The caller is responsible
* for ensuring that rcu_read_[un]lock() is called.
* with address family @family, 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_dom_map
*
netlbl_domhsh_getentry
(
const
char
*
domain
)
struct
netlbl_dom_map
*
netlbl_domhsh_getentry
(
const
char
*
domain
,
u16
family
)
{
return
netlbl_domhsh_search_def
(
domain
);
if
(
family
==
AF_UNSPEC
)
return
NULL
;
return
netlbl_domhsh_search_def
(
domain
,
family
);
}
/**
...
...
@@ -696,7 +891,7 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af4(const char *domain,
struct
netlbl_dom_map
*
dom_iter
;
struct
netlbl_af4list
*
addr_iter
;
dom_iter
=
netlbl_domhsh_search_def
(
domain
);
dom_iter
=
netlbl_domhsh_search_def
(
domain
,
AF_INET
);
if
(
dom_iter
==
NULL
)
return
NULL
;
...
...
@@ -726,7 +921,7 @@ struct netlbl_dommap_def *netlbl_domhsh_getentry_af6(const char *domain,
struct
netlbl_dom_map
*
dom_iter
;
struct
netlbl_af6list
*
addr_iter
;
dom_iter
=
netlbl_domhsh_search_def
(
domain
);
dom_iter
=
netlbl_domhsh_search_def
(
domain
,
AF_INET6
);
if
(
dom_iter
==
NULL
)
return
NULL
;
...
...
net/netlabel/netlabel_domainhash.h
View file @
d011a4d8
...
...
@@ -51,6 +51,7 @@ struct netlbl_dommap_def {
union
{
struct
netlbl_domaddr_map
*
addrsel
;
struct
cipso_v4_doi
*
cipso
;
struct
calipso_doi
*
calipso
;
};
};
#define netlbl_domhsh_addr4_entry(iter) \
...
...
@@ -70,6 +71,7 @@ struct netlbl_domaddr6_map {
struct
netlbl_dom_map
{
char
*
domain
;
u16
family
;
struct
netlbl_dommap_def
def
;
u32
valid
;
...
...
@@ -91,14 +93,23 @@ int netlbl_domhsh_remove_af4(const char *domain,
const
struct
in_addr
*
addr
,
const
struct
in_addr
*
mask
,
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
);
int
netlbl_domhsh_remove_af6
(
const
char
*
domain
,
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_domhsh_remove
(
const
char
*
domain
,
u16
family
,
struct
netlbl_audit
*
audit_info
);
int
netlbl_domhsh_remove_default
(
u16
family
,
struct
netlbl_audit
*
audit_info
);
struct
netlbl_dom_map
*
netlbl_domhsh_getentry
(
const
char
*
domain
,
u16
family
);
struct
netlbl_dommap_def
*
netlbl_domhsh_getentry_af4
(
const
char
*
domain
,
__be32
addr
);
#if IS_ENABLED(CONFIG_IPV6)
struct
netlbl_dommap_def
*
netlbl_domhsh_getentry_af6
(
const
char
*
domain
,
const
struct
in6_addr
*
addr
);
int
netlbl_domhsh_remove_af6
(
const
char
*
domain
,
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
struct
netlbl_audit
*
audit_info
);
#endif
/* IPv6 */
int
netlbl_domhsh_walk
(
u32
*
skip_bkt
,
...
...
net/netlabel/netlabel_kapi.c
View file @
d011a4d8
...
...
@@ -37,12 +37,14 @@
#include <net/ipv6.h>
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
#include <net/calipso.h>
#include <asm/bug.h>
#include <linux/atomic.h>
#include "netlabel_domainhash.h"
#include "netlabel_unlabeled.h"
#include "netlabel_cipso_v4.h"
#include "netlabel_calipso.h"
#include "netlabel_user.h"
#include "netlabel_mgmt.h"
#include "netlabel_addrlist.h"
...
...
@@ -72,12 +74,17 @@ int netlbl_cfg_map_del(const char *domain,
struct
netlbl_audit
*
audit_info
)
{
if
(
addr
==
NULL
&&
mask
==
NULL
)
{
return
netlbl_domhsh_remove
(
domain
,
audit_info
);
return
netlbl_domhsh_remove
(
domain
,
family
,
audit_info
);
}
else
if
(
addr
!=
NULL
&&
mask
!=
NULL
)
{
switch
(
family
)
{
case
AF_INET
:
return
netlbl_domhsh_remove_af4
(
domain
,
addr
,
mask
,
audit_info
);
#if IS_ENABLED(CONFIG_IPV6)
case
AF_INET6
:
return
netlbl_domhsh_remove_af6
(
domain
,
addr
,
mask
,
audit_info
);
#endif
/* IPv6 */
default:
return
-
EPFNOSUPPORT
;
}
...
...
@@ -119,6 +126,7 @@ int netlbl_cfg_unlbl_map_add(const char *domain,
if
(
entry
->
domain
==
NULL
)
goto
cfg_unlbl_map_add_failure
;
}
entry
->
family
=
family
;
if
(
addr
==
NULL
&&
mask
==
NULL
)
entry
->
def
.
type
=
NETLBL_NLTYPE_UNLABELED
;
...
...
@@ -345,6 +353,7 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_ATOMIC
);
if
(
entry
==
NULL
)
goto
out_entry
;
entry
->
family
=
AF_INET
;
if
(
domain
!=
NULL
)
{
entry
->
domain
=
kstrdup
(
domain
,
GFP_ATOMIC
);
if
(
entry
->
domain
==
NULL
)
...
...
@@ -399,6 +408,139 @@ int netlbl_cfg_cipsov4_map_add(u32 doi,
return
ret_val
;
}
/**
* netlbl_cfg_calipso_add - Add a new CALIPSO DOI definition
* @doi_def: CALIPSO DOI definition
* @audit_info: NetLabel audit information
*
* Description:
* Add a new CALIPSO DOI definition as defined by @doi_def. Returns zero on
* success and negative values on failure.
*
*/
int
netlbl_cfg_calipso_add
(
struct
calipso_doi
*
doi_def
,
struct
netlbl_audit
*
audit_info
)
{
#if IS_ENABLED(CONFIG_IPV6)
return
calipso_doi_add
(
doi_def
,
audit_info
);
#else
/* IPv6 */
return
-
ENOSYS
;
#endif
/* IPv6 */
}
/**
* netlbl_cfg_calipso_del - Remove an existing CALIPSO DOI definition
* @doi: CALIPSO DOI
* @audit_info: NetLabel audit information
*
* Description:
* Remove an existing CALIPSO DOI definition matching @doi. Returns zero on
* success and negative values on failure.
*
*/
void
netlbl_cfg_calipso_del
(
u32
doi
,
struct
netlbl_audit
*
audit_info
)
{
#if IS_ENABLED(CONFIG_IPV6)
calipso_doi_remove
(
doi
,
audit_info
);
#endif
/* IPv6 */
}
/**
* netlbl_cfg_calipso_map_add - Add a new CALIPSO DOI mapping
* @doi: the CALIPSO DOI
* @domain: the domain mapping to add
* @addr: IP address
* @mask: IP address mask
* @audit_info: NetLabel audit information
*
* Description:
* Add a new NetLabel/LSM domain mapping for the given CALIPSO DOI to the
* NetLabel subsystem. A @domain value of NULL adds a new default domain
* mapping. Returns zero on success, negative values on failure.
*
*/
int
netlbl_cfg_calipso_map_add
(
u32
doi
,
const
char
*
domain
,
const
struct
in6_addr
*
addr
,
const
struct
in6_addr
*
mask
,
struct
netlbl_audit
*
audit_info
)
{
#if IS_ENABLED(CONFIG_IPV6)
int
ret_val
=
-
ENOMEM
;
struct
calipso_doi
*
doi_def
;
struct
netlbl_dom_map
*
entry
;
struct
netlbl_domaddr_map
*
addrmap
=
NULL
;
struct
netlbl_domaddr6_map
*
addrinfo
=
NULL
;
doi_def
=
calipso_doi_getdef
(
doi
);
if
(
doi_def
==
NULL
)
return
-
ENOENT
;
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_ATOMIC
);
if
(
entry
==
NULL
)
goto
out_entry
;
entry
->
family
=
AF_INET6
;
if
(
domain
!=
NULL
)
{
entry
->
domain
=
kstrdup
(
domain
,
GFP_ATOMIC
);
if
(
entry
->
domain
==
NULL
)
goto
out_domain
;
}
if
(
addr
==
NULL
&&
mask
==
NULL
)
{
entry
->
def
.
calipso
=
doi_def
;
entry
->
def
.
type
=
NETLBL_NLTYPE_CALIPSO
;
}
else
if
(
addr
!=
NULL
&&
mask
!=
NULL
)
{
addrmap
=
kzalloc
(
sizeof
(
*
addrmap
),
GFP_ATOMIC
);
if
(
addrmap
==
NULL
)
goto
out_addrmap
;
INIT_LIST_HEAD
(
&
addrmap
->
list4
);
INIT_LIST_HEAD
(
&
addrmap
->
list6
);
addrinfo
=
kzalloc
(
sizeof
(
*
addrinfo
),
GFP_ATOMIC
);
if
(
addrinfo
==
NULL
)
goto
out_addrinfo
;
addrinfo
->
def
.
calipso
=
doi_def
;
addrinfo
->
def
.
type
=
NETLBL_NLTYPE_CALIPSO
;
addrinfo
->
list
.
addr
=
*
addr
;
addrinfo
->
list
.
addr
.
s6_addr32
[
0
]
&=
mask
->
s6_addr32
[
0
];
addrinfo
->
list
.
addr
.
s6_addr32
[
1
]
&=
mask
->
s6_addr32
[
1
];
addrinfo
->
list
.
addr
.
s6_addr32
[
2
]
&=
mask
->
s6_addr32
[
2
];
addrinfo
->
list
.
addr
.
s6_addr32
[
3
]
&=
mask
->
s6_addr32
[
3
];
addrinfo
->
list
.
mask
=
*
mask
;
addrinfo
->
list
.
valid
=
1
;
ret_val
=
netlbl_af6list_add
(
&
addrinfo
->
list
,
&
addrmap
->
list6
);
if
(
ret_val
!=
0
)
goto
cfg_calipso_map_add_failure
;
entry
->
def
.
addrsel
=
addrmap
;
entry
->
def
.
type
=
NETLBL_NLTYPE_ADDRSELECT
;
}
else
{
ret_val
=
-
EINVAL
;
goto
out_addrmap
;
}
ret_val
=
netlbl_domhsh_add
(
entry
,
audit_info
);
if
(
ret_val
!=
0
)
goto
cfg_calipso_map_add_failure
;
return
0
;
cfg_calipso_map_add_failure:
kfree
(
addrinfo
);
out_addrinfo:
kfree
(
addrmap
);
out_addrmap:
kfree
(
entry
->
domain
);
out_domain:
kfree
(
entry
);
out_entry:
calipso_doi_putdef
(
doi_def
);
return
ret_val
;
#else
/* IPv6 */
return
-
ENOSYS
;
#endif
/* IPv6 */
}
/*
* Security Attribute Functions
*/
...
...
@@ -519,6 +661,7 @@ int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset)
return
-
ENOENT
;
}
EXPORT_SYMBOL
(
netlbl_catmap_walk
);
/**
* netlbl_catmap_walkrng - Find the end of a string of set bits
...
...
@@ -609,20 +752,19 @@ int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap,
off
=
catmap
->
startbit
;
*
offset
=
off
;
}
iter
=
_netlbl_catmap_getnode
(
&
catmap
,
off
,
_CM_F_
NONE
,
0
);
iter
=
_netlbl_catmap_getnode
(
&
catmap
,
off
,
_CM_F_
WALK
,
0
);
if
(
iter
==
NULL
)
{
*
offset
=
(
u32
)
-
1
;
return
0
;
}
if
(
off
<
iter
->
startbit
)
{
off
=
iter
->
startbit
;
*
offset
=
off
;
*
offset
=
iter
->
startbit
;
off
=
0
;
}
else
off
-=
iter
->
startbit
;
idx
=
off
/
NETLBL_CATMAP_MAPSIZE
;
*
bitmap
=
iter
->
bitmap
[
idx
]
>>
(
off
%
NETLBL_CATMAP_SIZE
);
*
bitmap
=
iter
->
bitmap
[
idx
]
>>
(
off
%
NETLBL_CATMAP_
MAP
SIZE
);
return
0
;
}
...
...
@@ -655,6 +797,7 @@ int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap,
return
0
;
}
EXPORT_SYMBOL
(
netlbl_catmap_setbit
);
/**
* netlbl_catmap_setrng - Set a range of bits in a LSM secattr catmap
...
...
@@ -727,6 +870,76 @@ int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap,
return
0
;
}
/* Bitmap functions
*/
/**
* netlbl_bitmap_walk - Walk a bitmap looking for a bit
* @bitmap: the bitmap
* @bitmap_len: length in bits
* @offset: starting offset
* @state: if non-zero, look for a set (1) bit else look for a cleared (0) bit
*
* Description:
* Starting at @offset, walk the bitmap from left to right until either the
* desired bit is found or we reach the end. Return the bit offset, -1 if
* not found, or -2 if error.
*/
int
netlbl_bitmap_walk
(
const
unsigned
char
*
bitmap
,
u32
bitmap_len
,
u32
offset
,
u8
state
)
{
u32
bit_spot
;
u32
byte_offset
;
unsigned
char
bitmask
;
unsigned
char
byte
;
byte_offset
=
offset
/
8
;
byte
=
bitmap
[
byte_offset
];
bit_spot
=
offset
;
bitmask
=
0x80
>>
(
offset
%
8
);
while
(
bit_spot
<
bitmap_len
)
{
if
((
state
&&
(
byte
&
bitmask
)
==
bitmask
)
||
(
state
==
0
&&
(
byte
&
bitmask
)
==
0
))
return
bit_spot
;
bit_spot
++
;
bitmask
>>=
1
;
if
(
bitmask
==
0
)
{
byte
=
bitmap
[
++
byte_offset
];
bitmask
=
0x80
;
}
}
return
-
1
;
}
EXPORT_SYMBOL
(
netlbl_bitmap_walk
);
/**
* netlbl_bitmap_setbit - Sets a single bit in a bitmap
* @bitmap: the bitmap
* @bit: the bit
* @state: if non-zero, set the bit (1) else clear the bit (0)
*
* Description:
* Set a single bit in the bitmask. Returns zero on success, negative values
* on error.
*/
void
netlbl_bitmap_setbit
(
unsigned
char
*
bitmap
,
u32
bit
,
u8
state
)
{
u32
byte_spot
;
u8
bitmask
;
/* gcc always rounds to zero when doing integer division */
byte_spot
=
bit
/
8
;
bitmask
=
0x80
>>
(
bit
%
8
);
if
(
state
)
bitmap
[
byte_spot
]
|=
bitmask
;
else
bitmap
[
byte_spot
]
&=
~
bitmask
;
}
EXPORT_SYMBOL
(
netlbl_bitmap_setbit
);
/*
* LSM Functions
*/
...
...
@@ -774,7 +987,7 @@ int netlbl_sock_setattr(struct sock *sk,
struct
netlbl_dom_map
*
dom_entry
;
rcu_read_lock
();
dom_entry
=
netlbl_domhsh_getentry
(
secattr
->
domain
);
dom_entry
=
netlbl_domhsh_getentry
(
secattr
->
domain
,
family
);
if
(
dom_entry
==
NULL
)
{
ret_val
=
-
ENOENT
;
goto
socket_setattr_return
;
...
...
@@ -799,9 +1012,21 @@ int netlbl_sock_setattr(struct sock *sk,
break
;
#if IS_ENABLED(CONFIG_IPV6)
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
;
switch
(
dom_entry
->
def
.
type
)
{
case
NETLBL_NLTYPE_ADDRSELECT
:
ret_val
=
-
EDESTADDRREQ
;
break
;
case
NETLBL_NLTYPE_CALIPSO
:
ret_val
=
calipso_sock_setattr
(
sk
,
dom_entry
->
def
.
calipso
,
secattr
);
break
;
case
NETLBL_NLTYPE_UNLABELED
:
ret_val
=
0
;
break
;
default:
ret_val
=
-
ENOENT
;
}
break
;
#endif
/* IPv6 */
default:
...
...
@@ -824,7 +1049,16 @@ int netlbl_sock_setattr(struct sock *sk,
*/
void
netlbl_sock_delattr
(
struct
sock
*
sk
)
{
cipso_v4_sock_delattr
(
sk
);
switch
(
sk
->
sk_family
)
{
case
AF_INET
:
cipso_v4_sock_delattr
(
sk
);
break
;
#if IS_ENABLED(CONFIG_IPV6)
case
AF_INET6
:
calipso_sock_delattr
(
sk
);
break
;
#endif
/* IPv6 */
}
}
/**
...
...
@@ -850,7 +1084,7 @@ int netlbl_sock_getattr(struct sock *sk,
break
;
#if IS_ENABLED(CONFIG_IPV6)
case
AF_INET6
:
ret_val
=
-
ENOMSG
;
ret_val
=
calipso_sock_getattr
(
sk
,
secattr
)
;
break
;
#endif
/* IPv6 */
default:
...
...
@@ -878,6 +1112,9 @@ int netlbl_conn_setattr(struct sock *sk,
{
int
ret_val
;
struct
sockaddr_in
*
addr4
;
#if IS_ENABLED(CONFIG_IPV6)
struct
sockaddr_in6
*
addr6
;
#endif
struct
netlbl_dommap_def
*
entry
;
rcu_read_lock
();
...
...
@@ -898,7 +1135,7 @@ int netlbl_conn_setattr(struct sock *sk,
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
);
netlbl
_sock_delattr
(
sk
);
ret_val
=
0
;
break
;
default:
...
...
@@ -907,9 +1144,27 @@ int netlbl_conn_setattr(struct sock *sk,
break
;
#if IS_ENABLED(CONFIG_IPV6)
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
;
addr6
=
(
struct
sockaddr_in6
*
)
addr
;
entry
=
netlbl_domhsh_getentry_af6
(
secattr
->
domain
,
&
addr6
->
sin6_addr
);
if
(
entry
==
NULL
)
{
ret_val
=
-
ENOENT
;
goto
conn_setattr_return
;
}
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_CALIPSO
:
ret_val
=
calipso_sock_setattr
(
sk
,
entry
->
calipso
,
secattr
);
break
;
case
NETLBL_NLTYPE_UNLABELED
:
/* just delete the protocols we support for right now
* but we could remove other protocols if needed */
netlbl_sock_delattr
(
sk
);
ret_val
=
0
;
break
;
default:
ret_val
=
-
ENOENT
;
}
break
;
#endif
/* IPv6 */
default:
...
...
@@ -936,12 +1191,13 @@ int netlbl_req_setattr(struct request_sock *req,
{
int
ret_val
;
struct
netlbl_dommap_def
*
entry
;
struct
inet_request_sock
*
ireq
=
inet_rsk
(
req
);
rcu_read_lock
();
switch
(
req
->
rsk_ops
->
family
)
{
case
AF_INET
:
entry
=
netlbl_domhsh_getentry_af4
(
secattr
->
domain
,
i
net_rsk
(
req
)
->
ir_rmt_addr
);
i
req
->
ir_rmt_addr
);
if
(
entry
==
NULL
)
{
ret_val
=
-
ENOENT
;
goto
req_setattr_return
;
...
...
@@ -952,9 +1208,7 @@ int netlbl_req_setattr(struct request_sock *req,
entry
->
cipso
,
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_req_delattr
(
req
);
netlbl_req_delattr
(
req
);
ret_val
=
0
;
break
;
default:
...
...
@@ -963,9 +1217,24 @@ int netlbl_req_setattr(struct request_sock *req,
break
;
#if IS_ENABLED(CONFIG_IPV6)
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
;
entry
=
netlbl_domhsh_getentry_af6
(
secattr
->
domain
,
&
ireq
->
ir_v6_rmt_addr
);
if
(
entry
==
NULL
)
{
ret_val
=
-
ENOENT
;
goto
req_setattr_return
;
}
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_CALIPSO
:
ret_val
=
calipso_req_setattr
(
req
,
entry
->
calipso
,
secattr
);
break
;
case
NETLBL_NLTYPE_UNLABELED
:
netlbl_req_delattr
(
req
);
ret_val
=
0
;
break
;
default:
ret_val
=
-
ENOENT
;
}
break
;
#endif
/* IPv6 */
default:
...
...
@@ -987,7 +1256,16 @@ int netlbl_req_setattr(struct request_sock *req,
*/
void
netlbl_req_delattr
(
struct
request_sock
*
req
)
{
cipso_v4_req_delattr
(
req
);
switch
(
req
->
rsk_ops
->
family
)
{
case
AF_INET
:
cipso_v4_req_delattr
(
req
);
break
;
#if IS_ENABLED(CONFIG_IPV6)
case
AF_INET6
:
calipso_req_delattr
(
req
);
break
;
#endif
/* IPv6 */
}
}
/**
...
...
@@ -1007,13 +1285,17 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
{
int
ret_val
;
struct
iphdr
*
hdr4
;
#if IS_ENABLED(CONFIG_IPV6)
struct
ipv6hdr
*
hdr6
;
#endif
struct
netlbl_dommap_def
*
entry
;
rcu_read_lock
();
switch
(
family
)
{
case
AF_INET
:
hdr4
=
ip_hdr
(
skb
);
entry
=
netlbl_domhsh_getentry_af4
(
secattr
->
domain
,
hdr4
->
daddr
);
entry
=
netlbl_domhsh_getentry_af4
(
secattr
->
domain
,
hdr4
->
daddr
);
if
(
entry
==
NULL
)
{
ret_val
=
-
ENOENT
;
goto
skbuff_setattr_return
;
...
...
@@ -1034,9 +1316,26 @@ int netlbl_skbuff_setattr(struct sk_buff *skb,
break
;
#if IS_ENABLED(CONFIG_IPV6)
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
;
hdr6
=
ipv6_hdr
(
skb
);
entry
=
netlbl_domhsh_getentry_af6
(
secattr
->
domain
,
&
hdr6
->
daddr
);
if
(
entry
==
NULL
)
{
ret_val
=
-
ENOENT
;
goto
skbuff_setattr_return
;
}
switch
(
entry
->
type
)
{
case
NETLBL_NLTYPE_CALIPSO
:
ret_val
=
calipso_skbuff_setattr
(
skb
,
entry
->
calipso
,
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
=
calipso_skbuff_delattr
(
skb
);
break
;
default:
ret_val
=
-
ENOENT
;
}
break
;
#endif
/* IPv6 */
default:
...
...
@@ -1075,6 +1374,9 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
break
;
#if IS_ENABLED(CONFIG_IPV6)
case
AF_INET6
:
ptr
=
calipso_optptr
(
skb
);
if
(
ptr
&&
calipso_getattr
(
ptr
,
secattr
)
==
0
)
return
0
;
break
;
#endif
/* IPv6 */
}
...
...
@@ -1085,6 +1387,7 @@ int netlbl_skbuff_getattr(const struct sk_buff *skb,
/**
* netlbl_skbuff_err - Handle a LSM error on a sk_buff
* @skb: the packet
* @family: the family
* @error: the error code
* @gateway: true if host is acting as a gateway, false otherwise
*
...
...
@@ -1094,10 +1397,14 @@ 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
,
int
gateway
)
void
netlbl_skbuff_err
(
struct
sk_buff
*
skb
,
u16
family
,
int
error
,
int
gateway
)
{
if
(
cipso_v4_optptr
(
skb
))
cipso_v4_error
(
skb
,
error
,
gateway
);
switch
(
family
)
{
case
AF_INET
:
if
(
cipso_v4_optptr
(
skb
))
cipso_v4_error
(
skb
,
error
,
gateway
);
break
;
}
}
/**
...
...
@@ -1112,11 +1419,15 @@ void netlbl_skbuff_err(struct sk_buff *skb, int error, int gateway)
void
netlbl_cache_invalidate
(
void
)
{
cipso_v4_cache_invalidate
();
#if IS_ENABLED(CONFIG_IPV6)
calipso_cache_invalidate
();
#endif
/* IPv6 */
}
/**
* netlbl_cache_add - Add an entry to a NetLabel protocol cache
* @skb: the packet
* @family: the family
* @secattr: the packet's security attributes
*
* Description:
...
...
@@ -1125,7 +1436,7 @@ void netlbl_cache_invalidate(void)
* values on error.
*
*/
int
netlbl_cache_add
(
const
struct
sk_buff
*
skb
,
int
netlbl_cache_add
(
const
struct
sk_buff
*
skb
,
u16
family
,
const
struct
netlbl_lsm_secattr
*
secattr
)
{
unsigned
char
*
ptr
;
...
...
@@ -1133,10 +1444,20 @@ int netlbl_cache_add(const struct sk_buff *skb,
if
((
secattr
->
flags
&
NETLBL_SECATTR_CACHE
)
==
0
)
return
-
ENOMSG
;
ptr
=
cipso_v4_optptr
(
skb
);
if
(
ptr
)
return
cipso_v4_cache_add
(
ptr
,
secattr
);
switch
(
family
)
{
case
AF_INET
:
ptr
=
cipso_v4_optptr
(
skb
);
if
(
ptr
)
return
cipso_v4_cache_add
(
ptr
,
secattr
);
break
;
#if IS_ENABLED(CONFIG_IPV6)
case
AF_INET6
:
ptr
=
calipso_optptr
(
skb
);
if
(
ptr
)
return
calipso_cache_add
(
ptr
,
secattr
);
break
;
#endif
/* IPv6 */
}
return
-
ENOMSG
;
}
...
...
@@ -1161,6 +1482,7 @@ struct audit_buffer *netlbl_audit_start(int type,
{
return
netlbl_audit_start_common
(
type
,
audit_info
);
}
EXPORT_SYMBOL
(
netlbl_audit_start
);
/*
* Setup Functions
...
...
net/netlabel/netlabel_mgmt.c
View file @
d011a4d8
...
...
@@ -41,8 +41,10 @@
#include <net/ipv6.h>
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
#include <net/calipso.h>
#include <linux/atomic.h>
#include "netlabel_calipso.h"
#include "netlabel_domainhash.h"
#include "netlabel_user.h"
#include "netlabel_mgmt.h"
...
...
@@ -72,6 +74,8 @@ static const struct nla_policy netlbl_mgmt_genl_policy[NLBL_MGMT_A_MAX + 1] = {
[
NLBL_MGMT_A_PROTOCOL
]
=
{
.
type
=
NLA_U32
},
[
NLBL_MGMT_A_VERSION
]
=
{
.
type
=
NLA_U32
},
[
NLBL_MGMT_A_CV4DOI
]
=
{
.
type
=
NLA_U32
},
[
NLBL_MGMT_A_FAMILY
]
=
{
.
type
=
NLA_U16
},
[
NLBL_MGMT_A_CLPDOI
]
=
{
.
type
=
NLA_U32
},
};
/*
...
...
@@ -95,6 +99,9 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
int
ret_val
=
-
EINVAL
;
struct
netlbl_domaddr_map
*
addrmap
=
NULL
;
struct
cipso_v4_doi
*
cipsov4
=
NULL
;
#if IS_ENABLED(CONFIG_IPV6)
struct
calipso_doi
*
calipso
=
NULL
;
#endif
u32
tmp_val
;
struct
netlbl_dom_map
*
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_KERNEL
);
...
...
@@ -119,6 +126,11 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
switch
(
entry
->
def
.
type
)
{
case
NETLBL_NLTYPE_UNLABELED
:
if
(
info
->
attrs
[
NLBL_MGMT_A_FAMILY
])
entry
->
family
=
nla_get_u16
(
info
->
attrs
[
NLBL_MGMT_A_FAMILY
]);
else
entry
->
family
=
AF_UNSPEC
;
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
if
(
!
info
->
attrs
[
NLBL_MGMT_A_CV4DOI
])
...
...
@@ -128,12 +140,30 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
cipsov4
=
cipso_v4_doi_getdef
(
tmp_val
);
if
(
cipsov4
==
NULL
)
goto
add_free_domain
;
entry
->
family
=
AF_INET
;
entry
->
def
.
cipso
=
cipsov4
;
break
;
#if IS_ENABLED(CONFIG_IPV6)
case
NETLBL_NLTYPE_CALIPSO
:
if
(
!
info
->
attrs
[
NLBL_MGMT_A_CLPDOI
])
goto
add_free_domain
;
tmp_val
=
nla_get_u32
(
info
->
attrs
[
NLBL_MGMT_A_CLPDOI
]);
calipso
=
calipso_doi_getdef
(
tmp_val
);
if
(
calipso
==
NULL
)
goto
add_free_domain
;
entry
->
family
=
AF_INET6
;
entry
->
def
.
calipso
=
calipso
;
break
;
#endif
/* IPv6 */
default:
goto
add_free_domain
;
}
if
((
entry
->
family
==
AF_INET
&&
info
->
attrs
[
NLBL_MGMT_A_IPV6ADDR
])
||
(
entry
->
family
==
AF_INET6
&&
info
->
attrs
[
NLBL_MGMT_A_IPV4ADDR
]))
goto
add_doi_put_def
;
if
(
info
->
attrs
[
NLBL_MGMT_A_IPV4ADDR
])
{
struct
in_addr
*
addr
;
struct
in_addr
*
mask
;
...
...
@@ -178,6 +208,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
goto
add_free_addrmap
;
}
entry
->
family
=
AF_INET
;
entry
->
def
.
type
=
NETLBL_NLTYPE_ADDRSELECT
;
entry
->
def
.
addrsel
=
addrmap
;
#if IS_ENABLED(CONFIG_IPV6)
...
...
@@ -220,6 +251,8 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
map
->
list
.
mask
=
*
mask
;
map
->
list
.
valid
=
1
;
map
->
def
.
type
=
entry
->
def
.
type
;
if
(
calipso
)
map
->
def
.
calipso
=
calipso
;
ret_val
=
netlbl_af6list_add
(
&
map
->
list
,
&
addrmap
->
list6
);
if
(
ret_val
!=
0
)
{
...
...
@@ -227,6 +260,7 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
goto
add_free_addrmap
;
}
entry
->
family
=
AF_INET6
;
entry
->
def
.
type
=
NETLBL_NLTYPE_ADDRSELECT
;
entry
->
def
.
addrsel
=
addrmap
;
#endif
/* IPv6 */
...
...
@@ -242,6 +276,9 @@ static int netlbl_mgmt_add_common(struct genl_info *info,
kfree
(
addrmap
);
add_doi_put_def:
cipso_v4_doi_putdef
(
cipsov4
);
#if IS_ENABLED(CONFIG_IPV6)
calipso_doi_putdef
(
calipso
);
#endif
add_free_domain:
kfree
(
entry
->
domain
);
add_free_entry:
...
...
@@ -278,6 +315,10 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
return
ret_val
;
}
ret_val
=
nla_put_u16
(
skb
,
NLBL_MGMT_A_FAMILY
,
entry
->
family
);
if
(
ret_val
!=
0
)
return
ret_val
;
switch
(
entry
->
def
.
type
)
{
case
NETLBL_NLTYPE_ADDRSELECT
:
nla_a
=
nla_nest_start
(
skb
,
NLBL_MGMT_A_SELECTORLIST
);
...
...
@@ -340,6 +381,15 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
if
(
ret_val
!=
0
)
return
ret_val
;
switch
(
map6
->
def
.
type
)
{
case
NETLBL_NLTYPE_CALIPSO
:
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_CLPDOI
,
map6
->
def
.
calipso
->
doi
);
if
(
ret_val
!=
0
)
return
ret_val
;
break
;
}
nla_nest_end
(
skb
,
nla_b
);
}
#endif
/* IPv6 */
...
...
@@ -347,15 +397,25 @@ static int netlbl_mgmt_listentry(struct sk_buff *skb,
nla_nest_end
(
skb
,
nla_a
);
break
;
case
NETLBL_NLTYPE_UNLABELED
:
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_PROTOCOL
,
entry
->
def
.
type
);
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_PROTOCOL
,
entry
->
def
.
type
);
break
;
case
NETLBL_NLTYPE_CIPSOV4
:
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_PROTOCOL
,
entry
->
def
.
type
);
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_PROTOCOL
,
entry
->
def
.
type
);
if
(
ret_val
!=
0
)
return
ret_val
;
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_CV4DOI
,
entry
->
def
.
cipso
->
doi
);
break
;
case
NETLBL_NLTYPE_CALIPSO
:
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_PROTOCOL
,
entry
->
def
.
type
);
if
(
ret_val
!=
0
)
return
ret_val
;
ret_val
=
nla_put_u32
(
skb
,
NLBL_MGMT_A_CLPDOI
,
entry
->
def
.
calipso
->
doi
);
break
;
}
return
ret_val
;
...
...
@@ -418,7 +478,7 @@ static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
netlbl_netlink_auditinfo
(
skb
,
&
audit_info
);
domain
=
nla_data
(
info
->
attrs
[
NLBL_MGMT_A_DOMAIN
]);
return
netlbl_domhsh_remove
(
domain
,
&
audit_info
);
return
netlbl_domhsh_remove
(
domain
,
AF_UNSPEC
,
&
audit_info
);
}
/**
...
...
@@ -536,7 +596,7 @@ static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
netlbl_netlink_auditinfo
(
skb
,
&
audit_info
);
return
netlbl_domhsh_remove_default
(
&
audit_info
);
return
netlbl_domhsh_remove_default
(
AF_UNSPEC
,
&
audit_info
);
}
/**
...
...
@@ -556,6 +616,12 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
struct
sk_buff
*
ans_skb
=
NULL
;
void
*
data
;
struct
netlbl_dom_map
*
entry
;
u16
family
;
if
(
info
->
attrs
[
NLBL_MGMT_A_FAMILY
])
family
=
nla_get_u16
(
info
->
attrs
[
NLBL_MGMT_A_FAMILY
]);
else
family
=
AF_INET
;
ans_skb
=
nlmsg_new
(
NLMSG_DEFAULT_SIZE
,
GFP_KERNEL
);
if
(
ans_skb
==
NULL
)
...
...
@@ -566,7 +632,7 @@ static int netlbl_mgmt_listdef(struct sk_buff *skb, struct genl_info *info)
goto
listdef_failure
;
rcu_read_lock
();
entry
=
netlbl_domhsh_getentry
(
NULL
);
entry
=
netlbl_domhsh_getentry
(
NULL
,
family
);
if
(
entry
==
NULL
)
{
ret_val
=
-
ENOENT
;
goto
listdef_failure_lock
;
...
...
@@ -651,6 +717,15 @@ static int netlbl_mgmt_protocols(struct sk_buff *skb,
goto
protocols_return
;
protos_sent
++
;
}
#if IS_ENABLED(CONFIG_IPV6)
if
(
protos_sent
==
2
)
{
if
(
netlbl_mgmt_protocols_cb
(
skb
,
cb
,
NETLBL_NLTYPE_CALIPSO
)
<
0
)
goto
protocols_return
;
protos_sent
++
;
}
#endif
protocols_return:
cb
->
args
[
0
]
=
protos_sent
;
...
...
net/netlabel/netlabel_mgmt.h
View file @
d011a4d8
...
...
@@ -58,7 +58,10 @@
*
* NLBL_MGMT_A_CV4DOI
*
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required,
* however the following attribute may optionally be sent:
*
* NLBL_MGMT_A_FAMILY
*
* o REMOVE:
* Sent by an application to remove a domain mapping from the NetLabel
...
...
@@ -77,6 +80,7 @@
* Required attributes:
*
* NLBL_MGMT_A_DOMAIN
* NLBL_MGMT_A_FAMILY
*
* If the IP address selectors are not used the following attribute is
* required:
...
...
@@ -108,7 +112,10 @@
*
* NLBL_MGMT_A_CV4DOI
*
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required.
* If using NETLBL_NLTYPE_UNLABELED no other attributes are required,
* however the following attribute may optionally be sent:
*
* NLBL_MGMT_A_FAMILY
*
* o REMOVEDEF:
* Sent by an application to remove the default domain mapping from the
...
...
@@ -117,13 +124,17 @@
* o LISTDEF:
* This message can be sent either from an application or by the kernel in
* response to an application generated LISTDEF message. When sent by an
* application there is no payload. On success the kernel should send a
* response using the following format.
* application there may be an optional payload.
*
* If the IP address selectors are not used the following attribute is
* NLBL_MGMT_A_FAMILY
*
* On success the kernel should send a response using the following format:
*
* If the IP address selectors are not used the following attributes are
* required:
*
* NLBL_MGMT_A_PROTOCOL
* NLBL_MGMT_A_FAMILY
*
* If the IP address selectors are used then the following attritbute is
* required:
...
...
@@ -209,6 +220,12 @@ enum {
/* (NLA_NESTED)
* the selector list, there must be at least one
* NLBL_MGMT_A_ADDRSELECTOR attribute */
NLBL_MGMT_A_FAMILY
,
/* (NLA_U16)
* The address family */
NLBL_MGMT_A_CLPDOI
,
/* (NLA_U32)
* the CALIPSO DOI value */
__NLBL_MGMT_A_MAX
,
};
#define NLBL_MGMT_A_MAX (__NLBL_MGMT_A_MAX - 1)
...
...
net/netlabel/netlabel_unlabeled.c
View file @
d011a4d8
...
...
@@ -116,8 +116,8 @@ struct netlbl_unlhsh_walk_arg {
static
DEFINE_SPINLOCK
(
netlbl_unlhsh_lock
);
#define netlbl_unlhsh_rcu_deref(p) \
rcu_dereference_check(p, lockdep_is_held(&netlbl_unlhsh_lock))
static
struct
netlbl_unlhsh_tbl
*
netlbl_unlhsh
;
static
struct
netlbl_unlhsh_iface
*
netlbl_unlhsh_def
;
static
struct
netlbl_unlhsh_tbl
__rcu
*
netlbl_unlhsh
;
static
struct
netlbl_unlhsh_iface
__rcu
*
netlbl_unlhsh_def
;
/* Accept unlabeled packets flag */
static
u8
netlabel_unlabel_acceptflg
;
...
...
@@ -1537,6 +1537,7 @@ int __init netlbl_unlabel_defconf(void)
entry
=
kzalloc
(
sizeof
(
*
entry
),
GFP_KERNEL
);
if
(
entry
==
NULL
)
return
-
ENOMEM
;
entry
->
family
=
AF_UNSPEC
;
entry
->
def
.
type
=
NETLBL_NLTYPE_UNLABELED
;
ret_val
=
netlbl_domhsh_add_default
(
entry
,
&
audit_info
);
if
(
ret_val
!=
0
)
...
...
net/netlabel/netlabel_user.c
View file @
d011a4d8
...
...
@@ -44,6 +44,7 @@
#include "netlabel_mgmt.h"
#include "netlabel_unlabeled.h"
#include "netlabel_cipso_v4.h"
#include "netlabel_calipso.h"
#include "netlabel_user.h"
/*
...
...
@@ -71,6 +72,10 @@ int __init netlbl_netlink_init(void)
if
(
ret_val
!=
0
)
return
ret_val
;
ret_val
=
netlbl_calipso_genl_init
();
if
(
ret_val
!=
0
)
return
ret_val
;
return
netlbl_unlabel_genl_init
();
}
...
...
security/selinux/hooks.c
View file @
d011a4d8
...
...
@@ -4604,13 +4604,13 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
err
=
selinux_inet_sys_rcv_skb
(
sock_net
(
sk
),
skb
->
skb_iif
,
addrp
,
family
,
peer_sid
,
&
ad
);
if
(
err
)
{
selinux_netlbl_err
(
skb
,
err
,
0
);
selinux_netlbl_err
(
skb
,
family
,
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
);
selinux_netlbl_err
(
skb
,
family
,
err
,
0
);
return
err
;
}
}
...
...
@@ -4978,7 +4978,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb,
err
=
selinux_inet_sys_rcv_skb
(
dev_net
(
indev
),
indev
->
ifindex
,
addrp
,
family
,
peer_sid
,
&
ad
);
if
(
err
)
{
selinux_netlbl_err
(
skb
,
err
,
1
);
selinux_netlbl_err
(
skb
,
family
,
err
,
1
);
return
NF_DROP
;
}
}
...
...
@@ -5064,6 +5064,15 @@ static unsigned int selinux_ipv4_output(void *priv,
return
selinux_ip_output
(
skb
,
PF_INET
);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static
unsigned
int
selinux_ipv6_output
(
void
*
priv
,
struct
sk_buff
*
skb
,
const
struct
nf_hook_state
*
state
)
{
return
selinux_ip_output
(
skb
,
PF_INET6
);
}
#endif
/* IPV6 */
static
unsigned
int
selinux_ip_postroute_compat
(
struct
sk_buff
*
skb
,
int
ifindex
,
u16
family
)
...
...
@@ -6298,6 +6307,12 @@ static struct nf_hook_ops selinux_nf_ops[] = {
.
hooknum
=
NF_INET_FORWARD
,
.
priority
=
NF_IP6_PRI_SELINUX_FIRST
,
},
{
.
hook
=
selinux_ipv6_output
,
.
pf
=
NFPROTO_IPV6
,
.
hooknum
=
NF_INET_LOCAL_OUT
,
.
priority
=
NF_IP6_PRI_SELINUX_FIRST
,
},
#endif
/* IPV6 */
};
...
...
security/selinux/include/netlabel.h
View file @
d011a4d8
...
...
@@ -40,7 +40,8 @@
#ifdef CONFIG_NETLABEL
void
selinux_netlbl_cache_invalidate
(
void
);
void
selinux_netlbl_err
(
struct
sk_buff
*
skb
,
int
error
,
int
gateway
);
void
selinux_netlbl_err
(
struct
sk_buff
*
skb
,
u16
family
,
int
error
,
int
gateway
);
void
selinux_netlbl_sk_security_free
(
struct
sk_security_struct
*
sksec
);
void
selinux_netlbl_sk_security_reset
(
struct
sk_security_struct
*
sksec
);
...
...
@@ -72,6 +73,7 @@ static inline void selinux_netlbl_cache_invalidate(void)
}
static
inline
void
selinux_netlbl_err
(
struct
sk_buff
*
skb
,
u16
family
,
int
error
,
int
gateway
)
{
...
...
security/selinux/netlabel.c
View file @
d011a4d8
...
...
@@ -54,6 +54,7 @@
*
*/
static
int
selinux_netlbl_sidlookup_cached
(
struct
sk_buff
*
skb
,
u16
family
,
struct
netlbl_lsm_secattr
*
secattr
,
u32
*
sid
)
{
...
...
@@ -63,7 +64,7 @@ static int selinux_netlbl_sidlookup_cached(struct sk_buff *skb,
if
(
rc
==
0
&&
(
secattr
->
flags
&
NETLBL_SECATTR_CACHEABLE
)
&&
(
secattr
->
flags
&
NETLBL_SECATTR_CACHE
))
netlbl_cache_add
(
skb
,
secattr
);
netlbl_cache_add
(
skb
,
family
,
secattr
);
return
rc
;
}
...
...
@@ -151,9 +152,9 @@ void selinux_netlbl_cache_invalidate(void)
* 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
)
void
selinux_netlbl_err
(
struct
sk_buff
*
skb
,
u16
family
,
int
error
,
int
gateway
)
{
netlbl_skbuff_err
(
skb
,
error
,
gateway
);
netlbl_skbuff_err
(
skb
,
family
,
error
,
gateway
);
}
/**
...
...
@@ -214,7 +215,8 @@ int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
netlbl_secattr_init
(
&
secattr
);
rc
=
netlbl_skbuff_getattr
(
skb
,
family
,
&
secattr
);
if
(
rc
==
0
&&
secattr
.
flags
!=
NETLBL_SECATTR_NONE
)
rc
=
selinux_netlbl_sidlookup_cached
(
skb
,
&
secattr
,
sid
);
rc
=
selinux_netlbl_sidlookup_cached
(
skb
,
family
,
&
secattr
,
sid
);
else
*
sid
=
SECSID_NULL
;
*
type
=
secattr
.
type
;
...
...
@@ -284,7 +286,7 @@ int selinux_netlbl_inet_conn_request(struct request_sock *req, u16 family)
int
rc
;
struct
netlbl_lsm_secattr
secattr
;
if
(
family
!=
PF_INET
)
if
(
family
!=
PF_INET
&&
family
!=
PF_INET6
)
return
0
;
netlbl_secattr_init
(
&
secattr
);
...
...
@@ -333,7 +335,7 @@ int selinux_netlbl_socket_post_create(struct sock *sk, u16 family)
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
struct
netlbl_lsm_secattr
*
secattr
;
if
(
family
!=
PF_INET
)
if
(
family
!=
PF_INET
&&
family
!=
PF_INET6
)
return
0
;
secattr
=
selinux_netlbl_sock_genattr
(
sk
);
...
...
@@ -382,7 +384,8 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
netlbl_secattr_init
(
&
secattr
);
rc
=
netlbl_skbuff_getattr
(
skb
,
family
,
&
secattr
);
if
(
rc
==
0
&&
secattr
.
flags
!=
NETLBL_SECATTR_NONE
)
rc
=
selinux_netlbl_sidlookup_cached
(
skb
,
&
secattr
,
&
nlbl_sid
);
rc
=
selinux_netlbl_sidlookup_cached
(
skb
,
family
,
&
secattr
,
&
nlbl_sid
);
else
nlbl_sid
=
SECINITSID_UNLABELED
;
netlbl_secattr_destroy
(
&
secattr
);
...
...
@@ -405,10 +408,25 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
return
0
;
if
(
nlbl_sid
!=
SECINITSID_UNLABELED
)
netlbl_skbuff_err
(
skb
,
rc
,
0
);
netlbl_skbuff_err
(
skb
,
family
,
rc
,
0
);
return
rc
;
}
/**
* selinux_netlbl_option - Is this a NetLabel option
* @level: the socket level or protocol
* @optname: the socket option name
*
* Description:
* Returns true if @level and @optname refer to a NetLabel option.
* Helper for selinux_netlbl_socket_setsockopt().
*/
static
inline
int
selinux_netlbl_option
(
int
level
,
int
optname
)
{
return
(
level
==
IPPROTO_IP
&&
optname
==
IP_OPTIONS
)
||
(
level
==
IPPROTO_IPV6
&&
optname
==
IPV6_HOPOPTS
);
}
/**
* selinux_netlbl_socket_setsockopt - Do not allow users to remove a NetLabel
* @sock: the socket
...
...
@@ -431,7 +449,7 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
struct
netlbl_lsm_secattr
secattr
;
if
(
level
==
IPPROTO_IP
&&
optname
==
IP_OPTIONS
&&
if
(
selinux_netlbl_option
(
level
,
optname
)
&&
(
sksec
->
nlbl_state
==
NLBL_LABELED
||
sksec
->
nlbl_state
==
NLBL_CONNLABELED
))
{
netlbl_secattr_init
(
&
secattr
);
...
...
security/selinux/selinuxfs.c
View file @
d011a4d8
...
...
@@ -1347,7 +1347,7 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
{
char
*
page
;
ssize_t
ret
;
int
new_value
;
unsigned
int
new_value
;
ret
=
task_has_security
(
current
,
SECURITY__SETSECPARAM
);
if
(
ret
)
...
...
security/selinux/ss/ebitmap.c
View file @
d011a4d8
...
...
@@ -165,7 +165,7 @@ int ebitmap_netlbl_import(struct ebitmap *ebmap,
e_iter
=
kzalloc
(
sizeof
(
*
e_iter
),
GFP_ATOMIC
);
if
(
e_iter
==
NULL
)
goto
netlbl_import_failure
;
e_iter
->
startbit
=
offset
&
~
(
EBITMAP_SIZE
-
1
);
e_iter
->
startbit
=
offset
-
(
offset
%
EBITMAP_SIZE
);
if
(
e_prev
==
NULL
)
ebmap
->
node
=
e_iter
;
else
...
...
security/selinux/ss/services.c
View file @
d011a4d8
...
...
@@ -543,7 +543,7 @@ static void type_attribute_bounds_av(struct context *scontext,
struct
av_decision
*
avd
)
{
struct
context
lo_scontext
;
struct
context
lo_tcontext
;
struct
context
lo_tcontext
,
*
tcontextp
=
tcontext
;
struct
av_decision
lo_avd
;
struct
type_datum
*
source
;
struct
type_datum
*
target
;
...
...
@@ -553,67 +553,41 @@ static void type_attribute_bounds_av(struct context *scontext,
scontext
->
type
-
1
);
BUG_ON
(
!
source
);
if
(
!
source
->
bounds
)
return
;
target
=
flex_array_get_ptr
(
policydb
.
type_val_to_struct_array
,
tcontext
->
type
-
1
);
BUG_ON
(
!
target
);
if
(
source
->
bounds
)
{
memset
(
&
lo_avd
,
0
,
sizeof
(
lo_avd
));
memcpy
(
&
lo_scontext
,
scontext
,
sizeof
(
lo_scontext
));
lo_scontext
.
type
=
source
->
bounds
;
memset
(
&
lo_avd
,
0
,
sizeof
(
lo_avd
));
context_struct_compute_av
(
&
lo_scontext
,
tcontext
,
tclass
,
&
lo_avd
,
NULL
);
if
((
lo_avd
.
allowed
&
avd
->
allowed
)
==
avd
->
allowed
)
return
;
/* no masked permission */
masked
=
~
lo_avd
.
allowed
&
avd
->
allowed
;
}
memcpy
(
&
lo_scontext
,
scontext
,
sizeof
(
lo_scontext
));
lo_scontext
.
type
=
source
->
bounds
;
if
(
target
->
bounds
)
{
memset
(
&
lo_avd
,
0
,
sizeof
(
lo_avd
));
memcpy
(
&
lo_tcontext
,
tcontext
,
sizeof
(
lo_tcontext
));
lo_tcontext
.
type
=
target
->
bounds
;
context_struct_compute_av
(
scontext
,
&
lo_tcontext
,
tclass
,
&
lo_avd
,
NULL
);
if
((
lo_avd
.
allowed
&
avd
->
allowed
)
==
avd
->
allowed
)
return
;
/* no masked permission */
masked
=
~
lo_avd
.
allowed
&
avd
->
allowed
;
tcontextp
=
&
lo_tcontext
;
}
if
(
source
->
bounds
&&
target
->
bounds
)
{
memset
(
&
lo_avd
,
0
,
sizeof
(
lo_avd
));
/*
* lo_scontext and lo_tcontext are already
* set up.
*/
context_struct_compute_av
(
&
lo_scontext
,
tcontextp
,
tclass
,
&
lo_avd
,
NULL
);
context_struct_compute_av
(
&
lo_scontext
,
&
lo_tcontext
,
tclass
,
&
lo_avd
,
NULL
);
if
((
lo_avd
.
allowed
&
avd
->
allowed
)
==
avd
->
allowed
)
return
;
/* no masked permission */
masked
=
~
lo_avd
.
allowed
&
avd
->
allowed
;
}
masked
=
~
lo_avd
.
allowed
&
avd
->
allowed
;
if
(
masked
)
{
/* mask violated permissions */
avd
->
allowed
&=
~
masked
;
if
(
likely
(
!
masked
))
return
;
/* no masked permission */
/* audit masked permissions */
security_dump_masked_av
(
scontext
,
tcontext
,
tclass
,
masked
,
"bounds"
);
}
/* mask violated permissions */
avd
->
allowed
&=
~
masked
;
/* audit masked permissions */
security_dump_masked_av
(
scontext
,
tcontext
,
tclass
,
masked
,
"bounds"
);
}
/*
...
...
security/smack/smack_lsm.c
View file @
d011a4d8
...
...
@@ -3992,7 +3992,7 @@ static int smack_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
rc
=
smk_bu_note
(
"IPv4 delivery"
,
skp
,
ssp
->
smk_in
,
MAY_WRITE
,
rc
);
if
(
rc
!=
0
)
netlbl_skbuff_err
(
skb
,
rc
,
0
);
netlbl_skbuff_err
(
skb
,
sk
->
sk_family
,
rc
,
0
);
break
;
#if IS_ENABLED(CONFIG_IPV6)
case
PF_INET6
:
...
...
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