DynamoRIO / drmemory

Memory Debugger for Windows, Linux, Mac, and Android
Other
2.42k stars 261 forks source link

umbra mapping fails when vdso is placed in 0x7fff'ff4-0x7fff'ff8 gap #2363

Open derekbruening opened 3 years ago

derekbruening commented 3 years ago

Just running in a loop after fixing #1712 I still see a failure. This time though it's due to the kernel placing the stack, vvar, and vdso in the 0x7fff'ff4-0x7fff'ff8 gap which umbra assumes has nothing in it:

adding app segment [0x00007f00'00000000, 0x00008000'00000000)
ERROR: new app segment [0x00007f00'00000000, 0x00007fff'ff400000) conflicts with app seg [0x00007f00'00000000, 0x00008000'00000000)
ERROR: shadow segment failed for 0x00007f00'00000000-0x00007fff'ff400000
ASSERT FAILURE (thread 2826784): /home/bruening/drmemory/git/src/drmemory/shadow.c:289: false (fail to create shadow memory mapping)
$ cat /proc/`pgrep mmap`/maps
7ff8'6fe2d000-7ff86fe6d000 rw-p 00000000 00:00 0 
<...>
7ffa'84267000-7ffa8429f000 rw-p 00000000 00:00 0 
7fff'ff786000-7fffff7a7000 rw-p 00000000 00:00 0                          [stack]
7fff'ff7ae000-7fffff7b2000 r--p 00000000 00:00 0                          [vvar]
7fff'ff7b2000-7fffff7b4000 r-xp 00000000 00:00 0                          [vdso]

And here #1798 won't help b/c the kernel allocated there and it's too late for umbra to do anything about it.

@johnfxgalea -- this assumption is seeming untenable, unless we require running with ASLR disabled or sthg extreme, or we set the libdynamorio.so base to cover this gap, or other crazy things that would all rule out attach to an existing process launched some other way.

If we do accept that the kernel might put something there: the new tool from PR #2300 showed there is no mapping solution, right? What were we considering before: not allowing vsyscall to be shadowed?

derekbruening commented 3 years ago

Trying to remind myself: so vsyscall is:

 * app4: [0xFFFFFFFF'FF600000, 0xFFFFFFFF'FF601000]: vsyscall

It does not show up in the procfs maps file on my kernel. Was it removed at some point? That would make it easier.

@zhaoqin in case you have some time to look at this.

derekbruening commented 3 years ago

Look like my kernel is running with vsyscall=none (https://github.com/torvalds/linux/blob/abfbb29297c27e3f101f348dc9e467b0fe70f919/Documentation/admin-guide/kernel-parameters.txt#L5535-L5553). So for that case, we can solve this: if we don't see 0xffffffff'ff6 we can eliminate the 0x7fff'ff4-0x7ff'ff8 gap.

But it seems like this is still an issue even after that fix since I would assume that for vsyscall=emulate the kernel could still place vdso & co in that gap.

johnfxgalea commented 3 years ago

@johnfxgalea -- this assumption is seeming untenable, unless we require running with ASLR disabled or sthg extreme, or we set the libdynamorio.so base to cover this gap, or other crazy things that would all rule out attach to an existing process launched some other way.

Indeed, a general solution requires such extreme assumptions, which we cannot adopt as solutions. The enforcement of the split seemed promising, but this issue here now shows the contrary.

If we do accept that the kernel might put something there: the new tool from PR #2300 showed there is no mapping solution, right? What were we considering before: not allowing vsyscall to be shadowed?

If we do not consider vsyscall, then a layout is viable. This also avoids the gap.

For maximum flexibility, we perhaps might also want to consider switching to a multi-layered approach, achieving indirection to shadow blocks via tables, as similarly done for Umbra's 32-bit implementation. This comes at a cost of performance though, which we would need to evaluate.

johnfxgalea commented 3 years ago

The additional benefit of the above suggestion is that Ubmra's implementation is shared for 32-bit and 64-bit. Again, keeping in mind the cost of runtime performance.

johnfxgalea commented 3 years ago

Another option is to keep the current implementation for 64-bit, and find another possible gap that is more suitable, i.e., it does not touch 0x7fff'ff4-0x7fff'ff8 at all, (this also requires new disp values for the layout). Perhaps this new gap could be placed where the heap is approximately assumed to be. With this approach, https://github.com/DynamoRIO/drmemory/issues/1798 might be of help actually.

derekbruening commented 3 years ago

Perhaps this new gap could be placed where the heap is approximately assumed to be.

The application heap, i.e., the "break", right after the executable? I think that would be in the PIE range and so the executable itself could land there. Plus Umbra would fail SYS_brk and force the allocator into mmaps, which is a little more disruptive than failing an mmap, in terms of app execution looking less like it would natively. If it's possible, some location outside of the PIE and ld.so ASLR ranges would be ideal.