FuzzManager jako wybawienie dla pogubionych wśród swoich serwerów #2

Ten wpis jest częścią cyklu “Od zera do bughuntera” – listę wszystkich postów znajdziesz tutaj.

W poprzedniej części omówiłem prostą integrację fuzzerów AFL / HonggFuzz za pomocą tytułowego projektu. Na chwilę obecną jesteśmy w stanie automatycznie parsować raporty z awarii oraz prosto uploadować je na serwer zarządzający. W tej części zajmiejmy się badaniem pokrycia kodu oraz wbudowanym mechanizmem rozpoznawania duplikowanych crashy i ich agregacji w logiczne “kontenerki” w nomenklaturze projektu zwane “crash buckets”.

Pokrycie kodu a FuzzManager

Tym razem nie musimy pisać linijki kodu, lecz musimy dostosować się do wymagań stawianych przez FuzzManagera – dodanie źródeł testowanego projektu i jego kompilacja z przełącznikiem “–coverage” oraz wygenerowanie JSONa zawierającego dane o pokryciu za pomocą grcov. W moim przypadku komendy wyglądały w następujący sposób (przełącznik “-t coveralls+” jest kluczowy do poprawnego formatu wejściowego do FuzzManagera).

# Dodanie informacji o zrodle do serwera
python3 FuzzManager/server/manage.py setup_repository ghostpdl GITSourceCodeProvider /home/kamil/ghostpdl

# Przełącznik "-t coveralls+" jest kluczowy do poprawnego formatu wejściowego do FuzzManagera
grcov ghostpdl/ -t coveralls+ --commit-sha $(cd ghostpdl && git rev-parse HEAD) --token NONE -p `pwd`/ghostpdl/ > cc.json

# Upload JSONa z pokryciem kodu na serwer "zarzadzajacy" za pomocą modulu CovReporter
python3 -mCovReporter --repository ghostpdl --description "Lorem ipsum..." --submit cc.json

Jeżeli wszystko poszło po naszej myśli, nasz panel webowy pokaże informacje o badaniu danej wersji projektu (trzeba ręcznie dopisać “coverage” do URL – niestety nie ma przycisku w panelu webowym):

Pełna struktura katalogów, wraz z sumarycznym pokryciem każdego folderu:

Szczegółowy widok linii w pliku, które są w naszej “garści” – kolumna po numerze linii to liczba “przejść” przez dany kod:

Z mojej strony mały tip: warto przed każdą (ew. co drugą iteracją fuzzingu) badać pokrycie, wraz z przypadkami testowymi, które zostały znalezione przez fuzzer w poprzedniej iteracji. Oczywiście tyczy się to również uzupełniania lub wzbogacania korpusu o pliki pozyskane z innych źródeł. Pozwoli to śledzić ewolucję korpusu i dowiedzieć się, które aspekty wymagają poprawy. Interesująca może być również zmiana pokrycia jako funkcji korpusu i dodawanych ficzerów / bugfixów do projektu 🙂

Awarie, odmiennie niż jajka, wszystkie wpadają do jednego koszyka

Śródtytuł mocno osobliwy, jednak adekwatny: podczas fuzzingu znajdowane są setki jak nie tysiące awarii, które mają tą samą przyczynę a Crash Buckets jest mechanizmem, który potrafi nad tym zapanować. Klasyfikacja odbywa się za pomocą raportów o awarii ASAN \ Valgrind lub gdb. Następnie do nich aplikowane są warunki deklarowane w panelu webowym np. adres crasha mniejszy od 0xDEADBEEF, nazwa funkcji do_evil() lub charakterystyczna wartość stderr.

Podstawowym elementem bucketa jest wzorzec, którego dopasowanie scala wszystko w jedną całość – operuje on na wcześniej opisanych warunkach, które podczas tworzenia podpowiada sam FuzzManager (sekcja Signature):

Bardzo prosta sprawa, aczkolwiek musi paść słowo wyjaśnienia odnośnie typów bucketów, opisanych w dolnych checkbox’ach – na obecnym etapie rozwoju FuzzManagera pełnią jedynie funkcję dekoracyjną i nie mają żadnego wpływu na funkcjonalność (co potwierdza repozytorium na GH). Poniżej widok awarii, która została przyporządkowana do naszego pierwszego “koszyka”:

Podsumowanie

Tak jak poprzednio post nie jest długi, ma to na celu przeniesienie “ciężkości” na praktykę a nie czytanie. Mam nadzieję, że uważniejsi czytelnicy dostrzegli brak cenzury stacktrace’a błędu w Ghostscripcie, który został już załatany 🙂