]> git.proxmox.com Git - mirror_lxc.git/blame - src/tests/attach.c
tests: include config.h
[mirror_lxc.git] / src / tests / attach.c
CommitLineData
72863294
DE
1/* liblxcapi
2 *
3 * Copyright © 2013 Oracle.
4 *
5 * Authors:
6 * Dwight Engen <dwight.engen@oracle.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2, as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
e49c56d6
CB
22#include "config.h"
23
ba2be1a8 24#include <errno.h>
95ee490b 25#include <string.h>
94ac256f 26#include <unistd.h>
95ee490b 27#include <sys/stat.h>
94ac256f 28#include <sys/syscall.h>
ba2be1a8
CB
29#include <sys/types.h>
30
31#include "lxctest.h"
32#include "utils.h"
33#include "lsm/lsm.h"
34
35#include <lxc/lxccontainer.h>
72863294 36
34498dea 37#if !HAVE_STRLCPY
58db1a61 38#include "strlcpy.h"
18cd4b54
DJ
39#endif
40
72863294 41#define TSTNAME "lxc-attach-test"
c59ce7de
SH
42#define TSTOUT(fmt, ...) do { \
43 fprintf(stdout, fmt, ##__VA_ARGS__); fflush(NULL); \
44} while (0)
72863294 45#define TSTERR(fmt, ...) do { \
c59ce7de 46 fprintf(stderr, "%s:%d " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); fflush(NULL); \
72863294
DE
47} while (0)
48
72863294
DE
49static const char *lsm_config_key = NULL;
50static const char *lsm_label = NULL;
51
af04d847 52struct lsm_ops *lsm_ops;
d701d729 53
72863294
DE
54static void test_lsm_detect(void)
55{
af04d847 56 if (lsm_ops->enabled(lsm_ops)) {
d701d729 57 if (!strcmp(lsm_ops->name, "SELinux")) {
b84702ab 58 lsm_config_key = "lxc.selinux.context";
72863294
DE
59 lsm_label = "unconfined_u:unconfined_r:lxc_t:s0-s0:c0.c1023";
60 }
d701d729 61 else if (!strcmp(lsm_ops->name, "AppArmor")) {
a1d5fdfd 62 lsm_config_key = "lxc.apparmor.profile";
f58236fd
SH
63 if (file_exists("/proc/self/ns/cgroup"))
64 lsm_label = "lxc-container-default-cgns";
65 else
66 lsm_label = "lxc-container-default";
72863294
DE
67 }
68 else {
d701d729 69 TSTERR("unknown lsm %s enabled, add test code here", lsm_ops->name);
72863294
DE
70 exit(EXIT_FAILURE);
71 }
72 }
73}
74
bc605ac6 75#if HAVE_APPARMOR || HAVE_SELINUX
72863294
DE
76static void test_attach_lsm_set_config(struct lxc_container *ct)
77{
78 ct->load_config(ct, NULL);
79 ct->set_config_item(ct, lsm_config_key, lsm_label);
80 ct->save_config(ct, NULL);
81}
82
83static int test_attach_lsm_func_func(void* payload)
84{
af04d847 85 TSTOUT("%s", lsm_ops->process_label_get(lsm_ops, syscall(SYS_getpid)));
72863294
DE
86 return 0;
87}
88
89static int test_attach_lsm_func(struct lxc_container *ct)
90{
91 int ret;
92 pid_t pid;
93 int pipefd[2];
94 char result[1024];
95 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
96
c59ce7de 97 TSTOUT("Testing attach lsm label with func...\n");
72863294
DE
98
99 ret = pipe(pipefd);
100 if (ret < 0) {
101 TSTERR("pipe failed %d", ret);
102 return ret;
103 }
104 attach_options.stdout_fd = pipefd[1];
105 attach_options.attach_flags &= ~(LXC_ATTACH_LSM_EXEC|LXC_ATTACH_DROP_CAPABILITIES);
106 attach_options.attach_flags |= LXC_ATTACH_LSM_NOW;
107 ret = ct->attach(ct, test_attach_lsm_func_func, NULL, &attach_options, &pid);
108 if (ret < 0) {
109 TSTERR("attach failed");
110 goto err1;
111 }
112
113 ret = read(pipefd[0], result, sizeof(result)-1);
114 if (ret < 0) {
115 TSTERR("read failed %d", ret);
116 goto err2;
117 }
118
119 result[ret] = '\0';
120 if (strcmp(lsm_label, result)) {
121 TSTERR("LSM label mismatch expected:%s got:%s", lsm_label, result);
122 ret = -1;
123 goto err2;
124 }
125 ret = 0;
126
127err2:
dbdf8cf4 128 (void)wait_for_pid(pid);
72863294
DE
129err1:
130 close(pipefd[0]);
131 close(pipefd[1]);
132 return ret;
133}
134
135static int test_attach_lsm_cmd(struct lxc_container *ct)
136{
137 int ret;
138 pid_t pid;
139 int pipefd[2];
140 char result[1024];
141 char *space;
142 char *argv[] = {"cat", "/proc/self/attr/current", NULL};
143 lxc_attach_command_t command = {"cat", argv};
144 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
145
c59ce7de 146 TSTOUT("Testing attach lsm label with cmd...\n");
72863294
DE
147
148 ret = pipe(pipefd);
149 if (ret < 0) {
150 TSTERR("pipe failed %d", ret);
151 return ret;
152 }
153 attach_options.stdout_fd = pipefd[1];
154
155 ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, &pid);
156 if (ret < 0) {
157 TSTERR("attach failed");
158 goto err1;
159 }
160
161 ret = read(pipefd[0], result, sizeof(result)-1);
162 if (ret < 0) {
163 TSTERR("read failed %d", ret);
164 goto err2;
165 }
166 result[ret] = '\0';
46cd2845 167 space = strchr(result, '\n');
72863294
DE
168 if (space)
169 *space = '\0';
46cd2845 170 space = strchr(result, ' ');
72863294
DE
171 if (space)
172 *space = '\0';
173
174 ret = -1;
175 if (strcmp(lsm_label, result)) {
176 TSTERR("LSM label mismatch expected:%s got:%s", lsm_label, result);
177 goto err2;
178 }
179 ret = 0;
180
181err2:
dbdf8cf4 182 (void)wait_for_pid(pid);
72863294
DE
183err1:
184 close(pipefd[0]);
185 close(pipefd[1]);
186 return ret;
187}
188#else
189static void test_attach_lsm_set_config(struct lxc_container *ct) {}
190static int test_attach_lsm_func(struct lxc_container *ct) { return 0; }
191static int test_attach_lsm_cmd(struct lxc_container *ct) { return 0; }
192#endif /* HAVE_APPARMOR || HAVE_SELINUX */
193
194static int test_attach_func_func(void* payload)
195{
94ac256f 196 TSTOUT("%d", (int)syscall(SYS_getpid));
72863294
DE
197 return 0;
198}
199
200static int test_attach_func(struct lxc_container *ct)
201{
202 int ret;
203 pid_t pid,nspid;
204 int pipefd[2];
205 char result[1024];
206 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
207
c59ce7de 208 TSTOUT("Testing attach with func...\n");
72863294
DE
209
210 /* XXX: We can't just use &nspid and have test_attach_func_func fill
211 * it in because the function doesn't run in our process context but
212 * in a fork()ed from us context. We read the result through a pipe.
213 */
214 ret = pipe(pipefd);
215 if (ret < 0) {
216 TSTERR("pipe failed %d", ret);
217 return ret;
218 }
219 attach_options.stdout_fd = pipefd[1];
220
221 ret = ct->attach(ct, test_attach_func_func, NULL, &attach_options, &pid);
222 if (ret < 0) {
223 TSTERR("attach failed");
224 goto err1;
225 }
226
227 ret = read(pipefd[0], result, sizeof(result)-1);
228 if (ret < 0) {
229 TSTERR("read failed %d", ret);
230 goto err2;
231 }
232 result[ret] = '\0';
233
234 /* There is a small chance the pid is reused inside the NS, so we
235 * just print it and don't actually do this check
236 *
237 * if (pid == nspid) TSTERR(...)
238 */
239 nspid = atoi(result);
c59ce7de 240 TSTOUT("Pid:%d in NS:%d\n", pid, nspid);
72863294
DE
241 ret = 0;
242
243err2:
dbdf8cf4 244 (void)wait_for_pid(pid);
72863294
DE
245err1:
246 close(pipefd[0]);
247 close(pipefd[1]);
248 return ret;
249}
250
251static int test_attach_cmd(struct lxc_container *ct)
252{
253 int ret;
254 pid_t pid;
255 char *argv[] = {"cmp", "-s", "/sbin/init", "/bin/busybox", NULL};
256 lxc_attach_command_t command = {"cmp", argv};
257 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
258
c59ce7de 259 TSTOUT("Testing attach with success command...\n");
72863294
DE
260 ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, &pid);
261 if (ret < 0) {
262 TSTERR("attach failed");
263 return ret;
264 }
265
266 ret = wait_for_pid(pid);
267 if (ret < 0) {
268 TSTERR("attach success command got bad return %d", ret);
269 return ret;
270 }
271
c59ce7de 272 TSTOUT("Testing attach with failure command...\n");
72863294
DE
273 argv[2] = "/etc/fstab";
274 ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, &pid);
275 if (ret < 0) {
276 TSTERR("attach failed");
277 return ret;
278 }
279
280 ret = wait_for_pid(pid);
281 if (ret == 0) {
282 TSTERR("attach failure command got bad return %d", ret);
283 return -1;
284 }
285 return 0;
286}
287
288/* test_ct_destroy: stop and destroy the test container
289 *
290 * @ct : the container
291 */
292static void test_ct_destroy(struct lxc_container *ct)
293{
294 ct->stop(ct);
295 ct->destroy(ct);
296 lxc_container_put(ct);
297}
298
299/* test_ct_create: create and start test container
300 *
301 * @lxcpath : the lxcpath in which to create the container
302 * @group : name of the container group or NULL for default "lxc"
303 * @name : name of the container
304 * @template : template to use when creating the container
305 */
306static struct lxc_container *test_ct_create(const char *lxcpath,
307 const char *group, const char *name,
308 const char *template)
309{
310 int ret;
311 struct lxc_container *ct = NULL;
312
313 if (lxcpath) {
314 ret = mkdir(lxcpath, 0755);
315 if (ret < 0 && errno != EEXIST) {
316 TSTERR("failed to mkdir %s %s", lxcpath, strerror(errno));
317 goto out1;
318 }
319 }
320
321 if ((ct = lxc_container_new(name, lxcpath)) == NULL) {
322 TSTERR("instantiating container %s", name);
323 goto out1;
324 }
325 if (ct->is_defined(ct)) {
621c7cc7 326 test_ct_destroy(ct);
72863294
DE
327 ct = lxc_container_new(name, lxcpath);
328 }
329 if (!ct->createl(ct, template, NULL, NULL, 0, NULL)) {
330 TSTERR("creating container %s", name);
331 goto out2;
332 }
333
af04d847 334 if (lsm_ops->enabled(lsm_ops))
72863294
DE
335 test_attach_lsm_set_config(ct);
336
540f932a 337 ct->want_daemonize(ct, true);
72863294
DE
338 if (!ct->startl(ct, 0, NULL)) {
339 TSTERR("starting container %s", name);
340 goto out2;
341 }
342 return ct;
343
344out2:
345 test_ct_destroy(ct);
346 ct = NULL;
347out1:
348 return ct;
349}
350
351
0b98289e 352static int test_attach(const char *lxcpath, const char *name, const char *template)
72863294
DE
353{
354 int ret = -1;
355 struct lxc_container *ct;
356
c59ce7de 357 TSTOUT("Testing attach with on lxcpath:%s\n", lxcpath ? lxcpath : "<default>");
72863294
DE
358 ct = test_ct_create(lxcpath, NULL, name, template);
359 if (!ct)
360 goto err1;
361
362 ret = test_attach_cmd(ct);
363 if (ret < 0) {
364 TSTERR("attach cmd test failed");
365 goto err2;
366 }
367
368 ret = test_attach_func(ct);
369 if (ret < 0) {
370 TSTERR("attach func test failed");
371 goto err2;
372 }
373
af04d847 374 if (lsm_ops->enabled(lsm_ops)) {
72863294
DE
375 ret = test_attach_lsm_cmd(ct);
376 if (ret < 0) {
377 TSTERR("attach lsm cmd test failed");
378 goto err2;
379 }
380
381 ret = test_attach_lsm_func(ct);
382 if (ret < 0) {
383 TSTERR("attach lsm func test failed");
384 goto err2;
385 }
386 }
387 ret = 0;
388
389err2:
390 test_ct_destroy(ct);
391err1:
392 return ret;
393}
394
395int main(int argc, char *argv[])
396{
ba2be1a8
CB
397 int i, ret;
398 struct lxc_log log;
399 char template[sizeof(P_tmpdir"/attach_XXXXXX")];
400 int fret = EXIT_FAILURE;
401
18cd4b54
DJ
402 (void)strlcpy(template, P_tmpdir"/attach_XXXXXX", sizeof(template));
403
4eb19ac0 404 lsm_ops = lsm_init_static();
d701d729 405
ba2be1a8
CB
406 i = lxc_make_tmpfile(template, false);
407 if (i < 0) {
408 lxc_error("Failed to create temporary log file for container %s\n", TSTNAME);
409 exit(EXIT_FAILURE);
410 } else {
411 lxc_debug("Using \"%s\" as temporary log file for container %s\n", template, TSTNAME);
412 close(i);
413 }
414
415 log.name = TSTNAME;
416 log.file = template;
417 log.level = "TRACE";
418 log.prefix = "attach";
419 log.quiet = false;
420 log.lxcpath = NULL;
421 if (lxc_log_init(&log))
422 goto on_error;
72863294
DE
423
424 test_lsm_detect();
425 ret = test_attach(NULL, TSTNAME, "busybox");
426 if (ret < 0)
ba2be1a8 427 goto on_error;
72863294 428
c59ce7de 429 TSTOUT("\n");
72863294
DE
430 ret = test_attach(LXCPATH "/alternate-path-test", TSTNAME, "busybox");
431 if (ret < 0)
ba2be1a8 432 goto on_error;
72863294 433
c59ce7de 434 TSTOUT("All tests passed\n");
ba2be1a8
CB
435 fret = EXIT_SUCCESS;
436
437on_error:
438 if (fret != EXIT_SUCCESS) {
439 int fd;
440
441 fd = open(template, O_RDONLY);
442 if (fd >= 0) {
443 char buf[4096];
444 ssize_t buflen;
445 while ((buflen = read(fd, buf, 1024)) > 0) {
446 buflen = write(STDERR_FILENO, buf, buflen);
447 if (buflen <= 0)
448 break;
449 }
450 close(fd);
451 }
452 }
453 (void)rmdir(LXCPATH "/alternate-path-test");
454 (void)unlink(template);
455 exit(fret);
72863294 456}