8000 Make HashContexts serializable by kohler · Pull Request #5702 · php/php-src · GitHub
[go: up one dir, main page]

Skip to content

Make HashContexts serializable #5702

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Add unserializehash fuzzer.
Unlike the straight unserialize fuzzer, this runs only on HashContexts,
and it does an update and finalize on the contexts it creates.

With @nikic.
  • Loading branch information
kohler committed Jun 29, 2020
commit 417414b0345722c99da158b7bbe8e406659f28e2
3 changes: 3 additions & 0 deletions sapi/fuzzer/Makefile.frag
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ $(SAPI_FUZZER_PATH)/php-fuzz-parser: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_F
$(SAPI_FUZZER_PATH)/php-fuzz-unserialize: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_UNSERIALIZE_OBJS)
$(FUZZER_BUILD) $(PHP_FUZZER_UNSERIALIZE_OBJS) -o $@

$(SAPI_FUZZER_PATH)/php-fuzz-unserializehash: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_UNSERIALIZEHASH_OBJS)
$(FUZZER_BUILD) $(PHP_FUZZER_UNSERIALIZEHASH_OBJS) -o $@

$(SAPI_FUZZER_PATH)/php-fuzz-json: $(PHP_GLOBAL_OBJS) $(PHP_SAPI_OBJS) $(PHP_FUZZER_JSON_OBJS)
$(FUZZER_BUILD) $(PHP_FUZZER_JSON_OBJS) -o $@

Expand Down
9 changes: 9 additions & 0 deletions sapi/fuzzer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ When running `make` it creates these binaries in `sapi/fuzzer/`:

* `php-fuzz-parser`: Fuzzing language parser and compiler
* `php-fuzz-unserialize`: Fuzzing unserialize() function
* `php-fuzz-unserializehash`: Fuzzing unserialize() for HashContext objects
* `php-fuzz-json`: Fuzzing JSON parser (requires --enable-json)
* `php-fuzz-exif`: Fuzzing `exif_read_data()` function (requires --enable-exif)
* `php-fuzz-mbstring`: fuzzing `mb_ereg[i]()` (requires --enable-mbstring)
Expand All @@ -41,6 +42,14 @@ cp -r sapi/fuzzer/corpus/unserialize ./my-unserialize-corpus
sapi/fuzzer/php-fuzz-unserialize -dict=$PWD/sapi/fuzzer/dict/unserialize ./my-unserialize-corpus
```

For the unserializehash fuzzer, generate a corpus of initial hash serializations:

```sh
sapi/cli/php sapi/fuzzer/generate_unserializehash_corpus.php
cp -r sapi/fuzzer/corpus/unserializehash ./my-unserialize-corpus
sapi/fuzzer/php-fuzz-unserializehash ./my-unserialize-corpus
```

For the parser fuzzer, a corpus may be generated from Zend test files:

```sh
Expand Down
1 change: 1 addition & 0 deletions sapi/fuzzer/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ if test "$PHP_FUZZER" != "no"; then

PHP_FUZZER_TARGET([parser], PHP_FUZZER_PARSER_OBJS)
PHP_FUZZER_TARGET([unserialize], PHP_FUZZER_UNSERIALIZE_OBJS)
PHP_FUZZER_TARGET([unserializehash], PHP_FUZZER_UNSERIALIZEHASH_OBJS)
PHP_FUZZER_TARGET([json], PHP_FUZZER_JSON_OBJS)

if test -n "$enable_exif" && test "$enable_exif" != "no"; then
Expand Down
104 changes: 104 additions & 0 deletions sapi/fuzzer/fuzzer-unserializehash.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
+----------------------------------------------------------------------+
| Copyright (c) The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/


#include "fuzzer.h"

#include "Zend/zend.h"
#include "main/php_config.h"
#include "main/php_main.h"

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

#include "fuzzer-sapi.h"

#include "ext/standard/php_var.h"

int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t FullSize) {
zend_execute_data execute_data;
zend_function func;
const uint8_t *Start = memchr(Data, '|', FullSize);
if (!Start) {
return 0;
}
++Start;

size_t Size = (Data + FullSize) - Start;
unsigned char *orig_data = malloc(Size+1);
memcpy(orig_data, Start, Size);
orig_data[Size] = '\0';

if (fuzzer_request_startup()==FAILURE) {
return 0;
}

/* Set up a dummy stack frame so that exceptions may be thrown. */
{
memset(&execute_data, 0, sizeof(zend_execute_data));
memset(&func, 0, sizeof(zend_function));

func.type = ZEND_INTERNAL_FUNCTION;
func.common.function_name = ZSTR_EMPTY_ALLOC();
execute_data.func = &func;
EG(current_execute_data) = &execute_data;
}

{
const unsigned char *data = orig_data;
zval result;
ZVAL_UNDEF(&result);

php_unserialize_data_t var_hash;
PHP_VAR_UNSERIALIZE_INIT(var_hash);
php_var_unserialize(&result, (const unsigned char **) &data, data + Size, &var_hash);
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);

if (Z_TYPE(result) == IS_OBJECT
&& zend_string_equals_literal(Z_OBJCE(result)->name, "HashContext")) {
zval args[2];
ZVAL_COPY_VALUE(&args[0], &result);
ZVAL_STRINGL(&args[1], (char *) Data, (Start - Data) - 1);
fuzzer_call_php_func_zval("hash_update", 2, args);
zval_ptr_dtor(&args[1]);
fuzzer_call_php_func_zval("hash_final", 1, args);
}

zval_ptr_dtor(&result);

/* Destroy any thrown exception. */
if (EG(exception)) {
zend_object_release(EG(exception));
EG(exception) = NULL;
}
}

/* Unserialize may create circular structure. Make sure we free them.
* Two calls are performed to handle objects with destructors. */
zend_gc_collect_cycles();
zend_gc_collect_cycles();
php_request_shutdown(NULL);

free(orig_data);

return 0;
}

int LLVMFuzzerInitialize(int *argc, char ***argv) {
fuzzer_init_php();

/* fuzzer_shutdown_php(); */
return 0;
}
10 changes: 10 additions & 0 deletions sapi/fuzzer/generate_unserializehash_corpus.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?php

$corpusDir = __DIR__ . '/corpus/unserializehash';
@mkdir($corpusDir);

foreach (hash_algos() as $algo) {
$ctx = hash_init($algo);
$algx = preg_replace('/[^-_a-zA-Z0-9]/', '_', $algo);
file_put_contents($corpusDir . '/' . $algx, "x|" . serialize($ctx));
}
0