summaryrefslogtreecommitdiff
path: root/util/libreboot-utils
diff options
context:
space:
mode:
Diffstat (limited to 'util/libreboot-utils')
-rw-r--r--util/libreboot-utils/include/common.h28
-rw-r--r--util/libreboot-utils/lib/command.c6
-rw-r--r--util/libreboot-utils/lib/file.c288
-rw-r--r--util/libreboot-utils/lib/io.c7
-rw-r--r--util/libreboot-utils/lib/mkhtemp.c398
-rw-r--r--util/libreboot-utils/lib/num.c6
-rw-r--r--util/libreboot-utils/lib/rand.c11
-rw-r--r--util/libreboot-utils/lib/string.c54
-rw-r--r--util/libreboot-utils/lottery.c1
-rw-r--r--util/libreboot-utils/mkhtemp.c14
-rw-r--r--util/libreboot-utils/nvmutil.c6
11 files changed, 370 insertions, 449 deletions
diff --git a/util/libreboot-utils/include/common.h b/util/libreboot-utils/include/common.h
index bc0eb3b3..48831ea3 100644
--- a/util/libreboot-utils/include/common.h
+++ b/util/libreboot-utils/include/common.h
@@ -26,6 +26,24 @@
#include <unistd.h>
#endif
+/* dangerously cool macros:
+ */
+
+#define SUCCESS(x) ((x) >= 0)
+
+/* syscalls can set errno even on success; this
+ * is rare, but permitted. in various functions, we
+ * reset errno on success, to what the caller had,
+ * but we must still honour what was returned.
+ *
+ * lib/file.c is littered with examples
+ */
+#define reset_caller_errno(return_value) \
+ do { \
+ if (SUCCESS(return_value) && (!errno)) \
+ errno = saved_errno; \
+ } while (0)
+
#define items(x) (sizeof((x)) / sizeof((x)[0]))
/* system prototypes
@@ -464,7 +482,7 @@ ssize_t rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw,
int fsync_dir(const char *path);
ssize_t rw_file_exact(int fd, unsigned char *mem, size_t len,
off_t off, int rw_type, size_t max_retries, int off_reset);
-ssize_t prw(int fd, void *mem, size_t nrw,
+ssize_t rw(int fd, void *mem, size_t nrw,
off_t off, int rw_type);
int io_args(int fd, void *mem, size_t nrw,
off_t off, int rw_type);
@@ -489,7 +507,7 @@ int rw_retry(int saved_errno, ssize_t rval);
*/
void usage(void);
-int set_errno(int saved_errno, int fallback);
+int with_fallback_errno(int fallback);
void err_exit(int nvm_errval, const char *msg, ...);
func_t errhook(func_t ptr); /* hook function for cleanup on err */
const char *lbgetprogname(void);
@@ -506,7 +524,7 @@ int new_tmpdir(int *fd, char **path, char *tmpdir,
int new_tmp_common(int *fd, char **path, int type,
char *tmpdir, const char *template);
int mkhtemp_try_create(int dirfd,
- struct stat *st_dir_initial,
+ struct stat *st_dir_first,
char *fname_copy,
char *p,
size_t xc,
@@ -515,7 +533,7 @@ int mkhtemp_try_create(int dirfd,
int type);
int
mkhtemp_tmpfile_linux(int dirfd,
- struct stat *st_dir_initial,
+ struct stat *st_dir_first,
char *fname_copy,
char *p,
size_t xc,
@@ -523,7 +541,7 @@ mkhtemp_tmpfile_linux(int dirfd,
struct stat *st);
int mkhtemp(int *fd, struct stat *st,
char *template, int dirfd, const char *fname,
- struct stat *st_dir_initial, int type);
+ struct stat *st_dir_first, int type);
int world_writeable_and_sticky(const char *s,
int sticky_allowed, int always_sticky);
int same_dir(const char *a, const char *b);
diff --git a/util/libreboot-utils/lib/command.c b/util/libreboot-utils/lib/command.c
index 16ca8346..5ccf9de9 100644
--- a/util/libreboot-utils/lib/command.c
+++ b/util/libreboot-utils/lib/command.c
@@ -15,9 +15,6 @@
#include "../include/common.h"
-/* Guard against regressions by maintainers (command table)
- */
-
void
sanitize_command_list(void)
{
@@ -496,8 +493,7 @@ cat_buf(unsigned char *b)
err_exit(errno, "null pointer in cat command");
if (rw_file_exact(STDOUT_FILENO, b,
- GBE_PART_SIZE, 0, IO_WRITE, MAX_ZERO_RW_RETRY, OFF_ERR)
- < 0)
+ GBE_PART_SIZE, 0, IO_WRITE, MAX_ZERO_RW_RETRY, OFF_ERR) < 0)
err_exit(errno, "stdout: cat");
}
void
diff --git a/util/libreboot-utils/lib/file.c b/util/libreboot-utils/lib/file.c
index 42c91843..805db726 100644
--- a/util/libreboot-utils/lib/file.c
+++ b/util/libreboot-utils/lib/file.c
@@ -44,51 +44,31 @@ same_file(int fd, struct stat *st_old,
{
struct stat st;
int saved_errno = errno;
+ int rval = 0;
+ errno = 0;
- /* TODO: null/-1 checks
- * like this can be
- * generalised
- */
- if (st_old == NULL) {
- errno = EFAULT;
- goto err_same_file;
- }
- if (fd < 0) {
- errno = EBADF;
- goto err_same_file;
- }
-
- if (fstat(fd, &st) == -1)
- goto err_same_file;
-
- if (fd_verify_regular(fd, st_old, &st) < 0)
- goto err_same_file;
-
- if (check_size &&
- st.st_size != st_old->st_size)
- goto err_same_file;
+ if (if_err(st_old == NULL, EFAULT) ||
+ if_err(fd < 0, EBADF) ||
+ (rval = fstat(fd, &st)) < 0 ||
+ (rval = fd_verify_regular(fd, st_old, &st)) < 0 ||
+ if_err(check_size && st.st_size != st_old->st_size, ESTALE))
+ return with_fallback_errno(ESTALE);
- errno = saved_errno;
+ reset_caller_errno(rval);
return 0;
-
-err_same_file:
- return set_errno(saved_errno, ESTALE);
}
int
fsync_dir(const char *path)
{
int saved_errno = errno;
-
size_t pathlen = 0;
-
char *dirbuf = NULL;
int dirfd = -1;
-
char *slash = NULL;
struct stat st = {0};
-
- int close_errno;
+ int rval = 0;
+ errno = 0;
if (if_err(slen(path, PATH_MAX, &pathlen) == 0, EINVAL))
goto err_fsync_dir;
@@ -119,26 +99,23 @@ fsync_dir(const char *path)
);
if (if_err_sys(dirfd < 0) ||
- if_err_sys(fstat(dirfd, &st) < 0) ||
+ if_err_sys((rval = fstat(dirfd, &st)) < 0) ||
if_err(!S_ISDIR(st.st_mode), ENOTDIR)
||
- if_err_sys(fsync_on_eintr(dirfd) == -1))
+ if_err_sys((rval = fsync_on_eintr(dirfd)) == -1))
goto err_fsync_dir;
close_on_eintr(&dirfd);
-
free_and_set_null(&dirbuf);
- errno = saved_errno;
+ reset_caller_errno(rval);
return 0;
err_fsync_dir:
-
-
free_and_set_null(&dirbuf);
close_on_eintr(&dirfd);
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
}
/* rw_file_exact() - Read perfectly or die
@@ -162,34 +139,23 @@ ssize_t
rw_file_exact(int fd, unsigned char *mem, size_t nrw,
off_t off, int rw_type, size_t max_retries, int off_reset)
{
- ssize_t rval;
- ssize_t rc;
-
+ int saved_errno = errno;
+ ssize_t rval = 0;
+ ssize_t rc = 0;
size_t nrw_cur;
-
off_t off_cur;
void *mem_cur;
-
- size_t retries_on_zero;
-
- int saved_errno = errno;
+ size_t retries_on_zero = 0;
errno = 0;
- rval = 0;
-
- rc = 0;
- retries_on_zero = 0;
-
if (io_args(fd, mem, nrw, off, rw_type) == -1)
goto err_rw_file_exact;
while (1) {
/* Prevent theoretical overflow */
- if (rval >= 0 && (size_t)rval > (nrw - rc)) {
- errno = EOVERFLOW;
+ if (if_err(rval >= 0 && (size_t)rval > (nrw - rc), EOVERFLOW))
goto err_rw_file_exact;
- }
rc += rval;
if ((size_t)rc >= nrw)
@@ -198,50 +164,36 @@ rw_file_exact(int fd, unsigned char *mem, size_t nrw,
mem_cur = (void *)(mem + (size_t)rc);
nrw_cur = (size_t)(nrw - (size_t)rc);
- if (off < 0) {
- errno = EOVERFLOW;
+ if (if_err(off < 0, EOVERFLOW))
goto err_rw_file_exact;
- }
off_cur = off + (off_t)rc;
- rval = prw(fd, mem_cur, nrw_cur, off_cur,
- rw_type);
-
- if (rval < 0)
+ if ((rval = rw(fd, mem_cur, nrw_cur, off_cur, rw_type)) < 0)
goto err_rw_file_exact;
if (rval == 0) {
if (retries_on_zero++ < max_retries)
continue;
- errno = EIO;
goto err_rw_file_exact;
}
retries_on_zero = 0;
}
- if ((size_t)rc != nrw) {
-
- errno = EIO;
- goto err_rw_file_exact;
- }
-
- rval = rw_over_nrw(rc, nrw);
- if (rval < 0)
+ if (if_err((size_t)rc != nrw, EIO) ||
+ (rval = rw_over_nrw(rc, nrw)) < 0)
goto err_rw_file_exact;
- errno = saved_errno;
-
+ reset_caller_errno(rval);
return rval;
err_rw_file_exact:
-
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
}
-/* prw() - portable read-write with more
+/* rw() - read-write but with more
* safety checks than barebones libc
*
* A fallback is provided for regular read/write.
@@ -250,35 +202,40 @@ err_rw_file_exact:
*/
ssize_t
-prw(int fd, void *mem, size_t nrw,
+rw(int fd, void *mem, size_t nrw,
off_t off, int rw_type)
{
- ssize_t rval;
- ssize_t r;
+ ssize_t rval = 0;
+ ssize_t r = -1;
struct stat st;
int saved_errno = errno;
errno = 0;
if (io_args(fd, mem, nrw, off, rw_type) == -1)
- return set_errno(saved_errno, EIO);
-
- r = -1;
+ return with_fallback_errno(EINVAL);
- if (rw_type == IO_WRITE)
+ switch (rw_type) {
+ case IO_WRITE:
r = write_on_eintr(fd, mem, nrw);
- else if (rw_type == IO_READ)
+ break;
+ case IO_READ:
r = read_on_eintr(fd, mem, nrw);
- else if (rw_type == IO_PWRITE)
+ break;
+ case IO_PWRITE:
r = pwrite_on_eintr(fd, mem, nrw, off);
- else if (rw_type == IO_PREAD)
+ break;
+ case IO_PREAD:
r = pread_on_eintr(fd, mem, nrw, off);
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
if ((rval = rw_over_nrw(r, nrw)) < 0)
- return set_errno(saved_errno, EIO);
-
- if (rval >= 0 && !errno)
- errno = saved_errno;
+ return with_fallback_errno(EIO);
+ reset_caller_errno(rval);
return rval;
}
@@ -287,6 +244,7 @@ io_args(int fd, void *mem, size_t nrw,
off_t off, int rw_type)
{
int saved_errno = errno;
+ errno = 0;
if (if_err(mem == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
@@ -297,29 +255,31 @@ io_args(int fd, void *mem, size_t nrw,
if_err(rw_type > IO_PWRITE, EINVAL))
goto err_io_args;
- errno = saved_errno;
+ reset_caller_errno(0);
return 0;
err_io_args:
- return set_errno(saved_errno, EINVAL);
+ return with_fallback_errno(EINVAL);
}
int
check_file(int fd, struct stat *st)
{
int saved_errno = errno;
+ int rval = 0;
+ errno = 0;
if (if_err(fd < 0, EBADF) ||
if_err(st == NULL, EFAULT) ||
- if_err(fstat(fd, st) == -1, 0) ||
+ ((rval = fstat(fd, st)) == -1) ||
if_err(!S_ISREG(st->st_mode), EBADF))
goto err_is_file;
- errno = saved_errno;
+ reset_caller_errno(rval);
return 0;
err_is_file:
- return set_errno(saved_errno, EINVAL);
+ return with_fallback_errno(EINVAL);
}
/* POSIX can say whatever it wants.
@@ -328,15 +288,12 @@ err_is_file:
ssize_t
rw_over_nrw(ssize_t r, size_t nrw)
{
- int saved_errno = errno;
-
- if (if_err(!nrw, 0) ||
- if_err(r == -1, 0) ||
+ if (if_err(!nrw, EIO) ||
+ (r == -1) ||
if_err((size_t)r > SSIZE_MAX, ERANGE) ||
if_err((size_t)r > nrw, ERANGE))
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
- errno = saved_errno;
return r;
}
@@ -347,10 +304,8 @@ if_err(int condition, int errval)
{
if (!condition)
return 0;
-
if (errval)
errno = errval;
-
return 1;
}
int
@@ -431,6 +386,7 @@ fs_resolve_at(int dirfd, const char *path, int flags)
int saved_errno = errno;
int r;
int is_last;
+ errno = 0;
if (dirfd < 0 || path == NULL || *path == '\0') {
errno = EINVAL;
@@ -461,7 +417,7 @@ fs_resolve_at(int dirfd, const char *path, int flags)
nextfd = -1;
}
- errno = saved_errno;
+ reset_caller_errno(0);
return curfd;
err:
@@ -475,7 +431,7 @@ err:
close_on_eintr(&curfd);
errno = saved_errno;
- return -1;
+ return with_fallback_errno(EIO);
}
/* NOTE:
@@ -515,41 +471,36 @@ fs_next_component(const char **p,
name[len] = '\0';
/* reject . and .. */
- if ((name[0] == '.' && name[1] == '\0') ||
- (name[0] == '.' && name[1] == '.' && name[2] == '\0')) {
- errno = EPERM;
- return -1;
- }
+ if (if_err((name[0] == '.' && name[1] == '\0') ||
+ (name[0] == '.' && name[1] == '.' && name[2] == '\0'), EPERM))
+ goto err;
*p = s + len;
return 1;
+err:
+ return with_fallback_errno(EPERM);
}
int
fs_open_component(int dirfd, const char *name,
int flags, int is_last)
{
+ int saved_errno = errno;
int fd;
struct stat st;
+ errno = 0;
fd = openat_on_eintr(dirfd, name,
(is_last ? flags : (O_RDONLY | O_DIRECTORY)) |
O_NOFOLLOW | O_CLOEXEC, (flags & O_CREAT) ? 0600 : 0);
- if (!is_last) {
-
- if (if_err(fd < 0, EBADF) ||
- if_err_sys(fstat(fd, &st) < 0))
- return -1;
-
- if (!S_ISDIR(st.st_mode)) {
-
- close_on_eintr(&fd);
- errno = ENOTDIR;
- return -1;
- }
- }
+ if (!is_last &&
+ (if_err(fd < 0, EBADF) ||
+ if_err_sys(fstat(fd, &st) < 0) ||
+ if_err(!S_ISDIR(st.st_mode), ENOTDIR)))
+ return with_fallback_errno(EIO);
+ reset_caller_errno(fd);
return fd;
}
@@ -558,13 +509,14 @@ fs_dirname_basename(const char *path,
char **dir, char **base,
int allow_relative)
{
+ int saved_errno = errno;
char *buf = NULL;
char *slash;
size_t len;
- int rval;
+ errno = 0;
if (if_err(path == NULL || dir == NULL || base == NULL, EFAULT))
- return -1;
+ goto err;
slen(path, PATH_MAX, &len);
memcpy(smalloc(&buf, len + 1),
@@ -591,12 +543,14 @@ fs_dirname_basename(const char *path,
sdup(".", PATH_MAX, dir);
*base = buf;
} else {
- errno = EINVAL;
free_and_set_null(&buf);
- return -1;
+ goto err;
}
+ reset_caller_errno(0);
return 0;
+err:
+ return with_fallback_errno(EINVAL);
}
/* TODO: why does this abort, but others
@@ -608,7 +562,8 @@ open_file_on_eintr(const char *path,
struct stat *st)
{
int saved_errno = errno;
- int rval;
+ int rval = 0;
+ errno = 0;
if (path == NULL)
err_exit(EINVAL, "open_file_on_eintr: null path");
@@ -626,8 +581,17 @@ open_file_on_eintr(const char *path,
err_exit(errno,
"%s: open_file_on_eintr: could not close", path);
+ reset_caller_errno(rval);
*fd = rval;
+ /* we don't care about edge case behaviour here,
+ even if the next operation sets errno on success,
+ because the open() call is our main concern.
+ however, we also must preserve the new errno,
+ assuming it changed above under the same edge case */
+
+ saved_errno = errno;
+
if (st != NULL) {
if (fstat(*fd, st) < 0)
err_exit(errno, "%s: stat", path);
@@ -639,7 +603,7 @@ open_file_on_eintr(const char *path,
if (lseek_on_eintr(*fd, 0, SEEK_CUR, 1, 1) == (off_t)-1)
err_exit(errno, "%s: file not seekable", path);
- errno = saved_errno;
+ errno = saved_errno; /* see previous comment */
}
@@ -657,20 +621,24 @@ openat_on_eintr(int dirfd, const char *path,
RESOLVE_NO_MAGICLINKS
};
int saved_errno = errno;
- long rval;
+ long rval = 0;
+ errno = 0;
if (if_err(dirfd < 0, EBADF) ||
if_err(path == NULL, EFAULT))
- return set_errno(saved_errno, EIO);
+ goto err;
errno = 0;
while (sys_retry(saved_errno,
rval = syscall(SYS_openat2, dirfd, path, &how, sizeof(how))));
if (rval == -1) /* avoid long->int UB for -1 */
- return -1;
+ goto err;
+ reset_caller_errno(rval);
return (int)rval;
+err:
+ return with_fallback_errno(EIO); /* -1 */
}
#else /* regular openat on non-linux e.g. openbsd */
int
@@ -678,16 +646,17 @@ openat_on_eintr(int dirfd, const char *path,
int flags, mode_t mode)
{
int saved_errno = errno;
- int rval;
+ int rval = 0;
+ errno = 0;
if (if_err(dirfd < 0, EBADF) ||
if_err(path == NULL, EFAULT))
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
- errno = 0;
while (fs_retry(saved_errno,
rval = openat(dirfd, path, flags, mode)));
+ reset_caller_errno(rval);
return rval;
}
#endif
@@ -697,12 +666,13 @@ lseek_on_eintr(int fd, off_t off, int whence,
int loop_eagain, int loop_eintr)
{
int saved_errno = errno;
- off_t rval;
-
+ off_t rval = 0;
errno = 0;
+
while (off_retry(saved_errno,
rval = lseek(fd, off, whence)));
+ reset_caller_errno(rval);
return rval;
}
@@ -711,16 +681,17 @@ mkdirat_on_eintr(int dirfd,
const char *path, mode_t mode)
{
int saved_errno = errno;
- int rval;
+ int rval = 0;
+ errno = 0;
if (if_err(dirfd < 0, EBADF) ||
if_err(path == NULL, EFAULT))
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
- errno = 0;
while (fs_retry(saved_errno,
rval = mkdirat(dirfd, path, mode)));
+ reset_caller_errno(rval);
return rval;
}
@@ -729,17 +700,18 @@ read_on_eintr(int fd,
void *buf, size_t count)
{
int saved_errno = errno;
- ssize_t rval;
+ ssize_t rval = 0;
+ errno = 0;
if (if_err(buf == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
if_err(count == 0, EINVAL))
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
- errno = 0;
while (rw_retry(saved_errno,
rval = read(fd, buf, count)));
+ reset_caller_errno(rval);
return rval;
}
@@ -749,18 +721,19 @@ pread_on_eintr(int fd,
off_t off)
{
int saved_errno = errno;
- ssize_t rval;
+ ssize_t rval = 0;
+ errno = 0;
if (if_err(buf == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
if_err(off < 0, EFAULT) ||
if_err(count == 0, EINVAL))
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
- errno = 0;
while (rw_retry(saved_errno,
rval = pread(fd, buf, count, off)));
+ reset_caller_errno(rval);
return rval;
}
@@ -769,17 +742,18 @@ write_on_eintr(int fd,
void *buf, size_t count)
{
int saved_errno = errno;
- ssize_t rval;
+ ssize_t rval = 0;
+ errno = 0;
if (if_err(buf == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
if_err(count == 0, EINVAL))
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
- errno = 0;
while (rw_retry(saved_errno,
rval = write(fd, buf, count)));
+ reset_caller_errno(rval);
return rval;
}
@@ -789,18 +763,19 @@ pwrite_on_eintr(int fd,
off_t off)
{
int saved_errno = errno;
- ssize_t rval;
+ ssize_t rval = 0;
+ errno = 0;
if (if_err(buf == NULL, EFAULT) ||
if_err(fd < 0, EBADF) ||
if_err(off < 0, EFAULT) ||
if_err(count == 0, EINVAL))
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
- errno = 0;
while (rw_retry(saved_errno,
rval = pwrite(fd, buf, count, off)));
+ reset_caller_errno(rval);
return rval;
}
@@ -808,15 +783,16 @@ int
fsync_on_eintr(int fd)
{
int saved_errno = errno;
- int rval;
+ int rval = 0;
+ errno = 0;
if (if_err(fd < 0, EBADF))
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
- errno = 0;
while (fs_retry(saved_errno,
rval = fsync(fd)));
+ reset_caller_errno(rval);
return rval;
}
@@ -824,7 +800,7 @@ void
close_on_eintr(int *fd)
{
int saved_errno = errno;
- int rval;
+ int rval = 0;
if (fd == NULL)
err_exit(EINVAL, "close_on_eintr: null pointer");
@@ -839,6 +815,8 @@ close_on_eintr(int *fd)
err_exit(errno, "close_on_eintr: could not close");
*fd = -1;
+
+ reset_caller_errno(rval);
}
/* unified eintr looping.
diff --git a/util/libreboot-utils/lib/io.c b/util/libreboot-utils/lib/io.c
index f74ce261..9bbf1f30 100644
--- a/util/libreboot-utils/lib/io.c
+++ b/util/libreboot-utils/lib/io.c
@@ -470,9 +470,9 @@ ret_gbe_mv:
if (rval >= 0)
goto out;
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
out:
- errno = saved_errno;
+ reset_caller_errno(rval);
return rval;
}
@@ -572,6 +572,5 @@ rw_gbe_file_exact(int fd, unsigned char *mem, size_t nrw,
return rw_over_nrw(r, nrw);
err_rw_gbe_file_exact:
- errno = EIO;
- return -1;
+ return with_fallback_errno(EIO);
}
diff --git a/util/libreboot-utils/lib/mkhtemp.c b/util/libreboot-utils/lib/mkhtemp.c
index 7589a410..c1574634 100644
--- a/util/libreboot-utils/lib/mkhtemp.c
+++ b/util/libreboot-utils/lib/mkhtemp.c
@@ -67,20 +67,15 @@ new_tmp_common(int *fd, char **path, int type,
int dirfd = -1;
const char *fname = NULL;
- struct stat st_dir_initial;
+ struct stat st_dir_first;
char *fail_dir = NULL;
- if (path == NULL || fd == NULL) {
- errno = EFAULT;
- goto err;
- }
+ errno = 0;
- /* don't mess with someone elses file */
- if (*fd >= 0) {
- errno = EEXIST;
+ if (if_err(path == NULL || fd == NULL, EFAULT) ||
+ if_err(*fd >= 0, EEXIST)) /* don't touch someone else's file */
goto err;
- }
/* regarding **path:
* the pointer (to the pointer)
@@ -111,12 +106,7 @@ new_tmp_common(int *fd, char **path, int type,
tmpdir = env_tmpdir(0, &fail_dir, tmpdir);
#endif
}
- if (tmpdir == NULL)
- goto err;
-
- if (*tmpdir == '\0')
- goto err;
- if (*tmpdir != '/')
+ if (if_err(tmpdir ==NULL || *tmpdir == '\0' || *tmpdir != '/', EINVAL))
goto err;
if (template != NULL)
@@ -138,11 +128,11 @@ new_tmp_common(int *fd, char **path, int type,
if (dirfd < 0)
goto err;
- if (fstat(dirfd, &st_dir_initial) < 0)
+ if (fstat(dirfd, &st_dir_first) < 0)
goto err;
*fd = mkhtemp(fd, &st, dest, dirfd,
- fname, &st_dir_initial, type);
+ fname, &st_dir_first, type);
if (*fd < 0)
goto err;
@@ -151,15 +141,10 @@ new_tmp_common(int *fd, char **path, int type,
errno = saved_errno;
*path = dest;
+ reset_caller_errno(0);
return 0;
err:
-
- if (errno != saved_errno)
- saved_errno = errno;
- else
- saved_errno = errno = EIO;
-
free_and_set_null(&dest);
close_on_eintr(&dirfd);
@@ -173,7 +158,7 @@ err:
*path = fail_dir;
errno = saved_errno;
- return -1;
+ return with_fallback_errno(EIO);
}
@@ -184,13 +169,17 @@ char *
env_tmpdir(int bypass_all_sticky_checks, char **tmpdir,
char *override_tmpdir)
{
- char *t;
+ char *t = NULL;
int allow_noworld_unsticky;
int saved_errno = errno;
static const char tmp[] = "/tmp";
static const char vartmp[] = "/var/tmp";
+ char *rval = NULL;
+
+ errno = 0;
+
/* tmpdir is a user override, if set */
if (override_tmpdir == NULL)
t = getenv("TMPDIR");
@@ -200,48 +189,38 @@ env_tmpdir(int bypass_all_sticky_checks, char **tmpdir,
if (t != NULL && *t != '\0') {
if (tmpdir_policy(t,
- &allow_noworld_unsticky) < 0) {
- if (tmpdir != NULL)
- *tmpdir = t;
- return NULL; /* errno already set */
- }
+ &allow_noworld_unsticky) < 0)
+ goto err;
if (!world_writeable_and_sticky(t,
allow_noworld_unsticky,
- bypass_all_sticky_checks)) {
- if (tmpdir != NULL)
- *tmpdir = t;
- return NULL;
- }
+ bypass_all_sticky_checks))
+ goto err;
- errno = saved_errno;
- return t;
+ rval = t;
+ goto out;
}
allow_noworld_unsticky = 0;
- if (world_writeable_and_sticky(tmp,
- allow_noworld_unsticky,
- bypass_all_sticky_checks)) {
-
- if (tmpdir != NULL)
- *tmpdir = (char *)tmp;
-
- errno = saved_errno;
- return (char *)tmp;
- }
-
- if (world_writeable_and_sticky(vartmp,
- allow_noworld_unsticky,
- bypass_all_sticky_checks)) {
-
- if (tmpdir != NULL)
- *tmpdir = (char *)vartmp;
-
- errno = saved_errno;
- return (char *)vartmp;
- }
+ if (world_writeable_and_sticky(tmp, allow_noworld_unsticky,
+ bypass_all_sticky_checks))
+ rval = (char *)tmp;
+ else if (world_writeable_and_sticky(vartmp,
+ allow_noworld_unsticky, bypass_all_sticky_checks))
+ rval = (char *)vartmp;
+ else
+ goto err;
+out:
+ reset_caller_errno(0);
+ if (tmpdir != NULL)
+ *tmpdir = rval;
+ return rval;
+err:
+ if (tmpdir != NULL && t != NULL)
+ *tmpdir = t;
+ (void) with_fallback_errno(EPERM);
return NULL;
}
@@ -251,13 +230,11 @@ tmpdir_policy(const char *path,
{
int saved_errno = errno;
int r;
+ errno = 0;
- if (path == NULL ||
- allow_noworld_unsticky == NULL) {
-
- errno = EFAULT;
- return -1;
- }
+ if (if_err(path == NULL ||
+ allow_noworld_unsticky == NULL, EFAULT))
+ goto err_tmpdir_policy;
*allow_noworld_unsticky = 1;
@@ -273,11 +250,11 @@ tmpdir_policy(const char *path,
if (r > 0)
*allow_noworld_unsticky = 0;
- errno = saved_errno;
+ reset_caller_errno(0);
return 0;
err_tmpdir_policy:
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EPERM);
}
int
@@ -290,63 +267,48 @@ same_dir(const char *a, const char *b)
struct stat st_b;
int saved_errno = errno;
- int rval_scmp;
+ int rval = 0; /* LOGICAL error, 0, if 0 is returned */
+ errno = 0;
/* optimisation: if both dirs
are the same, we don't need
to check anything. sehr schnell!
*/
/* bonus: scmp checks null for us */
- if (!scmp(a, b, PATH_MAX, &rval_scmp))
+ if (!scmp(a, b, PATH_MAX, &rval))
goto success_same_dir;
+ else
+ rval = 0; /* reset */
- fd_a = fs_open(a, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
- if (fd_a < 0)
- goto err_same_dir;
-
- fd_b = fs_open(b, O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
- if (fd_b < 0)
- goto err_same_dir;
-
- if (fstat(fd_a, &st_a) < 0)
- goto err_same_dir;
-
- if (fstat(fd_b, &st_b) < 0)
+ if ((fd_a = fs_open(a, O_RDONLY | O_DIRECTORY | O_NOFOLLOW)) < 0 ||
+ (fd_b = fs_open(b, O_RDONLY | O_DIRECTORY | O_NOFOLLOW)) < 0 ||
+ fstat(fd_a, &st_a) < 0 ||
+ fstat(fd_b, &st_b) < 0)
goto err_same_dir;
if (st_a.st_dev == st_b.st_dev &&
st_a.st_ino == st_b.st_ino) {
-
- close_on_eintr(&fd_a);
- close_on_eintr(&fd_b);
-
success_same_dir:
-
- /* SUCCESS
- */
-
- errno = saved_errno;
- return 1;
+ rval = 1; /* SUCCESS */
}
close_on_eintr(&fd_a);
close_on_eintr(&fd_b);
- /* FAILURE (logical)
+ /* we reset caller errno regardless
+ * of success, so long as it's not
+ * a syscall error
*/
-
- errno = saved_errno;
- return 0;
+ reset_caller_errno(0);
+ return rval;
err_same_dir:
-
- /* FAILURE (probably syscall)
+ /* FAILURE (probably syscall) - returns -1
*/
-
close_on_eintr(&fd_a);
close_on_eintr(&fd_b);
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO); /* -1 */
}
/* bypass_all_sticky_checks: if set,
@@ -367,81 +329,45 @@ world_writeable_and_sticky(
int dirfd = -1;
int saved_errno = errno;
+ errno = 0;
- if (s == NULL || *s == '\0') {
- errno = EINVAL;
- goto sticky_hell;
- }
-
- /* mitigate symlink attacks*
- */
- dirfd = fs_open(s, O_RDONLY | O_DIRECTORY);
- if (dirfd < 0)
- goto sticky_hell;
-
- if (fstat(dirfd, &st) < 0)
- goto sticky_hell;
-
- if (!S_ISDIR(st.st_mode)) {
- errno = ENOTDIR;
- goto sticky_hell;
- }
-
- /* all of these checks are probably
- * redundant (execution rights)
- if (!(st.st_mode & S_IXUSR) ||
- !(st.st_mode & S_IXGRP) ||
- !(st.st_mode & S_IXOTH)) {
- */
- /* just require it for *you*, for now */
- if (!(st.st_mode & S_IXUSR)) {
- errno = EACCES;
+ if (if_err(s == NULL || *s == '\0', EINVAL) ||
+ (dirfd = fs_open(s, O_RDONLY | O_DIRECTORY)) < 0 ||
+ fstat(dirfd, &st) < 0 ||
+ if_err(!S_ISDIR(st.st_mode), ENOTDIR))
goto sticky_hell;
- }
/* *normal-**ish mode (libc):
*/
-
if (bypass_all_sticky_checks)
goto sticky_heaven; /* normal == no security */
/* extremely not-libc mode:
+ * only require stickiness on world-writeable dirs:
*/
-
if (st.st_mode & S_IWOTH) { /* world writeable */
- /* if world-writeable, only
- * allow sticky files
- */
- if (st.st_mode & S_ISVTX)
- goto sticky_heaven; /* sticky */
+ if (if_err(!(st.st_mode & S_ISVTX), EPERM))
+ goto sticky_hell; /* not sticky */
- errno = EPERM;
- goto sticky_hell; /* not sticky */
+ goto sticky_heaven; /* sticky! */
+ } else if (allow_noworld_unsticky) {
+ goto sticky_heaven; /* sticky visa */
+ } else {
+ goto sticky_hell; /* visa denied */
}
- /* for good measure */
+sticky_heaven:
if (faccessat(dirfd, ".", X_OK, AT_EACCESS) < 0)
- goto sticky_hell;
+ goto sticky_hell; /* down you go! */
- /* non-world-writeable, so
- * stickiness is do-not-care
- */
- if (allow_noworld_unsticky)
- goto sticky_heaven; /* sticky! */
-
- goto sticky_hell; /* heaven visa denied */
-
-sticky_heaven:
close_on_eintr(&dirfd);
- errno = saved_errno;
-
+ reset_caller_errno(0);
return 1;
sticky_hell:
close_on_eintr(&dirfd);
-
- (void) set_errno(saved_errno, EPERM);
+ (void) with_fallback_errno(EPERM);
return 0;
}
@@ -503,7 +429,7 @@ mkhtemp(int *fd,
char *template,
int dirfd,
const char *fname,
- struct stat *st_dir_initial,
+ struct stat *st_dir_first,
int type)
{
size_t template_len = 0;
@@ -521,11 +447,13 @@ mkhtemp(int *fd,
int r;
char *end;
+ errno = 0;
+
if (if_err(fd == NULL || template == NULL || fname == NULL ||
- st_dir_initial == NULL, EFAULT) ||
+ st_dir_first == NULL, EFAULT) ||
if_err(*fd >= 0, EEXIST) ||
if_err(dirfd < 0, EBADF))
- return -1;
+ goto err;
/* count X */
for (end = template + slen(template, PATH_MAX, &template_len);
@@ -533,15 +461,15 @@ mkhtemp(int *fd,
fname_len = slen(fname, PATH_MAX, &fname_len);
if (if_err(strrchr(fname, '/') != NULL, EINVAL))
- return -1;
+ goto err;
if (if_err(xc < 3 || xc > template_len, EINVAL) ||
if_err(fname_len > template_len, EOVERFLOW))
- return -1;
+ goto err;
if (if_err(vcmp(fname, template + template_len - fname_len,
fname_len) != 0, EINVAL))
- return -1;
+ goto err;
/* fname_copy = templatestr region only; p points to trailing XXXXXX */
memcpy(smalloc(&fname_copy, fname_len + 1),
@@ -552,7 +480,7 @@ mkhtemp(int *fd,
for (retries = 0; retries < MKHTEMP_RETRY_MAX; retries++) {
r = mkhtemp_try_create(dirfd,
- st_dir_initial, fname_copy,
+ st_dir_first, fname_copy,
p, xc, fd, st, type);
if (r == 0)
@@ -569,19 +497,22 @@ mkhtemp(int *fd,
}
errno = EEXIST;
-
err:
close_on_eintr(fd);
+ free_and_set_null(&fname_copy);
+
+ return with_fallback_errno(EIO);
success:
free_and_set_null(&fname_copy);
- return (*fd >= 0) ? *fd : -1;
+ reset_caller_errno(0);
+ return *fd;
}
int
mkhtemp_try_create(int dirfd,
- struct stat *st_dir_initial,
+ struct stat *st_dir_first,
char *fname_copy,
char *p,
size_t xc,
@@ -597,8 +528,10 @@ mkhtemp_try_create(int dirfd,
int file_created = 0;
int dir_created = 0;
+ errno = 0;
+
if (if_err(fd == NULL || st == NULL || p ==NULL || fname_copy ==NULL ||
- st_dir_initial == NULL, EFAULT) ||
+ st_dir_first == NULL, EFAULT) ||
if_err(*fd >= 0, EEXIST))
goto err;
@@ -608,14 +541,14 @@ mkhtemp_try_create(int dirfd,
memcpy(p, rstr = rchars(xc), xc);
free_and_set_null(&rstr);
- if (if_err_sys(fd_verify_dir_identity(dirfd, st_dir_initial) < 0))
+ if (if_err_sys(fd_verify_dir_identity(dirfd, st_dir_first) < 0))
goto err;
if (type == MKHTEMP_FILE) {
#ifdef __linux__
/* try O_TMPFILE fast path */
if (mkhtemp_tmpfile_linux(dirfd,
- st_dir_initial, fname_copy,
+ st_dir_first, fname_copy,
p, xc, fd, st) == 0) {
errno = saved_errno;
@@ -645,7 +578,7 @@ mkhtemp_try_create(int dirfd,
dir_created = 1;
/* do it again (mitigate directory race) */
- if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
+ if (fd_verify_dir_identity(dirfd, st_dir_first) < 0)
goto err;
if ((*fd = openat_on_eintr(dirfd, fname_copy,
@@ -657,7 +590,7 @@ mkhtemp_try_create(int dirfd,
goto err;
/* NOTE: pointless to check nlink here (only just opened) */
- if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
+ if (fd_verify_dir_identity(dirfd, st_dir_first) < 0)
goto err;
}
@@ -680,7 +613,7 @@ mkhtemp_try_create(int dirfd,
if (type == MKHTEMP_FILE) {
- if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
+ if (fd_verify_dir_identity(dirfd, st_dir_first) < 0)
goto err;
if (secure_file(fd, st, &st_open,
@@ -689,7 +622,7 @@ mkhtemp_try_create(int dirfd,
} else { /* dir: MKHTEMP_DIR */
- if (fd_verify_identity(*fd, &st_open, st_dir_initial) < 0)
+ if (fd_verify_identity(*fd, &st_open, st_dir_first) < 0)
goto err;
if (if_err(!S_ISDIR(st_open.st_mode), ENOTDIR) ||
@@ -698,10 +631,11 @@ mkhtemp_try_create(int dirfd,
goto err;
}
- errno = saved_errno;
rval = 1;
- goto out;
+out:
+ reset_caller_errno(0);
+ return rval;
err:
close_on_eintr(fd);
@@ -710,9 +644,7 @@ err:
if (dir_created)
(void) unlinkat(dirfd, fname_copy, AT_REMOVEDIR);
- rval = -1;
-out:
- return rval;
+ return with_fallback_errno(EPERM);
}
/* linux has its own special hardening
@@ -725,7 +657,7 @@ out:
#ifdef __linux__
int
mkhtemp_tmpfile_linux(int dirfd,
- struct stat *st_dir_initial,
+ struct stat *st_dir_first,
char *fname_copy,
char *p,
size_t xc,
@@ -737,22 +669,21 @@ mkhtemp_tmpfile_linux(int dirfd,
size_t retries;
int linked = 0;
char *rstr = NULL;
+ errno = 0;
- if (fd == NULL || st == NULL ||
+ if (if_err(fd == NULL || st == NULL ||
fname_copy == NULL || p == NULL ||
- st_dir_initial == NULL) {
- errno = EFAULT;
- return -1;
- }
+ st_dir_first == NULL, EFAULT))
+ goto err;
/* create unnamed tmpfile */
tmpfd = openat(dirfd, ".",
O_TMPFILE | O_RDWR | O_CLOEXEC, 0600);
if (tmpfd < 0)
- return -1;
+ goto err;
- if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
+ if (fd_verify_dir_identity(dirfd, st_dir_first) < 0)
goto err;
for (retries = 0; retries < MKHTEMP_RETRY_MAX; retries++) {
@@ -761,30 +692,19 @@ mkhtemp_tmpfile_linux(int dirfd,
free_and_set_null(&rstr);
if (fd_verify_dir_identity(dirfd,
- st_dir_initial) < 0)
+ st_dir_first) < 0)
goto err;
- if (linkat(tmpfd, "",
- dirfd, fname_copy,
- AT_EMPTY_PATH) == 0) {
+ if (linkat(tmpfd, "", dirfd, fname_copy, AT_EMPTY_PATH) == 0) {
linked = 1; /* file created */
- if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
- goto err;
-
- /* success */
- *fd = tmpfd;
-
- if (fstat(*fd, st) < 0)
+ if (fd_verify_dir_identity(dirfd, st_dir_first) < 0 ||
+ fstat(*fd = tmpfd, st) < 0 ||
+ secure_file(fd, st, st, O_APPEND, 1, 1, 0600) < 0)
goto err;
- if (secure_file(fd, st, st,
- O_APPEND, 1, 1, 0600) < 0)
- goto err;
-
- errno = saved_errno;
- return 0;
+ goto out;
}
if (errno != EEXIST)
@@ -794,13 +714,15 @@ mkhtemp_tmpfile_linux(int dirfd,
}
errno = EEXIST;
-
err:
if (linked)
(void) unlinkat(dirfd, fname_copy, 0);
close_on_eintr(&tmpfd);
- return -1;
+ return with_fallback_errno(EIO);
+out:
+ reset_caller_errno(0);
+ return 0;
}
#endif
@@ -821,6 +743,7 @@ int secure_file(int *fd,
int flags;
struct stat st_now;
int saved_errno = errno;
+ errno = 0;
if (if_err(fd == NULL || st == NULL, EFAULT) ||
if_err(*fd < 0, EBADF) ||
@@ -862,23 +785,28 @@ int secure_file(int *fd,
if (fchmod(*fd, mode) == -1)
goto err_demons;
- errno = saved_errno;
+ reset_caller_errno(0);
return 0;
err_demons:
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
}
int
fd_verify_regular(int fd,
const struct stat *expected,
struct stat *out)
-{if (
- if_err_sys(fd_verify_identity(fd, expected, out) < 0) ||
- if_err(!S_ISREG(out->st_mode), EBADF)
- ) return -1;
- else
+{
+ int saved_errno = errno;
+ errno = 0;
+
+ if (if_err_sys(fd_verify_identity(fd, expected, out) < 0) ||
+ if_err(!S_ISREG(out->st_mode), EBADF)) {
+ return with_fallback_errno(EIO);
+ } else {
+ reset_caller_errno(0);
return 0; /* regular file */
+ }
}
int
@@ -888,17 +816,18 @@ fd_verify_identity(int fd,
{
struct stat st_now;
int saved_errno = errno;
+ errno = 0;
if( if_err(fd < 0 || expected == NULL, EFAULT) ||
if_err_sys(fstat(fd, &st_now)) ||
if_err(st_now.st_dev != expected->st_dev ||
st_now.st_ino != expected->st_ino, ESTALE))
- return -1;
+ return with_fallback_errno(EIO);
if (out != NULL)
*out = st_now;
- errno = saved_errno;
+ reset_caller_errno(0);
return 0;
}
@@ -908,45 +837,35 @@ fd_verify_dir_identity(int fd,
{
struct stat st_now;
int saved_errno = errno;
+ errno = 0;
if (if_err(fd < 0 || expected == NULL, EFAULT) ||
- if_err_sys(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 (!S_ISDIR(st_now.st_mode)) {
- errno = ENOTDIR;
- return -1;
- }
+ if_err_sys(fstat(fd, &st_now) < 0) ||
+ if_err(st_now.st_dev != expected->st_dev, ESTALE) ||
+ if_err(st_now.st_ino != expected->st_ino, ESTALE) ||
+ if_err(!S_ISDIR(st_now.st_mode), ENOTDIR))
+ goto err;
- errno = saved_errno;
+ reset_caller_errno(0);
return 0;
+err:
+ return with_fallback_errno(EIO);
}
int
is_owner(struct stat *st)
{
- if (st == NULL) {
-
- errno = EFAULT;
- return -1;
- }
+ int saved_errno = errno;
+ errno = 0;
-#if ALLOW_ROOT_OVERRIDE
- if (st->st_uid != geteuid() && /* someone else's file */
- geteuid() != 0) { /* override for root */
-#else
- if (st->st_uid != geteuid()) { /* someone else's file */
-#endif /* and no root override */
- errno = EPERM;
- return -1;
- }
+ if (if_err(st == NULL, EFAULT) ||
+ if_err(st->st_uid != geteuid() /* someone else's file */
+#if defined(ALLOW_ROOT_OVERRIDE) && ((ALLOW_ROOT_OVERRIDE) > 0)
+ && geteuid() != 0 /* override for root */
+#endif
+ , EPERM)) return with_fallback_errno(EIO);
+ reset_caller_errno(0);
return 0;
}
@@ -955,6 +874,7 @@ lock_file(int fd, int flags)
{
struct flock fl;
int saved_errno = errno;
+ errno = 0;
if (if_err(fd < 0, EBADF) ||
if_err(flags < 0, EINVAL))
@@ -972,9 +892,9 @@ lock_file(int fd, int flags)
if (fcntl(fd, F_SETLK, &fl) == -1)
goto err_lock_file;
- saved_errno = errno;
+ reset_caller_errno(0);
return 0;
err_lock_file:
- return set_errno(saved_errno, EIO);
+ return with_fallback_errno(EIO);
}
diff --git a/util/libreboot-utils/lib/num.c b/util/libreboot-utils/lib/num.c
index e13a8853..ad349173 100644
--- a/util/libreboot-utils/lib/num.c
+++ b/util/libreboot-utils/lib/num.c
@@ -28,8 +28,6 @@
unsigned short
hextonum(char ch_s)
{
- int saved_errno = errno;
-
unsigned char ch;
size_t rval;
@@ -43,8 +41,8 @@ hextonum(char ch_s)
if ((unsigned int)(ch - 'a') <= 5)
return ch - 'a' + 10;
- if (ch == '?' || ch == 'x')
- return rsize(16); /* <-- with rejection sampling! */
+ if (ch == '?' || ch == 'x') /* random */
+ return (short)rsize(16); /* <-- with rejection sampling! */
return 16;
}
diff --git a/util/libreboot-utils/lib/rand.c b/util/libreboot-utils/lib/rand.c
index 20dc33cd..adfad3d7 100644
--- a/util/libreboot-utils/lib/rand.c
+++ b/util/libreboot-utils/lib/rand.c
@@ -127,6 +127,7 @@ void
rset(void *buf, size_t n)
{
int saved_errno = errno;
+ errno = 0;
if (if_err(buf == NULL, EFAULT))
goto err;
@@ -140,7 +141,6 @@ rset(void *buf, size_t n)
((USE_URANDOM) > 0))
arc4random_buf(buf, n);
- goto out;
#else
size_t off = 0;
@@ -166,7 +166,7 @@ retry_rand:
#endif
if (rc < 0)
- goto err;
+ goto err; /* syscall fehler */
if (rc == 0)
goto err; /* prevent infinite loop on fatal err */
@@ -180,16 +180,15 @@ retry_rand:
#endif
#endif
-out:
- errno = saved_errno;
+ reset_caller_errno(0);
return;
err:
#if defined(USE_URANDOM) && \
((USE_URANDOM) > 0)
close_on_eintr(&fd);
#endif
- err_exit(ECANCELED,
- "Randomisation failure, possibly unsupported in your kernel");
+ (void) with_fallback_errno(ECANCELED);
+ err_exit(errno, "Randomisierungsfehler");
exit(EXIT_FAILURE);
}
#endif
diff --git a/util/libreboot-utils/lib/string.c b/util/libreboot-utils/lib/string.c
index ad11d29d..ce54a524 100644
--- a/util/libreboot-utils/lib/string.c
+++ b/util/libreboot-utils/lib/string.c
@@ -50,6 +50,7 @@ pagesize(void)
{
static long rval = 0;
static int set = 0;
+ int saved_errno = 0;
if (!set) {
if ((rval = sysconf(_SC_PAGESIZE)) < 0)
@@ -57,6 +58,7 @@ pagesize(void)
set = 1;
}
+ reset_caller_errno(0);
return rval;
}
@@ -92,7 +94,9 @@ smalloc(char **buf, size_t size)
void *
vmalloc(void **buf, size_t size)
{
+ int saved_errno = errno;
void *rval = NULL;
+ errno = 0;
if (size >= SIZE_MAX - 1)
err_exit(EOVERFLOW, "integer overflow in vmalloc");
@@ -116,6 +120,7 @@ vmalloc(void **buf, size_t size)
if ((rval = malloc(size)) == NULL)
err_exit(errno, "malloc fail in vmalloc");
+ reset_caller_errno(0);
return *buf = rval;
}
@@ -131,6 +136,7 @@ scmp(const char *a,
size_t wa;
size_t wb;
int saved_errno = errno;
+ errno = 0;
if (if_err(a == NULL || b == NULL || rval == NULL, EFAULT))
goto err;
@@ -171,14 +177,14 @@ scmp(const char *a,
goto out;
err:
- (void) set_errno(saved_errno, EFAULT);
+ (void) with_fallback_errno(EFAULT);
if (rval != NULL)
*rval = -1;
err_exit(errno, "scmp");
return -1;
out:
- errno = saved_errno;
+ reset_caller_errno(0);
return *rval;
}
@@ -215,13 +221,14 @@ slen(const char *s,
size_t i = 0;
size_t w;
size_t j;
+ errno = 0;
if (if_err(s == NULL || rval == NULL, EFAULT))
goto err;
for ( ; ((uintptr_t)(s + i) % sizeof(size_t)) != 0; i++) {
- if (i >= maxlen)
+ if (if_err(i >= maxlen, EOVERFLOW))
goto err;
if (s[i] == '\0') {
*rval = i;
@@ -252,14 +259,14 @@ slen(const char *s,
}
err:
- (void) set_errno(saved_errno, EFAULT);
+ (void) with_fallback_errno(EFAULT);
if (rval != NULL)
*rval = 0;
err_exit(errno, "slen"); /* abort */
return 0; /* gcc15 is happy */
out:
- errno = saved_errno;
+ reset_caller_errno(0);
return *rval;
}
@@ -273,6 +280,7 @@ sdup(const char *s,
size_t i = 0;
char *out = NULL;
int saved_errno = errno;
+ errno = 0;
if (if_err(dest == NULL || *dest != NULL || s == NULL, EFAULT))
goto err;
@@ -326,12 +334,12 @@ err:
if (dest != NULL)
*dest = NULL;
- (void) set_errno(saved_errno, EFAULT);
+ (void) with_fallback_errno(EFAULT);
err_exit(errno, "sdup");
return NULL;
out:
- errno = saved_errno;
+ reset_caller_errno(0);
return *dest;
}
@@ -345,6 +353,7 @@ scatn(ssize_t sc, const char **sv,
char *rcur = NULL;
char *rtmp = NULL;
size_t i;
+ errno = 0;
if (if_err(sc < 2, EINVAL) ||
if_err(sv == NULL, EFAULT) ||
@@ -368,7 +377,7 @@ scatn(ssize_t sc, const char **sv,
rtmp = NULL;
}
- errno = saved_errno;
+ reset_caller_errno(0);
*rval = final;
return *rval;
err:
@@ -376,7 +385,7 @@ err:
free_and_set_null(&rtmp);
free_and_set_null(&final);
- (void) set_errno(saved_errno, EFAULT);
+ (void) with_fallback_errno(EFAULT);
err_exit(errno, "scatn");
return NULL;
@@ -391,6 +400,7 @@ scat(const char *s1, const char *s2,
size_t size2;
char *rval = NULL;
int saved_errno = errno;
+ errno = 0;
if (if_err(dest == NULL || *dest != NULL, EFAULT))
goto err;
@@ -408,11 +418,11 @@ scat(const char *s1, const char *s2,
memcpy(rval + size1, s2, size2);
*(rval + size1 + size2) = '\0';
+ reset_caller_errno(0);
*dest = rval;
- errno = saved_errno;
return *dest;
err:
- (void) set_errno(saved_errno, EINVAL);
+ (void) with_fallback_errno(EINVAL);
if (dest != NULL)
*dest = NULL;
err_exit(errno, "scat");
@@ -431,6 +441,7 @@ dcat(const char *s, size_t n,
char *rval1 = NULL;
char *rval2 = NULL;
int saved_errno = errno;
+ errno = 0;
if (if_err(dest1 == NULL || dest2 == NULL, EFAULT))
goto err;
@@ -450,7 +461,7 @@ dcat(const char *s, size_t n,
*dest1 = rval1;
*dest2 = rval2;
- errno = saved_errno;
+ reset_caller_errno(0);
return;
err:
@@ -459,7 +470,7 @@ err:
free_and_set_null(&rval1);
free_and_set_null(&rval2);
- (void) set_errno(saved_errno, EINVAL);
+ (void) with_fallback_errno(EINVAL);
err_exit(errno, "dcat");
}
@@ -477,6 +488,7 @@ vcmp(const void *s1, const void *s2, size_t n)
const unsigned char *x;
const unsigned char *y;
+ errno = 0;
if (if_err(s1 == NULL || s2 == NULL, EFAULT))
err_exit(EFAULT, "vcmp: null input");
@@ -497,7 +509,7 @@ vcmp(const void *s1, const void *s2, size_t n)
if (x[i] != y[i])
return (int)x[i] - (int)y[i];
- errno = saved_errno;
+ reset_caller_errno(0);
return 0;
}
@@ -507,9 +519,9 @@ vcmp(const void *s1, const void *s2, size_t n)
* under error condition.
*/
int
-set_errno(int saved_errno, int fallback)
+with_fallback_errno(int fallback)
{
- if (errno == saved_errno)
+ if (!errno)
errno = fallback;
return -1;
}
@@ -525,7 +537,8 @@ err_exit(int nvm_errval, const char *msg, ...)
func_t err_cleanup = errhook(NULL);
err_cleanup();
- errno = saved_errno;
+ reset_caller_errno(0);
+ saved_errno = errno;
if (!errno)
saved_errno = errno = ECANCELED;
@@ -536,6 +549,7 @@ err_exit(int nvm_errval, const char *msg, ...)
vfprintf(stderr, msg, args);
va_end(args);
+ errno = saved_errno;
fprintf(stderr, ": %s\n", strerror(errno));
exit(EXIT_FAILURE);
@@ -615,11 +629,12 @@ xpledgex(const char *promises, const char *execpromises)
{
int saved_errno = errno;
(void) promises, (void) execpromises, (void) saved_errno;
+ errno = 0;
#ifdef __OpenBSD__
if (pledge(promises, execpromises) == -1)
err_exit(errno, "pledge");
#endif
- errno = saved_errno;
+ reset_caller_errno(0);
return 0;
}
int
@@ -627,10 +642,11 @@ xunveilx(const char *path, const char *permissions)
{
int saved_errno = errno;
(void) path, (void) permissions, (void) saved_errno;
+ errno = 0;
#ifdef __OpenBSD__
if (pledge(promises, execpromises) == -1)
err_exit(errno, "pledge");
#endif
- errno = saved_errno;
+ reset_caller_errno(0);
return 0;
}
diff --git a/util/libreboot-utils/lottery.c b/util/libreboot-utils/lottery.c
index 9906ed11..1648cbc7 100644
--- a/util/libreboot-utils/lottery.c
+++ b/util/libreboot-utils/lottery.c
@@ -37,7 +37,6 @@ main(int argc, char **argv)
fprintf(stderr, "\n%s\n", same ? "You win!" : "You lose!");
- printf("%lu\n", PATH_MAX);
return same ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/util/libreboot-utils/mkhtemp.c b/util/libreboot-utils/mkhtemp.c
index f7480ed6..65e637e9 100644
--- a/util/libreboot-utils/mkhtemp.c
+++ b/util/libreboot-utils/mkhtemp.c
@@ -1,11 +1,13 @@
-/* SPDX-License-Identifier: MIT
- * Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
- *
+/* SPDX-License-Identifier: MIT ( >:3 )
+ * Copyright (c) 2026 Leah Rowe <leah@libreboot.org> /| |\
+ * / \
* Hardened mktemp (mkhtemp!)
*
* WORK IN PROGRESS (proof of concept), or, v0.0000001
* DO NOT PUT THIS IN YOUR LINUX DISTRO YET.
*
+ * In other words: for reference only -- PATCHES WELCOME!
+ *
* I will remove this notice when the code is mature, and
* probably contact several of your projects myself.
*
@@ -139,8 +141,4 @@ static void
exit_cleanup(void)
{
return;
-}/*
-
- ( >:3 )
- /| |\
- / \ */
+}
diff --git a/util/libreboot-utils/nvmutil.c b/util/libreboot-utils/nvmutil.c
index ec41371f..3102bd50 100644
--- a/util/libreboot-utils/nvmutil.c
+++ b/util/libreboot-utils/nvmutil.c
@@ -1,6 +1,6 @@
-/* SPDX-License-Identifier: MIT
- * Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org>
- *
+/* SPDX-License-Identifier: MIT ( >:3 )
+ * Copyright (c) 2022-2026 Leah Rowe <leah@libreboot.org> /| |\
+ * / \
* This tool lets you modify Intel GbE NVM (Gigabit Ethernet
* Non-Volatile Memory) images, e.g. change the MAC address.
* These images configure your Intel Gigabit Ethernet adapter.