1*4b9c6d91SCole Faust /* Copyright 2016 The ChromiumOS Authors
2*4b9c6d91SCole Faust * Use of this source code is governed by a BSD-style license that can be
3*4b9c6d91SCole Faust * found in the LICENSE file.
4*4b9c6d91SCole Faust *
5*4b9c6d91SCole Faust * Test platform independent logic of Minijail using gtest.
6*4b9c6d91SCole Faust */
7*4b9c6d91SCole Faust
8*4b9c6d91SCole Faust #include <errno.h>
9*4b9c6d91SCole Faust
10*4b9c6d91SCole Faust #include <dirent.h>
11*4b9c6d91SCole Faust #include <fcntl.h>
12*4b9c6d91SCole Faust #include <sys/mman.h>
13*4b9c6d91SCole Faust #include <sys/mount.h>
14*4b9c6d91SCole Faust #include <sys/stat.h>
15*4b9c6d91SCole Faust #include <sys/types.h>
16*4b9c6d91SCole Faust #include <sys/wait.h>
17*4b9c6d91SCole Faust #include <unistd.h>
18*4b9c6d91SCole Faust
19*4b9c6d91SCole Faust #include <gtest/gtest.h>
20*4b9c6d91SCole Faust
21*4b9c6d91SCole Faust #include <functional>
22*4b9c6d91SCole Faust #include <map>
23*4b9c6d91SCole Faust #include <set>
24*4b9c6d91SCole Faust #include <string>
25*4b9c6d91SCole Faust
26*4b9c6d91SCole Faust #include "landlock_util.h"
27*4b9c6d91SCole Faust #include "libminijail-private.h"
28*4b9c6d91SCole Faust #include "libminijail.h"
29*4b9c6d91SCole Faust #include "scoped_minijail.h"
30*4b9c6d91SCole Faust #include "unittest_util.h"
31*4b9c6d91SCole Faust #include "util.h"
32*4b9c6d91SCole Faust
33*4b9c6d91SCole Faust namespace {
34*4b9c6d91SCole Faust
35*4b9c6d91SCole Faust #if defined(__ANDROID__)
36*4b9c6d91SCole Faust # define ROOT_PREFIX "/system"
37*4b9c6d91SCole Faust #else
38*4b9c6d91SCole Faust # define ROOT_PREFIX ""
39*4b9c6d91SCole Faust #endif
40*4b9c6d91SCole Faust
41*4b9c6d91SCole Faust constexpr char kShellPath[] = ROOT_PREFIX "/bin/sh";
42*4b9c6d91SCole Faust constexpr char kCatPath[] = ROOT_PREFIX "/bin/cat";
43*4b9c6d91SCole Faust constexpr char kPreloadPath[] = "./libminijailpreload.so";
44*4b9c6d91SCole Faust constexpr size_t kBufferSize = 128;
45*4b9c6d91SCole Faust
GetProcessSubtreePids(pid_t root_pid)46*4b9c6d91SCole Faust std::set<pid_t> GetProcessSubtreePids(pid_t root_pid) {
47*4b9c6d91SCole Faust std::set<pid_t> pids{root_pid};
48*4b9c6d91SCole Faust bool progress = false;
49*4b9c6d91SCole Faust
50*4b9c6d91SCole Faust do {
51*4b9c6d91SCole Faust progress = false;
52*4b9c6d91SCole Faust DIR* d = opendir("/proc");
53*4b9c6d91SCole Faust if (!d)
54*4b9c6d91SCole Faust pdie("opendir(\"/proc\")");
55*4b9c6d91SCole Faust
56*4b9c6d91SCole Faust struct dirent* dir_entry;
57*4b9c6d91SCole Faust while ((dir_entry = readdir(d)) != nullptr) {
58*4b9c6d91SCole Faust if (dir_entry->d_type != DT_DIR)
59*4b9c6d91SCole Faust continue;
60*4b9c6d91SCole Faust char* end;
61*4b9c6d91SCole Faust const int pid = strtol(dir_entry->d_name, &end, 10);
62*4b9c6d91SCole Faust if (*end != '\0')
63*4b9c6d91SCole Faust continue;
64*4b9c6d91SCole Faust std::string path = "/proc/" + std::to_string(pid) + "/stat";
65*4b9c6d91SCole Faust
66*4b9c6d91SCole Faust FILE* f = fopen(path.c_str(), "re");
67*4b9c6d91SCole Faust if (!f) {
68*4b9c6d91SCole Faust if (errno == ENOENT) {
69*4b9c6d91SCole Faust // This loop is inherently racy, since PIDs can be reaped in the
70*4b9c6d91SCole Faust // middle of this. Not being able to find one /proc/PID/stat file is
71*4b9c6d91SCole Faust // completely normal.
72*4b9c6d91SCole Faust continue;
73*4b9c6d91SCole Faust }
74*4b9c6d91SCole Faust pdie("fopen(%s)", path.c_str());
75*4b9c6d91SCole Faust }
76*4b9c6d91SCole Faust pid_t ppid;
77*4b9c6d91SCole Faust int ret = fscanf(f, "%*d (%*[^)]) %*c %d", &ppid);
78*4b9c6d91SCole Faust fclose(f);
79*4b9c6d91SCole Faust if (ret != 1) {
80*4b9c6d91SCole Faust continue;
81*4b9c6d91SCole Faust }
82*4b9c6d91SCole Faust if (pids.find(ppid) == pids.end())
83*4b9c6d91SCole Faust continue;
84*4b9c6d91SCole Faust progress |= pids.insert(pid).second;
85*4b9c6d91SCole Faust }
86*4b9c6d91SCole Faust closedir(d);
87*4b9c6d91SCole Faust } while (progress);
88*4b9c6d91SCole Faust return pids;
89*4b9c6d91SCole Faust }
90*4b9c6d91SCole Faust
GetNamespaces(pid_t pid,const std::vector<std::string> & namespace_names)91*4b9c6d91SCole Faust std::map<std::string, std::string> GetNamespaces(
92*4b9c6d91SCole Faust pid_t pid,
93*4b9c6d91SCole Faust const std::vector<std::string>& namespace_names) {
94*4b9c6d91SCole Faust std::map<std::string, std::string> namespaces;
95*4b9c6d91SCole Faust char buf[kBufferSize];
96*4b9c6d91SCole Faust for (const auto& namespace_name : namespace_names) {
97*4b9c6d91SCole Faust std::string path = "/proc/" + std::to_string(pid) + "/ns/" + namespace_name;
98*4b9c6d91SCole Faust ssize_t len = readlink(path.c_str(), buf, sizeof(buf));
99*4b9c6d91SCole Faust if (len == -1)
100*4b9c6d91SCole Faust pdie("readlink(\"%s\")", path.c_str());
101*4b9c6d91SCole Faust namespaces.emplace(namespace_name, std::string(buf, len));
102*4b9c6d91SCole Faust }
103*4b9c6d91SCole Faust return namespaces;
104*4b9c6d91SCole Faust }
105*4b9c6d91SCole Faust
set_preload_path(minijail * j)106*4b9c6d91SCole Faust void set_preload_path(minijail *j) {
107*4b9c6d91SCole Faust #if defined(__ANDROID__)
108*4b9c6d91SCole Faust // libminijailpreload.so isn't available in android, so skip trying to load
109*4b9c6d91SCole Faust // it. Even without the preload, all the test cases either pass or are skipped
110*4b9c6d91SCole Faust // for other reasons.
111*4b9c6d91SCole Faust return;
112*4b9c6d91SCole Faust #endif
113*4b9c6d91SCole Faust // We need to get the absolute path because entering a new mntns will
114*4b9c6d91SCole Faust // implicitly chdir(/) for us.
115*4b9c6d91SCole Faust char *preload_path = realpath(kPreloadPath, nullptr);
116*4b9c6d91SCole Faust ASSERT_NE(preload_path, nullptr);
117*4b9c6d91SCole Faust minijail_set_preload_path(j, preload_path);
118*4b9c6d91SCole Faust free(preload_path);
119*4b9c6d91SCole Faust }
120*4b9c6d91SCole Faust
121*4b9c6d91SCole Faust } // namespace
122*4b9c6d91SCole Faust
123*4b9c6d91SCole Faust /* Silence unused variable warnings. */
TEST(silence,silence_unused)124*4b9c6d91SCole Faust TEST(silence, silence_unused) {
125*4b9c6d91SCole Faust EXPECT_STREQ(kLdPreloadEnvVar, kLdPreloadEnvVar);
126*4b9c6d91SCole Faust EXPECT_STREQ(kFdEnvVar, kFdEnvVar);
127*4b9c6d91SCole Faust EXPECT_STRNE(kFdEnvVar, kLdPreloadEnvVar);
128*4b9c6d91SCole Faust }
129*4b9c6d91SCole Faust
TEST(consumebytes,zero)130*4b9c6d91SCole Faust TEST(consumebytes, zero) {
131*4b9c6d91SCole Faust char buf[1024];
132*4b9c6d91SCole Faust size_t len = sizeof(buf);
133*4b9c6d91SCole Faust char *pos = &buf[0];
134*4b9c6d91SCole Faust EXPECT_NE(nullptr, consumebytes(0, &pos, &len));
135*4b9c6d91SCole Faust EXPECT_EQ(&buf[0], pos);
136*4b9c6d91SCole Faust EXPECT_EQ(sizeof(buf), len);
137*4b9c6d91SCole Faust }
138*4b9c6d91SCole Faust
TEST(consumebytes,exact)139*4b9c6d91SCole Faust TEST(consumebytes, exact) {
140*4b9c6d91SCole Faust char buf[1024];
141*4b9c6d91SCole Faust size_t len = sizeof(buf);
142*4b9c6d91SCole Faust char *pos = &buf[0];
143*4b9c6d91SCole Faust /* One past the end since it consumes the whole buffer. */
144*4b9c6d91SCole Faust char *end = &buf[sizeof(buf)];
145*4b9c6d91SCole Faust EXPECT_NE(nullptr, consumebytes(len, &pos, &len));
146*4b9c6d91SCole Faust EXPECT_EQ((size_t)0, len);
147*4b9c6d91SCole Faust EXPECT_EQ(end, pos);
148*4b9c6d91SCole Faust }
149*4b9c6d91SCole Faust
TEST(consumebytes,half)150*4b9c6d91SCole Faust TEST(consumebytes, half) {
151*4b9c6d91SCole Faust char buf[1024];
152*4b9c6d91SCole Faust size_t len = sizeof(buf);
153*4b9c6d91SCole Faust char *pos = &buf[0];
154*4b9c6d91SCole Faust /* One past the end since it consumes the whole buffer. */
155*4b9c6d91SCole Faust char *end = &buf[sizeof(buf) / 2];
156*4b9c6d91SCole Faust EXPECT_NE(nullptr, consumebytes(len / 2, &pos, &len));
157*4b9c6d91SCole Faust EXPECT_EQ(sizeof(buf) / 2, len);
158*4b9c6d91SCole Faust EXPECT_EQ(end, pos);
159*4b9c6d91SCole Faust }
160*4b9c6d91SCole Faust
TEST(consumebytes,toolong)161*4b9c6d91SCole Faust TEST(consumebytes, toolong) {
162*4b9c6d91SCole Faust char buf[1024];
163*4b9c6d91SCole Faust size_t len = sizeof(buf);
164*4b9c6d91SCole Faust char *pos = &buf[0];
165*4b9c6d91SCole Faust /* One past the end since it consumes the whole buffer. */
166*4b9c6d91SCole Faust EXPECT_EQ(nullptr, consumebytes(len + 1, &pos, &len));
167*4b9c6d91SCole Faust EXPECT_EQ(sizeof(buf), len);
168*4b9c6d91SCole Faust EXPECT_EQ(&buf[0], pos);
169*4b9c6d91SCole Faust }
170*4b9c6d91SCole Faust
TEST(consumestr,zero)171*4b9c6d91SCole Faust TEST(consumestr, zero) {
172*4b9c6d91SCole Faust char buf[1024];
173*4b9c6d91SCole Faust size_t len = 0;
174*4b9c6d91SCole Faust char *pos = &buf[0];
175*4b9c6d91SCole Faust memset(buf, 0xff, sizeof(buf));
176*4b9c6d91SCole Faust EXPECT_EQ(nullptr, consumestr(&pos, &len));
177*4b9c6d91SCole Faust EXPECT_EQ((size_t)0, len);
178*4b9c6d91SCole Faust EXPECT_EQ(&buf[0], pos);
179*4b9c6d91SCole Faust }
180*4b9c6d91SCole Faust
TEST(consumestr,nonul)181*4b9c6d91SCole Faust TEST(consumestr, nonul) {
182*4b9c6d91SCole Faust char buf[1024];
183*4b9c6d91SCole Faust size_t len = sizeof(buf);
184*4b9c6d91SCole Faust char *pos = &buf[0];
185*4b9c6d91SCole Faust memset(buf, 0xff, sizeof(buf));
186*4b9c6d91SCole Faust EXPECT_EQ(nullptr, consumestr(&pos, &len));
187*4b9c6d91SCole Faust EXPECT_EQ(sizeof(buf), len);
188*4b9c6d91SCole Faust EXPECT_EQ(&buf[0], pos);
189*4b9c6d91SCole Faust }
190*4b9c6d91SCole Faust
TEST(consumestr,full)191*4b9c6d91SCole Faust TEST(consumestr, full) {
192*4b9c6d91SCole Faust char buf[1024];
193*4b9c6d91SCole Faust size_t len = sizeof(buf);
194*4b9c6d91SCole Faust char *pos = &buf[0];
195*4b9c6d91SCole Faust memset(buf, 0xff, sizeof(buf));
196*4b9c6d91SCole Faust buf[sizeof(buf)-1] = '\0';
197*4b9c6d91SCole Faust EXPECT_EQ((void *)buf, consumestr(&pos, &len));
198*4b9c6d91SCole Faust EXPECT_EQ((size_t)0, len);
199*4b9c6d91SCole Faust EXPECT_EQ(&buf[sizeof(buf)], pos);
200*4b9c6d91SCole Faust }
201*4b9c6d91SCole Faust
TEST(consumestr,trailing_nul)202*4b9c6d91SCole Faust TEST(consumestr, trailing_nul) {
203*4b9c6d91SCole Faust char buf[1024];
204*4b9c6d91SCole Faust size_t len = sizeof(buf) - 1;
205*4b9c6d91SCole Faust char *pos = &buf[0];
206*4b9c6d91SCole Faust memset(buf, 0xff, sizeof(buf));
207*4b9c6d91SCole Faust buf[sizeof(buf)-1] = '\0';
208*4b9c6d91SCole Faust EXPECT_EQ(nullptr, consumestr(&pos, &len));
209*4b9c6d91SCole Faust EXPECT_EQ(sizeof(buf) - 1, len);
210*4b9c6d91SCole Faust EXPECT_EQ(&buf[0], pos);
211*4b9c6d91SCole Faust }
212*4b9c6d91SCole Faust
213*4b9c6d91SCole Faust class MarshalTest : public ::testing::Test {
214*4b9c6d91SCole Faust protected:
SetUp()215*4b9c6d91SCole Faust virtual void SetUp() {
216*4b9c6d91SCole Faust m_ = minijail_new();
217*4b9c6d91SCole Faust j_ = minijail_new();
218*4b9c6d91SCole Faust size_ = minijail_size(m_);
219*4b9c6d91SCole Faust }
TearDown()220*4b9c6d91SCole Faust virtual void TearDown() {
221*4b9c6d91SCole Faust minijail_destroy(m_);
222*4b9c6d91SCole Faust minijail_destroy(j_);
223*4b9c6d91SCole Faust }
224*4b9c6d91SCole Faust
225*4b9c6d91SCole Faust char buf_[4096];
226*4b9c6d91SCole Faust struct minijail *m_;
227*4b9c6d91SCole Faust struct minijail *j_;
228*4b9c6d91SCole Faust size_t size_;
229*4b9c6d91SCole Faust };
230*4b9c6d91SCole Faust
TEST_F(MarshalTest,empty)231*4b9c6d91SCole Faust TEST_F(MarshalTest, empty) {
232*4b9c6d91SCole Faust ASSERT_EQ(0, minijail_marshal(m_, buf_, sizeof(buf_)));
233*4b9c6d91SCole Faust EXPECT_EQ(0, minijail_unmarshal(j_, buf_, size_));
234*4b9c6d91SCole Faust }
235*4b9c6d91SCole Faust
236*4b9c6d91SCole Faust TEST_F(MarshalTest, 0xff) {
237*4b9c6d91SCole Faust memset(buf_, 0xff, sizeof(buf_));
238*4b9c6d91SCole Faust /* Should fail on the first consumestr since a NUL will never be found. */
239*4b9c6d91SCole Faust EXPECT_EQ(-EINVAL, minijail_unmarshal(j_, buf_, sizeof(buf_)));
240*4b9c6d91SCole Faust }
241*4b9c6d91SCole Faust
TEST_F(MarshalTest,copy_empty)242*4b9c6d91SCole Faust TEST_F(MarshalTest, copy_empty) {
243*4b9c6d91SCole Faust ASSERT_EQ(0, minijail_copy_jail(m_, j_));
244*4b9c6d91SCole Faust }
245*4b9c6d91SCole Faust
TEST(KillTest,running_process)246*4b9c6d91SCole Faust TEST(KillTest, running_process) {
247*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
248*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", "sleep 1000", nullptr};
249*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
250*4b9c6d91SCole Faust EXPECT_EQ(minijail_kill(j.get()), 128 + SIGTERM);
251*4b9c6d91SCole Faust EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
252*4b9c6d91SCole Faust }
253*4b9c6d91SCole Faust
TEST(KillTest,process_already_awaited)254*4b9c6d91SCole Faust TEST(KillTest, process_already_awaited) {
255*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
256*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", "sleep 1; exit 42", nullptr};
257*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
258*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), 42);
259*4b9c6d91SCole Faust EXPECT_EQ(minijail_kill(j.get()), -ESRCH);
260*4b9c6d91SCole Faust }
261*4b9c6d91SCole Faust
TEST(KillTest,process_already_finished_but_not_awaited)262*4b9c6d91SCole Faust TEST(KillTest, process_already_finished_but_not_awaited) {
263*4b9c6d91SCole Faust int fds[2];
264*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
265*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", "exit 42", nullptr};
266*4b9c6d91SCole Faust ASSERT_EQ(pipe(fds), 0);
267*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
268*4b9c6d91SCole Faust ASSERT_EQ(close(fds[1]), 0);
269*4b9c6d91SCole Faust // Wait for process to finish.
270*4b9c6d91SCole Faust char buf[PIPE_BUF];
271*4b9c6d91SCole Faust EXPECT_EQ(read(fds[0], buf, PIPE_BUF), 0);
272*4b9c6d91SCole Faust EXPECT_EQ(minijail_kill(j.get()), 42);
273*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
274*4b9c6d91SCole Faust }
275*4b9c6d91SCole Faust
TEST(KillTest,process_not_started)276*4b9c6d91SCole Faust TEST(KillTest, process_not_started) {
277*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
278*4b9c6d91SCole Faust EXPECT_EQ(minijail_kill(j.get()), -ECHILD);
279*4b9c6d91SCole Faust }
280*4b9c6d91SCole Faust
TEST(WaitTest,return_zero)281*4b9c6d91SCole Faust TEST(WaitTest, return_zero) {
282*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
283*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", "exit 0", nullptr};
284*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
285*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), 0);
286*4b9c6d91SCole Faust }
287*4b9c6d91SCole Faust
TEST(WaitTest,return_max)288*4b9c6d91SCole Faust TEST(WaitTest, return_max) {
289*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
290*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", "exit 255", nullptr};
291*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
292*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), 255);
293*4b9c6d91SCole Faust }
294*4b9c6d91SCole Faust
TEST(WaitTest,return_modulo)295*4b9c6d91SCole Faust TEST(WaitTest, return_modulo) {
296*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
297*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", "exit 256", nullptr};
298*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
299*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), 0);
300*4b9c6d91SCole Faust }
301*4b9c6d91SCole Faust
TEST(WaitTest,killed_by_sigkill)302*4b9c6d91SCole Faust TEST(WaitTest, killed_by_sigkill) {
303*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
304*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", "kill -KILL $$; sleep 1000", nullptr};
305*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
306*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_SIG_BASE + SIGKILL);
307*4b9c6d91SCole Faust }
308*4b9c6d91SCole Faust
TEST(WaitTest,killed_by_sigsys)309*4b9c6d91SCole Faust TEST(WaitTest, killed_by_sigsys) {
310*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
311*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", "kill -SYS $$; sleep 1000", nullptr};
312*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
313*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_JAIL);
314*4b9c6d91SCole Faust }
315*4b9c6d91SCole Faust
TEST(WaitTest,command_not_found)316*4b9c6d91SCole Faust TEST(WaitTest, command_not_found) {
317*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
318*4b9c6d91SCole Faust char* const argv[] = {"whatever", nullptr};
319*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), "command that cannot be found", argv), 0);
320*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_COMMAND);
321*4b9c6d91SCole Faust }
322*4b9c6d91SCole Faust
TEST(WaitTest,command_not_run)323*4b9c6d91SCole Faust TEST(WaitTest, command_not_run) {
324*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
325*4b9c6d91SCole Faust char* const argv[] = {"whatever", nullptr};
326*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), "/dev/null", argv), 0);
327*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), MINIJAIL_ERR_NO_ACCESS);
328*4b9c6d91SCole Faust }
329*4b9c6d91SCole Faust
TEST(WaitTest,no_process)330*4b9c6d91SCole Faust TEST(WaitTest, no_process) {
331*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
332*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
333*4b9c6d91SCole Faust }
334*4b9c6d91SCole Faust
TEST(WaitTest,can_wait_only_once)335*4b9c6d91SCole Faust TEST(WaitTest, can_wait_only_once) {
336*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
337*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", "exit 0", nullptr};
338*4b9c6d91SCole Faust EXPECT_EQ(minijail_run(j.get(), kShellPath, argv), 0);
339*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), 0);
340*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), -ECHILD);
341*4b9c6d91SCole Faust }
342*4b9c6d91SCole Faust
TEST(Test,minijail_preserve_fd_no_leak)343*4b9c6d91SCole Faust TEST(Test, minijail_preserve_fd_no_leak) {
344*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
345*4b9c6d91SCole Faust char* const script = R"(
346*4b9c6d91SCole Faust echo Hi >&1;
347*4b9c6d91SCole Faust exec 1>&-;
348*4b9c6d91SCole Faust read line1;
349*4b9c6d91SCole Faust read line2;
350*4b9c6d91SCole Faust echo "$line1$line2 and Goodbye" >&2;
351*4b9c6d91SCole Faust exit 42;
352*4b9c6d91SCole Faust )";
353*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", script, nullptr};
354*4b9c6d91SCole Faust
355*4b9c6d91SCole Faust const int npipes = 3;
356*4b9c6d91SCole Faust int fds[npipes][2];
357*4b9c6d91SCole Faust
358*4b9c6d91SCole Faust // Create pipes.
359*4b9c6d91SCole Faust for (int i = 0; i < npipes; ++i) {
360*4b9c6d91SCole Faust ASSERT_EQ(pipe(fds[i]), 0);
361*4b9c6d91SCole Faust }
362*4b9c6d91SCole Faust
363*4b9c6d91SCole Faust // All pipes are output pipes except for the first one which is used as
364*4b9c6d91SCole Faust // input pipe.
365*4b9c6d91SCole Faust std::swap(fds[0][0], fds[0][1]);
366*4b9c6d91SCole Faust
367*4b9c6d91SCole Faust for (int i = 0; i < npipes; ++i) {
368*4b9c6d91SCole Faust const int fd = fds[i][1];
369*4b9c6d91SCole Faust minijail_preserve_fd(j.get(), fd, i);
370*4b9c6d91SCole Faust }
371*4b9c6d91SCole Faust
372*4b9c6d91SCole Faust minijail_close_open_fds(j.get());
373*4b9c6d91SCole Faust
374*4b9c6d91SCole Faust EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
375*4b9c6d91SCole Faust
376*4b9c6d91SCole Faust // Close unused end of pipes.
377*4b9c6d91SCole Faust for (int i = 0; i < npipes; ++i) {
378*4b9c6d91SCole Faust const int fd = fds[i][1];
379*4b9c6d91SCole Faust ASSERT_EQ(close(fd), 0);
380*4b9c6d91SCole Faust }
381*4b9c6d91SCole Faust
382*4b9c6d91SCole Faust const int in = fds[0][0];
383*4b9c6d91SCole Faust const int out = fds[1][0];
384*4b9c6d91SCole Faust const int err = fds[2][0];
385*4b9c6d91SCole Faust
386*4b9c6d91SCole Faust char buf[PIPE_BUF];
387*4b9c6d91SCole Faust ssize_t nbytes;
388*4b9c6d91SCole Faust
389*4b9c6d91SCole Faust // Check that stdout pipe works.
390*4b9c6d91SCole Faust nbytes = read(out, buf, PIPE_BUF);
391*4b9c6d91SCole Faust ASSERT_GT(nbytes, 0);
392*4b9c6d91SCole Faust EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
393*4b9c6d91SCole Faust
394*4b9c6d91SCole Faust // Check that the write end of stdout pipe got closed by the child process. If
395*4b9c6d91SCole Faust // the child process kept other file descriptors connected to stdout, then the
396*4b9c6d91SCole Faust // parent process wouldn't be able to detect that all write ends of this pipe
397*4b9c6d91SCole Faust // are closed and it would block here.
398*4b9c6d91SCole Faust EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
399*4b9c6d91SCole Faust ASSERT_EQ(close(out), 0);
400*4b9c6d91SCole Faust
401*4b9c6d91SCole Faust // Check that stdin pipe works.
402*4b9c6d91SCole Faust const std::string s = "Greetings\n";
403*4b9c6d91SCole Faust EXPECT_EQ(write(in, s.data(), s.size()), s.size());
404*4b9c6d91SCole Faust
405*4b9c6d91SCole Faust // Close write end of pipe connected to child's stdin. If there was another
406*4b9c6d91SCole Faust // file descriptor connected to this write end, then the child process
407*4b9c6d91SCole Faust // wouldn't be able to detect that this write end is closed and it would
408*4b9c6d91SCole Faust // block.
409*4b9c6d91SCole Faust ASSERT_EQ(close(in), 0);
410*4b9c6d91SCole Faust
411*4b9c6d91SCole Faust // Check that child process continued and ended.
412*4b9c6d91SCole Faust nbytes = read(err, buf, PIPE_BUF);
413*4b9c6d91SCole Faust ASSERT_GT(nbytes, 0);
414*4b9c6d91SCole Faust EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
415*4b9c6d91SCole Faust
416*4b9c6d91SCole Faust // Check that the write end of the stderr pipe is closed when the child
417*4b9c6d91SCole Faust // process finishes.
418*4b9c6d91SCole Faust EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
419*4b9c6d91SCole Faust ASSERT_EQ(close(err), 0);
420*4b9c6d91SCole Faust
421*4b9c6d91SCole Faust // Check the child process termination status.
422*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), 42);
423*4b9c6d91SCole Faust }
424*4b9c6d91SCole Faust
TEST(Test,close_original_pipes_after_dup2)425*4b9c6d91SCole Faust TEST(Test, close_original_pipes_after_dup2) {
426*4b9c6d91SCole Faust // Pipe used by child process to signal that it continued after reading from
427*4b9c6d91SCole Faust // stdin.
428*4b9c6d91SCole Faust int to_wait[2];
429*4b9c6d91SCole Faust ASSERT_EQ(pipe(to_wait), 0);
430*4b9c6d91SCole Faust
431*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
432*4b9c6d91SCole Faust char* program;
433*4b9c6d91SCole Faust ASSERT_GT(asprintf(&program, R"(
434*4b9c6d91SCole Faust echo Hi >&1;
435*4b9c6d91SCole Faust echo There >&2;
436*4b9c6d91SCole Faust exec 1>&-;
437*4b9c6d91SCole Faust exec 2>&-;
438*4b9c6d91SCole Faust read line1;
439*4b9c6d91SCole Faust read line2;
440*4b9c6d91SCole Faust echo "$line1$line2 and Goodbye" >&%d;
441*4b9c6d91SCole Faust exit 42;
442*4b9c6d91SCole Faust )", to_wait[1]), 0);
443*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", program, nullptr};
444*4b9c6d91SCole Faust
445*4b9c6d91SCole Faust int in = -1;
446*4b9c6d91SCole Faust int out = -1;
447*4b9c6d91SCole Faust int err = -1;
448*4b9c6d91SCole Faust EXPECT_EQ(minijail_run_pid_pipes_no_preload(j.get(), kShellPath, argv,
449*4b9c6d91SCole Faust nullptr, &in, &out, &err),
450*4b9c6d91SCole Faust 0);
451*4b9c6d91SCole Faust free(program);
452*4b9c6d91SCole Faust
453*4b9c6d91SCole Faust EXPECT_GT(in, 0);
454*4b9c6d91SCole Faust EXPECT_GT(out, 0);
455*4b9c6d91SCole Faust EXPECT_GT(err, 0);
456*4b9c6d91SCole Faust
457*4b9c6d91SCole Faust char buf[PIPE_BUF];
458*4b9c6d91SCole Faust ssize_t n;
459*4b9c6d91SCole Faust
460*4b9c6d91SCole Faust // Check that stdout and stderr pipes work.
461*4b9c6d91SCole Faust n = read(out, buf, PIPE_BUF);
462*4b9c6d91SCole Faust ASSERT_GT(n, 0);
463*4b9c6d91SCole Faust EXPECT_EQ(std::string(buf, n), "Hi\n");
464*4b9c6d91SCole Faust
465*4b9c6d91SCole Faust n = read(err, buf, PIPE_BUF);
466*4b9c6d91SCole Faust ASSERT_GT(n, 0);
467*4b9c6d91SCole Faust EXPECT_EQ(std::string(buf, n), "There\n");
468*4b9c6d91SCole Faust
469*4b9c6d91SCole Faust // Check that the write ends of stdout and stderr pipes got closed by the
470*4b9c6d91SCole Faust // child process. If the child process kept other file descriptors connected
471*4b9c6d91SCole Faust // to stdout and stderr, then the parent process wouldn't be able to detect
472*4b9c6d91SCole Faust // that all write ends of these pipes are closed and it would block here.
473*4b9c6d91SCole Faust EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
474*4b9c6d91SCole Faust ASSERT_EQ(close(out), 0);
475*4b9c6d91SCole Faust EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
476*4b9c6d91SCole Faust ASSERT_EQ(close(err), 0);
477*4b9c6d91SCole Faust
478*4b9c6d91SCole Faust // Check that stdin pipe works.
479*4b9c6d91SCole Faust const std::string s = "Greetings\n";
480*4b9c6d91SCole Faust EXPECT_EQ(write(in, s.data(), s.size()), s.size());
481*4b9c6d91SCole Faust
482*4b9c6d91SCole Faust // Close write end of pipe connected to child's stdin. If there was another
483*4b9c6d91SCole Faust // file descriptor connected to this write end, then the child wouldn't be
484*4b9c6d91SCole Faust // able to detect that this write end is closed and it would block.
485*4b9c6d91SCole Faust ASSERT_EQ(close(in), 0);
486*4b9c6d91SCole Faust
487*4b9c6d91SCole Faust // Check that child process continued and ended.
488*4b9c6d91SCole Faust n = read(to_wait[0], buf, PIPE_BUF);
489*4b9c6d91SCole Faust ASSERT_GT(n, 0);
490*4b9c6d91SCole Faust EXPECT_EQ(std::string(buf, n), "Greetings and Goodbye\n");
491*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), 42);
492*4b9c6d91SCole Faust }
493*4b9c6d91SCole Faust
TEST(Test,minijail_no_clobber_pipe_fd)494*4b9c6d91SCole Faust TEST(Test, minijail_no_clobber_pipe_fd) {
495*4b9c6d91SCole Faust const ScopedMinijail j(minijail_new());
496*4b9c6d91SCole Faust char* const script = R"(
497*4b9c6d91SCole Faust echo Hi >&1;
498*4b9c6d91SCole Faust exec 1>&-;
499*4b9c6d91SCole Faust exec 4>&-;
500*4b9c6d91SCole Faust exec 7>&-;
501*4b9c6d91SCole Faust read line1;
502*4b9c6d91SCole Faust read line2;
503*4b9c6d91SCole Faust echo "$line1$line2 and Goodbye" >&2;
504*4b9c6d91SCole Faust exit 42;
505*4b9c6d91SCole Faust )";
506*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", script, nullptr};
507*4b9c6d91SCole Faust
508*4b9c6d91SCole Faust const int npipes = 3;
509*4b9c6d91SCole Faust int fds[npipes][2];
510*4b9c6d91SCole Faust
511*4b9c6d91SCole Faust // Create pipes.
512*4b9c6d91SCole Faust for (int i = 0; i < npipes; ++i) {
513*4b9c6d91SCole Faust ASSERT_EQ(pipe(fds[i]), 0);
514*4b9c6d91SCole Faust }
515*4b9c6d91SCole Faust
516*4b9c6d91SCole Faust // All pipes are output pipes except for the first one which is used as
517*4b9c6d91SCole Faust // input pipe.
518*4b9c6d91SCole Faust std::swap(fds[0][0], fds[0][1]);
519*4b9c6d91SCole Faust
520*4b9c6d91SCole Faust // Generate a lot of mappings to try to clobber any file descriptors generated
521*4b9c6d91SCole Faust // by libminijail.
522*4b9c6d91SCole Faust for (int offset = 0; offset < npipes * 3; offset += npipes) {
523*4b9c6d91SCole Faust for (int i = 0 ; i < npipes; ++i) {
524*4b9c6d91SCole Faust const int fd = fds[i][1];
525*4b9c6d91SCole Faust minijail_preserve_fd(j.get(), fd, i + offset);
526*4b9c6d91SCole Faust }
527*4b9c6d91SCole Faust }
528*4b9c6d91SCole Faust
529*4b9c6d91SCole Faust minijail_close_open_fds(j.get());
530*4b9c6d91SCole Faust
531*4b9c6d91SCole Faust EXPECT_EQ(minijail_run_no_preload(j.get(), kShellPath, argv), 0);
532*4b9c6d91SCole Faust
533*4b9c6d91SCole Faust // Close unused end of pipes.
534*4b9c6d91SCole Faust for (int i = 0; i < npipes; ++i) {
535*4b9c6d91SCole Faust const int fd = fds[i][1];
536*4b9c6d91SCole Faust ASSERT_EQ(close(fd), 0);
537*4b9c6d91SCole Faust }
538*4b9c6d91SCole Faust
539*4b9c6d91SCole Faust const int in = fds[0][0];
540*4b9c6d91SCole Faust const int out = fds[1][0];
541*4b9c6d91SCole Faust const int err = fds[2][0];
542*4b9c6d91SCole Faust
543*4b9c6d91SCole Faust char buf[PIPE_BUF];
544*4b9c6d91SCole Faust ssize_t nbytes;
545*4b9c6d91SCole Faust
546*4b9c6d91SCole Faust // Check that stdout pipe works.
547*4b9c6d91SCole Faust nbytes = read(out, buf, PIPE_BUF);
548*4b9c6d91SCole Faust ASSERT_GT(nbytes, 0);
549*4b9c6d91SCole Faust EXPECT_EQ(std::string(buf, nbytes), "Hi\n");
550*4b9c6d91SCole Faust
551*4b9c6d91SCole Faust // Check that the write end of stdout pipe got closed by the child process. If
552*4b9c6d91SCole Faust // the child process kept other file descriptors connected to stdout, then the
553*4b9c6d91SCole Faust // parent process wouldn't be able to detect that all write ends of this pipe
554*4b9c6d91SCole Faust // are closed and it would block here.
555*4b9c6d91SCole Faust EXPECT_EQ(read(out, buf, PIPE_BUF), 0);
556*4b9c6d91SCole Faust ASSERT_EQ(close(out), 0);
557*4b9c6d91SCole Faust
558*4b9c6d91SCole Faust // Check that stdin pipe works.
559*4b9c6d91SCole Faust const std::string s = "Greetings\n";
560*4b9c6d91SCole Faust EXPECT_EQ(write(in, s.data(), s.size()), s.size());
561*4b9c6d91SCole Faust
562*4b9c6d91SCole Faust // Close write end of pipe connected to child's stdin. If there was another
563*4b9c6d91SCole Faust // file descriptor connected to this write end, then the child process
564*4b9c6d91SCole Faust // wouldn't be able to detect that this write end is closed and it would
565*4b9c6d91SCole Faust // block.
566*4b9c6d91SCole Faust ASSERT_EQ(close(in), 0);
567*4b9c6d91SCole Faust
568*4b9c6d91SCole Faust // Check that child process continued and ended.
569*4b9c6d91SCole Faust nbytes = read(err, buf, PIPE_BUF);
570*4b9c6d91SCole Faust ASSERT_GT(nbytes, 0);
571*4b9c6d91SCole Faust EXPECT_EQ(std::string(buf, nbytes), "Greetings and Goodbye\n");
572*4b9c6d91SCole Faust
573*4b9c6d91SCole Faust // Check that the write end of the stderr pipe is closed when the child
574*4b9c6d91SCole Faust // process finishes.
575*4b9c6d91SCole Faust EXPECT_EQ(read(err, buf, PIPE_BUF), 0);
576*4b9c6d91SCole Faust ASSERT_EQ(close(err), 0);
577*4b9c6d91SCole Faust
578*4b9c6d91SCole Faust // Check the child process termination status.
579*4b9c6d91SCole Faust EXPECT_EQ(minijail_wait(j.get()), 42);
580*4b9c6d91SCole Faust }
581*4b9c6d91SCole Faust
TEST(Test,minijail_run_env_pid_pipes)582*4b9c6d91SCole Faust TEST(Test, minijail_run_env_pid_pipes) {
583*4b9c6d91SCole Faust // TODO(crbug.com/895875): The preload library interferes with ASan since they
584*4b9c6d91SCole Faust // both need to use LD_PRELOAD.
585*4b9c6d91SCole Faust if (running_with_asan())
586*4b9c6d91SCole Faust GTEST_SKIP();
587*4b9c6d91SCole Faust
588*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
589*4b9c6d91SCole Faust set_preload_path(j.get());
590*4b9c6d91SCole Faust
591*4b9c6d91SCole Faust char *argv[4];
592*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kCatPath);
593*4b9c6d91SCole Faust argv[1] = NULL;
594*4b9c6d91SCole Faust
595*4b9c6d91SCole Faust pid_t pid;
596*4b9c6d91SCole Faust int child_stdin, child_stdout;
597*4b9c6d91SCole Faust int mj_run_ret = minijail_run_pid_pipes(
598*4b9c6d91SCole Faust j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
599*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
600*4b9c6d91SCole Faust
601*4b9c6d91SCole Faust char teststr[] = "test\n";
602*4b9c6d91SCole Faust const size_t teststr_len = strlen(teststr);
603*4b9c6d91SCole Faust ssize_t write_ret = write(child_stdin, teststr, teststr_len);
604*4b9c6d91SCole Faust EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
605*4b9c6d91SCole Faust
606*4b9c6d91SCole Faust char buf[kBufferSize] = {};
607*4b9c6d91SCole Faust ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
608*4b9c6d91SCole Faust EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
609*4b9c6d91SCole Faust EXPECT_STREQ(buf, teststr);
610*4b9c6d91SCole Faust
611*4b9c6d91SCole Faust int status;
612*4b9c6d91SCole Faust EXPECT_EQ(kill(pid, SIGTERM), 0);
613*4b9c6d91SCole Faust EXPECT_EQ(waitpid(pid, &status, 0), pid);
614*4b9c6d91SCole Faust ASSERT_TRUE(WIFSIGNALED(status));
615*4b9c6d91SCole Faust EXPECT_EQ(WTERMSIG(status), SIGTERM);
616*4b9c6d91SCole Faust
617*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
618*4b9c6d91SCole Faust argv[1] = "-c";
619*4b9c6d91SCole Faust argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
620*4b9c6d91SCole Faust argv[3] = nullptr;
621*4b9c6d91SCole Faust
622*4b9c6d91SCole Faust char *envp[2];
623*4b9c6d91SCole Faust envp[0] = "TEST_VAR=test";
624*4b9c6d91SCole Faust envp[1] = NULL;
625*4b9c6d91SCole Faust
626*4b9c6d91SCole Faust // Set a canary env var in the parent that should not be present in the child.
627*4b9c6d91SCole Faust ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
628*4b9c6d91SCole Faust
629*4b9c6d91SCole Faust int child_stderr;
630*4b9c6d91SCole Faust mj_run_ret =
631*4b9c6d91SCole Faust minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
632*4b9c6d91SCole Faust &child_stdin, &child_stdout, &child_stderr);
633*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
634*4b9c6d91SCole Faust
635*4b9c6d91SCole Faust memset(buf, 0, sizeof(buf));
636*4b9c6d91SCole Faust read_ret = read(child_stderr, buf, sizeof(buf) - 1);
637*4b9c6d91SCole Faust EXPECT_GE(read_ret, 0);
638*4b9c6d91SCole Faust EXPECT_STREQ(buf, "|test\n");
639*4b9c6d91SCole Faust
640*4b9c6d91SCole Faust EXPECT_EQ(waitpid(pid, &status, 0), pid);
641*4b9c6d91SCole Faust ASSERT_TRUE(WIFEXITED(status));
642*4b9c6d91SCole Faust EXPECT_EQ(WEXITSTATUS(status), 0);
643*4b9c6d91SCole Faust }
644*4b9c6d91SCole Faust
TEST(Test,minijail_run_fd_env_pid_pipes)645*4b9c6d91SCole Faust TEST(Test, minijail_run_fd_env_pid_pipes) {
646*4b9c6d91SCole Faust // TODO(crbug.com/895875): The preload library interferes with ASan since they
647*4b9c6d91SCole Faust // both need to use LD_PRELOAD.
648*4b9c6d91SCole Faust if (running_with_asan())
649*4b9c6d91SCole Faust GTEST_SKIP();
650*4b9c6d91SCole Faust
651*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
652*4b9c6d91SCole Faust set_preload_path(j.get());
653*4b9c6d91SCole Faust
654*4b9c6d91SCole Faust char *argv[4];
655*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
656*4b9c6d91SCole Faust argv[1] = "-c";
657*4b9c6d91SCole Faust argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2\n";
658*4b9c6d91SCole Faust argv[3] = nullptr;
659*4b9c6d91SCole Faust
660*4b9c6d91SCole Faust char *envp[2];
661*4b9c6d91SCole Faust envp[0] = "TEST_VAR=test";
662*4b9c6d91SCole Faust envp[1] = nullptr;
663*4b9c6d91SCole Faust
664*4b9c6d91SCole Faust // Set a canary env var in the parent that should not be present in the child.
665*4b9c6d91SCole Faust ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
666*4b9c6d91SCole Faust
667*4b9c6d91SCole Faust int elf_fd = open(const_cast<char*>(kShellPath), O_RDONLY | O_CLOEXEC);
668*4b9c6d91SCole Faust ASSERT_NE(elf_fd, -1);
669*4b9c6d91SCole Faust
670*4b9c6d91SCole Faust int dev_null = open("/dev/null", O_RDONLY);
671*4b9c6d91SCole Faust ASSERT_NE(dev_null, -1);
672*4b9c6d91SCole Faust // Create a mapping to dev_null that would clobber elf_fd if it is not
673*4b9c6d91SCole Faust // relocated.
674*4b9c6d91SCole Faust minijail_preserve_fd(j.get(), dev_null, elf_fd);
675*4b9c6d91SCole Faust
676*4b9c6d91SCole Faust pid_t pid;
677*4b9c6d91SCole Faust int child_stdin, child_stdout, child_stderr;
678*4b9c6d91SCole Faust int mj_run_ret =
679*4b9c6d91SCole Faust minijail_run_fd_env_pid_pipes(j.get(), elf_fd, argv, envp, &pid,
680*4b9c6d91SCole Faust &child_stdin, &child_stdout, &child_stderr);
681*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
682*4b9c6d91SCole Faust close(dev_null);
683*4b9c6d91SCole Faust
684*4b9c6d91SCole Faust char buf[kBufferSize] = {};
685*4b9c6d91SCole Faust ssize_t read_ret = read(child_stderr, buf, sizeof(buf) - 1);
686*4b9c6d91SCole Faust EXPECT_GE(read_ret, 0);
687*4b9c6d91SCole Faust EXPECT_STREQ(buf, "|test\n");
688*4b9c6d91SCole Faust
689*4b9c6d91SCole Faust int status;
690*4b9c6d91SCole Faust EXPECT_EQ(waitpid(pid, &status, 0), pid);
691*4b9c6d91SCole Faust ASSERT_TRUE(WIFEXITED(status));
692*4b9c6d91SCole Faust EXPECT_EQ(WEXITSTATUS(status), 0);
693*4b9c6d91SCole Faust }
694*4b9c6d91SCole Faust
TEST(Test,minijail_run_env_pid_pipes_with_local_preload)695*4b9c6d91SCole Faust TEST(Test, minijail_run_env_pid_pipes_with_local_preload) {
696*4b9c6d91SCole Faust // TODO(crbug.com/895875): The preload library interferes with ASan since they
697*4b9c6d91SCole Faust // both need to use LD_PRELOAD.
698*4b9c6d91SCole Faust if (running_with_asan())
699*4b9c6d91SCole Faust GTEST_SKIP();
700*4b9c6d91SCole Faust
701*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
702*4b9c6d91SCole Faust
703*4b9c6d91SCole Faust char *argv[4];
704*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kCatPath);
705*4b9c6d91SCole Faust argv[1] = NULL;
706*4b9c6d91SCole Faust
707*4b9c6d91SCole Faust pid_t pid;
708*4b9c6d91SCole Faust int child_stdin, child_stdout;
709*4b9c6d91SCole Faust int mj_run_ret = minijail_run_pid_pipes(
710*4b9c6d91SCole Faust j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, NULL);
711*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
712*4b9c6d91SCole Faust
713*4b9c6d91SCole Faust char teststr[] = "test\n";
714*4b9c6d91SCole Faust const size_t teststr_len = strlen(teststr);
715*4b9c6d91SCole Faust ssize_t write_ret = write(child_stdin, teststr, teststr_len);
716*4b9c6d91SCole Faust EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
717*4b9c6d91SCole Faust
718*4b9c6d91SCole Faust char buf[kBufferSize] = {};
719*4b9c6d91SCole Faust ssize_t read_ret = read(child_stdout, buf, sizeof(buf) - 1);
720*4b9c6d91SCole Faust EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
721*4b9c6d91SCole Faust EXPECT_STREQ(buf, teststr);
722*4b9c6d91SCole Faust
723*4b9c6d91SCole Faust int status;
724*4b9c6d91SCole Faust EXPECT_EQ(kill(pid, SIGTERM), 0);
725*4b9c6d91SCole Faust EXPECT_EQ(waitpid(pid, &status, 0), pid);
726*4b9c6d91SCole Faust ASSERT_TRUE(WIFSIGNALED(status));
727*4b9c6d91SCole Faust EXPECT_EQ(WTERMSIG(status), SIGTERM);
728*4b9c6d91SCole Faust
729*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
730*4b9c6d91SCole Faust argv[1] = "-c";
731*4b9c6d91SCole Faust argv[2] = "echo \"${TEST_PARENT+set}|${TEST_VAR}\" >&2";
732*4b9c6d91SCole Faust argv[3] = nullptr;
733*4b9c6d91SCole Faust
734*4b9c6d91SCole Faust char *envp[2];
735*4b9c6d91SCole Faust envp[0] = "TEST_VAR=test";
736*4b9c6d91SCole Faust envp[1] = NULL;
737*4b9c6d91SCole Faust
738*4b9c6d91SCole Faust // Set a canary env var in the parent that should not be present in the child.
739*4b9c6d91SCole Faust ASSERT_EQ(setenv("TEST_PARENT", "test", 1 /*overwrite*/), 0);
740*4b9c6d91SCole Faust
741*4b9c6d91SCole Faust // Use the preload library from this test build.
742*4b9c6d91SCole Faust set_preload_path(j.get());
743*4b9c6d91SCole Faust
744*4b9c6d91SCole Faust int child_stderr;
745*4b9c6d91SCole Faust mj_run_ret =
746*4b9c6d91SCole Faust minijail_run_env_pid_pipes(j.get(), argv[0], argv, envp, &pid,
747*4b9c6d91SCole Faust &child_stdin, &child_stdout, &child_stderr);
748*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
749*4b9c6d91SCole Faust
750*4b9c6d91SCole Faust memset(buf, 0, sizeof(buf));
751*4b9c6d91SCole Faust read_ret = read(child_stderr, buf, sizeof(buf) - 1);
752*4b9c6d91SCole Faust EXPECT_GE(read_ret, 0);
753*4b9c6d91SCole Faust EXPECT_STREQ(buf, "|test\n");
754*4b9c6d91SCole Faust
755*4b9c6d91SCole Faust EXPECT_EQ(waitpid(pid, &status, 0), pid);
756*4b9c6d91SCole Faust ASSERT_TRUE(WIFEXITED(status));
757*4b9c6d91SCole Faust EXPECT_EQ(WEXITSTATUS(status), 0);
758*4b9c6d91SCole Faust }
759*4b9c6d91SCole Faust
TEST(Test,test_minijail_no_clobber_fds)760*4b9c6d91SCole Faust TEST(Test, test_minijail_no_clobber_fds) {
761*4b9c6d91SCole Faust int dev_null = open("/dev/null", O_RDONLY);
762*4b9c6d91SCole Faust ASSERT_NE(dev_null, -1);
763*4b9c6d91SCole Faust
764*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
765*4b9c6d91SCole Faust
766*4b9c6d91SCole Faust // Keep stderr.
767*4b9c6d91SCole Faust minijail_preserve_fd(j.get(), 2, 2);
768*4b9c6d91SCole Faust // Create a lot of mappings to dev_null to possibly clobber libminijail.c fds.
769*4b9c6d91SCole Faust for (int i = 3; i < 15; ++i) {
770*4b9c6d91SCole Faust minijail_preserve_fd(j.get(), dev_null, i);
771*4b9c6d91SCole Faust }
772*4b9c6d91SCole Faust
773*4b9c6d91SCole Faust char *argv[4];
774*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
775*4b9c6d91SCole Faust argv[1] = "-c";
776*4b9c6d91SCole Faust argv[2] = "echo Hello; read line1; echo \"${line1}\" >&2";
777*4b9c6d91SCole Faust argv[3] = nullptr;
778*4b9c6d91SCole Faust
779*4b9c6d91SCole Faust pid_t pid;
780*4b9c6d91SCole Faust int child_stdin;
781*4b9c6d91SCole Faust int child_stdout;
782*4b9c6d91SCole Faust int child_stderr;
783*4b9c6d91SCole Faust int mj_run_ret = minijail_run_pid_pipes_no_preload(
784*4b9c6d91SCole Faust j.get(), argv[0], argv, &pid, &child_stdin, &child_stdout, &child_stderr);
785*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
786*4b9c6d91SCole Faust
787*4b9c6d91SCole Faust char buf[kBufferSize];
788*4b9c6d91SCole Faust ssize_t read_ret = read(child_stdout, buf, sizeof(buf));
789*4b9c6d91SCole Faust EXPECT_GE(read_ret, 0);
790*4b9c6d91SCole Faust buf[read_ret] = '\0';
791*4b9c6d91SCole Faust EXPECT_STREQ(buf, "Hello\n");
792*4b9c6d91SCole Faust
793*4b9c6d91SCole Faust constexpr char to_write[] = "test in and err\n";
794*4b9c6d91SCole Faust ssize_t write_ret = write(child_stdin, to_write, sizeof(to_write));
795*4b9c6d91SCole Faust EXPECT_EQ(write_ret, sizeof(to_write));
796*4b9c6d91SCole Faust
797*4b9c6d91SCole Faust read_ret = read(child_stderr, buf, sizeof(buf));
798*4b9c6d91SCole Faust EXPECT_GE(read_ret, 0);
799*4b9c6d91SCole Faust buf[read_ret] = '\0';
800*4b9c6d91SCole Faust EXPECT_STREQ(buf, to_write);
801*4b9c6d91SCole Faust
802*4b9c6d91SCole Faust int status;
803*4b9c6d91SCole Faust waitpid(pid, &status, 0);
804*4b9c6d91SCole Faust ASSERT_TRUE(WIFEXITED(status));
805*4b9c6d91SCole Faust EXPECT_EQ(WEXITSTATUS(status), 0);
806*4b9c6d91SCole Faust
807*4b9c6d91SCole Faust close(dev_null);
808*4b9c6d91SCole Faust }
809*4b9c6d91SCole Faust
TEST(Test,test_minijail_no_fd_leaks)810*4b9c6d91SCole Faust TEST(Test, test_minijail_no_fd_leaks) {
811*4b9c6d91SCole Faust pid_t pid;
812*4b9c6d91SCole Faust int child_stdout;
813*4b9c6d91SCole Faust int mj_run_ret;
814*4b9c6d91SCole Faust ssize_t read_ret;
815*4b9c6d91SCole Faust char buf[kBufferSize];
816*4b9c6d91SCole Faust char script[kBufferSize];
817*4b9c6d91SCole Faust int status;
818*4b9c6d91SCole Faust char *argv[4];
819*4b9c6d91SCole Faust
820*4b9c6d91SCole Faust int dev_null = open("/dev/null", O_RDONLY);
821*4b9c6d91SCole Faust ASSERT_NE(dev_null, -1);
822*4b9c6d91SCole Faust snprintf(script,
823*4b9c6d91SCole Faust sizeof(script),
824*4b9c6d91SCole Faust "[ -e /proc/self/fd/%d ] && echo yes || echo no",
825*4b9c6d91SCole Faust dev_null);
826*4b9c6d91SCole Faust
827*4b9c6d91SCole Faust struct minijail *j = minijail_new();
828*4b9c6d91SCole Faust
829*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
830*4b9c6d91SCole Faust argv[1] = "-c";
831*4b9c6d91SCole Faust argv[2] = script;
832*4b9c6d91SCole Faust argv[3] = NULL;
833*4b9c6d91SCole Faust mj_run_ret = minijail_run_pid_pipes_no_preload(
834*4b9c6d91SCole Faust j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
835*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
836*4b9c6d91SCole Faust
837*4b9c6d91SCole Faust read_ret = read(child_stdout, buf, sizeof(buf));
838*4b9c6d91SCole Faust EXPECT_GE(read_ret, 0);
839*4b9c6d91SCole Faust buf[read_ret] = '\0';
840*4b9c6d91SCole Faust EXPECT_STREQ(buf, "yes\n");
841*4b9c6d91SCole Faust
842*4b9c6d91SCole Faust waitpid(pid, &status, 0);
843*4b9c6d91SCole Faust ASSERT_TRUE(WIFEXITED(status));
844*4b9c6d91SCole Faust EXPECT_EQ(WEXITSTATUS(status), 0);
845*4b9c6d91SCole Faust
846*4b9c6d91SCole Faust minijail_close_open_fds(j);
847*4b9c6d91SCole Faust mj_run_ret = minijail_run_pid_pipes_no_preload(
848*4b9c6d91SCole Faust j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
849*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
850*4b9c6d91SCole Faust
851*4b9c6d91SCole Faust read_ret = read(child_stdout, buf, sizeof(buf));
852*4b9c6d91SCole Faust EXPECT_GE(read_ret, 0);
853*4b9c6d91SCole Faust buf[read_ret] = '\0';
854*4b9c6d91SCole Faust EXPECT_STREQ(buf, "no\n");
855*4b9c6d91SCole Faust
856*4b9c6d91SCole Faust waitpid(pid, &status, 0);
857*4b9c6d91SCole Faust ASSERT_TRUE(WIFEXITED(status));
858*4b9c6d91SCole Faust EXPECT_EQ(WEXITSTATUS(status), 0);
859*4b9c6d91SCole Faust
860*4b9c6d91SCole Faust minijail_destroy(j);
861*4b9c6d91SCole Faust
862*4b9c6d91SCole Faust close(dev_null);
863*4b9c6d91SCole Faust }
864*4b9c6d91SCole Faust
TEST(Test,test_minijail_fork)865*4b9c6d91SCole Faust TEST(Test, test_minijail_fork) {
866*4b9c6d91SCole Faust pid_t mj_fork_ret;
867*4b9c6d91SCole Faust int status;
868*4b9c6d91SCole Faust int pipe_fds[2];
869*4b9c6d91SCole Faust ssize_t pid_size = sizeof(mj_fork_ret);
870*4b9c6d91SCole Faust
871*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
872*4b9c6d91SCole Faust
873*4b9c6d91SCole Faust ASSERT_EQ(pipe(pipe_fds), 0);
874*4b9c6d91SCole Faust
875*4b9c6d91SCole Faust mj_fork_ret = minijail_fork(j.get());
876*4b9c6d91SCole Faust ASSERT_GE(mj_fork_ret, 0);
877*4b9c6d91SCole Faust if (mj_fork_ret == 0) {
878*4b9c6d91SCole Faust pid_t pid_in_parent;
879*4b9c6d91SCole Faust // Wait for the parent to tell us the pid in the parent namespace.
880*4b9c6d91SCole Faust ASSERT_EQ(read(pipe_fds[0], &pid_in_parent, pid_size), pid_size);
881*4b9c6d91SCole Faust ASSERT_EQ(pid_in_parent, getpid());
882*4b9c6d91SCole Faust exit(0);
883*4b9c6d91SCole Faust }
884*4b9c6d91SCole Faust
885*4b9c6d91SCole Faust EXPECT_EQ(write(pipe_fds[1], &mj_fork_ret, pid_size), pid_size);
886*4b9c6d91SCole Faust waitpid(mj_fork_ret, &status, 0);
887*4b9c6d91SCole Faust ASSERT_TRUE(WIFEXITED(status));
888*4b9c6d91SCole Faust EXPECT_EQ(WEXITSTATUS(status), 0);
889*4b9c6d91SCole Faust }
890*4b9c6d91SCole Faust
early_exit(void * payload)891*4b9c6d91SCole Faust static int early_exit(void* payload) {
892*4b9c6d91SCole Faust exit(static_cast<int>(reinterpret_cast<intptr_t>(payload)));
893*4b9c6d91SCole Faust }
894*4b9c6d91SCole Faust
TEST(Test,test_minijail_callback)895*4b9c6d91SCole Faust TEST(Test, test_minijail_callback) {
896*4b9c6d91SCole Faust pid_t pid;
897*4b9c6d91SCole Faust int mj_run_ret;
898*4b9c6d91SCole Faust int status;
899*4b9c6d91SCole Faust char *argv[2];
900*4b9c6d91SCole Faust int exit_code = 42;
901*4b9c6d91SCole Faust
902*4b9c6d91SCole Faust struct minijail *j = minijail_new();
903*4b9c6d91SCole Faust
904*4b9c6d91SCole Faust status =
905*4b9c6d91SCole Faust minijail_add_hook(j, &early_exit, reinterpret_cast<void *>(exit_code),
906*4b9c6d91SCole Faust MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS);
907*4b9c6d91SCole Faust EXPECT_EQ(status, 0);
908*4b9c6d91SCole Faust
909*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kCatPath);
910*4b9c6d91SCole Faust argv[1] = NULL;
911*4b9c6d91SCole Faust mj_run_ret = minijail_run_pid_pipes_no_preload(j, argv[0], argv, &pid, NULL,
912*4b9c6d91SCole Faust NULL, NULL);
913*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
914*4b9c6d91SCole Faust
915*4b9c6d91SCole Faust status = minijail_wait(j);
916*4b9c6d91SCole Faust EXPECT_EQ(status, exit_code);
917*4b9c6d91SCole Faust
918*4b9c6d91SCole Faust minijail_destroy(j);
919*4b9c6d91SCole Faust }
920*4b9c6d91SCole Faust
TEST(Test,test_minijail_preserve_fd)921*4b9c6d91SCole Faust TEST(Test, test_minijail_preserve_fd) {
922*4b9c6d91SCole Faust int mj_run_ret;
923*4b9c6d91SCole Faust int status;
924*4b9c6d91SCole Faust char *argv[2];
925*4b9c6d91SCole Faust char teststr[] = "test\n";
926*4b9c6d91SCole Faust size_t teststr_len = strlen(teststr);
927*4b9c6d91SCole Faust int read_pipe[2];
928*4b9c6d91SCole Faust int write_pipe[2];
929*4b9c6d91SCole Faust char buf[1024];
930*4b9c6d91SCole Faust
931*4b9c6d91SCole Faust struct minijail *j = minijail_new();
932*4b9c6d91SCole Faust
933*4b9c6d91SCole Faust status = pipe(read_pipe);
934*4b9c6d91SCole Faust ASSERT_EQ(status, 0);
935*4b9c6d91SCole Faust status = pipe(write_pipe);
936*4b9c6d91SCole Faust ASSERT_EQ(status, 0);
937*4b9c6d91SCole Faust
938*4b9c6d91SCole Faust status = minijail_preserve_fd(j, write_pipe[0], STDIN_FILENO);
939*4b9c6d91SCole Faust ASSERT_EQ(status, 0);
940*4b9c6d91SCole Faust status = minijail_preserve_fd(j, read_pipe[1], STDOUT_FILENO);
941*4b9c6d91SCole Faust ASSERT_EQ(status, 0);
942*4b9c6d91SCole Faust minijail_close_open_fds(j);
943*4b9c6d91SCole Faust
944*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kCatPath);
945*4b9c6d91SCole Faust argv[1] = NULL;
946*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
947*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
948*4b9c6d91SCole Faust
949*4b9c6d91SCole Faust close(write_pipe[0]);
950*4b9c6d91SCole Faust status = write(write_pipe[1], teststr, teststr_len);
951*4b9c6d91SCole Faust EXPECT_EQ(status, (int)teststr_len);
952*4b9c6d91SCole Faust close(write_pipe[1]);
953*4b9c6d91SCole Faust
954*4b9c6d91SCole Faust close(read_pipe[1]);
955*4b9c6d91SCole Faust status = read(read_pipe[0], buf, 8);
956*4b9c6d91SCole Faust EXPECT_EQ(status, (int)teststr_len);
957*4b9c6d91SCole Faust buf[teststr_len] = 0;
958*4b9c6d91SCole Faust EXPECT_STREQ(buf, teststr);
959*4b9c6d91SCole Faust
960*4b9c6d91SCole Faust status = minijail_wait(j);
961*4b9c6d91SCole Faust EXPECT_EQ(status, 0);
962*4b9c6d91SCole Faust
963*4b9c6d91SCole Faust minijail_destroy(j);
964*4b9c6d91SCole Faust }
965*4b9c6d91SCole Faust
TEST(Test,test_minijail_reset_signal_mask)966*4b9c6d91SCole Faust TEST(Test, test_minijail_reset_signal_mask) {
967*4b9c6d91SCole Faust struct minijail *j = minijail_new();
968*4b9c6d91SCole Faust
969*4b9c6d91SCole Faust sigset_t original_signal_mask;
970*4b9c6d91SCole Faust {
971*4b9c6d91SCole Faust sigset_t signal_mask;
972*4b9c6d91SCole Faust ASSERT_EQ(0, sigemptyset(&signal_mask));
973*4b9c6d91SCole Faust ASSERT_EQ(0, sigaddset(&signal_mask, SIGUSR1));
974*4b9c6d91SCole Faust ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &signal_mask, &original_signal_mask));
975*4b9c6d91SCole Faust }
976*4b9c6d91SCole Faust
977*4b9c6d91SCole Faust minijail_reset_signal_mask(j);
978*4b9c6d91SCole Faust
979*4b9c6d91SCole Faust pid_t mj_fork_ret = minijail_fork(j);
980*4b9c6d91SCole Faust ASSERT_GE(mj_fork_ret, 0);
981*4b9c6d91SCole Faust if (mj_fork_ret == 0) {
982*4b9c6d91SCole Faust sigset_t signal_mask;
983*4b9c6d91SCole Faust ASSERT_EQ(0, sigprocmask(SIG_SETMASK, NULL, &signal_mask));
984*4b9c6d91SCole Faust ASSERT_EQ(0, sigismember(&signal_mask, SIGUSR1));
985*4b9c6d91SCole Faust minijail_destroy(j);
986*4b9c6d91SCole Faust exit(0);
987*4b9c6d91SCole Faust }
988*4b9c6d91SCole Faust
989*4b9c6d91SCole Faust ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_signal_mask, NULL));
990*4b9c6d91SCole Faust
991*4b9c6d91SCole Faust int status;
992*4b9c6d91SCole Faust waitpid(mj_fork_ret, &status, 0);
993*4b9c6d91SCole Faust ASSERT_TRUE(WIFEXITED(status));
994*4b9c6d91SCole Faust EXPECT_EQ(WEXITSTATUS(status), 0);
995*4b9c6d91SCole Faust
996*4b9c6d91SCole Faust minijail_destroy(j);
997*4b9c6d91SCole Faust }
998*4b9c6d91SCole Faust
TEST(Test,test_minijail_reset_signal_handlers)999*4b9c6d91SCole Faust TEST(Test, test_minijail_reset_signal_handlers) {
1000*4b9c6d91SCole Faust struct minijail *j = minijail_new();
1001*4b9c6d91SCole Faust
1002*4b9c6d91SCole Faust ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
1003*4b9c6d91SCole Faust ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_IGN));
1004*4b9c6d91SCole Faust ASSERT_EQ(SIG_IGN, signal(SIGUSR1, SIG_IGN));
1005*4b9c6d91SCole Faust
1006*4b9c6d91SCole Faust minijail_reset_signal_handlers(j);
1007*4b9c6d91SCole Faust
1008*4b9c6d91SCole Faust pid_t mj_fork_ret = minijail_fork(j);
1009*4b9c6d91SCole Faust ASSERT_GE(mj_fork_ret, 0);
1010*4b9c6d91SCole Faust if (mj_fork_ret == 0) {
1011*4b9c6d91SCole Faust ASSERT_EQ(SIG_DFL, signal(SIGUSR1, SIG_DFL));
1012*4b9c6d91SCole Faust minijail_destroy(j);
1013*4b9c6d91SCole Faust exit(0);
1014*4b9c6d91SCole Faust }
1015*4b9c6d91SCole Faust
1016*4b9c6d91SCole Faust ASSERT_NE(SIG_ERR, signal(SIGUSR1, SIG_DFL));
1017*4b9c6d91SCole Faust
1018*4b9c6d91SCole Faust int status;
1019*4b9c6d91SCole Faust waitpid(mj_fork_ret, &status, 0);
1020*4b9c6d91SCole Faust ASSERT_TRUE(WIFEXITED(status));
1021*4b9c6d91SCole Faust EXPECT_EQ(WEXITSTATUS(status), 0);
1022*4b9c6d91SCole Faust
1023*4b9c6d91SCole Faust minijail_destroy(j);
1024*4b9c6d91SCole Faust }
1025*4b9c6d91SCole Faust
1026*4b9c6d91SCole Faust // Test that bind mounting onto a non-existing location works.
TEST(Test,test_bind_mount_nonexistent_dest)1027*4b9c6d91SCole Faust TEST(Test, test_bind_mount_nonexistent_dest) {
1028*4b9c6d91SCole Faust TemporaryDir dir;
1029*4b9c6d91SCole Faust ASSERT_TRUE(dir.is_valid());
1030*4b9c6d91SCole Faust
1031*4b9c6d91SCole Faust // minijail_bind() expects absolute paths, but TemporaryDir::path can return
1032*4b9c6d91SCole Faust // relative paths on Linux.
1033*4b9c6d91SCole Faust std::string path = dir.path;
1034*4b9c6d91SCole Faust if (!is_android()) {
1035*4b9c6d91SCole Faust std::string cwd(getcwd(NULL, 0));
1036*4b9c6d91SCole Faust path = cwd + "/" + path;
1037*4b9c6d91SCole Faust }
1038*4b9c6d91SCole Faust
1039*4b9c6d91SCole Faust std::string path_src = path + "/src";
1040*4b9c6d91SCole Faust std::string path_dest = path + "/dest";
1041*4b9c6d91SCole Faust
1042*4b9c6d91SCole Faust EXPECT_EQ(mkdir(path_src.c_str(), 0700), 0);
1043*4b9c6d91SCole Faust
1044*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1045*4b9c6d91SCole Faust int bind_res = minijail_bind(j.get(), path_src.c_str(), path_dest.c_str(),
1046*4b9c6d91SCole Faust 0 /*writable*/);
1047*4b9c6d91SCole Faust EXPECT_EQ(bind_res, 0);
1048*4b9c6d91SCole Faust }
1049*4b9c6d91SCole Faust
1050*4b9c6d91SCole Faust // Test that bind mounting with a symlink behaves according to build-time
1051*4b9c6d91SCole Faust // configuration.
TEST(Test,test_bind_mount_symlink)1052*4b9c6d91SCole Faust TEST(Test, test_bind_mount_symlink) {
1053*4b9c6d91SCole Faust TemporaryDir dir;
1054*4b9c6d91SCole Faust ASSERT_TRUE(dir.is_valid());
1055*4b9c6d91SCole Faust
1056*4b9c6d91SCole Faust // minijail_bind() expects absolute paths, but TemporaryDir::path can return
1057*4b9c6d91SCole Faust // relative paths on Linux.
1058*4b9c6d91SCole Faust std::string path = dir.path;
1059*4b9c6d91SCole Faust if (!is_android()) {
1060*4b9c6d91SCole Faust std::string cwd(getcwd(NULL, 0));
1061*4b9c6d91SCole Faust path = cwd + "/" + path;
1062*4b9c6d91SCole Faust }
1063*4b9c6d91SCole Faust
1064*4b9c6d91SCole Faust std::string path_src = path + "/src";
1065*4b9c6d91SCole Faust std::string path_dest = path + "/dest";
1066*4b9c6d91SCole Faust std::string path_sym = path + "/symlink";
1067*4b9c6d91SCole Faust
1068*4b9c6d91SCole Faust EXPECT_EQ(mkdir(path_src.c_str(), 0700), 0);
1069*4b9c6d91SCole Faust EXPECT_EQ(mkdir(path_dest.c_str(), 0700), 0);
1070*4b9c6d91SCole Faust EXPECT_EQ(symlink(path_src.c_str(), path_sym.c_str()), 0);
1071*4b9c6d91SCole Faust
1072*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1073*4b9c6d91SCole Faust int bind_res = minijail_bind(j.get(), path_sym.c_str(), path_dest.c_str(),
1074*4b9c6d91SCole Faust 0 /*writable*/);
1075*4b9c6d91SCole Faust if (block_symlinks_in_bindmount_paths()) {
1076*4b9c6d91SCole Faust EXPECT_NE(bind_res, 0);
1077*4b9c6d91SCole Faust } else {
1078*4b9c6d91SCole Faust EXPECT_EQ(bind_res, 0);
1079*4b9c6d91SCole Faust }
1080*4b9c6d91SCole Faust EXPECT_EQ(unlink(path_sym.c_str()), 0);
1081*4b9c6d91SCole Faust }
1082*4b9c6d91SCole Faust
1083*4b9c6d91SCole Faust namespace {
1084*4b9c6d91SCole Faust
1085*4b9c6d91SCole Faust // Tests that require userns access.
1086*4b9c6d91SCole Faust // Android unit tests don't currently support entering user namespaces as
1087*4b9c6d91SCole Faust // unprivileged users due to having an older kernel. ChromeOS unit tests
1088*4b9c6d91SCole Faust // don't support it either due to being in a chroot environment (see man 2
1089*4b9c6d91SCole Faust // clone for more information about failure modes with the CLONE_NEWUSER flag).
1090*4b9c6d91SCole Faust class NamespaceTest : public ::testing::Test {
1091*4b9c6d91SCole Faust protected:
SetUpTestCase()1092*4b9c6d91SCole Faust static void SetUpTestCase() {
1093*4b9c6d91SCole Faust userns_supported_ = UsernsSupported();
1094*4b9c6d91SCole Faust }
1095*4b9c6d91SCole Faust
1096*4b9c6d91SCole Faust // Whether userns is supported.
1097*4b9c6d91SCole Faust static bool userns_supported_;
1098*4b9c6d91SCole Faust
UsernsSupported()1099*4b9c6d91SCole Faust static bool UsernsSupported() {
1100*4b9c6d91SCole Faust pid_t pid = fork();
1101*4b9c6d91SCole Faust if (pid == -1)
1102*4b9c6d91SCole Faust pdie("could not fork");
1103*4b9c6d91SCole Faust
1104*4b9c6d91SCole Faust if (pid == 0)
1105*4b9c6d91SCole Faust _exit(unshare(CLONE_NEWUSER) == 0 ? 0 : 1);
1106*4b9c6d91SCole Faust
1107*4b9c6d91SCole Faust int status;
1108*4b9c6d91SCole Faust if (waitpid(pid, &status, 0) < 0)
1109*4b9c6d91SCole Faust pdie("could not wait");
1110*4b9c6d91SCole Faust
1111*4b9c6d91SCole Faust if (!WIFEXITED(status))
1112*4b9c6d91SCole Faust die("child did not exit properly: %#x", status);
1113*4b9c6d91SCole Faust
1114*4b9c6d91SCole Faust bool ret = WEXITSTATUS(status) == 0;
1115*4b9c6d91SCole Faust if (!ret)
1116*4b9c6d91SCole Faust warn("Skipping userns related tests");
1117*4b9c6d91SCole Faust return ret;
1118*4b9c6d91SCole Faust }
1119*4b9c6d91SCole Faust };
1120*4b9c6d91SCole Faust
1121*4b9c6d91SCole Faust bool NamespaceTest::userns_supported_;
1122*4b9c6d91SCole Faust
1123*4b9c6d91SCole Faust } // namespace
1124*4b9c6d91SCole Faust
TEST_F(NamespaceTest,test_tmpfs_userns)1125*4b9c6d91SCole Faust TEST_F(NamespaceTest, test_tmpfs_userns) {
1126*4b9c6d91SCole Faust int mj_run_ret;
1127*4b9c6d91SCole Faust int status;
1128*4b9c6d91SCole Faust char *argv[4];
1129*4b9c6d91SCole Faust char uidmap[kBufferSize], gidmap[kBufferSize];
1130*4b9c6d91SCole Faust constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1131*4b9c6d91SCole Faust constexpr gid_t kTargetGid = 1000;
1132*4b9c6d91SCole Faust
1133*4b9c6d91SCole Faust if (!userns_supported_)
1134*4b9c6d91SCole Faust GTEST_SKIP();
1135*4b9c6d91SCole Faust
1136*4b9c6d91SCole Faust struct minijail *j = minijail_new();
1137*4b9c6d91SCole Faust
1138*4b9c6d91SCole Faust minijail_namespace_pids(j);
1139*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1140*4b9c6d91SCole Faust minijail_mount_tmp(j);
1141*4b9c6d91SCole Faust minijail_run_as_init(j);
1142*4b9c6d91SCole Faust
1143*4b9c6d91SCole Faust // Perform userns mapping.
1144*4b9c6d91SCole Faust minijail_namespace_user(j);
1145*4b9c6d91SCole Faust snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1146*4b9c6d91SCole Faust snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1147*4b9c6d91SCole Faust minijail_change_uid(j, kTargetUid);
1148*4b9c6d91SCole Faust minijail_change_gid(j, kTargetGid);
1149*4b9c6d91SCole Faust minijail_uidmap(j, uidmap);
1150*4b9c6d91SCole Faust minijail_gidmap(j, gidmap);
1151*4b9c6d91SCole Faust minijail_namespace_user_disable_setgroups(j);
1152*4b9c6d91SCole Faust
1153*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
1154*4b9c6d91SCole Faust argv[1] = "-c";
1155*4b9c6d91SCole Faust argv[2] = "exec touch /tmp/foo";
1156*4b9c6d91SCole Faust argv[3] = NULL;
1157*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j, argv[0], argv);
1158*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1159*4b9c6d91SCole Faust
1160*4b9c6d91SCole Faust status = minijail_wait(j);
1161*4b9c6d91SCole Faust EXPECT_EQ(status, 0);
1162*4b9c6d91SCole Faust
1163*4b9c6d91SCole Faust minijail_destroy(j);
1164*4b9c6d91SCole Faust }
1165*4b9c6d91SCole Faust
TEST_F(NamespaceTest,test_namespaces)1166*4b9c6d91SCole Faust TEST_F(NamespaceTest, test_namespaces) {
1167*4b9c6d91SCole Faust constexpr char teststr[] = "test\n";
1168*4b9c6d91SCole Faust
1169*4b9c6d91SCole Faust // TODO(crbug.com/895875): The preload library interferes with ASan since they
1170*4b9c6d91SCole Faust // both need to use LD_PRELOAD.
1171*4b9c6d91SCole Faust if (!userns_supported_ || running_with_asan())
1172*4b9c6d91SCole Faust GTEST_SKIP();
1173*4b9c6d91SCole Faust
1174*4b9c6d91SCole Faust std::string uidmap = "0 " + std::to_string(getuid()) + " 1";
1175*4b9c6d91SCole Faust std::string gidmap = "0 " + std::to_string(getgid()) + " 1";
1176*4b9c6d91SCole Faust
1177*4b9c6d91SCole Faust const std::vector<std::string> namespace_names = {"pid", "mnt", "user",
1178*4b9c6d91SCole Faust "net", "cgroup", "uts"};
1179*4b9c6d91SCole Faust // Grab the set of namespaces outside the container.
1180*4b9c6d91SCole Faust std::map<std::string, std::string> init_namespaces =
1181*4b9c6d91SCole Faust GetNamespaces(getpid(), namespace_names);
1182*4b9c6d91SCole Faust std::function<void(struct minijail*)> test_functions[] = {
1183*4b9c6d91SCole Faust [](struct minijail* j attribute_unused) {},
1184*4b9c6d91SCole Faust [](struct minijail* j) {
1185*4b9c6d91SCole Faust minijail_mount(j, "/", "/", "", MS_BIND | MS_REC | MS_RDONLY);
1186*4b9c6d91SCole Faust minijail_enter_pivot_root(j, "/tmp");
1187*4b9c6d91SCole Faust },
1188*4b9c6d91SCole Faust [](struct minijail* j) { minijail_enter_chroot(j, "/"); },
1189*4b9c6d91SCole Faust };
1190*4b9c6d91SCole Faust
1191*4b9c6d91SCole Faust // This test is run with and without the preload library.
1192*4b9c6d91SCole Faust for (const auto& run_function :
1193*4b9c6d91SCole Faust {minijail_run_pid_pipes, minijail_run_pid_pipes_no_preload}) {
1194*4b9c6d91SCole Faust for (const auto& test_function : test_functions) {
1195*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1196*4b9c6d91SCole Faust set_preload_path(j.get());
1197*4b9c6d91SCole Faust
1198*4b9c6d91SCole Faust // Enter all the namespaces we can.
1199*4b9c6d91SCole Faust minijail_namespace_cgroups(j.get());
1200*4b9c6d91SCole Faust minijail_namespace_net(j.get());
1201*4b9c6d91SCole Faust minijail_namespace_pids(j.get());
1202*4b9c6d91SCole Faust minijail_namespace_user(j.get());
1203*4b9c6d91SCole Faust minijail_namespace_vfs(j.get());
1204*4b9c6d91SCole Faust minijail_namespace_uts(j.get());
1205*4b9c6d91SCole Faust
1206*4b9c6d91SCole Faust // Set up the user namespace.
1207*4b9c6d91SCole Faust minijail_uidmap(j.get(), uidmap.c_str());
1208*4b9c6d91SCole Faust minijail_gidmap(j.get(), gidmap.c_str());
1209*4b9c6d91SCole Faust minijail_namespace_user_disable_setgroups(j.get());
1210*4b9c6d91SCole Faust
1211*4b9c6d91SCole Faust minijail_close_open_fds(j.get());
1212*4b9c6d91SCole Faust test_function(j.get());
1213*4b9c6d91SCole Faust
1214*4b9c6d91SCole Faust char* const argv[] = {const_cast<char*>(kCatPath), nullptr};
1215*4b9c6d91SCole Faust pid_t container_pid;
1216*4b9c6d91SCole Faust int child_stdin, child_stdout;
1217*4b9c6d91SCole Faust int mj_run_ret =
1218*4b9c6d91SCole Faust run_function(j.get(), argv[0], argv,
1219*4b9c6d91SCole Faust &container_pid, &child_stdin, &child_stdout, nullptr);
1220*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1221*4b9c6d91SCole Faust
1222*4b9c6d91SCole Faust // Send some data to stdin and read it back to ensure that the child
1223*4b9c6d91SCole Faust // process is running.
1224*4b9c6d91SCole Faust const size_t teststr_len = strlen(teststr);
1225*4b9c6d91SCole Faust ssize_t write_ret = write(child_stdin, teststr, teststr_len);
1226*4b9c6d91SCole Faust EXPECT_EQ(write_ret, static_cast<ssize_t>(teststr_len));
1227*4b9c6d91SCole Faust
1228*4b9c6d91SCole Faust char buf[kBufferSize];
1229*4b9c6d91SCole Faust ssize_t read_ret = read(child_stdout, buf, 8);
1230*4b9c6d91SCole Faust EXPECT_EQ(read_ret, static_cast<ssize_t>(teststr_len));
1231*4b9c6d91SCole Faust buf[teststr_len] = 0;
1232*4b9c6d91SCole Faust EXPECT_STREQ(buf, teststr);
1233*4b9c6d91SCole Faust
1234*4b9c6d91SCole Faust // Grab the set of namespaces in every container process. They must not
1235*4b9c6d91SCole Faust // match the ones in the init namespace, and they must all match each
1236*4b9c6d91SCole Faust // other.
1237*4b9c6d91SCole Faust std::map<std::string, std::string> container_namespaces =
1238*4b9c6d91SCole Faust GetNamespaces(container_pid, namespace_names);
1239*4b9c6d91SCole Faust EXPECT_NE(container_namespaces, init_namespaces);
1240*4b9c6d91SCole Faust for (pid_t pid : GetProcessSubtreePids(container_pid))
1241*4b9c6d91SCole Faust EXPECT_EQ(container_namespaces, GetNamespaces(pid, namespace_names));
1242*4b9c6d91SCole Faust
1243*4b9c6d91SCole Faust EXPECT_EQ(0, close(child_stdin));
1244*4b9c6d91SCole Faust
1245*4b9c6d91SCole Faust int status = minijail_wait(j.get());
1246*4b9c6d91SCole Faust EXPECT_EQ(status, 0);
1247*4b9c6d91SCole Faust }
1248*4b9c6d91SCole Faust }
1249*4b9c6d91SCole Faust }
1250*4b9c6d91SCole Faust
TEST_F(NamespaceTest,test_enter_ns)1251*4b9c6d91SCole Faust TEST_F(NamespaceTest, test_enter_ns) {
1252*4b9c6d91SCole Faust char uidmap[kBufferSize], gidmap[kBufferSize];
1253*4b9c6d91SCole Faust
1254*4b9c6d91SCole Faust if (!userns_supported_)
1255*4b9c6d91SCole Faust GTEST_SKIP();
1256*4b9c6d91SCole Faust
1257*4b9c6d91SCole Faust // We first create a child in a new userns so we have privs to run more tests.
1258*4b9c6d91SCole Faust // We can't combine the steps as the kernel disallows many resource sharing
1259*4b9c6d91SCole Faust // from outside the userns.
1260*4b9c6d91SCole Faust struct minijail *j = minijail_new();
1261*4b9c6d91SCole Faust
1262*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1263*4b9c6d91SCole Faust minijail_namespace_pids(j);
1264*4b9c6d91SCole Faust minijail_run_as_init(j);
1265*4b9c6d91SCole Faust
1266*4b9c6d91SCole Faust // Perform userns mapping.
1267*4b9c6d91SCole Faust minijail_namespace_user(j);
1268*4b9c6d91SCole Faust snprintf(uidmap, sizeof(uidmap), "0 %d 1", getuid());
1269*4b9c6d91SCole Faust snprintf(gidmap, sizeof(gidmap), "0 %d 1", getgid());
1270*4b9c6d91SCole Faust minijail_uidmap(j, uidmap);
1271*4b9c6d91SCole Faust minijail_gidmap(j, gidmap);
1272*4b9c6d91SCole Faust minijail_namespace_user_disable_setgroups(j);
1273*4b9c6d91SCole Faust
1274*4b9c6d91SCole Faust pid_t pid = minijail_fork(j);
1275*4b9c6d91SCole Faust if (pid == 0) {
1276*4b9c6d91SCole Faust // Child.
1277*4b9c6d91SCole Faust minijail_destroy(j);
1278*4b9c6d91SCole Faust
1279*4b9c6d91SCole Faust // Create new namespaces inside this userns which we may enter.
1280*4b9c6d91SCole Faust j = minijail_new();
1281*4b9c6d91SCole Faust minijail_namespace_net(j);
1282*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1283*4b9c6d91SCole Faust pid = minijail_fork(j);
1284*4b9c6d91SCole Faust if (pid == 0) {
1285*4b9c6d91SCole Faust // Child.
1286*4b9c6d91SCole Faust minijail_destroy(j);
1287*4b9c6d91SCole Faust
1288*4b9c6d91SCole Faust // Finally enter those namespaces.
1289*4b9c6d91SCole Faust j = minijail_new();
1290*4b9c6d91SCole Faust
1291*4b9c6d91SCole Faust set_preload_path(j);
1292*4b9c6d91SCole Faust
1293*4b9c6d91SCole Faust minijail_namespace_net(j);
1294*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1295*4b9c6d91SCole Faust
1296*4b9c6d91SCole Faust minijail_namespace_enter_net(j, "/proc/self/ns/net");
1297*4b9c6d91SCole Faust minijail_namespace_enter_vfs(j, "/proc/self/ns/mnt");
1298*4b9c6d91SCole Faust
1299*4b9c6d91SCole Faust char *argv[] = {"/bin/true", nullptr};
1300*4b9c6d91SCole Faust EXPECT_EQ(0, minijail_run(j, argv[0], argv));
1301*4b9c6d91SCole Faust EXPECT_EQ(0, minijail_wait(j));
1302*4b9c6d91SCole Faust minijail_destroy(j);
1303*4b9c6d91SCole Faust exit(0);
1304*4b9c6d91SCole Faust } else {
1305*4b9c6d91SCole Faust ASSERT_GT(pid, 0);
1306*4b9c6d91SCole Faust EXPECT_EQ(0, minijail_wait(j));
1307*4b9c6d91SCole Faust minijail_destroy(j);
1308*4b9c6d91SCole Faust exit(0);
1309*4b9c6d91SCole Faust }
1310*4b9c6d91SCole Faust } else {
1311*4b9c6d91SCole Faust ASSERT_GT(pid, 0);
1312*4b9c6d91SCole Faust EXPECT_EQ(0, minijail_wait(j));
1313*4b9c6d91SCole Faust minijail_destroy(j);
1314*4b9c6d91SCole Faust }
1315*4b9c6d91SCole Faust }
1316*4b9c6d91SCole Faust
TEST_F(NamespaceTest,test_remount_all_private)1317*4b9c6d91SCole Faust TEST_F(NamespaceTest, test_remount_all_private) {
1318*4b9c6d91SCole Faust pid_t pid;
1319*4b9c6d91SCole Faust int child_stdout;
1320*4b9c6d91SCole Faust int mj_run_ret;
1321*4b9c6d91SCole Faust ssize_t read_ret;
1322*4b9c6d91SCole Faust char buf[kBufferSize];
1323*4b9c6d91SCole Faust int status;
1324*4b9c6d91SCole Faust char *argv[4];
1325*4b9c6d91SCole Faust char uidmap[kBufferSize], gidmap[kBufferSize];
1326*4b9c6d91SCole Faust constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1327*4b9c6d91SCole Faust constexpr gid_t kTargetGid = 1000;
1328*4b9c6d91SCole Faust
1329*4b9c6d91SCole Faust if (!userns_supported_)
1330*4b9c6d91SCole Faust GTEST_SKIP();
1331*4b9c6d91SCole Faust
1332*4b9c6d91SCole Faust struct minijail *j = minijail_new();
1333*4b9c6d91SCole Faust
1334*4b9c6d91SCole Faust minijail_namespace_pids(j);
1335*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1336*4b9c6d91SCole Faust minijail_run_as_init(j);
1337*4b9c6d91SCole Faust
1338*4b9c6d91SCole Faust // Perform userns mapping.
1339*4b9c6d91SCole Faust minijail_namespace_user(j);
1340*4b9c6d91SCole Faust snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1341*4b9c6d91SCole Faust snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1342*4b9c6d91SCole Faust minijail_change_uid(j, kTargetUid);
1343*4b9c6d91SCole Faust minijail_change_gid(j, kTargetGid);
1344*4b9c6d91SCole Faust minijail_uidmap(j, uidmap);
1345*4b9c6d91SCole Faust minijail_gidmap(j, gidmap);
1346*4b9c6d91SCole Faust minijail_namespace_user_disable_setgroups(j);
1347*4b9c6d91SCole Faust
1348*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1349*4b9c6d91SCole Faust minijail_remount_mode(j, MS_PRIVATE);
1350*4b9c6d91SCole Faust
1351*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
1352*4b9c6d91SCole Faust argv[1] = "-c";
1353*4b9c6d91SCole Faust argv[2] = "grep -E 'shared:|master:|propagate_from:|unbindable:' "
1354*4b9c6d91SCole Faust "/proc/self/mountinfo";
1355*4b9c6d91SCole Faust argv[3] = NULL;
1356*4b9c6d91SCole Faust mj_run_ret = minijail_run_pid_pipes_no_preload(
1357*4b9c6d91SCole Faust j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1358*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1359*4b9c6d91SCole Faust
1360*4b9c6d91SCole Faust // There should be no output because all mounts should be remounted as
1361*4b9c6d91SCole Faust // private.
1362*4b9c6d91SCole Faust read_ret = read(child_stdout, buf, sizeof(buf));
1363*4b9c6d91SCole Faust EXPECT_EQ(read_ret, 0);
1364*4b9c6d91SCole Faust
1365*4b9c6d91SCole Faust // grep will exit with 1 if it does not find anything which is what we
1366*4b9c6d91SCole Faust // expect.
1367*4b9c6d91SCole Faust status = minijail_wait(j);
1368*4b9c6d91SCole Faust EXPECT_EQ(status, 1);
1369*4b9c6d91SCole Faust
1370*4b9c6d91SCole Faust minijail_destroy(j);
1371*4b9c6d91SCole Faust }
1372*4b9c6d91SCole Faust
TEST_F(NamespaceTest,test_fail_to_remount_one_private)1373*4b9c6d91SCole Faust TEST_F(NamespaceTest, test_fail_to_remount_one_private) {
1374*4b9c6d91SCole Faust int status;
1375*4b9c6d91SCole Faust char uidmap[kBufferSize], gidmap[kBufferSize];
1376*4b9c6d91SCole Faust constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1377*4b9c6d91SCole Faust constexpr gid_t kTargetGid = 1000;
1378*4b9c6d91SCole Faust
1379*4b9c6d91SCole Faust if (!userns_supported_)
1380*4b9c6d91SCole Faust GTEST_SKIP();
1381*4b9c6d91SCole Faust
1382*4b9c6d91SCole Faust struct minijail *j = minijail_new();
1383*4b9c6d91SCole Faust
1384*4b9c6d91SCole Faust minijail_namespace_pids(j);
1385*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1386*4b9c6d91SCole Faust minijail_mount_tmp(j);
1387*4b9c6d91SCole Faust minijail_run_as_init(j);
1388*4b9c6d91SCole Faust
1389*4b9c6d91SCole Faust // Perform userns mapping.
1390*4b9c6d91SCole Faust minijail_namespace_user(j);
1391*4b9c6d91SCole Faust snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1392*4b9c6d91SCole Faust snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1393*4b9c6d91SCole Faust minijail_change_uid(j, kTargetUid);
1394*4b9c6d91SCole Faust minijail_change_gid(j, kTargetGid);
1395*4b9c6d91SCole Faust minijail_uidmap(j, uidmap);
1396*4b9c6d91SCole Faust minijail_gidmap(j, gidmap);
1397*4b9c6d91SCole Faust minijail_namespace_user_disable_setgroups(j);
1398*4b9c6d91SCole Faust
1399*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1400*4b9c6d91SCole Faust minijail_remount_mode(j, MS_SHARED);
1401*4b9c6d91SCole Faust minijail_add_remount(j, "/proc", MS_PRIVATE);
1402*4b9c6d91SCole Faust
1403*4b9c6d91SCole Faust char *argv[] = {"/bin/true", nullptr};
1404*4b9c6d91SCole Faust minijail_run(j, argv[0], argv);
1405*4b9c6d91SCole Faust
1406*4b9c6d91SCole Faust status = minijail_wait(j);
1407*4b9c6d91SCole Faust EXPECT_GT(status, 0);
1408*4b9c6d91SCole Faust
1409*4b9c6d91SCole Faust minijail_destroy(j);
1410*4b9c6d91SCole Faust }
1411*4b9c6d91SCole Faust
TEST_F(NamespaceTest,test_remount_one_shared)1412*4b9c6d91SCole Faust TEST_F(NamespaceTest, test_remount_one_shared) {
1413*4b9c6d91SCole Faust pid_t pid;
1414*4b9c6d91SCole Faust int child_stdout;
1415*4b9c6d91SCole Faust int mj_run_ret;
1416*4b9c6d91SCole Faust ssize_t read_ret;
1417*4b9c6d91SCole Faust char buf[kBufferSize * 4];
1418*4b9c6d91SCole Faust int status;
1419*4b9c6d91SCole Faust char *argv[4];
1420*4b9c6d91SCole Faust char uidmap[kBufferSize], gidmap[kBufferSize];
1421*4b9c6d91SCole Faust constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1422*4b9c6d91SCole Faust constexpr gid_t kTargetGid = 1000;
1423*4b9c6d91SCole Faust
1424*4b9c6d91SCole Faust if (!userns_supported_)
1425*4b9c6d91SCole Faust GTEST_SKIP();
1426*4b9c6d91SCole Faust
1427*4b9c6d91SCole Faust struct minijail *j = minijail_new();
1428*4b9c6d91SCole Faust
1429*4b9c6d91SCole Faust minijail_namespace_pids(j);
1430*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1431*4b9c6d91SCole Faust minijail_mount_tmp(j);
1432*4b9c6d91SCole Faust minijail_run_as_init(j);
1433*4b9c6d91SCole Faust
1434*4b9c6d91SCole Faust // Perform userns mapping.
1435*4b9c6d91SCole Faust minijail_namespace_user(j);
1436*4b9c6d91SCole Faust snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1437*4b9c6d91SCole Faust snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1438*4b9c6d91SCole Faust minijail_change_uid(j, kTargetUid);
1439*4b9c6d91SCole Faust minijail_change_gid(j, kTargetGid);
1440*4b9c6d91SCole Faust minijail_uidmap(j, uidmap);
1441*4b9c6d91SCole Faust minijail_gidmap(j, gidmap);
1442*4b9c6d91SCole Faust minijail_namespace_user_disable_setgroups(j);
1443*4b9c6d91SCole Faust
1444*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1445*4b9c6d91SCole Faust minijail_remount_mode(j, MS_PRIVATE);
1446*4b9c6d91SCole Faust minijail_add_remount(j, "/proc", MS_SHARED);
1447*4b9c6d91SCole Faust
1448*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
1449*4b9c6d91SCole Faust argv[1] = "-c";
1450*4b9c6d91SCole Faust argv[2] = "grep -E 'shared:' /proc/self/mountinfo";
1451*4b9c6d91SCole Faust argv[3] = NULL;
1452*4b9c6d91SCole Faust mj_run_ret = minijail_run_pid_pipes_no_preload(
1453*4b9c6d91SCole Faust j, argv[0], argv, &pid, NULL, &child_stdout, NULL);
1454*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1455*4b9c6d91SCole Faust
1456*4b9c6d91SCole Faust // There should be no output because all mounts should be remounted as
1457*4b9c6d91SCole Faust // private.
1458*4b9c6d91SCole Faust read_ret = read(child_stdout, buf, sizeof(buf));
1459*4b9c6d91SCole Faust EXPECT_GE(read_ret, 0);
1460*4b9c6d91SCole Faust buf[read_ret] = '\0';
1461*4b9c6d91SCole Faust EXPECT_NE(std::string(buf).find("/proc"), std::string::npos);
1462*4b9c6d91SCole Faust
1463*4b9c6d91SCole Faust status = minijail_wait(j);
1464*4b9c6d91SCole Faust EXPECT_EQ(status, 0);
1465*4b9c6d91SCole Faust
1466*4b9c6d91SCole Faust minijail_destroy(j);
1467*4b9c6d91SCole Faust }
1468*4b9c6d91SCole Faust
1469*4b9c6d91SCole Faust // Test that using minijail_mount() for bind mounts works.
TEST_F(NamespaceTest,test_remount_ro_using_mount)1470*4b9c6d91SCole Faust TEST_F(NamespaceTest, test_remount_ro_using_mount) {
1471*4b9c6d91SCole Faust int status;
1472*4b9c6d91SCole Faust char uidmap[kBufferSize], gidmap[kBufferSize];
1473*4b9c6d91SCole Faust constexpr uid_t kTargetUid = 1000; // Any non-zero value will do.
1474*4b9c6d91SCole Faust constexpr gid_t kTargetGid = 1000;
1475*4b9c6d91SCole Faust
1476*4b9c6d91SCole Faust if (!userns_supported_)
1477*4b9c6d91SCole Faust GTEST_SKIP();
1478*4b9c6d91SCole Faust
1479*4b9c6d91SCole Faust struct minijail *j = minijail_new();
1480*4b9c6d91SCole Faust
1481*4b9c6d91SCole Faust minijail_namespace_pids(j);
1482*4b9c6d91SCole Faust minijail_namespace_vfs(j);
1483*4b9c6d91SCole Faust minijail_mount_tmp(j);
1484*4b9c6d91SCole Faust minijail_run_as_init(j);
1485*4b9c6d91SCole Faust
1486*4b9c6d91SCole Faust // Perform userns mapping.
1487*4b9c6d91SCole Faust minijail_namespace_user(j);
1488*4b9c6d91SCole Faust snprintf(uidmap, sizeof(uidmap), "%d %d 1", kTargetUid, getuid());
1489*4b9c6d91SCole Faust snprintf(gidmap, sizeof(gidmap), "%d %d 1", kTargetGid, getgid());
1490*4b9c6d91SCole Faust minijail_change_uid(j, kTargetUid);
1491*4b9c6d91SCole Faust minijail_change_gid(j, kTargetGid);
1492*4b9c6d91SCole Faust minijail_uidmap(j, uidmap);
1493*4b9c6d91SCole Faust minijail_gidmap(j, gidmap);
1494*4b9c6d91SCole Faust minijail_namespace_user_disable_setgroups(j);
1495*4b9c6d91SCole Faust
1496*4b9c6d91SCole Faust // Perform a RO remount using minijail_mount().
1497*4b9c6d91SCole Faust minijail_mount(j, "none", "/", "none", MS_REMOUNT | MS_BIND | MS_RDONLY);
1498*4b9c6d91SCole Faust
1499*4b9c6d91SCole Faust char *argv[] = {"/bin/true", nullptr};
1500*4b9c6d91SCole Faust minijail_run_no_preload(j, argv[0], argv);
1501*4b9c6d91SCole Faust
1502*4b9c6d91SCole Faust status = minijail_wait(j);
1503*4b9c6d91SCole Faust EXPECT_EQ(status, 0);
1504*4b9c6d91SCole Faust
1505*4b9c6d91SCole Faust minijail_destroy(j);
1506*4b9c6d91SCole Faust }
1507*4b9c6d91SCole Faust
1508*4b9c6d91SCole Faust namespace {
1509*4b9c6d91SCole Faust
1510*4b9c6d91SCole Faust // Tests that require Landlock support.
1511*4b9c6d91SCole Faust //
1512*4b9c6d91SCole Faust // These subclass NamespaceTest because they also require userns access.
1513*4b9c6d91SCole Faust // TODO(akhna): ideally, Landlock unit tests should be able to run w/o
1514*4b9c6d91SCole Faust // namespace_pids or namespace_user.
1515*4b9c6d91SCole Faust class LandlockTest : public NamespaceTest {
1516*4b9c6d91SCole Faust protected:
SetUpTestCase()1517*4b9c6d91SCole Faust static void SetUpTestCase() {
1518*4b9c6d91SCole Faust run_landlock_tests_ = LandlockSupported() && UsernsSupported();
1519*4b9c6d91SCole Faust }
1520*4b9c6d91SCole Faust
1521*4b9c6d91SCole Faust // Whether Landlock tests should be run.
1522*4b9c6d91SCole Faust static bool run_landlock_tests_;
1523*4b9c6d91SCole Faust
LandlockSupported()1524*4b9c6d91SCole Faust static bool LandlockSupported() {
1525*4b9c6d91SCole Faust // Check the Landlock version w/o creating a ruleset file descriptor.
1526*4b9c6d91SCole Faust int landlock_version = landlock_create_ruleset(
1527*4b9c6d91SCole Faust NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
1528*4b9c6d91SCole Faust if (landlock_version <= 0) {
1529*4b9c6d91SCole Faust const int err = errno;
1530*4b9c6d91SCole Faust warn("Skipping Landlock tests");
1531*4b9c6d91SCole Faust switch (err) {
1532*4b9c6d91SCole Faust case ENOSYS:
1533*4b9c6d91SCole Faust warn("Landlock not supported by the current kernel.");
1534*4b9c6d91SCole Faust break;
1535*4b9c6d91SCole Faust case EOPNOTSUPP:
1536*4b9c6d91SCole Faust warn("Landlock is currently disabled.");
1537*4b9c6d91SCole Faust break;
1538*4b9c6d91SCole Faust }
1539*4b9c6d91SCole Faust return false;
1540*4b9c6d91SCole Faust }
1541*4b9c6d91SCole Faust return true;
1542*4b9c6d91SCole Faust }
1543*4b9c6d91SCole Faust
1544*4b9c6d91SCole Faust // Sets up a minijail to make Landlock syscalls and child processes.
SetupLandlockTestingNamespaces(struct minijail * j)1545*4b9c6d91SCole Faust void SetupLandlockTestingNamespaces(struct minijail *j) {
1546*4b9c6d91SCole Faust minijail_namespace_pids(j);
1547*4b9c6d91SCole Faust minijail_namespace_user(j);
1548*4b9c6d91SCole Faust }
1549*4b9c6d91SCole Faust };
1550*4b9c6d91SCole Faust
1551*4b9c6d91SCole Faust bool LandlockTest::run_landlock_tests_;
1552*4b9c6d91SCole Faust
1553*4b9c6d91SCole Faust // Constants used in Landlock tests.
1554*4b9c6d91SCole Faust constexpr char kBinPath[] = "/bin";
1555*4b9c6d91SCole Faust constexpr char kEtcPath[] = "/etc";
1556*4b9c6d91SCole Faust constexpr char kLibPath[] = "/lib";
1557*4b9c6d91SCole Faust constexpr char kLib64Path[] = "/lib64";
1558*4b9c6d91SCole Faust constexpr char kTmpPath[] = "/tmp";
1559*4b9c6d91SCole Faust constexpr char kLsPath[] = "/bin/ls";
1560*4b9c6d91SCole Faust constexpr char kTestSymlinkScript[] = R"(
1561*4b9c6d91SCole Faust unlink /tmp/test-sym-link-1;
1562*4b9c6d91SCole Faust ln -s /bin /tmp/test-sym-link-1
1563*4b9c6d91SCole Faust )";
1564*4b9c6d91SCole Faust
1565*4b9c6d91SCole Faust } // namespace
1566*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_rx_allow)1567*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_rx_allow) {
1568*4b9c6d91SCole Faust int mj_run_ret;
1569*4b9c6d91SCole Faust int status;
1570*4b9c6d91SCole Faust char *argv[3];
1571*4b9c6d91SCole Faust if (!run_landlock_tests_)
1572*4b9c6d91SCole Faust GTEST_SKIP();
1573*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1574*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1575*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kBinPath);
1576*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1577*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLibPath);
1578*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1579*4b9c6d91SCole Faust
1580*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kLsPath);
1581*4b9c6d91SCole Faust argv[1] = const_cast<char*>(kCatPath);
1582*4b9c6d91SCole Faust argv[2] = NULL;
1583*4b9c6d91SCole Faust
1584*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1585*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1586*4b9c6d91SCole Faust status = minijail_wait(j.get());
1587*4b9c6d91SCole Faust EXPECT_EQ(status, 0);
1588*4b9c6d91SCole Faust }
1589*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_rx_deny)1590*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_rx_deny) {
1591*4b9c6d91SCole Faust int mj_run_ret;
1592*4b9c6d91SCole Faust int status;
1593*4b9c6d91SCole Faust char *argv[3];
1594*4b9c6d91SCole Faust if (!run_landlock_tests_)
1595*4b9c6d91SCole Faust GTEST_SKIP();
1596*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1597*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1598*4b9c6d91SCole Faust // Add irrelevant Landlock rule.
1599*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), "/var");
1600*4b9c6d91SCole Faust
1601*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kLsPath);
1602*4b9c6d91SCole Faust argv[1] = const_cast<char*>(kCatPath);
1603*4b9c6d91SCole Faust argv[2] = NULL;
1604*4b9c6d91SCole Faust
1605*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1606*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1607*4b9c6d91SCole Faust status = minijail_wait(j.get());
1608*4b9c6d91SCole Faust EXPECT_NE(status, 0);
1609*4b9c6d91SCole Faust }
1610*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_ro_allow)1611*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_ro_allow) {
1612*4b9c6d91SCole Faust int mj_run_ret;
1613*4b9c6d91SCole Faust int status;
1614*4b9c6d91SCole Faust char *argv[3];
1615*4b9c6d91SCole Faust if (!run_landlock_tests_)
1616*4b9c6d91SCole Faust GTEST_SKIP();
1617*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1618*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1619*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kBinPath);
1620*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1621*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLibPath);
1622*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1623*4b9c6d91SCole Faust // Add RO rule.
1624*4b9c6d91SCole Faust minijail_add_fs_restriction_ro(j.get(), "/var");
1625*4b9c6d91SCole Faust
1626*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kLsPath);
1627*4b9c6d91SCole Faust argv[1] = "/var";
1628*4b9c6d91SCole Faust argv[2] = NULL;
1629*4b9c6d91SCole Faust
1630*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1631*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1632*4b9c6d91SCole Faust status = minijail_wait(j.get());
1633*4b9c6d91SCole Faust EXPECT_EQ(status, 0);
1634*4b9c6d91SCole Faust }
1635*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_ro_deny)1636*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_ro_deny) {
1637*4b9c6d91SCole Faust int mj_run_ret;
1638*4b9c6d91SCole Faust int status;
1639*4b9c6d91SCole Faust char *argv[3];
1640*4b9c6d91SCole Faust if (!run_landlock_tests_)
1641*4b9c6d91SCole Faust GTEST_SKIP();
1642*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1643*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1644*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kBinPath);
1645*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1646*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLibPath);
1647*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1648*4b9c6d91SCole Faust // No RO rule for /var, because we want the cmd to fail.
1649*4b9c6d91SCole Faust
1650*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kLsPath);
1651*4b9c6d91SCole Faust argv[1] = "/var";
1652*4b9c6d91SCole Faust argv[2] = NULL;
1653*4b9c6d91SCole Faust
1654*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1655*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1656*4b9c6d91SCole Faust status = minijail_wait(j.get());
1657*4b9c6d91SCole Faust EXPECT_NE(status, 0);
1658*4b9c6d91SCole Faust }
1659*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_rw_allow)1660*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_rw_allow) {
1661*4b9c6d91SCole Faust int mj_run_ret;
1662*4b9c6d91SCole Faust int status;
1663*4b9c6d91SCole Faust char *argv[4];
1664*4b9c6d91SCole Faust if (!run_landlock_tests_)
1665*4b9c6d91SCole Faust GTEST_SKIP();
1666*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1667*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1668*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kBinPath);
1669*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1670*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLibPath);
1671*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1672*4b9c6d91SCole Faust // Add RW Landlock rule.
1673*4b9c6d91SCole Faust minijail_add_fs_restriction_rw(j.get(), kTmpPath);
1674*4b9c6d91SCole Faust
1675*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
1676*4b9c6d91SCole Faust argv[1] = "-c";
1677*4b9c6d91SCole Faust argv[2] = "exec echo 'bar' > /tmp/baz";
1678*4b9c6d91SCole Faust argv[3] = NULL;
1679*4b9c6d91SCole Faust
1680*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1681*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1682*4b9c6d91SCole Faust status = minijail_wait(j.get());
1683*4b9c6d91SCole Faust EXPECT_EQ(status, 0);
1684*4b9c6d91SCole Faust }
1685*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_rw_deny)1686*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_rw_deny) {
1687*4b9c6d91SCole Faust int mj_run_ret;
1688*4b9c6d91SCole Faust int status;
1689*4b9c6d91SCole Faust char *argv[4];
1690*4b9c6d91SCole Faust if (!run_landlock_tests_)
1691*4b9c6d91SCole Faust GTEST_SKIP();
1692*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1693*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1694*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kBinPath);
1695*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1696*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLibPath);
1697*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1698*4b9c6d91SCole Faust // No RW rule, because we want the cmd to fail.
1699*4b9c6d91SCole Faust
1700*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
1701*4b9c6d91SCole Faust argv[1] = "-c";
1702*4b9c6d91SCole Faust argv[2] = "exec echo 'bar' > /tmp/baz";
1703*4b9c6d91SCole Faust argv[3] = NULL;
1704*4b9c6d91SCole Faust
1705*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1706*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1707*4b9c6d91SCole Faust status = minijail_wait(j.get());
1708*4b9c6d91SCole Faust EXPECT_NE(status, 0);
1709*4b9c6d91SCole Faust }
1710*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_allow_symlinks_advanced_rw)1711*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_allow_symlinks_advanced_rw) {
1712*4b9c6d91SCole Faust int mj_run_ret;
1713*4b9c6d91SCole Faust int status;
1714*4b9c6d91SCole Faust if (!run_landlock_tests_)
1715*4b9c6d91SCole Faust GTEST_SKIP();
1716*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1717*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1718*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kBinPath);
1719*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1720*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLibPath);
1721*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1722*4b9c6d91SCole Faust minijail_add_fs_restriction_advanced_rw(j.get(), kTmpPath);
1723*4b9c6d91SCole Faust
1724*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", const_cast<char*>(kTestSymlinkScript),
1725*4b9c6d91SCole Faust nullptr};
1726*4b9c6d91SCole Faust
1727*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), kShellPath, argv);
1728*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1729*4b9c6d91SCole Faust status = minijail_wait(j.get());
1730*4b9c6d91SCole Faust EXPECT_EQ(status, 0);
1731*4b9c6d91SCole Faust }
1732*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_deny_symlinks_basic_rw)1733*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_deny_symlinks_basic_rw) {
1734*4b9c6d91SCole Faust int mj_run_ret;
1735*4b9c6d91SCole Faust int status;
1736*4b9c6d91SCole Faust if (!run_landlock_tests_)
1737*4b9c6d91SCole Faust GTEST_SKIP();
1738*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1739*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1740*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kBinPath);
1741*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1742*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLibPath);
1743*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1744*4b9c6d91SCole Faust minijail_add_fs_restriction_rw(j.get(), kTmpPath);
1745*4b9c6d91SCole Faust
1746*4b9c6d91SCole Faust char* const argv[] = {"sh", "-c", const_cast<char*>(kTestSymlinkScript),
1747*4b9c6d91SCole Faust nullptr};
1748*4b9c6d91SCole Faust
1749*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), kShellPath, argv);
1750*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1751*4b9c6d91SCole Faust status = minijail_wait(j.get());
1752*4b9c6d91SCole Faust EXPECT_NE(status, 0);
1753*4b9c6d91SCole Faust }
1754*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_rx_cannot_write)1755*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_rx_cannot_write) {
1756*4b9c6d91SCole Faust int mj_run_ret;
1757*4b9c6d91SCole Faust int status;
1758*4b9c6d91SCole Faust char *argv[4];
1759*4b9c6d91SCole Faust if (!run_landlock_tests_)
1760*4b9c6d91SCole Faust GTEST_SKIP();
1761*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1762*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1763*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kBinPath);
1764*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kEtcPath);
1765*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLibPath);
1766*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kLib64Path);
1767*4b9c6d91SCole Faust minijail_add_fs_restriction_rx(j.get(), kTmpPath);
1768*4b9c6d91SCole Faust
1769*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
1770*4b9c6d91SCole Faust argv[1] = "-c";
1771*4b9c6d91SCole Faust argv[2] = "exec echo 'bar' > /tmp/baz";
1772*4b9c6d91SCole Faust argv[3] = NULL;
1773*4b9c6d91SCole Faust
1774*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1775*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1776*4b9c6d91SCole Faust status = minijail_wait(j.get());
1777*4b9c6d91SCole Faust EXPECT_NE(status, 0);
1778*4b9c6d91SCole Faust }
1779*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_ro_cannot_wx)1780*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_ro_cannot_wx) {
1781*4b9c6d91SCole Faust int mj_run_ret;
1782*4b9c6d91SCole Faust int status;
1783*4b9c6d91SCole Faust char *argv[4];
1784*4b9c6d91SCole Faust if (!run_landlock_tests_)
1785*4b9c6d91SCole Faust GTEST_SKIP();
1786*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1787*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1788*4b9c6d91SCole Faust minijail_add_fs_restriction_ro(j.get(), kBinPath);
1789*4b9c6d91SCole Faust minijail_add_fs_restriction_ro(j.get(), kEtcPath);
1790*4b9c6d91SCole Faust minijail_add_fs_restriction_ro(j.get(), kLibPath);
1791*4b9c6d91SCole Faust minijail_add_fs_restriction_ro(j.get(), kLib64Path);
1792*4b9c6d91SCole Faust minijail_add_fs_restriction_ro(j.get(), kTmpPath);
1793*4b9c6d91SCole Faust
1794*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
1795*4b9c6d91SCole Faust argv[1] = "-c";
1796*4b9c6d91SCole Faust argv[2] = "exec echo 'bar' > /tmp/baz";
1797*4b9c6d91SCole Faust argv[3] = NULL;
1798*4b9c6d91SCole Faust
1799*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1800*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1801*4b9c6d91SCole Faust status = minijail_wait(j.get());
1802*4b9c6d91SCole Faust EXPECT_NE(status, 0);
1803*4b9c6d91SCole Faust }
1804*4b9c6d91SCole Faust
TEST_F(LandlockTest,test_rule_rw_cannot_exec)1805*4b9c6d91SCole Faust TEST_F(LandlockTest, test_rule_rw_cannot_exec) {
1806*4b9c6d91SCole Faust int mj_run_ret;
1807*4b9c6d91SCole Faust int status;
1808*4b9c6d91SCole Faust char *argv[4];
1809*4b9c6d91SCole Faust if (!run_landlock_tests_)
1810*4b9c6d91SCole Faust GTEST_SKIP();
1811*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1812*4b9c6d91SCole Faust SetupLandlockTestingNamespaces(j.get());
1813*4b9c6d91SCole Faust minijail_add_fs_restriction_rw(j.get(), kBinPath);
1814*4b9c6d91SCole Faust minijail_add_fs_restriction_rw(j.get(), kEtcPath);
1815*4b9c6d91SCole Faust minijail_add_fs_restriction_rw(j.get(), kLibPath);
1816*4b9c6d91SCole Faust minijail_add_fs_restriction_rw(j.get(), kLib64Path);
1817*4b9c6d91SCole Faust minijail_add_fs_restriction_rw(j.get(), kTmpPath);
1818*4b9c6d91SCole Faust
1819*4b9c6d91SCole Faust argv[0] = const_cast<char*>(kShellPath);
1820*4b9c6d91SCole Faust argv[1] = "-c";
1821*4b9c6d91SCole Faust argv[2] = "exec echo 'bar' > /tmp/baz";
1822*4b9c6d91SCole Faust argv[3] = NULL;
1823*4b9c6d91SCole Faust
1824*4b9c6d91SCole Faust mj_run_ret = minijail_run_no_preload(j.get(), argv[0], argv);
1825*4b9c6d91SCole Faust EXPECT_EQ(mj_run_ret, 0);
1826*4b9c6d91SCole Faust status = minijail_wait(j.get());
1827*4b9c6d91SCole Faust EXPECT_NE(status, 0);
1828*4b9c6d91SCole Faust }
1829*4b9c6d91SCole Faust
TestCreateSession(bool create_session)1830*4b9c6d91SCole Faust void TestCreateSession(bool create_session) {
1831*4b9c6d91SCole Faust int status;
1832*4b9c6d91SCole Faust int pipe_fds[2];
1833*4b9c6d91SCole Faust pid_t child_pid;
1834*4b9c6d91SCole Faust pid_t parent_sid = getsid(0);
1835*4b9c6d91SCole Faust ssize_t pid_size = sizeof(pid_t);
1836*4b9c6d91SCole Faust
1837*4b9c6d91SCole Faust ScopedMinijail j(minijail_new());
1838*4b9c6d91SCole Faust // stdin/stdout/stderr might be attached to TTYs. Close them to avoid creating
1839*4b9c6d91SCole Faust // a new session because of that.
1840*4b9c6d91SCole Faust minijail_close_open_fds(j.get());
1841*4b9c6d91SCole Faust
1842*4b9c6d91SCole Faust if (create_session)
1843*4b9c6d91SCole Faust minijail_create_session(j.get());
1844*4b9c6d91SCole Faust
1845*4b9c6d91SCole Faust ASSERT_EQ(pipe(pipe_fds), 0);
1846*4b9c6d91SCole Faust minijail_preserve_fd(j.get(), pipe_fds[0], pipe_fds[0]);
1847*4b9c6d91SCole Faust
1848*4b9c6d91SCole Faust child_pid = minijail_fork(j.get());
1849*4b9c6d91SCole Faust ASSERT_GE(child_pid, 0);
1850*4b9c6d91SCole Faust if (child_pid == 0) {
1851*4b9c6d91SCole Faust pid_t sid_in_parent;
1852*4b9c6d91SCole Faust ASSERT_EQ(read(pipe_fds[0], &sid_in_parent, pid_size), pid_size);
1853*4b9c6d91SCole Faust if (create_session)
1854*4b9c6d91SCole Faust ASSERT_NE(sid_in_parent, getsid(0));
1855*4b9c6d91SCole Faust else
1856*4b9c6d91SCole Faust ASSERT_EQ(sid_in_parent, getsid(0));
1857*4b9c6d91SCole Faust exit(0);
1858*4b9c6d91SCole Faust }
1859*4b9c6d91SCole Faust
1860*4b9c6d91SCole Faust EXPECT_EQ(write(pipe_fds[1], &parent_sid, pid_size), pid_size);
1861*4b9c6d91SCole Faust waitpid(child_pid, &status, 0);
1862*4b9c6d91SCole Faust ASSERT_TRUE(WIFEXITED(status));
1863*4b9c6d91SCole Faust EXPECT_EQ(WEXITSTATUS(status), 0);
1864*4b9c6d91SCole Faust }
1865*4b9c6d91SCole Faust
TEST(Test,default_no_new_session)1866*4b9c6d91SCole Faust TEST(Test, default_no_new_session) {
1867*4b9c6d91SCole Faust TestCreateSession(/*create_session=*/false);
1868*4b9c6d91SCole Faust }
1869*4b9c6d91SCole Faust
TEST(Test,create_new_session)1870*4b9c6d91SCole Faust TEST(Test, create_new_session) {
1871*4b9c6d91SCole Faust TestCreateSession(/*create_session=*/true);
1872*4b9c6d91SCole Faust }
1873