• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "sandboxed_api/sandbox2/util.h"
16 
17 #include <sched.h>
18 #include <sys/mman.h>
19 #include <sys/wait.h>
20 #include <unistd.h>
21 
22 #include <cstdint>
23 #include <cstdlib>
24 #include <cstring>
25 #include <string>
26 #include <vector>
27 
28 #include "gmock/gmock.h"
29 #include "gtest/gtest.h"
30 #include "absl/cleanup/cleanup.h"
31 #include "absl/log/check.h"
32 #include "absl/status/statusor.h"
33 #include "absl/strings/str_cat.h"
34 #include "absl/strings/string_view.h"
35 #include "absl/types/span.h"
36 #include "sandboxed_api/testing.h"
37 #include "sandboxed_api/util/status_matchers.h"
38 
39 namespace sandbox2::util {
40 namespace {
41 
42 using ::sapi::GetTestSourcePath;
43 using ::sapi::IsOk;
44 using ::testing::ElementsAre;
45 using ::testing::ElementsAreArray;
46 using ::testing::Eq;
47 using ::testing::Gt;
48 using ::testing::IsEmpty;
49 using ::testing::IsTrue;
50 using ::testing::Ne;
51 using ::testing::Not;
52 using ::testing::StartsWith;
53 using ::testing::StrEq;
54 
55 constexpr absl::string_view kTestString = "This is a test string";
56 
TEST(UtilTest,TestCreateMemFd)57 TEST(UtilTest, TestCreateMemFd) {
58   int fd = 0;
59   ASSERT_THAT(CreateMemFd(&fd), IsTrue());
60   EXPECT_THAT(fd, Gt(1));
61   close(fd);
62 }
63 
TEST(CharPtrArrayTest,FromStringVector)64 TEST(CharPtrArrayTest, FromStringVector) {
65   std::vector<std::string> strings = {"a", "b", "c"};
66   CharPtrArray array = CharPtrArray::FromStringVector(strings);
67   EXPECT_THAT(array.ToStringVector(), Eq(strings));
68   EXPECT_THAT(array.array(),
69               ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), nullptr));
70   EXPECT_THAT(array.data(), Eq(array.array().data()));
71 }
72 
TEST(CharPtrArrayTest,FromCharPtrArray)73 TEST(CharPtrArrayTest, FromCharPtrArray) {
74   std::vector<std::string> strings = {"a", "b", "c"};
75   std::vector<char*> string_arr;
76   for (std::string& s : strings) {
77     string_arr.push_back(s.data());
78   }
79   string_arr.push_back(nullptr);
80   CharPtrArray array(string_arr.data());
81   EXPECT_THAT(array.ToStringVector(), Eq(strings));
82   EXPECT_THAT(array.array(),
83               ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), nullptr));
84   EXPECT_THAT(array.data(), Eq(array.array().data()));
85 }
86 
TEST(GetProcStatusLineTest,Pid)87 TEST(GetProcStatusLineTest, Pid) {
88   std::string line = GetProcStatusLine(getpid(), "Pid");
89   EXPECT_THAT(line, Eq(absl::StrCat(getpid())));
90 }
91 
TEST(GetProcStatusLineTest,NonExisting)92 TEST(GetProcStatusLineTest, NonExisting) {
93   std::string line =
94       GetProcStatusLine(getpid(), "__N_o_n_ExistingStatusSetting");
95   EXPECT_THAT(line, IsEmpty());
96 }
97 
TEST(ForkWithFlagsTest,DoesForkNormally)98 TEST(ForkWithFlagsTest, DoesForkNormally) {
99   int pfds[2];
100   ASSERT_THAT(pipe(pfds), Eq(0));
101   pid_t child = ForkWithFlags(SIGCHLD);
102   ASSERT_THAT(child, Ne(-1));
103   if (child == 0) {
104     char c = 'a';
105     if (!write(pfds[1], &c, 1)) {
106       exit(EXIT_FAILURE);
107     }
108     exit(EXIT_SUCCESS);
109   }
110   close(pfds[1]);
111   char c = ' ';
112   EXPECT_THAT(read(pfds[0], &c, 1), Eq(1));
113   close(pfds[0]);
114   EXPECT_THAT(c, Eq('a'));
115   int status;
116   ASSERT_THAT(TEMP_FAILURE_RETRY(waitpid(child, &status, 0)), Eq(child));
117   EXPECT_TRUE(WIFEXITED(status));
118   EXPECT_THAT(WEXITSTATUS(status), Eq(0));
119 }
120 
TEST(ForkWithFlagsTest,UnsupportedFlag)121 TEST(ForkWithFlagsTest, UnsupportedFlag) {
122   EXPECT_THAT(ForkWithFlags(CLONE_CHILD_CLEARTID), Eq(-1));
123 }
124 
TEST(ReadCPathFromPidSplitPageTest,Normal)125 TEST(ReadCPathFromPidSplitPageTest, Normal) {
126   std::string test_str(kTestString);
127   absl::StatusOr<std::string> read =
128       ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(test_str.data()));
129   ASSERT_THAT(read, IsOk());
130   EXPECT_THAT(*read, Eq(kTestString));
131 }
132 
TEST(ReadCPathFromPidSplitPageTest,Overlong)133 TEST(ReadCPathFromPidSplitPageTest, Overlong) {
134   std::string test_str(PATH_MAX + 1, 'a');
135   absl::StatusOr<std::string> read =
136       ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(test_str.data()));
137   EXPECT_THAT(read, Not(IsOk()));
138 }
139 
TEST(ReadCPathFromPidSplitPageTest,SplitPage)140 TEST(ReadCPathFromPidSplitPageTest, SplitPage) {
141   const uintptr_t page_size = getpagesize();
142   char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
143                                            PROT_READ | PROT_WRITE,
144                                            MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
145   ASSERT_THAT(res, Ne(MAP_FAILED));
146   absl::Cleanup cleanup = [res, page_size]() {
147     ASSERT_THAT(munmap(res, 2 * page_size), Eq(0));
148   };
149   char* str = &res[page_size - kTestString.size() / 2];
150   memcpy(str, kTestString.data(), kTestString.size());
151   absl::StatusOr<std::string> read =
152       ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(str));
153   ASSERT_THAT(read, IsOk());
154   EXPECT_THAT(*read, Eq(kTestString));
155 }
156 
TEST(ReadCPathFromPidSplitPageTest,NearUnreadableMemory)157 TEST(ReadCPathFromPidSplitPageTest, NearUnreadableMemory) {
158   const uintptr_t page_size = getpagesize();
159   char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
160                                            PROT_READ | PROT_WRITE,
161                                            MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
162   ASSERT_THAT(res, Ne(MAP_FAILED));
163   absl::Cleanup cleanup = [res, page_size]() {
164     ASSERT_THAT(munmap(res, 2 * page_size), Eq(0));
165   };
166   ASSERT_THAT(mprotect(&res[page_size], page_size, PROT_NONE), Eq(0));
167   char* str = &res[page_size - kTestString.size() - 1];
168   memcpy(str, kTestString.data(), kTestString.size());
169   absl::StatusOr<std::string> read =
170       ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(str));
171   ASSERT_THAT(read, IsOk());
172   EXPECT_THAT(*read, Eq(kTestString));
173 }
174 
TEST(CommunitacteTest,Normal)175 TEST(CommunitacteTest, Normal) {
176   const std::string path =
177       GetTestSourcePath("sandbox2/testcases/util_communicate");
178   std::string output;
179   SAPI_ASSERT_OK_AND_ASSIGN(
180       int exit_code,
181       util::Communicate({path, "argv1", "argv2"}, {"env1", "env2"}, &output));
182   EXPECT_THAT(exit_code, Eq(0));
183   EXPECT_THAT(output, StartsWith("3\nargv1\nargv2\nenv1\nenv2\n"));
184 }
185 
TEST(ReadBytesFromPidTest,Normal)186 TEST(ReadBytesFromPidTest, Normal) {
187   absl::StatusOr<std::vector<uint8_t>> read = ReadBytesFromPid(
188       getpid(), reinterpret_cast<uintptr_t>(kTestString.data()),
189       kTestString.size());
190   EXPECT_THAT(*read, ElementsAreArray(kTestString));
191 }
192 
TEST(ReadBytesFromPidTest,NearUnmappedMemory)193 TEST(ReadBytesFromPidTest, NearUnmappedMemory) {
194   const uintptr_t page_size = getpagesize();
195   ASSERT_LE(kTestString.size(), page_size);
196   char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
197                                            PROT_READ | PROT_WRITE,
198                                            MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
199   ASSERT_THAT(res, Ne(MAP_FAILED));
200   ASSERT_THAT(munmap(&res[page_size], page_size), Eq(0));
201   absl::Cleanup cleanup = [res, page_size]() {
202     ASSERT_THAT(munmap(res, page_size), Eq(0));
203   };
204   char* data = &res[page_size - kTestString.size()];
205   memcpy(data, kTestString.data(), kTestString.size());
206   absl::StatusOr<std::vector<uint8_t>> read = ReadBytesFromPid(
207       getpid(), reinterpret_cast<uintptr_t>(data), 2 * kTestString.size());
208   ASSERT_THAT(read, IsOk());
209   EXPECT_THAT(*read, ElementsAreArray(kTestString));
210 }
211 
212 class ReadBytesFromPidIntoTest : public testing::TestWithParam<bool> {
213  protected:
Read(pid_t pid,uintptr_t ptr,absl::Span<char> data)214   absl::StatusOr<size_t> Read(pid_t pid, uintptr_t ptr, absl::Span<char> data) {
215     if (GetParam()) {
216       return internal::ReadBytesFromPidWithReadv(pid, ptr, data);
217     } else {
218       return internal::ReadBytesFromPidWithReadvInSplitChunks(pid, ptr, data);
219     }
220   }
221 };
222 
TEST_P(ReadBytesFromPidIntoTest,Normal)223 TEST_P(ReadBytesFromPidIntoTest, Normal) {
224   char data[kTestString.size()] = {0};
225   absl::StatusOr<size_t> bytes_read =
226       Read(getpid(), reinterpret_cast<uintptr_t>(kTestString.data()),
227            absl::MakeSpan(data));
228   ASSERT_THAT(bytes_read, IsOk());
229   EXPECT_THAT(*bytes_read, Eq(kTestString.size()));
230   EXPECT_THAT(data, ElementsAreArray(kTestString));
231 }
232 
TEST_P(ReadBytesFromPidIntoTest,SplitPage)233 TEST_P(ReadBytesFromPidIntoTest, SplitPage) {
234   const uintptr_t page_size = getpagesize();
235   ASSERT_LE(kTestString.size(), page_size);
236   char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
237                                            PROT_READ | PROT_WRITE,
238                                            MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
239   ASSERT_THAT(res, Ne(MAP_FAILED));
240   absl::Cleanup cleanup = [res, page_size]() {
241     ASSERT_THAT(munmap(res, 2 * page_size), Eq(0));
242   };
243   char* data = &res[page_size - kTestString.size() / 2];
244   memcpy(data, kTestString.data(), kTestString.size());
245   char output[kTestString.size()];
246   absl::StatusOr<size_t> bytes_read =
247       Read(getpid(), reinterpret_cast<uintptr_t>(data), absl::MakeSpan(output));
248   ASSERT_THAT(bytes_read, IsOk());
249   EXPECT_THAT(*bytes_read, Eq(kTestString.size()));
250   EXPECT_THAT(output, ElementsAreArray(kTestString));
251 }
252 
TEST_P(ReadBytesFromPidIntoTest,InvalidPid)253 TEST_P(ReadBytesFromPidIntoTest, InvalidPid) {
254   char data;
255   absl::StatusOr<size_t> bytes_read =
256       Read(-1, reinterpret_cast<uintptr_t>(&data), absl::MakeSpan(&data, 1));
257   ASSERT_THAT(bytes_read, Not(IsOk()));
258 }
259 
TEST_P(ReadBytesFromPidIntoTest,ZeroLength)260 TEST_P(ReadBytesFromPidIntoTest, ZeroLength) {
261   char data;
262   absl::StatusOr<size_t> bytes_read = Read(
263       getpid(), reinterpret_cast<uintptr_t>(&data), absl::MakeSpan(&data, 0));
264   ASSERT_THAT(bytes_read, IsOk());
265   ASSERT_THAT(*bytes_read, Eq(0));
266 }
267 
TEST_P(ReadBytesFromPidIntoTest,ZeroLengthWithInvalidPid)268 TEST_P(ReadBytesFromPidIntoTest, ZeroLengthWithInvalidPid) {
269   char data;
270   absl::StatusOr<size_t> bytes_read =
271       Read(-1, reinterpret_cast<uintptr_t>(&data), absl::MakeSpan(&data, 0));
272   ASSERT_THAT(bytes_read, IsOk());
273   ASSERT_THAT(*bytes_read, Eq(0));
274 }
275 
TEST_P(ReadBytesFromPidIntoTest,UnmappedMemory)276 TEST_P(ReadBytesFromPidIntoTest, UnmappedMemory) {
277   const uintptr_t page_size = getpagesize();
278   char* res =
279       reinterpret_cast<char*>(mmap(nullptr, page_size, PROT_READ | PROT_WRITE,
280                                    MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
281   ASSERT_THAT(res, Ne(MAP_FAILED));
282   ASSERT_THAT(munmap(res, page_size), Eq(0));
283   absl::StatusOr<size_t> bytes_read =
284       Read(getpid(), reinterpret_cast<uintptr_t>(res), absl::MakeSpan(res, 1));
285   ASSERT_THAT(bytes_read, Not(IsOk()));
286 }
287 
TEST_P(ReadBytesFromPidIntoTest,NearUnmappedMemory)288 TEST_P(ReadBytesFromPidIntoTest, NearUnmappedMemory) {
289   const uintptr_t page_size = getpagesize();
290   char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
291                                            PROT_READ | PROT_WRITE,
292                                            MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
293   ASSERT_THAT(res, Ne(MAP_FAILED));
294   // Unmap second page so there's a gap.
295   ASSERT_THAT(munmap(&res[page_size], page_size), Eq(0));
296   absl::Cleanup cleanup = [res, page_size]() {
297     ASSERT_THAT(munmap(res, page_size), Eq(0));
298   };
299   char* data = &res[page_size - kTestString.size() / 2];
300   memcpy(data, kTestString.data(), kTestString.size() / 2);
301   char output[kTestString.size()];
302   absl::StatusOr<size_t> bytes_read =
303       Read(getpid(), reinterpret_cast<uintptr_t>(data), absl::MakeSpan(output));
304   ASSERT_THAT(bytes_read, IsOk());
305   EXPECT_THAT(*bytes_read, Eq(kTestString.size() / 2));
306   EXPECT_THAT(absl::MakeSpan(data, kTestString.size() / 2),
307               Eq(absl::MakeSpan(kTestString.data(), kTestString.size() / 2)));
308 }
309 
TEST_P(ReadBytesFromPidIntoTest,ExceedIovMax)310 TEST_P(ReadBytesFromPidIntoTest, ExceedIovMax) {
311   // Read one page past the max readable memory in one set of iovecs.
312   const uintptr_t page_size = getpagesize();
313   const size_t length = (IOV_MAX + 1) * page_size;
314   char* data = reinterpret_cast<char*>(mmap(nullptr, length + page_size,
315                                             PROT_READ | PROT_WRITE,
316                                             MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
317   ASSERT_THAT(data, Ne(MAP_FAILED));
318   // Unmap second page so there's a gap.
319   ASSERT_THAT(munmap(&data[length], page_size), Eq(0));
320   absl::Cleanup cleanup = [data, length]() {
321     ASSERT_THAT(munmap(data, length), Eq(0));
322   };
323   memset(data, 0x0e, length);
324   std::vector<char> output(length);
325   absl::StatusOr<size_t> bytes_read =
326       Read(getpid(), reinterpret_cast<uintptr_t>(data),
327            absl::MakeSpan(output.data(), length));
328   ASSERT_THAT(bytes_read, IsOk());
329   EXPECT_THAT(*bytes_read, Eq(length));
330   EXPECT_THAT(output, ElementsAreArray(data, length));
331 }
332 
333 INSTANTIATE_TEST_SUITE_P(ReadBytesFromPidInto, ReadBytesFromPidIntoTest,
334                          testing::Values(true, false));
335 
336 class WriteBytesToPidFromTest : public testing::TestWithParam<bool> {
337  protected:
Write(pid_t pid,uintptr_t ptr,absl::Span<const char> data)338   absl::StatusOr<size_t> Write(pid_t pid, uintptr_t ptr,
339                                absl::Span<const char> data) {
340     if (GetParam()) {
341       return internal::WriteBytesToPidWithWritev(pid, ptr, data);
342     } else {
343       return internal::WriteBytesToPidWithProcMem(pid, ptr, data);
344     }
345   };
346 };
347 
TEST_P(WriteBytesToPidFromTest,Normal)348 TEST_P(WriteBytesToPidFromTest, Normal) {
349   char data[kTestString.size()] = {0};
350   absl::StatusOr<size_t> bytes_written =
351       Write(getpid(), reinterpret_cast<uintptr_t>(data), kTestString);
352   ASSERT_THAT(bytes_written, IsOk());
353   EXPECT_THAT(*bytes_written, Eq(kTestString.size()));
354   EXPECT_THAT(data, ElementsAreArray(kTestString));
355 }
356 
TEST_P(WriteBytesToPidFromTest,SplitPage)357 TEST_P(WriteBytesToPidFromTest, SplitPage) {
358   const uintptr_t page_size = getpagesize();
359   ASSERT_LE(kTestString.size(), page_size);
360   char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
361                                            PROT_READ | PROT_WRITE,
362                                            MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
363   ASSERT_THAT(res, Ne(MAP_FAILED));
364   absl::Cleanup cleanup = [res, page_size]() {
365     ASSERT_THAT(munmap(res, 2 * page_size), Eq(0));
366   };
367   char* data = &res[page_size - kTestString.size() / 2];
368   absl::StatusOr<size_t> bytes_written =
369       Write(getpid(), reinterpret_cast<uintptr_t>(data), kTestString);
370   ASSERT_THAT(bytes_written, IsOk());
371   EXPECT_THAT(*bytes_written, Eq(kTestString.size()));
372   EXPECT_THAT(kTestString, ElementsAreArray(data, kTestString.size()));
373 }
374 
TEST_P(WriteBytesToPidFromTest,InvalidPid)375 TEST_P(WriteBytesToPidFromTest, InvalidPid) {
376   char data = 0;
377   absl::StatusOr<size_t> bytes_written =
378       Write(-1, reinterpret_cast<uintptr_t>(&data), absl::MakeSpan(&data, 1));
379   ASSERT_THAT(bytes_written, Not(IsOk()));
380 }
381 
TEST_P(WriteBytesToPidFromTest,ZeroLength)382 TEST_P(WriteBytesToPidFromTest, ZeroLength) {
383   char data = 0;
384   absl::StatusOr<size_t> bytes_written = Write(
385       getpid(), reinterpret_cast<uintptr_t>(&data), absl::MakeSpan(&data, 0));
386   ASSERT_THAT(bytes_written, IsOk());
387   ASSERT_THAT(*bytes_written, Eq(0));
388 }
389 
TEST_P(WriteBytesToPidFromTest,ZeroLengthWithInvalidPid)390 TEST_P(WriteBytesToPidFromTest, ZeroLengthWithInvalidPid) {
391   char data = 0;
392   absl::StatusOr<size_t> bytes_written =
393       Write(-1, reinterpret_cast<uintptr_t>(&data), absl::MakeSpan(&data, 0));
394   ASSERT_THAT(bytes_written, IsOk());
395   ASSERT_THAT(*bytes_written, Eq(0));
396 }
397 
TEST_P(WriteBytesToPidFromTest,NearUnmappedMemory)398 TEST_P(WriteBytesToPidFromTest, NearUnmappedMemory) {
399   const uintptr_t page_size = getpagesize();
400   char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
401                                            PROT_READ | PROT_WRITE,
402                                            MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
403   ASSERT_THAT(res, Ne(MAP_FAILED));
404   ASSERT_THAT(munmap(&res[page_size], page_size), Eq(0));
405   absl::Cleanup cleanup = [res, page_size]() {
406     ASSERT_THAT(munmap(res, page_size), Eq(0));
407   };
408   char* data = &res[page_size - kTestString.size() / 2];
409   absl::StatusOr<size_t> bytes_written =
410       Write(getpid(), reinterpret_cast<uintptr_t>(data), kTestString);
411   ASSERT_THAT(bytes_written, IsOk());
412   EXPECT_THAT(*bytes_written, Eq(kTestString.size() / 2));
413   EXPECT_THAT(absl::MakeSpan(data, kTestString.size() / 2),
414               Eq(absl::MakeSpan(kTestString.data(), kTestString.size() / 2)));
415 }
416 
TEST_P(WriteBytesToPidFromTest,ExceedIovMax)417 TEST_P(WriteBytesToPidFromTest, ExceedIovMax) {
418   const uintptr_t page_size = getpagesize();
419   const size_t length = (IOV_MAX + 1) * page_size;
420   char* data = reinterpret_cast<char*>(mmap(nullptr, length + page_size,
421                                             PROT_READ | PROT_WRITE,
422                                             MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
423   ASSERT_THAT(data, Ne(MAP_FAILED));
424   // Unmap second page so there's a gap.
425   ASSERT_THAT(munmap(&data[length], page_size), Eq(0));
426   absl::Cleanup cleanup = [data, length]() {
427     ASSERT_THAT(munmap(data, length), Eq(0));
428   };
429   memset(data, 0, length);
430   const std::vector<char> src(length, 0x0e);
431   absl::StatusOr<size_t> bytes_written =
432       Write(getpid(), reinterpret_cast<uintptr_t>(data),
433             absl::MakeSpan(src.data(), length));
434   ASSERT_THAT(bytes_written, IsOk());
435   EXPECT_THAT(*bytes_written, Eq(length));
436   EXPECT_THAT(src, ElementsAreArray(data, length));
437 }
438 
439 INSTANTIATE_TEST_SUITE_P(WriteBytesToPidFrom, WriteBytesToPidFromTest,
440                          testing::Values(true, false));
441 
442 }  // namespace
443 }  // namespace sandbox2::util
444