diff --git a/ext/hash/hash.c b/ext/hash/hash.c index ec5391a62304..6e8bc49d34d1 100644 --- a/ext/hash/hash.c +++ b/ext/hash/hash.c @@ -388,7 +388,7 @@ static void php_hash_do_hash( } php_stream_close(stream); if (n < 0) { - efree(context); + php_hash_free_context(ops, context); RETURN_FALSE; } } else { @@ -397,7 +397,7 @@ static void php_hash_do_hash( digest = zend_string_alloc(ops->digest_size, 0); ops->hash_final((unsigned char *) ZSTR_VAL(digest), context); - efree(context); + php_hash_free_context(ops, context); if (raw_output) { ZSTR_VAL(digest)[ops->digest_size] = 0; @@ -536,7 +536,7 @@ static void php_hash_do_hash_hmac( } php_stream_close(stream); if (n < 0) { - efree(context); + php_hash_free_context(ops, context); efree(K); zend_string_efree(digest); RETURN_FALSE; @@ -554,7 +554,7 @@ static void php_hash_do_hash_hmac( /* Zero the key */ ZEND_SECURE_ZERO(K, ops->block_size); efree(K); - efree(context); + php_hash_free_context(ops, context); if (raw_output) { ZSTR_VAL(digest)[ops->digest_size] = 0; @@ -815,7 +815,7 @@ PHP_FUNCTION(hash_final) ZSTR_VAL(digest)[digest_len] = 0; /* Invalidate the object from further use */ - efree(hash->context); + php_hash_free_context(hash->ops, hash->context); hash->context = NULL; if (raw_output) { @@ -973,7 +973,7 @@ PHP_FUNCTION(hash_hkdf) ZEND_SECURE_ZERO(digest, ops->digest_size); ZEND_SECURE_ZERO(prk, ops->digest_size); efree(K); - efree(context); + php_hash_free_context(ops, context); efree(prk); efree(digest); ZSTR_VAL(returnval)[length] = 0; @@ -1089,7 +1089,7 @@ PHP_FUNCTION(hash_pbkdf2) efree(K1); efree(K2); efree(computed_salt); - efree(context); + php_hash_free_context(ops, context); efree(digest); efree(temp); @@ -1356,7 +1356,7 @@ PHP_FUNCTION(mhash_keygen_s2k) RETVAL_STRINGL(key, bytes); ZEND_SECURE_ZERO(key, bytes); efree(digest); - efree(context); + php_hash_free_context(ops, context); efree(key); } } @@ -1386,7 +1386,7 @@ static void php_hashcontext_dtor(zend_object *obj) { php_hashcontext_object *hash = php_hashcontext_from_object(obj); if (hash->context) { - efree(hash->context); + php_hash_free_context(hash->ops, hash->context); hash->context = NULL; } @@ -1422,7 +1422,7 @@ static zend_object *php_hashcontext_clone(zend_object *zobj) { newobj->ops->hash_init(newobj->context, NULL); if (SUCCESS != newobj->ops->hash_copy(newobj->ops, oldobj->context, newobj->context)) { - efree(newobj->context); + php_hash_free_context(newobj->ops, newobj->context); newobj->context = NULL; return znew; } diff --git a/ext/hash/hash_xxhash.c b/ext/hash/hash_xxhash.c index add922e8e84f..4e45f7a0d95e 100644 --- a/ext/hash/hash_xxhash.c +++ b/ext/hash/hash_xxhash.c @@ -152,7 +152,8 @@ const php_hash_ops php_hash_xxh3_64_ops = { 8, 8, sizeof(PHP_XXH3_64_CTX), - 0 + 0, + 64 }; typedef XXH_errorcode (*xxh3_reset_with_secret_func_t)(XXH3_state_t*, const void*, size_t); @@ -257,7 +258,8 @@ const php_hash_ops php_hash_xxh3_128_ops = { 16, 8, sizeof(PHP_XXH3_128_CTX), - 0 + 0, + 64 }; PHP_HASH_API void PHP_XXH3_128_Init(PHP_XXH3_128_CTX *ctx, HashTable *args) diff --git a/ext/hash/php_hash.h b/ext/hash/php_hash.h index f56605a33be6..34d44137028d 100644 --- a/ext/hash/php_hash.h +++ b/ext/hash/php_hash.h @@ -60,6 +60,7 @@ typedef struct _php_hash_ops { size_t block_size; size_t context_size; unsigned is_crypto: 1; + size_t context_align; } php_hash_ops; struct _php_hashcontext_object { @@ -163,9 +164,26 @@ PHP_HASH_API hash_spec_result php_hash_unserialize_spec(php_hashcontext_object * static inline void *php_hash_alloc_context(const php_hash_ops *ops) { /* Zero out context memory so serialization doesn't expose internals */ + if (ops->context_align > 0) { + size_t align = ops->context_align; + char *base = ecalloc(1, ops->context_size + align); + size_t offset = align - ((uintptr_t)base & (align - 1)); + char *ptr = base + offset; + ptr[-1] = (char)offset; + return ptr; + } return ecalloc(1, ops->context_size); } +static inline void php_hash_free_context(const php_hash_ops *ops, void *ctx) { + if (ops->context_align > 0) { + unsigned char offset = ((unsigned char *)ctx)[-1]; + efree((char *)ctx - offset); + return; + } + efree(ctx); +} + static inline void php_hash_bin2hex(char *out, const unsigned char *in, size_t in_len) { static const char hexits[17] = "0123456789abcdef";