/* * Copyright 2021 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 #include #include #include #include #include "tidybuffio.h" #include "tidy.h" // All boolean options. These will be set randomly // based on the fuzzer data. TidyOptionId bool_options[] = { TidyJoinClasses, TidyJoinStyles, TidyKeepFileTimes, TidyKeepTabs, TidyLiteralAttribs, TidyLogicalEmphasis, TidyLowerLiterals, TidyMakeBare, TidyFixUri, TidyForceOutput, TidyGDocClean, TidyHideComments, TidyMark, TidyXmlTags, TidyMakeClean, TidyAnchorAsName, TidyMergeEmphasis, TidyMakeBare, TidyMetaCharset, TidyMuteShow, TidyNCR, TidyNumEntities, TidyOmitOptionalTags, TidyPunctWrap, TidyQuiet, TidyQuoteAmpersand, TidyQuoteMarks, TidyQuoteNbsp, TidyReplaceColor, TidyShowFilename, TidyShowInfo, TidyShowMarkup, TidyShowMetaChange, TidyShowWarnings, TidySkipNested, TidyUpperCaseTags, TidyWarnPropAttrs, TidyWord2000, TidyWrapAsp, TidyWrapAttVals, TidyWrapJste, TidyWrapPhp, TidyWrapScriptlets, TidyWrapSection, TidyWriteBack, }; void set_option(const uint8_t** data, size_t *size, TidyDoc *tdoc, TidyOptionId tboolID) { uint8_t decider; decider = **data; *data += 1; *size -= 1; if (decider % 2 == 0) tidyOptSetBool( *tdoc, tboolID, yes ); else { tidyOptSetBool( *tdoc, tboolID, no ); } } int TidyXhtml(const uint8_t* data, size_t size, TidyBuffer* output, TidyBuffer* errbuf) { uint8_t decider; // We need enough data for picking all of the options. One byte per option. if (size < 5+(sizeof(bool_options)/sizeof(bool_options[0]))) { return 0; } TidyDoc tdoc = tidyCreate(); // Decide output format decider = *data; data++; size--; if (decider % 3 == 0) tidyOptSetBool( tdoc, TidyXhtmlOut, yes ); else { tidyOptSetBool( tdoc, TidyXhtmlOut, no ); } if (decider % 3 == 1) tidyOptSetBool( tdoc, TidyHtmlOut, yes ); else { tidyOptSetBool( tdoc, TidyHtmlOut, no ); } if (decider % 3 == 2) tidyOptSetBool( tdoc, TidyXmlOut, yes ); else { tidyOptSetBool( tdoc, TidyXmlOut, no ); } // Set options for (int i=0; i < sizeof(bool_options)/sizeof(TidyOptionId); i++) { set_option(&data, &size, &tdoc, bool_options[i]); } // Set an error buffer. tidySetErrorBuffer(tdoc, errbuf); // Parse the data decider = *data; data++; size--; switch (decider % 2) { case 0: { char filename[256]; sprintf(filename, "/tmp/libfuzzer.%d", getpid()); FILE *fp = fopen(filename, "wb"); if (!fp) { return 0; } fwrite(data, size, 1, fp); fclose(fp); tidyParseFile(tdoc, filename); unlink(filename); } break; case 1: { char *inp = malloc(size+1); inp[size] = '\0'; memcpy(inp, data, size); tidyParseString(tdoc, inp); free(inp); } } // Cleanup tidyRelease( tdoc ); return 0; } int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { TidyBuffer fuzz_toutput; TidyBuffer fuzz_terror; tidyBufInit(&fuzz_toutput); tidyBufInit(&fuzz_terror); TidyXhtml(data, size, &fuzz_toutput, &fuzz_terror); tidyBufFree(&fuzz_toutput); tidyBufFree(&fuzz_terror); return 0; }