1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/component_flash_hint_file_linux.h"
#include <errno.h>
#include <stdlib.h>
#include <sys/mount.h>
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/process/kill.h"
#include "base/test/multiprocess_test.h"
#include "base/test/scoped_path_override.h"
#include "base/test/test_timeouts.h"
#include "chrome/common/chrome_paths.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
namespace chrome {
class ComponentFlashHintFileTest : public base::MultiProcessTest {};
TEST_F(ComponentFlashHintFileTest, ExistsTest) {
const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
EXPECT_FALSE(component_flash_hint_file::DoesHintFileExist());
}
TEST_F(ComponentFlashHintFileTest, InstallTest) {
const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
EXPECT_FALSE(component_flash_hint_file::DoesHintFileExist());
base::FilePath flash_dir;
ASSERT_TRUE(PathService::Get(
chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN, &flash_dir));
base::File::Error error;
ASSERT_TRUE(base::CreateDirectoryAndGetError(flash_dir, &error));
// Write out a fixed byte array as the flash file.
uint8_t file[] = {0x4c, 0x65, 0x74, 0x20, 0x75, 0x73,
0x20, 0x6e, 0x6f, 0x74, 0x20, 0x67};
flash_dir = flash_dir.Append("libflash.so");
const std::string flash_version = "1.0.0.1";
ASSERT_EQ(static_cast<int>(sizeof(file)),
base::WriteFile(flash_dir, reinterpret_cast<const char*>(file),
sizeof(file)));
ASSERT_TRUE(component_flash_hint_file::RecordFlashUpdate(flash_dir, flash_dir,
flash_version));
ASSERT_TRUE(component_flash_hint_file::DoesHintFileExist());
// Confirm that the flash plugin can be verified and returned.
base::FilePath returned_flash_path;
std::string version;
ASSERT_TRUE(component_flash_hint_file::VerifyAndReturnFlashLocation(
&returned_flash_path, &version));
ASSERT_EQ(returned_flash_path, flash_dir);
ASSERT_EQ(version, flash_version);
// Now "corrupt" the flash file and make sure the checksum fails and nothing
// is returned.
file[0] = 0xAA;
ASSERT_TRUE(base::WriteFile(flash_dir, reinterpret_cast<const char*>(file),
sizeof(file)) == sizeof(file));
base::FilePath empty_path;
std::string empty_version;
ASSERT_FALSE(component_flash_hint_file::VerifyAndReturnFlashLocation(
&empty_path, &empty_version));
ASSERT_NE(empty_path, flash_dir);
ASSERT_FALSE(empty_version == flash_version);
}
TEST_F(ComponentFlashHintFileTest, CorruptionTest) {
const base::ScopedPathOverride path_override(chrome::DIR_USER_DATA);
EXPECT_FALSE(component_flash_hint_file::DoesHintFileExist());
base::FilePath flash_dir;
ASSERT_TRUE(PathService::Get(
chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN, &flash_dir));
base::File::Error error;
ASSERT_TRUE(base::CreateDirectoryAndGetError(flash_dir, &error));
flash_dir = flash_dir.Append("libflash.so");
const uint8_t file[] = {0x56, 0x61, 0x20, 0x67, 0x75, 0x76,
0x66, 0x20, 0x62, 0x61, 0x72, 0x20};
ASSERT_TRUE(base::WriteFile(flash_dir, reinterpret_cast<const char*>(file),
sizeof(file)) == sizeof(file));
const std::string flash_version = "1.0.0.1";
ASSERT_TRUE(component_flash_hint_file::RecordFlashUpdate(flash_dir, flash_dir,
flash_version));
ASSERT_TRUE(component_flash_hint_file::DoesHintFileExist());
// Now write out a new flash version that will not be moved into place.
const uint8_t updated_file[] = {0x43, 0x72, 0x62, 0x63, 0x79, 0x72,
0x20, 0x66, 0x7a, 0x76, 0x79, 0x76};
base::FilePath flash_dir_update;
ASSERT_TRUE(PathService::Get(
chrome::DIR_COMPONENT_UPDATED_PEPPER_FLASH_PLUGIN, &flash_dir_update));
flash_dir_update = flash_dir_update.Append("other_flash.so");
ASSERT_TRUE(base::WriteFile(flash_dir_update,
reinterpret_cast<const char*>(updated_file),
sizeof(updated_file)) == sizeof(updated_file));
ASSERT_TRUE(component_flash_hint_file::RecordFlashUpdate(
flash_dir_update, flash_dir, flash_version));
// |flash_dir_update| needs to be moved to |flash_dir|, but this test
// deliberately skips that step, so VerifyAndReturnFlashLocation should fail.
base::FilePath failed_flash_dir;
std::string failed_version;
ASSERT_FALSE(component_flash_hint_file::VerifyAndReturnFlashLocation(
&failed_flash_dir, &failed_version));
}
TEST_F(ComponentFlashHintFileTest, ExecTest1) {
base::ScopedTempDir temp_dir;
ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
base::FilePath file_path = temp_dir.path().Append("plugin.so");
const uint8_t file[] = {0x55, 0x62, 0x79, 0x71, 0x20,
0x6c, 0x62, 0x68, 0x65, 0x20};
ASSERT_TRUE(base::WriteFile(file_path, reinterpret_cast<const char*>(file),
sizeof(file)) == sizeof(file));
ASSERT_TRUE(component_flash_hint_file::TestExecutableMapping(file_path));
}
MULTIPROCESS_TEST_MAIN(NoExecMountTest) {
if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0) {
LOG(ERROR) << "This kernel does not support unprivileged namespaces. "
"ExecTest2 will succeed without running.";
return 0;
}
// Now mount a NOEXEC fs.
const unsigned long tmpfs_flags = MS_NODEV | MS_NOSUID | MS_NOEXEC;
base::ScopedTempDir temp_dir;
CHECK(temp_dir.CreateUniqueTempDir());
CHECK_EQ(0, mount("tmpfs", temp_dir.path().value().c_str(), "tmpfs",
tmpfs_flags, nullptr));
const base::FilePath file_path = temp_dir.path().Append("plugin.so");
const uint8_t file[] = {0x56, 0x61, 0x20, 0x67, 0x75, 0x72,
0x20, 0x70, 0x76, 0x67, 0x6c, 0x20};
bool test_exec = false;
bool file_written =
base::WriteFile(file_path, reinterpret_cast<const char*>(file),
sizeof(file)) == static_cast<int>(sizeof(file));
if (file_written)
test_exec = component_flash_hint_file::TestExecutableMapping(file_path);
if (umount(temp_dir.path().value().c_str()) != 0)
LOG(ERROR) << "Could not unmount directory " << temp_dir.path().value();
CHECK(file_written);
CHECK(!test_exec);
return 0;
}
TEST_F(ComponentFlashHintFileTest, ExecTest2) {
base::Process process = SpawnChild("NoExecMountTest");
ASSERT_TRUE(process.IsValid());
int exit_code = 42;
ASSERT_TRUE(process.WaitForExitWithTimeout(TestTimeouts::action_max_timeout(),
&exit_code));
EXPECT_EQ(0, exit_code);
}
} // namespace chrome
|