netfilter: nfnetlink_cttimeout: fetch timeouts for udplite and gre, too
authorFlorian Westphal <fw@strlen.de>
Sat, 17 Nov 2018 10:32:29 +0000 (11:32 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Mon, 26 Nov 2018 09:25:20 +0000 (10:25 +0100)
syzbot was able to trigger the WARN in cttimeout_default_get() by
passing UDPLITE as l4protocol.  Alias UDPLITE to UDP, both use
same timeout values.

Furthermore, also fetch GRE timeouts.  GRE is a bit more complicated,
as it still can be a module and its netns_proto_gre struct layout isn't
visible outside of the gre module. Can't move timeouts around, it
appears conntrack sysctl unregister assumes net_generic() returns
nf_proto_net, so we get crash. Expose layout of netns_proto_gre instead.

A followup nf-next patch could make gre tracker be built-in as well
if needed, its not that large.

Last, make the WARN() mention the missing protocol value in case
anything else is missing.

Reported-by: syzbot+2fae8fa157dd92618cae@syzkaller.appspotmail.com
Fixes: 8866df9264a3 ("netfilter: nfnetlink_cttimeout: pass default timeout policy to obj_to_nlattr")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/linux/netfilter/nf_conntrack_proto_gre.h
net/netfilter/nf_conntrack_proto_gre.c
net/netfilter/nfnetlink_cttimeout.c

index b8d95564bd53481acf0bd78b15a140e8ac761776..14edb795ab43045939f9976105cd9060603ea566 100644 (file)
@@ -21,6 +21,19 @@ struct nf_ct_gre_keymap {
        struct nf_conntrack_tuple tuple;
 };
 
+enum grep_conntrack {
+       GRE_CT_UNREPLIED,
+       GRE_CT_REPLIED,
+       GRE_CT_MAX
+};
+
+struct netns_proto_gre {
+       struct nf_proto_net     nf;
+       rwlock_t                keymap_lock;
+       struct list_head        keymap_list;
+       unsigned int            gre_timeouts[GRE_CT_MAX];
+};
+
 /* add new tuple->key_reply pair to keymap */
 int nf_ct_gre_keymap_add(struct nf_conn *ct, enum ip_conntrack_dir dir,
                         struct nf_conntrack_tuple *t);
index 9b48dc8b4b885a00d8806038fc5fd0948e60cbca..2a5e56c6d8d9f966be97de8ae9153cf3be260c5b 100644 (file)
 #include <linux/netfilter/nf_conntrack_proto_gre.h>
 #include <linux/netfilter/nf_conntrack_pptp.h>
 
-enum grep_conntrack {
-       GRE_CT_UNREPLIED,
-       GRE_CT_REPLIED,
-       GRE_CT_MAX
-};
-
 static const unsigned int gre_timeouts[GRE_CT_MAX] = {
        [GRE_CT_UNREPLIED]      = 30*HZ,
        [GRE_CT_REPLIED]        = 180*HZ,
 };
 
 static unsigned int proto_gre_net_id __read_mostly;
-struct netns_proto_gre {
-       struct nf_proto_net     nf;
-       rwlock_t                keymap_lock;
-       struct list_head        keymap_list;
-       unsigned int            gre_timeouts[GRE_CT_MAX];
-};
 
 static inline struct netns_proto_gre *gre_pernet(struct net *net)
 {
@@ -402,6 +390,8 @@ static int __init nf_ct_proto_gre_init(void)
 {
        int ret;
 
+       BUILD_BUG_ON(offsetof(struct netns_proto_gre, nf) != 0);
+
        ret = register_pernet_subsys(&proto_gre_net_ops);
        if (ret < 0)
                goto out_pernet;
index a518eb162344e6692e69989cf5ba0cdf03da1333..109b0d27345acc1afac24524c107043d4d10958a 100644 (file)
@@ -455,7 +455,8 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
        case IPPROTO_TCP:
                timeouts = nf_tcp_pernet(net)->timeouts;
                break;
-       case IPPROTO_UDP:
+       case IPPROTO_UDP: /* fallthrough */
+       case IPPROTO_UDPLITE:
                timeouts = nf_udp_pernet(net)->timeouts;
                break;
        case IPPROTO_DCCP:
@@ -469,13 +470,23 @@ static int cttimeout_default_get(struct net *net, struct sock *ctnl,
        case IPPROTO_SCTP:
 #ifdef CONFIG_NF_CT_PROTO_SCTP
                timeouts = nf_sctp_pernet(net)->timeouts;
+#endif
+               break;
+       case IPPROTO_GRE:
+#ifdef CONFIG_NF_CT_PROTO_GRE
+               if (l4proto->net_id) {
+                       struct netns_proto_gre *net_gre;
+
+                       net_gre = net_generic(net, *l4proto->net_id);
+                       timeouts = net_gre->gre_timeouts;
+               }
 #endif
                break;
        case 255:
                timeouts = &nf_generic_pernet(net)->timeout;
                break;
        default:
-               WARN_ON_ONCE(1);
+               WARN_ONCE(1, "Missing timeouts for proto %d", l4proto->l4proto);
                break;
        }