summaryrefslogtreecommitdiffstats
path: root/usr.sbin/mkuboot
diff options
context:
space:
mode:
authorpatrick <patrick@openbsd.org>2013-10-28 09:00:06 +0000
committerpatrick <patrick@openbsd.org>2013-10-28 09:00:06 +0000
commit87c5fb21bd6267fdc702e65c4bc4f0c4a84561cb (patch)
treec308bdf2000bdddee092b90bb964e731e439d41b /usr.sbin/mkuboot
parentinclude string.h for memcpy() (diff)
downloadwireguard-openbsd-87c5fb21bd6267fdc702e65c4bc4f0c4a84561cb.tar.xz
wireguard-openbsd-87c5fb21bd6267fdc702e65c4bc4f0c4a84561cb.zip
Improve mkuboot's ELF handling. This fixes the problem where mkuboot
running on 64-bit systems does not create valid images. While there, append kernel symbols at the end of the kernel. ok syl@
Diffstat (limited to 'usr.sbin/mkuboot')
-rw-r--r--usr.sbin/mkuboot/Makefile3
-rw-r--r--usr.sbin/mkuboot/copy_elf.c236
-rw-r--r--usr.sbin/mkuboot/copy_elf32.c3
-rw-r--r--usr.sbin/mkuboot/copy_elf64.c3
-rw-r--r--usr.sbin/mkuboot/mkuboot.c125
5 files changed, 289 insertions, 81 deletions
diff --git a/usr.sbin/mkuboot/Makefile b/usr.sbin/mkuboot/Makefile
index 50182167520..8533def100c 100644
--- a/usr.sbin/mkuboot/Makefile
+++ b/usr.sbin/mkuboot/Makefile
@@ -1,9 +1,10 @@
-# $OpenBSD: Makefile,v 1.2 2013/09/04 14:54:13 patrick Exp $
+# $OpenBSD: Makefile,v 1.3 2013/10/28 09:00:06 patrick Exp $
.if ${MACHINE} == "armv7"
BINDIR= /usr/sbin
PROG= mkuboot
+SRCS= mkuboot.c copy_elf32.c copy_elf64.c
DPADD= ${LIBZ}
LDADD= -lz
CFLAGS= -DMACHINE_ARCH=\"${MACHINE_ARCH}\"
diff --git a/usr.sbin/mkuboot/copy_elf.c b/usr.sbin/mkuboot/copy_elf.c
new file mode 100644
index 00000000000..1b7c603d49e
--- /dev/null
+++ b/usr.sbin/mkuboot/copy_elf.c
@@ -0,0 +1,236 @@
+/* $OpenBSD: copy_elf.c,v 1.1 2013/10/28 09:00:06 patrick Exp $ */
+
+/*
+ * Copyright (c) 2013 Miodrag Vallat.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <err.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/exec_elf.h>
+
+struct image_header;
+
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+
+extern u_long copy_data(int, const char *, int, const char *, u_long,
+ struct image_header *, Elf_Word);
+u_long copy_mem(void *, int, const char *, u_long, struct image_header *,
+ Elf_Word);
+extern u_long fill_zeroes(int, const char *, u_long, struct image_header *, Elf_Word);
+
+u_long
+ELFNAME(copy_elf)(int ifd, const char *iname, int ofd, const char *oname, u_long crc,
+ struct image_header *ih)
+{
+ ssize_t nbytes;
+ Elf_Ehdr ehdr, elf;
+ Elf_Phdr phdr;
+ Elf_Addr vaddr, ovaddr, svaddr, off, ssym;
+ Elf_Shdr *shp, *wshp;
+ Elf_Addr esym = 0, esymval;
+ int i, sz, havesyms;
+
+ nbytes = read(ifd, &ehdr, sizeof ehdr);
+ if (nbytes == -1)
+ err(1, "%s", iname);
+ if (nbytes != sizeof ehdr)
+ return 0;
+
+ elf = ehdr;
+
+ if (lseek(ifd, (off_t)elf.e_shoff, SEEK_SET) == -1) {
+ err(1, "%s unable to seek to section header", iname);
+ }
+
+ sz = elf.e_shnum * sizeof(Elf_Shdr);
+ shp = calloc(sz, 1);
+ if (read(ifd, shp, sz) != sz) {
+ err(1, "%s: read section headers", iname);
+ }
+ wshp = calloc(sz, 1);
+ memcpy(wshp, shp, sz);
+
+
+ /* first walk the load sections to find the kernel addresses */
+ /* next we walk the sections to find the
+ * location of esym (first address of data space
+ */
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ if (lseek(ifd, ehdr.e_phoff + i * ehdr.e_phentsize, SEEK_SET) ==
+ (off_t)-1)
+ err(1, "%s", iname);
+ if (read(ifd, &phdr, sizeof phdr) != sizeof(phdr))
+ err(1, "%s", iname);
+ /* assumes it loads in incrementing address order */
+ if (phdr.p_type == PT_LOAD)
+ vaddr = phdr.p_vaddr + phdr.p_memsz;
+ }
+
+ /* ok, we need to write the elf header and section header
+ * which contains info about the not yet written section data
+ * however due to crc the data all has to be written in order
+ * which means walking the structures twice once to precompute
+ * the data, once to write the data.
+ */
+ ssym = vaddr;
+ vaddr += roundup((sizeof(Elf_Ehdr) + sz), sizeof(Elf_Addr));
+ off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(Elf_Addr));
+ for (i = 0; i < elf.e_shnum; i++) {
+ if (esym == 0 && shp[i].sh_flags & SHF_WRITE) {
+ esym = shp[i].sh_addr;
+ }
+ if (shp[i].sh_type == SHT_SYMTAB ||
+ shp[i].sh_type == SHT_STRTAB) {
+#ifdef DEBUG
+ fprintf(stderr, "shdr %d %d/%d off %lx\n", i, shp[i].sh_type,
+ roundup(shp[i].sh_size, sizeof(Elf_Addr)), off);
+#endif
+ /* data is at shp[i].sh_offset of len shp[i].sh_size */
+ wshp[i].sh_offset = off;
+ off += roundup(shp[i].sh_size, sizeof(Elf_Addr));
+ vaddr += roundup(shp[i].sh_size, sizeof(Elf_Addr));
+ }
+ }
+ esymval = vaddr;
+#ifdef DEBUG
+ fprintf(stderr, "esymval %lx size %ld\n", esymval, esymval - ssym);
+#endif
+
+ for (i = 0; i < ehdr.e_phnum; i++) {
+#ifdef DEBUG
+ fprintf(stderr, "phdr %d/%d\n", i, ehdr.e_phnum);
+#endif
+ if (lseek(ifd, ehdr.e_phoff + i * ehdr.e_phentsize, SEEK_SET) ==
+ (off_t)-1)
+ err(1, "%s", iname);
+ if (read(ifd, &phdr, sizeof phdr) != sizeof(phdr))
+ err(1, "%s", iname);
+
+#ifdef DEBUG
+ fprintf(stderr, "vaddr %p offset %p filesz %p memsz %p\n",
+ phdr.p_vaddr, phdr.p_offset, phdr.p_filesz, phdr.p_memsz);
+#endif
+ if (i == 0)
+ vaddr = phdr.p_vaddr;
+ else if (vaddr != phdr.p_vaddr) {
+#ifdef DEBUG
+ fprintf(stderr, "gap %p->%p\n", vaddr, phdr.p_vaddr);
+#endif
+ /* fill the gap between the previous phdr if any */
+ crc = fill_zeroes(ofd, oname, crc, ih,
+ phdr.p_vaddr - vaddr);
+ vaddr = phdr.p_vaddr;
+ }
+
+ if (phdr.p_filesz != 0) {
+#ifdef DEBUG
+ fprintf(stderr, "copying %p from infile %p\n",
+ phdr.p_filesz, phdr.p_offset);
+#endif
+ /* esym will be in the data portion of a region */
+ if (esym >= phdr.p_vaddr &&
+ esym < phdr.p_vaddr + phdr.p_filesz) {
+ /* load the region up to the esym
+ * (may be empty)
+ */
+ Elf_Addr loadlen = esym - phdr.p_vaddr;
+
+ if (lseek(ifd, phdr.p_offset, SEEK_SET) ==
+ (off_t)-1)
+ err(1, "%s", iname);
+ crc = copy_data(ifd, iname, ofd, oname, crc,
+ ih, loadlen);
+
+ crc = copy_mem(&esymval, ofd, oname, crc, ih,
+ sizeof(esymval));
+
+ if (lseek(ifd, phdr.p_offset + loadlen +
+ sizeof(esymval), SEEK_SET) == (off_t)-1)
+ err(1, "%s", iname);
+ crc = copy_data(ifd, iname, ofd, oname, crc,
+ ih, phdr.p_filesz - loadlen -
+ sizeof(esymval));
+ } else {
+
+ if (lseek(ifd, phdr.p_offset, SEEK_SET) ==
+ (off_t)-1)
+ err(1, "%s", iname);
+ crc = copy_data(ifd, iname, ofd, oname, crc,
+ ih, phdr.p_filesz);
+ }
+ if (phdr.p_memsz - phdr.p_filesz != 0) {
+#ifdef DEBUG
+ fprintf(stderr, "zeroing %p\n",
+ phdr.p_memsz - phdr.p_filesz);
+#endif
+ crc = fill_zeroes(ofd, oname, crc, ih,
+ phdr.p_memsz - phdr.p_filesz);
+ }
+ ovaddr = vaddr + phdr.p_memsz;
+ } else {
+ ovaddr = vaddr;
+ }
+ /*
+ * If p_filesz == 0, this is likely .bss, which we do not
+ * need to provide. If it's not the last phdr, the gap
+ * filling code will output the necessary zeroes anyway.
+ */
+ vaddr += phdr.p_memsz;
+ }
+
+ vaddr = roundup(vaddr, sizeof(Elf_Addr));
+ if (vaddr != ovaddr) {
+#ifdef DEBUG
+ fprintf(stderr, "gap %p->%p\n", vaddr, phdr.p_vaddr);
+#endif
+ /* fill the gap between the previous phdr if not aligned */
+ crc = fill_zeroes(ofd, oname, crc, ih, vaddr - ovaddr);
+ }
+
+ for (havesyms = i = 0; i < elf.e_shnum; i++)
+ if (shp[i].sh_type == SHT_SYMTAB)
+ havesyms = 1;
+
+ if (havesyms == 0)
+ return crc;
+
+ elf.e_phoff = 0;
+ elf.e_shoff = sizeof(Elf_Ehdr);
+ elf.e_phentsize = 0;
+ elf.e_phnum = 0;
+ crc = copy_mem(&elf, ofd, oname, crc, ih, sizeof(elf));
+ crc = copy_mem(wshp, ofd, oname, crc, ih, sz);
+ off = sizeof(elf) + sz;
+
+ off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(Elf_Addr));
+ for (i = 0; i < elf.e_shnum; i++) {
+ if (shp[i].sh_type == SHT_SYMTAB ||
+ shp[i].sh_type == SHT_STRTAB) {
+ /* data is at shp[i].sh_offset of len shp[i].sh_size */
+ if (lseek(ifd, shp[i].sh_offset, SEEK_SET) == -1) {
+ err(1, "%s", iname);
+ }
+ off += shp[i].sh_size;
+ crc = copy_data(ifd, iname, ofd, oname, crc, ih,
+ shp[i].sh_size);
+ }
+ }
+
+ return crc;
+}
diff --git a/usr.sbin/mkuboot/copy_elf32.c b/usr.sbin/mkuboot/copy_elf32.c
new file mode 100644
index 00000000000..3d1aaf598e8
--- /dev/null
+++ b/usr.sbin/mkuboot/copy_elf32.c
@@ -0,0 +1,3 @@
+/* Public domain - not significant enough to copyright */
+#define ELFSIZE 32
+#include "copy_elf.c"
diff --git a/usr.sbin/mkuboot/copy_elf64.c b/usr.sbin/mkuboot/copy_elf64.c
new file mode 100644
index 00000000000..6e0f294c817
--- /dev/null
+++ b/usr.sbin/mkuboot/copy_elf64.c
@@ -0,0 +1,3 @@
+/* Public domain - not significant enough to copyright */
+#define ELFSIZE 64
+#include "copy_elf.c"
diff --git a/usr.sbin/mkuboot/mkuboot.c b/usr.sbin/mkuboot/mkuboot.c
index 94308cec4f0..a3c95b9da31 100644
--- a/usr.sbin/mkuboot/mkuboot.c
+++ b/usr.sbin/mkuboot/mkuboot.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mkuboot.c,v 1.2 2013/07/28 18:07:16 miod Exp $ */
+/* $OpenBSD: mkuboot.c,v 1.3 2013/10/28 09:00:06 patrick Exp $ */
/*
* Copyright (c) 2008 Mark Kettenis
@@ -70,10 +70,18 @@ struct image_header {
extern char *__progname;
+extern u_long elf32_copy_elf(int, const char *, int, const char *, u_long,
+ struct image_header *);
+extern u_long elf64_copy_elf(int, const char *, int, const char *, u_long,
+ struct image_header *);
+
u_long copy_data(int, const char *, int, const char *, u_long,
struct image_header *, Elf_Word);
-u_long copy_elf(int, const char *, int, const char *, u_long,
+u_long (*copy_elf)(int, const char *, int, const char *, u_long,
struct image_header *);
+
+u_long copy_mem(void *, int, const char *, u_long, struct image_header *,
+ Elf_Word);
u_long copy_raw(int, const char *, int, const char *, u_long,
struct image_header *);
u_long fill_zeroes(int, const char *, u_long, struct image_header *, Elf_Word);
@@ -210,7 +218,7 @@ main(int argc, char *argv[])
ih.ih_arch = mapptr->id;
ih.ih_type = typemapptr->id;
ih.ih_comp = IH_COMP_NONE;
- strlcpy(ih.ih_name, imgname, sizeof ih.ih_name);
+ strlcpy((char *)ih.ih_name, imgname, sizeof ih.ih_name);
ifd = open(iname, O_RDONLY);
if (ifd < 0)
@@ -234,11 +242,11 @@ main(int argc, char *argv[])
if (ih.ih_type == IH_TYPE_SCRIPT) {
/* scripts have two extra words of size/pad */
fsize = htobe32(sb.st_size);
- crc = crc32(crc, (void *)&fsize, sizeof(fsize));
+ crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize));
if (write(ofd, &fsize, sizeof fsize) != sizeof fsize)
err(1, "%s", oname);
fsize = 0;
- crc = crc32(crc, (void *)&fsize, sizeof(fsize));
+ crc = crc32(crc, (Bytef *)&fsize, sizeof(fsize));
if (write(ofd, &fsize, sizeof fsize) != sizeof fsize)
err(1, "%s", oname);
}
@@ -256,7 +264,7 @@ main(int argc, char *argv[])
ih.ih_size = htobe32(ih.ih_size);
/* Calculate header CRC. */
- crc = crc32(0, (void *)&ih, sizeof ih);
+ crc = crc32(0, (Bytef *)&ih, sizeof ih);
ih.ih_hcrc = htobe32(crc);
/* Write finalized header. */
@@ -282,79 +290,16 @@ is_elf(int ifd, const char *iname)
if (lseek(ifd, 0, SEEK_SET) != 0)
err(1, "%s", iname);
-
- return IS_ELF(ehdr);
-}
-
-u_long
-copy_elf(int ifd, const char *iname, int ofd, const char *oname, u_long crc,
- struct image_header *ih)
-{
- ssize_t nbytes;
- Elf_Ehdr ehdr;
- Elf_Phdr phdr;
- Elf_Addr vaddr;
- int i;
-
- nbytes = read(ifd, &ehdr, sizeof ehdr);
- if (nbytes == -1)
- err(1, "%s", iname);
- if (nbytes != sizeof ehdr)
+ if (!IS_ELF(ehdr))
return 0;
- for (i = 0; i < ehdr.e_phnum; i++) {
-#ifdef DEBUG
- fprintf(stderr, "phdr %d/%d\n", i, ehdr.e_phnum);
-#endif
- if (lseek(ifd, ehdr.e_phoff + i * ehdr.e_phentsize, SEEK_SET) ==
- (off_t)-1)
- err(1, "%s", iname);
- if (read(ifd, &phdr, sizeof phdr) != sizeof(phdr))
- err(1, "%s", iname);
-
-#ifdef DEBUG
- fprintf(stderr, "vaddr %p offset %p filesz %p memsz %p\n",
- phdr.p_vaddr, phdr.p_offset, phdr.p_filesz, phdr.p_memsz);
-#endif
- if (i == 0)
- vaddr = phdr.p_vaddr;
- else if (vaddr != phdr.p_vaddr) {
-#ifdef DEBUG
- fprintf(stderr, "gap %p->%p\n", vaddr, phdr.p_vaddr);
-#endif
- /* fill the gap between the previous phdr if any */
- crc = fill_zeroes(ofd, oname, crc, ih,
- phdr.p_vaddr - vaddr);
- vaddr = phdr.p_vaddr;
- }
-
- if (phdr.p_filesz != 0) {
-#ifdef DEBUG
- fprintf(stderr, "copying %p from infile %p\n",
- phdr.p_filesz, phdr.p_offset);
-#endif
- if (lseek(ifd, phdr.p_offset, SEEK_SET) == (off_t)-1)
- err(1, "%s", iname);
- crc = copy_data(ifd, iname, ofd, oname, crc, ih,
- phdr.p_filesz);
- if (phdr.p_memsz - phdr.p_filesz != 0) {
-#ifdef DEBUG
- fprintf(stderr, "zeroing %p\n",
- phdr.p_memsz - phdr.p_filesz);
-#endif
- crc = fill_zeroes(ofd, oname, crc, ih,
- phdr.p_memsz - phdr.p_filesz);
- }
- }
- /*
- * If p_filesz == 0, this is likely .bss, which we do not
- * need to provide. If it's not the last phdr, the gap
- * filling code will output the necessary zeroes anyway.
- */
- vaddr += phdr.p_memsz;
- }
-
- return crc;
+ if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
+ copy_elf = elf32_copy_elf;
+ else if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+ copy_elf = elf64_copy_elf;
+ else
+ err(1, "%s: invalid elf, not 32 or 64 bit", iname);
+ return 1;
}
u_long
@@ -371,7 +316,27 @@ copy_data(int ifd, const char *iname, int ofd, const char *oname, u_long crc,
err(1, "%s", iname);
if (write(ofd, buf, nbytes) != nbytes)
err(1, "%s", oname);
- crc = crc32(crc, buf, nbytes);
+ crc = crc32(crc, (Bytef *)buf, nbytes);
+ ih->ih_size += nbytes;
+ size -= nbytes;
+ }
+
+ return crc;
+}
+
+u_long
+copy_mem(void *mem, int ofd, const char *oname, u_long crc,
+ struct image_header *ih, Elf_Word size)
+{
+ ssize_t nbytes;
+ char *memp = (char *)mem;
+
+ while (size != 0) {
+ nbytes = size > BUFSIZ ? BUFSIZ : size;
+ if (write(ofd, memp, nbytes) != nbytes)
+ err(1, "%s", oname);
+ crc = crc32(crc, (Bytef *)memp, nbytes);
+ memp += nbytes;
ih->ih_size += nbytes;
size -= nbytes;
}
@@ -392,7 +357,7 @@ fill_zeroes(int ofd, const char *oname, u_long crc, struct image_header *ih,
nbytes = write(ofd, buf, chunk);
if (nbytes != chunk)
err(1, "%s", oname);
- crc = crc32(crc, buf, nbytes);
+ crc = crc32(crc, (Bytef *)buf, nbytes);
ih->ih_size += nbytes;
size -= nbytes;
}
@@ -412,7 +377,7 @@ copy_raw(int ifd, const char *iname, int ofd, const char *oname, u_long crc,
err(1, "%s", iname);
if (write(ofd, buf, nbytes) != nbytes)
err(1, "%s", oname);
- crc = crc32(crc, buf, nbytes);
+ crc = crc32(crc, (Bytef *)buf, nbytes);
ih->ih_size += nbytes;
}