如何在LinuxKernel中操作file(set_fs與get_fs)


在Kernel 中,照理說能存取至 0 ~ 4GB。但是實作層面卻是只能讓我們使用到3GB ~ 4GB

這會導致我們無法使用open(),write()這些在user space下的function。

而這樣的限制,實作在current->addr_limit 中

在Kernel中若真的想要能存取 0 ~ 4GB ,就要利用set_fs()與get_fs()來達成。

因為有這樣的限制存在,所以當我們在Linux撰寫程式碼時,如果也叫用了這些系統呼叫的函式,由於這些函式

(像是open(),write())被限定只能存取0—3GB的記憶體空間,可是因為我們目前是在核心程式碼使用這些系統函式,

所以說我們所配置的記憶體空間會是在3GB—4GB之間,

所以如果沒有把系統函式所能存取的記憶體空間重新設定為0—4GB的話,

那我們在核心使用的系統函式將會發生無法存取3GB以上記憶體空間的錯誤.

所以,我們可以在許多的Linux核心函式中看到以下的程式碼區段

oldfs=get_fs(); 

set_fs(KERNEL_DS); 設定為可以存取 0—4GB,包括Linux核心所屬的記憶體空間 執行核心所提供的系統呼叫

filp->f_op->write(filp,buf,size,&filp->f_pos);   

set_fs(oldfs); 執行完系統呼叫後,重新把記憶體空間設定回0—3GB

 

只有使用上面的方法,才能在內核中使用open,write等的系統調用。其實這樣做的主要原因是open,write的參數在用戶空間,在這些系統調用的實現里需要對參數進行檢查,就是檢查它的參數指針地址是不是用戶空間的。

系統調用本來是提供給用戶空間的程序訪問的,所以,對傳遞給它的參數(比如上面的buf),它默認會認為來自用戶空間,在->write()函數中,為了保護內核空間,一般會用get_fs()得到的值來和USER_DS進行比較,從而防止用戶空間程序“蓄意”破壞內核空間。 為了解決這個問題; set_fs(KERNEL_DS)將其能訪問的空間限制擴大到KERNEL_DS,這樣就可以在內核順利使用系統調用了!

我們這里以open系統調用為例子,它最終會調用下面所示的函數:

satic

int do_getname(const char __user *filename, char *page) {  

      int retval;  unsigned long len = PATH_MAX;

      if (!segment_eq(get_fs(), KERNEL_DS)) {

      if ((unsigned long) filename >= TASK_SIZE)    

      return -EFAULT;  

}

其中就會對char __user *filename這個用戶指針進行判斷,如果它不是segment_eq(get_fs(), KERNEL_DS)就需要如上面描述的檢查它的指針是不是用戶空間指針。內核使用系統調用參數肯定是內核空間,為了不讓這些系統調用檢查參數所以必須設置  set_fs(KERNEL_DS)才能使用該系統調用.

       file->f_op->write的流程可能會調用access_ok->__range_ok,而__range_ok會判斷訪問的buf是否在0~addr_limit之間,如何是就ok,否則invalid,這顯然是為用戶准備的檢查。addr_limit一般設為__PAGE_OFFSET,在內核空間,buf肯定>__PAGE_OFFSET,必須修改addr_limit,這就是set_fs的由來。

 

ps: 在 x86 linux 系統上 ,
KERNEL_DS 為 0xFFFFFFFF ,
USER_DS 可為 0x2000000 , 0x4000000 or 0x80000000 , 所以 , 很容易知道目前 IP 在哪個 space 上
 
 
所以 linux 提供了 :
get_fs() : 取得 process(thread) 的 limited address ( 即 USER_DS )
get_ds() : 取得 Kernel Space limited address ( KERNEL_DS )
set_fs( KERNEL_DS or USER_DS ) : 設定 task limit addr

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM