linux空間(linux基礎(chǔ)命令表)
一、 問題描述 access_ok函數(shù)是什么原理?
問題
二、問題分析 我們在內(nèi)核空間和用戶空間進行數(shù)據(jù)拷貝的時候必須判斷用戶空間地址是否合法 。主要通過偶函數(shù)access_ok來判斷 。
1. Linux用戶空間與內(nèi)核地址空間 Linux 操作系統(tǒng)和驅(qū)動程序運行在內(nèi)核空間,應用程序運行在用戶空間,兩者不能簡單地使用指針傳遞數(shù)據(jù),因為Linux使用的虛擬內(nèi)存機制,用戶空間的數(shù)據(jù)可能被換出,當內(nèi)核空間使用用戶空間指針時,對應的數(shù)據(jù)可能不在內(nèi)存中 。
通常32位Linux內(nèi)核地址空間劃分0~3G為用戶空間,3~4G為內(nèi)核空間 。注意這里是32位內(nèi)核地址空間劃分,64位內(nèi)核地址空間劃分是不同的 。
- 進程尋址空間0~4G
- 進程在用戶態(tài)只能訪問0~3G,只有進入內(nèi)核態(tài)才能訪問3G~4G
- 進程通過系統(tǒng)調(diào)用進入內(nèi)核態(tài)
- 每個進程虛擬空間的3G~4G部分是相同的
- 進程從用戶態(tài)進入內(nèi)核態(tài)不會引起CR3的改變但會引起堆棧的改變
access_ok ( type,addr,size); 功能:
access_ok — 檢查用戶空間指針是否有效 注意,根據(jù)體系結(jié)構(gòu)的不同,這個函數(shù)可能只是檢查指針是否在用戶空間范圍內(nèi),在調(diào)用這個函數(shù)之后,內(nèi)存訪問函數(shù)可能仍然返回 -EFAULT參數(shù)說明:
type Type of access: VERIFY_READ or VERIFY_WRITE. 請注意,VERIFY_WRITE是VERIFY_READ的超集——如果寫入一個塊是安全的,那么從它讀取總是安全的 。 addr 要檢查的塊的開始的用戶空間指針 size 要檢查的塊的大小返回值:
此函數(shù)檢查用戶空間中的內(nèi)存塊是否可用 。如果可用,則返回真(非0值),否則返回假 (0)。2. 源碼分析 #define access_ok(type, addr, size) (__range_ok(addr, size) == 0) /* We use 33-bit arithmetic here... */#define __range_ok(addr, size) ({ \ unsigned long flag, roksum; \ __chk_user_ptr(addr); \ __asm__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \ : "=&r" (flag), "=&r" (roksum) \ : "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \ : "cc"); \ flag; }) static inline void __chk_user_ptr(const volatile void *p, size_t size){ assert(p >= __user_addr_min && p + size <= __user_addr_max);} 其中__range_ok詳解如下: 參數(shù)對應:
flag -------- %0roksum -------- %1addr -------- %2size -------- %3 匯編指令詳解
adds %1, %2, %3 等價于:
rosum = addr + size 這個操作會影響狀態(tài)位(目的是影響是進位標志C) 。
以下的兩個指令都帶有條件CC,也就是當C=0的時候才執(zhí)行; 如果上面的加法指令進位了(C=1),則以下的指令都不執(zhí)行,flag就為初始值current_thread_info()->addr_limit(非0),并返回 。如果沒有進位(C=0),就執(zhí)行下面的指令:
sbcccs %1, %1, %0 該指令等價于
rosum = rosum - flag - 1 也就是(addr + size) – (current_thread_info()->addr_limit) – 1,操作影響符號位 。.
如果(addr + size) >= (current_thread_info()->addr_limit) – 1,則C=1 如果(addr + size) < (current_thread_info()->addr_limit) – 1,則C=0 當C=0的時候執(zhí)行以下指令,否則跳過(flag非零) 。
movcc %0, #0 等價于
flag = 0,給flag賦值0 。 綜上所述:__range_ok宏等價于:
如果(addr + size) >= (current_thread_info()->addr_limit) - 1,返回非零值如果(addr + size) < (current_thread_info()->addr_limit),返回零 而access_ok就是檢驗將要操作的用戶空間的地址范圍是否在當前進程的用戶地址空間限制中 。這個宏的功能很簡單,完全可以用C實現(xiàn),不是必須使用匯編 。由于這兩個函數(shù)使用頻繁,就使用匯編來實現(xiàn)部分功能來增加效率 。
3. 使用實例 我們在內(nèi)核拷貝數(shù)據(jù)到用戶空間或者從用戶空間拷貝數(shù)據(jù)到內(nèi)核空間,都需要判斷用戶空間地址是否在用戶空間 。
static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n){ if (access_ok(VERIFY_READ, from, n)) n = __copy_from_user(to, from, n); else /* security hole - plug it */ memset(to, 0, n); return n;}static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n){ if (access_ok(VERIFY_WRITE, to, n))
【linux空間 linux基礎(chǔ)命令表】
推薦閱讀
- 海虹炒雞蛋怎么炒好吃
- 涂素顏霜后要涂什么
- 藍環(huán)章魚能吃嗎
- 鹽橋是什么
- 柔膚水也都含有酒精成份嗎
- 新生軍訓 學生軍訓內(nèi)容
- 不避讓特種車輛扣幾分
- 精彩的小說 五本經(jīng)典小說
- 速干衣什么牌子好
