From 1532fa7577d3741c2e23555c2ccc08c6db77e733 Mon Sep 17 00:00:00 2001 From: Hamzeh Zawawy <hamzeh@google.com> Date: Tue, 5 Mar 2024 12:13:52 -0800 Subject: [PATCH] Adding fuzzer ResXMLTree Bug: 328272470 Test: m resxmlparser_fuzzer and then run binary Change-Id: I389abf4f8cfb534c354b9846293c5b583987f4e2 --- .../fuzz/resxmlparser_fuzzer/Android.bp | 51 ++++++++++++ .../resxmlparser_fuzzer.cpp | 80 +++++++++++++++++++ .../testdata/attributes.xml | 10 +++ .../resxmlparser_fuzzer/testdata/basic.xml | 5 ++ .../resxmlparser_fuzzer/testdata/cdata.xml | 6 ++ .../resxmlparser_fuzzer/xmlparser_fuzzer.dict | 11 +++ 6 files changed, 163 insertions(+) create mode 100644 libs/androidfw/fuzz/resxmlparser_fuzzer/Android.bp create mode 100644 libs/androidfw/fuzz/resxmlparser_fuzzer/resxmlparser_fuzzer.cpp create mode 100644 libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/attributes.xml create mode 100644 libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/basic.xml create mode 100644 libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/cdata.xml create mode 100644 libs/androidfw/fuzz/resxmlparser_fuzzer/xmlparser_fuzzer.dict diff --git a/libs/androidfw/fuzz/resxmlparser_fuzzer/Android.bp b/libs/androidfw/fuzz/resxmlparser_fuzzer/Android.bp new file mode 100644 index 000000000000..4b008a7b4815 --- /dev/null +++ b/libs/androidfw/fuzz/resxmlparser_fuzzer/Android.bp @@ -0,0 +1,51 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_libs_androidfw_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_libs_androidfw_license"], +} + +cc_fuzz { + name: "resxmlparser_fuzzer", + srcs: [ + "resxmlparser_fuzzer.cpp", + ], + host_supported: true, + + static_libs: ["libgmock"], + target: { + android: { + shared_libs: [ + "libandroidfw", + "libbase", + "libbinder", + "libcutils", + "liblog", + "libutils", + ], + }, + host: { + static_libs: [ + "libandroidfw", + "libbase", + "libbinder", + "libcutils", + "liblog", + "libutils", + ], + }, + darwin: { + // libbinder is not supported on mac + enabled: false, + }, + }, + + include_dirs: [ + "system/incremental_delivery/incfs/util/include/", + ], + + corpus: ["testdata/*"], + dictionary: "xmlparser_fuzzer.dict", +} diff --git a/libs/androidfw/fuzz/resxmlparser_fuzzer/resxmlparser_fuzzer.cpp b/libs/androidfw/fuzz/resxmlparser_fuzzer/resxmlparser_fuzzer.cpp new file mode 100644 index 000000000000..829a39617012 --- /dev/null +++ b/libs/androidfw/fuzz/resxmlparser_fuzzer/resxmlparser_fuzzer.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * 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 <memory> +#include <cstdint> +#include <cstddef> +#include <fuzzer/FuzzedDataProvider.h> +#include "androidfw/ResourceTypes.h" + +static void populateDynamicRefTableWithFuzzedData( + android::DynamicRefTable& table, + FuzzedDataProvider& fuzzedDataProvider) { + + const size_t numMappings = fuzzedDataProvider.ConsumeIntegralInRange<size_t>(1, 5); + for (size_t i = 0; i < numMappings; ++i) { + const uint8_t packageId = fuzzedDataProvider.ConsumeIntegralInRange<uint8_t>(0x02, 0x7F); + + // Generate a package name + std::string packageName; + size_t packageNameLength = fuzzedDataProvider.ConsumeIntegralInRange<size_t>(1, 128); + for (size_t j = 0; j < packageNameLength; ++j) { + // Consume characters only in the ASCII range (0x20 to 0x7E) to ensure valid UTF-8 + char ch = fuzzedDataProvider.ConsumeIntegralInRange<char>(0x20, 0x7E); + packageName.push_back(ch); + } + + // Convert std::string to String16 for compatibility + android::String16 androidPackageName(packageName.c_str(), packageName.length()); + + // Add the mapping to the table + table.addMapping(androidPackageName, packageId); + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + FuzzedDataProvider fuzzedDataProvider(data, size); + + auto dynamic_ref_table = std::make_shared<android::DynamicRefTable>(); + + // Populate the DynamicRefTable with fuzzed data + populateDynamicRefTableWithFuzzedData(*dynamic_ref_table, fuzzedDataProvider); + + auto tree = android::ResXMLTree(std::move(dynamic_ref_table)); + + std::vector<uint8_t> xmlData = fuzzedDataProvider.ConsumeRemainingBytes<uint8_t>(); + if (tree.setTo(xmlData.data(), xmlData.size()) != android::NO_ERROR) { + return 0; // Exit early if unable to parse XML data + } + + tree.restart(); + + size_t len = 0; + auto code = tree.next(); + if (code == android::ResXMLParser::START_TAG) { + // Access element name + auto name = tree.getElementName(&len); + + // Access attributes of the current element + for (size_t i = 0; i < tree.getAttributeCount(); i++) { + // Access attribute name + auto attrName = tree.getAttributeName(i, &len); + } + } else if (code == android::ResXMLParser::TEXT) { + const auto text = tree.getText(&len); + } + return 0; // Non-zero return values are reserved for future use. +} diff --git a/libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/attributes.xml b/libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/attributes.xml new file mode 100644 index 000000000000..417fec72be6a --- /dev/null +++ b/libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/attributes.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<root> + <child id="1"> + <subchild type="A">Content A</subchild> + <subchild type="B">Content B</subchild> + </child> + <child id="2" extra="data"> + <subchild type="C">Content C</subchild> + </child> +</root> diff --git a/libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/basic.xml b/libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/basic.xml new file mode 100644 index 000000000000..7e13db536fc9 --- /dev/null +++ b/libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/basic.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<root> + <child1>Value 1</child1> + <child2>Value 2</child2> +</root> diff --git a/libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/cdata.xml b/libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/cdata.xml new file mode 100644 index 000000000000..90cdf3513be9 --- /dev/null +++ b/libs/androidfw/fuzz/resxmlparser_fuzzer/testdata/cdata.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<root> + <!-- Example with special characters and CDATA --> + <data><![CDATA[Some <encoded> data & other "special" characters]]></data> + <message>Hello & Welcome!</message> +</root> diff --git a/libs/androidfw/fuzz/resxmlparser_fuzzer/xmlparser_fuzzer.dict b/libs/androidfw/fuzz/resxmlparser_fuzzer/xmlparser_fuzzer.dict new file mode 100644 index 000000000000..745ded4810f3 --- /dev/null +++ b/libs/androidfw/fuzz/resxmlparser_fuzzer/xmlparser_fuzzer.dict @@ -0,0 +1,11 @@ +root_tag=<root> +child_tag=<child> +end_child_tag=</child> +id_attr=id=" +type_attr=type=" +cdata_start=<![CDATA[ +cdata_end=]]> +ampersand_entity=& +xml_header=<?xml version="1.0" encoding="UTF-8"?> +comment_start=<!-- +comment_end= --> -- GitLab