You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
4.8 KiB
163 lines
4.8 KiB
https://bugs.gentoo.org/909542
|
|
https://gitlab.com/qemu-project/qemu/-/commit/10fad73a2bf1c76c8aa9d6322755e5f877d83ce5
|
|
|
|
From 10fad73a2bf1c76c8aa9d6322755e5f877d83ce5 Mon Sep 17 00:00:00 2001
|
|
From: Christian Schoenebeck <qemu_oss@crudebyte.com>
|
|
Date: Wed, 7 Jun 2023 18:29:33 +0200
|
|
Subject: [PATCH] 9pfs: prevent opening special files (CVE-2023-2861)
|
|
|
|
The 9p protocol does not specifically define how server shall behave when
|
|
client tries to open a special file, however from security POV it does
|
|
make sense for 9p server to prohibit opening any special file on host side
|
|
in general. A sane Linux 9p client for instance would never attempt to
|
|
open a special file on host side, it would always handle those exclusively
|
|
on its guest side. A malicious client however could potentially escape
|
|
from the exported 9p tree by creating and opening a device file on host
|
|
side.
|
|
|
|
With QEMU this could only be exploited in the following unsafe setups:
|
|
|
|
- Running QEMU binary as root AND 9p 'local' fs driver AND 'passthrough'
|
|
security model.
|
|
|
|
or
|
|
|
|
- Using 9p 'proxy' fs driver (which is running its helper daemon as
|
|
root).
|
|
|
|
These setups were already discouraged for safety reasons before,
|
|
however for obvious reasons we are now tightening behaviour on this.
|
|
|
|
Fixes: CVE-2023-2861
|
|
Reported-by: Yanwu Shen <ywsPlz@gmail.com>
|
|
Reported-by: Jietao Xiao <shawtao1125@gmail.com>
|
|
Reported-by: Jinku Li <jkli@xidian.edu.cn>
|
|
Reported-by: Wenbo Shen <shenwenbo@zju.edu.cn>
|
|
Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
|
|
Reviewed-by: Greg Kurz <groug@kaod.org>
|
|
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
|
|
Message-Id: <E1q6w7r-0000Q0-NM@lizzy.crudebyte.com>
|
|
(cherry picked from commit f6b0de53fb87ddefed348a39284c8e2f28dc4eda)
|
|
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
|
|
(Mjt: drop adding qemu_fstat wrapper for 7.2 where wrappers aren't used)
|
|
--- a/fsdev/virtfs-proxy-helper.c
|
|
+++ b/fsdev/virtfs-proxy-helper.c
|
|
@@ -26,6 +26,7 @@
|
|
#include "qemu/xattr.h"
|
|
#include "9p-iov-marshal.h"
|
|
#include "hw/9pfs/9p-proxy.h"
|
|
+#include "hw/9pfs/9p-util.h"
|
|
#include "fsdev/9p-iov-marshal.h"
|
|
|
|
#define PROGNAME "virtfs-proxy-helper"
|
|
@@ -338,6 +339,28 @@ static void resetugid(int suid, int sgid)
|
|
}
|
|
}
|
|
|
|
+/*
|
|
+ * Open regular file or directory. Attempts to open any special file are
|
|
+ * rejected.
|
|
+ *
|
|
+ * returns file descriptor or -1 on error
|
|
+ */
|
|
+static int open_regular(const char *pathname, int flags, mode_t mode)
|
|
+{
|
|
+ int fd;
|
|
+
|
|
+ fd = open(pathname, flags, mode);
|
|
+ if (fd < 0) {
|
|
+ return fd;
|
|
+ }
|
|
+
|
|
+ if (close_if_special_file(fd) < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return fd;
|
|
+}
|
|
+
|
|
/*
|
|
* send response in two parts
|
|
* 1) ProxyHeader
|
|
@@ -682,7 +705,7 @@ static int do_create(struct iovec *iovec)
|
|
if (ret < 0) {
|
|
goto unmarshal_err_out;
|
|
}
|
|
- ret = open(path.data, flags, mode);
|
|
+ ret = open_regular(path.data, flags, mode);
|
|
if (ret < 0) {
|
|
ret = -errno;
|
|
}
|
|
@@ -707,7 +730,7 @@ static int do_open(struct iovec *iovec)
|
|
if (ret < 0) {
|
|
goto err_out;
|
|
}
|
|
- ret = open(path.data, flags);
|
|
+ ret = open_regular(path.data, flags, 0);
|
|
if (ret < 0) {
|
|
ret = -errno;
|
|
}
|
|
--- a/hw/9pfs/9p-util.h
|
|
+++ b/hw/9pfs/9p-util.h
|
|
@@ -13,6 +13,8 @@
|
|
#ifndef QEMU_9P_UTIL_H
|
|
#define QEMU_9P_UTIL_H
|
|
|
|
+#include "qemu/error-report.h"
|
|
+
|
|
#ifdef O_PATH
|
|
#define O_PATH_9P_UTIL O_PATH
|
|
#else
|
|
@@ -112,6 +114,38 @@ static inline void close_preserve_errno(int fd)
|
|
errno = serrno;
|
|
}
|
|
|
|
+/**
|
|
+ * close_if_special_file() - Close @fd if neither regular file nor directory.
|
|
+ *
|
|
+ * @fd: file descriptor of open file
|
|
+ * Return: 0 on regular file or directory, -1 otherwise
|
|
+ *
|
|
+ * CVE-2023-2861: Prohibit opening any special file directly on host
|
|
+ * (especially device files), as a compromised client could potentially gain
|
|
+ * access outside exported tree under certain, unsafe setups. We expect
|
|
+ * client to handle I/O on special files exclusively on guest side.
|
|
+ */
|
|
+static inline int close_if_special_file(int fd)
|
|
+{
|
|
+ struct stat stbuf;
|
|
+
|
|
+ if (fstat(fd, &stbuf) < 0) {
|
|
+ close_preserve_errno(fd);
|
|
+ return -1;
|
|
+ }
|
|
+ if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)) {
|
|
+ error_report_once(
|
|
+ "9p: broken or compromised client detected; attempt to open "
|
|
+ "special file (i.e. neither regular file, nor directory)"
|
|
+ );
|
|
+ close(fd);
|
|
+ errno = ENXIO;
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
static inline int openat_dir(int dirfd, const char *name)
|
|
{
|
|
return openat(dirfd, name,
|
|
@@ -146,6 +180,10 @@ again:
|
|
return -1;
|
|
}
|
|
|
|
+ if (close_if_special_file(fd) < 0) {
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
serrno = errno;
|
|
/* O_NONBLOCK was only needed to open the file. Let's drop it. We don't
|
|
* do that with O_PATH since fcntl(F_SETFL) isn't supported, and openat()
|
|
--
|
|
GitLab
|