马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 兰陵月 于 2017-12-24 16:03 编辑
逻辑代码段1 IF far call and (PE = 1 and VM = 0) (* Protected mode or IA-32e Mode, not virtual-8086 mode*)
THEN
IF segment selector in target operand NULL
THEN #GP(0); FI;
IF segment selector index not within descriptor table limits
THEN #GP(new code segment selector); FI;
Read type and access rights of selected segment descriptor;
IF IA32_EFER.LMA = 0
THEN
IF segment type is not a conforming or nonconforming code segment, call gate, task gate, or TSS
THEN #GP(segment selector); FI;
ELSE
IF segment type is not a conforming or nonconforming code segment or 64-bit call gate,
THEN #GP(segment selector); FI;
FI;
Depending on type and access rights:
GO TO CONFORMING-CODE-SEGMENT;
GO TO NONCONFORMING-CODE-SEGMENT;
GO TO CALL-GATE;
GO TO TASK-GATE;
GO TO TASK-STATE-SEGMENT;
FI;
逻辑代码段2【由逻辑代码段1第21行跳转而来】-跳转到一致代码段 CONFORMING-CODE-SEGMENT:
IF L bit = 1 and D bit = 1 and IA32_EFER.LMA = 1
THEN GP(new code segment selector); FI;
IF DPL > CPL
THEN #GP(new code segment selector); FI;
IF segment not present
THEN #NP(new code segment selector); FI;
IF stack not large enough for return address
THEN #SS(0); FI;
tempEIP ← DEST(Offset);
IF OperandSize = 16
THEN
tempEIP ← tempEIP AND 0000FFFFH; FI; (* Clear upper 16 bits *)
IF (EFER.LMA = 0 or target mode = Compatibility mode) and (tempEIP outside new code segment limit)
THEN #GP(0); FI;
IF tempEIP is non-canonical
THEN #GP(0); FI;
IF OperandSize = 32
THEN
Push(CS); (* Padded with 16 high-order bits *)
Push(EIP);
CS ← DEST(CodeSegmentSelector);
(* Segment descriptor information also loaded *)
CS(RPL) ← CPL;
EIP ← tempEIP;
ELSE
IF OperandSize = 16
THEN
Push(CS);
Push(IP);
CS ← DEST(CodeSegmentSelector);
(* Segment descriptor information also loaded *)
CS(RPL) ← CPL;
EIP ← tempEIP;
ELSE (* OperandSize = 64 *)
Push(CS); (* Padded with 48 high-order bits *)
Push(RIP);
CS ← DEST(CodeSegmentSelector);
(* Segment descriptor information also loaded *)
CS(RPL) ← CPL;
RIP ← tempEIP;
FI;
FI;
END;
可以看到,上述各种情况下,CS段寄存器的RPL均被当前特权级CPL刷新,导致调用后的当前特权级CPL仍然为调用前的CPL的数值,程序跳转后运行在调用前的CPL级别下。
逻辑代码段3【由逻辑代码段1第22行跳转而来】-跳转到非一致代码段NONCONFORMING-CODE-SEGMENT:
IF L-Bit = 1 and D-BIT = 1 and IA32_EFER.LMA = 1
THEN GP(new code segment selector); FI;
IF (RPL > CPL) or (DPL ≠ CPL)
THEN #GP(new code segment selector); FI;
IF segment not present
THEN #NP(new code segment selector); FI;
IF stack not large enough for return address
THEN #SS(0); FI;
tempEIP ← DEST(Offset);
IF OperandSize = 16
THEN tempEIP ← tempEIP AND 0000FFFFH; FI; (* Clear upper 16 bits *)
IF (EFER.LMA = 0 or target mode = Compatibility mode) and (tempEIP outside new code segment limit)
THEN #GP(0); FI;
IF tempEIP is non-canonical
THEN #GP(0); FI;
IF OperandSize = 32
THEN
Push(CS); (* Padded with 16 high-order bits *)
Push(EIP);
CS ← DEST(CodeSegmentSelector);
(* Segment descriptor information also loaded *)
CS(RPL) ← CPL;
EIP ← tempEIP;
ELSE
IF OperandSize = 16
THEN
Push(CS);
Push(IP);
CS ← DEST(CodeSegmentSelector);
(* Segment descriptor information also loaded *)
CS(RPL) ← CPL;
EIP ← tempEIP;
ELSE (* OperandSize = 64 *)
Push(CS); (* Padded with 48 high-order bits *)
Push(RIP);
CS ← DEST(CodeSegmentSelector);
(* Segment descriptor information also loaded *)
CS(RPL) ← CPL;
RIP ← tempEIP;
FI;
FI;
END;
可以看到,上述各种情况下,CS段寄存器的RPL均被当前特权级CPL刷新,导致调用后的当前特权级CPL仍然为调用前的CPL的数值,程序跳转后运行在调用前的CPL级别下。
逻辑代码段4【由逻辑代码段1第23行跳转而来】-通过调用门调用 CALL-GATE:
IF call gate (DPL < CPL) or (RPL > DPL)
THEN #GP(call-gate selector); FI;
IF call gate not present
THEN #NP(call-gate selector); FI;
IF call-gate code-segment selector is NULL
THEN #GP(0); FI;
IF call-gate code-segment selector index is outside descriptor table limits
THEN #GP(call-gate code-segment selector); FI;
Read call-gate code-segment descriptor;
IF call-gate code-segment descriptor does not indicate a code segment
or call-gate code-segment descriptor DPL > CPL
THEN #GP(call-gate code-segment selector); FI;
IF IA32_EFER.LMA = 1 AND (call-gate code-segment descriptor is
not a 64-bit code segment or call-gate code-segment descriptor has both L-bit and D-bit set)
THEN #GP(call-gate code-segment selector); FI;
IF call-gate code segment not present
THEN #NP(call-gate code-segment selector); FI;
IF call-gate code segment is non-conforming and DPL < CPL
THEN go to MORE-PRIVILEGE;
ELSE go to SAME-PRIVILEGE;
FI;
END;
逻辑代码段5【由逻辑代码段4第28行跳转而来】-通过调用门(低特权级调用高特权级代码) MORE-PRIVILEGE:
IF current TSS is 32-bit
THEN
TSSstackAddress ← (new code-segment DPL*8) + 4;
IF (TSSstackAddress + 5) > current TSS limit
THEN #TS(current TSS selector); FI;
NewSS ← 2 bytes loaded from (TSS base + TSSstackAddress + 4);
NewESP ← 4 bytes loaded from (TSS base + TSSstackAddress);
ELSE
IF current TSS is 16-bit
THEN
TSSstackAddress ← (new code-segment DPL*4) + 2
IF (TSSstackAddress + 3) > current TSS limit
THEN #TS(current TSS selector); FI;
NewSS ← 2 bytes loaded from (TSS base + TSSstackAddress + 2);
NewESP ← 2 bytes loaded from (TSS base + TSSstackAddress);
ELSE (* current TSS is 64-bit *)
TSSstackAddress ← (new code-segment DPL*8) + 4;
IF (TSSstackAddress + 7) > current TSS limit
THEN #TS(current TSS selector); FI;
NewSS ← new code-segment DPL; (* NULL selector with RPL = new CPL *)
NewRSP ← 8 bytes loaded from (current TSS base + TSSstackAddress);
FI;
FI;
IF IA32_EFER.LMA = 0 and NewSS is NULL
THEN #TS(NewSS); FI;
Read new code-segment descriptor and new stack-segment descriptor;
IF IA32_EFER.LMA = 0 and
(NewSS RPL ≠ new code-segment DPL or
new stack-segment DPL ≠ new code-segment DPL or
new stack segment is not a writable data segment)
THEN #TS(NewSS); FI
IF IA32_EFER.LMA = 0 and new stack segment not present
THEN #SS(NewSS); FI;
IF CallGateSize = 32
THEN
IF new stack does not have room for parameters plus 16 bytes
THEN #SS(NewSS); FI;
IF CallGate(InstructionPointer) not within new code-segment limit
THEN #GP(0); FI;
SS ← newSS; (* Segment descriptor information also loaded *)
ESP ← newESP;
CS:EIP ← CallGate(CS:InstructionPointer);
(* Segment descriptor information also loaded *)
Push(oldSS:oldESP); (* From calling procedure *)
temp ← parameter count from call gate, masked to 5 bits;
Push(parameters from calling procedure’s stack, temp)
Push(oldCS:oldEIP); (* Return address to calling procedure *)
ELSE
IF CallGateSize = 16
THEN
IF new stack does not have room for parameters plus 8 bytes
THEN #SS(NewSS); FI;
IF (CallGate(InstructionPointer) AND FFFFH) not in new code-segment limit
THEN #GP(0); FI;
SS ← newSS; (* Segment descriptor information also loaded *)
ESP ← newESP;
CS:IP ← CallGate(CS:InstructionPointer);
(* Segment descriptor information also loaded *)
Push(oldSS:oldESP); (* From calling procedure *)
temp ← parameter count from call gate, masked to 5 bits;
Push(parameters from calling procedure’s stack, temp)
Push(oldCS:oldEIP); (* Return address to calling procedure *)
ELSE (* CallGateSize = 64 *)
IF pushing 32 bytes on the stack would use a non-canonical address
THEN #SS(NewSS); FI;
IF (CallGate(InstructionPointer) is non-canonical)
THEN #GP(0); FI;
SS ← NewSS; (* NewSS is NULL)
RSP ← NewESP;
CS:IP ← CallGate(CS:InstructionPointer);
(* Segment descriptor information also loaded *)
Push(oldSS:oldESP); (* From calling procedure *)
Push(oldCS:oldEIP); (* Return address to calling procedure *)
FI;
FI;
CPL ← CodeSegment(DPL)
CS(RPL) ← CPL
END;
可以看到,各种检查通过后,目标代码段的DPL数值被传送给了当前特权级CPL(第77行),然后再用CPL的数值刷新了CS段寄存器的RPL数值(第78行)。所以程序调用后的当前特权级CPL数值是目标代码段的特权级,而不是程序调用前的特权级,这样程序由当前代码的低特权级提升到了目标代码的高特权级,这是唯一的可以提升当前特权级CPL的情况
逻辑代码段6【由逻辑代码段4第2行跳转而来】-通过调用门(特权级相同) SAME-PRIVILEGE:
IF CallGateSize = 32
THEN
IF stack does not have room for 8 bytes
THEN #SS(0); FI;
IF CallGate(InstructionPointer) not within code segment limit
THEN #GP(0); FI;
CS:EIP ← CallGate(CS:EIP) (* Segment descriptor information also loaded *)
Push(oldCS:oldEIP); (* Return address to calling procedure *)
ELSE
If CallGateSize = 16
THEN
IF stack does not have room for 4 bytes
THEN #SS(0); FI;
IF CallGate(InstructionPointer) not within code segment limit
THEN #GP(0); FI;
CS:IP ← CallGate(CS:instruction pointer);
(* Segment descriptor information also loaded *)
Push(oldCS:oldIP); (* Return address to calling procedure *)
ELSE (* CallGateSize = 64)
IF pushing 16 bytes on the stack touches non-canonical addresses
THEN #SS(0); FI;
IF RIP non-canonical
THEN #GP(0); FI;
CS:IP ← CallGate(CS:instruction pointer);
(* Segment descriptor information also loaded *)
Push(oldCS:oldIP); (* Return address to calling procedure *)
FI;
FI;
CS(RPL) ← CPL
END;
可以看到,上述各种情况下,CS段寄存器的RPL被当前特权级CPL刷新,导致调用后的当前特权级CPL仍然为调用前的CPL的数值,程序跳转后运行在调用前的CPL级别下。
逻辑代码段7【由逻辑代码段1第24行跳转而来】-跳转到任务门 TASK-GATE:
IF task gate DPL < CPL or RPL
THEN #GP(task gate selector); FI;
IF task gate not present
THEN #NP(task gate selector); FI;
Read the TSS segment selector in the task-gate descriptor;
IF TSS segment selector local/global bit is set to local
or index not within GDT limits
THEN #GP(TSS selector); FI;
Access TSS descriptor in GDT;
IF TSS descriptor specifies that the TSS is busy (low-order 5 bits set to 00001)
THEN #GP(TSS selector); FI;
IF TSS not present
THEN #NP(TSS selector); FI;
SWITCH-TASKS (with nesting) to TSS;
IF EIP not within code segment limit
THEN #GP(0); FI;
END;
逻辑代码段8【由逻辑代码段1第25行跳转而来】-直接跳转到任务状态段TSS TASK-STATE-SEGMENT:
IF TSS DPL < CPL or RPL
or TSS descriptor indicates TSS not available
THEN #GP(TSS selector); FI;
IF TSS is not present
THEN #NP(TSS selector); FI;
SWITCH-TASKS (with nesting) to TSS;
IF EIP not within code segment limit
THEN #GP(0); FI;
END;
|