diff options
Diffstat (limited to 'util')
| -rw-r--r-- | util/nvmutil/nvmutil.c | 222 |
1 files changed, 134 insertions, 88 deletions
diff --git a/util/nvmutil/nvmutil.c b/util/nvmutil/nvmutil.c index 98f5bdcd..fe8364f7 100644 --- a/util/nvmutil/nvmutil.c +++ b/util/nvmutil/nvmutil.c @@ -416,6 +416,8 @@ static ssize_t rw_file_exact(int fd, u8 *mem, size_t len, static ssize_t prw(int fd, void *mem, size_t nrw, off_t off, int rw_type, int loop_eagain, int loop_eintr, int off_reset); +static int io_args(int fd, void *mem, size_t nrw, + off_t off, int rw_type); 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) || \ @@ -428,8 +430,8 @@ static int try_err(int loop_err, int errval); /* * Error handling and cleanup */ -static int close_files(void); static void err(int nvm_errval, const char *msg, ...); +static int close_files(void); static const char *getnvmprogname(void); static void usage(int usage_exit); @@ -703,12 +705,12 @@ main(int argc, char *argv[]) #ifdef NVMUTIL_PLEDGE #ifdef NVMUTIL_UNVEIL - if (pledge("stdio rpath wpath unveil", NULL) == -1) + if (pledge("stdio flock rpath wpath unveil", NULL) == -1) err(errno, "pledge"); if (unveil("/dev/null", "r") == -1) err(errno, "unveil /dev/null"); #else - if (pledge("stdio rpath wpath", NULL) == -1) + if (pledge("stdio flock rpath wpath", NULL) == -1) err(errno, "pledge"); #endif #endif @@ -725,25 +727,28 @@ main(int argc, char *argv[]) err(errno, "%s: unveil ro", fname); if (unveil(NULL, NULL) == -1) err(errno, "unveil block (ro)"); - if (pledge("stdio rpath", NULL) == -1) + if (pledge("stdio flock rpath", NULL) == -1) err(errno, "pledge ro (kill unveil)"); } else { if (unveil(fname, "rw") == -1) err(errno, "%s: unveil rw", fname); if (unveil(NULL, NULL) == -1) err(errno, "unveil block (rw)"); - if (pledge("stdio rpath wpath", NULL) == -1) + if (pledge("stdio flock rpath wpath", NULL) == -1) err(errno, "pledge rw (kill unveil)"); } #else if (command[cmd_index].flags == O_RDONLY) { - if (pledge("stdio rpath", NULL) == -1) + if (pledge("stdio flock rpath", NULL) == -1) err(errno, "pledge ro"); } #endif #endif +#if !defined(HAVE_ARC4RANDOM_BUF) || \ + (HAVE_ARC4RANDOM_BUF) < 1 srand((uint)(time(NULL) ^ getpid())); +#endif open_gbe_file(); lock_gbe_file(); @@ -942,11 +947,17 @@ xstrxcmp(const char *a, const char *b, size_t maxlen) err(EINVAL, "Empty string in xstrxcmp"); for (i = 0; i < maxlen; i++) { - if (a[i] != b[i]) - return (u8)a[i] - (u8)b[i]; + u8 ac = (u8)a[i]; + u8 bc = (u8)b[i]; - if (a[i] == '\0') - return 0; + if (ac == '\0' || bc == '\0') { + if (ac == bc) + return 0; + return ac - bc; + } + + if (ac != bc) + return ac - bc; } /* @@ -1812,9 +1823,10 @@ rw_gbe_file_exact(int fd, u8 *mem, size_t nrw, { size_t mem_addr; size_t buf_addr; + ssize_t r; - if (mem == NULL) - goto err_rw_gbe_file_exact; + if (io_args(fd, mem, nrw, off, rw_type) == -1) + return -1; mem_addr = (size_t)(void *)mem; buf_addr = (size_t)(void *)buf; @@ -1833,13 +1845,15 @@ rw_gbe_file_exact(int fd, u8 *mem, size_t nrw, if (nrw > (size_t)(gbe_file_size - off)) goto err_rw_gbe_file_exact; - if (nrw > GBE_PART_SIZE) + if (nrw > (size_t)GBE_PART_SIZE) goto err_rw_gbe_file_exact; - return rw_file_exact(fd, mem, nrw, off, rw_type, + r = rw_file_exact(fd, mem, nrw, off, rw_type, NO_LOOP_EAGAIN, LOOP_EINTR, MAX_ZERO_RW_RETRY, OFF_ERR); + return rw_over_nrw(r, nrw); + err_rw_gbe_file_exact: errno = EIO; return -1; @@ -1888,20 +1902,13 @@ rw_file_exact(int fd, u8 *mem, size_t nrw, size_t nrw_cur; void *mem_cur; - if (mem == NULL) - goto err_rw_file_exact; - - if (fd < 0 - || off < 0 - || !nrw /* prevent zero read request */ - || nrw > (size_t)SSIZE_MAX /* prevent overflow */ - || (uint)rw_type > IO_PWRITE) - goto err_rw_file_exact; + if (io_args(fd, mem, nrw, off, rw_type) == -1) + return -1; while (1) { /* Prevent theoretical overflow */ - if ((size_t)rv > (nrw - rc)) + if (rv >= 0 && (size_t)rv > (nrw - rc)) goto err_rw_file_exact; rc += rv; @@ -1910,6 +1917,8 @@ rw_file_exact(int fd, u8 *mem, size_t nrw, mem_cur = (void *)(mem + (size_t)rc); nrw_cur = (size_t)(nrw - (size_t)rc); + if (off < 0) + goto err_rw_file_exact; off_cur = (off_t)((size_t)off + (size_t)rc); rv = prw(fd, mem_cur, nrw_cur, off_cur, @@ -1997,15 +2006,8 @@ prw(int fd, void *mem, size_t nrw, off_t off_last; #endif - if (mem == NULL) - goto err_prw; - - if (fd < 0 - || off < 0 - || !nrw /* prevent zero read request */ - || nrw > (size_t)SSIZE_MAX /* prevent overflow */ - || (uint)rw_type > IO_PWRITE) - goto err_prw; + if (io_args(fd, mem, nrw, off, rw_type) == -1) + return -1; r = -1; @@ -2073,42 +2075,49 @@ real_pread_pwrite: * if the offset changed to what * we previously got. If it did, * then another thread may have - * changed it. + * changed it. Enabled if + * off_reset is OFF_RESET. * - * This is no substitute for real - * pread/pwrite, which would be - * fully atomic at kernel-level - * and do not use file offsets. - * - * TODO: Add a toggle to make it - * recover instead, reset - * to known offset, and - * carry on operations. - * - * 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. + * We do this *once*, on the theory + * that nothing is touching it now. */ - 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; - } + if (off_reset && off != verified) + lseek_loop(fd, off, SEEK_SET, + loop_eagain, loop_eintr); do { + /* + * Verify again before I/O + * (even with OFF_ERR) + * + * This implements the first check + * even with OFF_ERR, but without + * the recovery. On ERR_RESET, if + * the check fails again, then we + * know something else is touching + * the file, so it's best that we + * probably leave it alone and err. + * + * In other words, ERR_RESET only + * tolerates one change. Any more + * will cause an exit, including + * per EINTR/EAGAIN re-spin. + */ + verified = lseek_loop(fd, (off_t)0, SEEK_CUR, + loop_eagain, loop_eintr); + + if (off != verified) + goto err_prw; + if (rw_type == IO_PREAD) r = read(fd, mem, nrw); else if (rw_type == IO_PWRITE) r = write(fd, mem, nrw); - r = rw_over_nrw(r, nrw); + if (rw_over_nrw(r, nrw) == -1) { + errno = EIO; + break; + } } while (r == -1 && (errno == try_err(loop_eintr, EINTR) @@ -2116,14 +2125,15 @@ real_pread_pwrite: } saved_errno = errno; + off_last = lseek_loop(fd, off_orig, SEEK_SET, loop_eagain, loop_eintr); - if (off_last == (off_t)-1) { + + if (off_last != off_orig) { errno = saved_errno; - return -1; - } - if (off_last != off_orig) goto err_prw; + } + errno = saved_errno; return rw_over_nrw(r, nrw); @@ -2135,6 +2145,44 @@ err_prw: } static int +io_args(int fd, void *mem, size_t nrw, + off_t off, int rw_type) +{ + /* obviously */ + if (mem == NULL) + goto err_io_args; + + /* uninitialised fd */ + if (fd < 0) + goto err_io_args; + + /* negative offset */ + if (off < 0) + goto err_io_args; + + /* prevent zero-byte rw */ + if (!nrw) + goto err_io_args; + + /* prevent overflow */ + if (nrw > (size_t)SSIZE_MAX) + goto err_io_args; + + /* prevent overflow */ + if (((size_t)off + nrw) < (size_t)off) + goto err_io_args; + + if (rw_type > IO_PWRITE) + goto err_io_args; + + return 0; + +err_io_args: + errno = EIO; + return -1; +} + +static int check_file(int fd, struct stat *st) { if (fstat(fd, st) == -1) @@ -2243,35 +2291,12 @@ try_err(int loop_err, int errval) return -1; } -static int -close_files(void) -{ - int close_err_gbe = 0; - int saved_errno = errno; - - if (gbe_fd > -1) { - if (close(gbe_fd) == -1) - close_err_gbe = errno; - gbe_fd = -1; - } - - if (saved_errno) - errno = saved_errno; - - if (close_err_gbe) - return -1; - - return 0; -} - static void err(int nvm_errval, const char *msg, ...) { va_list args; - if (errno < 0) - errno = ECANCELED; - if (!errno) + if (errno == 0) errno = nvm_errval; (void)close_files(); @@ -2288,6 +2313,27 @@ err(int nvm_errval, const char *msg, ...) exit(EXIT_FAILURE); } +static int +close_files(void) +{ + int close_err_gbe = 0; + int saved_errno = errno; + + if (gbe_fd > -1) { + if (close(gbe_fd) == -1) + close_err_gbe = errno; + gbe_fd = -1; + } + + if (saved_errno) + errno = saved_errno; + + if (close_err_gbe) + return -1; + + return 0; +} + static const char * getnvmprogname(void) { |
