From f01657c826835afafe38ba5305e46c75b89574f7 Mon Sep 17 00:00:00 2001 From: Leah Rowe Date: Sat, 14 Mar 2026 00:55:50 +0000 Subject: util/nvmutil: make EINTR configurable in prw() Signed-off-by: Leah Rowe --- util/nvmutil/nvmutil.c | 69 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 44 insertions(+), 25 deletions(-) diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c index 85b6d4ed..34db6b92 100644 --- a/util/nvmutil/nvmutil.c +++ b/util/nvmutil/nvmutil.c @@ -330,15 +330,16 @@ static off_t gbe_x_offset(size_t part, const char *f_op, static ssize_t rw_gbe_file_exact(int fd, u8 *mem, size_t nrw, off_t off, int rw_type); static ssize_t rw_file_exact(int fd, u8 *mem, size_t len, - off_t off, int rw_type, int loop_eagain); + off_t off, int rw_type, int loop_eagain, int loop_eintr); static ssize_t rw_file_once(int fd, u8 *mem, size_t len, - off_t off, int rw_type, size_t rc, int loop_eagain); + off_t off, int rw_type, size_t rc, int loop_eagain, + int loop_eintr); static ssize_t prw(int fd, void *mem, size_t nrw, - off_t off, int rw_type, int loop_eagain); + off_t off, int rw_type, int loop_eagain, int loop_eintr); static int rw_over_nrw(ssize_t r, size_t nrw); static off_t lseek_eintr(int fd, off_t off, - int whence, int loop_eagain); -static int err_eagain(int loop_eagain); + int whence, int loop_eagain, int loop_eintr); +static int err_eagain(int loop_err, int errval); /* * Error handling and cleanup @@ -1153,7 +1154,7 @@ rhex(void) if (!n) { n = sizeof(rnum); - if (rw_file_exact(urandom_fd, rnum, n, 0, IO_READ, 0) == -1) + if (rw_file_exact(urandom_fd, rnum, n, 0, IO_READ, 0, 1) == -1) err(errno, "Randomisation failed"); } @@ -1322,7 +1323,7 @@ static void gbe_cat_buf(u8 *b) { if (rw_file_exact(STDOUT_FILENO, b, - GBE_PART_SIZE, 0, IO_WRITE, 1) < 0) + GBE_PART_SIZE, 0, IO_WRITE, 1, 1) < 0) err(errno, "stdout: cat"); } @@ -1576,7 +1577,7 @@ rw_gbe_file_exact(int fd, u8 *mem, size_t nrw, if (nrw > GBE_PART_SIZE) goto err_rw_gbe_file_exact; - return rw_file_exact(fd, mem, nrw, off, rw_type, 0); + return rw_file_exact(fd, mem, nrw, off, rw_type, 0, 1); err_rw_gbe_file_exact: errno = EIO; @@ -1602,14 +1603,15 @@ err_rw_gbe_file_exact: */ static ssize_t rw_file_exact(int fd, u8 *mem, size_t nrw, - off_t off, int rw_type, int loop_eagain) + off_t off, int rw_type, int loop_eagain, + int loop_eintr) { ssize_t rv; size_t rc; for (rc = 0, rv = 0; rc < nrw; ) { if ((rv = rw_file_once(fd, mem, nrw, off, rw_type, rc, - loop_eagain)) <= 0) + loop_eagain, loop_eintr)) <= 0) return -1; rc += (size_t)rv; @@ -1629,7 +1631,7 @@ rw_file_exact(int fd, u8 *mem, size_t nrw, static ssize_t rw_file_once(int fd, u8 *mem, size_t nrw, off_t off, int rw_type, size_t rc, - int loop_eagain) + int loop_eagain, int loop_eintr) { ssize_t rv; size_t retries_on_zero = 0; @@ -1639,7 +1641,8 @@ rw_file_once(int fd, u8 *mem, size_t nrw, goto err_rw_file_once; read_again: - rv = prw(fd, mem + rc, nrw - rc, off + rc, rw_type, loop_eagain); + rv = prw(fd, mem + rc, nrw - rc, off + rc, rw_type, + loop_eagain, loop_eintr); if (rv < 0) return -1; @@ -1672,10 +1675,21 @@ err_rw_file_once: * A fallback is provided for regular read/write. * rw_type can be IO_READ, IO_WRITE, IO_PREAD * or IO_PWRITE + * + * loop_eagain does a retry loop on EAGAIN if set + * loop_eintr does a retry loop on EINTR if set + * + * Unlike the bare syscalls, prw() does security + * checks e.g. checks NULL strings, checks bounds, + * also mitigates a few theoretical libc bugs. + * It is designed for extremely safe single-threaded + * I/O on applications that need it. */ + static ssize_t prw(int fd, void *mem, size_t nrw, - off_t off, int rw_type, int loop_eagain) + off_t off, int rw_type, + int loop_eagain, int loop_eintr) { off_t off_orig; ssize_t r; @@ -1708,8 +1722,8 @@ try_rw_again: else if (rw_type == IO_READ) r = read(fd, mem, nrw); - if (r == -1 && (errno == EINTR - || errno == err_eagain(loop_eagain))) + if (r == -1 && (errno == err_eagain(loop_eintr, EINTR) + || errno == err_eagain(loop_eagain, EAGAIN))) goto try_rw_again; return rw_over_nrw(r, nrw); @@ -1729,9 +1743,10 @@ try_rw_again: goto err_prw; if ((off_orig = lseek_eintr(fd, (off_t)0, SEEK_CUR, - loop_eagain)) == (off_t)-1) + loop_eagain, loop_eintr)) == (off_t)-1) r = -1; - else if (lseek_eintr(fd, off, SEEK_SET, loop_eagain) == (off_t)-1) + else if (lseek_eintr(fd, off, SEEK_SET, + loop_eagain, loop_eintr) == (off_t)-1) r = -1; do { @@ -1741,12 +1756,13 @@ try_rw_again: r = write(fd, mem, nrw); r = rw_over_nrw(r, nrw); - } while (r == -1 && (errno == EINTR - || errno == err_eagain(loop_eagain))); + } while (r == -1 && + (errno == err_eagain(loop_eintr, EINTR) + || errno == err_eagain(loop_eagain, EAGAIN))); saved_errno = errno; if (lseek_eintr(fd, off_orig, SEEK_SET, - loop_eagain) == (off_t)-1) { + loop_eagain, loop_eintr) == (off_t)-1) { if (r < 0) errno = saved_errno; return -1; @@ -1803,23 +1819,26 @@ err_rw_over_nrw: } static off_t -lseek_eintr(int fd, off_t off, int whence, int loop_eagain) +lseek_eintr(int fd, off_t off, int whence, + int loop_eagain, int loop_eintr) { off_t old; do { old = lseek(fd, off, whence); } while (old == (off_t)-1 - && (!(errno == EINTR || errno == err_eagain(loop_eagain)))); + && (!( + errno == err_eagain(loop_eintr, EINTR) || + errno == err_eagain(loop_eagain, EAGAIN)))); return old; } static int -err_eagain(int loop_eagain) +err_eagain(int loop_err, int errval) { - if (loop_eagain) - return EAGAIN; + if (loop_err) + return errval; /* errno is never negative, so functions checking it -- cgit v1.2.1