update_engine: Add delta_performer_fuzzer

delta_performer operates on data it downloads from Omaha servers. Most
of the data is signed, but there are a few header bytes that are not
signed. It worth doing this fuzzer.

BUG=chromium:1014275
TEST=FEATURES=test USE="asan fuzzer" emerge-amd64-generic update_engine

Change-Id: I514bac5f8c4d28833cd01e1456481fb593c9f51a
Reviewed-on: https://chromium-review.googlesource.com/c/aosp/platform/system/update_engine/+/1860994
Reviewed-by: Manoj Gupta <[email protected]>
Tested-by: Amin Hassani <[email protected]>
diff --git a/BUILD.gn b/BUILD.gn
index 1e803a0..01207bd 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -50,7 +50,10 @@
   }
 
   if (use.fuzzer) {
-    deps += [ ":update_engine_omaha_request_action_fuzzer" ]
+    deps += [
+      ":update_engine_delta_performer_fuzzer",
+      ":update_engine_omaha_request_action_fuzzer",
+    ]
   }
 }
 
@@ -553,6 +556,23 @@
 
 # Fuzzer target.
 if (use.fuzzer) {
+  executable("update_engine_delta_performer_fuzzer") {
+    sources = [
+      "payload_consumer/delta_performer_fuzzer.cc",
+    ]
+    configs += [
+      "//common-mk/common_fuzzer",
+      ":target_defaults",
+    ]
+    pkg_deps = [
+      "libbrillo-test-${libbase_ver}",
+      "libchrome-test-${libbase_ver}",
+    ]
+    deps = [
+      ":libupdate_engine",
+      ":update_engine_test_libs",
+    ]
+  }
   executable("update_engine_omaha_request_action_fuzzer") {
     sources = [
       "omaha_request_action_fuzzer.cc",
diff --git a/payload_consumer/delta_performer_fuzzer.cc b/payload_consumer/delta_performer_fuzzer.cc
new file mode 100644
index 0000000..53b168a
--- /dev/null
+++ b/payload_consumer/delta_performer_fuzzer.cc
@@ -0,0 +1,103 @@
+//
+// Copyright 2019 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 <string>
+
+#include <base/logging.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "update_engine/common/fake_boot_control.h"
+#include "update_engine/common/fake_hardware.h"
+#include "update_engine/common/prefs.h"
+#include "update_engine/payload_consumer/delta_performer.h"
+#include "update_engine/payload_consumer/download_action.h"
+#include "update_engine/payload_consumer/install_plan.h"
+
+namespace chromeos_update_engine {
+
+class FakeDownloadActionDelegate : public DownloadActionDelegate {
+ public:
+  FakeDownloadActionDelegate() = default;
+  ~FakeDownloadActionDelegate() = default;
+
+  // DownloadActionDelegate overrides;
+  void BytesReceived(uint64_t bytes_progressed,
+                     uint64_t bytes_received,
+                     uint64_t total) override{};
+
+  bool ShouldCancel(ErrorCode* cancel_reason) override { return false; };
+
+  void DownloadComplete() override{};
+
+  DISALLOW_COPY_AND_ASSIGN(FakeDownloadActionDelegate);
+};
+
+void FuzzDeltaPerformer(const uint8_t* data, size_t size) {
+  MemoryPrefs prefs;
+  FakeBootControl boot_control;
+  FakeHardware hardware;
+  FakeDownloadActionDelegate download_action_delegate;
+
+  FuzzedDataProvider data_provider(data, size);
+
+  InstallPlan install_plan{
+      .target_slot = 1,
+      .partitions = {InstallPlan::Partition{
+          .source_path = "/dev/zero",
+          .source_size = 4096,
+          .target_path = "/dev/null",
+          .target_size = 4096,
+      }},
+  };
+
+  InstallPlan::Payload payload{
+      .size = data_provider.ConsumeIntegralInRange<uint64_t>(0, 10000),
+      .metadata_size = data_provider.ConsumeIntegralInRange<uint64_t>(0, 1000),
+      .hash = data_provider.ConsumeBytes<uint8_t>(32),
+      .type = static_cast<InstallPayloadType>(
+          data_provider.ConsumeIntegralInRange(0, 3)),
+      .already_applied = data_provider.ConsumeBool(),
+  };
+
+  DeltaPerformer performer(&prefs,
+                           &boot_control,
+                           &hardware,
+                           &download_action_delegate,
+                           &install_plan,
+                           &payload,
+                           data_provider.ConsumeBool());
+  do {
+    auto chunk_size = data_provider.ConsumeIntegralInRange<size_t>(0, 100);
+    auto data = data_provider.ConsumeBytes<uint8_t>(chunk_size);
+    performer.Write(data.data(), data.size());
+  } while (data_provider.remaining_bytes() > 0);
+}
+
+}  // namespace chromeos_update_engine
+
+class Environment {
+ public:
+  Environment() { logging::SetMinLogLevel(logging::LOG_FATAL); }
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  if (size > 1000000) {
+    return 0;
+  }
+
+  static Environment env;
+  chromeos_update_engine::FuzzDeltaPerformer(data, size);
+  return 0;
+}