зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 1639030) for MDA failures in dom/media/test/test_eme_autoplay.html. CLOSED TREE
Backed out changeset e614d160ab92 (bug 1639030) Backed out changeset e93c2e3b1e62 (bug 1639030) Backed out changeset c40a82e96834 (bug 1639030)
This commit is contained in:
Родитель
6aa252b6bf
Коммит
feebf13084
|
@ -15,6 +15,4 @@
|
|||
|
||||
#include "build/buildflag.h"
|
||||
|
||||
#define BUILDFLAG_INTERNAL_USE_TCMALLOC() (0)
|
||||
|
||||
#endif // BASE_ALLOCATOR_BUILDFLAGS_H_
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a dummy version of base/debug/crash_logging.cc
|
||||
|
||||
#include "base/debug/crash_logging.h"
|
||||
|
||||
namespace base {
|
||||
namespace debug {
|
||||
|
||||
CrashKeyString* AllocateCrashKeyString(const char name[],
|
||||
CrashKeySize value_length) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SetCrashKeyString(CrashKeyString* crash_key, base::StringPiece value) {}
|
||||
|
||||
} // namespace debug
|
||||
} // namespace base
|
|
@ -4,24 +4,18 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a dummy version of Chromium source file base/debug/stack_trace.h
|
||||
// to provide a dummy class StackTrace.
|
||||
// This is a dummy version of Chromium source file base/debug/stack_trace.h.
|
||||
// To provide a dummy class StackTrace required in base/win/scoped_handle.cc.
|
||||
|
||||
#ifndef BASE_DEBUG_STACK_TRACE_H_
|
||||
#define BASE_DEBUG_STACK_TRACE_H_
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
namespace base {
|
||||
namespace debug {
|
||||
|
||||
class BASE_EXPORT StackTrace {
|
||||
public:
|
||||
StackTrace() {};
|
||||
|
||||
#if !defined(__UCLIBC__) & !defined(_AIX)
|
||||
void OutputToStream(std::ostream*) const {}
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace debug
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#ifndef BASE_FEATURE_LIST_H_
|
||||
#define BASE_FEATURE_LIST_H_
|
||||
|
||||
#include "base/macros.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// Specifies whether a given feature is enabled or disabled by default.
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
#include "base/files/file_path.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
using StringType = FilePath::StringType;
|
||||
|
@ -16,41 +18,6 @@ namespace {
|
|||
|
||||
const FilePath::CharType kStringTerminator = FILE_PATH_LITERAL('\0');
|
||||
|
||||
// If this FilePath contains a drive letter specification, returns the
|
||||
// position of the last character of the drive letter specification,
|
||||
// otherwise returns npos. This can only be true on Windows, when a pathname
|
||||
// begins with a letter followed by a colon. On other platforms, this always
|
||||
// returns npos.
|
||||
StringPieceType::size_type FindDriveLetter(StringPieceType path) {
|
||||
#if defined(FILE_PATH_USES_DRIVE_LETTERS)
|
||||
// This is dependent on an ASCII-based character set, but that's a
|
||||
// reasonable assumption. iswalpha can be too inclusive here.
|
||||
if (path.length() >= 2 && path[1] == L':' &&
|
||||
((path[0] >= L'A' && path[0] <= L'Z') ||
|
||||
(path[0] >= L'a' && path[0] <= L'z'))) {
|
||||
return 1;
|
||||
}
|
||||
#endif // FILE_PATH_USES_DRIVE_LETTERS
|
||||
return StringType::npos;
|
||||
}
|
||||
|
||||
bool IsPathAbsolute(StringPieceType path) {
|
||||
#if defined(FILE_PATH_USES_DRIVE_LETTERS)
|
||||
StringType::size_type letter = FindDriveLetter(path);
|
||||
if (letter != StringType::npos) {
|
||||
// Look for a separator right after the drive specification.
|
||||
return path.length() > letter + 1 &&
|
||||
FilePath::IsSeparator(path[letter + 1]);
|
||||
}
|
||||
// Look for a pair of leading separators.
|
||||
return path.length() > 1 &&
|
||||
FilePath::IsSeparator(path[0]) && FilePath::IsSeparator(path[1]);
|
||||
#else // FILE_PATH_USES_DRIVE_LETTERS
|
||||
// Look for a separator in the first position.
|
||||
return path.length() > 0 && FilePath::IsSeparator(path[0]);
|
||||
#endif // FILE_PATH_USES_DRIVE_LETTERS
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
FilePath::FilePath() = default;
|
||||
|
@ -70,148 +37,4 @@ FilePath& FilePath::operator=(const FilePath& that) = default;
|
|||
|
||||
FilePath& FilePath::operator=(FilePath&& that) = default;
|
||||
|
||||
// static
|
||||
bool FilePath::IsSeparator(CharType character) {
|
||||
for (size_t i = 0; i < kSeparatorsLength - 1; ++i) {
|
||||
if (character == kSeparators[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// libgen's dirname and basename aren't guaranteed to be thread-safe and aren't
|
||||
// guaranteed to not modify their input strings, and in fact are implemented
|
||||
// differently in this regard on different platforms. Don't use them, but
|
||||
// adhere to their behavior.
|
||||
FilePath FilePath::DirName() const {
|
||||
FilePath new_path(path_);
|
||||
new_path.StripTrailingSeparatorsInternal();
|
||||
|
||||
// The drive letter, if any, always needs to remain in the output. If there
|
||||
// is no drive letter, as will always be the case on platforms which do not
|
||||
// support drive letters, letter will be npos, or -1, so the comparisons and
|
||||
// resizes below using letter will still be valid.
|
||||
StringType::size_type letter = FindDriveLetter(new_path.path_);
|
||||
|
||||
StringType::size_type last_separator =
|
||||
new_path.path_.find_last_of(kSeparators, StringType::npos,
|
||||
kSeparatorsLength - 1);
|
||||
if (last_separator == StringType::npos) {
|
||||
// path_ is in the current directory.
|
||||
new_path.path_.resize(letter + 1);
|
||||
} else if (last_separator == letter + 1) {
|
||||
// path_ is in the root directory.
|
||||
new_path.path_.resize(letter + 2);
|
||||
} else if (last_separator == letter + 2 &&
|
||||
IsSeparator(new_path.path_[letter + 1])) {
|
||||
// path_ is in "//" (possibly with a drive letter); leave the double
|
||||
// separator intact indicating alternate root.
|
||||
new_path.path_.resize(letter + 3);
|
||||
} else if (last_separator != 0) {
|
||||
// path_ is somewhere else, trim the basename.
|
||||
new_path.path_.resize(last_separator);
|
||||
}
|
||||
|
||||
new_path.StripTrailingSeparatorsInternal();
|
||||
if (!new_path.path_.length())
|
||||
new_path.path_ = kCurrentDirectory;
|
||||
|
||||
return new_path;
|
||||
}
|
||||
|
||||
FilePath FilePath::BaseName() const {
|
||||
FilePath new_path(path_);
|
||||
new_path.StripTrailingSeparatorsInternal();
|
||||
|
||||
// The drive letter, if any, is always stripped.
|
||||
StringType::size_type letter = FindDriveLetter(new_path.path_);
|
||||
if (letter != StringType::npos) {
|
||||
new_path.path_.erase(0, letter + 1);
|
||||
}
|
||||
|
||||
// Keep everything after the final separator, but if the pathname is only
|
||||
// one character and it's a separator, leave it alone.
|
||||
StringType::size_type last_separator =
|
||||
new_path.path_.find_last_of(kSeparators, StringType::npos,
|
||||
kSeparatorsLength - 1);
|
||||
if (last_separator != StringType::npos &&
|
||||
last_separator < new_path.path_.length() - 1) {
|
||||
new_path.path_.erase(0, last_separator + 1);
|
||||
}
|
||||
|
||||
return new_path;
|
||||
}
|
||||
|
||||
FilePath FilePath::Append(StringPieceType component) const {
|
||||
StringPieceType appended = component;
|
||||
StringType without_nuls;
|
||||
|
||||
StringType::size_type nul_pos = component.find(kStringTerminator);
|
||||
if (nul_pos != StringPieceType::npos) {
|
||||
without_nuls = StringType(component.substr(0, nul_pos));
|
||||
appended = StringPieceType(without_nuls);
|
||||
}
|
||||
|
||||
DCHECK(!IsPathAbsolute(appended));
|
||||
|
||||
if (path_.compare(kCurrentDirectory) == 0 && !appended.empty()) {
|
||||
// Append normally doesn't do any normalization, but as a special case,
|
||||
// when appending to kCurrentDirectory, just return a new path for the
|
||||
// component argument. Appending component to kCurrentDirectory would
|
||||
// serve no purpose other than needlessly lengthening the path, and
|
||||
// it's likely in practice to wind up with FilePath objects containing
|
||||
// only kCurrentDirectory when calling DirName on a single relative path
|
||||
// component.
|
||||
return FilePath(appended);
|
||||
}
|
||||
|
||||
FilePath new_path(path_);
|
||||
new_path.StripTrailingSeparatorsInternal();
|
||||
|
||||
// Don't append a separator if the path is empty (indicating the current
|
||||
// directory) or if the path component is empty (indicating nothing to
|
||||
// append).
|
||||
if (!appended.empty() && !new_path.path_.empty()) {
|
||||
// Don't append a separator if the path still ends with a trailing
|
||||
// separator after stripping (indicating the root directory).
|
||||
if (!IsSeparator(new_path.path_.back())) {
|
||||
// Don't append a separator if the path is just a drive letter.
|
||||
if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) {
|
||||
new_path.path_.append(1, kSeparators[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_path.path_.append(appended.data(), appended.size());
|
||||
return new_path;
|
||||
}
|
||||
|
||||
FilePath FilePath::Append(const FilePath& component) const {
|
||||
return Append(component.value());
|
||||
}
|
||||
|
||||
void FilePath::StripTrailingSeparatorsInternal() {
|
||||
// If there is no drive letter, start will be 1, which will prevent stripping
|
||||
// the leading separator if there is only one separator. If there is a drive
|
||||
// letter, start will be set appropriately to prevent stripping the first
|
||||
// separator following the drive letter, if a separator immediately follows
|
||||
// the drive letter.
|
||||
StringType::size_type start = FindDriveLetter(path_) + 2;
|
||||
|
||||
StringType::size_type last_stripped = StringType::npos;
|
||||
for (StringType::size_type pos = path_.length();
|
||||
pos > start && IsSeparator(path_[pos - 1]);
|
||||
--pos) {
|
||||
// If the string only has two separators and they're at the beginning,
|
||||
// don't strip them, unless the string began with more than two separators.
|
||||
if (pos != start + 1 || last_stripped == start + 2 ||
|
||||
!IsSeparator(path_[start - 1])) {
|
||||
path_.resize(pos - 1);
|
||||
last_stripped = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a copy of a file that is generated by the chromium build, with
|
||||
// only the build flags we require.
|
||||
|
||||
// Generated by build/write_buildflag_header.py
|
||||
// From "//base:logging_buildflags"
|
||||
|
||||
#ifndef BASE_LOGGING_BUILDFLAGS_H_
|
||||
#define BASE_LOGGING_BUILDFLAGS_H_
|
||||
|
||||
#include "build/buildflag.h"
|
||||
|
||||
#define BUILDFLAG_INTERNAL_ENABLE_LOG_ERROR_NOT_REACHED() (0)
|
||||
|
||||
#endif // BASE_LOGGING_BUILDFLAGS_H_
|
|
@ -24,9 +24,9 @@ class BASE_EXPORT SharedMemoryTracker {
|
|||
return instance;
|
||||
}
|
||||
|
||||
void IncrementMemoryUsage(const SharedMemoryMapping& mapping) {};
|
||||
void IncrementMemoryUsage(const SharedMemory& shared_memory) {};
|
||||
|
||||
void DecrementMemoryUsage(const SharedMemoryMapping& mapping) {};
|
||||
void DecrementMemoryUsage(const SharedMemory& shared_memory) {};
|
||||
|
||||
private:
|
||||
SharedMemoryTracker() {};
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#ifndef BASE_METRICS_HISTOGRAM_MACROS_H_
|
||||
#define BASE_METRICS_HISTOGRAM_MACROS_H_
|
||||
|
||||
#define UMA_HISTOGRAM_ENUMERATION(name, sample) do { } while (0)
|
||||
#define UMA_HISTOGRAM_ENUMERATION(name, sample, enum_max) do { } while (0)
|
||||
#define SCOPED_UMA_HISTOGRAM_TIMER(name) do { } while (0)
|
||||
|
||||
#endif // BASE_METRICS_HISTOGRAM_MACROS_H_
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a cut down version of //base/observer_list.h
|
||||
|
||||
#ifndef BASE_OBSERVER_LIST_H_
|
||||
#define BASE_OBSERVER_LIST_H_
|
||||
|
||||
#endif // BASE_OBSERVER_LIST_H_
|
|
@ -1,25 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a reduced version of Chromium's //base/process/launch.h
|
||||
// to satisfy compiler.
|
||||
|
||||
#ifndef BASE_PROCESS_LAUNCH_H_
|
||||
#define BASE_PROCESS_LAUNCH_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/environment.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
#if defined(OS_WIN)
|
||||
typedef std::vector<HANDLE> HandlesToInheritVector;
|
||||
#endif
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_PROCESS_LAUNCH_H_
|
|
@ -1,17 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "base/process/memory.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
void TerminateBecauseOutOfMemory(size_t size) {
|
||||
MOZ_CRASH("Hit base::TerminateBecauseOutOfMemory");
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -35,8 +35,7 @@ namespace internal {
|
|||
|
||||
class BASE_EXPORT ScopedBlockingCallWithBaseSyncPrimitives {
|
||||
public:
|
||||
ScopedBlockingCallWithBaseSyncPrimitives(const Location& from_here,
|
||||
BlockingType blocking_type) {}
|
||||
ScopedBlockingCallWithBaseSyncPrimitives(BlockingType blocking_type) {};
|
||||
~ScopedBlockingCallWithBaseSyncPrimitives() {};
|
||||
};
|
||||
|
||||
|
|
|
@ -330,30 +330,6 @@ DeriveAppContainerSidFromAppContainerName(
|
|||
#define PROC_THREAD_ATTRIBUTE_ALL_APPLICATION_PACKAGES_POLICY \
|
||||
ProcThreadAttributeValue (ProcThreadAttributeAllApplicationPackagesPolicy, FALSE, TRUE, FALSE)
|
||||
|
||||
//
|
||||
// Define functions declared only when _WIN32_WINNT >= 0x0A00
|
||||
//
|
||||
|
||||
WINBASEAPI
|
||||
BOOL
|
||||
WINAPI
|
||||
IsWow64Process2(
|
||||
_In_ HANDLE hProcess,
|
||||
_Out_ USHORT* pProcessMachine,
|
||||
_Out_opt_ USHORT* pNativeMachine
|
||||
);
|
||||
|
||||
#endif // (_WIN32_WINNT < 0x0A00)
|
||||
|
||||
#if defined(__MINGW32__)
|
||||
|
||||
// winnt.h
|
||||
#define THREAD_DYNAMIC_CODE_ALLOW 1 // Opt-out of dynamic code generation.
|
||||
|
||||
// Mingw uses an old version THREAD_INFORMATION_CLASS defined in winbase.h
|
||||
// where ThreadDynamicCodePolicy does not exist.
|
||||
#define ThreadDynamicCodePolicy static_cast<THREAD_INFORMATION_CLASS>(2)
|
||||
|
||||
#endif // defined(__MINGW32__)
|
||||
#endif // (_WIN32_WINNT >= 0x0A00)
|
||||
|
||||
#endif // _SECURITY_SANDBOX_BASE_SHIM_SDKDECLS_H_
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a partial implementation of Chromium's source file
|
||||
// base/win/win_util.cc
|
||||
|
||||
#include "base/win/win_util.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_util.h"
|
||||
|
||||
namespace base {
|
||||
namespace win {
|
||||
|
||||
std::wstring GetWindowObjectName(HANDLE handle) {
|
||||
// Get the size of the name.
|
||||
std::wstring object_name;
|
||||
|
||||
DWORD size = 0;
|
||||
::GetUserObjectInformation(handle, UOI_NAME, nullptr, 0, &size);
|
||||
if (!size) {
|
||||
DPCHECK(false);
|
||||
return object_name;
|
||||
}
|
||||
|
||||
LOG_ASSERT(size % sizeof(wchar_t) == 0u);
|
||||
|
||||
// Query the name of the object.
|
||||
if (!::GetUserObjectInformation(
|
||||
handle, UOI_NAME, WriteInto(&object_name, size / sizeof(wchar_t)),
|
||||
size, &size)) {
|
||||
DPCHECK(false);
|
||||
}
|
||||
|
||||
return object_name;
|
||||
}
|
||||
|
||||
} // namespace win
|
||||
} // namespace base
|
|
@ -1,26 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a partial implementation of Chromium's source file
|
||||
// base/win/win_util.h
|
||||
|
||||
#ifndef BASE_WIN_WIN_UTIL_H_
|
||||
#define BASE_WIN_WIN_UTIL_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
|
||||
namespace base {
|
||||
namespace win {
|
||||
|
||||
// Returns the name of a desktop or a window station.
|
||||
BASE_EXPORT std::wstring GetWindowObjectName(HANDLE handle);
|
||||
|
||||
} // namespace win
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_WIN_WIN_UTIL_H_
|
|
@ -30,5 +30,5 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/registry_policy.cc b/secu
|
|||
// |access| with the new value.
|
||||
NTSTATUS TranslateMaximumAllowed(OBJECT_ATTRIBUTES* obj_attributes,
|
||||
DWORD* access) {
|
||||
NtOpenKeyFunction NtOpenKey = nullptr;
|
||||
NtOpenKeyFunction NtOpenKey = NULL;
|
||||
ResolveNTFunctionPtr("NtOpenKey", &NtOpenKey);
|
||||
|
|
|
@ -132,7 +132,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.c
|
|||
break;
|
||||
|
||||
@@ -227,32 +246,39 @@ TargetNtQueryAttributesFile(NtQueryAttri
|
||||
ResultCode code = CrossCall(ipc, IpcTag::NTQUERYATTRIBUTESFILE, name.get(),
|
||||
ResultCode code = CrossCall(ipc, IPC_NTQUERYATTRIBUTESFILE_TAG, name.get(),
|
||||
attributes, file_info, &answer);
|
||||
|
||||
if (SBOX_ALL_OK != code)
|
||||
|
@ -173,7 +173,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.c
|
|||
break;
|
||||
@@ -284,16 +310,20 @@ NTSTATUS WINAPI TargetNtQueryFullAttribu
|
||||
CrossCallReturn answer = {0};
|
||||
ResultCode code = CrossCall(ipc, IpcTag::NTQUERYFULLATTRIBUTESFILE,
|
||||
ResultCode code = CrossCall(ipc, IPC_NTQUERYFULLATTRIBUTESFILE_TAG,
|
||||
name.get(), attributes, file_info, &answer);
|
||||
|
||||
if (SBOX_ALL_OK != code)
|
||||
|
@ -213,7 +213,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.c
|
|||
break;
|
||||
@@ -366,14 +398,15 @@ TargetNtSetInformationFile(NtSetInformat
|
||||
ResultCode code =
|
||||
CrossCall(ipc, IpcTag::NTSETINFO_RENAME, file, io_status_buffer,
|
||||
CrossCall(ipc, IPC_NTSETINFO_RENAME_TAG, file, io_status_buffer,
|
||||
file_info_buffer, length, file_info_class, &answer);
|
||||
|
||||
if (SBOX_ALL_OK != code)
|
||||
|
@ -249,7 +249,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/handle_interception.cc b/
|
|||
DWORD desired_access,
|
||||
DWORD options) {
|
||||
@@ -29,17 +30,19 @@ ResultCode DuplicateHandleProxy(HANDLE s
|
||||
ResultCode code = CrossCall(ipc, IpcTag::DUPLICATEHANDLEPROXY,
|
||||
ResultCode code = CrossCall(ipc, IPC_DUPLICATEHANDLEPROXY_TAG,
|
||||
source_handle, target_process_id,
|
||||
desired_access, options, &answer);
|
||||
if (SBOX_ALL_OK != code)
|
||||
|
@ -652,64 +652,6 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/registry_interception.cc
|
|||
}
|
||||
|
||||
} // namespace sandbox
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/signed_interception.cc b/security/sandbox/chromium/sandbox/win/src/signed_interception.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/signed_interception.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/signed_interception.cc
|
||||
@@ -9,16 +9,17 @@
|
||||
#include "sandbox/win/src/crosscall_client.h"
|
||||
#include "sandbox/win/src/ipc_tags.h"
|
||||
#include "sandbox/win/src/policy_params.h"
|
||||
#include "sandbox/win/src/policy_target.h"
|
||||
#include "sandbox/win/src/sandbox_factory.h"
|
||||
#include "sandbox/win/src/sandbox_nt_util.h"
|
||||
#include "sandbox/win/src/sharedmem_ipc_client.h"
|
||||
#include "sandbox/win/src/target_services.h"
|
||||
+#include "mozilla/sandboxing/sandboxLogging.h"
|
||||
|
||||
namespace sandbox {
|
||||
|
||||
NTSTATUS WINAPI
|
||||
TargetNtCreateSection(NtCreateSectionFunction orig_CreateSection,
|
||||
PHANDLE section_handle,
|
||||
ACCESS_MASK desired_access,
|
||||
POBJECT_ATTRIBUTES object_attributes,
|
||||
@@ -37,16 +38,18 @@ TargetNtCreateSection(NtCreateSectionFun
|
||||
break;
|
||||
if (maximum_size)
|
||||
break;
|
||||
if (section_page_protection != PAGE_EXECUTE)
|
||||
break;
|
||||
if (allocation_attributes != SEC_IMAGE)
|
||||
break;
|
||||
|
||||
+ mozilla::sandboxing::LogBlocked("NtCreateSection");
|
||||
+
|
||||
// IPC must be fully started.
|
||||
void* memory = GetGlobalIPCMemory();
|
||||
if (!memory)
|
||||
break;
|
||||
|
||||
std::unique_ptr<wchar_t, NtAllocDeleter> path;
|
||||
|
||||
if (!NtGetPathFromHandle(file_handle, &path))
|
||||
@@ -73,16 +76,17 @@ TargetNtCreateSection(NtCreateSectionFun
|
||||
if (code != SBOX_ALL_OK)
|
||||
break;
|
||||
|
||||
if (!NT_SUCCESS(answer.nt_status))
|
||||
break;
|
||||
|
||||
__try {
|
||||
*section_handle = answer.handle;
|
||||
+ mozilla::sandboxing::LogAllowed("NtCreateSection");
|
||||
return answer.nt_status;
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) {
|
||||
break;
|
||||
}
|
||||
} while (false);
|
||||
|
||||
// Fall back to the original API in all failure cases.
|
||||
return orig_CreateSection(section_handle, desired_access, object_attributes,
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/sync_interception.cc b/security/sandbox/chromium/sandbox/win/src/sync_interception.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sync_interception.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sync_interception.cc
|
||||
|
|
|
@ -14,14 +14,14 @@ https://hg.mozilla.org/mozilla-central/rev/0f64b24c40c4
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
||||
@@ -213,16 +213,25 @@ bool FilesystemDispatcher::NtQueryAttrib
|
||||
@@ -221,16 +221,25 @@ bool FilesystemDispatcher::NtQueryAttrib
|
||||
params[FileName::BROKER] = ParamPickerMake(broker);
|
||||
|
||||
// To evaluate the policy we need to call back to the policy object. We
|
||||
// are just middlemen in the operation since is the FileSystemPolicy which
|
||||
// knows what to do.
|
||||
EvalResult result =
|
||||
policy_base_->EvalPolicy(IpcTag::NTQUERYATTRIBUTESFILE, params.GetBase());
|
||||
policy_base_->EvalPolicy(IPC_NTQUERYATTRIBUTESFILE_TAG, params.GetBase());
|
||||
|
||||
+ // If the policies forbid access (any result other than ASK_BROKER),
|
||||
+ // then check for user-granted access to file.
|
||||
|
@ -40,14 +40,14 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
|||
information, &nt_status)) {
|
||||
ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
|
||||
return true;
|
||||
@@ -253,16 +262,25 @@ bool FilesystemDispatcher::NtQueryFullAt
|
||||
@@ -261,16 +270,25 @@ bool FilesystemDispatcher::NtQueryFullAt
|
||||
params[FileName::BROKER] = ParamPickerMake(broker);
|
||||
|
||||
// To evaluate the policy we need to call back to the policy object. We
|
||||
// are just middlemen in the operation since is the FileSystemPolicy which
|
||||
// knows what to do.
|
||||
EvalResult result = policy_base_->EvalPolicy(
|
||||
IpcTag::NTQUERYFULLATTRIBUTESFILE, params.GetBase());
|
||||
IPC_NTQUERYFULLATTRIBUTESFILE_TAG, params.GetBase());
|
||||
|
||||
+ // If the policies forbid access (any result other than ASK_BROKER),
|
||||
+ // then check for user-granted access to file.
|
||||
|
@ -66,14 +66,14 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
|||
&nt_status)) {
|
||||
ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
|
||||
return true;
|
||||
@@ -306,16 +324,26 @@ bool FilesystemDispatcher::NtSetInformat
|
||||
@@ -316,16 +334,26 @@ bool FilesystemDispatcher::NtSetInformat
|
||||
params[FileName::BROKER] = ParamPickerMake(broker);
|
||||
|
||||
// To evaluate the policy we need to call back to the policy object. We
|
||||
// are just middlemen in the operation since is the FileSystemPolicy which
|
||||
// knows what to do.
|
||||
EvalResult result =
|
||||
policy_base_->EvalPolicy(IpcTag::NTSETINFO_RENAME, params.GetBase());
|
||||
policy_base_->EvalPolicy(IPC_NTSETINFO_RENAME_TAG, params.GetBase());
|
||||
|
||||
+ // If the policies forbid access (any result other than ASK_BROKER),
|
||||
+ // then check for user-granted write access to file. We only permit
|
||||
|
@ -96,7 +96,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc b/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc
|
||||
@@ -227,19 +227,16 @@ TargetNtQueryAttributesFile(NtQueryAttri
|
||||
@@ -223,19 +223,16 @@ NTSTATUS WINAPI TargetNtQueryAttributesF
|
||||
sizeof(FILE_BASIC_INFORMATION));
|
||||
|
||||
uint32_t broker = BROKER_FALSE;
|
||||
|
@ -105,18 +105,18 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.c
|
|||
params[FileName::NAME] = ParamPickerMake(name_ptr);
|
||||
params[FileName::BROKER] = ParamPickerMake(broker);
|
||||
|
||||
- if (!QueryBroker(IpcTag::NTQUERYATTRIBUTESFILE, params.GetBase()))
|
||||
- if (!QueryBroker(IPC_NTQUERYATTRIBUTESFILE_TAG, params.GetBase()))
|
||||
- break;
|
||||
-
|
||||
SharedMemIPCClient ipc(memory);
|
||||
CrossCallReturn answer = {0};
|
||||
ResultCode code = CrossCall(ipc, IpcTag::NTQUERYATTRIBUTESFILE, name.get(),
|
||||
ResultCode code = CrossCall(ipc, IPC_NTQUERYATTRIBUTESFILE_TAG, name.get(),
|
||||
attributes, file_info, &answer);
|
||||
|
||||
if (SBOX_ALL_OK != code)
|
||||
break;
|
||||
|
||||
@@ -292,19 +289,16 @@ NTSTATUS WINAPI TargetNtQueryFullAttribu
|
||||
@@ -290,19 +287,16 @@ NTSTATUS WINAPI TargetNtQueryFullAttribu
|
||||
sizeof(FILE_NETWORK_OPEN_INFORMATION));
|
||||
|
||||
uint32_t broker = BROKER_FALSE;
|
||||
|
@ -125,18 +125,18 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.c
|
|||
params[FileName::NAME] = ParamPickerMake(name_ptr);
|
||||
params[FileName::BROKER] = ParamPickerMake(broker);
|
||||
|
||||
- if (!QueryBroker(IpcTag::NTQUERYFULLATTRIBUTESFILE, params.GetBase()))
|
||||
- if (!QueryBroker(IPC_NTQUERYFULLATTRIBUTESFILE_TAG, params.GetBase()))
|
||||
- break;
|
||||
-
|
||||
SharedMemIPCClient ipc(memory);
|
||||
CrossCallReturn answer = {0};
|
||||
ResultCode code = CrossCall(ipc, IpcTag::NTQUERYFULLATTRIBUTESFILE,
|
||||
ResultCode code = CrossCall(ipc, IPC_NTQUERYFULLATTRIBUTESFILE_TAG,
|
||||
name.get(), attributes, file_info, &answer);
|
||||
|
||||
if (SBOX_ALL_OK != code)
|
||||
break;
|
||||
|
||||
@@ -374,19 +368,16 @@ TargetNtSetInformationFile(NtSetInformat
|
||||
@@ -369,19 +363,16 @@ NTSTATUS WINAPI TargetNtSetInformationFi
|
||||
break;
|
||||
|
||||
uint32_t broker = BROKER_FALSE;
|
||||
|
@ -145,7 +145,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.c
|
|||
params[FileName::NAME] = ParamPickerMake(name_ptr);
|
||||
params[FileName::BROKER] = ParamPickerMake(broker);
|
||||
|
||||
- if (!QueryBroker(IpcTag::NTSETINFO_RENAME, params.GetBase()))
|
||||
- if (!QueryBroker(IPC_NTSETINFO_RENAME_TAG, params.GetBase()))
|
||||
- break;
|
||||
-
|
||||
InOutCountedBuffer io_status_buffer(io_status, sizeof(IO_STATUS_BLOCK));
|
||||
|
|
|
@ -12,7 +12,7 @@ https://hg.mozilla.org/mozilla-central/rev/c70d06fa5302
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/sandbox/chromium/sandbox/win/src/win_utils.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/win_utils.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/win_utils.cc
|
||||
@@ -194,61 +194,66 @@ bool ResolveRegistryName(std::wstring na
|
||||
@@ -190,62 +190,67 @@ bool ResolveRegistryName(base::string16
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -22,12 +22,12 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/s
|
|||
// \Device\HarddiskVolume0\some\foo\bar
|
||||
// \??\HarddiskVolume0\some\foo\bar
|
||||
+// \??\UNC\SERVER\Share\some\foo\bar
|
||||
DWORD IsReparsePoint(const std::wstring& full_path) {
|
||||
DWORD IsReparsePoint(const base::string16& full_path) {
|
||||
// Check if it's a pipe. We can't query the attributes of a pipe.
|
||||
if (IsPipe(full_path))
|
||||
return ERROR_NOT_A_REPARSE_POINT;
|
||||
|
||||
std::wstring path;
|
||||
base::string16 path;
|
||||
bool nt_path = IsNTPath(full_path, &path);
|
||||
bool has_drive = StartsWithDriveLetter(path);
|
||||
bool is_device_path = IsDevicePath(path, &path);
|
||||
|
@ -37,13 +37,13 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/s
|
|||
|
||||
- bool added_implied_device = false;
|
||||
if (!has_drive) {
|
||||
- path = std::wstring(kNTDotPrefix) + path;
|
||||
- path = base::string16(kNTDotPrefix) + path;
|
||||
- added_implied_device = true;
|
||||
+ // Add Win32 device namespace prefix, required for some Windows APIs.
|
||||
+ path.insert(0, kNTDotPrefix);
|
||||
}
|
||||
|
||||
- std::wstring::size_type last_pos = std::wstring::npos;
|
||||
- base::string16::size_type last_pos = base::string16::npos;
|
||||
- bool passed_once = false;
|
||||
+ // Ensure that volume path matches start of path.
|
||||
+ wchar_t vol_path[MAX_PATH];
|
||||
|
@ -73,6 +73,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/s
|
|||
- (path.rfind(L'\\') == kNTDotPrefixLen - 1)) {
|
||||
- break;
|
||||
- }
|
||||
NOTREACHED_NT();
|
||||
return error;
|
||||
}
|
||||
} else if (FILE_ATTRIBUTE_REPARSE_POINT & attributes) {
|
||||
|
@ -93,12 +94,12 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/s
|
|||
// we'll get from |handle| will be \device\harddiskvolume1\some\foo\bar.
|
||||
bool SameObject(HANDLE handle, const wchar_t* full_path) {
|
||||
// Check if it's a pipe.
|
||||
@@ -258,63 +263,67 @@ bool SameObject(HANDLE handle, const wch
|
||||
std::wstring actual_path;
|
||||
@@ -256,63 +261,67 @@ bool SameObject(HANDLE handle, const wch
|
||||
base::string16 actual_path;
|
||||
if (!GetPathFromHandle(handle, &actual_path))
|
||||
return false;
|
||||
|
||||
std::wstring path(full_path);
|
||||
base::string16 path(full_path);
|
||||
DCHECK_NT(!path.empty());
|
||||
|
||||
// This may end with a backslash.
|
||||
|
@ -118,7 +119,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/s
|
|||
bool has_drive = StartsWithDriveLetter(path);
|
||||
|
||||
if (!has_drive && nt_path) {
|
||||
std::wstring simple_actual_path;
|
||||
base::string16 simple_actual_path;
|
||||
- if (!IsDevicePath(actual_path, &simple_actual_path))
|
||||
- return false;
|
||||
-
|
||||
|
@ -186,5 +187,5 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/s
|
|||
|
||||
// Just make a best effort here. There are lots of corner cases that we're
|
||||
// not expecting - and will fail to make long.
|
||||
bool ConvertToLongPath(std::wstring* native_path,
|
||||
const std::wstring* drive_letter) {
|
||||
bool ConvertToLongPath(base::string16* native_path,
|
||||
const base::string16* drive_letter) {
|
||||
|
|
|
@ -6,10 +6,32 @@
|
|||
# Parent 5ef34aa8c8918649528048dd60907862a4355e29
|
||||
Bug 1515088 Part 2: Set LoaderThreads to 1 in the RTL_USER_PROCESS_PARAMETERS structure on child process start-up. r=aklotz
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/nt_internals.h b/security/sandbox/chromium/sandbox/win/src/nt_internals.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/nt_internals.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/nt_internals.h
|
||||
@@ -312,16 +312,18 @@ typedef enum _PROCESSINFOCLASS {
|
||||
// Partial definition only.
|
||||
typedef struct _PEB {
|
||||
BYTE InheritedAddressSpace;
|
||||
BYTE ReadImageFileExecOptions;
|
||||
BYTE BeingDebugged;
|
||||
BYTE SpareBool;
|
||||
PVOID Mutant;
|
||||
PVOID ImageBaseAddress;
|
||||
+ PVOID Ldr;
|
||||
+ PVOID ProcessParameters;
|
||||
} PEB, *PPEB;
|
||||
|
||||
typedef LONG KPRIORITY;
|
||||
|
||||
typedef struct _PROCESS_BASIC_INFORMATION {
|
||||
union {
|
||||
NTSTATUS ExitStatus;
|
||||
PVOID padding_for_x64_0;
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/sandbox/chromium/sandbox/win/src/win_utils.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/win_utils.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/win_utils.cc
|
||||
@@ -456,20 +456,21 @@ bool GetNtPathFromWin32Path(const std::w
|
||||
@@ -453,20 +453,21 @@ bool GetNtPathFromWin32Path(const base::
|
||||
bool rv = GetPathFromHandle(file, nt_path);
|
||||
::CloseHandle(file);
|
||||
return rv;
|
||||
|
@ -33,7 +55,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/s
|
|||
::WriteProcessMemory(child_process, address, buffer, length, &written) &&
|
||||
(length == written);
|
||||
|
||||
@@ -544,16 +545,40 @@ void* GetProcessBaseAddress(HANDLE proce
|
||||
@@ -511,16 +512,40 @@ void* GetProcessBaseAddress(HANDLE proce
|
||||
&bytes_read) ||
|
||||
(sizeof(magic) != bytes_read)) {
|
||||
return nullptr;
|
||||
|
@ -51,7 +73,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/s
|
|||
+ // field so there is a, probably small, risk that it might change or move in
|
||||
+ // the future. In order to slightly guard against that we only update if the
|
||||
+ // value is currently 0.
|
||||
+ auto processParameters = reinterpret_cast<uint8_t*>(peb.ProcessParameters);
|
||||
+ uint8_t* processParameters = static_cast<uint8_t*>(peb.ProcessParameters);
|
||||
+ const uint32_t loaderThreadsOffset = 0x40c;
|
||||
+ uint32_t maxLoaderThreads = 0;
|
||||
+ BOOL memoryRead = ::ReadProcessMemory(
|
||||
|
@ -69,16 +91,16 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.cc b/security/s
|
|||
return base_address;
|
||||
}
|
||||
|
||||
DWORD GetTokenInformation(HANDLE token,
|
||||
TOKEN_INFORMATION_CLASS info_class,
|
||||
std::unique_ptr<BYTE[]>* buffer) {
|
||||
// Get the required buffer size.
|
||||
DWORD size = 0;
|
||||
}; // namespace sandbox
|
||||
|
||||
void ResolveNTFunctionPtr(const char* name, void* ptr) {
|
||||
static volatile HMODULE ntdll = NULL;
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.h b/security/sandbox/chromium/sandbox/win/src/win_utils.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/win_utils.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/win_utils.h
|
||||
@@ -111,17 +111,18 @@ HKEY GetReservedKeyFromName(const std::w
|
||||
bool ResolveRegistryName(std::wstring name, std::wstring* resolved_name);
|
||||
@@ -102,17 +102,18 @@ HKEY GetReservedKeyFromName(const base::
|
||||
bool ResolveRegistryName(base::string16 name, base::string16* resolved_name);
|
||||
|
||||
// Writes |length| bytes from the provided |buffer| into the address space of
|
||||
// |child_process|, at the specified |address|, preserving the original write
|
||||
|
@ -90,10 +112,10 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/win_utils.h b/security/sa
|
|||
+ size_t length,
|
||||
+ DWORD writeProtection = PAGE_WRITECOPY);
|
||||
|
||||
// Allocates |buffer_bytes| in child (PAGE_READWRITE) and copies data
|
||||
// from |local_buffer| in this process into |child|. |remote_buffer|
|
||||
// contains the address in the chile. If a zero byte copy is
|
||||
// requested |true| is returned and no allocation or copying is
|
||||
// attempted. Returns false if allocation or copying fails. If
|
||||
// copying fails, the allocation will be reversed.
|
||||
bool CopyToChildMemory(HANDLE child,
|
||||
// Returns true if the provided path points to a pipe.
|
||||
bool IsPipe(const base::string16& path);
|
||||
|
||||
// Converts a NTSTATUS code to a Win32 error code.
|
||||
DWORD GetLastErrorFromNtStatus(NTSTATUS status);
|
||||
|
||||
// Returns the address of the main exe module in memory taking in account
|
||||
|
|
|
@ -30,10 +30,10 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
|||
FilesystemDispatcher::FilesystemDispatcher(PolicyBase* policy_base)
|
||||
: policy_base_(policy_base) {
|
||||
static const IPCCall create_params = {
|
||||
{IpcTag::NTCREATEFILE,
|
||||
{WCHAR_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE,
|
||||
UINT32_TYPE, UINT32_TYPE}},
|
||||
@@ -105,16 +107,26 @@ bool FilesystemDispatcher::NtCreateFile(
|
||||
{IPC_NTCREATEFILE_TAG,
|
||||
{WCHAR_TYPE,
|
||||
UINT32_TYPE,
|
||||
@@ -110,16 +112,26 @@ bool FilesystemDispatcher::NtCreateFile(
|
||||
params[OpenFile::OPTIONS] = ParamPickerMake(create_options);
|
||||
params[OpenFile::BROKER] = ParamPickerMake(broker);
|
||||
|
||||
|
@ -41,7 +41,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
|||
// are just middlemen in the operation since is the FileSystemPolicy which
|
||||
// knows what to do.
|
||||
EvalResult result =
|
||||
policy_base_->EvalPolicy(IpcTag::NTCREATEFILE, params.GetBase());
|
||||
policy_base_->EvalPolicy(IPC_NTCREATEFILE_TAG, params.GetBase());
|
||||
+
|
||||
+ // If the policies forbid access (any result other than ASK_BROKER),
|
||||
+ // then check for user-granted access to file.
|
||||
|
@ -60,7 +60,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
|||
file_attributes, share_access, create_disposition, create_options,
|
||||
&handle, &nt_status, &io_information)) {
|
||||
ipc->return_info.nt_status = STATUS_ACCESS_DENIED;
|
||||
@@ -150,16 +162,26 @@ bool FilesystemDispatcher::NtOpenFile(IP
|
||||
@@ -157,16 +169,26 @@ bool FilesystemDispatcher::NtOpenFile(IP
|
||||
params[OpenFile::OPTIONS] = ParamPickerMake(open_options);
|
||||
params[OpenFile::BROKER] = ParamPickerMake(broker);
|
||||
|
||||
|
@ -68,7 +68,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
|||
// are just middlemen in the operation since is the FileSystemPolicy which
|
||||
// knows what to do.
|
||||
EvalResult result =
|
||||
policy_base_->EvalPolicy(IpcTag::NTOPENFILE, params.GetBase());
|
||||
policy_base_->EvalPolicy(IPC_NTOPENFILE_TAG, params.GetBase());
|
||||
+
|
||||
+ // If the policies forbid access (any result other than ASK_BROKER),
|
||||
+ // then check for user-granted access to file.
|
||||
|
@ -90,7 +90,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_dispatcher.cc
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc b/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc
|
||||
@@ -75,19 +75,16 @@ NTSTATUS WINAPI TargetNtCreateFile(NtCre
|
||||
@@ -70,19 +70,16 @@ NTSTATUS WINAPI TargetNtCreateFile(NtCre
|
||||
CountedParameterSet<OpenFile> params;
|
||||
const wchar_t* name_ptr = name.get();
|
||||
params[OpenFile::NAME] = ParamPickerMake(name_ptr);
|
||||
|
@ -99,7 +99,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.c
|
|||
params[OpenFile::OPTIONS] = ParamPickerMake(options_uint32);
|
||||
params[OpenFile::BROKER] = ParamPickerMake(broker);
|
||||
|
||||
- if (!QueryBroker(IpcTag::NTCREATEFILE, params.GetBase()))
|
||||
- if (!QueryBroker(IPC_NTCREATEFILE_TAG, params.GetBase()))
|
||||
- break;
|
||||
-
|
||||
SharedMemIPCClient ipc(memory);
|
||||
|
@ -107,25 +107,25 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.c
|
|||
// The following call must match in the parameters with
|
||||
// FilesystemDispatcher::ProcessNtCreateFile.
|
||||
ResultCode code =
|
||||
CrossCall(ipc, IpcTag::NTCREATEFILE, name.get(), attributes,
|
||||
CrossCall(ipc, IPC_NTCREATEFILE_TAG, name.get(), attributes,
|
||||
desired_access_uint32, file_attributes, sharing, disposition,
|
||||
options_uint32, &answer);
|
||||
@@ -160,19 +157,16 @@ NTSTATUS WINAPI TargetNtOpenFile(NtOpenF
|
||||
const wchar_t* name_ptr = name.get();
|
||||
@@ -154,19 +151,16 @@ NTSTATUS WINAPI TargetNtOpenFile(NtOpenF
|
||||
CountedParameterSet<OpenFile> params;
|
||||
const wchar_t* name_ptr = name.get();
|
||||
params[OpenFile::NAME] = ParamPickerMake(name_ptr);
|
||||
params[OpenFile::ACCESS] = ParamPickerMake(desired_access_uint32);
|
||||
params[OpenFile::DISPOSITION] = ParamPickerMake(disposition_uint32);
|
||||
params[OpenFile::OPTIONS] = ParamPickerMake(options_uint32);
|
||||
params[OpenFile::BROKER] = ParamPickerMake(broker);
|
||||
|
||||
- if (!QueryBroker(IpcTag::NTOPENFILE, params.GetBase()))
|
||||
- if (!QueryBroker(IPC_NTOPENFILE_TAG, params.GetBase()))
|
||||
- break;
|
||||
-
|
||||
SharedMemIPCClient ipc(memory);
|
||||
CrossCallReturn answer = {0};
|
||||
ResultCode code =
|
||||
CrossCall(ipc, IpcTag::NTOPENFILE, name.get(), attributes,
|
||||
CrossCall(ipc, IPC_NTOPENFILE_TAG, name.get(), attributes,
|
||||
desired_access_uint32, sharing, options_uint32, &answer);
|
||||
if (SBOX_ALL_OK != code)
|
||||
break;
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
# HG changeset patch
|
||||
# User Bob Owen <bobowencode@gmail.com>
|
||||
# Date 1577387989 0
|
||||
# Thu Dec 26 19:19:49 2019 +0000
|
||||
# Node ID 32adf437117bdca54be4959813acbb604f65137f
|
||||
# Parent 214214029beb6cca606e11ba519d11cc7dbb37af
|
||||
Bug 1605867: Don't duplicate IPC shared memory when we might fail to launch the process correctly. r=handyman
|
||||
|
||||
Differential Revision: https://phabricator.services.mozilla.com/D58271
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/target_process.cc b/security/sandbox/chromium/sandbox/win/src/target_process.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/target_process.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/target_process.cc
|
||||
@@ -286,45 +286,28 @@ ResultCode TargetProcess::Init(Dispatche
|
||||
shared_section_.Set(::CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr,
|
||||
PAGE_READWRITE | SEC_COMMIT, 0,
|
||||
shared_mem_size, nullptr));
|
||||
if (!shared_section_.IsValid()) {
|
||||
*win_error = ::GetLastError();
|
||||
return SBOX_ERROR_CREATE_FILE_MAPPING;
|
||||
}
|
||||
|
||||
- DWORD access = FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY;
|
||||
- HANDLE target_shared_section;
|
||||
- if (!::DuplicateHandle(::GetCurrentProcess(), shared_section_.Get(),
|
||||
- sandbox_process_info_.process_handle(),
|
||||
- &target_shared_section, access, false, 0)) {
|
||||
- *win_error = ::GetLastError();
|
||||
- return SBOX_ERROR_DUPLICATE_SHARED_SECTION;
|
||||
- }
|
||||
-
|
||||
void* shared_memory = ::MapViewOfFile(
|
||||
shared_section_.Get(), FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0);
|
||||
if (!shared_memory) {
|
||||
*win_error = ::GetLastError();
|
||||
return SBOX_ERROR_MAP_VIEW_OF_SHARED_SECTION;
|
||||
}
|
||||
|
||||
CopyPolicyToTarget(policy, shared_policy_size,
|
||||
reinterpret_cast<char*>(shared_memory) + shared_IPC_size);
|
||||
|
||||
ResultCode ret;
|
||||
// Set the global variables in the target. These are not used on the broker.
|
||||
- g_shared_section = target_shared_section;
|
||||
- ret = TransferVariable("g_shared_section", &g_shared_section,
|
||||
- sizeof(g_shared_section));
|
||||
- g_shared_section = nullptr;
|
||||
- if (SBOX_ALL_OK != ret) {
|
||||
- *win_error = ::GetLastError();
|
||||
- return ret;
|
||||
- }
|
||||
g_shared_IPC_size = shared_IPC_size;
|
||||
ret = TransferVariable("g_shared_IPC_size", &g_shared_IPC_size,
|
||||
sizeof(g_shared_IPC_size));
|
||||
g_shared_IPC_size = 0;
|
||||
if (SBOX_ALL_OK != ret) {
|
||||
*win_error = ::GetLastError();
|
||||
return ret;
|
||||
}
|
||||
@@ -339,16 +322,34 @@ ResultCode TargetProcess::Init(Dispatche
|
||||
|
||||
ipc_server_.reset(new SharedMemIPCServer(
|
||||
sandbox_process_info_.process_handle(),
|
||||
sandbox_process_info_.process_id(), thread_pool_, ipc_dispatcher));
|
||||
|
||||
if (!ipc_server_->Init(shared_memory, shared_IPC_size, kIPCChannelSize))
|
||||
return SBOX_ERROR_NO_SPACE;
|
||||
|
||||
+ DWORD access = FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY;
|
||||
+ HANDLE target_shared_section;
|
||||
+ if (!::DuplicateHandle(::GetCurrentProcess(), shared_section_.Get(),
|
||||
+ sandbox_process_info_.process_handle(),
|
||||
+ &target_shared_section, access, false, 0)) {
|
||||
+ *win_error = ::GetLastError();
|
||||
+ return SBOX_ERROR_DUPLICATE_SHARED_SECTION;
|
||||
+ }
|
||||
+
|
||||
+ g_shared_section = target_shared_section;
|
||||
+ ret = TransferVariable("g_shared_section", &g_shared_section,
|
||||
+ sizeof(g_shared_section));
|
||||
+ g_shared_section = nullptr;
|
||||
+ if (SBOX_ALL_OK != ret) {
|
||||
+ *win_error = ::GetLastError();
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
// After this point we cannot use this handle anymore.
|
||||
::CloseHandle(sandbox_process_info_.TakeThreadHandle());
|
||||
|
||||
return SBOX_ALL_OK;
|
||||
}
|
||||
|
||||
void TargetProcess::Terminate() {
|
||||
if (!sandbox_process_info_.IsValid())
|
|
@ -5,4 +5,3 @@ consult_PermissionsService_for_file_access.patch
|
|||
allow_flash_temporary_files.patch
|
||||
arm64_set_LoaderThreads.patch
|
||||
change_to_DCHECK_in_CloseHandleWrapper.patch
|
||||
move_shared_memory_duplication_after_initialization.patch
|
||||
|
|
|
@ -17,11 +17,11 @@ Differential Revision: https://phabricator.services.mozilla.com/D29474
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc b/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
|
||||
@@ -431,16 +431,21 @@ void ConvertProcessMitigationsToPolicy(M
|
||||
@@ -400,16 +400,21 @@ void ConvertProcessMitigationsToPolicy(M
|
||||
|
||||
// Mitigations >= Win8.1:
|
||||
//----------------------------------------------------------------------------
|
||||
if (version >= base::win::Version::WIN8_1) {
|
||||
if (version >= base::win::VERSION_WIN8_1) {
|
||||
if (flags & MITIGATION_DYNAMIC_CODE_DISABLE) {
|
||||
*policy_value_1 |=
|
||||
PROCESS_CREATION_MITIGATION_POLICY_PROHIBIT_DYNAMIC_CODE_ALWAYS_ON;
|
||||
|
@ -35,14 +35,14 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc b/
|
|||
|
||||
// Mitigations >= Win10:
|
||||
//----------------------------------------------------------------------------
|
||||
if (version >= base::win::Version::WIN10) {
|
||||
if (version >= base::win::VERSION_WIN10) {
|
||||
if (flags & MITIGATION_NONSYSTEM_FONT_DISABLE) {
|
||||
*policy_value_1 |=
|
||||
PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON;
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/security_level.h b/security/sandbox/chromium/sandbox/win/src/security_level.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/security_level.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/security_level.h
|
||||
@@ -282,11 +282,20 @@ const MitigationFlags MITIGATION_IMAGE_L
|
||||
@@ -273,11 +273,20 @@ const MitigationFlags MITIGATION_IMAGE_L
|
||||
const MitigationFlags MITIGATION_IMAGE_LOAD_PREFER_SYS32 = 0x00100000;
|
||||
|
||||
// Prevents hyperthreads from interfering with indirect branch predictions.
|
||||
|
|
|
@ -12,7 +12,7 @@ https://hg.mozilla.org/mozilla-central/rev/14374cd9497a
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
|
||||
@@ -51,16 +51,17 @@ DWORD GetObjectSecurityDescriptor(HANDLE
|
||||
@@ -51,16 +51,17 @@
|
||||
|
||||
} // namespace
|
||||
|
||||
|
@ -28,9 +28,9 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
|
|||
if (lockdown_default_dacl)
|
||||
restricted_token.SetLockdownDefaultDacl();
|
||||
|
||||
std::vector<std::wstring> privilege_exceptions;
|
||||
std::vector<base::string16> privilege_exceptions;
|
||||
std::vector<Sid> sid_exceptions;
|
||||
@@ -73,19 +74,22 @@ DWORD CreateRestrictedToken(HANDLE effec
|
||||
@@ -68,19 +69,22 @@ DWORD CreateRestrictedToken(TokenLevel s
|
||||
deny_sids = false;
|
||||
remove_privileges = false;
|
||||
break;
|
||||
|
@ -56,7 +56,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
|
|||
sid_exceptions.push_back(WinWorldSid);
|
||||
sid_exceptions.push_back(WinInteractiveSid);
|
||||
sid_exceptions.push_back(WinAuthenticatedUserSid);
|
||||
@@ -108,49 +112,57 @@ DWORD CreateRestrictedToken(HANDLE effec
|
||||
@@ -93,49 +97,57 @@ DWORD CreateRestrictedToken(TokenLevel s
|
||||
break;
|
||||
}
|
||||
case USER_INTERACTIVE: {
|
||||
|
@ -133,7 +133,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
|
||||
@@ -33,16 +33,17 @@ enum TokenType { IMPERSONATION = 0, PRIM
|
||||
@@ -33,16 +33,17 @@ enum TokenType {
|
||||
// If the function succeeds, the return value is ERROR_SUCCESS. If the
|
||||
// function fails, the return value is the win32 error code corresponding to
|
||||
// the error.
|
||||
|
@ -154,7 +154,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
|
||||
@@ -101,16 +101,21 @@ class TargetPolicy {
|
||||
@@ -95,16 +95,21 @@ class TargetPolicy {
|
||||
virtual ResultCode SetTokenLevel(TokenLevel initial, TokenLevel lockdown) = 0;
|
||||
|
||||
// Returns the initial token level.
|
||||
|
@ -179,7 +179,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h b/securi
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
|
||||
@@ -152,16 +152,20 @@ ResultCode PolicyBase::SetTokenLevel(Tok
|
||||
@@ -149,16 +149,20 @@ ResultCode PolicyBase::SetTokenLevel(Tok
|
||||
TokenLevel PolicyBase::GetInitialTokenLevel() const {
|
||||
return initial_level_;
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/
|
|||
ui_exceptions_ = ui_exceptions;
|
||||
return SBOX_ALL_OK;
|
||||
}
|
||||
@@ -413,17 +417,18 @@ ResultCode PolicyBase::MakeJobObject(bas
|
||||
@@ -402,17 +406,18 @@ ResultCode PolicyBase::MakeJobObject(bas
|
||||
|
||||
ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
|
||||
base::win::ScopedHandle* lockdown,
|
||||
|
@ -213,14 +213,14 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/
|
|||
+ PRIMARY, lockdown_default_dacl_,
|
||||
+ use_restricting_sids_, lockdown);
|
||||
if (ERROR_SUCCESS != result)
|
||||
return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_TOKEN;
|
||||
return SBOX_ERROR_GENERIC;
|
||||
|
||||
// If we're launching on the alternate desktop we need to make sure the
|
||||
// integrity label on the object is no higher than the sandboxed process's
|
||||
// integrity level. So, we lower the label on the desktop process if it's
|
||||
// not already low enough for our process.
|
||||
if (use_alternate_desktop_ && integrity_level_ != INTEGRITY_LEVEL_LAST) {
|
||||
@@ -482,17 +487,18 @@ ResultCode PolicyBase::MakeTokens(base::
|
||||
@@ -466,17 +471,18 @@ ResultCode PolicyBase::MakeTokens(base::
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,7 +233,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/
|
|||
+ IMPERSONATION, lockdown_default_dacl_,
|
||||
+ use_restricting_sids_, initial);
|
||||
if (ERROR_SUCCESS != result)
|
||||
return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_IMP_TOKEN;
|
||||
return SBOX_ERROR_GENERIC;
|
||||
|
||||
return SBOX_ALL_OK;
|
||||
}
|
||||
|
@ -243,7 +243,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h
|
||||
@@ -41,16 +41,17 @@ class PolicyBase final : public TargetPo
|
||||
@@ -37,16 +37,17 @@ class PolicyBase final : public TargetPo
|
||||
PolicyBase();
|
||||
|
||||
// TargetPolicy:
|
||||
|
@ -257,11 +257,11 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h b/s
|
|||
JobLevel GetJobLevel() const override;
|
||||
ResultCode SetJobMemoryLimit(size_t memory_limit) override;
|
||||
ResultCode SetAlternateDesktop(bool alternate_winstation) override;
|
||||
std::wstring GetAlternateDesktop() const override;
|
||||
base::string16 GetAlternateDesktop() const override;
|
||||
ResultCode CreateAlternateDesktop(bool alternate_winstation) override;
|
||||
void DestroyAlternateDesktop() override;
|
||||
ResultCode SetIntegrityLevel(IntegrityLevel integrity_level) override;
|
||||
@@ -134,16 +135,17 @@ class PolicyBase final : public TargetPo
|
||||
@@ -122,16 +123,17 @@ class PolicyBase final : public TargetPo
|
||||
// The policy takes ownership of them.
|
||||
typedef std::list<TargetProcess*> TargetSet;
|
||||
TargetSet targets_;
|
||||
|
|
|
@ -1,461 +0,0 @@
|
|||
# HG changeset patch
|
||||
# User Bob Owen <bobowencode@gmail.com>
|
||||
# Date 1584045580 0
|
||||
# Thu Mar 12 20:39:40 2020 +0000
|
||||
# Node ID c996dbc3e3663fb372feb8e171562e86b09583b6
|
||||
# Parent f96efa1d9f5c676c0ee8fd80044a494258eff3d3
|
||||
Bug 1557282 Part 1: Take chromium commit c1ce57ea5d31208af589b4839390a44ab20b0c8f. r=handyman,gcp
|
||||
|
||||
This adds AddRestrictingRandomSid feature, which fixes our issues with
|
||||
SetLockdownDefaultDacl, apart from when we are running from a network drive.
|
||||
|
||||
Differential Revision: https://phabricator.services.mozilla.com/D66610
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token.cc b/security/sandbox/chromium/sandbox/win/src/restricted_token.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token.cc
|
||||
@@ -141,16 +141,24 @@ DWORD RestrictedToken::GetRestrictedToke
|
||||
} else {
|
||||
// Modify the default dacl on the token to contain Restricted.
|
||||
if (!AddSidToDefaultDacl(new_token.Get(), WinRestrictedCodeSid,
|
||||
GRANT_ACCESS, GENERIC_ALL)) {
|
||||
return ::GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
+ for (const auto& default_dacl_sid : sids_for_default_dacl_) {
|
||||
+ if (!AddSidToDefaultDacl(new_token.Get(), std::get<0>(default_dacl_sid),
|
||||
+ std::get<1>(default_dacl_sid),
|
||||
+ std::get<2>(default_dacl_sid))) {
|
||||
+ return ::GetLastError();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
// Add user to default dacl.
|
||||
if (!AddUserSidToDefaultDacl(new_token.Get(), GENERIC_ALL))
|
||||
return ::GetLastError();
|
||||
|
||||
DWORD error = SetTokenIntegrityLevel(new_token.Get(), integrity_level_);
|
||||
if (ERROR_SUCCESS != error)
|
||||
return error;
|
||||
|
||||
@@ -405,9 +413,20 @@ DWORD RestrictedToken::SetIntegrityLevel
|
||||
integrity_level_ = integrity_level;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
void RestrictedToken::SetLockdownDefaultDacl() {
|
||||
lockdown_default_dacl_ = true;
|
||||
}
|
||||
|
||||
+DWORD RestrictedToken::AddDefaultDaclSid(const Sid& sid,
|
||||
+ ACCESS_MODE access_mode,
|
||||
+ ACCESS_MASK access) {
|
||||
+ DCHECK(init_);
|
||||
+ if (!init_)
|
||||
+ return ERROR_NO_TOKEN;
|
||||
+
|
||||
+ sids_for_default_dacl_.push_back(std::make_tuple(sid, access_mode, access));
|
||||
+ return ERROR_SUCCESS;
|
||||
+}
|
||||
+
|
||||
} // namespace sandbox
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token.h b/security/sandbox/chromium/sandbox/win/src/restricted_token.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token.h
|
||||
@@ -2,16 +2,17 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef SANDBOX_SRC_RESTRICTED_TOKEN_H_
|
||||
#define SANDBOX_SRC_RESTRICTED_TOKEN_H_
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
+#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "sandbox/win/src/restricted_token_utils.h"
|
||||
#include "sandbox/win/src/security_level.h"
|
||||
@@ -169,23 +170,31 @@ class RestrictedToken {
|
||||
// Sets the token integrity level. This is only valid on Vista. The integrity
|
||||
// level cannot be higher than your current integrity level.
|
||||
DWORD SetIntegrityLevel(IntegrityLevel integrity_level);
|
||||
|
||||
// Set a flag which indicates the created token should have a locked down
|
||||
// default DACL when created.
|
||||
void SetLockdownDefaultDacl();
|
||||
|
||||
+ // Add a SID to the default DACL. These SIDs are added regardless of the
|
||||
+ // SetLockdownDefaultDacl state.
|
||||
+ DWORD AddDefaultDaclSid(const Sid& sid,
|
||||
+ ACCESS_MODE access_mode,
|
||||
+ ACCESS_MASK access);
|
||||
+
|
||||
private:
|
||||
// The list of restricting sids in the restricted token.
|
||||
std::vector<Sid> sids_to_restrict_;
|
||||
// The list of privileges to remove in the restricted token.
|
||||
std::vector<LUID> privileges_to_disable_;
|
||||
// The list of sids to mark as Deny Only in the restricted token.
|
||||
std::vector<Sid> sids_for_deny_only_;
|
||||
+ // The list of sids to add to the default DACL of the restricted token.
|
||||
+ std::vector<std::tuple<Sid, ACCESS_MODE, ACCESS_MASK>> sids_for_default_dacl_;
|
||||
// The token to restrict. Can only be set in a constructor.
|
||||
base::win::ScopedHandle effective_token_;
|
||||
// The token integrity level. Only valid on Vista.
|
||||
IntegrityLevel integrity_level_;
|
||||
// Tells if the object is initialized or not (if Init() has been called)
|
||||
bool init_;
|
||||
// Lockdown the default DACL when creating new tokens.
|
||||
bool lockdown_default_dacl_;
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.cc
|
||||
@@ -51,22 +51,29 @@ DWORD GetObjectSecurityDescriptor(HANDLE
|
||||
|
||||
} // namespace
|
||||
|
||||
DWORD CreateRestrictedToken(HANDLE effective_token,
|
||||
TokenLevel security_level,
|
||||
IntegrityLevel integrity_level,
|
||||
TokenType token_type,
|
||||
bool lockdown_default_dacl,
|
||||
+ PSID unique_restricted_sid,
|
||||
bool use_restricting_sids,
|
||||
base::win::ScopedHandle* token) {
|
||||
RestrictedToken restricted_token;
|
||||
restricted_token.Init(effective_token);
|
||||
if (lockdown_default_dacl)
|
||||
restricted_token.SetLockdownDefaultDacl();
|
||||
+ if (unique_restricted_sid) {
|
||||
+ restricted_token.AddDefaultDaclSid(Sid(unique_restricted_sid), GRANT_ACCESS,
|
||||
+ GENERIC_ALL);
|
||||
+ restricted_token.AddDefaultDaclSid(Sid(WinCreatorOwnerRightsSid),
|
||||
+ GRANT_ACCESS, READ_CONTROL);
|
||||
+ }
|
||||
|
||||
std::vector<std::wstring> privilege_exceptions;
|
||||
std::vector<Sid> sid_exceptions;
|
||||
|
||||
bool deny_sids = true;
|
||||
bool remove_privileges = true;
|
||||
|
||||
switch (security_level) {
|
||||
@@ -118,50 +125,60 @@ DWORD CreateRestrictedToken(HANDLE effec
|
||||
sid_exceptions.push_back(WinAuthenticatedUserSid);
|
||||
privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
|
||||
if (use_restricting_sids) {
|
||||
restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
|
||||
restricted_token.AddRestrictingSid(WinWorldSid);
|
||||
restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
|
||||
restricted_token.AddRestrictingSidCurrentUser();
|
||||
restricted_token.AddRestrictingSidLogonSession();
|
||||
+ if (unique_restricted_sid)
|
||||
+ restricted_token.AddRestrictingSid(Sid(unique_restricted_sid));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case USER_LIMITED: {
|
||||
sid_exceptions.push_back(WinBuiltinUsersSid);
|
||||
sid_exceptions.push_back(WinWorldSid);
|
||||
sid_exceptions.push_back(WinInteractiveSid);
|
||||
privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
|
||||
if (use_restricting_sids) {
|
||||
restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
|
||||
restricted_token.AddRestrictingSid(WinWorldSid);
|
||||
restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
|
||||
+ if (unique_restricted_sid)
|
||||
+ restricted_token.AddRestrictingSid(Sid(unique_restricted_sid));
|
||||
|
||||
// This token has to be able to create objects in BNO.
|
||||
// Unfortunately, on Vista+, it needs the current logon sid
|
||||
// in the token to achieve this. You should also set the process to be
|
||||
// low integrity level so it can't access object created by other
|
||||
// processes.
|
||||
restricted_token.AddRestrictingSidLogonSession();
|
||||
+ } else {
|
||||
+ restricted_token.AddUserSidForDenyOnly();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case USER_RESTRICTED: {
|
||||
privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
|
||||
restricted_token.AddUserSidForDenyOnly();
|
||||
if (use_restricting_sids) {
|
||||
restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
|
||||
+ if (unique_restricted_sid)
|
||||
+ restricted_token.AddRestrictingSid(Sid(unique_restricted_sid));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case USER_LOCKDOWN: {
|
||||
restricted_token.AddUserSidForDenyOnly();
|
||||
if (use_restricting_sids) {
|
||||
restricted_token.AddRestrictingSid(WinNullSid);
|
||||
+ if (unique_restricted_sid)
|
||||
+ restricted_token.AddRestrictingSid(Sid(unique_restricted_sid));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: { return ERROR_BAD_ARGUMENTS; }
|
||||
}
|
||||
|
||||
DWORD err_code = ERROR_SUCCESS;
|
||||
if (deny_sids) {
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/restricted_token_utils.h
|
||||
@@ -33,16 +33,17 @@ enum TokenType { IMPERSONATION = 0, PRIM
|
||||
// If the function succeeds, the return value is ERROR_SUCCESS. If the
|
||||
// function fails, the return value is the win32 error code corresponding to
|
||||
// the error.
|
||||
DWORD CreateRestrictedToken(HANDLE effective_token,
|
||||
TokenLevel security_level,
|
||||
IntegrityLevel integrity_level,
|
||||
TokenType token_type,
|
||||
bool lockdown_default_dacl,
|
||||
+ PSID unique_restricted_sid,
|
||||
bool use_restricting_sids,
|
||||
base::win::ScopedHandle* token);
|
||||
|
||||
// Sets the integrity label on a object handle.
|
||||
DWORD SetObjectIntegrityLabel(HANDLE handle,
|
||||
SE_OBJECT_TYPE type,
|
||||
const wchar_t* ace_access,
|
||||
const wchar_t* integrity_level_sid);
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
|
||||
@@ -256,16 +256,20 @@ class TargetPolicy {
|
||||
// ownership of the handle.
|
||||
virtual void AddHandleToShare(HANDLE handle) = 0;
|
||||
|
||||
// Locks down the default DACL of the created lockdown and initial tokens
|
||||
// to restrict what other processes are allowed to access a process' kernel
|
||||
// resources.
|
||||
virtual void SetLockdownDefaultDacl() = 0;
|
||||
|
||||
+ // Adds a restricting random SID to the restricted SIDs list as well as
|
||||
+ // the default DACL.
|
||||
+ virtual void AddRestrictingRandomSid() = 0;
|
||||
+
|
||||
// Enable OPM API redirection when in Win32k lockdown.
|
||||
virtual void SetEnableOPMRedirection() = 0;
|
||||
// Enable OPM API emulation when in Win32k lockdown.
|
||||
virtual bool GetEnableOPMRedirection() = 0;
|
||||
|
||||
// Configure policy to use an AppContainer profile. |package_name| is the
|
||||
// name of the profile to use. Specifying True for |create_profile| ensures
|
||||
// the profile exists, if set to False process creation will fail if the
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
|
||||
@@ -105,16 +105,17 @@ PolicyBase::PolicyBase()
|
||||
delayed_integrity_level_(INTEGRITY_LEVEL_LAST),
|
||||
mitigations_(0),
|
||||
delayed_mitigations_(0),
|
||||
is_csrss_connected_(true),
|
||||
policy_maker_(nullptr),
|
||||
policy_(nullptr),
|
||||
lowbox_sid_(nullptr),
|
||||
lockdown_default_dacl_(false),
|
||||
+ add_restricting_random_sid_(false),
|
||||
enable_opm_redirection_(false),
|
||||
effective_token_(nullptr) {
|
||||
::InitializeCriticalSection(&lock_);
|
||||
dispatcher_.reset(new TopLevelDispatcher(this));
|
||||
}
|
||||
|
||||
PolicyBase::~PolicyBase() {
|
||||
TargetSet::iterator it;
|
||||
@@ -389,16 +390,20 @@ void PolicyBase::AddHandleToShare(HANDLE
|
||||
|
||||
handles_to_share_.push_back(handle);
|
||||
}
|
||||
|
||||
void PolicyBase::SetLockdownDefaultDacl() {
|
||||
lockdown_default_dacl_ = true;
|
||||
}
|
||||
|
||||
+void PolicyBase::AddRestrictingRandomSid() {
|
||||
+ add_restricting_random_sid_ = true;
|
||||
+}
|
||||
+
|
||||
const base::HandlesToInheritVector& PolicyBase::GetHandlesBeingShared() {
|
||||
return handles_to_share_;
|
||||
}
|
||||
|
||||
ResultCode PolicyBase::MakeJobObject(base::win::ScopedHandle* job) {
|
||||
if (job_level_ == JOB_NONE) {
|
||||
job->Close();
|
||||
return SBOX_ALL_OK;
|
||||
@@ -413,22 +418,26 @@ ResultCode PolicyBase::MakeJobObject(bas
|
||||
|
||||
*job = job_obj.Take();
|
||||
return SBOX_ALL_OK;
|
||||
}
|
||||
|
||||
ResultCode PolicyBase::MakeTokens(base::win::ScopedHandle* initial,
|
||||
base::win::ScopedHandle* lockdown,
|
||||
base::win::ScopedHandle* lowbox) {
|
||||
+ Sid random_sid = Sid::GenerateRandomSid();
|
||||
+ PSID random_sid_ptr = nullptr;
|
||||
+ if (add_restricting_random_sid_)
|
||||
+ random_sid_ptr = random_sid.GetPSID();
|
||||
+
|
||||
// Create the 'naked' token. This will be the permanent token associated
|
||||
// with the process and therefore with any thread that is not impersonating.
|
||||
- DWORD result =
|
||||
- CreateRestrictedToken(effective_token_, lockdown_level_, integrity_level_,
|
||||
- PRIMARY, lockdown_default_dacl_,
|
||||
- use_restricting_sids_, lockdown);
|
||||
+ DWORD result = CreateRestrictedToken(
|
||||
+ effective_token_, lockdown_level_, integrity_level_, PRIMARY,
|
||||
+ lockdown_default_dacl_, random_sid_ptr, use_restricting_sids_, lockdown);
|
||||
if (ERROR_SUCCESS != result)
|
||||
return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_TOKEN;
|
||||
|
||||
// If we're launching on the alternate desktop we need to make sure the
|
||||
// integrity label on the object is no higher than the sandboxed process's
|
||||
// integrity level. So, we lower the label on the desktop process if it's
|
||||
// not already low enough for our process.
|
||||
if (use_alternate_desktop_ && integrity_level_ != INTEGRITY_LEVEL_LAST) {
|
||||
@@ -485,20 +494,19 @@ ResultCode PolicyBase::MakeTokens(base::
|
||||
TOKEN_ALL_ACCESS)) {
|
||||
return SBOX_ERROR_CANNOT_MODIFY_LOWBOX_TOKEN_DACL;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the 'better' token. We use this token as the one that the main
|
||||
// thread uses when booting up the process. It should contain most of
|
||||
// what we need (before reaching main( ))
|
||||
- result =
|
||||
- CreateRestrictedToken(effective_token_, initial_level_, integrity_level_,
|
||||
- IMPERSONATION, lockdown_default_dacl_,
|
||||
- use_restricting_sids_, initial);
|
||||
+ result = CreateRestrictedToken(
|
||||
+ effective_token_, initial_level_, integrity_level_, IMPERSONATION,
|
||||
+ lockdown_default_dacl_, random_sid_ptr, use_restricting_sids_, initial);
|
||||
if (ERROR_SUCCESS != result)
|
||||
return SBOX_ERROR_CANNOT_CREATE_RESTRICTED_IMP_TOKEN;
|
||||
|
||||
return SBOX_ALL_OK;
|
||||
}
|
||||
|
||||
PSID PolicyBase::GetLowBoxSid() const {
|
||||
return lowbox_sid_;
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.h
|
||||
@@ -69,16 +69,17 @@ class PolicyBase final : public TargetPo
|
||||
ResultCode AddRule(SubSystem subsystem,
|
||||
Semantics semantics,
|
||||
const wchar_t* pattern) override;
|
||||
ResultCode AddDllToUnload(const wchar_t* dll_name) override;
|
||||
ResultCode AddKernelObjectToClose(const wchar_t* handle_type,
|
||||
const wchar_t* handle_name) override;
|
||||
void AddHandleToShare(HANDLE handle) override;
|
||||
void SetLockdownDefaultDacl() override;
|
||||
+ void AddRestrictingRandomSid() override;
|
||||
void SetEnableOPMRedirection() override;
|
||||
bool GetEnableOPMRedirection() override;
|
||||
ResultCode AddAppContainerProfile(const wchar_t* package_name,
|
||||
bool create_profile) override;
|
||||
scoped_refptr<AppContainerProfile> GetAppContainerProfile() override;
|
||||
void SetEffectiveToken(HANDLE token) override;
|
||||
|
||||
// Get the AppContainer profile as its internal type.
|
||||
@@ -165,16 +166,17 @@ class PolicyBase final : public TargetPo
|
||||
// This is a map of handle-types to names that we need to close in the
|
||||
// target process. A null set means we need to close all handles of the
|
||||
// given type.
|
||||
HandleCloser handle_closer_;
|
||||
PSID lowbox_sid_;
|
||||
base::win::ScopedHandle lowbox_directory_;
|
||||
std::unique_ptr<Dispatcher> dispatcher_;
|
||||
bool lockdown_default_dacl_;
|
||||
+ bool add_restricting_random_sid_;
|
||||
|
||||
static HDESK alternate_desktop_handle_;
|
||||
static HWINSTA alternate_winstation_handle_;
|
||||
static HDESK alternate_desktop_local_winstation_handle_;
|
||||
static IntegrityLevel alternate_desktop_integrity_level_label_;
|
||||
static IntegrityLevel
|
||||
alternate_desktop_local_winstation_integrity_level_label_;
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/sid.cc b/security/sandbox/chromium/sandbox/win/src/sid.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sid.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sid.cc
|
||||
@@ -2,18 +2,20 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "sandbox/win/src/sid.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <sddl.h>
|
||||
+#include <stdlib.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
+#include "base/rand_util.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "sandbox/win/src/win_utils.h"
|
||||
|
||||
namespace sandbox {
|
||||
|
||||
namespace {
|
||||
|
||||
DWORD WellKnownCapabilityToRid(WellKnownCapabilities capability) {
|
||||
@@ -127,16 +129,24 @@ Sid Sid::FromSubAuthorities(PSID_IDENTIF
|
||||
|
||||
Sid Sid::AllRestrictedApplicationPackages() {
|
||||
SID_IDENTIFIER_AUTHORITY package_authority = {SECURITY_APP_PACKAGE_AUTHORITY};
|
||||
DWORD sub_authorities[] = {SECURITY_APP_PACKAGE_BASE_RID,
|
||||
SECURITY_BUILTIN_PACKAGE_ANY_RESTRICTED_PACKAGE};
|
||||
return FromSubAuthorities(&package_authority, 2, sub_authorities);
|
||||
}
|
||||
|
||||
+Sid Sid::GenerateRandomSid() {
|
||||
+ SID_IDENTIFIER_AUTHORITY package_authority = {SECURITY_NULL_SID_AUTHORITY};
|
||||
+ DWORD sub_authorities[4] = {};
|
||||
+ base::RandBytes(&sub_authorities, sizeof(sub_authorities));
|
||||
+ return FromSubAuthorities(&package_authority, _countof(sub_authorities),
|
||||
+ sub_authorities);
|
||||
+}
|
||||
+
|
||||
PSID Sid::GetPSID() const {
|
||||
return const_cast<BYTE*>(sid_);
|
||||
}
|
||||
|
||||
bool Sid::IsValid() const {
|
||||
return !!::IsValidSid(GetPSID());
|
||||
}
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/sid.h b/security/sandbox/chromium/sandbox/win/src/sid.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sid.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sid.h
|
||||
@@ -47,16 +47,18 @@ class Sid {
|
||||
// Create a Sid from a SDDL format string, such as S-1-1-0.
|
||||
static Sid FromSddlString(const wchar_t* sddl_sid);
|
||||
// Create a Sid from a set of sub authorities.
|
||||
static Sid FromSubAuthorities(PSID_IDENTIFIER_AUTHORITY identifier_authority,
|
||||
BYTE sub_authority_count,
|
||||
PDWORD sub_authorities);
|
||||
// Create the restricted all application packages sid.
|
||||
static Sid AllRestrictedApplicationPackages();
|
||||
+ // Generate a random SID value.
|
||||
+ static Sid GenerateRandomSid();
|
||||
|
||||
// Returns sid_.
|
||||
PSID GetPSID() const;
|
||||
|
||||
// Gets whether the sid is valid.
|
||||
bool IsValid() const;
|
||||
|
||||
// Converts the SID to a SDDL format string.
|
|
@ -9,7 +9,7 @@ Bug 1297740.
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.cc b/security/sandbox/chromium/sandbox/win/src/broker_services.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/broker_services.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/broker_services.cc
|
||||
@@ -414,16 +414,17 @@ DWORD WINAPI BrokerServicesBase::TargetE
|
||||
@@ -301,16 +301,17 @@ DWORD WINAPI BrokerServicesBase::TargetE
|
||||
NOTREACHED();
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.cc b/secu
|
|||
return SBOX_ERROR_BAD_PARAMS;
|
||||
|
||||
if (!policy)
|
||||
@@ -609,17 +610,17 @@ ResultCode BrokerServicesBase::SpawnTarg
|
||||
@@ -486,17 +487,17 @@ ResultCode BrokerServicesBase::SpawnTarg
|
||||
// Brokerservices does not own the target object. It is owned by the Policy.
|
||||
base::win::ScopedProcessInformation process_info;
|
||||
TargetProcess* target = new TargetProcess(
|
||||
|
@ -65,9 +65,9 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.h b/secur
|
|||
#include "sandbox/win/src/crosscall_server.h"
|
||||
#include "sandbox/win/src/job.h"
|
||||
#include "sandbox/win/src/sandbox.h"
|
||||
#include "sandbox/win/src/sandbox_policy_base.h"
|
||||
#include "sandbox/win/src/sharedmem_ipc_server.h"
|
||||
@@ -39,16 +40,17 @@ class BrokerServicesBase final : public
|
||||
#include "sandbox/win/src/win2k_threadpool.h"
|
||||
@@ -45,16 +46,17 @@ class BrokerServicesBase final : public
|
||||
|
||||
~BrokerServicesBase();
|
||||
|
||||
|
@ -88,7 +88,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.h b/secur
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.h b/security/sandbox/chromium/sandbox/win/src/sandbox.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox.h
|
||||
@@ -84,16 +84,17 @@ class BrokerServices {
|
||||
@@ -79,16 +79,17 @@ class BrokerServices {
|
||||
// parameter will hold the last Win32 error value.
|
||||
// target: returns the resulting target process information such as process
|
||||
// handle and PID just as if CreateProcess() had been called. The caller is
|
||||
|
@ -109,25 +109,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.h b/security/sand
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/target_process.cc b/security/sandbox/chromium/sandbox/win/src/target_process.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/target_process.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/target_process.cc
|
||||
@@ -9,16 +9,17 @@
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/free_deleter.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
+#include "base/process/environment_internal.h"
|
||||
#include "base/win/startup_information.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "sandbox/win/src/crosscall_client.h"
|
||||
#include "sandbox/win/src/crosscall_server.h"
|
||||
#include "sandbox/win/src/policy_low_level.h"
|
||||
#include "sandbox/win/src/restricted_token_utils.h"
|
||||
#include "sandbox/win/src/sandbox_types.h"
|
||||
#include "sandbox/win/src/security_capabilities.h"
|
||||
@@ -137,16 +138,17 @@ TargetProcess::~TargetProcess() {
|
||||
@@ -137,16 +137,17 @@ TargetProcess::~TargetProcess() {
|
||||
// Creates the target (child) process suspended and assigns it to the job
|
||||
// object.
|
||||
ResultCode TargetProcess::Create(
|
||||
|
@ -145,10 +127,10 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/target_process.cc b/secur
|
|||
|
||||
// Start the target process suspended.
|
||||
DWORD flags =
|
||||
@@ -156,22 +158,29 @@ ResultCode TargetProcess::Create(
|
||||
@@ -156,22 +157,29 @@ ResultCode TargetProcess::Create(
|
||||
flags |= EXTENDED_STARTUPINFO_PRESENT;
|
||||
|
||||
if (job_ && base::win::GetVersion() < base::win::Version::WIN8) {
|
||||
if (job_ && base::win::GetVersion() < base::win::VERSION_WIN8) {
|
||||
// Windows 8 implements nested jobs, but for older systems we need to
|
||||
// break out of any job we're in to enforce our restrictions.
|
||||
flags |= CREATE_BREAKAWAY_FROM_JOB;
|
||||
|
@ -156,7 +138,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/target_process.cc b/secur
|
|||
|
||||
+ LPTCH original_environment = GetEnvironmentStrings();
|
||||
+ base::NativeEnvironmentString new_environment =
|
||||
+ base::internal::AlterEnvironment(original_environment, env_changes);
|
||||
+ base::AlterEnvironment(original_environment, env_changes);
|
||||
+ // Ignore return value? What can we do?
|
||||
+ FreeEnvironmentStrings(original_environment);
|
||||
+ LPVOID new_env_ptr = (void*)new_environment.data();
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
# Parent 96707276b26997ea2a8e9fd8fdacc0c863717e7b
|
||||
Allow a special all paths rule in the Windows process sandbox when using semantics FILES_ALLOW_READONLY. r=jimm
|
||||
|
||||
This also changes the read only related status checks in filesystem_interception.cc
|
||||
to include STATUS_NETWORK_OPEN_RESTRICTION (0xC0000201), which gets returned in
|
||||
some cases and fails because we never ask the broker.
|
||||
This also changes the read only related status checks in filesystem_interception.cc to include STATUS_NETWORK_OPEN_RESTRICTION (0xC0000201), which gets returned in some cases and fails because we never ask the broker.
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc b/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.cc
|
||||
|
@ -54,7 +52,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.c
|
|||
|
||||
do {
|
||||
if (!ValidParameter(file, sizeof(HANDLE), WRITE))
|
||||
@@ -106,17 +111,18 @@ NTSTATUS WINAPI TargetNtOpenFile(NtOpenF
|
||||
@@ -106,17 +111,18 @@ NTSTATUS WINAPI TargetNtCreateFile(NtCre
|
||||
ACCESS_MASK desired_access,
|
||||
POBJECT_ATTRIBUTES object_attributes,
|
||||
PIO_STATUS_BLOCK io_status,
|
||||
|
@ -94,7 +92,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_interception.c
|
|||
|
||||
do {
|
||||
if (!ValidParameter(file_attributes, sizeof(FILE_BASIC_INFORMATION), WRITE))
|
||||
@@ -232,17 +239,18 @@ TargetNtQueryAttributesFile(NtQueryAttri
|
||||
@@ -232,17 +239,18 @@ NTSTATUS WINAPI TargetNtQueryAttributesF
|
||||
|
||||
NTSTATUS WINAPI TargetNtQueryFullAttributesFile(
|
||||
NtQueryFullAttributesFileFunction orig_QueryFullAttributes,
|
||||
|
@ -121,7 +119,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/filesystem_policy.cc b/se
|
|||
bool FileSystemPolicy::GenerateRules(const wchar_t* name,
|
||||
TargetPolicy::Semantics semantics,
|
||||
LowLevelPolicy* policy) {
|
||||
std::wstring mod_name(name);
|
||||
base::string16 mod_name(name);
|
||||
if (mod_name.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# HG changeset patch
|
||||
# User Bob Owen <bobowencode@gmail.com>
|
||||
# Date 1549903491 0
|
||||
# Mon Feb 11 16:44:51 2019 +0000
|
||||
# Node ID 3bb3e5a6275db53530d50549b7b329cc1248d450
|
||||
# Parent fc9d5e40028058abeb06f8bdc2f75fc868fbe14b
|
||||
|
||||
Fix incorrect int use in Kernel32BaseVersion in windows_version.cc. r=aklotz
|
||||
|
||||
diff --git a/security/sandbox/chromium/base/win/windows_version.cc b/security/sandbox/chromium/base/win/windows_version.cc
|
||||
--- a/security/sandbox/chromium/base/win/windows_version.cc
|
||||
+++ b/security/sandbox/chromium/base/win/windows_version.cc
|
||||
@@ -236,23 +236,23 @@ Version OSInfo::Kernel32Version() const
|
||||
// kernel32 will still be the "real" version.
|
||||
base::Version OSInfo::Kernel32BaseVersion() const {
|
||||
static const base::NoDestructor<base::Version> version([] {
|
||||
std::unique_ptr<FileVersionInfoWin> file_version_info(
|
||||
static_cast<FileVersionInfoWin*>(
|
||||
FileVersionInfoWin::CreateFileVersionInfo(
|
||||
base::FilePath(FILE_PATH_LITERAL("kernel32.dll")))));
|
||||
DCHECK(file_version_info);
|
||||
- const int major =
|
||||
+ const uint32_t major =
|
||||
HIWORD(file_version_info->fixed_file_info()->dwFileVersionMS);
|
||||
- const int minor =
|
||||
+ const uint32_t minor =
|
||||
LOWORD(file_version_info->fixed_file_info()->dwFileVersionMS);
|
||||
- const int build =
|
||||
+ const uint32_t build =
|
||||
HIWORD(file_version_info->fixed_file_info()->dwFileVersionLS);
|
||||
- const int patch =
|
||||
+ const uint32_t patch =
|
||||
LOWORD(file_version_info->fixed_file_info()->dwFileVersionLS);
|
||||
return base::Version(std::vector<uint32_t>{major, minor, build, patch});
|
||||
}());
|
||||
return *version;
|
||||
}
|
||||
|
||||
std::string OSInfo::processor_model_name() {
|
||||
if (processor_model_name_.empty()) {
|
|
@ -46,7 +46,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/app_container_profile_bas
|
|||
GetModuleHandle(L"userenv"), "GetAppContainerFolderPath"));
|
||||
if (!get_app_container_folder_path)
|
||||
return false;
|
||||
std::wstring sddl_str;
|
||||
base::string16 sddl_str;
|
||||
if (!package_sid_.ToSddlString(&sddl_str))
|
||||
return false;
|
||||
base::win::ScopedCoMem<wchar_t> path_str;
|
||||
|
@ -62,7 +62,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/app_container_profile_bas
|
|||
+#if defined(MOZ_SANDBOX)
|
||||
+ IMMEDIATE_CRASH();
|
||||
+#else
|
||||
std::wstring sddl_str;
|
||||
base::string16 sddl_str;
|
||||
if (!package_sid_.ToSddlString(&sddl_str))
|
||||
return false;
|
||||
*pipe_path = base::FilePath(base::StringPrintf(L"\\\\.\\pipe\\%ls\\%ls",
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
# HG changeset patch
|
||||
# User Bob Owen <bobowencode@gmail.com>
|
||||
# Date 1509027042 -3600
|
||||
# Thu Oct 26 15:10:42 2017 +0100
|
||||
# Node ID c4557696d42ef22c6eccfd178b3d739a265e2894
|
||||
# Parent ec58d9068a540487e67c0eac2c60c53dea31d3c3
|
||||
Don't compile sandbox::ApplyMitigationsToCurrentThread. r=aklotz
|
||||
|
||||
This brings in new dependencies via FilePath and we don't currently use it.
|
||||
As far as I can tell Chromium doesn't use it either.
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc b/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
|
||||
@@ -230,16 +230,19 @@ bool ApplyProcessMitigationsToCurrentPro
|
||||
ERROR_ACCESS_DENIED != ::GetLastError()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+// This function isn't used yet and adds dependencies for FilePath and
|
||||
+// ScopedNativeLibrary.
|
||||
+#if !defined(MOZ_SANDBOX)
|
||||
bool ApplyMitigationsToCurrentThread(MitigationFlags flags) {
|
||||
if (!CanSetMitigationsPerThread(flags))
|
||||
return false;
|
||||
|
||||
base::win::Version version = base::win::GetVersion();
|
||||
|
||||
if (version < base::win::VERSION_WIN10_RS1)
|
||||
return true;
|
||||
@@ -263,16 +266,17 @@ bool ApplyMitigationsToCurrentThread(Mit
|
||||
if (!set_thread_info_function(::GetCurrentThread(), ThreadDynamicCodePolicy,
|
||||
&thread_policy, sizeof(thread_policy))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
+#endif
|
||||
|
||||
void ConvertProcessMitigationsToPolicy(MitigationFlags flags,
|
||||
DWORD64* policy_flags,
|
||||
size_t* size) {
|
||||
base::win::Version version = base::win::GetVersion();
|
||||
|
||||
*policy_flags = 0;
|
||||
#if defined(_WIN64)
|
|
@ -14,10 +14,10 @@ https://hg.mozilla.org/mozilla-central/rev/477b991bf6fa7b4511768649c9bf37c7275d3
|
|||
diff --git a/security/sandbox/chromium/base/time/time.cc b/security/sandbox/chromium/base/time/time.cc
|
||||
--- a/security/sandbox/chromium/base/time/time.cc
|
||||
+++ b/security/sandbox/chromium/base/time/time.cc
|
||||
@@ -281,16 +281,17 @@ Time Time::Midnight(bool is_local) const
|
||||
if (FromExploded(is_local, exploded, &out_time))
|
||||
return out_time;
|
||||
}
|
||||
@@ -241,16 +241,17 @@ Time Time::LocalMidnight() const {
|
||||
Time out_time;
|
||||
if (FromLocalExploded(exploded, &out_time))
|
||||
return out_time;
|
||||
// This function must not fail.
|
||||
NOTREACHED();
|
||||
return Time();
|
||||
|
@ -32,7 +32,7 @@ diff --git a/security/sandbox/chromium/base/time/time.cc b/security/sandbox/chro
|
|||
|
||||
if (time_string[0] == '\0')
|
||||
return false;
|
||||
@@ -301,16 +302,17 @@ bool Time::FromStringInternal(const char
|
||||
@@ -261,16 +262,17 @@ bool Time::FromStringInternal(const char
|
||||
&result_time);
|
||||
if (PR_SUCCESS != result)
|
||||
return false;
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
# HG changeset patch
|
||||
# User Toshihito Kikuchi <tkikuchi@mozilla.com>
|
||||
# Date 1588735588 25200
|
||||
# Tue May 05 20:26:28 2020 -0700
|
||||
# Node ID 8214c0253f550d73b5e79dfd825b09f5c1a06fbd
|
||||
# Parent 2d5ee142bde533ba4f93afaae081a444eac0abe2
|
||||
Lower SDK version requirement from 19H1 to RS4. r=bobowen
|
||||
|
||||
We still use 10.0.17134.0 SDK while Chromium requires 10.0.18362.0 or higher.
|
||||
|
||||
diff --git a/security/sandbox/chromium/base/win/windows_version.cc b/security/sandbox/chromium/base/win/windows_version.cc
|
||||
--- a/security/sandbox/chromium/base/win/windows_version.cc
|
||||
+++ b/security/sandbox/chromium/base/win/windows_version.cc
|
||||
@@ -17,18 +17,18 @@
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/win/registry.h"
|
||||
|
||||
#if !defined(__clang__) && _MSC_FULL_VER < 191125507
|
||||
#error VS 2017 Update 3.2 or higher is required
|
||||
#endif
|
||||
|
||||
-#if !defined(NTDDI_WIN10_19H1)
|
||||
-#error Windows 10.0.18362.0 SDK or higher required.
|
||||
+#if !defined(NTDDI_WIN10_RS4)
|
||||
+#error Windows 10.0.17134.0 SDK or higher required.
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace win {
|
||||
|
||||
namespace {
|
||||
|
||||
// The values under the CurrentVersion registry hive are mirrored under
|
|
@ -0,0 +1,37 @@
|
|||
# HG changeset patch
|
||||
# User Tom Ritter <tom@mozilla.com>
|
||||
# Date 1516824525 21600
|
||||
# Wed Jan 24 14:08:45 2018 -0600
|
||||
# Node ID b09622ad2731f02ed7f231295bc9421d76b083e6
|
||||
# Parent 2b890d81a1e3ebc4872958022c8d425d5689b31d
|
||||
Bug 1432790 Remove a stray \ to fix the MinGW build. r?bobowen
|
||||
|
||||
The GCC case includes a stray \ at the end of the line that gcc
|
||||
complains about.
|
||||
|
||||
For reference purposes, this commit is a combination of Bug 1431621
|
||||
and Bug 1432790 combined together so that it looks like I hadn't
|
||||
screwed it up.
|
||||
|
||||
diff --git a/security/sandbox/chromium/base/win/scoped_handle.h b/security/sandbox/chromium/base/win/scoped_handle.h
|
||||
--- a/security/sandbox/chromium/base/win/scoped_handle.h
|
||||
+++ b/security/sandbox/chromium/base/win/scoped_handle.h
|
||||
@@ -13,17 +13,17 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
|
||||
// TODO(rvargas): remove this with the rest of the verifier.
|
||||
#if defined(COMPILER_MSVC)
|
||||
#include <intrin.h>
|
||||
#define BASE_WIN_GET_CALLER _ReturnAddress()
|
||||
#elif defined(COMPILER_GCC)
|
||||
-#define BASE_WIN_GET_CALLER __builtin_extract_return_addr(\\
|
||||
+#define BASE_WIN_GET_CALLER __builtin_extract_return_addr(\
|
||||
__builtin_return_address(0))
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace win {
|
||||
|
||||
// Generic wrapper for raw handles that takes care of closing handles
|
||||
// automatically. The class interface follows the style of
|
|
@ -32,10 +32,10 @@ diff --git a/security/sandbox/chromium/base/win/pe_image.h b/security/sandbox/ch
|
|||
--- a/security/sandbox/chromium/base/win/pe_image.h
|
||||
+++ b/security/sandbox/chromium/base/win/pe_image.h
|
||||
@@ -14,17 +14,17 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(_WIN32_WINNT_WIN8)
|
||||
// The Windows 8 SDK defines FACILITY_VISUALCPP in winerror.h.
|
||||
#undef FACILITY_VISUALCPP
|
||||
|
|
|
@ -20,14 +20,14 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/target_process.cc b/secur
|
|||
#if SANDBOX_EXPORTS
|
||||
HMODULE module = ::LoadLibrary(exe_name_.get());
|
||||
if (!module)
|
||||
return SBOX_ERROR_CANNOT_LOADLIBRARY_EXECUTABLE;
|
||||
return SBOX_ERROR_GENERIC;
|
||||
|
||||
- child_var = ::GetProcAddress(module, name);
|
||||
+ child_var = reinterpret_cast<void*>(::GetProcAddress(module, name));
|
||||
::FreeLibrary(module);
|
||||
|
||||
if (!child_var)
|
||||
return SBOX_ERROR_CANNOT_FIND_VARIABLE_ADDRESS;
|
||||
return SBOX_ERROR_GENERIC;
|
||||
|
||||
size_t offset =
|
||||
reinterpret_cast<char*>(child_var) - reinterpret_cast<char*>(module);
|
||||
|
|
|
@ -11,7 +11,7 @@ MozReview-Commit-ID: D7REZiAIMpN
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/crosscall_params.h b/security/sandbox/chromium/sandbox/win/src/crosscall_params.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/crosscall_params.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/crosscall_params.h
|
||||
@@ -78,16 +78,17 @@ union MultiType {
|
||||
@@ -61,16 +61,17 @@ union MultiType {
|
||||
ULONG_PTR ulong_ptr;
|
||||
};
|
||||
|
||||
|
@ -29,9 +29,9 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/crosscall_params.h b/secu
|
|||
uint32_t offset_;
|
||||
uint32_t size_;
|
||||
};
|
||||
@@ -287,16 +288,18 @@ class ActualCallParams : public CrossCal
|
||||
@@ -271,16 +272,18 @@ class ActualCallParams : public CrossCal
|
||||
protected:
|
||||
ActualCallParams() : CrossCallParams(IpcTag::UNUSED, NUMBER_PARAMS) {}
|
||||
ActualCallParams() : CrossCallParams(0, NUMBER_PARAMS) { }
|
||||
|
||||
private:
|
||||
ParamInfo param_info_[NUMBER_PARAMS + 1];
|
||||
|
@ -167,7 +167,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/crosscall_server.cc b/sec
|
|||
// Avoid compiler optimizations across this point. Any value stored in
|
||||
// memory should be stored for real, and values previously read from memory
|
||||
// should be actually read.
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
base::subtle::MemoryBarrier();
|
||||
|
||||
- min_declared_size =
|
||||
- sizeof(CrossCallParams) + ((param_count + 1) * sizeof(ParamInfo));
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
# HG changeset patch
|
||||
# User Bob Owen <bobowencode@gmail.com>
|
||||
# Date 1558340081 -3600
|
||||
# Mon May 20 09:14:41 2019 +0100
|
||||
# Node ID ba49022852e0cd13ddb6afa501b61c1f603d60b7
|
||||
# Parent 672e222dce87dd64c3e2a1381d16aec71b21aef6
|
||||
Bug 1552160: always undefine MemoryBarrier in Windows sandbox on MinGW.
|
||||
|
||||
diff --git a/security/sandbox/chromium/base/atomicops.h b/security/sandbox/chromium/base/atomicops.h
|
||||
--- a/security/sandbox/chromium/base/atomicops.h
|
||||
+++ b/security/sandbox/chromium/base/atomicops.h
|
||||
@@ -34,17 +34,17 @@
|
||||
// identify the STL implementation.
|
||||
// - libc++: captures __config for _LIBCPP_VERSION
|
||||
// - libstdc++: captures bits/c++config.h for __GLIBCXX__
|
||||
#include <cstddef>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
-#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS)
|
||||
+#if defined(OS_WIN) && (defined(ARCH_CPU_64_BITS) || defined(__MINGW32__))
|
||||
// windows.h #defines this (only on x64). This causes problems because the
|
||||
// public API also uses MemoryBarrier at the public name for this fence. So, on
|
||||
// X64, undef it, and call its documented
|
||||
// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
|
||||
// implementation directly.
|
||||
#undef MemoryBarrier
|
||||
#endif
|
||||
|
||||
diff --git a/security/sandbox/chromium/base/atomicops_internals_x86_msvc.h b/security/sandbox/chromium/base/atomicops_internals_x86_msvc.h
|
||||
--- a/security/sandbox/chromium/base/atomicops_internals_x86_msvc.h
|
||||
+++ b/security/sandbox/chromium/base/atomicops_internals_x86_msvc.h
|
||||
@@ -9,17 +9,17 @@
|
||||
|
||||
#include "base/win/windows_types.h"
|
||||
|
||||
#include <intrin.h>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
-#if defined(ARCH_CPU_64_BITS)
|
||||
+#if defined(ARCH_CPU_64_BITS) || defined(__MINGW32__)
|
||||
// windows.h #defines this (only on x64). This causes problems because the
|
||||
// public API also uses MemoryBarrier at the public name for this fence. So, on
|
||||
// X64, undef it, and call its documented
|
||||
// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
|
||||
// implementation directly.
|
||||
#undef MemoryBarrier
|
||||
#endif
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,28 +1,28 @@
|
|||
update_chromium_linux_x86_syscalls.patch
|
||||
revert_remove_AddTargetPeer.patch
|
||||
revert_remove_BrokerDuplicateHandle.patch
|
||||
replace_ScopedNativeLibrary_in_ApplyMitigationsToCurrentThread.patch
|
||||
ifdef_out_ApplyMitigationsToCurrentThread.patch
|
||||
ifdef_out_FromStringInternal.patch
|
||||
add_option_to_not_use_restricting_sids.patch
|
||||
ifdef_out_SequenceChecker_code.patch
|
||||
allow_read_only_all_paths_rule.patch
|
||||
revert_TargetNtSetInformationThread_change.patch
|
||||
mingw_base_win_get_caller.patch
|
||||
mingw_copy_s.patch
|
||||
mingw_operator_new.patch
|
||||
mingw_cast_getprocaddress.patch
|
||||
mingw_capitalization.patch
|
||||
mingw_disable_one_try.patch
|
||||
mingw_offsetof.patch
|
||||
fix_incorrect_int_use_in_Kernel32BaseVersion.patch
|
||||
revert_removal_of_AlterEnvironment_on_Windows.patch
|
||||
allow_env_changes.patch
|
||||
ifdef_out_AppContainerProfileBase_testing_functions.patch
|
||||
mingw_missing_windows_types_defines.patch
|
||||
mingw_undefine_MemoryBarrier.patch
|
||||
add_return_in_QueryCancellationTraitsForNonCancellables_to_satisfy_build.patch
|
||||
include_atomic_header_in_platform_thread.patch
|
||||
aarch64_control_flow_guard.patch
|
||||
revert_removal_of_app_dir_for_DLL_load.patch
|
||||
more_chromium_linux_x86_x64_syscalls.patch
|
||||
add_support_for_random_restricted_SID.patch
|
||||
revert_Token_serialization_and_deserialization.patch
|
||||
remove_unused_functions_from_StrtodTrimmed.patch
|
||||
remove_extraneous_backslash_introduced_by_clang_tidy.patch
|
||||
remove_include_delayimp_h_from_pe_image_cc.patch
|
||||
lower_SDK_version_requirement.patch
|
||||
public_siginfo_fields.patch
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
# HG changeset patch
|
||||
# User Michael Forney <mforney@mforney.org>
|
||||
# Date 1581009438 0
|
||||
# Thu Feb 06 17:17:18 2020 +0000
|
||||
# Node ID 3ec8c96f4d53916de5223b2eda5e8d66fb6ca227
|
||||
# Parent 362056ef41086e1faf6ee088c1daef9c73e01370
|
||||
Bug 1611565 - Cherry-pick upstream patch to use public siginfo_t fields r=gcp
|
||||
|
||||
Upstream patch:
|
||||
https://chromium.googlesource.com/chromium/src.git/+/6bd491daaf28a8281136931133504c23a18f819f%5E%21/#F0
|
||||
|
||||
_sifields is a glibc-internal field, and is not available on musl
|
||||
libc. Instead, use the public-facing fields si_call_addr, si_syscall,
|
||||
and si_arch, if they are available.
|
||||
|
||||
Differential Revision: https://phabricator.services.mozilla.com/D61051
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc
|
||||
--- a/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/linux/seccomp-bpf/trap.cc
|
||||
@@ -159,21 +159,28 @@ void Trap::SigSys(int nr, LinuxSigInfo*
|
||||
// See crbug.com/178166.
|
||||
// TODO(jln): add a DCHECK or move back to FATAL.
|
||||
RAW_LOG(ERROR, "Unexpected SIGSYS received.");
|
||||
errno = old_errno;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
- // Obtain the siginfo information that is specific to SIGSYS. Unfortunately,
|
||||
- // most versions of glibc don't include this information in siginfo_t. So,
|
||||
- // we need to explicitly copy it into a arch_sigsys structure.
|
||||
+ // Obtain the siginfo information that is specific to SIGSYS.
|
||||
struct arch_sigsys sigsys;
|
||||
+#if defined(si_call_addr) && !defined(__native_client_nonsfi__)
|
||||
+ sigsys.ip = info->si_call_addr;
|
||||
+ sigsys.nr = info->si_syscall;
|
||||
+ sigsys.arch = info->si_arch;
|
||||
+#else
|
||||
+ // If the version of glibc doesn't include this information in
|
||||
+ // siginfo_t (older than 2.17), we need to explicitly copy it
|
||||
+ // into an arch_sigsys structure.
|
||||
memcpy(&sigsys, &info->_sifields, sizeof(sigsys));
|
||||
+#endif
|
||||
|
||||
#if defined(__mips__)
|
||||
// When indirect syscall (syscall(__NR_foo, ...)) is made on Mips, the
|
||||
// number in register SECCOMP_SYSCALL(ctx) is always __NR_syscall and the
|
||||
// real number of a syscall (__NR_foo) is in SECCOMP_PARM1(ctx)
|
||||
bool sigsys_nr_is_bad = sigsys.nr != static_cast<int>(SECCOMP_SYSCALL(ctx)) &&
|
||||
sigsys.nr != static_cast<int>(SECCOMP_PARM1(ctx));
|
||||
#else
|
|
@ -1,34 +0,0 @@
|
|||
# HG changeset patch
|
||||
# User Toshihito Kikuchi <tkikuchi@mozilla.com>
|
||||
# Date 1588867789 25200
|
||||
# Thu May 07 09:09:49 2020 -0700
|
||||
# Node ID 29fbfefe6f5f533fb5aa4339015cea4746ad6493
|
||||
# Parent 044c15e89ecca19afc1750c439f4e82879679462
|
||||
Remove Extraneous Backslash Introduced by clang-tidy in ScopedHandle. r=bobowen
|
||||
|
||||
Need the following commit to compile with Mingw, which has not reached
|
||||
the stable channel yet.
|
||||
https://chromium.googlesource.com/chromium/src.git/+/1620fe70c299f1f18b2f2c652d16739f6e3c5f78
|
||||
|
||||
diff --git a/security/sandbox/chromium/base/win/scoped_handle.h b/security/sandbox/chromium/base/win/scoped_handle.h
|
||||
--- a/security/sandbox/chromium/base/win/scoped_handle.h
|
||||
+++ b/security/sandbox/chromium/base/win/scoped_handle.h
|
||||
@@ -15,17 +15,17 @@
|
||||
#include "base/macros.h"
|
||||
|
||||
// TODO(rvargas): remove this with the rest of the verifier.
|
||||
#if defined(COMPILER_MSVC)
|
||||
#include <intrin.h>
|
||||
#define BASE_WIN_GET_CALLER _ReturnAddress()
|
||||
#elif defined(COMPILER_GCC)
|
||||
#define BASE_WIN_GET_CALLER \
|
||||
- __builtin_extract_return_addr(\ __builtin_return_address(0))
|
||||
+ __builtin_extract_return_addr(__builtin_return_address(0))
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace win {
|
||||
|
||||
// Generic wrapper for raw handles that takes care of closing handles
|
||||
// automatically. The class interface follows the style of
|
||||
// the ScopedFILE class with two additions:
|
|
@ -1,32 +0,0 @@
|
|||
# HG changeset patch
|
||||
# User Toshihito Kikuchi <tkikuchi@mozilla.com>
|
||||
# Date 1588871424 25200
|
||||
# Thu May 07 10:10:24 2020 -0700
|
||||
# Node ID 2d5ee142bde533ba4f93afaae081a444eac0abe2
|
||||
# Parent 29fbfefe6f5f533fb5aa4339015cea4746ad6493
|
||||
Don't include delayimp.h twice from //base/win/pe_image.cc to compile with Mingw. r=bobowen
|
||||
|
||||
The second include was introduced by
|
||||
https://chromium.googlesource.com/chromium/src.git/+/5c23d46846111ea16aaf2a9b45355cca5ddbf6d8
|
||||
|
||||
diff --git a/security/sandbox/chromium/base/win/pe_image.cc b/security/sandbox/chromium/base/win/pe_image.cc
|
||||
--- a/security/sandbox/chromium/base/win/pe_image.cc
|
||||
+++ b/security/sandbox/chromium/base/win/pe_image.cc
|
||||
@@ -2,17 +2,16 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file implements PEImage, a generic class to manipulate PE files.
|
||||
// This file was adapted from GreenBorder's Code.
|
||||
|
||||
#include "base/win/pe_image.h"
|
||||
|
||||
-#include <delayimp.h>
|
||||
#include <stddef.h>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/win/current_module.h"
|
||||
|
||||
namespace base {
|
|
@ -1,48 +0,0 @@
|
|||
# HG changeset patch
|
||||
# User Toshihito Kikuchi <tkikuchi@mozilla.com>
|
||||
# Date 1588733379 25200
|
||||
# Tue May 05 19:49:39 2020 -0700
|
||||
# Node ID 044c15e89ecca19afc1750c439f4e82879679462
|
||||
# Parent a18431660425e41c26c716413aac0294987c985a
|
||||
Remove unused functions from //base/third_party/double_conversion/double-conversion to compile. r=bobowen
|
||||
|
||||
diff --git a/security/sandbox/chromium/base/third_party/double_conversion/double-conversion/strtod.cc b/security/sandbox/chromium/base/third_party/double_conversion/double-conversion/strtod.cc
|
||||
--- a/security/sandbox/chromium/base/third_party/double_conversion/double-conversion/strtod.cc
|
||||
+++ b/security/sandbox/chromium/base/third_party/double_conversion/double-conversion/strtod.cc
|
||||
@@ -445,36 +445,18 @@ static bool ComputeGuess(Vector<const ch
|
||||
return true;
|
||||
}
|
||||
if (*guess == Double::Infinity()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
-static bool IsDigit(const char d) {
|
||||
- return ('0' <= d) && (d <= '9');
|
||||
-}
|
||||
-
|
||||
-static bool IsNonZeroDigit(const char d) {
|
||||
- return ('1' <= d) && (d <= '9');
|
||||
-}
|
||||
-
|
||||
-static bool AssertTrimmedDigits(const Vector<const char>& buffer) {
|
||||
- for(int i = 0; i < buffer.length(); ++i) {
|
||||
- if(!IsDigit(buffer[i])) {
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
- return (buffer.length() == 0) || (IsNonZeroDigit(buffer[0]) && IsNonZeroDigit(buffer[buffer.length()-1]));
|
||||
-}
|
||||
-
|
||||
double StrtodTrimmed(Vector<const char> trimmed, int exponent) {
|
||||
DOUBLE_CONVERSION_ASSERT(trimmed.length() <= kMaxSignificantDecimalDigits);
|
||||
- DOUBLE_CONVERSION_ASSERT(AssertTrimmedDigits(trimmed));
|
||||
double guess;
|
||||
const bool is_correct = ComputeGuess(trimmed, exponent, &guess);
|
||||
if (is_correct) {
|
||||
return guess;
|
||||
}
|
||||
DiyFp upper_boundary = Double(guess).UpperBoundary();
|
||||
int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
|
||||
if (comparison < 0) {
|
|
@ -1,59 +0,0 @@
|
|||
# HG changeset patch
|
||||
# User Toshihito Kikuchi <tkikuchi@mozilla.com>
|
||||
# Date 1589672273 25200
|
||||
# Sat May 16 16:37:53 2020 -0700
|
||||
# Node ID c14ef8304c36fdc2570b77b63b36114cff2d070d
|
||||
# Parent 90b5f63770f52fab163adaed1d5812b2887b335a
|
||||
Use GetModuleHandle/GetProcAddress in ApplyMitigationsToCurrentThread. r=bobowen
|
||||
|
||||
This patch removes the use of base::ScopedNativeLibrary from
|
||||
sandbox::ApplyMitigationsToCurrentThread because to avoid
|
||||
new dependencies.
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc b/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/process_mitigations.cc
|
||||
@@ -5,18 +5,16 @@
|
||||
#include "sandbox/win/src/process_mitigations.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <windows.h>
|
||||
#include <wow64apiset.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
-#include "base/files/file_path.h"
|
||||
-#include "base/scoped_native_library.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "build/build_config.h"
|
||||
#include "sandbox/win/src/nt_internals.h"
|
||||
#include "sandbox/win/src/restricted_token_utils.h"
|
||||
#include "sandbox/win/src/sandbox_rand.h"
|
||||
#include "sandbox/win/src/win_utils.h"
|
||||
|
||||
namespace {
|
||||
@@ -321,22 +319,19 @@ bool ApplyMitigationsToCurrentThread(Mit
|
||||
return true;
|
||||
|
||||
// Enable dynamic code per-thread policies.
|
||||
if (flags & MITIGATION_DYNAMIC_CODE_OPT_OUT_THIS_THREAD) {
|
||||
DWORD thread_policy = THREAD_DYNAMIC_CODE_ALLOW;
|
||||
|
||||
// NOTE: SetThreadInformation API only exists on >= Win8. Dynamically
|
||||
// get function handle.
|
||||
- base::ScopedNativeLibrary dll(base::FilePath(L"kernel32.dll"));
|
||||
- if (!dll.is_valid())
|
||||
- return false;
|
||||
SetThreadInformationFunction set_thread_info_function =
|
||||
- reinterpret_cast<SetThreadInformationFunction>(
|
||||
- dll.GetFunctionPointer("SetThreadInformation"));
|
||||
+ reinterpret_cast<SetThreadInformationFunction>(::GetProcAddress(
|
||||
+ ::GetModuleHandleA("kernel32.dll"), "SetThreadInformation"));
|
||||
if (!set_thread_info_function)
|
||||
return false;
|
||||
|
||||
// NOTE: Must use the pseudo-handle here, a thread HANDLE won't work.
|
||||
if (!set_thread_info_function(::GetCurrentThread(), ThreadDynamicCodePolicy,
|
||||
&thread_policy, sizeof(thread_policy))) {
|
||||
return false;
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
# HG changeset patch
|
||||
# User Toshihito Kikuchi <tkikuchi@mozilla.com>
|
||||
# Date 1588530677 25200
|
||||
# Sun May 03 11:31:17 2020 -0700
|
||||
# Node ID a18431660425e41c26c716413aac0294987c985a
|
||||
# Parent e149b1937231ccc3c1c07f45acf0e7e71117854f
|
||||
Revert chromium's ffe1d0eb42d1d75f2b6a3b4145eff69f235a19ee. r=bobowen
|
||||
|
||||
Undoing the following commit as it brings more dependency but unused in our code.
|
||||
https://chromium.googlesource.com/chromium/src.git/+/ffe1d0eb42d1d75f2b6a3b4145eff69f235a19ee
|
||||
|
||||
diff --git a/security/sandbox/chromium/base/token.cc b/security/sandbox/chromium/base/token.cc
|
||||
--- a/security/sandbox/chromium/base/token.cc
|
||||
+++ b/security/sandbox/chromium/base/token.cc
|
||||
@@ -1,17 +1,16 @@
|
||||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/token.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
-#include "base/pickle.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// static
|
||||
Token Token::CreateRandom() {
|
||||
Token token;
|
||||
@@ -21,26 +20,9 @@ Token Token::CreateRandom() {
|
||||
base::RandBytes(&token, sizeof(token));
|
||||
return token;
|
||||
}
|
||||
|
||||
std::string Token::ToString() const {
|
||||
return base::StringPrintf("%016" PRIX64 "%016" PRIX64, high_, low_);
|
||||
}
|
||||
|
||||
-void WriteTokenToPickle(Pickle* pickle, const Token& token) {
|
||||
- pickle->WriteUInt64(token.high());
|
||||
- pickle->WriteUInt64(token.low());
|
||||
-}
|
||||
-
|
||||
-Optional<Token> ReadTokenFromPickle(PickleIterator* pickle_iterator) {
|
||||
- uint64_t high;
|
||||
- if (!pickle_iterator->ReadUInt64(&high))
|
||||
- return nullopt;
|
||||
-
|
||||
- uint64_t low;
|
||||
- if (!pickle_iterator->ReadUInt64(&low))
|
||||
- return nullopt;
|
||||
-
|
||||
- return Token(high, low);
|
||||
-}
|
||||
-
|
||||
} // namespace base
|
||||
diff --git a/security/sandbox/chromium/base/token.h b/security/sandbox/chromium/base/token.h
|
||||
--- a/security/sandbox/chromium/base/token.h
|
||||
+++ b/security/sandbox/chromium/base/token.h
|
||||
@@ -7,17 +7,16 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <tuple>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/hash/hash.h"
|
||||
-#include "base/optional.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// A Token is a randomly chosen 128-bit integer. This class supports generation
|
||||
// from a cryptographically strong random source, or constexpr construction over
|
||||
// fixed values (e.g. to store a pre-generated constant value). Tokens are
|
||||
// similar in spirit and purpose to UUIDs, without many of the constraints and
|
||||
// expectations (such as byte layout and string representation) clasically
|
||||
@@ -63,19 +62,11 @@ class BASE_EXPORT Token {
|
||||
|
||||
// For use in std::unordered_map.
|
||||
struct TokenHash {
|
||||
size_t operator()(const base::Token& token) const {
|
||||
return base::HashInts64(token.high(), token.low());
|
||||
}
|
||||
};
|
||||
|
||||
-class Pickle;
|
||||
-class PickleIterator;
|
||||
-
|
||||
-// For serializing and deserializing Token values.
|
||||
-BASE_EXPORT void WriteTokenToPickle(Pickle* pickle, const Token& token);
|
||||
-BASE_EXPORT Optional<Token> ReadTokenFromPickle(
|
||||
- PickleIterator* pickle_iterator);
|
||||
-
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_TOKEN_H_
|
|
@ -0,0 +1,150 @@
|
|||
# HG changeset patch
|
||||
# User Bob Owen <bobowencode@gmail.com>
|
||||
# Date 1560256605 -3600
|
||||
# Tue Jun 11 13:36:45 2019 +0100
|
||||
# Node ID 686d4b711b65b7cd8692e92e9a7ae152a942b69e
|
||||
# Parent 213d707af158b3d276c8cce56aba2e3c27abda82
|
||||
Bug 1552160: Revert removal of AlterEnvironment from chromium code on Windows. r=jld
|
||||
|
||||
diff --git a/security/sandbox/chromium/base/environment.cc b/security/sandbox/chromium/base/environment.cc
|
||||
--- a/security/sandbox/chromium/base/environment.cc
|
||||
+++ b/security/sandbox/chromium/base/environment.cc
|
||||
@@ -96,34 +96,32 @@ class EnvironmentImpl : public Environme
|
||||
return !!SetEnvironmentVariable(UTF8ToWide(variable_name).c_str(), nullptr);
|
||||
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
// On success, zero is returned.
|
||||
return !unsetenv(variable_name.data());
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
// Parses a null-terminated input string of an environment block. The key is
|
||||
// placed into the given string, and the total length of the line, including
|
||||
// the terminating null, is returned.
|
||||
size_t ParseEnvLine(const NativeEnvironmentString::value_type* input,
|
||||
NativeEnvironmentString* key) {
|
||||
// Skip to the equals or end of the string, this is the key.
|
||||
size_t cur = 0;
|
||||
while (input[cur] && input[cur] != '=')
|
||||
cur++;
|
||||
*key = NativeEnvironmentString(&input[0], cur);
|
||||
|
||||
// Now just skip to the end of the string.
|
||||
while (input[cur])
|
||||
cur++;
|
||||
return cur + 1;
|
||||
}
|
||||
-#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace env_vars {
|
||||
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
// On Posix systems, this variable contains the location of the user's home
|
||||
// directory. (e.g, /home/username/).
|
||||
@@ -138,17 +136,57 @@ Environment::~Environment() = default;
|
||||
std::unique_ptr<Environment> Environment::Create() {
|
||||
return std::make_unique<EnvironmentImpl>();
|
||||
}
|
||||
|
||||
bool Environment::HasVar(StringPiece variable_name) {
|
||||
return GetVar(variable_name, nullptr);
|
||||
}
|
||||
|
||||
-#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
+#if defined(OS_WIN)
|
||||
+
|
||||
+string16 AlterEnvironment(const wchar_t* env,
|
||||
+ const EnvironmentMap& changes) {
|
||||
+ string16 result;
|
||||
+
|
||||
+ // First copy all unmodified values to the output.
|
||||
+ size_t cur_env = 0;
|
||||
+ string16 key;
|
||||
+ while (env[cur_env]) {
|
||||
+ const wchar_t* line = &env[cur_env];
|
||||
+ size_t line_length = ParseEnvLine(line, &key);
|
||||
+
|
||||
+ // Keep only values not specified in the change vector.
|
||||
+ EnvironmentMap::const_iterator found_change = changes.find(key);
|
||||
+ if (found_change == changes.end())
|
||||
+ result.append(line, line_length);
|
||||
+
|
||||
+ cur_env += line_length;
|
||||
+ }
|
||||
+
|
||||
+ // Now append all modified and new values.
|
||||
+ for (EnvironmentMap::const_iterator i = changes.begin();
|
||||
+ i != changes.end(); ++i) {
|
||||
+ if (!i->second.empty()) {
|
||||
+ result.append(i->first);
|
||||
+ result.push_back('=');
|
||||
+ result.append(i->second);
|
||||
+ result.push_back(0);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // An additional null marks the end of the list. We always need a double-null
|
||||
+ // in case nothing was added above.
|
||||
+ if (result.empty())
|
||||
+ result.push_back(0);
|
||||
+ result.push_back(0);
|
||||
+ return result;
|
||||
+}
|
||||
+
|
||||
+#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
|
||||
std::unique_ptr<char* []> AlterEnvironment(const char* const* const env,
|
||||
const EnvironmentMap& changes) {
|
||||
std::string value_storage; // Holds concatenated null-terminated strings.
|
||||
std::vector<size_t> result_indices; // Line indices into value_storage.
|
||||
|
||||
// First build up all of the unchanged environment strings. These are
|
||||
// null-terminated of the form "key=value".
|
||||
diff --git a/security/sandbox/chromium/base/environment.h b/security/sandbox/chromium/base/environment.h
|
||||
--- a/security/sandbox/chromium/base/environment.h
|
||||
+++ b/security/sandbox/chromium/base/environment.h
|
||||
@@ -48,27 +48,36 @@ class BASE_EXPORT Environment {
|
||||
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
typedef string16 NativeEnvironmentString;
|
||||
typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
|
||||
EnvironmentMap;
|
||||
|
||||
+// Returns a modified environment vector constructed from the given environment
|
||||
+// and the list of changes given in |changes|. Each key in the environment is
|
||||
+// matched against the first element of the pairs. In the event of a match, the
|
||||
+// value is replaced by the second of the pair, unless the second is empty, in
|
||||
+// which case the key-value is removed.
|
||||
+//
|
||||
+// This Windows version takes and returns a Windows-style environment block
|
||||
+// which is a concatenated list of null-terminated 16-bit strings. The end is
|
||||
+// marked by a double-null terminator. The size of the returned string will
|
||||
+// include the terminators.
|
||||
+BASE_EXPORT string16 AlterEnvironment(const wchar_t* env,
|
||||
+ const EnvironmentMap& changes);
|
||||
+
|
||||
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
|
||||
typedef std::string NativeEnvironmentString;
|
||||
typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
|
||||
EnvironmentMap;
|
||||
|
||||
-// Returns a modified environment vector constructed from the given environment
|
||||
-// and the list of changes given in |changes|. Each key in the environment is
|
||||
-// matched against the first element of the pairs. In the event of a match, the
|
||||
-// value is replaced by the second of the pair, unless the second is empty, in
|
||||
-// which case the key-value is removed.
|
||||
+// See general comments for the Windows version above.
|
||||
//
|
||||
// This Posix version takes and returns a Posix-style environment block, which
|
||||
// is a null-terminated list of pointers to null-terminated strings. The
|
||||
// returned array will have appended to it the storage for the array itself so
|
||||
// there is only one pointer to manage, but this means that you can't copy the
|
||||
// array without keeping the original around.
|
||||
BASE_EXPORT std::unique_ptr<char* []> AlterEnvironment(
|
||||
const char* const* env,
|
|
@ -1,53 +1,88 @@
|
|||
# HG changeset patch
|
||||
# User Toshihito Kikuchi <tkikuchi@mozilla.com>
|
||||
# Date 1589671259 25200
|
||||
# Sat May 16 16:20:59 2020 -0700
|
||||
# Node ID 0b5183a01df78cc85264f2eae2c4d8e407bb1112
|
||||
# Parent d093cd9ccfcf06f4a1f0d7f1a4bd0f143ef92b4b
|
||||
Add BrokerServicesBase::IsSafeDuplicationTarget. r=bobowen
|
||||
# User Bob Owen <bobowencode@gmail.com>
|
||||
# Date 1485985799 0
|
||||
# Wed Feb 01 21:49:59 2017 +0000
|
||||
# Node ID 8faee368c603dab03076d8900f01acfd776caaeb
|
||||
# Parent dba4611d335189b9a3314f5dc57935f554c8b945
|
||||
Reinstate sandbox::BrokerServices::AddTargetPeer r=aklotz
|
||||
|
||||
This patch adds BrokerServicesBase::IsSafeDuplicationTarget and
|
||||
BrokerServicesBase::AddTargetPeer using the new ProcessTracker introduced by
|
||||
https://chromium.googlesource.com/chromium/src.git/+/3d8382cf9dd44cf9c05e43e42c500f4825e1fed8
|
||||
We need these methods for HandlePolicy which is added as a different patch.
|
||||
|
||||
Chromium used to have AddTargetPeer and IsActiveTarget, but removed by
|
||||
the following commits because they were no longer used in Chromium.
|
||||
https://chromium.googlesource.com/chromium/src.git/+/996b42db5296bd3d11b3d7fde1a4602bbcefed2c
|
||||
https://chromium.googlesource.com/chromium/src.git/+/e615a1152ac6e10f1a91f0629fb8b5ca223ffbdc
|
||||
This is basically a revert of chromium commit 996b42db5296bd3d11b3d7fde1a4602bbcefed2c.
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.cc b/security/sandbox/chromium/sandbox/win/src/broker_services.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/broker_services.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/broker_services.cc
|
||||
@@ -154,16 +154,18 @@ namespace sandbox {
|
||||
@@ -41,16 +41,17 @@ sandbox::ResultCode SpawnCleanup(sandbox
|
||||
delete target;
|
||||
return sandbox::SBOX_ERROR_GENERIC;
|
||||
}
|
||||
|
||||
// the different commands that you can send to the worker thread that
|
||||
// executes TargetEventsThread().
|
||||
enum {
|
||||
THREAD_CTRL_NONE,
|
||||
+ THREAD_CTRL_REMOVE_PEER,
|
||||
THREAD_CTRL_QUIT,
|
||||
THREAD_CTRL_LAST,
|
||||
};
|
||||
|
||||
// Helper structure that allows the Broker to associate a job notification
|
||||
// with a job object and with a policy.
|
||||
struct JobTracker {
|
||||
JobTracker(base::win::ScopedHandle job,
|
||||
@@ -77,16 +78,37 @@ void JobTracker::FreeResources() {
|
||||
HANDLE stale_job_handle = job.Get();
|
||||
job.Close();
|
||||
|
||||
// In OnJobEmpty() we don't actually use the job handle directly.
|
||||
policy->OnJobEmpty(stale_job_handle);
|
||||
policy = nullptr;
|
||||
}
|
||||
}
|
||||
+
|
||||
+// Helper structure that allows the broker to track peer processes
|
||||
+struct PeerTracker {
|
||||
+ PeerTracker(DWORD process_id, HANDLE broker_job_port)
|
||||
+ : wait_object(NULL), id(process_id), job_port(broker_job_port) {
|
||||
+ }
|
||||
+
|
||||
+ HANDLE wait_object;
|
||||
+ base::win::ScopedHandle process;
|
||||
+ DWORD id;
|
||||
+ HANDLE job_port;
|
||||
+};
|
||||
+
|
||||
+void DeregisterPeerTracker(PeerTracker* peer) {
|
||||
+ // Deregistration shouldn't fail, but we leak rather than crash if it does.
|
||||
+ if (::UnregisterWaitEx(peer->wait_object, INVALID_HANDLE_VALUE)) {
|
||||
+ delete peer;
|
||||
+ } else {
|
||||
+ NOTREACHED();
|
||||
+ }
|
||||
+}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace sandbox {
|
||||
|
||||
BrokerServicesBase::BrokerServicesBase() {}
|
||||
|
||||
// The broker uses a dedicated worker thread that services the job completion
|
||||
// port to perform policy notifications and associated cleanup tasks.
|
||||
ResultCode BrokerServicesBase::Init() {
|
||||
if (job_port_.IsValid() || thread_pool_)
|
||||
return SBOX_ERROR_UNEXPECTED_CALL;
|
||||
|
||||
+ ::InitializeCriticalSection(&lock_);
|
||||
+
|
||||
job_port_.Set(::CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0));
|
||||
if (!job_port_.IsValid())
|
||||
return SBOX_ERROR_CANNOT_INIT_BROKERSERVICES;
|
||||
|
||||
no_targets_.Set(::CreateEventW(nullptr, true, false, nullptr));
|
||||
|
||||
job_thread_.Set(::CreateThread(nullptr, 0, // Default security and stack.
|
||||
TargetEventsThread, this, 0, nullptr));
|
||||
@@ -191,16 +193,17 @@ BrokerServicesBase::~BrokerServicesBase(
|
||||
|
||||
if (job_thread_.IsValid() &&
|
||||
WAIT_TIMEOUT == ::WaitForSingleObject(job_thread_.Get(), 1000)) {
|
||||
@@ -132,16 +154,22 @@ BrokerServicesBase::~BrokerServicesBase(
|
||||
// Cannot clean broker services.
|
||||
NOTREACHED();
|
||||
return;
|
||||
}
|
||||
|
||||
tracker_list_.clear();
|
||||
thread_pool_.reset();
|
||||
+ ::DeleteCriticalSection(&lock_);
|
||||
|
||||
+ // Cancel the wait events and delete remaining peer trackers.
|
||||
+ for (PeerTrackerMap::iterator it = peer_map_.begin();
|
||||
+ it != peer_map_.end(); ++it) {
|
||||
+ DeregisterPeerTracker(it->second);
|
||||
+ }
|
||||
+
|
||||
::DeleteCriticalSection(&lock_);
|
||||
}
|
||||
|
||||
scoped_refptr<TargetPolicy> BrokerServicesBase::CreatePolicy() {
|
||||
|
@ -55,99 +90,45 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.cc b/secu
|
|||
// change the downcast to it in SpawnTarget().
|
||||
scoped_refptr<TargetPolicy> policy(new PolicyBase);
|
||||
// PolicyBase starts with refcount 1.
|
||||
policy->Release();
|
||||
@@ -283,16 +286,21 @@ DWORD WINAPI BrokerServicesBase::TargetE
|
||||
if (1 == target_counter) {
|
||||
::ResetEvent(no_targets);
|
||||
}
|
||||
@@ -247,16 +275,23 @@ DWORD WINAPI BrokerServicesBase::TargetE
|
||||
break;
|
||||
}
|
||||
|
||||
case JOB_OBJECT_MSG_EXIT_PROCESS:
|
||||
case JOB_OBJECT_MSG_ABNORMAL_EXIT_PROCESS: {
|
||||
+ {
|
||||
+ AutoLock lock(&broker->lock_);
|
||||
+ broker->active_targets_.erase(
|
||||
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)));
|
||||
+ }
|
||||
size_t erase_result = child_process_ids.erase(
|
||||
static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)));
|
||||
if (erase_result != 1U) {
|
||||
// The process was untracked e.g. a child process of the target.
|
||||
--untracked_target_counter;
|
||||
DCHECK(untracked_target_counter >= 0);
|
||||
}
|
||||
--target_counter;
|
||||
@@ -348,27 +356,31 @@ DWORD WINAPI BrokerServicesBase::TargetE
|
||||
tracker->wait_handle = INVALID_HANDLE_VALUE;
|
||||
default: {
|
||||
NOTREACHED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
processes.push_back(std::move(tracker));
|
||||
|
||||
} else if (THREAD_CTRL_PROCESS_SIGNALLED == key) {
|
||||
ProcessTracker* tracker =
|
||||
static_cast<ProcessTracker*>(reinterpret_cast<void*>(ovl));
|
||||
|
||||
+ {
|
||||
+ AutoLock lock(&broker->lock_);
|
||||
+ broker->active_targets_.erase(tracker->process_id);
|
||||
+ }
|
||||
+
|
||||
::UnregisterWait(tracker->wait_handle);
|
||||
tracker->wait_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
// PID is unique until the process handle is closed in dtor.
|
||||
processes.erase(std::remove_if(processes.begin(), processes.end(),
|
||||
[&](auto&& p) -> bool {
|
||||
return p->process_id ==
|
||||
tracker->process_id;
|
||||
}),
|
||||
processes.end());
|
||||
-
|
||||
} else if (THREAD_CTRL_GET_POLICY_INFO == key) {
|
||||
// Clone the policies for sandbox diagnostics.
|
||||
std::unique_ptr<PolicyDiagnosticsReceiver> receiver;
|
||||
receiver.reset(static_cast<PolicyDiagnosticsReceiver*>(
|
||||
reinterpret_cast<void*>(ovl)));
|
||||
// The PollicyInfo ctor copies essential information from the trackers.
|
||||
auto policy_list = std::make_unique<PolicyDiagnosticList>();
|
||||
for (auto&& process_tracker : processes) {
|
||||
@@ -637,47 +649,79 @@ ResultCode BrokerServicesBase::SpawnTarg
|
||||
// the tracker. The worker thread takes ownership of these objects.
|
||||
CHECK(::PostQueuedCompletionStatus(
|
||||
job_port_.Get(), 0, THREAD_CTRL_NEW_JOB_TRACKER,
|
||||
reinterpret_cast<LPOVERLAPPED>(tracker)));
|
||||
// There is no obvious recovery after failure here. Previous version with
|
||||
// SpawnCleanup() caused deletion of TargetProcess twice. crbug.com/480639
|
||||
CHECK(
|
||||
AssociateCompletionPort(tracker->job.Get(), job_port_.Get(), tracker));
|
||||
+
|
||||
+ AutoLock lock(&lock_);
|
||||
+ active_targets_.insert(process_info.process_id());
|
||||
} else {
|
||||
- // Duplicate the process handle to give the tracking machinery
|
||||
- // something valid to wait on in the tracking thread.
|
||||
- HANDLE tmp_process_handle = INVALID_HANDLE_VALUE;
|
||||
- if (!::DuplicateHandle(::GetCurrentProcess(), process_info.process_handle(),
|
||||
- ::GetCurrentProcess(), &tmp_process_handle,
|
||||
- SYNCHRONIZE, false, 0 /*no options*/)) {
|
||||
- *last_error = ::GetLastError();
|
||||
+ result = AddTargetPeerInternal(process_info.process_handle(),
|
||||
+ process_info.process_id(),
|
||||
+ policy_base, last_error);
|
||||
+ if (result != SBOX_ALL_OK) {
|
||||
// This may fail in the same way as Job associated processes.
|
||||
// crbug.com/480639.
|
||||
SpawnCleanup(target);
|
||||
- return SBOX_ERROR_CANNOT_DUPLICATE_PROCESS_HANDLE;
|
||||
+ return result;
|
||||
+ } else if (THREAD_CTRL_REMOVE_PEER == key) {
|
||||
+ // Remove a process from our list of peers.
|
||||
+ AutoLock lock(&broker->lock_);
|
||||
+ PeerTrackerMap::iterator it = broker->peer_map_.find(
|
||||
+ static_cast<DWORD>(reinterpret_cast<uintptr_t>(ovl)));
|
||||
+ DeregisterPeerTracker(it->second);
|
||||
+ broker->peer_map_.erase(it);
|
||||
} else if (THREAD_CTRL_QUIT == key) {
|
||||
// The broker object is being destroyed so the thread needs to exit.
|
||||
return 0;
|
||||
} else {
|
||||
// We have not implemented more commands.
|
||||
NOTREACHED();
|
||||
}
|
||||
- base::win::ScopedHandle dup_process_handle(tmp_process_handle);
|
||||
- ProcessTracker* tracker = new ProcessTracker(
|
||||
- policy_base, process_info.process_id(), std::move(dup_process_handle));
|
||||
- // The tracker and policy will leak if this call fails.
|
||||
- ::PostQueuedCompletionStatus(job_port_.Get(), 0,
|
||||
- THREAD_CTRL_NEW_PROCESS_TRACKER,
|
||||
- reinterpret_cast<LPOVERLAPPED>(tracker));
|
||||
}
|
||||
@@ -460,25 +495,70 @@ ResultCode BrokerServicesBase::SpawnTarg
|
||||
// TODO(wfh): Find a way to make this have the correct lifetime.
|
||||
policy_base->AddRef();
|
||||
|
||||
// We have to signal the event once here because the completion port will
|
||||
// never get a message that this target is being terminated thus we should
|
||||
// not block WaitForAllTargets until we have at least one target with job.
|
||||
if (child_process_ids_.empty())
|
||||
::SetEvent(no_targets_.Get());
|
||||
+ // We can not track the life time of such processes and it is responsibility
|
||||
+ // of the host application to make sure that spawned targets without jobs
|
||||
+ // are terminated when the main application don't need them anymore.
|
||||
+ // Sandbox policy engine needs to know that these processes are valid
|
||||
+ // targets for e.g. BrokerDuplicateHandle so track them as peer processes.
|
||||
+ AddTargetPeer(process_info.process_handle());
|
||||
}
|
||||
|
||||
*target_info = process_info.Take();
|
||||
|
@ -159,75 +140,74 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.cc b/secu
|
|||
return SBOX_ALL_OK;
|
||||
}
|
||||
|
||||
+bool BrokerServicesBase::IsSafeDuplicationTarget(DWORD process_id) {
|
||||
+ AutoLock lock(&lock_);
|
||||
+ return active_targets_.find(process_id) != active_targets_.end();
|
||||
bool BrokerServicesBase::IsActiveTarget(DWORD process_id) {
|
||||
AutoLock lock(&lock_);
|
||||
- return child_process_ids_.find(process_id) != child_process_ids_.end();
|
||||
+ return child_process_ids_.find(process_id) != child_process_ids_.end() ||
|
||||
+ peer_map_.find(process_id) != peer_map_.end();
|
||||
+}
|
||||
+
|
||||
+ResultCode BrokerServicesBase::AddTargetPeerInternal(
|
||||
+ HANDLE peer_process_handle,
|
||||
+ DWORD peer_process_id,
|
||||
+ scoped_refptr<PolicyBase> policy_base,
|
||||
+ DWORD* last_error) {
|
||||
+ // Duplicate the process handle to give the tracking machinery
|
||||
+ // something valid to wait on in the tracking thread.
|
||||
+ HANDLE tmp_process_handle = INVALID_HANDLE_VALUE;
|
||||
+ if (!::DuplicateHandle(::GetCurrentProcess(), peer_process_handle,
|
||||
+ ::GetCurrentProcess(), &tmp_process_handle,
|
||||
+ SYNCHRONIZE, false, 0 /*no options*/)) {
|
||||
+ *last_error = ::GetLastError();
|
||||
+ return SBOX_ERROR_CANNOT_DUPLICATE_PROCESS_HANDLE;
|
||||
+ }
|
||||
+ base::win::ScopedHandle dup_process_handle(tmp_process_handle);
|
||||
+ ProcessTracker* tracker = new ProcessTracker(
|
||||
+ policy_base, peer_process_id, std::move(dup_process_handle));
|
||||
+ // The tracker and policy will leak if this call fails.
|
||||
+ ::PostQueuedCompletionStatus(job_port_.Get(), 0,
|
||||
+ THREAD_CTRL_NEW_PROCESS_TRACKER,
|
||||
+ reinterpret_cast<LPOVERLAPPED>(tracker));
|
||||
+
|
||||
+ AutoLock lock(&lock_);
|
||||
+ active_targets_.insert(peer_process_id);
|
||||
+
|
||||
+ return SBOX_ALL_OK;
|
||||
+VOID CALLBACK BrokerServicesBase::RemovePeer(PVOID parameter, BOOLEAN timeout) {
|
||||
+ PeerTracker* peer = reinterpret_cast<PeerTracker*>(parameter);
|
||||
+ // Don't check the return code because we this may fail (safely) at shutdown.
|
||||
+ ::PostQueuedCompletionStatus(
|
||||
+ peer->job_port, 0, THREAD_CTRL_REMOVE_PEER,
|
||||
+ reinterpret_cast<LPOVERLAPPED>(static_cast<uintptr_t>(peer->id)));
|
||||
+}
|
||||
+
|
||||
+ResultCode BrokerServicesBase::AddTargetPeer(HANDLE peer_process) {
|
||||
+ DWORD last_error;
|
||||
+ return AddTargetPeerInternal(peer_process, ::GetProcessId(peer_process),
|
||||
+ nullptr, &last_error);
|
||||
+}
|
||||
+ std::unique_ptr<PeerTracker> peer(
|
||||
+ new PeerTracker(::GetProcessId(peer_process), job_port_.Get()));
|
||||
+ if (!peer->id)
|
||||
+ return SBOX_ERROR_GENERIC;
|
||||
+
|
||||
ResultCode BrokerServicesBase::GetPolicyDiagnostics(
|
||||
std::unique_ptr<PolicyDiagnosticsReceiver> receiver) {
|
||||
CHECK(job_thread_.IsValid());
|
||||
// Post to the job thread.
|
||||
if (!::PostQueuedCompletionStatus(
|
||||
job_port_.Get(), 0, THREAD_CTRL_GET_POLICY_INFO,
|
||||
reinterpret_cast<LPOVERLAPPED>(receiver.get()))) {
|
||||
receiver->OnError(SBOX_ERROR_GENERIC);
|
||||
+ HANDLE process_handle;
|
||||
+ if (!::DuplicateHandle(::GetCurrentProcess(), peer_process,
|
||||
+ ::GetCurrentProcess(), &process_handle,
|
||||
+ SYNCHRONIZE, FALSE, 0)) {
|
||||
+ return SBOX_ERROR_GENERIC;
|
||||
+ }
|
||||
+ peer->process.Set(process_handle);
|
||||
+
|
||||
+ AutoLock lock(&lock_);
|
||||
+ if (!peer_map_.insert(std::make_pair(peer->id, peer.get())).second)
|
||||
+ return SBOX_ERROR_BAD_PARAMS;
|
||||
+
|
||||
+ if (!::RegisterWaitForSingleObject(
|
||||
+ &peer->wait_object, peer->process.Get(), RemovePeer, peer.get(),
|
||||
+ INFINITE, WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD)) {
|
||||
+ peer_map_.erase(peer->id);
|
||||
+ return SBOX_ERROR_GENERIC;
|
||||
+ }
|
||||
+
|
||||
+ // Release the pointer since it will be cleaned up by the callback.
|
||||
+ ignore_result(peer.release());
|
||||
+ return SBOX_ALL_OK;
|
||||
}
|
||||
|
||||
} // namespace sandbox
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.h b/security/sandbox/chromium/sandbox/win/src/broker_services.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/broker_services.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/broker_services.h
|
||||
@@ -13,16 +13,17 @@
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "sandbox/win/src/crosscall_server.h"
|
||||
#include "sandbox/win/src/job.h"
|
||||
@@ -19,16 +19,17 @@
|
||||
#include "sandbox/win/src/sandbox.h"
|
||||
+#include "sandbox/win/src/sandbox_policy_base.h"
|
||||
#include "sandbox/win/src/sharedmem_ipc_server.h"
|
||||
#include "sandbox/win/src/win2k_threadpool.h"
|
||||
#include "sandbox/win/src/win_utils.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct JobTracker;
|
||||
+struct PeerTracker;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace sandbox {
|
||||
|
||||
// BrokerServicesBase ---------------------------------------------------------
|
||||
// Broker implementation version 0
|
||||
@@ -43,16 +44,24 @@ class BrokerServicesBase final : public
|
||||
//
|
||||
@@ -48,28 +49,35 @@ class BrokerServicesBase final : public
|
||||
scoped_refptr<TargetPolicy> CreatePolicy() override;
|
||||
ResultCode SpawnTarget(const wchar_t* exe_path,
|
||||
const wchar_t* command_line,
|
||||
|
@ -237,53 +217,58 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/broker_services.h b/secur
|
|||
PROCESS_INFORMATION* target) override;
|
||||
ResultCode WaitForAllTargets() override;
|
||||
+ ResultCode AddTargetPeer(HANDLE peer_process) override;
|
||||
+
|
||||
+ // Checks if the supplied process ID matches one of the broker's active
|
||||
+ // target processes. We use this method for the specific purpose of
|
||||
+ // checking if we can safely duplicate a handle to the supplied process
|
||||
+ // in DuplicateHandleProxyAction.
|
||||
+ bool IsSafeDuplicationTarget(DWORD process_id);
|
||||
+
|
||||
ResultCode GetPolicyDiagnostics(
|
||||
std::unique_ptr<PolicyDiagnosticsReceiver> receiver) override;
|
||||
|
||||
// Checks if the supplied process ID matches one of the broker's active
|
||||
// target processes
|
||||
// Returns:
|
||||
// true if there is an active target process for this ID, otherwise false.
|
||||
bool IsActiveTarget(DWORD process_id);
|
||||
|
||||
private:
|
||||
+ typedef std::list<JobTracker*> JobTrackerList;
|
||||
+ typedef std::map<DWORD, PeerTracker*> PeerTrackerMap;
|
||||
+
|
||||
// The routine that the worker thread executes. It is in charge of
|
||||
// notifications and cleanup-related tasks.
|
||||
static DWORD WINAPI TargetEventsThread(PVOID param);
|
||||
|
||||
@@ -65,14 +74,27 @@ class BrokerServicesBase final : public
|
||||
+ // Removes a target peer from the process list if it expires.
|
||||
+ static VOID CALLBACK RemovePeer(PVOID parameter, BOOLEAN timeout);
|
||||
+
|
||||
// The completion port used by the job objects to communicate events to
|
||||
// the worker thread.
|
||||
base::win::ScopedHandle job_port_;
|
||||
|
||||
// Handle to a manual-reset event that is signaled when the total target
|
||||
// process count reaches zero.
|
||||
base::win::ScopedHandle no_targets_;
|
||||
|
||||
// Handle to the worker thread that reacts to job notifications.
|
||||
base::win::ScopedHandle job_thread_;
|
||||
@@ -81,16 +89,20 @@ class BrokerServicesBase final : public
|
||||
CRITICAL_SECTION lock_;
|
||||
|
||||
// Provides a pool of threads that are used to wait on the IPC calls.
|
||||
std::unique_ptr<ThreadProvider> thread_pool_;
|
||||
|
||||
+ // The set representing the broker's active target processes including
|
||||
+ // both sandboxed and unsandboxed peer processes.
|
||||
+ std::set<DWORD> active_targets_;
|
||||
+
|
||||
+ // Lock used to protect active_targets_ from being simultaneously accessed
|
||||
+ // by multiple threads.
|
||||
+ CRITICAL_SECTION lock_;
|
||||
+
|
||||
+ ResultCode AddTargetPeerInternal(HANDLE peer_process_handle,
|
||||
+ DWORD peer_process_id,
|
||||
+ scoped_refptr<PolicyBase> policy_base,
|
||||
+ DWORD* last_error);
|
||||
// List of the trackers for closing and cleanup purposes.
|
||||
std::list<std::unique_ptr<JobTracker>> tracker_list_;
|
||||
|
||||
+ // Maps peer process IDs to the saved handle and wait event.
|
||||
+ // Prevents peer callbacks from accessing the broker after destruction.
|
||||
+ PeerTrackerMap peer_map_;
|
||||
+
|
||||
// Provides a fast lookup to identify sandboxed processes that belong to a
|
||||
// job. Consult |jobless_process_handles_| for handles of processes without
|
||||
// jobs.
|
||||
std::set<DWORD> child_process_ids_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BrokerServicesBase);
|
||||
};
|
||||
|
||||
} // namespace sandbox
|
||||
|
||||
#endif // SANDBOX_WIN_SRC_BROKER_SERVICES_H_
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.h b/security/sandbox/chromium/sandbox/win/src/sandbox.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox.h
|
||||
@@ -96,16 +96,24 @@ class BrokerServices {
|
||||
@@ -86,16 +86,24 @@ class BrokerServices {
|
||||
PROCESS_INFORMATION* target) = 0;
|
||||
|
||||
// This call blocks (waits) for all the targets to terminate.
|
||||
// Returns:
|
||||
|
@ -291,7 +276,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.h b/security/sand
|
|||
// If the return is ERROR_GENERIC, you can call ::GetLastError() to get
|
||||
// more information.
|
||||
virtual ResultCode WaitForAllTargets() = 0;
|
||||
|
||||
+
|
||||
+ // Adds an unsandboxed process as a peer for policy decisions (e.g.
|
||||
+ // HANDLES_DUP_ANY policy).
|
||||
+ // Returns:
|
||||
|
@ -299,12 +284,11 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.h b/security/sand
|
|||
+ // If the return is ERROR_GENERIC, you can call ::GetLastError() to get
|
||||
+ // more information.
|
||||
+ virtual ResultCode AddTargetPeer(HANDLE peer_process) = 0;
|
||||
+
|
||||
// This call creates a snapshot of policies managed by the sandbox and
|
||||
// returns them via a helper class.
|
||||
// Parameters:
|
||||
// receiver: The |PolicyDiagnosticsReceiver| implementation will be
|
||||
// called to accept the results of the call.
|
||||
// Returns:
|
||||
// ALL_OK if the request was dispatched. All other return values
|
||||
// imply failure, and the responder will not receive its completion
|
||||
|
||||
protected:
|
||||
~BrokerServices() {}
|
||||
};
|
||||
|
||||
// TargetServices models the current process from the perspective
|
||||
// of a target process. To obtain a pointer to it use
|
||||
// Sandbox::GetTargetServices(). Note that this call returns a non-null
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
# HG changeset patch
|
||||
# User Toshihito Kikuchi <tkikuchi@mozilla.com>
|
||||
# Date 1589671733 25200
|
||||
# Sat May 16 16:28:53 2020 -0700
|
||||
# Node ID 91bb5c3807cfe657cc24c9a3c217dd1f57db6d5c
|
||||
# Parent 22eb0bf7180801edf775be44cf299a50e01eb7bf
|
||||
Reinstate sandbox::TargetServices::BrokerDuplicateHandle. r=bobowen
|
||||
# User Bob Owen <bobowencode@gmail.com>
|
||||
# Date 1485985575 0
|
||||
# Wed Feb 01 21:46:15 2017 +0000
|
||||
# Node ID 9328428e5f863472f3702057b01d472b46b7b6a2
|
||||
# Parent 4c1880ac25a66dec6455dc88ba693096d65df704
|
||||
Reinstate sandbox::TargetServices::BrokerDuplicateHandle. r=aklotz
|
||||
|
||||
This patch reverts the commit removing sandbox::TargetServices::BrokerDuplicateHandle
|
||||
and applies the new IpcTag type.
|
||||
|
||||
https://chromium.googlesource.com/chromium/src.git/+/569193665184525ca366e65d0735f5c851106e43
|
||||
https://chromium.googlesource.com/chromium/src.git/+/c8cff7f9663ce6d1ef35e5c717f43c867c3906eb
|
||||
This basically reverts chromium commit 569193665184525ca366e65d0735f5c851106e43.
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.cc b/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.cc
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/handle_dispatcher.cc
|
||||
@@ -0,0 +1,93 @@
|
||||
@@ -0,0 +1,92 @@
|
||||
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
|
@ -41,7 +37,7 @@ new file mode 100644
|
|||
+HandleDispatcher::HandleDispatcher(PolicyBase* policy_base)
|
||||
+ : policy_base_(policy_base) {
|
||||
+ static const IPCCall duplicate_handle_proxy = {
|
||||
+ {IpcTag::DUPLICATEHANDLEPROXY,
|
||||
+ {IPC_DUPLICATEHANDLEPROXY_TAG,
|
||||
+ {VOIDPTR_TYPE, UINT32_TYPE, UINT32_TYPE, UINT32_TYPE}},
|
||||
+ reinterpret_cast<CallbackGeneric>(
|
||||
+ &HandleDispatcher::DuplicateHandleProxy)};
|
||||
|
@ -50,15 +46,14 @@ new file mode 100644
|
|||
+}
|
||||
+
|
||||
+bool HandleDispatcher::SetupService(InterceptionManager* manager,
|
||||
+ IpcTag service) {
|
||||
+ int service) {
|
||||
+ // We perform no interceptions for handles right now.
|
||||
+ switch (service) {
|
||||
+ case IpcTag::DUPLICATEHANDLEPROXY:
|
||||
+ return true;
|
||||
+
|
||||
+ default:
|
||||
+ return false;
|
||||
+ case IPC_DUPLICATEHANDLEPROXY_TAG:
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+bool HandleDispatcher::DuplicateHandleProxy(IPCInfo* ipc,
|
||||
|
@ -98,7 +93,7 @@ new file mode 100644
|
|||
+ params[HandleTarget::NAME] = ParamPickerMake(type_info->Name.Buffer);
|
||||
+ params[HandleTarget::TARGET] = ParamPickerMake(target_process_id);
|
||||
+
|
||||
+ EvalResult eval = policy_base_->EvalPolicy(IpcTag::DUPLICATEHANDLEPROXY,
|
||||
+ EvalResult eval = policy_base_->EvalPolicy(IPC_DUPLICATEHANDLEPROXY_TAG,
|
||||
+ params.GetBase());
|
||||
+ ipc->return_info.win32_result =
|
||||
+ HandlePolicy::DuplicateHandleProxyAction(eval, handle.Get(),
|
||||
|
@ -137,7 +132,7 @@ new file mode 100644
|
|||
+ ~HandleDispatcher() override {}
|
||||
+
|
||||
+ // Dispatcher interface.
|
||||
+ bool SetupService(InterceptionManager* manager, IpcTag service) override;
|
||||
+ bool SetupService(InterceptionManager* manager, int service) override;
|
||||
+
|
||||
+ private:
|
||||
+ // Processes IPC requests coming from calls to
|
||||
|
@ -189,7 +184,7 @@ new file mode 100644
|
|||
+
|
||||
+ SharedMemIPCClient ipc(memory);
|
||||
+ CrossCallReturn answer = {0};
|
||||
+ ResultCode code = CrossCall(ipc, IpcTag::DUPLICATEHANDLEPROXY,
|
||||
+ ResultCode code = CrossCall(ipc, IPC_DUPLICATEHANDLEPROXY_TAG,
|
||||
+ source_handle, target_process_id,
|
||||
+ desired_access, options, &answer);
|
||||
+ if (SBOX_ALL_OK != code)
|
||||
|
@ -239,7 +234,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/handle_policy.cc b/securi
|
|||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/handle_policy.cc
|
||||
@@ -0,0 +1,93 @@
|
||||
@@ -0,0 +1,92 @@
|
||||
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
|
@ -287,7 +282,7 @@ new file mode 100644
|
|||
+ CASE_INSENSITIVE)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (!policy->AddRule(IpcTag::DUPLICATEHANDLEPROXY, &duplicate_rule)) {
|
||||
+ if (!policy->AddRule(IPC_DUPLICATEHANDLEPROXY_TAG, &duplicate_rule)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ return true;
|
||||
|
@ -307,8 +302,7 @@ new file mode 100644
|
|||
+ base::win::ScopedHandle remote_target_process;
|
||||
+ if (target_process_id != ::GetCurrentProcessId()) {
|
||||
+ // Sandboxed children are dynamic, so we check that manually.
|
||||
+ if (!BrokerServicesBase::GetInstance()->IsSafeDuplicationTarget(
|
||||
+ target_process_id)) {
|
||||
+ if (!BrokerServicesBase::GetInstance()->IsActiveTarget(target_process_id)) {
|
||||
+ return ERROR_ACCESS_DENIED;
|
||||
+ }
|
||||
+
|
||||
|
@ -499,28 +493,29 @@ new file mode 100644
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/ipc_tags.h b/security/sandbox/chromium/sandbox/win/src/ipc_tags.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/ipc_tags.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/ipc_tags.h
|
||||
@@ -23,16 +23,17 @@ enum class IpcTag {
|
||||
NTOPENPROCESS,
|
||||
NTOPENPROCESSTOKEN,
|
||||
NTOPENPROCESSTOKENEX,
|
||||
CREATEPROCESSW,
|
||||
CREATEEVENT,
|
||||
OPENEVENT,
|
||||
NTCREATEKEY,
|
||||
NTOPENKEY,
|
||||
+ DUPLICATEHANDLEPROXY,
|
||||
GDI_GDIDLLINITIALIZE,
|
||||
GDI_GETSTOCKOBJECT,
|
||||
USER_REGISTERCLASSW,
|
||||
CREATETHREAD,
|
||||
USER_ENUMDISPLAYMONITORS,
|
||||
USER_ENUMDISPLAYDEVICES,
|
||||
USER_GETMONITORINFO,
|
||||
GDI_CREATEOPMPROTECTEDOUTPUTS,
|
||||
@@ -23,16 +23,17 @@ enum {
|
||||
IPC_NTOPENPROCESS_TAG,
|
||||
IPC_NTOPENPROCESSTOKEN_TAG,
|
||||
IPC_NTOPENPROCESSTOKENEX_TAG,
|
||||
IPC_CREATEPROCESSW_TAG,
|
||||
IPC_CREATEEVENT_TAG,
|
||||
IPC_OPENEVENT_TAG,
|
||||
IPC_NTCREATEKEY_TAG,
|
||||
IPC_NTOPENKEY_TAG,
|
||||
+ IPC_DUPLICATEHANDLEPROXY_TAG,
|
||||
IPC_GDI_GDIDLLINITIALIZE_TAG,
|
||||
IPC_GDI_GETSTOCKOBJECT_TAG,
|
||||
IPC_USER_REGISTERCLASSW_TAG,
|
||||
IPC_CREATETHREAD_TAG,
|
||||
IPC_USER_ENUMDISPLAYMONITORS_TAG,
|
||||
IPC_USER_ENUMDISPLAYDEVICES_TAG,
|
||||
IPC_USER_GETMONITORINFO_TAG,
|
||||
IPC_GDI_CREATEOPMPROTECTEDOUTPUTS_TAG,
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.h b/security/sandbox/chromium/sandbox/win/src/sandbox.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox.h
|
||||
@@ -161,16 +161,30 @@ class TargetServices {
|
||||
@@ -136,16 +136,30 @@ class TargetServices {
|
||||
// processing any untrusted data or running third-party code. If this call
|
||||
// fails the current process could be terminated immediately.
|
||||
virtual void LowerToken() = 0;
|
||||
|
||||
|
@ -528,7 +523,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.h b/security/sand
|
|||
// information about the current state of the process, such as whether
|
||||
// LowerToken has been called or not.
|
||||
virtual ProcessState* GetState() = 0;
|
||||
|
||||
+
|
||||
+ // Requests the broker to duplicate the supplied handle into the target
|
||||
+ // process. The target process must be an active sandbox child process
|
||||
+ // and the source process must have a corresponding policy allowing
|
||||
|
@ -542,30 +537,28 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox.h b/security/sand
|
|||
+ HANDLE* target_handle,
|
||||
+ DWORD desired_access,
|
||||
+ DWORD options) = 0;
|
||||
+
|
||||
|
||||
protected:
|
||||
~TargetServices() {}
|
||||
};
|
||||
|
||||
class PolicyInfo {
|
||||
public:
|
||||
// Returns a JSON representation of the policy snapshot.
|
||||
// This pointer has the same lifetime as this PolicyInfo object.
|
||||
} // namespace sandbox
|
||||
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h
|
||||
@@ -25,28 +25,32 @@ class TargetPolicy {
|
||||
@@ -24,27 +24,31 @@ class TargetPolicy {
|
||||
// exactly like the CreateProcess API does. See the comment at the top of
|
||||
// process_thread_dispatcher.cc for more details.
|
||||
enum SubSystem {
|
||||
SUBSYS_FILES, // Creation and opening of files and pipes.
|
||||
SUBSYS_NAMED_PIPES, // Creation of named pipes.
|
||||
SUBSYS_PROCESS, // Creation of child processes.
|
||||
SUBSYS_REGISTRY, // Creation and opening of registry keys.
|
||||
SUBSYS_SYNC, // Creation of named sync objects.
|
||||
+ SUBSYS_HANDLES, // Duplication of handles to other processes.
|
||||
SUBSYS_WIN32K_LOCKDOWN, // Win32K Lockdown related policy.
|
||||
SUBSYS_SIGNED_BINARY // Signed binary policy.
|
||||
SUBSYS_FILES, // Creation and opening of files and pipes.
|
||||
SUBSYS_NAMED_PIPES, // Creation of named pipes.
|
||||
SUBSYS_PROCESS, // Creation of child processes.
|
||||
SUBSYS_REGISTRY, // Creation and opening of registry keys.
|
||||
SUBSYS_SYNC, // Creation of named sync objects.
|
||||
+ SUBSYS_HANDLES, // Duplication of handles to other processes.
|
||||
SUBSYS_WIN32K_LOCKDOWN // Win32K Lockdown related policy.
|
||||
};
|
||||
|
||||
// Allowable semantics when a rule is matched.
|
||||
|
@ -590,14 +583,14 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h b/securi
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc
|
||||
@@ -12,16 +12,17 @@
|
||||
@@ -10,16 +10,17 @@
|
||||
|
||||
#include "base/callback.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/win/win_util.h"
|
||||
#include "base/win/windows_version.h"
|
||||
#include "sandbox/win/src/acl.h"
|
||||
#include "sandbox/win/src/filesystem_policy.h"
|
||||
+#include "sandbox/win/src/handle_policy.h"
|
||||
#include "sandbox/win/src/interception.h"
|
||||
|
@ -608,7 +601,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/
|
|||
#include "sandbox/win/src/policy_low_level.h"
|
||||
#include "sandbox/win/src/process_mitigations.h"
|
||||
#include "sandbox/win/src/process_mitigations_win32k_policy.h"
|
||||
@@ -754,16 +755,24 @@ ResultCode PolicyBase::AddRuleInternal(S
|
||||
@@ -733,16 +734,24 @@ ResultCode PolicyBase::AddRuleInternal(S
|
||||
}
|
||||
case SUBSYS_REGISTRY: {
|
||||
if (!RegistryPolicy::GenerateRules(pattern, semantics, policy_maker_)) {
|
||||
|
@ -626,13 +619,13 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy_base.cc b/
|
|||
+ }
|
||||
+
|
||||
case SUBSYS_WIN32K_LOCKDOWN: {
|
||||
// Win32k intercept rules only supported on Windows 8 and above. This must
|
||||
// match the version checks in process_mitigations.cc for consistency.
|
||||
if (base::win::GetVersion() >= base::win::Version::WIN8) {
|
||||
DCHECK_EQ(MITIGATION_WIN32K_DISABLE,
|
||||
mitigations_ & MITIGATION_WIN32K_DISABLE)
|
||||
<< "Enable MITIGATION_WIN32K_DISABLE before adding win32k policy "
|
||||
"rules.";
|
||||
if (!ProcessMitigationsWin32KLockdownPolicy::GenerateRules(
|
||||
pattern, semantics, policy_maker_)) {
|
||||
NOTREACHED();
|
||||
return SBOX_ERROR_BAD_PARAMS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
diff --git a/security/sandbox/chromium/sandbox/win/src/target_services.cc b/security/sandbox/chromium/sandbox/win/src/target_services.cc
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/target_services.cc
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/target_services.cc
|
||||
|
@ -654,9 +647,9 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/target_services.cc b/secu
|
|||
#include "sandbox/win/src/sandbox_nt_util.h"
|
||||
#include "sandbox/win/src/sandbox_types.h"
|
||||
#include "sandbox/win/src/sharedmem_ipc_client.h"
|
||||
@@ -239,9 +240,19 @@ void ProcessState::SetRevertedToSelf() {
|
||||
if (process_state_ < ProcessStateInternal::REVERTED_TO_SELF)
|
||||
process_state_ = ProcessStateInternal::REVERTED_TO_SELF;
|
||||
@@ -259,9 +260,19 @@ void ProcessState::SetRevertedToSelf() {
|
||||
if (process_state_ < 3)
|
||||
process_state_ = 3;
|
||||
}
|
||||
|
||||
void ProcessState::SetCsrssConnected(bool csrss_connected) {
|
||||
|
@ -677,7 +670,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/target_services.cc b/secu
|
|||
diff --git a/security/sandbox/chromium/sandbox/win/src/target_services.h b/security/sandbox/chromium/sandbox/win/src/target_services.h
|
||||
--- a/security/sandbox/chromium/sandbox/win/src/target_services.h
|
||||
+++ b/security/sandbox/chromium/sandbox/win/src/target_services.h
|
||||
@@ -40,16 +40,21 @@ class ProcessState {
|
||||
@@ -41,16 +41,21 @@ class ProcessState {
|
||||
class TargetServicesBase : public TargetServices {
|
||||
public:
|
||||
TargetServicesBase();
|
||||
|
@ -720,24 +713,24 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/top_level_dispatcher.cc b
|
|||
#include "sandbox/win/src/process_thread_dispatcher.h"
|
||||
#include "sandbox/win/src/registry_dispatcher.h"
|
||||
#include "sandbox/win/src/sandbox_policy_base.h"
|
||||
@@ -55,16 +56,20 @@ TopLevelDispatcher::TopLevelDispatcher(P
|
||||
ipc_targets_[static_cast<size_t>(IpcTag::OPENEVENT)] = dispatcher;
|
||||
@@ -53,16 +54,20 @@ TopLevelDispatcher::TopLevelDispatcher(P
|
||||
ipc_targets_[IPC_OPENEVENT_TAG] = dispatcher;
|
||||
sync_dispatcher_.reset(dispatcher);
|
||||
|
||||
dispatcher = new RegistryDispatcher(policy_);
|
||||
ipc_targets_[static_cast<size_t>(IpcTag::NTCREATEKEY)] = dispatcher;
|
||||
ipc_targets_[static_cast<size_t>(IpcTag::NTOPENKEY)] = dispatcher;
|
||||
ipc_targets_[IPC_NTCREATEKEY_TAG] = dispatcher;
|
||||
ipc_targets_[IPC_NTOPENKEY_TAG] = dispatcher;
|
||||
registry_dispatcher_.reset(dispatcher);
|
||||
|
||||
+ dispatcher = new HandleDispatcher(policy_);
|
||||
+ ipc_targets_[static_cast<size_t>(IpcTag::DUPLICATEHANDLEPROXY)] = dispatcher;
|
||||
+ ipc_targets_[IPC_DUPLICATEHANDLEPROXY_TAG] = dispatcher;
|
||||
+ handle_dispatcher_.reset(dispatcher);
|
||||
+
|
||||
dispatcher = new ProcessMitigationsWin32KDispatcher(policy_);
|
||||
ipc_targets_[static_cast<size_t>(IpcTag::GDI_GDIDLLINITIALIZE)] = dispatcher;
|
||||
ipc_targets_[static_cast<size_t>(IpcTag::GDI_GETSTOCKOBJECT)] = dispatcher;
|
||||
ipc_targets_[static_cast<size_t>(IpcTag::USER_REGISTERCLASSW)] = dispatcher;
|
||||
ipc_targets_[static_cast<size_t>(IpcTag::USER_ENUMDISPLAYMONITORS)] =
|
||||
dispatcher;
|
||||
ipc_targets_[static_cast<size_t>(IpcTag::USER_ENUMDISPLAYDEVICES)] =
|
||||
dispatcher;
|
||||
ipc_targets_[IPC_GDI_GDIDLLINITIALIZE_TAG] = dispatcher;
|
||||
ipc_targets_[IPC_GDI_GETSTOCKOBJECT_TAG] = dispatcher;
|
||||
ipc_targets_[IPC_USER_REGISTERCLASSW_TAG] = dispatcher;
|
||||
ipc_targets_[IPC_USER_ENUMDISPLAYMONITORS_TAG] = dispatcher;
|
||||
ipc_targets_[IPC_USER_ENUMDISPLAYDEVICES_TAG] = dispatcher;
|
||||
ipc_targets_[IPC_USER_GETMONITORINFO_TAG] = dispatcher;
|
||||
ipc_targets_[IPC_GDI_CREATEOPMPROTECTEDOUTPUTS_TAG] = dispatcher;
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
# HG changeset patch
|
||||
# User Gian-Carlo Pascutto <gcp@mozilla.com>
|
||||
# Date 1465410964 -7200
|
||||
# Wed Jun 08 20:36:04 2016 +0200
|
||||
# Node ID 37ac7119fe8df776c850624a9a95dd182ff469b0
|
||||
# Parent 5d0dab9cddb8410f891f22a1bead1c1975adb5bd
|
||||
Update chromium's list of linux-x86-32 syscalls. r=jld
|
||||
|
||||
Originally landed as changset:
|
||||
https://hg.mozilla.org/mozilla-central/rev/adb1d2a92e0d
|
||||
|
||||
diff --git a/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h b/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
|
||||
--- a/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
|
||||
+++ b/security/sandbox/chromium/sandbox/linux/system_headers/x86_32_linux_syscalls.h
|
||||
@@ -1417,10 +1417,78 @@
|
||||
#if !defined(__NR_getrandom)
|
||||
#define __NR_getrandom 355
|
||||
#endif
|
||||
|
||||
#if !defined(__NR_memfd_create)
|
||||
#define __NR_memfd_create 356
|
||||
#endif
|
||||
|
||||
+#if !defined(__NR_bpf)
|
||||
+#define __NR_bpf 357
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_execveat)
|
||||
+#define __NR_execveat 358
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_socket)
|
||||
+#define __NR_socket 359
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_socketpair)
|
||||
+#define __NR_socketpair 360
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_bind)
|
||||
+#define __NR_bind 361
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_connect)
|
||||
+#define __NR_connect 362
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_listen)
|
||||
+#define __NR_listen 363
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_accept4)
|
||||
+#define __NR_accept4 364
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_getsockopt)
|
||||
+#define __NR_getsockopt 365
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_setsockopt)
|
||||
+#define __NR_setsockopt 366
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_getsockname)
|
||||
+#define __NR_getsockname 367
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_getpeername)
|
||||
+#define __NR_getpeername 368
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_sendto)
|
||||
+#define __NR_sendto 369
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_sendmsg)
|
||||
+#define __NR_sendmsg 370
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_recvfrom)
|
||||
+#define __NR_recvfrom 371
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_recvmsg)
|
||||
+#define __NR_recvmsg 372
|
||||
+#endif
|
||||
+
|
||||
+#if !defined(__NR_shutdown)
|
||||
+#define __NR_shutdown 373
|
||||
+#endif
|
||||
+
|
||||
#endif // SANDBOX_LINUX_SYSTEM_HEADERS_X86_32_LINUX_SYSCALLS_H_
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This is a partial implementation of Chromium's source file
|
||||
// //sandbox/win/src/sandbox_policy_diagnostic.h
|
||||
|
||||
#ifndef SANDBOX_WIN_SRC_SANDBOX_POLICY_DIAGNOSTIC_H_
|
||||
#define SANDBOX_WIN_SRC_SANDBOX_POLICY_DIAGNOSTIC_H_
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace sandbox {
|
||||
|
||||
class PolicyBase;
|
||||
|
||||
class PolicyDiagnostic final : public PolicyInfo {
|
||||
public:
|
||||
PolicyDiagnostic(PolicyBase*) {}
|
||||
~PolicyDiagnostic() override = default;
|
||||
const char* JsonString() override { MOZ_CRASH(); }
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(PolicyDiagnostic);
|
||||
};
|
||||
|
||||
} // namespace sandbox
|
||||
|
||||
#endif // SANDBOX_WIN_SRC_SANDBOX_POLICY_DIAGNOSTIC_H_
|
|
@ -48,11 +48,11 @@ AtExitManager::~AtExitManager() {
|
|||
// static
|
||||
void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
|
||||
DCHECK(func);
|
||||
RegisterTask(base::BindOnce(func, param));
|
||||
RegisterTask(base::Bind(func, param));
|
||||
}
|
||||
|
||||
// static
|
||||
void AtExitManager::RegisterTask(base::OnceClosure task) {
|
||||
void AtExitManager::RegisterTask(base::Closure task) {
|
||||
if (!g_top_manager) {
|
||||
NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
|
||||
return;
|
||||
|
@ -75,7 +75,7 @@ void AtExitManager::ProcessCallbacksNow() {
|
|||
// Callbacks may try to add new callbacks, so run them without holding
|
||||
// |lock_|. This is an error and caught by the DCHECK in RegisterTask(), but
|
||||
// handle it gracefully in release builds so we don't deadlock.
|
||||
base::stack<base::OnceClosure> tasks;
|
||||
base::stack<base::Closure> tasks;
|
||||
{
|
||||
AutoLock lock(g_top_manager->lock_);
|
||||
tasks.swap(g_top_manager->stack_);
|
||||
|
@ -89,7 +89,8 @@ void AtExitManager::ProcessCallbacksNow() {
|
|||
ScopedAllowCrossThreadRefCountAccess allow_cross_thread_ref_count_access;
|
||||
|
||||
while (!tasks.empty()) {
|
||||
std::move(tasks.top()).Run();
|
||||
base::Closure task = tasks.top();
|
||||
task.Run();
|
||||
tasks.pop();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ class BASE_EXPORT AtExitManager {
|
|||
static void RegisterCallback(AtExitCallbackType func, void* param);
|
||||
|
||||
// Registers the specified task to be called at exit.
|
||||
static void RegisterTask(base::OnceClosure task);
|
||||
static void RegisterTask(base::Closure task);
|
||||
|
||||
// Calls the functions registered with RegisterCallback in LIFO order. It
|
||||
// is possible to register new callbacks after calling this function.
|
||||
|
@ -63,7 +63,7 @@ class BASE_EXPORT AtExitManager {
|
|||
private:
|
||||
base::Lock lock_;
|
||||
|
||||
base::stack<base::OnceClosure> stack_ GUARDED_BY(lock_);
|
||||
base::stack<base::Closure> stack_ GUARDED_BY(lock_);
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
bool processing_callbacks_ GUARDED_BY(lock_) = false;
|
||||
|
|
|
@ -39,6 +39,15 @@
|
|||
#include "base/base_export.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN) && (defined(ARCH_CPU_64_BITS) || defined(__MINGW32__))
|
||||
// windows.h #defines this (only on x64). This causes problems because the
|
||||
// public API also uses MemoryBarrier at the public name for this fence. So, on
|
||||
// X64, undef it, and call its documented
|
||||
// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
|
||||
// implementation directly.
|
||||
#undef MemoryBarrier
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
|
@ -91,7 +100,8 @@ Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
|
|||
// ensure that no later memory access can be reordered ahead of the operation.
|
||||
// "Release" operations ensure that no previous memory access can be reordered
|
||||
// after the operation. "Barrier" operations have both "Acquire" and "Release"
|
||||
// semantics.
|
||||
// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
|
||||
// access.
|
||||
Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value);
|
||||
|
@ -99,6 +109,7 @@ Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
|
|||
Atomic32 old_value,
|
||||
Atomic32 new_value);
|
||||
|
||||
void MemoryBarrier();
|
||||
void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
|
||||
void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
|
||||
void Release_Store(volatile Atomic32* ptr, Atomic32 value);
|
||||
|
|
|
@ -52,6 +52,16 @@ typedef volatile std::atomic<Atomic32>* AtomicLocation32;
|
|||
static_assert(sizeof(*(AtomicLocation32) nullptr) == sizeof(Atomic32),
|
||||
"incompatible 32-bit atomic layout");
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
#if defined(__GLIBCXX__)
|
||||
// Work around libstdc++ bug 51038 where atomic_thread_fence was declared but
|
||||
// not defined, leading to the linker complaining about undefined references.
|
||||
__atomic_thread_fence(std::memory_order_seq_cst);
|
||||
#else
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
|
@ -109,7 +119,7 @@ inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
|
|||
|
||||
inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
((AtomicLocation32)ptr)->store(value, std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
|
||||
|
@ -125,7 +135,7 @@ inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
|||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
MemoryBarrier();
|
||||
return ((AtomicLocation32)ptr)->load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
|
@ -192,7 +202,7 @@ inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
|
|||
|
||||
inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
((AtomicLocation64)ptr)->store(value, std::memory_order_relaxed);
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
MemoryBarrier();
|
||||
}
|
||||
|
||||
inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
|
||||
|
@ -208,7 +218,7 @@ inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
|||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
MemoryBarrier();
|
||||
return ((AtomicLocation64)ptr)->load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,11 +11,18 @@
|
|||
|
||||
#include <intrin.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(ARCH_CPU_64_BITS) || defined(__MINGW32__)
|
||||
// windows.h #defines this (only on x64). This causes problems because the
|
||||
// public API also uses MemoryBarrier at the public name for this fence. So, on
|
||||
// X64, undef it, and call its documented
|
||||
// (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684208.aspx)
|
||||
// implementation directly.
|
||||
#undef MemoryBarrier
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
|
@ -49,6 +56,18 @@ inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
|
|||
return Barrier_AtomicIncrement(ptr, increment);
|
||||
}
|
||||
|
||||
inline void MemoryBarrier() {
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
// See #undef and note at the top of this file.
|
||||
__faststorefence();
|
||||
#else
|
||||
// We use the implementation of MemoryBarrier from WinNT.h
|
||||
LONG barrier;
|
||||
|
||||
_InterlockedOr(&barrier, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
|
||||
Atomic32 old_value,
|
||||
Atomic32 new_value) {
|
||||
|
@ -85,7 +104,7 @@ inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
|
|||
}
|
||||
|
||||
inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
|
@ -154,7 +173,7 @@ inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
|
|||
}
|
||||
|
||||
inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
MemoryBarrier();
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace switches {
|
||||
|
||||
// Delays execution of TaskPriority::BEST_EFFORT tasks until shutdown.
|
||||
// Delays execution of base::TaskPriority::BEST_EFFORT tasks until shutdown.
|
||||
const char kDisableBestEffortTasks[] = "disable-best-effort-tasks";
|
||||
|
||||
// Disables the crash reporting.
|
||||
|
@ -16,9 +16,6 @@ const char kDisableBreakpad[] = "disable-breakpad";
|
|||
// Comma-separated list of feature names to disable. See also kEnableFeatures.
|
||||
const char kDisableFeatures[] = "disable-features";
|
||||
|
||||
// Force disabling of low-end device mode when set.
|
||||
const char kDisableLowEndDeviceMode[] = "disable-low-end-device-mode";
|
||||
|
||||
// Indicates that crash reporting should be enabled. On platforms where helper
|
||||
// processes cannot access to files needed to make this decision, this flag is
|
||||
// generated internally.
|
||||
|
@ -27,9 +24,15 @@ const char kEnableCrashReporter[] = "enable-crash-reporter";
|
|||
// Comma-separated list of feature names to enable. See also kDisableFeatures.
|
||||
const char kEnableFeatures[] = "enable-features";
|
||||
|
||||
// Generates full memory crash dump.
|
||||
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
|
||||
|
||||
// Force low-end device mode when set.
|
||||
const char kEnableLowEndDeviceMode[] = "enable-low-end-device-mode";
|
||||
|
||||
// Force disabling of low-end device mode when set.
|
||||
const char kDisableLowEndDeviceMode[] = "disable-low-end-device-mode";
|
||||
|
||||
// This option can be used to force field trials when testing changes locally.
|
||||
// The argument is a list of name and value pairs, separated by slashes. If a
|
||||
// trial name is prefixed with an asterisk, that trial will start activated.
|
||||
|
@ -40,19 +43,44 @@ const char kEnableLowEndDeviceMode[] = "enable-low-end-device-mode";
|
|||
// FieldTrialList::CreateTrialsFromString() in field_trial.h for details.
|
||||
const char kForceFieldTrials[] = "force-fieldtrials";
|
||||
|
||||
// Generates full memory crash dump.
|
||||
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
|
||||
|
||||
// Logs information about all tasks posted with TaskPriority::BEST_EFFORT. Use
|
||||
// this to diagnose issues that are thought to be caused by
|
||||
// TaskPriority::BEST_EFFORT execution fences. Note: Tasks posted to a
|
||||
// non-BEST_EFFORT UpdateableSequencedTaskRunner whose priority is later lowered
|
||||
// to BEST_EFFORT are not logged.
|
||||
const char kLogBestEffortTasks[] = "log-best-effort-tasks";
|
||||
|
||||
// Suppresses all error dialogs when present.
|
||||
const char kNoErrorDialogs[] = "noerrdialogs";
|
||||
|
||||
// When running certain tests that spawn child processes, this switch indicates
|
||||
// to the test framework that the current process is a child process.
|
||||
const char kTestChildProcess[] = "test-child-process";
|
||||
|
||||
// When running certain tests that spawn child processes, this switch indicates
|
||||
// to the test framework that the current process should not initialize ICU to
|
||||
// avoid creating any scoped handles too early in startup.
|
||||
const char kTestDoNotInitializeIcu[] = "test-do-not-initialize-icu";
|
||||
|
||||
// Gives the default maximal active V-logging level; 0 is the default.
|
||||
// Normally positive values are used for V-logging levels.
|
||||
const char kV[] = "v";
|
||||
|
||||
// Gives the per-module maximal V-logging levels to override the value
|
||||
// given by --v. E.g. "my_module=2,foo*=3" would change the logging
|
||||
// level for all code in source files "my_module.*" and "foo*.*"
|
||||
// ("-inl" suffixes are also disregarded for this matching).
|
||||
//
|
||||
// Any pattern containing a forward or backward slash will be tested
|
||||
// against the whole pathname and not just the module. E.g.,
|
||||
// "*/foo/bar/*=2" would change the logging level for all code in
|
||||
// source files under a "foo/bar" directory.
|
||||
const char kVModule[] = "vmodule";
|
||||
|
||||
// Will wait for 60 seconds for a debugger to come to attach to the process.
|
||||
const char kWaitForDebugger[] = "wait-for-debugger";
|
||||
|
||||
// Sends trace events from these categories to a file.
|
||||
// --trace-to-file on its own sends to default categories.
|
||||
const char kTraceToFile[] = "trace-to-file";
|
||||
|
||||
// Specifies the file name for --trace-to-file. If unspecified, it will
|
||||
// go to a default file name.
|
||||
const char kTraceToFileName[] = "trace-to-file-name";
|
||||
|
||||
// Starts the sampling based profiler for the browser process at startup. This
|
||||
// will only work if chrome has been built with the gn arg enable_profiling =
|
||||
// true. The output will go to the value of kProfilingFile.
|
||||
|
@ -74,45 +102,7 @@ const char kProfilingFile[] = "profiling-file";
|
|||
// specified.
|
||||
const char kProfilingFlush[] = "profiling-flush";
|
||||
|
||||
// When running certain tests that spawn child processes, this switch indicates
|
||||
// to the test framework that the current process is a child process.
|
||||
const char kTestChildProcess[] = "test-child-process";
|
||||
|
||||
// When running certain tests that spawn child processes, this switch indicates
|
||||
// to the test framework that the current process should not initialize ICU to
|
||||
// avoid creating any scoped handles too early in startup.
|
||||
const char kTestDoNotInitializeIcu[] = "test-do-not-initialize-icu";
|
||||
|
||||
// Sends trace events from these categories to a file.
|
||||
// --trace-to-file on its own sends to default categories.
|
||||
const char kTraceToFile[] = "trace-to-file";
|
||||
|
||||
// Specifies the file name for --trace-to-file. If unspecified, it will
|
||||
// go to a default file name.
|
||||
const char kTraceToFileName[] = "trace-to-file-name";
|
||||
|
||||
// Gives the default maximal active V-logging level; 0 is the default.
|
||||
// Normally positive values are used for V-logging levels.
|
||||
const char kV[] = "v";
|
||||
|
||||
// Gives the per-module maximal V-logging levels to override the value
|
||||
// given by --v. E.g. "my_module=2,foo*=3" would change the logging
|
||||
// level for all code in source files "my_module.*" and "foo*.*"
|
||||
// ("-inl" suffixes are also disregarded for this matching).
|
||||
//
|
||||
// Any pattern containing a forward or backward slash will be tested
|
||||
// against the whole pathname and not just the module. E.g.,
|
||||
// "*/foo/bar/*=2" would change the logging level for all code in
|
||||
// source files under a "foo/bar" directory.
|
||||
const char kVModule[] = "vmodule";
|
||||
|
||||
// Will wait for 60 seconds for a debugger to come to attach to the process.
|
||||
const char kWaitForDebugger[] = "wait-for-debugger";
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Disable high-resolution timer on Windows.
|
||||
const char kDisableHighResTimer[] = "disable-highres-timer";
|
||||
|
||||
// Disables the USB keyboard detection for blocking the OSK on Win8+.
|
||||
const char kDisableUsbKeyboardDetect[] = "disable-usb-keyboard-detect";
|
||||
#endif
|
||||
|
@ -136,14 +126,17 @@ const char kEnableCrashReporterForTesting[] =
|
|||
// Enables the reached code profiler that samples all threads in all processes
|
||||
// to determine which functions are almost never executed.
|
||||
const char kEnableReachedCodeProfiler[] = "enable-reached-code-profiler";
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
// Controls whether or not retired instruction counts are surfaced for threads
|
||||
// in trace events on Linux.
|
||||
// Specifies optimization of memory layout of the native library using the
|
||||
// orderfile symbols given in base/android/library_loader/anchor_functions.h,
|
||||
// via madvise and changing the library prefetch behavior.
|
||||
//
|
||||
// This flag requires the BPF sandbox to be disabled.
|
||||
const char kEnableThreadInstructionCount[] = "enable-thread-instruction-count";
|
||||
// If this switch is not specified, an optimization may be done depending on a
|
||||
// synthetic trial. If specified, its values may be 'on' or 'off'. These
|
||||
// override the synthetic trial.
|
||||
//
|
||||
// This flag is only used on architectures with SUPPORTS_CODE_ORDERING defined.
|
||||
const char kOrderfileMemoryOptimization[] = "orderfile-memory-optimization";
|
||||
#endif
|
||||
|
||||
} // namespace switches
|
||||
|
|
|
@ -20,7 +20,6 @@ extern const char kEnableFeatures[];
|
|||
extern const char kEnableLowEndDeviceMode[];
|
||||
extern const char kForceFieldTrials[];
|
||||
extern const char kFullMemoryCrashReport[];
|
||||
extern const char kLogBestEffortTasks[];
|
||||
extern const char kNoErrorDialogs[];
|
||||
extern const char kProfilingAtStart[];
|
||||
extern const char kProfilingFile[];
|
||||
|
@ -34,7 +33,6 @@ extern const char kVModule[];
|
|||
extern const char kWaitForDebugger[];
|
||||
|
||||
#if defined(OS_WIN)
|
||||
extern const char kDisableHighResTimer[];
|
||||
extern const char kDisableUsbKeyboardDetect[];
|
||||
#endif
|
||||
|
||||
|
@ -51,10 +49,6 @@ extern const char kEnableReachedCodeProfiler[];
|
|||
extern const char kOrderfileMemoryOptimization[];
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
extern const char kEnableThreadInstructionCount[];
|
||||
#endif
|
||||
|
||||
} // namespace switches
|
||||
|
||||
#endif // BASE_BASE_SWITCHES_H_
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "base/bind_internal.h"
|
||||
|
@ -42,7 +41,7 @@
|
|||
// class C : public base::RefCounted<C> { void F(); };
|
||||
// auto instance = base::MakeRefCounted<C>();
|
||||
// auto cb = base::BindOnce(&C::F, instance);
|
||||
// std::move(cb).Run(); // Identical to instance->F()
|
||||
// cb.Run(); // Identical to instance->F()
|
||||
//
|
||||
// base::Bind is currently a type alias for base::BindRepeating(). In the
|
||||
// future, we expect to flip this to default to base::BindOnce().
|
||||
|
@ -180,36 +179,26 @@ template <bool is_once, bool is_method, typename... Args>
|
|||
using MakeUnwrappedTypeList =
|
||||
typename MakeUnwrappedTypeListImpl<is_once, is_method, Args...>::Type;
|
||||
|
||||
// Used below in BindImpl to determine whether to use Invoker::Run or
|
||||
// Invoker::RunOnce.
|
||||
// Note: Simply using `kIsOnce ? &Invoker::RunOnce : &Invoker::Run` does not
|
||||
// work, since the compiler needs to check whether both expressions are
|
||||
// well-formed. Using `Invoker::Run` with a OnceCallback triggers a
|
||||
// static_assert, which is why the ternary expression does not compile.
|
||||
// TODO(crbug.com/752720): Remove this indirection once we have `if constexpr`.
|
||||
template <typename Invoker>
|
||||
constexpr auto GetInvokeFunc(std::true_type) {
|
||||
return Invoker::RunOnce;
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
template <typename Invoker>
|
||||
constexpr auto GetInvokeFunc(std::false_type) {
|
||||
return Invoker::Run;
|
||||
}
|
||||
// Bind as OnceCallback.
|
||||
template <typename Functor, typename... Args>
|
||||
inline OnceCallback<MakeUnboundRunType<Functor, Args...>>
|
||||
BindOnce(Functor&& functor, Args&&... args) {
|
||||
static_assert(!internal::IsOnceCallback<std::decay_t<Functor>>() ||
|
||||
(std::is_rvalue_reference<Functor&&>() &&
|
||||
!std::is_const<std::remove_reference_t<Functor>>()),
|
||||
"BindOnce requires non-const rvalue for OnceCallback binding."
|
||||
" I.e.: base::BindOnce(std::move(callback)).");
|
||||
|
||||
template <template <typename> class CallbackT,
|
||||
typename Functor,
|
||||
typename... Args>
|
||||
decltype(auto) BindImpl(Functor&& functor, Args&&... args) {
|
||||
// This block checks if each |args| matches to the corresponding params of the
|
||||
// target function. This check does not affect the behavior of Bind, but its
|
||||
// error message should be more readable.
|
||||
static constexpr bool kIsOnce = IsOnceCallback<CallbackT<void()>>::value;
|
||||
using Helper = internal::BindTypeHelper<Functor, Args...>;
|
||||
using FunctorTraits = typename Helper::FunctorTraits;
|
||||
using BoundArgsList = typename Helper::BoundArgsList;
|
||||
using UnwrappedArgsList =
|
||||
internal::MakeUnwrappedTypeList<kIsOnce, FunctorTraits::is_method,
|
||||
internal::MakeUnwrappedTypeList<true, FunctorTraits::is_method,
|
||||
Args&&...>;
|
||||
using BoundParamsList = typename Helper::BoundParamsList;
|
||||
static_assert(internal::AssertBindArgsValidity<
|
||||
|
@ -220,14 +209,13 @@ decltype(auto) BindImpl(Functor&& functor, Args&&... args) {
|
|||
using BindState = internal::MakeBindStateType<Functor, Args...>;
|
||||
using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
|
||||
using Invoker = internal::Invoker<BindState, UnboundRunType>;
|
||||
using CallbackType = CallbackT<UnboundRunType>;
|
||||
using CallbackType = OnceCallback<UnboundRunType>;
|
||||
|
||||
// Store the invoke func into PolymorphicInvoke before casting it to
|
||||
// InvokeFuncStorage, so that we can ensure its type matches to
|
||||
// PolymorphicInvoke, to which CallbackType will cast back.
|
||||
using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
|
||||
PolymorphicInvoke invoke_func =
|
||||
GetInvokeFunc<Invoker>(std::integral_constant<bool, kIsOnce>());
|
||||
PolymorphicInvoke invoke_func = &Invoker::RunOnce;
|
||||
|
||||
using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage;
|
||||
return CallbackType(BindState::Create(
|
||||
|
@ -235,23 +223,6 @@ decltype(auto) BindImpl(Functor&& functor, Args&&... args) {
|
|||
std::forward<Functor>(functor), std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Bind as OnceCallback.
|
||||
template <typename Functor, typename... Args>
|
||||
inline OnceCallback<MakeUnboundRunType<Functor, Args...>> BindOnce(
|
||||
Functor&& functor,
|
||||
Args&&... args) {
|
||||
static_assert(!internal::IsOnceCallback<std::decay_t<Functor>>() ||
|
||||
(std::is_rvalue_reference<Functor&&>() &&
|
||||
!std::is_const<std::remove_reference_t<Functor>>()),
|
||||
"BindOnce requires non-const rvalue for OnceCallback binding."
|
||||
" I.e.: base::BindOnce(std::move(callback)).");
|
||||
|
||||
return internal::BindImpl<OnceCallback>(std::forward<Functor>(functor),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// Bind as RepeatingCallback.
|
||||
template <typename Functor, typename... Args>
|
||||
inline RepeatingCallback<MakeUnboundRunType<Functor, Args...>>
|
||||
|
@ -260,8 +231,36 @@ BindRepeating(Functor&& functor, Args&&... args) {
|
|||
!internal::IsOnceCallback<std::decay_t<Functor>>(),
|
||||
"BindRepeating cannot bind OnceCallback. Use BindOnce with std::move().");
|
||||
|
||||
return internal::BindImpl<RepeatingCallback>(std::forward<Functor>(functor),
|
||||
std::forward<Args>(args)...);
|
||||
// This block checks if each |args| matches to the corresponding params of the
|
||||
// target function. This check does not affect the behavior of Bind, but its
|
||||
// error message should be more readable.
|
||||
using Helper = internal::BindTypeHelper<Functor, Args...>;
|
||||
using FunctorTraits = typename Helper::FunctorTraits;
|
||||
using BoundArgsList = typename Helper::BoundArgsList;
|
||||
using UnwrappedArgsList =
|
||||
internal::MakeUnwrappedTypeList<false, FunctorTraits::is_method,
|
||||
Args&&...>;
|
||||
using BoundParamsList = typename Helper::BoundParamsList;
|
||||
static_assert(internal::AssertBindArgsValidity<
|
||||
std::make_index_sequence<Helper::num_bounds>, BoundArgsList,
|
||||
UnwrappedArgsList, BoundParamsList>::ok,
|
||||
"The bound args need to be convertible to the target params.");
|
||||
|
||||
using BindState = internal::MakeBindStateType<Functor, Args...>;
|
||||
using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
|
||||
using Invoker = internal::Invoker<BindState, UnboundRunType>;
|
||||
using CallbackType = RepeatingCallback<UnboundRunType>;
|
||||
|
||||
// Store the invoke func into PolymorphicInvoke before casting it to
|
||||
// InvokeFuncStorage, so that we can ensure its type matches to
|
||||
// PolymorphicInvoke, to which CallbackType will cast back.
|
||||
using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
|
||||
PolymorphicInvoke invoke_func = &Invoker::Run;
|
||||
|
||||
using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage;
|
||||
return CallbackType(BindState::Create(
|
||||
reinterpret_cast<InvokeFuncStorage>(invoke_func),
|
||||
std::forward<Functor>(functor), std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
// Unannotated Bind.
|
||||
|
@ -276,27 +275,22 @@ Bind(Functor&& functor, Args&&... args) {
|
|||
|
||||
// Special cases for binding to a base::Callback without extra bound arguments.
|
||||
template <typename Signature>
|
||||
OnceCallback<Signature> BindOnce(OnceCallback<Signature> callback) {
|
||||
return callback;
|
||||
}
|
||||
|
||||
template <typename Signature>
|
||||
OnceCallback<Signature> BindOnce(RepeatingCallback<Signature> callback) {
|
||||
return callback;
|
||||
OnceCallback<Signature> BindOnce(OnceCallback<Signature> closure) {
|
||||
return closure;
|
||||
}
|
||||
|
||||
template <typename Signature>
|
||||
RepeatingCallback<Signature> BindRepeating(
|
||||
RepeatingCallback<Signature> callback) {
|
||||
return callback;
|
||||
RepeatingCallback<Signature> closure) {
|
||||
return closure;
|
||||
}
|
||||
|
||||
template <typename Signature>
|
||||
Callback<Signature> Bind(Callback<Signature> callback) {
|
||||
return callback;
|
||||
Callback<Signature> Bind(Callback<Signature> closure) {
|
||||
return closure;
|
||||
}
|
||||
|
||||
// Unretained() allows binding a non-refcounted class, and to disable
|
||||
// Unretained() allows Bind() to bind a non-refcounted class, and to disable
|
||||
// refcounting on arguments that are refcounted objects.
|
||||
//
|
||||
// EXAMPLE OF Unretained():
|
||||
|
@ -308,9 +302,9 @@ Callback<Signature> Bind(Callback<Signature> callback) {
|
|||
//
|
||||
// // In some function somewhere.
|
||||
// Foo foo;
|
||||
// OnceClosure foo_callback =
|
||||
// BindOnce(&Foo::func, Unretained(&foo));
|
||||
// std::move(foo_callback).Run(); // Prints "Foo:f".
|
||||
// Closure foo_callback =
|
||||
// Bind(&Foo::func, Unretained(&foo));
|
||||
// foo_callback.Run(); // Prints "Foo:f".
|
||||
//
|
||||
// Without the Unretained() wrapper on |&foo|, the above call would fail
|
||||
// to compile because Foo does not support the AddRef() and Release() methods.
|
||||
|
@ -327,13 +321,13 @@ static inline internal::UnretainedWrapper<T> Unretained(T* o) {
|
|||
// void foo(RefCountedBytes* bytes) {}
|
||||
//
|
||||
// scoped_refptr<RefCountedBytes> bytes = ...;
|
||||
// OnceClosure callback = BindOnce(&foo, base::RetainedRef(bytes));
|
||||
// std::move(callback).Run();
|
||||
// Closure callback = Bind(&foo, base::RetainedRef(bytes));
|
||||
// callback.Run();
|
||||
//
|
||||
// Without RetainedRef, the scoped_refptr would try to implicitly convert to
|
||||
// a raw pointer and fail compilation:
|
||||
//
|
||||
// OnceClosure callback = BindOnce(&foo, bytes); // ERROR!
|
||||
// Closure callback = Bind(&foo, bytes); // ERROR!
|
||||
template <typename T>
|
||||
static inline internal::RetainedRefWrapper<T> RetainedRef(T* o) {
|
||||
return internal::RetainedRefWrapper<T>(o);
|
||||
|
@ -343,41 +337,40 @@ static inline internal::RetainedRefWrapper<T> RetainedRef(scoped_refptr<T> o) {
|
|||
return internal::RetainedRefWrapper<T>(std::move(o));
|
||||
}
|
||||
|
||||
// Owned() transfers ownership of an object to the callback resulting from
|
||||
// bind; the object will be deleted when the callback is deleted.
|
||||
// Owned() transfers ownership of an object to the Callback resulting from
|
||||
// bind; the object will be deleted when the Callback is deleted.
|
||||
//
|
||||
// EXAMPLE OF Owned():
|
||||
//
|
||||
// void foo(int* arg) { cout << *arg << endl }
|
||||
//
|
||||
// int* pn = new int(1);
|
||||
// RepeatingClosure foo_callback = BindRepeating(&foo, Owned(pn));
|
||||
// Closure foo_callback = Bind(&foo, Owned(pn));
|
||||
//
|
||||
// foo_callback.Run(); // Prints "1"
|
||||
// foo_callback.Run(); // Prints "1"
|
||||
// *pn = 2;
|
||||
// *n = 2;
|
||||
// foo_callback.Run(); // Prints "2"
|
||||
//
|
||||
// foo_callback.Reset(); // |pn| is deleted. Also will happen when
|
||||
// // |foo_callback| goes out of scope.
|
||||
//
|
||||
// Without Owned(), someone would have to know to delete |pn| when the last
|
||||
// reference to the callback is deleted.
|
||||
// reference to the Callback is deleted.
|
||||
template <typename T>
|
||||
static inline internal::OwnedWrapper<T> Owned(T* o) {
|
||||
return internal::OwnedWrapper<T>(o);
|
||||
}
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
static inline internal::OwnedWrapper<T, Deleter> Owned(
|
||||
std::unique_ptr<T, Deleter>&& ptr) {
|
||||
return internal::OwnedWrapper<T, Deleter>(std::move(ptr));
|
||||
template <typename T>
|
||||
static inline internal::OwnedWrapper<T> Owned(std::unique_ptr<T>&& ptr) {
|
||||
return internal::OwnedWrapper<T>(std::move(ptr));
|
||||
}
|
||||
|
||||
// Passed() is for transferring movable-but-not-copyable types (eg. unique_ptr)
|
||||
// through a RepeatingCallback. Logically, this signifies a destructive transfer
|
||||
// of the state of the argument into the target function. Invoking
|
||||
// RepeatingCallback::Run() twice on a callback that was created with a Passed()
|
||||
// through a Callback. Logically, this signifies a destructive transfer of
|
||||
// the state of the argument into the target function. Invoking
|
||||
// Callback::Run() twice on a Callback that was created with a Passed()
|
||||
// argument will CHECK() because the first invocation would have already
|
||||
// transferred ownership to the target function.
|
||||
//
|
||||
|
@ -394,22 +387,22 @@ static inline internal::OwnedWrapper<T, Deleter> Owned(
|
|||
//
|
||||
// // |cb| is given ownership of Foo(). |f| is now NULL.
|
||||
// // You can use std::move(f) in place of &f, but it's more verbose.
|
||||
// RepeatingClosure cb = BindRepeating(&TakesOwnership, Passed(&f));
|
||||
// Closure cb = Bind(&TakesOwnership, Passed(&f));
|
||||
//
|
||||
// // Run was never called so |cb| still owns Foo() and deletes
|
||||
// // it on Reset().
|
||||
// cb.Reset();
|
||||
//
|
||||
// // |cb| is given a new Foo created by CreateFoo().
|
||||
// cb = BindRepeating(&TakesOwnership, Passed(CreateFoo()));
|
||||
// cb = Bind(&TakesOwnership, Passed(CreateFoo()));
|
||||
//
|
||||
// // |arg| in TakesOwnership() is given ownership of Foo(). |cb|
|
||||
// // no longer owns Foo() and, if reset, would not delete Foo().
|
||||
// cb.Run(); // Foo() is now transferred to |arg| and deleted.
|
||||
// cb.Run(); // This CHECK()s since Foo() already been used once.
|
||||
//
|
||||
// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and is
|
||||
// best suited for use with the return value of a function or other temporary
|
||||
// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and
|
||||
// is best suited for use with the return value of a function or other temporary
|
||||
// rvalues. The second takes a pointer to the scoper and is just syntactic sugar
|
||||
// to avoid having to write Passed(std::move(scoper)).
|
||||
//
|
||||
|
@ -425,21 +418,21 @@ static inline internal::PassedWrapper<T> Passed(T* scoper) {
|
|||
return internal::PassedWrapper<T>(std::move(*scoper));
|
||||
}
|
||||
|
||||
// IgnoreResult() is used to adapt a function or callback with a return type to
|
||||
// IgnoreResult() is used to adapt a function or Callback with a return type to
|
||||
// one with a void return. This is most useful if you have a function with,
|
||||
// say, a pesky ignorable bool return that you want to use with PostTask or
|
||||
// something else that expect a callback with a void return.
|
||||
// something else that expect a Callback with a void return.
|
||||
//
|
||||
// EXAMPLE OF IgnoreResult():
|
||||
//
|
||||
// int DoSomething(int arg) { cout << arg << endl; }
|
||||
//
|
||||
// // Assign to a callback with a void return type.
|
||||
// OnceCallback<void(int)> cb = BindOnce(IgnoreResult(&DoSomething));
|
||||
// std::move(cb).Run(1); // Prints "1".
|
||||
// // Assign to a Callback with a void return type.
|
||||
// Callback<void(int)> cb = Bind(IgnoreResult(&DoSomething));
|
||||
// cb->Run(1); // Prints "1".
|
||||
//
|
||||
// // Prints "2" on |ml|.
|
||||
// ml->PostTask(FROM_HERE, BindOnce(IgnoreResult(&DoSomething), 2);
|
||||
// // Prints "1" on |ml|.
|
||||
// ml->PostTask(FROM_HERE, BindOnce(IgnoreResult(&DoSomething), 1);
|
||||
template <typename T>
|
||||
static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
|
||||
return internal::IgnoreResultHelper<T>(std::move(data));
|
||||
|
@ -454,9 +447,8 @@ static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
|
|||
// EXAMPLE OF RetainBlock():
|
||||
//
|
||||
// // Wrap the block and bind it to a callback.
|
||||
// OnceCallback<void(int)> cb =
|
||||
// BindOnce(RetainBlock(^(int n) { NSLog(@"%d", n); }));
|
||||
// std::move(cb).Run(1); // Logs "1".
|
||||
// Callback<void(int)> cb = Bind(RetainBlock(^(int n) { NSLog(@"%d", n); }));
|
||||
// cb.Run(1); // Logs "1".
|
||||
template <typename R, typename... Args>
|
||||
base::mac::ScopedBlock<R (^)(Args...)> RetainBlock(R (^block)(Args...)) {
|
||||
return base::mac::ScopedBlock<R (^)(Args...)>(block,
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "build/build_config.h"
|
||||
|
||||
// This defines a set of simple functions and utilities that people want when
|
||||
// using {Once,Repeating}Callback<> and Bind{Once,Repeating}().
|
||||
// using Callback<> and Bind().
|
||||
|
||||
namespace base {
|
||||
|
||||
|
|
|
@ -104,16 +104,15 @@ struct IgnoreResultHelper {
|
|||
T functor_;
|
||||
};
|
||||
|
||||
template <typename T, typename Deleter = std::default_delete<T>>
|
||||
template <typename T>
|
||||
class OwnedWrapper {
|
||||
public:
|
||||
explicit OwnedWrapper(T* o) : ptr_(o) {}
|
||||
explicit OwnedWrapper(std::unique_ptr<T, Deleter>&& ptr)
|
||||
: ptr_(std::move(ptr)) {}
|
||||
explicit OwnedWrapper(std::unique_ptr<T>&& ptr) : ptr_(std::move(ptr)) {}
|
||||
T* get() const { return ptr_.get(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<T, Deleter> ptr_;
|
||||
std::unique_ptr<T> ptr_;
|
||||
};
|
||||
|
||||
// PassedWrapper is a copyable adapter for a scoper that ignores const.
|
||||
|
@ -355,9 +354,10 @@ template <typename Functor, typename SFINAE>
|
|||
struct FunctorTraits;
|
||||
|
||||
// For empty callable types.
|
||||
// This specialization is intended to allow binding captureless lambdas, based
|
||||
// on the fact that captureless lambdas are empty while capturing lambdas are
|
||||
// not. This also allows any functors as far as it's an empty class.
|
||||
// This specialization is intended to allow binding captureless lambdas by
|
||||
// base::Bind(), based on the fact that captureless lambdas are empty while
|
||||
// capturing lambdas are not. This also allows any functors as far as it's an
|
||||
// empty class.
|
||||
// Example:
|
||||
//
|
||||
// // Captureless lambdas are allowed.
|
||||
|
@ -791,10 +791,10 @@ BanUnconstructedRefCountedReceiver(const Receiver& receiver, Unused&&...) {
|
|||
//
|
||||
// scoped_refptr<Foo> oo = Foo::Create();
|
||||
DCHECK(receiver->HasAtLeastOneRef())
|
||||
<< "base::Bind{Once,Repeating}() refuses to create the first reference "
|
||||
"to ref-counted objects. That typically happens around PostTask() in "
|
||||
"their constructor, and such objects can be destroyed before `new` "
|
||||
"returns if the task resolves fast enough.";
|
||||
<< "base::Bind() refuses to create the first reference to ref-counted "
|
||||
"objects. That is typically happens around PostTask() in their "
|
||||
"constructor, and such objects can be destroyed before `new` returns "
|
||||
"if the task resolves fast enough.";
|
||||
}
|
||||
|
||||
// BindState<>
|
||||
|
@ -917,7 +917,7 @@ using MakeBindStateType =
|
|||
// };
|
||||
//
|
||||
// WeakPtr<Foo> oo = nullptr;
|
||||
// base::BindOnce(&Foo::bar, oo).Run();
|
||||
// base::Bind(&Foo::bar, oo).Run();
|
||||
template <typename T>
|
||||
struct IsWeakReceiver : std::false_type {};
|
||||
|
||||
|
@ -953,11 +953,9 @@ struct BindUnwrapTraits<internal::RetainedRefWrapper<T>> {
|
|||
static T* Unwrap(const internal::RetainedRefWrapper<T>& o) { return o.get(); }
|
||||
};
|
||||
|
||||
template <typename T, typename Deleter>
|
||||
struct BindUnwrapTraits<internal::OwnedWrapper<T, Deleter>> {
|
||||
static T* Unwrap(const internal::OwnedWrapper<T, Deleter>& o) {
|
||||
return o.get();
|
||||
}
|
||||
template <typename T>
|
||||
struct BindUnwrapTraits<internal::OwnedWrapper<T>> {
|
||||
static T* Unwrap(const internal::OwnedWrapper<T>& o) { return o.get(); }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
|
@ -1,209 +0,0 @@
|
|||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This file defines some bit utilities.
|
||||
|
||||
#ifndef BASE_BITS_H_
|
||||
#define BASE_BITS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/logging.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(COMPILER_MSVC)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace bits {
|
||||
|
||||
// Returns true iff |value| is a power of 2.
|
||||
template <typename T,
|
||||
typename = typename std::enable_if<std::is_integral<T>::value>>
|
||||
constexpr inline bool IsPowerOfTwo(T value) {
|
||||
// From "Hacker's Delight": Section 2.1 Manipulating Rightmost Bits.
|
||||
//
|
||||
// Only positive integers with a single bit set are powers of two. If only one
|
||||
// bit is set in x (e.g. 0b00000100000000) then |x-1| will have that bit set
|
||||
// to zero and all bits to its right set to 1 (e.g. 0b00000011111111). Hence
|
||||
// |x & (x-1)| is 0 iff x is a power of two.
|
||||
return value > 0 && (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
// Round up |size| to a multiple of alignment, which must be a power of two.
|
||||
inline size_t Align(size_t size, size_t alignment) {
|
||||
DCHECK(IsPowerOfTwo(alignment));
|
||||
return (size + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
// Round down |size| to a multiple of alignment, which must be a power of two.
|
||||
inline size_t AlignDown(size_t size, size_t alignment) {
|
||||
DCHECK(IsPowerOfTwo(alignment));
|
||||
return size & ~(alignment - 1);
|
||||
}
|
||||
|
||||
// CountLeadingZeroBits(value) returns the number of zero bits following the
|
||||
// most significant 1 bit in |value| if |value| is non-zero, otherwise it
|
||||
// returns {sizeof(T) * 8}.
|
||||
// Example: 00100010 -> 2
|
||||
//
|
||||
// CountTrailingZeroBits(value) returns the number of zero bits preceding the
|
||||
// least significant 1 bit in |value| if |value| is non-zero, otherwise it
|
||||
// returns {sizeof(T) * 8}.
|
||||
// Example: 00100010 -> 1
|
||||
//
|
||||
// C does not have an operator to do this, but fortunately the various
|
||||
// compilers have built-ins that map to fast underlying processor instructions.
|
||||
#if defined(COMPILER_MSVC)
|
||||
|
||||
template <typename T, unsigned bits = sizeof(T) * 8>
|
||||
ALWAYS_INLINE
|
||||
typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 4,
|
||||
unsigned>::type
|
||||
CountLeadingZeroBits(T x) {
|
||||
static_assert(bits > 0, "invalid instantiation");
|
||||
unsigned long index;
|
||||
return LIKELY(_BitScanReverse(&index, static_cast<uint32_t>(x)))
|
||||
? (31 - index - (32 - bits))
|
||||
: bits;
|
||||
}
|
||||
|
||||
template <typename T, unsigned bits = sizeof(T) * 8>
|
||||
ALWAYS_INLINE
|
||||
typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) == 8,
|
||||
unsigned>::type
|
||||
CountLeadingZeroBits(T x) {
|
||||
static_assert(bits > 0, "invalid instantiation");
|
||||
unsigned long index;
|
||||
// MSVC only supplies _BitScanReverse64 when building for a 64-bit target.
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
return LIKELY(_BitScanReverse64(&index, static_cast<uint64_t>(x)))
|
||||
? (63 - index)
|
||||
: 64;
|
||||
#else
|
||||
uint32_t left = static_cast<uint32_t>(x >> 32);
|
||||
if (LIKELY(_BitScanReverse(&index, left)))
|
||||
return 31 - index;
|
||||
|
||||
uint32_t right = static_cast<uint32_t>(x);
|
||||
if (LIKELY(_BitScanReverse(&index, right)))
|
||||
return 63 - index;
|
||||
|
||||
return 64;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T, unsigned bits = sizeof(T) * 8>
|
||||
ALWAYS_INLINE
|
||||
typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 4,
|
||||
unsigned>::type
|
||||
CountTrailingZeroBits(T x) {
|
||||
static_assert(bits > 0, "invalid instantiation");
|
||||
unsigned long index;
|
||||
return LIKELY(_BitScanForward(&index, static_cast<uint32_t>(x))) ? index
|
||||
: bits;
|
||||
}
|
||||
|
||||
template <typename T, unsigned bits = sizeof(T) * 8>
|
||||
ALWAYS_INLINE
|
||||
typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) == 8,
|
||||
unsigned>::type
|
||||
CountTrailingZeroBits(T x) {
|
||||
static_assert(bits > 0, "invalid instantiation");
|
||||
unsigned long index;
|
||||
// MSVC only supplies _BitScanForward64 when building for a 64-bit target.
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
return LIKELY(_BitScanForward64(&index, static_cast<uint64_t>(x))) ? index
|
||||
: 64;
|
||||
#else
|
||||
uint32_t right = static_cast<uint32_t>(x);
|
||||
if (LIKELY(_BitScanForward(&index, right)))
|
||||
return index;
|
||||
|
||||
uint32_t left = static_cast<uint32_t>(x >> 32);
|
||||
if (LIKELY(_BitScanForward(&index, left)))
|
||||
return 32 + index;
|
||||
|
||||
return 64;
|
||||
#endif
|
||||
}
|
||||
|
||||
ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) {
|
||||
return CountLeadingZeroBits(x);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) {
|
||||
return CountLeadingZeroBits(x);
|
||||
}
|
||||
|
||||
#elif defined(COMPILER_GCC)
|
||||
|
||||
// __builtin_clz has undefined behaviour for an input of 0, even though there's
|
||||
// clearly a return value that makes sense, and even though some processor clz
|
||||
// instructions have defined behaviour for 0. We could drop to raw __asm__ to
|
||||
// do better, but we'll avoid doing that unless we see proof that we need to.
|
||||
template <typename T, unsigned bits = sizeof(T) * 8>
|
||||
ALWAYS_INLINE
|
||||
typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8,
|
||||
unsigned>::type
|
||||
CountLeadingZeroBits(T value) {
|
||||
static_assert(bits > 0, "invalid instantiation");
|
||||
return LIKELY(value)
|
||||
? bits == 64
|
||||
? __builtin_clzll(static_cast<uint64_t>(value))
|
||||
: __builtin_clz(static_cast<uint32_t>(value)) - (32 - bits)
|
||||
: bits;
|
||||
}
|
||||
|
||||
template <typename T, unsigned bits = sizeof(T) * 8>
|
||||
ALWAYS_INLINE
|
||||
typename std::enable_if<std::is_unsigned<T>::value && sizeof(T) <= 8,
|
||||
unsigned>::type
|
||||
CountTrailingZeroBits(T value) {
|
||||
return LIKELY(value) ? bits == 64
|
||||
? __builtin_ctzll(static_cast<uint64_t>(value))
|
||||
: __builtin_ctz(static_cast<uint32_t>(value))
|
||||
: bits;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE uint32_t CountLeadingZeroBits32(uint32_t x) {
|
||||
return CountLeadingZeroBits(x);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE uint64_t CountLeadingZeroBits64(uint64_t x) {
|
||||
return CountLeadingZeroBits(x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ALWAYS_INLINE size_t CountLeadingZeroBitsSizeT(size_t x) {
|
||||
return CountLeadingZeroBits(x);
|
||||
}
|
||||
|
||||
ALWAYS_INLINE size_t CountTrailingZeroBitsSizeT(size_t x) {
|
||||
return CountTrailingZeroBits(x);
|
||||
}
|
||||
|
||||
// Returns the integer i such as 2^i <= n < 2^(i+1)
|
||||
inline int Log2Floor(uint32_t n) {
|
||||
return 31 - CountLeadingZeroBits(n);
|
||||
}
|
||||
|
||||
// Returns the integer i such as 2^(i-1) < n <= 2^i
|
||||
inline int Log2Ceiling(uint32_t n) {
|
||||
// When n == 0, we want the function to return -1.
|
||||
// When n == 0, (n - 1) will underflow to 0xFFFFFFFF, which is
|
||||
// why the statement below starts with (n ? 32 : -1).
|
||||
return (n ? 32 : -1) - CountLeadingZeroBits(n - 1);
|
||||
}
|
||||
|
||||
} // namespace bits
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_BITS_H_
|
|
@ -2,9 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// NOTE: Header files that do not require the full definition of
|
||||
// base::{Once,Repeating}Callback or base::{Once,Repeating}Closure should
|
||||
// #include "base/callback_forward.h" instead of this file.
|
||||
// NOTE: Header files that do not require the full definition of Callback or
|
||||
// Closure should #include "base/callback_forward.h" instead of this file.
|
||||
|
||||
#ifndef BASE_CALLBACK_H_
|
||||
#define BASE_CALLBACK_H_
|
||||
|
@ -43,7 +42,7 @@
|
|||
//
|
||||
// Callbacks also support cancellation. A common use is binding the receiver
|
||||
// object as a WeakPtr<T>. If that weak pointer is invalidated, calling Run()
|
||||
// will be a no-op. Note that |IsCancelled()| and |is_null()| are distinct:
|
||||
// will be a no-op. Note that |is_cancelled()| and |is_null()| are distinct:
|
||||
// simply cancelling a callback will not also make it null.
|
||||
//
|
||||
// base::Callback is currently a type alias for base::RepeatingCallback. In the
|
||||
|
@ -118,14 +117,10 @@ class RepeatingCallback<R(Args...)> : public internal::CallbackBaseCopyable {
|
|||
RepeatingCallback(RepeatingCallback&&) noexcept = default;
|
||||
RepeatingCallback& operator=(RepeatingCallback&&) noexcept = default;
|
||||
|
||||
bool operator==(const RepeatingCallback& other) const {
|
||||
bool Equals(const RepeatingCallback& other) const {
|
||||
return EqualsInternal(other);
|
||||
}
|
||||
|
||||
bool operator!=(const RepeatingCallback& other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
R Run(Args... args) const & {
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(this->polymorphic_invoke());
|
||||
|
@ -140,7 +135,7 @@ class RepeatingCallback<R(Args...)> : public internal::CallbackBaseCopyable {
|
|||
RepeatingCallback cb = std::move(*this);
|
||||
PolymorphicInvoke f =
|
||||
reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
|
||||
return f(std::move(cb).bind_state_.get(), std::forward<Args>(args)...);
|
||||
return f(cb.bind_state_.get(), std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -16,9 +16,8 @@ class RepeatingCallback;
|
|||
template <typename Signature>
|
||||
using Callback = RepeatingCallback<Signature>;
|
||||
|
||||
// Syntactic sugar to make OnceClosure<void()> and RepeatingClosure<void()>
|
||||
// easier to declare since they will be used in a lot of APIs with delayed
|
||||
// execution.
|
||||
// Syntactic sugar to make Callback<void()> easier to declare since it
|
||||
// will be used in a lot of APIs with delayed execution.
|
||||
using OnceClosure = OnceCallback<void()>;
|
||||
using RepeatingClosure = RepeatingCallback<void()>;
|
||||
using Closure = Callback<void()>;
|
||||
|
|
|
@ -19,19 +19,14 @@ struct FakeBindState;
|
|||
|
||||
namespace internal {
|
||||
|
||||
class BindStateBase;
|
||||
class FinallyExecutorCommon;
|
||||
class ThenAndCatchExecutorCommon;
|
||||
class CallbackBase;
|
||||
class CallbackBaseCopyable;
|
||||
|
||||
template <typename ReturnType>
|
||||
class PostTaskExecutor;
|
||||
class BindStateBase;
|
||||
|
||||
template <typename Functor, typename... BoundArgs>
|
||||
struct BindState;
|
||||
|
||||
class CallbackBase;
|
||||
class CallbackBaseCopyable;
|
||||
|
||||
struct BindStateBaseRefCountTraits {
|
||||
static void Destruct(const BindStateBase*);
|
||||
};
|
||||
|
@ -45,10 +40,11 @@ using PassingType = std::conditional_t<std::is_scalar<T>::value, T, T&&>;
|
|||
// DoInvoke function to perform the function execution. This allows
|
||||
// us to shield the Callback class from the types of the bound argument via
|
||||
// "type erasure."
|
||||
// At the base level, the only task is to add reference counting data. Avoid
|
||||
// using or inheriting any virtual functions. Creating a vtable for every
|
||||
// BindState template instantiation results in a lot of bloat. Its only task is
|
||||
// to call the destructor which can be done with a function pointer.
|
||||
// At the base level, the only task is to add reference counting data. Don't use
|
||||
// RefCountedThreadSafe since it requires the destructor to be a virtual method.
|
||||
// Creating a vtable for every BindState template instantiation results in a lot
|
||||
// of bloat. Its only task is to call the destructor which can be done with a
|
||||
// function pointer.
|
||||
class BASE_EXPORT BindStateBase
|
||||
: public RefCountedThreadSafe<BindStateBase, BindStateBaseRefCountTraits> {
|
||||
public:
|
||||
|
@ -139,12 +135,6 @@ class BASE_EXPORT CallbackBase {
|
|||
void Reset();
|
||||
|
||||
protected:
|
||||
friend class FinallyExecutorCommon;
|
||||
friend class ThenAndCatchExecutorCommon;
|
||||
|
||||
template <typename ReturnType>
|
||||
friend class PostTaskExecutor;
|
||||
|
||||
using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;
|
||||
|
||||
// Returns true if this callback equals |other|. |other| may be null.
|
||||
|
|
|
@ -9,10 +9,6 @@
|
|||
|
||||
#if defined(COMPILER_MSVC)
|
||||
|
||||
#if !defined(__clang__)
|
||||
#error "Only clang-cl is supported on Windows, see https://crbug.com/988071"
|
||||
#endif
|
||||
|
||||
// Macros for suppressing and disabling warnings on MSVC.
|
||||
//
|
||||
// Warning numbers are enumerated at:
|
||||
|
@ -26,8 +22,8 @@
|
|||
|
||||
// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled.
|
||||
// The warning remains disabled until popped by MSVC_POP_WARNING.
|
||||
#define MSVC_PUSH_DISABLE_WARNING(n) \
|
||||
__pragma(warning(push)) __pragma(warning(disable : n))
|
||||
#define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
|
||||
__pragma(warning(disable:n))
|
||||
|
||||
// Pop effects of innermost MSVC_PUSH_* macro.
|
||||
#define MSVC_POP_WARNING() __pragma(warning(pop))
|
||||
|
@ -141,7 +137,7 @@
|
|||
// For member functions, the implicit this parameter counts as index 1.
|
||||
#if defined(COMPILER_GCC) || defined(__clang__)
|
||||
#define PRINTF_FORMAT(format_param, dots_param) \
|
||||
__attribute__((format(printf, format_param, dots_param)))
|
||||
__attribute__((format(printf, format_param, dots_param)))
|
||||
#else
|
||||
#define PRINTF_FORMAT(format_param, dots_param)
|
||||
#endif
|
||||
|
@ -170,14 +166,14 @@
|
|||
// Mark a memory region fully initialized.
|
||||
// Use this to annotate code that deliberately reads uninitialized data, for
|
||||
// example a GC scavenging root set pointers from the stack.
|
||||
#define MSAN_UNPOISON(p, size) __msan_unpoison(p, size)
|
||||
#define MSAN_UNPOISON(p, size) __msan_unpoison(p, size)
|
||||
|
||||
// Check a memory region for initializedness, as if it was being used here.
|
||||
// If any bits are uninitialized, crash with an MSan report.
|
||||
// Use this to sanitize data which MSan won't be able to track, e.g. before
|
||||
// passing data to another process via shared memory.
|
||||
#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size) \
|
||||
__msan_check_mem_is_initialized(p, size)
|
||||
__msan_check_mem_is_initialized(p, size)
|
||||
#else // MEMORY_SANITIZER
|
||||
#define MSAN_UNPOISON(p, size)
|
||||
#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size)
|
||||
|
@ -242,57 +238,4 @@
|
|||
#define PRETTY_FUNCTION __func__
|
||||
#endif
|
||||
|
||||
#if !defined(CPU_ARM_NEON)
|
||||
#if defined(__arm__)
|
||||
#if !defined(__ARMEB__) && !defined(__ARM_EABI__) && !defined(__EABI__) && \
|
||||
!defined(__VFP_FP__) && !defined(_WIN32_WCE) && !defined(ANDROID)
|
||||
#error Chromium does not support middle endian architecture
|
||||
#endif
|
||||
#if defined(__ARM_NEON__)
|
||||
#define CPU_ARM_NEON 1
|
||||
#endif
|
||||
#endif // defined(__arm__)
|
||||
#endif // !defined(CPU_ARM_NEON)
|
||||
|
||||
#if !defined(HAVE_MIPS_MSA_INTRINSICS)
|
||||
#if defined(__mips_msa) && defined(__mips_isa_rev) && (__mips_isa_rev >= 5)
|
||||
#define HAVE_MIPS_MSA_INTRINSICS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) && __has_attribute(uninitialized)
|
||||
// Attribute "uninitialized" disables -ftrivial-auto-var-init=pattern for
|
||||
// the specified variable.
|
||||
// Library-wide alternative is
|
||||
// 'configs -= [ "//build/config/compiler:default_init_stack_vars" ]' in .gn
|
||||
// file.
|
||||
//
|
||||
// See "init_stack_vars" in build/config/compiler/BUILD.gn and
|
||||
// http://crbug.com/977230
|
||||
// "init_stack_vars" is enabled for non-official builds and we hope to enable it
|
||||
// in official build in 2020 as well. The flag writes fixed pattern into
|
||||
// uninitialized parts of all local variables. In rare cases such initialization
|
||||
// is undesirable and attribute can be used:
|
||||
// 1. Degraded performance
|
||||
// In most cases compiler is able to remove additional stores. E.g. if memory is
|
||||
// never accessed or properly initialized later. Preserved stores mostly will
|
||||
// not affect program performance. However if compiler failed on some
|
||||
// performance critical code we can get a visible regression in a benchmark.
|
||||
// 2. memset, memcpy calls
|
||||
// Compiler may replaces some memory writes with memset or memcpy calls. This is
|
||||
// not -ftrivial-auto-var-init specific, but it can happen more likely with the
|
||||
// flag. It can be a problem if code is not linked with C run-time library.
|
||||
//
|
||||
// Note: The flag is security risk mitigation feature. So in future the
|
||||
// attribute uses should be avoided when possible. However to enable this
|
||||
// mitigation on the most of the code we need to be less strict now and minimize
|
||||
// number of exceptions later. So if in doubt feel free to use attribute, but
|
||||
// please document the problem for someone who is going to cleanup it later.
|
||||
// E.g. platform, bot, benchmark or test name in patch description or next to
|
||||
// the attribute.
|
||||
#define STACK_UNINITIALIZED __attribute__((uninitialized))
|
||||
#else
|
||||
#define STACK_UNINITIALIZED
|
||||
#endif
|
||||
|
||||
#endif // BASE_COMPILER_SPECIFIC_H_
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_CONTAINERS_BUFFER_ITERATOR_H_
|
||||
#define BASE_CONTAINERS_BUFFER_ITERATOR_H_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/bit_cast.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "base/numerics/checked_math.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// BufferIterator is a bounds-checked container utility to access variable-
|
||||
// length, heterogeneous structures contained within a buffer. If the data are
|
||||
// homogeneous, use base::span<> instead.
|
||||
//
|
||||
// After being created with a weakly-owned buffer, BufferIterator returns
|
||||
// pointers to structured data within the buffer. After each method call that
|
||||
// returns data in the buffer, the iterator position is advanced by the byte
|
||||
// size of the object (or span of objects) returned. If there are not enough
|
||||
// bytes remaining in the buffer to return the requested object(s), a nullptr
|
||||
// or empty span is returned.
|
||||
//
|
||||
// This class is similar to base::Pickle, which should be preferred for
|
||||
// serializing to disk. Pickle versions its header and does not support writing
|
||||
// structures, which are problematic for serialization due to struct padding and
|
||||
// version shear concerns.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// std::vector<uint8_t> buffer(4096);
|
||||
// if (!ReadSomeData(&buffer, buffer.size())) {
|
||||
// LOG(ERROR) << "Failed to read data.";
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// BufferIterator<uint8_t> iterator(buffer);
|
||||
// uint32_t* num_items = iterator.Object<uint32_t>();
|
||||
// if (!num_items) {
|
||||
// LOG(ERROR) << "No num_items field."
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// base::span<const item_struct> items =
|
||||
// iterator.Span<item_struct>(*num_items);
|
||||
// if (items.size() != *num_items) {
|
||||
// LOG(ERROR) << "Not enough items.";
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// // ... validate the objects in |items|.
|
||||
template <typename B>
|
||||
class BufferIterator {
|
||||
public:
|
||||
static_assert(std::is_same<std::remove_const_t<B>, char>::value ||
|
||||
std::is_same<std::remove_const_t<B>, unsigned char>::value,
|
||||
"Underlying buffer type must be char-type.");
|
||||
|
||||
BufferIterator() {}
|
||||
BufferIterator(B* data, size_t size)
|
||||
: BufferIterator(make_span(data, size)) {}
|
||||
explicit BufferIterator(span<B> buffer)
|
||||
: buffer_(buffer), remaining_(buffer) {}
|
||||
~BufferIterator() {}
|
||||
|
||||
// Returns a pointer to a mutable structure T in the buffer at the current
|
||||
// position. On success, the iterator position is advanced by sizeof(T). If
|
||||
// there are not sizeof(T) bytes remaining in the buffer, returns nullptr.
|
||||
template <typename T,
|
||||
typename =
|
||||
typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
|
||||
T* MutableObject() {
|
||||
size_t size = sizeof(T);
|
||||
size_t next_position;
|
||||
if (!CheckAdd(position(), size).AssignIfValid(&next_position))
|
||||
return nullptr;
|
||||
if (next_position > total_size())
|
||||
return nullptr;
|
||||
T* t = bit_cast<T*>(remaining_.data());
|
||||
remaining_ = remaining_.subspan(size);
|
||||
return t;
|
||||
}
|
||||
|
||||
// Returns a const pointer to an object of type T in the buffer at the current
|
||||
// position.
|
||||
template <typename T,
|
||||
typename =
|
||||
typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
|
||||
const T* Object() {
|
||||
return MutableObject<const T>();
|
||||
}
|
||||
|
||||
// Returns a span of |count| T objects in the buffer at the current position.
|
||||
// On success, the iterator position is advanced by |sizeof(T) * count|. If
|
||||
// there are not enough bytes remaining in the buffer to fulfill the request,
|
||||
// returns an empty span.
|
||||
template <typename T,
|
||||
typename =
|
||||
typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
|
||||
span<T> MutableSpan(size_t count) {
|
||||
size_t size;
|
||||
if (!CheckMul(sizeof(T), count).AssignIfValid(&size))
|
||||
return span<T>();
|
||||
size_t next_position;
|
||||
if (!CheckAdd(position(), size).AssignIfValid(&next_position))
|
||||
return span<T>();
|
||||
if (next_position > total_size())
|
||||
return span<T>();
|
||||
auto result = span<T>(bit_cast<T*>(remaining_.data()), count);
|
||||
remaining_ = remaining_.subspan(size);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns a span to |count| const objects of type T in the buffer at the
|
||||
// current position.
|
||||
template <typename T,
|
||||
typename =
|
||||
typename std::enable_if_t<std::is_trivially_copyable<T>::value>>
|
||||
span<const T> Span(size_t count) {
|
||||
return MutableSpan<const T>(count);
|
||||
}
|
||||
|
||||
// Resets the iterator position to the absolute offset |to|.
|
||||
void Seek(size_t to) { remaining_ = buffer_.subspan(to); }
|
||||
|
||||
// Returns the total size of the underlying buffer.
|
||||
size_t total_size() { return buffer_.size(); }
|
||||
|
||||
// Returns the current position in the buffer.
|
||||
size_t position() { return buffer_.size_bytes() - remaining_.size_bytes(); }
|
||||
|
||||
private:
|
||||
// The original buffer that the iterator was constructed with.
|
||||
const span<B> buffer_;
|
||||
// A subspan of |buffer_| containing the remaining bytes to iterate over.
|
||||
span<B> remaining_;
|
||||
// Copy and assign allowed.
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CONTAINERS_BUFFER_ITERATOR_H_
|
|
@ -1,205 +0,0 @@
|
|||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_CONTAINERS_CHECKED_ITERATORS_H_
|
||||
#define BASE_CONTAINERS_CHECKED_ITERATORS_H_
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/containers/util.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
template <typename T>
|
||||
class CheckedContiguousIterator {
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = std::remove_cv_t<T>;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
using iterator_category = std::random_access_iterator_tag;
|
||||
|
||||
// Required for converting constructor below.
|
||||
template <typename U>
|
||||
friend class CheckedContiguousIterator;
|
||||
|
||||
constexpr CheckedContiguousIterator() = default;
|
||||
constexpr CheckedContiguousIterator(T* start, const T* end)
|
||||
: CheckedContiguousIterator(start, start, end) {}
|
||||
constexpr CheckedContiguousIterator(const T* start, T* current, const T* end)
|
||||
: start_(start), current_(current), end_(end) {
|
||||
CHECK_LE(start, current);
|
||||
CHECK_LE(current, end);
|
||||
}
|
||||
constexpr CheckedContiguousIterator(const CheckedContiguousIterator& other) =
|
||||
default;
|
||||
|
||||
// Converting constructor allowing conversions like CCI<T> to CCI<const T>,
|
||||
// but disallowing CCI<const T> to CCI<T> or CCI<Derived> to CCI<Base>, which
|
||||
// are unsafe. Furthermore, this is the same condition as used by the
|
||||
// converting constructors of std::span<T> and std::unique_ptr<T[]>.
|
||||
// See https://wg21.link/n4042 for details.
|
||||
template <
|
||||
typename U,
|
||||
std::enable_if_t<std::is_convertible<U (*)[], T (*)[]>::value>* = nullptr>
|
||||
constexpr CheckedContiguousIterator(const CheckedContiguousIterator<U>& other)
|
||||
: start_(other.start_), current_(other.current_), end_(other.end_) {
|
||||
// We explicitly don't delegate to the 3-argument constructor here. Its
|
||||
// CHECKs would be redundant, since we expect |other| to maintain its own
|
||||
// invariant. However, DCHECKs never hurt anybody. Presumably.
|
||||
DCHECK_LE(other.start_, other.current_);
|
||||
DCHECK_LE(other.current_, other.end_);
|
||||
}
|
||||
|
||||
~CheckedContiguousIterator() = default;
|
||||
|
||||
constexpr CheckedContiguousIterator& operator=(
|
||||
const CheckedContiguousIterator& other) = default;
|
||||
|
||||
constexpr bool operator==(const CheckedContiguousIterator& other) const {
|
||||
CheckComparable(other);
|
||||
return current_ == other.current_;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const CheckedContiguousIterator& other) const {
|
||||
CheckComparable(other);
|
||||
return current_ != other.current_;
|
||||
}
|
||||
|
||||
constexpr bool operator<(const CheckedContiguousIterator& other) const {
|
||||
CheckComparable(other);
|
||||
return current_ < other.current_;
|
||||
}
|
||||
|
||||
constexpr bool operator<=(const CheckedContiguousIterator& other) const {
|
||||
CheckComparable(other);
|
||||
return current_ <= other.current_;
|
||||
}
|
||||
|
||||
constexpr bool operator>(const CheckedContiguousIterator& other) const {
|
||||
CheckComparable(other);
|
||||
return current_ > other.current_;
|
||||
}
|
||||
|
||||
constexpr bool operator>=(const CheckedContiguousIterator& other) const {
|
||||
CheckComparable(other);
|
||||
return current_ >= other.current_;
|
||||
}
|
||||
|
||||
constexpr CheckedContiguousIterator& operator++() {
|
||||
CHECK_NE(current_, end_);
|
||||
++current_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr CheckedContiguousIterator operator++(int) {
|
||||
CheckedContiguousIterator old = *this;
|
||||
++*this;
|
||||
return old;
|
||||
}
|
||||
|
||||
constexpr CheckedContiguousIterator& operator--() {
|
||||
CHECK_NE(current_, start_);
|
||||
--current_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr CheckedContiguousIterator operator--(int) {
|
||||
CheckedContiguousIterator old = *this;
|
||||
--*this;
|
||||
return old;
|
||||
}
|
||||
|
||||
constexpr CheckedContiguousIterator& operator+=(difference_type rhs) {
|
||||
if (rhs > 0) {
|
||||
CHECK_LE(rhs, end_ - current_);
|
||||
} else {
|
||||
CHECK_LE(-rhs, current_ - start_);
|
||||
}
|
||||
current_ += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr CheckedContiguousIterator operator+(difference_type rhs) const {
|
||||
CheckedContiguousIterator it = *this;
|
||||
it += rhs;
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr CheckedContiguousIterator& operator-=(difference_type rhs) {
|
||||
if (rhs < 0) {
|
||||
CHECK_LE(-rhs, end_ - current_);
|
||||
} else {
|
||||
CHECK_LE(rhs, current_ - start_);
|
||||
}
|
||||
current_ -= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr CheckedContiguousIterator operator-(difference_type rhs) const {
|
||||
CheckedContiguousIterator it = *this;
|
||||
it -= rhs;
|
||||
return it;
|
||||
}
|
||||
|
||||
constexpr friend difference_type operator-(
|
||||
const CheckedContiguousIterator& lhs,
|
||||
const CheckedContiguousIterator& rhs) {
|
||||
CHECK_EQ(lhs.start_, rhs.start_);
|
||||
CHECK_EQ(lhs.end_, rhs.end_);
|
||||
return lhs.current_ - rhs.current_;
|
||||
}
|
||||
|
||||
constexpr reference operator*() const {
|
||||
CHECK_NE(current_, end_);
|
||||
return *current_;
|
||||
}
|
||||
|
||||
constexpr pointer operator->() const {
|
||||
CHECK_NE(current_, end_);
|
||||
return current_;
|
||||
}
|
||||
|
||||
constexpr reference operator[](difference_type rhs) const {
|
||||
CHECK_GE(rhs, 0);
|
||||
CHECK_LT(rhs, end_ - current_);
|
||||
return current_[rhs];
|
||||
}
|
||||
|
||||
static bool IsRangeMoveSafe(const CheckedContiguousIterator& from_begin,
|
||||
const CheckedContiguousIterator& from_end,
|
||||
const CheckedContiguousIterator& to)
|
||||
WARN_UNUSED_RESULT {
|
||||
if (from_end < from_begin)
|
||||
return false;
|
||||
const auto from_begin_uintptr = get_uintptr(from_begin.current_);
|
||||
const auto from_end_uintptr = get_uintptr(from_end.current_);
|
||||
const auto to_begin_uintptr = get_uintptr(to.current_);
|
||||
const auto to_end_uintptr =
|
||||
get_uintptr((to + std::distance(from_begin, from_end)).current_);
|
||||
|
||||
return to_begin_uintptr >= from_end_uintptr ||
|
||||
to_end_uintptr <= from_begin_uintptr;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr void CheckComparable(const CheckedContiguousIterator& other) const {
|
||||
CHECK_EQ(start_, other.start_);
|
||||
CHECK_EQ(end_, other.end_);
|
||||
}
|
||||
|
||||
const T* start_ = nullptr;
|
||||
T* current_ = nullptr;
|
||||
const T* end_ = nullptr;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using CheckedContiguousConstIterator = CheckedContiguousIterator<const T>;
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_CONTAINERS_CHECKED_ITERATORS_H_
|
|
@ -14,7 +14,6 @@
|
|||
#include "base/containers/vector_buffer.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/template_util.h"
|
||||
|
||||
// base::circular_deque is similar to std::deque. Unlike std::deque, the
|
||||
|
@ -522,15 +521,15 @@ class circular_deque {
|
|||
return buffer_[i - right_size];
|
||||
}
|
||||
value_type& at(size_type i) {
|
||||
return const_cast<value_type&>(as_const(*this).at(i));
|
||||
return const_cast<value_type&>(
|
||||
const_cast<const circular_deque*>(this)->at(i));
|
||||
}
|
||||
|
||||
value_type& operator[](size_type i) {
|
||||
return const_cast<value_type&>(as_const(*this)[i]);
|
||||
value_type& operator[](size_type i) { return at(i); }
|
||||
const value_type& operator[](size_type i) const {
|
||||
return const_cast<circular_deque*>(this)->at(i);
|
||||
}
|
||||
|
||||
const value_type& operator[](size_type i) const { return at(i); }
|
||||
|
||||
value_type& front() {
|
||||
DCHECK(!empty());
|
||||
return buffer_[begin_];
|
||||
|
|
|
@ -1,530 +0,0 @@
|
|||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_CONTAINERS_SPAN_H_
|
||||
#define BASE_CONTAINERS_SPAN_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "base/containers/checked_iterators.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/stl_util.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// [views.constants]
|
||||
constexpr size_t dynamic_extent = std::numeric_limits<size_t>::max();
|
||||
|
||||
template <typename T, size_t Extent = dynamic_extent>
|
||||
class span;
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
struct ExtentImpl : std::integral_constant<size_t, dynamic_extent> {};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct ExtentImpl<T[N]> : std::integral_constant<size_t, N> {};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct ExtentImpl<std::array<T, N>> : std::integral_constant<size_t, N> {};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct ExtentImpl<base::span<T, N>> : std::integral_constant<size_t, N> {};
|
||||
|
||||
template <typename T>
|
||||
using Extent = ExtentImpl<std::remove_cv_t<std::remove_reference_t<T>>>;
|
||||
|
||||
template <typename T>
|
||||
struct IsSpanImpl : std::false_type {};
|
||||
|
||||
template <typename T, size_t Extent>
|
||||
struct IsSpanImpl<span<T, Extent>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
using IsSpan = IsSpanImpl<std::decay_t<T>>;
|
||||
|
||||
template <typename T>
|
||||
struct IsStdArrayImpl : std::false_type {};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct IsStdArrayImpl<std::array<T, N>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
using IsStdArray = IsStdArrayImpl<std::decay_t<T>>;
|
||||
|
||||
template <typename T>
|
||||
using IsCArray = std::is_array<std::remove_reference_t<T>>;
|
||||
|
||||
template <typename From, typename To>
|
||||
using IsLegalDataConversion = std::is_convertible<From (*)[], To (*)[]>;
|
||||
|
||||
template <typename Container, typename T>
|
||||
using ContainerHasConvertibleData = IsLegalDataConversion<
|
||||
std::remove_pointer_t<decltype(base::data(std::declval<Container>()))>,
|
||||
T>;
|
||||
|
||||
template <typename Container>
|
||||
using ContainerHasIntegralSize =
|
||||
std::is_integral<decltype(base::size(std::declval<Container>()))>;
|
||||
|
||||
template <typename From, size_t FromExtent, typename To, size_t ToExtent>
|
||||
using EnableIfLegalSpanConversion =
|
||||
std::enable_if_t<(ToExtent == dynamic_extent || ToExtent == FromExtent) &&
|
||||
IsLegalDataConversion<From, To>::value>;
|
||||
|
||||
// SFINAE check if Array can be converted to a span<T>.
|
||||
template <typename Array, typename T, size_t Extent>
|
||||
using EnableIfSpanCompatibleArray =
|
||||
std::enable_if_t<(Extent == dynamic_extent ||
|
||||
Extent == internal::Extent<Array>::value) &&
|
||||
ContainerHasConvertibleData<Array, T>::value>;
|
||||
|
||||
// SFINAE check if Container can be converted to a span<T>.
|
||||
template <typename Container, typename T>
|
||||
using IsSpanCompatibleContainer =
|
||||
std::conditional_t<!IsSpan<Container>::value &&
|
||||
!IsStdArray<Container>::value &&
|
||||
!IsCArray<Container>::value &&
|
||||
ContainerHasConvertibleData<Container, T>::value &&
|
||||
ContainerHasIntegralSize<Container>::value,
|
||||
std::true_type,
|
||||
std::false_type>;
|
||||
|
||||
template <typename Container, typename T>
|
||||
using EnableIfSpanCompatibleContainer =
|
||||
std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value>;
|
||||
|
||||
template <typename Container, typename T, size_t Extent>
|
||||
using EnableIfSpanCompatibleContainerAndSpanIsDynamic =
|
||||
std::enable_if_t<IsSpanCompatibleContainer<Container, T>::value &&
|
||||
Extent == dynamic_extent>;
|
||||
|
||||
// A helper template for storing the size of a span. Spans with static extents
|
||||
// don't require additional storage, since the extent itself is specified in the
|
||||
// template parameter.
|
||||
template <size_t Extent>
|
||||
class ExtentStorage {
|
||||
public:
|
||||
constexpr explicit ExtentStorage(size_t size) noexcept {}
|
||||
constexpr size_t size() const noexcept { return Extent; }
|
||||
};
|
||||
|
||||
// Specialization of ExtentStorage for dynamic extents, which do require
|
||||
// explicit storage for the size.
|
||||
template <>
|
||||
struct ExtentStorage<dynamic_extent> {
|
||||
constexpr explicit ExtentStorage(size_t size) noexcept : size_(size) {}
|
||||
constexpr size_t size() const noexcept { return size_; }
|
||||
|
||||
private:
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// A span is a value type that represents an array of elements of type T. Since
|
||||
// it only consists of a pointer to memory with an associated size, it is very
|
||||
// light-weight. It is cheap to construct, copy, move and use spans, so that
|
||||
// users are encouraged to use it as a pass-by-value parameter. A span does not
|
||||
// own the underlying memory, so care must be taken to ensure that a span does
|
||||
// not outlive the backing store.
|
||||
//
|
||||
// span is somewhat analogous to StringPiece, but with arbitrary element types,
|
||||
// allowing mutation if T is non-const.
|
||||
//
|
||||
// span is implicitly convertible from C++ arrays, as well as most [1]
|
||||
// container-like types that provide a data() and size() method (such as
|
||||
// std::vector<T>). A mutable span<T> can also be implicitly converted to an
|
||||
// immutable span<const T>.
|
||||
//
|
||||
// Consider using a span for functions that take a data pointer and size
|
||||
// parameter: it allows the function to still act on an array-like type, while
|
||||
// allowing the caller code to be a bit more concise.
|
||||
//
|
||||
// For read-only data access pass a span<const T>: the caller can supply either
|
||||
// a span<const T> or a span<T>, while the callee will have a read-only view.
|
||||
// For read-write access a mutable span<T> is required.
|
||||
//
|
||||
// Without span:
|
||||
// Read-Only:
|
||||
// // std::string HexEncode(const uint8_t* data, size_t size);
|
||||
// std::vector<uint8_t> data_buffer = GenerateData();
|
||||
// std::string r = HexEncode(data_buffer.data(), data_buffer.size());
|
||||
//
|
||||
// Mutable:
|
||||
// // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...);
|
||||
// char str_buffer[100];
|
||||
// SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14);
|
||||
//
|
||||
// With span:
|
||||
// Read-Only:
|
||||
// // std::string HexEncode(base::span<const uint8_t> data);
|
||||
// std::vector<uint8_t> data_buffer = GenerateData();
|
||||
// std::string r = HexEncode(data_buffer);
|
||||
//
|
||||
// Mutable:
|
||||
// // ssize_t SafeSNPrintf(base::span<char>, const char* fmt, Args...);
|
||||
// char str_buffer[100];
|
||||
// SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14);
|
||||
//
|
||||
// Spans with "const" and pointers
|
||||
// -------------------------------
|
||||
//
|
||||
// Const and pointers can get confusing. Here are vectors of pointers and their
|
||||
// corresponding spans:
|
||||
//
|
||||
// const std::vector<int*> => base::span<int* const>
|
||||
// std::vector<const int*> => base::span<const int*>
|
||||
// const std::vector<const int*> => base::span<const int* const>
|
||||
//
|
||||
// Differences from the C++20 draft
|
||||
// --------------------------------
|
||||
//
|
||||
// http://eel.is/c++draft/views contains the latest C++20 draft of std::span.
|
||||
// Chromium tries to follow the draft as close as possible. Differences between
|
||||
// the draft and the implementation are documented in subsections below.
|
||||
//
|
||||
// Differences from [span.objectrep]:
|
||||
// - as_bytes() and as_writable_bytes() return spans of uint8_t instead of
|
||||
// std::byte (std::byte is a C++17 feature)
|
||||
//
|
||||
// Differences from [span.cons]:
|
||||
// - Constructing a static span (i.e. Extent != dynamic_extent) from a dynamic
|
||||
// sized container (e.g. std::vector) requires an explicit conversion (in the
|
||||
// C++20 draft this is simply UB)
|
||||
//
|
||||
// Differences from [span.obs]:
|
||||
// - empty() is marked with WARN_UNUSED_RESULT instead of [[nodiscard]]
|
||||
// ([[nodiscard]] is a C++17 feature)
|
||||
//
|
||||
// Furthermore, all constructors and methods are marked noexcept due to the lack
|
||||
// of exceptions in Chromium.
|
||||
//
|
||||
// Due to the lack of class template argument deduction guides in C++14
|
||||
// appropriate make_span() utility functions are provided.
|
||||
|
||||
// [span], class template span
|
||||
template <typename T, size_t Extent>
|
||||
class span : public internal::ExtentStorage<Extent> {
|
||||
private:
|
||||
using ExtentStorage = internal::ExtentStorage<Extent>;
|
||||
|
||||
public:
|
||||
using element_type = T;
|
||||
using value_type = std::remove_cv_t<T>;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = T*;
|
||||
using reference = T&;
|
||||
using iterator = CheckedContiguousIterator<T>;
|
||||
using const_iterator = CheckedContiguousConstIterator<T>;
|
||||
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||
static constexpr size_t extent = Extent;
|
||||
|
||||
// [span.cons], span constructors, copy, assignment, and destructor
|
||||
constexpr span() noexcept : ExtentStorage(0), data_(nullptr) {
|
||||
static_assert(Extent == dynamic_extent || Extent == 0, "Invalid Extent");
|
||||
}
|
||||
|
||||
constexpr span(T* data, size_t size) noexcept
|
||||
: ExtentStorage(size), data_(data) {
|
||||
CHECK(Extent == dynamic_extent || Extent == size);
|
||||
}
|
||||
|
||||
// Artificially templatized to break ambiguity for span(ptr, 0).
|
||||
template <typename = void>
|
||||
constexpr span(T* begin, T* end) noexcept : span(begin, end - begin) {
|
||||
// Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
|
||||
CHECK(begin <= end);
|
||||
}
|
||||
|
||||
template <
|
||||
size_t N,
|
||||
typename = internal::EnableIfSpanCompatibleArray<T (&)[N], T, Extent>>
|
||||
constexpr span(T (&array)[N]) noexcept : span(base::data(array), N) {}
|
||||
|
||||
template <
|
||||
size_t N,
|
||||
typename = internal::
|
||||
EnableIfSpanCompatibleArray<std::array<value_type, N>&, T, Extent>>
|
||||
constexpr span(std::array<value_type, N>& array) noexcept
|
||||
: span(base::data(array), N) {}
|
||||
|
||||
template <size_t N,
|
||||
typename = internal::EnableIfSpanCompatibleArray<
|
||||
const std::array<value_type, N>&,
|
||||
T,
|
||||
Extent>>
|
||||
constexpr span(const std::array<value_type, N>& array) noexcept
|
||||
: span(base::data(array), N) {}
|
||||
|
||||
// Conversion from a container that has compatible base::data() and integral
|
||||
// base::size().
|
||||
template <
|
||||
typename Container,
|
||||
typename =
|
||||
internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<Container&,
|
||||
T,
|
||||
Extent>>
|
||||
constexpr span(Container& container) noexcept
|
||||
: span(base::data(container), base::size(container)) {}
|
||||
|
||||
template <
|
||||
typename Container,
|
||||
typename = internal::EnableIfSpanCompatibleContainerAndSpanIsDynamic<
|
||||
const Container&,
|
||||
T,
|
||||
Extent>>
|
||||
constexpr span(const Container& container) noexcept
|
||||
: span(base::data(container), base::size(container)) {}
|
||||
|
||||
constexpr span(const span& other) noexcept = default;
|
||||
|
||||
// Conversions from spans of compatible types and extents: this allows a
|
||||
// span<T> to be seamlessly used as a span<const T>, but not the other way
|
||||
// around. If extent is not dynamic, OtherExtent has to be equal to Extent.
|
||||
template <
|
||||
typename U,
|
||||
size_t OtherExtent,
|
||||
typename =
|
||||
internal::EnableIfLegalSpanConversion<U, OtherExtent, T, Extent>>
|
||||
constexpr span(const span<U, OtherExtent>& other)
|
||||
: span(other.data(), other.size()) {}
|
||||
|
||||
constexpr span& operator=(const span& other) noexcept = default;
|
||||
~span() noexcept = default;
|
||||
|
||||
// [span.sub], span subviews
|
||||
template <size_t Count>
|
||||
constexpr span<T, Count> first() const noexcept {
|
||||
static_assert(Extent == dynamic_extent || Count <= Extent,
|
||||
"Count must not exceed Extent");
|
||||
CHECK(Extent != dynamic_extent || Count <= size());
|
||||
return {data(), Count};
|
||||
}
|
||||
|
||||
template <size_t Count>
|
||||
constexpr span<T, Count> last() const noexcept {
|
||||
static_assert(Extent == dynamic_extent || Count <= Extent,
|
||||
"Count must not exceed Extent");
|
||||
CHECK(Extent != dynamic_extent || Count <= size());
|
||||
return {data() + (size() - Count), Count};
|
||||
}
|
||||
|
||||
template <size_t Offset, size_t Count = dynamic_extent>
|
||||
constexpr span<T,
|
||||
(Count != dynamic_extent
|
||||
? Count
|
||||
: (Extent != dynamic_extent ? Extent - Offset
|
||||
: dynamic_extent))>
|
||||
subspan() const noexcept {
|
||||
static_assert(Extent == dynamic_extent || Offset <= Extent,
|
||||
"Offset must not exceed Extent");
|
||||
static_assert(Extent == dynamic_extent || Count == dynamic_extent ||
|
||||
Count <= Extent - Offset,
|
||||
"Count must not exceed Extent - Offset");
|
||||
CHECK(Extent != dynamic_extent || Offset <= size());
|
||||
CHECK(Extent != dynamic_extent || Count == dynamic_extent ||
|
||||
Count <= size() - Offset);
|
||||
return {data() + Offset, Count != dynamic_extent ? Count : size() - Offset};
|
||||
}
|
||||
|
||||
constexpr span<T, dynamic_extent> first(size_t count) const noexcept {
|
||||
// Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
|
||||
CHECK(count <= size());
|
||||
return {data(), count};
|
||||
}
|
||||
|
||||
constexpr span<T, dynamic_extent> last(size_t count) const noexcept {
|
||||
// Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
|
||||
CHECK(count <= size());
|
||||
return {data() + (size() - count), count};
|
||||
}
|
||||
|
||||
constexpr span<T, dynamic_extent> subspan(size_t offset,
|
||||
size_t count = dynamic_extent) const
|
||||
noexcept {
|
||||
// Note: CHECK_LE is not constexpr, hence regular CHECK must be used.
|
||||
CHECK(offset <= size());
|
||||
CHECK(count == dynamic_extent || count <= size() - offset);
|
||||
return {data() + offset, count != dynamic_extent ? count : size() - offset};
|
||||
}
|
||||
|
||||
// [span.obs], span observers
|
||||
constexpr size_t size() const noexcept { return ExtentStorage::size(); }
|
||||
constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
|
||||
constexpr bool empty() const noexcept WARN_UNUSED_RESULT {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
// [span.elem], span element access
|
||||
constexpr T& operator[](size_t idx) const noexcept {
|
||||
// Note: CHECK_LT is not constexpr, hence regular CHECK must be used.
|
||||
CHECK(idx < size());
|
||||
return *(data() + idx);
|
||||
}
|
||||
|
||||
constexpr T& front() const noexcept {
|
||||
static_assert(Extent == dynamic_extent || Extent > 0,
|
||||
"Extent must not be 0");
|
||||
CHECK(Extent != dynamic_extent || !empty());
|
||||
return *data();
|
||||
}
|
||||
|
||||
constexpr T& back() const noexcept {
|
||||
static_assert(Extent == dynamic_extent || Extent > 0,
|
||||
"Extent must not be 0");
|
||||
CHECK(Extent != dynamic_extent || !empty());
|
||||
return *(data() + size() - 1);
|
||||
}
|
||||
|
||||
constexpr T* data() const noexcept { return data_; }
|
||||
|
||||
// [span.iter], span iterator support
|
||||
constexpr iterator begin() const noexcept {
|
||||
return iterator(data_, data_ + size());
|
||||
}
|
||||
constexpr iterator end() const noexcept {
|
||||
return iterator(data_, data_ + size(), data_ + size());
|
||||
}
|
||||
|
||||
constexpr const_iterator cbegin() const noexcept { return begin(); }
|
||||
constexpr const_iterator cend() const noexcept { return end(); }
|
||||
|
||||
constexpr reverse_iterator rbegin() const noexcept {
|
||||
return reverse_iterator(end());
|
||||
}
|
||||
constexpr reverse_iterator rend() const noexcept {
|
||||
return reverse_iterator(begin());
|
||||
}
|
||||
|
||||
constexpr const_reverse_iterator crbegin() const noexcept {
|
||||
return const_reverse_iterator(cend());
|
||||
}
|
||||
constexpr const_reverse_iterator crend() const noexcept {
|
||||
return const_reverse_iterator(cbegin());
|
||||
}
|
||||
|
||||
private:
|
||||
T* data_;
|
||||
};
|
||||
|
||||
// span<T, Extent>::extent can not be declared inline prior to C++17, hence this
|
||||
// definition is required.
|
||||
template <class T, size_t Extent>
|
||||
constexpr size_t span<T, Extent>::extent;
|
||||
|
||||
// [span.objectrep], views of object representation
|
||||
template <typename T, size_t X>
|
||||
span<const uint8_t, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)>
|
||||
as_bytes(span<T, X> s) noexcept {
|
||||
return {reinterpret_cast<const uint8_t*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
size_t X,
|
||||
typename = std::enable_if_t<!std::is_const<T>::value>>
|
||||
span<uint8_t, (X == dynamic_extent ? dynamic_extent : sizeof(T) * X)>
|
||||
as_writable_bytes(span<T, X> s) noexcept {
|
||||
return {reinterpret_cast<uint8_t*>(s.data()), s.size_bytes()};
|
||||
}
|
||||
|
||||
// Type-deducing helpers for constructing a span.
|
||||
template <int&... ExplicitArgumentBarrier, typename T>
|
||||
constexpr span<T> make_span(T* data, size_t size) noexcept {
|
||||
return {data, size};
|
||||
}
|
||||
|
||||
template <int&... ExplicitArgumentBarrier, typename T>
|
||||
constexpr span<T> make_span(T* begin, T* end) noexcept {
|
||||
return {begin, end};
|
||||
}
|
||||
|
||||
// make_span utility function that deduces both the span's value_type and extent
|
||||
// from the passed in argument.
|
||||
//
|
||||
// Usage: auto span = base::make_span(...);
|
||||
template <int&... ExplicitArgumentBarrier, typename Container>
|
||||
constexpr auto make_span(Container&& container) noexcept {
|
||||
using T =
|
||||
std::remove_pointer_t<decltype(base::data(std::declval<Container>()))>;
|
||||
using Extent = internal::Extent<Container>;
|
||||
return span<T, Extent::value>(std::forward<Container>(container));
|
||||
}
|
||||
|
||||
// make_span utility function that allows callers to explicit specify the span's
|
||||
// extent, the value_type is deduced automatically. This is useful when passing
|
||||
// a dynamically sized container to a method expecting static spans, when the
|
||||
// container is known to have the correct size.
|
||||
//
|
||||
// Note: This will CHECK that N indeed matches size(container).
|
||||
//
|
||||
// Usage: auto static_span = base::make_span<N>(...);
|
||||
template <size_t N, int&... ExplicitArgumentBarrier, typename Container>
|
||||
constexpr auto make_span(Container&& container) noexcept {
|
||||
using T =
|
||||
std::remove_pointer_t<decltype(base::data(std::declval<Container>()))>;
|
||||
return span<T, N>(base::data(container), base::size(container));
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
// Note: std::tuple_size, std::tuple_element and std::get are specialized for
|
||||
// static spans, so that they can be used in C++17's structured bindings. While
|
||||
// we don't support C++17 yet, there is no harm in providing these
|
||||
// specializations already.
|
||||
namespace std {
|
||||
|
||||
// [span.tuple], tuple interface
|
||||
#if defined(__clang__)
|
||||
// Due to https://llvm.org/PR39871 and https://llvm.org/PR41331 and their
|
||||
// respective fixes different versions of libc++ declare std::tuple_size and
|
||||
// std::tuple_element either as classes or structs. In order to be able to
|
||||
// specialize std::tuple_size and std::tuple_element for custom base types we
|
||||
// thus need to disable -Wmismatched-tags in order to support all build
|
||||
// configurations. Note that this is blessed by the standard in
|
||||
// https://timsong-cpp.github.io/cppwp/n4140/dcl.type.elab#3.
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
template <typename T, size_t X>
|
||||
struct tuple_size<base::span<T, X>> : public integral_constant<size_t, X> {};
|
||||
|
||||
template <typename T>
|
||||
struct tuple_size<base::span<T, base::dynamic_extent>>; // not defined
|
||||
|
||||
template <size_t I, typename T, size_t X>
|
||||
struct tuple_element<I, base::span<T, X>> {
|
||||
static_assert(
|
||||
base::dynamic_extent != X,
|
||||
"std::tuple_element<> not supported for base::span<T, dynamic_extent>");
|
||||
static_assert(I < X,
|
||||
"Index out of bounds in std::tuple_element<> (base::span)");
|
||||
using type = T;
|
||||
};
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop // -Wmismatched-tags
|
||||
#endif
|
||||
|
||||
template <size_t I, typename T, size_t X>
|
||||
constexpr T& get(base::span<T, X> s) noexcept {
|
||||
static_assert(base::dynamic_extent != X,
|
||||
"std::get<> not supported for base::span<T, dynamic_extent>");
|
||||
static_assert(I < X, "Index out of bounds in std::get<> (base::span)");
|
||||
return s[I];
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // BASE_CONTAINERS_SPAN_H_
|
|
@ -13,6 +13,7 @@
|
|||
#include <utility>
|
||||
|
||||
#include "base/stl_util.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
|
||||
#include "base/files/file_util.h"
|
||||
|
@ -27,44 +28,6 @@
|
|||
|
||||
namespace base {
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
namespace internal {
|
||||
|
||||
std::tuple<int, int, int, int> ComputeX86FamilyAndModel(
|
||||
const std::string& vendor,
|
||||
int signature) {
|
||||
int family = (signature >> 8) & 0xf;
|
||||
int model = (signature >> 4) & 0xf;
|
||||
int ext_family = 0;
|
||||
int ext_model = 0;
|
||||
|
||||
// The "Intel 64 and IA-32 Architectures Developer's Manual: Vol. 2A"
|
||||
// specifies the Extended Model is defined only when the Base Family is
|
||||
// 06h or 0Fh.
|
||||
// The "AMD CPUID Specification" specifies that the Extended Model is
|
||||
// defined only when Base Family is 0Fh.
|
||||
// Both manuals define the display model as
|
||||
// {ExtendedModel[3:0],BaseModel[3:0]} in that case.
|
||||
if (family == 0xf || (family == 0x6 && vendor == "GenuineIntel")) {
|
||||
ext_model = (signature >> 16) & 0xf;
|
||||
model += ext_model << 4;
|
||||
}
|
||||
// Both the "Intel 64 and IA-32 Architectures Developer's Manual: Vol. 2A"
|
||||
// and the "AMD CPUID Specification" specify that the Extended Family is
|
||||
// defined only when the Base Family is 0Fh.
|
||||
// Both manuals define the display family as {0000b,BaseFamily[3:0]} +
|
||||
// ExtendedFamily[7:0] in that case.
|
||||
if (family == 0xf) {
|
||||
ext_family = (signature >> 20) & 0xff;
|
||||
family += ext_family;
|
||||
}
|
||||
|
||||
return {family, model, ext_family, ext_model};
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
#endif // defined(ARCH_CPU_X86_FAMILY)
|
||||
|
||||
CPU::CPU()
|
||||
: signature_(0),
|
||||
type_(0),
|
||||
|
@ -85,7 +48,6 @@ CPU::CPU()
|
|||
has_avx2_(false),
|
||||
has_aesni_(false),
|
||||
has_non_stop_time_stamp_counter_(false),
|
||||
is_running_in_vm_(false),
|
||||
cpu_vendor_("unknown") {
|
||||
Initialize();
|
||||
}
|
||||
|
@ -194,6 +156,7 @@ void CPU::Initialize() {
|
|||
memcpy(cpu_string, &cpu_info[1], kVendorNameSize);
|
||||
cpu_string[kVendorNameSize] = '\0';
|
||||
cpu_vendor_ = cpu_string;
|
||||
bool hypervisor = false;
|
||||
|
||||
// Interpret CPU feature information.
|
||||
if (num_ids > 0) {
|
||||
|
@ -204,9 +167,11 @@ void CPU::Initialize() {
|
|||
}
|
||||
signature_ = cpu_info[0];
|
||||
stepping_ = cpu_info[0] & 0xf;
|
||||
model_ = ((cpu_info[0] >> 4) & 0xf) + ((cpu_info[0] >> 12) & 0xf0);
|
||||
family_ = (cpu_info[0] >> 8) & 0xf;
|
||||
type_ = (cpu_info[0] >> 12) & 0x3;
|
||||
std::tie(family_, model_, ext_family_, ext_model_) =
|
||||
internal::ComputeX86FamilyAndModel(cpu_vendor_, signature_);
|
||||
ext_model_ = (cpu_info[0] >> 16) & 0xf;
|
||||
ext_family_ = (cpu_info[0] >> 20) & 0xff;
|
||||
has_mmx_ = (cpu_info[3] & 0x00800000) != 0;
|
||||
has_sse_ = (cpu_info[3] & 0x02000000) != 0;
|
||||
has_sse2_ = (cpu_info[3] & 0x04000000) != 0;
|
||||
|
@ -221,7 +186,7 @@ void CPU::Initialize() {
|
|||
// This is checking for any hypervisor. Hypervisors may choose not to
|
||||
// announce themselves. Hypervisors trap CPUID and sometimes return
|
||||
// different results to underlying hardware.
|
||||
is_running_in_vm_ = (cpu_info[2] & 0x80000000) != 0;
|
||||
hypervisor = (cpu_info[2] & 0x80000000) != 0;
|
||||
|
||||
// AVX instructions will generate an illegal instruction exception unless
|
||||
// a) they are supported by the CPU,
|
||||
|
@ -270,7 +235,7 @@ void CPU::Initialize() {
|
|||
has_non_stop_time_stamp_counter_ = (cpu_info[3] & (1 << 8)) != 0;
|
||||
}
|
||||
|
||||
if (!has_non_stop_time_stamp_counter_ && is_running_in_vm_) {
|
||||
if (!has_non_stop_time_stamp_counter_ && hypervisor) {
|
||||
int cpu_info_hv[4] = {};
|
||||
__cpuid(cpu_info_hv, 0x40000000);
|
||||
if (cpu_info_hv[1] == 0x7263694D && // Micr
|
||||
|
@ -286,14 +251,8 @@ void CPU::Initialize() {
|
|||
has_non_stop_time_stamp_counter_ = true;
|
||||
}
|
||||
}
|
||||
#elif defined(ARCH_CPU_ARM_FAMILY)
|
||||
#if (defined(OS_ANDROID) || defined(OS_LINUX))
|
||||
#elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
|
||||
cpu_brand_ = *CpuInfoBrand();
|
||||
#elif defined(OS_WIN)
|
||||
// Windows makes high-resolution thread timing information available in
|
||||
// user-space.
|
||||
has_non_stop_time_stamp_counter_ = true;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -6,25 +6,11 @@
|
|||
#define BASE_CPU_H_
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
namespace internal {
|
||||
|
||||
// Compute the CPU family and model based on the vendor and CPUID signature.
|
||||
// Returns in order: family, model, extended family, extended model.
|
||||
BASE_EXPORT std::tuple<int, int, int, int> ComputeX86FamilyAndModel(
|
||||
const std::string& vendor,
|
||||
int signature);
|
||||
|
||||
} // namespace internal
|
||||
#endif // defined(ARCH_CPU_X86_FAMILY)
|
||||
|
||||
// Query information about the processor.
|
||||
class BASE_EXPORT CPU final {
|
||||
public:
|
||||
|
@ -66,7 +52,6 @@ class BASE_EXPORT CPU final {
|
|||
bool has_non_stop_time_stamp_counter() const {
|
||||
return has_non_stop_time_stamp_counter_;
|
||||
}
|
||||
bool is_running_in_vm() const { return is_running_in_vm_; }
|
||||
|
||||
IntelMicroArchitecture GetIntelMicroArchitecture() const;
|
||||
const std::string& cpu_brand() const { return cpu_brand_; }
|
||||
|
@ -94,7 +79,6 @@ class BASE_EXPORT CPU final {
|
|||
bool has_avx2_;
|
||||
bool has_aesni_;
|
||||
bool has_non_stop_time_stamp_counter_;
|
||||
bool is_running_in_vm_;
|
||||
std::string cpu_vendor_;
|
||||
std::string cpu_brand_;
|
||||
};
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_DEBUG_CRASH_LOGGING_H_
|
||||
#define BASE_DEBUG_CRASH_LOGGING_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
namespace base {
|
||||
namespace debug {
|
||||
|
||||
// A crash key is an annotation that is carried along with a crash report, to
|
||||
// provide additional debugging information beyond a stack trace. Crash keys
|
||||
// have a name and a string value.
|
||||
//
|
||||
// The preferred API is //components/crash/core/common:crash_key, however not
|
||||
// all clients can hold a direct dependency on that target. The API provided
|
||||
// in this file indirects the dependency.
|
||||
//
|
||||
// Example usage:
|
||||
// static CrashKeyString* crash_key =
|
||||
// AllocateCrashKeyString("name", CrashKeySize::Size32);
|
||||
// SetCrashKeyString(crash_key, "value");
|
||||
// ClearCrashKeyString(crash_key);
|
||||
|
||||
// The maximum length for a crash key's value must be one of the following
|
||||
// pre-determined values.
|
||||
enum class CrashKeySize {
|
||||
Size32 = 32,
|
||||
Size64 = 64,
|
||||
Size256 = 256,
|
||||
};
|
||||
|
||||
struct CrashKeyString;
|
||||
|
||||
// Allocates a new crash key with the specified |name| with storage for a
|
||||
// value up to length |size|. This will return null if the crash key system is
|
||||
// not initialized.
|
||||
BASE_EXPORT CrashKeyString* AllocateCrashKeyString(const char name[],
|
||||
CrashKeySize size);
|
||||
|
||||
// Stores |value| into the specified |crash_key|. The |crash_key| may be null
|
||||
// if AllocateCrashKeyString() returned null. If |value| is longer than the
|
||||
// size with which the key was allocated, it will be truncated.
|
||||
BASE_EXPORT void SetCrashKeyString(CrashKeyString* crash_key,
|
||||
base::StringPiece value);
|
||||
|
||||
// Clears any value that was stored in |crash_key|. The |crash_key| may be
|
||||
// null.
|
||||
BASE_EXPORT void ClearCrashKeyString(CrashKeyString* crash_key);
|
||||
|
||||
// A scoper that sets the specified key to value for the lifetime of the
|
||||
// object, and clears it on destruction.
|
||||
class BASE_EXPORT ScopedCrashKeyString {
|
||||
public:
|
||||
ScopedCrashKeyString(CrashKeyString* crash_key, base::StringPiece value);
|
||||
~ScopedCrashKeyString();
|
||||
|
||||
private:
|
||||
CrashKeyString* const crash_key_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedCrashKeyString);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// The following declarations are used to initialize the crash key system
|
||||
// in //base by providing implementations for the above functions.
|
||||
|
||||
// The virtual interface that provides the implementation for the crash key
|
||||
// API. This is implemented by a higher-layer component, and the instance is
|
||||
// set using the function below.
|
||||
class CrashKeyImplementation {
|
||||
public:
|
||||
virtual ~CrashKeyImplementation() = default;
|
||||
|
||||
virtual CrashKeyString* Allocate(const char name[], CrashKeySize size) = 0;
|
||||
virtual void Set(CrashKeyString* crash_key, base::StringPiece value) = 0;
|
||||
virtual void Clear(CrashKeyString* crash_key) = 0;
|
||||
};
|
||||
|
||||
// Initializes the crash key system in base by replacing the existing
|
||||
// implementation, if it exists, with |impl|. The |impl| is copied into base.
|
||||
BASE_EXPORT void SetCrashKeyImplementation(
|
||||
std::unique_ptr<CrashKeyImplementation> impl);
|
||||
|
||||
// The base structure for a crash key, storing the allocation metadata.
|
||||
struct CrashKeyString {
|
||||
constexpr CrashKeyString(const char name[], CrashKeySize size)
|
||||
: name(name), size(size) {}
|
||||
const char* const name;
|
||||
const CrashKeySize size;
|
||||
};
|
||||
|
||||
} // namespace debug
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_DEBUG_CRASH_LOGGING_H_
|
|
@ -38,12 +38,6 @@ BASE_EXPORT void BreakDebugger();
|
|||
BASE_EXPORT void SetSuppressDebugUI(bool suppress);
|
||||
BASE_EXPORT bool IsDebugUISuppressed();
|
||||
|
||||
// If a debugger is present, verifies that it is properly set up, and DCHECK()s
|
||||
// if misconfigured. Currently only verifies that //tools/gdb/gdbinit has been
|
||||
// sourced when using gdb on Linux and //tools/lldb/lldbinit.py has been sourced
|
||||
// when using lldb on macOS.
|
||||
BASE_EXPORT void VerifyDebugger();
|
||||
|
||||
} // namespace debug
|
||||
} // namespace base
|
||||
|
||||
|
|
|
@ -19,23 +19,29 @@
|
|||
#endif // defined(OS_WIN)
|
||||
|
||||
// TODO(peria): Enable profiling on Windows.
|
||||
#if BUILDFLAG(ENABLE_PROFILING) && BUILDFLAG(USE_TCMALLOC) && !defined(OS_WIN)
|
||||
#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
|
||||
#if BUILDFLAG(USE_NEW_TCMALLOC)
|
||||
#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
|
||||
#else
|
||||
#include "third_party/tcmalloc/gperftools-2.0/chromium/src/gperftools/profiler.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace debug {
|
||||
|
||||
// TODO(peria): Enable profiling on Windows.
|
||||
#if BUILDFLAG(ENABLE_PROFILING) && BUILDFLAG(USE_TCMALLOC) && !defined(OS_WIN)
|
||||
#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
|
||||
|
||||
static int profile_count = 0;
|
||||
|
||||
void StartProfiling(const std::string& name) {
|
||||
++profile_count;
|
||||
std::string full_name(name);
|
||||
std::string pid = NumberToString(GetCurrentProcId());
|
||||
std::string count = NumberToString(profile_count);
|
||||
std::string pid = IntToString(GetCurrentProcId());
|
||||
std::string count = IntToString(profile_count);
|
||||
ReplaceSubstringsAfterOffset(&full_name, 0, "{pid}", pid);
|
||||
ReplaceSubstringsAfterOffset(&full_name, 0, "{count}", count);
|
||||
ProfilerStart(full_name.c_str());
|
||||
|
@ -152,7 +158,7 @@ FunctionType FindFunctionInImports(const char* function_name) {
|
|||
base::win::PEImage image(CURRENT_MODULE());
|
||||
|
||||
FunctionSearchContext ctx = { function_name, NULL };
|
||||
image.EnumImportChunks(FindResolutionFunctionInImports, &ctx, nullptr);
|
||||
image.EnumImportChunks(FindResolutionFunctionInImports, &ctx);
|
||||
|
||||
return reinterpret_cast<FunctionType>(ctx.function);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
|
||||
#include "base/environment.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/strings/string_util.h"
|
||||
|
@ -97,6 +101,23 @@ class EnvironmentImpl : public Environment {
|
|||
}
|
||||
};
|
||||
|
||||
// Parses a null-terminated input string of an environment block. The key is
|
||||
// placed into the given string, and the total length of the line, including
|
||||
// the terminating null, is returned.
|
||||
size_t ParseEnvLine(const NativeEnvironmentString::value_type* input,
|
||||
NativeEnvironmentString* key) {
|
||||
// Skip to the equals or end of the string, this is the key.
|
||||
size_t cur = 0;
|
||||
while (input[cur] && input[cur] != '=')
|
||||
cur++;
|
||||
*key = NativeEnvironmentString(&input[0], cur);
|
||||
|
||||
// Now just skip to the end of the string.
|
||||
while (input[cur])
|
||||
cur++;
|
||||
return cur + 1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace env_vars {
|
||||
|
@ -120,4 +141,97 @@ bool Environment::HasVar(StringPiece variable_name) {
|
|||
return GetVar(variable_name, nullptr);
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
|
||||
string16 AlterEnvironment(const wchar_t* env,
|
||||
const EnvironmentMap& changes) {
|
||||
string16 result;
|
||||
|
||||
// First copy all unmodified values to the output.
|
||||
size_t cur_env = 0;
|
||||
string16 key;
|
||||
while (env[cur_env]) {
|
||||
const wchar_t* line = &env[cur_env];
|
||||
size_t line_length = ParseEnvLine(line, &key);
|
||||
|
||||
// Keep only values not specified in the change vector.
|
||||
EnvironmentMap::const_iterator found_change = changes.find(key);
|
||||
if (found_change == changes.end())
|
||||
result.append(line, line_length);
|
||||
|
||||
cur_env += line_length;
|
||||
}
|
||||
|
||||
// Now append all modified and new values.
|
||||
for (EnvironmentMap::const_iterator i = changes.begin();
|
||||
i != changes.end(); ++i) {
|
||||
if (!i->second.empty()) {
|
||||
result.append(i->first);
|
||||
result.push_back('=');
|
||||
result.append(i->second);
|
||||
result.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
// An additional null marks the end of the list. We always need a double-null
|
||||
// in case nothing was added above.
|
||||
if (result.empty())
|
||||
result.push_back(0);
|
||||
result.push_back(0);
|
||||
return result;
|
||||
}
|
||||
|
||||
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
|
||||
std::unique_ptr<char* []> AlterEnvironment(const char* const* const env,
|
||||
const EnvironmentMap& changes) {
|
||||
std::string value_storage; // Holds concatenated null-terminated strings.
|
||||
std::vector<size_t> result_indices; // Line indices into value_storage.
|
||||
|
||||
// First build up all of the unchanged environment strings. These are
|
||||
// null-terminated of the form "key=value".
|
||||
std::string key;
|
||||
for (size_t i = 0; env[i]; i++) {
|
||||
size_t line_length = ParseEnvLine(env[i], &key);
|
||||
|
||||
// Keep only values not specified in the change vector.
|
||||
auto found_change = changes.find(key);
|
||||
if (found_change == changes.end()) {
|
||||
result_indices.push_back(value_storage.size());
|
||||
value_storage.append(env[i], line_length);
|
||||
}
|
||||
}
|
||||
|
||||
// Now append all modified and new values.
|
||||
for (const auto& i : changes) {
|
||||
if (!i.second.empty()) {
|
||||
result_indices.push_back(value_storage.size());
|
||||
value_storage.append(i.first);
|
||||
value_storage.push_back('=');
|
||||
value_storage.append(i.second);
|
||||
value_storage.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
size_t pointer_count_required =
|
||||
result_indices.size() + 1 + // Null-terminated array of pointers.
|
||||
(value_storage.size() + sizeof(char*) - 1) / sizeof(char*); // Buffer.
|
||||
std::unique_ptr<char* []> result(new char*[pointer_count_required]);
|
||||
|
||||
// The string storage goes after the array of pointers.
|
||||
char* storage_data = reinterpret_cast<char*>(
|
||||
&result.get()[result_indices.size() + 1]);
|
||||
if (!value_storage.empty())
|
||||
memcpy(storage_data, value_storage.data(), value_storage.size());
|
||||
|
||||
// Fill array of pointers at the beginning of the result.
|
||||
for (size_t i = 0; i < result_indices.size(); i++)
|
||||
result[i] = &storage_data[result_indices[i]];
|
||||
result[result_indices.size()] = 0; // Null terminator.
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // OS_POSIX || OS_FUCHSIA
|
||||
|
||||
} // namespace base
|
||||
|
|
|
@ -38,23 +38,52 @@ class BASE_EXPORT Environment {
|
|||
// Syntactic sugar for GetVar(variable_name, nullptr);
|
||||
virtual bool HasVar(StringPiece variable_name);
|
||||
|
||||
// Returns true on success, otherwise returns false. This method should not
|
||||
// be called in a multi-threaded process.
|
||||
// Returns true on success, otherwise returns false.
|
||||
virtual bool SetVar(StringPiece variable_name,
|
||||
const std::string& new_value) = 0;
|
||||
|
||||
// Returns true on success, otherwise returns false. This method should not
|
||||
// be called in a multi-threaded process.
|
||||
// Returns true on success, otherwise returns false.
|
||||
virtual bool UnSetVar(StringPiece variable_name) = 0;
|
||||
};
|
||||
|
||||
|
||||
#if defined(OS_WIN)
|
||||
using NativeEnvironmentString = std::wstring;
|
||||
|
||||
typedef string16 NativeEnvironmentString;
|
||||
typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
|
||||
EnvironmentMap;
|
||||
|
||||
// Returns a modified environment vector constructed from the given environment
|
||||
// and the list of changes given in |changes|. Each key in the environment is
|
||||
// matched against the first element of the pairs. In the event of a match, the
|
||||
// value is replaced by the second of the pair, unless the second is empty, in
|
||||
// which case the key-value is removed.
|
||||
//
|
||||
// This Windows version takes and returns a Windows-style environment block
|
||||
// which is a concatenated list of null-terminated 16-bit strings. The end is
|
||||
// marked by a double-null terminator. The size of the returned string will
|
||||
// include the terminators.
|
||||
BASE_EXPORT string16 AlterEnvironment(const wchar_t* env,
|
||||
const EnvironmentMap& changes);
|
||||
|
||||
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
using NativeEnvironmentString = std::string;
|
||||
|
||||
typedef std::string NativeEnvironmentString;
|
||||
typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
|
||||
EnvironmentMap;
|
||||
|
||||
// See general comments for the Windows version above.
|
||||
//
|
||||
// This Posix version takes and returns a Posix-style environment block, which
|
||||
// is a null-terminated list of pointers to null-terminated strings. The
|
||||
// returned array will have appended to it the storage for the array itself so
|
||||
// there is only one pointer to manage, but this means that you can't copy the
|
||||
// array without keeping the original around.
|
||||
BASE_EXPORT std::unique_ptr<char* []> AlterEnvironment(
|
||||
const char* const* env,
|
||||
const EnvironmentMap& changes);
|
||||
|
||||
#endif
|
||||
using EnvironmentMap =
|
||||
std::map<NativeEnvironmentString, NativeEnvironmentString>;
|
||||
|
||||
} // namespace base
|
||||
|
||||
|
|
|
@ -104,7 +104,6 @@
|
|||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -153,7 +152,7 @@ class BASE_EXPORT FilePath {
|
|||
#if defined(OS_WIN)
|
||||
// On Windows, for Unicode-aware applications, native pathnames are wchar_t
|
||||
// arrays encoded in UTF-16.
|
||||
typedef std::wstring StringType;
|
||||
typedef base::string16 StringType;
|
||||
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
// On most platforms, native pathnames are char arrays, and the encoding
|
||||
// may or may not be specified. On Mac OS X, native pathnames are encoded
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright 2013 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/stl_util.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
#if defined(FILE_PATH_USES_WIN_SEPARATORS)
|
||||
const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/");
|
||||
#else // FILE_PATH_USES_WIN_SEPARATORS
|
||||
const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/");
|
||||
#endif // FILE_PATH_USES_WIN_SEPARATORS
|
||||
|
||||
const size_t FilePath::kSeparatorsLength = base::size(kSeparators);
|
||||
|
||||
const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL(".");
|
||||
const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
|
||||
|
||||
const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.');
|
||||
|
||||
} // namespace base
|
|
@ -2,11 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/hash/hash.h"
|
||||
|
||||
#include "base/rand_util.h"
|
||||
#include "base/third_party/cityhash/city.h"
|
||||
#include "build/build_config.h"
|
||||
#include "base/hash.h"
|
||||
|
||||
// Definition in base/third_party/superfasthash/superfasthash.c. (Third-party
|
||||
// code did not come with its own header file, so declaring the function here.)
|
||||
|
@ -15,18 +11,34 @@ extern "C" uint32_t SuperFastHash(const char* data, int len);
|
|||
|
||||
namespace base {
|
||||
|
||||
namespace {
|
||||
uint32_t Hash(const void* data, size_t length) {
|
||||
// Currently our in-memory hash is the same as the persistent hash. The
|
||||
// split between in-memory and persistent hash functions is maintained to
|
||||
// allow the in-memory hash function to be updated in the future.
|
||||
return PersistentHash(data, length);
|
||||
}
|
||||
|
||||
size_t FastHashImpl(base::span<const uint8_t> data) {
|
||||
// We use the updated CityHash within our namespace (not the deprecated
|
||||
// version from third_party/smhasher).
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
return base::internal::cityhash_v111::CityHash64(
|
||||
reinterpret_cast<const char*>(data.data()), data.size());
|
||||
#else
|
||||
return base::internal::cityhash_v111::CityHash32(
|
||||
reinterpret_cast<const char*>(data.data()), data.size());
|
||||
#endif
|
||||
uint32_t Hash(const std::string& str) {
|
||||
return PersistentHash(str.data(), str.size());
|
||||
}
|
||||
|
||||
uint32_t Hash(const string16& str) {
|
||||
return PersistentHash(str.data(), str.size() * sizeof(char16));
|
||||
}
|
||||
|
||||
uint32_t PersistentHash(const void* data, size_t length) {
|
||||
// This hash function must not change, since it is designed to be persistable
|
||||
// to disk.
|
||||
if (length > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
NOTREACHED();
|
||||
return 0;
|
||||
}
|
||||
return ::SuperFastHash(reinterpret_cast<const char*>(data),
|
||||
static_cast<int>(length));
|
||||
}
|
||||
|
||||
uint32_t PersistentHash(const std::string& str) {
|
||||
return PersistentHash(str.data(), str.size());
|
||||
}
|
||||
|
||||
// Implement hashing for pairs of at-most 32 bit integer values.
|
||||
|
@ -38,7 +50,7 @@ size_t FastHashImpl(base::span<const uint8_t> data) {
|
|||
// h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32
|
||||
//
|
||||
// Contact danakj@chromium.org for any questions.
|
||||
size_t HashInts32Impl(uint32_t value1, uint32_t value2) {
|
||||
size_t HashInts32(uint32_t value1, uint32_t value2) {
|
||||
uint64_t value1_64 = value1;
|
||||
uint64_t hash64 = (value1_64 << 32) | value2;
|
||||
|
||||
|
@ -59,7 +71,7 @@ size_t HashInts32Impl(uint32_t value1, uint32_t value2) {
|
|||
// breaking the two 64-bit inputs into 4 32-bit values:
|
||||
// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
|
||||
// Then we reduce our result to 32 bits if required, similar to above.
|
||||
size_t HashInts64Impl(uint64_t value1, uint64_t value2) {
|
||||
size_t HashInts64(uint64_t value1, uint64_t value2) {
|
||||
uint32_t short_random1 = 842304669U;
|
||||
uint32_t short_random2 = 619063811U;
|
||||
uint32_t short_random3 = 937041849U;
|
||||
|
@ -89,79 +101,4 @@ size_t HashInts64Impl(uint64_t value1, uint64_t value2) {
|
|||
return high_bits;
|
||||
}
|
||||
|
||||
// The random seed is used to perturb the output of base::FastHash() and
|
||||
// base::HashInts() so that it is only deterministic within the lifetime of a
|
||||
// process. This prevents inadvertent dependencies on the underlying
|
||||
// implementation, e.g. anything that persists the hash value and expects it to
|
||||
// be unchanging will break.
|
||||
//
|
||||
// Note: this is the same trick absl uses to generate a random seed. This is
|
||||
// more robust than using base::RandBytes(), which can fail inside a sandboxed
|
||||
// environment. Note that without ASLR, the seed won't be quite as random...
|
||||
#if DCHECK_IS_ON()
|
||||
constexpr const void* kSeed = &kSeed;
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
T Scramble(T input) {
|
||||
#if DCHECK_IS_ON()
|
||||
return HashInts64Impl(input, reinterpret_cast<uintptr_t>(kSeed));
|
||||
#else
|
||||
return input;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
size_t FastHash(base::span<const uint8_t> data) {
|
||||
return Scramble(FastHashImpl(data));
|
||||
}
|
||||
|
||||
uint32_t Hash(const void* data, size_t length) {
|
||||
// Currently our in-memory hash is the same as the persistent hash. The
|
||||
// split between in-memory and persistent hash functions is maintained to
|
||||
// allow the in-memory hash function to be updated in the future.
|
||||
return PersistentHash(data, length);
|
||||
}
|
||||
|
||||
uint32_t Hash(const std::string& str) {
|
||||
return PersistentHash(as_bytes(make_span(str)));
|
||||
}
|
||||
|
||||
uint32_t Hash(const string16& str) {
|
||||
return PersistentHash(as_bytes(make_span(str)));
|
||||
}
|
||||
|
||||
uint32_t PersistentHash(span<const uint8_t> data) {
|
||||
// This hash function must not change, since it is designed to be persistable
|
||||
// to disk.
|
||||
if (data.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
NOTREACHED();
|
||||
return 0;
|
||||
}
|
||||
return ::SuperFastHash(reinterpret_cast<const char*>(data.data()),
|
||||
static_cast<int>(data.size()));
|
||||
}
|
||||
|
||||
uint32_t PersistentHash(const void* data, size_t length) {
|
||||
return PersistentHash(make_span(static_cast<const uint8_t*>(data), length));
|
||||
}
|
||||
|
||||
uint32_t PersistentHash(const std::string& str) {
|
||||
return PersistentHash(str.data(), str.size());
|
||||
}
|
||||
|
||||
size_t HashInts32(uint32_t value1, uint32_t value2) {
|
||||
return Scramble(HashInts32Impl(value1, value2));
|
||||
}
|
||||
|
||||
// Implement hashing for pairs of up-to 64-bit integer values.
|
||||
// We use the compound integer hash method to produce a 64-bit hash code, by
|
||||
// breaking the two 64-bit inputs into 4 32-bit values:
|
||||
// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
|
||||
// Then we reduce our result to 32 bits if required, similar to above.
|
||||
size_t HashInts64(uint64_t value1, uint64_t value2) {
|
||||
return Scramble(HashInts64Impl(value1, value2));
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -2,8 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_HASH_HASH_H_
|
||||
#define BASE_HASH_HASH_H_
|
||||
#ifndef BASE_HASH_H_
|
||||
#define BASE_HASH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
@ -13,42 +13,26 @@
|
|||
#include <utility>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
// WARNING: This hash functions should not be used for any cryptographic
|
||||
// purpose.
|
||||
|
||||
// Deprecated: Computes a hash of a memory buffer, use FastHash() instead.
|
||||
// If you need to persist a change on disk or between computers, use
|
||||
// PersistentHash().
|
||||
// TODO(https://crbug.com/1025358): Migrate client code to new hash function.
|
||||
// Computes a hash of a memory buffer. This hash function is subject to change
|
||||
// in the future, so use only for temporary in-memory structures. If you need
|
||||
// to persist a change on disk or between computers, use PersistentHash().
|
||||
//
|
||||
// WARNING: This hash function should not be used for any cryptographic purpose.
|
||||
BASE_EXPORT uint32_t Hash(const void* data, size_t length);
|
||||
BASE_EXPORT uint32_t Hash(const std::string& str);
|
||||
BASE_EXPORT uint32_t Hash(const string16& str);
|
||||
|
||||
// Really *fast* and high quality hash.
|
||||
// Recommended hash function for general use, we pick the best performant
|
||||
// hash for each build target.
|
||||
// It is prone to be updated whenever a newer/faster hash function is
|
||||
// publicly available.
|
||||
// May changed without warning, do not expect stability of outputs.
|
||||
BASE_EXPORT size_t FastHash(base::span<const uint8_t> data);
|
||||
inline size_t FastHash(StringPiece str) {
|
||||
return FastHash(as_bytes(make_span(str)));
|
||||
}
|
||||
|
||||
// Computes a hash of a memory buffer. This hash function must not change so
|
||||
// that code can use the hashed values for persistent storage purposes or
|
||||
// sending across the network. If a new persistent hash function is desired, a
|
||||
// new version will have to be added in addition.
|
||||
//
|
||||
// WARNING: This hash function should not be used for any cryptographic purpose.
|
||||
BASE_EXPORT uint32_t PersistentHash(base::span<const uint8_t> data);
|
||||
BASE_EXPORT uint32_t PersistentHash(const void* data, size_t length);
|
||||
BASE_EXPORT uint32_t PersistentHash(const std::string& str);
|
||||
|
||||
|
@ -83,4 +67,4 @@ struct IntPairHash<std::pair<Type1, Type2>> {
|
|||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_HASH_HASH_H_
|
||||
#endif // BASE_HASH_H_
|
|
@ -1,168 +0,0 @@
|
|||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_IMMEDIATE_CRASH_H_
|
||||
#define BASE_IMMEDIATE_CRASH_H_
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
// Crashes in the fastest possible way with no attempt at logging.
|
||||
// There are several constraints; see http://crbug.com/664209 for more context.
|
||||
//
|
||||
// - TRAP_SEQUENCE_() must be fatal. It should not be possible to ignore the
|
||||
// resulting exception or simply hit 'continue' to skip over it in a debugger.
|
||||
// - Different instances of TRAP_SEQUENCE_() must not be folded together, to
|
||||
// ensure crash reports are debuggable. Unlike __builtin_trap(), asm volatile
|
||||
// blocks will not be folded together.
|
||||
// Note: TRAP_SEQUENCE_() previously required an instruction with a unique
|
||||
// nonce since unlike clang, GCC folds together identical asm volatile
|
||||
// blocks.
|
||||
// - TRAP_SEQUENCE_() must produce a signal that is distinct from an invalid
|
||||
// memory access.
|
||||
// - TRAP_SEQUENCE_() must be treated as a set of noreturn instructions.
|
||||
// __builtin_unreachable() is used to provide that hint here. clang also uses
|
||||
// this as a heuristic to pack the instructions in the function epilogue to
|
||||
// improve code density.
|
||||
//
|
||||
// Additional properties that are nice to have:
|
||||
// - TRAP_SEQUENCE_() should be as compact as possible.
|
||||
// - The first instruction of TRAP_SEQUENCE_() should not change, to avoid
|
||||
// shifting crash reporting clusters. As a consequence of this, explicit
|
||||
// assembly is preferred over intrinsics.
|
||||
// Note: this last bullet point may no longer be true, and may be removed in
|
||||
// the future.
|
||||
|
||||
// Note: TRAP_SEQUENCE Is currently split into two macro helpers due to the fact
|
||||
// that clang emits an actual instruction for __builtin_unreachable() on certain
|
||||
// platforms (see https://crbug.com/958675). In addition, the int3/bkpt/brk will
|
||||
// be removed in followups, so splitting it up like this now makes it easy to
|
||||
// land the followups.
|
||||
|
||||
#if defined(COMPILER_GCC)
|
||||
|
||||
#if defined(OS_NACL)
|
||||
|
||||
// Crash report accuracy is not guaranteed on NaCl.
|
||||
#define TRAP_SEQUENCE1_() __builtin_trap()
|
||||
#define TRAP_SEQUENCE2_() asm volatile("")
|
||||
|
||||
#elif defined(ARCH_CPU_X86_FAMILY)
|
||||
|
||||
// TODO(https://crbug.com/958675): In theory, it should be possible to use just
|
||||
// int3. However, there are a number of crashes with SIGILL as the exception
|
||||
// code, so it seems likely that there's a signal handler that allows execution
|
||||
// to continue after SIGTRAP.
|
||||
#define TRAP_SEQUENCE1_() asm volatile("int3")
|
||||
|
||||
#if defined(OS_MACOSX)
|
||||
// Intentionally empty: __builtin_unreachable() is always part of the sequence
|
||||
// (see IMMEDIATE_CRASH below) and already emits a ud2 on Mac.
|
||||
#define TRAP_SEQUENCE2_() asm volatile("")
|
||||
#else
|
||||
#define TRAP_SEQUENCE2_() asm volatile("ud2")
|
||||
#endif // defined(OS_MACOSX)
|
||||
|
||||
#elif defined(ARCH_CPU_ARMEL)
|
||||
|
||||
// bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running
|
||||
// as a 32 bit userspace app on arm64. There doesn't seem to be any way to
|
||||
// cause a SIGTRAP from userspace without using a syscall (which would be a
|
||||
// problem for sandboxing).
|
||||
// TODO(https://crbug.com/958675): Remove bkpt from this sequence.
|
||||
#define TRAP_SEQUENCE1_() asm volatile("bkpt #0")
|
||||
#define TRAP_SEQUENCE2_() asm volatile("udf #0")
|
||||
|
||||
#elif defined(ARCH_CPU_ARM64)
|
||||
|
||||
// This will always generate a SIGTRAP on arm64.
|
||||
// TODO(https://crbug.com/958675): Remove brk from this sequence.
|
||||
#define TRAP_SEQUENCE1_() asm volatile("brk #0")
|
||||
#define TRAP_SEQUENCE2_() asm volatile("hlt #0")
|
||||
|
||||
#else
|
||||
|
||||
// Crash report accuracy will not be guaranteed on other architectures, but at
|
||||
// least this will crash as expected.
|
||||
#define TRAP_SEQUENCE1_() __builtin_trap()
|
||||
#define TRAP_SEQUENCE2_() asm volatile("")
|
||||
|
||||
#endif // ARCH_CPU_*
|
||||
|
||||
#elif defined(COMPILER_MSVC)
|
||||
|
||||
#if !defined(__clang__)
|
||||
|
||||
// MSVC x64 doesn't support inline asm, so use the MSVC intrinsic.
|
||||
#define TRAP_SEQUENCE1_() __debugbreak()
|
||||
#define TRAP_SEQUENCE2_()
|
||||
|
||||
#elif defined(ARCH_CPU_ARM64)
|
||||
|
||||
// Windows ARM64 uses "BRK #F000" as its breakpoint instruction, and
|
||||
// __debugbreak() generates that in both VC++ and clang.
|
||||
#define TRAP_SEQUENCE1_() __debugbreak()
|
||||
// Intentionally empty: __builtin_unreachable() is always part of the sequence
|
||||
// (see IMMEDIATE_CRASH below) and already emits a ud2 on Win64,
|
||||
// https://crbug.com/958373
|
||||
#define TRAP_SEQUENCE2_() __asm volatile("")
|
||||
|
||||
#else
|
||||
|
||||
#define TRAP_SEQUENCE1_() asm volatile("int3")
|
||||
#define TRAP_SEQUENCE2_() asm volatile("ud2")
|
||||
|
||||
#endif // __clang__
|
||||
|
||||
#else
|
||||
|
||||
#error No supported trap sequence!
|
||||
|
||||
#endif // COMPILER_GCC
|
||||
|
||||
#define TRAP_SEQUENCE_() \
|
||||
do { \
|
||||
TRAP_SEQUENCE1_(); \
|
||||
TRAP_SEQUENCE2_(); \
|
||||
} while (false)
|
||||
|
||||
// CHECK() and the trap sequence can be invoked from a constexpr function.
|
||||
// This could make compilation fail on GCC, as it forbids directly using inline
|
||||
// asm inside a constexpr function. However, it allows calling a lambda
|
||||
// expression including the same asm.
|
||||
// The side effect is that the top of the stacktrace will not point to the
|
||||
// calling function, but to this anonymous lambda. This is still useful as the
|
||||
// full name of the lambda will typically include the name of the function that
|
||||
// calls CHECK() and the debugger will still break at the right line of code.
|
||||
#if !defined(COMPILER_GCC)
|
||||
|
||||
#define WRAPPED_TRAP_SEQUENCE_() TRAP_SEQUENCE_()
|
||||
|
||||
#else
|
||||
|
||||
#define WRAPPED_TRAP_SEQUENCE_() \
|
||||
do { \
|
||||
[] { TRAP_SEQUENCE_(); }(); \
|
||||
} while (false)
|
||||
|
||||
#endif // !defined(COMPILER_GCC)
|
||||
|
||||
#if defined(__clang__) || defined(COMPILER_GCC)
|
||||
|
||||
// __builtin_unreachable() hints to the compiler that this is noreturn and can
|
||||
// be packed in the function epilogue.
|
||||
#define IMMEDIATE_CRASH() \
|
||||
({ \
|
||||
WRAPPED_TRAP_SEQUENCE_(); \
|
||||
__builtin_unreachable(); \
|
||||
})
|
||||
|
||||
#else
|
||||
|
||||
// This is supporting non-chromium user of logging.h to build with MSVC, like
|
||||
// pdfium. On MSVC there is no __builtin_unreachable().
|
||||
#define IMMEDIATE_CRASH() WRAPPED_TRAP_SEQUENCE_()
|
||||
|
||||
#endif // defined(__clang__) || defined(COMPILER_GCC)
|
||||
|
||||
#endif // BASE_IMMEDIATE_CRASH_H_
|
|
@ -43,7 +43,7 @@ Location::Location(const char* function_name,
|
|||
std::string Location::ToString() const {
|
||||
if (has_source_info()) {
|
||||
return std::string(function_name_) + "@" + file_name_ + ":" +
|
||||
NumberToString(line_number_);
|
||||
IntToString(line_number_);
|
||||
}
|
||||
return StringPrintf("pc:%p", program_counter_);
|
||||
}
|
||||
|
@ -69,25 +69,6 @@ NOINLINE Location Location::CreateFromHere(const char* function_name,
|
|||
return Location(function_name, file_name, line_number, RETURN_ADDRESS());
|
||||
}
|
||||
|
||||
#if SUPPORTS_LOCATION_BUILTINS && BUILDFLAG(ENABLE_LOCATION_SOURCE)
|
||||
// static
|
||||
NOINLINE Location Location::Current(const char* function_name,
|
||||
const char* file_name,
|
||||
int line_number) {
|
||||
return Location(function_name, file_name, line_number, RETURN_ADDRESS());
|
||||
}
|
||||
#elif SUPPORTS_LOCATION_BUILTINS
|
||||
// static
|
||||
NOINLINE Location Location::Current(const char* file_name) {
|
||||
return Location(file_name, RETURN_ADDRESS());
|
||||
}
|
||||
#else
|
||||
// static
|
||||
NOINLINE Location Location::Current() {
|
||||
return Location(nullptr, RETURN_ADDRESS());
|
||||
}
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
NOINLINE const void* GetProgramCounter() {
|
||||
return RETURN_ADDRESS();
|
||||
|
|
|
@ -8,29 +8,14 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/debug/debugging_buildflags.h"
|
||||
#include "base/hash/hash.h"
|
||||
#include "build/build_config.h"
|
||||
#include "base/hash.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
#if defined(__has_builtin)
|
||||
// Clang allows detection of these builtins.
|
||||
#define SUPPORTS_LOCATION_BUILTINS \
|
||||
(__has_builtin(__builtin_FUNCTION) && __has_builtin(__builtin_FILE) && \
|
||||
__has_builtin(__builtin_LINE))
|
||||
#elif defined(COMPILER_GCC) && __GNUC__ >= 7
|
||||
// GCC has supported these for a long time, but they point at the function
|
||||
// declaration in the case of default arguments, rather than at the call site.
|
||||
#define SUPPORTS_LOCATION_BUILTINS 1
|
||||
#else
|
||||
#define SUPPORTS_LOCATION_BUILTINS 0
|
||||
#endif
|
||||
|
||||
// Location provides basic info where of an object was constructed, or was
|
||||
// significantly brought to life.
|
||||
class BASE_EXPORT Location {
|
||||
|
@ -88,16 +73,6 @@ class BASE_EXPORT Location {
|
|||
const char* file_name,
|
||||
int line_number);
|
||||
|
||||
#if SUPPORTS_LOCATION_BUILTINS && BUILDFLAG(ENABLE_LOCATION_SOURCE)
|
||||
static Location Current(const char* function_name = __builtin_FUNCTION(),
|
||||
const char* file_name = __builtin_FILE(),
|
||||
int line_number = __builtin_LINE());
|
||||
#elif SUPPORTS_LOCATION_BUILTINS
|
||||
static Location Current(const char* file_name = __builtin_FILE());
|
||||
#else
|
||||
static Location Current();
|
||||
#endif
|
||||
|
||||
private:
|
||||
const char* function_name_ = nullptr;
|
||||
const char* file_name_ = nullptr;
|
||||
|
@ -133,7 +108,7 @@ template <>
|
|||
struct hash<::base::Location> {
|
||||
std::size_t operator()(const ::base::Location& loc) const {
|
||||
const void* program_counter = loc.program_counter();
|
||||
return base::FastHash(base::as_bytes(base::make_span(&program_counter, 1)));
|
||||
return base::Hash(&program_counter, sizeof(void*));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <stddef.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
@ -18,18 +17,13 @@
|
|||
#include "base/base_export.h"
|
||||
#include "base/callback_forward.h"
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/immediate_crash.h"
|
||||
#include "base/logging_buildflags.h"
|
||||
#include "base/debug/debugger.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/scoped_clear_last_error.h"
|
||||
#include "base/strings/string_piece_forward.h"
|
||||
#include "base/template_util.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_CHROMEOS)
|
||||
#include <cstdio>
|
||||
#endif
|
||||
|
||||
//
|
||||
// Optional message capabilities
|
||||
// -----------------------------
|
||||
|
@ -168,35 +162,27 @@ namespace logging {
|
|||
|
||||
// TODO(avi): do we want to do a unification of character types here?
|
||||
#if defined(OS_WIN)
|
||||
typedef wchar_t PathChar;
|
||||
typedef base::char16 PathChar;
|
||||
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
typedef char PathChar;
|
||||
#endif
|
||||
|
||||
// A bitmask of potential logging destinations.
|
||||
using LoggingDestination = uint32_t;
|
||||
// Specifies where logs will be written. Multiple destinations can be specified
|
||||
// with bitwise OR.
|
||||
// Unless destination is LOG_NONE, all logs with severity ERROR and above will
|
||||
// be written to stderr in addition to the specified destination.
|
||||
enum : uint32_t {
|
||||
// Where to record logging output? A flat file and/or system debug log
|
||||
// via OutputDebugString.
|
||||
enum LoggingDestination {
|
||||
LOG_NONE = 0,
|
||||
LOG_TO_FILE = 1 << 0,
|
||||
LOG_TO_SYSTEM_DEBUG_LOG = 1 << 1,
|
||||
LOG_TO_STDERR = 1 << 2,
|
||||
|
||||
LOG_TO_ALL = LOG_TO_FILE | LOG_TO_SYSTEM_DEBUG_LOG | LOG_TO_STDERR,
|
||||
LOG_TO_ALL = LOG_TO_FILE | LOG_TO_SYSTEM_DEBUG_LOG,
|
||||
|
||||
// On Windows, use a file next to the exe.
|
||||
// On POSIX platforms, where it may not even be possible to locate the
|
||||
// executable on disk, use stderr.
|
||||
// On Fuchsia, use the Fuchsia logging service.
|
||||
#if defined(OS_FUCHSIA) || defined(OS_NACL)
|
||||
LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG,
|
||||
#elif defined(OS_WIN)
|
||||
// On Windows, use a file next to the exe; on POSIX platforms, where
|
||||
// it may not even be possible to locate the executable on disk, use
|
||||
// stderr.
|
||||
#if defined(OS_WIN)
|
||||
LOG_DEFAULT = LOG_TO_FILE,
|
||||
#elif defined(OS_POSIX)
|
||||
LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG | LOG_TO_STDERR,
|
||||
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
LOG_DEFAULT = LOG_TO_SYSTEM_DEBUG_LOG,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
@ -214,22 +200,21 @@ enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
|
|||
enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
|
||||
|
||||
struct BASE_EXPORT LoggingSettings {
|
||||
// Equivalent to logging destination enum, but allows for multiple
|
||||
// destinations.
|
||||
uint32_t logging_dest = LOG_DEFAULT;
|
||||
// The defaults values are:
|
||||
//
|
||||
// logging_dest: LOG_DEFAULT
|
||||
// log_file: NULL
|
||||
// lock_log: LOCK_LOG_FILE
|
||||
// delete_old: APPEND_TO_OLD_LOG_FILE
|
||||
LoggingSettings();
|
||||
|
||||
// The four settings below have an effect only when LOG_TO_FILE is
|
||||
LoggingDestination logging_dest;
|
||||
|
||||
// The three settings below have an effect only when LOG_TO_FILE is
|
||||
// set in |logging_dest|.
|
||||
const PathChar* log_file_path = nullptr;
|
||||
LogLockingState lock_log = LOCK_LOG_FILE;
|
||||
OldFileDeletionState delete_old = APPEND_TO_OLD_LOG_FILE;
|
||||
#if defined(OS_CHROMEOS)
|
||||
// Contains an optional file that logs should be written to. If present,
|
||||
// |log_file_path| will be ignored, and the logging system will take ownership
|
||||
// of the FILE. If there's an error writing to this file, no fallback paths
|
||||
// will be opened.
|
||||
FILE* log_file = nullptr;
|
||||
#endif
|
||||
const PathChar* log_file;
|
||||
LogLockingState lock_log;
|
||||
OldFileDeletionState delete_old;
|
||||
};
|
||||
|
||||
// Define different names for the BaseInitLoggingImpl() function depending on
|
||||
|
@ -315,10 +300,10 @@ BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs);
|
|||
// however clients can use this function to override with their own handling
|
||||
// (e.g. a silent one for Unit Tests)
|
||||
using LogAssertHandlerFunction =
|
||||
base::RepeatingCallback<void(const char* file,
|
||||
int line,
|
||||
const base::StringPiece message,
|
||||
const base::StringPiece stack_trace)>;
|
||||
base::Callback<void(const char* file,
|
||||
int line,
|
||||
const base::StringPiece message,
|
||||
const base::StringPiece stack_trace)>;
|
||||
|
||||
class BASE_EXPORT ScopedLogAssertHandler {
|
||||
public:
|
||||
|
@ -530,9 +515,9 @@ BASE_EXPORT extern std::ostream* g_swallow_stream;
|
|||
class CheckOpResult {
|
||||
public:
|
||||
// |message| must be non-null if and only if the check failed.
|
||||
constexpr CheckOpResult(std::string* message) : message_(message) {}
|
||||
CheckOpResult(std::string* message) : message_(message) {}
|
||||
// Returns true if the check succeeded.
|
||||
constexpr operator bool() const { return !message_; }
|
||||
operator bool() const { return !message_; }
|
||||
// Returns the message.
|
||||
std::string* message() { return message_; }
|
||||
|
||||
|
@ -540,6 +525,110 @@ class CheckOpResult {
|
|||
std::string* message_;
|
||||
};
|
||||
|
||||
// Crashes in the fastest possible way with no attempt at logging.
|
||||
// There are different constraints to satisfy here, see http://crbug.com/664209
|
||||
// for more context:
|
||||
// - The trap instructions, and hence the PC value at crash time, have to be
|
||||
// distinct and not get folded into the same opcode by the compiler.
|
||||
// On Linux/Android this is tricky because GCC still folds identical
|
||||
// asm volatile blocks. The workaround is generating distinct opcodes for
|
||||
// each CHECK using the __COUNTER__ macro.
|
||||
// - The debug info for the trap instruction has to be attributed to the source
|
||||
// line that has the CHECK(), to make crash reports actionable. This rules
|
||||
// out the ability of using a inline function, at least as long as clang
|
||||
// doesn't support attribute(artificial).
|
||||
// - Failed CHECKs should produce a signal that is distinguishable from an
|
||||
// invalid memory access, to improve the actionability of crash reports.
|
||||
// - The compiler should treat the CHECK as no-return instructions, so that the
|
||||
// trap code can be efficiently packed in the prologue of the function and
|
||||
// doesn't interfere with the main execution flow.
|
||||
// - When debugging, developers shouldn't be able to accidentally step over a
|
||||
// CHECK. This is achieved by putting opcodes that will cause a non
|
||||
// continuable exception after the actual trap instruction.
|
||||
// - Don't cause too much binary bloat.
|
||||
#if defined(COMPILER_GCC)
|
||||
|
||||
#if defined(ARCH_CPU_X86_FAMILY) && !defined(OS_NACL)
|
||||
// int 3 will generate a SIGTRAP.
|
||||
#define TRAP_SEQUENCE() \
|
||||
asm volatile( \
|
||||
"int3; ud2; push %0;" ::"i"(static_cast<unsigned char>(__COUNTER__)))
|
||||
|
||||
#elif defined(ARCH_CPU_ARMEL) && !defined(OS_NACL)
|
||||
// bkpt will generate a SIGBUS when running on armv7 and a SIGTRAP when running
|
||||
// as a 32 bit userspace app on arm64. There doesn't seem to be any way to
|
||||
// cause a SIGTRAP from userspace without using a syscall (which would be a
|
||||
// problem for sandboxing).
|
||||
#define TRAP_SEQUENCE() \
|
||||
asm volatile("bkpt #0; udf %0;" ::"i"(__COUNTER__ % 256))
|
||||
|
||||
#elif defined(ARCH_CPU_ARM64) && !defined(OS_NACL)
|
||||
// This will always generate a SIGTRAP on arm64.
|
||||
#define TRAP_SEQUENCE() \
|
||||
asm volatile("brk #0; hlt %0;" ::"i"(__COUNTER__ % 65536))
|
||||
|
||||
#else
|
||||
// Crash report accuracy will not be guaranteed on other architectures, but at
|
||||
// least this will crash as expected.
|
||||
#define TRAP_SEQUENCE() __builtin_trap()
|
||||
#endif // ARCH_CPU_*
|
||||
|
||||
#elif defined(COMPILER_MSVC)
|
||||
|
||||
// Clang is cleverer about coalescing int3s, so we need to add a unique-ish
|
||||
// instruction following the __debugbreak() to have it emit distinct locations
|
||||
// for CHECKs rather than collapsing them all together. It would be nice to use
|
||||
// a short intrinsic to do this (and perhaps have only one implementation for
|
||||
// both clang and MSVC), however clang-cl currently does not support intrinsics.
|
||||
// On the flip side, MSVC x64 doesn't support inline asm. So, we have to have
|
||||
// two implementations. Normally clang-cl's version will be 5 bytes (1 for
|
||||
// `int3`, 2 for `ud2`, 2 for `push byte imm`, however, TODO(scottmg):
|
||||
// https://crbug.com/694670 clang-cl doesn't currently support %'ing
|
||||
// __COUNTER__, so eventually it will emit the dword form of push.
|
||||
// TODO(scottmg): Reinvestigate a short sequence that will work on both
|
||||
// compilers once clang supports more intrinsics. See https://crbug.com/693713.
|
||||
#if !defined(__clang__)
|
||||
#define TRAP_SEQUENCE() __debugbreak()
|
||||
#elif defined(ARCH_CPU_ARM64)
|
||||
#define TRAP_SEQUENCE() \
|
||||
__asm volatile("brk #0\n hlt %0\n" ::"i"(__COUNTER__ % 65536));
|
||||
#else
|
||||
#define TRAP_SEQUENCE() ({ {__asm int 3 __asm ud2 __asm push __COUNTER__}; })
|
||||
#endif // __clang__
|
||||
|
||||
#else
|
||||
#error Port
|
||||
#endif // COMPILER_GCC
|
||||
|
||||
// CHECK() and the trap sequence can be invoked from a constexpr function.
|
||||
// This could make compilation fail on GCC, as it forbids directly using inline
|
||||
// asm inside a constexpr function. However, it allows calling a lambda
|
||||
// expression including the same asm.
|
||||
// The side effect is that the top of the stacktrace will not point to the
|
||||
// calling function, but to this anonymous lambda. This is still useful as the
|
||||
// full name of the lambda will typically include the name of the function that
|
||||
// calls CHECK() and the debugger will still break at the right line of code.
|
||||
#if !defined(COMPILER_GCC)
|
||||
#define WRAPPED_TRAP_SEQUENCE() TRAP_SEQUENCE()
|
||||
#else
|
||||
#define WRAPPED_TRAP_SEQUENCE() \
|
||||
do { \
|
||||
[] { TRAP_SEQUENCE(); }(); \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(COMPILER_GCC)
|
||||
#define IMMEDIATE_CRASH() \
|
||||
({ \
|
||||
WRAPPED_TRAP_SEQUENCE(); \
|
||||
__builtin_unreachable(); \
|
||||
})
|
||||
#else
|
||||
// This is supporting non-chromium user of logging.h to build with MSVC, like
|
||||
// pdfium. On MSVC there is no __builtin_unreachable().
|
||||
#define IMMEDIATE_CRASH() WRAPPED_TRAP_SEQUENCE()
|
||||
#endif
|
||||
|
||||
// CHECK dies with a fatal error if condition is not true. It is *not*
|
||||
// controlled by NDEBUG, so the check will be executed regardless of
|
||||
// compilation mode.
|
||||
|
@ -570,6 +659,26 @@ class CheckOpResult {
|
|||
|
||||
#else // !(OFFICIAL_BUILD && NDEBUG)
|
||||
|
||||
#if defined(_PREFAST_) && defined(OS_WIN)
|
||||
// Use __analysis_assume to tell the VC++ static analysis engine that
|
||||
// assert conditions are true, to suppress warnings. The LAZY_STREAM
|
||||
// parameter doesn't reference 'condition' in /analyze builds because
|
||||
// this evaluation confuses /analyze. The !! before condition is because
|
||||
// __analysis_assume gets confused on some conditions:
|
||||
// http://randomascii.wordpress.com/2011/09/13/analyze-for-visual-studio-the-ugly-part-5/
|
||||
|
||||
#define CHECK(condition) \
|
||||
__analysis_assume(!!(condition)), \
|
||||
LAZY_STREAM(LOG_STREAM(FATAL), false) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#define PCHECK(condition) \
|
||||
__analysis_assume(!!(condition)), \
|
||||
LAZY_STREAM(PLOG_STREAM(FATAL), false) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#else // _PREFAST_
|
||||
|
||||
// Do as much work as possible out of line to reduce inline code size.
|
||||
#define CHECK(condition) \
|
||||
LAZY_STREAM(::logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
|
||||
|
@ -579,6 +688,8 @@ class CheckOpResult {
|
|||
LAZY_STREAM(PLOG_STREAM(FATAL), !ANALYZER_ASSUME_TRUE(condition)) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#endif // _PREFAST_
|
||||
|
||||
// Helper macro for binary operators.
|
||||
// Don't use this macro directly in your code, use CHECK_EQ et al below.
|
||||
// The 'switch' is used to prevent the 'else' from being ambiguous when the
|
||||
|
@ -607,16 +718,6 @@ MakeCheckOpValueString(std::ostream* os, const T& v) {
|
|||
(*os) << v;
|
||||
}
|
||||
|
||||
// Overload for types that no operator<< but do have .ToString() defined.
|
||||
template <typename T>
|
||||
inline typename std::enable_if<
|
||||
!base::internal::SupportsOstreamOperator<const T&>::value &&
|
||||
base::internal::SupportsToString<const T&>::value,
|
||||
void>::type
|
||||
MakeCheckOpValueString(std::ostream* os, const T& v) {
|
||||
(*os) << v.ToString();
|
||||
}
|
||||
|
||||
// Provide an overload for functions and function pointers. Function pointers
|
||||
// don't implicitly convert to void* but do implicitly convert to bool, so
|
||||
// without this function pointers are always printed as 1 or 0. (MSVC isn't
|
||||
|
@ -685,21 +786,20 @@ std::string* MakeCheckOpString<std::string, std::string>(
|
|||
// The checked condition is wrapped with ANALYZER_ASSUME_TRUE, which under
|
||||
// static analysis builds, blocks analysis of the current path if the
|
||||
// condition is false.
|
||||
#define DEFINE_CHECK_OP_IMPL(name, op) \
|
||||
template <class t1, class t2> \
|
||||
constexpr std::string* Check##name##Impl(const t1& v1, const t2& v2, \
|
||||
const char* names) { \
|
||||
if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
|
||||
return nullptr; \
|
||||
else \
|
||||
return ::logging::MakeCheckOpString(v1, v2, names); \
|
||||
} \
|
||||
constexpr std::string* Check##name##Impl(int v1, int v2, \
|
||||
const char* names) { \
|
||||
if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
|
||||
return nullptr; \
|
||||
else \
|
||||
return ::logging::MakeCheckOpString(v1, v2, names); \
|
||||
#define DEFINE_CHECK_OP_IMPL(name, op) \
|
||||
template <class t1, class t2> \
|
||||
inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
|
||||
const char* names) { \
|
||||
if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
|
||||
return NULL; \
|
||||
else \
|
||||
return ::logging::MakeCheckOpString(v1, v2, names); \
|
||||
} \
|
||||
inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
|
||||
if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
|
||||
return NULL; \
|
||||
else \
|
||||
return ::logging::MakeCheckOpString(v1, v2, names); \
|
||||
}
|
||||
DEFINE_CHECK_OP_IMPL(EQ, ==)
|
||||
DEFINE_CHECK_OP_IMPL(NE, !=)
|
||||
|
@ -717,9 +817,9 @@ DEFINE_CHECK_OP_IMPL(GT, > )
|
|||
#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
|
||||
|
||||
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
|
||||
#define DCHECK_IS_ON() false
|
||||
#define DCHECK_IS_ON() 0
|
||||
#else
|
||||
#define DCHECK_IS_ON() true
|
||||
#define DCHECK_IS_ON() 1
|
||||
#endif
|
||||
|
||||
// Definitions for DLOG et al.
|
||||
|
@ -785,6 +885,21 @@ const LogSeverity LOG_DCHECK = LOG_FATAL;
|
|||
// DCHECK_IS_ON() is true. When DCHECK_IS_ON() is false, the macros use
|
||||
// EAT_STREAM_PARAMETERS to avoid expressions that would create temporaries.
|
||||
|
||||
#if defined(_PREFAST_) && defined(OS_WIN)
|
||||
// See comments on the previous use of __analysis_assume.
|
||||
|
||||
#define DCHECK(condition) \
|
||||
__analysis_assume(!!(condition)), \
|
||||
LAZY_STREAM(LOG_STREAM(DCHECK), false) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#define DPCHECK(condition) \
|
||||
__analysis_assume(!!(condition)), \
|
||||
LAZY_STREAM(PLOG_STREAM(DCHECK), false) \
|
||||
<< "Check failed: " #condition ". "
|
||||
|
||||
#else // !(defined(_PREFAST_) && defined(OS_WIN))
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
|
||||
#define DCHECK(condition) \
|
||||
|
@ -801,6 +916,8 @@ const LogSeverity LOG_DCHECK = LOG_FATAL;
|
|||
|
||||
#endif // DCHECK_IS_ON()
|
||||
|
||||
#endif // defined(_PREFAST_) && defined(OS_WIN)
|
||||
|
||||
// Helper macro for binary operators.
|
||||
// Don't use this macro directly in your code, use DCHECK_EQ et al below.
|
||||
// The 'switch' is used to prevent the 'else' from being ambiguous when the
|
||||
|
@ -865,7 +982,7 @@ const LogSeverity LOG_DCHECK = LOG_FATAL;
|
|||
#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
|
||||
#define DCHECK_GT(val1, val2) DCHECK_OP(GT, > , val1, val2)
|
||||
|
||||
#if BUILDFLAG(ENABLE_LOG_ERROR_NOT_REACHED)
|
||||
#if !DCHECK_IS_ON() && defined(OS_CHROMEOS)
|
||||
// Implement logging of NOTREACHED() as a dedicated function to get function
|
||||
// call overhead down to a minimum.
|
||||
void LogErrorNotReached(const char* file, int line);
|
||||
|
@ -921,7 +1038,6 @@ class BASE_EXPORT LogMessage {
|
|||
// The file and line information passed in to the constructor.
|
||||
const char* file_;
|
||||
const int line_;
|
||||
const char* file_basename_;
|
||||
|
||||
// This is useful since the LogMessage class uses a lot of Win32 calls
|
||||
// that will lose the value of GLE and the code that called the log function
|
||||
|
@ -1001,14 +1117,6 @@ class BASE_EXPORT ErrnoLogMessage {
|
|||
// after this call.
|
||||
BASE_EXPORT void CloseLogFile();
|
||||
|
||||
#if defined(OS_CHROMEOS)
|
||||
// Returns a new file handle that will write to the same destination as the
|
||||
// currently open log file. Returns nullptr if logging to a file is disabled,
|
||||
// or if opening the file failed. This is intended to be used to initialize
|
||||
// logging in child processes that are unable to open files.
|
||||
BASE_EXPORT FILE* DuplicateLogFILE();
|
||||
#endif
|
||||
|
||||
// Async signal safe logging mechanism.
|
||||
BASE_EXPORT void RawLog(int level, const char* message);
|
||||
|
||||
|
@ -1027,7 +1135,7 @@ BASE_EXPORT void RawLog(int level, const char* message);
|
|||
BASE_EXPORT bool IsLoggingToFileEnabled();
|
||||
|
||||
// Returns the default log file path.
|
||||
BASE_EXPORT std::wstring GetLogFileFullPath();
|
||||
BASE_EXPORT base::string16 GetLogFileFullPath();
|
||||
#endif
|
||||
|
||||
} // namespace logging
|
||||
|
@ -1065,13 +1173,18 @@ inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
|
|||
#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED"
|
||||
#endif
|
||||
|
||||
#define NOTIMPLEMENTED() DLOG(ERROR) << NOTIMPLEMENTED_MSG
|
||||
#define NOTIMPLEMENTED_LOG_ONCE() \
|
||||
do { \
|
||||
static bool logged_once = false; \
|
||||
DLOG_IF(ERROR, !logged_once) << NOTIMPLEMENTED_MSG; \
|
||||
logged_once = true; \
|
||||
} while (0); \
|
||||
#if defined(OS_ANDROID) && defined(OFFICIAL_BUILD)
|
||||
#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS
|
||||
#define NOTIMPLEMENTED_LOG_ONCE() EAT_STREAM_PARAMETERS
|
||||
#else
|
||||
#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG
|
||||
#define NOTIMPLEMENTED_LOG_ONCE() \
|
||||
do { \
|
||||
static bool logged_once = false; \
|
||||
LOG_IF(ERROR, !logged_once) << NOTIMPLEMENTED_MSG; \
|
||||
logged_once = true; \
|
||||
} while (0); \
|
||||
EAT_STREAM_PARAMETERS
|
||||
#endif
|
||||
|
||||
#endif // BASE_LOGGING_H_
|
||||
|
|
|
@ -10,10 +10,6 @@
|
|||
#ifndef BASE_MACROS_H_
|
||||
#define BASE_MACROS_H_
|
||||
|
||||
// ALL DISALLOW_xxx MACROS ARE DEPRECATED; DO NOT USE IN NEW CODE.
|
||||
// Use explicit deletions instead. See the section on copyability/movability in
|
||||
// //styleguide/c++/c++-dos-and-donts.md for more information.
|
||||
|
||||
// Put this in the declarations for a class to be uncopyable.
|
||||
#define DISALLOW_COPY(TypeName) \
|
||||
TypeName(const TypeName&) = delete
|
||||
|
|
|
@ -1,62 +0,0 @@
|
|||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/memory/platform_shared_memory_region.h"
|
||||
|
||||
#include "base/memory/shared_memory_mapping.h"
|
||||
#include "base/numerics/checked_math.h"
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
// static
|
||||
PlatformSharedMemoryRegion PlatformSharedMemoryRegion::CreateWritable(
|
||||
size_t size) {
|
||||
return Create(Mode::kWritable, size);
|
||||
}
|
||||
|
||||
// static
|
||||
PlatformSharedMemoryRegion PlatformSharedMemoryRegion::CreateUnsafe(
|
||||
size_t size) {
|
||||
return Create(Mode::kUnsafe, size);
|
||||
}
|
||||
|
||||
PlatformSharedMemoryRegion::PlatformSharedMemoryRegion() = default;
|
||||
PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
|
||||
PlatformSharedMemoryRegion&& other) = default;
|
||||
PlatformSharedMemoryRegion& PlatformSharedMemoryRegion::operator=(
|
||||
PlatformSharedMemoryRegion&& other) = default;
|
||||
PlatformSharedMemoryRegion::~PlatformSharedMemoryRegion() = default;
|
||||
|
||||
PlatformSharedMemoryRegion::ScopedPlatformHandle
|
||||
PlatformSharedMemoryRegion::PassPlatformHandle() {
|
||||
return std::move(handle_);
|
||||
}
|
||||
|
||||
bool PlatformSharedMemoryRegion::MapAt(off_t offset,
|
||||
size_t size,
|
||||
void** memory,
|
||||
size_t* mapped_size) const {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
|
||||
if (size == 0)
|
||||
return false;
|
||||
|
||||
size_t end_byte;
|
||||
if (!CheckAdd(offset, size).AssignIfValid(&end_byte) || end_byte > size_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = MapAtInternal(offset, size, memory, mapped_size);
|
||||
if (success) {
|
||||
DCHECK_EQ(
|
||||
0U, reinterpret_cast<uintptr_t>(*memory) & (kMapMinimumAlignment - 1));
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace base
|
|
@ -1,301 +0,0 @@
|
|||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
|
||||
#define BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/compiler_specific.h"
|
||||
#include "base/gtest_prod_util.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/unguessable_token.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include <mach/mach.h>
|
||||
#include "base/mac/scoped_mach_port.h"
|
||||
#elif defined(OS_FUCHSIA)
|
||||
#include <lib/zx/vmo.h>
|
||||
#elif defined(OS_WIN)
|
||||
#include "base/win/scoped_handle.h"
|
||||
#include "base/win/windows_types.h"
|
||||
#elif defined(OS_POSIX)
|
||||
#include <sys/types.h>
|
||||
#include "base/file_descriptor_posix.h"
|
||||
#include "base/files/scoped_file.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
namespace content {
|
||||
class SandboxIPCHandler;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
#if defined(OS_POSIX) && (!defined(OS_MACOSX) || defined(OS_IOS)) && \
|
||||
!defined(OS_ANDROID)
|
||||
// Helper structs to keep two descriptors on POSIX. It's needed to support
|
||||
// ConvertToReadOnly().
|
||||
struct BASE_EXPORT FDPair {
|
||||
// The main shared memory descriptor that is used for mapping. May be either
|
||||
// writable or read-only, depending on region's mode.
|
||||
int fd;
|
||||
// The read-only descriptor, valid only in kWritable mode. Replaces |fd| when
|
||||
// a region is converted to read-only.
|
||||
int readonly_fd;
|
||||
};
|
||||
|
||||
struct BASE_EXPORT ScopedFDPair {
|
||||
ScopedFDPair();
|
||||
ScopedFDPair(ScopedFD in_fd, ScopedFD in_readonly_fd);
|
||||
ScopedFDPair(ScopedFDPair&&);
|
||||
ScopedFDPair& operator=(ScopedFDPair&&);
|
||||
~ScopedFDPair();
|
||||
|
||||
FDPair get() const;
|
||||
|
||||
ScopedFD fd;
|
||||
ScopedFD readonly_fd;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Implementation class for shared memory regions.
|
||||
//
|
||||
// This class does the following:
|
||||
//
|
||||
// - Wraps and owns a shared memory region platform handle.
|
||||
// - Provides a way to allocate a new region of platform shared memory of given
|
||||
// size.
|
||||
// - Provides a way to create mapping of the region in the current process'
|
||||
// address space, under special access-control constraints (see Mode).
|
||||
// - Provides methods to help transferring the handle across process boundaries.
|
||||
// - Holds a 128-bit unique identifier used to uniquely identify the same
|
||||
// kernel region resource across processes (used for memory tracking).
|
||||
// - Has a method to retrieve the region's size in bytes.
|
||||
//
|
||||
// IMPORTANT NOTE: Users should never use this directly, but
|
||||
// ReadOnlySharedMemoryRegion, WritableSharedMemoryRegion or
|
||||
// UnsafeSharedMemoryRegion since this is an implementation class.
|
||||
class BASE_EXPORT PlatformSharedMemoryRegion {
|
||||
public:
|
||||
// Permission mode of the platform handle. Each mode corresponds to one of the
|
||||
// typed shared memory classes:
|
||||
//
|
||||
// * ReadOnlySharedMemoryRegion: A region that can only create read-only
|
||||
// mappings.
|
||||
//
|
||||
// * WritableSharedMemoryRegion: A region that can only create writable
|
||||
// mappings. The region can be demoted to ReadOnlySharedMemoryRegion without
|
||||
// the possibility of promoting back to writable.
|
||||
//
|
||||
// * UnsafeSharedMemoryRegion: A region that can only create writable
|
||||
// mappings. The region cannot be demoted to ReadOnlySharedMemoryRegion.
|
||||
enum class Mode {
|
||||
kReadOnly, // ReadOnlySharedMemoryRegion
|
||||
kWritable, // WritableSharedMemoryRegion
|
||||
kUnsafe, // UnsafeSharedMemoryRegion
|
||||
kMaxValue = kUnsafe
|
||||
};
|
||||
|
||||
// Errors that can occur during Shared Memory construction.
|
||||
// These match tools/metrics/histograms/enums.xml.
|
||||
// This enum is append-only.
|
||||
enum class CreateError {
|
||||
SUCCESS = 0,
|
||||
SIZE_ZERO = 1,
|
||||
SIZE_TOO_LARGE = 2,
|
||||
INITIALIZE_ACL_FAILURE = 3,
|
||||
INITIALIZE_SECURITY_DESC_FAILURE = 4,
|
||||
SET_SECURITY_DESC_FAILURE = 5,
|
||||
CREATE_FILE_MAPPING_FAILURE = 6,
|
||||
REDUCE_PERMISSIONS_FAILURE = 7,
|
||||
ALREADY_EXISTS = 8,
|
||||
ALLOCATE_FILE_REGION_FAILURE = 9,
|
||||
FSTAT_FAILURE = 10,
|
||||
INODES_MISMATCH = 11,
|
||||
GET_SHMEM_TEMP_DIR_FAILURE = 12,
|
||||
kMaxValue = GET_SHMEM_TEMP_DIR_FAILURE
|
||||
};
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
// Structure to limit access to executable region creation.
|
||||
struct ExecutableRegion {
|
||||
private:
|
||||
// Creates a new shared memory region the unsafe mode (writable and not and
|
||||
// convertible to read-only), and in addition marked executable. A ScopedFD
|
||||
// to this region is returned. Any any mapping will have to be done
|
||||
// manually, including setting executable permissions if necessary
|
||||
//
|
||||
// This is only used to support sandbox_ipc_linux.cc, and should not be used
|
||||
// anywhere else in chrome. This is restricted via AllowCreateExecutable.
|
||||
// TODO(crbug.com/982879): remove this when NaCl is unshipped.
|
||||
//
|
||||
// Returns an invalid ScopedFD if the call fails.
|
||||
static ScopedFD CreateFD(size_t size);
|
||||
|
||||
friend class content::SandboxIPCHandler;
|
||||
};
|
||||
#endif
|
||||
|
||||
// Platform-specific shared memory type used by this class.
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
using PlatformHandle = mach_port_t;
|
||||
using ScopedPlatformHandle = mac::ScopedMachSendRight;
|
||||
#elif defined(OS_FUCHSIA)
|
||||
using PlatformHandle = zx::unowned_vmo;
|
||||
using ScopedPlatformHandle = zx::vmo;
|
||||
#elif defined(OS_WIN)
|
||||
using PlatformHandle = HANDLE;
|
||||
using ScopedPlatformHandle = win::ScopedHandle;
|
||||
#elif defined(OS_ANDROID)
|
||||
using PlatformHandle = int;
|
||||
using ScopedPlatformHandle = ScopedFD;
|
||||
#else
|
||||
using PlatformHandle = FDPair;
|
||||
using ScopedPlatformHandle = ScopedFDPair;
|
||||
#endif
|
||||
|
||||
// The minimum alignment in bytes that any mapped address produced by Map()
|
||||
// and MapAt() is guaranteed to have.
|
||||
enum { kMapMinimumAlignment = 32 };
|
||||
|
||||
// Creates a new PlatformSharedMemoryRegion with corresponding mode and size.
|
||||
// Creating in kReadOnly mode isn't supported because then there will be no
|
||||
// way to modify memory content.
|
||||
static PlatformSharedMemoryRegion CreateWritable(size_t size);
|
||||
static PlatformSharedMemoryRegion CreateUnsafe(size_t size);
|
||||
|
||||
// Returns a new PlatformSharedMemoryRegion that takes ownership of the
|
||||
// |handle|. All parameters must be taken from another valid
|
||||
// PlatformSharedMemoryRegion instance, e.g. |size| must be equal to the
|
||||
// actual region size as allocated by the kernel.
|
||||
// Closes the |handle| and returns an invalid instance if passed parameters
|
||||
// are invalid.
|
||||
static PlatformSharedMemoryRegion Take(ScopedPlatformHandle handle,
|
||||
Mode mode,
|
||||
size_t size,
|
||||
const UnguessableToken& guid);
|
||||
#if defined(OS_POSIX) && !defined(OS_ANDROID) && \
|
||||
!(defined(OS_MACOSX) && !defined(OS_IOS))
|
||||
// Specialized version of Take() for POSIX that takes only one file descriptor
|
||||
// instead of pair. Cannot be used with kWritable |mode|.
|
||||
static PlatformSharedMemoryRegion Take(ScopedFD handle,
|
||||
Mode mode,
|
||||
size_t size,
|
||||
const UnguessableToken& guid);
|
||||
#endif
|
||||
|
||||
// Default constructor initializes an invalid instance, i.e. an instance that
|
||||
// doesn't wrap any valid platform handle.
|
||||
PlatformSharedMemoryRegion();
|
||||
|
||||
// Move operations are allowed.
|
||||
PlatformSharedMemoryRegion(PlatformSharedMemoryRegion&&);
|
||||
PlatformSharedMemoryRegion& operator=(PlatformSharedMemoryRegion&&);
|
||||
|
||||
// Destructor closes the platform handle. Does nothing if the handle is
|
||||
// invalid.
|
||||
~PlatformSharedMemoryRegion();
|
||||
|
||||
// Passes ownership of the platform handle to the caller. The current instance
|
||||
// becomes invalid. It's the responsibility of the caller to close the
|
||||
// handle. If the current instance is invalid, ScopedPlatformHandle will also
|
||||
// be invalid.
|
||||
ScopedPlatformHandle PassPlatformHandle() WARN_UNUSED_RESULT;
|
||||
|
||||
// Returns the platform handle. The current instance keeps ownership of this
|
||||
// handle.
|
||||
PlatformHandle GetPlatformHandle() const;
|
||||
|
||||
// Whether the platform handle is valid.
|
||||
bool IsValid() const;
|
||||
|
||||
// Duplicates the platform handle and creates a new PlatformSharedMemoryRegion
|
||||
// with the same |mode_|, |size_| and |guid_| that owns this handle. Returns
|
||||
// invalid region on failure, the current instance remains valid.
|
||||
// Can be called only in kReadOnly and kUnsafe modes, CHECK-fails if is
|
||||
// called in kWritable mode.
|
||||
PlatformSharedMemoryRegion Duplicate() const;
|
||||
|
||||
// Converts the region to read-only. Returns whether the operation succeeded.
|
||||
// Makes the current instance invalid on failure. Can be called only in
|
||||
// kWritable mode, all other modes will CHECK-fail. The object will have
|
||||
// kReadOnly mode after this call on success.
|
||||
bool ConvertToReadOnly();
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
// Same as above, but |mapped_addr| is used as a hint to avoid additional
|
||||
// mapping of the memory object.
|
||||
// |mapped_addr| must be mapped location of |memory_object_|. If the location
|
||||
// is unknown, |mapped_addr| should be |nullptr|.
|
||||
bool ConvertToReadOnly(void* mapped_addr);
|
||||
#endif // defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
|
||||
// Converts the region to unsafe. Returns whether the operation succeeded.
|
||||
// Makes the current instance invalid on failure. Can be called only in
|
||||
// kWritable mode, all other modes will CHECK-fail. The object will have
|
||||
// kUnsafe mode after this call on success.
|
||||
bool ConvertToUnsafe();
|
||||
|
||||
// Maps |size| bytes of the shared memory region starting with the given
|
||||
// |offset| into the caller's address space. |offset| must be aligned to value
|
||||
// of |SysInfo::VMAllocationGranularity()|. Fails if requested bytes are out
|
||||
// of the region limits.
|
||||
// Returns true and sets |memory| and |mapped_size| on success, returns false
|
||||
// and leaves output parameters in unspecified state otherwise. The mapped
|
||||
// address is guaranteed to have an alignment of at least
|
||||
// |kMapMinimumAlignment|.
|
||||
bool MapAt(off_t offset,
|
||||
size_t size,
|
||||
void** memory,
|
||||
size_t* mapped_size) const;
|
||||
|
||||
const UnguessableToken& GetGUID() const { return guid_; }
|
||||
|
||||
size_t GetSize() const { return size_; }
|
||||
|
||||
Mode GetMode() const { return mode_; }
|
||||
|
||||
private:
|
||||
FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
|
||||
CreateReadOnlyRegionDeathTest);
|
||||
FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
|
||||
CheckPlatformHandlePermissionsCorrespondToMode);
|
||||
static PlatformSharedMemoryRegion Create(Mode mode,
|
||||
size_t size
|
||||
#if defined(OS_LINUX)
|
||||
,
|
||||
bool executable = false
|
||||
#endif
|
||||
);
|
||||
|
||||
static bool CheckPlatformHandlePermissionsCorrespondToMode(
|
||||
PlatformHandle handle,
|
||||
Mode mode,
|
||||
size_t size);
|
||||
|
||||
PlatformSharedMemoryRegion(ScopedPlatformHandle handle,
|
||||
Mode mode,
|
||||
size_t size,
|
||||
const UnguessableToken& guid);
|
||||
|
||||
bool MapAtInternal(off_t offset,
|
||||
size_t size,
|
||||
void** memory,
|
||||
size_t* mapped_size) const;
|
||||
|
||||
ScopedPlatformHandle handle_;
|
||||
Mode mode_ = Mode::kReadOnly;
|
||||
size_t size_ = 0;
|
||||
UnguessableToken guid_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(PlatformSharedMemoryRegion);
|
||||
};
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
|
|
@ -1,343 +0,0 @@
|
|||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/memory/platform_shared_memory_region.h"
|
||||
|
||||
#include <aclapi.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/allocator/partition_allocator/page_allocator.h"
|
||||
#include "base/bits.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "base/metrics/histogram_macros.h"
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
||||
namespace base {
|
||||
namespace subtle {
|
||||
|
||||
namespace {
|
||||
|
||||
// Emits UMA metrics about encountered errors. Pass zero (0) for |winerror|
|
||||
// if there is no associated Windows error.
|
||||
void LogError(PlatformSharedMemoryRegion::CreateError error, DWORD winerror) {
|
||||
UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error);
|
||||
static_assert(ERROR_SUCCESS == 0, "Windows error code changed!");
|
||||
if (winerror != ERROR_SUCCESS)
|
||||
UmaHistogramSparse("SharedMemory.CreateWinError", winerror);
|
||||
}
|
||||
|
||||
typedef enum _SECTION_INFORMATION_CLASS {
|
||||
SectionBasicInformation,
|
||||
} SECTION_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _SECTION_BASIC_INFORMATION {
|
||||
PVOID BaseAddress;
|
||||
ULONG Attributes;
|
||||
LARGE_INTEGER Size;
|
||||
} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
|
||||
|
||||
typedef ULONG(__stdcall* NtQuerySectionType)(
|
||||
HANDLE SectionHandle,
|
||||
SECTION_INFORMATION_CLASS SectionInformationClass,
|
||||
PVOID SectionInformation,
|
||||
ULONG SectionInformationLength,
|
||||
PULONG ResultLength);
|
||||
|
||||
// Returns the length of the memory section starting at the supplied address.
|
||||
size_t GetMemorySectionSize(void* address) {
|
||||
MEMORY_BASIC_INFORMATION memory_info;
|
||||
if (!::VirtualQuery(address, &memory_info, sizeof(memory_info)))
|
||||
return 0;
|
||||
return memory_info.RegionSize -
|
||||
(static_cast<char*>(address) -
|
||||
static_cast<char*>(memory_info.AllocationBase));
|
||||
}
|
||||
|
||||
// Checks if the section object is safe to map. At the moment this just means
|
||||
// it's not an image section.
|
||||
bool IsSectionSafeToMap(HANDLE handle) {
|
||||
static NtQuerySectionType nt_query_section_func =
|
||||
reinterpret_cast<NtQuerySectionType>(
|
||||
::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
|
||||
DCHECK(nt_query_section_func);
|
||||
|
||||
// The handle must have SECTION_QUERY access for this to succeed.
|
||||
SECTION_BASIC_INFORMATION basic_information = {};
|
||||
ULONG status =
|
||||
nt_query_section_func(handle, SectionBasicInformation, &basic_information,
|
||||
sizeof(basic_information), nullptr);
|
||||
if (status)
|
||||
return false;
|
||||
return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
|
||||
}
|
||||
|
||||
// Returns a HANDLE on success and |nullptr| on failure.
|
||||
// This function is similar to CreateFileMapping, but removes the permissions
|
||||
// WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE.
|
||||
//
|
||||
// A newly created file mapping has two sets of permissions. It has access
|
||||
// control permissions (WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE) and
|
||||
// file permissions (FILE_MAP_READ, FILE_MAP_WRITE, etc.). The Chrome sandbox
|
||||
// prevents HANDLEs with the WRITE_DAC permission from being duplicated into
|
||||
// unprivileged processes.
|
||||
//
|
||||
// In order to remove the access control permissions, after being created the
|
||||
// handle is duplicated with only the file access permissions.
|
||||
HANDLE CreateFileMappingWithReducedPermissions(SECURITY_ATTRIBUTES* sa,
|
||||
size_t rounded_size,
|
||||
LPCWSTR name) {
|
||||
HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, sa, PAGE_READWRITE, 0,
|
||||
static_cast<DWORD>(rounded_size), name);
|
||||
if (!h) {
|
||||
LogError(
|
||||
PlatformSharedMemoryRegion::CreateError::CREATE_FILE_MAPPING_FAILURE,
|
||||
GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HANDLE h2;
|
||||
ProcessHandle process = GetCurrentProcess();
|
||||
BOOL success = ::DuplicateHandle(
|
||||
process, h, process, &h2, FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY,
|
||||
FALSE, 0);
|
||||
BOOL rv = ::CloseHandle(h);
|
||||
DCHECK(rv);
|
||||
|
||||
if (!success) {
|
||||
LogError(
|
||||
PlatformSharedMemoryRegion::CreateError::REDUCE_PERMISSIONS_FAILURE,
|
||||
GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return h2;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Take(
|
||||
win::ScopedHandle handle,
|
||||
Mode mode,
|
||||
size_t size,
|
||||
const UnguessableToken& guid) {
|
||||
if (!handle.IsValid())
|
||||
return {};
|
||||
|
||||
if (size == 0)
|
||||
return {};
|
||||
|
||||
if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
|
||||
return {};
|
||||
|
||||
if (!IsSectionSafeToMap(handle.Get()))
|
||||
return {};
|
||||
|
||||
CHECK(
|
||||
CheckPlatformHandlePermissionsCorrespondToMode(handle.Get(), mode, size));
|
||||
|
||||
return PlatformSharedMemoryRegion(std::move(handle), mode, size, guid);
|
||||
}
|
||||
|
||||
HANDLE PlatformSharedMemoryRegion::GetPlatformHandle() const {
|
||||
return handle_.Get();
|
||||
}
|
||||
|
||||
bool PlatformSharedMemoryRegion::IsValid() const {
|
||||
return handle_.IsValid();
|
||||
}
|
||||
|
||||
PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Duplicate() const {
|
||||
if (!IsValid())
|
||||
return {};
|
||||
|
||||
CHECK_NE(mode_, Mode::kWritable)
|
||||
<< "Duplicating a writable shared memory region is prohibited";
|
||||
|
||||
HANDLE duped_handle;
|
||||
ProcessHandle process = GetCurrentProcess();
|
||||
BOOL success =
|
||||
::DuplicateHandle(process, handle_.Get(), process, &duped_handle, 0,
|
||||
FALSE, DUPLICATE_SAME_ACCESS);
|
||||
if (!success)
|
||||
return {};
|
||||
|
||||
return PlatformSharedMemoryRegion(win::ScopedHandle(duped_handle), mode_,
|
||||
size_, guid_);
|
||||
}
|
||||
|
||||
bool PlatformSharedMemoryRegion::ConvertToReadOnly() {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
|
||||
CHECK_EQ(mode_, Mode::kWritable)
|
||||
<< "Only writable shared memory region can be converted to read-only";
|
||||
|
||||
win::ScopedHandle handle_copy(handle_.Take());
|
||||
|
||||
HANDLE duped_handle;
|
||||
ProcessHandle process = GetCurrentProcess();
|
||||
BOOL success =
|
||||
::DuplicateHandle(process, handle_copy.Get(), process, &duped_handle,
|
||||
FILE_MAP_READ | SECTION_QUERY, FALSE, 0);
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
handle_.Set(duped_handle);
|
||||
mode_ = Mode::kReadOnly;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlatformSharedMemoryRegion::ConvertToUnsafe() {
|
||||
if (!IsValid())
|
||||
return false;
|
||||
|
||||
CHECK_EQ(mode_, Mode::kWritable)
|
||||
<< "Only writable shared memory region can be converted to unsafe";
|
||||
|
||||
mode_ = Mode::kUnsafe;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PlatformSharedMemoryRegion::MapAtInternal(off_t offset,
|
||||
size_t size,
|
||||
void** memory,
|
||||
size_t* mapped_size) const {
|
||||
bool write_allowed = mode_ != Mode::kReadOnly;
|
||||
// Try to map the shared memory. On the first failure, release any reserved
|
||||
// address space for a single entry.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
*memory = MapViewOfFile(
|
||||
handle_.Get(), FILE_MAP_READ | (write_allowed ? FILE_MAP_WRITE : 0),
|
||||
static_cast<uint64_t>(offset) >> 32, static_cast<DWORD>(offset), size);
|
||||
if (*memory)
|
||||
break;
|
||||
ReleaseReservation();
|
||||
}
|
||||
if (!*memory) {
|
||||
DPLOG(ERROR) << "Failed executing MapViewOfFile";
|
||||
return false;
|
||||
}
|
||||
|
||||
*mapped_size = GetMemorySectionSize(*memory);
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
|
||||
size_t size) {
|
||||
// TODO(crbug.com/210609): NaCl forces us to round up 64k here, wasting 32k
|
||||
// per mapping on average.
|
||||
static const size_t kSectionSize = 65536;
|
||||
if (size == 0) {
|
||||
LogError(CreateError::SIZE_ZERO, 0);
|
||||
return {};
|
||||
}
|
||||
|
||||
// Aligning may overflow so check that the result doesn't decrease.
|
||||
size_t rounded_size = bits::Align(size, kSectionSize);
|
||||
if (rounded_size < size ||
|
||||
rounded_size > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
LogError(CreateError::SIZE_TOO_LARGE, 0);
|
||||
return {};
|
||||
}
|
||||
|
||||
CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
|
||||
"lead to this region being non-modifiable";
|
||||
|
||||
// Add an empty DACL to enforce anonymous read-only sections.
|
||||
ACL dacl;
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) {
|
||||
LogError(CreateError::INITIALIZE_ACL_FAILURE, GetLastError());
|
||||
return {};
|
||||
}
|
||||
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
|
||||
LogError(CreateError::INITIALIZE_SECURITY_DESC_FAILURE, GetLastError());
|
||||
return {};
|
||||
}
|
||||
if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE)) {
|
||||
LogError(CreateError::SET_SECURITY_DESC_FAILURE, GetLastError());
|
||||
return {};
|
||||
}
|
||||
|
||||
string16 name;
|
||||
if (win::GetVersion() < win::Version::WIN8_1) {
|
||||
// Windows < 8.1 ignores DACLs on certain unnamed objects (like shared
|
||||
// sections). So, we generate a random name when we need to enforce
|
||||
// read-only.
|
||||
uint64_t rand_values[4];
|
||||
RandBytes(&rand_values, sizeof(rand_values));
|
||||
name = ASCIIToUTF16(StringPrintf("CrSharedMem_%016llx%016llx%016llx%016llx",
|
||||
rand_values[0], rand_values[1],
|
||||
rand_values[2], rand_values[3]));
|
||||
DCHECK(!name.empty());
|
||||
}
|
||||
|
||||
SECURITY_ATTRIBUTES sa = {sizeof(sa), &sd, FALSE};
|
||||
// Ask for the file mapping with reduced permisions to avoid passing the
|
||||
// access control permissions granted by default into unpriviledged process.
|
||||
HANDLE h = CreateFileMappingWithReducedPermissions(
|
||||
&sa, rounded_size, name.empty() ? nullptr : as_wcstr(name));
|
||||
if (h == nullptr) {
|
||||
// The error is logged within CreateFileMappingWithReducedPermissions().
|
||||
return {};
|
||||
}
|
||||
|
||||
win::ScopedHandle scoped_h(h);
|
||||
// Check if the shared memory pre-exists.
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
LogError(CreateError::ALREADY_EXISTS, ERROR_ALREADY_EXISTS);
|
||||
return {};
|
||||
}
|
||||
|
||||
LogError(CreateError::SUCCESS, ERROR_SUCCESS);
|
||||
return PlatformSharedMemoryRegion(std::move(scoped_h), mode, size,
|
||||
UnguessableToken::Create());
|
||||
}
|
||||
|
||||
// static
|
||||
bool PlatformSharedMemoryRegion::CheckPlatformHandlePermissionsCorrespondToMode(
|
||||
PlatformHandle handle,
|
||||
Mode mode,
|
||||
size_t size) {
|
||||
// Call ::DuplicateHandle() with FILE_MAP_WRITE as a desired access to check
|
||||
// if the |handle| has a write access.
|
||||
ProcessHandle process = GetCurrentProcess();
|
||||
HANDLE duped_handle;
|
||||
BOOL success = ::DuplicateHandle(process, handle, process, &duped_handle,
|
||||
FILE_MAP_WRITE, FALSE, 0);
|
||||
if (success) {
|
||||
BOOL rv = ::CloseHandle(duped_handle);
|
||||
DCHECK(rv);
|
||||
}
|
||||
|
||||
bool is_read_only = !success;
|
||||
bool expected_read_only = mode == Mode::kReadOnly;
|
||||
|
||||
if (is_read_only != expected_read_only) {
|
||||
DLOG(ERROR) << "File mapping handle has wrong access rights: it is"
|
||||
<< (is_read_only ? " " : " not ") << "read-only but it should"
|
||||
<< (expected_read_only ? " " : " not ") << "be";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
|
||||
win::ScopedHandle handle,
|
||||
Mode mode,
|
||||
size_t size,
|
||||
const UnguessableToken& guid)
|
||||
: handle_(std::move(handle)), mode_(mode), size_(size), guid_(guid) {}
|
||||
|
||||
} // namespace subtle
|
||||
} // namespace base
|
|
@ -4,9 +4,6 @@
|
|||
|
||||
#include "base/memory/ref_counted.h"
|
||||
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/threading/thread_collision_warner.h"
|
||||
|
||||
namespace base {
|
||||
|
@ -35,35 +32,15 @@ RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
|
|||
}
|
||||
#endif
|
||||
|
||||
// For security and correctness, we check the arithmetic on ref counts.
|
||||
//
|
||||
// In an attempt to avoid binary bloat (from inlining the `CHECK`), we define
|
||||
// these functions out-of-line. However, compilers are wily. Further testing may
|
||||
// show that `NOINLINE` helps or hurts.
|
||||
//
|
||||
// This is a security check. In 32-bit-archs, an attacker would run out of
|
||||
// address space after allocating at most 2^32 scoped_refptrs. This replicates
|
||||
// that boundary for 64-bit-archs.
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
void RefCountedBase::AddRefImpl() const {
|
||||
// An attacker could induce use-after-free bugs, and potentially exploit them,
|
||||
// by creating so many references to a ref-counted object that the reference
|
||||
// count overflows. On 32-bit architectures, there is not enough address space
|
||||
// to succeed. But on 64-bit architectures, it might indeed be possible.
|
||||
// Therefore, we can elide the check for arithmetic overflow on 32-bit, but we
|
||||
// must check on 64-bit.
|
||||
//
|
||||
// Make sure the addition didn't wrap back around to 0. This form of check
|
||||
// works because we assert that `ref_count_` is an unsigned integer type.
|
||||
CHECK(++ref_count_ != 0);
|
||||
}
|
||||
|
||||
void RefCountedBase::ReleaseImpl() const {
|
||||
// Make sure the subtraction didn't wrap back around from 0 to the max value.
|
||||
// That could cause memory leaks, and may induce application-semantic
|
||||
// correctness or safety bugs. (E.g. what if we really needed that object to
|
||||
// be destroyed at the right time?)
|
||||
//
|
||||
// Note that unlike with overflow, underflow could also happen on 32-bit
|
||||
// architectures. Arguably, we should do this check on32-bit machines too.
|
||||
CHECK(--ref_count_ != std::numeric_limits<decltype(ref_count_)>::max());
|
||||
// Check if |ref_count_| overflow only on 64 bit archs since the number of
|
||||
// objects may exceed 2^32.
|
||||
// To avoid the binary size bloat, use non-inline function here.
|
||||
CHECK(++ref_count_ > 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ class BASE_EXPORT RefCountedBase {
|
|||
|
||||
// Returns true if the object should self-delete.
|
||||
bool Release() const {
|
||||
ReleaseImpl();
|
||||
--ref_count_;
|
||||
|
||||
// TODO(maruel): Add back once it doesn't assert 500 times/sec.
|
||||
// Current thread books the critical section "AddRelease"
|
||||
|
@ -126,10 +126,8 @@ class BASE_EXPORT RefCountedBase {
|
|||
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
void AddRefImpl() const;
|
||||
void ReleaseImpl() const;
|
||||
#else
|
||||
void AddRefImpl() const { ++ref_count_; }
|
||||
void ReleaseImpl() const { --ref_count_; }
|
||||
#endif
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
|
@ -137,8 +135,6 @@ class BASE_EXPORT RefCountedBase {
|
|||
#endif
|
||||
|
||||
mutable uint32_t ref_count_ = 0;
|
||||
static_assert(std::is_unsigned<decltype(ref_count_)>::value,
|
||||
"ref_count_ must be an unsigned type.");
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
mutable bool needs_adopt_ref_ = false;
|
||||
|
@ -448,16 +444,6 @@ class RefCountedData
|
|||
~RefCountedData() = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool operator==(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
|
||||
return lhs.data == rhs.data;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool operator!=(const RefCountedData<T>& lhs, const RefCountedData<T>& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_REF_COUNTED_H_
|
||||
|
|
|
@ -25,17 +25,10 @@ class RefCounted;
|
|||
template <class, typename>
|
||||
class RefCountedThreadSafe;
|
||||
class SequencedTaskRunner;
|
||||
class WrappedPromise;
|
||||
|
||||
template <typename T>
|
||||
scoped_refptr<T> AdoptRef(T* t);
|
||||
|
||||
namespace internal {
|
||||
|
||||
class BasePromise;
|
||||
|
||||
} // namespace internal
|
||||
|
||||
namespace subtle {
|
||||
|
||||
enum AdoptRefTag { kAdoptRefTag };
|
||||
|
@ -178,16 +171,8 @@ class scoped_refptr {
|
|||
|
||||
constexpr scoped_refptr() = default;
|
||||
|
||||
// Allow implicit construction from nullptr.
|
||||
constexpr scoped_refptr(std::nullptr_t) {}
|
||||
|
||||
// Constructs from a raw pointer. Note that this constructor allows implicit
|
||||
// conversion from T* to scoped_refptr<T> which is strongly discouraged. If
|
||||
// you are creating a new ref-counted object please use
|
||||
// base::MakeRefCounted<T>() or base::WrapRefCounted<T>(). Otherwise you
|
||||
// should move or copy construct from an existing scoped_refptr<T> to the
|
||||
// ref-counted object.
|
||||
scoped_refptr(T* p) : ptr_(p) {
|
||||
// Constructs from raw pointer. constexpr if |p| is null.
|
||||
constexpr scoped_refptr(T* p) : ptr_(p) {
|
||||
if (ptr_)
|
||||
AddRef(ptr_);
|
||||
}
|
||||
|
@ -236,11 +221,6 @@ class scoped_refptr {
|
|||
return ptr_;
|
||||
}
|
||||
|
||||
scoped_refptr& operator=(std::nullptr_t) {
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
scoped_refptr& operator=(T* p) { return *this = scoped_refptr(p); }
|
||||
|
||||
// Unified assignment operator.
|
||||
|
@ -280,11 +260,6 @@ class scoped_refptr {
|
|||
friend scoped_refptr<U> base::AdoptRef(U*);
|
||||
friend class ::base::SequencedTaskRunner;
|
||||
|
||||
// Friend access so these classes can use the constructor below as part of a
|
||||
// binary size optimization.
|
||||
friend class ::base::internal::BasePromise;
|
||||
friend class ::base::WrappedPromise;
|
||||
|
||||
// Returns the owned pointer (if any), releasing ownership to the caller. The
|
||||
// caller is responsible for managing the lifetime of the reference.
|
||||
T* release();
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_MEMORY_SHARED_MEMORY_H_
|
||||
#define BASE_MEMORY_SHARED_MEMORY_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/base_export.h"
|
||||
#include "base/hash.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/memory/shared_memory_handle.h"
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/strings/string16.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_POSIX) || defined(OS_FUCHSIA)
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <semaphore.h>
|
||||
#include "base/file_descriptor_posix.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/files/scoped_file.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/win/scoped_handle.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
class FilePath;
|
||||
|
||||
// Options for creating a shared memory object.
|
||||
struct BASE_EXPORT SharedMemoryCreateOptions {
|
||||
#if !defined(OS_FUCHSIA)
|
||||
// DEPRECATED (crbug.com/345734):
|
||||
// If NULL, the object is anonymous. This pointer is owned by the caller
|
||||
// and must live through the call to Create().
|
||||
const std::string* name_deprecated = nullptr;
|
||||
|
||||
// DEPRECATED (crbug.com/345734):
|
||||
// If true, and the shared memory already exists, Create() will open the
|
||||
// existing shared memory and ignore the size parameter. If false,
|
||||
// shared memory must not exist. This flag is meaningless unless
|
||||
// name_deprecated is non-NULL.
|
||||
bool open_existing_deprecated = false;
|
||||
#endif
|
||||
|
||||
// Size of the shared memory object to be created.
|
||||
// When opening an existing object, this has no effect.
|
||||
size_t size = 0;
|
||||
|
||||
// If true, mappings might need to be made executable later.
|
||||
bool executable = false;
|
||||
|
||||
// If true, the file can be shared read-only to a process.
|
||||
bool share_read_only = false;
|
||||
};
|
||||
|
||||
// Platform abstraction for shared memory.
|
||||
// SharedMemory consumes a SharedMemoryHandle [potentially one that it created]
|
||||
// to map a shared memory OS resource into the virtual address space of the
|
||||
// current process.
|
||||
class BASE_EXPORT SharedMemory {
|
||||
public:
|
||||
SharedMemory();
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Similar to the default constructor, except that this allows for
|
||||
// calling LockDeprecated() to acquire the named mutex before either Create or
|
||||
// Open are called on Windows.
|
||||
explicit SharedMemory(const string16& name);
|
||||
#endif
|
||||
|
||||
// Create a new SharedMemory object from an existing, open
|
||||
// shared memory file.
|
||||
//
|
||||
// WARNING: This does not reduce the OS-level permissions on the handle; it
|
||||
// only affects how the SharedMemory will be mmapped. Use
|
||||
// GetReadOnlyHandle to drop permissions. TODO(jln,jyasskin): DCHECK
|
||||
// that |read_only| matches the permissions of the handle.
|
||||
SharedMemory(const SharedMemoryHandle& handle, bool read_only);
|
||||
|
||||
// Closes any open files.
|
||||
~SharedMemory();
|
||||
|
||||
// Return true iff the given handle is valid (i.e. not the distingished
|
||||
// invalid value; NULL for a HANDLE and -1 for a file descriptor)
|
||||
static bool IsHandleValid(const SharedMemoryHandle& handle);
|
||||
|
||||
// Closes a shared memory handle.
|
||||
static void CloseHandle(const SharedMemoryHandle& handle);
|
||||
|
||||
// Returns the maximum number of handles that can be open at once per process.
|
||||
static size_t GetHandleLimit();
|
||||
|
||||
// Duplicates The underlying OS primitive. Returns an invalid handle on
|
||||
// failure. The caller is responsible for destroying the duplicated OS
|
||||
// primitive.
|
||||
static SharedMemoryHandle DuplicateHandle(const SharedMemoryHandle& handle);
|
||||
|
||||
#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
|
||||
// This method requires that the SharedMemoryHandle is backed by a POSIX fd.
|
||||
static int GetFdFromSharedMemoryHandle(const SharedMemoryHandle& handle);
|
||||
#endif
|
||||
|
||||
// Creates a shared memory object as described by the options struct.
|
||||
// Returns true on success and false on failure.
|
||||
bool Create(const SharedMemoryCreateOptions& options);
|
||||
|
||||
// Creates and maps an anonymous shared memory segment of size size.
|
||||
// Returns true on success and false on failure.
|
||||
bool CreateAndMapAnonymous(size_t size);
|
||||
|
||||
// Creates an anonymous shared memory segment of size size.
|
||||
// Returns true on success and false on failure.
|
||||
bool CreateAnonymous(size_t size) {
|
||||
SharedMemoryCreateOptions options;
|
||||
options.size = size;
|
||||
return Create(options);
|
||||
}
|
||||
|
||||
#if (!defined(OS_MACOSX) || defined(OS_IOS)) && !defined(OS_FUCHSIA)
|
||||
// DEPRECATED (crbug.com/345734):
|
||||
// Creates or opens a shared memory segment based on a name.
|
||||
// If open_existing is true, and the shared memory already exists,
|
||||
// opens the existing shared memory and ignores the size parameter.
|
||||
// If open_existing is false, shared memory must not exist.
|
||||
// size is the size of the block to be created.
|
||||
// Returns true on success, false on failure.
|
||||
bool CreateNamedDeprecated(
|
||||
const std::string& name, bool open_existing, size_t size) {
|
||||
SharedMemoryCreateOptions options;
|
||||
options.name_deprecated = &name;
|
||||
options.open_existing_deprecated = open_existing;
|
||||
options.size = size;
|
||||
return Create(options);
|
||||
}
|
||||
|
||||
// Deletes resources associated with a shared memory segment based on name.
|
||||
// Not all platforms require this call.
|
||||
bool Delete(const std::string& name);
|
||||
|
||||
// Opens a shared memory segment based on a name.
|
||||
// If read_only is true, opens for read-only access.
|
||||
// Returns true on success, false on failure.
|
||||
bool Open(const std::string& name, bool read_only);
|
||||
#endif // !defined(OS_MACOSX) || defined(OS_IOS)
|
||||
|
||||
// Maps the shared memory into the caller's address space.
|
||||
// Returns true on success, false otherwise. The memory address
|
||||
// is accessed via the memory() accessor. The mapped address is guaranteed to
|
||||
// have an alignment of at least MAP_MINIMUM_ALIGNMENT. This method will fail
|
||||
// if this object is currently mapped.
|
||||
bool Map(size_t bytes) {
|
||||
return MapAt(0, bytes);
|
||||
}
|
||||
|
||||
// Same as above, but with |offset| to specify from begining of the shared
|
||||
// memory block to map.
|
||||
// |offset| must be alignent to value of |SysInfo::VMAllocationGranularity()|.
|
||||
bool MapAt(off_t offset, size_t bytes);
|
||||
enum { MAP_MINIMUM_ALIGNMENT = 32 };
|
||||
|
||||
// Unmaps the shared memory from the caller's address space.
|
||||
// Returns true if successful; returns false on error or if the
|
||||
// memory is not mapped.
|
||||
bool Unmap();
|
||||
|
||||
// The size requested when the map is first created.
|
||||
size_t requested_size() const { return requested_size_; }
|
||||
|
||||
// The actual size of the mapped memory (may be larger than requested).
|
||||
size_t mapped_size() const { return mapped_size_; }
|
||||
|
||||
// Gets a pointer to the opened memory space if it has been
|
||||
// Mapped via Map(). Returns NULL if it is not mapped.
|
||||
void* memory() const { return memory_; }
|
||||
|
||||
// Returns the underlying OS handle for this segment.
|
||||
// Use of this handle for anything other than an opaque
|
||||
// identifier is not portable.
|
||||
SharedMemoryHandle handle() const;
|
||||
|
||||
// Returns the underlying OS handle for this segment. The caller takes
|
||||
// ownership of the handle and memory is unmapped. This is equivalent to
|
||||
// duplicating the handle and then calling Unmap() and Close() on this object,
|
||||
// without the overhead of duplicating the handle.
|
||||
SharedMemoryHandle TakeHandle();
|
||||
|
||||
// Closes the open shared memory segment. The memory will remain mapped if
|
||||
// it was previously mapped.
|
||||
// It is safe to call Close repeatedly.
|
||||
void Close();
|
||||
|
||||
// Returns a read-only handle to this shared memory region. The caller takes
|
||||
// ownership of the handle. For POSIX handles, CHECK-fails if the region
|
||||
// wasn't Created or Opened with share_read_only=true, which is required to
|
||||
// make the handle read-only. When the handle is passed to the IPC subsystem,
|
||||
// that takes ownership of the handle. As such, it's not valid to pass the
|
||||
// sample handle to the IPC subsystem twice. Returns an invalid handle on
|
||||
// failure.
|
||||
SharedMemoryHandle GetReadOnlyHandle() const;
|
||||
|
||||
// Returns an ID for the mapped region. This is ID of the SharedMemoryHandle
|
||||
// that was mapped. The ID is valid even after the SharedMemoryHandle is
|
||||
// Closed, as long as the region is not unmapped.
|
||||
const UnguessableToken& mapped_id() const { return mapped_id_; }
|
||||
|
||||
private:
|
||||
#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_ANDROID) && \
|
||||
(!defined(OS_MACOSX) || defined(OS_IOS))
|
||||
bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// If true indicates this came from an external source so needs extra checks
|
||||
// before being mapped.
|
||||
bool external_section_ = false;
|
||||
string16 name_;
|
||||
#elif !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
|
||||
// If valid, points to the same memory region as shm_, but with readonly
|
||||
// permissions.
|
||||
SharedMemoryHandle readonly_shm_;
|
||||
#endif
|
||||
|
||||
// The OS primitive that backs the shared memory region.
|
||||
SharedMemoryHandle shm_;
|
||||
|
||||
size_t mapped_size_ = 0;
|
||||
void* memory_ = nullptr;
|
||||
bool read_only_ = false;
|
||||
size_t requested_size_ = 0;
|
||||
base::UnguessableToken mapped_id_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SharedMemory);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_SHARED_MEMORY_H_
|
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2017 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/memory/shared_memory_handle.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
SharedMemoryHandle::SharedMemoryHandle(const SharedMemoryHandle& handle) =
|
||||
default;
|
||||
|
||||
SharedMemoryHandle& SharedMemoryHandle::operator=(
|
||||
const SharedMemoryHandle& handle) = default;
|
||||
|
||||
base::UnguessableToken SharedMemoryHandle::GetGUID() const {
|
||||
return guid_;
|
||||
}
|
||||
|
||||
size_t SharedMemoryHandle::GetSize() const {
|
||||
return size_;
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -0,0 +1,220 @@
|
|||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
|
||||
#define BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "base/unguessable_token.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/win/windows_types.h"
|
||||
#elif defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include <mach/mach.h>
|
||||
#include "base/base_export.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/process/process_handle.h"
|
||||
#elif defined(OS_POSIX)
|
||||
#include <sys/types.h>
|
||||
#include "base/file_descriptor_posix.h"
|
||||
#elif defined(OS_FUCHSIA)
|
||||
#include <zircon/types.h>
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
// SharedMemoryHandle is the smallest possible IPC-transportable "reference" to
|
||||
// a shared memory OS resource. A "reference" can be consumed exactly once [by
|
||||
// base::SharedMemory] to map the shared memory OS resource into the virtual
|
||||
// address space of the current process.
|
||||
// TODO(erikchen): This class should have strong ownership semantics to prevent
|
||||
// leaks of the underlying OS resource. https://crbug.com/640840.
|
||||
class BASE_EXPORT SharedMemoryHandle {
|
||||
public:
|
||||
// The default constructor returns an invalid SharedMemoryHandle.
|
||||
SharedMemoryHandle();
|
||||
|
||||
// Standard copy constructor. The new instance shares the underlying OS
|
||||
// primitives.
|
||||
SharedMemoryHandle(const SharedMemoryHandle& handle);
|
||||
|
||||
// Standard assignment operator. The updated instance shares the underlying
|
||||
// OS primitives.
|
||||
SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
|
||||
|
||||
// Closes the underlying OS resource.
|
||||
// The fact that this method needs to be "const" is an artifact of the
|
||||
// original interface for base::SharedMemory::CloseHandle.
|
||||
// TODO(erikchen): This doesn't clear the underlying reference, which seems
|
||||
// like a bug, but is how this class has always worked. Fix this:
|
||||
// https://crbug.com/716072.
|
||||
void Close() const;
|
||||
|
||||
// Whether ownership of the underlying OS resource is implicitly passed to
|
||||
// the IPC subsystem during serialization.
|
||||
void SetOwnershipPassesToIPC(bool ownership_passes);
|
||||
bool OwnershipPassesToIPC() const;
|
||||
|
||||
// Whether the underlying OS resource is valid.
|
||||
bool IsValid() const;
|
||||
|
||||
// Duplicates the underlying OS resource. Using the return value as a
|
||||
// parameter to an IPC message will cause the IPC subsystem to consume the OS
|
||||
// resource.
|
||||
SharedMemoryHandle Duplicate() const;
|
||||
|
||||
// Uniques identifies the shared memory region that the underlying OS resource
|
||||
// points to. Multiple SharedMemoryHandles that point to the same shared
|
||||
// memory region will have the same GUID. Preserved across IPC.
|
||||
base::UnguessableToken GetGUID() const;
|
||||
|
||||
// Returns the size of the memory region that SharedMemoryHandle points to.
|
||||
size_t GetSize() const;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Takes implicit ownership of |h|.
|
||||
// |guid| uniquely identifies the shared memory region pointed to by the
|
||||
// underlying OS resource. If the HANDLE is associated with another
|
||||
// SharedMemoryHandle, the caller must pass the |guid| of that
|
||||
// SharedMemoryHandle. Otherwise, the caller should generate a new
|
||||
// UnguessableToken.
|
||||
// Passing the wrong |size| has no immediate consequence, but may cause errors
|
||||
// when trying to map the SharedMemoryHandle at a later point in time.
|
||||
SharedMemoryHandle(HANDLE h, size_t size, const base::UnguessableToken& guid);
|
||||
HANDLE GetHandle() const;
|
||||
#elif defined(OS_FUCHSIA)
|
||||
// Takes implicit ownership of |h|.
|
||||
// |guid| uniquely identifies the shared memory region pointed to by the
|
||||
// underlying OS resource. If the zx_handle_t is associated with another
|
||||
// SharedMemoryHandle, the caller must pass the |guid| of that
|
||||
// SharedMemoryHandle. Otherwise, the caller should generate a new
|
||||
// UnguessableToken.
|
||||
// Passing the wrong |size| has no immediate consequence, but may cause errors
|
||||
// when trying to map the SharedMemoryHandle at a later point in time.
|
||||
SharedMemoryHandle(zx_handle_t h,
|
||||
size_t size,
|
||||
const base::UnguessableToken& guid);
|
||||
zx_handle_t GetHandle() const;
|
||||
#elif defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
// Makes a Mach-based SharedMemoryHandle of the given size. On error,
|
||||
// subsequent calls to IsValid() return false.
|
||||
// Passing the wrong |size| has no immediate consequence, but may cause errors
|
||||
// when trying to map the SharedMemoryHandle at a later point in time.
|
||||
SharedMemoryHandle(mach_vm_size_t size, const base::UnguessableToken& guid);
|
||||
|
||||
// Makes a Mach-based SharedMemoryHandle from |memory_object|, a named entry
|
||||
// in the current task. The memory region has size |size|.
|
||||
// Passing the wrong |size| has no immediate consequence, but may cause errors
|
||||
// when trying to map the SharedMemoryHandle at a later point in time.
|
||||
SharedMemoryHandle(mach_port_t memory_object,
|
||||
mach_vm_size_t size,
|
||||
const base::UnguessableToken& guid);
|
||||
|
||||
// Exposed so that the SharedMemoryHandle can be transported between
|
||||
// processes.
|
||||
mach_port_t GetMemoryObject() const;
|
||||
|
||||
// The SharedMemoryHandle must be valid.
|
||||
// Returns whether the SharedMemoryHandle was successfully mapped into memory.
|
||||
// On success, |memory| is an output variable that contains the start of the
|
||||
// mapped memory.
|
||||
bool MapAt(off_t offset, size_t bytes, void** memory, bool read_only);
|
||||
#elif defined(OS_POSIX)
|
||||
// Creates a SharedMemoryHandle from an |fd| supplied from an external
|
||||
// service.
|
||||
// Passing the wrong |size| has no immediate consequence, but may cause errors
|
||||
// when trying to map the SharedMemoryHandle at a later point in time.
|
||||
static SharedMemoryHandle ImportHandle(int fd, size_t size);
|
||||
|
||||
// Returns the underlying OS resource.
|
||||
int GetHandle() const;
|
||||
|
||||
// Invalidates [but doesn't close] the underlying OS resource. This will leak
|
||||
// unless the caller is careful.
|
||||
int Release();
|
||||
#endif
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
// Marks the current file descriptor as read-only, for the purpose of
|
||||
// mapping. This is independent of the region's read-only status.
|
||||
void SetReadOnly() { read_only_ = true; }
|
||||
|
||||
// Returns true iff the descriptor is to be used for read-only
|
||||
// mappings.
|
||||
bool IsReadOnly() const { return read_only_; }
|
||||
|
||||
// Returns true iff the corresponding region is read-only.
|
||||
bool IsRegionReadOnly() const;
|
||||
|
||||
// Try to set the region read-only. This will fail any future attempt
|
||||
// at read-write mapping.
|
||||
bool SetRegionReadOnly() const;
|
||||
#endif
|
||||
|
||||
#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
|
||||
// Constructs a SharedMemoryHandle backed by a FileDescriptor. The newly
|
||||
// created instance has the same ownership semantics as base::FileDescriptor.
|
||||
// This typically means that the SharedMemoryHandle takes ownership of the
|
||||
// |fd| if |auto_close| is true. Unfortunately, it's common for existing code
|
||||
// to make shallow copies of SharedMemoryHandle, and the one that is finally
|
||||
// passed into a base::SharedMemory is the one that "consumes" the fd.
|
||||
//
|
||||
// |guid| uniquely identifies the shared memory region pointed to by the
|
||||
// underlying OS resource. If |file_descriptor| is associated with another
|
||||
// SharedMemoryHandle, the caller must pass the |guid| of that
|
||||
// SharedMemoryHandle. Otherwise, the caller should generate a new
|
||||
// UnguessableToken.
|
||||
// Passing the wrong |size| has no immediate consequence, but may cause errors
|
||||
// when trying to map the SharedMemoryHandle at a later point in time.
|
||||
SharedMemoryHandle(const base::FileDescriptor& file_descriptor,
|
||||
size_t size,
|
||||
const base::UnguessableToken& guid);
|
||||
#endif
|
||||
|
||||
private:
|
||||
#if defined(OS_WIN)
|
||||
HANDLE handle_ = nullptr;
|
||||
|
||||
// Whether passing this object as a parameter to an IPC message passes
|
||||
// ownership of |handle_| to the IPC stack. This is meant to mimic the
|
||||
// behavior of the |auto_close| parameter of FileDescriptor. This member only
|
||||
// affects attachment-brokered SharedMemoryHandles.
|
||||
// Defaults to |false|.
|
||||
bool ownership_passes_to_ipc_ = false;
|
||||
#elif defined(OS_FUCHSIA)
|
||||
zx_handle_t handle_ = ZX_HANDLE_INVALID;
|
||||
bool ownership_passes_to_ipc_ = false;
|
||||
#elif defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
friend class SharedMemory;
|
||||
friend bool CheckReadOnlySharedMemoryHandleForTesting(
|
||||
SharedMemoryHandle handle);
|
||||
|
||||
mach_port_t memory_object_ = MACH_PORT_NULL;
|
||||
|
||||
// Whether passing this object as a parameter to an IPC message passes
|
||||
// ownership of |memory_object_| to the IPC stack. This is meant to mimic
|
||||
// the behavior of the |auto_close| parameter of FileDescriptor.
|
||||
// Defaults to |false|.
|
||||
bool ownership_passes_to_ipc_ = false;
|
||||
#elif defined(OS_ANDROID)
|
||||
friend class SharedMemory;
|
||||
|
||||
FileDescriptor file_descriptor_;
|
||||
bool read_only_ = false;
|
||||
#elif defined(OS_POSIX)
|
||||
FileDescriptor file_descriptor_;
|
||||
#endif
|
||||
|
||||
base::UnguessableToken guid_;
|
||||
|
||||
// The size of the region referenced by the SharedMemoryHandle.
|
||||
size_t size_ = 0;
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/memory/shared_memory_handle.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/unguessable_token.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace base {
|
||||
|
||||
SharedMemoryHandle::SharedMemoryHandle() {}
|
||||
|
||||
SharedMemoryHandle::SharedMemoryHandle(HANDLE h,
|
||||
size_t size,
|
||||
const base::UnguessableToken& guid)
|
||||
: handle_(h), guid_(guid), size_(size) {}
|
||||
|
||||
void SharedMemoryHandle::Close() const {
|
||||
DCHECK(handle_ != nullptr);
|
||||
::CloseHandle(handle_);
|
||||
}
|
||||
|
||||
bool SharedMemoryHandle::IsValid() const {
|
||||
return handle_ != nullptr;
|
||||
}
|
||||
|
||||
SharedMemoryHandle SharedMemoryHandle::Duplicate() const {
|
||||
HANDLE duped_handle;
|
||||
ProcessHandle process = GetCurrentProcess();
|
||||
BOOL success = ::DuplicateHandle(process, handle_, process, &duped_handle, 0,
|
||||
FALSE, DUPLICATE_SAME_ACCESS);
|
||||
if (!success)
|
||||
return SharedMemoryHandle();
|
||||
|
||||
base::SharedMemoryHandle handle(duped_handle, GetSize(), GetGUID());
|
||||
handle.SetOwnershipPassesToIPC(true);
|
||||
return handle;
|
||||
}
|
||||
|
||||
HANDLE SharedMemoryHandle::GetHandle() const {
|
||||
return handle_;
|
||||
}
|
||||
|
||||
void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
|
||||
ownership_passes_to_ipc_ = ownership_passes;
|
||||
}
|
||||
|
||||
bool SharedMemoryHandle::OwnershipPassesToIPC() const {
|
||||
return ownership_passes_to_ipc_;
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -1,115 +0,0 @@
|
|||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/memory/shared_memory_mapping.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/shared_memory_tracker.h"
|
||||
#include "base/unguessable_token.h"
|
||||
#include "build/build_config.h"
|
||||
|
||||
#if defined(OS_POSIX)
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <aclapi.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
#include <mach/mach_vm.h>
|
||||
#include "base/mac/mach_logging.h"
|
||||
#endif
|
||||
|
||||
#if defined(OS_FUCHSIA)
|
||||
#include <lib/zx/vmar.h>
|
||||
#include "base/fuchsia/fuchsia_logging.h"
|
||||
#endif
|
||||
|
||||
namespace base {
|
||||
|
||||
SharedMemoryMapping::SharedMemoryMapping() = default;
|
||||
|
||||
SharedMemoryMapping::SharedMemoryMapping(SharedMemoryMapping&& mapping) noexcept
|
||||
: memory_(mapping.memory_),
|
||||
size_(mapping.size_),
|
||||
mapped_size_(mapping.mapped_size_),
|
||||
guid_(mapping.guid_) {
|
||||
mapping.memory_ = nullptr;
|
||||
}
|
||||
|
||||
SharedMemoryMapping& SharedMemoryMapping::operator=(
|
||||
SharedMemoryMapping&& mapping) noexcept {
|
||||
Unmap();
|
||||
memory_ = mapping.memory_;
|
||||
size_ = mapping.size_;
|
||||
mapped_size_ = mapping.mapped_size_;
|
||||
guid_ = mapping.guid_;
|
||||
mapping.memory_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
SharedMemoryMapping::~SharedMemoryMapping() {
|
||||
Unmap();
|
||||
}
|
||||
|
||||
SharedMemoryMapping::SharedMemoryMapping(void* memory,
|
||||
size_t size,
|
||||
size_t mapped_size,
|
||||
const UnguessableToken& guid)
|
||||
: memory_(memory), size_(size), mapped_size_(mapped_size), guid_(guid) {
|
||||
SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
|
||||
}
|
||||
|
||||
void SharedMemoryMapping::Unmap() {
|
||||
if (!IsValid())
|
||||
return;
|
||||
|
||||
SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
|
||||
#if defined(OS_WIN)
|
||||
if (!UnmapViewOfFile(memory_))
|
||||
DPLOG(ERROR) << "UnmapViewOfFile";
|
||||
#elif defined(OS_FUCHSIA)
|
||||
uintptr_t addr = reinterpret_cast<uintptr_t>(memory_);
|
||||
zx_status_t status = zx::vmar::root_self()->unmap(addr, mapped_size_);
|
||||
if (status != ZX_OK)
|
||||
ZX_DLOG(ERROR, status) << "zx_vmar_unmap";
|
||||
#elif defined(OS_MACOSX) && !defined(OS_IOS)
|
||||
kern_return_t kr = mach_vm_deallocate(
|
||||
mach_task_self(), reinterpret_cast<mach_vm_address_t>(memory_),
|
||||
mapped_size_);
|
||||
MACH_DLOG_IF(ERROR, kr != KERN_SUCCESS, kr) << "mach_vm_deallocate";
|
||||
#else
|
||||
if (munmap(memory_, mapped_size_) < 0)
|
||||
DPLOG(ERROR) << "munmap";
|
||||
#endif
|
||||
}
|
||||
|
||||
ReadOnlySharedMemoryMapping::ReadOnlySharedMemoryMapping() = default;
|
||||
ReadOnlySharedMemoryMapping::ReadOnlySharedMemoryMapping(
|
||||
ReadOnlySharedMemoryMapping&&) noexcept = default;
|
||||
ReadOnlySharedMemoryMapping& ReadOnlySharedMemoryMapping::operator=(
|
||||
ReadOnlySharedMemoryMapping&&) noexcept = default;
|
||||
ReadOnlySharedMemoryMapping::ReadOnlySharedMemoryMapping(
|
||||
void* address,
|
||||
size_t size,
|
||||
size_t mapped_size,
|
||||
const UnguessableToken& guid)
|
||||
: SharedMemoryMapping(address, size, mapped_size, guid) {}
|
||||
|
||||
WritableSharedMemoryMapping::WritableSharedMemoryMapping() = default;
|
||||
WritableSharedMemoryMapping::WritableSharedMemoryMapping(
|
||||
WritableSharedMemoryMapping&&) noexcept = default;
|
||||
WritableSharedMemoryMapping& WritableSharedMemoryMapping::operator=(
|
||||
WritableSharedMemoryMapping&&) noexcept = default;
|
||||
WritableSharedMemoryMapping::WritableSharedMemoryMapping(
|
||||
void* address,
|
||||
size_t size,
|
||||
size_t mapped_size,
|
||||
const UnguessableToken& guid)
|
||||
: SharedMemoryMapping(address, size, mapped_size, guid) {}
|
||||
|
||||
} // namespace base
|
|
@ -1,252 +0,0 @@
|
|||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
|
||||
#define BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
|
||||
#include "base/containers/buffer_iterator.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "base/macros.h"
|
||||
#include "base/unguessable_token.h"
|
||||
|
||||
namespace base {
|
||||
|
||||
namespace subtle {
|
||||
class PlatformSharedMemoryRegion;
|
||||
} // namespace subtle
|
||||
|
||||
// Base class for scoped handles to a shared memory mapping created from a
|
||||
// shared memory region. Created shared memory mappings remain valid even if the
|
||||
// creator region is transferred or destroyed.
|
||||
//
|
||||
// Each mapping has an UnguessableToken that identifies the shared memory region
|
||||
// it was created from. This is used for memory metrics, to avoid overcounting
|
||||
// shared memory.
|
||||
class BASE_EXPORT SharedMemoryMapping {
|
||||
public:
|
||||
// Default constructor initializes an invalid instance.
|
||||
SharedMemoryMapping();
|
||||
|
||||
// Move operations are allowed.
|
||||
SharedMemoryMapping(SharedMemoryMapping&& mapping) noexcept;
|
||||
SharedMemoryMapping& operator=(SharedMemoryMapping&& mapping) noexcept;
|
||||
|
||||
// Unmaps the region if the mapping is valid.
|
||||
virtual ~SharedMemoryMapping();
|
||||
|
||||
// Returns true iff the mapping is valid. False means there is no
|
||||
// corresponding area of memory.
|
||||
bool IsValid() const { return memory_ != nullptr; }
|
||||
|
||||
// Returns the logical size of the mapping in bytes. This is precisely the
|
||||
// size requested by whoever created the mapping, and it is always less than
|
||||
// or equal to |mapped_size()|. This is undefined for invalid instances.
|
||||
size_t size() const {
|
||||
DCHECK(IsValid());
|
||||
return size_;
|
||||
}
|
||||
|
||||
// Returns the actual size of the mapping in bytes. This is always at least
|
||||
// as large as |size()| but may be larger due to platform mapping alignment
|
||||
// constraints. This is undefined for invalid instances.
|
||||
size_t mapped_size() const {
|
||||
DCHECK(IsValid());
|
||||
return mapped_size_;
|
||||
}
|
||||
|
||||
// Returns 128-bit GUID of the region this mapping belongs to.
|
||||
const UnguessableToken& guid() const {
|
||||
DCHECK(IsValid());
|
||||
return guid_;
|
||||
}
|
||||
|
||||
protected:
|
||||
SharedMemoryMapping(void* address,
|
||||
size_t size,
|
||||
size_t mapped_size,
|
||||
const UnguessableToken& guid);
|
||||
void* raw_memory_ptr() const { return memory_; }
|
||||
|
||||
private:
|
||||
friend class SharedMemoryTracker;
|
||||
|
||||
void Unmap();
|
||||
|
||||
void* memory_ = nullptr;
|
||||
size_t size_ = 0;
|
||||
size_t mapped_size_ = 0;
|
||||
UnguessableToken guid_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SharedMemoryMapping);
|
||||
};
|
||||
|
||||
// Class modeling a read-only mapping of a shared memory region into the
|
||||
// current process' address space. This is created by ReadOnlySharedMemoryRegion
|
||||
// instances.
|
||||
class BASE_EXPORT ReadOnlySharedMemoryMapping : public SharedMemoryMapping {
|
||||
public:
|
||||
// Default constructor initializes an invalid instance.
|
||||
ReadOnlySharedMemoryMapping();
|
||||
|
||||
// Move operations are allowed.
|
||||
ReadOnlySharedMemoryMapping(ReadOnlySharedMemoryMapping&&) noexcept;
|
||||
ReadOnlySharedMemoryMapping& operator=(
|
||||
ReadOnlySharedMemoryMapping&&) noexcept;
|
||||
|
||||
// Returns the base address of the mapping. This is read-only memory. This is
|
||||
// page-aligned. This is nullptr for invalid instances.
|
||||
const void* memory() const { return raw_memory_ptr(); }
|
||||
|
||||
// Returns a pointer to a page-aligned const T if the mapping is valid and
|
||||
// large enough to contain a T, or nullptr otherwise.
|
||||
template <typename T>
|
||||
const T* GetMemoryAs() const {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Copying non-trivially-copyable object across memory spaces "
|
||||
"is dangerous");
|
||||
if (!IsValid())
|
||||
return nullptr;
|
||||
if (sizeof(T) > size())
|
||||
return nullptr;
|
||||
return static_cast<const T*>(raw_memory_ptr());
|
||||
}
|
||||
|
||||
// Returns a span of const T. The number of elements is autodeduced from the
|
||||
// size of the shared memory mapping. The number of elements may be
|
||||
// autodeduced as zero, i.e. the mapping is invalid or the size of the mapping
|
||||
// isn't large enough to contain even one T: in that case, an empty span
|
||||
// will be returned. The first element, if any, is guaranteed to be
|
||||
// page-aligned.
|
||||
template <typename T>
|
||||
span<const T> GetMemoryAsSpan() const {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Copying non-trivially-copyable object across memory spaces "
|
||||
"is dangerous");
|
||||
if (!IsValid())
|
||||
return span<const T>();
|
||||
size_t count = size() / sizeof(T);
|
||||
return GetMemoryAsSpan<T>(count);
|
||||
}
|
||||
|
||||
// Returns a span of const T with |count| elements if the mapping is valid and
|
||||
// large enough to contain |count| elements, or an empty span otherwise. The
|
||||
// first element, if any, is guaranteed to be page-aligned.
|
||||
template <typename T>
|
||||
span<const T> GetMemoryAsSpan(size_t count) const {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Copying non-trivially-copyable object across memory spaces "
|
||||
"is dangerous");
|
||||
if (!IsValid())
|
||||
return span<const T>();
|
||||
if (size() / sizeof(T) < count)
|
||||
return span<const T>();
|
||||
return span<const T>(static_cast<const T*>(raw_memory_ptr()), count);
|
||||
}
|
||||
|
||||
// Returns a BufferIterator of const T.
|
||||
template <typename T>
|
||||
BufferIterator<const T> GetMemoryAsBufferIterator() const {
|
||||
return BufferIterator<const T>(GetMemoryAsSpan<T>());
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ReadOnlySharedMemoryRegion;
|
||||
ReadOnlySharedMemoryMapping(void* address,
|
||||
size_t size,
|
||||
size_t mapped_size,
|
||||
const UnguessableToken& guid);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ReadOnlySharedMemoryMapping);
|
||||
};
|
||||
|
||||
// Class modeling a writable mapping of a shared memory region into the
|
||||
// current process' address space. This is created by *SharedMemoryRegion
|
||||
// instances.
|
||||
class BASE_EXPORT WritableSharedMemoryMapping : public SharedMemoryMapping {
|
||||
public:
|
||||
// Default constructor initializes an invalid instance.
|
||||
WritableSharedMemoryMapping();
|
||||
|
||||
// Move operations are allowed.
|
||||
WritableSharedMemoryMapping(WritableSharedMemoryMapping&&) noexcept;
|
||||
WritableSharedMemoryMapping& operator=(
|
||||
WritableSharedMemoryMapping&&) noexcept;
|
||||
|
||||
// Returns the base address of the mapping. This is writable memory. This is
|
||||
// page-aligned. This is nullptr for invalid instances.
|
||||
void* memory() const { return raw_memory_ptr(); }
|
||||
|
||||
// Returns a pointer to a page-aligned T if the mapping is valid and large
|
||||
// enough to contain a T, or nullptr otherwise.
|
||||
template <typename T>
|
||||
T* GetMemoryAs() const {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Copying non-trivially-copyable object across memory spaces "
|
||||
"is dangerous");
|
||||
if (!IsValid())
|
||||
return nullptr;
|
||||
if (sizeof(T) > size())
|
||||
return nullptr;
|
||||
return static_cast<T*>(raw_memory_ptr());
|
||||
}
|
||||
|
||||
// Returns a span of T. The number of elements is autodeduced from the size of
|
||||
// the shared memory mapping. The number of elements may be autodeduced as
|
||||
// zero, i.e. the mapping is invalid or the size of the mapping isn't large
|
||||
// enough to contain even one T: in that case, an empty span will be returned.
|
||||
// The first element, if any, is guaranteed to be page-aligned.
|
||||
template <typename T>
|
||||
span<T> GetMemoryAsSpan() const {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Copying non-trivially-copyable object across memory spaces "
|
||||
"is dangerous");
|
||||
if (!IsValid())
|
||||
return span<T>();
|
||||
size_t count = size() / sizeof(T);
|
||||
return GetMemoryAsSpan<T>(count);
|
||||
}
|
||||
|
||||
// Returns a span of T with |count| elements if the mapping is valid and large
|
||||
// enough to contain |count| elements, or an empty span otherwise. The first
|
||||
// element, if any, is guaranteed to be page-aligned.
|
||||
template <typename T>
|
||||
span<T> GetMemoryAsSpan(size_t count) const {
|
||||
static_assert(std::is_trivially_copyable<T>::value,
|
||||
"Copying non-trivially-copyable object across memory spaces "
|
||||
"is dangerous");
|
||||
if (!IsValid())
|
||||
return span<T>();
|
||||
if (size() / sizeof(T) < count)
|
||||
return span<T>();
|
||||
return span<T>(static_cast<T*>(raw_memory_ptr()), count);
|
||||
}
|
||||
|
||||
// Returns a BufferIterator of T.
|
||||
template <typename T>
|
||||
BufferIterator<T> GetMemoryAsBufferIterator() {
|
||||
return BufferIterator<T>(GetMemoryAsSpan<T>());
|
||||
}
|
||||
|
||||
private:
|
||||
friend WritableSharedMemoryMapping MapAtForTesting(
|
||||
subtle::PlatformSharedMemoryRegion* region,
|
||||
off_t offset,
|
||||
size_t size);
|
||||
friend class ReadOnlySharedMemoryRegion;
|
||||
friend class WritableSharedMemoryRegion;
|
||||
friend class UnsafeSharedMemoryRegion;
|
||||
WritableSharedMemoryMapping(void* address,
|
||||
size_t size,
|
||||
size_t mapped_size,
|
||||
const UnguessableToken& guid);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WritableSharedMemoryMapping);
|
||||
};
|
||||
|
||||
} // namespace base
|
||||
|
||||
#endif // BASE_MEMORY_SHARED_MEMORY_MAPPING_H_
|
|
@ -0,0 +1,388 @@
|
|||
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/memory/shared_memory.h"
|
||||
|
||||
#include <aclapi.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/allocator/partition_allocator/page_allocator.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/shared_memory_tracker.h"
|
||||
#include "base/metrics/histogram_functions.h"
|
||||
#include "base/metrics/histogram_macros.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/strings/utf_string_conversions.h"
|
||||
#include "base/unguessable_token.h"
|
||||
#include "base/win/windows_version.h"
|
||||
|
||||
namespace base {
|
||||
namespace {
|
||||
|
||||
// Errors that can occur during Shared Memory construction.
|
||||
// These match tools/metrics/histograms/histograms.xml.
|
||||
// This enum is append-only.
|
||||
enum CreateError {
|
||||
SUCCESS = 0,
|
||||
SIZE_ZERO = 1,
|
||||
SIZE_TOO_LARGE = 2,
|
||||
INITIALIZE_ACL_FAILURE = 3,
|
||||
INITIALIZE_SECURITY_DESC_FAILURE = 4,
|
||||
SET_SECURITY_DESC_FAILURE = 5,
|
||||
CREATE_FILE_MAPPING_FAILURE = 6,
|
||||
REDUCE_PERMISSIONS_FAILURE = 7,
|
||||
ALREADY_EXISTS = 8,
|
||||
CREATE_ERROR_LAST = ALREADY_EXISTS
|
||||
};
|
||||
|
||||
// Emits UMA metrics about encountered errors. Pass zero (0) for |winerror|
|
||||
// if there is no associated Windows error.
|
||||
void LogError(CreateError error, DWORD winerror) {
|
||||
UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error,
|
||||
CREATE_ERROR_LAST + 1);
|
||||
static_assert(ERROR_SUCCESS == 0, "Windows error code changed!");
|
||||
if (winerror != ERROR_SUCCESS)
|
||||
UmaHistogramSparse("SharedMemory.CreateWinError", winerror);
|
||||
}
|
||||
|
||||
typedef enum _SECTION_INFORMATION_CLASS {
|
||||
SectionBasicInformation,
|
||||
} SECTION_INFORMATION_CLASS;
|
||||
|
||||
typedef struct _SECTION_BASIC_INFORMATION {
|
||||
PVOID BaseAddress;
|
||||
ULONG Attributes;
|
||||
LARGE_INTEGER Size;
|
||||
} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
|
||||
|
||||
typedef ULONG(__stdcall* NtQuerySectionType)(
|
||||
HANDLE SectionHandle,
|
||||
SECTION_INFORMATION_CLASS SectionInformationClass,
|
||||
PVOID SectionInformation,
|
||||
ULONG SectionInformationLength,
|
||||
PULONG ResultLength);
|
||||
|
||||
// Returns the length of the memory section starting at the supplied address.
|
||||
size_t GetMemorySectionSize(void* address) {
|
||||
MEMORY_BASIC_INFORMATION memory_info;
|
||||
if (!::VirtualQuery(address, &memory_info, sizeof(memory_info)))
|
||||
return 0;
|
||||
return memory_info.RegionSize - (static_cast<char*>(address) -
|
||||
static_cast<char*>(memory_info.AllocationBase));
|
||||
}
|
||||
|
||||
// Checks if the section object is safe to map. At the moment this just means
|
||||
// it's not an image section.
|
||||
bool IsSectionSafeToMap(HANDLE handle) {
|
||||
static NtQuerySectionType nt_query_section_func;
|
||||
if (!nt_query_section_func) {
|
||||
nt_query_section_func = reinterpret_cast<NtQuerySectionType>(
|
||||
::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
|
||||
DCHECK(nt_query_section_func);
|
||||
}
|
||||
|
||||
// The handle must have SECTION_QUERY access for this to succeed.
|
||||
SECTION_BASIC_INFORMATION basic_information = {};
|
||||
ULONG status =
|
||||
nt_query_section_func(handle, SectionBasicInformation, &basic_information,
|
||||
sizeof(basic_information), nullptr);
|
||||
if (status)
|
||||
return false;
|
||||
return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
|
||||
}
|
||||
|
||||
// Returns a HANDLE on success and |nullptr| on failure.
|
||||
// This function is similar to CreateFileMapping, but removes the permissions
|
||||
// WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE.
|
||||
//
|
||||
// A newly created file mapping has two sets of permissions. It has access
|
||||
// control permissions (WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE) and
|
||||
// file permissions (FILE_MAP_READ, FILE_MAP_WRITE, etc.). ::DuplicateHandle()
|
||||
// with the parameter DUPLICATE_SAME_ACCESS copies both sets of permissions.
|
||||
//
|
||||
// The Chrome sandbox prevents HANDLEs with the WRITE_DAC permission from being
|
||||
// duplicated into unprivileged processes. But the only way to copy file
|
||||
// permissions is with the parameter DUPLICATE_SAME_ACCESS. This means that
|
||||
// there is no way for a privileged process to duplicate a file mapping into an
|
||||
// unprivileged process while maintaining the previous file permissions.
|
||||
//
|
||||
// By removing all access control permissions of a file mapping immediately
|
||||
// after creation, ::DuplicateHandle() effectively only copies the file
|
||||
// permissions.
|
||||
HANDLE CreateFileMappingWithReducedPermissions(SECURITY_ATTRIBUTES* sa,
|
||||
size_t rounded_size,
|
||||
LPCWSTR name) {
|
||||
HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, sa, PAGE_READWRITE, 0,
|
||||
static_cast<DWORD>(rounded_size), name);
|
||||
if (!h) {
|
||||
LogError(CREATE_FILE_MAPPING_FAILURE, GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HANDLE h2;
|
||||
BOOL success = ::DuplicateHandle(
|
||||
GetCurrentProcess(), h, GetCurrentProcess(), &h2,
|
||||
FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY, FALSE, 0);
|
||||
BOOL rv = ::CloseHandle(h);
|
||||
DCHECK(rv);
|
||||
|
||||
if (!success) {
|
||||
LogError(REDUCE_PERMISSIONS_FAILURE, GetLastError());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return h2;
|
||||
}
|
||||
|
||||
} // namespace.
|
||||
|
||||
SharedMemory::SharedMemory() {}
|
||||
|
||||
SharedMemory::SharedMemory(const string16& name) : name_(name) {}
|
||||
|
||||
SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
|
||||
: external_section_(true), shm_(handle), read_only_(read_only) {}
|
||||
|
||||
SharedMemory::~SharedMemory() {
|
||||
Unmap();
|
||||
Close();
|
||||
}
|
||||
|
||||
// static
|
||||
bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
|
||||
return handle.IsValid();
|
||||
}
|
||||
|
||||
// static
|
||||
void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
|
||||
handle.Close();
|
||||
}
|
||||
|
||||
// static
|
||||
size_t SharedMemory::GetHandleLimit() {
|
||||
// Rounded down from value reported here:
|
||||
// http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx
|
||||
return static_cast<size_t>(1 << 23);
|
||||
}
|
||||
|
||||
// static
|
||||
SharedMemoryHandle SharedMemory::DuplicateHandle(
|
||||
const SharedMemoryHandle& handle) {
|
||||
return handle.Duplicate();
|
||||
}
|
||||
|
||||
bool SharedMemory::CreateAndMapAnonymous(size_t size) {
|
||||
return CreateAnonymous(size) && Map(size);
|
||||
}
|
||||
|
||||
bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
|
||||
// TODO(crbug.com/210609): NaCl forces us to round up 64k here, wasting 32k
|
||||
// per mapping on average.
|
||||
static const size_t kSectionMask = 65536 - 1;
|
||||
DCHECK(!options.executable);
|
||||
DCHECK(!shm_.IsValid());
|
||||
if (options.size == 0) {
|
||||
LogError(SIZE_ZERO, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check maximum accounting for overflow.
|
||||
if (options.size >
|
||||
static_cast<size_t>(std::numeric_limits<int>::max()) - kSectionMask) {
|
||||
LogError(SIZE_TOO_LARGE, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask;
|
||||
name_ = options.name_deprecated ? ASCIIToUTF16(*options.name_deprecated)
|
||||
: string16();
|
||||
SECURITY_ATTRIBUTES sa = {sizeof(sa), nullptr, FALSE};
|
||||
SECURITY_DESCRIPTOR sd;
|
||||
ACL dacl;
|
||||
|
||||
if (name_.empty()) {
|
||||
// Add an empty DACL to enforce anonymous read-only sections.
|
||||
sa.lpSecurityDescriptor = &sd;
|
||||
if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) {
|
||||
LogError(INITIALIZE_ACL_FAILURE, GetLastError());
|
||||
return false;
|
||||
}
|
||||
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
|
||||
LogError(INITIALIZE_SECURITY_DESC_FAILURE, GetLastError());
|
||||
return false;
|
||||
}
|
||||
if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE)) {
|
||||
LogError(SET_SECURITY_DESC_FAILURE, GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (win::GetVersion() < win::VERSION_WIN8_1) {
|
||||
// Windows < 8.1 ignores DACLs on certain unnamed objects (like shared
|
||||
// sections). So, we generate a random name when we need to enforce
|
||||
// read-only.
|
||||
uint64_t rand_values[4];
|
||||
RandBytes(&rand_values, sizeof(rand_values));
|
||||
name_ = ASCIIToUTF16(StringPrintf(
|
||||
"CrSharedMem_%016llx%016llx%016llx%016llx", rand_values[0],
|
||||
rand_values[1], rand_values[2], rand_values[3]));
|
||||
DCHECK(!name_.empty());
|
||||
}
|
||||
}
|
||||
|
||||
shm_ = SharedMemoryHandle(
|
||||
CreateFileMappingWithReducedPermissions(
|
||||
&sa, rounded_size, name_.empty() ? nullptr : as_wcstr(name_)),
|
||||
rounded_size, UnguessableToken::Create());
|
||||
if (!shm_.IsValid()) {
|
||||
// The error is logged within CreateFileMappingWithReducedPermissions().
|
||||
return false;
|
||||
}
|
||||
|
||||
requested_size_ = options.size;
|
||||
|
||||
// Check if the shared memory pre-exists.
|
||||
if (GetLastError() == ERROR_ALREADY_EXISTS) {
|
||||
// If the file already existed, set requested_size_ to 0 to show that
|
||||
// we don't know the size.
|
||||
requested_size_ = 0;
|
||||
external_section_ = true;
|
||||
if (!options.open_existing_deprecated) {
|
||||
Close();
|
||||
// From "if" above: GetLastError() == ERROR_ALREADY_EXISTS.
|
||||
LogError(ALREADY_EXISTS, ERROR_ALREADY_EXISTS);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LogError(SUCCESS, ERROR_SUCCESS);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::Delete(const std::string& name) {
|
||||
// intentionally empty -- there is nothing for us to do on Windows.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::Open(const std::string& name, bool read_only) {
|
||||
DCHECK(!shm_.IsValid());
|
||||
DWORD access = FILE_MAP_READ | SECTION_QUERY;
|
||||
if (!read_only)
|
||||
access |= FILE_MAP_WRITE;
|
||||
name_ = ASCIIToUTF16(name);
|
||||
read_only_ = read_only;
|
||||
|
||||
// This form of sharing shared memory is deprecated. https://crbug.com/345734.
|
||||
// However, we can't get rid of it without a significant refactor because its
|
||||
// used to communicate between two versions of the same service process, very
|
||||
// early in the life cycle.
|
||||
// Technically, we should also pass the GUID from the original shared memory
|
||||
// region. We don't do that - this means that we will overcount this memory,
|
||||
// which thankfully isn't relevant since Chrome only communicates with a
|
||||
// single version of the service process.
|
||||
// We pass the size |0|, which is a dummy size and wrong, but otherwise
|
||||
// harmless.
|
||||
shm_ = SharedMemoryHandle(
|
||||
OpenFileMapping(access, false, name_.empty() ? nullptr : as_wcstr(name_)),
|
||||
0u, UnguessableToken::Create());
|
||||
if (!shm_.IsValid())
|
||||
return false;
|
||||
// If a name specified assume it's an external section.
|
||||
if (!name_.empty())
|
||||
external_section_ = true;
|
||||
// Note: size_ is not set in this case.
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::MapAt(off_t offset, size_t bytes) {
|
||||
if (!shm_.IsValid()) {
|
||||
DLOG(ERROR) << "Invalid SharedMemoryHandle.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (bytes > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
DLOG(ERROR) << "Bytes required exceeds the 2G limitation.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memory_) {
|
||||
DLOG(ERROR) << "The SharedMemory has been mapped already.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (external_section_ && !IsSectionSafeToMap(shm_.GetHandle())) {
|
||||
DLOG(ERROR) << "SharedMemoryHandle is not safe to be mapped.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Try to map the shared memory. On the first failure, release any reserved
|
||||
// address space for a single retry.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
memory_ = MapViewOfFile(
|
||||
shm_.GetHandle(),
|
||||
read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
|
||||
static_cast<uint64_t>(offset) >> 32, static_cast<DWORD>(offset), bytes);
|
||||
if (memory_)
|
||||
break;
|
||||
ReleaseReservation();
|
||||
}
|
||||
if (!memory_) {
|
||||
DPLOG(ERROR) << "Failed executing MapViewOfFile";
|
||||
return false;
|
||||
}
|
||||
|
||||
DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
|
||||
(SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
|
||||
mapped_size_ = GetMemorySectionSize(memory_);
|
||||
mapped_id_ = shm_.GetGUID();
|
||||
SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SharedMemory::Unmap() {
|
||||
if (!memory_)
|
||||
return false;
|
||||
|
||||
SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
|
||||
UnmapViewOfFile(memory_);
|
||||
memory_ = nullptr;
|
||||
mapped_id_ = UnguessableToken();
|
||||
return true;
|
||||
}
|
||||
|
||||
SharedMemoryHandle SharedMemory::GetReadOnlyHandle() const {
|
||||
HANDLE result;
|
||||
ProcessHandle process = GetCurrentProcess();
|
||||
if (!::DuplicateHandle(process, shm_.GetHandle(), process, &result,
|
||||
FILE_MAP_READ | SECTION_QUERY, FALSE, 0)) {
|
||||
return SharedMemoryHandle();
|
||||
}
|
||||
SharedMemoryHandle handle =
|
||||
SharedMemoryHandle(result, shm_.GetSize(), shm_.GetGUID());
|
||||
handle.SetOwnershipPassesToIPC(true);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void SharedMemory::Close() {
|
||||
if (shm_.IsValid()) {
|
||||
shm_.Close();
|
||||
shm_ = SharedMemoryHandle();
|
||||
}
|
||||
}
|
||||
|
||||
SharedMemoryHandle SharedMemory::handle() const {
|
||||
return shm_;
|
||||
}
|
||||
|
||||
SharedMemoryHandle SharedMemory::TakeHandle() {
|
||||
SharedMemoryHandle handle(shm_);
|
||||
handle.SetOwnershipPassesToIPC(true);
|
||||
Unmap();
|
||||
shm_ = SharedMemoryHandle();
|
||||
return handle;
|
||||
}
|
||||
|
||||
} // namespace base
|
|
@ -1,80 +0,0 @@
|
|||
// Copyright 2018 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "base/memory/unsafe_shared_memory_region.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace base {
|
||||
|
||||
UnsafeSharedMemoryRegion::CreateFunction*
|
||||
UnsafeSharedMemoryRegion::create_hook_ = nullptr;
|
||||
|
||||
// static
|
||||
UnsafeSharedMemoryRegion UnsafeSharedMemoryRegion::Create(size_t size) {
|
||||
if (create_hook_)
|
||||
return create_hook_(size);
|
||||
|
||||
subtle::PlatformSharedMemoryRegion handle =
|
||||
subtle::PlatformSharedMemoryRegion::CreateUnsafe(size);
|
||||
|
||||
return UnsafeSharedMemoryRegion(std::move(handle));
|
||||
}
|
||||
|
||||
// static
|
||||
UnsafeSharedMemoryRegion UnsafeSharedMemoryRegion::Deserialize(
|
||||
subtle::PlatformSharedMemoryRegion handle) {
|
||||
return UnsafeSharedMemoryRegion(std::move(handle));
|
||||
}
|
||||
|
||||
// static
|
||||
subtle::PlatformSharedMemoryRegion
|
||||
UnsafeSharedMemoryRegion::TakeHandleForSerialization(
|
||||
UnsafeSharedMemoryRegion region) {
|
||||
return std::move(region.handle_);
|
||||
}
|
||||
|
||||
UnsafeSharedMemoryRegion::UnsafeSharedMemoryRegion() = default;
|
||||
UnsafeSharedMemoryRegion::UnsafeSharedMemoryRegion(
|
||||
UnsafeSharedMemoryRegion&& region) = default;
|
||||
UnsafeSharedMemoryRegion& UnsafeSharedMemoryRegion::operator=(
|
||||
UnsafeSharedMemoryRegion&& region) = default;
|
||||
UnsafeSharedMemoryRegion::~UnsafeSharedMemoryRegion() = default;
|
||||
|
||||
UnsafeSharedMemoryRegion UnsafeSharedMemoryRegion::Duplicate() const {
|
||||
return UnsafeSharedMemoryRegion(handle_.Duplicate());
|
||||
}
|
||||
|
||||
WritableSharedMemoryMapping UnsafeSharedMemoryRegion::Map() const {
|
||||
return MapAt(0, handle_.GetSize());
|
||||
}
|
||||
|
||||
WritableSharedMemoryMapping UnsafeSharedMemoryRegion::MapAt(off_t offset,
|
||||
size_t size) const {
|
||||
if (!IsValid())
|
||||
return {};
|
||||
|
||||
void* memory = nullptr;
|
||||
size_t mapped_size = 0;
|
||||
if (!handle_.MapAt(offset, size, &memory, &mapped_size))
|
||||
return {};
|
||||
|
||||
return WritableSharedMemoryMapping(memory, size, mapped_size,
|
||||
handle_.GetGUID());
|
||||
}
|
||||
|
||||
bool UnsafeSharedMemoryRegion::IsValid() const {
|
||||
return handle_.IsValid();
|
||||
}
|
||||
|
||||
UnsafeSharedMemoryRegion::UnsafeSharedMemoryRegion(
|
||||
subtle::PlatformSharedMemoryRegion handle)
|
||||
: handle_(std::move(handle)) {
|
||||
if (handle_.IsValid()) {
|
||||
CHECK_EQ(handle_.GetMode(),
|
||||
subtle::PlatformSharedMemoryRegion::Mode::kUnsafe);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace base
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче