2011-11-25 66 views

回答

15

copy_from_user()的實現高度依賴於體系結構。

在x86和x86-64上,它只是直接從用戶空間地址讀取數據並寫入內核空間地址,而如果配置了SMAP(Supervisor Mode Access Prevention),則暫時禁用它。其中最棘手的部分是copy_from_user()代碼被放置在一個特殊區域,以便頁面錯誤處理程序可以識別其中發生故障的時間。在copy_from_user()中發生的內存保護錯誤不會像任何其他進程上下文代碼所觸發的那樣終止進程,也不會像在中斷上下文中那樣使內核發生混亂 - 它只是在代碼中恢復執行路徑返回給調用者-EFAULT

+0

謝謝,我確信回合由內核直接訪問,所以基本上我想它在傳遞到它的指針/地址的事先檢查,以檢查是否存在無效的地址不傳遞到函數I意思是說地址屬於一些其他的用戶空間進程...無論如何,我不知道你提到的內存保護事情....因此,我的DOUBT是在copy_to_user的情況下回合...因爲用戶空間在內核空間VM中傳遞一個地址....用戶空間如何處理它。或者是內核將該地址映射到某個用戶空間地址 – Santi1986

+3

@ Santi1986:'copy_to_user()'的工作原理完全相同除了源地址和目標地址交換之外 - 它從內核地址讀取並寫入用戶空間地址。在兩者中完成的唯一檢查是用戶空間地址真* *低於內核/用戶拆分;沒有必要檢查屬於其他用戶進程的地址,因爲'copy _ * _ user()'僅在進程上下文中調用,這意味着* all *地址是內核地址或屬於當前進程。 – caf

+0

感謝您的時間,我只是瀏覽儘管代碼並發現了這個內核檢查通過access_ok指針的有效性),基本功能__copy _ * _用戶稱爲內部使用此功能__copy _ * _ user_inatomic這最後調用__copy __ * _ user_ll,這真正的複製,並且PAGES是PINNED PRIOR COPYING ....如果整個數據沒有被複制,其填充零(通過傳遞給該調用的len) – Santi1986

1

copy_from_user()系統調用的實現是使用來自不同地址空間的兩個緩衝區完成的。

  • 用戶空間緩衝區在用戶虛擬地址中。
  • 內核空間緩衝區在內核虛擬地址。

當調用copy_from_user()系統調用時,數據從用戶緩衝區複製到內核緩衝區。

的字符設備驅動程序代碼,在使用下面給出調用copy_from_user()A部分(寫操作):

ssize_t供cdev_fops_write(結構文件*翻轉,常量字符__user * UBUF,爲size_t計數,參數loff_t * f_pos)

{

unsigned int *kbuf; 

copy_from_user(kbuf, ubuf, count); 

printk(KERN_INFO "Data: %d",*kbuf); 

}

+0

確定我對你的懷疑回答是,它適用於copy_from_user。由於內核正在傳遞內核空間地址,因此如何回合copy_to_user,用戶空間進程如何訪問它。內核是否先在用戶空間虛擬機中創建一個映射,以便用戶可以從那裏訪問它 – Santi1986

7

關於「內核傳遞內核空間地址時如何回覆copy_to_user,用戶空間進程如何訪問它」

用戶空間進程可以嘗試訪問任何地址。但是,如果該地址未映射到該進程用戶空間(即該進程的頁表中)或存在訪問問題(如嘗試寫入只讀位置),則會生成頁面錯誤。請注意,至少在x86上,每個進程都將所有內核空間映射到該進程的虛擬地址空間的最低1 GB,而4 GB總地址空間的上千兆字節(我在此使用的是32位經典案例)用於過程文本(即代碼)和數據。 向用戶空間或從用戶空間複製的副本由代表進程執行的內核代碼執行,實際上它是該進程在複製過程中正在使用的內存映射(即頁表)。這發生在執行處於內核模式時 - 即x86語言中的特權/超級用戶模式。 假設用戶空間代碼已經通過合法的目標位置(即,在該進程地址空間中正確映射的地址)將數據複製到從內核上下文運行的copy_to_user將能夠正常地寫入該地址/區域以解決問題,並且在控制返回給用戶之後,用戶空間也可以從該進程本身設置的位置讀取以開始。 更多有趣的細節可以在Daniel P. Bovet,Marco Cesati的「理解Linux內核」第3版的第9章和第10章中找到。特別是,access_ok()是一個必要但不充分的有效性檢查。用戶仍然可以傳遞不屬於進程地址空間的地址。在這種情況下,內核代碼執行副本時會發生Page Fault異常。最有趣的部分是內核頁面錯誤處理程序如何確定在這種情況下的頁面錯誤不是由於內核代碼中的錯誤而是由用戶的錯誤地址造成的(特別是如果內核代碼來自內核模塊加載)。

1

最好的回答有什麼不對,copy_(從|到)用戶不能在中斷上下文中使用,他們可能睡覺,複製(從|到)用戶功能只能在進程上下文中使用, 進程的頁表包括內核需要訪問它的所有信息,所以內核可以直接訪問用戶空間的地址,如果我們能夠確保頁面地址是在內存中,使用複製(從|到)_user功能,因爲他們可以爲我們檢查它,如果用戶空間尋址頁面沒有駐留,它會直接爲我們修復它。