summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2026-03-24 00:28:15 +0000
committerLeah Rowe <leah@libreboot.org>2026-03-24 01:25:53 +0000
commitf2544d094ba88e1cfbb7993ad67444852cfd5efd (patch)
tree252172594a1284e59e88c73c22f0201508809022 /util
parentafcd535816b45fd7b0e0d07c1a8580f6f462f5e4 (diff)
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 <leah@libreboot.org>
Diffstat (limited to 'util')
-rw-r--r--util/libreboot-utils/.gitignore (renamed from util/nvmutil/.gitignore)1
-rw-r--r--util/libreboot-utils/AUTHORS (renamed from util/nvmutil/AUTHORS)0
-rw-r--r--util/libreboot-utils/COPYING (renamed from util/nvmutil/COPYING)0
-rw-r--r--util/libreboot-utils/Makefile (renamed from util/nvmutil/Makefile)32
-rw-r--r--util/libreboot-utils/include/common.h (renamed from util/nvmutil/include/common.h)8
-rw-r--r--util/libreboot-utils/lib/checksum.c (renamed from util/nvmutil/lib/checksum.c)0
-rw-r--r--util/libreboot-utils/lib/command.c (renamed from util/nvmutil/lib/command.c)0
-rw-r--r--util/libreboot-utils/lib/file.c (renamed from util/nvmutil/lib/file.c)0
-rw-r--r--util/libreboot-utils/lib/io.c (renamed from util/nvmutil/lib/io.c)0
-rw-r--r--util/libreboot-utils/lib/mkhtemp.c (renamed from util/nvmutil/lib/mkhtemp.c)10
-rw-r--r--util/libreboot-utils/lib/num.c (renamed from util/nvmutil/lib/num.c)0
-rw-r--r--util/libreboot-utils/lib/state.c (renamed from util/nvmutil/lib/state.c)27
-rw-r--r--util/libreboot-utils/lib/string.c (renamed from util/nvmutil/lib/string.c)32
-rw-r--r--util/libreboot-utils/lib/usage.c (renamed from util/nvmutil/lib/usage.c)0
-rw-r--r--util/libreboot-utils/lib/word.c (renamed from util/nvmutil/lib/word.c)0
-rw-r--r--util/libreboot-utils/mkhtemp.c139
-rw-r--r--util/libreboot-utils/nvmutil.c (renamed from util/nvmutil/nvmutil.c)10
17 files changed, 208 insertions, 51 deletions
diff --git a/util/nvmutil/.gitignore b/util/libreboot-utils/.gitignore
index 9414c836..fbf110f9 100644
--- a/util/nvmutil/.gitignore
+++ b/util/libreboot-utils/.gitignore
@@ -1,5 +1,6 @@
/nvm
/nvmutil
+/mkhtemp
*.bin
*.o
*.d
diff --git a/util/nvmutil/AUTHORS b/util/libreboot-utils/AUTHORS
index f38ea210..f38ea210 100644
--- a/util/nvmutil/AUTHORS
+++ b/util/libreboot-utils/AUTHORS
diff --git a/util/nvmutil/COPYING b/util/libreboot-utils/COPYING
index 47c35a86..47c35a86 100644
--- a/util/nvmutil/COPYING
+++ b/util/libreboot-utils/COPYING
diff --git a/util/nvmutil/Makefile b/util/libreboot-utils/Makefile
index a2b65aeb..f741d3f5 100644
--- a/util/nvmutil/Makefile
+++ b/util/libreboot-utils/Makefile
@@ -24,8 +24,9 @@ STRICT = $(WARN) -std=c90 -pedantic -Werror
HELLFLAGS = $(STRICT) -Weverything
PROG = nvmutil
+PROGMKH = mkhtemp
-OBJS = \
+OBJS_NVMUTIL = \
obj/nvmutil.o \
obj/lib/state.o \
obj/lib/file.o \
@@ -38,17 +39,28 @@ OBJS = \
obj/lib/word.o \
obj/lib/mkhtemp.o
+OBJS_MKHTEMP = \
+ obj/mkhtemp.o \
+ obj/lib/file.o \
+ obj/lib/string.o \
+ obj/lib/num.o \
+ obj/lib/mkhtemp.o
+
# default mode
CFLAGS_MODE = $(PORTABLE)
CC_MODE = $(CC)
-all: $(PROG)
+all: $(PROG) $(PROGMKH)
+
+$(PROG): $(OBJS_NVMUTIL)
+ $(CC_MODE) $(OBJS_NVMUTIL) -o $(PROG) $(LDFLAGS)
-$(PROG): $(OBJS)
- $(CC_MODE) $(OBJS) -o $(PROG) $(LDFLAGS)
+$(PROGMKH): $(OBJS_MKHTEMP)
+ $(CC_MODE) $(OBJS_MKHTEMP) -o $(PROGMKH) $(LDFLAGS)
# ensure obj directory exists
-$(OBJS): obj
+$(OBJS_NVMUTIL): obj
+$(OBJS_MKHTEMP): obj
obj:
mkdir obj || true
@@ -59,6 +71,9 @@ obj:
obj/nvmutil.o: nvmutil.c
$(CC_MODE) $(CFLAGS_MODE) -c nvmutil.c -o obj/nvmutil.o
+obj/mkhtemp.o: mkhtemp.c
+ $(CC_MODE) $(CFLAGS_MODE) -c mkhtemp.c -o obj/mkhtemp.o
+
# library/helper objects
obj/lib/state.o: lib/state.c
@@ -93,16 +108,19 @@ obj/lib/mkhtemp.o: lib/mkhtemp.c
# install
-install: $(PROG)
+install: $(PROG) $(PROGMKH)
$(INSTALL) -d $(DESTDIR)$(PREFIX)/bin
$(INSTALL) $(PROG) $(DESTDIR)$(PREFIX)/bin/$(PROG)
chmod 755 $(DESTDIR)$(PREFIX)/bin/$(PROG)
+ $(INSTALL) $(PROGMKH) $(DESTDIR)$(PREFIX)/bin/$(PROGMKH)
+ chmod 755 $(DESTDIR)$(PREFIX)/bin/$(PROGMKH)
uninstall:
rm -f $(DESTDIR)$(PREFIX)/bin/$(PROG)
+ rm -f $(DESTDIR)$(PREFIX)/bin/$(PROGMKH)
clean:
- rm -f $(PROG) $(OBJS)
+ rm -f $(PROG) $(PROGMKH) $(OBJS_NVMUTIL) $(OBJS_MKHTEMP)
distclean: clean
diff --git a/util/nvmutil/include/common.h b/util/libreboot-utils/include/common.h
index 4aca1772..5d6405bc 100644
--- a/util/nvmutil/include/common.h
+++ b/util/libreboot-utils/include/common.h
@@ -1,5 +1,9 @@
/* SPDX-License-Identifier: MIT
* Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
+
+ TODO: this file should be split, into headers for each
+ C source file specifically. it was originally just
+ for nvmutil, until i added mkhtemp to the mix
*/
@@ -495,8 +499,8 @@ const char *getnvmprogname(void);
int new_tmpfile(int *fd, char **path);
int new_tmpdir(int *fd, char **path);
-static int new_tmp_common(int *fd, char **path, int type);
-static int mkhtemp_try_create(int dirfd,
+int new_tmp_common(int *fd, char **path, int type);
+int mkhtemp_try_create(int dirfd,
struct stat *st_dir_initial,
char *fname_copy,
char *p,
diff --git a/util/nvmutil/lib/checksum.c b/util/libreboot-utils/lib/checksum.c
index b417dc7e..b417dc7e 100644
--- a/util/nvmutil/lib/checksum.c
+++ b/util/libreboot-utils/lib/checksum.c
diff --git a/util/nvmutil/lib/command.c b/util/libreboot-utils/lib/command.c
index 3a863d23..3a863d23 100644
--- a/util/nvmutil/lib/command.c
+++ b/util/libreboot-utils/lib/command.c
diff --git a/util/nvmutil/lib/file.c b/util/libreboot-utils/lib/file.c
index ea2bcd0b..ea2bcd0b 100644
--- a/util/nvmutil/lib/file.c
+++ b/util/libreboot-utils/lib/file.c
diff --git a/util/nvmutil/lib/io.c b/util/libreboot-utils/lib/io.c
index 94bde87e..94bde87e 100644
--- a/util/nvmutil/lib/io.c
+++ b/util/libreboot-utils/lib/io.c
diff --git a/util/nvmutil/lib/mkhtemp.c b/util/libreboot-utils/lib/mkhtemp.c
index 2fcb894e..7c2f1fde 100644
--- a/util/nvmutil/lib/mkhtemp.c
+++ b/util/libreboot-utils/lib/mkhtemp.c
@@ -39,7 +39,7 @@ new_tmpdir(int *fd, char **path)
return new_tmp_common(fd, path, MKHTEMP_DIR);
}
-static int
+int
new_tmp_common(int *fd, char **path, int type)
{
#if defined(PATH_LEN) && \
@@ -466,13 +466,13 @@ sticky_hell:
/* mk(h)temp - hardened mktemp.
* like mkstemp, but (MUCH) harder.
*
- * designed to resist TOCTOU attacsk
+ * designed to resist TOCTOU attacks
* e.g. directory race / symlink attack
*
* extremely strict and even implements
* some limited userspace-level sandboxing,
- * similar to openbsd unveil (which you
- * can also use with this in your program)
+ * similar in spirit to openbsd unveil,
+ * though unveil is from kernel space.
*
* supports both files and directories.
* file: type = MKHTEMP_FILE (0)
@@ -661,7 +661,7 @@ success:
return (*fd >= 0) ? *fd : -1;
}
-static int
+int
mkhtemp_try_create(int dirfd,
struct stat *st_dir_initial,
char *fname_copy,
diff --git a/util/nvmutil/lib/num.c b/util/libreboot-utils/lib/num.c
index 343350b0..343350b0 100644
--- a/util/nvmutil/lib/num.c
+++ b/util/libreboot-utils/lib/num.c
diff --git a/util/nvmutil/lib/state.c b/util/libreboot-utils/lib/state.c
index 19d5cd8c..d06a8869 100644
--- a/util/nvmutil/lib/state.c
+++ b/util/libreboot-utils/lib/state.c
@@ -152,33 +152,6 @@ xstatus(void)
return x;
}
-/* early init functions that
- should not access state
- WARNING:
- does not do cleanup. only
- call this during pre-init
- */
-void
-err_no_cleanup(int nvm_errval, const char *msg, ...)
-{
- va_list args;
-
- if (errno == 0)
- errno = nvm_errval;
- if (!errno)
- errno = ECANCELED;
-
- fprintf(stderr, "nvmutil: ");
-
- va_start(args, msg);
- vfprintf(stderr, msg, args);
- va_end(args);
-
- fprintf(stderr, ": %s\n", strerror(errno));
-
- exit(EXIT_FAILURE);
-}
-
void
err(int nvm_errval, const char *msg, ...)
{
diff --git a/util/nvmutil/lib/string.c b/util/libreboot-utils/lib/string.c
index ca58fb1c..cb37c1ba 100644
--- a/util/nvmutil/lib/string.c
+++ b/util/libreboot-utils/lib/string.c
@@ -8,8 +8,11 @@
#include <sys/stat.h>
#include <errno.h>
+#include <stdarg.h>
#include <stddef.h>
+#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include <unistd.h>
#include "../include/common.h"
@@ -112,3 +115,32 @@ slen(const char *s,
*rval = ch;
return 0;
}
+
+/* the one for nvmutil state is in state.c */
+/* this one just exits */
+void
+err_no_cleanup(int nvm_errval, const char *msg, ...)
+{
+ va_list args;
+
+#if defined(__OpenBSD__) && defined(OpenBSD)
+#if (OpenBSD) >= 509
+ if (pledge("stdio", NULL) == -1)
+ fprintf(stderr, "pledge failure during exit");
+#endif
+#endif
+
+ if (!errno)
+ errno = ECANCELED;
+
+ fprintf(stderr, "nvmutil: ");
+
+ va_start(args, msg);
+ vfprintf(stderr, msg, args);
+ va_end(args);
+
+ fprintf(stderr, ": %s\n", strerror(errno));
+
+ exit(EXIT_FAILURE);
+}
+
diff --git a/util/nvmutil/lib/usage.c b/util/libreboot-utils/lib/usage.c
index 3b0614e8..3b0614e8 100644
--- a/util/nvmutil/lib/usage.c
+++ b/util/libreboot-utils/lib/usage.c
diff --git a/util/nvmutil/lib/word.c b/util/libreboot-utils/lib/word.c
index f84dae6a..f84dae6a 100644
--- a/util/nvmutil/lib/word.c
+++ b/util/libreboot-utils/lib/word.c
diff --git a/util/libreboot-utils/mkhtemp.c b/util/libreboot-utils/mkhtemp.c
new file mode 100644
index 00000000..5e7fcc0f
--- /dev/null
+++ b/util/libreboot-utils/mkhtemp.c
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: MIT
+ * Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
+ *
+ * WORK IN PROGRESS (proof of concept), or, v0.0000001
+ *
+ * Mkhtemp - Hardened mktemp. Create files and directories
+ * randomly as determined by user's TMPDIR, or fallback. It
+ * attemps to provide mitigation against several TOCTOU-based
+ * attacks e.g. directory rename / symlink attacks, and it
+ * generally provides much higher strictness than previous
+ * implementations such as mktemp, mkstemp or even mkdtemp.
+ *
+ * Many programs rely on mktemp, and they use TMPDIR in a way
+ * that is quite insecure. Mkhtemp intends to change that,
+ * quite dramatically, with: userspace sandbox (and use OS
+ * level options e.g. OBSD pledge where available), constant
+ * identity/ownership checks on files, MUCH stricter ownership
+ * restrictions (e.g. enforce sticky bit policy on world-
+ * writeable tmpdirs), preventing operation on other people's
+ * files (only your own files) - even root is restricted,
+ * depending on how the code is compiled. Please read the code.
+ *
+ * This is the utility version, which makes use of the also-
+ * included library. No docs yet - source code are the docs,
+ * and the (ever evolving, and hardening) specification.
+ *
+ * This was written from scratch, for use in nvmutil, and
+ * it is designed to be portable (BSD, Linux). Patches
+ * very much welcome.
+ *
+ * WARNING: This is MUCH stricter than every other mktemp
+ * implementation, even more so than mkdtemp or
+ * the OpenBSD version of mkstemp. It *will* break,
+ * or more specifically, reveal the flaws in, almost
+ * every major critical infrastructure, because most
+ * people already use mktemp extremely insecurely.
+ *
+ * This tool is written by me, for me, and also Libreboot, but
+ * it will be summitted for review to various Linux distros
+ * and BSD projects once it has reached maturity.
+ */
+
+#if defined(__linux__) && !defined(_GNU_SOURCE)
+/* for openat2 on linux */
+#define _GNU_SOURCE 1
+#endif
+
+#ifdef __OpenBSD__
+#include <sys/param.h> /* pledge(2) */
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "include/common.h"
+
+int
+main(int argc, char *argv[])
+{
+ char *s = NULL;
+ int fd = -1;
+ char c;
+ int type = MKHTEMP_FILE;
+ size_t len;
+
+#if defined (PATH_LEN) && \
+ (PATH_LEN) >= 256
+ size_t maxlen = PATH_LEN;
+#else
+ size_t maxlen = 4096;
+#endif
+
+/* https://man.openbsd.org/pledge.2 */
+#if defined(__OpenBSD__) && defined(OpenBSD)
+#if (OpenBSD) >= 509
+ if (pledge("stdio flock rpath wpath cpath", NULL) == -1)
+ err_no_cleanup(errno, "pledge, main");
+#endif
+#endif
+
+ while ((c =
+ getopt(argc, argv, "d")) != -1) {
+
+ switch(c) {
+ case 'd':
+
+ type = MKHTEMP_DIR;
+ break;
+ default:
+
+ err_no_cleanup(EINVAL,
+ "usage: mkhtemp [-d]\n");
+ }
+ }
+
+ if (new_tmp_common(&fd, &s, type) < 0)
+ err_no_cleanup(errno, NULL);
+
+#if defined(__OpenBSD__) && defined(OpenBSD)
+#if (OpenBSD) >= 509
+ if (pledge("stdio", NULL) == -1)
+ err_no_cleanup(errno, "pledge, exit");
+#endif
+#endif
+
+ if (s == NULL)
+ err_no_cleanup(EFAULT, "bad string initialisation");
+
+ if (*s == '\0')
+ err_no_cleanup(EFAULT, "empty string initialisation");
+
+ if (slen(s, maxlen, &len) < 0)
+ err_no_cleanup(EFAULT, "unterminated string initialisation");
+
+ printf("%s\n", s);
+
+ return EXIT_SUCCESS;
+}/*
+
+
+ ( >:3 )
+ /| |\
+ / \
+
+
+
+
+
+ */
diff --git a/util/nvmutil/nvmutil.c b/util/libreboot-utils/nvmutil.c
index 266654e8..cb08ec43 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/libreboot-utils/nvmutil.c
@@ -35,16 +35,6 @@ main(int argc, char *argv[])
size_t c;
- int rval;
- char *test = NULL;
- int fd = -1;
- rval = new_tmpdir(&fd, &test);
- if (rval < 0)
- err_no_cleanup(errno, "TESTERR: ");
-
- printf("TEST: %s\n", test);
- exit(1);
-
/* https://man.openbsd.org/pledge.2
https://man.openbsd.org/unveil.2 */
#if defined(__OpenBSD__) && defined(OpenBSD)