Skip to content

Commit e9195b2

Browse files
committed
Merge branch 'PHP-8.1' into PHP-8.2
* PHP-8.1: Fix undefined behaviour in unpack()
2 parents 0ff059c + 8786283 commit e9195b2

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ PHP NEWS
8181
(apache2)). (nielsdos)
8282
. Fixed oss-fuzz #57392 (Buffer-overflow in php_fgetcsv() with \0 delimiter
8383
and enclosure). (ilutov)
84+
. Fixed undefined behaviour in unpack(). (nielsdos)
8485

8586
16 Mar 2023, PHP 8.2.4
8687

ext/standard/pack.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -750,7 +750,16 @@ PHP_FUNCTION(unpack)
750750
c = *format;
751751

752752
if (c >= '0' && c <= '9') {
753-
repetitions = atoi(format);
753+
errno = 0;
754+
long tmp = strtol(format, NULL, 10);
755+
/* There is not strtoi. We have to check the range ourselves.
756+
* With 32-bit long the INT_{MIN,MAX} are useless because long == int, but with 64-bit they do limit us to 32-bit. */
757+
if (errno || tmp < INT_MIN || tmp > INT_MAX) {
758+
php_error_docref(NULL, E_WARNING, "Type %c: integer overflow", type);
759+
zend_array_destroy(Z_ARR_P(return_value));
760+
RETURN_FALSE;
761+
}
762+
repetitions = tmp;
754763

755764
while (formatlen > 0 && *format >= '0' && *format <= '9') {
756765
format++;
@@ -800,7 +809,7 @@ PHP_FUNCTION(unpack)
800809

801810
case 'h':
802811
case 'H':
803-
size = (repetitions > 0) ? (repetitions + (repetitions % 2)) / 2 : repetitions;
812+
size = (repetitions > 0) ? ((unsigned int) repetitions + 1) / 2 : repetitions;
804813
repetitions = 1;
805814
break;
806815

@@ -865,12 +874,6 @@ PHP_FUNCTION(unpack)
865874
RETURN_THROWS();
866875
}
867876

868-
if (size != 0 && size != -1 && size < 0) {
869-
php_error_docref(NULL, E_WARNING, "Type %c: integer overflow", type);
870-
zend_array_destroy(Z_ARR_P(return_value));
871-
RETURN_FALSE;
872-
}
873-
874877

875878
/* Do actual unpacking */
876879
for (i = 0; i != repetitions; i++ ) {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
--TEST--
2+
Test unpacking at the 32-bit integer limit
3+
--FILE--
4+
<?php
5+
$a = pack("AAAAAAAAAAAA", 1,2,3,4,5,6,7,8,9,10,11,12);
6+
unpack('h2147483647', $a);
7+
?>
8+
--EXPECTF--
9+
Warning: unpack(): Type h: not enough input, need 1073741824, have 12 in %s on line %d

0 commit comments

Comments
 (0)