Commit 6908d45e authored by Greg Thompson's avatar Greg Thompson Committed by Commit Bot

Update the last-modified time of modified PE files.

Windows does not necessarily change the last-modified time of files that
are modified via a r/w file mapping. This CL explicitly sets the
last-modified time on PE files (.exes and .dlls) modified by
alternate_version_generator.exe. This is significant because it appears
that the Windows loader does some caching of data about an .exe and
doesn't flush this cache if a new file with the same last-modified time
as an old file appears. This caused Chrome launches to fail with
STATUS_OBJECT_NAME_NOT_FOUND (0xC0000034).

BUG=461856
R=huangs@chromium.org, mmeade@chromium.org

Change-Id: Ic0e0f68ef9ca62e02bb828267352c2f7052ff908
Reviewed-on: https://chromium-review.googlesource.com/1009705
Commit-Queue: Greg Thompson <grt@chromium.org>
Reviewed-by: default avatarSamuel Huang <huangs@chromium.org>
Cr-Commit-Position: refs/heads/master@{#550532}
parent fd7e0290
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "chrome/installer/test/alternate_version_generator.h" #include "chrome/installer/test/alternate_version_generator.h"
#include <windows.h> #include <windows.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
...@@ -48,6 +49,7 @@ ...@@ -48,6 +49,7 @@
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/version.h" #include "base/version.h"
#include "base/win/pe_image.h" #include "base/win/pe_image.h"
#include "base/win/scoped_handle.h" #include "base/win/scoped_handle.h"
...@@ -315,17 +317,17 @@ void VisitResource(const upgrade_test::EntryPath& path, ...@@ -315,17 +317,17 @@ void VisitResource(const upgrade_test::EntryPath& path,
// Updates version strings found in an image's .rdata (read-only data) section. // Updates version strings found in an image's .rdata (read-only data) section.
// This handles uses of CHROME_VERSION_STRING (e.g., chrome::kChromeVersion). // This handles uses of CHROME_VERSION_STRING (e.g., chrome::kChromeVersion).
// Version numbers found even as substrings of larger strings are updated. // Version numbers found even as substrings of larger strings are updated.
bool UpdateVersionInData(const base::win::PEImage& image, bool UpdateVersionInData(base::win::PEImage* image,
VisitResourceContext* context) { VisitResourceContext* context) {
DCHECK_EQ(context->current_version_str.size(), DCHECK_EQ(context->current_version_str.size(),
context->new_version_str.size()); context->new_version_str.size());
IMAGE_SECTION_HEADER* rdata_header = IMAGE_SECTION_HEADER* rdata_header =
image.GetImageSectionHeaderByName(".rdata"); image->GetImageSectionHeaderByName(".rdata");
if (!rdata_header) if (!rdata_header)
return true; // Nothing to update. return true; // Nothing to update.
size_t size = rdata_header->SizeOfRawData; size_t size = rdata_header->SizeOfRawData;
uint8_t* data = reinterpret_cast<uint8_t*>(image.module()) + uint8_t* data = reinterpret_cast<uint8_t*>(image->module()) +
rdata_header->PointerToRawData; rdata_header->PointerToRawData;
// Replace all wide string occurrences of |current_version| with // Replace all wide string occurrences of |current_version| with
...@@ -360,7 +362,6 @@ bool UpdateVersionIfMatch(const base::FilePath& image_file, ...@@ -360,7 +362,6 @@ bool UpdateVersionIfMatch(const base::FilePath& image_file,
return false; return false;
} }
bool result = false;
uint32_t flags = base::File::FLAG_OPEN | base::File::FLAG_READ | uint32_t flags = base::File::FLAG_OPEN | base::File::FLAG_READ |
base::File::FLAG_WRITE | base::File::FLAG_EXCLUSIVE_READ | base::File::FLAG_WRITE | base::File::FLAG_EXCLUSIVE_READ |
base::File::FLAG_EXCLUSIVE_WRITE; base::File::FLAG_EXCLUSIVE_WRITE;
...@@ -376,26 +377,37 @@ bool UpdateVersionIfMatch(const base::FilePath& image_file, ...@@ -376,26 +377,37 @@ bool UpdateVersionIfMatch(const base::FilePath& image_file,
file.Initialize(image_file, flags); file.Initialize(image_file, flags);
} }
if (file.IsValid()) { if (!file.IsValid()) {
base::MemoryMappedFile image_mapping;
if (image_mapping.Initialize(std::move(file),
base::MemoryMappedFile::READ_WRITE)) {
base::win::PEImageAsData image(
reinterpret_cast<HMODULE>(image_mapping.data()));
// PEImage class does not support other-architecture images.
if (image.GetNTHeaders()->OptionalHeader.Magic ==
IMAGE_NT_OPTIONAL_HDR_MAGIC) {
result = upgrade_test::EnumResources(
image, &VisitResource, reinterpret_cast<uintptr_t>(context));
result = result && UpdateVersionInData(image, context);
} else {
result = true;
}
}
} else {
PLOG(DFATAL) << "Failed to open \"" << image_file.value() << "\""; PLOG(DFATAL) << "Failed to open \"" << image_file.value() << "\"";
return false;
} }
return result;
// Map the file into memory for modification (give the mapping its own handle
// to the file so that its last-modified time can be updated below).
base::MemoryMappedFile image_mapping;
if (!image_mapping.Initialize(file.Duplicate(),
base::MemoryMappedFile::READ_WRITE)) {
return false;
}
base::win::PEImageAsData image(
reinterpret_cast<HMODULE>(image_mapping.data()));
// PEImage class does not support other-architecture images. Skip over such
// files.
if (image.GetNTHeaders()->OptionalHeader.Magic !=
IMAGE_NT_OPTIONAL_HDR_MAGIC) {
return true;
}
// Explicitly update the last-modified time of the file if modifications are
// successfully made. This is required to convince the Windows loader that the
// modified file is distinct from the original. Windows does not necessarily
// update the last-modified time of a file that is written to via a read-write
// mapping.
return upgrade_test::EnumResources(image, &VisitResource,
reinterpret_cast<uintptr_t>(context)) &&
UpdateVersionInData(&image, context) &&
file.SetTimes(base::Time(), base::Time::Now());
} }
bool UpdateManifestVersion(const base::FilePath& manifest, bool UpdateManifestVersion(const base::FilePath& manifest,
......
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