systemd

Timothée Ravier (@siosm) - https://tim.siosm.fr/cours

5e année cycle ingénieur, filière STI

Option Sécurité des Systèmes Ubiquitaires

2021-2022

Sommaire

Historique

Fonctionnement

journald

Securité

Histoire : SystemV et sysinit (1983)

  • Runlevels (/etc/inittab)
  • Script shell pour chaque service (/etc/init.d/nginx), très souvent spécifique à chaque distribution
  • Démarrage séquentiel, arrêt séquentiel
  • Difficile de maintenir des modifications dans la durée
  • Aucune information sur l'état du système et les services démarrés
  • Difficile de suivre les processus dans la durée (/var/run/nginx.pid)

Histoire : launchd (2005, Mac OS X 10.4)

  • Démarre le système et gère les services
  • Démarrage des services en parallèle et à la demande
  • Démon launchd (PID 1) et « télécommande » launchctl pour gérer les services
  • Gestion des daemons par utilisateur possible
  • Configuration en XML

Histoire : Upstart (2006, Ubuntu 6.10)

  • Démarrage des service à la suite d'événements
  • La carte bluetooth est disponible \Rightarrow démarre le service bluetooth
  • Le réseau est disponible \Rightarrow montage des disques distants
  • Difficile d'empêcher un service de démarrer automatiquement
  • Meilleur que SysV, mais pas assez puissant

Histoire : et les autres...

Implémentations alternatives, généralement basées sur un langage de script :

  • OpenRC (2007, Gentoo)
  • rcNG (NetBSD, FreeBSD et DragonFlyBSD)
  • runit
  • Service Management Facility (SMF, OpenIndiana)

https://linuxfr.org/news/petit-etat-de-l-art-des-systemes-d-initialisation-1

systemd

  • Première version annoncée le 30 mars 2010
  • Développeurs principaux : Lennart Poettering, Kay Sievers, Harald Hoyer, Daniel Mack, Tom Gundersen, David Herrmann
  • Adopté comme init par défaut par pratiquement toutes les distributions majeures (RHEL, Fedora, Ubuntu, Debian, openSUSE, Arch Linux, NixOS, etc.)
  • Optionnel pour Gentoo (openrc par défaut)
  • Non disponible sur Alpine, Slackware, Void

systemd

  • Au début : juste un remplaçant d'init
  • Désormais : ensemble de blocs de base pour construire un système Linux
  • Beaucoup de rumeurs et fausses informations circulent à propos de systemd : The Biggest Myths about systemd
  • Adapté à tous les environnements : Distributions embarquées, voitures, téléphones, tablettes, supercalculateurs, desktops, etc.

Fonctionnement

Fonctionnalités

  • Gestionnaire des services et du système : vue globale
  • Contrôle des « units » plutôt que des démons ou processus
  • Gestion des dépendances entre les units
  • Suivi des processus qui composent chaque unit :
    • Correspondance unit \Leftrightarrow processus
    • Arrêt maîtrisé des units
  • Temps de démarrage minimal
  • Debuggable : Reproductibilité, récupération de tous les logs du système
  • Interface utilisateur : systemctl

Init : PID 1

  • « Premier » processus lancé par le noyau
  • Succède dans le cas général à l'initrd
  • Chargé de démarrer le reste du système :
    • montage des partitions supplémentaires (/ et /usr montées par l'initrd)
    • démarrage des services systèmes
  • Parent de tous les processus orphelins

Init : systemd PID 1

  • Spécialiste du lancement de processus :
    • Quoi? service nginx, mysql, etc.
    • Comment? UID, GID, CWD, capabilities, env, etc.
    • Quand? au démarrage, gestion des dépendances, activation suite à un timer, une socket, un message D-Bus, etc.
    • Qui? Logs
  • et de leur suivi :
    • Qui? Quels processus font parti de mon service ?
    • Status : watchdogs, socket de notification
    • Redémarrage : en cas d'échec, à la réception d'un SIGSEGV
    • Arrêt propre : aucun processus oublié

cgroups

  • systemd place les processus de chaque unit dans un cgroup distinct
  • systemd « seul » gestionnaire des cgroups
  • Changement de granularité : processus \Rightarrow service (cgroup)
  • Réponse facile aux questions :
    • A quel service appartient ce processus ?
    • Quels processus font partie de ce service ?

cgroups : systemd-cgls

11 types d'units systemd

  • nginx.service
  • multi-user.target
  • sshd.socket
  • systemd-tmpfiles-clean.timer
  • -.mount, home.mount
  • acpid.path
  • system.slice, user-1000.slice
  • session-1.scope
  • sys-devices-virtual-block-dm\x2d0.device
  • proc-sys-fs-binfmt_misc.automount
  • dev-mapper-system\x2dswap.swap

Units : Emplacements

  • (/usr)/lib/systemd/system : Fournies par la distribution (lecture seule);

  • /run/systemd/system : Générées à l'exécution, non persistantes;

  • /etc/systemd/system : Crées et modifiées par l'administrateur.

  • Ordre de priorité : /etc/ \rightarrow /run/ \rightarrow /usr/lib/

  • Liste des units :

    • installées : systemctl list-unit-files
    • chargées : systemctl list-units

Units : httpd.service

# systemctl cat httpd.service
[Unit]
Description=Apache Web Server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/httpd/httpd.pid

ExecStart=/usr/bin/apachectl start
ExecStop=/usr/bin/apachectl graceful-stop
ExecReload=/usr/bin/apachectl graceful

PrivateTmp=true
LimitNOFILE=infinity

[Install]
WantedBy=multi-user.target

Units : httpd.service

# systemctl show -p Description httpd.service
[Unit]
Description=Apache Web Server

Units : httpd.service

# systemctl start httpd.service

[Unit]
Description=Apache Web Server

[Service]
Type=forking
PIDFile=/run/httpd/httpd.pid

ExecStart=/usr/bin/apachectl start

Units : httpd.service

# systemctl stop httpd.service

[Unit]
Description=Apache Web Server

[Service]
Type=forking
PIDFile=/run/httpd/httpd.pid

ExecStart=/usr/bin/apachectl start
ExecStop=/usr/bin/apachectl graceful-stop

# systemctl kill --signal=SIGTERM httpd.service

Units : httpd.service

# systemctl reload httpd.service

[Unit]
Description=Apache Web Server

[Service]
Type=forking
PIDFile=/run/httpd/httpd.pid

ExecStart=/usr/bin/apachectl start
ExecStop=/usr/bin/apachectl graceful-stop
ExecReload=/usr/bin/apachectl graceful

Pages de manuel correspondantes

Exemple : systemctl status

Gestion des dépendances

  • Gestion explicite :

    • Dépendance : Requires= / Wants=
      • systemctl show -p Requires nginx
      • systemctl show -p Wants nginx
      • systemctl list-dependencies nginx
      • systemctl list-dependencies --reverse nginx
    • Ordre : After= / Before= :
      • systemctl show -p After nginx
      • systemctl show -p Before nginx
      • systemctl list-dependencies --after nginx
      • systemctl list-dependencies --before nginx
  • Gestion implicite :

    • Activation via une socket TCP ou UNIX
    • Activation via D-Bus

Comment ordonner le lancement d'un service?

Démarrer nginx après mysql et seulement si son lancement a réussi :\ $ cat /etc/systemd/system/nginx.service.d/after-mysql.conf

[Unit]
Requires=mysql.service
After=mysql.service

Units : target

  • Remplaçant des runlevels SysVinit
  • Points de synchronisation
  • Regroupe plusieurs units à l'aide des dépendances
  • Plus flexible (pas de limite en quantité et simultanéité)

Units : httpd.service

[Unit]
Description=Apache Web Server
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
PIDFile=/run/httpd/httpd.pid

ExecStart=/usr/bin/apachectl start
ExecStop=/usr/bin/apachectl graceful-stop
ExecReload=/usr/bin/apachectl graceful

[Install]
WantedBy=multi-user.target

Usage : Démarrage au boot

# systemctl enable httpd.service
ln -s /usr/lib/systemd/system/httpd.service \
    /etc/systemd/system/multi-user.target.wants/
# systemctl disable httpd.service
rm /etc/.../multi-user.target.wants/httpd.service
# systemctl mask httpd.service
ln -s /dev/null /etc/systemd/system/httpd.service

Rrésoudre un problème avec un service ?

  • # systemctl --state failed
  • # systemctl status foo.service
  • # systemctl show foo.service
  • # journalctl -e
  • # journalctl -e -u foo.service
  • # journalctl -e /usr/bin/foo
  • # journalctl -e _PID=123456

Résoudre un problème au démarrage ?

  • Options noyau :
    • systemd.unit=rescue.target
    • systemd.unit=emergency.target
    • systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M
    • systemd.debug-shell (tty9)
    • systemd.confirm_spawn=true
  • # systemctl list-jobs

Problème de dépendance ?

# systemctl list-dependencies
# systemd-analyze dot home.mount | dot -Tsvg > plt.svg
$ firefox plt.svg

Problème de performance ?

# systemd-analyze plot > boot.svg

Problème de performance ?

journald

Commandes usuelles

  • journalctl -e : affiche les logs les plus récents du boot courant
  • journalctl -b -1 : affiche les logs du boot précédent
  • journalctl -b -0 _PID=333 : limite l'affichage aux logs émis par le PID 333 pour ce boot
  • journalctl -k : équivalent de dmesg
  • journalctl -u nginx(.service) : affiches tous les logs liés au service nginx
  • journalctl -f -n 50 : affiche les 50 derniers logs puis affiche les logs au fur et à mesure
  • journalctl /usr/bin/dbus-daemon : tous les logs émis par le binaire /usr/bin/dbus-daemon

Problème lors d'un précédent démarrage ?

Vérifier /etc/systemd/journald.conf :

[Journal]
...
Storage=persistent

# journalctl -b -1

logind, resolved, networkd, timesyncd, etc.

Autres projets rattachés

  • logind : gère les sessions utilisateurs
  • resolved : resolveur DNS
  • networkd : gestionnaire de la configuration réseau
  • timesyncd : client NTP (client uniquement)
  • etc.

Sécurité

Fonctionnalité de sécurité

Support de « toutes » les options proposées par le noyau :

  • UID, GID
  • limites & Co
  • cgroups v1 & v2
  • namespaces
  • capabilities
  • seccomp-bpf
  • etc.

Exemples : Durcissement système à l'aide de systemd (SSTIC 2017)

Sécurité de systemd ?

  • Quelques vulnérabilités majeures : CVE-2018-15686, CVE-2018-15688, CVE-2016-7795, CVE-2016-10156, CVE-2013-4392, CVE-2013-4327, CVE-2012-1174, CVE-2012-0871
  • Bugs médiatiques : CVE-2017-1000082, CVE-2017-9445, CVE-2017-15908
  • Ecrit en C mais la majeure parties des bugs sont logiques (non liées au langage)
  • Surface d'attaque assez limitée
  • Démons systèmes correctement confinés (voir vulnérabilités resolved)

Suite

SELinux

--- # Démons principaux **Système** > `systemd` (PID 1), `udevd`, `journald`, `logind` **Utilisateur, lancé à la demande** > `systemd --user` **Système, lancés à la demande** > `localed`, `hostnamed`, `timedated` **Système, optionnels, lancés à la demande** > `timesyncd`, `machined`, `networkd`, `resolved`, `socket-proxyd`

# Units : multi-users.target ``` [Unit] Description=Multi-User System Documentation=man:systemd.special(7) Requires=basic.target Conflicts=rescue.service rescue.target After=basic.target rescue.service rescue.target AllowIsolate=yes ``` ---

# Démarrage du système - Démarrage de `default.target` - Boot $\Leftrightarrow$ `systemctl start default.target` - Résolution des dépendances - Démarrage des units - Apparition des devices --- # Démarrage du système ![](img/boot.png) ---

# Usage : Démarrage lorsque le réseau est OK Exemple sous Debian : - Target : `network-online.target}; - Pas de dépendance par défaut; - Choisir ce qui permet d'atteindre l'état « réseau OK »; \pause{ - Les interfaces définies dans le fichier `/etc/network/interfaces} sont configurées : - `\$ ln -s /lib/systemd/system/networking.service /etc/systemd/system/network-online.target.requires/ \pause{ - Service devant attendre que le réseau soit OK\@ : - `\$ cat /etc/systemd/system/foo.service.d/bar.conf ``` [Unit] Requires=network-online.target After=network-online.target ``` --- \begin{frame}[fragile]{Interaction \(\mathbf{udevd}\) / \(\mathbf{systemd}\) - Entrée dans `/etc/fstab} : ``` /dev/sda3 /home ext4 rw,nodev,nosuid 0 2 ``` - Exemple : \begin{enumerate \def\labelenumi{\arabic{enumi}. \setcounter{enumi}{-1 - `systemd-fstab-generator} \(\Rightarrow\) `home.mount - Attends la découverte du périphérique de type block : `dev-sda3.device}; - Vérification du système de fichier : `systemd-fsck@dev-sda.service}; - Monte le système de fichier. \end{enumerate ---

# Débugger \(\mathbf{systemd}\)? Documentation : {\footnotesize - \url{https://freedesktop.org/wiki/Software/systemd/Debugging/ - \url{https://fedoraproject.org/wiki/How\_to\_debug\_Systemd\_problems - \url{https://wiki.archlinux.org/index.php/Systemd\#Troubleshooting - \url{https://wiki.debian.org/systemd\#Debugging --- # Design et fonctionnalités : Standardisation - Standardisation : chaque distribution avait ses propres scripts d'init et ses propres fichiers de configurations. - Tout est maintenant commun : - `/etc/hostname} $\Rightarrow$ `hostnamectl}; - `/etc/locale.conf}, `/etc/vconsole.conf $\Rightarrow$ `localectl}; - `/etc/localtime} $\Rightarrow$ `timedatectl}. - Mais pas encore supporté par toutes les distributions (attention notamment sur Debian \& Ubuntu). --- # `/run} - systemd a introduit le dossier `/run}; - Utilise le système de fichier `tmpfs} pour stocker les données temporairement; - Disponible très tôt au démarrage; - Utilisable pour stocker les informations non permanentes liées aux services; - Voir **file-hierarchy(7)}.%chktex 36 --- # tmpfiles.d - `/\{etc,usr/lib\}/tmpfiles.d/*.conf - Liste de dossiers ou fichiers à créer automatiquement au démarrage; - Exemple : `\$ cat /usr/lib/tmpfiles.d/tuned.conf ``` d /run/tuned 0755 root root - ``` - Voir **tmpfiles.d(5)}.%chktex 36 --- \begin{frame}[fragile]{sysusers.d - `/\{etc,usr/lib\}/sysusers.d/*.conf - Liste d'utilisateur système à créer automatiquement au démarrage si ils n'existent pas déjà; - Exemple : `\$ cat /usr/lib/sysuers.d/mariadb.conf ``` u mysql - "MariaDB" /var/lib/mysql ``` - Voir **sysusers.d(5)}.%chktex 36 ---

# Design - Similaire à syslog(-ng)/rsyslog : Récupère les messages envoyés par les processus sur la socket `/dev/log` et les stocke sur le disque - Démon lancé très tôt au boot et fortement intégré avec systemd - Cette intégration permets d'obtenir beaucoup plus d'informations que ce qui normalement possible avec (r)syslog(-ng) - Utilise un format de stockage personnalisé et compressé: [Journal File Format](https://www.freedesktop.org/wiki/Software/systemd/journal-files/) ---