From 5afc8df46cdf1a10fc44d43208cf449357009d2a Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Wed, 22 Sep 2021 15:02:01 -0400 Subject: [PATCH 1/5] virtiofsd: xattr mapping add a new type "unsupported" Right now for xattr remapping, we support types of "prefix", "ok" or "bad". Type "bad" returns -EPERM on setxattr and hides xattr in listxattr. For getxattr, mapping code returns -EPERM but getxattr code converts it to -ENODATA. I need a new semantics where if an xattr is unsupported, then getxattr()/setxattr() return -ENOTSUP and listxattr() should hide the xattr. This is needed to simulate that security.selinux is not supported by virtiofs filesystem and in that case client falls back to some default label specified by policy. So add a new type "unsupported" which returns -ENOTSUP on getxattr() and setxattr() and hides xattrs in listxattr(). For example, one can use following mapping rule to not support security.selinux xattr and allow others. "-o xattrmap=/unsupported/all/security.selinux/security.selinux//ok/all///" Suggested-by: "Dr. David Alan Gilbert" Signed-off-by: Vivek Goyal Message-Id: Reviewed-by: Dr. David Alan Gilbert Signed-off-by: Dr. David Alan Gilbert --- docs/tools/virtiofsd.rst | 6 ++++++ tools/virtiofsd/passthrough_ll.c | 17 ++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst index b208f2a6f0..cc31402830 100644 --- a/docs/tools/virtiofsd.rst +++ b/docs/tools/virtiofsd.rst @@ -183,6 +183,12 @@ Using ':' as the separator a rule is of the form: 'ok' as either an explicit terminator or for special handling of certain patterns. +- 'unsupported' - If a client tries to use a name matching 'key' it's + denied using ENOTSUP; when the server passes an attribute + name matching 'prepend' it's hidden. In many ways it's use is very like + 'ok' as either an explicit terminator or for special handling of certain + patterns. + **key** is a string tested as a prefix on an attribute name originating on the client. It maybe empty in which case a 'client' rule will always match on client names. diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c index 38b2af8599..64b5b4fbb1 100644 --- a/tools/virtiofsd/passthrough_ll.c +++ b/tools/virtiofsd/passthrough_ll.c @@ -2465,6 +2465,11 @@ static void lo_flock(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi, * Automatically reversed on read */ #define XATTR_MAP_FLAG_PREFIX (1 << 2) +/* + * The attribute is unsupported; + * ENOTSUP on write, hidden on read. + */ +#define XATTR_MAP_FLAG_UNSUPPORTED (1 << 3) /* scopes */ /* Apply rule to get/set/remove */ @@ -2636,6 +2641,8 @@ static void parse_xattrmap(struct lo_data *lo) tmp_entry.flags |= XATTR_MAP_FLAG_OK; } else if (strstart(map, "bad", &map)) { tmp_entry.flags |= XATTR_MAP_FLAG_BAD; + } else if (strstart(map, "unsupported", &map)) { + tmp_entry.flags |= XATTR_MAP_FLAG_UNSUPPORTED; } else if (strstart(map, "map", &map)) { /* * map is sugar that adds a number of rules, and must be @@ -2646,8 +2653,8 @@ static void parse_xattrmap(struct lo_data *lo) } else { fuse_log(FUSE_LOG_ERR, "%s: Unexpected type;" - "Expecting 'prefix', 'ok', 'bad' or 'map' in rule %zu\n", - __func__, lo->xattr_map_nentries); + "Expecting 'prefix', 'ok', 'bad', 'unsupported' or 'map'" + " in rule %zu\n", __func__, lo->xattr_map_nentries); exit(1); } @@ -2749,6 +2756,9 @@ static int xattr_map_client(const struct lo_data *lo, const char *client_name, if (cur_entry->flags & XATTR_MAP_FLAG_BAD) { return -EPERM; } + if (cur_entry->flags & XATTR_MAP_FLAG_UNSUPPORTED) { + return -ENOTSUP; + } if (cur_entry->flags & XATTR_MAP_FLAG_OK) { /* Unmodified name */ return 0; @@ -2788,7 +2798,8 @@ static int xattr_map_server(const struct lo_data *lo, const char *server_name, if ((cur_entry->flags & XATTR_MAP_FLAG_SERVER) && (strstart(server_name, cur_entry->prepend, &end))) { - if (cur_entry->flags & XATTR_MAP_FLAG_BAD) { + if (cur_entry->flags & XATTR_MAP_FLAG_BAD || + cur_entry->flags & XATTR_MAP_FLAG_UNSUPPORTED) { return -ENODATA; } if (cur_entry->flags & XATTR_MAP_FLAG_OK) { From a88abc6f841ea7f0a9c57d69ccf133e2c7d12348 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Thu, 30 Sep 2021 11:30:27 -0400 Subject: [PATCH 2/5] virtiofsd: Remove unused virtio_fs_config definition "struct virtio_fs_config" definition seems to be unused in fuse_virtio.c. Remove it. Signed-off-by: Vivek Goyal Message-Id: <20210930153037.1194279-4-vgoyal@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/fuse_virtio.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c index 8f4fd165b9..da7b6a76bf 100644 --- a/tools/virtiofsd/fuse_virtio.c +++ b/tools/virtiofsd/fuse_virtio.c @@ -82,12 +82,6 @@ struct fv_VuDev { struct fv_QueueInfo **qi; }; -/* From spec */ -struct virtio_fs_config { - char tag[36]; - uint32_t num_queues; -}; - /* Callback from libvhost-user */ static uint64_t fv_get_features(VuDev *dev) { From c68276556a1e6e035f9a27d0dbb2f87b349f3aea Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Thu, 30 Sep 2021 11:30:28 -0400 Subject: [PATCH 3/5] virtiofsd: Add a helper to send element on virtqueue We have open coded logic to take locks and push element on virtqueue at three places. Add a helper and use it everywhere. Code is easier to read and less number of lines of code. Signed-off-by: Vivek Goyal Message-Id: <20210930153037.1194279-5-vgoyal@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/fuse_virtio.c | 45 ++++++++++++++--------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c index da7b6a76bf..fcf12db9cd 100644 --- a/tools/virtiofsd/fuse_virtio.c +++ b/tools/virtiofsd/fuse_virtio.c @@ -243,6 +243,21 @@ static void vu_dispatch_unlock(struct fv_VuDev *vud) assert(ret == 0); } +static void vq_send_element(struct fv_QueueInfo *qi, VuVirtqElement *elem, + ssize_t len) +{ + struct fuse_session *se = qi->virtio_dev->se; + VuDev *dev = &se->virtio_dev->dev; + VuVirtq *q = vu_get_queue(dev, qi->qidx); + + vu_dispatch_rdlock(qi->virtio_dev); + pthread_mutex_lock(&qi->vq_lock); + vu_queue_push(dev, q, elem, len); + vu_queue_notify(dev, q); + pthread_mutex_unlock(&qi->vq_lock); + vu_dispatch_unlock(qi->virtio_dev); +} + /* * Called back by ll whenever it wants to send a reply/message back * The 1st element of the iov starts with the fuse_out_header @@ -253,8 +268,6 @@ int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch, { FVRequest *req = container_of(ch, FVRequest, ch); struct fv_QueueInfo *qi = ch->qi; - VuDev *dev = &se->virtio_dev->dev; - VuVirtq *q = vu_get_queue(dev, qi->qidx); VuVirtqElement *elem = &req->elem; int ret = 0; @@ -296,13 +309,7 @@ int virtio_send_msg(struct fuse_session *se, struct fuse_chan *ch, copy_iov(iov, count, in_sg, in_num, tosend_len); - vu_dispatch_rdlock(qi->virtio_dev); - pthread_mutex_lock(&qi->vq_lock); - vu_queue_push(dev, q, elem, tosend_len); - vu_queue_notify(dev, q); - pthread_mutex_unlock(&qi->vq_lock); - vu_dispatch_unlock(qi->virtio_dev); - + vq_send_element(qi, elem, tosend_len); req->reply_sent = true; err: @@ -321,8 +328,6 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, { FVRequest *req = container_of(ch, FVRequest, ch); struct fv_QueueInfo *qi = ch->qi; - VuDev *dev = &se->virtio_dev->dev; - VuVirtq *q = vu_get_queue(dev, qi->qidx); VuVirtqElement *elem = &req->elem; int ret = 0; g_autofree struct iovec *in_sg_cpy = NULL; @@ -430,12 +435,7 @@ int virtio_send_data_iov(struct fuse_session *se, struct fuse_chan *ch, out_sg->len = tosend_len; } - vu_dispatch_rdlock(qi->virtio_dev); - pthread_mutex_lock(&qi->vq_lock); - vu_queue_push(dev, q, elem, tosend_len); - vu_queue_notify(dev, q); - pthread_mutex_unlock(&qi->vq_lock); - vu_dispatch_unlock(qi->virtio_dev); + vq_send_element(qi, elem, tosend_len); req->reply_sent = true; return 0; } @@ -447,7 +447,6 @@ static void fv_queue_worker(gpointer data, gpointer user_data) { struct fv_QueueInfo *qi = user_data; struct fuse_session *se = qi->virtio_dev->se; - struct VuDev *dev = &qi->virtio_dev->dev; FVRequest *req = data; VuVirtqElement *elem = &req->elem; struct fuse_buf fbuf = {}; @@ -589,17 +588,9 @@ out: /* If the request has no reply, still recycle the virtqueue element */ if (!req->reply_sent) { - struct VuVirtq *q = vu_get_queue(dev, qi->qidx); - fuse_log(FUSE_LOG_DEBUG, "%s: elem %d no reply sent\n", __func__, elem->index); - - vu_dispatch_rdlock(qi->virtio_dev); - pthread_mutex_lock(&qi->vq_lock); - vu_queue_push(dev, q, elem, 0); - vu_queue_notify(dev, q); - pthread_mutex_unlock(&qi->vq_lock); - vu_dispatch_unlock(qi->virtio_dev); + vq_send_element(qi, elem, 0); } pthread_mutex_destroy(&req->ch.lock); From 50cf6d6cb7b6b0e43f626da2a65d7277add21bd9 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Thu, 30 Sep 2021 11:30:29 -0400 Subject: [PATCH 4/5] virtiofsd: Add a helper to stop all queues Use a helper to stop all the queues. Later in the patch series I am planning to use this helper at one more place later in the patch series. Signed-off-by: Vivek Goyal Message-Id: <20210930153037.1194279-6-vgoyal@redhat.com> Reviewed-by: Stefan Hajnoczi Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/fuse_virtio.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c index fcf12db9cd..baead08b28 100644 --- a/tools/virtiofsd/fuse_virtio.c +++ b/tools/virtiofsd/fuse_virtio.c @@ -740,6 +740,18 @@ static void fv_queue_cleanup_thread(struct fv_VuDev *vud, int qidx) vud->qi[qidx] = NULL; } +static void stop_all_queues(struct fv_VuDev *vud) +{ + for (int i = 0; i < vud->nqueues; i++) { + if (!vud->qi[i]) { + continue; + } + + fuse_log(FUSE_LOG_INFO, "%s: Stopping queue %d thread\n", __func__, i); + fv_queue_cleanup_thread(vud, i); + } +} + /* Callback from libvhost-user on start or stop of a queue */ static void fv_queue_set_started(VuDev *dev, int qidx, bool started) { @@ -870,15 +882,7 @@ int virtio_loop(struct fuse_session *se) * Make sure all fv_queue_thread()s quit on exit, as we're about to * free virtio dev and fuse session, no one should access them anymore. */ - for (int i = 0; i < se->virtio_dev->nqueues; i++) { - if (!se->virtio_dev->qi[i]) { - continue; - } - - fuse_log(FUSE_LOG_INFO, "%s: Stopping queue %d thread\n", __func__, i); - fv_queue_cleanup_thread(se->virtio_dev, i); - } - + stop_all_queues(se->virtio_dev); fuse_log(FUSE_LOG_INFO, "%s: Exit\n", __func__); return 0; From 555a76e5e5dc2cd3c84c5e1bc060be17d5b32584 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 14 Oct 2021 13:25:54 +0100 Subject: [PATCH 5/5] virtiofsd: Error on bad socket group name Make the '--socket-group=' option fail if the group name is unknown: ./tools/virtiofsd/virtiofsd .... --socket-group=zaphod vhost socket: unable to find group 'zaphod' Reported-by: Xiaoling Gao Signed-off-by: Dr. David Alan Gilbert Message-Id: <20211014122554.34599-1-dgilbert@redhat.com> Reviewed-by: Vivek Goyal Signed-off-by: Dr. David Alan Gilbert --- tools/virtiofsd/fuse_virtio.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c index baead08b28..60b96470c5 100644 --- a/tools/virtiofsd/fuse_virtio.c +++ b/tools/virtiofsd/fuse_virtio.c @@ -988,6 +988,13 @@ static int fv_create_listen_socket(struct fuse_session *se) "vhost socket failed to set group to %s (%d): %m\n", se->vu_socket_group, g->gr_gid); } + } else { + fuse_log(FUSE_LOG_ERR, + "vhost socket: unable to find group '%s'\n", + se->vu_socket_group); + close(listen_sock); + umask(old_umask); + return -1; } } umask(old_umask);