Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

io: return error when reading/writing to unmapped memory #3323

Merged
merged 12 commits into from
Feb 11, 2023
25 changes: 12 additions & 13 deletions librz/analysis/esil/esil.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,10 +314,8 @@ static int internal_esil_mem_write_no_null(RzAnalysisEsil *esil, ut64 addr, cons
}

RZ_API int rz_analysis_esil_mem_write(RzAnalysisEsil *esil, ut64 addr, const ut8 *buf, int len) {
rz_return_val_if_fail(esil && buf, 0);
int ret = 0;
if (!buf || !esil) {
return 0;
}
addr &= esil->addrmask;
if (esil->cb.hook_mem_write) {
ret = esil->cb.hook_mem_write(esil, addr, buf, len);
Expand Down Expand Up @@ -1809,14 +1807,13 @@ static bool esil_poke_n(RzAnalysisEsil *esil, int bits) {
src2 = rz_analysis_esil_pop(esil);
if (src2 && rz_analysis_esil_get_parm(esil, src2, &num2)) {
rz_write_ble(b, num, esil->analysis->big_endian, 64);
ret = rz_analysis_esil_mem_write(esil, addr, b, bytes);
if (ret == 0) {
rz_write_ble(b, num2, esil->analysis->big_endian, 64);
ret = rz_analysis_esil_mem_write(esil, addr + 8, b, bytes);
}
rz_analysis_esil_mem_write(esil, addr, b, bytes);
rz_write_ble(b, num2, esil->analysis->big_endian, 64);
rz_analysis_esil_mem_write(esil, addr + 8, b, bytes);
ret = true;
goto out;
}
ret = -1;
ret = false;
goto out;
}
// this is a internal peek performed before a poke
Expand All @@ -1831,7 +1828,8 @@ static bool esil_poke_n(RzAnalysisEsil *esil, int bits) {
esil->lastsz = bits;
num = num & bitmask;
rz_write_ble(b, num, esil->analysis->big_endian, bits);
ret = rz_analysis_esil_mem_write(esil, addr, b, bytes);
rz_analysis_esil_mem_write(esil, addr, b, bytes);
ret = true;
}
}
out:
Expand Down Expand Up @@ -1931,23 +1929,24 @@ static bool esil_peek_n(RzAnalysisEsil *esil, int bits) {
if (dst && isregornum(esil, dst, &addr)) {
if (bits == 128) {
ut8 a[sizeof(ut64) * 2] = { 0 };
ret = rz_analysis_esil_mem_read(esil, addr, a, bytes);
rz_analysis_esil_mem_read(esil, addr, a, bytes);
ut64 b = rz_read_ble(a, esil->analysis->big_endian, bits);
ut64 c = rz_read_ble(a + 8, esil->analysis->big_endian, bits);
rz_strf(res, "0x%" PFMT64x, b);
rz_analysis_esil_push(esil, res);
rz_strf(res, "0x%" PFMT64x, c);
rz_analysis_esil_push(esil, res);
free(dst);
return ret;
return true;
}
ut64 bitmask = genmask(bits - 1);
ut8 a[sizeof(ut64)] = { 0 };
ret = rz_analysis_esil_mem_read(esil, addr, a, bytes);
rz_analysis_esil_mem_read(esil, addr, a, bytes);
ut64 b = rz_read_ble(a, esil->analysis->big_endian, bits);
rz_strf(res, "0x%" PFMT64x, b & bitmask);
rz_analysis_esil_push(esil, res);
esil->lastsz = bits;
ret = true;
}
free(dst);
return ret;
Expand Down
6 changes: 5 additions & 1 deletion librz/bin/format/mach0/dyldcache_rebase.c
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,11 @@ static ut64 buf_get_size(RzBuffer *b) {

static st64 buf_seek(RzBuffer *b, st64 addr, int whence) {
BufCtx *ctx = b->priv;
return ctx->off = rz_seek_offset(ctx->off, rz_buf_size(b), addr, whence);
st64 val = rz_seek_offset(ctx->off, rz_buf_size(b), addr, whence);
if (val == -1) {
return -1;
}
return ctx->off = (ut64)val;
}

static ut8 *buf_get_whole_buf(RzBuffer *b, ut64 *sz) {
Expand Down
2 changes: 1 addition & 1 deletion librz/core/cil.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ static void initialize_stack(RzCore *core, ut64 addr, ut64 size) {
break;
case 'z': // "zero"
case '0':
rz_core_cmdf(core, "wow 00 @ 0x%" PFMT64x "!0x%" PFMT64x, addr + i, left);
rz_core_cmdf(core, "wb 00 @ 0x%" PFMT64x "!0x%" PFMT64x, addr + i, left);
break;
}
}
Expand Down
1 change: 0 additions & 1 deletion librz/core/cio.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ RZ_API void rz_core_seek_arch_bits(RzCore *core, ut64 addr) {
}
}

// TODO: kill this wrapper
RZ_API bool rz_core_write_at(RzCore *core, ut64 addr, const ut8 *buf, int size) {
rz_return_val_if_fail(core && buf && addr != UT64_MAX, false);
if (size < 1) {
Expand Down
2 changes: 1 addition & 1 deletion librz/core/cmd/cmd_resize.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ RZ_IPI RzCmdStatus rz_resize_handler(RzCore *core, int argc, const char **argv,
if (!core->file) {
return RZ_CMD_STATUS_ERROR;
}
ut64 oldsize = (core->file) ? rz_io_fd_size(core->io, core->file->fd) : 0;
ut64 oldsize = rz_io_fd_size(core->io, core->file->fd);
if (oldsize == -1) {
return RZ_CMD_STATUS_ERROR;
}
Expand Down
4 changes: 2 additions & 2 deletions librz/core/cmd/cmd_write.c
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ RZ_IPI RzCmdStatus rz_write_random_handler(RzCore *core, int argc, const char **
return RZ_CMD_STATUS_ERROR;
}
size_t length = rz_num_math(core->num, argv[1]);
return rz_core_write_random_at(core, core->offset, length) ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
return bool2status(rz_core_write_random_at(core, core->offset, length));
}

RZ_IPI RzCmdStatus rz_write_handler(RzCore *core, int argc, const char **argv) {
Expand All @@ -443,7 +443,7 @@ RZ_IPI RzCmdStatus rz_write_wide_string_handler(RzCore *core, int argc, const ch
}

RZ_IPI RzCmdStatus rz_write_hex_handler(RzCore *core, int argc, const char **argv) {
return rz_core_write_hexpair(core, core->offset, argv[1]) > 0 ? RZ_CMD_STATUS_OK : RZ_CMD_STATUS_ERROR;
return bool2status(rz_core_write_hexpair(core, core->offset, argv[1]) > 0);
}

RZ_IPI RzCmdStatus rz_write_hex_from_file_handler(RzCore *core, int argc, const char **argv) {
Expand Down
2 changes: 1 addition & 1 deletion librz/core/tui/panels.c
Original file line number Diff line number Diff line change
Expand Up @@ -3207,7 +3207,7 @@ int __assemble_cb(void *user) {

int __fill_cb(void *user) {
RzCore *core = (RzCore *)user;
__add_cmdf_panel(core, "Fill with: ", "wow %s");
__add_cmdf_panel(core, "Fill with: ", "wb %s");
return 0;
}

Expand Down
12 changes: 8 additions & 4 deletions librz/core/tui/visual.c
Original file line number Diff line number Diff line change
Expand Up @@ -1825,9 +1825,13 @@ static bool insert_mode_enabled(RzCore *core) {
case 'f':
if (visual->insertNibble != -1) {
char hexpair[3] = { visual->insertNibble, ch, 0 };
rz_core_write_hexpair(core, core->offset + core->print->cur, hexpair);
core->print->cur++;
bool res = rz_core_write_hexpair(core, core->offset + core->print->cur, hexpair);
visual->insertNibble = -1;
if (!res) {
RZ_LOG_ERROR("Cannot write at address %" PFMT64x ".\n", core->offset + core->print->cur);
break;
}
core->print->cur++;
} else {
visual->insertNibble = ch;
}
Expand Down Expand Up @@ -2449,7 +2453,7 @@ RZ_IPI int rz_core_visual_cmd(RzCore *core, const char *arg) {
rz_cons_flush();
rz_cons_set_raw(0);
if (ch == 'I') {
strcpy(buf, "wow ");
strcpy(buf, "wb ");
rz_line_set_prompt("insert hexpair block: ");
if (rz_cons_fgets(buf + 4, sizeof(buf) - 4, 0, NULL) < 0) {
buf[0] = '\0';
Expand Down Expand Up @@ -2477,7 +2481,7 @@ RZ_IPI int rz_core_visual_cmd(RzCore *core, const char *arg) {
if (core->print->ocur != -1) {
int bs = RZ_ABS(core->print->cur - core->print->ocur) + 1;
core->blocksize = bs;
strcpy(buf, "wow ");
strcpy(buf, "wb ");
} else {
strcpy(buf, "wx ");
}
Expand Down
17 changes: 13 additions & 4 deletions librz/include/rz_util/rz_buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,17 +64,26 @@ typedef enum {
/* utils */

/// change cur according to addr and whence (RZ_BUF_SET/RZ_BUF_CUR/RZ_BUF_END)
static inline ut64 rz_seek_offset(ut64 cur, ut64 length, st64 addr, int whence) {
static inline st64 rz_seek_offset(ut64 cur, ut64 length, st64 addr, int whence) {
switch (whence) {
case RZ_BUF_CUR:
return cur + (ut64)addr;
if (ST64_ADD_OVFCHK((st64)cur, addr)) {
return -1;
}
return cur + addr;
case RZ_BUF_SET:
if ((st64)addr < 0) {
return -1;
}
return addr;
case RZ_BUF_END:
return length + (ut64)addr;
if (ST64_ADD_OVFCHK((st64)length, addr)) {
return -1;
}
return length + addr;
default:
rz_warn_if_reached();
return cur;
return -1;
}
}

Expand Down
12 changes: 5 additions & 7 deletions librz/io/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ static st64 on_map_skyline(RzIO *io, ut64 vaddr, ut8 *buf, int len, int match_fl
RzVector *skyline = &io->map_skyline.v;
ut64 addr = vaddr;
size_t i;
bool ret = true, wrap = !prefix_mode && vaddr + len < vaddr;
bool ret = false, wrap = !prefix_mode && vaddr + len < vaddr;
#define CMP(addr, part) ((addr) < rz_itv_end(((RzSkylineItem *)(part))->itv) - 1 ? -1 : (addr) > rz_itv_end(((RzSkylineItem *)(part))->itv) - 1 ? 1 \
: 0)
// Let i be the first skyline part whose right endpoint > addr
Expand All @@ -49,7 +49,7 @@ static st64 on_map_skyline(RzIO *io, ut64 vaddr, ut8 *buf, int len, int match_fl
while (i < rz_vector_len(skyline)) {
const RzSkylineItem *part = rz_vector_index_ptr(skyline, i);
// Right endpoint <= addr
if (rz_itv_end(part->itv) - 1 < addr) {
if (rz_itv_end(part->itv) == 0 || rz_itv_end(part->itv) - 1 < addr) {
i++;
if (wrap && i == rz_vector_len(skyline)) {
wrap = false;
Expand Down Expand Up @@ -84,9 +84,7 @@ static st64 on_map_skyline(RzIO *io, ut64 vaddr, ut8 *buf, int len, int match_fl
break;
}
} else {
if (result != len1) {
ret = false;
}
ret = result == len1;
addr += len1;
}
} else if (prefix_mode) {
Expand Down Expand Up @@ -306,7 +304,7 @@ RZ_API bool rz_io_read_at(RzIO *io, ut64 addr, ut8 *buf, int len) {
? rz_io_vread_at_mapped(io, addr, buf, len)
: rz_io_pread_at(io, addr, buf, len) > 0;
if (io->cached & RZ_PERM_R) {
(void)rz_io_cache_read(io, addr, buf, len);
ret |= rz_io_cache_read(io, addr, buf, len);
}
return ret;
}
Expand All @@ -327,7 +325,7 @@ RZ_API bool rz_io_read_at_mapped(RzIO *io, ut64 addr, ut8 *buf, int len) {
ret = rz_io_pread_at(io, addr, buf, len) > 0;
}
if (io->cached & RZ_PERM_R) {
(void)rz_io_cache_read(io, addr, buf, len);
ret |= rz_io_cache_read(io, addr, buf, len);
}
return ret;
}
Expand Down
6 changes: 4 additions & 2 deletions librz/io/io_desc.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,14 +349,16 @@ RZ_API bool rz_io_desc_get_base(RzIODesc *desc, ut64 *base) {
}

RZ_API int rz_io_desc_read_at(RzIODesc *desc, ut64 addr, ut8 *buf, int len) {
if (desc && buf && (rz_io_desc_seek(desc, addr, RZ_IO_SEEK_SET) == addr)) {
ut64 val = rz_io_desc_seek(desc, addr, RZ_IO_SEEK_SET);
if (desc && buf && val != UT64_MAX && val == addr) {
return rz_io_desc_read(desc, buf, len);
}
return 0;
}

RZ_API int rz_io_desc_write_at(RzIODesc *desc, ut64 addr, const ut8 *buf, int len) {
if (desc && buf && (rz_io_desc_seek(desc, addr, RZ_IO_SEEK_SET) == addr)) {
ut64 val = rz_io_desc_seek(desc, addr, RZ_IO_SEEK_SET);
if (desc && buf && val != UT64_MAX && val == addr) {
return rz_io_desc_write(desc, buf, len);
}
return 0;
Expand Down
7 changes: 5 additions & 2 deletions librz/io/p/io_default.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,11 @@ static ut64 rz_io_def_mmap_seek(RzIO *io, RzIOMMapFileObj *mmo, ut64 offset, int
// NOTE: io->off should not be set here and code outside RzIO should not
// rely on it to get the current seek. They should use `rz_io_seek` instead.
// Keep it here until all use cases of io->off are converted.
io->off = rz_buf_seek(mmo->buf, offset, iowhence2buf(whence));
return io->off;
st64 val = rz_buf_seek(mmo->buf, offset, iowhence2buf(whence));
if (val == -1) {
return -1;
}
return io->off = val;
}

static void rz_io_def_mmap_free(RzIOMMapFileObj *mmo) {
Expand Down
5 changes: 3 additions & 2 deletions librz/util/buf_bytes.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,11 @@ static ut64 buf_bytes_get_size(RzBuffer *b) {

static st64 buf_bytes_seek(RzBuffer *b, st64 addr, int whence) {
struct buf_bytes_priv *priv = get_priv_bytes(b);
if (addr < 0 && (-addr) > (st64)priv->offset) {
st64 val = rz_seek_offset(priv->offset, priv->length, addr, whence);
if (val == -1) {
return -1;
}
return priv->offset = rz_seek_offset(priv->offset, priv->length, addr, whence);
return priv->offset = val;
}

static ut8 *buf_bytes_get_whole_buf(RzBuffer *b, ut64 *sz) {
Expand Down
6 changes: 5 additions & 1 deletion librz/util/buf_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,11 @@ static bool buf_io_fini(RzBuffer *b) {

static st64 buf_io_seek(RzBuffer *b, st64 addr, int whence) {
BufIOPriv *priv = b->priv;
priv->offset = rz_seek_offset(priv->offset, 0, addr, whence);
st64 val = rz_seek_offset(priv->offset, 0, addr, whence);
if (val == -1) {
return -1;
}
priv->offset = val;
// can't express the seek right if the highest bit is set,
// but at least tell the caller there was no error:
return RZ_MIN(priv->offset, ST64_MAX);
Expand Down
4 changes: 2 additions & 2 deletions test/db/cmd/cmd_open
Original file line number Diff line number Diff line change
Expand Up @@ -319,12 +319,12 @@ EXPECT=<<EOF
EOF
RUN

NAME=oC ob fix
NAME=malloc ob fix
FILE=--
CMDS=<<EOF
e asm.arch=x86
e asm.bits=64
oC 1024
o malloc://1024
obl
EOF
EXPECT=<<EOF
Expand Down
2 changes: 0 additions & 2 deletions test/db/cmd/cmd_pde
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ EXPECT=<<EOF
0x0001018c ldr lr, [pc, 4]
0x00010190 add lr, pc, lr
0x00010194 ldr pc, [lr, 8]!
0x00000000 cpsr:
0x00000000 invalid
EOF
RUN

Expand Down
10 changes: 5 additions & 5 deletions test/unit/test_core_bin.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ bool test_map(void) {

ut8 buf[8];
r = rz_io_read_at(core->io, 0, buf, sizeof(buf));
mu_assert_true(r, "io read");
mu_assert_false(r, "io read");
mu_assert_memeq(buf, (const ut8 *)"\xff\xff\xff\xff\xff\xff\xff\xff", 8, "unmapped read");
r = rz_io_read_at(core->io, 0xfe, buf, sizeof(buf));
mu_assert_true(r, "io read");
Expand Down Expand Up @@ -253,10 +253,10 @@ bool test_cfile_close(void) {

ut8 buf[8];
r = rz_io_read_at(core->io, 0xfe, buf, sizeof(buf));
mu_assert_true(r, "io read");
mu_assert_false(r, "io read");
mu_assert_memeq(buf, (const ut8 *)"\xff\xff\xff\xff\xff\xff\xff\xff", 8, "direct map read after close");
r = rz_io_read_at(core->io, 0x22e, buf, sizeof(buf));
mu_assert_true(r, "io read");
mu_assert_false(r, "io read");
mu_assert_memeq(buf, (const ut8 *)"\xff\xff\xff\xff\xff\xff\xff\xff", 8, "direct map read with zeroes end after close");

rz_core_free(core);
Expand Down Expand Up @@ -498,7 +498,7 @@ bool test_cfile_close_manual_vfile_fd(void) {
mu_assert_eq(rz_pvector_len(&core->io->maps), 0, "io maps count");

r = rz_io_read_at(core->io, 0x8000, buf, sizeof(buf));
mu_assert_true(r, "io read");
mu_assert_false(r, "io read");
mu_assert_memeq(buf, (const ut8 *)"\xff\xff\xff\xff\xff\xff\xff\xff", 8, "manual vfile map read");

rz_core_free(core);
Expand Down Expand Up @@ -538,7 +538,7 @@ bool test_cfile_close_manual_vfile_map(void) {
// now everything should be gone, including the vfile map which indirectly pointed into the core file's vfile fd
mu_assert_eq(rz_pvector_len(&core->io->maps), 0, "io maps count");
r = rz_io_read_at(core->io, 0x8000, buf, sizeof(buf));
mu_assert_true(r, "io read");
mu_assert_false(r, "io read");
mu_assert_memeq(buf, (const ut8 *)"\xff\xff\xff\xff\xff\xff\xff\xff", 8, "manual vfile map read");

rz_core_free(core);
Expand Down
Loading