Skip to content

Commit 5737d31

Browse files
iabynsteve-m-hay
authored andcommitted
Perl_my_setenv(); handle integer wrap
RT #133204 Wean this function off int/I32 and onto UV/Size_t. Also, replace all malloc-ish calls with a wrapper that does overflow checks, In particular, it was doing (nlen + vlen + 2) which could wrap when the combined length of the environment variable name and value exceeded around 0x7fffffff. The wrapper check function is probably overkill, but belt and braces... NB this function has several variant parts, #ifdef'ed by platform type; I have blindly changed the parts that aren't compiled under linux. (cherry picked from commit 34716e2)
1 parent adf1b5d commit 5737d31

File tree

1 file changed

+53
-23
lines changed

1 file changed

+53
-23
lines changed

util.c

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2064,8 +2064,40 @@ Perl_new_warnings_bitfield(pTHX_ STRLEN *buffer, const char *const bits,
20642064
*(s+(nlen+1+vlen)) = '\0'
20652065

20662066
#ifdef USE_ENVIRON_ARRAY
2067-
/* VMS' my_setenv() is in vms.c */
2067+
2068+
/* small wrapper for use by Perl_my_setenv that mallocs, or reallocs if
2069+
* 'current' is non-null, with up to three sizes that are added together.
2070+
* It handles integer overflow.
2071+
*/
2072+
static char *
2073+
S_env_alloc(void *current, Size_t l1, Size_t l2, Size_t l3, Size_t size)
2074+
{
2075+
void *p;
2076+
Size_t sl, l = l1 + l2;
2077+
2078+
if (l < l2)
2079+
goto panic;
2080+
l += l3;
2081+
if (l < l3)
2082+
goto panic;
2083+
sl = l * size;
2084+
if (sl < l)
2085+
goto panic;
2086+
2087+
p = current
2088+
? safesysrealloc(current, sl)
2089+
: safesysmalloc(sl);
2090+
if (p)
2091+
return (char*)p;
2092+
2093+
panic:
2094+
croak_memory_wrap();
2095+
}
2096+
2097+
2098+
/* VMS' my_setenv() is in vms.c */
20682099
#if !defined(WIN32) && !defined(NETWARE)
2100+
20692101
void
20702102
Perl_my_setenv(pTHX_ const char *nam, const char *val)
20712103
{
@@ -2081,28 +2113,27 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
20812113
#ifndef PERL_USE_SAFE_PUTENV
20822114
if (!PL_use_safe_putenv) {
20832115
/* most putenv()s leak, so we manipulate environ directly */
2084-
I32 i;
2085-
const I32 len = strlen(nam);
2086-
int nlen, vlen;
2116+
UV i;
2117+
Size_t vlen, nlen = strlen(nam);
20872118

20882119
/* where does it go? */
20892120
for (i = 0; environ[i]; i++) {
2090-
if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
2121+
if (strnEQ(environ[i], nam, nlen) && environ[i][nlen] == '=')
20912122
break;
20922123
}
20932124

20942125
if (environ == PL_origenviron) { /* need we copy environment? */
2095-
I32 j;
2096-
I32 max;
2126+
UV j, max;
20972127
char **tmpenv;
20982128

20992129
max = i;
21002130
while (environ[max])
21012131
max++;
2102-
tmpenv = (char**)safesysmalloc((max+2) * sizeof(char*));
2132+
/* XXX shouldn't that be max+1 rather than max+2 ??? - DAPM */
2133+
tmpenv = (char**)S_env_alloc(NULL, max, 2, 0, sizeof(char*));
21032134
for (j=0; j<max; j++) { /* copy environment */
2104-
const int len = strlen(environ[j]);
2105-
tmpenv[j] = (char*)safesysmalloc((len+1)*sizeof(char));
2135+
const Size_t len = strlen(environ[j]);
2136+
tmpenv[j] = S_env_alloc(NULL, len, 1, 0, 1);
21062137
Copy(environ[j], tmpenv[j], len+1, char);
21072138
}
21082139
tmpenv[max] = NULL;
@@ -2121,15 +2152,15 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
21212152
#endif
21222153
}
21232154
if (!environ[i]) { /* does not exist yet */
2124-
environ = (char**)safesysrealloc(environ, (i+2) * sizeof(char*));
2155+
environ = (char**)S_env_alloc(environ, i, 2, 0, sizeof(char*));
21252156
environ[i+1] = NULL; /* make sure it's null terminated */
21262157
}
21272158
else
21282159
safesysfree(environ[i]);
2129-
nlen = strlen(nam);
2160+
21302161
vlen = strlen(val);
21312162

2132-
environ[i] = (char*)safesysmalloc((nlen+vlen+2) * sizeof(char));
2163+
environ[i] = S_env_alloc(NULL, nlen, vlen, 2, 1);
21332164
/* all that work just for this */
21342165
my_setenv_format(environ[i], nam, nlen, val, vlen);
21352166
} else {
@@ -2154,22 +2185,21 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
21542185
if (environ) /* old glibc can crash with null environ */
21552186
(void)unsetenv(nam);
21562187
} else {
2157-
const int nlen = strlen(nam);
2158-
const int vlen = strlen(val);
2159-
char * const new_env =
2160-
(char*)safesysmalloc((nlen + vlen + 2) * sizeof(char));
2188+
const Size_t nlen = strlen(nam);
2189+
const Size_t vlen = strlen(val);
2190+
char * const new_env = S_env_alloc(NULL, nlen, vlen, 2, 1);
21612191
my_setenv_format(new_env, nam, nlen, val, vlen);
21622192
(void)putenv(new_env);
21632193
}
21642194
# else /* ! HAS_UNSETENV */
21652195
char *new_env;
2166-
const int nlen = strlen(nam);
2167-
int vlen;
2196+
const Size_t nlen = strlen(nam);
2197+
Size_t vlen;
21682198
if (!val) {
21692199
val = "";
21702200
}
21712201
vlen = strlen(val);
2172-
new_env = (char*)safesysmalloc((nlen + vlen + 2) * sizeof(char));
2202+
new_env = S_env_alloc(NULL, nlen, vlen, 2, 1);
21732203
/* all that work just for this */
21742204
my_setenv_format(new_env, nam, nlen, val, vlen);
21752205
(void)putenv(new_env);
@@ -2192,14 +2222,14 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val)
21922222
{
21932223
dVAR;
21942224
char *envstr;
2195-
const int nlen = strlen(nam);
2196-
int vlen;
2225+
const Size_t nlen = strlen(nam);
2226+
Size_t vlen;
21972227

21982228
if (!val) {
21992229
val = "";
22002230
}
22012231
vlen = strlen(val);
2202-
Newx(envstr, nlen+vlen+2, char);
2232+
envstr = S_env_alloc(NULL, nlen, vlen, 2, 1);
22032233
my_setenv_format(envstr, nam, nlen, val, vlen);
22042234
(void)PerlEnv_putenv(envstr);
22052235
Safefree(envstr);

0 commit comments

Comments
 (0)