aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Moore <pmoore@redhat.com>2013-12-04 16:10:51 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-12-20 10:45:09 -0500
commit348d7867154c8d7b6f472cbe5918b1169dd13b0c (patch)
tree7e326e48368b2aa7e0edf226af00c78b2c5ee452
parent216c4a776a12148e8386070da71b9f10ab854e93 (diff)
selinux: handle TCP SYN-ACK packets correctly in selinux_ip_postroute()
commit 446b802437f285de68ffb8d6fac3c44c3cab5b04 upstream. In selinux_ip_postroute() we perform access checks based on the packet's security label. For locally generated traffic we get the packet's security label from the associated socket; this works in all cases except for TCP SYN-ACK packets. In the case of SYN-ACK packet's the correct security label is stored in the connection's request_sock, not the server's socket. Unfortunately, at the point in time when selinux_ip_postroute() is called we can't query the request_sock directly, we need to recreate the label using the same logic that originally labeled the associated request_sock. See the inline comments for more explanation. Reported-by: Janak Desai <Janak.Desai@gtri.gatech.edu> Tested-by: Janak Desai <Janak.Desai@gtri.gatech.edu> Signed-off-by: Paul Moore <pmoore@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--security/selinux/hooks.c68
1 files changed, 53 insertions, 15 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 27860faab12e..5e58d7dd7b69 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3737,6 +3737,30 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
3737 return 0; 3737 return 0;
3738} 3738}
3739 3739
3740/**
3741 * selinux_conn_sid - Determine the child socket label for a connection
3742 * @sk_sid: the parent socket's SID
3743 * @skb_sid: the packet's SID
3744 * @conn_sid: the resulting connection SID
3745 *
3746 * If @skb_sid is valid then the user:role:type information from @sk_sid is
3747 * combined with the MLS information from @skb_sid in order to create
3748 * @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy
3749 * of @sk_sid. Returns zero on success, negative values on failure.
3750 *
3751 */
3752static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
3753{
3754 int err = 0;
3755
3756 if (skb_sid != SECSID_NULL)
3757 err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid);
3758 else
3759 *conn_sid = sk_sid;
3760
3761 return err;
3762}
3763
3740/* socket security operations */ 3764/* socket security operations */
3741 3765
3742static int socket_sockcreate_sid(const struct task_security_struct *tsec, 3766static int socket_sockcreate_sid(const struct task_security_struct *tsec,
@@ -4343,7 +4367,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4343 struct sk_security_struct *sksec = sk->sk_security; 4367 struct sk_security_struct *sksec = sk->sk_security;
4344 int err; 4368 int err;
4345 u16 family = sk->sk_family; 4369 u16 family = sk->sk_family;
4346 u32 newsid; 4370 u32 connsid;
4347 u32 peersid; 4371 u32 peersid;
4348 4372
4349 /* handle mapped IPv4 packets arriving via IPv6 sockets */ 4373 /* handle mapped IPv4 packets arriving via IPv6 sockets */
@@ -4353,16 +4377,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4353 err = selinux_skb_peerlbl_sid(skb, family, &peersid); 4377 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
4354 if (err) 4378 if (err)
4355 return err; 4379 return err;
4356 if (peersid == SECSID_NULL) { 4380 err = selinux_conn_sid(sksec->sid, peersid, &connsid);
4357 req->secid = sksec->sid; 4381 if (err)
4358 req->peer_secid = SECSID_NULL; 4382 return err;
4359 } else { 4383 req->secid = connsid;
4360 err = security_sid_mls_copy(sksec->sid, peersid, &newsid); 4384 req->peer_secid = peersid;
4361 if (err)
4362 return err;
4363 req->secid = newsid;
4364 req->peer_secid = peersid;
4365 }
4366 4385
4367 return selinux_netlbl_inet_conn_request(req, family); 4386 return selinux_netlbl_inet_conn_request(req, family);
4368} 4387}
@@ -4736,12 +4755,12 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4736 if (!secmark_active && !peerlbl_active) 4755 if (!secmark_active && !peerlbl_active)
4737 return NF_ACCEPT; 4756 return NF_ACCEPT;
4738 4757
4739 /* if the packet is being forwarded then get the peer label from the
4740 * packet itself; otherwise check to see if it is from a local
4741 * application or the kernel, if from an application get the peer label
4742 * from the sending socket, otherwise use the kernel's sid */
4743 sk = skb->sk; 4758 sk = skb->sk;
4744 if (sk == NULL) { 4759 if (sk == NULL) {
4760 /* Without an associated socket the packet is either coming
4761 * from the kernel or it is being forwarded; check the packet
4762 * to determine which and if the packet is being forwarded
4763 * query the packet directly to determine the security label. */
4745 if (skb->skb_iif) { 4764 if (skb->skb_iif) {
4746 secmark_perm = PACKET__FORWARD_OUT; 4765 secmark_perm = PACKET__FORWARD_OUT;
4747 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) 4766 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
@@ -4750,7 +4769,26 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4750 secmark_perm = PACKET__SEND; 4769 secmark_perm = PACKET__SEND;
4751 peer_sid = SECINITSID_KERNEL; 4770 peer_sid = SECINITSID_KERNEL;
4752 } 4771 }
4772 } else if (sk->sk_state == TCP_LISTEN) {
4773 /* Locally generated packet but the associated socket is in the
4774 * listening state which means this is a SYN-ACK packet. In
4775 * this particular case the correct security label is assigned
4776 * to the connection/request_sock but unfortunately we can't
4777 * query the request_sock as it isn't queued on the parent
4778 * socket until after the SYN-ACK packet is sent; the only
4779 * viable choice is to regenerate the label like we do in
4780 * selinux_inet_conn_request(). See also selinux_ip_output()
4781 * for similar problems. */
4782 u32 skb_sid;
4783 struct sk_security_struct *sksec = sk->sk_security;
4784 if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
4785 return NF_DROP;
4786 if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid))
4787 return NF_DROP;
4788 secmark_perm = PACKET__SEND;
4753 } else { 4789 } else {
4790 /* Locally generated packet, fetch the security label from the
4791 * associated socket. */
4754 struct sk_security_struct *sksec = sk->sk_security; 4792 struct sk_security_struct *sksec = sk->sk_security;
4755 peer_sid = sksec->sid; 4793 peer_sid = sksec->sid;
4756 secmark_perm = PACKET__SEND; 4794 secmark_perm = PACKET__SEND;