diff --git a/init/fuzzer/Android.bp b/init/fuzzer/Android.bp
new file mode 100644
index 000000000..acbb7468a
--- /dev/null
+++ b/init/fuzzer/Android.bp
@@ -0,0 +1,72 @@
+/*
+ * 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",
+ ],
+}
+
+cc_fuzz {
+ name: "init_property_fuzzer",
+ srcs: [
+ "init_property_fuzzer.cpp",
+ ],
+ defaults: ["libinit_defaults"],
+}
+
+cc_fuzz {
+ name: "init_ueventHandler_fuzzer",
+ srcs: [
+ "init_ueventHandler_fuzzer.cpp",
+ ],
+ defaults: [
+ "libinit_defaults",
+ ],
+}
diff --git a/init/fuzzer/README.md b/init/fuzzer/README.md
new file mode 100644
index 000000000..fc9a6a675
--- /dev/null
+++ b/init/fuzzer/README.md
@@ -0,0 +1,98 @@
+# Fuzzers for libinit
+
+## Table of contents
++ [init_parser_fuzzer](#InitParser)
++ [init_property_fuzzer](#InitProperty)
++ [init_ueventHandler_fuzzer](#InitUeventHandler)
+
+# 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`,
1.`/system/etc/init` |Value obtained from FuzzedDataProvider|
+|`kValidInputs`| 0.`{"","cpu", "10", "10"}`,
1.`{"","RLIM_CPU", "10", "10"}`,
2.`{"","12", "unlimited", "10"}`,
3.`{"","13", "-1", "10"}`,
4.`{"","14", "10", "unlimited"}`,
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
+```
+
+# Fuzzer for InitProperty
+
+InitProperty supports the following parameters:
+ PropertyType (parameter name: "PropertyType")
+
+| Parameter| Valid Values |Configured Value|
+|-------------|----------|----- |
+|`PropertyType`| 0.`STRING`,
1.`BOOL`,
2.`INT`,
3.`UINT`,
4.`DOUBLE`,
5.`SIZE`,
6.`ENUM`,
7.`RANDOM`|Value obtained from FuzzedDataProvider|
+
+#### Steps to run
+1. Build the fuzzer
+```
+ $ mm -j$(nproc) init_property_fuzzer
+```
+2. Run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/init_property_fuzzer/init_property_fuzzer
+```
+
+# Fuzzer for InitUeventHandler
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+InitUeventHandler supports the following parameters:
+1. Major (parameter name: `major`)
+2. Minor (parameter name: `minor`)
+3. PartitionNum (parameter name: `partition_num`)
+4. Uid (parameter name: `uid`)
+5. Gid (parameter name: `gid`)
+6. Action (parameter name: `action`)
+7. Path (parameter name: `path`)
+8. Subsystem (parameter name: `subsystem`)
+9. PartitionName (parameter name: `partition_name`)
+10. DeviceName (parameter name: `device_name`)
+11. Modalias (parameter name: `modalias`)
+12. DevPath (parameter name: `devPath`)
+13. HandlerPath (parameter name: `handlerPath`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `major` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `minor` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `partition_num ` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `uid` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `gid` | `UINT32_MIN` to `UINT32_MAX` | Value obtained from FuzzedDataProvider|
+| `action` | `String` | Value obtained from FuzzedDataProvider|
+| `path` | `String` | Value obtained from FuzzedDataProvider|
+| `subsystem` | `String` | Value obtained from FuzzedDataProvider|
+| `partition_name` | `String` | Value obtained from FuzzedDataProvider|
+| `device_name` | `String` | Value obtained from FuzzedDataProvider|
+| `modalias` | `String` | Value obtained from FuzzedDataProvider|
+| `devPath` | `String` | Value obtained from FuzzedDataProvider|
+| `handlerPath` | `String` | Value obtained from FuzzedDataProvider|
+
+This also ensures that the plugin is always deterministic for any given input.
+
+#### Steps to run
+1. Build the fuzzer
+```
+$ mm -j$(nproc) init_ueventHandler_fuzzer
+```
+2. Run on device
+```
+$ adb sync data
+$ adb shell /data/fuzz/arm64/init_ueventHandler_fuzzer/init_ueventHandler_fuzzer
+```
diff --git a/init/fuzzer/init_parser_fuzzer.cpp b/init/fuzzer/init_parser_fuzzer.cpp
new file mode 100644
index 000000000..e6a78a2c4
--- /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
+#include
+#include
+#include
+#include
+
+using namespace android;
+using namespace android::init;
+
+const std::vector 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 GenerateInterfaceMetadata();
+
+ FuzzedDataProvider fdp_;
+};
+
+void InitParserFuzzer::InvokeLimitParser() {
+ if (fdp_.ConsumeBool()) {
+ std::vector 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 InitParserFuzzer::GenerateInterfaceMetadata() {
+ std::vector random_interface;
+ for (size_t idx = 0; idx < fdp_.ConsumeIntegral(); ++idx) {
+ HidlInterfaceMetadata metadata;
+ metadata.name = fdp_.ConsumeRandomLengthString(kMaxBytes);
+ for (size_t idx1 = 0; idx1 < fdp_.ConsumeIntegral(); ++idx1) {
+ metadata.inherited.push_back(fdp_.ConsumeRandomLengthString(kMaxBytes));
+ }
+ random_interface.push_back(metadata);
+ }
+ return random_interface;
+}
+
+InterfaceInheritanceHierarchyMap InitParserFuzzer::GenerateHierarchyMap() {
+ InterfaceInheritanceHierarchyMap result;
+ std::vector random_interface;
+ if (fdp_.ConsumeBool()) {
+ random_interface = GenerateInterfaceMetadata();
+ } else {
+ random_interface = HidlInterfaceMetadata::all();
+ }
+
+ for (const HidlInterfaceMetadata& iface : random_interface) {
+ std::set 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 interface_set;
+ for (size_t idx = 0; idx < fdp_.ConsumeIntegral(); ++idx) {
+ auto set_interface_values = fdp_.PickValueInArray>({
+ [&]() {
+ 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(&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>({
+ [&]() { 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;
+}
diff --git a/init/fuzzer/init_property_fuzzer.cpp b/init/fuzzer/init_property_fuzzer.cpp
new file mode 100644
index 000000000..22df37559
--- /dev/null
+++ b/init/fuzzer/init_property_fuzzer.cpp
@@ -0,0 +1,140 @@
+/*
+ * 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
+#include
+#include
+#include
+#include "fuzzer/FuzzedDataProvider.h"
+
+using namespace android;
+using namespace android::init;
+using android::init::persistent_property_filename;
+
+const std::string kTempDir = "/data/local/tmp/";
+const std::string kFuzzerPropertyFile = kTempDir + "persistent_properties";
+constexpr int32_t kMaxPropertyLength = 10;
+const std::string kPrefix = "persist.";
+const std::string kPropertyName = kPrefix + "sys.timezone";
+const std::string kPropertyValue = "America/Los_Angeles";
+const std::string kLegacyPropertyFile = "/data/property/persist.properties";
+const std::string kSizeSuffix[3] = {"g", "k", "m"};
+constexpr int32_t kMinNumStrings = 1;
+constexpr int32_t kMaxNumStrings = 10;
+
+enum PropertyType { STRING, BOOL, INT, UINT, DOUBLE, SIZE, ENUM, RANDOM, kMaxValue = RANDOM };
+
+class InitPropertyFuzzer {
+ public:
+ InitPropertyFuzzer(const uint8_t* data, size_t size) : fdp_(data, size){};
+ void process();
+
+ private:
+ void InvokeCheckType();
+ void InvokeWritePersistentProperty();
+ void RemoveFiles();
+ void CreateFuzzerPropertyFile(const std::string property_file);
+ FuzzedDataProvider fdp_;
+};
+
+void InitPropertyFuzzer::InvokeCheckType() {
+ std::string property_type;
+ std::string value;
+ int type = fdp_.ConsumeEnum();
+ switch (type) {
+ case STRING:
+ value = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
+ property_type = "string";
+ break;
+ case BOOL:
+ value = fdp_.ConsumeBool();
+ property_type = "bool";
+ break;
+ case INT:
+ value = fdp_.ConsumeIntegral();
+ property_type = "int";
+ break;
+ case UINT:
+ value = fdp_.ConsumeIntegral();
+ property_type = "uint";
+ break;
+ case DOUBLE:
+ value = fdp_.ConsumeFloatingPoint();
+ property_type = "double";
+ break;
+ case SIZE:
+ value = fdp_.ConsumeIntegral();
+ value = value.append(fdp_.PickValueInArray(kSizeSuffix));
+ property_type = "size";
+ break;
+ case ENUM:
+ value = fdp_.ConsumeIntegral();
+ property_type = "enum";
+ break;
+ case RANDOM:
+ value = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
+ property_type = fdp_.ConsumeRandomLengthString(kMaxPropertyLength);
+ break;
+ }
+
+ CheckType(property_type, value);
+}
+
+void InitPropertyFuzzer::InvokeWritePersistentProperty() {
+ if (fdp_.ConsumeBool()) {
+ WritePersistentProperty(kPropertyName, kPropertyValue);
+ } else {
+ WritePersistentProperty((kPrefix + fdp_.ConsumeRandomLengthString(kMaxPropertyLength)),
+ fdp_.ConsumeRandomLengthString(kMaxPropertyLength));
+ }
+}
+
+void InitPropertyFuzzer::RemoveFiles() {
+ remove(kFuzzerPropertyFile.c_str());
+ remove(kLegacyPropertyFile.c_str());
+}
+
+void InitPropertyFuzzer::CreateFuzzerPropertyFile(const std::string property_file) {
+ std::ofstream out;
+ out.open(property_file, std::ios::binary | std::ofstream::trunc);
+ chmod(property_file.c_str(), S_IRWXU);
+ const int32_t numStrings = fdp_.ConsumeIntegralInRange(kMinNumStrings, kMaxNumStrings);
+ for (int32_t i = 0; i < numStrings; ++i) {
+ out << fdp_.ConsumeRandomLengthString(kMaxPropertyLength) << "\n";
+ }
+ out.close();
+}
+
+void InitPropertyFuzzer::process() {
+ persistent_property_filename = kFuzzerPropertyFile;
+ /* Property and legacy files are created using createFuzzerPropertyFile() and */
+ /* are used in the below APIs. Hence createFuzzerPropertyFile() is not a part */
+ /* of the lambda construct. */
+ CreateFuzzerPropertyFile(kFuzzerPropertyFile);
+ CreateFuzzerPropertyFile(kLegacyPropertyFile);
+ auto property_type = fdp_.PickValueInArray>({
+ [&]() { InvokeCheckType(); },
+ [&]() { InvokeWritePersistentProperty(); },
+ [&]() { LoadPersistentProperties(); },
+ });
+ property_type();
+ RemoveFiles();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ InitPropertyFuzzer initPropertyFuzzer(data, size);
+ initPropertyFuzzer.process();
+ return 0;
+}
diff --git a/init/fuzzer/init_ueventHandler_fuzzer.cpp b/init/fuzzer/init_ueventHandler_fuzzer.cpp
new file mode 100644
index 000000000..b6d5f8a42
--- /dev/null
+++ b/init/fuzzer/init_ueventHandler_fuzzer.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+
+using namespace android;
+using namespace android::init;
+constexpr int32_t kMaxBytes = 100;
+constexpr int32_t kMaxSize = 1000;
+constexpr int32_t kMinSize = 1;
+
+/*'HandleUevent' prefixes the path with '/sys' and hence this is required to point
+ * to'/data/local/tmp' dir.*/
+const std::string kPath = "/../data/local/tmp/";
+const std::string kPathPrefix = "/..";
+
+void MakeFile(FuzzedDataProvider* fdp, std::string s) {
+ std::ofstream out;
+ out.open(s, std::ios::binary | std::ofstream::trunc);
+ for (int32_t idx = 0; idx < fdp->ConsumeIntegralInRange(kMinSize, kMaxSize); ++idx) {
+ out << fdp->ConsumeRandomLengthString(kMaxBytes) << "\n";
+ }
+ out.close();
+}
+
+void CreateDir(std::string Directory, FuzzedDataProvider* fdp) {
+ std::string tmp = Directory.substr(kPathPrefix.length());
+ mkdir_recursive(android::base::Dirname(tmp.c_str()),
+ S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+ MakeFile(fdp, tmp + "/data");
+ MakeFile(fdp, tmp + "/loading");
+}
+
+std::string SelectRandomString(FuzzedDataProvider* fdp, std::string s) {
+ if (fdp->ConsumeBool()) {
+ if (fdp->ConsumeBool()) {
+ return fdp->ConsumeRandomLengthString(kMaxBytes);
+ } else {
+ return s;
+ }
+ }
+ return "";
+}
+
+Uevent CreateUevent(FuzzedDataProvider* fdp) {
+ Uevent uevent;
+ uevent.action = SelectRandomString(fdp, "add");
+ uevent.subsystem = SelectRandomString(fdp, "firmware");
+ uevent.path = SelectRandomString(fdp, kPath + fdp->ConsumeRandomLengthString(kMaxBytes));
+ uevent.firmware = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+ uevent.partition_name = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+ uevent.device_name = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+ uevent.modalias = fdp->ConsumeBool() ? fdp->ConsumeRandomLengthString(kMaxBytes) : "";
+ uevent.partition_num = fdp->ConsumeIntegral();
+ uevent.major = fdp->ConsumeIntegral();
+ uevent.minor = fdp->ConsumeIntegral();
+ return uevent;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ while (fdp.remaining_bytes()) {
+ auto invoke_uevent_handler_fuzzer = fdp.PickValueInArray>({
+ [&]() {
+ std::vector modalias_vector;
+ for (size_t idx = 0;
+ idx < fdp.ConsumeIntegralInRange(kMinSize, kMaxSize); ++idx) {
+ modalias_vector.push_back(fdp.ConsumeRandomLengthString(kMaxBytes));
+ }
+ ModaliasHandler modalias_handler = ModaliasHandler(modalias_vector);
+ modalias_handler.HandleUevent(CreateUevent(&fdp));
+ },
+ [&]() {
+ std::vector external_handlers;
+ std::vector firmware_directories;
+ for (size_t idx = 0;
+ idx < fdp.ConsumeIntegralInRange(kMinSize, kMaxSize); ++idx) {
+ std::string devPath = fdp.ConsumeRandomLengthString(kMaxBytes);
+ uid_t uid = fdp.ConsumeIntegral();
+ gid_t gid = fdp.ConsumeIntegral();
+ std::string handlerPath = fdp.ConsumeRandomLengthString(kMaxBytes);
+ ExternalFirmwareHandler externalFirmwareHandler =
+ ExternalFirmwareHandler(devPath, uid, gid, handlerPath);
+ external_handlers.push_back(externalFirmwareHandler);
+ firmware_directories.push_back(fdp.ConsumeRandomLengthString(kMaxBytes));
+ }
+ FirmwareHandler firmware_handler =
+ FirmwareHandler(firmware_directories, external_handlers);
+ Uevent uevent = CreateUevent(&fdp);
+ if (fdp.ConsumeBool() && uevent.path.size() != 0 &&
+ uevent.path.find(kPath) == 0) {
+ CreateDir(uevent.path, &fdp);
+ firmware_handler.HandleUevent(uevent);
+ std::string s = uevent.path.substr(kPathPrefix.length());
+ remove(s.c_str());
+ } else {
+ firmware_handler.HandleUevent(uevent);
+ }
+ },
+ });
+ invoke_uevent_handler_fuzzer();
+ }
+ return 0;
+}