W zeszłym miesiącu ukazała się nowa wersja Ubuntu oznaczona numerkiem 16.04, więc pora na krótką recenzję oraz na rozwiązanie problemu UEFI i modułów kernela.
Oczywiście nie będzie to artykuł pokazujący 10,15 czy 20 czynności do wykonania po instalacji systemu, gdyż jest już tego dużo w sieci i generalnie wszędzie piszą to samo. Ja natomiast omówię co mi się podoba w nowej wersji Ubuntu. Dodatkowo omówię problem, który pojawił się w tej wersji i jak sobie z nim poradziłem.
Ubuntu 16.04 to pierwszy LTS, który nieco zawiódł i podzielił zwolenników tego systemu. Jedni narzekają na to, że nie ma Unity 8. Inni są niezadowoleni z tego, że Synaptic nie pokazuje wszystkich pakietów (zepsute indeksowanie). Ja nie należę ani do jednych, ani do drugich.
Dla mnie 16.04 to udany system, choć rzeczywiście to indeksowanie mogłoby lepiej działać. Nie rozumiem narzekania, dlaczego nie ma w Ubuntu Unity 8 lub serwera wyświetlania Mir. Szczerze, nawet nie wiem co takiego wspaniałego jest w tym Unity 8, że wszyscy o tym piszą. Dla mnie Unity 7 jest super środowiskiem, choć na początku miało swoje minusy (ciągłe zwiechy czy resetowanie się). Teraz to pełnoprawne środowisko i w dodatku stabilne.
Mir miałem szanse testować jeszcze w wersji 14.04 i 14.10 na starym laptopie z wbudowaną kartą Intela. Działał szybciej niż zwykle X'y, ale miał jeden, czasem wkurzający mankament: we wszystkich aplikacjach, które odwlekały wygaszacz ekranu i działały na pełnym ekranie (gry, SMPlayer) co jakiś czas ekran migał na czarno. Po powrocie do X'ów wszystko wracało do normy.
W końcu w Ubuntu 16.04 można przenieść launcher Unity na dół ekranu. Super, że jest wybór, nawet ładnie to wygląda, ale już się przyzwyczaiłem do lewego brzegu ekranu. Rozumiem też, dlaczego właśnie tam pierwotnie umieszczono launcher. Teraz ekrany są szersze niż dłuższe, więc zaoszczędzono wysokość ekranu kosztem szerokości, której i tak jest pod dostatkiem.
Nowością w tej wersji są również kontenery aplikacji Snappy. Są one podobne trochę do Dockera, którym się ostatnio zajmuję służbowo. Ma to swoje plusy, np. aplikacja jest odizolowana od systemu i jedyne co ma z nim wspólnego to uruchomiony kernel. Ale jest też poważny minus: nawet mała aplikacja jak kalkulator będzie ważyć sto kilkadziesiąt megabajtów. Czemu tak? Kontener to zamknięte środowisko i nie ma dostępu do plików systemowych. Aby program mógł być uruchomiony, potrzebne są wszystkie zależności systemowe, wszystkie biblioteki z którymi został skompilowany. Całe te środowisko uruchomieniowe o nazwie 'ubuntu-core' musi być pobrane i dodane do kontenera. Zatem pliki zaczynają się dublować, a co za tym idzie zajmują więcej miejsca. Ma to niby ułatwić życie programistom, którzy nie będą musieli się martwić tym, czy użytkownik ma w systemie odpowiednie biblioteki (tak jakby teraz musieli się tym martwić, skoro bibliotekę można pobrać z repo i współdzielić ją z innymi programami). Ale to rozwiązanie ma też swój plus. Czasami się zdarzają programy, które działają tylko z określoną wersją biblioteki. Nie chcemy jej zmieniać w systemie, bo polegają na niej inne programy, więc w kontenerze możemy zamknąć aplikację wraz z tą konkretną wersją biblioteki.
Jak już wcześniej napisałem, kontener jest odizolowany od systemu (kwestia bezpieczeństwa i niezależności). To sprawia, że integracja ze środowiskiem graficznym również jest ograniczona. Programu zamkniętego w kontenerze nie będzie można zminimalizować do ikonki na panelu, ani również nie będzie pojawiała się ilość powiadomień na ikonce w launcherze.
Choć jest to fajna technologia, nie wróżę jej świetlanej przyszłości na desktopie. W środowiskach serwerowych czy wbudowanych widzę masę zastosowań dla takich rozwiązań jak Snappy czy Docker. Choć jest jeden wyjątek: kiedyś mogłem grać bez problemu w linuksową wersję Neverwinter Nights. Teraz nie mam dźwięku, ponieważ gra wymaga jakiejś starej biblioteki. Wpadłem więc na pomysł, aby w kontenerze zamknąć grę wraz ze środowiskiem uruchomieniowym ze starego Ubuntu, w którym dźwięk był. Ciekaw jestem czy to rozwiązanie zadziała.
Na koniec omówię problem, z którym się spotkałem po aktualizacji systemu do 16.04. Od wersji 14.10, którą zainstalowałem na nowym laptopie, używam UEFI. Nie sprawiało to problemów, klucz podpisujący kernele sprawował się nieźle z UEFI, ale pozwalał on tylko na uruchomienie kernela i na tym ochrona systemu przez SecureBoot się kończyła. W 16.04 w kernelach włączono opcję CONFIG_EFI_SECURE_BOOT_SIG_ENFORCE, która powoduje, że nie tylko kernel musi być podpisany, ale również wszystkie moduły kernela. Nie było problemów ze wszystkimi open source'owymi modułami, ale z tymi od nVidii czy Oracle już tak. Wyskakiwał taki oto błąd:
modprobe: ERROR: could not insert 'nvidia_361': Required key not available sign module
To powodowało, że nie mogłem używać drugiej karty graficznej bądź VirtualBox'a. Co do nVidii pomyślałem czemu Canonical, który podpisał swoim prywatnym kluczem kernel nie podpisze również modułów ze sterami do nVidii, które są w ich oficjalnym repo ze sterami ppa:graphics-drivers/ppa. Jak się później okazało, podpisywanie modułów nie odbywa się na etapie kompilacji. Podpisuje się gotowe binarki.
Po lekturze na oficjalnej stronie dokumentacji Ubuntu oraz poradnika jak podpisywać moduły kernela w dokumentacji RedHata wpadłem na pomysł: a czemu samemu nie podpisywać tych modułów. Za pomocą programu xca wygenerowałem klucz prywatny, a z niego certyfikat CA (centrum certyfikacji). Wygenerowany w ten sposób certyfikat (w formacie der) dodałem do bazy MOK (Machine Owner Key). MOK to baza kluczy autoryzujących uruchomienie kernela i modułów, która współdziała z SecureBoot.
# mokutils --import certCA.der
Program po zaimportowaniu certyfikatu zapytał się o hasło do bazy MOK. Jako że przedtem niczego nie importowałem, baza z certyfikatami dopiero została stworzona. Po restarcie systemu, na samym początku, jeszcze przed GRUBem uruchomił się MOKManager. Jest to program na partycji EFI, który jest wywoływany, gdy zajdzie zmiana w bazie MOK. Wybieramy opcję Enroll keys. Podajemy hasło do bazy, którą wcześniej zabezpieczyliśmy hasłem, wybieramy certyfikat CA, który dodaliśmy przed chwilą i potwierdzamy. Po reboocie mamy już połowę sukcesu. Teraz trzeba podpisać moduły kluczem prywatnym, z którego wygenerowaliśmy CA.
Na początek trzeba sprawdzić, czy mamy zainstalowane nagłówki kernela. W ścieżce /usr/src/«wersja kernela»/scripts/sign-file znajduje się program do podpisywania modułów. W ścieżce /lib/modules/«wersja kernela»/updates/dkms/ są moduły do podpisania. W moim przypadku były to moduły Bumblebee, nVidia i VirtualBox. Przypuśćmy, że chce podpisać moduły nVidii.
/usr/src/linux-headers-4.4.0-22-lowlatency/scripts/sign-file sha256 CA.pem CAcert.cer /lib/modules/4.4.0-22-lowlatency/updates/dkms/nvidia_361.ko nvidia_361.ko
Parametry polecenia:
- sha256 - metoda podpisywania
- CA.pem - klucz prywatny w formacie pem w bieżącym katalogu
- CAcert.cer - certyfikat publiczny CA w bieżącym katalogu, ten sam co w bazie MOK
- /lib/modules/4.4.0-22-lowlatency/updates/dkms/nvidia_361.ko - ścieżka dostępu do modułu
- nvidia_361.ko - podpisany moduł, zapisany w bieżącym katalogu
Ostatni parametr możemy pominąć, a wtedy podpiszemy moduł w miejscu. Jeżeli nie podpisujemy w miejscu, trzeba będzie potem zamienić pliki niepodpisane na podpisane.
Tak traktujemy wszystkie pliki z katalogu /lib/modules/4.4.0-22-lowlatency/updates/dkms/. Gdy skończymy podpisywać, możemy spróbować, czy uda nam się załadować moduł np.
# modprobe nvidia_361
Jeżeli nie wyskoczy żaden błąd, to znaczy, że udało nam się prawidłowo podpisać i teraz możemy używać podpisanych modułów.
Dzięki temu zabiegowi zyskujemy jeszcze jedną warstwę zabezpieczeń przed malware'm na Linuksie. Oczywiście mógłby ktoś powiedzieć, że "przecież na Linuksa nie ma wirusów". Do czasu. Linux staje się coraz bardziej popularny i kiedyś może nadejść moment, że zaczną się pojawiać trojany czy wirusy na Linuksie. Lepiej się uczyć na cudzych błędach i zabezpieczyć się zawczasu. Jednym ze sposobów atakowania Linuksa jest instalacja własnego modułu. Ktoś pod przykrywką super przydatnego programu, może zachęcić nas do zainstalowania paczki deb, a w tym momencie skrypt instalacyjny doda swój moduł, który będzie się uruchamiał z uprawnieniami roota co start systemu. A wtedy będzie mógł robić wszystko.
Mechanizm wymagania podpisanych modułów nie pozwoli na załadowanie niepodpisanego modułu, przez co atakujący nie będzie mógł przejąć kontroli nad komputerem ofiary. Patrząc po forach jak ludzie dodają do systemu każde PPA bez weryfikacji, zagrożenie jest realne. Ważne będzie również, aby nie trzymać na dysku klucza prywatnego w formie niezaszyfrowanej, ponieważ hakerzy będą się pewnie starali wyszukiwać na dysku takich kluczy i próbować podpisywać moduł.
Podsumowując Ubuntu 16.04 w porównaniu do 15.10 niewiele się zmieniło, przynajmniej jeżeli chodzi o wygląd. Pod maską doszło kilka elementów, ale też nie wszyscy muszą z nich korzystać. Osobiście zauważyłem tylko jeden bug, ten z Synapticiem. Reszta systemu chodzi tak samo jak we wcześniejszej wersji co mnie cieszy, bo skończyły się czasy, gdy po instalacji nowego Ubuntu trzeba było spędzić dzień na przystosowaniu komputera do swoich wymogów. Teraz po prostu zaktualizowałem system, uruchomiłem ponownie i działa. A jakie są Wasze spostrzeżenia dotyczące najnowszego wydania 16.04?