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/status/statusor.h"
32 #include "absl/strings/str_cat.h"
33 #include "absl/strings/string_view.h"
34 #include "sandboxed_api/util/status_matchers.h"
35
36 namespace sandbox2::util {
37 namespace {
38
39 using ::sapi::IsOk;
40 using ::testing::ElementsAre;
41 using ::testing::Eq;
42 using ::testing::Gt;
43 using ::testing::IsEmpty;
44 using ::testing::IsTrue;
45 using ::testing::Ne;
46 using ::testing::Not;
47 using ::testing::StrEq;
48
49 constexpr absl::string_view kTestString = "This is a test string";
50
TEST(UtilTest,TestCreateMemFd)51 TEST(UtilTest, TestCreateMemFd) {
52 int fd = 0;
53 ASSERT_THAT(CreateMemFd(&fd), IsTrue());
54 EXPECT_THAT(fd, Gt(1));
55 close(fd);
56 }
57
TEST(CharPtrArrayTest,FromStringVector)58 TEST(CharPtrArrayTest, FromStringVector) {
59 std::vector<std::string> strings = {"a", "b", "c"};
60 CharPtrArray array = CharPtrArray::FromStringVector(strings);
61 EXPECT_THAT(array.ToStringVector(), Eq(strings));
62 EXPECT_THAT(array.array(),
63 ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), nullptr));
64 EXPECT_THAT(array.data(), Eq(array.array().data()));
65 }
66
TEST(CharPtrArrayTest,FromCharPtrArray)67 TEST(CharPtrArrayTest, FromCharPtrArray) {
68 std::vector<std::string> strings = {"a", "b", "c"};
69 std::vector<char*> string_arr;
70 for (std::string& s : strings) {
71 string_arr.push_back(s.data());
72 }
73 string_arr.push_back(nullptr);
74 CharPtrArray array(string_arr.data());
75 EXPECT_THAT(array.ToStringVector(), Eq(strings));
76 EXPECT_THAT(array.array(),
77 ElementsAre(StrEq("a"), StrEq("b"), StrEq("c"), nullptr));
78 EXPECT_THAT(array.data(), Eq(array.array().data()));
79 }
80
TEST(GetProcStatusLineTest,Pid)81 TEST(GetProcStatusLineTest, Pid) {
82 std::string line = GetProcStatusLine(getpid(), "Pid");
83 EXPECT_THAT(line, Eq(absl::StrCat(getpid())));
84 }
85
TEST(GetProcStatusLineTest,NonExisting)86 TEST(GetProcStatusLineTest, NonExisting) {
87 std::string line =
88 GetProcStatusLine(getpid(), "__N_o_n_ExistingStatusSetting");
89 EXPECT_THAT(line, IsEmpty());
90 }
91
TEST(ForkWithFlagsTest,DoesForkNormally)92 TEST(ForkWithFlagsTest, DoesForkNormally) {
93 int pfds[2];
94 ASSERT_THAT(pipe(pfds), Eq(0));
95 pid_t child = ForkWithFlags(SIGCHLD);
96 ASSERT_THAT(child, Ne(-1));
97 if (child == 0) {
98 char c = 'a';
99 if (!write(pfds[1], &c, 1)) {
100 exit(EXIT_FAILURE);
101 }
102 exit(EXIT_SUCCESS);
103 }
104 close(pfds[1]);
105 char c = ' ';
106 EXPECT_THAT(read(pfds[0], &c, 1), Eq(1));
107 close(pfds[0]);
108 EXPECT_THAT(c, Eq('a'));
109 int status;
110 ASSERT_THAT(TEMP_FAILURE_RETRY(waitpid(child, &status, 0)), Eq(child));
111 EXPECT_TRUE(WIFEXITED(status));
112 EXPECT_THAT(WEXITSTATUS(status), Eq(0));
113 }
114
TEST(ForkWithFlagsTest,UnsupportedFlag)115 TEST(ForkWithFlagsTest, UnsupportedFlag) {
116 EXPECT_THAT(ForkWithFlags(CLONE_CHILD_CLEARTID), Eq(-1));
117 }
118
TEST(ReadCPathFromPidSplitPageTest,Normal)119 TEST(ReadCPathFromPidSplitPageTest, Normal) {
120 std::string test_str(kTestString);
121 absl::StatusOr<std::string> read =
122 ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(test_str.data()));
123 ASSERT_THAT(read, IsOk());
124 EXPECT_THAT(*read, Eq(kTestString));
125 }
126
TEST(ReadCPathFromPidSplitPageTest,Overlong)127 TEST(ReadCPathFromPidSplitPageTest, Overlong) {
128 std::string test_str(PATH_MAX + 1, 'a');
129 absl::StatusOr<std::string> read =
130 ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(test_str.data()));
131 EXPECT_THAT(read, Not(IsOk()));
132 }
133
TEST(ReadCPathFromPidSplitPageTest,SplitPage)134 TEST(ReadCPathFromPidSplitPageTest, SplitPage) {
135 const uintptr_t page_size = getpagesize();
136 char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
137 PROT_READ | PROT_WRITE,
138 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
139 ASSERT_THAT(res, Ne(MAP_FAILED));
140 absl::Cleanup cleanup = [res, page_size]() {
141 ASSERT_THAT(munmap(res, 2 * page_size), Eq(0));
142 };
143 char* str = &res[page_size - kTestString.size() / 2];
144 memcpy(str, kTestString.data(), kTestString.size());
145 absl::StatusOr<std::string> read =
146 ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(str));
147 ASSERT_THAT(read, IsOk());
148 EXPECT_THAT(*read, Eq(kTestString));
149 }
150
TEST(ReadCPathFromPidSplitPageTest,NearUnreadableMemory)151 TEST(ReadCPathFromPidSplitPageTest, NearUnreadableMemory) {
152 const uintptr_t page_size = getpagesize();
153 char* res = reinterpret_cast<char*>(mmap(nullptr, 2 * page_size,
154 PROT_READ | PROT_WRITE,
155 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0));
156 ASSERT_THAT(res, Ne(MAP_FAILED));
157 absl::Cleanup cleanup = [res, page_size]() {
158 ASSERT_THAT(munmap(res, 2 * page_size), Eq(0));
159 };
160 ASSERT_THAT(mprotect(&res[page_size], page_size, PROT_NONE), Eq(0));
161 char* str = &res[page_size - kTestString.size() - 1];
162 memcpy(str, kTestString.data(), kTestString.size());
163 absl::StatusOr<std::string> read =
164 ReadCPathFromPid(getpid(), reinterpret_cast<uintptr_t>(str));
165 ASSERT_THAT(read, IsOk());
166 EXPECT_THAT(*read, Eq(kTestString));
167 }
168
169 } // namespace
170 } // namespace sandbox2::util
171