]>
Commit | Line | Data |
---|---|---|
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 |
34 | static const char *lsm_config_key = NULL; |
35 | static const char *lsm_label = NULL; | |
36 | ||
37 | static 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 |
56 | static 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 | ||
63 | static int test_attach_lsm_func_func(void* payload) | |
64 | { | |
65 | printf("%s", lsm_process_label_get(getpid())); | |
66 | return 0; | |
67 | } | |
68 | ||
69 | static 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 | ||
107 | err2: | |
108 | wait_for_pid(pid); | |
109 | err1: | |
110 | close(pipefd[0]); | |
111 | close(pipefd[1]); | |
112 | return ret; | |
113 | } | |
114 | ||
115 | static 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 | ||
161 | err2: | |
162 | wait_for_pid(pid); | |
163 | err1: | |
164 | close(pipefd[0]); | |
165 | close(pipefd[1]); | |
166 | return ret; | |
167 | } | |
168 | #else | |
169 | static void test_attach_lsm_set_config(struct lxc_container *ct) {} | |
170 | static int test_attach_lsm_func(struct lxc_container *ct) { return 0; } | |
171 | static int test_attach_lsm_cmd(struct lxc_container *ct) { return 0; } | |
172 | #endif /* HAVE_APPARMOR || HAVE_SELINUX */ | |
173 | ||
174 | static int test_attach_func_func(void* payload) | |
175 | { | |
176 | printf("%d", getpid()); | |
177 | return 0; | |
178 | } | |
179 | ||
180 | static 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 | ||
223 | err2: | |
224 | wait_for_pid(pid); | |
225 | err1: | |
226 | close(pipefd[0]); | |
227 | close(pipefd[1]); | |
228 | return ret; | |
229 | } | |
230 | ||
231 | static 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 | */ | |
272 | static 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 | */ | |
286 | static 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 | ||
325 | out2: | |
326 | test_ct_destroy(ct); | |
327 | ct = NULL; | |
328 | out1: | |
329 | return ct; | |
330 | } | |
331 | ||
332 | ||
333 | int 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 | ||
370 | err2: | |
371 | test_ct_destroy(ct); | |
372 | err1: | |
373 | return ret; | |
374 | } | |
375 | ||
376 | int 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 | } |