1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/bind.h"
6 #include "base/files/file_util.h"
7 #include "base/files/scoped_temp_dir.h"
8 #include "base/memory/scoped_refptr.h"
9 #include "base/test/multiprocess_test.h"
10 #include "base/test/task_environment.h"
11 #include "base/win/scoped_handle.h"
12 #include "base/win/shortcut.h"
13 #include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
14 #include "chrome/chrome_cleaner/mojom/parser_interface.mojom.h"
15 #include "chrome/chrome_cleaner/parsers/broker/sandbox_setup_hooks.h"
16 #include "chrome/chrome_cleaner/parsers/shortcut_parser/broker/sandboxed_shortcut_parser.h"
17 #include "chrome/chrome_cleaner/parsers/shortcut_parser/broker/shortcut_parser_api.h"
18 #include "chrome/chrome_cleaner/parsers/shortcut_parser/sandboxed_lnk_parser_test_util.h"
19 #include "chrome/chrome_cleaner/parsers/target/sandbox_setup.h"
20 #include "mojo/public/cpp/system/platform_handle.h"
21 #include "sandbox/win/src/sandbox_factory.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23 #include "testing/multiprocess_func_list.h"
24 
25 namespace chrome_cleaner {
26 
27 class LnkParserSandboxSetupTest : public base::MultiProcessTest {
28  public:
LnkParserSandboxSetupTest()29   LnkParserSandboxSetupTest()
30       : parser_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {}
31 
SetUp()32   void SetUp() override {
33     mojo_task_runner_ = MojoTaskRunner::Create();
34     ParserSandboxSetupHooks setup_hooks(
35         mojo_task_runner_.get(),
36         base::BindOnce([] { FAIL() << "Parser sandbox connection error"; }));
37     ASSERT_EQ(RESULT_CODE_SUCCESS,
38               StartSandboxTarget(MakeCmdLine("LnkParserSandboxTargetMain"),
39                                  &setup_hooks, SandboxType::kTest));
40     parser_ = setup_hooks.TakeParserRemote();
41     shortcut_parser_ = std::make_unique<SandboxedShortcutParser>(
42         mojo_task_runner_.get(), parser_.get());
43 
44     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
45     ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_.GetPath(),
46                                                &not_lnk_file_path_));
47   }
48 
49  protected:
50   scoped_refptr<MojoTaskRunner> mojo_task_runner_;
51   RemoteParserPtr parser_;
52 
53   std::unique_ptr<ShortcutParserAPI> shortcut_parser_;
54   ParsedLnkFile test_parsed_shortcut_;
55   mojom::LnkParsingResult test_result_code_;
56 
57   base::test::SingleThreadTaskEnvironment task_environment_;
58 
59   base::FilePath not_lnk_file_path_;
60   base::ScopedTempDir temp_dir_;
61 };
62 
MULTIPROCESS_TEST_MAIN(LnkParserSandboxTargetMain)63 MULTIPROCESS_TEST_MAIN(LnkParserSandboxTargetMain) {
64   sandbox::TargetServices* sandbox_target_services =
65       sandbox::SandboxFactory::GetTargetServices();
66   CHECK(sandbox_target_services);
67 
68   EXPECT_EQ(RESULT_CODE_SUCCESS,
69             RunParserSandboxTarget(*base::CommandLine::ForCurrentProcess(),
70                                    sandbox_target_services));
71 
72   return ::testing::Test::HasNonfatalFailure();
73 }
74 
TEST_F(LnkParserSandboxSetupTest,ParseCorrectShortcutSandboxedTest)75 TEST_F(LnkParserSandboxSetupTest, ParseCorrectShortcutSandboxedTest) {
76   base::FilePath shortcut_path =
77       temp_dir_.GetPath().AppendASCII("test_shortcut.lnk");
78 
79   base::win::ShortcutProperties shortcut_properties;
80   shortcut_properties.set_target(not_lnk_file_path_);
81   const int32_t icon_index = 0;
82   shortcut_properties.set_icon(not_lnk_file_path_, icon_index);
83   const std::wstring lnk_arguments = L"argument1 -f -t -a -o";
84   shortcut_properties.set_arguments(lnk_arguments);
85 
86   base::win::ScopedHandle lnk_file_handle = CreateAndOpenShortcutInTempDir(
87       "test_lnk.lnk", shortcut_properties, &temp_dir_);
88   ASSERT_TRUE(lnk_file_handle.IsValid());
89 
90   base::RunLoop run_loop;
91   // Unretained is safe here because we will block on the run loop until
92   // OnLnkParseDone is called.
93   shortcut_parser_->ParseShortcut(
94       std::move(lnk_file_handle),
95       base::BindOnce(&OnLnkParseDone, &test_parsed_shortcut_,
96                      &test_result_code_, run_loop.QuitClosure()));
97   run_loop.Run();
98 
99   ASSERT_EQ(test_result_code_, mojom::LnkParsingResult::SUCCESS);
100   EXPECT_TRUE(CheckParsedShortcut(test_parsed_shortcut_, not_lnk_file_path_,
101                                   lnk_arguments, not_lnk_file_path_,
102                                   icon_index));
103 }
104 
TEST_F(LnkParserSandboxSetupTest,ParseIncorrectShortcutSandboxedTest)105 TEST_F(LnkParserSandboxSetupTest, ParseIncorrectShortcutSandboxedTest) {
106   // Feed the temp file to the parser and expect an error.
107   base::File not_shortcut_file(
108       not_lnk_file_path_,
109       base::File::Flags::FLAG_OPEN | base::File::Flags::FLAG_READ);
110   base::win::ScopedHandle not_shortcut_handle(
111       not_shortcut_file.TakePlatformFile());
112 
113   base::RunLoop run_loop;
114   // Unretained is safe here because we will block on the run loop until
115   // OnLnkParseDone is called.
116   shortcut_parser_->ParseShortcut(
117       std::move(not_shortcut_handle),
118       base::BindOnce(&OnLnkParseDone, &test_parsed_shortcut_,
119                      &test_result_code_, run_loop.QuitClosure()));
120   run_loop.Run();
121 
122   ASSERT_NE(test_result_code_, mojom::LnkParsingResult::SUCCESS);
123   EXPECT_TRUE(CheckParsedShortcut(test_parsed_shortcut_, base::FilePath(L""),
124                                   L"", base::FilePath(L""),
125                                   /*icon_index=*/-1));
126 }
127 
128 }  // namespace chrome_cleaner
129