blob: ff141f5a65eb71b2406fbaeed10f7f0ce48c451d [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Fuzzer for the Sanitizer API, intended to be run on ClusterFuzz.
//
// To test out locally:
// - Assuming
// $OUT is your local build output directory with use_libbfuzzer set.
// $GEN is the suitable 'gen' directory under $OUT. $GEN is
// $OUT/gen/third_party_blink/renderer/modules/sanitizer_api.
// - Build:
// $ ninja -C $OUT sanitizer_api_fuzzer
// - Run with:
// $ $OUT/sanitizer_api_fuzzer --dict=$GEN/sanitizer_api.dict \
// $(mktemp -d) $GEN/corpus/
#include "sanitizer.h"
#include "testing/libfuzzer/proto/lpm_interface.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
#include "third_party/blink/renderer/bindings/modules/v8/string_or_document_fragment_or_document.h"
#include "third_party/blink/renderer/bindings/modules/v8/string_or_trusted_html_or_document_fragment_or_document.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_sanitizer_config.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
#include "third_party/blink/renderer/modules/sanitizer_api/sanitizer_config.pb.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/testing/blink_fuzzer_test_support.h"
#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
ScriptState* Initialization() {
static BlinkFuzzerTestSupport test_support = BlinkFuzzerTestSupport();
static DummyPageHolder* g_page_holder = new DummyPageHolder();
return ToScriptStateForMainWorld(&g_page_holder->GetFrame());
}
Vector<String> ToVector(
const google::protobuf::RepeatedPtrField<std::string>& inputs) {
Vector<String> elements;
for (auto i : inputs) {
elements.push_back(i.c_str());
}
return elements;
}
void MakeConfiguration(SanitizerConfig* sanitizer_config,
const SanitizerConfigProto& proto) {
if (proto.allow_elements_size()) {
sanitizer_config->setAllowElements(ToVector(proto.allow_elements()));
}
if (proto.block_elements_size()) {
sanitizer_config->setBlockElements(ToVector(proto.block_elements()));
}
if (proto.drop_elements_size()) {
sanitizer_config->setDropElements(ToVector(proto.drop_elements()));
}
if (proto.allow_attributes_size()) {
Vector<std::pair<String, Vector<String>>> allow_attributes;
for (auto i : proto.allow_attributes()) {
allow_attributes.push_back(std::pair<String, Vector<String>>(
i.first.c_str(), ToVector(i.second.element())));
}
sanitizer_config->setAllowAttributes(allow_attributes);
}
if (proto.drop_attributes_size()) {
Vector<std::pair<String, Vector<String>>> drop_attributes;
for (auto i : proto.drop_attributes()) {
drop_attributes.push_back(std::pair<String, Vector<String>>(
i.first.c_str(), ToVector(i.second.element())));
}
sanitizer_config->setDropAttributes(drop_attributes);
}
sanitizer_config->setAllowCustomElements(proto.allow_custom_elements());
}
void TextProtoFuzzer(const SanitizerConfigProto& proto,
ScriptState* script_state) {
// Create Sanitizer based on proto's config..
LocalDOMWindow* window = LocalDOMWindow::From(script_state);
auto* sanitizer_config = MakeGarbageCollected<SanitizerConfig>();
MakeConfiguration(sanitizer_config, proto);
auto* sanitizer = MakeGarbageCollected<Sanitizer>(
window->GetExecutionContext(), sanitizer_config);
// Sanitize string given in proto. Method depends on sanitize_to_string.
String str = proto.html_string().c_str();
if (proto.sanitize_to_string()) {
StringOrTrustedHTMLOrDocumentFragmentOrDocument str1 =
StringOrTrustedHTMLOrDocumentFragmentOrDocument::FromString(str);
sanitizer->sanitize(script_state, str1, IGNORE_EXCEPTION_FOR_TESTING);
} else {
StringOrDocumentFragmentOrDocument str2 =
StringOrDocumentFragmentOrDocument::FromString(str);
sanitizer->sanitizeToString(script_state, str2,
IGNORE_EXCEPTION_FOR_TESTING);
}
// The fuzzer will eventually run out of memory. Force the GC to run every
// N-th time. This will trigger both V8 + Oilpan GC.
static size_t counter = 0;
if (counter++ > 1000) {
counter = 0;
V8PerIsolateData::MainThreadIsolate()->RequestGarbageCollectionForTesting(
v8::Isolate::kFullGarbageCollection);
}
}
} // namespace blink
DEFINE_TEXT_PROTO_FUZZER(const SanitizerConfigProto& proto) {
static blink::ScriptState* script_state = blink::Initialization();
blink::TextProtoFuzzer(proto, script_state);
}