Skip to content

Commit 05342f4

Browse files
committed
Fix GH-20601: ftp_connect() timeout argument overflow.
1 parent 27f17c3 commit 05342f4

File tree

2 files changed

+37
-3
lines changed

2 files changed

+37
-3
lines changed

ext/ftp/tests/gh20601.phpt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
GH-20601 (ftp_connect timeout overflow)
3+
--EXTENSIONS--
4+
ftp
5+
--SKIPIF--
6+
<?php
7+
if (PHP_INT_SIZE != 8) die("skip: 64-bit only");
8+
if (PHP_OS_FAMILY === 'Windows') die("skip not for windows");
9+
?>
10+
--FILE--
11+
<?php
12+
try {
13+
ftp_connect('127.0.0.1', 1024, PHP_INT_MAX);
14+
} catch (\ValueError $e) {
15+
echo $e->getMessage();
16+
}
17+
?>
18+
--EXPECT--
19+
timeout value overflow

main/network.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,16 +315,23 @@ static inline void sub_times(struct timeval a, struct timeval b, struct timeval
315315
}
316316
}
317317

318-
static inline void php_network_set_limit_time(struct timeval *limit_time,
318+
static inline zend_result php_network_set_limit_time(struct timeval *limit_time,
319319
struct timeval *timeout)
320320
{
321321
gettimeofday(limit_time, NULL);
322+
const double timeoutmax = (double) PHP_TIMEOUT_ULL_MAX / 1000000.0;
323+
324+
if (limit_time->tv_sec > (timeoutmax - timeout->tv_sec)) {
325+
return FAILURE;
326+
}
327+
322328
limit_time->tv_sec += timeout->tv_sec;
323329
limit_time->tv_usec += timeout->tv_usec;
324330
if (limit_time->tv_usec >= 1000000) {
325331
limit_time->tv_usec -= 1000000;
326332
limit_time->tv_sec++;
327333
}
334+
return SUCCESS;
328335
}
329336
#endif
330337

@@ -391,7 +398,11 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd,
391398
if (timeout) {
392399
memcpy(&working_timeout, timeout, sizeof(working_timeout));
393400
#if HAVE_GETTIMEOFDAY
394-
php_network_set_limit_time(&limit_time, &working_timeout);
401+
if (UNEXPECTED(php_network_set_limit_time(&limit_time, &working_timeout) == FAILURE)) {
402+
error = ERANGE;
403+
ret = -1;
404+
goto ok;
405+
}
395406
#endif
396407
}
397408

@@ -849,7 +860,11 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short
849860
if (timeout) {
850861
memcpy(&working_timeout, timeout, sizeof(working_timeout));
851862
#if HAVE_GETTIMEOFDAY
852-
php_network_set_limit_time(&limit_time, &working_timeout);
863+
if (UNEXPECTED(php_network_set_limit_time(&limit_time, &working_timeout) == FAILURE)) {
864+
php_network_freeaddresses(psal);
865+
zend_value_error("timeout value overflow");
866+
return -1;
867+
}
853868
#endif
854869
}
855870

0 commit comments

Comments
 (0)