lxc/0044-fix-HOME-env-unset-error.patch
haozi007 aedeb84ae5 fix HOME env of container unset error
Signed-off-by: haozi007 <liuhao27@huawei.com>
(cherry picked from commit d97043c9d07b01f0d12e3bdaa5daff150bffe5b5)
2022-07-25 20:35:17 +08:00

322 lines
8.3 KiB
Diff

From d86ad6bf0acaa98b11344627a8118a2945b8da1e Mon Sep 17 00:00:00 2001
From: haozi007 <liuhao27@huawei.com>
Date: Mon, 25 Jul 2022 11:08:29 +0800
Subject: [PATCH] fix HOME env unset error
Signed-off-by: haozi007 <liuhao27@huawei.com>
---
src/lxc/isulad_utils.c | 190 +++++++++++++++++++++++++++++++++++++++++
src/lxc/isulad_utils.h | 3 +
src/lxc/start.c | 14 +--
src/lxc/utils.c | 22 ++++-
4 files changed, 218 insertions(+), 11 deletions(-)
diff --git a/src/lxc/isulad_utils.c b/src/lxc/isulad_utils.c
index b282404..f72b5fe 100644
--- a/src/lxc/isulad_utils.c
+++ b/src/lxc/isulad_utils.c
@@ -6,11 +6,21 @@
* Create: 2020-04-11
******************************************************************************/
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio_ext.h>
#include "isulad_utils.h"
#include "log.h"
@@ -97,3 +107,183 @@ FILE *lxc_fopen(const char *filename, const char *mode)
return fopen_cloexec(rpath, mode);
}
+
+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 7a6ab00..1368c83 100644
--- a/src/lxc/isulad_utils.h
+++ b/src/lxc/isulad_utils.h
@@ -9,6 +9,7 @@
#define __iSULAD_UTILS_H
#include <stdio.h>
+#include <pwd.h>
extern int lxc_mem_realloc(void **newptr, size_t newsize, void *oldptr, size_t oldsize);
extern void *lxc_common_calloc_s(size_t size);
@@ -17,4 +18,6 @@ extern char *safe_strdup(const char *src);
extern int lxc_open(const char *filename, int flags, mode_t mode);
extern FILE *lxc_fopen(const char *filename, const char *mode);
+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 c1563e0..aeafd47 100644
--- a/src/lxc/start.c
+++ b/src/lxc/start.c
@@ -1716,6 +1716,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;
@@ -1723,13 +1730,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)
diff --git a/src/lxc/utils.c b/src/lxc/utils.c
index b39b6a8..20ca181 100644
--- a/src/lxc/utils.c
+++ b/src/lxc/utils.c
@@ -2213,20 +2213,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'");
--
2.25.1