diff options
author | raymes@chromium.org <raymes@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-04 23:32:50 +0000 |
---|---|---|
committer | raymes@chromium.org <raymes@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-04 23:32:50 +0000 |
commit | 2432c058351cb5b4da6b1c5a9c756d1758c9ee5d (patch) | |
tree | 372850500a04180aa8e45c38347010a15398eaee /content/browser/renderer_host/pepper | |
parent | f574c40f701805a0da0129915a9dc691cd79d355 (diff) | |
download | chromium_src-2432c058351cb5b4da6b1c5a9c756d1758c9ee5d.zip chromium_src-2432c058351cb5b4da6b1c5a9c756d1758c9ee5d.tar.gz chromium_src-2432c058351cb5b4da6b1c5a9c756d1758c9ee5d.tar.bz2 |
The refactors PPB_Flash_File_ModuleLocal/FileRef to the new resource model. Calls for both these interfaces are now made directly to the browser. This removes the in-process implementation for these interfaces also (as they are flash-only). Tests are added for PPB_Flash_File_ModuleLocal.
Review URL: https://codereview.chromium.org/11359097
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@171080 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/renderer_host/pepper')
8 files changed, 458 insertions, 511 deletions
diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc index 3e074c4..d7faf83 100644 --- a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc +++ b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.cc @@ -3,8 +3,8 @@ // found in the LICENSE file. #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h" -#include "content/browser/renderer_host/pepper/pepper_message_filter.h" +#include "content/browser/renderer_host/pepper/pepper_message_filter.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_view_host.h" #include "ipc/ipc_message_macros.h" @@ -16,12 +16,19 @@ BrowserPpapiHost* BrowserPpapiHost::CreateExternalPluginProcess( IPC::Sender* sender, ppapi::PpapiPermissions permissions, base::ProcessHandle plugin_child_process, + int plugin_child_process_id, IPC::ChannelProxy* channel, net::HostResolver* host_resolver, int render_process_id, int render_view_id) { + // TODO(raymes): Figure out how to plumb plugin_name and + // profile_data_directory through for NaCl. They are currently only needed for + // PPB_Flash_File interfaces so it doesn't matter. + std::string plugin_name; + FilePath profile_data_directory; BrowserPpapiHostImpl* browser_ppapi_host = - new BrowserPpapiHostImpl(sender, permissions); + new BrowserPpapiHostImpl(sender, permissions, plugin_name, + profile_data_directory, plugin_child_process_id); browser_ppapi_host->set_plugin_process_handle(plugin_child_process); channel->AddFilter( @@ -37,9 +44,15 @@ BrowserPpapiHost* BrowserPpapiHost::CreateExternalPluginProcess( BrowserPpapiHostImpl::BrowserPpapiHostImpl( IPC::Sender* sender, - const ppapi::PpapiPermissions& permissions) + const ppapi::PpapiPermissions& permissions, + const std::string& plugin_name, + const FilePath& profile_data_directory, + int plugin_process_id) : ppapi_host_(sender, permissions), - plugin_process_handle_(base::kNullProcessHandle) { + plugin_process_handle_(base::kNullProcessHandle), + plugin_name_(plugin_name), + profile_data_directory_(profile_data_directory), + plugin_process_id_(plugin_process_id) { message_filter_ = new HostMessageFilter(&ppapi_host_); ppapi_host_.AddHostFactoryFilter(scoped_ptr<ppapi::host::HostFactory>( new ContentBrowserPepperHostFactory(this))); @@ -80,6 +93,18 @@ bool BrowserPpapiHostImpl::GetRenderViewIDsForInstance( return true; } +const std::string& BrowserPpapiHostImpl::GetPluginName() { + return plugin_name_; +} + +const FilePath& BrowserPpapiHostImpl::GetProfileDataDirectory() { + return profile_data_directory_; +} + +int BrowserPpapiHostImpl::GetPluginProcessID() { + return plugin_process_id_; +} + void BrowserPpapiHostImpl::AddInstanceForView(PP_Instance instance, int render_process_id, int render_view_id) { diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h index bee35a6..77eb8a8 100644 --- a/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h +++ b/content/browser/renderer_host/pepper/browser_ppapi_host_impl.h @@ -6,9 +6,11 @@ #define CONTENT_BROWSER_RENDERER_HOST_PEPPER_BROWSER_PPAPI_HOST_IMPL_H_ #include <map> +#include <string> #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/file_path.h" #include "content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h" #include "content/common/content_export.h" #include "content/public/browser/browser_ppapi_host.h" @@ -23,7 +25,10 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost { // as it is known (we start the process asynchronously so it won't be known // when this object is created). BrowserPpapiHostImpl(IPC::Sender* sender, - const ppapi::PpapiPermissions& permissions); + const ppapi::PpapiPermissions& permissions, + const std::string& plugin_name, + const FilePath& profile_data_directory, + int plugin_process_id); virtual ~BrowserPpapiHostImpl(); // BrowserPpapiHost. @@ -33,6 +38,9 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost { virtual bool GetRenderViewIDsForInstance(PP_Instance instance, int* render_process_id, int* render_view_id) const OVERRIDE; + virtual const std::string& GetPluginName() OVERRIDE; + virtual const FilePath& GetProfileDataDirectory() OVERRIDE; + virtual int GetPluginProcessID() OVERRIDE; void set_plugin_process_handle(base::ProcessHandle handle) { plugin_process_handle_ = handle; @@ -79,6 +87,9 @@ class CONTENT_EXPORT BrowserPpapiHostImpl : public BrowserPpapiHost { ppapi::host::PpapiHost ppapi_host_; base::ProcessHandle plugin_process_handle_; + std::string plugin_name_; + FilePath profile_data_directory_; + int plugin_process_id_; // Tracks all PP_Instances in this plugin and maps them to // RenderProcess/RenderView IDs. diff --git a/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc b/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc index 941782c..a85f086 100644 --- a/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc +++ b/content/browser/renderer_host/pepper/browser_ppapi_host_test.cc @@ -13,7 +13,10 @@ BrowserPpapiHostTest::BrowserPpapiHostTest() : sink_() { ppapi_host_.reset(new BrowserPpapiHostImpl( &sink_, - ppapi::PpapiPermissions::AllPermissions())); + ppapi::PpapiPermissions::AllPermissions(), + std::string(), + FilePath(), + 0)); ppapi_host_->set_plugin_process_handle(base::GetCurrentProcessHandle()); } diff --git a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc index 3033adb..fd9a13a 100644 --- a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc +++ b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc @@ -6,6 +6,7 @@ #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h" #include "content/browser/renderer_host/pepper/pepper_flash_browser_host.h" +#include "content/browser/renderer_host/pepper/pepper_flash_file_host.h" #include "content/browser/renderer_host/pepper/pepper_gamepad_host.h" #include "content/browser/renderer_host/pepper/pepper_print_settings_manager.h" #include "content/browser/renderer_host/pepper/pepper_printing_host.h" @@ -62,6 +63,9 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost( case PpapiHostMsg_Flash_Create::ID: return scoped_ptr<ResourceHost>(new PepperFlashBrowserHost( host_, instance, params.pp_resource())); + case PpapiHostMsg_FlashFile_Create::ID: + return scoped_ptr<ResourceHost>(new PepperFlashFileHost( + host_, instance, params.pp_resource())); } } diff --git a/content/browser/renderer_host/pepper/pepper_file_message_filter.cc b/content/browser/renderer_host/pepper/pepper_file_message_filter.cc deleted file mode 100644 index 428c6ed..0000000 --- a/content/browser/renderer_host/pepper/pepper_file_message_filter.cc +++ /dev/null @@ -1,367 +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. - -#include "content/browser/renderer_host/pepper/pepper_file_message_filter.h" - -#include "base/callback.h" -#include "base/file_path.h" -#include "base/file_util.h" -#include "base/logging.h" -#include "base/platform_file.h" -#include "base/process_util.h" -#include "base/threading/sequenced_worker_pool.h" -#include "content/browser/child_process_security_policy_impl.h" -#include "content/browser/renderer_host/render_process_host_impl.h" -#include "content/public/browser/browser_thread.h" -#include "content/public/common/content_constants.h" -#include "ipc/ipc_platform_file.h" -#include "ppapi/proxy/pepper_file_messages.h" -#include "ppapi/shared_impl/file_path.h" - -#if defined(OS_POSIX) -#include "base/file_descriptor_posix.h" -#endif - -namespace content { -namespace { - -// Used to check if the renderer has permission for the requested operation. -// TODO(viettrungluu): Verify these. They don't necessarily quite make sense, -// but it seems to be approximately what the file system code does. -const int kReadPermissions = base::PLATFORM_FILE_OPEN | - base::PLATFORM_FILE_READ | - base::PLATFORM_FILE_EXCLUSIVE_READ; -const int kWritePermissions = base::PLATFORM_FILE_OPEN | - base::PLATFORM_FILE_CREATE | - base::PLATFORM_FILE_CREATE_ALWAYS | - base::PLATFORM_FILE_OPEN_TRUNCATED | - base::PLATFORM_FILE_WRITE | - base::PLATFORM_FILE_EXCLUSIVE_WRITE | - base::PLATFORM_FILE_WRITE_ATTRIBUTES; - -IPC::PlatformFileForTransit PlatformFileToPlatformFileForTransit( - base::ProcessHandle peer_handle, - base::PlatformFile file_handle, - base::PlatformFileError* error) { - IPC::PlatformFileForTransit file; -#if defined(OS_WIN) - // Duplicate the file handle so that the renderer process can access the file. - if (!DuplicateHandle(GetCurrentProcess(), file_handle, - peer_handle, &file, 0, false, - DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { - // file_handle is closed whether or not DuplicateHandle succeeds. - *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED; - file = INVALID_HANDLE_VALUE; - } -#else - file = base::FileDescriptor(file_handle, true); -#endif - return file; -} - -} // namespace - -PepperFileMessageFilter::PepperFileMessageFilter(int child_id) - : child_id_(child_id), - channel_(NULL) { -} - -base::TaskRunner* PepperFileMessageFilter::OverrideTaskRunnerForMessage( - const IPC::Message& message) { - // The blocking pool provides a pool of threads to run file - // operations, instead of a single thread which might require - // queuing time. Since these messages are synchronous as sent from - // the plugin, the sending thread cannot send a new message until - // this one returns, so there is no need to sequence tasks here. If - // the plugin has multiple threads, it cannot make assumptions about - // ordering of IPC message sends, so it cannot make assumptions - // about ordering of operations caused by those IPC messages. - if (IPC_MESSAGE_CLASS(message) == PepperFileMsgStart) - return BrowserThread::GetBlockingPool(); - return NULL; -} - -bool PepperFileMessageFilter::OnMessageReceived(const IPC::Message& message, - bool* message_was_ok) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP_EX(PepperFileMessageFilter, message, *message_was_ok) - IPC_MESSAGE_HANDLER(PepperFileMsg_OpenFile, OnOpenFile) - IPC_MESSAGE_HANDLER(PepperFileMsg_RenameFile, OnRenameFile) - IPC_MESSAGE_HANDLER(PepperFileMsg_DeleteFileOrDir, OnDeleteFileOrDir) - IPC_MESSAGE_HANDLER(PepperFileMsg_CreateDir, OnCreateDir) - IPC_MESSAGE_HANDLER(PepperFileMsg_QueryFile, OnQueryFile) - IPC_MESSAGE_HANDLER(PepperFileMsg_GetDirContents, OnGetDirContents) - IPC_MESSAGE_HANDLER(PepperFileMsg_CreateTemporaryFile, - OnCreateTemporaryFile) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP_EX() - return handled; -} - -void PepperFileMessageFilter::OnDestruct() const { - BrowserThread::DeleteOnIOThread::Destruct(this); -} - -// static -FilePath PepperFileMessageFilter::GetDataDirName(const FilePath& profile_path) { - return profile_path.Append(kPepperDataDirname); -} - -PepperFileMessageFilter::~PepperFileMessageFilter() { - // This function should be called on the IO thread. - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); -} - -// Called on the FILE thread: -void PepperFileMessageFilter::OnOpenFile( - const ppapi::PepperFilePath& path, - int flags, - base::PlatformFileError* error, - IPC::PlatformFileForTransit* file) { - FilePath full_path = ValidateAndConvertPepperFilePath(path, flags); - if (full_path.empty()) { - *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED; - *file = IPC::InvalidPlatformFileForTransit(); - return; - } - - base::PlatformFile file_handle = base::CreatePlatformFile( - full_path, flags, NULL, error); - - if (*error != base::PLATFORM_FILE_OK || - file_handle == base::kInvalidPlatformFileValue) { - *file = IPC::InvalidPlatformFileForTransit(); - return; - } - - // Make sure we didn't try to open a directory: directory fd shouldn't pass - // to untrusted processes because they open security holes. - base::PlatformFileInfo info; - if (!base::GetPlatformFileInfo(file_handle, &info) || info.is_directory) { - // When in doubt, throw it out. - *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED; - *file = IPC::InvalidPlatformFileForTransit(); - return; - } - - *file = PlatformFileToPlatformFileForTransit(peer_handle(), file_handle, - error); -} - -void PepperFileMessageFilter::OnRenameFile( - const ppapi::PepperFilePath& from_path, - const ppapi::PepperFilePath& to_path, - base::PlatformFileError* error) { - FilePath from_full_path = ValidateAndConvertPepperFilePath(from_path, - kWritePermissions); - FilePath to_full_path = ValidateAndConvertPepperFilePath(to_path, - kWritePermissions); - if (from_full_path.empty() || to_full_path.empty()) { - *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED; - return; - } - - bool result = file_util::Move(from_full_path, to_full_path); - *error = result ? base::PLATFORM_FILE_OK - : base::PLATFORM_FILE_ERROR_ACCESS_DENIED; -} - -void PepperFileMessageFilter::OnDeleteFileOrDir( - const ppapi::PepperFilePath& path, - bool recursive, - base::PlatformFileError* error) { - FilePath full_path = ValidateAndConvertPepperFilePath(path, - kWritePermissions); - if (full_path.empty()) { - *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED; - return; - } - - bool result = file_util::Delete(full_path, recursive); - *error = result ? base::PLATFORM_FILE_OK - : base::PLATFORM_FILE_ERROR_ACCESS_DENIED; -} - -void PepperFileMessageFilter::OnCreateDir( - const ppapi::PepperFilePath& path, - base::PlatformFileError* error) { - FilePath full_path = ValidateAndConvertPepperFilePath(path, - kWritePermissions); - if (full_path.empty()) { - *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED; - return; - } - - bool result = file_util::CreateDirectory(full_path); - *error = result ? base::PLATFORM_FILE_OK - : base::PLATFORM_FILE_ERROR_ACCESS_DENIED; -} - -void PepperFileMessageFilter::OnQueryFile( - const ppapi::PepperFilePath& path, - base::PlatformFileInfo* info, - base::PlatformFileError* error) { - FilePath full_path = ValidateAndConvertPepperFilePath(path, kReadPermissions); - if (full_path.empty()) { - *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED; - return; - } - - bool result = file_util::GetFileInfo(full_path, info); - *error = result ? base::PLATFORM_FILE_OK - : base::PLATFORM_FILE_ERROR_ACCESS_DENIED; -} - -void PepperFileMessageFilter::OnGetDirContents( - const ppapi::PepperFilePath& path, - ppapi::DirContents* contents, - base::PlatformFileError* error) { - FilePath full_path = ValidateAndConvertPepperFilePath(path, kReadPermissions); - if (full_path.empty()) { - *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED; - return; - } - - contents->clear(); - - file_util::FileEnumerator enumerator(full_path, false, - file_util::FileEnumerator::FILES | - file_util::FileEnumerator::DIRECTORIES | - file_util::FileEnumerator::INCLUDE_DOT_DOT); - - while (!enumerator.Next().empty()) { - file_util::FileEnumerator::FindInfo info; - enumerator.GetFindInfo(&info); - ppapi::DirEntry entry = { - file_util::FileEnumerator::GetFilename(info), - file_util::FileEnumerator::IsDirectory(info) - }; - contents->push_back(entry); - } - - *error = base::PLATFORM_FILE_OK; -} - -void PepperFileMessageFilter::OnCreateTemporaryFile( - base::PlatformFileError* error, - IPC::PlatformFileForTransit* file) { - *error = base::PLATFORM_FILE_ERROR_FAILED; - *file = IPC::InvalidPlatformFileForTransit(); - - ppapi::PepperFilePath dir_path( - ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL, FilePath()); - FilePath validated_dir_path = ValidateAndConvertPepperFilePath( - dir_path, kReadPermissions | kWritePermissions); - if (validated_dir_path.empty() || - (!file_util::DirectoryExists(validated_dir_path) && - !file_util::CreateDirectory(validated_dir_path))) { - *error = base::PLATFORM_FILE_ERROR_ACCESS_DENIED; - return; - } - - FilePath file_path; - if (!file_util::CreateTemporaryFileInDir(validated_dir_path, &file_path)) - return; - - base::PlatformFile file_handle = base::CreatePlatformFile( - file_path, - base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ | - base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_TEMPORARY | - base::PLATFORM_FILE_DELETE_ON_CLOSE, - NULL, error); - - if (*error != base::PLATFORM_FILE_OK) { - DCHECK_EQ(file_handle, base::kInvalidPlatformFileValue); - return; - } - - *file = PlatformFileToPlatformFileForTransit(peer_handle(), file_handle, - error); -} - -FilePath PepperFileMessageFilter::ValidateAndConvertPepperFilePath( - const ppapi::PepperFilePath& pepper_path, int flags) { - FilePath file_path; // Empty path returned on error. - if (pepper_path.domain() == ppapi::PepperFilePath::DOMAIN_ABSOLUTE) { - if (pepper_path.path().IsAbsolute() && - ChildProcessSecurityPolicyImpl::GetInstance()->HasPermissionsForFile( - child_id(), pepper_path.path(), flags)) - file_path = pepper_path.path(); - } - return file_path; -} - -PepperTrustedFileMessageFilter::PepperTrustedFileMessageFilter( - int child_id, - const std::string& plugin_name, - const FilePath& profile_data_directory) - : PepperFileMessageFilter(child_id) { - plugin_data_directory_ = GetDataDirName(profile_data_directory).Append( - FilePath::FromUTF8Unsafe(plugin_name)); -} - -PepperTrustedFileMessageFilter::~PepperTrustedFileMessageFilter() { -} - -FilePath PepperTrustedFileMessageFilter::ValidateAndConvertPepperFilePath( - const ppapi::PepperFilePath& pepper_path, - int flags) { - FilePath file_path; // Empty path returned on error. - switch (pepper_path.domain()) { - case ppapi::PepperFilePath::DOMAIN_ABSOLUTE: - if (pepper_path.path().IsAbsolute() && - ChildProcessSecurityPolicyImpl::GetInstance()->HasPermissionsForFile( - child_id(), pepper_path.path(), flags)) - file_path = pepper_path.path(); - break; - case ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL: - // This filter provides the module name portion of the path to prevent - // plugins from accessing each other's data. - if (!pepper_path.path().IsAbsolute() && - !pepper_path.path().ReferencesParent()) - file_path = plugin_data_directory_.Append(pepper_path.path()); - break; - default: - NOTREACHED(); - break; - } - return file_path; -} - -PepperUnsafeFileMessageFilter::PepperUnsafeFileMessageFilter( - int child_id, - const FilePath& profile_data_directory) - : PepperFileMessageFilter(child_id) { - profile_data_directory_ = GetDataDirName(profile_data_directory); -} - -PepperUnsafeFileMessageFilter::~PepperUnsafeFileMessageFilter() { -} - -FilePath PepperUnsafeFileMessageFilter::ValidateAndConvertPepperFilePath( - const ppapi::PepperFilePath& pepper_path, - int flags) { - FilePath file_path; // Empty path returned on error. - switch (pepper_path.domain()) { - case ppapi::PepperFilePath::DOMAIN_ABSOLUTE: - if (pepper_path.path().IsAbsolute() && - ChildProcessSecurityPolicyImpl::GetInstance()->HasPermissionsForFile( - child_id(), pepper_path.path(), flags)) - file_path = pepper_path.path(); - break; - case ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL: - // The message supplies the module portion of the path (so it can't - // really be trusted). - if (!pepper_path.path().IsAbsolute() && - !pepper_path.path().ReferencesParent()) - file_path = profile_data_directory_.Append(pepper_path.path()); - break; - default: - NOTREACHED(); - break; - } - return file_path; -} - -} // namespace content diff --git a/content/browser/renderer_host/pepper/pepper_file_message_filter.h b/content/browser/renderer_host/pepper/pepper_file_message_filter.h deleted file mode 100644 index 7efca84..0000000 --- a/content/browser/renderer_host/pepper/pepper_file_message_filter.h +++ /dev/null @@ -1,138 +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 CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FILE_MESSAGE_FILTER_H_ -#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FILE_MESSAGE_FILTER_H_ - -#include <string> -#include <vector> - -#include "base/file_path.h" -#include "base/memory/ref_counted.h" -#include "base/process.h" -#include "base/sequenced_task_runner_helpers.h" -#include "build/build_config.h" -#include "content/public/browser/browser_message_filter.h" -#include "ipc/ipc_platform_file.h" -#include "ppapi/shared_impl/dir_contents.h" - -namespace ppapi { -class PepperFilePath; -} - -namespace content { -class BrowserContext; - -// A message filter for Pepper-specific File I/O messages. Used on -// renderer channels, this denys the renderer the trusted operations -// permitted only by plugin processes. -class PepperFileMessageFilter : public BrowserMessageFilter { - public: - explicit PepperFileMessageFilter(int child_id); - - // BrowserMessageFilter methods: - virtual base::TaskRunner* OverrideTaskRunnerForMessage( - const IPC::Message& message) OVERRIDE; - virtual bool OnMessageReceived(const IPC::Message& message, - bool* message_was_ok) OVERRIDE; - virtual void OnDestruct() const OVERRIDE; - - int child_id() const { return child_id_; } - - // Returns the name of the pepper data directory that we'll use for local - // storage. The argument is the profile path so that this can be used on any - // thread independent of the profile context. - static FilePath GetDataDirName(const FilePath& profile_path); - - protected: - virtual ~PepperFileMessageFilter(); - - private: - friend class BrowserThread; - friend class base::DeleteHelper<PepperFileMessageFilter>; - - // Called on the FILE thread: - void OnOpenFile(const ppapi::PepperFilePath& path, - int flags, - base::PlatformFileError* error, - IPC::PlatformFileForTransit* file); - void OnRenameFile(const ppapi::PepperFilePath& from_path, - const ppapi::PepperFilePath& to_path, - base::PlatformFileError* error); - void OnDeleteFileOrDir(const ppapi::PepperFilePath& path, - bool recursive, - base::PlatformFileError* error); - void OnCreateDir(const ppapi::PepperFilePath& path, - base::PlatformFileError* error); - void OnQueryFile(const ppapi::PepperFilePath& path, - base::PlatformFileInfo* info, - base::PlatformFileError* error); - void OnGetDirContents(const ppapi::PepperFilePath& path, - ppapi::DirContents* contents, - base::PlatformFileError* error); - void OnCreateTemporaryFile(base::PlatformFileError* error, - IPC::PlatformFileForTransit* file); - - // Validate and convert the Pepper file path to a "real" |FilePath|. Returns - // an empty |FilePath| on error. - virtual FilePath ValidateAndConvertPepperFilePath( - const ppapi::PepperFilePath& pepper_path, int flags); - - // The ID of the child process. - const int child_id_; - - // The channel associated with the renderer connection. This pointer is not - // owned by this class. - IPC::Channel* channel_; - - DISALLOW_COPY_AND_ASSIGN(PepperFileMessageFilter); -}; - -// Message filter used with out-of-process pepper flash plugin channels that -// provides the trusted operations permitted only by plugin processes. -class PepperTrustedFileMessageFilter : public PepperFileMessageFilter { - public: - PepperTrustedFileMessageFilter(int child_id, - const std::string& plugin_name, - const FilePath& profile_data_directory); - - protected: - virtual ~PepperTrustedFileMessageFilter(); - - private: - virtual FilePath ValidateAndConvertPepperFilePath( - const ppapi::PepperFilePath& pepper_path, int flags) OVERRIDE; - - // The path to the per-plugin directory under the per-profile data directory - // (includes module name). - FilePath plugin_data_directory_; - - DISALLOW_COPY_AND_ASSIGN(PepperTrustedFileMessageFilter); -}; - -// Message filter used with in-process pepper flash plugins that provides the -// renderer channels with the trusted operations permitted only by plugin -// process. This should not be used as part of normal operations, and may -// only be applied under the control of a command-line flag. -class PepperUnsafeFileMessageFilter : public PepperFileMessageFilter { - public: - PepperUnsafeFileMessageFilter(int child_id, - const FilePath& profile_data_directory); - - protected: - virtual ~PepperUnsafeFileMessageFilter(); - - private: - virtual FilePath ValidateAndConvertPepperFilePath( - const ppapi::PepperFilePath& pepper_path, int flags) OVERRIDE; - - // The per-profile data directory (not including module name). - FilePath profile_data_directory_; - - DISALLOW_COPY_AND_ASSIGN(PepperUnsafeFileMessageFilter); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FILE_MESSAGE_FILTER_H_ diff --git a/content/browser/renderer_host/pepper/pepper_flash_file_host.cc b/content/browser/renderer_host/pepper/pepper_flash_file_host.cc new file mode 100644 index 0000000..4bd23cd --- /dev/null +++ b/content/browser/renderer_host/pepper/pepper_flash_file_host.cc @@ -0,0 +1,365 @@ +// 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. + +#include "content/browser/renderer_host/pepper/pepper_flash_file_host.h" + +#include "base/bind.h" +#include "base/file_util.h" +#include "base/task_runner.h" +#include "base/threading/sequenced_worker_pool.h" +#include "content/browser/child_process_security_policy_impl.h" +#include "content/public/browser/browser_ppapi_host.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/common/content_constants.h" +#include "ipc/ipc_platform_file.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/host/dispatch_host_message.h" +#include "ppapi/host/host_message_context.h" +#include "ppapi/host/ppapi_host.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/file_path.h" +#include "ppapi/shared_impl/file_type_conversion.h" + +namespace content { + +namespace { +// Used to check if the renderer has permission for the requested operation. +// TODO(viettrungluu): Verify these. They don't necessarily quite make sense, +// but it seems to be approximately what the file system code does. +const int kReadPermissions = base::PLATFORM_FILE_OPEN | + base::PLATFORM_FILE_READ | + base::PLATFORM_FILE_EXCLUSIVE_READ; +const int kWritePermissions = base::PLATFORM_FILE_OPEN | + base::PLATFORM_FILE_CREATE | + base::PLATFORM_FILE_CREATE_ALWAYS | + base::PLATFORM_FILE_OPEN_TRUNCATED | + base::PLATFORM_FILE_WRITE | + base::PLATFORM_FILE_EXCLUSIVE_WRITE | + base::PLATFORM_FILE_WRITE_ATTRIBUTES; + +// All file messages are handled by BrowserThread's blocking pool. +class FileMessageFilter : public ppapi::host::ResourceMessageFilter { + public: + FileMessageFilter(const std::string& plugin_name, + const FilePath& profile_data_directory, + int plugin_process_id, + base::ProcessHandle plugin_process_handle); + protected: + // ppapi::host::ResourceMessageFilter implementation. + virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage( + const IPC::Message& msg) OVERRIDE; + virtual int32_t OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) OVERRIDE; + + private: + virtual ~FileMessageFilter(); + + int32_t OnOpenFile(ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& path, + int flags); + int32_t OnRenameFile(ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& from_path, + const ppapi::PepperFilePath& to_path); + int32_t OnDeleteFileOrDir(ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& path, + bool recursive); + int32_t OnCreateDir(ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& path); + int32_t OnQueryFile(ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& path); + int32_t OnGetDirContents(ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& path); + int32_t OnCreateTemporaryFile(ppapi::host::HostMessageContext* context); + + FilePath ValidateAndConvertPepperFilePath( + const ppapi::PepperFilePath& pepper_path, + int flags); + + FilePath plugin_data_directory_; + int plugin_process_id_; + base::ProcessHandle plugin_process_handle_; +}; + +FileMessageFilter::FileMessageFilter( + const std::string& plugin_name, + const FilePath& profile_data_directory, + int plugin_process_id, + base::ProcessHandle plugin_process_handle) + : plugin_process_id_(plugin_process_id), + plugin_process_handle_(plugin_process_handle) { + if (profile_data_directory.empty() || plugin_name.empty()) { + // These are used to construct the path. If they are not set it means we + // will construct a bad path and could provide access to the wrong files. + // In this case, |plugin_data_directory_| will remain unset and + // |ValidateAndConvertPepperFilePath| will fail. + NOTREACHED(); + } else { + plugin_data_directory_ = PepperFlashFileHost::GetDataDirName( + profile_data_directory).Append(FilePath::FromUTF8Unsafe(plugin_name)); + } +} + +FileMessageFilter::~FileMessageFilter() { +} + +scoped_refptr<base::TaskRunner> +FileMessageFilter::OverrideTaskRunnerForMessage(const IPC::Message& msg) { + // The blocking pool provides a pool of threads to run file + // operations, instead of a single thread which might require + // queuing time. Since these messages are synchronous as sent from + // the plugin, the sending thread cannot send a new message until + // this one returns, so there is no need to sequence tasks here. If + // the plugin has multiple threads, it cannot make assumptions about + // ordering of IPC message sends, so it cannot make assumptions + // about ordering of operations caused by those IPC messages. + return scoped_refptr<base::TaskRunner>(BrowserThread::GetBlockingPool()); +} + +int32_t FileMessageFilter::OnResourceMessageReceived( + const IPC::Message& msg, + ppapi::host::HostMessageContext* context) { + IPC_BEGIN_MESSAGE_MAP(FileMessageFilter, msg) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_OpenFile, + OnOpenFile) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_RenameFile, + OnRenameFile) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_DeleteFileOrDir, + OnDeleteFileOrDir) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_CreateDir, + OnCreateDir) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_QueryFile, + OnQueryFile) + PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_GetDirContents, + OnGetDirContents) + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( + PpapiHostMsg_FlashFile_CreateTemporaryFile, + OnCreateTemporaryFile) + IPC_END_MESSAGE_MAP() + return PP_ERROR_FAILED; +} + +int32_t FileMessageFilter::OnOpenFile( + ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& path, + int flags) { + FilePath full_path = ValidateAndConvertPepperFilePath(path, flags); + if (full_path.empty()) { + return ppapi::PlatformFileErrorToPepperError( + base::PLATFORM_FILE_ERROR_ACCESS_DENIED); + } + + base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; + base::PlatformFile file_handle = base::CreatePlatformFile( + full_path, flags, NULL, &error); + if (error != base::PLATFORM_FILE_OK) { + DCHECK_EQ(file_handle, base::kInvalidPlatformFileValue); + return ppapi::PlatformFileErrorToPepperError(error); + } + + // Make sure we didn't try to open a directory: directory fd shouldn't be + // passed to untrusted processes because they open security holes. + base::PlatformFileInfo info; + if (!base::GetPlatformFileInfo(file_handle, &info) || info.is_directory) { + // When in doubt, throw it out. + base::ClosePlatformFile(file_handle); + return ppapi::PlatformFileErrorToPepperError( + base::PLATFORM_FILE_ERROR_ACCESS_DENIED); + } + + IPC::PlatformFileForTransit file = IPC::GetFileHandleForProcess(file_handle, + plugin_process_handle_, true); + ppapi::host::ReplyMessageContext reply_context = + context->MakeReplyMessageContext(); + reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle( + ppapi::proxy::SerializedHandle::FILE, file)); + SendReply(reply_context, IPC::Message()); + return PP_OK_COMPLETIONPENDING; +} + +int32_t FileMessageFilter::OnRenameFile( + ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& from_path, + const ppapi::PepperFilePath& to_path) { + FilePath from_full_path = ValidateAndConvertPepperFilePath(from_path, + kWritePermissions); + FilePath to_full_path = ValidateAndConvertPepperFilePath(to_path, + kWritePermissions); + if (from_full_path.empty() || to_full_path.empty()) { + return ppapi::PlatformFileErrorToPepperError( + base::PLATFORM_FILE_ERROR_ACCESS_DENIED); + } + + bool result = file_util::Move(from_full_path, to_full_path); + return ppapi::PlatformFileErrorToPepperError(result ? + base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED); +} + +int32_t FileMessageFilter::OnDeleteFileOrDir( + ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& path, + bool recursive) { + FilePath full_path = ValidateAndConvertPepperFilePath(path, + kWritePermissions); + if (full_path.empty()) { + return ppapi::PlatformFileErrorToPepperError( + base::PLATFORM_FILE_ERROR_ACCESS_DENIED); + } + + bool result = file_util::Delete(full_path, recursive); + return ppapi::PlatformFileErrorToPepperError(result ? + base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED); +} +int32_t FileMessageFilter::OnCreateDir( + ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& path) { + FilePath full_path = ValidateAndConvertPepperFilePath(path, + kWritePermissions); + if (full_path.empty()) { + return ppapi::PlatformFileErrorToPepperError( + base::PLATFORM_FILE_ERROR_ACCESS_DENIED); + } + + bool result = file_util::CreateDirectory(full_path); + return ppapi::PlatformFileErrorToPepperError(result ? + base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED); +} + +int32_t FileMessageFilter::OnQueryFile( + ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& path) { + FilePath full_path = ValidateAndConvertPepperFilePath(path, + kReadPermissions); + if (full_path.empty()) { + return ppapi::PlatformFileErrorToPepperError( + base::PLATFORM_FILE_ERROR_ACCESS_DENIED); + } + + base::PlatformFileInfo info; + bool result = file_util::GetFileInfo(full_path, &info); + context->reply_msg = PpapiPluginMsg_FlashFile_QueryFileReply(info); + return ppapi::PlatformFileErrorToPepperError(result ? + base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED); +} + +int32_t FileMessageFilter::OnGetDirContents( + ppapi::host::HostMessageContext* context, + const ppapi::PepperFilePath& path) { + FilePath full_path = ValidateAndConvertPepperFilePath(path, kReadPermissions); + if (full_path.empty()) { + return ppapi::PlatformFileErrorToPepperError( + base::PLATFORM_FILE_ERROR_ACCESS_DENIED); + } + + ppapi::DirContents contents; + file_util::FileEnumerator enumerator(full_path, false, + file_util::FileEnumerator::FILES | + file_util::FileEnumerator::DIRECTORIES | + file_util::FileEnumerator::INCLUDE_DOT_DOT); + + while (!enumerator.Next().empty()) { + file_util::FileEnumerator::FindInfo info; + enumerator.GetFindInfo(&info); + ppapi::DirEntry entry = { + file_util::FileEnumerator::GetFilename(info), + file_util::FileEnumerator::IsDirectory(info) + }; + contents.push_back(entry); + } + + context->reply_msg = PpapiPluginMsg_FlashFile_GetDirContentsReply(contents); + return PP_OK; +} + +int32_t FileMessageFilter::OnCreateTemporaryFile( + ppapi::host::HostMessageContext* context) { + ppapi::PepperFilePath dir_path( + ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL, FilePath()); + FilePath validated_dir_path = ValidateAndConvertPepperFilePath( + dir_path, kReadPermissions | kWritePermissions); + if (validated_dir_path.empty() || + (!file_util::DirectoryExists(validated_dir_path) && + !file_util::CreateDirectory(validated_dir_path))) { + return ppapi::PlatformFileErrorToPepperError( + base::PLATFORM_FILE_ERROR_ACCESS_DENIED); + } + + FilePath file_path; + if (!file_util::CreateTemporaryFileInDir(validated_dir_path, &file_path)) { + return ppapi::PlatformFileErrorToPepperError( + base::PLATFORM_FILE_ERROR_FAILED); + } + + base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED; + base::PlatformFile file_handle = base::CreatePlatformFile( + file_path, + base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ | + base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_TEMPORARY | + base::PLATFORM_FILE_DELETE_ON_CLOSE, + NULL, &error); + + if (error != base::PLATFORM_FILE_OK) { + DCHECK_EQ(file_handle, base::kInvalidPlatformFileValue); + return ppapi::PlatformFileErrorToPepperError(error); + } + + IPC::PlatformFileForTransit file = IPC::GetFileHandleForProcess(file_handle, + plugin_process_handle_, true); + ppapi::host::ReplyMessageContext reply_context = + context->MakeReplyMessageContext(); + reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle( + ppapi::proxy::SerializedHandle::FILE, file)); + SendReply(reply_context, IPC::Message()); + return PP_OK_COMPLETIONPENDING; +} + +FilePath FileMessageFilter::ValidateAndConvertPepperFilePath( + const ppapi::PepperFilePath& pepper_path, + int flags) { + FilePath file_path; // Empty path returned on error. + switch (pepper_path.domain()) { + case ppapi::PepperFilePath::DOMAIN_ABSOLUTE: + if (pepper_path.path().IsAbsolute() && + ChildProcessSecurityPolicyImpl::GetInstance()->HasPermissionsForFile( + plugin_process_id_, pepper_path.path(), flags)) + file_path = pepper_path.path(); + break; + case ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL: + // This filter provides the module name portion of the path to prevent + // plugins from accessing each other's data. + if (!plugin_data_directory_.empty() && + !pepper_path.path().IsAbsolute() && + !pepper_path.path().ReferencesParent()) + file_path = plugin_data_directory_.Append(pepper_path.path()); + break; + default: + NOTREACHED(); + break; + } + return file_path; +} + +} // namespace + +PepperFlashFileHost::PepperFlashFileHost( + BrowserPpapiHost* host, + PP_Instance instance, + PP_Resource resource) + : ResourceHost(host->GetPpapiHost(), instance, resource) { + AddFilter(scoped_refptr<ppapi::host::ResourceMessageFilter>( + new FileMessageFilter(host->GetPluginName(), + host->GetProfileDataDirectory(), + host->GetPluginProcessID(), + host->GetPluginProcessHandle()))); +} + +PepperFlashFileHost::~PepperFlashFileHost() { +} + +// static +FilePath PepperFlashFileHost::GetDataDirName(const FilePath& profile_path) { + return profile_path.Append(kPepperDataDirname); +} + +} // namespace content diff --git a/content/browser/renderer_host/pepper/pepper_flash_file_host.h b/content/browser/renderer_host/pepper/pepper_flash_file_host.h new file mode 100644 index 0000000..6b45d98 --- /dev/null +++ b/content/browser/renderer_host/pepper/pepper_flash_file_host.h @@ -0,0 +1,44 @@ +// 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 CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_FILE_HOST_H_ +#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_FILE_HOST_H_ + +#include "base/compiler_specific.h" +#include "base/file_path.h" +#include "base/memory/ref_counted.h" +#include "base/process.h" +#include "ppapi/host/resource_host.h" +#include "ppapi/host/resource_message_filter.h" + +namespace ppapi { +class PepperFilePath; +} + +namespace ppapi { +namespace host { +struct ReplyMessageContext; +} +} + +namespace content { + +class BrowserPpapiHost; + +class PepperFlashFileHost : public ppapi::host::ResourceHost { + public: + PepperFlashFileHost(BrowserPpapiHost* host, + PP_Instance instance, + PP_Resource resource); + virtual ~PepperFlashFileHost(); + + static FilePath GetDataDirName(const FilePath& profile_path); + + private: + DISALLOW_COPY_AND_ASSIGN(PepperFlashFileHost); +}; + +} // namespace content + +#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_PEPPER_FLASH_FILE_HOST_H_ |