diff options
| -rw-r--r-- | include/inject.sh | 6 | ||||
| -rw-r--r-- | util/nvmutil/Makefile | 23 | ||||
| -rw-r--r-- | util/nvmutil/nvmutil.c | 240 |
3 files changed, 166 insertions, 103 deletions
diff --git a/include/inject.sh b/include/inject.sh index 6a1b0768..783e06ed 100644 --- a/include/inject.sh +++ b/include/inject.sh @@ -6,7 +6,7 @@ cbcfgsdir="config/coreboot" tmpromdel="$XBMK_CACHE/DO_NOT_FLASH" -nvm="util/nvmutil/nvm" +nvmutil="util/nvmutil/nvmutil" ifdtool="elf/coreboot/default/ifdtool" checkvars="CONFIG_GBE_BIN_PATH" @@ -200,13 +200,13 @@ modify_mac() x_ make -C util/nvmutil clean x_ make -C util/nvmutil - x_ "$nvm" "$xbtmp/gbe" setmac "$new_mac" + x_ "$nvmutil" "$xbtmp/gbe" setmac "$new_mac" fi fx_ newmac x_ find "$tmpromdir" -maxdepth 1 -type f -name "*.rom" printf "\nThe following GbE NVM data will be written:\n" - x_ "$nvm" "$xbtmp/gbe" dump | grep -v "bytes read from file" || : + x_ "$nvmutil" "$xbtmp/gbe" dump | grep -v "bytes read from file" || : } newmac() 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 7bd61704..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,19 +38,19 @@ 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); static void set_mac_nib(size_t mac_str_pos, size_t mac_byte_pos, size_t mac_nib_pos); -static uint8_t hextonum(char ch_s); -static uint8_t rhex(void); +static uint16_t hextonum(char ch_s); +static uint16_t rhex(void); 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); @@ -108,14 +109,14 @@ static void set_err(int errval); #define MAX_RETRY_READ 30 /* - * Portably macro based on BSD nitems. + * Portable macro based on BSD nitems. * Used to count the number of commands (see below). */ #define items(x) (sizeof((x)) / sizeof((x)[0])) +#ifndef HAVE_ARC4RANDOM_BUF static const char newrandom[] = "/dev/urandom"; static const char oldrandom[] = "/dev/random"; /* fallback on OLD unix */ -#ifndef HAVE_ARC4RANDOM_BUF static const char *rname = NULL; #endif @@ -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: ./nvm gbe.bin setmac xx:xx:xx:xx:xx:xx + * 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"); } @@ -331,10 +367,27 @@ conv_argv_part_num(const char *part_str) if (part_str[0] == '\0' || part_str[1] != '\0') err(EINVAL, "Partnum string '%s' wrong length", part_str); - ch = (unsigned char)part_str[0] - '0'; + ch = (unsigned char)part_str[0]; + + if (ch < '0' || ch > '1') + err(EINVAL, "Bad part number (%c)", ch); + + return (size_t)(ch - '0'); +} + +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); - check_part_num((size_t)ch); - return (size_t)ch; + command[d].run(); } static void @@ -355,21 +408,29 @@ open_dev_urandom(void) { struct stat st_urandom_fd; + printf("Randomisation method: %s\n", newrandom); + + /* + * Try /dev/urandom first + */ rname = newrandom; + if ((urandom_fd = open(rname, O_RDONLY)) != -1) + return; - if ((urandom_fd = open(rname, O_RDONLY)) == -1) { - /* - * Fall back to /dev/random on old platforms - * where /dev/urandom does not exist. - * - * We must reset the error condition first, - * to prevent stale error status later. - */ - errno = 0; + fprintf(stderr, "Can't open %s (will use %s instead)\n", + newrandom, oldrandom); - rname = oldrandom; - xopen(&urandom_fd, rname, O_RDONLY, &st_urandom_fd); - } + /* + * Fall back to /dev/random on old platforms + * where /dev/urandom does not exist. + * + * We must reset the error condition first, + * to prevent stale error status later. + */ + errno = 0; + + rname = oldrandom; + xopen(&urandom_fd, rname, O_RDONLY, &st_urandom_fd); } #endif @@ -413,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"); } @@ -452,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); @@ -508,8 +556,7 @@ set_mac_nib(size_t mac_str_pos, mac_ch = mac_str[mac_str_pos + mac_nib_pos]; - hex_num = hextonum(mac_ch); - if (hex_num > 15) + if ((hex_num = hextonum(mac_ch)) > 15) err(EINVAL, "Invalid character '%c'", mac_str[mac_str_pos + mac_nib_pos]); @@ -535,7 +582,7 @@ set_mac_nib(size_t mac_str_pos, | ((mac_nib_pos ^ 1) << 2)); /* left or right nib? */ } -static uint8_t +static uint16_t hextonum(char ch_s) { /* @@ -558,7 +605,7 @@ hextonum(char ch_s) return 16; /* invalid character */ } -static uint8_t +static uint16_t rhex(void) { static size_t n = 0; @@ -573,7 +620,7 @@ rhex(void) #endif } - return rnum[--n] & 0xf; + return (uint16_t)(rnum[--n] & 0xf); } static void @@ -583,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); @@ -621,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); @@ -639,7 +689,7 @@ cmd_dump(void) ++num_invalid; printf("MAC (part %zu): ", partnum); - print_mac_address(partnum); + print_mac_from_nvm(partnum); hexdump(partnum); } @@ -648,7 +698,7 @@ cmd_dump(void) } static void -print_mac_address(size_t partnum) +print_mac_from_nvm(size_t partnum) { size_t c; @@ -772,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; @@ -871,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); } /* |
