Fix misaligned access when reading irep; close #2630

Add padding bytes before iseq block that may be used as mrb_code[].
Note that dumped mrb format has changed.

Based on a patch from kimu_shu <alfvegardrisc@gmail.com>
parent 23db5331
...@@ -43,7 +43,7 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); ...@@ -43,7 +43,7 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*);
/* Rite Binary File header */ /* Rite Binary File header */
#define RITE_BINARY_IDENTIFIER "RITE" #define RITE_BINARY_IDENTIFIER "RITE"
#define RITE_BINARY_FORMAT_VER "0002" #define RITE_BINARY_FORMAT_VER "0003"
#define RITE_COMPILER_NAME "MATZ" #define RITE_COMPILER_NAME "MATZ"
#define RITE_COMPILER_VERSION "0000" #define RITE_COMPILER_VERSION "0000"
...@@ -56,6 +56,7 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*); ...@@ -56,6 +56,7 @@ MRB_API mrb_irep *mrb_read_irep(mrb_state*, const uint8_t*);
#define RITE_SECTION_LV_IDENTIFIER "LVAR" #define RITE_SECTION_LV_IDENTIFIER "LVAR"
#define MRB_DUMP_DEFAULT_STR_LEN 128 #define MRB_DUMP_DEFAULT_STR_LEN 128
#define MRB_DUMP_ALIGNMENT sizeof(uint32_t)
/* binary header */ /* binary header */
struct rite_binary_header { struct rite_binary_header {
......
...@@ -24,6 +24,17 @@ static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep); ...@@ -24,6 +24,17 @@ static size_t get_irep_record_size_1(mrb_state *mrb, mrb_irep *irep);
# error This code cannot be built on your environment. # error This code cannot be built on your environment.
#endif #endif
static size_t
write_padding(uint8_t *buf)
{
const size_t align = MRB_DUMP_ALIGNMENT;
size_t pad_len = -(intptr_t)buf & (align-1);
if (pad_len > 0) {
memset(buf, 0, pad_len);
}
return pad_len;
}
static size_t static size_t
get_irep_header_size(mrb_state *mrb) get_irep_header_size(mrb_state *mrb)
{ {
...@@ -55,6 +66,7 @@ get_iseq_block_size(mrb_state *mrb, mrb_irep *irep) ...@@ -55,6 +66,7 @@ get_iseq_block_size(mrb_state *mrb, mrb_irep *irep)
size_t size = 0; size_t size = 0;
size += sizeof(uint32_t); /* ilen */ size += sizeof(uint32_t); /* ilen */
size += sizeof(uint32_t); /* max padding */
size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */ size += sizeof(uint32_t) * irep->ilen; /* iseq(n) */
return size; return size;
...@@ -67,6 +79,7 @@ write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags) ...@@ -67,6 +79,7 @@ write_iseq_block(mrb_state *mrb, mrb_irep *irep, uint8_t *buf, uint8_t flags)
uint32_t iseq_no; uint32_t iseq_no;
cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */ cur += uint32_to_bin(irep->ilen, cur); /* number of opcode */
cur += write_padding(cur);
if (flags & FLAG_BYTEORDER_NATIVE) { if (flags & FLAG_BYTEORDER_NATIVE) {
memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code)); memcpy(cur, irep->iseq, irep->ilen * sizeof(mrb_code));
cur += irep->ilen * sizeof(mrb_code); cur += irep->ilen * sizeof(mrb_code);
...@@ -272,9 +285,10 @@ get_irep_record_size(mrb_state *mrb, mrb_irep *irep) ...@@ -272,9 +285,10 @@ get_irep_record_size(mrb_state *mrb, mrb_irep *irep)
} }
static int static int
write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_record_size, uint8_t flags) write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *irep_record_size, uint8_t flags)
{ {
uint32_t i; uint32_t i;
uint8_t *src = bin;
if (irep == NULL) { if (irep == NULL) {
return MRB_DUMP_INVALID_IREP; return MRB_DUMP_INVALID_IREP;
...@@ -285,8 +299,6 @@ write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_rec ...@@ -285,8 +299,6 @@ write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_rec
return MRB_DUMP_GENERAL_FAILURE; return MRB_DUMP_GENERAL_FAILURE;
} }
memset(bin, 0, *irep_record_size);
bin += write_irep_header(mrb, irep, bin); bin += write_irep_header(mrb, irep, bin);
bin += write_iseq_block(mrb, irep, bin, flags); bin += write_iseq_block(mrb, irep, bin, flags);
bin += write_pool_block(mrb, irep, bin); bin += write_pool_block(mrb, irep, bin);
...@@ -300,9 +312,9 @@ write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_rec ...@@ -300,9 +312,9 @@ write_irep_record(mrb_state *mrb, mrb_irep *irep, uint8_t* bin, size_t *irep_rec
if (result != MRB_DUMP_OK) { if (result != MRB_DUMP_OK) {
return result; return result;
} }
*irep_record_size += rsize;
bin += rsize; bin += rsize;
} }
*irep_record_size = bin - src;
return MRB_DUMP_OK; return MRB_DUMP_OK;
} }
...@@ -334,10 +346,9 @@ write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin) ...@@ -334,10 +346,9 @@ write_section_irep_header(mrb_state *mrb, size_t section_size, uint8_t *bin)
} }
static int static int
write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, uint8_t flags) write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, size_t *len_p, uint8_t flags)
{ {
int result; int result;
size_t section_size = 0; /* size of irep record */
size_t rsize = 0; size_t rsize = 0;
uint8_t *cur = bin; uint8_t *cur = bin;
...@@ -346,14 +357,13 @@ write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, uint8_t flags) ...@@ -346,14 +357,13 @@ write_section_irep(mrb_state *mrb, mrb_irep *irep, uint8_t *bin, uint8_t flags)
} }
cur += sizeof(struct rite_section_irep_header); cur += sizeof(struct rite_section_irep_header);
section_size += sizeof(struct rite_section_irep_header);
result = write_irep_record(mrb, irep, cur, &rsize, flags); result = write_irep_record(mrb, irep, cur, &rsize, flags);
if (result != MRB_DUMP_OK) { if (result != MRB_DUMP_OK) {
return result; return result;
} }
section_size += rsize; *len_p = cur - bin + rsize;
write_section_irep_header(mrb, section_size, bin); write_section_irep_header(mrb, *len_p, bin);
return MRB_DUMP_OK; return MRB_DUMP_OK;
} }
...@@ -866,6 +876,7 @@ static int ...@@ -866,6 +876,7 @@ static int
dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size, uint8_t flags) dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t *bin_size, uint8_t flags)
{ {
int result = MRB_DUMP_GENERAL_FAILURE; int result = MRB_DUMP_GENERAL_FAILURE;
size_t malloc_size;
size_t section_irep_size; size_t section_irep_size;
size_t section_lineno_size = 0, section_lv_size = 0; size_t section_lineno_size = 0, section_lv_size = 0;
uint8_t *cur = NULL; uint8_t *cur = NULL;
...@@ -906,17 +917,20 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t ...@@ -906,17 +917,20 @@ dump_irep(mrb_state *mrb, mrb_irep *irep, int debug_info, uint8_t **bin, size_t
section_lv_size += get_lv_section_size(mrb, irep, lv_syms, lv_syms_len); section_lv_size += get_lv_section_size(mrb, irep, lv_syms, lv_syms_len);
} }
*bin_size = sizeof(struct rite_binary_header) + malloc_size = sizeof(struct rite_binary_header) +
section_irep_size + section_lineno_size + section_lv_size + section_irep_size + section_lineno_size + section_lv_size +
sizeof(struct rite_binary_footer); sizeof(struct rite_binary_footer);
cur = *bin = (uint8_t*)mrb_malloc(mrb, *bin_size); cur = *bin = (uint8_t*)mrb_malloc(mrb, malloc_size);
cur += sizeof(struct rite_binary_header); cur += sizeof(struct rite_binary_header);
result = write_section_irep(mrb, irep, cur, flags); result = write_section_irep(mrb, irep, cur, &section_irep_size, flags);
if (result != MRB_DUMP_OK) { if (result != MRB_DUMP_OK) {
goto error_exit; goto error_exit;
} }
cur += section_irep_size; cur += section_irep_size;
*bin_size = sizeof(struct rite_binary_header) +
section_irep_size + section_lineno_size + section_lv_size +
sizeof(struct rite_binary_footer);
/* write DEBUG section */ /* write DEBUG section */
if (debug_info) { if (debug_info) {
......
...@@ -31,6 +31,13 @@ ...@@ -31,6 +31,13 @@
# error This code cannot be built on your environment. # error This code cannot be built on your environment.
#endif #endif
static size_t
skip_padding(const uint8_t *buf)
{
const size_t align = MRB_DUMP_ALIGNMENT;
return -(intptr_t)buf & (align-1);
}
static size_t static size_t
offset_crc_body(void) offset_crc_body(void)
{ {
...@@ -68,6 +75,8 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag ...@@ -68,6 +75,8 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag
/* ISEQ BLOCK */ /* ISEQ BLOCK */
irep->ilen = (size_t)bin_to_uint32(src); irep->ilen = (size_t)bin_to_uint32(src);
src += sizeof(uint32_t); src += sizeof(uint32_t);
src += skip_padding(src);
if (irep->ilen > 0) { if (irep->ilen > 0) {
if (SIZE_ERROR_MUL(sizeof(mrb_code), irep->ilen)) { if (SIZE_ERROR_MUL(sizeof(mrb_code), irep->ilen)) {
return NULL; return NULL;
......
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