diff -Nru lxcfs-0.7/debian/changelog lxcfs-0.7/debian/changelog --- lxcfs-0.7/debian/changelog 2015-04-20 08:45:30.000000000 -0500 +++ lxcfs-0.7/debian/changelog 2015-11-03 16:11:30.000000000 -0600 @@ -1,3 +1,10 @@ +lxcfs (0.7-0ubuntu4.15.04.1) vivid-security; urgency=medium + + * Fix missing privilege check when moving pids to a new cgroup + (LP: #1512854) + + -- Serge Hallyn Tue, 03 Nov 2015 16:10:54 -0600 + lxcfs (0.7-0ubuntu4) vivid; urgency=medium * Add some more sanity checks (LP: #1413405) diff -Nru lxcfs-0.7/debian/patches/0005-Fix-movepid-cve.patch lxcfs-0.7/debian/patches/0005-Fix-movepid-cve.patch --- lxcfs-0.7/debian/patches/0005-Fix-movepid-cve.patch 1969-12-31 18:00:00.000000000 -0600 +++ lxcfs-0.7/debian/patches/0005-Fix-movepid-cve.patch 2015-11-03 16:16:35.000000000 -0600 @@ -0,0 +1,138 @@ +From 81f73961319fe0c7d10cbb09ac507774139c8442 Mon Sep 17 00:00:00 2001 +From: Serge Hallyn +Date: Tue, 3 Nov 2015 14:20:56 -0600 +Subject: Implement privilege check when moving tasks + +When writing pids to a tasks file in lxcfs, lxcfs was checking +for privilege over the tasks file but not over the pid being +moved. Since the cgm_movepid request is done as root on the host, +not with the requestor's credentials, we must copy the check which +cgmanager was doing to ensure that the requesting task is allowed +to change the victim task's cgroup membership. + +Signed-off-by: Serge Hallyn +--- + lxcfs.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 97 insertions(+), 2 deletions(-) + +Index: lxcfs-0.7/lxcfs.c +=================================================================== +--- lxcfs-0.7.orig/lxcfs.c ++++ lxcfs-0.7/lxcfs.c +@@ -1163,7 +1163,95 @@ again: + goto loop; + } + +-static bool do_write_pids(pid_t tpid, const char *contrl, const char *cg, const char *file, const char *buf) ++/* ++ * Given host @uid, return the uid to which it maps in ++ * @pid's user namespace, or -1 if none. ++ */ ++bool hostuid_to_ns(uid_t uid, pid_t pid, uid_t *answer) ++{ ++ FILE *f; ++ char line[400]; ++ ++ sprintf(line, "/proc/%d/uid_map", pid); ++ if ((f = fopen(line, "r")) == NULL) { ++ return false; ++ } ++ ++ *answer = convert_id_to_ns(f, uid); ++ fclose(f); ++ ++ if (*answer == -1) ++ return false; ++ return true; ++} ++ ++/* ++ * get_pid_creds: get the real uid and gid of @pid from ++ * /proc/$$/status ++ * (XXX should we use euid here?) ++ */ ++void get_pid_creds(pid_t pid, uid_t *uid, gid_t *gid) ++{ ++ char line[400]; ++ uid_t u; ++ gid_t g; ++ FILE *f; ++ ++ *uid = -1; ++ *gid = -1; ++ sprintf(line, "/proc/%d/status", pid); ++ if ((f = fopen(line, "r")) == NULL) { ++ fprintf(stderr, "Error opening %s: %s\n", line, strerror(errno)); ++ return; ++ } ++ while (fgets(line, 400, f)) { ++ if (strncmp(line, "Uid:", 4) == 0) { ++ if (sscanf(line+4, "%u", &u) != 1) { ++ fprintf(stderr, "bad uid line for pid %u\n", pid); ++ fclose(f); ++ return; ++ } ++ *uid = u; ++ } else if (strncmp(line, "Gid:", 4) == 0) { ++ if (sscanf(line+4, "%u", &g) != 1) { ++ fprintf(stderr, "bad gid line for pid %u\n", pid); ++ fclose(f); ++ return; ++ } ++ *gid = g; ++ } ++ } ++ fclose(f); ++} ++ ++/* ++ * May the requestor @r move victim @v to a new cgroup? ++ * This is allowed if ++ * . they are the same task ++ * . they are ownedy by the same uid ++ * . @r is root on the host, or ++ * . @v's uid is mapped into @r's where @r is root. ++ */ ++bool may_move_pid(pid_t r, uid_t r_uid, pid_t v) ++{ ++ uid_t v_uid, tmpuid; ++ gid_t v_gid; ++ ++ if (r == v) ++ return true; ++ if (r_uid == 0) ++ return true; ++ get_pid_creds(v, &v_uid, &v_gid); ++ if (r_uid == v_uid) ++ return true; ++ if (hostuid_to_ns(r_uid, r, &tmpuid) && tmpuid == 0 ++ && hostuid_to_ns(v_uid, r, &tmpuid)) ++ return true; ++ return false; ++} ++ ++static bool do_write_pids(pid_t tpid, uid_t tuid, const char *contrl, const char *cg, ++ const char *file, const char *buf) + { + int sock[2] = {-1, -1}; + pid_t qpid, cpid = -1; +@@ -1198,6 +1286,10 @@ static bool do_write_pids(pid_t tpid, co + + if (recv_creds(sock[0], &cred, &v)) { + if (v == '0') { ++ if (!may_move_pid(tpid, tuid, cred.pid)) { ++ fail = true; ++ break; ++ } + if (!cgm_move_pid(contrl, cg, cred.pid)) + fail = true; + } +@@ -1274,7 +1366,7 @@ int cg_write(const char *path, const cha + strcmp(path2, "/cgroup.procs") == 0 || + strcmp(path2, "cgroup.procs") == 0) + // special case - we have to translate the pids +- r = do_write_pids(fc->pid, controller, path1, path2, localbuf); ++ r = do_write_pids(fc->pid, fc->uid, controller, path1, path2, localbuf); + else + r = cgm_set_value(controller, path1, path2, localbuf); + diff -Nru lxcfs-0.7/debian/patches/series lxcfs-0.7/debian/patches/series --- lxcfs-0.7/debian/patches/series 2015-04-20 08:47:37.000000000 -0500 +++ lxcfs-0.7/debian/patches/series 2015-11-03 16:12:02.000000000 -0600 @@ -2,3 +2,4 @@ 0002-Make-sure-that-that-cgroup-and-the-controller-are-se.patch 0003-free-d-at-program-end.patch 0004-Add-some-more-sanity-checks.patch +0005-Fix-movepid-cve.patch