[lxc-devel] [PATCH 1/1] cgmanager: chown cgroups to the container root

Stéphane Graber stgraber at ubuntu.com
Fri Jan 24 16:41:03 UTC 2014


On Thu, Jan 23, 2014 at 11:56:15PM -0600, Serge Hallyn wrote:
> After this patch, starting an unprivileged container using
> cgmanager gets the cgroup chown to the container root, so
> that it can install the cgmanager (proxy) and make cgroup
> requests.
> 
> (Still desirable and not in this patch is the automatic setup of
> /sys/fs/cgroup/manager/sock, which you can currently do with
> two lxc.mount.entries)
> 
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
> ---
>  src/lxc/cgmanager.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++-
>  src/lxc/cgroup.c    |   8 +++
>  src/lxc/cgroup.h    |   2 +
>  src/lxc/start.c     |   3 +
>  4 files changed, 178 insertions(+), 2 deletions(-)
> 
> diff --git a/src/lxc/cgmanager.c b/src/lxc/cgmanager.c
> index e43e1f7..4f83272 100644
> --- a/src/lxc/cgmanager.c
> +++ b/src/lxc/cgmanager.c
> @@ -75,6 +75,44 @@ static void cgmanager_disconnected(DBusConnection *connection)
>  	}
>  }
>  
> +static int send_creds(int sock, int rpid, int ruid, int rgid)
> +{
> +	struct msghdr msg = { 0 };
> +	struct iovec iov;
> +	struct cmsghdr *cmsg;
> +	struct ucred cred = {
> +		.pid = rpid,
> +		.uid = ruid,
> +		.gid = rgid,
> +	};
> +	char cmsgbuf[CMSG_SPACE(sizeof(cred))];
> +	char buf[1];
> +	buf[0] = 'p';
> +
> +	msg.msg_control = cmsgbuf;
> +	msg.msg_controllen = sizeof(cmsgbuf);
> +
> +	cmsg = CMSG_FIRSTHDR(&msg);
> +	cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
> +	cmsg->cmsg_level = SOL_SOCKET;
> +	cmsg->cmsg_type = SCM_CREDENTIALS;
> +	memcpy(CMSG_DATA(cmsg), &cred, sizeof(cred));
> +
> +	msg.msg_name = NULL;
> +	msg.msg_namelen = 0;
> +
> +	iov.iov_base = buf;
> +	iov.iov_len = sizeof(buf);
> +	msg.msg_iov = &iov;
> +	msg.msg_iovlen = 1;
> +
> +	if (sendmsg(sock, &msg, 0) < 0) {
> +		perror("sendmsg");
> +		return -1;
> +	}
> +	return 0;
> +}
> +
>  #define CGMANAGER_DBUS_SOCK "unix:path=/sys/fs/cgroup/cgmanager/sock"
>  bool lxc_init_cgmanager(void)
>  {
> @@ -120,10 +158,121 @@ static bool lxc_cgmanager_create(const char *controller, const char *cgroup_path
>  		return false;
>  	}
>  
> -	// TODO - try to chown the cgroup to the container root
>  	return true;
>  }
>  
> +struct chown_data {
> +	const char *controller;
> +	const char *cgroup_path;
> +};
> +
> +static int do_chown_cgroup(const char *controller, const char *cgroup_path)
> +{
> +	int sv[2] = {-1, -1}, optval = 1;
> +	char buf[1];
> +
> +	if (setgid(0) < 0)
> +		WARN("Failed to setgid to 0");
> +	if (setuid(0) < 0)
> +		WARN("Failed to setuid to 0");
> +
> +	if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sv) < 0) {
> +		SYSERROR("Error creating socketpair");
> +		exit(1);
> +	}
> +	if (setsockopt(sv[1], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
> +		SYSERROR("setsockopt failed");
> +		exit(1);
> +	}
> +	if (setsockopt(sv[0], SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) {
> +		SYSERROR("setsockopt failed");
> +		exit(1);
> +	}

Shouldn't those "exit(1)" be "return -1" instead?

> +	if ( cgmanager_chown_scm_sync(NULL, cgroup_manager, controller,
> +				       cgroup_path, sv[1]) != 0) {
> +		ERROR("call to cgmanager_chown_scm_sync failed");
> + 		return -1;
> + 	}
> +	/* now send credentials */
> +
> +	fd_set rfds;
> +	FD_ZERO(&rfds);
> +	FD_SET(sv[0], &rfds);
> +	if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) {
> +		ERROR("Error getting go-ahead from server: %s", strerror(errno));
> +		return -1;
> +	}
> +	if (read(sv[0], &buf, 1) != 1) {
> +		ERROR("Error getting reply from server over socketpair");
> +		return -1;
> +	}
> +	if (send_creds(sv[0], getpid(), getuid(), getgid())) {
> +		ERROR("Error sending pid over SCM_CREDENTIAL");
> +		return -1;
> +	}
> +	FD_ZERO(&rfds);
> +	FD_SET(sv[0], &rfds);
> +	if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) {
> +		ERROR("Error getting go-ahead from server: %s", strerror(errno));
> +		return -1;
> +	}
> +	if (read(sv[0], &buf, 1) != 1) {
> +		ERROR("Error getting reply from server over socketpair");
> +		return -1;
> +	}
> +	if (send_creds(sv[0], getpid(), 0, 0)) {
> +		ERROR("Error sending pid over SCM_CREDENTIAL");
> +		return -1;
> +	}
> +	FD_ZERO(&rfds);
> +	FD_SET(sv[0], &rfds);
> +	if (select(sv[0]+1, &rfds, NULL, NULL, NULL) < 0) {
> +		ERROR("Error getting go-ahead from server: %s", strerror(errno));
> +		return -1;
> +	}
> +	int ret = read(sv[0], buf, 1);
> +	close(sv[0]);
> +	close(sv[1]);
> +	if (ret == 1 && *buf == '1')
> +		return 0;
> +	return -1;
> +}
> +
> +static int chown_cgroup_wrapper(void *data)
> +{
> +	struct chown_data *arg = data;
> +	return do_chown_cgroup(arg->controller, arg->cgroup_path);
> +}
> +
> +static bool chown_cgroup(const char *controller, const char *cgroup_path,
> +			struct lxc_conf *conf)
> +{
> +	pid_t pid;
> +	struct chown_data data;
> +	data.controller = controller;
> +	data.cgroup_path = cgroup_path;
> +
> +	if (lxc_list_empty(&conf->id_map)) {
> +		if (do_chown_cgroup(controller, cgroup_path) < 0)
> +			return false;
> +		return true;
> +	}
> +
> +	if ((pid = fork()) < 0) {
> +		SYSERROR("fork");
> +		return false;
> +	}
> +	if (pid > 0) {
> +		if (wait_for_pid(pid)) {
> +			ERROR("Error chowning cgroup");
> +			return false;
> +		}
> +		return true;
> +	}
> +	if (userns_exec_1(conf, chown_cgroup_wrapper, &data) < 0)
> +		exit(1);
> +	exit(0);
> +}
>  
>  struct cgm_data {
>  	int nr_subsystems;
> @@ -432,6 +581,19 @@ static bool cgm_setup_limits(struct lxc_handler *handler, bool with_devices)
>  	return setup_limits(handler, with_devices);
>  }
>  
> +static bool cgm_chown(struct lxc_handler *handler)
> +{
> +	struct cgm_data *d = handler->cgroup_info->data;
> +	int i;
> +
> +	for (i = 0; i < d->nr_subsystems; i++) {
> +		if (!chown_cgroup(d->subsystems[i], d->cgroup_path, handler->conf))
> +			WARN("Failed to chown %s:%s to container root",
> +				d->subsystems[i], d->cgroup_path);
> +	}
> +	return true;
> +}
> +
>  static struct cgroup_ops cgmanager_ops = {
>  	.destroy = cgm_destroy,
>  	.init = cgm_init,
> @@ -443,6 +605,7 @@ static struct cgroup_ops cgmanager_ops = {
>  	.set = cgm_set,
>  	.unfreeze_fromhandler = cgm_unfreeze_fromhandler,
>  	.setup_limits = cgm_setup_limits,
> -	.name = "cgmanager"
> +	.name = "cgmanager",
> +	.chown = cgm_chown,
>  };
>  #endif
> diff --git a/src/lxc/cgroup.c b/src/lxc/cgroup.c
> index 4482b32..ce1096d 100644
> --- a/src/lxc/cgroup.c
> +++ b/src/lxc/cgroup.c
> @@ -2199,6 +2199,7 @@ static struct cgroup_ops cgfs_ops = {
>  	.unfreeze_fromhandler = cgfs_unfreeze_fromhandler,
>  	.setup_limits = cgroupfs_setup_limits,
>  	.name = "cgroupfs",
> +	.chown = NULL,
>  };
>  static void init_cg_ops(void)
>  {
> @@ -2297,3 +2298,10 @@ bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices)
>  {
>  	return active_cg_ops->setup_limits(handler, with_devices);
>  }
> +
> +bool cgroup_chown(struct lxc_handler *handler)
> +{
> +	if (active_cg_ops->chown)
> +		return active_cg_ops->chown(handler);
> +	return true;
> +}
> diff --git a/src/lxc/cgroup.h b/src/lxc/cgroup.h
> index af5a5c8..fbb3b87 100644
> --- a/src/lxc/cgroup.h
> +++ b/src/lxc/cgroup.h
> @@ -180,6 +180,7 @@ struct cgroup_ops {
>  	int (*get)(const char *filename, char *value, size_t len, const char *name, const char *lxcpath);
>  	int (*unfreeze_fromhandler)(struct lxc_handler *handler);
>  	bool (*setup_limits)(struct lxc_handler *handler, bool with_devices);
> +	bool (*chown)(struct lxc_handler *handler);
>  	const char *name;
>  };
>  
> @@ -209,6 +210,7 @@ extern void cgroup_destroy(struct lxc_handler *handler);
>  extern bool cgroup_init(struct lxc_handler *handler);
>  extern bool cgroup_create(struct lxc_handler *handler);
>  extern bool cgroup_setup_limits(struct lxc_handler *handler, bool with_devices);
> +extern bool cgroup_chown(struct lxc_handler *handler);
>  extern bool cgroup_enter(struct lxc_handler *handler);
>  extern void cgroup_cleanup(struct lxc_handler *handler);
>  extern bool cgroup_create_legacy(struct lxc_handler *handler);
> diff --git a/src/lxc/start.c b/src/lxc/start.c
> index 2fcd845..6de7a83 100644
> --- a/src/lxc/start.c
> +++ b/src/lxc/start.c
> @@ -804,6 +804,9 @@ static int lxc_spawn(struct lxc_handler *handler)
>  	if (!cgroup_enter(handler))
>  		goto out_delete_net;
>  
> +	if (!cgroup_chown(handler))
> +		goto out_delete_net;
> +
>  	if (failed_before_rename)
>  		goto out_delete_net;
>  
> -- 
> 1.8.5.3
> 
> _______________________________________________
> lxc-devel mailing list
> lxc-devel at lists.linuxcontainers.org
> http://lists.linuxcontainers.org/listinfo/lxc-devel

-- 
Stéphane Graber
Ubuntu developer
http://www.ubuntu.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20140124/cd6aa5d9/attachment.pgp>


More information about the lxc-devel mailing list