mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-03-25 13:29:03 +02:00
WIP dir support (also demons)
Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
@@ -36,6 +36,13 @@
|
||||
|
||||
int fchmod(int fd, mode_t mode);
|
||||
|
||||
#define MKHTEMP_RETRY_MAX 512
|
||||
#define MKHTEMP_SPIN_THRESHOLD 32
|
||||
|
||||
#define MKHTEMP_FILE 0
|
||||
#define MKHTEMP_DIR 1
|
||||
|
||||
|
||||
/* if 1: on operations that
|
||||
* check ownership, always
|
||||
* permit root to access even
|
||||
@@ -493,10 +500,11 @@ static int mkhtemp_try_create(int dirfd,
|
||||
char *p,
|
||||
size_t xc,
|
||||
int *fd,
|
||||
struct stat *st);
|
||||
struct stat *st,
|
||||
int type);
|
||||
int mkhtemp(int *fd, struct stat *st,
|
||||
char *template, int dirfd, const char *fname,
|
||||
struct stat *st_dir_initial);
|
||||
struct stat *st_dir_initial, int type);
|
||||
int mkhtemp_fill_random(char *p, size_t xc);
|
||||
int world_writeable_and_sticky(const char *s,
|
||||
int sticky_allowed, int always_sticky);
|
||||
@@ -529,6 +537,8 @@ int fs_dirname_basename(const char *path,
|
||||
char **dir, char **base, int allow_relative);
|
||||
int openat2p(int dirfd, const char *path,
|
||||
int flags, mode_t mode);
|
||||
int mkdirat_on_eintr(int dirfd,
|
||||
const char *pathname, mode_t mode);
|
||||
|
||||
/* asserts */
|
||||
|
||||
|
||||
@@ -30,9 +30,6 @@
|
||||
/* check that a file changed
|
||||
*/
|
||||
|
||||
#define MKHTEMP_RETRY_MAX 512
|
||||
#define MKHTEMP_SPIN_THRESHOLD 32
|
||||
|
||||
int
|
||||
same_file(int fd, struct stat *st_old,
|
||||
int check_size)
|
||||
@@ -109,7 +106,7 @@ xopen(int *fd_ptr, const char *path, int flags, struct stat *st)
|
||||
if (!S_ISREG(st->st_mode))
|
||||
err(errno, "%s: not a regular file", path);
|
||||
|
||||
if (lseek(*fd_ptr, 0, SEEK_CUR) == (off_t)-1)
|
||||
if (lseek_on_eintr(*fd_ptr, 0, SEEK_CUR, 1, 1) == (off_t)-1)
|
||||
err(errno, "%s: file not seekable", path);
|
||||
}
|
||||
|
||||
@@ -131,6 +128,8 @@ fsync_dir(const char *path)
|
||||
char *slash = NULL;
|
||||
struct stat st = {0};
|
||||
|
||||
int close_errno;
|
||||
|
||||
#if defined(PATH_LEN) && \
|
||||
(PATH_LEN) >= 256
|
||||
maxlen = PATH_LEN;
|
||||
@@ -233,7 +232,9 @@ err_fsync_dir:
|
||||
|
||||
if (dirfd >= 0) {
|
||||
|
||||
close_errno = errno;
|
||||
(void) close_on_eintr(dirfd);
|
||||
errno = close_errno;
|
||||
dirfd = -1;
|
||||
}
|
||||
|
||||
@@ -263,6 +264,7 @@ new_tmpfile(int *fd, char **path)
|
||||
"tmpXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
|
||||
char *tmpdir = NULL;
|
||||
|
||||
int close_errno;
|
||||
size_t dirlen;
|
||||
size_t destlen;
|
||||
char *dest = NULL; /* final path */
|
||||
@@ -275,15 +277,26 @@ new_tmpfile(int *fd, char **path)
|
||||
if (path == NULL || fd == NULL) {
|
||||
errno = EFAULT;
|
||||
goto err_new_tmpfile;
|
||||
} else if (*path == NULL) {
|
||||
errno = EFAULT;
|
||||
goto err_new_tmpfile;
|
||||
}
|
||||
|
||||
if (*fd >= 0) { /* file already opend */
|
||||
/* don't mess with someone's file
|
||||
* if already opened
|
||||
*/
|
||||
if (*fd >= 0) {
|
||||
errno = EEXIST;
|
||||
goto err_new_tmpfile;
|
||||
}
|
||||
|
||||
/* regarding **path:
|
||||
* the pointer (to the pointer)
|
||||
* must nott be null, but we don't
|
||||
* care about the pointer it points
|
||||
* to. you should expect it to be
|
||||
* replaced upon successful return
|
||||
*
|
||||
* (on error, it will not be touched)
|
||||
*/
|
||||
|
||||
*fd = -1;
|
||||
|
||||
#if defined(PERMIT_NON_STICKY_ALWAYS) && \
|
||||
@@ -335,12 +348,15 @@ new_tmpfile(int *fd, char **path)
|
||||
if (fstat(dirfd, &st_dir_initial) < 0)
|
||||
goto err_new_tmpfile;
|
||||
|
||||
*fd = mkhtemp(fd, &st, dest, dirfd, fname, &st_dir_initial);
|
||||
*fd = mkhtemp(fd, &st, dest, dirfd,
|
||||
fname, &st_dir_initial, MKHTEMP_FILE);
|
||||
if (*fd < 0)
|
||||
goto err_new_tmpfile;
|
||||
|
||||
if (dirfd >= 0) {
|
||||
close_errno = errno;
|
||||
(void) close_on_eintr(dirfd);
|
||||
errno = close_errno;
|
||||
dirfd = -1;
|
||||
}
|
||||
|
||||
@@ -363,14 +379,16 @@ err_new_tmpfile:
|
||||
}
|
||||
|
||||
if (dirfd >= 0) {
|
||||
|
||||
close_errno = errno;
|
||||
(void) close_on_eintr(dirfd);
|
||||
errno = close_errno;
|
||||
dirfd = -1;
|
||||
}
|
||||
|
||||
if (*fd >= 0) {
|
||||
|
||||
close_errno = errno;
|
||||
(void) close_on_eintr(*fd);
|
||||
errno = close_errno;
|
||||
*fd = -1;
|
||||
}
|
||||
|
||||
@@ -661,18 +679,53 @@ sticky_hell:
|
||||
|
||||
/* mk(h)temp - hardened mktemp.
|
||||
* like mkstemp, but (MUCH) harder.
|
||||
* TODO:
|
||||
* directory support (currently only
|
||||
* generates files)
|
||||
*
|
||||
* designed to resist TOCTOU attacsk
|
||||
* e.g. directory race / symlink attack
|
||||
*
|
||||
* extremely strict and even implements
|
||||
* some limited userspace-level sandboxing,
|
||||
* similar to openbsd unveil (which you
|
||||
* can also use with this in your program)
|
||||
*
|
||||
* supports both files and directories.
|
||||
* file: type = MKHTEMP_FILE (0)
|
||||
* dir: type = MKHTEMP_DIR (1)
|
||||
*
|
||||
* DESIGN NOTES:
|
||||
*
|
||||
* caller is expected to handle
|
||||
* cleanup e.g. free(), on *st,
|
||||
* *template, *fname (all of the
|
||||
* pointers). ditto fd cleanup.
|
||||
*
|
||||
* some limited cleanup is
|
||||
* performed here, e.g. directory/file
|
||||
* cleanup on error in mkhtemp_try_create
|
||||
*
|
||||
* we only check if these are not NULL,
|
||||
* and the caller is expected to take
|
||||
* care; without too many conditions,
|
||||
* these functions are more flexible,
|
||||
* but some precauttions are taken:
|
||||
*
|
||||
* when used via the function new_tmpfile
|
||||
* or new_tmpdir, thtis is extremely strict,
|
||||
* much stricter than previous mktemp
|
||||
* variants. for example, it is much
|
||||
* stricter about stickiness on world
|
||||
* writeable directories, and it enforces
|
||||
* file ownership under hardened mode
|
||||
* (only lets you touch your own files/dirs)
|
||||
*/
|
||||
|
||||
int
|
||||
mkhtemp(int *fd,
|
||||
struct stat *st,
|
||||
char *template,
|
||||
int dirfd,
|
||||
const char *fname,
|
||||
struct stat *st_dir_initial)
|
||||
struct stat *st_dir_initial,
|
||||
int type)
|
||||
{
|
||||
size_t len = 0;
|
||||
size_t xc = 0;
|
||||
@@ -683,6 +736,7 @@ mkhtemp(int *fd,
|
||||
|
||||
size_t retries;
|
||||
|
||||
int close_errno;
|
||||
int saved_errno = errno;
|
||||
|
||||
#if defined(PATH_LEN) && \
|
||||
@@ -703,8 +757,11 @@ mkhtemp(int *fd,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we do not mess with an
|
||||
open descriptor.
|
||||
*/
|
||||
if (*fd >= 0) {
|
||||
errno = EEXIST;
|
||||
errno = EEXIST; /* leave their file alone */
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -778,13 +835,20 @@ mkhtemp(int *fd,
|
||||
p,
|
||||
xc,
|
||||
fd,
|
||||
st);
|
||||
st,
|
||||
type);
|
||||
|
||||
if (r != 1) {
|
||||
if (retries >= MKHTEMP_SPIN_THRESHOLD)
|
||||
if (r == 0) {
|
||||
if (retries >= MKHTEMP_SPIN_THRESHOLD) {
|
||||
/* usleep can return EINTR */
|
||||
close_errno = errno;
|
||||
usleep((useconds_t)rlong() & 0x3FF);
|
||||
errno = close_errno;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (r < 0)
|
||||
goto err;
|
||||
|
||||
/* success: copy final name back */
|
||||
memcpy(template + len - fname_len,
|
||||
@@ -798,7 +862,9 @@ mkhtemp(int *fd,
|
||||
|
||||
err:
|
||||
if (*fd >= 0) {
|
||||
close_errno = errno;
|
||||
(void)close_on_eintr(*fd);
|
||||
errno = close_errno;
|
||||
*fd = -1;
|
||||
}
|
||||
|
||||
@@ -817,34 +883,75 @@ mkhtemp_try_create(int dirfd,
|
||||
char *p,
|
||||
size_t xc,
|
||||
int *fd,
|
||||
struct stat *st)
|
||||
struct stat *st,
|
||||
int type)
|
||||
{
|
||||
struct stat st_dir_now;
|
||||
struct stat st_open;
|
||||
int saved_errno = errno;
|
||||
int close_errno;
|
||||
int rval = -1;
|
||||
|
||||
if (mkhtemp_fill_random(p, xc) < 0)
|
||||
goto err;
|
||||
int file_created = 0;
|
||||
int dir_created = 0;
|
||||
|
||||
if (fstat(dirfd, &st_dir_now) < 0)
|
||||
if (fd == NULL || st == NULL || p == NULL || fname_copy == NULL ||
|
||||
st_dir_initial == NULL) {
|
||||
errno = EFAULT;
|
||||
goto err;
|
||||
} else if (*fd >= 0) { /* do not mess with someone else's file */
|
||||
errno = EEXIST;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (mkhtemp_fill_random(p, xc) < 0)
|
||||
goto err;
|
||||
|
||||
if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
|
||||
goto err;
|
||||
|
||||
*fd = openat2p(dirfd, fname_copy,
|
||||
O_RDWR | O_CREAT | O_EXCL |
|
||||
O_NOFOLLOW | O_CLOEXEC | O_NOCTTY,
|
||||
0600);
|
||||
if (type == MKHTEMP_FILE) {
|
||||
*fd = openat2p(dirfd, fname_copy,
|
||||
O_RDWR | O_CREAT | O_EXCL |
|
||||
O_NOFOLLOW | O_CLOEXEC | O_NOCTTY,
|
||||
0600);
|
||||
|
||||
/* O_CREAT and O_EXCL guarantees
|
||||
* creation upon success
|
||||
*/
|
||||
if (*fd >= 0)
|
||||
file_created = 1;
|
||||
|
||||
} else { /* dir: MKHTEMP_DIR */
|
||||
|
||||
if (mkdirat_on_eintr(dirfd, fname_copy, 0700) < 0)
|
||||
goto err;
|
||||
|
||||
/* ^ NOTE: opening the directory here
|
||||
will never set errno=EEXIST,
|
||||
since we're not creating it */
|
||||
|
||||
dir_created = 1;
|
||||
|
||||
/* do it again (mitigate directory race) */
|
||||
if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
|
||||
goto err;
|
||||
|
||||
*fd = openat2p(dirfd, fname_copy,
|
||||
O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0);
|
||||
if (*fd < 0)
|
||||
goto err;
|
||||
|
||||
if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
|
||||
goto err;
|
||||
|
||||
}
|
||||
|
||||
/* NOTE: openat2p and mkdirat_on_eintr
|
||||
* already handled EINTR/EAGAIN looping
|
||||
*/
|
||||
|
||||
if (*fd < 0) {
|
||||
if (errno == EEXIST ||
|
||||
errno == EINTR ||
|
||||
errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
errno == ETXTBSY) {
|
||||
if (errno == EEXIST) {
|
||||
|
||||
rval = 0;
|
||||
goto out;
|
||||
@@ -852,17 +959,37 @@ mkhtemp_try_create(int dirfd,
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* fd is now live */
|
||||
|
||||
if (fstat(*fd, &st_open) < 0)
|
||||
goto err;
|
||||
|
||||
if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
|
||||
goto err;
|
||||
if (type == MKHTEMP_FILE) {
|
||||
|
||||
if (secure_file(fd, st, &st_open,
|
||||
O_APPEND, 1, 1, 0600) < 0)
|
||||
goto err;
|
||||
if (fd_verify_dir_identity(dirfd, st_dir_initial) < 0)
|
||||
goto err;
|
||||
|
||||
if (secure_file(fd, st, &st_open,
|
||||
O_APPEND, 1, 1, 0600) < 0) /* WARNING: only once */
|
||||
goto err;
|
||||
|
||||
} else { /* dir: MKHTEMP_DIR */
|
||||
|
||||
if (fd_verify_identity(*fd, &st_open, st_dir_initial) < 0)
|
||||
goto err;
|
||||
|
||||
if (!S_ISDIR(st_open.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (is_owner(&st_open) < 0)
|
||||
goto err;
|
||||
|
||||
/* group/world writeable */
|
||||
if (st_open.st_mode & (S_IWGRP | S_IWOTH)) {
|
||||
errno = EPERM;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
errno = saved_errno;
|
||||
rval = 1;
|
||||
@@ -876,6 +1003,12 @@ err:
|
||||
*fd = -1;
|
||||
}
|
||||
|
||||
if (file_created)
|
||||
(void) unlinkat(dirfd, fname_copy, 0);
|
||||
|
||||
if (dir_created)
|
||||
(void) unlinkat(dirfd, fname_copy, AT_REMOVEDIR);
|
||||
|
||||
errno = close_errno;
|
||||
rval = -1;
|
||||
out:
|
||||
@@ -947,6 +1080,11 @@ err_mkhtemp_fill_random:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* WARNING: **ONCE** per file.
|
||||
*
|
||||
* !!! DO NOT RUN TWICE PER FILE. BEWARE OF THE DEMON !!!
|
||||
* watch out for spikes!
|
||||
*/
|
||||
int secure_file(int *fd,
|
||||
struct stat *st,
|
||||
struct stat *expected,
|
||||
@@ -958,25 +1096,25 @@ int secure_file(int *fd,
|
||||
int flags;
|
||||
struct stat st_now;
|
||||
int saved_errno = errno;
|
||||
|
||||
/* you have been warned */
|
||||
if (fd == NULL) {
|
||||
errno = EFAULT;
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
}
|
||||
if (*fd < 0) {
|
||||
errno = EBADF;
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
}
|
||||
|
||||
if (st == NULL) {
|
||||
errno = EFAULT;
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
}
|
||||
|
||||
flags = fcntl(*fd, F_GETFL);
|
||||
|
||||
if (flags == -1)
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
|
||||
if (bad_flags > 0) {
|
||||
|
||||
@@ -984,49 +1122,49 @@ int secure_file(int *fd,
|
||||
* by allowing offsets to be ignored */
|
||||
if (flags & bad_flags) {
|
||||
errno = EPERM;
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
}
|
||||
}
|
||||
|
||||
if (fstat(*fd, &st_now) == -1)
|
||||
goto err_secure_file;
|
||||
|
||||
if (expected != NULL) {
|
||||
if (fd_verify_identity(*fd, expected, &st_now) < 0)
|
||||
goto err_secure_file;
|
||||
if (fd_verify_regular(*fd, expected, st) < 0)
|
||||
goto err_demons;
|
||||
} else {
|
||||
if (fstat(*fd, &st_now) == -1)
|
||||
goto err_demons;
|
||||
|
||||
if (!S_ISREG(st_now.st_mode)) {
|
||||
errno = EBADF;
|
||||
goto err_demons;
|
||||
}
|
||||
|
||||
*st = st_now;
|
||||
}
|
||||
|
||||
*st = st_now;
|
||||
|
||||
if (!S_ISREG(st->st_mode)) {
|
||||
errno = EBADF;
|
||||
goto err_secure_file;
|
||||
}
|
||||
|
||||
if (fd_verify_regular(*fd, expected, st) < 0)
|
||||
goto err_secure_file;
|
||||
|
||||
if (check_seek) {
|
||||
|
||||
/* check if it's seekable */
|
||||
if (lseek(*fd, 0, SEEK_CUR) == (off_t)-1)
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
}
|
||||
|
||||
/* tmpfile re/un linked while open */
|
||||
if (st->st_nlink != 1) {
|
||||
errno = ELOOP;
|
||||
goto err_secure_file;
|
||||
/* don't release the demon
|
||||
*/
|
||||
if (st->st_nlink != 1) { /***********/
|
||||
/* ( >:3 ) */
|
||||
errno = ELOOP; /* /| |\ */ /* don't let him out */
|
||||
goto err_demons; /* / \ */
|
||||
/***********/
|
||||
}
|
||||
|
||||
if (st->st_uid != geteuid() && /* someone else's file */
|
||||
geteuid() != 0) { /* override for root */
|
||||
|
||||
errno = EPERM;
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
}
|
||||
if (is_owner(st) < 0)
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
|
||||
/* world-writeable or group-ownership.
|
||||
* if these are set, then others could
|
||||
@@ -1034,26 +1172,26 @@ int secure_file(int *fd,
|
||||
*/
|
||||
if (st->st_mode & (S_IWGRP | S_IWOTH)) {
|
||||
errno = EPERM;
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
}
|
||||
|
||||
if (do_lock) {
|
||||
if (lock_file(*fd, flags) == -1)
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
|
||||
if (expected != NULL) {
|
||||
if (fd_verify_identity(*fd, expected, &st_now) < 0)
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
}
|
||||
}
|
||||
|
||||
if (fchmod(*fd, mode) == -1)
|
||||
goto err_secure_file;
|
||||
goto err_demons;
|
||||
|
||||
errno = saved_errno;
|
||||
return 0;
|
||||
|
||||
err_secure_file:
|
||||
err_demons:
|
||||
|
||||
if (errno == saved_errno)
|
||||
errno = EIO;
|
||||
@@ -1674,7 +1812,9 @@ lseek_on_eintr(int fd, off_t off, int whence,
|
||||
old = lseek(fd, off, whence);
|
||||
} while (old == (off_t)-1 && (
|
||||
errno == try_err(loop_eintr, EINTR) ||
|
||||
errno == try_err(loop_eagain, EAGAIN)));
|
||||
errno == try_err(loop_eintr, ETXTBSY) ||
|
||||
errno == try_err(loop_eagain, EAGAIN) ||
|
||||
errno == try_err(loop_eagain, EWOULDBLOCK)));
|
||||
|
||||
return old;
|
||||
}
|
||||
@@ -1697,7 +1837,9 @@ close_on_eintr(int fd)
|
||||
|
||||
do {
|
||||
r = close(fd);
|
||||
} while (r == -1 && (errno == EINTR || errno == EAGAIN));
|
||||
} while (r == -1 && (
|
||||
errno == EINTR || errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK || errno == ETXTBSY));
|
||||
|
||||
if (r >= 0)
|
||||
errno = saved_errno;
|
||||
@@ -1713,7 +1855,8 @@ fsync_on_eintr(int fd)
|
||||
|
||||
do {
|
||||
r = fsync(fd);
|
||||
} while (r == -1 && (errno == EINTR || errno == EAGAIN));
|
||||
} while (r == -1 && (errno == EINTR || errno == EAGAIN ||
|
||||
errno == ETXTBSY || errno == EWOULDBLOCK));
|
||||
|
||||
if (r >= 0)
|
||||
errno = saved_errno;
|
||||
@@ -1797,6 +1940,8 @@ fs_mkdir_p_at(int dirfd, const char *path, mode_t mode)
|
||||
struct stat st_parent_initial;
|
||||
struct stat st_parent_now;
|
||||
int saved_errno = errno;
|
||||
int close_errno;
|
||||
int dir_created = 0;
|
||||
int r;
|
||||
|
||||
if (path == NULL) {
|
||||
@@ -1834,16 +1979,20 @@ fs_mkdir_p_at(int dirfd, const char *path, mode_t mode)
|
||||
if (errno != ENOENT)
|
||||
goto err;
|
||||
|
||||
if (mkdirat(dirfd, name, mode) < 0)
|
||||
if (mkdirat_on_eintr(dirfd, name, mode) < 0)
|
||||
goto err;
|
||||
|
||||
dir_created = 1;
|
||||
|
||||
nextfd = openat2p(dirfd, name,
|
||||
O_RDONLY | O_DIRECTORY | O_CLOEXEC, 0);
|
||||
if (nextfd < 0)
|
||||
goto err;
|
||||
}
|
||||
|
||||
close_errno = errno;
|
||||
(void)close_on_eintr(dirfd);
|
||||
errno = close_errno;
|
||||
dirfd = nextfd;
|
||||
nextfd = -1;
|
||||
|
||||
@@ -1855,9 +2004,11 @@ fs_mkdir_p_at(int dirfd, const char *path, mode_t mode)
|
||||
|
||||
err:
|
||||
if (dirfd >= 0)
|
||||
(void)close_on_eintr(dirfd);
|
||||
(void) close_on_eintr(dirfd);
|
||||
if (nextfd >= 0)
|
||||
(void)close_on_eintr(nextfd);
|
||||
(void) close_on_eintr(nextfd);
|
||||
if (dir_created)
|
||||
(void) unlinkat(dirfd, name, AT_REMOVEDIR);
|
||||
|
||||
errno = saved_errno;
|
||||
return (-1);
|
||||
@@ -2122,6 +2273,7 @@ fs_dirname_basename(const char *path,
|
||||
* with fallback for others e.g. openbsd
|
||||
*
|
||||
* BONUS: arg checks
|
||||
* TODO: consider EINTR/EAGAIN retry loop
|
||||
*/
|
||||
int
|
||||
openat2p(int dirfd, const char *path,
|
||||
@@ -2137,6 +2289,8 @@ openat2p(int dirfd, const char *path,
|
||||
RESOLVE_NO_MAGICLINKS |
|
||||
RESOLVE_NO_XDEV
|
||||
};
|
||||
int saved_errno = errno;
|
||||
int rval;
|
||||
#endif
|
||||
|
||||
if (dirfd < 0) {
|
||||
@@ -2149,15 +2303,64 @@ openat2p(int dirfd, const char *path,
|
||||
return -1;
|
||||
}
|
||||
|
||||
retry:
|
||||
errno = 0;
|
||||
|
||||
#ifdef __linux__
|
||||
/* more secure than regular openat,
|
||||
* but linux-only at the time of writing
|
||||
*/
|
||||
return syscall(SYS_openat2, dirfd, path, &how, sizeof(how));
|
||||
rval = syscall(SYS_openat2, dirfd, path, &how, sizeof(how));
|
||||
#else
|
||||
/* less secure, but e.g. openbsd
|
||||
* doesn't have openat2 yet
|
||||
*/
|
||||
return openat(dirfd, path, flags, mode);
|
||||
rval = openat(dirfd, path, flags, mode);
|
||||
#endif
|
||||
if (rval == -1 && (
|
||||
errno == EINTR ||
|
||||
errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
errno == ETXTBSY))
|
||||
goto retry;
|
||||
|
||||
if (rval >= 0)
|
||||
errno = saved_errno;
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
mkdirat_on_eintr( /* <-- say that 10 times to please the demon */
|
||||
int dirfd,
|
||||
const char *path, mode_t mode)
|
||||
{
|
||||
int saved_errno = errno;
|
||||
int rval;
|
||||
|
||||
if (dirfd < 0) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (path == NULL) {
|
||||
errno = EFAULT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
retry:
|
||||
errno = 0;
|
||||
rval = mkdirat(dirfd, path, mode);
|
||||
|
||||
if (rval == -1 && (
|
||||
errno == EINTR ||
|
||||
errno == EAGAIN ||
|
||||
errno == EWOULDBLOCK ||
|
||||
errno == ETXTBSY))
|
||||
goto retry;
|
||||
|
||||
if (rval >= 0)
|
||||
errno = saved_errno;
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user