Saturday, September 4, 2010

Porównanie systemów: biblioteki .so czy .dll?

Temat bibliotek jest na co dzień mało spotykany, po prostu system, a raczej aplikacje ich potrzebują aby działać. Jednak biblioteki dynamicznie ładowane (.dll) czy współdzielone (.so) pozornie decydują o czymś więcej, niż tylko o tym, czy program ich wymagający się uruchomi. Okazuje się, że od tych założeń zależy w bardzo dużej mierze ocena użytkowników co do całego system. Dlaczego? Ponieważ jedne z modeli stwarza problemy dla użytkownika, a drugi nie. W takim razie po co ktoś wybrał te pierwsze rozwiązanie? Wszystkie odpowiedzi na te pytania zmierzają do ostatnio bardzo popularnego tematu związanego z bezpieczeństwem w systemach Windows. Temat ten jest obecnie na tyle gorący aby zainteresować nim czytelnika. Jeżeli zastanawiasz się dlaczego GNU/Linux nie może zastąpić systemu Windows, oraz dlaczego na Windows XP bez problemu zainstalujesz najnowsza aplikacje podczas, gdy na pingwinie oznacza to wojnę z bibliotekami, to ten artykuł jest przeznaczony dla Ciebie.

Gorącym tematem, o którym wspomniałem jest „DLL hijacking”, czyli atak na bibliotekę programu, a właściwie jej wykorzystanie do uruchomienia własnego kodu. Zanim omówię ten problem najpierw jednak wrócę do pytania dlaczego Windows jest „lepszy”?. Dla przykładu porównam mechanizm używania bibliotek, z których korzysta aplikacja, np. Firefox na obu systemach, GNU/Linux i Windows XP. Dlaczego starsza wersja systemu? Ponieważ świetnie obrazuje efekt innego podejścia do implementacji mechanizmu bibliotek.

Chyba każdy wie, ze biblioteki te istnieją po to, aby zaoszczędzić pamięć. Gdy potężna aplikacja zostaje uruchomiona, do pamięci ładowany jest przez system operacyjny minimalny kod. Jest to zależne od programistów aplikacji, a nie systemu. Gdy użyjemy którejś z bardziej rozbudowanych funkcji, program załaduje odpowiedni kod jego obsługi, np. czytanie innego formatu plików wideo. Wczytanie to ma postać załadowania pliku .dll lub .so do przestrzeni roboczej programu.

Wróćmy jednak do instalacji Firefoxa 4 na dwóch różnych systemach. Gdy zechcemy zaktualizować swoją przeglądarkę na systemie Windows XP wystarczy że ją ściągniemy, zainstalujemy i to wszystko. Instalacja powiedzie się, mimo iż instalujemy nową aplikacje na systemie, który ma prawie 10 lat. Wszystkie biblioteki wymagane prze całkowicie nową aplikacje zostaną skopiowane do katalogu macierzystego programu i stamtąd zostaną załadowane przez aplikacje.

W przypadku GNU/Linux tak łatwo już nie ma. Możemy ściągnąć najnowsze źródła albo odpowiedni plik binarny i spróbować uruchomić go na naszym systemie. Niestety zakończy się to komunikatem o niespełnionych zależnościach, np. w postaci „Biblioteka X jest w wersji 1.0, wymagana jest wersja 2.0”. Jaki jest tego powód? Właściwie dwa. Pierwszy to model projektowy, który zakłada centralizacje i nie duplikowanie wersji bibliotek zgromadzonych w systemie. Podobnie jest w systemie Windows, z tym, że w nim scentralizowane są tylko biblioteki systemowe, np. gui32.dll, ntdll.dll, user32.dll. Biblioteki używane przez programy nie są związane w żaden sposób z systemem, są one niezależne od niego.

Chyba już wszyscy wiedza w czym problem. Pozostaje teraz pytanie, w takim razie dlaczego w systemach Unix nie przyjęto takiego założenia jak w systemie Windows sokor daje większe możliwości? Odpowiedzią na to pytanie jest między innymi obecnie popularna podatność występująca w systemach z rodziny Windows zwana DLL hijacking. Jak już wspomniałem, podatność ta polega na podkładaniu własnego kodu, który zostanie załadowany do pamięci przez jakiś program. Możliwe jest to, ponieważ biblioteki te nie są chronione przez mechanizmy obronne systemu, np. takie jak prawa dostępu. Dlaczego? Ponieważ nie są jego częścią. Czy separowanie bibliotek naprawdę jest dużym problemem? Okazuje się, ze tak. Gdy w systemie Unix zostanie odkryta podatność wszystkie aplikacje używające podatnej biblioteki stają się zagrożone, ale aktualizacja systemowa biblioteki naprawia ten problem hurtowo. W przypadku systemu Windows nie ma takiej możliwości załatania biblioteki, z których korzysta np. Firefox. Obecnie poprawianie takich błędów wymaga indywidualnego nakładania łatek dla każdej aplikacji z osobna, co jak wiadomo w dużym środowisku jest niewygodnym rozwiązaniem.

Dlatego podejście użyte w systemach Unix ma sens i przetrwało do dziś, opierając się modzie na nowe oprogramowanie. Jest to również jeden z głównych powodów projektowych, z których używanie aplikacji biurkowych jest w pewnym sensie ograniczone. Projektanci systemu Unix postawili na centralizację oraz bezpieczeństwo mechanizmu ładowanych bibliotek. Projektanci systemu Windows postawili na umożliwienie użytkownikowi zarządzanie bibliotekami, w celu bezproblemowej aktualizacji aplikacji. Tylko, czy powierzenie użytkownikowi takiego zadania jest rozsądną decyzją? Z punktu widzenia projektantów systemu i celów jakie mieli osiągnąć z pewności tak. Świadczy o tym popularyzacja tego systemu jako platformy systemowej dla większości aplikacji.

Różnica z podejść projektowych wynika jeszcze z samego modelu w jakim jest rozprowadzany kod. W przypadku bibliotek otwartych zarządzanie nimi przez system nie stanowi problemu. Inaczej ma się sprawa do oprogramowania komercyjnego, którego twórcy nie chcą aby ktoś lub coś kontrolowało ich kod.