Co powstrzymuje program asemblera przed awarią systemu operacyjnego? [Zamknięte]

18

Przede wszystkim jestem początkujący, więc jeśli to pytanie brzmi głupio, proszę wskazać błędne założenia.

Z tego, co rozumiem, zadaniem systemu operacyjnego jest zarządzanie sprzętem i oprogramowaniem działającym w systemie operacyjnym. Z tego, co rozumiem, programy montażowe pozwalają niemal bezpośrednio kontrolować sprzęt. W programie asemblera można odczytywać i zapisywać dane w rejestrach oraz odczytywać i zapisywać dane w pamięci RAM.

Biorąc pod uwagę swobodę bałagania się w rejestrach i pamięci RAM, czy nie byłoby możliwe, aby programy asemblacyjne wpływały na system operacyjny? Załóżmy, że system operacyjny używa rejestru A do przechowywania ważnych informacji i załóżmy, że w tym systemie operacyjnym uruchamiam złożony program. Jeśli program pomyślnie zapisuje śmieci w rejestrze A, na pewno wpłynie to na system operacyjny.

Pytania:

  1. Czy można zepsuć rejestr A w sposób opisany powyżej?

  2. Jeśli nie, co powstrzymuje programy asemblujące od modyfikowania rejestrów używanych przez system operacyjny?

Strumień
źródło
13
inteligentni programiści ...
Tony Stewart Sunnyskyguy EE75
Obecnie istnieje wiele architektur komputerowych, a także opracowano wiele systemów operacyjnych. Jaką architekturę / system operacyjny masz na myśli? W niektórych (starych) architekturach nie było możliwości zatrzymania programu przed uruchomieniem, to prawda. Ale nowoczesny sprzęt / system operacyjny ma wbudowane narzędzia sprzętowe, które dają tylko część pamięci dla programu w trybie „normalnym” (nie superużytkownika) i nie może uzyskać dostępu do pamięci poza tym limitem. Rejestry są bezpłatne, ponieważ system operacyjny nie przechowuje żadnych użytecznych informacji w rejestrach, tylko w pamięci / na dysku.
cyclone125 11.03.19
2
W mikroprocesorze program działa w „trybie użytkownika”, systemy operacyjne działają w „trybie systemu”. Jeśli program trybu użytkownika wykona na przykład instrukcję zatrzymania, maszyna nie zatrzyma się. Zatrzymanie byłoby uwięzione, a system operacyjny wywołany. Jeśli chodzi o pamięć RAM, system operacyjny skonfigurowałby środowisko dla programu trybu użytkownika, aby za pośrednictwem sprzętu do zarządzania pamięcią program użytkownika postrzegał jako adres pamięci RAM X tak naprawdę nie byłby adresem pamięci RAM X.
George White
1
@flux Zaktualizowałem swój komentarz. Odpowiedź brzmiałaby: nie ma „ogólnej” odpowiedzi na twoje pytanie, ponieważ istnieją / były różne architektury komputerów / systemy operacyjne. Może być na różne sposoby.
cyclone125 11.03.19
2
... Dawno temu pisałem w surowym kodzie maszynowym. Hej !!! :-)
Russell McMahon

Odpowiedzi:

33

Ostatecznie wszystkie programy są kodami maszynowymi, niezależnie od tego, czy językiem źródłowym był asembler czy język wysokiego poziomu.

Ważną rzeczą jest to, że istnieją mechanizmy sprzętowe , które ograniczają możliwości danego procesu, w tym „mieszanie się” z rejestrami, które mogą wpływać na inne programy lub sam system operacyjny.

Zaczęło się od prostego rozróżnienia między trybami działania „użytkownik” i „nadzorca” i od tego czasu przekształciło się w architekturę bezpieczeństwa z wieloma „pierścieniami” przywilejów.


Oto bardzo ogólny przykład, aby uczynić go nieco bardziej konkretnym:

  • W „trybie użytkownika” proces nie może uzyskać dostępu do pamięci, która nie została przypisana do jego identyfikatora procesu. Pamięć przypisana do innych procesów i sam system operacyjny jest zablokowany. Obejmuje to wartości rejestrów używanych przez te inne procesy. Jest to wymuszane przez sprzęt MMU.

  • Dlatego w „trybie użytkownika” proces nie może uzyskać dostępu do rejestrów kontrolnych MMU.

  • I oczywiście w „trybie użytkownika” proces nie może zmienić trybu na „tryb nadzorcy”, chyba że za pomocą bardzo dobrze zdefiniowanego mechanizmu, który wymaga wywołania funkcji systemu operacyjnego.

System operacyjny przejmie kontrolę, jeśli proces spróbuje złamać którąkolwiek z tych reguł. Kiedy to się stanie, system operacyjny może po prostu zatrzymać proces obrażania, nigdy nie wykonując żadnych instrukcji.

Dave Tweed
źródło
2
Jeśli dobrze rozumiem, mówisz: Niektóre procesory mają „tryb użytkownika” i „tryb nadzorcy”. System operacyjny działa w „trybie nadzorcy” i przełącza procesor w „tryb użytkownika”, aby uruchomić mój fikcyjny program asemblacyjny. W „trybie użytkownika” istnieją rejestry i adresy RAM, do których program asemblujący nie może uzyskać dostępu z powodu celowego zaprojektowania sprzętu.
Flux
3
Zasadniczo ta odpowiedź opisuje nowoczesne architektury „podobne do i386” z MMU i trybem chronionym. Ale prawdą jest, że istnieje wiele starych (i8080, MOS 6502 itp.), A także współczesnych, prostszych (AVR, ARM Cortex-M itp.) Architektur, które nie mają tych funkcji i jeśli używany jest jakiś system operacyjny (np. Stary CP / M, nowoczesne FreeRTOS, ChibiOS itp.) Nic nie może powstrzymać programu przed tym, co robi.
cyclone125
2
@Flux Architektury i386 (i nowsze) dostarczają szczegółowych informacji do nauki. Architektura x86 ma nie tylko adresy pamięci, które można chronić, ale także adresy I / O. (Istnieją różne instrukcje dotyczące dostępu do pamięci i dostępu do wejść / wyjść.) W i386 + istnieją trzy adresy pamięci. Adres oparty na segmentach / selektorach wykorzystuje rejestr selektorów, który odwołuje się do wpisu tabeli (GDT lub LDT), aby zamapować parę na pojedynczy 32-bitowy adres liniowy. Tabele stronicowania następnie tłumaczą 32-bitowy adres liniowy na 36-bitowy adres fizyczny (P-II.) Ochrona istnieje na obu etapach translacji.
jonk
4
@flux Twoje streszczenie jest poprawne. Program w chronionym systemie pamięci z odpowiednim systemem wielozadaniowym nie powinien mieć możliwości awarii systemu przy pomocy jakiegokolwiek strumienia instrukcji. Nawet nieprawidłowe - trafiają do specjalnego handlera.
pjc50,
Chociaż istnieje wiele pierścieni (przynajmniej w x86), bardzo, bardzo rzadko zdarza się, że używa się więcej niż dwóch pierścieni.
las
10

Wiele wielozadaniowych systemów operacyjnych korzysta ze struktury danych zwanej Blokiem Kontroli Procesu (PCB) w celu rozwiązania problemu z nadpisywaniem rejestru. Po uruchomieniu kodu system operacyjny tworzy nowy proces, aby go śledzić. Płytka drukowana zawiera informacje o twoim procesie i przestrzeni przydzielonej do przechowywania zawartości rejestru. Powiedzmy, że proces A jest aktualnie uruchomiony na procesorze, a Twój kod jest w trakcie procesu B. Co się dzieje, gdy uruchamiasz swój kod, dzieje się tak:

  1. Dane stanu procesu A (zawartość rejestru, licznik programu itp.) Są kopiowane na jego płytkę drukowaną.

  2. Dane stanu procesu B są kopiowane z jego PCB do rejestrów CPU

  3. Proces B działa na procesorze, dopóki nie zakończy się lub nie zostanie zablokowany

  4. Dane stanu procesu B są kopiowane z powrotem na jego płytkę drukowaną

  5. Dane stanu procesu A są kopiowane z powrotem do procesora i kontynuuje działanie

Jeśli system operacyjny działa jako proces A, możesz zobaczyć, jak zapisywanie jego rejestrów przed uruchomieniem programu, a następnie kopiowanie ich z powrotem do procesora po zakończeniu programu zapobiega programom użytkownika mylącym się z tym, co dzieje się w innych procesach.

Aby uniknąć zapisywania danych użytkownika przez system operacyjny w pamięci, większość platform korzysta z segmentacji pamięci. Zasadniczo za pomocą pamięci wirtualnej przestrzeń adresowa, którą widzi proces, może być odwzorowana na dowolny dowolny zakres adresów fizycznych. Dopóki przestrzenie pamięci fizycznej procesów nie nakładają się, jeden proces nie może zastąpić danych innego.

Oczywiście różne systemy operacyjne działają inaczej, więc nie będzie to miało zastosowania w każdym przypadku. Ponadto na większości platform procesy systemu operacyjnego działają w innym trybie niż procesy użytkownika i są tam pewne zawiłości.

jtst
źródło
4

Zależy od platformy, o której mówisz.

  • Na bardziej podstawowym procesorze procesor wykonuje tylko instrukcje, które program nakazuje mu wykonać.

  • W bardziej wyrafinowanym procesorze dostępne są (przynajmniej) dwa tryby. W jednym trybie procesor robi wszystko, co program mu nakazuje. W drugim trybie sam procesor odmawia wykonania niektórych instrukcji.

Co powstrzymuje program przed awarią całego systemu? W przypadku pierwszego typu procesora odpowiedź brzmi „nic”. W przypadku podstawowego procesora pojedynczy nieuczciwy program może rzeczywiście spowodować awarię całego systemu. Wszystkie wczesne 8-bitowe komputery domowe i wiele 16-bitowych należą do tej kategorii.

Na nowoczesnym komputerze procesor ma sprzęt „ochronny”. Zasadniczo system operacyjny działa w specjalnym trybie, który pozwala mu robić wszystko, podczas gdy normalne programy działają w trybie, w którym procesor zezwala tylko na określone działania (w zależności od ustawień skonfigurowanych przez system operacyjny na procesorze). Rzeczy takie jak dostęp tylko do niektórych rejestrów lub dostęp do określonych zakresów pamięci.

Oczywiście zezwolenie jednemu nieuczciwemu programowi na awarię całego systemu jest złe. (Istnieją również poważne konsekwencje dla bezpieczeństwa, gdy zezwalamy nieuczciwemu programowi na dostęp do dowolnych danych.) Aby tego uniknąć, potrzebujesz dwóch rzeczy:

  1. Procesor, który faktycznie ma sprzęt zabezpieczający (tzn. Można go skonfigurować tak, aby odmawiał wykonania niektórych instrukcji).

  2. System operacyjny, który faktycznie korzysta z tych funkcji, aby się chronić. (Nie ma sensu mieć układu z obwodem ochronnym, jeśli system operacyjny nigdy go nie używa!)

Prawie każdy nowoczesny system operacyjny na pulpicie, który możesz nazwać (Windows, Linux, Mac OS, BSD ...), to system operacyjny w trybie chronionym działający na procesorze ze sprzętem ochronnym. Jeśli tworzysz oprogramowanie wbudowane w 8-bitowy mikrokontroler, prawdopodobnie nie ma on żadnego sprzętu ochronnego. (Lub dowolny system operacyjny, jeśli o to chodzi ...)

MathematicalOrchid
źródło
1

P: Co powstrzymuje program asemblera przed awarią systemu operacyjnego?

A. Nic.

Jednak wielu bardzo sprytnych programistów przez lata bardzo się starało, aby było to coraz trudniejsze. Niestety, dla każdego sprytnego programisty jest wielu, wielu innych, którzy między nimi są bardziej kreatywni, ambitni, a czasem po prostu więcej szczęścia niż sprytni. Za każdym razem, gdy sprytny programista mówi, że nikt nie powinien, nie chciałby lub nie mógłby czegoś zrobić, ktoś znajdzie sposób, aby to zrobić. Microsoft Windows (jako przykład) istnieje od prawie 35 lat, a my wciąż mamy BSoD (Blue Screens of Death), które są tylko instrukcjami, które spowodowały awarię systemu operacyjnego.

Zacznijmy od małej terminologii. Wszystko, co działa na komputerze, robi to w kodzie maszynowym. Bit odczytujący naciśnięcia klawiszy lub ruch wskaźnika myszy, bit zmieniający kolor piksela na ekranie lub odczytujący bajt z pliku oraz bit, który oblicza, czy kula trafiła w złego faceta, czy bit decydujący jeśli wniosek o kartę kredytową zostanie zaakceptowany, wszystkie są wykonywane jako sekwencja instrukcji kodu maszynowego. Niektóre zadania są tak powszechne i wykonywane tak często, że sensowne jest zebranie instrukcji wymaganych do ich wykonania i umożliwienie wszystkim korzystania z tego zestawu. Pęczek tych zadań, które pozwalają lub pomagają innym w korzystaniu z komputera, zwykle nazywa się systemem operacyjnym, ale nic nie różni się między nimi a innymi programami. Wszystkie są tylko sekwencjami instrukcji kodu maszynowego.

Co sprawia, że ​​systemy operacyjne są bardziej skomplikowane (a zatem podatne na awarie), to fakt, że muszą one uwzględniać rzeczy, o których zwykle nie trzeba myśleć. Weź przykład najprostszej pracy. Chcę napisać wiadomość na końcu pliku. W języku wysokiego poziomu napisałbyś coś takiego:

  with open("myFile.txt", "w+") as f:
      # do some really clever things
      f.write("Goodbye cruel world!")

Zignorujmy wszystkie szczegóły dotyczące dostępu do stanów fizycznych i ich zmiany lub ich interpretacji jako bitów i bajtów lub sposobu przesyłania tych bajtów do iz pamięci i procesora, i ufaj, że wszystko obsługiwane przez programy dostarczane przez system operacyjny za kulisami. Zastanówmy się, jak dołączyć na końcu pliku. 1) Dowiedz się, gdzie jest koniec pliku, 2) napisz coś w tej pozycji. Co może pójść nie tak? Właściwie całkiem sporo. Zastanów się, co jeszcze dzieje się na komputerze, gdy robisz sprytne rzeczy. Jeśli cokolwiek innego zrobione przez kogoś innego (w tym sam system operacyjny) w jakikolwiek sposób zmieni plik, nad którym pracujesz, to ta naprawdę prosta praca nagle staje się o wiele bardziej skomplikowana. Plik jest dłuższy, plik jest krótszy. Pliku już nie ma. Dysk jest pełny,

Paul Smith
źródło