我讀過Linux內核中的__user
說明符,用於標記函數參數Sparse以檢查函數參數。我可以傳遞一個指向linux內核空間的指針給__user參數嗎?
特別是,鑑於
int foo1(char * buf);
一個不能將指針傳遞給用戶空間buf
。
其他方式如何?在
int foo2(char __user * buf);
可以或必須我通過用戶提供的指針?我猜測前者是因爲用戶提供的指針可能真的是任何東西,但我還沒有在任何地方找到正式的__user規範。
我讀過Linux內核中的__user
說明符,用於標記函數參數Sparse以檢查函數參數。我可以傳遞一個指向linux內核空間的指針給__user參數嗎?
特別是,鑑於
int foo1(char * buf);
一個不能將指針傳遞給用戶空間buf
。
其他方式如何?在
int foo2(char __user * buf);
可以或必須我通過用戶提供的指針?我猜測前者是因爲用戶提供的指針可能真的是任何東西,但我還沒有在任何地方找到正式的__user規範。
請記住,__user
從根本上意味着指針指向用戶地址空間。它不一定是由用戶提供的,但它確實意味着它不能成爲內核內存的指針。在某些體系結構(如x86和x86_64)上,內核和用戶內存位於相同的地址空間,並且僅通過邊界(即x86中的3G以上的內核)區分。在這些體系結構中,__user
主要用作註釋以提醒開發人員應小心處理。然而,這並非總是如此!一些體系結構(如PowerPC)實際上完全爲內核使用單獨的地址空間;在這些體系結構中,__user
具有新的重要性,因爲它表示使用特殊功能(如copy_from_user
)必須來訪問指針。正常的內存訪問根本不起作用,因爲它會試圖取消引用內核地址空間中的指針,在那裏它可能無效。
A __user
指針可能會傳遞到copy_from_user
,copy_to_user
或類似的東西。
在x86-64的,這些在copy_user_64.S
實現:
/* Standard copy_to_user with segment limit checking */
ENTRY(_copy_to_user)
CFI_STARTPROC
GET_THREAD_INFO(%rax)
movq %rdi,%rcx
addq %rdx,%rcx
jc bad_to_user
cmpq TI_addr_limit(%rax),%rcx
ja bad_to_user
ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \
copy_user_generic_unrolled,copy_user_generic_string, \
copy_user_enhanced_fast_string
CFI_ENDPROC
ENDPROC(_copy_to_user)
/* Standard copy_from_user with segment limit checking */
ENTRY(_copy_from_user)
CFI_STARTPROC
GET_THREAD_INFO(%rax)
movq %rsi,%rcx
addq %rdx,%rcx
jc bad_from_user
cmpq TI_addr_limit(%rax),%rcx
ja bad_from_user
ALTERNATIVE_JUMP X86_FEATURE_REP_GOOD,X86_FEATURE_ERMS, \
copy_user_generic_unrolled,copy_user_generic_string, \
copy_user_enhanced_fast_string
CFI_ENDPROC
ENDPROC(_copy_from_user)
注cmpq TI_addr_limit(%rax),%rcx
這將確保您的指針是小於或等於current_thread_info()->addr_limit
。
此限制由set_fs()
宏設置,該宏在許多地方被調用。特別地,它可以與USER_DS
被稱爲其是定義爲:
#define USER_DS MAKE_MM_SEG(TASK_SIZE_MAX)
TASK_SIZE_MAX
定義爲:
/*
* User space process size. 47bits minus one guard page.
* ...
*/
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
在X86-64,內核在高(或負)虛擬映射地址空間。所以內核指針會失敗檢查。
總之,我覺得__user
指針不能是實際用戶提供,但保證是一個有效的用戶空間地址。我認爲唯一的限制是你必須確保你在當前的上下文中傳遞的指針是有效的(這取決於我們在說什麼,可能隨時改變)。
很好的回答;我的探索更加簡潔。事實上,在例如x86-64用戶空間是一種*模擬*獨立的地址空間。正如我的回答所見,您可以*從內核代碼訪問用戶空間指針。 –