--- /dev/null
+From 47180068276a04ed31d24fe04c673138208b07a9 Mon Sep 17 00:00:00 2001
+From: Paul Moore <pmoore@redhat.com>
+Date: Wed, 4 Dec 2013 16:10:45 -0500
+Subject: selinux: handle TCP SYN-ACK packets correctly in selinux_ip_output()
+
+From: Paul Moore <pmoore@redhat.com>
+
+commit 47180068276a04ed31d24fe04c673138208b07a9 upstream.
+
+In selinux_ip_output() we always label packets based on the parent
+socket. While this approach works in almost all cases, it doesn't
+work in the case of TCP SYN-ACK packets when the correct label is not
+the label of the parent socket, but rather the label of the larval
+socket represented by the request_sock struct.
+
+Unfortunately, since the request_sock isn't queued on the parent
+socket until *after* the SYN-ACK packet is sent, we can't lookup the
+request_sock to determine the correct label for the packet; at this
+point in time the best we can do is simply pass/NF_ACCEPT the packet.
+It must be said that simply passing the packet without any explicit
+labeling action, while far from ideal, is not terrible as the SYN-ACK
+packet will inherit any IP option based labeling from the initial
+connection request so the label *should* be correct and all our
+access controls remain in place so we shouldn't have to worry about
+information leaks.
+
+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>
+
+---
+ security/selinux/hooks.c | 25 +++++++++++++++++++++++--
+ 1 file changed, 23 insertions(+), 2 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -52,6 +52,7 @@
+ #include <net/icmp.h>
+ #include <net/ip.h> /* for local_port_range[] */
+ #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>
+@@ -4605,6 +4606,7 @@ static unsigned int selinux_ipv6_forward
+ static unsigned int selinux_ip_output(struct sk_buff *skb,
+ u16 family)
+ {
++ struct sock *sk;
+ u32 sid;
+
+ if (!netlbl_enabled())
+@@ -4613,8 +4615,27 @@ static unsigned int selinux_ip_output(st
+ /* 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;
--- /dev/null
+From 446b802437f285de68ffb8d6fac3c44c3cab5b04 Mon Sep 17 00:00:00 2001
+From: Paul Moore <pmoore@redhat.com>
+Date: Wed, 4 Dec 2013 16:10:51 -0500
+Subject: selinux: handle TCP SYN-ACK packets correctly in selinux_ip_postroute()
+
+From: Paul Moore <pmoore@redhat.com>
+
+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>
+
+---
+ security/selinux/hooks.c | 68 ++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 53 insertions(+), 15 deletions(-)
+
+--- a/security/selinux/hooks.c
++++ b/security/selinux/hooks.c
+@@ -3734,6 +3734,30 @@ static int selinux_skb_peerlbl_sid(struc
+ 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,
+@@ -4355,7 +4379,7 @@ static int selinux_inet_conn_request(str
+ struct sk_security_struct *sksec = sk->sk_security;
+ int err;
+ u16 family = sk->sk_family;
+- u32 newsid;
++ u32 connsid;
+ u32 peersid;
+
+ /* handle mapped IPv4 packets arriving via IPv6 sockets */
+@@ -4365,16 +4389,11 @@ static int selinux_inet_conn_request(str
+ 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);
+ }
+@@ -4723,12 +4742,12 @@ static unsigned int selinux_ip_postroute
+ 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))
+@@ -4737,7 +4756,26 @@ static unsigned int selinux_ip_postroute
+ 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;
++ 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;