diff options
author | Sunil Nimmagadda <sunil@cvs.openbsd.org> | 2019-04-16 06:09:53 +0000 |
---|---|---|
committer | Sunil Nimmagadda <sunil@cvs.openbsd.org> | 2019-04-16 06:09:53 +0000 |
commit | 181c8f2567e5d5e3acc84dbf2b07ea167c0c0e3e (patch) | |
tree | 371ef7db05dcac2df56ce3088205ed4c4414ca6c /usr.sbin | |
parent | d67c1561e6dcace59a295625d39e096ba0fc58f8 (diff) |
Rewrite using libelf(3).
Lots of help with build/tests on sparc64 from jsg@, thank you.
ok deraadt
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/rdsetroot/Makefile | 6 | ||||
-rw-r--r-- | usr.sbin/rdsetroot/elf32.c | 3 | ||||
-rw-r--r-- | usr.sbin/rdsetroot/elf64.c | 3 | ||||
-rw-r--r-- | usr.sbin/rdsetroot/elfrd_size.c | 396 | ||||
-rw-r--r-- | usr.sbin/rdsetroot/rdsetroot.c | 259 | ||||
-rw-r--r-- | usr.sbin/rdsetroot/rdsetroot.h | 13 |
6 files changed, 181 insertions, 499 deletions
diff --git a/usr.sbin/rdsetroot/Makefile b/usr.sbin/rdsetroot/Makefile index eb9059ab556..2278f738c2a 100644 --- a/usr.sbin/rdsetroot/Makefile +++ b/usr.sbin/rdsetroot/Makefile @@ -1,7 +1,9 @@ -# $OpenBSD: Makefile,v 1.1 2019/04/05 21:07:11 deraadt Exp $ +# $OpenBSD: Makefile,v 1.2 2019/04/16 06:09:52 sunil Exp $ PROG= rdsetroot MAN= rdsetroot.8 -SRCS= rdsetroot.c elf32.c elf64.c + +LDADD+= -lelf +DPADD+= ${LIBELF} .include <bsd.prog.mk> diff --git a/usr.sbin/rdsetroot/elf32.c b/usr.sbin/rdsetroot/elf32.c deleted file mode 100644 index 4b303b5135f..00000000000 --- a/usr.sbin/rdsetroot/elf32.c +++ /dev/null @@ -1,3 +0,0 @@ -/* $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 deleted file mode 100644 index 3f453fd586e..00000000000 --- a/usr.sbin/rdsetroot/elf64.c +++ /dev/null @@ -1,3 +0,0 @@ -/* $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 deleted file mode 100644 index 1a9755990c4..00000000000 --- a/usr.sbin/rdsetroot/elfrd_size.c +++ /dev/null @@ -1,396 +0,0 @@ -/* $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.c b/usr.sbin/rdsetroot/rdsetroot.c index ef3101e3329..34fa86a7d77 100644 --- a/usr.sbin/rdsetroot/rdsetroot.c +++ b/usr.sbin/rdsetroot/rdsetroot.c @@ -1,79 +1,53 @@ -/* $OpenBSD: rdsetroot.c,v 1.1 2019/04/05 21:07:11 deraadt Exp $ */ +/* $OpenBSD: rdsetroot.c,v 1.2 2019/04/16 06:09:52 sunil Exp $ */ /* - * Copyright (c) 1994 Gordon W. Ross - * Copyright (c) 1997 Per Fogelstrom. (ELF modifications) - * All rights reserved. + * Copyright (c) 2019 Sunil Nimmagadda <sunil@openbsd.org> * - * 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. + * 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. * - * 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. + * 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. */ -/* - * 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 <err.h> #include <fcntl.h> +#include <gelf.h> +#include <libelf.h> #include <stdio.h> +#include <stdint.h> #include <stdlib.h> +#include <string.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; +int find_rd_root_image(uint64_t *, uint64_t *, off_t *, size_t *); +int symbol_get_u64(const char *, uint64_t *); __dead void usage(void); -int debug; - -struct elf_fn *elf_fn; +Elf *e; +Elf_Scn *symtab; +size_t nsymb, strtabndx, strtabsz; int -main(int argc, char *argv[]) +main(int argc, char **argv) { - int ch, kfd, n, xflag = 0, fsfd; - char *fs = NULL; - char *kernel; - u_int32_t *ip; + GElf_Shdr shdr; + Elf_Scn *scn; + char *dataseg, *kernel = NULL, *fs = NULL, *name; + off_t mmap_off, rd_root_size_val; + size_t shstrndx, mmap_size; + uint64_t rd_root_size_off, rd_root_image_off; + uint32_t *ip; + int ch, debug = 0, fsfd, kfd, n, xflag = 0; while ((ch = getopt(argc, argv, "dx")) != -1) { switch (ch) { @@ -98,8 +72,7 @@ main(int argc, char *argv[]) } else usage(); - kfd = open(kernel, xflag ? O_RDONLY : O_RDWR, 0644); - if (kfd < 0) + if ((kfd = open(kernel, xflag ? O_RDONLY : O_RDWR, 0644)) < 0) err(1, "%s", kernel); if (fs) { @@ -119,24 +92,59 @@ main(int argc, char *argv[]) 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 (elf_version(EV_CURRENT) == EV_NONE) + errx(1, "elf_version: %s", elf_errmsg(-1)); - if (!IS_ELF(head)) - err(1, "%s: bad magic number", kernel); + if ((e = elf_begin(kfd, xflag ? ELF_C_READ : ELF_C_RDWR, NULL)) == NULL) + errx(1, "elf_begin: %s", elf_errmsg(-1)); - 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); + if (elf_kind(e) != ELF_K_ELF) + errx(1, "%s: not an elf", kernel); + + if (gelf_getclass(e) == ELFCLASSNONE) + errx(1, "%s: invalid elf, not 32 or 64 bit", kernel); + + /* Retrieve index of section name string table. */ + if (elf_getshdrstrndx(e, &shstrndx) != 0) + errx(1, "elf_getshdrstrndx: %s", elf_errmsg(-1)); + + /* Find symbol table, string table. */ + scn = symtab = NULL; + while ((scn = elf_nextscn(e, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) != &shdr) + errx(1, "elf_getshdr: %s", elf_errmsg(-1)); + + if ((name = elf_strptr(e, shstrndx, shdr.sh_name)) == NULL) + errx(1, "elf_strptr: %s", elf_errmsg(-1)); + + if (strcmp(name, ELF_SYMTAB) == 0 && + shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) { + symtab = scn; + nsymb = shdr.sh_size / shdr.sh_entsize; + } + + if (strcmp(name, ELF_STRTAB) == 0 && + shdr.sh_type == SHT_STRTAB) { + strtabndx = elf_ndxscn(scn); + strtabsz = shdr.sh_size; + } } - elf_fn->locate_image(kfd, &head, kernel, &rd_root_size_off, - &rd_root_image_off, &mmap_off, &mmap_size); + if (symtab == NULL) + errx(1, "symbol table not found"); + + if (strtabndx == 0) + errx(1, "string table not found"); + + if (find_rd_root_image(&rd_root_size_off, &rd_root_image_off, + &mmap_off, &mmap_size) != 0) + errx(1, "can't locate space for rd_root_image!"); + + if (debug) { + fprintf(stderr, "rd_root_size_off: 0x%llx\n", rd_root_size_off); + fprintf(stderr, "rd_root_image_off: 0x%llx\n", + rd_root_image_off); + } /* * Map in the whole data segment. @@ -146,23 +154,19 @@ main(int argc, char *argv[]) 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); + err(1, "%s: cannot map data seg", kernel); /* * Find value in the location: rd_root_size */ - ip = (u_int32_t *) (dataseg + rd_root_size_off); + ip = (uint32_t *) (dataseg + rd_root_size_off); rd_root_size_val = *ip; - if (debug) + 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, @@ -191,7 +195,98 @@ main(int argc, char *argv[]) if (debug) fprintf(stderr, "...copied %d bytes\n", n); - exit(0); + + elf_end(e); + return 0; +} + +int +find_rd_root_image(uint64_t *rd_root_size_off, uint64_t *rd_root_image_off, + off_t *pmmap_off, size_t *pmmap_size) +{ + GElf_Phdr phdr; + size_t i, phdrnum; + unsigned long kernel_start, kernel_size; + uint64_t adiff, rd_root_size, rd_root_image, size_off, image_off; + int error = 1; + + if (symbol_get_u64("rd_root_size", &rd_root_size) != 0) + errx(1, "no rd_root_image symbols?"); + + if (symbol_get_u64("rd_root_image", &rd_root_image) != 0) + errx(1, "no rd_root_image symbols?"); + + /* Retrieve number of program headers. */ + if (elf_getphdrnum(e, &phdrnum) != 0) + errx(1, "elf_getphdrnum: %s", elf_errmsg(-1)); + + /* Locate the data segment. */ + for (i = 0; i < phdrnum; i++) { + if (gelf_getphdr(e, i, &phdr) != &phdr) + errx(1, "gelf_getphdr: %s", elf_errmsg(-1)); + + if (phdr.p_type != PT_LOAD) + continue; + + kernel_start = phdr.p_paddr; + kernel_size = phdr.p_filesz; + adiff = phdr.p_vaddr - phdr.p_paddr; + + size_off = rd_root_size - kernel_start; + image_off = rd_root_image - kernel_start; + if (size_off < adiff || image_off < adiff) + continue; + + size_off -= adiff; + image_off -= adiff; + if (image_off >= kernel_size) + continue; + if (size_off >= kernel_size) + errx(1, "rd_root_size not in data segment"); + + *pmmap_off = phdr.p_offset; + *pmmap_size = kernel_size; + *rd_root_size_off = size_off; + *rd_root_image_off = image_off; + error = 0; + break; + } + + return error; +} + +int +symbol_get_u64(const char *symbol, uint64_t *result) +{ + GElf_Sym sym; + Elf_Data *data; + const char *name; + size_t i; + int error = 1; + + data = NULL; + while ((data = elf_rawdata(symtab, data)) != NULL) { + for (i = 0; i < nsymb; i++) { + if (gelf_getsym(data, i, &sym) != &sym) + continue; + + if (sym.st_name >= strtabsz) + break; + + if ((name = elf_strptr(e, strtabndx, + sym.st_name)) == NULL) + continue; + + if (strcmp(name, symbol) == 0) { + if (result) + *result = sym.st_value; + error = 0; + break; + } + } + } + + return error; } __dead void diff --git a/usr.sbin/rdsetroot/rdsetroot.h b/usr.sbin/rdsetroot/rdsetroot.h deleted file mode 100644 index 6c05227aa75..00000000000 --- a/usr.sbin/rdsetroot/rdsetroot.h +++ /dev/null @@ -1,13 +0,0 @@ -/* $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; |