0

dlp: Pass file access callback to file stream reader

The callback is passed through the calls from the mojo interface to the file stream reader. Where it is used to gain a ScopedFileAccess token to read files.

The callback is not yet created for the calls depending on the destination URL. That will happen with a CL for b/262203074.

There are different cases for default behavior, where we do not need to query the daemon with a specific URL. Only files explicitly known/downloaded to the user can be protected. That excludes e.g. caches. The daemon would not deny those accesses, so we do not have to ask for permission. The other default are cases, where we want to allow access regardless of the rules. Here we have to query the daemon with a request for the system component (e.g. by the callback returned by ScopedFileAccessDelegate::GetCallbackForSystemIO).

Design doc: go/access-to-dlp-restricted-files-upload

BUG=b:262199707

Change-Id: Id71ac3463aae4c0d0b02bb3a264c2a8d05798f22
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4197601
Reviewed-by: Sergey Poromov <poromov@chromium.org>
Reviewed-by: Austin Sullivan <asully@chromium.org>
Commit-Queue: Daniel Brinkers <brinky@google.com>
Reviewed-by: Marcello Salomao <msalomao@google.com>
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1114995}
This commit is contained in:
Daniel Brinkers
2023-03-09 07:39:05 +00:00
committed by Chromium LUCI CQ
parent 9df0c47961
commit 9dacf9e173
42 changed files with 509 additions and 97 deletions

@ -12,6 +12,7 @@
#include "ash/webui/file_manager/url_constants.h" #include "ash/webui/file_manager/url_constants.h"
#include "base/check_op.h" #include "base/check_op.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/functional/callback_helpers.h"
#include "base/notreached.h" #include "base/notreached.h"
#include "base/strings/escape.h" #include "base/strings/escape.h"
#include "base/task/task_traits.h" #include "base/task/task_traits.h"
@ -24,6 +25,7 @@
#include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h" #include "chrome/browser/media_galleries/fileapi/media_file_system_backend.h"
#include "chrome/common/url_constants.h" #include "chrome/common/url_constants.h"
#include "chromeos/ash/components/dbus/cros_disks/cros_disks_client.h" #include "chromeos/ash/components/dbus/cros_disks/cros_disks_client.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "components/user_manager/user.h" #include "components/user_manager/user.h"
#include "storage/browser/file_system/async_file_util.h" #include "storage/browser/file_system/async_file_util.h"
#include "storage/browser/file_system/external_mount_points.h" #include "storage/browser/file_system/external_mount_points.h"
@ -421,7 +423,9 @@ FileSystemBackend::CreateFileStreamReader(
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
storage::FileSystemContext* context) const { storage::FileSystemContext* context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) const {
DCHECK(url.is_valid()); DCHECK(url.is_valid());
if (!IsAccessAllowed(url)) if (!IsAccessAllowed(url))
@ -431,8 +435,15 @@ FileSystemBackend::CreateFileStreamReader(
case storage::kFileSystemTypeProvided: case storage::kFileSystemTypeProvided:
return file_system_provider_delegate_->CreateFileStreamReader( return file_system_provider_delegate_->CreateFileStreamReader(
url, offset, max_bytes_to_read, expected_modification_time, context); url, offset, max_bytes_to_read, expected_modification_time, context);
// The dlp file_access callback is needed for the local filesystem only.
case storage::kFileSystemTypeLocal: case storage::kFileSystemTypeLocal:
case storage::kFileSystemTypeRestrictedLocal: case storage::kFileSystemTypeRestrictedLocal:
return storage::FileStreamReader::CreateForLocalFile(
base::ThreadPool::CreateTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE})
.get(),
url.path(), offset, expected_modification_time,
std::move(file_access));
case storage::kFileSystemTypeDriveFs: case storage::kFileSystemTypeDriveFs:
case storage::kFileSystemTypeSmbFs: case storage::kFileSystemTypeSmbFs:
case storage::kFileSystemTypeFuseBox: case storage::kFileSystemTypeFuseBox:

@ -14,6 +14,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "components/account_id/account_id.h" #include "components/account_id/account_id.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "storage/browser/file_system/file_system_backend.h" #include "storage/browser/file_system/file_system_backend.h"
#include "storage/browser/file_system/task_runner_bound_observer_list.h" #include "storage/browser/file_system/task_runner_bound_observer_list.h"
#include "storage/common/file_system/file_system_types.h" #include "storage/common/file_system/file_system_types.h"
@ -125,7 +126,9 @@ class FileSystemBackend : public storage::ExternalFileSystemBackend {
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
storage::FileSystemContext* context) const override; storage::FileSystemContext* context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) const override;
std::unique_ptr<storage::FileStreamWriter> CreateFileStreamWriter( std::unique_ptr<storage::FileStreamWriter> CreateFileStreamWriter(
const storage::FileSystemURL& url, const storage::FileSystemURL& url,
int64_t offset, int64_t offset,

@ -4,12 +4,16 @@
#include "chrome/browser/chromeos/policy/dlp/dlp_scoped_file_access_delegate.h" #include "chrome/browser/chromeos/policy/dlp/dlp_scoped_file_access_delegate.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h" #include "base/functional/bind.h"
#include "base/functional/callback_forward.h" #include "base/functional/callback_forward.h"
#include "base/process/process_handle.h" #include "base/process/process_handle.h"
#include "base/task/bind_post_task.h" #include "base/task/bind_post_task.h"
#include "chrome/browser/chromeos/policy/dlp/dlp_file_access_copy_or_move_delegate_factory.h" #include "chrome/browser/chromeos/policy/dlp/dlp_file_access_copy_or_move_delegate_factory.h"
#include "chromeos/dbus/dlp/dlp_client.h" #include "chromeos/dbus/dlp/dlp_client.h"
#include "components/file_access/scoped_file_access.h"
#include "components/file_access/scoped_file_access_copy.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
@ -56,7 +60,7 @@ void DlpScopedFileAccessDelegate::Initialize(chromeos::DlpClient* client) {
if (!request_files_access_for_system_io_callback_) { if (!request_files_access_for_system_io_callback_) {
request_files_access_for_system_io_callback_ = request_files_access_for_system_io_callback_ =
new file_access::ScopedFileAccessDelegate:: new file_access::ScopedFileAccessDelegate::
RequestFilesAccessForSystemIOCallback(base::BindPostTask( RequestFilesAccessIOCallback(base::BindPostTask(
content::GetUIThreadTaskRunner({}), content::GetUIThreadTaskRunner({}),
base::BindRepeating(&RequestFileAccessForSystem))); base::BindRepeating(&RequestFileAccessForSystem)));
} }
@ -115,6 +119,29 @@ void DlpScopedFileAccessDelegate::RequestFilesAccessForSystem(
PostRequestFileAccessToDaemon(request, std::move(callback)); PostRequestFileAccessToDaemon(request, std::move(callback));
} }
DlpScopedFileAccessDelegate::RequestFilesAccessIOCallback
DlpScopedFileAccessDelegate::CreateFileAccessCallback(
const GURL& destination) const {
return base::BindPostTask(
content::GetUIThreadTaskRunner({}),
base::BindRepeating(
[](const GURL& destination, const std::vector<base::FilePath>& files,
base::OnceCallback<void(file_access::ScopedFileAccess)> callback) {
if (file_access::ScopedFileAccessDelegate::HasInstance()) {
file_access::ScopedFileAccessDelegate::Get()->RequestFilesAccess(
files, destination,
base::BindPostTask(content::GetIOThreadTaskRunner({}),
std::move(callback)));
} else {
content::GetIOThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback),
file_access::ScopedFileAccess::Allowed()));
}
},
destination));
}
void DlpScopedFileAccessDelegate::PostRequestFileAccessToDaemon( void DlpScopedFileAccessDelegate::PostRequestFileAccessToDaemon(
const ::dlp::RequestFileAccessRequest request, const ::dlp::RequestFileAccessRequest request,
base::OnceCallback<void(file_access::ScopedFileAccess)> callback) { base::OnceCallback<void(file_access::ScopedFileAccess)> callback) {

@ -44,6 +44,8 @@ class DlpScopedFileAccessDelegate
const std::vector<base::FilePath>& files, const std::vector<base::FilePath>& files,
base::OnceCallback<void(file_access::ScopedFileAccess)> callback) base::OnceCallback<void(file_access::ScopedFileAccess)> callback)
override; override;
RequestFilesAccessIOCallback CreateFileAccessCallback(
const GURL& destination) const override;
protected: protected:
explicit DlpScopedFileAccessDelegate(chromeos::DlpClient* client); explicit DlpScopedFileAccessDelegate(chromeos::DlpClient* client);

@ -36,7 +36,8 @@ class DlpScopedFileAccessDelegateTest : public testing::Test {
protected: protected:
content::BrowserTaskEnvironment task_environment_; content::BrowserTaskEnvironment task_environment_;
chromeos::FakeDlpClient fake_dlp_client_; chromeos::FakeDlpClient fake_dlp_client_;
DlpScopedFileAccessDelegate delegate_{&fake_dlp_client_}; std::unique_ptr<DlpScopedFileAccessDelegate> delegate_{
new DlpScopedFileAccessDelegate(&fake_dlp_client_)};
}; };
TEST_F(DlpScopedFileAccessDelegateTest, TestNoSingleton) { TEST_F(DlpScopedFileAccessDelegateTest, TestNoSingleton) {
@ -44,14 +45,14 @@ TEST_F(DlpScopedFileAccessDelegateTest, TestNoSingleton) {
base::CreateTemporaryFile(&file_path); base::CreateTemporaryFile(&file_path);
base::test::TestFuture<file_access::ScopedFileAccess> future1; base::test::TestFuture<file_access::ScopedFileAccess> future1;
delegate_.RequestFilesAccess({file_path}, GURL("example.com"), delegate_->RequestFilesAccess({file_path}, GURL("example.com"),
future1.GetCallback()); future1.GetCallback());
EXPECT_TRUE(future1.Get<0>().is_allowed()); EXPECT_TRUE(future1.Get<0>().is_allowed());
fake_dlp_client_.SetFileAccessAllowed(false); fake_dlp_client_.SetFileAccessAllowed(false);
base::test::TestFuture<file_access::ScopedFileAccess> future2; base::test::TestFuture<file_access::ScopedFileAccess> future2;
delegate_.RequestFilesAccess({file_path}, GURL("example.com"), delegate_->RequestFilesAccess({file_path}, GURL("example.com"),
future2.GetCallback()); future2.GetCallback());
EXPECT_FALSE(future2.Get<0>().is_allowed()); EXPECT_FALSE(future2.Get<0>().is_allowed());
} }
@ -87,6 +88,84 @@ TEST_F(DlpScopedFileAccessDelegateTest,
EXPECT_TRUE(future1.Get<0>().is_allowed()); EXPECT_TRUE(future1.Get<0>().is_allowed());
} }
TEST_F(DlpScopedFileAccessDelegateTest, CreateFileAccessCallbackAllowTest) {
base::FilePath file_path;
base::CreateTemporaryFile(&file_path);
DlpScopedFileAccessDelegate::Initialize(&fake_dlp_client_);
fake_dlp_client_.SetFileAccessAllowed(true);
base::test::TestFuture<file_access::ScopedFileAccess> future;
auto* delegate = file_access::ScopedFileAccessDelegate::Get();
auto cb = delegate->CreateFileAccessCallback(GURL("https://google.com"));
cb.Run({file_path}, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_allowed());
}
TEST_F(DlpScopedFileAccessDelegateTest, CreateFileAccessCallbackDenyTest) {
base::FilePath file_path;
base::CreateTemporaryFile(&file_path);
DlpScopedFileAccessDelegate::Initialize(&fake_dlp_client_);
fake_dlp_client_.SetFileAccessAllowed(false);
base::test::TestFuture<file_access::ScopedFileAccess> future;
auto* delegate = file_access::ScopedFileAccessDelegate::Get();
auto cb = delegate->CreateFileAccessCallback(GURL("https://google.com"));
cb.Run({file_path}, future.GetCallback());
EXPECT_FALSE(future.Get<0>().is_allowed());
}
TEST_F(DlpScopedFileAccessDelegateTest,
CreateFileAccessCallbackLostInstanceTest) {
base::FilePath file_path;
base::CreateTemporaryFile(&file_path);
DlpScopedFileAccessDelegate::Initialize(&fake_dlp_client_);
fake_dlp_client_.SetFileAccessAllowed(false);
base::test::TestFuture<file_access::ScopedFileAccess> future;
auto* delegate = file_access::ScopedFileAccessDelegate::Get();
auto cb = delegate->CreateFileAccessCallback(GURL("https://google.com"));
delegate_.reset();
cb.Run({file_path}, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_allowed());
}
TEST_F(DlpScopedFileAccessDelegateTest, GetCallbackSystemTest) {
base::FilePath file_path;
base::CreateTemporaryFile(&file_path);
DlpScopedFileAccessDelegate::Initialize(&fake_dlp_client_);
// Post a task on IO thread to sync with to be sure the IO task setting
// `request_files_access_for_system_io_callback_` has run.
base::RunLoop init;
auto io_thread = content::GetIOThreadTaskRunner({});
io_thread->PostTask(
FROM_HERE, base::BindOnce(&base::RunLoop::Quit, base::Unretained(&init)));
init.Run();
base::test::TestFuture<file_access::ScopedFileAccess> future;
auto* delegate = file_access::ScopedFileAccessDelegate::Get();
auto cb = delegate->GetCallbackForSystem();
EXPECT_TRUE(cb);
cb.Run({file_path}, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_allowed());
}
TEST_F(DlpScopedFileAccessDelegateTest, GetCallbackSystemNoSingeltonTest) {
base::FilePath file_path;
base::CreateTemporaryFile(&file_path);
base::test::TestFuture<file_access::ScopedFileAccess> future;
auto* delegate = file_access::ScopedFileAccessDelegate::Get();
auto cb = delegate->GetCallbackForSystem();
EXPECT_TRUE(cb);
cb.Run({file_path}, future.GetCallback());
EXPECT_TRUE(future.Get<0>().is_allowed());
}
TEST_F(DlpScopedFileAccessDelegateTest, TestMultipleInstances) { TEST_F(DlpScopedFileAccessDelegateTest, TestMultipleInstances) {
DlpScopedFileAccessDelegate::Initialize(nullptr); DlpScopedFileAccessDelegate::Initialize(nullptr);
EXPECT_NO_FATAL_FAILURE(DlpScopedFileAccessDelegate::Initialize(nullptr)); EXPECT_NO_FATAL_FAILURE(DlpScopedFileAccessDelegate::Initialize(nullptr));
@ -209,7 +288,6 @@ TEST_F(DlpScopedFileAccessDelegateTaskTest,
std::move(callback)); std::move(callback));
}), }),
false /* = restore_original_callback*/); false /* = restore_original_callback*/);
// The request for file access should be granted as that is the default // The request for file access should be granted as that is the default
// behaviour for no running dlp (no rules). // behaviour for no running dlp (no rules).
io_thread_->PostTask( io_thread_->PostTask(

@ -316,7 +316,9 @@ MediaFileSystemBackend::CreateFileStreamReader(
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
FileSystemContext* context) const { FileSystemContext* context,
file_access::ScopedFileAccessDelegate::
RequestFilesAccessIOCallback /*file_access*/) const {
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH) #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
if (url.type() == storage::kFileSystemTypeDeviceMedia) { if (url.type() == storage::kFileSystemTypeDeviceMedia) {
std::unique_ptr<storage::FileStreamReader> reader = std::unique_ptr<storage::FileStreamReader> reader =

@ -17,6 +17,7 @@
#include "build/chromeos_buildflags.h" #include "build/chromeos_buildflags.h"
#include "chrome/browser/media_galleries/media_galleries_preferences.h" #include "chrome/browser/media_galleries/media_galleries_preferences.h"
#include "components/download/public/common/quarantine_connection.h" #include "components/download/public/common/quarantine_connection.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "storage/browser/file_system/file_system_backend.h" #include "storage/browser/file_system/file_system_backend.h"
#include "storage/browser/file_system/file_system_request_info.h" #include "storage/browser/file_system/file_system_request_info.h"
#include "storage/browser/file_system/task_runner_bound_observer_list.h" #include "storage/browser/file_system/task_runner_bound_observer_list.h"
@ -85,7 +86,9 @@ class MediaFileSystemBackend : public storage::FileSystemBackend {
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
storage::FileSystemContext* context) const override; storage::FileSystemContext* context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) const override;
std::unique_ptr<storage::FileStreamWriter> CreateFileStreamWriter( std::unique_ptr<storage::FileStreamWriter> CreateFileStreamWriter(
const storage::FileSystemURL& url, const storage::FileSystemURL& url,
int64_t offset, int64_t offset,

@ -163,7 +163,9 @@ SyncFileSystemBackend::CreateFileStreamReader(
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
storage::FileSystemContext* context) const { storage::FileSystemContext* context,
file_access::ScopedFileAccessDelegate::
RequestFilesAccessIOCallback /*file_access*/) const {
DCHECK(CanHandleType(url.type())); DCHECK(CanHandleType(url.type()));
return GetDelegate()->CreateFileStreamReader( return GetDelegate()->CreateFileStreamReader(
url, offset, expected_modification_time, context); url, offset, expected_modification_time, context);

@ -12,6 +12,7 @@
#include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr.h"
#include "chrome/browser/sync_file_system/sync_callbacks.h" #include "chrome/browser/sync_file_system/sync_callbacks.h"
#include "chrome/browser/sync_file_system/sync_status_code.h" #include "chrome/browser/sync_file_system/sync_status_code.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "storage/browser/file_system/file_system_backend.h" #include "storage/browser/file_system/file_system_backend.h"
#include "storage/browser/file_system/file_system_quota_util.h" #include "storage/browser/file_system/file_system_quota_util.h"
#include "storage/browser/file_system/sandbox_file_system_backend_delegate.h" #include "storage/browser/file_system/sandbox_file_system_backend_delegate.h"
@ -60,7 +61,9 @@ class SyncFileSystemBackend : public storage::FileSystemBackend {
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
storage::FileSystemContext* context) const override; storage::FileSystemContext* context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) const override;
std::unique_ptr<storage::FileStreamWriter> CreateFileStreamWriter( std::unique_ptr<storage::FileStreamWriter> CreateFileStreamWriter(
const storage::FileSystemURL& url, const storage::FileSystemURL& url,
int64_t offset, int64_t offset,

@ -3,6 +3,9 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "components/file_access/scoped_file_access_delegate.h" #include "components/file_access/scoped_file_access_delegate.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "components/file_access/scoped_file_access.h"
namespace file_access { namespace file_access {
// static // static
@ -35,6 +38,21 @@ void ScopedFileAccessDelegate::RequestFilesAccessForSystemIO(
} }
} }
// static
ScopedFileAccessDelegate::RequestFilesAccessIOCallback
ScopedFileAccessDelegate::GetCallbackForSystem() {
return base::BindRepeating(
[](const std::vector<base::FilePath>& file_paths,
base::OnceCallback<void(ScopedFileAccess)> callback) {
if (request_files_access_for_system_io_callback_) {
request_files_access_for_system_io_callback_->Run(
file_paths, std::move(callback));
} else {
std::move(callback).Run(ScopedFileAccess::Allowed());
}
});
}
ScopedFileAccessDelegate::ScopedFileAccessDelegate() { ScopedFileAccessDelegate::ScopedFileAccessDelegate() {
if (scoped_file_access_delegate_) { if (scoped_file_access_delegate_) {
delete scoped_file_access_delegate_; delete scoped_file_access_delegate_;
@ -53,18 +71,18 @@ ScopedFileAccessDelegate*
ScopedFileAccessDelegate::scoped_file_access_delegate_ = nullptr; ScopedFileAccessDelegate::scoped_file_access_delegate_ = nullptr;
// static // static
ScopedFileAccessDelegate::RequestFilesAccessForSystemIOCallback* ScopedFileAccessDelegate::RequestFilesAccessIOCallback*
ScopedFileAccessDelegate::request_files_access_for_system_io_callback_ = ScopedFileAccessDelegate::request_files_access_for_system_io_callback_ =
nullptr; nullptr;
ScopedFileAccessDelegate::ScopedRequestFilesAccessCallbackForTesting:: ScopedFileAccessDelegate::ScopedRequestFilesAccessCallbackForTesting::
ScopedRequestFilesAccessCallbackForTesting( ScopedRequestFilesAccessCallbackForTesting(
RequestFilesAccessForSystemIOCallback callback, RequestFilesAccessIOCallback callback,
bool restore_original_callback) bool restore_original_callback)
: restore_original_callback_(restore_original_callback) { : restore_original_callback_(restore_original_callback) {
original_callback_ = request_files_access_for_system_io_callback_; original_callback_ = request_files_access_for_system_io_callback_;
request_files_access_for_system_io_callback_ = request_files_access_for_system_io_callback_ =
new RequestFilesAccessForSystemIOCallback(std::move(callback)); new RequestFilesAccessIOCallback(std::move(callback));
} }
ScopedFileAccessDelegate::ScopedRequestFilesAccessCallbackForTesting:: ScopedFileAccessDelegate::ScopedRequestFilesAccessCallbackForTesting::

@ -29,7 +29,7 @@ namespace file_access {
// to packages without direct access to the UI thread. // to packages without direct access to the UI thread.
class COMPONENT_EXPORT(FILE_ACCESS) ScopedFileAccessDelegate { class COMPONENT_EXPORT(FILE_ACCESS) ScopedFileAccessDelegate {
public: public:
using RequestFilesAccessForSystemIOCallback = using RequestFilesAccessIOCallback =
base::RepeatingCallback<void(const std::vector<base::FilePath>&, base::RepeatingCallback<void(const std::vector<base::FilePath>&,
base::OnceCallback<void(ScopedFileAccess)>)>; base::OnceCallback<void(ScopedFileAccess)>)>;
@ -62,6 +62,12 @@ class COMPONENT_EXPORT(FILE_ACCESS) ScopedFileAccessDelegate {
const std::vector<base::FilePath>& files, const std::vector<base::FilePath>& files,
base::OnceCallback<void(file_access::ScopedFileAccess)> callback) = 0; base::OnceCallback<void(file_access::ScopedFileAccess)> callback) = 0;
// Creates a callback to gain file access for the given `destination`. The
// callback should be called on the IO thread. The method itself from the UI
// thread.
virtual RequestFilesAccessIOCallback CreateFileAccessCallback(
const GURL& destination) const = 0;
// Called from the IO thread. Switches to the UI thread and calls // Called from the IO thread. Switches to the UI thread and calls
// RequestFilesAccessForSystem there. The `callback` is run on the IO thread // RequestFilesAccessForSystem there. The `callback` is run on the IO thread
// again. // again.
@ -105,7 +111,7 @@ class COMPONENT_EXPORT(FILE_ACCESS) ScopedFileAccessDelegate {
// Otherwise, it destroys the original callback when this class is // Otherwise, it destroys the original callback when this class is
// destroyed. // destroyed.
explicit ScopedRequestFilesAccessCallbackForTesting( explicit ScopedRequestFilesAccessCallbackForTesting(
RequestFilesAccessForSystemIOCallback callback, RequestFilesAccessIOCallback callback,
bool restore_original_callback = true); bool restore_original_callback = true);
virtual ~ScopedRequestFilesAccessCallbackForTesting(); virtual ~ScopedRequestFilesAccessCallbackForTesting();
@ -121,8 +127,12 @@ class COMPONENT_EXPORT(FILE_ACCESS) ScopedFileAccessDelegate {
private: private:
bool restore_original_callback_; bool restore_original_callback_;
RequestFilesAccessForSystemIOCallback* original_callback_ = nullptr; RequestFilesAccessIOCallback* original_callback_ = nullptr;
}; };
// Get a callback to get file access to files for system component
// destination. Can be called from IO or UI thread. The callback should be
// called on IO thread only.
static RequestFilesAccessIOCallback GetCallbackForSystem();
protected: protected:
ScopedFileAccessDelegate(); ScopedFileAccessDelegate();
@ -136,7 +146,7 @@ class COMPONENT_EXPORT(FILE_ACCESS) ScopedFileAccessDelegate {
// A single instance for a callback living on the IO thread which switches to // A single instance for a callback living on the IO thread which switches to
// the UI thread to call RequestFilesAccessForSystem from there and switch // the UI thread to call RequestFilesAccessForSystem from there and switch
// back to IO thread handing the ScopedFileAccess to another (given) callback. // back to IO thread handing the ScopedFileAccess to another (given) callback.
static RequestFilesAccessForSystemIOCallback* static RequestFilesAccessIOCallback*
request_files_access_for_system_io_callback_; request_files_access_for_system_io_callback_;
}; };

@ -8,6 +8,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/functional/bind.h" #include "base/functional/bind.h"
#include "base/functional/callback_forward.h" #include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h" #include "base/location.h"
#include "base/test/mock_callback.h" #include "base/test/mock_callback.h"
#include "base/test/task_environment.h" #include "base/test/task_environment.h"
@ -30,6 +31,10 @@ class ScopedFileAccessDelegateTestInstance : public ScopedFileAccessDelegate {
void RequestFilesAccessForSystem( void RequestFilesAccessForSystem(
const std::vector<base::FilePath>& files, const std::vector<base::FilePath>& files,
base::OnceCallback<void(ScopedFileAccess)> callback) override {} base::OnceCallback<void(ScopedFileAccess)> callback) override {}
RequestFilesAccessIOCallback CreateFileAccessCallback(
const GURL& destination) const override {
return base::DoNothing();
}
}; };
int ScopedFileAccessDelegateTestInstance::instance_counter = 0; int ScopedFileAccessDelegateTestInstance::instance_counter = 0;

@ -25,6 +25,10 @@ class MockScopedFileAccessDelegate : public ScopedFileAccessDelegate {
(const std::vector<base::FilePath>&, (const std::vector<base::FilePath>&,
base::OnceCallback<void(ScopedFileAccess)>), base::OnceCallback<void(ScopedFileAccess)>),
(override)); (override));
MOCK_METHOD((RequestFilesAccessIOCallback),
CreateFileAccessCallback,
(const GURL& destination),
(const override));
}; };
} // namespace file_access } // namespace file_access

@ -6,6 +6,7 @@
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/functional/bind.h" #include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "content/browser/blob_storage/chrome_blob_storage_context.h" #include "content/browser/blob_storage/chrome_blob_storage_context.h"
#include "content/browser/child_process_security_policy_impl.h" #include "content/browser/child_process_security_policy_impl.h"
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
@ -31,6 +32,11 @@ class BindingDelegate : public storage::BlobRegistryImpl::Delegate {
bool CanAccessDataForOrigin(const url::Origin& origin) override { bool CanAccessDataForOrigin(const url::Origin& origin) override {
return security_policy_handle_.CanAccessDataForOrigin(origin); return security_policy_handle_.CanAccessDataForOrigin(origin);
} }
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
GetAccessCallback() override {
// TODO (b/262203074) create actual callback
return base::NullCallback();
}
private: private:
ChildProcessSecurityPolicyImpl::Handle security_policy_handle_; ChildProcessSecurityPolicyImpl::Handle security_policy_handle_;

@ -12,11 +12,13 @@
#include "base/files/file_enumerator.h" #include "base/files/file_enumerator.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/functional/bind.h" #include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/guid.h" #include "base/guid.h"
#include "base/supports_user_data.h" #include "base/supports_user_data.h"
#include "base/task/single_thread_task_runner.h" #include "base/task/single_thread_task_runner.h"
#include "base/task/task_runner.h" #include "base/task/task_runner.h"
#include "base/task/thread_pool.h" #include "base/task/thread_pool.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "content/browser/storage_partition_impl.h" #include "content/browser/storage_partition_impl.h"
#include "content/public/browser/blob_handle.h" #include "content/public/browser/blob_handle.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
@ -214,14 +216,16 @@ std::unique_ptr<BlobHandle> ChromeBlobStorageContext::CreateMemoryBackedBlob(
return blob_handle; return blob_handle;
} }
void ChromeBlobStorageContext::CreateFileSystemBlob( void ChromeBlobStorageContext::CreateFileSystemBlobWithFileAccess(
scoped_refptr<storage::FileSystemContext> file_system_context, scoped_refptr<storage::FileSystemContext> file_system_context,
mojo::PendingReceiver<blink::mojom::Blob> blob_receiver, mojo::PendingReceiver<blink::mojom::Blob> blob_receiver,
const storage::FileSystemURL& url, const storage::FileSystemURL& url,
const std::string& blob_uuid, const std::string& blob_uuid,
const std::string& content_type, const std::string& content_type,
const uint64_t file_size, const uint64_t file_size,
const base::Time& file_modification_time) { const base::Time& file_modification_time,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
auto blob_builder = std::make_unique<storage::BlobDataBuilder>(blob_uuid); auto blob_builder = std::make_unique<storage::BlobDataBuilder>(blob_uuid);
@ -229,9 +233,9 @@ void ChromeBlobStorageContext::CreateFileSystemBlob(
// Use AppendFileSystemFile here, since we're streaming the file directly // Use AppendFileSystemFile here, since we're streaming the file directly
// from the file system backend, and the file thus might not actually be // from the file system backend, and the file thus might not actually be
// backed by a file on disk. // backed by a file on disk.
blob_builder->AppendFileSystemFile(url, 0, file_size, blob_builder->AppendFileSystemFile(
file_modification_time, url, 0, file_size, file_modification_time,
std::move(file_system_context)); std::move(file_system_context), std::move(file_access));
} }
blob_builder->set_content_type(content_type); blob_builder->set_content_type(content_type);
@ -245,6 +249,19 @@ void ChromeBlobStorageContext::CreateFileSystemBlob(
storage::BlobImpl::Create(std::move(blob_handle), std::move(blob_receiver)); storage::BlobImpl::Create(std::move(blob_handle), std::move(blob_receiver));
} }
void ChromeBlobStorageContext::CreateFileSystemBlob(
scoped_refptr<storage::FileSystemContext> file_system_context,
mojo::PendingReceiver<blink::mojom::Blob> blob_receiver,
const storage::FileSystemURL& url,
const std::string& blob_uuid,
const std::string& content_type,
const uint64_t file_size,
const base::Time& file_modification_time) {
CreateFileSystemBlobWithFileAccess(
file_system_context, std::move(blob_receiver), url, blob_uuid,
content_type, file_size, file_modification_time, base::NullCallback());
}
// static // static
scoped_refptr<network::SharedURLLoaderFactory> scoped_refptr<network::SharedURLLoaderFactory>
ChromeBlobStorageContext::URLLoaderFactoryForToken( ChromeBlobStorageContext::URLLoaderFactoryForToken(

@ -12,10 +12,12 @@
#include <vector> #include <vector>
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/task/sequenced_task_runner_helpers.h" #include "base/task/sequenced_task_runner_helpers.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "mojo/public/cpp/bindings/pending_remote.h" #include "mojo/public/cpp/bindings/pending_remote.h"
@ -78,6 +80,23 @@ class CONTENT_EXPORT ChromeBlobStorageContext
base::span<const uint8_t> data, base::span<const uint8_t> data,
const std::string& content_type); const std::string& content_type);
// Creates a FileSystem File blob accessible by the renderer via the blob
// remote corresponding to `blob_receiver`. The callback can grant or deny the
// read access to the file. The callback `file_access` is used to grant or
// deny access to files under dlp restrictions. Leaving it at NullCallback
// will lead to default behaviour, which currently is granting it (until
// b/265908846 is done).
void CreateFileSystemBlobWithFileAccess(
scoped_refptr<storage::FileSystemContext> file_system_context,
mojo::PendingReceiver<blink::mojom::Blob> blob_receiver,
const storage::FileSystemURL& url,
const std::string& blob_uuid,
const std::string& content_type,
const uint64_t file_size,
const base::Time& file_modification_time,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access);
// Creates a FileSystem File blob accessible by the renderer via the blob // Creates a FileSystem File blob accessible by the renderer via the blob
// remote corresponding to `blob_receiver`. // remote corresponding to `blob_receiver`.
void CreateFileSystemBlob( void CreateFileSystemBlob(

@ -5,6 +5,7 @@ import("//testing/test.gni")
test("storage_unittests") { test("storage_unittests") {
deps = [ deps = [
"//components/file_access:test_support",
"//storage/browser:unittests", "//storage/browser:unittests",
"//storage/common:unittests", "//storage/common:unittests",
] ]

@ -351,6 +351,7 @@ source_set("unittests") {
"//base/test:test_support", "//base/test:test_support",
"//build:chromeos_buildflags", "//build:chromeos_buildflags",
"//components/file_access:file_access", "//components/file_access:file_access",
"//components/file_access:test_support",
"//components/services/filesystem/public/mojom", "//components/services/filesystem/public/mojom",
"//components/services/storage/public/cpp", "//components/services/storage/public/cpp",
"//mojo/public/cpp/system", "//mojo/public/cpp/system",
@ -420,6 +421,7 @@ static_library("test_support") {
":browser", ":browser",
"//base/test:test_support", "//base/test:test_support",
"//build:chromeos_buildflags", "//build:chromeos_buildflags",
"//components/file_access:file_access",
"//components/services/storage/public/cpp", "//components/services/storage/public/cpp",
"//components/services/storage/public/mojom", "//components/services/storage/public/mojom",
"//net:test_support", "//net:test_support",

@ -17,6 +17,7 @@
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "storage/browser/blob/blob_entry.h" #include "storage/browser/blob/blob_entry.h"
#include "storage/browser/blob/blob_storage_registry.h" #include "storage/browser/blob/blob_storage_registry.h"
#include "storage/browser/blob/shareable_blob_data_item.h" #include "storage/browser/blob/shareable_blob_data_item.h"
@ -146,13 +147,16 @@ BlobDataBuilder::FutureFile BlobDataBuilder::AppendFutureFile(
return FutureFile(std::move(item)); return FutureFile(std::move(item));
} }
void BlobDataBuilder::AppendFile(const FilePath& file_path, void BlobDataBuilder::AppendFile(
uint64_t offset, const FilePath& file_path,
uint64_t length, uint64_t offset,
const base::Time& expected_modification_time) { uint64_t length,
auto item = BlobDataItem::CreateFile(file_path, offset, length, const base::Time& expected_modification_time,
expected_modification_time, file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
ShareableFileReference::Get(file_path)); file_access) {
auto item = BlobDataItem::CreateFile(
file_path, offset, length, expected_modification_time,
ShareableFileReference::Get(file_path), std::move(file_access));
DCHECK(!item->IsFutureFileItem()) << file_path.value(); DCHECK(!item->IsFutureFileItem()) << file_path.value();
auto shareable_item = base::MakeRefCounted<ShareableBlobDataItem>( auto shareable_item = base::MakeRefCounted<ShareableBlobDataItem>(
@ -277,7 +281,8 @@ void BlobDataBuilder::SliceBlob(const BlobEntry* source,
case BlobDataItem::Type::kFile: { case BlobDataItem::Type::kFile: {
data_item = BlobDataItem::CreateFile( data_item = BlobDataItem::CreateFile(
source_item->path(), source_item->offset() + item_offset, read_size, source_item->path(), source_item->offset() + item_offset, read_size,
source_item->expected_modification_time(), source_item->file_ref_); source_item->expected_modification_time(), source_item->file_ref_,
source_item->file_access_);
if (source_item->IsFutureFileItem()) { if (source_item->IsFutureFileItem()) {
// The source file isn't a real file yet (path is fake), so store the // The source file isn't a real file yet (path is fake), so store the
@ -290,7 +295,7 @@ void BlobDataBuilder::SliceBlob(const BlobEntry* source,
data_item = BlobDataItem::CreateFileFilesystem( data_item = BlobDataItem::CreateFileFilesystem(
source_item->filesystem_url(), source_item->offset() + item_offset, source_item->filesystem_url(), source_item->offset() + item_offset,
read_size, source_item->expected_modification_time(), read_size, source_item->expected_modification_time(),
source_item->file_system_context()); source_item->file_system_context(), source_item->file_access_);
break; break;
} }
case BlobDataItem::Type::kReadableDataHandle: { case BlobDataItem::Type::kReadableDataHandle: {
@ -320,11 +325,13 @@ void BlobDataBuilder::AppendFileSystemFile(
uint64_t offset, uint64_t offset,
uint64_t length, uint64_t length,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
scoped_refptr<FileSystemContext> file_system_context) { scoped_refptr<FileSystemContext> file_system_context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) {
DCHECK_GT(length, 0ul); DCHECK_GT(length, 0ul);
auto item = BlobDataItem::CreateFileFilesystem( auto item = BlobDataItem::CreateFileFilesystem(
url, offset, length, expected_modification_time, url, offset, length, expected_modification_time,
std::move(file_system_context)); std::move(file_system_context), std::move(file_access));
auto shareable_item = base::MakeRefCounted<ShareableBlobDataItem>( auto shareable_item = base::MakeRefCounted<ShareableBlobDataItem>(
std::move(item), ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA); std::move(item), ShareableBlobDataItem::POPULATED_WITHOUT_QUOTA);

@ -13,8 +13,10 @@
#include "base/component_export.h" #include "base/component_export.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/numerics/checked_math.h" #include "base/numerics/checked_math.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "components/services/storage/public/mojom/blob_storage_context.mojom.h" #include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
#include "storage/browser/blob/blob_data_item.h" #include "storage/browser/blob/blob_data_item.h"
#include "storage/browser/blob/blob_data_snapshot.h" #include "storage/browser/blob/blob_data_snapshot.h"
@ -132,11 +134,17 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataBuilder {
// You must know the length of the file, you cannot use kuint64max to specify // You must know the length of the file, you cannot use kuint64max to specify
// the whole file. This method creates a ShareableFileReference to the given // the whole file. This method creates a ShareableFileReference to the given
// file, which is stored in this builder. // file, which is stored in this builder. The callback `file_access` is used
void AppendFile(const base::FilePath& file_path, // to grant or deny access to files under dlp restrictions. Leaving it at
uint64_t offset, // NullCallback will lead to default behaviour, which currently is granting it
uint64_t length, // (until b/265908846 is done).
const base::Time& expected_modification_time); void AppendFile(
const base::FilePath& file_path,
uint64_t offset,
uint64_t length,
const base::Time& expected_modification_time,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access = base::NullCallback());
void AppendBlob(const std::string& uuid, void AppendBlob(const std::string& uuid,
uint64_t offset, uint64_t offset,
@ -150,7 +158,9 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataBuilder {
uint64_t offset, uint64_t offset,
uint64_t length, uint64_t length,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
scoped_refptr<FileSystemContext> file_system_context); scoped_refptr<FileSystemContext> file_system_context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access = base::NullCallback());
void AppendReadableDataHandle(scoped_refptr<DataHandle> data_handle) { void AppendReadableDataHandle(scoped_refptr<DataHandle> data_handle) {
auto length = data_handle->GetSize(); auto length = data_handle->GetSize();

@ -10,6 +10,8 @@
#include "base/ranges/algorithm.h" #include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/remote.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "services/network/public/cpp/data_pipe_to_source_stream.h" #include "services/network/public/cpp/data_pipe_to_source_stream.h"
@ -80,8 +82,12 @@ scoped_refptr<BlobDataItem> BlobDataItem::CreateBytesDescription(
} }
// static // static
scoped_refptr<BlobDataItem> BlobDataItem::CreateFile(base::FilePath path) { scoped_refptr<BlobDataItem> BlobDataItem::CreateFile(
return CreateFile(path, 0, blink::BlobUtils::kUnknownSize); base::FilePath path,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) {
return CreateFile(path, 0, blink::BlobUtils::kUnknownSize, base::Time(),
nullptr, std::move(file_access));
} }
// static // static
@ -90,12 +96,15 @@ scoped_refptr<BlobDataItem> BlobDataItem::CreateFile(
uint64_t offset, uint64_t offset,
uint64_t length, uint64_t length,
base::Time expected_modification_time, base::Time expected_modification_time,
scoped_refptr<ShareableFileReference> file_ref) { scoped_refptr<ShareableFileReference> file_ref,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) {
auto item = auto item =
base::WrapRefCounted(new BlobDataItem(Type::kFile, offset, length)); base::WrapRefCounted(new BlobDataItem(Type::kFile, offset, length));
item->path_ = std::move(path); item->path_ = std::move(path);
item->expected_modification_time_ = std::move(expected_modification_time); item->expected_modification_time_ = std::move(expected_modification_time);
item->file_ref_ = std::move(file_ref); item->file_ref_ = std::move(file_ref);
item->file_access_ = std::move(file_access);
// TODO(mek): DCHECK(!item->IsFutureFileItem()) when BlobDataBuilder has some // TODO(mek): DCHECK(!item->IsFutureFileItem()) when BlobDataBuilder has some
// other way of slicing a future file. // other way of slicing a future file.
return item; return item;
@ -120,12 +129,15 @@ scoped_refptr<BlobDataItem> BlobDataItem::CreateFileFilesystem(
uint64_t offset, uint64_t offset,
uint64_t length, uint64_t length,
base::Time expected_modification_time, base::Time expected_modification_time,
scoped_refptr<FileSystemContext> file_system_context) { scoped_refptr<FileSystemContext> file_system_context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) {
auto item = base::WrapRefCounted( auto item = base::WrapRefCounted(
new BlobDataItem(Type::kFileFilesystem, offset, length)); new BlobDataItem(Type::kFileFilesystem, offset, length));
item->filesystem_url_ = url; item->filesystem_url_ = url;
item->expected_modification_time_ = std::move(expected_modification_time); item->expected_modification_time_ = std::move(expected_modification_time);
item->file_system_context_ = std::move(file_system_context); item->file_system_context_ = std::move(file_system_context);
item->file_access_ = std::move(file_access);
return item; return item;
} }

@ -14,8 +14,11 @@
#include "base/component_export.h" #include "base/component_export.h"
#include "base/containers/span.h" #include "base/containers/span.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "components/file_access/scoped_file_access.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "components/services/storage/public/mojom/blob_storage_context.mojom.h" #include "components/services/storage/public/mojom/blob_storage_context.mojom.h"
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
#include "storage/browser/blob/shareable_file_reference.h" #include "storage/browser/blob/shareable_file_reference.h"
@ -83,13 +86,18 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataItem
static scoped_refptr<BlobDataItem> CreateBytes( static scoped_refptr<BlobDataItem> CreateBytes(
base::span<const uint8_t> bytes); base::span<const uint8_t> bytes);
static scoped_refptr<BlobDataItem> CreateBytesDescription(size_t length); static scoped_refptr<BlobDataItem> CreateBytesDescription(size_t length);
static scoped_refptr<BlobDataItem> CreateFile(base::FilePath path); static scoped_refptr<BlobDataItem> CreateFile(
base::FilePath path,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access = base::NullCallback());
static scoped_refptr<BlobDataItem> CreateFile( static scoped_refptr<BlobDataItem> CreateFile(
base::FilePath path, base::FilePath path,
uint64_t offset, uint64_t offset,
uint64_t length, uint64_t length,
base::Time expected_modification_time = base::Time(), base::Time expected_modification_time = base::Time(),
scoped_refptr<ShareableFileReference> file_ref = nullptr); scoped_refptr<ShareableFileReference> file_ref = nullptr,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access = base::NullCallback());
static scoped_refptr<BlobDataItem> CreateFutureFile(uint64_t offset, static scoped_refptr<BlobDataItem> CreateFutureFile(uint64_t offset,
uint64_t length, uint64_t length,
uint64_t file_id); uint64_t file_id);
@ -98,7 +106,9 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataItem
uint64_t offset, uint64_t offset,
uint64_t length, uint64_t length,
base::Time expected_modification_time, base::Time expected_modification_time,
scoped_refptr<FileSystemContext> file_system_context); scoped_refptr<FileSystemContext> file_system_context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access = base::NullCallback());
static scoped_refptr<BlobDataItem> CreateReadableDataHandle( static scoped_refptr<BlobDataItem> CreateReadableDataHandle(
scoped_refptr<DataHandle> data_handle, scoped_refptr<DataHandle> data_handle,
uint64_t offset, uint64_t offset,
@ -146,6 +156,12 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataItem
// Returns |file_id| given to CreateFutureFile. // Returns |file_id| given to CreateFutureFile.
uint64_t GetFutureFileID() const; uint64_t GetFutureFileID() const;
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access() const {
DCHECK(type_ == Type::kFile || type_ == Type::kFileFilesystem);
return file_access_;
}
private: private:
friend class BlobBuilderFromStream; friend class BlobBuilderFromStream;
friend class BlobDataBuilder; friend class BlobDataBuilder;
@ -195,6 +211,9 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobDataItem
scoped_refptr<FileSystemContext> scoped_refptr<FileSystemContext>
file_system_context_; // For Type::kFileFilesystem. file_system_context_; // For Type::kFileFilesystem.
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access_; // For Type::kFile and kFileFilesystem.
}; };
COMPONENT_EXPORT(STORAGE_BROWSER) COMPONENT_EXPORT(STORAGE_BROWSER)

@ -17,6 +17,7 @@
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/task/thread_pool.h" #include "base/task/thread_pool.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
#include "net/base/net_errors.h" #include "net/base/net_errors.h"
#include "storage/browser/blob/blob_data_handle.h" #include "storage/browser/blob/blob_data_handle.h"
@ -515,8 +516,7 @@ BlobReader::Status BlobReader::ReadItem() {
GetOrCreateFileReaderAtIndex(current_item_index_); GetOrCreateFileReaderAtIndex(current_item_index_);
if (!reader) if (!reader)
return ReportError(net::ERR_FILE_NOT_FOUND); return ReportError(net::ERR_FILE_NOT_FOUND);
return ReadFileItem(reader, bytes_to_read, item.file_access());
return ReadFileItem(reader, bytes_to_read);
} }
void BlobReader::AdvanceItem() { void BlobReader::AdvanceItem() {
@ -560,8 +560,11 @@ void BlobReader::ReadBytesItem(const BlobDataItem& item, int bytes_to_read) {
AdvanceBytesRead(bytes_to_read); AdvanceBytesRead(bytes_to_read);
} }
BlobReader::Status BlobReader::ReadFileItem(FileStreamReader* reader, BlobReader::Status BlobReader::ReadFileItem(
int bytes_to_read) { FileStreamReader* reader,
int bytes_to_read,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!io_pending_) DCHECK(!io_pending_)
<< "Can't begin IO while another IO operation is pending."; << "Can't begin IO while another IO operation is pending.";
@ -725,7 +728,8 @@ std::unique_ptr<FileStreamReader> BlobReader::CreateFileStreamReader(
} }
return FileStreamReader::CreateForLocalFile( return FileStreamReader::CreateForLocalFile(
file_task_runner_.get(), item.path(), file_task_runner_.get(), item.path(),
item.offset() + additional_offset, item.expected_modification_time()); item.offset() + additional_offset, item.expected_modification_time(),
item.file_access());
case BlobDataItem::Type::kFileFilesystem: { case BlobDataItem::Type::kFileFilesystem: {
int64_t max_bytes_to_read = int64_t max_bytes_to_read =
item.length() == std::numeric_limits<uint64_t>::max() item.length() == std::numeric_limits<uint64_t>::max()
@ -738,7 +742,8 @@ std::unique_ptr<FileStreamReader> BlobReader::CreateFileStreamReader(
} }
return item.file_system_context()->CreateFileStreamReader( return item.file_system_context()->CreateFileStreamReader(
item.filesystem_url(), item.offset() + additional_offset, item.filesystem_url(), item.offset() + additional_offset,
max_bytes_to_read, item.expected_modification_time()); max_bytes_to_read, item.expected_modification_time(),
item.file_access());
} }
case BlobDataItem::Type::kBytes: case BlobDataItem::Type::kBytes:
case BlobDataItem::Type::kBytesDescription: case BlobDataItem::Type::kBytesDescription:

@ -13,9 +13,13 @@
#include <vector> #include <vector>
#include "base/component_export.h" #include "base/component_export.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/gtest_prod_util.h" #include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "components/file_access/scoped_file_access.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "mojo/public/cpp/base/big_buffer.h" #include "mojo/public/cpp/base/big_buffer.h"
#include "mojo/public/cpp/system/data_pipe.h" #include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/completion_once_callback.h" #include "net/base/completion_once_callback.h"
@ -168,7 +172,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobReader {
FRIEND_TEST_ALL_PREFIXES(BlobReaderTest, HandleBeforeAsyncCancel); FRIEND_TEST_ALL_PREFIXES(BlobReaderTest, HandleBeforeAsyncCancel);
FRIEND_TEST_ALL_PREFIXES(BlobReaderTest, ReadFromIncompleteBlob); FRIEND_TEST_ALL_PREFIXES(BlobReaderTest, ReadFromIncompleteBlob);
BlobReader(const BlobDataHandle* blob_handle); explicit BlobReader(const BlobDataHandle* blob_handle);
bool total_size_calculated() const { bool total_size_calculated() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@ -208,7 +212,11 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobReader {
void AdvanceItem(); void AdvanceItem();
void AdvanceBytesRead(int result); void AdvanceBytesRead(int result);
void ReadBytesItem(const BlobDataItem& item, int bytes_to_read); void ReadBytesItem(const BlobDataItem& item, int bytes_to_read);
BlobReader::Status ReadFileItem(FileStreamReader* reader, int bytes_to_read); BlobReader::Status ReadFileItem(
FileStreamReader* reader,
int bytes_to_read,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access);
void DidReadFile(int result); void DidReadFile(int result);
void DeleteItemReaders(); void DeleteItemReaders();
Status ReadReadableDataHandle(const BlobDataItem& item, int bytes_to_read); Status ReadReadableDataHandle(const BlobDataItem& item, int bytes_to_read);

@ -8,9 +8,12 @@
#include "base/barrier_closure.h" #include "base/barrier_closure.h"
#include "base/functional/bind.h" #include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h" #include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr.h"
#include "base/task/sequenced_task_runner.h" #include "base/task/sequenced_task_runner.h"
#include "components/file_access/scoped_file_access.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "net/base/features.h" #include "net/base/features.h"
#include "storage/browser/blob/blob_builder_from_stream.h" #include "storage/browser/blob/blob_builder_from_stream.h"
#include "storage/browser/blob/blob_data_builder.h" #include "storage/browser/blob/blob_data_builder.h"
@ -57,17 +60,21 @@ class BlobRegistryImpl::BlobUnderConstruction {
mojo::Remote<blink::mojom::Blob> blob; mojo::Remote<blink::mojom::Blob> blob;
}; };
BlobUnderConstruction(BlobRegistryImpl* blob_registry, BlobUnderConstruction(
const std::string& uuid, BlobRegistryImpl* blob_registry,
const std::string& content_type, const std::string& uuid,
const std::string& content_disposition, const std::string& content_type,
std::vector<ElementEntry> elements, const std::string& content_disposition,
mojo::ReportBadMessageCallback bad_message_callback) std::vector<ElementEntry> elements,
mojo::ReportBadMessageCallback bad_message_callback,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access)
: blob_registry_(blob_registry), : blob_registry_(blob_registry),
uuid_(uuid), uuid_(uuid),
builder_(std::make_unique<BlobDataBuilder>(uuid)), builder_(std::make_unique<BlobDataBuilder>(uuid)),
elements_(std::move(elements)), elements_(std::move(elements)),
bad_message_callback_(std::move(bad_message_callback)) { bad_message_callback_(std::move(bad_message_callback)),
file_access_(std::move(file_access)) {
builder_->set_content_type(content_type); builder_->set_content_type(content_type);
builder_->set_content_disposition(content_disposition); builder_->set_content_disposition(content_disposition);
} }
@ -213,6 +220,10 @@ class BlobRegistryImpl::BlobUnderConstruction {
// Number of dependent blobs that have started constructing. // Number of dependent blobs that have started constructing.
size_t ready_dependent_blob_count_ = 0; size_t ready_dependent_blob_count_ = 0;
// Callback to gain dlp file access.
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access_;
base::WeakPtrFactory<BlobUnderConstruction> weak_ptr_factory_{this}; base::WeakPtrFactory<BlobUnderConstruction> weak_ptr_factory_{this};
}; };
@ -383,9 +394,9 @@ void BlobRegistryImpl::BlobUnderConstruction::ResolvedAllBlobDependencies() {
} }
} else if (element->is_file()) { } else if (element->is_file()) {
const auto& f = element->get_file(); const auto& f = element->get_file();
builder_->AppendFile( builder_->AppendFile(f->path, f->offset, f->length,
f->path, f->offset, f->length, f->expected_modification_time.value_or(base::Time()),
f->expected_modification_time.value_or(base::Time())); file_access_);
} else if (element->is_blob()) { } else if (element->is_blob()) {
DCHECK(blob_uuid_it != referenced_blob_uuids_.end()); DCHECK(blob_uuid_it != referenced_blob_uuids_.end());
const std::string& blob_uuid = *blob_uuid_it++; const std::string& blob_uuid = *blob_uuid_it++;
@ -565,7 +576,7 @@ void BlobRegistryImpl::Register(
blobs_under_construction_[uuid] = std::make_unique<BlobUnderConstruction>( blobs_under_construction_[uuid] = std::make_unique<BlobUnderConstruction>(
this, uuid, content_type, content_disposition, std::move(element_entries), this, uuid, content_type, content_disposition, std::move(element_entries),
receivers_.GetBadMessageCallback()); receivers_.GetBadMessageCallback(), delegate->GetAccessCallback());
std::unique_ptr<BlobDataHandle> handle = context_->AddFutureBlob( std::unique_ptr<BlobDataHandle> handle = context_->AddFutureBlob(
uuid, content_type, content_disposition, uuid, content_type, content_disposition,

@ -9,6 +9,9 @@
#include "base/component_export.h" #include "base/component_export.h"
#include "base/containers/flat_set.h" #include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h" #include "base/containers/unique_ptr_adapters.h"
#include "base/functional/callback_forward.h"
#include "components/file_access/scoped_file_access.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/self_owned_associated_receiver.h" #include "mojo/public/cpp/bindings/self_owned_associated_receiver.h"
#include "storage/browser/blob/blob_url_registry.h" #include "storage/browser/blob/blob_url_registry.h"
@ -35,6 +38,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) BlobRegistryImpl
virtual ~Delegate() {} virtual ~Delegate() {}
virtual bool CanReadFile(const base::FilePath& file) = 0; virtual bool CanReadFile(const base::FilePath& file) = 0;
virtual bool CanAccessDataForOrigin(const url::Origin& origin) = 0; virtual bool CanAccessDataForOrigin(const url::Origin& origin) = 0;
virtual file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
GetAccessCallback() = 0;
}; };
BlobRegistryImpl(base::WeakPtr<BlobStorageContext> context, BlobRegistryImpl(base::WeakPtr<BlobStorageContext> context,

@ -530,8 +530,8 @@ void BlobStorageContext::FinishBuilding(BlobEntry* entry) {
scoped_refptr<BlobDataItem> new_item = BlobDataItem::CreateFile( scoped_refptr<BlobDataItem> new_item = BlobDataItem::CreateFile(
source_item->path(), source_item->path(),
source_item->offset() + copy.source_item_offset, dest_size, source_item->offset() + copy.source_item_offset, dest_size,
source_item->expected_modification_time(), source_item->expected_modification_time(), source_item->file_ref_,
source_item->file_ref_); source_item->file_access_);
copy.dest_item->set_item(std::move(new_item)); copy.dest_item->set_item(std::move(new_item));
break; break;
} }

@ -12,7 +12,11 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/component_export.h" #include "base/component_export.h"
#include "base/files/file.h" #include "base/files/file.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "components/file_access/scoped_file_access.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "components/services/storage/public/cpp/filesystem/filesystem_proxy.h" #include "components/services/storage/public/cpp/filesystem/filesystem_proxy.h"
#include "net/base/completion_once_callback.h" #include "net/base/completion_once_callback.h"
@ -45,7 +49,9 @@ class FileStreamReader {
scoped_refptr<base::TaskRunner> task_runner, scoped_refptr<base::TaskRunner> task_runner,
const base::FilePath& file_path, const base::FilePath& file_path,
int64_t initial_offset, int64_t initial_offset,
const base::Time& expected_modification_time); const base::Time& expected_modification_time,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access = base::NullCallback());
// Creates a new FileReader for a local file |file_path|, which is a // Creates a new FileReader for a local file |file_path|, which is a
// relative path into |filesystem_proxy|. This function's behavior // relative path into |filesystem_proxy|. This function's behavior

@ -16,7 +16,9 @@
#include "base/files/file.h" #include "base/files/file.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/functional/callback_forward.h" #include "base/functional/callback_forward.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "storage/browser/file_system/file_permission_policy.h" #include "storage/browser/file_system/file_permission_policy.h"
#include "storage/browser/file_system/file_stream_reader.h"
#include "storage/browser/file_system/open_file_system_mode.h" #include "storage/browser/file_system/open_file_system_mode.h"
#include "storage/browser/file_system/task_runner_bound_observer_list.h" #include "storage/browser/file_system/task_runner_bound_observer_list.h"
#include "storage/common/file_system/file_system_types.h" #include "storage/common/file_system/file_system_types.h"
@ -121,13 +123,17 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemBackend {
// ERR_UPLOAD_FILE_CHANGED error. // ERR_UPLOAD_FILE_CHANGED error.
// This method itself does *not* check if the given path exists and is a // This method itself does *not* check if the given path exists and is a
// regular file. At most |max_bytes_to_read| can be fetched from the file // regular file. At most |max_bytes_to_read| can be fetched from the file
// stream reader. // stream reader. The callback `file_access` grants access to dlp restricted
// files. If it is a NullCallback currently the access will be granted. This
// will change to being denied after b/265908846
virtual std::unique_ptr<FileStreamReader> CreateFileStreamReader( virtual std::unique_ptr<FileStreamReader> CreateFileStreamReader(
const FileSystemURL& url, const FileSystemURL& url,
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
FileSystemContext* context) const = 0; FileSystemContext* context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) const = 0;
// Creates a new file stream writer for a given filesystem URL |url| with an // Creates a new file stream writer for a given filesystem URL |url| with an
// offset |offset|. // offset |offset|.

@ -19,6 +19,7 @@
#include "base/task/sequenced_task_runner.h" #include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h" #include "base/task/single_thread_task_runner.h"
#include "base/types/pass_key.h" #include "base/types/pass_key.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "components/services/storage/public/cpp/buckets/bucket_info.h" #include "components/services/storage/public/cpp/buckets/bucket_info.h"
#include "components/services/storage/public/cpp/buckets/constants.h" #include "components/services/storage/public/cpp/buckets/constants.h"
#include "components/services/storage/public/cpp/quota_client_callback_wrapper.h" #include "components/services/storage/public/cpp/quota_client_callback_wrapper.h"
@ -595,14 +596,17 @@ std::unique_ptr<FileStreamReader> FileSystemContext::CreateFileStreamReader(
const FileSystemURL& url, const FileSystemURL& url,
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time) { const base::Time& expected_modification_time,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) {
if (!url.is_valid()) if (!url.is_valid())
return nullptr; return nullptr;
FileSystemBackend* backend = GetFileSystemBackend(url.type()); FileSystemBackend* backend = GetFileSystemBackend(url.type());
if (!backend) if (!backend)
return nullptr; return nullptr;
return backend->CreateFileStreamReader(url, offset, max_bytes_to_read, return backend->CreateFileStreamReader(url, offset, max_bytes_to_read,
expected_modification_time, this); expected_modification_time, this,
std::move(file_access));
} }
std::unique_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter( std::unique_ptr<FileStreamWriter> FileSystemContext::CreateFileStreamWriter(

@ -15,6 +15,7 @@
#include "base/component_export.h" #include "base/component_export.h"
#include "base/files/file.h" #include "base/files/file.h"
#include "base/functional/callback.h" #include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/ref_counted_delete_on_sequence.h" #include "base/memory/ref_counted_delete_on_sequence.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
@ -22,6 +23,7 @@
#include "base/threading/sequence_bound.h" #include "base/threading/sequence_bound.h"
#include "base/types/pass_key.h" #include "base/types/pass_key.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "components/services/storage/public/cpp/quota_error_or.h" #include "components/services/storage/public/cpp/quota_error_or.h"
#include "components/services/storage/public/mojom/quota_client.mojom.h" #include "components/services/storage/public/mojom/quota_client.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/receiver.h"
@ -281,7 +283,9 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) FileSystemContext
const FileSystemURL& url, const FileSystemURL& url,
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time); const base::Time& expected_modification_time,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access = base::NullCallback());
// Creates new FileStreamWriter instance to write into a file pointed by // Creates new FileStreamWriter instance to write into a file pointed by
// `url` from `offset`. // `url` from `offset`.

@ -129,10 +129,12 @@ IsolatedFileSystemBackend::CreateFileStreamReader(
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
FileSystemContext* context) const { FileSystemContext* context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) const {
return FileStreamReader::CreateForLocalFile( return FileStreamReader::CreateForLocalFile(
context->default_file_task_runner(), url.path(), offset, context->default_file_task_runner(), url.path(), offset,
expected_modification_time); expected_modification_time, std::move(file_access));
} }
std::unique_ptr<FileStreamWriter> std::unique_ptr<FileStreamWriter>

@ -9,6 +9,7 @@
#include <memory> #include <memory>
#include "components/file_access/scoped_file_access_delegate.h"
#include "storage/browser/file_system/file_system_backend.h" #include "storage/browser/file_system/file_system_backend.h"
#include "storage/browser/file_system/task_runner_bound_observer_list.h" #include "storage/browser/file_system/task_runner_bound_observer_list.h"
@ -44,7 +45,9 @@ class IsolatedFileSystemBackend : public FileSystemBackend {
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
FileSystemContext* context) const override; FileSystemContext* context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) const override;
std::unique_ptr<FileStreamWriter> CreateFileStreamWriter( std::unique_ptr<FileStreamWriter> CreateFileStreamWriter(
const FileSystemURL& url, const FileSystemURL& url,
int64_t offset, int64_t offset,

@ -12,11 +12,14 @@
#include "base/check_op.h" #include "base/check_op.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/functional/bind.h" #include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h" #include "base/location.h"
#include "base/task/bind_post_task.h" #include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h" #include "base/task/sequenced_task_runner.h"
#include "base/task/task_runner.h" #include "base/task/task_runner.h"
#include "base/types/pass_key.h" #include "base/types/pass_key.h"
#include "components/file_access/scoped_file_access.h"
#include "components/file_access/scoped_file_access_delegate.h" #include "components/file_access/scoped_file_access_delegate.h"
#include "net/base/file_stream.h" #include "net/base/file_stream.h"
#include "net/base/io_buffer.h" #include "net/base/io_buffer.h"
@ -46,10 +49,13 @@ std::unique_ptr<FileStreamReader> FileStreamReader::CreateForLocalFile(
scoped_refptr<base::TaskRunner> task_runner, scoped_refptr<base::TaskRunner> task_runner,
const base::FilePath& file_path, const base::FilePath& file_path,
int64_t initial_offset, int64_t initial_offset,
const base::Time& expected_modification_time) { const base::Time& expected_modification_time,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) {
return std::make_unique<LocalFileStreamReader>( return std::make_unique<LocalFileStreamReader>(
std::move(task_runner), file_path, initial_offset, std::move(task_runner), file_path, initial_offset,
expected_modification_time, base::PassKey<FileStreamReader>()); expected_modification_time, base::PassKey<FileStreamReader>(),
std::move(file_access));
} }
LocalFileStreamReader::~LocalFileStreamReader() = default; LocalFileStreamReader::~LocalFileStreamReader() = default;
@ -84,11 +90,14 @@ LocalFileStreamReader::LocalFileStreamReader(
const base::FilePath& file_path, const base::FilePath& file_path,
int64_t initial_offset, int64_t initial_offset,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
base::PassKey<FileStreamReader> /*pass_key*/) base::PassKey<FileStreamReader> /*pass_key*/,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access)
: task_runner_(std::move(task_runner)), : task_runner_(std::move(task_runner)),
file_path_(file_path), file_path_(file_path),
initial_offset_(initial_offset), initial_offset_(initial_offset),
expected_modification_time_(expected_modification_time) {} expected_modification_time_(expected_modification_time),
file_access_(std::move(file_access)) {}
void LocalFileStreamReader::Open(net::CompletionOnceCallback callback) { void LocalFileStreamReader::Open(net::CompletionOnceCallback callback) {
DCHECK(!has_pending_open_); DCHECK(!has_pending_open_);
@ -98,8 +107,12 @@ void LocalFileStreamReader::Open(net::CompletionOnceCallback callback) {
base::OnceCallback<void(file_access::ScopedFileAccess)> open_cb = base::OnceCallback<void(file_access::ScopedFileAccess)> open_cb =
base::BindOnce(&LocalFileStreamReader::OnScopedFileAccessRequested, base::BindOnce(&LocalFileStreamReader::OnScopedFileAccessRequested,
weak_factory_.GetWeakPtr(), std::move(callback)); weak_factory_.GetWeakPtr(), std::move(callback));
if (file_access_) {
file_access_.Run({file_path_}, std::move(open_cb));
return;
}
// TODO(b/262199707 b/265908846): Replace with getting access through a // TODO(b/265908846): Replace with getting access through a
// callback. // callback.
file_access::ScopedFileAccessDelegate::RequestFilesAccessForSystemIO( file_access::ScopedFileAccessDelegate::RequestFilesAccessForSystemIO(
{file_path_}, std::move(open_cb)); {file_path_}, std::move(open_cb));

@ -12,10 +12,13 @@
#include "base/component_export.h" #include "base/component_export.h"
#include "base/files/file.h" #include "base/files/file.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/types/pass_key.h" #include "base/types/pass_key.h"
#include "components/file_access/scoped_file_access.h" #include "components/file_access/scoped_file_access.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "net/base/completion_once_callback.h" #include "net/base/completion_once_callback.h"
#include "storage/browser/file_system/file_stream_reader.h" #include "storage/browser/file_system/file_stream_reader.h"
@ -34,11 +37,14 @@ namespace storage {
class COMPONENT_EXPORT(STORAGE_BROWSER) LocalFileStreamReader class COMPONENT_EXPORT(STORAGE_BROWSER) LocalFileStreamReader
: public FileStreamReader { : public FileStreamReader {
public: public:
LocalFileStreamReader(scoped_refptr<base::TaskRunner> task_runner, LocalFileStreamReader(
const base::FilePath& file_path, scoped_refptr<base::TaskRunner> task_runner,
int64_t initial_offset, const base::FilePath& file_path,
const base::Time& expected_modification_time, int64_t initial_offset,
base::PassKey<FileStreamReader> pass_key); const base::Time& expected_modification_time,
base::PassKey<FileStreamReader> pass_key,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access);
~LocalFileStreamReader() override; ~LocalFileStreamReader() override;
// FileStreamReader overrides. // FileStreamReader overrides.
@ -76,6 +82,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) LocalFileStreamReader
const int64_t initial_offset_; const int64_t initial_offset_;
const base::Time expected_modification_time_; const base::Time expected_modification_time_;
bool has_pending_open_ = false; bool has_pending_open_ = false;
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access_;
base::WeakPtrFactory<LocalFileStreamReader> weak_factory_{this}; base::WeakPtrFactory<LocalFileStreamReader> weak_factory_{this};
}; };

@ -15,6 +15,7 @@
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h" #include "base/files/scoped_temp_dir.h"
#include "base/functional/bind.h" #include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/functional/callback_helpers.h" #include "base/functional/callback_helpers.h"
#include "base/location.h" #include "base/location.h"
#include "base/run_loop.h" #include "base/run_loop.h"
@ -70,14 +71,23 @@ class LocalFileStreamReaderTest : public FileStreamReaderTest {
file_thread_.Stop(); file_thread_.Stop();
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
} }
std::unique_ptr<FileStreamReader> CreateFileReader( std::unique_ptr<FileStreamReader> CreateFileReader(
const std::string& file_name, const std::string& file_name,
int64_t initial_offset, int64_t initial_offset,
const base::Time& expected_modification_time) override { const base::Time& expected_modification_time) override {
return CreateFileReader(file_name, initial_offset,
expected_modification_time, base::NullCallback());
}
std::unique_ptr<FileStreamReader> CreateFileReader(
const std::string& file_name,
int64_t initial_offset,
const base::Time& expected_modification_time,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) {
return FileStreamReader::CreateForLocalFile( return FileStreamReader::CreateForLocalFile(
file_task_runner(), test_dir().AppendASCII(file_name), initial_offset, file_task_runner(), test_dir().AppendASCII(file_name), initial_offset,
expected_modification_time); expected_modification_time, std::move(file_access));
} }
void WriteFile(const std::string& file_name, void WriteFile(const std::string& file_name,
@ -124,7 +134,7 @@ INSTANTIATE_TYPED_TEST_SUITE_P(Local,
FileStreamReaderTypedTest, FileStreamReaderTypedTest,
LocalFileStreamReaderTest); LocalFileStreamReaderTest);
// TODO(b/262199707 b/265908846): Replace direct call to // TODO(b/265908846): Replace direct call to
// file_access::ScopedFileAccessDelegate with getting access through a callback. // file_access::ScopedFileAccessDelegate with getting access through a callback.
TEST_F(LocalFileStreamReaderTest, ReadAllowedByDataLeakPrevention) { TEST_F(LocalFileStreamReaderTest, ReadAllowedByDataLeakPrevention) {
this->WriteTestFile(); this->WriteTestFile();
@ -151,7 +161,7 @@ TEST_F(LocalFileStreamReaderTest, ReadAllowedByDataLeakPrevention) {
ASSERT_EQ(this->kTestData, data); ASSERT_EQ(this->kTestData, data);
} }
// TODO(b/262199707 b/265908846): Replace direct call to // TODO(b/265908846): Replace direct call to
// file_access::ScopedFileAccessDelegate with getting access through a callback. // file_access::ScopedFileAccessDelegate with getting access through a callback.
TEST_F(LocalFileStreamReaderTest, ReadBlockedByDataLeakPrevention) { TEST_F(LocalFileStreamReaderTest, ReadBlockedByDataLeakPrevention) {
this->WriteTestFile(); this->WriteTestFile();
@ -178,4 +188,50 @@ TEST_F(LocalFileStreamReaderTest, ReadBlockedByDataLeakPrevention) {
ASSERT_EQ("", data); ASSERT_EQ("", data);
} }
TEST_F(LocalFileStreamReaderTest, ReadAllowedByDataLeakPreventionCallback) {
this->WriteTestFile();
base::MockRepeatingCallback<void(
const std::vector<base::FilePath>&,
base::OnceCallback<void(file_access::ScopedFileAccess)>)>
callback;
EXPECT_CALL(
callback,
Run(testing::ElementsAre(test_dir().AppendASCII(kTestFileName)), _))
.WillOnce(base::test::RunOnceCallback<1>(CreateScopedFileAccess(true)));
std::unique_ptr<FileStreamReader> reader(this->CreateFileReader(
std::string(this->kTestFileName), 0, this->test_file_modification_time(),
callback.Get()));
int result = 0;
std::string data;
ReadFromReader(reader.get(), &data, this->kTestData.size(), &result);
ASSERT_EQ(net::OK, result);
ASSERT_EQ(this->kTestData, data);
}
TEST_F(LocalFileStreamReaderTest, ReadBlockedByDataLeakPreventionCallback) {
this->WriteTestFile();
base::MockRepeatingCallback<void(
const std::vector<base::FilePath>&,
base::OnceCallback<void(file_access::ScopedFileAccess)>)>
callback;
file_access::ScopedFileAccessDelegate::
ScopedRequestFilesAccessCallbackForTesting file_access_callback(
callback.Get());
EXPECT_CALL(
callback,
Run(testing::ElementsAre(test_dir().AppendASCII(kTestFileName)), _))
.WillOnce(base::test::RunOnceCallback<1>(CreateScopedFileAccess(false)));
std::unique_ptr<FileStreamReader> reader(this->CreateFileReader(
std::string(this->kTestFileName), 0, this->test_file_modification_time(),
callback.Get()));
int result = 0;
std::string data;
ReadFromReader(reader.get(), &data, this->kTestData.size(), &result);
ASSERT_EQ(net::ERR_ACCESS_DENIED, result);
ASSERT_EQ("", data);
}
} // namespace storage } // namespace storage

@ -13,6 +13,7 @@
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/functional/bind.h" #include "base/functional/bind.h"
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "storage/browser/file_system/async_file_util_adapter.h" #include "storage/browser/file_system/async_file_util_adapter.h"
#include "storage/browser/file_system/copy_or_move_file_validator.h" #include "storage/browser/file_system/copy_or_move_file_validator.h"
#include "storage/browser/file_system/file_stream_reader.h" #include "storage/browser/file_system/file_stream_reader.h"
@ -137,7 +138,9 @@ SandboxFileSystemBackend::CreateFileStreamReader(
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
FileSystemContext* context) const { FileSystemContext* context,
file_access::ScopedFileAccessDelegate::
RequestFilesAccessIOCallback /*file_access*/) const {
DCHECK(CanHandleType(url.type())); DCHECK(CanHandleType(url.type()));
DCHECK(delegate_); DCHECK(delegate_);
return delegate_->CreateFileStreamReader(url, offset, return delegate_->CreateFileStreamReader(url, offset,

@ -14,6 +14,7 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/component_export.h" #include "base/component_export.h"
#include "base/memory/raw_ptr.h" #include "base/memory/raw_ptr.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "storage/browser/file_system/file_system_backend.h" #include "storage/browser/file_system/file_system_backend.h"
#include "storage/browser/file_system/file_system_quota_util.h" #include "storage/browser/file_system/file_system_quota_util.h"
#include "storage/browser/file_system/sandbox_file_system_backend_delegate.h" #include "storage/browser/file_system/sandbox_file_system_backend_delegate.h"
@ -58,7 +59,9 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) SandboxFileSystemBackend
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
FileSystemContext* context) const override; FileSystemContext* context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) const override;
std::unique_ptr<FileStreamWriter> CreateFileStreamWriter( std::unique_ptr<FileStreamWriter> CreateFileStreamWriter(
const FileSystemURL& url, const FileSystemURL& url,
int64_t offset, int64_t offset,

@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "storage/browser/test/mock_blob_registry_delegate.h" #include "storage/browser/test/mock_blob_registry_delegate.h"
#include "base/functional/callback_helpers.h"
namespace storage { namespace storage {
@ -15,4 +16,9 @@ bool MockBlobRegistryDelegate::CanAccessDataForOrigin(
return can_access_data_for_origin; return can_access_data_for_origin;
} }
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
MockBlobRegistryDelegate::GetAccessCallback() {
return base::DoNothing();
}
} // namespace storage } // namespace storage

@ -19,6 +19,8 @@ class MockBlobRegistryDelegate
bool CanReadFile(const base::FilePath& file) override; bool CanReadFile(const base::FilePath& file) override;
bool CanAccessDataForOrigin(const url::Origin& origin) override; bool CanAccessDataForOrigin(const url::Origin& origin) override;
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
GetAccessCallback() override;
bool can_read_file_result = true; bool can_read_file_result = true;
bool can_access_data_for_origin = true; bool can_access_data_for_origin = true;

@ -13,6 +13,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/observer_list.h" #include "base/observer_list.h"
#include "base/task/sequenced_task_runner.h" #include "base/task/sequenced_task_runner.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "storage/browser/file_system/copy_or_move_file_validator.h" #include "storage/browser/file_system/copy_or_move_file_validator.h"
#include "storage/browser/file_system/file_observers.h" #include "storage/browser/file_system/file_observers.h"
#include "storage/browser/file_system/file_system_operation.h" #include "storage/browser/file_system/file_system_operation.h"
@ -216,7 +217,9 @@ std::unique_ptr<FileStreamReader> TestFileSystemBackend::CreateFileStreamReader(
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
FileSystemContext* context) const { FileSystemContext* context,
file_access::ScopedFileAccessDelegate::
RequestFilesAccessIOCallback /*file_access*/) const {
return std::make_unique<SandboxFileStreamReader>(context, url, offset, return std::make_unique<SandboxFileStreamReader>(context, url, offset,
expected_modification_time); expected_modification_time);
} }

@ -11,6 +11,7 @@
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "components/file_access/scoped_file_access_delegate.h"
#include "storage/browser/file_system/async_file_util_adapter.h" #include "storage/browser/file_system/async_file_util_adapter.h"
#include "storage/browser/file_system/file_system_backend.h" #include "storage/browser/file_system/file_system_backend.h"
#include "storage/browser/file_system/task_runner_bound_observer_list.h" #include "storage/browser/file_system/task_runner_bound_observer_list.h"
@ -61,7 +62,9 @@ class TestFileSystemBackend : public FileSystemBackend {
int64_t offset, int64_t offset,
int64_t max_bytes_to_read, int64_t max_bytes_to_read,
const base::Time& expected_modification_time, const base::Time& expected_modification_time,
FileSystemContext* context) const override; FileSystemContext* context,
file_access::ScopedFileAccessDelegate::RequestFilesAccessIOCallback
file_access) const override;
std::unique_ptr<FileStreamWriter> CreateFileStreamWriter( std::unique_ptr<FileStreamWriter> CreateFileStreamWriter(
const FileSystemURL& url, const FileSystemURL& url,
int64_t offset, int64_t offset,