Skip to content

Commit b6d6106

Browse files
committed
Fix GH-18173: ext/hash relies on implementation-defined malloc alignment
XXH3_state_t requires 64-byte alignment for its acc, customSecret, and buffer members. php_hash_alloc_context() used ecalloc() which only guarantees alignof(max_align_t) alignment -- typically 16 bytes on x86_64. When heap layout broke that assumption, xxhash's aligned loads would segfault. Add a context_align field to php_hash_ops. When set, php_hash_alloc_context() over-allocates and manually aligns the returned pointer, storing the offset for php_hash_free_context() to recover the original allocation.
1 parent 1f4b169 commit b6d6106

17 files changed

+89
-34
lines changed

ext/hash/hash.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ static void php_hash_do_hash(
392392
}
393393
php_stream_close(stream);
394394
if (n < 0) {
395-
efree(context);
395+
php_hash_free_context(ops, context);
396396
RETURN_FALSE;
397397
}
398398
} else {
@@ -401,7 +401,7 @@ static void php_hash_do_hash(
401401

402402
digest = zend_string_alloc(ops->digest_size, 0);
403403
ops->hash_final((unsigned char *) ZSTR_VAL(digest), context);
404-
efree(context);
404+
php_hash_free_context(ops, context);
405405

406406
if (raw_output) {
407407
ZSTR_VAL(digest)[ops->digest_size] = 0;
@@ -540,7 +540,7 @@ static void php_hash_do_hash_hmac(
540540
}
541541
php_stream_close(stream);
542542
if (n < 0) {
543-
efree(context);
543+
php_hash_free_context(ops, context);
544544
efree(K);
545545
zend_string_release(digest);
546546
RETURN_FALSE;
@@ -558,7 +558,7 @@ static void php_hash_do_hash_hmac(
558558
/* Zero the key */
559559
ZEND_SECURE_ZERO(K, ops->block_size);
560560
efree(K);
561-
efree(context);
561+
php_hash_free_context(ops, context);
562562

563563
if (raw_output) {
564564
ZSTR_VAL(digest)[ops->digest_size] = 0;
@@ -817,7 +817,7 @@ PHP_FUNCTION(hash_final)
817817
ZSTR_VAL(digest)[digest_len] = 0;
818818

819819
/* Invalidate the object from further use */
820-
efree(hash->context);
820+
php_hash_free_context(hash->ops, hash->context);
821821
hash->context = NULL;
822822

823823
if (raw_output) {
@@ -975,7 +975,7 @@ PHP_FUNCTION(hash_hkdf)
975975
ZEND_SECURE_ZERO(digest, ops->digest_size);
976976
ZEND_SECURE_ZERO(prk, ops->digest_size);
977977
efree(K);
978-
efree(context);
978+
php_hash_free_context(ops, context);
979979
efree(prk);
980980
efree(digest);
981981
ZSTR_VAL(returnval)[length] = 0;
@@ -1091,7 +1091,7 @@ PHP_FUNCTION(hash_pbkdf2)
10911091
efree(K1);
10921092
efree(K2);
10931093
efree(computed_salt);
1094-
efree(context);
1094+
php_hash_free_context(ops, context);
10951095
efree(digest);
10961096
efree(temp);
10971097

@@ -1347,7 +1347,7 @@ PHP_FUNCTION(mhash_keygen_s2k)
13471347
RETVAL_STRINGL(key, bytes);
13481348
ZEND_SECURE_ZERO(key, bytes);
13491349
efree(digest);
1350-
efree(context);
1350+
php_hash_free_context(ops, context);
13511351
efree(key);
13521352
}
13531353
}
@@ -1377,7 +1377,7 @@ static void php_hashcontext_dtor(zend_object *obj) {
13771377
php_hashcontext_object *hash = php_hashcontext_from_object(obj);
13781378

13791379
if (hash->context) {
1380-
efree(hash->context);
1380+
php_hash_free_context(hash->ops, hash->context);
13811381
hash->context = NULL;
13821382
}
13831383

@@ -1413,7 +1413,7 @@ static zend_object *php_hashcontext_clone(zend_object *zobj) {
14131413
newobj->ops->hash_init(newobj->context, NULL);
14141414

14151415
if (SUCCESS != newobj->ops->hash_copy(newobj->ops, oldobj->context, newobj->context)) {
1416-
efree(newobj->context);
1416+
php_hash_free_context(newobj->ops, newobj->context);
14171417
newobj->context = NULL;
14181418
return znew;
14191419
}

ext/hash/hash_adler32.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,6 @@ const php_hash_ops php_hash_adler32_ops = {
7070
4, /* what to say here? */
7171
4,
7272
sizeof(PHP_ADLER32_CTX),
73+
0,
7374
0
7475
};

ext/hash/hash_crc32.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ const php_hash_ops php_hash_crc32_ops = {
102102
4, /* what to say here? */
103103
4,
104104
sizeof(PHP_CRC32_CTX),
105+
0,
105106
0
106107
};
107108

@@ -117,6 +118,7 @@ const php_hash_ops php_hash_crc32b_ops = {
117118
4, /* what to say here? */
118119
4,
119120
sizeof(PHP_CRC32_CTX),
121+
0,
120122
0
121123
};
122124

@@ -132,5 +134,6 @@ const php_hash_ops php_hash_crc32c_ops = {
132134
4, /* what to say here? */
133135
4,
134136
sizeof(PHP_CRC32_CTX),
137+
0,
135138
0
136139
};

ext/hash/hash_fnv.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const php_hash_ops php_hash_fnv132_ops = {
3232
4,
3333
4,
3434
sizeof(PHP_FNV132_CTX),
35+
0,
3536
0
3637
};
3738

@@ -47,6 +48,7 @@ const php_hash_ops php_hash_fnv1a32_ops = {
4748
4,
4849
4,
4950
sizeof(PHP_FNV132_CTX),
51+
0,
5052
0
5153
};
5254

@@ -62,6 +64,7 @@ const php_hash_ops php_hash_fnv164_ops = {
6264
8,
6365
4,
6466
sizeof(PHP_FNV164_CTX),
67+
0,
6568
0
6669
};
6770

@@ -77,6 +80,7 @@ const php_hash_ops php_hash_fnv1a64_ops = {
7780
8,
7881
4,
7982
sizeof(PHP_FNV164_CTX),
83+
0,
8084
0
8185
};
8286

ext/hash/hash_gost.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,8 @@ const php_hash_ops php_hash_gost_ops = {
329329
32,
330330
32,
331331
sizeof(PHP_GOST_CTX),
332-
1
332+
1,
333+
0
333334
};
334335

335336
const php_hash_ops php_hash_gost_crypto_ops = {
@@ -344,5 +345,6 @@ const php_hash_ops php_hash_gost_crypto_ops = {
344345
32,
345346
32,
346347
sizeof(PHP_GOST_CTX),
347-
1
348+
1,
349+
0
348350
};

ext/hash/hash_haval.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ const php_hash_ops php_hash_##p##haval##b##_ops = { \
252252
php_hash_serialize, \
253253
php_hash_unserialize, \
254254
PHP_HAVAL_SPEC, \
255-
((b) / 8), 128, sizeof(PHP_HAVAL_CTX), 1 }; \
255+
((b) / 8), 128, sizeof(PHP_HAVAL_CTX), 1, 0 }; \
256256
PHP_HASH_API void PHP_##p##HAVAL##b##Init(PHP_HAVAL_CTX *context, ZEND_ATTRIBUTE_UNUSED HashTable *args) \
257257
{ int i; context->count[0] = context->count[1] = 0; \
258258
for(i = 0; i < 8; i++) context->state[i] = D0[i]; \

ext/hash/hash_joaat.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const php_hash_ops php_hash_joaat_ops = {
3333
4,
3434
4,
3535
sizeof(PHP_JOAAT_CTX),
36+
0,
3637
0
3738
};
3839

ext/hash/hash_md.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ const php_hash_ops php_hash_md5_ops = {
2929
16,
3030
64,
3131
sizeof(PHP_MD5_CTX),
32-
1
32+
1,
33+
0
3334
};
3435

3536
const php_hash_ops php_hash_md4_ops = {
@@ -44,7 +45,8 @@ const php_hash_ops php_hash_md4_ops = {
4445
16,
4546
64,
4647
sizeof(PHP_MD4_CTX),
47-
1
48+
1,
49+
0
4850
};
4951

5052
static int php_md2_unserialize(php_hashcontext_object *hash, zend_long magic, const zval *zv);
@@ -61,7 +63,8 @@ const php_hash_ops php_hash_md2_ops = {
6163
16,
6264
16,
6365
sizeof(PHP_MD2_CTX),
64-
1
66+
1,
67+
0
6568
};
6669

6770
/* MD common stuff */

ext/hash/hash_murmur.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ const php_hash_ops php_hash_murmur3a_ops = {
3333
4,
3434
4,
3535
sizeof(PHP_MURMUR3A_CTX),
36+
0,
3637
0
3738
};
3839

@@ -95,6 +96,7 @@ const php_hash_ops php_hash_murmur3c_ops = {
9596
16,
9697
4,
9798
sizeof(PHP_MURMUR3C_CTX),
99+
0,
98100
0
99101
};
100102

@@ -174,6 +176,7 @@ const php_hash_ops php_hash_murmur3f_ops = {
174176
16,
175177
8,
176178
sizeof(PHP_MURMUR3F_CTX),
179+
0,
177180
0
178181
};
179182

ext/hash/hash_ripemd.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ const php_hash_ops php_hash_ripemd128_ops = {
3333
16,
3434
64,
3535
sizeof(PHP_RIPEMD128_CTX),
36-
1
36+
1,
37+
0
3738
};
3839

3940
const php_hash_ops php_hash_ripemd160_ops = {
@@ -48,7 +49,8 @@ const php_hash_ops php_hash_ripemd160_ops = {
4849
20,
4950
64,
5051
sizeof(PHP_RIPEMD160_CTX),
51-
1
52+
1,
53+
0
5254
};
5355

5456
const php_hash_ops php_hash_ripemd256_ops = {
@@ -63,7 +65,8 @@ const php_hash_ops php_hash_ripemd256_ops = {
6365
32,
6466
64,
6567
sizeof(PHP_RIPEMD256_CTX),
66-
1
68+
1,
69+
0
6770
};
6871

6972
const php_hash_ops php_hash_ripemd320_ops = {
@@ -78,7 +81,8 @@ const php_hash_ops php_hash_ripemd320_ops = {
7881
40,
7982
64,
8083
sizeof(PHP_RIPEMD320_CTX),
81-
1
84+
1,
85+
0
8286
};
8387

8488
/* {{{ PHP_RIPEMD128Init

0 commit comments

Comments
 (0)