render / rpms / qemu

Forked from rpms/qemu 8 months ago
Clone

Blame 0054-virtiofsd-check-input-buffer-size-in-fuse_lowlevel.c.patch

1d442b
From: Stefan Hajnoczi <stefanha@redhat.com>
1d442b
Date: Mon, 27 Jan 2020 19:01:23 +0000
1d442b
Subject: [PATCH] virtiofsd: check input buffer size in fuse_lowlevel.c ops
1d442b
1d442b
Each FUSE operation involves parsing the input buffer.  Currently the
1d442b
code assumes the input buffer is large enough for the expected
1d442b
arguments.  This patch uses fuse_mbuf_iter to check the size.
1d442b
1d442b
Most operations are simple to convert.  Some are more complicated due to
1d442b
variable-length inputs or different sizes depending on the protocol
1d442b
version.
1d442b
1d442b
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
1d442b
Reviewed-by: Sergio Lopez <slp@redhat.com>
1d442b
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
1d442b
(cherry picked from commit 70995754416eb4491c31607fe380a83cfd25a087)
1d442b
---
1d442b
 tools/virtiofsd/fuse_lowlevel.c | 581 +++++++++++++++++++++++++-------
1d442b
 1 file changed, 456 insertions(+), 125 deletions(-)
1d442b
1d442b
diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
1d442b
index 611e8b0354..02e1d83038 100644
1d442b
--- a/tools/virtiofsd/fuse_lowlevel.c
1d442b
+++ b/tools/virtiofsd/fuse_lowlevel.c
1d442b
@@ -19,6 +19,7 @@
1d442b
 #include <assert.h>
1d442b
 #include <errno.h>
1d442b
 #include <limits.h>
1d442b
+#include <stdbool.h>
1d442b
 #include <stddef.h>
1d442b
 #include <stdio.h>
1d442b
 #include <stdlib.h>
1d442b
@@ -27,7 +28,6 @@
1d442b
 #include <unistd.h>
1d442b
 
1d442b
 
1d442b
-#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg)))
1d442b
 #define OFFSET_MAX 0x7fffffffffffffffLL
1d442b
 
1d442b
 struct fuse_pollhandle {
1d442b
@@ -706,9 +706,14 @@ int fuse_reply_lseek(fuse_req_t req, off_t off)
1d442b
     return send_reply_ok(req, &arg, sizeof(arg));
1d442b
 }
1d442b
 
1d442b
-static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_lookup(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                      struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    char *name = (char *)inarg;
1d442b
+    const char *name = fuse_mbuf_iter_advance_str(iter);
1d442b
+    if (!name) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.lookup) {
1d442b
         req->se->op.lookup(req, nodeid, name);
1d442b
@@ -717,9 +722,16 @@ static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_forget(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                      struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_forget_in *arg = (struct fuse_forget_in *)inarg;
1d442b
+    struct fuse_forget_in *arg;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.forget) {
1d442b
         req->se->op.forget(req, nodeid, arg->nlookup);
1d442b
@@ -729,20 +741,48 @@ static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
 }
1d442b
 
1d442b
 static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
1d442b
-                            const void *inarg)
1d442b
+                            struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_batch_forget_in *arg = (void *)inarg;
1d442b
-    struct fuse_forget_one *param = (void *)PARAM(arg);
1d442b
-    unsigned int i;
1d442b
+    struct fuse_batch_forget_in *arg;
1d442b
+    struct fuse_forget_data *forgets;
1d442b
+    size_t scount;
1d442b
 
1d442b
     (void)nodeid;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_none(req);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
+    /*
1d442b
+     * Prevent integer overflow.  The compiler emits the following warning
1d442b
+     * unless we use the scount local variable:
1d442b
+     *
1d442b
+     * error: comparison is always false due to limited range of data type
1d442b
+     * [-Werror=type-limits]
1d442b
+     *
1d442b
+     * This may be true on 64-bit hosts but we need this check for 32-bit
1d442b
+     * hosts.
1d442b
+     */
1d442b
+    scount = arg->count;
1d442b
+    if (scount > SIZE_MAX / sizeof(forgets[0])) {
1d442b
+        fuse_reply_none(req);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
+    forgets = fuse_mbuf_iter_advance(iter, arg->count * sizeof(forgets[0]));
1d442b
+    if (!forgets) {
1d442b
+        fuse_reply_none(req);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     if (req->se->op.forget_multi) {
1d442b
-        req->se->op.forget_multi(req, arg->count,
1d442b
-                                 (struct fuse_forget_data *)param);
1d442b
+        req->se->op.forget_multi(req, arg->count, forgets);
1d442b
     } else if (req->se->op.forget) {
1d442b
+        unsigned int i;
1d442b
+
1d442b
         for (i = 0; i < arg->count; i++) {
1d442b
-            struct fuse_forget_one *forget = &param[i];
1d442b
             struct fuse_req *dummy_req;
1d442b
 
1d442b
             dummy_req = fuse_ll_alloc_req(req->se);
1d442b
@@ -754,7 +794,7 @@ static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
1d442b
             dummy_req->ctx = req->ctx;
1d442b
             dummy_req->ch = NULL;
1d442b
 
1d442b
-            req->se->op.forget(dummy_req, forget->nodeid, forget->nlookup);
1d442b
+            req->se->op.forget(dummy_req, forgets[i].ino, forgets[i].nlookup);
1d442b
         }
1d442b
         fuse_reply_none(req);
1d442b
     } else {
1d442b
@@ -762,12 +802,19 @@ static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid,
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_getattr(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                       struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
     struct fuse_file_info *fip = NULL;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
-    struct fuse_getattr_in *arg = (struct fuse_getattr_in *)inarg;
1d442b
+    struct fuse_getattr_in *arg;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (arg->getattr_flags & FUSE_GETATTR_FH) {
1d442b
         memset(&fi, 0, sizeof(fi));
1d442b
@@ -782,14 +829,21 @@ static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_setattr(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                       struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_setattr_in *arg = (struct fuse_setattr_in *)inarg;
1d442b
-
1d442b
     if (req->se->op.setattr) {
1d442b
+        struct fuse_setattr_in *arg;
1d442b
         struct fuse_file_info *fi = NULL;
1d442b
         struct fuse_file_info fi_store;
1d442b
         struct stat stbuf;
1d442b
+
1d442b
+        arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+        if (!arg) {
1d442b
+            fuse_reply_err(req, EINVAL);
1d442b
+            return;
1d442b
+        }
1d442b
+
1d442b
         memset(&stbuf, 0, sizeof(stbuf));
1d442b
         convert_attr(arg, &stbuf);
1d442b
         if (arg->valid & FATTR_FH) {
1d442b
@@ -810,9 +864,16 @@ static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_access(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                      struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_access_in *arg = (struct fuse_access_in *)inarg;
1d442b
+    struct fuse_access_in *arg;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.access) {
1d442b
         req->se->op.access(req, nodeid, arg->mask);
1d442b
@@ -821,9 +882,10 @@ static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_readlink(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                        struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    (void)inarg;
1d442b
+    (void)iter;
1d442b
 
1d442b
     if (req->se->op.readlink) {
1d442b
         req->se->op.readlink(req, nodeid);
1d442b
@@ -832,10 +894,18 @@ static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_mknod(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                     struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_mknod_in *arg = (struct fuse_mknod_in *)inarg;
1d442b
-    char *name = PARAM(arg);
1d442b
+    struct fuse_mknod_in *arg;
1d442b
+    const char *name;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    name = fuse_mbuf_iter_advance_str(iter);
1d442b
+    if (!arg || !name) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     req->ctx.umask = arg->umask;
1d442b
 
1d442b
@@ -846,22 +916,37 @@ static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                     struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_mkdir_in *arg = (struct fuse_mkdir_in *)inarg;
1d442b
+    struct fuse_mkdir_in *arg;
1d442b
+    const char *name;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    name = fuse_mbuf_iter_advance_str(iter);
1d442b
+    if (!arg || !name) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     req->ctx.umask = arg->umask;
1d442b
 
1d442b
     if (req->se->op.mkdir) {
1d442b
-        req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode);
1d442b
+        req->se->op.mkdir(req, nodeid, name, arg->mode);
1d442b
     } else {
1d442b
         fuse_reply_err(req, ENOSYS);
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_unlink(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                      struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    char *name = (char *)inarg;
1d442b
+    const char *name = fuse_mbuf_iter_advance_str(iter);
1d442b
+
1d442b
+    if (!name) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.unlink) {
1d442b
         req->se->op.unlink(req, nodeid, name);
1d442b
@@ -870,9 +955,15 @@ static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                     struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    char *name = (char *)inarg;
1d442b
+    const char *name = fuse_mbuf_iter_advance_str(iter);
1d442b
+
1d442b
+    if (!name) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.rmdir) {
1d442b
         req->se->op.rmdir(req, nodeid, name);
1d442b
@@ -881,10 +972,16 @@ static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_symlink(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                       struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    char *name = (char *)inarg;
1d442b
-    char *linkname = ((char *)inarg) + strlen((char *)inarg) + 1;
1d442b
+    const char *name = fuse_mbuf_iter_advance_str(iter);
1d442b
+    const char *linkname = fuse_mbuf_iter_advance_str(iter);
1d442b
+
1d442b
+    if (!name || !linkname) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.symlink) {
1d442b
         req->se->op.symlink(req, linkname, nodeid, name);
1d442b
@@ -893,11 +990,20 @@ static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_rename(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                      struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_rename_in *arg = (struct fuse_rename_in *)inarg;
1d442b
-    char *oldname = PARAM(arg);
1d442b
-    char *newname = oldname + strlen(oldname) + 1;
1d442b
+    struct fuse_rename_in *arg;
1d442b
+    const char *oldname;
1d442b
+    const char *newname;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    oldname = fuse_mbuf_iter_advance_str(iter);
1d442b
+    newname = fuse_mbuf_iter_advance_str(iter);
1d442b
+    if (!arg || !oldname || !newname) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.rename) {
1d442b
         req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, 0);
1d442b
@@ -906,11 +1012,20 @@ static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_rename2(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                       struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_rename2_in *arg = (struct fuse_rename2_in *)inarg;
1d442b
-    char *oldname = PARAM(arg);
1d442b
-    char *newname = oldname + strlen(oldname) + 1;
1d442b
+    struct fuse_rename2_in *arg;
1d442b
+    const char *oldname;
1d442b
+    const char *newname;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    oldname = fuse_mbuf_iter_advance_str(iter);
1d442b
+    newname = fuse_mbuf_iter_advance_str(iter);
1d442b
+    if (!arg || !oldname || !newname) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.rename) {
1d442b
         req->se->op.rename(req, nodeid, oldname, arg->newdir, newname,
1d442b
@@ -920,24 +1035,38 @@ static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_link(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                    struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_link_in *arg = (struct fuse_link_in *)inarg;
1d442b
+    struct fuse_link_in *arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    const char *name = fuse_mbuf_iter_advance_str(iter);
1d442b
+
1d442b
+    if (!arg || !name) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.link) {
1d442b
-        req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg));
1d442b
+        req->se->op.link(req, arg->oldnodeid, nodeid, name);
1d442b
     } else {
1d442b
         fuse_reply_err(req, ENOSYS);
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_create(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                      struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_create_in *arg = (struct fuse_create_in *)inarg;
1d442b
-
1d442b
     if (req->se->op.create) {
1d442b
+        struct fuse_create_in *arg;
1d442b
         struct fuse_file_info fi;
1d442b
-        char *name = PARAM(arg);
1d442b
+        const char *name;
1d442b
+
1d442b
+        arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+        name = fuse_mbuf_iter_advance_str(iter);
1d442b
+        if (!arg || !name) {
1d442b
+            fuse_reply_err(req, EINVAL);
1d442b
+            return;
1d442b
+        }
1d442b
 
1d442b
         memset(&fi, 0, sizeof(fi));
1d442b
         fi.flags = arg->flags;
1d442b
@@ -950,11 +1079,18 @@ static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_open(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                    struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_open_in *arg = (struct fuse_open_in *)inarg;
1d442b
+    struct fuse_open_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.flags = arg->flags;
1d442b
 
1d442b
@@ -965,13 +1101,15 @@ static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_read(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                    struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
1d442b
-
1d442b
     if (req->se->op.read) {
1d442b
+        struct fuse_read_in *arg;
1d442b
         struct fuse_file_info fi;
1d442b
 
1d442b
+        arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+
1d442b
         memset(&fi, 0, sizeof(fi));
1d442b
         fi.fh = arg->fh;
1d442b
         fi.lock_owner = arg->lock_owner;
1d442b
@@ -982,11 +1120,24 @@ static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_write(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                     struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_write_in *arg = (struct fuse_write_in *)inarg;
1d442b
+    struct fuse_write_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
-    char *param;
1d442b
+    const char *param;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
+    param = fuse_mbuf_iter_advance(iter, arg->size);
1d442b
+    if (!param) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
@@ -994,7 +1145,6 @@ static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
 
1d442b
     fi.lock_owner = arg->lock_owner;
1d442b
     fi.flags = arg->flags;
1d442b
-    param = PARAM(arg);
1d442b
 
1d442b
     if (req->se->op.write) {
1d442b
         req->se->op.write(req, nodeid, param, arg->size, arg->offset, &fi);
1d442b
@@ -1052,11 +1202,18 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t nodeid,
1d442b
     se->op.write_buf(req, nodeid, pbufv, arg->offset, &fi);
1d442b
 }
1d442b
 
1d442b
-static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_flush(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                     struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_flush_in *arg = (struct fuse_flush_in *)inarg;
1d442b
+    struct fuse_flush_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
     fi.flush = 1;
1d442b
@@ -1069,19 +1226,26 @@ static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_release(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                       struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_release_in *arg = (struct fuse_release_in *)inarg;
1d442b
+    struct fuse_release_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.flags = arg->flags;
1d442b
     fi.fh = arg->fh;
1d442b
     fi.flush = (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0;
1d442b
     fi.lock_owner = arg->lock_owner;
1d442b
+
1d442b
     if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) {
1d442b
         fi.flock_release = 1;
1d442b
-        fi.lock_owner = arg->lock_owner;
1d442b
     }
1d442b
 
1d442b
     if (req->se->op.release) {
1d442b
@@ -1091,11 +1255,19 @@ static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_fsync(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                     struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_fsync_in *arg = (struct fuse_fsync_in *)inarg;
1d442b
+    struct fuse_fsync_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
-    int datasync = arg->fsync_flags & 1;
1d442b
+    int datasync;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+    datasync = arg->fsync_flags & 1;
1d442b
 
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
@@ -1111,11 +1283,18 @@ static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_opendir(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                       struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_open_in *arg = (struct fuse_open_in *)inarg;
1d442b
+    struct fuse_open_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.flags = arg->flags;
1d442b
 
1d442b
@@ -1126,11 +1305,18 @@ static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_readdir(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                       struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
1d442b
+    struct fuse_read_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
 
1d442b
@@ -1141,11 +1327,18 @@ static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                           struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_read_in *arg = (struct fuse_read_in *)inarg;
1d442b
+    struct fuse_read_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
 
1d442b
@@ -1156,11 +1349,18 @@ static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                          struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_release_in *arg = (struct fuse_release_in *)inarg;
1d442b
+    struct fuse_release_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.flags = arg->flags;
1d442b
     fi.fh = arg->fh;
1d442b
@@ -1172,11 +1372,19 @@ static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                        struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_fsync_in *arg = (struct fuse_fsync_in *)inarg;
1d442b
+    struct fuse_fsync_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
-    int datasync = arg->fsync_flags & 1;
1d442b
+    int datasync;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+    datasync = arg->fsync_flags & 1;
1d442b
 
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
@@ -1188,10 +1396,11 @@ static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_statfs(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                      struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
     (void)nodeid;
1d442b
-    (void)inarg;
1d442b
+    (void)iter;
1d442b
 
1d442b
     if (req->se->op.statfs) {
1d442b
         req->se->op.statfs(req, nodeid);
1d442b
@@ -1204,11 +1413,25 @@ static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                        struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_setxattr_in *arg = (struct fuse_setxattr_in *)inarg;
1d442b
-    char *name = PARAM(arg);
1d442b
-    char *value = name + strlen(name) + 1;
1d442b
+    struct fuse_setxattr_in *arg;
1d442b
+    const char *name;
1d442b
+    const char *value;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    name = fuse_mbuf_iter_advance_str(iter);
1d442b
+    if (!arg || !name) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
+    value = fuse_mbuf_iter_advance(iter, arg->size);
1d442b
+    if (!value) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.setxattr) {
1d442b
         req->se->op.setxattr(req, nodeid, name, value, arg->size, arg->flags);
1d442b
@@ -1217,20 +1440,36 @@ static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                        struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *)inarg;
1d442b
+    struct fuse_getxattr_in *arg;
1d442b
+    const char *name;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    name = fuse_mbuf_iter_advance_str(iter);
1d442b
+    if (!arg || !name) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.getxattr) {
1d442b
-        req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size);
1d442b
+        req->se->op.getxattr(req, nodeid, name, arg->size);
1d442b
     } else {
1d442b
         fuse_reply_err(req, ENOSYS);
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                         struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_getxattr_in *arg = (struct fuse_getxattr_in *)inarg;
1d442b
+    struct fuse_getxattr_in *arg;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.listxattr) {
1d442b
         req->se->op.listxattr(req, nodeid, arg->size);
1d442b
@@ -1239,9 +1478,15 @@ static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                           struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    char *name = (char *)inarg;
1d442b
+    const char *name = fuse_mbuf_iter_advance_str(iter);
1d442b
+
1d442b
+    if (!name) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.removexattr) {
1d442b
         req->se->op.removexattr(req, nodeid, name);
1d442b
@@ -1265,12 +1510,19 @@ static void convert_fuse_file_lock(struct fuse_file_lock *fl,
1d442b
     flock->l_pid = fl->pid;
1d442b
 }
1d442b
 
1d442b
-static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_getlk(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                     struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_lk_in *arg = (struct fuse_lk_in *)inarg;
1d442b
+    struct fuse_lk_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
     struct flock flock;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
     fi.lock_owner = arg->owner;
1d442b
@@ -1284,12 +1536,18 @@ static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
 }
1d442b
 
1d442b
 static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
1d442b
-                            const void *inarg, int sleep)
1d442b
+                            struct fuse_mbuf_iter *iter, int sleep)
1d442b
 {
1d442b
-    struct fuse_lk_in *arg = (struct fuse_lk_in *)inarg;
1d442b
+    struct fuse_lk_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
     struct flock flock;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
     fi.lock_owner = arg->owner;
1d442b
@@ -1327,14 +1585,16 @@ static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid,
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_setlk(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                     struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    do_setlk_common(req, nodeid, inarg, 0);
1d442b
+    do_setlk_common(req, nodeid, iter, 0);
1d442b
 }
1d442b
 
1d442b
-static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                      struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    do_setlk_common(req, nodeid, inarg, 1);
1d442b
+    do_setlk_common(req, nodeid, iter, 1);
1d442b
 }
1d442b
 
1d442b
 static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
1d442b
@@ -1379,12 +1639,20 @@ static int find_interrupted(struct fuse_session *se, struct fuse_req *req)
1d442b
     return 0;
1d442b
 }
1d442b
 
1d442b
-static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                         struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_interrupt_in *arg = (struct fuse_interrupt_in *)inarg;
1d442b
+    struct fuse_interrupt_in *arg;
1d442b
     struct fuse_session *se = req->se;
1d442b
 
1d442b
     (void)nodeid;
1d442b
+
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     if (se->debug) {
1d442b
         fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n",
1d442b
                  (unsigned long long)arg->unique);
1d442b
@@ -1425,9 +1693,15 @@ static struct fuse_req *check_interrupt(struct fuse_session *se,
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_bmap(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                    struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_bmap_in *arg = (struct fuse_bmap_in *)inarg;
1d442b
+    struct fuse_bmap_in *arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
 
1d442b
     if (req->se->op.bmap) {
1d442b
         req->se->op.bmap(req, nodeid, arg->blocksize, arg->block);
1d442b
@@ -1436,18 +1710,34 @@ static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                     struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_ioctl_in *arg = (struct fuse_ioctl_in *)inarg;
1d442b
-    unsigned int flags = arg->flags;
1d442b
-    void *in_buf = arg->in_size ? PARAM(arg) : NULL;
1d442b
+    struct fuse_ioctl_in *arg;
1d442b
+    unsigned int flags;
1d442b
+    void *in_buf = NULL;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
+    flags = arg->flags;
1d442b
     if (flags & FUSE_IOCTL_DIR && !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) {
1d442b
         fuse_reply_err(req, ENOTTY);
1d442b
         return;
1d442b
     }
1d442b
 
1d442b
+    if (arg->in_size) {
1d442b
+        in_buf = fuse_mbuf_iter_advance(iter, arg->in_size);
1d442b
+        if (!in_buf) {
1d442b
+            fuse_reply_err(req, EINVAL);
1d442b
+            return;
1d442b
+        }
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
 
1d442b
@@ -1468,11 +1758,18 @@ void fuse_pollhandle_destroy(struct fuse_pollhandle *ph)
1d442b
     free(ph);
1d442b
 }
1d442b
 
1d442b
-static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_poll(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                    struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_poll_in *arg = (struct fuse_poll_in *)inarg;
1d442b
+    struct fuse_poll_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
     fi.poll_events = arg->events;
1d442b
@@ -1496,11 +1793,18 @@ static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                         struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_fallocate_in *arg = (struct fuse_fallocate_in *)inarg;
1d442b
+    struct fuse_fallocate_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
 
1d442b
@@ -1513,12 +1817,17 @@ static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
 }
1d442b
 
1d442b
 static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
1d442b
-                               const void *inarg)
1d442b
+                               struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_copy_file_range_in *arg =
1d442b
-        (struct fuse_copy_file_range_in *)inarg;
1d442b
+    struct fuse_copy_file_range_in *arg;
1d442b
     struct fuse_file_info fi_in, fi_out;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
     memset(&fi_in, 0, sizeof(fi_in));
1d442b
     fi_in.fh = arg->fh_in;
1d442b
 
1d442b
@@ -1535,11 +1844,17 @@ static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in,
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_lseek(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                     struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_lseek_in *arg = (struct fuse_lseek_in *)inarg;
1d442b
+    struct fuse_lseek_in *arg;
1d442b
     struct fuse_file_info fi;
1d442b
 
1d442b
+    arg = fuse_mbuf_iter_advance(iter, sizeof(*arg));
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
     memset(&fi, 0, sizeof(fi));
1d442b
     fi.fh = arg->fh;
1d442b
 
1d442b
@@ -1550,15 +1865,33 @@ static void do_lseek(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     }
1d442b
 }
1d442b
 
1d442b
-static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_init(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                    struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
-    struct fuse_init_in *arg = (struct fuse_init_in *)inarg;
1d442b
+    size_t compat_size = offsetof(struct fuse_init_in, max_readahead);
1d442b
+    struct fuse_init_in *arg;
1d442b
     struct fuse_init_out outarg;
1d442b
     struct fuse_session *se = req->se;
1d442b
     size_t bufsize = se->bufsize;
1d442b
     size_t outargsize = sizeof(outarg);
1d442b
 
1d442b
     (void)nodeid;
1d442b
+
1d442b
+    /* First consume the old fields... */
1d442b
+    arg = fuse_mbuf_iter_advance(iter, compat_size);
1d442b
+    if (!arg) {
1d442b
+        fuse_reply_err(req, EINVAL);
1d442b
+        return;
1d442b
+    }
1d442b
+
1d442b
+    /* ...and now consume the new fields. */
1d442b
+    if (arg->major == 7 && arg->minor >= 6) {
1d442b
+        if (!fuse_mbuf_iter_advance(iter, sizeof(*arg) - compat_size)) {
1d442b
+            fuse_reply_err(req, EINVAL);
1d442b
+            return;
1d442b
+        }
1d442b
+    }
1d442b
+
1d442b
     if (se->debug) {
1d442b
         fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor);
1d442b
         if (arg->major == 7 && arg->minor >= 6) {
1d442b
@@ -1791,12 +2124,13 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
     send_reply_ok(req, &outarg, outargsize);
1d442b
 }
1d442b
 
1d442b
-static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
1d442b
+static void do_destroy(fuse_req_t req, fuse_ino_t nodeid,
1d442b
+                       struct fuse_mbuf_iter *iter)
1d442b
 {
1d442b
     struct fuse_session *se = req->se;
1d442b
 
1d442b
     (void)nodeid;
1d442b
-    (void)inarg;
1d442b
+    (void)iter;
1d442b
 
1d442b
     se->got_destroy = 1;
1d442b
     if (se->op.destroy) {
1d442b
@@ -1976,7 +2310,7 @@ int fuse_req_interrupted(fuse_req_t req)
1d442b
 }
1d442b
 
1d442b
 static struct {
1d442b
-    void (*func)(fuse_req_t, fuse_ino_t, const void *);
1d442b
+    void (*func)(fuse_req_t, fuse_ino_t, struct fuse_mbuf_iter *);
1d442b
     const char *name;
1d442b
 } fuse_ll_ops[] = {
1d442b
     [FUSE_LOOKUP] = { do_lookup, "LOOKUP" },
1d442b
@@ -2060,7 +2394,6 @@ void fuse_session_process_buf_int(struct fuse_session *se,
1d442b
     const struct fuse_buf *buf = bufv->buf;
1d442b
     struct fuse_mbuf_iter iter = FUSE_MBUF_ITER_INIT(buf);
1d442b
     struct fuse_in_header *in;
1d442b
-    const void *inarg;
1d442b
     struct fuse_req *req;
1d442b
     int err;
1d442b
 
1d442b
@@ -2138,13 +2471,11 @@ void fuse_session_process_buf_int(struct fuse_session *se,
1d442b
         }
1d442b
     }
1d442b
 
1d442b
-    inarg = (void *)&in[1];
1d442b
     if (in->opcode == FUSE_WRITE && se->op.write_buf) {
1d442b
         do_write_buf(req, in->nodeid, &iter, bufv);
1d442b
     } else {
1d442b
-        fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg);
1d442b
+        fuse_ll_ops[in->opcode].func(req, in->nodeid, &iter);
1d442b
     }
1d442b
-
1d442b
     return;
1d442b
 
1d442b
 reply_err: