This technical deep dive expands on the information in the Speculative Behavior of SWAPGS and Segment Registers disclosure.
In the IA-32 architecture, memory segmentation is used in the formation of physical memory addresses. Segment descriptors specify a base address (along with other attributes) for each segment, on which the rest of the physical address is built. The segment information is stored in a table in memory, and the individual segments are referenced by selectors that act as indices into this table. The architecture defines a set of segment registers (CS, SS, DS, ES, FS, and GS) that can each hold one selector value. One of these registers is either implicitly or explicitly used for every effective address memory access. More information on segmentation can be found in the Intel® 64 and IA-32 Architectures Software Developer Manual, Volume 3a, Chapter 3, Protected Mode Memory Management.
Many operating systems use the GS segment register to reference application and kernel data that is specific to a thread or processor. In such cases, the operating system maintains both user space and kernel values of GS. The
SWAPGS instruction is a privileged CPU instruction used to exchange the application and kernel values of GS.
If operating systems that use
SWAPGS to switch the contents of the GS register on kernel entry have code paths that conditionally determine whether or not to execute the instruction and then also contain memory references offset from the register, those OSes may be vulnerable to malicious actors who can cause the
SWAPGS instruction to be speculatively executed or bypassed. The CVE assigned to this vulnerability is CVE-2019-1125 (5.6 Medium CVSS:3.0/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:N/A:N/E:P/RL:O/RC:C).
We can use the example code sequence below to illustrate both of these cases:
0 test 1 je skip 2 swapgs 3 mov r10, qword ptr gs:[1000h] 4 mov rbx, [r10] 5 ... 6 skip: 7 mov rcx, qword ptr gs:[2000h] 8 mov rbx, [rcx] 9 …
If GS holds the user space value on entry (for example, if this was part of a system call) and the branch is speculatively predicted to be taken, then the speculative execution path skips the
SWAPGS instruction. The memory reference on line 7 would speculatively execute with the user space value of GS, and thus may load kernel data from an address specified by a malicious actor. The memory reference on line 8 would be based on the value loaded by line 7, which may affect the cache in a way that might be detectable by a malicious actor in user space.
In the other case, if GS holds the kernel value on entry (for example, if this code was part of an interrupt handler where interrupts could be generated from either kernel or user space) and the branch is speculatively predicted to not be taken, then the speculative execution path executes the
SWAPGS instruction, switching to the user space value of GS. The memory reference on line 3 would speculatively execute with the user space value and thus may load kernel data from an address specified by a malicious actor. The memory reference on line 4 would be based on the value loaded by line 3, which would affect the cache in a way that might be detectable by a malicious actor in user space.
Note: Real software may not have sequences that are as simple as the example above.
When converting an effective address into a linear address, the address generation hardware needs to know the base address and the limit of the applicable segment. When a segment register is written, these fields are cached within the processor in a microarchitectural structure called the segment register file.
Register renaming is a microarchitectural technique that can improve performance by allowing an operation to execute and update a register before the processor knows whether older operations will cause a jump mispredict, trap, interrupt, or exception. For at least some types of register renaming, a renamed register file will have more physical entries than the number of architectural registers that software can specify and a mapping from each architectural register to each physical entry. When software writes one of these registers, the hardware picks a new physical register file entry, writes the result into it, and causes the architectural register to point to the physical register instead of overwriting the contents of the physical register that was previously used. If that operation retires (no older operation takes a jump mispredict, trap, interrupt, or exception) then the old (unused) physical register file entry is no longer needed and can be reclaimed. However, if the operation does not retire, then the old contents of that register can be restored by mapping the architectural register back to the old physical register file entry.
This technique can also be applied to segment registers. A processor can maintain a renamed segment register file and keep updating the architectural segment register to point to the correct entry (reflecting the current architectural state) in the segment register file. This may be applicable to instructions which directly operate on segment bases, like
WRGSBASE, as well.
The processor may speculatively execute instructions that perform writes to segment registers, and thus segment bases, in the segment register file. Since these operations happen under a speculative window, the processor may allocate an entry in the segment register file and update it with a new base address. Later, the processor may determine that this speculative execution path was wrong and thus will not update the architectural state. The architectural segment register would still point to the old entry and the old base. The entry allocated in the segment register file during the speculative window may retain its speculatively written value. For lack of other terminology, we can call this entry a stale segment register entry as it is not currently being used for the architectural segment register. If the processor determines that the speculative execution path was correct, then it will update the architectural state to the newly written value. In this case, the previously used entry that held the old base would become a stale segment register entry.
If the segment register is loaded with a new selector value, a processor may perform the following operations:
On processors with segment renaming, step 5 may still occur when step 2 detects that the segment descriptor is not valid. If the descriptor is invalid, step 2 ensures the operation faults and the changes are never reflected in the architectural state. However, if dependent instructions consume the results of this segment write (for example, by reading it out through
RDFSBASE), the dependent instructions may speculatively get the value from the newly allocated segment entry in the segment register file (from step 3). Some implementations will not write the segment register file when the segment descriptor is invalid, which can result in the value in the allocated segment entry being a stale value that was written by some previous segment write operation. Malicious actors may be able to reveal this stale value using a speculative execution disclosure gadget.
The affected CPUs have two dedicated segment register file entries for each architectural segment, one of which is currently used for the segment, while the other is currently unused at any particular time. These entries are not shared between logical processors (for example, no entry is sometimes used by hyperthread 0 and sometimes used by hyperthread 1 on the same physical core), nor are they shared between different architectural segment registers (for example, there is no segment register file entry that is sometimes allocated to GS and sometimes to FS).
The values contained in a stale segment register file entry may belong to previously run software. It may be possible for a malicious actor to infer the value in the unused segment register file entry, thus inferring the segment base of that previously run software. This may apply to previously run applications, guests, kernels, or virtual machine managers (VMMs). Most software only uses non-zero segment bases for those segments used for thread local storage (FS and GS segments).
Malicious actors who are able to control victim execution (for example, through a lack of mitigations against branch target injection attacks (also known as Spectre variant 2)) may be able to induce the victim to speculatively execute a segment write with data desired by the malicious actor. This speculatively written data may go into the unused segment register file entry of the destination segment.
When the malicious code later runs on the same logical processor, the malicious actor may be able to recover this data from the unused segment register file entry using the aforementioned technique.
It is also possible for two pieces of software to intentionally pass data through the unused segment register file entry of a segment.
After assessing this issue, industry partners determined that mitigations for this issue would be implemented by the operating system. For more details about these mitigations, refer to the Microsoft* security advisory for Windows* operating systems and the latest kernel.org documentation for Linux* operating systems.
Generically, the recommended mitigation for when
SWAPGS is speculatively missed (as in the first example case above) is to add an
LFENCE or serializing instruction before the first memory reference using GS (for example, between lines 6 and 7 in the example code) on all paths that can speculatively skip the
SWAPGS instruction. This will create a speculation barrier that forces the conditional to be evaluated before the memory reference executes.
The mitigation for when an extra
SWAPGS instruction is speculatively executed when it should not be (as in the second case above) is to add an
LFENCE or serializing instruction after the
SWAPGS instruction (for example, after line 2 in the example code).
However, for optimal performance, each instance of
SWAPGS should be evaluated to determine whether an
LFENCE is actually needed. For instance, a potentially problematic code sequence might only speculatively execute without mappings of secret data, in which case the malicious actor would not have access to that data. In other cases, there may be some other serializing instruction before the memory accesses that would serve the same purpose as
LFENCE. Writes to the CR3 register used to mitigate rogue data cache load (also known as Meltdown) are serializing instructions and can be utilized for serialization in lieu of
Many channels already exist that can be used for side channels. In general, the mitigations outlined above do not prevent the side channels, but rather prevent malicious actors from controlling speculation in order to put victim data into the channel in the first place. For example, a branch target injection attack that uses segment registers as a side channel (instead of using the data caches as the original branch target injection attack did) should be mitigated by preventing branch target injection attacks in general (for example, through retpoline or indirect branch restricted speculation (IBRS)) instead of attempting to address the specific channel (in this case, segment registers).
The unused segment register file entry may contain information from previously run applications or guests. Most segment bases are zero except for segments used for thread local storage (FS and GS). Intel does not believe that these segment bases are application secrets and does not recommend mitigating this information leakage.
The segment register file entries for a segment can be overwritten with the specified data by a pair of
POP xS, or
LGS instructions that write that segment on at least Intel® microarchitecture code name Sandy Bridge and later processors. Loading a null segment selector may be lower latency than loading a segment from a descriptor table.
SWAPGS being executed after ring transitions, applications cannot observe the GS value from previous applications, but they may be able to infer the kernel GS base.
Intel recommends that you always keep your systems up to date with the latest security updates and guidance from your OS and VMM vendors.
Intel expects the following products are potentially affected by these issues:
|Family/Model||Step||Processor Families /
Processor Number Series
|Segment Register Write||SWAPGS
Missed (Spectre V1 Variant)
(Spectre V1 Variant)
|06_2EH||All||Intel® Xeon® processor 7500, 6500 series (Nehalem-EX)||Yes||Yes||Yes|
|All||Intel® Core™ i7 and i5 Processors (Nehalem, Nehalem-G)||Yes||Yes||Yes|
|06_1AH||All||Intel® Core™ i7 Processor, Intel Xeon processor 3400, 3500, 5500 series (Nehalem-EP)||Yes||Yes||Yes|
|06_2FH||All||Intel® Xeon® Processor E7 Family (Westmere-EX)||Yes||Yes||Yes|
|All||Intel® Xeon® processors 3600, 5600 series, Intel® Core™ i7, i5 and i3 Processors (Westmere, Westmere-EP)||Yes||Yes||Yes|
|06_2DH||All||Intel® Xeon® processor E5 Family based on Intel microarchitecture code name Sandy Bridge, Intel® Core™ i7-39xx Processor Extreme Edition||Yes||Yes||Yes|
|06_2AH||All||Intel® Xeon® processor E3-1200 product family; 2nd Generation Intel® Core™ i7, i5, i3 Processors 2xxx Series (Sandy Bridge)||Yes||Yes||Yes|
|06_3EH||All||Intel® Xeon® processor E7-8800/4800/2800 v2 product families based on Ivy Bridge-E microarchitecture||Yes||Yes||Yes|
|06_3EH||All||Intel® Xeon® processor E5-2600/1600 v2 product families and Intel® Xeon® processor E5-2400 v2 product family based on Ivy Bridge-E microarchitecture, Intel® Core™ i7-49xx Processor Extreme Edition||Yes||Yes||Yes|
|06_3AH||All||3rd Generation Intel® Core™ Processor and Intel® Xeon® processor E3-1200 v2 product family based on Ivy Bridge microarchitecture||Yes||Yes||Yes|
|06_3FH||All||Intel® Xeon® processor E5-4600/2600/1600 v3 product families, Intel® Xeon® processor E7 v3 product families based on Haswell-E microarchitecture, Intel® Core™ i7-59xx Processor Extreme Edition||Yes||Yes||Yes|
|All||4th Generation Intel® Core™ processor and Intel® Xeon® processor E3-1200 v3 product family based on Haswell microarchitecture||Yes||Yes||Yes|
|06_56H||All||Intel® Xeon® processor D-1500 product family based on Broadwell microarchitecture||Yes||Yes||Yes|
|06_4FH||All||Intel® Xeon® processor E5 v4 Family based on Broadwell microarchitecture, Intel® Xeon® processor E7 v4 Family, Intel® Core™ i7-69xx Processor Extreme Edition||Yes||Yes||Yes|
|06_47H||All||5th generation Intel® Core™ processors, Intel® Xeon® processor E3-1200 v4 product family based on Broadwell microarchitecture||Yes||Yes||Yes|
|06_3DH||All||Intel® Core™ M-5xxx Processor, 5th generation Intel® Core™ processors based on Broadwell microarchitecture||Yes||Yes||Yes|
|06_55H||<=4||Intel® Xeon® Processor Scalable Family based on Skylake microarchitecture||Yes||Yes||Yes|
|All||6th generation Intel® Core™ processors and Intel® Xeon® processor E3-1500m v5 product family and E3- 1200 v5 product family based on Skylake microarchitecture||Yes||Yes||Yes|
|06_8EH||<=A||7th/8th generation Intel® Core™ processors based on Kaby/Coffee Lake microarchitecture||Yes||Yes||Yes|
|06_9EH||<=B||7th/8th generation Intel® Core™ processors based on Kaby/Coffee Lake microarchitecture||Yes||Yes||Yes|
|06_9E||0xC||8th generation Intel® Core™ processors based on Coffee Lake microarchitecture||Yes||Yes||Yes|
|06_8E||0xC||Whiskey Lake (ULT refresh)||Yes||Yes||Yes|
|06_9E||0xD||Whiskey Lake (Desktop||Yes||Yes||Yes|
|06_55H||5||2nd Generation Intel® Xeon® Scalable Processors based on Cascade Lake microarchitecture||Yes||Yes||Yes|
|06_55H||6, 7||2nd Generation Intel® Xeon® Scalable Processors based on Cascade Lake microarchitecture||Yes||Yes||Yes|
|All||Intel Atom® processors based on the Bonnell, Saltwell, Silvermont, Airmont, Goldmont, and GoldmontPlus microarchitectures||No||Yes||No|
|All||Intel® Xeon Phi™ processors based on the Knights Mill, Knights Landing, and Knights Corner microarchitectures||No||Yes||No|
Intel thanks the Linux kernel community and other industry partners who have contributed significantly to mitigations for speculative execution side channel methods, and recognizes the following people for their development efforts and dedication to software security: