зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 3 changesets (bug 1639030) for sandbox related bustages CLOSED TREE
Backed out changeset 55b963f34eb0 (bug 1639030) Backed out changeset 0c2d7e8a4131 (bug 1639030) Backed out changeset 9d82c8fa3d3b (bug 1639030)
This commit is contained in:
Родитель
6a7bf3be7b
Коммит
55458f847e
|
@ -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;
|
||||
|
@ -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))
|
||||
@@ -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: {
|
||||
+ {
|
||||
default: {
|
||||
NOTREACHED();
|
||||
break;
|
||||
}
|
||||
}
|
||||
+ } else if (THREAD_CTRL_REMOVE_PEER == key) {
|
||||
+ // Remove a process from our list of peers.
|
||||
+ AutoLock lock(&broker->lock_);
|
||||
+ broker->active_targets_.erase(
|
||||
+ PeerTrackerMap::iterator it = broker->peer_map_.find(
|
||||
+ 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;
|
||||
}
|
||||
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());
|
||||
+ 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 {
|
||||
- // 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;
|
||||
// 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:
|
||||
+ case IPC_DUPLICATEHANDLEPROXY_TAG:
|
||||
+ return true;
|
||||
+
|
||||
+ default:
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ 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,19 +537,18 @@ 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 {
|
||||
|
@ -564,8 +558,7 @@ diff --git a/security/sandbox/chromium/sandbox/win/src/sandbox_policy.h b/securi
|
|||
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_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))
|
||||
|
@ -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,7 +300,7 @@ 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,
|
||||
base::Callback<void(const char* file,
|
||||
int line,
|
||||
const base::StringPiece message,
|
||||
const base::StringPiece stack_trace)>;
|
||||
|
@ -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
|
||||
|
@ -687,17 +788,16 @@ std::string* MakeCheckOpString<std::string, std::string>(
|
|||
// 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, \
|
||||
inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
|
||||
const char* names) { \
|
||||
if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
|
||||
return nullptr; \
|
||||
return NULL; \
|
||||
else \
|
||||
return ::logging::MakeCheckOpString(v1, v2, names); \
|
||||
} \
|
||||
constexpr std::string* Check##name##Impl(int v1, int v2, \
|
||||
const char* names) { \
|
||||
inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
|
||||
if (ANALYZER_ASSUME_TRUE(v1 op v2)) \
|
||||
return nullptr; \
|
||||
return NULL; \
|
||||
else \
|
||||
return ::logging::MakeCheckOpString(v1, v2, names); \
|
||||
}
|
||||
|
@ -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
|
||||
#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; \
|
||||
DLOG_IF(ERROR, !logged_once) << NOTIMPLEMENTED_MSG; \
|
||||
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
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче