看了linux**,感 覺其對核心記憶體的保護做得不是很好,還有感覺大家有些地方理解不對(主要是linux的**看起來的樣子和實際的樣子不太一樣),所以談談我對linux 系統核心空間的保護和使用者空間與系統空間資料傳遞的**看法。注意我說的都是i386體系結構,別的體系結構可以看相應的**,不敢保證結果是否是如我所說。 推薦閱讀:《linux 核心管理概述》
linux
建立程序的時候建立了兩套段描述符,在檔案segment.h有說明
#ifndef _a**_segment_h
#define _a**_segment_h
#define __kernel_cs 0x10
#define __kernel_ds 0x18
#define __user_cs 0x23
#define __user_ds 0x2b
#endif
乙個用於核心**,乙個用於使用者**。執行核心**的時候用核心的段描述符號就可以直接訪問使用者空間,但執行使用者**的時候使用者段描述符不能訪問核心空間,這是用的保護模式一些機制,具體**不再介紹。不懂的就得看看介紹保護模式的一些書籍了。
在使用者**呼叫系統函式的時候,程式進入了系統核心**,描述符也已經切換到了核心的描述符,這時可以直接訪問使用者空間或者核心空間,兩者的引數資料傳遞也很簡單,可以直接拷貝等。但看了linux**的都知道,系統函式**裡面的使用者空間與核心空間引數傳遞是沒有這麼直接拷貝的,那是為什麼呢?大家想一想,使用者呼叫的一些指標引數等,可以指向核心空間,如果不加以檢測直接拷貝,那麼使用者空間**就可以通過系統呼叫讀寫核心空間了,這顯然是不准許的。所以 核心**裡面就採用了統一的一些函式:
copy_from_user/copy_to_user
和__generic_copy_from_user/__gerneric_copy_to_user等,而在這些函式裡面實現使用者呼叫傳遞的指標合法性檢測,使用者引數提供的指標等不能指向系統空間,這樣編寫核心**的時候只要呼叫這些函式就能實現了對核心空間的保護,編寫也比較方便。這就提醒大家自己編寫核心**的時候,千萬不要圖方便直接使用者空間與核心空間的引數拷貝,其實那些copy函式並不是說使用者空間與核心空間要怎麼切換才能拷貝,這點我看很多人都沒有真正的理解
檔案 uaccess.h:
#define make_mm_seg(s) ((mm_segment_t) )
#define kernel_ds make_mm_seg(0xffffffff)
#define user_ds make_mm_seg(page_offset)
#define get_ds() (kernel_ds)
//
取得核心空間範圍 yrg
#define get_fs() (current->addr_limit)
//
取得使用者空間範圍 yrg
#define set_fs(x) (current->addr_limit = (x))
//
設定使用者空間範圍 yrg
檔案 processor.h :
typedef struct mm_segment_t;
檔案 page.h :
include
#define __page_offset (page_offset_raw)
#define page_offset ((unsigned long)__page_offset)
檔案page_offset.h:
#include
#ifdef config_1gb
#define page_offset_raw 0xc0000000
#elif defined(config_2gb)
#define page_offset_raw 0x80000000
#elif defined(config_3gb)
#define page_offset_raw 0x40000000
#endif
//
這個顯然可以配置使用者空間與系統空間大小 yrg
大家看那get_ds()、get_fs()、set_fs()等函式可能不是你剛看到時想的那麼一回事吧?他們看來好象是訪問或者設定段,其實只是訪問或者設定乙個程序變數罷了。
你看那些copy函式使得傳遞的一些引數只能是指向使用者空間,那麼核心**對系統一些函式的呼叫怎麼辦呢,因為那時的引數都在核心空間裡面呀。你仔細看看上面不是有個set_fs(x)呼叫嗎,那就是設定這個使用者空間限制的呼叫,只要臨時設定使用者空間限制為核心空間的範圍,呼叫完了過後恢復就是了。你再看下面**就對那幾個set_fs()的作用清楚了吧。
->filename is in our kernel space
unsigned long old_fs_value = get_fs();
set_fs(get_ds()); /* after this we can access the user space data */
open(filename
, o_creat|o_rdwr|o_excl, 0640);
set_fs(old_fs_value); /* restore fs... */
好了,原理講完了,**大家也看明白了,我們再看看這種程式設計好不好呢?其實這種程式設計顯然不好。缺點如下:
還沒有形成統一的保護方式,對核心空間的保護不好。核心**程式設計不注意的話就可能使得使用者程式突破核心空間的保護。這點編寫核心**的同志一定得注意使用者空間與系統空間的拷貝一定得用那些copy函式,不要自己簡單的直接拷貝。
核心**對系統函式呼叫時設定使用者空間限制不好。這點如果設定了哪個程序的使用者空間限制還沒有設定回去的時候如果程序使用者**得到執行(應該不太可能吧)那麼就突破了核心空間限制。還有如果核心**不注意忘了恢復使用者空間限制那麼也使得核心空間保護失效。
其實有好的辦法,實現也很簡單。就是用乙個核心全域性變數儲存使用者空間範圍,這個啟動的時候根據配置計算好,核心呼叫的時候可以很方便的引用這個變數對使用者**的呼叫引數實現檢測,用另乙個核心全域性變數來區分程式是在核心態還是使用者態執行,如果在核心態再呼叫系統函式就可以不用檢測系統呼叫的引數是在核心空 間還是使用者空間。這樣就可以避免修改那個全域性變數的麻煩。
核心空間的審核系統
linux一線運維實戰 清華大學出版社 即將出版 24.3.3 核心空間的審核系統 審核系統以模組的方式連入作業系統的核心,然後對作業系統核心中發生的審核資訊做進一步的處理後將這些資訊傳送到它特有的緩衝區,之後通過特定的通訊機制與核心空間審核系統互動並把資訊寫入到特定的日誌檔案系統,而這過程中需要呼...
Linux的使用者空間與核心空間
當核心模組 或執行緒訪問記憶體時,中的記憶體位址都為邏輯位址,而對應到真正的物理記憶體位址,需要位址一對一的對映,如邏輯位址0xc0000003對應的實體地址為0 3,0xc0000004對應的實體地址為0 4,邏輯位址與實體地址對應的關係為 邏輯位址物理記憶體位址 0xc0000000 0 00x...
linux底層記憶體管理 核心空間的夥伴系統
linux核心的夥伴演算法最大限度的減少了記憶體的碎片,其實應該說成是盡自己最大的努力減少了記憶體 的碎片。其思想就是將物理記憶體分成10個鍊錶,每乙個鍊錶的元素代表一系列的連續頁面,連續頁面的數量隨鍊錶的不同而不同,linux中有10個這樣的鏈 表,按照2的從0到9次冪的連續頁面數量組成,比如鍊錶...