mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-03-25 13:29:03 +02:00
Compare commits
19 Commits
1f4ab21403
...
6402a0fbe9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6402a0fbe9 | ||
|
|
4131402589 | ||
|
|
0c23474322 | ||
|
|
84a9e8f89b | ||
|
|
007dece09e | ||
|
|
bb9010fdc1 | ||
|
|
08b1d95874 | ||
|
|
8f3bc13ac5 | ||
|
|
aa67cf087d | ||
|
|
66f1640552 | ||
|
|
724c9bb36c | ||
|
|
3d6e2637d6 | ||
|
|
1e45d19f5d | ||
|
|
7d64b8ea8d | ||
|
|
45ea92a077 | ||
|
|
b5af1bf3ac | ||
|
|
f8ddb6ef84 | ||
|
|
c59b3b7638 | ||
|
|
0f9ce929b4 |
@@ -88,10 +88,6 @@ static void check_enum_bin(size_t a, const char *a_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 set_io_flags(int argc, char *argv[]);
|
||||
static void run_cmd(size_t c);
|
||||
static void check_command_num(size_t c);
|
||||
static uint8_t valid_command(size_t c);
|
||||
static int xstrxcmp(const char *a, const char *b, size_t maxlen);
|
||||
#ifndef NVMUTIL_ARC4RANDOM_BUF
|
||||
static void open_dev_urandom(void);
|
||||
@@ -102,6 +98,9 @@ static void read_gbe_file(void);
|
||||
static void read_gbe_file_part(size_t part);
|
||||
static void read_checksums(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);
|
||||
@@ -110,12 +109,14 @@ 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 ssize_t read_gbe_file_exact(int fd, void *buf, size_t len,
|
||||
off_t off, const char *path, const char *op);
|
||||
static void read_file_exact(int fd, uint8_t *mem, size_t len,
|
||||
off_t off, uint8_t plesen, const char *path);
|
||||
static void write_mac_part(size_t partnum);
|
||||
static void cmd_helper_dump(void);
|
||||
static void print_mac_from_nvm(size_t partnum);
|
||||
static void hexdump(size_t partnum);
|
||||
static void cmd_helper_cat(void);
|
||||
static void gbe_cat_buf(uint8_t *b);
|
||||
static void write_gbe_file(void);
|
||||
static void override_part_modified(void);
|
||||
static void set_checksum(size_t part);
|
||||
@@ -127,7 +128,7 @@ static void check_nvm_bound(size_t pos16, size_t part);
|
||||
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 uint8_t *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 err(int nvm_errval, const char *msg, ...);
|
||||
@@ -192,11 +193,11 @@ static const char *rname = NULL;
|
||||
* The code will handle this properly.
|
||||
*/
|
||||
static uint8_t buf[GBE_FILE_SIZE];
|
||||
static uint8_t pad[GBE_PART_SIZE];
|
||||
|
||||
static uint16_t mac_buf[3];
|
||||
static off_t gbe_file_size;
|
||||
|
||||
static int gbe_flags;
|
||||
#ifndef NVMUTIL_ARC4RANDOM_BUF
|
||||
static int urandom_fd = -1;
|
||||
#endif
|
||||
@@ -232,6 +233,9 @@ enum {
|
||||
CMD_SETMAC,
|
||||
CMD_SWAP,
|
||||
CMD_COPY,
|
||||
CMD_CAT,
|
||||
CMD_CAT16,
|
||||
CMD_CAT128
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -272,27 +276,24 @@ struct commands {
|
||||
uint8_t chksum_read;
|
||||
uint8_t chksum_write;
|
||||
size_t rw_size; /* within the 4KB GbE part */
|
||||
int flags; /* e.g. O_RDWR or O_RDONLY */
|
||||
};
|
||||
|
||||
/*
|
||||
* Command table, for nvmutil commands
|
||||
*/
|
||||
static const struct commands command[] = {
|
||||
/*
|
||||
* 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,
|
||||
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
|
||||
NVM_SIZE },
|
||||
SKIP_CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
|
||||
NVM_SIZE, O_RDONLY },
|
||||
|
||||
{ CMD_SETMAC, "setmac", cmd_helper_setmac, ARGC_3,
|
||||
NO_INVERT, SET_MOD_OFF,
|
||||
ARG_NOPART,
|
||||
CHECKSUM_READ, CHECKSUM_WRITE,
|
||||
NVM_SIZE },
|
||||
NVM_SIZE, O_RDWR },
|
||||
|
||||
/*
|
||||
* OPTIMISATION: Read inverted, so no copying is needed.
|
||||
@@ -301,7 +302,7 @@ static const struct commands command[] = {
|
||||
PART_INVERT, SET_MOD_BOTH,
|
||||
ARG_NOPART,
|
||||
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
|
||||
GBE_PART_SIZE },
|
||||
GBE_PART_SIZE, O_RDWR },
|
||||
|
||||
/*
|
||||
* OPTIMISATION: Read inverted, so no copying is needed.
|
||||
@@ -311,7 +312,25 @@ static const struct commands command[] = {
|
||||
PART_INVERT, SET_MOD_N,
|
||||
ARG_PART,
|
||||
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
|
||||
GBE_PART_SIZE },
|
||||
GBE_PART_SIZE, O_RDWR },
|
||||
|
||||
{ CMD_CAT, "cat", cmd_helper_cat, ARGC_3,
|
||||
NO_INVERT, SET_MOD_OFF,
|
||||
ARG_NOPART,
|
||||
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
|
||||
GBE_PART_SIZE, O_RDONLY },
|
||||
|
||||
{ CMD_CAT16, "cat16", cmd_helper_cat, ARGC_3,
|
||||
NO_INVERT, SET_MOD_OFF,
|
||||
ARG_NOPART,
|
||||
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
|
||||
GBE_PART_SIZE, O_RDONLY },
|
||||
|
||||
{ CMD_CAT128, "cat128", cmd_helper_cat, ARGC_3,
|
||||
NO_INVERT, SET_MOD_OFF,
|
||||
ARG_NOPART,
|
||||
CHECKSUM_READ, SKIP_CHECKSUM_WRITE,
|
||||
GBE_PART_SIZE, O_RDONLY },
|
||||
};
|
||||
|
||||
#define MAX_CMD_LEN 50
|
||||
@@ -348,11 +367,10 @@ main(int argc, char *argv[])
|
||||
|
||||
set_cmd(argc, argv);
|
||||
set_cmd_args(argc, argv);
|
||||
set_io_flags(argc, argv);
|
||||
|
||||
#ifdef NVMUTIL_PLEDGE
|
||||
#ifdef NVMUTIL_UNVEIL
|
||||
if (gbe_flags == O_RDONLY) {
|
||||
if (command[cmd_index].flags == O_RDONLY) {
|
||||
if (unveil(fname, "r") == -1)
|
||||
err(ECANCELED, "%s: unveil ro", fname);
|
||||
if (unveil(NULL, NULL) == -1)
|
||||
@@ -368,7 +386,7 @@ main(int argc, char *argv[])
|
||||
err(ECANCELED, "pledge rw (kill unveil)");
|
||||
}
|
||||
#else
|
||||
if (gbe_flags == O_RDONLY) {
|
||||
if (command[cmd_index].flags == O_RDONLY) {
|
||||
if (pledge("stdio rpath", NULL) == -1)
|
||||
err(ECANCELED, "pledge ro");
|
||||
}
|
||||
@@ -391,6 +409,11 @@ main(int argc, char *argv[])
|
||||
err(ECANCELED, "pledge stdio (main)");
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Used by CMD_CAT, for padding
|
||||
*/
|
||||
memset(pad, 0xff, sizeof(pad));
|
||||
|
||||
read_gbe_file();
|
||||
read_checksums();
|
||||
|
||||
@@ -398,7 +421,7 @@ main(int argc, char *argv[])
|
||||
|
||||
if (errno)
|
||||
err(errno, "%s: Unhandled error (WRITE SKIPPED)", fname);
|
||||
else if (gbe_flags != O_RDONLY)
|
||||
else if (command[cmd_index].flags == O_RDWR)
|
||||
write_gbe_file();
|
||||
|
||||
close_files();
|
||||
@@ -485,6 +508,10 @@ sanitize_command_index(size_t c)
|
||||
if (gbe_rw_size > GBE_PART_SIZE)
|
||||
err(EINVAL, "rw_size larger than GbE part: %zu",
|
||||
gbe_rw_size);
|
||||
|
||||
if (command[c].flags != O_RDONLY &&
|
||||
command[c].flags != O_RDWR)
|
||||
err(EINVAL, "invalid cmd.flags setting");
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -557,46 +584,6 @@ conv_argv_part_num(const char *part_str)
|
||||
return (size_t)(ch - '0');
|
||||
}
|
||||
|
||||
static void
|
||||
set_io_flags(int argc, char *argv[])
|
||||
{
|
||||
gbe_flags = O_RDWR;
|
||||
|
||||
if (argc < 3)
|
||||
return;
|
||||
|
||||
if (xstrxcmp(argv[2], "dump", MAX_CMD_LEN) == 0)
|
||||
gbe_flags = O_RDONLY;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Portable strcmp() but blocks NULL/empty/unterminated
|
||||
* strings. Even stricter than strncmp().
|
||||
@@ -661,7 +648,7 @@ open_gbe_file(void)
|
||||
{
|
||||
struct stat gbe_st;
|
||||
|
||||
xopen(&gbe_fd, fname, gbe_flags, &gbe_st);
|
||||
xopen(&gbe_fd, fname, command[cmd_index].flags, &gbe_st);
|
||||
|
||||
gbe_file_size = gbe_st.st_size;
|
||||
|
||||
@@ -708,17 +695,12 @@ static void
|
||||
read_gbe_file_part(size_t p)
|
||||
{
|
||||
size_t gbe_rw_size = command[cmd_index].rw_size;
|
||||
|
||||
void *mem_offset =
|
||||
uint8_t *mem_offset =
|
||||
gbe_mem_offset(p ^ command[cmd_index].invert, "pread");
|
||||
|
||||
if ((size_t)read_gbe_file_exact(gbe_fd, mem_offset,
|
||||
gbe_rw_size, gbe_file_offset(p, "pread"), fname, "pread") !=
|
||||
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);
|
||||
read_file_exact(gbe_fd, mem_offset,
|
||||
gbe_rw_size, gbe_file_offset(p, "pread"),
|
||||
1, fname);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -764,9 +746,13 @@ read_checksums(void)
|
||||
if (num_invalid < max_invalid)
|
||||
errno = 0;
|
||||
|
||||
if (num_invalid >= max_invalid)
|
||||
if (num_invalid >= max_invalid) {
|
||||
if (max_invalid == 1)
|
||||
err(ECANCELED, "%s: part %zu has a bad checksum",
|
||||
fname, part);
|
||||
err(ECANCELED, "%s: No valid checksum found in file",
|
||||
fname);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -775,25 +761,41 @@ 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_helper_setmac(void)
|
||||
{
|
||||
@@ -930,81 +932,46 @@ rhex(void)
|
||||
{
|
||||
static size_t n = 0;
|
||||
static uint8_t rnum[12];
|
||||
#ifndef NVMUTIL_ARC4RANDOM_BUF
|
||||
int max_retries;
|
||||
#endif
|
||||
|
||||
#ifdef NVMUTIL_ARC4RANDOM_BUF
|
||||
if (!n) {
|
||||
n = sizeof(rnum);
|
||||
#ifdef NVMUTIL_ARC4RANDOM_BUF
|
||||
arc4random_buf(rnum, n);
|
||||
}
|
||||
#else
|
||||
for (max_retries = 0; max_retries < 50 && !n; max_retries++)
|
||||
n = (size_t)read_gbe_file_exact(urandom_fd,
|
||||
rnum, sizeof(rnum), 0, rname, NULL);
|
||||
if (!n || n > sizeof(rnum))
|
||||
err(ECANCELED, "Randomisation failure");
|
||||
read_file_exact(urandom_fd, rnum, n, 0, 0, rname);
|
||||
#endif
|
||||
}
|
||||
|
||||
return (uint16_t)(rnum[--n] & 0xf);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
read_gbe_file_exact(int fd, void *buf, size_t len,
|
||||
off_t off, const char *path, const char *op)
|
||||
static void
|
||||
read_file_exact(int fd, uint8_t *mem,
|
||||
size_t len, off_t off, uint8_t plesen, const char *path)
|
||||
{
|
||||
int retry;
|
||||
ssize_t rval;
|
||||
ssize_t rval = -1;
|
||||
ssize_t rc = 0;
|
||||
|
||||
if (fd == -1)
|
||||
err(ECANCELED, "Trying to open bad fd: %s", path);
|
||||
|
||||
for (retry = 0; retry < MAX_RETRY_RW; retry++) {
|
||||
if (op)
|
||||
rval = pread(fd, buf, len, off);
|
||||
for (rc = 0; rc != (ssize_t)len; rc += rval) {
|
||||
if (plesen)
|
||||
rval = pread(fd, mem + rc, len - rc, off + rc);
|
||||
else
|
||||
rval = read(fd, buf, len);
|
||||
rval = read(fd, mem + rc, len - rc);
|
||||
|
||||
if (rval == (ssize_t)len) {
|
||||
errno = 0;
|
||||
return rval;
|
||||
if (rval > -1) {
|
||||
if (!rval) /* prevent infinite loop */
|
||||
err(EIO, "%s: read of 0 bytes", path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rval != -1) {
|
||||
#ifndef NVMUTIL_ARC4RANDOM_BUF
|
||||
if (fd == urandom_fd) {
|
||||
/*
|
||||
* /dev/[u]random reads can still return
|
||||
* partial reads legally, on some weird
|
||||
* Unix systems (especially older ones).
|
||||
*
|
||||
* We use a circular buffer for random
|
||||
* bytes in rhex(), so we can just use
|
||||
* the smaller amount of bytes and call
|
||||
* read_gbe_file_exact again if necessary.
|
||||
*/
|
||||
if (rval > 0) {
|
||||
errno = 0;
|
||||
return rval;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
err(ECANCELED,
|
||||
"Short %s, %zd bytes, on file: %s",
|
||||
op ? op : "read", rval, path);
|
||||
}
|
||||
if (errno != EINTR || rval < -1)
|
||||
err(EIO, "%s", path);
|
||||
|
||||
if (errno != EINTR)
|
||||
err(ECANCELED,
|
||||
"Could not %s file: '%s'",
|
||||
op ? op : "read", path);
|
||||
errno = 0;
|
||||
}
|
||||
|
||||
err(EINTR, "%s: max retries exceeded on file: %s",
|
||||
op ? op : "read", path);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1028,7 +995,18 @@ cmd_helper_dump(void)
|
||||
{
|
||||
size_t partnum;
|
||||
|
||||
part_valid[0] = good_checksum(0);
|
||||
part_valid[1] = good_checksum(1);
|
||||
|
||||
if (part_valid[0] || part_valid[1])
|
||||
errno = 0;
|
||||
|
||||
for (partnum = 0; partnum < 2; partnum++) {
|
||||
if (!part_valid[partnum])
|
||||
fprintf(stderr,
|
||||
"BAD checksum %04x in part %zu (expected %04x)\n",
|
||||
nvm_word(NVM_CHECKSUM_WORD, partnum),
|
||||
partnum, calculated_checksum(partnum));
|
||||
|
||||
printf("MAC (part %zu): ", partnum);
|
||||
print_mac_from_nvm(partnum);
|
||||
@@ -1070,6 +1048,41 @@ hexdump(size_t partnum)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_helper_cat(void)
|
||||
{
|
||||
size_t p;
|
||||
size_t ff;
|
||||
size_t n = 0;
|
||||
|
||||
if (cmd_index == CMD_CAT16)
|
||||
n = 1;
|
||||
else if (cmd_index == CMD_CAT128)
|
||||
n = 15;
|
||||
else if (cmd_index != CMD_CAT)
|
||||
err(ECANCELED, "cmd_helper_cat called erroneously");
|
||||
|
||||
fflush(NULL);
|
||||
|
||||
for (p = 0; p < 2; p++) {
|
||||
gbe_cat_buf(buf + (p * GBE_PART_SIZE));
|
||||
|
||||
for (ff = 0; ff < n; ff++)
|
||||
gbe_cat_buf(pad);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gbe_cat_buf(uint8_t *b)
|
||||
{
|
||||
size_t wc;
|
||||
ssize_t w = 0;
|
||||
|
||||
for (wc = 0; wc < GBE_PART_SIZE; wc += w)
|
||||
if ((w = write(STDOUT_FILENO, b + wc, GBE_PART_SIZE - wc)) < 1)
|
||||
err(EIO, "%s: stdout", fname);
|
||||
}
|
||||
|
||||
static void
|
||||
write_gbe_file(void)
|
||||
{
|
||||
@@ -1077,7 +1090,7 @@ write_gbe_file(void)
|
||||
size_t partnum;
|
||||
uint8_t update_checksum;
|
||||
|
||||
if (gbe_flags == O_RDONLY)
|
||||
if (command[cmd_index].flags == O_RDONLY)
|
||||
return;
|
||||
|
||||
update_checksum = command[cmd_index].chksum_write;
|
||||
@@ -1231,7 +1244,7 @@ write_gbe_file_part(size_t p)
|
||||
|
||||
if (rval != -1)
|
||||
err(ECANCELED,
|
||||
"%s: Short pwrite, %zd bytes",
|
||||
"%s: Short pwrite of %zd bytes",
|
||||
fname, rval);
|
||||
|
||||
if (errno != EINTR)
|
||||
@@ -1264,13 +1277,13 @@ gbe_file_offset(size_t p, const char *f_op)
|
||||
* but used to check Gbe bounds in memory,
|
||||
* and it is *also* used during file I/O.
|
||||
*/
|
||||
static void *
|
||||
static uint8_t *
|
||||
gbe_mem_offset(size_t p, const char *f_op)
|
||||
{
|
||||
off_t gbe_off = gbe_x_offset(p, f_op, "mem",
|
||||
GBE_PART_SIZE, GBE_FILE_SIZE);
|
||||
|
||||
return (void *)(buf + gbe_off);
|
||||
return (uint8_t *)(buf + gbe_off);
|
||||
}
|
||||
|
||||
static off_t
|
||||
@@ -1375,8 +1388,12 @@ usage(uint8_t usage_exit)
|
||||
"\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);
|
||||
"\t%s FILE copy 0|1\n"
|
||||
"\t%s FILE cat\n"
|
||||
"\t%s FILE cat16\n"
|
||||
"\t%s FILE cat128\n",
|
||||
util, util, util, util,
|
||||
util, util, util);
|
||||
|
||||
if (usage_exit)
|
||||
err(EINVAL, "Too few arguments");
|
||||
|
||||
Reference in New Issue
Block a user