omaha_response_handler_action.cc revision 39910dcd1d68987ccee7c3031dc269233a8490bb
1// 2// Copyright (C) 2011 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/omaha_response_handler_action.h" 18 19#include <string> 20 21#include <base/logging.h> 22#include <base/strings/string_util.h> 23#include <policy/device_policy.h> 24 25#include "update_engine/common/constants.h" 26#include "update_engine/common/hardware_interface.h" 27#include "update_engine/common/prefs_interface.h" 28#include "update_engine/common/utils.h" 29#include "update_engine/connection_manager_interface.h" 30#include "update_engine/omaha_request_params.h" 31#include "update_engine/payload_consumer/delta_performer.h" 32#include "update_engine/payload_state_interface.h" 33 34using std::string; 35 36namespace chromeos_update_engine { 37 38OmahaResponseHandlerAction::OmahaResponseHandlerAction( 39 SystemState* system_state) 40 : OmahaResponseHandlerAction(system_state, 41 constants::kOmahaResponseDeadlineFile) {} 42 43OmahaResponseHandlerAction::OmahaResponseHandlerAction( 44 SystemState* system_state, const string& deadline_file) 45 : system_state_(system_state), 46 got_no_update_response_(false), 47 key_path_(constants::kUpdatePayloadPublicKeyPath), 48 deadline_file_(deadline_file) {} 49 50void OmahaResponseHandlerAction::PerformAction() { 51 CHECK(HasInputObject()); 52 ScopedActionCompleter completer(processor_, this); 53 const OmahaResponse& response = GetInputObject(); 54 if (!response.update_exists) { 55 got_no_update_response_ = true; 56 LOG(INFO) << "There are no updates. Aborting."; 57 return; 58 } 59 60 // All decisions as to which URL should be used have already been done. So, 61 // make the current URL as the download URL. 62 string current_url = system_state_->payload_state()->GetCurrentUrl(); 63 if (current_url.empty()) { 64 // This shouldn't happen as we should always supply the HTTPS backup URL. 65 // Handling this anyway, just in case. 66 LOG(ERROR) << "There are no suitable URLs in the response to use."; 67 completer.set_code(ErrorCode::kOmahaResponseInvalid); 68 return; 69 } 70 71 install_plan_.download_url = current_url; 72 install_plan_.version = response.version; 73 74 OmahaRequestParams* const params = system_state_->request_params(); 75 PayloadStateInterface* const payload_state = system_state_->payload_state(); 76 77 // If we're using p2p to download and there is a local peer, use it. 78 if (payload_state->GetUsingP2PForDownloading() && 79 !payload_state->GetP2PUrl().empty()) { 80 LOG(INFO) << "Replacing URL " << install_plan_.download_url 81 << " with local URL " << payload_state->GetP2PUrl() 82 << " since p2p is enabled."; 83 install_plan_.download_url = payload_state->GetP2PUrl(); 84 payload_state->SetUsingP2PForDownloading(true); 85 } 86 87 // Fill up the other properties based on the response. 88 install_plan_.payload_size = response.size; 89 install_plan_.payload_hash = response.hash; 90 install_plan_.metadata_size = response.metadata_size; 91 install_plan_.metadata_signature = response.metadata_signature; 92 install_plan_.public_key_rsa = response.public_key_rsa; 93 install_plan_.hash_checks_mandatory = AreHashChecksMandatory(response); 94 install_plan_.is_resume = 95 DeltaPerformer::CanResumeUpdate(system_state_->prefs(), response.hash); 96 if (install_plan_.is_resume) { 97 payload_state->UpdateResumed(); 98 } else { 99 payload_state->UpdateRestarted(); 100 LOG_IF(WARNING, !DeltaPerformer::ResetUpdateProgress( 101 system_state_->prefs(), false)) 102 << "Unable to reset the update progress."; 103 LOG_IF(WARNING, !system_state_->prefs()->SetString( 104 kPrefsUpdateCheckResponseHash, response.hash)) 105 << "Unable to save the update check response hash."; 106 } 107 install_plan_.is_full_update = !response.is_delta_payload; 108 109 install_plan_.source_slot = system_state_->boot_control()->GetCurrentSlot(); 110 install_plan_.target_slot = install_plan_.source_slot == 0 ? 1 : 0; 111 112 // The Omaha response doesn't include the channel name for this image, so we 113 // use the download_channel we used during the request to tag the target slot. 114 // This will be used in the next boot to know the channel the image was 115 // downloaded from. 116 string current_channel_key = 117 kPrefsChannelOnSlotPrefix + std::to_string(install_plan_.target_slot); 118 system_state_->prefs()->SetString(current_channel_key, 119 params->download_channel()); 120 121 if (params->to_more_stable_channel() && params->is_powerwash_allowed()) 122 install_plan_.powerwash_required = true; 123 124 TEST_AND_RETURN(HasOutputPipe()); 125 if (HasOutputPipe()) 126 SetOutputObject(install_plan_); 127 LOG(INFO) << "Using this install plan:"; 128 install_plan_.Dump(); 129 130 // Send the deadline data (if any) to Chrome through a file. This is a pretty 131 // hacky solution but should be OK for now. 132 // 133 // TODO(petkov): Re-architect this to avoid communication through a 134 // file. Ideally, we would include this information in D-Bus's GetStatus 135 // method and UpdateStatus signal. A potential issue is that update_engine may 136 // be unresponsive during an update download. 137 if (!deadline_file_.empty()) { 138 utils::WriteFile(deadline_file_.c_str(), 139 response.deadline.data(), 140 response.deadline.size()); 141 chmod(deadline_file_.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 142 } 143 144 completer.set_code(ErrorCode::kSuccess); 145} 146 147bool OmahaResponseHandlerAction::AreHashChecksMandatory( 148 const OmahaResponse& response) { 149 // We sometimes need to waive the hash checks in order to download from 150 // sources that don't provide hashes, such as dev server. 151 // At this point UpdateAttempter::IsAnyUpdateSourceAllowed() has already been 152 // checked, so an unofficial update URL won't get this far unless it's OK to 153 // use without a hash. Additionally, we want to always waive hash checks on 154 // unofficial builds (i.e. dev/test images). 155 // The end result is this: 156 // * Base image: 157 // - Official URLs require a hash. 158 // - Unofficial URLs only get this far if the IsAnyUpdateSourceAllowed() 159 // devmode/debugd checks pass, in which case the hash is waived. 160 // * Dev/test image: 161 // - Any URL is allowed through with no hash checking. 162 if (!system_state_->request_params()->IsUpdateUrlOfficial() || 163 !system_state_->hardware()->IsOfficialBuild()) { 164 // Still do a hash check if a public key is included. 165 if (!response.public_key_rsa.empty()) { 166 // The autoupdate_CatchBadSignatures test checks for this string 167 // in log-files. Keep in sync. 168 LOG(INFO) << "Mandating payload hash checks since Omaha Response " 169 << "for unofficial build includes public RSA key."; 170 return true; 171 } else { 172 LOG(INFO) << "Waiving payload hash checks for unofficial update URL."; 173 return false; 174 } 175 } 176 177 // If we're using p2p, |install_plan_.download_url| may contain a 178 // HTTP URL even if |response.payload_urls| contain only HTTPS URLs. 179 if (!base::StartsWithASCII(install_plan_.download_url, "https://", false)) { 180 LOG(INFO) << "Mandating hash checks since download_url is not HTTPS."; 181 return true; 182 } 183 184 // TODO(jaysri): VALIDATION: For official builds, we currently waive hash 185 // checks for HTTPS until we have rolled out at least once and are confident 186 // nothing breaks. chromium-os:37082 tracks turning this on for HTTPS 187 // eventually. 188 189 // Even if there's a single non-HTTPS URL, make the hash checks as 190 // mandatory because we could be downloading the payload from any URL later 191 // on. It's really hard to do book-keeping based on each byte being 192 // downloaded to see whether we only used HTTPS throughout. 193 for (size_t i = 0; i < response.payload_urls.size(); i++) { 194 if (!base::StartsWithASCII(response.payload_urls[i], "https://", false)) { 195 LOG(INFO) << "Mandating payload hash checks since Omaha response " 196 << "contains non-HTTPS URL(s)"; 197 return true; 198 } 199 } 200 201 LOG(INFO) << "Waiving payload hash checks since Omaha response " 202 << "only has HTTPS URL(s)"; 203 return false; 204} 205 206} // namespace chromeos_update_engine 207