Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bfad381c authored by Andy Lutomirski's avatar Andy Lutomirski Committed by H. Peter Anvin
Browse files

x86/vdso: Improve the fake section headers



Fully stripping the vDSO has other unfortunate side effects:

 - binutils is unable to find ELF notes without a SHT_NOTE section.

 - Even elfutils has trouble: it can find ELF notes without a section
   table at all, but if a section table is present, it won't look for
   PT_NOTE.

 - gdb wants section names to match between stripped DSOs and their
   symbols; otherwise it will corrupt symbol addresses.

We're also breaking the rules: section 0 is supposed to be SHT_NULL.

Fix these problems by building a better fake section table.  While
we're at it, we might as well let buggy Go versions keep working well
by giving the SHT_DYNSYM entry the correct size.

This is a bit unfortunate: it adds quite a bit of size to the vdso
image.

If/when binutils improves and the improved versions become widespread,
it would be worth considering dropping most of this.

Signed-off-by: default avatarAndy Lutomirski <luto@amacapital.net>
Link: http://lkml.kernel.org/r/0e546a5eeaafdf1840e6ee654a55c1e727c26663.1403129369.git.luto@amacapital.net


Signed-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
parent c1979c37
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -11,7 +11,6 @@ VDSO32-$(CONFIG_COMPAT) := y

# files to link into the vdso
vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o vdso-fakesections.o
vobjs-nox32 := vdso-fakesections.o

# files to link into kernel
obj-y				+= vma.o
@@ -134,7 +133,7 @@ override obj-dirs = $(dir $(obj)) $(obj)/vdso32/

targets += vdso32/vdso32.lds
targets += vdso32/note.o vdso32/vclock_gettime.o $(vdso32.so-y:%=vdso32/%.o)
targets += vdso32/vclock_gettime.o
targets += vdso32/vclock_gettime.o vdso32/vdso-fakesections.o

$(obj)/vdso32.o: $(vdso32-images:%=$(obj)/%)

@@ -155,6 +154,7 @@ $(vdso32-images:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32)
$(vdso32-images:%=$(obj)/%.dbg): $(obj)/vdso32-%.so.dbg: FORCE \
				 $(obj)/vdso32/vdso32.lds \
				 $(obj)/vdso32/vclock_gettime.o \
				 $(obj)/vdso32/vdso-fakesections.o \
				 $(obj)/vdso32/note.o \
				 $(obj)/vdso32/%.o
	$(call if_changed,vdso)
+18 −26
Original line number Diff line number Diff line
@@ -2,31 +2,23 @@
 * Copyright 2014 Andy Lutomirski
 * Subject to the GNU Public License, v.2
 *
 * Hack to keep broken Go programs working.
 *
 * The Go runtime had a couple of bugs: it would read the section table to try
 * to figure out how many dynamic symbols there were (it shouldn't have looked
 * at the section table at all) and, if there were no SHT_SYNDYM section table
 * entry, it would use an uninitialized value for the number of symbols.  As a
 * workaround, we supply a minimal section table.  vdso2c will adjust the
 * in-memory image so that "vdso_fake_sections" becomes the section table.
 *
 * The bug was introduced by:
 * https://code.google.com/p/go/source/detail?r=56ea40aac72b (2012-08-31)
 * and is being addressed in the Go runtime in this issue:
 * https://code.google.com/p/go/issues/detail?id=8197
 * String table for loadable section headers.  See vdso2c.h for why
 * this exists.
 */

#ifndef __x86_64__
#error This hack is specific to the 64-bit vDSO
#endif

#include <linux/elf.h>

extern const __visible struct elf64_shdr vdso_fake_sections[];
const __visible struct elf64_shdr vdso_fake_sections[] = {
	{
		.sh_type = SHT_DYNSYM,
		.sh_entsize = sizeof(Elf64_Sym),
	}
};
const char fake_shstrtab[] __attribute__((section(".fake_shstrtab"))) =
	".hash\0"
	".dynsym\0"
	".dynstr\0"
	".gnu.version\0"
	".gnu.version_d\0"
	".dynamic\0"
	".rodata\0"
	".fake_shstrtab\0"  /* Yay, self-referential code. */
	".note\0"
	".data\0"
	".altinstructions\0"
	".altinstr_replacement\0"
	".eh_frame_hdr\0"
	".eh_frame\0"
	".text";
+32 −8
Original line number Diff line number Diff line
@@ -6,6 +6,16 @@
 * This script controls its layout.
 */

#if defined(BUILD_VDSO64)
# define SHDR_SIZE 64
#elif defined(BUILD_VDSO32) || defined(BUILD_VDSOX32)
# define SHDR_SIZE 40
#else
# error unknown VDSO target
#endif

#define NUM_FAKE_SHDRS 16

SECTIONS
{
	. = SIZEOF_HEADERS;
@@ -25,7 +35,21 @@ SECTIONS

	.dynamic	: { *(.dynamic) }		:text	:dynamic

	.rodata		: { *(.rodata*) }		:text
	.rodata		: {
		*(.rodata*)

		/*
		 * Ideally this would live in a C file, but that won't
		 * work cleanly for x32 until we start building the x32
		 * C code using an x32 toolchain.
		 */
		VDSO_FAKE_SECTION_TABLE_START = .;
		. = . + NUM_FAKE_SHDRS * SHDR_SIZE;
		VDSO_FAKE_SECTION_TABLE_END = .;
	}						:text

	.fake_shstrtab	: { *(.fake_shstrtab) }		:text

	.data		: {
		*(.data*)
		*(.sdata*)
+2 −0
Original line number Diff line number Diff line
@@ -6,6 +6,8 @@
 * the DSO.
 */

#define BUILD_VDSO64

#include "vdso-layout.lds.S"

/*
+22 −9
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ enum {
	sym_vvar_page,
	sym_hpet_page,
	sym_end_mapping,
	sym_VDSO_FAKE_SECTION_TABLE_START,
	sym_VDSO_FAKE_SECTION_TABLE_END,
};

const int special_pages[] = {
@@ -30,15 +32,26 @@ const int special_pages[] = {
	sym_hpet_page,
};

char const * const required_syms[] = {
	[sym_vvar_page] = "vvar_page",
	[sym_hpet_page] = "hpet_page",
	[sym_end_mapping] = "end_mapping",
	"VDSO32_NOTE_MASK",
	"VDSO32_SYSENTER_RETURN",
	"__kernel_vsyscall",
	"__kernel_sigreturn",
	"__kernel_rt_sigreturn",
struct vdso_sym {
	const char *name;
	bool export;
};

struct vdso_sym required_syms[] = {
	[sym_vvar_page] = {"vvar_page", true},
	[sym_hpet_page] = {"hpet_page", true},
	[sym_end_mapping] = {"end_mapping", true},
	[sym_VDSO_FAKE_SECTION_TABLE_START] = {
		"VDSO_FAKE_SECTION_TABLE_START", false
	},
	[sym_VDSO_FAKE_SECTION_TABLE_END] = {
		"VDSO_FAKE_SECTION_TABLE_END", false
	},
	{"VDSO32_NOTE_MASK", true},
	{"VDSO32_SYSENTER_RETURN", true},
	{"__kernel_vsyscall", true},
	{"__kernel_sigreturn", true},
	{"__kernel_rt_sigreturn", true},
};

__attribute__((format(printf, 1, 2))) __attribute__((noreturn))
Loading