作者: wzt
原文鏈接:https://mp.weixin.qq.com/s/-RyiuZIZWxUc38q7vGXY7A
1 用戶層
Freebsd默認的編譯器是clang,在libc的實現如下:
libc/secure/stack_protector.c:
long __stack_chk_guard[8] = {0, 0, 0, 0, 0, 0, 0, 0};[1]
static void __guard_setup(void) __attribute__((__constructor__, __used__));[2
static void
__guard_setup(void)
{
error = _elf_aux_info(AT_CANARY, (void *)tmp_stack_chk_guard,[3]
sizeof(tmp_stack_chk_guard));
if (error == 0 && tmp_stack_chk_guard[0] != 0) {
for (idx = 0; idx < nitems(__stack_chk_guard); idx++) {
__stack_chk_guard[idx] = tmp_stack_chk_guard[idx];
tmp_stack_chk_guard[idx] = 0;
}
return;
}
len = sizeof(__stack_chk_guard);
if (__sysctl(mib, nitems(mib), __stack_chk_guard, &len, NULL, 0) ==
-1 || len != sizeof(__stack_chk_guard)) {
/* If sysctl was unsuccessful, use the "terminator canary". */
((unsigned char *)(void *)__stack_chk_guard)[0] = 0;[4]
((unsigned char *)(void *)__stack_chk_guard)[1] = 0;
((unsigned char *)(void *)__stack_chk_guard)[2] = '\n';
((unsigned char *)(void *)__stack_chk_guard)[3] = 255;
}
}
[1] 處的__stack_chk_guard是個全局數組,保存的是每個進程的stack canary值,它是通過[3]處的_elf_aux_info獲取, 而這個值是在內核執行execve加載二進制程序時就提前設置好的:
exec_copyout_strings:
/*
* Prepare the canary for SSP.
*/
arc4rand(canary, sizeof(canary), 0);
destp -= sizeof(canary);
imgp->canary = destp;
copyout(canary, (void *)destp, sizeof(canary));
imgp->canarylen = sizeof(canary);
如果用戶使用的是gcc編譯器,那么stack canary的值則是在libc初始化時動態生成的:
contrib/gcclibs/libssp/ssp.c:
void *__stack_chk_guard = 0;
static void __attribute__ ((constructor))
__guard_setup (void)
{
fd = open ("/dev/urandom", O_RDONLY);
if (fd != -1)
{
ssize_t size = read (fd, &__stack_chk_guard,
sizeof (__stack_chk_guard));
}
p = (unsigned char *) &__stack_chk_guard;
p[sizeof(__stack_chk_guard)-1] = 255;
p[sizeof(__stack_chk_guard)-2] = '\n';
p[0] = 0;
}
通過讀取/dev/urandom來獲取一個指針地址,在64位上就是8字節。
2 內核層
大家要注意一個進程有兩個棧, 一個棧用于運行在用戶態, 一個棧用于進程使用系統調用時的內核棧。 freebsd的所有進程的內核棧都使用的是同一個stack canary值, 而linux的每個進程內核棧stack canary值都是不一樣的,這樣做會帶來更高的安全強度,但是對于設計來講,則會加大了性能開銷,linux為了實現這個功能,需要在進程切換的路徑中增加對stack canary的切換。
kern/stack_protector.c:
long __stack_chk_guard[8] = {};
static void
__stack_chk_init(void *dummy __unused)
{
size_t i;
long guard[nitems(__stack_chk_guard)];
arc4rand(guard, sizeof(guard), 0);
for (i = 0; i < nitems(guard); i++)
__stack_chk_guard[i] = guard[i];
}
很簡單,使用arc4rand生成一個隨機值,僅此而已, 非常簡單。
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/1621/
暫無評論