access_ok()

  内核空间虽然可以访问用户空间,但是在访问之前,一般需要先检查其合法性,通过access_ok(type, addr, size)进行判断,以确定传入的缓冲区的确属于用户缓冲区,例如:

access_ok()
 1 static ssize_t read_port(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 2 {    
 3     unsigned long i = *ppos;
 4     char __user *tmp = buf;
 5 
 6     if (!access_ok(VERIFY_WRITE, buf, count)) 
 7         return -EFAULT;
 8     while (count-- > 0 && i < 65536) {
 9         if (__put_user(inb(i), tmp) < 0)
10             return -EFAULT;
11         i++;
12         tmp++;
13     }
14     *ppos = i;
15     return tmp - buf;
16 }
View Code

  上述代码中引用__put_user()与前文件讲解的put_user()的区别在于前者不进行类似access_ok()的检查,而后者会进行这一检查。在本例中,不使用put_user()而使用__put_user()的原因是在__put_user()调用之前,已经手动检查了用户空间缓冲区(buf指向的大小为count的内存)的合法性。get_user()和__get_user()的区别也相似。

  特别要提醒读者注意的是:在内核空间与用户空间的界面处,内核检查用户空间缓冲区的合法性显得尤为重要,Linux内核的许多安全漏洞都是因为遗忘了这一检查造成的,非法入侵者可以伪造一片内核空间缓冲区地址传入系统调用的接口,让系统对这个evil指针指向的内核空间填充数据。

  其实copy_from_user()、copy_to_user()内部也进行了这样的检查。

access_ok()
 1 static inline unsigned long __must_check copy_from_user(void *to, const void __user *from,
 2     unsigned long n)
 3 {
 4     if (access_ok(VERIFY_READ, from, n))
 5         n = __copy_from_user(to, from, n);
 6     else /* security hole - plug it */
 7         memset(to, 0, n);
 8     return n;
 9 }
10 
11 static inline unsigned long __must_check copy_to_user(void __user *to, const void *from,
12     unsigned long n)
13 {
14     if (access_ok(VERIFY_WRITE, to, n))
15         n = __copy_to_user(to, from, n);
16     return n;
17 }
View Code

 

  

access_ok()

上一篇:MySQL--WHERE专题


下一篇:网络设备配置中经常使用的access-list(Cisco)或rule(华为设备中使用)