• [^] # Re: Très intéressant, mais moins pratique que pledge

    Posté par (site web personnel) . En réponse à la dépêche Linux capabilities : se passer des commandes su et sudo. Évalué à 3.

    Soyons d'accord sur ça : non, aucun programme actuel ne vérifie ce que vous souhaitez vérifier avec votre projet. Si je grossis un peu le trait (dites-moi si je me trompe, qu'on soit définitivement d'accord sur la question), votre projet est d'intercepter tous les appels systèmes pour vérifier à la fois si ce sont des appels autorisés, et les paramètres qui y sont passés. Au final oui, vous allez bien plus loin que ce qui existe. Mais je vois 2 problèmes majeurs : les outils (et méthodes) actuels se rapprochent d'une vérification à gros grain mais qui couvre une (très) bonne partie des problèmes, et la complexité pour décrire des autorisations.

    Revenons sur vos exemples.
    Concernant les ports ouverts, effectivement, pledge et doas ne peuvent pas vérifier cela. En revanche c'est le travail de pf (le pare-feux packet filter), et il le fait très bien, il va même au delà de ce que vous souhaitez faire : vous pouvez préciser les messages qui sont ou pas accepter (est-ce qu'il doit accepter d'ouvrir des connexions TCP à partir de ce port, ou seulement en recevoir ? Est-ce de l'UDP ? SCTP ? Quelle taille de buffer ? ...).

    Pour l'exemple que vous donnez d'un subprocess qui serait appelé par un programme d'awazan, et que ce programme aurait été modifié par awazan pour y ajouter des éléments dans pledge, c'est au final très peu réaliste. En réalité, il est hors de question de donner des droits root à un simple utilisateur sur un programme de l'utilisateur. C'est un non sens, littéralement une faille de sécurité.

    Comme nous l'avons vu pour l'instant, les exemples couvrent l'usage du réseau, ce qui est important également c'est l'usage du système de fichiers, et pour ça la séparation de privilèges (que j'ajouterai volontiers : amorcée par le projet OpenBSD...) et le chroot. Rien qu'avec les outils que je viens de citer, on sait gérer en grande partie le réseau (quels sont les ports qui peuvent être ouverts), on ne laisse pas une application ouvrir des fichiers au hasard sur le système (elle est contrainte dans une racine séparée), et on ne laisse pas un simple utilisateur s'octroyer des droits (hors de question qu'on laisse des droits root sur un programme utilisateur, on donne le droit à un utilisateur de lancer un programme root avec des paramètres prédéfinis).

    On peut dire également que votre projet permet à un simple utilisateur de lancer son propre programme de manière sûre... si on a fait un gros travail en amont pour contraindre le programme qu'il veut lancer à ne faire que ce dont on a décidé. Effectivement, vous pouvez aller jusqu'à préciser à la fois qu'un programme en particulier sera utilisé par un utilisateur en particulier et qu'il n'aura pas le droit d'ouvrir autre chose qu'un port en particulier. Mais tout ceci reste laborieux, et en pratique les paramètres vont changer très souvent. Là où les outils actuels font bien leur travail est qu'ils maintiennent une balance intéressante entre le temps pris pour l'administration/développement, et les vérifications qui sont faites. C'est simple, rapide à implémenter, et du coup c'est utilisé.

    Ensuite, concernant la complexité de description des autorisations. Vous avez fait un travail pour alléger l'écriture des différentes règles en définissant des rôles à des utilisateurs et des groupes, ce qui est un moyen assez simple de regrouper des instructions qui ont un même sens sémantique. Ça ne va pas assez loin, c'est même bien trop simpliste. Les exemples qu'on peut voir sont également simplistes, et je ne vois pas votre projet fonctionner pour de grosses applications, il y a un manque d'expressivité. Je ne peux que vous conseiller de regarder la syntaxe de pf dans la FAQ OpenBSD pour vous en inspirer.

    Pour que votre solution soit utilisable, il faudrait selon moi regrouper les appels système, pouvoir donner des indications "laxistes" où on dirait "vérifie que le programme X n'ouvre que le port Y, mais je m'en fous de tout autre paramètre lié au réseau". Sinon on sera obligé d'écrire des tonnes d'instructions pour couvrir tous les appels qui sont fait. Par exemple, si un programme a besoin de lire et écrire des fichiers, il va être un peu pénible de devoir faire une instruction pour préciser tous les appels de open avec tous les fichiers (ou alors il faut s'inspirer des tables dans pf). Bref, regardez la syntaxe pf, il y a déjà tout ce que vous voulez : des tables pour regrouper des capacités, utilisateurs, groupes, des instructions de blocage ou acceptation (block, pass) et la possibilité de dire "tout sauf" (via '!') ce qui est pratique, des macros pour simplifier la lecture, des listes, des ancres pour donner la possibilité à une application externe d'ajouter des instructions à la volée...

    Allez, je ne résiste pas à donner un exemple :

    table <webusers> { awazan, toto } # table = liste qui peut être màj à la volée via une commande
    cap_net_web = "cap_net_bind_service port { 80, 443 }"
    progweb = "/usr/local/sbin/webfail.py"

    cap_fs = { toutes les capacités liées au système de fichiers }

    pass cap_net_web to <webusers> prog progweb
    pass log cap_fs to <webusers> prog progweb label "fs web" # autorise et log tous les accès aux fichiers
    block # bloque tout ce qui n'est pas explicitement autorisé au dessus

    Bon, si le projet se dessine au final comme ça, il m'intéresse. ;) Là il commencerait à devenir intéressant dans la pratique (pour le debug principalement).

    PS: Vous ne pouvez pas le savoir... mais il y a un commentaire que j'ai posté il y a plus d'un an sous cette vidéo... :-D