[lxc-devel] [lxcfs/master] pam_cgfs: change handling of name=systemd

hallyn on Github lxc-bot at linuxcontainers.org
Tue Feb 9 08:16:18 UTC 2016


A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 857 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160209/c427f6b3/attachment.bin>
-------------- next part --------------
From edd25678d5701cda14c36a511c4d01c53ebd9fd4 Mon Sep 17 00:00:00 2001
From: Serge Hallyn <serge.hallyn at ubuntu.com>
Date: Mon, 8 Feb 2016 21:58:11 -0800
Subject: [PATCH] pam_cgfs: change handling of name=systemd

Don't always ignore it.

Do ignore it (like all others) if not listed in the -c argument.

If the logged in task's name=systemd cgroup != that of the init
task's, assume we are in systemd and rename the user's.

If they are the same, assume we are in upstart or sysvinit and
create=chown a name=systemd cgroup just as for the others.

This should fix

https://bugs.launchpad.net/ubuntu/+source/lxcfs/+bug/1543353

and allow the ubuntu systemd package to drop its cgroup related
delta.

Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
 pam/pam_cgfs.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 69 insertions(+), 16 deletions(-)

diff --git a/pam/pam_cgfs.c b/pam/pam_cgfs.c
index 070aaf3..14581cb 100644
--- a/pam/pam_cgfs.c
+++ b/pam/pam_cgfs.c
@@ -3,14 +3,19 @@
  * Copyright © 2016 Canonical, Inc
  * Author: Serge Hallyn <serge.hallyn at ubuntu.com>
  *
- * When a user logs in, this pam module will create cgroups which
- * the user may administer, for all controllers except name=systemd,
- * or for any controllers listed on the command line (if any are
- * listed).
+ * When a user logs in, this pam module will create cgroups which the user
+ * may administer, either for all controllers or for any controllers listed
+ * on the command line (if any are listed).
  *
  * The cgroup created will be "user/$user/0" for the first session,
  * "user/$user/1" for the second, etc.
  *
+ * name=systemd is handled specially.  If the host is an upstart system,
+ * the logged in user may not get a cgroup created.  On a systemd system,
+ * one is created but not chowned to the user.  In the former case, we
+ * create one as usual, in the latter case we simply chown whatever cgroup
+ * the user is in.
+ *
  * All requested cgroups must be mounted under /sys/fs/cgroup/$controller,
  * no messing around with finding mountpoints.
  *
@@ -140,9 +145,11 @@ static bool mkdir_p(const char *root, char *path)
 struct controller {
 	struct controller *next;
 	int id;
+	bool systemd_created;
 	char *name;
 	char *mount_path;
 	char *init_path;
+	char *cur_path;
 };
 
 #define MAXCONTROLLERS 20
@@ -159,6 +166,12 @@ static char *find_controller_path(struct controller *c)
 		if (exists(path))
 			return path;
 		free(path);
+		if (strncmp(c->name, "name=", 5) == 0) {
+			path = must_strcat("/sys/fs/cgroup/", c->name + 5, NULL);
+			if (exists(path))
+				return path;
+			free(path);
+		}
 		c = c->next;
 	}
 	return NULL;
@@ -185,7 +198,7 @@ static void get_mounted_paths(void)
 	}
 }
 
-static void add_controller(int id, char *tok)
+static void add_controller(int id, char *tok, char *cur_path)
 {
 	struct controller *c;
 	
@@ -195,6 +208,9 @@ static void add_controller(int id, char *tok)
 	do {
 		c->name = strdup(tok);
 	} while (!c->name);
+	do {
+		c->cur_path = strdup(cur_path);
+	} while (!c->cur_path);
 	c->id = id;
 	c->next = controllers[id];
 	c->mount_path = NULL;
@@ -213,6 +229,7 @@ static void drop_controller(int which)
 	while (c) {
 		struct controller *tmp = c->next;
 		free(c->name);
+		free(c->cur_path);
 		free(c);
 		c = tmp;
 	}
@@ -309,8 +326,11 @@ static bool fill_in_init_paths(void)
 			goto out;
 		}
 		prune_init_scope(ip);
-		for (c = controllers[id]; c; c = c->next)
+		for (c = controllers[id]; c; c = c->next) {
+			if (strcmp(c->name, "name=systemd") == 0)
+				c->systemd_created = strcmp(ip, c->cur_path) != 0;
 			c->init_path = ip;
+		}
 	}
 	ret = true;
 out:
@@ -335,6 +355,7 @@ static void print_found_controllers(void) {
 			fprintf(stderr, " Next mount: index %d name %s\n", c->id, c->name);
 			fprintf(stderr, "             mount path %s\n", c->mount_path ? c->mount_path : "(none)");
 			fprintf(stderr, "             init task path %s\n", c->init_path);
+			fprintf(stderr, "             login task path %s\n", c->cur_path);
 			c = c->next;
 		}
 	}
@@ -350,7 +371,7 @@ static inline void print_found_controllers(void) { };
 static bool get_active_controllers(void)
 {
 	FILE *f;
-	char *line = NULL, *tok;
+	char *line = NULL, *tok, *cur_path;
 	size_t len = 0;
 
 	f = fopen("/proc/self/cgroup", "r");
@@ -359,7 +380,7 @@ static bool get_active_controllers(void)
 	while (getline(&line, &len, f) != -1) {
 		int id;
 		char *subsystems;
-		if (sscanf(line, "%d:%m[^:]:", &id, &subsystems) != 2) {
+		if (sscanf(line, "%d:%m[^:]:%ms", &id, &subsystems, &cur_path) != 3) {
 			mysyslog(LOG_ERR, "Corrupt /proc/self/cgroup\n");
 			fclose(f);
 			free(line);
@@ -368,16 +389,15 @@ static bool get_active_controllers(void)
 		if (id < 0 || id > 20) {
 			mysyslog(LOG_ERR, "Too many subsystems\n");
 			free(subsystems);
+			free(cur_path);
 			fclose(f);
 			free(line);
 			return false;
 		}
-		if (strcmp(subsystems, "name=systemd") == 0)
-			goto next;
 		for (tok = strtok(subsystems, ","); tok; tok = strtok(NULL, ","))
-			add_controller(id, tok);
-next:
+			add_controller(id, tok, cur_path);
 		free(subsystems);
+		free(cur_path);
 	}
 	fclose(f);
 	free(line);
@@ -396,11 +416,36 @@ static bool get_active_controllers(void)
 	return true;
 }
 
+/*
+ * Handle systemd creation.  Return true if all's done.  Returns false if
+ * the caller needs to create=chown a cgroup
+ */
+static bool handle_systemd_create(const struct controller *c, uid_t uid, gid_t gid)
+{
+	char *user_path;
+
+	if (!c->systemd_created)
+		return false;
+
+	user_path = must_strcat(c->mount_path, c->cur_path, NULL);
+
+	// a name=systemd cgroup has already been created, just chown it
+	if (chown(user_path, uid, gid) < 0)
+		mysyslog(LOG_WARNING, "Failed to chown %s to %d:%d: %m\n",
+				user_path, (int)uid, (int)gid);
+	free(user_path);
+	return true;
+}
+
 static bool cgfs_create_forone(const struct controller *c, uid_t uid, gid_t gid, const char *cg, bool *existed)
 {
 	while (c) {
 		if (!c->mount_path || !c->init_path)
 			goto next;
+
+		if (strcmp(c->name, "name=systemd") == 0 && handle_systemd_create(c, uid, gid))
+			return true;
+
 		char *path = must_strcat(c->mount_path, c->init_path, cg, NULL);
 #if DEBUG
 		fprintf(stderr, "Creating %s for %s\n", path, c->name);
@@ -409,10 +454,11 @@ static bool cgfs_create_forone(const struct controller *c, uid_t uid, gid_t gid,
 			free(path);
 			*existed = true;
 #if DEBUG
-		fprintf(stderr, "%s existed\n", path);
+			fprintf(stderr, "%s existed\n", path);
 #endif
 			return true;
 		}
+
 		bool pass = mkdir_p(c->mount_path, path);
 #if DEBUG
 		fprintf(stderr, "Creating %s %s\n", path, pass ? "succeeded" : "failed");
@@ -551,7 +597,7 @@ static bool do_enter(struct controller *c, const char *cg)
 	return false;
 }
 
-static bool cgfs_enter(const char *cg)
+static bool cgfs_enter(const char *cg, bool skip_systemd)
 {
 	int i;
 
@@ -561,6 +607,13 @@ static bool cgfs_enter(const char *cg)
 		if (!c)
 			continue;
 
+		if (strcmp(c->name, "name=systemd") == 0) {
+			if (skip_systemd)
+				continue;
+			if (c->systemd_created)
+				continue;
+		}
+
 		if (!do_enter(c, cg))
 			return false;
 	}
@@ -570,7 +623,7 @@ static bool cgfs_enter(const char *cg)
 
 static void cgfs_escape(void)
 {
-	if (!cgfs_enter("/")) {
+	if (!cgfs_enter("/", true)) {
 		mysyslog(LOG_WARNING, "Failed to escape to init's cgroup\n");
 	}
 }
@@ -621,7 +674,7 @@ static int handle_login(const char *user)
 			continue;
 		}
 
-		if (!cgfs_enter(cg)) {
+		if (!cgfs_enter(cg, false)) {
 			mysyslog(LOG_ERR, "Failed to enter user cgroup %s for user %s\n", cg, user);
 			return PAM_SESSION_ERR;
 		}


More information about the lxc-devel mailing list