ClassiCube / ClassiCube

Custom Minecraft Classic / ClassiCube client written in C from scratch (formerly ClassicalSharp in C#)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Heap buffer overflow in Codebook_DecodeSetup

khang06 opened this issue · comments

i wrote this quick and (very) dirty fuzzer for the vorbis stuff

// this is just a modified version of Music_PlayOgg
// any bugs in that logic *should* appear here
int LLVMFuzzerTestOneInput(uint8_t *Data, size_t Size) {
    struct Stream source_notptr;
    Stream_ReadonlyMemory(&source_notptr, Data, Size);
    struct Stream* source = &source_notptr;

    uint8_t buffer[OGG_BUFFER_SIZE];
    struct Stream stream;
    struct VorbisState vorbis = { 0 };
    struct AudioFormat fmt;

    int chunkSize, samplesPerSecond;
    int16_t* data = NULL;
    bool completed;
    int i, next;
    ReturnCode res;

    Ogg_MakeStream(&stream, buffer, source);
    vorbis.Source = &stream;
    if ((res = Vorbis_DecodeHeaders(&vorbis))) goto cleanup;

    fmt.Channels = vorbis.Channels;
    fmt.SampleRate = vorbis.SampleRate;
    fmt.BitsPerSample = 16;

    /* largest possible vorbis frame decodes to blocksize1 * channels samples */
    /* so we may end up decoding slightly over a second of audio */
    chunkSize = fmt.Channels * (fmt.SampleRate + vorbis.BlockSizes[1]);
    samplesPerSecond = fmt.Channels * fmt.SampleRate;
    data = (int16_t*)Mem_Alloc(chunkSize * AUDIO_MAX_BUFFERS, 2, "Ogg final output");

    /* fill up with some samples before playing */
    for (i = 0; i < AUDIO_MAX_BUFFERS && !res; i++) {
        res = Music_Buffer(i, &data[chunkSize * i], samplesPerSecond, &vorbis);
    }

    for (;;) {
        res = Music_Buffer(next, &data[chunkSize * next], samplesPerSecond, &vorbis);
        /* need to specially handle last bit of audio */
        if (res) break;
    }

cleanup:
    Mem_Free(data);
    Vorbis_Free(&vorbis);
    return 0;
}

also requires a modified function in Audio.c

ReturnCode Music_Buffer(int i, int16_t* data, int maxSamples, struct VorbisState* ctx) {
	int samples = 0;
	int16_t* cur;
	ReturnCode res = 0, res2;

	while (samples < maxSamples) {
		if ((res = Vorbis_DecodeFrame(ctx))) break;

		cur = &data[samples];
		samples += Vorbis_OutputFrame(ctx, cur);
	}

	return res;
}

since i changed a lot in this function, there could be a flaw in my fuzzing logic. but the crash itself doesn't look related

pi@raspberrypi:~/ClassiCube/src $ ./ClassiCube SIGABRT.PC.76afa45c.STACK.badbad0c3cb96303.CODE.-6.ADDR.\(nil\).INSTR.mov_r0\,_r4.2019-06-01.23\:08\:33.25453.fuzz
Accepting input from 'SIGABRT.PC.76afa45c.STACK.badbad0c3cb96303.CODE.-6.ADDR.(nil).INSTR.mov_r0,_r4.2019-06-01.23:08:33.25453.fuzz'
Usage for fuzzing: honggfuzz -P [flags] -- ./ClassiCube
=================================================================
==25612==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6aa01680 at pc 0x002e6ea0 bp 0x7ee200d8 sp 0x7ee200d4
WRITE of size 1 at 0x6aa01680 thread T0
    #0 0x2e6e9c in Codebook_DecodeSetup /home/pi/ClassiCube/src/Vorbis.c:321:21
    #1 0x2e009c in Vorbis_DecodeSetup /home/pi/ClassiCube/src/Vorbis.c:1197:9
    #2 0x2deea4 in Vorbis_DecodeHeaders /home/pi/ClassiCube/src/Vorbis.c:1258:13
    #3 0x1dec10 in LLVMFuzzerTestOneInput /home/pi/ClassiCube/src/Program.c:191:16

0x6aa01680 is located 0 bytes to the right of 64-byte region [0x6aa01640,0x6aa01680)
allocated by thread T0 here:
    #0 0x10d618 in __interceptor_malloc /home/tcwg-buildslave/workspace/tcwg-llvm-release/tcwg-tk1_32-build/final/llvm.src/projects/compiler-rt/lib/asan/asan_malloc_linux.cc:146:3
    #1 0x330f78 in Mem_Alloc /home/pi/ClassiCube/src/Platform.c:137
    #2 0x2e6080 in Codebook_DecodeSetup /home/pi/ClassiCube/src/Vorbis.c:293:27
    #3 0x2e009c in Vorbis_DecodeSetup /home/pi/ClassiCube/src/Vorbis.c:1197:9
    #4 0x2deea4 in Vorbis_DecodeHeaders /home/pi/ClassiCube/src/Vorbis.c:1258:13
    #5 0x1dec10 in LLVMFuzzerTestOneInput /home/pi/ClassiCube/src/Program.c:191:16
    #6 0x43c8f8 in HonggfuzzMain (/home/pi/ClassiCube/src/ClassiCube+0x43c8f8)

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/pi/ClassiCube/src/Vorbis.c:321:21 in Codebook_DecodeSetup
Shadow bytes around the buggy address:
  0x2d540280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x2d540290: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x2d5402a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x2d5402b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x2d5402c0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
=>0x2d5402d0:[fa]fa fa fa 00 00 00 00 00 00 00 04 fa fa fa fa
  0x2d5402e0: 00 00 00 00 00 00 00 04 fa fa fa fa fa fa fa fa
  0x2d5402f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x2d540300: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x2d540310: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x2d540320: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==25612==ABORTING

heapoobw1ogg.zip