summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2012-05-04 21:37:28 +0200
committerJozsef Kadlecsik <kadlec@blackhole.kfki.hu>2012-05-04 21:37:28 +0200
commit7219d88329cabcdd05df9477af6e2dee007b60b1 (patch)
tree1acd3e29f2bbbce49dc8e2b0e0d8ed18a9f111a3
parent02cb61dcb7a120b7a5f7a480fd2b43f49e28dafc (diff)
Fix timeout value overflow bug at large timeout parameters
Large timeout parameters could result wrong timeout values due to an overflow at msec to jiffies conversion (reported by Andreas Herz)
-rw-r--r--include/libipset/parse.h2
-rw-r--r--kernel/include/linux/netfilter/ipset/ip_set_timeout.h4
-rw-r--r--kernel/net/netfilter/xt_set.c15
-rw-r--r--lib/ipset_bitmap_ip.c4
-rw-r--r--lib/ipset_bitmap_ipmac.c4
-rw-r--r--lib/ipset_bitmap_port.c4
-rw-r--r--lib/ipset_hash_ip.c4
-rw-r--r--lib/ipset_hash_ipport.c4
-rw-r--r--lib/ipset_hash_ipportip.c4
-rw-r--r--lib/ipset_hash_ipportnet.c6
-rw-r--r--lib/ipset_hash_net.c6
-rw-r--r--lib/ipset_hash_netiface.c6
-rw-r--r--lib/ipset_hash_netport.c6
-rw-r--r--lib/ipset_list_set.c4
-rw-r--r--lib/parse.c31
15 files changed, 75 insertions, 29 deletions
diff --git a/include/libipset/parse.h b/include/libipset/parse.h
index d18e3cc..85aa291 100644
--- a/include/libipset/parse.h
+++ b/include/libipset/parse.h
@@ -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,
diff --git a/kernel/include/linux/netfilter/ipset/ip_set_timeout.h b/kernel/include/linux/netfilter/ipset/ip_set_timeout.h
index 4792320..9fba34f 100644
--- a/kernel/include/linux/netfilter/ipset/ip_set_timeout.h
+++ b/kernel/include/linux/netfilter/ipset/ip_set_timeout.h
@@ -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;
}
diff --git a/kernel/net/netfilter/xt_set.c b/kernel/net/netfilter/xt_set.c
index 0ec8138..e97a31b 100644
--- a/kernel/net/netfilter/xt_set.c
+++ b/kernel/net/netfilter/xt_set.c
@@ -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)
diff --git a/lib/ipset_bitmap_ip.c b/lib/ipset_bitmap_ip.c
index 8b8220d..9e97b67 100644
--- a/lib/ipset_bitmap_ip.c
+++ b/lib/ipset_bitmap_ip.c
@@ -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,
},
{ },
};
diff --git a/lib/ipset_bitmap_ipmac.c b/lib/ipset_bitmap_ipmac.c
index d822bf6..2a58019 100644
--- a/lib/ipset_bitmap_ipmac.c
+++ b/lib/ipset_bitmap_ipmac.c
@@ -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,
},
{ },
};
diff --git a/lib/ipset_bitmap_port.c b/lib/ipset_bitmap_port.c
index 69be809..3101b22 100644
--- a/lib/ipset_bitmap_port.c
+++ b/lib/ipset_bitmap_port.c
@@ -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,
},
{ },
};
diff --git a/lib/ipset_hash_ip.c b/lib/ipset_hash_ip.c
index 912b991..e885b13 100644
--- a/lib/ipset_hash_ip.c
+++ b/lib/ipset_hash_ip.c
@@ -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,
},
{ },
};
diff --git a/lib/ipset_hash_ipport.c b/lib/ipset_hash_ipport.c
index 748e452..54664e1 100644
--- a/lib/ipset_hash_ipport.c
+++ b/lib/ipset_hash_ipport.c
@@ -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,
},
{ },
};
diff --git a/lib/ipset_hash_ipportip.c b/lib/ipset_hash_ipportip.c
index 7c046a3..4599b01 100644
--- a/lib/ipset_hash_ipportip.c
+++ b/lib/ipset_hash_ipportip.c
@@ -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,
},
{ },
};
diff --git a/lib/ipset_hash_ipportnet.c b/lib/ipset_hash_ipportnet.c
index 0813b7d..af85639 100644
--- a/lib/ipset_hash_ipportnet.c
+++ b/lib/ipset_hash_ipportnet.c
@@ -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,
diff --git a/lib/ipset_hash_net.c b/lib/ipset_hash_net.c
index 0fd2608..5829f50 100644
--- a/lib/ipset_hash_net.c
+++ b/lib/ipset_hash_net.c
@@ -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,
diff --git a/lib/ipset_hash_netiface.c b/lib/ipset_hash_netiface.c
index 880ba7d..7fca5fe 100644
--- a/lib/ipset_hash_netiface.c
+++ b/lib/ipset_hash_netiface.c
@@ -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,
diff --git a/lib/ipset_hash_netport.c b/lib/ipset_hash_netport.c
index b910c81..d8d220e 100644
--- a/lib/ipset_hash_netport.c
+++ b/lib/ipset_hash_netport.c
@@ -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,
diff --git a/lib/ipset_list_set.c b/lib/ipset_list_set.c
index d95290b..67c29b6 100644
--- a/lib/ipset_list_set.c
+++ b/lib/ipset_list_set.c
@@ -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,
diff --git a/lib/parse.c b/lib/parse.c
index 30efdb6..2cbd30e 100644
--- a/lib/parse.c
+++ b/lib/parse.c
@@ -1130,6 +1130,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
* @opt: option kind of the data
@@ -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;