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