blob: 36a3ba61f8e9800e9e8a09b99f75822ae72573c2 [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 Reid4843d6b2017-03-31 18:14:30 -070070 int add_dev_allow[MAX_ADD_DEVICE_CALLS];
Dylan Reid355d5e42016-04-29 16:53:31 -070071 int add_dev_major[MAX_ADD_DEVICE_CALLS];
72 int add_dev_minor[MAX_ADD_DEVICE_CALLS];
73 int add_dev_read[MAX_ADD_DEVICE_CALLS];
74 int add_dev_write[MAX_ADD_DEVICE_CALLS];
75 int add_dev_modify[MAX_ADD_DEVICE_CALLS];
76 char add_dev_type[MAX_ADD_DEVICE_CALLS];
77 int add_dev_called_count;
Chinyue Chenfac909e2016-06-24 14:17:42 +080078
79 int set_cpu_shares_count;
80 int set_cpu_quota_count;
81 int set_cpu_period_count;
82 int set_cpu_rt_runtime_count;
83 int set_cpu_rt_period_count;
Dylan Reid837c74a2016-01-22 17:25:21 -080084};
85
86static struct mock_cgroup gmcg;
87
88static int mock_freeze(const struct container_cgroup *cg)
89{
90 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
91 return mcg->freeze_ret;
92}
93
94static int mock_thaw(const struct container_cgroup *cg)
95{
96 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
97 return mcg->thaw_ret;
98}
99
100static int mock_deny_all_devices(const struct container_cgroup *cg)
101{
102 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
103 ++mcg->deny_all_devs_called_count;
104 return mcg->deny_all_devs_ret;
105}
106
Dylan Reid4843d6b2017-03-31 18:14:30 -0700107static int mock_add_device(const struct container_cgroup *cg, int allow,
108 int major, int minor, int read, int write,
109 int modify, char type)
Dylan Reid837c74a2016-01-22 17:25:21 -0800110{
111 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
Dylan Reid355d5e42016-04-29 16:53:31 -0700112
113 if (mcg->add_dev_called_count >= MAX_ADD_DEVICE_CALLS)
114 return mcg->add_device_ret;
Dylan Reid4843d6b2017-03-31 18:14:30 -0700115 mcg->add_dev_allow[mcg->add_dev_called_count] = allow;
Dylan Reid355d5e42016-04-29 16:53:31 -0700116 mcg->add_dev_major[mcg->add_dev_called_count] = major;
117 mcg->add_dev_minor[mcg->add_dev_called_count] = minor;
118 mcg->add_dev_read[mcg->add_dev_called_count] = read;
119 mcg->add_dev_write[mcg->add_dev_called_count] = write;
120 mcg->add_dev_modify[mcg->add_dev_called_count] = modify;
121 mcg->add_dev_type[mcg->add_dev_called_count] = type;
122 mcg->add_dev_called_count++;
Dylan Reid837c74a2016-01-22 17:25:21 -0800123 return mcg->add_device_ret;
124}
125
Chinyue Chenfac909e2016-06-24 14:17:42 +0800126static int mock_set_cpu_shares(const struct container_cgroup *cg, int shares)
127{
128 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
129 mcg->set_cpu_shares_count++;
130 return mcg->set_cpu_ret;
131}
132
133static int mock_set_cpu_quota(const struct container_cgroup *cg, int quota)
134{
135 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
136 mcg->set_cpu_quota_count++;
137 return mcg->set_cpu_ret;
138}
139
140static int mock_set_cpu_period(const struct container_cgroup *cg, int period)
141{
142 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
143 mcg->set_cpu_period_count++;
144 return mcg->set_cpu_ret;
145}
146
147static int mock_set_cpu_rt_runtime(const struct container_cgroup *cg, int rt_runtime)
148{
149 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
150 mcg->set_cpu_rt_runtime_count++;
151 return mcg->set_cpu_ret;
152}
153
154static int mock_set_cpu_rt_period(const struct container_cgroup *cg, int rt_period)
155{
156 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
157 mcg->set_cpu_rt_period_count++;
158 return mcg->set_cpu_ret;
159}
160
Dylan Reid837c74a2016-01-22 17:25:21 -0800161struct container_cgroup *container_cgroup_new(const char *name,
Keshav Santhanam998fd7d2016-07-12 13:33:00 -0700162 const char *cgroup_root,
Dylan Reida9966422016-07-21 10:11:34 -0700163 const char *cgroup_parent,
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700164 uid_t uid, gid_t gid)
Dylan Reid837c74a2016-01-22 17:25:21 -0800165{
166 gmcg.cg.name = strdup(name);
167 return &gmcg.cg;
168}
169
170void container_cgroup_destroy(struct container_cgroup *c)
171{
172 free(c->name);
173}
174
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700175TEST(premounted_runfs)
176{
177 char premounted_runfs[] = "/tmp/cgtest_run/root";
178 struct container_config *config = container_config_create();
179 ASSERT_NE(NULL, config);
180
181 container_config_premounted_runfs(config, premounted_runfs);
182 const char *result = container_config_get_premounted_runfs(config);
183 ASSERT_EQ(0, strcmp(result, premounted_runfs));
184
185 container_config_destroy(config);
186}
187
188TEST(pid_file_path)
189{
190 char pid_file_path[] = "/tmp/cgtest_run/root/container.pid";
191 struct container_config *config = container_config_create();
192 ASSERT_NE(NULL, config);
193
194 container_config_pid_file(config, pid_file_path);
195 const char *result = container_config_get_pid_file(config);
196 ASSERT_EQ(0, strcmp(result, pid_file_path));
197
198 container_config_destroy(config);
199}
200
Dylan Reid837c74a2016-01-22 17:25:21 -0800201/* Start of tests. */
202FIXTURE(container_test) {
203 struct container_config *config;
204 struct container *container;
205 int mount_flags;
206 char *rootfs;
207};
208
209FIXTURE_SETUP(container_test)
210{
211 char temp_template[] = "/tmp/cgtestXXXXXX";
212 char rundir_template[] = "/tmp/cgtest_runXXXXXX";
213 char *rundir;
214 char path[256];
Dylan Reid17fd53f2016-11-18 19:14:41 -0800215 const char *pargs[] = {
Dylan Reid837c74a2016-01-22 17:25:21 -0800216 "/sbin/init",
217 };
218
219 memset(&mount_call_args, 0, sizeof(mount_call_args));
220 mount_called = 0;
221 memset(&mknod_call_args, 0, sizeof(mknod_call_args));
222 mkdtemp_root = NULL;
223
224 memset(&gmcg, 0, sizeof(gmcg));
225 static const struct cgroup_ops cgops = {
226 .freeze = mock_freeze,
227 .thaw = mock_thaw,
228 .deny_all_devices = mock_deny_all_devices,
229 .add_device = mock_add_device,
Chinyue Chenfac909e2016-06-24 14:17:42 +0800230 .set_cpu_shares = mock_set_cpu_shares,
231 .set_cpu_quota = mock_set_cpu_quota,
232 .set_cpu_period = mock_set_cpu_period,
233 .set_cpu_rt_runtime = mock_set_cpu_rt_runtime,
234 .set_cpu_rt_period = mock_set_cpu_rt_period,
Dylan Reid837c74a2016-01-22 17:25:21 -0800235 };
236 gmcg.cg.ops = &cgops;
237
238 self->rootfs = strdup(mkdtemp(temp_template));
239
240 kill_called = 0;
241 minijail_alt_syscall_table = NULL;
242 minijail_ipc_called = 0;
243 minijail_vfs_called = 0;
244 minijail_net_called = 0;
245 minijail_pids_called = 0;
246 minijail_run_as_init_called = 0;
247 minijail_user_called = 0;
248 minijail_wait_called = 0;
249 minijail_reset_signal_mask_called = 0;
250 mount_ret = 0;
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800251 stat_rdev_ret = makedev(2, 3);
Dylan Reid837c74a2016-01-22 17:25:21 -0800252
253 snprintf(path, sizeof(path), "%s/dev", self->rootfs);
254 //mkdir(path, S_IRWXU | S_IRWXG);
255
256 self->mount_flags = MS_NOSUID | MS_NODEV | MS_NOEXEC;
257
258 self->config = container_config_create();
259 container_config_rootfs(self->config, self->rootfs);
260 container_config_program_argv(self->config, pargs, 1);
261 container_config_alt_syscall_table(self->config, "testsyscalltable");
262 container_config_add_mount(self->config,
263 "testtmpfs",
264 "tmpfs",
265 "/tmp",
266 "tmpfs",
267 NULL,
Mike Frysinger05e594e2017-01-10 02:11:08 -0500268 NULL,
Dylan Reid837c74a2016-01-22 17:25:21 -0800269 self->mount_flags,
Mike Frysinger412dbd22017-01-06 01:50:34 -0500270 0,
Dylan Reid837c74a2016-01-22 17:25:21 -0800271 1000,
272 1000,
273 0x666,
274 0,
275 1);
276 container_config_add_device(self->config,
277 'c',
278 "/dev/foo",
279 S_IRWXU | S_IRWXG,
280 245,
281 2,
Dylan Reid355d5e42016-04-29 16:53:31 -0700282 0,
283 1000,
284 1001,
285 1,
286 1,
287 0);
288 /* test dynamic minor on /dev/null */
289 container_config_add_device(self->config,
290 'c',
291 "/dev/null",
292 S_IRWXU | S_IRWXG,
293 1,
294 -1,
295 1,
Dylan Reid837c74a2016-01-22 17:25:21 -0800296 1000,
297 1001,
298 1,
299 1,
300 0);
301
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800302 container_config_set_cpu_shares(self->config, TEST_CPU_SHARES);
303 container_config_set_cpu_cfs_params(
304 self->config, TEST_CPU_QUOTA, TEST_CPU_PERIOD);
Chinyue Chenfac909e2016-06-24 14:17:42 +0800305 /* Invalid params, so this won't be applied. */
306 container_config_set_cpu_rt_params(self->config, 20000, 20000);
307
Dylan Reid837c74a2016-01-22 17:25:21 -0800308 rundir = mkdtemp(rundir_template);
Dylan Reide040c6b2016-05-02 18:49:02 -0700309 self->container = container_new("containerUT", rundir);
Dylan Reid837c74a2016-01-22 17:25:21 -0800310 ASSERT_NE(NULL, self->container);
311}
312
313FIXTURE_TEARDOWN(container_test)
314{
315 char path[256];
316 int i;
317
318 container_destroy(self->container);
319 snprintf(path, sizeof(path), "rm -rf %s", self->rootfs);
320 EXPECT_EQ(0, system(path));
321 free(self->rootfs);
322
323 for (i = 0; i < mount_called; i++) {
324 free(mount_call_args[i].source);
325 free(mount_call_args[i].target);
326 free(mount_call_args[i].filesystemtype);
327 }
328 free(mknod_call_args.pathname);
329 free(mkdtemp_root);
330}
331
332TEST_F(container_test, test_mount_tmp_start)
333{
334 char *path;
335
Dylan Reide040c6b2016-05-02 18:49:02 -0700336 EXPECT_EQ(0, container_start(self->container, self->config));
Dylan Reid837c74a2016-01-22 17:25:21 -0800337 EXPECT_EQ(2, mount_called);
338 EXPECT_EQ(0, strcmp(mount_call_args[1].source, "tmpfs"));
339 EXPECT_LT(0, asprintf(&path, "%s/root/tmp", mkdtemp_root));
340 EXPECT_EQ(0, strcmp(mount_call_args[1].target, path));
341 free(path);
342 EXPECT_EQ(0, strcmp(mount_call_args[1].filesystemtype,
343 "tmpfs"));
344 EXPECT_EQ(mount_call_args[1].mountflags, self->mount_flags);
345 EXPECT_EQ(mount_call_args[1].data, NULL);
346
347 EXPECT_EQ(1, minijail_ipc_called);
348 EXPECT_EQ(1, minijail_vfs_called);
349 EXPECT_EQ(1, minijail_net_called);
350 EXPECT_EQ(1, minijail_pids_called);
351 EXPECT_EQ(1, minijail_user_called);
352 EXPECT_EQ(1, minijail_run_as_init_called);
353 EXPECT_EQ(1, gmcg.deny_all_devs_called_count);
354
Dylan Reid4843d6b2017-03-31 18:14:30 -0700355 EXPECT_EQ(1, gmcg.add_dev_allow[0]);
Dylan Reid355d5e42016-04-29 16:53:31 -0700356 EXPECT_EQ(245, gmcg.add_dev_major[0]);
357 EXPECT_EQ(2, gmcg.add_dev_minor[0]);
358 EXPECT_EQ(1, gmcg.add_dev_read[0]);
359 EXPECT_EQ(1, gmcg.add_dev_write[0]);
360 EXPECT_EQ(0, gmcg.add_dev_modify[0]);
361 EXPECT_EQ('c', gmcg.add_dev_type[0]);
362
Dylan Reid4843d6b2017-03-31 18:14:30 -0700363 EXPECT_EQ(1, gmcg.add_dev_allow[1]);
Dylan Reid355d5e42016-04-29 16:53:31 -0700364 EXPECT_EQ(1, gmcg.add_dev_major[1]);
365 EXPECT_EQ(3, gmcg.add_dev_minor[1]);
366 EXPECT_EQ(1, gmcg.add_dev_read[1]);
367 EXPECT_EQ(1, gmcg.add_dev_write[1]);
368 EXPECT_EQ(0, gmcg.add_dev_modify[1]);
369 EXPECT_EQ('c', gmcg.add_dev_type[1]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800370
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800371 EXPECT_LT(0, asprintf(&path, "%s/root/dev/null", mkdtemp_root));
372 EXPECT_EQ(0, strcmp(mknod_call_args.pathname, path));
373 free(path);
374 EXPECT_EQ(mknod_call_args.mode, S_IRWXU | S_IRWXG | S_IFCHR);
375 EXPECT_EQ(mknod_call_args.dev, makedev(1, 3));
376
Chinyue Chenfac909e2016-06-24 14:17:42 +0800377 EXPECT_EQ(1, gmcg.set_cpu_shares_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800378 EXPECT_EQ(TEST_CPU_SHARES,
379 container_config_get_cpu_shares(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800380 EXPECT_EQ(1, gmcg.set_cpu_quota_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800381 EXPECT_EQ(TEST_CPU_QUOTA,
382 container_config_get_cpu_quota(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800383 EXPECT_EQ(1, gmcg.set_cpu_period_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800384 EXPECT_EQ(TEST_CPU_PERIOD,
385 container_config_get_cpu_period(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800386 EXPECT_EQ(0, gmcg.set_cpu_rt_runtime_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800387 EXPECT_EQ(0, container_config_get_cpu_rt_runtime(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800388 EXPECT_EQ(0, gmcg.set_cpu_rt_period_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800389 EXPECT_EQ(0, container_config_get_cpu_rt_period(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800390
Dylan Reid837c74a2016-01-22 17:25:21 -0800391 ASSERT_NE(NULL, minijail_alt_syscall_table);
392 EXPECT_EQ(0, strcmp(minijail_alt_syscall_table,
393 "testsyscalltable"));
394
395 EXPECT_EQ(0, container_wait(self->container));
396 EXPECT_EQ(1, minijail_wait_called);
397 EXPECT_EQ(1, minijail_reset_signal_mask_called);
398}
399
400TEST_F(container_test, test_kill_container)
401{
Dylan Reide040c6b2016-05-02 18:49:02 -0700402 EXPECT_EQ(0, container_start(self->container, self->config));
Dylan Reid837c74a2016-01-22 17:25:21 -0800403 EXPECT_EQ(0, container_kill(self->container));
404 EXPECT_EQ(1, kill_called);
405 EXPECT_EQ(SIGKILL, kill_sig);
406 EXPECT_EQ(1, minijail_wait_called);
407}
408
409/* libc stubs so the UT doesn't need root to call mount, etc. */
410int mount(const char *source, const char *target,
411 const char *filesystemtype, unsigned long mountflags,
412 const void *data)
413{
414 if (mount_called >= 5)
415 return 0;
416
417 mount_call_args[mount_called].source = strdup(source);
418 mount_call_args[mount_called].target = strdup(target);
419 mount_call_args[mount_called].filesystemtype = strdup(filesystemtype);
420 mount_call_args[mount_called].mountflags = mountflags;
421 mount_call_args[mount_called].data = data;
422 ++mount_called;
423 return 0;
424}
425
426int umount(const char *target)
427{
428 return 0;
429}
430
431int mknod(const char *pathname, mode_t mode, dev_t dev)
432{
433 mknod_call_args.pathname = strdup(pathname);
434 mknod_call_args.mode = mode;
435 mknod_call_args.dev = dev;
436 return 0;
437}
438
439int chown(const char *path, uid_t owner, gid_t group)
440{
441 return 0;
442};
443
444int kill(pid_t pid, int sig)
445{
446 ++kill_called;
447 kill_sig = sig;
448 return 0;
449}
450
451int stat(const char *path, struct stat *buf)
452{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800453 buf->st_rdev = stat_rdev_ret;
Dylan Reid837c74a2016-01-22 17:25:21 -0800454 return 0;
455}
456
457int chmod(const char *path, mode_t mode)
458{
459 return 0;
460}
461
462char *mkdtemp(char *template)
463{
464 mkdtemp_root = strdup(template);
465 return template;
466}
467
468int mkdir(const char *pathname, mode_t mode)
469{
470 return 0;
471}
472
473int rmdir(const char *pathname)
474{
475 return 0;
476}
477
478int unlink(const char *pathname)
479{
480 return 0;
481}
482
483/* Minijail stubs */
484struct minijail *minijail_new(void)
485{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800486 return (struct minijail *)0x55;
487}
488
489void minijail_destroy(struct minijail *j)
490{
Dylan Reid837c74a2016-01-22 17:25:21 -0800491}
492
493int minijail_mount(struct minijail *j, const char *src, const char *dest,
494 const char *type, unsigned long flags)
495{
496 return 0;
497}
498
499void minijail_namespace_vfs(struct minijail *j)
500{
501 ++minijail_vfs_called;
502}
503
504void minijail_namespace_ipc(struct minijail *j)
505{
506 ++minijail_ipc_called;
507}
508
509void minijail_namespace_net(struct minijail *j)
510{
511 ++minijail_net_called;
512}
513
514void minijail_namespace_pids(struct minijail *j)
515{
516 ++minijail_pids_called;
517}
518
519void minijail_namespace_user(struct minijail *j)
520{
521 ++minijail_user_called;
522}
523
524int minijail_uidmap(struct minijail *j, const char *uidmap)
525{
526 return 0;
527}
528
529int minijail_gidmap(struct minijail *j, const char *gidmap)
530{
531 return 0;
532}
533
534int minijail_enter_pivot_root(struct minijail *j, const char *dir)
535{
536 return 0;
537}
538
539void minijail_run_as_init(struct minijail *j)
540{
541 ++minijail_run_as_init_called;
542}
543
544int minijail_run_pid_pipes_no_preload(struct minijail *j, const char *filename,
545 char *const argv[], pid_t *pchild_pid,
546 int *pstdin_fd, int *pstdout_fd,
547 int *pstderr_fd)
548{
549 *pchild_pid = INIT_TEST_PID;
550 return 0;
551}
552
553int minijail_write_pid_file(struct minijail *j, const char *path)
554{
555 return 0;
556}
557
558int minijail_wait(struct minijail *j)
559{
560 ++minijail_wait_called;
561 return 0;
562}
563
564int minijail_use_alt_syscall(struct minijail *j, const char *table)
565{
566 minijail_alt_syscall_table = table;
567 return 0;
568}
569
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800570int minijail_add_to_cgroup(struct minijail *j, const char *cg_path)
Dylan Reid837c74a2016-01-22 17:25:21 -0800571{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800572 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800573}
574
575void minijail_reset_signal_mask(struct minijail *j)
576{
577 ++minijail_reset_signal_mask_called;
578}
579
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800580void minijail_skip_remount_private(struct minijail *j)
581{
582}
583
Dylan Reid837c74a2016-01-22 17:25:21 -0800584TEST_HARNESS_MAIN