Aditya Wazir | 55fec45 | 2021-08-27 17:47:41 +0530 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (C) 2021 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include <update_engine/common/download_action.h> |
| 18 | #include <update_engine/common/boot_control_stub.h> |
| 19 | #include <update_engine/common/hardware_interface.h> |
| 20 | #include <update_engine/common/http_fetcher.h> |
| 21 | #include <update_engine/common/error_code.h> |
| 22 | #include <update_engine/common/proxy_resolver.h> |
| 23 | #include <update_engine/common/action_processor.h> |
| 24 | #include <string.h> |
| 25 | #include <utils/Log.h> |
| 26 | #include <fuzzer/FuzzedDataProvider.h> |
| 27 | |
| 28 | using namespace chromeos_update_engine; |
| 29 | using namespace std; |
| 30 | |
| 31 | constexpr size_t kSizeMin = 1; |
| 32 | constexpr size_t kSizeMax = 1000; |
| 33 | constexpr size_t kHashSize = 32; |
| 34 | constexpr size_t kStringMaxLength = 20; |
| 35 | const string kDownloadUrl = "http://fake_url.invalid"; |
| 36 | const string kSourcePath = "/dev/zero"; |
| 37 | const string kTargetPath = "/dev/null"; |
| 38 | |
| 39 | class TestPrefsInterface : public PrefsInterface { |
| 40 | public: |
| 41 | TestPrefsInterface(FuzzedDataProvider* fdp) : mFdp(fdp) { |
| 42 | mMetadataSize = mFdp->ConsumeIntegralInRange<int64_t>(kSizeMin, kSizeMax); |
| 43 | mSignatureSize = mFdp->ConsumeIntegralInRange<int64_t>(kSizeMin, kSizeMax); |
| 44 | }; |
| 45 | |
| 46 | bool GetString(std::string_view key, std::string* value) const { |
| 47 | if (key == "manifest-bytes") { |
| 48 | *value = mFdp->ConsumeRandomLengthString(mMetadataSize + mSignatureSize); |
| 49 | return true; |
| 50 | } |
| 51 | *value = ""; |
| 52 | return false; |
| 53 | }; |
| 54 | |
| 55 | bool SetString(std::string_view /*key*/, std::string_view /*value*/) { |
| 56 | return true; |
| 57 | }; |
| 58 | |
| 59 | bool GetInt64(std::string_view key, int64_t* value) const { |
| 60 | if (key == "manifest-metadata-size") { |
| 61 | *value = mMetadataSize; |
| 62 | return true; |
| 63 | } |
| 64 | if (key == "manifest-signature-size") { |
| 65 | *value = mSignatureSize; |
| 66 | return true; |
| 67 | } |
| 68 | *value = 0; |
| 69 | return false; |
| 70 | } |
| 71 | |
| 72 | bool SetInt64(std::string_view /*key*/, const int64_t /*value*/) { |
| 73 | return true; |
| 74 | } |
| 75 | |
| 76 | bool GetBoolean(std::string_view /*key*/, bool* value) const { |
| 77 | *value = true; |
| 78 | return true; |
| 79 | } |
| 80 | |
| 81 | bool SetBoolean(std::string_view /*key*/, const bool /*value*/) { |
| 82 | return true; |
| 83 | } |
| 84 | |
| 85 | bool Exists(std::string_view /*key*/) const { return true; } |
| 86 | |
| 87 | bool Delete(std::string_view /*key*/) { return true; } |
| 88 | |
| 89 | bool Delete(std::string_view /*pref_key*/, |
| 90 | const std::vector<std::string>& /*nss*/) { |
| 91 | return true; |
| 92 | } |
| 93 | |
| 94 | bool GetSubKeys(std::string_view /*ns*/, |
| 95 | std::vector<std::string>* keys) const { |
| 96 | keys->push_back(""); |
| 97 | return true; |
| 98 | } |
| 99 | |
| 100 | void AddObserver(std::string_view /*key*/, ObserverInterface* /*observer*/) {} |
| 101 | |
| 102 | void RemoveObserver(std::string_view /*key*/, |
| 103 | ObserverInterface* /*observer*/) {} |
| 104 | |
| 105 | private: |
| 106 | FuzzedDataProvider* mFdp; |
| 107 | int64_t mMetadataSize; |
| 108 | int64_t mSignatureSize; |
| 109 | }; |
| 110 | |
| 111 | class TestHardwareInterface : public HardwareInterface { |
| 112 | public: |
| 113 | bool IsOfficialBuild() const { return true; }; |
| 114 | |
| 115 | bool IsNormalBootMode() const { return true; }; |
| 116 | |
| 117 | bool AreDevFeaturesEnabled() const { return true; }; |
| 118 | |
| 119 | bool IsOOBEEnabled() const { return true; }; |
| 120 | |
| 121 | bool IsOOBEComplete(base::Time* /*out_time_of_oobe*/) const { return true; }; |
| 122 | |
| 123 | string GetHardwareClass() const { return ""; }; |
| 124 | |
| 125 | string GetDeviceRequisition() const { return ""; }; |
| 126 | |
| 127 | int32_t GetMinKernelKeyVersion() const { return 0; }; |
| 128 | |
| 129 | int32_t GetMinFirmwareKeyVersion() const { return 0; }; |
| 130 | |
| 131 | int32_t GetMaxFirmwareKeyRollforward() const { return 0; }; |
| 132 | |
| 133 | bool SetMaxFirmwareKeyRollforward(int32_t /*firmware_max_rollforward*/) { |
| 134 | return true; |
| 135 | }; |
| 136 | |
| 137 | bool SetMaxKernelKeyRollforward(int32_t /*kernel_max_rollforward*/) { |
| 138 | return true; |
| 139 | }; |
| 140 | |
| 141 | int32_t GetPowerwashCount() const { return 0; }; |
| 142 | |
| 143 | bool SchedulePowerwash(bool /*save_rollback_data*/) { return true; }; |
| 144 | |
| 145 | bool CancelPowerwash() { return true; }; |
| 146 | |
| 147 | bool GetNonVolatileDirectory(base::FilePath* path) const { |
| 148 | base::FilePath local_path(constants::kNonVolatileDirectory); |
| 149 | *path = local_path; |
| 150 | return true; |
| 151 | }; |
| 152 | |
| 153 | bool GetPowerwashSafeDirectory(base::FilePath* /*path*/) const { |
| 154 | return false; |
| 155 | }; |
| 156 | |
| 157 | int64_t GetBuildTimestamp() const { return 0; }; |
| 158 | |
| 159 | bool AllowDowngrade() const { return true; }; |
| 160 | |
| 161 | bool GetFirstActiveOmahaPingSent() const { return true; }; |
| 162 | |
| 163 | bool SetFirstActiveOmahaPingSent() { return true; }; |
| 164 | |
| 165 | void SetWarmReset(bool /*warm_reset*/){}; |
| 166 | |
| 167 | void SetVbmetaDigestForInactiveSlot(bool /*reset*/){}; |
| 168 | |
| 169 | string GetVersionForLogging(const string& /*partition_name*/) const { |
| 170 | return ""; |
| 171 | }; |
| 172 | |
| 173 | ErrorCode IsPartitionUpdateValid(const string& /*partition_name*/, |
| 174 | const string& /*new_version*/) const { |
| 175 | return ErrorCode::kSuccess; |
| 176 | }; |
| 177 | |
| 178 | const char* GetPartitionMountOptions(const string& /*partition_name*/) const { |
| 179 | return ""; |
| 180 | }; |
| 181 | }; |
| 182 | |
| 183 | class TestProxyResolver : public ProxyResolver { |
| 184 | public: |
| 185 | virtual ~TestProxyResolver() {} |
| 186 | |
| 187 | ProxyRequestId GetProxiesForUrl(const string& /*url*/, |
| 188 | const ProxiesResolvedFn& /*callback*/) { |
| 189 | return 0; |
| 190 | }; |
| 191 | |
| 192 | bool CancelProxyRequest(ProxyRequestId /*request*/) { return true; }; |
| 193 | }; |
| 194 | |
| 195 | class TestHttpFetcher : public HttpFetcher { |
| 196 | public: |
| 197 | TestHttpFetcher(ProxyResolver* proxy_resolver, FuzzedDataProvider* fdp) |
| 198 | : HttpFetcher(proxy_resolver), mFdp(fdp){}; |
| 199 | virtual ~TestHttpFetcher() {} |
| 200 | |
| 201 | void SetOffset(off_t /*offset*/) {} |
| 202 | |
| 203 | void SetLength(size_t /*length*/) {} |
| 204 | void UnsetLength() {} |
| 205 | |
| 206 | void BeginTransfer(const string& /*url*/) { |
| 207 | if (mFdp->remaining_bytes() > 0) { |
| 208 | size_t maxSize = mFdp->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax); |
| 209 | vector<uint8_t> data = mFdp->ConsumeBytes<uint8_t>(maxSize); |
| 210 | delegate()->ReceivedBytes(this, data.data(), data.size()); |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | void TerminateTransfer() {} |
| 215 | |
| 216 | void SetHeader(const string& /*header_name*/, |
| 217 | const string& /*header_value*/) {} |
| 218 | |
| 219 | bool GetHeader(const string& /*header_name*/, string* header_value) const { |
| 220 | *header_value = ""; |
| 221 | return true; |
| 222 | } |
| 223 | |
| 224 | void Pause() {} |
| 225 | |
| 226 | void Unpause() {} |
| 227 | |
| 228 | void set_idle_seconds(int32_t /*seconds*/) {} |
| 229 | void set_retry_seconds(int32_t /*seconds*/) {} |
| 230 | |
| 231 | void set_low_speed_limit(int32_t /*low_speed_bps*/, |
| 232 | int32_t /*low_speed_sec*/) {} |
| 233 | |
| 234 | void set_connect_timeout(int32_t /*connect_timeout_seconds*/) {} |
| 235 | |
| 236 | void set_max_retry_count(int32_t /*max_retry_count*/) {} |
| 237 | |
| 238 | size_t GetBytesDownloaded() { return 0; } |
| 239 | |
| 240 | private: |
| 241 | FuzzedDataProvider* mFdp; |
| 242 | }; |
| 243 | |
| 244 | class TestActionProcessor : public ActionProcessor { |
| 245 | public: |
| 246 | void StartProcessing() {} |
| 247 | |
| 248 | void EnqueueAction(unique_ptr<AbstractAction> /*action*/){}; |
| 249 | |
| 250 | void ActionComplete(AbstractAction* /*actionptr*/, ErrorCode /*code*/){}; |
| 251 | }; |
| 252 | |
| 253 | class chromeos_update_engine::DownloadActionTest { |
| 254 | public: |
| 255 | DownloadActionTest() : mActionPipe(new ActionPipe<InstallPlan>()) {} |
| 256 | ~DownloadActionTest() { mActionPipe = nullptr; } |
| 257 | |
| 258 | void fuzzDownloadAction(const uint8_t* data, size_t size); |
| 259 | |
| 260 | private: |
| 261 | shared_ptr<ActionPipe<InstallPlan>> mActionPipe = nullptr; |
| 262 | }; |
| 263 | |
| 264 | void DownloadActionTest::fuzzDownloadAction(const uint8_t* data, size_t size) { |
| 265 | FuzzedDataProvider fdp = FuzzedDataProvider(data, size); |
| 266 | |
| 267 | InstallPlan install_plan; |
| 268 | install_plan.download_url = kDownloadUrl; |
| 269 | install_plan.version = fdp.ConsumeRandomLengthString(kStringMaxLength); |
| 270 | install_plan.target_slot = fdp.ConsumeBool() ? 0 : 1; |
| 271 | install_plan.hash_checks_mandatory = fdp.ConsumeBool(); |
| 272 | InstallPlan::Partition partition; |
| 273 | partition.name = fdp.ConsumeRandomLengthString(kStringMaxLength); |
| 274 | partition.source_path = kSourcePath; |
| 275 | partition.source_size = fdp.ConsumeIntegralInRange(kSizeMin, kSizeMax); |
| 276 | partition.target_path = kTargetPath; |
| 277 | partition.target_size = fdp.ConsumeIntegralInRange(kSizeMin, kSizeMax); |
| 278 | install_plan.partitions.push_back(partition); |
| 279 | InstallPlan::Payload payload; |
| 280 | payload.payload_urls.emplace_back(kDownloadUrl); |
| 281 | payload.size = fdp.ConsumeIntegralInRange(kSizeMin, kSizeMax); |
| 282 | payload.metadata_size = |
| 283 | fdp.ConsumeIntegralInRange<uint64_t>(kSizeMin, kSizeMax), |
| 284 | payload.hash = fdp.ConsumeBytes<uint8_t>(kHashSize), |
| 285 | payload.already_applied = fdp.ConsumeBool(); |
| 286 | install_plan.payloads.push_back(payload); |
| 287 | install_plan.is_resume = fdp.ConsumeBool(); |
| 288 | mActionPipe->set_contents(install_plan); |
| 289 | |
| 290 | TestPrefsInterface prefs(&fdp); |
| 291 | BootControlStub boot_control; |
| 292 | TestHardwareInterface hardwareInterface; |
| 293 | TestProxyResolver proxyResolver; |
| 294 | TestHttpFetcher* httpFetcher = new TestHttpFetcher(&proxyResolver, &fdp); |
| 295 | bool interactive = fdp.ConsumeBool(); |
| 296 | unique_ptr<DownloadAction> downloadAction = make_unique<DownloadAction>( |
| 297 | &prefs, &boot_control, &hardwareInterface, httpFetcher, interactive); |
| 298 | |
| 299 | downloadAction->set_in_pipe(mActionPipe); |
| 300 | TestActionProcessor actionProcessor; |
| 301 | downloadAction->SetProcessor(&actionProcessor); |
| 302 | |
| 303 | downloadAction->PerformAction(); |
| 304 | } |
| 305 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
| 306 | DownloadActionTest downloadActionFuzzer; |
| 307 | downloadActionFuzzer.fuzzDownloadAction(data, size); |
| 308 | return 0; |
| 309 | } |