Reading intel x86 Manual and other sources, i did not understand the difference between DPL (Descriptor privilege level) and RPL (Requested privilege level). Why is there necessity to have both? Thank you so much
The CPL (current privilege level). The RPL (requestor's privilege level) of the selector used to specify the call gate. The DPL of the gate descriptor. The DPL of the descriptor of the target executable segment.
RPL field is used to harden the CPL, when higher-privileged code is servicing lower-privileged processes requests. Assume a higher-privileged device-driver that supports a mechanism where, it can copy data from disks directly into lower-privileged processes' data-segments.
The CPL is your current privilege level. The DPL is the privilege level of a segment. It defines the minimum1 privilege level required to access the segment.
RPL is the two least significant bits of selector RPL is used to establish a less trusted privilege level than CPL for the use of a segment and this level is called the task's Effective Privilege Level (EPL).
Good question.
To make this simpler, let's first just consider CPL and DPL:
RPL is a privilege level associated with a segment selector. A segment selector is just a 16-bit value that references a segment. Every memory access (implicitly2 or otherwise) uses a segment selector as part of the access.
When accessing a segment, there are actually two checks that must be performed. Access to the segment is only allowed if both of the following are true:
So even if CPL is sufficiently privileged to access a segment, the access will still be denied if the segment selector that references that segment is not sufficiently privileged.
What's the purpose of this? Well, the reasoning is a bit dated now, but the Intel documentation offers a scenario that goes something like this:
An application would ordinarily not be able to access the memory in segment X (because CPL > DPL). But depending on how the system call was implemented, an application might be able to invoke the system call with a parameter of an address within segment X. Then, because the system call is privileged, it would be able to write to segment X on behalf of the application. This could introduce a privilege escalation vulnerability into the operating system.
To mitigate this, the official recommendation is that when a privileged routine accepts a segment selector provided by unprivileged code, it should first set the RPL of the segment selector to match that of the unprivileged code3. This way, the operating system would not be able to make any accesses to that segment that the unprivileged caller would not already be able to make. This helps enforce the boundary between the operating system and applications.
Segment protection was introduced with the 286, before paging existed in the x86 family of processors. Back then, segmentation was the only way to restrict access to kernel memory from a user-mode context. RPL provided a convenient way to enforce this restriction when passing pointers across different privilege levels.
Modern operating systems use paging to restrict access to memory, which removes the need for segmentation. Since we don't need segmentation, we can use a flat memory model, which means segment registers CS
, DS
, SS
, and ES
all have a base of zero and extend through the entire address space. In fact, in 64-bit "long mode", a flat memory model is enforced, regardless of the contents of those four segment registers. Segments are still used sometimes (for example, Windows uses FS
and GS
to point to the Thread Information Block and 0x23 and 0x33 to switch between 32- and 64-bit code, and Linux is similar), but you just don't go passing segments around anymore. So RPL is mostly an unused leftover from older times.
You asked why it was a necessity to have both DPL and RPL. Even in the context of the 286, it wasn't actually a necessity to have RPL. Considering the above scenario, a privileged procedure could always just retrieve the DPL of the provided segment via the LAR instruction, compare this to the privilege of the caller, and preemptively bail out if the caller's privilege is insufficient to access the segment. However, setting the RPL, in my opinion, is a more elegant and simpler way of managing segment accesses across different privilege levels.
To learn more about privilege levels, check out Volume 3 of Intel's software developer manuals, particularly the sections titled "Privilege Levels" and "Checking Caller Access Privileges".
1 Technically, the DPL can have different meanings depending on what type of segment or gate is being accessed. For the sake of simplicity, everything I describe applies to data segments specifically. Check the Intel docs for more information
2 For example, the instruction pointer implicitly uses the segment selector stored in CS when fetching instructions; most types of data accesses implicitly use the segment selector stored in DS, etc.
3 See the ARPL instruction (16-bit/32-bit protected mode only)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With