diff options
Diffstat (limited to 'util/nvmutil')
| -rw-r--r-- | util/nvmutil/Makefile | 23 | ||||
| -rw-r--r-- | util/nvmutil/nvmutil.c | 186 |
2 files changed, 134 insertions, 75 deletions
diff --git a/util/nvmutil/Makefile b/util/nvmutil/Makefile index b8ec2ad3..91b5ba1c 100644 --- a/util/nvmutil/Makefile +++ b/util/nvmutil/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: MIT -# SPDX-FileCopyrightText: 2022,2025 Leah Rowe <leah@libreboot.org> +# SPDX-FileCopyrightText: 2022,2026 Leah Rowe <leah@libreboot.org> # SPDX-FileCopyrightText: 2023 Riku Viitanen <riku.viitanen@protonmail.com> CC?=cc @@ -8,17 +8,28 @@ DESTDIR?= PREFIX?=/usr/local INSTALL?=install +# nvm is the old binary name, +# but it was renamed to nvmutil +# to avoid conflict with a certain +# package manager by that name! + nvm: nvmutil.c - $(CC) $(CFLAGS) nvmutil.c -o nvm + rm -f nvm + $(CC) $(CFLAGS) nvmutil.c -o nvmutil install: - $(INSTALL) nvm $(DESTDIR)$(PREFIX)/bin/nvm + $(INSTALL) nvmutil $(DESTDIR)$(PREFIX)/bin/nvmutil + +# do not delete *bin/nvm because +# there is a package manager by +# that name. this makefile now +# treats nvmutil as the binary uninstall: - rm -f $(DESTDIR)$(PREFIX)/bin/nvm + rm -f $(DESTDIR)$(PREFIX)/bin/nvmutil distclean: - rm -f nvm + rm -f nvm nvmutil clean: - rm -f nvm + rm -f nvm nvmutil diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c index 3a374e6c..c6193d9e 100644 --- a/util/nvmutil/nvmutil.c +++ b/util/nvmutil/nvmutil.c @@ -30,6 +30,7 @@ static void set_cmd(int argc, char *argv[]); static void check_cmd_args(int argc, char *argv[]); static size_t conv_argv_part_num(const char *part_str); +static void run_cmd(ssize_t c); static void set_io_flags(int argc, char *argv[]); static void open_gbe_file(void); #ifndef HAVE_ARC4RANDOM_BUF @@ -37,7 +38,7 @@ static void open_dev_urandom(void); #endif static void xopen(int *fd, const char *path, int flags, struct stat *st); static void read_gbe_file(void); -static void read_gbe_file_part(size_t part, uint8_t invert); +static void read_gbe_file_part(size_t part); static void cmd_setmac(void); static void parse_mac_string(void); static void set_mac_byte(size_t mac_byte_pos); @@ -49,7 +50,7 @@ static void read_file_exact(int fd, void *buf, size_t len, off_t off, const char *path, const char *op); static int write_mac_part(size_t partnum); static void cmd_dump(void); -static void print_mac_address(size_t partnum); +static void print_mac_from_nvm(size_t partnum); static void hexdump(size_t partnum); static void cmd_setchecksum(void); static void set_checksum(size_t part); @@ -139,7 +140,6 @@ static int urandom_fd = -1; #endif static int gbe_fd = -1; static size_t part; -static uint8_t invert; static uint8_t part_modified[2]; static const char *mac_str; @@ -147,21 +147,54 @@ static const char rmac[] = "xx:xx:xx:xx:xx:xx"; static const char *fname; static const char *argv0; +#define PART_INVERT 1 +#define NO_INVERT 0 +#define ARGC_3 3 +#define ARGC_4 4 + +/* + * Used as indices for command[] + * + * MUST be in the same order as entries in + * command[] - or run_cmd() will detect this, + * and cause a non-zero exit (err). + */ +enum { + CMD_DUMP, + CMD_SETMAC, + CMD_SWAP, + CMD_COPY, + CMD_BRICK, + CMD_SETCHECKSUM +}; +#define CMD_NULL -1 + struct commands { + size_t chk; /* use by in later check on run_cmd, + against cmd index, to verify correct enum order */ const char *str; - void (*cmd)(void); - int args; + void (*run)(void); + int argc; + uint8_t invert; }; + +/* + * Pointers used for running nvmutil commands + */ static const struct commands command[] = { - { "dump", cmd_dump, 3 }, - { "setmac", cmd_setmac, 3 }, - { "swap", cmd_swap, 3 }, - { "copy", cmd_copy, 4 }, - { "brick", cmd_brick, 4 }, - { "setchecksum", cmd_setchecksum, 4 }, + { CMD_DUMP, "dump", cmd_dump, ARGC_3, NO_INVERT }, + { CMD_SETMAC, "setmac", cmd_setmac, ARGC_3, NO_INVERT }, + { CMD_SWAP, "swap", cmd_swap, ARGC_3, PART_INVERT }, + { CMD_COPY, "copy", cmd_copy, ARGC_4, PART_INVERT }, + { CMD_BRICK, "brick", cmd_brick, ARGC_4, NO_INVERT }, + { CMD_SETCHECKSUM, "setchecksum", cmd_setchecksum, + ARGC_4, NO_INVERT }, }; -static void (*cmd)(void) = NULL; +/* + * Index in command[], will be set later + */ +static ssize_t cmd = CMD_NULL; int main(int argc, char *argv[]) @@ -179,18 +212,16 @@ main(int argc, char *argv[]) /* * For restricted filesystem access on early error. * - * Unveiling the random device early, regardless of - * whether we will use it, prevents operations on any - * GbE files until we permit it, while performing the - * prerequisite error checks. + * This prevents access to /dev/urandom, which we + * should never use in OpenBSD (we use arc4random), + * thus guarding against any future bugs there. * - * We don't actually use the random device on platforms - * that have arc4random, which includes OpenBSD. + * This also prevents early reads to the GbE file, + * while performing other checks; we will later + * unveil the GbE file, to allow access. */ - if (unveil("/dev/urandom", "r") == -1) - err(ECANCELED, "unveil '/dev/urandom'"); - if (unveil("/dev/random", "r") == -1) - err(ECANCELED, "unveil '/dev/random'"); + if (unveil("/dev/null", "r") == -1) + err(ECANCELED, "unveil '/dev/null'"); #endif set_cmd(argc, argv); @@ -215,8 +246,12 @@ main(int argc, char *argv[]) } #endif -#ifndef HAVE_ARC4RANDOM_BUF - open_dev_urandom(); +#ifdef HAVE_ARC4RANDOM_BUF + if (cmd == CMD_SETMAC) + printf("Randomisation method: arc4random_buf\n"); +#else + if (cmd == CMD_SETMAC) + open_dev_urandom(); #endif open_gbe_file(); @@ -226,14 +261,16 @@ main(int argc, char *argv[]) #endif read_gbe_file(); - (*cmd)(); + run_cmd(cmd); write_gbe_file(); if (close(gbe_fd) == -1) err(ECANCELED, "close '%s'", fname); #ifndef HAVE_ARC4RANDOM_BUF - if (close(urandom_fd) == -1) - err(ECANCELED, "close '%s'", rname); + if (urandom_fd > -1) { + if (close(urandom_fd) == -1) + err(ECANCELED, "close '%s'", rname); + } #endif /* @@ -249,7 +286,7 @@ main(int argc, char *argv[]) * However, if we're not using cmd_dump, then * we have a bug somewhere in the code. */ - if (cmd != cmd_dump) { + if (cmd != CMD_DUMP) { if (errno) err(ECANCELED, "Unhandled error on exit"); } @@ -263,14 +300,12 @@ main(int argc, char *argv[]) static void set_cmd(int argc, char *argv[]) { - size_t i; - /* * No extra args: ./nvmutil gbe.bin * Equivalent: ./nvmutil gbe.bin setmac xx:xx:xx:xx:xx:xx */ if (argc == 2) { - cmd = cmd_setmac; + cmd = CMD_SETMAC; return; } @@ -278,43 +313,44 @@ set_cmd(int argc, char *argv[]) * Three or more args. * Example: ./nvmutil gbe.bin copy 0 */ - for (i = 0; i < items(command); i++) { - if (strcmp(argv[2], command[i].str) != 0) + for (cmd = 0; cmd < (ssize_t)items(command); cmd++) { + if (strcmp(argv[2], command[cmd].str) != 0) continue; - if (argc >= command[i].args) { - cmd = command[i].cmd; - break; + if (argc >= command[cmd].argc) { + return; } - err(EINVAL, "Too few args: command '%s'", command[i].str); + err(EINVAL, "Too few args: command '%s'", command[cmd].str); } + + cmd = CMD_NULL; } static void check_cmd_args(int argc, char *argv[]) { - if (cmd == NULL && argc > 2) { + if (cmd == CMD_NULL && argc > 2) { /* * Example: ./nvmutil gbe.bin xx:1f:16:xx:xx:xx * Equivalent ./nvmutil gbe.bin setmac xx:1f:16:xx:xx:xx */ mac_str = argv[2]; - cmd = cmd_setmac; - } else if (cmd == cmd_setmac) { + cmd = CMD_SETMAC; + } else if (cmd == CMD_SETMAC) { /* * Example: ./nvmutil gbe.bin setmac xx:1f:16:xx:xx:xx */ mac_str = rmac; /* random MAC */ if (argc > 3) mac_str = argv[3]; - } else if (cmd != NULL && argc > 3) { /* user-supplied partnum */ + } else if (cmd != CMD_NULL && argc > 3) { /* user-supplied partnum */ /* * Example: ./nvmutil gbe.bin copy 0 */ part = conv_argv_part_num(argv[3]); } - if (cmd == NULL) + if (cmd == CMD_NULL) err(EINVAL, "Bad command"); } @@ -340,6 +376,21 @@ conv_argv_part_num(const char *part_str) } static void +run_cmd(ssize_t c) +{ + size_t d = (size_t)c; + + if (d >= items(command)) + err(ECANCELED, "run_cmd: Invalid run_cmd arg: %zd", c); + + if (d != command[d].chk) + err(ECANCELED, "run_cmd: Invalid chk value (%zu) vs arg: %zd", + command[d].chk, c); + + command[d].run(); +} + +static void set_io_flags(int argc, char *argv[]) { gbe_flags = O_RDWR; @@ -357,6 +408,8 @@ open_dev_urandom(void) { struct stat st_urandom_fd; + printf("Randomisation method: %s\n", newrandom); + /* * Try /dev/urandom first */ @@ -364,6 +417,9 @@ open_dev_urandom(void) if ((urandom_fd = open(rname, O_RDONLY)) != -1) return; + fprintf(stderr, "Can't open %s (will use %s instead)\n", + newrandom, oldrandom); + /* * Fall back to /dev/random on old platforms * where /dev/urandom does not exist. @@ -418,36 +474,23 @@ read_gbe_file(void) * * We can skip reading the other part, thus: */ - if (cmd == cmd_copy || - cmd == cmd_brick || - cmd == cmd_setchecksum) + if (cmd == CMD_COPY || + cmd == CMD_BRICK || + cmd == CMD_SETCHECKSUM) do_read[part ^ 1] = 0; - /* - * SPEED HACK: - * - * On copy/swap commands, flip where data gets written to memory, - * so that cmd_copy and cmd_swap don't have to work on every word - * - * NOTE: - * - * write_gbe_file() will not use this, but copy/setchecksum commands - * will directly manipulate part_modified[], telling write_gbe_file() - * to also write in reverse, as in read_gbe_file(). - */ - if (cmd == cmd_copy || cmd == cmd_swap) - invert = 1; - for (p = 0; p < 2; p++) { if (do_read[p]) - read_gbe_file_part(p, invert); + read_gbe_file_part(p); } } static void -read_gbe_file_part(size_t p, uint8_t invert) +read_gbe_file_part(size_t p) { - read_file_exact(gbe_fd, gbe_mem_offset(p ^ invert, "pread"), + void *mem_offset = gbe_mem_offset(p ^ command[cmd].invert, "pread"); + + read_file_exact(gbe_fd, mem_offset, GBE_PART_SIZE, gbe_file_offset(p, "pread"), fname, "pread"); } @@ -457,8 +500,8 @@ cmd_setmac(void) size_t partnum; uint8_t mac_updated = 0; - parse_mac_string(); printf("MAC address to be written: %s\n", mac_str); + parse_mac_string(); for (partnum = 0; partnum < 2; partnum++) mac_updated |= write_mac_part(partnum); @@ -587,6 +630,9 @@ read_file_exact(int fd, void *buf, size_t len, int retry; ssize_t rval; + if (fd == -1) + err(ECANCELED, "Trying to open bad fd: %s", path); + for (retry = 0; retry < MAX_RETRY_READ; retry++) { if (op) rval = pread(fd, buf, len, off); @@ -625,7 +671,7 @@ write_mac_part(size_t partnum) set_word(w, partnum, mac_buf[w]); printf("Wrote MAC address to part %zu: ", partnum); - print_mac_address(partnum); + print_mac_from_nvm(partnum); set_checksum(partnum); @@ -643,7 +689,7 @@ cmd_dump(void) ++num_invalid; printf("MAC (part %zu): ", partnum); - print_mac_address(partnum); + print_mac_from_nvm(partnum); hexdump(partnum); } @@ -652,7 +698,7 @@ cmd_dump(void) } static void -print_mac_address(size_t partnum) +print_mac_from_nvm(size_t partnum) { size_t c; @@ -776,7 +822,7 @@ good_checksum(size_t partnum) return 1; fprintf(stderr, "WARNING: BAD checksum in part %zu\n", - partnum ^ invert); + partnum ^ command[cmd].invert); set_err(ECANCELED); return 0; @@ -875,8 +921,10 @@ write_gbe_file_part(size_t p) static off_t gbe_file_offset(size_t p, const char *f_op) { + off_t gbe_file_half_size = gbe_file_size >> 1; + return gbe_x_offset(p, f_op, "file", - gbe_file_size >> 1, gbe_file_size); + gbe_file_half_size, gbe_file_size); } /* |
