[转载]辨析access_ok put_user __put_user get_user __get_user

来源:互联网 发布:路由器网络不稳定 编辑:程序博客网 时间:2024/05/16 07:10

在使用ioctl的可选arg参数时,如果传递的是一个整数,它可以直接使用。如果是一个指针,,就必须小心。当用一个指针引用用户空间,我们必须确保用户地址是有效的,其校验(不传送数据) 由函数access_ok实现,定义在 :

int access_ok(int type, const void *addr, unsigned long size);

第一个参数应当是VERIFY_READ(读)或VERIFY_WRITE(读写);addr参数为用户空间地址,size 为字节数,可使用sizeof()。access_ok返回一个布尔值:1是成功 (存取没问题) 和0是失败 (存取有问题)。如果它返回假,驱动应当返回-EFAULT给调用者。

注意:首先,access_ok不做校验内存存取的完整工作;它只检查内存引用是否在这个进程有合理权限的内存范围中,且确保这个地址不指向内核空间内存。其次,大部分驱动代码不需要真正调用access_ok,而直接使用put_user(datum, ptr)和get_user(local, ptr),它们带有校验的功能,确保进程能够写入给定的内存地址,成功时返回0,并且在错误时返回-EFAULT。

put_user(datum, ptr) __put_user(datum, ptr) get_user(local, ptr) __get_user(local, ptr)

这些宏它们相对copy_to_user和copy_from_user快,并且这些宏已被编写来允许传递任何类型的指针,只要它是一个用户空间地址,传送的数据大小依赖prt 参数的类型并且在编译时使用sizeof 和typeof 等编译器内建宏确定。他们只传送1、2、4或8 个字节。如果使用以上函数来传送一个大小不适合的值,结果常常是一个来自编译器的奇怪消息,如”coversion to non-scalar type requested”。在这些情况中,必须使用copy_to_user或者copy_from_user。

__put_user和__get_user进行更少的检查 (不调用access_ok),但是仍然能够失败如果被指向的内存对用户是不可写的,所以他们应只用在内存区已经用access_ok检查过的时候。作为通用的规则:当实现一个read方法时,调用__put_user来节省几个周期,或者当你拷贝几个项时,因此,在第一次数据传送之前调用access_ok一次。

xxxx 会去调用 __xxxx
一般有几种情况要分开写
1、
xxxx 是统一的接口,而__xxxx 是具体cpu架构下的实现,很可能有多个__xxxx,当然最终只有一个__xxxx被编译

2、xxxx 检验一下参数或加保护后调__xxxx ,这类似一种编码习惯,能减少bug

3、xxxx的参数或返回值有有更改,为了低版本的代码不用修改,实现一个__xxxx做过渡。

0 0