Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
Leah Rowe
2026-03-26 04:25:51 +00:00
parent c2c24b7a24
commit 5ea7fe22b2
4 changed files with 31 additions and 115 deletions
+1 -1
View File
@@ -83,7 +83,7 @@ int fchmod(int fd, mode_t mode);
#endif #endif
#ifndef REAL_POS_IO #ifndef REAL_POS_IO
#define REAL_POS_IO 1 #define REAL_POS_IO 0
#endif #endif
#ifndef LOOP_EAGAIN #ifndef LOOP_EAGAIN
+19 -33
View File
@@ -203,6 +203,7 @@ rw_file_exact(int fd, unsigned char *mem, size_t nrw,
size_t retries_on_zero; size_t retries_on_zero;
int saved_errno = errno; int saved_errno = errno;
errno = 0;
rval = 0; rval = 0;
@@ -294,6 +295,11 @@ err_rw_file_exact:
* a change was detected, assuming * a change was detected, assuming
* nothing else is touching it now * nothing else is touching it now
* off_reset 0: never reset if changed * off_reset 0: never reset if changed
*
* REAL_POS_IO is enabled by default in common.h
* and the fallback version was written for fun.
* You should just use the real one (REAL_POS_IO 1),
* since it is generally more reliable.
*/ */
ssize_t ssize_t
@@ -313,6 +319,7 @@ prw(int fd, void *mem, size_t nrw,
off_t off_last; off_t off_last;
#endif #endif
int saved_errno = errno; int saved_errno = errno;
errno = 0;
if (io_args(fd, mem, nrw, off, rw_type) if (io_args(fd, mem, nrw, off, rw_type)
== -1) == -1)
@@ -542,7 +549,7 @@ lseek_on_eintr(int fd, off_t off, int whence,
} }
/* two functions that reduce sloccount by /* two functions that reduce sloccount by
* two hundred lines... no, now three. */ * two hundred lines */
int int
if_err(int condition, int errval) if_err(int condition, int errval)
{ {
@@ -554,13 +561,6 @@ if_err(int condition, int errval)
return 1; return 1;
} }
/* technically pointless, but stylistically
* pleasing alongside if_err chains.
* use this one for syscalls that are
* expected to set errno
* also use it for non-system calls
* that act like them, e.g. prw() or
* rw_write_exact() */
int int
if_err_sys(int condition) if_err_sys(int condition)
{ {
@@ -616,10 +616,8 @@ close_warn(int *fd, char *s)
return 0; return 0;
} }
/* TODO: remove this. giant liability. /* TODO: remove this, and just check
make close calls always err instead, * err on every close. */
when they fail. otherwise we hide bugs!
*/
void void
close_no_err(int *fd) close_no_err(int *fd)
{ {
@@ -636,7 +634,6 @@ close_no_err(int *fd)
/* TODO: make fd a pointer insttead /* TODO: make fd a pointer insttead
and automatically reset -1 here */ and automatically reset -1 here */
/* BUT DO NOT reset -1 on error */
int int
close_on_eintr(int fd) close_on_eintr(int fd)
{ {
@@ -683,11 +680,10 @@ fs_rename_at(int olddirfd, const char *old,
return renameat(olddirfd, old, newdirfd, new); return renameat(olddirfd, old, newdirfd, new);
} }
/* secure open, based on /* secure open, based on relative path to root
* relative path to root
* *
* always a fixed fd for / * always a fixed fd for / see: rootfs()
* see: rootfs() * and fs_resolve_at()
*/ */
int int
fs_open(const char *path, int flags) fs_open(const char *path, int flags)
@@ -702,12 +698,8 @@ fs_open(const char *path, int flags)
return fs_resolve_at(fs->rootfd, path + 1, flags); return fs_resolve_at(fs->rootfd, path + 1, flags);
} }
/* singleton function /* singleton function that returns a fixed descriptor of /
* that returns a fixed * used throughout, for repeated integrity checks
* descriptor of /
*
* used throughout, for
* repeated integrity checks
*/ */
struct filesystem * struct filesystem *
rootfs(void) rootfs(void)
@@ -729,8 +721,7 @@ rootfs(void)
return &global_fs; return &global_fs;
} }
/* filesystem sandboxing. /* filesystem sandboxing in userspace
* (in userspace)
*/ */
int int
fs_resolve_at(int dirfd, const char *path, int flags) fs_resolve_at(int dirfd, const char *path, int flags)
@@ -769,10 +760,9 @@ fs_resolve_at(int dirfd, const char *path, int flags)
if (nextfd < 0) if (nextfd < 0)
goto err; goto err;
/* close previous fd IF it is not the original input */ /* close previous fd if not the original input */
if (curfd != dirfd) { if (curfd != dirfd)
(void) close_on_eintr(curfd); (void) close_on_eintr(curfd);
}
curfd = nextfd; curfd = nextfd;
nextfd = -1; nextfd = -1;
@@ -921,9 +911,6 @@ fs_dirname_basename(const char *path,
/* portable wrapper for use of openat2 on linux, /* portable wrapper for use of openat2 on linux,
* with fallback for others e.g. openbsd * with fallback for others e.g. openbsd
*
* BONUS: arg checks
* TODO: consider EINTR/EAGAIN retry loop
*/ */
int int
openat2p(int dirfd, const char *path, openat2p(int dirfd, const char *path,
@@ -974,8 +961,7 @@ retry:
} }
int int
mkdirat_on_eintr( /* <-- say that 10 times to please the demon */ mkdirat_on_eintr(int dirfd,
int dirfd,
const char *path, mode_t mode) const char *path, mode_t mode)
{ {
int saved_errno = errno; int saved_errno = errno;
+8 -44
View File
@@ -51,22 +51,6 @@ new_tmpdir(int *fd, char **path, char *tmpdir,
tmpdir, template); tmpdir, template);
} }
/* note: tmpdir is an override of TMPDIR or /tmp or /var/tmp */
/* WARNING:
* on error, *path (at **path) may be
NULL, or if the error pertains to
an actual TMPDIR, set. if set, it
will be using *static* memory and
must not be freed. on success,
a pointer to heap memory is set
instead.
* see:
* env_tmpdir()
* this is for error reports if e.g.
* TMPDIR isn't found (but is set)
* if TMPDIR isn't set, it will
* default to /tmp or /var/tmp
*/
int int
new_tmp_common(int *fd, char **path, int type, new_tmp_common(int *fd, char **path, int type,
char *tmpdir, const char *template) char *tmpdir, const char *template)
@@ -443,20 +427,8 @@ world_writeable_and_sticky(
goto sticky_hell; goto sticky_hell;
} }
/* must be fully executable /* all of these checks are probably
* by everyone, or openat2 * redundant (execution rights)
* becomes unreliable**
*
* TODO: loosen these, as a toggle.
* execution rights isn't
* really a requirement for
* TMPDIR, except maybe search,
* but this function will be
* generalised at some point
* for use in other tools
* besides just mkhtemp.
*/
/*
if (!(st.st_mode & S_IXUSR) || if (!(st.st_mode & S_IXUSR) ||
!(st.st_mode & S_IXGRP) || !(st.st_mode & S_IXGRP) ||
!(st.st_mode & S_IXOTH)) { !(st.st_mode & S_IXOTH)) {
@@ -473,7 +445,7 @@ world_writeable_and_sticky(
if (bypass_all_sticky_checks) if (bypass_all_sticky_checks)
goto sticky_heaven; /* normal == no security */ goto sticky_heaven; /* normal == no security */
/* unhinged leah mode: /* extremely not-libc mode:
*/ */
if (st.st_mode & S_IWOTH) { /* world writeable */ if (st.st_mode & S_IWOTH) { /* world writeable */
@@ -488,9 +460,7 @@ world_writeable_and_sticky(
goto sticky_hell; /* not sticky */ goto sticky_hell; /* not sticky */
} }
/* if anyone even looks at you funny, drop /* for good measure */
* everything on the floor and refuse to function
*/
if (faccessat(dirfd, ".", X_OK, AT_EACCESS) < 0) if (faccessat(dirfd, ".", X_OK, AT_EACCESS) < 0)
goto sticky_hell; goto sticky_hell;
@@ -503,7 +473,6 @@ world_writeable_and_sticky(
goto sticky_hell; /* heaven visa denied */ goto sticky_hell; /* heaven visa denied */
sticky_heaven: sticky_heaven:
/* i like the one in hamburg better */
close_no_err(&dirfd); close_no_err(&dirfd);
errno = saved_errno; errno = saved_errno;
@@ -515,10 +484,7 @@ sticky_hell:
if (errno == saved_errno) if (errno == saved_errno)
errno = EPERM; errno = EPERM;
saved_errno = errno;
close_no_err(&dirfd); close_no_err(&dirfd);
errno = saved_errno; errno = saved_errno;
return 0; return 0;
@@ -909,11 +875,9 @@ retry_rand:
/* WARNING: **ONCE** per file. /* WARNING: **ONCE** per file.
* *
* !!! DO NOT RUN TWICE PER FILE. BEWARE OF THE DEMON !!! * some of these checks will trip up
* watch out for spikes! * if you do them twice; all of them
*/ * only need to be done once anyway.
/* TODO: bad_flags can be negative, and is
* ignored if it is. should we err instead?
*/ */
int secure_file(int *fd, int secure_file(int *fd,
struct stat *st, struct stat *st,
@@ -945,7 +909,7 @@ int secure_file(int *fd,
if (check_seek) { /***********/ if (check_seek) { /***********/
if (lseek(*fd, 0, SEEK_CUR) == (off_t)-1) if (lseek(*fd, 0, SEEK_CUR) == (off_t)-1)
goto err_demons; goto err_demons;
} /* don't release the demon */ } /* don't release the demon! */
if (if_err(st->st_nlink != 1, ELOOP) || if (if_err(st->st_nlink != 1, ELOOP) ||
if_err(st->st_uid != geteuid() && geteuid() != 0, EPERM) || if_err(st->st_uid != geteuid() && geteuid() != 0, EPERM) ||
+3 -37
View File
@@ -1,12 +1,8 @@
/* SPDX-License-Identifier: MIT /* SPDX-License-Identifier: MIT
* Copyright (c) 2026 Leah Rowe <leah@libreboot.org> * Copyright (c) 2026 Leah Rowe <leah@libreboot.org>
* *
* Numerical functions. * Non-randomisation-related numerical functions.
* NOTE: randomness was moved to rand.c * For rand functions, see: rand.c
*/
/*
TODO: properly handle errno in this file
*/ */
#ifdef __OpenBSD__ #ifdef __OpenBSD__
@@ -27,44 +23,14 @@ TODO: properly handle errno in this file
#include "../include/common.h" #include "../include/common.h"
/* TODO:
* make this and errno handling more
* flexible
in particular:
hextonum could be modified to
write into a buffer instead,
with the converted numbers,
of an arbitrary length
*/
unsigned short unsigned short
hextonum(char ch_s) hextonum(char ch_s)
{ {
int saved_errno = errno; int saved_errno = errno;
/* rlong() can return error,
but preserves errno if no
error. we need to detect
this because it handles
/dev/urandom sometimes
therefore, if it's zero
at start, we know if there
was an err at the end, by
return value zero, if errno
was set; this is technically
valid, since zero is also
a valid random number!
it's an edge case that i had
to fix. i'll rewrite the code
better later. for now, it
should be ok.
*/
errno = 0;
unsigned char ch; unsigned char ch;
size_t rval; size_t rval;
errno = 0;
ch = (unsigned char)ch_s; ch = (unsigned char)ch_s;