[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Bug binutils/25319] New: Usage of unitialized heap in tic4x_print_cond
From: |
v.manhnd at vincss dot net |
Subject: |
[Bug binutils/25319] New: Usage of unitialized heap in tic4x_print_cond |
Date: |
Fri, 27 Dec 2019 08:12:47 +0000 |
https://sourceware.org/bugzilla/show_bug.cgi?id=25319
Bug ID: 25319
Summary: Usage of unitialized heap in tic4x_print_cond
Product: binutils
Version: unspecified
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: binutils
Assignee: unassigned at sourceware dot org
Reporter: v.manhnd at vincss dot net
Target Milestone: ---
Created attachment 12151
--> https://sourceware.org/bugzilla/attachment.cgi?id=12151&action=edit
PoC
Hello,
There is a usage of uninitialized heap in
opcodes/tic4x-dis.c:tic4x_print_cond()
## Analysis
Look at the initialization code of tic4x_conds:
--------------------------------------------
/* Define conditional branch/load suffixes. Put desired form for
disassembler last. */
static const tic4x_cond_t tic4x_conds[] =
{
{ "u", 0x00 },
{ "c", 0x01 }, { "lo", 0x01 },
{ "ls", 0x02 },
{ "hi", 0x03 },
{ "nc", 0x04 }, { "hs", 0x04 },
{ "z", 0x05 }, { "eq", 0x05 },
{ "nz", 0x06 }, { "ne", 0x06 },
{ "n", 0x07 }, { "l", 0x07 }, { "lt", 0x07 },
{ "le", 0x08 },
{ "p", 0x09 }, { "gt", 0x09 },
{ "nn", 0x0a }, { "ge", 0x0a },
{ "nv", 0x0c },
{ "v", 0x0d },
{ "nuf", 0x0e },
{ "uf", 0x0f },
{ "nlv", 0x10 },
{ "lv", 0x11 },
{ "nluf", 0x12 },
{ "luf", 0x13 },
{ "zuf", 0x14 },
/* Dummy entry, not included in num_conds. This
lets code examine entry i+1 without checking
if we've run off the end of the table. */
{ "", 0x0}
};
--------------------------------------------
Here you see the largest cond of a tic4x_cond is 0x14.
Look at the following code of opcodes/tic4x-dis.c:tic4x_print_cond():
--------------------------------------------
272: static int
273: tic4x_print_cond (struct disassemble_info *info, unsigned int cond)
274: {
275: static tic4x_cond_t **condtable = NULL;
276: unsigned int i;
277:
278: if (condtable == NULL)
279: {
280: condtable = xmalloc (sizeof (tic4x_cond_t *) * 32);
281: for (i = 0; i < tic4x_num_conds; i++)
282: condtable[tic4x_conds[i].cond] = (tic4x_cond_t *)(tic4x_conds + i);
283: }
284: if (cond > 31 || condtable[cond] == NULL)
285: return 0;
286: if (info != NULL)
287: (*info->fprintf_func) (info->stream, "%s", condtable[cond]->name);
288: return 1;
289: }
--------------------------------------------
At lines 280, condtable is malloced as an array of 32 elements. At line 382,
condtable is intialized with condtable[tic4x_conds[i].cond] = (tic4x_cond_t
*)(tic4x_conds + i). Because the largest tic4x_cond.cond is 0x14 = 20, so the
element from offset 21 to 31 is not initialized. This can lead to information
leak due to the print function at 287.
## Reproduction
--------------------PoC code----------------
#include "sysdep.h"
#include "bfd.h"
#include "dis-asm.h"
#include "disassemble.h"
#include <stdint.h>
#define MAX_TEXT_SIZE 256
#define MAX_PAYLOAD_SIZE 100
int gDebug = 0;
typedef struct
{
char *buffer;
size_t pos;
} SFILE;
static int objdump_sprintf (SFILE *f, const char *format, ...)
{
size_t n;
va_list args;
va_start (args, format);
if (f->pos >= MAX_TEXT_SIZE){
printf("buffer needs more space\n");
return 0;
}
n = vsnprintf (f->buffer + f->pos, MAX_TEXT_SIZE - f->pos, format, args);
if (gDebug) {
vfprintf(stdout, format, args);
}
va_end (args);
f->pos += n;
return n;
}
static void objdump_print_address (bfd_vma vma, struct disassemble_info *inf)
{
(*inf->fprintf_func) (inf->stream, "0x%lx", vma);
}
int fuzzTest(const uint8_t *Data, size_t Size) {
char AssemblyText[MAX_TEXT_SIZE];
struct disassemble_info disasm_info;
SFILE s;
bfd abfd;
if (Size < 10) {
// 10 bytes for options
return 0;
}
init_disassemble_info (&disasm_info, stdout, (fprintf_ftype) fprintf);
disasm_info.fprintf_func = objdump_sprintf;
disasm_info.print_address_func = objdump_print_address;
disasm_info.display_endian = disasm_info.endian = BFD_ENDIAN_LITTLE;
disasm_info.buffer = Data;
disasm_info.buffer_vma = 0x1000;
disasm_info.buffer_length = Size-10;
disasm_info.insn_info_valid = 0;
s.buffer = AssemblyText;
s.pos = 0;
disasm_info.stream = &s;
disasm_info.bytes_per_line = 0;
disasm_info.arch = Data[Size-1];
disasm_info.mach = *((unsigned long *) (Data + Size - 9));
disasm_info.flavour = Data[Size-10];
if (bfd_lookup_arch (disasm_info.arch, disasm_info.mach) != NULL) {
disassembler_ftype disasfunc = disassembler(disasm_info.arch, 0,
disasm_info.mach, NULL);
if (disasfunc != NULL) {
disassemble_init_for_target(&disasm_info);
disasfunc(0x1000, &disasm_info);
disassemble_free_target(&disasm_info);
}
}
return 0;
}
size_t readFile(char* fileName, char* result, int maxSize)
{
FILE *f = fopen(fileName, "rb");
if (f == NULL) {
fprintf(stdout, "Error cannot read file %s\n", fileName);
exit(1);
}
fseek(f, 0, SEEK_END);
size_t fsize = ftell(f);
fseek(f, 0, SEEK_SET);
if (maxSize != -1 && fsize > maxSize) { fsize = maxSize; }
if (fsize > MAX_PAYLOAD_SIZE) fsize = MAX_PAYLOAD_SIZE;
size_t read = fread(result, 1, fsize, f);
fclose(f);
if (read != fsize) {
fprintf(stdout, "Error while reading file %s\n", fileName);
exit(1);
}
return fsize;
}
int main(int argc, char* argv[])
{
size_t n;
uint8_t Data[MAX_PAYLOAD_SIZE];
if (argc > 2) if (strcmp(argv[2], "debug") == 0) gDebug = 1;
//while(__AFL_LOOP(1000)) {
n = readFile(argv[1], (char*)Data, sizeof(Data));
fuzzTest(Data, n);
//}
return 0;
}
------------------------------------------
-----------------Compilation--------------
Compile binutils in 32 bit and address sanitizer.
./configure --disable-gdb --enable-targets=all CC=gcc CXX=g++ CFLAGS='-m32
-ggdb3 -fsanitize=address -O0' LDFLAGS=-m32 CXXFLAGS='-m32 -O0
-fsanitize=address -ggdb3'
And compile the PoC:
gcc -fsanitize=address -m32 -ggdb3 -O0 -I ./binutils-gdb-gcc-asan-32/include/
-I ./binutils-gdb-gcc-asan-32/bfd/ -I ./binutils-gdb-gcc-asan-32/opcodes/ -c
fuzz_disassemble.c -o fuzz_disassemble.o
gcc -fsanitize=address -O0 -m32 -ggdb3 fuzz_disassemble.o -o
fuzz_disassemble-32-libfuzzer binutils-gdb-gcc-asan-32/opcodes/libopcodes.a
binutils-gdb-gcc-asan-32/bfd/libbfd.a
binutils-gdb-gcc-asan-32/libiberty/libiberty.a
binutils-gdb-gcc-asan-32/zlib/libz.a
------------------Log Crash----------------
root@manh-ubuntu16:~/fuzz/fuzz_binutils# ./fuzz_disassemble-gcc-asan-32
crash-disassemble
ASAN:SIGSEGV
=================================================================
==21804==ERROR: AddressSanitizer: SEGV on unknown address 0xbebebebe (pc
0x0829b3d5 bp 0xfff0a758 sp 0xfff0a720 T0)
#0 0x829b3d4 in tic4x_print_cond
/root/fuzz/fuzz_binutils/binutils-gdb-gcc-asan-32/opcodes/tic4x-dis.c:287
#1 0x829b7e9 in tic4x_print_op
/root/fuzz/fuzz_binutils/binutils-gdb-gcc-asan-32/opcodes/tic4x-dis.c:376
#2 0x829c886 in tic4x_disassemble
/root/fuzz/fuzz_binutils/binutils-gdb-gcc-asan-32/opcodes/tic4x-dis.c:731
#3 0x829ce82 in print_insn_tic4x
/root/fuzz/fuzz_binutils/binutils-gdb-gcc-asan-32/opcodes/tic4x-dis.c:774
#4 0x804a9d5 in fuzzTest /root/fuzz/fuzz_binutils/fuzz_disassemble.c:75
#5 0x804ad93 in main /root/fuzz/fuzz_binutils/fuzz_disassemble.c:115
#6 0xf7030636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
#7 0x804a250
(/root/fuzz/fuzz_binutils/fuzz_disassemble-gcc-asan-32+0x804a250)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV
/root/fuzz/fuzz_binutils/binutils-gdb-gcc-asan-32/opcodes/tic4x-dis.c:287
tic4x_print_cond
==21804==ABORTING
--
Thanks & Regards,
Nguyen Duc Manh
VinCSS (a member of Vingroup)
[E] address@hidden
[W] www.vincss.net
--
You are receiving this mail because:
You are on the CC list for the bug.
- [Bug binutils/25319] New: Usage of unitialized heap in tic4x_print_cond,
v.manhnd at vincss dot net <=