blob: e8772733e6b849da6c5a496fcbca7f8875fcc761 [file] [log] [blame]
/*
* 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;
}