Skip to content

Commit 6b64496

Browse files
committed
ext/hash: Fix GH-16711: Segfault in mhash()
1 parent 5253647 commit 6b64496

File tree

1 file changed

+54
-53
lines changed

1 file changed

+54
-53
lines changed

ext/hash/hash.c

Lines changed: 54 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ static struct mhash_bc_entry mhash_to_hash[MHASH_NUM_ALGOS] = {
9999
{"XXH3", "xxh3", 40},
100100
{"XXH128", "xxh128", 41},
101101
};
102+
static bool php_is_valid_mhash_algo(zend_long hash_algo) {
103+
return hash_algo >= 0 && hash_algo < MHASH_NUM_ALGOS && hash_algo != 4 && hash_algo != 6 && hash_algo != 26;
104+
}
105+
102106
#endif
103107

104108
/* Hash Registry Access */
@@ -1184,10 +1188,11 @@ static void mhash_init(INIT_FUNC_ARGS)
11841188
int algo_number = 0;
11851189

11861190
for (algo_number = 0; algo_number < MHASH_NUM_ALGOS; algo_number++) {
1187-
struct mhash_bc_entry algorithm = mhash_to_hash[algo_number];
1188-
if (algorithm.mhash_name == NULL) {
1191+
if (!php_is_valid_mhash_algo(algo_number)) {
11891192
continue;
11901193
}
1194+
struct mhash_bc_entry algorithm = mhash_to_hash[algo_number];
1195+
ZEND_ASSERT(algorithm.mhash_name != NULL);
11911196

11921197
len = slprintf(buf, 127, "MHASH_%s", algorithm.mhash_name);
11931198
zend_register_long_constant(buf, len, algorithm.value, CONST_CS | CONST_PERSISTENT, module_number);
@@ -1209,11 +1214,12 @@ PHP_FUNCTION(mhash)
12091214
}
12101215

12111216
/* need to convert the first parameter from int constant to string algorithm name */
1212-
if (algorithm >= 0 && algorithm < MHASH_NUM_ALGOS) {
1217+
if (php_is_valid_mhash_algo(algorithm)) {
12131218
struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
1214-
if (algorithm_lookup.hash_name) {
1215-
algo = zend_string_init(algorithm_lookup.hash_name, strlen(algorithm_lookup.hash_name), 0);
1216-
}
1219+
ZEND_ASSERT(algorithm_lookup.hash_name != NULL);
1220+
algo = zend_string_init(algorithm_lookup.hash_name, strlen(algorithm_lookup.hash_name), 0);
1221+
} else {
1222+
RETURN_FALSE;
12171223
}
12181224

12191225
if (key) {
@@ -1222,9 +1228,8 @@ PHP_FUNCTION(mhash)
12221228
php_hash_do_hash(return_value, algo, data, data_len, 1, 0, NULL);
12231229
}
12241230

1225-
if (algo) {
1226-
zend_string_release(algo);
1227-
}
1231+
ZEND_ASSERT(algo != NULL);
1232+
zend_string_release(algo);
12281233
}
12291234
/* }}} */
12301235

@@ -1237,11 +1242,10 @@ PHP_FUNCTION(mhash_get_hash_name)
12371242
RETURN_THROWS();
12381243
}
12391244

1240-
if (algorithm >= 0 && algorithm < MHASH_NUM_ALGOS) {
1245+
if (php_is_valid_mhash_algo(algorithm)) {
12411246
struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
1242-
if (algorithm_lookup.mhash_name) {
1243-
RETURN_STRING(algorithm_lookup.mhash_name);
1244-
}
1247+
ZEND_ASSERT(algorithm_lookup.mhash_name != NULL);
1248+
RETURN_STRING(algorithm_lookup.mhash_name);
12451249
}
12461250
RETURN_FALSE;
12471251
}
@@ -1267,14 +1271,12 @@ PHP_FUNCTION(mhash_get_block_size)
12671271
}
12681272
RETVAL_FALSE;
12691273

1270-
if (algorithm >= 0 && algorithm < MHASH_NUM_ALGOS) {
1274+
if (php_is_valid_mhash_algo(algorithm)) {
12711275
struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
1272-
if (algorithm_lookup.mhash_name) {
1273-
const php_hash_ops *ops = zend_hash_str_find_ptr(&php_hash_hashtable, algorithm_lookup.hash_name, strlen(algorithm_lookup.hash_name));
1274-
if (ops) {
1275-
RETVAL_LONG(ops->digest_size);
1276-
}
1277-
}
1276+
ZEND_ASSERT(algorithm_lookup.hash_name != NULL);
1277+
const php_hash_ops *ops = zend_hash_str_find_ptr(&php_hash_hashtable, algorithm_lookup.hash_name, strlen(algorithm_lookup.hash_name));
1278+
ZEND_ASSERT(ops != NULL);
1279+
RETVAL_LONG(ops->digest_size);
12781280
}
12791281
}
12801282
/* }}} */
@@ -1309,46 +1311,45 @@ PHP_FUNCTION(mhash_keygen_s2k)
13091311
salt_len = SALT_SIZE;
13101312

13111313
RETVAL_FALSE;
1312-
if (algorithm >= 0 && algorithm < MHASH_NUM_ALGOS) {
1314+
if (php_is_valid_mhash_algo(algorithm)) {
13131315
struct mhash_bc_entry algorithm_lookup = mhash_to_hash[algorithm];
1314-
if (algorithm_lookup.mhash_name) {
1315-
const php_hash_ops *ops = zend_hash_str_find_ptr(&php_hash_hashtable, algorithm_lookup.hash_name, strlen(algorithm_lookup.hash_name));
1316-
if (ops) {
1317-
unsigned char null = '\0';
1318-
void *context;
1319-
char *key, *digest;
1320-
int i = 0, j = 0;
1321-
size_t block_size = ops->digest_size;
1322-
size_t times = bytes / block_size;
1323-
1324-
if ((bytes % block_size) != 0) {
1325-
times++;
1326-
}
1316+
ZEND_ASSERT(algorithm_lookup.hash_name != NULL);
1317+
const php_hash_ops *ops = zend_hash_str_find_ptr(&php_hash_hashtable, algorithm_lookup.hash_name, strlen(algorithm_lookup.hash_name));
1318+
if (ops) {
1319+
unsigned char null = '\0';
1320+
void *context;
1321+
char *key, *digest;
1322+
int i = 0, j = 0;
1323+
size_t block_size = ops->digest_size;
1324+
size_t times = bytes / block_size;
1325+
1326+
if ((bytes % block_size) != 0) {
1327+
times++;
1328+
}
13271329

1328-
context = php_hash_alloc_context(ops);
1329-
ops->hash_init(context, NULL);
1330+
context = php_hash_alloc_context(ops);
1331+
ops->hash_init(context, NULL);
13301332

1331-
key = ecalloc(1, times * block_size);
1332-
digest = emalloc(ops->digest_size + 1);
1333+
key = ecalloc(1, times * block_size);
1334+
digest = emalloc(ops->digest_size + 1);
13331335

1334-
for (i = 0; i < times; i++) {
1335-
ops->hash_init(context, NULL);
1336+
for (i = 0; i < times; i++) {
1337+
ops->hash_init(context, NULL);
13361338

1337-
for (j=0;j<i;j++) {
1338-
ops->hash_update(context, &null, 1);
1339-
}
1340-
ops->hash_update(context, (unsigned char *)padded_salt, salt_len);
1341-
ops->hash_update(context, (unsigned char *)password, password_len);
1342-
ops->hash_final((unsigned char *)digest, context);
1343-
memcpy( &key[i*block_size], digest, block_size);
1339+
for (j=0;j<i;j++) {
1340+
ops->hash_update(context, &null, 1);
13441341
}
1345-
1346-
RETVAL_STRINGL(key, bytes);
1347-
ZEND_SECURE_ZERO(key, bytes);
1348-
efree(digest);
1349-
efree(context);
1350-
efree(key);
1342+
ops->hash_update(context, (unsigned char *)padded_salt, salt_len);
1343+
ops->hash_update(context, (unsigned char *)password, password_len);
1344+
ops->hash_final((unsigned char *)digest, context);
1345+
memcpy( &key[i*block_size], digest, block_size);
13511346
}
1347+
1348+
RETVAL_STRINGL(key, bytes);
1349+
ZEND_SECURE_ZERO(key, bytes);
1350+
efree(digest);
1351+
efree(context);
1352+
efree(key);
13521353
}
13531354
}
13541355
}

0 commit comments

Comments
 (0)