Skip to content

Commit

Permalink
MIPS: vDSO: Fix Malta EVA mapping to vDSO page structs
Browse files Browse the repository at this point in the history
The page structures associated with the vDSO pages in the kernel image
are calculated using virt_to_page(), which uses __pa() under the hood to
find the pfn associated with the virtual address. The vDSO data pointers
however point to kernel symbols, so __pa_symbol() should really be used
instead.

Since there is no equivalent to virt_to_page() which uses __pa_symbol(),
fix init_vdso_image() to work directly with pfns, calculated with
__phys_to_pfn(__pa_symbol(...)).

This issue broke the Malta Enhanced Virtual Addressing (EVA)
configuration which has a non-default implementation of __pa_symbol().
This is because it uses a physical alias so that the kernel executes
from KSeg0 (VA 0x80000000 -> PA 0x00000000), while RAM is provided to
the kernel in the KUSeg range (VA 0x00000000 -> PA 0x80000000) which
uses the same underlying RAM.

Since there are no page structures associated with the low physical
address region, some arbitrary kernel memory would be interpreted as a
page structure for the vDSO pages and badness ensues.

Fixes: ebb5e78 ("MIPS: Initial implementation of a VDSO")
Signed-off-by: James Hogan <[email protected]>
Cc: Leonid Yegoshin <[email protected]>
Cc: [email protected]
Cc: <[email protected]> # 4.4.x-
Patchwork: https://patchwork.linux-mips.org/patch/14229/
Signed-off-by: Ralf Baechle <[email protected]>
  • Loading branch information
James Hogan authored and ralfbaechle committed Sep 21, 2016
1 parent 08bccf4 commit 554af0c
Showing 1 changed file with 4 additions and 4 deletions.
8 changes: 4 additions & 4 deletions arch/mips/kernel/vdso.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,16 @@ static struct vm_special_mapping vdso_vvar_mapping = {
static void __init init_vdso_image(struct mips_vdso_image *image)
{
unsigned long num_pages, i;
unsigned long data_pfn;

BUG_ON(!PAGE_ALIGNED(image->data));
BUG_ON(!PAGE_ALIGNED(image->size));

num_pages = image->size / PAGE_SIZE;

for (i = 0; i < num_pages; i++) {
image->mapping.pages[i] =
virt_to_page(image->data + (i * PAGE_SIZE));
}
data_pfn = __phys_to_pfn(__pa_symbol(image->data));
for (i = 0; i < num_pages; i++)
image->mapping.pages[i] = pfn_to_page(data_pfn + i);
}

static int __init init_vdso(void)
Expand Down

0 comments on commit 554af0c

Please sign in to comment.