web-dev-qa-db-fra.com

Exécuter un programme C non fiable dans un bac à sable sous Linux qui l'empêche d'ouvrir des fichiers, de bifurquer, etc.?

Je me demandais s'il existe un moyen d'exécuter un programme C non fiable sous un bac à sable sous Linux. Quelque chose qui empêcherait le programme d'ouvrir des fichiers ou des connexions réseau, ou de bifurquer, d'exécuter, etc.?

Ce serait un petit programme, un devoir, qui est téléchargé sur un serveur et sur lequel des tests unitaires sont exécutés. Le programme serait donc de courte durée.

107
Frank

J'ai utilisé Systrace pour bac à sable des programmes non approuvés à la fois de manière interactive et en mode automatique. Il a un backend basé sur ptrace() qui permet son utilisation sur un système Linux sans privilèges spéciaux, ainsi qu'un backend beaucoup plus rapide et plus puissant qui nécessite de patcher le noyau.

Il est également possible de créer un sandbox sur des systèmes de type Unix en utilisant chroot(1) , bien que ce ne soit pas aussi simple ou sécurisé. Conteneurs Linux et prisons FreeBSD sont une meilleure alternative au chroot. Une autre alternative sous Linux consiste à utiliser un cadre de sécurité comme SELinux ou AppArmor , ce que je proposerais pour les systèmes de production.

Nous serions en mesure de vous aider davantage si vous nous disiez exactement ce que vous voulez faire.

MODIFIER:

Systrace fonctionnerait pour votre cas, mais je pense que quelque chose basé sur le Linux Security Model comme AppArmor ou SELinux est une alternative plus standard, et donc préférée, en fonction de votre distribution.

EDIT 2:

Alors que chroot(1) est disponible sur la plupart (tous?) Des systèmes de type Unix, il a quelques problèmes:

  • Il peut être rompu. Si vous allez réellement compiler ou exécuter des programmes C non fiables sur votre système, vous êtes particulièrement vulnérable à ce problème. Et si vos élèves sont comme les miens, quelqu'un essaiera de sortir de la prison.

  • Vous devez créer une hiérarchie complète de système de fichiers indépendante avec tout ce qui est nécessaire pour votre tâche. Vous n'avez pas besoin d'avoir un compilateur dans le chroot, mais tout ce qui est requis pour exécuter les programmes compilés doit être inclus. Bien qu'il existe des utilitaires qui aident à cela, ce n'est toujours pas trivial.

  • Vous devez maintenir le chroot. Comme il est indépendant, les fichiers chroot ne seront pas mis à jour avec votre distribution. Vous devrez soit recréer le chroot régulièrement, soit y inclure les outils de mise à jour nécessaires, ce qui nécessiterait essentiellement qu'il s'agisse d'une distribution Linux complète. Vous devrez également conserver les données système et utilisateur (mots de passe, fichiers d'entrée e.t.c.) synchronisées avec le système hôte.

  • chroot() protège uniquement le système de fichiers. Cela n'empêche pas un programme malveillant d'ouvrir des sockets réseau ou un programme mal écrit d'aspirer toutes les ressources disponibles.

Le problème d'utilisation des ressources est commun à toutes les alternatives. Quotas du système de fichiers empêchera les programmes de remplir le disque. Les bons paramètres ulimit ( setrlimit() en C) peuvent protéger contre la surutilisation de la mémoire et toute bombe à la fourche, ainsi que mettre un terme à Porcs CPU. Nice(1) peut réduire la priorité de ces programmes afin que l'ordinateur puisse être utilisé sans problème pour toutes les tâches jugées plus importantes.

46
thkala

J'ai écrit un aperçu des techniques de sandboxing sous Linux récemment. Je pense que votre approche la plus simple serait d'utiliser des conteneurs Linux (lxc) si cela ne vous dérange pas de bifurquer et ainsi de suite, ce qui n'a pas vraiment d'importance dans cet environnement. Vous pouvez donner au processus un système de fichiers racine en lecture seule, une connexion réseau de bouclage isolée, et vous pouvez toujours le tuer facilement et définir des limites de mémoire, etc.

Seccomp va être un peu difficile, car le code ne peut même pas allouer de mémoire.

Selinux est l'autre option, mais je pense que cela pourrait être plus de travail qu'un conteneur.

18
Justin Cormack

Vous pouvez utiliser Qemu pour tester rapidement les affectations. Cette procédure ci-dessous prend moins de 5 secondes sur mon ordinateur portable de 5 ans.

Supposons que l'étudiant doive développer un programme qui accepte les entiers non signés, chacun sur sa propre ligne, jusqu'à ce qu'une ligne avec "-1" arrive. Le programme doit ensuite faire la moyenne de tous les ints et produire "Moyenne:% f". Voici comment tester un programme complètement isolé:

  1. Tout d'abord, obtenez root.bin de Jslinux, nous l'utiliserons comme espace utilisateur (il a le compilateur tcc C):

    wget https://github.com/levskaya/jslinux-deobfuscated/raw/master/root.bin

  2. Nous voulons mettre la soumission de l'étudiant dans root.bin, alors configurez le périphérique de boucle:

    Sudo losetup /dev/loop0 root.bin

    (vous pouvez également utiliser fuseext2, mais ce n'est pas très stable. S'il se stabilise, vous n'aurez pas besoin de root pour tout cela)

  3. Créez un répertoire vide:

    mkdir mountpoint

  4. Mont root.bin:

    Sudo mount /dev/loop0 mountpoint

  5. Entrez le système de fichiers monté:

    cd mountpoint.

  6. Fixer les droits:

    Sudo chown -R `whoami` .

  7. mkdir -p etc/init.d
  8. vi etc/init.d:

    #!/bin/sh
    cd /root
    echo READY 2>&1 > /dev/ttyS0
    tcc assignment.c 2>&1 > /dev/ttyS0
    ./a.out 2>&1 > /dev/ttyS0
    
  9. chmod +x etc/init.d/rcS

  10. Copiez la soumission sur la machine virtuelle:

    cp ~/student_assignment.c root/assignment.c

  11. Quittez la racine de la machine virtuelle FS:

    cd ..

  12. Sudo umount mountpoint
  13. Maintenant que l'image est prête, il nous suffit de l'exécuter. Il compilera et exécutera la soumission après le démarrage.
  14. mkfifo /tmp/guest_output
  15. Ouvrez un terminal séparé et commencez à écouter la sortie invité:

    dd if=/tmp/guest_output bs=1

  16. Dans un autre terminal:

    qemu-system-i386 -kernel vmlinuz-3.5.0-27-generic -initrd root.bin -monitor stdio -nographic -serial pipe:/tmp/guestoutput (Je viens d'utiliser le noyau Ubuntu ici, mais de nombreux noyaux fonctionneront)

  17. Lorsque la sortie d'invité affiche "READY", vous pouvez envoyer des clés à VM à partir de l'invite qemu. Par exemple, pour tester cette affectation, vous pouvez faire

    (qemu) sendkey 1
    (qemu) sendkey 4
    (qemu) sendkey ret
    (qemu) sendkey 1
    (qemu) sendkey 0
    (qemu) sendkey ret
    (qemu) sendkey minus
    (qemu) sendkey 1
    (qemu) sendkey ret
    
  18. À présent Average = 12.000000 devrait apparaître sur le canal de sortie invité. Si ce n'est pas le cas, l'élève a échoué.

  19. Quittez qemu: quit

Un programme qui réussit le test est ici: https://stackoverflow.com/a/14424295/30948 . Utilisez simplement tcclib.h au lieu de stdio.h.

6
Janus Troelsen

Essayez Linux en mode utilisateur . Il présente une surcharge de performances d'environ 1% pour les travaux gourmands en ressources processeur, mais il peut être 6 fois plus lent pour les travaux gourmands en E/S.

5
pts

L'exécuter à l'intérieur d'une machine virtuelle devrait vous offrir toute la sécurité et les restrictions que vous souhaitez.

QEMU serait un bon choix pour cela et tout le travail (télécharger l'application, mettre à jour l'image disque, démarrer QEMU, exécuter l'application à l'intérieur et enregistrer la sortie pour une récupération ultérieure) pourrait être scriptée pour des tests automatisés.

3
Laurent Parenteau

seccomp et seccomp-bpf accomplissent cela avec le moindre effort: https://www.kernel.org/doc/Documentation/prctl/seccomp_filter.txt

3
cptaffe

Quand il s'agit de sanboxing basé sur l'extraction de ptrace (strace):

" sydbox " sandbox et " pinktrace " bibliothèque de programmation (c'est C99 mais il existe des liaisons vers python et Ruby pour autant que je sache).

Liens collectés liés au sujet:

http://www.diigo.com/user/wierzowiecki/sydbox

(désolé, pas de liens directs, mais pas encore assez de points de réputation)

3

Firejail est l'un des outils les plus complets pour ce faire - il prend en charge seccomp, les conteneurs de système de fichiers, les capacités et plus encore:

https://firejail.wordpress.com/features-3/

2
Federico

Cela semble également prometteur. Un sandbox de système de fichiers pour Linux utilisant des interceptions syscall.

https://github.com/adtac/fssb

1
mauron85

Cette bibliothèque devrait bien servir votre objectif

http://sandbox.sourceforge.net

Bonne chance!

1
thoaionline