From nobody Sat Feb 7 09:38:15 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1571918150; cv=none; d=zoho.com; s=zohoarc; b=P4kRzKK/7YKNpmm7pskp/OY7mJd0lpmyftswLO7VKmAMIc/geKKb/H5rnew0am8JW4LscSCWyc45FIL272PmxZ+2c73gVpMMVRcXB8mAqIeWhMuj0vL6w2wX4qzT7JEVmb1r+Q22SvTERcI5ThJAv09Ys9oImmGYcqVq7I4oHng= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1571918150; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=ui2Y+ocRQxzzkeIX5ySyCoXwG2tfJlsb/HVTFRvxaB0=; b=dq7y3STqUI3sEwLdz446FOOkztYP37/yyABxXlvP++2oM2uTOOX5L2AxRcCXEwPDU2BrVi1KY7Ge3/oIy3KP9linamlRJJM9AvjnnISykKZdFK/mDXEbO9MncRjwmVhU+raLR4K04dx8H7QX1UTC5RtDtmluRf+7ctlwqN0sBSM= ARC-Authentication-Results: i=1; mx.zoho.com; dkim=pass; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1571918150364541.3247397670998; Thu, 24 Oct 2019 04:55:50 -0700 (PDT) Received: from localhost ([::1]:40364 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iNbiW-0002dL-Fb for importer@patchew.org; Thu, 24 Oct 2019 07:55:48 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:39374) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iNbHz-0003jE-Tb for qemu-devel@nongnu.org; Thu, 24 Oct 2019 07:28:30 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iNbHw-0008Ut-6d for qemu-devel@nongnu.org; Thu, 24 Oct 2019 07:28:23 -0400 Received: from us-smtp-1.mimecast.com ([205.139.110.61]:49108 helo=us-smtp-delivery-1.mimecast.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1iNbHw-0008Un-0Q for qemu-devel@nongnu.org; Thu, 24 Oct 2019 07:28:20 -0400 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-208-ZsT16eUzO9GvEtoYfm_RCg-1; Thu, 24 Oct 2019 07:28:14 -0400 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 6CC0A80183D; Thu, 24 Oct 2019 11:28:13 +0000 (UTC) Received: from dgilbert-t580.localhost (ovpn-117-248.ams2.redhat.com [10.36.117.248]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9EEF3196B2; Thu, 24 Oct 2019 11:28:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1571916499; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ui2Y+ocRQxzzkeIX5ySyCoXwG2tfJlsb/HVTFRvxaB0=; b=hHjME6zwXx1LKDlC/xt+ocqvqIOstHJdkA61rnzdgQtDV6qyzfiAlwcc09X6hOgKwydia7 6RICN9Dvh7wuW89FUmlLc1EWvFU+I65UWoQ1WuNQV9tV3fqu/S6XygwSN2GzHJJS6MVeqb gBJZ29MvENs2gDsua4FKV+VoPtHMzyk= From: "Dr. David Alan Gilbert (git)" To: qemu-devel@nongnu.org, renzhen@linux.alibaba.com, eguan@linux.alibaba.com, ganesh.mahalingam@intel.com, m.mizuma@jp.fujitsu.com, mszeredi@redhat.com, misono.tomohiro@jp.fujitsu.com, tao.peng@linux.alibaba.com, piaojun@huawei.com, stefanha@redhat.com, vgoyal@redhat.com, mst@redhat.com, berrange@redhat.com Subject: [PATCH 12/25] virtiofsd: check input buffer size in fuse_lowlevel.c ops Date: Thu, 24 Oct 2019 12:27:05 +0100 Message-Id: <20191024112718.34657-13-dgilbert@redhat.com> In-Reply-To: <20191024112718.34657-1-dgilbert@redhat.com> References: <20191024112718.34657-1-dgilbert@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-MC-Unique: ZsT16eUzO9GvEtoYfm_RCg-1 X-Mimecast-Spam-Score: 0 Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 205.139.110.61 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @redhat.com) Content-Type: text/plain; charset="utf-8" From: Stefan Hajnoczi Each FUSE operation involves parsing the input buffer. Currently the code assumes the input buffer is large enough for the expected arguments. This patch uses fuse_mbuf_iter to check the size. Most operations are simple to convert. Some are more complicated due to variable-length inputs or different sizes depending on the protocol version. Signed-off-by: Stefan Hajnoczi --- contrib/virtiofsd/fuse_lowlevel.c | 621 +++++++++++++++++++++++------- 1 file changed, 482 insertions(+), 139 deletions(-) diff --git a/contrib/virtiofsd/fuse_lowlevel.c b/contrib/virtiofsd/fuse_low= level.c index 7927348398..d032e411e1 100644 --- a/contrib/virtiofsd/fuse_lowlevel.c +++ b/contrib/virtiofsd/fuse_lowlevel.c @@ -15,6 +15,7 @@ #include "fuse_misc.h" #include "fuse_virtio.h" =20 +#include #include #include #include @@ -27,7 +28,6 @@ =20 =20 =20 -#define PARAM(inarg) (((char *)(inarg)) + sizeof(*(inarg))) #define OFFSET_MAX 0x7fffffffffffffffLL =20 struct fuse_pollhandle { @@ -705,9 +705,14 @@ int fuse_reply_poll(fuse_req_t req, unsigned revents) return send_reply_ok(req, &arg, sizeof(arg)); } =20 -static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_lookup(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - char *name =3D (char *) inarg; + const char *name =3D fuse_mbuf_iter_advance_str(iter); + if (!name) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.lookup) req->se->op.lookup(req, nodeid, name); @@ -715,9 +720,16 @@ static void do_lookup(fuse_req_t req, fuse_ino_t nodei= d, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_forget(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_forget(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_forget_in *arg =3D (struct fuse_forget_in *) inarg; + struct fuse_forget_in *arg; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.forget) req->se->op.forget(req, nodeid, arg->nlookup); @@ -726,20 +738,47 @@ static void do_forget(fuse_req_t req, fuse_ino_t node= id, const void *inarg) } =20 static void do_batch_forget(fuse_req_t req, fuse_ino_t nodeid, - const void *inarg) + struct fuse_mbuf_iter *iter) { - struct fuse_batch_forget_in *arg =3D (void *) inarg; - struct fuse_forget_one *param =3D (void *) PARAM(arg); - unsigned int i; + struct fuse_batch_forget_in *arg; + struct fuse_forget_data *forgets; + size_t scount; =20 (void) nodeid; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_none(req); + } + + /* Prevent integer overflow. The compiler emits the following warning + * unless we use the scount local variable: + * + * error: comparison is always false due to limited range of data type + * [-Werror=3Dtype-limits] + * + * This may be true on 64-bit hosts but we need this check for 32-bit + * hosts. + */ + scount =3D arg->count; + if (scount > SIZE_MAX / sizeof(forgets[0])) { + fuse_reply_none(req); + return; + } + + forgets =3D fuse_mbuf_iter_advance(iter, arg->count * + sizeof(forgets[0])); + if (!forgets) { + fuse_reply_none(req); + return; + } + if (req->se->op.forget_multi) { - req->se->op.forget_multi(req, arg->count, - (struct fuse_forget_data *) param); + req->se->op.forget_multi(req, arg->count, forgets); } else if (req->se->op.forget) { + unsigned int i; + for (i =3D 0; i < arg->count; i++) { - struct fuse_forget_one *forget =3D ¶m[i]; struct fuse_req *dummy_req; =20 dummy_req =3D fuse_ll_alloc_req(req->se); @@ -750,8 +789,8 @@ static void do_batch_forget(fuse_req_t req, fuse_ino_t = nodeid, dummy_req->ctx =3D req->ctx; dummy_req->ch =3D NULL; =20 - req->se->op.forget(dummy_req, forget->nodeid, - forget->nlookup); + req->se->op.forget(dummy_req, forgets[i].ino, + forgets[i].nlookup); } fuse_reply_none(req); } else { @@ -759,13 +798,20 @@ static void do_batch_forget(fuse_req_t req, fuse_ino_= t nodeid, } } =20 -static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, const void *inar= g) +static void do_getattr(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { struct fuse_file_info *fip =3D NULL; struct fuse_file_info fi; =20 if (req->se->conn.proto_minor >=3D 9) { - struct fuse_getattr_in *arg =3D (struct fuse_getattr_in *) inarg; + struct fuse_getattr_in *arg; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (arg->getattr_flags & FUSE_GETATTR_FH) { memset(&fi, 0, sizeof(fi)); @@ -780,14 +826,21 @@ static void do_getattr(fuse_req_t req, fuse_ino_t nod= eid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, const void *inar= g) +static void do_setattr(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_setattr_in *arg =3D (struct fuse_setattr_in *) inarg; - if (req->se->op.setattr) { + struct fuse_setattr_in *arg; struct fuse_file_info *fi =3D NULL; struct fuse_file_info fi_store; struct stat stbuf; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&stbuf, 0, sizeof(stbuf)); convert_attr(arg, &stbuf); if (arg->valid & FATTR_FH) { @@ -812,9 +865,16 @@ static void do_setattr(fuse_req_t req, fuse_ino_t node= id, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_access(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_access(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_access_in *arg =3D (struct fuse_access_in *) inarg; + struct fuse_access_in *arg; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.access) req->se->op.access(req, nodeid, arg->mask); @@ -822,9 +882,10 @@ static void do_access(fuse_req_t req, fuse_ino_t nodei= d, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, const void *ina= rg) +static void do_readlink(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - (void) inarg; + (void) iter; =20 if (req->se->op.readlink) req->se->op.readlink(req, nodeid); @@ -832,15 +893,24 @@ static void do_readlink(fuse_req_t req, fuse_ino_t no= deid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_mknod(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_mknod_in *arg =3D (struct fuse_mknod_in *) inarg; - char *name =3D PARAM(arg); + bool compat =3D req->se->conn.proto_minor < 12; + struct fuse_mknod_in *arg; + const char *name; =20 - if (req->se->conn.proto_minor >=3D 12) + arg =3D fuse_mbuf_iter_advance(iter, + compat ? FUSE_COMPAT_MKNOD_IN_SIZE : sizeof(*arg)); + name =3D fuse_mbuf_iter_advance_str(iter); + if (!arg || !name) { + fuse_reply_err(req, EINVAL); + return; + } + + if (!compat) { req->ctx.umask =3D arg->umask; - else - name =3D (char *) inarg + FUSE_COMPAT_MKNOD_IN_SIZE; + } =20 if (req->se->op.mknod) req->se->op.mknod(req, nodeid, name, arg->mode, arg->rdev); @@ -848,22 +918,40 @@ static void do_mknod(fuse_req_t req, fuse_ino_t nodei= d, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_mkdir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_mkdir_in *arg =3D (struct fuse_mkdir_in *) inarg; + bool compat =3D req->se->conn.proto_minor < 12; + struct fuse_mkdir_in *arg; + const char *name; =20 - if (req->se->conn.proto_minor >=3D 12) + arg =3D fuse_mbuf_iter_advance(iter, + compat ? sizeof(uint32_t) : sizeof(*arg)); + name =3D fuse_mbuf_iter_advance_str(iter); + if (!arg || !name) { + fuse_reply_err(req, EINVAL); + return; + } + + if (!compat) { req->ctx.umask =3D arg->umask; + } =20 if (req->se->op.mkdir) - req->se->op.mkdir(req, nodeid, PARAM(arg), arg->mode); + req->se->op.mkdir(req, nodeid, name, arg->mode); else fuse_reply_err(req, ENOSYS); } =20 -static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_unlink(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - char *name =3D (char *) inarg; + const char *name =3D fuse_mbuf_iter_advance_str(iter); + + if (!name) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.unlink) req->se->op.unlink(req, nodeid, name); @@ -871,9 +959,15 @@ static void do_unlink(fuse_req_t req, fuse_ino_t nodei= d, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_rmdir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - char *name =3D (char *) inarg; + const char *name =3D fuse_mbuf_iter_advance_str(iter); + + if (!name) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.rmdir) req->se->op.rmdir(req, nodeid, name); @@ -881,10 +975,16 @@ static void do_rmdir(fuse_req_t req, fuse_ino_t nodei= d, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, const void *inar= g) +static void do_symlink(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - char *name =3D (char *) inarg; - char *linkname =3D ((char *) inarg) + strlen((char *) inarg) + 1; + const char *name =3D fuse_mbuf_iter_advance_str(iter); + const char *linkname =3D fuse_mbuf_iter_advance_str(iter); + + if (!name || !linkname) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.symlink) req->se->op.symlink(req, linkname, nodeid, name); @@ -892,11 +992,20 @@ static void do_symlink(fuse_req_t req, fuse_ino_t nod= eid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_rename(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_rename(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_rename_in *arg =3D (struct fuse_rename_in *) inarg; - char *oldname =3D PARAM(arg); - char *newname =3D oldname + strlen(oldname) + 1; + struct fuse_rename_in *arg; + const char *oldname; + const char *newname; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + oldname =3D fuse_mbuf_iter_advance_str(iter); + newname =3D fuse_mbuf_iter_advance_str(iter); + if (!arg || !oldname || !newname) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.rename) req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, @@ -905,11 +1014,20 @@ static void do_rename(fuse_req_t req, fuse_ino_t nod= eid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, const void *inar= g) +static void do_rename2(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_rename2_in *arg =3D (struct fuse_rename2_in *) inarg; - char *oldname =3D PARAM(arg); - char *newname =3D oldname + strlen(oldname) + 1; + struct fuse_rename2_in *arg; + const char *oldname; + const char *newname; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + oldname =3D fuse_mbuf_iter_advance_str(iter); + newname =3D fuse_mbuf_iter_advance_str(iter); + if (!arg || !oldname || !newname) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.rename) req->se->op.rename(req, nodeid, oldname, arg->newdir, newname, @@ -918,42 +1036,65 @@ static void do_rename2(fuse_req_t req, fuse_ino_t no= deid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_link(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_link(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_link_in *arg =3D (struct fuse_link_in *) inarg; + struct fuse_link_in *arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + const char *name =3D fuse_mbuf_iter_advance_str(iter); + + if (!arg || !name) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.link) - req->se->op.link(req, arg->oldnodeid, nodeid, PARAM(arg)); + req->se->op.link(req, arg->oldnodeid, nodeid, name); else fuse_reply_err(req, ENOSYS); } =20 -static void do_create(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_create(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_create_in *arg =3D (struct fuse_create_in *) inarg; - if (req->se->op.create) { + bool compat =3D req->se->conn.proto_minor < 12; + struct fuse_create_in *arg; struct fuse_file_info fi; - char *name =3D PARAM(arg); + const char *name; + + arg =3D fuse_mbuf_iter_advance(iter, compat ? + sizeof(struct fuse_open_in) : + sizeof(*arg)); + name =3D fuse_mbuf_iter_advance_str(iter); + if (!arg || !name) { + fuse_reply_err(req, EINVAL); + return; + } =20 memset(&fi, 0, sizeof(fi)); fi.flags =3D arg->flags; =20 - if (req->se->conn.proto_minor >=3D 12) + if (!compat) { req->ctx.umask =3D arg->umask; - else - name =3D (char *) inarg + sizeof(struct fuse_open_in); + } =20 req->se->op.create(req, nodeid, name, arg->mode, &fi); } else fuse_reply_err(req, ENOSYS); } =20 -static void do_open(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_open(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_open_in *arg =3D (struct fuse_open_in *) inarg; + struct fuse_open_in *arg; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.flags =3D arg->flags; =20 @@ -963,16 +1104,21 @@ static void do_open(fuse_req_t req, fuse_ino_t nodei= d, const void *inarg) fuse_reply_open(req, &fi); } =20 -static void do_read(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_read(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_read_in *arg =3D (struct fuse_read_in *) inarg; - if (req->se->op.read) { + bool compat =3D req->se->conn.proto_minor < 9; + struct fuse_read_in *arg; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, compat ? + offsetof(struct fuse_read_in, lock_owner) : + sizeof(*arg)); + memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; - if (req->se->conn.proto_minor >=3D 9) { + if (!compat) { fi.lock_owner =3D arg->lock_owner; fi.flags =3D arg->flags; } @@ -981,22 +1127,34 @@ static void do_read(fuse_req_t req, fuse_ino_t nodei= d, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_write(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_write(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_write_in *arg =3D (struct fuse_write_in *) inarg; + bool compat =3D req->se->conn.proto_minor < 9; + struct fuse_write_in *arg; struct fuse_file_info fi; - char *param; + const char *param; + + arg =3D fuse_mbuf_iter_advance(iter, compat ? + FUSE_COMPAT_WRITE_IN_SIZE : sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + + param =3D fuse_mbuf_iter_advance(iter, arg->size); + if (!param) { + fuse_reply_err(req, EINVAL); + return; + } =20 memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; fi.writepage =3D (arg->write_flags & FUSE_WRITE_CACHE) !=3D 0; =20 - if (req->se->conn.proto_minor < 9) { - param =3D ((char *) arg) + FUSE_COMPAT_WRITE_IN_SIZE; - } else { + if (!compat) { fi.lock_owner =3D arg->lock_owner; fi.flags =3D arg->flags; - param =3D PARAM(arg); } =20 if (req->se->op.write) @@ -1062,16 +1220,27 @@ static void do_write_buf(fuse_req_t req, fuse_ino_t= nodeid, se->op.write_buf(req, nodeid, pbufv, arg->offset, &fi); } =20 -static void do_flush(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_flush(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_flush_in *arg =3D (struct fuse_flush_in *) inarg; + bool compat =3D req->se->conn.proto_minor < 7; + struct fuse_flush_in *arg; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, compat ? + offsetof(struct fuse_flush_in, lock_owner) : + sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; fi.flush =3D 1; - if (req->se->conn.proto_minor >=3D 7) + if (!compat) { fi.lock_owner =3D arg->lock_owner; + } =20 if (req->se->op.flush) req->se->op.flush(req, nodeid, &fi); @@ -1079,21 +1248,31 @@ static void do_flush(fuse_req_t req, fuse_ino_t nod= eid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_release(fuse_req_t req, fuse_ino_t nodeid, const void *inar= g) +static void do_release(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_release_in *arg =3D (struct fuse_release_in *) inarg; + bool compat =3D req->se->conn.proto_minor < 8; + struct fuse_release_in *arg; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, compat ? + offsetof(struct fuse_release_in, lock_owner) : + sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.flags =3D arg->flags; fi.fh =3D arg->fh; - if (req->se->conn.proto_minor >=3D 8) { + if (!compat) { fi.flush =3D (arg->release_flags & FUSE_RELEASE_FLUSH) ? 1 : 0; fi.lock_owner =3D arg->lock_owner; - } - if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) { - fi.flock_release =3D 1; - fi.lock_owner =3D arg->lock_owner; + + if (arg->release_flags & FUSE_RELEASE_FLOCK_UNLOCK) { + fi.flock_release =3D 1; + } } =20 if (req->se->op.release) @@ -1102,11 +1281,19 @@ static void do_release(fuse_req_t req, fuse_ino_t n= odeid, const void *inarg) fuse_reply_err(req, 0); } =20 -static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_fsync(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_fsync_in *arg =3D (struct fuse_fsync_in *) inarg; + struct fuse_fsync_in *arg; struct fuse_file_info fi; - int datasync =3D arg->fsync_flags & 1; + int datasync; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + datasync =3D arg->fsync_flags & 1; =20 memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; @@ -1120,11 +1307,18 @@ static void do_fsync(fuse_req_t req, fuse_ino_t nod= eid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, const void *inar= g) +static void do_opendir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_open_in *arg =3D (struct fuse_open_in *) inarg; + struct fuse_open_in *arg; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.flags =3D arg->flags; =20 @@ -1134,11 +1328,18 @@ static void do_opendir(fuse_req_t req, fuse_ino_t n= odeid, const void *inarg) fuse_reply_open(req, &fi); } =20 -static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inar= g) +static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_read_in *arg =3D (struct fuse_read_in *) inarg; + struct fuse_read_in *arg; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; =20 @@ -1148,11 +1349,18 @@ static void do_readdir(fuse_req_t req, fuse_ino_t n= odeid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, const void *= inarg) +static void do_readdirplus(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_read_in *arg =3D (struct fuse_read_in *) inarg; + struct fuse_read_in *arg; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; =20 @@ -1162,11 +1370,18 @@ static void do_readdirplus(fuse_req_t req, fuse_ino= _t nodeid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *i= narg) +static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_release_in *arg =3D (struct fuse_release_in *) inarg; + struct fuse_release_in *arg; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.flags =3D arg->flags; fi.fh =3D arg->fh; @@ -1177,11 +1392,19 @@ static void do_releasedir(fuse_req_t req, fuse_ino_= t nodeid, const void *inarg) fuse_reply_err(req, 0); } =20 -static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, const void *ina= rg) +static void do_fsyncdir(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_fsync_in *arg =3D (struct fuse_fsync_in *) inarg; + struct fuse_fsync_in *arg; struct fuse_file_info fi; - int datasync =3D arg->fsync_flags & 1; + int datasync; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + datasync =3D arg->fsync_flags & 1; =20 memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; @@ -1192,10 +1415,11 @@ static void do_fsyncdir(fuse_req_t req, fuse_ino_t = nodeid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_statfs(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { (void) nodeid; - (void) inarg; + (void) iter; =20 if (req->se->op.statfs) req->se->op.statfs(req, nodeid); @@ -1208,11 +1432,25 @@ static void do_statfs(fuse_req_t req, fuse_ino_t no= deid, const void *inarg) } } =20 -static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, const void *ina= rg) +static void do_setxattr(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_setxattr_in *arg =3D (struct fuse_setxattr_in *) inarg; - char *name =3D PARAM(arg); - char *value =3D name + strlen(name) + 1; + struct fuse_setxattr_in *arg; + const char *name; + const char *value; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + name =3D fuse_mbuf_iter_advance_str(iter); + if (!arg || !name) { + fuse_reply_err(req, EINVAL); + return; + } + + value =3D fuse_mbuf_iter_advance(iter, arg->size); + if (!value) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.setxattr) req->se->op.setxattr(req, nodeid, name, value, arg->size, @@ -1221,19 +1459,35 @@ static void do_setxattr(fuse_req_t req, fuse_ino_t = nodeid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, const void *ina= rg) +static void do_getxattr(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_getxattr_in *arg =3D (struct fuse_getxattr_in *) inarg; + struct fuse_getxattr_in *arg; + const char *name; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + name =3D fuse_mbuf_iter_advance_str(iter); + if (!arg || !name) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.getxattr) - req->se->op.getxattr(req, nodeid, PARAM(arg), arg->size); + req->se->op.getxattr(req, nodeid, name, arg->size); else fuse_reply_err(req, ENOSYS); } =20 -static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, const void *in= arg) +static void do_listxattr(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_getxattr_in *arg =3D (struct fuse_getxattr_in *) inarg; + struct fuse_getxattr_in *arg; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.listxattr) req->se->op.listxattr(req, nodeid, arg->size); @@ -1241,9 +1495,15 @@ static void do_listxattr(fuse_req_t req, fuse_ino_t = nodeid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, const void *= inarg) +static void do_removexattr(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - char *name =3D (char *) inarg; + const char *name =3D fuse_mbuf_iter_advance_str(iter); + + if (!name) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.removexattr) req->se->op.removexattr(req, nodeid, name); @@ -1265,12 +1525,19 @@ static void convert_fuse_file_lock(struct fuse_file= _lock *fl, flock->l_pid =3D fl->pid; } =20 -static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_getlk(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_lk_in *arg =3D (struct fuse_lk_in *) inarg; + struct fuse_lk_in *arg; struct fuse_file_info fi; struct flock flock; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; fi.lock_owner =3D arg->owner; @@ -1283,12 +1550,18 @@ static void do_getlk(fuse_req_t req, fuse_ino_t nod= eid, const void *inarg) } =20 static void do_setlk_common(fuse_req_t req, fuse_ino_t nodeid, - const void *inarg, int sleep) + struct fuse_mbuf_iter *iter, int sleep) { - struct fuse_lk_in *arg =3D (struct fuse_lk_in *) inarg; + struct fuse_lk_in *arg; struct fuse_file_info fi; struct flock flock; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; fi.lock_owner =3D arg->owner; @@ -1323,14 +1596,16 @@ static void do_setlk_common(fuse_req_t req, fuse_in= o_t nodeid, } } =20 -static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_setlk(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - do_setlk_common(req, nodeid, inarg, 0); + do_setlk_common(req, nodeid, iter, 0); } =20 -static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_setlkw(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - do_setlk_common(req, nodeid, inarg, 1); + do_setlk_common(req, nodeid, iter, 1); } =20 static int find_interrupted(struct fuse_session *se, struct fuse_req *req) @@ -1372,12 +1647,20 @@ static int find_interrupted(struct fuse_session *se= , struct fuse_req *req) return 0; } =20 -static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, const void *in= arg) +static void do_interrupt(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_interrupt_in *arg =3D (struct fuse_interrupt_in *) inarg; + struct fuse_interrupt_in *arg; struct fuse_session *se =3D req->se; =20 (void) nodeid; + + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + if (se->debug) fuse_log(FUSE_LOG_DEBUG, "INTERRUPT: %llu\n", (unsigned long long) arg->unique); @@ -1415,9 +1698,15 @@ static struct fuse_req *check_interrupt(struct fuse_= session *se, return NULL; } =20 -static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_bmap(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_bmap_in *arg =3D (struct fuse_bmap_in *) inarg; + struct fuse_bmap_in *arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } =20 if (req->se->op.bmap) req->se->op.bmap(req, nodeid, arg->blocksize, arg->block); @@ -1425,19 +1714,35 @@ static void do_bmap(fuse_req_t req, fuse_ino_t node= id, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_ioctl(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_ioctl_in *arg =3D (struct fuse_ioctl_in *) inarg; - unsigned int flags =3D arg->flags; - void *in_buf =3D arg->in_size ? PARAM(arg) : NULL; + struct fuse_ioctl_in *arg; + unsigned int flags; + void *in_buf =3D NULL; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + + flags =3D arg->flags; if (flags & FUSE_IOCTL_DIR && !(req->se->conn.want & FUSE_CAP_IOCTL_DIR)) { fuse_reply_err(req, ENOTTY); return; } =20 + if (arg->in_size) { + in_buf =3D fuse_mbuf_iter_advance(iter, arg->in_size); + if (!in_buf) { + fuse_reply_err(req, EINVAL); + return; + } + } + memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; =20 @@ -1459,11 +1764,18 @@ void fuse_pollhandle_destroy(struct fuse_pollhandle= *ph) free(ph); } =20 -static void do_poll(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_poll(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_poll_in *arg =3D (struct fuse_poll_in *) inarg; + struct fuse_poll_in *arg; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; fi.poll_events =3D arg->events; @@ -1487,11 +1799,18 @@ static void do_poll(fuse_req_t req, fuse_ino_t node= id, const void *inarg) } } =20 -static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, const void *in= arg) +static void do_fallocate(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_fallocate_in *arg =3D (struct fuse_fallocate_in *) inarg; + struct fuse_fallocate_in *arg; struct fuse_file_info fi; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi, 0, sizeof(fi)); fi.fh =3D arg->fh; =20 @@ -1501,11 +1820,18 @@ static void do_fallocate(fuse_req_t req, fuse_ino_t= nodeid, const void *inarg) fuse_reply_err(req, ENOSYS); } =20 -static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, const= void *inarg) +static void do_copy_file_range(fuse_req_t req, fuse_ino_t nodeid_in, + struct fuse_mbuf_iter *iter) { - struct fuse_copy_file_range_in *arg =3D (struct fuse_copy_file_range_in *= ) inarg; + struct fuse_copy_file_range_in *arg; struct fuse_file_info fi_in, fi_out; =20 + arg =3D fuse_mbuf_iter_advance(iter, sizeof(*arg)); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + memset(&fi_in, 0, sizeof(fi_in)); fi_in.fh =3D arg->fh_in; =20 @@ -1522,15 +1848,34 @@ static void do_copy_file_range(fuse_req_t req, fuse= _ino_t nodeid_in, const void fuse_reply_err(req, ENOSYS); } =20 -static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg) +static void do_init(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { - struct fuse_init_in *arg =3D (struct fuse_init_in *) inarg; + size_t compat_size =3D offsetof(struct fuse_init_in, max_readahead); + struct fuse_init_in *arg; struct fuse_init_out outarg; struct fuse_session *se =3D req->se; size_t bufsize =3D se->bufsize; size_t outargsize =3D sizeof(outarg); =20 (void) nodeid; + + /* First consume the old fields... */ + arg =3D fuse_mbuf_iter_advance(iter, compat_size); + if (!arg) { + fuse_reply_err(req, EINVAL); + return; + } + + /* ...and now consume the new fields. */ + if (arg->major =3D=3D 7 && arg->minor >=3D 6) { + if (!fuse_mbuf_iter_advance(iter, sizeof(*arg) - + compat_size)) { + fuse_reply_err(req, EINVAL); + return; + } + } + if (se->debug) { fuse_log(FUSE_LOG_DEBUG, "INIT: %u.%u\n", arg->major, arg->minor); if (arg->major =3D=3D 7 && arg->minor >=3D 6) { @@ -1744,12 +2089,13 @@ static void do_init(fuse_req_t req, fuse_ino_t node= id, const void *inarg) send_reply_ok(req, &outarg, outargsize); } =20 -static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, const void *inar= g) +static void do_destroy(fuse_req_t req, fuse_ino_t nodeid, + struct fuse_mbuf_iter *iter) { struct fuse_session *se =3D req->se; =20 (void) nodeid; - (void) inarg; + (void) iter; =20 se->got_destroy =3D 1; if (se->op.destroy) @@ -1934,7 +2280,7 @@ int fuse_req_interrupted(fuse_req_t req) } =20 static struct { - void (*func)(fuse_req_t, fuse_ino_t, const void *); + void (*func)(fuse_req_t, fuse_ino_t, struct fuse_mbuf_iter *); const char *name; } fuse_ll_ops[] =3D { [FUSE_LOOKUP] =3D { do_lookup, "LOOKUP" }, @@ -2013,7 +2359,6 @@ void fuse_session_process_buf_int(struct fuse_session= *se, const struct fuse_buf *buf =3D bufv->buf; struct fuse_mbuf_iter iter =3D FUSE_MBUF_ITER_INIT(buf); struct fuse_in_header *in; - const void *inarg; struct fuse_req *req; int err; =20 @@ -2086,12 +2431,10 @@ void fuse_session_process_buf_int(struct fuse_sessi= on *se, fuse_reply_err(intr, EAGAIN); } =20 - inarg =3D (void *) &in[1]; if (in->opcode =3D=3D FUSE_WRITE && se->op.write_buf) do_write_buf(req, in->nodeid, &iter, bufv); else - fuse_ll_ops[in->opcode].func(req, in->nodeid, inarg); - + fuse_ll_ops[in->opcode].func(req, in->nodeid, &iter); return; =20 reply_err: --=20 2.23.0