Commit 7e0868eb authored by Dominique Fauteux-Chapleau's avatar Dominique Fauteux-Chapleau Committed by Commit Bot

Add file type checking to DLP scanning.


Bug: 1008510
Change-Id: Ib6d4e68972c6287539bf5a59e768b31103683bf3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1855679Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarDaniel Rubery <drubery@chromium.org>
Reviewed-by: default avatarRoger Tawa <rogerta@chromium.org>
Commit-Queue: Dominique Fauteux-Chapleau <domfc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#708988}
parent 2509e67f
......@@ -4,6 +4,8 @@
#include <stddef.h>
#include <string>
#include <utility>
#include <vector>
#include "base/command_line.h"
......@@ -271,8 +273,8 @@ TEST_F(FileSelectHelperTest, DeepScanCompletionCallback_OneOKFile) {
std::vector<blink::mojom::FileChooserFileInfoPtr> orig_files;
safe_browsing::DeepScanningDialogDelegate::Data data;
safe_browsing::DeepScanningDialogDelegate::Result result;
PrepareDeepScanCompletionCallbackArgs({data_dir_.AppendASCII("foo")}, {true},
&orig_files, &data, &result);
PrepareDeepScanCompletionCallbackArgs({data_dir_.AppendASCII("foo.doc")},
{true}, &orig_files, &data, &result);
file_select_helper->AddRef(); // Normally called by RunFileChooser().
file_select_helper->DeepScanCompletionCallback(std::move(orig_files), data,
......@@ -296,7 +298,7 @@ TEST_F(FileSelectHelperTest, DeepScanCompletionCallback_TwoOKFiles) {
safe_browsing::DeepScanningDialogDelegate::Data data;
safe_browsing::DeepScanningDialogDelegate::Result result;
PrepareDeepScanCompletionCallbackArgs(
{data_dir_.AppendASCII("foo"), data_dir_.AppendASCII("bar")},
{data_dir_.AppendASCII("foo.doc"), data_dir_.AppendASCII("bar.doc")},
{true, true}, &orig_files, &data, &result);
file_select_helper->AddRef(); // Normally called by RunFileChooser().
......@@ -321,7 +323,7 @@ TEST_F(FileSelectHelperTest, DeepScanCompletionCallback_TwoBadFiles) {
safe_browsing::DeepScanningDialogDelegate::Data data;
safe_browsing::DeepScanningDialogDelegate::Result result;
PrepareDeepScanCompletionCallbackArgs(
{data_dir_.AppendASCII("foo"), data_dir_.AppendASCII("bar")},
{data_dir_.AppendASCII("foo.doc"), data_dir_.AppendASCII("bar.doc")},
{false, false}, &orig_files, &data, &result);
file_select_helper->AddRef(); // Normally called by RunFileChooser().
......@@ -346,7 +348,7 @@ TEST_F(FileSelectHelperTest, DeepScanCompletionCallback_OKBadFiles) {
safe_browsing::DeepScanningDialogDelegate::Data data;
safe_browsing::DeepScanningDialogDelegate::Result result;
PrepareDeepScanCompletionCallbackArgs(
{data_dir_.AppendASCII("foo"), data_dir_.AppendASCII("bar")},
{data_dir_.AppendASCII("foo.doc"), data_dir_.AppendASCII("bar.doc")},
{false, true}, &orig_files, &data, &result);
file_select_helper->AddRef(); // Normally called by RunFileChooser().
......@@ -354,7 +356,7 @@ TEST_F(FileSelectHelperTest, DeepScanCompletionCallback_OKBadFiles) {
result);
ASSERT_EQ(1u, files.size());
EXPECT_EQ(data_dir_.AppendASCII("bar"),
EXPECT_EQ(data_dir_.AppendASCII("bar.doc"),
files[0]->get_native_file()->file_path);
}
......
......@@ -7,6 +7,7 @@
#include <algorithm>
#include <memory>
#include <numeric>
#include <string>
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
......@@ -14,6 +15,7 @@
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
#include "chrome/browser/policy/browser_dm_token_storage.h"
......@@ -151,6 +153,29 @@ bool DlpTriggeredRulesOK(
return true;
}
// File types supported for DLP scanning.
// Keep sorted for efficient access.
constexpr const std::array<const base::FilePath::CharType*, 36>
kSupportedDLPFileTypes = {
FILE_PATH_LITERAL(".bzip"), FILE_PATH_LITERAL(".cab"),
FILE_PATH_LITERAL(".doc"), FILE_PATH_LITERAL(".docx"),
FILE_PATH_LITERAL(".eps"), FILE_PATH_LITERAL(".gzip"),
FILE_PATH_LITERAL(".hwp"), FILE_PATH_LITERAL(".img_for_ocr"),
FILE_PATH_LITERAL(".kml"), FILE_PATH_LITERAL(".kmz"),
FILE_PATH_LITERAL(".odp"), FILE_PATH_LITERAL(".ods"),
FILE_PATH_LITERAL(".odt"), FILE_PATH_LITERAL(".pdf"),
FILE_PATH_LITERAL(".ppt"), FILE_PATH_LITERAL(".pptx"),
FILE_PATH_LITERAL(".ps"), FILE_PATH_LITERAL(".rar"),
FILE_PATH_LITERAL(".rtf"), FILE_PATH_LITERAL(".sdc"),
FILE_PATH_LITERAL(".sdd"), FILE_PATH_LITERAL(".sdw"),
FILE_PATH_LITERAL(".seven_z"), FILE_PATH_LITERAL(".sxc"),
FILE_PATH_LITERAL(".sxi"), FILE_PATH_LITERAL(".sxw"),
FILE_PATH_LITERAL(".tar"), FILE_PATH_LITERAL(".ttf"),
FILE_PATH_LITERAL(".txt"), FILE_PATH_LITERAL(".wml"),
FILE_PATH_LITERAL(".wpd"), FILE_PATH_LITERAL(".xls"),
FILE_PATH_LITERAL(".xlsx"), FILE_PATH_LITERAL(".xml"),
FILE_PATH_LITERAL(".xps"), FILE_PATH_LITERAL(".zip")};
} // namespace
// A BinaryUploadService::Request implementation that gets the data to scan
......@@ -239,6 +264,29 @@ void DeepScanningDialogDelegate::OnCanceled() {
RunCallback();
}
// static
bool DeepScanningDialogDelegate::FileTypeSupported(const bool for_malware_scan,
const bool for_dlp_scan,
const base::FilePath& path) {
// At least one of the booleans needs to be true.
DCHECK(for_malware_scan || for_dlp_scan);
// Accept any file type for malware scans.
if (for_malware_scan)
return true;
// Accept any file type in the supported list for DLP scans.
if (for_dlp_scan) {
base::FilePath::StringType extension(path.FinalExtension());
std::transform(extension.begin(), extension.end(), extension.begin(),
tolower);
return std::binary_search(kSupportedDLPFileTypes.begin(),
kSupportedDLPFileTypes.end(), extension);
}
return false;
}
// static
bool DeepScanningDialogDelegate::IsEnabled(Profile* profile,
GURL url,
......@@ -467,14 +515,20 @@ bool DeepScanningDialogDelegate::UploadData() {
}
// Create a file request for each file.
for (const auto& path : data_.paths) {
for (size_t i = 0; i < data_.paths.size(); ++i) {
if (FileTypeSupported(data_.do_malware_scan, data_.do_dlp_scan,
data_.paths[i])) {
auto request = std::make_unique<FileSourceRequest>(
weak_ptr_factory_.GetWeakPtr(), path,
weak_ptr_factory_.GetWeakPtr(), data_.paths[i],
base::BindOnce(&DeepScanningDialogDelegate::FileRequestCallback,
weak_ptr_factory_.GetWeakPtr(), path));
weak_ptr_factory_.GetWeakPtr(), data_.paths[i]));
PrepareRequest(DlpDeepScanningClientRequest::FILE_UPLOAD, request.get());
UploadFileForDeepScanning(path, std::move(request));
UploadFileForDeepScanning(data_.paths[i], std::move(request));
} else {
++file_result_count_;
result_.paths_results[i] = true;
}
}
return !text_request_complete_ || file_result_count_ != data_.paths.size();
......
......@@ -5,9 +5,13 @@
#ifndef CHROME_BROWSER_SAFE_BROWSING_CLOUD_CONTENT_SCANNING_DEEP_SCANNING_DIALOG_DELEGATE_H_
#define CHROME_BROWSER_SAFE_BROWSING_CLOUD_CONTENT_SCANNING_DEEP_SCANNING_DIALOG_DELEGATE_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string16.h"
......@@ -160,6 +164,11 @@ class DeepScanningDialogDelegate : public TabModalConfirmDialogDelegate {
// Overrides the DM token used for testing purposes.
static void SetDMTokenForTesting(const char* dm_token);
// Returns true if the given file type is supported for scanning.
static bool FileTypeSupported(const bool for_malware_scan,
const bool for_dlp_scan,
const base::FilePath& path);
protected:
DeepScanningDialogDelegate(content::WebContents* web_contents,
Data data,
......
......@@ -5,6 +5,7 @@
#include "chrome/browser/safe_browsing/cloud_content_scanning/deep_scanning_dialog_delegate.h"
#include <map>
#include <string>
#include <vector>
#include "base/bind.h"
......@@ -560,7 +561,7 @@ TEST_F(DeepScanningDialogDelegateAuditOnlyTest, FileData) {
DeepScanningDialogDelegate::Data data;
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(profile(), url, &data));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.doc"));
bool called = false;
DeepScanningDialogDelegate::ShowForWebContents(
......@@ -585,8 +586,8 @@ TEST_F(DeepScanningDialogDelegateAuditOnlyTest, FileData2) {
DeepScanningDialogDelegate::Data data;
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(profile(), url, &data));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/bar"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.doc"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/bar.doc"));
bool called = false;
DeepScanningDialogDelegate::ShowForWebContents(
......@@ -613,8 +614,8 @@ TEST_F(DeepScanningDialogDelegateAuditOnlyTest, StringFileData) {
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(profile(), url, &data));
data.text.emplace_back(base::UTF8ToUTF16("foo"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/bar"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.doc"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/bar.doc"));
bool called = false;
DeepScanningDialogDelegate::ShowForWebContents(
......@@ -644,11 +645,11 @@ TEST_F(DeepScanningDialogDelegateAuditOnlyTest, StringFileDataPartialSuccess) {
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(profile(), url, &data));
data.text.emplace_back(base::UTF8ToUTF16("foo"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_malware_1"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_malware_2"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_dlp_status"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_dlp_rule"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.doc"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_malware_1.doc"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_malware_2.doc"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_dlp_status.doc"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_fail_dlp_rule.doc"));
// Mark some files with failed scans.
PathFailsDeepScan(data.paths[1],
......@@ -713,6 +714,165 @@ TEST_F(DeepScanningDialogDelegateAuditOnlyTest, EmptyWait) {
EXPECT_TRUE(called);
}
TEST_F(DeepScanningDialogDelegateAuditOnlyTest, SupportedTypes) {
SetWaitPolicy(DELAY_UPLOADS);
GURL url(kTestUrl);
DeepScanningDialogDelegate::Data data;
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(profile(), url, &data));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.bzip"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.cab"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.doc"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.docx"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.eps"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.gzip"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.hwp"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.img_for_ocr"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.kml"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.kmz"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.odp"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.ods"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.odt"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.pdf"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.ppt"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.pptx"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.ps"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.rar"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.rtf"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.sdc"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.sdd"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.sdw"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.seven_z"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.sxc"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.sxi"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.sxw"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.tar"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.ttf"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.txt"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.wml"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.wpd"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.xls"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.xlsx"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.xml"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.xps"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.zip"));
// Mark all files with failed scans.
for (const auto& path : data.paths)
PathFailsDeepScan(path, FakeDeepScanningDialogDelegate::MalwareResponse(
MalwareDeepScanningVerdict::UWS));
bool called = false;
DeepScanningDialogDelegate::ShowForWebContents(
contents(), std::move(data),
base::BindOnce(
[](bool* called, const DeepScanningDialogDelegate::Data& data,
const DeepScanningDialogDelegate::Result& result) {
EXPECT_EQ(36u, data.paths.size());
ASSERT_EQ(36u, result.paths_results.size());
// The supported types should be marked as false.
for (const auto& result : result.paths_results)
EXPECT_FALSE(result);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(DeepScanningDialogDelegateAuditOnlyTest, UnsupportedTypes) {
SetWaitPolicy(DELAY_UPLOADS);
GURL url(kTestUrl);
DeepScanningDialogDelegate::Data data;
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(profile(), url, &data));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.these"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.file"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.types"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.are"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.not"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.supported"));
// Mark all files with failed scans.
for (const auto& path : data.paths)
PathFailsDeepScan(path, FakeDeepScanningDialogDelegate::MalwareResponse(
MalwareDeepScanningVerdict::UWS));
bool called = false;
DeepScanningDialogDelegate::ShowForWebContents(
contents(), std::move(data),
base::BindOnce(
[](bool* called, const DeepScanningDialogDelegate::Data& data,
const DeepScanningDialogDelegate::Result& result) {
EXPECT_EQ(6u, data.paths.size());
ASSERT_EQ(6u, result.paths_results.size());
// The unsupported types should be marked as true.
for (const bool path_result : result.paths_results)
EXPECT_TRUE(path_result);
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
TEST_F(DeepScanningDialogDelegateAuditOnlyTest, SupportedAndUnsupportedTypes) {
SetWaitPolicy(DELAY_UPLOADS);
GURL url(kTestUrl);
DeepScanningDialogDelegate::Data data;
ASSERT_TRUE(DeepScanningDialogDelegate::IsEnabled(profile(), url, &data));
// Only 3 of these file types are supported (bzip, cab and doc). They are
// mixed in the list so as to show that insertion order does not matter.
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.bzip"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.these"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.file"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.types"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.cab"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.are"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.not"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.supported"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo_no_extension"));
data.paths.emplace_back(FILE_PATH_LITERAL("/tmp/foo.doc"));
// Mark all files with failed scans.
for (const auto& path : data.paths)
PathFailsDeepScan(path, FakeDeepScanningDialogDelegate::MalwareResponse(
MalwareDeepScanningVerdict::UWS));
bool called = false;
DeepScanningDialogDelegate::ShowForWebContents(
contents(), std::move(data),
base::BindOnce(
[](bool* called, const DeepScanningDialogDelegate::Data& data,
const DeepScanningDialogDelegate::Result& result) {
EXPECT_EQ(10u, data.paths.size());
ASSERT_EQ(10u, result.paths_results.size());
// The unsupported types should be marked as true, and the valid
// types as false since they are marked as failed scans.
size_t i = 0;
for (const bool expected : {false, true, true, true, false, true,
true, true, true, false}) {
ASSERT_EQ(expected, result.paths_results[i]);
++i;
}
*called = true;
},
&called));
RunUntilDone();
EXPECT_TRUE(called);
}
} // namespace
} // namespace safe_browsing
......@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <memory>
#include <string>
#include "base/bind.h"
#include "base/files/file_path.h"
......@@ -165,10 +166,10 @@ TEST_F(ChromeWebContentsViewDelegateHandleOnPerformDrop, FileContents) {
// Make sure DropData::filenames is handled correctly.
TEST_F(ChromeWebContentsViewDelegateHandleOnPerformDrop, Files) {
content::DropData data;
data.filenames.emplace_back(base::FilePath(FILE_PATH_LITERAL("C:\\Foo")),
base::FilePath(FILE_PATH_LITERAL("Foo")));
data.filenames.emplace_back(base::FilePath(FILE_PATH_LITERAL("C:\\Bar")),
base::FilePath(FILE_PATH_LITERAL("Bar")));
data.filenames.emplace_back(base::FilePath(FILE_PATH_LITERAL("C:\\Foo.doc")),
base::FilePath(FILE_PATH_LITERAL("Foo.doc")));
data.filenames.emplace_back(base::FilePath(FILE_PATH_LITERAL("C:\\Bar.doc")),
base::FilePath(FILE_PATH_LITERAL("Bar.doc")));
RunTest(data, /*enable=*/false, /*scan_succeeds=*/true);
RunTest(data, /*enable=*/true, /*scan_succeeds=*/false);
RunTest(data, /*enable=*/true, /*scan_succeeds=*/true);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment