Blame 0066-virtiofsd-fix-libfuse-information-leaks.patch

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