2013-08-05 15 views
5

W moim środowisku niestandardowym biblioteka przechwytująca jest wstępnie załadowana, co powoduje specjalną implementację wywołań bind(), connect() itd.Czy używanie funkcji linux wyłącza LD_PRELOAD

Problem widzę tylko wtedy, gdy aplikacja jest jawnie włączona możliwości za pomocą polecenia setcap, uruchomienie aplikacji nie może wstępnie załadować biblioteki przechwytywania i wywołuje domyślną libc connect().

Czy to oczekiwane zachowanie? Jeśli tak, jaki może być powód wyłączenia LD_PRELOAD?

Czy istnieje jakieś ulepszenie lub metoda, której można użyć do pomyślnego wstępnego załadowania biblioteki z włączonymi funkcjami.

+2

Zobacz [to pytanie] (http://stackoverflow.com/questions/9843178/linux-capabilities-setcap-seems-to-disable-ld-library-path) dla odpowiedzi. – scai

+1

Możesz napisać program otoki dla docelowego pliku binarnego. Będzie mniej więcej musiało być ustawione na root. Spowoduje to rozwidlenie procesu potomnego, a następnie wykonanie docelowego pliku binarnego (z zestawem 'LD_PRELOAD'); docelowy plik binarny nie ma ustawionych żadnych możliwości plików. Twoja biblioteka wstępnego ładowania komunikuje się następnie z procesem podrzędnym (za pośrednictwem np. Pary gniazd, powiedzmy, fd 3), z procesem podrzędnym, przyznając niezbędne możliwości procesowi docelowemu, a następnie kończąc (oraz bibliotekę wstępnego ładowania zbierającego dziecko). Daj mi znać, jeśli chcesz mieć przykład. –

+0

@NominalAnimal Cieszę się, że możesz pokazać mi przykład. –

Odpowiedz

4

Podobnie jak odpowiedział Oliver Matthews, LD_PRELOAD jest wyłączone zarówno dla plików binarnych Setuid, jak i dla plików binarnych posiadających możliwości plików, ze względów bezpieczeństwa.

wstępnego ładowania biblioteki jednocześnie umożliwiając możliwości plików, masz dwie opcje:

  1. Ustaw fabrycznie biblioteka setuid korzeń

    (Linux dynamiczny linker ld.so ma wczytywać biblioteki nawet setuid/plików -capability obsługą plików binarnych, jeśli biblioteki są root i oznaczony setuid.)

  2. Użyj setuid korzeniowy opakowanie

    Opakowanie uzyskuje pełne uprawnienia roota (zarówno rzeczywisty, jak i efektywny identyfikator użytkownika i grupy zero) i przechowuje oryginalny rzeczywisty identyfikator użytkownika i grupy do np. Zmienne środowiska).

    Wstępnie załadowana biblioteka ma konstruktor, np.

    static void my_library_init(void) __attribute__((constructor)); 
    static void my_library_init(void) 
    { 
        /* ... */ 
    } 
    

    który jest automatycznie prowadzony przed main() (ale może po innych konstruktorów w innych bibliotekach fabrycznie lub w bibliotekach że zainstalowane fabrycznie biblioteki zależą).

    Ten konstruktor uzyskuje pożądane właściwości, wyznaczone za pomocą zmiennych środowiskowych (getenv(), cap_from_text()) lub sam plik wykonywalny pliku binarnego (cap_from_file("/proc/self/exe")).

    Konstruktor musi tymczasowo użyć prctl(PR_SET_KEEPCAPS, 1) zachować możliwości nad zmianą tożsamości i zachować CAP_SETUID i CAP_SETGID możliwości, aby móc zmienić tożsamość od nasady do użytkownika i grupy określonej w zmiennych środowiskowych, przed ograniczając się do ostatecznej możliwości zestaw.

Obie opcje mają oczywiste względy bezpieczeństwa. Zalecam sprawdzenie poprawności (i wyczyszczenie LD_PRELOAD) we wstępnie załadowanym konstruktorze biblioteki. Jeśli cokolwiek wydaje się podejrzane, użyj _exit(), aby natychmiast przerwać proces.

Ogólnie rzecz biorąc, zalecam pierwszą opcję prostoty (zarówno problemy z implementacją, jak i bezpieczeństwem), ale jeśli jest jakiś powód, którego nie można użyć, mogę dostarczyć kod koncepcyjny dla drugiego przypadku. (Sprawdziłem obie opcje działa na systemie Ubuntu 12.04.2 LTS z jądrem x86-64 w wersji 3.8.0-27, używając systemu plików ext4.)

Mam nadzieję, że to pomoże.

+0

Opcja 1, ustawienie opcji setuid root na preload biblioteki pomogło mi w wstępnym ładowaniu. Jednak gdy ustawiam programowalność zdolności, która ma kilka zmian granic po 'exec',' prctl (PR_SET_KEEPCAPS, 1L) 'nie zachował możliwości. Moje wykonanie programu testowego zostało uruchomione przy użyciu 'strace/gdb./Executable', które nie zachowało możliwości i odniosło sukces, gdy działało jako'./Executable'. Dzieje się tak dlatego, że ma on przejście od powłoki do 'strace/gdb', po którym następuje'./Executable'. Chciałbym wiedzieć, co powoduje, że możliwości nie zachowują się ponad zmianami granic. –

+0

@SunEric: 'prctl (PR_SET_KEEPCAPS, 1L)' działa tylko dla następnego 'exec *()', ponieważ 'PR_SET_KEEPCAPS' jest zawsze resetowane do 0 po wywołaniu' exec *() '. Jest to wspomniane na stronie man 2 prctl. –

4

Tak, ze względów bezpieczeństwa (patrz man sudo).

Będziesz musiał obejść go, otwarcie biblioteki z wewnątrz kodu na początku main() przy użyciu dlopen (lub przez opakowanie główne lub podobne).

+0

Popraw mnie, jeśli nie rozumiem nic o 'ld_preload': biblioteka obiektów współdzielonych jest wstępnie ładowana, zanim jakakolwiek standardowa biblioteka funkcjonuje. Jeśli jest to prawdą, wymagana biblioteka jest wstępnie załadowana, a następnie 'libc.so'; Jak zasugerowałeś otwarcie biblioteki używając 'dlopen' w aplikacji' main() ', czy symbole nie są już rozwiązane przez preinstalowaną bibliotekę lub bibliotekę libc przed uruchomieniem' dlopen'? –