lunixbochs / usercorn

dynamic binary analysis via platform emulation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Static x86 elf crash after sys_set_thread_area

felberj opened this issue · comments

commented

My static hello world for x86 (src and binary below) crashes shortly after the syscall set_thread_area. I found this while trying to implement my own minimal kernel that communicates with unicorn, so I am more than willing to help you figure out what is happening here.

Unfortunately I have no clue what exactly this syscall should do, but I found some resouces:

For me it looks like the program crashes right after its next access to the stack after the syscall set_thread_area. Interesting to note here is that the report is invalid read at 0xf6dc, but the stack pointer is at 0x607ff6dc. This seems to be a bug in the MemHook of the unicorn engine, because the rust bindings also report a truncated value of the esp.

Questions while looking at your implementation at linux.go

  • why did you choose the gdt entry number 2 instead of the next free slot?
  • why did you choose the flags 0x12?
  • Not sure whether the writing of X86_REG_GS is done correctly. Should't you do it like here?

static.c:

#include <stdio.h>

int main() {
    printf("hello world\n");
}

and my Makefile:

all:
        gcc -static -m32 -o static_x86 static.c
        gcc -static -m64 -o static_x86_64 static.c

the binary:
static_x86.zip

crashdump

$ ./usercorn ../testdata/static/static_x86
invalid read: @0xf6dc, 0x4 = 0x0
[memory map]
  0x60000000-0x60800000 rwx [stack]
  0x60800000-0x60801000 ---
  0x8048000-0x80ea000 r-x static_x86 [exe]
  0x80ea000-0x80ed000 rw- static_x86 [exe]
  0x80ed000-0x80ee000 rw- [brk]
  0x100000-0x101000 rwx
[registers]
   cs 0x00000000   ebx 0x607ff710  eflags 0x00000004   esp 0x607ff6dc 
   ds 0x00000000   ecx 0x00000000   eip 0x0806ffc2    fs 0x00000000 
  eax 0x00000002   edi 0x080ebaa0    es 0x00000000    gs 0x00000002 
  ebp 0x00000000   edx 0x00000040   esi 0x00000040    ss 0x00000000 
[stacktrace]
  0x806ffc2 _dl_sysinfo_int80+0x2
panic: Invalid memory read (UC_ERR_READ_UNMAPPED)

goroutine 1 [running]:
github.com/lunixbochs/usercorn/go/cmd.(*UsercornCmd).Run(0xc420096a50, 0xc420084080, 0x2, 0x2, 0xc4200b1800, 0x23, 0x40)
	/Users/jonasfelber/dev/usercorn/.gopath/src/github.com/lunixbochs/usercorn/go/cmd/cmd.go:334 +0x1761
main.main()
	/Users/jonasfelber/dev/usercorn/go/cmd/usercorn/main.go:12 +0x7f
.text:08049302                 call    _dl_sysinfo ; <-- syscall set_thread_area
.text:08049308                 add     esp, 10h
.text:0804930B                 test    eax, eax
.text:0804930D                 jz      short loc_8049320
.text:0804930F                 sub     esp, 0Ch
.text:08049312                 push    offset aSet_thread_are ; "set_thread_area failed when setting up "...
.text:08049317                 call    __libc_fatal
.text:08049317 ; ---------------------------------------------------------------------------
.text:0804931C                 align 10h
.text:08049320
.text:08049320 loc_8049320:                            ; CODE XREF: __libc_setup_tls+14D�j
.text:08049320                 mov     eax, [esp+4Ch+var_2C]
.text:08049324                 lea     eax, ds:3[eax*8]
.text:0804932B                 mov     gs, eax
.text:0804932D                 mov     eax, [esp+4Ch+var_34]
.text:08049331                 mov     ecx, [esp+4Ch+var_40]
.text:08049335                 mov     [edi+238h], ebp
.text:0804933B                 mov     dword ptr [edi+244h], 1
.text:08049345                 mov     ds:dword_80EBFB4, edi
.text:0804934B                 mov     ds:static_slotinfo, 40h
.text:08049355                 mov     [edi+22Ch], eax
.text:0804935B                 mov     eax, [esp+4Ch+var_38]
.text:0804935F                 mov     [edi+234h], ecx
.text:08049365                 mov     ecx, [esp+4Ch+var_30]
.text:08049369                 mov     ds:_dl_tls_max_dtv_idx, 1
.text:08049373                 mov     ds:_dl_tls_dtv_slotinfo_list, offset static_slotinfo
.text:0804937D                 mov     [edi+230h], eax
.text:08049383                 mov     eax, _dl_tls_static_size
.text:08049388                 mov     ds:_dl_tls_static_used, ecx
.text:0804938E                 mov     ds:_dl_tls_static_nelem, 1
.text:08049398                 lea     eax, [ecx+eax+3Fh]
.text:0804939C                 and     eax, 0FFFFFFC0h
.text:0804939F                 add     eax, 4C0h
.text:080493A4                 cmp     esi, 40h
.text:080493A7                 mov     _dl_tls_static_size, eax
.text:080493AC                 mov     eax, 40h
.text:080493B1                 cmovb   esi, eax
.text:080493B4                 mov     ds:_dl_tls_static_align, esi
.text:080493BA                 add     esp, 3Ch
.text:080493BD                 pop     ebx ; <-- crash
commented

Actually, usercorn crashed even earlier at the first return after set_thread_area

.text:0806FFC0 _dl_sysinfo_int80 proc near             ; CODE XREF: backtrace_and_maps+46�p
.text:0806FFC0                                         ; backtrace_and_maps+77�p ...
.text:0806FFC0                 int     80h             
.text:0806FFC2                 retn ; <-- crash here

Not sure whether the writing of X86_REG_GS is done correctly. Should't you do it like here?

I thought x86-32 had no FS_base and GS_base MSRs. My GDT stuff isn't working yet on 32-bit and I don't remember why. I don't use a free GDT slot, because I provide the whole GDT myself.

I doubt there's a bug in mem hook, imo it's more likely you're seeing a GS offset where GS is zero.

From memory, I think the problem was- when you set up the segment selectors, you need to set all of them up, but Unicorn longjumps when you change SS (stack selector), so I don't set that one. I did confirm from a custom Unicorn build that manually setting FS_base and GS_base works great, so the only problem is with the new GDT stuff.

GDT should now be fixed in gdt branch and in unstable branch

Edit: kinda... gdt loads but unicorn deadlocks. need to investigate.

commented

Thank you very much! I will look into it tomorrow during my flight! Where does it deadlock?

Right after set_thread_area :) I might need to tweak the segment flags. I'm using https://github.com/unicorn-engine/unicorn/blob/master/samples/sample_x86_32_gdt_and_seg_regs.c#L186 for reference

commented

Did you try the value 0x96 that apparently worked in unicorn-engine/unicorn#522 for the access flags of the stack segment?

commented

I took the time to look into it again and I am not sure whether you have pushed the newest version onto the gdt branch, because when I run my sample file it does not give me any output.

By comparing your implementation with the sample implementation, it looks like you are setting the access and flag part wrong.

commented

Imho should be like this (types removed so I can play with it in the playground)

entry |= (limit) & 0xFFFF
entry |= (((limit) >> 16) & 0xF) << 48
entry |= ((base) & 0xFFFFFF) << 16
entry |= ((base>>24) & 0xFF) << 56
entry |= ((access) & 0xFF) << 40
entry |= ((flags) & 0xF0) << 48
commented

Actually never mind, you are setting it correctly!

Should be fixed (for static only) in gdt and unstable branches

fixed in unstable for both static and dynamic, finally merging all of unstable to master and closing this.