8eb8e7
From 17858779e42103ae815c8cf7c4d390207e485856 Mon Sep 17 00:00:00 2001
8eb8e7
From: Jitka Plesnikova <jplesnik@redhat.com>
8eb8e7
Date: Mon, 7 Jan 2019 13:38:36 +0100
8eb8e7
Subject: [PATCH] Perl_my_setenv(); handle integer wrap
8eb8e7
8eb8e7
RT #133204
8eb8e7
8eb8e7
Wean this function off int/I32 and onto UV/Size_t.
8eb8e7
Also, replace all malloc-ish calls with a wrapper that does
8eb8e7
overflow checks,
8eb8e7
8eb8e7
In particular, it was doing (nlen + vlen + 2) which could wrap when
8eb8e7
the combined length of the environment variable name and value
8eb8e7
exceeded around 0x7fffffff.
8eb8e7
8eb8e7
The wrapper check function is probably overkill, but belt and braces...
8eb8e7
8eb8e7
NB this function has several variant parts, #ifdef'ed by platform
8eb8e7
type; I have blindly changed the parts that aren't compiled under linux.
8eb8e7
8eb8e7
Backported David Mitchell's patch to 5.16.3
8eb8e7
---
8eb8e7
 util.c | 75 ++++++++++++++++++++++++++++++++++++++++------------------
8eb8e7
 1 file changed, 52 insertions(+), 23 deletions(-)
8eb8e7
8eb8e7
diff --git a/util.c b/util.c
8eb8e7
index c1dca62..1357ad5 100644
8eb8e7
--- a/util.c
8eb8e7
+++ b/util.c
8eb8e7
@@ -2029,7 +2029,38 @@ Perl_new_warnings_bitfield(pTHX_ STRLEN *buffer, const char *const bits,
8eb8e7
    *(s+(nlen+1+vlen)) = '\0'
8eb8e7
 
8eb8e7
 #ifdef USE_ENVIRON_ARRAY
8eb8e7
-       /* VMS' my_setenv() is in vms.c */
8eb8e7
+
8eb8e7
+/* small wrapper for use by Perl_my_setenv that mallocs, or reallocs if
8eb8e7
+ * 'current' is non-null, with up to three sizes that are added together.
8eb8e7
+ * It handles integer overflow.
8eb8e7
+ */
8eb8e7
+static char *
8eb8e7
+S_env_alloc(void *current, Size_t l1, Size_t l2, Size_t l3, Size_t size)
8eb8e7
+{
8eb8e7
+    void *p;
8eb8e7
+    Size_t sl, l = l1 + l2;
8eb8e7
+
8eb8e7
+    if (l < l2)
8eb8e7
+        goto panic;
8eb8e7
+    l += l3;
8eb8e7
+    if (l < l3)
8eb8e7
+        goto panic;
8eb8e7
+    sl = l * size;
8eb8e7
+    if (sl < l)
8eb8e7
+        goto panic;
8eb8e7
+
8eb8e7
+    p = current
8eb8e7
+            ? safesysrealloc(current, sl)
8eb8e7
+            : safesysmalloc(sl);
8eb8e7
+    if (p)
8eb8e7
+        return (char*)p;
8eb8e7
+
8eb8e7
+  panic:
8eb8e7
+    Perl_croak_nocontext("%s", PL_memory_wrap);
8eb8e7
+}
8eb8e7
+
8eb8e7
+
8eb8e7
+/* VMS' my_setenv() is in vms.c */
8eb8e7
 #if !defined(WIN32) && !defined(NETWARE)
8eb8e7
 void
8eb8e7
 Perl_my_setenv(pTHX_ const char *nam, const char *val)
8eb8e7
@@ -2043,28 +2074,27 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
8eb8e7
 #ifndef PERL_USE_SAFE_PUTENV
8eb8e7
     if (!PL_use_safe_putenv) {
8eb8e7
     /* most putenv()s leak, so we manipulate environ directly */
8eb8e7
-    register I32 i;
8eb8e7
-    register const I32 len = strlen(nam);
8eb8e7
-    int nlen, vlen;
8eb8e7
+    UV i;
8eb8e7
+    Size_t vlen, nlen = strlen(nam);
8eb8e7
 
8eb8e7
     /* where does it go? */
8eb8e7
     for (i = 0; environ[i]; i++) {
8eb8e7
-        if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
8eb8e7
+        if (strnEQ(environ[i], nam, nlen) && environ[i][nlen] == '=')
8eb8e7
             break;
8eb8e7
     }
8eb8e7
 
8eb8e7
     if (environ == PL_origenviron) {   /* need we copy environment? */
8eb8e7
-       I32 j;
8eb8e7
-       I32 max;
8eb8e7
+       UV j, max;
8eb8e7
        char **tmpenv;
8eb8e7
 
8eb8e7
        max = i;
8eb8e7
        while (environ[max])
8eb8e7
            max++;
8eb8e7
-       tmpenv = (char**)safesysmalloc((max+2) * sizeof(char*));
8eb8e7
+       /* XXX shouldn't that be max+1 rather than max+2 ??? - DAPM */
8eb8e7
+       tmpenv = (char**)S_env_alloc(NULL, max, 2, 0, sizeof(char*));
8eb8e7
        for (j=0; j
8eb8e7
-           const int len = strlen(environ[j]);
8eb8e7
-           tmpenv[j] = (char*)safesysmalloc((len+1)*sizeof(char));
8eb8e7
+           const Size_t len = strlen(environ[j]);
8eb8e7
+           tmpenv[j] = S_env_alloc(NULL, len, 1, 0, 1);
8eb8e7
            Copy(environ[j], tmpenv[j], len+1, char);
8eb8e7
        }
8eb8e7
        tmpenv[max] = NULL;
8eb8e7
@@ -2079,15 +2109,15 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
8eb8e7
        return;
8eb8e7
     }
8eb8e7
     if (!environ[i]) {                 /* does not exist yet */
8eb8e7
-       environ = (char**)safesysrealloc(environ, (i+2) * sizeof(char*));
8eb8e7
+       environ = (char**)S_env_alloc(environ, i, 2, 0, sizeof(char*));
8eb8e7
        environ[i+1] = NULL;    /* make sure it's null terminated */
8eb8e7
     }
8eb8e7
     else
8eb8e7
        safesysfree(environ[i]);
8eb8e7
-       nlen = strlen(nam);
8eb8e7
+
8eb8e7
        vlen = strlen(val);
8eb8e7
 
8eb8e7
-       environ[i] = (char*)safesysmalloc((nlen+vlen+2) * sizeof(char));
8eb8e7
+       environ[i] = S_env_alloc(NULL, nlen, vlen, 2, 1);
8eb8e7
        /* all that work just for this */
8eb8e7
        my_setenv_format(environ[i], nam, nlen, val, vlen);
8eb8e7
     } else {
8eb8e7
@@ -2107,22 +2137,21 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
8eb8e7
         if (val == NULL) {
8eb8e7
             (void)unsetenv(nam);
8eb8e7
         } else {
8eb8e7
-	    const int nlen = strlen(nam);
8eb8e7
-	    const int vlen = strlen(val);
8eb8e7
-	    char * const new_env =
8eb8e7
-                (char*)safesysmalloc((nlen + vlen + 2) * sizeof(char));
8eb8e7
+	    const Size_t nlen = strlen(nam);
8eb8e7
+	    const Size_t vlen = strlen(val);
8eb8e7
+	    char * const new_env = S_env_alloc(NULL, nlen, vlen, 2, 1);
8eb8e7
             my_setenv_format(new_env, nam, nlen, val, vlen);
8eb8e7
             (void)putenv(new_env);
8eb8e7
         }
8eb8e7
 #       else /* ! HAS_UNSETENV */
8eb8e7
         char *new_env;
8eb8e7
-	const int nlen = strlen(nam);
8eb8e7
-	int vlen;
8eb8e7
+	const Size_t nlen = strlen(nam);
8eb8e7
+	Size_t vlen;
8eb8e7
         if (!val) {
8eb8e7
 	   val = "";
8eb8e7
         }
8eb8e7
         vlen = strlen(val);
8eb8e7
-        new_env = (char*)safesysmalloc((nlen + vlen + 2) * sizeof(char));
8eb8e7
+        new_env = S_env_alloc(NULL, nlen, vlen, 2, 1);
8eb8e7
         /* all that work just for this */
8eb8e7
         my_setenv_format(new_env, nam, nlen, val, vlen);
8eb8e7
         (void)putenv(new_env);
8eb8e7
@@ -2141,14 +2170,14 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
8eb8e7
 {
8eb8e7
     dVAR;
8eb8e7
     register char *envstr;
8eb8e7
-    const int nlen = strlen(nam);
8eb8e7
-    int vlen;
8eb8e7
+    const Size_t nlen = strlen(nam);
8eb8e7
+    Size_t vlen;
8eb8e7
 
8eb8e7
     if (!val) {
8eb8e7
        val = "";
8eb8e7
     }
8eb8e7
     vlen = strlen(val);
8eb8e7
-    Newx(envstr, nlen+vlen+2, char);
8eb8e7
+    envstr = S_env_alloc(NULL, nlen, vlen, 2, 1);
8eb8e7
     my_setenv_format(envstr, nam, nlen, val, vlen);
8eb8e7
     (void)PerlEnv_putenv(envstr);
8eb8e7
     Safefree(envstr);
8eb8e7
-- 
8eb8e7
2.17.2
8eb8e7