aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2020-11-05 20:11:06 +0200
committerSergey Poznyakoff <gray@gnu.org>2020-11-05 20:11:06 +0200
commit753987210e9e136b59d433c8293a856e98826ee9 (patch)
tree648dd7fd4646cf7fc8c6304d8049e2e6f6f2d78e /src
parente337b4120f2961b9b9c11a09a23a50fc4416502d (diff)
downloadmailfromd-753987210e9e136b59d433c8293a856e98826ee9.tar.gz
mailfromd-753987210e9e136b59d433c8293a856e98826ee9.tar.bz2
Improve numeric overflow checking during stack/data reallocation
* src/gram.y (strtosize): Improve numeric overflow checking. * src/prog.c (expand_dataseg): Change signature. Improve reallocation strategy and overflow checking. Don't throw exception on error, that's the responsibility of the caller. All uses changed. * src/prog.h (expand_dataseg): Change signature. * src/builtin/debug.bi (_expand_dataseg): Update call to expand_dataseg.
Diffstat (limited to 'src')
-rw-r--r--src/builtin/debug.bi5
-rw-r--r--src/gram.y29
-rw-r--r--src/prog.c77
-rw-r--r--src/prog.h2
4 files changed, 61 insertions, 52 deletions
diff --git a/src/builtin/debug.bi b/src/builtin/debug.bi
index 655e8c88..e53a1b61 100644
--- a/src/builtin/debug.bi
+++ b/src/builtin/debug.bi
@@ -105,8 +105,9 @@ END
MF_DEFUN(_expand_dataseg, VOID, NUMBER words)
{
- expand_dataseg(env, words,
- _("out of stack space; increase #pragma stacksize"));
+ MF_ASSERT(expand_dataseg(env, words) == 0,
+ mfe_failure,
+ _("out of stack space; increase #pragma stacksize"));
}
END
diff --git a/src/gram.y b/src/gram.y
index 401ec8ac..203e80a0 100644
--- a/src/gram.y
+++ b/src/gram.y
@@ -21,6 +21,7 @@
#include <fnmatch.h>
#include <netdb.h>
+#include <limits.h>
#include "mailfromd.h"
#include <mailutils/yyloc.h>
#include "prog.h"
@@ -3297,31 +3298,36 @@ pragma_regex(int argc, char **argv, const char *text)
static int
strtosize(const char *text, size_t *psize)
{
- unsigned long n;
- size_t size;
+ unsigned long size;
+ size_t factor = 1;
char *p;
- n = strtoul(text, &p, 0);
- size = n;
+ size = strtoul(text, &p, 0);
+ if (size == ULONG_MAX && errno == ERANGE) {
+ parse_error(_("invalid size: numeric overflow occurred"));
+ return 2;
+ }
+
switch (*p) {
case 't':
case 'T':
- size *= 1024;
+ factor = 1024;
case 'g':
case 'G':
- size *= 1024;
+ factor *= 1024;
case 'm':
case 'M':
- size *= 1024;
+ factor *= 1024;
case 'k':
case 'K':
- size *= 1024;
+ factor *= 1024;
p++;
if (*p && (*p == 'b' || *p == 'B'))
p++;
break;
case 0:
+ factor = 1;
break;
default:
@@ -3329,12 +3335,12 @@ strtosize(const char *text, size_t *psize)
return 1;
}
- if (size < n) {
+ if (((size_t)-1) / factor < size) {
parse_error(_("invalid size: numeric overflow occurred"));
return 2;
}
- *psize = size;
+ *psize = size * factor;
return 0;
}
@@ -3359,7 +3365,8 @@ pragma_stacksize(int argc, char **argv, const char *text)
return;
}
case 2:
- strtosize(argv[1], &size);
+ if (strtosize(argv[1], &size))
+ return;
}
stack_size = size;
diff --git a/src/prog.c b/src/prog.c
index 9b5cec7e..14d8f321 100644
--- a/src/prog.c
+++ b/src/prog.c
@@ -570,46 +570,39 @@ env_fixup_autos(eval_environ_t env, ptrdiff_t offset)
int
-expand_dataseg(eval_environ_t env, size_t count, const char *errtext)
+expand_dataseg(eval_environ_t env, size_t count)
{
STKVAL *newds;
ptrdiff_t offset;
size_t new_stack_size;
size_t diff;
+ enum { DATASEG_MAX = ((size_t)-1) / sizeof(STKVAL) };
switch (stack_expand_policy) {
case stack_expand_add:
diff = ((count + stack_expand_incr - 1) / stack_expand_incr)
* stack_expand_incr;
+ if (DATASEG_MAX - diff < env->stack_size)
+ return -1;
new_stack_size = env->stack_size + diff;
break;
case stack_expand_twice:
- new_stack_size = 2 * env->stack_size;
- if (new_stack_size < env->stack_size) {
- if (errtext)
- runtime_error(env, "%s", errtext);
- else
- return 1;
- }
- diff = new_stack_size - env->stack_size;
- if (diff < count) {
- if (errtext)
- runtime_error(env, "%s", errtext);
- else
- return 1;
- }
+ new_stack_size = env->stack_size;
+ do {
+ if (DATASEG_MAX / 2 < new_stack_size)
+ return -1;
+ new_stack_size *= 2;
+ diff = new_stack_size - env->stack_size;
+ } while (diff < count);
}
if ((stack_max_size && new_stack_size > stack_max_size)
+ || DATASEG_MAX - datasize < new_stack_size
|| (newds = realloc(env->dataseg,
(new_stack_size + datasize)
- * sizeof env->dataseg[0])) == NULL) {
- if (errtext)
- runtime_error(env, "%s", errtext);
- else
- return 1;
- }
+ * sizeof env->dataseg[0])) == NULL)
+ return 1;
offset = (char*)newds - (char*)env->dataseg;
env->dataseg = newds;
@@ -772,8 +765,9 @@ push(eval_environ_t env, STKVAL val)
("tos=%lu, toh=%lu",
(unsigned long) env->tos,
(unsigned long) env->toh));
- expand_dataseg(env, 1,
- _("out of stack space; increase #pragma stacksize"));
+ if (expand_dataseg(env, 1))
+ runtime_error(env, "%s",
+ _("out of stack space; increase #pragma stacksize"));
}
env->dataseg[env->tos--] = val;
}
@@ -790,9 +784,11 @@ size_t
heap_reserve_words(eval_environ_t env, size_t words)
{
size_t off = env->toh;
- if (env->toh + words > env->tos)
- expand_dataseg(env, words,
- _("heap overrun; increase #pragma stacksize"));
+ if (env->toh + words > env->tos) {
+ if (expand_dataseg(env, words))
+ runtime_error(env, "%s",
+ _("heap overrun; increase #pragma stacksize"));
+ }
env->toh += words;
return off;
}
@@ -808,9 +804,11 @@ heap_tempspace(eval_environ_t env, size_t size)
{
size_t words = B2STACK(size);
STKVAL ret;
- if (env->toh + words > env->tos)
- expand_dataseg(env, words,
- _("heap overrun; increase #pragma stacksize"));
+ if (env->toh + words > env->tos) {
+ if (expand_dataseg(env, words))
+ runtime_error(env, "%s",
+ _("heap overrun; increase #pragma stacksize"));
+ }
mf_c_val(ret, ptr) = env->dataseg + env->toh;
return ret;
}
@@ -847,9 +845,11 @@ heap_obstack_grow(eval_environ_t env, void * MFL_DATASEG ptr, size_t size)
char *ret;
env_register_auto(env, (void*) &ptr);
- if (env->tos - env->toh < words + B2STACK(env->temp_size))
- expand_dataseg(env, words,
- _("memory chunk too big to fit into heap"));
+ if (env->tos - env->toh < words + B2STACK(env->temp_size)) {
+ if (expand_dataseg(env, words))
+ runtime_error(env, "%s",
+ _("memory chunk too big to fit into heap"));
+ }
ret = (char*) env_data_ref(env, env->temp_start) + env->temp_size;
if (ptr)
memmove(ret, ptr, size);
@@ -1037,8 +1037,9 @@ instr_stkalloc(eval_environ_t env)
(unsigned long) env->tos,
(unsigned long) env->toh,
n));
- expand_dataseg(env, env->toh - (env->tos - n),
- _("Out of stack space; increase #pragma stacksize"));
+ if (expand_dataseg(env, env->toh - (env->tos - n)))
+ runtime_error(env, "%s",
+ _("Out of stack space; increase #pragma stacksize"));
}
env->tos -= n;
advance_pc(env, 1);
@@ -2416,7 +2417,7 @@ env_vsprintf(eval_environ_t env, const char *biname,
size_t size;
if (env->tos == env->toh)
- if (expand_dataseg(env, B2STACK(strlen(fmt)), NULL)) {
+ if (expand_dataseg(env, B2STACK(strlen(fmt)))) {
env_vsprintf_error(fmt, ap);
break;
}
@@ -2428,8 +2429,8 @@ env_vsprintf(eval_environ_t env, const char *biname,
if (biname) {
n = snprintf(s, size, "%s: ", biname);
if (n >= size) {
- n += strlen(fmt); /* rough estimation */
- if (expand_dataseg(env, B2STACK(n), NULL)) {
+ n += strlen(fmt); /* rough estimate */
+ if (expand_dataseg(env, B2STACK(n))) {
env_vsprintf_error(fmt, ap);
break;
}
@@ -2438,7 +2439,7 @@ env_vsprintf(eval_environ_t env, const char *biname,
}
k = vsnprintf(s + n, size - n, fmt, ap);
if (k >= size) {
- if (expand_dataseg(env, B2STACK(k), NULL)) {
+ if (expand_dataseg(env, B2STACK(k))) {
env_vsprintf_error(fmt, ap);
break;
}
diff --git a/src/prog.h b/src/prog.h
index 96727ff7..b5c8dbad 100644
--- a/src/prog.h
+++ b/src/prog.h
@@ -111,7 +111,7 @@ void env_get_locus(eval_environ_t env, struct mu_locus_range *loc);
STKVAL env_get_reg(eval_environ_t env);
prog_counter_t env_register_read(eval_environ_t env, int what);
char *env_vaptr(eval_environ_t env, size_t off);
-int expand_dataseg(eval_environ_t env, size_t count, const char *errtext);
+int expand_dataseg(eval_environ_t env, size_t count);
void *env_get_builtin_priv(eval_environ_t env, int id);
int builtin_priv_register(void *(*init)(void), void (*destroy)(void*),

Return to:

Send suggestions and report system problems to the System administrator.