本文将mark下SMAP(Supervisor Memory Access Protection) and SMEP(Supervisor Memory Execute Protection)相关notes,参考kernel版本为v6.3

Introduction

SMEP prevents the kernel running in ring 0 from executing code which is user accessible. SMAP prevents the kernel from accessing userspace memory while the AC flag in the RFLAGS register is clear. These features can help harden the kernel against exploitation and prevent certain kinds of memory corruption.

Description from SDM




copy_to_user

由于内核空间与用户空间的内存不能直接互访,因此需要借助内核函数copy_to_user完成内核空间到用户空间的复制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* igb_ptp_get_ts_config - get hardware time stamping config
* @netdev: netdev struct
* @ifr: interface struct
*
* Get the hwtstamp_config settings to return to the user. Rather than attempt
* to deconstruct the settings from the registers, just return a shadow copy
* of the last known settings.
**/
int igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct hwtstamp_config *config = &adapter->tstamp_config;

return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ?
-EFAULT : 0;
}
1
2
3
4
copy_to_user
└── _copy_to_user
└── raw_copy_to_user
└── copy_user_generic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static __always_inline __must_check unsigned long
copy_user_generic(void *to, const void *from, unsigned len)
{
unsigned ret;

/*
* If CPU has ERMS feature, use copy_user_enhanced_fast_string.
* Otherwise, if CPU has rep_good feature, use copy_user_generic_string.
* Otherwise, use copy_user_generic_unrolled.
*/
alternative_call_2(copy_user_generic_unrolled,
copy_user_generic_string,
X86_FEATURE_REP_GOOD,
copy_user_enhanced_fast_string,
X86_FEATURE_ERMS,
ASM_OUTPUT2("=a" (ret), "=D" (to), "=S" (from),
"=d" (len)),
"1" (to), "2" (from), "3" (len)
: "memory", "rcx", "r8", "r9", "r10", "r11");
return ret;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
SYM_FUNC_START(copy_user_generic_string)
ASM_STAC
cmpl $8,%edx
jb 2f /* less than 8 bytes, go to byte copy loop */
ALIGN_DESTINATION
movl %edx,%ecx
shrl $3,%ecx
andl $7,%edx
1: rep movsq
2: movl %edx,%ecx
3: rep movsb
xorl %eax,%eax
ASM_CLAC
RET

11: leal (%rdx,%rcx,8),%ecx
12: movl %ecx,%edx /* ecx is zerorest also */
jmp .Lcopy_user_handle_tail

_ASM_EXTABLE_CPY(1b, 11b)
_ASM_EXTABLE_CPY(3b, 12b)
SYM_FUNC_END(copy_user_generic_string)
EXPORT_SYMBOL(copy_user_generic_string)

从copy_user_generic_string的第2行可知,在内核态往用户态复制内存前,需要运行STAC指令;从第13行可知,在内核态往用户态复制内存后,需要运行CLAC指令。


参考资料:

  1. Supervisor Memory Protection
  2. x86, smap: Add STAC and CLAC instructions to control user space access
  3. copy_to_user/copy_from_user参数解析