blob: 2764212c1ade88c948f019aec5e0a3767b2007eb [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>
hscham4ce3c992021-02-19 16:37:23 +090022#include <base/callback_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) {}
Qijiang Fan6bc59e12020-11-11 02:51:06 +090097 MockCgroup(const MockCgroup&) = delete;
98 MockCgroup& operator=(const MockCgroup&) = delete;
99
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700100 ~MockCgroup() = default;
101
102 static std::unique_ptr<libcontainer::Cgroup> Create(
103 base::StringPiece name,
104 const base::FilePath& cgroup_root,
105 const base::FilePath& cgroup_parent,
106 uid_t cgroup_owner,
107 gid_t cgroup_group) {
Ben Chanc4929c62017-09-29 23:25:39 -0700108 return std::make_unique<MockCgroup>(g_mock_cgroup_state);
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700109 }
110
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700111 bool Freeze() override { return state_->freeze_ret; }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700112
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700113 bool Thaw() override { return state_->thaw_ret; }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700114
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700115 bool DenyAllDevices() override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700116 ++state_->deny_all_devs_called_count;
117 return state_->deny_all_devs_ret;
118 }
119
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700120 bool AddDevice(bool allow,
121 int major,
122 int minor,
123 bool read,
124 bool write,
125 bool modify,
126 char type) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700127 state_->added_devices.emplace_back(MockCgroupState::AddedDevice{
128 allow, major, minor, read, write, modify, type});
129 return state_->add_device_ret;
130 }
131
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700132 bool SetCpuShares(int shares) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700133 state_->set_cpu_shares_count++;
134 return state_->set_cpu_ret;
135 }
136
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700137 bool SetCpuQuota(int quota) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700138 state_->set_cpu_quota_count++;
139 return state_->set_cpu_ret;
140 }
141
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700142 bool SetCpuPeriod(int period) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700143 state_->set_cpu_period_count++;
144 return state_->set_cpu_ret;
145 }
146
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700147 bool SetCpuRtRuntime(int rt_runtime) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700148 state_->set_cpu_rt_runtime_count++;
149 return state_->set_cpu_ret;
150 }
151
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700152 bool SetCpuRtPeriod(int rt_period) override {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700153 state_->set_cpu_rt_period_count++;
154 return state_->set_cpu_ret;
155 }
156
157 private:
158 MockCgroupState* const state_;
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700159};
160
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700161struct MockMinijailState {
162 std::string alt_syscall_table;
163 int ipc_called_count;
164 int vfs_called_count;
165 int net_called_count;
166 int pids_called_count;
167 int run_as_init_called_count;
168 int user_called_count;
169 int cgroups_called_count;
170 int wait_called_count;
171 int reset_signal_mask_called_count;
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -0700172 int reset_signal_handlers_called_count;
Risanfd41aee2018-08-15 14:03:38 +0900173 int set_supplementary_gids_called_count;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700174 int pid;
175 std::map<minijail_hook_event_t, std::vector<MinijailHookCallback>> hooks;
176};
177MockMinijailState* g_mock_minijail_state = nullptr;
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700178
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700179} // namespace
Dylan Reid837c74a2016-01-22 17:25:21 -0800180
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700181TEST(LibcontainerTest, PremountedRunfs) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700182 char premounted_runfs[] = "/tmp/cgtest_run/root";
183 struct container_config* config = container_config_create();
184 ASSERT_NE(nullptr, config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700185
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700186 container_config_premounted_runfs(config, premounted_runfs);
187 const char* result = container_config_get_premounted_runfs(config);
188 ASSERT_EQ(0, strcmp(result, premounted_runfs));
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700189
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700190 container_config_destroy(config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700191}
192
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700193TEST(LibcontainerTest, PidFilePath) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700194 char pid_file_path[] = "/tmp/cgtest_run/root/container.pid";
195 struct container_config* config = container_config_create();
196 ASSERT_NE(nullptr, config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700197
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700198 container_config_pid_file(config, pid_file_path);
199 const char* result = container_config_get_pid_file(config);
200 ASSERT_EQ(0, strcmp(result, pid_file_path));
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700201
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700202 container_config_destroy(config);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700203}
204
yusukesbbc37a72017-11-21 09:51:54 -0800205TEST(LibcontainerTest, DumpConfig) {
206 struct container_config* config = container_config_create();
207 ASSERT_NE(nullptr, config);
208
209 // Confirm that container_config_dump() returns a non-empty string.
210 std::unique_ptr<char, decltype(&free)> config_str(
yusukes32622542018-01-05 18:59:52 -0800211 container_config_dump(config, false /* sort_vector */), free);
yusukesbbc37a72017-11-21 09:51:54 -0800212 ASSERT_NE(nullptr, config_str.get());
213 EXPECT_NE(0U, strlen(config_str.get()));
214
215 // Also confirm that the string has multiple lines.
216 EXPECT_LT(1U, base::SplitString(config_str.get(), "\n", base::KEEP_WHITESPACE,
217 base::SPLIT_WANT_NONEMPTY)
218 .size());
219
220 container_config_destroy(config);
221}
222
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700223class ContainerTest : public ::testing::Test {
224 public:
225 ContainerTest() = default;
Qijiang Fan6bc59e12020-11-11 02:51:06 +0900226 ContainerTest(const ContainerTest&) = delete;
227 ContainerTest& operator=(const ContainerTest&) = delete;
228
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700229 ~ContainerTest() override = default;
Dylan Reid837c74a2016-01-22 17:25:21 -0800230
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700231 void SetUp() override {
232 g_mock_posix_state = new MockPosixState();
233 g_mock_cgroup_state = new MockCgroupState();
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700234 g_mock_minijail_state = new MockMinijailState();
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700235 libcontainer::Cgroup::SetCgroupFactoryForTesting(&MockCgroup::Create);
Dylan Reid837c74a2016-01-22 17:25:21 -0800236
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700237 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700238
Satoru Takabayashicf730fb2018-08-03 16:42:36 +0900239 ASSERT_TRUE(base::CreateTemporaryDirInDir(temp_dir_.GetPath(),
240 "container_test", &rootfs_));
Dylan Reid837c74a2016-01-22 17:25:21 -0800241
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700242 mount_flags_ = MS_NOSUID | MS_NODEV | MS_NOEXEC;
Dylan Reid837c74a2016-01-22 17:25:21 -0800243
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700244 config_.reset(new Config());
245 container_config_uid_map(config_->get(), "0 0 4294967295");
246 container_config_gid_map(config_->get(), "0 0 4294967295");
247 container_config_rootfs(config_->get(), rootfs_.value().c_str());
Dylan Reid837c74a2016-01-22 17:25:21 -0800248
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700249 static const char* kArgv[] = {
250 "/sbin/init",
251 };
252 container_config_program_argv(config_->get(), kArgv, 1);
253 container_config_alt_syscall_table(config_->get(), "testsyscalltable");
Tom Hughes25f969a2020-08-27 15:57:27 -0700254 container_config_add_mount(config_->get(), "testtmpfs", "tmpfs", "/tmp",
255 "tmpfs", nullptr, nullptr, mount_flags_, 0, 1000,
256 1000, 0x666, 0, 0);
257 container_config_add_device(config_->get(), 'c', "/dev/foo",
258 S_IRWXU | S_IRWXG, 245, 2, 0, 0, 1000, 1001, 1,
259 1, 0);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700260 // test dynamic minor on /dev/null
Tom Hughes25f969a2020-08-27 15:57:27 -0700261 container_config_add_device(config_->get(), 'c', "/dev/null",
262 S_IRWXU | S_IRWXG, 1, -1, 0, 1, 1000, 1001, 1,
263 1, 0);
Stephen Barber771653f2017-10-04 23:48:57 -0700264 static const char* kNamespaces[] = {
Tom Hughes25f969a2020-08-27 15:57:27 -0700265 "cgroup", "ipc", "mount", "network", "pid", "user",
Stephen Barber771653f2017-10-04 23:48:57 -0700266 };
267 container_config_namespaces(config_->get(), kNamespaces,
Qijiang Fane19d67d2020-04-01 08:18:39 +0900268 base::size(kNamespaces));
Dylan Reid837c74a2016-01-22 17:25:21 -0800269
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700270 container_config_set_cpu_shares(config_->get(), kTestCpuShares);
Tom Hughes25f969a2020-08-27 15:57:27 -0700271 container_config_set_cpu_cfs_params(config_->get(), kTestCpuQuota,
272 kTestCpuPeriod);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700273 /* Invalid params, so this won't be applied. */
274 container_config_set_cpu_rt_params(config_->get(), 20000, 20000);
Dylan Reid837c74a2016-01-22 17:25:21 -0800275
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700276 base::FilePath rundir;
Satoru Takabayashicf730fb2018-08-03 16:42:36 +0900277 ASSERT_TRUE(base::CreateTemporaryDirInDir(temp_dir_.GetPath(),
278 "container_test_run", &rundir));
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700279 container_.reset(new Container("containerUT", rundir));
280 ASSERT_NE(nullptr, container_.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700281 }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700282
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700283 void TearDown() override {
284 container_.reset();
285 config_.reset();
Dylan Reid837c74a2016-01-22 17:25:21 -0800286
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700287 ASSERT_TRUE(temp_dir_.Delete());
288 delete g_mock_posix_state;
289 g_mock_posix_state = nullptr;
290 libcontainer::Cgroup::SetCgroupFactoryForTesting(nullptr);
291 delete g_mock_cgroup_state;
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700292 delete g_mock_minijail_state;
293 g_mock_minijail_state = nullptr;
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700294 }
295
296 protected:
yusukesbbc37a72017-11-21 09:51:54 -0800297 const Config* config() const { return config_.get(); }
298
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700299 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_;
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700306};
307
308TEST_F(ContainerTest, TestMountTmpStart) {
309 ASSERT_EQ(0, container_start(container_->get(), config_->get()));
310 ASSERT_EQ(2, g_mock_posix_state->mount_args.size());
311 EXPECT_EQ(false, g_mock_posix_state->mount_args[1].outside_mount);
312 EXPECT_STREQ("tmpfs", g_mock_posix_state->mount_args[1].source.c_str());
313 EXPECT_STREQ("/tmp",
314 g_mock_posix_state->mount_args[1].target.value().c_str());
315 EXPECT_STREQ("tmpfs",
316 g_mock_posix_state->mount_args[1].filesystemtype.c_str());
317 EXPECT_EQ(g_mock_posix_state->mount_args[1].mountflags,
318 static_cast<unsigned long>(mount_flags_));
319 EXPECT_EQ(nullptr, g_mock_posix_state->mount_args[1].data);
Dylan Reid837c74a2016-01-22 17:25:21 -0800320
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700321 EXPECT_EQ(1, g_mock_minijail_state->ipc_called_count);
322 EXPECT_EQ(1, g_mock_minijail_state->vfs_called_count);
323 EXPECT_EQ(1, g_mock_minijail_state->net_called_count);
324 EXPECT_EQ(1, g_mock_minijail_state->pids_called_count);
325 EXPECT_EQ(1, g_mock_minijail_state->user_called_count);
326 EXPECT_EQ(1, g_mock_minijail_state->cgroups_called_count);
327 EXPECT_EQ(1, g_mock_minijail_state->run_as_init_called_count);
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700328 EXPECT_EQ(1, g_mock_cgroup_state->deny_all_devs_called_count);
Dylan Reid837c74a2016-01-22 17:25:21 -0800329
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700330 ASSERT_EQ(2, g_mock_cgroup_state->added_devices.size());
331 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].allow);
332 EXPECT_EQ(245, g_mock_cgroup_state->added_devices[0].major);
333 EXPECT_EQ(2, g_mock_cgroup_state->added_devices[0].minor);
334 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].read);
335 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[0].write);
336 EXPECT_EQ(0, g_mock_cgroup_state->added_devices[0].modify);
337 EXPECT_EQ('c', g_mock_cgroup_state->added_devices[0].type);
Dylan Reid355d5e42016-04-29 16:53:31 -0700338
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700339 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].allow);
340 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].major);
341 EXPECT_EQ(-1, g_mock_cgroup_state->added_devices[1].minor);
342 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].read);
343 EXPECT_EQ(1, g_mock_cgroup_state->added_devices[1].write);
344 EXPECT_EQ(0, g_mock_cgroup_state->added_devices[1].modify);
345 EXPECT_EQ('c', g_mock_cgroup_state->added_devices[1].type);
Dylan Reid837c74a2016-01-22 17:25:21 -0800346
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700347 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_shares_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700348 EXPECT_EQ(kTestCpuShares, container_config_get_cpu_shares(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700349 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_quota_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700350 EXPECT_EQ(kTestCpuQuota, container_config_get_cpu_quota(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700351 EXPECT_EQ(1, g_mock_cgroup_state->set_cpu_period_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700352 EXPECT_EQ(kTestCpuPeriod, container_config_get_cpu_period(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700353 EXPECT_EQ(0, g_mock_cgroup_state->set_cpu_rt_runtime_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700354 EXPECT_EQ(0, container_config_get_cpu_rt_runtime(config_->get()));
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700355 EXPECT_EQ(0, g_mock_cgroup_state->set_cpu_rt_period_count);
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700356 EXPECT_EQ(0, container_config_get_cpu_rt_period(config_->get()));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800357
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700358 ASSERT_NE(std::string(), g_mock_minijail_state->alt_syscall_table);
359 EXPECT_EQ("testsyscalltable", g_mock_minijail_state->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800360
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700361 EXPECT_EQ(0, container_wait(container_->get()));
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700362 EXPECT_EQ(1, g_mock_minijail_state->wait_called_count);
363 EXPECT_EQ(1, g_mock_minijail_state->reset_signal_mask_called_count);
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -0700364 EXPECT_EQ(1, g_mock_minijail_state->reset_signal_handlers_called_count);
Risanfd41aee2018-08-15 14:03:38 +0900365 EXPECT_EQ(0, g_mock_minijail_state->set_supplementary_gids_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
yusukesbbc37a72017-11-21 09:51:54 -0800375// Does the same as LibcontainerTest.DumpConfig but with more configuration
376// parameters similar to the production.
377TEST_F(ContainerTest, DumpConfig) {
378 struct container_config* config = this->config()->get();
379 ASSERT_NE(nullptr, config);
380 std::unique_ptr<char, decltype(&free)> config_str(
yusukes32622542018-01-05 18:59:52 -0800381 container_config_dump(config, true /* sort_vector */), free);
yusukesbbc37a72017-11-21 09:51:54 -0800382 ASSERT_NE(nullptr, config_str.get());
383 EXPECT_NE(0U, strlen(config_str.get()));
384 EXPECT_LT(1U, base::SplitString(config_str.get(), "\n", base::KEEP_WHITESPACE,
385 base::SPLIT_WANT_NONEMPTY)
386 .size());
387}
388
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700389} // namespace libcontainer
390
391// libc stubs so the UT doesn't need root to call mount, etc.
Luis Hector Chavezf9b16872017-09-14 14:22:15 -0700392extern "C" {
393
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700394extern decltype(chmod) __real_chmod;
395int __wrap_chmod(const char* path, mode_t mode) {
396 if (!libcontainer::g_mock_posix_state)
397 return __real_chmod(path, mode);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700398 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800399}
400
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700401extern decltype(chown) __real_chown;
402int __wrap_chown(const char* path, uid_t owner, gid_t group) {
403 if (!libcontainer::g_mock_posix_state)
404 return __real_chown(path, owner, group);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700405 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800406}
407
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700408extern decltype(getuid) __real_getuid;
409uid_t __wrap_getuid(void) {
410 if (!libcontainer::g_mock_posix_state)
411 return __real_getuid();
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700412 return 0;
413}
414
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700415extern decltype(kill) __real_kill;
416int __wrap_kill(pid_t pid, int sig) {
417 if (!libcontainer::g_mock_posix_state)
418 return __real_kill(pid, sig);
419 libcontainer::g_mock_posix_state->kill_sigs.push_back(sig);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700420 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800421}
422
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700423extern decltype(mkdir) __real_mkdir;
424int __wrap_mkdir(const char* pathname, mode_t mode) {
425 if (!libcontainer::g_mock_posix_state)
426 return __real_mkdir(pathname, mode);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700427 return 0;
Luis Hector Chavez836d7b22017-09-14 15:11:15 -0700428}
Dylan Reid837c74a2016-01-22 17:25:21 -0800429
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700430extern decltype(mkdtemp) __real_mkdtemp;
431char* __wrap_mkdtemp(char* template_string) {
432 if (!libcontainer::g_mock_posix_state)
433 return __real_mkdtemp(template_string);
434 libcontainer::g_mock_posix_state->mkdtemp_root =
435 base::FilePath(template_string);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700436 return template_string;
Dylan Reid837c74a2016-01-22 17:25:21 -0800437}
438
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700439extern decltype(mount) __real_mount;
440int __wrap_mount(const char* source,
441 const char* target,
442 const char* filesystemtype,
443 unsigned long mountflags,
444 const void* data) {
445 if (!libcontainer::g_mock_posix_state)
446 return __real_mount(source, target, filesystemtype, mountflags, data);
447
448 libcontainer::g_mock_posix_state->mount_args.emplace_back(
Tom Hughes25f969a2020-08-27 15:57:27 -0700449 libcontainer::MockPosixState::MountArgs{source, base::FilePath(target),
450 filesystemtype, mountflags, data,
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700451 true});
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700452 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800453}
454
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700455extern decltype(rmdir) __real_rmdir;
456int __wrap_rmdir(const char* pathname) {
457 if (!libcontainer::g_mock_posix_state)
458 return __real_rmdir(pathname);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700459 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800460}
461
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700462extern decltype(umount) __real_umount;
463int __wrap_umount(const char* target) {
464 if (!libcontainer::g_mock_posix_state)
465 return __real_umount(target);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700466 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800467}
468
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700469extern decltype(umount2) __real_umount2;
470int __wrap_umount2(const char* target, int flags) {
471 if (!libcontainer::g_mock_posix_state)
472 return __real_umount2(target, flags);
473 return 0;
474}
475
476extern decltype(unlink) __real_unlink;
477int __wrap_unlink(const char* pathname) {
478 if (!libcontainer::g_mock_posix_state)
479 return __real_unlink(pathname);
480 return 0;
481}
482
483extern decltype(__xmknod) __real___xmknod;
484int __wrap___xmknod(int ver, const char* pathname, mode_t mode, dev_t* dev) {
485 if (!libcontainer::g_mock_posix_state)
486 return __real___xmknod(ver, pathname, mode, dev);
487 return 0;
488}
489
490extern decltype(__xstat) __real___xstat;
491int __wrap___xstat(int ver, const char* path, struct stat* buf) {
492 if (!libcontainer::g_mock_posix_state)
493 return __real___xstat(ver, path, buf);
494 buf->st_rdev = libcontainer::g_mock_posix_state->stat_rdev_ret;
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700495 return 0;
496}
497
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700498extern decltype(setns) __real_setns;
499int __wrap_setns(int fd, int nstype) {
500 if (!libcontainer::g_mock_posix_state)
501 return __real_setns(fd, nstype);
502 return 0;
503}
504
Dylan Reid837c74a2016-01-22 17:25:21 -0800505/* Minijail stubs */
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700506struct minijail* minijail_new(void) {
507 return (struct minijail*)0x55;
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800508}
509
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700510void minijail_destroy(struct minijail* j) {}
511
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700512int minijail_mount_with_data(struct minijail* j,
513 const char* source,
514 const char* target,
515 const char* filesystemtype,
516 unsigned long mountflags,
517 const char* data) {
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700518 libcontainer::g_mock_posix_state->mount_args.emplace_back(
Tom Hughes25f969a2020-08-27 15:57:27 -0700519 libcontainer::MockPosixState::MountArgs{source, base::FilePath(target),
520 filesystemtype, mountflags, data,
Luis Hector Chavez58725a82017-09-19 21:14:17 -0700521 false});
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700522 return 0;
523}
524
Luis Hector Chavezedec56e2017-09-19 15:43:53 -0700525void minijail_namespace_user_disable_setgroups(struct minijail* j) {}
Dylan Reid837c74a2016-01-22 17:25:21 -0800526
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700527void minijail_namespace_vfs(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700528 ++libcontainer::g_mock_minijail_state->vfs_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800529}
530
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700531void minijail_namespace_ipc(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700532 ++libcontainer::g_mock_minijail_state->ipc_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800533}
534
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700535void minijail_namespace_net(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700536 ++libcontainer::g_mock_minijail_state->net_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800537}
538
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700539void minijail_namespace_pids(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700540 ++libcontainer::g_mock_minijail_state->pids_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800541}
542
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700543void minijail_namespace_user(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700544 ++libcontainer::g_mock_minijail_state->user_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800545}
546
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700547void minijail_namespace_cgroups(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700548 ++libcontainer::g_mock_minijail_state->cgroups_called_count;
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700549}
550
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700551int minijail_uidmap(struct minijail* j, const char* uidmap) {
552 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800553}
554
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700555int minijail_gidmap(struct minijail* j, const char* gidmap) {
556 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800557}
558
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700559int minijail_enter_pivot_root(struct minijail* j, const char* dir) {
560 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800561}
562
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700563void minijail_run_as_init(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700564 ++libcontainer::g_mock_minijail_state->run_as_init_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800565}
566
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700567int minijail_run_pid_pipes_no_preload(struct minijail* j,
568 const char* filename,
569 char* const argv[],
570 pid_t* pchild_pid,
571 int* pstdin_fd,
572 int* pstdout_fd,
573 int* pstderr_fd) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700574 libcontainer::g_mock_minijail_state->pid = fork();
575 if (libcontainer::g_mock_minijail_state->pid == -1)
576 return libcontainer::g_mock_minijail_state->pid;
577
578 if (libcontainer::g_mock_minijail_state->pid == 0) {
Tom Hughes25f969a2020-08-27 15:57:27 -0700579 for (minijail_hook_event_t event :
580 {MINIJAIL_HOOK_EVENT_PRE_CHROOT, MINIJAIL_HOOK_EVENT_PRE_DROP_CAPS,
581 MINIJAIL_HOOK_EVENT_PRE_EXECVE}) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700582 auto it = libcontainer::g_mock_minijail_state->hooks.find(event);
583 if (it == libcontainer::g_mock_minijail_state->hooks.end())
584 continue;
585 for (auto& hook : it->second) {
586 int rc = hook.Run();
587 if (rc)
588 _exit(rc);
589 }
590 }
591 _exit(0);
592 }
593
594 *pchild_pid = libcontainer::g_mock_minijail_state->pid;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700595 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800596}
597
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700598int minijail_write_pid_file(struct minijail* j, const char* path) {
599 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800600}
601
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700602int minijail_wait(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700603 ++libcontainer::g_mock_minijail_state->wait_called_count;
604 int status;
605 if (HANDLE_EINTR(
606 waitpid(libcontainer::g_mock_minijail_state->pid, &status, 0)) < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700607 PLOG(ERROR) << "Failed to wait for minijail";
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700608 return -errno;
609 }
610 if (!WIFEXITED(status)) {
611 LOG(ERROR) << "minijail terminated abnormally: " << std::hex << status;
612 return -ECANCELED;
613 }
614 // Exit status gets truncated to 8 bits. This should sign-extend it so that
615 // any negative values we passed are preserved.
616 return static_cast<int8_t>(WEXITSTATUS(status));
Dylan Reid837c74a2016-01-22 17:25:21 -0800617}
618
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700619int minijail_use_alt_syscall(struct minijail* j, const char* table) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700620 libcontainer::g_mock_minijail_state->alt_syscall_table = table;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700621 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800622}
623
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700624int minijail_add_to_cgroup(struct minijail* j, const char* cg_path) {
625 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800626}
627
Chris Morin404a2692019-06-14 17:46:56 -0700628int minijail_forward_signals(struct minijail* j) {
629 return 0;
630}
631
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700632void minijail_reset_signal_mask(struct minijail* j) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700633 ++libcontainer::g_mock_minijail_state->reset_signal_mask_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -0800634}
635
Luis Hector Chavezcd9a6b62018-04-04 08:39:44 -0700636void minijail_reset_signal_handlers(struct minijail* j) {
637 ++libcontainer::g_mock_minijail_state->reset_signal_handlers_called_count;
638}
639
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700640void minijail_skip_remount_private(struct minijail* j) {}
Dylan Reid837c74a2016-01-22 17:25:21 -0800641
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700642int minijail_preserve_fd(struct minijail* j, int parent_fd, int child_fd) {
643 return 0;
644}
645
646int minijail_add_hook(struct minijail* j,
647 minijail_hook_t hook,
648 void* payload,
649 minijail_hook_event_t event) {
650 auto it = libcontainer::g_mock_minijail_state->hooks.insert(
651 std::make_pair(event, std::vector<libcontainer::MinijailHookCallback>()));
652 it.first->second.emplace_back(base::Bind(hook, base::Unretained(payload)));
653 return 0;
654}
655
Luis Hector Chavez9e03e172017-09-15 11:29:54 -0700656void minijail_close_open_fds(struct minijail* j) {}
657
Risanfd41aee2018-08-15 14:03:38 +0900658void minijail_set_supplementary_gids(struct minijail* j,
659 size_t size,
660 const gid_t* list) {
661 ++libcontainer::g_mock_minijail_state->set_supplementary_gids_called_count;
662}
663
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700664} // extern "C"