mirror of
https://github.com/troglobit/finit.git
synced 2026-10-02 05:52:48 +07:00
Apply a PAM session to run/task/sysv/services Finit starts, pam_limits
above all, so a service running as a given user picks up that user's
limits the way a login does.
Add a new `pam` setting for the new block format (only), like the
per-service directories, naming a file in /etc/pam.d:
service weston {
user = "weston"
pam = "weston-autologin"
command = "/usr/bin/weston --continue-without-input"
}
pam_close_session() has to be called by a process still holding the
handle, and the handle does not survive exec(). Hence the keeper: it
holds the handle, drops to the service's credentials, and waits for a
parent-death signal before closing the session. Same shape as
systemd's (sd-pam), for the same reason, and one per fork, so the
script hooks open and close their own.
The keeper closes the descriptors it inherited from Finit and only
those. Closing everything would also take out what pam_open_session()
opened for itself, a keyring fd or a lock file, and leave the modules
to close a session with those pulled out from under them. Closing
nothing, as (sd-pam) does, would leave it holding the write end of the
notify pipe for the service's whole lifetime and starve notify = "s6"
services of their ready signal. So the fds open before pam_start()
are snapshotted and exactly those are closed, while the ones PAM opens
after are marked close-on-exec so the daemon does not inherit them
either.
A refused value, a denied account stack, an uninstalled pam.d file,
and a build without PAM support all keep the service from starting
rather than running it with the stacks skipped: one that quietly loses
pam_limits and its private /tmp, with nothing said. Capabilities a
module like pam_cap.so granted are merged into the IAB Finit applies
instead of being replaced by it, which only helps a service that also
sets capabilities, the other arm being a plain setuid() with nothing
left to restore once permitted is empty.
The test sysroot gains pam_permit.so, pam_deny.so and pam_limits.so,
which ldd cannot see, libpam dlopen()s them, and the test skips when
the host has none to stage. The negative cases pin the exit status
rather than only asserting crashed, which serv reports for any early
exit, so a bad command or an unwritable pidfile cannot pass for a
rejected session.
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
302 lines
11 KiB
Markdown
302 lines
11 KiB
Markdown
Building Finit
|
|
==============
|
|
|
|
Finit comes with a traditional configure script to control features and
|
|
optional plugins to enable. It depends on three external libraries:
|
|
|
|
- [libuEv][], the event loop
|
|
- [libite][] (-lite), much needed frog DNA
|
|
- [libConfuse][], the parser behind the .conf format
|
|
|
|
The bundled device manager, keventd, needs a fourth: libblkid from
|
|
[util-linux][]. It reads the filesystem UUID and label off block
|
|
devices, which is what the curated rules name the `/dev/disk/by-uuid/`
|
|
and `/dev/disk/by-label/` symlinks after. keventd is enabled by
|
|
default, so this is a hard requirement unless you build with
|
|
`--without-keventd`.
|
|
|
|
PAM session support for services is built by default. It needs
|
|
[Linux-PAM][] (-lpam); the build falls back to no PAM support when that
|
|
library is missing. A static build, `--enable-static`, disables PAM
|
|
too, since libpam loads its modules with `dlopen()`.
|
|
|
|
> [!IMPORTANT]
|
|
> Most free/open source software packages that use `configure` default
|
|
> to install to `/usr/local`. However, some Linux distributions do no
|
|
> longer search that path for installed software, e.g. Fedora and Alpine
|
|
> Linux. To get finit's configure script to find its dependencies you
|
|
> have to help the `pkg-config` tool a bit if you do not change the
|
|
> default prefix path:
|
|
>
|
|
> PKG_CONFIG_LIBDIR=/usr/local/lib/pkgconfig ./configure
|
|
|
|
The configure script checks for all dependencies, including the correct
|
|
version of the above mentioned libraries. Currently required versions:
|
|
|
|
- libite v2.2.0, or later
|
|
- libuEv v2.2.0, or later
|
|
- libConfuse v3.3, or later
|
|
- libblkid, any version, when keventd is enabled
|
|
|
|
|
|
Configure
|
|
---------
|
|
|
|
Below are a few of the main switches to configure:
|
|
|
|
* `--prefix=..`: Usually you want to set this to `/usr`, default is the GNU
|
|
default: `/usr/local`
|
|
|
|
* `--exec-prefix=..`: This you want to set to the empty string, or `/`, to
|
|
ensure the programs `finit` and `initctl` are installed to the proper
|
|
locations. Linux expects an "init" in `/sbin`, default: `--prefix`
|
|
|
|
* `--sysconfdir=..`: follows `--prefix`, you likely want it to be `/etc`
|
|
|
|
* `--localstatedir=..`: follows `--prefix`, you likely want `/var`
|
|
|
|
* `--enable-static`: Build Finit statically. The plugins will be
|
|
built-ins (.o files) and all external libraries, except the C library
|
|
will be linked statically.
|
|
|
|
* `--disable-pam`: Opt out of Finit's built-in PAM session support,
|
|
enabled by default, which lets a service declare `pam = "name"` and
|
|
run inside a session set up from `/etc/pam.d/name`. Needs libpam,
|
|
falls back to disabled when it is missing, and is also disabled for
|
|
`--enable-static` builds. Asking for `--enable-pam` and
|
|
`--enable-static` together is an error rather than a fallback. See
|
|
[PAM Sessions](config/pam.md)
|
|
|
|
* `--enable-kernel-cmdline`: Enable Finit pre-4.1 parsing of init args from
|
|
`/proc/cmdline`, this is *not recommended* since Finit may be running as the
|
|
init for container apps that can see the host's `/proc` filesystem
|
|
|
|
* `--disable-dbus`: Opt out of Finit's built-in D-Bus support, enabled by
|
|
default. See [D-Bus Integration](dbus.md) for what it provides. Not to
|
|
be confused with `--disable-dbus-plugin` below, which only governs
|
|
starting an external `dbus-daemon`
|
|
|
|
* `--enable-alsa-utils-plugin`: Enable the optional `alsa-utils.so` sound plugin.
|
|
|
|
* `--disable-dbus-plugin`: Drop the `dbus.so` plugin, which launches
|
|
`dbus-daemon` at boot. Enabled by default; the plugin does nothing on
|
|
a system that has no `dbus-daemon` installed, so opting out is only
|
|
needed to keep init from starting a bus on a system that has one.
|
|
Unrelated to the built-in bus, see `--disable-dbus` above.
|
|
|
|
* `--enable-resolvconf-plugin`: Enable the `resolvconf.so` optional plugin.
|
|
|
|
* `--enable-x11-common-plugin`: Enable the optional X Window `x11-common.so` plugin.
|
|
|
|
* `--without-keventd`: Drop the bundled device manager, for systems that
|
|
run mdev, mdevd, or udevd instead. Enabled by default, and the only
|
|
thing that pulls in libblkid. See [Bundled Device Manager](keventd.md).
|
|
|
|
* `--without-sulogin`: Drop the bundled `sulogin`, enabled by default,
|
|
and use the system `sulogin(8)` instead. The one shipped with Finit
|
|
*allows password-less* login if the `root` user is disabled or has no
|
|
password at all. `--with-sulogin=USER` prompts for another user's
|
|
password than `root`'s.
|
|
|
|
* `--without-watchdog`: Drop the bundled `watchdogd`, enabled by default
|
|
on `/dev/watchdog`, `--with-watchdog=DEV` selects another device.
|
|
Finit starts it when the device node exists, see [Watchdog](watchdog.md).
|
|
|
|
* `--with-libsystemd`: Build the replacement `libsystemd`, which lets
|
|
programs that use `sd_notify()` talk to Finit without systemd. Off by
|
|
default because it installs `libsystemd.so.0` in `$libdir`: on a host
|
|
that has the real one, ours shadows it in the loader cache and every
|
|
program linking it, `dbus-daemon` and `udevd` included, loses the
|
|
symbols it needs. Safe on a systemd-free system, which is the point
|
|
of it.
|
|
|
|
For more configure flags, see <kbd>./configure --help</kbd>
|
|
|
|
> [!NOTE]
|
|
> The configure script is not available in the GIT sources. It is
|
|
> however included in (officially supported) released tarballs. The
|
|
> idea is that you should not need GNU autotools to build, only the
|
|
> above mentioned dependencies, a POSIX shell, a C compiler and make.
|
|
> Any contributing to Finit can generate it from `configure.ac` using
|
|
> the `autogen.sh` script.
|
|
|
|
|
|
Example
|
|
-------
|
|
|
|
First, unpack the archive:
|
|
|
|
```shell
|
|
$ tar xf finit-4.3.tar.gz
|
|
$ cd finit-4.3/
|
|
```
|
|
|
|
Then configure, build and install:
|
|
|
|
```shell
|
|
$ ./configure --prefix=/usr --exec-prefix= \
|
|
--sysconfdir=/etc --localstatedir=/var
|
|
$ make
|
|
.
|
|
.
|
|
.
|
|
$ DESTDIR=/tmp/finit make install
|
|
```
|
|
|
|
In this example the [finit-4.3.tar.gz][1] archive is unpacked to the
|
|
user's home directory, configured, built and installed to a temporary
|
|
staging directory. The environment variable `DESTDIR` controls the
|
|
destination directory when installing, very useful for building binary
|
|
standalone packages.
|
|
|
|
Finit 4.1 and later can detect if it runs on an embedded system, or a
|
|
system that use BusyBox tools instead of udev & C:o. On such systems
|
|
`mdev` instead of `udev` is used. However, remember to also change the
|
|
Linux config to:
|
|
|
|
CONFIG_UEVENT_HELPER_PATH="/sbin/mdev"
|
|
|
|
> [!TIP]
|
|
> If you run into problems starting Finit, take a look at `finit.c`.
|
|
> One of the most common problems is a custom Linux kernel build that
|
|
> lack `CONFIG_DEVTMPFS`. Another is too much cruft in the system
|
|
> `/etc/fstab`.
|
|
|
|
|
|
Testing
|
|
-------
|
|
|
|
`make check` runs the test suite in a private namespace, so it is safe
|
|
on a running system. It needs `unshare` and, on Ubuntu, unprivileged
|
|
user namespaces enabled:
|
|
|
|
```shell
|
|
sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0
|
|
make check
|
|
```
|
|
|
|
The D-Bus message parser is the only place in Finit where bytes off a
|
|
socket become pointers, so it also has a fuzz target. `make check`
|
|
runs it as a fixed sweep, which takes milliseconds and needs nothing
|
|
beyond the normal build. To fuzz it properly, build it with clang and
|
|
libFuzzer:
|
|
|
|
```shell
|
|
clang -fsanitize=fuzzer,address -DLINK_FUZZ_LIBFUZZER -D_GNU_SOURCE \
|
|
-I libink -I . -o fuzz-msg-parse \
|
|
test/src/fuzz-msg-parse.c libink/*.c
|
|
mkdir -p .fuzz-corpus
|
|
./fuzz-msg-parse .fuzz-corpus -max_total_time=300
|
|
```
|
|
|
|
Give it a corpus directory as above and it saves what it learns there,
|
|
so the next run picks up where this one left off instead of starting
|
|
cold. Nothing writes to it unless you name it: without the argument
|
|
libFuzzer keeps everything in memory and the run leaves only crashes
|
|
behind. `make distclean` clears the corpus and the target.
|
|
|
|
Once a corpus has grown, most of it reaches code some earlier input
|
|
already reached. Minimise it:
|
|
|
|
```shell
|
|
./fuzz-msg-parse -merge=1 .fuzz-corpus-min .fuzz-corpus
|
|
rm -rf .fuzz-corpus && mv .fuzz-corpus-min .fuzz-corpus
|
|
```
|
|
|
|
Run `./configure` first, the target needs the generated `config.h`.
|
|
If the link fails with `cannot find -lstdc++`, install the `libstdc++`
|
|
headers matching the newest GCC on the system, not the default one:
|
|
clang picks the newest tree it finds, and that is the one that needs
|
|
them. CI runs this target on every pull request, carrying its
|
|
corpus between runs so it reaches deeper over time.
|
|
|
|
Feed a file back to the target to reproduce a find:
|
|
|
|
```shell
|
|
./fuzz-msg-parse crash-3f2a...
|
|
```
|
|
|
|
|
|
Running
|
|
-------
|
|
|
|
Having successfully built Finit it is now be time to take it for a test
|
|
drive. The `make install` attempts to set up finit as the system system
|
|
init, `/sbin/init`, but this is usually a symlink pointing to the
|
|
current init.
|
|
|
|
So either change the symlink, or change your boot loader (GRUB, LOADLIN,
|
|
LILO, U-Boot/Barebox or RedBoot) configuration to append the following
|
|
to the kernel command line:
|
|
|
|
```shell
|
|
append="init=/sbin/finit"
|
|
```
|
|
|
|
Remember to also set up an initial `/etc/finit.conf` before rebooting!
|
|
|
|
|
|
Recovery
|
|
--------
|
|
|
|
To rescue a system with Finit, append the following to the kernel
|
|
command line:
|
|
|
|
```shell
|
|
append="init=/sbin/finit rescue"
|
|
```
|
|
|
|
This tells Finit to start in a very limited recovery mode, no services
|
|
are loaded, no filesystems are mounted or checked, and no networking is
|
|
enabled. The default Finit rescue mode configuration is installed into
|
|
`/lib/finit/rescue.conf`, which can be safely removed or changed.
|
|
|
|
By default the a root shell, without login, is started.
|
|
|
|
> [!IMPORTANT]
|
|
> In rescue mode `initctl` will not work, the same goes for `reboot`,
|
|
> `shutdown`, and `poweroff` commands, provided they are the Finit
|
|
> versions of these commands. Use the `-f` flag to force the action.
|
|
|
|
|
|
Debugging
|
|
---------
|
|
|
|
Edit, or append to, the kernel command line: remove `quiet` to enable
|
|
kernel messages and add `finit.debug` to enable Finit debug messages.
|
|
|
|
```shell
|
|
append="init=/sbin/finit -- finit.debug"
|
|
```
|
|
|
|
Notice the `--` separator.
|
|
|
|
To debug startup issues, in particular issues with getty/login, add
|
|
the following to your Finit .conf file:
|
|
|
|
tty board {
|
|
runlevel = "12345789"
|
|
notty = true
|
|
noclear = true
|
|
}
|
|
|
|
The `notty` option ensures reusing the stdin/stdout set up by the
|
|
kernel. Remember, this is only for debugging and would leave your
|
|
production system potentially wide open.
|
|
|
|
There is also a rescue shell available, in case Finit crashes and the
|
|
kernel usually reboots: `configure --enable-emergency-shell`. However,
|
|
the behavior of Finit is severely limited when this is enabled, so use
|
|
it only for debugging start up issues when Finit crashes.
|
|
|
|
> [!CAUTION]
|
|
> None of these options should be enabled on production systems since
|
|
> they can potentially give a user root access.
|
|
|
|
[1]: https://github.com/finit-project/finit/releases/download/4.3/finit-4.3.tar.gz
|
|
[libuEv]: https://github.com/troglobit/libuev
|
|
[libite]: https://github.com/troglobit/libite
|
|
[libConfuse]: https://github.com/libconfuse/libconfuse
|
|
[util-linux]: https://github.com/util-linux/util-linux
|
|
[Linux-PAM]: https://github.com/linux-pam/linux-pam
|