From: Jozsef Kadlecsik Date: Fri, 4 May 2012 19:37:28 +0000 (+0200) Subject: Fix timeout value overflow bug at large timeout parameters X-Git-Tag: v6.12.1~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7219d88329cabcdd05df9477af6e2dee007b60b1;p=thirdparty%2Fipset.git 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) --- diff --git a/include/libipset/parse.h b/include/libipset/parse.h index d18e3cc9..85aa2918 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 47923205..9fba34f8 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 0ec8138a..e97a31b8 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 8b8220d4..9e97b67c 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 d822bf67..2a580198 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 69be8090..3101b224 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 912b9918..e885b138 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 748e452f..54664e12 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 7c046a30..4599b01d 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 0813b7dd..af856392 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 0fd26081..5829f504 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 880ba7de..7fca5fec 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 b910c81e..d8d220ee 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 d95290b8..67c29b6a 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 30efdb6e..2cbd30e1 100644 --- a/lib/parse.c +++ b/lib/parse.c @@ -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;