[lxc-devel] [lxcfs/master] pam_cgfs: create a new systemd cgroup if current isn't ours
hallyn on Github
lxc-bot at linuxcontainers.org
Mon Mar 14 20:58:11 UTC 2016
A non-text attachment was scrubbed...
Name: not available
Type: text/x-mailbox
Size: 599 bytes
Desc: not available
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20160314/187a4a0a/attachment.bin>
-------------- next part --------------
From 44e6d94d2cf678c0bd69b8246b1c3e00bbc1afbe Mon Sep 17 00:00:00 2001
From: Serge Hallyn <serge.hallyn at ubuntu.com>
Date: Mon, 14 Mar 2016 12:19:27 -0700
Subject: [PATCH] pam_cgfs: create a new systemd cgroup if current isn't ours
If current systemd cgroup does not end in user-$uid.slice/session-c%d.scope,
then pam did not create our current systemd cgroup for us, so create a new
one rather than chowning the current one.
This happens with noninteractive sessions.
Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
---
pam/pam_cgfs.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 67 insertions(+), 10 deletions(-)
diff --git a/pam/pam_cgfs.c b/pam/pam_cgfs.c
index ef2d576..cfda38d 100644
--- a/pam/pam_cgfs.c
+++ b/pam/pam_cgfs.c
@@ -10,11 +10,11 @@
* 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.
+ * name=systemd is handled specially. If the host is an upstart system
+ * or the login is noninteractive, then the logged in user does not get
+ * a cgroup created. On a systemd interactive login, 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.
@@ -139,7 +139,7 @@ static bool mkdir_p(const char *root, char *path)
*e = orig;
b = e + 1;
}
-
+
}
struct controller {
@@ -201,7 +201,7 @@ static void get_mounted_paths(void)
static void add_controller(int id, char *tok, char *cur_path)
{
struct controller *c;
-
+
do {
c = malloc(sizeof(struct controller));
} while (!c);
@@ -417,10 +417,59 @@ static bool get_active_controllers(void)
}
/*
+ * the systemd-created path is: user-$uid.slice/session-c$session.scope
+ * If that is not the end of our systemd path, then we're not part of
+ * the PAM call that created that path.
+ *
+ * The last piece is chowned to $uid, the user- part not.
+ * Note - if the user creates paths that look like what we're looking for
+ * to 'fool' us, either
+ * . they fool us, we create new cgroups, and they get auto-logged-out.
+ * . they fool a root sudo, systemd cgroup is not changed but chowned,
+ * and they lose ownership of their cgroups
+ */
+static bool systemd_created_slice_for_us(struct controller *c, const char *in, uid_t uid)
+{
+ char *p, *copy = strdupa(in);
+ size_t len;
+ int id;
+
+ if (!copy || strlen(copy) < 28)
+ return false;
+ p = copy + strlen(copy) - 1;
+ /* skip any trailing '/' (shouldn't be any, but be sure) */
+ while (p >= copy && *p == '/')
+ *(p--) = '\0';
+ if (p < copy)
+ return false;
+
+ /* Get last path element */
+ while (p >= copy && *p != '/')
+ p--;
+ if (p < copy)
+ return false;
+ /* make sure it is session-something.scope */
+ len = strlen(p+1);
+ if (strncmp(p+1, "session-", strlen("session-")) != 0 ||
+ strncmp(p+1 + len - 6, ".scope", 6) != 0)
+ return false;
+
+ /* ok last path piece checks out, now check the second to last */
+ *(p+1) = '\0';
+ while (p >= copy && *(--p) != '/');
+ if (sscanf(p+1, "user-%d.slice/", &id) != 1)
+ return false;
+
+ if (id != (int)uid)
+ return false;
+
+ 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)
+static bool handle_systemd_create(struct controller *c, uid_t uid, gid_t gid)
{
char *user_path;
@@ -429,6 +478,14 @@ static bool handle_systemd_create(const struct controller *c, uid_t uid, gid_t g
user_path = must_strcat(c->mount_path, c->cur_path, NULL);
+ // Is this actually our cgroup, or was it created for someone
+ // else?
+ if (!systemd_created_slice_for_us(c, user_path, uid)) {
+ c->systemd_created = false;
+ free(user_path);
+ return false;
+ }
+
// 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",
@@ -437,7 +494,7 @@ static bool handle_systemd_create(const struct controller *c, uid_t uid, gid_t g
return true;
}
-static bool cgfs_create_forone(const struct controller *c, uid_t uid, gid_t gid, const char *cg, bool *existed)
+static bool cgfs_create_forone(struct controller *c, uid_t uid, gid_t gid, const char *cg, bool *existed)
{
while (c) {
if (!c->mount_path || !c->init_path)
@@ -650,7 +707,7 @@ static int handle_login(const char *user)
uid_t uid = 0;
gid_t gid = 0;
char cg[MAXPATHLEN];
-
+
if (!get_uid_gid(user, &uid, &gid)) {
mysyslog(LOG_ERR, "Failed to get uid and gid for %s\n", user);
return PAM_SESSION_ERR;
More information about the lxc-devel
mailing list