Écrit par moi en anglais, traduit à 95% par ChatGPT.
Tout le monde sait que permettre à différentes applications d'accéder librement aux données des autres n'est pas exactement optimal d'un point de vue sécurité. Alors que les serveurs bénéficient de conteneurs pour isoler les applications entre elles, nous manquons d'une bonne solution pour le bureau. Ou pas ?
Il y a, évidemment, flatpak. Malheureusement, flatpak se présente comme un "cadre de distribution et de sandboxing d'applications Linux". Ça ne va pas le faire. J'ai déjà une distribution. J'en suis très content. Je veux exécuter les applications de ma distribution de manière isolée.
Heureusement, la partie sandboxing de flatpak est en fait un projet séparé, moins connu : bubblewrap. Essayons de l'utiliser pour sécuriser notre bureau.
Commençons par l'une des choses les plus simples à sandboxer, un shell :
$ bwrap zsh
bwrap: execvp zsh: Aucun fichier ou dossier de ce type
Euh… quoi ?
Revenons à ce que fait bubblewrap : il crée en fait un nouveau espace de noms de système de fichiers, vide. Le mot-clé ici est "vide". Il n'y a pas d'exécutable zsh dedans. Corrigeons cela :
$ bwrap --ro-bind /usr /usr /usr/bin/zsh
bwrap: execvp /usr/bin/zsh: Aucun fichier ou dossier de ce type
Bizarre. Mais la commande suivante vous dira ce qui a échoué :
$ ldd /usr/bin/zsh
linux-vdso.so.1 (0x00007fff5d189000)
libcap.so.2 => /usr/lib/libcap.so.2 (0x00007ff55abe2000)
libncursesw.so.6 => /usr/lib/libncursesw.so.6 (0x00007ff55ab6b000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007ff55aa7e000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007ff55a89c000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007ff55ad24000)
Les bibliothèques partagées. Donc, nous avons besoin de /lib64
également. Pour être sûrs, incluons aussi /bin
, /lib
et /sbin
, bien qu'ils ne soient que des liens symboliques sur mon système et ne devraient pas être nécessaires. Ajoutons également /etc
pour des choses comme /etc/profile.d
ou /etc/localtime
:
$ bwrap --ro-bind /usr /usr --ro-bind /bin /bin --ro-bind /lib /lib --ro-bind /lib64 /lib64 --ro-bind /sbin /sbin --ro-bind /etc /etc /usr/bin/zsh
/usr/share/zsh/scripts/newuser:5: aucun fichier ou dossier de ce type : /dev/null
zsh-newuser-install:23: aucun fichier ou dossier de ce type : /dev/null
zsh-newuser-install:24: aucun fichier ou dossier de ce type : /dev/null
$
Oui, /dev/null
est plutôt important. De nombreuses applications en auront besoin. Nous pourrions le lier (en utilisant --dev-bind
), mais il y a aussi /dev/zero
, /dev/urandom
, et probablement d'autres. Nous pourrions lier /dev
, mais cela signifierait que les applications sandboxées auraient accès aux périphériques — cela ne semble pas être une bonne idée. Heureusement, bubblewrap a pensé à tout et nous a fourni une option --dev
(et une option --proc
pour des problèmes similaires). Nous avons aussi --tmpfs
pour /tmp
. Utilisons-les :
$ bwrap --ro-bind /usr /usr --ro-bind /bin /bin --ro-bind /lib /lib --ro-bind /lib64 /lib64 --ro-bind /sbin /sbin --ro-bind /etc /etc --proc /proc --dev /dev --tmpfs /tmp /usr/bin/zsh
$ ls /
bin dev etc lib lib64 proc sbin tmp usr
Remarquez l'absence de /home
: nous ne l'avons pas lié, donc il n'est pas accessible. Tout programme compromis qui est exécuté dans cette session shell sera incapable d'accéder à nos données personnelles (en l'absence de toute exploitation d'escalade de privilèges donnant un accès root).
Bien ! Nous sommes dans un sandbox ! Nous sommes en sécurité !
Vraiment ?
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 21592 12736 ? Ss 10:37 0:01 /sbin/init verbose
root 2 0.0 0.0 0 0 ? S 10:37 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S 10:37 0:00 [pool_workqueue_release]
root 4 0.0 0.0 0 0 ? I< 10:37 0:00 [kworker/R-rcu_g]
root 5 0.0 0.0 0 0 ? I< 10:37 0:00 [kworker/R-rcu_p]
root 6 0.0 0.0 0 0 ? I< 10:37 0:00 [kworker/R-slub_]
root 7 0.0 0.0 0 0 ? I< 10:37 0:00 [kworker/R-netns]
root 12 0.0 0.0 0 0 ? I< 10:37 0:00 [kworker/R-mm_pe]
...
systemd+ 426 0.0 0.0 91220 8468 ? Ssl 10:37 0:00 /usr/lib/systemd/systemd-timesyncd
avahi 438 0.0 0.0 8932 4776 ? Ss 10:37 0:00 avahi-daemon: running [desk.local]
dbus 439 0.0 0.0 9752 4976 ? Ss 10:37 0:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root 441 0.0 0.0 11016 7284 ? Ss 10:37 0:00 sshd: /usr/bin/sshd -D [listener] 0 of 10-100 startups
...
sloonz 1427 0.0 0.4 513896 70208 ? Sl 10:38 0:13 /usr/lib/firefox/firefox -contentproc -parentBuildID 20231130105227 -prefsLen 44628 -prefMapSize 241694 -appDir /usr/lib/firefox/browser {5508672c-0163-4fa1-adeb-7f40773b136b} 3 true rdd
...
Oups…
$ env
...
SHELL=/bin/zsh
WORDCHARS=*?_-.[]~=&;!#$%^(){}<>
HISTSIZE=50000
I3SOCK=/run/user/1000/sway-ipc.1000.548.sock
SSH_AUTH_SOCK=/run/user/1000/ssh-agent.socket
CREDENTIALS_DIRECTORY=/run/credentials/getty@tty1.service
MEMORY_PRESSURE_WRITE=c29tZSAyMDAwMDAgMjAwMDAwMAA=
XCURSOR_SIZE=24
...
AWS_SECRET_ACCESS_KEY=[redacted]
Oh non. Renforçons le sandboxing.
$ bwrap --help
...
--unshare-all Unshare every namespace we support by default
--share-net Retain the network namespace (can only combine with --unshare-all)
--unshare-user Create new user namespace (may be automatically implied if not setuid)
--unshare-user-try Create new user namespace if possible else continue by skipping it
--unshare-ipc Create new ipc namespace
--unshare-pid Create new pid namespace
--unshare-net Create new network namespace
--unshare-uts Create new uts namespace
--unshare-cgroup Create new cgroup namespace
--unshare-cgroup-try Create new cgroup namespace if possible else continue by skipping it
...
--clearenv Unset all environment variables
...
Que voulons-nous dissocier ("unshare") ici ?
Dissocier l'espace de noms réseau est une très mauvaise idée, à moins que vous ne vouliez empêcher une application d'accéder à tout réseau (y compris localhost).
Dissocier l'espace de noms des PID (processus) semble être une évidence, tout comme vider l'environnement.
L'espace de noms IPC est probablement, la plupart du temps, sans problème à dissocier (les éléments importants comme les fifo, les pipe et les sockets unix sont dans l'espace de noms du système de fichiers, à l'exception des sockets unix abstraits qui sont dans l'espace de noms réseau), mais il est aussi difficile de voir l'intérêt (le processus compromis devrait trouver un programme exploitable fonctionnant dans l'environnement non sandboxé dont le vecteur d'attaque serait les files d'attente de messages POSIX ou l'IPC SYSV, qui en pratique sont très rarement utilisés par les applications de bureau). Nous verrons plus tard que sandboxer des applications graphiques peut entraîner des complications, et dissocier l'espace de noms IPC pourrait ajouter des bugs vraiment difficiles à traquer en plus de ceux-là. Nous aurons déjà assez à faire lorsque nous essaierons de sandboxer des applications de bureau, donc ne dissociions pas cela.
Je ne vois pas l'intérêt de dissocier l'espace de noms UTS (il s'agit de vider le nom d'hôte), de même pour cgroup (à moins éventuellement que vous ne vouliez appliquer des limites au nouveau cgroup créé plus tard, mais je n'ai jamais essayé). Je ne vois pas non plus de gros problème à les dissocier. Tirez à pile ou face pour décider.
Toute cette histoire de partager ou non l'espace de noms utilisateur est une (petite mais ennuyeuse) boîte de Pandore que je ne tenterai pas de couvrir extensivement ici (probablemet jamais). Pour faire court : cela dépend de la manière dont votre distribution a installé bubblewrap (suid ou non) et aura des effets minimaux (le plus grand étant que dissocier signifie que les fichiers appartenant à root appartiendront à personne dans le sandbox). Contentons-nous du comportement par défaut sur votre système (quel qu'il soit).
Ajoutons donc --clearenv
et --unshare-ipc
à nos arguments de base pour bubblewrap. Si vous êtes particulièrement paranoïaque, vous pouvez ajouter --unshare-uts
, --unshare-user
et --unshare-ipc
:
$ bwrap --ro-bind /usr /usr --ro-bind /bin /bin --ro-bind /lib /lib --ro-bind /lib64 /lib64 --ro-bind /sbin /sbin --ro-bind /etc /etc --proc /proc --dev /dev --tmpfs /tmp --clearenv --unshare-pid /usr/bin/zsh
$ ls /
bin dev etc lib lib64 proc sbin tmp usr
$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
sloonz 1 0.0 0.0 2720 1152 ? S 15:39 0:00 bwrap --ro-bind /usr /usr --ro-bind /bin /bin --ro-bind /lib /lib --ro-bind /lib64 /lib64 --ro-bind /sbin /sbin --ro-bind /etc /etc --proc /proc --dev /dev --tmpfs /tmp --clearenv --unshare-pid /usr/bin/zsh
sloonz 3 0.0 0.0 6084 4436 ? S 15:39 0:00 /usr/bin/zsh
sloonz 6 100 0.0 8024 3988 ? R+ 15:39 0:00 ps aux
$ killall firefox
firefox: no process found
$ env
PWD=/
HOME=/home/sloonz
LOGNAME=sloonz
SHLVL=1
OLDPWD=/
_=/bin/env
Cela semble bon pour une application sans état (par exemple, si vous voulez sandboxer curl https://ipinfo.io
pour obtenir votre IP). Que faire si vous voulez conserver des fichiers entre les sessions ? Eh bien, utilisons un répertoire temporaire pour le home :
$ mkdir ~/sandboxes/my-node-project
$ bwrap --ro-bind /usr /usr --ro-bind /bin /bin --ro-bind /lib /lib --ro-bind /lib64 /lib64 --ro-bind /sbin /sbin --ro-bind /etc /etc --proc /proc --dev /dev --tmpfs /tmp --clearenv --unshare-pid --bind ~/sandboxes/my-node-project ~ --chdir ~ /usr/bin/zsh
$ npm install whatever
De cette façon, node_modules
sera installé dans ~
(dans votre sandbox) ou ~/sandboxes/my-node-project
(dans l'environnement non-sandboxé). Si vous installez par hasard une bibliothèque node compromise, cela ne compromettra pas votre répertoire personnel.
Vous voudrez peut-être lier certains fichiers de configuration courants, comme ~/.zshrc
(à moins que vous n'ayez une variable d'environnement AWS_SECRET_ACCESS_KEY
dedans) ou ~/.config/nvim
. Souvenez-vous de les lier en lecture seule (--ro-bind
au lieu de --bind
) ; sinon, un processus compromis pourrait y écrire une charge malveillante pour obtenir un accès la prochaine fois que ces fichiers sont lus (et exécutés) dans votre environnement non-sandboxé.
Dans la prochaine partie, nous verrons les bases de l'exécution d'applications graphiques sandboxées comme un IDE ou votre navigateur.
P.S.: à la fois l'article initial en anglais et la traduction quasi-automatiques en français est une expérience nouvelle pour moi (je n’ai jamais réellement écrit d’article, ou tenu de blog). Lancez des tomates pour que ça s'arrête, des fleurs pour que ça continue. La partie 2 est déjà bien avancée et sera probablement publiée quelle que soit la réaction, la partie 3 n’est que partiellement dans ma tête et peut être expulsée à tout instant.
# bubblewrap
Posté par Xanatos . Évalué à 4.
Merci pour la série d'articles à venir, c'est un sujet que j'avais commencé à rtfm mais sans plus.
Ayant fait un profil bubblerwrap pour Firefox sur une machine j'avais trouvé ça bien plus complexe que Firejail (qui propose des preset).
[^] # Re: bubblewrap
Posté par Moonz . Évalué à 5.
Oui, parmi les solutions de sandbox évoquées dans les commentaires, firejail est celle qui se rapproche le plus de bubblewrap.
Les grosses différences :
--bind ~/.config/mozilla ~/.mozilla
par exemple)Toutes ces raisons font que personnellement je préfère bubblewrap. Mais les deux sont conceptuellement très proches.
[^] # Re: bubblewrap
Posté par gUI (Mastodon) . Évalué à 4.
Bin justement, en lisant ton journal j'ai été étonné de voir que quand même pas mal de chose sont partagées par défaut (le passage : Bien ! Nous sommes dans un sandbox ! Nous sommes en sécurité ! Vraiment ?) donc c'est un peu ce qui m'a dérouté, dans le sens où j'ai du mal à voir pour quoi ça a été conçu à la base.
On dirait que le comportement par défaut c'est un
chroot
, mais que via des options on peut se rapprocher du comportement des conteneurs.En théorie, la théorie et la pratique c'est pareil. En pratique c'est pas vrai.
[^] # Re: bubblewrap
Posté par barmic 🦦 . Évalué à 6.
Tout est dans cette phrase :
Il ne sandbox que le système de fichier. Ce qui le rapproche effectivement d'un chroot. C'est plus pratique parce que tu n'utilise pas un dossier existant (à créer au préalable, à bind les dossiers dont tu as besoin, puis à nettoyer ensuite) et tu n'a pas besoin d'être root.
Après c'est du namespace linux c'est exactement ce que font les conteneurs (docker, systemd-nspawn, lxc, flatpack,…).
https://linuxfr.org/users/barmic/journaux/y-en-a-marre-de-ce-gros-troll
[^] # Re: bubblewrap
Posté par Lucky Seven . Évalué à 2.
Attention à partager tout le
/etc
donc … Il y a peut-être des mots de passe wifi, ou le /etc/shadow, ou autre données sensible dans les confs.Ceci est peut-être un bon début :
BubbleWrap aussi supporte seccomp. Je pense que bubblewrap a beaucoup de fonctionnalités aussi, mais il faut mettre les mains dedans…
D'ailleurs, je conseillerais d'utiliser
--new-session
et--cap-drop ALL
aussi[^] # Re: bubblewrap
Posté par Moonz . Évalué à 3.
J’avoue que pour le coup c’est un gros coup de flemme, et que c’est une bonne idée d’être plus sélectif /etc. Ceci dit si pour /etc/shadow si tu n’as pas le droit de le lire hors de la sandbox (et normalement tu n’as pas le droit) tu n’as pas non plus le droit de le lire dans la sandbox.
Très bonne remarque, j’étais passé à côté de celui ci
À moins que j’aie loupé un truc, un utilisateur non-privilégié ne devrait pas avoir de cap activée à la base, non ?
[^] # Re: bubblewrap
Posté par Lucky Seven . Évalué à 1. Dernière modification le 02 janvier 2024 à 00:31.
Oui effectivement, mais c'est tout de même plus sûr de ne pas le partager, sur un droit mal mis ou un soucis de config. On sait jamais…
Oui tu as raison, je l'ajoute un peu automatiquement, mais ça ne concerne que les utilisateurs non-privilégiés.
# conteneur? vm?
Posté par devnewton 🍺 (site web personnel) . Évalué à 5.
Quels sont les avantages de bubblewrap par rapport à un moteur de conteneurs (comme podman par exemple)?
Pour isoler un programme de "pas confiance", est-ce qu'il ne vaut pas mieux une machine virtuelle ?
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: conteneur? vm?
Posté par Moonz . Évalué à 3.
Bubblewrap est plus bas niveau, il ne gère que l’aspect sandboxing, pas l’aspect gestion d’images. Tu peux probablement réécrire une grosse partie de podman en tant que surcouche à bubblewrap. Il est aussi plus limité dans ses ambitions, en partie parce qu’il est prévu pour tourner en suid (donc utilisable par un simple utilisateur, pas besoin d’être root pour créer une sandbox).
Ce qui est un avantage, si, comme moi, tu ne veux pas gérer des images, mais réutiliser le système géré par ta distribution.
Ça dépend de "pas confiance" et "vaut mieux".
Une machine virtuelle est clairement plus sécurisée, oui, et si le but est d’étudier un malware, ça me semble une meilleure idée.
Mais une application qui tourne sur une VM pourra difficilement s’intégrer dans ton environnement graphique en partageant le socket Wayland et en communiquant sur ton bus de session D-Bus. Et tu retombes sur la problématique que je veux éviter, "gestion d’images".
[^] # Re: conteneur? vm?
Posté par ptit_poulet . Évalué à 1.
SystemD tout simplement ?
[^] # Re: conteneur? vm?
Posté par Moonz . Évalué à 2.
Je ne suis pas sur de suivre ? systemd-nspawn nécessite également les droits root, et ne peut pas à ma connaissance faire l’équivalent de
--bind ~/sandboxes/app ~
.[^] # Re: conteneur? vm?
Posté par ptit_poulet . Évalué à 1.
Je pensais à portablectl :
[^] # Re: conteneur? vm?
Posté par Moonz . Évalué à 2.
Je ne connaissais pas du tout. Ceci dit, gestionnaire d'images, c'est à la base ce que je souhaitais éviter.
[^] # Re: conteneur? vm?
Posté par ptit_poulet . Évalué à 1.
Oui et non car au final tu installes ton appli et ça ajoute les dépendances nécessaires.
Après si tu veux éviter d'utiliser trop d'espace, tu peux toujours installer une base que tu réutilises à coup d'overlayfs.
Y a pas grand chose à gérer au final ;)
[^] # Re: conteneur? vm?
Posté par devnewton 🍺 (site web personnel) . Évalué à 7.
Podman aussi n'a pas besoin d'être root :-)
Par contre, effectivement il doit toujours lui falloir une image…
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: conteneur? vm?
Posté par cg . Évalué à 2.
Subuser est intéressant aussi.
(super journal, par ailleurs !)
[^] # Re: conteneur? vm?
Posté par devnewton 🍺 (site web personnel) . Évalué à 4.
Arf subuser propose une installation via pip et utilise docker sans parler de rootless/daemonless.
Installer une porte blindée en cassant la fenêtre 😜.
Le post ci-dessus est une grosse connerie, ne le lisez pas sérieusement.
[^] # Re: conteneur? vm?
Posté par Moonz . Évalué à 3. Dernière modification le 26 décembre 2023 à 18:20.
Je ne connaissais pas, merci. Il y a des choses intéressantes dedans, comme la possibilité d'interdire l'accès au clipboard, qu’il faudrait que je regarde comment c’est implémenté.
Ceci dit dans le principe d’être fondé sur docker je suis très dubitatif, je vois mal comment autoriser un utilisateur à accéder au démon docker sans que ce soit une faile de sécurité en soi (si l’utilisateur peut lancer des commandes docker, il peut lancer, schématiquement,
docker -v /:/ -u root bash
)[^] # Re: conteneur? vm?
Posté par Marc Quinton . Évalué à 1.
il ne s'agit pas de se prémunir dans le cas de subuser d'une attaque locale au système ; l'utilisateur est réputé de confiance ; il s'agit plutot de faire du sandboxing sur un environnement mal maitrisé avec peu de confiance ; par exemple Firefox et de nombreux plugins.
# La suite !
Posté par patrick_g (site web personnel) . Évalué à 10.
Super article. Je lance des fleurs pour avoir la suite !
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.