From: Christian Schoenebeck <qemu_oss@crudebyte.com>
To: qemu-devel@nongnu.org, Mauro Matteo Cascella <mcascell@redhat.com>
Cc: yw s <ywsplz@gmail.com>,
shawtao1125@gmail.com, jkli@xidian.edu.cn, shenwenbo@zju.edu.cn,
Greg Kurz <groug@kaod.org>
Subject: Re: [PATCH v2] 9pfs: prevent opening special files (CVE-2023-2861)
Date: Wed, 07 Jun 2023 13:02:17 +0200 [thread overview]
Message-ID: <2567904.5Pe2IrQ8Qc@silver> (raw)
In-Reply-To: <20230606180028.5305af87@bahia>
On Tuesday, June 6, 2023 6:00:28 PM CEST Greg Kurz wrote:
> Hi Christian,
>
> On Tue, 06 Jun 2023 15:57:50 +0200
> Christian Schoenebeck <qemu_oss@crudebyte.com> wrote:
>
> > 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>
> > ---
> > v1 -> v2:
> > - Add equivalent fix for 'proxy' fs driver.
> > - Minor adjustments on commit log.
> >
>
> Note that this might be a bit confusing for reviewers since
> v1 was never posted to qemu-devel. Technically, this should
> have been posted without the v2 tag.
I felt it wouldn't make it any better, as it might otherwise confuse those who
already got the previous two patch emails.
> > fsdev/virtfs-proxy-helper.c | 48 +++++++++++++++++++++++++++++++++++--
> > hw/9pfs/9p-util.h | 29 ++++++++++++++++++++++
> > 2 files changed, 75 insertions(+), 2 deletions(-)
> >
> > diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c
> > index 5cafcd7703..f311519fa3 100644
> > --- 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,49 @@ 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;
> > + struct stat stbuf;
> > +
> > + fd = open(pathname, flags, mode);
> > + if (fd < 0) {
> > + return fd;
> > + }
> > +
> > + /* 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.
> > + */
> > + if (qemu_fstat(fd, &stbuf) < 0) {
> > + close_preserve_errno(fd);
> > + return -1;
> > + }
> > + if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)) {
> > + /* Tcreate and Tlcreate 9p messages mandate to immediately open the
> > + * created file for I/O. So this is not (necessarily) due to a broken
> > + * client, and hence no error message is to be reported in this case.
> > + */
> > + if (!(flags & O_CREAT)) {
>
> Tlcreate is explicitly about creating regular files only (see [1] and
> v9fs_lcreate()) and I don't quite see how open() could successfully
> create a regular file and the resulting fd is fstat'ed as something
> else.
>
> Tcreate seems to cover more types but again only regular files (with O_CREAT)
> or directories (without O_CREAT) are expected here (see v9fs_create()).
>
> Unless I'm missing something, it seems that the comment and the O_CREAT
> check should be removed.
>
> [1] https://github.com/chaos/diod/blob/master/protocol.md#lcreate----create-regular-file
You are right about Tlcreate, but for Tcreate 9p2000.u specifies, quote:
"In addition to creating directories with DMDIR, 9P2000.u allows the creation
of symlinks (DMSYMLINK), devices (DMDEVICE), named pipes (DMNAMEPIPE), and
sockets (DMSOCKET)."
http://ericvh.github.io/9p-rfc/rfc9p2000.u.html#anchor17
So I just remove mentioning Tlcreate in the comment?
>
> > + 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 fd;
> > +}
> > +
> > /*
> > * send response in two parts
> > * 1) ProxyHeader
> > @@ -682,7 +726,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 +751,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;
> > }
> > diff --git a/hw/9pfs/9p-util.h b/hw/9pfs/9p-util.h
> > index c314cf381d..9da1a0538d 100644
> > --- 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
> > @@ -95,6 +97,7 @@ static inline int errno_to_dotl(int err) {
> > #endif
> >
> > #define qemu_openat openat
> > +#define qemu_fstat fstat
> > #define qemu_fstatat fstatat
> > #define qemu_mkdirat mkdirat
> > #define qemu_renameat renameat
> > @@ -118,6 +121,7 @@ static inline int openat_file(int dirfd, const char *name, int flags,
> > mode_t mode)
> > {
> > int fd, serrno, ret;
> > + struct stat stbuf;
> >
> > #ifndef CONFIG_DARWIN
> > again:
> > @@ -142,6 +146,31 @@ again:
> > return -1;
> > }
> >
> > + /* 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.
> > + */
> > + if (qemu_fstat(fd, &stbuf) < 0) {
> > + close_preserve_errno(fd);
> > + return -1;
> > + }
> > + if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)) {
> > + /* Tcreate and Tlcreate 9p messages mandate to immediately open the
> > + * created file for I/O. So this is not (necessarily) due to a broken
> > + * client, and hence no error message is to be reported in this case.
> > + */
>
> Same remark as with the proxy helper.
>
> If you agree with my suggestions, feel free to add my R-b right away.
>
> Cheers,
I'll definitely take the time for another (v3) round in this case. Thanks!
> --
> Greg
>
> > + if (!(flags & O_CREAT)) {
> > + 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;
> > + }
> > +
> > 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()
>
>
next prev parent reply other threads:[~2023-06-07 11:03 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-06 13:57 [PATCH v2] 9pfs: prevent opening special files (CVE-2023-2861) Christian Schoenebeck
2023-06-06 16:00 ` Greg Kurz
2023-06-07 11:02 ` Christian Schoenebeck [this message]
2023-06-07 13:24 ` Greg Kurz
2023-06-07 13:27 ` Christian Schoenebeck
2023-06-06 18:48 ` Michael Tokarev
2023-06-07 11:05 ` Christian Schoenebeck
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2567904.5Pe2IrQ8Qc@silver \
--to=qemu_oss@crudebyte.com \
--cc=groug@kaod.org \
--cc=jkli@xidian.edu.cn \
--cc=mcascell@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=shawtao1125@gmail.com \
--cc=shenwenbo@zju.edu.cn \
--cc=ywsplz@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).