Enforce cache_path requirements for NetworkService (see issue #2622).

This change adds a new CefSettings.root_cache_path value that must be either
equal to or a parent directory of all CefSettings.cache_path and
CefRequestContextSettings.cache_path values. The sandbox may block read/write
access from the NetworkService to directories that do not meet this requirement.

To test: Run cefclient with a combination of the following flags:

--cache-path=c:\temp\cache
  Cache data should be persisted to the specified directory.

--request-context-per-browser
  A separate numbered cache directory should be created underneath the
  cache-path directory for each new browser instance.

--enable-network-service --disable-extensions
  Same tests, but with NetworkService enabled.

Known issues:
- When NetworkService is enabled a C:\temp\cache\cache\Cache directory is
  created (should be C:\temp\cache\Cache).
This commit is contained in:
Marshall Greenblatt
2019-03-24 14:41:42 -04:00
parent 9b43d265c3
commit b65f336f81
10 changed files with 120 additions and 57 deletions

View File

@@ -24,7 +24,6 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/font_family_cache.h"
#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
#include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
@@ -260,16 +259,13 @@ CefBrowserContext::~CefBrowserContext() {
}
void CefBrowserContext::Initialize() {
CefContext* context = CefContext::Get();
cache_path_ = base::FilePath(CefString(&settings_.cache_path));
if (!cache_path_.empty()) {
base::ThreadRestrictions::ScopedAllowIO allow_io;
if (!base::DirectoryExists(cache_path_) &&
!base::CreateDirectory(cache_path_)) {
LOG(ERROR) << "The cache_path directory could not be created: "
<< cache_path_.value();
cache_path_ = base::FilePath();
CefString(&settings_.cache_path).clear();
}
if (!context->ValidateCachePath(cache_path_)) {
// Reset to in-memory storage.
CefString(&settings_.cache_path).clear();
cache_path_ = base::FilePath();
}
if (!cache_path_.empty())
@@ -278,7 +274,7 @@ void CefBrowserContext::Initialize() {
if (settings_.accept_language_list.length == 0) {
// Use the global language list setting.
CefString(&settings_.accept_language_list) =
CefString(&CefContext::Get()->settings().accept_language_list);
CefString(&context->settings().accept_language_list);
}
// Initialize the PrefService object.

View File

@@ -7,6 +7,7 @@
#include "libcef/browser/browser_context.h"
#include "libcef/browser/chrome_profile_manager_stub.h"
#include "libcef/browser/context.h"
#include "libcef/browser/prefs/browser_prefs.h"
#include "libcef/browser/thread_util.h"
#include "libcef/common/cef_switches.h"
@@ -39,11 +40,13 @@ void ChromeBrowserProcessStub::Initialize() {
DCHECK(!context_initialized_);
DCHECK(!shutdown_);
const CefSettings& settings = CefContext::Get()->settings();
const base::FilePath& cache_path =
base::FilePath(CefString(&settings.cache_path));
// Used for very early NetworkService initialization.
// TODO(cef): These preferences could be persisted in the DIR_USER_DATA
// directory.
local_state_ =
browser_prefs::CreatePrefService(nullptr, base::FilePath(), false);
local_state_ = browser_prefs::CreatePrefService(
nullptr, cache_path, !!settings.persist_user_preferences);
initialized_ = true;
}

View File

@@ -49,6 +49,7 @@
#include "base/json/json_reader.h"
#include "base/path_service.h"
#include "base/stl_util.h"
#include "base/threading/thread_restrictions.h"
#include "cef/grit/cef_resources.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_service.h"
@@ -57,7 +58,6 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/constants.mojom.h"
#include "chrome/grit/browser_resources.h"
@@ -1200,6 +1200,11 @@ void CefContentBrowserClient::OnNetworkServiceCreated(
DCHECK(local_state);
if (!SystemNetworkContextManager::GetInstance()) {
// TODO(network): This triggers creation of ChromeBrowserPolicyConnector via
// ChromeBrowserProcessStub::policy_service() which loads some system DLLs
// on Windows. Determine the correct initialization timing to avoid the need
// for ScopedAllowIO here.
base::ThreadRestrictions::ScopedAllowIO allow_io;
SystemNetworkContextManager::CreateInstance(local_state);
}
// Need to set up global NetworkService state before anything else uses it.
@@ -1215,24 +1220,26 @@ network::mojom::NetworkContextPtr CefContentBrowserClient::CreateNetworkContext(
return profile->CreateNetworkContext(in_memory, relative_partition_path);
}
// The sandbox may block read/write access from the NetworkService to
// directories that are not returned by this method.
std::vector<base::FilePath>
CefContentBrowserClient::GetNetworkContextsParentDirectory() {
base::FilePath user_data_dir;
base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
DCHECK(!user_data_dir.empty());
base::FilePath user_data_path;
base::PathService::Get(chrome::DIR_USER_DATA, &user_data_path);
DCHECK(!user_data_path.empty());
// TODO(cef): Do we really want to create a cache directory underneath
// DIR_USER_DATA?
base::FilePath cache_dir;
chrome::GetUserCacheDirectory(user_data_dir, &cache_dir);
DCHECK(!cache_dir.empty());
// The CefContext::ValidateCachePath method enforces the requirement that all
// cache_path values be either equal to or a child of root_cache_path.
const base::FilePath& root_cache_path =
base::FilePath(CefString(&CefContext::Get()->settings().root_cache_path));
// On some platforms, the cache is a child of the user_data_dir so only
// return the one path.
if (user_data_dir.IsParent(cache_dir))
return {user_data_dir};
// root_cache_path may sometimes be empty or a child of user_data_path, so
// only return the one path in that case.
if (root_cache_path.empty() || user_data_path.IsParent(root_cache_path)) {
return {user_data_path};
}
return {user_data_dir, cache_dir};
return {user_data_path, root_cache_path};
}
bool CefContentBrowserClient::HandleExternalProtocol(

View File

@@ -22,6 +22,7 @@
#include "base/files/file_util.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_restrictions.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "content/app/content_service_manager_main_delegate.h"
#include "content/browser/startup_helper.h"
@@ -370,6 +371,18 @@ bool CefContext::Initialize(const CefMainArgs& args,
SignalChromeElf();
#endif
base::FilePath cache_path = base::FilePath(CefString(&settings_.cache_path));
if (!ValidateCachePath(cache_path)) {
// Reset to in-memory storage.
CefString(&settings_.cache_path).clear();
cache_path = base::FilePath();
}
const base::FilePath& root_cache_path =
base::FilePath(CefString(&settings_.root_cache_path));
if (root_cache_path.empty() && !cache_path.empty()) {
CefString(&settings_.root_cache_path) = CefString(&settings_.cache_path);
}
main_delegate_.reset(new CefMainDelegate(application));
browser_info_manager_.reset(new CefBrowserInfoManager);
@@ -533,6 +546,31 @@ void CefContext::PopulateRequestContextSettings(
CefString(&settings_.accept_language_list);
}
bool CefContext::ValidateCachePath(const base::FilePath& cache_path) {
if (cache_path.empty())
return true;
const base::FilePath& root_cache_path =
base::FilePath(CefString(&settings_.root_cache_path));
if (!root_cache_path.empty() && root_cache_path != cache_path &&
!root_cache_path.IsParent(cache_path)) {
LOG(ERROR) << "The cache_path directory (" << cache_path.value()
<< ") is not a child of the root_cache_path directory ("
<< root_cache_path.value() << ")";
return false;
}
base::ThreadRestrictions::ScopedAllowIO allow_io;
if (!base::DirectoryExists(cache_path) &&
!base::CreateDirectory(cache_path)) {
LOG(ERROR) << "The cache_path directory (" << cache_path.value()
<< ") could not be created.";
return false;
}
return true;
}
void CefContext::OnContextInitialized() {
CEF_REQUIRE_UIT();

View File

@@ -73,10 +73,13 @@ class CefContext {
CefTraceSubscriber* GetTraceSubscriber();
// Populate the request context settings based on CefSettings and command-
// line flags.
// Populate request context settings for the global system context based on
// CefSettings and command-line flags.
void PopulateRequestContextSettings(CefRequestContextSettings* settings);
// Verify that |cache_path| is valid and create it if necessary.
bool ValidateCachePath(const base::FilePath& cache_path);
private:
void OnContextInitialized();

View File

@@ -193,6 +193,12 @@ std::unique_ptr<PrefService> CreatePrefService(Profile* profile,
// Based on ProfileImpl::RegisterProfilePrefs.
registry->RegisterBooleanPref(prefs::kPrintingEnabled, true);
// Cache preferences.
// Based on ProfileImpl::RegisterProfilePrefs.
registry->RegisterFilePathPref(prefs::kDiskCacheDir, cache_path);
registry->RegisterIntegerPref(prefs::kDiskCacheSize, 0);
registry->RegisterIntegerPref(prefs::kMediaCacheSize, 0);
// Spell checking preferences.
// Modify defaults from SpellcheckServiceFactory::RegisterProfilePrefs.
std::string spellcheck_lang =