Search code examples
assemblyprocesslinux-kernelgdbportable-executable

.text in memory being overwritten during execution


I've been working on a simple PE process loader for Linux. I think I've gotten the basics down; much of the code I use comes from binfmt_elf.c and binfmt_aout.c. My test executable is about is simple as possible (FASM format):

format PE GUI 4.0
entry main

section '.text' code readable executable
main:
    mov eax, 4
    add eax, 5
    ret

This program (math1) is compiled 32-bit, and the VM I'm running in (Xubuntu 12.04) is also 32-bit. I compiled the loader as a kernel module and installed it with insmod. The loader appears to work so far, and I've checked for error codes at every possible step. All it does is mmap the code section at the start address 0x401000 and call start_thread() with that address. If I type something like ./math1.exe at the command line, my loader is indeed invoked. So, if all goes according to plan, I should get the return value 9 every time. Instead of executing, however, math1 segfaults every time, so I opened it up in gdb to see what was happening.

Before execution, everything looks normal. If I dump at the start address, I see exactly what I should (I can confirm that this is the machine code for the above program):

(gdb) x/9xb 0x401000
0x401000:   0xb8    0x04    0x00    0x00    0x00    0x83    0xc0    0x05
0x401008:   0xc3
(gdb) run
Starting program: /media/sf_Sandbox/math1.exe 

Program received signal SIGSEGV, Segmentation fault.
0x00401002 in ?? ()

After the segfault, dumping at the same address, the memory has totally changed, and, from the register dump, it doesn't appear that the first instruction is ever executed:

(gdb) x/9xb 0x401000
0x401000:   0x4d    0x5a    0x80    0x00    0x01    0x00    0x00    0x00
0x401008:   0x04
(gdb) info all-registers
eax            0x0  0
ecx            0x81394e8    135501032
edx            0x64656d2f   1684368687
ebx            0x8139548    135501128
esp            0xbfffe5a0   0xbfffe5a0
ebp            0xffffffff   0xffffffff
esi            0x81394e8    135501032
edi            0x2f7ff4 3112948
eip            0x401002 0x401002
eflags         0x210296 [ PF AF SF IF RF ID ]
cs             0x73 115
ss             0x7b 123
ds             0x7b 123
es             0x7b 123
fs             0x0  0
gs             0x0  0
...more registers...

I want to know what would make something like this happen, and what I might be able to do to fix it. I'm suspecting that the code I use to set up the stack frame might be a little... off, but I'm not sure how to tell if that's what's causing this. I know this is a really specific question, but I'm hoping someone can give me some advice.


Solution

  • The error was caused by a faulty page-aligning on my part, and the mysterious hex dump contents were, in fact, the MS-DOS header of the PE file in question. I fixed it by using kernel_read and copy_to_user instead of do_mmap to avoid failure on non-page-aligned sections.