Processor Privilege-Levels How the x86 processor accomplishes transitions among its four distinct privilege-levels

advertisement
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 ability to perform certain actions
• Four distinct privilege-levels are supported
• Organizing concept: 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
Rin2: 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 only possible by using a special
control-structure (known as a call gate)
• The ‘gate’ is defined by a data-structure
located in a system memory-segment
normally inaccessible to modifications
• A transition from an inner ring to an outer
ring is not nearly so strictly controlled
Data-sharing
• Procedure-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 is frequently used as a
shared-access storage-area
• But among routines with different levels of
privilege, this could create “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 a ‘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
0x9A
(ignored)
callgate-selector
opcode
offset-field
segment-field
• In as86 assembly language:
callf #0, #callgate-selector
What does the CPU do?
• When CPU fetches a far-call instruction, it
looks up that instruction’s specified
descriptor
• If it’s a call-gate descriptor, and if access is
allowed (i.e., CPL  DPL), then the CPU
will perform a complex series of actions to
accomplish a requested ring-transition
• CPL (Current Privilege Level) is based on
least significant 2-bits in CS (also in SS)
Series of CPU 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 callgate)
• They’re from a special system-segment,
called the TSS (Task State Segment)
• The CPU locates its TSS by referring to
the value in register TR (Task Register)
Diagram of 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: retf
– Restores CS:IP from current stack
– Restores SS:SP from current stack
• Or use the far-return instruction: retf n
– Restores CS:IP from current stack
– Discards n bytes from stack (parameters)
– Restores SS:IP from 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 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 ring0 SS:SP)
– Task-Gate and TSS Descriptors (for ‘callf’)
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
ESP2
12
SS2
24
…
…
ESP0
SS0
ESP1
SS1
SS2
System Segment-Descriptors
S-bit is zero
Base[ 31..24 ]
D
Limit
P P 0
[19..16]
L
Base[ 15..0 ]
type
0 = reserved
1 = 16-bit TSS (available)
2 = LDT
3 = 16-bit TSS (busy)
type
Base[ 23..16 ]
Limit[ 15..0 ]
type
8 = reserved
9 = 32-bit TSS (available)
A = reserved
B = 32-bit TSS (busy)
In-class exercise #2
• Modify the ‘tryring1.s’ demo so that it first
enters ring2, then calls to ring1 from ring2
(but returns to ring2), and then finally calls
to ring0 in order to exit protected-mode
• How many stack-segments do you need?
• How many code-segment descriptors?
• How many VRAM-segment descriptors?
Download