PostgreSQL 原始碼解讀(226)- Linux Kernel(虛擬記憶體)
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)
三、參考資料
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/6906/viewspace-2656764/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- PostgreSQL 原始碼解讀(229)- Linux Kernel(程式虛擬記憶體#3)SQL原始碼Linux記憶體
- PostgreSQL 原始碼解讀(227)- Linux Kernel(程式虛擬記憶體#2)SQL原始碼Linux記憶體
- Linux 虛擬記憶體Linux記憶體
- 鴻蒙輕核心原始碼分析:虛擬記憶體鴻蒙原始碼記憶體
- Linux增加虛擬記憶體方法Linux記憶體
- 虛擬記憶體有什麼用 虛擬記憶體不足怎麼解決記憶體
- 讀懂Windows虛擬記憶體問題Windows記憶體
- 實體記憶體和虛擬記憶體記憶體
- 詳細理解Linux虛擬記憶體Linux記憶體
- Linux 虛擬記憶體引數配置Linux記憶體
- 虛擬記憶體筆記記憶體筆記
- Flutter引擎原始碼解讀-記憶體管理篇Flutter原始碼記憶體
- iOS記憶體管理和malloc原始碼解讀iOS記憶體原始碼
- 聊聊虛擬記憶體記憶體
- 虛擬記憶體系統——瞭解記憶體的工作原理記憶體
- 解密虛擬 DOM——snabbdom 核心原始碼解讀解密原始碼
- 為什麼 Linux 需要虛擬記憶體Linux記憶體
- linux伺服器增加虛擬記憶體Linux伺服器記憶體
- Windows及Linux系統虛擬記憶體WindowsLinux記憶體
- linux積累——swap虛擬記憶體建立Linux記憶體
- 5.虛擬記憶體記憶體
- 虛擬記憶體到實體記憶體(32位)記憶體
- 【Java基礎】實體記憶體&虛擬記憶體Java記憶體
- PostgreSQL 原始碼解讀(3)- 如何閱讀原始碼SQL原始碼
- JVM原始碼分析之堆外記憶體完全解讀JVM原始碼記憶體
- ThreadLocal原始碼解讀和記憶體洩露分析thread原始碼記憶體洩露
- 資源供給:記憶體和虛擬記憶體記憶體
- LINUX系統程式設計 LINUX 虛擬記憶體Linux程式設計記憶體
- 教你如何擴大電腦的虛擬記憶體? 什麼是虛擬記憶體?記憶體
- linux kernel記憶體碎片防治技術Linux記憶體
- 走出虛擬記憶體禁(轉)記憶體
- ORACLE DISCOVERER虛擬記憶體低Oracle記憶體
- 虛擬記憶體(待補充)記憶體
- Linux記憶體不夠了?看看如何開啟虛擬記憶體增加記憶體使用量Linux記憶體
- Java虛擬機器記憶體區域詳解Java虛擬機記憶體
- win10虛擬記憶體怎麼設定 win10虛擬記憶體設定步驟詳解Win10記憶體
- 記憶體管理兩部曲之虛擬記憶體管理記憶體
- linux報告虛擬記憶體統計資訊-vmstatLinux記憶體