aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Moore <pmoore@redhat.com>2013-12-04 16:10:51 -0500
committerPaul Moore <pmoore@redhat.com>2013-12-12 17:21:31 -0500
commit446b802437f285de68ffb8d6fac3c44c3cab5b04 (patch)
tree2123c25875f8ad75114592e4755d21429765a6c0
parent47180068276a04ed31d24fe04c673138208b07a9 (diff)
selinux: handle TCP SYN-ACK packets correctly in selinux_ip_postroute()
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> Cc: stable@vger.kernel.org Signed-off-by: Paul Moore <pmoore@redhat.com>
-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 877bab748c87..cc076a9b0344 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -3847,6 +3847,30 @@ static int selinux_skb_peerlbl_sid(struct sk_buff *skb, u16 family, u32 *sid)
3847 return 0; 3847 return 0;
3848} 3848}
3849 3849
3850/**
3851 * selinux_conn_sid - Determine the child socket label for a connection
3852 * @sk_sid: the parent socket's SID
3853 * @skb_sid: the packet's SID
3854 * @conn_sid: the resulting connection SID
3855 *
3856 * If @skb_sid is valid then the user:role:type information from @sk_sid is
3857 * combined with the MLS information from @skb_sid in order to create
3858 * @conn_sid. If @skb_sid is not valid then then @conn_sid is simply a copy
3859 * of @sk_sid. Returns zero on success, negative values on failure.
3860 *
3861 */
3862static int selinux_conn_sid(u32 sk_sid, u32 skb_sid, u32 *conn_sid)
3863{
3864 int err = 0;
3865
3866 if (skb_sid != SECSID_NULL)
3867 err = security_sid_mls_copy(sk_sid, skb_sid, conn_sid);
3868 else
3869 *conn_sid = sk_sid;
3870
3871 return err;
3872}
3873
3850/* socket security operations */ 3874/* socket security operations */
3851 3875
3852static int socket_sockcreate_sid(const struct task_security_struct *tsec, 3876static int socket_sockcreate_sid(const struct task_security_struct *tsec,
@@ -4453,7 +4477,7 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4453 struct sk_security_struct *sksec = sk->sk_security; 4477 struct sk_security_struct *sksec = sk->sk_security;
4454 int err; 4478 int err;
4455 u16 family = sk->sk_family; 4479 u16 family = sk->sk_family;
4456 u32 newsid; 4480 u32 connsid;
4457 u32 peersid; 4481 u32 peersid;
4458 4482
4459 /* handle mapped IPv4 packets arriving via IPv6 sockets */ 4483 /* handle mapped IPv4 packets arriving via IPv6 sockets */
@@ -4463,16 +4487,11 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
4463 err = selinux_skb_peerlbl_sid(skb, family, &peersid); 4487 err = selinux_skb_peerlbl_sid(skb, family, &peersid);
4464 if (err) 4488 if (err)
4465 return err; 4489 return err;
4466 if (peersid == SECSID_NULL) { 4490 err = selinux_conn_sid(sksec->sid, peersid, &connsid);
4467 req->secid = sksec->sid; 4491 if (err)
4468 req->peer_secid = SECSID_NULL; 4492 return err;
4469 } else { 4493 req->secid = connsid;
4470 err = security_sid_mls_copy(sksec->sid, peersid, &newsid); 4494 req->peer_secid = peersid;
4471 if (err)
4472 return err;
4473 req->secid = newsid;
4474 req->peer_secid = peersid;
4475 }
4476 4495
4477 return selinux_netlbl_inet_conn_request(req, family); 4496 return selinux_netlbl_inet_conn_request(req, family);
4478} 4497}
@@ -4846,12 +4865,12 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4846 if (!secmark_active && !peerlbl_active) 4865 if (!secmark_active && !peerlbl_active)
4847 return NF_ACCEPT; 4866 return NF_ACCEPT;
4848 4867
4849 /* if the packet is being forwarded then get the peer label from the
4850 * packet itself; otherwise check to see if it is from a local
4851 * application or the kernel, if from an application get the peer label
4852 * from the sending socket, otherwise use the kernel's sid */
4853 sk = skb->sk; 4868 sk = skb->sk;
4854 if (sk == NULL) { 4869 if (sk == NULL) {
4870 /* Without an associated socket the packet is either coming
4871 * from the kernel or it is being forwarded; check the packet
4872 * to determine which and if the packet is being forwarded
4873 * query the packet directly to determine the security label. */
4855 if (skb->skb_iif) { 4874 if (skb->skb_iif) {
4856 secmark_perm = PACKET__FORWARD_OUT; 4875 secmark_perm = PACKET__FORWARD_OUT;
4857 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid)) 4876 if (selinux_skb_peerlbl_sid(skb, family, &peer_sid))
@@ -4860,7 +4879,26 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex,
4860 secmark_perm = PACKET__SEND; 4879 secmark_perm = PACKET__SEND;
4861 peer_sid = SECINITSID_KERNEL; 4880 peer_sid = SECINITSID_KERNEL;
4862 } 4881 }
4882 } else if (sk->sk_state == TCP_LISTEN) {
4883 /* Locally generated packet but the associated socket is in the
4884 * listening state which means this is a SYN-ACK packet. In
4885 * this particular case the correct security label is assigned
4886 * to the connection/request_sock but unfortunately we can't
4887 * query the request_sock as it isn't queued on the parent
4888 * socket until after the SYN-ACK packet is sent; the only
4889 * viable choice is to regenerate the label like we do in
4890 * selinux_inet_conn_request(). See also selinux_ip_output()
4891 * for similar problems. */
4892 u32 skb_sid;
4893 struct sk_security_struct *sksec = sk->sk_security;
4894 if (selinux_skb_peerlbl_sid(skb, family, &skb_sid))
4895 return NF_DROP;
4896 if (selinux_conn_sid(sksec->sid, skb_sid, &peer_sid))
4897 return NF_DROP;
4898 secmark_perm = PACKET__SEND;
4863 } else { 4899 } else {
4900 /* Locally generated packet, fetch the security label from the
4901 * associated socket. */
4864 struct sk_security_struct *sksec = sk->sk_security; 4902 struct sk_security_struct *sksec = sk->sk_security;
4865 peer_sid = sksec->sid; 4903 peer_sid = sksec->sid;
4866 secmark_perm = PACKET__SEND; 4904 secmark_perm = PACKET__SEND;