commit 9c41660679e740eecc4831b4a0043a09197d44dd
Author: Serge Hallyn <serge.hallyn@ubuntu.com>
Date:   Wed Feb 11 19:07:38 2015 -0600

    Fix subdirectory check
    
    Commit 6a30adc22cc05b5 was not quite complete.  If the task is in
    /xxx then it may act on /xxx or /xxx/a, but not /xxx2.  This commit
    fixes the check to disallow /xxx2.  It also commonizes the check,
    cleaning up the code a bit.
    
    Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>

Index: cgmanager-0.33/cgmanager.c
===================================================================
--- cgmanager-0.33.orig/cgmanager.c
+++ cgmanager-0.33/cgmanager.c
@@ -557,20 +557,13 @@ next:
 int get_value_main(void *parent, const char *controller, const char *cgroup,
 		const char *key, struct ucred p, struct ucred r, char **value)
 {
-	char pcgpath[MAXPATHLEN], path[MAXPATHLEN];
+	char path[MAXPATHLEN];
 
 	if (!sane_cgroup(cgroup)) {
 		nih_error("%s: unsafe cgroup", __func__);
 		return -1;
 	}
 
-	// Get p's current cgroup in pcgpath
-	if (!compute_pid_cgroup(p.pid, controller, "", pcgpath, NULL)) {
-		nih_error("%s: Could not determine the proxy's cgroup for %s",
-				__func__, controller);
-		return -1;
-	}
-
 	if (!compute_pid_cgroup(r.pid, controller, cgroup, path, NULL)) {
 		nih_error("%s: Could not determine the requested cgroup (%s:%s)",
                 __func__, controller, cgroup);
@@ -583,9 +576,7 @@ int get_value_main(void *parent, const c
 		return -1;
 	}
 
-	// Make sure target cgroup is under proxy's
-	int plen = strlen(pcgpath);
-	if (strncmp(pcgpath, path, plen) != 0) {
+	if (!path_is_under_taskcg(p.pid, controller, path)) {
 		nih_error("%s: target cgroup is not below r (%d)'s", __func__,
 			r.pid);
 		return -1;
@@ -622,29 +613,20 @@ int set_value_main(const char *controlle
 		struct ucred r)
 
 {
-	char pcgpath[MAXPATHLEN], path[MAXPATHLEN];
+	char path[MAXPATHLEN];
 
 	if (!sane_cgroup(cgroup)) {
 		nih_error("%s: unsafe cgroup", __func__);
 		return -1;
 	}
 
-	// Get p's current cgroup in pcgpath
-	if (!compute_pid_cgroup(p.pid, controller, "", pcgpath, NULL)) {
-		nih_error("%s: Could not determine the proxy's cgroup for %s",
-				__func__, controller);
-		return -1;
-	}
-
 	if (!compute_pid_cgroup(r.pid, controller, cgroup, path, NULL)) {
 		nih_error("%s: Could not determine the requested cgroup (%s:%s)",
                 __func__, controller, cgroup);
 		return -1;
 	}
 
-	// Make sure target cgroup is under proxy's
-	int plen = strlen(pcgpath);
-	if (strncmp(pcgpath, path, plen) != 0) {
+	if (!path_is_under_taskcg(p.pid, controller, path)) {
 		nih_error("%s: target cgroup is not below r (%d)'s", __func__,
 			r.pid);
 		return -1;
@@ -852,7 +834,7 @@ next:
 int get_tasks_main(void *parent, const char *controller, const char *cgroup,
 			struct ucred p, struct ucred r, int32_t **pids)
 {
-	char pcgpath[MAXPATHLEN], path[MAXPATHLEN];
+	char path[MAXPATHLEN];
 	const char *key = "tasks";
 	int alloced_pids = 0, nrpids = 0;
 
@@ -861,22 +843,13 @@ int get_tasks_main(void *parent, const c
 		return -1;
 	}
 
-	// Get p's current cgroup in pcgpath
-	if (!compute_pid_cgroup(p.pid, controller, "", pcgpath, NULL)) {
-		nih_error("%s: Could not determine the proxy's cgroup for %s",
-				__func__, controller);
-		return -1;
-	}
-
 	if (!compute_pid_cgroup(r.pid, controller, cgroup, path, NULL)) {
 		nih_error("%s: Could not determine the requested cgroup (%s:%s)",
                 __func__, controller, cgroup);
 		return -1;
 	}
 
-	// Make sure target cgroup is under proxy's
-	int plen = strlen(pcgpath);
-	if (strncmp(pcgpath, path, plen) != 0) {
+	if (!path_is_under_taskcg(p.pid, controller, path)) {
 		nih_error("%s: target cgroup is not below r (%d)'s", __func__,
 			r.pid);
 		return -1;
@@ -951,7 +924,7 @@ int collect_tasks(void *parent, const ch
 		struct ucred p, struct ucred r, int32_t **pids,
 		int *alloced_pids, int *nrpids)
 {
-	char pcgpath[MAXPATHLEN], path[MAXPATHLEN];
+	char path[MAXPATHLEN];
 	nih_local char *rpath = NULL;
 
 	if (!sane_cgroup(cgroup)) {
@@ -959,22 +932,13 @@ int collect_tasks(void *parent, const ch
 		return -1;
 	}
 
-	// Get p's current cgroup in pcgpath
-	if (!compute_pid_cgroup(p.pid, controller, "", pcgpath, NULL)) {
-		nih_error("%s: Could not determine the proxy's cgroup for %s",
-				__func__, controller);
-		return -1;
-	}
-
 	if (!compute_pid_cgroup(r.pid, controller, cgroup, path, NULL)) {
 		nih_error("%s: Could not determine the requested cgroup (%s:%s)",
                 __func__, controller, cgroup);
 		return -2;
 	}
 
-	// Make sure target cgroup is under proxy's
-	int plen = strlen(pcgpath);
-	if (strncmp(pcgpath, path, plen) != 0) {
+	if (!path_is_under_taskcg(p.pid, controller, path)) {
 		nih_error("%s: target cgroup is not below r (%d)'s", __func__,
 			r.pid);
 		return -1;
@@ -1044,7 +1008,7 @@ next:
 int list_children_main(void *parent, const char *controller, const char *cgroup,
 			struct ucred p, struct ucred r, char ***output)
 {
-	char pcgpath[MAXPATHLEN], path[MAXPATHLEN];
+	char path[MAXPATHLEN];
 
 	*output = NULL;
 	if (!sane_cgroup(cgroup)) {
@@ -1052,22 +1016,13 @@ int list_children_main(void *parent, con
 		return -1;
 	}
 
-	// Get p's current cgroup in pcgpath
-	if (!compute_pid_cgroup(p.pid, controller, "", pcgpath, NULL)) {
-		nih_error("%s: Could not determine the proxy's cgroup for %s",
-				__func__, controller);
-		return -1;
-	}
-
 	if (!compute_pid_cgroup(r.pid, controller, cgroup, path, NULL)) {
 		nih_error("%s: Could not determine the requested cgroup (%s:%s)",
                 __func__, controller, cgroup);
 		return -1;
 	}
 
-	// Make sure target cgroup is under proxy's
-	int plen = strlen(pcgpath);
-	if (strncmp(pcgpath, path, plen) != 0) {
+	if (!path_is_under_taskcg(p.pid, controller, path)) {
 		nih_error("%s: target cgroup is not below r (%d)'s", __func__,
 			r.pid);
 		return -1;
Index: cgmanager-0.33/fs.c
===================================================================
--- cgmanager-0.33.orig/fs.c
+++ cgmanager-0.33/fs.c
@@ -1707,3 +1707,34 @@ bool was_premounted(const char *controll
 		return false;
 	return all_mounts[i].premounted;
 }
+
+/*
+ * Check that (absolute) @path is under @pid's cgroup for @contr
+ */
+bool path_is_under_taskcg(pid_t pid, const char *contr,const char *path)
+{
+	char pcgpath[MAXPATHLEN];
+	size_t plen;
+
+	// Get p's current cgroup in pcgpath
+	if (!compute_pid_cgroup(pid, contr, "", pcgpath, NULL)) {
+		nih_error("%s: Could not determine the proxy's cgroup for %s",
+				__func__, contr);
+		return false;
+	}
+	plen = strlen(pcgpath);
+	// path must start with pcgpath
+	if (strncmp(pcgpath, path, plen) != 0)
+		return false;
+	// If path is equal to pcgpath then that's ok
+	if (plen == strlen(path))
+		return true;
+	/*
+	 * if path is longer than pcpgath, then it must be a subdirectory
+	 * of pcpgpath. I.e. if pcgpath is /xxx then /xxx/a is ok, /xxx2 is
+	 * not.
+	 */
+	if (path[plen] == '/')
+		return true;
+	return false;
+}
Index: cgmanager-0.33/fs.h
===================================================================
--- cgmanager-0.33.orig/fs.h
+++ cgmanager-0.33/fs.h
@@ -57,3 +57,4 @@ bool was_premounted(const char *controll
 void do_prune_comounts(char *controllers);
 void do_list_controllers(void *parent, char ***output);
 void convert_directory_contents(struct keys_return_type **keys, struct ucred r);
+bool path_is_under_taskcg(pid_t pid, const char *contr,const char *path);
