El fuzz testing es un método potente para descubrir defectos de software al proporcionar a un programa un volumen masivo de entradas semialeatorizadas. Si bien AFL++ es una plataforma líder para objetivos en C y C++ en Linux, lograr una alta eficiencia requiere una configuración deliberada de sanitizadores y variables de entorno. El uso de Address Sanitizer (ASan) y Undefined Behavior Sanitizer (UBSan) es un requisito básico, pero los ajustes predeterminados de ASan pueden ser insuficientes. Por ejemplo, aumentar `max_malloc_fill_size` a un valor grande (como 1GB) asegura que la memoria no inicializada se llene con un patrón, evitando que el fuzzer pase por alto errores donde un programa lee datos no inicializados más allá de un pequeño búfer predeterminado de 4KiB. Además, habilitar `detect_stack_use_after_return` puede capturar errores de memoria más complejos, incluso si reduce ligeramente la velocidad del fuzzing.
Las elecciones arquitectónicas impactan significativamente la velocidad y profundidad de una campaña de fuzzing. Una de las optimizaciones más efectivas es el uso del modo persistente de AFL++, que puede ser un orden de magnitud más rápido que el fuzzing in-place porque evita la sobrecarga de reiniciar repetidamente el proceso objetivo. Para implementar esto, los desarrolladores pueden usar una plantilla de prueba personalizada que envuelve la lógica del objetivo en un bucle. Un matiz técnico clave en esta configuración es evitar el error común de pasar el búfer de AFL++ directamente al objetivo. Debido a que el búfer de AFL++ es más grande que la longitud de la entrada, ASan podría no detectar desbordamientos de lectura. En su lugar, la plantilla de prueba debe crear una copia ajustada al tamaño de la entrada, asegurando que los límites del programa se apliquen estrictamente y sean detectables por el sanitizador.
Más allá de la configuración, las técnicas de 'hacksaw' pueden simplificar las pruebas de componentes complejos y estrechamente acoplados. En lugar de gestionar sistemas de compilación complejos para cada prueba, los desarrolladores pueden incluir los archivos fuente del objetivo directamente en una única unidad de traducción (TU) dentro de la plantilla de fuzzing. Esto permite que el fuzzer acceda a funciones y variables estáticas directamente, permitiendo probar interfaces internas que no están expuestas a través de APIs públicas. Además, para programas que requieren rutas de sistema de archivos, el uso de descriptores de archivos en memoria (vía `memfd_create`) permite que el fuzzer proporcione datos a través de la ruta `/proc/self/fd/`. Este enfoque admite el fuzzing paralelo al asegurar que cada proceso tenga una ruta de archivo única, evitando también el desgaste innecesario del almacenamiento físico. Para maximizar el rendimiento general, también se recomienda mantener los casos de prueba pequeños y usar binarios de objetivo más simples para asegurar que el fuzzer pase más tiempo explorando nuevas rutas de ejecución en lugar de analizar datos grandes y no esenciales.
