qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] virtiofsd: fix libfuse information leaks


From: Dr. David Alan Gilbert
Subject: Re: [PATCH] virtiofsd: fix libfuse information leaks
Date: Fri, 22 Nov 2019 14:18:37 +0000
User-agent: Mutt/1.12.1 (2019-06-15)

* Stefan Hajnoczi (address@hidden) wrote:
> Some FUSE message replies contain padding fields that are not
> initialized by libfuse.  This is fine in traditional FUSE applications
> because the kernel is trusted.  virtiofsd does not trust the guest and
> must not expose uninitialized memory.
> 
> Use C struct initializers to automatically zero out memory.  Not all of
> these code changes are strictly necessary but they will prevent future
> information leaks if the structs are extended.
> 
> Signed-off-by: Stefan Hajnoczi <address@hidden>

Reviewed-by: Dr. David Alan Gilbert <address@hidden>

Thanks, merged.

Dave

> ---
>  contrib/virtiofsd/fuse_lowlevel.c | 150 +++++++++++++++---------------
>  1 file changed, 76 insertions(+), 74 deletions(-)
> 
> diff --git a/contrib/virtiofsd/fuse_lowlevel.c 
> b/contrib/virtiofsd/fuse_lowlevel.c
> index 7fa8861f5d..8a4234630d 100644
> --- a/contrib/virtiofsd/fuse_lowlevel.c
> +++ b/contrib/virtiofsd/fuse_lowlevel.c
> @@ -45,21 +45,23 @@ static __attribute__((constructor)) void 
> fuse_ll_init_pagesize(void)
>  
>  static void convert_stat(const struct stat *stbuf, struct fuse_attr *attr)
>  {
> -     attr->ino       = stbuf->st_ino;
> -     attr->mode      = stbuf->st_mode;
> -     attr->nlink     = stbuf->st_nlink;
> -     attr->uid       = stbuf->st_uid;
> -     attr->gid       = stbuf->st_gid;
> -     attr->rdev      = stbuf->st_rdev;
> -     attr->size      = stbuf->st_size;
> -     attr->blksize   = stbuf->st_blksize;
> -     attr->blocks    = stbuf->st_blocks;
> -     attr->atime     = stbuf->st_atime;
> -     attr->mtime     = stbuf->st_mtime;
> -     attr->ctime     = stbuf->st_ctime;
> -     attr->atimensec = ST_ATIM_NSEC(stbuf);
> -     attr->mtimensec = ST_MTIM_NSEC(stbuf);
> -     attr->ctimensec = ST_CTIM_NSEC(stbuf);
> +     *attr = (struct fuse_attr) {
> +             .ino            = stbuf->st_ino,
> +             .mode           = stbuf->st_mode,
> +             .nlink          = stbuf->st_nlink,
> +             .uid            = stbuf->st_uid,
> +             .gid            = stbuf->st_gid,
> +             .rdev           = stbuf->st_rdev,
> +             .size           = stbuf->st_size,
> +             .blksize        = stbuf->st_blksize,
> +             .blocks         = stbuf->st_blocks,
> +             .atime          = stbuf->st_atime,
> +             .mtime          = stbuf->st_mtime,
> +             .ctime          = stbuf->st_ctime,
> +             .atimensec      = ST_ATIM_NSEC(stbuf),
> +             .mtimensec      = ST_MTIM_NSEC(stbuf),
> +             .ctimensec      = ST_CTIM_NSEC(stbuf),
> +     };
>  }
>  
>  static void convert_attr(const struct fuse_setattr_in *attr, struct stat 
> *stbuf)
> @@ -181,16 +183,16 @@ static int fuse_send_msg(struct fuse_session *se, 
> struct fuse_chan *ch,
>  int fuse_send_reply_iov_nofree(fuse_req_t req, int error, struct iovec *iov,
>                              int count)
>  {
> -     struct fuse_out_header out;
> +     struct fuse_out_header out = {
> +             .unique = req->unique,
> +             .error = error,
> +     };
>  
>       if (error <= -1000 || error > 0) {
>               fuse_log(FUSE_LOG_ERR, "fuse: bad error value: %i\n",   error);
>               error = -ERANGE;
>       }
>  
> -     out.unique = req->unique;
> -     out.error = error;
> -
>       iov[0].iov_base = &out;
>       iov[0].iov_len = sizeof(struct fuse_out_header);
>  
> @@ -271,14 +273,16 @@ size_t fuse_add_direntry(fuse_req_t req, char *buf, 
> size_t bufsize,
>  static void convert_statfs(const struct statvfs *stbuf,
>                          struct fuse_kstatfs *kstatfs)
>  {
> -     kstatfs->bsize   = stbuf->f_bsize;
> -     kstatfs->frsize  = stbuf->f_frsize;
> -     kstatfs->blocks  = stbuf->f_blocks;
> -     kstatfs->bfree   = stbuf->f_bfree;
> -     kstatfs->bavail  = stbuf->f_bavail;
> -     kstatfs->files   = stbuf->f_files;
> -     kstatfs->ffree   = stbuf->f_ffree;
> -     kstatfs->namelen = stbuf->f_namemax;
> +     *kstatfs = (struct fuse_kstatfs) {
> +             .bsize   = stbuf->f_bsize,
> +             .frsize  = stbuf->f_frsize,
> +             .blocks  = stbuf->f_blocks,
> +             .bfree   = stbuf->f_bfree,
> +             .bavail  = stbuf->f_bavail,
> +             .files   = stbuf->f_files,
> +             .ffree   = stbuf->f_ffree,
> +             .namelen = stbuf->f_namemax,
> +     };
>  }
>  
>  static int send_reply_ok(fuse_req_t req, const void *arg, size_t argsize)
> @@ -320,12 +324,14 @@ static unsigned int calc_timeout_nsec(double t)
>  static void fill_entry(struct fuse_entry_out *arg,
>                      const struct fuse_entry_param *e)
>  {
> -     arg->nodeid = e->ino;
> -     arg->generation = e->generation;
> -     arg->entry_valid = calc_timeout_sec(e->entry_timeout);
> -     arg->entry_valid_nsec = calc_timeout_nsec(e->entry_timeout);
> -     arg->attr_valid = calc_timeout_sec(e->attr_timeout);
> -     arg->attr_valid_nsec = calc_timeout_nsec(e->attr_timeout);
> +     *arg = (struct fuse_entry_out) {
> +             .nodeid = e->ino,
> +             .generation = e->generation,
> +             .entry_valid = calc_timeout_sec(e->entry_timeout),
> +             .entry_valid_nsec = calc_timeout_nsec(e->entry_timeout),
> +             .attr_valid = calc_timeout_sec(e->attr_timeout),
> +             .attr_valid_nsec = calc_timeout_nsec(e->attr_timeout),
> +     };
>       convert_stat(&e->attr, &arg->attr);
>  }
>  
> @@ -351,10 +357,12 @@ size_t fuse_add_direntry_plus(fuse_req_t req, char 
> *buf, size_t bufsize,
>       fill_entry(&dp->entry_out, e);
>  
>       struct fuse_dirent *dirent = &dp->dirent;
> -     dirent->ino = e->attr.st_ino;
> -     dirent->off = off;
> -     dirent->namelen = namelen;
> -     dirent->type = (e->attr.st_mode & S_IFMT) >> 12;
> +     *dirent = (struct fuse_dirent) {
> +             .ino = e->attr.st_ino,
> +             .off = off,
> +             .namelen = namelen,
> +             .type = (e->attr.st_mode & S_IFMT) >> 12,
> +     };
>       memcpy(dirent->name, name, namelen);
>       memset(dirent->name + namelen, 0, entlen_padded - entlen);
>  
> @@ -504,15 +512,14 @@ int fuse_reply_data(fuse_req_t req, struct fuse_bufvec 
> *bufv,
>                   enum fuse_buf_copy_flags flags)
>  {
>       struct iovec iov[2];
> -     struct fuse_out_header out;
> +     struct fuse_out_header out = {
> +             .unique = req->unique,
> +     };
>       int res;
>  
>       iov[0].iov_base = &out;
>       iov[0].iov_len = sizeof(struct fuse_out_header);
>  
> -     out.unique = req->unique;
> -     out.error = 0;
> -
>       res = fuse_send_data_iov(req->se, req->ch, iov, 1, bufv, flags);
>       if (res <= 0) {
>               fuse_free_req(req);
> @@ -2203,13 +2210,13 @@ static void do_destroy(fuse_req_t req, fuse_ino_t 
> nodeid,
>  static int send_notify_iov(struct fuse_session *se, int notify_code,
>                          struct iovec *iov, int count)
>  {
> -     struct fuse_out_header out;
> +     struct fuse_out_header out = {
> +             .error = notify_code,
> +     };
>  
>       if (!se->got_init)
>               return -ENOTCONN;
>  
> -     out.unique = 0;
> -     out.error = notify_code;
>       iov[0].iov_base = &out;
>       iov[0].iov_len = sizeof(struct fuse_out_header);
>  
> @@ -2219,11 +2226,11 @@ static int send_notify_iov(struct fuse_session *se, 
> int notify_code,
>  int fuse_lowlevel_notify_poll(struct fuse_pollhandle *ph)
>  {
>       if (ph != NULL) {
> -             struct fuse_notify_poll_wakeup_out outarg;
> +             struct fuse_notify_poll_wakeup_out outarg = {
> +                     .kh = ph->kh,
> +             };
>               struct iovec iov[2];
>  
> -             outarg.kh = ph->kh;
> -
>               iov[1].iov_base = &outarg;
>               iov[1].iov_len = sizeof(outarg);
>  
> @@ -2236,7 +2243,11 @@ int fuse_lowlevel_notify_poll(struct fuse_pollhandle 
> *ph)
>  int fuse_lowlevel_notify_inval_inode(struct fuse_session *se, fuse_ino_t ino,
>                                    off_t off, off_t len)
>  {
> -     struct fuse_notify_inval_inode_out outarg;
> +     struct fuse_notify_inval_inode_out outarg = {
> +             .ino = ino,
> +             .off = off,
> +             .len = len,
> +     };
>       struct iovec iov[2];
>  
>       if (!se)
> @@ -2244,10 +2255,6 @@ int fuse_lowlevel_notify_inval_inode(struct 
> fuse_session *se, fuse_ino_t ino,
>  
>       if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
>               return -ENOSYS;
> -     
> -     outarg.ino = ino;
> -     outarg.off = off;
> -     outarg.len = len;
>  
>       iov[1].iov_base = &outarg;
>       iov[1].iov_len = sizeof(outarg);
> @@ -2258,7 +2265,10 @@ int fuse_lowlevel_notify_inval_inode(struct 
> fuse_session *se, fuse_ino_t ino,
>  int fuse_lowlevel_notify_inval_entry(struct fuse_session *se, fuse_ino_t 
> parent,
>                                    const char *name, size_t namelen)
>  {
> -     struct fuse_notify_inval_entry_out outarg;
> +     struct fuse_notify_inval_entry_out outarg = {
> +             .parent = parent,
> +             .namelen = namelen,
> +     };
>       struct iovec iov[3];
>  
>       if (!se)
> @@ -2267,10 +2277,6 @@ int fuse_lowlevel_notify_inval_entry(struct 
> fuse_session *se, fuse_ino_t parent,
>       if (se->conn.proto_major < 6 || se->conn.proto_minor < 12)
>               return -ENOSYS;
>  
> -     outarg.parent = parent;
> -     outarg.namelen = namelen;
> -     outarg.padding = 0;
> -
>       iov[1].iov_base = &outarg;
>       iov[1].iov_len = sizeof(outarg);
>       iov[2].iov_base = (void *)name;
> @@ -2283,7 +2289,11 @@ int fuse_lowlevel_notify_delete(struct fuse_session 
> *se,
>                               fuse_ino_t parent, fuse_ino_t child,
>                               const char *name, size_t namelen)
>  {
> -     struct fuse_notify_delete_out outarg;
> +     struct fuse_notify_delete_out outarg = {
> +             .parent = parent,
> +             .child = child,
> +             .namelen = namelen,
> +     };
>       struct iovec iov[3];
>  
>       if (!se)
> @@ -2292,11 +2302,6 @@ int fuse_lowlevel_notify_delete(struct fuse_session 
> *se,
>       if (se->conn.proto_major < 6 || se->conn.proto_minor < 18)
>               return -ENOSYS;
>  
> -     outarg.parent = parent;
> -     outarg.child = child;
> -     outarg.namelen = namelen;
> -     outarg.padding = 0;
> -
>       iov[1].iov_base = &outarg;
>       iov[1].iov_len = sizeof(outarg);
>       iov[2].iov_base = (void *)name;
> @@ -2309,10 +2314,15 @@ int fuse_lowlevel_notify_store(struct fuse_session 
> *se, fuse_ino_t ino,
>                              off_t offset, struct fuse_bufvec *bufv,
>                              enum fuse_buf_copy_flags flags)
>  {
> -     struct fuse_out_header out;
> -     struct fuse_notify_store_out outarg;
> +     struct fuse_out_header out = {
> +             .error = FUSE_NOTIFY_STORE,
> +     };
> +     struct fuse_notify_store_out outarg = {
> +             .nodeid = ino,
> +             .offset = offset,
> +             .size = fuse_buf_size(bufv),
> +     };
>       struct iovec iov[3];
> -     size_t size = fuse_buf_size(bufv);
>       int res;
>  
>       if (!se)
> @@ -2321,14 +2331,6 @@ int fuse_lowlevel_notify_store(struct fuse_session 
> *se, fuse_ino_t ino,
>       if (se->conn.proto_major < 6 || se->conn.proto_minor < 15)
>               return -ENOSYS;
>  
> -     out.unique = 0;
> -     out.error = FUSE_NOTIFY_STORE;
> -
> -     outarg.nodeid = ino;
> -     outarg.offset = offset;
> -     outarg.size = size;
> -     outarg.padding = 0;
> -
>       iov[0].iov_base = &out;
>       iov[0].iov_len = sizeof(out);
>       iov[1].iov_base = &outarg;
> -- 
> 2.23.0
> 
--
Dr. David Alan Gilbert / address@hidden / Manchester, UK




reply via email to

[Prev in Thread] Current Thread [Next in Thread]