From owner-svn-src-all@freebsd.org Sun Mar 8 21:02:36 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 8FB35275EB7; Sun, 8 Mar 2020 21:02:36 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 48bDMJ43Wsz4Jw1; Sun, 8 Mar 2020 21:02:36 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 8647827F47; Sun, 8 Mar 2020 21:02:36 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 028L2aZI013446; Sun, 8 Mar 2020 21:02:36 GMT (envelope-from emaste@FreeBSD.org) Received: (from emaste@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 028L2a1w013444; Sun, 8 Mar 2020 21:02:36 GMT (envelope-from emaste@FreeBSD.org) Message-Id: <202003082102.028L2a1w013444@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: emaste set sender to emaste@FreeBSD.org using -f From: Ed Maste Date: Sun, 8 Mar 2020 21:02:36 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r358780 - stable/12/tools/tools/controlelf X-SVN-Group: stable-12 X-SVN-Commit-Author: emaste X-SVN-Commit-Paths: stable/12/tools/tools/controlelf X-SVN-Commit-Revision: 358780 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 08 Mar 2020 21:02:36 -0000 Author: emaste Date: Sun Mar 8 21:02:35 2020 New Revision: 358780 URL: https://svnweb.freebsd.org/changeset/base/358780 Log: Add tool to modify ELF binary feature control bits MFC r352797: Add tool to modify ELF binary feature control bits This will allow feature control bits (e.g. for ASLR, PROT_MAX) to be inspected or modified. Some clean-up and additional work is likely still required, but we can iterate on this in the tree. Submitted by: Bora Özarslan MFC r352799: controlelf: clean up warnings - use explicit ELF note name when not found - no trailing . on warnings - no \n MFC r352801: controlelf: install standard BSD 2 clause license MFC r352803: controlelf: some style(9) cleanup MFC r352805: controlelf: add protmax control MFC r352806: controlelf: tidy up option parsing MFC r352808: controlelf: simplify feature string parsing Also add error handling on failure to seek/write updated value. MFC r352809: controlelf: exit with error if file endianness does not match host We need to add support for cross-endian operation, but until that's done just exit with an error rather than misbehaving. MFC r352815: controlelf: update man page Some minor corrections, clarifications or rewording. Sponsored by: The FreeBSD Foundation Added: stable/12/tools/tools/controlelf/ - copied from r352797, head/tools/tools/controlelf/ Modified: stable/12/tools/tools/controlelf/controlelf.1 stable/12/tools/tools/controlelf/controlelf.c Directory Properties: stable/12/ (props changed) Modified: stable/12/tools/tools/controlelf/controlelf.1 ============================================================================== --- head/tools/tools/controlelf/controlelf.1 Fri Sep 27 16:27:52 2019 (r352797) +++ stable/12/tools/tools/controlelf/controlelf.1 Sun Mar 8 21:02:35 2020 (r358780) @@ -26,12 +26,12 @@ .\" .\" $FreeBSD$ .\" -.Dd February 21, 2019 +.Dd September 27, 2019 .Dt CONTROLELF 1 .Os .Sh NAME .Nm controlelf -.Nd change an ELF binary's control features +.Nd change an ELF binary's feature control note .Sh SYNOPSIS .Nm .Op Fl h | Fl -help @@ -41,33 +41,33 @@ .Sh DESCRIPTION The .Nm -utility modifies an ELF binary to change it's control features. +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 -Writes the list of all known ELF types to standard output. +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 modes: +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. -Followed by a comma separated features. +A comma separated list of feature names follows the operation. .El .Pp If -.Fl e , -option wasn't specified, +.Fl e +is not specified .Nm -will display the current control features for the files named by the arguments +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 @@ -83,10 +83,12 @@ controlelf file controlelf -e +aslr file .Ed .Sh HISTORY -The .Nm -manual page first appeared in +first appeared in .Fx 13.0 . .Sh AUTHORS -This manual page was written by -.An Bora Ozarslan Mt borako.ozarslan@gmail.com . +.Nm +was written by +.An Bora Ozarslan Mt borako.ozarslan@gmail.com +under sponsorship from the +.Fx Foundation. Modified: stable/12/tools/tools/controlelf/controlelf.c ============================================================================== --- head/tools/tools/controlelf/controlelf.c Fri Sep 27 16:27:52 2019 (r352797) +++ stable/12/tools/tools/controlelf/controlelf.c Sun Mar 8 21:02:35 2020 (r358780) @@ -1,5 +1,5 @@ /*- - * SPDX-License-Identifier: BSD-3-Clause + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2019 The FreeBSD Foundation. * @@ -10,26 +10,27 @@ * 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. + * 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 ``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. + * 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 @@ -47,66 +48,73 @@ __FBSDID("$FreeBSD$"); -static bool convert_to_feature_val(char*, u_int32_t*); -static bool edit_file_features(Elf *, int, int, char*); +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 bool print_file_features(Elf *, int, int, char *); static void usage(void); struct ControlFeatures { const char *alias; - unsigned long featureVal; + unsigned long value; const char *desc; }; static struct ControlFeatures featurelist[] = { - { "aslr", NT_FREEBSD_FCTL_ASLR_DISABLE, "Disable ASLR" } + { "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 controlelf_longopts[] = { - { "help", no_argument, NULL, 'h' }, - { NULL, 0, NULL, 0 } +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, listed, editfeatures, retval; + int ch, fd, editfeatures, retval; char *features; + bool lflag; - listed = 0; + 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:", controlelf_longopts, - NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "hle:", long_opts, NULL)) != -1) { switch (ch) { case 'l': print_features(); - listed = 1; + lflag = true; break; case 'e': features = optarg; editfeatures = 1; break; case 'h': - usage(); - break; default: usage(); } } argc -= optind; argv += optind; - if (!argc) { - if (listed) + if (argc == 0) { + if (lflag) exit(0); else { warnx("no file(s) specified"); @@ -117,8 +125,8 @@ main(int argc, char **argv) while (argc) { elf = NULL; - if ((fd = open(argv[0], editfeatures ? O_RDWR : - O_RDONLY, 0)) < 0) { + if ((fd = open(argv[0], + editfeatures ? O_RDWR : O_RDONLY, 0)) < 0) { warn("error opening file %s", argv[0]); retval = 1; goto fail; @@ -132,10 +140,9 @@ main(int argc, char **argv) if ((kind = elf_kind(elf)) != ELF_K_ELF) { if (kind == ELF_K_AR) - warnx("file '%s' is an archive.", argv[0]); + warnx("file '%s' is an archive", argv[0]); else - warnx("file '%s' is not an ELF file.", - argv[0]); + warnx("file '%s' is not an ELF file", argv[0]); retval = 1; goto fail; } @@ -145,13 +152,24 @@ main(int argc, char **argv) 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])) { + 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)) { + } else if (!edit_file_features(elf, ehdr.e_phnum, fd, + features)) { retval = 1; goto fail; } @@ -169,7 +187,8 @@ fail: return (retval); } -#define USAGE_MESSAGE "\ +#define USAGE_MESSAGE \ + "\ Usage: %s [options] file...\n\ Set or display the control features for an ELF object.\n\n\ Supported options are:\n\ @@ -186,47 +205,40 @@ usage(void) } static bool -convert_to_feature_val(char* feature_str, u_int32_t* feature_val) +convert_to_feature_val(char *feature_str, u_int32_t *feature_val) { - char *feature_input, *feature; + char *feature; int i, len; u_int32_t input; - bool add, set; + char operation; - add = set = false; input = 0; - - if (feature_str[0] == '+') - add = true; - else if (feature_str[0] == '=') - set = true; - else if (feature_str[0] != '-') { - warnx("'%c' is not an operator. Use instead '+', '-', '='.", - feature_str[0]); - return (false); - } - - feature_input = feature_str + 1; + operation = *feature_str; + feature_str++; len = nitems(featurelist); - while ((feature = strsep(&feature_input, ",")) != NULL) { + while ((feature = strsep(&feature_str, ",")) != NULL) { for (i = 0; i < len; ++i) { if (strcmp(featurelist[i].alias, feature) == 0) { - input |= featurelist[i].featureVal; + input |= featurelist[i].value; break; } } if (i == len) { - warnx("%s is not a valid feature.", feature); + warnx("%s is not a valid feature", feature); return (false); } } - if (add) { + if (operation == '+') { *feature_val |= input; - } else if (set) { + } else if (operation == '=') { *feature_val = input; + } else if (operation == '-') { + *feature_val &= ~input; } else { - *feature_val -= (*feature_val) & input; + warnx("'%c' not an operator - use '+', '-', '='", + feature_str[0]); + return (false); } return (true); } @@ -238,15 +250,19 @@ edit_file_features(Elf *elf, int phcount, int fd, char u_int64_t off; if (!get_file_features(elf, phcount, fd, &features, &off)) { - warnx("No control features note on the file.\n"); + warnx("NT_FREEBSD_FEATURE_CTL note not found"); return (false); } if (!convert_to_feature_val(val, &features)) return (false); - lseek(fd, off, SEEK_SET); - write(fd, &features, sizeof(u_int32_t)); + 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); } @@ -257,12 +273,13 @@ print_features(void) printf("Known features are:\n"); for (i = 0; i < nitems(featurelist); ++i) - printf("%s\t\t %s\n", featurelist[i].alias, + printf("%-16s%s\n", featurelist[i].alias, featurelist[i].desc); } static bool -print_file_features(Elf *elf, int phcount, int fd, char *filename) { +print_file_features(Elf *elf, int phcount, int fd, char *filename) +{ u_int32_t features; unsigned long i; @@ -272,10 +289,10 @@ print_file_features(Elf *elf, int phcount, int fd, cha printf("File '%s' features:\n", filename); for (i = 0; i < nitems(featurelist); ++i) { - printf("%s\t\t'%s' is ", featurelist[i].alias, + printf("%-16s'%s' is ", featurelist[i].alias, featurelist[i].desc); - if ((featurelist[i].featureVal & features) == 0) + if ((featurelist[i].value & features) == 0) printf("un"); printf("set.\n"); @@ -284,7 +301,8 @@ print_file_features(Elf *elf, int phcount, int fd, cha } static bool -get_file_features(Elf *elf, int phcount, int fd, u_int32_t *features, u_int64_t *off) +get_file_features(Elf *elf, int phcount, int fd, u_int32_t *features, + u_int64_t *off) { GElf_Phdr phdr; Elf_Note note; @@ -327,7 +345,7 @@ get_file_features(Elf *elf, int phcount, int fd, u_int namesz = roundup2(note.n_namesz, 4); name = malloc(namesz); if (name == NULL) { - warn("malloc() failed.\n"); + warn("malloc() failed."); return (false); } descsz = roundup2(note.n_descsz, 4); @@ -339,7 +357,7 @@ get_file_features(Elf *elf, int phcount, int fd, u_int note.n_type != NT_FREEBSD_FEATURE_CTL) { /* Not the right note. Skip the description */ if (lseek(fd, descsz, SEEK_CUR) < 0) { - warn("lseek() failed.\n"); + warn("lseek() failed."); free(name); return (false); } @@ -360,7 +378,7 @@ get_file_features(Elf *elf, int phcount, int fd, u_int * descriptor. This should respect descsz. */ if (note.n_descsz > sizeof(u_int32_t)) - warnx("Feature note is bigger than expected."); + warnx("Feature note is bigger than expected"); read(fd, features, sizeof(u_int32_t)); if (off != NULL) *off = phdr.p_offset + read_total; @@ -369,6 +387,6 @@ get_file_features(Elf *elf, int phcount, int fd, u_int } } - warnx("Couldn't find a note header with control feature note."); + warnx("NT_FREEBSD_FEATURE_CTL note not found"); return (false); }