load.c: add data boundary check for broken compiled binary.

parent aba3d427
......@@ -59,7 +59,7 @@ str_to_double(mrb_state *mrb, const char *p)
#endif
static mrb_bool
read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags, mrb_irep **irepp)
read_irep_record_1(mrb_state *mrb, const uint8_t *bin, const uint8_t *end, size_t *len, uint8_t flags, mrb_irep **irepp)
{
int i;
const uint8_t *src = bin;
......@@ -102,6 +102,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
if (SIZE_ERROR_MUL(irep->ilen, sizeof(mrb_code))) {
return FALSE;
}
if (src + data_len > end) return FALSE;
if ((flags & FLAG_SRC_MALLOC) == 0) {
irep->iseq = (mrb_code*)src;
irep->flags |= MRB_ISEQ_NO_FREE;
......@@ -117,6 +118,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
/* POOL BLOCK */
plen = bin_to_uint16(src); /* number of pool */
src += sizeof(uint16_t);
if (src > end) return FALSE;
if (plen > 0) {
if (SIZE_ERROR_MUL(plen, sizeof(mrb_value))) {
return FALSE;
......@@ -130,6 +132,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
switch (tt) { /* pool data */
case IREP_TT_INT32:
{
if (src + sizeof(uint32_t) > end) return FALSE;
mrb_int v = (int32_t)bin_to_uint32(src);
src += sizeof(uint32_t);
#ifdef MRB_64BIT
......@@ -144,6 +147,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
case IREP_TT_INT64:
#ifdef MRB_INT64
{
if (src + sizeof(uint32_t)*2 > end) return FALSE;
uint64_t i64 = bin_to_uint32(src);
src += sizeof(uint32_t);
i64 <<= 32;
......@@ -160,6 +164,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
case IREP_TT_BIGINT:
pool_data_len = bin_to_uint8(src); /* pool data length */
src += sizeof(uint8_t);
if (src + pool_data_len > end) return FALSE;
{
char *p;
pool[i].tt = IREP_TT_BIGINT;
......@@ -172,6 +177,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
case IREP_TT_FLOAT:
#ifndef MRB_NO_FLOAT
if (src + sizeof(double) > end) return FALSE;
pool[i].tt = tt;
pool[i].u.f = str_to_double(mrb, (const char*)src);
src += sizeof(double);
......@@ -183,6 +189,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
case IREP_TT_STR:
pool_data_len = bin_to_uint16(src); /* pool data length */
src += sizeof(uint16_t);
if (src + pool_data_len > end) return FALSE;
if (st) {
pool[i].tt = (pool_data_len<<2) | IREP_TT_SSTR;
pool[i].u.str = (const char*)src;
......@@ -208,6 +215,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
/* SYMS BLOCK */
irep->slen = bin_to_uint16(src); /* syms length */
src += sizeof(uint16_t);
if (src > end) return FALSE;
if (irep->slen > 0) {
if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) {
return FALSE;
......@@ -223,6 +231,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
continue;
}
if (src + snl > end) return FALSE;
if (flags & FLAG_SRC_MALLOC) {
syms[i] = mrb_intern(mrb, (char *)src, snl);
}
......@@ -242,10 +251,10 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
}
static mrb_bool
read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags, mrb_irep **irepp)
read_irep_record(mrb_state *mrb, const uint8_t *bin, const uint8_t *end, size_t *len, uint8_t flags, mrb_irep **irepp)
{
int ai = mrb_gc_arena_save(mrb);
mrb_bool readsuccess = read_irep_record_1(mrb, bin, len, flags, irepp);
mrb_bool readsuccess = read_irep_record_1(mrb, bin, end, len, flags, irepp);
mrb_irep **reps;
int i;
......@@ -261,7 +270,7 @@ read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags,
for (i=0; i<(*irepp)->rlen; i++) {
size_t rlen;
readsuccess = read_irep_record(mrb, bin, &rlen, flags, &reps[i]);
readsuccess = read_irep_record(mrb, bin, end, &rlen, flags, &reps[i]);
mrb_gc_arena_restore(mrb, ai);
if (!readsuccess) {
return FALSE;
......@@ -274,10 +283,9 @@ read_irep_record(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flags,
}
static mrb_irep*
read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags, struct RProc **proc)
read_section_irep(mrb_state *mrb, const uint8_t *bin, size_t size, uint8_t flags, struct RProc **proc)
{
size_t len;
if (size < sizeof(struct rite_section_irep_header)) return NULL;
/*
* This proc object keeps all the data in progress to avoid memory leaks
* if something goes wrong while reading irep.
......@@ -285,8 +293,9 @@ read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags, struct RPro
*proc = mrb_proc_new(mrb, NULL);
mrb_irep **irepp = (mrb_irep**)&(*proc)->body.irep;
size_t len;
bin += sizeof(struct rite_section_irep_header);
if (read_irep_record(mrb, bin, &len, flags, irepp)) {
if (read_irep_record(mrb, bin, bin+size, &len, flags, irepp)) {
return *irepp;
}
else {
......@@ -295,7 +304,7 @@ read_section_irep(mrb_state *mrb, const uint8_t *bin, uint8_t flags, struct RPro
}
static int
read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len)
read_debug_record(mrb_state *mrb, const uint8_t *start, const uint8_t *end, mrb_irep* irep, size_t *record_len, const mrb_sym *filenames, size_t filenames_len)
{
const uint8_t *bin = start;
ptrdiff_t diff;
......@@ -313,13 +322,15 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
bin += sizeof(uint32_t);
debug->flen = bin_to_uint16(bin);
debug->files = (mrb_irep_debug_info_file**)mrb_calloc(mrb, irep->debug_info->flen, sizeof(mrb_irep_debug_info*));
bin += sizeof(uint16_t);
if (bin > end) return MRB_DUMP_GENERAL_FAILURE;
debug->files = (mrb_irep_debug_info_file**)mrb_calloc(mrb, irep->debug_info->flen, sizeof(mrb_irep_debug_info*));
for (f_idx = 0; f_idx < debug->flen; ++f_idx) {
mrb_irep_debug_info_file *file;
uint16_t filename_idx;
if (bin > end) return MRB_DUMP_GENERAL_FAILURE;
file = (mrb_irep_debug_info_file *)mrb_calloc(mrb, 1, sizeof(*file));
debug->files[f_idx] = file;
......@@ -338,9 +349,10 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
bin += sizeof(uint8_t);
switch (file->line_type) {
case mrb_debug_line_ary: {
uint32_t l;
size_t l = sizeof(uint16_t) * (size_t)file->line_entry_count;
file->lines.ary = (uint16_t *)mrb_malloc(mrb, sizeof(uint16_t) * (size_t)(file->line_entry_count));
if (bin + l > end) return MRB_DUMP_GENERAL_FAILURE;
file->lines.ary = (uint16_t *)mrb_malloc(mrb, l);
for (l = 0; l < file->line_entry_count; ++l) {
file->lines.ary[l] = bin_to_uint16(bin);
bin += sizeof(uint16_t);
......@@ -348,11 +360,12 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
} break;
case mrb_debug_line_flat_map: {
uint32_t l;
size_t c = (size_t)file->line_entry_count;
size_t n = sizeof(mrb_irep_debug_info_line);
file->lines.flat_map = (mrb_irep_debug_info_line*)mrb_calloc(
mrb, (size_t)(file->line_entry_count), sizeof(mrb_irep_debug_info_line));
for (l = 0; l < file->line_entry_count; ++l) {
if (bin + c*n > end) return MRB_DUMP_GENERAL_FAILURE;
file->lines.flat_map = (mrb_irep_debug_info_line*)mrb_calloc(mrb, c, n);
for (size_t l = 0; l < file->line_entry_count; ++l) {
file->lines.flat_map[l].start_pos = bin_to_uint32(bin);
bin += sizeof(uint32_t);
file->lines.flat_map[l].line = bin_to_uint16(bin);
......@@ -361,7 +374,10 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
} break;
case mrb_debug_line_packed_map: {
file->lines.packed_map = (uint8_t*)mrb_calloc(mrb, 1, (size_t)file->line_entry_count);
size_t l = (size_t)file->line_entry_count;
if (bin + l > end) return MRB_DUMP_GENERAL_FAILURE;
file->lines.packed_map = (uint8_t*)mrb_calloc(mrb, 1, l);
memcpy(file->lines.packed_map, bin, file->line_entry_count);
bin += file->line_entry_count;
} break;
......@@ -381,7 +397,7 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
size_t len;
int ret;
ret = read_debug_record(mrb, bin, (mrb_irep*)irep->reps[i], &len, filenames, filenames_len);
ret = read_debug_record(mrb, bin, end, (mrb_irep*)irep->reps[i], &len, filenames, filenames_len);
if (ret != MRB_DUMP_OK) return ret;
bin += len;
}
......@@ -394,9 +410,10 @@ read_debug_record(mrb_state *mrb, const uint8_t *start, mrb_irep* irep, size_t *
}
static int
read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags)
read_section_debug(mrb_state *mrb, const uint8_t *start, size_t size, mrb_irep *irep, uint8_t flags)
{
const uint8_t *bin;
const uint8_t *end = start + size;
ptrdiff_t diff;
struct rite_section_debug_header *header;
uint16_t i;
......@@ -412,11 +429,16 @@ read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t
filenames_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
if (bin > end) return MRB_DUMP_GENERAL_FAILURE;
filenames_obj = mrb_str_new(mrb, NULL, sizeof(mrb_sym) * (size_t)filenames_len);
filenames = (mrb_sym*)RSTRING_PTR(filenames_obj);
for (i = 0; i < filenames_len; ++i) {
uint16_t f_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
if (bin + f_len > end) {
result = MRB_DUMP_GENERAL_FAILURE;
goto debug_exit;
}
if (flags & FLAG_SRC_MALLOC) {
filenames[i] = mrb_intern(mrb, (const char *)bin, (size_t)f_len);
}
......@@ -426,7 +448,7 @@ read_section_debug(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t
bin += f_len;
}
result = read_debug_record(mrb, bin, irep, &len, filenames, filenames_len);
result = read_debug_record(mrb, bin, end, irep, &len, filenames, filenames_len);
if (result != MRB_DUMP_OK) goto debug_exit;
bin += len;
......@@ -449,6 +471,7 @@ read_lv_record(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, size_t *rec
ptrdiff_t diff;
int i;
if (irep->nlocals == 0) return MRB_DUMP_GENERAL_FAILURE;
irep->lv = lv = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * (irep->nlocals - 1));
for (i = 0; i + 1 < irep->nlocals; ++i) {
......@@ -482,9 +505,10 @@ read_lv_record(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, size_t *rec
}
static int
read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t flags)
read_section_lv(mrb_state *mrb, const uint8_t *start, size_t size, mrb_irep *irep, uint8_t flags)
{
const uint8_t *bin;
const uint8_t *end = start + size;
ptrdiff_t diff;
struct rite_section_lv_header const *header;
uint32_t i;
......@@ -502,12 +526,13 @@ read_section_lv(mrb_state *mrb, const uint8_t *start, mrb_irep *irep, uint8_t fl
syms_len = bin_to_uint32(bin);
bin += sizeof(uint32_t);
if (bin > end) return MRB_DUMP_READ_FAULT;
syms_obj = mrb_str_new(mrb, NULL, sizeof(mrb_sym) * (size_t)syms_len);
syms = (mrb_sym*)RSTRING_PTR(syms_obj);
for (i = 0; i < syms_len; ++i) {
uint16_t const str_len = bin_to_uint16(bin);
bin += sizeof(uint16_t);
if (bin > end) return MRB_DUMP_READ_FAULT;
syms[i] = intern_func(mrb, (const char*)bin, str_len);
bin += str_len;
}
......@@ -580,20 +605,22 @@ read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags)
bin_size -= sizeof(struct rite_binary_header);
while (bin_size > sizeof(struct rite_section_header)) {
section_header = (const struct rite_section_header *)bin;
uint32_t section_size = bin_to_uint32(section_header->section_size);
if (bin_size < section_size) return NULL;
if (memcmp(section_header->section_ident, RITE_SECTION_IREP_IDENT, sizeof(section_header->section_ident)) == 0) {
irep = read_section_irep(mrb, bin, flags, &proc);
irep = read_section_irep(mrb, bin, bin_size, flags, &proc);
if (!irep) return NULL;
}
else if (memcmp(section_header->section_ident, RITE_SECTION_DEBUG_IDENT, sizeof(section_header->section_ident)) == 0) {
if (!irep) return NULL; /* corrupted data */
result = read_section_debug(mrb, bin, irep, flags);
result = read_section_debug(mrb, bin, bin_size, irep, flags);
if (result < MRB_DUMP_OK) {
return NULL;
}
}
else if (memcmp(section_header->section_ident, RITE_SECTION_LV_IDENT, sizeof(section_header->section_ident)) == 0) {
if (!irep) return NULL;
result = read_section_lv(mrb, bin, irep, flags);
result = read_section_lv(mrb, bin, bin_size, irep, flags);
if (result < MRB_DUMP_OK) {
return NULL;
}
......@@ -602,7 +629,6 @@ read_irep(mrb_state *mrb, const uint8_t *bin, size_t bufsize, uint8_t flags)
break;
}
uint32_t section_size = bin_to_uint32(section_header->section_size);
bin += section_size;
bin_size -= section_size;
}
......@@ -615,7 +641,7 @@ mrb_proc_read_irep(mrb_state *mrb, const uint8_t *bin)
{
uint8_t flags = mrb_ro_data_p((char*)bin) ? FLAG_SRC_STATIC : FLAG_SRC_MALLOC;
return read_irep(mrb, bin, (size_t)-1, flags);
return read_irep(mrb, bin, (size_t)UINT32_MAX, flags);
}
DEFINE_READ_IREP_FUNC(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment