Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
d93aca60
Commit
d93aca60
authored
Dec 13, 2013
by
James Morris
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
git://git.infradead.org/users/pcmoore/selinux_fixes
into for-linus
parents
54fb723c
c0828e50
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
165 additions
and
42 deletions
+165
-42
security/selinux/hooks.c
security/selinux/hooks.c
+112
-25
security/selinux/include/xfrm.h
security/selinux/include/xfrm.h
+5
-3
security/selinux/xfrm.c
security/selinux/xfrm.c
+48
-14
No files found.
security/selinux/hooks.c
View file @
d93aca60
...
@@ -53,6 +53,7 @@
...
@@ -53,6 +53,7 @@
#include <net/ip.h>
/* for local_port_range[] */
#include <net/ip.h>
/* for local_port_range[] */
#include <net/sock.h>
#include <net/sock.h>
#include <net/tcp.h>
/* struct or_callable used in sock_rcv_skb */
#include <net/tcp.h>
/* struct or_callable used in sock_rcv_skb */
#include <net/inet_connection_sock.h>
#include <net/net_namespace.h>
#include <net/net_namespace.h>
#include <net/netlabel.h>
#include <net/netlabel.h>
#include <linux/uaccess.h>
#include <linux/uaccess.h>
...
@@ -3828,7 +3829,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
...
@@ -3828,7 +3829,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
u32
nlbl_sid
;
u32
nlbl_sid
;
u32
nlbl_type
;
u32
nlbl_type
;
err
=
selinux_
skb_xfrm
_sid
(
skb
,
&
xfrm_sid
);
err
=
selinux_
xfrm_skb
_sid
(
skb
,
&
xfrm_sid
);
if
(
unlikely
(
err
))
if
(
unlikely
(
err
))
return
-
EACCES
;
return
-
EACCES
;
err
=
selinux_netlbl_skbuff_getsid
(
skb
,
family
,
&
nlbl_type
,
&
nlbl_sid
);
err
=
selinux_netlbl_skbuff_getsid
(
skb
,
family
,
&
nlbl_type
,
&
nlbl_sid
);
...
@@ -3846,6 +3847,30 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
...
@@ -3846,6 +3847,30 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
return
0
;
return
0
;
}
}
/**
* selinux_conn_sid - Determine the child socket label for a connection
* @sk_sid: the parent socket's SID
* @skb_sid: the packet's SID
* @conn_sid: the resulting connection SID
*
* If @skb_sid is valid then the user:role:type information from @sk_sid is
* combined with the MLS information from @skb_sid in order to create
* @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy
* of @sk_sid. Returns zero on success, negative values on failure.
*
*/
static
int
selinux_conn_sid
(
u32
sk_sid
,
u32
skb_sid
,
u32
*
conn_sid
)
{
int
err
=
0
;
if
(
skb_sid
!=
SECSID_NULL
)
err
=
security_sid_mls_copy
(
sk_sid
,
skb_sid
,
conn_sid
);
else
*
conn_sid
=
sk_sid
;
return
err
;
}
/* socket security operations */
/* socket security operations */
static
int
socket_sockcreate_sid
(
const
struct
task_security_struct
*
tsec
,
static
int
socket_sockcreate_sid
(
const
struct
task_security_struct
*
tsec
,
...
@@ -4452,7 +4477,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
...
@@ -4452,7 +4477,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
int
err
;
int
err
;
u16
family
=
sk
->
sk_family
;
u16
family
=
sk
->
sk_family
;
u32
new
sid
;
u32
conn
sid
;
u32
peersid
;
u32
peersid
;
/* handle mapped IPv4 packets arriving via IPv6 sockets */
/* handle mapped IPv4 packets arriving via IPv6 sockets */
...
@@ -4462,16 +4487,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
...
@@ -4462,16 +4487,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
err
=
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
peersid
);
err
=
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
peersid
);
if
(
err
)
if
(
err
)
return
err
;
return
err
;
if
(
peersid
==
SECSID_NULL
)
{
err
=
selinux_conn_sid
(
sksec
->
sid
,
peersid
,
&
connsid
);
req
->
secid
=
sksec
->
sid
;
if
(
err
)
req
->
peer_secid
=
SECSID_NULL
;
return
err
;
}
else
{
req
->
secid
=
connsid
;
err
=
security_sid_mls_copy
(
sksec
->
sid
,
peersid
,
&
newsid
);
req
->
peer_secid
=
peersid
;
if
(
err
)
return
err
;
req
->
secid
=
newsid
;
req
->
peer_secid
=
peersid
;
}
return
selinux_netlbl_inet_conn_request
(
req
,
family
);
return
selinux_netlbl_inet_conn_request
(
req
,
family
);
}
}
...
@@ -4731,6 +4751,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
...
@@ -4731,6 +4751,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
static
unsigned
int
selinux_ip_output
(
struct
sk_buff
*
skb
,
static
unsigned
int
selinux_ip_output
(
struct
sk_buff
*
skb
,
u16
family
)
u16
family
)
{
{
struct
sock
*
sk
;
u32
sid
;
u32
sid
;
if
(
!
netlbl_enabled
())
if
(
!
netlbl_enabled
())
...
@@ -4739,8 +4760,27 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
...
@@ -4739,8 +4760,27 @@ static unsigned int selinux_ip_output(struct sk_buff *skb,
/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
/* we do this in the LOCAL_OUT path and not the POST_ROUTING path
* because we want to make sure we apply the necessary labeling
* because we want to make sure we apply the necessary labeling
* before IPsec is applied so we can leverage AH protection */
* before IPsec is applied so we can leverage AH protection */
if
(
skb
->
sk
)
{
sk
=
skb
->
sk
;
struct
sk_security_struct
*
sksec
=
skb
->
sk
->
sk_security
;
if
(
sk
)
{
struct
sk_security_struct
*
sksec
;
if
(
sk
->
sk_state
==
TCP_LISTEN
)
/* if the socket is the listening state then this
* packet is a SYN-ACK packet which means it needs to
* be labeled based on the connection/request_sock and
* not the parent socket. unfortunately, we can't
* lookup the request_sock yet as it isn't queued on
* the parent socket until after the SYN-ACK is sent.
* the "solution" is to simply pass the packet as-is
* as any IP option based labeling should be copied
* from the initial connection request (in the IP
* layer). it is far from ideal, but until we get a
* security label in the packet itself this is the
* best we can do. */
return
NF_ACCEPT
;
/* standard practice, label using the parent socket */
sksec
=
sk
->
sk_security
;
sid
=
sksec
->
sid
;
sid
=
sksec
->
sid
;
}
else
}
else
sid
=
SECINITSID_KERNEL
;
sid
=
SECINITSID_KERNEL
;
...
@@ -4810,27 +4850,36 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
...
@@ -4810,27 +4850,36 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
* as fast and as clean as possible. */
* as fast and as clean as possible. */
if
(
!
selinux_policycap_netpeer
)
if
(
!
selinux_policycap_netpeer
)
return
selinux_ip_postroute_compat
(
skb
,
ifindex
,
family
);
return
selinux_ip_postroute_compat
(
skb
,
ifindex
,
family
);
secmark_active
=
selinux_secmark_enabled
();
peerlbl_active
=
selinux_peerlbl_enabled
();
if
(
!
secmark_active
&&
!
peerlbl_active
)
return
NF_ACCEPT
;
sk
=
skb
->
sk
;
#ifdef CONFIG_XFRM
#ifdef CONFIG_XFRM
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
/* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec
* packet transformation so allow the packet to pass without any checks
* packet transformation so allow the packet to pass without any checks
* since we'll have another chance to perform access control checks
* since we'll have another chance to perform access control checks
* when the packet is on it's final way out.
* when the packet is on it's final way out.
* NOTE: there appear to be some IPv6 multicast cases where skb->dst
* NOTE: there appear to be some IPv6 multicast cases where skb->dst
* is NULL, in this case go ahead and apply access control. */
* is NULL, in this case go ahead and apply access control.
if
(
skb_dst
(
skb
)
!=
NULL
&&
skb_dst
(
skb
)
->
xfrm
!=
NULL
)
* NOTE: if this is a local socket (skb->sk != NULL) that is in the
* TCP listening state we cannot wait until the XFRM processing
* is done as we will miss out on the SA label if we do;
* unfortunately, this means more work, but it is only once per
* connection. */
if
(
skb_dst
(
skb
)
!=
NULL
&&
skb_dst
(
skb
)
->
xfrm
!=
NULL
&&
!
(
sk
!=
NULL
&&
sk
->
sk_state
==
TCP_LISTEN
))
return
NF_ACCEPT
;
return
NF_ACCEPT
;
#endif
#endif
secmark_active
=
selinux_secmark_enabled
();
peerlbl_active
=
selinux_peerlbl_enabled
();
if
(
!
secmark_active
&&
!
peerlbl_active
)
return
NF_ACCEPT
;
/* if the packet is being forwarded then get the peer label from the
* packet itself; otherwise check to see if it is from a local
* application or the kernel, if from an application get the peer label
* from the sending socket, otherwise use the kernel's sid */
sk
=
skb
->
sk
;
if
(
sk
==
NULL
)
{
if
(
sk
==
NULL
)
{
/* Without an associated socket the packet is either coming
* from the kernel or it is being forwarded; check the packet
* to determine which and if the packet is being forwarded
* query the packet directly to determine the security label. */
if
(
skb
->
skb_iif
)
{
if
(
skb
->
skb_iif
)
{
secmark_perm
=
PACKET__FORWARD_OUT
;
secmark_perm
=
PACKET__FORWARD_OUT
;
if
(
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
peer_sid
))
if
(
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
peer_sid
))
...
@@ -4839,7 +4888,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
...
@@ -4839,7 +4888,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
secmark_perm
=
PACKET__SEND
;
secmark_perm
=
PACKET__SEND
;
peer_sid
=
SECINITSID_KERNEL
;
peer_sid
=
SECINITSID_KERNEL
;
}
}
}
else
if
(
sk
->
sk_state
==
TCP_LISTEN
)
{
/* Locally generated packet but the associated socket is in the
* listening state which means this is a SYN-ACK packet. In
* this particular case the correct security label is assigned
* to the connection/request_sock but unfortunately we can't
* query the request_sock as it isn't queued on the parent
* socket until after the SYN-ACK packet is sent; the only
* viable choice is to regenerate the label like we do in
* selinux_inet_conn_request(). See also selinux_ip_output()
* for similar problems. */
u32
skb_sid
;
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
if
(
selinux_skb_peerlbl_sid
(
skb
,
family
,
&
skb_sid
))
return
NF_DROP
;
/* At this point, if the returned skb peerlbl is SECSID_NULL
* and the packet has been through at least one XFRM
* transformation then we must be dealing with the "final"
* form of labeled IPsec packet; since we've already applied
* all of our access controls on this packet we can safely
* pass the packet. */
if
(
skb_sid
==
SECSID_NULL
)
{
switch
(
family
)
{
case
PF_INET
:
if
(
IPCB
(
skb
)
->
flags
&
IPSKB_XFRM_TRANSFORMED
)
return
NF_ACCEPT
;
break
;
case
PF_INET6
:
if
(
IP6CB
(
skb
)
->
flags
&
IP6SKB_XFRM_TRANSFORMED
)
return
NF_ACCEPT
;
default:
return
NF_DROP_ERR
(
-
ECONNREFUSED
);
}
}
if
(
selinux_conn_sid
(
sksec
->
sid
,
skb_sid
,
&
peer_sid
))
return
NF_DROP
;
secmark_perm
=
PACKET__SEND
;
}
else
{
}
else
{
/* Locally generated packet, fetch the security label from the
* associated socket. */
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
struct
sk_security_struct
*
sksec
=
sk
->
sk_security
;
peer_sid
=
sksec
->
sid
;
peer_sid
=
sksec
->
sid
;
secmark_perm
=
PACKET__SEND
;
secmark_perm
=
PACKET__SEND
;
...
...
security/selinux/include/xfrm.h
View file @
d93aca60
...
@@ -39,6 +39,7 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
...
@@ -39,6 +39,7 @@ int selinux_xfrm_sock_rcv_skb(u32 sk_sid, struct sk_buff *skb,
int
selinux_xfrm_postroute_last
(
u32
sk_sid
,
struct
sk_buff
*
skb
,
int
selinux_xfrm_postroute_last
(
u32
sk_sid
,
struct
sk_buff
*
skb
,
struct
common_audit_data
*
ad
,
u8
proto
);
struct
common_audit_data
*
ad
,
u8
proto
);
int
selinux_xfrm_decode_session
(
struct
sk_buff
*
skb
,
u32
*
sid
,
int
ckall
);
int
selinux_xfrm_decode_session
(
struct
sk_buff
*
skb
,
u32
*
sid
,
int
ckall
);
int
selinux_xfrm_skb_sid
(
struct
sk_buff
*
skb
,
u32
*
sid
);
static
inline
void
selinux_xfrm_notify_policyload
(
void
)
static
inline
void
selinux_xfrm_notify_policyload
(
void
)
{
{
...
@@ -79,11 +80,12 @@ static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid,
...
@@ -79,11 +80,12 @@ static inline int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid,
static
inline
void
selinux_xfrm_notify_policyload
(
void
)
static
inline
void
selinux_xfrm_notify_policyload
(
void
)
{
{
}
}
#endif
static
inline
int
selinux_
skb_xfrm
_sid
(
struct
sk_buff
*
skb
,
u32
*
sid
)
static
inline
int
selinux_
xfrm_skb
_sid
(
struct
sk_buff
*
skb
,
u32
*
sid
)
{
{
return
selinux_xfrm_decode_session
(
skb
,
sid
,
0
);
*
sid
=
SECSID_NULL
;
return
0
;
}
}
#endif
#endif
/* _SELINUX_XFRM_H_ */
#endif
/* _SELINUX_XFRM_H_ */
security/selinux/xfrm.c
View file @
d93aca60
...
@@ -209,19 +209,26 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
...
@@ -209,19 +209,26 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
NULL
)
?
0
:
1
);
NULL
)
?
0
:
1
);
}
}
/*
static
u32
selinux_xfrm_skb_sid_egress
(
struct
sk_buff
*
skb
)
* LSM hook implementation that checks and/or returns the xfrm sid for the
* incoming packet.
*/
int
selinux_xfrm_decode_session
(
struct
sk_buff
*
skb
,
u32
*
sid
,
int
ckall
)
{
{
u32
sid_session
=
SECSID_NULL
;
struct
dst_entry
*
dst
=
skb_dst
(
skb
)
;
struct
sec_path
*
sp
;
struct
xfrm_state
*
x
;
if
(
skb
==
NULL
)
if
(
dst
==
NULL
)
goto
out
;
return
SECSID_NULL
;
x
=
dst
->
xfrm
;
if
(
x
==
NULL
||
!
selinux_authorizable_xfrm
(
x
))
return
SECSID_NULL
;
return
x
->
security
->
ctx_sid
;
}
static
int
selinux_xfrm_skb_sid_ingress
(
struct
sk_buff
*
skb
,
u32
*
sid
,
int
ckall
)
{
u32
sid_session
=
SECSID_NULL
;
struct
sec_path
*
sp
=
skb
->
sp
;
sp
=
skb
->
sp
;
if
(
sp
)
{
if
(
sp
)
{
int
i
;
int
i
;
...
@@ -247,6 +254,30 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
...
@@ -247,6 +254,30 @@ int selinux_xfrm_decode_session(struct sk_buff *skb, u32 *sid, int ckall)
return
0
;
return
0
;
}
}
/*
* LSM hook implementation that checks and/or returns the xfrm sid for the
* incoming packet.
*/
int
selinux_xfrm_decode_session
(
struct
sk_buff
*
skb
,
u32
*
sid
,
int
ckall
)
{
if
(
skb
==
NULL
)
{
*
sid
=
SECSID_NULL
;
return
0
;
}
return
selinux_xfrm_skb_sid_ingress
(
skb
,
sid
,
ckall
);
}
int
selinux_xfrm_skb_sid
(
struct
sk_buff
*
skb
,
u32
*
sid
)
{
int
rc
;
rc
=
selinux_xfrm_skb_sid_ingress
(
skb
,
sid
,
0
);
if
(
rc
==
0
&&
*
sid
==
SECSID_NULL
)
*
sid
=
selinux_xfrm_skb_sid_egress
(
skb
);
return
rc
;
}
/*
/*
* LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
* LSM hook implementation that allocs and transfers uctx spec to xfrm_policy.
*/
*/
...
@@ -327,19 +358,22 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
...
@@ -327,19 +358,22 @@ int selinux_xfrm_state_alloc_acquire(struct xfrm_state *x,
return
rc
;
return
rc
;
ctx
=
kmalloc
(
sizeof
(
*
ctx
)
+
str_len
,
GFP_ATOMIC
);
ctx
=
kmalloc
(
sizeof
(
*
ctx
)
+
str_len
,
GFP_ATOMIC
);
if
(
!
ctx
)
if
(
!
ctx
)
{
return
-
ENOMEM
;
rc
=
-
ENOMEM
;
goto
out
;
}
ctx
->
ctx_doi
=
XFRM_SC_DOI_LSM
;
ctx
->
ctx_doi
=
XFRM_SC_DOI_LSM
;
ctx
->
ctx_alg
=
XFRM_SC_ALG_SELINUX
;
ctx
->
ctx_alg
=
XFRM_SC_ALG_SELINUX
;
ctx
->
ctx_sid
=
secid
;
ctx
->
ctx_sid
=
secid
;
ctx
->
ctx_len
=
str_len
;
ctx
->
ctx_len
=
str_len
;
memcpy
(
ctx
->
ctx_str
,
ctx_str
,
str_len
);
memcpy
(
ctx
->
ctx_str
,
ctx_str
,
str_len
);
kfree
(
ctx_str
);
x
->
security
=
ctx
;
x
->
security
=
ctx
;
atomic_inc
(
&
selinux_xfrm_refcount
);
atomic_inc
(
&
selinux_xfrm_refcount
);
return
0
;
out:
kfree
(
ctx_str
);
return
rc
;
}
}
/*
/*
...
...
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