Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libvirt broken in musl due to lack of utmpx implementation in musl #14721

Closed
ktm5j opened this issue Sep 25, 2019 · 13 comments
Closed

libvirt broken in musl due to lack of utmpx implementation in musl #14721

ktm5j opened this issue Sep 25, 2019 · 13 comments
Labels
bug Something isn't working

Comments

@ktm5j
Copy link

ktm5j commented Sep 25, 2019

System

  • xuname: Void 5.2.15_1 x86_64-musl GenuineIntel uptodate rF
    output of xuname (part of xtools)
  • package: libvirt - 5.7.0-r0 (assuming all versions?
    affected package(s) including the version

Expected behavior

After installing libvirt and configuring services, I should be able to connect to the host using virt-manager/virsh/etc and use normally

Actual behavior

libvirt starts properly, and I can connect using virt-manager/virsh.. however once I try to create a VM I am given this error message:

[root@ruby ~ ]# virsh create /tmp/vm.xml
error: Failed to create domain from /tmp/vm.xml
error: internal error: child reported (status=125): Unable to get host boot time: No data available  

Steps to reproduce the behavior

Install libvirt under musl and try using it

I have tracked the error down to an issue with musl's lack of utmpx implementation. The error message is generated by this if statement in libvirt

The function is calling virHostGetBootTime() from src/util/virhostuptime.c where the error occurs. This function is calling getutxid() from utmpx.h however the musl implementation of utmpx simply returns NULL for this and many other functions.

Has libvirt ever worked under musl? Is this happening now because of a change that was made in libvirt? Sorry if this is the wrong place to file this issue, but I would really like to get this working if possible

Thanks

@Hoshpak Hoshpak added the bug Something isn't working label Sep 25, 2019
@Hoshpak
Copy link
Member

Hoshpak commented Sep 25, 2019

I don't know for sure if libvirt ever worked on musl since I've never tried it. But if this is the only issue there is on musl, it should have worked before the last update. Version 5.7.0 introduced the virHostGetBootTime() check and thus also stopped working on Void glibc systems. This was solved by writing a record to utmp at boot time.

I'm not sure how we should deal with this. Libvirt is using POSIX functions here so they are not relying on something that generally is libc specific. Musl implements the POSIX specifications which only states that these functions shall be declared and function prototypes shall be provided, not that the functions actually have to do anything.

I tried earlier to pretend that the function is not available and compile libvirtd that way but that just makes it error out with a different error.

@loreb
Copy link
Contributor

loreb commented Oct 10, 2019

I didn't try, but I guess you could use http://skarnet.org/software/utmps/ - install it, run the server and LD_PRELOAD libutmps as a workaround.

Long term, since musl refuses (rightfully imho) to implement those things, the solution would be to add the client part to the musl C library (a rewrite without the skalibs), falling back to a NOP if utmpd is not running; this requires

  • someone who cares enough to do the work
  • convincing the musl guys to accept the patch
  • convincing the utmps author to freeze and document the protocol

Better solutions are welcome - eg if all you need is boot time you could stub that, but next releases may need something more, so this is probably a worse solution...

@akschu
Copy link

akschu commented Oct 11, 2019

There seems to be a config option you can change to disable this feature in libvirt:

https://bugzilla.redhat.com/show_bug.cgi?id=1760885

@ktm5j
Copy link
Author

ktm5j commented Oct 11, 2019

@akschu Yes that works!! Thank you so much, greatly appreciate the workaround.

I have a week off coming up, I'll see if I can come up with a good solution that doesn't remove functionality

@akschu
Copy link

akschu commented Oct 11, 2019

I'm not entirely sure what that removes that we care about. Perhaps you can tell me...

@ktm5j
Copy link
Author

ktm5j commented Oct 11, 2019

I suppose nothing important, I'm perfectly happy with this solution

@ktm5j
Copy link
Author

ktm5j commented Oct 11, 2019

Though certainly something needs to happen.. as of now if you install libvirt under void-musl, it's non-functional and with nothing obvious to point you in the right direction. Can we make this a default option?

Since these functions were added to libvirt recently, and they seem to be geared towards security.. will other things break in the future without these time functions available?

@Hoshpak
Copy link
Member

Hoshpak commented Oct 12, 2019

I will disable that feature by default for the musl packages. Since the file is a conf_file, it will only be updated for people who haven't made any manual changes to the file previously. Since it works fine on glibc systems, I think we can leave it at the default there.

@ktm5j
Copy link
Author

ktm5j commented Oct 12, 2019

Sounds great! Thanks for the best Linux distro I've used in years! I really appreciate all the work you guys do.

@zippy2
Copy link

zippy2 commented Oct 14, 2019

I don't know for sure if libvirt ever worked on musl since I've never tried it. But if this is the only issue there is on musl, it should have worked before the last update. Version 5.7.0 introduced the virHostGetBootTime() check and thus also stopped working on Void glibc systems. This was solved by writing a record to utmp at boot time.

I'm not sure how we should deal with this. Libvirt is using POSIX functions here so they are not relying on something that generally is libc specific. Musl implements the POSIX specifications which only states that these functions shall be declared and function prototypes shall be provided, not that the functions actually have to do anything.

Wait what? Can you elaborate more please? I'm the one who wrote that code and I don't recall seeing this behaviour documented somewhere. How can one write good software when libraries are playing tricks like this? Our code is #ifdef-ed and at configure time presence of getutxid() is checked. I can put another case for linux systems that don't have the function (presumably the function will read /proc/uptime and then do some time calculations).

I tried earlier to pretend that the function is not available and compile libvirtd that way but that just makes it error out with a different error.

Yes, because libvirt's philosophy is to use POSIX and be able to compile on POSIX systems. Anything that's above has to be in a separate module.

@Hoshpak
Copy link
Member

Hoshpak commented Oct 14, 2019

I was refering to https://pubs.opengroup.org/onlinepubs/9699919799/ which states:

The following shall be declared as functions and may also be defined as macros. Function prototypes shall be provided.

void          endutxent(void);
struct utmpx *getutxent(void);
struct utmpx *getutxid(const struct utmpx *);
struct utmpx *getutxline(const struct utmpx *);
struct utmpx *pututxline(const struct utmpx *);
void          setutxent(void);

Musl implements that by declaring the functions and just having them return NULL when called in https://git.musl-libc.org/cgit/musl/tree/src/legacy/utmpx.c .

This is arguably a bad way to do it but I think since the standard does not mandate an implementation they are not technically breaking the specification. So the check for the function's existance will succeed, the code will compile but it will not work the way it's inteded to do.

We had the same issue with glibc earlier since runit as an init system does not write utmp records as other init systems do so libvirt would fail the same way as it did on musl. We worked around that however by writing a boot record within our own boot scripts.

@zippy2
Copy link

zippy2 commented Oct 14, 2019

That is some creative interpretation by musl developers. The same wording is used for time(2):

The following shall be declared as functions and may also be defined as macros. Function prototypes shall be provided.
...
time_t     time(time_t *);

https://pubs.opengroup.org/onlinepubs/9699919799/

But okay, I will write a patch that tries to use /proc/uptime if getutxent fails.

@loreb
Copy link
Contributor

loreb commented Oct 14, 2019

@zippy2 fyi it's not creative interpretation, it's intentional because there's no way you can implement those functions sanely in a library - it's in their FAQ after all, you need an external process to implement them properly (the musl developers think a setuid executable because they are writing a libc, so all they need is to install /usr/local/bin/musl-utmp, ska prefers a daemon because he's writing a supervision suite + init).

There was even an article on hacker news a few months ago detailing in which ways these functions were broken on the various unices and how nobody cared enough to fix them; the only reasons I personally care (a little bit) are w(1) and "last login on $date", which are both broken on a musl-based distro.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants