summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/Makefile4
-rw-r--r--usr.sbin/rdsetroot/Makefile7
-rw-r--r--usr.sbin/rdsetroot/elf32.c3
-rw-r--r--usr.sbin/rdsetroot/elf64.c3
-rw-r--r--usr.sbin/rdsetroot/elfrd_size.c396
-rw-r--r--usr.sbin/rdsetroot/rdsetroot.854
-rw-r--r--usr.sbin/rdsetroot/rdsetroot.c204
-rw-r--r--usr.sbin/rdsetroot/rdsetroot.h13
8 files changed, 682 insertions, 2 deletions
diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile
index f62cc04e093..e8869d618ce 100644
--- a/usr.sbin/Makefile
+++ b/usr.sbin/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.204 2019/01/26 10:59:30 florian Exp $
+# $OpenBSD: Makefile,v 1.205 2019/04/05 21:07:11 deraadt Exp $
.include <bsd.own.mk>
@@ -13,7 +13,7 @@ SUBDIR= ac accton acme-client acpidump adduser amd apm apmd arp \
npppctl npppd nsd ntpd ocspcheck ospfctl ospfd ospf6d ospf6ctl \
pcidump pkg_add portmap pppd procmap pstat pwd_mkdb \
quot quotaon ractl rad radiusctl radiusd rarpd rbootd \
- rcctl rdate rebound relayctl relayd repquota ripctl ripd \
+ rcctl rdate rdsetroot rebound relayctl relayd repquota ripctl ripd \
rmt route6d rpc.bootparamd rpc.lockd rpc.statd \
sa sasyncd sensorsd slaacctl slowcgi smtpd \
snmpctl snmpd spamdb switchctl switchd syslogc syslogd sysmerge \
diff --git a/usr.sbin/rdsetroot/Makefile b/usr.sbin/rdsetroot/Makefile
new file mode 100644
index 00000000000..eb9059ab556
--- /dev/null
+++ b/usr.sbin/rdsetroot/Makefile
@@ -0,0 +1,7 @@
+# $OpenBSD: Makefile,v 1.1 2019/04/05 21:07:11 deraadt Exp $
+
+PROG= rdsetroot
+MAN= rdsetroot.8
+SRCS= rdsetroot.c elf32.c elf64.c
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/rdsetroot/elf32.c b/usr.sbin/rdsetroot/elf32.c
new file mode 100644
index 00000000000..4b303b5135f
--- /dev/null
+++ b/usr.sbin/rdsetroot/elf32.c
@@ -0,0 +1,3 @@
+/* $OpenBSD: elf32.c,v 1.1 2019/04/05 21:07:11 deraadt Exp $ */
+#define ELFSIZE 32
+#include "elfrd_size.c"
diff --git a/usr.sbin/rdsetroot/elf64.c b/usr.sbin/rdsetroot/elf64.c
new file mode 100644
index 00000000000..3f453fd586e
--- /dev/null
+++ b/usr.sbin/rdsetroot/elf64.c
@@ -0,0 +1,3 @@
+/* $OpenBSD: elf64.c,v 1.1 2019/04/05 21:07:11 deraadt Exp $ */
+#define ELFSIZE 64
+#include "elfrd_size.c"
diff --git a/usr.sbin/rdsetroot/elfrd_size.c b/usr.sbin/rdsetroot/elfrd_size.c
new file mode 100644
index 00000000000..1a9755990c4
--- /dev/null
+++ b/usr.sbin/rdsetroot/elfrd_size.c
@@ -0,0 +1,396 @@
+/* $OpenBSD: elfrd_size.c,v 1.1 2019/04/05 21:07:11 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ * Copyright (c) 1997 Per Fogelstrom. (ELF modifications)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <elf.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <nlist.h>
+#include <err.h>
+
+#include <errno.h>
+#include <limits.h>
+
+#include "rdsetroot.h"
+
+void
+ELFNAME(locate_image)(int, struct elfhdr *, char *, long *, long *, off_t *,
+ size_t *);
+int
+ELFNAME(find_rd_root_image)(char *, int, Elf_Phdr *, int, long *, long *,
+ off_t *, size_t *);
+int
+ELFNAME(nlist)(int, struct nlist *);
+
+struct elf_fn ELFDEFNNAME(fn) =
+{
+ ELFNAME(locate_image),
+ ELFNAME(find_rd_root_image)
+};
+
+void
+ELFNAME(locate_image)(int fd, struct elfhdr *ghead, char *file,
+ long *prd_root_size_off, long *prd_root_image_off, off_t *pmmap_off,
+ size_t *pmmap_size)
+{
+ int n;
+ int found = 0;
+ size_t phsize;
+ Elf_Ehdr head;
+
+ Elf_Phdr *ph;
+
+ /* elfhdr may not have the full header? */
+ lseek(fd, 0, SEEK_SET);
+
+ if (read(fd, &head, sizeof(head)) != sizeof(head))
+ err(1, "can't read phdr area");
+
+ phsize = head.e_phnum * sizeof(Elf_Phdr);
+ if ((ph = malloc(phsize)) == NULL)
+ err(1, "malloc");
+
+ lseek(fd, head.e_phoff, SEEK_SET);
+
+ if (read(fd, ph, phsize) != phsize)
+ err(1, "can't read phdr area");
+
+ for (n = 0; n < head.e_phnum && !found; n++) {
+ if (ph[n].p_type == PT_LOAD)
+ found = ELFNAME(find_rd_root_image)(file, fd, &ph[n],
+ n, prd_root_size_off, prd_root_image_off,
+ pmmap_off, pmmap_size);
+ }
+ if (!found)
+ errx(1, "can't locate space for rd_root_image!");
+ free(ph);
+}
+
+struct nlist ELFNAME(wantsyms)[] = {
+ { "_rd_root_size", 0 },
+ { "_rd_root_image", 0 },
+ { NULL, 0 }
+};
+
+int
+ELFNAME(find_rd_root_image)(char *file, int fd, Elf_Phdr *ph, int segment,
+ long *prd_root_size_off, long *prd_root_image_off, off_t *pmmap_off,
+ size_t *pmmap_size)
+{
+ unsigned long kernel_start, kernel_size;
+ uint64_t rd_root_size_off, rd_root_image_off;
+
+ if (ELFNAME(nlist)(fd, ELFNAME(wantsyms)))
+ errx(1, "no rd_root_image symbols?");
+ kernel_start = ph->p_paddr;
+ kernel_size = ph->p_filesz;
+
+ rd_root_size_off = ELFNAME(wantsyms)[0].n_value - kernel_start;
+ if (rd_root_size_off < (ph->p_vaddr - ph->p_paddr))
+ return (0);
+ rd_root_size_off -= (ph->p_vaddr - ph->p_paddr);
+
+ rd_root_image_off = ELFNAME(wantsyms)[1].n_value - kernel_start;
+ if (rd_root_image_off < (ph->p_vaddr - ph->p_paddr))
+ return (0);
+ rd_root_image_off -= (ph->p_vaddr - ph->p_paddr);
+
+ if (debug) {
+ fprintf(stderr, "segment %d rd_root_size_off = 0x%llx\n", segment,
+ rd_root_size_off);
+ if ((ph->p_vaddr - ph->p_paddr) != 0)
+ fprintf(stderr, "root_off v %zx p %zx, diff %zx altered %llx\n",
+ (size_t)ph->p_vaddr, (size_t)ph->p_paddr,
+ (size_t)(ph->p_vaddr - ph->p_paddr),
+ rd_root_size_off - (ph->p_vaddr - ph->p_paddr));
+ fprintf(stderr, "rd_root_image_off = 0x%llx\n", rd_root_image_off);
+ }
+
+ /*
+ * Sanity check locations of db_* symbols
+ */
+ if (rd_root_image_off >= kernel_size)
+ return (0);
+ if (rd_root_size_off >= kernel_size)
+ errx(1, "rd_root_size not in data segment?");
+ *pmmap_off = ph->p_offset;
+ *pmmap_size = kernel_size;
+ *prd_root_size_off = rd_root_size_off;
+ *prd_root_image_off = rd_root_image_off;
+ return (1);
+}
+
+/*
+ * __elf_is_okay__ - Determine if ehdr really
+ * is ELF and valid for the target platform.
+ *
+ * WARNING: This is NOT a ELF ABI function and
+ * as such its use should be restricted.
+ */
+int
+ELFNAME(__elf_is_okay__)(Elf_Ehdr *ehdr)
+{
+ int retval = 0;
+ /*
+ * We need to check magic, class size, endianess,
+ * and version before we look at the rest of the
+ * Elf_Ehdr structure. These few elements are
+ * represented in a machine independent fashion.
+ */
+ if (IS_ELF(*ehdr) &&
+ ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
+ ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
+
+#if 0 /* allow cross, no arch check */
+ /* Now check the machine dependent header */
+ if (ehdr->e_machine == ELF_TARG_MACH &&
+ ehdr->e_version == ELF_TARG_VER)
+#endif
+ retval = 1;
+ }
+
+ return retval;
+}
+
+#define ISLAST(p) (p->n_name == 0 || p->n_name[0] == 0)
+#define MIN(x, y) ((x)<(y)? (x) : (y))
+
+
+int
+ELFNAME(nlist)(int fd, struct nlist *list)
+{
+ struct nlist *p;
+ caddr_t strtab;
+ Elf_Off symoff = 0, symstroff = 0;
+ Elf_Word symsize = 0;
+ long symstrsize = 0;
+ Elf_Sword nent, cc, i;
+ Elf_Sym sbuf[1024];
+ Elf_Sym *s;
+ Elf_Ehdr ehdr;
+ Elf_Shdr *shdr = NULL;
+ size_t shdr_size;
+ struct stat st;
+ int usemalloc = 0;
+ size_t left, len;
+
+ /* Make sure obj is OK */
+ if (pread(fd, &ehdr, sizeof(Elf_Ehdr), (off_t)0) != sizeof(Elf_Ehdr) ||
+ !ELFNAME(__elf_is_okay__)(&ehdr) || fstat(fd, &st) < 0)
+ return (-1);
+
+ /* calculate section header table size */
+ shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
+
+ /* Make sure it's not too big to mmap */
+ if (SIZE_MAX - ehdr.e_shoff < shdr_size ||
+ (S_ISREG(st.st_mode) && ehdr.e_shoff + shdr_size > st.st_size)) {
+ errno = EFBIG;
+ return (-1);
+ }
+
+ /* mmap section header table */
+ shdr = (Elf_Shdr *)mmap(NULL, (size_t)shdr_size, PROT_READ,
+ MAP_SHARED|MAP_FILE, fd, (off_t) ehdr.e_shoff);
+ if (shdr == MAP_FAILED) {
+ usemalloc = 1;
+ if ((shdr = malloc(shdr_size)) == NULL)
+ return (-1);
+
+ if (pread(fd, shdr, shdr_size, (off_t)ehdr.e_shoff) !=
+ shdr_size) {
+ free(shdr);
+ return (-1);
+ }
+ }
+
+ /*
+ * Find the symbol table entry and its corresponding
+ * string table entry. Version 1.1 of the ABI states
+ * that there is only one symbol table but that this
+ * could change in the future.
+ */
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB) {
+ if (shdr[i].sh_link >= ehdr.e_shnum)
+ continue;
+ symoff = shdr[i].sh_offset;
+ symsize = shdr[i].sh_size;
+ symstroff = shdr[shdr[i].sh_link].sh_offset;
+ symstrsize = shdr[shdr[i].sh_link].sh_size;
+ break;
+ }
+ }
+
+ /* Flush the section header table */
+ if (usemalloc)
+ free(shdr);
+ else
+ munmap((caddr_t)shdr, shdr_size);
+
+ /*
+ * clean out any left-over information for all valid entries.
+ * Type and value defined to be 0 if not found; historical
+ * versions cleared other and desc as well. Also figure out
+ * the largest string length so don't read any more of the
+ * string table than we have to.
+ *
+ * XXX clearing anything other than n_type and n_value violates
+ * the semantics given in the man page.
+ */
+ nent = 0;
+ for (p = list; !ISLAST(p); ++p) {
+ p->n_type = 0;
+ p->n_other = 0;
+ p->n_desc = 0;
+ p->n_value = 0;
+ ++nent;
+ }
+
+ /* Don't process any further if object is stripped. */
+ /* ELFism - dunno if stripped by looking at header */
+ if (symoff == 0)
+ return nent;
+
+ /* Check for files too large to mmap. */
+ if (SIZE_MAX - symstrsize < symstroff ||
+ (S_ISREG(st.st_mode) && symstrsize + symstroff > st.st_size)) {
+ errno = EFBIG;
+ return (-1);
+ }
+
+ /*
+ * Map string table into our address space. This gives us
+ * an easy way to randomly access all the strings, without
+ * making the memory allocation permanent as with malloc/free
+ * (i.e., munmap will return it to the system).
+ */
+ if (usemalloc) {
+ if ((strtab = malloc(symstrsize)) == NULL)
+ return (-1);
+ if (pread(fd, strtab, symstrsize, (off_t)symstroff) !=
+ symstrsize) {
+ free(strtab);
+ return (-1);
+ }
+ } else {
+ strtab = mmap(NULL, (size_t)symstrsize, PROT_READ,
+ MAP_SHARED|MAP_FILE, fd, (off_t) symstroff);
+ if (strtab == MAP_FAILED)
+ return (-1);
+ }
+
+ while (symsize >= sizeof(Elf_Sym)) {
+ cc = MIN(symsize, sizeof(sbuf));
+ if (pread(fd, sbuf, cc, (off_t)symoff) != cc)
+ break;
+ symsize -= cc;
+ symoff += cc;
+ for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) {
+ Elf_Word soff = s->st_name;
+
+ if (soff == 0 || soff >= symstrsize)
+ continue;
+ left = symstrsize - soff;
+
+ for (p = list; !ISLAST(p); p++) {
+ char *sym;
+
+ /*
+ * First we check for the symbol as it was
+ * provided by the user. If that fails
+ * and the first char is an '_', skip over
+ * the '_' and try again.
+ * XXX - What do we do when the user really
+ * wants '_foo' and there are symbols
+ * for both 'foo' and '_foo' in the
+ * table and 'foo' is first?
+ */
+ sym = p->n_name;
+ len = strlen(sym);
+
+ if ((len >= left ||
+ strcmp(&strtab[soff], sym) != 0) &&
+ (sym[0] != '_' || len - 1 >= left ||
+ strcmp(&strtab[soff], sym + 1) != 0))
+ continue;
+
+ p->n_value = s->st_value;
+
+ /* XXX - type conversion */
+ /* is pretty rude. */
+ switch (ELF_ST_TYPE(s->st_info)) {
+ case STT_NOTYPE:
+ switch (s->st_shndx) {
+ case SHN_UNDEF:
+ p->n_type = N_UNDF;
+ break;
+ case SHN_ABS:
+ p->n_type = N_ABS;
+ break;
+ case SHN_COMMON:
+ p->n_type = N_COMM;
+ break;
+ default:
+ p->n_type = N_COMM | N_EXT;
+ break;
+ }
+ break;
+ case STT_OBJECT:
+ p->n_type = N_DATA;
+ break;
+ case STT_FUNC:
+ p->n_type = N_TEXT;
+ break;
+ case STT_FILE:
+ p->n_type = N_FN;
+ break;
+ }
+ if (ELF_ST_BIND(s->st_info) == STB_LOCAL)
+ p->n_type = N_EXT;
+ p->n_desc = 0;
+ p->n_other = 0;
+ if (--nent <= 0)
+ break;
+ }
+ }
+ }
+ if (usemalloc)
+ free(strtab);
+ else
+ munmap(strtab, symstrsize);
+ return (nent);
+}
diff --git a/usr.sbin/rdsetroot/rdsetroot.8 b/usr.sbin/rdsetroot/rdsetroot.8
new file mode 100644
index 00000000000..8bcf2038260
--- /dev/null
+++ b/usr.sbin/rdsetroot/rdsetroot.8
@@ -0,0 +1,54 @@
+.\" $OpenBSD: rdsetroot.8,v 1.1 2019/04/05 21:07:11 deraadt Exp $
+.\"
+.\" Copyright (c) 2019 Theo de Raadt
+.\"
+.\" 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.
+.\"
+.Dd $Mdocdate: April 5 2019 $
+.Dt RDSETROOT 8
+.Os
+.Sh NAME
+.Nm rdsetroot
+.Nd insert disk image into RAMDISK kernel
+.Sh SYNOPSIS
+.Nm rdsetroot
+.Op Fl dx
+.Ar kernel
+.Op Ar disk.fs
+.Sh DESCRIPTION
+The
+.Nm
+utility inserts the file
+.Ar disk.fs
+into the reserved space inside a RAMDISK kernel.
+If
+.Ar disk.fs
+is not specified,
+.Nm
+reads from standard input.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl d
+Debug.
+.It Fl x
+Rather than inserting, extract the
+.Ar disk.fs
+image.
+The disk can be made accessable using
+.Xr vnconfig 8 ,
+filesystems can be manipulated, and finally re-inserted into the RAMDISK kernel.
+.Sh SEE ALSO
+.Xr config 8 ,
+.Xr disklabel 8 ,
+.Xr vnconfig 8 \ No newline at end of file
diff --git a/usr.sbin/rdsetroot/rdsetroot.c b/usr.sbin/rdsetroot/rdsetroot.c
new file mode 100644
index 00000000000..ef3101e3329
--- /dev/null
+++ b/usr.sbin/rdsetroot/rdsetroot.c
@@ -0,0 +1,204 @@
+/* $OpenBSD: rdsetroot.c,v 1.1 2019/04/05 21:07:11 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1994 Gordon W. Ross
+ * Copyright (c) 1997 Per Fogelstrom. (ELF modifications)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copy a ramdisk image into the space reserved for it.
+ * Kernel variables: rd_root_size, rd_root_image
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <elf.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+
+#include "rdsetroot.h"
+
+struct elfhdr head;
+
+/* Offsets relative to start of data segment. */
+long rd_root_image_off, rd_root_size_off;
+
+/* value in the location at rd_root_size_off */
+off_t rd_root_size_val;
+
+/* pointers to pieces of mapped file */
+char *dataseg;
+
+/* parameters to mmap digged out from program header */
+off_t mmap_off;
+size_t mmap_size;
+
+__dead void usage(void);
+
+int debug;
+
+struct elf_fn *elf_fn;
+
+int
+main(int argc, char *argv[])
+{
+ int ch, kfd, n, xflag = 0, fsfd;
+ char *fs = NULL;
+ char *kernel;
+ u_int32_t *ip;
+
+ while ((ch = getopt(argc, argv, "dx")) != -1) {
+ switch (ch) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'x':
+ xflag = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 1)
+ kernel = argv[0];
+ else if (argc == 2) {
+ kernel = argv[0];
+ fs = argv[1];
+ } else
+ usage();
+
+ kfd = open(kernel, xflag ? O_RDONLY : O_RDWR, 0644);
+ if (kfd < 0)
+ err(1, "%s", kernel);
+
+ if (fs) {
+ if (xflag)
+ fsfd = open(fs, O_RDWR | O_CREAT | O_TRUNC, 0644);
+ else
+ fsfd = open(fs, O_RDONLY, 0644);
+ } else {
+ if (xflag)
+ fsfd = dup(STDOUT_FILENO);
+ else
+ fsfd = dup(STDIN_FILENO);
+ }
+ if (fsfd < 0)
+ err(1, "%s", fs);
+
+ if (pledge("stdio", NULL) == -1)
+ err(1, "pledge");
+
+ n = read(kfd, &head, sizeof(head));
+ if (n < sizeof(head))
+ err(1, "%s: reading header", kernel);
+
+ if (!IS_ELF(head))
+ err(1, "%s: bad magic number", kernel);
+
+ if (head.e_ident[EI_CLASS] == ELFCLASS32) {
+ elf_fn = &ELF32_fn;
+ } else if (head.e_ident[EI_CLASS] == ELFCLASS64) {
+ elf_fn = &ELF64_fn;
+ } else {
+ fprintf(stderr, "%s: invalid elf, not 32 or 64 bit", kernel);
+ exit(1);
+ }
+
+ elf_fn->locate_image(kfd, &head, kernel, &rd_root_size_off,
+ &rd_root_image_off, &mmap_off, &mmap_size);
+
+ /*
+ * Map in the whole data segment.
+ * The file offset needs to be page aligned.
+ */
+ dataseg = mmap(NULL, mmap_size,
+ xflag ? PROT_READ : PROT_READ | PROT_WRITE,
+ MAP_SHARED, kfd, mmap_off);
+ if (dataseg == MAP_FAILED)
+ err(1, "%s: can not map data seg", kernel);
+
+ /*
+ * Find value in the location: rd_root_size
+ */
+ ip = (u_int32_t *) (dataseg + rd_root_size_off);
+ rd_root_size_val = *ip;
+ if (debug)
+ fprintf(stderr, "rd_root_size val: 0x%llx (%lld blocks)\n",
+ (unsigned long long)rd_root_size_val,
+ (unsigned long long)rd_root_size_val >> 9);
+
+ /*
+ * Copy the symbol table and string table.
+ */
+ if (debug)
+ fprintf(stderr, "copying root image...\n");
+
+ if (xflag) {
+ n = write(fsfd, dataseg + rd_root_image_off,
+ (size_t)rd_root_size_val);
+ if (n != rd_root_size_val)
+ err(1, "write");
+ } else {
+ struct stat sstat;
+
+ if (fstat(fsfd, &sstat) == -1)
+ err(1, "fstat");
+ if (S_ISREG(sstat.st_mode) &&
+ sstat.st_size > rd_root_size_val) {
+ fprintf(stderr, "ramdisk too small 0x%llx 0x%llx\n",
+ (unsigned long long)sstat.st_size,
+ (unsigned long long)rd_root_size_val);
+ exit(1);
+ }
+ n = read(fsfd, dataseg + rd_root_image_off,
+ (size_t)rd_root_size_val);
+ if (n < 0)
+ err(1, "read");
+
+ msync(dataseg, mmap_size, 0);
+ }
+
+ if (debug)
+ fprintf(stderr, "...copied %d bytes\n", n);
+ exit(0);
+}
+
+__dead void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr, "usage: %s [-dx] bsd [fs]\n", __progname);
+ exit(1);
+}
diff --git a/usr.sbin/rdsetroot/rdsetroot.h b/usr.sbin/rdsetroot/rdsetroot.h
new file mode 100644
index 00000000000..6c05227aa75
--- /dev/null
+++ b/usr.sbin/rdsetroot/rdsetroot.h
@@ -0,0 +1,13 @@
+/* $OpenBSD: rdsetroot.h,v 1.1 2019/04/05 21:07:11 deraadt Exp $ */
+
+struct elf_fn {
+ void (*locate_image)(int, struct elfhdr *, char *, long *, long *,
+ off_t *, size_t *);
+ int (*find_rd_root_image)(char *, int, Elf_Phdr *, int, long *, long *,
+ off_t *, size_t *);
+
+};
+
+extern int debug;
+extern struct elf_fn ELF32_fn;
+extern struct elf_fn ELF64_fn;