0

Use request_initiator in quarantine

When source_url cannot be used (e.g. data:// URLs), try using the
request_initiator as HostUrl instead.

Bug: 351165321
Change-Id: I0c481a2da634891abaf18d7795cd911d04aec1ff
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5824218
Commit-Queue: Daniel Rubery <drubery@chromium.org>
Reviewed-by: Ayu Ishii <ayui@chromium.org>
Reviewed-by: Will Harris <wfh@chromium.org>
Reviewed-by: Derek Schuff <dschuff@chromium.org>
Reviewed-by: Min Qin <qinmin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1352856}
This commit is contained in:
Daniel Rubery
2024-09-09 17:27:07 +00:00
committed by Chromium LUCI CQ
parent abefe04fdc
commit 4fbe682556
21 changed files with 220 additions and 58 deletions

@ -42,7 +42,8 @@ void ScanFile(
if (quarantine_remote) {
quarantine_remote->QuarantineFile(
dest_platform_path, GURL(), GURL(), std::string(),
dest_platform_path, GURL(), GURL(), /*request_initiator=*/std::nullopt,
std::string(),
base::BindOnce(&OnFileQuarantined, std::move(result_callback)));
} else {
std::move(result_callback).Run(base::File::FILE_OK);

@ -8,6 +8,7 @@ include_rules = [
"+components/safe_browsing/buildflags.h",
"+components/safe_browsing/content/common",
"+components/services/quarantine/quarantine.h",
"+components/services/quarantine/public",
"+components/ukm/test_ukm_recorder.h",
"+crypto",
"+mojo/public/c/system",

@ -650,7 +650,7 @@ void BaseFile::AnnotateWithSourceInformation(
authority_url, referrer_url));
quarantine_service_->QuarantineFile(
full_path_, authority_url, referrer_url, client_guid,
full_path_, authority_url, referrer_url, request_initiator, client_guid,
base::BindOnce(&BaseFile::OnFileQuarantined,
weak_factory_.GetWeakPtr()));
}

@ -33,6 +33,8 @@
#include "components/download/public/common/download_file_impl.h"
#include "components/download/public/common/download_interrupt_reasons.h"
#include "components/download/public/common/mock_input_stream.h"
#include "components/services/quarantine/public/mojom/quarantine.mojom.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "net/base/net_errors.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -44,11 +46,13 @@
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::InSequence;
using ::testing::Return;
using ::testing::Sequence;
using ::testing::SetArgPointee;
using ::testing::StrictMock;
using ::testing::WithArg;
namespace download {
namespace {
@ -139,6 +143,18 @@ class TestDownloadFileImpl : public DownloadFileImpl {
#endif
};
class MockQuarantine : public quarantine::mojom::Quarantine {
public:
MOCK_METHOD(void,
QuarantineFile,
(const base::FilePath& full_path,
const GURL& source_url,
const GURL& referrer_url,
const std::optional<url::Origin>& request_initiator,
const std::string& client_guid,
quarantine::mojom::Quarantine::QuarantineFileCallback callback));
};
} // namespace
class DownloadFileTest : public testing::Test {
@ -164,7 +180,8 @@ class DownloadFileTest : public testing::Test {
additional_streams_(std::vector<raw_ptr<StrictMock<MockInputStream>>>{
nullptr, nullptr}),
bytes_(-1),
bytes_per_sec_(-1) {}
bytes_per_sec_(-1),
quarantine_remote_(&quarantine_) {}
~DownloadFileTest() override {}
@ -187,6 +204,12 @@ class DownloadFileTest : public testing::Test {
EXPECT_CALL(*(observer_.get()), DestinationUpdate(_, _, _))
.Times(AnyNumber())
.WillRepeatedly(Invoke(this, &DownloadFileTest::SetUpdateDownloadInfo));
ON_CALL(quarantine_, QuarantineFile(_, _, _, _, _, _))
.WillByDefault(WithArg<5>(
[](quarantine::mojom::Quarantine::QuarantineFileCallback callback) {
std::move(callback).Run(
quarantine::mojom::QuarantineFileResult::OK);
}));
bool result = download_dir_.CreateUniqueTempDir();
CHECK(result);
}
@ -425,9 +448,18 @@ class DownloadFileTest : public testing::Test {
break;
case RENAME_AND_ANNOTATE:
// We cannot rebind a mojo::Remote without resetting it. The
// real implementation binds a new Remote on every call to
// RenameAndAnnotate, but it's simpler to reuse
// `quarantine_remote_` in tests.
quarantine_remote_.reset();
download_file_->RenameAndAnnotate(
full_path, "12345678-ABCD-1234-DCBA-123456789ABC", GURL(), GURL(),
/*request_initiator=*/std::nullopt, mojo::NullRemote(),
full_path, "12345678-ABCD-1234-DCBA-123456789ABC",
GURL("https://source.example.com/"),
GURL("https://referrer.example.com/"),
/*request_initiator=*/
url::Origin::Create(GURL("https://initiator.example.com/")),
quarantine_remote_.BindNewPipeAndPassRemote(),
std::move(completion_callback));
break;
}
@ -527,6 +559,8 @@ class DownloadFileTest : public testing::Test {
// Keep track of what data should be saved to the disk file.
std::string expected_data_;
MockQuarantine quarantine_;
private:
void SetRenameResult(base::OnceClosure closure,
DownloadInterruptReason* reason_p,
@ -540,6 +574,8 @@ class DownloadFileTest : public testing::Test {
std::move(closure).Run();
}
mojo::Receiver<quarantine::mojom::Quarantine> quarantine_remote_;
base::test::TaskEnvironment task_environment_;
};
@ -1274,4 +1310,31 @@ TEST_F(DownloadFileTest, SecondStreamReadsOffsetWrittenByFirst) {
DestroyDownloadFile(0, false);
}
TEST_F(DownloadFileTest, PropagatesUrlAndInitiatorToQuarantine) {
ASSERT_TRUE(CreateDownloadFile(true));
base::FilePath initial_path(download_file_->FullPath());
base::FilePath path_1(initial_path.InsertBeforeExtensionASCII("_1"));
EXPECT_CALL(
quarantine_,
QuarantineFile(
_, GURL("https://source.example.com/"),
GURL("https://referrer.example.com"),
Eq(url::Origin::Create(GURL("https://initiator.example.com/"))), _,
_))
.WillOnce(WithArg<5>(
[](quarantine::mojom::Quarantine::QuarantineFileCallback callback) {
std::move(callback).Run(
quarantine::mojom::QuarantineFileResult::OK);
}));
base::FilePath new_path;
EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_NONE,
RenameAndAnnotate(path_1, &new_path));
EXPECT_EQ(path_1.value(), new_path.value());
FinishStream(DOWNLOAD_INTERRUPT_REASON_NONE, true, kEmptyHash);
base::RunLoop().RunUntilIdle();
DestroyDownloadFile(0);
}
} // namespace download

@ -11,5 +11,6 @@ mojom("mojom") {
"//mojo/public/mojom/base",
"//sandbox/policy/mojom",
"//url/mojom:url_mojom_gurl",
"//url/mojom:url_mojom_origin",
]
}

@ -7,6 +7,7 @@ module quarantine.mojom;
import "mojo/public/mojom/base/file_path.mojom";
import "sandbox/policy/mojom/sandbox.mojom";
import "url/mojom/url.mojom";
import "url/mojom/origin.mojom";
enum QuarantineFileResult {
OK, // Success.
@ -29,9 +30,15 @@ enum QuarantineFileResult {
[ServiceSandbox=sandbox.mojom.Sandbox.kNoSandbox]
interface Quarantine {
// Quarantine a file that was downloaded from the internet. This method
// will apply platform-dependent annotations to the file to indicate that
// it came from the internet, and what URL(s) led to the file. For more
// details, see the documentation in
// //components/services/quarantine/quarantine.h.
QuarantineFile(mojo_base.mojom.FilePath full_path,
url.mojom.Url source_url,
url.mojom.Url referrer_url,
url.mojom.Origin? request_initiator,
string client_guid)
=> (QuarantineFileResult result);
};

@ -13,6 +13,7 @@ namespace quarantine {
void QuarantineFile(const base::FilePath& file,
const GURL& source_url,
const GURL& referrer_url,
const std::optional<url::Origin>& request_initiator,
const std::string& client_guid,
mojom::Quarantine::QuarantineFileCallback callback) {
std::move(callback).Run(QuarantineFileResult::OK);

@ -58,6 +58,9 @@ using mojom::QuarantineFileResult;
// |source_url|: URL from which the file content was downloaded. This is empty
// for off-the-record download.
// |referrer_url|: Referring URL. This is empty for off-the-record download.
// `request_initiator`: Origin initiating the request. This is meant to
// replace the source URL when the source URL is not suitable for use in an
// annotation (e.g. a data URL).
// |client_guid|: Only used on Windows. Identifies the client application
// that downloaded the file.
// |callback|: Will be called with the quarantine result on completion.
@ -70,6 +73,7 @@ using mojom::QuarantineFileResult;
void QuarantineFile(const base::FilePath& file,
const GURL& source_url,
const GURL& referrer_url,
const std::optional<url::Origin>& request_initiator,
const std::string& client_guid,
mojom::Quarantine::QuarantineFileCallback callback);

@ -27,6 +27,7 @@ void OnFileAdded(mojom::Quarantine::QuarantineFileCallback callback,
void QuarantineFile(const base::FilePath& file,
const GURL& source_url_unsafe,
const GURL& referrer_url_unsafe,
const std::optional<url::Origin>& request_initiator,
const std::string& client_guid,
mojom::Quarantine::QuarantineFileCallback callback) {
if (!chromeos::DlpClient::Get() || !chromeos::DlpClient::Get()->IsAlive()) {

@ -34,6 +34,7 @@ void QuarantineImpl::QuarantineFile(
const base::FilePath& full_path,
const GURL& source_url,
const GURL& referrer_url,
const std::optional<url::Origin>& request_initiator,
const std::string& client_guid,
mojom::Quarantine::QuarantineFileCallback callback) {
#if BUILDFLAG(IS_MAC)
@ -50,7 +51,7 @@ void QuarantineImpl::QuarantineFile(
FROM_HERE,
base::BindOnce(
&quarantine::QuarantineFile, full_path, source_url, referrer_url,
client_guid,
request_initiator, client_guid,
base::BindOnce(&ReplyToCallback,
base::SingleThreadTaskRunner::GetCurrentDefault(),
std::move(callback))));

@ -33,6 +33,7 @@ class QuarantineImpl : public mojom::Quarantine {
const base::FilePath& full_path,
const GURL& source_url,
const GURL& referrer_url,
const std::optional<url::Origin>& request_initiator,
const std::string& client_guid,
mojom::Quarantine::QuarantineFileCallback callback) override;

@ -96,6 +96,7 @@ bool AddOriginMetadataToFile(const base::FilePath& file,
void QuarantineFile(const base::FilePath& file,
const GURL& source_url_unsafe,
const GURL& referrer_url_unsafe,
const std::optional<url::Origin>& request_initiator,
const std::string& client_guid,
mojom::Quarantine::QuarantineFileCallback callback) {
if (!base::PathExists(file)) {
@ -111,6 +112,9 @@ void QuarantineFile(const base::FilePath& file,
GURL source_url = SanitizeUrlForQuarantine(source_url_unsafe);
GURL referrer_url = SanitizeUrlForQuarantine(referrer_url_unsafe);
if (source_url.is_empty() && request_initiator.has_value()) {
source_url = SanitizeUrlForQuarantine(request_initiator->GetURL());
}
// Don't consider it an error if we fail to add origin metadata.
AddOriginMetadataToFile(file, source_url, referrer_url);

@ -26,9 +26,11 @@
namespace quarantine {
namespace {
void CheckQuarantineResult(QuarantineFileResult result,
void CheckQuarantineResult(base::OnceClosure quit_closure,
QuarantineFileResult result,
QuarantineFileResult expected_result) {
EXPECT_EQ(expected_result, result);
std::move(quit_closure).Run();
}
class QuarantineMacTest : public testing::Test {
@ -69,23 +71,37 @@ class QuarantineMacTest : public testing::Test {
};
TEST_F(QuarantineMacTest, CheckMetadataSetCorrectly) {
QuarantineFile(
test_file_, source_url_, referrer_url_, "",
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
base::RunLoop run_loop;
QuarantineFile(test_file_, source_url_, referrer_url_,
/*request_initiator=*/std::nullopt, "",
base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
QuarantineFileResult::OK));
run_loop.Run();
EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, referrer_url_));
}
TEST_F(QuarantineMacTest, SetMetadataMultipleTimes) {
GURL dummy_url("http://www.dummy.example.com");
QuarantineFile(
test_file_, source_url_, referrer_url_, "",
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
QuarantineFile(
test_file_, dummy_url, dummy_url, "",
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, referrer_url_));
{
base::RunLoop run_loop;
QuarantineFile(
test_file_, source_url_, referrer_url_,
/*request_initiator=*/std::nullopt, "",
base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
QuarantineFileResult::OK));
run_loop.Run();
}
{
base::RunLoop run_loop;
GURL dummy_url("http://www.dummy.example.com");
QuarantineFile(
test_file_, dummy_url, dummy_url,
/*request_initiator=*/std::nullopt, "",
base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
QuarantineFileResult::OK));
run_loop.Run();
EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, referrer_url_));
}
}
TEST_F(QuarantineMacTest, IsFileQuarantined_NoFile) {
@ -99,20 +115,24 @@ TEST_F(QuarantineMacTest, IsFileQuarantined_NoAnnotationsOnFile) {
}
TEST_F(QuarantineMacTest, IsFileQuarantined_SourceUrlOnly) {
QuarantineFile(
test_file_, source_url_, GURL(), std::string(),
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
base::RunLoop run_loop;
QuarantineFile(test_file_, source_url_, GURL(),
/*request_initiator=*/std::nullopt, std::string(),
base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
QuarantineFileResult::OK));
run_loop.Run();
EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, GURL()));
EXPECT_TRUE(IsFileQuarantined(test_file_, GURL(), GURL()));
EXPECT_TRUE(IsFileQuarantined(test_file_, GURL(), referrer_url_));
}
TEST_F(QuarantineMacTest, IsFileQuarantined_FullMetadata) {
QuarantineFile(
test_file_, source_url_, referrer_url_, std::string(),
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
base::RunLoop run_loop;
QuarantineFile(test_file_, source_url_, referrer_url_,
/*request_initiator=*/std::nullopt, std::string(),
base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
QuarantineFileResult::OK));
run_loop.Run();
EXPECT_TRUE(IsFileQuarantined(test_file_, GURL(), GURL()));
EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, GURL()));
EXPECT_TRUE(IsFileQuarantined(test_file_, source_url_, referrer_url_));
@ -120,24 +140,28 @@ TEST_F(QuarantineMacTest, IsFileQuarantined_FullMetadata) {
}
TEST_F(QuarantineMacTest, IsFileQuarantined_Sanitize) {
base::RunLoop run_loop;
GURL host_url{"https://user:pass@example.com/foo/bar?x#y"};
GURL host_url_clean{"https://example.com/foo/bar?x#y"};
GURL referrer_url{"https://user:pass@example.com/foo/index?x#y"};
GURL referrer_url_clean{"https://example.com/foo/index?x#y"};
QuarantineFile(
test_file_, host_url, referrer_url, std::string(),
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
QuarantineFile(test_file_, host_url, referrer_url,
/*request_initiator=*/std::nullopt, std::string(),
base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
QuarantineFileResult::OK));
run_loop.Run();
EXPECT_TRUE(
IsFileQuarantined(test_file_, host_url_clean, referrer_url_clean));
}
TEST_F(QuarantineMacTest, IsFileQuarantined_AgentBundleIdentifier) {
QuarantineFile(
test_file_, source_url_, referrer_url_, "",
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
base::RunLoop run_loop;
QuarantineFile(test_file_, source_url_, referrer_url_,
/*request_initiator=*/std::nullopt, "",
base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
QuarantineFileResult::OK));
run_loop.Run();
NSDictionary* properties = GetQuarantineProperties(test_file_);
ASSERT_TRUE(properties);
@ -157,10 +181,12 @@ TEST_F(QuarantineMacTest, IsFileQuarantined_AgentBundleIdentifier) {
}
TEST_F(QuarantineMacTest, NoWhereFromsKeyIfNoURLs) {
QuarantineFile(
test_file_, GURL(), GURL(), std::string(),
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
base::RunLoop run_loop;
QuarantineFile(test_file_, GURL(), GURL(), /*request_initiator=*/std::nullopt,
std::string(),
base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
QuarantineFileResult::OK));
run_loop.Run();
NSString* file_path = base::apple::FilePathToNSString(test_file_);
ASSERT_NE(nullptr, file_path);
@ -178,5 +204,18 @@ TEST_F(QuarantineMacTest, NoWhereFromsKeyIfNoURLs) {
EXPECT_FALSE(attr);
}
TEST_F(QuarantineMacTest, RequestInitiatorReplacesSourceUrl) {
base::RunLoop run_loop;
QuarantineFile(test_file_, GURL("data://text/html,payload"), referrer_url_,
/*request_initiator=*/
url::Origin::Create(GURL("http://www.source.example.com/")),
"",
base::BindOnce(&CheckQuarantineResult, run_loop.QuitClosure(),
QuarantineFileResult::OK));
run_loop.Run();
EXPECT_TRUE(IsFileQuarantined(
test_file_, GURL("http://www.source.example.com/"), referrer_url_));
}
} // namespace
} // namespace quarantine

@ -59,7 +59,8 @@ TEST_F(QuarantineServiceTest, QuarantineFile) {
base::RunLoop run_loop;
quarantine_->QuarantineFile(
test_file, GURL(kInternetURL), GURL(kInternetReferrerURL), std::string(),
test_file, GURL(kInternetURL), GURL(kInternetReferrerURL),
/*request_initiator=*/std::nullopt, std::string(),
base::BindOnce(&QuarantineServiceTest::OnFileQuarantined,
base::Unretained(this), test_file,
run_loop.QuitClosure()));

@ -64,7 +64,8 @@ class QuarantineTest : public testing::Test {
TEST_F(QuarantineTest, FileCanBeOpenedForReadAfterAnnotation) {
base::FilePath test_file = GetTestFilePath();
QuarantineFile(
test_file, GURL(kInternetURL), GURL(kInternetReferrerURL), kTestGUID,
test_file, GURL(kInternetURL), GURL(kInternetReferrerURL),
/*request_initiator=*/std::nullopt, kTestGUID,
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -76,7 +77,7 @@ TEST_F(QuarantineTest, FileCanBeOpenedForReadAfterAnnotation) {
TEST_F(QuarantineTest, FileCanBeAnnotatedWithNoGUID) {
QuarantineFile(
GetTestFilePath(), GURL(kInternetURL), GURL(kInternetReferrerURL),
std::string(),
/*request_initiator=*/std::nullopt, std::string(),
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
}

@ -225,6 +225,7 @@ QuarantineFileResult SetInternetZoneIdentifierDirectly(
void QuarantineFile(const base::FilePath& file,
const GURL& source_url_unsafe,
const GURL& referrer_url_unsafe,
const std::optional<url::Origin>& request_initiator,
const std::string& client_guid,
mojom::Quarantine::QuarantineFileCallback callback) {
base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
@ -245,6 +246,10 @@ void QuarantineFile(const base::FilePath& file,
}
GURL source_url = SanitizeUrlForQuarantine(source_url_unsafe);
if (source_url.is_empty() && request_initiator.has_value()) {
source_url = SanitizeUrlForQuarantine(request_initiator->GetURL());
}
GURL referrer_url = SanitizeUrlForQuarantine(referrer_url_unsafe);
if (file_size == 0 || IsEqualGUID(guid, GUID_NULL)) {

@ -187,7 +187,7 @@ class QuarantineWinTest : public ::testing::Test {
TEST_F(QuarantineWinTest, MissingFile) {
QuarantineFile(GetTempDir().AppendASCII("does-not-exist.exe"),
GURL(kDummySourceUrl), GURL(kDummyReferrerUrl),
kDummyClientGuid,
/*request_initiator=*/std::nullopt, kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult,
QuarantineFileResult::FILE_MISSING));
base::RunLoop().RunUntilIdle();
@ -210,7 +210,8 @@ TEST_F(QuarantineWinTest, LocalFile_DependsOnLocalConfig) {
ASSERT_TRUE(CreateFile(test_file));
QuarantineFile(
test_file, GURL(source_url), GURL(), kDummyClientGuid,
test_file, GURL(source_url), GURL(), /*request_initiator=*/std::nullopt,
kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -237,7 +238,8 @@ TEST_F(QuarantineWinTest, DownloadedFile_DependsOnLocalConfig) {
ASSERT_TRUE(CreateFile(test_file));
QuarantineFile(
test_file, GURL(source_url), GURL(), kDummyClientGuid,
test_file, GURL(source_url), GURL(), /*request_initiator=*/std::nullopt,
kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -270,7 +272,7 @@ TEST_F(QuarantineWinTest, UnsafeReferrer_DependsOnLocalConfig) {
ASSERT_TRUE(CreateFile(test_file));
QuarantineFile(
test_file, GURL("http://example.com/good"), GURL(referrer_url),
kDummyClientGuid,
/*request_initiator=*/std::nullopt, kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -293,7 +295,8 @@ TEST_F(QuarantineWinTest, EmptySource_DependsOnLocalConfig) {
ASSERT_TRUE(CreateFile(test_file));
QuarantineFile(
test_file, GURL(), GURL(), kDummyClientGuid,
test_file, GURL(), GURL(), /*request_initiator=*/std::nullopt,
kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -314,7 +317,8 @@ TEST_F(QuarantineWinTest, EmptyFile) {
ASSERT_TRUE(base::WriteFile(test_file, ""));
QuarantineFile(
test_file, net::FilePathToFileURL(test_file), GURL(), kDummyClientGuid,
test_file, net::FilePathToFileURL(test_file), GURL(),
/*request_initiator=*/std::nullopt, kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -336,7 +340,8 @@ TEST_F(QuarantineWinTest, NoClientGuid) {
ASSERT_TRUE(CreateFile(test_file));
QuarantineFile(
test_file, net::FilePathToFileURL(test_file), GURL(), std::string(),
test_file, net::FilePathToFileURL(test_file), GURL(),
/*request_initiator=*/std::nullopt, std::string(),
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -359,7 +364,8 @@ TEST_F(QuarantineWinTest, SuperLongURL) {
std::string source_url("http://example.com/");
source_url.append(INTERNET_MAX_URL_LENGTH * 2, 'a');
QuarantineFile(
test_file, GURL(source_url), GURL(), std::string(),
test_file, GURL(source_url), GURL(), /*request_initiator=*/std::nullopt,
std::string(),
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -380,7 +386,8 @@ TEST_F(QuarantineWinTest, TrustedSite) {
ASSERT_TRUE(CreateFile(test_file));
QuarantineFile(
test_file, source_url, GURL(), kDummyClientGuid,
test_file, source_url, GURL(), /*request_initiator=*/std::nullopt,
kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -398,7 +405,8 @@ TEST_F(QuarantineWinTest, RestrictedSite) {
ASSERT_TRUE(CreateFile(test_file));
// Files from a restricted site are deleted.
QuarantineFile(test_file, source_url, GURL(), kDummyClientGuid,
QuarantineFile(test_file, source_url, GURL(),
/*request_initiator=*/std::nullopt, kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult,
QuarantineFileResult::BLOCKED_BY_POLICY));
base::RunLoop().RunUntilIdle();
@ -417,7 +425,8 @@ TEST_F(QuarantineWinTest, TrustedSite_AlreadyQuarantined) {
// Ensure the file already contains a zone identifier.
ASSERT_TRUE(AddInternetZoneIdentifierDirectly(test_file));
QuarantineFile(
test_file, source_url, GURL(), kDummyClientGuid,
test_file, source_url, GURL(), /*request_initiator=*/std::nullopt,
kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -439,7 +448,8 @@ TEST_F(QuarantineWinTest, RestrictedSite_AlreadyQuarantined) {
ASSERT_TRUE(AddInternetZoneIdentifierDirectly(test_file));
// Files from a restricted site are deleted.
QuarantineFile(test_file, source_url, GURL(), kDummyClientGuid,
QuarantineFile(test_file, source_url, GURL(),
/*request_initiator=*/std::nullopt, kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult,
QuarantineFileResult::BLOCKED_BY_POLICY));
base::RunLoop().RunUntilIdle();
@ -463,7 +473,8 @@ TEST_F(QuarantineWinTest, MetaData_ApplyMOTW_Directly) {
// An invalid GUID will cause QuarantineFile() to apply the MOTW directly.
QuarantineFile(
test_file, host_url, referrer_url, std::string(),
test_file, host_url, referrer_url, /*request_initiator=*/std::nullopt,
std::string(),
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
@ -484,11 +495,26 @@ TEST_F(QuarantineWinTest, MetaData_InvokeAS) {
base::StrCat({"https://", GetInternetSite(), "/folder/index?x#y"}));
QuarantineFile(
test_file, host_url, referrer_url, kDummyClientGuid,
test_file, host_url, referrer_url, /*request_initiator=*/std::nullopt,
kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsFileQuarantined(test_file, host_url_clean, referrer_url_clean));
}
TEST_F(QuarantineWinTest, RequestInitiatorReplacesSourceUrl) {
base::FilePath test_file = GetTempDir().AppendASCII("foo.exe");
ASSERT_TRUE(CreateFile(test_file));
GURL host_url(base::StrCat({"https://", GetInternetSite(), "/"}));
QuarantineFile(
test_file, GURL("data://text/html,payload"), GURL(),
url::Origin::Create(host_url), kDummyClientGuid,
base::BindOnce(&CheckQuarantineResult, QuarantineFileResult::OK));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(IsFileQuarantined(test_file, host_url, GURL()));
}
} // namespace quarantine

@ -67,6 +67,7 @@ class MockQuarantine : public quarantine::mojom::Quarantine {
void QuarantineFile(const base::FilePath& full_path,
const GURL& source_url,
const GURL& referrer_url,
const std::optional<url::Origin>& request_initiator,
const std::string& client_guid,
QuarantineFileCallback callback) override {
paths.push_back(full_path);

@ -344,6 +344,9 @@ void FileSystemAccessSafeMoveHelper::DidFileDoQuarantine(
quarantine::mojom::Quarantine* raw_quarantine = quarantine_remote.get();
raw_quarantine->QuarantineFile(
target_url.path(), authority_url, referrer_url,
// TODO(crbug.com/351165321): Consider propagating request_initiator
// information here.
/*request_initiator=*/std::nullopt,
GetContentClient()
->browser()
->GetApplicationClientGUIDForQuarantineCheck(),

@ -54,6 +54,7 @@ class MockQuarantine : public quarantine::mojom::Quarantine {
void QuarantineFile(const base::FilePath& full_path,
const GURL& source_url,
const GURL& referrer_url,
const std::optional<url::Origin>& request_initiator,
const std::string& client_guid,
QuarantineFileCallback callback) override {
paths.push_back(full_path);

@ -482,7 +482,7 @@ void PepperFileIOHost::OnLocalFileOpened(
quarantine::mojom::Quarantine* raw_quarantine = quarantine_remote.get();
raw_quarantine->QuarantineFile(
path, browser_ppapi_host_->GetDocumentURLForInstance(pp_instance()),
GURL(), std::string(),
GURL(), /*request_initiator=*/std::nullopt, std::string(),
mojo::WrapCallbackWithDefaultInvokeIfNotRun(
base::BindOnce(&PepperFileIOHost::OnLocalFileQuarantined,
weak_ptr_factory_.GetWeakPtr(), reply_context, path,