Skip to content

Commit 759829b

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: ext/hash: Fix buffer overflow in hash_pbkdf2() with a large output length
2 parents 48190ac + fbef051 commit 759829b

4 files changed

Lines changed: 55 additions & 3 deletions

File tree

ext/hash/hash.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
#include <config.h>
1818
#endif
1919

20-
#include <math.h>
2120
#include "php_hash.h"
2221
#include "ext/standard/info.h"
2322
#include "ext/standard/file.h"
@@ -1033,10 +1032,10 @@ PHP_FUNCTION(hash_pbkdf2)
10331032
}
10341033
digest_length = length;
10351034
if (!raw_output) {
1036-
digest_length = (zend_long) ceil((float) length / 2.0);
1035+
digest_length = length / 2 + (length % 2);
10371036
}
10381037

1039-
loops = (zend_long) ceil((float) digest_length / (float) ops->digest_size);
1038+
loops = (digest_length - 1) / ops->digest_size + 1;
10401039

10411040
result = safe_emalloc(loops, ops->digest_size, 0);
10421041

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Hash: hash_pbkdf2() function : large output length
3+
--FILE--
4+
<?php
5+
6+
$length = 33554433;
7+
$hash = hash_pbkdf2('md5', 'password', 'salt', 1, $length);
8+
9+
/* The last hexit comes from the first byte of the final PBKDF2 block. */
10+
$block = intdiv(intdiv($length + 1, 2) - 1, 16) + 1;
11+
$expected = bin2hex(hash_hmac('md5', 'salt' . pack('N', $block), 'password', true));
12+
13+
var_dump(strlen($hash));
14+
var_dump($hash[$length - 1] === $expected[0]);
15+
16+
?>
17+
--EXPECT--
18+
int(33554433)
19+
bool(true)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Hash: hash_pbkdf2() function : output length of PHP_INT_MAX
3+
--SKIPIF--
4+
<?php
5+
if (PHP_INT_SIZE == 4) die("skip this test is not for 32bit platforms");
6+
if (getenv("USE_ZEND_ALLOC") === "0") die("skip Zend MM disabled");
7+
?>
8+
--INI--
9+
memory_limit=128M
10+
--FILE--
11+
<?php
12+
13+
hash_pbkdf2('md5', 'password', 'salt', 1, PHP_INT_MAX);
14+
15+
?>
16+
--EXPECTF--
17+
Fatal error: Allowed memory size of 134217728 bytes exhausted%s(tried to allocate 4611686018427387904 bytes) in %s on line %d
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Hash: hash_pbkdf2() function : raw output length of PHP_INT_MAX
3+
--SKIPIF--
4+
<?php
5+
if (PHP_INT_SIZE == 4) die("skip this test is not for 32bit platforms");
6+
if (getenv("USE_ZEND_ALLOC") === "0") die("skip Zend MM disabled");
7+
?>
8+
--INI--
9+
memory_limit=128M
10+
--FILE--
11+
<?php
12+
13+
hash_pbkdf2('md5', 'password', 'salt', 1, PHP_INT_MAX, true);
14+
15+
?>
16+
--EXPECTF--
17+
Fatal error: Allowed memory size of 134217728 bytes exhausted%s(tried to allocate 9223372036854775808 bytes) in %s on line %d

0 commit comments

Comments
 (0)