[Pkg-libvirt-maintainers] Bug#1031802: fuse3: inaccurate information in symbols file (was: Re: libvirt-daemon-driver-lxc: Incorrect dependencies)

Andrea Bolognani eof at kiyuko.org
Sat Mar 18 13:46:47 GMT 2023


On Thu, Feb 23, 2023 at 01:03:50AM +0100, Vincent Danjean wrote:
> After doing a partial upgrade of my system (i.e. only libvirt-daemon
> with its required dependencies), libvirtd refused to start.
> In systemd journal, I can see:
> 
> févr. 23 00:53:32 eyak libvirtd[3010536]: internal error: Failed to load module '/usr/lib/x86_64-linux-gnu/libvirt/connection-driver/libvirt_driver_lxc.so': /usr/lib/x86_64-linux-gnu/libvirt/connection-driver/libvirt_driver_lxc.so: undefined symbol: fuse_new_31, version FUSE_3.1
> 
> Upgrading libfuse3-3 from 3.12.0-1 to 3.14.0-2 fixed the problem.
> libvirt-daemon-driver-lxc should bump its dependency on libfuse3-3.
> For now, there is:
> Depends: [...] libfuse3-3 (>= 3.2.3) [...]
> 
> If this dependency is automaticcaly generated, then it probably
> means there is a bug in the libfuse3-3 package (its shlibs file)

Hi Vincent,

thanks for taking the time to report this issue, and sorry it took me
a few weeks to get back to you.

After successfully reproducing it by downgrading my machine to
libvirt 9.0.0-1 and fuse3 3.12.0-1 builds obtained from snapshot.d.o,
I have spent some time trying to figure out the root cause.

tl;dr it's indeed an issue with fuse3's symbols file.

Comparing the exported symbols for libfuse3.so.3, we can see that
3.12.0-1 contains

  0000000000013af0 g    DF .text	0000000000000111  FUSE_3.1    fuse_new_30
  0000000000013af0 g    DF .text	0000000000000111 (FUSE_3.0)   fuse_new
  00000000000134f0 g    DF .text	00000000000005f8  FUSE_3.1    fuse_new

and 3.14.0-2 contains

  0000000000014a70 g    DF .text	0000000000000111  FUSE_3.1    fuse_new_30
  0000000000014470 g    DF .text	00000000000005f8  FUSE_3.1    fuse_new_31
  0000000000014a70 g    DF .text	0000000000000111 (FUSE_3.0)   fuse_new
  0000000000014470 g    DF .text	00000000000005f8  FUSE_3.1    fuse_new

Notice how fuse_new_31, the function that libvirt_driver_lxc.so
references, only shows up in the latter.

Looking at the build log for libvirt 9.0.0-1

  https://buildd.debian.org/status/fetch.php?pkg=libvirt&arch=amd64&ver=9.0.0-1&stamp=1674930232&raw=0

we can see that it was built against fuse3 3.13.0-2. That version
exports the same symbols as 3.14.0-2, so we can use them
interchangeably for the purpose of this discussion.

Now, there are some shenanigans in include/fuse.h from version 3.13.0
onwards that result in libvirt (which defines FUSE_USE_VERSION=31 in
its source) referencing fuse_new_31 at FUSE_3.1. If you look at older
builds of libvirt, for example 8.10.0-3 (which was built against
fuse3 3.12.0-2), you'll see that fuse_new at FUSE_3.1 is referenced
instead.

To be honest I haven't looked too hard at the logic there, but the
outcome is self-apparent. Building against fuse3 3.13 results in
picking up the new symbol, which 3.12 didn't have, and so libvirt
will only work with fuse3 >= 3.13.

This wouldn't be a problem per se: libraries introduce new symbols
all the time, and once programs start referencing them it's expected
that they won't work with older versions of the library.

In this case, however, as you've noticed libvirt-daemon-driver-lxc
contains an inaccurate dependency: it claims that it can work with
fuse3 >= 3.2.3, while we've just demonstrated that it really needs
fuse3 >= 3.13.0-1. Why is this happening?

Comparing the upstream version scripts for fuse 3.12 and 3.13, we can
see the following differences:

  --- 12/lib/fuse_versionscript	2022-09-08 12:02:45.000000000 +0200
  +++ 13/lib/fuse_versionscript	2023-01-13 11:33:35.000000000 +0100
  @@ -39,6 +39,7 @@
   		fuse_session_new;
   		fuse_main_real;
   		fuse_mount;
  +		fuse_session_custom_io;
   		fuse_session_mount;
   		fuse_new;
   		fuse_opt_insert_arg;
  @@ -139,6 +140,7 @@
   	        fuse_lib_help;
   		fuse_invalidate_path;
   		fuse_new_30;
  +		fuse_new_31;
   		fuse_new;
   } FUSE_3.0;
  
  @@ -184,6 +186,7 @@
   		fuse_parse_cmdline;
   		fuse_parse_cmdline_30;
   		fuse_parse_cmdline_312;
  +		fuse_lowlevel_notify_expire_entry;
   } FUSE_3.4;
  
   # Local Variables:

In other words, upstream developers have retroactively added symbols
(fuse_new_31) to existing symbol groups (FUSE_3.1). This was probably
done with good intentions, as the name of the function clearly
indicates that it was introduced in version 3.1 and the fact that it
was missing from the symbol group was almost certainly a bug.
However, addressing the issue the way they've done it also has the
unintended consequence that you've experienced.

I believe it should be possible to work around this in Debian by
adding an entry like

  fuse_new_31 at FUSE_3.1 3.13.0

to debian/libfuse3-3.symbols, but really this looks like an upstream
bug in my opinion: even if the function was present in the source
code all the way back in 3.1, it's only publicly exported starting
with 3.13, and so exposing it as fuse_new_31 at FUSE_3.13 would have
been the correct way to go about it IMO.

Either way, this is for the fuse3 maintainer and upstream to decide,
and there's nothing libvirt can do. I'm going to reassing the bug
accordingly.

-- 
Andrea Bolognani <eof at kiyuko.org>
Resistance is futile, you will be garbage collected.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://alioth-lists.debian.net/pipermail/pkg-libvirt-maintainers/attachments/20230318/6b6c9ef9/attachment.sig>


More information about the Pkg-libvirt-maintainers mailing list