why and how do the addresses returned by 'cat /proc/self/maps' change when it's executed again - linux

I'm trying to understand linux memory management.
Why and how do the addresses returned by 'cat /proc/self/maps' change when it's executed again
user#notebook:/$ cat /proc/self/maps | grep heap
55dc94a7c000-55dc94a9d000 rw-p 00000000 00:00 0 [heap]
user#notebook:/$ cat /proc/self/maps | grep heap
562609879000-56260989a000 rw-p 00000000 00:00 0 [heap]

This is due to Address Space Layout Randomization, aka ASLR. Linux will load code and libraries at different locations each time to make it harder to exploit buffer overflows and similar.
You can disable it with
echo 0 > /proc/sys/kernel/randomize_va_space
which will make the addresses the same each time. You can then re-enable it with:
echo 2 > /proc/sys/kernel/randomize_va_space
and the addresses will be randomized again.

Related

Is there a way to have a.out loaded in linux x86_64 "high memory"?

If I look at the memory mapping for a 64-bit process on Linux (x86_64) I see that the a.out is mapped in fairly low memory:
$ cat /proc/1160/maps
00400000-004dd000 r-xp 00000000 103:03 536876177 /usr/bin/bash
006dc000-006dd000 r--p 000dc000 103:03 536876177 /usr/bin/bash
006dd000-006e6000 rw-p 000dd000 103:03 536876177 /usr/bin/bash
006e6000-006ec000 rw-p 00000000 00:00 0
00e07000-00e6a000 rw-p 00000000 00:00 0 [heap]
7fbeac11c000-7fbeac128000 r-xp 00000000 103:03 1074688839 /usr/lib64/libnss_files-2.17.so
7fbeac128000-7fbeac327000 ---p 0000c000 103:03 1074688839 /usr/lib64/libnss_files-2.17.so
I'd like to map a 2G memory region in the very lowest portion of memory, but have to put this in the region after these a.out mappings, crossing into the second 2G region.
Is the a.out being mapped here part of the x86_64 ABI, or can this load address be moved to a different region, using one of:
runtime loader flags
linker flags when the executable is created
?
Yes. Building a Linux x86-64 application as a position-independent executable will cause both it and its heap to be mapped into high memory, right along with libc and other libraries. This should leave the space under 2GB free for your use. (However, note that the kernel will probably protect the first 64KB or so of memory from being mapped to protect it from certain exploits; look up vm.mmap_min_addr for information.)
To build your application as a position-independent executable, pass -pie -fPIE to the compiler.

Disagreement between AT_SYSINFO_EHDR and /proc/self/maps

So I know that AT_SYSINFO_EHDR should contain a pointer to the VDSO.
I also know that the VDSO shows up in /proc/[pid]/maps.
But it looks like the outputs don't match.
For example, take this run:
LD_SHOW_AUXV=1 cat /proc/self/maps
[...]
AT_SYSINFO_EHDR: 0x2aaaaaac6000
[...]
2aaaaaac6000-2aaaaaac7000 r-xp 2aaaaaac6000 00:00 0
[...]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vdso]
[...]
Why is there a difference? Am I missing something?
[EDIT]
Okay, I looked at the outputs in other machines and the outputs match there. So I guess this is something specific to that one machine. I would still appreciate an explanation if you have one.

virtual memory in linux

I am debugging one issue where a same program behaves differently on different Linux boxes (all 2.6 kernels). Basically on some linux box, mmap() of 16MB always succeeds, but on other linux box the same mmap() would fail with "ENOMEM".
I checked /proc//maps and saw the virtual memory map on different linux boxes are quite different. One thing is: the address range for heap:
linux box1: the mmap() would return address of 31162000-31164000
linux box2: the mmap() would return address of a9a67000-a9a69000
My question is: for a particular process, how is linux virtual memory arranged? What decides the actual address ranges? Why the mmap() would fail even I can still see some large unused virtual address ranges?
UPDATE: here is an example of address space where mmap() of 16MB would fail:
10024000-10f6b000 rwxp 10024000 00:00 0 [heap]
30000000-3000c000 rw-p 30000000 00:00 0
3000c000-3000d000 r--s 00000000 00:0c 5461 /dev/shm/mymap1
3000d000-3000e000 rw-s 00001000 00:0c 5461 /dev/shm/mymap2
3000e000-30014000 r--s 00000000 00:0c 5463 /dev/shm/mymap3
30014000-300e0000 r--s 00000000 00:0c 5465 /dev/shm/mymap4
300e0000-310e0000 r--s 00000000 00:0b 2554 /dev/mymap5
310e0000-31162000 rw-p 310e0000 00:00 0
31162000-31164000 rw-s 00000000 00:0c 3554306 /dev/shm/mymap6
31164000-312e4000 rw-s 00000000 00:0c 3554307 /dev/shm/mymap7
312e4000-32019000 rw-s 00000000 00:0c 3554309 /dev/shm/mymap8
7f837000-7f84c000 rw-p 7ffeb000 00:00 0 [stack]
in the above example: there are still big space between the last mymap8 and [stack]. But further mmap() of 16MB would fail. My question is: how does Linux decide mmap() base and the allowed range?
Thanks.

identifying glibc mmap areas (VMA's) from a Linux kernel module

I understood When allocating a blocks of memory larger than MMAP_THRESHOLD bytes, the glibc malloc() implementation allocates the memory as a private anonymous mapping using mmap ,and this mmap allocated area wont come as a part of [heap] in linux vma.
So is there any method available to identify all the glibc mmap areas from a linux kernel module.?
example :
One of test program which do malloc greater than MMAP_THRESHOLD many times shows cat /proc/pid/maps output as
00013000-00085000 rw-p 00000000 00:00 0 [heap]
40000000-40016000 r-xp 00000000 00:0c 14107305 /lib/arm-linux-gnueabi/ld-2.13.so
4025e000-4025f000 r--p 00001000 00:0c 14107276 /lib/arm-linux-gnueabi/libdl-2.13.so
4025f000-40260000 rw-p 00002000 00:0c 14107276 /lib/arm-linux-gnueabi/libdl-2.13.so
.....
.....
40260000-40261000 ---p 00000000 00:00 0
40261000-40a60000 rw-p 00000000 00:00 0
40a60000-40a61000 ---p 00000000 00:00 0
40a61000-42247000 rw-p 00000000 00:00 0
beed8000-beef9000 rw-p 00000000 00:00 0 [stack]
In this few are (40a61000-42247000,40261000-40a60000) actually glibc mmap areas,So from a Linux kernel module is there any way to identify this areas ,something like below code which identify stack and heap ?
if (vma->vm_start <= mm->start_brk &&
vma->vm_end >= mm->brk) {
name = "[heap]";
} else if (vma->vm_start <= mm->start_stack &&
vma->vm_end >= mm->start_stack) {
name = "[stack]";
}
I believe you should not dump the memory of your application from a kernel module. You should consider using application checkpointing, see this answer and the Berkley checkpoint restart library
You could also consider using the core dumping facilities inside the kernel.

Get pages attribute by system call in Linux

Is there any system call or function that can get page attribute like readable, writable, executable by page address?
I know we can use mprotect to set pages attribute, but I have no idea if we can get pages attribute. Any comment is appreciated.
There isn't. You need to use the proc interface, which contains lots of information about each process in various files. The information you're looking for is in plaintext, in /proc/<pid>/maps. You can take a look at it for your current process by running:
$ cat /proc/$$/maps
You can find some more information in man 5 proc.
The example given at the above link is:
address perms offset dev inode pathname
08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm
08056000-08058000 rw-p 0000d000 03:0c 64593 /usr/sbin/gpm
08058000-0805b000 rwxp 00000000 00:00 0
40000000-40013000 r-xp 00000000 03:0c 4165 /lib/ld-2.2.4.so
40013000-40015000 rw-p 00012000 03:0c 4165 /lib/ld-2.2.4.so
4001f000-40135000 r-xp 00000000 03:0c 45494 /lib/libc-2.2.4.so
40135000-4013e000 rw-p 00115000 03:0c 45494 /lib/libc-2.2.4.so
4013e000-40142000 rw-p 00000000 00:00 0
bffff000-c0000000 rwxp 00000000 00:00 0
As you can see, the permissions are the second (space-delimited) field there. So from a program (like in C, since you mentioned mprotect(), you could open up /proc/$$/maps with fopen(), then use fgets() or scanf() to pull the data out. You're just looking for that perms field of the range where your page lies.

Resources