Skip to content

[llvm-mc] crashes with SIGSEGV when asked to assemble certain BPF instructions with mismatched registers #145180

@jcttrll

Description

@jcttrll

Due to the unusual representation of some BPF instructions in pseudo-C, the instruction register appears twice (for example, r0 in the below code):

r0 = atomic_fetch_add((u64*)(r2 + 0), r0) 

A mismatch between the two register names (for example, r0 and r1), is, of course, invalid, since there is no such BPF instruction:

r0 = atomic_fetch_add((u64*)(r2 + 0), r1) 

Instead of reporting a syntax error, llvm-mc crashes with SIGSEGV when fed such an instruction (observed in a release build of version 19.1.7):

$ echo 'r0 = atomic_fetch_add((u64*)(r2 + 0), r1)' | llvm-mc --arch bpf --filetype null PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace. Stack dump: 0. Program arguments: llvm-mc --arch bpf --filetype null #0 0x00007fef52043539 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/usr/lib64/libLLVM.so.19.1+0xa43539) #1 0x00007fef52040ac0 llvm::sys::RunSignalHandlers() (/usr/lib64/libLLVM.so.19.1+0xa40ac0) #2 0x00007fef52043d1b SignalHandler(int) (/usr/lib64/libLLVM.so.19.1+0xa43d1b) #3 0x00007fef50e57980 __restore_rt (/lib64/libc.so.6+0x57980) #4 0x00007fef54c2c9b2 (anonymous namespace)::BPFAsmParser::convertToMapAndConstraints(unsigned int, llvm::SmallVectorImpl<std::unique_ptr<llvm::MCParsedAsmOperand, std::default_delete<llvm::MCParsedAsmOperand>>> const&) (/usr/lib64/libLLVM.so.19.1+0x362c9b2) #5 0x00005559f966d750 Segmentation fault (core dumped) 

A debug build from the GitHub main branch (at 0c47628) provides more insight:

$ echo 'r0 = atomic_fetch_add((u64*)(r2 + 0), r1)' | ../../bin/llvm-mc --arch bpfel --filetype null Unknown match type detected! UNREACHABLE executed at /llvm-project/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp:352! PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace. Stack dump: 0. Program arguments: ../../bin/llvm-mc --arch bpfel --filetype null #0 0x00000000006bb83c llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /llvm-project/llvm/lib/Support/Unix/Signals.inc:804:0 #1 0x00000000006bbcfd PrintStackTraceSignalHandler(void*) /llvm-project/llvm/lib/Support/Unix/Signals.inc:888:0 #2 0x00000000006b95e1 llvm::sys::RunSignalHandlers() /llvm-project/llvm/lib/Support/Signals.cpp:105:0 #3 0x00000000006bb1f7 SignalHandler(int, siginfo_t*, void*) /llvm-project/llvm/lib/Support/Unix/Signals.inc:418:0 #4 0x00007fbd5e257980 __restore_rt (/lib64/libc.so.6+0x57980) #5 0x00007fbd5e2a949c __pthread_kill_implementation /usr/src/debug/glibc-2.38-150600.14.14.2.x86_64/nptl/pthread_kill.c:44:76 #6 0x00007fbd5e2578c2 gsignal /usr/src/debug/glibc-2.38-150600.14.14.2.x86_64/signal/../sysdeps/posix/raise.c:27:6 #7 0x00007fbd5e23f64f abort /usr/src/debug/glibc-2.38-150600.14.14.2.x86_64/stdlib/abort.c:81:7 #8 0x00000000006326bd bindingsErrorHandler(void*, char const*, bool) /llvm-project/llvm/lib/Support/ErrorHandling.cpp:242:0 #9 0x000000000042f672 (anonymous namespace)::BPFAsmParser::matchAndEmitInstruction(llvm::SMLoc, unsigned int&, llvm::SmallVectorImpl<std::unique_ptr<llvm::MCParsedAsmOperand, std::default_delete<llvm::MCParsedAsmOperand>>>&, llvm::MCStreamer&, unsigned long&, bool) /llvm-project/llvm/lib/Target/BPF/AsmParser/BPFAsmParser.cpp:313:0 #10 0x00000000005879d6 (anonymous namespace)::AsmParser::parseAndMatchAndEmitTargetInstruction((anonymous namespace)::ParseStatementInfo&, llvm::StringRef, llvm::AsmToken, llvm::SMLoc) /llvm-project/llvm/lib/MC/MCParser/AsmParser.cpp:2311:0 #11 0x0000000000587349 (anonymous namespace)::AsmParser::parseStatement((anonymous namespace)::ParseStatementInfo&, llvm::MCAsmParserSemaCallback*) /llvm-project/llvm/lib/MC/MCParser/AsmParser.cpp:2244:0 #12 0x00000000005815fb (anonymous namespace)::AsmParser::Run(bool, bool) /llvm-project/llvm/lib/MC/MCParser/AsmParser.cpp:979:0 #13 0x000000000040a13e AssembleInput(char const*, llvm::Target const*, llvm::SourceMgr&, llvm::MCContext&, llvm::MCStreamer&, llvm::MCAsmInfo&, llvm::MCSubtargetInfo&, llvm::MCInstrInfo&, llvm::MCTargetOptions const&) /llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp:348:0 #14 0x000000000040bba7 main /llvm-project/llvm/tools/llvm-mc/llvm-mc.cpp:596:0 #15 0x00007fbd5e240eec __libc_start_call_main /usr/src/debug/glibc-2.38-150600.14.14.2.x86_64/csu/../sysdeps/nptl/libc_start_call_main.h:74:3 #16 0x00007fbd5e240fb5 call_init /usr/src/debug/glibc-2.38-150600.14.14.2.x86_64/csu/../csu/libc-start.c:128:20 #17 0x00007fbd5e240fb5 __libc_start_main@GLIBC_2.2.5 /usr/src/debug/glibc-2.38-150600.14.14.2.x86_64/csu/../csu/libc-start.c:347:5 #18 0x00000000004097b1 _start /home/abuild/rpmbuild/BUILD/glibc-2.38/csu/../sysdeps/x86_64/start.S:117:0 Aborted (core dumped) 

The switch in BPFAsmParser::matchAndEmitInstruction is apparently missing a case Match_InvalidTiedOperandto handle various Constraints in BPFInstrInfo.td, such as on line 946. This causes the crash when encountering the following (and possibly more) illegal instructions with mismatched registers:

r0 = bswap16 r1 r0 = bswap32 r1 r0 = bswap64 r1 r0 = atomic_fetch_add((u64*)(r2 + 0), r1) r0 = atomic_fetch_and((u64*)(r2 + 0), r1) r0 = atomic_fetch_or((u64*)(r2 + 0), r1) r0 = atomic_fetch_xor((u64*)(r2 + 0), r1) w0 = xchg32_32(r2 + 0, w1) r0 = xchg_64(r2 + 0, r1) 

Metadata

Metadata

Assignees

No one assigned

    Labels

    backend:BPFcrashPrefer [crash-on-valid] or [crash-on-invalid]

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions