Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 8 Mar 2020 21:02:36 +0000 (UTC)
From:      Ed Maste <emaste@FreeBSD.org>
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
Message-ID:  <202003082102.028L2a1w013444@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <borako.ozarslan@gmail.com>
  
  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 <sys/param.h>
 #include <sys/elf_common.h>
+#include <sys/endian.h>
 #include <sys/stat.h>
 
 #include <err.h>
@@ -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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202003082102.028L2a1w013444>