vdso handling

Pedro Alves palves@redhat.com
Thu Mar 13 14:59:00 GMT 2014


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



More information about the Gdb mailing list