blob: 5f6710a4def0ce436e8fa9c6bf0a39e2cd90f880 [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;
21
22struct mount_args {
23 char *source;
24 char *target;
25 char *filesystemtype;
26 unsigned long mountflags;
27 const void *data;
28};
29static struct mount_args mount_call_args[5];
30static int mount_called;
31
32struct mknod_args {
33 char *pathname;
34 mode_t mode;
35 dev_t dev;
36};
37static struct mknod_args mknod_call_args;
Chinyue Chen03c54ae2016-06-29 12:29:10 +080038static dev_t stat_rdev_ret;
Dylan Reid837c74a2016-01-22 17:25:21 -080039
40static int kill_called;
41static int kill_sig;
42static const char *minijail_alt_syscall_table;
43static int minijail_ipc_called;
44static int minijail_vfs_called;
45static int minijail_net_called;
46static int minijail_pids_called;
47static int minijail_run_as_init_called;
48static int minijail_user_called;
49static int minijail_wait_called;
50static int minijail_reset_signal_mask_called;
51static int mount_ret;
52static char *mkdtemp_root;
53
54/* global mock cgroup. */
Dylan Reid355d5e42016-04-29 16:53:31 -070055#define MAX_ADD_DEVICE_CALLS 2
Dylan Reid837c74a2016-01-22 17:25:21 -080056struct mock_cgroup {
57 struct container_cgroup cg;
58 int freeze_ret;
59 int thaw_ret;
60 int deny_all_devs_ret;
61 int add_device_ret;
Chinyue Chenfac909e2016-06-24 14:17:42 +080062 int set_cpu_ret;
Dylan Reid837c74a2016-01-22 17:25:21 -080063
64 int init_called_count;
65 int deny_all_devs_called_count;
66
Dylan Reid355d5e42016-04-29 16:53:31 -070067 int add_dev_major[MAX_ADD_DEVICE_CALLS];
68 int add_dev_minor[MAX_ADD_DEVICE_CALLS];
69 int add_dev_read[MAX_ADD_DEVICE_CALLS];
70 int add_dev_write[MAX_ADD_DEVICE_CALLS];
71 int add_dev_modify[MAX_ADD_DEVICE_CALLS];
72 char add_dev_type[MAX_ADD_DEVICE_CALLS];
73 int add_dev_called_count;
Chinyue Chenfac909e2016-06-24 14:17:42 +080074
75 int set_cpu_shares_count;
76 int set_cpu_quota_count;
77 int set_cpu_period_count;
78 int set_cpu_rt_runtime_count;
79 int set_cpu_rt_period_count;
Dylan Reid837c74a2016-01-22 17:25:21 -080080};
81
82static struct mock_cgroup gmcg;
83
84static int mock_freeze(const struct container_cgroup *cg)
85{
86 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
87 return mcg->freeze_ret;
88}
89
90static int mock_thaw(const struct container_cgroup *cg)
91{
92 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
93 return mcg->thaw_ret;
94}
95
96static int mock_deny_all_devices(const struct container_cgroup *cg)
97{
98 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
99 ++mcg->deny_all_devs_called_count;
100 return mcg->deny_all_devs_ret;
101}
102
103static int mock_add_device(const struct container_cgroup *cg, int major,
104 int minor, int read, int write, int modify,
105 char type)
106{
107 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
Dylan Reid355d5e42016-04-29 16:53:31 -0700108
109 if (mcg->add_dev_called_count >= MAX_ADD_DEVICE_CALLS)
110 return mcg->add_device_ret;
111 mcg->add_dev_major[mcg->add_dev_called_count] = major;
112 mcg->add_dev_minor[mcg->add_dev_called_count] = minor;
113 mcg->add_dev_read[mcg->add_dev_called_count] = read;
114 mcg->add_dev_write[mcg->add_dev_called_count] = write;
115 mcg->add_dev_modify[mcg->add_dev_called_count] = modify;
116 mcg->add_dev_type[mcg->add_dev_called_count] = type;
117 mcg->add_dev_called_count++;
Dylan Reid837c74a2016-01-22 17:25:21 -0800118 return mcg->add_device_ret;
119}
120
Chinyue Chenfac909e2016-06-24 14:17:42 +0800121static int mock_set_cpu_shares(const struct container_cgroup *cg, int shares)
122{
123 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
124 mcg->set_cpu_shares_count++;
125 return mcg->set_cpu_ret;
126}
127
128static int mock_set_cpu_quota(const struct container_cgroup *cg, int quota)
129{
130 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
131 mcg->set_cpu_quota_count++;
132 return mcg->set_cpu_ret;
133}
134
135static int mock_set_cpu_period(const struct container_cgroup *cg, int period)
136{
137 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
138 mcg->set_cpu_period_count++;
139 return mcg->set_cpu_ret;
140}
141
142static int mock_set_cpu_rt_runtime(const struct container_cgroup *cg, int rt_runtime)
143{
144 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
145 mcg->set_cpu_rt_runtime_count++;
146 return mcg->set_cpu_ret;
147}
148
149static int mock_set_cpu_rt_period(const struct container_cgroup *cg, int rt_period)
150{
151 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
152 mcg->set_cpu_rt_period_count++;
153 return mcg->set_cpu_ret;
154}
155
Dylan Reid837c74a2016-01-22 17:25:21 -0800156struct container_cgroup *container_cgroup_new(const char *name,
157 const char *cgroup_root)
158{
159 gmcg.cg.name = strdup(name);
160 return &gmcg.cg;
161}
162
163void container_cgroup_destroy(struct container_cgroup *c)
164{
165 free(c->name);
166}
167
168/* Start of tests. */
169FIXTURE(container_test) {
170 struct container_config *config;
171 struct container *container;
172 int mount_flags;
173 char *rootfs;
174};
175
176FIXTURE_SETUP(container_test)
177{
178 char temp_template[] = "/tmp/cgtestXXXXXX";
179 char rundir_template[] = "/tmp/cgtest_runXXXXXX";
180 char *rundir;
181 char path[256];
182 char *pargs[] = {
183 "/sbin/init",
184 };
185
186 memset(&mount_call_args, 0, sizeof(mount_call_args));
187 mount_called = 0;
188 memset(&mknod_call_args, 0, sizeof(mknod_call_args));
189 mkdtemp_root = NULL;
190
191 memset(&gmcg, 0, sizeof(gmcg));
192 static const struct cgroup_ops cgops = {
193 .freeze = mock_freeze,
194 .thaw = mock_thaw,
195 .deny_all_devices = mock_deny_all_devices,
196 .add_device = mock_add_device,
Chinyue Chenfac909e2016-06-24 14:17:42 +0800197 .set_cpu_shares = mock_set_cpu_shares,
198 .set_cpu_quota = mock_set_cpu_quota,
199 .set_cpu_period = mock_set_cpu_period,
200 .set_cpu_rt_runtime = mock_set_cpu_rt_runtime,
201 .set_cpu_rt_period = mock_set_cpu_rt_period,
Dylan Reid837c74a2016-01-22 17:25:21 -0800202 };
203 gmcg.cg.ops = &cgops;
204
205 self->rootfs = strdup(mkdtemp(temp_template));
206
207 kill_called = 0;
208 minijail_alt_syscall_table = NULL;
209 minijail_ipc_called = 0;
210 minijail_vfs_called = 0;
211 minijail_net_called = 0;
212 minijail_pids_called = 0;
213 minijail_run_as_init_called = 0;
214 minijail_user_called = 0;
215 minijail_wait_called = 0;
216 minijail_reset_signal_mask_called = 0;
217 mount_ret = 0;
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800218 stat_rdev_ret = makedev(2, 3);
Dylan Reid837c74a2016-01-22 17:25:21 -0800219
220 snprintf(path, sizeof(path), "%s/dev", self->rootfs);
221 //mkdir(path, S_IRWXU | S_IRWXG);
222
223 self->mount_flags = MS_NOSUID | MS_NODEV | MS_NOEXEC;
224
225 self->config = container_config_create();
226 container_config_rootfs(self->config, self->rootfs);
227 container_config_program_argv(self->config, pargs, 1);
228 container_config_alt_syscall_table(self->config, "testsyscalltable");
229 container_config_add_mount(self->config,
230 "testtmpfs",
231 "tmpfs",
232 "/tmp",
233 "tmpfs",
234 NULL,
235 self->mount_flags,
236 1000,
237 1000,
238 0x666,
239 0,
240 1);
241 container_config_add_device(self->config,
242 'c',
243 "/dev/foo",
244 S_IRWXU | S_IRWXG,
245 245,
246 2,
Dylan Reid355d5e42016-04-29 16:53:31 -0700247 0,
248 1000,
249 1001,
250 1,
251 1,
252 0);
253 /* test dynamic minor on /dev/null */
254 container_config_add_device(self->config,
255 'c',
256 "/dev/null",
257 S_IRWXU | S_IRWXG,
258 1,
259 -1,
260 1,
Dylan Reid837c74a2016-01-22 17:25:21 -0800261 1000,
262 1001,
263 1,
264 1,
265 0);
266
Chinyue Chenfac909e2016-06-24 14:17:42 +0800267 container_config_set_cpu_shares(self->config, 200);
268 container_config_set_cpu_cfs_params(self->config, 20000, 50000);
269 /* Invalid params, so this won't be applied. */
270 container_config_set_cpu_rt_params(self->config, 20000, 20000);
271
Dylan Reid837c74a2016-01-22 17:25:21 -0800272 rundir = mkdtemp(rundir_template);
Dylan Reide040c6b2016-05-02 18:49:02 -0700273 self->container = container_new("containerUT", rundir);
Dylan Reid837c74a2016-01-22 17:25:21 -0800274 ASSERT_NE(NULL, self->container);
275}
276
277FIXTURE_TEARDOWN(container_test)
278{
279 char path[256];
280 int i;
281
282 container_destroy(self->container);
283 snprintf(path, sizeof(path), "rm -rf %s", self->rootfs);
284 EXPECT_EQ(0, system(path));
285 free(self->rootfs);
286
287 for (i = 0; i < mount_called; i++) {
288 free(mount_call_args[i].source);
289 free(mount_call_args[i].target);
290 free(mount_call_args[i].filesystemtype);
291 }
292 free(mknod_call_args.pathname);
293 free(mkdtemp_root);
294}
295
296TEST_F(container_test, test_mount_tmp_start)
297{
298 char *path;
299
Dylan Reide040c6b2016-05-02 18:49:02 -0700300 EXPECT_EQ(0, container_start(self->container, self->config));
Dylan Reid837c74a2016-01-22 17:25:21 -0800301 EXPECT_EQ(2, mount_called);
302 EXPECT_EQ(0, strcmp(mount_call_args[1].source, "tmpfs"));
303 EXPECT_LT(0, asprintf(&path, "%s/root/tmp", mkdtemp_root));
304 EXPECT_EQ(0, strcmp(mount_call_args[1].target, path));
305 free(path);
306 EXPECT_EQ(0, strcmp(mount_call_args[1].filesystemtype,
307 "tmpfs"));
308 EXPECT_EQ(mount_call_args[1].mountflags, self->mount_flags);
309 EXPECT_EQ(mount_call_args[1].data, NULL);
310
311 EXPECT_EQ(1, minijail_ipc_called);
312 EXPECT_EQ(1, minijail_vfs_called);
313 EXPECT_EQ(1, minijail_net_called);
314 EXPECT_EQ(1, minijail_pids_called);
315 EXPECT_EQ(1, minijail_user_called);
316 EXPECT_EQ(1, minijail_run_as_init_called);
317 EXPECT_EQ(1, gmcg.deny_all_devs_called_count);
318
Dylan Reid355d5e42016-04-29 16:53:31 -0700319 EXPECT_EQ(245, gmcg.add_dev_major[0]);
320 EXPECT_EQ(2, gmcg.add_dev_minor[0]);
321 EXPECT_EQ(1, gmcg.add_dev_read[0]);
322 EXPECT_EQ(1, gmcg.add_dev_write[0]);
323 EXPECT_EQ(0, gmcg.add_dev_modify[0]);
324 EXPECT_EQ('c', gmcg.add_dev_type[0]);
325
326 EXPECT_EQ(1, gmcg.add_dev_major[1]);
327 EXPECT_EQ(3, gmcg.add_dev_minor[1]);
328 EXPECT_EQ(1, gmcg.add_dev_read[1]);
329 EXPECT_EQ(1, gmcg.add_dev_write[1]);
330 EXPECT_EQ(0, gmcg.add_dev_modify[1]);
331 EXPECT_EQ('c', gmcg.add_dev_type[1]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800332
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800333 EXPECT_LT(0, asprintf(&path, "%s/root/dev/null", mkdtemp_root));
334 EXPECT_EQ(0, strcmp(mknod_call_args.pathname, path));
335 free(path);
336 EXPECT_EQ(mknod_call_args.mode, S_IRWXU | S_IRWXG | S_IFCHR);
337 EXPECT_EQ(mknod_call_args.dev, makedev(1, 3));
338
Chinyue Chenfac909e2016-06-24 14:17:42 +0800339 EXPECT_EQ(1, gmcg.set_cpu_shares_count);
340 EXPECT_EQ(1, gmcg.set_cpu_quota_count);
341 EXPECT_EQ(1, gmcg.set_cpu_period_count);
342 EXPECT_EQ(0, gmcg.set_cpu_rt_runtime_count);
343 EXPECT_EQ(0, gmcg.set_cpu_rt_period_count);
344
Dylan Reid837c74a2016-01-22 17:25:21 -0800345 ASSERT_NE(NULL, minijail_alt_syscall_table);
346 EXPECT_EQ(0, strcmp(minijail_alt_syscall_table,
347 "testsyscalltable"));
348
349 EXPECT_EQ(0, container_wait(self->container));
350 EXPECT_EQ(1, minijail_wait_called);
351 EXPECT_EQ(1, minijail_reset_signal_mask_called);
352}
353
354TEST_F(container_test, test_kill_container)
355{
Dylan Reide040c6b2016-05-02 18:49:02 -0700356 EXPECT_EQ(0, container_start(self->container, self->config));
Dylan Reid837c74a2016-01-22 17:25:21 -0800357 EXPECT_EQ(0, container_kill(self->container));
358 EXPECT_EQ(1, kill_called);
359 EXPECT_EQ(SIGKILL, kill_sig);
360 EXPECT_EQ(1, minijail_wait_called);
361}
362
363/* libc stubs so the UT doesn't need root to call mount, etc. */
364int mount(const char *source, const char *target,
365 const char *filesystemtype, unsigned long mountflags,
366 const void *data)
367{
368 if (mount_called >= 5)
369 return 0;
370
371 mount_call_args[mount_called].source = strdup(source);
372 mount_call_args[mount_called].target = strdup(target);
373 mount_call_args[mount_called].filesystemtype = strdup(filesystemtype);
374 mount_call_args[mount_called].mountflags = mountflags;
375 mount_call_args[mount_called].data = data;
376 ++mount_called;
377 return 0;
378}
379
380int umount(const char *target)
381{
382 return 0;
383}
384
385int mknod(const char *pathname, mode_t mode, dev_t dev)
386{
387 mknod_call_args.pathname = strdup(pathname);
388 mknod_call_args.mode = mode;
389 mknod_call_args.dev = dev;
390 return 0;
391}
392
393int chown(const char *path, uid_t owner, gid_t group)
394{
395 return 0;
396};
397
398int kill(pid_t pid, int sig)
399{
400 ++kill_called;
401 kill_sig = sig;
402 return 0;
403}
404
405int stat(const char *path, struct stat *buf)
406{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800407 buf->st_rdev = stat_rdev_ret;
Dylan Reid837c74a2016-01-22 17:25:21 -0800408 return 0;
409}
410
411int chmod(const char *path, mode_t mode)
412{
413 return 0;
414}
415
416char *mkdtemp(char *template)
417{
418 mkdtemp_root = strdup(template);
419 return template;
420}
421
422int mkdir(const char *pathname, mode_t mode)
423{
424 return 0;
425}
426
427int rmdir(const char *pathname)
428{
429 return 0;
430}
431
432int unlink(const char *pathname)
433{
434 return 0;
435}
436
437/* Minijail stubs */
438struct minijail *minijail_new(void)
439{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800440 return (struct minijail *)0x55;
441}
442
443void minijail_destroy(struct minijail *j)
444{
Dylan Reid837c74a2016-01-22 17:25:21 -0800445}
446
447int minijail_mount(struct minijail *j, const char *src, const char *dest,
448 const char *type, unsigned long flags)
449{
450 return 0;
451}
452
453void minijail_namespace_vfs(struct minijail *j)
454{
455 ++minijail_vfs_called;
456}
457
458void minijail_namespace_ipc(struct minijail *j)
459{
460 ++minijail_ipc_called;
461}
462
463void minijail_namespace_net(struct minijail *j)
464{
465 ++minijail_net_called;
466}
467
468void minijail_namespace_pids(struct minijail *j)
469{
470 ++minijail_pids_called;
471}
472
473void minijail_namespace_user(struct minijail *j)
474{
475 ++minijail_user_called;
476}
477
478int minijail_uidmap(struct minijail *j, const char *uidmap)
479{
480 return 0;
481}
482
483int minijail_gidmap(struct minijail *j, const char *gidmap)
484{
485 return 0;
486}
487
488int minijail_enter_pivot_root(struct minijail *j, const char *dir)
489{
490 return 0;
491}
492
493void minijail_run_as_init(struct minijail *j)
494{
495 ++minijail_run_as_init_called;
496}
497
498int minijail_run_pid_pipes_no_preload(struct minijail *j, const char *filename,
499 char *const argv[], pid_t *pchild_pid,
500 int *pstdin_fd, int *pstdout_fd,
501 int *pstderr_fd)
502{
503 *pchild_pid = INIT_TEST_PID;
504 return 0;
505}
506
507int minijail_write_pid_file(struct minijail *j, const char *path)
508{
509 return 0;
510}
511
512int minijail_wait(struct minijail *j)
513{
514 ++minijail_wait_called;
515 return 0;
516}
517
518int minijail_use_alt_syscall(struct minijail *j, const char *table)
519{
520 minijail_alt_syscall_table = table;
521 return 0;
522}
523
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800524int minijail_add_to_cgroup(struct minijail *j, const char *cg_path)
Dylan Reid837c74a2016-01-22 17:25:21 -0800525{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800526 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800527}
528
529void minijail_reset_signal_mask(struct minijail *j)
530{
531 ++minijail_reset_signal_mask_called;
532}
533
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800534void minijail_skip_remount_private(struct minijail *j)
535{
536}
537
Dylan Reid837c74a2016-01-22 17:25:21 -0800538TEST_HARNESS_MAIN