# Plan ataku `SIGSTOP` i `SIGCONT` ## `SIGSTOP` ### Implementacja w NetBSD #### Wysłanie `SIGSTOP` do pojedynczego procesu przez `kill` - [`sys_kill`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#301) - [`kill1`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#kill1) - [`kpsignal2`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1297): wysyła sygnał do pojedynczego procesu -- Wyczyść oczekujące sygnały `SIGCONT` -- Jeśli proces już jest zatrzymany, koniec -- Dodaj sygnał do listy oczekujących na dostarczenie do procesu ([`sigput`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigput)) -- Dostarcz sygnał do każdego wątku zdolnego go obsłużyć/przyjąć (czyli do wszystkich poza tymi śpiącymi snem nieprzerywalnym i zatrzymanymi przez debugger) --- Sygnał próbujemy dostarczyć do wątku przy użyciu [`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109) - [`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109): powiadamia wątek o sygnale i wybudza żeby mógł go obsłużyć -- Powiadom wątek o sygnale ([`signotify`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#signotify)) -- Jeśli wątek jest aktywny (wykonuje się albo jest na runqueue) to koniec -- Jeśli wątek jest zatrzymany to koniec (ale tylko dlatego że wysyłamy `SIGSTOP`, jeśli wysyłalibyśmy inny sygnał (taki, który nie zatrzymuje procesu), to wątek zostałby wybudzony aby mógł obsłużyć sygnał) -- Jeśli wątek śpi snem przerywalnym, to jest wybudzany ([`setrunnable`](http://bxr.su/NetBSD/sys/kern/kern_synch.c#855)) #### Odbiór sygnału `SIGSTOP` - [`lwp_userret`](http://bxr.su/NetBSD/sys/kern/kern_lwp.c#1587) -- Sprawdź, czy nie czekają na nas jakieś sygnały (flaga `LW_PENDSIG`, ustawiana w [`signotify`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#signotify)) -- Znajdź sygnał czekający na obsługę ([`issignal`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1827)) -- Obsłuż sygnał ([`postsig`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#2050)) - [`issignal`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1827): Wybiera oczekujący sygnał dla wątku, zatrzymuje wątek jeśli sygnał tak mówi -- Najpierw szukaj sygnału w liście per-wątek, potem w liście per-proces -- Jeśli sygnał ma zatrzymać proces, to zatrzymaj się ([`sigswitch`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigswitch)) - [`sigswitch`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigswitch): -- Jeśli jesteś pierwszym zatrzymującym się wątkiem procesu, [`proc_stop`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#proc_stop) -- Jeśli jesteś ostatnim zatrzymującym się wątkiem, [`proc_stop_done`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#proc_stop_done) -- Przełącz się na inny wątek ([`sigswitch_unlock_and_switch_away`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigswitch_unlock_and_switch_away)) - [`proc_stop`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#proc_stop): Zatrzymuje proces -- Ustaw w procesie flagę `PS_STOPPING` -- to daje innym wątkom sygnał do zatrzymania -- Zatrzymaj wszystkie wątki śpiące snem przerywalnym ([`proc_stop_lwps`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#proc_stop_lwps)): --- Zatrzymane w ten sposób wątki są cały czas na sleepqueue, zmienia się tylko ich status (z `LSSLEEP` na `LSSTOP`) -- Spraw, aby pozostałe wątki sprawdziły na wyjściu z jądra sygnały ([`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109)) -- Uruchom callouta, który co chwilę skanuje procesy i dla każdego zatrzymującego się procesu, którego nie wszystkie wątki się zatrzymały, zatrzymuje wątki śpiące snem przerywalnym ([`proc_stop_callout`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#2403)). - [`proc_stop_done`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#proc_stop_done): Oznacza proces jako zatrzymany i powiadamia rodzica sygnałem `SIGCHLD` - [`sigswitch_unlock_and_switch_away`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigswitch_unlock_and_switch_away): Ustawia status wątku na `LSSTOP` i przełącza wątek (`mi_switch`) ## `SIGCONT` ### Implementacja w NetBSD #### Wysłanie `SIGCONT` do pojedynczego procesu przez `kill` - [`sys_kill`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#301) - [`kill1`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#kill1) - [`kpsignal2`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1297): wysyła sygnał do pojedynczego procesu -- Wyczyść oczekujące sygnały zatrzymujące proces (`SIGTSTP`, `SIGSTOP`, `SIGTTOU`, `SIGTTIN`) -- Jeśli proces jest aktywny, nie jest w trakcie zatrzymywania się i proces nie obsługuje `SIGCONT`, koniec -- Jeśli proces jest zatrzymany lub w trakcie zatrzymywania się: --- Zmień status procesu na aktywny --- Powiadom rodzica o zmianie statusu dziecka sygnałem SIGCHLD --- Jeśli proces obsługuje `SIGCONT`, dodaj sygnał do listy oczekujących na dostarczenie do procesu ([`sigput`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#sigput)) -- Dostarcz sygnał do każdego wątku zdolnego go obsłużyć/przyjąć (czyli do wszystkich poza tymi śpiącymi snem nieprzerywalnym i zatrzymanymi przez debugger) --- Sygnał próbujemy dostarczyć do wątku przy użyciu [`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109) - [`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109): powiadamia wątek o sygnale i wybudza żeby mógł go obsłużyć -- Powiadom wątek o sygnale ([`signotify`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#signotify)) -- Jeśli wątek maskuje `SIGCONT` i nie jest zatrzymany, koniec (zatrzymane wątki zawsze są wybudzane `SIGCONT`em, niezależnie od innych rzeczy) -- Jeśli wątek jest aktywny (wykonuje się albo jest na runqueue) to koniec -- Jeśli wątek jest zatrzymany: --- Jeśli `l_wchan != NULL` (czyli wątek jest na sleepqueue), przywracamy go do stanu `LSSLEEP` --- W p.p. wątek jest wybudzany ([`setrunnable`](http://bxr.su/NetBSD/sys/kern/kern_synch.c#855)) --- Jeśli wątek śpi snem przerywalnym, to jest wybudzany ([`setrunnable`](http://bxr.su/NetBSD/sys/kern/kern_synch.c#855)) ## Wysyłanie sygnału do zatrzymanego procesu - [`sys_kill`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#301): nie ma żadnej logiki - [`kill1`](http://bxr.su/NetBSD/sys/kern/sys_sig.c#kill1): sprawdza uprawnienia i czy proces jest żywy (`SACTIVE` lub `SSTOP`) - [`kpsignal2`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1297): po wstawieniu sygnału na listę pending bezwarunkowo powiadamiamy wątek lub wątki o sygnale ([w tym miejscu](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1491)) - [`sigpost`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1109): -- [`case LSSTOP:`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1192) --- Jeśli wątek nie jest na sleepqueue lub jest na sleepqueue i można go przerwać, to wybudzamy wątek [w tym miejscu](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1212) - Wątki zatrzymują się w [`issignal`](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1827): pierwszy wątek (ten, który zdjął sygnał do zatrzymania z kolejki sygnałów) zatrzymuje się [tu](http://bxr.su/NetBSD/sys/kern/kern_sig.c#2006), wszystkie pozostałe [tu](http://bxr.su/NetBSD/sys/kern/kern_sig.c#1853). Po wybudzeniu wątek od razu sprawdza, czy proces jest zatrzymany i zatrzymuje się jeśli tak, więc inne sygnały nie będą obsługiwane dopóki proces nie zostanie wznowiony. ## Co trzeba zrobić w Mimikerze - Nowe akcje w `def_sigact`: `SA_STOP` i `SA_CONT` - Nowy stan wątku: `TDS_STOPPED` - Nowy stan procesu: `PS_STOPPED` - `sig_kill`: -- Wznawianie procesu -- Dochodzi dodatkowy przypadek przy wybudzaniu wątku: teraz może też być zatrzymany -- Może przyda się funkcja do wybudzania wątków, coś w stylu [`setrunnable`](http://bxr.su/NetBSD/sys/kern/kern_synch.c#855) - Zatrzymywanie procesu w `sig_post` - `sleepq`: czy chcemy pozostawiać zatrzymane wątki śpiące snem przerywalnym na sleepq? Chyba prościej będzie przerywać sen przed zatrzymaniem ## Co jest w POSIXie ale nie jest priorytetem - Powiadamianie rodzica o zmianie statusu dziecka