xref: /freebsd/usr.bin/elfctl/elfctl.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
179bfb05bSEd Maste /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
379bfb05bSEd Maste  *
479bfb05bSEd Maste  * Copyright (c) 2019 The FreeBSD Foundation.
579bfb05bSEd Maste  *
679bfb05bSEd Maste  * This software was developed by Bora Ozarslan under sponsorship from
779bfb05bSEd Maste  * the FreeBSD Foundation.
879bfb05bSEd Maste  *
979bfb05bSEd Maste  * Redistribution and use in source and binary forms, with or without
1079bfb05bSEd Maste  * modification, are permitted provided that the following conditions
1179bfb05bSEd Maste  * are met:
1279bfb05bSEd Maste  * 1. Redistributions of source code must retain the above copyright
1379bfb05bSEd Maste  *    notice, this list of conditions and the following disclaimer.
1479bfb05bSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
1579bfb05bSEd Maste  *    notice, this list of conditions and the following disclaimer in the
1679bfb05bSEd Maste  *    documentation and/or other materials provided with the distribution.
1779bfb05bSEd Maste  *
1879bfb05bSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1979bfb05bSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2079bfb05bSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2179bfb05bSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2279bfb05bSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2379bfb05bSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2479bfb05bSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2579bfb05bSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2679bfb05bSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2779bfb05bSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2879bfb05bSEd Maste  * SUCH DAMAGE.
2979bfb05bSEd Maste  */
3079bfb05bSEd Maste 
3179bfb05bSEd Maste #include <sys/param.h>
3279bfb05bSEd Maste #include <sys/elf_common.h>
3379bfb05bSEd Maste #include <sys/endian.h>
3479bfb05bSEd Maste #include <sys/stat.h>
3579bfb05bSEd Maste 
3686f33b5fSEd Maste #include <ctype.h>
3779bfb05bSEd Maste #include <err.h>
3886f33b5fSEd Maste #include <errno.h>
3979bfb05bSEd Maste #include <fcntl.h>
4079bfb05bSEd Maste #include <gelf.h>
4179bfb05bSEd Maste #include <getopt.h>
4279bfb05bSEd Maste #include <libelf.h>
4379bfb05bSEd Maste #include <stdbool.h>
449940ac80SKonstantin Belousov #include <stdint.h>
4579bfb05bSEd Maste #include <stdio.h>
4679bfb05bSEd Maste #include <stdlib.h>
4779bfb05bSEd Maste #include <string.h>
4879bfb05bSEd Maste #include <unistd.h>
4979bfb05bSEd Maste 
5079bfb05bSEd Maste #include "_elftc.h"
5182b611edSEd Maste static bool convert_to_feature_val(const char *, uint32_t *);
524a27bf12SMarcin Wojtas static bool edit_file_features(Elf *, int, int, char *, bool);
534a27bf12SMarcin Wojtas static bool get_file_features(Elf *, int, int, uint32_t *, uint64_t *, bool);
5479bfb05bSEd Maste static void print_features(void);
554a27bf12SMarcin Wojtas static bool print_file_features(Elf *, int, int, char *, bool);
56*a1b6427aSAlfonso Gregory static void usage(void) __dead2;
5779bfb05bSEd Maste 
5879bfb05bSEd Maste struct ControlFeatures {
5979bfb05bSEd Maste 	const char *alias;
6079bfb05bSEd Maste 	unsigned long value;
6179bfb05bSEd Maste 	const char *desc;
6279bfb05bSEd Maste };
6379bfb05bSEd Maste 
6479bfb05bSEd Maste static struct ControlFeatures featurelist[] = {
65c763f99dSEd Maste 	{ "noaslr",	NT_FREEBSD_FCTL_ASLR_DISABLE,	"Disable ASLR" },
66c763f99dSEd Maste 	{ "noprotmax",	NT_FREEBSD_FCTL_PROTMAX_DISABLE,
6779bfb05bSEd Maste 	    "Disable implicit PROT_MAX" },
68c763f99dSEd Maste 	{ "nostackgap",	NT_FREEBSD_FCTL_STKGAP_DISABLE, "Disable stack gap" },
69d06e23f9SEd Maste 	{ "wxneeded",	NT_FREEBSD_FCTL_WXNEEDED, "Requires W+X mappings" },
70bc6f027aSKonstantin Belousov 	{ "la48",	NT_FREEBSD_FCTL_LA48, "amd64: Limit user VA to 48bit" },
7179bfb05bSEd Maste };
7279bfb05bSEd Maste 
7379bfb05bSEd Maste static struct option long_opts[] = {
7479bfb05bSEd Maste 	{ "help",	no_argument,	NULL,	'h' },
7579bfb05bSEd Maste 	{ NULL,		0,		NULL,	0 }
7679bfb05bSEd Maste };
7779bfb05bSEd Maste 
7879bfb05bSEd Maste #if BYTE_ORDER == LITTLE_ENDIAN
794a27bf12SMarcin Wojtas #define	HOST_ENDIAN	ELFDATA2LSB
804a27bf12SMarcin Wojtas #define	SWAP_ENDIAN	ELFDATA2MSB
8179bfb05bSEd Maste #else
824a27bf12SMarcin Wojtas #define	HOST_ENDIAN	ELFDATA2MSB
834a27bf12SMarcin Wojtas #define	SWAP_ENDIAN	ELFDATA2LSB
8479bfb05bSEd Maste #endif
8579bfb05bSEd Maste 
86f6d95a01SEd Maste static bool iflag;
87f6d95a01SEd Maste 
8879bfb05bSEd Maste int
main(int argc,char ** argv)8979bfb05bSEd Maste main(int argc, char **argv)
9079bfb05bSEd Maste {
9179bfb05bSEd Maste 	GElf_Ehdr ehdr;
9279bfb05bSEd Maste 	Elf *elf;
9379bfb05bSEd Maste 	Elf_Kind kind;
94ba6d70a0SEd Maste 	int ch, fd, retval;
9579bfb05bSEd Maste 	char *features;
964a27bf12SMarcin Wojtas 	bool editfeatures, lflag, endian_swap;
9779bfb05bSEd Maste 
9879bfb05bSEd Maste 	lflag = 0;
99ba6d70a0SEd Maste 	editfeatures = false;
10079bfb05bSEd Maste 	retval = 0;
101fdafb99dSKyle Evans 	features = NULL;
10279bfb05bSEd Maste 
10379bfb05bSEd Maste 	if (elf_version(EV_CURRENT) == EV_NONE)
10479bfb05bSEd Maste 		errx(EXIT_FAILURE, "elf_version error");
10579bfb05bSEd Maste 
106f6d95a01SEd Maste 	while ((ch = getopt_long(argc, argv, "hile:", long_opts, NULL)) != -1) {
10779bfb05bSEd Maste 		switch (ch) {
108f6d95a01SEd Maste 		case 'i':
109f6d95a01SEd Maste 			iflag = true;
110f6d95a01SEd Maste 			break;
11179bfb05bSEd Maste 		case 'l':
11279bfb05bSEd Maste 			print_features();
11379bfb05bSEd Maste 			lflag = true;
11479bfb05bSEd Maste 			break;
11579bfb05bSEd Maste 		case 'e':
116f0cf9b60SEd Maste 			if (features != NULL)
117f0cf9b60SEd Maste 				errx(1, "-e may be specified only once");
11879bfb05bSEd Maste 			features = optarg;
119ba6d70a0SEd Maste 			editfeatures = true;
12079bfb05bSEd Maste 			break;
12179bfb05bSEd Maste 		case 'h':
12279bfb05bSEd Maste 		default:
12379bfb05bSEd Maste 			usage();
12479bfb05bSEd Maste 		}
12579bfb05bSEd Maste 	}
12679bfb05bSEd Maste 	argc -= optind;
12779bfb05bSEd Maste 	argv += optind;
12879bfb05bSEd Maste 	if (argc == 0) {
12979bfb05bSEd Maste 		if (lflag)
13079bfb05bSEd Maste 			exit(0);
13179bfb05bSEd Maste 		else {
13279bfb05bSEd Maste 			warnx("no file(s) specified");
13379bfb05bSEd Maste 			usage();
13479bfb05bSEd Maste 		}
13579bfb05bSEd Maste 	}
13679bfb05bSEd Maste 
13779bfb05bSEd Maste 	while (argc) {
13879bfb05bSEd Maste 		elf = NULL;
13979bfb05bSEd Maste 
14079bfb05bSEd Maste 		if ((fd = open(argv[0],
14179bfb05bSEd Maste 		    editfeatures ? O_RDWR : O_RDONLY, 0)) < 0) {
14279bfb05bSEd Maste 			warn("error opening file %s", argv[0]);
14379bfb05bSEd Maste 			retval = 1;
14479bfb05bSEd Maste 			goto fail;
14579bfb05bSEd Maste 		}
14679bfb05bSEd Maste 
14779bfb05bSEd Maste 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
14879bfb05bSEd Maste 			warnx("elf_begin failed: %s", elf_errmsg(-1));
14979bfb05bSEd Maste 			retval = 1;
15079bfb05bSEd Maste 			goto fail;
15179bfb05bSEd Maste 		}
15279bfb05bSEd Maste 
15379bfb05bSEd Maste 		if ((kind = elf_kind(elf)) != ELF_K_ELF) {
15479bfb05bSEd Maste 			if (kind == ELF_K_AR)
15579bfb05bSEd Maste 				warnx("file '%s' is an archive", argv[0]);
15679bfb05bSEd Maste 			else
15779bfb05bSEd Maste 				warnx("file '%s' is not an ELF file", argv[0]);
15879bfb05bSEd Maste 			retval = 1;
15979bfb05bSEd Maste 			goto fail;
16079bfb05bSEd Maste 		}
16179bfb05bSEd Maste 
16279bfb05bSEd Maste 		if (gelf_getehdr(elf, &ehdr) == NULL) {
16379bfb05bSEd Maste 			warnx("gelf_getehdr: %s", elf_errmsg(-1));
16479bfb05bSEd Maste 			retval = 1;
16579bfb05bSEd Maste 			goto fail;
16679bfb05bSEd Maste 		}
1674a27bf12SMarcin Wojtas 
1684a27bf12SMarcin Wojtas 		if (ehdr.e_ident[EI_DATA] == HOST_ENDIAN) {
1694a27bf12SMarcin Wojtas 			endian_swap = false;
1704a27bf12SMarcin Wojtas 		} else if (ehdr.e_ident[EI_DATA] == SWAP_ENDIAN) {
1714a27bf12SMarcin Wojtas 			endian_swap = true;
1724a27bf12SMarcin Wojtas 		} else {
1734a27bf12SMarcin Wojtas 			warnx("file endianness unknown");
17479bfb05bSEd Maste 			retval = 1;
17579bfb05bSEd Maste 			goto fail;
17679bfb05bSEd Maste 		}
17779bfb05bSEd Maste 
17879bfb05bSEd Maste 		if (!editfeatures) {
17979bfb05bSEd Maste 			if (!print_file_features(elf, ehdr.e_phnum, fd,
1804a27bf12SMarcin Wojtas 			    argv[0], endian_swap)) {
18179bfb05bSEd Maste 				retval = 1;
18279bfb05bSEd Maste 				goto fail;
18379bfb05bSEd Maste 			}
18479bfb05bSEd Maste 		} else if (!edit_file_features(elf, ehdr.e_phnum, fd,
1854a27bf12SMarcin Wojtas 		    features, endian_swap)) {
18679bfb05bSEd Maste 			retval = 1;
18779bfb05bSEd Maste 			goto fail;
18879bfb05bSEd Maste 		}
18979bfb05bSEd Maste fail:
19079bfb05bSEd Maste 		if (elf != NULL)
19179bfb05bSEd Maste 			elf_end(elf);
19279bfb05bSEd Maste 
19379bfb05bSEd Maste 		if (fd >= 0)
19479bfb05bSEd Maste 			close(fd);
19579bfb05bSEd Maste 
19679bfb05bSEd Maste 		argc--;
19779bfb05bSEd Maste 		argv++;
19879bfb05bSEd Maste 	}
19979bfb05bSEd Maste 
20079bfb05bSEd Maste 	return (retval);
20179bfb05bSEd Maste }
20279bfb05bSEd Maste 
20379bfb05bSEd Maste #define USAGE_MESSAGE \
20479bfb05bSEd Maste 	"\
20579bfb05bSEd Maste Usage: %s [options] file...\n\
20679bfb05bSEd Maste   Set or display the control features for an ELF object.\n\n\
20779bfb05bSEd Maste   Supported options are:\n\
20879bfb05bSEd Maste   -l                        List known control features.\n\
209f6d95a01SEd Maste   -i                        Ignore unknown features.\n\
21079bfb05bSEd Maste   -e [+-=]feature,list      Edit features from a comma separated list.\n\
21179bfb05bSEd Maste   -h | --help               Print a usage message and exit.\n"
21279bfb05bSEd Maste 
21379bfb05bSEd Maste static void
usage(void)21479bfb05bSEd Maste usage(void)
21579bfb05bSEd Maste {
21679bfb05bSEd Maste 
21779bfb05bSEd Maste 	fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());
21879bfb05bSEd Maste 	exit(1);
21979bfb05bSEd Maste }
22079bfb05bSEd Maste 
22179bfb05bSEd Maste static bool
convert_to_feature_val(const char * feature_str,uint32_t * feature_val)22282b611edSEd Maste convert_to_feature_val(const char *feature_str, uint32_t *feature_val)
22379bfb05bSEd Maste {
22482b611edSEd Maste 	char *feature, *feature_tmp;
22579bfb05bSEd Maste 	int i, len;
22687a920c0SEd Maste 	uint32_t input;
22779bfb05bSEd Maste 	char operation;
22879bfb05bSEd Maste 
22979bfb05bSEd Maste 	input = 0;
23079bfb05bSEd Maste 	operation = *feature_str;
23179bfb05bSEd Maste 	feature_str++;
232b8185579SEd Maste 
233b8185579SEd Maste 	if (operation != '+' && operation != '-' && operation != '=')
234b8185579SEd Maste 		errx(1, "'%c' not an operator - use '+', '-', '='", operation);
235b8185579SEd Maste 
23682b611edSEd Maste 	if ((feature_tmp = strdup(feature_str)) == NULL)
23782b611edSEd Maste 		err(1, "strdup");
23879bfb05bSEd Maste 	len = nitems(featurelist);
23982b611edSEd Maste 	while ((feature = strsep(&feature_tmp, ",")) != NULL) {
24079bfb05bSEd Maste 		for (i = 0; i < len; ++i) {
24179bfb05bSEd Maste 			if (strcmp(featurelist[i].alias, feature) == 0) {
24279bfb05bSEd Maste 				input |= featurelist[i].value;
24379bfb05bSEd Maste 				break;
24479bfb05bSEd Maste 			}
2453dfcb70bSEd Maste 			/* XXX Backwards compatibility for "no"-prefix flags. */
2463dfcb70bSEd Maste 			if (strncmp(featurelist[i].alias, "no", 2) == 0 &&
2473dfcb70bSEd Maste 			    strcmp(featurelist[i].alias + 2, feature) == 0) {
2483dfcb70bSEd Maste 				input |= featurelist[i].value;
2493dfcb70bSEd Maste 				warnx(
2503dfcb70bSEd Maste 				    "interpreting %s as %s; please specify %s",
2513dfcb70bSEd Maste 				    feature, featurelist[i].alias,
2523dfcb70bSEd Maste 				    featurelist[i].alias);
2533dfcb70bSEd Maste 				break;
2543dfcb70bSEd Maste 			}
25579bfb05bSEd Maste 		}
25679bfb05bSEd Maste 		if (i == len) {
25786f33b5fSEd Maste 			if (isdigit(feature[0])) {
25886f33b5fSEd Maste 				char *eptr;
2599940ac80SKonstantin Belousov 				unsigned long long val;
26086f33b5fSEd Maste 
26186f33b5fSEd Maste 				errno = 0;
2629940ac80SKonstantin Belousov 				val = strtoll(feature, &eptr, 0);
26386f33b5fSEd Maste 				if (eptr == feature || *eptr != '\0')
26486f33b5fSEd Maste 					errno = EINVAL;
2659940ac80SKonstantin Belousov 				else if (val > UINT32_MAX)
26686f33b5fSEd Maste 					errno = ERANGE;
26786f33b5fSEd Maste 				if (errno != 0) {
26886f33b5fSEd Maste 					warn("%s invalid", feature);
26982b611edSEd Maste 					free(feature_tmp);
27086f33b5fSEd Maste 					return (false);
27186f33b5fSEd Maste 				}
272f302fd1aSEd Maste 				input |= val;
27386f33b5fSEd Maste 			} else {
27479bfb05bSEd Maste 				warnx("%s is not a valid feature", feature);
27582b611edSEd Maste 				if (!iflag) {
27682b611edSEd Maste 					free(feature_tmp);
27779bfb05bSEd Maste 					return (false);
27879bfb05bSEd Maste 				}
27979bfb05bSEd Maste 			}
28086f33b5fSEd Maste 		}
28182b611edSEd Maste 	}
28279bfb05bSEd Maste 
28379bfb05bSEd Maste 	if (operation == '+') {
28479bfb05bSEd Maste 		*feature_val |= input;
28579bfb05bSEd Maste 	} else if (operation == '=') {
28679bfb05bSEd Maste 		*feature_val = input;
28779bfb05bSEd Maste 	} else if (operation == '-') {
28879bfb05bSEd Maste 		*feature_val &= ~input;
28979bfb05bSEd Maste 	}
29082b611edSEd Maste 	free(feature_tmp);
29179bfb05bSEd Maste 	return (true);
29279bfb05bSEd Maste }
29379bfb05bSEd Maste 
29479bfb05bSEd Maste static bool
edit_file_features(Elf * elf,int phcount,int fd,char * val,bool endian_swap)2954a27bf12SMarcin Wojtas edit_file_features(Elf *elf, int phcount, int fd, char *val, bool endian_swap)
29679bfb05bSEd Maste {
2973f2508b7SEd Maste 	uint32_t features, prev_features;
29887a920c0SEd Maste 	uint64_t off;
29979bfb05bSEd Maste 
3004a27bf12SMarcin Wojtas 	if (!get_file_features(elf, phcount, fd, &features, &off,
3014a27bf12SMarcin Wojtas 	    endian_swap)) {
30279bfb05bSEd Maste 		warnx("NT_FREEBSD_FEATURE_CTL note not found");
30379bfb05bSEd Maste 		return (false);
30479bfb05bSEd Maste 	}
30579bfb05bSEd Maste 
3063f2508b7SEd Maste 	prev_features = features;
30779bfb05bSEd Maste 	if (!convert_to_feature_val(val, &features))
30879bfb05bSEd Maste 		return (false);
3093f2508b7SEd Maste 	/* Avoid touching file if no change. */
3103f2508b7SEd Maste 	if (features == prev_features)
3113f2508b7SEd Maste 		return (true);
31279bfb05bSEd Maste 
3134a27bf12SMarcin Wojtas 	if (endian_swap)
3144a27bf12SMarcin Wojtas 		features = bswap32(features);
3154a27bf12SMarcin Wojtas 
31679bfb05bSEd Maste 	if (lseek(fd, off, SEEK_SET) == -1 ||
31779bfb05bSEd Maste 	    write(fd, &features, sizeof(features)) <
31879bfb05bSEd Maste 	    (ssize_t)sizeof(features)) {
31979bfb05bSEd Maste 		warnx("error writing feature value");
32079bfb05bSEd Maste 		return (false);
32179bfb05bSEd Maste 	}
32279bfb05bSEd Maste 	return (true);
32379bfb05bSEd Maste }
32479bfb05bSEd Maste 
32579bfb05bSEd Maste static void
print_features(void)32679bfb05bSEd Maste print_features(void)
32779bfb05bSEd Maste {
32879bfb05bSEd Maste 	size_t i;
32979bfb05bSEd Maste 
33079bfb05bSEd Maste 	printf("Known features are:\n");
33179bfb05bSEd Maste 	for (i = 0; i < nitems(featurelist); ++i)
33279bfb05bSEd Maste 		printf("%-16s%s\n", featurelist[i].alias,
33379bfb05bSEd Maste 		    featurelist[i].desc);
33479bfb05bSEd Maste }
33579bfb05bSEd Maste 
33679bfb05bSEd Maste static bool
print_file_features(Elf * elf,int phcount,int fd,char * filename,bool endian_swap)3374a27bf12SMarcin Wojtas print_file_features(Elf *elf, int phcount, int fd, char *filename,
3384a27bf12SMarcin Wojtas     bool endian_swap)
33979bfb05bSEd Maste {
34087a920c0SEd Maste 	uint32_t features;
34179bfb05bSEd Maste 	unsigned long i;
34279bfb05bSEd Maste 
3434a27bf12SMarcin Wojtas 	if (!get_file_features(elf, phcount, fd, &features, NULL,
3444a27bf12SMarcin Wojtas 	    endian_swap)) {
34579bfb05bSEd Maste 		return (false);
34679bfb05bSEd Maste 	}
34779bfb05bSEd Maste 
34879bfb05bSEd Maste 	printf("File '%s' features:\n", filename);
34979bfb05bSEd Maste 	for (i = 0; i < nitems(featurelist); ++i) {
35079bfb05bSEd Maste 		printf("%-16s'%s' is ", featurelist[i].alias,
35179bfb05bSEd Maste 		    featurelist[i].desc);
35279bfb05bSEd Maste 
35379bfb05bSEd Maste 		if ((featurelist[i].value & features) == 0)
35479bfb05bSEd Maste 			printf("un");
35579bfb05bSEd Maste 
35679bfb05bSEd Maste 		printf("set.\n");
35779bfb05bSEd Maste 	}
35879bfb05bSEd Maste 	return (true);
35979bfb05bSEd Maste }
36079bfb05bSEd Maste 
36179bfb05bSEd Maste static bool
get_file_features(Elf * elf,int phcount,int fd,uint32_t * features,uint64_t * off,bool endian_swap)36287a920c0SEd Maste get_file_features(Elf *elf, int phcount, int fd, uint32_t *features,
3634a27bf12SMarcin Wojtas     uint64_t *off, bool endian_swap)
36479bfb05bSEd Maste {
36579bfb05bSEd Maste 	GElf_Phdr phdr;
36679bfb05bSEd Maste 	Elf_Note note;
36779bfb05bSEd Maste 	unsigned long read_total;
36879bfb05bSEd Maste 	int namesz, descsz, i;
36979bfb05bSEd Maste 	char *name;
37079bfb05bSEd Maste 
37179bfb05bSEd Maste 	/*
37279bfb05bSEd Maste 	 * Go through each program header to find one that is of type PT_NOTE
37379bfb05bSEd Maste 	 * and has a note for feature control.
37479bfb05bSEd Maste 	 */
37579bfb05bSEd Maste 	for (i = 0; i < phcount; ++i) {
37679bfb05bSEd Maste 		if (gelf_getphdr(elf, i, &phdr) == NULL) {
37779bfb05bSEd Maste 			warnx("gelf_getphdr failed: %s", elf_errmsg(-1));
37879bfb05bSEd Maste 			return (false);
37979bfb05bSEd Maste 		}
38079bfb05bSEd Maste 
38179bfb05bSEd Maste 		if (phdr.p_type != PT_NOTE)
38279bfb05bSEd Maste 			continue;
38379bfb05bSEd Maste 
38479bfb05bSEd Maste 		if (lseek(fd, phdr.p_offset, SEEK_SET) < 0) {
38579bfb05bSEd Maste 			warn("lseek() failed:");
38679bfb05bSEd Maste 			return (false);
38779bfb05bSEd Maste 		}
38879bfb05bSEd Maste 
38979bfb05bSEd Maste 		read_total = 0;
39079bfb05bSEd Maste 		while (read_total < phdr.p_filesz) {
39176cd520dSEd Maste 			if (read(fd, &note, sizeof(note)) <
39276cd520dSEd Maste 			    (ssize_t)sizeof(note)) {
39376cd520dSEd Maste 				warnx("elf note header too short");
39479bfb05bSEd Maste 				return (false);
39579bfb05bSEd Maste 			}
39679bfb05bSEd Maste 			read_total += sizeof(note);
39779bfb05bSEd Maste 
3984a27bf12SMarcin Wojtas 			if (endian_swap) {
3994a27bf12SMarcin Wojtas 				note.n_namesz = bswap32(note.n_namesz);
4004a27bf12SMarcin Wojtas 				note.n_descsz = bswap32(note.n_descsz);
4014a27bf12SMarcin Wojtas 				note.n_type = bswap32(note.n_type);
4024a27bf12SMarcin Wojtas 			}
4034a27bf12SMarcin Wojtas 
40479bfb05bSEd Maste 			/*
40579bfb05bSEd Maste 			 * XXX: Name and descriptor are 4 byte aligned, however,
40679bfb05bSEd Maste 			 * the size given doesn't include the padding.
40779bfb05bSEd Maste 			 */
40879bfb05bSEd Maste 			namesz = roundup2(note.n_namesz, 4);
40979bfb05bSEd Maste 			name = malloc(namesz);
41079bfb05bSEd Maste 			if (name == NULL) {
41179bfb05bSEd Maste 				warn("malloc() failed.");
41279bfb05bSEd Maste 				return (false);
41379bfb05bSEd Maste 			}
41479bfb05bSEd Maste 			descsz = roundup2(note.n_descsz, 4);
41576cd520dSEd Maste 			if (read(fd, name, namesz) < namesz) {
41676cd520dSEd Maste 				warnx("elf note name too short");
417b7a9e9d6SEd Maste 				free(name);
41876cd520dSEd Maste 				return (false);
41976cd520dSEd Maste 			}
42079bfb05bSEd Maste 			read_total += namesz;
42179bfb05bSEd Maste 
42279bfb05bSEd Maste 			if (note.n_namesz != 8 ||
42379bfb05bSEd Maste 			    strncmp("FreeBSD", name, 7) != 0 ||
42479bfb05bSEd Maste 			    note.n_type != NT_FREEBSD_FEATURE_CTL) {
42579bfb05bSEd Maste 				/* Not the right note. Skip the description */
42679bfb05bSEd Maste 				if (lseek(fd, descsz, SEEK_CUR) < 0) {
42779bfb05bSEd Maste 					warn("lseek() failed.");
42879bfb05bSEd Maste 					free(name);
42979bfb05bSEd Maste 					return (false);
43079bfb05bSEd Maste 				}
43179bfb05bSEd Maste 				read_total += descsz;
43279bfb05bSEd Maste 				free(name);
43379bfb05bSEd Maste 				continue;
43479bfb05bSEd Maste 			}
43579bfb05bSEd Maste 
43687a920c0SEd Maste 			if (note.n_descsz < sizeof(uint32_t)) {
43779bfb05bSEd Maste 				warnx("Feature descriptor can't "
43879bfb05bSEd Maste 				    "be less than 4 bytes");
43979bfb05bSEd Maste 				free(name);
44079bfb05bSEd Maste 				return (false);
44179bfb05bSEd Maste 			}
44279bfb05bSEd Maste 
44379bfb05bSEd Maste 			/*
44479bfb05bSEd Maste 			 * XXX: For now we look at only 4 bytes of the
44579bfb05bSEd Maste 			 * descriptor. This should respect descsz.
44679bfb05bSEd Maste 			 */
44787a920c0SEd Maste 			if (note.n_descsz > sizeof(uint32_t))
44879bfb05bSEd Maste 				warnx("Feature note is bigger than expected");
44976cd520dSEd Maste 			if (read(fd, features, sizeof(uint32_t)) <
45076cd520dSEd Maste 			    (ssize_t)sizeof(uint32_t)) {
45176cd520dSEd Maste 				warnx("feature note data too short");
452b7a9e9d6SEd Maste 				free(name);
45376cd520dSEd Maste 				return (false);
45476cd520dSEd Maste 			}
4554a27bf12SMarcin Wojtas 			if (endian_swap)
4564a27bf12SMarcin Wojtas 				*features = bswap32(*features);
45779bfb05bSEd Maste 			if (off != NULL)
45879bfb05bSEd Maste 				*off = phdr.p_offset + read_total;
45979bfb05bSEd Maste 			free(name);
46079bfb05bSEd Maste 			return (true);
46179bfb05bSEd Maste 		}
46279bfb05bSEd Maste 	}
46379bfb05bSEd Maste 
46479bfb05bSEd Maste 	warnx("NT_FREEBSD_FEATURE_CTL note not found");
46579bfb05bSEd Maste 	return (false);
46679bfb05bSEd Maste }
467