blob: 124ef59e73e1879578bccf28ad2c8cdea4a0e9d1 [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>
yusukesbbc37a72017-11-21 09:51:54 -080027#include <base/strings/string_split.h>
Luis Hector Chavez58725a82017-09-19 21:14:17 -070028#include <gtest/gtest.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080029
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070030#include "libcontainer/cgroup.h"
31#include "libcontainer/config.h"
32#include "libcontainer/container.h"
Luis Hector Chavez836d7b22017-09-14 15:11:15 -070033#include "libcontainer/libcontainer.h"
Luis Hector Chavez835d39e2017-09-19 15:16:31 -070034#include "libcontainer/libcontainer_util.h"
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070035
Luis Hector Chavez58725a82017-09-19 21:14:17 -070036namespace libcontainer {
37
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070038namespace {
39
Luis Hector Chavez644d2042017-09-19 18:56:44 -070040using MinijailHookCallback = base::Callback<int()>;
41
Luis Hector Chavez58725a82017-09-19 21:14:17 -070042constexpr int kTestCpuShares = 200;
43constexpr int kTestCpuQuota = 20000;
44constexpr int kTestCpuPeriod = 50000;
45
46struct MockPosixState {
47 struct MountArgs {
48 std::string source;
49 base::FilePath target;
50 std::string filesystemtype;
51 unsigned long mountflags;
52 const void* data;
53 bool outside_mount;
54 };
55 std::vector<MountArgs> mount_args;
56
57 dev_t stat_rdev_ret = makedev(2, 3);
58
59 std::vector<int> kill_sigs;
60 base::FilePath mkdtemp_root;
61};
62MockPosixState* g_mock_posix_state = nullptr;
63
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070064struct MockCgroupState {
65 struct AddedDevice {
66 bool allow;
67 int major;
68 int minor;
69 bool read;
70 bool write;
71 bool modify;
72 char type;
73 };
74
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -070075 bool freeze_ret = true;
76 bool thaw_ret = true;
77 bool deny_all_devs_ret = true;
78 bool add_device_ret = true;
79 bool set_cpu_ret = true;
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070080
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070081 int deny_all_devs_called_count;
82
83 std::vector<AddedDevice> added_devices;
84
85 int set_cpu_shares_count;
86 int set_cpu_quota_count;
87 int set_cpu_period_count;
88 int set_cpu_rt_runtime_count;
89 int set_cpu_rt_period_count;
90};
91MockCgroupState* g_mock_cgroup_state = nullptr;
92
93class MockCgroup : public libcontainer::Cgroup {
94 public:
95 explicit MockCgroup(MockCgroupState* state) : state_(state) {}
96 ~MockCgroup() = default;
97
98 static std::unique_ptr<libcontainer::Cgroup> Create(
99 base::StringPiece name,
100 const base::FilePath& cgroup_root,
101 const base::FilePath& cgroup_parent,
102 uid_t cgroup_owner,
103 gid_t cgroup_group) {
Ben Chanc4929c62017-09-29 23:25:39 -0700104 return std::make_unique<MockCgroup>(g_mock_cgroup_state);
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700105 }
106
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700107 bool Freeze() override { return state_->freeze_ret; }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700108
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700109 bool Thaw() override { return state_->thaw_ret; }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700110
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700111 bool DenyAllDevices() override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700112 ++state_->deny_all_devs_called_count;
113 return state_->deny_all_devs_ret;
114 }
115
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700116 bool AddDevice(bool allow,
117 int major,
118 int minor,
119 bool read,
120 bool write,
121 bool modify,
122 char type) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700123 state_->added_devices.emplace_back(MockCgroupState::AddedDevice{
124 allow, major, minor, read, write, modify, type});
125 return state_->add_device_ret;
126 }
127
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700128 bool SetCpuShares(int shares) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700129 state_->set_cpu_shares_count++;
130 return state_->set_cpu_ret;
131 }
132
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700133 bool SetCpuQuota(int quota) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700134 state_->set_cpu_quota_count++;
135 return state_->set_cpu_ret;
136 }
137
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700138 bool SetCpuPeriod(int period) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700139 state_->set_cpu_period_count++;
140 return state_->set_cpu_ret;
141 }
142
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700143 bool SetCpuRtRuntime(int rt_runtime) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700144 state_->set_cpu_rt_runtime_count++;
145 return state_->set_cpu_ret;
146 }
147
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700148 bool SetCpuRtPeriod(int rt_period) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700149 state_->set_cpu_rt_period_count++;
150 return state_->set_cpu_ret;
151 }
152
153 private:
154 MockCgroupState* const state_;
155
156 DISALLOW_COPY_AND_ASSIGN(MockCgroup);
157};
158
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700159struct MockMinijailState {
160 std::string alt_syscall_table;
161 int ipc_called_count;
162 int vfs_called_count;
163 int net_called_count;
164 int pids_called_count;
165 int run_as_init_called_count;
166 int user_called_count;
167 int cgroups_called_count;
168 int wait_called_count;
169 int reset_signal_mask_called_count;
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -0700170 int reset_signal_handlers_called_count;
Risanfd41aee2018-08-15 14:03:38 +0900171 int set_supplementary_gids_called_count;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700172 int pid;
173 std::map<minijail_hook_event_t, std::vector<MinijailHookCallback>> hooks;
174};
175MockMinijailState* g_mock_minijail_state = nullptr;
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700176
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700177} // namespace
Dylan Reid837c74a2016-01-22 17:25:21 -0800178
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700179TEST(LibcontainerTest, PremountedRunfs) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700180 char premounted_runfs[] = "/tmp/cgtest_run/root";
181 struct container_config* config = container_config_create();
182 ASSERT_NE(nullptr, config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700183
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700184 container_config_premounted_runfs(config, premounted_runfs);
185 const char* result = container_config_get_premounted_runfs(config);
186 ASSERT_EQ(0, strcmp(result, premounted_runfs));
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700187
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700188 container_config_destroy(config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700189}
190
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700191TEST(LibcontainerTest, PidFilePath) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700192 char pid_file_path[] = "/tmp/cgtest_run/root/container.pid";
193 struct container_config* config = container_config_create();
194 ASSERT_NE(nullptr, config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700195
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700196 container_config_pid_file(config, pid_file_path);
197 const char* result = container_config_get_pid_file(config);
198 ASSERT_EQ(0, strcmp(result, pid_file_path));
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700199
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700200 container_config_destroy(config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700201}
202
yusukesbbc37a72017-11-21 09:51:54 -0800203TEST(LibcontainerTest, DumpConfig) {
204 struct container_config* config = container_config_create();
205 ASSERT_NE(nullptr, config);
206
207 // Confirm that container_config_dump() returns a non-empty string.
208 std::unique_ptr<char, decltype(&free)> config_str(
yusukes32622542018-01-05 18:59:52 -0800209 container_config_dump(config, false /* sort_vector */), free);
yusukesbbc37a72017-11-21 09:51:54 -0800210 ASSERT_NE(nullptr, config_str.get());
211 EXPECT_NE(0U, strlen(config_str.get()));
212
213 // Also confirm that the string has multiple lines.
214 EXPECT_LT(1U, base::SplitString(config_str.get(), "\n", base::KEEP_WHITESPACE,
215 base::SPLIT_WANT_NONEMPTY)
216 .size());
217
218 container_config_destroy(config);
219}
220
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700221class ContainerTest : public ::testing::Test {
222 public:
223 ContainerTest() = default;
224 ~ContainerTest() override = default;
Dylan Reid837c74a2016-01-22 17:25:21 -0800225
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700226 void SetUp() override {
227 g_mock_posix_state = new MockPosixState();
228 g_mock_cgroup_state = new MockCgroupState();
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700229 g_mock_minijail_state = new MockMinijailState();
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700230 libcontainer::Cgroup::SetCgroupFactoryForTesting(&MockCgroup::Create);
Dylan Reid837c74a2016-01-22 17:25:21 -0800231
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700232 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700233
Satoru Takabayashicf730fb2018-08-03 16:42:36 +0900234 ASSERT_TRUE(base::CreateTemporaryDirInDir(temp_dir_.GetPath(),
235 "container_test", &rootfs_));
Dylan Reid837c74a2016-01-22 17:25:21 -0800236
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700237 mount_flags_ = MS_NOSUID | MS_NODEV | MS_NOEXEC;
Dylan Reid837c74a2016-01-22 17:25:21 -0800238
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700239 config_.reset(new Config());
240 container_config_uid_map(config_->get(), "0 0 4294967295");
241 container_config_gid_map(config_->get(), "0 0 4294967295");
242 container_config_rootfs(config_->get(), rootfs_.value().c_str());
Dylan Reid837c74a2016-01-22 17:25:21 -0800243
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700244 static const char* kArgv[] = {
245 "/sbin/init",
246 };
247 container_config_program_argv(config_->get(), kArgv, 1);
248 container_config_alt_syscall_table(config_->get(), "testsyscalltable");
249 container_config_add_mount(config_->get(),
250 "testtmpfs",
251 "tmpfs",
252 "/tmp",
253 "tmpfs",
254 nullptr,
255 nullptr,
256 mount_flags_,
257 0,
258 1000,
259 1000,
260 0x666,
261 0,
262 0);
263 container_config_add_device(config_->get(),
264 'c',
265 "/dev/foo",
266 S_IRWXU | S_IRWXG,
267 245,
268 2,
269 0,
Stephen Barber7bae6642017-11-30 10:47:12 -0800270 0,
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700271 1000,
272 1001,
273 1,
274 1,
275 0);
276 // test dynamic minor on /dev/null
277 container_config_add_device(config_->get(),
278 'c',
279 "/dev/null",
280 S_IRWXU | S_IRWXG,
281 1,
282 -1,
Stephen Barber7bae6642017-11-30 10:47:12 -0800283 0,
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700284 1,
285 1000,
286 1001,
287 1,
288 1,
289 0);
Stephen Barber771653f2017-10-04 23:48:57 -0700290 static const char* kNamespaces[] = {
291 "cgroup",
292 "ipc",
293 "mount",
294 "network",
295 "pid",
296 "user",
297 };
298 container_config_namespaces(config_->get(), kNamespaces,
299 arraysize(kNamespaces));
Dylan Reid837c74a2016-01-22 17:25:21 -0800300
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700301 container_config_set_cpu_shares(config_->get(), kTestCpuShares);
302 container_config_set_cpu_cfs_params(
303 config_->get(), kTestCpuQuota, kTestCpuPeriod);
304 /* Invalid params, so this won't be applied. */
305 container_config_set_cpu_rt_params(config_->get(), 20000, 20000);
Dylan Reid837c74a2016-01-22 17:25:21 -0800306
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700307 base::FilePath rundir;
Satoru Takabayashicf730fb2018-08-03 16:42:36 +0900308 ASSERT_TRUE(base::CreateTemporaryDirInDir(temp_dir_.GetPath(),
309 "container_test_run", &rundir));
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700310 container_.reset(new Container("containerUT", rundir));
311 ASSERT_NE(nullptr, container_.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700312 }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700313
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700314 void TearDown() override {
315 container_.reset();
316 config_.reset();
Dylan Reid837c74a2016-01-22 17:25:21 -0800317
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700318 ASSERT_TRUE(temp_dir_.Delete());
319 delete g_mock_posix_state;
320 g_mock_posix_state = nullptr;
321 libcontainer::Cgroup::SetCgroupFactoryForTesting(nullptr);
322 delete g_mock_cgroup_state;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700323 delete g_mock_minijail_state;
324 g_mock_minijail_state = nullptr;
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700325 }
326
327 protected:
yusukesbbc37a72017-11-21 09:51:54 -0800328 const Config* config() const { return config_.get(); }
329
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700330 std::unique_ptr<Config> config_;
331 std::unique_ptr<Container> container_;
332 int mount_flags_;
333 base::FilePath rootfs_;
334
335 private:
336 base::ScopedTempDir temp_dir_;
337
338 DISALLOW_COPY_AND_ASSIGN(ContainerTest);
339};
340
341TEST_F(ContainerTest, TestMountTmpStart) {
342 ASSERT_EQ(0, container_start(container_->get(), config_->get()));
343 ASSERT_EQ(2, g_mock_posix_state->mount_args.size());
344 EXPECT_EQ(false, g_mock_posix_state->mount_args[1].outside_mount);
345 EXPECT_STREQ("tmpfs", g_mock_posix_state->mount_args[1].source.c_str());
346 EXPECT_STREQ("/tmp",
347 g_mock_posix_state->mount_args[1].target.value().c_str());
348 EXPECT_STREQ("tmpfs",
349 g_mock_posix_state->mount_args[1].filesystemtype.c_str());
350 EXPECT_EQ(g_mock_posix_state->mount_args[1].mountflags,
351 static_cast<unsigned long>(mount_flags_));
352 EXPECT_EQ(nullptr, g_mock_posix_state->mount_args[1].data);
Dylan Reid837c74a2016-01-22 17:25:21 -0800353
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700354 EXPECT_EQ(1, g_mock_minijail_state->ipc_called_count);
355 EXPECT_EQ(1, g_mock_minijail_state->vfs_called_count);
356 EXPECT_EQ(1, g_mock_minijail_state->net_called_count);
357 EXPECT_EQ(1, g_mock_minijail_state->pids_called_count);
358 EXPECT_EQ(1, g_mock_minijail_state->user_called_count);
359 EXPECT_EQ(1, g_mock_minijail_state->cgroups_called_count);
360 EXPECT_EQ(1, g_mock_minijail_state->run_as_init_called_count);
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700361 EXPECT_EQ(1, g_mock_cgroup_state->deny_all_devs_called_count);
Dylan Reid837c74a2016-01-22 17:25:21 -0800362
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700363 ASSERT_EQ(2, g_mock_cgroup_state->added_devices.size());
364 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].allow);
365 EXPECT_EQ(245, g_mock_cgroup_state->added_devices[0].major);
366 EXPECT_EQ(2, g_mock_cgroup_state->added_devices[0].minor);
367 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].read);
368 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].write);
369 EXPECT_EQ(0, g_mock_cgroup_state->added_devices[0].modify);
370 EXPECT_EQ('c', g_mock_cgroup_state->added_devices[0].type);
Dylan Reid355d5e42016-04-29 16:53:31 -0700371
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700372 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].allow);
373 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].major);
374 EXPECT_EQ(-1, g_mock_cgroup_state->added_devices[1].minor);
375 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].read);
376 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].write);
377 EXPECT_EQ(0, g_mock_cgroup_state->added_devices[1].modify);
378 EXPECT_EQ('c', g_mock_cgroup_state->added_devices[1].type);
Dylan Reid837c74a2016-01-22 17:25:21 -0800379
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700380 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_shares_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700381 EXPECT_EQ(kTestCpuShares, container_config_get_cpu_shares(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700382 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_quota_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700383 EXPECT_EQ(kTestCpuQuota, container_config_get_cpu_quota(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700384 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_period_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700385 EXPECT_EQ(kTestCpuPeriod, container_config_get_cpu_period(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700386 EXPECT_EQ(0, g_mock_cgroup_state->set_cpu_rt_runtime_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700387 EXPECT_EQ(0, container_config_get_cpu_rt_runtime(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700388 EXPECT_EQ(0, g_mock_cgroup_state->set_cpu_rt_period_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700389 EXPECT_EQ(0, container_config_get_cpu_rt_period(config_->get()));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800390
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700391 ASSERT_NE(std::string(), g_mock_minijail_state->alt_syscall_table);
392 EXPECT_EQ("testsyscalltable", g_mock_minijail_state->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800393
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700394 EXPECT_EQ(0, container_wait(container_->get()));
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700395 EXPECT_EQ(1, g_mock_minijail_state->wait_called_count);
396 EXPECT_EQ(1, g_mock_minijail_state->reset_signal_mask_called_count);
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -0700397 EXPECT_EQ(1, g_mock_minijail_state->reset_signal_handlers_called_count);
Risanfd41aee2018-08-15 14:03:38 +0900398 EXPECT_EQ(0, g_mock_minijail_state->set_supplementary_gids_called_count);
Dylan Reid837c74a2016-01-22 17:25:21 -0800399}
400
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700401TEST_F(ContainerTest, TestKillContainer) {
402 ASSERT_EQ(0, container_start(container_->get(), config_->get()));
403 EXPECT_EQ(0, container_kill(container_->get()));
404 EXPECT_EQ(std::vector<int>{SIGKILL}, g_mock_posix_state->kill_sigs);
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700405 EXPECT_EQ(1, g_mock_minijail_state->wait_called_count);
Dylan Reid837c74a2016-01-22 17:25:21 -0800406}
407
yusukesbbc37a72017-11-21 09:51:54 -0800408// Does the same as LibcontainerTest.DumpConfig but with more configuration
409// parameters similar to the production.
410TEST_F(ContainerTest, DumpConfig) {
411 struct container_config* config = this->config()->get();
412 ASSERT_NE(nullptr, config);
413 std::unique_ptr<char, decltype(&free)> config_str(
yusukes32622542018-01-05 18:59:52 -0800414 container_config_dump(config, true /* sort_vector */), free);
yusukesbbc37a72017-11-21 09:51:54 -0800415 ASSERT_NE(nullptr, config_str.get());
416 EXPECT_NE(0U, strlen(config_str.get()));
417 EXPECT_LT(1U, base::SplitString(config_str.get(), "\n", base::KEEP_WHITESPACE,
418 base::SPLIT_WANT_NONEMPTY)
419 .size());
420}
421
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700422} // namespace libcontainer
423
424// libc stubs so the UT doesn't need root to call mount, etc.
Luis Hector Chavezf9b16872017-09-14 14:22:15 -0700425extern "C" {
426
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700427extern decltype(chmod) __real_chmod;
428int __wrap_chmod(const char* path, mode_t mode) {
429 if (!libcontainer::g_mock_posix_state)
430 return __real_chmod(path, mode);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700431 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800432}
433
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700434extern decltype(chown) __real_chown;
435int __wrap_chown(const char* path, uid_t owner, gid_t group) {
436 if (!libcontainer::g_mock_posix_state)
437 return __real_chown(path, owner, group);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700438 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800439}
440
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700441extern decltype(getuid) __real_getuid;
442uid_t __wrap_getuid(void) {
443 if (!libcontainer::g_mock_posix_state)
444 return __real_getuid();
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700445 return 0;
446}
447
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700448extern decltype(kill) __real_kill;
449int __wrap_kill(pid_t pid, int sig) {
450 if (!libcontainer::g_mock_posix_state)
451 return __real_kill(pid, sig);
452 libcontainer::g_mock_posix_state->kill_sigs.push_back(sig);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700453 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800454}
455
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700456extern decltype(mkdir) __real_mkdir;
457int __wrap_mkdir(const char* pathname, mode_t mode) {
458 if (!libcontainer::g_mock_posix_state)
459 return __real_mkdir(pathname, mode);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700460 return 0;
Luis Hector Chavez836d7b22017-09-14 15:11:15 -0700461}
Dylan Reid837c74a2016-01-22 17:25:21 -0800462
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700463extern decltype(mkdtemp) __real_mkdtemp;
464char* __wrap_mkdtemp(char* template_string) {
465 if (!libcontainer::g_mock_posix_state)
466 return __real_mkdtemp(template_string);
467 libcontainer::g_mock_posix_state->mkdtemp_root =
468 base::FilePath(template_string);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700469 return template_string;
Dylan Reid837c74a2016-01-22 17:25:21 -0800470}
471
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700472extern decltype(mount) __real_mount;
473int __wrap_mount(const char* source,
474 const char* target,
475 const char* filesystemtype,
476 unsigned long mountflags,
477 const void* data) {
478 if (!libcontainer::g_mock_posix_state)
479 return __real_mount(source, target, filesystemtype, mountflags, data);
480
481 libcontainer::g_mock_posix_state->mount_args.emplace_back(
482 libcontainer::MockPosixState::MountArgs{source,
483 base::FilePath(target),
484 filesystemtype,
485 mountflags,
486 data,
487 true});
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700488 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800489}
490
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700491extern decltype(rmdir) __real_rmdir;
492int __wrap_rmdir(const char* pathname) {
493 if (!libcontainer::g_mock_posix_state)
494 return __real_rmdir(pathname);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700495 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800496}
497
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700498extern decltype(umount) __real_umount;
499int __wrap_umount(const char* target) {
500 if (!libcontainer::g_mock_posix_state)
501 return __real_umount(target);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700502 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800503}
504
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700505extern decltype(umount2) __real_umount2;
506int __wrap_umount2(const char* target, int flags) {
507 if (!libcontainer::g_mock_posix_state)
508 return __real_umount2(target, flags);
509 return 0;
510}
511
512extern decltype(unlink) __real_unlink;
513int __wrap_unlink(const char* pathname) {
514 if (!libcontainer::g_mock_posix_state)
515 return __real_unlink(pathname);
516 return 0;
517}
518
519extern decltype(__xmknod) __real___xmknod;
520int __wrap___xmknod(int ver, const char* pathname, mode_t mode, dev_t* dev) {
521 if (!libcontainer::g_mock_posix_state)
522 return __real___xmknod(ver, pathname, mode, dev);
523 return 0;
524}
525
526extern decltype(__xstat) __real___xstat;
527int __wrap___xstat(int ver, const char* path, struct stat* buf) {
528 if (!libcontainer::g_mock_posix_state)
529 return __real___xstat(ver, path, buf);
530 buf->st_rdev = libcontainer::g_mock_posix_state->stat_rdev_ret;
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700531 return 0;
532}
533
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700534extern decltype(setns) __real_setns;
535int __wrap_setns(int fd, int nstype) {
536 if (!libcontainer::g_mock_posix_state)
537 return __real_setns(fd, nstype);
538 return 0;
539}
540
Dylan Reid837c74a2016-01-22 17:25:21 -0800541/* Minijail stubs */
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700542struct minijail* minijail_new(void) {
543 return (struct minijail*)0x55;
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800544}
545
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700546void minijail_destroy(struct minijail* j) {}
547
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700548int minijail_mount_with_data(struct minijail* j,
549 const char* source,
550 const char* target,
551 const char* filesystemtype,
552 unsigned long mountflags,
553 const char* data) {
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700554 libcontainer::g_mock_posix_state->mount_args.emplace_back(
555 libcontainer::MockPosixState::MountArgs{source,
556 base::FilePath(target),
557 filesystemtype,
558 mountflags,
559 data,
560 false});
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700561 return 0;
562}
563
Luis Hector Chavezedec56e2017-09-19 15:43:53 -0700564void minijail_namespace_user_disable_setgroups(struct minijail* j) {}
Dylan Reid837c74a2016-01-22 17:25:21 -0800565
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700566void minijail_namespace_vfs(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700567 ++libcontainer::g_mock_minijail_state->vfs_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800568}
569
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700570void minijail_namespace_ipc(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700571 ++libcontainer::g_mock_minijail_state->ipc_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800572}
573
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700574void minijail_namespace_net(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700575 ++libcontainer::g_mock_minijail_state->net_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800576}
577
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700578void minijail_namespace_pids(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700579 ++libcontainer::g_mock_minijail_state->pids_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800580}
581
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700582void minijail_namespace_user(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700583 ++libcontainer::g_mock_minijail_state->user_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800584}
585
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700586void minijail_namespace_cgroups(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700587 ++libcontainer::g_mock_minijail_state->cgroups_called_count;
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700588}
589
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700590int minijail_uidmap(struct minijail* j, const char* uidmap) {
591 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800592}
593
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700594int minijail_gidmap(struct minijail* j, const char* gidmap) {
595 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800596}
597
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700598int minijail_enter_pivot_root(struct minijail* j, const char* dir) {
599 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800600}
601
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700602void minijail_run_as_init(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700603 ++libcontainer::g_mock_minijail_state->run_as_init_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800604}
605
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700606int minijail_run_pid_pipes_no_preload(struct minijail* j,
607 const char* filename,
608 char* const argv[],
609 pid_t* pchild_pid,
610 int* pstdin_fd,
611 int* pstdout_fd,
612 int* pstderr_fd) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700613 libcontainer::g_mock_minijail_state->pid = fork();
614 if (libcontainer::g_mock_minijail_state->pid == -1)
615 return libcontainer::g_mock_minijail_state->pid;
616
617 if (libcontainer::g_mock_minijail_state->pid == 0) {
618 for (minijail_hook_event_t event : {MINIJAIL_HOOK_EVENT_PRE_CHROOT,
619 MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS,
620 MINIJAIL_HOOK_EVENT_PRE_EXECVE}) {
621 auto it = libcontainer::g_mock_minijail_state->hooks.find(event);
622 if (it == libcontainer::g_mock_minijail_state->hooks.end())
623 continue;
624 for (auto& hook : it->second) {
625 int rc = hook.Run();
626 if (rc)
627 _exit(rc);
628 }
629 }
630 _exit(0);
631 }
632
633 *pchild_pid = libcontainer::g_mock_minijail_state->pid;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700634 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800635}
636
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700637int minijail_write_pid_file(struct minijail* j, const char* path) {
638 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800639}
640
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700641int minijail_wait(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700642 ++libcontainer::g_mock_minijail_state->wait_called_count;
643 int status;
644 if (HANDLE_EINTR(
645 waitpid(libcontainer::g_mock_minijail_state->pid, &status, 0)) < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700646 PLOG(ERROR) << "Failed to wait for minijail";
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700647 return -errno;
648 }
649 if (!WIFEXITED(status)) {
650 LOG(ERROR) << "minijail terminated abnormally: " << std::hex << status;
651 return -ECANCELED;
652 }
653 // Exit status gets truncated to 8 bits. This should sign-extend it so that
654 // any negative values we passed are preserved.
655 return static_cast<int8_t>(WEXITSTATUS(status));
Dylan Reid837c74a2016-01-22 17:25:21 -0800656}
657
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700658int minijail_use_alt_syscall(struct minijail* j, const char* table) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700659 libcontainer::g_mock_minijail_state->alt_syscall_table = table;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700660 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800661}
662
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700663int minijail_add_to_cgroup(struct minijail* j, const char* cg_path) {
664 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800665}
666
Chris Morin404a2692019-06-14 17:46:56 -0700667int minijail_forward_signals(struct minijail* j) {
668 return 0;
669}
670
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700671void minijail_reset_signal_mask(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700672 ++libcontainer::g_mock_minijail_state->reset_signal_mask_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800673}
674
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -0700675void minijail_reset_signal_handlers(struct minijail* j) {
676 ++libcontainer::g_mock_minijail_state->reset_signal_handlers_called_count;
677}
678
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700679void minijail_skip_remount_private(struct minijail* j) {}
Dylan Reid837c74a2016-01-22 17:25:21 -0800680
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700681int minijail_preserve_fd(struct minijail* j, int parent_fd, int child_fd) {
682 return 0;
683}
684
685int minijail_add_hook(struct minijail* j,
686 minijail_hook_t hook,
687 void* payload,
688 minijail_hook_event_t event) {
689 auto it = libcontainer::g_mock_minijail_state->hooks.insert(
690 std::make_pair(event, std::vector<libcontainer::MinijailHookCallback>()));
691 it.first->second.emplace_back(base::Bind(hook, base::Unretained(payload)));
692 return 0;
693}
694
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700695void minijail_close_open_fds(struct minijail* j) {}
696
Risanfd41aee2018-08-15 14:03:38 +0900697void minijail_set_supplementary_gids(struct minijail* j,
698 size_t size,
699 const gid_t* list) {
700 ++libcontainer::g_mock_minijail_state->set_supplementary_gids_called_count;
701}
702
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700703} // extern "C"