blob: 158d97579289d2defed947a7852f8aa6afbd818a [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
172/* Start of tests. */
173FIXTURE(container_test) {
174 struct container_config *config;
175 struct container *container;
176 int mount_flags;
177 char *rootfs;
178};
179
180FIXTURE_SETUP(container_test)
181{
182 char temp_template[] = "/tmp/cgtestXXXXXX";
183 char rundir_template[] = "/tmp/cgtest_runXXXXXX";
184 char *rundir;
185 char path[256];
186 char *pargs[] = {
187 "/sbin/init",
188 };
189
190 memset(&mount_call_args, 0, sizeof(mount_call_args));
191 mount_called = 0;
192 memset(&mknod_call_args, 0, sizeof(mknod_call_args));
193 mkdtemp_root = NULL;
194
195 memset(&gmcg, 0, sizeof(gmcg));
196 static const struct cgroup_ops cgops = {
197 .freeze = mock_freeze,
198 .thaw = mock_thaw,
199 .deny_all_devices = mock_deny_all_devices,
200 .add_device = mock_add_device,
Chinyue Chenfac909e2016-06-24 14:17:42 +0800201 .set_cpu_shares = mock_set_cpu_shares,
202 .set_cpu_quota = mock_set_cpu_quota,
203 .set_cpu_period = mock_set_cpu_period,
204 .set_cpu_rt_runtime = mock_set_cpu_rt_runtime,
205 .set_cpu_rt_period = mock_set_cpu_rt_period,
Dylan Reid837c74a2016-01-22 17:25:21 -0800206 };
207 gmcg.cg.ops = &cgops;
208
209 self->rootfs = strdup(mkdtemp(temp_template));
210
211 kill_called = 0;
212 minijail_alt_syscall_table = NULL;
213 minijail_ipc_called = 0;
214 minijail_vfs_called = 0;
215 minijail_net_called = 0;
216 minijail_pids_called = 0;
217 minijail_run_as_init_called = 0;
218 minijail_user_called = 0;
219 minijail_wait_called = 0;
220 minijail_reset_signal_mask_called = 0;
221 mount_ret = 0;
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800222 stat_rdev_ret = makedev(2, 3);
Dylan Reid837c74a2016-01-22 17:25:21 -0800223
224 snprintf(path, sizeof(path), "%s/dev", self->rootfs);
225 //mkdir(path, S_IRWXU | S_IRWXG);
226
227 self->mount_flags = MS_NOSUID | MS_NODEV | MS_NOEXEC;
228
229 self->config = container_config_create();
230 container_config_rootfs(self->config, self->rootfs);
231 container_config_program_argv(self->config, pargs, 1);
232 container_config_alt_syscall_table(self->config, "testsyscalltable");
233 container_config_add_mount(self->config,
234 "testtmpfs",
235 "tmpfs",
236 "/tmp",
237 "tmpfs",
238 NULL,
239 self->mount_flags,
240 1000,
241 1000,
242 0x666,
243 0,
244 1);
245 container_config_add_device(self->config,
246 'c',
247 "/dev/foo",
248 S_IRWXU | S_IRWXG,
249 245,
250 2,
Dylan Reid355d5e42016-04-29 16:53:31 -0700251 0,
252 1000,
253 1001,
254 1,
255 1,
256 0);
257 /* test dynamic minor on /dev/null */
258 container_config_add_device(self->config,
259 'c',
260 "/dev/null",
261 S_IRWXU | S_IRWXG,
262 1,
263 -1,
264 1,
Dylan Reid837c74a2016-01-22 17:25:21 -0800265 1000,
266 1001,
267 1,
268 1,
269 0);
270
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800271 container_config_set_cpu_shares(self->config, TEST_CPU_SHARES);
272 container_config_set_cpu_cfs_params(
273 self->config, TEST_CPU_QUOTA, TEST_CPU_PERIOD);
Chinyue Chenfac909e2016-06-24 14:17:42 +0800274 /* Invalid params, so this won't be applied. */
275 container_config_set_cpu_rt_params(self->config, 20000, 20000);
276
Dylan Reid837c74a2016-01-22 17:25:21 -0800277 rundir = mkdtemp(rundir_template);
Dylan Reide040c6b2016-05-02 18:49:02 -0700278 self->container = container_new("containerUT", rundir);
Dylan Reid837c74a2016-01-22 17:25:21 -0800279 ASSERT_NE(NULL, self->container);
280}
281
282FIXTURE_TEARDOWN(container_test)
283{
284 char path[256];
285 int i;
286
287 container_destroy(self->container);
288 snprintf(path, sizeof(path), "rm -rf %s", self->rootfs);
289 EXPECT_EQ(0, system(path));
290 free(self->rootfs);
291
292 for (i = 0; i < mount_called; i++) {
293 free(mount_call_args[i].source);
294 free(mount_call_args[i].target);
295 free(mount_call_args[i].filesystemtype);
296 }
297 free(mknod_call_args.pathname);
298 free(mkdtemp_root);
299}
300
301TEST_F(container_test, test_mount_tmp_start)
302{
303 char *path;
304
Dylan Reide040c6b2016-05-02 18:49:02 -0700305 EXPECT_EQ(0, container_start(self->container, self->config));
Dylan Reid837c74a2016-01-22 17:25:21 -0800306 EXPECT_EQ(2, mount_called);
307 EXPECT_EQ(0, strcmp(mount_call_args[1].source, "tmpfs"));
308 EXPECT_LT(0, asprintf(&path, "%s/root/tmp", mkdtemp_root));
309 EXPECT_EQ(0, strcmp(mount_call_args[1].target, path));
310 free(path);
311 EXPECT_EQ(0, strcmp(mount_call_args[1].filesystemtype,
312 "tmpfs"));
313 EXPECT_EQ(mount_call_args[1].mountflags, self->mount_flags);
314 EXPECT_EQ(mount_call_args[1].data, NULL);
315
316 EXPECT_EQ(1, minijail_ipc_called);
317 EXPECT_EQ(1, minijail_vfs_called);
318 EXPECT_EQ(1, minijail_net_called);
319 EXPECT_EQ(1, minijail_pids_called);
320 EXPECT_EQ(1, minijail_user_called);
321 EXPECT_EQ(1, minijail_run_as_init_called);
322 EXPECT_EQ(1, gmcg.deny_all_devs_called_count);
323
Dylan Reid355d5e42016-04-29 16:53:31 -0700324 EXPECT_EQ(245, gmcg.add_dev_major[0]);
325 EXPECT_EQ(2, gmcg.add_dev_minor[0]);
326 EXPECT_EQ(1, gmcg.add_dev_read[0]);
327 EXPECT_EQ(1, gmcg.add_dev_write[0]);
328 EXPECT_EQ(0, gmcg.add_dev_modify[0]);
329 EXPECT_EQ('c', gmcg.add_dev_type[0]);
330
331 EXPECT_EQ(1, gmcg.add_dev_major[1]);
332 EXPECT_EQ(3, gmcg.add_dev_minor[1]);
333 EXPECT_EQ(1, gmcg.add_dev_read[1]);
334 EXPECT_EQ(1, gmcg.add_dev_write[1]);
335 EXPECT_EQ(0, gmcg.add_dev_modify[1]);
336 EXPECT_EQ('c', gmcg.add_dev_type[1]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800337
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800338 EXPECT_LT(0, asprintf(&path, "%s/root/dev/null", mkdtemp_root));
339 EXPECT_EQ(0, strcmp(mknod_call_args.pathname, path));
340 free(path);
341 EXPECT_EQ(mknod_call_args.mode, S_IRWXU | S_IRWXG | S_IFCHR);
342 EXPECT_EQ(mknod_call_args.dev, makedev(1, 3));
343
Chinyue Chenfac909e2016-06-24 14:17:42 +0800344 EXPECT_EQ(1, gmcg.set_cpu_shares_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800345 EXPECT_EQ(TEST_CPU_SHARES,
346 container_config_get_cpu_shares(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800347 EXPECT_EQ(1, gmcg.set_cpu_quota_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800348 EXPECT_EQ(TEST_CPU_QUOTA,
349 container_config_get_cpu_quota(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800350 EXPECT_EQ(1, gmcg.set_cpu_period_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800351 EXPECT_EQ(TEST_CPU_PERIOD,
352 container_config_get_cpu_period(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800353 EXPECT_EQ(0, gmcg.set_cpu_rt_runtime_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800354 EXPECT_EQ(0, container_config_get_cpu_rt_runtime(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800355 EXPECT_EQ(0, gmcg.set_cpu_rt_period_count);
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800356 EXPECT_EQ(0, container_config_get_cpu_rt_period(self->config));
Chinyue Chenfac909e2016-06-24 14:17:42 +0800357
Dylan Reid837c74a2016-01-22 17:25:21 -0800358 ASSERT_NE(NULL, minijail_alt_syscall_table);
359 EXPECT_EQ(0, strcmp(minijail_alt_syscall_table,
360 "testsyscalltable"));
361
362 EXPECT_EQ(0, container_wait(self->container));
363 EXPECT_EQ(1, minijail_wait_called);
364 EXPECT_EQ(1, minijail_reset_signal_mask_called);
365}
366
367TEST_F(container_test, test_kill_container)
368{
Dylan Reide040c6b2016-05-02 18:49:02 -0700369 EXPECT_EQ(0, container_start(self->container, self->config));
Dylan Reid837c74a2016-01-22 17:25:21 -0800370 EXPECT_EQ(0, container_kill(self->container));
371 EXPECT_EQ(1, kill_called);
372 EXPECT_EQ(SIGKILL, kill_sig);
373 EXPECT_EQ(1, minijail_wait_called);
374}
375
376/* libc stubs so the UT doesn't need root to call mount, etc. */
377int mount(const char *source, const char *target,
378 const char *filesystemtype, unsigned long mountflags,
379 const void *data)
380{
381 if (mount_called >= 5)
382 return 0;
383
384 mount_call_args[mount_called].source = strdup(source);
385 mount_call_args[mount_called].target = strdup(target);
386 mount_call_args[mount_called].filesystemtype = strdup(filesystemtype);
387 mount_call_args[mount_called].mountflags = mountflags;
388 mount_call_args[mount_called].data = data;
389 ++mount_called;
390 return 0;
391}
392
393int umount(const char *target)
394{
395 return 0;
396}
397
398int mknod(const char *pathname, mode_t mode, dev_t dev)
399{
400 mknod_call_args.pathname = strdup(pathname);
401 mknod_call_args.mode = mode;
402 mknod_call_args.dev = dev;
403 return 0;
404}
405
406int chown(const char *path, uid_t owner, gid_t group)
407{
408 return 0;
409};
410
411int kill(pid_t pid, int sig)
412{
413 ++kill_called;
414 kill_sig = sig;
415 return 0;
416}
417
418int stat(const char *path, struct stat *buf)
419{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800420 buf->st_rdev = stat_rdev_ret;
Dylan Reid837c74a2016-01-22 17:25:21 -0800421 return 0;
422}
423
424int chmod(const char *path, mode_t mode)
425{
426 return 0;
427}
428
429char *mkdtemp(char *template)
430{
431 mkdtemp_root = strdup(template);
432 return template;
433}
434
435int mkdir(const char *pathname, mode_t mode)
436{
437 return 0;
438}
439
440int rmdir(const char *pathname)
441{
442 return 0;
443}
444
445int unlink(const char *pathname)
446{
447 return 0;
448}
449
450/* Minijail stubs */
451struct minijail *minijail_new(void)
452{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800453 return (struct minijail *)0x55;
454}
455
456void minijail_destroy(struct minijail *j)
457{
Dylan Reid837c74a2016-01-22 17:25:21 -0800458}
459
460int minijail_mount(struct minijail *j, const char *src, const char *dest,
461 const char *type, unsigned long flags)
462{
463 return 0;
464}
465
466void minijail_namespace_vfs(struct minijail *j)
467{
468 ++minijail_vfs_called;
469}
470
471void minijail_namespace_ipc(struct minijail *j)
472{
473 ++minijail_ipc_called;
474}
475
476void minijail_namespace_net(struct minijail *j)
477{
478 ++minijail_net_called;
479}
480
481void minijail_namespace_pids(struct minijail *j)
482{
483 ++minijail_pids_called;
484}
485
486void minijail_namespace_user(struct minijail *j)
487{
488 ++minijail_user_called;
489}
490
491int minijail_uidmap(struct minijail *j, const char *uidmap)
492{
493 return 0;
494}
495
496int minijail_gidmap(struct minijail *j, const char *gidmap)
497{
498 return 0;
499}
500
501int minijail_enter_pivot_root(struct minijail *j, const char *dir)
502{
503 return 0;
504}
505
506void minijail_run_as_init(struct minijail *j)
507{
508 ++minijail_run_as_init_called;
509}
510
511int minijail_run_pid_pipes_no_preload(struct minijail *j, const char *filename,
512 char *const argv[], pid_t *pchild_pid,
513 int *pstdin_fd, int *pstdout_fd,
514 int *pstderr_fd)
515{
516 *pchild_pid = INIT_TEST_PID;
517 return 0;
518}
519
520int minijail_write_pid_file(struct minijail *j, const char *path)
521{
522 return 0;
523}
524
525int minijail_wait(struct minijail *j)
526{
527 ++minijail_wait_called;
528 return 0;
529}
530
531int minijail_use_alt_syscall(struct minijail *j, const char *table)
532{
533 minijail_alt_syscall_table = table;
534 return 0;
535}
536
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800537int minijail_add_to_cgroup(struct minijail *j, const char *cg_path)
Dylan Reid837c74a2016-01-22 17:25:21 -0800538{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800539 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800540}
541
542void minijail_reset_signal_mask(struct minijail *j)
543{
544 ++minijail_reset_signal_mask_called;
545}
546
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800547void minijail_skip_remount_private(struct minijail *j)
548{
549}
550
Dylan Reid837c74a2016-01-22 17:25:21 -0800551TEST_HARNESS_MAIN