| Issue |
185355
|
| Summary |
[MC][X86] Clang crashes when assembling x86-64 AVX `vcmpps`/`vcmppd` with symbol as comparison predicate
|
| Labels |
clang
|
| Assignees |
|
| Reporter |
venkyqz
|
## Summary
`llvm-mc` crashes with an assertion failure when assembling x86-64 AVX `vcmpps` or `vcmppd` instructions where the comparison-predicate operand is a symbol reference rather than a literal integer constant. The release build silently assembles the instruction with a wrong encoding (exit 0) — **crash-gap bug**.
This is the **first crash-gap bug documented in the x86/x86-64 backend**.
## Reproduction
**Godbolt Link**
+ https://godbolt.org/z/K6z3cjTT6
### AT&T Syntax (Primary Trigger)
**Test File (`poc.s`):**
```asm
.text
vcmpps $f0, %xmm0, %xmm1, %xmm2
```
Any symbol reference (e.g., `$f0`, `$xmm0`, `$rax`) as the comparison predicate will trigger the divergence.
**Commands:**
```bash
# Debug Build - Crashes with assertion
printf ".text\nvcmpps \$f0, %%xmm0, %%xmm1, %%xmm2\n" | llvm-mc - \
--triple=x86_64-linux-gnu -mattr=+avx --filetype=obj -o /dev/null
# Exit 134, Assertion failed
# Release Build - Silent miscompilation
printf ".text\nvcmpps \$f0, %%xmm0, %%xmm1, %%xmm2\n" | llvm-mc - \
--triple=x86_64-linux-gnu -mattr=+avx --filetype=obj -o /dev/null
# Exit 0, emits corrupted object code with wrong encoding
```
### Intel Syntax (OFFSET Modifier Bypass)
Intel syntax normally rejects bare symbols, but `OFFSET` modifier bypasses the protection:
```bash
# Debug Build - Crashes with assertion
echo "vcmpps xmm0, xmm1, xmm2, OFFSET f0" | llvm-mc - \
--triple=x86_64-linux-gnu -x86-asm-syntax=intel --filetype=obj -o /dev/null
# Exit 134
```
**Debug Build Output:**
```
llvm-mc: .../llvm/include/llvm/MC/MCInst.h:85:
int64_t llvm::MCOperand::getImm() const:
Assertion `isImm() && "This is not an immediate"' failed.
Stack dump:
#9 llvm::MCOperand::getImm() const MCInst.h:85
#10 llvm::X86::optimizeInstFromVEX3ToVEX2(...)
X86EncodingOptimization.cpp:58
#11 X86AsmParser::processInstruction(...) X86AsmParser.cpp:3855
...
```
---
## Root Cause
The vulnerability stems from an unguarded `getImm()` call in `optimizeInstFromVEX3ToVEX2`. For `VCMPPS{Y}rri` and `VCMPPD{Y}rri` opcodes, the function reads the comparison predicate to decide whether the instruction is commutative for VEX prefix optimization. When the predicate operand is a symbol reference (`MCExpr`) instead of an integer immediate (`MCImm`), `getImm()` unconditionally fires the assertion.
**Vulnerable Code (`X86EncodingOptimization.cpp:58`):**
```cpp
case X86::VCMPPSrri:
case X86::VCMPPDrri:
case X86::VCMPPSYrri:
case X86::VCMPPDYrri: {
switch (MI.getOperand(3).getImm() & 0x7) { // BUG: No isImm() check!
case 0x00: // EQ
case 0x03: // UNORD
...
```
The release build skips the assertion and returns garbage from `getImm()`, producing wrong binary encoding silently.
**Trigger Paths:**
| Syntax | Input | Parser Behavior | Result |
|--------|-------|-----------------|--------|
| AT&T | `vcmpps $f0, %xmm0, %xmm1, %xmm2` | Accepts `$f0` as symbol | Crash-gap |
| Intel | `vcmpps xmm0, xmm1, xmm2, f0` | Rejects bare symbol | Protected |
| Intel | `vcmpps xmm0, xmm1, xmm2, OFFSET f0` | Accepts `OFFSET` _expression_ | Crash-gap |
---
## Impact
| Build Type | Behavior | Security Risk |
|------------|----------|---------------|
| Debug | Assertion failure (Exit 134) | Detectable |
| Release | Silent miscompilation (Exit 0) | **Undetectable in CI/CD** |
**Affected Instructions:**
| Instruction | Debug Exit | Release Exit |
|-------------|------------|--------------|
| `vcmpps $f0, %xmm0, %xmm1, %xmm2` (AT&T) | 134 | 0 |
| `vcmppd $f0, %xmm0, %xmm1, %xmm2` (AT&T) | 134 | 0 |
| `vcmpps $f0, %ymm0, %ymm1, %ymm2` (AT&T) | 134 | 0 |
| `vcmppd $f0, %ymm0, %ymm1, %ymm2` (AT&T) | 134 | 0 |
| `vcmpps xmm0, xmm1, xmm2, OFFSET f0` (Intel) | 134 | 0 |
| `vcmppd xmm0, xmm1, xmm2, OFFSET f0` (Intel) | 134 | 0 |
**Not Affected:**
| Instruction | Reason |
|-------------|--------|
| `vcmpps $f0, (%rax), %xmm1, %xmm2` | Memory form — no VEX optimization |
| `vcmpps $f0, %xmm0, %xmm1, %k1` | AVX-512 EVEX — different encoding path |
| `vcmpss $f0, %xmm0, %xmm1, %xmm2` | Scalar — different fixup path |
| `cmpps $f0, %xmm0, %xmm1` | Legacy SSE — no VEX optimization |
This demonstrates a classic "Assertion Evaporation" vulnerability where security checks exist in debug builds but are stripped in release builds.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs