summaryrefslogtreecommitdiff
path: root/util/nvmutil/nvmutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/nvmutil/nvmutil.c')
-rw-r--r--util/nvmutil/nvmutil.c240
1 files changed, 146 insertions, 94 deletions
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);
}
/*