aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAditya Wazir <aditya.wazir@ittiam.com>2022-04-05 01:28:43 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2022-04-05 01:28:43 +0000
commitb0bda4937f4ce51a3014ec6c5e72d23220d927f8 (patch)
treecc0a00cbb0a4cb515702f9ebf4467d4ad6e1244e
parent9ffb6c0508ad916c60b861dbdb1644ffdb3ec396 (diff)
parent55fec45931f4830ff047b42ef678e0178cca28fc (diff)
downloadupdate_engine-b0bda4937f4ce51a3014ec6c5e72d23220d927f8.tar.gz
Added updateEngine_downloadAction_fuzzer am: 55fec45931
Original change: https://android-review.googlesource.com/c/platform/system/update_engine/+/1810483 Change-Id: Ie91c0da6e4739cfb8bdef63378590974654ab8f6 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--fuzzer/Android.bp68
-rw-r--r--fuzzer/README.md57
-rw-r--r--fuzzer/updateEngine_downloadAction_fuzzer.cpp309
3 files changed, 434 insertions, 0 deletions
diff --git a/fuzzer/Android.bp b/fuzzer/Android.bp
new file mode 100644
index 00000000..04cf9db8
--- /dev/null
+++ b/fuzzer/Android.bp
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+cc_defaults {
+ name: "updateEngineFuzzer_defaults",
+ static_libs: [
+ "libupdate_engine_android",
+ "libavb",
+ "libavb_user",
+ "gkiprops",
+ "libpayload_consumer",
+ "libupdate_engine_boot_control",
+ "PlatformProperties",
+ ],
+ shared_libs: [
+ "apex_aidl_interface-cpp",
+ "libandroid_net",
+ "libbase",
+ "libbinder",
+ "libbinderwrapper",
+ "libbootloader_message",
+ "libbrillo-binder",
+ "libcurl",
+ "libcutils",
+ "libupdate_engine_stable-V1-cpp",
+ "liblog",
+ "libssl",
+ "libstatslog",
+ "libutils",
+ "libbrillo-stream",
+ "libbrillo",
+ "libchrome",
+ ],
+ include_dirs: ["system"],
+ fuzz_config: {
+ cc: [
+ "android-ota@google.com",
+ ],
+ componentid: 155276,
+ },
+}
+
+cc_fuzz {
+ name: "updateEngine_downloadAction_fuzzer",
+ srcs: [
+ "updateEngine_downloadAction_fuzzer.cpp",
+ ],
+ defaults: [
+ "updateEngineFuzzer_defaults",
+ "libupdate_engine_boot_control_exports",
+ "libpayload_consumer_exports",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+}
diff --git a/fuzzer/README.md b/fuzzer/README.md
new file mode 100644
index 00000000..a54dd31a
--- /dev/null
+++ b/fuzzer/README.md
@@ -0,0 +1,57 @@
+# Fuzzer for libupdate_engine_android
+## Table of contents
++ [updateEngine_downloadAction_fuzzer](#updateEngine_downloadAction_fuzzer)
+
+# <a name="updateEngine_downloadAction_fuzzer"></a> Fuzzer for download_action
+
+## Plugin Design Considerations
+The fuzzer plugin for libupdate_engine_android is designed based on the understanding of the library
+ and tries to achieve the following:
+
+##### 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.
+
+libupdate_engine_android supports the following parameters:
+1. Version (parameter name: `version`)
+2. Already_Applied (parameter name: `already_applied`)
+3. Is_Resume (parameter name: `is_resume`)
+4. Interactive (parameter name: `interactive`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `version` | `String` | Value obtained from FuzzedDataProvider|
+| `already_applied` | `true` or `false` | Value obtained from FuzzedDataProvider|
+| `is_resume` | `true` or `false` | Value obtained from FuzzedDataProvider|
+| `interactive` | `true` or `false` | Value obtained from FuzzedDataProvider|
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the libupdate_engine_android module.
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build updateEngine_downloadAction_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) updateEngine_downloadAction_fuzzer
+```
+#### Steps to run
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/${TARGET_ARCH}/updateEngine_downloadAction_fuzzer/updateEngine_downloadAction_fuzzer
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/fuzzer/updateEngine_downloadAction_fuzzer.cpp b/fuzzer/updateEngine_downloadAction_fuzzer.cpp
new file mode 100644
index 00000000..e8772733
--- /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;
+}