blob: 6ba4434898354fd76a8caeac10c23fb61ab1b6f1 [file] [log] [blame]
Luis Hector Chavez58725a82017-09-19 21:14:17 -07001// Copyright 2016 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Dylan Reid837c74a2016-01-22 17:25:21 -08004
Dylan Reid837c74a2016-01-22 17:25:21 -08005#include <errno.h>
6#include <signal.h>
7#include <sys/mount.h>
8#include <sys/stat.h>
9#include <sys/types.h>
10#include <unistd.h>
11
Luis Hector Chavez644d2042017-09-19 18:56:44 -070012#include <map>
Luis Hector Chavezedec56e2017-09-19 15:43:53 -070013#include <memory>
Luis Hector Chavez58725a82017-09-19 21:14:17 -070014#include <string>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070015#include <utility>
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070016#include <vector>
Luis Hector Chavezedec56e2017-09-19 15:43:53 -070017
Luis Hector Chavez644d2042017-09-19 18:56:44 -070018#include <base/bind.h>
19#include <base/bind_helpers.h>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070020#include <base/files/file_path.h>
Luis Hector Chavez58725a82017-09-19 21:14:17 -070021#include <base/files/file_util.h>
22#include <base/files/scoped_temp_dir.h>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070023#include <base/posix/eintr_wrapper.h>
Luis Hector Chavez58725a82017-09-19 21:14:17 -070024#include <gtest/gtest.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080025
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070026#include "libcontainer/cgroup.h"
27#include "libcontainer/config.h"
28#include "libcontainer/container.h"
Luis Hector Chavez836d7b22017-09-14 15:11:15 -070029#include "libcontainer/libcontainer.h"
Luis Hector Chavez835d39e2017-09-19 15:16:31 -070030#include "libcontainer/libcontainer_util.h"
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070031
Luis Hector Chavez58725a82017-09-19 21:14:17 -070032namespace libcontainer {
33
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070034namespace {
35
Luis Hector Chavez644d2042017-09-19 18:56:44 -070036using MinijailHookCallback = base::Callback<int()>;
37
Luis Hector Chavez58725a82017-09-19 21:14:17 -070038constexpr int kTestCpuShares = 200;
39constexpr int kTestCpuQuota = 20000;
40constexpr int kTestCpuPeriod = 50000;
41
42struct MockPosixState {
43 struct MountArgs {
44 std::string source;
45 base::FilePath target;
46 std::string filesystemtype;
47 unsigned long mountflags;
48 const void* data;
49 bool outside_mount;
50 };
51 std::vector<MountArgs> mount_args;
52
53 dev_t stat_rdev_ret = makedev(2, 3);
54
55 std::vector<int> kill_sigs;
56 base::FilePath mkdtemp_root;
57};
58MockPosixState* g_mock_posix_state = nullptr;
59
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070060struct MockCgroupState {
61 struct AddedDevice {
62 bool allow;
63 int major;
64 int minor;
65 bool read;
66 bool write;
67 bool modify;
68 char type;
69 };
70
71 int freeze_ret;
72 int thaw_ret;
73 int deny_all_devs_ret;
74 int add_device_ret;
75 int set_cpu_ret;
76
77 int init_called_count;
78 int deny_all_devs_called_count;
79
80 std::vector<AddedDevice> added_devices;
81
82 int set_cpu_shares_count;
83 int set_cpu_quota_count;
84 int set_cpu_period_count;
85 int set_cpu_rt_runtime_count;
86 int set_cpu_rt_period_count;
87};
88MockCgroupState* g_mock_cgroup_state = nullptr;
89
90class MockCgroup : public libcontainer::Cgroup {
91 public:
92 explicit MockCgroup(MockCgroupState* state) : state_(state) {}
93 ~MockCgroup() = default;
94
95 static std::unique_ptr<libcontainer::Cgroup> Create(
96 base::StringPiece name,
97 const base::FilePath& cgroup_root,
98 const base::FilePath& cgroup_parent,
99 uid_t cgroup_owner,
100 gid_t cgroup_group) {
Ben Chanc4929c62017-09-29 23:25:39 -0700101 return std::make_unique<MockCgroup>(g_mock_cgroup_state);
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700102 }
103
104 int Freeze() override { return state_->freeze_ret; }
105
106 int Thaw() override { return state_->thaw_ret; }
107
108 int DenyAllDevices() override {
109 ++state_->deny_all_devs_called_count;
110 return state_->deny_all_devs_ret;
111 }
112
113 int AddDevice(bool allow,
114 int major,
115 int minor,
116 bool read,
117 bool write,
118 bool modify,
119 char type) override {
120 state_->added_devices.emplace_back(MockCgroupState::AddedDevice{
121 allow, major, minor, read, write, modify, type});
122 return state_->add_device_ret;
123 }
124
125 int SetCpuShares(int shares) override {
126 state_->set_cpu_shares_count++;
127 return state_->set_cpu_ret;
128 }
129
130 int SetCpuQuota(int quota) override {
131 state_->set_cpu_quota_count++;
132 return state_->set_cpu_ret;
133 }
134
135 int SetCpuPeriod(int period) override {
136 state_->set_cpu_period_count++;
137 return state_->set_cpu_ret;
138 }
139
140 int SetCpuRtRuntime(int rt_runtime) override {
141 state_->set_cpu_rt_runtime_count++;
142 return state_->set_cpu_ret;
143 }
144
145 int SetCpuRtPeriod(int rt_period) override {
146 state_->set_cpu_rt_period_count++;
147 return state_->set_cpu_ret;
148 }
149
150 private:
151 MockCgroupState* const state_;
152
153 DISALLOW_COPY_AND_ASSIGN(MockCgroup);
154};
155
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700156struct MockMinijailState {
157 std::string alt_syscall_table;
158 int ipc_called_count;
159 int vfs_called_count;
160 int net_called_count;
161 int pids_called_count;
162 int run_as_init_called_count;
163 int user_called_count;
164 int cgroups_called_count;
165 int wait_called_count;
166 int reset_signal_mask_called_count;
167 int pid;
168 std::map<minijail_hook_event_t, std::vector<MinijailHookCallback>> hooks;
169};
170MockMinijailState* g_mock_minijail_state = nullptr;
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700171
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700172} // namespace
Dylan Reid837c74a2016-01-22 17:25:21 -0800173
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700174TEST(LibcontainerTest, PremountedRunfs) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700175 char premounted_runfs[] = "/tmp/cgtest_run/root";
176 struct container_config* config = container_config_create();
177 ASSERT_NE(nullptr, config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700178
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700179 container_config_premounted_runfs(config, premounted_runfs);
180 const char* result = container_config_get_premounted_runfs(config);
181 ASSERT_EQ(0, strcmp(result, premounted_runfs));
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700182
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700183 container_config_destroy(config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700184}
185
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700186TEST(LibcontainerTest, PidFilePath) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700187 char pid_file_path[] = "/tmp/cgtest_run/root/container.pid";
188 struct container_config* config = container_config_create();
189 ASSERT_NE(nullptr, config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700190
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700191 container_config_pid_file(config, pid_file_path);
192 const char* result = container_config_get_pid_file(config);
193 ASSERT_EQ(0, strcmp(result, pid_file_path));
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700194
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700195 container_config_destroy(config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700196}
197
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700198TEST(LibcontainerTest, LogPreserve) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700199 errno = EPERM;
200 PLOG_PRESERVE(ERROR) << "This is an expected error log";
201 ASSERT_EQ(EPERM, errno);
202}
203
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700204class ContainerTest : public ::testing::Test {
205 public:
206 ContainerTest() = default;
207 ~ContainerTest() override = default;
Dylan Reid837c74a2016-01-22 17:25:21 -0800208
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700209 void SetUp() override {
210 g_mock_posix_state = new MockPosixState();
211 g_mock_cgroup_state = new MockCgroupState();
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700212 g_mock_minijail_state = new MockMinijailState();
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700213 libcontainer::Cgroup::SetCgroupFactoryForTesting(&MockCgroup::Create);
Dylan Reid837c74a2016-01-22 17:25:21 -0800214
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700215 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700216
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700217 ASSERT_TRUE(base::CreateTemporaryDirInDir(
218 temp_dir_.path(), FILE_PATH_LITERAL("container_test"), &rootfs_));
Dylan Reid837c74a2016-01-22 17:25:21 -0800219
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700220 mount_flags_ = MS_NOSUID | MS_NODEV | MS_NOEXEC;
Dylan Reid837c74a2016-01-22 17:25:21 -0800221
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700222 config_.reset(new Config());
223 container_config_uid_map(config_->get(), "0 0 4294967295");
224 container_config_gid_map(config_->get(), "0 0 4294967295");
225 container_config_rootfs(config_->get(), rootfs_.value().c_str());
Dylan Reid837c74a2016-01-22 17:25:21 -0800226
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700227 static const char* kArgv[] = {
228 "/sbin/init",
229 };
230 container_config_program_argv(config_->get(), kArgv, 1);
231 container_config_alt_syscall_table(config_->get(), "testsyscalltable");
232 container_config_add_mount(config_->get(),
233 "testtmpfs",
234 "tmpfs",
235 "/tmp",
236 "tmpfs",
237 nullptr,
238 nullptr,
239 mount_flags_,
240 0,
241 1000,
242 1000,
243 0x666,
244 0,
245 0);
246 container_config_add_device(config_->get(),
247 'c',
248 "/dev/foo",
249 S_IRWXU | S_IRWXG,
250 245,
251 2,
252 0,
253 1000,
254 1001,
255 1,
256 1,
257 0);
258 // test dynamic minor on /dev/null
259 container_config_add_device(config_->get(),
260 'c',
261 "/dev/null",
262 S_IRWXU | S_IRWXG,
263 1,
264 -1,
265 1,
266 1000,
267 1001,
268 1,
269 1,
270 0);
Dylan Reid837c74a2016-01-22 17:25:21 -0800271
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700272 container_config_set_cpu_shares(config_->get(), kTestCpuShares);
273 container_config_set_cpu_cfs_params(
274 config_->get(), kTestCpuQuota, kTestCpuPeriod);
275 /* Invalid params, so this won't be applied. */
276 container_config_set_cpu_rt_params(config_->get(), 20000, 20000);
Dylan Reid837c74a2016-01-22 17:25:21 -0800277
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700278 base::FilePath rundir;
279 ASSERT_TRUE(base::CreateTemporaryDirInDir(
280 temp_dir_.path(), FILE_PATH_LITERAL("container_test_run"), &rundir));
281 container_.reset(new Container("containerUT", rundir));
282 ASSERT_NE(nullptr, container_.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700283 }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700284
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700285 void TearDown() override {
286 container_.reset();
287 config_.reset();
Dylan Reid837c74a2016-01-22 17:25:21 -0800288
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700289 ASSERT_TRUE(temp_dir_.Delete());
290 delete g_mock_posix_state;
291 g_mock_posix_state = nullptr;
292 libcontainer::Cgroup::SetCgroupFactoryForTesting(nullptr);
293 delete g_mock_cgroup_state;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700294 delete g_mock_minijail_state;
295 g_mock_minijail_state = nullptr;
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700296 }
297
298 protected:
299 std::unique_ptr<Config> config_;
300 std::unique_ptr<Container> container_;
301 int mount_flags_;
302 base::FilePath rootfs_;
303
304 private:
305 base::ScopedTempDir temp_dir_;
306
307 DISALLOW_COPY_AND_ASSIGN(ContainerTest);
308};
309
310TEST_F(ContainerTest, TestMountTmpStart) {
311 ASSERT_EQ(0, container_start(container_->get(), config_->get()));
312 ASSERT_EQ(2, g_mock_posix_state->mount_args.size());
313 EXPECT_EQ(false, g_mock_posix_state->mount_args[1].outside_mount);
314 EXPECT_STREQ("tmpfs", g_mock_posix_state->mount_args[1].source.c_str());
315 EXPECT_STREQ("/tmp",
316 g_mock_posix_state->mount_args[1].target.value().c_str());
317 EXPECT_STREQ("tmpfs",
318 g_mock_posix_state->mount_args[1].filesystemtype.c_str());
319 EXPECT_EQ(g_mock_posix_state->mount_args[1].mountflags,
320 static_cast<unsigned long>(mount_flags_));
321 EXPECT_EQ(nullptr, g_mock_posix_state->mount_args[1].data);
Dylan Reid837c74a2016-01-22 17:25:21 -0800322
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700323 EXPECT_EQ(1, g_mock_minijail_state->ipc_called_count);
324 EXPECT_EQ(1, g_mock_minijail_state->vfs_called_count);
325 EXPECT_EQ(1, g_mock_minijail_state->net_called_count);
326 EXPECT_EQ(1, g_mock_minijail_state->pids_called_count);
327 EXPECT_EQ(1, g_mock_minijail_state->user_called_count);
328 EXPECT_EQ(1, g_mock_minijail_state->cgroups_called_count);
329 EXPECT_EQ(1, g_mock_minijail_state->run_as_init_called_count);
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700330 EXPECT_EQ(1, g_mock_cgroup_state->deny_all_devs_called_count);
Dylan Reid837c74a2016-01-22 17:25:21 -0800331
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700332 ASSERT_EQ(2, g_mock_cgroup_state->added_devices.size());
333 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].allow);
334 EXPECT_EQ(245, g_mock_cgroup_state->added_devices[0].major);
335 EXPECT_EQ(2, g_mock_cgroup_state->added_devices[0].minor);
336 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].read);
337 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].write);
338 EXPECT_EQ(0, g_mock_cgroup_state->added_devices[0].modify);
339 EXPECT_EQ('c', g_mock_cgroup_state->added_devices[0].type);
Dylan Reid355d5e42016-04-29 16:53:31 -0700340
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700341 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].allow);
342 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].major);
343 EXPECT_EQ(-1, g_mock_cgroup_state->added_devices[1].minor);
344 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].read);
345 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].write);
346 EXPECT_EQ(0, g_mock_cgroup_state->added_devices[1].modify);
347 EXPECT_EQ('c', g_mock_cgroup_state->added_devices[1].type);
Dylan Reid837c74a2016-01-22 17:25:21 -0800348
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700349 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_shares_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700350 EXPECT_EQ(kTestCpuShares, container_config_get_cpu_shares(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700351 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_quota_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700352 EXPECT_EQ(kTestCpuQuota, container_config_get_cpu_quota(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700353 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_period_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700354 EXPECT_EQ(kTestCpuPeriod, container_config_get_cpu_period(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700355 EXPECT_EQ(0, g_mock_cgroup_state->set_cpu_rt_runtime_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700356 EXPECT_EQ(0, container_config_get_cpu_rt_runtime(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700357 EXPECT_EQ(0, g_mock_cgroup_state->set_cpu_rt_period_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700358 EXPECT_EQ(0, container_config_get_cpu_rt_period(config_->get()));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800359
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700360 ASSERT_NE(std::string(), g_mock_minijail_state->alt_syscall_table);
361 EXPECT_EQ("testsyscalltable", g_mock_minijail_state->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800362
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700363 EXPECT_EQ(0, container_wait(container_->get()));
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700364 EXPECT_EQ(1, g_mock_minijail_state->wait_called_count);
365 EXPECT_EQ(1, g_mock_minijail_state->reset_signal_mask_called_count);
Dylan Reid837c74a2016-01-22 17:25:21 -0800366}
367
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700368TEST_F(ContainerTest, TestKillContainer) {
369 ASSERT_EQ(0, container_start(container_->get(), config_->get()));
370 EXPECT_EQ(0, container_kill(container_->get()));
371 EXPECT_EQ(std::vector<int>{SIGKILL}, g_mock_posix_state->kill_sigs);
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700372 EXPECT_EQ(1, g_mock_minijail_state->wait_called_count);
Dylan Reid837c74a2016-01-22 17:25:21 -0800373}
374
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700375} // namespace libcontainer
376
377// libc stubs so the UT doesn't need root to call mount, etc.
Luis Hector Chavezf9b16872017-09-14 14:22:15 -0700378extern "C" {
379
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700380extern decltype(chmod) __real_chmod;
381int __wrap_chmod(const char* path, mode_t mode) {
382 if (!libcontainer::g_mock_posix_state)
383 return __real_chmod(path, mode);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700384 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800385}
386
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700387extern decltype(chown) __real_chown;
388int __wrap_chown(const char* path, uid_t owner, gid_t group) {
389 if (!libcontainer::g_mock_posix_state)
390 return __real_chown(path, owner, group);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700391 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800392}
393
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700394extern decltype(getuid) __real_getuid;
395uid_t __wrap_getuid(void) {
396 if (!libcontainer::g_mock_posix_state)
397 return __real_getuid();
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700398 return 0;
399}
400
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700401extern decltype(kill) __real_kill;
402int __wrap_kill(pid_t pid, int sig) {
403 if (!libcontainer::g_mock_posix_state)
404 return __real_kill(pid, sig);
405 libcontainer::g_mock_posix_state->kill_sigs.push_back(sig);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700406 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800407}
408
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700409extern decltype(mkdir) __real_mkdir;
410int __wrap_mkdir(const char* pathname, mode_t mode) {
411 if (!libcontainer::g_mock_posix_state)
412 return __real_mkdir(pathname, mode);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700413 return 0;
Luis Hector Chavez836d7b22017-09-14 15:11:15 -0700414}
Dylan Reid837c74a2016-01-22 17:25:21 -0800415
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700416extern decltype(mkdtemp) __real_mkdtemp;
417char* __wrap_mkdtemp(char* template_string) {
418 if (!libcontainer::g_mock_posix_state)
419 return __real_mkdtemp(template_string);
420 libcontainer::g_mock_posix_state->mkdtemp_root =
421 base::FilePath(template_string);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700422 return template_string;
Dylan Reid837c74a2016-01-22 17:25:21 -0800423}
424
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700425extern decltype(mount) __real_mount;
426int __wrap_mount(const char* source,
427 const char* target,
428 const char* filesystemtype,
429 unsigned long mountflags,
430 const void* data) {
431 if (!libcontainer::g_mock_posix_state)
432 return __real_mount(source, target, filesystemtype, mountflags, data);
433
434 libcontainer::g_mock_posix_state->mount_args.emplace_back(
435 libcontainer::MockPosixState::MountArgs{source,
436 base::FilePath(target),
437 filesystemtype,
438 mountflags,
439 data,
440 true});
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700441 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800442}
443
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700444extern decltype(rmdir) __real_rmdir;
445int __wrap_rmdir(const char* pathname) {
446 if (!libcontainer::g_mock_posix_state)
447 return __real_rmdir(pathname);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700448 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800449}
450
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700451extern decltype(umount) __real_umount;
452int __wrap_umount(const char* target) {
453 if (!libcontainer::g_mock_posix_state)
454 return __real_umount(target);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700455 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800456}
457
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700458extern decltype(umount2) __real_umount2;
459int __wrap_umount2(const char* target, int flags) {
460 if (!libcontainer::g_mock_posix_state)
461 return __real_umount2(target, flags);
462 return 0;
463}
464
465extern decltype(unlink) __real_unlink;
466int __wrap_unlink(const char* pathname) {
467 if (!libcontainer::g_mock_posix_state)
468 return __real_unlink(pathname);
469 return 0;
470}
471
472extern decltype(__xmknod) __real___xmknod;
473int __wrap___xmknod(int ver, const char* pathname, mode_t mode, dev_t* dev) {
474 if (!libcontainer::g_mock_posix_state)
475 return __real___xmknod(ver, pathname, mode, dev);
476 return 0;
477}
478
479extern decltype(__xstat) __real___xstat;
480int __wrap___xstat(int ver, const char* path, struct stat* buf) {
481 if (!libcontainer::g_mock_posix_state)
482 return __real___xstat(ver, path, buf);
483 buf->st_rdev = libcontainer::g_mock_posix_state->stat_rdev_ret;
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700484 return 0;
485}
486
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700487extern decltype(setns) __real_setns;
488int __wrap_setns(int fd, int nstype) {
489 if (!libcontainer::g_mock_posix_state)
490 return __real_setns(fd, nstype);
491 return 0;
492}
493
Dylan Reid837c74a2016-01-22 17:25:21 -0800494/* Minijail stubs */
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700495struct minijail* minijail_new(void) {
496 return (struct minijail*)0x55;
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800497}
498
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700499void minijail_destroy(struct minijail* j) {}
500
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700501int minijail_mount_with_data(struct minijail* j,
502 const char* source,
503 const char* target,
504 const char* filesystemtype,
505 unsigned long mountflags,
506 const char* data) {
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700507 libcontainer::g_mock_posix_state->mount_args.emplace_back(
508 libcontainer::MockPosixState::MountArgs{source,
509 base::FilePath(target),
510 filesystemtype,
511 mountflags,
512 data,
513 false});
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700514 return 0;
515}
516
Luis Hector Chavezedec56e2017-09-19 15:43:53 -0700517void minijail_namespace_user_disable_setgroups(struct minijail* j) {}
Dylan Reid837c74a2016-01-22 17:25:21 -0800518
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700519void minijail_namespace_vfs(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700520 ++libcontainer::g_mock_minijail_state->vfs_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800521}
522
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700523void minijail_namespace_ipc(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700524 ++libcontainer::g_mock_minijail_state->ipc_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800525}
526
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700527void minijail_namespace_net(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700528 ++libcontainer::g_mock_minijail_state->net_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800529}
530
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700531void minijail_namespace_pids(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700532 ++libcontainer::g_mock_minijail_state->pids_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800533}
534
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700535void minijail_namespace_user(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700536 ++libcontainer::g_mock_minijail_state->user_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800537}
538
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700539void minijail_namespace_cgroups(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700540 ++libcontainer::g_mock_minijail_state->cgroups_called_count;
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700541}
542
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700543int minijail_uidmap(struct minijail* j, const char* uidmap) {
544 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800545}
546
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700547int minijail_gidmap(struct minijail* j, const char* gidmap) {
548 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800549}
550
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700551int minijail_enter_pivot_root(struct minijail* j, const char* dir) {
552 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800553}
554
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700555void minijail_run_as_init(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700556 ++libcontainer::g_mock_minijail_state->run_as_init_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800557}
558
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700559int minijail_run_pid_pipes_no_preload(struct minijail* j,
560 const char* filename,
561 char* const argv[],
562 pid_t* pchild_pid,
563 int* pstdin_fd,
564 int* pstdout_fd,
565 int* pstderr_fd) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700566 libcontainer::g_mock_minijail_state->pid = fork();
567 if (libcontainer::g_mock_minijail_state->pid == -1)
568 return libcontainer::g_mock_minijail_state->pid;
569
570 if (libcontainer::g_mock_minijail_state->pid == 0) {
571 for (minijail_hook_event_t event : {MINIJAIL_HOOK_EVENT_PRE_CHROOT,
572 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS,
573 MINIJAIL_HOOK_EVENT_PRE_EXECVE}) {
574 auto it = libcontainer::g_mock_minijail_state->hooks.find(event);
575 if (it == libcontainer::g_mock_minijail_state->hooks.end())
576 continue;
577 for (auto& hook : it->second) {
578 int rc = hook.Run();
579 if (rc)
580 _exit(rc);
581 }
582 }
583 _exit(0);
584 }
585
586 *pchild_pid = libcontainer::g_mock_minijail_state->pid;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700587 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800588}
589
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700590int minijail_write_pid_file(struct minijail* j, const char* path) {
591 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800592}
593
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700594int minijail_wait(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700595 ++libcontainer::g_mock_minijail_state->wait_called_count;
596 int status;
597 if (HANDLE_EINTR(
598 waitpid(libcontainer::g_mock_minijail_state->pid, &status, 0)) < 0) {
599 PLOG_PRESERVE(ERROR) << "Failed to wait for minijail";
600 return -errno;
601 }
602 if (!WIFEXITED(status)) {
603 LOG(ERROR) << "minijail terminated abnormally: " << std::hex << status;
604 return -ECANCELED;
605 }
606 // Exit status gets truncated to 8 bits. This should sign-extend it so that
607 // any negative values we passed are preserved.
608 return static_cast<int8_t>(WEXITSTATUS(status));
Dylan Reid837c74a2016-01-22 17:25:21 -0800609}
610
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700611int minijail_use_alt_syscall(struct minijail* j, const char* table) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700612 libcontainer::g_mock_minijail_state->alt_syscall_table = table;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700613 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800614}
615
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700616int minijail_add_to_cgroup(struct minijail* j, const char* cg_path) {
617 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800618}
619
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700620void minijail_reset_signal_mask(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700621 ++libcontainer::g_mock_minijail_state->reset_signal_mask_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800622}
623
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700624void minijail_skip_remount_private(struct minijail* j) {}
Dylan Reid837c74a2016-01-22 17:25:21 -0800625
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700626int minijail_preserve_fd(struct minijail* j, int parent_fd, int child_fd) {
627 return 0;
628}
629
630int minijail_add_hook(struct minijail* j,
631 minijail_hook_t hook,
632 void* payload,
633 minijail_hook_event_t event) {
634 auto it = libcontainer::g_mock_minijail_state->hooks.insert(
635 std::make_pair(event, std::vector<libcontainer::MinijailHookCallback>()));
636 it.first->second.emplace_back(base::Bind(hook, base::Unretained(payload)));
637 return 0;
638}
639
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700640void minijail_close_open_fds(struct minijail* j) {}
641
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700642} // extern "C"