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 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)
Download