blob: 51385cbcbd88dcb0931c2db6f9b3ec6e83e76ee4 [file] [log] [blame]
Dylan Reid837c74a2016-01-22 17:25:21 -08001/* 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.
4 */
5
6#define _GNU_SOURCE /* For asprintf */
7
8#include <errno.h>
9#include <signal.h>
10#include <sys/mount.h>
11#include <sys/stat.h>
12#include <sys/types.h>
13#include <unistd.h>
14
15#include "test_harness.h"
16
17#include "container_cgroup.h"
18#include "libcontainer.h"
19
20static const pid_t INIT_TEST_PID = 5555;
Chinyue Chen4f3fd682016-07-01 14:11:42 +080021static const int TEST_CPU_SHARES = 200;
22static const int TEST_CPU_QUOTA = 20000;
23static const int TEST_CPU_PERIOD = 50000;
Dylan Reid837c74a2016-01-22 17:25:21 -080024
25struct mount_args {
26 char *source;
27 char *target;
28 char *filesystemtype;
29 unsigned long mountflags;
30 const void *data;
31};
32static struct mount_args mount_call_args[5];
33static int mount_called;
34
35struct mknod_args {
36 char *pathname;
37 mode_t mode;
38 dev_t dev;
39};
40static struct mknod_args mknod_call_args;
Chinyue Chen03c54ae2016-06-29 12:29:10 +080041static dev_t stat_rdev_ret;
Dylan Reid837c74a2016-01-22 17:25:21 -080042
43static int kill_called;
44static int kill_sig;
45static const char *minijail_alt_syscall_table;
46static int minijail_ipc_called;
47static int minijail_vfs_called;
48static int minijail_net_called;
49static int minijail_pids_called;
50static int minijail_run_as_init_called;
51static int minijail_user_called;
52static int minijail_wait_called;
53static int minijail_reset_signal_mask_called;
54static int mount_ret;
55static char *mkdtemp_root;
56
57/* global mock cgroup. */
Dylan Reid355d5e42016-04-29 16:53:31 -070058#define MAX_ADD_DEVICE_CALLS 2
Dylan Reid837c74a2016-01-22 17:25:21 -080059struct mock_cgroup {
60 struct container_cgroup cg;
61 int freeze_ret;
62 int thaw_ret;
63 int deny_all_devs_ret;
64 int add_device_ret;
Chinyue Chenfac909e2016-06-24 14:17:42 +080065 int set_cpu_ret;
Dylan Reid837c74a2016-01-22 17:25:21 -080066
67 int init_called_count;
68 int deny_all_devs_called_count;
69
Dylan Reid355d5e42016-04-29 16:53:31 -070070 int add_dev_major[MAX_ADD_DEVICE_CALLS];
71 int add_dev_minor[MAX_ADD_DEVICE_CALLS];
72 int add_dev_read[MAX_ADD_DEVICE_CALLS];
73 int add_dev_write[MAX_ADD_DEVICE_CALLS];
74 int add_dev_modify[MAX_ADD_DEVICE_CALLS];
75 char add_dev_type[MAX_ADD_DEVICE_CALLS];
76 int add_dev_called_count;
Chinyue Chenfac909e2016-06-24 14:17:42 +080077
78 int set_cpu_shares_count;
79 int set_cpu_quota_count;
80 int set_cpu_period_count;
81 int set_cpu_rt_runtime_count;
82 int set_cpu_rt_period_count;
Dylan Reid837c74a2016-01-22 17:25:21 -080083};
84
85static struct mock_cgroup gmcg;
86
87static int mock_freeze(const struct container_cgroup *cg)
88{
89 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
90 return mcg->freeze_ret;
91}
92
93static int mock_thaw(const struct container_cgroup *cg)
94{
95 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
96 return mcg->thaw_ret;
97}
98
99static int mock_deny_all_devices(const struct container_cgroup *cg)
100{
101 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
102 ++mcg->deny_all_devs_called_count;
103 return mcg->deny_all_devs_ret;
104}
105
106static int mock_add_device(const struct container_cgroup *cg, int major,
107 int minor, int read, int write, int modify,
108 char type)
109{
110 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
Dylan Reid355d5e42016-04-29 16:53:31 -0700111
112 if (mcg->add_dev_called_count >= MAX_ADD_DEVICE_CALLS)
113 return mcg->add_device_ret;
114 mcg->add_dev_major[mcg->add_dev_called_count] = major;
115 mcg->add_dev_minor[mcg->add_dev_called_count] = minor;
116 mcg->add_dev_read[mcg->add_dev_called_count] = read;
117 mcg->add_dev_write[mcg->add_dev_called_count] = write;
118 mcg->add_dev_modify[mcg->add_dev_called_count] = modify;
119 mcg->add_dev_type[mcg->add_dev_called_count] = type;
120 mcg->add_dev_called_count++;
Dylan Reid837c74a2016-01-22 17:25:21 -0800121 return mcg->add_device_ret;
122}
123
Chinyue Chenfac909e2016-06-24 14:17:42 +0800124static int mock_set_cpu_shares(const struct container_cgroup *cg, int shares)
125{
126 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
127 mcg->set_cpu_shares_count++;
128 return mcg->set_cpu_ret;
129}
130
131static int mock_set_cpu_quota(const struct container_cgroup *cg, int quota)
132{
133 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
134 mcg->set_cpu_quota_count++;
135 return mcg->set_cpu_ret;
136}
137
138static int mock_set_cpu_period(const struct container_cgroup *cg, int period)
139{
140 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
141 mcg->set_cpu_period_count++;
142 return mcg->set_cpu_ret;
143}
144
145static int mock_set_cpu_rt_runtime(const struct container_cgroup *cg, int rt_runtime)
146{
147 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
148 mcg->set_cpu_rt_runtime_count++;
149 return mcg->set_cpu_ret;
150}
151
152static int mock_set_cpu_rt_period(const struct container_cgroup *cg, int rt_period)
153{
154 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
155 mcg->set_cpu_rt_period_count++;
156 return mcg->set_cpu_ret;
157}
158
Dylan Reid837c74a2016-01-22 17:25:21 -0800159struct container_cgroup *container_cgroup_new(const char *name,
Keshav Santhanam998fd7d2016-07-12 13:33:00 -0700160 const char *cgroup_root,
161 const char *cgroup_parent)
Dylan Reid837c74a2016-01-22 17:25:21 -0800162{
163 gmcg.cg.name = strdup(name);
164 return &gmcg.cg;
165}
166
167void container_cgroup_destroy(struct container_cgroup *c)
168{
169 free(c->name);
170}
171
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700172TEST(premounted_runfs)
173{
174 char premounted_runfs[] = "/tmp/cgtest_run/root";
175 struct container_config *config = container_config_create();
176 ASSERT_NE(NULL, config);
177
178 container_config_premounted_runfs(config, premounted_runfs);
179 const char *result = container_config_get_premounted_runfs(config);
180 ASSERT_EQ(0, strcmp(result, premounted_runfs));
181
182 container_config_destroy(config);
183}
184
185TEST(pid_file_path)
186{
187 char pid_file_path[] = "/tmp/cgtest_run/root/container.pid";
188 struct container_config *config = container_config_create();
189 ASSERT_NE(NULL, config);
190
191 container_config_pid_file(config, pid_file_path);
192 const char *result = container_config_get_pid_file(config);
193 ASSERT_EQ(0, strcmp(result, pid_file_path));
194
195 container_config_destroy(config);
196}
197
Dylan Reid837c74a2016-01-22 17:25:21 -0800198/* Start of tests. */
199FIXTURE(container_test) {
200 struct container_config *config;
201 struct container *container;
202 int mount_flags;
203 char *rootfs;
204};
205
206FIXTURE_SETUP(container_test)
207{
208 char temp_template[] = "/tmp/cgtestXXXXXX";
209 char rundir_template[] = "/tmp/cgtest_runXXXXXX";
210 char *rundir;
211 char path[256];
212 char *pargs[] = {
213 "/sbin/init",
214 };
215
216 memset(&mount_call_args, 0, sizeof(mount_call_args));
217 mount_called = 0;
218 memset(&mknod_call_args, 0, sizeof(mknod_call_args));
219 mkdtemp_root = NULL;
220
221 memset(&gmcg, 0, sizeof(gmcg));
222 static const struct cgroup_ops cgops = {
223 .freeze = mock_freeze,
224 .thaw = mock_thaw,
225 .deny_all_devices = mock_deny_all_devices,
226 .add_device = mock_add_device,
Chinyue Chenfac909e2016-06-24 14:17:42 +0800227 .set_cpu_shares = mock_set_cpu_shares,
228 .set_cpu_quota = mock_set_cpu_quota,
229 .set_cpu_period = mock_set_cpu_period,
230 .set_cpu_rt_runtime = mock_set_cpu_rt_runtime,
231 .set_cpu_rt_period = mock_set_cpu_rt_period,
Dylan Reid837c74a2016-01-22 17:25:21 -0800232 };
233 gmcg.cg.ops = &cgops;
234
235 self->rootfs = strdup(mkdtemp(temp_template));
236
237 kill_called = 0;
238 minijail_alt_syscall_table = NULL;
239 minijail_ipc_called = 0;
240 minijail_vfs_called = 0;
241 minijail_net_called = 0;
242 minijail_pids_called = 0;
243 minijail_run_as_init_called = 0;
244 minijail_user_called = 0;
245 minijail_wait_called = 0;
246 minijail_reset_signal_mask_called = 0;
247 mount_ret = 0;
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800248 stat_rdev_ret = makedev(2, 3);
Dylan Reid837c74a2016-01-22 17:25:21 -0800249
250 snprintf(path, sizeof(path), "%s/dev", self->rootfs);
251 //mkdir(path, S_IRWXU | S_IRWXG);
252
253 self->mount_flags = MS_NOSUID | MS_NODEV | MS_NOEXEC;
254
255 self->config = container_config_create();
256 container_config_rootfs(self->config, self->rootfs);
257 container_config_program_argv(self->config, pargs, 1);
258 container_config_alt_syscall_table(self->config, "testsyscalltable");
259 container_config_add_mount(self->config,
260 "testtmpfs",
261 "tmpfs",
262 "/tmp",
263 "tmpfs",
264 NULL,
265 self->mount_flags,
266 1000,
267 1000,
268 0x666,
269 0,
270 1);
271 container_config_add_device(self->config,
272 'c',
273 "/dev/foo",
274 S_IRWXU | S_IRWXG,
275 245,
276 2,
Dylan Reid355d5e42016-04-29 16:53:31 -0700277 0,
278 1000,
279 1001,
280 1,
281 1,
282 0);
283 /* test dynamic minor on /dev/null */
284 container_config_add_device(self->config,
285 'c',
286 "/dev/null",
287 S_IRWXU | S_IRWXG,
288 1,
289 -1,
290 1,
Dylan Reid837c74a2016-01-22 17:25:21 -0800291 1000,
292 1001,
293 1,
294 1,
295 0);
296
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800297 container_config_set_cpu_shares(self->config, TEST_CPU_SHARES);
298 container_config_set_cpu_cfs_params(
299 self->config, TEST_CPU_QUOTA, TEST_CPU_PERIOD);
Chinyue Chenfac909e2016-06-24 14:17:42 +0800300 /* Invalid params, so this won't be applied. */
301 container_config_set_cpu_rt_params(self->config, 20000, 20000);
302
Dylan Reid837c74a2016-01-22 17:25:21 -0800303 rundir = mkdtemp(rundir_template);
Dylan Reide040c6b2016-05-02 18:49:02 -0700304 self->container = container_new("containerUT", rundir);
Dylan Reid837c74a2016-01-22 17:25:21 -0800305 ASSERT_NE(NULL, self->container);
306}
307
308FIXTURE_TEARDOWN(container_test)
309{
310 char path[256];
311 int i;
312
313 container_destroy(self->container);
314 snprintf(path, sizeof(path), "rm -rf %s", self->rootfs);
315 EXPECT_EQ(0, system(path));
316 free(self->rootfs);
317
318 for (i = 0; i < mount_called; i++) {
319 free(mount_call_args[i].source);
320 free(mount_call_args[i].target);
321 free(mount_call_args[i].filesystemtype);
322 }
323 free(mknod_call_args.pathname);
324 free(mkdtemp_root);
325}
326
327TEST_F(container_test, test_mount_tmp_start)
328{
329 char *path;
330
Dylan Reide040c6b2016-05-02 18:49:02 -0700331 EXPECT_EQ(0, container_start(self->container, self->config));
Dylan Reid837c74a2016-01-22 17:25:21 -0800332 EXPECT_EQ(2, mount_called);
333 EXPECT_EQ(0, strcmp(mount_call_args[1].source, "tmpfs"));
334 EXPECT_LT(0, asprintf(&path, "%s/root/tmp", mkdtemp_root));
335 EXPECT_EQ(0, strcmp(mount_call_args[1].target, path));
336 free(path);
337 EXPECT_EQ(0, strcmp(mount_call_args[1].filesystemtype,
338 "tmpfs"));
339 EXPECT_EQ(mount_call_args[1].mountflags, self->mount_flags);
340 EXPECT_EQ(mount_call_args[1].data, NULL);
341
342 EXPECT_EQ(1, minijail_ipc_called);
343 EXPECT_EQ(1, minijail_vfs_called);
344 EXPECT_EQ(1, minijail_net_called);
345 EXPECT_EQ(1, minijail_pids_called);
346 EXPECT_EQ(1, minijail_user_called);
347 EXPECT_EQ(1, minijail_run_as_init_called);
348 EXPECT_EQ(1, gmcg.deny_all_devs_called_count);
349
Dylan Reid355d5e42016-04-29 16:53:31 -0700350 EXPECT_EQ(245, gmcg.add_dev_major[0]);
351 EXPECT_EQ(2, gmcg.add_dev_minor[0]);
352 EXPECT_EQ(1, gmcg.add_dev_read[0]);
353 EXPECT_EQ(1, gmcg.add_dev_write[0]);
354 EXPECT_EQ(0, gmcg.add_dev_modify[0]);
355 EXPECT_EQ('c', gmcg.add_dev_type[0]);
356
357 EXPECT_EQ(1, gmcg.add_dev_major[1]);
358 EXPECT_EQ(3, gmcg.add_dev_minor[1]);
359 EXPECT_EQ(1, gmcg.add_dev_read[1]);
360 EXPECT_EQ(1, gmcg.add_dev_write[1]);
361 EXPECT_EQ(0, gmcg.add_dev_modify[1]);
362 EXPECT_EQ('c', gmcg.add_dev_type[1]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800363
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800364 EXPECT_LT(0, asprintf(&path, "%s/root/dev/null", mkdtemp_root));
365 EXPECT_EQ(0, strcmp(mknod_call_args.pathname, path));
366 free(path);
367 EXPECT_EQ(mknod_call_args.mode, S_IRWXU | S_IRWXG | S_IFCHR);
368 EXPECT_EQ(mknod_call_args.dev, makedev(1, 3));
369
Chinyue Chenfac909e2016-06-24 14:17:42 +0800370 EXPECT_EQ(1, gmcg.set_cpu_shares_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800371 EXPECT_EQ(TEST_CPU_SHARES,
372 container_config_get_cpu_shares(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800373 EXPECT_EQ(1, gmcg.set_cpu_quota_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800374 EXPECT_EQ(TEST_CPU_QUOTA,
375 container_config_get_cpu_quota(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800376 EXPECT_EQ(1, gmcg.set_cpu_period_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800377 EXPECT_EQ(TEST_CPU_PERIOD,
378 container_config_get_cpu_period(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800379 EXPECT_EQ(0, gmcg.set_cpu_rt_runtime_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800380 EXPECT_EQ(0, container_config_get_cpu_rt_runtime(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800381 EXPECT_EQ(0, gmcg.set_cpu_rt_period_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800382 EXPECT_EQ(0, container_config_get_cpu_rt_period(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800383
Dylan Reid837c74a2016-01-22 17:25:21 -0800384 ASSERT_NE(NULL, minijail_alt_syscall_table);
385 EXPECT_EQ(0, strcmp(minijail_alt_syscall_table,
386 "testsyscalltable"));
387
388 EXPECT_EQ(0, container_wait(self->container));
389 EXPECT_EQ(1, minijail_wait_called);
390 EXPECT_EQ(1, minijail_reset_signal_mask_called);
391}
392
393TEST_F(container_test, test_kill_container)
394{
Dylan Reide040c6b2016-05-02 18:49:02 -0700395 EXPECT_EQ(0, container_start(self->container, self->config));
Dylan Reid837c74a2016-01-22 17:25:21 -0800396 EXPECT_EQ(0, container_kill(self->container));
397 EXPECT_EQ(1, kill_called);
398 EXPECT_EQ(SIGKILL, kill_sig);
399 EXPECT_EQ(1, minijail_wait_called);
400}
401
402/* libc stubs so the UT doesn't need root to call mount, etc. */
403int mount(const char *source, const char *target,
404 const char *filesystemtype, unsigned long mountflags,
405 const void *data)
406{
407 if (mount_called >= 5)
408 return 0;
409
410 mount_call_args[mount_called].source = strdup(source);
411 mount_call_args[mount_called].target = strdup(target);
412 mount_call_args[mount_called].filesystemtype = strdup(filesystemtype);
413 mount_call_args[mount_called].mountflags = mountflags;
414 mount_call_args[mount_called].data = data;
415 ++mount_called;
416 return 0;
417}
418
419int umount(const char *target)
420{
421 return 0;
422}
423
424int mknod(const char *pathname, mode_t mode, dev_t dev)
425{
426 mknod_call_args.pathname = strdup(pathname);
427 mknod_call_args.mode = mode;
428 mknod_call_args.dev = dev;
429 return 0;
430}
431
432int chown(const char *path, uid_t owner, gid_t group)
433{
434 return 0;
435};
436
437int kill(pid_t pid, int sig)
438{
439 ++kill_called;
440 kill_sig = sig;
441 return 0;
442}
443
444int stat(const char *path, struct stat *buf)
445{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800446 buf->st_rdev = stat_rdev_ret;
Dylan Reid837c74a2016-01-22 17:25:21 -0800447 return 0;
448}
449
450int chmod(const char *path, mode_t mode)
451{
452 return 0;
453}
454
455char *mkdtemp(char *template)
456{
457 mkdtemp_root = strdup(template);
458 return template;
459}
460
461int mkdir(const char *pathname, mode_t mode)
462{
463 return 0;
464}
465
466int rmdir(const char *pathname)
467{
468 return 0;
469}
470
471int unlink(const char *pathname)
472{
473 return 0;
474}
475
476/* Minijail stubs */
477struct minijail *minijail_new(void)
478{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800479 return (struct minijail *)0x55;
480}
481
482void minijail_destroy(struct minijail *j)
483{
Dylan Reid837c74a2016-01-22 17:25:21 -0800484}
485
486int minijail_mount(struct minijail *j, const char *src, const char *dest,
487 const char *type, unsigned long flags)
488{
489 return 0;
490}
491
492void minijail_namespace_vfs(struct minijail *j)
493{
494 ++minijail_vfs_called;
495}
496
497void minijail_namespace_ipc(struct minijail *j)
498{
499 ++minijail_ipc_called;
500}
501
502void minijail_namespace_net(struct minijail *j)
503{
504 ++minijail_net_called;
505}
506
507void minijail_namespace_pids(struct minijail *j)
508{
509 ++minijail_pids_called;
510}
511
512void minijail_namespace_user(struct minijail *j)
513{
514 ++minijail_user_called;
515}
516
517int minijail_uidmap(struct minijail *j, const char *uidmap)
518{
519 return 0;
520}
521
522int minijail_gidmap(struct minijail *j, const char *gidmap)
523{
524 return 0;
525}
526
527int minijail_enter_pivot_root(struct minijail *j, const char *dir)
528{
529 return 0;
530}
531
532void minijail_run_as_init(struct minijail *j)
533{
534 ++minijail_run_as_init_called;
535}
536
537int minijail_run_pid_pipes_no_preload(struct minijail *j, const char *filename,
538 char *const argv[], pid_t *pchild_pid,
539 int *pstdin_fd, int *pstdout_fd,
540 int *pstderr_fd)
541{
542 *pchild_pid = INIT_TEST_PID;
543 return 0;
544}
545
546int minijail_write_pid_file(struct minijail *j, const char *path)
547{
548 return 0;
549}
550
551int minijail_wait(struct minijail *j)
552{
553 ++minijail_wait_called;
554 return 0;
555}
556
557int minijail_use_alt_syscall(struct minijail *j, const char *table)
558{
559 minijail_alt_syscall_table = table;
560 return 0;
561}
562
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800563int minijail_add_to_cgroup(struct minijail *j, const char *cg_path)
Dylan Reid837c74a2016-01-22 17:25:21 -0800564{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800565 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800566}
567
568void minijail_reset_signal_mask(struct minijail *j)
569{
570 ++minijail_reset_signal_mask_called;
571}
572
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800573void minijail_skip_remount_private(struct minijail *j)
574{
575}
576
Dylan Reid837c74a2016-01-22 17:25:21 -0800577TEST_HARNESS_MAIN