============================ Zadanie 2: BPF redactor ============================ Data ogłoszenia: 26.03.2024 Materiały dodatkowe =================== - Plik .config: :download:`CONFIG_Z2` - Testy: :download:`z2-tst-public.tar.gz` Wprowadzenie ============ Redagowanie to proces polegający na dokonywaniu zmian w tekście przed jego publikacją. W systemach informatycznych, termin "redakcja danych" pojawia się w odniesieniu do usuwaniu z plików wrażyliwych danych takich jak hasła. Współczesne wersje jądra mają podsystem BPF pozwalający na ładowanie prostych fragmentów kodu i wykonywanie ich w jądrze. Możemy wykorzystać ten podsystem do wykonania redkacji pliku w trakcie jego odczytu, aby zapobiec odczytaniu wrażliwych danych przez użytkownika. Zadanie ======= Zaimplementować system do redagowania plików podczas ich odczytu. W tym celu należy dodać nowe wywołania systemowe, a także możliwość wpięcia do kernela mechanizmu sprawdzania — pary programów BPF, które będą wykonane przy syscallach (odpowiednio): a) `open`, `openat`, `openat2`, `creat` w celu ustalenia czy przy następnych operacjach odczytu wykonanych na pliku zostanie wykonana redakcja. b) w przypadku plików dla których redakcja ma zostać wykonana: `read`, `pread`, `readv`, `preadv`, `preadv2` dokona redakcji oraz zapamięta liczbę zmodyfikowanych bajtów. Tak zainstalowany program BPF powinien mieć następujące możliwości: - dostęp (tylko do odczytu) do struktury `readctor_ctx` opisanej dalej - dostęp (do odczytu i zapisu) do pamięci w której znajdują sie odczytywane dane - dostęp (do odczytu) do informacji o pliku z którego czytamy Liczba znaków zmienionych podczas redakcji każdego pliku powinna być zapamiętana. Do zarządzania redakcją należy zaimplementować następujące wywołania systemowe: ``int count_redactions(int fd)`` - zwraca liczbę zmienionych znaków podczas redakcji danego pliku ``int reset_redactions(int fd)`` - czyści licznik zapamiętanych zmian dla danego pliku Ustalenia techniczne ==================== Należy dodać nowy typ programów BPF: ``BPF_PROG_TYPE_REDACTOR`` (mający numer o 1 większy od ``BPF_PROG_TYPE_NETFILTER``). Należy dodać nowy typ podpięcia programów BPF: ``BPF_REDACTOR`` (mający numer o 1 większy od ``BPF_NETKIT_PEER``). Dane przekazywane w kontekście wywołania BPF mają format: .. code-block:: c struct redactor_ctx { union { struct { loff_t offset; size_t size; }; struct { u64 flags; umode_t mode; kuid_t uid; kgid_t gid; }; }; }; Należy dodać dwa punkty podpięcia: ``int bpf_redactor_decide(struct redactor_ctx *)`` - jeśli zwróci dodatnią liczbę, to plik zostanie poddany redakcji ``int bpf_redactor_redact(struct redactor_ctx *)`` - dokona redakcji danych odczytywanych z pliku oraz zwróci liczbę wyredaktowanych; w przypadku błędu, wykonywanego syscalla należy przerwać zwracając `-EINVAL`. Nowododany typ BPF powinien móc podpiąć się do nich (i tylko do nich) poprzez ``BPF_RAW_TRACEPOINT_OPEN``. Nie trzeba wspierać w zadaniu funkcji `mmap`, ani `vmsplice`, `splice`, `tee`, `sendfile`. Należy dodać nowe funkcje dostępne dla nowego typu programów (i tylko dla nich), która umożliwią redakcję przez program BPF. ``int bpf_copy_to_buffer (void *ctx, unsigned long offset, void *ptr, unsigned long size)`` ``int bpf_copy_from_buffer (void *ctx, unsigned long offset, void *ptr, unsigned long size)`` Nowy typ programu powinien mieć dostęp do następujących funkcji (i żadnych innych): - bazowy wspólny zbiór funkcji - powyższe funkcje - istniejące funkcje get_current_uid_gid i get_current_pid_tgid Kompilacja rozwiązania ====================== Uruchomienie rozwiązania wymaga prawidłowo skonfigurowanego jądra, z ustawieniami takimi jak ``CONFIG_DEBUG_INFO_BTF=y`` które celowo nie zostały włączone w konfiguracji zzałączonej przy trzecim laboratorium, ponieważ owe opcje wydłużają kompilację oraz zwiększają wymagania na zasoby. Z uwagi na to, może być wymagane powiększenie obrazu używanego na laboratoriach o kilka lub kilkanaście gigabajtów. Aby przetestować rozwiązanie najłatwiej wykorzystać plik konfiguracyjny załączony w sekcji z materiałami. Skompilowanie testów wymaga pliku vmlinux.h, który nie został dołączony do testów. Można go wygenerować np. przy pomocy programu bpftool. Natomiast żadne dodatkowe zmiany w załączonej bibliotece libbpf nie są już wymagane. Skompilowanie rozwiązania i testów w maszynie wirtualnej wymaga też instalację pakietów dwarves oraz clang. Wskazówki ================== Podczas testowania rozwiazązania może się okazać, że wprowadzony przez studenta błąd uniemożliwia bootowanie maszyny wirtualnej. W takiej sytuacji polecam użyć parametrów -kernel, -hda oraz -append "root=/dev/sda3" wraz z wcześniej skopiowanymi działającymi plikami vmlinuz i initrd (https://qemu-project.gitlab.io/qemu/system/linuxboot.html). Jeśli nie przygotowaliście sobie wcześniej plików vmlinuz i initrd na taką ewentualność, to ewentualnie można je wykopiować z obrazu bazowago używanego na laboratorium. W celu kompilacji jądra przy użyciu wielu rdzeni należy nie tylko pamiętać o opcji -j do polecenia make, ale również zapenić, że maszyna wirtualna ma możliwość wykorzystania wielu rdzeni (np. przez opcję -smp). Forma rozwiązania ==================== Jako rozwiązanie należy wysłać paczkę zawierającą patch na jądro w wersji 6.7.6 wygenerowany przez ``git format-patch``` oraz krótki opis rozwiazania.