Re: vdso handling

Pedro Alves
2014-03-13T14:59:36Z

On 03/13/2014 01:03 PM, Alan Modra wrote:
> On Thu, Mar 13, 2014 at 10:52:16AM +0100, Mark Wielaard wrote:
>> On Thu, 2014-03-13 at 11:31 +1030, Alan Modra wrote:
>>> It wouldn't
>>> help in the vdso case anyway, since the problem there is that you only
>>> have the loaded part of the original ELF file.
>>
>> Note that the vdso is often special, compared to other ELF dsos, because
>> the loaded part is just the complete ELF image in memory. Since they are
>> very simple they will just have one PT_LOAD at offset zero and if the
>> image is smaller than the page size then the whole file is just simply
>> mapped into memory completely. So by fetching the vdso ELF image from
>> remote memory you should be able to get the section headers and the
>> not-allocated sections too.
>
> Yes, but if the vdso does not fit in a page (which incidentally is
> inferred by program header p_align), then you may lose the section
> headers. I was assuming this was the case.

Hmm. How so? On x86 (arch/x86/vdso/vdso.S), the kernel just does:

.globl vdso_start, vdso_end
.align PAGE_SIZE
vdso_start:
.incbin "arch/x86/vdso/vdso.so"
vdso_end:
.align PAGE_SIZE /* extra data here leaks to userspace. */

And then arch/x86/vdso/vma.c has:

static int __init init_vdso(void)
{
int npages = (vdso_end - vdso_start + PAGE_SIZE - 1) / PAGE_SIZE;
int i;

patch_vdso64(vdso_start, vdso_end - vdso_start);

vdso_size = npages << PAGE_SHIFT;
for (i = 0; i < npages; i++)
vdso_pages[i] = virt_to_page(vdso_start + i*PAGE_SIZE);

#ifdef CONFIG_X86_X32_ABI
patch_vdsox32(vdsox32_start, vdsox32_end - vdsox32_start);
npages = (vdsox32_end - vdsox32_start + PAGE_SIZE - 1) / PAGE_SIZE;
vdsox32_size = npages << PAGE_SHIFT;
for (i = 0; i < npages; i++)
vdsox32_pages[i] = virt_to_page(vdsox32_start + i*PAGE_SIZE);
#endif

return 0;
}

And patch_vdso64 _relies_ on sections being present at runtime:

static void __init patch_vdso64(void *vdso, size_t len)
{
Elf64_Ehdr *hdr = vdso;
Elf64_Shdr *sechdrs, *alt_sec = 0;
char *secstrings;
void *alt_data;
int i;

BUG_ON(len < sizeof(Elf64_Ehdr));
BUG_ON(memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0);

sechdrs = (void *)hdr + hdr->e_shoff;
secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;

for (i = 1; i < hdr->e_shnum; i++) {
Elf64_Shdr *shdr = &sechdrs[i];
if (!strcmp(secstrings + shdr->sh_name, ".altinstructions")) {
alt_sec = shdr;
goto found;
}
}

/* If we get here, it's probably a bug. */
pr_warning("patch_vdso64: .altinstructions not found\n");
return; /* nothing to patch */

found:
alt_data = (void *)hdr + alt_sec->sh_offset;
apply_alternatives(alt_data, alt_data + alt_sec->sh_size);
}

On e.g., arch/powerpc/kernel/vdso.c, I see even a lot more
code looking at the sections of the vdso.

--
Pedro Alves