From e42640b500227a9b86d90a069fa83fa07b138a4f Mon Sep 17 00:00:00 2001 From: Aleksandar Andrejevic Date: Thu, 6 Nov 2014 05:16:14 +0000 Subject: [PATCH] [FAST486] Fix the limit calculation when using page granularity. RETF can also perform inter-privilege returns. Fix the privilege checks when loading CS. DPL != CPL is only a #GP when we're doing a jump or a call. svn path=/trunk/; revision=65280 --- reactos/lib/fast486/common.c | 14 ++++++- reactos/lib/fast486/common.inl | 19 ++++++--- reactos/lib/fast486/extraops.c | 7 +++- reactos/lib/fast486/opcodes.c | 75 ++++++++++++++++++++++++++++++---- reactos/lib/fast486/opgroups.c | 14 ++++++- 5 files changed, 109 insertions(+), 20 deletions(-) diff --git a/reactos/lib/fast486/common.c b/reactos/lib/fast486/common.c index 3d666ae90eb..a16b5914e41 100644 --- a/reactos/lib/fast486/common.c +++ b/reactos/lib/fast486/common.c @@ -553,7 +553,12 @@ Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Se /* Calculate the limit of the new TSS */ NewTssLimit = NewTssDescriptor.Limit | (NewTssDescriptor.LimitHigh << 16); - if (NewTssDescriptor.Granularity) NewTssLimit <<= 12; + + if (NewTssDescriptor.Granularity) + { + NewTssLimit <<= 12; + NewTssLimit |= 0x00000FFF; + } if (NewTssLimit < sizeof(FAST486_TSS)) { @@ -739,7 +744,12 @@ Fast486TaskSwitch(PFAST486_STATE State, FAST486_TASK_SWITCH_TYPE Type, USHORT Se State->Ldtr.Selector = NewTss.Ldtr; State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24); State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16); - if (GdtEntry.Granularity) State->Ldtr.Limit <<= 12; + + if (GdtEntry.Granularity) + { + State->Ldtr.Limit <<= 12; + State->Ldtr.Limit |= 0x00000FFF; + } } else { diff --git a/reactos/lib/fast486/common.inl b/reactos/lib/fast486/common.inl index 68285831e56..73bb537a7ae 100644 --- a/reactos/lib/fast486/common.inl +++ b/reactos/lib/fast486/common.inl @@ -594,16 +594,12 @@ Fast486LoadSegmentInternal(PFAST486_STATE State, { /* Regular code segment */ - if ((GET_SEGMENT_RPL(Selector) > Fast486GetCurrentPrivLevel(State)) - || (Fast486GetCurrentPrivLevel(State) != GdtEntry.Dpl)) + if ((GET_SEGMENT_RPL(Selector) < Fast486GetCurrentPrivLevel(State))) { Fast486ExceptionWithErrorCode(State, Exception, Selector); return FALSE; } } - - /* Update CPL */ - State->Cpl = GET_SEGMENT_RPL(Selector); } else { @@ -653,7 +649,11 @@ Fast486LoadSegmentInternal(PFAST486_STATE State, CachedDescriptor->Size = GdtEntry.Size; /* Check for page granularity */ - if (GdtEntry.Granularity) CachedDescriptor->Limit <<= 12; + if (GdtEntry.Granularity) + { + CachedDescriptor->Limit <<= 12; + CachedDescriptor->Limit |= 0x00000FFF; + } } else { @@ -730,6 +730,13 @@ Fast486ProcessGate(PFAST486_STATE State, USHORT Selector, ULONG Offset, BOOLEAN default: { + /* Security check for jumps and calls only */ + if (State->Cpl != Descriptor.Dpl) + { + Fast486ExceptionWithErrorCode(State, FAST486_EXCEPTION_GP, Selector); + return FALSE; + } + return TRUE; } } diff --git a/reactos/lib/fast486/extraops.c b/reactos/lib/fast486/extraops.c index 6a73fb8fe86..1f2fc727697 100644 --- a/reactos/lib/fast486/extraops.c +++ b/reactos/lib/fast486/extraops.c @@ -475,7 +475,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeLsl) /* Calculate the limit */ Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16); - if (GdtEntry.Granularity) Limit <<= 12; + + if (GdtEntry.Granularity) + { + Limit <<= 12; + Limit |= 0x00000FFF; + } /* Set ZF */ State->Flags.Zf = TRUE; diff --git a/reactos/lib/fast486/opcodes.c b/reactos/lib/fast486/opcodes.c index 0e004eae9f3..7ac8014702d 100644 --- a/reactos/lib/fast486/opcodes.c +++ b/reactos/lib/fast486/opcodes.c @@ -4474,6 +4474,63 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeRetFar) return; } + if ((State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) && !State->Flags.Vm) + { + INT i; + INT OldCpl = Fast486GetCurrentPrivLevel(State); + ULONG StackPtr; + ULONG StackSel; + + if (GET_SEGMENT_RPL(Segment) > OldCpl) + { + /* Pop ESP */ + if (!Fast486StackPop(State, &StackPtr)) + { + /* Exception */ + return; + } + + /* Pop SS */ + if (!Fast486StackPop(State, &StackSel)) + { + /* Exception */ + return; + } + + /* Load new SS */ + if (!Fast486LoadSegment(State, FAST486_REG_SS, StackSel)) + { + /* Exception */ + return; + } + + /* Set ESP */ + if (Size) State->GeneralRegs[FAST486_REG_ESP].Long = StackPtr; + else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr); + } + + /* Update the CPL */ + State->Cpl = GET_SEGMENT_RPL(Segment); + + if (State->Cpl > OldCpl) + { + /* Check segment security */ + for (i = 0; i < FAST486_NUM_SEG_REGS; i++) + { + /* Don't check CS or SS */ + if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue; + + if ((State->Cpl > State->SegmentRegs[i].Dpl) + && (!State->SegmentRegs[i].Executable + || !State->SegmentRegs[i].DirConf)) + { + /* Load the NULL descriptor in the segment */ + if (!Fast486LoadSegment(State, i, 0)) return; + } + } + } + } + /* Load new (E)IP, and if necessary, pop the parameters */ if (Size) { @@ -4582,7 +4639,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret) /* Check for protected mode */ if (State->ControlRegisters[FAST486_REG_CR0] & FAST486_CR0_PE) { - INT Cpl = Fast486GetCurrentPrivLevel(State); + INT OldCpl = Fast486GetCurrentPrivLevel(State); if (State->Flags.Vm) { @@ -4660,7 +4717,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret) if (Size) State->InstPtr.Long = InstPtr; else State->InstPtr.LowWord = LOWORD(InstPtr); - if (GET_SEGMENT_RPL(CodeSel) > Cpl) + if (GET_SEGMENT_RPL(CodeSel) > OldCpl) { /* Pop ESP */ if (!Fast486StackPop(State, &StackPtr)) @@ -4688,27 +4745,27 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeIret) else State->GeneralRegs[FAST486_REG_ESP].LowWord = LOWORD(StackPtr); } + /* Update the CPL */ + State->Cpl = GET_SEGMENT_RPL(CodeSel); + /* Set the new flags */ if (Size) State->Flags.Long = NewFlags.Long & PROT_MODE_FLAGS_MASK; else State->Flags.LowWord = NewFlags.LowWord & PROT_MODE_FLAGS_MASK; State->Flags.AlwaysSet = TRUE; /* Set additional flags */ - if (Cpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If; - if (Cpl == 0) State->Flags.Iopl = NewFlags.Iopl; + if (OldCpl <= State->Flags.Iopl) State->Flags.If = NewFlags.If; + if (OldCpl == 0) State->Flags.Iopl = NewFlags.Iopl; - if (GET_SEGMENT_RPL(CodeSel) > Cpl) + if (State->Cpl > OldCpl) { - /* Update the CPL */ - Cpl = Fast486GetCurrentPrivLevel(State); - /* Check segment security */ for (i = 0; i < FAST486_NUM_SEG_REGS; i++) { /* Don't check CS or SS */ if ((i == FAST486_REG_CS) || (i == FAST486_REG_SS)) continue; - if ((Cpl > State->SegmentRegs[i].Dpl) + if ((State->Cpl > State->SegmentRegs[i].Dpl) && (!State->SegmentRegs[i].Executable || !State->SegmentRegs[i].DirConf)) { diff --git a/reactos/lib/fast486/opgroups.c b/reactos/lib/fast486/opgroups.c index 95a99cc9f5c..3f5e828e233 100644 --- a/reactos/lib/fast486/opgroups.c +++ b/reactos/lib/fast486/opgroups.c @@ -1804,7 +1804,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00) State->Ldtr.Selector = Selector; State->Ldtr.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24); State->Ldtr.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16); - if (GdtEntry.Granularity) State->Ldtr.Limit <<= 12; + + if (GdtEntry.Granularity) + { + State->Ldtr.Limit <<= 12; + State->Ldtr.Limit |= 0x00000FFF; + } break; } @@ -1886,7 +1891,12 @@ FAST486_OPCODE_HANDLER(Fast486ExtOpcodeGroup0F00) State->TaskReg.Selector = Selector; State->TaskReg.Base = GdtEntry.Base | (GdtEntry.BaseMid << 16) | (GdtEntry.BaseHigh << 24); State->TaskReg.Limit = GdtEntry.Limit | (GdtEntry.LimitHigh << 16); - if (GdtEntry.Granularity) State->TaskReg.Limit <<= 12; + + if (GdtEntry.Granularity) + { + State->TaskReg.Limit <<= 12; + State->TaskReg.Limit |= 0x00000FFF; + } break; } -- 2.17.1