New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CONFIG_STACKPROTECTOR] Wrong instruction was generated when the customized stack protector is enabled for i386 #1854
Comments
cc @xiangzh1 |
Not a bug. This is invalid input. By specifying |
But it could work in GCC. In my patch, it is necessary to define a Per-CPU variable for extern unsigned long __stack_chk_guard;
void test(unsigned long canary)
{
asm volatile("movq %[val], %%gs:%[var]"
: [var] "+m" (__stack_chk_guard)
: [val] "re" (canary));
}
int foo(int i)
{
char X[200];
X[i] = 1;
return 3;
} I tested |
What happens if |
Your case (implicit I recommend that you define |
The link failed due to the undefined symbol "__stack_chk_guard". ld.lld: error: undefined symbol: __stack_chk_guard
>>> referenced by usercopy_64.c
>>> vmlinux.o:(trace_event_raw_event_initcall_level)
>>> referenced by usercopy_64.c
>>> vmlinux.o:(trace_event_raw_event_initcall_level)
>>> referenced by usercopy_64.c
>>> vmlinux.o:(perf_trace_initcall_level) |
Actually, x86_32 had already used the same options for the per-cpu stack protector in the mainline (commit: 3fb0fdb). Therefore, I believe it would also generate wrong instructions for the 32-bit kernel. However, it still booted successfully. When I used objdump on arch/x86/kernel/cpu/common.c, where the __stack_chk_guard symbol is defined, the generated instruction is: 000001b0 <load_direct_gdt>:
1b0: 55 push %ebp
1b1: 89 e5 mov %esp,%ebp
1b3: 83 ec 0c sub $0xc,%esp
1b6: 8b 0d 00 00 00 00 mov 0x0,%ecx
1b8: R_386_32 __stack_chk_guard
1bc: 89 4d fc mov %ecx,-0x4(%ebp) The compile command is: savedcmd_arch/x86/kernel/cpu/common.o := clang -Wp,-MMD,arch/x86/kernel/cpu/.common.o.d -nostdinc -I./arch/x86/include -I./arch/x86/include/generated -I./include -I./arch/x86/include/uapi -I./arch/x86/include/generated/uapi -I./include/uapi -I./include/generated/uapi -include ./include/linux/compiler-version.h -include ./include/linux/kconfig.h -include ./include/linux/compiler_types.h -D__KERNEL__ -Werror -fmacro-prefix-map=./= -Wall -Wundef -Werror=strict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -fshort-wchar -fno-PIE -Werror=implicit-function-declaration -Werror=implicit-int -Werror=return-type -Wno-format-security -funsigned-char -std=gnu11 --target=x86_64-linux-gnu -fintegrated-as -Werror=unknown-warning-option -Werror=ignored-optimization-argument -Werror=option-ignored -Werror=unused-command-line-argument -mno-sse -mno-mmx -mno-sse2 -mno-3dnow -mno-avx -fcf-protection=none -m32 -msoft-float -mregparm=3 -freg-struct-return -fno-pic -mstack-alignment=4 -march=i686 -ffreestanding -mstack-protector-guard-reg=fs -mstack-protector-guard-symbol=__stack_chk_guard -Wno-sign-compare -fno-asynchronous-unwind-tables -mretpoline-external-thunk -mfunction-return=thunk-extern -fno-delete-null-pointer-checks -Wno-frame-address -Wno-address-of-packed-member -O2 -Wframe-larger-than=2048 -fstack-protector-strong -Wno-gnu -Wno-unused-but-set-variable -Wno-unused-const-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-stack-clash-protection -mfentry -DCC_USING_FENTRY -falign-functions=4 -Wdeclaration-after-statement -Wvla -Wno-pointer-sign -Wcast-function-type -Wimplicit-fallthrough -fno-strict-overflow -fno-stack-check -Werror=date-time -Werror=incompatible-pointer-types -Wno-initializer-overrides -Wno-format -Wformat-extra-args -Wformat-invalid-specifier -Wformat-zero-length -Wnonnull -Wformat-insufficient-args -Wno-sign-compare -Wno-pointer-to-enum-cast -Wno-tautological-constant-out-of-range-compare -Wno-unaligned-access -DKBUILD_MODFILE='"arch/x86/kernel/cpu/common"' -DKBUILD_BASENAME='"common"' -DKBUILD_MODNAME='"common"' -D__KBUILD_MODNAME=kmod_common -c -o arch/x86/kernel/cpu/common.o arch/x86/kernel/cpu/common.c Where GCC generates: 00000024 <load_direct_gdt>:
24: 55 push %ebp
25: 89 c2 mov %eax,%edx
27: 89 e5 mov %esp,%ebp
29: 83 ec 0c sub $0xc,%esp
2c: 64 a1 00 00 00 00 mov %fs:0x0,%eax
2e: R_386_32 __stack_chk_guard
32: 89 45 fc mov %eax,-0x4(%ebp) So it seems that GCC and CLANG generate different code for the 32-bit kernel as well. However, CLANG always generates non-TLS references for the 32-bit kernel, which is different from the 64-bit kernel that generates both non-TLS and TLS references. Therefore, the 32-bit kernel may boot by accident for CLANG, but I don't believe it is correct because it functions more like a global stack protector. |
Sorry for the confusion, I should clarify that CLANG generates both non-TLS and TLS references for the 32-bit kernel as well, but it still manages to boot successfully. I may need to figure out why this is the case. |
After conducting a thorough investigation, I have discovered the reason why the 32-bit kernel is able to boot successfully. It is because the However, the
Based on my analysis, it appears that the stack protector may be broken for the 32-bit kernel in CLANG in the mainline. |
https://godbolt.org/z/9q59r6E4P shows the code difference; it's whether or not cc @xiangzh1 |
CLANG version:
clang version 17.0.0 (https://github.com/llvm/llvm-project.git e369577cd0585d928cad1edfa7d546f3f6750f39)
Hello.
After llvm/llvm-project#60116 was resolved, the patch for using per-cpu stack protector for X86_64 still couldn't work due to wrong instructions being generated in some files. After diving deep into the issue, I was able to reproduce it.
The compile command is:
clang -S -c -m64 -O0 -mcmodel=kernel -fno-PIE -fstack-protector -mstack-protector-guard-reg=gs -mstack-protector-guard-symbol=__stack_chk_guard test.c -o test.s
I found that if there is a definition of "_stack_chk_guard" in the file:
The output assembly is:
It would generate wrong instruction without %gs.
If there is a declaration of "__stack_chk_guard" in the file:
The output assembly is:
It would generate right instruction.
However, If there is a reference of "__stack_chk_guard" in the file:
The output assembly is:
It would generate wrong instruction without %gs too.
This is why I found the wrong instruction in some files where "__stack_chk_guard" was set up.
The text was updated successfully, but these errors were encountered: