Zadanie 4: Powrót Kalkulatora Wyborczego

Data ogłoszenia: 06.06.2019

Termin oddania: 05.09.2019 (brak możliwości spóźnienia)

Materiały dodatkowe

Wprowadzenie

Niestety, nie wszystkie rozwiązania pierwszego zadania spełniły nasze oczekiwania – w niektórych okręgach wyborczych, Kalkulator Wyborczy zakończył działanie śmiertelnym sygnałem SIGSEGV. Ze względów bezpieczeństwa, nie możemy używać debuggera na maszynach liczących głosy – dostaliśmy jedynie zrzuty core wytworzone przez nasz Kalkulator. Przy analizie tych zrzutów pojawił się poważny problem: przyczyna błędów leży najprawdopodobniej w kodzie obsługi plików, a zrzuty core nie zawierają żadnych informacji o otwartych plikach w momencie awarii programu.

Zadanie

Dopisać do kodu tworzącego pliki core w jądrze kod zrzucający tablicę otwartych plików w momencie śmierci procesu, pozwalając nam na zdebugowanie kodu przed jesiennymi wyborami.

Szczegóły

Ponieważ jeden plik core może zawierać wiele wątków z różnymi tablicami deskryptorów (przypadek CLONE_VM bez CLONE_FILES), plik powinien zawierać osobny zrzut tablicy deskryptorów dla każdego wątku (analogicznie do zrzutów rejestrów). Każdy z tych zrzutów powinien być jedną strukturą ElfXX_Note o nazwie LINUX i nowo zdefiniowanym typie NT_FDS (numeryczna wartość 0x4f4453). Struktura ta powinna być umieszczona bezpośrednio po wszystkich strukturach opisujących stan rejestrów danego wątku. Zawartość (pole desc) tej struktury powinna być następująca:

  • uint32_t num_fds: liczba otwartych deskryptorów
  • dla każdego deskryptora, po kolei:
    • uint32_t fd: numer deskryptora,
    • uint32_t flags: flagi pliku (pole f_flags w struct file),
    • uint64_t pos (niekoniecznie wyrównane): pozycja w pliku (pole f_pos),
    • uint32_t mode: tryb otwarcia pliku (pole f_mode),
    • uint32_t domain: jeżeli plik jest socketem, domena socketu (czyli stała AF_*), w przeciwnym wypadku -1,
    • uint32_t type: jeżeli plik jest socketem, typ socketu (czyli stała SOCK_*), w przeciwnym wypadku -1,
    • uint16_t local_addr_len jeżeli plik jest socketem i ma lokalny adres, rozmiar lokalnego adresu w bajtach, w przeciwnym wypadku 0,
    • uint16_t remote_addr_len jeżeli plik jest socketem i ma zdalny adres, rozmiar zdalnego adresu w bajtach, w przeciwnym wypadku 0,
    • uint8_t local_addr[local_addr_len]: jeżeli plik jest socketem, lokalny adres (czyli to, co zwróciłoby getsockname),
    • uint8_t remote_addr[remote_addr_len]: jeżeli plik jest socketem, zdalny adres (czyli to, co zwróciłoby getpeername),
    • char path[]: ścieżka do pliku, zakończona bajtem zerowym. W przypadku plików specjalnych (socket, pipe, …), należy użyć tej samej sztucznej nazwy, co system plików proc,
    • uint8_t _pad[]: tyle bajtów zerowych, ile potrzeba, by wyrównać pozycję do 4 bajtów.

Do weryfikacji, że dane są zrzucane w poprawnym formacie, dostarczamy skrypt parse.py.

Zasady oceniania

Za zadanie można uzyskać do 10 punktów. Na ocenę zadania składają się dwie części:

  • funkcjonalność rozwiązania:
    • brak specjalnej obsługi socketów – wypełnienie pól domain/type/*_addr stałymi wartościami (0 punktów)
    • pełne rozwiązanie z obsługą socketów (2 punkty)
  • wynik testów (od 0 do 8 punktów)
  • ocena kodu rozwiązania (od 0 do -10 punktów)

Punktacja

Testy weryfikujące działanie socketów były warte 2 pkt., a pozostałe testy - 8pkt.

Punkty z oceny kodu:

  1. Niepoprawna postać rozwiązania / nienakładający patch (-2.0)
  2. Brak README (-0.1)
  3. Copy-paste kodu (wiele funkcji zamiast makra) (-0.0)
  4. Wyciek pamięci (-0.5)
  5. Nadmiarowy diff (zmiany dot. wyłącnie białych znaków) (-0.0)
  6. Dodawanie stałej (małej) liczby bajtów local_addr / remote_addr do core (-0.5, tylko jeśli przechodzą testy)
  7. Użycie polskiego nazewnictwa (-0.2)
  8. Definicja typu NT_FDS w niestandardowym miejscu / brak definicji (-0.0)
  9. Race condition – możliwoć wystąpienia zmiany stanu między obliczaniem potrzebnej pamięci a momentem kopiowania (-0.5)

Forma rozwiązania

Jako rozwiązanie należy wysłać paczkę zawierającą:

  • patcha na jądro w wersji 4.20.8, w jednym z następujących formatów:
    • patch wygenerowaniy przez diffa z opcjami -uprN nakładający się przez patch -p1
    • git format-patch
  • krótki opis rozwiązania

Rozwiązania prosimy nadsyłać na adres p.zuk@mimuw.edu.pl z kopią do mwk@mimuw.edu.pl.