Re: vdso handling

Pedro Alves <[email protected]>
Newsgroups gmane.comp.gdb.devel,gmane.comp.gnu.binutils
Message-ID <[email protected]>
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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.