902636
From e0d64e481e5a9fab5ff90d2a8f84afcd3311d13b Mon Sep 17 00:00:00 2001
902636
From: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
902636
Date: Mon, 27 Jan 2020 19:01:35 +0100
902636
Subject: [PATCH 064/116] virtiofsd: fix libfuse information leaks
902636
MIME-Version: 1.0
902636
Content-Type: text/plain; charset=UTF-8
902636
Content-Transfer-Encoding: 8bit
902636
902636
RH-Author: Dr. David Alan Gilbert <dgilbert@redhat.com>
902636
Message-id: <20200127190227.40942-61-dgilbert@redhat.com>
902636
Patchwork-id: 93515
902636
O-Subject: [RHEL-AV-8.2 qemu-kvm PATCH 060/112] virtiofsd: fix libfuse information leaks
902636
Bugzilla: 1694164
902636
RH-Acked-by: Philippe Mathieu-Daudé <philmd@redhat.com>
902636
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
902636
RH-Acked-by: Sergio Lopez Pascual <slp@redhat.com>
902636
902636
From: Stefan Hajnoczi <stefanha@redhat.com>
902636
902636
Some FUSE message replies contain padding fields that are not
902636
initialized by libfuse.  This is fine in traditional FUSE applications
902636
because the kernel is trusted.  virtiofsd does not trust the guest and
902636
must not expose uninitialized memory.
902636
902636
Use C struct initializers to automatically zero out memory.  Not all of
902636
these code changes are strictly necessary but they will prevent future
902636
information leaks if the structs are extended.
902636
902636
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
902636
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
902636
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
902636
Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
902636
(cherry picked from commit 3db2876a0153ac7103c077c53090e020faffb3ea)
902636
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
902636
---
902636
 tools/virtiofsd/fuse_lowlevel.c | 150 ++++++++++++++++++++--------------------
902636
 1 file changed, 76 insertions(+), 74 deletions(-)
902636
902636
diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
902636
index 2d6dc5a..6ceb33d 100644
902636
--- a/tools/virtiofsd/fuse_lowlevel.c
902636
+++ b/tools/virtiofsd/fuse_lowlevel.c
902636
@@ -44,21 +44,23 @@ static __attribute__((constructor)) void fuse_ll_init_pagesize(void)
902636
 
902636
 static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
902636
 {
902636
-    attr->ino = stbuf->st_ino;
902636
-    attr->mode = stbuf->st_mode;
902636
-    attr->nlink = stbuf->st_nlink;
902636
-    attr->uid = stbuf->st_uid;
902636
-    attr->gid = stbuf->st_gid;
902636
-    attr->rdev = stbuf->st_rdev;
902636
-    attr->size = stbuf->st_size;
902636
-    attr->blksize = stbuf->st_blksize;
902636
-    attr->blocks = stbuf->st_blocks;
902636
-    attr->atime = stbuf->st_atime;
902636
-    attr->mtime = stbuf->st_mtime;
902636
-    attr->ctime = stbuf->st_ctime;
902636
-    attr->atimensec = ST_ATIM_NSEC(stbuf);
902636
-    attr->mtimensec = ST_MTIM_NSEC(stbuf);
902636
-    attr->ctimensec = ST_CTIM_NSEC(stbuf);
902636
+    *attr = (struct fuse_attr){
902636
+        .ino = stbuf->st_ino,
902636
+        .mode = stbuf->st_mode,
902636
+        .nlink = stbuf->st_nlink,
902636
+        .uid = stbuf->st_uid,
902636
+        .gid = stbuf->st_gid,
902636
+        .rdev = stbuf->st_rdev,
902636
+        .size = stbuf->st_size,
902636
+        .blksize = stbuf->st_blksize,
902636
+        .blocks = stbuf->st_blocks,
902636
+        .atime = stbuf->st_atime,
902636
+        .mtime = stbuf->st_mtime,
902636
+        .ctime = stbuf->st_ctime,
902636
+        .atimensec = ST_ATIM_NSEC(stbuf),
902636
+        .mtimensec = ST_MTIM_NSEC(stbuf),
902636
+        .ctimensec = ST_CTIM_NSEC(stbuf),
902636
+    };
902636
 }
902636
 
902636
 static void convert_attr(const struct fuse_setattr_in *attr, struct stat *stbuf)
902636
@@ -183,16 +185,16 @@ static int fuse_send_msg(struct fuse_session *se, struct fuse_chan *ch,
902636
 int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
902636
                                int count)
902636
 {
902636
-    struct fuse_out_header out;
902636
+    struct fuse_out_header out = {
902636
+        .unique = req->unique,
902636
+        .error = error,
902636
+    };
902636
 
902636
     if (error <= -1000 || error > 0) {
902636
         fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n", error);
902636
         error = -ERANGE;
902636
     }
902636
 
902636
-    out.unique = req->unique;
902636
-    out.error = error;
902636
-
902636
     iov[0].iov_base = &out;
902636
     iov[0].iov_len = sizeof(struct fuse_out_header);
902636
 
902636
@@ -277,14 +279,16 @@ size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
902636
 static void convert_statfs(const struct statvfs *stbuf,
902636
                            struct fuse_kstatfs *kstatfs)
902636
 {
902636
-    kstatfs->bsize = stbuf->f_bsize;
902636
-    kstatfs->frsize = stbuf->f_frsize;
902636
-    kstatfs->blocks = stbuf->f_blocks;
902636
-    kstatfs->bfree = stbuf->f_bfree;
902636
-    kstatfs->bavail = stbuf->f_bavail;
902636
-    kstatfs->files = stbuf->f_files;
902636
-    kstatfs->ffree = stbuf->f_ffree;
902636
-    kstatfs->namelen = stbuf->f_namemax;
902636
+    *kstatfs = (struct fuse_kstatfs){
902636
+        .bsize = stbuf->f_bsize,
902636
+        .frsize = stbuf->f_frsize,
902636
+        .blocks = stbuf->f_blocks,
902636
+        .bfree = stbuf->f_bfree,
902636
+        .bavail = stbuf->f_bavail,
902636
+        .files = stbuf->f_files,
902636
+        .ffree = stbuf->f_ffree,
902636
+        .namelen = stbuf->f_namemax,
902636
+    };
902636
 }
902636
 
902636
 static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
902636
@@ -328,12 +332,14 @@ static unsigned int calc_timeout_nsec(double t)
902636
 static void fill_entry(struct fuse_entry_out *arg,
902636
                        const struct fuse_entry_param *e)
902636
 {
902636
-    arg->nodeid = e->ino;
902636
-    arg->generation = e->generation;
902636
-    arg->entry_valid = calc_timeout_sec(e->entry_timeout);
902636
-    arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
902636
-    arg->attr_valid = calc_timeout_sec(e->attr_timeout);
902636
-    arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
902636
+    *arg = (struct fuse_entry_out){
902636
+        .nodeid = e->ino,
902636
+        .generation = e->generation,
902636
+        .entry_valid = calc_timeout_sec(e->entry_timeout),
902636
+        .entry_valid_nsec = calc_timeout_nsec(e->entry_timeout),
902636
+        .attr_valid = calc_timeout_sec(e->attr_timeout),
902636
+        .attr_valid_nsec = calc_timeout_nsec(e->attr_timeout),
902636
+    };
902636
     convert_stat(&e->attr, &arg->attr);
902636
 }
902636
 
902636
@@ -362,10 +368,12 @@ size_t fuse_add_direntry_plus(fuse_req_t req, char *buf, size_t bufsize,
902636
     fill_entry(&dp->entry_out, e);
902636
 
902636
     struct fuse_dirent *dirent = &dp->dirent;
902636
-    dirent->ino = e->attr.st_ino;
902636
-    dirent->off = off;
902636
-    dirent->namelen = namelen;
902636
-    dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
902636
+    *dirent = (struct fuse_dirent){
902636
+        .ino = e->attr.st_ino,
902636
+        .off = off,
902636
+        .namelen = namelen,
902636
+        .type = (e->attr.st_mode & S_IFMT) >> 12,
902636
+    };
902636
     memcpy(dirent->name, name, namelen);
902636
     memset(dirent->name + namelen, 0, entlen_padded - entlen);
902636
 
902636
@@ -496,15 +504,14 @@ static int fuse_send_data_iov(struct fuse_session *se, struct fuse_chan *ch,
902636
 int fuse_reply_data(fuse_req_t req, struct fuse_bufvec *bufv)
902636
 {
902636
     struct iovec iov[2];
902636
-    struct fuse_out_header out;
902636
+    struct fuse_out_header out = {
902636
+        .unique = req->unique,
902636
+    };
902636
     int res;
902636
 
902636
     iov[0].iov_base = &out;
902636
     iov[0].iov_len = sizeof(struct fuse_out_header);
902636
 
902636
-    out.unique = req->unique;
902636
-    out.error = 0;
902636
-
902636
     res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv);
902636
     if (res <= 0) {
902636
         fuse_free_req(req);
902636
@@ -2145,14 +2152,14 @@ static void do_destroy(fuse_req_t req, fuse_ino_t nodeid,
902636
 static int send_notify_iov(struct fuse_session *se, int notify_code,
902636
                            struct iovec *iov, int count)
902636
 {
902636
-    struct fuse_out_header out;
902636
+    struct fuse_out_header out = {
902636
+        .error = notify_code,
902636
+    };
902636
 
902636
     if (!se->got_init) {
902636
         return -ENOTCONN;
902636
     }
902636
 
902636
-    out.unique = 0;
902636
-    out.error = notify_code;
902636
     iov[0].iov_base = &out;
902636
     iov[0].iov_len = sizeof(struct fuse_out_header);
902636
 
902636
@@ -2162,11 +2169,11 @@ static int send_notify_iov(struct fuse_session *se, int notify_code,
902636
 int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
902636
 {
902636
     if (ph != NULL) {
902636
-        struct fuse_notify_poll_wakeup_out outarg;
902636
+        struct fuse_notify_poll_wakeup_out outarg = {
902636
+            .kh = ph->kh,
902636
+        };
902636
         struct iovec iov[2];
902636
 
902636
-        outarg.kh = ph->kh;
902636
-
902636
         iov[1].iov_base = &outarg;
902636
         iov[1].iov_len = sizeof(outarg);
902636
 
902636
@@ -2179,17 +2186,17 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
902636
 int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
902636
                                      off_t off, off_t len)
902636
 {
902636
-    struct fuse_notify_inval_inode_out outarg;
902636
+    struct fuse_notify_inval_inode_out outarg = {
902636
+        .ino = ino,
902636
+        .off = off,
902636
+        .len = len,
902636
+    };
902636
     struct iovec iov[2];
902636
 
902636
     if (!se) {
902636
         return -EINVAL;
902636
     }
902636
 
902636
-    outarg.ino = ino;
902636
-    outarg.off = off;
902636
-    outarg.len = len;
902636
-
902636
     iov[1].iov_base = &outarg;
902636
     iov[1].iov_len = sizeof(outarg);
902636
 
902636
@@ -2199,17 +2206,16 @@ int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
902636
 int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t parent,
902636
                                      const char *name, size_t namelen)
902636
 {
902636
-    struct fuse_notify_inval_entry_out outarg;
902636
+    struct fuse_notify_inval_entry_out outarg = {
902636
+        .parent = parent,
902636
+        .namelen = namelen,
902636
+    };
902636
     struct iovec iov[3];
902636
 
902636
     if (!se) {
902636
         return -EINVAL;
902636
     }
902636
 
902636
-    outarg.parent = parent;
902636
-    outarg.namelen = namelen;
902636
-    outarg.padding = 0;
902636
-
902636
     iov[1].iov_base = &outarg;
902636
     iov[1].iov_len = sizeof(outarg);
902636
     iov[2].iov_base = (void *)name;
902636
@@ -2222,18 +2228,17 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
902636
                                 fuse_ino_t child, const char *name,
902636
                                 size_t namelen)
902636
 {
902636
-    struct fuse_notify_delete_out outarg;
902636
+    struct fuse_notify_delete_out outarg = {
902636
+        .parent = parent,
902636
+        .child = child,
902636
+        .namelen = namelen,
902636
+    };
902636
     struct iovec iov[3];
902636
 
902636
     if (!se) {
902636
         return -EINVAL;
902636
     }
902636
 
902636
-    outarg.parent = parent;
902636
-    outarg.child = child;
902636
-    outarg.namelen = namelen;
902636
-    outarg.padding = 0;
902636
-
902636
     iov[1].iov_base = &outarg;
902636
     iov[1].iov_len = sizeof(outarg);
902636
     iov[2].iov_base = (void *)name;
902636
@@ -2245,24 +2250,21 @@ int fuse_lowlevel_notify_delete(struct fuse_session *se, fuse_ino_t parent,
902636
 int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino,
902636
                                off_t offset, struct fuse_bufvec *bufv)
902636
 {
902636
-    struct fuse_out_header out;
902636
-    struct fuse_notify_store_out outarg;
902636
+    struct fuse_out_header out = {
902636
+        .error = FUSE_NOTIFY_STORE,
902636
+    };
902636
+    struct fuse_notify_store_out outarg = {
902636
+        .nodeid = ino,
902636
+        .offset = offset,
902636
+        .size = fuse_buf_size(bufv),
902636
+    };
902636
     struct iovec iov[3];
902636
-    size_t size = fuse_buf_size(bufv);
902636
     int res;
902636
 
902636
     if (!se) {
902636
         return -EINVAL;
902636
     }
902636
 
902636
-    out.unique = 0;
902636
-    out.error = FUSE_NOTIFY_STORE;
902636
-
902636
-    outarg.nodeid = ino;
902636
-    outarg.offset = offset;
902636
-    outarg.size = size;
902636
-    outarg.padding = 0;
902636
-
902636
     iov[0].iov_base = &out;
902636
     iov[0].iov_len = sizeof(out);
902636
     iov[1].iov_base = &outarg;
902636
-- 
902636
1.8.3.1
902636