]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
attach: unifiy /proc/<init-pid>/status parsing
authorChristian Brauner <christian.brauner@ubuntu.com>
Mon, 1 Feb 2021 10:37:22 +0000 (11:37 +0100)
committerChristian Brauner <christian.brauner@ubuntu.com>
Mon, 1 Feb 2021 11:29:59 +0000 (12:29 +0100)
and move it out of do_attach(). The less we do in the container's context the
better.

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
src/lxc/attach.c

index 187ff37d39b030a7dd0d3fe940779f3b386be345..869f2c148f4684d7e904169072b02bf557a913fd 100644 (file)
@@ -61,6 +61,8 @@ struct attach_context {
        int init_pid;
        int dfd_init_pid;
        int dfd_self_pid;
+       uid_t init_uid;
+       gid_t init_gid;
        char *lsm_label;
        struct lxc_container *container;
        signed long personality;
@@ -149,6 +151,8 @@ static struct attach_context *alloc_attach_context(void)
 
        ctx->dfd_self_pid = -EBADF;
        ctx->dfd_init_pid = -EBADF;
+       ctx->init_uid = 0;
+       ctx->init_gid = 0;
 
        for (int i = 0; i < LXC_NS_MAX; i++)
                ctx->ns_fd[i] = -EBADF;
@@ -176,17 +180,75 @@ static int get_personality(const char *name, const char *lxcpath,
        return 0;
 }
 
+static int parse_init_status(struct attach_context *ctx, lxc_attach_options_t *options)
+{
+       __do_free char *line = NULL;
+       __do_fclose FILE *f = NULL;
+       size_t len = 0;
+       bool caps_found = false;
+       bool uid_found, gid_found;
+
+       f = fdopenat(ctx->dfd_init_pid, "status", "re");
+       if (!f)
+               return -errno;
+
+       if (options->namespaces & CLONE_NEWUSER)
+               uid_found = gid_found = false;
+       else
+               uid_found = gid_found = true;
+
+       while (getline(&line, &len, f) != -1) {
+               signed long value = -1;
+               int ret;
+
+               if (options->namespaces & CLONE_NEWUSER) {
+                       /*
+                        * Format is: real, effective, saved set user, fs we only care
+                        * about real uid.
+                        */
+                       ret = sscanf(line, "Uid: %ld", &value);
+                       if (ret != EOF && ret == 1) {
+                               uid_found = true;
+                               ctx->init_uid = (uid_t)value;
+                               goto next;
+                       }
+
+                       ret = sscanf(line, "Gid: %ld", &value);
+                       if (ret != EOF && ret == 1) {
+                               gid_found = true;
+                               ctx->init_gid = (gid_t)value;
+                               goto next;
+                       }
+               }
+
+               ret = sscanf(line, "CapBnd: %llx", &ctx->capability_mask);
+               if (ret != EOF && ret == 1) {
+                       caps_found = true;
+                       goto next;
+               }
+
+        next:
+               if (uid_found && gid_found && caps_found)
+                       break;
+
+       }
+
+       /*
+        * TODO: we should also parse supplementary groups and use
+        * setgroups() to set them.
+        */
+
+       return 0;
+}
+
 static int get_attach_context(struct attach_context *ctx,
                              struct lxc_container *container,
                              lxc_attach_options_t *options)
 {
-       __do_close int dfd_self_pid = -EBADF, dfd_init_pid = -EBADF, fd_status = -EBADF, init_pidfd = -EBADF;
-       __do_free char *line = NULL, *lsm_label = NULL;
-       __do_fclose FILE *f_status = NULL;
+       __do_close int init_pidfd = -EBADF;
+       __do_free char *lsm_label = NULL;
        int ret;
-       bool found;
        char path[LXC_PROC_PID_LEN];
-       size_t line_bufsz = 0;
 
        ctx->container = container;
        ctx->attach_flags = options->attach_flags;
@@ -204,20 +266,16 @@ static int get_attach_context(struct attach_context *ctx,
        if (ret < 0 || ret >= sizeof(path))
                return ret_errno(EIO);
 
-       dfd_self_pid = openat(-EBADF, path, O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_PATH | O_DIRECTORY);
-       if (dfd_self_pid < 0)
+       ctx->dfd_self_pid = openat(-EBADF, path, O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_PATH | O_DIRECTORY);
+       if (ctx->dfd_self_pid < 0)
                return -errno;
 
        ret = snprintf(path, sizeof(path), "/proc/%d", ctx->init_pid);
        if (ret < 0 || ret >= sizeof(path))
                return ret_errno(EIO);
 
-       dfd_init_pid = openat(-EBADF, path, O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_PATH | O_DIRECTORY);
-       if (dfd_init_pid < 0)
-               return -errno;
-
-       fd_status = openat(dfd_init_pid, "status", O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_RDONLY);
-       if (fd_status < 0)
+       ctx->dfd_init_pid = openat(-EBADF, path, O_CLOEXEC | O_NOCTTY | O_NOFOLLOW | O_PATH | O_DIRECTORY);
+       if (ctx->dfd_init_pid < 0)
                return -errno;
 
        if (init_pidfd >= 0) {
@@ -228,23 +286,9 @@ static int get_attach_context(struct attach_context *ctx,
                        TRACE("Container process still running and PID was not recycled");
        }
 
-       f_status = fdopen(fd_status, "re");
-       if (!f_status)
-               return log_error_errno(-errno, errno, "Failed to open file descriptor %d", fd_status);
-       move_fd(fd_status);
-
-       found = false;
-
-       while (getline(&line, &line_bufsz, f_status) != -1) {
-               ret = sscanf(line, "CapBnd: %llx", &ctx->capability_mask);
-               if (ret != EOF && ret == 1) {
-                       found = true;
-                       break;
-               }
-       }
-
-       if (!found)
-               return log_error_errno(-ENOENT, ENOENT, "Failed to read capability bounding set from %s/status", path);
+       ret = parse_init_status(ctx, options);
+       if (ret)
+               return log_error_errno(-errno, errno, "Failed to open parse status file");
 
        ctx->lsm_ops = lsm_init_static();
 
@@ -252,7 +296,7 @@ static int get_attach_context(struct attach_context *ctx,
                if (ctx->attach_flags & LXC_ATTACH_LSM_LABEL)
                        lsm_label = options->lsm_label;
                else
-                       lsm_label = ctx->lsm_ops->process_label_get_at(ctx->lsm_ops, dfd_init_pid);
+                       lsm_label = ctx->lsm_ops->process_label_get_at(ctx->lsm_ops, ctx->dfd_init_pid);
                if (!lsm_label)
                        WARN("No security context received");
                else
@@ -270,8 +314,6 @@ static int get_attach_context(struct attach_context *ctx,
                        return log_error_errno(-ENOMEM, ENOMEM, "Failed to allocate new lxc config");
        }
 
-       ctx->dfd_init_pid = move_fd(dfd_init_pid);
-       ctx->dfd_self_pid = move_fd(dfd_self_pid);
        ctx->lsm_label = move_ptr(lsm_label);
        return 0;
 }
@@ -733,54 +775,6 @@ reap_child:
        return move_ptr(result);
 }
 
-static void lxc_attach_get_init_uidgid(uid_t *init_uid, gid_t *init_gid)
-{
-       __do_free char *line = NULL;
-       __do_fclose FILE *proc_file = NULL;
-       char proc_fn[LXC_PROC_STATUS_LEN];
-       int ret;
-       size_t line_bufsz = 0;
-       long value = -1;
-       uid_t uid = LXC_INVALID_UID;
-       gid_t gid = LXC_INVALID_GID;
-
-       ret = snprintf(proc_fn, LXC_PROC_STATUS_LEN, "/proc/%d/status", 1);
-       if (ret < 0 || ret >= LXC_PROC_STATUS_LEN)
-               return;
-
-       proc_file = fopen(proc_fn, "re");
-       if (!proc_file)
-               return;
-
-       while (getline(&line, &line_bufsz, proc_file) != -1) {
-               /* Format is: real, effective, saved set user, fs we only care
-                * about real uid.
-                */
-               ret = sscanf(line, "Uid: %ld", &value);
-               if (ret != EOF && ret == 1) {
-                       uid = (uid_t)value;
-               } else {
-                       ret = sscanf(line, "Gid: %ld", &value);
-                       if (ret != EOF && ret == 1)
-                               gid = (gid_t)value;
-               }
-
-               if (uid != LXC_INVALID_UID && gid != LXC_INVALID_GID)
-                       break;
-       }
-
-       /* Only override arguments if we found something. */
-       if (uid != LXC_INVALID_UID)
-               *init_uid = uid;
-
-       if (gid != LXC_INVALID_GID)
-               *init_gid = gid;
-
-       /* TODO: we should also parse supplementary groups and use
-        * setgroups() to set them.
-        */
-}
-
 static bool fetch_seccomp(struct lxc_container *c, lxc_attach_options_t *options)
 {
        __do_free char *path = NULL;
@@ -964,7 +958,10 @@ __noreturn static void do_attach(struct attach_payload *ap)
                 * init was started with.
                 */
                if (ns_root_uid == LXC_INVALID_UID)
-                       lxc_attach_get_init_uidgid(&ns_root_uid, &ns_root_gid);
+                       ns_root_uid = ctx->init_uid;
+
+               if (ns_root_gid == LXC_INVALID_UID)
+                       ns_root_gid = ctx->init_gid;
 
                if (ns_root_uid == LXC_INVALID_UID)
                        goto on_error;