From: Dwight Engen Date: Thu, 17 Oct 2013 17:02:49 +0000 (-0400) Subject: support setting lsm label at exec or immediately X-Git-Tag: lxc-1.0.0.alpha2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=72863294f63e27ac263a774aab37aace20dc1bc5;p=thirdparty%2Flxc.git support setting lsm label at exec or immediately - Add attach test cases - Moved setting of LSM label later to avoid failure of IPC between parent and child during attach Signed-off-by: Dwight Engen Signed-off-by: Serge Hallyn --- diff --git a/.gitignore b/.gitignore index ab0105af6..8901fc7b3 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ src/lxc/lxc-user-nic src/python-lxc/build/ src/python-lxc/lxc/__pycache__/ +src/tests/lxc-test-attach src/tests/lxc-test-cgpath src/tests/lxc-test-clonetest src/tests/lxc-test-concurrent diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 37cefb020..aea0c337d 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -918,15 +918,6 @@ int attach_child_main(void* data) rexit(-1); } - /* load apparmor profile */ - if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_APPARMOR)) { - ret = lsm_process_label_set(init_ctx->lsm_label, 0); - if (ret < 0) { - shutdown(ipc_socket, SHUT_RDWR); - rexit(-1); - } - } - /* A description of the purpose of this functionality is * provided in the lxc-attach(1) manual page. We have to * remount here and not in the parent process, otherwise @@ -1023,6 +1014,17 @@ int attach_child_main(void* data) shutdown(ipc_socket, SHUT_RDWR); close(ipc_socket); + + /* set new apparmor profile/selinux context */ + if ((options->namespaces & CLONE_NEWNS) && (options->attach_flags & LXC_ATTACH_LSM)) { + int on_exec; + + on_exec = options->attach_flags & LXC_ATTACH_LSM_EXEC ? 1 : 0; + ret = lsm_process_label_set(init_ctx->lsm_label, 0, on_exec); + if (ret < 0) { + rexit(-1); + } + } lxc_proc_put_context_info(init_ctx); /* The following is done after the communication socket is diff --git a/src/lxc/attach_options.h b/src/lxc/attach_options.h index 5291e4f55..c8c4d0a1a 100644 --- a/src/lxc/attach_options.h +++ b/src/lxc/attach_options.h @@ -36,10 +36,11 @@ enum { LXC_ATTACH_MOVE_TO_CGROUP = 0x00000001, LXC_ATTACH_DROP_CAPABILITIES = 0x00000002, LXC_ATTACH_SET_PERSONALITY = 0x00000004, - LXC_ATTACH_APPARMOR = 0x00000008, + LXC_ATTACH_LSM_EXEC = 0x00000008, /* the following are off by default */ LXC_ATTACH_REMOUNT_PROC_SYS = 0x00010000, + LXC_ATTACH_LSM_NOW = 0x00020000, /* we have 16 bits for things that are on by default * and 16 bits that are off by default, that should @@ -49,6 +50,8 @@ enum { LXC_ATTACH_DEFAULT = 0x0000FFFF }; +#define LXC_ATTACH_LSM (LXC_ATTACH_LSM_EXEC | LXC_ATTACH_LSM_NOW) + typedef struct lxc_attach_options_t lxc_attach_options_t; typedef int (*lxc_attach_exec_t)(void* payload); diff --git a/src/lxc/lsm/apparmor.c b/src/lxc/lsm/apparmor.c index 146564fde..cf8020d1f 100644 --- a/src/lxc/lsm/apparmor.c +++ b/src/lxc/lsm/apparmor.c @@ -130,13 +130,14 @@ static int apparmor_am_unconfined(void) * * @label : the profile to set * @default : use the default profile if label is NULL + * @on_exec : the new profile will take effect on exec(2) not immediately * * Returns 0 on success, < 0 on failure * - * Notes: This relies on /proc being available. The new context - * will take effect immediately. + * Notes: This relies on /proc being available. */ -static int apparmor_process_label_set(const char *label, int use_default) +static int apparmor_process_label_set(const char *label, int use_default, + int on_exec) { if (!apparmor_enabled()) return 0; @@ -153,15 +154,19 @@ static int apparmor_process_label_set(const char *label, int use_default) return 0; } - /* XXX: instant instead of aa_change_onexec(), may be used by attach - * when using a function that doesn't exec - */ - if (aa_change_profile(label) < 0) { - SYSERROR("failed to change apparmor profile to %s", label); - return -1; + if (on_exec) { + if (aa_change_onexec(label) < 0) { + SYSERROR("failed to change exec apparmor profile to %s", label); + return -1; + } + } else { + if (aa_change_profile(label) < 0) { + SYSERROR("failed to change apparmor profile to %s", label); + return -1; + } } - INFO("changed apparmor profile to %s", label); + INFO("changed apparmor%s profile to %s", on_exec ? " exec" : "", label); return 0; } diff --git a/src/lxc/lsm/lsm.c b/src/lxc/lsm/lsm.c index 066102bb5..a41ab8806 100644 --- a/src/lxc/lsm/lsm.c +++ b/src/lxc/lsm/lsm.c @@ -85,13 +85,13 @@ char *lsm_process_label_get(pid_t pid) return drv->process_label_get(pid); } -int lsm_process_label_set(const char *label, int use_default) +int lsm_process_label_set(const char *label, int use_default, int on_exec) { if (!drv) { ERROR("LSM driver not inited"); return -1; } - return drv->process_label_set(label, use_default); + return drv->process_label_set(label, use_default, on_exec); } /* diff --git a/src/lxc/lsm/lsm.h b/src/lxc/lsm/lsm.h index 621e1af0a..6916800c6 100644 --- a/src/lxc/lsm/lsm.h +++ b/src/lxc/lsm/lsm.h @@ -33,7 +33,8 @@ struct lsm_drv { int (*enabled)(void); char *(*process_label_get)(pid_t pid); - int (*process_label_set)(const char *label, int use_default); + int (*process_label_set)(const char *label, int use_default, + int on_exec); }; #if HAVE_APPARMOR || HAVE_SELINUX @@ -41,7 +42,7 @@ void lsm_init(void); int lsm_enabled(void); const char *lsm_name(void); char *lsm_process_label_get(pid_t pid); -int lsm_process_label_set(const char *label, int use_default); +int lsm_process_label_set(const char *label, int use_default, int on_exec); int lsm_proc_mount(struct lxc_conf *lxc_conf); void lsm_proc_unmount(struct lxc_conf *lxc_conf); #else @@ -49,7 +50,7 @@ static inline void lsm_init(void) { } static inline int lsm_enabled(void) { return 0; } static inline const char *lsm_name(void) { return "none"; } static inline char *lsm_process_label_get(pid_t pid) { return NULL; } -static inline int lsm_process_label_set(char *label, int use_default) { return 0; } +static inline int lsm_process_label_set(char *label, int use_default, int on_exec) { return 0; } static inline int lsm_proc_mount(struct lxc_conf *lxc_conf) { return 0; } static inline void lsm_proc_unmount(struct lxc_conf *lxc_conf) { } #endif diff --git a/src/lxc/lsm/nop.c b/src/lxc/lsm/nop.c index e39b0f514..e5db1241a 100644 --- a/src/lxc/lsm/nop.c +++ b/src/lxc/lsm/nop.c @@ -29,7 +29,8 @@ static char *nop_process_label_get(pid_t pid) return NULL; } -static int nop_process_label_set(const char *label, int use_default) +static int nop_process_label_set(const char *label, int use_default, + int on_exec) { return 0; } diff --git a/src/lxc/lsm/selinux.c b/src/lxc/lsm/selinux.c index ef5beb0b3..b1b02530a 100644 --- a/src/lxc/lsm/selinux.c +++ b/src/lxc/lsm/selinux.c @@ -61,13 +61,14 @@ static char *selinux_process_label_get(pid_t pid) * * @label : the context to set * @default : use the default context if label is NULL + * @on_exec : the new context will take effect on exec(2) not immediately * * Returns 0 on success, < 0 on failure * - * Notes: This relies on /proc being available. The new context - * will take effect on the next exec(2). + * Notes: This relies on /proc being available. */ -static int selinux_process_label_set(const char *label, int use_default) +static int selinux_process_label_set(const char *label, int use_default, + int on_exec) { if (!label) { if (use_default) @@ -78,12 +79,19 @@ static int selinux_process_label_set(const char *label, int use_default) if (!strcmp(label, "unconfined_t")) return 0; - if (setexeccon_raw((char *)label) < 0) { - SYSERROR("failed to set new SELinux context %s", label); - return -1; + if (on_exec) { + if (setexeccon_raw((char *)label) < 0) { + SYSERROR("failed to set new SELinux exec context %s", label); + return -1; + } + } else { + if (setcon_raw((char *)label) < 0) { + SYSERROR("failed to set new SELinux context %s", label); + return -1; + } } - INFO("changed SELinux context to %s", label); + INFO("changed SELinux%s context to %s", on_exec ? " exec" : "", label); return 0; } diff --git a/src/lxc/lxc_attach.c b/src/lxc/lxc_attach.c index 7d912b25f..b49771b03 100644 --- a/src/lxc/lxc_attach.c +++ b/src/lxc/lxc_attach.c @@ -199,7 +199,7 @@ int main(int argc, char *argv[]) if (remount_sys_proc) attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS; if (elevated_privileges) - attach_options.attach_flags &= ~(LXC_ATTACH_MOVE_TO_CGROUP | LXC_ATTACH_DROP_CAPABILITIES | LXC_ATTACH_APPARMOR); + attach_options.attach_flags &= ~(LXC_ATTACH_MOVE_TO_CGROUP | LXC_ATTACH_DROP_CAPABILITIES | LXC_ATTACH_LSM_EXEC); attach_options.namespaces = namespace_flags; attach_options.personality = new_personality; attach_options.env_policy = env_policy; diff --git a/src/lxc/start.c b/src/lxc/start.c index 753840358..2bf417eaa 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -556,14 +556,10 @@ static int do_start(void *data) if (lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP)) return -1; - /* XXX: hmm apparmor switches right away since it uses - * aa_change_profile() and not aa_change_onexec(). SELinux on the other - * hand is going to transition on exec(). Is it bad to run the stuff - * between here and exec() in the more privileged context? - */ + /* Set the label to change to when we exec(2) the container's init */ if (lsm_process_label_set(handler->conf->lsm_aa_profile ? handler->conf->lsm_aa_profile : - handler->conf->lsm_se_context, 1) < 0) + handler->conf->lsm_se_context, 1, 1) < 0) goto out_warn_father; lsm_proc_unmount(handler->conf); diff --git a/src/python-lxc/lxc.c b/src/python-lxc/lxc.c index b6e08047a..e42ed350b 100644 --- a/src/python-lxc/lxc.c +++ b/src/python-lxc/lxc.c @@ -1268,7 +1268,8 @@ PyInit__lxc(void) PYLXC_EXPORT_CONST(LXC_ATTACH_MOVE_TO_CGROUP); PYLXC_EXPORT_CONST(LXC_ATTACH_DROP_CAPABILITIES); PYLXC_EXPORT_CONST(LXC_ATTACH_SET_PERSONALITY); - PYLXC_EXPORT_CONST(LXC_ATTACH_APPARMOR); + PYLXC_EXPORT_CONST(LXC_ATTACH_LSM_NOW); + PYLXC_EXPORT_CONST(LXC_ATTACH_LSM_EXEC); PYLXC_EXPORT_CONST(LXC_ATTACH_REMOUNT_PROC_SYS); PYLXC_EXPORT_CONST(LXC_ATTACH_DEFAULT); diff --git a/src/python-lxc/lxc/__init__.py b/src/python-lxc/lxc/__init__.py index 6a29903d1..8ae785247 100644 --- a/src/python-lxc/lxc/__init__.py +++ b/src/python-lxc/lxc/__init__.py @@ -472,7 +472,8 @@ LXC_ATTACH_CLEAR_ENV = _lxc.LXC_ATTACH_CLEAR_ENV LXC_ATTACH_MOVE_TO_CGROUP = _lxc.LXC_ATTACH_MOVE_TO_CGROUP LXC_ATTACH_DROP_CAPABILITIES = _lxc.LXC_ATTACH_DROP_CAPABILITIES LXC_ATTACH_SET_PERSONALITY = _lxc.LXC_ATTACH_SET_PERSONALITY -LXC_ATTACH_APPARMOR = _lxc.LXC_ATTACH_APPARMOR +LXC_ATTACH_LSM_NOW = _lxc.LXC_ATTACH_LSM_NOW +LXC_ATTACH_LSM_EXEC = _lxc.LXC_ATTACH_LSM_EXEC LXC_ATTACH_REMOUNT_PROC_SYS = _lxc.LXC_ATTACH_REMOUNT_PROC_SYS LXC_ATTACH_DEFAULT = _lxc.LXC_ATTACH_DEFAULT CLONE_NEWUTS = _lxc.CLONE_NEWUTS diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index 509e41405..cae82bf41 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -22,6 +22,7 @@ lxc_test_concurrent_SOURCES = concurrent.c lxc_test_may_control_SOURCES = may_control.c lxc_test_reboot_SOURCES = reboot.c lxc_test_list_SOURCES = list.c +lxc_test_attach_SOURCES = attach.c AM_CFLAGS=-I$(top_srcdir)/src \ -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ @@ -30,12 +31,20 @@ AM_CFLAGS=-I$(top_srcdir)/src \ -DLXCINITDIR=\"$(LXCINITDIR)\" \ -DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" +if ENABLE_APPARMOR +AM_CFLAGS += -DHAVE_APPARMOR +endif + +if ENABLE_SELINUX +AM_CFLAGS += -DHAVE_SELINUX +endif + bin_PROGRAMS = lxc-test-containertests lxc-test-locktests lxc-test-startone \ lxc-test-destroytest lxc-test-saveconfig lxc-test-createtest \ lxc-test-shutdowntest lxc-test-get_item lxc-test-getkeys lxc-test-lxcpath \ lxc-test-cgpath lxc-test-clonetest lxc-test-console lxc-usernic-test \ lxc-test-snapshot lxc-test-concurrent lxc-test-may-control \ - lxc-test-reboot lxc-test-list + lxc-test-reboot lxc-test-list lxc-test-attach bin_SCRIPTS = lxc-test-usernic diff --git a/src/tests/attach.c b/src/tests/attach.c new file mode 100644 index 000000000..54650bde7 --- /dev/null +++ b/src/tests/attach.c @@ -0,0 +1,392 @@ +/* liblxcapi + * + * Copyright © 2013 Oracle. + * + * Authors: + * Dwight Engen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include + +#include +#include + +#define TSTNAME "lxc-attach-test" +#define TSTERR(fmt, ...) do { \ + fprintf(stderr, "%s:%d " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__); \ +} while (0) + +#if HAVE_APPARMOR || HAVE_SELINUX +static const char *lsm_config_key = NULL; +static const char *lsm_label = NULL; + +static void test_lsm_detect(void) +{ + if (lsm_enabled()) { + if (!strcmp(lsm_name(), "SELinux")) { + lsm_config_key = "lxc.se_context"; + lsm_label = "unconfined_u:unconfined_r:lxc_t:s0-s0:c0.c1023"; + } + else if (!strcmp(lsm_name(), "AppArmor")) { + lsm_config_key = "lxc.aa_profile"; + lsm_label = "lxc-container-default"; + } + else { + TSTERR("unknown lsm %s enabled, add test code here", lsm_name()); + exit(EXIT_FAILURE); + } + } +} + +static void test_attach_lsm_set_config(struct lxc_container *ct) +{ + ct->load_config(ct, NULL); + ct->set_config_item(ct, lsm_config_key, lsm_label); + ct->save_config(ct, NULL); +} + +static int test_attach_lsm_func_func(void* payload) +{ + printf("%s", lsm_process_label_get(getpid())); + return 0; +} + +static int test_attach_lsm_func(struct lxc_container *ct) +{ + int ret; + pid_t pid; + int pipefd[2]; + char result[1024]; + lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; + + printf("Testing attach lsm label with func...\n"); + + ret = pipe(pipefd); + if (ret < 0) { + TSTERR("pipe failed %d", ret); + return ret; + } + attach_options.stdout_fd = pipefd[1]; + attach_options.attach_flags &= ~(LXC_ATTACH_LSM_EXEC|LXC_ATTACH_DROP_CAPABILITIES); + attach_options.attach_flags |= LXC_ATTACH_LSM_NOW; + ret = ct->attach(ct, test_attach_lsm_func_func, NULL, &attach_options, &pid); + if (ret < 0) { + TSTERR("attach failed"); + goto err1; + } + + ret = read(pipefd[0], result, sizeof(result)-1); + if (ret < 0) { + TSTERR("read failed %d", ret); + goto err2; + } + + result[ret] = '\0'; + if (strcmp(lsm_label, result)) { + TSTERR("LSM label mismatch expected:%s got:%s", lsm_label, result); + ret = -1; + goto err2; + } + ret = 0; + +err2: + wait_for_pid(pid); +err1: + close(pipefd[0]); + close(pipefd[1]); + return ret; +} + +static int test_attach_lsm_cmd(struct lxc_container *ct) +{ + int ret; + pid_t pid; + int pipefd[2]; + char result[1024]; + char *space; + char *argv[] = {"cat", "/proc/self/attr/current", NULL}; + lxc_attach_command_t command = {"cat", argv}; + lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; + + printf("Testing attach lsm label with cmd...\n"); + + ret = pipe(pipefd); + if (ret < 0) { + TSTERR("pipe failed %d", ret); + return ret; + } + attach_options.stdout_fd = pipefd[1]; + + ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, &pid); + if (ret < 0) { + TSTERR("attach failed"); + goto err1; + } + + ret = read(pipefd[0], result, sizeof(result)-1); + if (ret < 0) { + TSTERR("read failed %d", ret); + goto err2; + } + result[ret] = '\0'; + space = index(result, '\n'); + if (space) + *space = '\0'; + space = index(result, ' '); + if (space) + *space = '\0'; + + ret = -1; + if (strcmp(lsm_label, result)) { + TSTERR("LSM label mismatch expected:%s got:%s", lsm_label, result); + goto err2; + } + ret = 0; + +err2: + wait_for_pid(pid); +err1: + close(pipefd[0]); + close(pipefd[1]); + return ret; +} +#else +static void test_attach_lsm_set_config(struct lxc_container *ct) {} +static int test_attach_lsm_func(struct lxc_container *ct) { return 0; } +static int test_attach_lsm_cmd(struct lxc_container *ct) { return 0; } +#endif /* HAVE_APPARMOR || HAVE_SELINUX */ + +static int test_attach_func_func(void* payload) +{ + printf("%d", getpid()); + return 0; +} + +static int test_attach_func(struct lxc_container *ct) +{ + int ret; + pid_t pid,nspid; + int pipefd[2]; + char result[1024]; + lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; + + printf("Testing attach with func...\n"); + + /* XXX: We can't just use &nspid and have test_attach_func_func fill + * it in because the function doesn't run in our process context but + * in a fork()ed from us context. We read the result through a pipe. + */ + ret = pipe(pipefd); + if (ret < 0) { + TSTERR("pipe failed %d", ret); + return ret; + } + attach_options.stdout_fd = pipefd[1]; + + ret = ct->attach(ct, test_attach_func_func, NULL, &attach_options, &pid); + if (ret < 0) { + TSTERR("attach failed"); + goto err1; + } + + ret = read(pipefd[0], result, sizeof(result)-1); + if (ret < 0) { + TSTERR("read failed %d", ret); + goto err2; + } + result[ret] = '\0'; + + /* There is a small chance the pid is reused inside the NS, so we + * just print it and don't actually do this check + * + * if (pid == nspid) TSTERR(...) + */ + nspid = atoi(result); + printf("Pid:%d in NS:%d\n", pid, nspid); + ret = 0; + +err2: + wait_for_pid(pid); +err1: + close(pipefd[0]); + close(pipefd[1]); + return ret; +} + +static int test_attach_cmd(struct lxc_container *ct) +{ + int ret; + pid_t pid; + char *argv[] = {"cmp", "-s", "/sbin/init", "/bin/busybox", NULL}; + lxc_attach_command_t command = {"cmp", argv}; + lxc_attach_options_t attach_options = LXC_ATTACH_OPTIONS_DEFAULT; + + printf("Testing attach with success command...\n"); + ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, &pid); + if (ret < 0) { + TSTERR("attach failed"); + return ret; + } + + ret = wait_for_pid(pid); + if (ret < 0) { + TSTERR("attach success command got bad return %d", ret); + return ret; + } + + printf("Testing attach with failure command...\n"); + argv[2] = "/etc/fstab"; + ret = ct->attach(ct, lxc_attach_run_command, &command, &attach_options, &pid); + if (ret < 0) { + TSTERR("attach failed"); + return ret; + } + + ret = wait_for_pid(pid); + if (ret == 0) { + TSTERR("attach failure command got bad return %d", ret); + return -1; + } + return 0; +} + +/* test_ct_destroy: stop and destroy the test container + * + * @ct : the container + */ +static void test_ct_destroy(struct lxc_container *ct) +{ + ct->stop(ct); + ct->destroy(ct); + lxc_container_put(ct); +} + +/* test_ct_create: create and start test container + * + * @lxcpath : the lxcpath in which to create the container + * @group : name of the container group or NULL for default "lxc" + * @name : name of the container + * @template : template to use when creating the container + */ +static struct lxc_container *test_ct_create(const char *lxcpath, + const char *group, const char *name, + const char *template) +{ + int ret; + struct lxc_container *ct = NULL; + + if (lxcpath) { + ret = mkdir(lxcpath, 0755); + if (ret < 0 && errno != EEXIST) { + TSTERR("failed to mkdir %s %s", lxcpath, strerror(errno)); + goto out1; + } + } + + if ((ct = lxc_container_new(name, lxcpath)) == NULL) { + TSTERR("instantiating container %s", name); + goto out1; + } + if (ct->is_defined(ct)) { + ct->stop(ct); + ct->destroy(ct); + ct = lxc_container_new(name, lxcpath); + } + if (!ct->createl(ct, template, NULL, NULL, 0, NULL)) { + TSTERR("creating container %s", name); + goto out2; + } + + if (lsm_enabled()) + test_attach_lsm_set_config(ct); + + ct->want_daemonize(ct); + if (!ct->startl(ct, 0, NULL)) { + TSTERR("starting container %s", name); + goto out2; + } + return ct; + +out2: + test_ct_destroy(ct); + ct = NULL; +out1: + return ct; +} + + +int test_attach(const char *lxcpath, const char *name, const char *template) +{ + int ret = -1; + struct lxc_container *ct; + + printf("Testing attach with on lxcpath:%s\n", lxcpath ? lxcpath : ""); + ct = test_ct_create(lxcpath, NULL, name, template); + if (!ct) + goto err1; + + ret = test_attach_cmd(ct); + if (ret < 0) { + TSTERR("attach cmd test failed"); + goto err2; + } + + ret = test_attach_func(ct); + if (ret < 0) { + TSTERR("attach func test failed"); + goto err2; + } + + if (lsm_enabled()) { + ret = test_attach_lsm_cmd(ct); + if (ret < 0) { + TSTERR("attach lsm cmd test failed"); + goto err2; + } + + ret = test_attach_lsm_func(ct); + if (ret < 0) { + TSTERR("attach lsm func test failed"); + goto err2; + } + } + ret = 0; + +err2: + test_ct_destroy(ct); +err1: + return ret; +} + +int main(int argc, char *argv[]) +{ + int ret; + + test_lsm_detect(); + ret = test_attach(NULL, TSTNAME, "busybox"); + if (ret < 0) + return EXIT_FAILURE; + + printf("\n"); + ret = test_attach(LXCPATH "/alternate-path-test", TSTNAME, "busybox"); + if (ret < 0) + return EXIT_FAILURE; + + printf("All tests passed\n"); + return EXIT_SUCCESS; +}