From 79376a900a72f47e5f18523d8d2d16c1bbd87438 Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Sun, 22 Mar 2026 21:59:22 +0000 Subject: WIP cleanup Signed-off-by: Leah Rowe --- util/nvmutil/include/common.h | 6 ++ util/nvmutil/lib/file.c | 182 +++++++++++++++++++++++++++--------------- 2 files changed, 125 insertions(+), 63 deletions(-) (limited to 'util/nvmutil') diff --git a/util/nvmutil/include/common.h b/util/nvmutil/include/common.h index e856664f..6ae7af04 100644 --- a/util/nvmutil/include/common.h +++ b/util/nvmutil/include/common.h @@ -324,6 +324,12 @@ size_t conv_argv_part_num(const char *part_str); */ void open_gbe_file(void); +int fd_verify_regular(int fd, + const struct stat *expected, + struct stat *out); +int fd_verify_identity(int fd, + const struct stat *expected, + struct stat *out); int is_owner(struct stat *st); int lock_file(int fd, int flags); int same_file(int fd, struct stat *st_old, int check_size); diff --git a/util/nvmutil/lib/file.c b/util/nvmutil/lib/file.c index 50b48065..f3ef15cb 100644 --- a/util/nvmutil/lib/file.c +++ b/util/nvmutil/lib/file.c @@ -56,13 +56,8 @@ same_file(int fd, struct stat *st_old, if (fstat(fd, &st) == -1) goto err_same_file; - if (st.st_dev != st_old->st_dev || - st.st_ino != st_old->st_ino || - !S_ISREG(st.st_mode)) { - - errno = ESTALE; + if (fd_verify_regular(fd, st_old, &st) < 0) goto err_same_file; - } if (check_size && st.st_size != st_old->st_size) @@ -90,6 +85,17 @@ err_same_file: make it return, and handle the return value/errno (this could return e.g. EINTR) + + TODO: this function is not used by mkhtemp, nor will + it probably be, it's currently used by nvmutil, + for opening intel gbe nvm config files. i can + probably remove it though and unify witth some + of the verification code now used for mkhtemp + +TODO: and don't abort. return -1. and handle in the caller. + +minor obstacle: the mkhtemp code always requires absolute +paths, whereas the gbe editor takes relative paths. */ void xopen(int *fd_ptr, const char *path, int flags, struct stat *st) @@ -259,15 +265,12 @@ new_tmpfile(int *fd, char **path) size_t dirlen; size_t destlen; - size_t baselen; char *dest = NULL; /* final path */ int saved_errno = errno; int dirfd = -1; const char *fname = NULL; struct stat st_dir_initial; - char *dir = NULL; - char *base = NULL; if (path == NULL || fd == NULL) { errno = EFAULT; @@ -294,6 +297,10 @@ new_tmpfile(int *fd, char **path) if (slen(tmpdir, maxlen, &dirlen) < 0) goto err_new_tmpfile; + if (*tmpdir == '\0') + goto err_new_tmpfile; + if (*tmpdir != '/') + goto err_new_tmpfile; /* using sizeof (not slen) adds an extra byte, * useful because we either want '.' or '/' @@ -336,10 +343,6 @@ new_tmpfile(int *fd, char **path) (void) close_on_eintr(dirfd); dirfd = -1; } - if (dir != NULL) { - free(dir); - dir = NULL; - } errno = saved_errno; @@ -371,11 +374,6 @@ err_new_tmpfile: *fd = -1; } - if (dir != NULL) { - free(dir); - dir = NULL; - } - errno = saved_errno; return -1; @@ -694,6 +692,7 @@ mkhtemp(int *fd, size_t max_len = 4096; #endif int r; + char *end; if (fd == NULL || template == NULL || @@ -736,14 +735,11 @@ mkhtemp(int *fd, } /* count trailing X */ - { - char *end = template + len; - - while (end > template && *--end == 'X') - xc++; - } + end = template + len; + while (end > template && *--end == 'X') + xc++; - if (xc < 6 || xc > len) { + if (xc < 12 || xc > len) { errno = EINVAL; return -1; } @@ -784,9 +780,11 @@ mkhtemp(int *fd, fd, st); - /* DoS mitigation; add jitter delay (0–1023 µs) */ - if (r != 1 && retries >= MKHTEMP_SPIN_THRESHOLD) - usleep((useconds_t)rlong() & 0x3FF); + if (r != 1) { + if (retries >= MKHTEMP_SPIN_THRESHOLD) + usleep((useconds_t)rlong() & 0x3FF); + continue; + } /* success: copy final name back */ memcpy(template + len - fname_len, @@ -825,17 +823,18 @@ mkhtemp_try_create(int dirfd, struct stat st_open; int saved_errno = errno; int close_errno; + int rval = -1; if (mkhtemp_fill_random(p, xc) < 0) - return -1; + goto err; if (fstat(dirfd, &st_dir_now) < 0) - return -1; + goto err; if (st_dir_now.st_dev != st_dir_initial->st_dev || st_dir_now.st_ino != st_dir_initial->st_ino) { errno = ESTALE; - return -1; + goto err; } *fd = openat2p(dirfd, fname_copy, @@ -843,40 +842,53 @@ mkhtemp_try_create(int dirfd, O_NOFOLLOW | O_CLOEXEC | O_NOCTTY, 0600); - if (*fd >= 0) { + if (*fd < 0) { + if (errno == EEXIST || + errno == EINTR || + errno == EAGAIN || + errno == EWOULDBLOCK || + errno == ETXTBSY) { + + rval = 0; + goto out; + } + goto err; + } - if (fstat(*fd, &st_open) < 0) - return -1; + /* fd is now live */ - if (fstat(dirfd, &st_dir_now) < 0) - return -1; + if (fstat(*fd, &st_open) < 0) + goto err; - if (st_dir_now.st_dev != st_dir_initial->st_dev || - st_dir_now.st_ino != st_dir_initial->st_ino) { + if (fstat(dirfd, &st_dir_now) < 0) + goto err; - close_errno = errno; - (void) close_on_eintr(*fd); - errno = close_errno; + if (st_dir_now.st_dev != st_dir_initial->st_dev || + st_dir_now.st_ino != st_dir_initial->st_ino) { + errno = ESTALE; + goto err; + } - errno = ESTALE; - return -1; - } + if (secure_file(fd, st, &st_open, + O_APPEND, 1, 1, 0600) < 0) + goto err; - if (secure_file(fd, st, &st_open, O_APPEND, 1, 1, 0600) < 0) - return -1; + errno = saved_errno; + rval = 1; + goto out; - errno = saved_errno; - return 1; /* success */ - } +err: + close_errno = errno; - if (errno == EEXIST || - errno == EINTR || - errno == EAGAIN || - errno == EWOULDBLOCK || - errno == ETXTBSY) - return 0; /* retry */ + if (fd != NULL && *fd >= 0) { + (void) close_on_eintr(*fd); + *fd = -1; + } - return -1; /* fatal */ + errno = close_errno; + rval = -1; +out: + return rval; } int @@ -985,21 +997,17 @@ int secure_file(int *fd, } } - if (fstat(*fd, st) == -1) + if (fstat(*fd, &st_now) == -1) goto err_secure_file; - /* verify inode/device stability */ if (expected != NULL) { - if (st_now.st_dev != expected->st_dev || - st_now.st_ino != expected->st_ino) { - + st_now.st_ino != expected->st_ino) { errno = ESTALE; goto err_secure_file; } } - /* now copy to caller */ *st = st_now; if (!S_ISREG(st->st_mode)) { @@ -1007,6 +1015,9 @@ int secure_file(int *fd, goto err_secure_file; } + if (fd_verify_regular(*fd, expected, st) < 0) + goto err_secure_file; + if (check_seek) { /* check if it's seekable */ @@ -1057,6 +1068,51 @@ err_secure_file: return -1; } +int +fd_verify_regular(int fd, + const struct stat *expected, + struct stat *out) +{ + if (fd_verify_identity(fd, expected, out) < 0) + return -1; + + if (!S_ISREG(out->st_mode)) { + errno = EBADF; + return -1; + } + + return 0; /* regular file */ +} + +int +fd_verify_identity(int fd, + const struct stat *expected, + struct stat *out) +{ + struct stat st_now; + int saved_errno = errno; + + if (fd < 0 || expected == NULL) { + errno = EFAULT; + return -1; + } + + if (fstat(fd, &st_now) < 0) + return -1; + + if (st_now.st_dev != expected->st_dev || + st_now.st_ino != expected->st_ino) { + errno = ESTALE; + return -1; + } + + if (out != NULL) + *out = st_now; + + errno = saved_errno; + return 0; +} + int is_owner(struct stat *st) { @@ -1812,7 +1868,7 @@ fs_open(const char *path, int flags) } fs = rootfs(); - if (!fs) + if (fs == NULL) return -1; rel = path + 1; -- cgit v1.2.1