============================ Zadanie 2: BPF sanitizer ============================ Data ogłoszenia: 29.03.2022 Ostatnia aktualizacja: 5.04.2022 Materiały dodatkowe =================== - :download:`sanitizer.h` - :download:`z2-tests-part.tar.xz` Wprowadzenie ============ Czasem chcielibyśmy zagwarantować, że pewne krytyczne informacje nie zostaną zapisane (np. credentiale nie trafią w postaci jawnej do logów dostępnych dla szerszej grupy użytkowników). Współczesne wersje jądra mają podsystem eBPF pozwalający na ładowanie prostych fragmentów kodu i wykonywanie ich w jądrze. Możemy wykorzystać ten podsystem to filtrowania informacji zapisywanych przez programy. Zadanie ======= Dodać możliwość wpięcia do kernela sanityzatora — pary programów eBPF, które będą wykonane przy syscallach (odpowiednio): - `open`, `openat`, `openat2`, `creat` - program eBPF zadecyduje, czy tak otwarty plik będzie podlegał sanityzacji, - w przypadku plików polegających sanityzacji: `write`, `pwrite`, `writev`, `pwritev`, `pwritev2` i zadecyduje, czy zapisywane dane mogą być przekazane w niezmienionej postaci. Jeśli będzie to wymagane, program eBPF dokona niezbędnych modyfikacji. Tak zainstalowany program eBPF powinien mieć następujące możliwości: - dostęp (tylko do odczytu) do kontekstu w formie struktury `sanitizer_ctx` opisanej w załączonym ``sanitizer.h``, - dostęp (do odczytu i zapisu) do pamięci w której znajdują sie zapisywane dane, Ustalenia techniczne ==================== Należy dodać nowy typ programów eBPF: ``BPF_PROG_TYPE_SANITIZER`` (mający numer o 1 większy od ``BPF_PROG_TYPE_SYSCALL``). Należy dodać nowy typ podpięcia programów eBPF: ``BPF_SANITIZER`` (mający numer o 1 większy od ``BPF_PERF_EVENT``). Należy dodać dwa punkty podpięcia: ``int bpf_sanitizer_check(struct sanitizer_ctx *)`` zwraca 0 jeśli otwarty plik nie podlega sanityzacji, 1 w przeciwnym wypadku, ``int bpf_sanitizer_sanitize(struct sanitizer_ctx *)`` zwraca 0 jeśli proces sanityzacji przebiegł pomyślnie; w przypadku błędu, wykonywango syscalla należy przerwać zwracając `-EINVAL`. Nowodododany typ eBPF powinien móc podpiąć się do nich (i tylko do nich) poprzez wywołanie ``BPF_RAW_TRACEPOINT_OPEN`` - należy adekwatnie dostosować ten proces. Można założyć, że dodane punkty podpięcia nie będą wykorzystywane przez inne programy eBPF. Nie trzeba wspierać w zadaniu funkcji `mmap` — próba zamapowania pliku który podlega sanityzacji powinna się skończyć błędem. Nie trzeba też wspierać `vmsplice`, `splice`, `tee`, `sendfile`. W przypadku funkcji operujących na wektorach, każdy element podlega indywidualnej sanityzacji. Wykonywany program eBPF nie powinien modyfikować buforów po stronie użytkownika - należy utworzyć kopię, która będzie dostępna dla programu eBPF. Należy dodać 2 nowe funkcje dostępne dla nowego typu programów (i tylko dla nich), które umożliwiają dostęp do zapisywanych danych: ``int bpf_copy_from_buffer (void *ctx, u64 offset, void *ptr, u32 size)`` Pobiera ``size`` danych podlegających sanityzacji spod offsetu ``offset`` do tablicy ``ptr`` w programie eBPF. Do wywołania należy przekazać aktualny kontekst `ctx`. Zwracana jest liczba nieskopiowanych bajtów. ``int bpf_copy_to_buffer (void *ctx, u64 offset, void *ptr, u32 size)`` Analogicznie jak wyżej, kopiuje dane z tablicy ``ptr`` w eBPF nadpisując sanityzowane dane pod offsetem ``offset``. Nowy typ programów powinien mieć dostęp do następujących funkcji (i żadnych innych): - bazowy wspólny zbiór funkcji, - powyższe 2 funkcje, - istniejące funkcje ``get_current_uid_gid``, ``get_current_pid_tgid``. Forma rozwiązania ================= Jako rozwiązanie należy wysłać paczkę zawierającą: - patcha na jądro w wersji 5.16.5, 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 ``a.jackowski@mimuw.edu.pl``.