39 votes

Comment créer un sandbox de code C léger?

J'aimerais construire un C le pré-processeur / compilateur qui permet des fonctions sont collectées auprès des locaux et des sources en ligne. c'est à dire:

#fetch MP3FileBuilder http://scripts.com/MP3Builder.gz
#fetch IpodDeviceReader http://apple.com/modules/MP3Builder.gz

void mymodule_main() {
  MP3FileBuilder(&some_data);
}

C'est la partie facile.

La partie la plus difficile est j'ai besoin d'un moyen fiable de "bac à sable" importées code de direct ou d'un accès illimité à disque ou d'un système de ressources (y compris l'allocation de la mémoire et de la pile). J'ai besoin d'un moyen pour exécuter en toute sécurité de petits extraits de non approuvé le code C (modules) sans la surcharge de les mettre dans des processus distinct, VM ou d'un interprète (un thread séparé serait acceptable si).

EXIGENCES

  • J'avais besoin de mettre des quotas sur l'accès aux données et aux ressources, y compris les temps de calcul.
  • Je vais bloquer l'accès direct à la norme bibliothèques
  • Je veux arrêter de code malveillant qui crée de la récursivité sans fin
  • Je veux limiter statique et dynamique de l'allocation à des limites spécifiques
  • Je veux attraper toutes les exceptions, le module peut soulever (comme la division par 0).
  • Les Modules ne peuvent interagir avec d'autres modules via core interfaces
  • Les Modules ne peuvent interagir avec le système I/O, etc..) via des interfaces de base
  • Les Modules doivent permettre bits ops, les mathématiques, les tableaux, les énumérations, les boucles et la ramification.
  • Les Modules ne peuvent pas utiliser l'ASM
  • Je veux limiter pointeur et tableau d'accès à la mémoire réservée pour le module (via un custom safe_malloc())
  • Doit prendre en charge la norme ANSI C ou un sous-ensemble (voir ci-dessous)
  • Le système doit être léger et multi-plateforme (y compris les systèmes embarqués).
  • Le système doit être GPL ou LGPL compatible.

Je suis heureux de vous contenter d'un sous-ensemble de C. je n'ai pas besoin des choses comme des modèles ou des classes. Je suis principalement intéressé par les choses les langages de haut niveau ne font pas bien rapide comme les mathématiques, les opérations sur les bits, et de la recherche et de traitement de données binaires.

C'est pas l'intention que du code C existant peut être réutilisé sans modification de créer un module. L'intention est que les modules seraient nécessaires pour se conformer à un ensemble de règles et de restrictions visant à limiter le module de base de la logique et des opérations de transformation (comme un transcodage de vidéo ou des opérations de compression par exemple).

La contribution théorique à un tel compilateur/pré-processeur serait un unique C ANSI fichier (ou sous-ensemble sûr) avec un module_main fonction, ou un pré-processeur de directives, pas de l'ASM, Il permettrait à boucles, les branchements, les appels de fonction, le pointeur de maths (limitée à une gamme alloué pour le module), de décalage de bits, bitfields, les plâtres, les énumérations, les tableaux, ints, des flotteurs, des cordes et des mathématiques. Tout le reste est facultatif.

EXEMPLE DE MISE EN ŒUVRE

Voici un pseudo-extrait de code pour expliquer ce mieux. Voici un module qui la dépasse l'allocation de mémoire de quota et crée également une récursion infinie.

buffer* transcodeToAVI_main( &in_buffer ) {
    int buffer[1000000000]; // allocation exceeding quota
    while(true) {} // infinite loop
    return buffer;
}

Voici une version transformée où notre préprocesseur a ajouté des points d'observation pour vérifier l'utilisation de la mémoire et de la récursivité et enveloppé le tout dans un gestionnaire d'exception.

buffer* transcodeToAVI_main( &in_buffer ) {
    try {
        core_funcStart(__FILE__,__FUNC__); // tell core we're executing this function
        buffer = core_newArray(1000000000, __FILE__, __FUNC__); // memory allocation from quota
        while(true) {
           core_checkLoop(__FILE__, __FUNC__, __LINE__) && break; // break loop on recursion limit
        } 
        core_moduleEnd(__FILE__,__FUNC__);
    } catch {
        core_exceptionHandler(__FILE__, __FUNC__);
    }
    return buffer;
}

Je me rends compte de l'exécution de ces contrôles impact sur les performances du module mais je pense qu'elle le fera toujours mieux que de haut niveau ou VM langues pour les tâches qu'il est censé résoudre. Je n'essaie pas d'arrêter les modules de faire des choses carrément, je suis juste essayer de forcer ces dangereux que les choses arrivent d'une façon contrôlée (comme via les commentaires des utilisateurs). c'est à dire: "Module de X a dépassé l'allocation de la mémoire, de poursuivre ou d'abandonner?".

Mise à JOUR

Le meilleur que j'ai eu jusqu'à présent est d'utiliser un compilateur (Comme un piraté CCT) avec les limites de la vérification et de la coutume, de la fonction et le code de boucle pour attraper les récurrences. Je voudrais encore entendre les pensées sur quoi d'autre j'ai besoin de vérifier pour la ou les solutions sont là. J'imagine que la suppression de l'ASM et de la vérification des pointeurs avant de l'utiliser résout un grand nombre de préoccupations exprimées dans les réponses précédentes ci-dessous. J'ai ajouté une prime de soulever certains plus de commentaires hors de la communauté.

Pour le bounty, je suis à la recherche de:

  • Les détails d'éventuels exploits contre le système théorique défini ci-dessus
  • Possible d'optimisations sur la vérification des pointeurs sur chaque accès
  • Expérimentale implémentations open source de concepts (tels que Google Native Client)
  • Des Solutions qui prennent en charge un large éventail de système d'exploitation et les périphériques (no OS/matériel de solutions à base d')
  • Des Solutions qui prennent en charge la plupart C des opérations, ou encore C++ (si c'est possible)

Le crédit supplémentaire pour une méthode qui peut fonctionner avec GCC (c'est à dire, un pré-processeur ou de la petite GCC patch).

Je vais aussi donner de la considération à toute personne qui peut prouver de façon concluante ce que j'essaie ne peut pas être fait à tous. Vous aurez besoin d'être assez convaincante, car aucune des objections à ce jour ont vraiment cloué sur les aspects techniques de pourquoi ils pensent que c'est impossible. Dans la défense de ceux qui ont dit non à cette question a été posée comme un moyen d'exécuter en toute sécurité C++. J'ai maintenant mis à l'échelle de retour l'exigence d'un sous-ensemble limité de C.

Ma compréhension de C pourrait être classés comme des "intermédiaires", ma compréhension du matériel PC est peut-être une étape ci-dessous "avancé". Essayez de coach vos réponses à ce niveau si vous le pouvez. Je suis pas C expert, je vais en grande partie basées sur les votes donné une réponse, ainsi que la façon dont près de la réponse à mes besoins. Vous pouvez les aider en fournissant des éléments de preuve suffisants pour vos réclamations (intimés) et par le vote (tout le monde). Je vais attribuer une réponse une fois le bounty compte à rebours atteint 6 heures.

Enfin, je crois que la résolution de ce problème serait un grand pas vers le maintien, C est la pertinence est de plus en plus en réseau et paranoïaque du monde. Comme les autres langues de combler l'écart de performance et de puissance de calcul augmente, il sera plus difficile et plus difficile à justifier le risque de développement en C (comme c'est maintenant avec l'ASM). Je crois que vos réponses ont bien plus de la pertinence de la notation d'un peu de points donc merci de contribuer à ce que vous pouvez, même si la prime a expiré.

15voto

Rutger Nijlunsing Points 3051

Depuis la norme C est beaucoup trop large pour être admis, vous aurez besoin d'aller dans l'autre sens: préciser le nombre minimal de sous-ensemble de C dont vous avez besoin, et essayer de mettre cela en œuvre. Même ANSI C est déjà trop compliqué et permet de comportement indésirable.

L'aspect de C qui est plus problématiques sont les pointeurs: le langage C nécessite pointeur arithmitic, et ceux qui ne sont pas vérifiées. Par exemple:

char a[100];
printf("%p %p\n", a[10], 10[a]);

permettra à la fois d'imprimer la même adresse. Depuis a[10] == 10[a] == *(10 + a) == *(a + 10).

Tous ces pointeur accès ne peut pas être vérifié au moment de la compilation. C'est la même complexité que de demander au compilateur pour " tous les bugs dans un programme qui permettrait de résoudre le problème de l'arrêt.

Puisque vous voulez cette fonction pour être en mesure d'exécuter dans le même processus (éventuellement dans un autre thread) vous partager la mémoire entre votre application et le 'coffre-fort' module puisque c'est tout l'intérêt d'avoir un thread: partager des données pour un accès plus rapide. Cependant, cela signifie également que les deux threads peuvent lire et écrire la même mémoire.

Et puisque vous ne pouvez pas prouver moment de la compilation, où les pointeurs de fin, vous devez le faire au moment de l'exécution. Ce qui signifie que le code comme un "[10] "doit être traduit à quelque chose comme" get_byte(a + 10)' à quel point je n'appellerais pas ça C plus.

Google Native Client

Donc, si c'est vrai, comment est-ce que google le faire alors? Ainsi, contrairement aux exigences ici (cross-plateforme (y compris les systèmes embarqués)), Google se concentre sur x86, qui a en plus de la pagination de la page protections également registres de segment. Ce qui permet de créer un bac à sable où un autre thread ne partage pas la même mémoire de la même façon: le bac à sable est par la segmentation limité de changer seulement de sa propre mémoire. En outre:

  • une liste de coffre-fort x86 assemblée des constructions est assemblé
  • gcc est changé à émettre sécuritaire de constructions
  • cette liste est construite d'une manière qui est vérifiable.
  • après le chargement d'un module, cette vérification est effectuée

Donc, c'est de la plate-forme et n'est pas un "simple" solution, bien qu'un travail. Lire la suite dans leur document de recherche.

Conclusion

Donc, quel que soit l'itinéraire que vous allez, vous avez besoin pour commencer avec quelque chose de nouveau qui est vérifiable et alors seulement vous pouvez commencer par l'adaptation de l'existant d'un compilateur ou d'en générer un nouveau. Cependant, en essayant d'imiter le C ANSI oblige à réfléchir sur le problème de pointeur. Google modélisé leur sandbox pas sur le C ANSI, mais sur un sous-ensemble de x86, ce qui leur a permis d'utiliser des compilateurs existants en grande partie avec l'inconvénient d'être lié à x86.

10voto

Matt J Points 15475

Je pense que vous obtenez beaucoup de lecture à propos de certains de la mise en œuvre préoccupations et les choix de Google a fait lors de la conception de Native Client, un système d'exécution x86 code (en toute sécurité, nous l'espérons) dans le navigateur. Vous devrez peut-être faire un peu de la source de réécriture ou de la source-à-source de la compilation, de faire le code de sécurité si elle ne l'est pas, mais vous devriez être en mesure de s'appuyer sur la NaCL bac à sable pour attraper votre code assembleur généré si il essaie de faire quelque chose de trop funky.

5voto

Josh Kelley Points 24438

Si je devais le faire, je voudrais étudier un des deux approches:

  • L'utilisation du CERN CINT pour exécuter un code sandbox dans les services d'un interprète et de voir à propos de la limitation de ce que l'interprète de permis. Ce ne serait probablement pas donner la très bonne performance.
  • L'utilisation de LLVM pour créer une représentation intermédiaire du code C++ et ensuite voir s'il est possible d'exécuter du bytecode dans un sandbox Java-style VM.

Cependant, je suis d'accord avec les autres que c'est probablement une horrible impliqués projet. Regarder les problèmes que les navigateurs web ont eu avec buggy, ou suspendus plugins déstabilise l'ensemble de navigateur. Ou de regarder les notes de version pour la Wireshark projet; presque chaque nouvelle version, il semble, contient des correctifs de sécurité pour des problèmes de son protocole dissectors que puis affecter l'ensemble du programme. Si un C/C++ sandbox était faisable, je m'attends à de ces projets ont verrouillé sur un par maintenant.

5voto

SpliFF Points 21945

Je suis tombé sur de Minuscules Compilateur C (TCC). C'est peut être ce dont j'ai besoin:

*  SMALL! You can compile and execute C code everywhere, for example on rescue disks (about 100KB for x86 TCC executable, including C preprocessor, C compiler, assembler and linker).
* FAST! tcc generates x86 code. No byte code overhead. Compile, assemble and link several times faster than GCC.
* UNLIMITED! Any C dynamic library can be used directly. TCC is heading torward full ISOC99 compliance. TCC can of course compile itself.
* SAFE! tcc includes an optional memory and bound checker. Bound checked code can be mixed freely with standard code.
* Compile and execute C source directly. No linking or assembly necessary. Full C preprocessor and GNU-like assembler included.
* C script supported : just add '#!/usr/local/bin/tcc -run' at the first line of your C source, and execute it directly from the command line.
* With libtcc, you can use TCC as a backend for dynamic code generation.

C'est un très petit programme qui est sur le piratage il une option viable (hack GCC?, pas dans cette vie!). Je pense qu'elle fera une excellente base de départ pour construire mon propre restreint compilateur de. Je vais enlever le support pour les fonctionnalités de la langue je ne peux pas le faire en toute sécurité et l'enrouler ou de remplacer l'allocation de la mémoire et de la boucle de la manipulation.

La CCT peut déjà faire la vérification des limites sur les accès à la mémoire, qui est l'un de mes exigences.

libtcc est aussi une grande fonctionnalité, car j'ai peut alors gérer la compilation de code en interne.

Je ne vous attendez pas à être facile, mais il me donne de l'espoir que je peux obtenir des performances proches de C avec moins de risques.

Encore envie d'entendre d'autres idées si.

3voto

MSalters Points 74024

Parfaitement impossible. La langue ne fonctionne tout simplement pas de cette façon. Le concept de classes est perdu très tôt dans la plupart des compilateurs, y compris GCC. Même si c'était le cas, il n'y aurait aucun moyen d'associer chaque allocation de mémoire à un objet réel, sans parler d'un "module".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X