blob: e6a77d911a3880f86a5042418a951937d5fefccc [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>
yusukesbbc37a72017-11-21 09:51:54 -08007#include <stdlib.h>
8#include <string.h>
Dylan Reid837c74a2016-01-22 17:25:21 -08009#include <sys/mount.h>
10#include <sys/stat.h>
Yunlian Jiangd25646b2018-10-24 19:41:06 -070011#include <sys/sysmacros.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080012#include <sys/types.h>
13#include <unistd.h>
14
Luis Hector Chavez644d2042017-09-19 18:56:44 -070015#include <map>
Luis Hector Chavezedec56e2017-09-19 15:43:53 -070016#include <memory>
Luis Hector Chavez58725a82017-09-19 21:14:17 -070017#include <string>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070018#include <utility>
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070019#include <vector>
Luis Hector Chavezedec56e2017-09-19 15:43:53 -070020
Luis Hector Chavez644d2042017-09-19 18:56:44 -070021#include <base/bind.h>
22#include <base/bind_helpers.h>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070023#include <base/files/file_path.h>
Luis Hector Chavez58725a82017-09-19 21:14:17 -070024#include <base/files/file_util.h>
25#include <base/files/scoped_temp_dir.h>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070026#include <base/posix/eintr_wrapper.h>
Qijiang Fane19d67d2020-04-01 08:18:39 +090027#include <base/stl_util.h>
yusukesbbc37a72017-11-21 09:51:54 -080028#include <base/strings/string_split.h>
Luis Hector Chavez58725a82017-09-19 21:14:17 -070029#include <gtest/gtest.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080030
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070031#include "libcontainer/cgroup.h"
32#include "libcontainer/config.h"
33#include "libcontainer/container.h"
Luis Hector Chavez836d7b22017-09-14 15:11:15 -070034#include "libcontainer/libcontainer.h"
Luis Hector Chavez835d39e2017-09-19 15:16:31 -070035#include "libcontainer/libcontainer_util.h"
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070036
Luis Hector Chavez58725a82017-09-19 21:14:17 -070037namespace libcontainer {
38
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070039namespace {
40
Luis Hector Chavez644d2042017-09-19 18:56:44 -070041using MinijailHookCallback = base::Callback<int()>;
42
Luis Hector Chavez58725a82017-09-19 21:14:17 -070043constexpr int kTestCpuShares = 200;
44constexpr int kTestCpuQuota = 20000;
45constexpr int kTestCpuPeriod = 50000;
46
47struct MockPosixState {
48 struct MountArgs {
49 std::string source;
50 base::FilePath target;
51 std::string filesystemtype;
52 unsigned long mountflags;
53 const void* data;
54 bool outside_mount;
55 };
56 std::vector<MountArgs> mount_args;
57
58 dev_t stat_rdev_ret = makedev(2, 3);
59
60 std::vector<int> kill_sigs;
61 base::FilePath mkdtemp_root;
62};
63MockPosixState* g_mock_posix_state = nullptr;
64
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070065struct MockCgroupState {
66 struct AddedDevice {
67 bool allow;
68 int major;
69 int minor;
70 bool read;
71 bool write;
72 bool modify;
73 char type;
74 };
75
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -070076 bool freeze_ret = true;
77 bool thaw_ret = true;
78 bool deny_all_devs_ret = true;
79 bool add_device_ret = true;
80 bool set_cpu_ret = true;
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070081
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070082 int deny_all_devs_called_count;
83
84 std::vector<AddedDevice> added_devices;
85
86 int set_cpu_shares_count;
87 int set_cpu_quota_count;
88 int set_cpu_period_count;
89 int set_cpu_rt_runtime_count;
90 int set_cpu_rt_period_count;
91};
92MockCgroupState* g_mock_cgroup_state = nullptr;
93
94class MockCgroup : public libcontainer::Cgroup {
95 public:
96 explicit MockCgroup(MockCgroupState* state) : state_(state) {}
97 ~MockCgroup() = default;
98
99 static std::unique_ptr<libcontainer::Cgroup> Create(
100 base::StringPiece name,
101 const base::FilePath& cgroup_root,
102 const base::FilePath& cgroup_parent,
103 uid_t cgroup_owner,
104 gid_t cgroup_group) {
Ben Chanc4929c62017-09-29 23:25:39 -0700105 return std::make_unique<MockCgroup>(g_mock_cgroup_state);
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700106 }
107
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700108 bool Freeze() override { return state_->freeze_ret; }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700109
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700110 bool Thaw() override { return state_->thaw_ret; }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700111
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700112 bool DenyAllDevices() override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700113 ++state_->deny_all_devs_called_count;
114 return state_->deny_all_devs_ret;
115 }
116
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700117 bool AddDevice(bool allow,
118 int major,
119 int minor,
120 bool read,
121 bool write,
122 bool modify,
123 char type) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700124 state_->added_devices.emplace_back(MockCgroupState::AddedDevice{
125 allow, major, minor, read, write, modify, type});
126 return state_->add_device_ret;
127 }
128
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700129 bool SetCpuShares(int shares) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700130 state_->set_cpu_shares_count++;
131 return state_->set_cpu_ret;
132 }
133
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700134 bool SetCpuQuota(int quota) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700135 state_->set_cpu_quota_count++;
136 return state_->set_cpu_ret;
137 }
138
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700139 bool SetCpuPeriod(int period) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700140 state_->set_cpu_period_count++;
141 return state_->set_cpu_ret;
142 }
143
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700144 bool SetCpuRtRuntime(int rt_runtime) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700145 state_->set_cpu_rt_runtime_count++;
146 return state_->set_cpu_ret;
147 }
148
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700149 bool SetCpuRtPeriod(int rt_period) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700150 state_->set_cpu_rt_period_count++;
151 return state_->set_cpu_ret;
152 }
153
154 private:
155 MockCgroupState* const state_;
156
157 DISALLOW_COPY_AND_ASSIGN(MockCgroup);
158};
159
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700160struct MockMinijailState {
161 std::string alt_syscall_table;
162 int ipc_called_count;
163 int vfs_called_count;
164 int net_called_count;
165 int pids_called_count;
166 int run_as_init_called_count;
167 int user_called_count;
168 int cgroups_called_count;
169 int wait_called_count;
170 int reset_signal_mask_called_count;
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -0700171 int reset_signal_handlers_called_count;
Risanfd41aee2018-08-15 14:03:38 +0900172 int set_supplementary_gids_called_count;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700173 int pid;
174 std::map<minijail_hook_event_t, std::vector<MinijailHookCallback>> hooks;
175};
176MockMinijailState* g_mock_minijail_state = nullptr;
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700177
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700178} // namespace
Dylan Reid837c74a2016-01-22 17:25:21 -0800179
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700180TEST(LibcontainerTest, PremountedRunfs) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700181 char premounted_runfs[] = "/tmp/cgtest_run/root";
182 struct container_config* config = container_config_create();
183 ASSERT_NE(nullptr, config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700184
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700185 container_config_premounted_runfs(config, premounted_runfs);
186 const char* result = container_config_get_premounted_runfs(config);
187 ASSERT_EQ(0, strcmp(result, premounted_runfs));
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700188
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700189 container_config_destroy(config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700190}
191
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700192TEST(LibcontainerTest, PidFilePath) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700193 char pid_file_path[] = "/tmp/cgtest_run/root/container.pid";
194 struct container_config* config = container_config_create();
195 ASSERT_NE(nullptr, config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700196
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700197 container_config_pid_file(config, pid_file_path);
198 const char* result = container_config_get_pid_file(config);
199 ASSERT_EQ(0, strcmp(result, pid_file_path));
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700200
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700201 container_config_destroy(config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700202}
203
yusukesbbc37a72017-11-21 09:51:54 -0800204TEST(LibcontainerTest, DumpConfig) {
205 struct container_config* config = container_config_create();
206 ASSERT_NE(nullptr, config);
207
208 // Confirm that container_config_dump() returns a non-empty string.
209 std::unique_ptr<char, decltype(&free)> config_str(
yusukes32622542018-01-05 18:59:52 -0800210 container_config_dump(config, false /* sort_vector */), free);
yusukesbbc37a72017-11-21 09:51:54 -0800211 ASSERT_NE(nullptr, config_str.get());
212 EXPECT_NE(0U, strlen(config_str.get()));
213
214 // Also confirm that the string has multiple lines.
215 EXPECT_LT(1U, base::SplitString(config_str.get(), "\n", base::KEEP_WHITESPACE,
216 base::SPLIT_WANT_NONEMPTY)
217 .size());
218
219 container_config_destroy(config);
220}
221
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700222class ContainerTest : public ::testing::Test {
223 public:
224 ContainerTest() = default;
225 ~ContainerTest() override = default;
Dylan Reid837c74a2016-01-22 17:25:21 -0800226
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700227 void SetUp() override {
228 g_mock_posix_state = new MockPosixState();
229 g_mock_cgroup_state = new MockCgroupState();
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700230 g_mock_minijail_state = new MockMinijailState();
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700231 libcontainer::Cgroup::SetCgroupFactoryForTesting(&MockCgroup::Create);
Dylan Reid837c74a2016-01-22 17:25:21 -0800232
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700233 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700234
Satoru Takabayashicf730fb2018-08-03 16:42:36 +0900235 ASSERT_TRUE(base::CreateTemporaryDirInDir(temp_dir_.GetPath(),
236 "container_test", &rootfs_));
Dylan Reid837c74a2016-01-22 17:25:21 -0800237
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700238 mount_flags_ = MS_NOSUID | MS_NODEV | MS_NOEXEC;
Dylan Reid837c74a2016-01-22 17:25:21 -0800239
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700240 config_.reset(new Config());
241 container_config_uid_map(config_->get(), "0 0 4294967295");
242 container_config_gid_map(config_->get(), "0 0 4294967295");
243 container_config_rootfs(config_->get(), rootfs_.value().c_str());
Dylan Reid837c74a2016-01-22 17:25:21 -0800244
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700245 static const char* kArgv[] = {
246 "/sbin/init",
247 };
248 container_config_program_argv(config_->get(), kArgv, 1);
249 container_config_alt_syscall_table(config_->get(), "testsyscalltable");
250 container_config_add_mount(config_->get(),
251 "testtmpfs",
252 "tmpfs",
253 "/tmp",
254 "tmpfs",
255 nullptr,
256 nullptr,
257 mount_flags_,
258 0,
259 1000,
260 1000,
261 0x666,
262 0,
263 0);
264 container_config_add_device(config_->get(),
265 'c',
266 "/dev/foo",
267 S_IRWXU | S_IRWXG,
268 245,
269 2,
270 0,
Stephen Barber7bae6642017-11-30 10:47:12 -0800271 0,
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700272 1000,
273 1001,
274 1,
275 1,
276 0);
277 // test dynamic minor on /dev/null
278 container_config_add_device(config_->get(),
279 'c',
280 "/dev/null",
281 S_IRWXU | S_IRWXG,
282 1,
283 -1,
Stephen Barber7bae6642017-11-30 10:47:12 -0800284 0,
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700285 1,
286 1000,
287 1001,
288 1,
289 1,
290 0);
Stephen Barber771653f2017-10-04 23:48:57 -0700291 static const char* kNamespaces[] = {
292 "cgroup",
293 "ipc",
294 "mount",
295 "network",
296 "pid",
297 "user",
298 };
299 container_config_namespaces(config_->get(), kNamespaces,
Qijiang Fane19d67d2020-04-01 08:18:39 +0900300 base::size(kNamespaces));
Dylan Reid837c74a2016-01-22 17:25:21 -0800301
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700302 container_config_set_cpu_shares(config_->get(), kTestCpuShares);
303 container_config_set_cpu_cfs_params(
304 config_->get(), kTestCpuQuota, kTestCpuPeriod);
305 /* Invalid params, so this won't be applied. */
306 container_config_set_cpu_rt_params(config_->get(), 20000, 20000);
Dylan Reid837c74a2016-01-22 17:25:21 -0800307
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700308 base::FilePath rundir;
Satoru Takabayashicf730fb2018-08-03 16:42:36 +0900309 ASSERT_TRUE(base::CreateTemporaryDirInDir(temp_dir_.GetPath(),
310 "container_test_run", &rundir));
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700311 container_.reset(new Container("containerUT", rundir));
312 ASSERT_NE(nullptr, container_.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700313 }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700314
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700315 void TearDown() override {
316 container_.reset();
317 config_.reset();
Dylan Reid837c74a2016-01-22 17:25:21 -0800318
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700319 ASSERT_TRUE(temp_dir_.Delete());
320 delete g_mock_posix_state;
321 g_mock_posix_state = nullptr;
322 libcontainer::Cgroup::SetCgroupFactoryForTesting(nullptr);
323 delete g_mock_cgroup_state;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700324 delete g_mock_minijail_state;
325 g_mock_minijail_state = nullptr;
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700326 }
327
328 protected:
yusukesbbc37a72017-11-21 09:51:54 -0800329 const Config* config() const { return config_.get(); }
330
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700331 std::unique_ptr<Config> config_;
332 std::unique_ptr<Container> container_;
333 int mount_flags_;
334 base::FilePath rootfs_;
335
336 private:
337 base::ScopedTempDir temp_dir_;
338
339 DISALLOW_COPY_AND_ASSIGN(ContainerTest);
340};
341
342TEST_F(ContainerTest, TestMountTmpStart) {
343 ASSERT_EQ(0, container_start(container_->get(), config_->get()));
344 ASSERT_EQ(2, g_mock_posix_state->mount_args.size());
345 EXPECT_EQ(false, g_mock_posix_state->mount_args[1].outside_mount);
346 EXPECT_STREQ("tmpfs", g_mock_posix_state->mount_args[1].source.c_str());
347 EXPECT_STREQ("/tmp",
348 g_mock_posix_state->mount_args[1].target.value().c_str());
349 EXPECT_STREQ("tmpfs",
350 g_mock_posix_state->mount_args[1].filesystemtype.c_str());
351 EXPECT_EQ(g_mock_posix_state->mount_args[1].mountflags,
352 static_cast<unsigned long>(mount_flags_));
353 EXPECT_EQ(nullptr, g_mock_posix_state->mount_args[1].data);
Dylan Reid837c74a2016-01-22 17:25:21 -0800354
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700355 EXPECT_EQ(1, g_mock_minijail_state->ipc_called_count);
356 EXPECT_EQ(1, g_mock_minijail_state->vfs_called_count);
357 EXPECT_EQ(1, g_mock_minijail_state->net_called_count);
358 EXPECT_EQ(1, g_mock_minijail_state->pids_called_count);
359 EXPECT_EQ(1, g_mock_minijail_state->user_called_count);
360 EXPECT_EQ(1, g_mock_minijail_state->cgroups_called_count);
361 EXPECT_EQ(1, g_mock_minijail_state->run_as_init_called_count);
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700362 EXPECT_EQ(1, g_mock_cgroup_state->deny_all_devs_called_count);
Dylan Reid837c74a2016-01-22 17:25:21 -0800363
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700364 ASSERT_EQ(2, g_mock_cgroup_state->added_devices.size());
365 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].allow);
366 EXPECT_EQ(245, g_mock_cgroup_state->added_devices[0].major);
367 EXPECT_EQ(2, g_mock_cgroup_state->added_devices[0].minor);
368 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].read);
369 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].write);
370 EXPECT_EQ(0, g_mock_cgroup_state->added_devices[0].modify);
371 EXPECT_EQ('c', g_mock_cgroup_state->added_devices[0].type);
Dylan Reid355d5e42016-04-29 16:53:31 -0700372
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700373 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].allow);
374 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].major);
375 EXPECT_EQ(-1, g_mock_cgroup_state->added_devices[1].minor);
376 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].read);
377 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].write);
378 EXPECT_EQ(0, g_mock_cgroup_state->added_devices[1].modify);
379 EXPECT_EQ('c', g_mock_cgroup_state->added_devices[1].type);
Dylan Reid837c74a2016-01-22 17:25:21 -0800380
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700381 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_shares_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700382 EXPECT_EQ(kTestCpuShares, container_config_get_cpu_shares(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700383 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_quota_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700384 EXPECT_EQ(kTestCpuQuota, container_config_get_cpu_quota(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700385 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_period_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700386 EXPECT_EQ(kTestCpuPeriod, container_config_get_cpu_period(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700387 EXPECT_EQ(0, g_mock_cgroup_state->set_cpu_rt_runtime_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700388 EXPECT_EQ(0, container_config_get_cpu_rt_runtime(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700389 EXPECT_EQ(0, g_mock_cgroup_state->set_cpu_rt_period_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700390 EXPECT_EQ(0, container_config_get_cpu_rt_period(config_->get()));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800391
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700392 ASSERT_NE(std::string(), g_mock_minijail_state->alt_syscall_table);
393 EXPECT_EQ("testsyscalltable", g_mock_minijail_state->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800394
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700395 EXPECT_EQ(0, container_wait(container_->get()));
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700396 EXPECT_EQ(1, g_mock_minijail_state->wait_called_count);
397 EXPECT_EQ(1, g_mock_minijail_state->reset_signal_mask_called_count);
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -0700398 EXPECT_EQ(1, g_mock_minijail_state->reset_signal_handlers_called_count);
Risanfd41aee2018-08-15 14:03:38 +0900399 EXPECT_EQ(0, g_mock_minijail_state->set_supplementary_gids_called_count);
Dylan Reid837c74a2016-01-22 17:25:21 -0800400}
401
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700402TEST_F(ContainerTest, TestKillContainer) {
403 ASSERT_EQ(0, container_start(container_->get(), config_->get()));
404 EXPECT_EQ(0, container_kill(container_->get()));
405 EXPECT_EQ(std::vector<int>{SIGKILL}, g_mock_posix_state->kill_sigs);
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700406 EXPECT_EQ(1, g_mock_minijail_state->wait_called_count);
Dylan Reid837c74a2016-01-22 17:25:21 -0800407}
408
yusukesbbc37a72017-11-21 09:51:54 -0800409// Does the same as LibcontainerTest.DumpConfig but with more configuration
410// parameters similar to the production.
411TEST_F(ContainerTest, DumpConfig) {
412 struct container_config* config = this->config()->get();
413 ASSERT_NE(nullptr, config);
414 std::unique_ptr<char, decltype(&free)> config_str(
yusukes32622542018-01-05 18:59:52 -0800415 container_config_dump(config, true /* sort_vector */), free);
yusukesbbc37a72017-11-21 09:51:54 -0800416 ASSERT_NE(nullptr, config_str.get());
417 EXPECT_NE(0U, strlen(config_str.get()));
418 EXPECT_LT(1U, base::SplitString(config_str.get(), "\n", base::KEEP_WHITESPACE,
419 base::SPLIT_WANT_NONEMPTY)
420 .size());
421}
422
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700423} // namespace libcontainer
424
425// libc stubs so the UT doesn't need root to call mount, etc.
Luis Hector Chavezf9b16872017-09-14 14:22:15 -0700426extern "C" {
427
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700428extern decltype(chmod) __real_chmod;
429int __wrap_chmod(const char* path, mode_t mode) {
430 if (!libcontainer::g_mock_posix_state)
431 return __real_chmod(path, mode);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700432 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800433}
434
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700435extern decltype(chown) __real_chown;
436int __wrap_chown(const char* path, uid_t owner, gid_t group) {
437 if (!libcontainer::g_mock_posix_state)
438 return __real_chown(path, owner, group);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700439 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800440}
441
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700442extern decltype(getuid) __real_getuid;
443uid_t __wrap_getuid(void) {
444 if (!libcontainer::g_mock_posix_state)
445 return __real_getuid();
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700446 return 0;
447}
448
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700449extern decltype(kill) __real_kill;
450int __wrap_kill(pid_t pid, int sig) {
451 if (!libcontainer::g_mock_posix_state)
452 return __real_kill(pid, sig);
453 libcontainer::g_mock_posix_state->kill_sigs.push_back(sig);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700454 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800455}
456
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700457extern decltype(mkdir) __real_mkdir;
458int __wrap_mkdir(const char* pathname, mode_t mode) {
459 if (!libcontainer::g_mock_posix_state)
460 return __real_mkdir(pathname, mode);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700461 return 0;
Luis Hector Chavez836d7b22017-09-14 15:11:15 -0700462}
Dylan Reid837c74a2016-01-22 17:25:21 -0800463
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700464extern decltype(mkdtemp) __real_mkdtemp;
465char* __wrap_mkdtemp(char* template_string) {
466 if (!libcontainer::g_mock_posix_state)
467 return __real_mkdtemp(template_string);
468 libcontainer::g_mock_posix_state->mkdtemp_root =
469 base::FilePath(template_string);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700470 return template_string;
Dylan Reid837c74a2016-01-22 17:25:21 -0800471}
472
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700473extern decltype(mount) __real_mount;
474int __wrap_mount(const char* source,
475 const char* target,
476 const char* filesystemtype,
477 unsigned long mountflags,
478 const void* data) {
479 if (!libcontainer::g_mock_posix_state)
480 return __real_mount(source, target, filesystemtype, mountflags, data);
481
482 libcontainer::g_mock_posix_state->mount_args.emplace_back(
483 libcontainer::MockPosixState::MountArgs{source,
484 base::FilePath(target),
485 filesystemtype,
486 mountflags,
487 data,
488 true});
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700489 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800490}
491
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700492extern decltype(rmdir) __real_rmdir;
493int __wrap_rmdir(const char* pathname) {
494 if (!libcontainer::g_mock_posix_state)
495 return __real_rmdir(pathname);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700496 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800497}
498
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700499extern decltype(umount) __real_umount;
500int __wrap_umount(const char* target) {
501 if (!libcontainer::g_mock_posix_state)
502 return __real_umount(target);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700503 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800504}
505
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700506extern decltype(umount2) __real_umount2;
507int __wrap_umount2(const char* target, int flags) {
508 if (!libcontainer::g_mock_posix_state)
509 return __real_umount2(target, flags);
510 return 0;
511}
512
513extern decltype(unlink) __real_unlink;
514int __wrap_unlink(const char* pathname) {
515 if (!libcontainer::g_mock_posix_state)
516 return __real_unlink(pathname);
517 return 0;
518}
519
520extern decltype(__xmknod) __real___xmknod;
521int __wrap___xmknod(int ver, const char* pathname, mode_t mode, dev_t* dev) {
522 if (!libcontainer::g_mock_posix_state)
523 return __real___xmknod(ver, pathname, mode, dev);
524 return 0;
525}
526
527extern decltype(__xstat) __real___xstat;
528int __wrap___xstat(int ver, const char* path, struct stat* buf) {
529 if (!libcontainer::g_mock_posix_state)
530 return __real___xstat(ver, path, buf);
531 buf->st_rdev = libcontainer::g_mock_posix_state->stat_rdev_ret;
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700532 return 0;
533}
534
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700535extern decltype(setns) __real_setns;
536int __wrap_setns(int fd, int nstype) {
537 if (!libcontainer::g_mock_posix_state)
538 return __real_setns(fd, nstype);
539 return 0;
540}
541
Dylan Reid837c74a2016-01-22 17:25:21 -0800542/* Minijail stubs */
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700543struct minijail* minijail_new(void) {
544 return (struct minijail*)0x55;
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800545}
546
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700547void minijail_destroy(struct minijail* j) {}
548
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700549int minijail_mount_with_data(struct minijail* j,
550 const char* source,
551 const char* target,
552 const char* filesystemtype,
553 unsigned long mountflags,
554 const char* data) {
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700555 libcontainer::g_mock_posix_state->mount_args.emplace_back(
556 libcontainer::MockPosixState::MountArgs{source,
557 base::FilePath(target),
558 filesystemtype,
559 mountflags,
560 data,
561 false});
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700562 return 0;
563}
564
Luis Hector Chavezedec56e2017-09-19 15:43:53 -0700565void minijail_namespace_user_disable_setgroups(struct minijail* j) {}
Dylan Reid837c74a2016-01-22 17:25:21 -0800566
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700567void minijail_namespace_vfs(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700568 ++libcontainer::g_mock_minijail_state->vfs_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800569}
570
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700571void minijail_namespace_ipc(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700572 ++libcontainer::g_mock_minijail_state->ipc_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800573}
574
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700575void minijail_namespace_net(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700576 ++libcontainer::g_mock_minijail_state->net_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800577}
578
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700579void minijail_namespace_pids(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700580 ++libcontainer::g_mock_minijail_state->pids_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800581}
582
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700583void minijail_namespace_user(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700584 ++libcontainer::g_mock_minijail_state->user_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800585}
586
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700587void minijail_namespace_cgroups(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700588 ++libcontainer::g_mock_minijail_state->cgroups_called_count;
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700589}
590
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700591int minijail_uidmap(struct minijail* j, const char* uidmap) {
592 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800593}
594
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700595int minijail_gidmap(struct minijail* j, const char* gidmap) {
596 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800597}
598
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700599int minijail_enter_pivot_root(struct minijail* j, const char* dir) {
600 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800601}
602
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700603void minijail_run_as_init(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700604 ++libcontainer::g_mock_minijail_state->run_as_init_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800605}
606
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700607int minijail_run_pid_pipes_no_preload(struct minijail* j,
608 const char* filename,
609 char* const argv[],
610 pid_t* pchild_pid,
611 int* pstdin_fd,
612 int* pstdout_fd,
613 int* pstderr_fd) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700614 libcontainer::g_mock_minijail_state->pid = fork();
615 if (libcontainer::g_mock_minijail_state->pid == -1)
616 return libcontainer::g_mock_minijail_state->pid;
617
618 if (libcontainer::g_mock_minijail_state->pid == 0) {
619 for (minijail_hook_event_t event : {MINIJAIL_HOOK_EVENT_PRE_CHROOT,
620 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS,
621 MINIJAIL_HOOK_EVENT_PRE_EXECVE}) {
622 auto it = libcontainer::g_mock_minijail_state->hooks.find(event);
623 if (it == libcontainer::g_mock_minijail_state->hooks.end())
624 continue;
625 for (auto& hook : it->second) {
626 int rc = hook.Run();
627 if (rc)
628 _exit(rc);
629 }
630 }
631 _exit(0);
632 }
633
634 *pchild_pid = libcontainer::g_mock_minijail_state->pid;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700635 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800636}
637
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700638int minijail_write_pid_file(struct minijail* j, const char* path) {
639 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800640}
641
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700642int minijail_wait(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700643 ++libcontainer::g_mock_minijail_state->wait_called_count;
644 int status;
645 if (HANDLE_EINTR(
646 waitpid(libcontainer::g_mock_minijail_state->pid, &status, 0)) < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700647 PLOG(ERROR) << "Failed to wait for minijail";
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700648 return -errno;
649 }
650 if (!WIFEXITED(status)) {
651 LOG(ERROR) << "minijail terminated abnormally: " << std::hex << status;
652 return -ECANCELED;
653 }
654 // Exit status gets truncated to 8 bits. This should sign-extend it so that
655 // any negative values we passed are preserved.
656 return static_cast<int8_t>(WEXITSTATUS(status));
Dylan Reid837c74a2016-01-22 17:25:21 -0800657}
658
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700659int minijail_use_alt_syscall(struct minijail* j, const char* table) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700660 libcontainer::g_mock_minijail_state->alt_syscall_table = table;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700661 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800662}
663
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700664int minijail_add_to_cgroup(struct minijail* j, const char* cg_path) {
665 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800666}
667
Chris Morin404a2692019-06-14 17:46:56 -0700668int minijail_forward_signals(struct minijail* j) {
669 return 0;
670}
671
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700672void minijail_reset_signal_mask(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700673 ++libcontainer::g_mock_minijail_state->reset_signal_mask_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800674}
675
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -0700676void minijail_reset_signal_handlers(struct minijail* j) {
677 ++libcontainer::g_mock_minijail_state->reset_signal_handlers_called_count;
678}
679
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700680void minijail_skip_remount_private(struct minijail* j) {}
Dylan Reid837c74a2016-01-22 17:25:21 -0800681
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700682int minijail_preserve_fd(struct minijail* j, int parent_fd, int child_fd) {
683 return 0;
684}
685
686int minijail_add_hook(struct minijail* j,
687 minijail_hook_t hook,
688 void* payload,
689 minijail_hook_event_t event) {
690 auto it = libcontainer::g_mock_minijail_state->hooks.insert(
691 std::make_pair(event, std::vector<libcontainer::MinijailHookCallback>()));
692 it.first->second.emplace_back(base::Bind(hook, base::Unretained(payload)));
693 return 0;
694}
695
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700696void minijail_close_open_fds(struct minijail* j) {}
697
Risanfd41aee2018-08-15 14:03:38 +0900698void minijail_set_supplementary_gids(struct minijail* j,
699 size_t size,
700 const gid_t* list) {
701 ++libcontainer::g_mock_minijail_state->set_supplementary_gids_called_count;
702}
703
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700704} // extern "C"