>From c378426d560a8a071656f08e7f27bf5fbe9b17ad Mon Sep 17 00:00:00 2001
From: Tycho Andersen <tycho.andersen@canonical.com>
Date: Mon, 7 Dec 2015 17:07:05 -0700
Subject: [PATCH 1/4] cgroup: add cgroup_escape() call

We'll use this in the next patch to escape to the root cgroup before we
exec criu.

v2: s/cgm_connected/cmg_needs_disconnect/g

Signed-off-by: Tycho Andersen <tycho.andersen@canonical.com>
Acked-by: Serge E. Hallyn <serge.hallyn@ubuntu.com>
---
 src/lxc/cgfs.c      | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lxc/cgmanager.c | 19 ++++++++++++++++---
 src/lxc/cgroup.c    |  7 +++++++
 src/lxc/cgroup.h    |  2 ++
 4 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/src/lxc/cgfs.c b/src/lxc/cgfs.c
index d65f2d7..94b3d87 100644
--- a/src/lxc/cgfs.c
+++ b/src/lxc/cgfs.c
@@ -2343,6 +2343,55 @@ static const char *cgfs_canonical_path(void *hdata)
 	return path;
 }
 
+static bool cgfs_escape(void)
+{
+	struct cgroup_meta_data *md;
+	int i;
+	bool ret = false;
+
+	md = lxc_cgroup_load_meta();
+	if (!md)
+		return false;
+
+	for (i = 1; i <= md->maximum_hierarchy; i++) {
+		struct cgroup_hierarchy *h = md->hierarchies[i];
+		struct cgroup_mount_point *mp;
+		char *tasks;
+		FILE *f;
+		int written;
+
+		if (!h) {
+			WARN("not escaping hierarchy %d", i);
+			continue;
+		}
+
+		mp = lxc_cgroup_find_mount_point(h, "/", true);
+		if (!mp)
+			goto out;
+
+		tasks = cgroup_to_absolute_path(mp, "/", "tasks");
+		if (!tasks)
+			goto out;
+
+		f = fopen(tasks, "a");
+		free(tasks);
+		if (!f)
+			goto out;
+
+		written = fprintf(f, "%d\n", getpid());
+		fclose(f);
+		if (written < 0) {
+			SYSERROR("writing tasks failed\n");
+			goto out;
+		}
+	}
+
+	ret = true;
+out:
+	lxc_cgroup_put_meta(md);
+	return ret;
+}
+
 static bool cgfs_unfreeze(void *hdata)
 {
 	struct cgfs_data *d = hdata;
@@ -2408,6 +2457,7 @@ static struct cgroup_ops cgfs_ops = {
 	.create_legacy = cgfs_create_legacy,
 	.get_cgroup = cgfs_get_cgroup,
 	.canonical_path = cgfs_canonical_path,
+	.escape = cgfs_escape,
 	.get = lxc_cgroupfs_get,
 	.set = lxc_cgroupfs_set,
 	.unfreeze = cgfs_unfreeze,
diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c
index 05df0da..b82be59 100644
--- a/src/lxc/cgmanager.c
+++ b/src/lxc/cgmanager.c
@@ -312,13 +312,22 @@ static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path
  * be in "/lxc/c1" rather than "/user/..../c1"
  * called internally with connection already open
  */
-static bool lxc_cgmanager_escape(void)
+static bool cgm_escape(void)
 {
-	bool ret = true;
+	bool ret = true, cgm_needs_disconnect = false;
 	pid_t me = getpid();
 	char **slist = subsystems;
 	int i;
 
+	if (!cgroup_manager) {
+		if (!cgm_dbus_connect()) {
+			ERROR("Error connecting to cgroup manager");
+			return false;
+		}
+		cgm_needs_disconnect = true;
+	}
+
+
 	if (cgm_all_controllers_same)
 		slist = subsystems_inone;
 
@@ -335,6 +344,9 @@ static bool lxc_cgmanager_escape(void)
 		}
 	}
 
+	if (cgm_needs_disconnect)
+		cgm_dbus_disconnect();
+
 	return ret;
 }
 
@@ -1307,7 +1319,7 @@ struct cgroup_ops *cgm_ops_init(void)
 		goto err1;
 
 	// root;  try to escape to root cgroup
-	if (geteuid() == 0 && !lxc_cgmanager_escape())
+	if (geteuid() == 0 && !cgm_escape())
 		goto err2;
 	cgm_dbus_disconnect();
 
@@ -1524,6 +1536,7 @@ static struct cgroup_ops cgmanager_ops = {
 	.create_legacy = NULL,
 	.get_cgroup = cgm_get_cgroup,
 	.canonical_path = cgm_canonical_path,
+	.escape = cgm_escape,
 	.get = cgm_get,
 	.set = cgm_set,
 	.unfreeze = cgm_unfreeze,
diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
index b1c764f..aeb8a58 100644
--- a/src/lxc/cgroup.c
+++ b/src/lxc/cgroup.c
@@ -109,6 +109,13 @@ const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem
 	return NULL;
 }
 
+bool cgroup_escape(void)
+{
+	if (ops)
+		return ops->escape();
+	return false;
+}
+
 const char *cgroup_canonical_path(struct lxc_handler *handler)
 {
 	if (geteuid()) {
diff --git a/src/lxc/cgroup.h b/src/lxc/cgroup.h
index 7704c04..e3d3ce4 100644
--- a/src/lxc/cgroup.h
+++ b/src/lxc/cgroup.h
@@ -47,6 +47,7 @@ struct cgroup_ops {
 	bool (*create_legacy)(void *hdata, pid_t pid);
 	const char *(*get_cgroup)(void *hdata, const char *subsystem);
 	const char *(*canonical_path)(void *hdata);
+	bool (*escape)(void);
 	int (*set)(const char *filename, const char *value, const char *name, const char *lxcpath);
 	int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
 	bool (*unfreeze)(void *hdata);
@@ -71,6 +72,7 @@ extern void cgroup_cleanup(struct lxc_handler *handler);
 extern bool cgroup_create_legacy(struct lxc_handler *handler);
 extern int cgroup_nrtasks(struct lxc_handler *handler);
 extern const char *cgroup_get_cgroup(struct lxc_handler *handler, const char *subsystem);
+extern bool cgroup_escape(void);
 
 /*
  * Currently, this call  only makes sense for privileged containers.
-- 
2.5.0

