-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Closed
Description
The Clang compiler generates code for a function that overwrites the lr
register without saving its data on stack beforehand.
This bug was detected on a large software component and the problem was minimized to a PoC (see example.c).
Clang versions info:
- llvmorg-17-init - bug wasn't detected
- llvmorg-17.0.2 - bug detected
- llvmorg-17.0.6 - bug detected
- llvmorg-18-init - bug detected
Host OS: Ubuntu 20.04.3 LTS
In disassembler the bug looks like this (generated example.c.o.objdump
):
00000010 <BUGGY_FUNCTION>:
; if (!ctx) {
10: cmp r0, #0
14: beq 0x48 <BUGGY_FUNCTION+0x38> @ imm = #0x2c <-- Goto 0x48 if "(!ctx)" is True.
; ctx->cmd_c = func_2;
18: ldr r12, [pc, #0x40] @ 0x60 <BUGGY_FUNCTION+0x50> <-- Continue if "(!ctx)" is False.
1c: mov r1, r0
20: mov r0, #0
; ctx->cmd_a = func_0;
24: add lr, r1, #8 <-- ERROR. THIS LOOKS CRAZY!!! "lr" WAS NOT STORED ON THE STACK!
; ctx->cmd_c = func_2;
28: ldr r12, [pc, r12]
... < SOME OTHER CODE > ...
44: bx lr <-- ERROR. BRANCH TO "lr" ADDRESS THAT WAS PREVIOUSLY CORRUPTED!!!
48: push {r11, lr}
... < SOME OTHER CODE > ...
Steps to reproduce.
- example.c
void __attribute__((optnone)) printer(int line) {}
#define INFO() printer(__LINE__);
extern int func_0(void);
extern int func_1(void);
extern int func_2(void);
typedef int (*f_ptr_t)(void);
typedef struct operation {
double double_0;
f_ptr_t cmd_a;
f_ptr_t cmd_b;
f_ptr_t cmd_c;
f_ptr_t cmd_d;
} operation_t;
int BUGGY_FUNCTION(operation_t *ctx)
{
// INFO(); // UNCOMMENT TO FIX ASSEMBLY CODE GENERATION!!!
if (!ctx) {
INFO()
return -1;
}
ctx->cmd_a = func_0;
ctx->cmd_b = func_1;
ctx->cmd_c = func_2;
ctx->cmd_d = (void *)0;
return 0;
}
- reproduce.sh
#!/bin/bash
SDK_BIN_PATH=<PUT YOUR BIN PATH LOCATION HERE>
CC="${SDK_BIN_PATH}/armv7-none-gnueabi-clang"
OBJDUMP="${SDK_BIN_PATH}/armv7-none-gnueabi-objdump"
INPUT_FILE=example.c
OBJ_FILE=example.c.o
OBJDUMP_FILE=example.c.o.objdump
echo "Compile and objdump..." \
&& "${CC}" -ggdb -Os -fPIE -c "${INPUT_FILE}" -o "${OBJ_FILE}" \
&& "${OBJDUMP}" -dS "${OBJ_FILE}" | tee "${OBJDUMP_FILE}"
Metadata
Metadata
Assignees
Type
Projects
Status
Done
Relationships
Development
Select code repository
Activity
jroelofs commentedon Feb 1, 2024
Smells like shrink-wrapping.
llvmbot commentedon Feb 1, 2024
@llvm/issue-subscribers-backend-arm
Author: Victor Signaevskyi (P1119r1m)
Clang versions info:
Host OS: Ubuntu 20.04.3 LTS
In disassembler the bug looks like this (generated
example.c.o.objdump
):Steps to reproduce.
fhahn commentedon Feb 1, 2024
I suspect this was fixed by swiftlang@b1a5ee1
Could you check with a build from current
main
or the upcoming 18.x release candidates?davemgreen commentedon Feb 1, 2024
I still see the same in https://godbolt.org/z/7PKxqj7vx I'm afraid.
It looks like what @jroelofs says - shrink wrapping leads to frame lowering in one of the two branches, followed by a bit of tail folding ends up with the load/store optimizing using lr that it thinks is available.
P1119r1m commentedon Feb 1, 2024
BTW, there is no bug if to build it for
-target armv4t-none-eabi
instead of-target thumbv7a-none-eabi
:P1119r1m commentedon Feb 5, 2024
Dear contributors/collaborators,
are there any chance to fix this compiler bug?
There is a feeling that this bug can manifest itself in many other places in the code.
Maybe not even only in 32-bit architectures.
Also, I think this bug could be used in some hacker attacks.
P1119r1m commentedon Feb 21, 2024
@jroelofs @davemgreen @fhahn
I think we should report a CVE for this Clang issue to warn at least all ARM32 users about this Clang compiler vulnerability.
smithp35 commentedon Feb 21, 2024
If you feel like this is a security issue please report using the process in https://llvm.org/docs/Security.html . My instinct is that this would not be a worthy of a CVE. CVEs are used to report security vulnerabilities in programs, this looks like a code-generation bug that if it affects your program it is likely to crash. It doesn't look like something that would be systemicly reproduced across many programs.
P1119r1m commentedon Feb 21, 2024
@smithp35 Thanks for the link.
I think the bug deserves a CVE because "security experts" can intentionally look for this incorrect binary pattern in binaries and exploit it.
Theoretically, thanks to this compiler bug, one can branch to any address.
smithp35 commentedon Feb 21, 2024
Feel free to report it to the LLVM security group if you disagree with me.
P1119r1m commentedon Feb 21, 2024
@smithp35 Thank you. Reported locally to LLVM security group as:
jroelofs commentedon Feb 21, 2024
workaround:
-mllvm --enable-shrink-wrap=false
https://godbolt.org/z/3Koq6YEWW
197 remaining items