Les sandbox Linux et Fil-C
(fil-c.org)- La sécurité mémoire et le sandboxing sont deux concepts de sécurité indépendants, et il faut disposer des deux pour mettre en place une défense robuste
- Fil-C est une implémentation à sécurité mémoire de C/C++, qui garantit cette sécurité jusqu’au niveau des appels système Linux et peut être utilisée même dans des composants système comme OpenSSH
- Lors du portage du sandbox basé sur seccomp-BPF d’OpenSSH vers Fil-C, les principaux défis ont porté sur les limites de création de threads et l’ajustement du filtre seccomp
- Pour la gestion des threads d’arrière-plan du runtime Fil-C, l’API
zlock_runtime_threads()a été ajoutée afin de contrôler le comportement des threads à l’intérieur du sandbox - Fil-C applique de façon synchronisée les appels
prctlà tous les threads du runtime, afin que no_new_privs et le filtre seccomp soient appliqués de manière cohérente à l’ensemble du processus
Relation entre sécurité mémoire et sandboxing
- La sécurité mémoire et le sandboxing sont deux couches de sécurité distinctes, et l’une seule ne fournit pas une protection complète
- Exemple de programme sûr en mémoire mais non sandboxé : un programme Java qui peut écraser un fichier via une entrée utilisateur
- Exemple de programme sandboxé mais non sûr en mémoire : un programme écrit en assembleur avec des privilèges limités
- En pratique, un sandbox présente des failles structurelles, comme l’autorisation de communication avec un processus broker
- Il est donc préférable de combiner sécurité mémoire et sandboxing
Combinaison de Fil-C et du sandbox OpenSSH
- Fil-C est une implémentation à sécurité mémoire de C/C++, qui conserve cette sécurité au niveau des appels système Linux
- Le runtime Fil-C peut fonctionner même dans des composants système de bas niveau comme
initouudevd - OpenSSH fonctionne normalement avec Fil-C et utilise un sandbox seccomp-BPF
- Le runtime Fil-C peut fonctionner même dans des composants système de bas niveau comme
- Sous Linux, OpenSSH construit son sandbox avec les outils suivants
chrootpour restreindre l’accès au système de fichiers- Exécution sous l’utilisateur/groupe
sshd setrlimitpour limiter l’ouverture de fichiers et la création de processus- Filtre seccomp-BPF pour n’autoriser que les appels système permis
- Fil-C prend en charge
chrootet le changement d’utilisateur par défaut, maissetrlimitet seccomp-BPF peuvent entrer en conflit avec le fonctionnement du runtime, ce qui demande des ajustements supplémentaires
Contrôle des threads dans le runtime Fil-C
- Le runtime Fil-C utilise des threads d’arrière-plan pour le garbage collection, qu’il suspend et relance automatiquement si nécessaire
- Le sandbox
setrlimitd’OpenSSH vise à interdire la création de nouveaux processus, et la création de threads par le runtime peut donc enfreindre cette règle - Pour résoudre ce problème, l’API
zlock_runtime_threads()a été ajoutée à<stdfil.h>- Le runtime crée immédiatement les threads dont il a besoin, puis désactive leur arrêt automatique par la suite
- L’appel est effectué dans la fonction
ssh_sandbox_childd’OpenSSH avantsetrlimitou seccomp-BPF
Ajustement du filtre seccomp d’OpenSSH
- Après l’application de
zlock_runtime_threads(), la plupart des fonctions du sandbox continuent de fonctionner telles quelles - Les changements suivants ont été apportés au filtre seccomp
- En cas de violation, réglage sur
SECCOMP_RET_KILL_PROCESSafin de terminer aussi les threads d’arrière-plan de Fil-C - Ajout de
MAP_NORESERVEà la liste des autorisations, pour permettre l’utilisation de l’allocateur mémoire de Fil-C - Autorisation de l’appel
sched_yield, utilisé dans l’implémentation des verrous de Fil-C
- En cas de violation, réglage sur
- Les appels
futexutilisés par Fil-C pour la synchronisation étaient déjà autorisés, donc aucun changement supplémentaire n’était nécessaire
Mise en œuvre de prctl dans Fil-C
- OpenSSH utilise deux appels
prctllors de l’installation du filtre seccompPR_SET_NO_NEW_PRIVSpour empêcher l’acquisition de privilèges supplémentairesPR_SET_SECCOMP, SECCOMP_MODE_FILTERpour activer le filtre
- Le problème est que
prctlne s’applique qu’au thread appelant, ce qui laisse le risque que d’autres threads du runtime Fil-C restent sans filtre - Pour éviter cela, Fil-C utilise l’API
filc_runtime_threads_handshake()afin d’appliquer la configuration de manière synchronisée à tous les threads du runtime- Elle garantit que chaque thread exécute le même appel
prctl - En présence de plusieurs threads utilisateur, elle déclenche une erreur de sûreté Fil-C pour renforcer la protection
- Elle garantit que chaque thread exécute le même appel
Conclusion
- La combinaison de la sécurité mémoire et du sandboxing constitue l’approche de sécurité la plus solide
- Fil-C intègre complètement le sandbox basé sur seccomp d’OpenSSH tout en préservant la sécurité mémoire sans réduire le niveau de protection
- Dans un environnement Linux, Fil-C permet d’obtenir à la fois une sécurité au niveau système et une sûreté au niveau du langage
1 commentaires
Commentaires sur Hacker News
Je me demande pourquoi il n’y a aucune mention de landlock
Il existe une approche de compilation hybride C → WASM → C
Cela permet de contrôler entièrement les interactions avec l’OS, tout en sandboxant les accès mémoire comme avec WASM, tout en restant techniquement du code C
Voir RLBox pour plus d’informations
Elles peuvent corrompre la mémoire, mais l’étendue des dégâts reste confinée à l’intérieur de la sandbox
Des systèmes comme SECCOMP sont bureaucratiques, car il faut définir très finement toutes les politiques d’interaction
Fil-C, au contraire, adopte une approche où le langage et le runtime eux-mêmes cherchent à garantir le bon fonctionnement du programme
Les binaires Fil-C sont des exécutables ordinaires, donc ils peuvent aussi être utilisés avec des sandboxs comme SECCOMP
Linux a mis 20 ans à créer l’interface
prctl, donc pour voir quelque chose de similaire dans WASI, il faudra sans doute attendre 10 ansOn peut toujours produire des flux d’exécution étranges à l’intérieur de la sandbox
L’auteur de Fil-C est doué pour les inventions techniquement intéressantes, mais je m’inquiète du niveau réel de validation de l’implémentation
Il a dit qu’on pouvait compiler des programmes
setuidavec Fil-C, mais la partie modifiée deld.sopeut être risquéeLes applications
setuiddoivent être écrites de façon extrêmement défensive vis-à-vis des variables d’environnement, des descripteurs de fichiers, derlimit, des signaux, etc.Ces aspects semblent encore inachevés, donc il y a un risque à l’utiliser dans une vraie infrastructure
Cela dit, tester une base de code avec Fil-C pourrait permettre de découvrir des bugs intéressants
La modification de
ld.soest mineure et sert essentiellement à lui apprendre la disposition delibcLe bug
getenvlié àsetuida déjà été corrigé avecsecure_getenvDans ces critiques, il y a une part de vérité et une part de FUD
Avec Fil-C, en situation de data race, les pointeurs et les capabilities peuvent devenir incohérents
Cela peut provoquer une violation de la sûreté mémoire
L’auteur le nie, mais la comparaison avec Java n’est pas appropriée
La technologie est excellente, mais l’attitude de l’auteur nuit à la confiance
WASM est à la fois une sandbox et un environnement d’exécution, et selon la façon dont on l’utilise, on peut obtenir un certain niveau de sûreté mémoire
Si l’on compile du C en WASM, les bugs existent toujours, mais leur portée est limitée
Il est donc juste de classer WASM comme une technologie de sandboxing, mais en tant qu’environnement d’exécution il offre davantage de possibilités
Un bug dans le module B peut permettre de lire les données du module A
En d’autres termes, WASM n’est qu’un remplaçant léger des sandboxs de processus
On pourrait dire la même chose de C : « c’est sûr selon la façon dont on l’utilise »
WASM empêche de s’échapper du runtime, mais n’empêche pas de s’échapper de la mémoire du programme interne
Demande de comparaison entre Fil-C et Rust
Fil-C convient pour renforcer des programmes C existants en mettant l’accent sur la compatibilité et la sécurité
Rust est mieux adapté aux nouvelles bases de code pour obtenir sûreté statique et performances
Fil-C implique une légère perte de performances, mais il est utile pour du code C existant (
ffmpeg,nginx,sudo, etc.)Rust se distingue par le multithreading et son système de types
Son objectif n’est pas d’améliorer la conception du langage, mais d’apporter la sûreté mémoire
Ses concurrents sont plus proches de D, Nim ou Go que de Rust
Rust les prévient à la compilation
Les deux approches sont orthogonales, et on pourrait ajouter à Rust des vérifications à l’exécution dans le style de Fil-C
Les MicroVM gagnent progressivement en popularité
Je me demande comment Fil-C pourrait en tirer parti
J’espère que ce projet recevra davantage d’attention
Ce serait bien que des outils critiques comme sudo ou polkit soient distribués avec sûreté mémoire
J’aimerais qu’on utilise davantage le sandboxing, même avec des langages sûrs en mémoire
C’est dommage que Rust ou Go utilisent si peu les sandboxs au niveau OS
Il est difficile à configurer au niveau d’une bibliothèque, et il est sensible à la version du noyau ou à l’implémentation de
libcIl ne peut pas filtrer les entrées derrière des pointeurs comme les chemins de fichiers, ce qui montre ses limites
C’est pourquoi il faut généralement le configurer directement au niveau de l’application
En revanche, le runtime de Go est plus lourd, donc il est plus difficile à sécuriser comme Fil-C
Je me demande en quoi Fil-C diffère de l’Address Sanitizer (ASan) de clang
Si cela se limite à produire une panic à l’exécution, peut-on vraiment appeler cela de la « sûreté mémoire » ?
Certains bugs lui échappent
Son approche consiste à placer des « red zones » autour de la mémoire, donc la détection dépend parfois de la chance
La sûreté mémoire ne signifie pas « ne jamais planter », mais « empêcher qu’un accès invalide produise un effet »
Question sur les raisons pour lesquelles on n’utiliserait pas une VM complète comme sandbox
Un processus analyse les entrées sans privilèges, tandis qu’un autre fonctionne avec des privilèges élevés
Les deux communiquent via IPC
Utiliser une VM augmente la sécurité, mais ajoute beaucoup d’overhead, et complique des fonctions comme l’accès au GPU ou aux fichiers
C’est pourquoi, en général, le sandboxing au niveau OS est plus propre
Il faut attribuer le GPU de manière dédiée, et même Qubes ne se connecte que via du forwarding X11, donc sans accélération