main: use openat2 where available

Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
Giuseppe Scrivano 2020-04-21 17:15:41 +02:00
parent f040ab0343
commit fb8eb3300e
No known key found for this signature in database
GPG Key ID: E4730F97F60286ED
4 changed files with 83 additions and 21 deletions

View File

@ -129,7 +129,7 @@ direct_opendir (struct ovl_layer *l, const char *path)
cleanup_close int cleanup_fd = -1; cleanup_close int cleanup_fd = -1;
DIR *dp = NULL; DIR *dp = NULL;
cleanup_fd = TEMP_FAILURE_RETRY (openat (l->fd, path, O_DIRECTORY)); cleanup_fd = TEMP_FAILURE_RETRY (safe_openat (l->fd, path, O_DIRECTORY, 0));
if (cleanup_fd < 0) if (cleanup_fd < 0)
return NULL; return NULL;
@ -151,7 +151,7 @@ direct_closedir (void *dirp)
static int static int
direct_openat (struct ovl_layer *l, const char *path, int flags, mode_t mode) direct_openat (struct ovl_layer *l, const char *path, int flags, mode_t mode)
{ {
return TEMP_FAILURE_RETRY (openat (l->fd, path, flags, mode)); return TEMP_FAILURE_RETRY (safe_openat (l->fd, path, flags, mode));
} }
static ssize_t static ssize_t

36
main.c
View File

@ -494,7 +494,7 @@ set_fd_opaque (int fd)
return -1; return -1;
} }
create_opq_whiteout: create_opq_whiteout:
opq_whiteout_fd = TEMP_FAILURE_RETRY (openat (fd, OPAQUE_WHITEOUT, O_CREAT|O_WRONLY|O_NONBLOCK, 0700)); opq_whiteout_fd = TEMP_FAILURE_RETRY (safe_openat (fd, OPAQUE_WHITEOUT, O_CREAT|O_WRONLY|O_NONBLOCK, 0700));
return (opq_whiteout_fd >= 0 || ret == 0) ? 0 : -1; return (opq_whiteout_fd >= 0 || ret == 0) ? 0 : -1;
} }
@ -2445,7 +2445,7 @@ create_directory (struct ovl_data *lo, int dirfd, const char *name, const struct
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = dfd = TEMP_FAILURE_RETRY (openat (lo->workdir_fd, wd_tmp_file_name, O_RDONLY)); ret = dfd = TEMP_FAILURE_RETRY (safe_openat (lo->workdir_fd, wd_tmp_file_name, O_RDONLY, 0));
if (ret < 0) if (ret < 0)
goto out; goto out;
@ -2645,11 +2645,11 @@ copyup (struct ovl_data *lo, struct ovl_node *node)
goto success; goto success;
} }
ret = sfd = node->layer->ds->openat (node->layer, node->path, O_RDONLY|O_NONBLOCK, 0755); ret = sfd = node->layer->ds->openat (node->layer, node->path, O_RDONLY|O_NONBLOCK, 0);
if (sfd < 0) if (sfd < 0)
goto exit; goto exit;
ret = dfd = TEMP_FAILURE_RETRY (openat (lo->workdir_fd, wd_tmp_file_name, O_CREAT|O_WRONLY, st.st_mode)); ret = dfd = TEMP_FAILURE_RETRY (safe_openat (lo->workdir_fd, wd_tmp_file_name, O_CREAT|O_WRONLY, st.st_mode));
if (dfd < 0) if (dfd < 0)
goto exit; goto exit;
@ -2865,7 +2865,7 @@ empty_dirfd (int fd)
{ {
int dfd; int dfd;
dfd = openat (dirfd (dp), dent->d_name, O_DIRECTORY); dfd = safe_openat (dirfd (dp), dent->d_name, O_DIRECTORY, 0);
if (dfd < 0) if (dfd < 0)
return -1; return -1;
@ -2893,7 +2893,7 @@ empty_dir (struct ovl_layer *l, const char *path)
cleanup_close int cleanup_fd = -1; cleanup_close int cleanup_fd = -1;
int ret; int ret;
cleanup_fd = TEMP_FAILURE_RETRY (openat (l->fd, path, O_DIRECTORY)); cleanup_fd = TEMP_FAILURE_RETRY (safe_openat (l->fd, path, O_DIRECTORY, 0));
if (cleanup_fd < 0) if (cleanup_fd < 0)
return -1; return -1;
@ -3171,7 +3171,7 @@ direct_create_file (struct ovl_layer *l, int dirfd, const char *path, uid_t uid,
/* try to create directly the file if it doesn't need to be chowned. */ /* try to create directly the file if it doesn't need to be chowned. */
if (uid == lo->uid && gid == lo->gid) if (uid == lo->uid && gid == lo->gid)
{ {
ret = TEMP_FAILURE_RETRY (openat (get_upper_layer (lo)->fd, path, flags, mode)); ret = TEMP_FAILURE_RETRY (safe_openat (get_upper_layer (lo)->fd, path, flags, mode));
if (ret >= 0) if (ret >= 0)
return ret; return ret;
/* if it fails (e.g. there is a whiteout) then fallback to create it in /* if it fails (e.g. there is a whiteout) then fallback to create it in
@ -3180,7 +3180,7 @@ direct_create_file (struct ovl_layer *l, int dirfd, const char *path, uid_t uid,
sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ()); sprintf (wd_tmp_file_name, "%lu", get_next_wd_counter ());
fd = TEMP_FAILURE_RETRY (openat (lo->workdir_fd, wd_tmp_file_name, flags, mode)); fd = TEMP_FAILURE_RETRY (safe_openat (lo->workdir_fd, wd_tmp_file_name, flags, mode));
if (fd < 0) if (fd < 0)
return -1; return -1;
if (uid != lo->uid || gid != lo->gid) if (uid != lo->uid || gid != lo->gid)
@ -3590,7 +3590,7 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru
switch (mode & S_IFMT) switch (mode & S_IFMT)
{ {
case S_IFREG: case S_IFREG:
cleaned_up_fd = fd = TEMP_FAILURE_RETRY (openat (dirfd, node->path, O_NOFOLLOW|O_NONBLOCK|(to_set & FUSE_SET_ATTR_SIZE ? O_WRONLY : 0))); cleaned_up_fd = fd = TEMP_FAILURE_RETRY (safe_openat (dirfd, node->path, O_NOFOLLOW|O_NONBLOCK|(to_set & FUSE_SET_ATTR_SIZE ? O_WRONLY : 0), 0));
if (fd < 0) if (fd < 0)
{ {
fuse_reply_err (req, errno); fuse_reply_err (req, errno);
@ -3599,7 +3599,7 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru
break; break;
case S_IFDIR: case S_IFDIR:
cleaned_up_fd = fd = TEMP_FAILURE_RETRY (openat (dirfd, node->path, O_NOFOLLOW|O_NONBLOCK)); cleaned_up_fd = fd = TEMP_FAILURE_RETRY (safe_openat (dirfd, node->path, O_NOFOLLOW|O_NONBLOCK, 0));
if (fd < 0) if (fd < 0)
{ {
if (errno != ELOOP) if (errno != ELOOP)
@ -3611,7 +3611,7 @@ ovl_setattr (fuse_req_t req, fuse_ino_t ino, struct stat *attr, int to_set, stru
break; break;
case S_IFLNK: case S_IFLNK:
cleaned_up_fd = TEMP_FAILURE_RETRY (openat (dirfd, node->path, O_PATH|O_NOFOLLOW|O_NONBLOCK)); cleaned_up_fd = TEMP_FAILURE_RETRY (safe_openat (dirfd, node->path, O_PATH|O_NOFOLLOW|O_NONBLOCK, 0));
if (cleaned_up_fd < 0) if (cleaned_up_fd < 0)
{ {
fuse_reply_err (req, errno); fuse_reply_err (req, errno);
@ -3981,7 +3981,7 @@ ovl_rename_exchange (fuse_req_t req, fuse_ino_t parent, const char *name,
if (pnode == NULL) if (pnode == NULL)
goto error; goto error;
ret = TEMP_FAILURE_RETRY (openat (node_dirfd (pnode), pnode->path, O_DIRECTORY)); ret = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (pnode), pnode->path, O_DIRECTORY, 0));
if (ret < 0) if (ret < 0)
goto error; goto error;
srcfd = ret; srcfd = ret;
@ -3990,7 +3990,7 @@ ovl_rename_exchange (fuse_req_t req, fuse_ino_t parent, const char *name,
if (destpnode == NULL) if (destpnode == NULL)
goto error; goto error;
ret = TEMP_FAILURE_RETRY (openat (node_dirfd (destpnode), destpnode->path, O_DIRECTORY)); ret = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (destpnode), destpnode->path, O_DIRECTORY, 0));
if (ret < 0) if (ret < 0)
goto error; goto error;
destfd = ret; destfd = ret;
@ -4106,7 +4106,7 @@ ovl_rename_direct (fuse_req_t req, fuse_ino_t parent, const char *name,
if (pnode == NULL) if (pnode == NULL)
goto error; goto error;
ret = TEMP_FAILURE_RETRY (openat (node_dirfd (pnode), pnode->path, O_DIRECTORY)); ret = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (pnode), pnode->path, O_DIRECTORY, 0));
if (ret < 0) if (ret < 0)
goto error; goto error;
srcfd = ret; srcfd = ret;
@ -4115,7 +4115,7 @@ ovl_rename_direct (fuse_req_t req, fuse_ino_t parent, const char *name,
if (destpnode == NULL) if (destpnode == NULL)
goto error; goto error;
ret = TEMP_FAILURE_RETRY (openat (node_dirfd (destpnode), destpnode->path, O_DIRECTORY)); ret = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (destpnode), destpnode->path, O_DIRECTORY, 0));
if (ret < 0) if (ret < 0)
goto error; goto error;
destfd = ret; destfd = ret;
@ -4622,7 +4622,7 @@ direct_fsync (struct ovl_layer *l, int fd, const char *path, int datasync)
if (fd < 0) if (fd < 0)
{ {
cfd = openat (l->fd, path, O_NOFOLLOW|O_DIRECTORY); cfd = safe_openat (l->fd, path, O_NOFOLLOW|O_DIRECTORY, 0);
if (cfd < 0) if (cfd < 0)
return cfd; return cfd;
fd = cfd; fd = cfd;
@ -4813,7 +4813,7 @@ ovl_fallocate (fuse_req_t req, fuse_ino_t ino, int mode, off_t offset, off_t len
} }
dirfd = node_dirfd (node); dirfd = node_dirfd (node);
fd = openat (dirfd, node->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY, 0755); fd = safe_openat (dirfd, node->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY, 0);
if (fd < 0) if (fd < 0)
{ {
fuse_reply_err (req, errno); fuse_reply_err (req, errno);
@ -4878,7 +4878,7 @@ ovl_copy_file_range (fuse_req_t req, fuse_ino_t ino_in, off_t off_in, struct fus
return; return;
} }
fd_dest = TEMP_FAILURE_RETRY (openat (node_dirfd (dnode), dnode->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY)); fd_dest = TEMP_FAILURE_RETRY (safe_openat (node_dirfd (dnode), dnode->path, O_NONBLOCK|O_NOFOLLOW|O_WRONLY, 0));
if (fd_dest < 0) if (fd_dest < 0)
{ {
fuse_reply_err (req, errno); fuse_reply_err (req, errno);

62
utils.c
View File

@ -25,6 +25,10 @@
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <sys/sysmacros.h> #include <sys/sysmacros.h>
#include <sys/syscall.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef TEMP_FAILURE_RETRY #ifndef TEMP_FAILURE_RETRY
#define TEMP_FAILURE_RETRY(expression) \ #define TEMP_FAILURE_RETRY(expression) \
@ -35,6 +39,62 @@
__result; })) __result; }))
#endif #endif
#ifndef RESOLVE_IN_ROOT
# define RESOLVE_IN_ROOT 0x10
#endif
#ifndef __NR_openat2
# define __NR_openat2 437
#endif
/* List of all valid flags for the open/openat flags argument: */
#define VALID_OPEN_FLAGS \
(O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \
O_APPEND | O_NDELAY | O_NONBLOCK | O_NDELAY | O_SYNC | O_DSYNC | \
FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \
O_NOATIME | O_CLOEXEC | O_PATH | O_TMPFILE)
static int
syscall_openat2 (int dirfd, const char *path, uint64_t flags, uint64_t mode, uint64_t resolve)
{
struct openat2_open_how
{
uint64_t flags;
uint64_t mode;
uint64_t resolve;
}
how =
{
.flags = flags & VALID_OPEN_FLAGS,
.mode = (flags & O_CREAT) ? (mode & 07777) : 0,
.resolve = resolve,
};
return (int) syscall (__NR_openat2, dirfd, path, &how, sizeof (how), 0);
}
int
safe_openat (int dirfd, const char *pathname, int flags, mode_t mode)
{
static bool openat2_supported = true;
if (openat2_supported)
{
int ret;
ret = syscall_openat2 (dirfd, pathname, flags, mode, RESOLVE_IN_ROOT);
if (ret < 0)
{
if (errno == ENOSYS)
openat2_supported = false;
if (errno == ENOSYS || errno == EINVAL)
goto fallback;
}
return ret;
}
fallback:
return openat (dirfd, pathname, flags, mode);
}
int int
file_exists_at (int dirfd, const char *pathname) file_exists_at (int dirfd, const char *pathname)
{ {
@ -148,7 +208,7 @@ open_fd_or_get_path (struct ovl_layer *l, const char *path, char *out, int *fd,
{ {
out[0] = '\0'; out[0] = '\0';
*fd = l->ds->openat (l, path, O_NONBLOCK|O_NOFOLLOW|flags, 0755); *fd = l->ds->openat (l, path, O_NONBLOCK|O_NOFOLLOW|flags, 0);
if (*fd < 0 && (errno == ELOOP || errno == EISDIR || errno == ENXIO)) if (*fd < 0 && (errno == ELOOP || errno == EISDIR || errno == ENXIO))
{ {
strconcat3 (out, PATH_MAX, l->path, "/", path); strconcat3 (out, PATH_MAX, l->path, "/", path);

View File

@ -53,4 +53,6 @@ int open_fd_or_get_path (struct ovl_layer *l, const char *path, char *out, int *
void statx_to_stat (struct statx *stx, struct stat *st); void statx_to_stat (struct statx *stx, struct stat *st);
# endif # endif
int safe_openat (int dirfd, const char *pathname, int flags, mode_t mode);
#endif #endif