Privilégiumszintek

A processzor szegmens védelmi mechanizmusa 4 privilégium szintet különböztet meg, 0-tól, 3-ig számozva. A legnagyobb számmal jelzett privilégium szint a legkevesebb jogot jelenti. Az alábbi ábra bemutatja, hogy hogyan értelmezhetőek ezek a privilégium szintek, védelmi gyűrűként. A középső gyűrű (fenntartott a legprivilegizáltabb kód, adat és verem részére) használt a kritikus szoftver úgy, mint az operációsrendszer kernelének szegmenseinek tárolására. A külső gyűrűk kevésbé kritikus szoftver elhelyezésére használhatóak. (Az olyan operációsrendszerek melyek nem kívánják kihasználni a teljes hardveres védelmet elég 2 privilégium szintet használniuk a 4-ből. Erre a javasolt privilégium szintek a 0-s a kernelnek és a 3-as az egyéb illetve felhasználói programoknak. A mai elterjedt operációs rendszerek legritkább esetben használják ki mind a 4 privilégium szintet: Windows 98, Windows NT két privilégium szint, OS/2 és Linux három (0,1,3).)

A processzor arra használja a privilégium szinteket, hogy megakadályozza a programot vagy taszkot abban, hogy nála számmal alacsonyabb privilégium szinten (az-az privilegizáltabb szinten) dolgozzon. Ez alól kivételt képez az előre megtervezett, kontrollált körülmények közötti alacsonyabb privilégium szintű szegmensek elérése (tehát csak bizonyos módon, kapukon keresztül érhetőek el az aktuálisnál privilegizáltabb szegmensek). Amikor a processzor privilégium szint sértést észlel általános védelmi hiba kivételt (#GP) generál.

A privilégium szint ellenőrzésére a kód- és adatszegmensek között a processzor az alábbi három típusú privilégium szintet különbözteti meg:

  • Aktuális privilégium szint (Current privilege level - CPL, ezután csak: CPL). A CPL az éppen futtatott program vagy taszk privilégium szintjét jelenti. Ez a CS és SS regiszter 0. és 1. bitei tárolják. Általában a privilégium szint megegyezik annak a kódszegmensnek a privilégium szintjével, melyről az utasítások éppen végrehajtódnak. A processzor akkor változtatja meg a CPL-t, amikor a végrehajtás egy másik privilégium szintű kódszegmensre kerül. A CPL-t különböző módon kezeli a processzor illeszkedő, illetve nem illeszkedő kódszegmensek esetén. Illeszkedő (conforming) kódszegmens bármely privilégium szintről elérhető, mely egyenlő vagy számmal nagyobb (kevésbé privilegizált) privilégium szintű, mint az illeszkedő kódszegmens DPL-je. Szintén a CPL nem változik, ha processzor az aktuális CPL-től eltérő privilégium szintű illeszkedő kódszegmenst hív meg.
  • Leíró privilégium szint (Descriptor privilege level - DPL, ezután csak: DPL). A DPL egy szegmens vagy kapu privilégium szintjét adja meg. Ez a szegmens vagy kapu leíró DPL mezőjében van tárolva. Amikor az éppen futó kódszegmens megpróbál hozzáférni egy szegmenshez vagy kapuhoz akkor annak DPL-jét összehasonlítja a CPL-lel és az RPL-lel a processzor (részletesebben alább). A DPL különböző módon értelmezett a leíró típustól függően:
  • Adatszegmens: A DPL megmutatja azt a számmal jelzett legnagyobb privilégium szintet, amiről a szegmens elérése még megengedett (tehát ezen számmal kisebb egyenlőnek kell lennie a CPL-nek). Pl.: A DPL egy adatszegmens privilégium szintjét jelenti, melynek értéke legyen most 1. Így ehhez a szegmenshez alapértelmezés szerint csak a 0, vagy 1-es privilégium szinten futó programok (CPL = 0, 1) férhetnek hozzá.
  • Nem illeszkedő kódszegmensek használata call-kapu nélkül: A DPL megadja azt a privilégium szintet, mellyel a programnak vagy taszknak rendelkeznie kell ahhoz, hogy elérhesse ezt a szegmenst. Pl.: ha a DPL-je a nem illeszkedő kódszegmensnek 0, akkor csak a 0 CPL-en futó programok vagy taszkok érhetik el ezt a szegmenst.
  • Call-kapu (Call gate): A DPL megmutatja azt a számmal jelzett legnagyobb privilégium szintet, amivel az éppen futó program vagy taszk még elérheti a call-kaput. (Hasonló a hozzáférési szabály az adatszegmensnél elmondottakhoz.)
  • Illeszkedő és nem illeszkedő kódszegmens elérése call-kapun keresztül: A DPL megadja azt a számmal jelzett legkisebb privilégium szintet, melynél a program vagy taszknak még megengedett a szegmens elérése. Pl.: ha egy illeszkedő kódszegmens DPL-je 2, akkor a CPL 0, vagy 1 szinten futó programok nem érhetik el.
  • TSS: A DPL megmutatja azt a számmal jelzett legnagyobb privilégium szintet, amivel az éppen futó program vagy taszk még elérheti a taszk kaput. (Hasonló a hozzáférési szabály az adatszegmensnél elmondottakhoz.)
  • Igényelt privilégium szint (Requested privilege level - RPL, ezután csak: RPL). Az RPL egy felülbíráló privilégium szint, mely a szegmens kiválasztókhoz rendelt. Ez a szegmens kiválasztók 0. és 1-es bitein helyezkednek el. A processzor ellenőrzi az RPL-t a CPL-lel együtt, hogy megállapítsa, engedélyezett -e a szegmenshez való hozzáférés. Még akkor is, ha szegmenst elérni kívánó programnak vagy taszknak meg van az elegendő jogosultsága a szegmens eléréséhez, a processzor akkor is letilthatja az elérést, ha az RPL nem megfelelő nagyságú privilégium ad (determinál). Ez az, ha a szegmens kiválasztó RPL-je számmal jelezve nagyobb, mint a CPL, akkor az RPL felülbírálja a CPL-t és oda-vissza. Az RPL használható arra, hogy biztosak lehessünk abban, hogy a privilegizált kód nem fér hozzá a felhasználói program nevében a kívánt szegmenshez; csak akkor, ha magának a programnak (az igénylőnek) is meg van arra a szegmensre a megfelelő jogosultsága. (Tehát egy kevésbé privilegizált program nem férhet hozzá egy privilegizáltabb, pl. az operációs rendszer kernel-ének segítségével a tőle eltiltott szegmensekhez alapesetben.) (Lásd a "A hívó hozzáférési jogainak vizsgálata (az ARPL utasítás)" részt az RPL részletesebb illetve tipikus használatának leírása végett.)

A privilégium szintek ellenőrzése a szegmens leíróra mutató szegmens kiválasztó (szegmens) regiszterbe töltésekor történik. Az adatszegmensek vizsgálata különbözik a kódszegmensek közötti végrehajtás átadási vizsgálattól, így az alábbi két külön részben tárgyaljuk.

A privilégium szint vizsgálat adatszegmensek hozzáférése esetén

Ahhoz, hogy hozzáférjünk az adatszegmenshez, a szegmens kiválasztót az adatszegmens (DS, ES, FG, vagy GS), vagy a veremszegmens regiszterbe kell tölteni (SS). (A szegmens regisztereknek a MOV, POP, LDS, LES, LFS, LGS, és LSS utasításokkal adhatunk értéket.) Mielőtt a processzor beletöltené az értéket a szegmens regiszterbe privilégium vizsgálatot készít, (lásd ábra) azáltal, hogy összehasonlítja az éppen futó program vagy taszk privilégium szintjét (a CPL-t), a szegmens kiválasztó által szolgáltatott RPL-t, és a szegmens leíró által szolgáltatott DPL-t (ez az a szegmens leíró, melyet a szegmens kiválasztó indexelt meg). A processzor a szegmens regiszterbe tölti a szegmens kiválasztót, ha a DPL számmal kifejezve nagyobb vagy egyenlő, mint a CPL és az RPL. Ellenkező esetben általános védelmi hiba generálódik (#GP) és a szegmens kiválasztó nem töltődik a regiszterbe.

Privilégium vizsgálat adat éléréskor

 

Az alábbi ábra négy rutint (mindegyik más kódszegmensben, rendre: A, B, C, és D) mutat be, s mindegyik más privilégium szinten helyezkedik el. Mind a négy rutin ugyanahhoz az adatszegmenshez kíván hozzáférni.

  • Az A kódszegmensben található rutin el tudja érni az E-vel jelölt adatszegmenst az E1 szegmens kiválasztóval, mert az A kódszegmens CPL-je, és az E1 szegmens kiválasztó RPL-je egyenlő az E adatszegmens DPL-jével.
  • A B kódszegmensben található rutin el tudja érni az E-vel jelölt adatszegmenst az E2 szegmens kiválasztóval, mert az A kódszegmens CPL-je, és az E2 szegmens kiválasztó RPL-je egyformán számmal jelezve kisebb (privilegizáltabb), mint az E adatszegmens DPL-je. A B kódszegmensbeli rutin szintén elérheti az E adatszegmenst az E1-gyel jelölt szegmens kiválasztóval.
  • A C kódszegmensben található rutin nem tudja elérni az E-vel jelölt adatszegmenst az E3 szegmens kiválasztóval (szaggatott vonal az ábrán), mert az C kódszegmens CPL-je, és az E3 szegmens kiválasztó RPL-je szám szerint nagyobb (kevésbé privilegizált), mint a E adatszegmens DPL-je. Még abban az esetben se érheti el a példánkbeli C rutin az E adatszegmenst ha az E1 vagy E2 szegmens kiválasztókat használná ugyanis igaz, hogy az RPL megfelelő értékű lenne, de még mindig nem férhetne a szegmenshez, hisz a CPL-je nem eléggé privilegizált (számmal: túl nagy a CPL értéke az eléréshez).

Példa adatszegmens elérésére, különböző privilégium szintekről

  • A D kódszegmensben található rutin elérhetné az E adatszegmenst hiszen a D kódszegmens CPL-je szám szerint kisebb, mint az adatszegmens DPL-je. Viszont az E3 szegmens kiválasztó RPL-je (az E3 szegmens kiválasztót használja a D kódszegmensbeli rutin az E adatszegmens elérésére példánkban), tehát az RPL szám szerint nagyobb, mint az adatszegmens DPL-je, így mégsem érheti el a kívánt szegmenst. Ha a D kódszegmensbeli rutin az E1 vagy E2 szegmens kiválasztókat használná a hozzáférés engedélyezett lenne.

Amint azt az előző példa bemutatta, a címezhető tartomány is úgy változik ahogy a program vagy taszk CPL-je változik. Amikor a CPL 0, akkor bármely privilégium szint adatszegmensei elérhetőek, ha CPL 1, akkor az 1 és 3 közötti privilégium szintek adatszegmensei érhetőek el, s ha a CPL 3, akkor csak a 3-as privilégium szinthez tarozó adatszegmensek érhetőek el.

A szegmens kiválasztó RPL-je mindig felülírhatja a program vagy taszk privilégium szint szerint címezhető tartományát. Ha az RPL-eket helyesen választjuk meg, számos hibát előzhetünk meg a véletlen (vagy szándékos) olyan szegmens kiválasztók használatából eredően, amikor kevésbé privilegizált kóddal akarunk privilegizáltabb adatszegmenshez hozzáférni.

Fontos megjegyezni, hogy az adatszegmens RPL-je a szoftver hatásköre alá tartozik, így nagy figyelemmel kell eljárni. Pl., egy felhasználói program 3-as CPL-en futva is beállíthatja az adatszegmens kiválasztó RPL-jét 0-ra. Így az RPL 0-ra állításával, csak a CPL vizsgálata történik meg. Lévén, hogy az RPL vizsgálata figyelmen kívül hagyódik szándékos védelem kikerülés történik, direkt hozzáférés történik az adatszegmenshez a privilégium szint vizsgálat megsértésével. Hogy megakadályozzuk ezen privilégium szint vizsgálat megsértéseket, a program vagy rutin megvizsgálhatja a hozzáférést, valahányszor adatszegmens kiválasztót kap egy másik rutintól vagy programtól. (Bővebben a "A hívó hozzáférési jogainak vizsgálata (az ARPL utasítás)" részben.)

Adat elérése a kódszegmensben

Bizonyos esetekben szükséges lehet, hogy a kódszegmensben elhelyezett adat struktúrákhoz hozzáférhessünk. Az alábbi lehetőségek vannak az adat kódszegmensbeli elérésére:

  • Töltsünk egy adatszegmens regiszterbe egy nem illeszkedő, olvasható kódszegmenst definiáló szegmens leírót.
  • Töltsünk egy adatszegmens regiszterbe egy illeszkedő, olvasható kódszegmenst definiáló szegmens leírót.
  • Használjunk egy kódszegmenst felülbíráló prefixumot (CS), hogy olvashassuk az olvashatóra állított kódszegmenst a már CS regiszterbe töltött szegmens kiválasztóval.

Az első mód hasonló az adatszegmensekhez való hozzáférésnél elmondottakhoz. A második mód mindig használható, hisz az illeszkedő kódszegmens privilégium szintje ténylegesen megegyezik a CPL-lel, a DPL-jére való tekintet nélkül. A harmadik mód is hasonlóan mindig használható, hisz a CS regiszter által kiválasztott (kód)szegmens DPL-je megegyezik a CPL-lel (lévén, hogy mindig ugyanaz ez a két szám).

Privilégium szint vizsgálat az SS regiszterbe töltéskor

A privilégium szint vizsgálat történik az SS regiszterbe történő veremszegmens leíró töltésekor is. Itt minden a veremszegmenshez csatlakozó privilégium szintnek meg kell egyeznie a CPL-lel; tehát a CPL-nek, a veremszegmens kiválasztó RPL-jének és a veremszegmens leíró DPL-jének is azonosaknak kell lenniük. Ha az RPL és a DPL nem egyenlő a CPL-lel, akkor általános védelmi hiba (#GP) generálódik.

Privilégium szint vizsgálat a kódszegmensek közötti program vezérlés átadásakor

Ahhoz, hogy egyik kódszegmensből a másikra irányítsuk a vezérlést, a cél kódszegmens szegmens kiválasztóját a kódszegmens regiszterbe, a CS-be kell tölteni. Ennek a regiszterbe töltési folyamat részeként a processzor megvizsgálja a cél kódszegmensének szegmens leíróját határ, típus, és privilégium szerint. Ha ezek a vizsgálatok sikeresen fejeződtek be, akkor a CS regiszterbe betöltött a kívánt szegmens kiválasztó, a programvezérlés átadódik az új kódszegmensre és a program futtatása az új kódszegmens EIP által mutatott első utasításán kezdődik.

A program vezérlésének átadása a JMP, CALL, RET, INT n utasításokkal történik, és az IRET utasítással a megszakítás és kivétel kezelésnél szükséges vezérlés átadás történik. A kivételek, megszakítások, és az IRET utasítás speciális eseteit itt nem részletezzük. Ezen fejezet csak a JMP, CALL és RET utasítások szerepére szorítkozik.

A JMP vagy CALL utasítások más kódszegmenseket hívhatnak az alábbi négy módon:

    A parancs operandusa tartalmazza a cél kódszegmens szegmens kiválasztóját

    A parancs operandusa egy call-kapu leíróra mutat, mely tartalmazza a cél kódszegmens szegmens kiválasztóját.

    A parancs operandusa egy TSS-re mutat, mely tartalmazza a cél kódszegmens szegmens kiválasztóját.

    A parancs operandusa egy taszk kapura mutat, mely egy TSS-re mutat, és ezen TSS tartalmazza a kívánt kódszegmens szegmens kiválasztóját.

Az alábbi részek leírják az első két vezérlés átadási módot.

Közvetlen hívás vagy ugrás kódszegmensre

A közeli JMP, CALL és RET utasítások az aktuális kódszegmensben irányítják át a vezérlést, így privilégium szint vizsgálat nem történik. A távoli JMP, CALL, és RET utasítások az aktuálisból egy másik kódszegmensbe irányítják a program vezérlését, így a processzor privilégium szint vizsgálatot végez.

Ha call-kapu nélkül irányítjuk át a vezérlést az aktuális szegmensről egy másikra, akkor a processzor négy féle privilégium információt vizsgál meg:

Privilégium szint vizsgálat kapu nélküli vezérlés átadáskor

    A CPL vizsgálata. (Itt a CPL az éppen futó, annak a kódszegmensnek a privilégium szintje, mely a hívást kezdeményezi. Ezen kódszegmens adott rutinja tartalmazza a hívást vagy ugrást.)

    A DPL a cél szegmens, azon szegmens leírója által szolgáltatott privilégium szint, mely tartalmazza a meghívott rutint.

    Az RPL a cél kódszegmens, szegmens kiválasztójában megadott privilégium szint. (A szegmens regiszter megfelelő bitei.)

    Az illeszkedő (C - conforming) flag a cél kódszegmens szegmens leírójában található, mely meghatározza, hogy illeszkedő (a C flag bekapcsolva) vagy nem illeszkedő (C flag kikapcsolva) a kódszegmens. (A "Kód- és adatszegmens leíró típusok" részben ezen flaggel részletesen foglalkoztunk.)

A CPL, RPL és DPL privilégium szintek összehasonlítása és értelmezése függ attól, hogy az illeszkedő (C) flag bekapcsolt -e. Az alábbi részeket ettől függően tárgyaljuk.

Nem illeszkedő kódszegmensekhez való hozzáférés

Amikor nem illeszkedő kódszegmensekhez férünk hozzá, a hívó kódszegmens CPL-jének egyenlőnek kell lennie a cél kódszegmens DPL-jével, különben a processzor általános védelmi hibát (#GP) generál.

Például, az alábbi ábrában a C kódszegmens egy nem illeszkedő kódszegmens. Így az A kódszegmensben lévő rutin meghívhatja a C kódszegmensbeli rutint a C1 szegmens kiválasztót használva, ugyanis azonos privilégium szinten vannak (Az A kódszegmens CPL-je egyenlő a C kódszegmens DPL-jével). Viszont a B kódszegmensbeli rutin nem hívhatja meg a C kódszegmensbeli rutint, se a C1, se a C2 szegmens kiválasztóval, ugyanis a két kódszegmens eltérő privilégium szinten van.

Példa illeszkedő és nem illeszkedő kódszegmensek elérése különböző privilégium szintekről

A nem illeszkedő kódszegmensre mutató szegmens kiválasztó RPL-jének korlátozott szerepe van a privilégium szint vizsgálatban. Az RPL-nek szám szerint kisebbnek vagy egyenlőnek kell lennie (privilegizáltabbnak), mint a hívó kódszegmens CPL-jének, hogy a vezérlés átirányítás megtörténhessen. Amint a fenti ábra mutatja a C1, C2 szegmens kiválasztók RPL-je lehet 0, 1, vagy 2 de semmiképpen sem lehet 3.

Amikor a nem illeszkedő kódszegmens szegmens kiválasztója a CS regiszterbe töltődik, a privilégium szintet tartalmazó mező nem változik meg, marad az eredeti CPL (a hívó rutin CPL-je). Ez igaz még akkor is, ha a szegmens kiválasztó RPL-je különbözik a CPL-től.

Illeszkedő kódszegmensek elérése

Amikor illeszkedő kódszegmenst kívánunk elérni, a hívó rutint tartalmazó kódszegmens CPL-je szám szerint nagyobb, vagy egyenlő (kevésbé privilegizált) lehet, mint a cél kódszegmens DPL-je. Ha a CPL kisebb, mint a DPL a processzor általános védelmi hibát generál. (A cél (hívott) kódszegmens szegmens kiválasztójának RPL-je nem vizsgált illeszkedő kódszegmens esetében.)

A fenti ábrában a D, egy illeszkedő kódszegmenst jelöl. Mind az A és B kódszegmensbeli rutin elérheti a D kódszegmens kívánt rutinját (akár a D1, vagy D2 szegmens kiválasztóval, külön-külön), ugyanis mind az A illetve B kódszegmensnek nagyobb vagy egyenlő a CPL-je, mint a meghívott illeszkedő kódszegmens DPL-je. Illeszkedő kódszegmensek esetén, a DPL azt a legalacsonyabb (számú) privilégium szintet jelenti, melyről a hívó még elérheti a rutint a kívánt kódszegmensben.

Megjegyzendő, hogy a D1 és D2 szegmens kiválasztók megegyeznek az RPL-jeiket kivéve. Annál fogva, hogy az RPL-ek nincsenek vizsgálva illeszkedő kódszegmens esetében, valójában a két szegmens kiválasztó felcserélhető.

Amikor a program vezérlés egy illeszkedő kódszegmensbe van irányítva, a CPL nem változik meg még akkor sem, ha a hívott kódszegmens DPL-je kisebb, mint a CPL. Ez az egyetlen olyan eset melyben eltérhet a CPL az aktuális kódszegmens DPL-jétől. Mivel a CPL nem változik meg, nem történik verem váltás (ugyanis minden CPL váltáskor annak a privilégium szintnek megfelelő vermet kell használni).

Illeszkedő szegmenseket, olyan kód modulokban használunk, mint például a matematikai könyvtárak, egyes kivétel kezelő rutinok, melyek támogatják ugyan az alkalmazást, de nincsen szükségük a védett rendszer-szolgáltatásokra. Ezen modulok részei ugyan az operációs rendszernek vagy futtatónak, ugyanakkor futtathatóak szám szerint nagyobb privilégium szintről (kevésbé privilegizált szintről), mint maga a rutin (pl. a kernel) privilégium szintje. A CPL-t a hívó kódszegmens privilégium szintjén tartva amikor az illeszkedő kódszegmensre váltunk, elkerülhető hogy a felhasználói program (a hívó program) hozzáférhessen a nem illeszkedő kódszegmensekhez. (Tehát, ha az illeszkedő kódszegmensre való ugráskor a CPL a hívott illeszkedő kódszegmens CPL-jét venné át, akkor lehetősége lenne a felhasználói programnak a nem illeszkedő kódszegmensek elérésére is, hiszen már egy privilegizáltabb CPL-re jutott az illeszkedő kódszegmensre váltás révén. Így semmiképpen sem érhető el jogtalanul a privilegizáltabb, védett adat (mely nem illeszkedő kódszegmensben van).)

A legtöbb kódszegmens nem illeszkedő kódszegmens. Ezen szegmensek esetén csak akkor történhet meg a vezérlés átadás, ha a kódszegmens azonos privilégium szintű. Ellenkező esetben az egyetlen hozzáférési lehetőség csak a call-kapun keresztül történhet. Ezt a következő fejezetek írják le.