Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Heap buffer overflow in Codebook_DecodeSetup #591

Closed
khang06 opened this issue Jun 1, 2019 · 0 comments
Closed

Heap buffer overflow in Codebook_DecodeSetup #591

khang06 opened this issue Jun 1, 2019 · 0 comments

Comments

@khang06
Copy link

khang06 commented Jun 1, 2019

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant