[lxc-devel] [PATCH] add_device_node: act in a chroot
Stéphane Graber
stgraber at ubuntu.com
Fri Feb 7 19:21:22 UTC 2014
On Fri, Feb 07, 2014 at 01:00:50PM -0600, Serge Hallyn wrote:
> The goal is to avoid an absolute symlink in the guest redirecting
> us to the host's /dev. Thanks to the libvirt team for considering
> that possibility!
>
> We want to work on kernels which do not support setns, so we simply
> chroot into the container before doing any rm/mknod. If /dev/vda5
> is a symlink to /XXX, or /dev is a symlink to /etc, this is now
> correctly resolved locally in the chroot.
>
> We would have preferred to use realpath() to check that the resolved
> path is not changed, but realpath across /proc/pid/root does not
> work as expected.
>
> Signed-off-by: Serge Hallyn <serge.hallyn at ubuntu.com>
Acked-by: Stéphane Graber <stgraber at ubuntu.com>
> ---
> src/lxc/lxccontainer.c | 110 +++++++++++++++++++++++++++++--------------------
> 1 file changed, 65 insertions(+), 45 deletions(-)
>
> diff --git a/src/lxc/lxccontainer.c b/src/lxc/lxccontainer.c
> index 90f089c..ac92bf1 100644
> --- a/src/lxc/lxccontainer.c
> +++ b/src/lxc/lxccontainer.c
> @@ -3084,34 +3084,80 @@ static bool lxcapi_may_control(struct lxc_container *c)
> return lxc_try_cmd(c->name, c->config_path) == 0;
> }
>
> +static bool do_add_remove_node(pid_t init_pid, const char *path, bool add,
> + struct stat *st)
> +{
> + char chrootpath[MAXPATHLEN];
> + char *directory_path = NULL;
> + pid_t pid;
> + int ret;
> +
> + if ((pid = fork()) < 0) {
> + SYSERROR("failed to fork a child helper");
> + return false;
> + }
> + if (pid) {
> + if (wait_for_pid(pid) != 0) {
> + ERROR("Failed to create note in guest");
> + return false;
> + }
> + return true;
> + }
> +
> + /* prepare the path */
> + ret = snprintf(chrootpath, MAXPATHLEN, "/proc/%d/root", init_pid);
> + if (ret < 0 || ret >= MAXPATHLEN)
> + return false;
> +
> + if (chdir(chrootpath) < 0)
> + exit(1);
> + if (chroot(".") < 0)
> + exit(1);
> + /* remove path if it exists */
> + if(faccessat(AT_FDCWD, path, F_OK, AT_SYMLINK_NOFOLLOW) == 0) {
> + if (unlink(path) < 0) {
> + ERROR("unlink failed");
> + exit(1);
> + }
> + }
> + if (!add)
> + exit(0);
> +
> + /* create any missing directories */
> + directory_path = dirname(strdup(path));
> + if (mkdir_p(directory_path, 0755) < 0 && errno != EEXIST) {
> + ERROR("failed to create directory");
> + exit(1);
> + }
> +
> + /* create the device node */
> + if (mknod(path, st->st_mode, st->st_rdev) < 0) {
> + ERROR("mknod failed");
> + exit(1);
> + }
> +
> + exit(0);
> +}
> +
> static bool add_remove_device_node(struct lxc_container *c, const char *src_path, const char *dest_path, bool add)
> {
> int ret;
> struct stat st;
> - char path[MAXPATHLEN];
> char value[MAX_BUFFER];
> - char *directory_path = NULL;
> const char *p;
>
> /* make sure container is running */
> if (!c->is_running(c)) {
> ERROR("container is not running");
> - goto out;
> + return false;
> }
>
> /* use src_path if dest_path is NULL otherwise use dest_path */
> p = dest_path ? dest_path : src_path;
>
> - /* prepare the path */
> - ret = snprintf(path, MAXPATHLEN, "/proc/%d/root/%s", c->init_pid(c), p);
> - if (ret < 0 || ret >= MAXPATHLEN)
> - goto out;
> - remove_trailing_slashes(path);
> -
> - p = add ? src_path : path;
> /* make sure we can access p */
> if(access(p, F_OK) < 0 || stat(p, &st) < 0)
> - goto out;
> + return false;
>
> /* continue if path is character device or block device */
> if (S_ISCHR(st.st_mode))
> @@ -3119,55 +3165,29 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
> else if (S_ISBLK(st.st_mode))
> ret = snprintf(value, MAX_BUFFER, "b %d:%d rwm", major(st.st_rdev), minor(st.st_rdev));
> else
> - goto out;
> + return false;
>
> /* check snprintf return code */
> if (ret < 0 || ret >= MAX_BUFFER)
> - goto out;
> + return false;
>
> - directory_path = dirname(strdup(path));
> - /* remove path and directory_path (if empty) */
> - if(access(path, F_OK) == 0) {
> - if (unlink(path) < 0) {
> - ERROR("unlink failed");
> - goto out;
> - }
> - if (rmdir(directory_path) < 0 && errno != ENOTEMPTY) {
> - ERROR("rmdir failed");
> - goto out;
> - }
> - }
> + if (!do_add_remove_node(c->init_pid(c), p, add, &st))
> + return false;
>
> + /* add or remove device to/from cgroup access list */
> if (add) {
> - /* create the missing directories */
> - if (mkdir_p(directory_path, 0755) < 0) {
> - ERROR("failed to create directory");
> - goto out;
> - }
> -
> - /* create the device node */
> - if (mknod(path, st.st_mode, st.st_rdev) < 0) {
> - ERROR("mknod failed");
> - goto out;
> - }
> -
> - /* add device node to device list */
> if (!c->set_cgroup_item(c, "devices.allow", value)) {
> ERROR("set_cgroup_item failed while adding the device node");
> - goto out;
> + return false;
> }
> } else {
> - /* remove device node from device list */
> if (!c->set_cgroup_item(c, "devices.deny", value)) {
> ERROR("set_cgroup_item failed while removing the device node");
> - goto out;
> + return false;
> }
> }
> +
> return true;
> -out:
> - if (directory_path)
> - free(directory_path);
> - return false;
> }
>
> static bool lxcapi_add_device_node(struct lxc_container *c, const char *src_path, const char *dest_path)
> --
> 1.8.3.2
>
> _______________________________________________
> 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: 819 bytes
Desc: Digital signature
URL: <http://lists.linuxcontainers.org/pipermail/lxc-devel/attachments/20140207/6ccafa92/attachment.pgp>
More information about the lxc-devel
mailing list