blob: 1b357abcf717722b625e1173f74ad3fa822d31db [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;
62
63 int init_called_count;
64 int deny_all_devs_called_count;
65
Dylan Reid355d5e42016-04-29 16:53:31 -070066 int add_dev_major[MAX_ADD_DEVICE_CALLS];
67 int add_dev_minor[MAX_ADD_DEVICE_CALLS];
68 int add_dev_read[MAX_ADD_DEVICE_CALLS];
69 int add_dev_write[MAX_ADD_DEVICE_CALLS];
70 int add_dev_modify[MAX_ADD_DEVICE_CALLS];
71 char add_dev_type[MAX_ADD_DEVICE_CALLS];
72 int add_dev_called_count;
Dylan Reid837c74a2016-01-22 17:25:21 -080073};
74
75static struct mock_cgroup gmcg;
76
77static int mock_freeze(const struct container_cgroup *cg)
78{
79 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
80 return mcg->freeze_ret;
81}
82
83static int mock_thaw(const struct container_cgroup *cg)
84{
85 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
86 return mcg->thaw_ret;
87}
88
89static int mock_deny_all_devices(const struct container_cgroup *cg)
90{
91 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
92 ++mcg->deny_all_devs_called_count;
93 return mcg->deny_all_devs_ret;
94}
95
96static int mock_add_device(const struct container_cgroup *cg, int major,
97 int minor, int read, int write, int modify,
98 char type)
99{
100 struct mock_cgroup *mcg = (struct mock_cgroup *)cg;
Dylan Reid355d5e42016-04-29 16:53:31 -0700101
102 if (mcg->add_dev_called_count >= MAX_ADD_DEVICE_CALLS)
103 return mcg->add_device_ret;
104 mcg->add_dev_major[mcg->add_dev_called_count] = major;
105 mcg->add_dev_minor[mcg->add_dev_called_count] = minor;
106 mcg->add_dev_read[mcg->add_dev_called_count] = read;
107 mcg->add_dev_write[mcg->add_dev_called_count] = write;
108 mcg->add_dev_modify[mcg->add_dev_called_count] = modify;
109 mcg->add_dev_type[mcg->add_dev_called_count] = type;
110 mcg->add_dev_called_count++;
Dylan Reid837c74a2016-01-22 17:25:21 -0800111 return mcg->add_device_ret;
112}
113
114struct container_cgroup *container_cgroup_new(const char *name,
115 const char *cgroup_root)
116{
117 gmcg.cg.name = strdup(name);
118 return &gmcg.cg;
119}
120
121void container_cgroup_destroy(struct container_cgroup *c)
122{
123 free(c->name);
124}
125
126/* Start of tests. */
127FIXTURE(container_test) {
128 struct container_config *config;
129 struct container *container;
130 int mount_flags;
131 char *rootfs;
132};
133
134FIXTURE_SETUP(container_test)
135{
136 char temp_template[] = "/tmp/cgtestXXXXXX";
137 char rundir_template[] = "/tmp/cgtest_runXXXXXX";
138 char *rundir;
139 char path[256];
140 char *pargs[] = {
141 "/sbin/init",
142 };
143
144 memset(&mount_call_args, 0, sizeof(mount_call_args));
145 mount_called = 0;
146 memset(&mknod_call_args, 0, sizeof(mknod_call_args));
147 mkdtemp_root = NULL;
148
149 memset(&gmcg, 0, sizeof(gmcg));
150 static const struct cgroup_ops cgops = {
151 .freeze = mock_freeze,
152 .thaw = mock_thaw,
153 .deny_all_devices = mock_deny_all_devices,
154 .add_device = mock_add_device,
155 };
156 gmcg.cg.ops = &cgops;
157
158 self->rootfs = strdup(mkdtemp(temp_template));
159
160 kill_called = 0;
161 minijail_alt_syscall_table = NULL;
162 minijail_ipc_called = 0;
163 minijail_vfs_called = 0;
164 minijail_net_called = 0;
165 minijail_pids_called = 0;
166 minijail_run_as_init_called = 0;
167 minijail_user_called = 0;
168 minijail_wait_called = 0;
169 minijail_reset_signal_mask_called = 0;
170 mount_ret = 0;
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800171 stat_rdev_ret = makedev(2, 3);
Dylan Reid837c74a2016-01-22 17:25:21 -0800172
173 snprintf(path, sizeof(path), "%s/dev", self->rootfs);
174 //mkdir(path, S_IRWXU | S_IRWXG);
175
176 self->mount_flags = MS_NOSUID | MS_NODEV | MS_NOEXEC;
177
178 self->config = container_config_create();
179 container_config_rootfs(self->config, self->rootfs);
180 container_config_program_argv(self->config, pargs, 1);
181 container_config_alt_syscall_table(self->config, "testsyscalltable");
182 container_config_add_mount(self->config,
183 "testtmpfs",
184 "tmpfs",
185 "/tmp",
186 "tmpfs",
187 NULL,
188 self->mount_flags,
189 1000,
190 1000,
191 0x666,
192 0,
193 1);
194 container_config_add_device(self->config,
195 'c',
196 "/dev/foo",
197 S_IRWXU | S_IRWXG,
198 245,
199 2,
Dylan Reid355d5e42016-04-29 16:53:31 -0700200 0,
201 1000,
202 1001,
203 1,
204 1,
205 0);
206 /* test dynamic minor on /dev/null */
207 container_config_add_device(self->config,
208 'c',
209 "/dev/null",
210 S_IRWXU | S_IRWXG,
211 1,
212 -1,
213 1,
Dylan Reid837c74a2016-01-22 17:25:21 -0800214 1000,
215 1001,
216 1,
217 1,
218 0);
219
220 rundir = mkdtemp(rundir_template);
Dylan Reide040c6b2016-05-02 18:49:02 -0700221 self->container = container_new("containerUT", rundir);
Dylan Reid837c74a2016-01-22 17:25:21 -0800222 ASSERT_NE(NULL, self->container);
223}
224
225FIXTURE_TEARDOWN(container_test)
226{
227 char path[256];
228 int i;
229
230 container_destroy(self->container);
231 snprintf(path, sizeof(path), "rm -rf %s", self->rootfs);
232 EXPECT_EQ(0, system(path));
233 free(self->rootfs);
234
235 for (i = 0; i < mount_called; i++) {
236 free(mount_call_args[i].source);
237 free(mount_call_args[i].target);
238 free(mount_call_args[i].filesystemtype);
239 }
240 free(mknod_call_args.pathname);
241 free(mkdtemp_root);
242}
243
244TEST_F(container_test, test_mount_tmp_start)
245{
246 char *path;
247
Dylan Reide040c6b2016-05-02 18:49:02 -0700248 EXPECT_EQ(0, container_start(self->container, self->config));
Dylan Reid837c74a2016-01-22 17:25:21 -0800249 EXPECT_EQ(2, mount_called);
250 EXPECT_EQ(0, strcmp(mount_call_args[1].source, "tmpfs"));
251 EXPECT_LT(0, asprintf(&path, "%s/root/tmp", mkdtemp_root));
252 EXPECT_EQ(0, strcmp(mount_call_args[1].target, path));
253 free(path);
254 EXPECT_EQ(0, strcmp(mount_call_args[1].filesystemtype,
255 "tmpfs"));
256 EXPECT_EQ(mount_call_args[1].mountflags, self->mount_flags);
257 EXPECT_EQ(mount_call_args[1].data, NULL);
258
259 EXPECT_EQ(1, minijail_ipc_called);
260 EXPECT_EQ(1, minijail_vfs_called);
261 EXPECT_EQ(1, minijail_net_called);
262 EXPECT_EQ(1, minijail_pids_called);
263 EXPECT_EQ(1, minijail_user_called);
264 EXPECT_EQ(1, minijail_run_as_init_called);
265 EXPECT_EQ(1, gmcg.deny_all_devs_called_count);
266
Dylan Reid355d5e42016-04-29 16:53:31 -0700267 EXPECT_EQ(245, gmcg.add_dev_major[0]);
268 EXPECT_EQ(2, gmcg.add_dev_minor[0]);
269 EXPECT_EQ(1, gmcg.add_dev_read[0]);
270 EXPECT_EQ(1, gmcg.add_dev_write[0]);
271 EXPECT_EQ(0, gmcg.add_dev_modify[0]);
272 EXPECT_EQ('c', gmcg.add_dev_type[0]);
273
274 EXPECT_EQ(1, gmcg.add_dev_major[1]);
275 EXPECT_EQ(3, gmcg.add_dev_minor[1]);
276 EXPECT_EQ(1, gmcg.add_dev_read[1]);
277 EXPECT_EQ(1, gmcg.add_dev_write[1]);
278 EXPECT_EQ(0, gmcg.add_dev_modify[1]);
279 EXPECT_EQ('c', gmcg.add_dev_type[1]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800280
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800281 EXPECT_LT(0, asprintf(&path, "%s/root/dev/null", mkdtemp_root));
282 EXPECT_EQ(0, strcmp(mknod_call_args.pathname, path));
283 free(path);
284 EXPECT_EQ(mknod_call_args.mode, S_IRWXU | S_IRWXG | S_IFCHR);
285 EXPECT_EQ(mknod_call_args.dev, makedev(1, 3));
286
Dylan Reid837c74a2016-01-22 17:25:21 -0800287 ASSERT_NE(NULL, minijail_alt_syscall_table);
288 EXPECT_EQ(0, strcmp(minijail_alt_syscall_table,
289 "testsyscalltable"));
290
291 EXPECT_EQ(0, container_wait(self->container));
292 EXPECT_EQ(1, minijail_wait_called);
293 EXPECT_EQ(1, minijail_reset_signal_mask_called);
294}
295
296TEST_F(container_test, test_kill_container)
297{
Dylan Reide040c6b2016-05-02 18:49:02 -0700298 EXPECT_EQ(0, container_start(self->container, self->config));
Dylan Reid837c74a2016-01-22 17:25:21 -0800299 EXPECT_EQ(0, container_kill(self->container));
300 EXPECT_EQ(1, kill_called);
301 EXPECT_EQ(SIGKILL, kill_sig);
302 EXPECT_EQ(1, minijail_wait_called);
303}
304
305/* libc stubs so the UT doesn't need root to call mount, etc. */
306int mount(const char *source, const char *target,
307 const char *filesystemtype, unsigned long mountflags,
308 const void *data)
309{
310 if (mount_called >= 5)
311 return 0;
312
313 mount_call_args[mount_called].source = strdup(source);
314 mount_call_args[mount_called].target = strdup(target);
315 mount_call_args[mount_called].filesystemtype = strdup(filesystemtype);
316 mount_call_args[mount_called].mountflags = mountflags;
317 mount_call_args[mount_called].data = data;
318 ++mount_called;
319 return 0;
320}
321
322int umount(const char *target)
323{
324 return 0;
325}
326
327int mknod(const char *pathname, mode_t mode, dev_t dev)
328{
329 mknod_call_args.pathname = strdup(pathname);
330 mknod_call_args.mode = mode;
331 mknod_call_args.dev = dev;
332 return 0;
333}
334
335int chown(const char *path, uid_t owner, gid_t group)
336{
337 return 0;
338};
339
340int kill(pid_t pid, int sig)
341{
342 ++kill_called;
343 kill_sig = sig;
344 return 0;
345}
346
347int stat(const char *path, struct stat *buf)
348{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800349 buf->st_rdev = stat_rdev_ret;
Dylan Reid837c74a2016-01-22 17:25:21 -0800350 return 0;
351}
352
353int chmod(const char *path, mode_t mode)
354{
355 return 0;
356}
357
358char *mkdtemp(char *template)
359{
360 mkdtemp_root = strdup(template);
361 return template;
362}
363
364int mkdir(const char *pathname, mode_t mode)
365{
366 return 0;
367}
368
369int rmdir(const char *pathname)
370{
371 return 0;
372}
373
374int unlink(const char *pathname)
375{
376 return 0;
377}
378
379/* Minijail stubs */
380struct minijail *minijail_new(void)
381{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800382 return (struct minijail *)0x55;
383}
384
385void minijail_destroy(struct minijail *j)
386{
Dylan Reid837c74a2016-01-22 17:25:21 -0800387}
388
389int minijail_mount(struct minijail *j, const char *src, const char *dest,
390 const char *type, unsigned long flags)
391{
392 return 0;
393}
394
395void minijail_namespace_vfs(struct minijail *j)
396{
397 ++minijail_vfs_called;
398}
399
400void minijail_namespace_ipc(struct minijail *j)
401{
402 ++minijail_ipc_called;
403}
404
405void minijail_namespace_net(struct minijail *j)
406{
407 ++minijail_net_called;
408}
409
410void minijail_namespace_pids(struct minijail *j)
411{
412 ++minijail_pids_called;
413}
414
415void minijail_namespace_user(struct minijail *j)
416{
417 ++minijail_user_called;
418}
419
420int minijail_uidmap(struct minijail *j, const char *uidmap)
421{
422 return 0;
423}
424
425int minijail_gidmap(struct minijail *j, const char *gidmap)
426{
427 return 0;
428}
429
430int minijail_enter_pivot_root(struct minijail *j, const char *dir)
431{
432 return 0;
433}
434
435void minijail_run_as_init(struct minijail *j)
436{
437 ++minijail_run_as_init_called;
438}
439
440int minijail_run_pid_pipes_no_preload(struct minijail *j, const char *filename,
441 char *const argv[], pid_t *pchild_pid,
442 int *pstdin_fd, int *pstdout_fd,
443 int *pstderr_fd)
444{
445 *pchild_pid = INIT_TEST_PID;
446 return 0;
447}
448
449int minijail_write_pid_file(struct minijail *j, const char *path)
450{
451 return 0;
452}
453
454int minijail_wait(struct minijail *j)
455{
456 ++minijail_wait_called;
457 return 0;
458}
459
460int minijail_use_alt_syscall(struct minijail *j, const char *table)
461{
462 minijail_alt_syscall_table = table;
463 return 0;
464}
465
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800466int minijail_add_to_cgroup(struct minijail *j, const char *cg_path)
Dylan Reid837c74a2016-01-22 17:25:21 -0800467{
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800468 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800469}
470
471void minijail_reset_signal_mask(struct minijail *j)
472{
473 ++minijail_reset_signal_mask_called;
474}
475
Chinyue Chen03c54ae2016-06-29 12:29:10 +0800476void minijail_skip_remount_private(struct minijail *j)
477{
478}
479
Dylan Reid837c74a2016-01-22 17:25:21 -0800480TEST_HARNESS_MAIN