ITPub博客

首页 > 数据库 > PostgreSQL > PostgreSQL 源码解读(226)- Linux Kernel(进程虚拟内存#1)

PostgreSQL 源码解读(226)- Linux Kernel(进程虚拟内存#1)

翻译 PostgreSQL 作者:husthxd 时间:2019-09-11 16:20:30 0 删除 编辑

PostgreSQL使用进程架构,每个连接对应一个后台进程,为了更好的理解这种架构,有必要深入理解进程的相关知识.本节主要介绍了Linux下的进程虚拟内存结构.

一、虚拟内存

虚拟内存是一种通过软硬件结合实现的内存管理机制.程序通过内存映射表建立虚拟内存地址和物理内存地址之间的映射关系.在进程或任务看起来存储就像是连续的地址空间,或者是连续段的集合.OS管理虚拟地址空间和实际内存->虚拟内存的分配.在CPU中的地址转换硬件通常称为内存管理单元(简称MMU),自动转换虚拟地址为物理地址.OS中软件可以扩展这些机制来提供比实际内存大多的虚拟地址空间.
使用虚拟内存的优点包括通过强制管理共享内存空间来释放应用占用内存/通过内存隔离增强安全性/可使用比实际内存要大的内存空间/使用页技术等.
虚拟内存

每个进程都有自己的虚拟内存空间:
1.虚拟内存的大小取决于系统架构;
2.OS处理虚拟内存的方式不太一样,Linux下,虚拟内存分为内核空间和用户空间两部分.
进程的虚拟内存结构

进程的虚拟内存空间布局

1.只读段,包括代码和常量等;
2.数据段,包括全局变量等;
3.堆,包括动态分配的内存,从低地址开始向上增长;
4.文件映射段,包括动态库/共享内存等,从高地址开始向下增长;
5.栈,包括局部变量和函数调用的上下文等.

二、proc文件系统

下面先看一个C语言的例子:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/**
 * main - uses strdup to create a new string, and prints the
 * address of the new duplcated string
 *
 * Return: EXIT_FAILURE if malloc failed. Otherwise EXIT_SUCCESS
 */
int main(void)
{
    char *s;
    s = strdup("Holberton");
    if (s == NULL)
    {
        fprintf(stderr, "Can't allocate mem with malloc\n");
        return (EXIT_FAILURE);
    }
    printf("%p\n", (void *)s);
    return (EXIT_SUCCESS);
}

源代码另存为main.c文件,编译执行

[root@localhost linux]# gcc -Wall -Wextra -pedantic -Werror main.c -o holberton
[root@localhost linux]# ./holberton 
0x1bc2010

输出的0x1bc2010是字符串在进程虚拟内存空间中的地址.
实际上,Linux通过/proc/[pid]/maps来存储进程映射的虚拟内存区间和权限信息.

A file containing the currently mapped memory regions and their access permissions.

/proc/[pid]/mem文件用于open/read/lseek函数访问进程(虚拟)内存页.

/proc/[pid]/mem
This file can be used to access the pages of a process’s memory through open(2), read(2), and lseek(2).

下面我们稍微修改下main.c中的逻辑,每隔1s打印字符串

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
/**              
 * main - uses strdup to create a new string, loops forever-ever
 *                
 * Return: EXIT_FAILURE if malloc failed. Other never returns
 */
int main(void)
{
     char *s;
     unsigned long int i;
     s = strdup("Holberton");
     if (s == NULL)
     {
          fprintf(stderr, "Can't allocate mem with malloc\n");
          return (EXIT_FAILURE);
     }
     i = 0;
     while (s)
     {
          printf("[%lu] %s (%p)\n", i, s, (void *)s);
          sleep(1);
          i++;
     }
     return (EXIT_SUCCESS);
}

编译执行,输出如下

[root@localhost linux]# gcc -Wall -Wextra -pedantic -Werror loop.c -o loop
[root@localhost linux]# ./loop
[0] Holberton (0x1db0010)
...

下面分析进程loop在/proc中的信息
首先,获取该进程的pid

[root@localhost linux]# ps -aux|grep './loop'
root     21437  0.0  0.0   4300   348 pts/1    S+   16:07   0:00 ./loop

查看该进程的maps和mem

[root@localhost linux]# cat /proc/21437/maps 
00400000-00401000 r-xp 00000000 fd:00 251955270                          /data/source/linux/loop
00600000-00601000 r--p 00000000 fd:00 251955270                          /data/source/linux/loop
00601000-00602000 rw-p 00001000 fd:00 251955270                          /data/source/linux/loop
01db0000-01dd1000 rw-p 00000000 00:00 0                                  [heap]
7f605d2e0000-7f605d498000 r-xp 00000000 fd:00 153635                     /usr/lib64/libc-2.17.so
7f605d498000-7f605d698000 ---p 001b8000 fd:00 153635                     /usr/lib64/libc-2.17.so
7f605d698000-7f605d69c000 r--p 001b8000 fd:00 153635                     /usr/lib64/libc-2.17.so
7f605d69c000-7f605d69e000 rw-p 001bc000 fd:00 153635                     /usr/lib64/libc-2.17.so
7f605d69e000-7f605d6a3000 rw-p 00000000 00:00 0 
7f605d6a3000-7f605d6c4000 r-xp 00000000 fd:00 153628                     /usr/lib64/ld-2.17.so
7f605d8b7000-7f605d8ba000 rw-p 00000000 00:00 0 
7f605d8c2000-7f605d8c4000 rw-p 00000000 00:00 0 
7f605d8c4000-7f605d8c5000 r--p 00021000 fd:00 153628                     /usr/lib64/ld-2.17.so
7f605d8c5000-7f605d8c6000 rw-p 00022000 fd:00 153628                     /usr/lib64/ld-2.17.so
7f605d8c6000-7f605d8c7000 rw-p 00000000 00:00 0 
7ffd04019000-7ffd0403a000 rw-p 00000000 00:00 0                          [stack]
7ffd0404f000-7ffd04051000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
[root@localhost linux]# 
[root@localhost linux]# ll /proc/21437/mem
-rw-------. 1 root root 0 Sep 11 16:09 /proc/21437/mem

进程loop的堆区间为01db0000-01dd1000,权限为rw-p(read/write/private)

r = read
w = write
x = execute
s = shared
p = private (copy on write)

./loop输出的地址为0x1db0010,为字符串分配的内存空间位于堆空间中.已知字符串的地址和大小,可以通过待修改虚拟内存中的字符串值,Hack程序输出.
执行hack

[root@localhost linux]# python3.4 read_write_heap.py 21437 Holberton "Hi,Hacker"
[*] maps: /proc/21437/maps
[*] mem: /proc/21437/mem
[*] Found [heap]:
    pathname = [heap]
    addresses = 01db0000-01dd1000
    permisions = rw-p
    offset = 00000000
    inode = 0
    Addr start [1db0000] | end [1dd1000]
[*] Found 'Holberton' at 10
[*] Writing 'Hi,Hacker' at 1db0010
[root@localhost linux]#

hack后的程序输出

...
[719] Holberton (0x1db0010)
[720] Hi,Hacker (0x1db0010)
[721] Hi,Hacker (0x1db0010)
[722] Hi,Hacker (0x1db0010)
[723] Hi,Hacker (0x1db0010)
[724] Hi,Hacker (0x1db0010)
[725] Hi,Hacker (0x1db0010)
[726] Hi,Hacker (0x1db0010)
[727] Hi,Hacker (0x1db0010)
[728] Hi,Hacker (0x1db0010)
[729] Hi,Hacker (0x1db0010)
[730] Hi,Hacker (0x1db0010)

三、参考资料

Virtual memory
Hack The Virtual Memory: C strings & /proc
Udis86

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/6906/viewspace-2656764/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
ITPUB数据库版块资深版主,对Oracle、PostgreSQL有深入研究。现就职于广州云图数据技术有限公司,系统架构师。

注册时间:2007-12-28

  • 博文量
    1374
  • 访问量
    3827353