Commit 25c7531c by Serge Hallyn Committed by Stéphane Graber

cgmanager: use absolute cgroup path to switch cgroups at attach

If an unprivileged user does 'lxc-start -n u1' in one login session, followed by 'lxc-attach -n u1' in another session, the attach will fail if the sessions are in different cgroups. The same is true of lxc-cgroup commands. Address this by using the GetPidCgroupAbs and MovePidAbs which work with the containers' cgroup path relative to the cgproxy. Since GetPidCgroupAbs is new to api version 3 in cgmanager, use the old method if we are on an older cgmanager. Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com> Tested-by: 's avatar"S.Çağlar Onur" <caglar@10ur.org> Acked-by: 's avatarStéphane Graber <stgraber@ubuntu.com>
parent cbf0bae6
...@@ -256,6 +256,14 @@ AM_COND_IF([ENABLE_CGMANAGER], ...@@ -256,6 +256,14 @@ AM_COND_IF([ENABLE_CGMANAGER],
PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16]) PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.2.16])
]) ])
AC_MSG_CHECKING(for get_pid_cgroup_abs_sync)
AC_SEARCH_LIBS([cgmanager_get_pid_cgroup_abs_sync], [cgmanager], [have_abs_cgroups=yes], [have_abs_cgroups=no], [-lnih -lnih-dbus -ldbus-1])
if test "x$have_abs_cgroups" = "xyes"; then
AC_DEFINE([HAVE_CGMANAGER_GET_PID_CGROUP_ABS_SYNC], 1, [Have cgmanager_get_pid_cgroup_abs_sync])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
# Linux capabilities # Linux capabilities
AC_ARG_ENABLE([capabilities], AC_ARG_ENABLE([capabilities],
[AC_HELP_STRING([--enable-capabilities], [enable kernel capabilities support [default=auto]])], [AC_HELP_STRING([--enable-capabilities], [enable kernel capabilities support [default=auto]])],
......
...@@ -107,6 +107,7 @@ static void process_lock_setup_atfork(void) ...@@ -107,6 +107,7 @@ static void process_lock_setup_atfork(void)
#endif #endif
static NihDBusProxy *cgroup_manager = NULL; static NihDBusProxy *cgroup_manager = NULL;
static int32_t api_version;
static struct cgroup_ops cgmanager_ops; static struct cgroup_ops cgmanager_ops;
static int nr_subsystems; static int nr_subsystems;
...@@ -162,11 +163,11 @@ static bool cgm_dbus_connect(void) ...@@ -162,11 +163,11 @@ static bool cgm_dbus_connect(void)
return false; return false;
} }
// force fd passing negotiation // get the api version
if (cgmanager_ping_sync(NULL, cgroup_manager, 0) != 0) { if (cgmanager_get_api_version_sync(NULL, cgroup_manager, &api_version) != 0) {
NihError *nerr; NihError *nerr;
nerr = nih_error_get(); nerr = nih_error_get();
ERROR("Error pinging cgroup manager: %s", nerr->message); ERROR("Error cgroup manager api version: %s", nerr->message);
nih_free(nerr); nih_free(nerr);
cgm_dbus_disconnect(); cgm_dbus_disconnect();
return false; return false;
...@@ -554,13 +555,21 @@ bad: ...@@ -554,13 +555,21 @@ bad:
* Internal helper, must be called with cgmanager dbus socket open * Internal helper, must be called with cgmanager dbus socket open
*/ */
static bool lxc_cgmanager_enter(pid_t pid, const char *controller, static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
const char *cgroup_path) const char *cgroup_path, bool abs)
{ {
if (cgmanager_move_pid_sync(NULL, cgroup_manager, controller, int ret;
cgroup_path, pid) != 0) {
if (abs)
ret = cgmanager_move_pid_abs_sync(NULL, cgroup_manager,
controller, cgroup_path, pid);
else
ret = cgmanager_move_pid_sync(NULL, cgroup_manager,
controller, cgroup_path, pid);
if (ret != 0) {
NihError *nerr; NihError *nerr;
nerr = nih_error_get(); nerr = nih_error_get();
ERROR("call to cgmanager_move_pid_sync failed: %s", nerr->message); ERROR("call to cgmanager_move_pid_%ssync failed: %s",
abs ? "abs_" : "", nerr->message);
nih_free(nerr); nih_free(nerr);
return false; return false;
} }
...@@ -568,12 +577,12 @@ static bool lxc_cgmanager_enter(pid_t pid, const char *controller, ...@@ -568,12 +577,12 @@ static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
} }
/* Internal helper, must be called with cgmanager dbus socket open */ /* Internal helper, must be called with cgmanager dbus socket open */
static bool do_cgm_enter(pid_t pid, const char *cgroup_path) static bool do_cgm_enter(pid_t pid, const char *cgroup_path, bool abs)
{ {
int i; int i;
for (i = 0; i < nr_subsystems; i++) { for (i = 0; i < nr_subsystems; i++) {
if (!lxc_cgmanager_enter(pid, subsystems[i], cgroup_path)) if (!lxc_cgmanager_enter(pid, subsystems[i], cgroup_path, abs))
return false; return false;
} }
return true; return true;
...@@ -590,7 +599,7 @@ static inline bool cgm_enter(void *hdata, pid_t pid) ...@@ -590,7 +599,7 @@ static inline bool cgm_enter(void *hdata, pid_t pid)
} }
if (!d || !d->cgroup_path) if (!d || !d->cgroup_path)
goto out; goto out;
if (do_cgm_enter(pid, d->cgroup_path)) if (do_cgm_enter(pid, d->cgroup_path, false))
ret = true; ret = true;
out: out:
cgm_dbus_disconnect(); cgm_dbus_disconnect();
...@@ -606,6 +615,41 @@ static const char *cgm_get_cgroup(void *hdata, const char *subsystem) ...@@ -606,6 +615,41 @@ static const char *cgm_get_cgroup(void *hdata, const char *subsystem)
return d->cgroup_path; return d->cgroup_path;
} }
#if HAVE_CGMANAGER_GET_PID_CGROUP_ABS_SYNC
static inline bool abs_cgroup_supported(void) {
return api_version >= 3;
}
#else
static inline bool abs_cgroup_supported(void) {
return false;
}
#define cgmanager_get_pid_cgroup_abs_sync(...) -1
#endif
static char *try_get_abs_cgroup(const char *name, const char *lxcpath,
const char *controller)
{
char *cgroup = NULL;
if (abs_cgroup_supported()) {
/* get the container init pid and ask for its abs cgroup */
pid_t pid = lxc_cmd_get_init_pid(name, lxcpath);
if (pid < 0)
return NULL;
if (cgmanager_get_pid_cgroup_abs_sync(NULL, cgroup_manager,
controller, pid, &cgroup) != 0) {
cgroup = NULL;
NihError *nerr;
nerr = nih_error_get();
nih_free(nerr);
}
return cgroup;
}
/* use the command interface to look for the cgroup */
return lxc_cmd_get_cgroup_path(name, lxcpath, controller);
}
/* /*
* nrtasks is called by the utmp helper by the container monitor. * nrtasks is called by the utmp helper by the container monitor.
* cgmanager socket was closed after cgroup setup was complete, so we need * cgmanager socket was closed after cgroup setup was complete, so we need
...@@ -641,10 +685,20 @@ out: ...@@ -641,10 +685,20 @@ out:
return pids_len; return pids_len;
} }
static inline void free_abs_cgroup(char *cgroup)
{
if (!cgroup)
return;
if (abs_cgroup_supported())
nih_free(cgroup);
else
free(cgroup);
}
/* cgm_get is called to get container cgroup settings, not during startup */ /* cgm_get is called to get container cgroup settings, not during startup */
static int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath) static int cgm_get(const char *filename, char *value, size_t len, const char *name, const char *lxcpath)
{ {
char *result, *controller, *key, *cgroup; char *result, *controller, *key, *cgroup = NULL;
size_t newlen; size_t newlen;
controller = alloca(strlen(filename)+1); controller = alloca(strlen(filename)+1);
...@@ -654,14 +708,17 @@ static int cgm_get(const char *filename, char *value, size_t len, const char *na ...@@ -654,14 +708,17 @@ static int cgm_get(const char *filename, char *value, size_t len, const char *na
return -1; return -1;
*key = '\0'; *key = '\0';
/* use the command interface to look for the cgroup */
cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
if (!cgroup)
return -1;
if (!cgm_dbus_connect()) { if (!cgm_dbus_connect()) {
ERROR("Error connecting to cgroup manager"); ERROR("Error connecting to cgroup manager");
return -1; return -1;
} }
cgroup = try_get_abs_cgroup(name, lxcpath, controller);
if (!cgroup) {
cgm_dbus_disconnect();
return -1;
}
if (cgmanager_get_value_sync(NULL, cgroup_manager, controller, cgroup, filename, &result) != 0) { if (cgmanager_get_value_sync(NULL, cgroup_manager, controller, cgroup, filename, &result) != 0) {
/* /*
* must consume the nih error * must consume the nih error
...@@ -671,12 +728,12 @@ static int cgm_get(const char *filename, char *value, size_t len, const char *na ...@@ -671,12 +728,12 @@ static int cgm_get(const char *filename, char *value, size_t len, const char *na
NihError *nerr; NihError *nerr;
nerr = nih_error_get(); nerr = nih_error_get();
nih_free(nerr); nih_free(nerr);
free(cgroup); free_abs_cgroup(cgroup);
cgm_dbus_disconnect(); cgm_dbus_disconnect();
return -1; return -1;
} }
cgm_dbus_disconnect(); cgm_dbus_disconnect();
free(cgroup); free_abs_cgroup(cgroup);
newlen = strlen(result); newlen = strlen(result);
if (!len || !value) { if (!len || !value) {
// user queries the size // user queries the size
...@@ -717,7 +774,7 @@ static int cgm_do_set(const char *controller, const char *file, ...@@ -717,7 +774,7 @@ static int cgm_do_set(const char *controller, const char *file,
/* cgm_set is called to change cgroup settings, not during startup */ /* cgm_set is called to change cgroup settings, not during startup */
static int cgm_set(const char *filename, const char *value, const char *name, const char *lxcpath) static int cgm_set(const char *filename, const char *value, const char *name, const char *lxcpath)
{ {
char *controller, *key, *cgroup; char *controller, *key, *cgroup = NULL;
int ret; int ret;
controller = alloca(strlen(filename)+1); controller = alloca(strlen(filename)+1);
...@@ -727,21 +784,21 @@ static int cgm_set(const char *filename, const char *value, const char *name, co ...@@ -727,21 +784,21 @@ static int cgm_set(const char *filename, const char *value, const char *name, co
return -1; return -1;
*key = '\0'; *key = '\0';
/* use the command interface to look for the cgroup */
cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, controller);
if (!cgroup) {
ERROR("Failed to get cgroup for controller %s for %s:%s",
controller, lxcpath, name);
return -1;
}
if (!cgm_dbus_connect()) { if (!cgm_dbus_connect()) {
ERROR("Error connecting to cgroup manager"); ERROR("Error connecting to cgroup manager");
free(cgroup); free(cgroup);
return false; return false;
} }
cgroup = try_get_abs_cgroup(name, lxcpath, controller);
if (!cgroup) {
ERROR("Failed to get cgroup for controller %s for %s:%s",
controller, lxcpath, name);
cgm_dbus_disconnect();
return -1;
}
ret = cgm_do_set(controller, filename, cgroup, value); ret = cgm_do_set(controller, filename, cgroup, value);
cgm_dbus_disconnect(); cgm_dbus_disconnect();
free(cgroup); free_abs_cgroup(cgroup);
return ret; return ret;
} }
...@@ -947,36 +1004,29 @@ static bool cgm_chown(void *hdata, struct lxc_conf *conf) ...@@ -947,36 +1004,29 @@ static bool cgm_chown(void *hdata, struct lxc_conf *conf)
*/ */
static bool cgm_attach(const char *name, const char *lxcpath, pid_t pid) static bool cgm_attach(const char *name, const char *lxcpath, pid_t pid)
{ {
bool pass = false; bool pass;
char *cgroup = NULL; char *cgroup = NULL;
struct lxc_container *c;
c = lxc_container_new(name, lxcpath); if (!cgm_dbus_connect()) {
if (!c) { ERROR("Error connecting to cgroup manager");
ERROR("Could not load container %s:%s", lxcpath, name);
return false; return false;
} }
// cgm_create makes sure that we have the same cgroup name for all // cgm_create makes sure that we have the same cgroup name for all
// subsystems, so since this is a slow command over the cmd socket, // subsystems, so since this is a slow command over the cmd socket,
// just get the cgroup name for the first one. // just get the cgroup name for the first one.
cgroup = lxc_cmd_get_cgroup_path(name, lxcpath, subsystems[0]); cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]);
if (!cgroup) { if (!cgroup) {
ERROR("Failed to get cgroup for controller %s", subsystems[0]); ERROR("Failed to get cgroup for controller %s", subsystems[0]);
goto out; cgm_dbus_disconnect();
return false;
} }
if (!cgm_dbus_connect()) { pass = do_cgm_enter(pid, cgroup, abs_cgroup_supported());
ERROR("Error connecting to cgroup manager");
goto out;
}
pass = do_cgm_enter(pid, cgroup);
cgm_dbus_disconnect(); cgm_dbus_disconnect();
if (!pass) if (!pass)
ERROR("Failed to enter group %s", cgroup); ERROR("Failed to enter group %s", cgroup);
out: free_abs_cgroup(cgroup);
free(cgroup);
lxc_container_put(c);
return pass; return pass;
} }
......
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