From: Christian Brauner Date: Mon, 1 Feb 2021 10:37:22 +0000 (+0100) Subject: attach: unifiy /proc//status parsing X-Git-Tag: lxc-5.0.0~309^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9680e7b062ff3e947bd3e0460d76758d44f15bb4;p=thirdparty%2Flxc.git attach: unifiy /proc//status parsing and move it out of do_attach(). The less we do in the container's context the better. Signed-off-by: Christian Brauner --- diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 187ff37d3..869f2c148 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -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;