GNU/Linux >> Tutoriels Linux >  >> Linux

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

J'ai utilisé Systrace pour sandboxer des programmes non fiables à la fois de manière interactive et en mode automatique. Il a un ptrace() -backend 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 un patch du noyau.

Il est également possible de créer un bac à sable sur des systèmes de type Unix en utilisant chroot(1) , même si ce n'est pas aussi simple ou sûr. Les conteneurs Linux et les prisons FreeBSD sont une meilleure alternative au chroot. Une autre alternative sous Linux consiste à utiliser un framework 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 disiez exactement ce que vous voulez faire.

MODIF :

Systrace fonctionnerait pour votre cas, mais je pense que quelque chose basé sur le modèle de sécurité Linux comme AppArmor ou SELinux est une alternative plus standard, et donc préférée, selon votre distribution.

MODIFICATION 2 :

Alors que chroot(1) est disponible sur la plupart (tous ?) des systèmes de type Unix, il présente 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 VA essayer de s'évader de prison.

  • Vous devez créer une hiérarchie de système de fichiers entièrement indépendante avec tout ce qui est nécessaire à votre tâche. Vous n'avez pas besoin d'avoir un compilateur dans le chroot, mais tout ce qui est nécessaire 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 à part entière. Vous devrez également synchroniser les données système et utilisateur (mots de passe, fichiers d'entrée, etc.) 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. Les quotas de système de fichiers empêcheront les programmes de remplir le disque. ulimit correct (setrlimit() en C) les paramètres peuvent protéger contre la surutilisation de la mémoire et toutes les bombes de fourche, ainsi que mettre un terme aux 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.


J'ai récemment écrit un aperçu des techniques de sandboxing sous Linux. Je pense que votre approche la plus simple serait d'utiliser des conteneurs Linux (lxc) si cela ne vous dérange pas de bifurquer, etc., 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 en boucle 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 demander plus de travail qu'un conteneur.


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

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

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

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

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

    sudo losetup /dev/loop0 root.bin

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

  3. Faites un répertoire vide :

    mkdir mountpoint

  4. Monter root.bin :

    sudo mount /dev/loop0 mountpoint

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

    cd mountpoint .

  6. Droits de correction :

    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 VM :

    cp ~/student_assignment.c root/assignment.c

  11. Quittez le FS racine de la VM :

    cd ..

  12. sudo umount mountpoint
  13. Maintenant que l'image est prête, il ne nous reste plus qu'à 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 de l'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 de l'invité affiche "READY", vous pouvez envoyer des clés à la VM à partir de l'invite qemu. Par exemple, pour tester cette affectation, vous pouvez le 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. Maintenant Average = 12.000000 doit apparaître sur le tuyau de sortie de l'invité. Si ce n'est pas le cas, l'élève a échoué.

  19. Quitter qemu :quit

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


Linux
  1. Linux - Comment exécuter un chargeur de démarrage à partir de Linux ?

  2. Linux - Quelles données doivent être exclues des fichiers journaux, des messages d'erreur, etc. Si elles sont publiées en ligne ?

  3. Migrer un serveur Linux depuis la ligne de commande

  4. Comment programmer les fichiers d'arborescence de périphériques Linux .dts ?

  5. Exécution d'un programme potentiellement dangereux sous Linux

Configuration Linux :Comprendre les répertoires *.d dans /etc

Comment télécharger des fichiers à partir de serveurs Linux distants

Top 20 des commandes Linux Vim qui augmentent la productivité

Brilliant Ways sur la façon d'exécuter un programme sous Linux

Comment écrire et exécuter un programme C sous Linux

Comment exécuter la commande SUDO dans WinSCP pour transférer des fichiers de Windows vers Linux