Zadanie 3: System Soczewka™

Data ogłoszenia: 09.05.2019

Termin oddania: 13.06.2019 (ostateczny 27.06.2019)

Wprowadzenie

Dowiedzieliśmy się, że pewne osoby używały sprzętu wydziałowego niezgodnie z regulaminem Laboratorium Komputerowego, uruchamiając na nim niedozwolone i niebezpieczne programy, a także wykorzystując go do niedozwolonych celów, W celu walki z tym procederem postanowiliśmy skompilować listę słów kluczowych powiązanych z podejrzanym użyciem i stworzyć system monitorujący, wykrywający wystąpienia tych słów na maszynie – system Soczewka™.

Zadanie

Napisać główny komponent systemu Soczewka™ – zmodyfikować jądro systemu Linux tak, by wykrywało użycie przez użytkowników podejrzanych słów.

Lista podsłuchiwanych słów będzie przekazywana przez administratorów jako parametr w linii poleceń jądra, na przykład tak:

boot vmlinuz root=/dev/sda1 soczewka=tiananmen,bomb,h4x,harddoom,mwk,pzuk

Można przyjąć ograniczenie do 64 podejrzanych słów, o długości maksymalnie 64 znaków każde.

Aby rozpoznać procesy, które powinny być podsłuchiwane, należy dodać do jądra nową flagę capability: CAP_SYS_SOCZEWKA_IMMUNE. Należy podsłuchiwać wszystkie procesy, które nie mają ustawionej tej flagi.

W podsłuchiwanych procesach należy monitorować następujące dane:

  • wszystkie dane wchodzące do jądra przez copy_from_user
  • wszystkie dane wychodzące z jądra przez copy_to_user
  • dane w zwalnianych stronach pamięci z flagą MAP_ANONYMOUS, czyli:
    • strony, na których użytkownik wywoła munmap
    • strony zwalniane w wywołaniu brk
    • przy kończeniu pracy procesu (przez exit, śmiertelny sygnał, bądź w jakikolwiek inny sposób), wszystkie strony wciąż zmapowane w pamięć procesu

W przypadku znalezienia wystąpienia podejrzanego słowa w podsłuchiwanych danych, należy wypisać przez printk następujące informacje:

  • pid, uid oraz gid procesu wykonującego podejrzaną aktywność

  • znalezione podejrzane słowo

  • bajty znajdujące się w przechwyconych danych w okół podejrzanego słowa: 256 bajtów przed słowem i 256 bajtów za słowem (bądź mniej, jeśli wyjechalibyśmy poza zakres przechwyconych danych lub strony). Żeby zabezpieczyć się przed danymi z poza ASCII, należy te dane wypisać jako hex dump:

    $ echo -n "abch4xdef"
    
    [491972.475072] soczewka: PID 1337 UID 1000 GID 1000 h4x before [61 62 63] after [64 65 66]
    

Aby uniknąć zaśmiecenia systemowych logów przez procesy, które wykazują dużo podejrzanej aktywności, należy dla każdego procesu przechowywać informację, które podejrzane słowa zostały już w nim wykryte i nie wypisywać komunikatów dla kolejnych wystąpień w tym procesie. Dziecko utworzone przez fork uważamy tutaj za nowy proces, który powinien mieć pustą listę wystąpień słów.

Zasady oceniania

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

  • funkcjonalność rozwiązania:
    • wykrywanie słów tylko w copy_*_user (0 punktów)
    • wykrywanie słów w copy_*_user i stronach pamięci zwalnianych przez brk/munmap (1 punkt)
    • wykrywanie słów w copy_*_user i stronach pamięci zwalnianych przez brk/munmap bądź zakończenie procesu (2 punkty)
  • wynik testów (od 0 do 8 punktów)
  • ocena kodu rozwiązania (od 0 do -10 punktów)

Punkty ujemne za kod można było dostać za:

  1. Możliwość przeplotów przy wypisywaniu komuniktów soczewki dla różnych procesów (-0.2 pkt)
  2. Brak nowej linii w printk (-0.1 pkt)
  3. Skanowanie niepoprawnego zakresu w copy_*_user (-0.2 pkt)
  4. Wykorzystanie globalnego bufora bez mutexu (-0.2 pkt)
  5. Wyciek pamięci (-0.2 pkt)
  6. Nieprawidłowa obsługa warunku brzegowego: copy_*_user kopiujące wyłącznie niedozwolone słowo (-0.1 pkt)
  7. Niepoprawna implementacja przeszukiwania - obsługa wyłącznie sytuacji gdy szukane słowo znajduje się na początku przeszukiwanego obszaru (-0.1 pkt)
  8. Nieprawidłowe parsowanie cmdline (-0.1 pkt)
  9. Brak obsługi mapowań MAP_ANONYMOUS | MAP_SHARED (-0.1 pkt, tylko rozwiązania na 9/10 pkt)
  10. Brak ustawiania początkowej wartości flagi w init_task (-0.0 pkt)
  11. Niestandardowy format logowania, wymagający modyfikacji do uruchomienia testów (-0.2 pkt)
  12. Wypisywanie nieprawidłowego UID/GID (-0.2 pkt)
  13. Brak obsługi huge pages (-0.1 pkt, tylko rozwiązania na 9/10 pkt)
  14. Brak skanowania stron znajdujących się na SWAP-ie (-0.4 pkt, tylko rozwiązania na 9/10 pkt)

Testy (dla funkcjonalności na 8pkt):

  • list_badwords - wypisujemy słowa kluczowe (copy_from_user) (1.5 pkt)
  • simple_read - czytamy /proc/cmdline (copy_to_user) (1.5 pkt)
  • multiple_copy - obie akcje powyżej, powtórzone (1.5 pkt)
  • multiple_copy_cap - jak wyżej, ale program ma ustawione capability CAP_SYS_SOCZEWKA_IMMUNE (1.5 pkt)
  • fork - weryfikacja czy fork ma wyczyszczone flagi (1.5 pkt)
  • thread - uruchamiamy wiele wątków, każdy wykonuje ekwiwalent multiple_copy (0.5 pkt)

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.

Uwagi i wskazówki

  • w przypadku gdy w systemie jest obecny swap, dopuszczamy rozwiązania w których:
    • weryfikujemy strony trafiające na swap w momencie zapisu na dysk
    • w munmap bądź przy zakończeniu procesu sprawdzamy już tylko strony znajdujące się w pamięci
  • można założyć, że poszukiwane słowa mieszczą się w obrębie strony