2023-06-01 07:31:08 +00:00
|
|
|
/* Copyright (c) 2022, 2023 Leah Rowe <info@minifree.org> */
|
|
|
|
/* SPDX-License-Identifier: MIT */
|
2022-11-17 12:07:09 +00:00
|
|
|
|
2023-06-01 07:25:55 +00:00
|
|
|
#include "nvmutil.h"
|
2023-06-01 07:21:25 +00:00
|
|
|
|
2022-11-17 12:07:09 +00:00
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
util/nvmutil: Use unveil, and harden pledges
After /dev/urandom (for MAC address randomisation) and
the GbE file have been handled, unveil them. Unveil is
a system call provided by OpenBSD that, when called,
restricts access only to the files and/or directories
specified, each given specific permissions.
You can learn more about unveil here:
https://man.openbsd.org/unveil.2
An ifdef rule makes nvmutil only use unveil on OpenBSD,
because it's not available anywhere else. This is the same
as with the pledge() system call.
Where invalid arguments are given, and no action performed,
pledge promises are also reduced to just stdio, preventing
any writes to files, or reads from files.
Signed-off-by: Leah Rowe <leah@libreboot.org>
2023-05-31 07:53:08 +00:00
|
|
|
xpledge("stdio rpath wpath unveil", NULL);
|
2023-06-03 19:03:18 +00:00
|
|
|
xunveil("/dev/urandom", "r");
|
2023-06-03 18:39:37 +00:00
|
|
|
err_if((errno = argc < 3 ? EINVAL : errno));
|
|
|
|
if ((flags = (strcmp(COMMAND, "dump") == 0) ? O_RDONLY : flags)
|
2023-06-03 19:03:18 +00:00
|
|
|
== O_RDONLY) {
|
|
|
|
xunveil(FILENAME, "r");
|
|
|
|
xpledge("stdio rpath", NULL);
|
|
|
|
} else {
|
|
|
|
xunveil(FILENAME, "rw");
|
|
|
|
xpledge("stdio rpath wpath", NULL);
|
|
|
|
}
|
2023-06-03 18:39:37 +00:00
|
|
|
openFiles(FILENAME);
|
|
|
|
xpledge("stdio", NULL);
|
2023-06-03 19:03:18 +00:00
|
|
|
|
2023-06-03 11:06:36 +00:00
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
if (strcmp(COMMAND, op[i].str) == 0)
|
2023-06-03 14:08:29 +00:00
|
|
|
if ((cmd = argc >= op[i].args ? op[i].cmd : NULL))
|
2023-06-03 11:06:36 +00:00
|
|
|
break;
|
|
|
|
if (cmd == cmd_setmac)
|
|
|
|
strMac = (argc > 3) ? MAC_ADDRESS : strRMac;
|
|
|
|
else if ((cmd != NULL) && (argc > 3))
|
|
|
|
err_if((errno = (!((part = PARTNUM[0] - '0') == 0 || part == 1))
|
|
|
|
|| PARTNUM[1] ? EINVAL : errno));
|
2023-06-03 18:39:37 +00:00
|
|
|
err_if((errno = (cmd == NULL) ? EINVAL : errno));
|
2022-11-17 12:07:09 +00:00
|
|
|
|
2023-06-03 19:03:18 +00:00
|
|
|
readGbeFile(FILENAME);
|
2023-06-03 11:06:36 +00:00
|
|
|
(*cmd)();
|
2023-06-03 19:03:18 +00:00
|
|
|
|
2023-06-01 13:07:20 +00:00
|
|
|
if ((gbeFileModified) && (flags != O_RDONLY))
|
|
|
|
writeGbeFile(FILENAME);
|
2023-05-31 08:30:13 +00:00
|
|
|
err_if((errno != 0) && (cmd != &cmd_dump));
|
2023-04-06 17:38:05 +00:00
|
|
|
return errno;
|
2022-11-17 12:07:09 +00:00
|
|
|
}
|
|
|
|
|
2023-01-27 15:09:34 +00:00
|
|
|
void
|
2023-06-01 12:35:34 +00:00
|
|
|
openFiles(const char *path)
|
2022-11-17 12:07:09 +00:00
|
|
|
{
|
2023-06-01 13:04:44 +00:00
|
|
|
struct stat st;
|
2023-06-03 18:39:37 +00:00
|
|
|
xopen(fd, path, flags);
|
2023-06-01 09:31:21 +00:00
|
|
|
if ((st.st_size != SIZE_8KB))
|
2023-04-07 01:21:37 +00:00
|
|
|
err(errno = ECANCELED, "File `%s` not 8KiB", path);
|
2023-06-01 13:04:44 +00:00
|
|
|
xopen(rfd, "/dev/urandom", O_RDONLY);
|
2023-06-01 09:31:21 +00:00
|
|
|
errno = errno != ENOTDIR ? errno : 0;
|
2023-06-01 12:35:34 +00:00
|
|
|
}
|
2023-01-27 15:09:34 +00:00
|
|
|
|
2023-06-01 12:35:34 +00:00
|
|
|
void
|
|
|
|
readGbeFile(const char *path)
|
|
|
|
{
|
2023-06-03 12:44:04 +00:00
|
|
|
nf = ((cmd == cmd_swap) || (cmd == cmd_copy)) ? SIZE_4KB : nf;
|
2023-06-03 11:06:36 +00:00
|
|
|
skipread[part ^ 1] = (cmd == &cmd_copy) | (cmd == &cmd_setchecksum)
|
|
|
|
| (cmd == &cmd_brick);
|
2023-06-01 09:31:21 +00:00
|
|
|
gbe[1] = (gbe[0] = (size_t) buf) + SIZE_4KB;
|
2023-04-07 01:08:06 +00:00
|
|
|
for (int p = 0; p < 2; p++) {
|
|
|
|
if (skipread[p])
|
|
|
|
continue;
|
2023-06-01 09:31:21 +00:00
|
|
|
xpread(fd, (uint8_t *) gbe[p], nf, p << 12, path);
|
2023-06-02 10:52:49 +00:00
|
|
|
handle_endianness(p);
|
2023-01-27 15:09:34 +00:00
|
|
|
}
|
2022-11-17 12:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-06-03 11:06:36 +00:00
|
|
|
cmd_setmac(void)
|
2022-11-17 12:07:09 +00:00
|
|
|
{
|
2023-04-07 01:21:37 +00:00
|
|
|
if (invalidMacAddress(strMac, mac))
|
2023-04-05 20:33:39 +00:00
|
|
|
err(errno = ECANCELED, "Bad MAC address");
|
2023-04-05 22:55:04 +00:00
|
|
|
for (int partnum = 0; partnum < 2; partnum++) {
|
2023-04-07 01:21:37 +00:00
|
|
|
if (validChecksum(part = partnum)) {
|
|
|
|
for (int w = 0; w < 3; w++)
|
|
|
|
setWord(w, partnum, mac[w]);
|
|
|
|
cmd_setchecksum();
|
|
|
|
}
|
2023-04-05 20:33:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2023-04-07 01:21:37 +00:00
|
|
|
invalidMacAddress(const char *strMac, uint16_t *mac)
|
2023-04-05 20:33:39 +00:00
|
|
|
{
|
2023-04-05 20:53:12 +00:00
|
|
|
uint64_t total = 0;
|
2023-04-07 01:21:37 +00:00
|
|
|
if (strnlen(strMac, 20) == 17) {
|
2023-06-03 11:06:36 +00:00
|
|
|
for (uint8_t h, i = 0; i < 16; i += 3) {
|
2023-04-05 20:33:39 +00:00
|
|
|
if (i != 15)
|
|
|
|
if (strMac[i + 2] != ':')
|
2023-04-07 01:21:37 +00:00
|
|
|
return 1;
|
2023-04-06 17:38:05 +00:00
|
|
|
int byte = i / 3;
|
|
|
|
for (int nib = 0; nib < 2; nib++, total += h) {
|
2023-04-05 22:55:04 +00:00
|
|
|
if ((h = hextonum(strMac[i + nib])) > 15)
|
2023-04-07 01:21:37 +00:00
|
|
|
return 1;
|
2023-04-05 20:33:39 +00:00
|
|
|
if ((byte == 0) && (nib == 1))
|
|
|
|
if (strMac[i + nib] == '?')
|
2023-04-06 18:41:53 +00:00
|
|
|
h = (h & 0xE) | 2; /* local, unicast */
|
2023-04-05 22:55:04 +00:00
|
|
|
mac[byte >> 1] |= ((uint16_t ) h)
|
2023-06-01 11:16:12 +00:00
|
|
|
<< ((8 * (byte % 2)) + (4 * (nib ^ 1)));
|
2022-11-17 12:07:09 +00:00
|
|
|
}
|
2023-04-07 01:21:37 +00:00
|
|
|
}}
|
|
|
|
return ((total == 0) | (mac[0] & 1)); /* multicast/all-zero banned */
|
2022-11-17 12:07:09 +00:00
|
|
|
}
|
|
|
|
|
2022-11-27 09:29:37 +00:00
|
|
|
uint8_t
|
2023-04-06 17:38:05 +00:00
|
|
|
hextonum(char ch)
|
2022-11-27 09:29:37 +00:00
|
|
|
{
|
2022-12-05 03:26:18 +00:00
|
|
|
if ((ch >= '0') && (ch <= '9'))
|
2023-04-06 17:38:05 +00:00
|
|
|
return ch - '0';
|
2022-12-05 03:26:18 +00:00
|
|
|
else if ((ch >= 'A') && (ch <= 'F'))
|
2023-04-06 17:38:05 +00:00
|
|
|
return ch - 'A' + 10;
|
2022-12-05 03:26:18 +00:00
|
|
|
else if ((ch >= 'a') && (ch <= 'f'))
|
2023-04-06 17:38:05 +00:00
|
|
|
return ch - 'a' + 10;
|
2023-06-03 11:06:36 +00:00
|
|
|
return (ch == '?') ? rhex() : 16;
|
2022-12-03 12:27:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
rhex(void)
|
|
|
|
{
|
2023-06-03 11:06:36 +00:00
|
|
|
static uint8_t n = 0, rnum[16];
|
2023-06-01 13:04:44 +00:00
|
|
|
if (!n)
|
2023-06-01 09:31:21 +00:00
|
|
|
xpread(rfd, (uint8_t *) &rnum, (n = 15) + 1, 0, "/dev/urandom");
|
2023-05-31 07:02:46 +00:00
|
|
|
return rnum[n--] & 0xf;
|
2022-11-27 09:29:37 +00:00
|
|
|
}
|
|
|
|
|
2022-11-26 23:16:33 +00:00
|
|
|
void
|
|
|
|
cmd_dump(void)
|
|
|
|
{
|
2023-06-03 11:06:36 +00:00
|
|
|
for (int partnum = 0, numInvalid = 0; partnum < 2; partnum++) {
|
2022-11-26 23:16:33 +00:00
|
|
|
if (!validChecksum(partnum))
|
|
|
|
++numInvalid;
|
|
|
|
printf("MAC (part %d): ", partnum);
|
2023-06-03 11:06:36 +00:00
|
|
|
showmac(partnum), hexdump(partnum);
|
|
|
|
errno = ((numInvalid < 2) && (partnum)) ? 0 : errno;
|
2022-11-26 23:16:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
showmac(int partnum)
|
|
|
|
{
|
2023-04-05 22:55:04 +00:00
|
|
|
for (int c = 0; c < 3; c++) {
|
2023-06-03 11:06:36 +00:00
|
|
|
uint16_t val16 = word(c, partnum);
|
2023-04-05 22:55:04 +00:00
|
|
|
printf("%02x:%02x", val16 & 0xff, val16 >> 8);
|
2023-04-06 20:56:36 +00:00
|
|
|
printf(c == 2 ? "\n" : ":");
|
2022-11-26 23:16:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
hexdump(int partnum)
|
|
|
|
{
|
2023-04-05 22:55:04 +00:00
|
|
|
for (int row = 0; row < 8; row++) {
|
2023-04-10 23:46:45 +00:00
|
|
|
printf("%07x", row << 4);
|
2023-04-05 22:55:04 +00:00
|
|
|
for (int c = 0; c < 8; c++) {
|
2023-04-07 12:43:37 +00:00
|
|
|
uint16_t val16 = word((row << 3) + c, partnum);
|
2023-04-10 23:46:45 +00:00
|
|
|
printf(" %02x%02x", val16 >> 8, val16 & 0xff);
|
2023-06-03 11:06:36 +00:00
|
|
|
} printf("\n");
|
2022-11-26 23:16:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-26 23:25:23 +00:00
|
|
|
void
|
|
|
|
cmd_setchecksum(void)
|
|
|
|
{
|
2023-04-05 22:55:04 +00:00
|
|
|
uint16_t val16 = 0;
|
|
|
|
for (int c = 0; c < 0x3F; c++)
|
2022-11-26 23:25:23 +00:00
|
|
|
val16 += word(c, part);
|
|
|
|
setWord(0x3F, part, 0xBABA - val16);
|
|
|
|
}
|
|
|
|
|
2022-11-26 23:29:41 +00:00
|
|
|
void
|
|
|
|
cmd_brick(void)
|
|
|
|
{
|
|
|
|
if (validChecksum(part))
|
|
|
|
setWord(0x3F, part, (word(0x3F, part)) ^ 0xFF);
|
|
|
|
}
|
|
|
|
|
2022-11-26 23:34:13 +00:00
|
|
|
void
|
|
|
|
cmd_swap(void)
|
|
|
|
{
|
2023-06-03 11:06:36 +00:00
|
|
|
if ((gbeFileModified = nvmPartModified[0] = nvmPartModified[1]
|
|
|
|
= validChecksum(1) | validChecksum(0)))
|
2023-06-01 11:21:55 +00:00
|
|
|
xorswap(gbe[0], gbe[1]); /* speedhack: swap ptr, not words */
|
2022-11-26 23:34:13 +00:00
|
|
|
}
|
|
|
|
|
2022-11-26 23:42:45 +00:00
|
|
|
void
|
|
|
|
cmd_copy(void)
|
|
|
|
{
|
2023-06-03 11:06:36 +00:00
|
|
|
if ((gbeFileModified = nvmPartModified[part ^ 1] = validChecksum(part)))
|
2023-06-01 11:21:55 +00:00
|
|
|
gbe[part ^ 1] = gbe[part]; /* speedhack: copy ptr, not words */
|
2022-11-26 23:42:45 +00:00
|
|
|
}
|
|
|
|
|
2022-11-17 12:07:09 +00:00
|
|
|
int
|
|
|
|
validChecksum(int partnum)
|
|
|
|
{
|
2023-04-05 22:55:04 +00:00
|
|
|
uint16_t total = 0;
|
|
|
|
for(int w = 0; w <= 0x3F; w++)
|
2022-11-17 12:07:09 +00:00
|
|
|
total += word(w, partnum);
|
2022-11-26 11:26:07 +00:00
|
|
|
if (total == 0xBABA)
|
|
|
|
return 1;
|
|
|
|
fprintf(stderr, "WARNING: BAD checksum in part %d\n", partnum);
|
2023-04-06 20:56:36 +00:00
|
|
|
return (errno = ECANCELED) & 0;
|
2022-11-17 12:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-01-27 20:13:15 +00:00
|
|
|
setWord(int pos16, int partnum, uint16_t val16)
|
2022-11-17 12:07:09 +00:00
|
|
|
{
|
2023-06-01 07:21:25 +00:00
|
|
|
if ((gbeFileModified = 1) && word(pos16, partnum) != val16)
|
2023-06-01 06:31:16 +00:00
|
|
|
nvmPartModified[partnum] = 1 | (word(pos16, partnum) = val16);
|
2022-11-17 12:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2023-06-01 09:31:21 +00:00
|
|
|
xorswap_buf(int partnum)
|
2022-12-05 03:26:18 +00:00
|
|
|
{
|
2023-04-05 22:55:04 +00:00
|
|
|
uint8_t *nbuf = (uint8_t *) gbe[partnum];
|
2023-06-01 09:31:21 +00:00
|
|
|
for (size_t w = 0; w < (nf >> 1); w++)
|
2023-06-01 06:21:30 +00:00
|
|
|
xorswap(nbuf[w << 1], nbuf[(w << 1) + 1]);
|
2022-11-17 12:07:09 +00:00
|
|
|
}
|
2022-11-27 09:43:47 +00:00
|
|
|
|
|
|
|
void
|
2023-06-01 09:31:21 +00:00
|
|
|
writeGbeFile(const char *filename)
|
2022-11-27 09:43:47 +00:00
|
|
|
{
|
2023-06-03 11:06:36 +00:00
|
|
|
errno = 0;
|
2023-06-02 10:52:49 +00:00
|
|
|
for (int x = gbe[0] > gbe[1] ? 1 : 0, p = 0; p < 2; p++, x ^= 1) {
|
|
|
|
if (!nvmPartModified[x])
|
|
|
|
continue;
|
|
|
|
handle_endianness(x);
|
|
|
|
xpwrite(fd, (uint8_t *) gbe[x], nf, x << 12, filename);
|
2022-11-27 09:43:47 +00:00
|
|
|
}
|
2023-06-01 09:31:21 +00:00
|
|
|
xclose(fd, filename);
|
2022-11-27 09:43:47 +00:00
|
|
|
}
|