Added init_parser_fuzzer
Test: ./init_parser_fuzzer
Bug: 218631398
Change-Id: Iae344c1e174fb5e07a0fb6813744fa1ae78eff6a
diff --git a/init/fuzzer/Android.bp b/init/fuzzer/Android.bp
new file mode 100644
index 0000000..28a65b2
--- /dev/null
+++ b/init/fuzzer/Android.bp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+cc_defaults {
+ name: "libinit_defaults",
+ static_libs: [
+ "libc++fs",
+ "liblmkd_utils",
+ "libmodprobe",
+ "libprotobuf-cpp-lite",
+ "libpropertyinfoparser",
+ "libsnapshot_init",
+ "libinit",
+ ],
+ shared_libs: [
+ "libbase",
+ "libfs_mgr",
+ "libhidl-gen-utils",
+ "libkeyutils",
+ "liblog",
+ "libprocessgroup",
+ "libselinux",
+ ],
+ header_libs: ["libinit_headers"],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
+
+cc_fuzz {
+ name: "init_parser_fuzzer",
+ srcs: [
+ "init_parser_fuzzer.cpp",
+ ],
+ shared_libs: ["libhidlmetadata",],
+ defaults: [
+ "libinit_defaults",
+ ],
+}
diff --git a/init/fuzzer/README.md b/init/fuzzer/README.md
new file mode 100644
index 0000000..902f30a
--- /dev/null
+++ b/init/fuzzer/README.md
@@ -0,0 +1,26 @@
+# Fuzzers for libinit
+
+## Table of contents
++ [init_parser_fuzzer](#InitParser)
+
+# <a name="InitParser"></a> Fuzzer for InitParser
+
+InitParser supports the following parameters:
+1. ValidPathNames (parameter name: "kValidPaths")
+2. ValidParseInputs (parameter name: "kValidInputs")
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+|`kValidPaths`| 0.`/system/etc/init/hw/init.rc`,<br/> 1.`/system/etc/init` |Value obtained from FuzzedDataProvider|
+|`kValidInputs`| 0.`{"","cpu", "10", "10"}`,<br/> 1.`{"","RLIM_CPU", "10", "10"}`,<br/> 2.`{"","12", "unlimited", "10"}`,<br/> 3.`{"","13", "-1", "10"}`,<br/> 4.`{"","14", "10", "unlimited"}`,<br/> 5.`{"","15", "10", "-1"}` |Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) init_parser_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/init_parser_fuzzer/init_parser_fuzzer
+```
diff --git a/init/fuzzer/init_parser_fuzzer.cpp b/init/fuzzer/init_parser_fuzzer.cpp
new file mode 100644
index 0000000..e6a78a2
--- /dev/null
+++ b/init/fuzzer/init_parser_fuzzer.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2022 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 <fuzzer/FuzzedDataProvider.h>
+#include <hidl/metadata.h>
+#include <import_parser.h>
+#include <interface_utils.h>
+#include <rlimit_parser.h>
+
+using namespace android;
+using namespace android::init;
+
+const std::vector<std::string> kValidInputs[] = {
+ {"", "cpu", "10", "10"}, {"", "RLIM_CPU", "10", "10"}, {"", "12", "unlimited", "10"},
+ {"", "13", "-1", "10"}, {"", "14", "10", "unlimited"}, {"", "15", "10", "-1"},
+};
+
+const std::string kValidPaths[] = {
+ "/system/etc/init/hw/init.rc",
+ "/system/etc/init",
+};
+
+const int32_t kMaxBytes = 256;
+const std::string kValidInterfaces = "android.frameworks.vr.composer@2.0::IVrComposerClient";
+
+class InitParserFuzzer {
+ public:
+ InitParserFuzzer(const uint8_t* data, size_t size) : fdp_(data, size){};
+ void Process();
+
+ private:
+ void InvokeParser();
+ void InvokeLimitParser();
+ void InvokeInterfaceUtils();
+ InterfaceInheritanceHierarchyMap GenerateHierarchyMap();
+ std::vector<HidlInterfaceMetadata> GenerateInterfaceMetadata();
+
+ FuzzedDataProvider fdp_;
+};
+
+void InitParserFuzzer::InvokeLimitParser() {
+ if (fdp_.ConsumeBool()) {
+ std::vector<std::string> input;
+ input.push_back("");
+ input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ input.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ ParseRlimit(input);
+ } else {
+ ParseRlimit(fdp_.PickValueInArray(kValidInputs));
+ }
+}
+
+std::vector<HidlInterfaceMetadata> InitParserFuzzer::GenerateInterfaceMetadata() {
+ std::vector<HidlInterfaceMetadata> random_interface;
+ for (size_t idx = 0; idx < fdp_.ConsumeIntegral<size_t>(); ++idx) {
+ HidlInterfaceMetadata metadata;
+ metadata.name = fdp_.ConsumeRandomLengthString(kMaxBytes);
+ for (size_t idx1 = 0; idx1 < fdp_.ConsumeIntegral<size_t>(); ++idx1) {
+ metadata.inherited.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ }
+ random_interface.push_back(metadata);
+ }
+ return random_interface;
+}
+
+InterfaceInheritanceHierarchyMap InitParserFuzzer::GenerateHierarchyMap() {
+ InterfaceInheritanceHierarchyMap result;
+ std::vector<HidlInterfaceMetadata> random_interface;
+ if (fdp_.ConsumeBool()) {
+ random_interface = GenerateInterfaceMetadata();
+ } else {
+ random_interface = HidlInterfaceMetadata::all();
+ }
+
+ for (const HidlInterfaceMetadata& iface : random_interface) {
+ std::set<FQName> inherited_interfaces;
+ for (const std::string& intf : iface.inherited) {
+ FQName fqname;
+ (void)fqname.setTo(intf);
+ inherited_interfaces.insert(fqname);
+ }
+ FQName fqname;
+ (void)fqname.setTo(iface.name);
+ result[fqname] = inherited_interfaces;
+ }
+ return result;
+}
+
+void InitParserFuzzer::InvokeInterfaceUtils() {
+ InterfaceInheritanceHierarchyMap hierarchy_map = GenerateHierarchyMap();
+ SetKnownInterfaces(hierarchy_map);
+ IsKnownInterface(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ std::set<std::string> interface_set;
+ for (size_t idx = 0; idx < fdp_.ConsumeIntegral<size_t>(); ++idx) {
+ auto set_interface_values = fdp_.PickValueInArray<const std::function<void()>>({
+ [&]() {
+ interface_set.insert(("aidl/" + fdp_.ConsumeRandomLengthString(kMaxBytes)));
+ },
+ [&]() { interface_set.insert(fdp_.ConsumeRandomLengthString(kMaxBytes)); },
+ [&]() { interface_set.insert(kValidInterfaces); },
+ });
+ set_interface_values();
+ }
+ CheckInterfaceInheritanceHierarchy(interface_set, hierarchy_map);
+}
+
+void InitParserFuzzer::InvokeParser() {
+ Parser parser;
+ std::string name = fdp_.ConsumeBool() ? fdp_.ConsumeRandomLengthString(kMaxBytes) : "import";
+ parser.AddSectionParser(name, std::make_unique<ImportParser>(&parser));
+ std::string path = fdp_.ConsumeBool() ? fdp_.PickValueInArray(kValidPaths)
+ : fdp_.ConsumeRandomLengthString(kMaxBytes);
+ parser.ParseConfig(path);
+ parser.ParseConfigFileInsecure(path);
+}
+
+void InitParserFuzzer::Process() {
+ while (fdp_.remaining_bytes()) {
+ auto invoke_parser_fuzzer = fdp_.PickValueInArray<const std::function<void()>>({
+ [&]() { InvokeParser(); },
+ [&]() { InvokeInterfaceUtils(); },
+ [&]() { InvokeLimitParser(); },
+ });
+ invoke_parser_fuzzer();
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ InitParserFuzzer init_parser_fuzzer(data, size);
+ init_parser_fuzzer.Process();
+ return 0;
+}