[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Is an init required to obey policy-rc.d during boot ?



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.


Reply to: