access_ok
access_ok()
用来代替老版本的 verify_area()
检查用户空间指针是否可用
函数原型:
access_ok (type, addr, size);
变量说明:
type : 访问类型,其值可为 VERIFY_READ 或 VERIFY_WRITE 。
addr : 用户空间的指针变量,指向一个要检查的内存块开始处。
size : 要检查内存块大小
注意:
VERIFY_WRITE 是 VERIFY_READ 的超集
如果可以安全写内存块,那么肯定能读到内存块。
返回值:
此函数检查用户空间中的内存块是否可用。
如果可用,则返回真(非0值),否则返回假 (0) 。
代码示例:
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
参考:https://blog.csdn.net/dfz87292/article/details/102394781?utm_term=accessok%E5%87%BD%E6%95%B0&utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allsobaiduweb~default-0-102394781&spm=3001.4430
//=======================================================================
kernel get_user 示例
在内核空间和用户空间交换数据时, get_user 和 put_user 是两个两用的函数。
相对于 copy_to_user 和 copy_from_user ,主要用于完成一些简单类型变量(char、int、long等)的拷贝任务,
对于一些复合类型的变量,比如数据结构或者数组类型,get_user 和 put_user 函数还是无法胜任,
这两个函数内部将对指针指向的对象长度进行检查,在 arm 平台上只支持长度为1,2,4,8的变量。
struct Demo {
int index;
int count;
};
// arg1 是用户空间传递下来的地址
struct Demo __user *demo1 = (struct Demo __user *)arg1;
// index 用来承接用户空间的对应值
int index;
if (get_user(index, &demo1->index))
return -EFAULT;
// arg2 是用户空间传递下来的地址
int count = 2;
struct Demo __user *demo2 = (struct Demo __user *)arg2;
if (put_user(count, &demo2->count))
return -EFAULT;
//=======================================================================
put_user 和 get_user 具体分析
#define put_user(x, ptr) \
({ \
void __user *__p = (ptr); \
might_fault(); \
access_ok(VERIFY_WRITE, __p, sizeof(*ptr)) ? \
__put_user((x), ((__typeof__(*(ptr)) __user *)__p)) : \
-EFAULT; \
})
#define __put_user(x, ptr) \
({ \
__typeof__(*(ptr)) __x = (x); \
int __pu_err = -EFAULT; \
__chk_user_ptr(ptr); \
switch (sizeof (*(ptr))) { \
case 1: \
case 2: \
case 4: \
case 8: \
__pu_err = __put_user_fn(sizeof (*(ptr)), \
ptr, &__x); \
break; \
default: \
__put_user_bad(); \
break; \
} \
__pu_err; \
})
static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
{
return unlikely(raw_copy_to_user(ptr, x, size)) ? -EFAULT : 0;
}
#define get_user(x, ptr) \
({ \
const void __user *__p = (ptr); \
might_fault(); \
access_ok(VERIFY_READ, __p, sizeof(*ptr)) ? \
__get_user((x), (__typeof__(*(ptr)) __user *)__p) :\
((x) = (__typeof__(*(ptr)))0,-EFAULT); \
})
static inline int __get_user_fn(size_t size, const void __user *ptr, void *x)
{
return unlikely(raw_copy_from_user(x, ptr, size)) ? -EFAULT : 0;
}
#define __get_user(x, ptr) \
({ \
int __gu_err = -EFAULT; \
__chk_user_ptr(ptr); \
switch (sizeof(*(ptr))) { \
case 1: { \
unsigned char __x = 0; \
__gu_err = __get_user_fn(sizeof (*(ptr)), \
ptr, &__x); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
case 2: { \
unsigned short __x = 0; \
__gu_err = __get_user_fn(sizeof (*(ptr)), \
ptr, &__x); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
case 4: { \
unsigned int __x = 0; \
__gu_err = __get_user_fn(sizeof (*(ptr)), \
ptr, &__x); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
case 8: { \
unsigned long long __x = 0; \
__gu_err = __get_user_fn(sizeof (*(ptr)), \
ptr, &__x); \
(x) = *(__force __typeof__(*(ptr)) *) &__x; \
break; \
}; \
default: \
__get_user_bad(); \
break; \
} \
__gu_err; \
})
小彩蛋
static inline void uaccess_disable(void)
{
__uaccess_disable(ARM64_HAS_PAN);
}
static inline void uaccess_enable(void)
{
__uaccess_enable(ARM64_HAS_PAN);
}
本文详细介绍了Linux内核中access_ok函数的作用及使用方法,该函数用于检查用户空间指针的有效性。此外,还深入分析了get_user和put_user函数的工作原理,并通过示例展示了如何在内核空间与用户空间之间安全地交换数据。

1102

被折叠的 条评论
为什么被折叠?



