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-01 09:31:21 +00:00
|
|
|
int flags = O_RDWR;
|
2022-11-27 00:27:07 +00:00
|
|
|
void (*cmd)(void) = NULL;
|
2023-01-28 23:01:41 +00:00
|
|
|
const char *strMac = NULL, *strRMac = "??:??:??:??:??:??";
|
2022-11-17 12:07:09 +00:00
|
|
|
|
|
|
|
if (argc == 3) {
|
|
|
|
if (strcmp(COMMAND, "dump") == 0) {
|
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 unveil", NULL);
|
2022-11-17 12:07:09 +00:00
|
|
|
flags = O_RDONLY;
|
2022-11-27 00:27:07 +00:00
|
|
|
cmd = &cmd_dump;
|
2023-04-07 13:50:36 +00:00
|
|
|
} else if (strcmp(COMMAND, "setmac") == 0) {
|
2023-04-06 18:30:20 +00:00
|
|
|
strMac = (char *) strRMac; /* random mac address */
|
2023-04-07 13:50:36 +00:00
|
|
|
} else if (strcmp(COMMAND, "swap") == 0) {
|
2022-11-27 00:27:07 +00:00
|
|
|
cmd = &cmd_swap;
|
2023-06-01 09:31:21 +00:00
|
|
|
nf = SIZE_4KB;
|
2023-04-07 13:50:36 +00:00
|
|
|
}
|
2022-11-17 12:07:09 +00:00
|
|
|
} else if (argc == 4) {
|
2023-04-07 13:50:36 +00:00
|
|
|
if (strcmp(COMMAND, "setmac") == 0) {
|
2023-04-06 18:30:20 +00:00
|
|
|
strMac = MAC_ADDRESS; /* user-supplied mac address */
|
2023-04-07 13:50:36 +00:00
|
|
|
} else if ((!((part = PARTNUM[0] - '0') == 0 || part == 1))
|
|
|
|
|| PARTNUM[1]) { /* only allow '1' or '0' */
|
2022-11-17 12:07:09 +00:00
|
|
|
errno = EINVAL;
|
2023-04-07 13:50:36 +00:00
|
|
|
} else if (strcmp(COMMAND, "setchecksum") == 0) {
|
2022-11-27 00:27:07 +00:00
|
|
|
cmd = &cmd_setchecksum;
|
2023-04-07 13:50:36 +00:00
|
|
|
} else if (strcmp(COMMAND, "brick") == 0) {
|
2022-11-27 00:27:07 +00:00
|
|
|
cmd = &cmd_brick;
|
2023-04-07 13:50:36 +00:00
|
|
|
} else if (strcmp(COMMAND, "copy") == 0) {
|
2022-11-27 00:27:07 +00:00
|
|
|
cmd = &cmd_copy;
|
2023-06-01 09:31:21 +00:00
|
|
|
nf = SIZE_4KB;
|
2023-04-07 13:50:36 +00:00
|
|
|
}
|
2022-11-27 00:39:06 +00:00
|
|
|
}
|
2022-11-17 12:07:09 +00:00
|
|
|
|
2023-06-01 07:21:25 +00:00
|
|
|
err_if((errno = ((strMac == NULL) && (cmd == NULL)) ? EINVAL : errno));
|
2023-05-31 08:30:13 +00:00
|
|
|
|
|
|
|
skipread[part ^ 1] = (cmd == &cmd_copy) |
|
|
|
|
(cmd == &cmd_setchecksum) | (cmd == &cmd_brick);
|
2023-06-01 09:31:21 +00:00
|
|
|
readGbeFile(FILENAME, flags);
|
2023-05-31 08:30:13 +00:00
|
|
|
(void)rhex();
|
|
|
|
xunveil("/dev/urandom", "r");
|
|
|
|
if (flags == O_RDONLY) {
|
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", NULL);
|
2023-05-31 08:30:13 +00:00
|
|
|
} else {
|
|
|
|
xpledge("stdio wpath unveil", NULL);
|
|
|
|
xunveil(FILENAME, "w");
|
|
|
|
}
|
2022-11-17 12:07:09 +00:00
|
|
|
|
2023-05-31 08:30:13 +00:00
|
|
|
if (strMac != NULL)
|
|
|
|
cmd_setmac(strMac); /* nvm gbe.bin setmac */
|
|
|
|
else if (cmd != NULL)
|
|
|
|
(*cmd)(); /* all other commands except setmac */
|
2023-06-01 09:31:21 +00:00
|
|
|
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 09:31:21 +00:00
|
|
|
readGbeFile(const char *path, int flags)
|
2022-11-17 12:07:09 +00:00
|
|
|
{
|
2023-06-01 09:31:21 +00:00
|
|
|
xopen(fd, path, flags);
|
|
|
|
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 09:31:21 +00:00
|
|
|
errno = errno != ENOTDIR ? errno : 0;
|
2023-01-27 15:09:34 +00:00
|
|
|
|
2023-06-01 09:31:21 +00:00
|
|
|
big_endian = ((uint8_t *) &test)[0] ^ 1;
|
|
|
|
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);
|
|
|
|
handle_endianness();
|
2023-01-27 15:09:34 +00:00
|
|
|
}
|
2022-11-17 12:07:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-11-27 09:43:47 +00:00
|
|
|
cmd_setmac(const char *strMac)
|
2022-11-17 12:07:09 +00:00
|
|
|
{
|
2023-04-05 20:33:39 +00:00
|
|
|
uint16_t mac[3] = {0, 0, 0};
|
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 22:55:04 +00:00
|
|
|
uint8_t h;
|
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-04-05 22:55:04 +00:00
|
|
|
for (int 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-04-07 01:21:37 +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;
|
2022-12-05 03:26:18 +00:00
|
|
|
else if (ch == '?')
|
2023-04-06 18:30:20 +00:00
|
|
|
return rhex(); /* random number */
|
2022-12-05 03:26:18 +00:00
|
|
|
else
|
2022-12-03 12:27:53 +00:00
|
|
|
return 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t
|
|
|
|
rhex(void)
|
|
|
|
{
|
2023-05-31 07:02:46 +00:00
|
|
|
static int rfd = -1, n = 0;
|
|
|
|
static uint8_t rnum[16];
|
|
|
|
if (!n) {
|
2023-06-01 09:31:21 +00:00
|
|
|
xopen(rfd, "/dev/urandom", O_RDONLY);
|
|
|
|
xpread(rfd, (uint8_t *) &rnum, (n = 15) + 1, 0, "/dev/urandom");
|
2022-11-27 09:29:37 +00:00
|
|
|
}
|
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-04-05 22:55:04 +00:00
|
|
|
int partnum, numInvalid = 0;
|
2023-04-06 17:38:05 +00:00
|
|
|
for (partnum = 0; partnum < 2; partnum++) {
|
2022-11-26 23:16:33 +00:00
|
|
|
if (!validChecksum(partnum))
|
|
|
|
++numInvalid;
|
|
|
|
printf("MAC (part %d): ", partnum);
|
|
|
|
showmac(partnum);
|
|
|
|
hexdump(partnum);
|
|
|
|
}
|
|
|
|
if (numInvalid < 2)
|
|
|
|
errno = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
showmac(int partnum)
|
|
|
|
{
|
|
|
|
uint16_t val16;
|
2023-04-05 22:55:04 +00:00
|
|
|
for (int c = 0; c < 3; c++) {
|
2022-11-26 23:16:33 +00:00
|
|
|
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);
|
2022-11-26 23:16:33 +00:00
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-01 06:21:30 +00:00
|
|
|
xorswap(gbe[0], gbe[1]); /* speedhack: swap ptr, not words */
|
2023-04-07 01:21:37 +00:00
|
|
|
gbeFileModified = nvmPartModified[0] = nvmPartModified[1]
|
|
|
|
= validChecksum(1) | validChecksum(0);
|
2022-11-26 23:34:13 +00:00
|
|
|
}
|
|
|
|
|
2022-11-26 23:42:45 +00:00
|
|
|
void
|
|
|
|
cmd_copy(void)
|
|
|
|
{
|
2023-04-07 01:21:37 +00:00
|
|
|
gbe[part ^ 1] = gbe[part]; /* speedhack: copy ptr, not words */
|
|
|
|
gbeFileModified = nvmPartModified[part ^ 1] = validChecksum(part);
|
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-04-07 12:43:37 +00:00
|
|
|
if (gbeFileModified)
|
|
|
|
errno = 0;
|
2023-04-07 13:11:19 +00:00
|
|
|
for (int p = 0; p < 2; p++) {
|
2023-04-06 19:48:28 +00:00
|
|
|
if (gbe[0] > gbe[1])
|
|
|
|
p ^= 1; /* speedhack: write sequentially on-disk */
|
2023-04-06 17:59:49 +00:00
|
|
|
if (!nvmPartModified[p])
|
2023-01-28 20:27:24 +00:00
|
|
|
goto next_part;
|
2023-06-01 09:31:21 +00:00
|
|
|
handle_endianness();
|
|
|
|
xpwrite(fd, (uint8_t *) gbe[p], nf, p << 12, filename);
|
2023-01-28 20:27:24 +00:00
|
|
|
next_part:
|
|
|
|
if (gbe[0] > gbe[1])
|
2023-04-06 19:48:28 +00:00
|
|
|
p ^= 1; /* speedhack: write sequentially on-disk */
|
2022-11-27 09:43:47 +00:00
|
|
|
}
|
2023-06-01 09:31:21 +00:00
|
|
|
xclose(fd, filename);
|
2023-05-31 07:02:46 +00:00
|
|
|
xpledge("stdio", NULL);
|
2022-11-27 09:43:47 +00:00
|
|
|
}
|