xemu/hw/9pfs/9p-util.h
Greg Kurz 918112c02a 9pfs: fix O_PATH build break with older glibc versions
When O_PATH is used with O_DIRECTORY, it only acts as an optimization: the
openat() syscall simply finds the name in the VFS, and doesn't trigger the
underlying filesystem.

On systems that don't define O_PATH, because they have glibc version 2.13
or older for example, we can safely omit it. We don't want to deactivate
O_PATH globally though, in case it is used without O_DIRECTORY. The is done
with a dedicated macro.

Systems without O_PATH may thus fail to resolve names that involve
unreadable directories, compared to newer systems succeeding, but such
corner case failure is our only option on those older systems to avoid
the security hole of chasing symlinks inappropriately.

Signed-off-by: Greg Kurz <groug@kaod.org>
Reviewed-by: Eric Blake <eblake@redhat.com>
(added last paragraph to changelog as suggested by Eric Blake)
Signed-off-by: Greg Kurz <groug@kaod.org>
2017-03-06 17:34:01 +01:00

60 lines
1.4 KiB
C

/*
* 9p utilities
*
* Copyright IBM, Corp. 2017
*
* Authors:
* Greg Kurz <groug@kaod.org>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef QEMU_9P_UTIL_H
#define QEMU_9P_UTIL_H
static inline void close_preserve_errno(int fd)
{
int serrno = errno;
close(fd);
errno = serrno;
}
static inline int openat_dir(int dirfd, const char *name)
{
#ifdef O_PATH
#define OPENAT_DIR_O_PATH O_PATH
#else
#define OPENAT_DIR_O_PATH 0
#endif
return openat(dirfd, name, O_DIRECTORY | O_RDONLY | OPENAT_DIR_O_PATH);
}
static inline int openat_file(int dirfd, const char *name, int flags,
mode_t mode)
{
int fd, serrno, ret;
fd = openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
mode);
if (fd == -1) {
return -1;
}
serrno = errno;
/* O_NONBLOCK was only needed to open the file. Let's drop it. */
ret = fcntl(fd, F_SETFL, flags);
assert(!ret);
errno = serrno;
return fd;
}
int relative_openat_nofollow(int dirfd, const char *path, int flags,
mode_t mode);
ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
void *value, size_t size);
int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
void *value, size_t size, int flags);
#endif