[Virtio-fs] [PATCH v8 1/3] virtiofsd: add .ioctl() support

Jeffle Xu jefflexu at linux.alibaba.com
Mon May 16 03:39:04 UTC 2022


Support FS_IOC_[G|S]ETFLAGS and FS_IOC_FS[G|S]ETXATTR ioctls in prep
for the following per-inode DAX feature.

Currently only quering and setting FS_DAX_FL/FS_XFLAG_DAX flag are
supported for security concern. The restriction can be relaxed if it
is needed later.

Signed-off-by: Jeffle Xu <jefflexu at linux.alibaba.com>
---
 tools/virtiofsd/passthrough_ll.c      | 121 ++++++++++++++++++++++++++
 tools/virtiofsd/passthrough_seccomp.c |   1 +
 2 files changed, 122 insertions(+)

diff --git a/tools/virtiofsd/passthrough_ll.c b/tools/virtiofsd/passthrough_ll.c
index b7c1fa71b5..f52398f1f4 100644
--- a/tools/virtiofsd/passthrough_ll.c
+++ b/tools/virtiofsd/passthrough_ll.c
@@ -47,6 +47,7 @@
 #include <dirent.h>
 #include <pthread.h>
 #include <sys/file.h>
+#include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <sys/prctl.h>
 #include <sys/resource.h>
@@ -54,6 +55,7 @@
 #include <sys/wait.h>
 #include <sys/xattr.h>
 #include <syslog.h>
+#include <linux/fs.h>
 
 #include "qemu/cutils.h"
 #include "passthrough_helpers.h"
@@ -2188,6 +2190,124 @@ out:
     fuse_reply_err(req, saverr);
 }
 
+static int lo_ioctl_write(int fd, unsigned int cmd, const void *in_buf)
+{
+    int res = 0;
+
+    if (cmd == FS_IOC_SETFLAGS) {
+        const unsigned int *in_flags = in_buf;
+        unsigned int flags;
+
+        res = ioctl(fd, FS_IOC_GETFLAGS, &flags);
+        if (res < 0) {
+            return errno;
+        }
+
+        if (*in_flags & FS_DAX_FL) {
+            flags |= FS_DAX_FL;
+        } else {
+            flags &= ~FS_DAX_FL;
+        }
+
+        res = ioctl(fd, cmd, &flags);
+    } else if (cmd == FS_IOC_FSSETXATTR) {
+        const struct fsxattr *in_xfa = in_buf;
+        struct fsxattr xfa;
+
+        res = ioctl(fd, FS_IOC_FSGETXATTR, &xfa);
+        if (res < 0) {
+            return errno;
+        }
+
+        if (in_xfa->fsx_xflags & FS_XFLAG_DAX) {
+            xfa.fsx_xflags |= FS_XFLAG_DAX;
+        } else {
+            xfa.fsx_xflags &= ~FS_XFLAG_DAX;
+        }
+
+        res = ioctl(fd, cmd, &xfa);
+    }
+
+    return res < 0 ? errno : 0;
+}
+
+static int lo_ioctl_read(int fd, unsigned int cmd, size_t out_bufsz,
+                         void **out_buf)
+{
+    int res;
+    void *buf = NULL;
+
+    buf = malloc(out_bufsz);
+    if (!buf) {
+        return errno;
+    }
+
+    res = ioctl(fd, cmd, buf);
+    if (res < 0) {
+        free(buf);
+        return errno;
+    }
+
+    if (cmd == FS_IOC_GETFLAGS) {
+        unsigned int *flags = buf;
+
+        *flags = *flags & FS_DAX_FL;
+    } else if (cmd == FS_IOC_FSGETXATTR) {
+        struct fsxattr *xfa = buf;
+
+        *xfa = (struct fsxattr) {
+            .fsx_xflags = xfa->fsx_xflags & FS_XFLAG_DAX,
+        };
+    }
+
+    *out_buf = buf;
+    return 0;
+}
+
+static void lo_ioctl(fuse_req_t req, fuse_ino_t ino, unsigned int cmd,
+                     void *arg, struct fuse_file_info *fi,
+                     unsigned flags, const void *in_buf,
+                     size_t in_bufsz, size_t out_bufsz)
+{
+    int fd = lo_fi_fd(req, fi);
+    int res = ENOSYS;
+    void *buf = NULL;
+    size_t size = 0;
+
+    fuse_log(FUSE_LOG_DEBUG, "lo_ioctl(ino=%" PRIu64 ", cmd=0x%x, flags=0x%x, "
+            "in_bufsz = %lu, out_bufsz = %lu)\n",
+            ino, cmd, flags, in_bufsz, out_bufsz);
+
+    /*
+     * Unrestricted ioctl is not supported yet.
+     * Currently only quering and setting FS_DAX_FL/FS_XFLAG_DAX flag are
+     * supported to enable per-inode DAX feature. The restriction can be
+     * relaxed if it's needed later.
+     */
+    if (flags & FUSE_IOCTL_UNRESTRICTED ||
+        !(cmd == FS_IOC_SETFLAGS || cmd == FS_IOC_GETFLAGS ||
+          cmd == FS_IOC_FSSETXATTR || cmd == FS_IOC_FSGETXATTR)) {
+        fuse_log(FUSE_LOG_DEBUG, "unsupported cmd %u, flags %x\n", cmd, flags);
+        goto err;
+    }
+
+    if (_IOC_DIR(cmd) == _IOC_READ) {
+        size = out_bufsz;
+        res = lo_ioctl_read(fd, cmd, out_bufsz, &buf);
+    } else if (_IOC_DIR(cmd) == _IOC_WRITE) {
+        res = lo_ioctl_write(fd, cmd, in_buf);
+    }
+    if (res) {
+        goto err;
+    }
+
+    fuse_reply_ioctl(req, 0, buf, size);
+    free(buf);
+    return;
+err:
+    fuse_reply_err(req, res);
+}
+
 static void lo_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
                         struct fuse_file_info *fi)
 {
@@ -3474,6 +3594,7 @@ static struct fuse_lowlevel_ops lo_oper = {
     .fsyncdir = lo_fsyncdir,
     .create = lo_create,
     .getlk = lo_getlk,
+    .ioctl = lo_ioctl,
     .setlk = lo_setlk,
     .open = lo_open,
     .release = lo_release,
diff --git a/tools/virtiofsd/passthrough_seccomp.c b/tools/virtiofsd/passthrough_seccomp.c
index f49ed94b5e..eaed5b151b 100644
--- a/tools/virtiofsd/passthrough_seccomp.c
+++ b/tools/virtiofsd/passthrough_seccomp.c
@@ -62,6 +62,7 @@ static const int syscall_allowlist[] = {
     SCMP_SYS(gettid),
     SCMP_SYS(gettimeofday),
     SCMP_SYS(getxattr),
+    SCMP_SYS(ioctl),
     SCMP_SYS(linkat),
     SCMP_SYS(listxattr),
     SCMP_SYS(lseek),
-- 
2.27.0



More information about the Virtio-fs mailing list