From f2544d094ba88e1cfbb7993ad67444852cfd5efd Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Tue, 24 Mar 2026 00:28:15 +0000 Subject: util/mkhtemp: new utility (hardened mktemp) part of the same code library as nvmutil. as part of this, i renamed util/nvmutil to util/libreboot-utils/ because it is now a multi-utility codebase. this is more efficient, since i also wish to use mkhtemp (function) in nvmutil. Signed-off-by: Leah Rowe --- util/libreboot-utils/lib/state.c | 252 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 util/libreboot-utils/lib/state.c (limited to 'util/libreboot-utils/lib/state.c') diff --git a/util/libreboot-utils/lib/state.c b/util/libreboot-utils/lib/state.c new file mode 100644 index 00000000..d06a8869 --- /dev/null +++ b/util/libreboot-utils/lib/state.c @@ -0,0 +1,252 @@ +/* SPDX-License-Identifier: MIT + * Copyright (c) 2022-2026 Leah Rowe + * + * State machine (singleton) for nvmutil data. + */ + +#ifdef __OpenBSD__ +#include +#endif +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/common.h" + +struct xstate * +xstart(int argc, char *argv[]) +{ + static int first_run = 1; + static int pre_init = 0; + + static struct xstate us = { + /* DO NOT MESS THIS UP, OR THERE WILL BE DEMONS */ + { + { + CMD_DUMP, "dump", cmd_helper_dump, ARGC_3, + ARG_NOPART, + SKIP_CHECKSUM_READ, SKIP_CHECKSUM_WRITE, + NVM_SIZE, O_RDONLY + }, { + CMD_SETMAC, "setmac", cmd_helper_setmac, ARGC_3, + ARG_NOPART, + CHECKSUM_READ, CHECKSUM_WRITE, + NVM_SIZE, O_RDWR + }, { + CMD_SWAP, "swap", cmd_helper_swap, ARGC_3, + ARG_NOPART, + CHECKSUM_READ, SKIP_CHECKSUM_WRITE, + GBE_PART_SIZE, O_RDWR + }, { + CMD_COPY, "copy", cmd_helper_copy, ARGC_4, + ARG_PART, + CHECKSUM_READ, SKIP_CHECKSUM_WRITE, + GBE_PART_SIZE, O_RDWR + }, { + CMD_CAT, "cat", cmd_helper_cat, ARGC_3, + ARG_NOPART, + CHECKSUM_READ, SKIP_CHECKSUM_WRITE, + GBE_PART_SIZE, O_RDONLY + }, { + CMD_CAT16, "cat16", cmd_helper_cat16, ARGC_3, + ARG_NOPART, + CHECKSUM_READ, SKIP_CHECKSUM_WRITE, + GBE_PART_SIZE, O_RDONLY + }, { + CMD_CAT128, "cat128", cmd_helper_cat128, ARGC_3, + ARG_NOPART, + CHECKSUM_READ, SKIP_CHECKSUM_WRITE, + GBE_PART_SIZE, O_RDONLY + } + }, + + /* ->mac */ + {NULL, "xx:xx:xx:xx:xx:xx", {0, 0, 0}}, /* .str, .rmac, .mac_buf */ + + /* .f */ + {0}, + + /* .argv0 (for our getprogname implementation) */ + NULL, + + /* ->i (index to cmd[]) */ + 0, + + /* .no_cmd (set 0 when a command is found) */ + 1, + + /* .cat (cat helpers set this) */ + -1 + + }; + + if (!first_run) { + if (pre_init) + err_no_cleanup(ECANCELED, + "Outside access to state during init"); + + first_run = 0; + + return &us; + } + + if (argc < 3) + err_no_cleanup(EINVAL, "xstart: Too few arguments"); + if (argv == NULL) + err_no_cleanup(EINVAL, "xstart: NULL argv"); + + first_run = 0; + pre_init = 1; + + us.f.buf = us.f.real_buf; + + us.argv0 = argv[0]; + us.f.fname = argv[1]; + + if (new_tmpfile(&us.f.tmp_fd, &us.f.tname) < 0) + err_no_cleanup(errno, "xstart: cannot create tmpfile"); + + /* parse user command */ +/* TODO: CHECK ACCESSES VIA xstatus() */ + set_cmd(argc, argv); + set_cmd_args(argc, argv); + + if (us.f.tname == NULL) + err_no_cleanup(errno, "x->f.tname null"); + if (*us.f.tname == '\0') + err_no_cleanup(errno, "x->f.tname empty"); + + if (fstat(us.f.tmp_fd, &us.f.tmp_st) < 0) + err_no_cleanup(errno, "%s: stat", us.f.tname); + + memset(us.f.real_buf, 0, sizeof(us.f.real_buf)); + memset(us.f.bufcmp, 0, sizeof(us.f.bufcmp)); + + /* for good measure */ + memset(us.f.pad, 0, sizeof(us.f.pad)); + + pre_init = 0; + + return &us; +} + +struct xstate * +xstatus(void) +{ + struct xstate *x = xstart(0, NULL); + + if (x == NULL) + err_no_cleanup(EACCES, "NULL pointer to xstate"); + + sanitize_command_list(); + + return x; +} + +void +err(int nvm_errval, const char *msg, ...) +{ + struct xstate *x = xstatus(); + + va_list args; + + if (errno == 0) + errno = nvm_errval; + if (!errno) + errno = ECANCELED; + + (void)exit_cleanup(); + + if (x != NULL) + fprintf(stderr, "%s: ", getnvmprogname()); + + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + + fprintf(stderr, ": %s\n", strerror(errno)); + + exit(EXIT_FAILURE); +} + +const char * +getnvmprogname(void) +{ + struct xstate *x = xstatus(); + + const char *p; + static char fallback[] = "nvmutil"; + + char *rval = fallback; + + if (x != NULL) { + if (x->argv0 == NULL || *x->argv0 == '\0') + return ""; + + rval = x->argv0; + } + + p = strrchr(rval, '/'); + + if (p) + return p + 1; + else + return rval; +} + +int +exit_cleanup(void) +{ + struct xstate *x = xstatus(); + struct xfile *f; + + int close_err; + int saved_errno; + + close_err = 0; + saved_errno = errno; + + if (x != NULL) { + f = &x->f; + + if (f->gbe_fd > -1) { + if (close_on_eintr(f->gbe_fd) == -1) { + f->gbe_fd = -1; + close_err = 1; + } + f->gbe_fd = -1; + } + + if (f->tmp_fd > -1) { + if (close_on_eintr(f->tmp_fd) == -1) { + f->tmp_fd = -1; + close_err = 1; + } + f->tmp_fd = -1; + } + + if (f->tname != NULL) { + if (unlink(f->tname) == -1) + close_err = 1; + } + + f->tmp_fd = -1; + } + + if (saved_errno) + errno = saved_errno; + + if (close_err) + return -1; + + return 0; +} -- cgit v1.2.1