@ -53,6 +53,7 @@
# include <net/ip.h> /* for local_port_range[] */
# include <net/sock.h>
# 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/netlabel.h>
# include <linux/uaccess.h>
@ -3824,7 +3825,7 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
u32 nlbl_sid ;
u32 nlbl_type ;
err = selinux_skb_ xfrm_sid ( skb , & xfrm_sid ) ;
err = selinux_xfrm_skb _sid ( skb , & xfrm_sid ) ;
if ( unlikely ( err ) )
return - EACCES ;
err = selinux_netlbl_skbuff_getsid ( skb , family , & nlbl_type , & nlbl_sid ) ;
@ -3842,6 +3843,30 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
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 */
static int socket_sockcreate_sid ( const struct task_security_struct * tsec ,
@ -4448,7 +4473,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
struct sk_security_struct * sksec = sk - > sk_security ;
int err ;
u16 family = sk - > sk_family ;
u32 new sid ;
u32 con nsid;
u32 peersid ;
/* handle mapped IPv4 packets arriving via IPv6 sockets */
@ -4458,16 +4483,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
err = selinux_skb_peerlbl_sid ( skb , family , & peersid ) ;
if ( err )
return err ;
if ( peersid = = SECSID_NULL ) {
req - > secid = sksec - > sid ;
req - > peer_secid = SECSID_NULL ;
} else {
err = security_sid_mls_copy ( sksec - > sid , peersid , & newsid ) ;
if ( err )
return err ;
req - > secid = newsid ;
req - > peer_secid = peersid ;
}
err = selinux_conn_sid ( sksec - > sid , peersid , & connsid ) ;
if ( err )
return err ;
req - > secid = connsid ;
req - > peer_secid = peersid ;
return selinux_netlbl_inet_conn_request ( req , family ) ;
}
@ -4727,6 +4747,7 @@ static unsigned int selinux_ipv6_forward(const struct nf_hook_ops *ops,
static unsigned int selinux_ip_output ( struct sk_buff * skb ,
u16 family )
{
struct sock * sk ;
u32 sid ;
if ( ! netlbl_enabled ( ) )
@ -4735,8 +4756,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
* because we want to make sure we apply the necessary labeling
* before IPsec is applied so we can leverage AH protection */
if ( skb - > sk ) {
struct sk_security_struct * sksec = skb - > sk - > sk_security ;
sk = skb - > sk ;
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 ;
} else
sid = SECINITSID_KERNEL ;
@ -4806,27 +4846,36 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
* as fast and as clean as possible . */
if ( ! selinux_policycap_netpeer )
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
/* 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
* since we ' ll have another chance to perform access control checks
* when the packet is on it ' s final way out .
* NOTE : there appear to be some IPv6 multicast cases where skb - > dst
* is NULL , in this case go ahead and apply access control . */
if ( skb_dst ( skb ) ! = NULL & & skb_dst ( skb ) - > xfrm ! = NULL )
* is NULL , in this case go ahead and apply access control .
* 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 ;
# 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 ) {
/* 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 ) {
secmark_perm = PACKET__FORWARD_OUT ;
if ( selinux_skb_peerlbl_sid ( skb , family , & peer_sid ) )
@ -4835,7 +4884,45 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
secmark_perm = PACKET__SEND ;
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 {
/* Locally generated packet, fetch the security label from the
* associated socket . */
struct sk_security_struct * sksec = sk - > sk_security ;
peer_sid = sksec - > sid ;
secmark_perm = PACKET__SEND ;