diff -Nru cgmanager-0.32/debian/changelog cgmanager-0.32/debian/changelog --- cgmanager-0.32/debian/changelog 2014-09-18 21:32:41.000000000 +0000 +++ cgmanager-0.32/debian/changelog 2014-12-16 00:54:02.000000000 +0000 @@ -1,3 +1,13 @@ +cgmanager (0.32-4ubuntu1.1) utopic-security; urgency=medium + + * SECURITY UPDATE: Cross-cgroup resource control bypass. + - debian/patches/0001-make-sure-to-check-cgroup-hierarchy.patch, modify + cgmanager.c to verify that requests are allowed under the caller's + cgroup. + - CVE-2014-1425 + + -- Seth Arnold Mon, 15 Dec 2014 16:50:25 -0800 + cgmanager (0.32-4ubuntu1) utopic; urgency=medium * Fix wrong reporting of whether a cgroup existed at create when using diff -Nru cgmanager-0.32/debian/patches/0001-make-sure-to-check-cgroup-hierarchy.patch cgmanager-0.32/debian/patches/0001-make-sure-to-check-cgroup-hierarchy.patch --- cgmanager-0.32/debian/patches/0001-make-sure-to-check-cgroup-hierarchy.patch 1970-01-01 00:00:00.000000000 +0000 +++ cgmanager-0.32/debian/patches/0001-make-sure-to-check-cgroup-hierarchy.patch 2014-12-16 00:58:47.000000000 +0000 @@ -0,0 +1,201 @@ +From 6267916d4ea939794e0583cd8b08bd0b9594a6e2 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Wed, 26 Nov 2014 01:00:10 -0600 +Subject: [PATCH 1/1] make sure to check cgroup hierarchy + +Some cases weren't doing that, although at least those were still +checking for proper ownership. + +Signed-off-by: Serge Hallyn +--- + cgmanager.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 80 insertions(+), 5 deletions(-) + +Index: b/cgmanager.c +=================================================================== +--- a/cgmanager.c ++++ b/cgmanager.c +@@ -556,13 +556,20 @@ + int get_value_main(void *parent, const char *controller, const char *cgroup, + const char *key, struct ucred p, struct ucred r, char **value) + { +- char path[MAXPATHLEN]; ++ char pcgpath[MAXPATHLEN], 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); +@@ -575,6 +582,14 @@ + return -1; + } + ++ // Make sure target cgroup is under proxy's ++ int plen = strlen(pcgpath); ++ if (strncmp(pcgpath, path, plen) != 0) { ++ nih_error("%s: target cgroup is not below r (%d)'s", __func__, ++ r.pid); ++ return -1; ++ } ++ + /* append the filename */ + if (strlen(path) + strlen(key) + 2 > MAXPATHLEN) { + nih_error("%s: filename too long for cgroup %s key %s", __func__, path, key); +@@ -606,19 +621,34 @@ + struct ucred r) + + { +- char path[MAXPATHLEN]; ++ char pcgpath[MAXPATHLEN], 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) { ++ nih_error("%s: target cgroup is not below r (%d)'s", __func__, ++ r.pid); ++ return -1; ++ } ++ + /* Check access rights to the cgroup directory */ + if (!may_access(r.pid, r.uid, r.gid, path, O_RDONLY)) { + nih_error("%s: Pid %d may not access %s\n", __func__, r.pid, path); +@@ -821,7 +851,7 @@ + int get_tasks_main(void *parent, const char *controller, const char *cgroup, + struct ucred p, struct ucred r, int32_t **pids) + { +- char path[MAXPATHLEN]; ++ char pcgpath[MAXPATHLEN], path[MAXPATHLEN]; + const char *key = "tasks"; + int alloced_pids = 0, nrpids = 0; + +@@ -830,12 +860,27 @@ + 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) { ++ nih_error("%s: target cgroup is not below r (%d)'s", __func__, ++ r.pid); ++ return -1; ++ } ++ + /* Check access rights to the cgroup directory */ + if (!may_access(r.pid, r.uid, r.gid, path, O_RDONLY)) { + nih_error("%s: Pid %d may not access %s\n", __func__, r.pid, path); +@@ -904,7 +949,7 @@ + struct ucred p, struct ucred r, int32_t **pids, + int *alloced_pids, int *nrpids) + { +- char path[MAXPATHLEN]; ++ char pcgpath[MAXPATHLEN], path[MAXPATHLEN]; + nih_local char *rpath = NULL; + + if (!sane_cgroup(cgroup)) { +@@ -912,12 +957,27 @@ + 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) { ++ nih_error("%s: target cgroup is not below r (%d)'s", __func__, ++ r.pid); ++ return -1; ++ } ++ + /* Check access rights to the cgroup directory */ + if (!may_access(r.pid, r.uid, r.gid, path, O_RDONLY)) { + nih_error("%s: Pid %d may not access %s\n", __func__, r.pid, path); +@@ -980,7 +1040,7 @@ + int list_children_main(void *parent, const char *controller, const char *cgroup, + struct ucred p, struct ucred r, char ***output) + { +- char path[MAXPATHLEN]; ++ char pcgpath[MAXPATHLEN], path[MAXPATHLEN]; + + *output = NULL; + if (!sane_cgroup(cgroup)) { +@@ -988,12 +1048,27 @@ + 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) { ++ nih_error("%s: target cgroup is not below r (%d)'s", __func__, ++ r.pid); ++ return -1; ++ } ++ + /* Check access rights to the cgroup directory */ + if (!may_access(r.pid, r.uid, r.gid, path, O_RDONLY)) { + nih_error("%s: Pid %d may not access %s\n", __func__, r.pid, path); diff -Nru cgmanager-0.32/debian/patches/series cgmanager-0.32/debian/patches/series --- cgmanager-0.32/debian/patches/series 2014-09-18 21:31:58.000000000 +0000 +++ cgmanager-0.32/debian/patches/series 2014-12-16 00:54:12.000000000 +0000 @@ -4,3 +4,4 @@ 0004-cgmanager-remount-sys-fs-cgroup-rw-if-needed.patch 0005-create_main-set-existed-to-1-not-0.patch 0006-create_main-set-existed-1-if-cgroup-existed-for-any-.patch +0001-make-sure-to-check-cgroup-hierarchy.patch