OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "sandbox/linux/services/broker_process.h" | |
6 | |
7 #include <errno.h> | |
8 #include <fcntl.h> | |
9 #include <sys/stat.h> | |
10 #include <sys/types.h> | |
11 #include <sys/wait.h> | |
12 #include <string> | |
13 #include <vector> | |
14 | |
15 #include "base/logging.h" | |
16 #include "sandbox/linux/tests/unit_tests.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 | |
19 namespace sandbox { | |
20 | |
21 TEST(BrokerProcess, CreateAndDestroy) { | |
22 std::vector<std::string> read_whitelist; | |
23 read_whitelist.push_back("/proc/cpuinfo"); | |
24 | |
25 BrokerProcess* open_broker = new BrokerProcess(read_whitelist, | |
26 std::vector<std::string>()); | |
27 ASSERT_TRUE(open_broker->Init(NULL)); | |
28 pid_t broker_pid = open_broker->broker_pid(); | |
29 delete(open_broker); | |
30 | |
31 // Now we check that the broker has exited properly. | |
32 int status = 0; | |
33 EXPECT_EQ(waitpid(broker_pid, &status, 0), broker_pid); | |
34 EXPECT_TRUE(WIFEXITED(status)); | |
35 EXPECT_EQ(WEXITSTATUS(status), 0); | |
36 } | |
37 | |
38 TEST(BrokerProcess, TestOpenNull) { | |
39 const std::vector<std::string> empty; | |
40 BrokerProcess open_broker(empty, empty); | |
41 ASSERT_TRUE(open_broker.Init(NULL)); | |
42 | |
43 int fd = open_broker.Open(NULL, O_RDONLY); | |
44 EXPECT_EQ(fd, -EFAULT); | |
45 } | |
46 | |
47 void TestOpenFilePerms(bool fast_check_in_client) { | |
48 const char kR_WhiteListed[] = "/proc/DOESNOTEXIST1"; | |
49 const char kW_WhiteListed[] = "/proc/DOESNOTEXIST2"; | |
50 const char kRW_WhiteListed[] = "/proc/DOESNOTEXIST3"; | |
51 const char k_NotWhitelisted[] = "/proc/DOESNOTEXIST4"; | |
52 | |
53 std::vector<std::string> read_whitelist; | |
54 read_whitelist.push_back(kR_WhiteListed); | |
55 read_whitelist.push_back(kRW_WhiteListed); | |
56 | |
57 std::vector<std::string> write_whitelist; | |
58 write_whitelist.push_back(kW_WhiteListed); | |
59 write_whitelist.push_back(kRW_WhiteListed); | |
60 | |
61 BrokerProcess open_broker(read_whitelist, | |
62 write_whitelist, | |
63 fast_check_in_client); | |
64 ASSERT_TRUE(open_broker.Init(NULL)); | |
65 | |
66 int fd = -1; | |
67 fd = open_broker.Open(kR_WhiteListed, O_RDONLY); | |
68 EXPECT_EQ(fd, -ENOENT); | |
69 fd = open_broker.Open(kR_WhiteListed, O_WRONLY); | |
70 EXPECT_EQ(fd, -EPERM); | |
71 fd = open_broker.Open(kR_WhiteListed, O_RDWR); | |
72 EXPECT_EQ(fd, -EPERM); | |
73 | |
74 fd = open_broker.Open(kW_WhiteListed, O_RDONLY); | |
75 EXPECT_EQ(fd, -EPERM); | |
76 fd = open_broker.Open(kW_WhiteListed, O_WRONLY); | |
77 EXPECT_EQ(fd, -ENOENT); | |
78 fd = open_broker.Open(kW_WhiteListed, O_RDWR); | |
79 EXPECT_EQ(fd, -EPERM); | |
80 | |
81 fd = open_broker.Open(kRW_WhiteListed, O_RDONLY); | |
82 EXPECT_EQ(fd, -ENOENT); | |
83 fd = open_broker.Open(kRW_WhiteListed, O_WRONLY); | |
84 EXPECT_EQ(fd, -ENOENT); | |
85 fd = open_broker.Open(kRW_WhiteListed, O_RDWR); | |
86 EXPECT_EQ(fd, -ENOENT); | |
87 | |
88 fd = open_broker.Open(k_NotWhitelisted, O_RDONLY); | |
89 EXPECT_EQ(fd, -EPERM); | |
90 fd = open_broker.Open(k_NotWhitelisted, O_WRONLY); | |
91 EXPECT_EQ(fd, -EPERM); | |
92 fd = open_broker.Open(k_NotWhitelisted, O_RDWR); | |
93 EXPECT_EQ(fd, -EPERM); | |
94 | |
95 // We have some extra sanity check for clearly wrong values. | |
96 fd = open_broker.Open(kRW_WhiteListed, O_RDONLY|O_WRONLY|O_RDWR); | |
97 EXPECT_EQ(fd, -EPERM); | |
98 } | |
99 | |
100 // Run the same thing twice. The second time, we make sure that no security | |
101 // check is performed on the client. | |
102 TEST(BrokerProcess, OpenFilePermsWithClientCheck) { | |
103 TestOpenFilePerms(true /* fast_check_in_client */); | |
104 } | |
105 | |
106 TEST(BrokerProcess, OpenOpenFilePermsNoClientCheck) { | |
107 TestOpenFilePerms(false /* fast_check_in_client */); | |
108 } | |
109 | |
110 | |
111 void TestOpenCpuinfo(bool fast_check_in_client) { | |
112 const char kFileCpuInfo[] = "/proc/cpuinfo"; | |
113 std::vector<std::string> read_whitelist; | |
114 read_whitelist.push_back(kFileCpuInfo); | |
115 | |
116 BrokerProcess* open_broker = new BrokerProcess(read_whitelist, | |
117 std::vector<std::string>(), | |
118 fast_check_in_client); | |
119 ASSERT_TRUE(open_broker->Init(NULL)); | |
120 pid_t broker_pid = open_broker->broker_pid(); | |
121 | |
122 int fd = -1; | |
123 fd = open_broker->Open(kFileCpuInfo, O_RDWR); | |
124 EXPECT_EQ(fd, -EPERM); | |
125 | |
126 // Open cpuinfo via the broker. | |
127 int cpuinfo_fd = open_broker->Open(kFileCpuInfo, O_RDONLY); | |
128 ASSERT_GE(cpuinfo_fd, 0); | |
129 char buf[3]; | |
130 memset(buf, 0, sizeof(buf)); | |
131 int read_len1 = read(cpuinfo_fd, buf, sizeof(buf)); | |
132 EXPECT_GT(read_len1, 0); | |
133 | |
134 // Open cpuinfo directly. | |
135 int cpuinfo_fd2 = open(kFileCpuInfo, O_RDONLY); | |
136 ASSERT_GE(cpuinfo_fd2, 0); | |
137 char buf2[3]; | |
138 memset(buf2, 1, sizeof(buf2)); | |
139 int read_len2 = read(cpuinfo_fd2, buf2, sizeof(buf2)); | |
140 EXPECT_GT(read_len1, 0); | |
141 | |
142 // The following is not guaranteed true, but will be in practice. | |
143 EXPECT_EQ(read_len1, read_len2); | |
144 // Compare the cpuinfo as returned by the broker with the one we opened | |
145 // ourselves. | |
146 EXPECT_EQ(memcmp(buf, buf2, read_len1), 0); | |
147 | |
148 if (fd >= 0) | |
149 close(fd); | |
150 if (cpuinfo_fd >= 0) | |
151 close(cpuinfo_fd); | |
152 if (cpuinfo_fd2 >= 0) | |
153 close(cpuinfo_fd); | |
154 | |
155 delete(open_broker); | |
156 | |
157 // Now we check that the broker has exited properly. | |
158 int status = 0; | |
159 EXPECT_EQ(waitpid(broker_pid, &status, 0), broker_pid); | |
160 EXPECT_TRUE(WIFEXITED(status)); | |
161 EXPECT_EQ(WEXITSTATUS(status), 0); | |
162 } | |
163 | |
164 // Run the same thing twice. The second time, we make sure that no security | |
165 // check is performed on the client. | |
166 TEST(BrokerProcess, OpenCpuinfoWithClientCheck) { | |
167 TestOpenCpuinfo(true /* fast_check_in_client */); | |
168 } | |
169 | |
170 TEST(BrokerProcess, OpenCpuinfoNoClientCheck) { | |
171 TestOpenCpuinfo(false /* fast_check_in_client */); | |
172 } | |
173 | |
174 TEST(BrokerProcess, OpenFileRW) { | |
175 char templatename[] = "BrokerProcessXXXXXX"; | |
176 int tempfile = mkstemp(templatename); | |
177 ASSERT_GE(tempfile, 0); | |
178 char tempfile_name[2048]; | |
179 int written = snprintf(tempfile_name, sizeof(tempfile_name), | |
180 "/proc/self/fd/%d", tempfile); | |
181 ASSERT_LT(written, static_cast<int>(sizeof(tempfile_name))); | |
182 | |
183 std::vector<std::string> whitelist; | |
184 whitelist.push_back(tempfile_name); | |
185 | |
186 BrokerProcess open_broker(whitelist, whitelist); | |
187 ASSERT_TRUE(open_broker.Init(NULL)); | |
188 | |
189 int tempfile2 = -1; | |
190 tempfile2 = open_broker.Open(tempfile_name, O_RDWR); | |
191 ASSERT_GE(tempfile2, 0); | |
192 | |
193 // Write to the descriptor opened by the broker. | |
194 char test_text[] = "TESTTESTTEST"; | |
195 ssize_t len = write(tempfile2, test_text, sizeof(test_text)); | |
196 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); | |
197 | |
198 // Read back from the original file descriptor what we wrote through | |
199 // the descriptor provided by the broker. | |
200 char buf[1024]; | |
201 len = read(tempfile, buf, sizeof(buf)); | |
202 | |
203 ASSERT_EQ(len, static_cast<ssize_t>(sizeof(test_text))); | |
204 ASSERT_EQ(memcmp(test_text, buf, sizeof(test_text)), 0); | |
205 | |
206 // Cleanup the temporary file. | |
207 char tempfile_full_path[2048]; | |
208 // Make sure tempfile_full_path will terminate with a 0. | |
209 memset(tempfile_full_path, 0, sizeof(tempfile_full_path)); | |
210 ssize_t ret = readlink(tempfile_name, tempfile_full_path, | |
211 sizeof(tempfile_full_path)); | |
212 ASSERT_GT(ret, 0); | |
213 // Make sure we still have a trailing zero in tempfile_full_path. | |
214 ASSERT_LT(ret, static_cast<ssize_t>(sizeof(tempfile_full_path))); | |
215 ASSERT_EQ(unlink(tempfile_full_path), 0); | |
216 | |
217 EXPECT_EQ(close(tempfile), 0); | |
218 EXPECT_EQ(close(tempfile2), 0); | |
219 } | |
220 | |
221 // Sandbox test because we could get a SIGPIPE. | |
222 SANDBOX_TEST(BrokerProcess, BrokerDied) { | |
223 std::vector<std::string> read_whitelist; | |
224 read_whitelist.push_back("/proc/cpuinfo"); | |
225 | |
226 BrokerProcess open_broker(read_whitelist, | |
227 std::vector<std::string>(), | |
228 true /* fast_check_in_client */, | |
229 true /* quiet_failures_for_tests */); | |
230 SANDBOX_ASSERT(open_broker.Init(NULL)); | |
231 pid_t broker_pid = open_broker.broker_pid(); | |
232 SANDBOX_ASSERT(kill(broker_pid, SIGKILL) == 0); | |
233 | |
234 // Now we check that the broker has exited properly. | |
235 int status = 0; | |
236 SANDBOX_ASSERT(waitpid(broker_pid, &status, 0) == broker_pid); | |
237 SANDBOX_ASSERT(WIFSIGNALED(status)); | |
238 SANDBOX_ASSERT(WTERMSIG(status) == SIGKILL); | |
239 // Hopefully doing Open with a dead broker won't SIGPIPE us. | |
240 SANDBOX_ASSERT(open_broker.Open("/proc/cpuinfo", O_RDONLY) == -ENOMEM); | |
241 } | |
242 | |
243 void TestComplexFlags(bool fast_check_in_client) { | |
244 std::vector<std::string> whitelist; | |
245 whitelist.push_back("/proc/cpuinfo"); | |
246 | |
247 BrokerProcess open_broker(whitelist, | |
248 whitelist, | |
249 fast_check_in_client); | |
250 ASSERT_TRUE(open_broker.Init(NULL)); | |
251 // Test that we do the right thing for O_CLOEXEC and O_NONBLOCK. | |
252 // Presently, the right thing is to always deny them since they are not | |
253 // supported. | |
254 int fd = -1; | |
255 fd = open_broker.Open("/proc/cpuinfo", O_RDONLY); | |
256 ASSERT_GE(fd, 0); | |
257 ASSERT_EQ(close(fd), 0); | |
258 | |
259 ASSERT_EQ(open_broker.Open("/proc/cpuinfo", O_RDONLY | O_CLOEXEC), -EPERM); | |
260 ASSERT_EQ(open_broker.Open("/proc/cpuinfo", O_RDONLY | O_NONBLOCK), -EPERM); | |
261 } | |
262 | |
263 TEST(BrokerProcess, ComplexFlagsWithClientCheck) { | |
264 TestComplexFlags(true /* fast_check_in_client */); | |
265 } | |
266 | |
267 TEST(BrokerProcess, ComplexFlagsNoClientCheck) { | |
268 TestComplexFlags(false /* fast_check_in_client */); | |
269 } | |
270 | |
271 } // namespace sandbox | |
OLD | NEW |