x86/vdso: Handle faults on timens page
If a task belongs to a time namespace then the VVAR page which contains the system wide VDSO data is replaced with a namespace specific page which has the same layout as the VVAR page. Co-developed-by: Andrei Vagin <avagin@gmail.com> Signed-off-by: Andrei Vagin <avagin@gmail.com> Signed-off-by: Dmitry Safonov <dima@arista.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/r/20191112012724.250792-25-dima@arista.com
This commit is contained in:
parent
afaa7b5ac7
commit
af34ebeb86
|
@ -14,11 +14,14 @@
|
|||
#include <linux/elf.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/time_namespace.h>
|
||||
|
||||
#include <asm/pvclock.h>
|
||||
#include <asm/vgtod.h>
|
||||
#include <asm/proto.h>
|
||||
#include <asm/vdso.h>
|
||||
#include <asm/vvar.h>
|
||||
#include <asm/tlb.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/desc.h>
|
||||
#include <asm/cpufeature.h>
|
||||
|
@ -107,10 +110,36 @@ static int vvar_mremap(const struct vm_special_mapping *sm,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TIME_NS
|
||||
static struct page *find_timens_vvar_page(struct vm_area_struct *vma)
|
||||
{
|
||||
if (likely(vma->vm_mm == current->mm))
|
||||
return current->nsproxy->time_ns->vvar_page;
|
||||
|
||||
/*
|
||||
* VM_PFNMAP | VM_IO protect .fault() handler from being called
|
||||
* through interfaces like /proc/$pid/mem or
|
||||
* process_vm_{readv,writev}() as long as there's no .access()
|
||||
* in special_mapping_vmops().
|
||||
* For more details check_vma_flags() and __access_remote_vm()
|
||||
*/
|
||||
|
||||
WARN(1, "vvar_page accessed remotely");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static inline struct page *find_timens_vvar_page(struct vm_area_struct *vma)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
|
||||
struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
const struct vdso_image *image = vma->vm_mm->context.vdso_image;
|
||||
unsigned long pfn;
|
||||
long sym_offset;
|
||||
|
||||
if (!image)
|
||||
|
@ -130,8 +159,21 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
|
|||
return VM_FAULT_SIGBUS;
|
||||
|
||||
if (sym_offset == image->sym_vvar_page) {
|
||||
return vmf_insert_pfn(vma, vmf->address,
|
||||
__pa_symbol(&__vvar_page) >> PAGE_SHIFT);
|
||||
struct page *timens_page = find_timens_vvar_page(vma);
|
||||
|
||||
pfn = __pa_symbol(&__vvar_page) >> PAGE_SHIFT;
|
||||
|
||||
/*
|
||||
* If a task belongs to a time namespace then a namespace
|
||||
* specific VVAR is mapped with the sym_vvar_page offset and
|
||||
* the real VVAR page is mapped with the sym_timens_page
|
||||
* offset.
|
||||
* See also the comment near timens_setup_vdso_data().
|
||||
*/
|
||||
if (timens_page)
|
||||
pfn = page_to_pfn(timens_page);
|
||||
|
||||
return vmf_insert_pfn(vma, vmf->address, pfn);
|
||||
} else if (sym_offset == image->sym_pvclock_page) {
|
||||
struct pvclock_vsyscall_time_info *pvti =
|
||||
pvclock_get_pvti_cpu0_va();
|
||||
|
@ -146,6 +188,14 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
|
|||
if (tsc_pg && vclock_was_used(VCLOCK_HVCLOCK))
|
||||
return vmf_insert_pfn(vma, vmf->address,
|
||||
virt_to_phys(tsc_pg) >> PAGE_SHIFT);
|
||||
} else if (sym_offset == image->sym_timens_page) {
|
||||
struct page *timens_page = find_timens_vvar_page(vma);
|
||||
|
||||
if (!timens_page)
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
||||
pfn = __pa_symbol(&__vvar_page) >> PAGE_SHIFT;
|
||||
return vmf_insert_pfn(vma, vmf->address, pfn);
|
||||
}
|
||||
|
||||
return VM_FAULT_SIGBUS;
|
||||
|
|
|
@ -3342,6 +3342,8 @@ static const struct vm_operations_struct special_mapping_vmops = {
|
|||
.fault = special_mapping_fault,
|
||||
.mremap = special_mapping_mremap,
|
||||
.name = special_mapping_name,
|
||||
/* vDSO code relies that VVAR can't be accessed remotely */
|
||||
.access = NULL,
|
||||
};
|
||||
|
||||
static const struct vm_operations_struct legacy_special_mapping_vmops = {
|
||||
|
|
Loading…
Reference in New Issue