[lxc-devel] [lxcfs/master] pam: cgroup v2 fixes

brauner on Github lxc-bot at linuxcontainers.org
Thu Nov 2 14:25:08 UTC 2017


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 693 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20171102/86670aa2/attachment.bin>
-------------- next part --------------
From 52123c231b81ded4a6d2767d0e41c95a6b5a99ea Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 2 Nov 2017 13:26:36 +0100
Subject: [PATCH 1/3] bindings: record mount namespace

This will allows us to attach to the mount namespace in case we need to debug or
perform some action on update.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 bindings.c | 37 ++++++++++++++++++++++++-------------
 1 file changed, 24 insertions(+), 13 deletions(-)

diff --git a/bindings.c b/bindings.c
index fe521a3..33d349c 100644
--- a/bindings.c
+++ b/bindings.c
@@ -139,6 +139,7 @@ static char **hierarchies;
  * another namespace using the *at() family of functions
  * {openat(), fchownat(), ...}. */
 static int *fd_hierarchies;
+static int cgroup_mount_ns_fd = -1;
 
 static void unlock_mutex(pthread_mutex_t *l)
 {
@@ -421,6 +422,7 @@ static void print_subsystems(void)
 {
 	int i;
 
+	fprintf(stderr, "mount namespace: %d\n", cgroup_mount_ns_fd);
 	fprintf(stderr, "hierarchies:\n");
 	for (i = 0; i < num_hierarchies; i++) {
 		if (hierarchies[i])
@@ -4477,6 +4479,19 @@ static bool permute_root(void)
 	return true;
 }
 
+static int preserve_ns(int pid)
+{
+	int ret;
+	size_t len = 5 /* /proc */ + 21 /* /int_as_str */ + 7 /* /ns/mnt */ + 1 /* \0 */;
+	char path[len];
+
+	ret = snprintf(path, len, "/proc/%d/ns/mnt", pid);
+	if (ret < 0 || (size_t)ret >= len)
+		return -1;
+
+	return open(path, O_RDONLY | O_CLOEXEC);
+}
+
 static bool cgfs_prepare_mounts(void)
 {
 	if (!mkdir_p(BASEDIR, 0700)) {
@@ -4494,6 +4509,12 @@ static bool cgfs_prepare_mounts(void)
 		return false;
 	}
 
+	cgroup_mount_ns_fd = preserve_ns(getpid());
+	if (cgroup_mount_ns_fd < 0) {
+		lxcfs_error("Failed to preserve mount namespace: %s.\n", strerror(errno));
+		return false;
+	}
+
 	if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, 0) < 0) {
 		lxcfs_error("Failed to remount / private: %s.\n", strerror(errno));
 		return false;
@@ -4567,19 +4588,6 @@ static bool cgfs_setup_controllers(void)
 	return true;
 }
 
-static int preserve_ns(int pid)
-{
-	int ret;
-	size_t len = 5 /* /proc */ + 21 /* /int_as_str */ + 7 /* /ns/mnt */ + 1 /* \0 */;
-	char path[len];
-
-	ret = snprintf(path, len, "/proc/%d/ns/mnt", pid);
-	if (ret < 0 || (size_t)ret >= len)
-		return -1;
-
-	return open(path, O_RDONLY | O_CLOEXEC);
-}
-
 static void __attribute__((constructor)) collect_and_mount_subsystems(void)
 {
 	FILE *f;
@@ -4680,4 +4688,7 @@ static void __attribute__((destructor)) free_subsystems(void)
 	}
 	free(hierarchies);
 	free(fd_hierarchies);
+
+	if (cgroup_mount_ns_fd >= 0)
+		close(cgroup_mount_ns_fd);
 }

From 569b4b093f4df00a989b006c74b74a02d4f2e0ea Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 2 Nov 2017 13:30:03 +0100
Subject: [PATCH 2/3] bindings: remove unused function

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 bindings.c | 18 ------------------
 1 file changed, 18 deletions(-)

diff --git a/bindings.c b/bindings.c
index 33d349c..a8f302b 100644
--- a/bindings.c
+++ b/bindings.c
@@ -3593,24 +3593,6 @@ static uint64_t get_reaper_age(pid_t pid)
 	return procage;
 }
 
-static uint64_t get_reaper_btime(pid)
-{
-	int ret;
-	struct sysinfo sys;
-	uint64_t procstart;
-	uint64_t uptime;
-
-	ret = sysinfo(&sys);
-	if (ret < 0) {
-		lxcfs_debug("%s\n", "failed to retrieve system information");
-		return 0;
-	}
-
-	uptime = (uint64_t)time(NULL) - (uint64_t)sys.uptime;
-	procstart = get_reaper_start_time_in_sec(pid);
-	return uptime + procstart;
-}
-
 #define CPUALL_MAX_SIZE (BUF_RESERVE_SIZE / 2)
 static int proc_stat_read(char *buf, size_t size, off_t offset,
 		struct fuse_file_info *fi)

From c4f53b5f24a77b7231dacc3047f49d8f60ac9c30 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner at ubuntu.com>
Date: Thu, 2 Nov 2017 13:30:13 +0100
Subject: [PATCH 3/3] pam: adapt to changed cgroup v2 layout

In order to enable proper unprivileged cgroup delegation on newer kernels we not
just need delegate the "cgroup.procs" file to the user but also to
"cgroup.threads". But don't report an error in case it doesn't exist.
Also delegate "cgroup.subtree_control" to enable users to hand over controllers
to descendant cgroups.

Signed-off-by: Christian Brauner <christian.brauner at ubuntu.com>
---
 pam/pam_cgfs.c | 36 ++++++++++++++++++++++++++++++++----
 1 file changed, 32 insertions(+), 4 deletions(-)

diff --git a/pam/pam_cgfs.c b/pam/pam_cgfs.c
index ecd0618..1880352 100644
--- a/pam/pam_cgfs.c
+++ b/pam/pam_cgfs.c
@@ -2267,6 +2267,7 @@ static bool cgv1_create(const char *cgroup, uid_t uid, gid_t gid, bool *existed)
  */
 static bool cgv2_create(const char *cgroup, uid_t uid, gid_t gid, bool *existed)
 {
+	int ret;
 	char *clean_base_cgroup;
 	char *path;
 	struct cgv2_hierarchy *v2;
@@ -2284,7 +2285,7 @@ static bool cgv2_create(const char *cgroup, uid_t uid, gid_t gid, bool *existed)
 	 */
 	if (cg_systemd_chown_existing_cgroup(v2->mountpoint, v2->base_cgroup,
 					     uid, gid, v2->systemd_user_slice))
-		goto chown_cgroup_procs_file;
+		goto delegate_files;
 
 	/* We need to make sure that we do not create an endless chain of
 	 * sub-cgroups. So we check if we have already logged in somehow (sudo
@@ -2310,7 +2311,7 @@ static bool cgv2_create(const char *cgroup, uid_t uid, gid_t gid, bool *existed)
 		free(path);
 		if (our_cg) {
 			*existed = false;
-			goto chown_cgroup_procs_file;
+			goto delegate_files;
 		} else {
 			*existed = true;
 			return false;
@@ -2331,7 +2332,7 @@ static bool cgv2_create(const char *cgroup, uid_t uid, gid_t gid, bool *existed)
 		lxcfs_debug("Chowned %s to %d:%d.\n", path, (int)uid, (int)gid);
 	free(path);
 
-chown_cgroup_procs_file:
+delegate_files:
 	/* chown cgroup.procs to user */
 	if (v2->systemd_user_slice)
 		path = must_make_path(v2->mountpoint, v2->base_cgroup,
@@ -2339,13 +2340,40 @@ static bool cgv2_create(const char *cgroup, uid_t uid, gid_t gid, bool *existed)
 	else
 		path = must_make_path(v2->mountpoint, v2->base_cgroup, cgroup,
 				      "/cgroup.procs", NULL);
-	if (chown(path, uid, gid) < 0)
+	ret = chown(path, uid, gid);
+	if (ret < 0)
 		mysyslog(LOG_WARNING, "Failed to chown %s to %d:%d: %s.\n",
 			 path, (int)uid, (int)gid, strerror(errno), NULL);
 	else
 		lxcfs_debug("Chowned %s to %d:%d.\n", path, (int)uid, (int)gid);
 	free(path);
 
+	/* chown cgroup.subtree_control to user */
+	if (v2->systemd_user_slice)
+		path = must_make_path(v2->mountpoint, v2->base_cgroup,
+				      "/cgroup.subtree_control", NULL);
+	else
+		path = must_make_path(v2->mountpoint, v2->base_cgroup, cgroup,
+				      "/cgroup.subtree_control", NULL);
+	ret = chown(path, uid, gid);
+	if (ret < 0)
+		mysyslog(LOG_WARNING, "Failed to chown %s to %d:%d: %s.\n",
+			 path, (int)uid, (int)gid, strerror(errno), NULL);
+	free(path);
+
+	/* chown cgroup.threads to user */
+	if (v2->systemd_user_slice)
+		path = must_make_path(v2->mountpoint, v2->base_cgroup,
+				      "/cgroup.threads", NULL);
+	else
+		path = must_make_path(v2->mountpoint, v2->base_cgroup, cgroup,
+				      "/cgroup.threads", NULL);
+	ret = chown(path, uid, gid);
+	if (ret < 0 && errno != ENOENT)
+		mysyslog(LOG_WARNING, "Failed to chown %s to %d:%d: %s.\n",
+			 path, (int)uid, (int)gid, strerror(errno), NULL);
+	free(path);
+
 	return true;
 }
 


More information about the lxc-devel mailing list