diff options
| author | Leah Rowe <leah@libreboot.org> | 2026-03-24 00:28:15 +0000 |
|---|---|---|
| committer | Leah Rowe <leah@libreboot.org> | 2026-03-24 01:25:53 +0000 |
| commit | f2544d094ba88e1cfbb7993ad67444852cfd5efd (patch) | |
| tree | 252172594a1284e59e88c73c22f0201508809022 /util | |
| parent | afcd535816b45fd7b0e0d07c1a8580f6f462f5e4 (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.c | 139 | ||||
| -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) |
