Skip to content

Commit

Permalink
fix: Buffer overflow in string.format when called with malformed args (
Browse files Browse the repository at this point in the history
…#419)

The current format specifier is stored in a small buffer on the stack, but the maxium length was not enforced, so a buffer overflow was possible. Added a check to actually limit it's length.

Added a test case to verify an ASAN crash does not occur.
  • Loading branch information
alufers authored Apr 15, 2024
1 parent 6e1c947 commit 6e26c4b
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 4 deletions.
13 changes: 9 additions & 4 deletions src/be_strlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ static const char* skip2dig(const char *s)
return s;
}

static const char* get_mode(const char *str, char *buf)
static const char* get_mode(const char *str, char *buf, size_t buf_len)
{
const char *p = str;
while (*p && strchr(FLAGES, *p)) { /* skip flags */
Expand All @@ -560,8 +560,13 @@ static const char* get_mode(const char *str, char *buf)
p = skip2dig(++p); /* skip width (2 digits at most) */
}
*(buf++) = '%';
strncpy(buf, str, p - str + 1);
buf[p - str + 1] = '\0';
size_t mode_size = p - str + 1;
/* Leave 2 bytes for the leading % and the trailing '\0' */
if (mode_size > buf_len - 2) {
mode_size = buf_len - 2;
}
strncpy(buf, str, mode_size);
buf[mode_size] = '\0';
return p;
}

Expand Down Expand Up @@ -632,7 +637,7 @@ int be_str_format(bvm *vm)
}
pushstr(vm, format, p - format);
concat2(vm);
p = get_mode(p + 1, mode);
p = get_mode(p + 1, mode, sizeof(mode));
buf[0] = '\0';
if (index > top && *p != '%') {
be_raise(vm, "runtime_error", be_pushfstring(vm,
Expand Down
3 changes: 3 additions & 0 deletions tests/string.be
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,9 @@ assert(string.format("%s", false) == 'false')

assert(string.format("%q", "\ntest") == '\'\\ntest\'')

# corrupt format string should not crash the VM
string.format("%0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f", 3.5)

# format is now synonym to string.format
assert(format == string.format)
assert(format("%.1f", 3) == '3.0')
Expand Down

0 comments on commit 6e26c4b

Please sign in to comment.