canary的前世今生
1.gs:14
这个地址是在tls存储的,据说不会映射到虚拟内存中。
然而发现0xb7e20914的值始终和canary相同。
回溯发现0xb7e20914是由
0xb7ffef0c<_dl_random>:0xbffff53b
地址的值赋予的。
2.程序初始过程
用户态下面:
动态链接库ld-linux.so.2
_start->_ld_start->_ld_start_finish->_ld_sysdep_start->dl_main->security_init(而在security_init中实现了对0xb7e20914的赋值)
而在_start前面,内核已经初始化用户栈,并且0xbffff53b已经完成赋值。
完整过程:
user:bash通过fork()生成一个新的进程,继而调用excve()执行ELF文件
kernel:sys_execve()->do_execve()->search_binary_handle()
boot_init_stack_canary()->get_random_bytes()->extract_entropy()
user:_start->_ld_start->_ld_start_finish->_ld_sysdep_start->dl_main->security_init(ld-linux-so.2)
_start->_libc_start_main->exit
3.操作系统版本
/* Support for the AT_RANDOM auxiliary vector entry was added in 2.6.29. */ #if __LINUX_KERNEL_VERSION >= 0x02061d # define __ASSUME_AT_RANDOM 1 #endif
static inline uintptr_t __attribute__ ((always_inline)) _dl_setup_stack_chk_guard (void *dl_random) { union { uintptr_t num; unsigned char bytes[sizeof (uintptr_t)]; } ret; #ifndef __ASSUME_AT_RANDOM if (__builtin_expect (dl_random == NULL, 0)) { const size_t filllen = sizeof (ret.bytes) - 1; ret.num = 0; # ifdef ENABLE_STACKGUARD_RANDOMIZE int fd = open_not_cancel_2 ("/dev/urandom", O_RDONLY); if (fd >= 0) { ssize_t reslen = read_not_cancel (fd, ret.bytes + 1, filllen); close_not_cancel_no_status (fd); if (reslen == (ssize_t) filllen) return ret.num; } # endif ret.bytes[filllen - 2] = 255; ret.bytes[filllen - 3] = '\n'; } else #endif { /* We need in the moment only 8 bytes on 32-bit platforms and 16 bytes on 64-bit platforms. Therefore we can use the data directly and not use the kernel-provided data to seed a PRNG. */ memcpy (ret.bytes, dl_random, sizeof (ret)); #if BYTE_ORDER == LITTLE_ENDIAN ret.num &= ~0xff; #elif BYTE_ORDER == BIG_ENDIAN ret.num &= ~(0xff << (8 * (sizeof (ret) - 1))); #else # error "BYTE_ORDER unknown" #endif } return ret.num; }
这表明当Linux kernel>2.6.29时,canary是由Linux内核生成的(_dl_random)保存的值;否则canary由"/dev/urandom"生成或直接赋值为0xff0a0000。最后将canary的最后一个字节改为00字节。
4.源码
canary可能在binfmt_elf.c的create_elf_tables中实现,而ASLR可能在load_elf_binary->arch_randomize_brk中实现