mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-01-10 18:04:04 -05:00
arm64/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. Signed-off-by: Andrei Vagin <avagin@gmail.com> Reviewed-by: Vincenzo Frascino <vincenzo.frascino@arm.com> Reviewed-by: Dmitry Safonov <dima@arista.com> Link: https://lore.kernel.org/r/20200624083321.144975-5-avagin@gmail.com Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:
committed by
Catalin Marinas
parent
3503d56cc7
commit
ee3cda8e46
@@ -18,6 +18,7 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/time_namespace.h>
|
||||
#include <linux/timekeeper_internal.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <vdso/datapage.h>
|
||||
@@ -164,15 +165,62 @@ int vdso_join_timens(struct task_struct *task, struct time_namespace *ns)
|
||||
mmap_read_unlock(mm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 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)
|
||||
{
|
||||
if (vmf->pgoff == 0)
|
||||
return vmf_insert_pfn(vma, vmf->address,
|
||||
sym_to_pfn(vdso_data));
|
||||
return VM_FAULT_SIGBUS;
|
||||
struct page *timens_page = find_timens_vvar_page(vma);
|
||||
unsigned long pfn;
|
||||
|
||||
switch (vmf->pgoff) {
|
||||
case VVAR_DATA_PAGE_OFFSET:
|
||||
if (timens_page)
|
||||
pfn = page_to_pfn(timens_page);
|
||||
else
|
||||
pfn = sym_to_pfn(vdso_data);
|
||||
break;
|
||||
#ifdef CONFIG_TIME_NS
|
||||
case VVAR_TIMENS_PAGE_OFFSET:
|
||||
/*
|
||||
* If a task belongs to a time namespace then a namespace
|
||||
* specific VVAR is mapped with the VVAR_DATA_PAGE_OFFSET and
|
||||
* the real VVAR page is mapped with the VVAR_TIMENS_PAGE_OFFSET
|
||||
* offset.
|
||||
* See also the comment near timens_setup_vdso_data().
|
||||
*/
|
||||
if (!timens_page)
|
||||
return VM_FAULT_SIGBUS;
|
||||
pfn = sym_to_pfn(vdso_data);
|
||||
break;
|
||||
#endif /* CONFIG_TIME_NS */
|
||||
default:
|
||||
return VM_FAULT_SIGBUS;
|
||||
}
|
||||
|
||||
return vmf_insert_pfn(vma, vmf->address, pfn);
|
||||
}
|
||||
|
||||
static int __setup_additional_pages(enum vdso_abi abi,
|
||||
|
||||
Reference in New Issue
Block a user