[Libguestfs] [PATCH nbdkit] New filter: tar.

Richard W.M. Jones rjones at redhat.com
Tue Jul 7 21:22:04 UTC 2020


On Tue, Jul 07, 2020 at 06:36:42PM +0100, Richard W.M. Jones wrote:
> +/* Get the file size. */
> +static int64_t
> +tar_get_size (struct nbdkit_next_ops *next_ops, void *nxdata,
> +              void *handle)
> +{
> +  struct handle *h = handle;
> +  return h->size;
> +}

Interesting crash caused here.  I'm going to document this on the
public mailing list so we can find it in future, but I do not offer a fix.

I noticed during testing that the filter segfaulted if you used
something like:

  nbdkit --filter=tar --filter=xz file disk.tar.xz tar-entry=disk

and did a simple query of the export TWICE:

  qemu-img info nbd:localhost:10809
  qemu-img info nbd:localhost:10809

Notice what I'm saying here is that the first qemu-img command worked
and the second one caused nbdkit to segfault.

The segfault turned out to be this assertion failure:

  263   assert (h->exportsize <= INT64_MAX); /* Guaranteed by negotiation phase */

with this stack trace:

  #1  0x00007fd737780884 in abort () from /lib64/libc.so.6
  #2  0x00007fd737780769 in __assert_fail_base.cold () from /lib64/libc.so.6
  #3  0x00007fd73778ff86 in __assert_fail () from /lib64/libc.so.6
  #4  0x00000000004057b0 in backend_valid_range (b=0x85dbf20, offset=512, 
      count=512) at backend.c:263
  #5  0x0000000000406488 in backend_pread (b=0x85dbf20, buf=0x85ec730, 
      count=512, offset=512, flags=0, err=0x7fd736afaa78) at backend.c:478
  #6  0x00007fd7372b3b94 in tar_pread (next_ops=0x424520 <next_ops>, 
      nxdata=0x85dbf20, handle=0x85a3130, buf=0x85ec730, count=512, offs=0, 
      flags=0, err=0x7fd736afaa78) at tar.c:315
  #7  0x000000000040bdbc in filter_pread (b=0x85da790, handle=0x85a3130, 
      buf=0x85ec730, count=512, offset=0, flags=0, err=0x7fd736afaa78)
      at filters.c:441
  #8  0x0000000000406536 in backend_pread (b=0x85da790, buf=0x85ec730, 
      count=512, offset=0, flags=0, err=0x7fd736afaa78) at backend.c:483
  #9  0x00000000004119ad in handle_request (cmd=0, flags=0, offset=0, count=512, 
      buf=0x85ec730, extents=0x0) at protocol.c:241
  #10 0x0000000000412bf8 in protocol_recv_request_send_reply () at protocol.c:713
  #11 0x0000000000408356 in handle_single_connection (sockin=7, sockout=7)
      at connections.c:175
  #12 0x000000000041820f in start_thread (datav=0x85a1fc0) at sockets.c:337
  #13 0x00007fd73792f479 in start_thread () from /lib64/libpthread.so.0
  #14 0x00007fd73785cb53 in clone () from /lib64/libc.so.6

The problem is that the xz backend’s exportsize is not cached from a
previous call to xz_get_size(), so when we come to try to validate the
range the assert fails.

The reason for this is tar_prepare only calls the underlying
next_ops->get_size() on the very first connection, because on
subsequent connections the offset/size has already been cached so we
don't need to do the work in calculate_offset_of_entry, and
calculate_offset_of_entry is what calls next_ops->get_size.

Also tar_get_size doesn't call next_ops->get_size because it doesn't
need the result, which would have been the second opportunity to cache
exportsize.

If neither of these things happen then the core server will crash.

I have fixed this in my copy of the tar filter by calling
next_ops->get_size in tar_get_size even though the result is not
needed.

I checked the other plugins and the suspicious ones were:

 - ext2
 - partition
 - truncate
 - xz

However I was not able to produce a test case that crashed any of
them.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
Fedora Windows cross-compiler. Compile Windows programs, test, and
build Windows installers. Over 100 libraries supported.
http://fedoraproject.org/wiki/MinGW




More information about the Libguestfs mailing list