Added updateEngine_downloadAction_fuzzer
Test: ./updateEngine_downloadAction_fuzzer
Bug: 193202513
Change-Id: If736e8a2bec73b5af18264ccdd2c3f56ded8c3dd
diff --git a/fuzzer/updateEngine_downloadAction_fuzzer.cpp b/fuzzer/updateEngine_downloadAction_fuzzer.cpp
new file mode 100644
index 0000000..e877273
--- /dev/null
+++ b/fuzzer/updateEngine_downloadAction_fuzzer.cpp
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2021 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 <update_engine/common/download_action.h>
+#include <update_engine/common/boot_control_stub.h>
+#include <update_engine/common/hardware_interface.h>
+#include <update_engine/common/http_fetcher.h>
+#include <update_engine/common/error_code.h>
+#include <update_engine/common/proxy_resolver.h>
+#include <update_engine/common/action_processor.h>
+#include <string.h>
+#include <utils/Log.h>
+#include <fuzzer/FuzzedDataProvider.h>
+
+using namespace chromeos_update_engine;
+using namespace std;
+
+constexpr size_t kSizeMin = 1;
+constexpr size_t kSizeMax = 1000;
+constexpr size_t kHashSize = 32;
+constexpr size_t kStringMaxLength = 20;
+const string kDownloadUrl = "http://fake_url.invalid";
+const string kSourcePath = "/dev/zero";
+const string kTargetPath = "/dev/null";
+
+class TestPrefsInterface : public PrefsInterface {
+ public:
+ TestPrefsInterface(FuzzedDataProvider* fdp) : mFdp(fdp) {
+ mMetadataSize = mFdp->ConsumeIntegralInRange<int64_t>(kSizeMin, kSizeMax);
+ mSignatureSize = mFdp->ConsumeIntegralInRange<int64_t>(kSizeMin, kSizeMax);
+ };
+
+ bool GetString(std::string_view key, std::string* value) const {
+ if (key == "manifest-bytes") {
+ *value = mFdp->ConsumeRandomLengthString(mMetadataSize + mSignatureSize);
+ return true;
+ }
+ *value = "";
+ return false;
+ };
+
+ bool SetString(std::string_view /*key*/, std::string_view /*value*/) {
+ return true;
+ };
+
+ bool GetInt64(std::string_view key, int64_t* value) const {
+ if (key == "manifest-metadata-size") {
+ *value = mMetadataSize;
+ return true;
+ }
+ if (key == "manifest-signature-size") {
+ *value = mSignatureSize;
+ return true;
+ }
+ *value = 0;
+ return false;
+ }
+
+ bool SetInt64(std::string_view /*key*/, const int64_t /*value*/) {
+ return true;
+ }
+
+ bool GetBoolean(std::string_view /*key*/, bool* value) const {
+ *value = true;
+ return true;
+ }
+
+ bool SetBoolean(std::string_view /*key*/, const bool /*value*/) {
+ return true;
+ }
+
+ bool Exists(std::string_view /*key*/) const { return true; }
+
+ bool Delete(std::string_view /*key*/) { return true; }
+
+ bool Delete(std::string_view /*pref_key*/,
+ const std::vector<std::string>& /*nss*/) {
+ return true;
+ }
+
+ bool GetSubKeys(std::string_view /*ns*/,
+ std::vector<std::string>* keys) const {
+ keys->push_back("");
+ return true;
+ }
+
+ void AddObserver(std::string_view /*key*/, ObserverInterface* /*observer*/) {}
+
+ void RemoveObserver(std::string_view /*key*/,
+ ObserverInterface* /*observer*/) {}
+
+ private:
+ FuzzedDataProvider* mFdp;
+ int64_t mMetadataSize;
+ int64_t mSignatureSize;
+};
+
+class TestHardwareInterface : public HardwareInterface {
+ public:
+ bool IsOfficialBuild() const { return true; };
+
+ bool IsNormalBootMode() const { return true; };
+
+ bool AreDevFeaturesEnabled() const { return true; };
+
+ bool IsOOBEEnabled() const { return true; };
+
+ bool IsOOBEComplete(base::Time* /*out_time_of_oobe*/) const { return true; };
+
+ string GetHardwareClass() const { return ""; };
+
+ string GetDeviceRequisition() const { return ""; };
+
+ int32_t GetMinKernelKeyVersion() const { return 0; };
+
+ int32_t GetMinFirmwareKeyVersion() const { return 0; };
+
+ int32_t GetMaxFirmwareKeyRollforward() const { return 0; };
+
+ bool SetMaxFirmwareKeyRollforward(int32_t /*firmware_max_rollforward*/) {
+ return true;
+ };
+
+ bool SetMaxKernelKeyRollforward(int32_t /*kernel_max_rollforward*/) {
+ return true;
+ };
+
+ int32_t GetPowerwashCount() const { return 0; };
+
+ bool SchedulePowerwash(bool /*save_rollback_data*/) { return true; };
+
+ bool CancelPowerwash() { return true; };
+
+ bool GetNonVolatileDirectory(base::FilePath* path) const {
+ base::FilePath local_path(constants::kNonVolatileDirectory);
+ *path = local_path;
+ return true;
+ };
+
+ bool GetPowerwashSafeDirectory(base::FilePath* /*path*/) const {
+ return false;
+ };
+
+ int64_t GetBuildTimestamp() const { return 0; };
+
+ bool AllowDowngrade() const { return true; };
+
+ bool GetFirstActiveOmahaPingSent() const { return true; };
+
+ bool SetFirstActiveOmahaPingSent() { return true; };
+
+ void SetWarmReset(bool /*warm_reset*/){};
+
+ void SetVbmetaDigestForInactiveSlot(bool /*reset*/){};
+
+ string GetVersionForLogging(const string& /*partition_name*/) const {
+ return "";
+ };
+
+ ErrorCode IsPartitionUpdateValid(const string& /*partition_name*/,
+ const string& /*new_version*/) const {
+ return ErrorCode::kSuccess;
+ };
+
+ const char* GetPartitionMountOptions(const string& /*partition_name*/) const {
+ return "";
+ };
+};
+
+class TestProxyResolver : public ProxyResolver {
+ public:
+ virtual ~TestProxyResolver() {}
+
+ ProxyRequestId GetProxiesForUrl(const string& /*url*/,
+ const ProxiesResolvedFn& /*callback*/) {
+ return 0;
+ };
+
+ bool CancelProxyRequest(ProxyRequestId /*request*/) { return true; };
+};
+
+class TestHttpFetcher : public HttpFetcher {
+ public:
+ TestHttpFetcher(ProxyResolver* proxy_resolver, FuzzedDataProvider* fdp)
+ : HttpFetcher(proxy_resolver), mFdp(fdp){};
+ virtual ~TestHttpFetcher() {}
+
+ void SetOffset(off_t /*offset*/) {}
+
+ void SetLength(size_t /*length*/) {}
+ void UnsetLength() {}
+
+ void BeginTransfer(const string& /*url*/) {
+ if (mFdp->remaining_bytes() > 0) {
+ size_t maxSize = mFdp->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+ vector<uint8_t> data = mFdp->ConsumeBytes<uint8_t>(maxSize);
+ delegate()->ReceivedBytes(this, data.data(), data.size());
+ }
+ }
+
+ void TerminateTransfer() {}
+
+ void SetHeader(const string& /*header_name*/,
+ const string& /*header_value*/) {}
+
+ bool GetHeader(const string& /*header_name*/, string* header_value) const {
+ *header_value = "";
+ return true;
+ }
+
+ void Pause() {}
+
+ void Unpause() {}
+
+ void set_idle_seconds(int32_t /*seconds*/) {}
+ void set_retry_seconds(int32_t /*seconds*/) {}
+
+ void set_low_speed_limit(int32_t /*low_speed_bps*/,
+ int32_t /*low_speed_sec*/) {}
+
+ void set_connect_timeout(int32_t /*connect_timeout_seconds*/) {}
+
+ void set_max_retry_count(int32_t /*max_retry_count*/) {}
+
+ size_t GetBytesDownloaded() { return 0; }
+
+ private:
+ FuzzedDataProvider* mFdp;
+};
+
+class TestActionProcessor : public ActionProcessor {
+ public:
+ void StartProcessing() {}
+
+ void EnqueueAction(unique_ptr<AbstractAction> /*action*/){};
+
+ void ActionComplete(AbstractAction* /*actionptr*/, ErrorCode /*code*/){};
+};
+
+class chromeos_update_engine::DownloadActionTest {
+ public:
+ DownloadActionTest() : mActionPipe(new ActionPipe<InstallPlan>()) {}
+ ~DownloadActionTest() { mActionPipe = nullptr; }
+
+ void fuzzDownloadAction(const uint8_t* data, size_t size);
+
+ private:
+ shared_ptr<ActionPipe<InstallPlan>> mActionPipe = nullptr;
+};
+
+void DownloadActionTest::fuzzDownloadAction(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+
+ InstallPlan install_plan;
+ install_plan.download_url = kDownloadUrl;
+ install_plan.version = fdp.ConsumeRandomLengthString(kStringMaxLength);
+ install_plan.target_slot = fdp.ConsumeBool() ? 0 : 1;
+ install_plan.hash_checks_mandatory = fdp.ConsumeBool();
+ InstallPlan::Partition partition;
+ partition.name = fdp.ConsumeRandomLengthString(kStringMaxLength);
+ partition.source_path = kSourcePath;
+ partition.source_size = fdp.ConsumeIntegralInRange(kSizeMin, kSizeMax);
+ partition.target_path = kTargetPath;
+ partition.target_size = fdp.ConsumeIntegralInRange(kSizeMin, kSizeMax);
+ install_plan.partitions.push_back(partition);
+ InstallPlan::Payload payload;
+ payload.payload_urls.emplace_back(kDownloadUrl);
+ payload.size = fdp.ConsumeIntegralInRange(kSizeMin, kSizeMax);
+ payload.metadata_size =
+ fdp.ConsumeIntegralInRange<uint64_t>(kSizeMin, kSizeMax),
+ payload.hash = fdp.ConsumeBytes<uint8_t>(kHashSize),
+ payload.already_applied = fdp.ConsumeBool();
+ install_plan.payloads.push_back(payload);
+ install_plan.is_resume = fdp.ConsumeBool();
+ mActionPipe->set_contents(install_plan);
+
+ TestPrefsInterface prefs(&fdp);
+ BootControlStub boot_control;
+ TestHardwareInterface hardwareInterface;
+ TestProxyResolver proxyResolver;
+ TestHttpFetcher* httpFetcher = new TestHttpFetcher(&proxyResolver, &fdp);
+ bool interactive = fdp.ConsumeBool();
+ unique_ptr<DownloadAction> downloadAction = make_unique<DownloadAction>(
+ &prefs, &boot_control, &hardwareInterface, httpFetcher, interactive);
+
+ downloadAction->set_in_pipe(mActionPipe);
+ TestActionProcessor actionProcessor;
+ downloadAction->SetProcessor(&actionProcessor);
+
+ downloadAction->PerformAction();
+}
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ DownloadActionTest downloadActionFuzzer;
+ downloadActionFuzzer.fuzzDownloadAction(data, size);
+ return 0;
+}