diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2012-05-04 21:37:28 +0200 |
---|---|---|
committer | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2012-05-04 21:37:28 +0200 |
commit | 7219d88329cabcdd05df9477af6e2dee007b60b1 (patch) | |
tree | 1acd3e29f2bbbce49dc8e2b0e0d8ed18a9f111a3 | |
parent | 02cb61dcb7a120b7a5f7a480fd2b43f49e28dafc (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.h | 2 | ||||
-rw-r--r-- | kernel/include/linux/netfilter/ipset/ip_set_timeout.h | 4 | ||||
-rw-r--r-- | kernel/net/netfilter/xt_set.c | 15 | ||||
-rw-r--r-- | lib/ipset_bitmap_ip.c | 4 | ||||
-rw-r--r-- | lib/ipset_bitmap_ipmac.c | 4 | ||||
-rw-r--r-- | lib/ipset_bitmap_port.c | 4 | ||||
-rw-r--r-- | lib/ipset_hash_ip.c | 4 | ||||
-rw-r--r-- | lib/ipset_hash_ipport.c | 4 | ||||
-rw-r--r-- | lib/ipset_hash_ipportip.c | 4 | ||||
-rw-r--r-- | lib/ipset_hash_ipportnet.c | 6 | ||||
-rw-r--r-- | lib/ipset_hash_net.c | 6 | ||||
-rw-r--r-- | lib/ipset_hash_netiface.c | 6 | ||||
-rw-r--r-- | lib/ipset_hash_netport.c | 6 | ||||
-rw-r--r-- | lib/ipset_list_set.c | 4 | ||||
-rw-r--r-- | lib/parse.c | 31 |
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; |