Commit 72863294 by Dwight Engen Committed by Serge Hallyn

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: 's avatarDwight Engen <dwight.engen@oracle.com> Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com>
parent 41ca8908
...@@ -76,6 +76,7 @@ src/lxc/lxc-user-nic ...@@ -76,6 +76,7 @@ src/lxc/lxc-user-nic
src/python-lxc/build/ src/python-lxc/build/
src/python-lxc/lxc/__pycache__/ src/python-lxc/lxc/__pycache__/
src/tests/lxc-test-attach
src/tests/lxc-test-cgpath src/tests/lxc-test-cgpath
src/tests/lxc-test-clonetest src/tests/lxc-test-clonetest
src/tests/lxc-test-concurrent src/tests/lxc-test-concurrent
......
...@@ -918,15 +918,6 @@ int attach_child_main(void* data) ...@@ -918,15 +918,6 @@ int attach_child_main(void* data)
rexit(-1); 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 /* A description of the purpose of this functionality is
* provided in the lxc-attach(1) manual page. We have to * provided in the lxc-attach(1) manual page. We have to
* remount here and not in the parent process, otherwise * remount here and not in the parent process, otherwise
...@@ -1023,6 +1014,17 @@ int attach_child_main(void* data) ...@@ -1023,6 +1014,17 @@ int attach_child_main(void* data)
shutdown(ipc_socket, SHUT_RDWR); shutdown(ipc_socket, SHUT_RDWR);
close(ipc_socket); 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); lxc_proc_put_context_info(init_ctx);
/* The following is done after the communication socket is /* The following is done after the communication socket is
......
...@@ -36,10 +36,11 @@ enum { ...@@ -36,10 +36,11 @@ enum {
LXC_ATTACH_MOVE_TO_CGROUP = 0x00000001, LXC_ATTACH_MOVE_TO_CGROUP = 0x00000001,
LXC_ATTACH_DROP_CAPABILITIES = 0x00000002, LXC_ATTACH_DROP_CAPABILITIES = 0x00000002,
LXC_ATTACH_SET_PERSONALITY = 0x00000004, LXC_ATTACH_SET_PERSONALITY = 0x00000004,
LXC_ATTACH_APPARMOR = 0x00000008, LXC_ATTACH_LSM_EXEC = 0x00000008,
/* the following are off by default */ /* the following are off by default */
LXC_ATTACH_REMOUNT_PROC_SYS = 0x00010000, LXC_ATTACH_REMOUNT_PROC_SYS = 0x00010000,
LXC_ATTACH_LSM_NOW = 0x00020000,
/* we have 16 bits for things that are on by default /* we have 16 bits for things that are on by default
* and 16 bits that are off by default, that should * and 16 bits that are off by default, that should
...@@ -49,6 +50,8 @@ enum { ...@@ -49,6 +50,8 @@ enum {
LXC_ATTACH_DEFAULT = 0x0000FFFF 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 struct lxc_attach_options_t lxc_attach_options_t;
typedef int (*lxc_attach_exec_t)(void* payload); typedef int (*lxc_attach_exec_t)(void* payload);
......
...@@ -130,13 +130,14 @@ static int apparmor_am_unconfined(void) ...@@ -130,13 +130,14 @@ static int apparmor_am_unconfined(void)
* *
* @label : the profile to set * @label : the profile to set
* @default : use the default profile if label is NULL * @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 * Returns 0 on success, < 0 on failure
* *
* Notes: This relies on /proc being available. The new context * Notes: This relies on /proc being available.
* will take effect immediately.
*/ */
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()) if (!apparmor_enabled())
return 0; return 0;
...@@ -153,15 +154,19 @@ static int apparmor_process_label_set(const char *label, int use_default) ...@@ -153,15 +154,19 @@ static int apparmor_process_label_set(const char *label, int use_default)
return 0; return 0;
} }
/* XXX: instant instead of aa_change_onexec(), may be used by attach if (on_exec) {
* when using a function that doesn't exec if (aa_change_onexec(label) < 0) {
*/ SYSERROR("failed to change exec apparmor profile to %s", label);
if (aa_change_profile(label) < 0) { return -1;
SYSERROR("failed to change 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; return 0;
} }
......
...@@ -85,13 +85,13 @@ char *lsm_process_label_get(pid_t pid) ...@@ -85,13 +85,13 @@ char *lsm_process_label_get(pid_t pid)
return drv->process_label_get(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) { if (!drv) {
ERROR("LSM driver not inited"); ERROR("LSM driver not inited");
return -1; return -1;
} }
return drv->process_label_set(label, use_default); return drv->process_label_set(label, use_default, on_exec);
} }
/* /*
......
...@@ -33,7 +33,8 @@ struct lsm_drv { ...@@ -33,7 +33,8 @@ struct lsm_drv {
int (*enabled)(void); int (*enabled)(void);
char *(*process_label_get)(pid_t pid); 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 #if HAVE_APPARMOR || HAVE_SELINUX
...@@ -41,7 +42,7 @@ void lsm_init(void); ...@@ -41,7 +42,7 @@ void lsm_init(void);
int lsm_enabled(void); int lsm_enabled(void);
const char *lsm_name(void); const char *lsm_name(void);
char *lsm_process_label_get(pid_t pid); 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); int lsm_proc_mount(struct lxc_conf *lxc_conf);
void lsm_proc_unmount(struct lxc_conf *lxc_conf); void lsm_proc_unmount(struct lxc_conf *lxc_conf);
#else #else
...@@ -49,7 +50,7 @@ static inline void lsm_init(void) { } ...@@ -49,7 +50,7 @@ static inline void lsm_init(void) { }
static inline int lsm_enabled(void) { return 0; } static inline int lsm_enabled(void) { return 0; }
static inline const char *lsm_name(void) { return "none"; } static inline const char *lsm_name(void) { return "none"; }
static inline char *lsm_process_label_get(pid_t pid) { 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 int lsm_proc_mount(struct lxc_conf *lxc_conf) { return 0; }
static inline void lsm_proc_unmount(struct lxc_conf *lxc_conf) { } static inline void lsm_proc_unmount(struct lxc_conf *lxc_conf) { }
#endif #endif
......
...@@ -29,7 +29,8 @@ static char *nop_process_label_get(pid_t pid) ...@@ -29,7 +29,8 @@ static char *nop_process_label_get(pid_t pid)
return NULL; 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; return 0;
} }
......
...@@ -61,13 +61,14 @@ static char *selinux_process_label_get(pid_t pid) ...@@ -61,13 +61,14 @@ static char *selinux_process_label_get(pid_t pid)
* *
* @label : the context to set * @label : the context to set
* @default : use the default context if label is NULL * @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 * Returns 0 on success, < 0 on failure
* *
* Notes: This relies on /proc being available. The new context * Notes: This relies on /proc being available.
* will take effect on the next exec(2).
*/ */
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 (!label) {
if (use_default) if (use_default)
...@@ -78,12 +79,19 @@ static int selinux_process_label_set(const char *label, int use_default) ...@@ -78,12 +79,19 @@ static int selinux_process_label_set(const char *label, int use_default)
if (!strcmp(label, "unconfined_t")) if (!strcmp(label, "unconfined_t"))
return 0; return 0;
if (setexeccon_raw((char *)label) < 0) { if (on_exec) {
SYSERROR("failed to set new SELinux context %s", label); if (setexeccon_raw((char *)label) < 0) {
return -1; 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; return 0;
} }
......
...@@ -199,7 +199,7 @@ int main(int argc, char *argv[]) ...@@ -199,7 +199,7 @@ int main(int argc, char *argv[])
if (remount_sys_proc) if (remount_sys_proc)
attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS; attach_options.attach_flags |= LXC_ATTACH_REMOUNT_PROC_SYS;
if (elevated_privileges) 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.namespaces = namespace_flags;
attach_options.personality = new_personality; attach_options.personality = new_personality;
attach_options.env_policy = env_policy; attach_options.env_policy = env_policy;
......
...@@ -556,14 +556,10 @@ static int do_start(void *data) ...@@ -556,14 +556,10 @@ static int do_start(void *data)
if (lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP)) if (lxc_sync_barrier_parent(handler, LXC_SYNC_CGROUP))
return -1; return -1;
/* XXX: hmm apparmor switches right away since it uses /* Set the label to change to when we exec(2) the container's init */
* 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?
*/
if (lsm_process_label_set(handler->conf->lsm_aa_profile ? if (lsm_process_label_set(handler->conf->lsm_aa_profile ?
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; goto out_warn_father;
lsm_proc_unmount(handler->conf); lsm_proc_unmount(handler->conf);
......
...@@ -1268,7 +1268,8 @@ PyInit__lxc(void) ...@@ -1268,7 +1268,8 @@ PyInit__lxc(void)
PYLXC_EXPORT_CONST(LXC_ATTACH_MOVE_TO_CGROUP); PYLXC_EXPORT_CONST(LXC_ATTACH_MOVE_TO_CGROUP);
PYLXC_EXPORT_CONST(LXC_ATTACH_DROP_CAPABILITIES); PYLXC_EXPORT_CONST(LXC_ATTACH_DROP_CAPABILITIES);
PYLXC_EXPORT_CONST(LXC_ATTACH_SET_PERSONALITY); 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_REMOUNT_PROC_SYS);
PYLXC_EXPORT_CONST(LXC_ATTACH_DEFAULT); PYLXC_EXPORT_CONST(LXC_ATTACH_DEFAULT);
......
...@@ -472,7 +472,8 @@ LXC_ATTACH_CLEAR_ENV = _lxc.LXC_ATTACH_CLEAR_ENV ...@@ -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_MOVE_TO_CGROUP = _lxc.LXC_ATTACH_MOVE_TO_CGROUP
LXC_ATTACH_DROP_CAPABILITIES = _lxc.LXC_ATTACH_DROP_CAPABILITIES LXC_ATTACH_DROP_CAPABILITIES = _lxc.LXC_ATTACH_DROP_CAPABILITIES
LXC_ATTACH_SET_PERSONALITY = _lxc.LXC_ATTACH_SET_PERSONALITY 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_REMOUNT_PROC_SYS = _lxc.LXC_ATTACH_REMOUNT_PROC_SYS
LXC_ATTACH_DEFAULT = _lxc.LXC_ATTACH_DEFAULT LXC_ATTACH_DEFAULT = _lxc.LXC_ATTACH_DEFAULT
CLONE_NEWUTS = _lxc.CLONE_NEWUTS CLONE_NEWUTS = _lxc.CLONE_NEWUTS
......
...@@ -22,6 +22,7 @@ lxc_test_concurrent_SOURCES = concurrent.c ...@@ -22,6 +22,7 @@ lxc_test_concurrent_SOURCES = concurrent.c
lxc_test_may_control_SOURCES = may_control.c lxc_test_may_control_SOURCES = may_control.c
lxc_test_reboot_SOURCES = reboot.c lxc_test_reboot_SOURCES = reboot.c
lxc_test_list_SOURCES = list.c lxc_test_list_SOURCES = list.c
lxc_test_attach_SOURCES = attach.c
AM_CFLAGS=-I$(top_srcdir)/src \ AM_CFLAGS=-I$(top_srcdir)/src \
-DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \ -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
...@@ -30,12 +31,20 @@ AM_CFLAGS=-I$(top_srcdir)/src \ ...@@ -30,12 +31,20 @@ AM_CFLAGS=-I$(top_srcdir)/src \
-DLXCINITDIR=\"$(LXCINITDIR)\" \ -DLXCINITDIR=\"$(LXCINITDIR)\" \
-DLXC_DEFAULT_CONFIG=\"$(LXC_DEFAULT_CONFIG)\" -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 \ bin_PROGRAMS = lxc-test-containertests lxc-test-locktests lxc-test-startone \
lxc-test-destroytest lxc-test-saveconfig lxc-test-createtest \ lxc-test-destroytest lxc-test-saveconfig lxc-test-createtest \
lxc-test-shutdowntest lxc-test-get_item lxc-test-getkeys lxc-test-lxcpath \ 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-cgpath lxc-test-clonetest lxc-test-console lxc-usernic-test \
lxc-test-snapshot lxc-test-concurrent lxc-test-may-control \ 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 bin_SCRIPTS = lxc-test-usernic
......
/* liblxcapi
*
* Copyright © 2013 Oracle.
*
* Authors:
* Dwight Engen <dwight.engen@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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment