git://git.exim.org
/
exim.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
CVE-2020-28009: Integer overflow in get_stdinput()
[exim.git]
/
src
/
src
/
string.c
diff --git
a/src/src/string.c
b/src/src/string.c
index 80cf49fdf1b297d14f0d25d43708b98c92e20660..27e030bd8e4575d211caf48cc8bc8cd4ba0ade64 100644
(file)
--- a/
src/src/string.c
+++ b/
src/src/string.c
@@
-3,6
+3,7
@@
*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
/* Miscellaneous string-handling functions. Some are not required for
/* See the file NOTICE for conditions of use and distribution. */
/* Miscellaneous string-handling functions. Some are not required for
@@
-280,17
+281,17
@@
return ch;
/* This function is called for critical strings. It checks for any
non-printing characters, and if any are found, it makes a new copy
of the string with suitable escape sequences. It is most often called by the
/* This function is called for critical strings. It checks for any
non-printing characters, and if any are found, it makes a new copy
of the string with suitable escape sequences. It is most often called by the
-macro string_printing(), which sets
allow_tab TRUE
.
+macro string_printing(), which sets
flags to 0
.
Arguments:
s the input string
Arguments:
s the input string
- allow_tab TRUE to allow tab as a printing character
+ flags Bit 0: convert tabs. Bit 1: convert spaces.
Returns: string with non-printers encoded as printing sequences
*/
const uschar *
Returns: string with non-printers encoded as printing sequences
*/
const uschar *
-string_printing2(const uschar *s,
BOOL allow_tab
)
+string_printing2(const uschar *s,
int flags
)
{
int nonprintcount = 0;
int length = 0;
{
int nonprintcount = 0;
int length = 0;
@@
-300,7
+301,10
@@
uschar *ss, *tt;
while (*t != 0)
{
int c = *t++;
while (*t != 0)
{
int c = *t++;
- if (!mac_isprint(c) || (!allow_tab && c == '\t')) nonprintcount++;
+ if ( !mac_isprint(c)
+ || flags & SP_TAB && c == '\t'
+ || flags & SP_SPACE && c == ' '
+ ) nonprintcount++;
length++;
}
length++;
}
@@
-309,17
+313,19
@@
if (nonprintcount == 0) return s;
/* Get a new block of store guaranteed big enough to hold the
expanded string. */
/* Get a new block of store guaranteed big enough to hold the
expanded string. */
-ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s));
+
tt =
ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s));
/* Copy everything, escaping non printers. */
/* Copy everything, escaping non printers. */
-t = s;
-tt = ss;
-
-while (*t != 0)
+for (t = s; *t; )
{
int c = *t;
{
int c = *t;
- if (mac_isprint(c) && (allow_tab || c != '\t')) *tt++ = *t++; else
+ if ( mac_isprint(c)
+ && (!(flags & SP_TAB) || c != '\t')
+ && (!(flags & SP_SPACE) || c != ' ')
+ )
+ *tt++ = *t++;
+ else
{
*tt++ = '\\';
switch (*t)
{
*tt++ = '\\';
switch (*t)
@@
-574,18
+580,14
@@
uschar *ss = yield = store_get(Ustrlen(s) + 1, is_tainted(s));
while (*s != 0)
{
if (*s != '\\')
while (*s != 0)
{
if (*s != '\\')
- {
*ss++ = *s++;
*ss++ = *s++;
- }
else if (isdigit(s[1]))
{
*ss++ = (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0';
s += 4;
}
else if (*(++s) != 0)
else if (isdigit(s[1]))
{
*ss++ = (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0';
s += 4;
}
else if (*(++s) != 0)
- {
*ss++ = *s++;
*ss++ = *s++;
- }
}
*ss = 0;
}
*ss = 0;
@@
-950,7
+952,10
@@
else
s = ss;
if (!*s || *++s != sep || sep_is_special) break;
}
s = ss;
if (!*s || *++s != sep || sep_is_special) break;
}
- while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--;
+ /* while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--; */
+ while ( g->ptr > 0 && isspace(g->s[g->ptr-1])
+ && (g->ptr == 1 || g->s[g->ptr-2] != '\\') )
+ g->ptr--;
buffer = string_from_gstring(g);
gstring_release_unused(g);
}
buffer = string_from_gstring(g);
gstring_release_unused(g);
}
@@
-1086,7
+1091,16
@@
existing length of the string. */
unsigned inc = oldsize < 4096 ? 127 : 1023;
unsigned inc = oldsize < 4096 ? 127 : 1023;
+if (g->ptr < 0 || g->ptr > g->size || g->size >= INT_MAX/2)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "internal error in gstring_grow (ptr %d size %d)", g->ptr, g->size);
+
if (count <= 0) return;
if (count <= 0) return;
+
+if (count >= INT_MAX/2 - g->ptr)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "internal error in gstring_grow (ptr %d count %d)", g->ptr, count);
+
g->size = (p + count + inc + 1) & ~inc; /* one for a NUL */
/* Try to extend an existing allocation. If the result of calling
g->size = (p + count + inc + 1) & ~inc; /* one for a NUL */
/* Try to extend an existing allocation. If the result of calling
@@
-1135,6
+1149,10
@@
string_catn(gstring * g, const uschar *s, int count)
int p;
BOOL srctaint = is_tainted(s);
int p;
BOOL srctaint = is_tainted(s);
+if (count < 0)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "internal error in string_catn (count %d)", count);
+
if (!g)
{
unsigned inc = count < 4096 ? 127 : 1023;
if (!g)
{
unsigned inc = count < 4096 ? 127 : 1023;
@@
-1144,8
+1162,12
@@
if (!g)
else if (srctaint && !is_tainted(g->s))
gstring_rebuffer(g);
else if (srctaint && !is_tainted(g->s))
gstring_rebuffer(g);
+if (g->ptr < 0 || g->ptr > g->size)
+ log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "internal error in string_catn (ptr %d size %d)", g->ptr, g->size);
+
p = g->ptr;
p = g->ptr;
-if (
p + count >= g->size
)
+if (
count >= g->size - p
)
gstring_grow(g, count);
/* Because we always specify the exact number of characters to copy, we can
gstring_grow(g, count);
/* Because we always specify the exact number of characters to copy, we can