Added init_ueventHandler_fuzzer

Test: ./init_ueventHandler_fuzzer
Bug: 218631398

Change-Id: I264d0891f14cc5836e45d08578347737c94a168f
diff --git a/init/fuzzer/Android.bp b/init/fuzzer/Android.bp
index b15b620..acbb746 100644
--- a/init/fuzzer/Android.bp
+++ b/init/fuzzer/Android.bp
@@ -60,3 +60,13 @@
     ],
     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
index 39cf6cf..fc9a6a6 100644
--- a/init/fuzzer/README.md
+++ b/init/fuzzer/README.md
@@ -3,6 +3,7 @@
 ## Table of contents
 + [init_parser_fuzzer](#InitParser)
 + [init_property_fuzzer](#InitProperty)
++ [init_ueventHandler_fuzzer](#InitUeventHandler)
 
 # <a name="InitParser"></a> Fuzzer for InitParser
 
@@ -45,3 +46,53 @@
   $ adb sync data
   $ adb shell /data/fuzz/arm64/init_property_fuzzer/init_property_fuzzer
 ```
+
+# <a name="InitUeventHandler"></a> 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_ueventHandler_fuzzer.cpp b/init/fuzzer/init_ueventHandler_fuzzer.cpp
new file mode 100644
index 0000000..b6d5f8a
--- /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 <devices.h>
+#include <firmware_handler.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <modalias_handler.h>
+#include <sys/stat.h>
+#include <util.h>
+#include <fstream>
+
+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<int32_t>();
+    uevent.major = fdp->ConsumeIntegral<int32_t>();
+    uevent.minor = fdp->ConsumeIntegral<int32_t>();
+    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<const std::function<void()>>({
+                [&]() {
+                    std::vector<std::string> modalias_vector;
+                    for (size_t idx = 0;
+                         idx < fdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize); ++idx) {
+                        modalias_vector.push_back(fdp.ConsumeRandomLengthString(kMaxBytes));
+                    }
+                    ModaliasHandler modalias_handler = ModaliasHandler(modalias_vector);
+                    modalias_handler.HandleUevent(CreateUevent(&fdp));
+                },
+                [&]() {
+                    std::vector<ExternalFirmwareHandler> external_handlers;
+                    std::vector<std::string> firmware_directories;
+                    for (size_t idx = 0;
+                         idx < fdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize); ++idx) {
+                        std::string devPath = fdp.ConsumeRandomLengthString(kMaxBytes);
+                        uid_t uid = fdp.ConsumeIntegral<uid_t>();
+                        gid_t gid = fdp.ConsumeIntegral<gid_t>();
+                        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;
+}