Czy możliwe jest odczytanie pamięci z innego programu poprzez przydzielenie całej pustej przestrzeni w systemie?


26

Teoretycznie, jeśli miałbym zbudować program, który przydzieliłby całą nieużywaną pamięć w systemie i nadal żądałby coraz większej ilości pamięci, ponieważ inne aplikacje zwalniały pamięć, której już nie potrzebują, czy byłoby możliwe odczytanie ostatnio zwolnionej pamięci z innych aplikacji ? Czy jest to w jakiś sposób chronione przez nowoczesny system operacyjny?

Nie mam na to praktycznego zastosowania, jestem po prostu ciekawy. Zdaję sobie sprawę, że istnieją pewne problemy z przydzielaniem „całej dostępnej pamięci” w prawdziwym życiu.

Edycja: Aby to wyjaśnić, pytam konkretnie o pamięć „Zwolnioną”, a nie dostęp do pamięci, która jest obecnie przydzielana przez inną aplikację.

Odpowiedzi:


23

Nie, ponieważ dobre jądro usuwa zawartość pamięci, zanim zostanie wydana procesowi w celu ochrony przed dokładnie takim atakiem, jaki proponujesz.

W systemach Unixy pamięć jest przydzielana procesom poprzez rozszerzenie tak zwanego przerwania programu , który jest limitem praktycznie adresowalnej przestrzeni, którą proces może wykorzystać. Proces informuje jądro, że chce rozszerzyć swoją przestrzeń adresowalną, a jądro pozwoli na to, jeśli pamięć jest dostępna lub jeśli połączenie nie powiedzie się. (Nazwa brk()wywołania systemowego pochodzi od tej koncepcji).

W praktyce duże bloki zwalnianej pamięci często nie stykają się z przerwaniem programu, co byłoby wymagane, aby proces zwrócił pamięć do jądra poprzez zmniejszenie przerwania programu. Wszystko to oczywiście zależy od implementacji malloc()i free(). Jeśli masz dostępne źródła, powiedzą ci, czy pamięć została kiedykolwiek zwrócona.

Nie ma to wpływu na bezpieczeństwo malloc()nie inicjowania pamięci, ponieważ wszystko, co uzyskało, brk()zostanie wyszorowane, a wszystko, co poprzednio free()zostało napisane przez ten sam proces.


19

Tak, teoretycznie możliwe jest odczytanie zwolnionej pamięci innego procesu. Było to przyczyną wielu ataków eskalacji uprawnień w ciągu dnia. Z tego powodu obecnie systemy operacyjne skutecznie zerują pamięć, jeśli została wcześniej przydzielona przez inny proces. Powodem, dla którego nie zawsze widzisz zerowaną pamięć, jest to, że bardziej efektywne jest nie zerowanie pamięci, jeśli wcześniej została przydzielona przez ten sam proces. System operacyjny próbuje przywrócić strony pamięci do tego samego procesu, jeśli to możliwe.


1
„Tak, ale nie” to „nie”. @Blrfl ma rację.
Ross Patterson

4
@RossPatterson: Z teoretycznego punktu widzenia Karl ma więcej racji niż ja. Praktyczna rzeczywistość jest taka, że ​​główne systemy operacyjne zamknęły tę dziurę przed laty.
Blrfl,

@Blrfl Zrozumiano. Ale „lata temu” miały miejsce pod koniec lat 60. XX wieku, kiedy to po raz pierwszy wprowadzono systemy przywoławcze i pamięć wirtualną. Z pewnością do czasu Multics, VM / 370 i OS / VS. Nieobecne błędy, nie było to możliwe w pamięci większości praktykujących programistów.
Ross Patterson

The reason you don't always see zeroed out memory is because it is more efficient not to zero out the memory if it was previously allocated by the same process Widzę tutaj pewną niespójność. Miałeś na myśli „ten sam plik wykonywalny”? Jak sprawdza się, czy nie zerować - ścieżką dysku?
jakub.g

1
Chyba coś mi umknęło. Dlaczego więc, kiedy kompiluję i uruchamiam jakiś program C ++ z, powiedzmy, niezainicjowanymi liczbami całkowitymi, nie są one równe 0, gdy czytam te zmienne?
jakub.g

2

W grę wchodzi kilka warstw, które wpływają na odpowiedź.

Jeśli przyjmiesz nowoczesny system operacyjny pamięci wirtualnej, nie będziesz w stanie zobaczyć pozostałości danych z innych procesów na przydzielanych stronach.

Kiedy proces jest ładowany po raz pierwszy, tablica stron jest ładowana i potencjalnie ramki rzeczywistej pamięci są przydzielane do tych stron. Tabela stron lub tabela uzupełniająca zawiera przynajmniej mapę całej pamięci, którą proces może przydzielić. Tutaj również ustawia się początkową przerwę procesu, o której mowa powyżej.

Podczas gdy malloc () może, jeśli proces jest dozwolony, zmienić przerwanie procesu, dodając więcej stron do tabeli strony procesów (strony dodatkowej) w celu spełnienia żądania, miejscem, w którym jeden proces może „uzyskać inny”, jest dane dolna warstwa pamięci rzeczywistej.

W obu tych scenariuszach nowoczesny system operacyjny korzystający ze stronicowania na żądanie lub leniwego przydzielania jeszcze nie przydziela pamięci fizycznej (ramek). System operacyjny po prostu „robi notatki” na temat tego, która pamięć wirtualna dla tego procesu jest uważana za prawidłową. Rzeczywista pamięć jest przydzielana tylko w razie potrzeby.

Pamięć fizyczna lub ramki są przydzielane do procesu, gdy strona wirtualna jest realizowana i odwzorowywana na tabelę stron procesów W tym miejscu istnieje możliwość ujawnienia danych. Dzieje się tak podczas błędu strony. Narażenie wynika z faktu, że poprzedni proces mógł używać tej samej ramki, a jego dane zostały porzucone lub zamienione, aby zrobić miejsce dla bieżącego żądania pamięci fizycznej. System operacyjny musi zachować ostrożność, aby upewnić się, że dane procesów żądających zostały odpowiednio zamienione lub ramka została wyczyszczona (wyzerowana) przed wznowieniem procesu. Jest to również wspomniane powyżej jako „stary, ale rozwiązany” problem.

To sprawia, że ​​nie ma znaczenia, czy pamięć innych procesów została „zwolniona”, czy nie. Kolejna „zwolniona” pamięć procesów nadal znajduje się na stronach przypisanych do tego procesu i zwykle nie jest odwzorowywana aż do zakończenia procesu, ponieważ zostaną one po prostu zamienione, gdy pamięć się wyczerpie lub zostaną w inny sposób eksmitowane. malloc () i free () zarządzają pamięcią wirtualną przypisaną do procesu na poziomie (użytkownika).

W twoim pytaniu twój proces nadal żąda coraz więcej pamięci, teoretycznie, wypychając wszystkie inne procesy z pamięci. W rzeczywistości istnieją strategie alokacji ramek - globalne i lokalne - które również mogą mieć wpływ na odpowiedź. Jest równie prawdopodobne, że proces wymusi zwolnienie pamięci z własnych stron, zanim będzie możliwe przekroczenie systemu operacyjnego i wszystkich innych procesów. Chociaż wykracza to poza początkowe pytanie.

Wszystko to jest dyskusyjne w systemie takim jak MS-DOS. MS-DOS (i inne, prostsze systemy) nie używają pamięci wirtualnej (same w sobie) i można łatwo szturchać i naciskać na inne „procesy” danych.

Dobrymi odniesieniami, które mogą być łatwiejsze do zrozumienia niż kod źródłowy Linuksa, byłby dobry podręcznik dotyczący systemów operacyjnych, Koncepcje systemów operacyjnych Silberscatz, Gavin i Gange lub Projektowanie systemów operacyjnych Andrew Tanenbaum. Również coś takiego jak Nachos z Berkeley lub Pintos ze Stanford to małe systemy operacyjne zbudowane do nauki i zawierające w sobie te same pomysły.


0

Próbowałem tego na Ubuntu 16.04 miesięcy temu. Tak jak powiedział 0xACE, nowoczesny system operacyjny przydziela wirtualną stronę zerową po wywołaniu malloc (). Ale jeśli nic nie napiszesz do przydzielonego bufora, nie zostanie on zamapowany w pamięci fizycznej (to znaczy zasada kopiuj przy zapisie), dlatego zawsze będziesz czytać zera z „niezainicjowanego” bloku. Być może istnieje jakiś wbudowany system operacyjny skompilowany z opcją „CONFIG_MMAP_ALLOW_UNITIALIZED” w celu uzyskania lepszej wydajności, w tym przypadku możesz uzyskać to, czego oczekujesz.


-1

Nie, nie pozwoli to innemu programowi na odczytanie pamięci innej osoby dzięki magii stronicowania . W ten sposób całkowite wykorzystanie pamięci może przekroczyć fizyczny RAM, rozładowując jego część na dysk twardy.

Ponadto maksymalna pamięć, jaką proces może przydzielić, jest arbitralnie ograniczona przez system operacyjny (do 4 koncertów dla architektury 32-bitowej), po czym następne allocwywołanie zwróci błąd braku pamięci.


Czy nie istnieją interfejsy API specyficzne dla platformy, które mogą to obejść? Naprawdę nie wiem, ale nie byłbym zaskoczony (na przykład Linux pozwala zapobiec przenoszeniu strony przez system operacyjny z pamięci fizycznej mlock).

Jeśli są 4 GB pamięci RAM, a stronicowanie jest ograniczone do 8 GB, co się stanie, jeśli aplikacja zażąda 12 GB (na x64)?
Arseni Mourzenko

wtedy wywołania systemowe powinny zwracać błąd, gdy pozostanie za mało wolnej pamięci, albo komputer po prostu zatrzyma się, gdy nie zostanie już nic ...
maniak ratchet

4
Nie pyta o czytanie pamięci innej osoby, ale raczej czytanie jej ZWOLNIONEJ pamięci. Ta sekcja pamięci RAM jest obecnie wolna i ... nie sądzę ... że schematy stronicowania zerują pamięć po uwolnieniu. Tak więc program przydzieli blok pamięci i przeanalizuje niezainicjowane dane, które już tam są.
Philip

@ philip poprawnie, pytam konkretnie o zwolnioną pamięć.
ConditionRacer
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.