在内核中调用系统调用,需要使用get_fs,set_fs来对其保护,因为这些函数会检查参数地址是不是
用户空间的,但是很显然,我们是在内核空间中调用这些系统调用。
#define get_ds() (KERNEL_DS)
可以看到这里的get_fs 直接返回的是当前进程的地址限制,用户进程和内核进程肯定是不一样的
#define get_fs() (current_thread_info()->addr_limit)
而set_fs稍微复杂点分析如下:
static inline void set_fs(mm_segment_t fs)
{
#首先设置当前进程的地址限制,这样一般是通过get_ds得到的
current_thread_info()->addr_limit = fs;
/*
* Prevent a mispredicted conditional call to set_fs from forwarding
* the wrong address limit to access_ok under speculation.
*/
dsb(nsh);
isb();
/* On user-mode return, check fs is correct */
set_thread_flag(TIF_FSCHECK);
/*
* Enable/disable UAO so that copy_to_user() etc can access
* kernel memory with the unprivileged instructions.
*/
#设置让非特权指令访问kernel的内存
if (IS_ENABLED(CONFIG_ARM64_UAO) && fs == KERNEL_DS)
asm(ALTERNATIVE("nop", SET_PSTATE_UAO(1), ARM64_HAS_UAO));
else
asm(ALTERNATIVE("nop", SET_PSTATE_UAO(0), ARM64_HAS_UAO,
CONFIG_ARM64_UAO));
}
这里的UAO目前都是默认打开的,是armv8.2的新特性
config ARM64_UAO
bool "Enable support for User Access Override (UAO)"
default y
help
User Access Override (UAO; part of the ARMv8.2 Extensions)
causes the 'unprivileged' variant of the load/store instructions to
be overridden to be privileged.
This option changes get_user() and friends to use the 'unprivileged'
variant of the load/store instructions. This ensures that user-space
really did have access to the supplied memory. When addr_limit is
set to kernel memory the UAO bit will be set, allowing privileged
access to kernel memory.
Choosing this option will cause copy_to_user() et al to use user-space
memory permissions.
The feature is detected at runtime, the kernel will use the
regular load/store instructions if the cpu does not implement the
feature.