]> git.proxmox.com Git - mirror_lxc.git/blame - src/tests/attach.c
Allow unsetting daemonize and close_fds
[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
22#include <lxc/lxccontainer.h>
23#include <lxc/utils.h>
24#include <lxc/lsm/lsm.h>
25
26#include <errno.h>
27#include <unistd.h>
28
29#define TSTNAME "lxc-attach-test"
30#define TSTERR(fmt, ...) do { \
31 fprintf(stderr, "%s:%d " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \
32} while (0)
33
72863294
DE
34static const char *lsm_config_key = NULL;
35static const char *lsm_label = NULL;
36
37static void test_lsm_detect(void)
38{
39 if (lsm_enabled()) {
40 if (!strcmp(lsm_name(), "SELinux")) {
41 lsm_config_key = "lxc.se_context";
42 lsm_label = "unconfined_u:unconfined_r:lxc_t:s0-s0:c0.c1023";
43 }
44 else if (!strcmp(lsm_name(), "AppArmor")) {
45 lsm_config_key = "lxc.aa_profile";
46 lsm_label = "lxc-container-default";
47 }
48 else {
49 TSTERR("unknown lsm %s enabled, add test code here", lsm_name());
50 exit(EXIT_FAILURE);
51 }
52 }
53}
54
bc605ac6 55#if HAVE_APPARMOR || HAVE_SELINUX
72863294
DE
56static void test_attach_lsm_set_config(struct lxc_container *ct)
57{
58 ct->load_config(ct, NULL);
59 ct->set_config_item(ct, lsm_config_key, lsm_label);
60 ct->save_config(ct, NULL);
61}
62
63static int test_attach_lsm_func_func(void* payload)
64{
65 printf("%s", lsm_process_label_get(getpid()));
66 return 0;
67}
68
69static int test_attach_lsm_func(struct lxc_container *ct)
70{
71 int ret;
72 pid_t pid;
73 int pipefd[2];
74 char result[1024];
75 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
76
77 printf("Testing attach lsm label with func...\n");
78
79 ret = pipe(pipefd);
80 if (ret < 0) {
81 TSTERR("pipe failed %d", ret);
82 return ret;
83 }
84 attach_options.stdout_fd = pipefd[1];
85 attach_options.attach_flags &= ~(LXC_ATTACH_LSM_EXEC|LXC_ATTACH_DROP_CAPABILITIES);
86 attach_options.attach_flags |= LXC_ATTACH_LSM_NOW;
87 ret = ct->attach(ct, test_attach_lsm_func_func, NULL, &attach_options, &pid);
88 if (ret < 0) {
89 TSTERR("attach failed");
90 goto err1;
91 }
92
93 ret = read(pipefd[0], result, sizeof(result)-1);
94 if (ret < 0) {
95 TSTERR("read failed %d", ret);
96 goto err2;
97 }
98
99 result[ret] = '\0';
100 if (strcmp(lsm_label, result)) {
101 TSTERR("LSM label mismatch expected:%s got:%s", lsm_label, result);
102 ret = -1;
103 goto err2;
104 }
105 ret = 0;
106
107err2:
108 wait_for_pid(pid);
109err1:
110 close(pipefd[0]);
111 close(pipefd[1]);
112 return ret;
113}
114
115static int test_attach_lsm_cmd(struct lxc_container *ct)
116{
117 int ret;
118 pid_t pid;
119 int pipefd[2];
120 char result[1024];
121 char *space;
122 char *argv[] = {"cat", "/proc/self/attr/current", NULL};
123 lxc_attach_command_t command = {"cat", argv};
124 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
125
126 printf("Testing attach lsm label with cmd...\n");
127
128 ret = pipe(pipefd);
129 if (ret < 0) {
130 TSTERR("pipe failed %d", ret);
131 return ret;
132 }
133 attach_options.stdout_fd = pipefd[1];
134
135 ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, &pid);
136 if (ret < 0) {
137 TSTERR("attach failed");
138 goto err1;
139 }
140
141 ret = read(pipefd[0], result, sizeof(result)-1);
142 if (ret < 0) {
143 TSTERR("read failed %d", ret);
144 goto err2;
145 }
146 result[ret] = '\0';
147 space = index(result, '\n');
148 if (space)
149 *space = '\0';
150 space = index(result, ' ');
151 if (space)
152 *space = '\0';
153
154 ret = -1;
155 if (strcmp(lsm_label, result)) {
156 TSTERR("LSM label mismatch expected:%s got:%s", lsm_label, result);
157 goto err2;
158 }
159 ret = 0;
160
161err2:
162 wait_for_pid(pid);
163err1:
164 close(pipefd[0]);
165 close(pipefd[1]);
166 return ret;
167}
168#else
169static void test_attach_lsm_set_config(struct lxc_container *ct) {}
170static int test_attach_lsm_func(struct lxc_container *ct) { return 0; }
171static int test_attach_lsm_cmd(struct lxc_container *ct) { return 0; }
172#endif /* HAVE_APPARMOR || HAVE_SELINUX */
173
174static int test_attach_func_func(void* payload)
175{
176 printf("%d", getpid());
177 return 0;
178}
179
180static int test_attach_func(struct lxc_container *ct)
181{
182 int ret;
183 pid_t pid,nspid;
184 int pipefd[2];
185 char result[1024];
186 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
187
188 printf("Testing attach with func...\n");
189
190 /* XXX: We can't just use &nspid and have test_attach_func_func fill
191 * it in because the function doesn't run in our process context but
192 * in a fork()ed from us context. We read the result through a pipe.
193 */
194 ret = pipe(pipefd);
195 if (ret < 0) {
196 TSTERR("pipe failed %d", ret);
197 return ret;
198 }
199 attach_options.stdout_fd = pipefd[1];
200
201 ret = ct->attach(ct, test_attach_func_func, NULL, &attach_options, &pid);
202 if (ret < 0) {
203 TSTERR("attach failed");
204 goto err1;
205 }
206
207 ret = read(pipefd[0], result, sizeof(result)-1);
208 if (ret < 0) {
209 TSTERR("read failed %d", ret);
210 goto err2;
211 }
212 result[ret] = '\0';
213
214 /* There is a small chance the pid is reused inside the NS, so we
215 * just print it and don't actually do this check
216 *
217 * if (pid == nspid) TSTERR(...)
218 */
219 nspid = atoi(result);
220 printf("Pid:%d in NS:%d\n", pid, nspid);
221 ret = 0;
222
223err2:
224 wait_for_pid(pid);
225err1:
226 close(pipefd[0]);
227 close(pipefd[1]);
228 return ret;
229}
230
231static int test_attach_cmd(struct lxc_container *ct)
232{
233 int ret;
234 pid_t pid;
235 char *argv[] = {"cmp", "-s", "/sbin/init", "/bin/busybox", NULL};
236 lxc_attach_command_t command = {"cmp", argv};
237 lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT;
238
239 printf("Testing attach with success command...\n");
240 ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, &pid);
241 if (ret < 0) {
242 TSTERR("attach failed");
243 return ret;
244 }
245
246 ret = wait_for_pid(pid);
247 if (ret < 0) {
248 TSTERR("attach success command got bad return %d", ret);
249 return ret;
250 }
251
252 printf("Testing attach with failure command...\n");
253 argv[2] = "/etc/fstab";
254 ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, &pid);
255 if (ret < 0) {
256 TSTERR("attach failed");
257 return ret;
258 }
259
260 ret = wait_for_pid(pid);
261 if (ret == 0) {
262 TSTERR("attach failure command got bad return %d", ret);
263 return -1;
264 }
265 return 0;
266}
267
268/* test_ct_destroy: stop and destroy the test container
269 *
270 * @ct : the container
271 */
272static void test_ct_destroy(struct lxc_container *ct)
273{
274 ct->stop(ct);
275 ct->destroy(ct);
276 lxc_container_put(ct);
277}
278
279/* test_ct_create: create and start test container
280 *
281 * @lxcpath : the lxcpath in which to create the container
282 * @group : name of the container group or NULL for default "lxc"
283 * @name : name of the container
284 * @template : template to use when creating the container
285 */
286static struct lxc_container *test_ct_create(const char *lxcpath,
287 const char *group, const char *name,
288 const char *template)
289{
290 int ret;
291 struct lxc_container *ct = NULL;
292
293 if (lxcpath) {
294 ret = mkdir(lxcpath, 0755);
295 if (ret < 0 && errno != EEXIST) {
296 TSTERR("failed to mkdir %s %s", lxcpath, strerror(errno));
297 goto out1;
298 }
299 }
300
301 if ((ct = lxc_container_new(name, lxcpath)) == NULL) {
302 TSTERR("instantiating container %s", name);
303 goto out1;
304 }
305 if (ct->is_defined(ct)) {
306 ct->stop(ct);
307 ct->destroy(ct);
308 ct = lxc_container_new(name, lxcpath);
309 }
310 if (!ct->createl(ct, template, NULL, NULL, 0, NULL)) {
311 TSTERR("creating container %s", name);
312 goto out2;
313 }
314
315 if (lsm_enabled())
316 test_attach_lsm_set_config(ct);
317
540f932a 318 ct->want_daemonize(ct, true);
72863294
DE
319 if (!ct->startl(ct, 0, NULL)) {
320 TSTERR("starting container %s", name);
321 goto out2;
322 }
323 return ct;
324
325out2:
326 test_ct_destroy(ct);
327 ct = NULL;
328out1:
329 return ct;
330}
331
332
333int test_attach(const char *lxcpath, const char *name, const char *template)
334{
335 int ret = -1;
336 struct lxc_container *ct;
337
338 printf("Testing attach with on lxcpath:%s\n", lxcpath ? lxcpath : "<default>");
339 ct = test_ct_create(lxcpath, NULL, name, template);
340 if (!ct)
341 goto err1;
342
343 ret = test_attach_cmd(ct);
344 if (ret < 0) {
345 TSTERR("attach cmd test failed");
346 goto err2;
347 }
348
349 ret = test_attach_func(ct);
350 if (ret < 0) {
351 TSTERR("attach func test failed");
352 goto err2;
353 }
354
355 if (lsm_enabled()) {
356 ret = test_attach_lsm_cmd(ct);
357 if (ret < 0) {
358 TSTERR("attach lsm cmd test failed");
359 goto err2;
360 }
361
362 ret = test_attach_lsm_func(ct);
363 if (ret < 0) {
364 TSTERR("attach lsm func test failed");
365 goto err2;
366 }
367 }
368 ret = 0;
369
370err2:
371 test_ct_destroy(ct);
372err1:
373 return ret;
374}
375
376int main(int argc, char *argv[])
377{
378 int ret;
379
380 test_lsm_detect();
381 ret = test_attach(NULL, TSTNAME, "busybox");
382 if (ret < 0)
383 return EXIT_FAILURE;
384
385 printf("\n");
386 ret = test_attach(LXCPATH "/alternate-path-test", TSTNAME, "busybox");
387 if (ret < 0)
388 return EXIT_FAILURE;
389
390 printf("All tests passed\n");
391 return EXIT_SUCCESS;
392}