作業系統核心

使用者/核心複製(copy_to_user / copy_from_user)

當程式發出系統呼叫時,它把指向自己記憶體的指標交給核心——「讀進這個緩衝區」、「從那個緩衝區寫出」。但那些指標來自不受信任的使用者程式碼,而核心是機器上最具特權的程式碼。它不能就這樣解參考它們。使用者/核心複製就是核心跨越邊界搬運資料的、有紀律且經過檢查的方式:copy_from_user 把資料從使用者緩衝區拉進核心,copy_to_user 把核心資料推出到使用者緩衝區——兩者都在碰觸任何一個位元組之前,先驗證使用者位址。

為何普通的指標解參考會危險,講具體一點。一個惡意或有臭蟲的程式可能傳入一個指進核心空間的指標、指向它並不擁有的記憶體,或根本指向無效之處。如果核心天真地做 *user_ptr,它可能代表那個程式讀取或覆寫核心資料——一場特權提升的災難——或在壞位址上讓整個核心當機。所以 copy_from_user 與 copy_to_user 先檢查那段位址範圍確實落在呼叫行程的使用者部分定址空間裡,再以一種能優雅捕捉錯誤(壞分頁)的方式進行複製:它不恐慌,而是停下複製並回傳無法複製的位元組數(非零即代表失敗),於是系統呼叫可以回傳像 -EFAULT 這樣的錯誤,而非當機。

為何這是核心程式設計裡最重要的規則之一:它是把核心/使用者邊界當作信任邊界的實務執行。每一個從使用者空間跨來的指標,在被驗證之前都被當作敵意的。一整類嚴重的核心漏洞,就來自那些忘了使用這些輔助函式、直接解參考一個使用者指標的程式碼路徑,或那些檢查了一個位址、之後又在它可能已被更改之後才使用它的程式碼(一個「檢查時到使用時」的臭蟲)。這個紀律陳述起來簡單、卻容易忘記:對一個來自使用者空間的指標,絕不信任、絕不直接解參考——永遠走經過檢查的複製。

sys_write(fd, user_buf, n):char kbuf[256]; if (copy_from_user(kbuf, user_buf, n)) return -EFAULT; // 經驗證的複製;遇到壞的使用者指標時回傳非零,而非當機——絕不直接做 *user_buf。

核心絕不直接解參考使用者指標;copy_from_user 驗證位址,遇到壞指標時以 -EFAULT 優雅地失敗。

若你之後又再次使用,只驗證位址一次並不足夠——在檢查與稍後使用之間,另一個執行緒可能更改那些分頁,這是「檢查時到使用時」(TOCTOU)的臭蟲。規則是絕對的:使用者空間指標不受信任;把每一次存取都繞經 copy_to_user/copy_from_user,絕不在核心裡直接解參考它。

又称
copy_to_usercopy_from_useruser-space memory access使用者記憶體存取