Processor Privilege-Levels How the x86 processor accomplishes transitions among its four distinct privilege-levels Rationale • The usefulness of protected-mode derives from its ability to enforce restrictions upon software’s freedom to take certain actions • Four distinct privilege-levels are supported • Organizing concept is “concentric rings” • Innermost ring has greatest privileges, and privileges diminish as rings move outward Four Privilege Rings Ring 3 Least-trusted level Ring 2 Ring 1 Ring 0 Most-trusted level Suggested purposes Ring0: operating system kernel Ring1: operating system services Ring2: custom extensions Ring3: ordinary user applications Unix/Linux and Windows Ring0: operating system Ring1: unused Ring2: unused Ring3: application programs Legal Ring-Transitions • A transition from an outer ring to an inner ring is made possible by using a special control-structure (known as a ‘call gate’) • The ‘gate’ is defined via a data-structure located in a ‘system’ memory-segment normally not accessible for modifications • A transition from an inner ring to an outer ring is not nearly so strictly controlled Data-sharing • Function-calls typically require that two separate routines share some data-values (e.g., parameter-values get passed from the calling routine to the called routine) • To support reentrancy and recursion, the processor’s stack-segment is frequently used as a ‘shared-access’ storage-area • But among routines with different levels of privilege this could create a “security hole” An example senario • Say a procedure that executes in ring 3 calls a procedure that executes in ring 2 • The ring 2 procedure uses a portion of its stack-area to create ‘automatic’ variables that it uses for temporary workspace • Upon return, the ring 3 procedure would be able to examine whatever values are left behind in this ring 2 workspace Data Isolation • To guard against unintentional sharing of privileged information, different stacks are provided at each distinct privilege-level • Accordingly, any transition from one ring to another must necessarily be accompanied by an mandatory ‘stack-switch’ operation • The CPU provides for automatic switching of stacks and copying of parameter-values Call-Gate Descriptors 63 32 offset[ 31..16 ] code-selector 31 D P P L 0 gate type parameter count offset[ 15..0 ] 0 Legend: P=present (1=yes, 0=no) DPL=Descriptor Prvilege Level (0,1,2,3) code-selector (specifies memory-segment containing procedure code) offset (specifies the procedure’s entry-point within its code-segment) parameter count (specifies how many parameter-values will be copied) gate-type (‘0x4’ means a 16-bit call-gate, ‘0xC’ means a 32-bit call-gate) An Interprivilege Call • When a lesser privileged routine wants to invoke a more privileged routine, it does so by using a ‘far call’ machine-instruction (also known as a “long call” in the GNU assembler’s terminology) 0x9A (ignored) opcode offset-field callgate-selector segment-field • In ‘as’ assembly language: lcall $callgate-selector, $0 What does the CPU do? • When CPU fetches a far-call instruction, it will use that instruction’s ‘selector’ value to look up a descriptor in the GDT (or in the current LDT) • If it’s a ‘call-gate’ descriptor, and if access is allowed (i.e., if CPL DPL), then the CPU will perform a complex sequence of actions which will accomplish the requested ‘ring-transition’ • CPL (Current Privilege Level) is based on least significant 2-bits in register CS (also in SS) Sequence of CPU’s actions - pushes the current SS:SP register-values onto a new stack-segment - copies the specified number of parameters from the old stack onto the new stack - pushes the updated CS:IP register-values onto the new stack - loads new values into registers CS:IP (from the callgate-descriptor) and into SS:SP The missing info? • Where do the new values for SS:SP come from? (They’re not found in the call-gate) • They’re from a special system-segment, known as the TSS (Task State Segment) • The CPU locates its TSS by referring to the value in register TR (Task Register) Diagram of the relationships old code-segment CS:IP new code-segment call-instruction TASK STATE SEGMENT stack-pointer OLD STACK SEGMENT Descriptor-Table called procedure params NEW STACK SEGMENT gate-descriptor params SS:SP TSS-descriptor TR GDTR Return to an Outer Ring • Use the far-return instruction: ‘lret’ – Restores CS:IP from the current stack – Restores SS:SP from the current stack • Or use the far-return instruction: ‘lret $n’ – Restores CS:IP from the current stack – Discards n parameter-bytes from that stack – Restores SS:SP from that current stack Demo-program: ‘tryring1.s’ • We have created a short program to show how this ring-transition mechanism works • It enters protected-mode (at ring0) • It ‘returns’ to a procedure in ring1 • Procedure shows a confirmation-message • The ring1 procedure then ‘calls’ to ring0 • The ring0 procedure exits protected-mode Data-structures needed • Global Descriptor Table needs to contain the protected-mode segment-descriptors and also the ‘call-gate’ descriptor – Code-segments for Ring0 and Ring1 – Stack-segments for Ring0 and Ring1 – Data-segment (for Ring1 to write to VRAM) – Task-State Segment (for the ring0 SS:SP) – Call-Gate Descriptor (for the ‘lcall’ to ring0) In-class Exercise #1 • Modify the ‘tryring1.s’ demo so that it uses a 32-bit call-gate and a 32-bit TSS TSS for 80286 (16-bits) 0 TSS for 80386 (32-bits) 0 2 SP0 4 4 SS0 8 6 8 SP1 12 SS1 16 10 SP2 20 12 SS2 24 … ESP0 SS0 ESP1 SS1 ESP2 … SS2 System Segment-Descriptors S-bit is zero Base[ 31..24 ] reserved =0 D Limit P P 0 [19..16] L Base[ 15..0 ] type Base[ 23..16 ] Limit[ 15..0 ] Type-codes for system-segments: 0 = reserved 1 = 16-bit TSS (available) 2 = LDT 3 = 16-bit TSS (busy) 8 = reserved 9 = 32-bit TSS (available) A = reserved B = 32-bit TSS (busy)