Futag icon indicating copy to clipboard operation
Futag copied to clipboard

Генерируются слишком сложные фаззинг обертки

Open dumprop opened this issue 1 year ago • 1 comments

Тестируемый проект: https://github.com/mz-automation/libiec61850

Конфигурация запуска Futag'a стандартная:

build_test = Builder(
    FUTAG_PATH,
    lib_path,
    clean=True,
)
build_test.auto_build()
build_test.analyze()

generator = Generator(
    FUTAG_PATH, 
    lib_path, 
)

generator.gen_targets(
    anonymous=False,
    max_wrappers= 10 
)

generator.compile_targets(
    4,
)

По итогу получил более 5 тысяч фаззинг целей, но их реализация достаточно запутанная и иногда даже сломанная.

Для примера сгенерированная фаззинг цель MmsValue_decodeMmsData:

int LLVMFuzzerTestOneInput(uint8_t * Fuzz_Data, size_t Fuzz_Size){
    if (Fuzz_Size < 1 * sizeof(char) + sizeof(int) + sizeof(int)) return 0;
    size_t dyn_cstring_buffer = (size_t) (Fuzz_Size + 1*sizeof(char) - (1 * sizeof(char) + sizeof(int) + sizeof(int) ));
    //generate random array of dynamic string sizes
    size_t dyn_cstring_size[1];
    dyn_cstring_size[0] = dyn_cstring_buffer;
    //end of generation random array of dynamic string sizes
    uint8_t * futag_pos = Fuzz_Data;
    //GEN_CSTRING1
    unsigned char * str_buffer = (unsigned char *) malloc((dyn_cstring_size[0] + 1)* sizeof(char));
    memset(str_buffer, 0, dyn_cstring_size[0] + 1);
    memcpy(str_buffer, futag_pos, dyn_cstring_size[0]);
    futag_pos += dyn_cstring_size[0];
    
    //GEN_SIZE
    int sz_bufPos = (int) dyn_cstring_size[0];
    
    //GEN_BUILTIN
    int b_bufferLength;
    memcpy(&b_bufferLength, futag_pos, sizeof(int));
    futag_pos += sizeof(int);
    
    //GEN_BUILTIN
    int b__endBufPos;
    memcpy(&b__endBufPos, futag_pos, sizeof(int));
    futag_pos += sizeof(int);
    //GEN_POINTER
    int * p_b__endBufPos = & b__endBufPos;
    
    //FUNCTION_CALL
    MmsValue_decodeMmsData(str_buffer ,sz_bufPos ,b_bufferLength ,p_b__endBufPos );
    //FREE
    if (str_buffer) {
        free(str_buffer);
        str_buffer = NULL;
    }
    return 0;
}

При первом же запуске на любых данных получаю падение т.е. оно вызвано ошибкой реализации харнесса. Если взять готовую реализацию на эту же функцию из репозитория:

int LLVMFuzzerTestOneInput(const char *data, size_t size) {
    int out;
    MmsValue* value = NULL;
    value = MmsValue_decodeMmsData(data, 0, size, &out);

    if (value != NULL) {
        MmsValue_delete(value);
    }

    return 0;
}

Данная реализация заметно более читаемая и не вызывает ложные крэши.

Как возможно решить данную проблему?

dumprop avatar Jul 15 '24 07:07 dumprop

Тестируемый проект: https://github.com/mz-automation/libiec61850

Конфигурация запуска Futag'a стандартная:

build_test = Builder(
    FUTAG_PATH,
    lib_path,
    clean=True,
)
build_test.auto_build()
build_test.analyze()

generator = Generator(
    FUTAG_PATH, 
    lib_path, 
)

generator.gen_targets(
    anonymous=False,
    max_wrappers= 10 
)

generator.compile_targets(
    4,
)

По итогу получил более 5 тысяч фаззинг целей, но их реализация достаточно запутанная и иногда даже сломанная.

Для примера сгенерированная фаззинг цель MmsValue_decodeMmsData:

int LLVMFuzzerTestOneInput(uint8_t * Fuzz_Data, size_t Fuzz_Size){
    if (Fuzz_Size < 1 * sizeof(char) + sizeof(int) + sizeof(int)) return 0;
    size_t dyn_cstring_buffer = (size_t) (Fuzz_Size + 1*sizeof(char) - (1 * sizeof(char) + sizeof(int) + sizeof(int) ));
    //generate random array of dynamic string sizes
    size_t dyn_cstring_size[1];
    dyn_cstring_size[0] = dyn_cstring_buffer;
    //end of generation random array of dynamic string sizes
    uint8_t * futag_pos = Fuzz_Data;
    //GEN_CSTRING1
    unsigned char * str_buffer = (unsigned char *) malloc((dyn_cstring_size[0] + 1)* sizeof(char));
    memset(str_buffer, 0, dyn_cstring_size[0] + 1);
    memcpy(str_buffer, futag_pos, dyn_cstring_size[0]);
    futag_pos += dyn_cstring_size[0];
    
    //GEN_SIZE
    int sz_bufPos = (int) dyn_cstring_size[0];
    
    //GEN_BUILTIN
    int b_bufferLength;
    memcpy(&b_bufferLength, futag_pos, sizeof(int));
    futag_pos += sizeof(int);
    
    //GEN_BUILTIN
    int b__endBufPos;
    memcpy(&b__endBufPos, futag_pos, sizeof(int));
    futag_pos += sizeof(int);
    //GEN_POINTER
    int * p_b__endBufPos = & b__endBufPos;
    
    //FUNCTION_CALL
    MmsValue_decodeMmsData(str_buffer ,sz_bufPos ,b_bufferLength ,p_b__endBufPos );
    //FREE
    if (str_buffer) {
        free(str_buffer);
        str_buffer = NULL;
    }
    return 0;
}

При первом же запуске на любых данных получаю падение т.е. оно вызвано ошибкой реализации харнесса. Если взять готовую реализацию на эту же функцию из репозитория:

int LLVMFuzzerTestOneInput(const char *data, size_t size) {
    int out;
    MmsValue* value = NULL;
    value = MmsValue_decodeMmsData(data, 0, size, &out);

    if (value != NULL) {
        MmsValue_delete(value);
    }

    return 0;
}

Данная реализация заметно более читаемая и не вызывает ложные крэши.

Как возможно решить данную проблему?

Это еще несложная обертка ) В данном случае после аргумента buffer типа строки идет аргумент bufPos типа целого числа Futag постарается угадать, что это комбинация строки и ее длины. Затем разделит входный буфер для передачи всем аргументам.

thientc avatar Jul 19 '24 16:07 thientc