We should pass O_NOFOLLOW otherwise openat() will follow symlinks and make QEMU vulnerable.
O_PATH was used as an optimization: the fd returned by openat_dir() is only passed to openat() actually, so we don't really need to reach the underlying filesystem. O_NOFOLLOW | O_PATH isn't an option: if name is a symlink, openat() will return a fd, forcing us to do some other syscall to detect we have a symlink. Also, O_PATH doesn't exist in glibc 2.13 and older. The only sane thing to do is hence to drop O_PATH, and only pass O_NOFOLLOW. While here, we also fix local_unlinkat_common() to use openat_dir() for the same reasons (it was a leftover in the original patchset actually). This fixes CVE-2016-9602. Signed-off-by: Greg Kurz <gr...@kaod.org> --- hw/9pfs/9p-local.c | 2 +- hw/9pfs/9p-util.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/9pfs/9p-local.c b/hw/9pfs/9p-local.c index 5db7104334d6..e31309a29c58 100644 --- a/hw/9pfs/9p-local.c +++ b/hw/9pfs/9p-local.c @@ -959,7 +959,7 @@ static int local_unlinkat_common(FsContext *ctx, int dirfd, const char *name, if (flags == AT_REMOVEDIR) { int fd; - fd = openat(dirfd, name, O_RDONLY | O_DIRECTORY | O_PATH); + fd = openat_dir(dirfd, name); if (fd == -1) { goto err_out; } diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h index 091f3ce88e15..4001d1fd8398 100644 --- a/hw/9pfs/9p-util.h +++ b/hw/9pfs/9p-util.h @@ -22,7 +22,7 @@ static inline void close_preserve_errno(int fd) static inline int openat_dir(int dirfd, const char *name) { - return openat(dirfd, name, O_DIRECTORY | O_RDONLY | O_PATH); + return openat(dirfd, name, O_DIRECTORY | O_RDONLY | O_NOFOLLOW); } static inline int openat_file(int dirfd, const char *name, int flags,