From 043b2483585a2d8168e0fde8b37054733a31f263 Mon Sep 17 00:00:00 2001 From: haozi007 Date: Mon, 25 Jul 2022 15:36:23 +0800 Subject: [PATCH] fix HOME env of container unset error Signed-off-by: haozi007 --- src/lxc/isulad_utils.c | 210 ++++++++++++++++++++++++++++++++++++++++- src/lxc/isulad_utils.h | 3 + src/lxc/start.c | 14 +-- 3 files changed, 216 insertions(+), 11 deletions(-) diff --git a/src/lxc/isulad_utils.c b/src/lxc/isulad_utils.c index 15d9323..cd7fca8 100644 --- a/src/lxc/isulad_utils.c +++ b/src/lxc/isulad_utils.c @@ -6,6 +6,10 @@ * Create: 2020-04-11 ******************************************************************************/ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE 1 +#endif + #include #include #include @@ -13,6 +17,10 @@ #include #include #include +#include +#include +#include +#include #include "isulad_utils.h" #include "log.h" @@ -244,20 +252,34 @@ out: // isulad: set env home in container int lxc_setup_env_home(uid_t uid) { +#define __PASSWD_FILE__ "/etc/passwd" char *homedir = "/"; // default home dir is / + FILE *stream = NULL; struct passwd pw, *pwbufp = NULL; char buf[BUFSIZ]; - int ret; - ret = getpwuid_r(uid, &pw, buf, sizeof(buf), &pwbufp); - if ((ret == 0) && (pwbufp != NULL) && (pwbufp->pw_uid == uid)) { - homedir = pwbufp->pw_dir; + stream = fopen_cloexec(__PASSWD_FILE__, "r"); + if (stream == NULL) { + SYSWARN("Failed to open %s", __PASSWD_FILE__); goto set_env; } +#if IS_BIONIC + while (util_getpwent_r(stream, &pw, buf, sizeof(buf), &pwbufp) == 0 && pwbufp != NULL) { +#else + while (fgetpwent_r(stream, &pw, buf, sizeof(buf), &pwbufp) == 0 && pwbufp != NULL) { +#endif + if (pwbufp->pw_uid == uid) { + homedir = pwbufp->pw_dir; + goto set_env; + } + } WARN("User invalid, can not find user '%u'", uid); set_env: + if (stream) + fclose(stream); + // if we didn't configure HOME, set it based on uid if (setenv("HOME", homedir, 0) < 0) { SYSERROR("Unable to set env 'HOME'"); @@ -317,3 +339,183 @@ bool is_non_negative_num(const char *s) } return true; } + +static int hold_int(const char delim, bool required, char **src, unsigned int *dst) +{ + unsigned long long int res = 0; + char *err_str = NULL; + + // ensure *src not a empty string + if (**src == '\0') { + ERROR("Empty subject on given entrie is not allowed."); + return -1; + } + + errno = 0; + // covert string to long long + res = strtoull(*src, &err_str, 0); + if (errno != 0 && errno != ERANGE) { + ERROR("Parse int from string failed."); + return -1; + } + + // **src is not a digit + if (err_str == *src) { + if (!required) { + ERROR("Integer part is missing."); + return -1; + } + // if required, just set 0 + *dst = 0; + } else { + if (sizeof(void *) > 4 && res > UINT_MAX) { // make sure 64-bit platform behave same as 32-bit + res = UINT_MAX; + } + res = res & UINT_MAX; + *dst = (uint32_t)res; + } + + // normal case + if (*err_str == delim) { + err_str++; + } else if (*err_str != '\0') { + ERROR("Invalid digit string."); + return -1; + } + + *src = err_str; // update src to next valid context in line. + return 0; +} + +static void hold_string(const char delim, char **src, char **dst) +{ + for (*dst = *src; **src != delim; ++(*src)) { + if (**src == '\0') { + break; + } + } + + if (**src == delim) { + **src = '\0'; + ++(*src); + } +} + +static int parse_line_pw(const char delim, char *line, struct passwd *result) +{ + int ret = 0; + bool required = false; + char *walker = NULL; + + walker = strpbrk(line, "\n"); + if (walker != NULL) { + // clear newline char + *walker = '\0'; + } + + hold_string(delim, &line, &result->pw_name); + + required = (result->pw_name[0] == '+' || result->pw_name[0] == '-') ? true : false; + + hold_string(delim, &line, &result->pw_passwd); + + ret = hold_int(delim, required, &line, &result->pw_uid); + if (ret != 0) { + // a legitimate line must have uid + ERROR("Parse uid error."); + return ret; + } + + ret = hold_int(delim, required, &line, &result->pw_gid); + if (ret != 0) { + // it's ok to not provide gid + ERROR("Parse gid error."); + return ret; + } + + hold_string(delim, &line, &result->pw_gecos); + + hold_string(delim, &line, &result->pw_dir); + + result->pw_shell = line; + return 0; +} + +char *util_left_trim_space(char *str) +{ + char *begin = str; + char *tmp = str; + while (isspace(*begin)) { + begin++; + } + while ((*tmp++ = *begin++)) { + } + return str; +} + +int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t buflen, struct passwd **result) +{ + const char delim = ':'; + char *buff_end = NULL; + char *walker = NULL; + bool got = false; + int ret = 0; + + if (stream == NULL || resbuf == NULL || buffer == NULL || result == NULL) { + ERROR("Password obj, params is NULL."); + return -1; + } + + if (buflen <= 1) { + ERROR("Inadequate buffer length was given."); + return -1; + } + + buff_end = buffer + buflen - 1; + flockfile(stream); + + while (1) { + *buff_end = '\xff'; + walker = fgets_unlocked(buffer, buflen, stream); + // if get NULL string + if (walker == NULL) { + *result = NULL; + // reach end of file, return error + if (feof(stream)) { + ret = ENOENT; + goto out; + } + // overflow buffer + ret = ERANGE; + goto out; + } + // just overflow last char in buffer + if (*buff_end != '\xff') { + *result = NULL; + ret = ERANGE; + goto out; + } + + (void)util_left_trim_space(buffer); + // skip comment line and empty line + if (walker[0] == '#' || walker[0] == '\0') { + continue; + } + + if (parse_line_pw(delim, walker, resbuf) == 0) { + got = true; + break; + } + } + if (!got) { + *result = NULL; + ret = ERANGE; + goto out; + } + + *result = resbuf; + ret = 0; +out: + funlockfile(stream); + return ret; +} \ No newline at end of file diff --git a/src/lxc/isulad_utils.h b/src/lxc/isulad_utils.h index 345f511..7a5eb89 100644 --- a/src/lxc/isulad_utils.h +++ b/src/lxc/isulad_utils.h @@ -10,6 +10,7 @@ #include #include +#include /* isulad: replace space with SPACE_MAGIC_STR */ #define SPACE_MAGIC_STR "[#)" @@ -96,4 +97,6 @@ extern bool lxc_process_alive(pid_t pid, unsigned long long start_time); extern bool is_non_negative_num(const char *s); +int util_getpwent_r(FILE *stream, struct passwd *resbuf, char *buffer, size_t buflen, struct passwd **result); + #endif diff --git a/src/lxc/start.c b/src/lxc/start.c index f82df34..6fe1203 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1727,6 +1727,13 @@ static int do_start(void *data) new_uid = handler->conf->init_uid; new_gid = handler->conf->init_gid; +#ifdef HAVE_ISULAD + // isulad: set env home in container, must before "Avoid unnecessary syscalls." + if (lxc_setup_env_home(new_uid) < 0) { + goto out_warn_father; + } +#endif + /* Avoid unnecessary syscalls. */ if (new_uid == nsuid) new_uid = LXC_INVALID_UID; @@ -1734,13 +1741,6 @@ static int do_start(void *data) if (new_gid == nsgid) new_gid = LXC_INVALID_GID; -#ifdef HAVE_ISULAD - // isulad: set env home in container - if (lxc_setup_env_home(new_uid) < 0) { - goto out_warn_father; - } -#endif - /* Make sure that the processes STDIO is correctly owned by the user that we are switching to */ ret = fix_stdio_permissions(new_uid); if (ret) -- 2.25.1