I got the strace output of my non-C binary (I filtered the noise out of the output for you):
Elf file type is EXEC (Executable file)
Entry point 0x401311
There are 7 program headers, starting at offset 64
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000db604 0x00000000000db604 R E 1000
LOAD 0x00000000000dc1c0 0x00000000004dd1c0 0x00000000004dd1c0
0x0000000000006220 0x00000000000091dc RW 1000
NOTE 0x00000000000001c8 0x00000000004001c8 0x00000000004001c8
0x0000000000000024 0x0000000000000024 R 4
GNU_EH_FRAME 0x00000000000d5680 0x00000000004d5680 0x00000000004d5680
0x0000000000005f84 0x0000000000005f84 R 4
GNU_STACK 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x0000000000000000 0x0000000000000000 RWE 0
TLS 0x00000000000dc1c0 0x00000000004dd1c0 0x00000000004dd1c0
0x0000000000000100 0x0000000000000100 R 10
GNU_RELRO 0x00000000000dc1c0 0x00000000004dd1c0 0x00000000004dd1c0
0x0000000000005e40 0x0000000000005e40 RW 20
Section to Segment mapping:
Segment Sections...
00 .note.gnu.build-id .init .text .fini .gcc_except_table .rodata .debug_gdb_scripts .eh_frame .eh_frame_hdr
01 .tdata .data.rel.ro.local .
data.rel.ro .init_array .got .got.plt .data .bss
02 .note.gnu.build-id
03 .eh_frame_hdr
04
05 .tdata
06 .tdata .data.rel.ro.local .
data.rel.ro .init_array .got .got.plt
Some notes:
As a test, I changed the non-C binary's target device file to /dev/zero, and then I could see that the non-C mmap attempt would succeed just fine.
After further verification and debugging based on guidance from another forum, I have convinced that the vm_flags change must be occuring somewhere in kernel land after control flow has left user land. Now I need to figure out how to use a kernel debugger or kprobes to walk through the execution of mmap callback delegation and see where the flags parameter is being changed.
I was pointed out to this:
http://lxr.free-electrons.com/source/mm/mmap.c#L1312But why would my vm_flags be changed by the kernel? And what can I do to get this to stop? Why is the kernel changing the vm_flags for a non-C binary using my device file, but not for either a C binary using my device file or any type of binary that's not using my device file?