Commit dec98a55 authored by Marshall Greenblatt's avatar Marshall Greenblatt
Browse files

macOS: Add support for and enable the V2 sandbox (issue #2459)

The CEF_USE_SANDBOX define is now used on all platforms.
parent fcad76b4
......@@ -1028,6 +1028,15 @@ if (is_win) {
}
}
if (is_mac) {
static_library("cef_sandbox") {
sources = [ "libcef_dll/sandbox/sandbox_mac.mm" ]
# CEF sources use include paths relative to the CEF root directory.
include_dirs = [ "." ]
deps = [ "//sandbox/mac:seatbelt" ]
}
}
#
# Service manifests.
......@@ -1568,6 +1577,7 @@ if (is_mac) {
sources = invoker.helper_sources
deps = [
":cef_sandbox",
":libcef_dll_wrapper",
]
if (defined(invoker.helper_deps)) {
......@@ -1582,6 +1592,10 @@ if (is_mac) {
]
info_plist_target = ":${app_name}_helper_plist"
if (defined(invoker.helper_defines)) {
defines = invoker.helper_defines
}
}
bundle_data("${app_name}_framework_bundle_data") {
......@@ -1628,6 +1642,10 @@ if (is_mac) {
libs = invoker.libs
}
if (defined(invoker.defines)) {
defines = invoker.defines
}
info_plist_target = ":${app_name}_plist"
}
}
......@@ -1687,6 +1705,9 @@ if (is_mac) {
helper_deps = [
":libcef_dll_wrapper",
]
helper_defines = [
"CEF_USE_SANDBOX",
]
info_plist = "tests/cefclient/resources/mac/Info.plist"
sources = gypi_paths2.includes_mac +
......@@ -1710,6 +1731,9 @@ if (is_mac) {
"AppKit.framework",
"OpenGL.framework",
]
defines = [
"CEF_USE_SANDBOX",
]
}
......@@ -1755,6 +1779,9 @@ if (is_mac) {
helper_deps = [
":libcef_dll_wrapper",
]
helper_defines = [
"CEF_USE_SANDBOX",
]
info_plist = "tests/cefsimple/mac/Info.plist"
sources = gypi_paths2.includes_mac +
......@@ -1769,6 +1796,9 @@ if (is_mac) {
":cefsimple_xibs",
":libcef_dll_wrapper",
]
defines = [
"CEF_USE_SANDBOX",
]
}
......@@ -1816,6 +1846,9 @@ if (is_mac) {
":libcef_dll_wrapper",
"//testing/gtest",
]
helper_defines = [
"CEF_USE_SANDBOX",
]
info_plist = "tests/ceftests/resources/mac/Info.plist"
sources = gypi_paths2.includes_mac +
......@@ -1837,6 +1870,9 @@ if (is_mac) {
libs = [
"AppKit.framework",
]
defines = [
"CEF_USE_SANDBOX",
]
}
} else {
#
......@@ -1893,6 +1929,10 @@ if (is_mac) {
":libcef_dll_wrapper",
]
defines = [
"CEF_USE_SANDBOX",
]
if (is_win) {
sources += gypi_paths2.includes_win +
gypi_paths2.shared_sources_win +
......@@ -1902,9 +1942,8 @@ if (is_mac) {
configs -= [ "//build/config/win:console" ]
configs += [ "//build/config/win:windowed" ]
defines = [
defines += [
"CEF_USE_ATL",
"CEF_USE_SANDBOX",
]
deps += [
......@@ -1966,6 +2005,10 @@ if (is_mac) {
":libcef_dll_wrapper",
]
defines = [
"CEF_USE_SANDBOX",
]
if (is_win) {
sources += gypi_paths2.includes_win +
gypi_paths2.cefsimple_sources_win
......@@ -1974,10 +2017,6 @@ if (is_mac) {
configs -= [ "//build/config/win:console" ]
configs += [ "//build/config/win:windowed" ]
defines = [
"CEF_USE_SANDBOX",
]
deps += [
":cef_sandbox",
"//build/win:default_exe_manifest",
......@@ -2035,14 +2074,14 @@ if (is_mac) {
"//testing/gtest",
]
defines = [
"CEF_USE_SANDBOX",
]
if (is_win) {
sources += gypi_paths2.shared_sources_win +
gypi_paths2.ceftests_sources_win
defines = [
"CEF_USE_SANDBOX",
]
deps += [
":cef_sandbox",
"//build/win:default_exe_manifest",
......
......@@ -79,6 +79,7 @@
'include/base/internal/cef_atomicops_atomicword_compat.h',
'include/base/internal/cef_atomicops_mac.h',
'include/cef_application_mac.h',
'include/cef_sandbox_mac.h',
'include/internal/cef_mac.h',
'include/internal/cef_types_mac.h',
],
......
......@@ -31,10 +31,11 @@ macro(PRINT_CEF_CONFIG)
endif()
if(OS_WINDOWS)
message(STATUS "CEF Windows sandbox: ${USE_SANDBOX}")
message(STATUS "Visual Studio ATL support: ${USE_ATL}")
endif()
message(STATUS "CEF sandbox: ${USE_SANDBOX}")
set(_libraries ${CEF_STANDARD_LIBS})
if(OS_WINDOWS AND USE_SANDBOX)
list(APPEND _libraries ${CEF_SANDBOX_STANDARD_LIBS})
......
......@@ -66,6 +66,10 @@ list(APPEND CEF_COMPILER_DEFINES
)
# Configure use of the sandbox.
option(USE_SANDBOX "Enable or disable use of the sandbox." ON)
#
# Linux configuration.
#
......@@ -217,6 +221,12 @@ if(OS_LINUX)
icudtl.dat
locales
)
if(USE_SANDBOX)
list(APPEND CEF_COMPILER_DEFINES
CEF_USE_SANDBOX # Used by apps to test if the sandbox is enabled
)
endif()
endif()
......@@ -313,6 +323,16 @@ if(OS_MACOSX)
set(CEF_BINARY_DIR "${_CEF_ROOT}/$<CONFIGURATION>")
set(CEF_BINARY_DIR_DEBUG "${_CEF_ROOT}/Debug")
set(CEF_BINARY_DIR_RELEASE "${_CEF_ROOT}/Release")
if(USE_SANDBOX)
list(APPEND CEF_COMPILER_DEFINES
CEF_USE_SANDBOX # Used by apps to test if the sandbox is enabled
)
# CEF sandbox library paths.
set(CEF_SANDBOX_LIB_DEBUG "${CEF_BINARY_DIR_DEBUG}/cef_sandbox.a")
set(CEF_SANDBOX_LIB_RELEASE "${CEF_BINARY_DIR_RELEASE}/cef_sandbox.a")
endif()
endif()
......@@ -329,8 +349,6 @@ if(OS_WINDOWS)
set(CMAKE_CXX_FLAGS_RELEASE "")
endif()
# Configure use of the sandbox.
option(USE_SANDBOX "Enable or disable use of the sandbox." ON)
if(USE_SANDBOX)
# Check if the current MSVC version is compatible with the cef_sandbox.lib
# static library. For a list of all version numbers see
......
// Copyright (c) 2018 Marshall A. Greenblatt. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the name Chromium Embedded
// Framework nor the names of its contributors may be used to endorse
// or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef CEF_INCLUDE_CEF_SANDBOX_MAC_H_
#define CEF_INCLUDE_CEF_SANDBOX_MAC_H_
#pragma once
#include "include/base/cef_build.h"
#if defined(OS_MACOSX)
#ifdef __cplusplus
extern "C" {
#endif
// The sandbox is used to restrict sub-processes (renderer, plugin, GPU, etc)
// from directly accessing system resources. This helps to protect the user
// from untrusted and potentially malicious Web content.
// See http://www.chromium.org/developers/design-documents/sandbox for
// complete details.
//
// To enable the sandbox on macOS the following requirements must be met:
// 1. Link the helper process executable with the cef_sandbox static library.
// 2. Call the cef_sandbox_initialize() function at the beginning of the
// helper executable main() function and before loading the CEF framework
// library. See include/wrapper/cef_library_loader.h for example usage.
///
// Initialize the sandbox for this process. Returns the sandbox context
// handle on success or NULL on failure. The returned handle should be
// passed to cef_sandbox_destroy() immediately before process termination.
///
void* cef_sandbox_initialize(int argc, char** argv);
///
// Destroy the specified sandbox context handle.
///
void cef_sandbox_destroy(void* sandbox_context);
#ifdef __cplusplus
}
///
// Scoped helper for managing the life span of a sandbox context handle.
///
class CefScopedSandboxContext {
public:
CefScopedSandboxContext();
~CefScopedSandboxContext();
// Load the sandbox for this process. Returns true on success.
bool Initialize(int argc, char** argv);
private:
void* sandbox_context_;
};
#endif // __cplusplus
#endif // defined(OS_MACOSX)
#endif // CEF_INCLUDE_CEF_SANDBOX_MAC_H_
......@@ -66,22 +66,34 @@ int cef_unload_library();
//
// Example usage in the main process:
//
// #include "include/wrapper/cef_library_loader.h"
//
// int main(int argc, char* argv[]) {
// // Dynamically load the CEF framework library.
// CefScopedLibraryLoader library_loader;
// if (!library_loader.LoadInMain())
// return 1;
//
// // Rest of the function here...
// // Continue with CEF initialization...
// }
//
// Example usage in the helper process:
//
// #include "include/cef_sandbox_mac.h"
// #include "include/wrapper/cef_library_loader.h"
//
// int main(int argc, char* argv[]) {
// // Initialize the macOS sandbox for this helper process.
// CefScopedSandboxContext sandbox_context;
// if (!sandbox_context.Initialize(argc, argv))
// return 1;
//
// // Dynamically load the CEF framework library.
// CefScopedLibraryLoader library_loader;
// if (!library_loader.LoadInHelper())
// return 1;
//
// // Rest of the function here...
// // Continue with CEF initialization...
// }
///
class CefScopedLibraryLoader {
......
......@@ -98,6 +98,20 @@ void OverrideFrameworkBundlePath() {
base::mac::SetOverrideFrameworkBundlePath(framework_path);
}
void OverrideOuterBundlePath() {
base::FilePath bundle_path = util_mac::GetMainBundlePath();
DCHECK(!bundle_path.empty());
base::mac::SetOverrideOuterBundlePath(bundle_path);
}
void OverrideBaseBundleID() {
std::string bundle_id = util_mac::GetMainBundleID();
DCHECK(!bundle_id.empty());
base::mac::SetBaseBundleID(bundle_id.c_str());
}
void OverrideChildProcessPath() {
base::FilePath child_process_path =
base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
......@@ -436,29 +450,6 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
switches::kUncaughtExceptionStackSize,
base::IntToString(settings.uncaught_exception_stack_size));
}
#if defined(OS_MACOSX)
std::vector<std::string> disable_features;
// TODO: Remove once MacV2Sandbox is supported. See issue #2459.
if (features::kMacV2Sandbox.default_state ==
base::FEATURE_ENABLED_BY_DEFAULT) {
disable_features.push_back(features::kMacV2Sandbox.name);
}
if (!disable_features.empty()) {
DCHECK(!base::FeatureList::GetInstance());
std::string disable_features_str =
command_line->GetSwitchValueASCII(switches::kDisableFeatures);
for (auto feature_str : disable_features) {
if (!disable_features_str.empty())
disable_features_str += ",";
disable_features_str += feature_str;
}
command_line->AppendSwitchASCII(switches::kDisableFeatures,
disable_features_str);
}
#endif // defined(OS_MACOSX)
}
if (content_client_.application().get()) {
......@@ -517,6 +508,8 @@ bool CefMainDelegate::BasicStartupComplete(int* exit_code) {
#if defined(OS_MACOSX)
OverrideFrameworkBundlePath();
OverrideOuterBundlePath();
OverrideBaseBundleID();
#endif
return false;
......
......@@ -6,6 +6,8 @@
#define CEF_LIBCEF_COMMON_UTIL_MAC_H_
#pragma once
#include <string>
namespace base {
class FilePath;
}
......@@ -31,6 +33,13 @@ base::FilePath GetFrameworkResourcesDirectory();
// "myapp.app/Contents/MacOS/myapp").
base::FilePath GetMainProcessPath();
// Returns the path to the top-level app bundle that contains the main process
// executable (e.g. "myapp.app").
base::FilePath GetMainBundlePath();
// Returns the identifier for the top-level app bundle.
std::string GetMainBundleID();
// Returns the path to the Resources directory inside the top-level app bundle
// (e.g. "myapp.app/Contents/Resources"). May return an empty value if not
// running in an app bundle.
......
......@@ -9,19 +9,15 @@
#include "base/base_paths.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/mac/bundle_locations.h"
#include "base/mac/foundation_util.h"
#include "base/path_service.h"
#include "base/strings/sys_string_conversions.h"
namespace util_mac {
namespace {
// Returns the path to the top-level app bundle that contains the main process
// executable.
base::FilePath GetMainBundlePath() {
return base::mac::GetAppBundlePath(GetMainProcessPath());
}
// Returns the path to the Frameworks directory inside the top-level app bundle.
base::FilePath GetFrameworksPath() {
base::FilePath bundle_path = GetMainBundlePath();
......@@ -68,6 +64,15 @@ base::FilePath GetMainProcessPath() {
return path;
}
base::FilePath GetMainBundlePath() {
return base::mac::GetAppBundlePath(GetMainProcessPath());
}
std::string GetMainBundleID() {
NSBundle* bundle = base::mac::OuterBundle();
return base::SysNSStringToUTF8([bundle bundleIdentifier]);
}
base::FilePath GetMainResourcesDirectory() {
base::FilePath bundle_path = GetMainBundlePath();
if (bundle_path.empty())
......
// Copyright 2018 The Chromium Embedded Framework Authors. Portions 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 <mach-o/dyld.h>
#include <stdio.h>
#include <memory>
#include "sandbox/mac/seatbelt_exec.h"
#include "include/cef_sandbox_mac.h"
void* cef_sandbox_initialize(int argc, char** argv) {
uint32_t exec_path_size = 0;
int rv = _NSGetExecutablePath(NULL, &exec_path_size);
if (rv != -1) {
return NULL;
}
std::unique_ptr<char[]> exec_path(new char[exec_path_size]);
rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size);
if (rv != 0) {
return NULL;
}
sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt =
sandbox::SeatbeltExecServer::CreateFromArguments(exec_path.get(), argc,
argv);
if (seatbelt.sandbox_required) {
if (!seatbelt.server) {
fprintf(stderr, "Failed to create the seatbelt sandbox server.\n");
return NULL;
}
if (!seatbelt.server->InitializeSandbox()) {
fprintf(stderr, "Failed to initialize the sandbox.\n");
return NULL;
}
}
auto* copy = new sandbox::SeatbeltExecServer::CreateFromArgumentsResult();
copy->sandbox_required = seatbelt.sandbox_required;
copy->server.swap(seatbelt.server);
return copy;
}
void cef_sandbox_destroy(void* sandbox_context) {
delete static_cast<sandbox::SeatbeltExecServer::CreateFromArgumentsResult*>(
sandbox_context);
}
CefScopedSandboxContext::CefScopedSandboxContext() : sandbox_context_(NULL) {}
CefScopedSandboxContext::~CefScopedSandboxContext() {
if (sandbox_context_) {
cef_sandbox_destroy(sandbox_context_);
}
}
bool CefScopedSandboxContext::Initialize(int argc, char** argv) {
if (sandbox_context_)
return false;
sandbox_context_ = cef_sandbox_initialize(argc, argv);
return !!sandbox_context_;
}
......@@ -186,6 +186,12 @@ if(OS_MACOSX)
OUTPUT_NAME ${CEF_HELPER_OUTPUT_NAME}
)
if(USE_SANDBOX)
# Logical target used to link the cef_sandbox library.
ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}")
target_link_libraries(${CEF_HELPER_TARGET} cef_sandbox_lib)
endif()
# Main executable target.
add_executable(${CEF_TARGET} MACOSX_BUNDLE ${CEFCLIENT_RESOURCES_SRCS} ${CEFCLIENT_SRCS})
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
......
......@@ -87,6 +87,13 @@ int RunMain(int argc, char* argv[]) {
CefSettings settings;
// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
// use of the sandbox.
#if !defined(CEF_USE_SANDBOX)
settings.no_sandbox = true;
#endif
// Populate the settings based on command line arguments.
context->PopulateSettings(&settings);
......
......@@ -368,6 +368,13 @@ int RunMain(int argc, char* argv[]) {
CefSettings settings;
// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
// use of the sandbox.
#if !defined(CEF_USE_SANDBOX)
settings.no_sandbox = true;
#endif
// Populate the settings based on command line arguments.
context->PopulateSettings(&settings);
......
......@@ -25,8 +25,8 @@
// #define CEF_USE_SANDBOX 1
#if defined(CEF_USE_SANDBOX)
// The cef_sandbox.lib static library is currently built with VS2015. It may not
// link successfully with other VS versions.
// The cef_sandbox.lib static library may not link successfully with all VS
// versions.
#pragma comment(lib, "cef_sandbox.lib")
#endif
......
......@@ -101,6 +101,12 @@ if(OS_MACOSX)
OUTPUT_NAME ${CEF_HELPER_OUTPUT_NAME}
)
if(USE_SANDBOX)
# Logical target used to link the cef_sandbox library.
ADD_LOGICAL_TARGET("cef_sandbox_lib" "${CEF_SANDBOX_LIB_DEBUG}" "${CEF_SANDBOX_LIB_RELEASE}")
target_link_libraries(${CEF_HELPER_TARGET} cef_sandbox_lib)
endif()
# Main executable target.
add_executable(${CEF_TARGET} MACOSX_BUNDLE ${CEFSIMPLE_RESOURCES_SRCS} ${CEFSIMPLE_SRCS})
SET_EXECUTABLE_TARGET_PROPERTIES(${CEF_TARGET})
......
......@@ -49,6 +49,13 @@ int main(int argc, char* argv[]) {
// Specify CEF global settings here.
CefSettings settings;
// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
// use of the sandbox.
#if !defined(CEF_USE_SANDBOX)
settings.no_sandbox = true;
#endif
// SimpleApp implements application-level callbacks for the browser process.
// It will create the first browser instance in OnContextInitialized() after
// CEF has initialized.
......
......@@ -128,6 +128,13 @@ int main(int argc, char* argv[]) {
// Specify CEF global settings here.
CefSettings settings;
// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
// automatically. Pass -DUSE_SANDBOX=OFF to the CMake command-line to disable
// use of the sandbox.
#if !defined(CEF_USE_SANDBOX)
settings.no_sandbox = true;
#endif
// SimpleApp implements application-level callbacks for the browser process.
// It will create the first browser instance in OnContextInitialized() after
// CEF has initialized.
......
......@@ -14,8 +14,8 @@
// #define CEF_USE_SANDBOX 1