Respect visible read-only IO map boundaries

This commit is contained in:
pancake committed 2026-11-07 14:21:04 +01:00
1 parent 21e49ad932
commit f30f21c13f
2 files changed
+80 -68

No files matched your search

+47 -68
View File
@@ -5,7 +5,8 @@
#include "R2LoadImage.h"
#include "R2Utils.h"
#include <cstring>
#include <memory>
#include <new>
R2LoadImage::R2LoadImage(RCoreMutex *coreMutex, AddrSpaceManager *addr_space_manager) : LoadImage("radare2_program"),
coreMutex(coreMutex),
@@ -26,66 +27,59 @@ string R2LoadImage::getArchType() const {
void R2LoadImage::adjustVma(long adjust) {
throw LowlevelError("Cannot adjust radare2 virtual memory");
}
static bool isptr(const ut8 *p, size_t remain) {
if (remain < sizeof(ut32)) {
return false;
static void addRangesWithPointers(RIO *io, RangeList &list, AddrSpace *space, ut64 begin, int size, int bits) {
std::unique_ptr<ut8[]> buf (new (std::nothrow) ut8[size]);
if (!buf) {
return;
}
ut32 ptr = 0;
memcpy (&ptr, p, sizeof(ptr));
if (ptr < 0x1000) {
return false;
const int nread = r_io_nread_at (io, begin, buf.get (), size);
const int width = bits / 8;
const ut64 maxptr = bits == 64? UT64_MAX: UT32_MAX;
int start = 0;
int i = 0;
for (; i <= nread - width; i += width) {
const ut64 ptr = r_read_ble (buf.get () + i, space->isBigEndian (), bits);
if (ptr < 0x1000 || ptr == maxptr) {
if (start < i) {
list.insertRange (space, begin + start, begin + i - 1);
}
start = i + width;
}
}
if (start < i) {
list.insertRange (space, begin + start, begin + i - 1);
}
return ptr != UT32_MAX;
}
static void addRangesWithPointers(RCoreLock &core, RangeList &list, AddrSpace *space) {
static void addReadonlyMapRanges(RCoreLock &core, RangeList &list, AddrSpace *space, bool scan) {
RIO *io = core->io;
RIOBank *bank = r_io_bank_get (io, io->bank);
r_list_foreach_cpp<RIOMapRef>(bank->maprefs, [&](RIOMapRef *mapref) {
RIOMap *map = r_io_map_get (io, mapref->id);
ut64 begin = r_io_map_begin (map);
ut64 end = r_io_map_end (map);
if (map->perm & R_PERM_W) {
return;
if (!io->va || !bank) {
return;
}
// The submap tree only includes ranges visible after applying map priority.
r_io_bank_drain (io, io->bank);
const int bits = core->rasm->config->bits == 64? 64: 32;
const int width = bits / 8;
RRBNode *node;
RIOSubMap *submap;
r_crbtree_foreach (bank->submaps, node, RIOSubMap, submap) {
RIOMap *map = r_io_map_get_by_ref (io, &submap->mapref);
if (!map || !(map->perm & R_PERM_R) || (map->perm & R_PERM_W)) {
continue;
}
ut64 fin = end - begin;
if (fin > 0xffffff) {
list.insertRange(space, begin, end);
return;
}
ut8 *buf = (ut8 *)malloc (fin);
if (!buf) {
list.insertRange(space, begin, end);
return;
}
r_io_read_at (io, begin, buf, fin);
ut64 base = begin;
ut64 basefin = begin;
ut8 *data = buf;
bool hasdata = false;
int inc = (core->rasm->config->bits == 64)? 8: 4;
for (ut64 i = 0; i < fin; i += inc) {
basefin = begin + i;
if (isptr (data + i, fin - i)) {
// eprintf ("valid %llx\n", data[i]);
hasdata = true;
} else {
if (hasdata) {
// eprintf ("0 append %llx %llx because of 0x%llx\n", base, basefin, *((ut64*)(data +i)));
if (base > 0) {
list.insertRange(space, base, basefin); // begin, end);
}
hasdata = false;
base = basefin;
}
const ut64 begin = r_io_map_begin (submap);
const ut64 size = r_io_map_size (submap);
if (scan && size <= 0xffffff) {
const ut64 misalignment = (begin - r_io_map_begin (map)) % width;
const ut64 skip = misalignment? width - misalignment: 0;
if (size >= skip + width) {
addRangesWithPointers (io, list, space, begin + skip, size - skip, bits);
}
} else {
list.insertRange (space, begin, r_io_map_to (submap));
}
free (buf);
if (hasdata) {
// eprintf ("1 append %llx %llx\n", base, basefin);
list.insertRange(space, base, basefin);
}
});
}
}
// the loader fills relocation targets in at runtime, so their on-disk bytes are not constants
@@ -127,23 +121,8 @@ void R2LoadImage::getReadonly(RangeList &list) const {
case 1:
break;
case 2:
// find ranges with pointers
addRangesWithPointers(core, list, space);
break;
case 3:
{
RIO *io = core->io;
RIOBank *bank = r_io_bank_get (io, io->bank);
r_list_foreach_cpp<RIOMapRef>(bank->maprefs, [&](RIOMapRef *mapref) {
RIOMap *map = r_io_map_get (io, mapref->id);
ut64 begin = r_io_map_begin (map);
ut64 end = r_io_map_end (map);
if (map->perm & R_PERM_W) {
return;
}
list.insertRange(space, begin, end);
});
}
addReadonlyMapRanges (core, list, space, roprop == 2);
break;
case 4:
list.insertRange(space, 0x1000, ST64_MAX - 1);
+33
View File
@@ -1060,3 +1060,36 @@ EXPECT=<<EOF2
(*_reloc.__gmon_start__)();
EOF2
RUN
NAME=readonly propagation respects adjacent and overlapping writable maps
FILE=-
ARGS=-a x86 -b 32
CMDS=<<EOF2
on malloc://24 0x1000 rwx
wx a1fc2f0000c39090a100300000c39090a104300000c3 @ 0x1000
on malloc://8 0x2ffc rw-
wx 0040000000500000 @ 0x2ffc
omp 3 r--
on malloc://4 0x3000 rw-
wx 2a000000 @ 0x3000
on malloc://4 0x3004 rw-
wx 2b000000 @ 0x3004
af @ 0x1000
af @ 0x1008
af @ 0x1010
e r2ghidra.roprop=3
pdg @ 0x1000~return
pdg @ 0x1008~return
pdg @ 0x1010~return
e r2ghidra.roprop=2
pdg @ 0x1000~return
pdg @ 0x1008~return
EOF2
EXPECT=<<EOF2
return 0x4000;
return *0x3000;
return *0x3004;
return 0x4000;
return *0x3000;
EOF2
RUN