[PATCH 02/02] Elf: Align elf notes properly

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



elf: Align elf notes properly

The kernel currently contains several elf note aligment implementations. Most
implementations follow the spec on 32-bit platforms, but none current aligns
the notes correctly on 64-bit platforms. This patch tries to fix this by
interpreting the 64-bit and 32-bit elf specs as the following:

offset bytes name
0      4     n_namesz -+                  -+
4      4     n_descsz  | elf note header   |
8      4     n_type   -+                   | elf note entry size - N4
12     N1    name                          |
N2     N3    desc                         -+

WS = word size in bytes (4 for 32 bit, 8 for 64 bit)
N1 = roundup(n_namesz + sizeof(elf note header), WS) - sizeof(elf note header)
N2 = sizeof(elf note header) + N1
N3 = roundup(n_descsz, WS)
N4 = sizeof(elf note header) + N1 + N2

The elf note header contains three 32-bit values on 32-bit and 64-bit systems. 
The header is followed by name and desc data together with padding. The 
alignment and padding varies depending on the word size.

I base my interpretation on the following:

TIS Elf spec v1.2
http://refspecs.freestandards.org/elf/elf.pdf

- Each elf note entry should be an array of 4-byte words.  (Page 42)
- Name should be terminated with a '\0'                    (Page 42)
- Desc and the next note should be aligned to 32 bits.     (Page 42)
- The example shows that the '\0' is included in n_namesz. (Page 43)

ELF-64 Object File Format, Version 1.5 Draft 2
http://www.busybox.net/cgi-bin/viewcvs.cgi/trunk/docs/elf-64-gen.pdf?rev=15356

- Each elf note entry should be an array of 8-byte words.  (Page 13)
- Name contains a NULL-terminated string.                  (Page 13)
- Desc and the next note should be aligned to 64 bits.     (Page 14)
- "The (name) length does not include the terminating null or the padding"
                                                           (Page 14)

The last line is kind of interesting since it conflicts with the 32-bit
example. I'm ignoring that and treating n_namesz the same regardless of 
word size. So n_namesz is used in the same fashion for both 32-bit and
64-bit platforms in this patch and the calculations above.

This patch fixes the following:

- i386: 32-bit crash notes aligns elf note header to 32-bit size
  This is basically a no-op because 12 is already aligned to 4.
  Use roundup() and sizeof(elf_addr_t).

- mips: The terminating NULL was not included in n_namesz.
  Use roundup(sizeof(elf note header) + n_namesz, sizeof(elf_addr_t)).
  Use sizeof(elf_addr_t).

- powerpc: 32-bit aligment is used regardless of word size.
  Use roundup(sizeof(elf note header) + n_namesz, sizeof(elf_addr_t)).
  Use sizeof(elf_addr_t).
  
- x86_64: 32-bit aligment is used regardless of word size.
  Use roundup(sizeof(elf note header) + n_namesz, sizeof(elf_addr_t)).
  Use sizeof(elf_addr_t).
  
- binfmt_elf / binfmt_elf_fdpic: 32-bit aligment is always used.
  Use roundup(sizeof(elf note header) + n_namesz, sizeof(elf_addr_t)).
  Use sizeof(elf_addr_t).

- kcore: 32-bit aligment is always used, elf_buflen calculation seems wrong.
  Use roundup(sizeof(elf note header) + n_namesz, sizeof(elf_addr_t)).
  Use sizeof(elf_addr_t).

- vmcore: 32-bit aligment is used for both 32-bit and 64-bit code.
  Use roundup(sizeof(elf note header) + n_namesz, sizeof(elf_addr_t)).
  Use sizeof(elf_addr_t).

Signed-off-by: Magnus Damm <[email protected]>
---

 Applies to 2.6.19-rc4.

 arch/i386/kernel/crash.c    |   16 ++++++++--------
 arch/mips/kernel/irixelf.c  |   12 ++++++------
 arch/powerpc/kernel/crash.c |   16 ++++++++--------
 arch/x86_64/kernel/crash.c  |   18 +++++++++---------
 fs/binfmt_elf.c             |   11 ++++++-----
 fs/binfmt_elf_fdpic.c       |   10 +++++-----
 fs/proc/kcore.c             |   26 ++++++++++++++------------
 fs/proc/vmcore.c            |   11 +++++------
 8 files changed, 61 insertions(+), 59 deletions(-)

--- 0002/arch/i386/kernel/crash.c
+++ work/arch/i386/kernel/crash.c	2006-11-02 16:59:52.000000000 +0900
@@ -31,7 +31,8 @@
 /* This keeps a track of which one is crashing cpu. */
 static int crashing_cpu;
 
-static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
+static unsigned char *
+append_elf_note(unsigned char *buf, char *name, unsigned type, void *data,
 							       size_t data_len)
 {
 	struct elf_note note;
@@ -40,16 +41,15 @@ static u32 *append_elf_note(u32 *buf, ch
 	note.n_descsz = data_len;
 	note.n_type   = type;
 	memcpy(buf, &note, sizeof(note));
-	buf += (sizeof(note) +3)/4;
-	memcpy(buf, name, note.n_namesz);
-	buf += (note.n_namesz + 3)/4;
+	memcpy(buf + sizeof(note), name, note.n_namesz);
+	buf += roundup(sizeof(note) + note.n_namesz, sizeof(elf_addr_t));
 	memcpy(buf, data, note.n_descsz);
-	buf += (note.n_descsz + 3)/4;
+	buf += roundup(note.n_descsz, sizeof(elf_addr_t));
 
 	return buf;
 }
 
-static void final_note(u32 *buf)
+static void final_note(unsigned char *buf)
 {
 	struct elf_note note;
 
@@ -62,7 +62,7 @@ static void final_note(u32 *buf)
 static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
 {
 	struct elf_prstatus prstatus;
-	u32 *buf;
+	unsigned char *buf;
 
 	if ((cpu < 0) || (cpu >= NR_CPUS))
 		return;
@@ -74,7 +74,7 @@ static void crash_save_this_cpu(struct p
 	 * squirrelled away.  ELF notes happen to provide
 	 * all of that, so there is no need to invent something new.
 	 */
-	buf = (u32*)per_cpu_ptr(crash_notes, cpu);
+	buf = (unsigned char *)per_cpu_ptr(crash_notes, cpu);
 	if (!buf)
 		return;
 	memset(&prstatus, 0, sizeof(prstatus));
--- 0003/arch/mips/kernel/irixelf.c
+++ work/arch/mips/kernel/irixelf.c	2006-11-02 16:59:52.000000000 +0900
@@ -1008,9 +1008,9 @@ static int notesize(struct memelfnote *e
 {
 	int sz;
 
-	sz = sizeof(struct elf_note);
-	sz += roundup(strlen(en->name), 4);
-	sz += roundup(en->datasz, 4);
+	sz = roundup(sizeof(struct elf_note) + strlen(en->name) + 1, 
+		     sizeof(elf_addr_t));
+	sz += roundup(en->datasz, sizeof(elf_addr_t));
 
 	return sz;
 }
@@ -1028,16 +1028,16 @@ static int writenote(struct memelfnote *
 {
 	struct elf_note en;
 
-	en.n_namesz = strlen(men->name);
+	en.n_namesz = strlen(men->name) + 1;
 	en.n_descsz = men->datasz;
 	en.n_type = men->type;
 
 	DUMP_WRITE(&en, sizeof(en));
 	DUMP_WRITE(men->name, en.n_namesz);
 	/* XXX - cast from long long to long to avoid need for libgcc.a */
-	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
+	DUMP_SEEK(roundup((unsigned long)file->f_pos, sizeof(elf_addr_t)));
 	DUMP_WRITE(men->data, men->datasz);
-	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
+	DUMP_SEEK(roundup((unsigned long)file->f_pos, sizeof(elf_addr_t)));
 
 	return 1;
 
--- 0001/arch/powerpc/kernel/crash.c
+++ work/arch/powerpc/kernel/crash.c	2006-11-02 16:59:52.000000000 +0900
@@ -46,7 +46,8 @@ int crashing_cpu = -1;
 static cpumask_t cpus_in_crash = CPU_MASK_NONE;
 cpumask_t cpus_in_sr = CPU_MASK_NONE;
 
-static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
+static unsigned char *
+append_elf_note(unsigned char *buf, char *name, unsigned type, void *data,
 							       size_t data_len)
 {
 	struct elf_note note;
@@ -55,16 +56,15 @@ static u32 *append_elf_note(u32 *buf, ch
 	note.n_descsz = data_len;
 	note.n_type   = type;
 	memcpy(buf, &note, sizeof(note));
-	buf += (sizeof(note) +3)/4;
-	memcpy(buf, name, note.n_namesz);
-	buf += (note.n_namesz + 3)/4;
+	memcpy(buf + sizeof(note), name, note.n_namesz);
+	buf += roundup(sizeof(note) + note.n_namesz, sizeof(elf_addr_t));
 	memcpy(buf, data, note.n_descsz);
-	buf += (note.n_descsz + 3)/4;
+	buf += roundup(note.n_descsz, sizeof(elf_addr_t));
 
 	return buf;
 }
 
-static void final_note(u32 *buf)
+static void final_note(unsigned char *buf)
 {
 	struct elf_note note;
 
@@ -77,7 +77,7 @@ static void final_note(u32 *buf)
 static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
 {
 	struct elf_prstatus prstatus;
-	u32 *buf;
+	unsigned char *buf;
 
 	if ((cpu < 0) || (cpu >= NR_CPUS))
 		return;
@@ -89,7 +89,7 @@ static void crash_save_this_cpu(struct p
 	 * squirrelled away.  ELF notes happen to provide
 	 * all of that that no need to invent something new.
 	 */
-	buf = (u32*)per_cpu_ptr(crash_notes, cpu);
+	buf = (unsigned char *)per_cpu_ptr(crash_notes, cpu);
 	if (!buf) 
 		return;
 
--- 0002/arch/x86_64/kernel/crash.c
+++ work/arch/x86_64/kernel/crash.c	2006-11-02 16:59:52.000000000 +0900
@@ -28,8 +28,9 @@
 /* This keeps a track of which one is crashing cpu. */
 static int crashing_cpu;
 
-static u32 *append_elf_note(u32 *buf, char *name, unsigned type,
-						void *data, size_t data_len)
+static unsigned char *
+append_elf_note(unsigned char *buf, char *name, unsigned type, void *data,
+							       size_t data_len)
 {
 	struct elf_note note;
 
@@ -37,16 +38,15 @@ static u32 *append_elf_note(u32 *buf, ch
 	note.n_descsz = data_len;
 	note.n_type   = type;
 	memcpy(buf, &note, sizeof(note));
-	buf += (sizeof(note) +3)/4;
-	memcpy(buf, name, note.n_namesz);
-	buf += (note.n_namesz + 3)/4;
+	memcpy(buf + sizeof(note), name, note.n_namesz);
+	buf += roundup(sizeof(note) + note.n_namesz, sizeof(elf_addr_t));
 	memcpy(buf, data, note.n_descsz);
-	buf += (note.n_descsz + 3)/4;
+	buf += roundup(note.n_descsz, sizeof(elf_addr_t));
 
 	return buf;
 }
 
-static void final_note(u32 *buf)
+static void final_note(unsigned char *buf)
 {
 	struct elf_note note;
 
@@ -59,7 +59,7 @@ static void final_note(u32 *buf)
 static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
 {
 	struct elf_prstatus prstatus;
-	u32 *buf;
+	unsigned char *buf;
 
 	if ((cpu < 0) || (cpu >= NR_CPUS))
 		return;
@@ -72,7 +72,7 @@ static void crash_save_this_cpu(struct p
 	 * all of that, no need to invent something new.
 	 */
 
-	buf = (u32*)per_cpu_ptr(crash_notes, cpu);
+	buf = (unsigned char *)per_cpu_ptr(crash_notes, cpu);
 
 	if (!buf)
 		return;
--- 0003/fs/binfmt_elf.c
+++ work/fs/binfmt_elf.c	2006-11-02 16:59:52.000000000 +0900
@@ -1204,9 +1204,9 @@ static int notesize(struct memelfnote *e
 {
 	int sz;
 
-	sz = sizeof(struct elf_note);
-	sz += roundup(strlen(en->name) + 1, 4);
-	sz += roundup(en->datasz, 4);
+	sz = roundup(sizeof(struct elf_note) + strlen(en->name) + 1, 
+		     sizeof(elf_addr_t));
+	sz += roundup(en->datasz, sizeof(elf_addr_t));
 
 	return sz;
 }
@@ -1216,8 +1216,9 @@ static int notesize(struct memelfnote *e
 
 static int alignfile(struct file *file, loff_t *foffset)
 {
-	static const char buf[4] = { 0, };
-	DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset);
+	static const char buf[sizeof(elf_addr_t)] = { 0, };
+	DUMP_WRITE(buf, roundup(*foffset, 
+				sizeof(elf_addr_t)) - *foffset, foffset);
 	return 1;
 }
 
--- 0003/fs/binfmt_elf_fdpic.c
+++ work/fs/binfmt_elf_fdpic.c	2006-11-02 16:59:52.000000000 +0900
@@ -1220,9 +1220,9 @@ static int notesize(struct memelfnote *e
 {
 	int sz;
 
-	sz = sizeof(struct elf_note);
-	sz += roundup(strlen(en->name) + 1, 4);
-	sz += roundup(en->datasz, 4);
+	sz = roundup(sizeof(struct elf_note) + strlen(en->name) + 1, 
+		     sizeof(elf_addr_t));
+	sz += roundup(en->datasz, sizeof(elf_addr_t));
 
 	return sz;
 }
@@ -1245,9 +1245,9 @@ static int writenote(struct memelfnote *
 	DUMP_WRITE(&en, sizeof(en));
 	DUMP_WRITE(men->name, en.n_namesz);
 	/* XXX - cast from long long to long to avoid need for libgcc.a */
-	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
+	DUMP_SEEK(roundup((unsigned long)file->f_pos, sizeof(elf_addr_t)));
 	DUMP_WRITE(men->data, men->datasz);
-	DUMP_SEEK(roundup((unsigned long)file->f_pos, 4));	/* XXX */
+	DUMP_SEEK(roundup((unsigned long)file->f_pos, sizeof(elf_addr_t)));
 
 	return 1;
 }
--- 0002/fs/proc/kcore.c
+++ work/fs/proc/kcore.c	2006-11-02 16:59:52.000000000 +0900
@@ -22,6 +22,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
+#define CORE_STR "CORE"
 
 static int open_kcore(struct inode * inode, struct file * filp)
 {
@@ -82,10 +83,11 @@ static size_t get_kcore_size(int *nphdr,
 	}
 	*elf_buflen =	sizeof(struct elfhdr) + 
 			(*nphdr + 2)*sizeof(struct elf_phdr) + 
-			3 * (sizeof(struct elf_note) + 4) +
-			sizeof(struct elf_prstatus) +
-			sizeof(struct elf_prpsinfo) +
-			sizeof(struct task_struct);
+		3 * roundup(sizeof(struct elf_note) + strlen(CORE_STR) + 1, 
+			    sizeof(elf_addr_t)) +
+		roundup(sizeof(struct elf_prstatus), sizeof(elf_addr_t)) +
+		roundup(sizeof(struct elf_prpsinfo), sizeof(elf_addr_t)) +
+		roundup(sizeof(struct task_struct), sizeof(elf_addr_t));
 	*elf_buflen = PAGE_ALIGN(*elf_buflen);
 	return size + *elf_buflen;
 }
@@ -99,9 +101,9 @@ static int notesize(struct memelfnote *e
 {
 	int sz;
 
-	sz = sizeof(struct elf_note);
-	sz += roundup((strlen(en->name) + 1), 4);
-	sz += roundup(en->datasz, 4);
+	sz = roundup(sizeof(struct elf_note) + strlen(en->name) + 1, 
+		     sizeof(elf_addr_t));
+	sz += roundup(en->datasz, sizeof(elf_addr_t));
 
 	return sz;
 } /* end notesize() */
@@ -124,9 +126,9 @@ static char *storenote(struct memelfnote
 	DUMP_WRITE(men->name, en.n_namesz);
 
 	/* XXX - cast from long long to long to avoid need for libgcc.a */
-	bufp = (char*) roundup((unsigned long)bufp,4);
+	bufp = (char*) roundup((unsigned long)bufp, sizeof(elf_addr_t));
 	DUMP_WRITE(men->data, men->datasz);
-	bufp = (char*) roundup((unsigned long)bufp,4);
+	bufp = (char*) roundup((unsigned long)bufp, sizeof(elf_addr_t));
 
 #undef DUMP_WRITE
 
@@ -210,7 +212,7 @@ static void elf_kcore_store_hdr(char *bu
 	nhdr->p_offset	= offset;
 
 	/* set up the process status */
-	notes[0].name = "CORE";
+	notes[0].name = CORE_STR;
 	notes[0].type = NT_PRSTATUS;
 	notes[0].datasz = sizeof(struct elf_prstatus);
 	notes[0].data = &prstatus;
@@ -221,7 +223,7 @@ static void elf_kcore_store_hdr(char *bu
 	bufp = storenote(&notes[0], bufp);
 
 	/* set up the process info */
-	notes[1].name	= "CORE";
+	notes[1].name	= CORE_STR;
 	notes[1].type	= NT_PRPSINFO;
 	notes[1].datasz	= sizeof(struct elf_prpsinfo);
 	notes[1].data	= &prpsinfo;
@@ -238,7 +240,7 @@ static void elf_kcore_store_hdr(char *bu
 	bufp = storenote(&notes[1], bufp);
 
 	/* set up the task structure */
-	notes[2].name	= "CORE";
+	notes[2].name	= CORE_STR;
 	notes[2].type	= NT_TASKSTRUCT;
 	notes[2].datasz	= sizeof(struct task_struct);
 	notes[2].data	= current;
--- 0001/fs/proc/vmcore.c
+++ work/fs/proc/vmcore.c	2006-11-02 17:01:12.000000000 +0900
@@ -7,6 +7,7 @@
  *
  */
 
+#include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/user.h>
@@ -255,9 +256,8 @@ static int __init merge_note_headers_elf
 		for (j = 0; j < max_sz; j += sz) {
 			if (nhdr_ptr->n_namesz == 0)
 				break;
-			sz = sizeof(Elf64_Nhdr) +
-				((nhdr_ptr->n_namesz + 3) & ~3) +
-				((nhdr_ptr->n_descsz + 3) & ~3);
+			sz = roundup(sizeof(Elf64_Nhdr) + nhdr_ptr->n_namesz, 
+				     8) + roundup(nhdr_ptr->n_descsz, 8);
 			real_sz += sz;
 			nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
 		}
@@ -336,9 +336,8 @@ static int __init merge_note_headers_elf
 		for (j = 0; j < max_sz; j += sz) {
 			if (nhdr_ptr->n_namesz == 0)
 				break;
-			sz = sizeof(Elf32_Nhdr) +
-				((nhdr_ptr->n_namesz + 3) & ~3) +
-				((nhdr_ptr->n_descsz + 3) & ~3);
+			sz = roundup(sizeof(Elf32_Nhdr) + nhdr_ptr->n_namesz, 
+				     4) + roundup(nhdr_ptr->n_descsz, 4);
 			real_sz += sz;
 			nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
 		}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux