Commit 956f113b by Serge Hallyn

cgmanager: several fixes

These all fix various ways that cgroup actions could fail if an unprivileged user's cgroup paths were not all the same for all controllers. 1. in cgm_{g,s}et, use the right controller, not the first in the list, to get the cgroup path. 2. when we pass 'all' to cgmanager for a ${METHOD}_abs, make sure that all cgroup paths are the same. That isn't necessary for methods not taking an absolute path, so split up the former cgm_supports_multiple_controllers() function into two booleans, one telling whether cgm supports it, and another telling us whether cgm supports it AND all controller cgroup paths are the same. 3. separately, do_cgm_enter with abs=true couldn't work if all cgroup paths were not the same. So just ditch that helper and call lxc_cgmanager_enter() where needed, because the special cases would be more complicated. Signed-off-by: 's avatarSerge Hallyn <serge.hallyn@ubuntu.com>
parent f422613e
...@@ -182,9 +182,60 @@ static bool cgm_dbus_connect(void) ...@@ -182,9 +182,60 @@ static bool cgm_dbus_connect(void)
return true; return true;
} }
static inline bool cgm_supports_multiple_controllers(void) static bool cgm_supports_multiple_controllers;
/*
* if cgm_all_controllers_same is true, then cgm_supports_multiple_controllers
* is true
*/
static bool cgm_all_controllers_same;
static void check_supports_multiple_controllers(void)
{ {
return api_version >= CGM_SUPPORTS_MULT_CONTROLLERS; FILE *f;
char *line = NULL, *prevpath = NULL;
size_t sz = 0;
cgm_supports_multiple_controllers = false;
cgm_all_controllers_same = false;
if (api_version < CGM_SUPPORTS_MULT_CONTROLLERS) {
cgm_supports_multiple_controllers = false;
return;
}
cgm_supports_multiple_controllers = true;
f = fopen("/proc/self/cgroup", "r");
if (!f)
return;
cgm_all_controllers_same = true;
while (getline(&line, &sz, f) != -1) {
/* file format: hierarchy:subsystems:group */
char *colon;
if (!line[0])
continue;
colon = strchr(line, ':');
if (!colon)
continue;
colon = strchr(colon+1, ':');
if (!colon)
continue;
colon++;
if (!prevpath) {
prevpath = alloca(strlen(colon)+1);
strcpy(prevpath, colon);
continue;
}
if (strcmp(prevpath, colon) != 0) {
cgm_all_controllers_same = false;
fclose(f);
return;
}
}
fclose(f);
} }
static int send_creds(int sock, int rpid, int ruid, int rgid) static int send_creds(int sock, int rpid, int ruid, int rgid)
...@@ -251,7 +302,7 @@ static bool lxc_cgmanager_escape(void) ...@@ -251,7 +302,7 @@ static bool lxc_cgmanager_escape(void)
char **slist = subsystems; char **slist = subsystems;
int i; int i;
if (cgm_supports_multiple_controllers()) if (cgm_all_controllers_same)
slist = subsystems_inone; slist = subsystems_inone;
for (i = 0; slist[i]; i++) { for (i = 0; slist[i]; i++) {
...@@ -367,7 +418,7 @@ static int chown_cgroup_wrapper(void *data) ...@@ -367,7 +418,7 @@ static int chown_cgroup_wrapper(void *data)
} }
destuid = get_ns_uid(arg->origuid); destuid = get_ns_uid(arg->origuid);
if (cgm_supports_multiple_controllers()) if (cgm_supports_multiple_controllers)
slist = subsystems_inone; slist = subsystems_inone;
for (i = 0; slist[i]; i++) { for (i = 0; slist[i]; i++) {
...@@ -425,7 +476,7 @@ static bool chown_cgroup(const char *cgroup_path, struct lxc_conf *conf) ...@@ -425,7 +476,7 @@ static bool chown_cgroup(const char *cgroup_path, struct lxc_conf *conf)
* This can't be done in the child namespace because it only group-owns * This can't be done in the child namespace because it only group-owns
* the cgroup * the cgroup
*/ */
if (cgm_supports_multiple_controllers()) if (cgm_supports_multiple_controllers)
slist = subsystems_inone; slist = subsystems_inone;
for (i = 0; slist[i]; i++) { for (i = 0; slist[i]; i++) {
...@@ -465,6 +516,9 @@ static void *cgm_init(const char *name) ...@@ -465,6 +516,9 @@ static void *cgm_init(const char *name)
ERROR("Error connecting to cgroup manager"); ERROR("Error connecting to cgroup manager");
return NULL; return NULL;
} }
check_supports_multiple_controllers();
d = malloc(sizeof(*d)); d = malloc(sizeof(*d));
if (!d) { if (!d) {
cgm_dbus_disconnect(); cgm_dbus_disconnect();
...@@ -509,7 +563,7 @@ static void cgm_destroy(void *hdata) ...@@ -509,7 +563,7 @@ static void cgm_destroy(void *hdata)
return; return;
} }
if (cgm_supports_multiple_controllers()) if (cgm_supports_multiple_controllers)
slist = subsystems_inone; slist = subsystems_inone;
for (i = 0; slist[i]; i++) for (i = 0; slist[i]; i++)
cgm_remove_cgroup(slist[i], d->cgroup_path); cgm_remove_cgroup(slist[i], d->cgroup_path);
...@@ -530,7 +584,7 @@ static inline void cleanup_cgroups(char *path) ...@@ -530,7 +584,7 @@ static inline void cleanup_cgroups(char *path)
int i; int i;
char **slist = subsystems; char **slist = subsystems;
if (cgm_supports_multiple_controllers()) if (cgm_supports_multiple_controllers)
slist = subsystems_inone; slist = subsystems_inone;
for (i = 0; slist[i]; i++) for (i = 0; slist[i]; i++)
cgm_remove_cgroup(slist[i], path); cgm_remove_cgroup(slist[i], path);
...@@ -576,7 +630,7 @@ again: ...@@ -576,7 +630,7 @@ again:
} }
existed = 0; existed = 0;
if (cgm_supports_multiple_controllers()) if (cgm_supports_multiple_controllers)
slist = subsystems_inone; slist = subsystems_inone;
for (i = 0; slist[i]; i++) { for (i = 0; slist[i]; i++) {
...@@ -636,34 +690,28 @@ static bool lxc_cgmanager_enter(pid_t pid, const char *controller, ...@@ -636,34 +690,28 @@ static bool lxc_cgmanager_enter(pid_t pid, const char *controller,
return true; return true;
} }
/* Internal helper, must be called with cgmanager dbus socket open */ static inline bool cgm_enter(void *hdata, pid_t pid)
static bool do_cgm_enter(pid_t pid, const char *cgroup_path, bool abs)
{ {
struct cgm_data *d = hdata;
char **slist = subsystems; char **slist = subsystems;
bool ret = false;
int i; int i;
if (cgm_supports_multiple_controllers()) if (!d || !d->cgroup_path)
slist = subsystems_inone;
for (i = 0; slist[i]; i++) {
if (!lxc_cgmanager_enter(pid, slist[i], cgroup_path, abs))
return false; return false;
}
return true;
}
static inline bool cgm_enter(void *hdata, pid_t pid)
{
struct cgm_data *d = hdata;
bool ret = false;
if (!cgm_dbus_connect()) { if (!cgm_dbus_connect()) {
ERROR("Error connecting to cgroup manager"); ERROR("Error connecting to cgroup manager");
return false; return false;
} }
if (!d || !d->cgroup_path)
if (cgm_all_controllers_same)
slist = subsystems_inone;
for (i = 0; slist[i]; i++) {
if (!lxc_cgmanager_enter(pid, slist[i], d->cgroup_path, false))
goto out; goto out;
if (do_cgm_enter(pid, d->cgroup_path, false)) }
ret = true; ret = true;
out: out:
cgm_dbus_disconnect(); cgm_dbus_disconnect();
...@@ -784,7 +832,7 @@ static void do_cgm_get(const char *name, const char *lxcpath, const char *filena ...@@ -784,7 +832,7 @@ static void do_cgm_get(const char *name, const char *lxcpath, const char *filena
WARN("Failed to warn cgm_get of error; parent may hang"); WARN("Failed to warn cgm_get of error; parent may hang");
exit(1); exit(1);
} }
cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]); cgroup = try_get_abs_cgroup(name, lxcpath, controller);
if (!cgroup) { if (!cgroup) {
cgm_dbus_disconnect(); cgm_dbus_disconnect();
ret = write(outp, &len, sizeof(len)); ret = write(outp, &len, sizeof(len));
...@@ -924,7 +972,7 @@ static void do_cgm_set(const char *name, const char *lxcpath, const char *filena ...@@ -924,7 +972,7 @@ static void do_cgm_set(const char *name, const char *lxcpath, const char *filena
WARN("Failed to warn cgm_set of error; parent may hang"); WARN("Failed to warn cgm_set of error; parent may hang");
exit(1); exit(1);
} }
cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]); cgroup = try_get_abs_cgroup(name, lxcpath, controller);
if (!cgroup) { if (!cgroup) {
cgm_dbus_disconnect(); cgm_dbus_disconnect();
ret = write(outp, &retval, sizeof(retval)); ret = write(outp, &retval, sizeof(retval));
...@@ -1222,24 +1270,35 @@ static bool cgm_chown(void *hdata, struct lxc_conf *conf) ...@@ -1222,24 +1270,35 @@ 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; bool pass = true;
char *cgroup = NULL; char *cgroup = NULL;
char **slist = subsystems;
int i;
if (!cgm_dbus_connect()) { if (!cgm_dbus_connect()) {
ERROR("Error connecting to cgroup manager"); ERROR("Error connecting to cgroup manager");
return false; return false;
} }
// 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, check_supports_multiple_controllers();
// just get the cgroup name for the first one.
cgroup = try_get_abs_cgroup(name, lxcpath, subsystems[0]); if (cgm_all_controllers_same)
slist = subsystems_inone;
for (i = 0; slist[i]; i++) {
cgroup = try_get_abs_cgroup(name, lxcpath, slist[i]);
if (!cgroup) { if (!cgroup) {
ERROR("Failed to get cgroup for controller %s", subsystems[0]); ERROR("Failed to get cgroup for controller %s", slist[i]);
cgm_dbus_disconnect(); cgm_dbus_disconnect();
return false; return false;
} }
pass = do_cgm_enter(pid, cgroup, abs_cgroup_supported()); if (!lxc_cgmanager_enter(pid, slist[i], cgroup, abs_cgroup_supported())) {
pass = false;
break;
}
}
cgm_dbus_disconnect(); cgm_dbus_disconnect();
if (!pass) if (!pass)
ERROR("Failed to enter group %s", cgroup); ERROR("Failed to enter group %s", cgroup);
......
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