x86/vdso: Use ->fault() instead of remap_pfn_range() for the vvar mapping
This is IMO much less ugly, and it also opens the door to disallowing unprivileged userspace HPET access on systems with usable TSCs. Signed-off-by: Andy Lutomirski <luto@kernel.org> Reviewed-by: Kees Cook <keescook@chromium.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Borislav Petkov <bp@alien8.de> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: Fenghua Yu <fenghua.yu@intel.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Quentin Casasnovas <quentin.casasnovas@oracle.com> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/c19c2909e5ee3c3d8742f916586676bb7c40345f.1451446564.git.luto@kernel.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
05ef76b20f
commit
a48a704261
|
@ -102,18 +102,69 @@ static const struct vm_special_mapping text_mapping = {
|
||||||
.fault = vdso_fault,
|
.fault = vdso_fault,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int 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;
|
||||||
|
long sym_offset;
|
||||||
|
int ret = -EFAULT;
|
||||||
|
|
||||||
|
if (!image)
|
||||||
|
return VM_FAULT_SIGBUS;
|
||||||
|
|
||||||
|
sym_offset = (long)(vmf->pgoff << PAGE_SHIFT) +
|
||||||
|
image->sym_vvar_start;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sanity check: a symbol offset of zero means that the page
|
||||||
|
* does not exist for this vdso image, not that the page is at
|
||||||
|
* offset zero relative to the text mapping. This should be
|
||||||
|
* impossible here, because sym_offset should only be zero for
|
||||||
|
* the page past the end of the vvar mapping.
|
||||||
|
*/
|
||||||
|
if (sym_offset == 0)
|
||||||
|
return VM_FAULT_SIGBUS;
|
||||||
|
|
||||||
|
if (sym_offset == image->sym_vvar_page) {
|
||||||
|
ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address,
|
||||||
|
__pa_symbol(&__vvar_page) >> PAGE_SHIFT);
|
||||||
|
} else if (sym_offset == image->sym_hpet_page) {
|
||||||
|
#ifdef CONFIG_HPET_TIMER
|
||||||
|
if (hpet_address) {
|
||||||
|
ret = vm_insert_pfn_prot(
|
||||||
|
vma,
|
||||||
|
(unsigned long)vmf->virtual_address,
|
||||||
|
hpet_address >> PAGE_SHIFT,
|
||||||
|
pgprot_noncached(PAGE_READONLY));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (sym_offset == image->sym_pvclock_page) {
|
||||||
|
struct pvclock_vsyscall_time_info *pvti =
|
||||||
|
pvclock_pvti_cpu0_va();
|
||||||
|
if (pvti) {
|
||||||
|
ret = vm_insert_pfn(
|
||||||
|
vma,
|
||||||
|
(unsigned long)vmf->virtual_address,
|
||||||
|
__pa(pvti) >> PAGE_SHIFT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0 || ret == -EBUSY)
|
||||||
|
return VM_FAULT_NOPAGE;
|
||||||
|
|
||||||
|
return VM_FAULT_SIGBUS;
|
||||||
|
}
|
||||||
|
|
||||||
static int map_vdso(const struct vdso_image *image, bool calculate_addr)
|
static int map_vdso(const struct vdso_image *image, bool calculate_addr)
|
||||||
{
|
{
|
||||||
struct mm_struct *mm = current->mm;
|
struct mm_struct *mm = current->mm;
|
||||||
struct vm_area_struct *vma;
|
struct vm_area_struct *vma;
|
||||||
unsigned long addr, text_start;
|
unsigned long addr, text_start;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
static struct page *no_pages[] = {NULL};
|
static const struct vm_special_mapping vvar_mapping = {
|
||||||
static struct vm_special_mapping vvar_mapping = {
|
|
||||||
.name = "[vvar]",
|
.name = "[vvar]",
|
||||||
.pages = no_pages,
|
.fault = vvar_fault,
|
||||||
};
|
};
|
||||||
struct pvclock_vsyscall_time_info *pvti;
|
|
||||||
|
|
||||||
if (calculate_addr) {
|
if (calculate_addr) {
|
||||||
addr = vdso_addr(current->mm->start_stack,
|
addr = vdso_addr(current->mm->start_stack,
|
||||||
|
@ -153,7 +204,8 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
|
||||||
vma = _install_special_mapping(mm,
|
vma = _install_special_mapping(mm,
|
||||||
addr,
|
addr,
|
||||||
-image->sym_vvar_start,
|
-image->sym_vvar_start,
|
||||||
VM_READ|VM_MAYREAD,
|
VM_READ|VM_MAYREAD|VM_IO|VM_DONTDUMP|
|
||||||
|
VM_PFNMAP,
|
||||||
&vvar_mapping);
|
&vvar_mapping);
|
||||||
|
|
||||||
if (IS_ERR(vma)) {
|
if (IS_ERR(vma)) {
|
||||||
|
@ -161,41 +213,6 @@ static int map_vdso(const struct vdso_image *image, bool calculate_addr)
|
||||||
goto up_fail;
|
goto up_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (image->sym_vvar_page)
|
|
||||||
ret = remap_pfn_range(vma,
|
|
||||||
text_start + image->sym_vvar_page,
|
|
||||||
__pa_symbol(&__vvar_page) >> PAGE_SHIFT,
|
|
||||||
PAGE_SIZE,
|
|
||||||
PAGE_READONLY);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
goto up_fail;
|
|
||||||
|
|
||||||
#ifdef CONFIG_HPET_TIMER
|
|
||||||
if (hpet_address && image->sym_hpet_page) {
|
|
||||||
ret = io_remap_pfn_range(vma,
|
|
||||||
text_start + image->sym_hpet_page,
|
|
||||||
hpet_address >> PAGE_SHIFT,
|
|
||||||
PAGE_SIZE,
|
|
||||||
pgprot_noncached(PAGE_READONLY));
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
goto up_fail;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
pvti = pvclock_pvti_cpu0_va();
|
|
||||||
if (pvti && image->sym_pvclock_page) {
|
|
||||||
ret = remap_pfn_range(vma,
|
|
||||||
text_start + image->sym_pvclock_page,
|
|
||||||
__pa(pvti) >> PAGE_SHIFT,
|
|
||||||
PAGE_SIZE,
|
|
||||||
PAGE_READONLY);
|
|
||||||
|
|
||||||
if (ret)
|
|
||||||
goto up_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
up_fail:
|
up_fail:
|
||||||
if (ret)
|
if (ret)
|
||||||
current->mm->context.vdso = NULL;
|
current->mm->context.vdso = NULL;
|
||||||
|
|
Loading…
Reference in New Issue