2009-10-15 8 views
12

Mam program napisany w C++, który używa dlopen do ładowania biblioteki dynamicznej (Linux, i386, .so). Kiedy plik biblioteki jest później modyfikowany, mój program ma tendencję do awarii. Jest to zrozumiałe, ponieważ przypuszczalnie plik jest po prostu mapowany do pamięci.Używając dlopena, w jaki sposób mogę poradzić sobie ze zmianami w wczytanym pliku biblioteki?

Moje pytanie brzmi: inaczej niż po prostu tworzenie kopii pliku i dlopening, czy jest sposób, aby załadować wspólny obiekt, który jest bezpieczny przed kolejnymi modyfikacjami, lub w dowolny sposób, aby odzyskać od modyfikacji do wspólnego obiektu który załadowałem?

Wyjaśnienie: Pytanie brzmi nie „jak mogę zainstalować nową bibliotekę bez awarii programu”, to „jeśli ktoś, kto nie jest kontrolować kopiowanie bibliotek wokół, jest to możliwe dla mnie, aby bronić się przed że?"

Odpowiedz

17

Jeśli przed zainstalowaniem nowej biblioteki będzie , myślę, że Twój system będzie przechowywać i-węzeł przydzielony, plik otwarty, a twój program uruchomiony. (A kiedy twój program w końcu się zakończy, wtedy zostaną ukryte głównie ukryte, ale wciąż dostępne zasoby plików.)

Aktualizacja: OK, doprecyzowanie. Dynamiczny linker faktycznie całkowicie "rozwiązuje" ten problem, przekazując flagę MAP_COPY, jeśli jest dostępna, do mmap(2). Jednak wersja MAP_COPY nie istnieje w systemie Linux i nie jest planowaną przyszłością. Drugi najlepszy to MAP_DENYWRITE, który, jak sądzę, używa program ładujący, który jest w Linuksie API i który Linux robił. Występuje błąd podczas zapisywania regionu podczas mapowania. Powinno nadal zezwalać na rm i zastępować. Problem polega na tym, że każdy, kto ma dostęp do pliku do odczytu, może go odwzorować i zablokować zapis, co spowoduje otwarcie lokalnego otworu DoS. (Rozważmy /etc/utmp. Pojawiła się propozycja, aby użyć bit wykonania uprawnień, aby to naprawić.)

Nie zamierzamy się podoba, ale jest trywialny łatka na jądro, które przywróci MAP_DENYWRITE funkcjonalności. Linux wciąż ma tę funkcję, po prostu usuwa bit w przypadku mmap(2). Trzeba to załatać w kodzie, który jest zduplikowany w architekturze, dla ia32 Wierzę, że plik jest arch/x86/ia32/sys_ia32.c.

asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len, 
          unsigned long prot, unsigned long flags, 
          unsigned long fd, unsigned long pgoff) 
{ 
     struct mm_struct *mm = current->mm; 
     unsigned long error; 
     struct file *file = NULL; 

     flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); // fix this line to not clear MAP_DENYWRITE 

To powinno być OK, o ile nie ma żadnych złośliwych lokalnych użytkowników z poświadczeniami. To nie jest zdalne DoS, tylko lokalne.

+0

To się zgadza. –

6

Po zainstalowaniu nowej wersji biblioteki poprawna procedura polega na utworzeniu nowego pliku w tym samym katalogu, a następnie zmianie jego nazwy na poprzednią. Stary plik pozostanie otwarty, i będzie nadal używany.

Menedżerowie pakietów, na przykład RPM, robią to automatycznie - dzięki czemu można aktualizować udostępnione biblioteki i pliki wykonywalne, gdy są uruchomione - ale stare wersje nadal działają.

W przypadku, gdy trzeba wziąć nową wersję, ponownie uruchomić proces lub ponownie załadować bibliotekę - ponowne uruchomienie procesu brzmi lepiej - program może sam się uruchomić. Nawet init może to zrobić.

1

Jeśli możesz dowiedzieć się, gdzie biblioteka jest zamapowana do pamięci, możesz być w stanie ją zapisać i wykonać trywialny zapis na każdej stronie (np. Odczytać i zapisać pierwszy bajt każdej strony). To powinno ci dać prywatną kopię każdej strony.

Jeśli "mprotect" nie działa (być może oryginalny plik prawdopodobnie był otwarty tylko do odczytu), możesz skopiować region do innej lokalizacji, zamapować region (używając mmap) na prywatny, można zapisać region, a następnie skopiować region z powrotem.

Chciałbym, aby system operacyjny miał "przekształcenie tego obszaru tylko do odczytu w region kopiowania przy zapisie". Nie sądzę jednak, żeby coś takiego istniało.

W każdym z tych scenariuszy nadal istnieje okno z luką w zabezpieczeniach - ktoś może zmodyfikować bibliotekę, podczas gdy dlopen wywołuje inicjalizatory lub zanim nastąpi wywołanie remapu. Nie jesteś naprawdę bezpieczny, chyba że możesz naprawić dynamiczny linker, jak opisuje @ DigitRoss.

Kto w ogóle edytuje twoje biblioteki? Znajdź tę osobę i uderz go w głowę patelnią.

+1

Dzięki za sugestie - niestety mam wiele kłopotów, jeśli smażę-robie ludzi zbyt często :-) – kdt

0

To intrygujące pytanie. Nienawidzę znajdować takich dziur w Linuksie i uwielbiam szukać sposobów ich naprawienia.

Moja sugestia została zainspirowana odpowiedzią @Paul Tomblin na this question about temporary files on Linux. Niektóre z pozostałych odpowiedzi sugerują istnienie tego mechanizmu, ale nie opisałem metody jego wykorzystania z aplikacji klienckiej, o którą prosiłeś.

Nie testowałem tego, więc nie mam pojęcia, jak dobrze to będzie działać. Ponadto mogą występować drobne obawy związane z bezpieczeństwem związane ze stanem wyścigu związane z krótkim okresem czasu między utworzeniem pliku tymczasowego a jego odłączeniem. Poza tym już zauważyłeś możliwość stworzenia kopii biblioteki, którą właśnie proponuję. Mój skręt polega na tym, że twoja tymczasowa kopia istnieje jako wpis w systemie plików tylko przez chwilę, bez względu na to, jak długo masz otwartą bibliotekę.

Gdy chcesz, aby załadować bibliotekę wykonaj następujące kroki:

  1. skopiować plik do tymczasowej lokalizacji, prawdopodobnie zaczynając mkstemp()
  2. obciążenia tymczasowa kopia biblioteki przy użyciu dlopen()
  3. unlink() plik tymczasowy
  4. postępować jak zwykle, zasoby plik zostanie automatycznie usunięte po dlclose()

Byłoby miło, gdyby istniał naprawdę łatwy sposób na osiągnięcie kroku "kopiowania pliku" bez konieczności kopiowania pliku. Na myśl przychodzą twarde linki, ale nie sądzę, że działałoby to w tych celach. Byłoby idealnie, gdyby Linux miał mechanizm kopiowania na piśmie, który był równie łatwy w użyciu jak link(), ale nie jestem świadomy takiego obiektu.

Edytuj: Odpowiedź @Zan Lynx wskazuje, że tworzenie niestandardowych kopii bibliotek dynamicznych może być marnotrawstwem, jeśli są one replikowane w wielu procesach. Moja sugestia prawdopodobnie ma sens tylko wtedy, gdy jest stosowana rozważnie - tylko dla tych bibliotek, które są zagrożone stąpaniem (prawdopodobnie niewielki podzbiór wszystkich bibliotek, które nie zawierają plików w/lib lub/usr/lib).

4

Nie można obronić się przed nadpisaniem biblioteki, jeśli ma ona uprawnienia do zapisu pliku.

Ponieważ pamięć dlopen mapuje plik biblioteki, wszystkie zmiany w pliku są widoczne w każdym procesie, który go otworzył.

Funkcja dlopen wykorzystuje odwzorowanie pamięci, ponieważ jest to najbardziej efektywny pod względem pamięci sposób korzystania z bibliotek współdzielonych. Kopia prywatna marnowałaby pamięć.

Jak powiedzieli inni, właściwym sposobem zastąpienia biblioteki współdzielonej w systemie Unix jest użycie odłączenia lub zmiany nazwy, , a nie, aby zastąpić bibliotekę nową kopią. Polecenie install zrobi to poprawnie.

Powiązane problemy