* chore: bump chromium in DEPS to 122.0.6239.2 * chore: update patches * refactor: extensions replaced StringPiece with string_view Ref: https://chromium-review.googlesource.com/c/chromium/src/+/5171926 * chore: bump chromium in DEPS to 122.0.6240.0 * chore: update patches * chore: bump chromium in DEPS to 122.0.6241.5 * chore: bump chromium in DEPS to 122.0.6245.0 * chore: bump chromium in DEPS to 122.0.6247.0 * chore: bump chromium in DEPS to 122.0.6249.0 * chore: bump chromium in DEPS to 122.0.6251.0 * 5192010: Rename {absl => std}::optional in //chrome/ https://chromium-review.googlesource.com/c/chromium/src/+/5192010 * 5109767: CodeHealth: Fix leaked raw_ptr in Linux ProcessSingleton https://chromium-review.googlesource.com/c/chromium/src/+/5109767 * 5105227: [media_preview] Show requested device in permission bubble https://chromium-review.googlesource.com/c/chromium/src/+/5105227 * chore: bump chromium in DEPS to 122.0.6253.0 * chore: update patches * 5180720: Polish tiled browser window UI on Linux | https://chromium-review.googlesource.com/c/chromium/src/+/5180720 * chore: update patches * chore: bump chromium in DEPS to 122.0.6255.0 * chore: update patches * 5186276: [autopip] Make "allow once" per navigation | https://chromium-review.googlesource.com/c/chromium/src/+/5186276 * chore: bump chromium in DEPS to 122.0.6257.0 * chore: bump chromium in DEPS to 122.0.6259.0 * chore: update patches * 5190661: Automated T* -> raw_ptr<T> rewrite "refresh" | https://chromium-review.googlesource.com/c/chromium/src/+/5190661 * 5206106: Make sure RenderFrameHosts are active when printing | https://chromium-review.googlesource.com/c/chromium/src/+/5206106 * 5202674: Reland "Automated T* -> raw_ptr<T> rewrite 'refresh'" https://chromium-review.googlesource.com/c/chromium/src/+/5202674 * fixup CodeHealth: Fix leaked raw_ptr in Linux ProcessSingleton https://chromium-review.googlesource.com/c/chromium/src/+/5109767 * fixup 5206106: Make sure RenderFrameHosts are active when printing * Make legacy ToV8() helpers private to ScriptPromiseResolver, their only user https://chromium-review.googlesource.com/c/chromium/src/+/5207474 * fixup CodeHealth: Fix leaked raw_ptr in Linux ProcessSingleton * fixup 5186276: [autopip] Make "allow once" per navigation https://chromium-review.googlesource.com/c/chromium/src/+/5186276 * chore: update patches after rebase * chore: bump chromium in DEPS to 122.0.6260.0 * 5191363: Mark LOG(FATAL) [[noreturn]] https://chromium-review.googlesource.com/c/chromium/src/+/5191363 * fixup 5186276: [autopip] Make "allow once" per navigation https://chromium-review.googlesource.com/c/chromium/src/+/5186276 * fixup Make legacy ToV8() helpers private to ScriptPromiseResolver https://chromium-review.googlesource.com/c/chromium/src/+/5207474 * chore: update patches * chore: bump chromium in DEPS to 122.0.6261.0 * chore: update patches * chore: restore patch that was mistakenly removed * 5181931: Improve LoginHandler (Part 9 / N) https://chromium-review.googlesource.com/c/chromium/src/+/5181931 * Dispatch SiteInstanceGotProcess() only when both process and site are set. https://chromium-review.googlesource.com/c/chromium/src/+/5142354 * 5171446: [AsyncSB] Pass navigation_id into CreateURLLoaderThrottles https://chromium-review.googlesource.com/c/chromium/src/+/5171446 * 5213708: Move DownloadTargetInfo into components/download https://chromium-review.googlesource.com/c/chromium/src/+/5213708 * extensions: Add a loader for Controlled Frame embedder scripts https://chromium-review.googlesource.com/c/chromium/src/+/5202765 * [CSC][Zoom] Add initial_zoom_level to DisplayMediaInformation https://chromium-review.googlesource.com/c/chromium/src/+/5168626 * chore: bump chromium in DEPS to 123.0.6262.0 * chore: bump chromium in DEPS to 122.0.6261.6 * fix: suppress clang -Wimplicit-const-int-float-conversion * fixup 5191363: Mark LOG(FATAL) [[noreturn]] for Windows https://chromium-review.googlesource.com/c/chromium/src/+/5191363 * 5167921: Remove Widget::IsTranslucentWindowOpacitySupported https://chromium-review.googlesource.com/c/chromium/src/+/5167921 Also 5148392: PinnedState: Support pinned state in PlatformWindowState | https://chromium-review.googlesource.com/c/chromium/src/+/5148392 * fixup: 5180720: Polish tiled browser window UI on Linux https://chromium-review.googlesource.com/c/chromium/src/+/5180720 * 5170669: clipboard: Migrate DOMException constructors to RejectWith- https://chromium-review.googlesource.com/c/chromium/src/+/5170669 * 5178824: [Fullscreen] Record UKM data https://chromium-review.googlesource.com/c/chromium/src/+/5178824 * chore: update patches after rebase --------- Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com> Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com> Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: VerteDinde <vertedinde@electronjs.org> Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
		
			
				
	
	
		
			149 lines
		
	
	
	
		
			4.8 KiB
			
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
	
		
			4.8 KiB
			
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright (c) 2021 Slack Technologies, Inc.
 | 
						|
// Use of this source code is governed by the MIT license that can be
 | 
						|
// found in the LICENSE file.
 | 
						|
 | 
						|
#include "shell/browser/net/asar/asar_file_validator.h"
 | 
						|
 | 
						|
#include <algorithm>
 | 
						|
#include <string>
 | 
						|
#include <utility>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
#include "base/logging.h"
 | 
						|
#include "base/notreached.h"
 | 
						|
#include "base/strings/string_number_conversions.h"
 | 
						|
#include "base/strings/string_util.h"
 | 
						|
#include "crypto/sha2.h"
 | 
						|
 | 
						|
namespace asar {
 | 
						|
 | 
						|
AsarFileValidator::AsarFileValidator(IntegrityPayload integrity,
 | 
						|
                                     base::File file)
 | 
						|
    : file_(std::move(file)), integrity_(std::move(integrity)) {
 | 
						|
  current_block_ = 0;
 | 
						|
  max_block_ = integrity_.blocks.size() - 1;
 | 
						|
}
 | 
						|
 | 
						|
AsarFileValidator::~AsarFileValidator() = default;
 | 
						|
 | 
						|
void AsarFileValidator::OnRead(base::span<char> buffer,
 | 
						|
                               mojo::FileDataSource::ReadResult* result) {
 | 
						|
  DCHECK(!done_reading_);
 | 
						|
 | 
						|
  uint64_t buffer_size = result->bytes_read;
 | 
						|
 | 
						|
  // Compute how many bytes we should hash, and add them to the current hash.
 | 
						|
  uint32_t block_size = integrity_.block_size;
 | 
						|
  uint64_t bytes_added = 0;
 | 
						|
  while (bytes_added < buffer_size) {
 | 
						|
    if (current_block_ > max_block_) {
 | 
						|
      LOG(FATAL)
 | 
						|
          << "Unexpected number of blocks while validating ASAR file stream";
 | 
						|
    }
 | 
						|
 | 
						|
    // Create a hash if we don't have one yet
 | 
						|
    if (!current_hash_) {
 | 
						|
      current_hash_byte_count_ = 0;
 | 
						|
      switch (integrity_.algorithm) {
 | 
						|
        case HashAlgorithm::kSHA256:
 | 
						|
          current_hash_ =
 | 
						|
              crypto::SecureHash::Create(crypto::SecureHash::SHA256);
 | 
						|
          break;
 | 
						|
        case HashAlgorithm::kNone:
 | 
						|
          CHECK(false);
 | 
						|
          break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Compute how many bytes we should hash, and add them to the current hash.
 | 
						|
    // We need to either add just enough bytes to fill up a block (block_size -
 | 
						|
    // current_bytes) or use every remaining byte (buffer_size - bytes_added)
 | 
						|
    int bytes_to_hash = std::min(block_size - current_hash_byte_count_,
 | 
						|
                                 buffer_size - bytes_added);
 | 
						|
    DCHECK_GT(bytes_to_hash, 0);
 | 
						|
    current_hash_->Update(buffer.data() + bytes_added, bytes_to_hash);
 | 
						|
    bytes_added += bytes_to_hash;
 | 
						|
    current_hash_byte_count_ += bytes_to_hash;
 | 
						|
    total_hash_byte_count_ += bytes_to_hash;
 | 
						|
 | 
						|
    if (current_hash_byte_count_ == block_size && !FinishBlock()) {
 | 
						|
      LOG(FATAL) << "Failed to validate block while streaming ASAR file: "
 | 
						|
                 << current_block_;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool AsarFileValidator::FinishBlock() {
 | 
						|
  if (current_hash_byte_count_ == 0) {
 | 
						|
    if (!done_reading_ || current_block_ > max_block_) {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!current_hash_) {
 | 
						|
    // This happens when we fail to read the resource. Compute empty content's
 | 
						|
    // hash in this case.
 | 
						|
    current_hash_ = crypto::SecureHash::Create(crypto::SecureHash::SHA256);
 | 
						|
  }
 | 
						|
 | 
						|
  uint8_t actual[crypto::kSHA256Length];
 | 
						|
 | 
						|
  // If the file reader is done we need to make sure we've either read up to the
 | 
						|
  // end of the file (the check below) or up to the end of a block_size byte
 | 
						|
  // boundary. If the below check fails we compute the next block boundary, how
 | 
						|
  // many bytes are needed to get there and then we manually read those bytes
 | 
						|
  // from our own file handle ensuring the data producer is unaware but we can
 | 
						|
  // validate the hash still.
 | 
						|
  if (done_reading_ &&
 | 
						|
      total_hash_byte_count_ - extra_read_ != read_max_ - read_start_) {
 | 
						|
    uint64_t bytes_needed = std::min(
 | 
						|
        integrity_.block_size - current_hash_byte_count_,
 | 
						|
        read_max_ - read_start_ - total_hash_byte_count_ + extra_read_);
 | 
						|
    uint64_t offset = read_start_ + total_hash_byte_count_ - extra_read_;
 | 
						|
    std::vector<uint8_t> abandoned_buffer(bytes_needed);
 | 
						|
    if (!file_.ReadAndCheck(offset, abandoned_buffer)) {
 | 
						|
      LOG(FATAL) << "Failed to read required portion of streamed ASAR archive";
 | 
						|
    }
 | 
						|
 | 
						|
    current_hash_->Update(&abandoned_buffer.front(), bytes_needed);
 | 
						|
  }
 | 
						|
 | 
						|
  current_hash_->Finish(actual, sizeof(actual));
 | 
						|
  current_hash_.reset();
 | 
						|
  current_hash_byte_count_ = 0;
 | 
						|
 | 
						|
  const std::string expected_hash = integrity_.blocks[current_block_];
 | 
						|
  const std::string actual_hex_hash =
 | 
						|
      base::ToLowerASCII(base::HexEncode(actual, sizeof(actual)));
 | 
						|
 | 
						|
  if (expected_hash != actual_hex_hash) {
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  current_block_++;
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void AsarFileValidator::OnDone() {
 | 
						|
  DCHECK(!done_reading_);
 | 
						|
  done_reading_ = true;
 | 
						|
  if (!FinishBlock()) {
 | 
						|
    LOG(FATAL) << "Failed to validate block while ending ASAR file stream: "
 | 
						|
               << current_block_;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void AsarFileValidator::SetRange(uint64_t read_start,
 | 
						|
                                 uint64_t extra_read,
 | 
						|
                                 uint64_t read_max) {
 | 
						|
  read_start_ = read_start;
 | 
						|
  extra_read_ = extra_read;
 | 
						|
  read_max_ = read_max;
 | 
						|
}
 | 
						|
 | 
						|
void AsarFileValidator::SetCurrentBlock(int current_block) {
 | 
						|
  current_block_ = current_block;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace asar
 |