Skip to content

Commit 2b8c008

Browse files
committed
Fix GH-12936: hash() function hangs endlessly if using sha512 on strings >= 4GiB
There's two problems: - Some loops used `unsigned int` instead of `size_t`. - The 2*N-bit addition that is emulated using 2 N bit numbers has a bug: it first truncated the number to 32/64 bit and only then shifted. This resulted in the wrong length info stored inside the resulting hash. Closes GH-12937.
1 parent 623da03 commit 2b8c008

File tree

7 files changed

+39
-24
lines changed

7 files changed

+39
-24
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ PHP NEWS
66
. Fix incorrect timeout in built-in web server when using router script and
77
max_input_time. (ilutov)
88

9+
- Hash:
10+
. Fixed bug GH-12936 (hash() function hangs endlessly if using sha512 on
11+
strings >= 4GiB). (nielsdos)
12+
913
- Opcache:
1014
. Fixed oss-fuzz #64727 (JIT undefined array key warning may overwrite DIM
1115
with NULL when DIM is the same var as result). (ilutov)

ext/hash/hash_adler32.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ PHP_HASH_API void PHP_ADLER32Init(PHP_ADLER32_CTX *context, ZEND_ATTRIBUTE_UNUSE
2525

2626
PHP_HASH_API void PHP_ADLER32Update(PHP_ADLER32_CTX *context, const unsigned char *input, size_t len)
2727
{
28-
uint32_t i, s[2];
28+
uint32_t s[2];
2929

3030
s[0] = context->state & 0xffff;
3131
s[1] = (context->state >> 16) & 0xffff;
32-
for (i = 0; i < len; ++i) {
32+
for (size_t i = 0; i < len; ++i) {
3333
s[0] += input[i];
3434
s[1] += s[0];
3535
if (s[1]>=0x7fffffff)

ext/hash/hash_haval.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,15 +280,16 @@ PHP_HASH_HAVAL_INIT(5,256)
280280
/* {{{ PHP_HAVALUpdate */
281281
PHP_HASH_API void PHP_HAVALUpdate(PHP_HAVAL_CTX *context, const unsigned char *input, size_t inputLen)
282282
{
283-
unsigned int i, index, partLen;
283+
unsigned int index, partLen;
284+
size_t i;
284285

285286
/* Compute number of bytes mod 128 */
286287
index = (unsigned int) ((context->count[0] >> 3) & 0x7F);
287288
/* Update number of bits */
288289
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
289290
context->count[1]++;
290291
}
291-
context->count[1] += ((uint32_t) inputLen >> 29);
292+
context->count[1] += (uint32_t) (inputLen >> 29);
292293

293294
partLen = 128 - index;
294295

ext/hash/hash_md.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ PHP_HASH_API void PHP_MD4InitArgs(PHP_MD4_CTX * context, ZEND_ATTRIBUTE_UNUSED H
204204
*/
205205
PHP_HASH_API void PHP_MD4Update(PHP_MD4_CTX * context, const unsigned char *input, size_t inputLen)
206206
{
207-
unsigned int i, index, partLen;
207+
unsigned int index, partLen;
208+
size_t i;
208209

209210
/* Compute number of bytes mod 64 */
210211
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
@@ -213,7 +214,7 @@ PHP_HASH_API void PHP_MD4Update(PHP_MD4_CTX * context, const unsigned char *inpu
213214
if ((context->count[0] += ((uint32_t) inputLen << 3))
214215
< ((uint32_t) inputLen << 3))
215216
context->count[1]++;
216-
context->count[1] += ((uint32_t) inputLen >> 29);
217+
context->count[1] += (uint32_t) (inputLen >> 29);
217218

218219
partLen = 64 - index;
219220

ext/hash/hash_ripemd.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ static void RIPEMD128Transform(uint32_t state[4], const unsigned char block[64])
271271
*/
272272
PHP_HASH_API void PHP_RIPEMD128Update(PHP_RIPEMD128_CTX * context, const unsigned char *input, size_t inputLen)
273273
{
274-
unsigned int i, index, partLen;
274+
unsigned int index, partLen;
275+
size_t i;
275276

276277
/* Compute number of bytes mod 64 */
277278
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
@@ -280,7 +281,7 @@ PHP_HASH_API void PHP_RIPEMD128Update(PHP_RIPEMD128_CTX * context, const unsigne
280281
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
281282
context->count[1]++;
282283
}
283-
context->count[1] += ((uint32_t) inputLen >> 29);
284+
context->count[1] += (uint32_t) (inputLen >> 29);
284285

285286
partLen = 64 - index;
286287

@@ -369,7 +370,8 @@ static void RIPEMD256Transform(uint32_t state[8], const unsigned char block[64])
369370
*/
370371
PHP_HASH_API void PHP_RIPEMD256Update(PHP_RIPEMD256_CTX * context, const unsigned char *input, size_t inputLen)
371372
{
372-
unsigned int i, index, partLen;
373+
unsigned int index, partLen;
374+
size_t i;
373375

374376
/* Compute number of bytes mod 64 */
375377
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
@@ -378,7 +380,7 @@ PHP_HASH_API void PHP_RIPEMD256Update(PHP_RIPEMD256_CTX * context, const unsigne
378380
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
379381
context->count[1]++;
380382
}
381-
context->count[1] += ((uint32_t) inputLen >> 29);
383+
context->count[1] += (uint32_t) (inputLen >> 29);
382384

383385
partLen = 64 - index;
384386

@@ -468,7 +470,8 @@ static void RIPEMD160Transform(uint32_t state[5], const unsigned char block[64])
468470
*/
469471
PHP_HASH_API void PHP_RIPEMD160Update(PHP_RIPEMD160_CTX * context, const unsigned char *input, size_t inputLen)
470472
{
471-
unsigned int i, index, partLen;
473+
unsigned int index, partLen;
474+
size_t i;
472475

473476
/* Compute number of bytes mod 64 */
474477
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
@@ -477,7 +480,7 @@ PHP_HASH_API void PHP_RIPEMD160Update(PHP_RIPEMD160_CTX * context, const unsigne
477480
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
478481
context->count[1]++;
479482
}
480-
context->count[1] += ((uint32_t) inputLen >> 29);
483+
context->count[1] += (uint32_t) (inputLen >> 29);
481484

482485
partLen = 64 - index;
483486

@@ -576,7 +579,8 @@ static void RIPEMD320Transform(uint32_t state[10], const unsigned char block[64]
576579
*/
577580
PHP_HASH_API void PHP_RIPEMD320Update(PHP_RIPEMD320_CTX * context, const unsigned char *input, size_t inputLen)
578581
{
579-
unsigned int i, index, partLen;
582+
unsigned int index, partLen;
583+
size_t i;
580584

581585
/* Compute number of bytes mod 64 */
582586
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
@@ -585,7 +589,7 @@ PHP_HASH_API void PHP_RIPEMD320Update(PHP_RIPEMD320_CTX * context, const unsigne
585589
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
586590
context->count[1]++;
587591
}
588-
context->count[1] += ((uint32_t) inputLen >> 29);
592+
context->count[1] += (uint32_t) (inputLen >> 29);
589593

590594
partLen = 64 - index;
591595

ext/hash/hash_sha.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,8 @@ PHP_HASH_API void PHP_SHA224InitArgs(PHP_SHA224_CTX * context, ZEND_ATTRIBUTE_UN
222222
*/
223223
PHP_HASH_API void PHP_SHA224Update(PHP_SHA224_CTX * context, const unsigned char *input, size_t inputLen)
224224
{
225-
unsigned int i, index, partLen;
225+
unsigned int index, partLen;
226+
size_t i;
226227

227228
/* Compute number of bytes mod 64 */
228229
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
@@ -231,7 +232,7 @@ PHP_HASH_API void PHP_SHA224Update(PHP_SHA224_CTX * context, const unsigned char
231232
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
232233
context->count[1]++;
233234
}
234-
context->count[1] += ((uint32_t) inputLen >> 29);
235+
context->count[1] += (uint32_t) (inputLen >> 29);
235236

236237
partLen = 64 - index;
237238

@@ -299,7 +300,8 @@ PHP_HASH_API void PHP_SHA224Final(unsigned char digest[28], PHP_SHA224_CTX * con
299300
*/
300301
PHP_HASH_API void PHP_SHA256Update(PHP_SHA256_CTX * context, const unsigned char *input, size_t inputLen)
301302
{
302-
unsigned int i, index, partLen;
303+
unsigned int index, partLen;
304+
size_t i;
303305

304306
/* Compute number of bytes mod 64 */
305307
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
@@ -308,7 +310,7 @@ PHP_HASH_API void PHP_SHA256Update(PHP_SHA256_CTX * context, const unsigned char
308310
if ((context->count[0] += ((uint32_t) inputLen << 3)) < ((uint32_t) inputLen << 3)) {
309311
context->count[1]++;
310312
}
311-
context->count[1] += ((uint32_t) inputLen >> 29);
313+
context->count[1] += (uint32_t) (inputLen >> 29);
312314

313315
partLen = 64 - index;
314316

@@ -513,7 +515,8 @@ static void SHA512Transform(uint64_t state[8], const unsigned char block[128])
513515
*/
514516
PHP_HASH_API void PHP_SHA384Update(PHP_SHA384_CTX * context, const unsigned char *input, size_t inputLen)
515517
{
516-
unsigned int i = 0, index, partLen;
518+
unsigned int index, partLen;
519+
size_t i = 0;
517520

518521
/* Compute number of bytes mod 128 */
519522
index = (unsigned int) ((context->count[0] >> 3) & 0x7F);
@@ -522,7 +525,7 @@ PHP_HASH_API void PHP_SHA384Update(PHP_SHA384_CTX * context, const unsigned char
522525
if ((context->count[0] += ((uint64_t) inputLen << 3)) < ((uint64_t) inputLen << 3)) {
523526
context->count[1]++;
524527
}
525-
context->count[1] += ((uint64_t) inputLen >> 61);
528+
context->count[1] += (uint64_t) (inputLen >> 61);
526529

527530
partLen = 128 - index;
528531

@@ -666,7 +669,8 @@ PHP_HASH_API void PHP_SHA512_224InitArgs(PHP_SHA512_CTX * context, ZEND_ATTRIBUT
666669
*/
667670
PHP_HASH_API void PHP_SHA512Update(PHP_SHA512_CTX * context, const unsigned char *input, size_t inputLen)
668671
{
669-
unsigned int i, index, partLen;
672+
unsigned int index, partLen;
673+
size_t i;
670674

671675
/* Compute number of bytes mod 128 */
672676
index = (unsigned int) ((context->count[0] >> 3) & 0x7F);
@@ -675,7 +679,7 @@ PHP_HASH_API void PHP_SHA512Update(PHP_SHA512_CTX * context, const unsigned char
675679
if ((context->count[0] += ((uint64_t) inputLen << 3)) < ((uint64_t) inputLen << 3)) {
676680
context->count[1]++;
677681
}
678-
context->count[1] += ((uint64_t) inputLen >> 61);
682+
context->count[1] += (uint64_t) (inputLen >> 61);
679683

680684
partLen = 128 - index;
681685

ext/standard/sha1.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ PHPAPI void PHP_SHA1InitArgs(PHP_SHA1_CTX * context, ZEND_ATTRIBUTE_UNUSED HashT
173173
PHPAPI void PHP_SHA1Update(PHP_SHA1_CTX * context, const unsigned char *input,
174174
size_t inputLen)
175175
{
176-
unsigned int i, index, partLen;
176+
unsigned int index, partLen;
177+
size_t i;
177178

178179
/* Compute number of bytes mod 64 */
179180
index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
@@ -182,7 +183,7 @@ PHPAPI void PHP_SHA1Update(PHP_SHA1_CTX * context, const unsigned char *input,
182183
if ((context->count[0] += ((uint32_t) inputLen << 3))
183184
< ((uint32_t) inputLen << 3))
184185
context->count[1]++;
185-
context->count[1] += ((uint32_t) inputLen >> 29);
186+
context->count[1] += (uint32_t) (inputLen >> 29);
186187

187188
partLen = 64 - index;
188189

0 commit comments

Comments
 (0)