/* SPDX-License-Identifier: MIT * Copyright (c) 2026 Leah Rowe * * 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 /* pledge(2) */ #endif #include #include #include #include #include #include #include #include #include #include #include #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 if (lbgetprogname(argv[0]) == NULL) err_no_cleanup(errno, "could not set progname"); /* 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, NULL) < 0) err_no_cleanup(errno, "%s", s); #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 ) /| |\ / \ */