進程地址空間的隔離 是現代操作系統的一個顯著特征。這也是區別于 “古代”操作系統 的顯著特征。
進程地址空間隔離意味著進程P1無法以隨意的方式訪問進程P2的內存,除非這塊內存被聲明是共享的。
這非常容易理解,我舉個例子。
我們知道,在原始野人社會,是沒有家庭的觀念的,所有的資源都是部落內共享的,所有的野人都可以以任意的方式在任意時間和任何其他野人交互。類似Dos這樣的操作系統就是這樣的,內存地址空間并沒有隔離。進程可以隨意訪問其它進程的內存。
后來有了家庭的觀念,家庭的資源被隔離,人們便不能私闖民宅了,人們無法以隨意的方式進入別人的家用別人的東西,除非這是主人允許的。操作系統進入現代模式后,進程也有了類似家庭的概念。
但家庭的概念是虛擬的,人們只是遵守約定而不去破壞別人的家庭。房子作為一個物理基礎設施,保護著家庭。在操作系統中,家庭類似于虛擬地址空間,而房子就是頁表。
鄰居不能闖入你的房子,但警察可以,政府公務人員以合理的理由也可以。所謂的特權管理機構只要理由充分,就可以進入普通人家的房子,touch這家人的東西。對于操作系統而言,這就是內核可以做的事,內核可以訪問任意進程的地址空間。
當然了,內核并不會無故私闖民宅,就像警察不會隨意闖入別人家里一樣。
但是,你可以讓內核故意這么做,做點無賴的事情。
我們來試一下,先看一個程序:
// test.c// gcc test.c -o test#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/mman.h>int main(){  char* addr = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);  strcpy(addr, "Zhejiang wenzhou pixie shi");  printf("addr: %lu  pid:%d/n", addr, getpid());  printf("before:%s /n", addr); getchar();  printf("after:%s/n", addr);  return 0;}這個程序的輸出非常簡單,before和after都會輸出 “Zhejiang wenzhou pixie shi”,但是我們想把這句話給改了,怎么辦呢?顯然,test進程如果自己不改它,那就沒轍…但是可以讓內核強制改啊,讓內核私闖民宅就是了。
接下來我寫一個內核模塊:
// test.c// make -C /lib/modules/`uname -r`/build SUBDIRS=`pwd` modules#include <linux/mm.h>#include <linux/sched.h>#include <linux/module.h>static int pid = 1;module_param(pid, int, 0644);static unsigned long addr = 0;module_param(addr, long, 0644);// 根據一個進程的虛擬地址找到它的頁表,相當于找到這家人的房子地址,然后闖入!static pte_t* get_pte(struct task_struct *task, unsigned long address){ pgd_t* pgd; pud_t* pud; pmd_t* pmd; pte_t* pte; struct mm_struct *mm = task->mm; pgd = pgd_offset(mm, address); if(pgd_none(*pgd) || pgd_bad(*pgd)) return NULL; pud = pud_offset(pgd, address); if(pud_none(*pud) || pud_bad(*pud)) return NULL; pmd = pmd_offset(pud, address); if(pmd_none(*pmd) || pmd_bad(*pmd)) return NULL; pte = pte_offset_kernel(pmd, address); if(pte_none(*pte)) return NULL; return pte;}static int test_init(void){ struct task_struct *task; pte_t* pte; struct page* page; // 找到這家人 task = pid_task(find_pid_ns(pid, &init_pid_ns), PIDTYPE_PID); // 找到這家人住在哪里 if(!(pte = get_pte(task, addr))) return -1; page = pte_page(*pte); // 強行闖入 addr = page_address(page); // sdajgdoiewhgikwnsviwgvwgvw strcpy(addr, (char *)"rain flooding water will not get fat!"); // 事了拂衣去,深藏功與名 return 0;}static void test_exit(void){}module_init(test_init);module_exit(test_exit);MODULE_LICENSE("GPL");
| 
 
 | 
新聞熱點
疑難解答