WIP: always use openat

why would i write a secure mktemp to be used
on linux from 1999?????

Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
Leah Rowe
2026-03-22 15:54:48 +00:00
parent 825d520575
commit 7694b307b8
2 changed files with 21 additions and 119 deletions

View File

@@ -69,13 +69,6 @@ int fchmod(int fd, mode_t mode);
#define OFF_RESET 1
#endif
/* by default: allow use
of openat in hardened mkstemp
*/
#ifndef DISABLE_OPENAT
#define DISABLE_OPENAT 0 /* change to 1 if you don't have openat (old unix) */
#endif
#ifndef S_ISVTX
#define S_ISVTX 01000
#endif
@@ -482,17 +475,9 @@ const char *getnvmprogname(void);
char *new_tmpfile(int *fd, int local, const char *path);
char *new_tmplate(int *fd, int local, const char *path);
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0)) /* for openat dir replacement mitigation
in mkhtemp()
*/
int mkhtemp(int *fd, struct stat *st,
char *template, int dirfd, const char *fname,
struct stat *st_dir_initial);
#else
int mkhtemp(int *fd, struct stat *st,
char *template);
#endif
int world_writeable_and_sticky(const char *s,
int sticky_allowed, int always_sticky);
int same_dir(const char *a, const char *b);

View File

@@ -16,7 +16,6 @@
#include "../include/common.h"
/* check that a file changed
*/
@@ -261,10 +260,6 @@ new_tmpfile(int *fd, int local,
int saved_errno = errno;
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0)) /* for openat dir replacement mitigation
in mkhtemp()
*/
int dirfd = -1;
const char *fname = NULL;
@@ -274,7 +269,6 @@ new_tmpfile(int *fd, int local,
* attack mitigation
*/
struct stat st_dir_initial;
#endif
char *dir = NULL;
char *base = NULL;
@@ -415,12 +409,7 @@ new_tmpfile(int *fd, int local,
memcpy(dest + 1 + baselen,
suffix, sizeof(suffix) - 1);
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0)) /* for openat dir replacement mitigation
* in mkhtemp(
*/
fname = base;
#endif
} else {
@@ -431,10 +420,6 @@ new_tmpfile(int *fd, int local,
memcpy(dest + dirlen + 1, suffix,
sizeof(suffix) - 1);
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0)) /* for openat dir replacement mitigation
in mkhtemp()
*/
dirfd = fs_resolve(tmpdir,
O_RDONLY | O_DIRECTORY);
if (dirfd < 0)
@@ -447,32 +432,24 @@ new_tmpfile(int *fd, int local,
goto err_new_tmpfile;
fname = dest + dirlen + 1;
#endif
}
*(dest + destlen) = '\0';
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0)) /* for openat dir replacement mitigation
in mkhtemp()
*/
*fd = mkhtemp(fd, &st, dest, dirfd, fname, &st_dir_initial);
#else
*fd = mkhtemp(fd, &st, dest);
#endif
if (*fd < 0)
goto err_new_tmpfile;
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0)) /* for openat dir replacement mitigation
in mkhtemp()
*/
if (dirfd >= 0) {
(void) close_on_eintr(dirfd);
dirfd = -1;
}
#endif
if (dir != NULL) {
free(dir);
dir = NULL;
}
errno = saved_errno;
return dest;
@@ -489,16 +466,11 @@ err_new_tmpfile:
dest = NULL;
}
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0)) /* for openat dir replacement mitigation
in mkhtemp()
*/
if (dirfd >= 0) {
(void) close_on_eintr(dirfd);
dirfd = -1;
}
#endif
if (*fd >= 0) {
@@ -506,6 +478,11 @@ err_new_tmpfile:
*fd = -1;
}
if (dir != NULL) {
free(dir);
dir = NULL;
}
errno = saved_errno;
return NULL;
@@ -798,20 +775,12 @@ sticky_hell:
* generates files)
*/
#if defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0)
int
mkhtemp(int *fd,
struct stat *st,
char *template)
#else
int mkhtemp(int *fd,
struct stat *st,
char *template,
int dirfd,
const char *fname,
struct stat *st_dir_initial)
#endif
{
/* NOTE: this function currently
* only supports *files*.
@@ -857,8 +826,6 @@ int mkhtemp(int *fd,
int saved_rand_error = 0;
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0))
char *fname_copy = NULL;
size_t fname_len = 0;
@@ -894,7 +861,6 @@ int mkhtemp(int *fd,
errno = EBADF;
goto err_mkhtemp;
}
#endif
if (fd == NULL ||
template == NULL) {
@@ -918,9 +884,6 @@ int mkhtemp(int *fd,
goto err_mkhtemp;
}
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0))
if (strrchr(fname, '/') != NULL) {
/* otherwise, a mangled
@@ -956,8 +919,6 @@ int mkhtemp(int *fd,
}
}
#endif
p = template + len;
while (p > template &&
@@ -970,9 +931,6 @@ int mkhtemp(int *fd,
goto err_mkhtemp;
}
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0))
if (fname_len > len ||
fname_len > (len - xc)) {
@@ -990,8 +948,6 @@ int mkhtemp(int *fd,
goto err_mkhtemp;
}
#endif
template_copy = malloc(len + 1);
if (template_copy == NULL) {
@@ -1005,9 +961,6 @@ int mkhtemp(int *fd,
*/
memcpy(template_copy, template, len + 1);
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0))
/* redundant copy, reduce chance of
* mangling (regression mitigation)
*/
@@ -1025,9 +978,6 @@ int mkhtemp(int *fd,
fname_len + 1);
p = fname_copy + fname_len - xc;
#else
p = template_copy + len - xc;
#endif
for (retries = 0; retries < max_retries; retries++) {
@@ -1068,13 +1018,6 @@ retry_rand:
p[chx] = ch[r % (sizeof(ch) - 1)];
}
#if defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0) /* openat(2) added to linux in 2006, BSDs later
*/
*fd = open(template_copy,
O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC |
O_NOCTTY, 0600);
#else
/*
* use the file descriptor instead.
* (danach prüfen wir die Sicherheit des Verzeichnisses)
@@ -1093,18 +1036,13 @@ retry_rand:
*fd = openat(dirfd, fname_copy,
O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC |
O_NOCTTY, 0600);
#endif
if (*fd >= 0) {
file_created = 1;
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0))
memcpy(template_copy + len - fname_len,
fname_copy, fname_len);
#endif
if (secure_file(fd, st, O_APPEND, 1, 1, 0600) < 0)
goto err_mkhtemp;
@@ -1157,34 +1095,21 @@ err_mkhtemp:
/* we created it, so *we* nuke it
*/
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0))
if (file_created &&
fname_copy != NULL)
(void) unlinkat(dirfd, fname_copy, 0);
#else
if (file_created)
(void) unlink(template_copy);
#endif
free(template_copy);
template_copy = NULL;
}
#if !(defined(DISABLE_OPENAT) && \
((DISABLE_OPENAT) > 0))
if (fname_copy != NULL) {
free(fname_copy);
fname_copy = NULL;
}
#endif
errno = saved_errno;
/* returning EINTR/EAGAIN
@@ -1946,6 +1871,16 @@ fs_resolve(const char *path, int flags)
return -1;
}
/* block "/" if flags pertain to creation/write.
don't mess with the user's root!
*/
if (path[0] == '/' && path[1] == '\0') {
if (flags & (O_CREAT | O_TRUNC | O_RDWR | O_WRONLY)) {
errno = EISDIR;
return -1;
}
}
if (slen(path, maxlen, &len) < 0)
return -1;
@@ -2047,26 +1982,11 @@ fs_open_component(int dirfd, const char *name,
{
int fd;
/* TODO:
open() fallback if DISABLE_OPENAT > 0
change function signature
and ditto any callers using
the same ifdefs. this would
allow us to implement somewhat
openat-like functionality with
openat2-like features, even on
systems that lack openat(2),
let alone openat2
*/
fd = openat(dirfd, name,
(is_last ? flags : (O_RDONLY | O_DIRECTORY)) |
O_NOFOLLOW | O_CLOEXEC);
/* on some systems, O_DIRECTORY is
* ignored or unreliable. We must
* assume that your operating system
* is lying. the OS always lies.
/* the patient always lies
*/
if (!is_last) {
@@ -2091,9 +2011,6 @@ fs_dirname_basename(const char *path,
char **dir, char **base,
int allow_relative)
{
/* TODO: audit maxlen use vs PATH_LEN
-- should implement length checks
*/
char *buf;
char *slash;
size_t len;