blob: f2ed85f61d80dab92e4136a500df453b2c5463e5 [file] [log] [blame]
Mike Frysinger8155d082012-04-06 15:23:18 -04001// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Andrew de los Reyes09e56d62010-04-23 13:45:53 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "update_engine/delta_performer.h"
Darin Petkovd7061ab2010-10-06 14:37:09 -07006
Andrew de los Reyes09e56d62010-04-23 13:45:53 -07007#include <endian.h>
8#include <errno.h>
Darin Petkovd7061ab2010-10-06 14:37:09 -07009
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070010#include <algorithm>
11#include <cstring>
Ben Chan02f7c1d2014-10-18 15:18:02 -070012#include <memory>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070013#include <string>
14#include <vector>
15
Ben Chan06c76a42014-09-05 08:21:06 -070016#include <base/files/file_util.h>
Alex Deymo161c4a12014-05-16 15:56:21 -070017#include <base/format_macros.h>
Alex Vakulenko75039d72014-03-25 12:36:28 -070018#include <base/strings/string_util.h>
19#include <base/strings/stringprintf.h>
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070020#include <google/protobuf/repeated_field.h>
21
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070022#include "update_engine/bzip_extent_writer.h"
Jay Srinivasand29695d2013-04-08 15:08:05 -070023#include "update_engine/constants.h"
Andrew de los Reyes353777c2010-10-08 10:34:30 -070024#include "update_engine/extent_ranges.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070025#include "update_engine/extent_writer.h"
David Zeuthene7f89172013-10-31 10:21:04 -070026#include "update_engine/hardware_interface.h"
Alex Deymo161c4a12014-05-16 15:56:21 -070027#include "update_engine/payload_constants.h"
Jay Srinivasan55f50c22013-01-10 19:24:35 -080028#include "update_engine/payload_state_interface.h"
Alex Deymo923d8fa2014-07-15 17:58:51 -070029#include "update_engine/payload_verifier.h"
Darin Petkov73058b42010-10-06 16:32:19 -070030#include "update_engine/prefs_interface.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070031#include "update_engine/subprocess.h"
Darin Petkov9c0baf82010-10-07 13:44:48 -070032#include "update_engine/terminator.h"
Jay Srinivasan1c0fe792013-03-28 16:45:25 -070033#include "update_engine/update_attempter.h"
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070034
Alex Deymo161c4a12014-05-16 15:56:21 -070035using google::protobuf::RepeatedPtrField;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070036using std::min;
37using std::string;
Ben Chan02f7c1d2014-10-18 15:18:02 -070038using std::unique_ptr;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070039using std::vector;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070040
41namespace chromeos_update_engine {
42
Jay Srinivasanf4318702012-09-24 11:56:24 -070043const uint64_t DeltaPerformer::kDeltaVersionSize = 8;
44const uint64_t DeltaPerformer::kDeltaManifestSizeSize = 8;
Don Garrett4d039442013-10-28 18:40:06 -070045const uint64_t DeltaPerformer::kSupportedMajorPayloadVersion = 1;
Don Garrettb8dd1d92013-11-22 17:40:02 -080046const uint64_t DeltaPerformer::kSupportedMinorPayloadVersion = 1;
47const uint64_t DeltaPerformer::kFullPayloadMinorVersion = 0;
Don Garrett4d039442013-10-28 18:40:06 -070048
Darin Petkovabc7bc02011-02-23 14:39:43 -080049const char DeltaPerformer::kUpdatePayloadPublicKeyPath[] =
50 "/usr/share/update_engine/update-payload-key.pub.pem";
Gilad Arnold8a86fa52013-01-15 12:35:05 -080051const unsigned DeltaPerformer::kProgressLogMaxChunks = 10;
52const unsigned DeltaPerformer::kProgressLogTimeoutSeconds = 30;
53const unsigned DeltaPerformer::kProgressDownloadWeight = 50;
54const unsigned DeltaPerformer::kProgressOperationsWeight = 50;
Darin Petkovabc7bc02011-02-23 14:39:43 -080055
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070056namespace {
Darin Petkov73058b42010-10-06 16:32:19 -070057const int kUpdateStateOperationInvalid = -1;
Darin Petkov61426142010-10-08 11:04:55 -070058const int kMaxResumedUpdateFailures = 10;
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -070059// Opens path for read/write, put the fd into *fd. On success returns true
60// and sets *err to 0. On failure, returns false and sets *err to errno.
61bool OpenFile(const char* path, int* fd, int* err) {
62 if (*fd != -1) {
63 LOG(ERROR) << "Can't open(" << path << "), *fd != -1 (it's " << *fd << ")";
64 *err = EINVAL;
65 return false;
66 }
67 *fd = open(path, O_RDWR, 000);
68 if (*fd < 0) {
69 *err = errno;
70 PLOG(ERROR) << "Unable to open file " << path;
71 return false;
72 }
73 *err = 0;
74 return true;
75}
76
Alex Vakulenkod2779df2014-06-16 13:19:00 -070077} // namespace
Andrew de los Reyes09e56d62010-04-23 13:45:53 -070078
Gilad Arnold8a86fa52013-01-15 12:35:05 -080079
80// Computes the ratio of |part| and |total|, scaled to |norm|, using integer
81// arithmetic.
82static uint64_t IntRatio(uint64_t part, uint64_t total, uint64_t norm) {
83 return part * norm / total;
84}
85
86void DeltaPerformer::LogProgress(const char* message_prefix) {
87 // Format operations total count and percentage.
88 string total_operations_str("?");
89 string completed_percentage_str("");
90 if (num_total_operations_) {
Alex Vakulenko75039d72014-03-25 12:36:28 -070091 total_operations_str = base::StringPrintf("%zu", num_total_operations_);
Gilad Arnold8a86fa52013-01-15 12:35:05 -080092 // Upcasting to 64-bit to avoid overflow, back to size_t for formatting.
93 completed_percentage_str =
Alex Vakulenko75039d72014-03-25 12:36:28 -070094 base::StringPrintf(" (%" PRIu64 "%%)",
Gilad Arnold8a86fa52013-01-15 12:35:05 -080095 IntRatio(next_operation_num_, num_total_operations_,
96 100));
97 }
98
99 // Format download total count and percentage.
100 size_t payload_size = install_plan_->payload_size;
101 string payload_size_str("?");
102 string downloaded_percentage_str("");
103 if (payload_size) {
Alex Vakulenko75039d72014-03-25 12:36:28 -0700104 payload_size_str = base::StringPrintf("%zu", payload_size);
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800105 // Upcasting to 64-bit to avoid overflow, back to size_t for formatting.
106 downloaded_percentage_str =
Alex Vakulenko75039d72014-03-25 12:36:28 -0700107 base::StringPrintf(" (%" PRIu64 "%%)",
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800108 IntRatio(total_bytes_received_, payload_size, 100));
109 }
110
111 LOG(INFO) << (message_prefix ? message_prefix : "") << next_operation_num_
112 << "/" << total_operations_str << " operations"
113 << completed_percentage_str << ", " << total_bytes_received_
114 << "/" << payload_size_str << " bytes downloaded"
115 << downloaded_percentage_str << ", overall progress "
116 << overall_progress_ << "%";
117}
118
119void DeltaPerformer::UpdateOverallProgress(bool force_log,
120 const char* message_prefix) {
121 // Compute our download and overall progress.
122 unsigned new_overall_progress = 0;
123 COMPILE_ASSERT(kProgressDownloadWeight + kProgressOperationsWeight == 100,
124 progress_weight_dont_add_up);
125 // Only consider download progress if its total size is known; otherwise
126 // adjust the operations weight to compensate for the absence of download
127 // progress. Also, make sure to cap the download portion at
128 // kProgressDownloadWeight, in case we end up downloading more than we
129 // initially expected (this indicates a problem, but could generally happen).
130 // TODO(garnold) the correction of operations weight when we do not have the
131 // total payload size, as well as the conditional guard below, should both be
132 // eliminated once we ensure that the payload_size in the install plan is
133 // always given and is non-zero. This currently isn't the case during unit
134 // tests (see chromium-os:37969).
135 size_t payload_size = install_plan_->payload_size;
136 unsigned actual_operations_weight = kProgressOperationsWeight;
137 if (payload_size)
138 new_overall_progress += min(
139 static_cast<unsigned>(IntRatio(total_bytes_received_, payload_size,
140 kProgressDownloadWeight)),
141 kProgressDownloadWeight);
142 else
143 actual_operations_weight += kProgressDownloadWeight;
144
145 // Only add completed operations if their total number is known; we definitely
146 // expect an update to have at least one operation, so the expectation is that
147 // this will eventually reach |actual_operations_weight|.
148 if (num_total_operations_)
149 new_overall_progress += IntRatio(next_operation_num_, num_total_operations_,
150 actual_operations_weight);
151
152 // Progress ratio cannot recede, unless our assumptions about the total
153 // payload size, total number of operations, or the monotonicity of progress
154 // is breached.
155 if (new_overall_progress < overall_progress_) {
156 LOG(WARNING) << "progress counter receded from " << overall_progress_
157 << "% down to " << new_overall_progress << "%; this is a bug";
158 force_log = true;
159 }
160 overall_progress_ = new_overall_progress;
161
162 // Update chunk index, log as needed: if forced by called, or we completed a
163 // progress chunk, or a timeout has expired.
164 base::Time curr_time = base::Time::Now();
165 unsigned curr_progress_chunk =
166 overall_progress_ * kProgressLogMaxChunks / 100;
167 if (force_log || curr_progress_chunk > last_progress_chunk_ ||
168 curr_time > forced_progress_log_time_) {
169 forced_progress_log_time_ = curr_time + forced_progress_log_wait_;
170 LogProgress(message_prefix);
171 }
172 last_progress_chunk_ = curr_progress_chunk;
173}
174
175
Gilad Arnoldfe133932014-01-14 12:25:50 -0800176size_t DeltaPerformer::CopyDataToBuffer(const char** bytes_p, size_t* count_p,
177 size_t max) {
178 const size_t count = *count_p;
179 if (!count)
180 return 0; // Special case shortcut.
181 size_t read_len = std::min(count, max - buffer_.size());
182 const char* bytes_start = *bytes_p;
183 const char* bytes_end = bytes_start + read_len;
184 buffer_.insert(buffer_.end(), bytes_start, bytes_end);
185 *bytes_p = bytes_end;
186 *count_p = count - read_len;
187 return read_len;
188}
189
190
191bool DeltaPerformer::HandleOpResult(bool op_result, const char* op_type_name,
192 ErrorCode* error) {
193 if (op_result)
194 return true;
195
196 LOG(ERROR) << "Failed to perform " << op_type_name << " operation "
197 << next_operation_num_;
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700198 *error = ErrorCode::kDownloadOperationExecutionError;
Gilad Arnoldfe133932014-01-14 12:25:50 -0800199 return false;
200}
201
202
Andrew de los Reyes353777c2010-10-08 10:34:30 -0700203// Returns true if |op| is idempotent -- i.e., if we can interrupt it and repeat
204// it safely. Returns false otherwise.
205bool DeltaPerformer::IsIdempotentOperation(
206 const DeltaArchiveManifest_InstallOperation& op) {
207 if (op.src_extents_size() == 0) {
208 return true;
209 }
Darin Petkov9fa7ec52010-10-18 11:45:23 -0700210 // When in doubt, it's safe to declare an op non-idempotent. Note that we
211 // could detect other types of idempotent operations here such as a MOVE that
212 // moves blocks onto themselves. However, we rely on the server to not send
213 // such operations at all.
Andrew de los Reyes353777c2010-10-08 10:34:30 -0700214 ExtentRanges src_ranges;
215 src_ranges.AddRepeatedExtents(op.src_extents());
216 const uint64_t block_count = src_ranges.blocks();
217 src_ranges.SubtractRepeatedExtents(op.dst_extents());
218 return block_count == src_ranges.blocks();
219}
220
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700221int DeltaPerformer::Open(const char* path, int flags, mode_t mode) {
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700222 int err;
223 if (OpenFile(path, &fd_, &err))
224 path_ = path;
225 return -err;
226}
227
228bool DeltaPerformer::OpenKernel(const char* kernel_path) {
229 int err;
230 bool success = OpenFile(kernel_path, &kernel_fd_, &err);
231 if (success)
232 kernel_path_ = kernel_path;
233 return success;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700234}
235
236int DeltaPerformer::Close() {
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700237 int err = 0;
238 if (close(kernel_fd_) == -1) {
239 err = errno;
240 PLOG(ERROR) << "Unable to close kernel fd:";
241 }
242 if (close(fd_) == -1) {
243 err = errno;
244 PLOG(ERROR) << "Unable to close rootfs fd:";
245 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700246 LOG_IF(ERROR, !hash_calculator_.Finalize()) << "Unable to finalize the hash.";
Darin Petkov934bb412010-11-18 11:21:35 -0800247 fd_ = -2; // Set to invalid so that calls to Open() will fail.
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700248 path_ = "";
Darin Petkov934bb412010-11-18 11:21:35 -0800249 if (!buffer_.empty()) {
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700250 LOG(INFO) << "Discarding " << buffer_.size() << " unused downloaded bytes";
251 if (err >= 0)
Darin Petkov934bb412010-11-18 11:21:35 -0800252 err = 1;
Darin Petkov934bb412010-11-18 11:21:35 -0800253 }
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700254 return -err;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700255}
256
Andrew de los Reyes89f17be2010-10-22 13:39:09 -0700257namespace {
258
259void LogPartitionInfoHash(const PartitionInfo& info, const string& tag) {
260 string sha256;
261 if (OmahaHashCalculator::Base64Encode(info.hash().data(),
262 info.hash().size(),
263 &sha256)) {
Darin Petkov3aefa862010-12-07 14:45:00 -0800264 LOG(INFO) << "PartitionInfo " << tag << " sha256: " << sha256
265 << " size: " << info.size();
Andrew de los Reyes89f17be2010-10-22 13:39:09 -0700266 } else {
267 LOG(ERROR) << "Base64Encode failed for tag: " << tag;
268 }
269}
270
271void LogPartitionInfo(const DeltaArchiveManifest& manifest) {
272 if (manifest.has_old_kernel_info())
273 LogPartitionInfoHash(manifest.old_kernel_info(), "old_kernel_info");
274 if (manifest.has_old_rootfs_info())
275 LogPartitionInfoHash(manifest.old_rootfs_info(), "old_rootfs_info");
276 if (manifest.has_new_kernel_info())
277 LogPartitionInfoHash(manifest.new_kernel_info(), "new_kernel_info");
278 if (manifest.has_new_rootfs_info())
279 LogPartitionInfoHash(manifest.new_rootfs_info(), "new_rootfs_info");
280}
281
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700282} // namespace
Andrew de los Reyes89f17be2010-10-22 13:39:09 -0700283
Don Garrett4d039442013-10-28 18:40:06 -0700284uint64_t DeltaPerformer::GetVersionOffset() {
Gilad Arnolddaa27402014-01-23 11:56:17 -0800285 // Manifest size is stored right after the magic string and the version.
286 return strlen(kDeltaMagic);
Don Garrett4d039442013-10-28 18:40:06 -0700287}
288
Jay Srinivasanf4318702012-09-24 11:56:24 -0700289uint64_t DeltaPerformer::GetManifestSizeOffset() {
Gilad Arnolddaa27402014-01-23 11:56:17 -0800290 // Manifest size is stored right after the magic string and the version.
291 return strlen(kDeltaMagic) + kDeltaVersionSize;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700292}
293
294uint64_t DeltaPerformer::GetManifestOffset() {
Gilad Arnolddaa27402014-01-23 11:56:17 -0800295 // Actual manifest begins right after the manifest size field.
296 return GetManifestSizeOffset() + kDeltaManifestSizeSize;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700297}
298
Gilad Arnoldfe133932014-01-14 12:25:50 -0800299uint64_t DeltaPerformer::GetMetadataSize() const {
Gilad Arnolddaa27402014-01-23 11:56:17 -0800300 return metadata_size_;
301}
302
303bool DeltaPerformer::GetManifest(DeltaArchiveManifest* out_manifest_p) const {
304 if (!manifest_parsed_)
305 return false;
306 *out_manifest_p = manifest_;
307 return true;
Gilad Arnoldfe133932014-01-14 12:25:50 -0800308}
309
Jay Srinivasanf4318702012-09-24 11:56:24 -0700310
Darin Petkov9574f7e2011-01-13 10:48:12 -0800311DeltaPerformer::MetadataParseResult DeltaPerformer::ParsePayloadMetadata(
312 const std::vector<char>& payload,
David Zeuthena99981f2013-04-29 13:42:47 -0700313 ErrorCode* error) {
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700314 *error = ErrorCode::kSuccess;
Jay Srinivasanf4318702012-09-24 11:56:24 -0700315 const uint64_t manifest_offset = GetManifestOffset();
Gilad Arnoldfe133932014-01-14 12:25:50 -0800316 uint64_t manifest_size = (metadata_size_ ?
317 metadata_size_ - manifest_offset : 0);
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700318
Gilad Arnoldfe133932014-01-14 12:25:50 -0800319 if (!manifest_size) {
320 // Ensure we have data to cover the payload header.
321 if (payload.size() < manifest_offset)
322 return kMetadataParseInsufficientData;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700323
Gilad Arnoldfe133932014-01-14 12:25:50 -0800324 // Validate the magic string.
325 if (memcmp(payload.data(), kDeltaMagic, strlen(kDeltaMagic)) != 0) {
326 LOG(ERROR) << "Bad payload format -- invalid delta magic.";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700327 *error = ErrorCode::kDownloadInvalidMetadataMagicString;
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800328 return kMetadataParseError;
329 }
Gilad Arnoldfe133932014-01-14 12:25:50 -0800330
331 // Extract the payload version from the metadata.
332 uint64_t major_payload_version;
333 COMPILE_ASSERT(sizeof(major_payload_version) == kDeltaVersionSize,
334 major_payload_version_size_mismatch);
335 memcpy(&major_payload_version,
336 &payload[GetVersionOffset()],
337 kDeltaVersionSize);
338 // switch big endian to host
339 major_payload_version = be64toh(major_payload_version);
340
341 if (major_payload_version != kSupportedMajorPayloadVersion) {
342 LOG(ERROR) << "Bad payload format -- unsupported payload version: "
343 << major_payload_version;
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700344 *error = ErrorCode::kUnsupportedMajorPayloadVersion;
Gilad Arnoldfe133932014-01-14 12:25:50 -0800345 return kMetadataParseError;
346 }
347
348 // Next, parse the manifest size.
349 COMPILE_ASSERT(sizeof(manifest_size) == kDeltaManifestSizeSize,
350 manifest_size_size_mismatch);
351 memcpy(&manifest_size,
352 &payload[GetManifestSizeOffset()],
353 kDeltaManifestSizeSize);
354 manifest_size = be64toh(manifest_size); // switch big endian to host
355
356 // If the metadata size is present in install plan, check for it immediately
357 // even before waiting for that many number of bytes to be downloaded in the
358 // payload. This will prevent any attack which relies on us downloading data
359 // beyond the expected metadata size.
360 metadata_size_ = manifest_offset + manifest_size;
361 if (install_plan_->hash_checks_mandatory) {
362 if (install_plan_->metadata_size != metadata_size_) {
363 LOG(ERROR) << "Mandatory metadata size in Omaha response ("
364 << install_plan_->metadata_size
365 << ") is missing/incorrect, actual = " << metadata_size_;
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700366 *error = ErrorCode::kDownloadInvalidMetadataSize;
Gilad Arnoldfe133932014-01-14 12:25:50 -0800367 return kMetadataParseError;
368 }
369 }
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700370 }
371
372 // Now that we have validated the metadata size, we should wait for the full
373 // metadata to be read in before we can parse it.
Gilad Arnoldfe133932014-01-14 12:25:50 -0800374 if (payload.size() < metadata_size_)
Darin Petkov9574f7e2011-01-13 10:48:12 -0800375 return kMetadataParseInsufficientData;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700376
377 // Log whether we validated the size or simply trusting what's in the payload
Jay Srinivasanf4318702012-09-24 11:56:24 -0700378 // here. This is logged here (after we received the full metadata data) so
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700379 // that we just log once (instead of logging n times) if it takes n
380 // DeltaPerformer::Write calls to download the full manifest.
Gilad Arnoldfe133932014-01-14 12:25:50 -0800381 if (install_plan_->metadata_size == metadata_size_) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700382 LOG(INFO) << "Manifest size in payload matches expected value from Omaha";
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800383 } else {
384 // For mandatory-cases, we'd have already returned a kMetadataParseError
385 // above. We'll be here only for non-mandatory cases. Just send a UMA stat.
386 LOG(WARNING) << "Ignoring missing/incorrect metadata size ("
387 << install_plan_->metadata_size
388 << ") in Omaha response as validation is not mandatory. "
Gilad Arnoldfe133932014-01-14 12:25:50 -0800389 << "Trusting metadata size in payload = " << metadata_size_;
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700390 SendUmaStat(ErrorCode::kDownloadInvalidMetadataSize);
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800391 }
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700392
Jay Srinivasanf4318702012-09-24 11:56:24 -0700393 // We have the full metadata in |payload|. Verify its integrity
394 // and authenticity based on the information we have in Omaha response.
Gilad Arnoldfe133932014-01-14 12:25:50 -0800395 *error = ValidateMetadataSignature(&payload[0], metadata_size_);
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700396 if (*error != ErrorCode::kSuccess) {
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800397 if (install_plan_->hash_checks_mandatory) {
David Zeuthenbc27aac2013-11-26 11:17:48 -0800398 // The autoupdate_CatchBadSignatures test checks for this string
399 // in log-files. Keep in sync.
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800400 LOG(ERROR) << "Mandatory metadata signature validation failed";
401 return kMetadataParseError;
402 }
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700403
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800404 // For non-mandatory cases, just send a UMA stat.
405 LOG(WARNING) << "Ignoring metadata signature validation failures";
406 SendUmaStat(*error);
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700407 *error = ErrorCode::kSuccess;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700408 }
409
Gilad Arnolddaa27402014-01-23 11:56:17 -0800410 // The payload metadata is deemed valid, it's safe to parse the protobuf.
411 if (!manifest_.ParseFromArray(&payload[manifest_offset], manifest_size)) {
Darin Petkov9574f7e2011-01-13 10:48:12 -0800412 LOG(ERROR) << "Unable to parse manifest in update file.";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700413 *error = ErrorCode::kDownloadManifestParseError;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800414 return kMetadataParseError;
415 }
Gilad Arnolddaa27402014-01-23 11:56:17 -0800416
417 manifest_parsed_ = true;
Darin Petkov9574f7e2011-01-13 10:48:12 -0800418 return kMetadataParseSuccess;
419}
420
421
Don Garrette410e0f2011-11-10 15:39:01 -0800422// Wrapper around write. Returns true if all requested bytes
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800423// were written, or false on any error, regardless of progress
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700424// and stores an action exit code in |error|.
425bool DeltaPerformer::Write(const void* bytes, size_t count,
David Zeuthena99981f2013-04-29 13:42:47 -0700426 ErrorCode *error) {
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700427 *error = ErrorCode::kSuccess;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700428
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700429 const char* c_bytes = reinterpret_cast<const char*>(bytes);
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -0800430 system_state_->payload_state()->DownloadProgress(count);
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800431
432 // Update the total byte downloaded count and the progress logs.
433 total_bytes_received_ += count;
434 UpdateOverallProgress(false, "Completed ");
435
Gilad Arnoldfe133932014-01-14 12:25:50 -0800436 while (!manifest_valid_) {
437 // Read data up to the needed limit; this is either the payload header size,
438 // or the full metadata size (once it becomes known).
439 const bool do_read_header = !metadata_size_;
440 CopyDataToBuffer(&c_bytes, &count,
441 (do_read_header ? GetManifestOffset() :
442 metadata_size_));
443
Gilad Arnolddaa27402014-01-23 11:56:17 -0800444 MetadataParseResult result = ParsePayloadMetadata(buffer_, error);
Gilad Arnold5cac5912013-05-24 17:21:17 -0700445 if (result == kMetadataParseError)
Don Garrette410e0f2011-11-10 15:39:01 -0800446 return false;
Gilad Arnoldfe133932014-01-14 12:25:50 -0800447 if (result == kMetadataParseInsufficientData) {
448 // If we just processed the header, make an attempt on the manifest.
449 if (do_read_header && metadata_size_)
450 continue;
451
Don Garrette410e0f2011-11-10 15:39:01 -0800452 return true;
Gilad Arnoldfe133932014-01-14 12:25:50 -0800453 }
Gilad Arnold21504f02013-05-24 08:51:22 -0700454
455 // Checks the integrity of the payload manifest.
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700456 if ((*error = ValidateManifest()) != ErrorCode::kSuccess)
Gilad Arnold21504f02013-05-24 08:51:22 -0700457 return false;
Gilad Arnolddaa27402014-01-23 11:56:17 -0800458 manifest_valid_ = true;
Gilad Arnold21504f02013-05-24 08:51:22 -0700459
Gilad Arnoldfe133932014-01-14 12:25:50 -0800460 // Clear the download buffer.
Gilad Arnolddaa27402014-01-23 11:56:17 -0800461 DiscardBuffer(false);
Darin Petkov73058b42010-10-06 16:32:19 -0700462 LOG_IF(WARNING, !prefs_->SetInt64(kPrefsManifestMetadataSize,
Gilad Arnoldfe133932014-01-14 12:25:50 -0800463 metadata_size_))
Darin Petkov73058b42010-10-06 16:32:19 -0700464 << "Unable to save the manifest metadata size.";
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700465
Andrew de los Reyes89f17be2010-10-22 13:39:09 -0700466 LogPartitionInfo(manifest_);
Darin Petkov9b230572010-10-08 10:20:09 -0700467 if (!PrimeUpdateState()) {
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700468 *error = ErrorCode::kDownloadStateInitializationError;
Darin Petkov9b230572010-10-08 10:20:09 -0700469 LOG(ERROR) << "Unable to prime the update state.";
Don Garrette410e0f2011-11-10 15:39:01 -0800470 return false;
Darin Petkov9b230572010-10-08 10:20:09 -0700471 }
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800472
473 num_rootfs_operations_ = manifest_.install_operations_size();
474 num_total_operations_ =
475 num_rootfs_operations_ + manifest_.kernel_install_operations_size();
476 if (next_operation_num_ > 0)
477 UpdateOverallProgress(true, "Resuming after ");
478 LOG(INFO) << "Starting to apply update payload operations";
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700479 }
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800480
481 while (next_operation_num_ < num_total_operations_) {
Jay Srinivasan1c0fe792013-03-28 16:45:25 -0700482 // Check if we should cancel the current attempt for any reason.
483 // In this case, *error will have already been populated with the reason
484 // why we're cancelling.
485 if (system_state_->update_attempter()->ShouldCancel(error))
486 return false;
487
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800488 const bool is_kernel_partition =
489 (next_operation_num_ >= num_rootfs_operations_);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700490 const DeltaArchiveManifest_InstallOperation &op =
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800491 is_kernel_partition ?
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700492 manifest_.kernel_install_operations(
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800493 next_operation_num_ - num_rootfs_operations_) :
494 manifest_.install_operations(next_operation_num_);
Gilad Arnoldfe133932014-01-14 12:25:50 -0800495
496 CopyDataToBuffer(&c_bytes, &count, op.data_length());
497
498 // Check whether we received all of the next operation's data payload.
499 if (!CanPerformInstallOperation(op))
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700500 return true;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700501
Jay Srinivasanf4318702012-09-24 11:56:24 -0700502 // Validate the operation only if the metadata signature is present.
Jay Srinivasan00f76b62012-09-17 18:48:36 -0700503 // Otherwise, keep the old behavior. This serves as a knob to disable
504 // the validation logic in case we find some regression after rollout.
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800505 // NOTE: If hash checks are mandatory and if metadata_signature is empty,
506 // we would have already failed in ParsePayloadMetadata method and thus not
507 // even be here. So no need to handle that case again here.
Jay Srinivasanf4318702012-09-24 11:56:24 -0700508 if (!install_plan_->metadata_signature.empty()) {
Jay Srinivasan00f76b62012-09-17 18:48:36 -0700509 // Note: Validate must be called only if CanPerformInstallOperation is
510 // called. Otherwise, we might be failing operations before even if there
511 // isn't sufficient data to compute the proper hash.
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800512 *error = ValidateOperationHash(op);
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700513 if (*error != ErrorCode::kSuccess) {
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800514 if (install_plan_->hash_checks_mandatory) {
515 LOG(ERROR) << "Mandatory operation hash check failed";
516 return false;
517 }
Jay Srinivasanf0572052012-10-23 18:12:56 -0700518
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800519 // For non-mandatory cases, just send a UMA stat.
520 LOG(WARNING) << "Ignoring operation validation errors";
Jay Srinivasanedce2832012-10-24 18:57:47 -0700521 SendUmaStat(*error);
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700522 *error = ErrorCode::kSuccess;
Jay Srinivasan00f76b62012-09-17 18:48:36 -0700523 }
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700524 }
525
Darin Petkov45580e42010-10-08 14:02:40 -0700526 // Makes sure we unblock exit when this operation completes.
Darin Petkov9c0baf82010-10-07 13:44:48 -0700527 ScopedTerminatorExitUnblocker exit_unblocker =
528 ScopedTerminatorExitUnblocker(); // Avoids a compiler unused var bug.
Gilad Arnoldfe133932014-01-14 12:25:50 -0800529
530 bool op_result;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700531 if (op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE ||
Gilad Arnoldfe133932014-01-14 12:25:50 -0800532 op.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ)
533 op_result = HandleOpResult(
534 PerformReplaceOperation(op, is_kernel_partition), "replace", error);
535 else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE)
536 op_result = HandleOpResult(
537 PerformMoveOperation(op, is_kernel_partition), "move", error);
538 else if (op.type() == DeltaArchiveManifest_InstallOperation_Type_BSDIFF)
539 op_result = HandleOpResult(
540 PerformBsdiffOperation(op, is_kernel_partition), "bsdiff", error);
541 else
542 op_result = HandleOpResult(false, "unknown", error);
543
544 if (!op_result)
545 return false;
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800546
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700547 next_operation_num_++;
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800548 UpdateOverallProgress(false, "Completed ");
Darin Petkov73058b42010-10-06 16:32:19 -0700549 CheckpointUpdateProgress();
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700550 }
Don Garrette410e0f2011-11-10 15:39:01 -0800551 return true;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700552}
553
David Zeuthen8f191b22013-08-06 12:27:50 -0700554bool DeltaPerformer::IsManifestValid() {
555 return manifest_valid_;
556}
557
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700558bool DeltaPerformer::CanPerformInstallOperation(
559 const chromeos_update_engine::DeltaArchiveManifest_InstallOperation&
560 operation) {
561 // Move operations don't require any data blob, so they can always
562 // be performed
563 if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_MOVE)
564 return true;
565
566 // See if we have the entire data blob in the buffer
567 if (operation.data_offset() < buffer_offset_) {
568 LOG(ERROR) << "we threw away data it seems?";
569 return false;
570 }
Darin Petkovd7061ab2010-10-06 14:37:09 -0700571
Gilad Arnoldfe133932014-01-14 12:25:50 -0800572 return (operation.data_offset() + operation.data_length() <=
573 buffer_offset_ + buffer_.size());
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700574}
575
576bool DeltaPerformer::PerformReplaceOperation(
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700577 const DeltaArchiveManifest_InstallOperation& operation,
578 bool is_kernel_partition) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700579 CHECK(operation.type() == \
580 DeltaArchiveManifest_InstallOperation_Type_REPLACE || \
581 operation.type() == \
582 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ);
583
584 // Since we delete data off the beginning of the buffer as we use it,
585 // the data we need should be exactly at the beginning of the buffer.
Darin Petkov9b230572010-10-08 10:20:09 -0700586 TEST_AND_RETURN_FALSE(buffer_offset_ == operation.data_offset());
587 TEST_AND_RETURN_FALSE(buffer_.size() >= operation.data_length());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700588
Darin Petkov437adc42010-10-07 13:12:24 -0700589 // Extract the signature message if it's in this operation.
590 ExtractSignatureMessage(operation);
Darin Petkovd7061ab2010-10-06 14:37:09 -0700591
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700592 DirectExtentWriter direct_writer;
593 ZeroPadExtentWriter zero_pad_writer(&direct_writer);
Ben Chan02f7c1d2014-10-18 15:18:02 -0700594 unique_ptr<BzipExtentWriter> bzip_writer;
Darin Petkovd7061ab2010-10-06 14:37:09 -0700595
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700596 // Since bzip decompression is optional, we have a variable writer that will
597 // point to one of the ExtentWriter objects above.
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700598 ExtentWriter* writer = nullptr;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700599 if (operation.type() == DeltaArchiveManifest_InstallOperation_Type_REPLACE) {
600 writer = &zero_pad_writer;
601 } else if (operation.type() ==
602 DeltaArchiveManifest_InstallOperation_Type_REPLACE_BZ) {
603 bzip_writer.reset(new BzipExtentWriter(&zero_pad_writer));
604 writer = bzip_writer.get();
605 } else {
606 NOTREACHED();
607 }
608
609 // Create a vector of extents to pass to the ExtentWriter.
610 vector<Extent> extents;
611 for (int i = 0; i < operation.dst_extents_size(); i++) {
612 extents.push_back(operation.dst_extents(i));
613 }
614
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700615 int fd = is_kernel_partition ? kernel_fd_ : fd_;
616
617 TEST_AND_RETURN_FALSE(writer->Init(fd, extents, block_size_));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700618 TEST_AND_RETURN_FALSE(writer->Write(&buffer_[0], operation.data_length()));
619 TEST_AND_RETURN_FALSE(writer->End());
Darin Petkovd7061ab2010-10-06 14:37:09 -0700620
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700621 // Update buffer
Gilad Arnolddaa27402014-01-23 11:56:17 -0800622 DiscardBuffer(true);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700623 return true;
624}
625
626bool DeltaPerformer::PerformMoveOperation(
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700627 const DeltaArchiveManifest_InstallOperation& operation,
628 bool is_kernel_partition) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700629 // Calculate buffer size. Note, this function doesn't do a sliding
630 // window to copy in case the source and destination blocks overlap.
631 // If we wanted to do a sliding window, we could program the server
632 // to generate deltas that effectively did a sliding window.
633
634 uint64_t blocks_to_read = 0;
635 for (int i = 0; i < operation.src_extents_size(); i++)
636 blocks_to_read += operation.src_extents(i).num_blocks();
637
638 uint64_t blocks_to_write = 0;
639 for (int i = 0; i < operation.dst_extents_size(); i++)
640 blocks_to_write += operation.dst_extents(i).num_blocks();
641
642 DCHECK_EQ(blocks_to_write, blocks_to_read);
643 vector<char> buf(blocks_to_write * block_size_);
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700644
645 int fd = is_kernel_partition ? kernel_fd_ : fd_;
646
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700647 // Read in bytes.
648 ssize_t bytes_read = 0;
649 for (int i = 0; i < operation.src_extents_size(); i++) {
650 ssize_t bytes_read_this_iteration = 0;
651 const Extent& extent = operation.src_extents(i);
Darin Petkov8a075a72013-04-25 14:46:09 +0200652 const size_t bytes = extent.num_blocks() * block_size_;
653 if (extent.start_block() == kSparseHole) {
654 bytes_read_this_iteration = bytes;
655 memset(&buf[bytes_read], 0, bytes);
656 } else {
657 TEST_AND_RETURN_FALSE(utils::PReadAll(fd,
658 &buf[bytes_read],
659 bytes,
660 extent.start_block() * block_size_,
661 &bytes_read_this_iteration));
662 }
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700663 TEST_AND_RETURN_FALSE(
Darin Petkov8a075a72013-04-25 14:46:09 +0200664 bytes_read_this_iteration == static_cast<ssize_t>(bytes));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700665 bytes_read += bytes_read_this_iteration;
666 }
667
Darin Petkov45580e42010-10-08 14:02:40 -0700668 // If this is a non-idempotent operation, request a delayed exit and clear the
669 // update state in case the operation gets interrupted. Do this as late as
670 // possible.
671 if (!IsIdempotentOperation(operation)) {
672 Terminator::set_exit_blocked(true);
673 ResetUpdateProgress(prefs_, true);
674 }
675
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700676 // Write bytes out.
677 ssize_t bytes_written = 0;
678 for (int i = 0; i < operation.dst_extents_size(); i++) {
679 const Extent& extent = operation.dst_extents(i);
Darin Petkov8a075a72013-04-25 14:46:09 +0200680 const size_t bytes = extent.num_blocks() * block_size_;
681 if (extent.start_block() == kSparseHole) {
Darin Petkov741a8222013-05-02 10:02:34 +0200682 DCHECK(buf.begin() + bytes_written ==
683 std::search_n(buf.begin() + bytes_written,
684 buf.begin() + bytes_written + bytes,
685 bytes, 0));
Darin Petkov8a075a72013-04-25 14:46:09 +0200686 } else {
687 TEST_AND_RETURN_FALSE(
688 utils::PWriteAll(fd,
689 &buf[bytes_written],
690 bytes,
691 extent.start_block() * block_size_));
692 }
693 bytes_written += bytes;
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700694 }
695 DCHECK_EQ(bytes_written, bytes_read);
696 DCHECK_EQ(bytes_written, static_cast<ssize_t>(buf.size()));
697 return true;
698}
699
700bool DeltaPerformer::ExtentsToBsdiffPositionsString(
701 const RepeatedPtrField<Extent>& extents,
702 uint64_t block_size,
703 uint64_t full_length,
704 string* positions_string) {
705 string ret;
706 uint64_t length = 0;
707 for (int i = 0; i < extents.size(); i++) {
708 Extent extent = extents.Get(i);
709 int64_t start = extent.start_block();
710 uint64_t this_length = min(full_length - length,
711 extent.num_blocks() * block_size);
712 if (start == static_cast<int64_t>(kSparseHole))
713 start = -1;
714 else
715 start *= block_size;
Alex Vakulenko75039d72014-03-25 12:36:28 -0700716 ret += base::StringPrintf("%" PRIi64 ":%" PRIu64 ",", start, this_length);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700717 length += this_length;
718 }
719 TEST_AND_RETURN_FALSE(length == full_length);
720 if (!ret.empty())
721 ret.resize(ret.size() - 1); // Strip trailing comma off
722 *positions_string = ret;
723 return true;
724}
725
726bool DeltaPerformer::PerformBsdiffOperation(
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700727 const DeltaArchiveManifest_InstallOperation& operation,
728 bool is_kernel_partition) {
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700729 // Since we delete data off the beginning of the buffer as we use it,
730 // the data we need should be exactly at the beginning of the buffer.
Darin Petkov9b230572010-10-08 10:20:09 -0700731 TEST_AND_RETURN_FALSE(buffer_offset_ == operation.data_offset());
732 TEST_AND_RETURN_FALSE(buffer_.size() >= operation.data_length());
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700733
734 string input_positions;
735 TEST_AND_RETURN_FALSE(ExtentsToBsdiffPositionsString(operation.src_extents(),
736 block_size_,
737 operation.src_length(),
738 &input_positions));
739 string output_positions;
740 TEST_AND_RETURN_FALSE(ExtentsToBsdiffPositionsString(operation.dst_extents(),
741 block_size_,
742 operation.dst_length(),
743 &output_positions));
744
745 string temp_filename;
746 TEST_AND_RETURN_FALSE(utils::MakeTempFile("/tmp/au_patch.XXXXXX",
747 &temp_filename,
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700748 nullptr));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700749 ScopedPathUnlinker path_unlinker(temp_filename);
750 {
751 int fd = open(temp_filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
752 ScopedFdCloser fd_closer(&fd);
753 TEST_AND_RETURN_FALSE(
754 utils::WriteAll(fd, &buffer_[0], operation.data_length()));
755 }
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700756
Darin Petkov7f2ec752013-04-03 14:45:19 +0200757 // Update the buffer to release the patch data memory as soon as the patch
758 // file is written out.
Gilad Arnolddaa27402014-01-23 11:56:17 -0800759 DiscardBuffer(true);
Darin Petkov7f2ec752013-04-03 14:45:19 +0200760
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700761 int fd = is_kernel_partition ? kernel_fd_ : fd_;
Alex Vakulenko75039d72014-03-25 12:36:28 -0700762 const string path = base::StringPrintf("/proc/self/fd/%d", fd);
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700763
Darin Petkov45580e42010-10-08 14:02:40 -0700764 // If this is a non-idempotent operation, request a delayed exit and clear the
765 // update state in case the operation gets interrupted. Do this as late as
766 // possible.
767 if (!IsIdempotentOperation(operation)) {
768 Terminator::set_exit_blocked(true);
769 ResetUpdateProgress(prefs_, true);
770 }
771
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700772 vector<string> cmd;
773 cmd.push_back(kBspatchPath);
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700774 cmd.push_back(path);
775 cmd.push_back(path);
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700776 cmd.push_back(temp_filename);
777 cmd.push_back(input_positions);
778 cmd.push_back(output_positions);
779 int return_code = 0;
Andrew de los Reyes5a232832010-10-12 16:20:54 -0700780 TEST_AND_RETURN_FALSE(
781 Subprocess::SynchronousExecFlags(cmd,
Darin Petkov85d02b72011-05-17 13:25:51 -0700782 G_SPAWN_LEAVE_DESCRIPTORS_OPEN,
Andrew de los Reyes5a232832010-10-12 16:20:54 -0700783 &return_code,
Alex Vakulenko88b591f2014-08-28 16:48:57 -0700784 nullptr));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700785 TEST_AND_RETURN_FALSE(return_code == 0);
786
787 if (operation.dst_length() % block_size_) {
788 // Zero out rest of final block.
789 // TODO(adlr): build this into bspatch; it's more efficient that way.
790 const Extent& last_extent =
791 operation.dst_extents(operation.dst_extents_size() - 1);
792 const uint64_t end_byte =
793 (last_extent.start_block() + last_extent.num_blocks()) * block_size_;
794 const uint64_t begin_byte =
795 end_byte - (block_size_ - operation.dst_length() % block_size_);
796 vector<char> zeros(end_byte - begin_byte);
797 TEST_AND_RETURN_FALSE(
Andrew de los Reyesf4c7ef12010-04-30 10:37:00 -0700798 utils::PWriteAll(fd, &zeros[0], end_byte - begin_byte, begin_byte));
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700799 }
Andrew de los Reyes09e56d62010-04-23 13:45:53 -0700800 return true;
801}
802
Darin Petkovd7061ab2010-10-06 14:37:09 -0700803bool DeltaPerformer::ExtractSignatureMessage(
804 const DeltaArchiveManifest_InstallOperation& operation) {
805 if (operation.type() != DeltaArchiveManifest_InstallOperation_Type_REPLACE ||
806 !manifest_.has_signatures_offset() ||
807 manifest_.signatures_offset() != operation.data_offset()) {
808 return false;
809 }
810 TEST_AND_RETURN_FALSE(manifest_.has_signatures_size() &&
811 manifest_.signatures_size() == operation.data_length());
812 TEST_AND_RETURN_FALSE(signatures_message_data_.empty());
813 TEST_AND_RETURN_FALSE(buffer_offset_ == manifest_.signatures_offset());
814 TEST_AND_RETURN_FALSE(buffer_.size() >= manifest_.signatures_size());
Darin Petkov4f0a07b2011-05-25 16:47:20 -0700815 signatures_message_data_.assign(
Darin Petkovd7061ab2010-10-06 14:37:09 -0700816 buffer_.begin(),
817 buffer_.begin() + manifest_.signatures_size());
Darin Petkov4f0a07b2011-05-25 16:47:20 -0700818
819 // Save the signature blob because if the update is interrupted after the
820 // download phase we don't go through this path anymore. Some alternatives to
821 // consider:
822 //
823 // 1. On resume, re-download the signature blob from the server and re-verify
824 // it.
825 //
826 // 2. Verify the signature as soon as it's received and don't checkpoint the
827 // blob and the signed sha-256 context.
828 LOG_IF(WARNING, !prefs_->SetString(kPrefsUpdateStateSignatureBlob,
829 string(&signatures_message_data_[0],
830 signatures_message_data_.size())))
831 << "Unable to store the signature blob.";
Darin Petkov437adc42010-10-07 13:12:24 -0700832 // The hash of all data consumed so far should be verified against the signed
833 // hash.
834 signed_hash_context_ = hash_calculator_.GetContext();
835 LOG_IF(WARNING, !prefs_->SetString(kPrefsUpdateStateSignedSHA256Context,
836 signed_hash_context_))
837 << "Unable to store the signed hash context.";
Darin Petkovd7061ab2010-10-06 14:37:09 -0700838 LOG(INFO) << "Extracted signature data of size "
839 << manifest_.signatures_size() << " at "
840 << manifest_.signatures_offset();
841 return true;
842}
843
David Zeuthene7f89172013-10-31 10:21:04 -0700844bool DeltaPerformer::GetPublicKeyFromResponse(base::FilePath *out_tmp_key) {
845 if (system_state_->hardware()->IsOfficialBuild() ||
846 utils::FileExists(public_key_path_.c_str()) ||
847 install_plan_->public_key_rsa.empty())
848 return false;
849
850 if (!utils::DecodeAndStoreBase64String(install_plan_->public_key_rsa,
851 out_tmp_key))
852 return false;
853
854 return true;
855}
856
David Zeuthena99981f2013-04-29 13:42:47 -0700857ErrorCode DeltaPerformer::ValidateMetadataSignature(
Jay Srinivasanf4318702012-09-24 11:56:24 -0700858 const char* metadata, uint64_t metadata_size) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700859
Jay Srinivasanf4318702012-09-24 11:56:24 -0700860 if (install_plan_->metadata_signature.empty()) {
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800861 if (install_plan_->hash_checks_mandatory) {
862 LOG(ERROR) << "Missing mandatory metadata signature in Omaha response";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700863 return ErrorCode::kDownloadMetadataSignatureMissingError;
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800864 }
865
866 // For non-mandatory cases, just send a UMA stat.
Jay Srinivasanf4318702012-09-24 11:56:24 -0700867 LOG(WARNING) << "Cannot validate metadata as the signature is empty";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700868 SendUmaStat(ErrorCode::kDownloadMetadataSignatureMissingError);
869 return ErrorCode::kSuccess;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700870 }
871
872 // Convert base64-encoded signature to raw bytes.
Jay Srinivasanf4318702012-09-24 11:56:24 -0700873 vector<char> metadata_signature;
874 if (!OmahaHashCalculator::Base64Decode(install_plan_->metadata_signature,
875 &metadata_signature)) {
876 LOG(ERROR) << "Unable to decode base64 metadata signature: "
877 << install_plan_->metadata_signature;
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700878 return ErrorCode::kDownloadMetadataSignatureError;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700879 }
880
David Zeuthene7f89172013-10-31 10:21:04 -0700881 // See if we should use the public RSA key in the Omaha response.
882 base::FilePath path_to_public_key(public_key_path_);
883 base::FilePath tmp_key;
884 if (GetPublicKeyFromResponse(&tmp_key))
885 path_to_public_key = tmp_key;
886 ScopedPathUnlinker tmp_key_remover(tmp_key.value());
887 if (tmp_key.empty())
888 tmp_key_remover.set_should_remove(false);
889
890 LOG(INFO) << "Verifying metadata hash signature using public key: "
891 << path_to_public_key.value();
892
Jay Srinivasanf4318702012-09-24 11:56:24 -0700893 vector<char> expected_metadata_hash;
Alex Deymo923d8fa2014-07-15 17:58:51 -0700894 if (!PayloadVerifier::GetRawHashFromSignature(metadata_signature,
895 path_to_public_key.value(),
896 &expected_metadata_hash)) {
Jay Srinivasanf4318702012-09-24 11:56:24 -0700897 LOG(ERROR) << "Unable to compute expected hash from metadata signature";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700898 return ErrorCode::kDownloadMetadataSignatureError;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700899 }
900
Jay Srinivasanf4318702012-09-24 11:56:24 -0700901 OmahaHashCalculator metadata_hasher;
902 metadata_hasher.Update(metadata, metadata_size);
903 if (!metadata_hasher.Finalize()) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700904 LOG(ERROR) << "Unable to compute actual hash of manifest";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700905 return ErrorCode::kDownloadMetadataSignatureVerificationError;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700906 }
907
Jay Srinivasanf4318702012-09-24 11:56:24 -0700908 vector<char> calculated_metadata_hash = metadata_hasher.raw_hash();
Alex Deymo923d8fa2014-07-15 17:58:51 -0700909 PayloadVerifier::PadRSA2048SHA256Hash(&calculated_metadata_hash);
Jay Srinivasanf4318702012-09-24 11:56:24 -0700910 if (calculated_metadata_hash.empty()) {
911 LOG(ERROR) << "Computed actual hash of metadata is empty.";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700912 return ErrorCode::kDownloadMetadataSignatureVerificationError;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700913 }
914
Jay Srinivasanf4318702012-09-24 11:56:24 -0700915 if (calculated_metadata_hash != expected_metadata_hash) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700916 LOG(ERROR) << "Manifest hash verification failed. Expected hash = ";
Jay Srinivasanf4318702012-09-24 11:56:24 -0700917 utils::HexDumpVector(expected_metadata_hash);
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700918 LOG(ERROR) << "Calculated hash = ";
Jay Srinivasanf4318702012-09-24 11:56:24 -0700919 utils::HexDumpVector(calculated_metadata_hash);
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700920 return ErrorCode::kDownloadMetadataSignatureMismatch;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700921 }
922
David Zeuthenbc27aac2013-11-26 11:17:48 -0800923 // The autoupdate_CatchBadSignatures test checks for this string in
924 // log-files. Keep in sync.
David Zeuthene7f89172013-10-31 10:21:04 -0700925 LOG(INFO) << "Metadata hash signature matches value in Omaha response.";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700926 return ErrorCode::kSuccess;
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700927}
928
Gilad Arnold21504f02013-05-24 08:51:22 -0700929ErrorCode DeltaPerformer::ValidateManifest() {
Don Garrettb8dd1d92013-11-22 17:40:02 -0800930 // Perform assorted checks to sanity check the manifest, make sure it
931 // matches data from other sources, and that it is a supported version.
Gilad Arnold21504f02013-05-24 08:51:22 -0700932 //
933 // TODO(garnold) in general, the presence of an old partition hash should be
934 // the sole indicator for a delta update, as we would generally like update
935 // payloads to be self contained and not assume an Omaha response to tell us
936 // that. However, since this requires some massive reengineering of the update
937 // flow (making filesystem copying happen conditionally only *after*
938 // downloading and parsing of the update manifest) we'll put it off for now.
939 // See chromium-os:7597 for further discussion.
Don Garrettb8dd1d92013-11-22 17:40:02 -0800940 if (install_plan_->is_full_update) {
941 if (manifest_.has_old_kernel_info() || manifest_.has_old_rootfs_info()) {
942 LOG(ERROR) << "Purported full payload contains old partition "
943 "hash(es), aborting update";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700944 return ErrorCode::kPayloadMismatchedType;
Don Garrettb8dd1d92013-11-22 17:40:02 -0800945 }
946
947 if (manifest_.minor_version() != kFullPayloadMinorVersion) {
948 LOG(ERROR) << "Manifest contains minor version "
949 << manifest_.minor_version()
950 << ", but all full payloads should have version "
951 << kFullPayloadMinorVersion << ".";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700952 return ErrorCode::kUnsupportedMinorPayloadVersion;
Don Garrettb8dd1d92013-11-22 17:40:02 -0800953 }
954 } else {
955 if (manifest_.minor_version() != kSupportedMinorPayloadVersion) {
956 LOG(ERROR) << "Manifest contains minor version "
957 << manifest_.minor_version()
958 << " not the supported "
959 << kSupportedMinorPayloadVersion;
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700960 return ErrorCode::kUnsupportedMinorPayloadVersion;
Don Garrettb8dd1d92013-11-22 17:40:02 -0800961 }
Gilad Arnold21504f02013-05-24 08:51:22 -0700962 }
963
964 // TODO(garnold) we should be adding more and more manifest checks, such as
965 // partition boundaries etc (see chromium-os:37661).
966
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700967 return ErrorCode::kSuccess;
Gilad Arnold21504f02013-05-24 08:51:22 -0700968}
969
David Zeuthena99981f2013-04-29 13:42:47 -0700970ErrorCode DeltaPerformer::ValidateOperationHash(
Gilad Arnold8a86fa52013-01-15 12:35:05 -0800971 const DeltaArchiveManifest_InstallOperation& operation) {
Jay Srinivasan51dcf262012-09-13 17:24:32 -0700972
Jay Srinivasan00f76b62012-09-17 18:48:36 -0700973 if (!operation.data_sha256_hash().size()) {
974 if (!operation.data_length()) {
975 // Operations that do not have any data blob won't have any operation hash
976 // either. So, these operations are always considered validated since the
Jay Srinivasanf4318702012-09-24 11:56:24 -0700977 // metadata that contains all the non-data-blob portions of the operation
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800978 // has already been validated. This is true for both HTTP and HTTPS cases.
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700979 return ErrorCode::kSuccess;
Jay Srinivasan00f76b62012-09-17 18:48:36 -0700980 }
981
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800982 // No hash is present for an operation that has data blobs. This shouldn't
983 // happen normally for any client that has this code, because the
Jay Srinivasan00f76b62012-09-17 18:48:36 -0700984 // corresponding update should have been produced with the operation
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800985 // hashes. So if it happens it means either we've turned operation hash
986 // generation off in DeltaDiffGenerator or it's a regression of some sort.
Jay Srinivasan00f76b62012-09-17 18:48:36 -0700987 // One caveat though: The last operation is a dummy signature operation
988 // that doesn't have a hash at the time the manifest is created. So we
989 // should not complaint about that operation. This operation can be
990 // recognized by the fact that it's offset is mentioned in the manifest.
991 if (manifest_.signatures_offset() &&
992 manifest_.signatures_offset() == operation.data_offset()) {
993 LOG(INFO) << "Skipping hash verification for signature operation "
994 << next_operation_num_ + 1;
995 } else {
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800996 if (install_plan_->hash_checks_mandatory) {
997 LOG(ERROR) << "Missing mandatory operation hash for operation "
998 << next_operation_num_ + 1;
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -0700999 return ErrorCode::kDownloadOperationHashMissingError;
Jay Srinivasan738fdf32012-12-07 17:40:54 -08001000 }
1001
1002 // For non-mandatory cases, just send a UMA stat.
1003 LOG(WARNING) << "Cannot validate operation " << next_operation_num_ + 1
1004 << " as there's no operation hash in manifest";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001005 SendUmaStat(ErrorCode::kDownloadOperationHashMissingError);
Jay Srinivasan00f76b62012-09-17 18:48:36 -07001006 }
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001007 return ErrorCode::kSuccess;
Jay Srinivasan00f76b62012-09-17 18:48:36 -07001008 }
1009
1010 vector<char> expected_op_hash;
1011 expected_op_hash.assign(operation.data_sha256_hash().data(),
1012 (operation.data_sha256_hash().data() +
1013 operation.data_sha256_hash().size()));
1014
1015 OmahaHashCalculator operation_hasher;
1016 operation_hasher.Update(&buffer_[0], operation.data_length());
1017 if (!operation_hasher.Finalize()) {
1018 LOG(ERROR) << "Unable to compute actual hash of operation "
1019 << next_operation_num_;
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001020 return ErrorCode::kDownloadOperationHashVerificationError;
Jay Srinivasan00f76b62012-09-17 18:48:36 -07001021 }
1022
1023 vector<char> calculated_op_hash = operation_hasher.raw_hash();
1024 if (calculated_op_hash != expected_op_hash) {
1025 LOG(ERROR) << "Hash verification failed for operation "
1026 << next_operation_num_ << ". Expected hash = ";
1027 utils::HexDumpVector(expected_op_hash);
1028 LOG(ERROR) << "Calculated hash over " << operation.data_length()
1029 << " bytes at offset: " << operation.data_offset() << " = ";
1030 utils::HexDumpVector(calculated_op_hash);
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001031 return ErrorCode::kDownloadOperationHashMismatch;
Jay Srinivasan00f76b62012-09-17 18:48:36 -07001032 }
1033
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001034 return ErrorCode::kSuccess;
Jay Srinivasan51dcf262012-09-13 17:24:32 -07001035}
1036
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -07001037#define TEST_AND_RETURN_VAL(_retval, _condition) \
1038 do { \
1039 if (!(_condition)) { \
1040 LOG(ERROR) << "VerifyPayload failure: " << #_condition; \
1041 return _retval; \
1042 } \
1043 } while (0);
Andrew de los Reyesfb830ba2011-04-04 11:42:43 -07001044
David Zeuthena99981f2013-04-29 13:42:47 -07001045ErrorCode DeltaPerformer::VerifyPayload(
Darin Petkov437adc42010-10-07 13:12:24 -07001046 const std::string& update_check_response_hash,
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -07001047 const uint64_t update_check_response_size) {
David Zeuthene7f89172013-10-31 10:21:04 -07001048
1049 // See if we should use the public RSA key in the Omaha response.
1050 base::FilePath path_to_public_key(public_key_path_);
1051 base::FilePath tmp_key;
1052 if (GetPublicKeyFromResponse(&tmp_key))
1053 path_to_public_key = tmp_key;
1054 ScopedPathUnlinker tmp_key_remover(tmp_key.value());
1055 if (tmp_key.empty())
1056 tmp_key_remover.set_should_remove(false);
1057
1058 LOG(INFO) << "Verifying payload using public key: "
1059 << path_to_public_key.value();
Darin Petkov437adc42010-10-07 13:12:24 -07001060
Jay Srinivasan0d8fb402012-05-07 19:19:38 -07001061 // Verifies the download size.
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001062 TEST_AND_RETURN_VAL(ErrorCode::kPayloadSizeMismatchError,
Jay Srinivasan0d8fb402012-05-07 19:19:38 -07001063 update_check_response_size ==
Gilad Arnoldfe133932014-01-14 12:25:50 -08001064 metadata_size_ + buffer_offset_);
Jay Srinivasan0d8fb402012-05-07 19:19:38 -07001065
Jay Srinivasan51dcf262012-09-13 17:24:32 -07001066 // Verifies the payload hash.
1067 const string& payload_hash_data = hash_calculator_.hash();
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001068 TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadVerificationError,
Jay Srinivasan51dcf262012-09-13 17:24:32 -07001069 !payload_hash_data.empty());
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001070 TEST_AND_RETURN_VAL(ErrorCode::kPayloadHashMismatchError,
Jay Srinivasan51dcf262012-09-13 17:24:32 -07001071 payload_hash_data == update_check_response_hash);
Darin Petkov437adc42010-10-07 13:12:24 -07001072
Darin Petkov437adc42010-10-07 13:12:24 -07001073 // Verifies the signed payload hash.
David Zeuthene7f89172013-10-31 10:21:04 -07001074 if (!utils::FileExists(path_to_public_key.value().c_str())) {
Darin Petkov437adc42010-10-07 13:12:24 -07001075 LOG(WARNING) << "Not verifying signed delta payload -- missing public key.";
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001076 return ErrorCode::kSuccess;
Darin Petkovd7061ab2010-10-06 14:37:09 -07001077 }
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001078 TEST_AND_RETURN_VAL(ErrorCode::kSignedDeltaPayloadExpectedError,
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -07001079 !signatures_message_data_.empty());
Darin Petkovd7061ab2010-10-06 14:37:09 -07001080 vector<char> signed_hash_data;
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001081 TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
Alex Deymo923d8fa2014-07-15 17:58:51 -07001082 PayloadVerifier::VerifySignature(
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -07001083 signatures_message_data_,
David Zeuthene7f89172013-10-31 10:21:04 -07001084 path_to_public_key.value(),
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -07001085 &signed_hash_data));
Darin Petkov437adc42010-10-07 13:12:24 -07001086 OmahaHashCalculator signed_hasher;
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001087 TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -07001088 signed_hasher.SetContext(signed_hash_context_));
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001089 TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -07001090 signed_hasher.Finalize());
Andrew de los Reyesbdfaaf02011-03-30 10:35:12 -07001091 vector<char> hash_data = signed_hasher.raw_hash();
Alex Deymo923d8fa2014-07-15 17:58:51 -07001092 PayloadVerifier::PadRSA2048SHA256Hash(&hash_data);
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001093 TEST_AND_RETURN_VAL(ErrorCode::kDownloadPayloadPubKeyVerificationError,
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -07001094 !hash_data.empty());
Andrew de los Reyesfb830ba2011-04-04 11:42:43 -07001095 if (hash_data != signed_hash_data) {
David Zeuthenbc27aac2013-11-26 11:17:48 -08001096 // The autoupdate_CatchBadSignatures test checks for this string
1097 // in log-files. Keep in sync.
Andrew de los Reyes771e1bd2011-08-30 14:47:23 -07001098 LOG(ERROR) << "Public key verification failed, thus update failed. "
Andrew de los Reyesfb830ba2011-04-04 11:42:43 -07001099 "Attached Signature:";
1100 utils::HexDumpVector(signed_hash_data);
1101 LOG(ERROR) << "Computed Signature:";
1102 utils::HexDumpVector(hash_data);
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001103 return ErrorCode::kDownloadPayloadPubKeyVerificationError;
Andrew de los Reyesfb830ba2011-04-04 11:42:43 -07001104 }
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -08001105
David Zeuthene7f89172013-10-31 10:21:04 -07001106 LOG(INFO) << "Payload hash matches value in payload.";
1107
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -08001108 // At this point, we are guaranteed to have downloaded a full payload, i.e
1109 // the one whose size matches the size mentioned in Omaha response. If any
1110 // errors happen after this, it's likely a problem with the payload itself or
1111 // the state of the system and not a problem with the URL or network. So,
Jay Srinivasan08262882012-12-28 19:29:43 -08001112 // indicate that to the payload state so that AU can backoff appropriately.
Jay Srinivasan2b5a0f02012-12-19 17:25:56 -08001113 system_state_->payload_state()->DownloadComplete();
1114
Gilad Arnoldd1c4d2d2014-06-05 14:07:53 -07001115 return ErrorCode::kSuccess;
Darin Petkovd7061ab2010-10-06 14:37:09 -07001116}
1117
Darin Petkov3aefa862010-12-07 14:45:00 -08001118bool DeltaPerformer::GetNewPartitionInfo(uint64_t* kernel_size,
1119 vector<char>* kernel_hash,
1120 uint64_t* rootfs_size,
1121 vector<char>* rootfs_hash) {
Darin Petkov2dd01092010-10-08 15:43:05 -07001122 TEST_AND_RETURN_FALSE(manifest_valid_ &&
1123 manifest_.has_new_kernel_info() &&
1124 manifest_.has_new_rootfs_info());
Darin Petkov3aefa862010-12-07 14:45:00 -08001125 *kernel_size = manifest_.new_kernel_info().size();
1126 *rootfs_size = manifest_.new_rootfs_info().size();
1127 vector<char> new_kernel_hash(manifest_.new_kernel_info().hash().begin(),
1128 manifest_.new_kernel_info().hash().end());
1129 vector<char> new_rootfs_hash(manifest_.new_rootfs_info().hash().begin(),
1130 manifest_.new_rootfs_info().hash().end());
1131 kernel_hash->swap(new_kernel_hash);
1132 rootfs_hash->swap(new_rootfs_hash);
Darin Petkov2dd01092010-10-08 15:43:05 -07001133 return true;
1134}
1135
Andrew de los Reyes100bb7d2011-08-09 17:35:07 -07001136namespace {
1137void LogVerifyError(bool is_kern,
1138 const string& local_hash,
1139 const string& expected_hash) {
1140 const char* type = is_kern ? "kernel" : "rootfs";
1141 LOG(ERROR) << "This is a server-side error due to "
1142 << "mismatched delta update image!";
1143 LOG(ERROR) << "The delta I've been given contains a " << type << " delta "
1144 << "update that must be applied over a " << type << " with "
1145 << "a specific checksum, but the " << type << " we're starting "
1146 << "with doesn't have that checksum! This means that "
1147 << "the delta I've been given doesn't match my existing "
1148 << "system. The " << type << " partition I have has hash: "
1149 << local_hash << " but the update expected me to have "
1150 << expected_hash << " .";
1151 if (is_kern) {
1152 LOG(INFO) << "To get the checksum of a kernel partition on a "
1153 << "booted machine, run this command (change /dev/sda2 "
1154 << "as needed): dd if=/dev/sda2 bs=1M 2>/dev/null | "
1155 << "openssl dgst -sha256 -binary | openssl base64";
1156 } else {
1157 LOG(INFO) << "To get the checksum of a rootfs partition on a "
1158 << "booted machine, run this command (change /dev/sda3 "
1159 << "as needed): dd if=/dev/sda3 bs=1M count=$(( "
1160 << "$(dumpe2fs /dev/sda3 2>/dev/null | grep 'Block count' "
1161 << "| sed 's/[^0-9]*//') / 256 )) | "
1162 << "openssl dgst -sha256 -binary | openssl base64";
1163 }
1164 LOG(INFO) << "To get the checksum of partitions in a bin file, "
1165 << "run: .../src/scripts/sha256_partitions.sh .../file.bin";
1166}
1167
1168string StringForHashBytes(const void* bytes, size_t size) {
1169 string ret;
1170 if (!OmahaHashCalculator::Base64Encode(bytes, size, &ret)) {
1171 ret = "<unknown>";
1172 }
1173 return ret;
1174}
1175} // namespace
1176
Darin Petkov698d0412010-10-13 10:59:44 -07001177bool DeltaPerformer::VerifySourcePartitions() {
1178 LOG(INFO) << "Verifying source partitions.";
1179 CHECK(manifest_valid_);
Jay Srinivasan51dcf262012-09-13 17:24:32 -07001180 CHECK(install_plan_);
Darin Petkov698d0412010-10-13 10:59:44 -07001181 if (manifest_.has_old_kernel_info()) {
1182 const PartitionInfo& info = manifest_.old_kernel_info();
Jay Srinivasan51dcf262012-09-13 17:24:32 -07001183 bool valid =
1184 !install_plan_->kernel_hash.empty() &&
1185 install_plan_->kernel_hash.size() == info.hash().size() &&
1186 memcmp(install_plan_->kernel_hash.data(),
Andrew de los Reyes100bb7d2011-08-09 17:35:07 -07001187 info.hash().data(),
Jay Srinivasan51dcf262012-09-13 17:24:32 -07001188 install_plan_->kernel_hash.size()) == 0;
Andrew de los Reyes100bb7d2011-08-09 17:35:07 -07001189 if (!valid) {
1190 LogVerifyError(true,
Jay Srinivasan51dcf262012-09-13 17:24:32 -07001191 StringForHashBytes(install_plan_->kernel_hash.data(),
1192 install_plan_->kernel_hash.size()),
Andrew de los Reyes100bb7d2011-08-09 17:35:07 -07001193 StringForHashBytes(info.hash().data(),
1194 info.hash().size()));
1195 }
1196 TEST_AND_RETURN_FALSE(valid);
Darin Petkov698d0412010-10-13 10:59:44 -07001197 }
1198 if (manifest_.has_old_rootfs_info()) {
1199 const PartitionInfo& info = manifest_.old_rootfs_info();
Jay Srinivasan51dcf262012-09-13 17:24:32 -07001200 bool valid =
1201 !install_plan_->rootfs_hash.empty() &&
1202 install_plan_->rootfs_hash.size() == info.hash().size() &&
1203 memcmp(install_plan_->rootfs_hash.data(),
Andrew de los Reyes100bb7d2011-08-09 17:35:07 -07001204 info.hash().data(),
Jay Srinivasan51dcf262012-09-13 17:24:32 -07001205 install_plan_->rootfs_hash.size()) == 0;
Andrew de los Reyes100bb7d2011-08-09 17:35:07 -07001206 if (!valid) {
1207 LogVerifyError(false,
Chris Sosa670d6802013-03-29 14:17:45 -07001208 StringForHashBytes(install_plan_->rootfs_hash.data(),
1209 install_plan_->rootfs_hash.size()),
Andrew de los Reyes100bb7d2011-08-09 17:35:07 -07001210 StringForHashBytes(info.hash().data(),
1211 info.hash().size()));
1212 }
1213 TEST_AND_RETURN_FALSE(valid);
Darin Petkov698d0412010-10-13 10:59:44 -07001214 }
1215 return true;
1216}
1217
Gilad Arnolddaa27402014-01-23 11:56:17 -08001218void DeltaPerformer::DiscardBuffer(bool do_advance_offset) {
Gilad Arnoldfe133932014-01-14 12:25:50 -08001219 // Update the buffer offset.
Gilad Arnolddaa27402014-01-23 11:56:17 -08001220 if (do_advance_offset)
Gilad Arnoldfe133932014-01-14 12:25:50 -08001221 buffer_offset_ += buffer_.size();
1222
1223 // Hash the content.
1224 hash_calculator_.Update(&buffer_[0], buffer_.size());
1225
1226 // Swap content with an empty vector to ensure that all memory is released.
1227 vector<char>().swap(buffer_);
Darin Petkovd7061ab2010-10-06 14:37:09 -07001228}
1229
Darin Petkov0406e402010-10-06 21:33:11 -07001230bool DeltaPerformer::CanResumeUpdate(PrefsInterface* prefs,
1231 string update_check_response_hash) {
1232 int64_t next_operation = kUpdateStateOperationInvalid;
1233 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsUpdateStateNextOperation,
1234 &next_operation) &&
1235 next_operation != kUpdateStateOperationInvalid &&
1236 next_operation > 0);
1237
1238 string interrupted_hash;
1239 TEST_AND_RETURN_FALSE(prefs->GetString(kPrefsUpdateCheckResponseHash,
1240 &interrupted_hash) &&
David Zeuthenc41c2282013-06-17 16:33:06 -07001241 !interrupted_hash.empty() &&
1242 interrupted_hash == update_check_response_hash);
Darin Petkov0406e402010-10-06 21:33:11 -07001243
Darin Petkov61426142010-10-08 11:04:55 -07001244 int64_t resumed_update_failures;
1245 TEST_AND_RETURN_FALSE(!prefs->GetInt64(kPrefsResumedUpdateFailures,
1246 &resumed_update_failures) ||
1247 resumed_update_failures <= kMaxResumedUpdateFailures);
1248
Darin Petkov0406e402010-10-06 21:33:11 -07001249 // Sanity check the rest.
1250 int64_t next_data_offset = -1;
1251 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsUpdateStateNextDataOffset,
1252 &next_data_offset) &&
1253 next_data_offset >= 0);
1254
Darin Petkov437adc42010-10-07 13:12:24 -07001255 string sha256_context;
Darin Petkov0406e402010-10-06 21:33:11 -07001256 TEST_AND_RETURN_FALSE(
Darin Petkov437adc42010-10-07 13:12:24 -07001257 prefs->GetString(kPrefsUpdateStateSHA256Context, &sha256_context) &&
1258 !sha256_context.empty());
Darin Petkov0406e402010-10-06 21:33:11 -07001259
1260 int64_t manifest_metadata_size = 0;
1261 TEST_AND_RETURN_FALSE(prefs->GetInt64(kPrefsManifestMetadataSize,
1262 &manifest_metadata_size) &&
1263 manifest_metadata_size > 0);
1264
1265 return true;
1266}
1267
Darin Petkov9b230572010-10-08 10:20:09 -07001268bool DeltaPerformer::ResetUpdateProgress(PrefsInterface* prefs, bool quick) {
Darin Petkov0406e402010-10-06 21:33:11 -07001269 TEST_AND_RETURN_FALSE(prefs->SetInt64(kPrefsUpdateStateNextOperation,
1270 kUpdateStateOperationInvalid));
Darin Petkov9b230572010-10-08 10:20:09 -07001271 if (!quick) {
1272 prefs->SetString(kPrefsUpdateCheckResponseHash, "");
1273 prefs->SetInt64(kPrefsUpdateStateNextDataOffset, -1);
David Zeuthen41996ad2013-09-24 15:43:24 -07001274 prefs->SetInt64(kPrefsUpdateStateNextDataLength, 0);
Darin Petkov9b230572010-10-08 10:20:09 -07001275 prefs->SetString(kPrefsUpdateStateSHA256Context, "");
1276 prefs->SetString(kPrefsUpdateStateSignedSHA256Context, "");
Darin Petkov4f0a07b2011-05-25 16:47:20 -07001277 prefs->SetString(kPrefsUpdateStateSignatureBlob, "");
Darin Petkov9b230572010-10-08 10:20:09 -07001278 prefs->SetInt64(kPrefsManifestMetadataSize, -1);
Darin Petkov61426142010-10-08 11:04:55 -07001279 prefs->SetInt64(kPrefsResumedUpdateFailures, 0);
Darin Petkov9b230572010-10-08 10:20:09 -07001280 }
Darin Petkov73058b42010-10-06 16:32:19 -07001281 return true;
1282}
1283
1284bool DeltaPerformer::CheckpointUpdateProgress() {
Darin Petkov9c0baf82010-10-07 13:44:48 -07001285 Terminator::set_exit_blocked(true);
Darin Petkov0406e402010-10-06 21:33:11 -07001286 if (last_updated_buffer_offset_ != buffer_offset_) {
Darin Petkov9c0baf82010-10-07 13:44:48 -07001287 // Resets the progress in case we die in the middle of the state update.
Darin Petkov9b230572010-10-08 10:20:09 -07001288 ResetUpdateProgress(prefs_, true);
Darin Petkov0406e402010-10-06 21:33:11 -07001289 TEST_AND_RETURN_FALSE(
Darin Petkov437adc42010-10-07 13:12:24 -07001290 prefs_->SetString(kPrefsUpdateStateSHA256Context,
Darin Petkov0406e402010-10-06 21:33:11 -07001291 hash_calculator_.GetContext()));
1292 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextDataOffset,
1293 buffer_offset_));
1294 last_updated_buffer_offset_ = buffer_offset_;
David Zeuthen41996ad2013-09-24 15:43:24 -07001295
1296 if (next_operation_num_ < num_total_operations_) {
1297 const bool is_kernel_partition =
1298 next_operation_num_ >= num_rootfs_operations_;
1299 const DeltaArchiveManifest_InstallOperation &op =
1300 is_kernel_partition ?
1301 manifest_.kernel_install_operations(
1302 next_operation_num_ - num_rootfs_operations_) :
1303 manifest_.install_operations(next_operation_num_);
1304 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextDataLength,
1305 op.data_length()));
1306 } else {
1307 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextDataLength,
1308 0));
1309 }
Darin Petkov0406e402010-10-06 21:33:11 -07001310 }
Darin Petkov73058b42010-10-06 16:32:19 -07001311 TEST_AND_RETURN_FALSE(prefs_->SetInt64(kPrefsUpdateStateNextOperation,
1312 next_operation_num_));
1313 return true;
1314}
1315
Darin Petkov9b230572010-10-08 10:20:09 -07001316bool DeltaPerformer::PrimeUpdateState() {
1317 CHECK(manifest_valid_);
1318 block_size_ = manifest_.block_size();
1319
1320 int64_t next_operation = kUpdateStateOperationInvalid;
1321 if (!prefs_->GetInt64(kPrefsUpdateStateNextOperation, &next_operation) ||
1322 next_operation == kUpdateStateOperationInvalid ||
1323 next_operation <= 0) {
1324 // Initiating a new update, no more state needs to be initialized.
Darin Petkov698d0412010-10-13 10:59:44 -07001325 TEST_AND_RETURN_FALSE(VerifySourcePartitions());
Darin Petkov9b230572010-10-08 10:20:09 -07001326 return true;
1327 }
1328 next_operation_num_ = next_operation;
1329
1330 // Resuming an update -- load the rest of the update state.
1331 int64_t next_data_offset = -1;
1332 TEST_AND_RETURN_FALSE(prefs_->GetInt64(kPrefsUpdateStateNextDataOffset,
1333 &next_data_offset) &&
1334 next_data_offset >= 0);
1335 buffer_offset_ = next_data_offset;
1336
Darin Petkov4f0a07b2011-05-25 16:47:20 -07001337 // The signed hash context and the signature blob may be empty if the
1338 // interrupted update didn't reach the signature.
Darin Petkov9b230572010-10-08 10:20:09 -07001339 prefs_->GetString(kPrefsUpdateStateSignedSHA256Context,
1340 &signed_hash_context_);
Darin Petkov4f0a07b2011-05-25 16:47:20 -07001341 string signature_blob;
1342 if (prefs_->GetString(kPrefsUpdateStateSignatureBlob, &signature_blob)) {
1343 signatures_message_data_.assign(signature_blob.begin(),
1344 signature_blob.end());
1345 }
Darin Petkov9b230572010-10-08 10:20:09 -07001346
1347 string hash_context;
1348 TEST_AND_RETURN_FALSE(prefs_->GetString(kPrefsUpdateStateSHA256Context,
1349 &hash_context) &&
1350 hash_calculator_.SetContext(hash_context));
1351
1352 int64_t manifest_metadata_size = 0;
1353 TEST_AND_RETURN_FALSE(prefs_->GetInt64(kPrefsManifestMetadataSize,
1354 &manifest_metadata_size) &&
1355 manifest_metadata_size > 0);
Gilad Arnoldfe133932014-01-14 12:25:50 -08001356 metadata_size_ = manifest_metadata_size;
Darin Petkov9b230572010-10-08 10:20:09 -07001357
Gilad Arnold8a86fa52013-01-15 12:35:05 -08001358 // Advance the download progress to reflect what doesn't need to be
1359 // re-downloaded.
1360 total_bytes_received_ += buffer_offset_;
1361
Darin Petkov61426142010-10-08 11:04:55 -07001362 // Speculatively count the resume as a failure.
1363 int64_t resumed_update_failures;
1364 if (prefs_->GetInt64(kPrefsResumedUpdateFailures, &resumed_update_failures)) {
1365 resumed_update_failures++;
1366 } else {
1367 resumed_update_failures = 1;
1368 }
1369 prefs_->SetInt64(kPrefsResumedUpdateFailures, resumed_update_failures);
Darin Petkov9b230572010-10-08 10:20:09 -07001370 return true;
1371}
1372
David Zeuthena99981f2013-04-29 13:42:47 -07001373void DeltaPerformer::SendUmaStat(ErrorCode code) {
Jay Srinivasan55f50c22013-01-10 19:24:35 -08001374 utils::SendErrorCodeToUma(system_state_, code);
Jay Srinivasanf0572052012-10-23 18:12:56 -07001375}
1376
Andrew de los Reyes09e56d62010-04-23 13:45:53 -07001377} // namespace chromeos_update_engine