Skip to content

Out of bound memory write when disassembling some PPC instructions #1912

Closed
@hamarituc

Description

@hamarituc

Summary

When disassembling PowerPC code, an out of bound write occurs during register decoding, which corrupts the heap memory management.

Consider the following code.

#include <stdio.h>
#include <stdlib.h>

#include <capstone/platform.h>
#include <capstone/capstone.h>

int main()
{
  csh handle;
  unsigned char code[] = { 0x2d, 0x03, 0x00, 0x80 };
  cs_insn *insn;
  size_t count;

  cs_open(CS_ARCH_PPC, CS_MODE_BIG_ENDIAN, &handle);
  cs_option(handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_NOREGNAME);
  cs_disasm(handle, code, sizeof(code) / sizeof(unsigned char), 0x1000, 0, &insn);
  cs_close(&handle);

  return 0;
}

Compile it.

$ gcc -g code.c -o /tmp/a.out -lcapstone

Actual behavior

When this code is run on an PPC64 host, it fails as follows (at least under Gentoo Linux):

free(): invalid pointer
Aborted

On other platforms the program might not fail, but the error exists as well.

Expected behavior

The program doesn't fail.

Additional context

The issue could be tracked down to function stripRegisterPrefix function with the following GDB session.

# gdb /tmp/a.out 
(gdb) break stripRegisterPrefix
Function "stripRegisterPrefix" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (stripRegisterPrefix) pending.
(gdb) run
Starting program: /tmp/a.out 
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".

Breakpoint 1, stripRegisterPrefix (RegName=0x7ffff7b68977 <AsmStrs.3+311> "cr2") at /var/tmp/portage/dev-libs/capstone-5.0_rc2-r1/work/capstone-5.0-rc2/arch/PowerPC/PPCInstPrinter.c:1104
1104            switch (RegName[0]) {
(gdb) n
1114                            if (RegName[1] == 'r') {
(gdb) 
1116                                    char *name = cs_strdup(RegName + 2);
(gdb) 
1119                                    name[strlen(name) - 2] = '\0';
(gdb) print name
$1 = 0x55555555c3b0 "2"
(gdb) print (size_t)strlen(name)
$2 = 1

In line 1119 the last two characters of name are removed. But the string is only one character long. So the byte immediately before the start of the string (which is part of the Glibc internal heap data structure) is overwritten by \0.

This error was introduced in commit 30627ba.

The instruction triggering the bug is:

$ cstool ppc64be "2d030080"
 0  2d 03 00 80  cmpwi  cr2, r3, 0x80

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions