summaryrefslogtreecommitdiff
path: root/util/libreboot-utils/mkhtemp.c
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/libreboot-utils/mkhtemp.c
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/libreboot-utils/mkhtemp.c')
-rw-r--r--util/libreboot-utils/mkhtemp.c139
1 files changed, 139 insertions, 0 deletions
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 )
+ /| |\
+ / \
+
+
+
+
+
+ */