Fix GH-15980: Signed integer overflow in main/streams/streams.c

We need to avoid signed integer overflows which are undefined behavior.
We catch that, and set `offset` to `ZEND_LONG_MAX` (which is also the
largest value of `zend_off_t` on all platforms).  Of course, after such
a seek a stream is no longer readable, but that matches the current
behavior for offsets near `ZEND_LONG_MAX`.

Closes GH-15989.
This commit is contained in:
Christoph M. Becker 2024-09-22 20:35:56 +02:00
parent f303840a86
commit 6a04c79e41
No known key found for this signature in database
GPG Key ID: D66C9593118BCCB6
3 changed files with 20 additions and 2 deletions

2
NEWS
View File

@ -29,6 +29,8 @@ PHP NEWS
- Streams:
. Fixed bugs GH-15908 and GH-15026 (leak / assertion failure in streams.c).
(nielsdos)
. Fixed bug GH-15980 (Signed integer overflow in main/streams/streams.c).
(cmb)
- TSRM:
. Prevent closing of unrelated handles. (cmb)

View File

@ -0,0 +1,11 @@
--TEST--
GH-15980 (Signed integer overflow in main/streams/streams.c)
--FILE--
<?php
$s = fopen(__FILE__, "r");
fseek($s, 1);
fseek($s, PHP_INT_MAX, SEEK_CUR);
var_dump(ftell($s) > 1);
?>
--EXPECT--
bool(true)

View File

@ -1354,8 +1354,13 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence)
switch(whence) {
case SEEK_CUR:
offset = stream->position + offset;
whence = SEEK_SET;
ZEND_ASSERT(stream->position >= 0);
if (UNEXPECTED(offset > ZEND_LONG_MAX - stream->position)) {
offset = ZEND_LONG_MAX;
} else {
offset = stream->position + offset;
}
whence = SEEK_SET;
break;
}
ret = stream->ops->seek(stream, offset, whence, &stream->position);