Search code examples
x86x86-64cpu-architectureprotected-mode

Why can't CPL be changed when running in an unprivileged ring (user mode)?


If the current privilege level is encoded in CS, which is modifiable by user-mode code, why can’t user-mode code modify CS to change CPL?


Solution

  • The question is broad, but I can give some general information and links referencing the Instruction Set architecture (ISA) which describes all the instructions.

    You can't MOV or POP a value into CS (on 286+1) so you are prevented from modifying CS that way. For example for POP there is a rule:

    The POP instruction cannot pop a value into the CS register. To load the CS register from the stack, use the RET instruction.

    And the rule for MOV is similar:

    The MOV instruction cannot be used to load the CS register.

    You can modify CS indirectly through syscall, sysenter, FAR jmp (via call gate), FAR call (via call gate), iret, retf(FAR return) or int . You can review the ISA for each instruction and what privilege level checks are applied. You can't arbitrarily change CPL if you don't have the privilege and access rights to do so.

    Under most circumstances if you have the privilege to affect a change to CPL it will be changed. If you don't have the required privileges you get an exception (privilege level checks usually involve RPL, CPL, DPL). If using conforming code segments (a different topic) you can request to execute code using a code segment with a higher privileged DPL but the CPL will remain unchanged. It is a case where the CPL and DPL (Descriptor privilege level) of CS can be different while code is executing.


    Footnotes

    1You were allowed to modify CS via POP and MOV on 8088/8086 processors.