From: Greg Kurz <groug@kaod.org>
To: Christian Schoenebeck via Qemu-devel <qemu-devel@nongnu.org>
Cc: "Daniel P. Berrangé" <berrange@redhat.com>,
"Christian Schoenebeck" <qemu_oss@crudebyte.com>,
"Dr. David Alan Gilbert" <dgilbert@redhat.com>,
"Antonios Motakis" <antonios.motakis@huawei.com>,
"Stefan Hajnoczi" <stefanha@gmail.com>
Subject: Re: [Qemu-devel] [PATCH v5 2/5] 9p: Treat multiple devices on one export as an error
Date: Wed, 31 Jul 2019 22:30:57 +0200 [thread overview]
Message-ID: <20190731223057.3439026e@bahia.lan> (raw)
In-Reply-To: <742b9d876d86fc263492885a7aacc1e1cda274e1.1562154272.git.qemu_oss@crudebyte.com>
On Wed, 3 Jul 2019 13:01:34 +0200
Christian Schoenebeck via Qemu-devel <qemu-devel@nongnu.org> wrote:
> The QID path should uniquely identify a file. However, the
> inode of a file is currently used as the QID path, which
> on its own only uniquely identifies files within a device.
> Here we track the device hosting the 9pfs share, in order
> to prevent security issues with QID path collisions from
> other devices.
>
> Signed-off-by: Antonios Motakis <antonios.motakis@huawei.com>
> [CS: - Assign dev_id to export root's device already in
> v9fs_device_realize_common(), not postponed in
> stat_to_qid().
> - error_report_once() if more than one device was
> shared by export.
> - Return -ENODEV instead of -ENOSYS in stat_to_qid().
> - Fixed typo in log comment. ]
> Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
> ---
The fix is good in the sense that it purely forbids cross-device accesses,
which provides improved security. But some people may wish to do cross-device
anyway, for example because they have ultimate knowledge or luck that their
usual setup doesn't have colliding inodes, or simply that their workload
doesn't care for inode numbers at all.
Next patches in this series introduce inode number remapping, which is
a good way of addressing collisions. This should always be used in a
cross-device setup. But again, people who don't do cross-device, may
wish to disable remapping to avoid the potential performance loss or
extra memory consumption.
I suggest you add a new property to the 9p device so that people can
choose the behavior that best fits their need. Something like:
-device virtio-9p,cross-device=[ignore|forbid|remap]
ignore: detect the cross-device condition and spit-once a big fat warning
about the potential consequences, and alternatives to avoid
them, but don't fail the I/O
forbid: detect the cross-device condition, spit-once an error and fail the
I/O like the current patch does
remap: well... remap all inode numbers
I would make 'ignore' the default since it is the current behavior, but
I'm ready to change my mind if someone has a convincing argument that
the default should be more secure.
Cc'ing Stefan and Dave in case they have some more suggestions after the
discussion we had on irc.
> hw/9pfs/9p.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++------------
> hw/9pfs/9p.h | 1 +
> 2 files changed, 56 insertions(+), 14 deletions(-)
>
> diff --git a/hw/9pfs/9p.c b/hw/9pfs/9p.c
> index 586a6dccba..8cc65c2c67 100644
> --- a/hw/9pfs/9p.c
> +++ b/hw/9pfs/9p.c
> @@ -572,10 +572,18 @@ static void coroutine_fn virtfs_reset(V9fsPDU *pdu)
> P9_STAT_MODE_SOCKET)
>
> /* This is the algorithm from ufs in spfs */
> -static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
> +static int stat_to_qid(V9fsPDU *pdu, const struct stat *stbuf, V9fsQID *qidp)
> {
> size_t size;
>
> + if (pdu->s->dev_id != stbuf->st_dev) {
> + error_report_once(
> + "9p: Multiple devices detected in same VirtFS export. "
> + "You must use a separate export for each device."
> + );
> + return -ENODEV;
> + }
> +
> memset(&qidp->path, 0, sizeof(qidp->path));
> size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
> memcpy(&qidp->path, &stbuf->st_ino, size);
> @@ -587,6 +595,8 @@ static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
> if (S_ISLNK(stbuf->st_mode)) {
> qidp->type |= P9_QID_TYPE_SYMLINK;
> }
> +
> + return 0;
> }
>
> static int coroutine_fn fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp,
> @@ -599,7 +609,10 @@ static int coroutine_fn fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp,
> if (err < 0) {
> return err;
> }
> - stat_to_qid(&stbuf, qidp);
> + err = stat_to_qid(pdu, &stbuf, qidp);
> + if (err < 0) {
> + return err;
> + }
> return 0;
> }
>
> @@ -830,7 +843,10 @@ static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *path,
>
> memset(v9stat, 0, sizeof(*v9stat));
>
> - stat_to_qid(stbuf, &v9stat->qid);
> + err = stat_to_qid(pdu, stbuf, &v9stat->qid);
> + if (err < 0) {
> + return err;
> + }
> v9stat->mode = stat_to_v9mode(stbuf);
> v9stat->atime = stbuf->st_atime;
> v9stat->mtime = stbuf->st_mtime;
> @@ -891,7 +907,7 @@ static int coroutine_fn stat_to_v9stat(V9fsPDU *pdu, V9fsPath *path,
> #define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */
>
>
> -static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
> +static int stat_to_v9stat_dotl(V9fsPDU *pdu, const struct stat *stbuf,
> V9fsStatDotl *v9lstat)
> {
> memset(v9lstat, 0, sizeof(*v9lstat));
> @@ -913,7 +929,7 @@ static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
> /* Currently we only support BASIC fields in stat */
> v9lstat->st_result_mask = P9_STATS_BASIC;
>
> - stat_to_qid(stbuf, &v9lstat->qid);
> + return stat_to_qid(pdu, stbuf, &v9lstat->qid);
> }
>
> static void print_sg(struct iovec *sg, int cnt)
> @@ -1115,7 +1131,6 @@ static void coroutine_fn v9fs_getattr(void *opaque)
> uint64_t request_mask;
> V9fsStatDotl v9stat_dotl;
> V9fsPDU *pdu = opaque;
> - V9fsState *s = pdu->s;
>
> retval = pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask);
> if (retval < 0) {
> @@ -1136,7 +1151,10 @@ static void coroutine_fn v9fs_getattr(void *opaque)
> if (retval < 0) {
> goto out;
> }
> - stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl);
> + retval = stat_to_v9stat_dotl(pdu, &stbuf, &v9stat_dotl);
> + if (retval < 0) {
> + goto out;
> + }
>
> /* fill st_gen if requested and supported by underlying fs */
> if (request_mask & P9_STATS_GEN) {
> @@ -1381,7 +1399,10 @@ static void coroutine_fn v9fs_walk(void *opaque)
> if (err < 0) {
> goto out;
> }
> - stat_to_qid(&stbuf, &qid);
> + err = stat_to_qid(pdu, &stbuf, &qid);
> + if (err < 0) {
> + goto out;
> + }
> v9fs_path_copy(&dpath, &path);
> }
> memcpy(&qids[name_idx], &qid, sizeof(qid));
> @@ -1483,7 +1504,10 @@ static void coroutine_fn v9fs_open(void *opaque)
> if (err < 0) {
> goto out;
> }
> - stat_to_qid(&stbuf, &qid);
> + err = stat_to_qid(pdu, &stbuf, &qid);
> + if (err < 0) {
> + goto out;
> + }
> if (S_ISDIR(stbuf.st_mode)) {
> err = v9fs_co_opendir(pdu, fidp);
> if (err < 0) {
> @@ -1593,7 +1617,10 @@ static void coroutine_fn v9fs_lcreate(void *opaque)
> fidp->flags |= FID_NON_RECLAIMABLE;
> }
> iounit = get_iounit(pdu, &fidp->path);
> - stat_to_qid(&stbuf, &qid);
> + err = stat_to_qid(pdu, &stbuf, &qid);
> + if (err < 0) {
> + goto out;
> + }
> err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
> if (err < 0) {
> goto out;
> @@ -2327,7 +2354,10 @@ static void coroutine_fn v9fs_create(void *opaque)
> }
> }
> iounit = get_iounit(pdu, &fidp->path);
> - stat_to_qid(&stbuf, &qid);
> + err = stat_to_qid(pdu, &stbuf, &qid);
> + if (err < 0) {
> + goto out;
> + }
> err = pdu_marshal(pdu, offset, "Qd", &qid, iounit);
> if (err < 0) {
> goto out;
> @@ -2384,7 +2414,10 @@ static void coroutine_fn v9fs_symlink(void *opaque)
> if (err < 0) {
> goto out;
> }
> - stat_to_qid(&stbuf, &qid);
> + err = stat_to_qid(pdu, &stbuf, &qid);
> + if (err < 0) {
> + goto out;
> + }
> err = pdu_marshal(pdu, offset, "Q", &qid);
> if (err < 0) {
> goto out;
> @@ -3064,7 +3097,10 @@ static void coroutine_fn v9fs_mknod(void *opaque)
> if (err < 0) {
> goto out;
> }
> - stat_to_qid(&stbuf, &qid);
> + err = stat_to_qid(pdu, &stbuf, &qid);
> + if (err < 0) {
> + goto out;
> + }
> err = pdu_marshal(pdu, offset, "Q", &qid);
> if (err < 0) {
> goto out;
> @@ -3222,7 +3258,10 @@ static void coroutine_fn v9fs_mkdir(void *opaque)
> if (err < 0) {
> goto out;
> }
> - stat_to_qid(&stbuf, &qid);
> + err = stat_to_qid(pdu, &stbuf, &qid);
> + if (err < 0) {
> + goto out;
> + }
> err = pdu_marshal(pdu, offset, "Q", &qid);
> if (err < 0) {
> goto out;
> @@ -3633,6 +3672,8 @@ int v9fs_device_realize_common(V9fsState *s, const V9fsTransport *t,
> goto out;
> }
>
> + s->dev_id = stat.st_dev;
> +
> s->ctx.fst = &fse->fst;
> fsdev_throttle_init(s->ctx.fst);
>
> diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h
> index 8883761b2c..5e316178d5 100644
> --- a/hw/9pfs/9p.h
> +++ b/hw/9pfs/9p.h
> @@ -256,6 +256,7 @@ struct V9fsState
> Error *migration_blocker;
> V9fsConf fsconf;
> V9fsQID root_qid;
> + dev_t dev_id;
> };
>
> /* 9p2000.L open flags */
next prev parent reply other threads:[~2019-07-31 20:31 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-07-03 11:44 [Qemu-devel] [PATCH v5 0/5] 9p: Fix file ID collisions Christian Schoenebeck via Qemu-devel
2019-07-03 10:55 ` [Qemu-devel] [PATCH v5 1/5] 9p: unsigned type for type, version, path Christian Schoenebeck via Qemu-devel
2019-07-31 19:14 ` Greg Kurz
2019-07-03 11:01 ` [Qemu-devel] [PATCH v5 2/5] 9p: Treat multiple devices on one export as an error Christian Schoenebeck via Qemu-devel
2019-07-31 20:30 ` Greg Kurz [this message]
2019-07-03 11:13 ` [Qemu-devel] [PATCH v5 3/5] 9p: Added virtfs option 'remap_inodes' Christian Schoenebeck via Qemu-devel
2019-07-06 10:22 ` Christian Schoenebeck via Qemu-devel
2019-08-30 11:48 ` Greg Kurz
2019-09-01 19:35 ` Christian Schoenebeck via Qemu-devel
2019-07-03 11:17 ` [Qemu-devel] [PATCH v5 4/5] 9p: stat_to_qid: implement slow path Christian Schoenebeck via Qemu-devel
2019-07-03 11:27 ` [Qemu-devel] [PATCH v5 5/5] 9p: Use variable length suffixes for inode remapping Christian Schoenebeck via Qemu-devel
2019-07-03 15:46 ` [Qemu-devel] [PATCH v5 0/5] 9p: Fix file ID collisions no-reply
2019-07-03 16:04 ` no-reply
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=20190731223057.3439026e@bahia.lan \
--to=groug@kaod.org \
--cc=antonios.motakis@huawei.com \
--cc=berrange@redhat.com \
--cc=dgilbert@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=qemu_oss@crudebyte.com \
--cc=stefanha@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.