Kernel

Linux kernel EFI boot stub i zaszyfrowany Debian (LUKS+LVM)

Szukając informacji na temat uruchamiania mojego zaszyfrowanego Debiana (LUKSv2+LVM) na laptopie z EFI/UEFI, natrafiłem na dość ciekawy mechanizm zwany kernel EFI boot stub, czasem też zwany kernel EFISTUB. Zadaniem tego mechanizmu jest uruchomienie linux'a bezpośrednio z poziomu firmware EFI z pominięciem czy też bez potrzeby stosowania dodatkowych menadżerów rozruchu (rEFInd) czy bootloader'ów (grub/grub2/syslinux/extlinux). Jakby nie patrzeć bardzo ciekawa alternatywa, która wymaga, by się z nią zapoznać i ocenić jej przydatność pod kątem użyteczności.

Jak przepisać linki initrd.img{,.old} i vmlinuz{,.old} z / do /boot/

Mając możliwość skonfigurowania EFI/UEFI na moim laptopie, postanowiłem jak najbardziej się za to przedsięwzięcie zabrać. Okazało się jednak, że w przypadku takiej dystrybucji linux'a jak Debian, to zadanie może być nieco problematyczne, zwłaszcza gdy chce się korzystać jedynie z menadżera rozruchu jakim jest rEFInd, czyli bez dodatkowego bootloader'a (grub/grub2/syslinux/extlinux) instalowanego bezpośrednio na dysku twardym i jednocześnie posiadając w pełni zaszyfrowany system (LUKSv2 + LVM). Rzecz w tym, że w takiej sytuacji w konfiguracji rEFInd trzeba podawać ścieżki bezpośrednio do plików initrd.img oraz vmlinuz (obecnych na partycji /boot/ ). W Debianie nazwy tych plików mają format initrd.img-x.x.x-x-amd64 i vmlinuz-x.x.x-x-amd64 . Za każdym razem, gdy wypuszczany jest nowy kernel, to ten numerek ( x.x.x-x ) ulega zmianie, co pociąga za sobą potrzebę ręcznego dostosowania konfiguracji rEFInd. Może i aktualizacje kernela w Debianie nie są jakoś stosunkowo częste ale może istnieje sposób, by ten problem z dostosowaniem konfiguracji rozwiązać?

Moduł TPE (Trusted Path Execution) dla kernela linux

Użytkownicy linux'a są zwykle chronieni przez mechanizmy bezpieczeństwa, które ten system jest w stanie zaoferować. Oczywiście deweloperzy różnych dystrybucji, np. Debiana, dokładają wszelkich możliwych starań, by system jako całość był wstępnie skonfigurowany tak, by końcowy użytkownik nie musiał za wiele majstrować przy zabezpieczeniach i mógł się czuć i być (przynajmniej względnie) bezpieczny. No i faktycznie złowrogie oprogramowanie ma czasem spore problemy dostać się do maszyny, którą operuje linux. Niemniej jednak, gdy już taki syf się do systemu dostanie, to zwykle niewiele dzieli go od przejęcia kontroli nad komputerem. Może i część zabezpieczeń linux'a zadziała i sprawi, że taki wirus/trojan czy nawet zwykły skrypt będzie miał ograniczone pole manewru, to i tak będzie on mógł przeprowadzić te akcje, które zwyczajny użytkownik systemu (nie root) jest zwykle w stanie poczynić, np. odebrać dźwięk i video ze stosownych urządzeń i przesłać te dane przez sieć. My z kolei możemy nawet tego faktu nie być świadomi. Jasne, że powinno się zwracać uwagę na to jakie pliki się pobiera z internetu i nie uruchamiać wszystkiego lekkomyślnie ale też trzeba mieć na uwadze fakt, że często jedna maszyna jest współdzielona, np. z członkami rodziny i oni już niekoniecznie muszą władać zaawansowaną wiedza z zakresu IT, by przewidzieć wszystkie możliwe zagrożenia czyhające na nich w sieci. Można za to postarać się, by uczynić naszą maszynę nieco bardziej odporną na niezbyt przemyślane zachowania użytkowników jej systemu operacyjnego. Jednym z kroków, które możemy podjąć, jest wdrożenie mechanizmu Trusted Path Execution (TPE), który póki co jest dostępny jedynie w formie patch'a na kernel linux'a lub też jako jego osobny moduł oferujący sporo więcej możliwości w stosunku do wspomnianej wcześniej łaty. W niniejszym artykule rzucimy sobie okiem na ten cały mechanizm TPE i zobaczymy jak jest on w stanie uchronić nasz OS przed niezbyt zaawansowaną ludzką inteligencją.

Jak na Debianie zrobić pakiet .deb zawierający moduł kernela linux (DKMS)

Kernel linux'a jest dość złożonym organizmem, który może zostać rozbudowany przy pomocy dodatkowego kodu ładowanego w postaci zewnętrznych modułów. Czasem ze względu na wczesny etap prac nad nową funkcjonalnością jądra, taki moduł może zachowywać się dość nieprzewidywalnie, co przekreśla jego szanse na pojawienie się w stabilnych wydaniach kernela. Czasem też z jakiegoś niezrozumiałego powodu pewne rzeczy nie są celowo dodawane do jądra operacyjnego. Jedną z nich jest moduł Trusted Path Execution (TPE), który jest w stanie znacznie poprawić bezpieczeństwo systemu uniemożliwiając przeprowadzenie w nim szeregu podejrzanych działań. W Debianie tego typu niedogodności związane z brakiem pewnych modułów można obejść przez zastosowanie mechanizmu DKMS, który przy instalacji modułu spoza głównego drzewa kernela linux'a jest nam go w stanie automatycznie zbudować. W repozytorium dystrybucji Debiana znajduje się już szereg pakietów z modułami (mają końcówki -dkms ) i w prosty sposób można je sobie doinstalować. Co jednak w przypadku, gdy mamy moduł, którego nikt jeszcze nie przygotował i nie wrzucił do repozytorium? Co, gdy takich modułów mamy kilka, a przy tym korzystamy z najnowszego stabilnego kernela, który jest aktualizowany średnio co kilka dni? Ręczna budowa wszystkich zewnętrznych modułów za każdym razem jak tylko wyjdzie nowsza wersja kernela, to nie najlepsze wyjście, zwłaszcza jak dojdzie nam do tego aktualizacja samych modułów. Można za to zrobić sobie paczkę .deb tak, by przy instalacji nowego jądra operacyjnego, system nam automatycznie zbudował wszystkie dodatkowe moduły, których nasz komputer wymaga do poprawnej pracy.

Czy brak wsparcia dla SYNPROXY w nftables jest problemem

Przenosząc swoje reguły z iptables na nftables zauważyłem, że jedna z nich (gdyby tylko jedna) nie została przetłumaczona przez ten dedykowany translator do reguł. Chodzi o mechanizm SYNPROXY, który jest zwykle wykorzystywany do ograniczenia skali ataków DDOS z wykorzystaniem pakietów SYN. Co by nie mówić, to ochrona jaką daje SYNPROXY jest jak najbardziej pożądana z perspektywy serwerów. Dlaczego zatem, gdy się zajrzy na stronę wspieranych rzeczy w nftables, to przy SYNPROXY widnieje bliżej nieokreślone sformułowanie consider native interface ? Po rozmowach z deweloperami udało się ustalić, że ten zapis oznacza brak wsparcia dla SYNPROXY w nftables . Jeśli zatem ktoś wykorzystuje ten mechanizm mając dodane stosowne reguły w iptables , to czy powinien się on obawiać przejścia na nftables ?

Jak ręcznie zweryfikować sygnaturę modułu kernela linux

Bawiąc się ostatnio kernelem linux na dystrybucji Debian i opcjami mającymi poprawić jego bezpieczeństwo, włączyłem sobie mechanizm podpisywania modułów. W ten sposób żaden zewnętrzny moduł nie zostanie załadowany przez jądro operacyjne, no chyba, że taki moduł będzie podpisany przez ten sam klucz co i kernel. Zdziwiłem się odrobinę, gdy moim oczom pokazał się hash md4 w wyjściu polecenia modinfo . Jak się okazało później, to niezbyt dokładne zinterpretowanie wiadomości PKCS#7 przez kmod było (i nadal jest) wynikiem błędu obecnego w tym pakiecie od już paru lat. W efekcie modinfo nie jest w stanie zweryfikować tej sygnatury, a w moim umyśle zaistniało pytanie: czy istnieje w ogóle możliwość manualnego sprawdzenia czy ta sygnatura jest w porządku? Kernel co prawda ten cały zabieg przeprowadza automatycznie ale przydałoby się ręcznie zweryfikować poprawność sygnatury modułu i przy okazji obadać sobie co tak naprawdę się dzieje podczas tego procesu.

Automatyczne podpisywanie modułów kernela przez DKMS

Budując kernel linux'a trzeba zastanowić się nad kwestią modułów, które nie są wbudowane bezpośrednio w samo jądro operacyjne. Nie chodzi tutaj bezpośrednio o funkcjonalność kernela, którą można zbudować jako moduł w procesie jego kompilacji ale raczej o wszystkie zewnętrzne moduły, które przez zespół kernela są traktowane jako out-of-tree . By poprawić nieco bezpieczeństwo związane z takimi modułami, można wdrożyć podpisy cyfrowe, które takie moduły muszą okazać podczas próby załadowania ich w systemie. Gdy moduł nie został podpisany, to kernel go nie załaduje zwracając przy tym błąd modprobe: ERROR: could not insert 'module': Required key not available . W ten sposób można ochronić się przed częścią ataków, w których moduły pochodzenia trzeciego mogą zostać załadowane i poczynić nam ogromne spustoszenie w systemie. Problem w tym, że w dystrybucji Debian wykorzystywany jest mechanizm DKMS (Dynamic Kernel Module Support). Może i mamy dzięki niemu możliwość instalacji w systemie całej masy dodatkowych modułów ale ich również nie będzie można załadować, bo nie zostały podpisane kluczem, którego certyfikat został zaszyty w kernelu. Można jednak zmusić mechanizm DKMS, by wskazane przez nas moduły podpisywał automatycznie przy ich instalacji i aktualizacji.

Budowanie kernela linux dla konkretnej maszyny z Debianem

Każda maszyna działająca pod kontrolą dystrybucji linux ma na swoim pokładzie kernel, czyli jądro operacyjne, które zarządza praktycznie każdym aspektem pracy takiego komputera. W dystrybucji Debian, kernel jest dostarczany w pakietach mających nazwy zaczynające się od linux-image-*. Te pakiety są budowane przez odpowiednie osoby z zespołu Debiana i udostępniane do łatwej instalacji użytkownikowi końcowemu. Niemniej jednak, taki kernel ma za zadanie działać na jak największej ilości komputerów, a przez to posiada całą masę modułów, które na naszej maszynie nigdy nie będą wykorzystane. Ten fakt nie wpływa w jakimś ogromnym stopniu na pracę maszyny, ale gdy później zachodzi potrzeba skonfigurowania kernela w nieco inny sposób, np. włączenie jednej czy dwóch opcji czy też nałożenie patch'a, który nie został zaaplikowany przez dev'ów Debiana, to trzeba taki kernel na nowo skompilować już samodzielnie, a to zajmie nam bardzo dużo czasu. Zamiast tego można pokusić się o przygotowanie kernela pod konkretny hardware wyłączając przy tym całą masę zbędnych rzeczy i ograniczając przy tym czas jaki jest potrzebny na zbudowanie całego jądra operacyjnego. Czy istnieje jakiś prosty sposób, by taki kernel zbudować sobie samemu mając przy tym minimalną wiedzę co do opcji kernela, które mogą nas przysporzyć o ból... głowy? Okazuje się, że tak i w tym artykule prześledzimy sobie cały ten proces.

Jak zdiagnozować kernel OOPS

Kernel linux'a, jak każdy inny program, podczas swojego działania może napotkać nieprzewidzianą przez programistów sytuację. W przypadku zwykłych aplikacji, pewne błędy krytyczne mogą doprowadzić do "naruszenia ochrony pamięci", co szerzej jest znane jako segfault. W przypadku wystąpienia tego błędu, proces zwykle jest unicestwiany. Co jednak w przypadku kernela? Odpowiedź jest prosta: kernel panic, czyli panika kernela, która pozostawia system w stanie braku jakichkolwiek oznak życia. Są jednak pewne błędy, z którymi kernel jest w stanie sobie poradzić i odzyskać sprawność w mniejszym lub większym stopniu. Te błędy są nazywane kernel OOPS. W tym wpisie postaramy się przeanalizować przykładowy OOPS i zobaczymy czy uda nam się ustalić przyczynę zaistniałego problemu.

Konfiguracja interfejsów IMQ w linux'ie

W linux'ie, kształtowanie przychodzącego ruchu sieciowego stwarza dość poważne problemy. Na dobrą sprawę, obecnie w kernelu nie ma żadnego mechanizmu, który byłby w stanie to zadanie realizować. Istnieją, co prawda, interfejsy IFB ale za ich pomocą jesteśmy w stanie z powodzeniem kształtować jedynie ruch wychodzący. W przypadku pakietów napływających, możemy jedynie ograniczyć im przepustowość. W tym powyższym linku jest wzmianka, że te interfejsy IFB są następcą interfejsów IMQ. Niemniej jednak, ten drugi projekt zdaje się działać, choć nie jest obecnie wspierany przez kernel linux'a. W tym wpisie postaramy się skonfigurować działające interfejsy IMQ, tak, by za ich pomocą skutecznie kształtować ruch przychodzący.