nf: qtaguid: workaround xt_socket_get_sk() returning bad SKs.
JP Abgrall [Tue, 28 Jun 2011 04:03:04 +0000 (21:03 -0700)]
(This is a direct cherry pick from 2.6.39: Id2a9912b)

* xt_socket_get_sk() returns invalid sockets when the sk_state is TCP_TIME_WAIT.
Added detection of time-wait.
* Added more constrained usage: qtaguid insures that xt_socket_get*_sk() is
not invoked for unexpected hooks or protocols (but I have not seen those
active at the point where the returned sk is bad).

Signed-off-by: JP Abgrall <jpa@google.com>
Change-Id: Id2a9912bb451a3e59d012fc55bbbd40fbb90693f

net/netfilter/xt_qtaguid.c

index a764552..320ad84 100644 (file)
@@ -8,7 +8,7 @@
  * published by the Free Software Foundation.
  */
 
-/* TODO: support ipv6 */
+/* TODO: support ipv6 for iface_stat */
 
 #include <linux/file.h>
 #include <linux/inetdevice.h>
 #include <net/udp.h>
 
 #include <linux/netfilter/xt_socket.h>
+/* We only use the xt_socket funcs within a similar context to avoid unexpected
+ * return values. */
+#define XT_SOCKET_SUPPORTED_HOOKS \
+       ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN))
 
 
 /*---------------------------------------------------------------------------*/
@@ -725,16 +729,39 @@ static struct sock *qtaguid_find_sk(const struct sk_buff *skb,
                                    struct xt_action_param *par)
 {
        struct sock *sk;
+       unsigned int hook_mask = (1 << par->hooknum);
 
-       sk = xt_socket_get4_sk(skb, par);
-       /* TODO: is this fixed?
-        * Seems to be issues on the file ptr for TCP+TIME_WAIT SKs.
+       pr_debug("xt_qtaguid: find_sk(skb=%p) hooknum=%d family=%d\n", skb,
+                par->hooknum, par->family);
+
+       /* Let's not abuse the the xt_socket_get*_sk(), or else it will
+        * return garbage SKs. */
+       if (!(hook_mask & XT_SOCKET_SUPPORTED_HOOKS))
+               return NULL;
+
+       switch (par->family) {
+       case NFPROTO_IPV6:
+               sk = xt_socket_get6_sk(skb, par);
+               break;
+       case NFPROTO_IPV4:
+               sk = xt_socket_get4_sk(skb, par);
+               break;
+       default:
+               return NULL;
+       }
+
+       /* Seems to be issues on the file ptr for TCP_TIME_WAIT SKs.
         * http://kerneltrap.org/mailarchive/linux-netdev/2010/10/21/6287959
+        * Not fixed in 3.0-r3 :(
         */
-       if (sk)
+       if (sk) {
                pr_debug("xt_qtaguid: %p->sk_proto=%u "
-                       "->sk_state=%d\n", sk, sk->sk_protocol,
-                       sk->sk_state);
+                        "->sk_state=%d\n", sk, sk->sk_protocol, sk->sk_state);
+               if (sk->sk_state  == TCP_TIME_WAIT) {
+                       xt_socket_put_sk(sk);
+                       sk = NULL;
+               }
+       }
        return sk;
 }
 
@@ -784,8 +811,8 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
        struct sock *sk;
        uid_t sock_uid;
        bool res;
-       pr_debug("xt_qtaguid[%d]: entered skb=%p par->in=%p/out=%p\n",
-               par->hooknum, skb, par->in, par->out);
+       pr_debug("xt_qtaguid[%d]: entered skb=%p par->in=%p/out=%p fam=%d\n",
+                par->hooknum, skb, par->in, par->out, par->family);
        if (skb == NULL) {
                res = (info->match ^ info->invert) == 0;
                goto ret_res;