From 738e06fca75fb977faa744242c0a944edb3f4c1c Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 19 Dec 2018 11:43:44 +0800 Subject: [PATCH] ip_vs: fix signed integer overflow while set timeout euler inclusion category: bugfix bugzilla: 5380 CVE: NA ------------------------------------------------- when do syzkallor test, there is a BUG report as blew: ================================================================================ UBSAN: Undefined behaviour in net/netfilter/ipvs/ip_vs_ctl.c:3133:21 signed integer overflow: 2147483647 * 1000 cannot be represented in type 'int' CPU: 17 PID: 44410 Comm: syz-executor Tainted: G B W ---- ------- 3.10.0-#1 Hardware name: Huawei Technologies Co., Ltd. Tecal RH2285 V2-12L/BC11SRSC1, BIOS RMISV060 06/07/2013 Call Trace: [] dump_stack+0x1e/0x20 lib/dump_stack.c:18 [] ubsan_epilogue+0x12/0x55 lib/ubsan.c:164 [] handle_overflow+0x1ba/0x215 lib/ubsan.c:195 [] __ubsan_handle_mul_overflow+0x2a/0x31 lib/ubsan.c:219 [] ip_vs_set_timeout+0x1e9/0x270 [ip_vs] [] do_ip_vs_set_ctl+0xad0/0xfa0 [ip_vs] [] nf_sockopt net/netfilter/nf_sockopt.c:111 [inline] [] nf_setsockopt+0xaf/0xf0 net/netfilter/nf_sockopt.c:118 [] ip_setsockopt+0xac/0xc0 net/ipv4/ip_sockglue.c:1121 [] udp_setsockopt+0x4a/0x90 net/ipv4/udp.c:1935 [] sock_common_setsockopt+0x76/0xc0 net/core/sock.c:2523 [] SYSC_setsockopt net/socket.c:1896 [inline] [] SyS_setsockopt+0x155/0x270 net/socket.c:1872 [] system_call_fastpath+0x22/0x27 ================================================================================ tcp_timeout can be set by ipvsadm command, while in ipvsadm, max timeout is 86400*31, check below: https://git.kernel.org/pub/scm/utils/kernel/ipvsadm/ipvsadm.git/tree/ipvsadm.c in kernel, it will be multiplied by HZ that can be 1000, then the max value of tcp_timeout, tcp_fin_timeout and udp_timeout would be 2678400000, which is beyond 2147483647. So, if set the timeout with 31 days, the effect value is the INT_MAX ms. Signed-off-by: Hui Wang Signed-off-by: Zhang Xiaoxu Reviewed-by: Wei Yongjun Signed-off-by: Zhang Xiaoxu [yyl: backport from rh7.5] Signed-off-by: Yang Yingliang --- net/netfilter/ipvs/ip_vs_ctl.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 518364f4abcc..3a26b87dcf47 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -2223,22 +2223,34 @@ static int ip_vs_set_timeout(struct netns_ipvs *ipvs, struct ip_vs_timeout_user #ifdef CONFIG_IP_VS_PROTO_TCP if (u->tcp_timeout) { pd = ip_vs_proto_data_get(ipvs, IPPROTO_TCP); - pd->timeout_table[IP_VS_TCP_S_ESTABLISHED] - = u->tcp_timeout * HZ; + if (u->tcp_timeout >= INT_MAX / HZ) { + pd->timeout_table[IP_VS_TCP_S_ESTABLISHED] = INT_MAX; + printk(KERN_WARNING "tcp_timeout * HZ overflowed, use INT_MAX as tcp_timeout instead\n"); + } else + pd->timeout_table[IP_VS_TCP_S_ESTABLISHED] + = u->tcp_timeout * HZ; } if (u->tcp_fin_timeout) { pd = ip_vs_proto_data_get(ipvs, IPPROTO_TCP); - pd->timeout_table[IP_VS_TCP_S_FIN_WAIT] - = u->tcp_fin_timeout * HZ; + if (u->tcp_fin_timeout >= INT_MAX / HZ) { + pd->timeout_table[IP_VS_TCP_S_FIN_WAIT] = INT_MAX; + printk(KERN_WARNING "tcp_fin_timeout * HZ overflowed, use INT_MAX as tcp_fin_timeout instead\n"); + } else + pd->timeout_table[IP_VS_TCP_S_FIN_WAIT] + = u->tcp_fin_timeout * HZ; } #endif #ifdef CONFIG_IP_VS_PROTO_UDP if (u->udp_timeout) { pd = ip_vs_proto_data_get(ipvs, IPPROTO_UDP); - pd->timeout_table[IP_VS_UDP_S_NORMAL] - = u->udp_timeout * HZ; + if (u->udp_timeout >= INT_MAX / HZ) { + pd->timeout_table[IP_VS_UDP_S_NORMAL] = INT_MAX; + printk(KERN_WARNING "udp_timeout * HZ overflowed, use INT_MAX as udp_timeout instead\n"); + } else + pd->timeout_table[IP_VS_UDP_S_NORMAL] + = u->udp_timeout * HZ; } #endif return 0; -- GitLab