Zadanie 3: modyfikacja jądra¶
Data ogłoszenia: 15.05.2018
Termin oddania: 12.06.2018 (ostateczny 26.06.2018)
Materiały dodatkowe¶
ptrace_remote.h
z3_test.tar
(aktualizacja 04.06.2018)
Wprowadzenie¶
Do śledzenia programów użytkownika w systemie Linux służy syscall ptrace
.
Ma on (m.in.) następujące możliwości:
- podpięcie do procesu śledzonego (targetu)
- monitorowanie i przechwytywanie sygnałów przychodzących do targetu
- pisanie i czytanie pamięci oraz stanu rejestrów targetu
- zatrzymywanie i wznawianie pracy targetu, w kilku trybach:
PTRACE_CONT
: target jest wznawiany do otrzymania sygnału lub ręcznego zatrzymaniaPTRACE_SYSCALL
: jak wyżej, ale target jest zatrzymywany przed wejściem do syscalla oraz po wyjściu z niegoPTRACE_SINGLESTEP
: target jest wznawiany, wykonuje jedną instrukcję procesora, po czym jest zatrzymywanyPTRACE_SYSEMU
,PTRACE_SYSEMU_SINGLESTEP
: jakPTRACE_SYSCALL
iPTRACE_SINGLESTEP
, ale syscalle wywoływane przez target nie są wykonywane przez kernel
Niestety, mechanizm ten jest bardzo prymitywny, i nie pozwala na wykonywanie wielu operacji bardzo przydatnych przy pisaniu debuggerów. Jednym z przykładów jest manipulacja otwartymi plikami czy mapowaniami w procesie (np. nie da się utworzyć nowego mapowania). Aby obejść to ograniczenie, debuggery muszą:
- znaleźć jakieś miejsce w segmencie kodu targetu
- zachować jego zawartość
- wstrzyknąć w to miejsce instrukcję wywołującą syscall
- zachować obecny stan rejestrów
- wstawić do rejestrów numer i parametry syscalla robiącego to, co debugger chce (np. mmap)
- ustawić wskaźnik instrukcji tak, aby wskazywał na wstrzyknięty kod
- uruchomić
PTRACE_SINGLESTEP
- wyciągnąć wynik syscalla z rejestru
- odtworzyć stan rejestrów
- odtworzyć nadpisane miejsce w segmencie kodu
Mechanizm ten ma pewne wady.
Zadanie¶
Dopisać do syscalla ptrace
operacje pozwalające na manipulację otwartymi
plikami i mapowaniami innych procesów:
PTRACE_REMOTE_MMAP
: tworzy nowe mapowanie w zdalnym procesie.addr
jest ignorowane,data
wskazuje na strukturęptrace_remote_mmap
, zawierającą parametry do wywołania:addr
: adres pod którym ma być utworzone mapowanie, bądź 0 aby jądro automatycznie wybrało adres (jak w zwykłymmmap
). Po udanym wywołaniu, jądro zapisze w tym polu wybrany adres.length
: jak w zwykłymmmap
.prot
: jak w zwykłymmmap
.flags
: jak w zwykłymmmap
.fd
: deskryptor pliku, który ma być zmapowany. Deskryptor pliku jest szukany w plikach procesu wywołującegoptrace
, a nie procesu w którym będzie tworzone mapowanie. Jeśliflags
zawieraMAP_ANONYMOUS
, to pole jest ignorowane.offset
: jak w zwykłymmmap
.
Jeśli tworzenie mapowania się udało, wynikiem tego wywołania jest 0, a adres mapowania jest zwracany w polu
addr
przekazanej struktury. Jeśli się nie udało, zwracany jest kod błędu, a poleaddr
nie jest modyfikowane.PTRACE_REMOTE_MUNMAP
: usuwa mapowanie w zdalnym procesie.addr
jest ignorowane, adata
wskazuje na strukturęptrace_remote_munmap
, zawierającą parametry wywołania. Wartość zwracana i parametry są takie, jak przy zwykłymmunmap
.PTRACE_REMOTE_MREMAP
: jakPTRACE_REMOTE_MMAP
, ale wywołujemremap
. Jeśli wywołanie się uda, wynikiem jest 0, a adres mapowania jest zwracany w polunew_addr
przekazanej struktury.PTRACE_REMOTE_MPROTECT
: jak wyżej, ale dlamprotect
.PTRACE_DUP_TO_REMOTE
: zachowuje się jakdup
, ale tworzy nowy deskryptor w zdalnym procesie.addr
jest ignorowany, adata
wskazuje na strukturęptrace_dup_to_remote
:local_fd
: deskryptor pliku w procesie wywołującymptrace
, który chcemy zduplikować do procesu śledzonegoflags
: flagi nowego deskryptora. Jedyną zdefiniowaną flagą jestO_CLOEXEC
.
Wynikiem wywołania jest deskryptor utworzony w zdalnym procesie, lub kod błędu.
PTRACE_DUP2_TO_REMOTE
: zachowuje się jakdup3
, ale tworzy nowy deskryptor w zdalnym procesie. Jak wyżej, ale pobiera dodatkowy parametr:remote_fd
: deskryptor pliku, który ma być utworzony (bądź zamieniony) w zdalnym procesie.
PTRACE_DUP_FROM_REMOTE
: zachowuje się jakdup
, ale duplikuje deskryptor ze zdalnego procesu do procesu wywołującegoptrace
.data
wskazuje na strukturęptrace_dup_from_remote
:remote_fd
: zdalny deskryptor pliku do zduplikowania.flags
: jak wPTRACE_DUP_TO_REMOTE
.
Wynikiem wywołania jest nowy deskryptor w procesie wywołującym, bądź kod błędu.
PTRACE_REMOTE_CLOSE
: zamyka deskryptor pliku w zdalnym procesie.data
wskazuje na strukturęptrace_remote_close
, zawierającą zdalny deskryptor. Wynik wywołania powinien być taki, jak wynik wywołaniaclose
.
Powyższe wywołania powinny działać na procesie, który jest przez nas śledzony
i jest akurat zatrzymany przez ptrace
. W przypadku użycia na innym procesie,
należy zwrócić ESRCH
.
Zasady oceniania¶
Za zadanie można uzyskać do 10 punktów. Na ocenę zadania składają się dwie części:
- wynik automatycznych testów (od 0 do 10 punktów)
- ocena kodu rozwiązania (od 0 do -10 punktów)
Punktacja za kod¶
- -0.3 Arytmetyka na wskaźnikach bezpośrednio, zamiast container_of, offset_of, itp.
- -0.8 Pobieranie nadmiarowych referencji do plików (wyciek), np. jak podano MAP_ANONYMOUS oraz fd
- -0.1 Błędna obsługa MAP_FIXED na adres 0 (to jest dozwolona operacja o ile CONFIG_DEFAULT_MMAP_MIN_ADDR=0)
- -0.5 PTRACE_REMOTE_MMAP modyfikuje dodatkowo inne pola ptrace_remote_mmap niż addr (kopiuje z powrote do userspace te zmiany).
- -0.5 PTRACE_REMOTE_MREMAP nie zwraca nowego new_addr do userspace
- -0.5 Potencjalny wyścig przy obsłudze DUP_{FROM,TO}_REMOTE - samo fcheck() zamiast fget(), bez odpowiednio chroniącej blokady
- -1.0 Niepoprawny patch (nie nakłada się, brakuje ptrace_remote.h, nie kompiluje się, itp).
Forma rozwiązania¶
Jako rozwiązanie należy wysłać paczkę zawierającą:
- patcha na jądro w wersji 4.9.13, w jednym z następujących formatów:
- patch wygenerowaniy przez diffa z opcjami
-uprN
nakładający się przezpatch -p1
git format-patch
- patch wygenerowaniy przez diffa z opcjami
- krótki opis rozwiązania
Rozwiązania prosimy nadsyłać na adres marmarek@mimuw.edu.pl
z kopią
do mwk@mimuw.edu.pl
.
Wskazówki¶
Można czerpać inspirację z systemu plików proc
– on już zawiera mechanizmy dostępu
do zdalnych procesów (choć tylko do odczytu).
Należy zwrócić uwagę na optymalizacje zawarte w kodzie do_mmap
/do_munmap
(i funkcji potomnych)
zakładające, że kod ten jest wywoływany z procesu będącego wewnątrz danej przestrzeni adresowej. Należy
poprawić te optymalizacje (np. wyłączając je dla procesów śledzonych przez ptrace
), bądź
zrealizować funkcjonalność przez wywołanie odpowiedniego kodu w kontekście docelowego procesu.