summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to 'util')
-rw-r--r--util/nvmutil/.gitignore3
-rw-r--r--util/nvmutil/ChangeLog.md8
-rw-r--r--util/nvmutil/Makefile33
-rw-r--r--util/nvmutil/README.md4
-rw-r--r--util/nvmutil/nvmutil.c774
5 files changed, 422 insertions, 400 deletions
diff --git a/util/nvmutil/.gitignore b/util/nvmutil/.gitignore
new file mode 100644
index 00000000..802202a4
--- /dev/null
+++ b/util/nvmutil/.gitignore
@@ -0,0 +1,3 @@
+/nvm
+/nvmutil
+*.bin
diff --git a/util/nvmutil/ChangeLog.md b/util/nvmutil/ChangeLog.md
deleted file mode 100644
index e1ed5754..00000000
--- a/util/nvmutil/ChangeLog.md
+++ /dev/null
@@ -1,8 +0,0 @@
-This change log has moved. Please refer here for historical pre-osboot-merge
-changes:
-
-<https://libreboot.org/docs/install/nvmutilimport.html>
-
-Osboot merged with Libreboot on November 17th, 2022. For nvmutil changes after
-this date, please check regular Libreboot release announcements which shall
-now specify any such changes.
diff --git a/util/nvmutil/Makefile b/util/nvmutil/Makefile
index 91b5ba1c..22376c70 100644
--- a/util/nvmutil/Makefile
+++ b/util/nvmutil/Makefile
@@ -3,33 +3,28 @@
# SPDX-FileCopyrightText: 2023 Riku Viitanen <riku.viitanen@protonmail.com>
CC?=cc
-CFLAGS?=-Os -Wall -Wextra -Werror -pedantic
+CFLAGS?=-Os -Wall -Wextra -Werror -pedantic -std=c99
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!
+PROG=nvmutil
-nvm: nvmutil.c
- rm -f nvm
- $(CC) $(CFLAGS) nvmutil.c -o nvmutil
+all: $(PROG)
-install:
- $(INSTALL) nvmutil $(DESTDIR)$(PREFIX)/bin/nvmutil
+$(PROG): nvmutil.c
+ $(CC) $(CFLAGS) nvmutil.c -o $(PROG)
-# do not delete *bin/nvm because
-# there is a package manager by
-# that name. this makefile now
-# treats nvmutil as the binary
+install: $(PROG)
+ mkdir -p $(DESTDIR)$(PREFIX)/bin/
+ install $(PROG) $(DESTDIR)$(PREFIX)/bin/
uninstall:
- rm -f $(DESTDIR)$(PREFIX)/bin/nvmutil
-
-distclean:
- rm -f nvm nvmutil
+ rm -f $(DESTDIR)$(PREFIX)/bin/$(PROG)
clean:
- rm -f nvm nvmutil
+ rm -f $(PROG)
+
+distclean: clean
+
+.PHONY: all install uninstall clean distclean
diff --git a/util/nvmutil/README.md b/util/nvmutil/README.md
deleted file mode 100644
index 03a25bc4..00000000
--- a/util/nvmutil/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-
-This documentation has become part of lbwww. See:
-
-<https://libreboot.org/docs/install/nvmutil.html>
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index 21fb8bdd..37959bd2 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)
{
@@ -675,16 +683,51 @@ read_gbe_file(void)
static void
read_gbe_file_part(size_t p)
{
- size_t gbe_rw_size = command[cmd_index].rw_size;
+ ssize_t rc;
+ size_t gbe_rw_size = command[cmd_index].rw_size;
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");
+ rc = read_gbe_file_exact(gbe_fd, mem_offset,
+ gbe_rw_size, gbe_file_offset(p, "pread"));
+
+ if (rc != (ssize_t)gbe_rw_size)
+ err(ECANCELED, "%s: Partial read from p%zu", fname, p);
+
+ 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);
+ }
+ }
- printf("Read %zu bytes from part %zu: %s\n",
- gbe_rw_size, p, fname);
+ err(EINTR, "%s: pread: max retries exceeded", fname);
+
+ return -1;
}
static void
@@ -731,20 +774,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 +869,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 +969,52 @@ 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));
+
+ if (!n || n > sizeof(rnum))
+ err(ECANCELED, "Randomisation failure");
#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) {
- errno = 0;
- return;
+ if (rval == -1) {
+ if (errno == EINTR)
+ continue;
+ err(errno, "%s", rname);
}
- if (rval != -1)
- err(ECANCELED,
- "Short %s, %zd bytes, on file: %s",
- op ? op : "read", rval, path);
+ if (!rval || (size_t)rval > len)
+ continue;
- if (errno != EINTR)
- err(ECANCELED,
- "Could not %s file: '%s'",
- op ? op : "read", path);
+ errno = 0;
+ return rval;
}
- 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 +1030,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 +1068,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 +1080,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 +1168,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 +1187,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 +1209,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 +1223,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 +1233,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 of %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 +1293,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 +1324,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 +1370,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");
}