Practical Reverse Engineering Exercise Solutions: Page 35 / Exercise 10
Our task:
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?
For a change, this is now a more theoretical than hands-on challenge. In order to address the exercise appropriately, we have to make sure we understood it correctly.
CS
(code segment) is the CPU segment register that contains the current ring level in bits 0 and 1. This encoded level is also commonly referred to as CPL (current privilege level).
More information is provided in the Intel 64 and IA-32 Architectures Software Developer’s Manual at https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf.
We learn that the processor fetches instructions from the code segment by using a logical address consisting of both the value in the CS
register and the value in the EIP
register. EIP
contains the offset within the code segment of the next instruction to be executed. Furthermore, the Intel Manual sets out:
“The
CS
register cannot be loaded explicitly by an application program. Instead, it is loaded implicitly by instructions or internal processor operations that change program control (such as, procedure calls, interrupt handling, or task switching).”
This is very similar to the EIP
register, which is only modified indirectly when executing instructions such as JMP
, RET
or CALL
.
Therefore, the CS register can only be modified with instructions such as INT
, SYSCALL/SYSRET
(64bit only) or SYSENTER/SYSEXIT
.
With the instruction SYSENTER
, user-mode code (i.e. CPL 3) can access special operating system (kernel-mode) code at privilege level 0. For instance, special privileged instructions can be accessed at CPL 0, such as the LGDT
instruction to load the GDT register.