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

Re: Policy consensus on transition when removing initscripts.



On Mon, 26 Jun 2023 at 15:03:51 +0900, Simon Richter wrote:
> On 6/25/23 23:15, Mark Hindley wrote:
> > The most recent proposal[6] for updating the Policy with a requirement to use
> > tmpfiles.d(5) states
> 
> >   "Init systems other than ``systemd`` should allow providing the same
> >   functionality as appropriate for each system, for example managing the
> >   directories from the init script shipped by the package."
> 
> The way I see it, we are getting a split between "daemons" and "services",
> and it simply does not make sense to start a "service" directly from an init
> script, because it requires the service orchestrator as its runtime
> environment.

That's certainly not how I understand the difference between a service
and a daemon. The LSB specification refers to the functionality provided
by a LSB init script as a service: this is not a new term introduced
by systemd, and daemons that need some one-time setup before the actual
daemon can be started are not a new concept either.

It's true that a lot of system services are a single daemon (long-running
background process) or a wrapper around a daemon, maybe with some extra
setup/teardown: for example /etc/init.d/dbus has always needed to ensure
that the machine ID exists before it can start dbus-daemon, and various
other init scripts need to create a directory in /run or whatever, owned
by the user ID with which they are going to start the actual daemon.
In systemd jargon, the init script is a "forking" service (it forks in
order to run the daemon process in the background, or instructs the
daemon process to use the double-fork pattern).

Other system services have no daemons at all: /etc/init.d/sudo and
/etc/init.d/apparmor do some one-time actions during boot, and then exit,
leaving no processes running (assuming they're working correctly). In
systemd jargon they're "oneshot" services.

A somewhat rarer category of system services involves a top-level init
script or systemd unit that results in multiple daemons being started,
for example /etc/init.d/postfix.

> "If it is present, it also needs to work." sounds like a reasonable
> statement though.

I'm fairly sure that's the intention here.

The typical case where a daemon has a functional dependency on
tmpfiles.d(5) is that the daemon needs some state directories, either on
disk (typically /var/lib) or in RAM (typically /run), to be set up as
root and chown'd to the appropriate user ID before it can do its work.
For example /usr/sbin/foo might run as user ID _foo and require /run/foo
and/or /var/lib/foo to be 0750 _foo:_foo.

Historically a lot of daemons have required being started as root and
then dropped privileges internally, allowing the daemon to set up those
directories while it is still root. However, not all daemon maintainers
will want their daemon implementation to be responsible for doing that:
when touching a non-root-owned directory as root, it's necessary to be
careful to avoid time-of-check/time-of-use attacks (perhaps involving
symlinks or hard links) that could allow a local attacker to trick the
daemon into changing the ownership or permissions of the wrong file.

Not wanting to drop privileges internally at all is also a design choice
for the daemon, and a valid one IMO: as well as the security impact of
any bugs that might exist in the privilege-dropping code, if a process
started as root and dropped privileges to some other uid, that permanently
restricts its ability to read information out of its own /proc, which is
not always desirable. If the daemon starts up unprivileged, then it can
read its own /proc in the usual way, but obviously it can't create a new
subdirectory of /run or /var/lib itself, so someone else needs to do that.

If a daemon needs its state directories set up in advance like that,
and if someone provides an init script, I hope it's uncontroversial
to say that the init script needs to take responsibility for creating
those state directories, either directly or by delegating it to a
dependency. That's equally true regardless of whether the init script
is provided by the same package as the daemon, or by some other package
like orphan-sysvinit-scripts, or by a local sysadmin.

One way to implement pre-creation of state directories is to use
the declarative tmpfiles.d(5) files. On systemd systems, the package
providing the service can rely on systemd to process those files. On
non-systemd-booted systems, one option is to run on the systemd-tmpfiles
executable (from the systemd-standalone-tmpfiles or systemd package)
during boot and during postinst to achieve the same thing. Another
option is to use a reimplementation of the tmpfiles.d(5) interface; a
third option is to open-code the directory creation in the init script
with some appropriate `mkdir -p`, `chmod` and `chown`, or `install -d`.

Looking at reimplementations of tmpfiles.d(5), OpenRC's opentmpfiles
exists as an upstream project, but was removed from Debian, and my
understanding is that it has some security concerns: there are various
time-of-check/time-of-use attacks available to a malicious local user
when tmpfiles.d implementations act on the contents of a non-root-owned
directory, which systemd-tmpfiles avoids by using the "at" family of
syscalls (fchownat() and so on), but it's difficult for a shell script
reimplementation to do the same.

An implementation in terms of `install -d` or `mkdir -p` might well suffer
from similar attacks in the general case, but hopefully the subset of
the tmpfiles.d interface used by most services is sufficiently small
that those attacks can be avoided for specific services.

    smcv


Reply to: