diff options
Diffstat (limited to 'util/nvmutil/nvmutil.c')
| -rw-r--r-- | util/nvmutil/nvmutil.c | 762 |
1 files changed, 393 insertions, 369 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c index 21fb8bdd..3bae308f 100644 --- a/util/nvmutil/nvmutil.c +++ b/util/nvmutil/nvmutil.c @@ -1,10 +1,32 @@ -/* SPDX-License-Identifier: MIT */ -/* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org> */ -/* Copyright (c) 2023 Riku Viitanen <riku.viitanen@protonmail.com> */ +/* SPDX-License-Identifier: MIT + * + * Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org> + * Copyright (c) 2023 Riku Viitanen <riku.viitanen@protonmail.com> + * + * This tool lets you modify Intel GbE NVM (Gigabit Ethernet + * Non-Volatile Memory) images, e.g. change the MAC address. + * These images configure your Intel Gigabit Ethernet adapter. + * + * This code is designed to be portable, running on as many + * Unix and Unix-like systems as possible (mainly BSD/Linux). + * + * Recommended CFLAGS for Clang/GCC: + * + * -Os -Wall -Wextra -Werror -pedantic -std=c99 + */ + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE 500 +#endif + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif #ifdef __OpenBSD__ #include <sys/param.h> #endif +#include <sys/types.h> #include <sys/stat.h> #include <errno.h> @@ -16,17 +38,26 @@ #include <string.h> #include <unistd.h> +#if __STDC_VERSION__ >= 201112L +_Static_assert(sizeof(uint16_t) == 2, "uint16_t must be 16 bits"); +#else +typedef char static_assert_uint16_t_is_2[(sizeof(uint16_t) == 2) ? 1 : -1]; +#endif + /* * The BSD versions that could realistically build * nvmutil almost certainly have arc4random (first - * introduced in 1990s or early 2000s in most of - * them - you can just patch as needed, on old BSD. + * introduced in 1990s to early 2000s). + * + * If you want it on another platform, e.g. Linux, + * just patch this accordingly. Or patch it to remove + * arc4random on old/weird Unix systems. */ #if defined(__OpenBSD__) || defined(__FreeBSD__) || \ defined(__NetBSD__) || defined(__APPLE__) || \ defined(__DragonFly__) -#ifndef HAVE_ARC4RANDOM_BUF -#define HAVE_ARC4RANDOM_BUF 1 +#ifndef NVMUTIL_ARC4RANDOM_BUF +#define NVMUTIL_ARC4RANDOM_BUF 1 #endif #endif @@ -52,59 +83,62 @@ static void sanitize_command_list(void); static void sanitize_command_index(size_t c); -static void check_bin(size_t a, const char *a_name); static void check_enum_bin(size_t a, const char *a_name, size_t b, const char *b_name); static void set_cmd(int argc, char *argv[]); static void set_cmd_args(int argc, char *argv[]); static size_t conv_argv_part_num(const char *part_str); -static void run_cmd(size_t c); -static void check_command_num(size_t c); -static uint8_t valid_command(size_t c); static void set_io_flags(int argc, char *argv[]); -static void open_gbe_file(void); -#ifndef HAVE_ARC4RANDOM_BUF +static int xstrxcmp(const char *a, const char *b, size_t maxlen); +#ifndef NVMUTIL_ARC4RANDOM_BUF static void open_dev_urandom(void); #endif +static void open_gbe_file(void); 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); +static ssize_t read_gbe_file_exact(int fd, void *buf, size_t len, + off_t off); static void read_checksums(void); -static void cmd_setmac(void); +static int good_checksum(size_t partnum); +static void run_cmd(size_t c); +static void check_command_num(size_t c); +static uint8_t valid_command(size_t c); +static void cmd_helper_setmac(void); static void parse_mac_string(void); +static size_t xstrxlen(const char *scmp, size_t maxlen); 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 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); +#ifndef NVMUTIL_ARC4RANDOM_BUF +static ssize_t read_dev_urandom(int fd, void *buf, + size_t len); +#endif static void write_mac_part(size_t partnum); -static void cmd_dump(void); +static void cmd_helper_dump(void); static void print_mac_from_nvm(size_t partnum); static void hexdump(size_t partnum); -static void cmd_setchecksum(void); +static void write_gbe_file(void); +static void override_part_modified(void); static void set_checksum(size_t part); -static void cmd_brick(void); -static int good_checksum(size_t partnum); +static uint16_t calculated_checksum(size_t p); static uint16_t nvm_word(size_t pos16, size_t part); static void set_nvm_word(size_t pos16, size_t part, uint16_t val16); +static void set_part_modified(size_t p); static void check_nvm_bound(size_t pos16, size_t part); -static void write_gbe_file(void); -static void override_part_modified(void); +static void check_bin(size_t a, const char *a_name); static void write_gbe_file_part(size_t part); static off_t gbe_file_offset(size_t part, const char *f_op); static void *gbe_mem_offset(size_t part, const char *f_op); static off_t gbe_x_offset(size_t part, const char *f_op, const char *d_type, off_t nsize, off_t ncmp); -static void set_part_modified(size_t p); -static void usage(uint8_t usage_exit); -static size_t xstrxlen(const char *scmp, size_t maxlen); -static int xstrxcmp(const char *a, const char *b, size_t maxlen); static void err(int nvm_errval, const char *msg, ...); +static void close_files(void); static const char *getnvmprogname(void); static void set_err(int errval); -static void close_files(void); +static void usage(uint8_t usage_exit); /* * Sizes in bytes: @@ -146,7 +180,7 @@ static void close_files(void); */ #define items(x) (sizeof((x)) / sizeof((x)[0])) -#ifndef HAVE_ARC4RANDOM_BUF +#ifndef NVMUTIL_ARC4RANDOM_BUF static const char newrandom[] = "/dev/urandom"; static const char oldrandom[] = "/dev/random"; /* fallback on OLD unix */ static const char *rname = NULL; @@ -167,7 +201,7 @@ static uint16_t mac_buf[3]; static off_t gbe_file_size; static int gbe_flags; -#ifndef HAVE_ARC4RANDOM_BUF +#ifndef NVMUTIL_ARC4RANDOM_BUF static int urandom_fd = -1; #endif static int gbe_fd = -1; @@ -202,8 +236,6 @@ enum { CMD_SETMAC, CMD_SWAP, CMD_COPY, - CMD_BRICK, - CMD_SETCHECKSUM }; /* @@ -250,13 +282,17 @@ struct commands { * Command table, for nvmutil commands */ static const struct commands command[] = { - { CMD_DUMP, "dump", cmd_dump, ARGC_3, + /* + * Unlike older versions, we require at least + * one checksum to be valid when running dump. + */ + { CMD_DUMP, "dump", cmd_helper_dump, ARGC_3, NO_INVERT, SET_MOD_OFF, ARG_NOPART, - SKIP_CHECKSUM_READ, SKIP_CHECKSUM_WRITE, + CHECKSUM_READ, SKIP_CHECKSUM_WRITE, NVM_SIZE }, - { CMD_SETMAC, "setmac", cmd_setmac, ARGC_3, + { CMD_SETMAC, "setmac", cmd_helper_setmac, ARGC_3, NO_INVERT, SET_MOD_OFF, ARG_NOPART, CHECKSUM_READ, CHECKSUM_WRITE, @@ -280,24 +316,6 @@ static const struct commands command[] = { ARG_PART, CHECKSUM_READ, SKIP_CHECKSUM_WRITE, GBE_PART_SIZE }, - - /* - * The non-target part will not be read. - */ - { CMD_BRICK, "brick", cmd_brick, ARGC_4, - NO_INVERT, SET_MOD_OFF, - ARG_PART, - CHECKSUM_READ, SKIP_CHECKSUM_WRITE, - NVM_SIZE }, - - /* - * The non-target part will not be read. - */ - { CMD_SETCHECKSUM, "setchecksum", cmd_setchecksum, ARGC_4, - NO_INVERT, SET_MOD_OFF, - ARG_PART, - SKIP_CHECKSUM_READ, CHECKSUM_WRITE, - NVM_SIZE }, }; #define MAX_CMD_LEN 50 @@ -313,7 +331,7 @@ int main(int argc, char *argv[]) { argv0 = argv[0]; - if (argc < 2) + if (argc < 3) usage(1); fname = argv[1]; @@ -340,14 +358,14 @@ main(int argc, char *argv[]) #ifdef NVMUTIL_UNVEIL if (gbe_flags == O_RDONLY) { if (unveil(fname, "r") == -1) - err(ECANCELED, "unveil ro '%s'", fname); + err(ECANCELED, "%s: unveil ro", fname); if (unveil(NULL, NULL) == -1) err(ECANCELED, "unveil block (ro)"); if (pledge("stdio rpath", NULL) == -1) err(ECANCELED, "pledge ro (kill unveil)"); } else { if (unveil(fname, "rw") == -1) - err(ECANCELED, "unveil rw '%s'", fname); + err(ECANCELED, "%s: unveil rw", fname); if (unveil(NULL, NULL) == -1) err(ECANCELED, "unveil block (rw)"); if (pledge("stdio rpath wpath", NULL) == -1) @@ -361,7 +379,7 @@ main(int argc, char *argv[]) #endif #endif -#ifndef HAVE_ARC4RANDOM_BUF +#ifndef NVMUTIL_ARC4RANDOM_BUF #if defined(__OpenBSD__) || defined(__FreeBSD__) || \ defined(__NetBSD__) || defined(__APPLE__) || \ defined(__DragonFly__) @@ -383,7 +401,7 @@ main(int argc, char *argv[]) run_cmd(cmd_index); if (errno) - err(errno, "Unhandled error: will not write file: %s", fname); + err(errno, "%s: Unhandled error (WRITE SKIPPED)", fname); else if (gbe_flags != O_RDONLY) write_gbe_file(); @@ -415,8 +433,13 @@ sanitize_command_index(size_t c) check_command_num(c); - if (command[c].argc < 2) - err(ECANCELED, "cmd index %zu: argc below 2, %d", + if (ARGC_3 != 3) + err(ECANCELED, "ARGC_3 is not equal to 3"); + if (ARGC_4 != 4) + err(ECANCELED, "ARGC_4 is not equal to 4"); + + if (command[c].argc < 3) + err(ECANCELED, "cmd index %zu: argc below 3, %d", c, command[c].argc); if (command[c].str == NULL) @@ -482,19 +505,17 @@ check_enum_bin(size_t a, const char *a_name, static void set_cmd(int argc, char *argv[]) { + const char *cmd_str; + for (cmd_index = 0; valid_command(cmd_index); cmd_index++) { - if (argc < 3) - break; + cmd_str = command[cmd_index].str; - if (xstrxcmp(argv[2], command[cmd_index].str, - MAX_CMD_LEN) != 0) + if (xstrxcmp(argv[2], cmd_str, MAX_CMD_LEN) != 0) continue; - - if (argc >= command[cmd_index].argc) + else if (argc >= command[cmd_index].argc) return; - err(EINVAL, "Too few args: command '%s'", - command[cmd_index].str); + err(EINVAL, "Too few args on command '%s'", cmd_str); } cmd_index = CMD_NULL; @@ -503,45 +524,25 @@ set_cmd(int argc, char *argv[]) static void set_cmd_args(int argc, char *argv[]) { - if (cmd_index == CMD_SETMAC && argc >= 4) { - /* - * 4th arg e.g.: ./nvmutil gbe.bin setmac 00:xx:11:22:xx:xx - */ - mac_str = argv[3]; - } else if (!valid_command(cmd_index) && argc >= 3) { - /* - * 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_index = CMD_SETMAC; - } else if (argc == 2) { - /* - * No extra args: ./nvmutil gbe.bin - * Equivalent: ./nvmutil gbe.bin setmac xx:xx:xx:xx:xx:xx - */ - mac_str = rmac; - cmd_index = CMD_SETMAC; - } else if (valid_command(cmd_index) && argc >= 4) { - if (command[cmd_index].arg_part) { - /* - * User-supplied partnum. - * Example: ./nvmutil gbe.bin copy 0 - */ - part = conv_argv_part_num(argv[3]); - } else { - err(ECANCELED, "Bad command: %s %s", - argv[2], argv[3]); - } - } else if (valid_command(cmd_index) && argc >= 3) { - if (cmd_index == CMD_SETMAC) - mac_str = rmac; - } + uint8_t arg_part; - if (!valid_command(cmd_index)) { - usage(0); - err(EINVAL, "Unhandled command error"); - } + if (!valid_command(cmd_index) || argc < 3) + usage(1); + + arg_part = command[cmd_index].arg_part; + + /* Maintainer bugs */ + if (arg_part && argc < 4) + err(ECANCELED, + "arg_part set for command that needs argc4"); + if (arg_part && cmd_index == CMD_SETMAC) + err(ECANCELED, + "arg_part set on CMD_SETMAC"); + + if (cmd_index == CMD_SETMAC) + mac_str = argc >= 4 ? argv[3] : rmac; + else if (arg_part) + part = conv_argv_part_num(argv[3]); } static size_t @@ -561,46 +562,53 @@ conv_argv_part_num(const char *part_str) } static void -run_cmd(size_t c) +set_io_flags(int argc, char *argv[]) { - check_command_num(c); - if (command[c].run) - command[c].run(); -} + gbe_flags = O_RDWR; -static void -check_command_num(size_t c) -{ - if (!valid_command(c)) - err(ECANCELED, "Invalid run_cmd arg: %zu", c); + if (argc < 3) + return; + + if (xstrxcmp(argv[2], "dump", MAX_CMD_LEN) == 0) + gbe_flags = O_RDONLY; } -static uint8_t -valid_command(size_t c) +/* + * Portable strcmp() but blocks NULL/empty/unterminated + * strings. Even stricter than strncmp(). + */ +static int +xstrxcmp(const char *a, const char *b, size_t maxlen) { - if (c >= N_COMMANDS) - return 0; + size_t i; - if (c != command[c].chk) - err(ECANCELED, "Invalid cmd chk value (%zu) vs arg: %zu", - command[c].chk, c); + if (a == NULL || b == NULL) + err(EINVAL, "NULL input to xstrxcmp"); - return 1; -} + if (*a == '\0' || *b == '\0') + err(EINVAL, "Empty string in xstrxcmp"); -static void -set_io_flags(int argc, char *argv[]) -{ - gbe_flags = O_RDWR; + for (i = 0; i < maxlen; i++) { + if (a[i] != b[i]) + return (unsigned char)a[i] - (unsigned char)b[i]; - if (argc < 3) - return; + if (a[i] == '\0') + return 0; + } - if (xstrxcmp(argv[2], "dump", MAX_CMD_LEN) == 0) - gbe_flags = O_RDONLY; + /* + * We reached maxlen, so assume unterminated string. + */ + err(EINVAL, "Unterminated string in xstrxcmp"); + + /* + * Should never reach here. This keeps compilers happy. + */ + errno = EINVAL; + return -1; } -#ifndef HAVE_ARC4RANDOM_BUF +#ifndef NVMUTIL_ARC4RANDOM_BUF static void open_dev_urandom(void) { @@ -680,11 +688,44 @@ read_gbe_file_part(size_t p) void *mem_offset = gbe_mem_offset(p ^ command[cmd_index].invert, "pread"); - read_file_exact(gbe_fd, mem_offset, - gbe_rw_size, gbe_file_offset(p, "pread"), fname, "pread"); + if ((size_t)read_gbe_file_exact(gbe_fd, mem_offset, + gbe_rw_size, gbe_file_offset(p, "pread")) != + gbe_rw_size) + err(ECANCELED, "%s: Partial read from p%zu", fname, p); - printf("Read %zu bytes from part %zu: %s\n", - gbe_rw_size, p, fname); + printf("%s: Read %zu bytes from p%zu\n", + fname, gbe_rw_size, p); +} + +static ssize_t +read_gbe_file_exact(int fd, + void *buf, size_t len, off_t off) +{ + int retry; + ssize_t rval; + + if (fd == -1) + err(ECANCELED, "Trying to open bad fd: %s", fname); + + for (retry = 0; retry < MAX_RETRY_RW; retry++) { + rval = pread(fd, buf, len, off); + + if (rval == (ssize_t)len) { + errno = 0; + return rval; + } else if (rval != -1) { + err(ECANCELED, + "%s: Short pread of %zd bytes", + fname, rval); + } else if (errno != EINTR) { + err(ECANCELED, + "%s: Could not pread", fname); + } + } + + err(EINTR, "%s: pread: max retries exceeded", fname); + + return -1; } static void @@ -731,20 +772,73 @@ read_checksums(void) errno = 0; if (num_invalid >= max_invalid) - err(ECANCELED, "No valid checksum found in file: %s", + err(ECANCELED, "%s: No valid checksum found in file", fname); } +static int +good_checksum(size_t partnum) +{ + uint16_t expected_checksum = calculated_checksum(partnum); + uint16_t current_checksum = nvm_word(NVM_CHECKSUM_WORD, partnum); + + size_t real_partnum = partnum ^ command[cmd_index].invert; + + if (current_checksum == expected_checksum) + return 1; + + fprintf(stderr, + "WARNING: BAD checksum in part %zu\n" + "EXPECTED checksum in part %zu: %04x\n" + "CURRENT checksum in part %zu: %04x\n", + real_partnum, + real_partnum, + expected_checksum, + real_partnum, + current_checksum); + + set_err(ECANCELED); + return 0; +} + +static void +run_cmd(size_t c) +{ + check_command_num(c); + if (command[c].run) + command[c].run(); +} + +static void +check_command_num(size_t c) +{ + if (!valid_command(c)) + err(ECANCELED, "Invalid run_cmd arg: %zu", c); +} + +static uint8_t +valid_command(size_t c) +{ + if (c >= N_COMMANDS) + return 0; + + if (c != command[c].chk) + err(ECANCELED, "Invalid cmd chk value (%zu) vs arg: %zu", + command[c].chk, c); + + return 1; +} + static void -cmd_setmac(void) +cmd_helper_setmac(void) { size_t partnum; - #ifdef HAVE_ARC4RANDOM_BUF - printf("Randomisation method: arc4random_buf\n"); - #else - printf("Randomisation method: %s\n", rname); - #endif +#ifdef NVMUTIL_ARC4RANDOM_BUF + printf("Randomisation method: arc4random_buf\n"); +#else + printf("Randomisation method: %s\n", rname); +#endif printf("MAC address to be written: %s\n", mac_str); parse_mac_string(); @@ -773,6 +867,33 @@ parse_mac_string(void) err(EINVAL, "Must not specify multicast MAC address"); } +/* + * strnlen() but aborts on NULL input, and empty strings. + * Our version also prohibits unterminated strings. + * strnlen() was standardized in POSIX.1-2008 and is not + * available on some older systems, so we provide our own. + */ +static size_t +xstrxlen(const char *scmp, size_t maxlen) +{ + size_t xstr_index; + + if (scmp == NULL) + err(EINVAL, "NULL input to xstrxlen"); + + if (*scmp == '\0') + err(EINVAL, "Empty string in xstrxlen"); + + for (xstr_index = 0; + xstr_index < maxlen && scmp[xstr_index] != '\0'; + xstr_index++); + + if (xstr_index == maxlen) + err(EINVAL, "Unterminated string in xstrxlen"); + + return xstr_index; +} + static void set_mac_byte(size_t mac_byte_pos) { @@ -846,52 +967,42 @@ rhex(void) static uint8_t rnum[12]; if (!n) { +#ifdef NVMUTIL_ARC4RANDOM_BUF n = sizeof(rnum); -#ifdef HAVE_ARC4RANDOM_BUF arc4random_buf(rnum, n); #else - read_file_exact(urandom_fd, rnum, n, 0, rname, NULL); + n = (size_t)read_dev_urandom( + urandom_fd, rnum, sizeof(rnum)); #endif } return (uint16_t)(rnum[--n] & 0xf); } -static void -read_file_exact(int fd, void *buf, size_t len, - off_t off, const char *path, const char *op) +#ifndef NVMUTIL_ARC4RANDOM_BUF +static ssize_t +read_dev_urandom(int fd, void *buf, size_t len) { int retry; ssize_t rval; if (fd == -1) - err(ECANCELED, "Trying to open bad fd: %s", path); + err(ECANCELED, "Trying to open bad fd: %s", rname); for (retry = 0; retry < MAX_RETRY_RW; retry++) { - if (op) - rval = pread(fd, buf, len, off); - else - rval = read(fd, buf, len); + rval = read(fd, buf, len); - if (rval == (ssize_t)len) { + if (rval && (size_t)rval <= len) { errno = 0; - return; + return rval; } - - if (rval != -1) - err(ECANCELED, - "Short %s, %zd bytes, on file: %s", - op ? op : "read", rval, path); - - if (errno != EINTR) - err(ECANCELED, - "Could not %s file: '%s'", - op ? op : "read", path); } - err(EINTR, "%s: max retries exceeded on file: %s", - op ? op : "read", path); + err(EINTR, "%s: read: max retries exceeded: %s", rname); + + return -1; } +#endif static void write_mac_part(size_t partnum) @@ -907,27 +1018,19 @@ write_mac_part(size_t partnum) printf("Wrote MAC address to part %zu: ", partnum); print_mac_from_nvm(partnum); - - set_checksum(partnum); } static void -cmd_dump(void) +cmd_helper_dump(void) { size_t partnum; - int num_invalid = 0; for (partnum = 0; partnum < 2; partnum++) { - if (!good_checksum(partnum)) - ++num_invalid; printf("MAC (part %zu): ", partnum); print_mac_from_nvm(partnum); hexdump(partnum); } - - if (num_invalid < 2) - errno = 0; } static void @@ -953,7 +1056,7 @@ hexdump(size_t partnum) uint16_t val16; for (row = 0; row < 8; row++) { - printf("%08zx ", row << 4); + printf("%08zx ", (size_t)row << 4); for (c = 0; c < 8; c++) { val16 = nvm_word((row << 3) + c, partnum); if (c == 4) @@ -965,47 +1068,76 @@ hexdump(size_t partnum) } static void -cmd_setchecksum(void) +write_gbe_file(void) { - set_checksum(part); + size_t p; + size_t partnum; + uint8_t update_checksum; + + if (gbe_flags == O_RDONLY) + return; + + update_checksum = command[cmd_index].chksum_write; + + override_part_modified(); + + for (p = 0; p < 2; p++) { + partnum = p ^ command[cmd_index].invert; + + if (!part_modified[partnum]) + continue; + + if (update_checksum) + set_checksum(partnum); + + write_gbe_file_part(partnum); + } } static void -set_checksum(size_t p) +override_part_modified(void) { - size_t c; - uint16_t val16 = 0; - - for (c = 0; c < NVM_CHECKSUM_WORD; c++) - val16 += nvm_word(c, p); + uint8_t mod_type = command[cmd_index].set_modified; - set_nvm_word(NVM_CHECKSUM_WORD, p, NVM_CHECKSUM - val16); + switch (mod_type) { + case SET_MOD_0: + set_part_modified(0); + break; + case SET_MOD_1: + set_part_modified(1); + break; + case SET_MOD_N: + set_part_modified(part ^ command[cmd_index].invert); + break; + case SET_MOD_BOTH: + set_part_modified(0); + set_part_modified(1); + break; + case SET_MOD_OFF: + break; + default: + err(EINVAL, "Unsupported set_mod type: %u", + mod_type); + } } static void -cmd_brick(void) +set_checksum(size_t p) { - uint16_t checksum_word = nvm_word(NVM_CHECKSUM_WORD, part); - set_nvm_word(NVM_CHECKSUM_WORD, part, checksum_word ^ 1); + check_bin(p, "part number"); + set_nvm_word(NVM_CHECKSUM_WORD, p, calculated_checksum(p)); } -static int -good_checksum(size_t partnum) +static uint16_t +calculated_checksum(size_t p) { - size_t w; - uint16_t total = 0; - - for (w = 0; w <= NVM_CHECKSUM_WORD; w++) - total += nvm_word(w, partnum); - - if (total == NVM_CHECKSUM) - return 1; + size_t c; + uint32_t val16 = 0; - fprintf(stderr, "WARNING: BAD checksum in part %zu\n", - partnum ^ command[cmd_index].invert); + for (c = 0; c < NVM_CHECKSUM_WORD; c++) + val16 += (uint32_t)nvm_word(c, p); - set_err(ECANCELED); - return 0; + return (uint16_t)((NVM_CHECKSUM - val16) & 0xffff); } /* @@ -1024,7 +1156,8 @@ nvm_word(size_t pos16, size_t p) check_nvm_bound(pos16, p); pos = (pos16 << 1) + (p * GBE_PART_SIZE); - return buf[pos] | (buf[pos + 1] << 8); + return (uint16_t)buf[pos] | + ((uint16_t)buf[pos + 1] << 8); } static void @@ -1042,6 +1175,13 @@ set_nvm_word(size_t pos16, size_t p, uint16_t val16) } static void +set_part_modified(size_t p) +{ + check_bin(p, "part number"); + part_modified[p] = 1; +} + +static void check_nvm_bound(size_t c, size_t p) { /* @@ -1057,49 +1197,10 @@ check_nvm_bound(size_t c, size_t p) } static void -write_gbe_file(void) -{ - size_t p; - size_t partnum; - - if (gbe_flags == O_RDONLY) - return; - - override_part_modified(); - - for (p = 0; p < 2; p++) { - partnum = p ^ command[cmd_index].invert; - - if (part_modified[partnum]) - write_gbe_file_part(partnum); - } -} - -static void -override_part_modified(void) +check_bin(size_t a, const char *a_name) { - uint8_t mod_type = command[cmd_index].set_modified; - - switch (mod_type) { - case SET_MOD_0: - set_part_modified(0); - break; - case SET_MOD_1: - set_part_modified(1); - break; - case SET_MOD_N: - set_part_modified(part ^ command[cmd_index].invert); - break; - case SET_MOD_BOTH: - set_part_modified(0); - set_part_modified(1); - break; - case SET_MOD_OFF: - break; - default: - err(EINVAL, "Unsupported set_mod type: %u", - mod_type); - } + if (a > 1) + err(ECANCELED, "%s must be 0 or 1, but is %zu", a_name, a); } static void @@ -1110,7 +1211,7 @@ write_gbe_file_part(size_t p) size_t gbe_rw_size; if (gbe_fd == -1) - err(ECANCELED, "Trying to write bad gbe_fd: %s", fname); + err(ECANCELED, "%s: Trying to write bad gbe_fd", fname); gbe_rw_size = command[cmd_index].rw_size; @@ -1120,22 +1221,22 @@ write_gbe_file_part(size_t p) if (rval == (ssize_t)gbe_rw_size) { errno = 0; - printf("Wrote %zu bytes to part %zu: %s\n", - gbe_rw_size, p, fname); + printf("%s: Wrote %zu bytes to part %zu\n", + fname, gbe_rw_size, p); return; } if (rval != -1) err(ECANCELED, - "Short pwrite, %zd bytes, on file: %s", - rval, fname); + "%s: Short pwrite, %zd bytes", + fname, rval); if (errno != EINTR) err(ECANCELED, - "Could not pwrite file: '%s'", fname); + "%s: pwrite failed on p%zu", fname, p); } - err(EINTR, "pwrite: max retries exceeded on file: %s", fname); + err(EINTR, "%s: pwrite: max retries exceeded on p%zu", fname, p); } /* @@ -1180,118 +1281,17 @@ gbe_x_offset(size_t p, const char *f_op, const char *d_type, off = (off_t)p * nsize; if (off + GBE_PART_SIZE > ncmp) - err(ECANCELED, "GbE %s %s out of bounds: %s", - d_type, f_op, fname); + err(ECANCELED, "%s: GbE %s %s out of bounds", + fname, d_type, f_op); if (off != 0 && off != ncmp >> 1) - err(ECANCELED, "GbE %s %s at bad offset: %s", - d_type, f_op, fname); + err(ECANCELED, "%s: GbE %s %s at bad offset", + fname, d_type, f_op); return off; } static void -set_part_modified(size_t p) -{ - check_bin(p, "part number"); - part_modified[p] = 1; -} - -static void -check_bin(size_t a, const char *a_name) -{ - if (a > 1) - err(ECANCELED, "%s must be 0 or 1, but is %zu", a_name, a); -} - -static void -usage(uint8_t usage_exit) -{ - const char *util = getnvmprogname(); - -#ifdef NVMUTIL_PLEDGE - if (pledge("stdio", NULL) == -1) - err(ECANCELED, "pledge"); -#endif - fprintf(stderr, - "Modify Intel GbE NVM images e.g. set MAC\n" - "USAGE:\n" - "\t%s FILE dump\n" - "\t%s FILE # same as setmac without [MAC]\n" - "\t%s FILE setmac [MAC]\n" - "\t%s FILE swap\n" - "\t%s FILE copy 0|1\n" - "\t%s FILE brick 0|1\n" - "\t%s FILE setchecksum 0|1\n", - util, util, util, util, util, util, util); - - if (usage_exit) - err(ECANCELED, "Too few arguments"); -} - -/* - * strnlen() but aborts on NULL input, and empty strings. - * Our version also prohibits unterminated strings. - * strnlen() was standardized in POSIX.1-2008 and is not - * available on some older systems, so we provide our own. - */ -static size_t -xstrxlen(const char *scmp, size_t maxlen) -{ - size_t xstr_index; - - if (scmp == NULL) - err(EINVAL, "NULL input to xstrxlen"); - - if (*scmp == '\0') - err(EINVAL, "Empty string in xstrxlen"); - - for (xstr_index = 0; - xstr_index < maxlen && scmp[xstr_index] != '\0'; - xstr_index++); - - if (xstr_index == maxlen) - err(EINVAL, "Unterminated string in xstrxlen"); - - return xstr_index; -} - -/* - * Portable, secure strcmp() with the same mentality - * as our xstrxlen - */ -static int -xstrxcmp(const char *a, const char *b, size_t maxlen) -{ - size_t i; - - if (a == NULL || b == NULL) - err(EINVAL, "NULL input to xstrxcmp"); - - if (*a == '\0' || *b == '\0') - err(EINVAL, "Empty string in xstrxcmp"); - - for (i = 0; i < maxlen; i++) { - if (a[i] != b[i]) - return (unsigned char)a[i] - (unsigned char)b[i]; - - if (a[i] == '\0') - return 0; - } - - /* - * We reached maxlen, so assume unterminated string. - */ - err(EINVAL, "Unterminated string in xstrxcmp"); - - /* - * Should never reach here. This keeps compilers happy. - */ - errno = EINVAL; - return -1; -} - -static void err(int nvm_errval, const char *msg, ...) { if (nvm_errval != -1) @@ -1312,6 +1312,24 @@ err(int nvm_errval, const char *msg, ...) exit(EXIT_FAILURE); } +static void +close_files(void) +{ + if (gbe_fd > -1) { + if (close(gbe_fd) == -1) + err(-1, "%s: close failed", fname); + gbe_fd = -1; + } + +#ifndef NVMUTIL_ARC4RANDOM_BUF + if (urandom_fd > -1) { + if (close(urandom_fd) == -1) + err(-1, "%s: close failed", rname); + urandom_fd = -1; + } +#endif +} + static const char * getnvmprogname(void) { @@ -1340,17 +1358,23 @@ set_err(int x) } static void -close_files(void) +usage(uint8_t usage_exit) { - if (gbe_fd > -1) { - if (close(gbe_fd) == -1) - err(-1, "close '%s'", fname); - } + const char *util = getnvmprogname(); -#ifndef HAVE_ARC4RANDOM_BUF - if (urandom_fd > -1) { - if (close(urandom_fd) == -1) - err(-1, "close '%s'", rname); - } +#ifdef NVMUTIL_PLEDGE + if (pledge("stdio", NULL) == -1) + err(ECANCELED, "pledge"); #endif + fprintf(stderr, + "Modify Intel GbE NVM images e.g. set MAC\n" + "USAGE:\n" + "\t%s FILE dump\n" + "\t%s FILE setmac [MAC]\n" + "\t%s FILE swap\n" + "\t%s FILE copy 0|1\n", + util, util, util, util); + + if (usage_exit) + err(EINVAL, "Too few arguments"); } |
