Skip to content

Commit

Permalink
fix getpwuid() thread safe issue
Browse files Browse the repository at this point in the history
Signed-off-by: Donghwa Jeong <dh48.jeong@samsung.com>
  • Loading branch information
2xsec committed Jun 14, 2018
1 parent db8b325 commit cb7aa5e
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 19 deletions.
29 changes: 24 additions & 5 deletions src/lxc/attach.c
Expand Up @@ -1501,25 +1501,43 @@ int lxc_attach_run_command(void* payload)
int lxc_attach_run_shell(void* payload)
{
uid_t uid;
struct passwd *passwd;
struct passwd pwent;
struct passwd *pwentp = NULL;
char *user_shell;
char *buf;
size_t bufsize;
int ret;

/* Ignore payload parameter. */
(void)payload;

uid = getuid();
passwd = getpwuid(uid);

bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (bufsize == -1)
bufsize = 1024;

buf = malloc(bufsize);
if (buf) {
ret = getpwuid_r(uid, &pwent, buf, bufsize, &pwentp);
if (!pwentp) {
if (ret == 0)
WARN("Could not find matched password record.");

WARN("Failed to get password record - %u", uid);
}
}

/* This probably happens because of incompatible nss implementations in
* host and container (remember, this code is still using the host's
* glibc but our mount namespace is in the container) we may try to get
* the information by spawning a [getent passwd uid] process and parsing
* the result.
*/
if (!passwd)
if (!pwentp)
user_shell = lxc_attach_getpwshell(uid);
else
user_shell = passwd->pw_shell;
user_shell = pwent.pw_shell;
if (user_shell)
execlp(user_shell, user_shell, (char *)NULL);

Expand All @@ -1528,7 +1546,8 @@ int lxc_attach_run_shell(void* payload)
*/
execlp("/bin/sh", "/bin/sh", (char *)NULL);
SYSERROR("Failed to execute shell");
if (!passwd)
if (!pwentp)
free(user_shell);
free(buf);
return -1;
}
31 changes: 26 additions & 5 deletions src/lxc/cmd/lxc_user_nic.c
Expand Up @@ -103,15 +103,35 @@ static int open_and_lock(char *path)

static char *get_username(void)
{
struct passwd *pwd;
struct passwd pwent;
struct passwd *pwentp = NULL;
char *buf;
char *username;
size_t bufsize;
int ret;

bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (bufsize == -1)
bufsize = 1024;

buf = malloc(bufsize);
if (!buf)
return NULL;

ret = getpwuid_r(getuid(), &pwent, buf, bufsize, &pwentp);
if (!pwentp) {
if (ret == 0)
usernic_error("%s", "Could not find matched password record\n");

pwd = getpwuid(getuid());
if (!pwd) {
usernic_error("Failed to get username: %s\n", strerror(errno));
usernic_error("Failed to get username: %s(%u)\n", strerror(errno), getuid());
free(buf);
return NULL;
}

return pwd->pw_name;
username = strdup(pwent.pw_name);
free(buf);

return username;
}

static void free_groupnames(char **groupnames)
Expand Down Expand Up @@ -1170,6 +1190,7 @@ int main(int argc, char *argv[])
}

n = get_alloted(me, args.type, args.link, &alloted);
free(me);

if (request == LXC_USERNIC_DELETE) {
int ret;
Expand Down
38 changes: 33 additions & 5 deletions src/lxc/cmd/lxc_usernsexec.c
Expand Up @@ -253,14 +253,42 @@ static int read_default_map(char *fnam, int which, char *username)

static int find_default_map(void)
{
struct passwd *p = getpwuid(getuid());
if (!p)
struct passwd pwent;
struct passwd *pwentp = NULL;
char *buf;
size_t bufsize;
int ret;

bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (bufsize == -1)
bufsize = 1024;

buf = malloc(bufsize);
if (!buf)
return -1;
if (read_default_map(subuidfile, ID_TYPE_UID, p->pw_name) < 0)

ret = getpwuid_r(getuid(), &pwent, buf, bufsize, &pwentp);
if (!pwentp) {
if (ret == 0)
printf("WARN: could not find matched password record\n");

printf("Failed to get password record - %u\n", getuid());
free(buf);
return -1;
if (read_default_map(subgidfile, ID_TYPE_GID, p->pw_name) < 0)
}

if (read_default_map(subuidfile, ID_TYPE_UID, pwent.pw_name) < 0) {
free(buf);
return -1;
return 0;
}

if (read_default_map(subgidfile, ID_TYPE_GID, pwent.pw_name) < 0) {
free(buf);
return -1;
}

free(buf);
return 0;
}

int main(int argc, char *argv[])
Expand Down
30 changes: 26 additions & 4 deletions src/lxc/conf.c
Expand Up @@ -4508,13 +4508,35 @@ int userns_exec_full(struct lxc_conf *conf, int (*fn)(void *), void *data,
/* not thread-safe, do not use from api without first forking */
static char *getuname(void)
{
struct passwd *result;
struct passwd pwent;
struct passwd *pwentp = NULL;
char *buf;
char *username;
size_t bufsize;
int ret;

result = getpwuid(geteuid());
if (!result)
bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
if (bufsize == -1)
bufsize = 1024;

buf = malloc(bufsize);
if (!buf)
return NULL;

return strdup(result->pw_name);
ret = getpwuid_r(geteuid(), &pwent, buf, bufsize, &pwentp);
if (!pwentp) {
if (ret == 0)
WARN("Could not find matched password record.");

ERROR("Failed to get password record - %u", geteuid());
free(buf);
return NULL;
}

username = strdup(pwent.pw_name);
free(buf);

return username;
}

/* not thread-safe, do not use from api without first forking */
Expand Down

0 comments on commit cb7aa5e

Please sign in to comment.