Copy_from&to_user詳解  轉載

copy_from&toza_user詳解
copy_from_user函數的目的是從用戶空間拷貝數據到內核空間,失敗返回沒有被拷貝的字節數,成功返回0.
這麼簡單的一個函數卻含蓋了許多關於內核方面的知識,比如內核關於異常出錯的處理.從用戶空間拷貝
數據到內核中時必須很小心,假如用戶空間的數據地址是個非法的地址,或是超出用戶空間的範圍,或是
那些地址還沒有被映射到,都可能對內核產生很大的影響,如oops,或被造成系統安全的影響.所以
copy_from_user函數的功能就不只是從用戶空間拷貝數據那樣簡單了,他還要做一些指針檢查連同處理這些
問題的方法.下面我們來仔細分析下這個函數.函數原型在[arch/i386/lib/usercopy.c]中
unsigned long
copy_from_user(void *to, const void __user *from, unsigned long n)
{
    might_sleep();    
    if (access_ok(VERIFY_READ, from, n))
        n = __copy_from_user(to, from, n);
    else
        memset(to, 0, n);
    return n;
}
首先這個函數是能夠睡眠的,他調用might_sleep()來處理,他在include/linux/kernel.h中定義,
本質也就是調用schedule(),轉到其他進程.接下來就要驗證用戶空間地址的有效性.他在
[/include/asm-i386/uaccess.h]中定義.
#define access_ok(type,addr,size) (likely(__range_ok(addr,size) == 0)),進一步調用__rang_ok
函數來處理,他所做的測試很簡單,就是比較addr+size這個地址的大小是否超出了用戶進程空間的大小,
也就是0xbfffffff.可能有讀者會問,只做地址範圍檢查,怎麼不做指針合法性的檢查呢,假如出現前面
提到過的問題怎麼辦?這個會在下面的函數中處理,我們慢慢看.在做完地址範圍檢查後,假如成功則調用
__copy_from_user函數開始拷貝數據了,假如失敗的話,就把從to指針指向的內核空間地址到to+size範圍
填充爲0.__copy_from_user也在uaceess.h中定義,
static inline unsigned long
__copy_from_user(void *to, const void __user *from, unsigned long n)
{
       might_sleep();
       return __copy_from_user_inatomic(to, from, n);
}
這裏繼續調用__copy_from_user_inatomic.
static inline unsigned long
__copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
{
    if (__builtin_constant_p(n)) {
        unsigned long ret;
        switch (n) {
        case 1:
            __get_user_size(*(u8 *)to, from, 1, ret, 1);
            return ret;
        case 2:
            __get_user_size(*(u16 *)to, from, 2, ret, 2);
            return ret;
        case 4:
            __get_user_size(*(u32 *)to, from, 4, ret, 4);
            return ret;
        }
    

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章