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, ¬e, 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