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