Index: head/tools/tools/controlelf/Makefile =================================================================== --- head/tools/tools/controlelf/Makefile +++ head/tools/tools/controlelf/Makefile @@ -1,14 +0,0 @@ -# $FreeBSD$ - -ELFTCDIR= ${SRCTOP}/contrib/elftoolchain - -PROG= controlelf -SRCS= controlelf.c - -LIBADD= elftc elf - -CFLAGS+=-I${ELFTCDIR}/libelftc -I${ELFTCDIR}/common - -WARNS?= 6 - -.include Index: head/tools/tools/controlelf/controlelf.1 =================================================================== --- head/tools/tools/controlelf/controlelf.1 +++ head/tools/tools/controlelf/controlelf.1 @@ -1,94 +0,0 @@ -.\" Copyright 2019 The FreeBSD Foundation. -.\" -.\" This software was developed by Bora Ozarslan under sponsorship from -.\" the FreeBSD Foundation. -.\" -.\" 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. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. -.\" -.\" $FreeBSD$ -.\" -.Dd September 27, 2019 -.Dt CONTROLELF 1 -.Os -.Sh NAME -.Nm controlelf -.Nd change an ELF binary's feature control note -.Sh SYNOPSIS -.Nm -.Op Fl h | Fl -help -.Op Fl l -.Op Fl e Ar featurelist -.Ar -.Sh DESCRIPTION -The -.Nm -utility modifies feature flags in the feature control note in an ELF binary. -.Pp -The options are as follows: -.Bl -tag -width indent -.It Fl h | Fl -help -Print a usage message and exit. -.It Fl l -List known ELF feature flags. -.It Fl e Ar featurelist -Edit features from the given comma separated list -.Ar featurelist . -.Ar featurelist -starts with one of the three operations: -.Dq Li + -to turn on the features, -.Dq Li - -to turn off the features, -.Dq Li = -to only turn on the given features. -A comma separated list of feature names follows the operation. -.El -.Pp -If -.Fl e -is not specified -.Nm -displays the status of each feature in the ELF note in each -.Ar . -.Sh EXIT STATUS -Exit status is 0 on success, and 1 if the command -fails if a file does not exist, is too short, -or fails to find or edit features note. -.Sh EXAMPLES -The following is an example of a typical usage -of the -.Nm -command: -.Bd -literal -offset indent -controlelf file -controlelf -e +aslr file -.Ed -.Sh HISTORY -.Nm -first appeared in -.Fx 13.0 . -.Sh AUTHORS -.Nm -was written by -.An Bora Ozarslan Mt borako.ozarslan@gmail.com -under sponsorship from the -.Fx Foundation. Index: head/tools/tools/controlelf/controlelf.c =================================================================== --- head/tools/tools/controlelf/controlelf.c +++ head/tools/tools/controlelf/controlelf.c @@ -1,392 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2019 The FreeBSD Foundation. - * - * This software was developed by Bora Ozarslan under sponsorship from - * the FreeBSD Foundation. - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "_elftc.h" - -__FBSDID("$FreeBSD$"); - -static bool convert_to_feature_val(char *, u_int32_t *); -static bool edit_file_features(Elf *, int, int, char *); -static bool get_file_features(Elf *, int, int, u_int32_t *, u_int64_t *); -static void print_features(void); -static bool print_file_features(Elf *, int, int, char *); -static void usage(void); - -struct ControlFeatures { - const char *alias; - unsigned long value; - const char *desc; -}; - -static struct ControlFeatures featurelist[] = { - { "aslr", NT_FREEBSD_FCTL_ASLR_DISABLE, "Disable ASLR" }, - { "protmax", NT_FREEBSD_FCTL_PROTMAX_DISABLE, - "Disable implicit PROT_MAX" }, - { "stackgap", NT_FREEBSD_FCTL_STKGAP_DISABLE, "Disable stack gap" }, -}; - -static struct option long_opts[] = { - { "help", no_argument, NULL, 'h' }, - { NULL, 0, NULL, 0 } -}; - -#if BYTE_ORDER == LITTLE_ENDIAN -#define SUPPORTED_ENDIAN ELFDATA2LSB -#else -#define SUPPORTED_ENDIAN ELFDATA2MSB -#endif - -int -main(int argc, char **argv) -{ - GElf_Ehdr ehdr; - Elf *elf; - Elf_Kind kind; - int ch, fd, editfeatures, retval; - char *features; - bool lflag; - - lflag = 0; - editfeatures = 0; - retval = 0; - - if (elf_version(EV_CURRENT) == EV_NONE) - errx(EXIT_FAILURE, "elf_version error"); - - while ((ch = getopt_long(argc, argv, "hle:", long_opts, NULL)) != -1) { - switch (ch) { - case 'l': - print_features(); - lflag = true; - break; - case 'e': - features = optarg; - editfeatures = 1; - break; - case 'h': - default: - usage(); - } - } - argc -= optind; - argv += optind; - if (argc == 0) { - if (lflag) - exit(0); - else { - warnx("no file(s) specified"); - usage(); - } - } - - while (argc) { - elf = NULL; - - if ((fd = open(argv[0], - editfeatures ? O_RDWR : O_RDONLY, 0)) < 0) { - warn("error opening file %s", argv[0]); - retval = 1; - goto fail; - } - - if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { - warnx("elf_begin failed: %s", elf_errmsg(-1)); - retval = 1; - goto fail; - } - - if ((kind = elf_kind(elf)) != ELF_K_ELF) { - if (kind == ELF_K_AR) - warnx("file '%s' is an archive", argv[0]); - else - warnx("file '%s' is not an ELF file", argv[0]); - retval = 1; - goto fail; - } - - if (gelf_getehdr(elf, &ehdr) == NULL) { - warnx("gelf_getehdr: %s", elf_errmsg(-1)); - retval = 1; - goto fail; - } - /* - * XXX need to support cross-endian operation, but for now - * exit on error rather than misbehaving. - */ - if (ehdr.e_ident[EI_DATA] != SUPPORTED_ENDIAN) { - warnx("file endianness must match host"); - retval = 1; - goto fail; - } - - if (!editfeatures) { - if (!print_file_features(elf, ehdr.e_phnum, fd, - argv[0])) { - retval = 1; - goto fail; - } - } else if (!edit_file_features(elf, ehdr.e_phnum, fd, - features)) { - retval = 1; - goto fail; - } -fail: - if (elf != NULL) - elf_end(elf); - - if (fd >= 0) - close(fd); - - argc--; - argv++; - } - - return (retval); -} - -#define USAGE_MESSAGE \ - "\ -Usage: %s [options] file...\n\ - Set or display the control features for an ELF object.\n\n\ - Supported options are:\n\ - -l List known control features.\n\ - -e [+-=]feature,list Edit features from a comma separated list.\n\ - -h | --help Print a usage message and exit.\n" - -static void -usage(void) -{ - - fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); - exit(1); -} - -static bool -convert_to_feature_val(char *feature_str, u_int32_t *feature_val) -{ - char *feature; - int i, len; - u_int32_t input; - char operation; - - input = 0; - operation = *feature_str; - feature_str++; - len = nitems(featurelist); - while ((feature = strsep(&feature_str, ",")) != NULL) { - for (i = 0; i < len; ++i) { - if (strcmp(featurelist[i].alias, feature) == 0) { - input |= featurelist[i].value; - break; - } - } - if (i == len) { - warnx("%s is not a valid feature", feature); - return (false); - } - } - - if (operation == '+') { - *feature_val |= input; - } else if (operation == '=') { - *feature_val = input; - } else if (operation == '-') { - *feature_val &= ~input; - } else { - warnx("'%c' not an operator - use '+', '-', '='", - feature_str[0]); - return (false); - } - return (true); -} - -static bool -edit_file_features(Elf *elf, int phcount, int fd, char *val) -{ - u_int32_t features; - u_int64_t off; - - if (!get_file_features(elf, phcount, fd, &features, &off)) { - warnx("NT_FREEBSD_FEATURE_CTL note not found"); - return (false); - } - - if (!convert_to_feature_val(val, &features)) - return (false); - - if (lseek(fd, off, SEEK_SET) == -1 || - write(fd, &features, sizeof(features)) < - (ssize_t)sizeof(features)) { - warnx("error writing feature value"); - return (false); - } - return (true); -} - -static void -print_features(void) -{ - size_t i; - - printf("Known features are:\n"); - for (i = 0; i < nitems(featurelist); ++i) - printf("%-16s%s\n", featurelist[i].alias, - featurelist[i].desc); -} - -static bool -print_file_features(Elf *elf, int phcount, int fd, char *filename) -{ - u_int32_t features; - unsigned long i; - - if (!get_file_features(elf, phcount, fd, &features, NULL)) { - return (false); - } - - printf("File '%s' features:\n", filename); - for (i = 0; i < nitems(featurelist); ++i) { - printf("%-16s'%s' is ", featurelist[i].alias, - featurelist[i].desc); - - if ((featurelist[i].value & features) == 0) - printf("un"); - - printf("set.\n"); - } - return (true); -} - -static bool -get_file_features(Elf *elf, int phcount, int fd, u_int32_t *features, - u_int64_t *off) -{ - GElf_Phdr phdr; - Elf_Note note; - unsigned long read_total; - int namesz, descsz, i; - char *name; - ssize_t size; - - /* - * Go through each program header to find one that is of type PT_NOTE - * and has a note for feature control. - */ - for (i = 0; i < phcount; ++i) { - if (gelf_getphdr(elf, i, &phdr) == NULL) { - warnx("gelf_getphdr failed: %s", elf_errmsg(-1)); - return (false); - } - - if (phdr.p_type != PT_NOTE) - continue; - - if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) { - warn("lseek() failed:"); - return (false); - } - - read_total = 0; - while (read_total < phdr.p_filesz) { - size = read(fd, ¬e, sizeof(note)); - if (size < (ssize_t)sizeof(note)) { - warn("read() failed:"); - return (false); - } - read_total += sizeof(note); - - /* - * XXX: Name and descriptor are 4 byte aligned, however, - * the size given doesn't include the padding. - */ - namesz = roundup2(note.n_namesz, 4); - name = malloc(namesz); - if (name == NULL) { - warn("malloc() failed."); - return (false); - } - descsz = roundup2(note.n_descsz, 4); - size = read(fd, name, namesz); - read_total += namesz; - - if (note.n_namesz != 8 || - strncmp("FreeBSD", name, 7) != 0 || - note.n_type != NT_FREEBSD_FEATURE_CTL) { - /* Not the right note. Skip the description */ - if (lseek(fd, descsz, SEEK_CUR) < 0) { - warn("lseek() failed."); - free(name); - return (false); - } - read_total += descsz; - free(name); - continue; - } - - if (note.n_descsz < sizeof(u_int32_t)) { - warnx("Feature descriptor can't " - "be less than 4 bytes"); - free(name); - return (false); - } - - /* - * XXX: For now we look at only 4 bytes of the - * descriptor. This should respect descsz. - */ - if (note.n_descsz > sizeof(u_int32_t)) - warnx("Feature note is bigger than expected"); - read(fd, features, sizeof(u_int32_t)); - if (off != NULL) - *off = phdr.p_offset + read_total; - free(name); - return (true); - } - } - - warnx("NT_FREEBSD_FEATURE_CTL note not found"); - return (false); -} Index: head/usr.bin/Makefile =================================================================== --- head/usr.bin/Makefile +++ head/usr.bin/Makefile @@ -31,6 +31,7 @@ diff \ dirname \ du \ + elfctl \ elfdump \ enigma \ env \ Index: head/usr.bin/elfctl/Makefile =================================================================== --- head/usr.bin/elfctl/Makefile +++ head/usr.bin/elfctl/Makefile @@ -0,0 +1,11 @@ +# $FreeBSD$ + +ELFTCDIR= ${SRCTOP}/contrib/elftoolchain + +PROG= elfctl + +LIBADD= elftc elf + +CFLAGS+=-I${ELFTCDIR}/libelftc -I${ELFTCDIR}/common + +.include Index: head/usr.bin/elfctl/elfctl.1 =================================================================== --- head/usr.bin/elfctl/elfctl.1 +++ head/usr.bin/elfctl/elfctl.1 @@ -0,0 +1,94 @@ +.\" Copyright 2019 The FreeBSD Foundation. +.\" +.\" This software was developed by Bora Ozarslan under sponsorship from +.\" the FreeBSD Foundation. +.\" +.\" 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. +.\" +.\" $FreeBSD$ +.\" +.Dd March 1, 2020 +.Dt ELFCTL 1 +.Os +.Sh NAME +.Nm elfctl +.Nd change an ELF binary's feature control note +.Sh SYNOPSIS +.Nm +.Op Fl h | Fl -help +.Op Fl l +.Op Fl e Ar featurelist +.Ar +.Sh DESCRIPTION +The +.Nm +utility modifies feature flags in the feature control note in an ELF binary. +.Pp +The options are as follows: +.Bl -tag -width indent +.It Fl h | Fl -help +Print a usage message and exit. +.It Fl l +List known ELF feature flags. +.It Fl e Ar featurelist +Edit features from the given comma separated list +.Ar featurelist . +.Ar featurelist +starts with one of the three operations: +.Dq Li + +to turn on the features, +.Dq Li - +to turn off the features, +.Dq Li = +to only turn on the given features. +A comma separated list of feature names follows the operation. +.El +.Pp +If +.Fl e +is not specified +.Nm +displays the status of each feature in the ELF note in each +.Ar . +.Sh EXIT STATUS +Exit status is 0 on success, and 1 if the command +fails if a file does not exist, is too short, +or fails to find or edit features note. +.Sh EXAMPLES +The following is an example of a typical usage +of the +.Nm +command: +.Bd -literal -offset indent +elfctl file +elfctl -e +aslr file +.Ed +.Sh HISTORY +.Nm +first appeared in +.Fx 13.0 . +.Sh AUTHORS +.Nm +was written by +.An Bora Ozarslan Mt borako.ozarslan@gmail.com +under sponsorship from the +.Fx Foundation. Index: head/usr.bin/elfctl/elfctl.c =================================================================== --- head/usr.bin/elfctl/elfctl.c +++ head/usr.bin/elfctl/elfctl.c @@ -0,0 +1,392 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 The FreeBSD Foundation. + * + * This software was developed by Bora Ozarslan under sponsorship from + * the FreeBSD Foundation. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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 +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "_elftc.h" + +__FBSDID("$FreeBSD$"); + +static bool convert_to_feature_val(char *, u_int32_t *); +static bool edit_file_features(Elf *, int, int, char *); +static bool get_file_features(Elf *, int, int, u_int32_t *, u_int64_t *); +static void print_features(void); +static bool print_file_features(Elf *, int, int, char *); +static void usage(void); + +struct ControlFeatures { + const char *alias; + unsigned long value; + const char *desc; +}; + +static struct ControlFeatures featurelist[] = { + { "aslr", NT_FREEBSD_FCTL_ASLR_DISABLE, "Disable ASLR" }, + { "protmax", NT_FREEBSD_FCTL_PROTMAX_DISABLE, + "Disable implicit PROT_MAX" }, + { "stackgap", NT_FREEBSD_FCTL_STKGAP_DISABLE, "Disable stack gap" }, +}; + +static struct option long_opts[] = { + { "help", no_argument, NULL, 'h' }, + { NULL, 0, NULL, 0 } +}; + +#if BYTE_ORDER == LITTLE_ENDIAN +#define SUPPORTED_ENDIAN ELFDATA2LSB +#else +#define SUPPORTED_ENDIAN ELFDATA2MSB +#endif + +int +main(int argc, char **argv) +{ + GElf_Ehdr ehdr; + Elf *elf; + Elf_Kind kind; + int ch, fd, editfeatures, retval; + char *features; + bool lflag; + + lflag = 0; + editfeatures = 0; + retval = 0; + + if (elf_version(EV_CURRENT) == EV_NONE) + errx(EXIT_FAILURE, "elf_version error"); + + while ((ch = getopt_long(argc, argv, "hle:", long_opts, NULL)) != -1) { + switch (ch) { + case 'l': + print_features(); + lflag = true; + break; + case 'e': + features = optarg; + editfeatures = 1; + break; + case 'h': + default: + usage(); + } + } + argc -= optind; + argv += optind; + if (argc == 0) { + if (lflag) + exit(0); + else { + warnx("no file(s) specified"); + usage(); + } + } + + while (argc) { + elf = NULL; + + if ((fd = open(argv[0], + editfeatures ? O_RDWR : O_RDONLY, 0)) < 0) { + warn("error opening file %s", argv[0]); + retval = 1; + goto fail; + } + + if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { + warnx("elf_begin failed: %s", elf_errmsg(-1)); + retval = 1; + goto fail; + } + + if ((kind = elf_kind(elf)) != ELF_K_ELF) { + if (kind == ELF_K_AR) + warnx("file '%s' is an archive", argv[0]); + else + warnx("file '%s' is not an ELF file", argv[0]); + retval = 1; + goto fail; + } + + if (gelf_getehdr(elf, &ehdr) == NULL) { + warnx("gelf_getehdr: %s", elf_errmsg(-1)); + retval = 1; + goto fail; + } + /* + * XXX need to support cross-endian operation, but for now + * exit on error rather than misbehaving. + */ + if (ehdr.e_ident[EI_DATA] != SUPPORTED_ENDIAN) { + warnx("file endianness must match host"); + retval = 1; + goto fail; + } + + if (!editfeatures) { + if (!print_file_features(elf, ehdr.e_phnum, fd, + argv[0])) { + retval = 1; + goto fail; + } + } else if (!edit_file_features(elf, ehdr.e_phnum, fd, + features)) { + retval = 1; + goto fail; + } +fail: + if (elf != NULL) + elf_end(elf); + + if (fd >= 0) + close(fd); + + argc--; + argv++; + } + + return (retval); +} + +#define USAGE_MESSAGE \ + "\ +Usage: %s [options] file...\n\ + Set or display the control features for an ELF object.\n\n\ + Supported options are:\n\ + -l List known control features.\n\ + -e [+-=]feature,list Edit features from a comma separated list.\n\ + -h | --help Print a usage message and exit.\n" + +static void +usage(void) +{ + + fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME()); + exit(1); +} + +static bool +convert_to_feature_val(char *feature_str, u_int32_t *feature_val) +{ + char *feature; + int i, len; + u_int32_t input; + char operation; + + input = 0; + operation = *feature_str; + feature_str++; + len = nitems(featurelist); + while ((feature = strsep(&feature_str, ",")) != NULL) { + for (i = 0; i < len; ++i) { + if (strcmp(featurelist[i].alias, feature) == 0) { + input |= featurelist[i].value; + break; + } + } + if (i == len) { + warnx("%s is not a valid feature", feature); + return (false); + } + } + + if (operation == '+') { + *feature_val |= input; + } else if (operation == '=') { + *feature_val = input; + } else if (operation == '-') { + *feature_val &= ~input; + } else { + warnx("'%c' not an operator - use '+', '-', '='", + feature_str[0]); + return (false); + } + return (true); +} + +static bool +edit_file_features(Elf *elf, int phcount, int fd, char *val) +{ + u_int32_t features; + u_int64_t off; + + if (!get_file_features(elf, phcount, fd, &features, &off)) { + warnx("NT_FREEBSD_FEATURE_CTL note not found"); + return (false); + } + + if (!convert_to_feature_val(val, &features)) + return (false); + + if (lseek(fd, off, SEEK_SET) == -1 || + write(fd, &features, sizeof(features)) < + (ssize_t)sizeof(features)) { + warnx("error writing feature value"); + return (false); + } + return (true); +} + +static void +print_features(void) +{ + size_t i; + + printf("Known features are:\n"); + for (i = 0; i < nitems(featurelist); ++i) + printf("%-16s%s\n", featurelist[i].alias, + featurelist[i].desc); +} + +static bool +print_file_features(Elf *elf, int phcount, int fd, char *filename) +{ + u_int32_t features; + unsigned long i; + + if (!get_file_features(elf, phcount, fd, &features, NULL)) { + return (false); + } + + printf("File '%s' features:\n", filename); + for (i = 0; i < nitems(featurelist); ++i) { + printf("%-16s'%s' is ", featurelist[i].alias, + featurelist[i].desc); + + if ((featurelist[i].value & features) == 0) + printf("un"); + + printf("set.\n"); + } + return (true); +} + +static bool +get_file_features(Elf *elf, int phcount, int fd, u_int32_t *features, + u_int64_t *off) +{ + GElf_Phdr phdr; + Elf_Note note; + unsigned long read_total; + int namesz, descsz, i; + char *name; + ssize_t size; + + /* + * Go through each program header to find one that is of type PT_NOTE + * and has a note for feature control. + */ + for (i = 0; i < phcount; ++i) { + if (gelf_getphdr(elf, i, &phdr) == NULL) { + warnx("gelf_getphdr failed: %s", elf_errmsg(-1)); + return (false); + } + + if (phdr.p_type != PT_NOTE) + continue; + + if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) { + warn("lseek() failed:"); + return (false); + } + + read_total = 0; + while (read_total < phdr.p_filesz) { + size = read(fd, ¬e, sizeof(note)); + if (size < (ssize_t)sizeof(note)) { + warn("read() failed:"); + return (false); + } + read_total += sizeof(note); + + /* + * XXX: Name and descriptor are 4 byte aligned, however, + * the size given doesn't include the padding. + */ + namesz = roundup2(note.n_namesz, 4); + name = malloc(namesz); + if (name == NULL) { + warn("malloc() failed."); + return (false); + } + descsz = roundup2(note.n_descsz, 4); + size = read(fd, name, namesz); + read_total += namesz; + + if (note.n_namesz != 8 || + strncmp("FreeBSD", name, 7) != 0 || + note.n_type != NT_FREEBSD_FEATURE_CTL) { + /* Not the right note. Skip the description */ + if (lseek(fd, descsz, SEEK_CUR) < 0) { + warn("lseek() failed."); + free(name); + return (false); + } + read_total += descsz; + free(name); + continue; + } + + if (note.n_descsz < sizeof(u_int32_t)) { + warnx("Feature descriptor can't " + "be less than 4 bytes"); + free(name); + return (false); + } + + /* + * XXX: For now we look at only 4 bytes of the + * descriptor. This should respect descsz. + */ + if (note.n_descsz > sizeof(u_int32_t)) + warnx("Feature note is bigger than expected"); + read(fd, features, sizeof(u_int32_t)); + if (off != NULL) + *off = phdr.p_offset + read_total; + free(name); + return (true); + } + } + + warnx("NT_FREEBSD_FEATURE_CTL note not found"); + return (false); +}