Commit 53796c72 authored by waffles's avatar waffles Committed by Commit bot

Sandbox the component updater's patcher utility process.

The code will now open files in the browser process before passing the
handles across IPC to the utility process. The utility process in turn
invokes courgette/bsdiff, which memory maps the files and operates on
them as before.

There is a behavioral difference when using the courgette or
courgette_mini tools: the output file will now be created/overwritten
at the start of the operation, and in the case of a failure, will be
deleted. Previously, the output file was created late in the operation
operation and several failure modes would leave it unmodified.

BUG=660325

Review-Url: https://codereview.chromium.org/2534873005
Cr-Commit-Position: refs/heads/master@{#437669}
parent fe95cd62
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "chrome/browser/component_updater/component_patcher_operation_out_of_process.h" #include "chrome/browser/component_updater/component_patcher_operation_out_of_process.h"
#include <memory>
#include <vector> #include <vector>
#include "base/bind.h" #include "base/bind.h"
...@@ -61,7 +62,6 @@ void PatchHost::StartProcess(std::unique_ptr<IPC::Message> message) { ...@@ -61,7 +62,6 @@ void PatchHost::StartProcess(std::unique_ptr<IPC::Message> message) {
this, base::ThreadTaskRunnerHandle::Get().get()); this, base::ThreadTaskRunnerHandle::Get().get());
host->SetName(l10n_util::GetStringUTF16( host->SetName(l10n_util::GetStringUTF16(
IDS_UTILITY_PROCESS_COMPONENT_PATCHER_NAME)); IDS_UTILITY_PROCESS_COMPONENT_PATCHER_NAME));
host->DisableSandbox();
host->Send(message.release()); host->Send(message.release());
} }
...@@ -102,13 +102,25 @@ void ChromeOutOfProcessPatcher::Patch( ...@@ -102,13 +102,25 @@ void ChromeOutOfProcessPatcher::Patch(
const base::FilePath& output_abs_path, const base::FilePath& output_abs_path,
base::Callback<void(int result)> callback) { base::Callback<void(int result)> callback) {
host_ = new PatchHost(callback, task_runner); host_ = new PatchHost(callback, task_runner);
IPC::PlatformFileForTransit input = IPC::TakePlatformFileForTransit(
base::File(
input_abs_path, base::File::FLAG_OPEN | base::File::FLAG_READ));
IPC::PlatformFileForTransit patch = IPC::TakePlatformFileForTransit(
base::File(
patch_abs_path, base::File::FLAG_OPEN | base::File::FLAG_READ));
IPC::PlatformFileForTransit output = IPC::TakePlatformFileForTransit(
base::File(
output_abs_path,
base::File::FLAG_CREATE |
base::File::FLAG_WRITE |
base::File::FLAG_EXCLUSIVE_WRITE));
std::unique_ptr<IPC::Message> patch_message; std::unique_ptr<IPC::Message> patch_message;
if (operation == update_client::kBsdiff) { if (operation == update_client::kBsdiff) {
patch_message.reset(new ChromeUtilityMsg_PatchFileBsdiff( patch_message.reset(new ChromeUtilityMsg_PatchFileBsdiff(
input_abs_path, patch_abs_path, output_abs_path)); input, patch, output));
} else if (operation == update_client::kCourgette) { } else if (operation == update_client::kCourgette) {
patch_message.reset(new ChromeUtilityMsg_PatchFileCourgette( patch_message.reset(new ChromeUtilityMsg_PatchFileCourgette(
input_abs_path, patch_abs_path, output_abs_path)); input, patch, output));
} else { } else {
NOTREACHED(); NOTREACHED();
} }
......
...@@ -144,17 +144,17 @@ IPC_STRUCT_END() ...@@ -144,17 +144,17 @@ IPC_STRUCT_END()
// and place the output in |output_file|. The patch should use the bsdiff // and place the output in |output_file|. The patch should use the bsdiff
// algorithm (Courgette's version). // algorithm (Courgette's version).
IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_PatchFileBsdiff, IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_PatchFileBsdiff,
base::FilePath /* input_file */, IPC::PlatformFileForTransit /* input_file */,
base::FilePath /* patch_file */, IPC::PlatformFileForTransit /* patch_file */,
base::FilePath /* output_file */) IPC::PlatformFileForTransit /* output_file */)
// Tell the utility process to patch the given |input_file| using |patch_file| // Tell the utility process to patch the given |input_file| using |patch_file|
// and place the output in |output_file|. The patch should use the Courgette // and place the output in |output_file|. The patch should use the Courgette
// algorithm. // algorithm.
IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_PatchFileCourgette, IPC_MESSAGE_CONTROL3(ChromeUtilityMsg_PatchFileCourgette,
base::FilePath /* input_file */, IPC::PlatformFileForTransit /* input_file */,
base::FilePath /* patch_file */, IPC::PlatformFileForTransit /* patch_file */,
base::FilePath /* output_file */) IPC::PlatformFileForTransit /* output_file */)
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
// Tell the utility process to create a zip file on the given list of files. // Tell the utility process to create a zip file on the given list of files.
......
...@@ -265,33 +265,26 @@ void ChromeContentUtilityClient::OnCreateZipFile( ...@@ -265,33 +265,26 @@ void ChromeContentUtilityClient::OnCreateZipFile(
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
void ChromeContentUtilityClient::OnPatchFileBsdiff( void ChromeContentUtilityClient::OnPatchFileBsdiff(
const base::FilePath& input_file, const IPC::PlatformFileForTransit& input_file,
const base::FilePath& patch_file, const IPC::PlatformFileForTransit& patch_file,
const base::FilePath& output_file) { const IPC::PlatformFileForTransit& output_file) {
if (input_file.empty() || patch_file.empty() || output_file.empty()) { const int patch_status = bsdiff::ApplyBinaryPatch(
Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1)); IPC::PlatformFileForTransitToFile(input_file),
} else { IPC::PlatformFileForTransitToFile(patch_file),
const int patch_status = bsdiff::ApplyBinaryPatch(input_file, IPC::PlatformFileForTransitToFile(output_file));
patch_file, Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
output_file);
Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
}
ReleaseProcessIfNeeded(); ReleaseProcessIfNeeded();
} }
void ChromeContentUtilityClient::OnPatchFileCourgette( void ChromeContentUtilityClient::OnPatchFileCourgette(
const base::FilePath& input_file, const IPC::PlatformFileForTransit& input_file,
const base::FilePath& patch_file, const IPC::PlatformFileForTransit& patch_file,
const base::FilePath& output_file) { const IPC::PlatformFileForTransit& output_file) {
if (input_file.empty() || patch_file.empty() || output_file.empty()) { const int patch_status = courgette::ApplyEnsemblePatch(
Send(new ChromeUtilityHostMsg_PatchFile_Finished(-1)); IPC::PlatformFileForTransitToFile(input_file),
} else { IPC::PlatformFileForTransitToFile(patch_file),
const int patch_status = courgette::ApplyEnsemblePatch( IPC::PlatformFileForTransitToFile(output_file));
input_file.value().c_str(), Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
patch_file.value().c_str(),
output_file.value().c_str());
Send(new ChromeUtilityHostMsg_PatchFile_Finished(patch_status));
}
ReleaseProcessIfNeeded(); ReleaseProcessIfNeeded();
} }
......
...@@ -50,12 +50,12 @@ class ChromeContentUtilityClient : public content::ContentUtilityClient { ...@@ -50,12 +50,12 @@ class ChromeContentUtilityClient : public content::ContentUtilityClient {
const base::FileDescriptor& dest_fd); const base::FileDescriptor& dest_fd);
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
void OnPatchFileBsdiff(const base::FilePath& input_file, void OnPatchFileBsdiff(const IPC::PlatformFileForTransit& input_file,
const base::FilePath& patch_file, const IPC::PlatformFileForTransit& patch_file,
const base::FilePath& output_file); const IPC::PlatformFileForTransit& output_file);
void OnPatchFileCourgette(const base::FilePath& input_file, void OnPatchFileCourgette(const IPC::PlatformFileForTransit& input_file,
const base::FilePath& patch_file, const IPC::PlatformFileForTransit& patch_file,
const base::FilePath& output_file); const IPC::PlatformFileForTransit& output_file);
void OnStartupPing(); void OnStartupPing();
#if defined(FULL_SAFE_BROWSING) #if defined(FULL_SAFE_BROWSING)
void OnAnalyzeZipFileForDownloadProtection( void OnAnalyzeZipFileForDownloadProtection(
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <stddef.h> // Required to define size_t on GCC #include <stddef.h> // Required to define size_t on GCC
#include "base/files/file.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
namespace courgette { namespace courgette {
...@@ -73,6 +74,15 @@ class EncodedProgram; ...@@ -73,6 +74,15 @@ class EncodedProgram;
Status ApplyEnsemblePatch(SourceStream* old, SourceStream* patch, Status ApplyEnsemblePatch(SourceStream* old, SourceStream* patch,
SinkStream* output); SinkStream* output);
// Applies the patch in |patch_file| to the bytes in |old_file| and writes the
// transformed ensemble to |new_file|.
// Returns C_OK unless something went wrong.
// This function first validates that the patch file has a proper header, so the
// function can be used to 'try' a patch.
Status ApplyEnsemblePatch(base::File old_file,
base::File patch_file,
base::File new_file);
// Applies the patch in |patch_file_name| to the bytes in |old_file_name| and // Applies the patch in |patch_file_name| to the bytes in |old_file_name| and
// writes the transformed ensemble to |new_file_name|. // writes the transformed ensemble to |new_file_name|.
// Returns C_OK unless something went wrong. // Returns C_OK unless something went wrong.
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include "base/files/file.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/files/memory_mapped_file.h" #include "base/files/memory_mapped_file.h"
#include "base/logging.h" #include "base/logging.h"
...@@ -371,33 +372,31 @@ Status ApplyEnsemblePatch(SourceStream* base, ...@@ -371,33 +372,31 @@ Status ApplyEnsemblePatch(SourceStream* base,
return C_OK; return C_OK;
} }
Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name, Status ApplyEnsemblePatch(base::File old_file,
const base::FilePath::CharType* patch_file_name, base::File patch_file,
const base::FilePath::CharType* new_file_name) { base::File new_file) {
base::FilePath patch_file_path(patch_file_name); base::MemoryMappedFile patch_file_mem;
base::MemoryMappedFile patch_file; if (!patch_file_mem.Initialize(std::move(patch_file)))
if (!patch_file.Initialize(patch_file_path))
return C_READ_OPEN_ERROR; return C_READ_OPEN_ERROR;
// 'Dry-run' the first step of the patch process to validate format of header. // 'Dry-run' the first step of the patch process to validate format of header.
SourceStream patch_header_stream; SourceStream patch_header_stream;
patch_header_stream.Init(patch_file.data(), patch_file.length()); patch_header_stream.Init(patch_file_mem.data(), patch_file_mem.length());
EnsemblePatchApplication patch_process; EnsemblePatchApplication patch_process;
Status status = patch_process.ReadHeader(&patch_header_stream); Status status = patch_process.ReadHeader(&patch_header_stream);
if (status != C_OK) if (status != C_OK)
return status; return status;
// Read the old_file. // Read the old_file.
base::FilePath old_file_path(old_file_name); base::MemoryMappedFile old_file_mem;
base::MemoryMappedFile old_file; if (!old_file_mem.Initialize(std::move(old_file)))
if (!old_file.Initialize(old_file_path))
return C_READ_ERROR; return C_READ_ERROR;
// Apply patch on streams. // Apply patch on streams.
SourceStream old_source_stream; SourceStream old_source_stream;
SourceStream patch_source_stream; SourceStream patch_source_stream;
old_source_stream.Init(old_file.data(), old_file.length()); old_source_stream.Init(old_file_mem.data(), old_file_mem.length());
patch_source_stream.Init(patch_file.data(), patch_file.length()); patch_source_stream.Init(patch_file_mem.data(), patch_file_mem.length());
SinkStream new_sink_stream; SinkStream new_sink_stream;
status = ApplyEnsemblePatch(&old_source_stream, &patch_source_stream, status = ApplyEnsemblePatch(&old_source_stream, &patch_source_stream,
&new_sink_stream); &new_sink_stream);
...@@ -405,12 +404,10 @@ Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name, ...@@ -405,12 +404,10 @@ Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name,
return status; return status;
// Write the patched data to |new_file_name|. // Write the patched data to |new_file_name|.
base::FilePath new_file_path(new_file_name); int written = new_file.Write(
int written = 0,
base::WriteFile( reinterpret_cast<const char*>(new_sink_stream.Buffer()),
new_file_path, static_cast<int>(new_sink_stream.Length()));
reinterpret_cast<const char*>(new_sink_stream.Buffer()),
static_cast<int>(new_sink_stream.Length()));
if (written == -1) if (written == -1)
return C_WRITE_OPEN_ERROR; return C_WRITE_OPEN_ERROR;
if (static_cast<size_t>(written) != new_sink_stream.Length()) if (static_cast<size_t>(written) != new_sink_stream.Length())
...@@ -419,4 +416,24 @@ Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name, ...@@ -419,4 +416,24 @@ Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name,
return C_OK; return C_OK;
} }
} // namespace Status ApplyEnsemblePatch(const base::FilePath::CharType* old_file_name,
const base::FilePath::CharType* patch_file_name,
const base::FilePath::CharType* new_file_name) {
Status result = ApplyEnsemblePatch(
base::File(
base::FilePath(old_file_name),
base::File::FLAG_OPEN | base::File::FLAG_READ),
base::File(
base::FilePath(patch_file_name),
base::File::FLAG_OPEN | base::File::FLAG_READ),
base::File(
base::FilePath(new_file_name),
base::File::FLAG_CREATE_ALWAYS |
base::File::FLAG_WRITE |
base::File::FLAG_EXCLUSIVE_WRITE));
if (result != C_OK)
base::DeleteFile(base::FilePath(new_file_name), false);
return result;
}
} // namespace courgette
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include <stdint.h> #include <stdint.h>
#include "base/files/file.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
namespace courgette { namespace courgette {
...@@ -76,6 +77,11 @@ BSDiffStatus ApplyBinaryPatch(courgette::SourceStream* old_stream, ...@@ -76,6 +77,11 @@ BSDiffStatus ApplyBinaryPatch(courgette::SourceStream* old_stream,
courgette::SourceStream* patch_stream, courgette::SourceStream* patch_stream,
courgette::SinkStream* new_stream); courgette::SinkStream* new_stream);
// As above, but simply takes base::Files.
BSDiffStatus ApplyBinaryPatch(base::File old_stream,
base::File patch_stream,
base::File new_stream);
// As above, but simply takes the file paths. // As above, but simply takes the file paths.
BSDiffStatus ApplyBinaryPatch(const base::FilePath& old_stream, BSDiffStatus ApplyBinaryPatch(const base::FilePath& old_stream,
const base::FilePath& patch_stream, const base::FilePath& patch_stream,
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "base/files/file_util.h"
#include "base/files/memory_mapped_file.h" #include "base/files/memory_mapped_file.h"
#include "courgette/crc.h" #include "courgette/crc.h"
#include "courgette/streams.h" #include "courgette/streams.h"
...@@ -189,24 +190,24 @@ BSDiffStatus ApplyBinaryPatch(SourceStream* old_stream, ...@@ -189,24 +190,24 @@ BSDiffStatus ApplyBinaryPatch(SourceStream* old_stream,
return OK; return OK;
} }
BSDiffStatus ApplyBinaryPatch(const base::FilePath& old_file_path, BSDiffStatus ApplyBinaryPatch(base::File old_file,
const base::FilePath& patch_file_path, base::File patch_file,
const base::FilePath& new_file_path) { base::File new_file) {
// Set up the old stream. // Set up the old stream.
base::MemoryMappedFile old_file; base::MemoryMappedFile old_file_mem;
if (!old_file.Initialize(old_file_path)) { if (!old_file_mem.Initialize(std::move(old_file))) {
return READ_ERROR; return READ_ERROR;
} }
SourceStream old_file_stream; SourceStream old_file_stream;
old_file_stream.Init(old_file.data(), old_file.length()); old_file_stream.Init(old_file_mem.data(), old_file_mem.length());
// Set up the patch stream. // Set up the patch stream.
base::MemoryMappedFile patch_file; base::MemoryMappedFile patch_file_mem;
if (!patch_file.Initialize(patch_file_path)) { if (!patch_file_mem.Initialize(std::move(patch_file))) {
return READ_ERROR; return READ_ERROR;
} }
SourceStream patch_file_stream; SourceStream patch_file_stream;
patch_file_stream.Init(patch_file.data(), patch_file.length()); patch_file_stream.Init(patch_file_mem.data(), patch_file_mem.length());
// Set up the new stream and apply the patch. // Set up the new stream and apply the patch.
SinkStream new_sink_stream; SinkStream new_sink_stream;
...@@ -217,12 +218,33 @@ BSDiffStatus ApplyBinaryPatch(const base::FilePath& old_file_path, ...@@ -217,12 +218,33 @@ BSDiffStatus ApplyBinaryPatch(const base::FilePath& old_file_path,
} }
// Write the stream to disk. // Write the stream to disk.
int written = base::WriteFile( int written = new_file.Write(
new_file_path, reinterpret_cast<const char*>(new_sink_stream.Buffer()), 0,
reinterpret_cast<const char*>(new_sink_stream.Buffer()),
static_cast<int>(new_sink_stream.Length())); static_cast<int>(new_sink_stream.Length()));
if (written != static_cast<int>(new_sink_stream.Length())) if (written != static_cast<int>(new_sink_stream.Length()))
return WRITE_ERROR; return WRITE_ERROR;
return OK; return OK;
} }
BSDiffStatus ApplyBinaryPatch(const base::FilePath& old_file_path,
const base::FilePath& patch_file_path,
const base::FilePath& new_file_path) {
BSDiffStatus result = ApplyBinaryPatch(
base::File(
old_file_path,
base::File::FLAG_OPEN | base::File::FLAG_READ),
base::File(
patch_file_path,
base::File::FLAG_OPEN | base::File::FLAG_READ),
base::File(
new_file_path,
base::File::FLAG_CREATE_ALWAYS |
base::File::FLAG_WRITE |
base::File::FLAG_EXCLUSIVE_WRITE));
if (result != OK)
base::DeleteFile(new_file_path, false);
return result;
}
} // namespace bsdiff } // namespace bsdiff
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment