/proc/self/maps - 3rd mapped piece of file?
I finally figured this out. The kernel does map only 2 segments. The third piece is a portion of one of the two loaded by the kernel. The run time linker, the program named in the INTERP pheader, which is /usr/lib/ld-2.24.so for me right now, changes the permissions on the mappings using mprotect()
so that there are read/write global variables, read-only global variables, and a read/execute text segment. You can see this happen using strace
, but it's easy to miss, as it's only a single mprotect()
call.
It wasn't a kernel change that caused this, it was a GNU lib C change.
Related videos on Youtube
Admin
Updated on September 18, 2022Comments
-
Admin over 1 year
I'm running Arch linux on my laptop, which is kernel 3.12.9 right now. Something has changed about the way the kernel maps in a dynamically-linked executable and I can't figure it out. Here's the example:
% /usr/bin/cat /proc/self/maps ... 00400000-0040b000 r-xp 00000000 08:02 1186756 /usr/bin/cat 0060a000-0060b000 r--p 0000a000 08:02 1186756 /usr/bin/cat 0060b000-0060c000 rw-p 0000b000 08:02 1186756 /usr/bin/cat 00d6c000-00d8d000 rw-p 00000000 00:00 0 [heap] 7f29b3485000-7f29b3623000 r-xp 00000000 08:02 1182988 /usr/lib/libc-2.19.so ...
My question is: what is the third mapping from
/usr/bin/cat
?Based on
readelf -l /usr/bin/cat
, there's a loadable segment of 0x1f8 bytes that should map at 0x400000. There's a loadable segment of 0xae10 bytes at 0x60ae10. Those two pieces of file correspond to the 00400000-0040b000 mapping, and the 0060a000-0060b000 mapping. But the third mapping, which claims to be at a file offset of 0xb000 bytes, doesn't seem to correspond to any Elf64_Phdr. In fact, the elf header only has 2 PT_LOAD segments.I read through
fs/binfm_elf.c
in the kernel 3.13.2 source code, and I don't see that the kernel maps in anything other than PT_LOAD segments. If I runstrace -o trace.out /usr/bin/cat /proc/self/maps
, I don't see anymmap()
calls that would map in a piece of/usr/bin/cat
, so that 3rd piece is mapped in by the kernel.I ran the same command (
cat /proc/self/maps
) on a RHEL server that was running kernel 2.6.18 + RH patches. That only shows 2 pieces of /usr/bin/cat mapped into memory, so this might be new with kernel 3.x.-
Admin about 10 yearsJust confirming your findings, I noticed the same differences on CentOS 5 (2.6.18-238.19.1.el5). However on CentOS 6 (2.6.32-358.11.1.el6.x86_64) it too shows the 3 segments. When reading this I also had the thought if this was something to do with SELinux or security in some way.
-
Admin about 10 yearsIsn't that code (
.text
), read-only data (.rodata
), and read-write global data (.data
)? -
Admin about 10 years@Gilles - if you do
readelf -h /usr/bin/cat
, you can see that the.text
and.rodata
sections end up in the first LOAD segment..data
and.bss
sections end up in the second LOAD segment. This 3rd mapped segment is something else. -
Admin over 9 years@psusi I'm pretty sure that the
.data
section belongs to the second loadable segment. -
Admin over 9 years@newbie, again, it can't since the second mapping is read only, and the data segment must be writable.
-
Admin over 9 years@psusi I'm talking about segment in ELF header, not a memory region. The second LOAD segment splits into two memory regions with
r--p
andrw-p
execute permissions respectively. The question is why does it happen. -
Admin over 9 years@newbie, because the Sections: header says it is divided into the .got.plt, .data, and .bss segments.
-
Admin over 9 years@psusi - I'm pretty sure that the ELF loader in the kernel doesn't look at the Sections header at all, just the Pheaders. I'm still confused about this, by the way. I was working on a "userland exec" at the time, and mapping in just the 2 LOAD segments works fine for userland exec
-
Admin over 9 years@newbie, that is pretty fscked up. The .init_array and .fini_array should definitely be read only, as they are actually mapped. Not sure why the headers says they aren't.
-