Capsicum, une séparation fine des privilèges pour UNIX

, par  bluestorm , popularité : 2%

Le projet Capsicum, lancé l’année dernière, tente d’adapter le modèle de sécurité par capacités («  capabilities  ») aux systèmes UNIX. En deux mots, il s’agit de permettre aux applications de faire tourner certaines parties de leur code dans des « sandboxes » (bacs à sable) aux droits très restreints, gérés finement, avec la possibilité de recevoir ou de déléguer dynamiquement une partie de ces droits.

C’est une approche de la sécurité qui mise sur la flexibilité et l’intégration directe dans les applications (au contraire de politiques externes décidées par l’administrateur système, comme avec SELinux) pour respecter le Principle of Least Authority, qui recommande qu’un bout de programme donné fonctionne avec seulement les droits dont il a besoin pour accomplir sa tâche. Ainsi, les conséquences d’une faille sont réduites et les vecteurs d’attaque diminuent énormément. Par exemple, je ne veux pas que le logiciel qui lit mes fichiers PDF ait le droit de lire le contenu de mon répertoire personnel et d’envoyer des e-mails.

Capsicum introduit de nouveaux appels et objets système, qui demandent une (relativement petite) modification du noyau, ainsi qu’une bibliothèque logicielle en espace utilisateur pour utiliser ces nouveaux appels système. FreeBSD a déjà fait les modifications nécessaires, et les chercheurs ont pu facilement convertir plusieurs applications au modèle Capsicum : tcpdump, dhclient, gzip et, avec l’aide d’un développeur Google, le navigateur Web chromium.

Capsicum peut ainsi renforcer considérablement la sécurité des applications UNIX classiques, sans demander de les recoder entièrement. Reste à voir si les développeurs du monde du Libre seront convaincus par ces approches compartimentées, et prêts à les prendre en compte lors de la conception de leurs logiciels.

Sommaire

La sécurité par capacités

La sécurité par capacités n’est pas une idée nouvelle : elle a été introduite en 1966 par Dennis et Van Horn, dans un article concernant les systèmes multi-utilisateur. Une capacité est une référence non-forgeable qui, simultanément, désigne un objet du système (fichier, périphérique…) et décrit une action autorisée sur cet objet (renommer le fichier, écrire sur le périphérique, etc.). La seule façon d’effectuer une action est de posséder et d’activer une capacité associée.

Dans un système UNIX classique (UNIX n’existait pas en 66, c’était la naissance de son ancêtre MULTICS), ce sont les objets du système qui «  connaissent  » les droits qui les concernent. Par exemple, les permissions d’un fichier indiquent quels utilisateurs peuvent y accéder et de quelle façon. Les capacités renversent la perspective : ce sont les agents du systèmes qui ont à leur disposition une liste d’actions autorisées.

Cela permet une gestion plus dynamique et plus fine des droits, car la notion d’«  agent  » peut être très fine : quand un programme lance un sous-programme, ou quand un utilisateur lance un programme, il peut choisir naturellement quelles capacités lui transmettre. Le Principle Of Least Authority est beaucoup mieux respecté que dans un système UNIX classique, où tous les processus lancés par le même utilisateur ont tous les droits de l’utilisateur : il y a une autorité «  ambiante  » qui peut être abusée.

Une capacité doit être non-forgeable pour qu’un agent ne puisse effectuer que les actions dont les droits lui ont été attribués. Ainsi, les utilisateurs n’ont pas accès au système de fichiers dans son ensemble, ils ne «  voient  » que les fichiers sur lesquels ils ont une capacité de lecture. Enfin, le fait de coupler la désignation d’un objet et l’autorité sur l’action qui l’accompagne, permet d’éviter les attaques de type « confused deputy ».

Enfin, attention à ne pas confondre, les capacités du monde de la sécurité sont différentes des « POSIX capabilities », des systèmes de contrôle de droits beaucoup plus grossiers (cf. cet argumentaire).

Aller plus loin :

Une bonne idée longtemps oubliée

Malgré des débuts prometteurs, l’idée des capacités a quasiment été oubliée dans les années 1980. Plusieurs causes ont contribué à cet échec : d’abord, le concept de « renversement de point de vue » par rapport aux Access Control List a paradoxalement répandu l’idée que les capacités n’apportaient en fait rien de nouveau, et que tout ce qui était fait pourrait aussi bien être fait, de façon symétrique, avec les listes d’accès de contrôle. Cette «  méconception  » ignore le fait que la gestion des droits au niveau de l’agent, et non de l’objet, permet une granularité beaucoup plus fine que les utilisateurs ou groupes utilisés dans les systèmes ACL classiques. Un modèle de droits doit être considéré de façon dynamique (modification et transmission des droits) et pas seulement statiquement, à un instant donné.

De plus, les premiers systèmes de capacités ne permettaient pas la révocation (le fait de retirer des droits qu’on a donné à un autre agent), et permettaient à chaque processus de diffuser ses propres droits sans restriction, ce qui met en péril les modèles de sécurité militaires où l’on veut garantir, par exemple, qu’une personne ayant accès à des documents « top secret » ne peut pas pour autant les faire lire à un simple moussaillon. On a depuis montré que les capacités permettaient en fait ces deux choses, mais le préjugé est resté.

Enfin et surtout, l’énorme succès d’UNIX, ayant une approche fondamentalement opposée à celle des capacités, a rapidement étouffé la recherche de systèmes alternatifs et incompatibles (cf. le pessimiste et grinçant Systems Software Research is Irrelevant (PDF, 23 transparents) de Rob Pike).

Cependant, un petit groupe d’irréductibles a continué à travailler sur les capacités. En particulier, les micro-noyaux (un autre franc succès du monde de l’informatique) ont souvent utilisé des capacités, car leur emploi est très naturel dans un contexte de passage de messages. En particulier les systèmes KeyKOS puis EROS ont montré qu’une conception entièrement basée sur les capacités était possible, sans perte de performances.

Mais les capacités peuvent être déployées à plus haut niveau que le noyau d’un système. Ainsi, Mark Miller a développé le langage de programmation E, épousant entièrement le concept de capacité, qui permet d’écrire des programmes distribués et sécurisés.

Enfin, l’environnement de bureau Capdesk a été écrit en E, et démontre qu’une interface utilisateur peut intrinsèquement favoriser la sécurité. Un exemple simple : sur un système classique, quand un utilisateur veut ouvrir un nouveau fichier dans son application préférée, celle-ci ouvre un « dialogue de choix de fichier » qui lui permet de naviguer dans son système et de choisir le fichier désiré que l’application ouvre ensuite. Mais pour faire cela, l’application doit nécessairement avoir le droit de lecture sur toute l’arborescence de l’utilisateur, pour lui permettre d’y naviguer. Dans CapDesk, le widget « choix de fichier » est en fait un programme externe auquel l’application fait appel, qui a le droit de naviguer dans les répertoires, et qui renvoie finalement à l’application un simple descripteur de fichier avec les bons droits. Ainsi, l’application n’a pas besoin des droits sur le système de fichiers. Enfin, au lieu d’un simple choix « ouvrir / annuler », on peut afficher, selon les besoins de l’application, « ouvrir en lecture » ou « ouvrir en écriture », pour que l’utilisateur soit mieux conscient des droits qu’il choisit de déléguer à l’application.

Mais les innovations révolutionnaires qui demandent de changer complètement de système d’exploitation, de langage de programmation ou d’environnement de bureau n’ont pas percé (de même que le micro-noyau L4, Lisp ou GNUStep). Les amateurs de capacités ont alors cherché à «  amadouer  » (tame) des environnements existants, en les restreignant de façon à pouvoir y garantir les bonnes propriétés des systèmes par capacité. Par exemple, il faut retirer d’un langage de programmation les fonctions qui « ajoutent de l’autorité ambiante », comme les fonctions convertissant un chemin en descripteur de fichier (contient l’autorité entière sur le système de fichiers), ou empêcher les conversions de types trop barbares, qui pourraient permettre de forger une capacité. Entre autres, des versions restreintes des langages Java (Joe-E), Scheme (W7), OCaml (Emily) ont été proposées. Moins le langage met en avant les variables globales et les effets de bord qui risquent de créer des
canaux cachés, plus il est facile à rendre « capability safe ».

Récemment, les capacités ont vu un net regain de popularité dans le cadre de la sécurisation du langage de programmation JavaScript. On a encore du mal à y croire, mais ce « langage bricolé » est devenu le standard de fait pour distribuer du code sur internet. Un environnement fortement multi-utilisateur avec distribution et exécution de code dans tous les sens, c’est un mélange explosif pour la sécurité, et de nombreuses failles ont commencé à apparaître (XSS…). Les efforts déployés pour restreindre les sites malicieux (comme le projet FBJS de Facebook) sont mis à mal par les défauts du langage, comme sa gestion abracadabrante des environnements de noms (« scopes »). En utilisant un modèle de capacités, on peut protéger le navigateur et les sites en les aidant à restreindre les droits des scripts exécutés. C’est le thème, entre autres, du prometteur projet Caja de Google. Les acteurs du Web ont même souhaité prendre en compte ces questions dans les nouvelles versions de JavaScript, et ont invité Mark Miller dans le comité de standardisation, pour proposer des évolutions du langage facilitant l’approche par capacités.

Pour approfondir :

  • Capability Myths Demolished (PDF, 15 pages) de Mark Miller, Ka-Ping Yee et Jonathan Shapiro, 2003. Cet article explique les «  méconceptions  » classiques qui ont fait du tort aux modèles par capacités, comment les corriger. C’est aussi une très bonne présentation des avantages des capacités  ;
  • le site du langage E, une mine d’informations (en anglais) sur les concepts sous-jacents, la programmation distribuée et les capacités  ;
  • le projet Waterken, un framework Web basé sur Joe-E, qui a raffiné les concepts de capacités dans le contexte de la programmation Web  ;
  • l’article User Interaction for Secure Systems (PDF, 16 pages), de Ka-Ping Yee, 2002, montre que négliger l’interface utilisateur, même dans un système respectant le Principle Of Least Authority, peut donner lieu à des problèmes de sécurité  ;
  • l’interview sur InfoQ de Mark Miller, où il discute de son travail dans le comité de standardisation de ECMAscript 5 pour obtenir un langage plus propice à la sécurité : ECMAScript 5, Caja and Retrofitting Security. Il y a une vidéo, mais ne fuyez pas tout de suite, un bonne transcription texte est disponible en dessous. Cliquez sur les petits «  +  » ou « Full page transcript », en bas, pour voir le texte, et sur les titres pour synchroniser à cet endroit de la vidéo  ;
  • L’article Object Capabilities and Isolation of Untrusted Web Applications (PDF, 16 pages) de Sergio Maffeis, John Mitchell, Ankur Taly, qui donne une preuve formelle de la sécurité d’un sous-ensemble de JavaScript (travail qui a permis de trouver des failles dans FBJS), et une autre preuve que le sous-ensemble utilisé par Caja est « capability-safe ».

    P.S. : John Mitchell a récemment donné un exposé (en anglais) à ce sujet au Collège de France, dans le cadre du cours sur la sécurité informatique qui y a lieu en ce moment. Des transparents sont disponibles, et un enregistrement audio devrait l’être bientôt.

    C’est aussi une remarque en passant pour dire que, si vous êtes dans la région parisienne et que vous voulez voir la sécurité vulgarisée pour votre grand-mère, ou presque, par des pointures du domaine, n’hésitez pas à passer au Collège de France le mercredi matin (mais attention, la salle est déjà bien remplie).

Le projet Capsicum

Le monde du développement Web, bien qu’il croule déjà sous le poids de la rétro‑compatibilité et des standards à rallonge, est encore relativement jeune et peut se permettre des expérimentations de fond.

Du côté des systèmes d’exploitation, l’évolution est moins rapide. Les systèmes d’exploitation actuels n’ont pas beaucoup évolué dans le domaine la sécurité, par rapport aux systèmes UNIX initiaux. Des systèmes plus fins ont été proposés, comme SELinux : l’idée d’ensemble est que ce sont les administrateurs(1) qui décident des politiques de sécurité en écrivant des scripts de «  profils  » regroupant un petit ensemble de droits, et qui forcent les applications à rentrer dans ces cadres. Malheureusement, ces politiques restent difficiles à écrire, maintenir et déployer, et ces approches n’ont donc pas encore sensiblement amélioré la situation pour les systèmes grand public.

L’approche la plus utilisée est celle des « sandboxes », qui consistent
à compartimenter des applications en utilisant les facilités du
système d’exploitation (« chroot » ou « seccomp », les jails FreeBSD,
etc.), mais leur gestion des droits est beaucoup moins fine que les
systèmes de capacités, avec souvent des approches « tout ou rien »
(par exemple, « seccomp » interdit tout sauf « read », « write » et « exit »).

Le projet Capsicum cherche à «  amadouer  » les appels système, en trouvant un compromis entre la flexibilité-fouillis des capacités (une capacité = un droit) et l’autorité ambiante écrasante des systèmes UNIX habituels. Ses concepteurs ont choisi de raffiner les descripteurs de fichiers UNIX en leur ajoutant des masques de droits permettant une gestion fine des droits (plus de 60 masques différents) auxquels ils sont associés. L’intérêt de réutiliser les descripteurs de fichiers au lieu d’une abstraction dédiée, est de rester dans un style de programmation qui est familier aux programmeurs système UNIX.

Le noyau maintient pour chaque processus un drapeau (flag) booléen qui indique s’il est en « mode capacités » : un programme classique (non sécurisé par Capsicum) ne l’est pas, mais peut choisir d’y entrer avec le nouvel appel système « cap_enter ». Ce drapeau est hérité par tous les processus créés, et ne peut être retiré. Quand le drapeau est activé, tous les appels système exposant de l’autorité ambiante sont interdits, d’autres sont restreints (par exemple « openat », qui ouvre un fichier à partir d’un répertoire donné, n’accepte plus que les chemins relatifs désignant un fichier dans le sous‑répertoire), et ceux qui restent sont légèrement modifiés pour prendre en compte les masques de droits du descripteur de fichier. Il y a aussi des appels système de bas niveau pour réduire les droits d’un descripteur de fichier, ou lancer un nouveau processus en lui transmettant une partie de ses droits. Enfin, la bibliothèque utilisateur libcapsicum propose des composants de plus haut niveau qui permettent de retrouver le niveau de confort (tout relatif) des programmes systèmes habituels, et les opérations courantes de manipulation de droits.

Les descripteurs de fichiers ne sont pas le seul espace de nom global des systèmes UNIX (malgré les efforts dans ce sens du projet Plan9). Les sockets réseau, timers et toutes les interfaces System V et POSIX bizarres pour manipuler, par exemple, la mémoire partagée, sont aussi contrôlés, ce qui est souvent négligé par les solutions de « sandboxing » existantes.

L’idée est de découper les applications en une partie privilégiée, qui tourne avec tous les droits qu’elle avait au lancement, et une ou plusieurs parties compartimentées, qui sont sous un appel à « cap_enter » avec exactement les droits nécessaires. Le but du jeu est que toutes les parties sensibles (en C, la manipulation de chaînes) soient compartimentées et que la partie privilégiée réalise le moins de choses possibles, ceci afin de réduire la surface d’attaque. Plus le découpage est fin, plus le logiciel respecte le Principle of Least Authority. Et la sécurité en est d’autant renforcée.

(1) : Plus généralement, les approches par Mandatory Access Control (SELinux) et par capacités sont complémentaires : le MAC vise à permettre à un administrateur système de contrôler les droits selon les besoins de son environnement, alors que les capacités servent
au développeur pour contrôler les droits selon les besoins de son application.

En savoir plus :

  • la page du projet Capsicum au laboratoire sécurité de l’université de Cambridge (GB)  ;
  • les transparents de la présentation (PDF, 31 pages) donnée à la conférence de sécurité USENIX en août dernier  ;
  • l’article « Capsicum : practical capabilities for UNIX » (PDF, 17 pages), par Robert Watson et Jonathan Anderson (Cambridge), Ben Laurie et Kris Kennaway (Google UK). Cet article contient une explication plus détaillée de Capsicum (logique  !), mais aussi des rapports d’expériences sur des essais de sécurisation de logiciels existants, et des mesures de performance pour évaluer le surcoût associé à ces modifications. Je les décrirai brièvement dans la prochaine partie, mais si vous voulez des détails, il faut aller lire ce papier. Enfin, l’article contient des comparaisons aux solutions existantes : si vous vous dites « mais, c’est pareil que SELinux / chroot / PLASH  ! », il faut aller lire ça.

Et ça marche  ?

Les gens de Google qui travaillent sur le navigateur Chromium se sont montrés très intéressés par le projet Capsicum. En effet, Chromium essaie de mettre en place des mécanismes de « sandboxing », ce qui a forcé les développeurs à évaluer les différentes solutions existant sur les principaux OS (Windows, Mac OSX, GNU/Linux, BSD…). Ils ont découvert qu’aucune solution n’est complètement satisfaisante : soit les droits sont trop grossiers, rigides ou difficiles à configurer (Sandbox de MacOS X, SELinux), soit les droits sont très restreints et il faut alors implémenter soi‑même une couche de médiation en utilisant un processus ayant plus d’autorité. Ainsi, la solution de confinement sous Windows et celle utilisant « seccomp » sous GNU/Linux ont demandé des dizaines de milliers de lignes de code supplémentaires, sans pour autant obtenir exactement les droits désirés… Capsicum leur a permis, en modifiant seulement une centaine de lignes de code, de mettre en place une sandbox flexible et répondant à leurs besoins.

Les développeurs de FreeBSD se sont aussi montrés intéressés par la technologie Capsicum, et se préparent à l’inclure dans la prochaine version de FreeBSD. Évidemment, comme Capsicum demande des modifications des appels système du noyau sur des points plutôt sensibles, il faut réussir à convaincre les développeurs de chaque noyau qu’inclure ces modifications vaut le coup… La communauté NetBSD a eu l’air plutôt favorablement intéressée, et un portage pour Linux serait en développement, mais l’inclusion en amont dans ces systèmes n’est pas encore d’actualité.

Du côté des autres applications, les développeurs de Capsicum ont converti les programmes « tcpdump », « dhclient » (tous deux déjà responsables de vulnérabilités liées au traitement des chaînes de caractères, et déjà partiellement compartimentés en utilisant d’autres technologies moins fines) et « gzip ».

Ci‑dessous, les 8 lignes de sécurisation du code de tcpdump. On commence par restreindre l’autorité ambiante des descripteurs de fichiers standard : on ne pourra plus utiliser que « fstat() » sur «  stdin  ». La fonction « lc_limitfd() » provient de capsicum-core, bibliothèque en espace utilisateur. Ensuite on passe en mode capacités avec « cap_enter ». À partir de ce moment, les paquets reçus seront analysés (opération sensible) dans un environnement à autorité minimale.

if (lc_limitfd(STDIN_FILENO, CAP_FSTAT) < 0)
    error("lc_limitfd: unable to limit STDIN_FILENO");
if (lc_limitfd(STDOUT_FILENO, CAP_FSTAT | CAP_SEEK | CAP_WRITE) < 0)
    error("lc_limitfd: unable to limit STDIN_FILENO");
if (lc_limitfd(STDERR_FILENO, CAP_FSTAT | CAP_SEEK | CAP_WRITE) < 0)
    error("lc_limitfd: unable to limit STDERR_FILENO");
if (cap_enter() < 0)
    error("cap_enter: %s", pcap_strerror(errno));

Les leçons tirées de ces expériences sont multiples. D’une part, les développeurs ont pu observer que sur une application réelle, le surcoût en performance lié au « sandboxing » est «  assez  » faible (moins de 10 % dans les cas défavorables, et un petit surcoût constant en général). Il y a quand même un coût qu’ils essaient de réduire en optimisant leur implémentation. Paradoxalement, Capsicum est moins coûteux que d’autres solutions de « sandboxing », donc, en convertissant un logiciel déjà compartimenté vers Capsicum, on peut en améliorer légèrement les performances, en plus d’obtenir une gestion plus fine des droits.

D’autre part, ils ont constaté que les applications qui reposaient déjà sur un modèle compartimenté avec « sandboxing » étaient extrêmement faciles à convertir vers Capsicum. Mais, le cas d’applications grand public n’ayant aucune expérience de séparation des privilèges risque d’être plus délicat…

La grande force de Capsicum par rapport aux autres solutions utilisant les capacités, c’est qu’il s’agit d’un raffinement, et non d’un remplacement, des systèmes de droits UNIX usuels : on peut convertir les applications une par une, et même module par module. Une mise en œuvre progressive, concentrée sur les applications sensibles, est donc possible. Mais il faut quand même motiver les développeurs à prendre ces problématiques en compte.

À quand Capsicum disponible sur Linux, et LibreOffice, Firefox et KDE respectant le principe de moindre autorité  ? Qui s’y colle  ?

Plus de détails croustillants :

  • la discussion sur la liste FreeBSD en vue d’une intégration dans la 9.x. Ce message, en particulier, contient des comparaisons à d’autres solutions de sécurité  ;
  • Capsicum est mentionné dans le rapport d’activité FreeBSD, avec un plan plus détaillé d’intégration dans FreeBSD  ;
  • le fil de discussion des gens de NetBSD au sujet de Capsicum  ;
  • deux messages (en juin et en janvier) de Heradon Douglas, un ingénieur Google qui travaille à un portage Linux sur ses 20 % de temps libre. On est encore loin d’une intégration en amont…

Cet article est repris du site http://linuxfr.org/news/capsicum-un...

Publications Derniers articles publiés

Sites favoris Tous les sites

84 sites référencés dans ce secteur