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