-
Notifications
You must be signed in to change notification settings - Fork 8k
Fix GH-20601: ftp_connect() timeout argument overflow. #20603
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| --TEST-- | ||
| GH-20601 (ftp_connect timeout overflow) | ||
| --EXTENSIONS-- | ||
| ftp | ||
| --SKIPIF-- | ||
| <?php | ||
| if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); | ||
| if (PHP_OS_FAMILY === 'Windows') die("skip not for windows"); | ||
| ?> | ||
| --FILE-- | ||
| <?php | ||
| try { | ||
| ftp_connect('127.0.0.1', 1024, PHP_INT_MAX); | ||
| } catch (\ValueError $e) { | ||
| echo $e->getMessage(); | ||
| } | ||
| ?> | ||
| --EXPECT-- | ||
| timeout value overflow | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -315,16 +315,24 @@ static inline void sub_times(struct timeval a, struct timeval b, struct timeval | |
| } | ||
| } | ||
|
|
||
| static inline void php_network_set_limit_time(struct timeval *limit_time, | ||
| static inline zend_result php_network_set_limit_time(struct timeval *limit_time, | ||
| struct timeval *timeout) | ||
| { | ||
| gettimeofday(limit_time, NULL); | ||
| const double timeoutmax = (double) PHP_TIMEOUT_ULL_MAX / 1000000.0; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm just checking the whole logic here and I wonder why PHP_TIMEOUT_ULL_MAX is unsigned int 64? The time_t is signed int 64 (or 32 on 32bit arch) if I'm not mistakend. And in this case this is later converted to int (see php_pollfd_for and mainly php_tvtoto). So what am I missing?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it s unsigned but my sense since it s that way because this constant is never used directly but converted from microseconds value to seconds (so yes unsigned int64 > double > time_t or int).
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But how is this covering the lower type overflows? I mean if it gets converted in php_tvtoto, then it will still overflow on conversion to int, right? |
||
|
|
||
| if (limit_time->tv_sec >= (timeoutmax - timeout->tv_sec)) { | ||
| zend_value_error("timeout value overflow"); | ||
| return FAILURE; | ||
| } | ||
|
||
|
|
||
| limit_time->tv_sec += timeout->tv_sec; | ||
| limit_time->tv_usec += timeout->tv_usec; | ||
| if (limit_time->tv_usec >= 1000000) { | ||
| limit_time->tv_usec -= 1000000; | ||
| limit_time->tv_sec++; | ||
| } | ||
| return SUCCESS; | ||
| } | ||
| #endif | ||
|
|
||
|
|
@@ -391,7 +399,11 @@ PHPAPI int php_network_connect_socket(php_socket_t sockfd, | |
| if (timeout) { | ||
| memcpy(&working_timeout, timeout, sizeof(working_timeout)); | ||
| #if HAVE_GETTIMEOFDAY | ||
| php_network_set_limit_time(&limit_time, &working_timeout); | ||
| if (UNEXPECTED(php_network_set_limit_time(&limit_time, &working_timeout) == FAILURE)) { | ||
| error = ERANGE; | ||
| ret = -1; | ||
| goto ok; | ||
| } | ||
| #endif | ||
|
Comment on lines
395
to
397
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
||
| } | ||
|
|
||
|
|
@@ -849,7 +861,10 @@ php_socket_t php_network_connect_socket_to_host(const char *host, unsigned short | |
| if (timeout) { | ||
| memcpy(&working_timeout, timeout, sizeof(working_timeout)); | ||
| #if HAVE_GETTIMEOFDAY | ||
| php_network_set_limit_time(&limit_time, &working_timeout); | ||
| if (UNEXPECTED(php_network_set_limit_time(&limit_time, &working_timeout) == FAILURE)) { | ||
| php_network_freeaddresses(psal); | ||
| return -1; | ||
| } | ||
| #endif | ||
|
Comment on lines
853
to
855
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto |
||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This an issue that cannot appear on 32 bit nor Windows?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes this test "failed" for both earlier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright