-
Bug
-
Resolution: Not a Bug
-
Normal
-
None
-
CentOS Stream 10
-
None
-
No
-
Moderate
-
rhel-pt-gcc
-
ssg_platform_tools
-
None
-
False
-
False
-
-
None
-
None
-
None
-
None
-
Unspecified
-
Unspecified
-
Unspecified
-
x86_64
-
None
Description of problem:
In EPEL 10 (e.g., CentOS Stream 10), an EPEL package(arm-none-eabi-gcc-cs)'s multiple binaries(e.g. arm-none-eabi-cpp) share a function cpp_error_at whose stack canary is stored at [RSP - 0x60], which is outside the function's allocated stack frame. This layout violates standard ABI conventions and suggests an LTO-related misplacement.
The issue does not occur in Fedora 40 and newer, where RPM_OPT_FLAGS includes -fno-omit-frame-pointer, causing the canary to be correctly stored relative to RBP. However, when the -fno-omit-frame-pointer flag is removed, even Fedora 40 reproduces the issue, indicating the root cause is LTO-triggered constant propagation.
The faulty instruction (e.g., at 0x0016d130 in arm-none-eabi-cpp) appears in an optimized clone of the function:
cpp_error_at(cpp_reader*, cpp_diagnostic_level, unsigned int, const char*, ...) [clone .constprop.0]
Manual attempts to reproduce the bug by building errors.cc in isolation using the same compiler, flags, and environment failed to trigger the faulty code generation. However, analysis of build.log shows that the object file errors.o was later archived into libcpp.a with LTO enabled via liblto_plugin.so, and this static archive was further LTO-linked in later stages, which is the likely root cause.
This behavior could lead to incorrect assumptions for stack analysis or static analysis tools, and violates the intended behavior of stack canary placement.
Version-Release number of selected component (if applicable):
arm-none-eabi-gcc-cs-14.1.0-1.el10_1.x86_64
(issue also reproducible in older versions on EPEL 10)
How reproducible:
Always reproducible in EPEL 10 with default mock or local build using centos-stream-10.
Steps to Reproduce:
Build arm-none-eabi-gcc-cs(can be found via
https://koji.fedoraproject.org/koji/buildinfo?buildID=2665566) in epel-10-x86_64 mock environment (or centos-stream-10).
Extract binary /usr/bin/arm-none-eabi-cpp from resulting RPM.
Disassemble it using any disassembler (e.g., Ghidra) and inspect cpp_error_at function.
Actual results:
Function cpp_error_at stores stack canary at [RSP - 0x60] outside the allocated stack frame.
Expected results:
Stack canary should be stored inside the allocated stack frame, usually at [RBP - offset] or [RSP + offset], following the ABI.
Additional info:
The affected function is an LTO-generated constant-propagation variant.
Root cause seems to stem from cross-object inlining and aggressive constant propagation during static archive (libcpp.a) LTO.
Removing -fno-omit-frame-pointer in Fedora 40 reproduces the same bug, indicating it is not EPEL-specific, but hidden due to default compiler flags.
And Full assembly code for cpp_error_at is below:
0x0016d130: ENDBR64
0x0016d134: PUSH RAX
0x0016d135: POP RAX
0x0016d136: SUB RSP,0x60
0x0016d13a: MOV qword ptr [RSP + -0x38],R8
0x0016d13f: MOV qword ptr [RSP + -0x30],R9
0x0016d144: TEST AL,AL
0x0016d146: JZ 0x0016d178
0x0016d148: VMOVAPS xmmword ptr [RSP + -0x28],XMM0
0x0016d14e: VMOVAPS xmmword ptr [RSP + -0x18],XMM1
0x0016d154: VMOVAPS xmmword ptr [RSP + -0x8],XMM2
0x0016d15a: VMOVAPS xmmword ptr [RSP + 0x8],XMM3
0x0016d160: VMOVAPS xmmword ptr [RSP + 0x18],XMM4
0x0016d166: VMOVAPS xmmword ptr [RSP + 0x28],XMM5
0x0016d16c: VMOVAPS xmmword ptr [RSP + 0x38],XMM6
0x0016d172: VMOVAPS xmmword ptr [RSP + 0x48],XMM7
0x0016d178: MOV RAX,qword ptr FS:[0x28]
0x0016d181: MOV qword ptr [RSP + -0x60],RAX
0x0016d186: XOR EAX,EAX
0x0016d188: LEA RAX,[RSP + 0x68]
0x0016d18d: MOV dword ptr [RSP + -0x78],0x20
0x0016d195: MOV qword ptr [RSP + -0x70],RAX
0x0016d19a: LEA RAX,[RSP + -0x58]
0x0016d19f: MOV dword ptr [RSP + -0x74],0x30
0x0016d1a7: MOV qword ptr [RSP + -0x68],RAX
0x0016d1ac: MOV RAX,qword ptr [0x00000028]
0x0016d1b4: UD2