我一直在做一些研究,我對這個宏有點困惑。希望有人能給我一些指導。我有一些IOCTL代碼(我繼承,不能寫)和它如果檢查access_ok()
上移動到了從用戶空間複製數據前的第一件事:什麼是使用Linux宏access_ok()
#define __lddk_copy_from_user(a,b,c) copy_from_user(a,b,c)
#define __lddk_copy_to_user(a,b,c) copy_to_user(a,b,c)
long can_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case COMMAND:
if(! access_ok(VERIFY_READ, (void *)arg, sizeof(Message_par_t)))
return(retval);
if(! access_ok(VERIFY_WRITE, (void *)arg, sizeof(Message_par_t)))
return(retval);
argp = &Command;
__lddk_copy_from_user((void *) argp,(Command_par_t *) arg, sizeof(Command_par_t));
因此,代碼工作得很好,但我不確定是否需要。第一個問題來自access_ok的返回描述:
- 如果該區域可能可訪問(儘管訪問仍可能導致-EFAULT),該函數將返回非零值。這個函數簡單地檢查地址是否可能在用戶空間中,而不是在內核中。
因此,這意味着它確實沒有更多然後確保我們正在檢查對指針可能在用戶空間初始化?既然我們知道除了用戶空間調用之外我們不能進入這個功能,除非我們打開一個有效的文件描述符到這個設備,否則這是不可能發生的,這真的需要嗎?確實沒有得到一個NULL指針是否真的更安全?
第二個問題來自這樣的描述:
- type參數可以被指定爲VERIFY_READ或VERIFY_WRITE。 VERIFY_WRITE符號還標識內存區域是否可讀和可寫。
這是否意味着我的代碼中的第一個檢查是多餘的?如果我們要檢查可寫區域,我們可以作爲免費贈品閱讀嗎?
我使用x86架構,因此access_ok()和__range_no_ok()的定義是從/usr/src/linux-3.1.10-1.16/arch/x86/include/asm/uaccess.h中定義的如下:
#define access_ok(type, addr, size) (likely(__range_not_ok(addr, size) == 0))
#define __range_not_ok(addr, size) \
({ \
unsigned long flag, roksum; \
__chk_user_ptr(addr); \
asm("add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0" \
: "=&r" (flag), "=r" (roksum) \
: "1" (addr), "g" ((long)(size)), \
"rm" (current_thread_info()->addr_limit.seg)); \
flag; \
})
我不是Linux內核專家,但根據我的經驗,通常我認爲最好只嘗試一下操作,讓函數失敗,而不是事先執行這些檢查*仍然*必須爲失敗(除非有一些性能原因,爲什麼提前進行支票可能會節省大量時間);同樣,檢查它看起來像'copy_from_user'的源已經執行了讀取檢查,所以它是多餘的。只要檢查它的返回值(=不能被複制的字節數),如果它不是零則失敗,你必須返回一個錯誤。 –
對此的回答取決於'__lddk_copy_from_user()'函數/宏的作用 - 這不在主流內核中。你能用這個函數的定義來更新你的問題嗎? – caf
@caf - 好點,這是「標準的」uCLinux can驅動程序,並且該封裝器在can_defs.h中定義,但是,在我不知道它是什麼之前,我必須先查看它。 – Mike