]> granicus.if.org Git - sudo/commitdiff
If env_init() was called implicitly via getenv(), setenv() or putenv()
authorTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 24 Jun 2010 11:42:29 +0000 (07:42 -0400)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Thu, 24 Jun 2010 11:42:29 +0000 (07:42 -0400)
just use the specified envp instead of mallocing a new copy.  This
prevents an infinite loop on OpenBSD which calls getenv() from malloc()
to get MALLOC_OPTIONS.

--HG--
branch : 1.7

env.c
sudo.c
sudo.h

diff --git a/env.c b/env.c
index 6ad9bd2a616625597e75443ebadc147bbf3f5b6b..75466241e38e59deda1f939f14ccb856daf944f0 100644 (file)
--- a/env.c
+++ b/env.c
@@ -90,6 +90,7 @@ struct environment {
     char **envp;               /* pointer to the new environment */
     size_t env_size;           /* size of new_environ in char **'s */
     size_t env_len;            /* number of slots used, not counting NULL */
+    int owned;                 /* do we own envp or is it the system's? */
 };
 
 /*
@@ -209,18 +210,26 @@ static const char *initial_keepenv_table[] = {
  * Initialize env based on envp.
  */
 void
-env_init(envp)
+env_init(envp, lazy)
     char * const envp[];
+    int lazy;
 {
-    /* May have gotten initialized lazily. */
-    if (env.envp == NULL) {
-       char * const *ep;
-       size_t len;
+    char * const *ep;
+    size_t len;
 
-       for (ep = envp; *ep != NULL; ep++)
-           continue;
-       len = (size_t)(ep - envp);
+    for (ep = envp; *ep != NULL; ep++)
+       continue;
+    len = (size_t)(ep - envp);
 
+    if (lazy) {
+       /*
+        * If we are already initialized due to lazy init (usualy via getenv())
+        * we need to avoid calling malloc() as it may call getenv() itself.
+        */
+       env.envp = (char **)envp;
+       env.env_len = len;
+       env.env_size = len;
+    } else if (!env.owned) {
        env.env_len = len;
        env.env_size = len + 1 + 128;
        env.envp = emalloc2(env.env_size, sizeof(char *));
@@ -229,6 +238,7 @@ env_init(envp)
 #endif
        memcpy(env.envp, envp, len * sizeof(char *));
        env.envp[len] = '\0';
+       env.owned = TRUE;
     }
 }
 
@@ -275,7 +285,7 @@ getenv(const char *var)
     size_t vlen = strlen(var);
 
     if (env.envp == NULL)
-       env_init(environ);
+       env_init(environ, TRUE);
 
     for (ev = env.envp; (cp = *ev) != NULL; ev++) {
        if (strncmp(var, cp, vlen) == 0 && cp[vlen] == '=')
@@ -298,7 +308,7 @@ setenv(var, val, overwrite)
     size_t esize;
 
     if (env.envp == NULL)
-       env_init(environ);
+       env_init(environ, TRUE);
 
     if (!var || *var == '\0') {
        errno = EINVAL;
@@ -350,7 +360,7 @@ unsetenv(var)
     size_t len;
 
     if (env.envp == NULL)
-       env_init(environ);
+       env_init(environ, TRUE);
 
     if (strchr(var, '=') != NULL) {
        errno = EINVAL;
@@ -395,7 +405,7 @@ putenv(string)
 #endif
 {
     if (env.envp == NULL)
-       env_init(environ);
+       env_init(environ, TRUE);
 
     if (strchr(string, '=') == NULL) {
        errno = EINVAL;
@@ -428,7 +438,15 @@ sudo_putenv(str, dupcheck, overwrite)
     /* Make sure there is room for the new entry plus a NULL. */
     if (env.env_len + 2 > env.env_size) {
        env.env_size += 128;
-       env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
+       if (env.owned) {
+           env.envp = erealloc3(env.envp, env.env_size, sizeof(char *));
+       } else {
+           /* We don't own env.envp, allocate a new one. */
+           ep = emalloc2(env.env_size, sizeof(char *));
+           memcpy(ep, env.envp, env.env_size * sizeof(char *));
+           env.envp = ep;
+           env.owned = TRUE;
+       }
 #ifdef ENV_DEBUG
        memset(env.envp + env.env_len, 0,
            (env.env_size - env.env_len) * sizeof(char *));
diff --git a/sudo.c b/sudo.c
index 7fecdfc051db66d5b1aa6bc3bf0977e7ecd33c9c..d17233d7a777ddb976a4c6cb4849a035052d5e5a 100644 (file)
--- a/sudo.c
+++ b/sudo.c
@@ -203,7 +203,7 @@ main(argc, argv, envp)
     (void) sigaction(SIGTSTP, &sa, &saved_sa_tstp);
 
     /* Initialize environment functions (including replacements). */
-    env_init(envp);
+    env_init(envp, FALSE);
 
     /*
      * Turn off core dumps and make sure fds 0-2 are open.
diff --git a/sudo.h b/sudo.h
index 0b074ef1ed0910c3934eea30bbe9ac9e44d587a0..4fbdeca6665387f0571ead7655223f10fea76d8c 100644 (file)
--- a/sudo.h
+++ b/sudo.h
@@ -226,7 +226,7 @@ void remove_timestamp       __P((int));
 
 /* env.c */
 char **env_get         __P((void));
-void env_init          __P((char * const envp[]));
+void env_init          __P((char * const envp[], int lazy));
 void init_envtables    __P((void));
 void insert_env_vars   __P((struct list_member *));
 void read_env_file     __P((const char *, int));