Linux编译x86架构内核出现_stack_chk_guard未定义错误
2017-07-18 10:56
597 查看
背景
android模拟器运行于virtualbox中,而virtualbox运行于x86架构的pc端,所以android及其Linux内核都编译成x86架构。当virtualbox的vt未开启的情况下android系统会出现各种问题,如arm库游戏不能运行,桌面平凡挂死重启。通过查看日志,都奔溃在了#00 pc 000183c6 /system/lib/libc.so (__get_thread+6)这个点。关于此点的日志分析过程请查看本人的另一篇文章的分析: Linux系统调用__get_thread获取TLS失败导致应用程序奔溃.
问题
在android内核为3.10时选择CONFIG_CC_STACKPROTECTOR=y(开启内核栈保护功能),在x86架构下能正常编译解决vt下桌面重复挂死、arm库游戏不能玩的问题。但是如果升级android内核为3.18,内核开启栈保护功能时,交叉编译x86架构下的linux内核就会出现编译错误。具体看如下开启内核配置和出错日志:
开启3.18栈保护的内核配置选项如下:
@@ -41,7 +41,6 @@ CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y CONFIG_HAVE_INTEL_TXT=y CONFIG_X86_32_SMP=y CONFIG_X86_HT=y -CONFIG_X86_32_LAZY_GS=y CONFIG_ARCH_HWEIGHT_CFLAGS="-fcall-saved-ecx -fcall-saved-edx" CONFIG_ARCH_SUPPORTS_UPROBES=y CONFIG_FIX_EARLYCON_MEM=y @@ -249,10 +248,10 @@ CONFIG_HAVE_CMPXCHG_DOUBLE=y CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y CONFIG_HAVE_ARCH_SECCOMP_FILTER=y CONFIG_HAVE_CC_STACKPROTECTOR=y -# CONFIG_CC_STACKPROTECTOR is not set -CONFIG_CC_STACKPROTECTOR_NONE=y +CONFIG_CC_STACKPROTECTOR=y +# CONFIG_CC_STACKPROTECTOR_NONE is not set # CONFIG_CC_STACKPROTECTOR_REGULAR is not set -# CONFIG_CC_STACKPROTECTOR_STRONG is not set +CONFIG_CC_STACKPROTECTOR_STRONG=y CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES=y CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y CONFIG_HAVE_ARCH_TRANSPARENT_HUGEPAGE=y
开启3.18内核栈保护配置后内核编译x86架构错误如下:
CHK include/generated/compile.h UPD include/generated/compile.h CC init/version.o LD init/built-in.o android-4.4.4/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.6/bin/i686-linux-android-ld: init/built-in.o: in function do_one_initcall:init_task.c(.text+0x7f): error: undefined reference to '__stack_chk_guard' android-4.4.4/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.6/bin/i686-linux-android-ld: init/built-in.o: in function do_one_initcall:init_task.c(.text+0x1c6): error: undefined reference to '__stack_chk_guard' android-4.4.4/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.6/bin/i686-linux-android-ld: init/built-in.o: in function name_to_dev_t:init_task.c(.text+0x261): error: undefined reference to '__stack_chk_guard' android-4.4.4/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.6/bin/i686-linux-android-ld: init/built-in.o: in function name_to_dev_t:init_task.c(.text+0x517): error: undefined reference to '__stack_chk_guard' make: *** [vmlinux] Error 1 arch/x86/Makefile:116: stack-protector enabled but compiler support broken
分析解决
上述error: undefined reference to '__stack_chk_guard'错误通过各种google也没有找到正解,有的说是gcc需要4.9及以上,然而用交叉编译工具4.9也不行。还查看了android源码关于
stack protector的相关修复,都没有啥卵用。最后通过查看
__stack_chk_guard字段发现,x86架构没有定义此字段,而
sh,arm,mips等架构确定义了。在穷途末路时只能自己动手依葫芦画瓢,期待有所进展。如下patch为本人添加,不仅能解决编译错误,还确实解决了vt未开启时,virtualbox下运行android镜像出现的各种问题。
Linux编译x86架构时__stack_chk_guard
未定义错误的修复patch
diff --git a/arch/x86/include/asm/stackprotector.h b/arch/x86/include/asm/stackprotector.h index 6a99859..3e2d812 100644 --- a/arch/x86/include/asm/stackprotector.h +++ b/arch/x86/include/asm/stackprotector.h @@ -41,6 +41,10 @@ #include <asm/desc.h> #include <linux/random.h> +#if (defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)) +extern unsigned long __stack_chk_guard; +#endif + /* * 24 byte read-only segment initializer for stack canary. Linker * can't handle the address bit shifting. Address will be set in @@ -79,6 +83,10 @@ static __always_inline void boot_init_stack_canary(void) #else this_cpu_write(stack_canary.canary, canary); #endif + +#if (defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)) + __stack_chk_guard = current->stack_canary; +#endif } static inline void setup_stack_canary_segment(int cpu) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 4eb204c..5ad8ab2 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -29,6 +29,12 @@ #include <asm/debugreg.h> #include <asm/nmi.h> + +#if (defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)) + unsigned long __stack_chk_guard __read_mostly; +/* 配置打开SMP时,会出现此__stack_chk_guard变量重复定义问题,所有只能在无SMP下生效 */ +//static DEFINE_PER_CPU(unsigned long,__stack_chk_guard) __read_mostly; +EXPORT_SYMBOL(__stack_chk_guard); +#endif + /* * per-CPU TSS segments. Threads are completely 'soft' on Linux, * no more per-task TSS's. The TSS size is kept cacheline-aligned diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 8f3ebfe..f027d25 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c @@ -39,6 +39,11 @@ #include <asm/pgtable.h> #include <asm/ldt.h> #include <asm/processor.h> + +#if (defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)) +#include <linux/stackprotector.h> +#endif + #include <asm/i387.h> #include <asm/fpu-internal.h> #include <asm/desc.h> @@ -249,6 +254,11 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) *next = &next_p->thread; int cpu = smp_processor_id(); struct tss_struct *tss = &per_cpu(init_tss, cpu); + + #if (defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)) + __stack_chk_guard = next_p->stack_canary; + #endif + fpu_switch_t fpu; /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */
为啥内核能正常选择打开栈保护功能但却无法编译通过呢,后面想了想,可能有如下原因:
一是godlfish内核主要对移动手机设备使用的内核,手机一般使用的是arm芯片,对于x86架构官方关注的也许并不多。二是默认此栈保护功能是关闭的,只有对运行稳定性有特殊需求的产品,如航天,太空类高稳定产品才需要考虑打开,打开后会稍微降低性能。
此patch应该是可以作为官网的patch来提交修复,福泽大众的,但本人从来没有提交过,限于水平有限,暂且记录,以备后忘。
【注:关于内核栈保护原理,可以参考文章:CC_STACKPROTECTOR防内核堆栈溢出补丁分析】
感谢
2017 …… ,卷起裤管跑,撸起袖子干!yanxiangyfg的专栏 : “忠于实践,记录点滴”
相关文章推荐
- 编译linux-2.6.20内核出现scripts/mod/sumversion.c:384: error: ‘PATH_MAX’ undeclared 错误
- Fedora9.0和VMware6.5下编译内核出现arm-linux-gcc无法找到的错误解决办法
- Linux内核编译出现__crc_munlock_vma_pages_all多次定义
- linux 内核编译时出现scripts/sign-file.c:23:30: fatal error: openssl/opensslv.h错误的解决办法
- linux 内核编译时出现scripts/sign-file.c:25:30: fatal error: openssl/opensslv.h错误的解决办法
- GCC-4.6.3编译linux2.6.32.12内核出现“重复的成员‘page’”错误的解决方法
- 在VMware上编译linux内核出现VFS: Cannot open root device "LABEL=/" or unknown-block(0,0) 错误的解决方法
- linux下编译C++程序出现错误 “*** stack smashing detected ***, eclipse解决方法
- 编译Linux内核出现include/linux/compiler-gcc.h:106:30: fatal error: linux/compiler-gcc5.h错误
- linux内核编译时出现的错误
- linux 内核编译时出现scripts/sign-file.c:23:30: fatal error: openssl/opensslv.h错误的解决办法
- linux内核编译过程中出现两个错误的解决方法~!
- linux 内核编译时出现scripts/sign-file.c:23:30: fatal error: openssl/opensslv.h错误的解决办法
- Linux 内核编译 出现错误 make:arm-none-linux-gnueabi-gcc:命令未找到
- Fedora9.0和VMware6.5下编译内核出现arm-linux-gcc无法找到的错误解决办法
- linux学习--编译php出现错误 : configure: error: libpng.(a|so) not found.
- Linux中 qt 编译出现tslib错误
- initramfs系统制作时,编译内核出现错误Kernel panic - not syncing: Attempted to kill init
- 解决编译linux2.4和linux 2.6内核出现/usr/bin/ld: cannot find -lncurses的问题
- 编译基于arm平台的内核,出现error: invalid option `abi=aapcs-linux'