URL: https://linuxfr.org/users/pied/journaux/seccomp-une-sandbox-integree-au-noyau-linux Title: Seccomp, une sandbox intégrée au noyau Linux... Authors: Pinaraf Date: 2014年05月04日T23:15:17+02:00 License: CC By-SA Tags: sécurité, seccomp, sandbox et concours_securite_201405 Score: 45 #Problématique# Utilisez-vous pour vos développements professionnels ou privés une solution d'intégration continue à la Jenkins ? Un tel logiciel permet d'accélérer le développement du code en le testant plus régulièrement, en le soumettant automatiquement à des tests unitaires. Mais que se passe-t-il si un vilain© soumet du code dangereux pour votre système d'intégration continue ? Si votre logiciel d'intégration continue se contente de compiler du code, vous pensez qu'il est protégé ? Quid d'une faille dans votre compilateur, ou d'un problème à l'exécution d'un test unitaire ? Vous vous retrouveriez alors avec un composant clé de votre infrastructure de développement corrompu, avec toutes les conséquences que cela peut avoir... À mon travail, par paranoïa, j'ai cherché comment faire pour pouvoir, à l'intégration du code, exécuter des tests sur nos projets Perl tout en restant protégé des vilains... #Comment faire...# J'ai précisé le langage utilisé, Perl. Perl a plusieurs particularités qui le rendent délicat à «sécuriser» dans un tel cadre : - il a été prouvé qu'on ne peut pas parser du code, rendant impossible toute analyse statique exhaustive (pour ceux que cela intéresse http://www.perlmonks.org/?node_id=663393), - même le plus simple contrôle par l'interpréteur (perl -c) permet une exécution arbitraire de code à l'aide des blocs BEGIN. Il faut donc se pencher sur un système de Sandbox. La sandbox intégrée à perl, le module Safe, ne nous aide pas à exécuter du «vrai» code : il ne pourra pas restreindre d'éventuelles manipulations via un module perl écrit en C par exemple. Tapons donc plus bas niveau : le noyau et la technologie utilisée par Google Chrome depuis peu sous Linux : seccomp. #Qu'est-ce-que seccomp ?# Seccomp permet de filtrer les appels systèmes d'un processus au niveau du noyau. La première version de cette technologie, introduite en 2005 dans le noyau 2.6.12, était très primitive : une fois passé en mode «sécurisé», un process ne pouvait plus exécuter qu'exit, read, write et sigreturn. Le strict minimum requis pour par exemple un cluster de calcul, mais largement insuffisant pour des applications complètes. La seconde version fut introduite dans le noyau 3.5 en juillet 2012 : seccomp-bpf. Un programme va envoyer au noyau un filtre BPF à appliquer sur les appels systèmes, et activer ensuite ce filtre. Ainsi, seuls les appels systèmes requis d'un logiciel peuvent être exécutés, toute tentative d'aller plus loin étant bloquée. Plus intéressant encore : les filtres peuvent être enchaînés, d'autres programmes exécutés avec leur propre restriction... Bien entendu, un tel filtre ne serait pas suffisant s'il ne permettait pas de filtrer également les paramètres passés aux appels système. Néanmoins, seules les valeurs directes peuvent être filtrées. Or une chaîne de caractère est passée par pointeur. Il faut donc avoir recours à un système plus complexe si l'on souhaite filtrer finement les fichiers ouverts. Mais on peut filtrer les droits, ça me suffit :) #Utilisons seccomp-bpf# Seccomp-bpf nécessite d'écrire du bytecode BPF, de l'envoyer au noyau par un prctl... C'est pénible. Une librairie a donc été écrite pour simplifier tout ça : http://sourceforge.net/projects/libseccomp/ ##Hello world## Nous allons pour le moment écrire un hello world, et le protéger des vilains... ```C #include int main (int argc, char **argv) { printf("Hello world\n"); return 0; } ``` Voilà, un programme extrêmement simple mais tellement capital qu'il faut le protéger par seccomp. Tout d'abord, quels appels système sont requis pour ce programme ? Facile, strace est notre ami. ``` snoopy@peanuts2:~/projects/seccomp-dlfp$ strace -c ./hello Hello world % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- -nan 0.000000 0 1 read -nan 0.000000 0 1 write -nan 0.000000 0 2 open -nan 0.000000 0 2 close -nan 0.000000 0 3 fstat -nan 0.000000 0 9 mmap -nan 0.000000 0 3 mprotect -nan 0.000000 0 1 munmap -nan 0.000000 0 1 brk -nan 0.000000 0 3 3 access -nan 0.000000 0 1 execve -nan 0.000000 0 1 arch_prctl ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000000 28 3 total ``` Pour la partie «active» du programme, celle qui nous intéresse plus : ``` fstat(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 3), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa7a47f9000 write(1, "Hello world\n", 12) = 12 exit_group(0) = ? ``` Facile ! Activons donc seccomp-bpf. Nous ferons la supposition que notre programme refusera de tourner sans, évidemment, pour ne pas prendre de risque. ```C #include #include int main(int argc, char **argv, char **envp) { scmp_filter_ctx scmp = seccomp_init(SCMP_ACT_KILL); if (!scmp) { fprintf(stderr, "Failed to initialize libseccomp\n"); return -1; } // Allow all needed syscalls seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(mmap), 0); seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(fstat), 0); // Load in the kernel if (seccomp_load(scmp) != 0) { fprintf(stderr, "Failed to load the filter in the kernel\n"); return -1; } printf("Hello world\n"); return 0; } ``` Compilons et exécutons : ``` snoopy@peanuts2:~/projects/seccomp-dlfp$ gcc -lseccomp hello-safe.c -o hello-safe ; ./hello-safe Hello world ``` Et si on rajoute un appel à unlink dans le code ? ``` snoopy@peanuts2:~/projects/seccomp-dlfp$ ./hello-safe Bad system call snoopy@peanuts2:~/projects/seccomp-dlfp$ echo $? 159 ``` Comment ça marche ? C'est très simple : seccomp_init crée un «contexte» pour la librairie seccomp, avec une action à effectuer par défaut. Puis chaque appel à seccomp_rule_add rajoute une règle dans le contexte, avec en paramètre le contexte, l'action à effectuer, le numéro de l'appel système (merci à la macro SCMP_SYS) et le nombre d'arguments sur lequel on va filtrer... Et enfin seccomp_load charge le contexte sur le processus courant dans le noyau. Attention, une fois le contexte chargé, il ne peut plus être déchargé pour d'évidentes raisons de sécurité. ##Les choses se compliquent : lisons des fichiers...## C'est tout de même plus pratique de pouvoir communiquer un peu avec le monde... Mais je ne veux pas que mon hello world soit corrompu et permette d'écrire sur mon disque. Je vais donc lui autoriser open uniquement avec le flag O_RDONLY. J'ajoute donc cette règle dans mon programme : ```C seccomp_rule_add(scmp, SCMP_ACT_ALLOW, SCMP_SYS(open), 1, SCMP_A1(SCMP_CMP_EQ, O_RDONLY)); ``` Et voilà... Aussi simple que cela. Imaginez les possibilités sur un programme SUID par exemple : pourquoi risquer de compromettre tous les droits d'un utilisateur si quelques lignes de code permettent de brider la fuite à quelques appels systèmes précis ? ##Tout n'est pas blanc ou noir## ALLOW et KILL... C'est sommaire. seccomp permet plus que ça : - TRAP : envoie un signal SIGSYS, - ERRNO(errno) : refuse l'appel avec l'erreur indiquée, - TRACE(msg_num) : génère un évènement ptrace. Armé de ces outils, vous pouvez commencer plein de choses : - développer plus aisément votre filtre seccomp en étant directement notifié des appels manquants, - faire croire à une non disponibilité du réseau pour exécuter un code qui fait des appels inutiles au réseau, - un monitoring plus poussé de vos processus avec un processus père se chargeant de donner des droits à des enfants à la demande, validant leurs demandes... Développer un tel logiciel parait hors de portée pour un simple journal par contre, surtout quand des gens l'ont déjà fait :) #Projets utilisant seccomp-bpf# Les plus beaux exemples d'utilisation de seccomp sont ceux qu'on ne voit pas : qemu, openssh 6.0, google chrome... Ces projets profitent de seccomp pour accroitre la sécurité sous Linux. En rédigeant ce journal, je suis aussi tombé (ouille) sur un beau projet de sandbox qui mériterait d'être plus connu : Mbox. http://pdos.csail.mit.edu/mbox/ Mbox combine seccomp, fakeroot et un système de fichiers temporaire pour permettre d'exécuter, en toute confiance et sans privilèges particuliers, un logiciel et de valider à la fin ses actions pour les "commiter" sur le système de fichier réel. Seccomp, c'est bon, mangez-en. Bien sûr, on vous dira «oui mais un conteneur c'est mieux», «une VM ça isole plus»... Ce n'est pas le même besoin, et seccomp est dans tous les cas un complément fort intéressant pour accroître la sécurité du système en mettant en place une politique volontaire de contrôle d'accès au sein des différents logiciels.

AltStyle によって変換されたページ (->オリジナル) /