From 52b54ee32d3431c8a6eeb09fef6696137647981d Mon Sep 17 00:00:00 2001 From: Rot127 <45763064+Rot127@users.noreply.github.com> Date: Sun, 6 Oct 2024 00:45:13 +0000 Subject: [PATCH] Fixing UB santizer, `LITBASE` and assert errors. (#2499) --- .github/workflows/CITest.yml | 7 +++++-- CMakeLists.txt | 4 ++-- SStream.c | 5 ++++- arch/AArch64/AArch64AddressingModes.h | 6 +++--- arch/ARM/ARMAddressingModes.h | 6 +++--- arch/HPPA/HPPADisassembler.c | 16 ++++++++-------- arch/Xtensa/XtensaDisassembler.c | 4 ++-- arch/Xtensa/XtensaInstPrinter.c | 6 +++--- arch/Xtensa/XtensaMapping.c | 8 ++++---- cs_priv.h | 2 +- tests/MC/Xtensa/arith.s.yaml | 2 +- tests/integration/test_litbase.c | 20 ++++++++++---------- 12 files changed, 46 insertions(+), 40 deletions(-) diff --git a/.github/workflows/CITest.yml b/.github/workflows/CITest.yml index 42219b6d0..42fa37384 100644 --- a/.github/workflows/CITest.yml +++ b/.github/workflows/CITest.yml @@ -24,6 +24,9 @@ concurrency: env: CI: true + UBSAN_OPTIONS: "halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1" + ASAN_OPTIONS: "halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1" + LSAN_OPTIONS: "halt_on_error=1:abort_on_error=1:print_summary=1:print_stacktrace=1" jobs: Linux: @@ -86,10 +89,10 @@ jobs: mkdir build && cd build # build static library cmake -DCAPSTONE_INSTALL=1 -DCMAKE_INSTALL_PREFIX=/usr -DENABLE_ASAN=${asan} -DCAPSTONE_BUILD_DIET=${diet_build} .. - cmake --build . --config Release + cmake --build . --config Debug # build shared library cmake -DCAPSTONE_INSTALL=1 -DBUILD_SHARED_LIBS=1 -DCMAKE_INSTALL_PREFIX=/usr -DCAPSTONE_BUILD_CSTEST=ON -DENABLE_ASAN=${asan} .. - sudo cmake --build . --config Release --target install + sudo cmake --build . --config Debug --target install - name: Lower number of KASL randomized address bits run: | diff --git a/CMakeLists.txt b/CMakeLists.txt index e79bf7c3d..345740c99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,8 +72,8 @@ option(ENABLE_COVERAGE "Enable test coverage" OFF) if (ENABLE_ASAN) message("Enabling ASAN") add_definitions(-DASAN_ENABLED) - add_compile_options(-fsanitize=address) - add_link_options(-fsanitize=address) + add_compile_options(-fsanitize=address,undefined) + add_link_options(-fsanitize=address,undefined) endif() if (ENABLE_COVERAGE) diff --git a/SStream.c b/SStream.c index a69150710..e561345d0 100644 --- a/SStream.c +++ b/SStream.c @@ -330,7 +330,10 @@ void printInt32(SStream *O, int32_t val) SStream_concat(O, "%" PRId32, val); } else { if (val < -HEX_THRESHOLD) { - SStream_concat(O, "-0x%" PRIx32, (uint32_t)-val); + if (val == INT32_MIN) + SStream_concat(O, "-0x%" PRIx32, (uint32_t) INT32_MAX + 1); + else + SStream_concat(O, "-0x%" PRIx32, (int32_t)-val); } else { SStream_concat(O, "-%" PRIu32, (uint32_t)-val); } diff --git a/arch/AArch64/AArch64AddressingModes.h b/arch/AArch64/AArch64AddressingModes.h index 46234645e..498b32325 100644 --- a/arch/AArch64/AArch64AddressingModes.h +++ b/arch/AArch64/AArch64AddressingModes.h @@ -441,9 +441,9 @@ static inline float AArch64_AM_getFPImmFloat(unsigned Imm) { // We expect an 8-bit binary encoding of a floating-point number here. - uint8_t Sign = (Imm >> 7) & 0x1; - uint8_t Exp = (Imm >> 4) & 0x7; - uint8_t Mantissa = Imm & 0xf; + uint32_t Sign = (Imm >> 7) & 0x1; + uint32_t Exp = (Imm >> 4) & 0x7; + uint32_t Mantissa = Imm & 0xf; // 8-bit FP IEEE Float Encoding // abcd efgh aBbbbbbc defgh000 00000000 00000000 diff --git a/arch/ARM/ARMAddressingModes.h b/arch/ARM/ARMAddressingModes.h index f87e45f90..8016d4042 100644 --- a/arch/ARM/ARMAddressingModes.h +++ b/arch/ARM/ARMAddressingModes.h @@ -769,9 +769,9 @@ static inline float ARM_AM_getFPImmFloat(unsigned Imm) { // We expect an 8-bit binary encoding of a floating-point number here. - uint8_t Sign = (Imm >> 7) & 0x1; - uint8_t Exp = (Imm >> 4) & 0x7; - uint8_t Mantissa = Imm & 0xf; + uint32_t Sign = (Imm >> 7) & 0x1; + uint32_t Exp = (Imm >> 4) & 0x7; + uint32_t Mantissa = Imm & 0xf; // 8-bit FP IEEE Float Encoding // abcd efgh aBbbbbbc defgh000 00000000 00000000 diff --git a/arch/HPPA/HPPADisassembler.c b/arch/HPPA/HPPADisassembler.c index 39ad8eabe..25816b156 100644 --- a/arch/HPPA/HPPADisassembler.c +++ b/arch/HPPA/HPPADisassembler.c @@ -162,7 +162,7 @@ static int extract_16(unsigned word, bool wide) /* Extract a 21 bit constant. */ -static int extract_21(unsigned word) +static int32_t extract_21(unsigned word) { int val; @@ -177,14 +177,14 @@ static int extract_21(unsigned word) val |= get_insn_field(word, 0, 4); val <<= 2; val |= get_insn_field(word, 7, 8); - return SignExtend32(val, 21) << 11; + return (uint32_t) SignExtend32(val, 21) << 11; } /* Extract a 12 bit constant from branch instructions. */ -static int extract_12(unsigned word) +static int32_t extract_12(unsigned word) { - return SignExtend32(get_insn_field(word, 19, 28) | + return (uint32_t) SignExtend32(get_insn_field(word, 19, 28) | get_insn_field(word, 29, 29) << 10 | (word & 0x1) << 11, 12) @@ -194,9 +194,9 @@ static int extract_12(unsigned word) /* Extract a 17 bit constant from branch instructions, returning the 19 bit signed value. */ -static int extract_17(unsigned word) +static int32_t extract_17(unsigned word) { - return SignExtend32(get_insn_field(word, 19, 28) | + return (uint32_t) SignExtend32(get_insn_field(word, 19, 28) | get_insn_field(word, 29, 29) << 10 | get_insn_field(word, 11, 15) << 11 | (word & 0x1) << 16, @@ -204,9 +204,9 @@ static int extract_17(unsigned word) << 2; } -static int extract_22(unsigned word) +static int32_t extract_22(unsigned word) { - return SignExtend32(get_insn_field(word, 19, 28) | + return (uint32_t) SignExtend32(get_insn_field(word, 19, 28) | get_insn_field(word, 29, 29) << 10 | get_insn_field(word, 11, 15) << 11 | get_insn_field(word, 6, 10) << 16 | diff --git a/arch/Xtensa/XtensaDisassembler.c b/arch/Xtensa/XtensaDisassembler.c index df56c75aa..8d465d329 100644 --- a/arch/Xtensa/XtensaDisassembler.c +++ b/arch/Xtensa/XtensaDisassembler.c @@ -154,8 +154,8 @@ static DecodeStatus decodeImm8Operand(MCInst *Inst, uint64_t Imm, static DecodeStatus decodeImm8_sh8Operand(MCInst *Inst, uint64_t Imm, int64_t Address, const void *Decoder) { - CS_ASSERT(isUIntN(8, Imm) && "Invalid immediate"); - MCOperand_CreateImm0(Inst, (SignExtend64((Imm << 8), 16))); + CS_ASSERT(isUIntN(16, Imm) && "Invalid immediate"); + MCOperand_CreateImm0(Inst, (SignExtend64((Imm), 16))); return MCDisassembler_Success; } diff --git a/arch/Xtensa/XtensaInstPrinter.c b/arch/Xtensa/XtensaInstPrinter.c index 53ddebb03..a10bfe8dc 100644 --- a/arch/Xtensa/XtensaInstPrinter.c +++ b/arch/Xtensa/XtensaInstPrinter.c @@ -127,13 +127,13 @@ static inline void printL32RTarget(MCInst *MI, int OpNum, SStream *O) if (MCOperand_isImm(MC)) { int64_t Value = MCOperand_getImm(MCInst_getOperand(MI, (OpNum))); - int64_t InstrOff = OneExtend32(Value << 2, 14); + int32_t InstrOff = (uint32_t)OneExtend32(Value, 16) << 2; CS_ASSERT( - (Value >= -262144 && Value <= -4) && + (InstrOff >= -262144 && InstrOff <= -4) && "Invalid argument, value must be in ranges [-262144,-4]"); SStream_concat0(O, ". "); if (MI->csh->LITBASE & 0x1) { - Value = (int64_t)(MI->csh->LITBASE & 0x7ff) + InstrOff; + Value = ((MI->csh->LITBASE & 0xfffff000) >> 12) + InstrOff; } else { Value = (((int64_t)MI->address + 3) & ~0x3) + InstrOff; } diff --git a/arch/Xtensa/XtensaMapping.c b/arch/Xtensa/XtensaMapping.c index c4a01a703..81fb33985 100644 --- a/arch/Xtensa/XtensaMapping.c +++ b/arch/Xtensa/XtensaMapping.c @@ -201,12 +201,12 @@ void Xtensa_add_cs_detail(MCInst *MI, xtensa_op_group op_group, va_list args) case XTENSA_OP_GROUP_L32RTARGET: { int64_t Value = MCOperand_getImm(MCInst_getOperand(MI, (op_num))); - int64_t InstrOff = OneExtend32(Value << 2, 14); + int32_t InstrOff = (uint32_t)OneExtend32(Value, 16) << 2; CS_ASSERT( - (Value >= -262144 && Value <= -4) && + (InstrOff >= -262144 && InstrOff <= -4) && "Invalid argument, value must be in ranges [-262144,-4]"); if (MI->csh->LITBASE & 0x1) { - Value = (int64_t)(MI->csh->LITBASE & 0x7ff) + InstrOff; + Value = ((MI->csh->LITBASE & 0xfffff000) >> 12) + InstrOff; } else { Value = (((int64_t)MI->address + 3) & ~0x3) + InstrOff; } @@ -226,4 +226,4 @@ void Xtensa_add_cs_detail(MCInst *MI, xtensa_op_group op_group, va_list args) xop->access = map_get_op_access(MI, op_num); Xtensa_inc_op_count(MI); -} \ No newline at end of file +} diff --git a/cs_priv.h b/cs_priv.h index 6eee98a33..476b30703 100644 --- a/cs_priv.h +++ b/cs_priv.h @@ -81,7 +81,7 @@ struct cs_struct { const uint8_t *regsize_map; // map to register size (x86-only for now) GetRegisterAccess_t reg_access; struct insn_mnem *mnem_list; // linked list of customized instruction mnemonic - uint32_t LITBASE; + uint32_t LITBASE; ///< The LITBASE register content. Bit 0 (LSB) indicatess if it is set. Bit[23:8] are the literal base address. }; #define MAX_ARCH CS_ARCH_MAX diff --git a/tests/MC/Xtensa/arith.s.yaml b/tests/MC/Xtensa/arith.s.yaml index 746f3e7b3..56f0e9094 100644 --- a/tests/MC/Xtensa/arith.s.yaml +++ b/tests/MC/Xtensa/arith.s.yaml @@ -56,7 +56,7 @@ test_cases: options: [ "xtensa" ] expected: insns: - - asm_text: "addmi a1, a2, 0" + - asm_text: "addmi a1, a2, 0x7f00" - input: diff --git a/tests/integration/test_litbase.c b/tests/integration/test_litbase.c index 0ba50c108..1ce63084c 100644 --- a/tests/integration/test_litbase.c +++ b/tests/integration/test_litbase.c @@ -59,23 +59,23 @@ static void test() size_t count = 0; count = cs_disasm(handle, (const uint8_t *)DATA, sizeof(DATA) - 1, - 0x10000, 2, &insn); + 0x100000, 2, &insn); // 1. Print out the instruction in default setup. - printf("Disassemble xtensa code with PC=0x10000\n"); - check_insn(insn, "l32r", "a1, . 0xc000"); - check_insn(insn + 1, "l32r", "a1, . 0x10000"); + printf("Disassemble xtensa code with PC=0x100000\n"); + check_insn(insn, "l32r", "a1, . 0xc0000"); + check_insn(insn + 1, "l32r", "a1, . 0x100000"); print_insn(insn, count); // Customized mnemonic JNE to JNZ using CS_OPT_LITBASE option - printf("\nNow customize engine to change LITBASA to 0xff001\n"); - cs_option(handle, CS_OPT_LITBASE, (size_t)0xff001); + printf("\nNow customize engine to change LITBASE to 0xfffff001\n"); + cs_option(handle, CS_OPT_LITBASE, (size_t)0xfffff001); count = cs_disasm(handle, (const uint8_t *)DATA, sizeof(DATA) - 1, - 0x10000, 2, &insn); + 0x100000, 2, &insn); // 2. Now print out the instruction in newly customized setup. - check_insn(insn, "l32r", "a1, . -0x3fff"); - check_insn(insn + 1, "l32r", "a1, . -3"); + check_insn(insn, "l32r", "a1, . 0xbffff"); + check_insn(insn + 1, "l32r", "a1, . 0xffffb"); print_insn(insn, count); // Done @@ -87,4 +87,4 @@ int main() test(); return 0; -} \ No newline at end of file +}