]> git.ipfire.org Git - thirdparty/ipset.git/commitdiff
Fix timeout value overflow bug at large timeout parameters
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 4 May 2012 19:37:28 +0000 (21:37 +0200)
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Fri, 4 May 2012 19:37:28 +0000 (21:37 +0200)
Large timeout parameters could result wrong timeout values due to
an overflow at msec to jiffies conversion (reported by Andreas Herz)

15 files changed:
include/libipset/parse.h
kernel/include/linux/netfilter/ipset/ip_set_timeout.h
kernel/net/netfilter/xt_set.c
lib/ipset_bitmap_ip.c
lib/ipset_bitmap_ipmac.c
lib/ipset_bitmap_port.c
lib/ipset_hash_ip.c
lib/ipset_hash_ipport.c
lib/ipset_hash_ipportip.c
lib/ipset_hash_ipportnet.c
lib/ipset_hash_net.c
lib/ipset_hash_netiface.c
lib/ipset_hash_netport.c
lib/ipset_list_set.c
lib/parse.c

index d18e3cc9c5a4f02b17b0a9da43a863cee8ebc0f8..85aa2918e67d0e9cc367cb336342fb183059a161 100644 (file)
@@ -72,6 +72,8 @@ extern int ipset_parse_after(struct ipset_session *session,
                             enum ipset_opt opt, const char *str);
 extern int ipset_parse_setname(struct ipset_session *session,
                               enum ipset_opt opt, const char *str);
+extern int ipset_parse_timeout(struct ipset_session *session,
+                              enum ipset_opt opt, const char *str);
 extern int ipset_parse_uint32(struct ipset_session *session,
                              enum ipset_opt opt, const char *str);
 extern int ipset_parse_uint8(struct ipset_session *session,
index 47923205a4ad426906d1fba4525645d4d547bcab..9fba34f84587978248195d63afda6662815f5dfb 100644 (file)
@@ -30,6 +30,10 @@ ip_set_timeout_uget(struct nlattr *tb)
 {
        unsigned int timeout = ip_set_get_h32(tb);
 
+       /* Normalize to fit into jiffies */
+       if (timeout > UINT_MAX/1000)
+               timeout = UINT_MAX/1000;
+
        /* Userspace supplied TIMEOUT parameter: adjust crazy size */
        return timeout == IPSET_NO_TIMEOUT ? IPSET_NO_TIMEOUT - 1 : timeout;
 }
index 0ec8138aa47052f8966fde995d68f240b7d377d4..e97a31b86ae10628a0f79c4b1ac566fe901b8405 100644 (file)
@@ -44,6 +44,14 @@ const struct ip_set_adt_opt n = {    \
        .cmdflags = cfs,                \
        .timeout = t,                   \
 }
+#define ADT_MOPT(n, f, d, fs, cfs, t)  \
+struct ip_set_adt_opt n = {            \
+       .family = f,                    \
+       .dim = d,                       \
+       .flags = fs,                    \
+       .cmdflags = cfs,                \
+       .timeout = t,                   \
+}
 
 /* Revision 0 interface: backward compatible with netfilter/iptables */
 
@@ -296,11 +304,14 @@ static unsigned int
 set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
 {
        const struct xt_set_info_target_v2 *info = par->targinfo;
-       ADT_OPT(add_opt, par->family, info->add_set.dim,
-               info->add_set.flags, info->flags, info->timeout);
+       ADT_MOPT(add_opt, par->family, info->add_set.dim,
+                info->add_set.flags, info->flags, info->timeout);
        ADT_OPT(del_opt, par->family, info->del_set.dim,
                info->del_set.flags, 0, UINT_MAX);
 
+       /* Normalize to fit into jiffies */
+       if (add_opt.timeout > UINT_MAX/1000)
+               add_opt.timeout = UINT_MAX/1000;
        if (info->add_set.index != IPSET_INVALID_ID)
                ip_set_add(info->add_set.index, skb, par, &add_opt);
        if (info->del_set.index != IPSET_INVALID_ID)
index 8b8220d4ed0e392b11d7f8e47845d3c08c2f4836..9e97b67cd57c0976849f330786a100fa3c85a41f 100644 (file)
@@ -21,7 +21,7 @@ static const struct ipset_arg bitmap_ip_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        /* Backward compatibility */
        { .name = { "from", NULL },
@@ -42,7 +42,7 @@ static const struct ipset_arg bitmap_ip_create_args[] = {
 static const struct ipset_arg bitmap_ip_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
index d822bf67b6f9f822f7c82c3ecb7c55290e00b429..2a580198a16d9d9d6127f33fde4659d74fe3d1c1 100644 (file)
@@ -17,7 +17,7 @@ static const struct ipset_arg bitmap_ipmac_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        /* Backward compatibility */
        { .name = { "from", NULL },
@@ -38,7 +38,7 @@ static const struct ipset_arg bitmap_ipmac_create_args[] = {
 static const struct ipset_arg bitmap_ipmac_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
index 69be8090a02619d54b08a4934e4cbe369bf0619a..3101b2245a4d6fa4c6eb37e3942cb7bd43b49597 100644 (file)
@@ -17,7 +17,7 @@ static const struct ipset_arg bitmap_port_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        /* Backward compatibility */
        { .name = { "from", NULL },
@@ -34,7 +34,7 @@ static const struct ipset_arg bitmap_port_create_args[] = {
 static const struct ipset_arg bitmap_port_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
index 912b9918727a17094c0f750eb5e7bb3932224913..e885b13813de4581ca99097f5670951b8020fda0 100644 (file)
@@ -39,7 +39,7 @@ static const struct ipset_arg hash_ip_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        /* Ignored options: backward compatibilty */
        { .name = { "probes", NULL },
@@ -60,7 +60,7 @@ static const struct ipset_arg hash_ip_create_args[] = {
 static const struct ipset_arg hash_ip_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
index 748e452f82e654b4c6cdfca8d6c5f58481abaf06..54664e12c9dce14a1813e1fed6214d5b88d923e7 100644 (file)
@@ -36,7 +36,7 @@ static const struct ipset_arg hash_ipport_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        /* Backward compatibility */
        { .name = { "probes", NULL },
@@ -65,7 +65,7 @@ static const struct ipset_arg hash_ipport_create_args[] = {
 static const struct ipset_arg hash_ipport_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
index 7c046a302a911d7cd0b024293b63717d895eea68..4599b01d23c5647243fb6255c95b42994611a8f9 100644 (file)
@@ -36,7 +36,7 @@ static const struct ipset_arg hash_ipportip_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        /* Backward compatibility */
        { .name = { "probes", NULL },
@@ -65,7 +65,7 @@ static const struct ipset_arg hash_ipportip_create_args[] = {
 static const struct ipset_arg hash_ipportip_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
index 0813b7dd71d8f4f08d29f8b05b57feb7cb5cd9d8..af8563924cc14c4d86243888b049e02f5d6d6da8 100644 (file)
@@ -36,7 +36,7 @@ static const struct ipset_arg hash_ipportnet_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        /* Backward compatibility */
        { .name = { "probes", NULL },
@@ -65,7 +65,7 @@ static const struct ipset_arg hash_ipportnet_create_args[] = {
 static const struct ipset_arg hash_ipportnet_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
@@ -255,7 +255,7 @@ struct ipset_type ipset_hash_ipportnet2 = {
 static const struct ipset_arg hash_ipportnet3_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { .name = { "nomatch", NULL },
          .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
index 0fd260816bd9026774a996d5943bd914e5e6116e..5829f504b0eaac975118a44206dd8762e89756f1 100644 (file)
@@ -35,7 +35,7 @@ static const struct ipset_arg hash_net_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        /* Ignored options: backward compatibilty */
        { .name = { "probes", NULL },
@@ -52,7 +52,7 @@ static const struct ipset_arg hash_net_create_args[] = {
 static const struct ipset_arg hash_net_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
@@ -165,7 +165,7 @@ struct ipset_type ipset_hash_net1 = {
 static const struct ipset_arg hash_net2_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { .name = { "nomatch", NULL },
          .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
index 880ba7def3bae5910d76532152b10670311d1b71..7fca5fec5f247235997a0b2762c44a498faece9d 100644 (file)
@@ -36,7 +36,7 @@ static const struct ipset_arg hash_netiface_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
@@ -44,7 +44,7 @@ static const struct ipset_arg hash_netiface_create_args[] = {
 static const struct ipset_arg hash_netiface_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
@@ -121,7 +121,7 @@ struct ipset_type ipset_hash_netiface0 = {
 static const struct ipset_arg hash_netiface1_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { .name = { "nomatch", NULL },
          .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
index b910c81e24f8b4fb41bcfb2e6f92dd7415feee50..d8d220ee913a1786bc2d871dcb2e191b3b32349c 100644 (file)
@@ -36,7 +36,7 @@ static const struct ipset_arg hash_netport_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
@@ -44,7 +44,7 @@ static const struct ipset_arg hash_netport_create_args[] = {
 static const struct ipset_arg hash_netport_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
@@ -201,7 +201,7 @@ struct ipset_type ipset_hash_netport2 = {
 static const struct ipset_arg hash_netport3_add_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { .name = { "nomatch", NULL },
          .has_arg = IPSET_NO_ARG,              .opt = IPSET_OPT_NOMATCH,
index d95290b881d6a7588abf7c68c11e6ded8cf516d4..67c29b6a6486f77d353d64aa6c0bcaf1a166b7a6 100644 (file)
@@ -17,7 +17,7 @@ static const struct ipset_arg list_set_create_args[] = {
        },
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { },
 };
@@ -25,7 +25,7 @@ static const struct ipset_arg list_set_create_args[] = {
 static const struct ipset_arg list_set_adt_args[] = {
        { .name = { "timeout", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_TIMEOUT,
-         .parse = ipset_parse_uint32,          .print = ipset_print_number,
+         .parse = ipset_parse_timeout,         .print = ipset_print_number,
        },
        { .name = { "before", NULL },
          .has_arg = IPSET_MANDATORY_ARG,       .opt = IPSET_OPT_NAMEREF,
index 30efdb6e2346b905210d40de77eb2cc88df0beb9..2cbd30e1003314a59eed0576f4a2a23e93bae368 100644 (file)
@@ -1129,6 +1129,35 @@ ipset_parse_ip4_net6(struct ipset_session *session,
 
 }
 
+/**
+ * ipset_parse_timeout - parse timeout parameter
+ * @session: session structure
+ * @opt: option kind of the data
+ * @str: string to parse
+ *
+ * Parse string as a timeout parameter. We have to take into account
+ * the jiffies storage in kernel.
+ *
+ * Returns 0 on success or a negative error code.
+ */
+int
+ipset_parse_timeout(struct ipset_session *session,
+                   enum ipset_opt opt, const char *str)
+{
+       int err;
+       unsigned long long num = 0;
+
+       assert(session);
+       assert(opt == IPSET_OPT_TIMEOUT);
+       assert(str);
+
+       err = string_to_number_ll(session, str, 0, UINT_MAX/1000, &num);
+       if (err == 0)
+               return ipset_session_data_set(session, opt, &num);
+
+       return err;
+}
+
 /**
  * ipset_parse_iptimeout - parse IPv4|IPv6 address and timeout
  * @session: session structure
@@ -1171,7 +1200,7 @@ ipset_parse_iptimeout(struct ipset_session *session,
        *a++ = '\0';
        err = parse_ip(session, opt, tmp, IPADDR_ANY);
        if (!err)
-               err = ipset_parse_uint32(session, IPSET_OPT_TIMEOUT, a);
+               err = ipset_parse_timeout(session, IPSET_OPT_TIMEOUT, a);
 
        free(saved);
        return err;