boinc icon indicating copy to clipboard operation
boinc copied to clipboard

On Linux, the manager cannot start the core client as a service

Open TheAspens opened this issue 6 years ago • 6 comments

This issue comes from discussions during the contributor call that was hosted on April 18, 2019 when discussing pull request #3094

The installation on Linux sets up the core client to run as a service. If the user sets their permissions correctly and then runs the BOINC Manager with the directory to /var/lib/boinc then they are able to connect to the core client.

The user is then able to cause the core client to exit. If they then open the manager again then the manager will start up a instance of the core-client with the directory set to /var/lib/boinc the manager will start up the core-client but run it under the user's id instead of the boinc id. This can cause a lot of issues.

The BOINC manager should instead detect that the /var/lib/boinc was run as a service and if the client is not running, it should then attempt to start the service or provide the users to instructions on how to do so.

TheAspens avatar Apr 18 '19 15:04 TheAspens

There are comments and functions starting from https://github.com/BOINC/boinc/blob/master/clientgui/BOINCClientManager.cpp#L91 explaining how service mode is detected and used by the Manager.

In consultations around #3094 leading up to the discussion, several users expressed that they would wish to prevent or delay BOINC startup as a service to allow prerequisites such as graphics drivers and WiFi networking to initialise first.

RichardHaselgrove avatar Apr 18 '19 15:04 RichardHaselgrove

This is likely a doomed proposition from the start. This kind of thing is easy on Windows and macOS (and even many non-Linux UNIX-like systems such as Solaris) because they have exactly one way to handle services. On Linux though, you have at least half a dozen possibilities, including:

  • Management through systemd as a system service (Most Linux systems these days)
  • Management through systemd as a user service (I don't know of any distros that explicitly configure things like this, but I know people who have things et up this way).
  • Handled under a traditional init.d setup (Older Debian and Fedora, still widely used by some people who explicitly switch off of systemd on Debian)
  • Handled by OpenRC (Gentoo and derivatives, as well as some others)
  • Handled by runit (Void Linux, among others)
  • Handled as a BSD-style rc.d service (used by some odd fringe distributions)

Note that that just covers the common cases, there are dozens of other possibilities (direct under sysv init, handled by s6, running under Upstart as a system service, running under a dedicated service manager such as monit independent of the init system, etc), and they can often be combined in non-trivial ways (for example, I run it as a system service under OpenRC (because I'm on Gentoo), but use monit to actually manage starting and stopping that service).

This also, mostly, ignores all the potential permissions issues involved here. The installation of BOINC can't sanely handle getting the permissions right, there's just too many variables. That leaves either running the manager with root privileges, or requiring special effort from the user to get things working correctly (which is easy to get wrong, and trivial to do insecurely).

several users expressed that they would wish to prevent or delay BOINC startup as a service to allow prerequisites such as graphics drivers and WiFi networking to initialise first.

I would suggest pointing them at their distribution's documentation then. If they're running BOINC as a system service, they should just need to configure service dependencies correctly.

Ferroin avatar Apr 18 '19 15:04 Ferroin

While there are many ways to run services on Linux, I believe that only systemd is used by the current install of the BOINC core-client when pulled from the maintained packages for debian and epel. As a result, I think that this is the case that should be handled.

I believe that what would be necessary to make this work is that the installation should create a file at /etc/sudoers.d/boinc that lets members of the group boinc run any of the following commands:

  • sudo systemctl stop boinc-client
  • sudo systemctl start boinc-client
  • sudo systemctl status boinc-client
  • sudo systemctl restart boinc-client

This should allow anyone who adds their user account to the boinc group (which is required to connect to the core-client running as a service) to then be able to manage the boinc service without requiring any additional permissions.

This should also allow the boinc manager when running under an id that belongs to the boinc group to be able to start/stop the client running as a service.

If someone builds the client on their own and sets it up under a different service mechanism, they should be able to look at what was done for systemd and do something similar for that.

TheAspens avatar Apr 18 '19 19:04 TheAspens

A quick check on Debian Sid seems to indicate that BOINC there still does work with sysv-init (just like pretty much every other package on Debian that doesn't explicitly require service provided by systemd).

That said, covering the case of conventional /etc/init.d scripts as well as systemd will indeed make things 'just work' for probably 95% of users on Linux. Overall, you just substitute the commands you listed for:

  • sudo /etc/init.d/boinc-client stop
  • sudo /etc/init.d/boinc-client start
  • sudo /etc/init.d/boinc-client status
  • sudo /etc/init.d/boinc-client restart

On Debian, that will actually work regardless of whether the system is using systemd or sysv-init (the boinc-client package installs the script regardless, and it calls out to systemd if systemd is in use on the system), but not on other systems which have either init system as an option (which will still need either the systemd commands or the init scripts as appropriate).

Abstracting that a bit to search for either boinc-client or boinc as the script name will get you compatibility with about 95% of systems still using sysv-init as well as any systems using OpenRC with the standard script for that for starting BOINC.

Issues I still see with this:

  • Detecting systemd reliably is surprisingly hard unless you actually depend on it. It's fully possible to have a 'complete' install of systemd while still actually using sysv-init as your init system, and Debian and Gentoo even support such a situation to a certain degree (otherwise it would be nearly impossible to switch a system from one to the other). The simplest code I've seen that works reliably even inside containers and those intermediate cases is still a few thousand lines of code.
  • sudo is not as ubiquitous as you might think. doas (from Open BSD) is surprisingly popular on Linux, and I've also seen quite a few boxes that have shifted to using only pkexec for privilege escalation. I don't see this as a show-stopper, but it would still be nice to work with any of the three.
  • There's no good way to determine if /etc/init.d/boinc status will actually work, and you can't rely on any specific output from it. Most distros use some variant of the Debian init script, so it's usually going to work, but it's not necessarily going to have consistent output (even on Debian itself, you get drastically different output between the systemd and sysv-init cases).
  • Exact behavior of the systemctl stop command is dependent on whether the service unit is required by the active target (or a dependency of the active target), activated through socket activation (I've seen people do this before, using the GUI RPC port as an activation trigger so that the client starts automatically when the manager tries to connect, as such an approach solves the problem of requiring X to be running for GPU's to work reliably), or handled manually. The case of it being an actual dependency is particularly important here, as that will be the common case, and systemctl stop does not guarantee in that case that the service will stay stopped.
  • It still leaves people on other distros out, requiring their package mainainers to handle things themselves. I'd at least suggest having a configure option to disable the manager's service management behavior so that distributions can disable it if they want to. Ideally, there would be a way to define what commands to use for service management on Linux at runtime somehow (or at least when building the manager), with a fallback to the systemd and init.d methods detailed above.

Ferroin avatar Apr 18 '19 19:04 Ferroin

Actually rather than configuring /etc/sudoers.d, another way is with a polkit configuration:

/etc/polkit-1/rules.d/57-manage-boinc-client-service.rules (centos/fedora)

polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.systemd1.manage-units" &&
        action.lookup("unit") == "boinc-client.service" &&
        subject.group == "boinc") {
        return polkit.Result.YES;
    }
});

Unfortunately, this is not available until polkit v 226 and RedHat/CentOS aren't on a high enough level. (ref: https://superuser.com/questions/1064616/polkit-systemd-interaction)

[edit: as a FYI - I was testing and writing this and didn't see @Ferrion 's response until after I posted]

TheAspens avatar Apr 18 '19 20:04 TheAspens

several users expressed that they would wish to prevent or delay BOINC startup as a service to allow prerequisites such as graphics drivers and WiFi networking to initialise first.

I would suggest pointing them at their distribution's documentation then. If they're running BOINC as a system service, they should just need to configure service dependencies correctly.

Precisely, that should be possible with systemd at least, see e.g. https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/. There are probably similar solutions for other service managers.

I believe that what would be necessary to make this work is that the installation should create a file at /etc/sudoers.d/boinc that lets members of the group boinc run any of the following commands:

* sudo systemctl stop boinc-client
* sudo systemctl start boinc-client
* sudo systemctl status boinc-client
* sudo systemctl restart boinc-client

As was discussed in #3094, the service model in Linux is that system services are started or stopped only by the administrator, and distributions don't want you to circumvent that. So this or the polkit rules are probably just going to be removed by packagers.

BOINC is a strange hybrid, since you'll typically want to have only one instance running per system, so it shouldn't be a user service, but the user controls it completely. But you could do the same with a webserver: you could provide a browser interface for managing all aspects of the webserver, but you'll have to switch to the terminal to restart it.

The user is then able to cause the core client to exit.

That I think is the issue. However, #3094 was wrong in my view as it removed the options from the GUI (where they are fine even under Linux, since you can also start the client under your user, e.g. for testing purposes), instead the client should refuse such requests when running as service. Ideally it would just process SIGTERM then and ignore any RPC requests to quit.

Not sure how to best detect whether the client is running as a service, but with systemd one could probably inspect /proc/$PID/cgroup, or /proc/self/cgroup from the client. However, it's difficult for the manager to know how the client is running, since all it has is a host:port combination plus password. So you probably have to leave it in the GUI, but print an error message if the client is a service. As a fallback, one could check if xdg-su is installed and have a button to run xdg-su systemctl stop boinc-client.service. But that wouldn't help if you want to restart the client, so not sure if it's helpful.

aaronpuchert avatar Jan 03 '21 20:01 aaronpuchert