On Thu, 23 Apr 2020 at 16:59:43 +0200, Simon Richter wrote: > The policy-rc.d mechanism is used by invoke-rc.d, which is defined as the > appropriate way to start an init script in Policy, so sysadmins have a > reasonable expectation that all init scripts use that mechanism.
It's documented in Policy as the appropriate way for *a maintainer script* to start an init script. debhelper-generated maintainer-script fragments in packages that have systemd services often don't actually use invoke-rc.d any more, but they do use deb-systemd-invoke, a Debian-specific program closely resembling invoke-rc.d; it does similar checks, including policy-rc.d. Policy should ideally document those two as being equally valid, if it doesn't already. policy-rc.d and invoke-rc.d are not documented in Policy to be a way to control what happens after you reboot, and neither sysv-rc nor systemd runs invoke-rc.d or consults policy-rc.d during normal system boot. Just to make sure I wasn't spreading misinformation, I tested this in a VM, using sysvinit: - apt install sysvinit-core (systemd is removed) - reboot - write "#!/bin/sh\nexit 101\n" into /usr/sbin/policy-rc.d - apt install apache2 (prints "invoke-rc.d: policy-rc.d denied execution of start") - pgrep apache (no output) - reboot - pgrep apache (now it is running) > As far as I can see, there is no similar mechanism in systemd that allows > blanket refusal or logging of unknown services, only masking of known > services by name. Taking a step back from policy.d specifically (since it is not a suitable tool to control what happens during boot), I think your statement is correct, but that's a bit like saying there's no mechanism in Unix that allows blanket refusal or logging of unknown executable programs, only deleting or `chmod -x` known programs by name.[1] Yes, it's true; but if there was such a mechanism, a large part of its practical effect would be to prevent the programs you do want, some of which probably run unknown-to-you programs as an implementation detail, from working correctly. systemd.preset(5) (see below) is probably the closest. However, systemd services can and do depend on other services (some of which might be an implementation detail of how a larger, user-facing service is broken up into modules, rather than something directly user- or network-facing). If they do, both targets and presets will normally start the depended-on service, in order to make the dependent service work. If you have looked at everything that depends on a specific service and decided that, even at the risk of breaking the dependent services, you still don't want to run it, that's what masking services is for. > On Wed, Apr 22, 2020 at 03:09:13PM +0100, Simon McVittie wrote: > > In a systemd-based system, I would achieve the equivalent of #950851 > > by telling systemd to start a restricted target that only contains the > > services I specifically want, instead of the default 'graphical.target' > > (targets are analogous to sysvinit runlevels, but you can have any number > > of them). Perhaps runit has, or could have, something similar? > > Can that be automated through a well-defined interface, to allow sysadmins > overseeing larger installations to control this centrally through one of > the automation frameworks? The submitter of #950851 was talking about special-purpose, single-use containers, rather than about full machines with sysadmins and a normal init system, and my suggestion was specific to that use-case. (Containers as a heavier-weight alternative to a chroot, rather than containers as a lighter-weight alternative to a VM.) systemd targets do have a well-defined interface, described in systemd.target(5) and in the KERNEL COMMAND LINE section of systemd(1). However, if you are setting up special-purpose targets, that's getting into OS design rather than sysadmin territory (the line between the two is of course very blurred, and the difference between a special-purpose OS and an extensively configured instance of a general-purpose OS is mostly a matter of point of view). If (as it sounds like to me) your use-case is not the same as that of the submitter of #950851, and you want to control what (high-level, user- and/or network-facing) services are started on a full machine that has a sysadmin and a normal init system and "mostly" boots in the normal Debian way, I'd suggest looking into systemd.preset(5) instead. Debian's normal policy is that "most" installed services get started on boot ("enabled" in systemd terminology), on the assumption that if you don't want the service, you wouldn't install it. Our systemd's default behaviour is configured accordingly. In systemd-using OSs that are more like the Red Hat family, where a standard installation includes a lot more potentially-unwanted services and as a result the policy is that "most" installed services *don't* get started on boot (not "enabled"), the systemd.preset(5) mechanism is how that policy is implemented. It sounds as though the Red-Hat-like configuration might be more suitable for your needs. According to systemd.preset(5), the Debian-ish enable-by-default behaviour is the upstream default, and the Red-Hat-ish disable-by-default behaviour is a one-line configuration change (presumably Red-Hat-derived distros install exactly that one line). Again, some services are critical to the boot process or to other services' assumptions: they'll often get pulled in by dependencies even if they are not "enabled", or they might be "statically enabled" in /usr, and either way masking or otherwise breaking them will tend to lead to a non-functional system. This is the same as with sysv-rc, where disabling most of rc2.d would be OK, but disabling most of rcS.d will probably get you a non-working system. > Can maintainer scripts expect systemd services to be available (mainly > thinking about tmpfilesd here, but there might be others that become > relevant in the future)? To be clear about that, there is no tmpfilesd daemon: the d in tmpfiles.d stands for directory like rc2.d, not daemon like sshd. On package installation, tmpfiles.d fragments are processed by maintainer scripts (driven by dh_installtmpfiles), without taking policy-rc.d into account. During boot, they are processed by systemd-tmpfiles-setup.service, which is a "one-shot" service (analogous to LSB init scripts like /etc/init.d/x11-common that run some commands and then exit, with no daemons or background processes left behind). If that service is masked, then anything that relied on it (quite a large proportion of a typical systemd-booted system) will fail. smcv [1] Arguably LSMs like AppArmor are such a mechanism, with both the good side (total control over what can be run) and the bad side (high probability that not everything you need was allowed)? :-) But AppArmor has a concept of unconfined programs that are allowed to run anything they want to, and many programs that are critical to having a working boot process, including init itself, are unconfined, which mitigates the bad side.