// 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 #include #include "base/basictypes.h" #include "base/files/file_path.h" #include "base/platform_file.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/public/common/url_constants.h" #include "content/test/test_content_browser_client.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" #include "webkit/browser/fileapi/file_permission_policy.h" #include "webkit/browser/fileapi/file_system_url.h" #include "webkit/browser/fileapi/isolated_context.h" #include "webkit/common/fileapi/file_system_types.h" namespace content { namespace { const int kRendererID = 42; const int kWorkerRendererID = kRendererID + 1; #if defined(FILE_PATH_USES_DRIVE_LETTERS) #define TEST_PATH(x) FILE_PATH_LITERAL("c:") FILE_PATH_LITERAL(x) #else #define TEST_PATH(x) FILE_PATH_LITERAL(x) #endif class ChildProcessSecurityPolicyTestBrowserClient : public TestContentBrowserClient { public: ChildProcessSecurityPolicyTestBrowserClient() {} virtual bool IsHandledURL(const GURL& url) OVERRIDE { return schemes_.find(url.scheme()) != schemes_.end(); } void ClearSchemes() { schemes_.clear(); } void AddScheme(const std::string& scheme) { schemes_.insert(scheme); } private: std::set schemes_; }; } // namespace class ChildProcessSecurityPolicyTest : public testing::Test { public: ChildProcessSecurityPolicyTest() : old_browser_client_(NULL) { } virtual void SetUp() { old_browser_client_ = SetBrowserClientForTesting(&test_browser_client_); // Claim to always handle chrome:// URLs because the CPSP's notion of // allowing WebUI bindings is hard-wired to this particular scheme. test_browser_client_.AddScheme(kChromeUIScheme); // Claim to always handle file:// URLs like the browser would. // net::URLRequest::IsHandledURL() no longer claims support for default // protocols as this is the responsibility of the browser (which is // responsible for adding the appropriate ProtocolHandler). test_browser_client_.AddScheme(kFileScheme); } virtual void TearDown() { test_browser_client_.ClearSchemes(); SetBrowserClientForTesting(old_browser_client_); } protected: void RegisterTestScheme(const std::string& scheme) { test_browser_client_.AddScheme(scheme); } void GrantPermissionsForFile(ChildProcessSecurityPolicyImpl* p, int child_id, const base::FilePath& file, int permissions) { p->GrantPermissionsForFile(child_id, file, permissions); } void CheckHasNoFileSystemPermission(ChildProcessSecurityPolicyImpl* p, const std::string& child_id) { EXPECT_FALSE(p->CanReadFileSystem(kRendererID, child_id)); EXPECT_FALSE(p->CanReadWriteFileSystem(kRendererID, child_id)); EXPECT_FALSE(p->CanCopyIntoFileSystem(kRendererID, child_id)); EXPECT_FALSE(p->CanDeleteFromFileSystem(kRendererID, child_id)); } void CheckHasNoFileSystemFilePermission(ChildProcessSecurityPolicyImpl* p, const base::FilePath& file, const fileapi::FileSystemURL& url) { EXPECT_FALSE(p->CanReadFile(kRendererID, file)); EXPECT_FALSE(p->CanCreateReadWriteFile(kRendererID, file)); EXPECT_FALSE(p->CanReadFileSystemFile(kRendererID, url)); EXPECT_FALSE(p->CanWriteFileSystemFile(kRendererID, url)); EXPECT_FALSE(p->CanCreateFileSystemFile(kRendererID, url)); EXPECT_FALSE(p->CanCreateReadWriteFileSystemFile(kRendererID, url)); EXPECT_FALSE(p->CanCopyIntoFileSystemFile(kRendererID, url)); EXPECT_FALSE(p->CanDeleteFileSystemFile(kRendererID, url)); } private: ChildProcessSecurityPolicyTestBrowserClient test_browser_client_; ContentBrowserClient* old_browser_client_; }; TEST_F(ChildProcessSecurityPolicyTest, IsWebSafeSchemeTest) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); EXPECT_TRUE(p->IsWebSafeScheme(kHttpScheme)); EXPECT_TRUE(p->IsWebSafeScheme(kHttpsScheme)); EXPECT_TRUE(p->IsWebSafeScheme(kFtpScheme)); EXPECT_TRUE(p->IsWebSafeScheme(kDataScheme)); EXPECT_TRUE(p->IsWebSafeScheme("feed")); EXPECT_TRUE(p->IsWebSafeScheme(chrome::kBlobScheme)); EXPECT_TRUE(p->IsWebSafeScheme(kFileSystemScheme)); EXPECT_FALSE(p->IsWebSafeScheme("registered-web-safe-scheme")); p->RegisterWebSafeScheme("registered-web-safe-scheme"); EXPECT_TRUE(p->IsWebSafeScheme("registered-web-safe-scheme")); EXPECT_FALSE(p->IsWebSafeScheme(kChromeUIScheme)); } TEST_F(ChildProcessSecurityPolicyTest, IsPseudoSchemeTest) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); EXPECT_TRUE(p->IsPseudoScheme(chrome::kAboutScheme)); EXPECT_TRUE(p->IsPseudoScheme(kJavaScriptScheme)); EXPECT_TRUE(p->IsPseudoScheme(kViewSourceScheme)); EXPECT_FALSE(p->IsPseudoScheme("registered-pseudo-scheme")); p->RegisterPseudoScheme("registered-pseudo-scheme"); EXPECT_TRUE(p->IsPseudoScheme("registered-pseudo-scheme")); EXPECT_FALSE(p->IsPseudoScheme(kChromeUIScheme)); } TEST_F(ChildProcessSecurityPolicyTest, StandardSchemesTest) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); p->Add(kRendererID); // Safe EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("http://www.google.com/"))); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("https://www.paypal.com/"))); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("ftp://ftp.gnu.org/"))); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("data:text/html,Hi"))); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("view-source:http://www.google.com/"))); EXPECT_TRUE(p->CanRequestURL( kRendererID, GURL("filesystem:http://localhost/temporary/a.gif"))); // Dangerous EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd"))); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("chrome://foo/bar"))); p->Remove(kRendererID); } TEST_F(ChildProcessSecurityPolicyTest, AboutTest) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); p->Add(kRendererID); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("about:blank"))); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("about:BlAnK"))); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("aBouT:BlAnK"))); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("aBouT:blank"))); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:memory"))); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:crash"))); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:cache"))); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:hang"))); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("aBoUt:memory"))); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:CrASh"))); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("abOuT:cAChe"))); // Requests for about: pages should be denied. p->GrantRequestURL(kRendererID, GURL("about:crash")); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("about:crash"))); // These requests for chrome:// pages should be granted. GURL chrome_url("chrome://foo"); p->GrantRequestURL(kRendererID, chrome_url); EXPECT_TRUE(p->CanRequestURL(kRendererID, chrome_url)); p->Remove(kRendererID); } TEST_F(ChildProcessSecurityPolicyTest, JavaScriptTest) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); p->Add(kRendererID); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("javascript:alert('xss')"))); p->GrantRequestURL(kRendererID, GURL("javascript:alert('xss')")); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("javascript:alert('xss')"))); p->Remove(kRendererID); } TEST_F(ChildProcessSecurityPolicyTest, RegisterWebSafeSchemeTest) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); p->Add(kRendererID); // Currently, "asdf" is destined for ShellExecute, so it is allowed. EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers"))); // Once we register "asdf", we default to deny. RegisterTestScheme("asdf"); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("asdf:rockers"))); // We can allow new schemes by adding them to the whitelist. p->RegisterWebSafeScheme("asdf"); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("asdf:rockers"))); // Cleanup. p->Remove(kRendererID); } TEST_F(ChildProcessSecurityPolicyTest, CanServiceCommandsTest) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); p->Add(kRendererID); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd"))); p->GrantRequestURL(kRendererID, GURL("file:///etc/passwd")); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd"))); // We should forget our state if we repeat a renderer id. p->Remove(kRendererID); p->Add(kRendererID); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd"))); p->Remove(kRendererID); } TEST_F(ChildProcessSecurityPolicyTest, ViewSource) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); p->Add(kRendererID); // View source is determined by the embedded scheme. EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("view-source:http://www.google.com/"))); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("view-source:file:///etc/passwd"))); EXPECT_FALSE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd"))); EXPECT_FALSE(p->CanRequestURL( kRendererID, GURL("view-source:view-source:http://www.google.com/"))); p->GrantRequestURL(kRendererID, GURL("view-source:file:///etc/passwd")); // View source needs to be able to request the embedded scheme. EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("view-source:file:///etc/passwd"))); EXPECT_TRUE(p->CanRequestURL(kRendererID, GURL("file:///etc/passwd"))); p->Remove(kRendererID); } TEST_F(ChildProcessSecurityPolicyTest, SpecificFile) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); p->Add(kRendererID); GURL icon_url("file:///tmp/foo.png"); GURL sensitive_url("file:///etc/passwd"); EXPECT_FALSE(p->CanRequestURL(kRendererID, icon_url)); EXPECT_FALSE(p->CanRequestURL(kRendererID, sensitive_url)); p->GrantRequestSpecificFileURL(kRendererID, icon_url); EXPECT_TRUE(p->CanRequestURL(kRendererID, icon_url)); EXPECT_FALSE(p->CanRequestURL(kRendererID, sensitive_url)); p->GrantRequestURL(kRendererID, icon_url); EXPECT_TRUE(p->CanRequestURL(kRendererID, icon_url)); EXPECT_TRUE(p->CanRequestURL(kRendererID, sensitive_url)); p->Remove(kRendererID); } TEST_F(ChildProcessSecurityPolicyTest, FileSystemGrantsTest) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); p->Add(kRendererID); std::string read_id = fileapi::IsolatedContext::GetInstance()-> RegisterFileSystemForVirtualPath(fileapi::kFileSystemTypeTest, "read_filesystem", base::FilePath()); std::string read_write_id = fileapi::IsolatedContext::GetInstance()-> RegisterFileSystemForVirtualPath(fileapi::kFileSystemTypeTest, "read_write_filesystem", base::FilePath()); std::string copy_into_id = fileapi::IsolatedContext::GetInstance()-> RegisterFileSystemForVirtualPath(fileapi::kFileSystemTypeTest, "copy_into_filesystem", base::FilePath()); std::string delete_from_id = fileapi::IsolatedContext::GetInstance()-> RegisterFileSystemForVirtualPath(fileapi::kFileSystemTypeTest, "delete_from_filesystem", base::FilePath()); // Test initially having no permissions. CheckHasNoFileSystemPermission(p, read_id); CheckHasNoFileSystemPermission(p, read_write_id); CheckHasNoFileSystemPermission(p, copy_into_id); CheckHasNoFileSystemPermission(p, delete_from_id); // Testing varying combinations of grants and checks. p->GrantReadFileSystem(kRendererID, read_id); EXPECT_TRUE(p->CanReadFileSystem(kRendererID, read_id)); EXPECT_FALSE(p->CanReadWriteFileSystem(kRendererID, read_id)); EXPECT_FALSE(p->CanCopyIntoFileSystem(kRendererID, read_id)); EXPECT_FALSE(p->CanDeleteFromFileSystem(kRendererID, read_id)); p->GrantReadFileSystem(kRendererID, read_write_id); p->GrantWriteFileSystem(kRendererID, read_write_id); EXPECT_TRUE(p->CanReadFileSystem(kRendererID, read_write_id)); EXPECT_TRUE(p->CanReadWriteFileSystem(kRendererID, read_write_id)); EXPECT_FALSE(p->CanCopyIntoFileSystem(kRendererID, read_write_id)); EXPECT_FALSE(p->CanDeleteFromFileSystem(kRendererID, read_write_id)); p->GrantCopyIntoFileSystem(kRendererID, copy_into_id); EXPECT_FALSE(p->CanReadFileSystem(kRendererID, copy_into_id)); EXPECT_FALSE(p->CanReadWriteFileSystem(kRendererID, copy_into_id)); EXPECT_TRUE(p->CanCopyIntoFileSystem(kRendererID, copy_into_id)); EXPECT_FALSE(p->CanDeleteFromFileSystem(kRendererID, copy_into_id)); p->GrantDeleteFromFileSystem(kRendererID, delete_from_id); EXPECT_FALSE(p->CanReadFileSystem(kRendererID, delete_from_id)); EXPECT_FALSE(p->CanReadWriteFileSystem(kRendererID, delete_from_id)); EXPECT_FALSE(p->CanCopyIntoFileSystem(kRendererID, delete_from_id)); EXPECT_TRUE(p->CanDeleteFromFileSystem(kRendererID, delete_from_id)); // Test revoke permissions on renderer ID removal. p->Remove(kRendererID); CheckHasNoFileSystemPermission(p, read_id); CheckHasNoFileSystemPermission(p, read_write_id); CheckHasNoFileSystemPermission(p, copy_into_id); CheckHasNoFileSystemPermission(p, delete_from_id); // Test having no permissions upon re-adding same renderer ID. p->Add(kRendererID); CheckHasNoFileSystemPermission(p, read_id); CheckHasNoFileSystemPermission(p, read_write_id); CheckHasNoFileSystemPermission(p, copy_into_id); CheckHasNoFileSystemPermission(p, delete_from_id); // Cleanup. p->Remove(kRendererID); fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(read_id); fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(read_write_id); fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(copy_into_id); fileapi::IsolatedContext::GetInstance()->RevokeFileSystem(delete_from_id); } TEST_F(ChildProcessSecurityPolicyTest, FilePermissionGrantingAndRevoking) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); p->RegisterFileSystemPermissionPolicy( fileapi::kFileSystemTypeTest, fileapi::FILE_PERMISSION_USE_FILE_PERMISSION); p->Add(kRendererID); base::FilePath file(TEST_PATH("/dir/testfile")); file = file.NormalizePathSeparators(); fileapi::FileSystemURL url = fileapi::FileSystemURL::CreateForTest( GURL("http://foo/"), fileapi::kFileSystemTypeTest, file); // Test initially having no permissions. CheckHasNoFileSystemFilePermission(p, file, url); // Testing every combination of permissions granting and revoking. p->GrantReadFile(kRendererID, file); EXPECT_TRUE(p->CanReadFile(kRendererID, file)); EXPECT_FALSE(p->CanCreateReadWriteFile(kRendererID, file)); EXPECT_TRUE(p->CanReadFileSystemFile(kRendererID, url)); EXPECT_FALSE(p->CanWriteFileSystemFile(kRendererID, url)); EXPECT_FALSE(p->CanCreateFileSystemFile(kRendererID, url)); EXPECT_FALSE(p->CanCreateReadWriteFileSystemFile(kRendererID, url)); EXPECT_FALSE(p->CanCopyIntoFileSystemFile(kRendererID, url)); EXPECT_FALSE(p->CanDeleteFileSystemFile(kRendererID, url)); p->RevokeAllPermissionsForFile(kRendererID, file); CheckHasNoFileSystemFilePermission(p, file, url); p->GrantCreateReadWriteFile(kRendererID, file); EXPECT_TRUE(p->CanReadFile(kRendererID, file)); EXPECT_TRUE(p->CanCreateReadWriteFile(kRendererID, file)); EXPECT_TRUE(p->CanReadFileSystemFile(kRendererID, url)); EXPECT_TRUE(p->CanWriteFileSystemFile(kRendererID, url)); EXPECT_TRUE(p->CanCreateFileSystemFile(kRendererID, url)); EXPECT_TRUE(p->CanCreateReadWriteFileSystemFile(kRendererID, url)); EXPECT_TRUE(p->CanCopyIntoFileSystemFile(kRendererID, url)); EXPECT_TRUE(p->CanDeleteFileSystemFile(kRendererID, url)); p->RevokeAllPermissionsForFile(kRendererID, file); CheckHasNoFileSystemFilePermission(p, file, url); // Test revoke permissions on renderer ID removal. p->GrantCreateReadWriteFile(kRendererID, file); EXPECT_TRUE(p->CanReadFile(kRendererID, file)); EXPECT_TRUE(p->CanCreateReadWriteFile(kRendererID, file)); EXPECT_TRUE(p->CanReadFileSystemFile(kRendererID, url)); EXPECT_TRUE(p->CanWriteFileSystemFile(kRendererID, url)); EXPECT_TRUE(p->CanCreateFileSystemFile(kRendererID, url)); EXPECT_TRUE(p->CanCreateReadWriteFileSystemFile(kRendererID, url)); EXPECT_TRUE(p->CanCopyIntoFileSystemFile(kRendererID, url)); EXPECT_TRUE(p->CanDeleteFileSystemFile(kRendererID, url)); p->Remove(kRendererID); CheckHasNoFileSystemFilePermission(p, file, url); // Test having no permissions upon re-adding same renderer ID. p->Add(kRendererID); CheckHasNoFileSystemFilePermission(p, file, url); // Cleanup. p->Remove(kRendererID); } TEST_F(ChildProcessSecurityPolicyTest, FilePermissions) { base::FilePath granted_file = base::FilePath(TEST_PATH("/home/joe")); base::FilePath sibling_file = base::FilePath(TEST_PATH("/home/bob")); base::FilePath child_file = base::FilePath(TEST_PATH("/home/joe/file")); base::FilePath parent_file = base::FilePath(TEST_PATH("/home")); base::FilePath parent_slash_file = base::FilePath(TEST_PATH("/home/")); base::FilePath child_traversal1 = base::FilePath(TEST_PATH("/home/joe/././file")); base::FilePath child_traversal2 = base::FilePath( TEST_PATH("/home/joe/file/../otherfile")); base::FilePath evil_traversal1 = base::FilePath(TEST_PATH("/home/joe/../../etc/passwd")); base::FilePath evil_traversal2 = base::FilePath( TEST_PATH("/home/joe/./.././../etc/passwd")); base::FilePath self_traversal = base::FilePath(TEST_PATH("/home/joe/../joe/file")); base::FilePath relative_file = base::FilePath(FILE_PATH_LITERAL("home/joe")); ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); // Grant permissions for a file. p->Add(kRendererID); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_OPEN)); GrantPermissionsForFile(p, kRendererID, granted_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_OPEN_TRUNCATED | base::PLATFORM_FILE_READ | base::PLATFORM_FILE_WRITE); EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_OPEN_TRUNCATED | base::PLATFORM_FILE_READ | base::PLATFORM_FILE_WRITE)); EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_CREATE)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, 0)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_OPEN_TRUNCATED | base::PLATFORM_FILE_READ | base::PLATFORM_FILE_WRITE)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, sibling_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, parent_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, child_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, child_traversal1, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, child_traversal2, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, evil_traversal1, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, evil_traversal2, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); // CPSP doesn't allow this case for the sake of simplicity. EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, self_traversal, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); p->Remove(kRendererID); // Grant permissions for the directory the file is in. p->Add(kRendererID); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_OPEN)); GrantPermissionsForFile(p, kRendererID, parent_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_OPEN)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_READ | base::PLATFORM_FILE_WRITE)); p->Remove(kRendererID); // Grant permissions for the directory the file is in (with trailing '/'). p->Add(kRendererID); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_OPEN)); GrantPermissionsForFile(p, kRendererID, parent_slash_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_OPEN)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_READ | base::PLATFORM_FILE_WRITE)); // Grant permissions for the file (should overwrite the permissions granted // for the directory). GrantPermissionsForFile(p, kRendererID, granted_file, base::PLATFORM_FILE_TEMPORARY); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_OPEN)); EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_TEMPORARY)); // Revoke all permissions for the file (it should inherit its permissions // from the directory again). p->RevokeAllPermissionsForFile(kRendererID, granted_file); EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_TEMPORARY)); p->Remove(kRendererID); // Grant file permissions for the file to main thread renderer process, // make sure its worker thread renderer process inherits those. p->Add(kRendererID); GrantPermissionsForFile(p, kRendererID, granted_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ); EXPECT_TRUE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, granted_file, base::PLATFORM_FILE_WRITE)); p->AddWorker(kWorkerRendererID, kRendererID); EXPECT_TRUE(p->HasPermissionsForFile(kWorkerRendererID, granted_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); EXPECT_FALSE(p->HasPermissionsForFile(kWorkerRendererID, granted_file, base::PLATFORM_FILE_WRITE)); p->Remove(kRendererID); EXPECT_FALSE(p->HasPermissionsForFile(kWorkerRendererID, granted_file, base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ)); p->Remove(kWorkerRendererID); p->Add(kRendererID); GrantPermissionsForFile(p, kRendererID, relative_file, base::PLATFORM_FILE_OPEN); EXPECT_FALSE(p->HasPermissionsForFile(kRendererID, relative_file, base::PLATFORM_FILE_OPEN)); p->Remove(kRendererID); } TEST_F(ChildProcessSecurityPolicyTest, CanServiceWebUIBindings) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); GURL url("chrome://thumb/http://www.google.com/"); p->Add(kRendererID); EXPECT_FALSE(p->HasWebUIBindings(kRendererID)); EXPECT_FALSE(p->CanRequestURL(kRendererID, url)); p->GrantWebUIBindings(kRendererID); EXPECT_TRUE(p->HasWebUIBindings(kRendererID)); EXPECT_TRUE(p->CanRequestURL(kRendererID, url)); p->Remove(kRendererID); } TEST_F(ChildProcessSecurityPolicyTest, RemoveRace) { ChildProcessSecurityPolicyImpl* p = ChildProcessSecurityPolicyImpl::GetInstance(); GURL url("file:///etc/passwd"); base::FilePath file(TEST_PATH("/etc/passwd")); p->Add(kRendererID); p->GrantRequestURL(kRendererID, url); p->GrantReadFile(kRendererID, file); p->GrantWebUIBindings(kRendererID); EXPECT_TRUE(p->CanRequestURL(kRendererID, url)); EXPECT_TRUE(p->CanReadFile(kRendererID, file)); EXPECT_TRUE(p->HasWebUIBindings(kRendererID)); p->Remove(kRendererID); // Renderers are added and removed on the UI thread, but the policy can be // queried on the IO thread. The ChildProcessSecurityPolicy needs to be // prepared to answer policy questions about renderers who no longer exist. // In this case, we default to secure behavior. EXPECT_FALSE(p->CanRequestURL(kRendererID, url)); EXPECT_FALSE(p->CanReadFile(kRendererID, file)); EXPECT_FALSE(p->HasWebUIBindings(kRendererID)); } } // namespace content