--- a/chrome/common/safe_browsing/binary_feature_extractor.cc +++ b/chrome/common/safe_browsing/binary_feature_extractor.cc @@ -4,6 +4,8 @@ #include "chrome/common/safe_browsing/binary_feature_extractor.h" +#include "build/build_config.h" + #include #include @@ -28,21 +30,43 @@ ExtractHeadersOption options, ClientDownloadRequest_ImageHeaders* image_headers, google::protobuf::RepeatedPtrField* signed_data) { + base::FilePath temp_dir; + if (!base::GetTempDir(&temp_dir)) { + return false; + } + + base::FilePath temp_path; + base::File temp_file = base::CreateAndOpenTemporaryFileInDir( + temp_dir, &temp_path, base::File::FLAG_WIN_TEMPORARY); + if (!temp_file.IsValid()) { + return false; + } + +#if BUILDFLAG(IS_WIN) + temp_file.DeleteOnClose(true); +#else + // Immediately delete/unlink the file from the directory namespace. + // This ensures: + // 1) Full isolation: no other process can inspect or open the file by path. + // 2) Guaranteed cleanup: if Chrome crashes, the OS automatically reclaims + // the disk space when the file descriptor is closed, preventing leaks. + // 3) Parity with Windows DeleteOnClose behavior. + base::DeleteFile(temp_path); +#endif + + base::File source_file(file_path, + base::File::FLAG_OPEN | base::File::FLAG_READ); + if (!source_file.IsValid()) { + return false; + } + + if (!base::CopyFileContents(source_file, temp_file)) { + return false; + } + + if (temp_file.Seek(base::File::FROM_BEGIN, 0) != 0) { + return false; + } base::MemoryMappedFile mapped_file; if (!mapped_file.Initialize(std::move(temp_file))) { --- a/chrome/common/safe_browsing/binary_feature_extractor_unittest.cc +++ b/chrome/common/safe_browsing/binary_feature_extractor_unittest.cc @@ -154,5 +154,28 @@ mock_extractor->ExtractImageFeatures( path_, BinaryFeatureExtractor::kDefaultOptions, &image_headers, nullptr); } + +TEST_F(BinaryFeatureExtractorTest, ExtractImageFeaturesContentMatch) { + constexpr char kTestData[] = "Safe copy of interesting binary content"; + WriteFileToHash(base::as_byte_span(std::string_view(kTestData))); + + scoped_refptr mock_extractor( + new MockBinaryFeatureExtractor()); + EXPECT_CALL(*mock_extractor, ExtractImageFeaturesFromData(_, _, _, _)) + .WillOnce( + [&](base::span data, + BinaryFeatureExtractor::ExtractHeadersOption options, + ClientDownloadRequest_ImageHeaders* image_headers, + google::protobuf::RepeatedPtrField* signed_data) { + EXPECT_EQ(std::string_view(kTestData), + std::string_view(reinterpret_cast(data.data()), + data.size())); + return true; + }); + + ClientDownloadRequest_ImageHeaders image_headers; + EXPECT_TRUE(mock_extractor->ExtractImageFeatures( + path_, BinaryFeatureExtractor::kDefaultOptions, &image_headers, nullptr)); +} } // namespace safe_browsing --- a/chrome/services/file_util/public/cpp/temporary_file_getter.cc +++ b/chrome/services/file_util/public/cpp/temporary_file_getter.cc @@ -4,6 +4,8 @@ #include "chrome/services/file_util/public/cpp/temporary_file_getter.h" +#include "build/build_config.h" + #include "base/files/file_util.h" #include "base/task/thread_pool.h" @@ -12,17 +14,34 @@ constexpr int kMaxNumberOfFilesAllowed = 10; base::File TemporaryFileGetterHelper(int num_files_requested) { + if (num_files_requested > kMaxNumberOfFilesAllowed) { + return base::File(); + } + + base::FilePath temp_dir; + if (!base::GetTempDir(&temp_dir)) { + return base::File(); + } + + base::FilePath temp_path; + base::File temp_file = base::CreateAndOpenTemporaryFileInDir( + temp_dir, &temp_path, base::File::FLAG_WIN_TEMPORARY); + if (!temp_file.IsValid()) { + return base::File(); + } + +#if BUILDFLAG(IS_WIN) + temp_file.DeleteOnClose(true); +#else + // Immediately delete/unlink the file from the directory namespace. + // This ensures: + // 1) Full isolation: no other process can inspect or open the file by path. + // 2) Guaranteed cleanup: if Chrome crashes, the OS automatically reclaims + // the disk space when the file descriptor is closed, preventing leaks. + // 3) Parity with Windows DeleteOnClose behavior. + base::DeleteFile(temp_path); +#endif + return temp_file; } } // namespace --- a/chrome/services/file_util/public/cpp/temporary_file_getter_unittest.cc +++ b/chrome/services/file_util/public/cpp/temporary_file_getter_unittest.cc @@ -45,5 +45,27 @@ EXPECT_FALSE(temp_file_.IsValid()); } +TEST_F(TemporaryFileGetterTest, GetTempFileWriteReadTest) { + auto callback = base::BindOnce(&UpdateTempFile, &temp_file_); + temp_file_getter_.RequestTemporaryFile(std::move(callback)); + task_environment_.RunUntilIdle(); + ASSERT_TRUE(temp_file_.IsValid()); + + constexpr char kTestData[] = "Some test data to write to temporary file getter"; + std::optional bytes_written = + temp_file_.WriteAtCurrentPos(base::as_byte_span(std::string_view(kTestData))); + ASSERT_TRUE(bytes_written.has_value()); + EXPECT_EQ(std::size(kTestData) - 1, bytes_written.value()); + + ASSERT_TRUE(temp_file_.Seek(base::File::FROM_BEGIN, 0) == 0); + + char read_buffer[sizeof(kTestData)] = {0}; + std::optional bytes_read = + temp_file_.ReadAtCurrentPos(base::as_writable_byte_span(read_buffer).first(bytes_written.value())); + ASSERT_TRUE(bytes_read.has_value()); + EXPECT_EQ(bytes_written.value(), bytes_read.value()); + EXPECT_EQ(std::string_view(kTestData), std::string_view(read_buffer, bytes_read.value())); +} + } // namespace safe_browsing