summaryrefslogtreecommitdiff
path: root/util
diff options
context:
space:
mode:
authorLeah Rowe <leah@libreboot.org>2026-03-14 22:38:56 +0000
committerLeah Rowe <leah@libreboot.org>2026-03-14 22:40:10 +0000
commit93603e1572ead36b16f9a421444df061ebf83b90 (patch)
tree2422bc0d99681091516338c4587c388c328f3a70 /util
parent0a4257f4edba883877362bd6f2d7d0265879d1d3 (diff)
nvmutil: toggle for fd thread-safety err state
Signed-off-by: Leah Rowe <leah@libreboot.org>
Diffstat (limited to 'util')
-rw-r--r--util/nvmutil/nvmutil.c40
1 files changed, 35 insertions, 5 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c
index 4a550e71..b3cea8da 100644
--- a/util/nvmutil/nvmutil.c
+++ b/util/nvmutil/nvmutil.c
@@ -15,6 +15,11 @@
* -Os -Wall -Wextra -Werror -pedantic -std=c90
*/
+#define OFF_ERR 0
+#ifndef OFF_RESET
+#define OFF_RESET 1
+#endif
+
/*
* NOTE: older Linux lacked arc4random.
* added in glibc 2.36. Just pass HAVE_ARC4RANDOM_BUF=0
@@ -409,7 +414,8 @@ static ssize_t rw_file_exact(int fd, u8 *mem, size_t len,
off_t off, int rw_type, int loop_eagain, int loop_eintr,
size_t max_retries);
static ssize_t prw(int fd, void *mem, size_t nrw,
- off_t off, int rw_type, int loop_eagain, int loop_eintr);
+ off_t off, int rw_type, int loop_eagain, int loop_eintr,
+ int off_reset);
static int check_file(int fd, struct stat *st);
static ssize_t rw_over_nrw(ssize_t r, size_t nrw);
#if !defined(HAVE_REAL_PREAD_PWRITE) || \
@@ -668,6 +674,8 @@ typedef char bool_loop_eintr[(LOOP_EINTR==1||LOOP_EINTR==0)?1:-1];
typedef char bool_loop_eagain[(LOOP_EAGAIN==1||LOOP_EAGAIN==0)?1:-1];
typedef char bool_no_loop_eintr[(NO_LOOP_EINTR==0)?1:-1];
typedef char bool_no_loop_eagain[(NO_LOOP_EAGAIN==0)?1:-1];
+typedef char bool_off_err[(OFF_ERR==0)?1:-1];
+typedef char bool_off_reset[(OFF_RESET==0||OFF_RESET==1)?1:-1];
static int io_err_gbe = 0;
static int rw_check_err_read[] = {0, 0};
@@ -1883,7 +1891,8 @@ rw_file_exact(int fd, u8 *mem, size_t nrw,
mem + (size_t)rc,
nrw - (size_t)rc,
off + (off_t)rc,
- rw_type, loop_eagain, loop_eintr);
+ rw_type, loop_eagain, loop_eintr,
+ OFF_ERR);
if (rv < 0)
return -1;
@@ -1941,12 +1950,23 @@ err_rw_file_exact:
* NOTE: If you use loop_eagain (1), you enable wait
* loop on EAGAIN. Beware if using this on a non-blocking
* pipe (it could spin indefinitely).
+ *
+ * off_reset: if zero, and using fallback pwrite/pread
+ * analogs, we check if a file offset changed,
+ * which would indicate another thread changed
+ * it, and return error, without resetting the
+ * file - this would allow that thread to keep
+ * running, but we could then cause a whole
+ * program exit if we wanted to.
+ * if not zero:
+ * we reset and continue, and pray for the worst.
*/
static ssize_t
prw(int fd, void *mem, size_t nrw,
off_t off, int rw_type,
- int loop_eagain, int loop_eintr)
+ int loop_eagain, int loop_eintr,
+ int off_reset)
{
ssize_t r;
int positional_rw;
@@ -2050,9 +2070,19 @@ real_pread_pwrite:
* Failure is the better option
* here, since recovery would
* mask hidden bugs in code.
+ * We cannot guarantee thread
+ * safety, except in the event
+ * that violations cause exit;
+ * you would then debug it.
*/
- if (off != verified)
- goto err_prw;
+ if (off != verified) {
+ if (!off_reset)
+ goto err_prw;
+
+ if (lseek_loop(fd, off, SEEK_SET,
+ loop_eagain, loop_eintr) == (off_t)-1)
+ return -1;
+ }
do {
if (rw_type == IO_PREAD)