/*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2000, 2001 David O'Brien * Copyright (c) 1996 Søren Schmidt * 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 * in this position and unchanged. * 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/cdefs.h> #include <sys/param.h> #include <sys/capsicum.h> #include <sys/elf_common.h> #include <sys/errno.h> #include <capsicum_helpers.h> #include <err.h> #include <fcntl.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <libcasper.h> #include <casper/cap_fileargs.h> static int elftype(const char *); static const char *iselftype(int); static void printelftypes(void); static void usage(void) __dead2; struct ELFtypes { const char *str; int value; }; /* XXX - any more types? */ static struct ELFtypes elftypes[] = { { "FreeBSD", ELFOSABI_FREEBSD }, { "Linux", ELFOSABI_LINUX }, { "Solaris", ELFOSABI_SOLARIS }, { "SVR4", ELFOSABI_SYSV } }; int main(int argc, char **argv) { const char *strtype = "FreeBSD"; int ch, flags, retval, type; bool change, force, listed; fileargs_t *fa; cap_rights_t rights; type = ELFOSABI_FREEBSD; retval = 0; change = false; force = false; listed = false; while ((ch = getopt(argc, argv, "f:lt:v")) != -1) switch (ch) { case 'f': if (change) errx(1, "f option incompatible with t option"); force = true; type = atoi(optarg); if (errno == ERANGE || type < 0 || type > 255) { warnx("invalid argument to option f: %s", optarg); usage(); } break; case 'l': printelftypes(); listed = true; break; case 'v': /* does nothing */ break; case 't': if (force) errx(1, "t option incompatible with f option"); change = true; strtype = optarg; break; default: usage(); } argc -= optind; argv += optind; if (argc == 0) { if (listed) exit(0); else { warnx("no file(s) specified"); usage(); } } if (!force && (type = elftype(strtype)) == -1) { warnx("invalid ELF type '%s'", strtype); printelftypes(); usage(); } flags = change || force ? O_RDWR : O_RDONLY; cap_rights_init(&rights, CAP_READ, CAP_SEEK); if (flags == O_RDWR) cap_rights_set(&rights, CAP_WRITE); fa = fileargs_init(argc, argv, flags, 0, &rights, FA_OPEN); if (fa == NULL) err(1, "unable to init casper"); caph_cache_catpages(); if (caph_limit_stdio() < 0 || caph_enter_casper() < 0) err(1, "unable to enter capability mode"); while (argc != 0) { int fd; char buffer[EI_NIDENT]; if ((fd = fileargs_open(fa, argv[0])) < 0) { warn("error opening file %s", argv[0]); retval = 1; goto fail; } if (read(fd, buffer, EI_NIDENT) < EI_NIDENT) { warnx("file '%s' too short", argv[0]); retval = 1; goto fail; } if (buffer[0] != ELFMAG0 || buffer[1] != ELFMAG1 || buffer[2] != ELFMAG2 || buffer[3] != ELFMAG3) { warnx("file '%s' is not ELF format", argv[0]); retval = 1; goto fail; } if (!change && !force) { fprintf(stdout, "File '%s' is of brand '%s' (%u).\n", argv[0], iselftype(buffer[EI_OSABI]), buffer[EI_OSABI]); if (!iselftype(type)) { warnx("ELF ABI Brand '%u' is unknown", type); printelftypes(); } } else { buffer[EI_OSABI] = type; lseek(fd, 0, SEEK_SET); if (write(fd, buffer, EI_NIDENT) != EI_NIDENT) { warn("error writing %s %d", argv[0], fd); retval = 1; goto fail; } } fail: close(fd); argc--; argv++; } fileargs_free(fa); return (retval); } static void usage(void) { (void)fprintf(stderr, "usage: brandelf [-lv] [-f ELF_ABI_number] [-t string] file ...\n"); exit(1); } static const char * iselftype(int etype) { size_t elfwalk; for (elfwalk = 0; elfwalk < nitems(elftypes); elfwalk++) if (etype == elftypes[elfwalk].value) return (elftypes[elfwalk].str); return (0); } static int elftype(const char *elfstrtype) { size_t elfwalk; for (elfwalk = 0; elfwalk < nitems(elftypes); elfwalk++) if (strcasecmp(elfstrtype, elftypes[elfwalk].str) == 0) return (elftypes[elfwalk].value); return (-1); } static void printelftypes(void) { size_t elfwalk; fprintf(stderr, "known ELF types are: "); for (elfwalk = 0; elfwalk < nitems(elftypes); elfwalk++) fprintf(stderr, "%s(%u) ", elftypes[elfwalk].str, elftypes[elfwalk].value); fprintf(stderr, "\n"); }