linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] kernel ASLR
@ 2013-04-12 20:13 Kees Cook
  2013-04-12 20:13 ` [PATCH 1/6] x86: relocs: generalize Elf structure names Kees Cook
                   ` (6 more replies)
  0 siblings, 7 replies; 40+ messages in thread
From: Kees Cook @ 2013-04-12 20:13 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, H. Peter Anvin, Thomas Gleixner, Ingo Molnar,
	x86, Jarkko Sakkinen, Matthew Garrett, Matt Fleming,
	Eric Northup, Dan Rosenberg, Julien Tinnes, Will Drewry,
	Kees Cook

This splits up the relocs tool changes into the separate logical pieces,
which should be easier to review. I could use some suggestions on a
better way to build it in the 4th patch. What I have now seems ugly,
but Kbuild would not give me its secrets.

RO IDT was sent separately is is living in the tip/kaslr tree at the
moment. The main logic for KASLR remains split into two pieces: offset
selection and offset usage.

Thanks,

-Kees


^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 1/6] x86: relocs: generalize Elf structure names
  2013-04-12 20:13 [PATCH v2 0/6] kernel ASLR Kees Cook
@ 2013-04-12 20:13 ` Kees Cook
  2013-04-16 23:17   ` [tip:x86/kaslr] x86, relocs: Generalize ELF " tip-bot for Kees Cook
  2013-04-12 20:13 ` [PATCH 2/6] x86: relocs: consolidate processing logic Kees Cook
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 40+ messages in thread
From: Kees Cook @ 2013-04-12 20:13 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, H. Peter Anvin, Thomas Gleixner, Ingo Molnar,
	x86, Jarkko Sakkinen, Matthew Garrett, Matt Fleming,
	Eric Northup, Dan Rosenberg, Julien Tinnes, Will Drewry,
	Kees Cook

In preparation for making the reloc tool operate on 64-bit relocations,
generalize the structure names for easy recompilation via #defines.

Based on work by Neill Clift and Michael Davidson.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/tools/relocs.c |  170 +++++++++++++++++++++++++++--------------------
 1 file changed, 99 insertions(+), 71 deletions(-)

diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 79d67bd..fd28ef7 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -12,20 +12,42 @@
 #include <regex.h>
 #include <tools/le_byteshift.h>
 
+#define ElfW(type)		_ElfW(ELF_BITS, type)
+#define _ElfW(bits, type)	__ElfW(bits, type)
+#define __ElfW(bits, type)	Elf##bits##_##type
+
+#define ELF_BITS		32
+#define ELF_MACHINE		EM_386
+#define ELF_MACHINE_NAME	"i386"
+#define SHT_REL_TYPE		SHT_REL
+
+#define ELF_CLASS		ELFCLASS32
+#define ELF_R_SYM(val)		ELF32_R_SYM(val)
+#define ELF_R_TYPE(val)		ELF32_R_TYPE(val)
+#define ELF_ST_TYPE(o)		ELF32_ST_TYPE(o)
+#define ELF_ST_BIND(o)		ELF32_ST_BIND(o)
+#define ELF_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY(o)
+
+#define Elf_Rel			ElfW(Rel)
+#define Elf_Ehdr		ElfW(Ehdr)
+#define Elf_Phdr		ElfW(Phdr)
+#define Elf_Shdr		ElfW(Shdr)
+#define Elf_Sym			ElfW(Sym)
+
 static void die(char *fmt, ...);
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-static Elf32_Ehdr ehdr;
+static Elf_Ehdr ehdr;
 static unsigned long reloc_count, reloc_idx;
 static unsigned long *relocs;
 static unsigned long reloc16_count, reloc16_idx;
 static unsigned long *relocs16;
 
 struct section {
-	Elf32_Shdr     shdr;
+	Elf_Shdr       shdr;
 	struct section *link;
-	Elf32_Sym      *symtab;
-	Elf32_Rel      *reltab;
+	Elf_Sym        *symtab;
+	Elf_Rel        *reltab;
 	char           *strtab;
 };
 static struct section *secs;
@@ -240,7 +262,7 @@ static const char *sec_name(unsigned shndx)
 	return name;
 }
 
-static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
+static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
 {
 	const char *name;
 	name = "<noname>";
@@ -274,6 +296,12 @@ static uint32_t elf32_to_cpu(uint32_t val)
 	return le32_to_cpu(val);
 }
 
+#define elf_half_to_cpu(x)	elf16_to_cpu(x)
+#define elf_word_to_cpu(x)	elf32_to_cpu(x)
+#define elf_addr_to_cpu(x)	elf32_to_cpu(x)
+#define elf_off_to_cpu(x)	elf32_to_cpu(x)
+#define elf_xword_to_cpu(x)	elf32_to_cpu(x)
+
 static void read_ehdr(FILE *fp)
 {
 	if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
@@ -283,8 +311,8 @@ static void read_ehdr(FILE *fp)
 	if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
 		die("No ELF magic\n");
 	}
-	if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
-		die("Not a 32 bit executable\n");
+	if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) {
+		die("Not a %d bit executable\n", ELF_BITS);
 	}
 	if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
 		die("Not a LSB ELF executable\n");
@@ -293,36 +321,36 @@ static void read_ehdr(FILE *fp)
 		die("Unknown ELF version\n");
 	}
 	/* Convert the fields to native endian */
-	ehdr.e_type      = elf16_to_cpu(ehdr.e_type);
-	ehdr.e_machine   = elf16_to_cpu(ehdr.e_machine);
-	ehdr.e_version   = elf32_to_cpu(ehdr.e_version);
-	ehdr.e_entry     = elf32_to_cpu(ehdr.e_entry);
-	ehdr.e_phoff     = elf32_to_cpu(ehdr.e_phoff);
-	ehdr.e_shoff     = elf32_to_cpu(ehdr.e_shoff);
-	ehdr.e_flags     = elf32_to_cpu(ehdr.e_flags);
-	ehdr.e_ehsize    = elf16_to_cpu(ehdr.e_ehsize);
-	ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
-	ehdr.e_phnum     = elf16_to_cpu(ehdr.e_phnum);
-	ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
-	ehdr.e_shnum     = elf16_to_cpu(ehdr.e_shnum);
-	ehdr.e_shstrndx  = elf16_to_cpu(ehdr.e_shstrndx);
+	ehdr.e_type      = elf_half_to_cpu(ehdr.e_type);
+	ehdr.e_machine   = elf_half_to_cpu(ehdr.e_machine);
+	ehdr.e_version   = elf_word_to_cpu(ehdr.e_version);
+	ehdr.e_entry     = elf_addr_to_cpu(ehdr.e_entry);
+	ehdr.e_phoff     = elf_off_to_cpu(ehdr.e_phoff);
+	ehdr.e_shoff     = elf_off_to_cpu(ehdr.e_shoff);
+	ehdr.e_flags     = elf_word_to_cpu(ehdr.e_flags);
+	ehdr.e_ehsize    = elf_half_to_cpu(ehdr.e_ehsize);
+	ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize);
+	ehdr.e_phnum     = elf_half_to_cpu(ehdr.e_phnum);
+	ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize);
+	ehdr.e_shnum     = elf_half_to_cpu(ehdr.e_shnum);
+	ehdr.e_shstrndx  = elf_half_to_cpu(ehdr.e_shstrndx);
 
 	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
 		die("Unsupported ELF header type\n");
 	}
-	if (ehdr.e_machine != EM_386) {
-		die("Not for x86\n");
+	if (ehdr.e_machine != ELF_MACHINE) {
+		die("Not for %s\n", ELF_MACHINE_NAME);
 	}
 	if (ehdr.e_version != EV_CURRENT) {
 		die("Unknown ELF version\n");
 	}
-	if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
+	if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) {
 		die("Bad Elf header size\n");
 	}
-	if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
+	if (ehdr.e_phentsize != sizeof(Elf_Phdr)) {
 		die("Bad program header entry\n");
 	}
-	if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
+	if (ehdr.e_shentsize != sizeof(Elf_Shdr)) {
 		die("Bad section header entry\n");
 	}
 	if (ehdr.e_shstrndx >= ehdr.e_shnum) {
@@ -333,7 +361,7 @@ static void read_ehdr(FILE *fp)
 static void read_shdrs(FILE *fp)
 {
 	int i;
-	Elf32_Shdr shdr;
+	Elf_Shdr shdr;
 
 	secs = calloc(ehdr.e_shnum, sizeof(struct section));
 	if (!secs) {
@@ -349,16 +377,16 @@ static void read_shdrs(FILE *fp)
 		if (fread(&shdr, sizeof shdr, 1, fp) != 1)
 			die("Cannot read ELF section headers %d/%d: %s\n",
 			    i, ehdr.e_shnum, strerror(errno));
-		sec->shdr.sh_name      = elf32_to_cpu(shdr.sh_name);
-		sec->shdr.sh_type      = elf32_to_cpu(shdr.sh_type);
-		sec->shdr.sh_flags     = elf32_to_cpu(shdr.sh_flags);
-		sec->shdr.sh_addr      = elf32_to_cpu(shdr.sh_addr);
-		sec->shdr.sh_offset    = elf32_to_cpu(shdr.sh_offset);
-		sec->shdr.sh_size      = elf32_to_cpu(shdr.sh_size);
-		sec->shdr.sh_link      = elf32_to_cpu(shdr.sh_link);
-		sec->shdr.sh_info      = elf32_to_cpu(shdr.sh_info);
-		sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
-		sec->shdr.sh_entsize   = elf32_to_cpu(shdr.sh_entsize);
+		sec->shdr.sh_name      = elf_word_to_cpu(shdr.sh_name);
+		sec->shdr.sh_type      = elf_word_to_cpu(shdr.sh_type);
+		sec->shdr.sh_flags     = elf_xword_to_cpu(shdr.sh_flags);
+		sec->shdr.sh_addr      = elf_addr_to_cpu(shdr.sh_addr);
+		sec->shdr.sh_offset    = elf_off_to_cpu(shdr.sh_offset);
+		sec->shdr.sh_size      = elf_xword_to_cpu(shdr.sh_size);
+		sec->shdr.sh_link      = elf_word_to_cpu(shdr.sh_link);
+		sec->shdr.sh_info      = elf_word_to_cpu(shdr.sh_info);
+		sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign);
+		sec->shdr.sh_entsize   = elf_xword_to_cpu(shdr.sh_entsize);
 		if (sec->shdr.sh_link < ehdr.e_shnum)
 			sec->link = &secs[sec->shdr.sh_link];
 	}
@@ -412,12 +440,12 @@ static void read_symtabs(FILE *fp)
 			die("Cannot read symbol table: %s\n",
 				strerror(errno));
 		}
-		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
-			Elf32_Sym *sym = &sec->symtab[j];
-			sym->st_name  = elf32_to_cpu(sym->st_name);
-			sym->st_value = elf32_to_cpu(sym->st_value);
-			sym->st_size  = elf32_to_cpu(sym->st_size);
-			sym->st_shndx = elf16_to_cpu(sym->st_shndx);
+		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
+			Elf_Sym *sym = &sec->symtab[j];
+			sym->st_name  = elf_word_to_cpu(sym->st_name);
+			sym->st_value = elf_addr_to_cpu(sym->st_value);
+			sym->st_size  = elf_xword_to_cpu(sym->st_size);
+			sym->st_shndx = elf_half_to_cpu(sym->st_shndx);
 		}
 	}
 }
@@ -428,7 +456,7 @@ static void read_relocs(FILE *fp)
 	int i,j;
 	for (i = 0; i < ehdr.e_shnum; i++) {
 		struct section *sec = &secs[i];
-		if (sec->shdr.sh_type != SHT_REL) {
+		if (sec->shdr.sh_type != SHT_REL_TYPE) {
 			continue;
 		}
 		sec->reltab = malloc(sec->shdr.sh_size);
@@ -445,10 +473,10 @@ static void read_relocs(FILE *fp)
 			die("Cannot read symbol table: %s\n",
 				strerror(errno));
 		}
-		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
-			Elf32_Rel *rel = &sec->reltab[j];
-			rel->r_offset = elf32_to_cpu(rel->r_offset);
-			rel->r_info   = elf32_to_cpu(rel->r_info);
+		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
+			Elf_Rel *rel = &sec->reltab[j];
+			rel->r_offset = elf_addr_to_cpu(rel->r_offset);
+			rel->r_info   = elf_xword_to_cpu(rel->r_info);
 		}
 	}
 }
@@ -468,8 +496,8 @@ static void print_absolute_symbols(void)
 			continue;
 		}
 		sym_strtab = sec->link->strtab;
-		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
-			Elf32_Sym *sym;
+		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
+			Elf_Sym *sym;
 			const char *name;
 			sym = &sec->symtab[j];
 			name = sym_name(sym_strtab, sym);
@@ -478,9 +506,9 @@ static void print_absolute_symbols(void)
 			}
 			printf("%5d %08x %5d %10s %10s %12s %s\n",
 				j, sym->st_value, sym->st_size,
-				sym_type(ELF32_ST_TYPE(sym->st_info)),
-				sym_bind(ELF32_ST_BIND(sym->st_info)),
-				sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
+				sym_type(ELF_ST_TYPE(sym->st_info)),
+				sym_bind(ELF_ST_BIND(sym->st_info)),
+				sym_visibility(ELF_ST_VISIBILITY(sym->st_other)),
 				name);
 		}
 	}
@@ -495,9 +523,9 @@ static void print_absolute_relocs(void)
 		struct section *sec = &secs[i];
 		struct section *sec_applies, *sec_symtab;
 		char *sym_strtab;
-		Elf32_Sym *sh_symtab;
+		Elf_Sym *sh_symtab;
 		int j;
-		if (sec->shdr.sh_type != SHT_REL) {
+		if (sec->shdr.sh_type != SHT_REL_TYPE) {
 			continue;
 		}
 		sec_symtab  = sec->link;
@@ -507,12 +535,12 @@ static void print_absolute_relocs(void)
 		}
 		sh_symtab  = sec_symtab->symtab;
 		sym_strtab = sec_symtab->link->strtab;
-		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
-			Elf32_Rel *rel;
-			Elf32_Sym *sym;
+		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
+			Elf_Rel *rel;
+			Elf_Sym *sym;
 			const char *name;
 			rel = &sec->reltab[j];
-			sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+			sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
 			name = sym_name(sym_strtab, sym);
 			if (sym->st_shndx != SHN_ABS) {
 				continue;
@@ -545,7 +573,7 @@ static void print_absolute_relocs(void)
 			printf("%08x %08x %10s %08x  %s\n",
 				rel->r_offset,
 				rel->r_info,
-				rel_type(ELF32_R_TYPE(rel->r_info)),
+				rel_type(ELF_R_TYPE(rel->r_info)),
 				sym->st_value,
 				name);
 		}
@@ -555,19 +583,19 @@ static void print_absolute_relocs(void)
 		printf("\n");
 }
 
-static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
+static void walk_relocs(void (*visit)(Elf_Rel *rel, Elf_Sym *sym),
 			int use_real_mode)
 {
 	int i;
 	/* Walk through the relocations */
 	for (i = 0; i < ehdr.e_shnum; i++) {
 		char *sym_strtab;
-		Elf32_Sym *sh_symtab;
+		Elf_Sym *sh_symtab;
 		struct section *sec_applies, *sec_symtab;
 		int j;
 		struct section *sec = &secs[i];
 
-		if (sec->shdr.sh_type != SHT_REL) {
+		if (sec->shdr.sh_type != SHT_REL_TYPE) {
 			continue;
 		}
 		sec_symtab  = sec->link;
@@ -577,16 +605,16 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
 		}
 		sh_symtab = sec_symtab->symtab;
 		sym_strtab = sec_symtab->link->strtab;
-		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
-			Elf32_Rel *rel;
-			Elf32_Sym *sym;
+		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
+			Elf_Rel *rel;
+			Elf_Sym *sym;
 			unsigned r_type;
 			const char *symname;
 			int shn_abs;
 
 			rel = &sec->reltab[j];
-			sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
-			r_type = ELF32_R_TYPE(rel->r_info);
+			sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
+			r_type = ELF_R_TYPE(rel->r_info);
 
 			shn_abs = sym->st_shndx == SHN_ABS;
 
@@ -647,18 +675,18 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
 	}
 }
 
-static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+static void count_reloc(Elf_Rel *rel, Elf_Sym *sym)
 {
-	if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+	if (ELF_R_TYPE(rel->r_info) == R_386_16)
 		reloc16_count++;
 	else
 		reloc_count++;
 }
 
-static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+static void collect_reloc(Elf_Rel *rel, Elf_Sym *sym)
 {
 	/* Remember the address that needs to be adjusted. */
-	if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+	if (ELF_R_TYPE(rel->r_info) == R_386_16)
 		relocs16[reloc16_idx++] = rel->r_offset;
 	else
 		relocs[reloc_idx++] = rel->r_offset;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 2/6] x86: relocs: consolidate processing logic
  2013-04-12 20:13 [PATCH v2 0/6] kernel ASLR Kees Cook
  2013-04-12 20:13 ` [PATCH 1/6] x86: relocs: generalize Elf structure names Kees Cook
@ 2013-04-12 20:13 ` Kees Cook
  2013-04-16 23:18   ` [tip:x86/kaslr] x86, relocs: Consolidate " tip-bot for Kees Cook
  2013-04-12 20:13 ` [PATCH 3/6] x86: relocs: add 64-bit ELF support to relocs tool Kees Cook
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 40+ messages in thread
From: Kees Cook @ 2013-04-12 20:13 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, H. Peter Anvin, Thomas Gleixner, Ingo Molnar,
	x86, Jarkko Sakkinen, Matthew Garrett, Matt Fleming,
	Eric Northup, Dan Rosenberg, Julien Tinnes, Will Drewry,
	Kees Cook

Instead of counting and then processing relocations, do it in a single
pass. This splits the processing logic into separate functions for
realmode and 32-bit (and paves the way for 64-bit). Also extracts helper
functions when emitting relocations.

Based on work by Neill Clift and Michael Davidson.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/tools/relocs.c |  304 ++++++++++++++++++++++++++---------------------
 1 file changed, 170 insertions(+), 134 deletions(-)

diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index fd28ef7..bdc5930 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -2,6 +2,7 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <inttypes.h>
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
@@ -38,10 +39,15 @@ static void die(char *fmt, ...);
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 static Elf_Ehdr ehdr;
-static unsigned long reloc_count, reloc_idx;
-static unsigned long *relocs;
-static unsigned long reloc16_count, reloc16_idx;
-static unsigned long *relocs16;
+
+struct relocs {
+	uint32_t	*offset;
+	unsigned long	count;
+	unsigned long	size;
+};
+
+static struct relocs relocs16;
+static struct relocs relocs32;
 
 struct section {
 	Elf_Shdr       shdr;
@@ -583,8 +589,23 @@ static void print_absolute_relocs(void)
 		printf("\n");
 }
 
-static void walk_relocs(void (*visit)(Elf_Rel *rel, Elf_Sym *sym),
-			int use_real_mode)
+static void add_reloc(struct relocs *r, uint32_t offset)
+{
+	if (r->count == r->size) {
+		unsigned long newsize = r->size + 50000;
+		void *mem = realloc(r->offset, newsize * sizeof(r->offset[0]));
+
+		if (!mem)
+			die("realloc of %ld entries for relocs failed\n",
+                                newsize);
+		r->offset = mem;
+		r->size = newsize;
+	}
+	r->offset[r->count++] = offset;
+}
+
+static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
+			Elf_Sym *sym, const char *symname))
 {
 	int i;
 	/* Walk through the relocations */
@@ -606,100 +627,142 @@ static void walk_relocs(void (*visit)(Elf_Rel *rel, Elf_Sym *sym),
 		sh_symtab = sec_symtab->symtab;
 		sym_strtab = sec_symtab->link->strtab;
 		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
-			Elf_Rel *rel;
-			Elf_Sym *sym;
-			unsigned r_type;
-			const char *symname;
-			int shn_abs;
+			Elf_Rel *rel = &sec->reltab[j];
+			Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
+			const char *symname = sym_name(sym_strtab, sym);
 
-			rel = &sec->reltab[j];
-			sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
-			r_type = ELF_R_TYPE(rel->r_info);
-
-			shn_abs = sym->st_shndx == SHN_ABS;
-
-			switch (r_type) {
-			case R_386_NONE:
-			case R_386_PC32:
-			case R_386_PC16:
-			case R_386_PC8:
-				/*
-				 * NONE can be ignored and and PC relative
-				 * relocations don't need to be adjusted.
-				 */
+			process(sec, rel, sym, symname);
+		}
+	}
+}
+
+static int do_reloc(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+		    const char *symname)
+{
+	unsigned r_type = ELF32_R_TYPE(rel->r_info);
+	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
+
+	switch (r_type) {
+	case R_386_NONE:
+	case R_386_PC32:
+	case R_386_PC16:
+	case R_386_PC8:
+		/*
+		 * NONE can be ignored and PC relative relocations don't
+		 * need to be adjusted.
+		 */
+		break;
+
+	case R_386_32:
+		if (shn_abs) {
+			/*
+			 * Whitelisted absolute symbols do not require
+			 * relocation.
+			 */
+			if (is_reloc(S_ABS, symname))
 				break;
 
-			case R_386_16:
-				symname = sym_name(sym_strtab, sym);
-				if (!use_real_mode)
-					goto bad;
-				if (shn_abs) {
-					if (is_reloc(S_ABS, symname))
-						break;
-					else if (!is_reloc(S_SEG, symname))
-						goto bad;
-				} else {
-					if (is_reloc(S_LIN, symname))
-						goto bad;
-					else
-						break;
-				}
-				visit(rel, sym);
+			die("Invalid absolute %s relocation: %s\n",
+			    rel_type(r_type), symname);
+			break;
+		}
+
+		add_reloc(&relocs32, rel->r_offset);
+		break;
+
+	default:
+		die("Unsupported relocation type: %s (%d)\n",
+		    rel_type(r_type), r_type);
+		break;
+	}
+
+	return 0;
+}
+
+static int do_reloc_real(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+			 const char *symname)
+{
+	unsigned r_type = ELF32_R_TYPE(rel->r_info);
+	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
+
+	switch (r_type) {
+	case R_386_NONE:
+	case R_386_PC32:
+	case R_386_PC16:
+	case R_386_PC8:
+		/*
+		 * NONE can be ignored and PC relative relocations don't
+		 * need to be adjusted.
+		 */
+		break;
+
+	case R_386_16:
+		if (shn_abs) {
+			/*
+			 * Whitelisted absolute symbols do not require
+			 * relocation.
+			 */
+			if (is_reloc(S_ABS, symname))
 				break;
 
-			case R_386_32:
-				symname = sym_name(sym_strtab, sym);
-				if (shn_abs) {
-					if (is_reloc(S_ABS, symname))
-						break;
-					else if (!is_reloc(S_REL, symname))
-						goto bad;
-				} else {
-					if (use_real_mode &&
-					    !is_reloc(S_LIN, symname))
-						break;
-				}
-				visit(rel, sym);
+			if (is_reloc(S_SEG, symname)) {
+				add_reloc(&relocs16, rel->r_offset);
+				break;
+			}
+		} else {
+			if (!is_reloc(S_LIN, symname))
 				break;
-			default:
-				die("Unsupported relocation type: %s (%d)\n",
-				    rel_type(r_type), r_type);
+		}
+		die("Invalid %s %s relocation: %s\n",
+		    shn_abs ? "absolute" : "relative",
+		    rel_type(r_type), symname);
+		break;
+
+	case R_386_32:
+		if (shn_abs) {
+			/*
+			 * Whitelisted absolute symbols do not require
+			 * relocation.
+			 */
+			if (is_reloc(S_ABS, symname))
+				break;
+
+			if (is_reloc(S_REL, symname)) {
+				add_reloc(&relocs32, rel->r_offset);
 				break;
-			bad:
-				symname = sym_name(sym_strtab, sym);
-				die("Invalid %s %s relocation: %s\n",
-				    shn_abs ? "absolute" : "relative",
-				    rel_type(r_type), symname);
 			}
+		} else {
+			if (is_reloc(S_LIN, symname))
+				add_reloc(&relocs32, rel->r_offset);
+			break;
 		}
-	}
-}
+		die("Invalid %s %s relocation: %s\n",
+		    shn_abs ? "absolute" : "relative",
+		    rel_type(r_type), symname);
+		break;
 
-static void count_reloc(Elf_Rel *rel, Elf_Sym *sym)
-{
-	if (ELF_R_TYPE(rel->r_info) == R_386_16)
-		reloc16_count++;
-	else
-		reloc_count++;
-}
+	default:
+		die("Unsupported relocation type: %s (%d)\n",
+		    rel_type(r_type), r_type);
+		break;
+	}
 
-static void collect_reloc(Elf_Rel *rel, Elf_Sym *sym)
-{
-	/* Remember the address that needs to be adjusted. */
-	if (ELF_R_TYPE(rel->r_info) == R_386_16)
-		relocs16[reloc16_idx++] = rel->r_offset;
-	else
-		relocs[reloc_idx++] = rel->r_offset;
+	return 0;
 }
 
 static int cmp_relocs(const void *va, const void *vb)
 {
-	const unsigned long *a, *b;
+	const uint32_t *a, *b;
 	a = va; b = vb;
 	return (*a == *b)? 0 : (*a > *b)? 1 : -1;
 }
 
-static int write32(unsigned int v, FILE *f)
+static void sort_relocs(struct relocs *r)
+{
+	qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
+}
+
+static int write32(uint32_t v, FILE *f)
 {
 	unsigned char buf[4];
 
@@ -707,33 +770,25 @@ static int write32(unsigned int v, FILE *f)
 	return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
 }
 
+static int write32_as_text(uint32_t v, FILE *f)
+{
+	return fprintf(f, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1;
+}
+
 static void emit_relocs(int as_text, int use_real_mode)
 {
 	int i;
-	/* Count how many relocations I have and allocate space for them. */
-	reloc_count = 0;
-	walk_relocs(count_reloc, use_real_mode);
-	relocs = malloc(reloc_count * sizeof(relocs[0]));
-	if (!relocs) {
-		die("malloc of %d entries for relocs failed\n",
-			reloc_count);
-	}
+	int (*write_reloc)(uint32_t, FILE *) = write32;
 
-	relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
-	if (!relocs16) {
-		die("malloc of %d entries for relocs16 failed\n",
-			reloc16_count);
-	}
 	/* Collect up the relocations */
-	reloc_idx = 0;
-	walk_relocs(collect_reloc, use_real_mode);
+	walk_relocs(use_real_mode ? do_reloc_real : do_reloc);
 
-	if (reloc16_count && !use_real_mode)
+	if (relocs16.count && !use_real_mode)
 		die("Segment relocations found but --realmode not specified\n");
 
 	/* Order the relocations for more efficient processing */
-	qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
-	qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);
+	sort_relocs(&relocs16);
+	sort_relocs(&relocs32);
 
 	/* Print the relocations */
 	if (as_text) {
@@ -742,43 +797,24 @@ static void emit_relocs(int as_text, int use_real_mode)
 		 */
 		printf(".section \".data.reloc\",\"a\"\n");
 		printf(".balign 4\n");
-		if (use_real_mode) {
-			printf("\t.long %lu\n", reloc16_count);
-			for (i = 0; i < reloc16_count; i++)
-				printf("\t.long 0x%08lx\n", relocs16[i]);
-			printf("\t.long %lu\n", reloc_count);
-			for (i = 0; i < reloc_count; i++) {
-				printf("\t.long 0x%08lx\n", relocs[i]);
-			}
-		} else {
-			/* Print a stop */
-			printf("\t.long 0x%08lx\n", (unsigned long)0);
-			for (i = 0; i < reloc_count; i++) {
-				printf("\t.long 0x%08lx\n", relocs[i]);
-			}
-		}
-
-		printf("\n");
+		write_reloc = write32_as_text;
 	}
-	else {
-		if (use_real_mode) {
-			write32(reloc16_count, stdout);
-			for (i = 0; i < reloc16_count; i++)
-				write32(relocs16[i], stdout);
-			write32(reloc_count, stdout);
-
-			/* Now print each relocation */
-			for (i = 0; i < reloc_count; i++)
-				write32(relocs[i], stdout);
-		} else {
-			/* Print a stop */
-			write32(0, stdout);
 
-			/* Now print each relocation */
-			for (i = 0; i < reloc_count; i++) {
-				write32(relocs[i], stdout);
-			}
-		}
+	if (use_real_mode) {
+		write_reloc(relocs16.count, stdout);
+		for (i = 0; i < relocs16.count; i++)
+			write_reloc(relocs16.offset[i], stdout);
+
+		write_reloc(relocs32.count, stdout);
+		for (i = 0; i < relocs32.count; i++)
+			write_reloc(relocs32.offset[i], stdout);
+	} else {
+		/* Print a stop */
+		write_reloc(0, stdout);
+
+		/* Now print each relocation */
+		for (i = 0; i < relocs32.count; i++)
+			write_reloc(relocs32.offset[i], stdout);
 	}
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 3/6] x86: relocs: add 64-bit ELF support to relocs tool
  2013-04-12 20:13 [PATCH v2 0/6] kernel ASLR Kees Cook
  2013-04-12 20:13 ` [PATCH 1/6] x86: relocs: generalize Elf structure names Kees Cook
  2013-04-12 20:13 ` [PATCH 2/6] x86: relocs: consolidate processing logic Kees Cook
@ 2013-04-12 20:13 ` Kees Cook
  2013-04-16 23:19   ` [tip:x86/kaslr] x86, relocs: Add " tip-bot for Kees Cook
  2013-04-12 20:13 ` [PATCH 4/6] x86: relocs: build separate 32/64-bit tools Kees Cook
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 40+ messages in thread
From: Kees Cook @ 2013-04-12 20:13 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, H. Peter Anvin, Thomas Gleixner, Ingo Molnar,
	x86, Jarkko Sakkinen, Matthew Garrett, Matt Fleming,
	Eric Northup, Dan Rosenberg, Julien Tinnes, Will Drewry,
	Kees Cook

This adds the ability to process relocations from the 64-bit kernel ELF,
if built with ELF_BITS=64 defined. The special case for the percpu area is
handled, along with some other symbols specific to the 64-bit kernel.

Based on work by Neill Clift and Michael Davidson.

Signed-off-by: Kees Cook <keescook@chromium.org>
---
 arch/x86/tools/relocs.c |  267 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 261 insertions(+), 6 deletions(-)

diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index bdc5930..1f7ff3d 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -17,19 +17,39 @@
 #define _ElfW(bits, type)	__ElfW(bits, type)
 #define __ElfW(bits, type)	Elf##bits##_##type
 
+#ifndef ELF_BITS
 #define ELF_BITS		32
+#endif
+
+#if (ELF_BITS == 64)
+#define ELF_MACHINE             EM_X86_64
+#define ELF_MACHINE_NAME        "x86_64"
+#define SHT_REL_TYPE            SHT_RELA
+#define Elf_Rel                 Elf64_Rela
+#else
 #define ELF_MACHINE		EM_386
 #define ELF_MACHINE_NAME	"i386"
 #define SHT_REL_TYPE		SHT_REL
+#define Elf_Rel			ElfW(Rel)
+#endif
 
+#if (ELF_BITS == 64)
+#define ELF_CLASS               ELFCLASS64
+#define ELF_R_SYM(val)          ELF64_R_SYM(val)
+#define ELF_R_TYPE(val)         ELF64_R_TYPE(val)
+#define ELF_ST_TYPE(o)          ELF64_ST_TYPE(o)
+#define ELF_ST_BIND(o)          ELF64_ST_BIND(o)
+#define ELF_ST_VISIBILITY(o)    ELF64_ST_VISIBILITY(o)
+#else
 #define ELF_CLASS		ELFCLASS32
 #define ELF_R_SYM(val)		ELF32_R_SYM(val)
 #define ELF_R_TYPE(val)		ELF32_R_TYPE(val)
 #define ELF_ST_TYPE(o)		ELF32_ST_TYPE(o)
 #define ELF_ST_BIND(o)		ELF32_ST_BIND(o)
 #define ELF_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY(o)
+#endif
 
-#define Elf_Rel			ElfW(Rel)
+#define Elf_Addr		ElfW(Addr)
 #define Elf_Ehdr		ElfW(Ehdr)
 #define Elf_Phdr		ElfW(Phdr)
 #define Elf_Shdr		ElfW(Shdr)
@@ -48,6 +68,7 @@ struct relocs {
 
 static struct relocs relocs16;
 static struct relocs relocs32;
+static struct relocs relocs64;
 
 struct section {
 	Elf_Shdr       shdr;
@@ -77,6 +98,9 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
 	"^(xen_irq_disable_direct_reloc$|"
 	"xen_save_fl_direct_reloc$|"
 	"VDSO|"
+#if (ELF_BITS == 64)
+	"__vvar_page|"
+#endif
 	"__crc_)",
 
 /*
@@ -100,6 +124,11 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
 	"__end_rodata|"
 	"__initramfs_start|"
 	"(jiffies|jiffies_64)|"
+#if (ELF_BITS == 64)
+	"__per_cpu_load|"
+	"init_per_cpu__.*|"
+	"__end_rodata_hpage_align|"
+#endif
 	"_end)$"
 };
 
@@ -226,6 +255,24 @@ static const char *rel_type(unsigned type)
 {
 	static const char *type_name[] = {
 #define REL_TYPE(X) [X] = #X
+#if (ELF_BITS == 64)
+		REL_TYPE(R_X86_64_NONE),
+		REL_TYPE(R_X86_64_64),
+		REL_TYPE(R_X86_64_PC32),
+		REL_TYPE(R_X86_64_GOT32),
+		REL_TYPE(R_X86_64_PLT32),
+		REL_TYPE(R_X86_64_COPY),
+		REL_TYPE(R_X86_64_GLOB_DAT),
+		REL_TYPE(R_X86_64_JUMP_SLOT),
+		REL_TYPE(R_X86_64_RELATIVE),
+		REL_TYPE(R_X86_64_GOTPCREL),
+		REL_TYPE(R_X86_64_32),
+		REL_TYPE(R_X86_64_32S),
+		REL_TYPE(R_X86_64_16),
+		REL_TYPE(R_X86_64_PC16),
+		REL_TYPE(R_X86_64_8),
+		REL_TYPE(R_X86_64_PC8),
+#else
 		REL_TYPE(R_386_NONE),
 		REL_TYPE(R_386_32),
 		REL_TYPE(R_386_PC32),
@@ -241,6 +288,7 @@ static const char *rel_type(unsigned type)
 		REL_TYPE(R_386_PC8),
 		REL_TYPE(R_386_16),
 		REL_TYPE(R_386_PC16),
+#endif
 #undef REL_TYPE
 	};
 	const char *name = "unknown type rel type name";
@@ -281,15 +329,42 @@ static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
 	return name;
 }
 
+static Elf_Sym *sym_lookup(const char *symname)
+{
+	int i;
+	for (i = 0; i < ehdr.e_shnum; i++) {
+		struct section *sec = &secs[i];
+		long nsyms;
+		char *strtab;
+		Elf_Sym *symtab;
+		Elf_Sym *sym;
 
+		if (sec->shdr.sh_type != SHT_SYMTAB)
+			continue;
+
+		nsyms = sec->shdr.sh_size/sizeof(Elf_Sym);
+		symtab = sec->symtab;
+		strtab = sec->link->strtab;
+
+		for (sym = symtab; --nsyms >= 0; sym++) {
+			if (!sym->st_name)
+				continue;
+			if (strcmp(symname, strtab + sym->st_name) == 0)
+				return sym;
+		}
+	}
+	return 0;
+}
 
 #if BYTE_ORDER == LITTLE_ENDIAN
 #define le16_to_cpu(val) (val)
 #define le32_to_cpu(val) (val)
+#define le64_to_cpu(val) (val)
 #endif
 #if BYTE_ORDER == BIG_ENDIAN
 #define le16_to_cpu(val) bswap_16(val)
 #define le32_to_cpu(val) bswap_32(val)
+#define le64_to_cpu(val) bswap_64(val)
 #endif
 
 static uint16_t elf16_to_cpu(uint16_t val)
@@ -304,9 +379,20 @@ static uint32_t elf32_to_cpu(uint32_t val)
 
 #define elf_half_to_cpu(x)	elf16_to_cpu(x)
 #define elf_word_to_cpu(x)	elf32_to_cpu(x)
+
+#if (ELF_BITS == 64)
+static uint64_t elf64_to_cpu(uint64_t val)
+{
+        return le64_to_cpu(val);
+}
+#define elf_addr_to_cpu(x)	elf64_to_cpu(x)
+#define elf_off_to_cpu(x)	elf64_to_cpu(x)
+#define elf_xword_to_cpu(x)	elf64_to_cpu(x)
+#else
 #define elf_addr_to_cpu(x)	elf32_to_cpu(x)
 #define elf_off_to_cpu(x)	elf32_to_cpu(x)
 #define elf_xword_to_cpu(x)	elf32_to_cpu(x)
+#endif
 
 static void read_ehdr(FILE *fp)
 {
@@ -483,6 +569,9 @@ static void read_relocs(FILE *fp)
 			Elf_Rel *rel = &sec->reltab[j];
 			rel->r_offset = elf_addr_to_cpu(rel->r_offset);
 			rel->r_info   = elf_xword_to_cpu(rel->r_info);
+#if (SHT_REL_TYPE == SHT_RELA)
+			rel->r_addend = elf_xword_to_cpu(rel->r_addend);
+#endif
 		}
 	}
 }
@@ -491,6 +580,13 @@ static void read_relocs(FILE *fp)
 static void print_absolute_symbols(void)
 {
 	int i;
+	const char *format;
+
+	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+		format = "%5d %016"PRIx64" %5"PRId64" %10s %10s %12s %s\n";
+	else
+		format = "%5d %08"PRIx32"  %5"PRId32" %10s %10s %12s %s\n";
+
 	printf("Absolute symbols\n");
 	printf(" Num:    Value Size  Type       Bind        Visibility  Name\n");
 	for (i = 0; i < ehdr.e_shnum; i++) {
@@ -510,7 +606,7 @@ static void print_absolute_symbols(void)
 			if (sym->st_shndx != SHN_ABS) {
 				continue;
 			}
-			printf("%5d %08x %5d %10s %10s %12s %s\n",
+			printf(format,
 				j, sym->st_value, sym->st_size,
 				sym_type(ELF_ST_TYPE(sym->st_info)),
 				sym_bind(ELF_ST_BIND(sym->st_info)),
@@ -524,6 +620,12 @@ static void print_absolute_symbols(void)
 static void print_absolute_relocs(void)
 {
 	int i, printed = 0;
+	const char *format;
+
+	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+		format = "%016"PRIx64" %016"PRIx64" %10s %016"PRIx64"  %s\n";
+	else
+		format = "%08"PRIx32" %08"PRIx32" %10s %08"PRIx32"  %s\n";
 
 	for (i = 0; i < ehdr.e_shnum; i++) {
 		struct section *sec = &secs[i];
@@ -576,7 +678,7 @@ static void print_absolute_relocs(void)
 				printed = 1;
 			}
 
-			printf("%08x %08x %10s %08x  %s\n",
+			printf(format,
 				rel->r_offset,
 				rel->r_info,
 				rel_type(ELF_R_TYPE(rel->r_info)),
@@ -636,8 +738,140 @@ static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
 	}
 }
 
-static int do_reloc(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
-		    const char *symname)
+/*
+ * The .data..percpu section is a special case for x86_64 SMP kernels.
+ * It is used to initialize the actual per_cpu areas and to provide
+ * definitions for the per_cpu variables that correspond to their offsets
+ * within the percpu area. Since the values of all of the symbols need
+ * to be offsets from the start of the per_cpu area the virtual address
+ * (sh_addr) of .data..percpu is 0 in SMP kernels.
+ *
+ * This means that:
+ *
+ *	Relocations that reference symbols in the per_cpu area do not
+ *	need further relocation (since the value is an offset relative
+ *	to the start of the per_cpu area that does not change).
+ *
+ *	Relocations that apply to the per_cpu area need to have their
+ *	offset adjusted by by the value of __per_cpu_load to make them
+ *	point to the correct place in the loaded image (because the
+ *	virtual address of .data..percpu is 0).
+ *
+ * For non SMP kernels .data..percpu is linked as part of the normal
+ * kernel data and does not require special treatment.
+ *
+ */
+static int per_cpu_shndx	= -1;
+Elf_Addr per_cpu_load_addr;
+
+static void percpu_init(void)
+{
+	int i;
+	for (i = 0; i < ehdr.e_shnum; i++) {
+		ElfW(Sym) *sym;
+		if (strcmp(sec_name(i), ".data..percpu"))
+			continue;
+
+		if (secs[i].shdr.sh_addr != 0)	/* non SMP kernel */
+			return;
+
+		sym = sym_lookup("__per_cpu_load");
+		if (!sym)
+			die("can't find __per_cpu_load\n");
+
+		per_cpu_shndx = i;
+		per_cpu_load_addr = sym->st_value;
+		return;
+	}
+}
+
+/*
+ * Check to see if a symbol lies in the .data..percpu section.
+ * For some as yet not understood reason the "__init_begin"
+ * symbol which immediately preceeds the .data..percpu section
+ * also shows up as it it were part of it so we do an explict
+ * check for that symbol name and ignore it.
+ */
+static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
+{
+	return (sym->st_shndx == per_cpu_shndx) &&
+		strcmp(symname, "__init_begin");
+}
+
+static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
+		      const char *symname)
+{
+	unsigned r_type = ELF64_R_TYPE(rel->r_info);
+	ElfW(Addr) offset = rel->r_offset;
+	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
+
+	if (sym->st_shndx == SHN_UNDEF)
+		return 0;
+
+	/*
+	 * Adjust the offset if this reloc applies to the percpu section.
+	 */
+	if (sec->shdr.sh_info == per_cpu_shndx)
+		offset += per_cpu_load_addr;
+
+	switch (r_type) {
+	case R_X86_64_NONE:
+	case R_X86_64_PC32:
+		/*
+		 * NONE can be ignored and PC relative relocations don't
+		 * need to be adjusted.
+		 */
+		break;
+
+	case R_X86_64_32:
+	case R_X86_64_32S:
+	case R_X86_64_64:
+		/*
+		 * References to the percpu area don't need to be adjusted.
+		 */
+		if (is_percpu_sym(sym, symname))
+			break;
+
+		if (shn_abs) {
+			/*
+			 * Whitelisted absolute symbols do not require
+			 * relocation.
+			 */
+			if (is_reloc(S_ABS, symname))
+				break;
+
+			die("Invalid absolute %s relocation: %s\n",
+			    rel_type(r_type), symname);
+			break;
+		}
+
+		/*
+		 * Relocation offsets for 64 bit kernels are output
+		 * as 32 bits and sign extended back to 64 bits when
+		 * the relocations are processed.
+		 * Make sure that the offset will fit.
+		 */
+		if ((int32_t)offset != (int64_t)offset)
+			die("Relocation offset doesn't fit in 32 bits\n");
+
+		if (r_type == R_X86_64_64)
+			add_reloc(&relocs64, offset);
+		else
+			add_reloc(&relocs32, offset);
+		break;
+
+	default:
+		die("Unsupported relocation type: %s (%d)\n",
+		    rel_type(r_type), r_type);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+		      const char *symname)
 {
 	unsigned r_type = ELF32_R_TYPE(rel->r_info);
 	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
@@ -779,9 +1013,18 @@ static void emit_relocs(int as_text, int use_real_mode)
 {
 	int i;
 	int (*write_reloc)(uint32_t, FILE *) = write32;
+	int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+			const char *symname);
+
+	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+		do_reloc = do_reloc64;
+	else if (!use_real_mode)
+		do_reloc = do_reloc32;
+	else
+		do_reloc = do_reloc_real;
 
 	/* Collect up the relocations */
-	walk_relocs(use_real_mode ? do_reloc_real : do_reloc);
+	walk_relocs(do_reloc);
 
 	if (relocs16.count && !use_real_mode)
 		die("Segment relocations found but --realmode not specified\n");
@@ -789,6 +1032,7 @@ static void emit_relocs(int as_text, int use_real_mode)
 	/* Order the relocations for more efficient processing */
 	sort_relocs(&relocs16);
 	sort_relocs(&relocs32);
+	sort_relocs(&relocs64);
 
 	/* Print the relocations */
 	if (as_text) {
@@ -809,6 +1053,15 @@ static void emit_relocs(int as_text, int use_real_mode)
 		for (i = 0; i < relocs32.count; i++)
 			write_reloc(relocs32.offset[i], stdout);
 	} else {
+		if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
+			/* Print a stop */
+			write_reloc(0, stdout);
+
+			/* Now print each relocation */
+			for (i = 0; i < relocs64.count; i++)
+				write_reloc(relocs64.offset[i], stdout);
+		}
+
 		/* Print a stop */
 		write_reloc(0, stdout);
 
@@ -876,6 +1129,8 @@ int main(int argc, char **argv)
 	read_strtabs(fp);
 	read_symtabs(fp);
 	read_relocs(fp);
+	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+		percpu_init();
 	if (show_absolute_syms) {
 		print_absolute_symbols();
 		goto out;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 4/6] x86: relocs: build separate 32/64-bit tools
  2013-04-12 20:13 [PATCH v2 0/6] kernel ASLR Kees Cook
                   ` (2 preceding siblings ...)
  2013-04-12 20:13 ` [PATCH 3/6] x86: relocs: add 64-bit ELF support to relocs tool Kees Cook
@ 2013-04-12 20:13 ` Kees Cook
  2013-04-16 22:21   ` H. Peter Anvin
                     ` (2 more replies)
  2013-04-12 20:13 ` [PATCH 5/6] x86: kaslr: routines to choose random base offset Kees Cook
                   ` (2 subsequent siblings)
  6 siblings, 3 replies; 40+ messages in thread
From: Kees Cook @ 2013-04-12 20:13 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, H. Peter Anvin, Thomas Gleixner, Ingo Molnar,
	x86, Jarkko Sakkinen, Matthew Garrett, Matt Fleming,
	Eric Northup, Dan Rosenberg, Julien Tinnes, Will Drewry,
	Kees Cook

Since the ELF structures and access macros change size based on 32 vs
64 bits, build a separate 32-bit relocs tool (for handling realmode
and 32-bit relocations), and a 64-bit relocs tool (for handling 64-bit
kernel relocations).

Signed-off-by: Kees Cook <keescook@chromium.org>
--
This is ugly with the "cp". Is there some other cleaner way to trigger
two builds with different defines from the same source file?
---
 arch/x86/boot/compressed/Makefile |    2 +-
 arch/x86/realmode/rm/Makefile     |    2 +-
 arch/x86/tools/.gitignore         |    3 ++-
 arch/x86/tools/Makefile           |   20 ++++++++++++++++++--
 4 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 5ef205c..0dac175 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -44,7 +44,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
 
 targets += $(patsubst $(obj)/%,%,$(VMLINUX_OBJS)) vmlinux.bin.all vmlinux.relocs
 
-CMD_RELOCS = arch/x86/tools/relocs
+CMD_RELOCS = arch/x86/tools/relocs_$(BITS)
 quiet_cmd_relocs = RELOCS  $@
       cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $<
 $(obj)/vmlinux.relocs: vmlinux FORCE
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 8869287..2b1e429 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -56,7 +56,7 @@ $(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs
 	$(call if_changed,objcopy)
 
 quiet_cmd_relocs = RELOCS  $@
-      cmd_relocs = arch/x86/tools/relocs --realmode $< > $@
+      cmd_relocs = arch/x86/tools/relocs_32 --realmode $< > $@
 
 targets += realmode.relocs
 $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE
diff --git a/arch/x86/tools/.gitignore b/arch/x86/tools/.gitignore
index be0ed06..2b45d5f 100644
--- a/arch/x86/tools/.gitignore
+++ b/arch/x86/tools/.gitignore
@@ -1 +1,2 @@
-relocs
+relocs_32*
+relocs_64*
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
index bae601f..a8cb70c 100644
--- a/arch/x86/tools/Makefile
+++ b/arch/x86/tools/Makefile
@@ -37,6 +37,22 @@ $(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/in
 
 $(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
 
+HOSTCFLAGS_relocs_32.o += -DELF_BITS=32
+HOSTCFLAGS_relocs_64.o += -DELF_BITS=64
+
+quiet_cmd_cp_reloc = GEN     $@
+      cmd_cp_reloc = cp $< $@
+
+$(obj)/relocs_%.c: $(srctree)/arch/x86/tools/relocs.c
+	$(call cmd,cp_reloc)
+
 HOST_EXTRACFLAGS += -I$(srctree)/tools/include
-hostprogs-y	+= relocs
-relocs: $(obj)/relocs
+hostprogs-y    += relocs_$(BITS)
+relocs_binaries = relocs_$(BITS)
+ifeq ($(CONFIG_64BIT),y)
+	hostprogs-y  += relocs_32
+	relocs_binaries += relocs_32
+endif
+relocs: $(relocs_binaries)
+relocs_32: $(obj)/relocs_32
+relocs_64: $(obj)/relocs_64
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 5/6] x86: kaslr: routines to choose random base offset
  2013-04-12 20:13 [PATCH v2 0/6] kernel ASLR Kees Cook
                   ` (3 preceding siblings ...)
  2013-04-12 20:13 ` [PATCH 4/6] x86: relocs: build separate 32/64-bit tools Kees Cook
@ 2013-04-12 20:13 ` Kees Cook
  2013-04-14  0:11   ` Yinghai Lu
  2013-04-12 20:13 ` [PATCH 6/6] x86: kaslr: relocate base offset at boot Kees Cook
  2013-04-16 18:08 ` [PATCH v2 0/6] kernel ASLR Kees Cook
  6 siblings, 1 reply; 40+ messages in thread
From: Kees Cook @ 2013-04-12 20:13 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, H. Peter Anvin, Thomas Gleixner, Ingo Molnar,
	x86, Jarkko Sakkinen, Matthew Garrett, Matt Fleming,
	Eric Northup, Dan Rosenberg, Julien Tinnes, Will Drewry,
	Kees Cook

This provides routines for selecting a randomized kernel base offset,
bounded by the e820 entries. It tries to use RDRAND and falls back to
RDTSC. If "noaslr" is on the kernel command line, no offset will be used.

Heavily based on work by Dan Rosenberg and Neill Clift.

Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Eric Northup <digitaleric@google.com>
---
 arch/x86/boot/compressed/Makefile |    2 +-
 arch/x86/boot/compressed/aslr.S   |  228 +++++++++++++++++++++++++++++++++++++
 2 files changed, 229 insertions(+), 1 deletion(-)
 create mode 100644 arch/x86/boot/compressed/aslr.S

diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 0dac175..feaf203 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -26,7 +26,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include
 
 VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
 	$(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \
-	$(obj)/piggy.o
+	$(obj)/piggy.o $(obj)/aslr.o
 
 $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
 
diff --git a/arch/x86/boot/compressed/aslr.S b/arch/x86/boot/compressed/aslr.S
new file mode 100644
index 0000000..37cdef4
--- /dev/null
+++ b/arch/x86/boot/compressed/aslr.S
@@ -0,0 +1,228 @@
+/*
+ *  arch/x86/boot/compressed/aslr.S
+ *
+ * Support routine for Kernel Address Space Layout Randomization used by both
+ * the 32 and 64 bit boot code.
+ *
+ */
+	.text
+
+#include <asm/boot.h>
+#include <asm/asm-offsets.h>
+#include <asm/cpufeature.h>
+#include <asm/processor-flags.h>
+#include <asm/e820.h>
+
+#ifdef CONFIG_RANDOMIZE_BASE
+
+	.globl	select_aslr_address
+	.code32
+
+/*
+ * Get the physical memory limit for the run from the physical load position of
+ * the kernel. The kernel loads at LOAD_PHYSICAL_ADDR and we need to know how
+ * much physical memory is available for use after that point to make sure the
+ * relocated kernel will fit. Returns the limit in eax.
+ */
+get_physical_run_end:
+	pushl	%edi
+	pushl	%esi
+	pushl	%ebx
+	pushl	%edx
+	pushl	%ecx
+	movzbl	BP_e820_entries(%esi), %edi
+	leal	BP_e820_map(%esi), %esi
+	testl	%edi, %edi
+	jz	5f
+1:	cmpl	$E820_RAM, E820_type(%esi)
+	jnz	4f
+	movl	E820_addr(%esi), %eax
+	movl	E820_addr+4(%esi), %edx
+	testl	%edx, %edx /* Start address is too big for 32 bit */
+	jnz	4f
+	cmpl	$LOAD_PHYSICAL_ADDR, %eax
+	ja	4f
+	movl	E820_size(%esi), %ecx
+	movl	E820_size+4(%esi), %ebx
+	addl	%eax, %ecx
+	adcl	%edx, %ebx
+	jz	2f /* end address not beyond 32bit*/
+/* For a large run set the limit as 2^32-1 */
+	xorl	%ecx, %ecx
+	decl	%ecx
+	jmp	3f
+2:	cmpl	$LOAD_PHYSICAL_ADDR, %ecx
+	jb	4f
+3:
+	movl	%ecx, %eax
+	jmp	6f
+
+4:	addl	$E820_entry_size, %esi
+	decl	%edi
+	jnz	1b
+5:	xorl	%eax, %eax /* Fail */
+6:	popl	%ecx
+	popl	%edx
+	popl	%ebx
+	popl	%esi
+	popl	%edi
+	ret
+
+/*
+ * Get a random value to be used for the ASLR kernel offset.
+ * Returns the value in eax.
+ */
+get_aslr_offset:
+	pushl	%ebx
+	pushl	%edx
+	pushl	%ecx
+	call	find_cmdline_option
+	testl	%eax, %eax
+	jne	4f
+	/* Standard check for cpuid */
+	pushfl	/* Push original flags */
+	pushfl
+	popl	%eax
+	movl	%eax, %ebx
+	xorl	$X86_EFLAGS_ID, %eax
+	pushl	%eax
+	popfl
+	pushfl
+	popl	%eax
+	popfl	/* Pop original flags */
+	cmpl	%eax, %ebx
+	/* Say zero offset if we can't change the flag */
+	movl	$0, %eax
+	je	4f
+
+	/* Check for cpuid 1 */
+	cpuid
+	cmpl	$0x1, %eax
+	jb	4f
+
+	movl	$0x1, %eax
+	cpuid
+	xor	%eax, %eax
+
+	/* RDRAND is bit 30 */
+	btl	$(X86_FEATURE_RDRAND & 31), %ecx
+	jc	1f
+
+	/* RDTSC is bit 4 */
+	btl	$(X86_FEATURE_TSC & 31), %edx
+	jc	3f
+
+	/* Nothing is supported */
+	jmp	4f
+1:
+	/*
+	 * RDRAND sets carry bit on success, otherwise we should try
+	 * again up to 16 times.
+	 */
+	movl	$0x10, %ecx
+2:
+	/* rdrand %eax */
+	.byte	0x0f, 0xc7, 0xf0
+	jc	4f
+	loop	2b
+
+	/* Fall through: if RDRAND is supported but fails, use RDTSC,
+	 * which is guaranteed to be supported.
+	 */
+3:
+	rdtsc
+	/*
+	 * Since this is time related get some of the least significant bits
+	 * past the alignment mask
+	*/
+	shll	$0x0c, %eax
+	/* Fix the maximal offset allowed */
+4:	andl	$CONFIG_RANDOMIZE_BASE_MAX_OFFSET-1, %eax
+	popl	%ecx
+	popl	%edx
+	popl	%ebx
+	ret
+
+/*
+ * Select the ASLR address to use. We can get called once either in 32
+ * or 64 bit mode. The latter if we have a 64 bit loader.
+ * Uses ebp as the input base and returns the result in eax.
+ */
+select_aslr_address:
+	pushl	%edx
+	pushl	%ebx
+	pushl	%ecx
+	pushl	%edi
+	call	get_aslr_offset
+	pushl	%eax
+	call	get_physical_run_end
+	movl	%eax, %edx
+	popl	%eax
+1:	movl	%ebp, %ebx
+	addl	%eax, %ebx
+	movl	BP_kernel_alignment(%esi), %edi
+	decl	%edi
+	addl	%edi, %ebx
+	notl	%edi
+	andl	%edi, %ebx
+	/* Make sure we don't copy beyond run */
+	leal	boot_stack_end(%ebx), %ecx
+	leal	z_extract_offset(%ecx), %ecx
+	cmpl	%edx, %ecx
+	jb	2f
+	shrl	$1, %eax /* Shink offset */
+	jne	1b /* Move on if offset zero */
+	mov	%ebp, %ebx
+2:	movl	%ebx, %eax
+	popl	%edi
+	popl	%ecx
+	popl	%ebx
+	popl	%edx
+	ret
+
+/*
+ * Find the "noaslr" option if present on the command line.
+ */
+find_cmdline_option:
+
+#define ASLR_STRLEN 6
+
+	pushl	%ecx
+	pushl	%edi
+	xorl	%eax, %eax /* Assume we fail */
+	movl	BP_cmd_line_ptr(%esi), %edi
+	testl	%edi, %edi
+	je	6f
+	/* Calculate string length */
+	leal	-1(%edi), %ecx
+1:	incl	%ecx
+	cmpb	$0, (%ecx)
+	jne	1b
+	subl	%edi, %ecx
+2:	cmpl	$ASLR_STRLEN, %ecx
+	jb	6f
+	cmpl	$0x73616f6e, (%edi) /* noas */
+	jne	4f
+	cmpb	$0x6c, 4(%edi) /* l */
+	jne	4f
+	cmpb	$0x72, 5(%edi) /* r */
+	jne	4f
+	/* If at the start then no beginning separator required */
+	cmpl	%edi, BP_cmd_line_ptr(%esi)
+	je	3f
+	cmpb	$0x20, -1(%edi)
+	ja	4f
+	/* If at the end then no end separator required */
+3:	cmpl	$ASLR_STRLEN, %ecx
+	je	5f
+	cmpb	$0x20, ASLR_STRLEN(%edi)
+	jbe	5f
+4:	incl	%edi
+	decl	%ecx
+	jmp	2b
+5:	incl	%eax /* Sucess */
+6:	popl	%edi
+	popl	%ecx
+	ret
+
+#endif /* CONFIG_RANDOMIZE_BASE */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-12 20:13 [PATCH v2 0/6] kernel ASLR Kees Cook
                   ` (4 preceding siblings ...)
  2013-04-12 20:13 ` [PATCH 5/6] x86: kaslr: routines to choose random base offset Kees Cook
@ 2013-04-12 20:13 ` Kees Cook
  2013-04-14  0:37   ` Yinghai Lu
  2013-04-16 18:08 ` [PATCH v2 0/6] kernel ASLR Kees Cook
  6 siblings, 1 reply; 40+ messages in thread
From: Kees Cook @ 2013-04-12 20:13 UTC (permalink / raw)
  To: linux-kernel
  Cc: kernel-hardening, H. Peter Anvin, Thomas Gleixner, Ingo Molnar,
	x86, Jarkko Sakkinen, Matthew Garrett, Matt Fleming,
	Eric Northup, Dan Rosenberg, Julien Tinnes, Will Drewry,
	Kees Cook

This creates CONFIG_RANDOMIZE_BASE, so that the base offset of the kernel
can be randomized at boot.

This makes kernel vulnerabilities harder to reliably exploit, especially
from remote attacks and local processes in seccomp containers. Keeping the
location of kernel addresses secret becomes very important when using this
feature, so enabling kptr_restrict and dmesg_restrict is recommended.
Besides direct address leaks, several other attacks are possible to bypass
this on local systems, including cache timing[1]. However, the benefits of
this feature in certain environments (e.g. remote services, heavily
confined local processes) exceed the perceived weaknesses[2].

Current entropy is low, since the kernel has basically a minimum 2MB
alignment and has been built with -2G memory addressing. As a result,
available entropy will be 8 bits in the best case. The e820 entries on a
given system may further limit the available memory. This is still be
enough for attacks that must guess the base address to fail 99% of the
time.

This feature is presently incompatible with hibernation.

When built into the kernel, the "noaslr" kernel command line option will
disable the feature.

Heavily based on work by Dan Rosenberg[3] and Neill Clift.

[1] http://www.internetsociety.org/sites/default/files/Practical%20Timing%20Side%20Channel%20Attacks%20Against%20Kernel%20Space%20ASLR.pdf
[2] http://forums.grsecurity.net/viewtopic.php?f=7&t=3367
[3] http://lkml.indiana.edu/hypermail/linux/kernel/1105.3/index.html#00520

Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: Eric Northup <digitaleric@google.com>
---
 Documentation/kernel-parameters.txt  |    4 +
 arch/x86/Kconfig                     |   51 +++++++++++--
 arch/x86/Makefile                    |    3 +
 arch/x86/boot/compressed/head_32.S   |   20 ++++-
 arch/x86/boot/compressed/head_64.S   |  135 ++++++++++++++++++++++++++++++++--
 arch/x86/include/asm/page_32_types.h |    2 +
 arch/x86/include/asm/page_64_types.h |    4 -
 arch/x86/include/asm/page_types.h    |    4 +
 arch/x86/kernel/asm-offsets.c        |   14 ++++
 arch/x86/kernel/setup.c              |   24 ++++++
 10 files changed, 240 insertions(+), 21 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 4609e81..e1b8993 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1839,6 +1839,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 	noapic		[SMP,APIC] Tells the kernel to not make use of any
 			IOAPICs that may be present in the system.
 
+	noaslr		[X86]
+			Disable kernel base offset ASLR (Address Space
+			Layout Randomization) if built into the kernel.
+
 	noautogroup	Disable scheduler automatic task group creation.
 
 	nobats		[PPC] Do not use BATs for mapping kernel lowmem
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 70c0f3d..6fe1a3b 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1649,8 +1649,8 @@ config PHYSICAL_START
 	  If kernel is a not relocatable (CONFIG_RELOCATABLE=n) then
 	  bzImage will decompress itself to above physical address and
 	  run from there. Otherwise, bzImage will run from the address where
-	  it has been loaded by the boot loader and will ignore above physical
-	  address.
+	  it has been loaded by the boot loader, using the above physical
+	  address as a lower bound.
 
 	  In normal kdump cases one does not have to set/change this option
 	  as now bzImage can be compiled as a completely relocatable image
@@ -1696,15 +1696,49 @@ config RELOCATABLE
 
 	  Note: If CONFIG_RELOCATABLE=y, then the kernel runs from the address
 	  it has been loaded at and the compile time physical address
-	  (CONFIG_PHYSICAL_START) is ignored.
-
-# Relocation on x86-32 needs some additional build support
+	  (CONFIG_PHYSICAL_START) is solely used as a lower bound.
+
+config RANDOMIZE_BASE
+	 bool "Randomize the address of the kernel image"
+	 depends on RELOCATABLE
+	 depends on !HIBERNATION
+	 default n
+	 ---help---
+	   Randomizes the phyiscal and virtual address at which the
+	   kernel image is decompressed, as a security feature that
+	   deters exploit attempts relying on knowledge of the location
+	   of kernel internals.
+
+	   This feature also uses a fixed mapping to move the IDT
+	   (if not already done as a fix for the F00F bug), to avoid
+	   exposing the location of kernel internals relative to the
+	   original IDT. This has the additional security benefit of
+	   marking the new virtual address of the IDT read-only.
+
+	   Entropy is generated using the RDRAND instruction if it
+	   is supported.  If not, then RDTSC is used, if supported. If
+	   neither RDRAND nor RDTSC are supported, then no randomness
+	   is introduced. Support for the CPUID instruction is required
+	   to check for the availability of these two instructions.
+
+config RANDOMIZE_BASE_MAX_OFFSET
+	hex "Maximum ASLR offset allowed"
+	depends on RANDOMIZE_BASE
+	default "0x10000000"
+	range 0x0 0x10000000
+	---help---
+	 Determines the maximal offset in bytes that will be applied to the
+	 kernel when Address Space Layout Randomization (ASLR) is active.
+	 Physical memory layout and kernel size may limit this further.
+	 This must be a power of two.
+
+# Relocation on x86-32/64 needs some additional build support
 config X86_NEED_RELOCS
 	def_bool y
-	depends on X86_32 && RELOCATABLE
+	depends on RELOCATABLE
 
 config PHYSICAL_ALIGN
-	hex "Alignment value to which kernel should be aligned" if X86_32
+	hex "Alignment value to which kernel should be aligned"
 	default "0x1000000"
 	range 0x2000 0x1000000
 	---help---
@@ -1724,6 +1758,9 @@ config PHYSICAL_ALIGN
 	  end result is that kernel runs from a physical address meeting
 	  above alignment restrictions.
 
+	  Generally when using CONFIG_RANDOMIZE_BASE, this is safe to
+	  lower to 0x200000.
+
 	  Don't change this unless you know what you are doing.
 
 config HOTPLUG_CPU
diff --git a/arch/x86/Makefile b/arch/x86/Makefile
index 5c47726..4f280bd 100644
--- a/arch/x86/Makefile
+++ b/arch/x86/Makefile
@@ -60,6 +60,9 @@ else
 	# Use -mpreferred-stack-boundary=3 if supported.
 	KBUILD_CFLAGS += $(call cc-option,-mno-sse -mpreferred-stack-boundary=3)
 
+        ifdef CONFIG_RANDOMIZE_BASE
+                LDFLAGS_vmlinux := --emit-relocs
+        endif
         # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu)
         cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8)
         cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona)
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index 1e3184f..957b1c7 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -29,6 +29,7 @@
 #include <asm/page_types.h>
 #include <asm/boot.h>
 #include <asm/asm-offsets.h>
+#include <asm/cpufeature.h>
 
 	__HEAD
 ENTRY(startup_32)
@@ -111,15 +112,29 @@ preferred_addr:
  */
 
 #ifdef CONFIG_RELOCATABLE
+#ifdef CONFIG_RANDOMIZE_BASE
+	/* Setup boot stack for calls */
+	leal	boot_stack_end(%ebp), %esp
+	call	select_aslr_address /* Select ASLR address */
+	movl	%eax, %ebx
+	/* LOAD_PHSYICAL_ADDR is the minimum safe address we can
+	 * decompress at */
+	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
+	jae	1f
+	movl	$LOAD_PHYSICAL_ADDR, %ebx
+1:
+#else /* CONFIG_RANDOMIZE_BASE */
 	movl	%ebp, %ebx
 	movl	BP_kernel_alignment(%esi), %eax
 	decl	%eax
 	addl    %eax, %ebx
 	notl	%eax
 	andl    %eax, %ebx
-#else
+#endif /* CONFIG_RANDOMIZE_BASE */
+
+#else /* CONFIG_RELOCATABLE */
 	movl	$LOAD_PHYSICAL_ADDR, %ebx
-#endif
+#endif /* CONFIG_RELOCATABLE */
 
 	/* Target address to relocate to for decompression */
 	addl	$z_extract_offset, %ebx
@@ -235,3 +250,4 @@ boot_heap:
 boot_stack:
 	.fill BOOT_STACK_SIZE, 1, 0
 boot_stack_end:
+	.globl	boot_stack_end
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index c1d383d..fc37910 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -59,7 +59,7 @@ ENTRY(startup_32)
 1:
 
 /*
- * Calculate the delta between where we were compiled to run
+ * Calculate the delta between where we were linked to load
  * at and where we were actually loaded at.  This can only be done
  * with a short local call on x86.  Nothing  else will tell us what
  * address we are running at.  The reserved chunk of the real-mode
@@ -78,10 +78,10 @@ ENTRY(startup_32)
 
 	call	verify_cpu
 	testl	%eax, %eax
-	jnz	no_longmode
+	jnz	hang
 
 /*
- * Compute the delta between where we were compiled to run at
+ * Compute the delta between where we were linked to load at
  * and where the code will actually run at.
  *
  * %ebp contains the address we are loaded at by the boot loader and %ebx
@@ -90,15 +90,32 @@ ENTRY(startup_32)
  */
 
 #ifdef CONFIG_RELOCATABLE
+#ifdef CONFIG_RANDOMIZE_BASE
+	call	select_aslr_address /* Select ASLR offset */
+	movl	%eax, %ebx
+	/* LOAD_PHYSICAL_ADDR is the minimum safe address we can
+	 * decompress at */
+	cmpl	$LOAD_PHYSICAL_ADDR, %ebx
+	jae	1f
+	movl	$LOAD_PHYSICAL_ADDR, %ebx
+#else /* CONFIG_RANDOMIZE_BASE */
 	movl	%ebp, %ebx
 	movl	BP_kernel_alignment(%esi), %eax
 	decl	%eax
 	addl	%eax, %ebx
 	notl	%eax
 	andl	%eax, %ebx
-#else
+#endif /* CONFIG_RANDOMIZE_BASE */
+
+#ifdef CONFIG_RANDOMIZE_BASE
+1:	movl	%ebx, %eax
+	subl	$LOAD_PHYSICAL_ADDR, %eax
+        movl	%eax, aslr_offset(%ebp)
+	incl	aslr_in_32bit(%ebp) /* say 32 bit code ran */
+#endif /* CONFIG_RANDOMIZE_BASE */
+#else /* CONFIG_RELOCATABLE */
 	movl	$LOAD_PHYSICAL_ADDR, %ebx
-#endif
+#endif /* CONFIG_RELOCATABLE */
 
 	/* Target address to relocate to for decompression */
 	addl	$z_extract_offset, %ebx
@@ -266,14 +283,30 @@ preferred_addr:
 	/* Start with the delta to where the kernel will run at. */
 #ifdef CONFIG_RELOCATABLE
 	leaq	startup_32(%rip) /* - $startup_32 */, %rbp
+#ifdef CONFIG_RANDOMIZE_BASE
+	leaq	boot_stack_end(%rip), %rsp
+	testl	$1, aslr_in_32bit(%rip)
+	jne	1f
+	call	select_aslr_address
+	movq	%rax, %rbp
+	jmp	2f
+1:	movl	aslr_offset(%rip), %eax
+	addq	%rax, %rbp
+	/* LOAD_PHYSICAL_ADDR is the minimum safe address we can
+	 * decompress at. */
+	cmpq	$LOAD_PHYSICAL_ADDR, %rbp
+	jae	2f
+	movq	$LOAD_PHYSICAL_ADDR, %rbp
+2:
+#endif	/* CONFIG_RANDOMIZE_BASE */
 	movl	BP_kernel_alignment(%rsi), %eax
 	decl	%eax
 	addq	%rax, %rbp
 	notq	%rax
 	andq	%rax, %rbp
-#else
+#else /* CONFIG_RELOCATABLE */
 	movq	$LOAD_PHYSICAL_ADDR, %rbp
-#endif
+#endif /* CONFIG_RELOCATABLE */
 
 	/* Target address to relocate to for decompression */
 	leaq	z_extract_offset(%rbp), %rbx
@@ -343,13 +376,85 @@ relocated:
 	call	decompress_kernel
 	popq	%rsi
 
+#ifdef CONFIG_RANDOMIZE_BASE
+/*
+ * Find the address of the relocations.
+ */
+	leaq	z_output_len(%rbp), %rdi
+
+/*
+ * Calculate the delta between where vmlinux was linked to load
+ * and where it was actually loaded.
+ */
+	movq	%rbp, %rbx
+	subq	$LOAD_PHYSICAL_ADDR, %rbx
+	je	3f	/* Nothing to be done if loaded at linked addr. */
+/*
+ * The kernel contains a table of relocation addresses. Those addresses
+ * have the final load address of the kernel in virtual memory.
+ * We are currently working in the self map. So we need to create an
+ * adjustment for kernel memory addresses to the self map. This will
+ * involve subtracting out the base address of the kernel.
+ */
+	movq	$-__START_KERNEL_map, %rdx /* Literal is too big for add etc */
+	addq	%rbx, %rdx
+/*
+ * Process relocations. 32 bit relocations first then 64 bit after.
+ * Two sets of binary relocations are added to the end of the
+ * kernel before compression. Each relocation table entry is the kernel
+ * address of the location which needs to be updated stored as a 32 bit
+ * value which is sign extended to 64 bits.
+ *
+ * Format is:
+ *
+ * kernel bits...
+ * 0 - zero terminator for 64 bit relocations
+ * 64 bit relocation repeated
+ * 0 - zero terminator for 32 bit relocations
+ * 32 bit relocation repeated
+ *
+ * So we work backwards from the end of the decompressed image.
+ */
+1:	subq	$4, %rdi
+	movslq	(%rdi), %rcx
+	testq	%rcx, %rcx
+	je	2f
+	addq	%rdx, %rcx
+/*
+ * Relocation can't be before the image or
+ * after the current position of the current relocation.
+ * This is a cheap bounds check. It could be more exact
+ * and limit to the end of the image prior to the relocations
+ * but allowing relocations themselves to be fixed up will not
+ * do any harm.
+ */
+	cmpq	%rbp, %rcx
+	jb	hang
+	cmpq	%rdi, %rcx
+	jae	hang
+	addl	%ebx, (%rcx)	/* 32 bit relocation */
+	jmp	1b
+2:	subq	$4, %rdi
+	movslq	(%rdi), %rcx
+	testq	%rcx, %rcx
+	je	3f
+	addq	%rdx, %rcx
+	cmpq	%rbp, %rcx
+	jb	hang
+	cmpq	%rdi, %rcx
+	jae	hang
+	addq	%rbx, (%rcx)	/* 64 bit relocation */
+	jmp	2b
+3:
+#endif /* CONFIG_RANDOMIZE_BASE */
+
 /*
  * Jump to the decompressed kernel.
  */
 	jmp	*%rbp
 
 	.code32
-no_longmode:
+hang:
 	/* This isn't an x86-64 CPU so hang */
 1:
 	hlt
@@ -369,6 +474,19 @@ gdt:
 	.quad   0x0000000000000000	/* TS continued */
 gdt_end:
 
+#ifdef CONFIG_RANDOMIZE_BASE
+aslr_offset:
+	.long	0			/* Offset selected for ASLR */
+/*
+ * Set if ASLR ran in 32 bit mode. For 64 bit loaders the 32 bit code
+ * doesn't run and we need to do the offset calculation there for the
+ * first time.
+ */
+aslr_in_32bit:
+	.long	0
+
+#endif /* CONFIG_RANDOMIZE_BASE */
+
 /*
  * Stack and heap for uncompression
  */
@@ -379,6 +497,7 @@ boot_heap:
 boot_stack:
 	.fill BOOT_STACK_SIZE, 1, 0
 boot_stack_end:
+	.globl	boot_stack_end
 
 /*
  * Space for page tables (not in .bss so not zeroed)
diff --git a/arch/x86/include/asm/page_32_types.h b/arch/x86/include/asm/page_32_types.h
index ef17af0..996582c 100644
--- a/arch/x86/include/asm/page_32_types.h
+++ b/arch/x86/include/asm/page_32_types.h
@@ -15,6 +15,8 @@
  */
 #define __PAGE_OFFSET		_AC(CONFIG_PAGE_OFFSET, UL)
 
+#define __START_KERNEL		(__PAGE_OFFSET + __PHYSICAL_START)
+
 #define THREAD_SIZE_ORDER	1
 #define THREAD_SIZE		(PAGE_SIZE << THREAD_SIZE_ORDER)
 
diff --git a/arch/x86/include/asm/page_64_types.h b/arch/x86/include/asm/page_64_types.h
index 8b491e6..c0dfe38 100644
--- a/arch/x86/include/asm/page_64_types.h
+++ b/arch/x86/include/asm/page_64_types.h
@@ -32,10 +32,6 @@
  */
 #define __PAGE_OFFSET           _AC(0xffff880000000000, UL)
 
-#define __PHYSICAL_START	((CONFIG_PHYSICAL_START +	 	\
-				  (CONFIG_PHYSICAL_ALIGN - 1)) &	\
-				 ~(CONFIG_PHYSICAL_ALIGN - 1))
-
 #define __START_KERNEL		(__START_KERNEL_map + __PHYSICAL_START)
 #define __START_KERNEL_map	_AC(0xffffffff80000000, UL)
 
diff --git a/arch/x86/include/asm/page_types.h b/arch/x86/include/asm/page_types.h
index 54c9787..b6f9b49 100644
--- a/arch/x86/include/asm/page_types.h
+++ b/arch/x86/include/asm/page_types.h
@@ -33,6 +33,10 @@
 	(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0 ) | \
 	 VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
+#define __PHYSICAL_START	((CONFIG_PHYSICAL_START +		\
+				  (CONFIG_PHYSICAL_ALIGN - 1)) &	\
+				 ~(CONFIG_PHYSICAL_ALIGN - 1))
+
 #ifdef CONFIG_X86_64
 #include <asm/page_64_types.h>
 #else
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index 2861082..7e014b7 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -70,6 +70,20 @@ void common(void) {
 	OFFSET(BP_pref_address, boot_params, hdr.pref_address);
 	OFFSET(BP_code32_start, boot_params, hdr.code32_start);
 
+	OFFSET(BP_scratch, boot_params, scratch);
+	OFFSET(BP_loadflags, boot_params, hdr.loadflags);
+	OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch);
+	OFFSET(BP_version, boot_params, hdr.version);
+	OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment);
+	OFFSET(BP_e820_map, boot_params, e820_map);
+	OFFSET(BP_e820_entries, boot_params, e820_entries);
+	OFFSET(BP_cmd_line_ptr, boot_params, hdr.cmd_line_ptr);
+
+	OFFSET(E820_addr, e820entry, addr);
+	OFFSET(E820_size, e820entry, size);
+	OFFSET(E820_type, e820entry, type);
+	DEFINE(E820_entry_size, sizeof(struct e820entry));
+
 	BLANK();
 	DEFINE(PTREGS_SIZE, sizeof(struct pt_regs));
 }
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 90d8cc9..fd9e68f 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -801,6 +801,18 @@ static void __init trim_low_memory_range(void)
 }
 	
 /*
+ * Dump out kernel offset information on panic.
+ */
+static int
+dump_kernel_offset(struct notifier_block *self, unsigned long v, void *p)
+{
+	pr_emerg("Kernel Offset: 0x%lx\n",
+		 (unsigned long)&_text - __START_KERNEL);
+
+	return 0;
+}
+
+/*
  * Determine if we were loaded by an EFI loader.  If so, then we have also been
  * passed the efi memmap, systab, etc., so we should use these data structures
  * for initialization.  Note, the efi init code path is determined by the
@@ -1220,3 +1232,15 @@ void __init i386_reserve_resources(void)
 }
 
 #endif /* CONFIG_X86_32 */
+
+static struct notifier_block kernel_offset_notifier = {
+	.notifier_call = dump_kernel_offset
+};
+
+static int __init register_kernel_offset_dumper(void)
+{
+	atomic_notifier_chain_register(&panic_notifier_list,
+					&kernel_offset_notifier);
+	return 0;
+}
+__initcall(register_kernel_offset_dumper);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [PATCH 5/6] x86: kaslr: routines to choose random base offset
  2013-04-12 20:13 ` [PATCH 5/6] x86: kaslr: routines to choose random base offset Kees Cook
@ 2013-04-14  0:11   ` Yinghai Lu
  0 siblings, 0 replies; 40+ messages in thread
From: Yinghai Lu @ 2013-04-14  0:11 UTC (permalink / raw)
  To: Kees Cook
  Cc: Linux Kernel Mailing List, kernel-hardening, H. Peter Anvin,
	Thomas Gleixner, Ingo Molnar, the arch/x86 maintainers,
	Jarkko Sakkinen, Matthew Garrett, Matt Fleming, Eric Northup,
	Dan Rosenberg, Julien Tinnes, Will Drewry

On Fri, Apr 12, 2013 at 1:13 PM, Kees Cook <keescook@chromium.org> wrote:
> This provides routines for selecting a randomized kernel base offset,
> bounded by the e820 entries. It tries to use RDRAND and falls back to
> RDTSC. If "noaslr" is on the kernel command line, no offset will be used.
>
> Heavily based on work by Dan Rosenberg and Neill Clift.
>
> Signed-off-by: Kees Cook <keescook@chromium.org>
> Cc: Eric Northup <digitaleric@google.com>
> ---
>  arch/x86/boot/compressed/Makefile |    2 +-
>  arch/x86/boot/compressed/aslr.S   |  228 +++++++++++++++++++++++++++++++++++++
>  2 files changed, 229 insertions(+), 1 deletion(-)
>  create mode 100644 arch/x86/boot/compressed/aslr.S
>
> diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
> index 0dac175..feaf203 100644
> --- a/arch/x86/boot/compressed/Makefile
> +++ b/arch/x86/boot/compressed/Makefile
> @@ -26,7 +26,7 @@ HOST_EXTRACFLAGS += -I$(srctree)/tools/include
>
>  VMLINUX_OBJS = $(obj)/vmlinux.lds $(obj)/head_$(BITS).o $(obj)/misc.o \
>         $(obj)/string.o $(obj)/cmdline.o $(obj)/early_serial_console.o \
> -       $(obj)/piggy.o
> +       $(obj)/piggy.o $(obj)/aslr.o
>
>  $(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
>
> diff --git a/arch/x86/boot/compressed/aslr.S b/arch/x86/boot/compressed/aslr.S
> new file mode 100644
> index 0000000..37cdef4
> --- /dev/null
> +++ b/arch/x86/boot/compressed/aslr.S
> @@ -0,0 +1,228 @@
> +/*
> + *  arch/x86/boot/compressed/aslr.S
> + *
> + * Support routine for Kernel Address Space Layout Randomization used by both
> + * the 32 and 64 bit boot code.
> + *
> + */
> +       .text
> +
> +#include <asm/boot.h>
> +#include <asm/asm-offsets.h>
> +#include <asm/cpufeature.h>
> +#include <asm/processor-flags.h>
> +#include <asm/e820.h>
> +
> +#ifdef CONFIG_RANDOMIZE_BASE
> +
> +       .globl  select_aslr_address
> +       .code32
> +
> +/*
> + * Get the physical memory limit for the run from the physical load position of
> + * the kernel. The kernel loads at LOAD_PHYSICAL_ADDR and we need to know how
> + * much physical memory is available for use after that point to make sure the
> + * relocated kernel will fit. Returns the limit in eax.
> + */
> +get_physical_run_end:
> +       pushl   %edi
> +       pushl   %esi
> +       pushl   %ebx
> +       pushl   %edx
> +       pushl   %ecx
> +       movzbl  BP_e820_entries(%esi), %edi
> +       leal    BP_e820_map(%esi), %esi
> +       testl   %edi, %edi
> +       jz      5f
> +1:     cmpl    $E820_RAM, E820_type(%esi)
> +       jnz     4f
> +       movl    E820_addr(%esi), %eax
> +       movl    E820_addr+4(%esi), %edx
> +       testl   %edx, %edx /* Start address is too big for 32 bit */
> +       jnz     4f
> +       cmpl    $LOAD_PHYSICAL_ADDR, %eax
> +       ja      4f
> +       movl    E820_size(%esi), %ecx
> +       movl    E820_size+4(%esi), %ebx
> +       addl    %eax, %ecx
> +       adcl    %edx, %ebx
> +       jz      2f /* end address not beyond 32bit*/
> +/* For a large run set the limit as 2^32-1 */
> +       xorl    %ecx, %ecx
> +       decl    %ecx
> +       jmp     3f
> +2:     cmpl    $LOAD_PHYSICAL_ADDR, %ecx
> +       jb      4f
> +3:
> +       movl    %ecx, %eax
> +       jmp     6f
> +
> +4:     addl    $E820_entry_size, %esi
> +       decl    %edi
> +       jnz     1b
> +5:     xorl    %eax, %eax /* Fail */
> +6:     popl    %ecx
> +       popl    %edx
> +       popl    %ebx
> +       popl    %esi
> +       popl    %edi
> +       ret
> +
> +/*
> + * Get a random value to be used for the ASLR kernel offset.
> + * Returns the value in eax.
> + */
> +get_aslr_offset:
> +       pushl   %ebx
> +       pushl   %edx
> +       pushl   %ecx
> +       call    find_cmdline_option
> +       testl   %eax, %eax
> +       jne     4f
> +       /* Standard check for cpuid */
> +       pushfl  /* Push original flags */
> +       pushfl
> +       popl    %eax
> +       movl    %eax, %ebx
> +       xorl    $X86_EFLAGS_ID, %eax
> +       pushl   %eax
> +       popfl
> +       pushfl
> +       popl    %eax
> +       popfl   /* Pop original flags */
> +       cmpl    %eax, %ebx
> +       /* Say zero offset if we can't change the flag */
> +       movl    $0, %eax
> +       je      4f
> +
> +       /* Check for cpuid 1 */
> +       cpuid
> +       cmpl    $0x1, %eax
> +       jb      4f
> +
> +       movl    $0x1, %eax
> +       cpuid
> +       xor     %eax, %eax
> +
> +       /* RDRAND is bit 30 */
> +       btl     $(X86_FEATURE_RDRAND & 31), %ecx
> +       jc      1f
> +
> +       /* RDTSC is bit 4 */
> +       btl     $(X86_FEATURE_TSC & 31), %edx
> +       jc      3f
> +
> +       /* Nothing is supported */
> +       jmp     4f
> +1:
> +       /*
> +        * RDRAND sets carry bit on success, otherwise we should try
> +        * again up to 16 times.
> +        */
> +       movl    $0x10, %ecx
> +2:
> +       /* rdrand %eax */
> +       .byte   0x0f, 0xc7, 0xf0
> +       jc      4f
> +       loop    2b
> +
> +       /* Fall through: if RDRAND is supported but fails, use RDTSC,
> +        * which is guaranteed to be supported.
> +        */
> +3:
> +       rdtsc
> +       /*
> +        * Since this is time related get some of the least significant bits
> +        * past the alignment mask
> +       */
> +       shll    $0x0c, %eax
> +       /* Fix the maximal offset allowed */
> +4:     andl    $CONFIG_RANDOMIZE_BASE_MAX_OFFSET-1, %eax
> +       popl    %ecx
> +       popl    %edx
> +       popl    %ebx
> +       ret
> +
> +/*
> + * Select the ASLR address to use. We can get called once either in 32
> + * or 64 bit mode. The latter if we have a 64 bit loader.
> + * Uses ebp as the input base and returns the result in eax.
> + */
> +select_aslr_address:
> +       pushl   %edx
> +       pushl   %ebx
> +       pushl   %ecx
> +       pushl   %edi
> +       call    get_aslr_offset
> +       pushl   %eax
> +       call    get_physical_run_end
> +       movl    %eax, %edx
> +       popl    %eax
> +1:     movl    %ebp, %ebx
> +       addl    %eax, %ebx
> +       movl    BP_kernel_alignment(%esi), %edi
> +       decl    %edi
> +       addl    %edi, %ebx
> +       notl    %edi
> +       andl    %edi, %ebx
> +       /* Make sure we don't copy beyond run */
> +       leal    boot_stack_end(%ebx), %ecx
> +       leal    z_extract_offset(%ecx), %ecx
> +       cmpl    %edx, %ecx
> +       jb      2f
> +       shrl    $1, %eax /* Shink offset */
> +       jne     1b /* Move on if offset zero */
> +       mov     %ebp, %ebx
> +2:     movl    %ebx, %eax
> +       popl    %edi
> +       popl    %ecx
> +       popl    %ebx
> +       popl    %edx
> +       ret

So the code could run when it is 64bit and bzImage64 is loaded above 4G?

Thanks

Yinghai

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-12 20:13 ` [PATCH 6/6] x86: kaslr: relocate base offset at boot Kees Cook
@ 2013-04-14  0:37   ` Yinghai Lu
  2013-04-14  3:06     ` H. Peter Anvin
  0 siblings, 1 reply; 40+ messages in thread
From: Yinghai Lu @ 2013-04-14  0:37 UTC (permalink / raw)
  To: Kees Cook
  Cc: Linux Kernel Mailing List, kernel-hardening, H. Peter Anvin,
	Thomas Gleixner, Ingo Molnar, the arch/x86 maintainers,
	Jarkko Sakkinen, Matthew Garrett, Matt Fleming, Eric Northup,
	Dan Rosenberg, Julien Tinnes, Will Drewry

On Fri, Apr 12, 2013 at 1:13 PM, Kees Cook <keescook@chromium.org> wrote:
[...]
> diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
> index c1d383d..fc37910 100644
> --- a/arch/x86/boot/compressed/head_64.S
> +++ b/arch/x86/boot/compressed/head_64.S
> @@ -59,7 +59,7 @@ ENTRY(startup_32)
>  1:
>
>  /*
> - * Calculate the delta between where we were compiled to run
> + * Calculate the delta between where we were linked to load
>   * at and where we were actually loaded at.  This can only be done
>   * with a short local call on x86.  Nothing  else will tell us what
>   * address we are running at.  The reserved chunk of the real-mode
> @@ -78,10 +78,10 @@ ENTRY(startup_32)
>
>         call    verify_cpu
>         testl   %eax, %eax
> -       jnz     no_longmode
> +       jnz     hang
>
>  /*
> - * Compute the delta between where we were compiled to run at
> + * Compute the delta between where we were linked to load at
>   * and where the code will actually run at.
>   *
>   * %ebp contains the address we are loaded at by the boot loader and %ebx
> @@ -90,15 +90,32 @@ ENTRY(startup_32)
>   */
>
>  #ifdef CONFIG_RELOCATABLE
> +#ifdef CONFIG_RANDOMIZE_BASE
> +       call    select_aslr_address /* Select ASLR offset */
> +       movl    %eax, %ebx
> +       /* LOAD_PHYSICAL_ADDR is the minimum safe address we can
> +        * decompress at */
> +       cmpl    $LOAD_PHYSICAL_ADDR, %ebx
> +       jae     1f
> +       movl    $LOAD_PHYSICAL_ADDR, %ebx
> +#else /* CONFIG_RANDOMIZE_BASE */
>         movl    %ebp, %ebx
>         movl    BP_kernel_alignment(%esi), %eax
>         decl    %eax
>         addl    %eax, %ebx
>         notl    %eax
>         andl    %eax, %ebx
> -#else
> +#endif /* CONFIG_RANDOMIZE_BASE */
> +
> +#ifdef CONFIG_RANDOMIZE_BASE
> +1:     movl    %ebx, %eax
> +       subl    $LOAD_PHYSICAL_ADDR, %eax
> +        movl   %eax, aslr_offset(%ebp)
> +       incl    aslr_in_32bit(%ebp) /* say 32 bit code ran */
> +#endif /* CONFIG_RANDOMIZE_BASE */
> +#else /* CONFIG_RELOCATABLE */
>         movl    $LOAD_PHYSICAL_ADDR, %ebx
> -#endif
> +#endif /* CONFIG_RELOCATABLE */
>
>         /* Target address to relocate to for decompression */
>         addl    $z_extract_offset, %ebx
> @@ -266,14 +283,30 @@ preferred_addr:
>         /* Start with the delta to where the kernel will run at. */
>  #ifdef CONFIG_RELOCATABLE
>         leaq    startup_32(%rip) /* - $startup_32 */, %rbp
> +#ifdef CONFIG_RANDOMIZE_BASE
> +       leaq    boot_stack_end(%rip), %rsp
> +       testl   $1, aslr_in_32bit(%rip)
> +       jne     1f
> +       call    select_aslr_address
> +       movq    %rax, %rbp

select_aslr_address only play %ebp, so you assume bzImage is loaded under 4G?

can you just run slect_aslr_address in 64bit only?

> +       jmp     2f
> +1:     movl    aslr_offset(%rip), %eax
> +       addq    %rax, %rbp
> +       /* LOAD_PHYSICAL_ADDR is the minimum safe address we can
> +        * decompress at. */
> +       cmpq    $LOAD_PHYSICAL_ADDR, %rbp
> +       jae     2f
> +       movq    $LOAD_PHYSICAL_ADDR, %rbp

should use old value before select_alsr_addr?

> +2:
> +#endif /* CONFIG_RANDOMIZE_BASE */
>         movl    BP_kernel_alignment(%rsi), %eax
>         decl    %eax
>         addq    %rax, %rbp
>         notq    %rax
>         andq    %rax, %rbp
> -#else
> +#else /* CONFIG_RELOCATABLE */
>         movq    $LOAD_PHYSICAL_ADDR, %rbp
> -#endif
> +#endif /* CONFIG_RELOCATABLE */
>
>         /* Target address to relocate to for decompression */
>         leaq    z_extract_offset(%rbp), %rbx
> @@ -343,13 +376,85 @@ relocated:
>         call    decompress_kernel
>         popq    %rsi
>
> +#ifdef CONFIG_RANDOMIZE_BASE
> +/*
> + * Find the address of the relocations.
> + */
> +       leaq    z_output_len(%rbp), %rdi
> +
> +/*
> + * Calculate the delta between where vmlinux was linked to load
> + * and where it was actually loaded.
> + */
> +       movq    %rbp, %rbx
> +       subq    $LOAD_PHYSICAL_ADDR, %rbx
> +       je      3f      /* Nothing to be done if loaded at linked addr. */
> +/*
> + * The kernel contains a table of relocation addresses. Those addresses
> + * have the final load address of the kernel in virtual memory.
> + * We are currently working in the self map. So we need to create an
> + * adjustment for kernel memory addresses to the self map. This will
> + * involve subtracting out the base address of the kernel.
> + */
> +       movq    $-__START_KERNEL_map, %rdx /* Literal is too big for add etc */
> +       addq    %rbx, %rdx
> +/*
> + * Process relocations. 32 bit relocations first then 64 bit after.
> + * Two sets of binary relocations are added to the end of the
> + * kernel before compression. Each relocation table entry is the kernel
> + * address of the location which needs to be updated stored as a 32 bit
> + * value which is sign extended to 64 bits.
> + *
> + * Format is:
> + *
> + * kernel bits...
> + * 0 - zero terminator for 64 bit relocations
> + * 64 bit relocation repeated
> + * 0 - zero terminator for 32 bit relocations
> + * 32 bit relocation repeated
> + *
> + * So we work backwards from the end of the decompressed image.
> + */
> +1:     subq    $4, %rdi
> +       movslq  (%rdi), %rcx
> +       testq   %rcx, %rcx
> +       je      2f
> +       addq    %rdx, %rcx
> +/*
> + * Relocation can't be before the image or
> + * after the current position of the current relocation.
> + * This is a cheap bounds check. It could be more exact
> + * and limit to the end of the image prior to the relocations
> + * but allowing relocations themselves to be fixed up will not
> + * do any harm.
> + */
> +       cmpq    %rbp, %rcx
> +       jb      hang
> +       cmpq    %rdi, %rcx
> +       jae     hang
> +       addl    %ebx, (%rcx)    /* 32 bit relocation */
> +       jmp     1b
> +2:     subq    $4, %rdi
> +       movslq  (%rdi), %rcx
> +       testq   %rcx, %rcx
> +       je      3f
> +       addq    %rdx, %rcx
> +       cmpq    %rbp, %rcx
> +       jb      hang
> +       cmpq    %rdi, %rcx
> +       jae     hang
> +       addq    %rbx, (%rcx)    /* 64 bit relocation */
> +       jmp     2b
> +3:
> +#endif /* CONFIG_RANDOMIZE_BASE */

so decompress code position is changed?

You may push out bss and other data area of run-time kernel of limit
that boot loader
chose according to setup_header.init_size.
aka that make those area overlap with ram hole or other area like
boot command line or initrd....


Thanks

Yinghai

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-14  0:37   ` Yinghai Lu
@ 2013-04-14  3:06     ` H. Peter Anvin
  2013-04-15 21:06       ` Eric Northup
  0 siblings, 1 reply; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-14  3:06 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Kees Cook, Linux Kernel Mailing List, kernel-hardening,
	Thomas Gleixner, Ingo Molnar, the arch/x86 maintainers,
	Jarkko Sakkinen, Matthew Garrett, Matt Fleming, Eric Northup,
	Dan Rosenberg, Julien Tinnes, Will Drewry

On 04/13/2013 05:37 PM, Yinghai Lu wrote:
> 
> so decompress code position is changed?
> 
> You may push out bss and other data area of run-time kernel of limit
> that boot loader
> chose according to setup_header.init_size.
> aka that make those area overlap with ram hole or other area like
> boot command line or initrd....
> 

Is there a strong reason to randomize the physical address on 64 bits
(and if so, shouldn't we do it right?)

	-hpa


-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-14  3:06     ` H. Peter Anvin
@ 2013-04-15 21:06       ` Eric Northup
  2013-04-15 21:25         ` H. Peter Anvin
  0 siblings, 1 reply; 40+ messages in thread
From: Eric Northup @ 2013-04-15 21:06 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Yinghai Lu, Kees Cook, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On Sat, Apr 13, 2013 at 8:06 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 04/13/2013 05:37 PM, Yinghai Lu wrote:
>>
>> so decompress code position is changed?
>>
>> You may push out bss and other data area of run-time kernel of limit
>> that boot loader
>> chose according to setup_header.init_size.
>> aka that make those area overlap with ram hole or other area like
>> boot command line or initrd....
>>
>
> Is there a strong reason to randomize the physical address on 64 bits
> (and if so, shouldn't we do it right?)

The reason to randomize the physical address is because of the kernel
direct mapping range -- a predictable-to-attackers physical address
implies a predictable-to-attackers virtual address.

It had seemed to me like changing the virtual base of the direct
mapping would be much more involved than physically relocating the
kernel, but better suggestions would be most welcome :-)

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 21:06       ` Eric Northup
@ 2013-04-15 21:25         ` H. Peter Anvin
  2013-04-15 21:41           ` Kees Cook
  0 siblings, 1 reply; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-15 21:25 UTC (permalink / raw)
  To: Eric Northup
  Cc: Yinghai Lu, Kees Cook, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On 04/15/2013 02:06 PM, Eric Northup wrote:
> On Sat, Apr 13, 2013 at 8:06 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>> On 04/13/2013 05:37 PM, Yinghai Lu wrote:
>>>
>>> so decompress code position is changed?
>>>
>>> You may push out bss and other data area of run-time kernel of limit
>>> that boot loader
>>> chose according to setup_header.init_size.
>>> aka that make those area overlap with ram hole or other area like
>>> boot command line or initrd....
>>>
>>
>> Is there a strong reason to randomize the physical address on 64 bits
>> (and if so, shouldn't we do it right?)
> 
> The reason to randomize the physical address is because of the kernel
> direct mapping range -- a predictable-to-attackers physical address
> implies a predictable-to-attackers virtual address.
> 
> It had seemed to me like changing the virtual base of the direct
> mapping would be much more involved than physically relocating the
> kernel, but better suggestions would be most welcome :-)
> 

You seem to be missing something here...

There are *two* mappings in 64-bit mode.  Physically, if you're going to
randomize you might as well randomize over the entire range... except
not too far down (on either 32 or 64 bit mode)... in particular, you
don't want to drop below 16 MiB if you can avoid it.

On 64 bits, there is no reason the virtual address has to be randomized
the same way.

	-hpa


-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 21:25         ` H. Peter Anvin
@ 2013-04-15 21:41           ` Kees Cook
  2013-04-15 21:44             ` Eric Northup
  2013-04-15 21:46             ` H. Peter Anvin
  0 siblings, 2 replies; 40+ messages in thread
From: Kees Cook @ 2013-04-15 21:41 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Eric Northup, Yinghai Lu, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On Mon, Apr 15, 2013 at 2:25 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 04/15/2013 02:06 PM, Eric Northup wrote:
>> On Sat, Apr 13, 2013 at 8:06 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>>> On 04/13/2013 05:37 PM, Yinghai Lu wrote:
>>>>
>>>> so decompress code position is changed?
>>>>
>>>> You may push out bss and other data area of run-time kernel of limit
>>>> that boot loader
>>>> chose according to setup_header.init_size.
>>>> aka that make those area overlap with ram hole or other area like
>>>> boot command line or initrd....
>>>>
>>>
>>> Is there a strong reason to randomize the physical address on 64 bits
>>> (and if so, shouldn't we do it right?)
>>
>> The reason to randomize the physical address is because of the kernel
>> direct mapping range -- a predictable-to-attackers physical address
>> implies a predictable-to-attackers virtual address.
>>
>> It had seemed to me like changing the virtual base of the direct
>> mapping would be much more involved than physically relocating the
>> kernel, but better suggestions would be most welcome :-)
>>
>
> You seem to be missing something here...
>
> There are *two* mappings in 64-bit mode.  Physically, if you're going to
> randomize you might as well randomize over the entire range... except
> not too far down (on either 32 or 64 bit mode)... in particular, you
> don't want to drop below 16 MiB if you can avoid it.
>
> On 64 bits, there is no reason the virtual address has to be randomized
> the same way.

Aren't we bound by the negative 2GB addressing due to -mcmodel=kernel?

-Kees

--
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 21:41           ` Kees Cook
@ 2013-04-15 21:44             ` Eric Northup
  2013-04-15 21:46             ` H. Peter Anvin
  1 sibling, 0 replies; 40+ messages in thread
From: Eric Northup @ 2013-04-15 21:44 UTC (permalink / raw)
  To: Kees Cook
  Cc: H. Peter Anvin, Yinghai Lu, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

W/the relocation information, we can pick the virtual address to load
at independent from the physical load address.

On Mon, Apr 15, 2013 at 2:41 PM, Kees Cook <keescook@chromium.org> wrote:
> On Mon, Apr 15, 2013 at 2:25 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>> On 04/15/2013 02:06 PM, Eric Northup wrote:
>>> On Sat, Apr 13, 2013 at 8:06 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>>>> On 04/13/2013 05:37 PM, Yinghai Lu wrote:
>>>>>
>>>>> so decompress code position is changed?
>>>>>
>>>>> You may push out bss and other data area of run-time kernel of limit
>>>>> that boot loader
>>>>> chose according to setup_header.init_size.
>>>>> aka that make those area overlap with ram hole or other area like
>>>>> boot command line or initrd....
>>>>>
>>>>
>>>> Is there a strong reason to randomize the physical address on 64 bits
>>>> (and if so, shouldn't we do it right?)
>>>
>>> The reason to randomize the physical address is because of the kernel
>>> direct mapping range -- a predictable-to-attackers physical address
>>> implies a predictable-to-attackers virtual address.
>>>
>>> It had seemed to me like changing the virtual base of the direct
>>> mapping would be much more involved than physically relocating the
>>> kernel, but better suggestions would be most welcome :-)
>>>
>>
>> You seem to be missing something here...
>>
>> There are *two* mappings in 64-bit mode.  Physically, if you're going to
>> randomize you might as well randomize over the entire range... except
>> not too far down (on either 32 or 64 bit mode)... in particular, you
>> don't want to drop below 16 MiB if you can avoid it.
>>
>> On 64 bits, there is no reason the virtual address has to be randomized
>> the same way.
>
> Aren't we bound by the negative 2GB addressing due to -mcmodel=kernel?
>
> -Kees
>
> --
> Kees Cook
> Chrome OS Security

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 21:41           ` Kees Cook
  2013-04-15 21:44             ` Eric Northup
@ 2013-04-15 21:46             ` H. Peter Anvin
  2013-04-15 21:59               ` Kees Cook
  2013-04-15 22:00               ` Yinghai Lu
  1 sibling, 2 replies; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-15 21:46 UTC (permalink / raw)
  To: Kees Cook
  Cc: Eric Northup, Yinghai Lu, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On 04/15/2013 02:41 PM, Kees Cook wrote:
>>
>> You seem to be missing something here...
>>
>> There are *two* mappings in 64-bit mode.  Physically, if you're going to
>> randomize you might as well randomize over the entire range... except
>> not too far down (on either 32 or 64 bit mode)... in particular, you
>> don't want to drop below 16 MiB if you can avoid it.
>>
>> On 64 bits, there is no reason the virtual address has to be randomized
>> the same way.
> 
> Aren't we bound by the negative 2GB addressing due to -mcmodel=kernel?
> 

Guys,

Please read what I wrote.

The 2 GB limit is for the *virtual* mapping.

The *physical* mapping, where it lands in RAM, is completely
independent, and if you're going to randomize the latter, there is no
reason it has to match the former.  Instead, randomize it freely.

That is different from the i386 kernel which runs at its
physical-mapping address.

Incidentally, for performance reasons please avoid locating the kernel
below CONFIG_PHYSICAL_ADDRESS if possible.

Also make sure your code works with more than 128 e820 entries.

	-hpa


-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 21:46             ` H. Peter Anvin
@ 2013-04-15 21:59               ` Kees Cook
  2013-04-16  2:31                 ` H. Peter Anvin
  2013-04-15 22:00               ` Yinghai Lu
  1 sibling, 1 reply; 40+ messages in thread
From: Kees Cook @ 2013-04-15 21:59 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Eric Northup, Yinghai Lu, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On Mon, Apr 15, 2013 at 2:46 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 04/15/2013 02:41 PM, Kees Cook wrote:
>>>
>>> You seem to be missing something here...
>>>
>>> There are *two* mappings in 64-bit mode.  Physically, if you're going to
>>> randomize you might as well randomize over the entire range... except
>>> not too far down (on either 32 or 64 bit mode)... in particular, you
>>> don't want to drop below 16 MiB if you can avoid it.
>>>
>>> On 64 bits, there is no reason the virtual address has to be randomized
>>> the same way.
>>
>> Aren't we bound by the negative 2GB addressing due to -mcmodel=kernel?
>>
>
> Guys,
>
> Please read what I wrote.
>
> The 2 GB limit is for the *virtual* mapping.
>
> The *physical* mapping, where it lands in RAM, is completely
> independent, and if you're going to randomize the latter, there is no
> reason it has to match the former.  Instead, randomize it freely.

Ah, gotcha. I don't see much benefit in doing this as it would make
the 32-bit and 64-bit logic pretty different without much real-world
gain, IMO.

> That is different from the i386 kernel which runs at its
> physical-mapping address.
>
> Incidentally, for performance reasons please avoid locating the kernel
> below CONFIG_PHYSICAL_ADDRESS if possible.

You mean CONFIG_PHYSICAL_START? This is already done in aslr.S via
LOAD_PHYSICAL_ADDR which is calculated from the
CONFIG_PHYSICAL_ALIGN-masked CONFIG_PHYSICAL_START.

> Also make sure your code works with more than 128 e820 entries.

There should be no problem here; we're using edi to count them.

-Kees

--
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 21:46             ` H. Peter Anvin
  2013-04-15 21:59               ` Kees Cook
@ 2013-04-15 22:00               ` Yinghai Lu
  2013-04-15 22:07                 ` Kees Cook
  2013-04-16  2:36                 ` H. Peter Anvin
  1 sibling, 2 replies; 40+ messages in thread
From: Yinghai Lu @ 2013-04-15 22:00 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Kees Cook, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On Mon, Apr 15, 2013 at 2:46 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 04/15/2013 02:41 PM, Kees Cook wrote:

> Please read what I wrote.
>
> The 2 GB limit is for the *virtual* mapping.
>
> The *physical* mapping, where it lands in RAM, is completely
> independent, and if you're going to randomize the latter, there is no
> reason it has to match the former.  Instead, randomize it freely.
>
> That is different from the i386 kernel which runs at its
> physical-mapping address.
>
> Incidentally, for performance reasons please avoid locating the kernel
> below CONFIG_PHYSICAL_ADDRESS if possible.
>
> Also make sure your code works with more than 128 e820 entries.

also do not overlap with boot_param, command_line, and initrd.

and need to double check setup_header.init_size to make sure bss and
etc will not
fall into memory hole or reserved area in e820.

also may need to setup page table for target position as bootloader may only
has ident mapping only for loaded bzImage 64 areas.

looks you are trying redo the work for bootloader to pick loaded phys addr.

Thanks

Yinghai

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 22:00               ` Yinghai Lu
@ 2013-04-15 22:07                 ` Kees Cook
  2013-04-15 22:38                   ` Yinghai Lu
  2013-04-16  2:36                 ` H. Peter Anvin
  1 sibling, 1 reply; 40+ messages in thread
From: Kees Cook @ 2013-04-15 22:07 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: H. Peter Anvin, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On Mon, Apr 15, 2013 at 3:00 PM, Yinghai Lu <yinghai@kernel.org> wrote:
> On Mon, Apr 15, 2013 at 2:46 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>> On 04/15/2013 02:41 PM, Kees Cook wrote:
>
>> Please read what I wrote.
>>
>> The 2 GB limit is for the *virtual* mapping.
>>
>> The *physical* mapping, where it lands in RAM, is completely
>> independent, and if you're going to randomize the latter, there is no
>> reason it has to match the former.  Instead, randomize it freely.
>>
>> That is different from the i386 kernel which runs at its
>> physical-mapping address.
>>
>> Incidentally, for performance reasons please avoid locating the kernel
>> below CONFIG_PHYSICAL_ADDRESS if possible.
>>
>> Also make sure your code works with more than 128 e820 entries.
>
> also do not overlap with boot_param, command_line, and initrd.
>
> and need to double check setup_header.init_size to make sure bss and
> etc will not
> fall into memory hole or reserved area in e820.
>
> also may need to setup page table for target position as bootloader may only
> has ident mapping only for loaded bzImage 64 areas.
>
> looks you are trying redo the work for bootloader to pick loaded phys addr.

aslr.S's select_aslr_address uses z_extract_offset as the upper bound.

-Kees

--
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 22:07                 ` Kees Cook
@ 2013-04-15 22:38                   ` Yinghai Lu
  2013-04-15 22:42                     ` Kees Cook
  2013-04-16  2:34                     ` H. Peter Anvin
  0 siblings, 2 replies; 40+ messages in thread
From: Yinghai Lu @ 2013-04-15 22:38 UTC (permalink / raw)
  To: Kees Cook
  Cc: H. Peter Anvin, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On Mon, Apr 15, 2013 at 3:07 PM, Kees Cook <keescook@chromium.org> wrote:
> On Mon, Apr 15, 2013 at 3:00 PM, Yinghai Lu <yinghai@kernel.org> wrote:
>> also do not overlap with boot_param, command_line, and initrd.
>>
>> and need to double check setup_header.init_size to make sure bss and
>> etc will not
>> fall into memory hole or reserved area in e820.
>>
>> also may need to setup page table for target position as bootloader may only
>> has ident mapping only for loaded bzImage 64 areas.
>>
>> looks you are trying redo the work for bootloader to pick loaded phys addr.
>
> aslr.S's select_aslr_address uses z_extract_offset as the upper bound.
>

so the decompressed image is not moved high?

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 22:38                   ` Yinghai Lu
@ 2013-04-15 22:42                     ` Kees Cook
  2013-04-15 22:57                       ` Yinghai Lu
  2013-04-16  2:34                     ` H. Peter Anvin
  1 sibling, 1 reply; 40+ messages in thread
From: Kees Cook @ 2013-04-15 22:42 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: H. Peter Anvin, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On Mon, Apr 15, 2013 at 3:38 PM, Yinghai Lu <yinghai@kernel.org> wrote:
> On Mon, Apr 15, 2013 at 3:07 PM, Kees Cook <keescook@chromium.org> wrote:
>> On Mon, Apr 15, 2013 at 3:00 PM, Yinghai Lu <yinghai@kernel.org> wrote:
>>> also do not overlap with boot_param, command_line, and initrd.
>>>
>>> and need to double check setup_header.init_size to make sure bss and
>>> etc will not
>>> fall into memory hole or reserved area in e820.
>>>
>>> also may need to setup page table for target position as bootloader may only
>>> has ident mapping only for loaded bzImage 64 areas.
>>>
>>> looks you are trying redo the work for bootloader to pick loaded phys addr.
>>
>> aslr.S's select_aslr_address uses z_extract_offset as the upper bound.
>
> so the decompressed image is not moved high?

No, I mean the size of the relocated image is using z_extract_offset
as the end size of the relocated memory. See select_aslr_address. It
takes the chosen aslr offset plus the location of z_extract_offset and
keeps reducing the offset until it's inside the physical end of
memory.

-Kees

--
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 22:42                     ` Kees Cook
@ 2013-04-15 22:57                       ` Yinghai Lu
  0 siblings, 0 replies; 40+ messages in thread
From: Yinghai Lu @ 2013-04-15 22:57 UTC (permalink / raw)
  To: Kees Cook
  Cc: H. Peter Anvin, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On Mon, Apr 15, 2013 at 3:42 PM, Kees Cook <keescook@chromium.org> wrote:
> On Mon, Apr 15, 2013 at 3:38 PM, Yinghai Lu <yinghai@kernel.org> wrote:
>
>> so the decompressed image is not moved high?
>
> No, I mean the size of the relocated image is using z_extract_offset
> as the end size of the relocated memory. See select_aslr_address. It
> takes the chosen aslr offset plus the location of z_extract_offset and
> keeps reducing the offset until it's inside the physical end of
> memory.

My point is:
If you move the decompressed high, for example, before aslr uncompressed
vmlinx is on [1024g+16M, 1024g+256M).
after aslr, it is on [1024g+16M + 32M, 1024g+256M + 32M).

You will need to make sure that 32M is still RAM in e820 memmap.
also those range should not be with boot_param, command line, and initrd.
as bootloader could put boot_param, commandline and initrd in that 32M range.

Yinghai

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 21:59               ` Kees Cook
@ 2013-04-16  2:31                 ` H. Peter Anvin
  2013-04-16  2:40                   ` H. Peter Anvin
  0 siblings, 1 reply; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-16  2:31 UTC (permalink / raw)
  To: Kees Cook
  Cc: Eric Northup, Yinghai Lu, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On 04/15/2013 02:59 PM, Kees Cook wrote:
>>
>> The *physical* mapping, where it lands in RAM, is completely
>> independent, and if you're going to randomize the latter, there is no
>> reason it has to match the former.  Instead, randomize it freely.
> 
> Ah, gotcha. I don't see much benefit in doing this as it would make
> the 32-bit and 64-bit logic pretty different without much real-world
> gain, IMO.
> 

You *have* to make them different anyway.  Otherwise you aren't really
doing anything useful on x86-64.

Seriously, do it right if anything.

I also am starting to think that this really would be done better being
integrated with the decompressor code, since that code already ends up
moving the code around... no reason to do this again.

>> That is different from the i386 kernel which runs at its
>> physical-mapping address.
>>
>> Incidentally, for performance reasons please avoid locating the kernel
>> below CONFIG_PHYSICAL_ADDRESS if possible.
> 
> You mean CONFIG_PHYSICAL_START? This is already done in aslr.S via
> LOAD_PHYSICAL_ADDR which is calculated from the
> CONFIG_PHYSICAL_ALIGN-masked CONFIG_PHYSICAL_START.
> 
>> Also make sure your code works with more than 128 e820 entries.
> 
> There should be no problem here; we're using edi to count them.

More than 128 entries are fed via a different protocol.

	-hpa

-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 22:38                   ` Yinghai Lu
  2013-04-15 22:42                     ` Kees Cook
@ 2013-04-16  2:34                     ` H. Peter Anvin
  1 sibling, 0 replies; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-16  2:34 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Kees Cook, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On 04/15/2013 03:38 PM, Yinghai Lu wrote:
> On Mon, Apr 15, 2013 at 3:07 PM, Kees Cook <keescook@chromium.org> wrote:
>> On Mon, Apr 15, 2013 at 3:00 PM, Yinghai Lu <yinghai@kernel.org> wrote:
>>> also do not overlap with boot_param, command_line, and initrd.
>>>
>>> and need to double check setup_header.init_size to make sure bss and
>>> etc will not
>>> fall into memory hole or reserved area in e820.
>>>
>>> also may need to setup page table for target position as bootloader may only
>>> has ident mapping only for loaded bzImage 64 areas.
>>>
>>> looks you are trying redo the work for bootloader to pick loaded phys addr.
>>
>> aslr.S's select_aslr_address uses z_extract_offset as the upper bound.

That seems really, really odd.

> so the decompressed image is not moved high?

This really seems wrong in so many ways.

If you relocate pre-decompression the amount of memory you need is given
by init_size:

#define ZO_INIT_SIZE    (ZO__end - ZO_startup_32 + ZO_z_extract_offset)
#define VO_INIT_SIZE    (VO__end - VO__text)
#if ZO_INIT_SIZE > VO_INIT_SIZE
#define INIT_SIZE ZO_INIT_SIZE
#else
#define INIT_SIZE VO_INIT_SIZE
#endif
init_size:              .long INIT_SIZE         # kernel initialization size

In real life, VO_INIT_SIZE dominates almost every time.

	-hpa

-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-15 22:00               ` Yinghai Lu
  2013-04-15 22:07                 ` Kees Cook
@ 2013-04-16  2:36                 ` H. Peter Anvin
  2013-04-16  2:56                   ` Yinghai Lu
  1 sibling, 1 reply; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-16  2:36 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Kees Cook, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On 04/15/2013 03:00 PM, Yinghai Lu wrote:
> 
> looks you are trying redo the work for bootloader to pick loaded phys addr.
> 

Well, that is exactly what they are doing.  On top of that they also
need to randomize the 64-bit virtual mapping.

I wonder if we need a bootloader bit to inhibit kaslr in addition to the
command line...

	-hpa


-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-16  2:31                 ` H. Peter Anvin
@ 2013-04-16  2:40                   ` H. Peter Anvin
  2013-04-16 16:08                     ` Kees Cook
  0 siblings, 1 reply; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-16  2:40 UTC (permalink / raw)
  To: Kees Cook
  Cc: Eric Northup, Yinghai Lu, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On 04/15/2013 07:31 PM, H. Peter Anvin wrote:
> 
> I also am starting to think that this really would be done better being
> integrated with the decompressor code, since that code already ends up
> moving the code around... no reason to do this again.
> 

Another good reason to do this in the decompressor wrapper: it can be
written in C that way.

	-hpa

-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-16  2:36                 ` H. Peter Anvin
@ 2013-04-16  2:56                   ` Yinghai Lu
  2013-04-16  3:02                     ` H. Peter Anvin
  0 siblings, 1 reply; 40+ messages in thread
From: Yinghai Lu @ 2013-04-16  2:56 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Kees Cook, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On Mon, Apr 15, 2013 at 7:36 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 04/15/2013 03:00 PM, Yinghai Lu wrote:
>>
>> looks you are trying redo the work for bootloader to pick loaded phys addr.
>>
>
> Well, that is exactly what they are doing.  On top of that they also
> need to randomize the 64-bit virtual mapping.
>
> I wonder if we need a bootloader bit to inhibit kaslr in addition to the
> command line...

so let the bootloader to parse kaslr and pick ramdom address,
and kernel arch/x86/boot/compressed/head_64.S to pick random virtual address?

Yinghai

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-16  2:56                   ` Yinghai Lu
@ 2013-04-16  3:02                     ` H. Peter Anvin
  2013-04-16 13:08                       ` Ingo Molnar
  0 siblings, 1 reply; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-16  3:02 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Kees Cook, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

No.  Fixing one bootloader is almost impossible.  Fixing them all is a Sisiphyean task.

Yinghai Lu <yinghai@kernel.org> wrote:

>On Mon, Apr 15, 2013 at 7:36 PM, H. Peter Anvin <hpa@zytor.com> wrote:
>> On 04/15/2013 03:00 PM, Yinghai Lu wrote:
>>>
>>> looks you are trying redo the work for bootloader to pick loaded
>phys addr.
>>>
>>
>> Well, that is exactly what they are doing.  On top of that they also
>> need to randomize the 64-bit virtual mapping.
>>
>> I wonder if we need a bootloader bit to inhibit kaslr in addition to
>the
>> command line...
>
>so let the bootloader to parse kaslr and pick ramdom address,
>and kernel arch/x86/boot/compressed/head_64.S to pick random virtual
>address?
>
>Yinghai

-- 
Sent from my mobile phone. Please excuse brevity and lack of formatting.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-16  3:02                     ` H. Peter Anvin
@ 2013-04-16 13:08                       ` Ingo Molnar
  2013-04-16 13:27                         ` H. Peter Anvin
  0 siblings, 1 reply; 40+ messages in thread
From: Ingo Molnar @ 2013-04-16 13:08 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Yinghai Lu, Kees Cook, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry


* H. Peter Anvin <hpa@zytor.com> wrote:

> No.  Fixing one bootloader is almost impossible.  Fixing them all is a 
> Sisiphyean task.

It's a self inflicted wound really: if only we had a reference bootloader in the 
kernel tree, which we could fix. The effort that went into fixing various 
bootloader interactions would have been enough to write two new bootloaders from 
scratch.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-16 13:08                       ` Ingo Molnar
@ 2013-04-16 13:27                         ` H. Peter Anvin
  0 siblings, 0 replies; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-16 13:27 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Yinghai Lu, Kees Cook, Eric Northup, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

Well... G**** is it's own problem (doing actively broken thinks for political reasons), but the real issue mostly is that there are a lot of them simply because there are a lot of ways one may want to load the kernel.

This is why things like decompression and the BIOS and EFI stubs are part of the kernel and not the bootloader.  In this case moving the randomization into the decompressor send like the right thing to do - C code, and no additional copy.

Ingo Molnar <mingo@kernel.org> wrote:

>
>* H. Peter Anvin <hpa@zytor.com> wrote:
>
>> No.  Fixing one bootloader is almost impossible.  Fixing them all is
>a 
>> Sisiphyean task.
>
>It's a self inflicted wound really: if only we had a reference
>bootloader in the 
>kernel tree, which we could fix. The effort that went into fixing
>various 
>bootloader interactions would have been enough to write two new
>bootloaders from 
>scratch.
>
>Thanks,
>
>	Ingo

-- 
Sent from my mobile phone. Please excuse brevity and lack of formatting.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 6/6] x86: kaslr: relocate base offset at boot
  2013-04-16  2:40                   ` H. Peter Anvin
@ 2013-04-16 16:08                     ` Kees Cook
  0 siblings, 0 replies; 40+ messages in thread
From: Kees Cook @ 2013-04-16 16:08 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Eric Northup, Yinghai Lu, Linux Kernel Mailing List,
	kernel-hardening, Thomas Gleixner, Ingo Molnar,
	the arch/x86 maintainers, Jarkko Sakkinen, Matthew Garrett,
	Matt Fleming, Dan Rosenberg, Julien Tinnes, Will Drewry

On Mon, Apr 15, 2013 at 7:40 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 04/15/2013 07:31 PM, H. Peter Anvin wrote:
>>
>> I also am starting to think that this really would be done better being
>> integrated with the decompressor code, since that code already ends up
>> moving the code around... no reason to do this again.
>>
>
> Another good reason to do this in the decompressor wrapper: it can be
> written in C that way.

This would make the code much more readable, for sure. And given that
the 64-bit relocation work happens after decompression, this seems
only right. Good idea! I'll start working on it.

-Kees

--
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 0/6] kernel ASLR
  2013-04-12 20:13 [PATCH v2 0/6] kernel ASLR Kees Cook
                   ` (5 preceding siblings ...)
  2013-04-12 20:13 ` [PATCH 6/6] x86: kaslr: relocate base offset at boot Kees Cook
@ 2013-04-16 18:08 ` Kees Cook
  2013-04-16 18:15   ` H. Peter Anvin
  6 siblings, 1 reply; 40+ messages in thread
From: Kees Cook @ 2013-04-16 18:08 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: LKML, kernel-hardening, Thomas Gleixner, Ingo Molnar, x86,
	Jarkko Sakkinen, Matthew Garrett, Matt Fleming, Eric Northup,
	Dan Rosenberg, Julien Tinnes, Will Drewry, Kees Cook

On Fri, Apr 12, 2013 at 1:13 PM, Kees Cook <keescook@chromium.org> wrote:
> This splits up the relocs tool changes into the separate logical pieces,
> which should be easier to review. I could use some suggestions on a
> better way to build it in the 4th patch. What I have now seems ugly,
> but Kbuild would not give me its secrets.

How does the relocation portion of this series look? It's separate
from the ASLR logic, but required for it. Do those changes look good
for the tip/kaslr tree?

Thanks,

-Kees

--
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH v2 0/6] kernel ASLR
  2013-04-16 18:08 ` [PATCH v2 0/6] kernel ASLR Kees Cook
@ 2013-04-16 18:15   ` H. Peter Anvin
  0 siblings, 0 replies; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-16 18:15 UTC (permalink / raw)
  To: Kees Cook
  Cc: LKML, kernel-hardening, Thomas Gleixner, Ingo Molnar, x86,
	Jarkko Sakkinen, Matthew Garrett, Matt Fleming, Eric Northup,
	Dan Rosenberg, Julien Tinnes, Will Drewry

On 04/16/2013 11:08 AM, Kees Cook wrote:
> On Fri, Apr 12, 2013 at 1:13 PM, Kees Cook <keescook@chromium.org> wrote:
>> This splits up the relocs tool changes into the separate logical pieces,
>> which should be easier to review. I could use some suggestions on a
>> better way to build it in the 4th patch. What I have now seems ugly,
>> but Kbuild would not give me its secrets.
> 
> How does the relocation portion of this series look? It's separate
> from the ASLR logic, but required for it. Do those changes look good
> for the tip/kaslr tree?
> 

They are probably okay... I should take a closer look.

I might prioritize it down since (a) I am sick, and (b) it is the week
before the merge window.

	-hpa

-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 4/6] x86: relocs: build separate 32/64-bit tools
  2013-04-12 20:13 ` [PATCH 4/6] x86: relocs: build separate 32/64-bit tools Kees Cook
@ 2013-04-16 22:21   ` H. Peter Anvin
  2013-04-16 22:38     ` Kees Cook
  2013-04-16 23:20   ` [tip:x86/kaslr] x86, relocs: Build " tip-bot for Kees Cook
  2013-04-16 23:22   ` [tip:x86/kaslr] x86, relocs: Refactor the relocs tool to merge 32- and 64-bit ELF tip-bot for H. Peter Anvin
  2 siblings, 1 reply; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-16 22:21 UTC (permalink / raw)
  To: Kees Cook
  Cc: linux-kernel, kernel-hardening, Thomas Gleixner, Ingo Molnar,
	x86, Jarkko Sakkinen, Matthew Garrett, Matt Fleming,
	Eric Northup, Dan Rosenberg, Julien Tinnes, Will Drewry

On 04/12/2013 01:13 PM, Kees Cook wrote:
> Since the ELF structures and access macros change size based on 32 vs
> 64 bits, build a separate 32-bit relocs tool (for handling realmode
> and 32-bit relocations), and a 64-bit relocs tool (for handling 64-bit
> kernel relocations).
> 
> Signed-off-by: Kees Cook <keescook@chromium.org>
> --
> This is ugly with the "cp". Is there some other cleaner way to trigger
> two builds with different defines from the same source file?

There definitely is.

Have simple wrapper files which do:

/* relocs_32.c */
#define ELF_BITS 32
#include "relocs.c"

/* relocs_64.c */
#define ELF_BITS 64
#include "relocs.c"

	-hpa



^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 4/6] x86: relocs: build separate 32/64-bit tools
  2013-04-16 22:21   ` H. Peter Anvin
@ 2013-04-16 22:38     ` Kees Cook
  2013-04-16 22:39       ` H. Peter Anvin
  0 siblings, 1 reply; 40+ messages in thread
From: Kees Cook @ 2013-04-16 22:38 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: LKML, kernel-hardening, Thomas Gleixner, Ingo Molnar, x86,
	Jarkko Sakkinen, Matthew Garrett, Matt Fleming, Eric Northup,
	Dan Rosenberg, Julien Tinnes, Will Drewry

On Tue, Apr 16, 2013 at 3:21 PM, H. Peter Anvin <hpa@zytor.com> wrote:
> On 04/12/2013 01:13 PM, Kees Cook wrote:
>> Since the ELF structures and access macros change size based on 32 vs
>> 64 bits, build a separate 32-bit relocs tool (for handling realmode
>> and 32-bit relocations), and a 64-bit relocs tool (for handling 64-bit
>> kernel relocations).
>>
>> Signed-off-by: Kees Cook <keescook@chromium.org>
>> --
>> This is ugly with the "cp". Is there some other cleaner way to trigger
>> two builds with different defines from the same source file?
>
> There definitely is.
>
> Have simple wrapper files which do:
>
> /* relocs_32.c */
> #define ELF_BITS 32
> #include "relocs.c"
>
> /* relocs_64.c */
> #define ELF_BITS 64
> #include "relocs.c"

That's what I did in my first pass, but it seemed even worse to me. I
will go back to this.

Thanks!

-Kees

--
Kees Cook
Chrome OS Security

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [PATCH 4/6] x86: relocs: build separate 32/64-bit tools
  2013-04-16 22:38     ` Kees Cook
@ 2013-04-16 22:39       ` H. Peter Anvin
  0 siblings, 0 replies; 40+ messages in thread
From: H. Peter Anvin @ 2013-04-16 22:39 UTC (permalink / raw)
  To: Kees Cook
  Cc: LKML, kernel-hardening, Thomas Gleixner, Ingo Molnar, x86,
	Jarkko Sakkinen, Matthew Garrett, Matt Fleming, Eric Northup,
	Dan Rosenberg, Julien Tinnes, Will Drewry

On 04/16/2013 03:38 PM, Kees Cook wrote:
>>
>> Have simple wrapper files which do:
>>
>> /* relocs_32.c */
>> #define ELF_BITS 32
>> #include "relocs.c"
>>
>> /* relocs_64.c */
>> #define ELF_BITS 64
>> #include "relocs.c"
> 
> That's what I did in my first pass, but it seemed even worse to me. I
> will go back to this.
> 

Actually, I'm trying to see if I can refactor this into one binary.
Hang on a few.

	-hpa



^ permalink raw reply	[flat|nested] 40+ messages in thread

* [tip:x86/kaslr] x86, relocs: Generalize ELF structure names
  2013-04-12 20:13 ` [PATCH 1/6] x86: relocs: generalize Elf structure names Kees Cook
@ 2013-04-16 23:17   ` tip-bot for Kees Cook
  0 siblings, 0 replies; 40+ messages in thread
From: tip-bot for Kees Cook @ 2013-04-16 23:17 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, keescook, tglx, hpa

Commit-ID:  bf11655cf2ecdcfaacbc8324da4a3edfe276ba9d
Gitweb:     http://git.kernel.org/tip/bf11655cf2ecdcfaacbc8324da4a3edfe276ba9d
Author:     Kees Cook <keescook@chromium.org>
AuthorDate: Fri, 12 Apr 2013 13:13:42 -0700
Committer:  H. Peter Anvin <hpa@linux.intel.com>
CommitDate: Tue, 16 Apr 2013 15:19:06 -0700

x86, relocs: Generalize ELF structure names

In preparation for making the reloc tool operate on 64-bit relocations,
generalize the structure names for easy recompilation via #defines.

Based on work by Neill Clift and Michael Davidson.

Signed-off-by: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/1365797627-20874-2-git-send-email-keescook@chromium.org
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
---
 arch/x86/tools/relocs.c | 170 ++++++++++++++++++++++++++++--------------------
 1 file changed, 99 insertions(+), 71 deletions(-)

diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 79d67bd..fd28ef7 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -12,20 +12,42 @@
 #include <regex.h>
 #include <tools/le_byteshift.h>
 
+#define ElfW(type)		_ElfW(ELF_BITS, type)
+#define _ElfW(bits, type)	__ElfW(bits, type)
+#define __ElfW(bits, type)	Elf##bits##_##type
+
+#define ELF_BITS		32
+#define ELF_MACHINE		EM_386
+#define ELF_MACHINE_NAME	"i386"
+#define SHT_REL_TYPE		SHT_REL
+
+#define ELF_CLASS		ELFCLASS32
+#define ELF_R_SYM(val)		ELF32_R_SYM(val)
+#define ELF_R_TYPE(val)		ELF32_R_TYPE(val)
+#define ELF_ST_TYPE(o)		ELF32_ST_TYPE(o)
+#define ELF_ST_BIND(o)		ELF32_ST_BIND(o)
+#define ELF_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY(o)
+
+#define Elf_Rel			ElfW(Rel)
+#define Elf_Ehdr		ElfW(Ehdr)
+#define Elf_Phdr		ElfW(Phdr)
+#define Elf_Shdr		ElfW(Shdr)
+#define Elf_Sym			ElfW(Sym)
+
 static void die(char *fmt, ...);
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-static Elf32_Ehdr ehdr;
+static Elf_Ehdr ehdr;
 static unsigned long reloc_count, reloc_idx;
 static unsigned long *relocs;
 static unsigned long reloc16_count, reloc16_idx;
 static unsigned long *relocs16;
 
 struct section {
-	Elf32_Shdr     shdr;
+	Elf_Shdr       shdr;
 	struct section *link;
-	Elf32_Sym      *symtab;
-	Elf32_Rel      *reltab;
+	Elf_Sym        *symtab;
+	Elf_Rel        *reltab;
 	char           *strtab;
 };
 static struct section *secs;
@@ -240,7 +262,7 @@ static const char *sec_name(unsigned shndx)
 	return name;
 }
 
-static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
+static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
 {
 	const char *name;
 	name = "<noname>";
@@ -274,6 +296,12 @@ static uint32_t elf32_to_cpu(uint32_t val)
 	return le32_to_cpu(val);
 }
 
+#define elf_half_to_cpu(x)	elf16_to_cpu(x)
+#define elf_word_to_cpu(x)	elf32_to_cpu(x)
+#define elf_addr_to_cpu(x)	elf32_to_cpu(x)
+#define elf_off_to_cpu(x)	elf32_to_cpu(x)
+#define elf_xword_to_cpu(x)	elf32_to_cpu(x)
+
 static void read_ehdr(FILE *fp)
 {
 	if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
@@ -283,8 +311,8 @@ static void read_ehdr(FILE *fp)
 	if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
 		die("No ELF magic\n");
 	}
-	if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
-		die("Not a 32 bit executable\n");
+	if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) {
+		die("Not a %d bit executable\n", ELF_BITS);
 	}
 	if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
 		die("Not a LSB ELF executable\n");
@@ -293,36 +321,36 @@ static void read_ehdr(FILE *fp)
 		die("Unknown ELF version\n");
 	}
 	/* Convert the fields to native endian */
-	ehdr.e_type      = elf16_to_cpu(ehdr.e_type);
-	ehdr.e_machine   = elf16_to_cpu(ehdr.e_machine);
-	ehdr.e_version   = elf32_to_cpu(ehdr.e_version);
-	ehdr.e_entry     = elf32_to_cpu(ehdr.e_entry);
-	ehdr.e_phoff     = elf32_to_cpu(ehdr.e_phoff);
-	ehdr.e_shoff     = elf32_to_cpu(ehdr.e_shoff);
-	ehdr.e_flags     = elf32_to_cpu(ehdr.e_flags);
-	ehdr.e_ehsize    = elf16_to_cpu(ehdr.e_ehsize);
-	ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
-	ehdr.e_phnum     = elf16_to_cpu(ehdr.e_phnum);
-	ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
-	ehdr.e_shnum     = elf16_to_cpu(ehdr.e_shnum);
-	ehdr.e_shstrndx  = elf16_to_cpu(ehdr.e_shstrndx);
+	ehdr.e_type      = elf_half_to_cpu(ehdr.e_type);
+	ehdr.e_machine   = elf_half_to_cpu(ehdr.e_machine);
+	ehdr.e_version   = elf_word_to_cpu(ehdr.e_version);
+	ehdr.e_entry     = elf_addr_to_cpu(ehdr.e_entry);
+	ehdr.e_phoff     = elf_off_to_cpu(ehdr.e_phoff);
+	ehdr.e_shoff     = elf_off_to_cpu(ehdr.e_shoff);
+	ehdr.e_flags     = elf_word_to_cpu(ehdr.e_flags);
+	ehdr.e_ehsize    = elf_half_to_cpu(ehdr.e_ehsize);
+	ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize);
+	ehdr.e_phnum     = elf_half_to_cpu(ehdr.e_phnum);
+	ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize);
+	ehdr.e_shnum     = elf_half_to_cpu(ehdr.e_shnum);
+	ehdr.e_shstrndx  = elf_half_to_cpu(ehdr.e_shstrndx);
 
 	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
 		die("Unsupported ELF header type\n");
 	}
-	if (ehdr.e_machine != EM_386) {
-		die("Not for x86\n");
+	if (ehdr.e_machine != ELF_MACHINE) {
+		die("Not for %s\n", ELF_MACHINE_NAME);
 	}
 	if (ehdr.e_version != EV_CURRENT) {
 		die("Unknown ELF version\n");
 	}
-	if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
+	if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) {
 		die("Bad Elf header size\n");
 	}
-	if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
+	if (ehdr.e_phentsize != sizeof(Elf_Phdr)) {
 		die("Bad program header entry\n");
 	}
-	if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
+	if (ehdr.e_shentsize != sizeof(Elf_Shdr)) {
 		die("Bad section header entry\n");
 	}
 	if (ehdr.e_shstrndx >= ehdr.e_shnum) {
@@ -333,7 +361,7 @@ static void read_ehdr(FILE *fp)
 static void read_shdrs(FILE *fp)
 {
 	int i;
-	Elf32_Shdr shdr;
+	Elf_Shdr shdr;
 
 	secs = calloc(ehdr.e_shnum, sizeof(struct section));
 	if (!secs) {
@@ -349,16 +377,16 @@ static void read_shdrs(FILE *fp)
 		if (fread(&shdr, sizeof shdr, 1, fp) != 1)
 			die("Cannot read ELF section headers %d/%d: %s\n",
 			    i, ehdr.e_shnum, strerror(errno));
-		sec->shdr.sh_name      = elf32_to_cpu(shdr.sh_name);
-		sec->shdr.sh_type      = elf32_to_cpu(shdr.sh_type);
-		sec->shdr.sh_flags     = elf32_to_cpu(shdr.sh_flags);
-		sec->shdr.sh_addr      = elf32_to_cpu(shdr.sh_addr);
-		sec->shdr.sh_offset    = elf32_to_cpu(shdr.sh_offset);
-		sec->shdr.sh_size      = elf32_to_cpu(shdr.sh_size);
-		sec->shdr.sh_link      = elf32_to_cpu(shdr.sh_link);
-		sec->shdr.sh_info      = elf32_to_cpu(shdr.sh_info);
-		sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
-		sec->shdr.sh_entsize   = elf32_to_cpu(shdr.sh_entsize);
+		sec->shdr.sh_name      = elf_word_to_cpu(shdr.sh_name);
+		sec->shdr.sh_type      = elf_word_to_cpu(shdr.sh_type);
+		sec->shdr.sh_flags     = elf_xword_to_cpu(shdr.sh_flags);
+		sec->shdr.sh_addr      = elf_addr_to_cpu(shdr.sh_addr);
+		sec->shdr.sh_offset    = elf_off_to_cpu(shdr.sh_offset);
+		sec->shdr.sh_size      = elf_xword_to_cpu(shdr.sh_size);
+		sec->shdr.sh_link      = elf_word_to_cpu(shdr.sh_link);
+		sec->shdr.sh_info      = elf_word_to_cpu(shdr.sh_info);
+		sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign);
+		sec->shdr.sh_entsize   = elf_xword_to_cpu(shdr.sh_entsize);
 		if (sec->shdr.sh_link < ehdr.e_shnum)
 			sec->link = &secs[sec->shdr.sh_link];
 	}
@@ -412,12 +440,12 @@ static void read_symtabs(FILE *fp)
 			die("Cannot read symbol table: %s\n",
 				strerror(errno));
 		}
-		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
-			Elf32_Sym *sym = &sec->symtab[j];
-			sym->st_name  = elf32_to_cpu(sym->st_name);
-			sym->st_value = elf32_to_cpu(sym->st_value);
-			sym->st_size  = elf32_to_cpu(sym->st_size);
-			sym->st_shndx = elf16_to_cpu(sym->st_shndx);
+		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
+			Elf_Sym *sym = &sec->symtab[j];
+			sym->st_name  = elf_word_to_cpu(sym->st_name);
+			sym->st_value = elf_addr_to_cpu(sym->st_value);
+			sym->st_size  = elf_xword_to_cpu(sym->st_size);
+			sym->st_shndx = elf_half_to_cpu(sym->st_shndx);
 		}
 	}
 }
@@ -428,7 +456,7 @@ static void read_relocs(FILE *fp)
 	int i,j;
 	for (i = 0; i < ehdr.e_shnum; i++) {
 		struct section *sec = &secs[i];
-		if (sec->shdr.sh_type != SHT_REL) {
+		if (sec->shdr.sh_type != SHT_REL_TYPE) {
 			continue;
 		}
 		sec->reltab = malloc(sec->shdr.sh_size);
@@ -445,10 +473,10 @@ static void read_relocs(FILE *fp)
 			die("Cannot read symbol table: %s\n",
 				strerror(errno));
 		}
-		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
-			Elf32_Rel *rel = &sec->reltab[j];
-			rel->r_offset = elf32_to_cpu(rel->r_offset);
-			rel->r_info   = elf32_to_cpu(rel->r_info);
+		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
+			Elf_Rel *rel = &sec->reltab[j];
+			rel->r_offset = elf_addr_to_cpu(rel->r_offset);
+			rel->r_info   = elf_xword_to_cpu(rel->r_info);
 		}
 	}
 }
@@ -468,8 +496,8 @@ static void print_absolute_symbols(void)
 			continue;
 		}
 		sym_strtab = sec->link->strtab;
-		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
-			Elf32_Sym *sym;
+		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
+			Elf_Sym *sym;
 			const char *name;
 			sym = &sec->symtab[j];
 			name = sym_name(sym_strtab, sym);
@@ -478,9 +506,9 @@ static void print_absolute_symbols(void)
 			}
 			printf("%5d %08x %5d %10s %10s %12s %s\n",
 				j, sym->st_value, sym->st_size,
-				sym_type(ELF32_ST_TYPE(sym->st_info)),
-				sym_bind(ELF32_ST_BIND(sym->st_info)),
-				sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
+				sym_type(ELF_ST_TYPE(sym->st_info)),
+				sym_bind(ELF_ST_BIND(sym->st_info)),
+				sym_visibility(ELF_ST_VISIBILITY(sym->st_other)),
 				name);
 		}
 	}
@@ -495,9 +523,9 @@ static void print_absolute_relocs(void)
 		struct section *sec = &secs[i];
 		struct section *sec_applies, *sec_symtab;
 		char *sym_strtab;
-		Elf32_Sym *sh_symtab;
+		Elf_Sym *sh_symtab;
 		int j;
-		if (sec->shdr.sh_type != SHT_REL) {
+		if (sec->shdr.sh_type != SHT_REL_TYPE) {
 			continue;
 		}
 		sec_symtab  = sec->link;
@@ -507,12 +535,12 @@ static void print_absolute_relocs(void)
 		}
 		sh_symtab  = sec_symtab->symtab;
 		sym_strtab = sec_symtab->link->strtab;
-		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
-			Elf32_Rel *rel;
-			Elf32_Sym *sym;
+		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
+			Elf_Rel *rel;
+			Elf_Sym *sym;
 			const char *name;
 			rel = &sec->reltab[j];
-			sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+			sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
 			name = sym_name(sym_strtab, sym);
 			if (sym->st_shndx != SHN_ABS) {
 				continue;
@@ -545,7 +573,7 @@ static void print_absolute_relocs(void)
 			printf("%08x %08x %10s %08x  %s\n",
 				rel->r_offset,
 				rel->r_info,
-				rel_type(ELF32_R_TYPE(rel->r_info)),
+				rel_type(ELF_R_TYPE(rel->r_info)),
 				sym->st_value,
 				name);
 		}
@@ -555,19 +583,19 @@ static void print_absolute_relocs(void)
 		printf("\n");
 }
 
-static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
+static void walk_relocs(void (*visit)(Elf_Rel *rel, Elf_Sym *sym),
 			int use_real_mode)
 {
 	int i;
 	/* Walk through the relocations */
 	for (i = 0; i < ehdr.e_shnum; i++) {
 		char *sym_strtab;
-		Elf32_Sym *sh_symtab;
+		Elf_Sym *sh_symtab;
 		struct section *sec_applies, *sec_symtab;
 		int j;
 		struct section *sec = &secs[i];
 
-		if (sec->shdr.sh_type != SHT_REL) {
+		if (sec->shdr.sh_type != SHT_REL_TYPE) {
 			continue;
 		}
 		sec_symtab  = sec->link;
@@ -577,16 +605,16 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
 		}
 		sh_symtab = sec_symtab->symtab;
 		sym_strtab = sec_symtab->link->strtab;
-		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
-			Elf32_Rel *rel;
-			Elf32_Sym *sym;
+		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
+			Elf_Rel *rel;
+			Elf_Sym *sym;
 			unsigned r_type;
 			const char *symname;
 			int shn_abs;
 
 			rel = &sec->reltab[j];
-			sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
-			r_type = ELF32_R_TYPE(rel->r_info);
+			sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
+			r_type = ELF_R_TYPE(rel->r_info);
 
 			shn_abs = sym->st_shndx == SHN_ABS;
 
@@ -647,18 +675,18 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
 	}
 }
 
-static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+static void count_reloc(Elf_Rel *rel, Elf_Sym *sym)
 {
-	if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+	if (ELF_R_TYPE(rel->r_info) == R_386_16)
 		reloc16_count++;
 	else
 		reloc_count++;
 }
 
-static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+static void collect_reloc(Elf_Rel *rel, Elf_Sym *sym)
 {
 	/* Remember the address that needs to be adjusted. */
-	if (ELF32_R_TYPE(rel->r_info) == R_386_16)
+	if (ELF_R_TYPE(rel->r_info) == R_386_16)
 		relocs16[reloc16_idx++] = rel->r_offset;
 	else
 		relocs[reloc_idx++] = rel->r_offset;

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [tip:x86/kaslr] x86, relocs: Consolidate processing logic
  2013-04-12 20:13 ` [PATCH 2/6] x86: relocs: consolidate processing logic Kees Cook
@ 2013-04-16 23:18   ` tip-bot for Kees Cook
  0 siblings, 0 replies; 40+ messages in thread
From: tip-bot for Kees Cook @ 2013-04-16 23:18 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, keescook, tglx, hpa

Commit-ID:  5d442e63d6a1b5736fd48a907bd7d2d87e411816
Gitweb:     http://git.kernel.org/tip/5d442e63d6a1b5736fd48a907bd7d2d87e411816
Author:     Kees Cook <keescook@chromium.org>
AuthorDate: Fri, 12 Apr 2013 13:13:43 -0700
Committer:  H. Peter Anvin <hpa@linux.intel.com>
CommitDate: Tue, 16 Apr 2013 15:19:13 -0700

x86, relocs: Consolidate processing logic

Instead of counting and then processing relocations, do it in a single
pass. This splits the processing logic into separate functions for
realmode and 32-bit (and paves the way for 64-bit). Also extracts helper
functions when emitting relocations.

Based on work by Neill Clift and Michael Davidson.

Signed-off-by: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/1365797627-20874-3-git-send-email-keescook@chromium.org
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
---
 arch/x86/tools/relocs.c | 304 +++++++++++++++++++++++++++---------------------
 1 file changed, 170 insertions(+), 134 deletions(-)

diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index fd28ef7..bdc5930 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -2,6 +2,7 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <inttypes.h>
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
@@ -38,10 +39,15 @@ static void die(char *fmt, ...);
 
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 static Elf_Ehdr ehdr;
-static unsigned long reloc_count, reloc_idx;
-static unsigned long *relocs;
-static unsigned long reloc16_count, reloc16_idx;
-static unsigned long *relocs16;
+
+struct relocs {
+	uint32_t	*offset;
+	unsigned long	count;
+	unsigned long	size;
+};
+
+static struct relocs relocs16;
+static struct relocs relocs32;
 
 struct section {
 	Elf_Shdr       shdr;
@@ -583,8 +589,23 @@ static void print_absolute_relocs(void)
 		printf("\n");
 }
 
-static void walk_relocs(void (*visit)(Elf_Rel *rel, Elf_Sym *sym),
-			int use_real_mode)
+static void add_reloc(struct relocs *r, uint32_t offset)
+{
+	if (r->count == r->size) {
+		unsigned long newsize = r->size + 50000;
+		void *mem = realloc(r->offset, newsize * sizeof(r->offset[0]));
+
+		if (!mem)
+			die("realloc of %ld entries for relocs failed\n",
+                                newsize);
+		r->offset = mem;
+		r->size = newsize;
+	}
+	r->offset[r->count++] = offset;
+}
+
+static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
+			Elf_Sym *sym, const char *symname))
 {
 	int i;
 	/* Walk through the relocations */
@@ -606,100 +627,142 @@ static void walk_relocs(void (*visit)(Elf_Rel *rel, Elf_Sym *sym),
 		sh_symtab = sec_symtab->symtab;
 		sym_strtab = sec_symtab->link->strtab;
 		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
-			Elf_Rel *rel;
-			Elf_Sym *sym;
-			unsigned r_type;
-			const char *symname;
-			int shn_abs;
+			Elf_Rel *rel = &sec->reltab[j];
+			Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
+			const char *symname = sym_name(sym_strtab, sym);
 
-			rel = &sec->reltab[j];
-			sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
-			r_type = ELF_R_TYPE(rel->r_info);
-
-			shn_abs = sym->st_shndx == SHN_ABS;
-
-			switch (r_type) {
-			case R_386_NONE:
-			case R_386_PC32:
-			case R_386_PC16:
-			case R_386_PC8:
-				/*
-				 * NONE can be ignored and and PC relative
-				 * relocations don't need to be adjusted.
-				 */
+			process(sec, rel, sym, symname);
+		}
+	}
+}
+
+static int do_reloc(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+		    const char *symname)
+{
+	unsigned r_type = ELF32_R_TYPE(rel->r_info);
+	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
+
+	switch (r_type) {
+	case R_386_NONE:
+	case R_386_PC32:
+	case R_386_PC16:
+	case R_386_PC8:
+		/*
+		 * NONE can be ignored and PC relative relocations don't
+		 * need to be adjusted.
+		 */
+		break;
+
+	case R_386_32:
+		if (shn_abs) {
+			/*
+			 * Whitelisted absolute symbols do not require
+			 * relocation.
+			 */
+			if (is_reloc(S_ABS, symname))
 				break;
 
-			case R_386_16:
-				symname = sym_name(sym_strtab, sym);
-				if (!use_real_mode)
-					goto bad;
-				if (shn_abs) {
-					if (is_reloc(S_ABS, symname))
-						break;
-					else if (!is_reloc(S_SEG, symname))
-						goto bad;
-				} else {
-					if (is_reloc(S_LIN, symname))
-						goto bad;
-					else
-						break;
-				}
-				visit(rel, sym);
+			die("Invalid absolute %s relocation: %s\n",
+			    rel_type(r_type), symname);
+			break;
+		}
+
+		add_reloc(&relocs32, rel->r_offset);
+		break;
+
+	default:
+		die("Unsupported relocation type: %s (%d)\n",
+		    rel_type(r_type), r_type);
+		break;
+	}
+
+	return 0;
+}
+
+static int do_reloc_real(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+			 const char *symname)
+{
+	unsigned r_type = ELF32_R_TYPE(rel->r_info);
+	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
+
+	switch (r_type) {
+	case R_386_NONE:
+	case R_386_PC32:
+	case R_386_PC16:
+	case R_386_PC8:
+		/*
+		 * NONE can be ignored and PC relative relocations don't
+		 * need to be adjusted.
+		 */
+		break;
+
+	case R_386_16:
+		if (shn_abs) {
+			/*
+			 * Whitelisted absolute symbols do not require
+			 * relocation.
+			 */
+			if (is_reloc(S_ABS, symname))
 				break;
 
-			case R_386_32:
-				symname = sym_name(sym_strtab, sym);
-				if (shn_abs) {
-					if (is_reloc(S_ABS, symname))
-						break;
-					else if (!is_reloc(S_REL, symname))
-						goto bad;
-				} else {
-					if (use_real_mode &&
-					    !is_reloc(S_LIN, symname))
-						break;
-				}
-				visit(rel, sym);
+			if (is_reloc(S_SEG, symname)) {
+				add_reloc(&relocs16, rel->r_offset);
+				break;
+			}
+		} else {
+			if (!is_reloc(S_LIN, symname))
 				break;
-			default:
-				die("Unsupported relocation type: %s (%d)\n",
-				    rel_type(r_type), r_type);
+		}
+		die("Invalid %s %s relocation: %s\n",
+		    shn_abs ? "absolute" : "relative",
+		    rel_type(r_type), symname);
+		break;
+
+	case R_386_32:
+		if (shn_abs) {
+			/*
+			 * Whitelisted absolute symbols do not require
+			 * relocation.
+			 */
+			if (is_reloc(S_ABS, symname))
+				break;
+
+			if (is_reloc(S_REL, symname)) {
+				add_reloc(&relocs32, rel->r_offset);
 				break;
-			bad:
-				symname = sym_name(sym_strtab, sym);
-				die("Invalid %s %s relocation: %s\n",
-				    shn_abs ? "absolute" : "relative",
-				    rel_type(r_type), symname);
 			}
+		} else {
+			if (is_reloc(S_LIN, symname))
+				add_reloc(&relocs32, rel->r_offset);
+			break;
 		}
-	}
-}
+		die("Invalid %s %s relocation: %s\n",
+		    shn_abs ? "absolute" : "relative",
+		    rel_type(r_type), symname);
+		break;
 
-static void count_reloc(Elf_Rel *rel, Elf_Sym *sym)
-{
-	if (ELF_R_TYPE(rel->r_info) == R_386_16)
-		reloc16_count++;
-	else
-		reloc_count++;
-}
+	default:
+		die("Unsupported relocation type: %s (%d)\n",
+		    rel_type(r_type), r_type);
+		break;
+	}
 
-static void collect_reloc(Elf_Rel *rel, Elf_Sym *sym)
-{
-	/* Remember the address that needs to be adjusted. */
-	if (ELF_R_TYPE(rel->r_info) == R_386_16)
-		relocs16[reloc16_idx++] = rel->r_offset;
-	else
-		relocs[reloc_idx++] = rel->r_offset;
+	return 0;
 }
 
 static int cmp_relocs(const void *va, const void *vb)
 {
-	const unsigned long *a, *b;
+	const uint32_t *a, *b;
 	a = va; b = vb;
 	return (*a == *b)? 0 : (*a > *b)? 1 : -1;
 }
 
-static int write32(unsigned int v, FILE *f)
+static void sort_relocs(struct relocs *r)
+{
+	qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
+}
+
+static int write32(uint32_t v, FILE *f)
 {
 	unsigned char buf[4];
 
@@ -707,33 +770,25 @@ static int write32(unsigned int v, FILE *f)
 	return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
 }
 
+static int write32_as_text(uint32_t v, FILE *f)
+{
+	return fprintf(f, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1;
+}
+
 static void emit_relocs(int as_text, int use_real_mode)
 {
 	int i;
-	/* Count how many relocations I have and allocate space for them. */
-	reloc_count = 0;
-	walk_relocs(count_reloc, use_real_mode);
-	relocs = malloc(reloc_count * sizeof(relocs[0]));
-	if (!relocs) {
-		die("malloc of %d entries for relocs failed\n",
-			reloc_count);
-	}
+	int (*write_reloc)(uint32_t, FILE *) = write32;
 
-	relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
-	if (!relocs16) {
-		die("malloc of %d entries for relocs16 failed\n",
-			reloc16_count);
-	}
 	/* Collect up the relocations */
-	reloc_idx = 0;
-	walk_relocs(collect_reloc, use_real_mode);
+	walk_relocs(use_real_mode ? do_reloc_real : do_reloc);
 
-	if (reloc16_count && !use_real_mode)
+	if (relocs16.count && !use_real_mode)
 		die("Segment relocations found but --realmode not specified\n");
 
 	/* Order the relocations for more efficient processing */
-	qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
-	qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);
+	sort_relocs(&relocs16);
+	sort_relocs(&relocs32);
 
 	/* Print the relocations */
 	if (as_text) {
@@ -742,43 +797,24 @@ static void emit_relocs(int as_text, int use_real_mode)
 		 */
 		printf(".section \".data.reloc\",\"a\"\n");
 		printf(".balign 4\n");
-		if (use_real_mode) {
-			printf("\t.long %lu\n", reloc16_count);
-			for (i = 0; i < reloc16_count; i++)
-				printf("\t.long 0x%08lx\n", relocs16[i]);
-			printf("\t.long %lu\n", reloc_count);
-			for (i = 0; i < reloc_count; i++) {
-				printf("\t.long 0x%08lx\n", relocs[i]);
-			}
-		} else {
-			/* Print a stop */
-			printf("\t.long 0x%08lx\n", (unsigned long)0);
-			for (i = 0; i < reloc_count; i++) {
-				printf("\t.long 0x%08lx\n", relocs[i]);
-			}
-		}
-
-		printf("\n");
+		write_reloc = write32_as_text;
 	}
-	else {
-		if (use_real_mode) {
-			write32(reloc16_count, stdout);
-			for (i = 0; i < reloc16_count; i++)
-				write32(relocs16[i], stdout);
-			write32(reloc_count, stdout);
-
-			/* Now print each relocation */
-			for (i = 0; i < reloc_count; i++)
-				write32(relocs[i], stdout);
-		} else {
-			/* Print a stop */
-			write32(0, stdout);
 
-			/* Now print each relocation */
-			for (i = 0; i < reloc_count; i++) {
-				write32(relocs[i], stdout);
-			}
-		}
+	if (use_real_mode) {
+		write_reloc(relocs16.count, stdout);
+		for (i = 0; i < relocs16.count; i++)
+			write_reloc(relocs16.offset[i], stdout);
+
+		write_reloc(relocs32.count, stdout);
+		for (i = 0; i < relocs32.count; i++)
+			write_reloc(relocs32.offset[i], stdout);
+	} else {
+		/* Print a stop */
+		write_reloc(0, stdout);
+
+		/* Now print each relocation */
+		for (i = 0; i < relocs32.count; i++)
+			write_reloc(relocs32.offset[i], stdout);
 	}
 }
 

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [tip:x86/kaslr] x86, relocs: Add 64-bit ELF support to relocs tool
  2013-04-12 20:13 ` [PATCH 3/6] x86: relocs: add 64-bit ELF support to relocs tool Kees Cook
@ 2013-04-16 23:19   ` tip-bot for Kees Cook
  0 siblings, 0 replies; 40+ messages in thread
From: tip-bot for Kees Cook @ 2013-04-16 23:19 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, keescook, tglx, hpa

Commit-ID:  946166af95d1defacfbc21e7c902d0556a2a7660
Gitweb:     http://git.kernel.org/tip/946166af95d1defacfbc21e7c902d0556a2a7660
Author:     Kees Cook <keescook@chromium.org>
AuthorDate: Fri, 12 Apr 2013 13:13:44 -0700
Committer:  H. Peter Anvin <hpa@linux.intel.com>
CommitDate: Tue, 16 Apr 2013 15:19:22 -0700

x86, relocs: Add 64-bit ELF support to relocs tool

This adds the ability to process relocations from the 64-bit kernel ELF,
if built with ELF_BITS=64 defined. The special case for the percpu area is
handled, along with some other symbols specific to the 64-bit kernel.

Based on work by Neill Clift and Michael Davidson.

Signed-off-by: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/1365797627-20874-4-git-send-email-keescook@chromium.org
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
---
 arch/x86/tools/relocs.c | 267 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 261 insertions(+), 6 deletions(-)

diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index bdc5930..1f7ff3d 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -17,19 +17,39 @@
 #define _ElfW(bits, type)	__ElfW(bits, type)
 #define __ElfW(bits, type)	Elf##bits##_##type
 
+#ifndef ELF_BITS
 #define ELF_BITS		32
+#endif
+
+#if (ELF_BITS == 64)
+#define ELF_MACHINE             EM_X86_64
+#define ELF_MACHINE_NAME        "x86_64"
+#define SHT_REL_TYPE            SHT_RELA
+#define Elf_Rel                 Elf64_Rela
+#else
 #define ELF_MACHINE		EM_386
 #define ELF_MACHINE_NAME	"i386"
 #define SHT_REL_TYPE		SHT_REL
+#define Elf_Rel			ElfW(Rel)
+#endif
 
+#if (ELF_BITS == 64)
+#define ELF_CLASS               ELFCLASS64
+#define ELF_R_SYM(val)          ELF64_R_SYM(val)
+#define ELF_R_TYPE(val)         ELF64_R_TYPE(val)
+#define ELF_ST_TYPE(o)          ELF64_ST_TYPE(o)
+#define ELF_ST_BIND(o)          ELF64_ST_BIND(o)
+#define ELF_ST_VISIBILITY(o)    ELF64_ST_VISIBILITY(o)
+#else
 #define ELF_CLASS		ELFCLASS32
 #define ELF_R_SYM(val)		ELF32_R_SYM(val)
 #define ELF_R_TYPE(val)		ELF32_R_TYPE(val)
 #define ELF_ST_TYPE(o)		ELF32_ST_TYPE(o)
 #define ELF_ST_BIND(o)		ELF32_ST_BIND(o)
 #define ELF_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY(o)
+#endif
 
-#define Elf_Rel			ElfW(Rel)
+#define Elf_Addr		ElfW(Addr)
 #define Elf_Ehdr		ElfW(Ehdr)
 #define Elf_Phdr		ElfW(Phdr)
 #define Elf_Shdr		ElfW(Shdr)
@@ -48,6 +68,7 @@ struct relocs {
 
 static struct relocs relocs16;
 static struct relocs relocs32;
+static struct relocs relocs64;
 
 struct section {
 	Elf_Shdr       shdr;
@@ -77,6 +98,9 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
 	"^(xen_irq_disable_direct_reloc$|"
 	"xen_save_fl_direct_reloc$|"
 	"VDSO|"
+#if (ELF_BITS == 64)
+	"__vvar_page|"
+#endif
 	"__crc_)",
 
 /*
@@ -100,6 +124,11 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
 	"__end_rodata|"
 	"__initramfs_start|"
 	"(jiffies|jiffies_64)|"
+#if (ELF_BITS == 64)
+	"__per_cpu_load|"
+	"init_per_cpu__.*|"
+	"__end_rodata_hpage_align|"
+#endif
 	"_end)$"
 };
 
@@ -226,6 +255,24 @@ static const char *rel_type(unsigned type)
 {
 	static const char *type_name[] = {
 #define REL_TYPE(X) [X] = #X
+#if (ELF_BITS == 64)
+		REL_TYPE(R_X86_64_NONE),
+		REL_TYPE(R_X86_64_64),
+		REL_TYPE(R_X86_64_PC32),
+		REL_TYPE(R_X86_64_GOT32),
+		REL_TYPE(R_X86_64_PLT32),
+		REL_TYPE(R_X86_64_COPY),
+		REL_TYPE(R_X86_64_GLOB_DAT),
+		REL_TYPE(R_X86_64_JUMP_SLOT),
+		REL_TYPE(R_X86_64_RELATIVE),
+		REL_TYPE(R_X86_64_GOTPCREL),
+		REL_TYPE(R_X86_64_32),
+		REL_TYPE(R_X86_64_32S),
+		REL_TYPE(R_X86_64_16),
+		REL_TYPE(R_X86_64_PC16),
+		REL_TYPE(R_X86_64_8),
+		REL_TYPE(R_X86_64_PC8),
+#else
 		REL_TYPE(R_386_NONE),
 		REL_TYPE(R_386_32),
 		REL_TYPE(R_386_PC32),
@@ -241,6 +288,7 @@ static const char *rel_type(unsigned type)
 		REL_TYPE(R_386_PC8),
 		REL_TYPE(R_386_16),
 		REL_TYPE(R_386_PC16),
+#endif
 #undef REL_TYPE
 	};
 	const char *name = "unknown type rel type name";
@@ -281,15 +329,42 @@ static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
 	return name;
 }
 
+static Elf_Sym *sym_lookup(const char *symname)
+{
+	int i;
+	for (i = 0; i < ehdr.e_shnum; i++) {
+		struct section *sec = &secs[i];
+		long nsyms;
+		char *strtab;
+		Elf_Sym *symtab;
+		Elf_Sym *sym;
 
+		if (sec->shdr.sh_type != SHT_SYMTAB)
+			continue;
+
+		nsyms = sec->shdr.sh_size/sizeof(Elf_Sym);
+		symtab = sec->symtab;
+		strtab = sec->link->strtab;
+
+		for (sym = symtab; --nsyms >= 0; sym++) {
+			if (!sym->st_name)
+				continue;
+			if (strcmp(symname, strtab + sym->st_name) == 0)
+				return sym;
+		}
+	}
+	return 0;
+}
 
 #if BYTE_ORDER == LITTLE_ENDIAN
 #define le16_to_cpu(val) (val)
 #define le32_to_cpu(val) (val)
+#define le64_to_cpu(val) (val)
 #endif
 #if BYTE_ORDER == BIG_ENDIAN
 #define le16_to_cpu(val) bswap_16(val)
 #define le32_to_cpu(val) bswap_32(val)
+#define le64_to_cpu(val) bswap_64(val)
 #endif
 
 static uint16_t elf16_to_cpu(uint16_t val)
@@ -304,9 +379,20 @@ static uint32_t elf32_to_cpu(uint32_t val)
 
 #define elf_half_to_cpu(x)	elf16_to_cpu(x)
 #define elf_word_to_cpu(x)	elf32_to_cpu(x)
+
+#if (ELF_BITS == 64)
+static uint64_t elf64_to_cpu(uint64_t val)
+{
+        return le64_to_cpu(val);
+}
+#define elf_addr_to_cpu(x)	elf64_to_cpu(x)
+#define elf_off_to_cpu(x)	elf64_to_cpu(x)
+#define elf_xword_to_cpu(x)	elf64_to_cpu(x)
+#else
 #define elf_addr_to_cpu(x)	elf32_to_cpu(x)
 #define elf_off_to_cpu(x)	elf32_to_cpu(x)
 #define elf_xword_to_cpu(x)	elf32_to_cpu(x)
+#endif
 
 static void read_ehdr(FILE *fp)
 {
@@ -483,6 +569,9 @@ static void read_relocs(FILE *fp)
 			Elf_Rel *rel = &sec->reltab[j];
 			rel->r_offset = elf_addr_to_cpu(rel->r_offset);
 			rel->r_info   = elf_xword_to_cpu(rel->r_info);
+#if (SHT_REL_TYPE == SHT_RELA)
+			rel->r_addend = elf_xword_to_cpu(rel->r_addend);
+#endif
 		}
 	}
 }
@@ -491,6 +580,13 @@ static void read_relocs(FILE *fp)
 static void print_absolute_symbols(void)
 {
 	int i;
+	const char *format;
+
+	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+		format = "%5d %016"PRIx64" %5"PRId64" %10s %10s %12s %s\n";
+	else
+		format = "%5d %08"PRIx32"  %5"PRId32" %10s %10s %12s %s\n";
+
 	printf("Absolute symbols\n");
 	printf(" Num:    Value Size  Type       Bind        Visibility  Name\n");
 	for (i = 0; i < ehdr.e_shnum; i++) {
@@ -510,7 +606,7 @@ static void print_absolute_symbols(void)
 			if (sym->st_shndx != SHN_ABS) {
 				continue;
 			}
-			printf("%5d %08x %5d %10s %10s %12s %s\n",
+			printf(format,
 				j, sym->st_value, sym->st_size,
 				sym_type(ELF_ST_TYPE(sym->st_info)),
 				sym_bind(ELF_ST_BIND(sym->st_info)),
@@ -524,6 +620,12 @@ static void print_absolute_symbols(void)
 static void print_absolute_relocs(void)
 {
 	int i, printed = 0;
+	const char *format;
+
+	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+		format = "%016"PRIx64" %016"PRIx64" %10s %016"PRIx64"  %s\n";
+	else
+		format = "%08"PRIx32" %08"PRIx32" %10s %08"PRIx32"  %s\n";
 
 	for (i = 0; i < ehdr.e_shnum; i++) {
 		struct section *sec = &secs[i];
@@ -576,7 +678,7 @@ static void print_absolute_relocs(void)
 				printed = 1;
 			}
 
-			printf("%08x %08x %10s %08x  %s\n",
+			printf(format,
 				rel->r_offset,
 				rel->r_info,
 				rel_type(ELF_R_TYPE(rel->r_info)),
@@ -636,8 +738,140 @@ static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
 	}
 }
 
-static int do_reloc(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
-		    const char *symname)
+/*
+ * The .data..percpu section is a special case for x86_64 SMP kernels.
+ * It is used to initialize the actual per_cpu areas and to provide
+ * definitions for the per_cpu variables that correspond to their offsets
+ * within the percpu area. Since the values of all of the symbols need
+ * to be offsets from the start of the per_cpu area the virtual address
+ * (sh_addr) of .data..percpu is 0 in SMP kernels.
+ *
+ * This means that:
+ *
+ *	Relocations that reference symbols in the per_cpu area do not
+ *	need further relocation (since the value is an offset relative
+ *	to the start of the per_cpu area that does not change).
+ *
+ *	Relocations that apply to the per_cpu area need to have their
+ *	offset adjusted by by the value of __per_cpu_load to make them
+ *	point to the correct place in the loaded image (because the
+ *	virtual address of .data..percpu is 0).
+ *
+ * For non SMP kernels .data..percpu is linked as part of the normal
+ * kernel data and does not require special treatment.
+ *
+ */
+static int per_cpu_shndx	= -1;
+Elf_Addr per_cpu_load_addr;
+
+static void percpu_init(void)
+{
+	int i;
+	for (i = 0; i < ehdr.e_shnum; i++) {
+		ElfW(Sym) *sym;
+		if (strcmp(sec_name(i), ".data..percpu"))
+			continue;
+
+		if (secs[i].shdr.sh_addr != 0)	/* non SMP kernel */
+			return;
+
+		sym = sym_lookup("__per_cpu_load");
+		if (!sym)
+			die("can't find __per_cpu_load\n");
+
+		per_cpu_shndx = i;
+		per_cpu_load_addr = sym->st_value;
+		return;
+	}
+}
+
+/*
+ * Check to see if a symbol lies in the .data..percpu section.
+ * For some as yet not understood reason the "__init_begin"
+ * symbol which immediately preceeds the .data..percpu section
+ * also shows up as it it were part of it so we do an explict
+ * check for that symbol name and ignore it.
+ */
+static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
+{
+	return (sym->st_shndx == per_cpu_shndx) &&
+		strcmp(symname, "__init_begin");
+}
+
+static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
+		      const char *symname)
+{
+	unsigned r_type = ELF64_R_TYPE(rel->r_info);
+	ElfW(Addr) offset = rel->r_offset;
+	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
+
+	if (sym->st_shndx == SHN_UNDEF)
+		return 0;
+
+	/*
+	 * Adjust the offset if this reloc applies to the percpu section.
+	 */
+	if (sec->shdr.sh_info == per_cpu_shndx)
+		offset += per_cpu_load_addr;
+
+	switch (r_type) {
+	case R_X86_64_NONE:
+	case R_X86_64_PC32:
+		/*
+		 * NONE can be ignored and PC relative relocations don't
+		 * need to be adjusted.
+		 */
+		break;
+
+	case R_X86_64_32:
+	case R_X86_64_32S:
+	case R_X86_64_64:
+		/*
+		 * References to the percpu area don't need to be adjusted.
+		 */
+		if (is_percpu_sym(sym, symname))
+			break;
+
+		if (shn_abs) {
+			/*
+			 * Whitelisted absolute symbols do not require
+			 * relocation.
+			 */
+			if (is_reloc(S_ABS, symname))
+				break;
+
+			die("Invalid absolute %s relocation: %s\n",
+			    rel_type(r_type), symname);
+			break;
+		}
+
+		/*
+		 * Relocation offsets for 64 bit kernels are output
+		 * as 32 bits and sign extended back to 64 bits when
+		 * the relocations are processed.
+		 * Make sure that the offset will fit.
+		 */
+		if ((int32_t)offset != (int64_t)offset)
+			die("Relocation offset doesn't fit in 32 bits\n");
+
+		if (r_type == R_X86_64_64)
+			add_reloc(&relocs64, offset);
+		else
+			add_reloc(&relocs32, offset);
+		break;
+
+	default:
+		die("Unsupported relocation type: %s (%d)\n",
+		    rel_type(r_type), r_type);
+		break;
+	}
+
+	return 0;
+}
+
+
+static int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+		      const char *symname)
 {
 	unsigned r_type = ELF32_R_TYPE(rel->r_info);
 	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
@@ -779,9 +1013,18 @@ static void emit_relocs(int as_text, int use_real_mode)
 {
 	int i;
 	int (*write_reloc)(uint32_t, FILE *) = write32;
+	int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
+			const char *symname);
+
+	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+		do_reloc = do_reloc64;
+	else if (!use_real_mode)
+		do_reloc = do_reloc32;
+	else
+		do_reloc = do_reloc_real;
 
 	/* Collect up the relocations */
-	walk_relocs(use_real_mode ? do_reloc_real : do_reloc);
+	walk_relocs(do_reloc);
 
 	if (relocs16.count && !use_real_mode)
 		die("Segment relocations found but --realmode not specified\n");
@@ -789,6 +1032,7 @@ static void emit_relocs(int as_text, int use_real_mode)
 	/* Order the relocations for more efficient processing */
 	sort_relocs(&relocs16);
 	sort_relocs(&relocs32);
+	sort_relocs(&relocs64);
 
 	/* Print the relocations */
 	if (as_text) {
@@ -809,6 +1053,15 @@ static void emit_relocs(int as_text, int use_real_mode)
 		for (i = 0; i < relocs32.count; i++)
 			write_reloc(relocs32.offset[i], stdout);
 	} else {
+		if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
+			/* Print a stop */
+			write_reloc(0, stdout);
+
+			/* Now print each relocation */
+			for (i = 0; i < relocs64.count; i++)
+				write_reloc(relocs64.offset[i], stdout);
+		}
+
 		/* Print a stop */
 		write_reloc(0, stdout);
 
@@ -876,6 +1129,8 @@ int main(int argc, char **argv)
 	read_strtabs(fp);
 	read_symtabs(fp);
 	read_relocs(fp);
+	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+		percpu_init();
 	if (show_absolute_syms) {
 		print_absolute_symbols();
 		goto out;

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [tip:x86/kaslr] x86, relocs: Build separate 32/64-bit tools
  2013-04-12 20:13 ` [PATCH 4/6] x86: relocs: build separate 32/64-bit tools Kees Cook
  2013-04-16 22:21   ` H. Peter Anvin
@ 2013-04-16 23:20   ` tip-bot for Kees Cook
  2013-04-16 23:22   ` [tip:x86/kaslr] x86, relocs: Refactor the relocs tool to merge 32- and 64-bit ELF tip-bot for H. Peter Anvin
  2 siblings, 0 replies; 40+ messages in thread
From: tip-bot for Kees Cook @ 2013-04-16 23:20 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, keescook, tglx, hpa

Commit-ID:  17c961f7702ff6037b66bb2e5f3ddd58de4ce7e5
Gitweb:     http://git.kernel.org/tip/17c961f7702ff6037b66bb2e5f3ddd58de4ce7e5
Author:     Kees Cook <keescook@chromium.org>
AuthorDate: Fri, 12 Apr 2013 13:13:45 -0700
Committer:  H. Peter Anvin <hpa@linux.intel.com>
CommitDate: Tue, 16 Apr 2013 15:22:01 -0700

x86, relocs: Build separate 32/64-bit tools

Since the ELF structures and access macros change size based on 32 vs
64 bits, build a separate 32-bit relocs tool (for handling realmode
and 32-bit relocations), and a 64-bit relocs tool (for handling 64-bit
kernel relocations).

Signed-off-by: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/1365797627-20874-5-git-send-email-keescook@chromium.org
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
---
 arch/x86/boot/compressed/Makefile |  2 +-
 arch/x86/realmode/rm/Makefile     |  2 +-
 arch/x86/tools/.gitignore         |  3 ++-
 arch/x86/tools/Makefile           | 20 ++++++++++++++++++--
 4 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 5ef205c..0dac175 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -44,7 +44,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
 
 targets += $(patsubst $(obj)/%,%,$(VMLINUX_OBJS)) vmlinux.bin.all vmlinux.relocs
 
-CMD_RELOCS = arch/x86/tools/relocs
+CMD_RELOCS = arch/x86/tools/relocs_$(BITS)
 quiet_cmd_relocs = RELOCS  $@
       cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $<
 $(obj)/vmlinux.relocs: vmlinux FORCE
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 8869287..2b1e429 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -56,7 +56,7 @@ $(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs
 	$(call if_changed,objcopy)
 
 quiet_cmd_relocs = RELOCS  $@
-      cmd_relocs = arch/x86/tools/relocs --realmode $< > $@
+      cmd_relocs = arch/x86/tools/relocs_32 --realmode $< > $@
 
 targets += realmode.relocs
 $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE
diff --git a/arch/x86/tools/.gitignore b/arch/x86/tools/.gitignore
index be0ed06..2b45d5f 100644
--- a/arch/x86/tools/.gitignore
+++ b/arch/x86/tools/.gitignore
@@ -1 +1,2 @@
-relocs
+relocs_32*
+relocs_64*
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
index bae601f..a8cb70c 100644
--- a/arch/x86/tools/Makefile
+++ b/arch/x86/tools/Makefile
@@ -37,6 +37,22 @@ $(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/in
 
 $(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
 
+HOSTCFLAGS_relocs_32.o += -DELF_BITS=32
+HOSTCFLAGS_relocs_64.o += -DELF_BITS=64
+
+quiet_cmd_cp_reloc = GEN     $@
+      cmd_cp_reloc = cp $< $@
+
+$(obj)/relocs_%.c: $(srctree)/arch/x86/tools/relocs.c
+	$(call cmd,cp_reloc)
+
 HOST_EXTRACFLAGS += -I$(srctree)/tools/include
-hostprogs-y	+= relocs
-relocs: $(obj)/relocs
+hostprogs-y    += relocs_$(BITS)
+relocs_binaries = relocs_$(BITS)
+ifeq ($(CONFIG_64BIT),y)
+	hostprogs-y  += relocs_32
+	relocs_binaries += relocs_32
+endif
+relocs: $(relocs_binaries)
+relocs_32: $(obj)/relocs_32
+relocs_64: $(obj)/relocs_64

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [tip:x86/kaslr] x86, relocs: Refactor the relocs tool to merge 32- and 64-bit ELF
  2013-04-12 20:13 ` [PATCH 4/6] x86: relocs: build separate 32/64-bit tools Kees Cook
  2013-04-16 22:21   ` H. Peter Anvin
  2013-04-16 23:20   ` [tip:x86/kaslr] x86, relocs: Build " tip-bot for Kees Cook
@ 2013-04-16 23:22   ` tip-bot for H. Peter Anvin
  2 siblings, 0 replies; 40+ messages in thread
From: tip-bot for H. Peter Anvin @ 2013-04-16 23:22 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: linux-kernel, hpa, mingo, keescook, tglx, hpa

Commit-ID:  c889ba801dc3b3a0155fa77d567f2c3a6097de1c
Gitweb:     http://git.kernel.org/tip/c889ba801dc3b3a0155fa77d567f2c3a6097de1c
Author:     H. Peter Anvin <hpa@linux.intel.com>
AuthorDate: Tue, 16 Apr 2013 16:02:58 -0700
Committer:  H. Peter Anvin <hpa@linux.intel.com>
CommitDate: Tue, 16 Apr 2013 16:02:58 -0700

x86, relocs: Refactor the relocs tool to merge 32- and 64-bit ELF

Refactor the relocs tool so that the same tool can handle 32- and
64-bit ELF.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Cc: Kees Cook <keescook@chromium.org>
Link: http://lkml.kernel.org/r/1365797627-20874-5-git-send-email-keescook@chromium.org
---
 arch/x86/boot/compressed/Makefile |   2 +-
 arch/x86/realmode/rm/Makefile     |   2 +-
 arch/x86/tools/.gitignore         |   3 +-
 arch/x86/tools/Makefile           |  21 +----
 arch/x86/tools/relocs.c           | 162 ++++++++------------------------------
 arch/x86/tools/relocs.h           |  36 +++++++++
 arch/x86/tools/relocs_32.c        |  17 ++++
 arch/x86/tools/relocs_64.c        |  17 ++++
 arch/x86/tools/relocs_common.c    |  76 ++++++++++++++++++
 9 files changed, 183 insertions(+), 153 deletions(-)

diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index 0dac175..5ef205c 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -44,7 +44,7 @@ $(obj)/vmlinux.bin: vmlinux FORCE
 
 targets += $(patsubst $(obj)/%,%,$(VMLINUX_OBJS)) vmlinux.bin.all vmlinux.relocs
 
-CMD_RELOCS = arch/x86/tools/relocs_$(BITS)
+CMD_RELOCS = arch/x86/tools/relocs
 quiet_cmd_relocs = RELOCS  $@
       cmd_relocs = $(CMD_RELOCS) $< > $@;$(CMD_RELOCS) --abs-relocs $<
 $(obj)/vmlinux.relocs: vmlinux FORCE
diff --git a/arch/x86/realmode/rm/Makefile b/arch/x86/realmode/rm/Makefile
index 2b1e429..8869287 100644
--- a/arch/x86/realmode/rm/Makefile
+++ b/arch/x86/realmode/rm/Makefile
@@ -56,7 +56,7 @@ $(obj)/realmode.bin: $(obj)/realmode.elf $(obj)/realmode.relocs
 	$(call if_changed,objcopy)
 
 quiet_cmd_relocs = RELOCS  $@
-      cmd_relocs = arch/x86/tools/relocs_32 --realmode $< > $@
+      cmd_relocs = arch/x86/tools/relocs --realmode $< > $@
 
 targets += realmode.relocs
 $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE
diff --git a/arch/x86/tools/.gitignore b/arch/x86/tools/.gitignore
index 2b45d5f..be0ed06 100644
--- a/arch/x86/tools/.gitignore
+++ b/arch/x86/tools/.gitignore
@@ -1,2 +1 @@
-relocs_32*
-relocs_64*
+relocs
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
index a8cb70c..e812034 100644
--- a/arch/x86/tools/Makefile
+++ b/arch/x86/tools/Makefile
@@ -37,22 +37,7 @@ $(obj)/test_get_len.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/in
 
 $(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/inat.c $(srctree)/arch/x86/include/asm/inat_types.h $(srctree)/arch/x86/include/asm/inat.h $(srctree)/arch/x86/include/asm/insn.h $(objtree)/arch/x86/lib/inat-tables.c
 
-HOSTCFLAGS_relocs_32.o += -DELF_BITS=32
-HOSTCFLAGS_relocs_64.o += -DELF_BITS=64
-
-quiet_cmd_cp_reloc = GEN     $@
-      cmd_cp_reloc = cp $< $@
-
-$(obj)/relocs_%.c: $(srctree)/arch/x86/tools/relocs.c
-	$(call cmd,cp_reloc)
-
 HOST_EXTRACFLAGS += -I$(srctree)/tools/include
-hostprogs-y    += relocs_$(BITS)
-relocs_binaries = relocs_$(BITS)
-ifeq ($(CONFIG_64BIT),y)
-	hostprogs-y  += relocs_32
-	relocs_binaries += relocs_32
-endif
-relocs: $(relocs_binaries)
-relocs_32: $(obj)/relocs_32
-relocs_64: $(obj)/relocs_64
+hostprogs-y	+= relocs
+relocs-objs     := relocs_32.o relocs_64.o relocs_common.o
+relocs: $(obj)/relocs
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 1f7ff3d..590be10 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -1,63 +1,15 @@
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <elf.h>
-#include <byteswap.h>
-#define USE_BSD
-#include <endian.h>
-#include <regex.h>
-#include <tools/le_byteshift.h>
+/* This is included from relocs_32/64.c */
 
 #define ElfW(type)		_ElfW(ELF_BITS, type)
 #define _ElfW(bits, type)	__ElfW(bits, type)
 #define __ElfW(bits, type)	Elf##bits##_##type
 
-#ifndef ELF_BITS
-#define ELF_BITS		32
-#endif
-
-#if (ELF_BITS == 64)
-#define ELF_MACHINE             EM_X86_64
-#define ELF_MACHINE_NAME        "x86_64"
-#define SHT_REL_TYPE            SHT_RELA
-#define Elf_Rel                 Elf64_Rela
-#else
-#define ELF_MACHINE		EM_386
-#define ELF_MACHINE_NAME	"i386"
-#define SHT_REL_TYPE		SHT_REL
-#define Elf_Rel			ElfW(Rel)
-#endif
-
-#if (ELF_BITS == 64)
-#define ELF_CLASS               ELFCLASS64
-#define ELF_R_SYM(val)          ELF64_R_SYM(val)
-#define ELF_R_TYPE(val)         ELF64_R_TYPE(val)
-#define ELF_ST_TYPE(o)          ELF64_ST_TYPE(o)
-#define ELF_ST_BIND(o)          ELF64_ST_BIND(o)
-#define ELF_ST_VISIBILITY(o)    ELF64_ST_VISIBILITY(o)
-#else
-#define ELF_CLASS		ELFCLASS32
-#define ELF_R_SYM(val)		ELF32_R_SYM(val)
-#define ELF_R_TYPE(val)		ELF32_R_TYPE(val)
-#define ELF_ST_TYPE(o)		ELF32_ST_TYPE(o)
-#define ELF_ST_BIND(o)		ELF32_ST_BIND(o)
-#define ELF_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY(o)
-#endif
-
 #define Elf_Addr		ElfW(Addr)
 #define Elf_Ehdr		ElfW(Ehdr)
 #define Elf_Phdr		ElfW(Phdr)
 #define Elf_Shdr		ElfW(Shdr)
 #define Elf_Sym			ElfW(Sym)
 
-static void die(char *fmt, ...);
-
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 static Elf_Ehdr ehdr;
 
 struct relocs {
@@ -79,14 +31,6 @@ struct section {
 };
 static struct section *secs;
 
-enum symtype {
-	S_ABS,
-	S_REL,
-	S_SEG,
-	S_LIN,
-	S_NSYMTYPES
-};
-
 static const char * const sym_regex_kernel[S_NSYMTYPES] = {
 /*
  * Following symbols have been audited. There values are constant and do
@@ -98,7 +42,7 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
 	"^(xen_irq_disable_direct_reloc$|"
 	"xen_save_fl_direct_reloc$|"
 	"VDSO|"
-#if (ELF_BITS == 64)
+#if ELF_BITS == 64
 	"__vvar_page|"
 #endif
 	"__crc_)",
@@ -124,7 +68,7 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
 	"__end_rodata|"
 	"__initramfs_start|"
 	"(jiffies|jiffies_64)|"
-#if (ELF_BITS == 64)
+#if ELF_BITS == 64
 	"__per_cpu_load|"
 	"init_per_cpu__.*|"
 	"__end_rodata_hpage_align|"
@@ -189,15 +133,6 @@ static void regex_init(int use_real_mode)
         }
 }
 
-static void die(char *fmt, ...)
-{
-	va_list ap;
-	va_start(ap, fmt);
-	vfprintf(stderr, fmt, ap);
-	va_end(ap);
-	exit(1);
-}
-
 static const char *sym_type(unsigned type)
 {
 	static const char *type_name[] = {
@@ -255,7 +190,7 @@ static const char *rel_type(unsigned type)
 {
 	static const char *type_name[] = {
 #define REL_TYPE(X) [X] = #X
-#if (ELF_BITS == 64)
+#if ELF_BITS == 64
 		REL_TYPE(R_X86_64_NONE),
 		REL_TYPE(R_X86_64_64),
 		REL_TYPE(R_X86_64_PC32),
@@ -380,7 +315,7 @@ static uint32_t elf32_to_cpu(uint32_t val)
 #define elf_half_to_cpu(x)	elf16_to_cpu(x)
 #define elf_word_to_cpu(x)	elf32_to_cpu(x)
 
-#if (ELF_BITS == 64)
+#if ELF_BITS == 64
 static uint64_t elf64_to_cpu(uint64_t val)
 {
         return le64_to_cpu(val);
@@ -582,7 +517,7 @@ static void print_absolute_symbols(void)
 	int i;
 	const char *format;
 
-	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+	if (ELF_BITS == 64)
 		format = "%5d %016"PRIx64" %5"PRId64" %10s %10s %12s %s\n";
 	else
 		format = "%5d %08"PRIx32"  %5"PRId32" %10s %10s %12s %s\n";
@@ -622,7 +557,7 @@ static void print_absolute_relocs(void)
 	int i, printed = 0;
 	const char *format;
 
-	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+	if (ELF_BITS == 64)
 		format = "%016"PRIx64" %016"PRIx64" %10s %016"PRIx64"  %s\n";
 	else
 		format = "%08"PRIx32" %08"PRIx32" %10s %08"PRIx32"  %s\n";
@@ -785,6 +720,8 @@ static void percpu_init(void)
 	}
 }
 
+#if ELF_BITS == 64
+
 /*
  * Check to see if a symbol lies in the .data..percpu section.
  * For some as yet not understood reason the "__init_begin"
@@ -798,6 +735,7 @@ static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
 		strcmp(symname, "__init_begin");
 }
 
+
 static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
 		      const char *symname)
 {
@@ -869,6 +807,7 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
 	return 0;
 }
 
+#else
 
 static int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
 		      const char *symname)
@@ -984,6 +923,8 @@ static int do_reloc_real(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
 	return 0;
 }
 
+#endif
+
 static int cmp_relocs(const void *va, const void *vb)
 {
 	const uint32_t *a, *b;
@@ -1016,12 +957,17 @@ static void emit_relocs(int as_text, int use_real_mode)
 	int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
 			const char *symname);
 
-	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+#if ELF_BITS == 64
+	if (!use_real_mode)
 		do_reloc = do_reloc64;
-	else if (!use_real_mode)
+	else
+		die("--realmode not valid for a 64-bit ELF file");
+#else
+	if (!use_real_mode)
 		do_reloc = do_reloc32;
 	else
 		do_reloc = do_reloc_real;
+#endif
 
 	/* Collect up the relocations */
 	walk_relocs(do_reloc);
@@ -1053,7 +999,7 @@ static void emit_relocs(int as_text, int use_real_mode)
 		for (i = 0; i < relocs32.count; i++)
 			write_reloc(relocs32.offset[i], stdout);
 	} else {
-		if (ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
+		if (ELF_BITS == 64) {
 			/* Print a stop */
 			write_reloc(0, stdout);
 
@@ -1071,76 +1017,30 @@ static void emit_relocs(int as_text, int use_real_mode)
 	}
 }
 
-static void usage(void)
-{
-	die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
-}
+#if ELF_BITS == 64
+# define process process_64
+#else
+# define process process_32
+#endif
 
-int main(int argc, char **argv)
+void process(FILE *fp, int use_real_mode, int as_text,
+	     int show_absolute_syms, int show_absolute_relocs)
 {
-	int show_absolute_syms, show_absolute_relocs;
-	int as_text, use_real_mode;
-	const char *fname;
-	FILE *fp;
-	int i;
-
-	show_absolute_syms = 0;
-	show_absolute_relocs = 0;
-	as_text = 0;
-	use_real_mode = 0;
-	fname = NULL;
-	for (i = 1; i < argc; i++) {
-		char *arg = argv[i];
-		if (*arg == '-') {
-			if (strcmp(arg, "--abs-syms") == 0) {
-				show_absolute_syms = 1;
-				continue;
-			}
-			if (strcmp(arg, "--abs-relocs") == 0) {
-				show_absolute_relocs = 1;
-				continue;
-			}
-			if (strcmp(arg, "--text") == 0) {
-				as_text = 1;
-				continue;
-			}
-			if (strcmp(arg, "--realmode") == 0) {
-				use_real_mode = 1;
-				continue;
-			}
-		}
-		else if (!fname) {
-			fname = arg;
-			continue;
-		}
-		usage();
-	}
-	if (!fname) {
-		usage();
-	}
 	regex_init(use_real_mode);
-	fp = fopen(fname, "r");
-	if (!fp) {
-		die("Cannot open %s: %s\n",
-			fname, strerror(errno));
-	}
 	read_ehdr(fp);
 	read_shdrs(fp);
 	read_strtabs(fp);
 	read_symtabs(fp);
 	read_relocs(fp);
-	if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+	if (ELF_BITS == 64)
 		percpu_init();
 	if (show_absolute_syms) {
 		print_absolute_symbols();
-		goto out;
+		return;
 	}
 	if (show_absolute_relocs) {
 		print_absolute_relocs();
-		goto out;
+		return;
 	}
 	emit_relocs(as_text, use_real_mode);
-out:
-	fclose(fp);
-	return 0;
 }
diff --git a/arch/x86/tools/relocs.h b/arch/x86/tools/relocs.h
new file mode 100644
index 0000000..07cdb1e
--- /dev/null
+++ b/arch/x86/tools/relocs.h
@@ -0,0 +1,36 @@
+#ifndef RELOCS_H
+#define RELOCS_H
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <elf.h>
+#include <byteswap.h>
+#define USE_BSD
+#include <endian.h>
+#include <regex.h>
+#include <tools/le_byteshift.h>
+
+void die(char *fmt, ...);
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+enum symtype {
+	S_ABS,
+	S_REL,
+	S_SEG,
+	S_LIN,
+	S_NSYMTYPES
+};
+
+void process_32(FILE *fp, int use_real_mode, int as_text,
+		int show_absolute_syms, int show_absolute_relocs);
+void process_64(FILE *fp, int use_real_mode, int as_text,
+		int show_absolute_syms, int show_absolute_relocs);
+
+#endif /* RELOCS_H */
diff --git a/arch/x86/tools/relocs_32.c b/arch/x86/tools/relocs_32.c
new file mode 100644
index 0000000..b2ade2b
--- /dev/null
+++ b/arch/x86/tools/relocs_32.c
@@ -0,0 +1,17 @@
+#include "relocs.h"
+
+#define ELF_BITS 32
+
+#define ELF_MACHINE		EM_386
+#define ELF_MACHINE_NAME	"i386"
+#define SHT_REL_TYPE		SHT_REL
+#define Elf_Rel			ElfW(Rel)
+
+#define ELF_CLASS		ELFCLASS32
+#define ELF_R_SYM(val)		ELF32_R_SYM(val)
+#define ELF_R_TYPE(val)		ELF32_R_TYPE(val)
+#define ELF_ST_TYPE(o)		ELF32_ST_TYPE(o)
+#define ELF_ST_BIND(o)		ELF32_ST_BIND(o)
+#define ELF_ST_VISIBILITY(o)	ELF32_ST_VISIBILITY(o)
+
+#include "relocs.c"
diff --git a/arch/x86/tools/relocs_64.c b/arch/x86/tools/relocs_64.c
new file mode 100644
index 0000000..56b61b7
--- /dev/null
+++ b/arch/x86/tools/relocs_64.c
@@ -0,0 +1,17 @@
+#include "relocs.h"
+
+#define ELF_BITS 64
+
+#define ELF_MACHINE             EM_X86_64
+#define ELF_MACHINE_NAME        "x86_64"
+#define SHT_REL_TYPE            SHT_RELA
+#define Elf_Rel                 Elf64_Rela
+
+#define ELF_CLASS               ELFCLASS64
+#define ELF_R_SYM(val)          ELF64_R_SYM(val)
+#define ELF_R_TYPE(val)         ELF64_R_TYPE(val)
+#define ELF_ST_TYPE(o)          ELF64_ST_TYPE(o)
+#define ELF_ST_BIND(o)          ELF64_ST_BIND(o)
+#define ELF_ST_VISIBILITY(o)    ELF64_ST_VISIBILITY(o)
+
+#include "relocs.c"
diff --git a/arch/x86/tools/relocs_common.c b/arch/x86/tools/relocs_common.c
new file mode 100644
index 0000000..44d3968
--- /dev/null
+++ b/arch/x86/tools/relocs_common.c
@@ -0,0 +1,76 @@
+#include "relocs.h"
+
+void die(char *fmt, ...)
+{
+	va_list ap;
+	va_start(ap, fmt);
+	vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	exit(1);
+}
+
+static void usage(void)
+{
+	die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
+}
+
+int main(int argc, char **argv)
+{
+	int show_absolute_syms, show_absolute_relocs;
+	int as_text, use_real_mode;
+	const char *fname;
+	FILE *fp;
+	int i;
+	unsigned char e_ident[EI_NIDENT];
+
+	show_absolute_syms = 0;
+	show_absolute_relocs = 0;
+	as_text = 0;
+	use_real_mode = 0;
+	fname = NULL;
+	for (i = 1; i < argc; i++) {
+		char *arg = argv[i];
+		if (*arg == '-') {
+			if (strcmp(arg, "--abs-syms") == 0) {
+				show_absolute_syms = 1;
+				continue;
+			}
+			if (strcmp(arg, "--abs-relocs") == 0) {
+				show_absolute_relocs = 1;
+				continue;
+			}
+			if (strcmp(arg, "--text") == 0) {
+				as_text = 1;
+				continue;
+			}
+			if (strcmp(arg, "--realmode") == 0) {
+				use_real_mode = 1;
+				continue;
+			}
+		}
+		else if (!fname) {
+			fname = arg;
+			continue;
+		}
+		usage();
+	}
+	if (!fname) {
+		usage();
+	}
+	fp = fopen(fname, "r");
+	if (!fp) {
+		die("Cannot open %s: %s\n", fname, strerror(errno));
+	}
+	if (fread(&e_ident, 1, EI_NIDENT, fp) != EI_NIDENT) {
+		die("Cannot read %s: %s", fname, strerror(errno));
+	}
+	rewind(fp);
+	if (e_ident[EI_CLASS] == ELFCLASS64)
+		process_64(fp, use_real_mode, as_text,
+			   show_absolute_syms, show_absolute_relocs);
+	else
+		process_32(fp, use_real_mode, as_text,
+			   show_absolute_syms, show_absolute_relocs);
+	fclose(fp);
+	return 0;
+}

^ permalink raw reply related	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2013-04-16 23:22 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-12 20:13 [PATCH v2 0/6] kernel ASLR Kees Cook
2013-04-12 20:13 ` [PATCH 1/6] x86: relocs: generalize Elf structure names Kees Cook
2013-04-16 23:17   ` [tip:x86/kaslr] x86, relocs: Generalize ELF " tip-bot for Kees Cook
2013-04-12 20:13 ` [PATCH 2/6] x86: relocs: consolidate processing logic Kees Cook
2013-04-16 23:18   ` [tip:x86/kaslr] x86, relocs: Consolidate " tip-bot for Kees Cook
2013-04-12 20:13 ` [PATCH 3/6] x86: relocs: add 64-bit ELF support to relocs tool Kees Cook
2013-04-16 23:19   ` [tip:x86/kaslr] x86, relocs: Add " tip-bot for Kees Cook
2013-04-12 20:13 ` [PATCH 4/6] x86: relocs: build separate 32/64-bit tools Kees Cook
2013-04-16 22:21   ` H. Peter Anvin
2013-04-16 22:38     ` Kees Cook
2013-04-16 22:39       ` H. Peter Anvin
2013-04-16 23:20   ` [tip:x86/kaslr] x86, relocs: Build " tip-bot for Kees Cook
2013-04-16 23:22   ` [tip:x86/kaslr] x86, relocs: Refactor the relocs tool to merge 32- and 64-bit ELF tip-bot for H. Peter Anvin
2013-04-12 20:13 ` [PATCH 5/6] x86: kaslr: routines to choose random base offset Kees Cook
2013-04-14  0:11   ` Yinghai Lu
2013-04-12 20:13 ` [PATCH 6/6] x86: kaslr: relocate base offset at boot Kees Cook
2013-04-14  0:37   ` Yinghai Lu
2013-04-14  3:06     ` H. Peter Anvin
2013-04-15 21:06       ` Eric Northup
2013-04-15 21:25         ` H. Peter Anvin
2013-04-15 21:41           ` Kees Cook
2013-04-15 21:44             ` Eric Northup
2013-04-15 21:46             ` H. Peter Anvin
2013-04-15 21:59               ` Kees Cook
2013-04-16  2:31                 ` H. Peter Anvin
2013-04-16  2:40                   ` H. Peter Anvin
2013-04-16 16:08                     ` Kees Cook
2013-04-15 22:00               ` Yinghai Lu
2013-04-15 22:07                 ` Kees Cook
2013-04-15 22:38                   ` Yinghai Lu
2013-04-15 22:42                     ` Kees Cook
2013-04-15 22:57                       ` Yinghai Lu
2013-04-16  2:34                     ` H. Peter Anvin
2013-04-16  2:36                 ` H. Peter Anvin
2013-04-16  2:56                   ` Yinghai Lu
2013-04-16  3:02                     ` H. Peter Anvin
2013-04-16 13:08                       ` Ingo Molnar
2013-04-16 13:27                         ` H. Peter Anvin
2013-04-16 18:08 ` [PATCH v2 0/6] kernel ASLR Kees Cook
2013-04-16 18:15   ` H. Peter Anvin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).