Skip to content

Commit

Permalink
Remove the size limit for memory read and write
Browse files Browse the repository at this point in the history
Eliminate the maximum size restriction for uc_mem_read and uc_mem_write. This
change is required to support applications, such as LLVM CFI, that map or unmap
memory blocks with sizes equal to or greater than INT_MAX.
  • Loading branch information
secretnonempty committed Mar 10, 2023
1 parent 7b8c63d commit 65ea637
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 47 deletions.
4 changes: 2 additions & 2 deletions include/uc_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,10 @@ typedef struct {
typedef void (*reg_reset_t)(struct uc_struct *uc);

typedef bool (*uc_write_mem_t)(AddressSpace *as, hwaddr addr,
const uint8_t *buf, int len);
const uint8_t *buf, hwaddr len);

typedef bool (*uc_read_mem_t)(AddressSpace *as, hwaddr addr, uint8_t *buf,
int len);
hwaddr len);

typedef void (*uc_args_void_t)(void *);

Expand Down
4 changes: 2 additions & 2 deletions qemu/unicorn_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size);

// return true on success, false on failure
static inline bool cpu_physical_mem_read(AddressSpace *as, hwaddr addr,
uint8_t *buf, int len)
uint8_t *buf, hwaddr len)
{
return cpu_physical_memory_rw(as, addr, (void *)buf, len, 0);
}

static inline bool cpu_physical_mem_write(AddressSpace *as, hwaddr addr,
const uint8_t *buf, int len)
const uint8_t *buf, hwaddr len)
{
return cpu_physical_memory_rw(as, addr, (void *)buf, len, 1);
}
Expand Down
78 changes: 35 additions & 43 deletions uc.c
Original file line number Diff line number Diff line change
Expand Up @@ -547,14 +547,14 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value)

// check if a memory area is mapped
// this is complicated because an area can overlap adjacent blocks
static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size)
static bool check_mem_area(uc_engine *uc, uint64_t address, uint64_t size)
{
size_t count = 0, len;
uint64_t count = 0, len;

while (count < size) {
MemoryRegion *mr = memory_mapping(uc, address);
if (mr) {
len = (size_t)MIN(size - count, mr->end - address);
len = (uint64_t)MIN(size - count, mr->end - address);
count += len;
address += len;
} else { // this address is not mapped in yet
Expand All @@ -566,17 +566,13 @@ static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size)
}

UNICORN_EXPORT
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, uint64_t size)
{
size_t count = 0, len;
uint64_t count = 0, len;
uint8_t *bytes = _bytes;

UC_INIT(uc);

// qemu cpu_physical_memory_rw() size is an int
if (size > INT_MAX)
return UC_ERR_ARG;

if (uc->mem_redirect) {
address = uc->mem_redirect(address);
}
Expand All @@ -589,7 +585,7 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
while (count < size) {
MemoryRegion *mr = memory_mapping(uc, address);
if (mr) {
len = (size_t)MIN(size - count, mr->end - address);
len = (uint64_t)MIN(size - count, mr->end - address);
if (uc->read_mem(&uc->address_space_memory, address, bytes, len) ==
false) {
break;
Expand All @@ -611,17 +607,13 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)

UNICORN_EXPORT
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes,
size_t size)
uint64_t size)
{
size_t count = 0, len;
uint64_t count = 0, len;
const uint8_t *bytes = _bytes;

UC_INIT(uc);

// qemu cpu_physical_memory_rw() size is an int
if (size > INT_MAX)
return UC_ERR_ARG;

if (uc->mem_redirect) {
address = uc->mem_redirect(address);
}
Expand All @@ -641,7 +633,7 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes,
uc->readonly_mem(mr, false);
}

len = (size_t)MIN(size - count, mr->end - address);
len = (uint64_t)MIN(size - count, mr->end - address);
if (uc->write_mem(&uc->address_space_memory, address, bytes, len) ==
false) {
break;
Expand Down Expand Up @@ -956,7 +948,7 @@ static int bsearch_mapped_blocks(const uc_engine *uc, uint64_t address)
}

// find if a memory range overlaps with existing mapped regions
static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size)
static bool memory_overlap(struct uc_struct *uc, uint64_t begin, uint64_t size)
{
unsigned int i;
uint64_t end = begin + size - 1;
Expand All @@ -976,7 +968,7 @@ static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size)
}

// common setup/error checking shared between uc_mem_map and uc_mem_map_ptr
static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size,
static uc_err mem_map(uc_engine *uc, uint64_t address, uint64_t size,
uint32_t perms, MemoryRegion *block)
{
MemoryRegion **regions;
Expand Down Expand Up @@ -1008,7 +1000,7 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size,
return UC_ERR_OK;
}

static uc_err mem_map_check(uc_engine *uc, uint64_t address, size_t size,
static uc_err mem_map_check(uc_engine *uc, uint64_t address, uint64_t size,
uint32_t perms)
{
if (size == 0) {
Expand Down Expand Up @@ -1045,7 +1037,7 @@ static uc_err mem_map_check(uc_engine *uc, uint64_t address, size_t size,
}

UNICORN_EXPORT
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
uc_err uc_mem_map(uc_engine *uc, uint64_t address, uint64_t size, uint32_t perms)
{
uc_err res;

Expand All @@ -1065,7 +1057,7 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
}

UNICORN_EXPORT
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size,
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, uint64_t size,
uint32_t perms, void *ptr)
{
uc_err res;
Expand All @@ -1090,7 +1082,7 @@ uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size,
}

UNICORN_EXPORT
uc_err uc_mmio_map(uc_engine *uc, uint64_t address, size_t size,
uc_err uc_mmio_map(uc_engine *uc, uint64_t address, uint64_t size,
uc_cb_mmio_read_t read_cb, void *user_data_read,
uc_cb_mmio_write_t write_cb, void *user_data_write)
{
Expand All @@ -1117,10 +1109,10 @@ uc_err uc_mmio_map(uc_engine *uc, uint64_t address, size_t size,
// Generally used in prepartion for splitting a MemoryRegion.
static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)
{
uint8_t *block = (uint8_t *)g_malloc0((size_t)int128_get64(mr->size));
uint8_t *block = (uint8_t *)g_malloc0((uint64_t)int128_get64(mr->size));
if (block != NULL) {
uc_err err =
uc_mem_read(uc, mr->addr, block, (size_t)int128_get64(mr->size));
uc_mem_read(uc, mr->addr, block, (uint64_t)int128_get64(mr->size));
if (err != UC_ERR_OK) {
free(block);
block = NULL;
Expand All @@ -1136,10 +1128,10 @@ static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)
Note this function may be called recursively.
*/
static bool split_mmio_region(struct uc_struct *uc, MemoryRegion *mr,
uint64_t address, size_t size, bool do_delete)
uint64_t address, uint64_t size, bool do_delete)
{
uint64_t begin, end, chunk_end;
size_t l_size, r_size, m_size;
uint64_t l_size, r_size, m_size;
mmio_cbs backup;

chunk_end = address + size;
Expand All @@ -1166,7 +1158,7 @@ static bool split_mmio_region(struct uc_struct *uc, MemoryRegion *mr,
*/

// unmap this region first, then do split it later
if (uc_mem_unmap(uc, mr->addr, (size_t)int128_get64(mr->size)) !=
if (uc_mem_unmap(uc, mr->addr, (uint64_t)int128_get64(mr->size)) !=
UC_ERR_OK) {
return false;
}
Expand All @@ -1180,9 +1172,9 @@ static bool split_mmio_region(struct uc_struct *uc, MemoryRegion *mr,
}

// compute sub region sizes
l_size = (size_t)(address - begin);
r_size = (size_t)(end - chunk_end);
m_size = (size_t)(chunk_end - address);
l_size = (uint64_t)(address - begin);
r_size = (uint64_t)(end - chunk_end);
m_size = (uint64_t)(chunk_end - address);

if (l_size > 0) {
if (uc_mmio_map(uc, begin, l_size, backup.read, backup.user_data_read,
Expand Down Expand Up @@ -1225,12 +1217,12 @@ static bool split_mmio_region(struct uc_struct *uc, MemoryRegion *mr,
// TODO: investigate whether qemu region manipulation functions already offered
// this capability
static bool split_region(struct uc_struct *uc, MemoryRegion *mr,
uint64_t address, size_t size, bool do_delete)
uint64_t address, uint64_t size, bool do_delete)
{
uint8_t *backup;
uint32_t perms;
uint64_t begin, end, chunk_end;
size_t l_size, m_size, r_size;
uint64_t l_size, m_size, r_size;
RAMBlock *block = NULL;
bool prealloc = false;

Expand Down Expand Up @@ -1287,7 +1279,7 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr,
end = mr->end;

// unmap this region first, then do split it later
if (uc_mem_unmap(uc, mr->addr, (size_t)int128_get64(mr->size)) !=
if (uc_mem_unmap(uc, mr->addr, (uint64_t)int128_get64(mr->size)) !=
UC_ERR_OK) {
goto error;
}
Expand All @@ -1308,9 +1300,9 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr,
}

// compute sub region sizes
l_size = (size_t)(address - begin);
r_size = (size_t)(end - chunk_end);
m_size = (size_t)(chunk_end - address);
l_size = (uint64_t)(address - begin);
r_size = (uint64_t)(end - chunk_end);
m_size = (uint64_t)(chunk_end - address);

// If there are error in any of the below operations, things are too far
// gone at that point to recover. Could try to remap orignal region, but
Expand Down Expand Up @@ -1378,13 +1370,13 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr,
}

UNICORN_EXPORT
uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size,
uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, uint64_t size,
uint32_t perms)
{
MemoryRegion *mr;
uint64_t addr = address;
uint64_t pc;
size_t count, len;
uint64_t count, len;
bool remove_exec = false;

UC_INIT(uc);
Expand Down Expand Up @@ -1424,7 +1416,7 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size,
count = 0;
while (count < size) {
mr = memory_mapping(uc, addr);
len = (size_t)MIN(size - count, mr->end - addr);
len = (uint64_t)MIN(size - count, mr->end - addr);
if (mr->ram) {
if (!split_region(uc, mr, addr, len, false)) {
return UC_ERR_NOMEM;
Expand Down Expand Up @@ -1466,11 +1458,11 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size,
}

UNICORN_EXPORT
uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size)
uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, uint64_t size)
{
MemoryRegion *mr;
uint64_t addr;
size_t count, len;
uint64_t count, len;

UC_INIT(uc);

Expand Down Expand Up @@ -1504,7 +1496,7 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size)
count = 0;
while (count < size) {
mr = memory_mapping(uc, addr);
len = (size_t)MIN(size - count, mr->end - addr);
len = (uint64_t)MIN(size - count, mr->end - addr);
if (!mr->ram) {
if (!split_mmio_region(uc, mr, addr, len, true)) {
return UC_ERR_NOMEM;
Expand Down

0 comments on commit 65ea637

Please sign in to comment.