diff options
author | Ravi Jotwani <rjotwani@google.com> | 2020-08-12 15:44:24 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-12 15:44:24 -0700 |
commit | 8a74af8f52c9e6c934c0f3aea3896bee080224f5 (patch) | |
tree | 9eaa14ad399ab494b1390f6166b90684099eec7d /projects/libyaml | |
parent | 089c9e039b11b216705a3bc2dc77cad039ac328c (diff) | |
download | oss-fuzz-8a74af8f52c9e6c934c0f3aea3896bee080224f5.tar.gz |
[libyaml] Add more fuzz targets (#4043)
* added draco integration files
* wrote build file and Dockerfile for Draco
* added more fuzzers, updated build script to generate corpus and options for each
* place yaml.dict in SRC first, rather than in OUT directly
* changed fuzzers from c++ to c, updated build script
* started using booleans instead of ints, updated naming conventions
* replaced all instances of with
* removed memsets, stopped using first two bytes of input, and removed file I/O
* fixed style, changed function return types to bool instead of int
* added libyaml_parser_fuzzer back, implemented string handling to not exceed buffer size in libyaml_emitter_fuzzer, and made style fixes
* changed boolean functions to return error, not success
* fixed inverted check
* changed variable names, fixed crash in libyaml_emitter_fuzzer
* fixed addition/subtraction style
* make a dynamically growing heap buffer
* place yaml_write_handler in distinct header file, style fixes
* fix style and memory safety issues in reformatter fuzzers, remove unused vars
* consistent assignment of done variables
Diffstat (limited to 'projects/libyaml')
-rw-r--r-- | projects/libyaml/Dockerfile | 4 | ||||
-rwxr-xr-x | projects/libyaml/build.sh | 23 | ||||
-rw-r--r-- | projects/libyaml/libyaml_deconstructor_alt_fuzzer.c | 833 | ||||
-rw-r--r-- | projects/libyaml/libyaml_deconstructor_fuzzer.c | 994 | ||||
-rw-r--r-- | projects/libyaml/libyaml_dumper_fuzzer.c | 311 | ||||
-rw-r--r-- | projects/libyaml/libyaml_emitter_fuzzer.c | 298 | ||||
-rw-r--r-- | projects/libyaml/libyaml_fuzzer.cc | 21 | ||||
-rw-r--r-- | projects/libyaml/libyaml_loader_fuzzer.c | 51 | ||||
-rw-r--r-- | projects/libyaml/libyaml_parser_fuzzer.c | 49 | ||||
-rw-r--r-- | projects/libyaml/libyaml_reformatter_alt_fuzzer.c | 86 | ||||
-rw-r--r-- | projects/libyaml/libyaml_reformatter_fuzzer.c | 86 | ||||
-rw-r--r-- | projects/libyaml/libyaml_scanner_fuzzer.c | 51 | ||||
-rw-r--r-- | projects/libyaml/yaml_write_handler.h | 37 |
13 files changed, 2816 insertions, 28 deletions
diff --git a/projects/libyaml/Dockerfile b/projects/libyaml/Dockerfile index d52249eb8..8477cced9 100644 --- a/projects/libyaml/Dockerfile +++ b/projects/libyaml/Dockerfile @@ -18,7 +18,7 @@ FROM gcr.io/oss-fuzz-base/base-builder RUN apt-get update && apt-get install -y make autoconf automake libtool RUN git clone --depth=1 https://github.com/yaml/libyaml -RUN zip libyaml_fuzzer_seed_corpus.zip libyaml/examples/* +RUN zip $SRC/libyaml_seed_corpus.zip libyaml/examples/* WORKDIR libyaml -COPY build.sh libyaml_fuzzer.cc libyaml_fuzzer.options yaml.dict $SRC/ +COPY build.sh *.h *_fuzzer.c libyaml_fuzzer.options yaml.dict $SRC/ diff --git a/projects/libyaml/build.sh b/projects/libyaml/build.sh index f78b99bab..1eb31302f 100755 --- a/projects/libyaml/build.sh +++ b/projects/libyaml/build.sh @@ -18,9 +18,22 @@ ./configure make "-j$(nproc)" -$CXX $CXXFLAGS -std=c++11 -Iinclude \ - $SRC/libyaml_fuzzer.cc -o $OUT/libyaml_fuzzer \ - $LIB_FUZZING_ENGINE src/.libs/libyaml.a +for fuzzer in $SRC/*_fuzzer.c; do + fuzzer_basename=$(basename -s .c $fuzzer) -cp $SRC/libyaml_fuzzer_seed_corpus.zip $OUT/ -cp $SRC/*.dict $SRC/*.options $OUT/ + $CC $CFLAGS \ + -I $SRC -Iinclude \ + -c $fuzzer -o $fuzzer_basename.o + + $CXX $CXXFLAGS \ + -std=c++11 \ + $fuzzer_basename.o \ + -o $OUT/$fuzzer_basename \ + $LIB_FUZZING_ENGINE \ + src/.libs/libyaml.a + + cp $SRC/libyaml_seed_corpus.zip "${OUT}/${fuzzer_basename}_seed_corpus.zip" + cp $SRC/libyaml_fuzzer.options "${OUT}/${fuzzer_basename}.options" +done + +cp $SRC/yaml.dict $OUT/ diff --git a/projects/libyaml/libyaml_deconstructor_alt_fuzzer.c b/projects/libyaml/libyaml_deconstructor_alt_fuzzer.c new file mode 100644 index 000000000..b8ac2fe50 --- /dev/null +++ b/projects/libyaml/libyaml_deconstructor_alt_fuzzer.c @@ -0,0 +1,833 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yaml.h" +#include "yaml_write_handler.h" +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef NDEBUG +#undef NDEBUG +#endif + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < 2) + return 0; + + bool done = false; + bool is_canonical = data[0] & 1; + bool is_unicode = data[1] & 1; + data += 2; + size -= 2; + + yaml_parser_t parser; + yaml_emitter_t emitter; + yaml_event_t input_event; + yaml_document_t output_document; + + int root; + + /* Initialize the parser and emitter objects. */ + + if (!yaml_parser_initialize(&parser)) { + return 1; + } + + if (!yaml_emitter_initialize(&emitter)) { + yaml_parser_delete(&parser); + return 1; + } + + /* Set the parser parameters. */ + + yaml_parser_set_input_string(&parser, data, size); + + /* Set the emitter parameters. */ + yaml_output_buffer_t out = {/*buf=*/NULL, /*size=*/0}; + yaml_emitter_set_output(&emitter, yaml_write_handler, &out); + + yaml_emitter_set_canonical(&emitter, is_canonical); + yaml_emitter_set_unicode(&emitter, is_unicode); + + /* Create and emit the STREAM-START event. */ + + if (!yaml_emitter_open(&emitter)) + goto error; + + /* Create a output_document object. */ + + if (!yaml_document_initialize(&output_document, NULL, NULL, NULL, 0, 0)) + goto error; + + /* Create the root sequence. */ + + root = yaml_document_add_sequence(&output_document, NULL, + YAML_BLOCK_SEQUENCE_STYLE); + if (!root) + goto error; + + /* Loop through the input events. */ + + while (!done) { + int properties, key, value, map, seq; + + /* Get the next event. */ + + if (!yaml_parser_parse(&parser, &input_event)) + goto error; + + /* Check if this is the stream end. */ + + done = (input_event.type == YAML_STREAM_END_EVENT); + + /* Create a mapping node and attach it to the root sequence. */ + + properties = yaml_document_add_mapping(&output_document, NULL, + YAML_BLOCK_MAPPING_STYLE); + if (!properties) + goto error; + if (!yaml_document_append_sequence_item(&output_document, root, properties)) + goto error; + + /* Analyze the event. */ + + switch (input_event.type) { + case YAML_STREAM_START_EVENT: + + /* Add 'type': 'STREAM-START'. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"type", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"STREAM-START", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + /* Add 'encoding': <encoding>. */ + + if (input_event.data.stream_start.encoding) { + yaml_encoding_t encoding = input_event.data.stream_start.encoding; + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"encoding", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, NULL, + (encoding == YAML_UTF8_ENCODING + ? (yaml_char_t *)"utf-8" + : encoding == YAML_UTF16LE_ENCODING + ? (yaml_char_t *)"utf-16-le" + : encoding == YAML_UTF16BE_ENCODING + ? (yaml_char_t *)"utf-16-be" + : (yaml_char_t *)"unknown"), + -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, value)) + goto error; + } + + break; + + case YAML_STREAM_END_EVENT: + + /* Add 'type': 'STREAM-END'. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"type", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"STREAM-END", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + break; + + case YAML_DOCUMENT_START_EVENT: + + /* Add 'type': 'DOCUMENT-START'. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"type", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"DOCUMENT-START", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + /* Display the output_document version numbers. */ + + if (input_event.data.document_start.version_directive) { + yaml_version_directive_t *version = + input_event.data.document_start.version_directive; + char number[64]; + + /* Add 'version': {}. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"version", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + map = yaml_document_add_mapping(&output_document, NULL, + YAML_FLOW_MAPPING_STYLE); + if (!map) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, map)) + goto error; + + /* Add 'major': <number>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"major", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + sprintf(number, "%d", version->major); + value = yaml_document_add_scalar( + &output_document, (yaml_char_t *)YAML_INT_TAG, + (yaml_char_t *)number, -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, map, key, + value)) + goto error; + + /* Add 'minor': <number>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"minor", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + sprintf(number, "%d", version->minor); + value = yaml_document_add_scalar( + &output_document, (yaml_char_t *)YAML_INT_TAG, + (yaml_char_t *)number, -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, map, key, + value)) + goto error; + } + + /* Display the output_document tag directives. */ + + if (input_event.data.document_start.tag_directives.start != + input_event.data.document_start.tag_directives.end) { + yaml_tag_directive_t *tag; + + /* Add 'tags': []. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"tags", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + seq = yaml_document_add_sequence(&output_document, NULL, + YAML_BLOCK_SEQUENCE_STYLE); + if (!seq) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, seq)) + goto error; + + for (tag = input_event.data.document_start.tag_directives.start; + tag != input_event.data.document_start.tag_directives.end; tag++) { + /* Add {}. */ + + map = yaml_document_add_mapping(&output_document, NULL, + YAML_FLOW_MAPPING_STYLE); + if (!map) + goto error; + if (!yaml_document_append_sequence_item(&output_document, seq, map)) + goto error; + + /* Add 'handle': <handle>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"handle", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, tag->handle, + -1, YAML_DOUBLE_QUOTED_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, map, key, + value)) + goto error; + + /* Add 'prefix': <prefix>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"prefix", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, tag->prefix, + -1, YAML_DOUBLE_QUOTED_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, map, key, + value)) + goto error; + } + } + + /* Add 'implicit': <flag>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"implicit", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, (yaml_char_t *)YAML_BOOL_TAG, + (input_event.data.document_start.implicit ? (yaml_char_t *)"true" + : (yaml_char_t *)"false"), + -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + break; + + case YAML_DOCUMENT_END_EVENT: + + /* Add 'type': 'DOCUMENT-END'. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"type", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"DOCUMENT-END", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + /* Add 'implicit': <flag>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"implicit", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, (yaml_char_t *)YAML_BOOL_TAG, + (input_event.data.document_end.implicit ? (yaml_char_t *)"true" + : (yaml_char_t *)"false"), + -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + break; + + case YAML_ALIAS_EVENT: + + /* Add 'type': 'ALIAS'. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"type", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"ALIAS", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + /* Add 'anchor': <anchor>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"anchor", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + input_event.data.alias.anchor, -1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + break; + + case YAML_SCALAR_EVENT: + + /* Add 'type': 'SCALAR'. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"type", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"SCALAR", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + /* Add 'anchor': <anchor>. */ + + if (input_event.data.scalar.anchor) { + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"anchor", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + input_event.data.scalar.anchor, -1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, value)) + goto error; + } + + /* Add 'tag': <tag>. */ + + if (input_event.data.scalar.tag) { + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"tag", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + input_event.data.scalar.tag, -1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, value)) + goto error; + } + + /* Add 'value': <value>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"value", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, NULL, input_event.data.scalar.value, + input_event.data.scalar.length, YAML_DOUBLE_QUOTED_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + /* Display if the scalar tag is implicit. */ + + /* Add 'implicit': {} */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"version", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + map = yaml_document_add_mapping(&output_document, NULL, + YAML_FLOW_MAPPING_STYLE); + if (!map) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + map)) + goto error; + + /* Add 'plain': <flag>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"plain", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, (yaml_char_t *)YAML_BOOL_TAG, + (input_event.data.scalar.plain_implicit ? (yaml_char_t *)"true" + : (yaml_char_t *)"false"), + -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, map, key, value)) + goto error; + + /* Add 'quoted': <flag>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"quoted", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, (yaml_char_t *)YAML_BOOL_TAG, + (input_event.data.scalar.quoted_implicit ? (yaml_char_t *)"true" + : (yaml_char_t *)"false"), + -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, map, key, value)) + goto error; + + /* Display the style information. */ + + if (input_event.data.scalar.style) { + yaml_scalar_style_t style = input_event.data.scalar.style; + + /* Add 'style': <style>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"style", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, NULL, + (yaml_char_t + *)(style == YAML_PLAIN_SCALAR_STYLE + ? "plain" + : style == YAML_SINGLE_QUOTED_SCALAR_STYLE + ? "single-quoted" + : style == YAML_DOUBLE_QUOTED_SCALAR_STYLE + ? "double-quoted" + : style == YAML_LITERAL_SCALAR_STYLE + ? "literal" + : style == YAML_FOLDED_SCALAR_STYLE + ? "folded" + : "unknown"), + -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, value)) + goto error; + } + + break; + + case YAML_SEQUENCE_START_EVENT: + + /* Add 'type': 'SEQUENCE-START'. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"type", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"SEQUENCE-START", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + /* Add 'anchor': <anchor>. */ + + if (input_event.data.sequence_start.anchor) { + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"anchor", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + input_event.data.sequence_start.anchor, + -1, YAML_DOUBLE_QUOTED_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, value)) + goto error; + } + + /* Add 'tag': <tag>. */ + + if (input_event.data.sequence_start.tag) { + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"tag", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + input_event.data.sequence_start.tag, + -1, YAML_DOUBLE_QUOTED_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, value)) + goto error; + } + + /* Add 'implicit': <flag>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"implicit", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, (yaml_char_t *)YAML_BOOL_TAG, + (input_event.data.sequence_start.implicit ? (yaml_char_t *)"true" + : (yaml_char_t *)"false"), + -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + /* Display the style information. */ + + if (input_event.data.sequence_start.style) { + yaml_sequence_style_t style = input_event.data.sequence_start.style; + + /* Add 'style': <style>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"style", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, NULL, + (yaml_char_t *)(style == YAML_BLOCK_SEQUENCE_STYLE + ? "block" + : style == YAML_FLOW_SEQUENCE_STYLE + ? "flow" + : "unknown"), + -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, value)) + goto error; + } + + break; + + case YAML_SEQUENCE_END_EVENT: + + /* Add 'type': 'SEQUENCE-END'. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"type", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"SEQUENCE-END", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + break; + + case YAML_MAPPING_START_EVENT: + + /* Add 'type': 'MAPPING-START'. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"type", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"MAPPING-START", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + /* Add 'anchor': <anchor>. */ + + if (input_event.data.mapping_start.anchor) { + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"anchor", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + input_event.data.mapping_start.anchor, + -1, YAML_DOUBLE_QUOTED_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, value)) + goto error; + } + + /* Add 'tag': <tag>. */ + + if (input_event.data.mapping_start.tag) { + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"tag", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + input_event.data.mapping_start.tag, -1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, value)) + goto error; + } + + /* Add 'implicit': <flag>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"implicit", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, (yaml_char_t *)YAML_BOOL_TAG, + (yaml_char_t *)(input_event.data.mapping_start.implicit ? "true" + : "false"), + -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + /* Display the style information. */ + + if (input_event.data.sequence_start.style) { + yaml_sequence_style_t style = input_event.data.sequence_start.style; + + /* Add 'style': <style>. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"style", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar( + &output_document, NULL, + (yaml_char_t *)(style == YAML_BLOCK_MAPPING_STYLE + ? "block" + : style == YAML_FLOW_MAPPING_STYLE ? "flow" + : "unknown"), + -1, YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, + key, value)) + goto error; + } + + break; + + case YAML_MAPPING_END_EVENT: + + /* Add 'type': 'MAPPING-END'. */ + + key = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"type", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!key) + goto error; + value = yaml_document_add_scalar(&output_document, NULL, + (yaml_char_t *)"MAPPING-END", -1, + YAML_PLAIN_SCALAR_STYLE); + if (!value) + goto error; + if (!yaml_document_append_mapping_pair(&output_document, properties, key, + value)) + goto error; + + break; + + default: + /* It couldn't really happen. */ + break; + } + + /* Delete the event object. */ + + yaml_event_delete(&input_event); + } + + if (!yaml_emitter_dump(&emitter, &output_document)) + goto error; + + yaml_emitter_close(&emitter); + +error: + + free(out.buf); + + yaml_event_delete(&input_event); + yaml_document_delete(&output_document); + yaml_parser_delete(&parser); + yaml_emitter_delete(&emitter); + + return 0; +} diff --git a/projects/libyaml/libyaml_deconstructor_fuzzer.c b/projects/libyaml/libyaml_deconstructor_fuzzer.c new file mode 100644 index 000000000..2f1079b80 --- /dev/null +++ b/projects/libyaml/libyaml_deconstructor_fuzzer.c @@ -0,0 +1,994 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yaml.h" +#include "yaml_write_handler.h" +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef NDEBUG +#undef NDEBUG +#endif + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < 2) + return 0; + + bool done = false; + bool is_canonical = data[0] & 1; + bool is_unicode = data[1] & 1; + data += 2; + size -= 2; + + yaml_parser_t parser; + yaml_emitter_t emitter; + yaml_event_t input_event; + yaml_event_t output_event; + + /* Initialize the parser and emitter objects. */ + + if (!yaml_parser_initialize(&parser)) { + return 1; + } + + if (!yaml_emitter_initialize(&emitter)) { + yaml_parser_delete(&parser); + return 1; + } + + /* Set the parser parameters. */ + + yaml_parser_set_input_string(&parser, data, size); + + /* Set the emitter parameters. */ + yaml_output_buffer_t out = {/*buf=*/NULL, /*size=*/0}; + yaml_emitter_set_output(&emitter, yaml_write_handler, &out); + + yaml_emitter_set_canonical(&emitter, is_canonical); + yaml_emitter_set_unicode(&emitter, is_unicode); + + /* Create and emit the STREAM-START event. */ + + if (!yaml_stream_start_event_initialize(&output_event, YAML_UTF8_ENCODING)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Create and emit the DOCUMENT-START event. */ + + if (!yaml_document_start_event_initialize(&output_event, NULL, NULL, NULL, 0)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Create and emit the SEQUENCE-START event. */ + + if (!yaml_sequence_start_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:seq", 1, + YAML_BLOCK_SEQUENCE_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Loop through the input events. */ + + while (!done) { + /* Get the next event. */ + + if (!yaml_parser_parse(&parser, &input_event)) + goto error; + + /* Check if this is the stream end. */ + + done = (input_event.type == YAML_STREAM_END_EVENT); + + /* Create and emit a MAPPING-START event. */ + + if (!yaml_mapping_start_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:map", 1, + YAML_BLOCK_MAPPING_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Analyze the event. */ + + switch (input_event.type) { + case YAML_STREAM_START_EVENT: + + /* Write 'type'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"type", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'STREAM-START'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"STREAM-START", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Display encoding information. */ + + if (input_event.data.stream_start.encoding) { + yaml_encoding_t encoding = input_event.data.stream_start.encoding; + + /* Write 'encoding'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"encoding", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the stream encoding. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)(encoding == YAML_UTF8_ENCODING + ? "utf-8" + : encoding == YAML_UTF16LE_ENCODING + ? "utf-16-le" + : encoding == YAML_UTF16BE_ENCODING + ? "utf-16-be" + : "unknown"), + -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + break; + + case YAML_STREAM_END_EVENT: + + /* Write 'type'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"type", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'STREAM-END'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"STREAM-END", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + break; + + case YAML_DOCUMENT_START_EVENT: + + /* Write 'type'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"type", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'DOCUMENT-START'. */ + + if (!yaml_scalar_event_initialize(&output_event, NULL, + (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"DOCUMENT-START", -1, 1, + 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Display the document version numbers. */ + + if (input_event.data.document_start.version_directive) { + yaml_version_directive_t *version = + input_event.data.document_start.version_directive; + char number[64]; + + /* Write 'version'. */ + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"version", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write '{'. */ + + if (!yaml_mapping_start_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:map", 1, + YAML_FLOW_MAPPING_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'major'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"major", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write a number. */ + + sprintf(number, "%d", version->major); + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:int", + (yaml_char_t *)number, -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'minor'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"minor", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write a number. */ + + sprintf(number, "%d", version->minor); + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:int", + (yaml_char_t *)number, -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write '}'. */ + + if (!yaml_mapping_end_event_initialize(&output_event)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + /* Display the document tag directives. */ + + if (input_event.data.document_start.tag_directives.start != + input_event.data.document_start.tag_directives.end) { + yaml_tag_directive_t *tag; + + /* Write 'tags'. */ + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"tags", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Start a block sequence. */ + + if (!yaml_sequence_start_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:seq", 1, + YAML_BLOCK_SEQUENCE_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + for (tag = input_event.data.document_start.tag_directives.start; + tag != input_event.data.document_start.tag_directives.end; tag++) { + /* Write '{'. */ + + if (!yaml_mapping_start_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:map", + 1, YAML_FLOW_MAPPING_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'handle'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"handle", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the tag directive handle. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)tag->handle, -1, 0, 1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'prefix'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"prefix", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the tag directive prefix. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)tag->prefix, -1, 0, 1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write '}'. */ + + if (!yaml_mapping_end_event_initialize(&output_event)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + /* End a block sequence. */ + + if (!yaml_sequence_end_event_initialize(&output_event)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + /* Write 'implicit'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"implicit", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write if the document is implicit. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:bool", + (yaml_char_t *)(input_event.data.document_start.implicit + ? "true" + : "false"), + -1, 1, 0, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + break; + + case YAML_DOCUMENT_END_EVENT: + + /* Write 'type'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"type", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'DOCUMENT-END'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"DOCUMENT-END", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'implicit'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"implicit", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write if the document is implicit. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:bool", + (yaml_char_t *)(input_event.data.document_end.implicit ? "true" + : "false"), + -1, 1, 0, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + break; + + case YAML_ALIAS_EVENT: + + /* Write 'type'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"type", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'ALIAS'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"ALIAS", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'anchor'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"anchor", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the alias anchor. */ + + if (!yaml_scalar_event_initialize(&output_event, NULL, + (yaml_char_t *)"tag:yaml.org,2002:str", + input_event.data.alias.anchor, -1, 0, 1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + break; + + case YAML_SCALAR_EVENT: + + /* Write 'type'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"type", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'SCALAR'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"SCALAR", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Display the scalar anchor. */ + + if (input_event.data.scalar.anchor) { + /* Write 'anchor'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"anchor", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the scalar anchor. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + input_event.data.scalar.anchor, -1, 0, 1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + /* Display the scalar tag. */ + + if (input_event.data.scalar.tag) { + /* Write 'tag'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"tag", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the scalar tag. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + input_event.data.scalar.tag, -1, 0, 1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + /* Display the scalar value. */ + + /* Write 'value'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"value", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the scalar value. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + input_event.data.scalar.value, input_event.data.scalar.length, 0, + 1, YAML_DOUBLE_QUOTED_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Display if the scalar tag is implicit. */ + + /* Write 'implicit'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"implicit", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write '{'. */ + + if (!yaml_mapping_start_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:map", 1, + YAML_FLOW_MAPPING_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'plain'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"plain", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write if the scalar is implicit in the plain style. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:bool", + (yaml_char_t *)(input_event.data.scalar.plain_implicit ? "true" + : "false"), + -1, 1, 0, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'quoted'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"non-plain", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write if the scalar is implicit in a non-plain style. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:bool", + (yaml_char_t *)(input_event.data.scalar.quoted_implicit + ? "true" + : "false"), + -1, 1, 0, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write '}'. */ + + if (!yaml_mapping_end_event_initialize(&output_event)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Display the style information. */ + + if (input_event.data.scalar.style) { + yaml_scalar_style_t style = input_event.data.scalar.style; + + /* Write 'style'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"style", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the scalar style. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t + *)(style == YAML_PLAIN_SCALAR_STYLE + ? "plain" + : style == YAML_SINGLE_QUOTED_SCALAR_STYLE + ? "single-quoted" + : style == YAML_DOUBLE_QUOTED_SCALAR_STYLE + ? "double-quoted" + : style == YAML_LITERAL_SCALAR_STYLE + ? "literal" + : style == + YAML_FOLDED_SCALAR_STYLE + ? "folded" + : "unknown"), + -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + break; + + case YAML_SEQUENCE_START_EVENT: + + /* Write 'type'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"type", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'SEQUENCE-START'. */ + + if (!yaml_scalar_event_initialize(&output_event, NULL, + (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"SEQUENCE-START", -1, 1, + 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Display the sequence anchor. */ + + if (input_event.data.sequence_start.anchor) { + /* Write 'anchor'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"anchor", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the sequence anchor. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + input_event.data.sequence_start.anchor, -1, 0, 1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + /* Display the sequence tag. */ + + if (input_event.data.sequence_start.tag) { + /* Write 'tag'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"tag", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the sequence tag. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + input_event.data.sequence_start.tag, -1, 0, 1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + /* Write 'implicit'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"implicit", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write if the sequence tag is implicit. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:bool", + (yaml_char_t *)(input_event.data.sequence_start.implicit + ? "true" + : "false"), + -1, 1, 0, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Display the style information. */ + + if (input_event.data.sequence_start.style) { + yaml_sequence_style_t style = input_event.data.sequence_start.style; + + /* Write 'style'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"style", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the scalar style. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)(style == YAML_BLOCK_SEQUENCE_STYLE + ? "block" + : style == YAML_FLOW_SEQUENCE_STYLE + ? "flow" + : "unknown"), + -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + break; + + case YAML_SEQUENCE_END_EVENT: + + /* Write 'type'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"type", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'SEQUENCE-END'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"SEQUENCE-END", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + break; + + case YAML_MAPPING_START_EVENT: + + /* Write 'type'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"type", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'MAPPING-START'. */ + + if (!yaml_scalar_event_initialize(&output_event, NULL, + (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"MAPPING-START", -1, 1, + 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Display the mapping anchor. */ + + if (input_event.data.mapping_start.anchor) { + /* Write 'anchor'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"anchor", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the mapping anchor. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + input_event.data.mapping_start.anchor, -1, 0, 1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + /* Display the mapping tag. */ + + if (input_event.data.mapping_start.tag) { + /* Write 'tag'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"tag", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the mapping tag. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + input_event.data.mapping_start.tag, -1, 0, 1, + YAML_DOUBLE_QUOTED_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + /* Write 'implicit'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"implicit", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write if the mapping tag is implicit. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:bool", + (yaml_char_t *)(input_event.data.mapping_start.implicit + ? "true" + : "false"), + -1, 1, 0, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Display the style information. */ + + if (input_event.data.mapping_start.style) { + yaml_mapping_style_t style = input_event.data.mapping_start.style; + + /* Write 'style'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"style", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write the scalar style. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)(style == YAML_BLOCK_MAPPING_STYLE + ? "block" + : style == YAML_FLOW_MAPPING_STYLE + ? "flow" + : "unknown"), + -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + break; + + case YAML_MAPPING_END_EVENT: + + /* Write 'type'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"type", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Write 'MAPPING-END'. */ + + if (!yaml_scalar_event_initialize( + &output_event, NULL, (yaml_char_t *)"tag:yaml.org,2002:str", + (yaml_char_t *)"MAPPING-END", -1, 1, 1, YAML_PLAIN_SCALAR_STYLE)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + break; + + default: + /* It couldn't really happen. */ + break; + } + + /* Delete the event object. */ + + yaml_event_delete(&input_event); + + /* Create and emit a MAPPING-END event. */ + + if (!yaml_mapping_end_event_initialize(&output_event)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + } + + /* Create and emit the SEQUENCE-END event. */ + + if (!yaml_sequence_end_event_initialize(&output_event)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Create and emit the DOCUMENT-END event. */ + + if (!yaml_document_end_event_initialize(&output_event, 0)) + goto error; + if (!yaml_emitter_emit(&emitter, &output_event)) + goto error; + + /* Create and emit the STREAM-END event. */ + + if (!yaml_stream_end_event_initialize(&output_event)) + goto error; + yaml_emitter_emit(&emitter, &output_event); + +error: + + free(out.buf); + + yaml_event_delete(&input_event); + yaml_parser_delete(&parser); + yaml_emitter_delete(&emitter); + + return 0; +} diff --git a/projects/libyaml/libyaml_dumper_fuzzer.c b/projects/libyaml/libyaml_dumper_fuzzer.c new file mode 100644 index 000000000..5ad8a4e08 --- /dev/null +++ b/projects/libyaml/libyaml_dumper_fuzzer.c @@ -0,0 +1,311 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yaml.h" +#include "yaml_write_handler.h" +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef NDEBUG +#undef NDEBUG +#endif + +#define MAX_DOCUMENTS 16 + +bool nodes_equal(yaml_document_t *document1, int index1, + yaml_document_t *document2, int index2, int level) { + const bool equal = true; + + if (level++ > 1000) + return !equal; + yaml_node_t *node1 = yaml_document_get_node(document1, index1); + + if (!node1) + return !equal; + + yaml_node_t *node2 = yaml_document_get_node(document2, index2); + + if (!node2) + return !equal; + + if (node1->type != node2->type) + return !equal; + + if (strcmp((char *)node1->tag, (char *)node2->tag) != 0) + return !equal; + + switch (node1->type) { + case YAML_SCALAR_NODE: + if (node1->data.scalar.length != node2->data.scalar.length) + return !equal; + if (strncmp((char *)node1->data.scalar.value, + (char *)node2->data.scalar.value, + node1->data.scalar.length) != 0) + return !equal; + break; + case YAML_SEQUENCE_NODE: + if ((node1->data.sequence.items.top - node1->data.sequence.items.start) != + (node2->data.sequence.items.top - node2->data.sequence.items.start)) + return !equal; + for (int k = 0; k < (node1->data.sequence.items.top - + node1->data.sequence.items.start); + k++) { + if (!nodes_equal(document1, node1->data.sequence.items.start[k], + document2, node2->data.sequence.items.start[k], level)) + return !equal; + } + break; + case YAML_MAPPING_NODE: + if ((node1->data.mapping.pairs.top - node1->data.mapping.pairs.start) != + (node2->data.mapping.pairs.top - node2->data.mapping.pairs.start)) + return !equal; + for (int k = 0; + k < (node1->data.mapping.pairs.top - node1->data.mapping.pairs.start); + k++) { + if (!nodes_equal(document1, node1->data.mapping.pairs.start[k].key, + document2, node2->data.mapping.pairs.start[k].key, + level)) + return !equal; + if (!nodes_equal(document1, node1->data.mapping.pairs.start[k].value, + document2, node2->data.mapping.pairs.start[k].value, + level)) + return !equal; + } + break; + default: + return !equal; + } + return equal; +} + +bool documents_equal(yaml_document_t *document1, yaml_document_t *document2) { + + const bool equal = true; + + if ((document1->version_directive && !document2->version_directive) || + (!document1->version_directive && document2->version_directive) || + (document1->version_directive && document2->version_directive && + (document1->version_directive->major != + document2->version_directive->major || + document1->version_directive->minor != + document2->version_directive->minor))) + return !equal; + + if ((document1->tag_directives.end - document1->tag_directives.start) != + (document2->tag_directives.end - document2->tag_directives.start)) + return !equal; + for (int k = 0; + k < (document1->tag_directives.end - document1->tag_directives.start); + k++) { + if ((strcmp((char *)document1->tag_directives.start[k].handle, + (char *)document2->tag_directives.start[k].handle) != 0) || + (strcmp((char *)document1->tag_directives.start[k].prefix, + (char *)document2->tag_directives.start[k].prefix) != 0)) + return !equal; + } + + if ((document1->nodes.top - document1->nodes.start) != + (document2->nodes.top - document2->nodes.start)) + return !equal; + + if (document1->nodes.top != document1->nodes.start) { + if (!nodes_equal(document1, 1, document2, 1, 0)) + return !equal; + } + + return equal; +} + +bool copy_document(yaml_document_t *document_to, + yaml_document_t *document_from) { + bool error = true; + + yaml_node_t *node; + yaml_node_item_t *item; + yaml_node_pair_t *pair; + + if (!yaml_document_initialize(document_to, document_from->version_directive, + document_from->tag_directives.start, + document_from->tag_directives.end, + document_from->start_implicit, + document_from->end_implicit)) + return !error; + + for (node = document_from->nodes.start; node < document_from->nodes.top; + node++) { + switch (node->type) { + case YAML_SCALAR_NODE: + if (!yaml_document_add_scalar( + document_to, node->tag, node->data.scalar.value, + node->data.scalar.length, node->data.scalar.style)) + goto out; + break; + case YAML_SEQUENCE_NODE: + if (!yaml_document_add_sequence(document_to, node->tag, + node->data.sequence.style)) + goto out; + break; + case YAML_MAPPING_NODE: + if (!yaml_document_add_mapping(document_to, node->tag, + node->data.mapping.style)) + goto out; + break; + default: + goto out; + } + } + + for (node = document_from->nodes.start; node < document_from->nodes.top; + node++) { + switch (node->type) { + case YAML_SEQUENCE_NODE: + for (item = node->data.sequence.items.start; + item < node->data.sequence.items.top; item++) { + if (!yaml_document_append_sequence_item( + document_to, node - document_from->nodes.start + 1, *item)) + goto out; + } + break; + case YAML_MAPPING_NODE: + for (pair = node->data.mapping.pairs.start; + pair < node->data.mapping.pairs.top; pair++) { + if (!yaml_document_append_mapping_pair( + document_to, node - document_from->nodes.start + 1, pair->key, + pair->value)) + goto out; + } + break; + default: + break; + } + } + return error; + +out: + yaml_document_delete(document_to); + return !error; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < 2) + return 0; + + yaml_parser_t parser; + yaml_emitter_t emitter; + + yaml_document_t document; + yaml_document_t documents[MAX_DOCUMENTS]; + size_t document_number = 0; + int count = 0; + bool done = false; + bool equal = false; + bool is_canonical = data[0] & 1; + bool is_unicode = data[1] & 1; + data += 2; + size -= 2; + + if (!yaml_parser_initialize(&parser)) + return 0; + + yaml_parser_set_input_string(&parser, data, size); + if (!yaml_emitter_initialize(&emitter)) + return 0; + + yaml_emitter_set_canonical(&emitter, is_canonical); + yaml_emitter_set_unicode(&emitter, is_unicode); + + yaml_output_buffer_t out = {/*buf=*/NULL, /*size=*/0}; + yaml_emitter_set_output(&emitter, yaml_write_handler, &out); + yaml_emitter_open(&emitter); + + while (!done) { + if (!yaml_parser_load(&parser, &document)) { + equal = 1; + break; + } + + done = (!yaml_document_get_root_node(&document)); + if (!done) { + if (document_number >= MAX_DOCUMENTS) { + yaml_document_delete(&document); + equal = true; + break; + } + + if (!copy_document(&documents[document_number++], &document)) { + yaml_document_delete(&document); + equal = true; + break; + } + if (!(yaml_emitter_dump(&emitter, &document) || + (yaml_emitter_flush(&emitter) && 0))) { + equal = true; + break; + } + + count++; + } else { + yaml_document_delete(&document); + } + } + + yaml_parser_delete(&parser); + yaml_emitter_close(&emitter); + yaml_emitter_delete(&emitter); + + if (!equal) { + count = 0; + done = false; + if (!yaml_parser_initialize(&parser)) + goto error; + + if (!out.buf) { + yaml_parser_delete(&parser); + goto error; + } + + yaml_parser_set_input_string(&parser, out.buf, out.size); + + while (!done) { + if (!yaml_parser_load(&parser, &document)) { + yaml_parser_delete(&parser); + goto error; + } + + done = (!yaml_document_get_root_node(&document)); + if (!done) { + if (!documents_equal(documents + count, &document)) { + yaml_parser_delete(&parser); + goto error; + } + count++; + } + yaml_document_delete(&document); + } + yaml_parser_delete(&parser); + } + + for (int k = 0; k < document_number; k++) { + yaml_document_delete(documents + k); + } + +error: + + free(out.buf); + return 0; +} diff --git a/projects/libyaml/libyaml_emitter_fuzzer.c b/projects/libyaml/libyaml_emitter_fuzzer.c new file mode 100644 index 000000000..d44bd609d --- /dev/null +++ b/projects/libyaml/libyaml_emitter_fuzzer.c @@ -0,0 +1,298 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yaml.h" +#include "yaml_write_handler.h" +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef NDEBUG +#undef NDEBUG +#endif + +#define MAX_EVENTS 1024 + +bool events_equal(yaml_event_t *event1, yaml_event_t *event2) { + + const bool equal = true; + + if (event1->type != event2->type) + return equal; + + switch (event1->type) { + case YAML_STREAM_START_EVENT: + return !equal; + + case YAML_DOCUMENT_START_EVENT: + if ((event1->data.document_start.version_directive && + !event2->data.document_start.version_directive) || + (!event1->data.document_start.version_directive && + event2->data.document_start.version_directive) || + (event1->data.document_start.version_directive && + event2->data.document_start.version_directive && + (event1->data.document_start.version_directive->major != + event2->data.document_start.version_directive->major || + event1->data.document_start.version_directive->minor != + event2->data.document_start.version_directive->minor))) + return equal; + if ((event1->data.document_start.tag_directives.end - + event1->data.document_start.tag_directives.start) != + (event2->data.document_start.tag_directives.end - + event2->data.document_start.tag_directives.start)) + return equal; + for (int k = 0; k < (event1->data.document_start.tag_directives.end - + event1->data.document_start.tag_directives.start); + k++) { + if ((strcmp((char *)event1->data.document_start.tag_directives.start[k] + .handle, + (char *)event2->data.document_start.tag_directives.start[k] + .handle) != 0) || + (strcmp((char *)event1->data.document_start.tag_directives.start[k] + .prefix, + (char *)event2->data.document_start.tag_directives.start[k] + .prefix) != 0)) + return equal; + } + return !equal; + + case YAML_DOCUMENT_END_EVENT: + return !equal; + + case YAML_ALIAS_EVENT: + return (strcmp((char *)event1->data.alias.anchor, + (char *)event2->data.alias.anchor) == 0); + + case YAML_SCALAR_EVENT: + if ((event1->data.scalar.anchor && !event2->data.scalar.anchor) || + (!event1->data.scalar.anchor && event2->data.scalar.anchor) || + (event1->data.scalar.anchor && event2->data.scalar.anchor && + strcmp((char *)event1->data.scalar.anchor, + (char *)event2->data.scalar.anchor) != 0)) + return equal; + if ((event1->data.scalar.tag && !event2->data.scalar.tag && + strcmp((char *)event1->data.scalar.tag, "!") != 0) || + (!event1->data.scalar.tag && event2->data.scalar.tag && + strcmp((char *)event2->data.scalar.tag, "!") != 0) || + (event1->data.scalar.tag && event2->data.scalar.tag && + strcmp((char *)event1->data.scalar.tag, + (char *)event2->data.scalar.tag) != 0)) + return equal; + if ((event1->data.scalar.length != event2->data.scalar.length) || + memcmp(event1->data.scalar.value, event2->data.scalar.value, + event1->data.scalar.length) != 0) + return equal; + if ((event1->data.scalar.plain_implicit != + event2->data.scalar.plain_implicit) || + (event1->data.scalar.quoted_implicit != + event2->data.scalar.quoted_implicit)) + return equal; + return !equal; + + case YAML_SEQUENCE_START_EVENT: + if ((event1->data.sequence_start.anchor && + !event2->data.sequence_start.anchor) || + (!event1->data.sequence_start.anchor && + event2->data.sequence_start.anchor) || + (event1->data.sequence_start.anchor && + event2->data.sequence_start.anchor && + strcmp((char *)event1->data.sequence_start.anchor, + (char *)event2->data.sequence_start.anchor) != 0)) + return equal; + if ((event1->data.sequence_start.tag && !event2->data.sequence_start.tag) || + (!event1->data.sequence_start.tag && event2->data.sequence_start.tag) || + (event1->data.sequence_start.tag && event2->data.sequence_start.tag && + strcmp((char *)event1->data.sequence_start.tag, + (char *)event2->data.sequence_start.tag) != 0)) + return equal; + if ((event1->data.sequence_start.implicit != + event2->data.sequence_start.implicit)) + return equal; + return !equal; + + case YAML_MAPPING_START_EVENT: + if ((event1->data.mapping_start.anchor && + !event2->data.mapping_start.anchor) || + (!event1->data.mapping_start.anchor && + event2->data.mapping_start.anchor) || + (event1->data.mapping_start.anchor && + event2->data.mapping_start.anchor && + strcmp((char *)event1->data.mapping_start.anchor, + (char *)event2->data.mapping_start.anchor) != 0)) + return equal; + if ((event1->data.mapping_start.tag && !event2->data.mapping_start.tag) || + (!event1->data.mapping_start.tag && event2->data.mapping_start.tag) || + (event1->data.mapping_start.tag && event2->data.mapping_start.tag && + strcmp((char *)event1->data.mapping_start.tag, + (char *)event2->data.mapping_start.tag) != 0)) + return equal; + if ((event1->data.mapping_start.implicit != + event2->data.mapping_start.implicit)) + return equal; + return !equal; + + default: + return !equal; + } +} + +bool copy_event(yaml_event_t *event_to, yaml_event_t *event_from) { + + switch (event_from->type) { + case YAML_STREAM_START_EVENT: + return yaml_stream_start_event_initialize( + event_to, event_from->data.stream_start.encoding); + + case YAML_STREAM_END_EVENT: + return yaml_stream_end_event_initialize(event_to); + + case YAML_DOCUMENT_START_EVENT: + return yaml_document_start_event_initialize( + event_to, event_from->data.document_start.version_directive, + event_from->data.document_start.tag_directives.start, + event_from->data.document_start.tag_directives.end, + event_from->data.document_start.implicit); + + case YAML_DOCUMENT_END_EVENT: + return yaml_document_end_event_initialize( + event_to, event_from->data.document_end.implicit); + + case YAML_ALIAS_EVENT: + return yaml_alias_event_initialize(event_to, event_from->data.alias.anchor); + + case YAML_SCALAR_EVENT: + return yaml_scalar_event_initialize( + event_to, event_from->data.scalar.anchor, event_from->data.scalar.tag, + event_from->data.scalar.value, event_from->data.scalar.length, + event_from->data.scalar.plain_implicit, + event_from->data.scalar.quoted_implicit, event_from->data.scalar.style); + + case YAML_SEQUENCE_START_EVENT: + return yaml_sequence_start_event_initialize( + event_to, event_from->data.sequence_start.anchor, + event_from->data.sequence_start.tag, + event_from->data.sequence_start.implicit, + event_from->data.sequence_start.style); + + case YAML_SEQUENCE_END_EVENT: + return yaml_sequence_end_event_initialize(event_to); + + case YAML_MAPPING_START_EVENT: + return yaml_mapping_start_event_initialize( + event_to, event_from->data.mapping_start.anchor, + event_from->data.mapping_start.tag, + event_from->data.mapping_start.implicit, + event_from->data.mapping_start.style); + + case YAML_MAPPING_END_EVENT: + return yaml_mapping_end_event_initialize(event_to); + } + + return false; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < 2) + return 0; + + yaml_parser_t parser; + yaml_emitter_t emitter; + yaml_event_t event; + yaml_event_t events[MAX_EVENTS]; + size_t event_number = 0; + bool done = false; + int count = 0; + bool is_canonical = data[0] & 1; + bool is_unicode = data[1] & 1; + data += 2; + size -= 2; + + if (!yaml_parser_initialize(&parser)) + return 0; + + yaml_parser_set_input_string(&parser, data, size); + if (!yaml_emitter_initialize(&emitter)) { + yaml_parser_delete(&parser); + return 0; + } + + yaml_emitter_set_canonical(&emitter, is_canonical); + yaml_emitter_set_unicode(&emitter, is_unicode); + + yaml_output_buffer_t out = {/*buf=*/NULL, /*size=*/0}; + yaml_emitter_set_output(&emitter, yaml_write_handler, &out); + + while (!done) { + if (!yaml_parser_parse(&parser, &event)) { + goto delete_parser; + } + + done = (event.type == YAML_STREAM_END_EVENT); + if (event_number >= MAX_EVENTS) { + yaml_event_delete(&event); + goto delete_parser; + } + + if (copy_event(&events[event_number++], &event)) { + yaml_event_delete(&event); + goto delete_parser; + } + + if (!yaml_emitter_emit(&emitter, &event)) { + goto delete_parser; + } + + } + + yaml_parser_delete(&parser); + + done = false; + if (!yaml_parser_initialize(&parser)) + goto error; + + yaml_parser_set_input_string(&parser, out.buf, out.size); + + while (!done) { + if (!yaml_parser_parse(&parser, &event)) + break; + + done = (event.type == YAML_STREAM_END_EVENT); + if (events_equal(events + count, &event)) { + yaml_event_delete(&event); + break; + } + + yaml_event_delete(&event); + count++; + } + +delete_parser: + + yaml_parser_delete(&parser); + +error: + + yaml_emitter_delete(&emitter); + + for (int k = 0; k < event_number; k++) { + yaml_event_delete(events + k); + } + + free(out.buf); + + return 0; +} diff --git a/projects/libyaml/libyaml_fuzzer.cc b/projects/libyaml/libyaml_fuzzer.cc deleted file mode 100644 index 57d50937f..000000000 --- a/projects/libyaml/libyaml_fuzzer.cc +++ /dev/null @@ -1,21 +0,0 @@ -#include <stdint.h> - -#include <yaml.h> - -extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - yaml_parser_t parser; - yaml_parser_initialize(&parser); - yaml_parser_set_input_string(&parser, data, size); - - int done = 0; - while (!done) { - yaml_event_t event; - if (!yaml_parser_parse(&parser, &event)) { - break; - } - done = (event.type == YAML_STREAM_END_EVENT); - yaml_event_delete(&event); - } - yaml_parser_delete(&parser); - return 0; -} diff --git a/projects/libyaml/libyaml_loader_fuzzer.c b/projects/libyaml/libyaml_loader_fuzzer.c new file mode 100644 index 000000000..6986feab9 --- /dev/null +++ b/projects/libyaml/libyaml_loader_fuzzer.c @@ -0,0 +1,51 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yaml.h" +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stdbool.h> + +#ifdef NDEBUG +#undef NDEBUG +#endif + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + yaml_parser_t parser; + yaml_document_t document; + bool done = false; + + if(!yaml_parser_initialize(&parser)) + return 0; + + yaml_parser_set_input_string(&parser, data, size); + + while (!done) + { + if (!yaml_parser_load(&parser, &document)) { + break; + } + + done = (!yaml_document_get_root_node(&document)); + + yaml_document_delete(&document); + } + + yaml_parser_delete(&parser); + + return 0; +} diff --git a/projects/libyaml/libyaml_parser_fuzzer.c b/projects/libyaml/libyaml_parser_fuzzer.c new file mode 100644 index 000000000..a0119bb38 --- /dev/null +++ b/projects/libyaml/libyaml_parser_fuzzer.c @@ -0,0 +1,49 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yaml.h" +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stdbool.h> + +#ifdef NDEBUG +#undef NDEBUG +#endif + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + yaml_parser_t parser; + yaml_event_t event; + bool done = false; + + if(!yaml_parser_initialize(&parser)) + return 0; + + yaml_parser_set_input_string(&parser, data, size); + + while (!done) + { + if (!yaml_parser_parse(&parser, &event)) break; + + done = (event.type == YAML_STREAM_END_EVENT); + + yaml_event_delete(&event); + } + + yaml_parser_delete(&parser); + + return 0; +} diff --git a/projects/libyaml/libyaml_reformatter_alt_fuzzer.c b/projects/libyaml/libyaml_reformatter_alt_fuzzer.c new file mode 100644 index 000000000..5ca6c2b41 --- /dev/null +++ b/projects/libyaml/libyaml_reformatter_alt_fuzzer.c @@ -0,0 +1,86 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yaml.h" +#include "yaml_write_handler.h" +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef NDEBUG +#undef NDEBUG +#endif + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < 2) + return 0; + + bool done = false; + bool is_canonical = data[0] & 1; + bool is_unicode = data[1] & 1; + data += 2; + size -= 2; + + yaml_parser_t parser; + yaml_emitter_t emitter; + yaml_document_t document; + + /* Initialize the parser and emitter objects. */ + + if (!yaml_parser_initialize(&parser)) + return 0; + + if (!yaml_emitter_initialize(&emitter)) + goto cleanup_parser; + + /* Set the parser parameters. */ + + yaml_parser_set_input_string(&parser, data, size); + + /* Set the emitter parameters. */ + yaml_output_buffer_t out = {/*buf=*/NULL, /*size=*/0}; + yaml_emitter_set_output(&emitter, yaml_write_handler, &out); + + yaml_emitter_set_canonical(&emitter, is_canonical); + yaml_emitter_set_unicode(&emitter, is_unicode); + + /* The main loop. */ + + while (!done) { + /* Get the next event. */ + + if (!yaml_parser_load(&parser, &document)) + break; + + /* Check if this is the stream end. */ + + done = (!yaml_document_get_root_node(&document)); + + /* Emit the event. */ + + if (!yaml_emitter_dump(&emitter, &document)) + break; + } + + free(out.buf); + yaml_emitter_delete(&emitter); + +cleanup_parser: + + yaml_parser_delete(&parser); + return 0; +} diff --git a/projects/libyaml/libyaml_reformatter_fuzzer.c b/projects/libyaml/libyaml_reformatter_fuzzer.c new file mode 100644 index 000000000..a43243f05 --- /dev/null +++ b/projects/libyaml/libyaml_reformatter_fuzzer.c @@ -0,0 +1,86 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yaml.h" +#include "yaml_write_handler.h" +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef NDEBUG +#undef NDEBUG +#endif + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + if (size < 2) + return 0; + + bool done = false; + bool is_canonical = data[0] & 1; + bool is_unicode = data[1] & 1; + data += 2; + size -= 2; + + yaml_parser_t parser; + yaml_emitter_t emitter; + yaml_event_t event; + + /* Initialize the parser and emitter objects. */ + + if (!yaml_parser_initialize(&parser)) + return 0; + + if (!yaml_emitter_initialize(&emitter)) + goto cleanup_parser; + + /* Set the parser parameters. */ + + yaml_parser_set_input_string(&parser, data, size); + + /* Set the emitter parameters. */ + yaml_output_buffer_t out = {/*buf=*/NULL, /*size=*/0}; + yaml_emitter_set_output(&emitter, yaml_write_handler, &out); + + yaml_emitter_set_canonical(&emitter, is_canonical); + yaml_emitter_set_unicode(&emitter, is_unicode); + + /* The main loop. */ + + while (!done) { + /* Get the next event. */ + + if (!yaml_parser_parse(&parser, &event)) + break; + + /* Check if this is the stream end. */ + + done = (event.type == YAML_STREAM_END_EVENT); + + /* Emit the event. */ + + if (!yaml_emitter_emit(&emitter, &event)) + break; + } + + free(out.buf); + yaml_emitter_delete(&emitter); + +cleanup_parser: + + yaml_parser_delete(&parser); + return 0; +} diff --git a/projects/libyaml/libyaml_scanner_fuzzer.c b/projects/libyaml/libyaml_scanner_fuzzer.c new file mode 100644 index 000000000..681f8b6df --- /dev/null +++ b/projects/libyaml/libyaml_scanner_fuzzer.c @@ -0,0 +1,51 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "yaml.h" +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <stdint.h> +#include <stdbool.h> + +#ifdef NDEBUG +#undef NDEBUG +#endif + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + yaml_parser_t parser; + yaml_token_t token; + bool done = false; + + if(!yaml_parser_initialize(&parser)) + return 0; + + yaml_parser_set_input_string(&parser, data, size); + + while (!done) + { + if (!yaml_parser_scan(&parser, &token)) { + break; + } + + done = (token.type == YAML_STREAM_END_TOKEN); + + yaml_token_delete(&token); + } + + yaml_parser_delete(&parser); + + return 0; +} diff --git a/projects/libyaml/yaml_write_handler.h b/projects/libyaml/yaml_write_handler.h new file mode 100644 index 000000000..cb5d26e8d --- /dev/null +++ b/projects/libyaml/yaml_write_handler.h @@ -0,0 +1,37 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef YAML_WRITE_HANDLER_H_ +#define YAML_WRITE_HANDLER_H_ + +typedef struct yaml_output_buffer { + unsigned char *buf; + size_t size; +} yaml_output_buffer_t; + +static int yaml_write_handler(void *data, unsigned char *buffer, size_t size) { + yaml_output_buffer_t *out = (yaml_output_buffer_t *)data; + + out->buf = (unsigned char *)realloc(out->buf, out->size + size); + if (!out->buf) { + out->size = 0; + return 1; + } + + memcpy(out->buf + out->size, buffer, size); + out->size += size; + return 0; +} + +#endif // YAML_WRITE_HANDLER_H_ |