lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu,  1 Jun 2017 00:44:15 -0500
From:   Josh Poimboeuf <jpoimboe@...hat.com>
To:     x86@...nel.org
Cc:     linux-kernel@...r.kernel.org, live-patching@...r.kernel.org,
        Linus Torvalds <torvalds@...ux-foundation.org>,
        Andy Lutomirski <luto@...nel.org>, Jiri Slaby <jslaby@...e.cz>,
        Ingo Molnar <mingo@...nel.org>,
        "H. Peter Anvin" <hpa@...or.com>,
        Peter Zijlstra <peterz@...radead.org>
Subject: [RFC PATCH 09/10] extable: add undwarf table sorting ability to sorttable script

The undwarf table needs to be sorted at vmlinux link time, just like the
extable.  Extend sorttable's functionality to do so.

Signed-off-by: Josh Poimboeuf <jpoimboe@...hat.com>
---
 init/Kconfig            |   4 ++
 scripts/Makefile        |   2 +-
 scripts/link-vmlinux.sh |   7 +-
 scripts/sorttable.c     | 178 +++++++++++++++++++++++++-----------------------
 scripts/sorttable.h     |  71 ++++++++++---------
 5 files changed, 142 insertions(+), 120 deletions(-)

diff --git a/init/Kconfig b/init/Kconfig
index 1d3475f..4c096f0 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -25,6 +25,10 @@ config IRQ_WORK
 
 config BUILDTIME_EXTABLE_SORT
 	bool
+	select SORTTABLE
+
+config SORTTABLE
+	bool
 
 config THREAD_INFO_IN_TASK
 	bool
diff --git a/scripts/Makefile b/scripts/Makefile
index a7b700f..99c05de 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -15,7 +15,7 @@ hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
 hostprogs-$(CONFIG_LOGO)         += pnmtologo
 hostprogs-$(CONFIG_VT)           += conmakehash
 hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
-hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sorttable
+hostprogs-$(CONFIG_SORTTABLE)    += sorttable
 hostprogs-$(CONFIG_ASN1)	 += asn1_compiler
 hostprogs-$(CONFIG_MODULE_SIG)	 += sign-file
 hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
index 18dd369..f4eb9dc 100755
--- a/scripts/link-vmlinux.sh
+++ b/scripts/link-vmlinux.sh
@@ -154,7 +154,12 @@ mksysmap()
 
 sortextable()
 {
-	${objtree}/scripts/sorttable ${1}
+	${objtree}/scripts/sorttable ${1} extable
+}
+
+sortundwarf()
+{
+	${objtree}/scripts/sorttable ${1} undwarf
 }
 
 # Delete output files in case of error
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index 17324dd..299db227 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -1,5 +1,5 @@
 /*
- * sorttable.c: Sort the kernel's exception table
+ * sorttable.c: Sort vmlinux tables
  *
  * Copyright 2011 - 2012 Cavium, Inc.
  *
@@ -51,11 +51,10 @@
 #define EM_ARCV2	195
 #endif
 
-static int fd_map;	/* File descriptor for file being modified. */
-static int mmap_failed; /* Boolean flag. */
+static int fd_map = -1;	/* File descriptor for file being modified. */
+static int mmap_succeeded; /* Boolean flag. */
 static void *ehdr_curr; /* current ElfXX_Ehdr *  for resource cleanup */
 static struct stat sb;	/* Remember .st_size, etc. */
-static jmp_buf jmpenv;	/* setjmp/longjmp per-file error escape */
 
 /* setjmp() return values */
 enum {
@@ -64,20 +63,19 @@ enum {
 	SJ_SUCCEED
 };
 
+enum sectype {
+	SEC_TYPE_EXTABLE,
+	SEC_TYPE_UNDWARF,
+};
+
 /* Per-file resource cleanup when multiple files. */
 static void
 cleanup(void)
 {
-	if (!mmap_failed)
+	if (mmap_succeeded)
 		munmap(ehdr_curr, sb.st_size);
-	close(fd_map);
-}
-
-static void __attribute__((noreturn))
-fail_file(void)
-{
-	cleanup();
-	longjmp(jmpenv, SJ_FAIL);
+	if (fd_map >= 0)
+		close(fd_map);
 }
 
 /*
@@ -93,19 +91,20 @@ static void *mmap_file(char const *fname)
 	fd_map = open(fname, O_RDWR);
 	if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
 		perror(fname);
-		fail_file();
+		return NULL;
 	}
 	if (!S_ISREG(sb.st_mode)) {
 		fprintf(stderr, "not a regular file: %s\n", fname);
-		fail_file();
+		return NULL;
 	}
 	addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,
 		    fd_map, 0);
 	if (addr == MAP_FAILED) {
-		mmap_failed = 1;
 		fprintf(stderr, "Could not mmap file: %s\n", fname);
-		fail_file();
+		return NULL;
 	}
+	mmap_succeeded = 1;
+
 	return addr;
 }
 
@@ -166,7 +165,7 @@ static void (*w8)(uint64_t, uint64_t *);
 static void (*w)(uint32_t, uint32_t *);
 static void (*w2)(uint16_t, uint16_t *);
 
-typedef void (*table_sort_t)(char *, int);
+typedef void (*table_sort_t)(char *, size_t, size_t);
 
 /*
  * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
@@ -194,7 +193,7 @@ static inline unsigned int get_secindex(unsigned int shndx,
 
 /* 32 bit and 64 bit are very similar */
 #include "sorttable.h"
-#define SORTEXTABLE_64
+#define SORTTABLE_64
 #include "sorttable.h"
 
 static int compare_relative_table(const void *a, const void *b)
@@ -209,36 +208,33 @@ static int compare_relative_table(const void *a, const void *b)
 	return 0;
 }
 
-static void x86_sort_relative_table(char *extab_image, int image_size)
+static void sort_relative_extable(char *image, size_t image_size, size_t entsize)
 {
 	int i;
 
+	/*
+	 * Do the same thing the runtime sort does, first normalize to
+	 * being relative to the start of the section.
+	 */
 	i = 0;
 	while (i < image_size) {
-		uint32_t *loc = (uint32_t *)(extab_image + i);
-
+		uint32_t *loc = (uint32_t *)(image + i);
 		w(r(loc) + i, loc);
-		w(r(loc + 1) + i + 4, loc + 1);
-		w(r(loc + 2) + i + 8, loc + 2);
-
-		i += sizeof(uint32_t) * 3;
+		i += 4;
 	}
 
-	qsort(extab_image, image_size / 12, 12, compare_relative_table);
+	qsort(image, image_size / entsize, entsize, compare_relative_table);
 
+	/* Now denormalize. */
 	i = 0;
 	while (i < image_size) {
-		uint32_t *loc = (uint32_t *)(extab_image + i);
-
+		uint32_t *loc = (uint32_t *)(image + i);
 		w(r(loc) - i, loc);
-		w(r(loc + 1) - (i + 4), loc + 1);
-		w(r(loc + 2) - (i + 8), loc + 2);
-
-		i += sizeof(uint32_t) * 3;
+		i += 4;
 	}
 }
 
-static void sort_relative_table(char *extab_image, int image_size)
+static void sort_undwarf_table(char *image, size_t image_size, size_t entsize)
 {
 	int i;
 
@@ -248,34 +244,39 @@ static void sort_relative_table(char *extab_image, int image_size)
 	 */
 	i = 0;
 	while (i < image_size) {
-		uint32_t *loc = (uint32_t *)(extab_image + i);
+		uint32_t *loc = (uint32_t *)(image + i);
 		w(r(loc) + i, loc);
-		i += 4;
+		i += entsize;
 	}
 
-	qsort(extab_image, image_size / 8, 8, compare_relative_table);
+	qsort(image, image_size / entsize, entsize, compare_relative_table);
 
 	/* Now denormalize. */
 	i = 0;
 	while (i < image_size) {
-		uint32_t *loc = (uint32_t *)(extab_image + i);
+		uint32_t *loc = (uint32_t *)(image + i);
 		w(r(loc) - i, loc);
-		i += 4;
+		i += entsize;
 	}
 }
 
-static void
-do_file(char const *const fname)
+static int do_file(char const *const fname, enum sectype sectype)
 {
 	table_sort_t custom_sort;
-	Elf32_Ehdr *ehdr = mmap_file(fname);
+	Elf32_Ehdr *ehdr;
+	const char *secname, *sort_needed_var;
+	size_t entsize_32, entsize_64;
+
+	ehdr = mmap_file(fname);
+	if (!ehdr)
+		return -1;
 
 	ehdr_curr = ehdr;
 	switch (ehdr->e_ident[EI_DATA]) {
 	default:
 		fprintf(stderr, "unrecognized ELF data encoding %d: %s\n",
 			ehdr->e_ident[EI_DATA], fname);
-		fail_file();
+		return -1;
 		break;
 	case ELFDATA2LSB:
 		r = rle;
@@ -298,7 +299,7 @@ do_file(char const *const fname)
 	||  (r2(&ehdr->e_type) != ET_EXEC && r2(&ehdr->e_type) != ET_DYN)
 	||  ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
 		fprintf(stderr, "unrecognized ET_EXEC/ET_DYN file %s\n", fname);
-		fail_file();
+		return -1;
 	}
 
 	custom_sort = NULL;
@@ -306,11 +307,13 @@ do_file(char const *const fname)
 	default:
 		fprintf(stderr, "unrecognized e_machine %d %s\n",
 			r2(&ehdr->e_machine), fname);
-		fail_file();
-		break;
+		return -1;
 	case EM_386:
 	case EM_X86_64:
-		custom_sort = x86_sort_relative_table;
+		if (sectype == SEC_TYPE_EXTABLE) {
+			custom_sort = sort_relative_extable;
+			entsize_32 = entsize_64 = 12;
+		}
 		break;
 
 	case EM_S390:
@@ -318,7 +321,10 @@ do_file(char const *const fname)
 	case EM_PARISC:
 	case EM_PPC:
 	case EM_PPC64:
-		custom_sort = sort_relative_table;
+		if (sectype == SEC_TYPE_EXTABLE) {
+			custom_sort = sort_relative_extable;
+			entsize_32 = entsize_64 = 8;
+		}
 		break;
 	case EM_ARCOMPACT:
 	case EM_ARCV2:
@@ -326,23 +332,38 @@ do_file(char const *const fname)
 	case EM_MICROBLAZE:
 	case EM_MIPS:
 	case EM_XTENSA:
+		entsize_32 = 8;
+		entsize_64 = 16;
 		break;
 	}  /* end switch */
 
+	switch (sectype) {
+	case SEC_TYPE_EXTABLE:
+		secname = "__ex_table";
+		sort_needed_var = "main_extable_sort_needed";
+		break;
+	case SEC_TYPE_UNDWARF:
+		secname = ".undwarf";
+		custom_sort = sort_undwarf_table;
+		entsize_32 = entsize_64 = 16;
+		sort_needed_var = NULL;
+		break;
+	}
+
 	switch (ehdr->e_ident[EI_CLASS]) {
 	default:
 		fprintf(stderr, "unrecognized ELF class %d %s\n",
 			ehdr->e_ident[EI_CLASS], fname);
-		fail_file();
-		break;
+		return -1;
 	case ELFCLASS32:
 		if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr)
 		||  r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) {
 			fprintf(stderr,
 				"unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
-			fail_file();
+			return -1;
 		}
-		do32(ehdr, fname, custom_sort);
+		if (do32(ehdr, fname, secname, entsize_32, custom_sort, sort_needed_var))
+			return -1;
 		break;
 	case ELFCLASS64: {
 		Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr;
@@ -350,51 +371,40 @@ do_file(char const *const fname)
 		||  r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) {
 			fprintf(stderr,
 				"unrecognized ET_EXEC/ET_DYN file: %s\n", fname);
-			fail_file();
+			return -1;
 		}
-		do64(ghdr, fname, custom_sort);
+		if (do64(ghdr, fname, secname, entsize_64, custom_sort, sort_needed_var))
+			return -1;
 		break;
 	}
 	}  /* end switch */
 
 	cleanup();
+
+	return 0;
 }
 
 int
 main(int argc, char *argv[])
 {
-	int n_error = 0;  /* gcc-4.3.0 false positive complaint */
-	int i;
+	char *file;
+	enum sectype sectype;
 
-	if (argc < 2) {
-		fprintf(stderr, "usage: sorttable vmlinux...\n");
-		return 0;
+	if (argc != 3) {
+		fprintf(stderr, "usage: sorttable <object file> <extable|undwarf>\n");
+		return -1;
 	}
 
-	/* Process each file in turn, allowing deep failure. */
-	for (i = 1; i < argc; i++) {
-		char *file = argv[i];
-		int const sjval = setjmp(jmpenv);
-
-		switch (sjval) {
-		default:
-			fprintf(stderr, "internal error: %s\n", file);
-			exit(1);
-			break;
-		case SJ_SETJMP:    /* normal sequence */
-			/* Avoid problems if early cleanup() */
-			fd_map = -1;
-			ehdr_curr = NULL;
-			mmap_failed = 1;
-			do_file(file);
-			break;
-		case SJ_FAIL:    /* error in do_file or below */
-			++n_error;
-			break;
-		case SJ_SUCCEED:    /* premature success */
-			/* do nothing */
-			break;
-		}  /* end switch */
+	file = argv[1];
+
+	if (!strcmp(argv[2], "extable"))
+		sectype = SEC_TYPE_EXTABLE;
+	else if (!strcmp(argv[2], "undwarf"))
+		sectype = SEC_TYPE_UNDWARF;
+	else  {
+		fprintf(stderr, "unsupported section type %s\n", argv[2]);
+		return -1;
 	}
-	return !!n_error;
+
+	return do_file(file, sectype);
 }
diff --git a/scripts/sorttable.h b/scripts/sorttable.h
index 0de9488..68f7200 100644
--- a/scripts/sorttable.h
+++ b/scripts/sorttable.h
@@ -1,5 +1,5 @@
 /*
- * sorttable.h
+ * sortextable.h
  *
  * Copyright 2011 - 2012 Cavium, Inc.
  *
@@ -13,7 +13,7 @@
  */
 
 #undef extable_ent_size
-#undef compare_extable
+#undef generic_compare
 #undef do_func
 #undef Elf_Addr
 #undef Elf_Ehdr
@@ -33,9 +33,8 @@
 #undef _r
 #undef _w
 
-#ifdef SORTEXTABLE_64
-# define extable_ent_size	16
-# define compare_extable	compare_extable_64
+#ifdef SORTTABLE_64
+# define generic_compare	generic_compare_64
 # define do_func		do64
 # define Elf_Addr		Elf64_Addr
 # define Elf_Ehdr		Elf64_Ehdr
@@ -55,8 +54,7 @@
 # define _r			r8
 # define _w			w8
 #else
-# define extable_ent_size	8
-# define compare_extable	compare_extable_32
+# define generic_compare	generic_compare_32
 # define do_func		do32
 # define Elf_Addr		Elf32_Addr
 # define Elf_Ehdr		Elf32_Ehdr
@@ -77,7 +75,7 @@
 # define _w			w
 #endif
 
-static int compare_extable(const void *a, const void *b)
+static int generic_compare(const void *a, const void *b)
 {
 	Elf_Addr av = _r(a);
 	Elf_Addr bv = _r(b);
@@ -89,14 +87,16 @@ static int compare_extable(const void *a, const void *b)
 	return 0;
 }
 
-static void
-do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
+static int
+do_func(Elf_Ehdr *ehdr, char const *const fname, char const *const secname,
+	size_t entsize, table_sort_t custom_sort,
+	char const *const sort_needed_var)
 {
 	Elf_Shdr *shdr;
 	Elf_Shdr *shstrtab_sec;
 	Elf_Shdr *strtab_sec = NULL;
 	Elf_Shdr *symtab_sec = NULL;
-	Elf_Shdr *extab_sec = NULL;
+	Elf_Shdr *table_sec = NULL;
 	Elf_Sym *sym;
 	const Elf_Sym *symtab;
 	Elf32_Word *symtab_shndx_start = NULL;
@@ -107,8 +107,8 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
 	uint32_t *sort_done_location;
 	const char *secstrtab;
 	const char *strtab;
-	char *extab_image;
-	int extab_index = 0;
+	char *table_image;
+	int table_index = 0;
 	int i;
 	int idx;
 	unsigned int num_sections;
@@ -128,13 +128,13 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
 	secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset);
 	for (i = 0; i < num_sections; i++) {
 		idx = r(&shdr[i].sh_name);
-		if (strcmp(secstrtab + idx, "__ex_table") == 0) {
-			extab_sec = shdr + i;
-			extab_index = i;
+		if (strcmp(secstrtab + idx, secname) == 0) {
+			table_sec = shdr + i;
+			table_index = i;
 		}
 		if ((r(&shdr[i].sh_type) == SHT_REL ||
 		     r(&shdr[i].sh_type) == SHT_RELA) &&
-		    r(&shdr[i].sh_info) == extab_index) {
+		    r(&shdr[i].sh_info) == table_index) {
 			relocs = (void *)ehdr + _r(&shdr[i].sh_offset);
 			relocs_size = _r(&shdr[i].sh_size);
 		}
@@ -147,35 +147,37 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
 				(const char *)ehdr + _r(&shdr[i].sh_offset));
 	}
 	if (strtab_sec == NULL) {
-		fprintf(stderr,	"no .strtab in  file: %s\n", fname);
-		fail_file();
+		fprintf(stderr,	"no .strtab in file: %s\n", fname);
+		return -1;
 	}
 	if (symtab_sec == NULL) {
-		fprintf(stderr,	"no .symtab in  file: %s\n", fname);
-		fail_file();
+		fprintf(stderr,	"no .symtab in file: %s\n", fname);
+		return -1;
 	}
 	symtab = (const Elf_Sym *)((const char *)ehdr +
 				   _r(&symtab_sec->sh_offset));
-	if (extab_sec == NULL) {
-		fprintf(stderr,	"no __ex_table in  file: %s\n", fname);
-		fail_file();
+	if (table_sec == NULL) {
+		fprintf(stderr,	"no %s section in file: %s\n", secname, fname);
+		return -1;
 	}
 	strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset);
 
-	extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
+	table_image = (void *)ehdr + _r(&table_sec->sh_offset);
 
 	if (custom_sort) {
-		custom_sort(extab_image, _r(&extab_sec->sh_size));
+		custom_sort(table_image, _r(&table_sec->sh_size), entsize);
 	} else {
-		int num_entries = _r(&extab_sec->sh_size) / extable_ent_size;
-		qsort(extab_image, num_entries,
-		      extable_ent_size, compare_extable);
+		int num_entries = _r(&table_sec->sh_size) / entsize;
+		qsort(table_image, num_entries, entsize, generic_compare);
 	}
 	/* If there were relocations, we no longer need them. */
 	if (relocs)
 		memset(relocs, 0, relocs_size);
 
-	/* find main_extable_sort_needed */
+	if (!sort_needed_var)
+		return 0;
+
+	/* find sort needed variable so we can clear it */
 	sort_needed_sym = NULL;
 	for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) {
 		sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
@@ -183,16 +185,16 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
 		if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
 			continue;
 		idx = r(&sym->st_name);
-		if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) {
+		if (strcmp(strtab + idx, sort_needed_var) == 0) {
 			sort_needed_sym = sym;
 			break;
 		}
 	}
 	if (sort_needed_sym == NULL) {
 		fprintf(stderr,
-			"no main_extable_sort_needed symbol in  file: %s\n",
-			fname);
-		fail_file();
+			"no %s symbol in file: %s\n",
+			sort_needed_var, fname);
+		return -1;
 	}
 	sort_needed_sec = &shdr[get_secindex(r2(&sym->st_shndx),
 					     sort_needed_sym - symtab,
@@ -208,4 +210,5 @@ do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort)
 #endif
 	/* We sorted it, clear the flag. */
 	w(0, sort_done_location);
+	return 0;
 }
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ