Fix for the swap offset calculation in the x86_64 "vm -p", "pte", and

user-space "vtop" commands.  The swap offset bits in an x86_64 PTE
were changed in Linux 4.6, and then again in Linux 4.18.1 with the
new L1TF security patchset.  Without the patch, the offset value
in the later kernels, or in older kernels with an L1TF backport,
show an incorrect swap offset value.
(anderson@redhat.com)
This commit is contained in:
Dave Anderson 2018-08-21 14:39:18 -04:00
parent 4ae70cc811
commit 3fcb69b9ae
2 changed files with 61 additions and 2 deletions

7
defs.h
View File

@ -3478,8 +3478,8 @@ struct arm64_stackframe {
#define SWP_TYPE(entry) (((entry) >> 1) & 0x3f)
#define SWP_OFFSET(entry) ((entry) >> 8)
#define __swp_type(entry) SWP_TYPE(entry)
#define __swp_offset(entry) SWP_OFFSET(entry)
#define __swp_type(entry) x86_64_swp_type(entry)
#define __swp_offset(entry) x86_64_swp_offset(entry)
#define TIF_SIGPENDING (2)
@ -5725,6 +5725,8 @@ void x86_64_dump_machdep_table(ulong);
ulong x86_64_PTOV(ulong);
ulong x86_64_VTOP(ulong);
int x86_64_IS_VMALLOC_ADDR(ulong);
ulong x86_64_swp_type(ulong);
ulong x86_64_swp_offset(ulong);
void x86_64_display_idt_table(void);
#define display_idt_table() x86_64_display_idt_table()
long x86_64_exception_frame(ulong, ulong, char *, struct bt_info *, FILE *);
@ -5864,6 +5866,7 @@ struct machine_specific {
#define VM_5LEVEL (0x2000)
#define ORC (0x4000)
#define KPTI (0x8000)
#define L1TF (0x10000)
#define VM_FLAGS (VM_ORIG|VM_2_6_11|VM_XEN|VM_XEN_RHEL4|VM_5LEVEL)

View File

@ -89,6 +89,7 @@ static void x86_64_init_kernel_pgd(void);
static void x86_64_cpu_pda_init(void);
static void x86_64_per_cpu_init(void);
static void x86_64_ist_init(void);
static void x86_64_l1tf_init(void);
static void x86_64_irq_stack_gap_init(void);
static void x86_64_entry_trampoline_init(void);
static void x86_64_post_init(void);
@ -694,6 +695,7 @@ x86_64_init(int when)
x86_64_framepointer_init();
x86_64_ORC_init();
x86_64_thread_return_init();
x86_64_l1tf_init();
if (THIS_KERNEL_VERSION >= LINUX(2,6,28))
machdep->machspec->page_protnone = _PAGE_GLOBAL;
@ -774,6 +776,8 @@ x86_64_dump_machdep_table(ulong arg)
fprintf(fp, "%sRANDOMIZED", others++ ? "|" : "");
if (machdep->flags & KPTI)
fprintf(fp, "%sKPTI", others++ ? "|" : "");
if (machdep->flags & L1TF)
fprintf(fp, "%sL1TF", others++ ? "|" : "");
fprintf(fp, ")\n");
fprintf(fp, " kvbase: %lx\n", machdep->kvbase);
@ -1504,6 +1508,17 @@ x86_64_irq_stack_gap_init(void)
}
}
/*
* Check kernel version and/or backport for L1TF
*/
static void
x86_64_l1tf_init(void)
{
if (THIS_KERNEL_VERSION >= LINUX(4,18,1) ||
kernel_symbol_exists("l1tf_mitigation"))
machdep->flags |= L1TF;
}
static void
x86_64_post_init(void)
{
@ -9062,4 +9077,45 @@ x86_64_in_kpti_entry_stack(int cpu, ulong rsp)
return 0;
}
/*
* Original:
*
* #define SWP_TYPE(entry) (((entry) >> 1) & 0x3f)
* #define SWP_OFFSET(entry) ((entry) >> 8)
*
* 4.8:
* | OFFSET (14-63) | TYPE (9-13) |0|X|X|X| X| X|X|X|0|
*
* l1tf:
* | ... | 11| 10| 9|8|7|6|5| 4| 3|2| 1|0| <- bit number
* | ... |SW3|SW2|SW1|G|L|D|A|CD|WT|U| W|P| <- bit names
* | TYPE (59-63) | ~OFFSET (9-58) |0|0|X|X| X| X|X|SD|0| <- swp entry
*/
ulong
x86_64_swp_type(ulong entry)
{
if (machdep->flags & L1TF)
return(entry >> 59);
if (THIS_KERNEL_VERSION >= LINUX(4,8,0))
return((entry >> 9) & 0x1f);
return SWP_TYPE(entry);
}
ulong
x86_64_swp_offset(ulong entry)
{
if (machdep->flags & L1TF)
return((~entry << 5) >> 14);
if (THIS_KERNEL_VERSION >= LINUX(4,8,0))
return(entry >> 14);
return SWP_OFFSET(entry);
}
#endif /* X86_64 */