mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-03-25 13:29:03 +02:00
@@ -324,6 +324,12 @@ size_t conv_argv_part_num(const char *part_str);
|
||||
*/
|
||||
|
||||
void open_gbe_file(void);
|
||||
int fd_verify_regular(int fd,
|
||||
const struct stat *expected,
|
||||
struct stat *out);
|
||||
int fd_verify_identity(int fd,
|
||||
const struct stat *expected,
|
||||
struct stat *out);
|
||||
int is_owner(struct stat *st);
|
||||
int lock_file(int fd, int flags);
|
||||
int same_file(int fd, struct stat *st_old, int check_size);
|
||||
|
||||
@@ -56,13 +56,8 @@ same_file(int fd, struct stat *st_old,
|
||||
if (fstat(fd, &st) == -1)
|
||||
goto err_same_file;
|
||||
|
||||
if (st.st_dev != st_old->st_dev ||
|
||||
st.st_ino != st_old->st_ino ||
|
||||
!S_ISREG(st.st_mode)) {
|
||||
|
||||
errno = ESTALE;
|
||||
if (fd_verify_regular(fd, st_old, &st) < 0)
|
||||
goto err_same_file;
|
||||
}
|
||||
|
||||
if (check_size &&
|
||||
st.st_size != st_old->st_size)
|
||||
@@ -90,6 +85,17 @@ err_same_file:
|
||||
make it return, and handle the return value/errno
|
||||
|
||||
(this could return e.g. EINTR)
|
||||
|
||||
TODO: this function is not used by mkhtemp, nor will
|
||||
it probably be, it's currently used by nvmutil,
|
||||
for opening intel gbe nvm config files. i can
|
||||
probably remove it though and unify witth some
|
||||
of the verification code now used for mkhtemp
|
||||
|
||||
TODO: and don't abort. return -1. and handle in the caller.
|
||||
|
||||
minor obstacle: the mkhtemp code always requires absolute
|
||||
paths, whereas the gbe editor takes relative paths.
|
||||
*/
|
||||
void
|
||||
xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
|
||||
@@ -259,15 +265,12 @@ new_tmpfile(int *fd, char **path)
|
||||
|
||||
size_t dirlen;
|
||||
size_t destlen;
|
||||
size_t baselen;
|
||||
char *dest = NULL; /* final path */
|
||||
int saved_errno = errno;
|
||||
int dirfd = -1;
|
||||
const char *fname = NULL;
|
||||
|
||||
struct stat st_dir_initial;
|
||||
char *dir = NULL;
|
||||
char *base = NULL;
|
||||
|
||||
if (path == NULL || fd == NULL) {
|
||||
errno = EFAULT;
|
||||
@@ -294,6 +297,10 @@ new_tmpfile(int *fd, char **path)
|
||||
|
||||
if (slen(tmpdir, maxlen, &dirlen) < 0)
|
||||
goto err_new_tmpfile;
|
||||
if (*tmpdir == '\0')
|
||||
goto err_new_tmpfile;
|
||||
if (*tmpdir != '/')
|
||||
goto err_new_tmpfile;
|
||||
|
||||
/* using sizeof (not slen) adds an extra byte,
|
||||
* useful because we either want '.' or '/'
|
||||
@@ -336,10 +343,6 @@ new_tmpfile(int *fd, char **path)
|
||||
(void) close_on_eintr(dirfd);
|
||||
dirfd = -1;
|
||||
}
|
||||
if (dir != NULL) {
|
||||
free(dir);
|
||||
dir = NULL;
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
|
||||
@@ -371,11 +374,6 @@ err_new_tmpfile:
|
||||
*fd = -1;
|
||||
}
|
||||
|
||||
if (dir != NULL) {
|
||||
free(dir);
|
||||
dir = NULL;
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
|
||||
return -1;
|
||||
@@ -694,6 +692,7 @@ mkhtemp(int *fd,
|
||||
size_t max_len = 4096;
|
||||
#endif
|
||||
int r;
|
||||
char *end;
|
||||
|
||||
if (fd == NULL ||
|
||||
template == NULL ||
|
||||
@@ -736,14 +735,11 @@ mkhtemp(int *fd,
|
||||
}
|
||||
|
||||
/* count trailing X */
|
||||
{
|
||||
char *end = template + len;
|
||||
end = template + len;
|
||||
while (end > template && *--end == 'X')
|
||||
xc++;
|
||||
|
||||
while (end > template && *--end == 'X')
|
||||
xc++;
|
||||
}
|
||||
|
||||
if (xc < 6 || xc > len) {
|
||||
if (xc < 12 || xc > len) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@@ -784,9 +780,11 @@ mkhtemp(int *fd,
|
||||
fd,
|
||||
st);
|
||||
|
||||
/* DoS mitigation; add jitter delay (0–1023 µs) */
|
||||
if (r != 1 && retries >= MKHTEMP_SPIN_THRESHOLD)
|
||||
usleep((useconds_t)rlong() & 0x3FF);
|
||||
if (r != 1) {
|
||||
if (retries >= MKHTEMP_SPIN_THRESHOLD)
|
||||
usleep((useconds_t)rlong() & 0x3FF);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* success: copy final name back */
|
||||
memcpy(template + len - fname_len,
|
||||
@@ -825,17 +823,18 @@ mkhtemp_try_create(int dirfd,
|
||||
struct stat st_open;
|
||||
int saved_errno = errno;
|
||||
int close_errno;
|
||||
int rval = -1;
|
||||
|
||||
if (mkhtemp_fill_random(p, xc) < 0)
|
||||
return -1;
|
||||
goto err;
|
||||
|
||||
if (fstat(dirfd, &st_dir_now) < 0)
|
||||
return -1;
|
||||
goto err;
|
||||
|
||||
if (st_dir_now.st_dev != st_dir_initial->st_dev ||
|
||||
st_dir_now.st_ino != st_dir_initial->st_ino) {
|
||||
errno = ESTALE;
|
||||
return -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
*fd = openat2p(dirfd, fname_copy,
|
||||
@@ -843,40 +842,53 @@ mkhtemp_try_create(int dirfd,
|
||||
O_NOFOLLOW | O_CLOEXEC | O_NOCTTY,
|
||||
0600);
|
||||
|
||||
if (*fd >= 0) {
|
||||
if (*fd < 0) {
|
||||
if (errno == EEXIST ||
|
||||
errno == EINTR ||
|
||||
errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
errno == ETXTBSY) {
|
||||
|
||||
if (fstat(*fd, &st_open) < 0)
|
||||
return -1;
|
||||
|
||||
if (fstat(dirfd, &st_dir_now) < 0)
|
||||
return -1;
|
||||
|
||||
if (st_dir_now.st_dev != st_dir_initial->st_dev ||
|
||||
st_dir_now.st_ino != st_dir_initial->st_ino) {
|
||||
|
||||
close_errno = errno;
|
||||
(void) close_on_eintr(*fd);
|
||||
errno = close_errno;
|
||||
|
||||
errno = ESTALE;
|
||||
return -1;
|
||||
rval = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (secure_file(fd, st, &st_open, O_APPEND, 1, 1, 0600) < 0)
|
||||
return -1;
|
||||
|
||||
errno = saved_errno;
|
||||
return 1; /* success */
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (errno == EEXIST ||
|
||||
errno == EINTR ||
|
||||
errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
errno == ETXTBSY)
|
||||
return 0; /* retry */
|
||||
/* fd is now live */
|
||||
|
||||
return -1; /* fatal */
|
||||
if (fstat(*fd, &st_open) < 0)
|
||||
goto err;
|
||||
|
||||
if (fstat(dirfd, &st_dir_now) < 0)
|
||||
goto err;
|
||||
|
||||
if (st_dir_now.st_dev != st_dir_initial->st_dev ||
|
||||
st_dir_now.st_ino != st_dir_initial->st_ino) {
|
||||
errno = ESTALE;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (secure_file(fd, st, &st_open,
|
||||
O_APPEND, 1, 1, 0600) < 0)
|
||||
goto err;
|
||||
|
||||
errno = saved_errno;
|
||||
rval = 1;
|
||||
goto out;
|
||||
|
||||
err:
|
||||
close_errno = errno;
|
||||
|
||||
if (fd != NULL && *fd >= 0) {
|
||||
(void) close_on_eintr(*fd);
|
||||
*fd = -1;
|
||||
}
|
||||
|
||||
errno = close_errno;
|
||||
rval = -1;
|
||||
out:
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
@@ -985,21 +997,17 @@ int secure_file(int *fd,
|
||||
}
|
||||
}
|
||||
|
||||
if (fstat(*fd, st) == -1)
|
||||
if (fstat(*fd, &st_now) == -1)
|
||||
goto err_secure_file;
|
||||
|
||||
/* verify inode/device stability */
|
||||
if (expected != NULL) {
|
||||
|
||||
if (st_now.st_dev != expected->st_dev ||
|
||||
st_now.st_ino != expected->st_ino) {
|
||||
|
||||
st_now.st_ino != expected->st_ino) {
|
||||
errno = ESTALE;
|
||||
goto err_secure_file;
|
||||
}
|
||||
}
|
||||
|
||||
/* now copy to caller */
|
||||
*st = st_now;
|
||||
|
||||
if (!S_ISREG(st->st_mode)) {
|
||||
@@ -1007,6 +1015,9 @@ int secure_file(int *fd,
|
||||
goto err_secure_file;
|
||||
}
|
||||
|
||||
if (fd_verify_regular(*fd, expected, st) < 0)
|
||||
goto err_secure_file;
|
||||
|
||||
if (check_seek) {
|
||||
|
||||
/* check if it's seekable */
|
||||
@@ -1057,6 +1068,51 @@ err_secure_file:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
fd_verify_regular(int fd,
|
||||
const struct stat *expected,
|
||||
struct stat *out)
|
||||
{
|
||||
if (fd_verify_identity(fd, expected, out) < 0)
|
||||
return -1;
|
||||
|
||||
if (!S_ISREG(out->st_mode)) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0; /* regular file */
|
||||
}
|
||||
|
||||
int
|
||||
fd_verify_identity(int fd,
|
||||
const struct stat *expected,
|
||||
struct stat *out)
|
||||
{
|
||||
struct stat st_now;
|
||||
int saved_errno = errno;
|
||||
|
||||
if (fd < 0 || expected == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (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 (out != NULL)
|
||||
*out = st_now;
|
||||
|
||||
errno = saved_errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
is_owner(struct stat *st)
|
||||
{
|
||||
@@ -1812,7 +1868,7 @@ fs_open(const char *path, int flags)
|
||||
}
|
||||
|
||||
fs = rootfs();
|
||||
if (!fs)
|
||||
if (fs == NULL)
|
||||
return -1;
|
||||
|
||||
rel = path + 1;
|
||||
|
||||
Reference in New Issue
Block a user