Compare commits

...

8 Commits

Author SHA1 Message Date
Leah Rowe
7ad924a91f nvmutil: make tmpdir string much more random
more random characters

i added support for higher than the standard 6
characters so i can go nuts

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-19 08:50:09 +00:00
Leah Rowe
50300f846f util/nvmutil: hardened mkstemp
200 retries, not 100.

and open with O_NOFOLLOW and O_CLOEXEC

check X on mkstemp

support more than 6 X in mkstemp

make PATH_LEN 4096

1024 is a bit low

make default mkstemp length 4096

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-19 08:42:58 +00:00
Leah Rowe
4b35d9ac29 nvmutil: rename lseek_loop to lseek_on_eintr
that's what it does!

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-19 07:48:53 +00:00
Leah Rowe
1fbe972fa7 nvmutil: rename x_i_close to close_on_eintr
that's what it does. waits for eintr to stop firing

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-19 07:45:34 +00:00
Leah Rowe
dcf698b9a0 nvmutil: don't have finite eintr wait
this is technically incorrect. we don't control
faults in the hardware.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-19 07:43:43 +00:00
Leah Rowe
2eee2b5cac nvmutil: rename x_i_fsync to fsync_on_eintr
that's what it does. waits on eintr.

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-19 07:41:04 +00:00
Leah Rowe
6d0bb47b82 util/rename: rename x_i_fsync
rename to fsync_on_eintr, because that's what it does

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-19 07:38:54 +00:00
Leah Rowe
846cb23585 nvmutil: remove memcmp/memcpy/strrchr/rename
i had this idea in my head of later porting this
to k&r c for fun. but screw it.

compiling on everything since 1989 is enough

Signed-off-by: Leah Rowe <leah@libreboot.org>
2026-03-19 07:37:53 +00:00
7 changed files with 81 additions and 182 deletions

View File

@@ -11,14 +11,6 @@
#include <sys/stat.h>
#include <limits.h>
/* keep SYS_RENAME 1 to
* use libc rename()
* recommended
*/
#ifndef SYS_RENAME
#define SYS_RENAME 1
#endif
#define items(x) (sizeof((x)) / sizeof((x)[0]))
/* system prototypes
@@ -43,7 +35,7 @@ int fchmod(int fd, mode_t mode);
#define MAX_CMD_LEN 50
#ifndef PATH_LEN
#define PATH_LEN 1024
#define PATH_LEN 4096
#endif
#define OFF_ERR 0
@@ -67,10 +59,6 @@ int fchmod(int fd, mode_t mode);
#define HAVE_REAL_PREAD_PWRITE 0
#endif
#ifndef MAX_EAGAIN_RETRIES
#define MAX_EAGAIN_RETRIES 100000
#endif
#ifndef LOOP_EAGAIN
#define LOOP_EAGAIN 1
#endif
@@ -416,7 +404,7 @@ int check_file(int fd, struct stat *st);
long rw_over_nrw(long r, unsigned long nrw);
#if !defined(HAVE_REAL_PREAD_PWRITE) || \
HAVE_REAL_PREAD_PWRITE < 1
off_t lseek_loop(int fd, off_t off,
off_t lseek_on_eintr(int fd, off_t off,
int whence, int loop_eagain, int loop_eintr);
#endif
int try_err(int loop_err, int errval);
@@ -433,16 +421,10 @@ const char *getnvmprogname(void);
*/
char *new_tmpfile(int *fd, int local, const char *path);
int x_i_mkstemp(char *template);
char *x_c_strrchr(const char *s, int c);
int x_i_rename(const char *src, const char *dst);
int mkstemp_n(char *template);
char *x_c_tmpdir(void);
int x_i_close(int fd);
void *x_v_memcpy(void *dst,
const void *src, unsigned long n);
int x_i_memcmp(const void *a,
const void *b, unsigned long n);
int x_i_fsync(int fd);
int close_on_eintr(int fd);
int fsync_on_eintr(int fd);
/* asserts */

View File

@@ -415,17 +415,17 @@ cmd_helper_swap(void)
check_cmd(cmd_helper_swap, "swap");
x_v_memcpy(
memcpy(
f->buf + (unsigned long)GBE_WORK_SIZE,
f->buf,
GBE_PART_SIZE);
x_v_memcpy(
memcpy(
f->buf,
f->buf + (unsigned long)GBE_PART_SIZE,
GBE_PART_SIZE);
x_v_memcpy(
memcpy(
f->buf + (unsigned long)GBE_PART_SIZE,
f->buf + (unsigned long)GBE_WORK_SIZE,
GBE_PART_SIZE);
@@ -442,7 +442,7 @@ cmd_helper_copy(void)
check_cmd(cmd_helper_copy, "copy");
x_v_memcpy(
memcpy(
f->buf + (unsigned long)((f->part ^ 1) * GBE_PART_SIZE),
f->buf + (unsigned long)(f->part * GBE_PART_SIZE),
GBE_PART_SIZE);

View File

@@ -5,6 +5,7 @@
* Safe file handling.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
@@ -66,7 +67,7 @@ xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
err(errno, "%s: file not seekable", path);
}
/* Ensure x_i_rename() is durable by syncing the
/* Ensure rename() is durable by syncing the
* directory containing the target file.
*/
@@ -112,8 +113,8 @@ fsync_dir(const char *path)
if (dirbuf == NULL)
goto err_fsync_dir;
x_v_memcpy(dirbuf, path, pathlen + 1);
slash = x_c_strrchr(dirbuf, '/');
memcpy(dirbuf, path, pathlen + 1);
slash = strrchr(dirbuf, '/');
if (slash != NULL) {
*slash = '\0';
@@ -146,10 +147,10 @@ fsync_dir(const char *path)
}
/* sync file on disk */
if (x_i_fsync(dirfd) == -1)
if (fsync_on_eintr(dirfd) == -1)
goto err_fsync_dir;
if (x_i_close(dirfd) == -1)
if (close_on_eintr(dirfd) == -1)
goto err_fsync_dir;
if (dirbuf != NULL)
@@ -169,7 +170,7 @@ err_fsync_dir:
free(dirbuf);
if (dirfd > -1)
x_i_close(dirfd);
close_on_eintr(dirfd);
errno = saved_errno;
@@ -211,7 +212,7 @@ new_tmpfile(int *fd, int local, const char *path)
*/
char tmp_none[] = "";
char tmp_default[] = "/tmp";
char default_tmpname[] = "tmpXXXXXX";
char default_tmpname[] = "tmpXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
char *tmpname;
char *base = NULL;
@@ -294,22 +295,22 @@ new_tmpfile(int *fd, int local, const char *path)
*dest = '.'; /* hidden file */
x_v_memcpy(dest + (unsigned long)1, tmpname, tmpname_len);
memcpy(dest + (unsigned long)1, tmpname, tmpname_len);
x_v_memcpy(dest + (unsigned long)1 + tmpname_len,
memcpy(dest + (unsigned long)1 + tmpname_len,
default_tmpname, tmpdir_len);
} else {
x_v_memcpy(dest, base, tmpdir_len);
memcpy(dest, base, tmpdir_len);
dest[tmpdir_len] = '/';
x_v_memcpy(dest + tmpdir_len + 1, tmpname, tmpname_len);
memcpy(dest + tmpdir_len + 1, tmpname, tmpname_len);
}
dest[tmppath_len] = '\0';
fd_tmp = x_i_mkstemp(dest);
fd_tmp = mkstemp_n(dest);
if (fd_tmp == -1)
goto err_new_tmpfile;
@@ -366,7 +367,7 @@ err_new_tmpfile:
free(dest);
if (fd_tmp > -1)
x_i_close(fd_tmp);
close_on_eintr(fd_tmp);
return NULL;
}
@@ -420,36 +421,56 @@ x_c_tmpdir(void)
*/
int
x_i_mkstemp(char *template)
mkstemp_n(char *template)
{
int fd;
int i, j;
unsigned long i, j;
unsigned long len;
char *p;
char ch[] =
unsigned long xc = 0;
static char ch[] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
unsigned long r;
unsigned long max_len =
#ifndef PATH_LEN
4096;
#else
(PATH_LEN);
#endif
len = xstrxlen(template, PATH_LEN);
len = xstrxlen(template, max_len);
/* find trailing XXXXXX */
if (len < 6)
if (len < 6) {
errno = EINVAL;
return -1;
}
p = template + len - 6;
p = template + len;
for (i = 0; i < 100; i++) {
while (p > template && p[-1] == 'X') {
--p;
++xc;
}
for (j = 0; j < 6; j++) {
if (xc < 6) {
errno = EINVAL;
return -1;
}
for (i = 0; i < 200; i++) {
for (j = 0; j < xc; j++) {
r = rlong();
p[j] = ch[(unsigned long)(r >> 1) % (sizeof(ch) - 1)];
}
fd = open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
fd = open(template,
O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW | O_CLOEXEC, 0600);
if (fd >= 0)
return fd;
@@ -605,12 +626,6 @@ prw(int fd, void *mem, unsigned long nrw,
int loop_eagain, int loop_eintr,
int off_reset)
{
#ifndef MAX_EAGAIN_RETRIES
unsigned long retries = 100000;
#else
unsigned long retries = MAX_EAGAIN_RETRIES;
#endif
long r;
int positional_rw;
struct stat st;
@@ -678,14 +693,14 @@ real_pread_pwrite:
HAVE_REAL_PREAD_PWRITE > 0
goto real_pread_pwrite;
#else
if ((off_orig = lseek_loop(fd, (off_t)0, SEEK_CUR,
if ((off_orig = lseek_on_eintr(fd, (off_t)0, SEEK_CUR,
loop_eagain, loop_eintr)) == (off_t)-1) {
r = -1;
} else if (lseek_loop(fd, off, SEEK_SET,
} else if (lseek_on_eintr(fd, off, SEEK_SET,
loop_eagain, loop_eintr) == (off_t)-1) {
r = -1;
} else {
verified = lseek_loop(fd, (off_t)0, SEEK_CUR,
verified = lseek_on_eintr(fd, (off_t)0, SEEK_CUR,
loop_eagain, loop_eintr);
/*
@@ -700,7 +715,7 @@ real_pread_pwrite:
* that nothing is touching it now.
*/
if (off_reset && off != verified)
lseek_loop(fd, off, SEEK_SET,
lseek_on_eintr(fd, off, SEEK_SET,
loop_eagain, loop_eintr);
do {
@@ -721,7 +736,7 @@ real_pread_pwrite:
* will cause an exit, including
* per EINTR/EAGAIN re-spin.
*/
verified = lseek_loop(fd, (off_t)0, SEEK_CUR,
verified = lseek_on_eintr(fd, (off_t)0, SEEK_CUR,
loop_eagain, loop_eintr);
if (off != verified)
@@ -739,13 +754,12 @@ real_pread_pwrite:
} while (r == -1 &&
(errno == try_err(loop_eintr, EINTR) ||
errno == try_err(loop_eagain, EAGAIN)) &&
retries++ < MAX_EAGAIN_RETRIES);
errno == try_err(loop_eagain, EAGAIN)));
}
saved_errno = errno;
off_last = lseek_loop(fd, off_orig, SEEK_SET,
off_last = lseek_on_eintr(fd, off_orig, SEEK_SET,
loop_eagain, loop_eintr);
if (off_last != off_orig) {
@@ -875,12 +889,12 @@ err_rw_over_nrw:
#if !defined(HAVE_REAL_PREAD_PWRITE) || \
HAVE_REAL_PREAD_PWRITE < 1
/*
* lseek_loop() does lseek() but optionally
* lseek_on_eintr() does lseek() but optionally
* on an EINTR/EAGAIN wait loop. Used by prw()
* for setting offsets for positional I/O.
*/
off_t
lseek_loop(int fd, off_t off, int whence,
lseek_on_eintr(int fd, off_t off, int whence,
int loop_eagain, int loop_eintr)
{
off_t old;
@@ -906,65 +920,8 @@ try_err(int loop_err, int errval)
return -1;
}
/* portable rename(). WARNING:
* not powercut-safe. do this to
* use system rename:
* #define SYS_RENAME 1
*
* written academically, but in reality,
* nearly all unix systems have rename()
*/
int
x_i_rename(const char *src, const char *dst)
{
#if defined(SYS_RENAME) &&\
SYS_RENAME > 0
return rename(src, dst);
#else
int sfd, dirfd;
ssize_t r;
char buf[8192];
sfd = open(src, O_RDONLY);
if (sfd < 0)
return -1;
dirfd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0600);
if (dirfd < 0) {
x_i_close(sfd);
return -1;
}
while ((r = read(sfd, buf, sizeof(buf))) > 0) {
ssize_t w = write(dirfd, buf, r);
if (w != r) {
x_i_close(sfd);
x_i_close(dirfd);
return -1;
}
}
if (r < 0) {
x_i_close(sfd);
x_i_close(dirfd);
return -1;
}
x_i_fsync(dirfd);
x_i_close(sfd);
x_i_close(dirfd);
if (unlink(src) < 0)
return -1;
return 0;
#endif
}
int
x_i_close(int fd)
close_on_eintr(int fd)
{
int r;
int saved_errno = errno;
@@ -980,7 +937,7 @@ x_i_close(int fd)
}
int
x_i_fsync(int fd)
fsync_on_eintr(int fd)
{
int r;

View File

@@ -79,7 +79,7 @@ copy_gbe(void)
if (f->gbe_file_size == SIZE_8KB)
return;
x_v_memcpy(f->buf + (unsigned long)GBE_PART_SIZE,
memcpy(f->buf + (unsigned long)GBE_PART_SIZE,
f->buf + (unsigned long)(f->gbe_file_size >> 1),
(unsigned long)GBE_PART_SIZE);
}
@@ -125,7 +125,7 @@ read_file(void)
/* needs sync, for verification
*/
if (x_i_fsync(f->tmp_fd) == -1)
if (fsync_on_eintr(f->tmp_fd) == -1)
err(errno, "%s: fsync (tmpfile copy)", f->tname);
_r = rw_file_exact(f->tmp_fd, f->bufcmp, f->gbe_file_size,
@@ -135,7 +135,7 @@ read_file(void)
if (_r < 0)
err(errno, "%s: read failed (cmp)", f->tname);
if (x_i_memcmp(f->buf, f->bufcmp, f->gbe_file_size) != 0)
if (memcmp(f->buf, f->bufcmp, f->gbe_file_size) != 0)
err(errno, "%s: %s: read contents differ (pre-test)",
f->fname, f->tname);
}
@@ -227,7 +227,7 @@ write_to_gbe_bin(void)
* We may otherwise read from
* cache, so we must sync.
*/
if (x_i_fsync(f->tmp_fd) == -1)
if (fsync_on_eintr(f->tmp_fd) == -1)
err(errno, "%s: fsync (pre-verification)",
f->tname);
@@ -246,12 +246,12 @@ write_to_gbe_bin(void)
saved_errno = errno;
if (x_i_close(f->tmp_fd) == -1) {
if (close_on_eintr(f->tmp_fd) == -1) {
fprintf(stderr, "FAIL: %s: close\n", f->tname);
f->io_err_gbe_bin = 1;
}
if (x_i_close(f->gbe_fd) == -1) {
if (close_on_eintr(f->gbe_fd) == -1) {
fprintf(stderr, "FAIL: %s: close\n", f->fname);
f->io_err_gbe_bin = 1;
}
@@ -331,7 +331,7 @@ check_written_part(unsigned long p)
f->rw_check_err_read[p] = f->io_err_gbe = 1;
else if ((unsigned long)rval != gbe_rw_size)
f->rw_check_partial_read[p] = f->io_err_gbe = 1;
else if (x_i_memcmp(mem_offset, f->pad, gbe_rw_size) != 0)
else if (memcmp(mem_offset, f->pad, gbe_rw_size) != 0)
f->rw_check_bad_part[p] = f->io_err_gbe = 1;
if (f->rw_check_err_read[p] ||
@@ -435,7 +435,7 @@ gbe_mv(void)
saved_errno = errno;
rval = x_i_rename(f->tname, f->fname);
rval = rename(f->tname, f->fname);
if (rval > -1) {
/*
@@ -484,13 +484,13 @@ gbe_mv(void)
if (rval < 0)
goto ret_gbe_mv;
if (x_i_fsync(dest_fd) == -1)
if (fsync_on_eintr(dest_fd) == -1)
goto ret_gbe_mv;
if (x_i_close(dest_fd) == -1)
if (close_on_eintr(dest_fd) == -1)
goto ret_gbe_mv;
if (x_i_rename(dest_tmp, f->fname) == -1)
if (rename(dest_tmp, f->fname) == -1)
goto ret_gbe_mv;
if (fsync_dir(f->fname) < 0) {
@@ -504,7 +504,7 @@ gbe_mv(void)
ret_gbe_mv:
if (f->gbe_fd > -1) {
if (x_i_close(f->gbe_fd) < 0)
if (close_on_eintr(f->gbe_fd) < 0)
rval = -1;
if (fsync_dir(f->fname) < 0) {
f->io_err_gbe_bin = 1;
@@ -514,7 +514,7 @@ ret_gbe_mv:
}
if (f->tmp_fd > -1) {
if (x_i_close(f->tmp_fd) < 0)
if (close_on_eintr(f->tmp_fd) < 0)
rval = -1;
f->tmp_fd = -1;

View File

@@ -80,7 +80,7 @@ rlong(void)
sizeof(unsigned long), 0, IO_READ, LOOP_EAGAIN,
LOOP_EINTR, MAX_ZERO_RW_RETRY, OFF_ERR);
if (x_i_close(fd) < 0)
if (close_on_eintr(fd) < 0)
err(errno, "Can't close randomness fd");
if (nr != sizeof(unsigned long))

View File

@@ -236,7 +236,7 @@ getnvmprogname(void)
rval = x->argv0;
}
p = x_c_strrchr(rval, '/');
p = strrchr(rval, '/');
if (p)
return p + 1;
@@ -260,13 +260,13 @@ exit_cleanup(void)
f = &x->f;
if (f->gbe_fd > -1) {
if (x_i_close(f->gbe_fd) == -1)
if (close_on_eintr(f->gbe_fd) == -1)
close_err = 1;
f->gbe_fd = -1;
}
if (f->tmp_fd > -1) {
if (x_i_close(f->tmp_fd) == -1)
if (close_on_eintr(f->tmp_fd) == -1)
close_err = 1;
}

View File

@@ -81,43 +81,3 @@ xstrxlen(const char *scmp, unsigned long maxlen)
return xstr_index;
}
char *
x_c_strrchr(const char *s, int c)
{
const char *p = NULL;
for ( ; *s; s++)
if (*s == (char)c)
p = s;
if (c == '\0')
return (char *)s;
return (char *)p;
}
void *
x_v_memcpy(void *dst, const void *src, unsigned long n)
{
unsigned char *d = (unsigned char *)dst;
const unsigned char *s = (const unsigned char *)src;
while (n--)
*d++ = *s++;
return dst;
}
int
x_i_memcmp(const void *a, const void *b, unsigned long n)
{
const unsigned char *pa = (const unsigned char *)a;
const unsigned char *pb = (const unsigned char *)b;
for ( ; n--; ++pa, ++pb)
if (*pa != *pb)
return *pa - *pb;
return 0;
}