[lxc-devel] [PATCH v2 2/2] support setting lsm label at exec or immediately

Dwight Engen dwight.engen at oracle.com
Thu Oct 17 17:02:49 UTC 2013


- 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 <dwight.engen at oracle.com>
---
v2: detect which lsm to test at runtime vs. compile time

 .gitignore                     |   1 +
 src/lxc/attach.c               |  20 ++-
 src/lxc/attach_options.h       |   5 +-
 src/lxc/lsm/apparmor.c         |  25 +--
 src/lxc/lsm/lsm.c              |   4 +-
 src/lxc/lsm/lsm.h              |   7 +-
 src/lxc/lsm/nop.c              |   3 +-
 src/lxc/lsm/selinux.c          |  22 ++-
 src/lxc/lxc_attach.c           |   2 +-
 src/lxc/start.c                |   8 +-
 src/python-lxc/lxc.c           |   3 +-
 src/python-lxc/lxc/__init__.py |   3 +-
 src/tests/Makefile.am          |  11 +-
 src/tests/attach.c             | 392 +++++++++++++++++++++++++++++++++++++++++
 14 files changed, 463 insertions(+), 43 deletions(-)
 create mode 100644 src/tests/attach.c

diff --git a/.gitignore b/.gitignore
index df8d5e1..b1223cd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,6 +77,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 37cefb0..aea0c33 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 5291e4f..c8c4d0a 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 146564f..cf8020d 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 508d640..9273101 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 5a6cf15..4128575 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 NULL; }
 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 e39b0f5..e5db124 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 ef5beb0..b1b0253 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 bd4e674..142d605 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 7538403..2bf417e 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 b6e0804..e42ed35 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 6a29903..8ae7852 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 509e414..cae82bf 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 0000000..54650bd
--- /dev/null
+++ b/src/tests/attach.c
@@ -0,0 +1,392 @@
+/* liblxcapi
+ *
+ * Copyright © 2013 Oracle.
+ *
+ * Authors:
+ * Dwight Engen <dwight.engen at oracle.com>
+ *
+ * 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 <lxc/lxccontainer.h>
+#include <lxc/utils.h>
+#include <lxc/lsm/lsm.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#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 : "<default>");
+	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;
+}
-- 
1.8.3.1





More information about the lxc-devel mailing list