|
415 | 415 |
|
416 | 416 | .macro CHECK_AND_APPLY_ESPFIX
|
417 | 417 | #ifdef CONFIG_X86_ESPFIX32
|
418 |
| -#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + (GDT_ENTRY_ESPFIX_SS * 8) |
| 418 | +#define GDT_ESPFIX_OFFSET (GDT_ENTRY_ESPFIX_SS * 8) |
| 419 | +#define GDT_ESPFIX_SS PER_CPU_VAR(gdt_page) + GDT_ESPFIX_OFFSET |
419 | 420 |
|
420 | 421 | ALTERNATIVE "jmp .Lend_\@", "", X86_BUG_ESPFIX
|
421 | 422 |
|
@@ -1147,12 +1148,26 @@ ENDPROC(entry_INT80_32)
|
1147 | 1148 | * We can't call C functions using the ESPFIX stack. This code reads
|
1148 | 1149 | * the high word of the segment base from the GDT and swiches to the
|
1149 | 1150 | * normal stack and adjusts ESP with the matching offset.
|
| 1151 | + * |
| 1152 | + * We might be on user CR3 here, so percpu data is not mapped and we can't |
| 1153 | + * access the GDT through the percpu segment. Instead, use SGDT to find |
| 1154 | + * the cpu_entry_area alias of the GDT. |
1150 | 1155 | */
|
1151 | 1156 | #ifdef CONFIG_X86_ESPFIX32
|
1152 | 1157 | /* fixup the stack */
|
1153 |
| - mov GDT_ESPFIX_SS + 4, %al /* bits 16..23 */ |
1154 |
| - mov GDT_ESPFIX_SS + 7, %ah /* bits 24..31 */ |
| 1158 | + pushl %ecx |
| 1159 | + subl $2*4, %esp |
| 1160 | + sgdt (%esp) |
| 1161 | + movl 2(%esp), %ecx /* GDT address */ |
| 1162 | + /* |
| 1163 | + * Careful: ECX is a linear pointer, so we need to force base |
| 1164 | + * zero. %cs is the only known-linear segment we have right now. |
| 1165 | + */ |
| 1166 | + mov %cs:GDT_ESPFIX_OFFSET + 4(%ecx), %al /* bits 16..23 */ |
| 1167 | + mov %cs:GDT_ESPFIX_OFFSET + 7(%ecx), %ah /* bits 24..31 */ |
1155 | 1168 | shl $16, %eax
|
| 1169 | + addl $2*4, %esp |
| 1170 | + popl %ecx |
1156 | 1171 | addl %esp, %eax /* the adjusted stack pointer */
|
1157 | 1172 | pushl $__KERNEL_DS
|
1158 | 1173 | pushl %eax
|
|
0 commit comments